@cluesmith/codev 3.3.2 → 3.3.4
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-D3XaKpZW.js → index-DZf6pNPE.js} +41 -41
- package/dashboard-dist/assets/index-DZf6pNPE.js.map +1 -0
- package/dashboard-dist/assets/index-DnYLy5C_.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 +79 -10
- package/dist/agent-farm/commands/inbox.js.map +1 -1
- package/dist/agent-farm/commands/interrupt.d.ts +4 -1
- package/dist/agent-farm/commands/interrupt.d.ts.map +1 -1
- package/dist/agent-farm/commands/interrupt.js +6 -3
- package/dist/agent-farm/commands/interrupt.js.map +1 -1
- package/dist/agent-farm/commands/reset.d.ts +4 -1
- package/dist/agent-farm/commands/reset.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset.js +6 -3
- package/dist/agent-farm/commands/reset.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +28 -0
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +79 -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 +16 -7
- 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/index.d.ts +3 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +8 -443
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/mailbox.d.ts +47 -7
- package/dist/agent-farm/db/mailbox.d.ts.map +1 -1
- package/dist/agent-farm/db/mailbox.js +56 -12
- package/dist/agent-farm/db/mailbox.js.map +1 -1
- package/dist/agent-farm/db/migrations.d.ts +57 -0
- package/dist/agent-farm/db/migrations.d.ts.map +1 -0
- package/dist/agent-farm/db/migrations.js +530 -0
- package/dist/agent-farm/db/migrations.js.map +1 -0
- package/dist/agent-farm/db/schema.d.ts +1 -1
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +1 -0
- package/dist/agent-farm/db/schema.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 +47 -0
- 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 +96 -19
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/cron-delivery.d.ts +7 -1
- package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/cron-delivery.js +2 -1
- package/dist/agent-farm/servers/cron-delivery.js.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.d.ts +44 -2
- package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.js +79 -6
- 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 +296 -12
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.js +566 -69
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +66 -19
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.js +204 -37
- 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 +28 -12
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +130 -79
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/render-gate.d.ts +77 -1
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
- package/dist/agent-farm/servers/render-gate.js +174 -25
- 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 +7 -3
- 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 +17 -10
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts +32 -0
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +186 -26
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +79 -9
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +21 -0
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +106 -13
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-utils.d.ts +35 -0
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +39 -0
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +26 -2
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/utils/message-format.d.ts +78 -2
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
- package/dist/agent-farm/utils/message-format.js +107 -11
- 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.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +61 -1
- 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 +165 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-image.d.ts +25 -1
- package/dist/commands/generate-image.d.ts.map +1 -1
- package/dist/commands/generate-image.js +410 -2
- package/dist/commands/generate-image.js.map +1 -1
- package/dist/commands/porch/prompts.d.ts.map +1 -1
- package/dist/commands/porch/prompts.js +18 -2
- package/dist/commands/porch/prompts.js.map +1 -1
- package/dist/lib/agent-env.d.ts +86 -0
- package/dist/lib/agent-env.d.ts.map +1 -0
- package/dist/lib/agent-env.js +126 -0
- package/dist/lib/agent-env.js.map +1 -0
- package/dist/lib/forge-contracts.d.ts +76 -5
- 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 +29 -1
- package/dist/lib/forge.d.ts.map +1 -1
- package/dist/lib/forge.js +96 -21
- 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-manager.d.ts +10 -1
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +38 -9
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +174 -8
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +299 -25
- 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/shellper-client.d.ts +73 -0
- package/dist/terminal/shellper-client.d.ts.map +1 -1
- package/dist/terminal/shellper-client.js +151 -0
- package/dist/terminal/shellper-client.js.map +1 -1
- package/dist/terminal/shellper-main.js +20 -3
- package/dist/terminal/shellper-main.js.map +1 -1
- package/dist/terminal/shellper-process.d.ts +2 -0
- package/dist/terminal/shellper-process.d.ts.map +1 -1
- package/dist/terminal/shellper-process.js +17 -1
- package/dist/terminal/shellper-process.js.map +1 -1
- package/dist/terminal/shellper-protocol.d.ts +28 -0
- package/dist/terminal/shellper-protocol.d.ts.map +1 -1
- package/dist/terminal/shellper-protocol.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/gitea/_lib.sh +214 -0
- package/scripts/forge/gitea/issue-comment.sh +8 -1
- package/scripts/forge/gitea/issue-view.sh +95 -4
- package/scripts/forge/gitea/pr-create.sh +155 -0
- package/scripts/forge/gitea/pr-exists.sh +32 -4
- package/scripts/forge/gitea/pr-list.sh +40 -31
- package/scripts/forge/gitea/pr-view.sh +65 -4
- package/scripts/forge/gitea/recently-merged.sh +91 -21
- package/scripts/forge/gitea/user-identity.sh +30 -1
- package/scripts/forge/github/issue-view.sh +5 -2
- package/scripts/forge/github/pr-create.sh +47 -0
- package/scripts/forge/github/pr-list.sh +6 -2
- package/scripts/forge/github/pr-search.sh +6 -2
- package/scripts/forge/gitlab/issue-search.sh +1 -0
- package/scripts/forge/gitlab/issue-view.sh +24 -4
- package/scripts/forge/gitlab/pr-create.sh +53 -0
- package/scripts/forge/gitlab/pr-search.sh +37 -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 +14 -2
- package/scripts/forge/linear/recently-closed.sh +1 -0
- package/scripts/forge/linear/user-identity.sh +1 -0
- package/skeleton/.claude/skills/generate-image/SKILL.md +39 -1
- package/skeleton/.codex/skills/generate-image/SKILL.md +39 -1
- package/skeleton/protocols/air/prompts/pr.md +6 -1
- package/skeleton/protocols/aspir/prompts/review.md +6 -1
- package/skeleton/protocols/bugfix/prompts/pr.md +6 -1
- package/skeleton/protocols/bugfix/protocol.md +2 -1
- package/skeleton/protocols/maintain/prompts/review.md +6 -1
- package/skeleton/protocols/pir/prompts/review.md +10 -7
- package/skeleton/protocols/spir/prompts/review.md +6 -1
- package/skeleton/resources/commands/agent-farm.md +28 -3
- package/skeleton/roles/consultant.md +32 -0
- package/skeleton/templates/AGENTS.md +1 -1
- package/skeleton/templates/CLAUDE.md +1 -1
- package/templates/tower.html +16 -1
- package/dashboard-dist/assets/index-BZRTEMtH.css +0 -32
- package/dashboard-dist/assets/index-D3XaKpZW.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shellper-protocol.js","sourceRoot":"","sources":["../../src/terminal/shellper-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAEhE,sBAAsB;AAEtB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;CACH,CAAC;AAIX,6BAA6B;AAE7B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO;AACvD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,+BAA+B;AAC7D,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,oDAAoD;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM;AAEzD,0BAA0B;AAE1B,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IACrC,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,UAAU;IACb,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,WAAW;CAChB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"shellper-protocol.js","sourceRoot":"","sources":["../../src/terminal/shellper-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
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 declare const XTERM_REPLY_TABLE_VERSION = "5.5.0";
|
|
64
|
+
/**
|
|
65
|
+
* Every recognized terminal reply in `data`, in the order the patterns match them.
|
|
66
|
+
*
|
|
67
|
+
* Diagnostics only — {@link stripTerminalReplies} does the real work and never calls this. It
|
|
68
|
+
* backs the `AF_LOG_INPUT_SIGNAL` trace, whose whole purpose is to let a human SEE which bytes
|
|
69
|
+
* were treated as a reply and which survived as input, rather than infer it from a hold that
|
|
70
|
+
* did or did not happen.
|
|
71
|
+
*/
|
|
72
|
+
export declare function terminalReplyMatches(data: string): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Render a byte run so it can be read in a log line: ESC as `\e`, other C0 controls and DEL as
|
|
75
|
+
* `\xNN`, everything else literal.
|
|
76
|
+
*
|
|
77
|
+
* Printing raw ESC to a terminal log would make the log itself move the cursor and repaint —
|
|
78
|
+
* the diagnostic would corrupt the thing it is diagnosing, and the reply bytes under
|
|
79
|
+
* investigation would be the ones that vanished.
|
|
80
|
+
*/
|
|
81
|
+
export declare function escapeBytes(data: string): string;
|
|
82
|
+
/**
|
|
83
|
+
* The human-input residue of one upstream chunk: `data` with every recognized terminal reply
|
|
84
|
+
* removed. Returns `''` when the chunk was nothing but replies — the caller reads that as "no
|
|
85
|
+
* human input here" and leaves the gate's input signal untouched.
|
|
86
|
+
*
|
|
87
|
+
* Pure and allocation-cheap; called on every keystroke, so the common case (plain text with
|
|
88
|
+
* no ESC at all) short-circuits before touching a regex.
|
|
89
|
+
*
|
|
90
|
+
* The short-circuit does NOT cover a bracketed paste: `ESC[200~ … ESC[201~` always contains
|
|
91
|
+
* ESC, so a pasted body — up to the 1 MiB a `/write` request body may carry — runs every
|
|
92
|
+
* pattern's `replace` over its full length. This is an EXTERNAL paste only (a human pasting
|
|
93
|
+
* into the browser terminal, or a caller POSTing one to `/api/terminals/:id/write`); a mail
|
|
94
|
+
* delivery's own bracketed paste (Issue #1567) is written with origin `'delivery'` and never
|
|
95
|
+
* reaches this function at all, so no long send pays the scan. Left as is deliberately: an
|
|
96
|
+
* external paste is a rare, human-paced event next to the per-keystroke path this function is
|
|
97
|
+
* tuned for, and any length guard cheap enough to be worth adding would have to decide where a
|
|
98
|
+
* reply may legitimately sit inside the payload — which is the over-strip direction, the
|
|
99
|
+
* silent one.
|
|
100
|
+
*/
|
|
101
|
+
export declare function stripTerminalReplies(data: string): string;
|
|
102
|
+
//# sourceMappingURL=terminal-replies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-replies.d.ts","sourceRoot":"","sources":["../../src/terminal/terminal-replies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,UAAU,CAAC;AAqDjD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAM3D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD"}
|
|
@@ -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.4",
|
|
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-
|
|
40
|
-
"@cluesmith/codev-
|
|
38
|
+
"@cluesmith/codev-core": "3.3.4",
|
|
39
|
+
"@cluesmith/codev-types": "3.3.4",
|
|
40
|
+
"@cluesmith/codev-sdk": "3.3.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@playwright/test": "^1.58.0",
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Shared helpers for the Gitea forge preset scripts.
|
|
2
|
+
#
|
|
3
|
+
# This file is SOURCED, not executed (`. "$(dirname "$0")/_lib.sh"`), so it has
|
|
4
|
+
# no shebang and defines only functions/vars. POSIX sh only — no bashisms — the
|
|
5
|
+
# scripts are #!/bin/sh and forge runs them via `sh -c`. It is not a forge
|
|
6
|
+
# concept: forge.ts builds presets from an explicit KNOWN_CONCEPTS allowlist, so
|
|
7
|
+
# a leading-underscore file in this directory is never registered as a concept.
|
|
8
|
+
#
|
|
9
|
+
# Sibling-file dependency: the five concept scripts that source this file need
|
|
10
|
+
# it to sit next to them. A hand-copied override in `.codev/scripts/forge/gitea/`
|
|
11
|
+
# must copy `_lib.sh` alongside the script, or the `.` line fails.
|
|
12
|
+
|
|
13
|
+
# Resolve owner/repo for the `tea api` path.
|
|
14
|
+
#
|
|
15
|
+
# `tea api` needs an explicit owner/repo in the path (unlike `tea pulls`/`tea
|
|
16
|
+
# issues`, which auto-detect it from the local git remote). Honor CODEV_REPO
|
|
17
|
+
# when set, else derive owner/repo from origin's URL (handles https, ssh, and
|
|
18
|
+
# scp-style remotes, with or without a .git suffix).
|
|
19
|
+
#
|
|
20
|
+
# Fails fast: if the result isn't a clean `owner/repo` (no origin remote, an
|
|
21
|
+
# unusual URL, etc.), print a stderr message naming CODEV_REPO as the remedy and
|
|
22
|
+
# return non-zero so the caller can `exit 1` — otherwise `tea api "repos//…"`
|
|
23
|
+
# fails later with a confusing 404. Callers must use: REPO="$(gitea_repo)" || exit 1
|
|
24
|
+
gitea_repo() {
|
|
25
|
+
_repo="${CODEV_REPO:-$(git remote get-url origin 2>/dev/null | sed -E -e 's#\.git$##' -e 's#.*[/:]([^/]+/[^/]+)$#\1#')}"
|
|
26
|
+
_owner=${_repo%%/*}
|
|
27
|
+
_rest=${_repo#*/}
|
|
28
|
+
# Valid iff exactly one slash, both sides non-empty:
|
|
29
|
+
# - "$_owner" = "$_repo" → no slash at all
|
|
30
|
+
# - -z "$_owner" / -z "$_rest" → empty owner or repo (e.g. "/x", "x/")
|
|
31
|
+
# - "$_rest" != "${_rest%/*}" → a second slash (e.g. "a/b/c")
|
|
32
|
+
if [ -z "$_repo" ] || [ "$_owner" = "$_repo" ] || [ -z "$_owner" ] || [ -z "$_rest" ] || [ "$_rest" != "${_rest%/*}" ]; then
|
|
33
|
+
echo "gitea forge: could not determine owner/repo from the 'origin' remote; set CODEV_REPO=owner/repo" >&2
|
|
34
|
+
return 1
|
|
35
|
+
fi
|
|
36
|
+
printf '%s' "$_repo"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# A jq prelude defining `gitea_epoch`: parse a timestamp to epoch seconds, or
|
|
40
|
+
# null if it isn't one. Prepend it to a jq program that needs to compare times:
|
|
41
|
+
# jq "${GITEA_JQ_LIB} <program>"
|
|
42
|
+
#
|
|
43
|
+
# Two input shapes, because two different producers feed it:
|
|
44
|
+
# - Gitea's RFC3339 response times. Gitea marshals them in the SERVER's
|
|
45
|
+
# timezone, so `Z` is NOT guaranteed — `2026-07-05T14:00:00+02:00` is a real
|
|
46
|
+
# response. `fromdateiso8601` only accepts `Z`, and a lexicographic compare
|
|
47
|
+
# across mixed offsets is simply wrong, so the offset is parsed and
|
|
48
|
+
# subtracted explicitly.
|
|
49
|
+
# - CODEV_SINCE_DATE, which callers set to either a full timestamp
|
|
50
|
+
# (`github.ts`) or a bare `YYYY-MM-DD` (`team-update.ts`). A bare date is
|
|
51
|
+
# read as midnight UTC, and a timestamp with no offset at all is read as
|
|
52
|
+
# UTC too.
|
|
53
|
+
#
|
|
54
|
+
# Input that isn't a recognizable date yields null, and every caller treats null
|
|
55
|
+
# as "don't know" — keep the item, keep walking — so a surprising format
|
|
56
|
+
# degrades to the old unbounded behavior rather than silently dropping data.
|
|
57
|
+
# This is shape validation, not a calendar: `2026-02-30` is normalized by
|
|
58
|
+
# `fromdateiso8601` into March rather than rejected. That only matters for a
|
|
59
|
+
# hand-written cutoff, and lands it a day or two off rather than anywhere wild.
|
|
60
|
+
GITEA_JQ_LIB='
|
|
61
|
+
def gitea_epoch:
|
|
62
|
+
if type == "string" then
|
|
63
|
+
((capture("^(?<d>\\d{4}-\\d{2}-\\d{2})(T(?<t>\\d{2}:\\d{2}:\\d{2})(\\.\\d+)?(?<o>Z|[+-](0\\d|1[0-4]):[0-5]\\d)?)?$")) // null) as $c
|
|
64
|
+
| if $c == null then null
|
|
65
|
+
# `try`: the regex only proves the SHAPE. `2026-13-99` matches it and then
|
|
66
|
+
# makes `fromdateiso8601` throw, which would abort the script with a raw
|
|
67
|
+
# jq error instead of degrading to "unknown time".
|
|
68
|
+
else (try (($c.d + "T" + ($c.t // "00:00:00") + "Z") | fromdateiso8601) catch null) as $e
|
|
69
|
+
| if $e == null then null
|
|
70
|
+
elif ($c.o == null or $c.o == "Z") then $e
|
|
71
|
+
else ($c.o | capture("^(?<s>[+-])(?<h>\\d{2}):(?<m>\\d{2})$")) as $z
|
|
72
|
+
| $e - (((($z.h | tonumber) * 3600) + (($z.m | tonumber) * 60))
|
|
73
|
+
* (if $z.s == "+" then 1 else -1 end))
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
else null end;
|
|
77
|
+
'
|
|
78
|
+
|
|
79
|
+
# Page size to request per page. Gitea caps list responses at the server's
|
|
80
|
+
# `max_response_items` (default 50), so `&limit=200` silently truncates to ~50
|
|
81
|
+
# with no client-side pagination. Requesting 50 matches that default cap; a
|
|
82
|
+
# server tuned higher just returns more per page (fewer round-trips).
|
|
83
|
+
GITEA_PAGE_LIMIT=50
|
|
84
|
+
|
|
85
|
+
# Hard ceiling on pages fetched, so a misbehaving server that never returns a
|
|
86
|
+
# short page can't spin forever. 100 pages × 50 = 5000 items — far beyond any
|
|
87
|
+
# real open-PR / recently-merged / all-pulls window we page over. Reaching it is
|
|
88
|
+
# an ERROR, not a stop condition (see below).
|
|
89
|
+
GITEA_MAX_PAGES=100
|
|
90
|
+
|
|
91
|
+
# Build one page URL. Split out so the ceiling probe below builds it the same
|
|
92
|
+
# way the loop does.
|
|
93
|
+
gitea_page_url() {
|
|
94
|
+
if [ -n "$2" ]; then
|
|
95
|
+
printf '%s?%s&limit=%s&page=%s' "$1" "$2" "$GITEA_PAGE_LIMIT" "$3"
|
|
96
|
+
else
|
|
97
|
+
printf '%s?limit=%s&page=%s' "$1" "$GITEA_PAGE_LIMIT" "$3"
|
|
98
|
+
fi
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Echo a page response's item count, or "!<type>" if it isn't a JSON array.
|
|
102
|
+
# `tea api` exits 0 on HTTP errors and prints the error body, and `jq length` is
|
|
103
|
+
# 0 for both `null` and `{}` — so without the type check an error body mid-walk
|
|
104
|
+
# looks exactly like an exhausted list.
|
|
105
|
+
gitea_page_count() {
|
|
106
|
+
printf '%s' "$1" | jq -r 'if type == "array" then length else "!" + type end'
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# Fetch a paginated Gitea list endpoint and emit ONE concatenated JSON array on
|
|
110
|
+
# stdout, so the caller's existing jq normalizer sees the same shape as before.
|
|
111
|
+
#
|
|
112
|
+
# Usage: tea_api_paged "repos/<owner>/<repo>/pulls" "state=all" ["<jq stop filter>"]
|
|
113
|
+
# $1 = API path (no page params)
|
|
114
|
+
# $2 = extra query string (may be empty), e.g. "state=open"
|
|
115
|
+
# $3 = optional jq program run on each page's array, with the PREVIOUS page
|
|
116
|
+
# bound as `$prev` (`null` on page 1); when it outputs `true` the walk
|
|
117
|
+
# stops after that page. Used by `recently-merged` to bound the walk with
|
|
118
|
+
# CODEV_SINCE_DATE — `$prev` is what lets it check ordering ACROSS a page
|
|
119
|
+
# boundary and not just within one page. It must be conservative: a false
|
|
120
|
+
# negative just costs another page, a false positive silently truncates.
|
|
121
|
+
#
|
|
122
|
+
# Loops page=1,2,3… concatenating each page's array, and stops when a page
|
|
123
|
+
# returns fewer than the requested limit (the last page), an empty/blank
|
|
124
|
+
# response, or the caller's stop filter fires.
|
|
125
|
+
#
|
|
126
|
+
# Reaching GITEA_MAX_PAGES with every page full means we do NOT know we have the
|
|
127
|
+
# whole list. Returning the partial array at exit 0 would be exactly the silent
|
|
128
|
+
# truncation this paginator exists to prevent (a short `pr-exists` walk reads as
|
|
129
|
+
# "no PR exists" and passes a porch pr_exists gate on a repo we simply failed to
|
|
130
|
+
# finish reading), so it fails loudly instead: stderr message, non-zero return,
|
|
131
|
+
# no stdout. One probe request first, because a list whose length is an exact
|
|
132
|
+
# multiple of the page size hits the ceiling with nothing actually missing, and
|
|
133
|
+
# failing on a complete result would be its own bug.
|
|
134
|
+
tea_api_paged() {
|
|
135
|
+
_path="$1"
|
|
136
|
+
_query="$2"
|
|
137
|
+
_stop="$3"
|
|
138
|
+
_page=1
|
|
139
|
+
_acc='[]'
|
|
140
|
+
_page_size=''
|
|
141
|
+
_terminal=''
|
|
142
|
+
_prev=''
|
|
143
|
+
while [ "$_page" -le "$GITEA_MAX_PAGES" ]; do
|
|
144
|
+
_resp="$(tea api "$(gitea_page_url "$_path" "$_query" "$_page")")" || return 1
|
|
145
|
+
# Blank body or an empty array → no more pages.
|
|
146
|
+
if [ -z "$_resp" ]; then
|
|
147
|
+
_terminal=1
|
|
148
|
+
break
|
|
149
|
+
fi
|
|
150
|
+
_count="$(gitea_page_count "$_resp")" || return 1
|
|
151
|
+
case "$_count" in
|
|
152
|
+
'!'*)
|
|
153
|
+
echo "gitea forge: page ${_page} of '${_path}' is not an array but a ${_count#!} (an HTTP error body reaches us at exit 0); refusing to return a truncated result" >&2
|
|
154
|
+
return 1
|
|
155
|
+
;;
|
|
156
|
+
esac
|
|
157
|
+
if [ "$_count" -eq 0 ]; then
|
|
158
|
+
_terminal=1
|
|
159
|
+
break
|
|
160
|
+
fi
|
|
161
|
+
_acc="$(printf '%s\n%s' "$_acc" "$_resp" | jq -s 'add')" || return 1
|
|
162
|
+
if [ -n "$_stop" ]; then
|
|
163
|
+
# Both pages go in on STDIN, not through `--argjson`. Linux caps a single
|
|
164
|
+
# argv string at MAX_ARG_STRLEN (128KiB) regardless of ARG_MAX, and a
|
|
165
|
+
# 50-item Gitea pulls page — each object embedding full `base.repo` and
|
|
166
|
+
# `head.repo` objects — is routinely ~90KiB and can exceed it. macOS has
|
|
167
|
+
# no per-argument cap, so this would have passed locally and failed on CI
|
|
168
|
+
# and on every Linux adopter.
|
|
169
|
+
_hit="$(printf '%s\n%s\n' "${_prev:-null}" "$_resp" \
|
|
170
|
+
| jq -n "[inputs] as \$i | \$i[0] as \$prev | \$i[1] | ( $_stop )")" || return 1
|
|
171
|
+
if [ "$_hit" = "true" ]; then
|
|
172
|
+
_terminal=1
|
|
173
|
+
break
|
|
174
|
+
fi
|
|
175
|
+
fi
|
|
176
|
+
# A server whose max_response_items is tuned below GITEA_PAGE_LIMIT
|
|
177
|
+
# truncates every page to its own cap, not the requested limit — so
|
|
178
|
+
# stopping when a page is shorter than the *requested* limit would break
|
|
179
|
+
# after page 1 even though more pages exist. Compare against the size
|
|
180
|
+
# actually observed on the first page instead.
|
|
181
|
+
[ -z "$_page_size" ] && _page_size="$_count"
|
|
182
|
+
if [ "$_count" -lt "$_page_size" ]; then
|
|
183
|
+
_terminal=1
|
|
184
|
+
break
|
|
185
|
+
fi
|
|
186
|
+
_prev="$_resp"
|
|
187
|
+
_page=$((_page + 1))
|
|
188
|
+
done
|
|
189
|
+
|
|
190
|
+
if [ -z "$_terminal" ]; then
|
|
191
|
+
# Ceiling reached with every page full. Probe one past it: if there is
|
|
192
|
+
# nothing there, the list length was just an exact multiple of the page
|
|
193
|
+
# size and what we have is complete.
|
|
194
|
+
_resp="$(tea api "$(gitea_page_url "$_path" "$_query" "$((GITEA_MAX_PAGES + 1))")")" || return 1
|
|
195
|
+
if [ -z "$_resp" ]; then
|
|
196
|
+
_terminal=1
|
|
197
|
+
else
|
|
198
|
+
_count="$(gitea_page_count "$_resp")" || return 1
|
|
199
|
+
case "$_count" in
|
|
200
|
+
'!'*)
|
|
201
|
+
echo "gitea forge: page $((GITEA_MAX_PAGES + 1)) of '${_path}' is not an array but a ${_count#!} (an HTTP error body reaches us at exit 0); refusing to return a truncated result" >&2
|
|
202
|
+
return 1
|
|
203
|
+
;;
|
|
204
|
+
esac
|
|
205
|
+
[ "$_count" -eq 0 ] && _terminal=1
|
|
206
|
+
fi
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
if [ -z "$_terminal" ]; then
|
|
210
|
+
echo "gitea forge: pagination for '${_path}' reached the ${GITEA_MAX_PAGES}-page ceiling without a terminal page; refusing to return a truncated result" >&2
|
|
211
|
+
return 1
|
|
212
|
+
fi
|
|
213
|
+
printf '%s' "$_acc"
|
|
214
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: issue-comment (Gitea via tea CLI)
|
|
3
|
-
|
|
3
|
+
# Input: CODEV_ISSUE_ID, CODEV_COMMENT_BODY
|
|
4
|
+
# Output: exit code only
|
|
5
|
+
#
|
|
6
|
+
# `tea issues` has no `comment` subcommand (its subcommands are list/create/
|
|
7
|
+
# edit/close). `tea comments add` only exists on tea 0.14.2+ and fails with
|
|
8
|
+
# "No help topic for comments" on the still-current 0.14.1 release. The
|
|
9
|
+
# top-level `tea comment` shorthand works on both 0.14.1 and 0.14.2+.
|
|
10
|
+
exec tea comment "$CODEV_ISSUE_ID" "$CODEV_COMMENT_BODY"
|