Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .claude/commands/triage-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Skip silently when:

Classify as `needs-human` and exit when:

- Any changed file path is under `packages/owletto-web/` — submodule two-PR rule (AGENTS.md). The agent must never push a parent commit referencing an unmerged submodule SHA.
- Any changed file path is under `packages/web/` — submodule two-PR rule (AGENTS.md). The agent must never push a parent commit referencing an unmerged submodule SHA.
- Any changed file path is under `.github/workflows/` or is `scripts/setup-dev.sh` — infra blast radius.
- Any changed file path is `.github/triage-config.yml` or `.claude/commands/triage-pr.md` — these define triage policy itself. A PR modifying them must not be evaluated by the (potentially-modified) policy on its own branch; the agent escalates so a human can review the change against `main`.
- Any review comment contains case-insensitive: `security`, `credential`, `token`, `secret`, `auth bypass`, `P0`, or `P1`.
Expand Down Expand Up @@ -208,6 +208,6 @@ The marker line at the top is parsed by future runs to short-circuit on matching
- **Never split unnecessarily.** Do not propose splitting a PR whose title scope is consistent and whose size is under the 1000-line gate, even if it touches multiple files.
- **`.js` import suffix in TS sources.** When fixing imports, add `.js` extensions to relative imports (NodeNext resolution).
- **Typecheck drift.** Always run BOTH `make build-packages` (package-local tsc emit) and `bun run typecheck` (root tsc check) — they catch different things.
- **Submodule two-PR rule.** Any change under `packages/owletto-web/` → `needs-human`, full stop.
- **Submodule two-PR rule.** Any change under `packages/web/` → `needs-human`, full stop.
- **Unused parameters.** Delete them; never prefix with `_`.
- **Bun, not npm.** Hooks enforce this.
10 changes: 5 additions & 5 deletions .github/actions/setup-submodule/action.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "Set up private submodule"
description: >
Checks out packages/owletto-web via deploy key when available. For forks and
Checks out packages/web via deploy key when available. For forks and
runs without the secret, writes a stub package.json so bun workspaces still
resolve (the web assets just won't build).

Expand Down Expand Up @@ -30,16 +30,16 @@ runs:
run: |
set -euo pipefail
git config --global url."git@github.com:lobu-ai/owletto-web.git".insteadOf "https://github.com/lobu-ai/owletto-web.git"
git submodule update --init --recursive packages/owletto-web
git submodule update --init --recursive packages/web

- name: Write stub package.json when submodule is unavailable
id: stub
if: inputs.deploy-key == ''
shell: bash
run: |
set -euo pipefail
echo "No deploy key — writing stub package.json for packages/owletto-web"
mkdir -p packages/owletto-web
echo "No deploy key — writing stub package.json for packages/web"
mkdir -p packages/web
# The stub omits the real submodule's deps, which means
# `bun install --frozen-lockfile` will fail against bun.lock.
# Callers should branch on the `stubbed` output to relax checks
Expand All @@ -52,5 +52,5 @@ runs:
' "version": "1.6.0",' \
' "description": "Stub — private submodule not initialized"' \
'}' \
> packages/owletto-web/package.json
> packages/web/package.json
echo "stubbed=true" >> "$GITHUB_OUTPUT"
2 changes: 1 addition & 1 deletion .github/triage-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ infra_paths:

# Submodule two-PR rule. Any change under these is needs-human.
two_pr_paths:
- packages/owletto-web/
- packages/web/

# Comment substring matches (case-insensitive) that escalate to needs-human.
escalation_keywords:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/build-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ env:
# tracking ghcr.io/lobu-ai/owletto-{app,worker,embeddings} after the
# owletto -> lobu monorepo consolidation.
IMAGE_NAME_APP: lobu-ai/owletto-app
IMAGE_NAME_WORKER: lobu-ai/owletto-worker
IMAGE_NAME_EMBEDDINGS: lobu-ai/owletto-embeddings
IMAGE_NAME_WORKER: lobu-ai/connector-worker
IMAGE_NAME_EMBEDDINGS: lobu-ai/embeddings

jobs:
generate-tag:
Expand Down Expand Up @@ -140,7 +140,7 @@ jobs:
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/user/packages/container/owletto-worker/visibility \
https://api.github.com/user/packages/container/connector-worker/visibility \
-d '{"visibility":"public"}' || true

build-embeddings-service:
Expand Down Expand Up @@ -190,5 +190,5 @@ jobs:
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/user/packages/container/owletto-embeddings/visibility \
https://api.github.com/user/packages/container/embeddings/visibility \
-d '{"visibility":"public"}' || true
52 changes: 26 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:

- name: Install bubblewrap (for embedded exec-sandbox tests)
# The worker exec-sandbox uses bwrap on Linux; without it, the live
# bwrap escape-matrix tests in `packages/worker/src/__tests__/exec-sandbox.test.ts`
# bwrap escape-matrix tests in `packages/agent-worker/src/__tests__/exec-sandbox.test.ts`
# auto-skip and we lose the only Linux verification path.
# Ubuntu 24.04 (ubuntu-latest) blocks unprivileged user namespaces via
# AppArmor by default; bwrap needs them, so flip the sysctl. See
Expand All @@ -54,14 +54,14 @@ jobs:
# install it in the worker runtime image" before it ships.
run: node scripts/check-connector-runtime-deps.mjs

- name: Build core + sdk + owletto-worker for downstream type-resolution
# owletto-worker integration tests import from its compiled `dist/`
- name: Build core + sdk + connector-worker for downstream type-resolution
# connector-worker integration tests import from its compiled `dist/`
# (subprocess-mode tests spawn the built executor); build it here
# so those run.
run: |
cd packages/core && bun run build && cd ../..
cd packages/owletto-sdk && bun run build && cd ../..
cd packages/owletto-worker && bun run build && cd ../..
cd packages/connector-sdk && bun run build && cd ../..
cd packages/connector-worker && bun run build && cd ../..

- name: core / cli (bun:test)
run: bun test packages/core packages/cli --coverage
Expand All @@ -72,23 +72,23 @@ jobs:
# passes; if Linux turns out different we'll narrow this back down,
# but we own the WASM concern via run-script-runtime.test.ts under
# Node + isolated-vm in the integration job below.
run: bun test packages/worker
run: bun test packages/agent-worker

- name: owletto-backend (bun:test units)
- name: server (bun:test units)
# The gateway code that used to live in packages/gateway is now under
# src/gateway/. Its DB-backed bun:test suite needs Postgres and runs
# in the integration job below; here we only run the pure-unit
# subdirectories that don't touch Postgres.
run: |
bun test packages/owletto-backend/src/__tests__/unit
bun test packages/owletto-backend/src/auth/__tests__/tool-access.test.ts
bun test packages/owletto-backend/src/gateway/infrastructure/queue
bun test packages/server/src/__tests__/unit
bun test packages/server/src/auth/__tests__/tool-access.test.ts
bun test packages/server/src/gateway/infrastructure/queue

- name: owletto-worker (bun:test)
# owletto-openclaw e2e tests need a live backend and belong in the
- name: connector-worker (bun:test)
# openclaw-plugin e2e tests need a live backend and belong in the
# smoke-example workflow, not the unit job.
run: |
bun test packages/owletto-worker
bun test packages/connector-worker

- name: Upload coverage
if: always()
Expand Down Expand Up @@ -118,17 +118,17 @@ jobs:
if: steps.submodule.outputs.stubbed != 'true'
run: bun install

- name: Build owletto-sdk (owletto-web imports its compiled dist)
- name: Build connector-sdk (owletto-web imports its compiled dist)
if: steps.submodule.outputs.stubbed != 'true'
run: cd packages/owletto-sdk && bun run build
run: cd packages/connector-sdk && bun run build

- name: owletto-web tests (vitest)
# owletto-web doesn't define a `test` script in its package.json yet
# (that change ships as a separate submodule PR). Invoke vitest
# directly via the workspace-installed binary so this works on
# whatever submodule SHA the parent repo points at.
if: steps.submodule.outputs.stubbed != 'true'
run: cd packages/owletto-web && ../../node_modules/.bin/vitest run
run: cd packages/web && ../../node_modules/.bin/vitest run

# Backend integration tests need a real Postgres + pgvector. We run them
# under Node (not bun) for two reasons: (1) the vitest suite uses Node-only
Expand Down Expand Up @@ -173,10 +173,10 @@ jobs:
- name: Install dependencies
run: bun install

- name: Build packages owletto-backend depends on
- name: Build packages server depends on
run: |
cd packages/core && bun run build && cd ../..
cd packages/owletto-sdk && bun run build && cd ../..
cd packages/connector-sdk && bun run build && cd ../..

- name: Verify Postgres health (fail fast if pgvector setup is broken)
run: |
Expand All @@ -187,22 +187,22 @@ jobs:
PGPASSWORD=postgres psql -h 127.0.0.1 -p 5433 -U postgres -d owletto_test \
-c "CREATE EXTENSION IF NOT EXISTS vector"

- name: owletto-backend integration suite (vitest under Node)
working-directory: packages/owletto-backend
- name: server integration suite (vitest under Node)
working-directory: packages/server
run: node ../../node_modules/.bin/vitest run --reporter=default

- name: owletto-backend gateway suite (bun:test, needs Postgres)
- name: server gateway suite (bun:test, needs Postgres)
# The gateway code that used to live in packages/gateway is now under
# src/gateway/__tests__/. These bun:test files are excluded from
# vitest (see vitest.config.ts) and need a real Postgres, so they run
# here in the integration job.
working-directory: packages/owletto-backend
working-directory: packages/server
run: bun test src/gateway/__tests__

- name: owletto-backend lobu route suite (bun:test, needs Postgres)
- name: server lobu route suite (bun:test, needs Postgres)
# These bun:test files live outside src/gateway and are also excluded
# from vitest because they import bun:test directly.
working-directory: packages/owletto-backend
working-directory: packages/server
run: bun test src/lobu/__tests__ src/workspace/__tests__

format-lint:
Expand Down Expand Up @@ -255,12 +255,12 @@ jobs:
# Root tsconfig excludes these packages, so `bun run typecheck`
# above never sees them. Run each package's own tsc here so a
# type error can't reach main and break the npm publish at
# release time. owletto-connectors and landing are intentionally
# release time. connectors and landing are intentionally
# left out — they need preconditions (DOM lib, `astro sync`)
# that belong to their own build pipelines.
run: |
set -euo pipefail
for pkg in owletto-backend owletto-worker owletto-sdk owletto-openclaw owletto-embeddings owletto-extension cli; do
for pkg in server connector-worker connector-sdk openclaw-plugin embeddings browser-extension cli; do
echo "::group::typecheck $pkg"
(cd "packages/$pkg" && bunx tsc --noEmit)
echo "::endgroup::"
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,17 @@ jobs:
- name: Build packages
run: bun run build

# Frontend (owletto-web) ships with the product but isn't covered by
# Frontend (web) ships with the product but isn't covered by
# any other PR check: root `bun run build` skips it, and the root
# tsconfig excludes packages/owletto-web. Without this gate, a TS error
# tsconfig excludes packages/web. Without this gate, a TS error
# in the submodule (or a stale submodule pointer) can silently regress
# the deploy.
# Build owletto-sdk first because owletto-web imports its compiled dist.
- name: Build frontend (owletto-web)
# Build connector-sdk first because the web submodule imports its compiled dist.
- name: Build frontend (web)
if: steps.submodule.outputs.stubbed != 'true'
run: |
cd packages/owletto-sdk && bun run build && cd ../..
cd packages/owletto-web && bun run build
cd packages/connector-sdk && bun run build && cd ../..
cd packages/web && bun run build

- name: Verify no uncommitted changes
if: steps.submodule.outputs.stubbed != 'true'
Expand Down
26 changes: 13 additions & 13 deletions .github/workflows/submodule-drift.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Submodule Drift

# Surfaces when packages/owletto-web (private) has merged commits past the
# Surfaces when packages/web (private) has merged commits past the
# parent's pinned SHA — i.e. the two-PR rule's parent bump is missing.
# Bot tag-update commits (FluxCD image automation) are exempted only when both
# the author and exact subject match — a sloppy human commit cannot slip past.
Expand Down Expand Up @@ -47,10 +47,10 @@ jobs:
# actions/checkout@v4 with default fetch-depth=1 only has the merge
# commit; pull the two endpoints by SHA so ls-tree can resolve them.
git fetch --depth=1 origin "$BASE_SHA" "$HEAD_SHA"
base_pointer=$(git ls-tree "$BASE_SHA" packages/owletto-web | awk '{print $3}')
head_pointer=$(git ls-tree "$HEAD_SHA" packages/owletto-web | awk '{print $3}')
base_pointer=$(git ls-tree "$BASE_SHA" packages/web | awk '{print $3}')
head_pointer=$(git ls-tree "$HEAD_SHA" packages/web | awk '{print $3}')
if [ "$base_pointer" != "$head_pointer" ]; then
echo "::error::Fork PRs cannot change the packages/owletto-web pointer."
echo "::error::Fork PRs cannot change the packages/web pointer."
echo " base: $base_pointer"
echo " head: $head_pointer"
echo "Submodule bumps must come from a same-repo PR (deploy-key-authorized)."
Expand All @@ -72,16 +72,16 @@ jobs:
shell: bash
run: |
set -euo pipefail
PINNED=$(git -C packages/owletto-web rev-parse HEAD)
git -C packages/owletto-web fetch --quiet origin main
REMOTE=$(git -C packages/owletto-web rev-parse origin/main)
PINNED=$(git -C packages/web rev-parse HEAD)
git -C packages/web fetch --quiet origin main
REMOTE=$(git -C packages/web rev-parse origin/main)

echo "Pinned (parent): $PINNED"
echo "owletto-web/main: $REMOTE"

# Hard rule: parent must never pin a SHA that isn't on owletto-web/main.
# FluxCD reads charts from owletto-web/main; an off-main pin breaks deploy.
if ! git -C packages/owletto-web merge-base --is-ancestor "$PINNED" origin/main; then
if ! git -C packages/web merge-base --is-ancestor "$PINNED" origin/main; then
echo "::error::Pinned SHA $PINNED is not reachable from owletto-web/main."
echo "This violates the rule against pinning unmerged submodule SHAs (see AGENTS.md)."
exit 1
Expand All @@ -95,7 +95,7 @@ jobs:
# Capture the log first so set -e propagates a git failure (process
# substitution would swallow it). tformat: guarantees a trailing
# newline so `read` doesn't drop the last commit.
LOG=$(git -C packages/owletto-web log \
LOG=$(git -C packages/web log \
--pretty='tformat:%h|%ae|%s' "$PINNED..origin/main")

# Walk each commit; exempt only those whose author email AND exact
Expand All @@ -106,7 +106,7 @@ jobs:
while IFS='|' read -r sha email subject; do
[ -z "$sha" ] && continue
if [ "$email" = "$BOT_AUTHOR_EMAIL" ] && [ "$subject" = "$BOT_SUBJECT" ]; then
outside=$(git -C packages/owletto-web show --name-only \
outside=$(git -C packages/web show --name-only \
--pretty='format:' "$sha" \
| sed '/^$/d' \
| grep -v '^deploy/' || true)
Expand All @@ -132,8 +132,8 @@ jobs:
printf '%s' "$DRIFT"
echo ""
echo "Fix (open as a separate PR):"
echo " git -C packages/owletto-web fetch origin"
echo " git -C packages/owletto-web checkout origin/main"
echo " git add packages/owletto-web"
echo " git -C packages/web fetch origin"
echo " git -C packages/web checkout origin/main"
echo " git add packages/web"
echo " git commit -m 'chore(submodule): bump owletto-web to current main'"
exit 1
10 changes: 5 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ data/
dump.rdb

# Auto-generated page CSS
packages/owletto-backend/src/gateway/routes/public/page-styles.ts
packages/server/src/gateway/routes/public/page-styles.ts
packages/owletto-cli/runtime/

# Auto-generated history page JS bundle
packages/owletto-backend/src/gateway/routes/public/history-page-bundle.ts
packages/owletto-backend/src/gateway/routes/public/agent-page-bundle.ts
packages/owletto-backend/src/gateway/routes/public/agents-page-bundle.ts
packages/owletto-backend/src/gateway/routes/public/agents-page-bundle.raw.js
packages/server/src/gateway/routes/public/history-page-bundle.ts
packages/server/src/gateway/routes/public/agent-page-bundle.ts
packages/server/src/gateway/routes/public/agents-page-bundle.ts
packages/server/src/gateway/routes/public/agents-page-bundle.raw.js

# Astro build artifacts
packages/landing/.astro/
Expand Down
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "packages/owletto-web"]
path = packages/owletto-web
[submodule "packages/web"]
path = packages/web
url = https://github.com/lobu-ai/owletto-web.git
Loading
Loading