Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
10841f2
ade code: per-provider Chat/CLI interface choice
arul28 Jul 3, 2026
bbd0545
ade cli: remote/sync reliability hardening (audit batch)
arul28 Jul 3, 2026
7c2a74a
ade code: perf — single-pass rows, memoized children, debounced backg…
arul28 Jul 3, 2026
1f2ddb1
ade code: fix tui bug and parity batch
arul28 Jul 3, 2026
c608bd0
ade code + sync: review-wave fixups (R1-R5, T1-T2)
arul28 Jul 3, 2026
e3b705d
Persist Work Chat/CLI interface choice on iOS (+ desktop verify)
arul28 Jul 3, 2026
9a9f3f6
ade code: interface persistence, closed-session browsing, /secrets, p…
arul28 Jul 3, 2026
580ee3d
Hub composer: reload per-project Chat/CLI mode on project switch
arul28 Jul 3, 2026
5ee4469
ade code: quality synthesis — digit-picker fixes, app.tsx extractions…
arul28 Jul 3, 2026
1d8983d
ade code: closed-session glyph — user-initiated closes are not failures
arul28 Jul 3, 2026
ca03a82
ade cli: parity with hardening branch
arul28 Jul 3, 2026
e524259
docs: sync internal docs with ade-code hardening branch
arul28 Jul 3, 2026
d0d87d0
test: steward pass — prune, consolidate ade-code suite
arul28 Jul 3, 2026
d03bd97
Merge origin/main (#692 mobile hub overhaul + landing perf) into hard…
arul28 Jul 3, 2026
0d80f5d
ship: iteration 1 — address 10 review comments (greptile P1, codex P1…
arul28 Jul 3, 2026
d442d2d
ship: iteration 2 — address 2 codex P3s (grid claudeChrome, CJK trunc…
arul28 Jul 3, 2026
9a50966
ship: iteration 3 — quote-aware VISUAL/EDITOR parsing (codex P3)
arul28 Jul 3, 2026
46153fe
ship: iteration 4 — provider-aware terminal hydrate + local-provider …
arul28 Jul 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion apps/ade-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ sync.getPin sync.setPin sync.clearPin
sync.setActiveLanePresence
```

`runtimeEvents.subscribe` returns `eventEpoch`, `nextCursor`, `hasMore`, `gap`, and `oldestCursor`; when `gap` is true, the caller's cursor predates the retained buffer and it should refresh state before resuming from `oldestCursor` / `nextCursor`.

**Project-scoped** — every other request must carry `params.projectId`. `ade/actions/call` (and the legacy ADE action / tool catalog underneath it) is dispatched into the per-project `ProjectScope` returned by `ProjectScopeRegistry.get(projectId)`.

`ade/initialize` advertises `runtimeInfo.multiProject: true` and `capabilities.projects: true`. Clients use that to switch between sending `projectId` per request (multi-project runtime) and the legacy per-process binding (embedded runtime). Sync is owned by the sync service for the most-recently-opened registered project; `ProjectScopeRegistry.ensureSyncHost` refreshes the active sync project when projects are added or removed.
Expand All @@ -217,7 +219,7 @@ ade code --print-state # smoke-test the connection and exit
ade code remote --target mac --project ADE
# attach to a saved desktop remote machine
ade code remote session --target mac --project ADE --session chat-1
# open a remote chat or Claude terminal session
# open a remote chat or provider CLI terminal session
ade --socket /path/to/ade.sock code # attach to a specific local endpoint
ade --project-root /repo code # bind to a specific project root
```
Expand Down Expand Up @@ -291,6 +293,8 @@ ade prs comments pr-id --text
ade run defs --text
ade run start web --lane lane-id
ade shell start --lane lane-id -- npm test
ade terminal list --lane lane-id --text
ade terminal resume --terminal session-id --text
ade new chat --mode chat --lane lane-id --provider codex --model openai/gpt-5.5 --reasoning-effort xhigh --no-fast --permissions full-auto --prompt "fix failing tests"
ade new chat --mode cli --lane lane-id --provider codex --model openai/gpt-5.5 --reasoning-effort xhigh --no-fast --permissions full-auto --prompt "fix failing tests"
ade new chat --mode chat --lane auto --lane-name fix-checkout-flow --prompt "fix failing tests"
Expand Down
19 changes: 5 additions & 14 deletions apps/ade-cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/ade-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"opencode-ai": "^1.15.5",
"react": "^19.2.7",
"sql.js": "^1.13.0",
"string-width": "^4.2.3",
"ws": "^8.20.0",
"yaml": "^2.8.2",
"zod": "^4.3.6"
Expand Down
4 changes: 3 additions & 1 deletion apps/ade-cli/src/adeRpcServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4844,7 +4844,9 @@ async function runTool(args: {
events: sliced,
nextCursor: result.nextCursor,
hasMore: filtered.length > limit || result.hasMore,
eventEpoch: result.eventEpoch
eventEpoch: result.eventEpoch,
gap: result.gap === true,
oldestCursor: result.oldestCursor ?? null
};
}
return runtime.eventBuffer.drain(cursor, limit);
Expand Down
64 changes: 64 additions & 0 deletions apps/ade-cli/src/bootstrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,73 @@ describe("createEventBuffer", () => {
const result = buffer.drain(0);
// Should have IDs 3, 4, 5 (the oldest 1, 2 were evicted)
expect(result.events.map((e) => e.id)).toEqual([3, 4, 5]);
expect(result.gap).toBe(true);
expect(result.oldestCursor).toBe(3);
expect(result.events[0]!.payload).toEqual({ i: 2 });
});

it("reports no gap when the next retained event is contiguous with the cursor", () => {
const buffer = createEventBuffer(3);

for (let i = 0; i < 5; i++) {
buffer.push({ timestamp: `2026-03-01T00:0${i}:00Z`, category: "runtime", payload: { i } });
}

const result = buffer.drain(2);
expect(result.events.map((event) => event.id)).toEqual([3, 4, 5]);
expect(result.gap).toBe(false);
expect(result.oldestCursor).toBe(3);
});

it("evicts by retained byte budget and reports the replay gap", () => {
const buffer = createEventBuffer(10, { maxBytes: 260, maxEventBytes: 260 });

for (let i = 0; i < 4; i++) {
buffer.push({
timestamp: `2026-03-01T00:0${i}:00Z`,
category: "pty",
payload: { data: "x".repeat(90), i },
});
}

const result = buffer.drain(0);
expect(result.events.length).toBeLessThan(4);
expect(result.events.at(-1)?.id).toBe(4);
expect(result.gap).toBe(true);
expect(result.oldestCursor).toBeGreaterThan(1);
});

it("does not retain events larger than the per-event cap but still notifies live subscribers", () => {
const buffer = createEventBuffer(10, { maxBytes: 1024, maxEventBytes: 64 });
const seen: BufferedEvent[] = [];
buffer.subscribe((event) => seen.push(event));

buffer.push({
timestamp: "2026-03-01T00:00:00Z",
category: "pty",
payload: { data: "x".repeat(200) },
});

expect(seen).toHaveLength(1);
const result = buffer.drain(0);
expect(result.events).toEqual([]);
expect(result.gap).toBe(true);
expect(result.nextCursor).toBe(1);
});

it("reports a replay gap when an oversized event is skipped between retained events", () => {
const buffer = createEventBuffer(10, { maxBytes: 4096, maxEventBytes: 180 });

buffer.push({ timestamp: "2026-03-01T00:00:00Z", category: "runtime", payload: { data: "small-1" } });
buffer.push({ timestamp: "2026-03-01T00:00:01Z", category: "runtime", payload: { data: "x".repeat(500) } });
buffer.push({ timestamp: "2026-03-01T00:00:02Z", category: "runtime", payload: { data: "small-2" } });

const result = buffer.drain(1);
expect(result.events.map((event) => event.id)).toEqual([3]);
expect(result.gap).toBe(true);
expect(result.oldestCursor).toBe(3);
});

it("drains events after cursor", () => {
const buffer = createEventBuffer();

Expand Down
Loading
Loading