@cluesmith/codev 3.3.0 → 3.3.2
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-JCbkpAcV.js → index-D3XaKpZW.js} +45 -43
- package/dashboard-dist/assets/index-D3XaKpZW.js.map +1 -0
- package/dashboard-dist/index.html +1 -1
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +99 -36
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/reset/constants.d.ts +119 -1
- package/dist/agent-farm/commands/reset/constants.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset/constants.js +119 -1
- package/dist/agent-farm/commands/reset/constants.js.map +1 -1
- package/dist/agent-farm/commands/reset/context.d.ts +20 -2
- package/dist/agent-farm/commands/reset/context.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset/context.js +44 -3
- package/dist/agent-farm/commands/reset/context.js.map +1 -1
- package/dist/agent-farm/commands/reset/index.d.ts +7 -7
- package/dist/agent-farm/commands/reset/index.js +8 -8
- package/dist/agent-farm/commands/reset/index.js.map +1 -1
- package/dist/agent-farm/commands/reset/receipt.d.ts +1 -1
- package/dist/agent-farm/commands/reset/receipt.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset/receipt.js +19 -8
- package/dist/agent-farm/commands/reset/receipt.js.map +1 -1
- package/dist/agent-farm/commands/reset/reorient.d.ts +1 -1
- package/dist/agent-farm/commands/reset/reorient.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset/reorient.js +12 -5
- package/dist/agent-farm/commands/reset/reorient.js.map +1 -1
- package/dist/agent-farm/commands/reset/self.d.ts +335 -0
- package/dist/agent-farm/commands/reset/self.d.ts.map +1 -0
- package/dist/agent-farm/commands/reset/self.js +636 -0
- package/dist/agent-farm/commands/reset/self.js.map +1 -0
- package/dist/agent-farm/commands/reset.d.ts +18 -3
- package/dist/agent-farm/commands/reset.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset.js +55 -33
- package/dist/agent-farm/commands/reset.js.map +1 -1
- package/dist/agent-farm/commands/self-refresh.d.ts +60 -0
- package/dist/agent-farm/commands/self-refresh.d.ts.map +1 -0
- package/dist/agent-farm/commands/self-refresh.js +506 -0
- package/dist/agent-farm/commands/self-refresh.js.map +1 -0
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +27 -2
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/spawn.d.ts +7 -0
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +13 -1
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +13 -0
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/lib/reconnect-backoff.d.ts +10 -0
- package/dist/agent-farm/lib/reconnect-backoff.d.ts.map +1 -1
- package/dist/agent-farm/lib/reconnect-backoff.js +10 -0
- package/dist/agent-farm/lib/reconnect-backoff.js.map +1 -1
- package/dist/agent-farm/lib/tower-client.d.ts +12 -0
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tower-client.js +12 -0
- package/dist/agent-farm/lib/tower-client.js.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +7 -3
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/canvas-relay.d.ts +60 -0
- package/dist/agent-farm/servers/canvas-relay.d.ts.map +1 -0
- package/dist/agent-farm/servers/canvas-relay.js +376 -0
- package/dist/agent-farm/servers/canvas-relay.js.map +1 -0
- package/dist/agent-farm/servers/gate-profiles.d.ts +1 -1
- package/dist/agent-farm/servers/gate-profiles.js +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.d.ts +141 -13
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.js +172 -16
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +24 -2
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.js +92 -32
- package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -1
- package/dist/agent-farm/servers/message-write.d.ts +58 -18
- package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
- package/dist/agent-farm/servers/message-write.js +73 -28
- package/dist/agent-farm/servers/message-write.js.map +1 -1
- package/dist/agent-farm/servers/overview.d.ts +19 -0
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +78 -1
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/render-gate.d.ts +13 -0
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
- package/dist/agent-farm/servers/render-gate.js +21 -0
- package/dist/agent-farm/servers/render-gate.js.map +1 -1
- package/dist/agent-farm/servers/session-submit.d.ts +221 -28
- package/dist/agent-farm/servers/session-submit.d.ts.map +1 -1
- package/dist/agent-farm/servers/session-submit.js +334 -43
- package/dist/agent-farm/servers/session-submit.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +269 -64
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +25 -3
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +6 -0
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +30 -5
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-tunnel.js +14 -0
- package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts +6 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +90 -37
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/types.d.ts +37 -2
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/harness.d.ts +3 -3
- package/dist/agent-farm/utils/harness.js +1 -1
- package/dist/agent-farm/utils/message-format.d.ts +67 -3
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
- package/dist/agent-farm/utils/message-format.js +127 -14
- package/dist/agent-farm/utils/message-format.js.map +1 -1
- package/dist/agent-farm/utils/server-utils.d.ts +86 -4
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +303 -5
- package/dist/agent-farm/utils/server-utils.js.map +1 -1
- package/dist/commands/porch/context-refresh.d.ts +181 -0
- package/dist/commands/porch/context-refresh.d.ts.map +1 -0
- package/dist/commands/porch/context-refresh.js +270 -0
- package/dist/commands/porch/context-refresh.js.map +1 -0
- package/dist/commands/porch/index.d.ts +6 -0
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +46 -0
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/porch/next.d.ts +0 -9
- package/dist/commands/porch/next.d.ts.map +1 -1
- package/dist/commands/porch/next.js +133 -4
- package/dist/commands/porch/next.js.map +1 -1
- package/dist/commands/porch/protocol.d.ts.map +1 -1
- package/dist/commands/porch/protocol.js +102 -0
- package/dist/commands/porch/protocol.js.map +1 -1
- package/dist/commands/porch/types.d.ts +61 -0
- package/dist/commands/porch/types.d.ts.map +1 -1
- package/dist/lib/forge-contracts.d.ts +9 -0
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/github.d.ts +15 -1
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +17 -0
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/self-refresh-invocation.d.ts +60 -0
- package/dist/lib/self-refresh-invocation.d.ts.map +1 -0
- package/dist/lib/self-refresh-invocation.js +64 -0
- package/dist/lib/self-refresh-invocation.js.map +1 -0
- package/dist/lib/test-env.d.ts +50 -0
- package/dist/lib/test-env.d.ts.map +1 -1
- package/dist/lib/test-env.js +76 -0
- package/dist/lib/test-env.js.map +1 -1
- package/dist/terminal/attach-replay.d.ts +39 -0
- package/dist/terminal/attach-replay.d.ts.map +1 -0
- package/dist/terminal/attach-replay.js +76 -0
- package/dist/terminal/attach-replay.js.map +1 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +35 -17
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +81 -12
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +113 -25
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/session-screen.d.ts +25 -0
- package/dist/terminal/session-screen.d.ts.map +1 -1
- package/dist/terminal/session-screen.js +53 -8
- package/dist/terminal/session-screen.js.map +1 -1
- package/package.json +10 -7
- package/scripts/forge/gitea/pr-view.sh +4 -1
- package/scripts/forge/github/pr-view.sh +1 -1
- package/scripts/forge/gitlab/pr-view.sh +4 -1
- package/skeleton/.claude/skills/afx/SKILL.md +54 -0
- package/skeleton/.claude/skills/arch-save/SKILL.md +8 -2
- package/skeleton/.claude/skills/builder-refresh/SKILL.md +138 -0
- package/skeleton/.codex/skills/afx/SKILL.md +54 -0
- package/skeleton/.codex/skills/arch-save/SKILL.md +8 -2
- package/skeleton/.codex/skills/builder-refresh/SKILL.md +138 -0
- package/skeleton/protocol-schema.json +17 -0
- package/skeleton/protocols/air/protocol.json +1 -1
- package/skeleton/protocols/aspir/protocol.json +5 -1
- package/skeleton/protocols/bugfix/protocol.json +1 -1
- package/skeleton/protocols/experiment/protocol.json +1 -1
- package/skeleton/protocols/maintain/protocol.json +1 -1
- package/skeleton/protocols/pir/builder-prompt.md +3 -2
- package/skeleton/protocols/pir/prompts/implement.md +1 -1
- package/skeleton/protocols/pir/prompts/plan.md +1 -1
- package/skeleton/protocols/pir/prompts/review.md +1 -1
- package/skeleton/protocols/pir/protocol.json +1 -1
- package/skeleton/protocols/pir/protocol.md +4 -4
- package/skeleton/protocols/protocol-schema.json +17 -0
- package/skeleton/protocols/research/protocol.json +1 -1
- package/skeleton/protocols/spike/protocol.json +1 -1
- package/skeleton/protocols/spir/protocol.json +5 -1
- package/skeleton/resources/commands/agent-farm.md +14 -11
- package/skeleton/roles/builder.md +3 -4
- package/templates/3d-viewer.html +32 -4
- package/templates/open.html +58 -12
- package/templates/tower.html +26 -7
- package/templates/vendor/three-3MFLoader.js +1478 -0
- package/templates/vendor/three-STLLoader.js +410 -0
- package/templates/vendor/three-TrackballControls.js +828 -0
- package/templates/vendor/three-fflate.module.js +2474 -0
- package/templates/vendor/three.module.js +53044 -0
- package/dashboard-dist/assets/index-JCbkpAcV.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-screen.d.ts","sourceRoot":"","sources":["../../src/terminal/session-screen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;
|
|
1
|
+
{"version":3,"file":"session-screen.d.ts","sourceRoot":"","sources":["../../src/terminal/session-screen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAQH,OAAO,KAAK,EAAE,QAAQ,IAAI,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AAsBpF,wFAAwF;AACxF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsC;IACjE,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAS;IAItB,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,QAAQ,CAAS;gBAEb,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAWtC;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOxC;;;;;;;;;;;;;;;;OAgBG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAMjC;;;;;;;;;;;;;OAaG;IACH,SAAS,IAAI,MAAM;IAKnB;;;;;;;OAOG;IACH,IAAI,UAAU,IAAI,QAAQ,GAAG,WAAW,CAEvC;IAED,0DAA0D;IAC1D,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,0FAA0F;IAC1F,OAAO,IAAI,IAAI;CAUhB"}
|
|
@@ -40,19 +40,29 @@
|
|
|
40
40
|
// and its named exports are not statically analyzable, so a native-node ESM
|
|
41
41
|
// `import { Terminal }` throws "Named export 'Terminal' not found" under the compiled
|
|
42
42
|
// dist (see the identical note in render-gate.ts). Default-import the module object.
|
|
43
|
+
// `@xterm/addon-serialize` ships the same way (same repo and release train).
|
|
43
44
|
import xtermHeadless from '@xterm/headless';
|
|
45
|
+
import xtermSerialize from '@xterm/addon-serialize';
|
|
44
46
|
const { Terminal } = xtermHeadless;
|
|
47
|
+
const { SerializeAddon } = xtermSerialize;
|
|
45
48
|
/**
|
|
46
|
-
* Scrollback retained by the mirror
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* Scrollback retained by the mirror, now serving two consumers (PIR #1354):
|
|
50
|
+
*
|
|
51
|
+
* - The render gate reads ONLY the current viewport (`viewportY … viewportY + rows`),
|
|
52
|
+
* never scrollback, and its verdict is identical for any scrollback ≥ rows (asserted
|
|
53
|
+
* by the production-path tests) — so for the gate this value is a free variable.
|
|
54
|
+
* - {@link SessionScreen.serialize} is the viewer-attach replay payload, and its
|
|
55
|
+
* scrollback IS the history a reconnecting viewer gets back. 1000 matches the ring
|
|
56
|
+
* buffer's default line capacity (`ringBufferLines`), so snapshot replay does not
|
|
57
|
+
* regress history depth versus the raw-ring replay it replaces.
|
|
58
|
+
*
|
|
59
|
+
* Memory: measured ~509 KB per fully-scrolled 200x50 terminal at 1000 lines (~215 KB
|
|
60
|
+
* at the previous 200) — the bounded per-session budget the plan commits to.
|
|
52
61
|
*/
|
|
53
|
-
const
|
|
62
|
+
const SCREEN_SCROLLBACK = 1000;
|
|
54
63
|
export class SessionScreen {
|
|
55
64
|
term;
|
|
65
|
+
serializer;
|
|
56
66
|
_cols;
|
|
57
67
|
_rows;
|
|
58
68
|
// Promise of the most recently issued write's parse completion. `@xterm/headless`
|
|
@@ -63,7 +73,12 @@ export class SessionScreen {
|
|
|
63
73
|
constructor(cols, rows) {
|
|
64
74
|
this._cols = cols;
|
|
65
75
|
this._rows = rows;
|
|
66
|
-
this.term = new Terminal({ cols, rows, allowProposedApi: true, scrollback:
|
|
76
|
+
this.term = new Terminal({ cols, rows, allowProposedApi: true, scrollback: SCREEN_SCROLLBACK });
|
|
77
|
+
this.serializer = new SerializeAddon();
|
|
78
|
+
// The addon's typings bind to the full `@xterm/xterm` Terminal; its runtime touches
|
|
79
|
+
// only the buffer/parser surface the headless build shares (proven by the round-trip
|
|
80
|
+
// suite), so the declared-type gap is bridged explicitly here.
|
|
81
|
+
this.term.loadAddon(this.serializer);
|
|
67
82
|
}
|
|
68
83
|
/**
|
|
69
84
|
* Fold one chunk of PTY output into the screen. Called at the session's single output
|
|
@@ -112,6 +127,36 @@ export class SessionScreen {
|
|
|
112
127
|
await this.pending;
|
|
113
128
|
return { term: this.term, cols: this._cols, rows: this._rows };
|
|
114
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Serialize the current screen state (both buffers, colors/attrs, cursor, alt-screen
|
|
132
|
+
* mode, plus up to {@link SCREEN_SCROLLBACK} lines of history) back into a terminal
|
|
133
|
+
* byte stream a client can replay — the O(screen) viewer-attach payload (PIR #1354).
|
|
134
|
+
*
|
|
135
|
+
* SYNCHRONOUS by design: it reads whatever is parsed into the grid right now.
|
|
136
|
+
* Callers wanting a coherent frame must flush first ({@link read}) and must call this
|
|
137
|
+
* with no intervening `await` afterward — the same no-interleave discipline the render
|
|
138
|
+
* gate's classifier relies on. `PtySession.replaySnapshot` owns that protocol.
|
|
139
|
+
*
|
|
140
|
+
* Throws whatever the addon throws; the caller maps failures to the raw-replay
|
|
141
|
+
* fallback. After {@link dispose} the term is freed — return '' rather than touching it
|
|
142
|
+
* (callers treat an empty snapshot for a non-empty session as a fallback signal).
|
|
143
|
+
*/
|
|
144
|
+
serialize() {
|
|
145
|
+
if (this.disposed)
|
|
146
|
+
return '';
|
|
147
|
+
return this.serializer.serialize({ scrollback: SCREEN_SCROLLBACK });
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Which buffer the emulated app is currently in. 'alternate' identifies the
|
|
151
|
+
* full-screen-TUI case whose delta resume is unservable from the line-based ring
|
|
152
|
+
* (`RingBuffer.getSince` returns [] for a caught-up client), so the attach path
|
|
153
|
+
* routes it to {@link serialize} instead. Read without flushing: worst case the
|
|
154
|
+
* routing decision lags the last few unparsed bytes, and both routes remain correct
|
|
155
|
+
* (the raw path keeps its client-nudge recovery).
|
|
156
|
+
*/
|
|
157
|
+
get bufferType() {
|
|
158
|
+
return this.term.buffer.active.type;
|
|
159
|
+
}
|
|
115
160
|
/** Current mirror geometry (matches the live session). */
|
|
116
161
|
get cols() {
|
|
117
162
|
return this._cols;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-screen.js","sourceRoot":"","sources":["../../src/terminal/session-screen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,wFAAwF;AACxF,4EAA4E;AAC5E,sFAAsF;AACtF,qFAAqF;AACrF,OAAO,aAAa,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"session-screen.js","sourceRoot":"","sources":["../../src/terminal/session-screen.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cluesmith/codev",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.2",
|
|
4
4
|
"description": "Codev CLI - AI-assisted software development framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"@anthropic-ai/claude-agent-sdk": "^0.2.41",
|
|
25
25
|
"@google/genai": "^1.0.0",
|
|
26
26
|
"@openai/codex-sdk": "^0.146.0",
|
|
27
|
+
"@xterm/addon-serialize": "^0.14.0",
|
|
27
28
|
"@xterm/headless": "^6.0.0",
|
|
28
29
|
"better-sqlite3": "^12.10.0",
|
|
29
30
|
"chalk": "^5.3.0",
|
|
@@ -34,24 +35,25 @@
|
|
|
34
35
|
"open": "^10.1.0",
|
|
35
36
|
"tree-kill": "^1.2.2",
|
|
36
37
|
"ws": "^8.18.0",
|
|
37
|
-
"@cluesmith/codev-core": "3.3.
|
|
38
|
-
"@cluesmith/codev-sdk": "3.3.
|
|
38
|
+
"@cluesmith/codev-core": "3.3.2",
|
|
39
|
+
"@cluesmith/codev-sdk": "3.3.2",
|
|
40
|
+
"@cluesmith/codev-types": "3.3.2"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@playwright/test": "^1.58.0",
|
|
42
|
-
"@xterm/xterm": "^5.5.0",
|
|
43
44
|
"@types/better-sqlite3": "^7.6.13",
|
|
44
45
|
"@types/js-yaml": "^4.0.9",
|
|
45
46
|
"@types/node": "^22.10.1",
|
|
46
47
|
"@types/ws": "^8.18.1",
|
|
47
48
|
"@vitest/coverage-v8": "^4.0.18",
|
|
49
|
+
"@xterm/xterm": "^5.5.0",
|
|
48
50
|
"jsdom": "^28.1.0",
|
|
49
51
|
"playwright": "^1.58.0",
|
|
52
|
+
"three": "0.160.0",
|
|
50
53
|
"tsx": "^4.19.2",
|
|
51
54
|
"typescript": "^6.0.3",
|
|
52
55
|
"vitest": "^4.0.15",
|
|
53
|
-
"@cluesmith/codev-web": "0.0.0"
|
|
54
|
-
"@cluesmith/codev-types": "3.3.0"
|
|
56
|
+
"@cluesmith/codev-web": "0.0.0"
|
|
55
57
|
},
|
|
56
58
|
"engines": {
|
|
57
59
|
"node": ">=20.0.0"
|
|
@@ -73,7 +75,8 @@
|
|
|
73
75
|
},
|
|
74
76
|
"scripts": {
|
|
75
77
|
"clean": "rm -rf dist",
|
|
76
|
-
"build": "pnpm --filter \"@cluesmith/codev^...\" build && pnpm clean && tsc && pnpm
|
|
78
|
+
"build": "pnpm --filter \"@cluesmith/codev^...\" build && pnpm clean && tsc && pnpm bundle-assets",
|
|
79
|
+
"bundle-assets": "pnpm copy-dashboard && pnpm copy-skeleton && node ./scripts/copy-three.mjs",
|
|
77
80
|
"copy-dashboard": "rm -rf dashboard-dist && cp -r ../../apps/web/dist dashboard-dist",
|
|
78
81
|
"dev:dashboard": "cd ../../apps/web && pnpm dev",
|
|
79
82
|
"copy-skeleton": "rm -rf skeleton && cp -r ../../codev-skeleton skeleton",
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: pr-view (Gitea via tea CLI)
|
|
3
|
-
|
|
3
|
+
# Sets `url` to the PR's browser page (`html_url`). Gitea's own `url` field is
|
|
4
|
+
# the API endpoint (would render raw JSON in a browser), so we prefer `html_url`
|
|
5
|
+
# and fall back to the existing `url` only if `html_url` is absent.
|
|
6
|
+
tea pulls view "$CODEV_PR_NUMBER" --output json | jq '.url = (.html_url // .url)'
|
|
@@ -7,5 +7,5 @@ if [ "$CODEV_INCLUDE_COMMENTS" = "1" ]; then
|
|
|
7
7
|
exec gh pr view "$CODEV_PR_NUMBER" --comments
|
|
8
8
|
else
|
|
9
9
|
exec gh pr view "$CODEV_PR_NUMBER" \
|
|
10
|
-
--json title,body,state,author,baseRefName,headRefName,additions,deletions
|
|
10
|
+
--json title,body,state,url,author,baseRefName,headRefName,additions,deletions
|
|
11
11
|
fi
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: pr-view (GitLab via glab CLI)
|
|
3
|
-
|
|
3
|
+
# Adds a `url` field mapped from GitLab's `web_url` (the MR's browser page);
|
|
4
|
+
# all other fields glab emits are passed through unchanged. `. + {url: …}` is
|
|
5
|
+
# non-destructive — if `web_url` is absent, `url` is null (optional by contract).
|
|
6
|
+
glab mr view "$CODEV_PR_NUMBER" --output json | jq '. + {url: .web_url}'
|
|
@@ -69,6 +69,60 @@ afx send 0042 "PR approved, please merge"
|
|
|
69
69
|
afx send 0585 "check the test output" --file /tmp/test-results.txt
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
## afx interrupt
|
|
73
|
+
|
|
74
|
+
Sends an ESC keystroke to a builder's PTY — the only thing that reaches it **mid-turn**.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
afx interrupt <builder>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Flag | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `--no-enter` | Send ESC alone, without the trailing Enter |
|
|
83
|
+
|
|
84
|
+
A builder chaining foreground waits inside one turn queues every `afx send` unread — including your order
|
|
85
|
+
to stop. ESC ends the turn so the queue processes. Distinct from `afx send --interrupt` (Ctrl+C).
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
afx interrupt 0042
|
|
89
|
+
afx send 0042 "That producer died — stop waiting and report."
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## afx refresh
|
|
93
|
+
|
|
94
|
+
Refreshes a builder's context: save working state → `/clear` → re-orient. Use when a builder's context window
|
|
95
|
+
is exhausted; `afx spawn --resume` reattaches the *same* conversation and does **not** give it a fresh one.
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
afx refresh <builder>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Flag | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `--dry-run` | Print what would be sent; write nothing to the builder |
|
|
104
|
+
| `--note <text>` | Extra context appended to the re-orientation |
|
|
105
|
+
| `--file <path>` | Append file content (48KB max, read from *your* filesystem) |
|
|
106
|
+
| `--interrupt-first` | ESC before the save request, for a builder already wedged |
|
|
107
|
+
| `--mode <strict\|soft>` | Override mode if it cannot be detected |
|
|
108
|
+
| `--timeout <seconds>` | Wait for the save-state receipt (default 300) |
|
|
109
|
+
| `--min-bytes <n>` | Minimum state-file size to accept (default 1000) |
|
|
110
|
+
| `--quiet-window <ms>` | Terminal silence counting as turn-ended (default 1500) |
|
|
111
|
+
|
|
112
|
+
Every gate fails safe: if the state file never arrives, carries a stale nonce, is a stub, is still being
|
|
113
|
+
written, or the builder will not go quiet, the command **aborts without clearing** and exits non-zero,
|
|
114
|
+
naming the gate. Requires a harness with in-session context clearing (Claude Code); others abort loudly.
|
|
115
|
+
|
|
116
|
+
`afx reset` is a deprecated alias: it still works, prints a one-line notice to stderr, and will be removed
|
|
117
|
+
in a future release.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
afx refresh 0042 --dry-run # inspect first — touches nothing
|
|
121
|
+
afx refresh 0042
|
|
122
|
+
afx refresh 0042 --note "PR #90 merged while you were mid-phase. Rebase first."
|
|
123
|
+
afx refresh 0042 --interrupt-first # builder is wedged mid-turn
|
|
124
|
+
```
|
|
125
|
+
|
|
72
126
|
## afx cleanup
|
|
73
127
|
|
|
74
128
|
Removes a builder's worktree and branch after work is done.
|
|
@@ -107,8 +107,14 @@ guarantee about the clear's completion. If the timing is wrong the re-init arriv
|
|
|
107
107
|
wrong moment, which costs one manual message (see below) and nothing else. That is the
|
|
108
108
|
whole reason this cycle can be built on a delay rather than on machinery.
|
|
109
109
|
|
|
110
|
-
Delayed sends are
|
|
111
|
-
|
|
110
|
+
Delayed sends **are persisted**. The body is written to the durable mailbox at request time
|
|
111
|
+
with a `not_before` timestamp, so Tower keeps no timer for it and a restart inside the window
|
|
112
|
+
does not lose it — the re-init is delivered once the delay passes. The one thing a restart does
|
|
113
|
+
drop is the Ctrl+C nudge of a delayed `--interrupt`, which this cycle does not use.
|
|
114
|
+
|
|
115
|
+
That removes a failure mode this section used to warn about, but not the need for the recovery
|
|
116
|
+
path below: delivery still waits on an empty prompt, so a re-init can arrive late rather than
|
|
117
|
+
never.
|
|
112
118
|
|
|
113
119
|
**If this send fails, do not end your turn.** Step 4 queued the `/clear`, but it does not
|
|
114
120
|
take effect until your turn ends — so at this moment you still have your full context and
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: builder-refresh
|
|
3
|
+
description: Refresh a builder's own context at a protocol boundary — save working state, verify it, clear, and re-orient. Use when porch emits a context-refresh task, or the builder is told to "refresh your context" / "run a self-refresh". A builder does not invoke this autonomously mid-task; porch chooses the moment. Counterpart to the architect's /arch-save.
|
|
4
|
+
argument-hint: "(none — porch's refresh task supplies the commands)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /builder-refresh — save, clear, and come back knowing where you are
|
|
8
|
+
|
|
9
|
+
You are a builder that has reached a protocol boundary. Your context can be discarded
|
|
10
|
+
here safely, because everything that matters is already on disk: the spec, the plan,
|
|
11
|
+
`status.yaml`, your thread narrative, and git history. A fresh context re-orients from
|
|
12
|
+
those artifacts rather than from memory.
|
|
13
|
+
|
|
14
|
+
**The enforcement is in the command, not in this document.** `afx self-refresh` refuses to
|
|
15
|
+
clear on an unverified save, refuses when the re-entry cannot be scheduled, and refuses
|
|
16
|
+
when your worktree has uncommitted tracked changes. This skill sequences the steps and
|
|
17
|
+
explains the judgement calls; it cannot and does not decide whether the clear is safe.
|
|
18
|
+
|
|
19
|
+
## When NOT to run this
|
|
20
|
+
|
|
21
|
+
**Porch chooses the moment. You do not.** Run this when porch's refresh task tells you to,
|
|
22
|
+
or when the architect directs it. Do not invoke it mid-task on your own judgement — a
|
|
23
|
+
boundary is a point a fresh context can resume *from*, and a mid-task snapshot resumes into
|
|
24
|
+
confusion.
|
|
25
|
+
|
|
26
|
+
If you are not at a boundary and think you need a refresh anyway, say so to the architect
|
|
27
|
+
rather than doing it: `afx send architect "..."`.
|
|
28
|
+
|
|
29
|
+
## The procedure
|
|
30
|
+
|
|
31
|
+
### 1. Use the commands porch gave you
|
|
32
|
+
|
|
33
|
+
Porch's refresh task contains the exact two commands for this boundary, including the
|
|
34
|
+
`--boundary` flag. **Run those, verbatim.**
|
|
35
|
+
|
|
36
|
+
Do not retype them from memory and do not omit the flag. `--boundary` binds the challenge
|
|
37
|
+
to the boundary it was issued at, so a challenge left behind by an aborted refresh cannot
|
|
38
|
+
be used to clear you at a *later* boundary, against a save describing work that has since
|
|
39
|
+
moved on. That guard has been silently disabled twice by an instruction that dropped the
|
|
40
|
+
flag, which is why this document deliberately does not restate the commands.
|
|
41
|
+
|
|
42
|
+
If you arrived here without a porch task — an architect-directed refresh, say — there is no
|
|
43
|
+
boundary to bind, and the flagless form is correct. Run `afx self-refresh --help` for the
|
|
44
|
+
exact spelling rather than guessing it.
|
|
45
|
+
|
|
46
|
+
### 2. Write your working state
|
|
47
|
+
|
|
48
|
+
The first command prints a save request naming a file and a marker line. Write that file.
|
|
49
|
+
|
|
50
|
+
**The marker must be the FIRST LINE**, reproduced exactly. A save whose nonce appears
|
|
51
|
+
further down is refused — that check exists because echoing the request back into the file
|
|
52
|
+
otherwise passed every gate, and echoing instructions is something agents do by accident.
|
|
53
|
+
|
|
54
|
+
**Write for a cold reader** — a competent agent that wakes up with your worktree, your
|
|
55
|
+
branch, and no memory of this conversation. Most of your state is already on disk, so do
|
|
56
|
+
not restate the spec or the plan. Carry only what the artifacts do not contain:
|
|
57
|
+
|
|
58
|
+
- **receipts** — what is done and *verified*, with paths and commit hashes, distinguishing
|
|
59
|
+
"written" from "verified";
|
|
60
|
+
- **deviations** from the plan, and why;
|
|
61
|
+
- **flaky or skipped tests**, and what you did about them;
|
|
62
|
+
- **deferred work**, and the reason;
|
|
63
|
+
- **standing orders** from the architect you are still bound by, including anything you
|
|
64
|
+
were told NOT to do;
|
|
65
|
+
- **the next concrete action**.
|
|
66
|
+
|
|
67
|
+
Pointers, not prose. The save has a minimum size, and it is not a word count to pad — a
|
|
68
|
+
file below it is indistinguishable from a stub. If you genuinely have less than that to
|
|
69
|
+
say, you are probably omitting receipts or standing orders.
|
|
70
|
+
|
|
71
|
+
### 3. Run the execute command, then stop
|
|
72
|
+
|
|
73
|
+
The second command verifies your save, writes a re-orientation to disk, schedules your
|
|
74
|
+
re-entry, and clears you — in that order, and only if every step succeeds.
|
|
75
|
+
|
|
76
|
+
**Then end your turn.** Do not start new work. The clear takes effect when the turn ends.
|
|
77
|
+
|
|
78
|
+
## If it refuses
|
|
79
|
+
|
|
80
|
+
Most refusals happen **before** anything destructive, and those leave your context
|
|
81
|
+
untouched. One does not. Read which you got.
|
|
82
|
+
|
|
83
|
+
### Pre-clear refusals — your context is intact
|
|
84
|
+
|
|
85
|
+
| Refusal | What it means |
|
|
86
|
+
|---|---|
|
|
87
|
+
| state file missing / too small / wrong nonce | Your save did not satisfy the gate — check the marker is on line 1 |
|
|
88
|
+
| worktree has uncommitted tracked changes | Commit first; a refreshed context re-orients from git, so uncommitted work is invisible to it |
|
|
89
|
+
| Tower is not running, or did not schedule the re-entry | Clearing would strand you, so it refused |
|
|
90
|
+
| challenge missing / already consumed / for a different boundary | Run the begin step again |
|
|
91
|
+
| invalid parameters | A flag is out of range — nothing was read or written |
|
|
92
|
+
| challenge could not be marked consumed | Nothing was cleared, but a re-entry **is** already queued and will arrive; ignore it. Retrying queues a second one |
|
|
93
|
+
|
|
94
|
+
For any of these: **report it and carry on.**
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
afx send architect "Context refresh refused at <boundary>: <the reason it printed>"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then run `porch next` for your normal tasks. **The refresh never blocks your work** — the
|
|
101
|
+
boundary is recorded as consumed either way, so a failed refresh costs you some context and
|
|
102
|
+
nothing else.
|
|
103
|
+
|
|
104
|
+
### `clear-failed` — you cannot assume anything
|
|
105
|
+
|
|
106
|
+
If the command reports that the clear was attempted but **may still have landed**, do not
|
|
107
|
+
treat that as a pre-clear refusal. Sending `/clear` can succeed on the wire and still report
|
|
108
|
+
an error, so from inside this turn it is genuinely unknown whether your context survives.
|
|
109
|
+
|
|
110
|
+
- A re-entry message **is** already queued and will arrive shortly. If your context was
|
|
111
|
+
cleared, that message is your re-orientation. If it was not, the message is harmless and
|
|
112
|
+
can be ignored.
|
|
113
|
+
- Do not start new work in this state.
|
|
114
|
+
- Tell the architect explicitly that the outcome is ambiguous:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
afx send architect "Self-refresh clear-failed at <boundary> — clear may or may not have landed; re-entry is queued"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## After the clear
|
|
121
|
+
|
|
122
|
+
A re-entry message arrives shortly, identifying itself as an automatic context refresh. It
|
|
123
|
+
carries your identity, protocol, project, worktree and branch, and points at
|
|
124
|
+
`.builder-reorient.md` — the full spawn-quality frame, on disk.
|
|
125
|
+
|
|
126
|
+
It will tell you to run `porch next`. Do that; porch's state is untouched by the clear and
|
|
127
|
+
its next task emission *is* your re-orientation.
|
|
128
|
+
|
|
129
|
+
**If the re-entry never arrives**, nothing is lost. `.builder-reorient.md` is on disk and
|
|
130
|
+
the architect can send you back with one message. Say so if you notice.
|
|
131
|
+
|
|
132
|
+
## What this does not do
|
|
133
|
+
|
|
134
|
+
- It does not write `status.yaml`. Only porch does, and the boundary is already recorded
|
|
135
|
+
there before you are asked to refresh.
|
|
136
|
+
- It does not decide *whether* to refresh. Porch decided that.
|
|
137
|
+
- It does not retry. A boundary is refreshed at most once, so a refusal means this boundary
|
|
138
|
+
simply does not get a refresh.
|
|
@@ -69,6 +69,60 @@ afx send 0042 "PR approved, please merge"
|
|
|
69
69
|
afx send 0585 "check the test output" --file /tmp/test-results.txt
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
## afx interrupt
|
|
73
|
+
|
|
74
|
+
Sends an ESC keystroke to a builder's PTY — the only thing that reaches it **mid-turn**.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
afx interrupt <builder>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Flag | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `--no-enter` | Send ESC alone, without the trailing Enter |
|
|
83
|
+
|
|
84
|
+
A builder chaining foreground waits inside one turn queues every `afx send` unread — including your order
|
|
85
|
+
to stop. ESC ends the turn so the queue processes. Distinct from `afx send --interrupt` (Ctrl+C).
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
afx interrupt 0042
|
|
89
|
+
afx send 0042 "That producer died — stop waiting and report."
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## afx refresh
|
|
93
|
+
|
|
94
|
+
Refreshes a builder's context: save working state → `/clear` → re-orient. Use when a builder's context window
|
|
95
|
+
is exhausted; `afx spawn --resume` reattaches the *same* conversation and does **not** give it a fresh one.
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
afx refresh <builder>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Flag | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `--dry-run` | Print what would be sent; write nothing to the builder |
|
|
104
|
+
| `--note <text>` | Extra context appended to the re-orientation |
|
|
105
|
+
| `--file <path>` | Append file content (48KB max, read from *your* filesystem) |
|
|
106
|
+
| `--interrupt-first` | ESC before the save request, for a builder already wedged |
|
|
107
|
+
| `--mode <strict\|soft>` | Override mode if it cannot be detected |
|
|
108
|
+
| `--timeout <seconds>` | Wait for the save-state receipt (default 300) |
|
|
109
|
+
| `--min-bytes <n>` | Minimum state-file size to accept (default 1000) |
|
|
110
|
+
| `--quiet-window <ms>` | Terminal silence counting as turn-ended (default 1500) |
|
|
111
|
+
|
|
112
|
+
Every gate fails safe: if the state file never arrives, carries a stale nonce, is a stub, is still being
|
|
113
|
+
written, or the builder will not go quiet, the command **aborts without clearing** and exits non-zero,
|
|
114
|
+
naming the gate. Requires a harness with in-session context clearing (Claude Code); others abort loudly.
|
|
115
|
+
|
|
116
|
+
`afx reset` is a deprecated alias: it still works, prints a one-line notice to stderr, and will be removed
|
|
117
|
+
in a future release.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
afx refresh 0042 --dry-run # inspect first — touches nothing
|
|
121
|
+
afx refresh 0042
|
|
122
|
+
afx refresh 0042 --note "PR #90 merged while you were mid-phase. Rebase first."
|
|
123
|
+
afx refresh 0042 --interrupt-first # builder is wedged mid-turn
|
|
124
|
+
```
|
|
125
|
+
|
|
72
126
|
## afx cleanup
|
|
73
127
|
|
|
74
128
|
Removes a builder's worktree and branch after work is done.
|
|
@@ -107,8 +107,14 @@ guarantee about the clear's completion. If the timing is wrong the re-init arriv
|
|
|
107
107
|
wrong moment, which costs one manual message (see below) and nothing else. That is the
|
|
108
108
|
whole reason this cycle can be built on a delay rather than on machinery.
|
|
109
109
|
|
|
110
|
-
Delayed sends are
|
|
111
|
-
|
|
110
|
+
Delayed sends **are persisted**. The body is written to the durable mailbox at request time
|
|
111
|
+
with a `not_before` timestamp, so Tower keeps no timer for it and a restart inside the window
|
|
112
|
+
does not lose it — the re-init is delivered once the delay passes. The one thing a restart does
|
|
113
|
+
drop is the Ctrl+C nudge of a delayed `--interrupt`, which this cycle does not use.
|
|
114
|
+
|
|
115
|
+
That removes a failure mode this section used to warn about, but not the need for the recovery
|
|
116
|
+
path below: delivery still waits on an empty prompt, so a re-init can arrive late rather than
|
|
117
|
+
never.
|
|
112
118
|
|
|
113
119
|
**If this send fails, do not end your turn.** Step 4 queued the `/clear`, but it does not
|
|
114
120
|
take effect until your turn ends — so at this moment you still have your full context and
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: builder-refresh
|
|
3
|
+
description: Refresh a builder's own context at a protocol boundary — save working state, verify it, clear, and re-orient. Use when porch emits a context-refresh task, or the builder is told to "refresh your context" / "run a self-refresh". A builder does not invoke this autonomously mid-task; porch chooses the moment. Counterpart to the architect's /arch-save.
|
|
4
|
+
argument-hint: "(none — porch's refresh task supplies the commands)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /builder-refresh — save, clear, and come back knowing where you are
|
|
8
|
+
|
|
9
|
+
You are a builder that has reached a protocol boundary. Your context can be discarded
|
|
10
|
+
here safely, because everything that matters is already on disk: the spec, the plan,
|
|
11
|
+
`status.yaml`, your thread narrative, and git history. A fresh context re-orients from
|
|
12
|
+
those artifacts rather than from memory.
|
|
13
|
+
|
|
14
|
+
**The enforcement is in the command, not in this document.** `afx self-refresh` refuses to
|
|
15
|
+
clear on an unverified save, refuses when the re-entry cannot be scheduled, and refuses
|
|
16
|
+
when your worktree has uncommitted tracked changes. This skill sequences the steps and
|
|
17
|
+
explains the judgement calls; it cannot and does not decide whether the clear is safe.
|
|
18
|
+
|
|
19
|
+
## When NOT to run this
|
|
20
|
+
|
|
21
|
+
**Porch chooses the moment. You do not.** Run this when porch's refresh task tells you to,
|
|
22
|
+
or when the architect directs it. Do not invoke it mid-task on your own judgement — a
|
|
23
|
+
boundary is a point a fresh context can resume *from*, and a mid-task snapshot resumes into
|
|
24
|
+
confusion.
|
|
25
|
+
|
|
26
|
+
If you are not at a boundary and think you need a refresh anyway, say so to the architect
|
|
27
|
+
rather than doing it: `afx send architect "..."`.
|
|
28
|
+
|
|
29
|
+
## The procedure
|
|
30
|
+
|
|
31
|
+
### 1. Use the commands porch gave you
|
|
32
|
+
|
|
33
|
+
Porch's refresh task contains the exact two commands for this boundary, including the
|
|
34
|
+
`--boundary` flag. **Run those, verbatim.**
|
|
35
|
+
|
|
36
|
+
Do not retype them from memory and do not omit the flag. `--boundary` binds the challenge
|
|
37
|
+
to the boundary it was issued at, so a challenge left behind by an aborted refresh cannot
|
|
38
|
+
be used to clear you at a *later* boundary, against a save describing work that has since
|
|
39
|
+
moved on. That guard has been silently disabled twice by an instruction that dropped the
|
|
40
|
+
flag, which is why this document deliberately does not restate the commands.
|
|
41
|
+
|
|
42
|
+
If you arrived here without a porch task — an architect-directed refresh, say — there is no
|
|
43
|
+
boundary to bind, and the flagless form is correct. Run `afx self-refresh --help` for the
|
|
44
|
+
exact spelling rather than guessing it.
|
|
45
|
+
|
|
46
|
+
### 2. Write your working state
|
|
47
|
+
|
|
48
|
+
The first command prints a save request naming a file and a marker line. Write that file.
|
|
49
|
+
|
|
50
|
+
**The marker must be the FIRST LINE**, reproduced exactly. A save whose nonce appears
|
|
51
|
+
further down is refused — that check exists because echoing the request back into the file
|
|
52
|
+
otherwise passed every gate, and echoing instructions is something agents do by accident.
|
|
53
|
+
|
|
54
|
+
**Write for a cold reader** — a competent agent that wakes up with your worktree, your
|
|
55
|
+
branch, and no memory of this conversation. Most of your state is already on disk, so do
|
|
56
|
+
not restate the spec or the plan. Carry only what the artifacts do not contain:
|
|
57
|
+
|
|
58
|
+
- **receipts** — what is done and *verified*, with paths and commit hashes, distinguishing
|
|
59
|
+
"written" from "verified";
|
|
60
|
+
- **deviations** from the plan, and why;
|
|
61
|
+
- **flaky or skipped tests**, and what you did about them;
|
|
62
|
+
- **deferred work**, and the reason;
|
|
63
|
+
- **standing orders** from the architect you are still bound by, including anything you
|
|
64
|
+
were told NOT to do;
|
|
65
|
+
- **the next concrete action**.
|
|
66
|
+
|
|
67
|
+
Pointers, not prose. The save has a minimum size, and it is not a word count to pad — a
|
|
68
|
+
file below it is indistinguishable from a stub. If you genuinely have less than that to
|
|
69
|
+
say, you are probably omitting receipts or standing orders.
|
|
70
|
+
|
|
71
|
+
### 3. Run the execute command, then stop
|
|
72
|
+
|
|
73
|
+
The second command verifies your save, writes a re-orientation to disk, schedules your
|
|
74
|
+
re-entry, and clears you — in that order, and only if every step succeeds.
|
|
75
|
+
|
|
76
|
+
**Then end your turn.** Do not start new work. The clear takes effect when the turn ends.
|
|
77
|
+
|
|
78
|
+
## If it refuses
|
|
79
|
+
|
|
80
|
+
Most refusals happen **before** anything destructive, and those leave your context
|
|
81
|
+
untouched. One does not. Read which you got.
|
|
82
|
+
|
|
83
|
+
### Pre-clear refusals — your context is intact
|
|
84
|
+
|
|
85
|
+
| Refusal | What it means |
|
|
86
|
+
|---|---|
|
|
87
|
+
| state file missing / too small / wrong nonce | Your save did not satisfy the gate — check the marker is on line 1 |
|
|
88
|
+
| worktree has uncommitted tracked changes | Commit first; a refreshed context re-orients from git, so uncommitted work is invisible to it |
|
|
89
|
+
| Tower is not running, or did not schedule the re-entry | Clearing would strand you, so it refused |
|
|
90
|
+
| challenge missing / already consumed / for a different boundary | Run the begin step again |
|
|
91
|
+
| invalid parameters | A flag is out of range — nothing was read or written |
|
|
92
|
+
| challenge could not be marked consumed | Nothing was cleared, but a re-entry **is** already queued and will arrive; ignore it. Retrying queues a second one |
|
|
93
|
+
|
|
94
|
+
For any of these: **report it and carry on.**
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
afx send architect "Context refresh refused at <boundary>: <the reason it printed>"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then run `porch next` for your normal tasks. **The refresh never blocks your work** — the
|
|
101
|
+
boundary is recorded as consumed either way, so a failed refresh costs you some context and
|
|
102
|
+
nothing else.
|
|
103
|
+
|
|
104
|
+
### `clear-failed` — you cannot assume anything
|
|
105
|
+
|
|
106
|
+
If the command reports that the clear was attempted but **may still have landed**, do not
|
|
107
|
+
treat that as a pre-clear refusal. Sending `/clear` can succeed on the wire and still report
|
|
108
|
+
an error, so from inside this turn it is genuinely unknown whether your context survives.
|
|
109
|
+
|
|
110
|
+
- A re-entry message **is** already queued and will arrive shortly. If your context was
|
|
111
|
+
cleared, that message is your re-orientation. If it was not, the message is harmless and
|
|
112
|
+
can be ignored.
|
|
113
|
+
- Do not start new work in this state.
|
|
114
|
+
- Tell the architect explicitly that the outcome is ambiguous:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
afx send architect "Self-refresh clear-failed at <boundary> — clear may or may not have landed; re-entry is queued"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## After the clear
|
|
121
|
+
|
|
122
|
+
A re-entry message arrives shortly, identifying itself as an automatic context refresh. It
|
|
123
|
+
carries your identity, protocol, project, worktree and branch, and points at
|
|
124
|
+
`.builder-reorient.md` — the full spawn-quality frame, on disk.
|
|
125
|
+
|
|
126
|
+
It will tell you to run `porch next`. Do that; porch's state is untouched by the clear and
|
|
127
|
+
its next task emission *is* your re-orientation.
|
|
128
|
+
|
|
129
|
+
**If the re-entry never arrives**, nothing is lost. `.builder-reorient.md` is on disk and
|
|
130
|
+
the architect can send you back with one message. Say so if you notice.
|
|
131
|
+
|
|
132
|
+
## What this does not do
|
|
133
|
+
|
|
134
|
+
- It does not write `status.yaml`. Only porch does, and the boundary is already recorded
|
|
135
|
+
there before you are asked to refresh.
|
|
136
|
+
- It does not decide *whether* to refresh. Porch decided that.
|
|
137
|
+
- It does not retry. A boundary is refreshed at most once, so a refusal means this boundary
|
|
138
|
+
simply does not get a refresh.
|
|
@@ -39,6 +39,23 @@
|
|
|
39
39
|
"description": "Signals that can be emitted during protocol execution",
|
|
40
40
|
"additionalProperties": { "$ref": "#/$defs/signal" }
|
|
41
41
|
},
|
|
42
|
+
"context_refresh": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"description": "Boundaries at which builders automatically refresh their context (Spec 1470). Absent means no refreshes.",
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"properties": {
|
|
47
|
+
"on_enter": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"description": "Protocol phase ids to refresh on entry to. Each must name a phase this protocol declares.",
|
|
50
|
+
"uniqueItems": true,
|
|
51
|
+
"items": { "type": "string" }
|
|
52
|
+
},
|
|
53
|
+
"on_plan_phase_advance": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"description": "Refresh when advancing from one plan phase to the next. Requires a 'per_plan_phase' phase. Excludes the first plan phase, which coincides with entering the phase itself."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
42
59
|
"phase_completion": {
|
|
43
60
|
"type": "object",
|
|
44
61
|
"description": "Checks run when a plan phase completes",
|