@cluesmith/codev 3.3.3 → 3.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard-dist/assets/index-BuflRUi6.js +220 -0
- package/dashboard-dist/assets/index-BuflRUi6.js.map +1 -0
- package/dashboard-dist/assets/index-r3bZzLmX.css +32 -0
- package/dashboard-dist/index.html +2 -2
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +48 -0
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/ide.d.ts +20 -0
- package/dist/agent-farm/commands/ide.d.ts.map +1 -0
- package/dist/agent-farm/commands/ide.js +138 -0
- package/dist/agent-farm/commands/ide.js.map +1 -0
- package/dist/agent-farm/commands/inbox.d.ts.map +1 -1
- package/dist/agent-farm/commands/inbox.js +15 -3
- package/dist/agent-farm/commands/inbox.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +3 -2
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +40 -6
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +28 -9
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/tower.d.ts +21 -9
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +90 -30
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/db/tower-owner.d.ts +168 -0
- package/dist/agent-farm/db/tower-owner.d.ts.map +1 -0
- package/dist/agent-farm/db/tower-owner.js +369 -0
- package/dist/agent-farm/db/tower-owner.js.map +1 -0
- package/dist/agent-farm/db/types.d.ts +30 -5
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/lib/ide-record.d.ts +65 -0
- package/dist/agent-farm/lib/ide-record.d.ts.map +1 -0
- package/dist/agent-farm/lib/ide-record.js +118 -0
- package/dist/agent-farm/lib/ide-record.js.map +1 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts +22 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +53 -5
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/decisions/file.d.ts +50 -0
- package/dist/agent-farm/servers/decisions/file.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/file.js +146 -0
- package/dist/agent-farm/servers/decisions/file.js.map +1 -0
- package/dist/agent-farm/servers/decisions/grammar.d.ts +36 -0
- package/dist/agent-farm/servers/decisions/grammar.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/grammar.js +109 -0
- package/dist/agent-farm/servers/decisions/grammar.js.map +1 -0
- package/dist/agent-farm/servers/decisions/notice.d.ts +11 -0
- package/dist/agent-farm/servers/decisions/notice.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/notice.js +18 -0
- package/dist/agent-farm/servers/decisions/notice.js.map +1 -0
- package/dist/agent-farm/servers/decisions/parse.d.ts +36 -0
- package/dist/agent-farm/servers/decisions/parse.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/parse.js +308 -0
- package/dist/agent-farm/servers/decisions/parse.js.map +1 -0
- package/dist/agent-farm/servers/decisions/routes.d.ts +17 -0
- package/dist/agent-farm/servers/decisions/routes.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/routes.js +160 -0
- package/dist/agent-farm/servers/decisions/routes.js.map +1 -0
- package/dist/agent-farm/servers/decisions/splice.d.ts +26 -0
- package/dist/agent-farm/servers/decisions/splice.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/splice.js +120 -0
- package/dist/agent-farm/servers/decisions/splice.js.map +1 -0
- package/dist/agent-farm/servers/decisions/stamp.d.ts +4 -0
- package/dist/agent-farm/servers/decisions/stamp.d.ts.map +1 -0
- package/dist/agent-farm/servers/decisions/stamp.js +171 -0
- package/dist/agent-farm/servers/decisions/stamp.js.map +1 -0
- package/dist/agent-farm/servers/gate-profiles.d.ts +23 -2
- package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.js +43 -2
- package/dist/agent-farm/servers/gate-profiles.js.map +1 -1
- package/dist/agent-farm/servers/ide-forward.d.ts +62 -0
- package/dist/agent-farm/servers/ide-forward.d.ts.map +1 -0
- package/dist/agent-farm/servers/ide-forward.js +274 -0
- package/dist/agent-farm/servers/ide-forward.js.map +1 -0
- package/dist/agent-farm/servers/ide-server.d.ts +68 -0
- package/dist/agent-farm/servers/ide-server.d.ts.map +1 -0
- package/dist/agent-farm/servers/ide-server.js +281 -0
- package/dist/agent-farm/servers/ide-server.js.map +1 -0
- package/dist/agent-farm/servers/mailbox-delivery.d.ts +213 -4
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.js +489 -68
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +18 -4
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.js +94 -21
- package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -1
- package/dist/agent-farm/servers/message-write.d.ts +138 -11
- package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
- package/dist/agent-farm/servers/message-write.js +144 -35
- package/dist/agent-farm/servers/message-write.js.map +1 -1
- package/dist/agent-farm/servers/overview.d.ts +32 -15
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +181 -103
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/render-gate.d.ts +53 -0
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
- package/dist/agent-farm/servers/render-gate.js +135 -24
- package/dist/agent-farm/servers/render-gate.js.map +1 -1
- package/dist/agent-farm/servers/session-submit.d.ts +7 -4
- package/dist/agent-farm/servers/session-submit.d.ts.map +1 -1
- package/dist/agent-farm/servers/session-submit.js +7 -4
- package/dist/agent-farm/servers/session-submit.js.map +1 -1
- package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-cron.js +4 -1
- package/dist/agent-farm/servers/tower-cron.js.map +1 -1
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +6 -7
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +116 -18
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +64 -7
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +53 -8
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +18 -1
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/utils/message-format.d.ts +8 -0
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
- package/dist/agent-farm/utils/message-format.js +21 -6
- package/dist/agent-farm/utils/message-format.js.map +1 -1
- package/dist/agent-farm/utils/port.d.ts +22 -0
- package/dist/agent-farm/utils/port.d.ts.map +1 -0
- package/dist/agent-farm/utils/port.js +35 -0
- package/dist/agent-farm/utils/port.js.map +1 -0
- package/dist/agent-farm/utils/server-utils.d.ts +26 -0
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +36 -0
- package/dist/agent-farm/utils/server-utils.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/consult/index.d.ts +20 -1
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +117 -3
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/consult/tree-tripwire.d.ts +177 -0
- package/dist/commands/consult/tree-tripwire.d.ts.map +1 -0
- package/dist/commands/consult/tree-tripwire.js +356 -0
- package/dist/commands/consult/tree-tripwire.js.map +1 -0
- package/dist/commands/doctor.d.ts +69 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +163 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-image.d.ts +5 -0
- package/dist/commands/generate-image.d.ts.map +1 -1
- package/dist/commands/generate-image.js +225 -4
- package/dist/commands/generate-image.js.map +1 -1
- package/dist/commands/porch/checks.d.ts +7 -1
- package/dist/commands/porch/checks.d.ts.map +1 -1
- package/dist/commands/porch/checks.js +77 -14
- package/dist/commands/porch/checks.js.map +1 -1
- package/dist/commands/porch/index.d.ts +38 -1
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +79 -43
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/porch/protocol.d.ts +4 -3
- package/dist/commands/porch/protocol.d.ts.map +1 -1
- package/dist/commands/porch/protocol.js +32 -5
- package/dist/commands/porch/protocol.js.map +1 -1
- package/dist/commands/porch/types.d.ts +2 -0
- package/dist/commands/porch/types.d.ts.map +1 -1
- package/dist/lib/agent-env.d.ts +95 -0
- package/dist/lib/agent-env.d.ts.map +1 -0
- package/dist/lib/agent-env.js +137 -0
- package/dist/lib/agent-env.js.map +1 -0
- package/dist/lib/config.d.ts +8 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/forge-contracts.d.ts +10 -0
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/forge-rate-limit.d.ts +45 -0
- package/dist/lib/forge-rate-limit.d.ts.map +1 -0
- package/dist/lib/forge-rate-limit.js +89 -0
- package/dist/lib/forge-rate-limit.js.map +1 -0
- package/dist/lib/forge.d.ts +28 -0
- package/dist/lib/forge.d.ts.map +1 -1
- package/dist/lib/forge.js +63 -10
- package/dist/lib/forge.js.map +1 -1
- package/dist/lib/github.d.ts +13 -1
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +58 -15
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/test-env.d.ts +17 -0
- package/dist/lib/test-env.d.ts.map +1 -1
- package/dist/lib/test-env.js +20 -0
- package/dist/lib/test-env.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +122 -4
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +142 -7
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +23 -2
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +115 -36
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/session-screen.d.ts +34 -5
- package/dist/terminal/session-screen.d.ts.map +1 -1
- package/dist/terminal/session-screen.js +52 -6
- package/dist/terminal/session-screen.js.map +1 -1
- package/dist/terminal/terminal-replies.d.ts +102 -0
- package/dist/terminal/terminal-replies.d.ts.map +1 -0
- package/dist/terminal/terminal-replies.js +181 -0
- package/dist/terminal/terminal-replies.js.map +1 -0
- package/package.json +4 -4
- package/scripts/forge/github/pr-list.sh +6 -2
- package/scripts/forge/github/pr-search.sh +4 -2
- package/scripts/forge/gitlab/issue-search.sh +1 -0
- package/scripts/forge/gitlab/pr-search.sh +35 -2
- package/scripts/forge/linear/auth-status.sh +1 -0
- package/scripts/forge/linear/issue-comment.sh +1 -0
- package/scripts/forge/linear/issue-list.sh +1 -0
- package/scripts/forge/linear/issue-search.sh +1 -0
- package/scripts/forge/linear/issue-view.sh +1 -0
- package/scripts/forge/linear/recently-closed.sh +1 -0
- package/scripts/forge/linear/user-identity.sh +1 -0
- package/skeleton/.claude/skills/afx/SKILL.md +15 -0
- package/skeleton/.claude/skills/arch-init/SKILL.md +56 -9
- package/skeleton/.claude/skills/arch-save/SKILL.md +100 -9
- package/skeleton/.claude/skills/consult/SKILL.md +9 -0
- package/skeleton/.claude/skills/generate-image/SKILL.md +19 -2
- package/skeleton/.claude/skills/porch/SKILL.md +18 -0
- package/skeleton/.codex/skills/afx/SKILL.md +15 -0
- package/skeleton/.codex/skills/arch-init/SKILL.md +56 -9
- package/skeleton/.codex/skills/arch-save/SKILL.md +100 -9
- package/skeleton/.codex/skills/consult/SKILL.md +9 -0
- package/skeleton/.codex/skills/generate-image/SKILL.md +19 -2
- package/skeleton/.codex/skills/porch/SKILL.md +18 -0
- package/skeleton/protocol-schema.json +6 -0
- package/skeleton/protocols/maintain/protocol.md +5 -0
- package/skeleton/protocols/pir/prompts/review.md +0 -1
- package/skeleton/protocols/protocol-schema.json +6 -0
- package/skeleton/resources/commands/agent-farm.md +71 -2
- package/skeleton/resources/commands/consult.md +9 -2
- package/skeleton/roles/consultant.md +32 -0
- package/skeleton/templates/AGENTS.md +1 -1
- package/skeleton/templates/CLAUDE.md +1 -1
- package/skeleton/templates/cheatsheet.md +1 -1
- package/dashboard-dist/assets/index-CUIjS_Vb.js +0 -199
- package/dashboard-dist/assets/index-CUIjS_Vb.js.map +0 -1
- package/dashboard-dist/assets/index-DnYLy5C_.css +0 -32
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal REPLY stripping for the delivery gate's input signal (Issue #1473).
|
|
3
|
+
*
|
|
4
|
+
* The render gate needs to know when a HUMAN has put something on a session's line, so a
|
|
5
|
+
* gated delivery never lands on a composer somebody has started typing into. The only
|
|
6
|
+
* server-side observation point is {@link PtySession.write}'s external branch — every live
|
|
7
|
+
* client (the web terminal, the VS Code webview, mobile, the raw
|
|
8
|
+
* `POST /api/terminals/:id/write` route) funnels through it.
|
|
9
|
+
*
|
|
10
|
+
* But that stream is not keystrokes. xterm forwards terminal REPLIES — DA, DSR, CPR,
|
|
11
|
+
* XTWINOPS, DECRPM, DECRQSS, OSC colour queries, focus reports — through the very same
|
|
12
|
+
* `onData` event as typed characters, because from the client's point of view they are all
|
|
13
|
+
* "bytes to send upstream". The web client strips a few of them, but ONLY while
|
|
14
|
+
* `rc.initialPhase` is true (`Terminal.tsx`) — for a session's entire steady-state life that
|
|
15
|
+
* filter is off, and the VS Code webview and mobile clients never had one at all. (`afx
|
|
16
|
+
* attach` is not in scope either way: it writes the shellper socket directly, so neither its
|
|
17
|
+
* keystrokes nor its replies ever pass through `PtySession.write()` — see arch.md §5.)
|
|
18
|
+
* Counting a reply as human input would produce a hold with nobody at the keyboard, and
|
|
19
|
+
* worse, a SELF-TRIP: our own delivery write repaints the TUI, the TUI queries geometry, the
|
|
20
|
+
* browser answers, and the answer reads as a keystroke that blocks the next delivery. So the
|
|
21
|
+
* filter is a precondition of the whole design, and it lives here — server-side, where every
|
|
22
|
+
* client is covered, rather than in one cooperative client.
|
|
23
|
+
*
|
|
24
|
+
* SIGNAL-ONLY. Nothing here changes what reaches the PTY: the caller still writes the full
|
|
25
|
+
* chunk verbatim, because the application ASKED for the reply and blocks waiting on it.
|
|
26
|
+
* Swallowing a DA reply would hang every attached terminal.
|
|
27
|
+
*
|
|
28
|
+
* ## Failure directions
|
|
29
|
+
*
|
|
30
|
+
* - **Over-strip** (a real keystroke eaten from the signal) → that keystroke goes uncounted,
|
|
31
|
+
* which is exactly today's behaviour, so never a regression — but it silently re-opens the
|
|
32
|
+
* race this issue exists to close, which is why the survival tests below are the strict half.
|
|
33
|
+
* - **Under-strip** (a reply counted as input) → a spurious `busy:recent-input` hold that
|
|
34
|
+
* clears on the next settle. Fail-safe, and now visible rather than silent.
|
|
35
|
+
*
|
|
36
|
+
* The filter is **chunk-local**: it sees exactly the string one `write()` was handed, so a
|
|
37
|
+
* reply that arrives split across two calls (a short socket read, a coalescing client) matches
|
|
38
|
+
* no pattern in either half and is under-stripped. That is the fail-safe direction — a hold
|
|
39
|
+
* that clears itself a settle later — and it is why no pattern here is written to span calls:
|
|
40
|
+
* buffering across chunks to catch it would put a real keystroke's arrival at the mercy of the
|
|
41
|
+
* NEXT chunk, which is the over-strip direction, and that one is silent.
|
|
42
|
+
*
|
|
43
|
+
* ## The table is derived from a PINNED dependency
|
|
44
|
+
*
|
|
45
|
+
* Every pattern below was read out of `@xterm/xterm@{@link XTERM_REPLY_TABLE_VERSION}`'s
|
|
46
|
+
* bundle — each `triggerDataEvent` call site that emits a reply rather than a keystroke. A
|
|
47
|
+
* version bump is therefore a REVIEW TRIGGER for this file: a newly-answered query (kitty
|
|
48
|
+
* keyboard, XTVERSION) becomes an uncounted-reply hold until its shape is added here. Two
|
|
49
|
+
* patterns below are pre-emptive for that reason and match nothing stock xterm 5.5 emits.
|
|
50
|
+
*
|
|
51
|
+
* ## Case sensitivity is load-bearing
|
|
52
|
+
*
|
|
53
|
+
* `ESC[C` is Right-arrow and `ESC[1;5C` is Ctrl-Right. The CSI family pattern keys on a
|
|
54
|
+
* LOWERCASE final byte set (`c`/`n`/`t`/`y`); an `i` flag on it would strip every arrow key,
|
|
55
|
+
* Home/End and shift-Tab out of the signal. No pattern here carries `i`, and
|
|
56
|
+
* `terminal-replies.test.ts` pins the survival of those exact sequences.
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* The `@xterm/xterm` version whose emission sites this table was enumerated from. Bumping the
|
|
60
|
+
* dependency past it means re-reading its `triggerDataEvent` call sites; a test asserts this
|
|
61
|
+
* constant against the installed package's version so the bump cannot pass silently.
|
|
62
|
+
*/
|
|
63
|
+
export const XTERM_REPLY_TABLE_VERSION = '5.5.0';
|
|
64
|
+
/**
|
|
65
|
+
* Sequences a terminal emulator sends UPSTREAM in answer to the application, never as a
|
|
66
|
+
* human action. Anchored one shape at a time — never a blanket "starts with ESC[" — so a
|
|
67
|
+
* keystroke can only be eaten by a pattern that names its exact form.
|
|
68
|
+
*
|
|
69
|
+
* What each covers, in xterm 5.5.0's own emission order:
|
|
70
|
+
*
|
|
71
|
+
* 1. The CSI answer family, keyed on a lowercase final byte:
|
|
72
|
+
* - DA1 `ESC[?1;2c`, `ESC[?6c` (`sendDeviceAttributesPrimary`)
|
|
73
|
+
* - DA2 `ESC[>0;276;0c`, `ESC[>85;95;0c`, `ESC[>83;40003;0c`
|
|
74
|
+
* - DSR `ESC[0n` (`deviceStatus`, param 5)
|
|
75
|
+
* - XTWINOPS `ESC[4;h;wt`, `ESC[6;h;wt`, `ESC[8;rows;colst`
|
|
76
|
+
* - DECRPM `ESC[?2004$y`, `ESC[1;2$y` (`_reportMode`)
|
|
77
|
+
* No key sequence xterm can produce ends in `c`, `n`, `t` or `y` — its key finals are
|
|
78
|
+
* `~ A B C D F H I O Z R M m`, all outside this class.
|
|
79
|
+
* 2. CPR `ESC[12;40R` and DECXCPR `ESC[?12;40R` — TWO params, not three. (An earlier
|
|
80
|
+
* three-param pattern would have missed both.)
|
|
81
|
+
* 3. The kitty-keyboard query answer, for a fork that grows one. Its literal `?` is what
|
|
82
|
+
* keeps it off real kitty-ENCODED keystrokes, which carry no `?`.
|
|
83
|
+
* 4. Focus in/out `ESC[I` / `ESC[O`. Stripped deliberately: a focus report cannot change
|
|
84
|
+
* composer CONTENT, whereas a click that could carries its own mouse report — which is
|
|
85
|
+
* preserved (see below). So this costs no coverage and stops an alt-tab holding mail.
|
|
86
|
+
* 5. DECRQSS `ESC P 1 $ r … ESC \` (`requestStatusString`).
|
|
87
|
+
* 6. XTVERSION `ESC P > | … ESC \` — pre-emptive; stock 5.5.0 never answers it.
|
|
88
|
+
* 7. OSC colour reports `ESC ] 10;rgb:…` / `ESC ] 4;12;rgb:…`, terminated by ST or BEL.
|
|
89
|
+
*
|
|
90
|
+
* NOT stripped, on purpose:
|
|
91
|
+
*
|
|
92
|
+
* - **Mouse reports** (`ESC[<0;10;5M`, `ESC[<0;10;5m`, and the X10 `ESC[M` + 3 bytes). These
|
|
93
|
+
* are built from a DOM event by the mouse ENCODERS and pushed through the generic data
|
|
94
|
+
* path — they are a human ACTION that can change the composer (a click moves the cursor,
|
|
95
|
+
* a middle-click pastes, a drag selects), not a parser answer. Stripping them would
|
|
96
|
+
* re-open the race for every mouse-driven TUI. Motion tracking can be chatty, but that
|
|
97
|
+
* only holds delivery while the mouse is actually moving, and it clears one settle after
|
|
98
|
+
* it stops — the fail-safe direction.
|
|
99
|
+
* - **Bracketed paste markers** (`ESC[200~` / `ESC[201~`). A paste is human input.
|
|
100
|
+
*
|
|
101
|
+
* Content-blind by construction: a reply-SHAPED byte run inside a bracketed paste is stripped
|
|
102
|
+
* from the signal while the surrounding pasted text still counts. Intended (over-strip is the
|
|
103
|
+
* safe direction) and pinned by a test.
|
|
104
|
+
*/
|
|
105
|
+
const TERMINAL_REPLY_PATTERNS = [
|
|
106
|
+
/\x1b\[[?>=]?[0-9;]*\$?[cnty]/g,
|
|
107
|
+
/\x1b\[\??[0-9]+;[0-9]+R/g,
|
|
108
|
+
/\x1b\[\?[0-9;]*u/g,
|
|
109
|
+
/\x1b\[[IO]/g,
|
|
110
|
+
/\x1bP[0-9]\$r[^\x1b]*\x1b\\/g,
|
|
111
|
+
/\x1bP>\|[^\x1b]*\x1b\\/g,
|
|
112
|
+
/\x1b\][0-9;]+;rgb:[0-9a-fA-F/]+(?:\x07|\x1b\\)/g,
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* Every recognized terminal reply in `data`, in the order the patterns match them.
|
|
116
|
+
*
|
|
117
|
+
* Diagnostics only — {@link stripTerminalReplies} does the real work and never calls this. It
|
|
118
|
+
* backs the `AF_LOG_INPUT_SIGNAL` trace, whose whole purpose is to let a human SEE which bytes
|
|
119
|
+
* were treated as a reply and which survived as input, rather than infer it from a hold that
|
|
120
|
+
* did or did not happen.
|
|
121
|
+
*/
|
|
122
|
+
export function terminalReplyMatches(data) {
|
|
123
|
+
const found = [];
|
|
124
|
+
for (const pattern of TERMINAL_REPLY_PATTERNS) {
|
|
125
|
+
for (const m of data.matchAll(pattern))
|
|
126
|
+
found.push(m[0]);
|
|
127
|
+
}
|
|
128
|
+
return found;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Render a byte run so it can be read in a log line: ESC as `\e`, other C0 controls and DEL as
|
|
132
|
+
* `\xNN`, everything else literal.
|
|
133
|
+
*
|
|
134
|
+
* Printing raw ESC to a terminal log would make the log itself move the cursor and repaint —
|
|
135
|
+
* the diagnostic would corrupt the thing it is diagnosing, and the reply bytes under
|
|
136
|
+
* investigation would be the ones that vanished.
|
|
137
|
+
*/
|
|
138
|
+
export function escapeBytes(data) {
|
|
139
|
+
let out = '';
|
|
140
|
+
for (const ch of data) {
|
|
141
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
142
|
+
if (ch === '\x1b')
|
|
143
|
+
out += '\\e';
|
|
144
|
+
else if (code < 0x20 || code === 0x7f)
|
|
145
|
+
out += `\\x${code.toString(16).padStart(2, '0')}`;
|
|
146
|
+
else
|
|
147
|
+
out += ch;
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The human-input residue of one upstream chunk: `data` with every recognized terminal reply
|
|
153
|
+
* removed. Returns `''` when the chunk was nothing but replies — the caller reads that as "no
|
|
154
|
+
* human input here" and leaves the gate's input signal untouched.
|
|
155
|
+
*
|
|
156
|
+
* Pure and allocation-cheap; called on every keystroke, so the common case (plain text with
|
|
157
|
+
* no ESC at all) short-circuits before touching a regex.
|
|
158
|
+
*
|
|
159
|
+
* The short-circuit does NOT cover a bracketed paste: `ESC[200~ … ESC[201~` always contains
|
|
160
|
+
* ESC, so a pasted body — up to the 1 MiB a `/write` request body may carry — runs every
|
|
161
|
+
* pattern's `replace` over its full length. This is an EXTERNAL paste only (a human pasting
|
|
162
|
+
* into the browser terminal, or a caller POSTing one to `/api/terminals/:id/write`); a mail
|
|
163
|
+
* delivery's own bracketed paste (Issue #1567) is written with origin `'delivery'` and never
|
|
164
|
+
* reaches this function at all, so no long send pays the scan. Left as is deliberately: an
|
|
165
|
+
* external paste is a rare, human-paced event next to the per-keystroke path this function is
|
|
166
|
+
* tuned for, and any length guard cheap enough to be worth adding would have to decide where a
|
|
167
|
+
* reply may legitimately sit inside the payload — which is the over-strip direction, the
|
|
168
|
+
* silent one.
|
|
169
|
+
*/
|
|
170
|
+
export function stripTerminalReplies(data) {
|
|
171
|
+
if (!data.includes('\x1b'))
|
|
172
|
+
return data;
|
|
173
|
+
let out = data;
|
|
174
|
+
for (const pattern of TERMINAL_REPLY_PATTERNS) {
|
|
175
|
+
out = out.replace(pattern, '');
|
|
176
|
+
if (out === '')
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=terminal-replies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-replies.js","sourceRoot":"","sources":["../../src/terminal/terminal-replies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,uBAAuB,GAAsB;IACjD,+BAA+B;IAC/B,0BAA0B;IAC1B,mBAAmB;IACnB,aAAa;IACb,8BAA8B;IAC9B,yBAAyB;IACzB,iDAAiD;CAClD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;QAC9C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,EAAE,KAAK,MAAM;YAAE,GAAG,IAAI,KAAK,CAAC;aAC3B,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI;YAAE,GAAG,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;;YACpF,GAAG,IAAI,EAAE,CAAC;IACjB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;QAC9C,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cluesmith/codev",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.5",
|
|
4
4
|
"description": "Codev CLI - AI-assisted software development framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"open": "^10.1.0",
|
|
36
36
|
"tree-kill": "^1.2.2",
|
|
37
37
|
"ws": "^8.18.0",
|
|
38
|
-
"@cluesmith/codev-core": "3.3.
|
|
39
|
-
"@cluesmith/codev-sdk": "3.3.
|
|
40
|
-
"@cluesmith/codev-types": "3.3.
|
|
38
|
+
"@cluesmith/codev-core": "3.3.5",
|
|
39
|
+
"@cluesmith/codev-sdk": "3.3.5",
|
|
40
|
+
"@cluesmith/codev-types": "3.3.5"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@playwright/test": "^1.58.0",
|
|
@@ -7,5 +7,9 @@
|
|
|
7
7
|
# as objects (users carry `login`; teams carry `slug`/`name` and no `login`), so
|
|
8
8
|
# `.login // empty` keeps user reviewers and drops team reviewers — matching the
|
|
9
9
|
# `reviewRequests: string[]` contract in PrListItem (forge-contracts.ts).
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
#
|
|
11
|
+
# Not `gh … | jq`: POSIX sh has no pipefail, so the caller would see jq's exit
|
|
12
|
+
# status and a rate-limited gh would look like a successful empty list (#1645).
|
|
13
|
+
# forge-executable: gh
|
|
14
|
+
out="$(gh pr list --json number,title,url,reviewDecision,body,createdAt,author,reviewRequests,isDraft)" || exit 1
|
|
15
|
+
printf '%s' "$out" | jq '[.[] | .reviewRequests = [.reviewRequests[].login // empty]]'
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: pr-search (GitHub via gh CLI)
|
|
3
3
|
# Input: CODEV_SEARCH_QUERY
|
|
4
|
-
# Output: JSON [{number, headRefName, baseRefName}]
|
|
4
|
+
# Output: JSON [{number, headRefName, baseRefName, state}]
|
|
5
5
|
# --state all is required so the search includes merged/closed PRs; without it
|
|
6
6
|
# `gh pr list` defaults to --state open and post-merge lookups return nothing (#759).
|
|
7
|
-
|
|
7
|
+
# `state` (OPEN/MERGED/CLOSED) lets consumers that only want open PRs filter
|
|
8
|
+
# client-side — the spawn collision guard must ignore merged/closed ones (#1637).
|
|
9
|
+
exec gh pr list --state all --search "$CODEV_SEARCH_QUERY" --json number,headRefName,baseRefName,state
|
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
# Forge concept: pr-search (GitLab via glab CLI)
|
|
2
|
+
# Forge concept: pr-search (GitLab via glab CLI — merge requests)
|
|
3
|
+
# Output: JSON [{number, headRefName, baseRefName, state, ...glab fields}]
|
|
4
|
+
#
|
|
5
|
+
# ⚠️ UNVERIFIED — `glab` is not available in the authoring environment (#920);
|
|
6
|
+
# written against glab's documented `mr list --output json` shape (confirmed
|
|
7
|
+
# against the field mappings already documented in gitlab/pr-list.sh and
|
|
8
|
+
# gitlab/pr-exists.sh). Smoke-test before relying on it.
|
|
9
|
+
#
|
|
3
10
|
# --all is required so the search includes merged/closed MRs; without it
|
|
4
11
|
# `glab mr list` defaults to opened only and post-merge lookups return nothing (#759).
|
|
5
|
-
|
|
12
|
+
#
|
|
13
|
+
# Maps glab's GitLab-shaped fields into the forge-neutral PrSearchItem contract
|
|
14
|
+
# (forge-contracts.ts); `. + {…}` is non-destructive for keys we don't touch:
|
|
15
|
+
# iid -> number (the MR number glab mr view/merge expects)
|
|
16
|
+
# source_branch -> headRefName
|
|
17
|
+
# target_branch -> baseRefName
|
|
18
|
+
# Without this the spawn guard's message reads `PR #undefined` and consult's
|
|
19
|
+
# findPRForIssue can't resolve the MR's base branch on GitLab.
|
|
20
|
+
#
|
|
21
|
+
# glab reports state lowercase (opened/merged/closed/locked); normalize to the
|
|
22
|
+
# GitHub convention (OPEN/MERGED/CLOSED) so consumers filter with one comparison.
|
|
23
|
+
# The spawn collision guard keys off state === "OPEN" to ignore merged MRs (#1637).
|
|
24
|
+
# `locked` (a transient merging state) maps to OPEN too: the guard should err
|
|
25
|
+
# toward the recoverable --force prompt, never silently skip a live collision.
|
|
26
|
+
#
|
|
27
|
+
# Not `glab … | jq`: POSIX sh has no pipefail, so the caller would see jq's exit
|
|
28
|
+
# status and a failed glab would look like a successful empty list (#1645).
|
|
29
|
+
# The capture-then-pipe shape hides `glab` from extractExecutable's first-line
|
|
30
|
+
# heuristic (it lands on the `printf` builtin), so declare the backend explicitly
|
|
31
|
+
# — same as github/pr-list.sh (#1645).
|
|
32
|
+
# forge-executable: glab
|
|
33
|
+
out="$(glab mr list --all --search "$CODEV_SEARCH_QUERY" --output json)" || exit 1
|
|
34
|
+
printf '%s' "$out" | jq 'map(.
|
|
35
|
+
+ {number: .iid}
|
|
36
|
+
+ {headRefName: .source_branch}
|
|
37
|
+
+ {baseRefName: .target_branch}
|
|
38
|
+
+ {state: ((.state // "") | ascii_downcase as $s | if $s == "opened" or $s == "locked" then "OPEN" else ($s | ascii_upcase) end)})'
|
|
@@ -184,8 +184,23 @@ There is NO `afx tower restart` — use `afx tower stop && afx tower start`.
|
|
|
184
184
|
```bash
|
|
185
185
|
afx workspace start # Start workspace for current project
|
|
186
186
|
afx workspace stop # Stop workspace processes
|
|
187
|
+
afx workspace add-architect --name <name> # Add a named sibling architect terminal
|
|
188
|
+
afx workspace remove-architect <name> # Remove a sibling architect (cannot remove main)
|
|
189
|
+
afx workspace recover # Revive builders whose shellper died (e.g. after reboot)
|
|
187
190
|
```
|
|
188
191
|
|
|
192
|
+
**Recreating a dead architect** (its process died while Tower kept the registration):
|
|
193
|
+
re-add it under the SAME name, then re-init its identity:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
afx workspace add-architect --name <name>
|
|
197
|
+
afx send architect:<name> "/arch-init <name>"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Builder-to-architect affinity survives the death (builders keep their Owner), so a
|
|
201
|
+
same-name re-add restores routing with no worktree impact and no builder disruption.
|
|
202
|
+
`afx workspace recover` revives builders only, not architects.
|
|
203
|
+
|
|
189
204
|
`afx dash` is a deprecated alias — use `afx workspace` instead.
|
|
190
205
|
|
|
191
206
|
## afx cron
|
|
@@ -46,12 +46,56 @@ name in a multi-architect workspace).
|
|
|
46
46
|
(`codev/state/*.md`); never commit them. Builder `*_thread.md` files
|
|
47
47
|
are the opposite: versioned, shipping with each builder PR.
|
|
48
48
|
|
|
49
|
-
3. **Confirm identity + orient
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
3. **Confirm identity + orient.** In one tight block, report: who you now are
|
|
50
|
+
(name + one-line role from the banner, if present), the file you read, and
|
|
51
|
+
the current-state / open-loops summary from the most recent dated section
|
|
52
|
+
(or the file's leading content if it has no dated sections). If the banner
|
|
53
|
+
carries a `NEXT TASK` line, report both halves of it, as
|
|
54
|
+
`Next task from the owner at save time: <verbatim> → resolved: <gloss>`
|
|
55
|
+
(omit `→ resolved: …` when the line carries no `[resolved at save: …]` gloss).
|
|
56
|
+
|
|
57
|
+
4. **Start on the next task, if the banner carries one.** It is the **first
|
|
58
|
+
action of the resumed session**, ahead of the general resume agenda — the
|
|
59
|
+
owner wrote it at save time precisely so it would not have to be typed
|
|
60
|
+
again once you came back. Begin it without waiting for a further prompt.
|
|
61
|
+
- It carries the owner's authority the way any owner message does, **with
|
|
62
|
+
the standard limits unchanged**. A next task never by itself approves a
|
|
63
|
+
porch gate, merges a PR, cuts a release, restarts Tower, or performs any
|
|
64
|
+
other act that needs a per-occasion word. If the next task *is* such an
|
|
65
|
+
act, prepare it and ask for the word live: a saved instruction is an
|
|
66
|
+
instruction, not a pre-spent approval.
|
|
67
|
+
- **The gloss carries the word — for the items it names, and only them.**
|
|
68
|
+
Items named in a `[resolved at save: …]` gloss are approved for the act
|
|
69
|
+
the owner's words name: "merge them all [resolved at save: PRs #1710,
|
|
70
|
+
#1712]" means merge #1710 and #1712 without asking again. The owner gave
|
|
71
|
+
the word at save time, and the saving session pinned it to those items.
|
|
72
|
+
This narrows the rule above; it does not remove it — and a line with no
|
|
73
|
+
gloss pre-approves nothing:
|
|
74
|
+
- The act must be the one the owner's words say. **A gloss never widens
|
|
75
|
+
the verb** — "merge" does not also approve a release.
|
|
76
|
+
- **Anything not in the gloss still needs the word live.** A PR that
|
|
77
|
+
appeared after the save, an item the gloss did not name, a gate the
|
|
78
|
+
words did not mention → prepare and ask, exactly as above.
|
|
79
|
+
- Porch gates are still relayed to the builder, never run by you: the
|
|
80
|
+
gloss lets you *relay* the approval without re-asking; it does not
|
|
81
|
+
change who runs `porch approve`.
|
|
82
|
+
- Ordinary verification still applies: an approved merge still waits for
|
|
83
|
+
green CI, and a gloss item you find already merged, closed, or changed
|
|
84
|
+
is reported, not forced.
|
|
85
|
+
- **A line marked `[carried over — …]` is orientation only.** Its gloss
|
|
86
|
+
was written by an earlier cycle and carries no word: ask for it before
|
|
87
|
+
any gated act.
|
|
88
|
+
- **This does not narrow the gate rule.** The human decision was explicit
|
|
89
|
+
at save time, and the gloss is its record. What the rule forbids —
|
|
90
|
+
inferring approval from a gate notification, from silence, or from an
|
|
91
|
+
agent's own judgment — stays forbidden; a gloss is none of those.
|
|
92
|
+
- **Once you have started, delete the `NEXT TASK` line from the banner**
|
|
93
|
+
and record the pickup as a log entry (`picked up next task: <verbatim>
|
|
94
|
+
→ resolved: <gloss>`, omitting `→ resolved: …` when there was no gloss).
|
|
95
|
+
A second re-init, or the next `/arch-save`, must not re-run it.
|
|
96
|
+
|
|
97
|
+
5. **Then follow the state file.** Carry out whatever it says to do on
|
|
98
|
+
resume. Do not invent a new agenda — resume the one the state file
|
|
55
99
|
describes.
|
|
56
100
|
|
|
57
101
|
## Saving your state (and knowing when to `/clear`)
|
|
@@ -118,9 +162,12 @@ Do not repeat it, and do not prompt for it at any other time.
|
|
|
118
162
|
**`/arch-save` packages this whole loop**, and is the preferred path when the
|
|
119
163
|
owner directs a refresh: it stops your monitors, writes the pruned state file,
|
|
120
164
|
clears, and schedules `/arch-init` to bring you back — in that order, which is
|
|
121
|
-
the part that matters.
|
|
122
|
-
|
|
123
|
-
|
|
165
|
+
the part that matters. It also accepts a **next task** as free text
|
|
166
|
+
(`/arch-save file and spawn that issue`), which it writes into the banner as a
|
|
167
|
+
`NEXT TASK` line for step 4 above to pick up. The save discipline above is
|
|
168
|
+
what it performs at its step 3, so this section remains the source of truth
|
|
169
|
+
for *how to write the file*; `/arch-save` is the source of truth for *the
|
|
170
|
+
sequence*. The manual path
|
|
124
171
|
(save → human clears → `/arch-init`) stays valid and is the fallback when
|
|
125
172
|
Tower is unavailable.
|
|
126
173
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: arch-save
|
|
3
3
|
description: Save an architect's state, clear its context, and re-init automatically — the packaged save→clear→re-init refresh cycle. Use when the owner directs a context refresh, or says "/arch-save", "save and clear", "refresh your context". Runs on the owner's direction; an architect does not invoke it autonomously mid-task. Counterpart to /arch-init, which recovers the state this writes.
|
|
4
|
-
argument-hint: "[name] (e.g. main;
|
|
4
|
+
argument-hint: "[name] [next task] (e.g. main; or: file and spawn that issue)"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# /arch-save — save state, clear, and come back as yourself
|
|
@@ -9,7 +9,18 @@ argument-hint: "[name] (e.g. main; omit to auto-detect via afx whoami)"
|
|
|
9
9
|
Long sessions accumulate stale context. This is the deliberate cure: you choose the
|
|
10
10
|
moment, you choose what survives, and a fresh session resumes from what you wrote.
|
|
11
11
|
|
|
12
|
-
`$ARGUMENTS`
|
|
12
|
+
`$ARGUMENTS` carries the architect name, a **next task** for the session that comes back,
|
|
13
|
+
or both:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/arch-save save, clear, re-init, then wait
|
|
17
|
+
/arch-save file and spawn that issue … and start on that first, unprompted
|
|
18
|
+
/arch-save main file and spawn that issue explicit name, then the next task
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The next task is how an owner who already knows what the refreshed session should do first
|
|
22
|
+
says so once, at the moment they direct the refresh, instead of watching for the re-init to
|
|
23
|
+
land and typing it again.
|
|
13
24
|
|
|
14
25
|
## When NOT to run this
|
|
15
26
|
|
|
@@ -28,20 +39,51 @@ action. A mid-task snapshot resumes into confusion.
|
|
|
28
39
|
Do these in order. **The order is the feature** — step 3 must precede step 4, because the
|
|
29
40
|
context that knows what to write is the one about to be destroyed.
|
|
30
41
|
|
|
31
|
-
### 1. Resolve your name
|
|
42
|
+
### 1. Resolve your name, then split off the next task
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
**Always run `afx whoami` first**, whatever `$ARGUMENTS` holds — the split below cannot
|
|
45
|
+
tell a name from a task until it knows your name. The name rules are unchanged:
|
|
35
46
|
|
|
47
|
+
- `type: architect` → the reported `name` is yours.
|
|
36
48
|
- `type: builder` → **STOP.** This terminal is a builder. Report the mismatch.
|
|
37
|
-
- Non-zero exit →
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
- Non-zero exit → you have no name yet. A single-token `$ARGUMENTS` that validates as a
|
|
50
|
+
name is still accepted as one; anything else → **STOP** and ask which architect you are.
|
|
51
|
+
Do **not** guess, and do not default to `main` — writing another architect's state file
|
|
52
|
+
is the exact failure `/arch-init` exists to prevent (#1094).
|
|
40
53
|
|
|
41
54
|
**Validate the name before building any path**: `[a-z][a-z0-9-]*`, at most 64 characters.
|
|
42
55
|
Reject slashes, `..`, uppercase, spaces. Never interpolate an unvalidated name into
|
|
43
56
|
`codev/state/<name>.md`.
|
|
44
57
|
|
|
58
|
+
Then split `$ARGUMENTS`:
|
|
59
|
+
|
|
60
|
+
1. `$ARGUMENTS` is empty → name from `afx whoami`, and there is no next task.
|
|
61
|
+
2. The **first whitespace-separated token** equals the whoami name (or, when whoami could
|
|
62
|
+
not resolve one, is a single token that validates as a name) → that token is the name,
|
|
63
|
+
and the **remainder** is the next-task text, which may be empty.
|
|
64
|
+
3. Otherwise → the **whole** of `$ARGUMENTS` is the next-task text, and the name comes
|
|
65
|
+
from `afx whoami`.
|
|
66
|
+
|
|
67
|
+
So `/arch-save` and `/arch-save main` behave exactly as they always have. The one
|
|
68
|
+
ambiguity — a next task whose first word happens to be your own architect name — is
|
|
69
|
+
accepted rather than worked around: lead with the explicit name
|
|
70
|
+
(`/arch-save main main is stalled, look at it`) to disambiguate.
|
|
71
|
+
|
|
72
|
+
**If you had to ask which architect you are, the next task still stands.** The answer
|
|
73
|
+
supplies the name; `$ARGUMENTS` already supplied the task. Do not make the owner retype it.
|
|
74
|
+
|
|
75
|
+
**Guard, applied after the split: a leading token that names a *different* architect stops
|
|
76
|
+
you.** If the first token validates as a name, differs from the name whoami reported, and
|
|
77
|
+
`codev/state/<token>.md` exists → **STOP and ask which architect you are. Write nothing.**
|
|
78
|
+
whoami can be wrong (#1094), and rule 3 would otherwise bury a real name-override inside
|
|
79
|
+
next-task text and save to whoami's file; a task that merely opens with a sibling's name is
|
|
80
|
+
the only case this costs, and it costs one clarification.
|
|
81
|
+
|
|
82
|
+
**This is not how `/arch-init` resolves a name**, and the asymmetry is deliberate:
|
|
83
|
+
`/arch-init` takes no next task, so any non-empty argument there is unambiguously a name
|
|
84
|
+
and overrides whoami outright. Here the first token is weighed *against* whoami, which is
|
|
85
|
+
why the guard above exists — never save into a name you did not verify.
|
|
86
|
+
|
|
45
87
|
### 2. Stop your own monitors
|
|
46
88
|
|
|
47
89
|
Enumerate every monitor, watcher or background task you armed, and stop it.
|
|
@@ -75,6 +117,50 @@ first (`cp codev/state/<name>.md codev/state/.<name>.bak.md`) is cheap insurance
|
|
|
75
117
|
**Content guardrails.** No secrets — tokens, keys, credentials. No transcript dumps, no
|
|
76
118
|
raw tool output. Only: current focus, open loops, and what a fresh session needs to resume.
|
|
77
119
|
|
|
120
|
+
**Write the next task into the banner**, if step 1 produced one. Add a single line to the
|
|
121
|
+
banner block, directly after the `⭐ THIS /clear IS INTENTIONAL` line:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
# ⏭ NEXT TASK (owner-directed at save, 2026-09-19T02:10Z): file and spawn that issue
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- **Verbatim.** Collapse newlines to spaces; do not paraphrase, expand, or "helpfully"
|
|
128
|
+
plan it. Those are the owner's words, and the context writing them down is the one about
|
|
129
|
+
to be destroyed — this is the last moment at which a paraphrase can be caught.
|
|
130
|
+
- **New text replaces** any existing NEXT TASK line.
|
|
131
|
+
- **No new text preserves an existing one.** A NEXT TASK line still in the banner means the
|
|
132
|
+
previous cycle never came back to pick it up; dropping it silently would lose an owner
|
|
133
|
+
instruction that nothing else is holding. **Mark it carried over when you preserve it:**
|
|
134
|
+
append `[carried over — gloss orients only; re-confirm before acting]` to the line (once;
|
|
135
|
+
a line already marked stays as it is). A gloss carries the owner's word only for the
|
|
136
|
+
cycle that wrote it.
|
|
137
|
+
|
|
138
|
+
**Then resolve its referents — resolve, don't plan.** After the clear, "them" points at
|
|
139
|
+
nothing; this context is the only one that knows what the owner meant. So pin every
|
|
140
|
+
referent in the owner's words to a concrete, durable identifier, and append it to the same
|
|
141
|
+
line, after the verbatim text, as a `[resolved at save: …]` gloss:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
# ⏭ NEXT TASK (owner-directed at save, 2026-09-22T13:40Z): merge them all [resolved at save: PRs #1710, #1712, #1715]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- **Every referent.** Pronouns and deictics — "them", "that issue", "his PR", "the failing
|
|
148
|
+
one" — become PR numbers, issue numbers, builder ids, branch names, file paths.
|
|
149
|
+
- **Resolution only.** The gloss names *what*, never *how*: no steps, no ordering, no
|
|
150
|
+
caveats, no "after CI is green". A gloss that contains a plan has overstepped; the
|
|
151
|
+
resumed session plans.
|
|
152
|
+
- **No referents → no gloss.** `/arch-save review PR #1712` needs nothing; write the line
|
|
153
|
+
as above without one. Never add an empty or redundant gloss.
|
|
154
|
+
- **Cannot resolve → do not clear.** If any referent is ambiguous or unknown to you,
|
|
155
|
+
**stop before step 4** and ask the owner which items are meant. Clearing with an
|
|
156
|
+
unresolved task destroys the only context that could have answered. This is the one
|
|
157
|
+
case where `/arch-save` may pause its own cycle — it is cheap, and the alternative is a
|
|
158
|
+
wrong merge. Tell the owner your monitors are already stopped (step 2), and on their
|
|
159
|
+
answer resume from here: write the gloss, then continue to step 4.
|
|
160
|
+
|
|
161
|
+
The gloss is more than orientation: `/arch-init` treats the items it names as approved for
|
|
162
|
+
the act the owner's words name, so it is how the owner's word survives the clear.
|
|
163
|
+
|
|
78
164
|
Use the template at the end of this document.
|
|
79
165
|
|
|
80
166
|
### 4. Clear
|
|
@@ -160,12 +246,17 @@ literal text on the front of the next message never executes.
|
|
|
160
246
|
|
|
161
247
|
The structure below comes from a live run of this cycle. Every element earns its place;
|
|
162
248
|
keep them all, including a `MONITORS:` line even when the answer is "none armed" — an
|
|
163
|
-
omitted monitor list is indistinguishable from a forgotten one.
|
|
249
|
+
omitted monitor list is indistinguishable from a forgotten one. The `NEXT TASK` line is the
|
|
250
|
+
single exception: it appears only when there is one.
|
|
164
251
|
|
|
165
252
|
```
|
|
166
253
|
# <lane> architect — state (vNN, <date> ~HH:MM UTC — <milestone>, DELIBERATE /clear cycle)
|
|
167
254
|
# ⭐ THIS /clear IS INTENTIONAL (owner-directed context refresh). On re-init: normal
|
|
168
255
|
# /arch-init flow, then:
|
|
256
|
+
# ⏭ NEXT TASK (owner-directed at save, <ISO timestamp>): <the owner's words, verbatim> [resolved at save: <referents>]
|
|
257
|
+
# — OPTIONAL; present only when the save carried one. The `[resolved at save: …]` gloss
|
|
258
|
+
# is optional too: present only when the words had referents to resolve. /arch-init
|
|
259
|
+
# starts here before the agenda below, then deletes this line and logs the pickup.
|
|
169
260
|
# 1. MONITORS: <what to stop if it is still firing, then what to re-arm> — watch target,
|
|
170
261
|
# cadence, alert pattern. Self-test once before trusting alerts. ("none armed" is a
|
|
171
262
|
# valid and complete answer.)
|
|
@@ -24,6 +24,15 @@ The `-m` / `--model` flag is **always required** except for `consult stats`.
|
|
|
24
24
|
| `codex` | `gpt` | Thorough (~200-250s), shell exploration |
|
|
25
25
|
| `claude` | `opus` | Agent SDK with tool use (~60-120s) |
|
|
26
26
|
|
|
27
|
+
## Credentials and `.env`
|
|
28
|
+
|
|
29
|
+
`consult` loads `<workspace>/.env` and sets every key the shell does not already define, **credentials included**. Those override your stored login:
|
|
30
|
+
|
|
31
|
+
- claude: `CLAUDE_CODE_OAUTH_TOKEN` (or `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_API_KEY`) beats the keychain login. When an OAuth token is set, the API keys are dropped.
|
|
32
|
+
- codex: `CODEX_API_KEY` beats the ChatGPT login. `OPENAI_API_KEY` is ignored.
|
|
33
|
+
|
|
34
|
+
Each SDK lane prints what it authenticates with, e.g. `[CLAUDE] auth: CLAUDE_CODE_OAUTH_TOKEN (from .env)`. If a review fails with a usage-limit or auth error while your own login works, check that line first. A key exported in the shell wins over `.env`.
|
|
35
|
+
|
|
27
36
|
## All flags
|
|
28
37
|
|
|
29
38
|
```
|