@cluesmith/codev 3.3.3 → 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-CUIjS_Vb.js → index-DZf6pNPE.js} +2 -2
- package/dashboard-dist/assets/{index-CUIjS_Vb.js.map → index-DZf6pNPE.js.map} +1 -1
- package/dashboard-dist/index.html +1 -1
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +48 -0
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/ide.d.ts +20 -0
- package/dist/agent-farm/commands/ide.d.ts.map +1 -0
- package/dist/agent-farm/commands/ide.js +138 -0
- package/dist/agent-farm/commands/ide.js.map +1 -0
- package/dist/agent-farm/commands/inbox.d.ts.map +1 -1
- package/dist/agent-farm/commands/inbox.js +15 -3
- package/dist/agent-farm/commands/inbox.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +16 -1
- 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/tower-owner.d.ts +168 -0
- package/dist/agent-farm/db/tower-owner.d.ts.map +1 -0
- package/dist/agent-farm/db/tower-owner.js +369 -0
- package/dist/agent-farm/db/tower-owner.js.map +1 -0
- package/dist/agent-farm/db/types.d.ts +30 -5
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/lib/ide-record.d.ts +65 -0
- package/dist/agent-farm/lib/ide-record.d.ts.map +1 -0
- package/dist/agent-farm/lib/ide-record.js +118 -0
- package/dist/agent-farm/lib/ide-record.js.map +1 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts +22 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +53 -5
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.d.ts +23 -2
- package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.js +43 -2
- package/dist/agent-farm/servers/gate-profiles.js.map +1 -1
- package/dist/agent-farm/servers/ide-forward.d.ts +62 -0
- package/dist/agent-farm/servers/ide-forward.d.ts.map +1 -0
- package/dist/agent-farm/servers/ide-forward.js +274 -0
- package/dist/agent-farm/servers/ide-forward.js.map +1 -0
- package/dist/agent-farm/servers/ide-server.d.ts +68 -0
- package/dist/agent-farm/servers/ide-server.d.ts.map +1 -0
- package/dist/agent-farm/servers/ide-server.js +281 -0
- package/dist/agent-farm/servers/ide-server.js.map +1 -0
- package/dist/agent-farm/servers/mailbox-delivery.d.ts +213 -4
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.js +489 -68
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +18 -4
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.js +94 -21
- package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -1
- package/dist/agent-farm/servers/message-write.d.ts +138 -11
- package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
- package/dist/agent-farm/servers/message-write.js +144 -35
- package/dist/agent-farm/servers/message-write.js.map +1 -1
- package/dist/agent-farm/servers/overview.d.ts +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 +53 -0
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
- package/dist/agent-farm/servers/render-gate.js +135 -24
- package/dist/agent-farm/servers/render-gate.js.map +1 -1
- package/dist/agent-farm/servers/session-submit.d.ts +7 -4
- package/dist/agent-farm/servers/session-submit.d.ts.map +1 -1
- package/dist/agent-farm/servers/session-submit.js +7 -4
- package/dist/agent-farm/servers/session-submit.js.map +1 -1
- package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-cron.js +4 -1
- package/dist/agent-farm/servers/tower-cron.js.map +1 -1
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +6 -7
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +53 -13
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +64 -7
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +53 -8
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +18 -1
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
- package/dist/agent-farm/utils/message-format.js +5 -6
- package/dist/agent-farm/utils/message-format.js.map +1 -1
- package/dist/agent-farm/utils/port.d.ts +22 -0
- package/dist/agent-farm/utils/port.d.ts.map +1 -0
- package/dist/agent-farm/utils/port.js +35 -0
- package/dist/agent-farm/utils/port.js.map +1 -0
- package/dist/agent-farm/utils/server-utils.d.ts +26 -0
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +36 -0
- package/dist/agent-farm/utils/server-utils.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/consult/index.d.ts.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 +163 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-image.d.ts +5 -0
- package/dist/commands/generate-image.d.ts.map +1 -1
- package/dist/commands/generate-image.js +225 -4
- package/dist/commands/generate-image.js.map +1 -1
- package/dist/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 +10 -0
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/forge-rate-limit.d.ts +45 -0
- package/dist/lib/forge-rate-limit.d.ts.map +1 -0
- package/dist/lib/forge-rate-limit.js +89 -0
- package/dist/lib/forge-rate-limit.js.map +1 -0
- package/dist/lib/forge.d.ts +28 -0
- package/dist/lib/forge.d.ts.map +1 -1
- package/dist/lib/forge.js +63 -10
- package/dist/lib/forge.js.map +1 -1
- package/dist/lib/github.d.ts +13 -1
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +58 -15
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/test-env.d.ts +17 -0
- package/dist/lib/test-env.d.ts.map +1 -1
- package/dist/lib/test-env.js +20 -0
- package/dist/lib/test-env.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +122 -4
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +142 -7
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +23 -2
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +115 -36
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/session-screen.d.ts +34 -5
- package/dist/terminal/session-screen.d.ts.map +1 -1
- package/dist/terminal/session-screen.js +52 -6
- package/dist/terminal/session-screen.js.map +1 -1
- package/dist/terminal/terminal-replies.d.ts +102 -0
- package/dist/terminal/terminal-replies.d.ts.map +1 -0
- package/dist/terminal/terminal-replies.js +181 -0
- package/dist/terminal/terminal-replies.js.map +1 -0
- package/package.json +4 -4
- package/scripts/forge/github/pr-list.sh +6 -2
- package/scripts/forge/github/pr-search.sh +4 -2
- package/scripts/forge/gitlab/issue-search.sh +1 -0
- package/scripts/forge/gitlab/pr-search.sh +35 -2
- package/scripts/forge/linear/auth-status.sh +1 -0
- package/scripts/forge/linear/issue-comment.sh +1 -0
- package/scripts/forge/linear/issue-list.sh +1 -0
- package/scripts/forge/linear/issue-search.sh +1 -0
- package/scripts/forge/linear/issue-view.sh +1 -0
- package/scripts/forge/linear/recently-closed.sh +1 -0
- package/scripts/forge/linear/user-identity.sh +1 -0
- package/skeleton/.claude/skills/generate-image/SKILL.md +19 -2
- package/skeleton/.codex/skills/generate-image/SKILL.md +19 -2
- package/skeleton/resources/commands/agent-farm.md +27 -2
- package/skeleton/roles/consultant.md +32 -0
- package/skeleton/templates/AGENTS.md +1 -1
- package/skeleton/templates/CLAUDE.md +1 -1
|
@@ -69,6 +69,10 @@ export class SessionScreen {
|
|
|
69
69
|
// parses asynchronously and processes writes FIFO, so awaiting the LATEST write's
|
|
70
70
|
// callback guarantees every earlier write is parsed too — the flush {@link read} needs.
|
|
71
71
|
pending = Promise.resolve();
|
|
72
|
+
// Chunk counters backing {@link hasUnparsedOutput}: `feed` numbers each chunk, its parse
|
|
73
|
+
// callback records the number. Equal means the grid shows every byte fed so far.
|
|
74
|
+
fedSeq = 0;
|
|
75
|
+
parsedSeq = 0;
|
|
72
76
|
disposed = false;
|
|
73
77
|
constructor(cols, rows) {
|
|
74
78
|
this._cols = cols;
|
|
@@ -90,7 +94,20 @@ export class SessionScreen {
|
|
|
90
94
|
feed(data) {
|
|
91
95
|
if (this.disposed)
|
|
92
96
|
return;
|
|
93
|
-
|
|
97
|
+
// Number every chunk and record the number its parse callback completes, so a synchronous
|
|
98
|
+
// caller can tell whether the grid is CURRENT (Issue #1664, CMAP round 2 — codex). xterm
|
|
99
|
+
// parses asynchronously and FIFO, so `parsedSeq !== fedSeq` means bytes have been fed that
|
|
100
|
+
// the grid does not show yet — and a composer redraw hiding in them is invisible to
|
|
101
|
+
// {@link peek}.
|
|
102
|
+
const seq = ++this.fedSeq;
|
|
103
|
+
this.pending = new Promise((resolve) => this.term.write(data, () => {
|
|
104
|
+
this.parsedSeq = seq;
|
|
105
|
+
resolve();
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
/** Have bytes been fed that the grid has not parsed yet? See {@link feed} and {@link peek}. */
|
|
109
|
+
get hasUnparsedOutput() {
|
|
110
|
+
return this.parsedSeq !== this.fedSeq;
|
|
94
111
|
}
|
|
95
112
|
/**
|
|
96
113
|
* Resize the mirror to match the live session (Spec 1313: the gate renders at the
|
|
@@ -110,11 +127,14 @@ export class SessionScreen {
|
|
|
110
127
|
* `await this.pending` drains every byte fed up to this call into the grid, so the returned
|
|
111
128
|
* buffer reflects AT LEAST the output counted by `ringBuffer.bytesWritten` at the moment the
|
|
112
129
|
* caller sampled its change-token (xterm parses writes FIFO but may run ahead into later queued
|
|
113
|
-
* writes, so the buffer can reflect *more* — never less).
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
130
|
+
* writes, so the buffer can reflect *more* — never less). The caller MUST read the returned
|
|
131
|
+
* buffer with no intervening `await` (the classifier is synchronous), so no `feed` can
|
|
132
|
+
* interleave the read.
|
|
133
|
+
*
|
|
134
|
+
* Issue #1664 retired the `bytesWritten` re-check this note used to point at — the delivery
|
|
135
|
+
* path no longer holds on whole-screen output, because a working agent always has some. What
|
|
136
|
+
* covers output landing after the flush is now {@link peek}, which refuses to answer at all
|
|
137
|
+
* while any fed byte is still unparsed.
|
|
118
138
|
*
|
|
119
139
|
* After {@link dispose} the term is freed and its parse callback may never fire, so this returns
|
|
120
140
|
* the current view WITHOUT awaiting `pending` — a disposed screen has no coherent frame, the
|
|
@@ -127,6 +147,32 @@ export class SessionScreen {
|
|
|
127
147
|
await this.pending;
|
|
128
148
|
return { term: this.term, cols: this._cols, rows: this._rows };
|
|
129
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* The live buffer WITHOUT flushing the parser (Issue #1664) — the synchronous counterpart of
|
|
152
|
+
* {@link read}, for a caller that cannot await.
|
|
153
|
+
*
|
|
154
|
+
* The delivery path's in-lock precheck runs inside the per-terminal submission lock,
|
|
155
|
+
* immediately before the first byte, and is synchronous by contract; it re-reads the composer
|
|
156
|
+
* region there to confirm the screen it measured is still the screen it is about to write
|
|
157
|
+
* onto. Awaiting a parse callback in that position is not available to it.
|
|
158
|
+
*
|
|
159
|
+
* `null` when the grid is not CURRENT — any byte fed but not yet parsed, or a disposed mirror
|
|
160
|
+
* (CMAP round 2 — codex). Without that, this would hand back a grid missing exactly the
|
|
161
|
+
* composer redraw the caller is checking for: output arriving after the stable sample and
|
|
162
|
+
* immediately before the in-lock precheck is queued for parsing, absent from the buffer, and
|
|
163
|
+
* the fingerprint would compare EQUAL and permit the write — the corruption race #1521 is
|
|
164
|
+
* about, which the retired `bytesWritten` comparison used to catch. Refusing to answer is the
|
|
165
|
+
* fail-safe direction: every caller treats `null` as "the composer moved" and holds, and the
|
|
166
|
+
* hold is self-clearing on the next pass a parse-turn later.
|
|
167
|
+
*
|
|
168
|
+
* This is why `peek()` is not simply "read without awaiting": a synchronous caller cannot
|
|
169
|
+
* flush, so the only honest answers are a coherent frame or none.
|
|
170
|
+
*/
|
|
171
|
+
peek() {
|
|
172
|
+
if (this.disposed || this.hasUnparsedOutput)
|
|
173
|
+
return null;
|
|
174
|
+
return { term: this.term, cols: this._cols, rows: this._rows };
|
|
175
|
+
}
|
|
130
176
|
/**
|
|
131
177
|
* Serialize the current screen state (both buffers, colors/attrs, cursor, alt-screen
|
|
132
178
|
* mode, plus up to {@link SCREEN_SCROLLBACK} lines of history) back into a terminal
|
|
@@ -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,6EAA6E;AAC7E,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAE5C,OAAO,cAAc,MAAM,wBAAwB,CAAC;AAEpD,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;AACnC,MAAM,EAAE,cAAc,EAAE,GAAG,cAAc,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAS/B,MAAM,OAAO,aAAa;IACP,IAAI,CAAmB;IACvB,UAAU,CAAsC;IACzD,KAAK,CAAS;IACd,KAAK,CAAS;IACtB,kFAAkF;IAClF,kFAAkF;IAClF,wFAAwF;IAChF,OAAO,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"session-screen.js","sourceRoot":"","sources":["../../src/terminal/session-screen.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",
|
|
@@ -7,5 +7,9 @@
|
|
|
7
7
|
# as objects (users carry `login`; teams carry `slug`/`name` and no `login`), so
|
|
8
8
|
# `.login // empty` keeps user reviewers and drops team reviewers — matching the
|
|
9
9
|
# `reviewRequests: string[]` contract in PrListItem (forge-contracts.ts).
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
#
|
|
11
|
+
# Not `gh … | jq`: POSIX sh has no pipefail, so the caller would see jq's exit
|
|
12
|
+
# status and a rate-limited gh would look like a successful empty list (#1645).
|
|
13
|
+
# forge-executable: gh
|
|
14
|
+
out="$(gh pr list --json number,title,url,reviewDecision,body,createdAt,author,reviewRequests,isDraft)" || exit 1
|
|
15
|
+
printf '%s' "$out" | jq '[.[] | .reviewRequests = [.reviewRequests[].login // empty]]'
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: pr-search (GitHub via gh CLI)
|
|
3
3
|
# Input: CODEV_SEARCH_QUERY
|
|
4
|
-
# Output: JSON [{number, headRefName, baseRefName}]
|
|
4
|
+
# Output: JSON [{number, headRefName, baseRefName, state}]
|
|
5
5
|
# --state all is required so the search includes merged/closed PRs; without it
|
|
6
6
|
# `gh pr list` defaults to --state open and post-merge lookups return nothing (#759).
|
|
7
|
-
|
|
7
|
+
# `state` (OPEN/MERGED/CLOSED) lets consumers that only want open PRs filter
|
|
8
|
+
# client-side — the spawn collision guard must ignore merged/closed ones (#1637).
|
|
9
|
+
exec gh pr list --state all --search "$CODEV_SEARCH_QUERY" --json number,headRefName,baseRefName,state
|
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
# Forge concept: pr-search (GitLab via glab CLI)
|
|
2
|
+
# Forge concept: pr-search (GitLab via glab CLI — merge requests)
|
|
3
|
+
# Output: JSON [{number, headRefName, baseRefName, state, ...glab fields}]
|
|
4
|
+
#
|
|
5
|
+
# ⚠️ UNVERIFIED — `glab` is not available in the authoring environment (#920);
|
|
6
|
+
# written against glab's documented `mr list --output json` shape (confirmed
|
|
7
|
+
# against the field mappings already documented in gitlab/pr-list.sh and
|
|
8
|
+
# gitlab/pr-exists.sh). Smoke-test before relying on it.
|
|
9
|
+
#
|
|
3
10
|
# --all is required so the search includes merged/closed MRs; without it
|
|
4
11
|
# `glab mr list` defaults to opened only and post-merge lookups return nothing (#759).
|
|
5
|
-
|
|
12
|
+
#
|
|
13
|
+
# Maps glab's GitLab-shaped fields into the forge-neutral PrSearchItem contract
|
|
14
|
+
# (forge-contracts.ts); `. + {…}` is non-destructive for keys we don't touch:
|
|
15
|
+
# iid -> number (the MR number glab mr view/merge expects)
|
|
16
|
+
# source_branch -> headRefName
|
|
17
|
+
# target_branch -> baseRefName
|
|
18
|
+
# Without this the spawn guard's message reads `PR #undefined` and consult's
|
|
19
|
+
# findPRForIssue can't resolve the MR's base branch on GitLab.
|
|
20
|
+
#
|
|
21
|
+
# glab reports state lowercase (opened/merged/closed/locked); normalize to the
|
|
22
|
+
# GitHub convention (OPEN/MERGED/CLOSED) so consumers filter with one comparison.
|
|
23
|
+
# The spawn collision guard keys off state === "OPEN" to ignore merged MRs (#1637).
|
|
24
|
+
# `locked` (a transient merging state) maps to OPEN too: the guard should err
|
|
25
|
+
# toward the recoverable --force prompt, never silently skip a live collision.
|
|
26
|
+
#
|
|
27
|
+
# Not `glab … | jq`: POSIX sh has no pipefail, so the caller would see jq's exit
|
|
28
|
+
# status and a failed glab would look like a successful empty list (#1645).
|
|
29
|
+
# The capture-then-pipe shape hides `glab` from extractExecutable's first-line
|
|
30
|
+
# heuristic (it lands on the `printf` builtin), so declare the backend explicitly
|
|
31
|
+
# — same as github/pr-list.sh (#1645).
|
|
32
|
+
# forge-executable: glab
|
|
33
|
+
out="$(glab mr list --all --search "$CODEV_SEARCH_QUERY" --output json)" || exit 1
|
|
34
|
+
printf '%s' "$out" | jq 'map(.
|
|
35
|
+
+ {number: .iid}
|
|
36
|
+
+ {headRefName: .source_branch}
|
|
37
|
+
+ {baseRefName: .target_branch}
|
|
38
|
+
+ {state: ((.state // "") | ascii_downcase as $s | if $s == "opened" or $s == "locked" then "OPEN" else ($s | ascii_upcase) end)})'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-image
|
|
3
|
-
description: AI image generation via Gemini
|
|
3
|
+
description: AI image generation via Gemini with optional async providers. Use when the user wants to generate, create, or make an image, or when you need to create visual assets like logos, diagrams, or illustrations. Requires the API key for the selected provider.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# generate-image - AI Image Generation
|
|
@@ -22,7 +22,7 @@ Note: this is a `codev` subcommand, not standalone.
|
|
|
22
22
|
-r, --resolution <res> Resolution: 1K, 2K, 4K (default: 1K)
|
|
23
23
|
-a, --aspect <ratio> Aspect ratio (default: 1:1)
|
|
24
24
|
--ref <image> Reference image (repeatable, max 14)
|
|
25
|
-
-p, --provider <name> Provider
|
|
25
|
+
-p, --provider <name> Provider name (default: gemini)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
## Aspect ratios
|
|
@@ -64,3 +64,20 @@ Measured differences on that path:
|
|
|
64
64
|
than silently ignoring the images.
|
|
65
65
|
- The model returns JPEG, so the output file is named after its actual bytes
|
|
66
66
|
instead of writing JPEG into the default `output.png`.
|
|
67
|
+
|
|
68
|
+
## MuAPI provider
|
|
69
|
+
|
|
70
|
+
`-p muapi` uses MuAPI's Nano Banana Pro endpoint with the same aspect-ratio and
|
|
71
|
+
resolution controls. Set `MUAPI_API_KEY` (or `MU_API_KEY`) using the [MuAPI
|
|
72
|
+
access keys page](https://muapi.ai/access-keys). Reference images are uploaded
|
|
73
|
+
to MuAPI and sent to the edit endpoint; returned media is downloaded only over
|
|
74
|
+
HTTPS.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
codev generate-image "A sunset over mountains" -p muapi -a 16:9
|
|
78
|
+
codev generate-image "Keep the subject, change the lighting" -p muapi --ref subject.png
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The provider submits a job, polls the [MuAPI image API](https://muapi.ai/ai-image-api),
|
|
82
|
+
and writes the returned image locally. Polling and individual requests are
|
|
83
|
+
bounded, and the API key is never sent to the returned media host.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-image
|
|
3
|
-
description: AI image generation via Gemini
|
|
3
|
+
description: AI image generation via Gemini with optional async providers. Use when the user wants to generate, create, or make an image, or when you need to create visual assets like logos, diagrams, or illustrations. Requires the API key for the selected provider.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# generate-image - AI Image Generation
|
|
@@ -22,7 +22,7 @@ Note: this is a `codev` subcommand, not standalone.
|
|
|
22
22
|
-r, --resolution <res> Resolution: 1K, 2K, 4K (default: 1K)
|
|
23
23
|
-a, --aspect <ratio> Aspect ratio (default: 1:1)
|
|
24
24
|
--ref <image> Reference image (repeatable, max 14)
|
|
25
|
-
-p, --provider <name> Provider
|
|
25
|
+
-p, --provider <name> Provider name (default: gemini)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
## Aspect ratios
|
|
@@ -64,3 +64,20 @@ Measured differences on that path:
|
|
|
64
64
|
than silently ignoring the images.
|
|
65
65
|
- The model returns JPEG, so the output file is named after its actual bytes
|
|
66
66
|
instead of writing JPEG into the default `output.png`.
|
|
67
|
+
|
|
68
|
+
## MuAPI provider
|
|
69
|
+
|
|
70
|
+
`-p muapi` uses MuAPI's Nano Banana Pro endpoint with the same aspect-ratio and
|
|
71
|
+
resolution controls. Set `MUAPI_API_KEY` (or `MU_API_KEY`) using the [MuAPI
|
|
72
|
+
access keys page](https://muapi.ai/access-keys). Reference images are uploaded
|
|
73
|
+
to MuAPI and sent to the edit endpoint; returned media is downloaded only over
|
|
74
|
+
HTTPS.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
codev generate-image "A sunset over mountains" -p muapi -a 16:9
|
|
78
|
+
codev generate-image "Keep the subject, change the lighting" -p muapi --ref subject.png
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The provider submits a job, polls the [MuAPI image API](https://muapi.ai/ai-image-api),
|
|
82
|
+
and writes the returned image locally. Polling and individual requests are
|
|
83
|
+
bounded, and the API key is never sent to the returned media host.
|