wicked-crew 0.7.28 → 0.7.29
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/README.md +9 -1
- package/dist/api/chat-scope.d.ts +210 -0
- package/dist/api/chat-scope.d.ts.map +1 -0
- package/dist/api/chat-scope.js +724 -0
- package/dist/api/chat-scope.js.map +1 -0
- package/dist/api/diagnostics.d.ts +30 -2
- package/dist/api/diagnostics.d.ts.map +1 -1
- package/dist/api/diagnostics.js +73 -5
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/governance-health.d.ts +163 -0
- package/dist/api/governance-health.d.ts.map +1 -0
- package/dist/api/governance-health.js +348 -0
- package/dist/api/governance-health.js.map +1 -0
- package/dist/api/open-path.d.ts.map +1 -1
- package/dist/api/open-path.js +2 -1
- package/dist/api/open-path.js.map +1 -1
- package/dist/api/post-hoc-deliver.d.ts +9 -5
- package/dist/api/post-hoc-deliver.d.ts.map +1 -1
- package/dist/api/post-hoc-deliver.js +21 -7
- package/dist/api/post-hoc-deliver.js.map +1 -1
- package/dist/api/routes.d.ts +48 -12
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +309 -48
- package/dist/api/routes.js.map +1 -1
- package/dist/api/seat-health.d.ts.map +1 -1
- package/dist/api/seat-health.js +25 -5
- package/dist/api/seat-health.js.map +1 -1
- package/dist/api/seat-signin.d.ts.map +1 -1
- package/dist/api/seat-signin.js +49 -23
- package/dist/api/seat-signin.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +20 -0
- package/dist/api/server.js.map +1 -1
- package/dist/campaigns/routes.d.ts +4 -4
- package/dist/cli/governance.d.ts +131 -0
- package/dist/cli/governance.d.ts.map +1 -0
- package/dist/cli/governance.js +354 -0
- package/dist/cli/governance.js.map +1 -0
- package/dist/cli/index.js +69 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/core/adapter.d.ts +89 -1
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +123 -7
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-reaper.d.ts.map +1 -1
- package/dist/core/bridge-reaper.js +4 -1
- package/dist/core/bridge-reaper.js.map +1 -1
- package/dist/core/deliver-text.d.ts +184 -0
- package/dist/core/deliver-text.d.ts.map +1 -0
- package/dist/core/deliver-text.js +434 -0
- package/dist/core/deliver-text.js.map +1 -0
- package/dist/core/deliver-triage.d.ts +90 -0
- package/dist/core/deliver-triage.d.ts.map +1 -0
- package/dist/core/deliver-triage.js +106 -0
- package/dist/core/deliver-triage.js.map +1 -0
- package/dist/core/deliver.d.ts +103 -9
- package/dist/core/deliver.d.ts.map +1 -1
- package/dist/core/deliver.js +244 -46
- package/dist/core/deliver.js.map +1 -1
- package/dist/core/estate-mcp-client.d.ts.map +1 -1
- package/dist/core/estate-mcp-client.js +7 -2
- package/dist/core/estate-mcp-client.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +11 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/governance-store.d.ts +197 -0
- package/dist/core/governance-store.d.ts.map +1 -0
- package/dist/core/governance-store.js +283 -0
- package/dist/core/governance-store.js.map +1 -0
- package/dist/core/repoPaths.d.ts +36 -5
- package/dist/core/repoPaths.d.ts.map +1 -1
- package/dist/core/repoPaths.js +46 -4
- package/dist/core/repoPaths.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +9 -4
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/projects/graph-paths.d.ts +4 -2
- package/dist/projects/graph-paths.d.ts.map +1 -1
- package/dist/projects/graph-paths.js +4 -2
- package/dist/projects/graph-paths.js.map +1 -1
- package/dist/projects/graph.d.ts +5 -4
- package/dist/projects/graph.d.ts.map +1 -1
- package/dist/projects/graph.js +22 -5
- package/dist/projects/graph.js.map +1 -1
- package/dist/projects/routes.d.ts.map +1 -1
- package/dist/projects/routes.js +18 -9
- package/dist/projects/routes.js.map +1 -1
- package/dist/skills/plugin-source.d.ts.map +1 -1
- package/dist/skills/plugin-source.js +3 -0
- package/dist/skills/plugin-source.js.map +1 -1
- package/dist/studio/assets/index-CeJTutxP.js +540 -0
- package/dist/studio/index.html +1 -1
- package/dist/studio/testid-inventory.json +212 -6
- package/endpoint-manifest.json +60 -12
- package/package.json +3 -3
- package/dist/studio/assets/index-CdmCMh2f.js +0 -539
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deliver phase's PR + commit TEXT (crew#524, acceptance finding F-3R2-014).
|
|
3
|
+
*
|
|
4
|
+
* `gh pr create --fill` opened wicked-studio#249 with a title cut MID-WORD out of the intent's first
|
|
5
|
+
* 72 characters (`…scenario CLN-2) aga`) and an EMPTY body: no `Fixes #214`, no run link, no record
|
|
6
|
+
* of what ran or what passed — and the commit carried the same truncated headline. A reviewer got
|
|
7
|
+
* nothing to review against. This module composes the text from the RUN instead. ONE composer, two
|
|
8
|
+
* moments it can be asked:
|
|
9
|
+
*
|
|
10
|
+
* - at DELIVERY, from the persisted run view (`GET /runs/:id/deliver-text`, text/plain): every
|
|
11
|
+
* phase the run went through with its seat and gate outcome, the repo checks the verify phase
|
|
12
|
+
* ran with their exit codes, the evaluator's verdict, and a link to the run;
|
|
13
|
+
* - at LAUNCH, from the workflow definition — the fallback the deliver script carries in case the
|
|
14
|
+
* daemon cannot answer when the PR opens (an auth-required daemon, no `curl`, a daemon that went
|
|
15
|
+
* away): the intent, the issue links, the run id and the phase list ARE known then; the runtime
|
|
16
|
+
* sections say plainly that they were not available rather than pretending.
|
|
17
|
+
*
|
|
18
|
+
* The title is the intent's first line, cut at a WORD boundary within {@link DELIVER_TITLE_MAX}
|
|
19
|
+
* characters (never mid-word), or `wicked-crew run <id>` when the intent is blank. `Fixes #N` is
|
|
20
|
+
* emitted when the intent names an issue with a closing verb (`fix issue #214`, `closes #7`); every
|
|
21
|
+
* other `#N` / `repo#N` / `owner/repo#N` mention rides as `Refs:`.
|
|
22
|
+
*
|
|
23
|
+
* FRAMING, shared by both carriers (the daemon's text/plain answer and the script's embedded
|
|
24
|
+
* fallback) so the script parses exactly one shape: line 1 = title, line 2 = blank, then the body.
|
|
25
|
+
* The framed text is also, verbatim, the message of the commit the deliver phase MAKES when the
|
|
26
|
+
* run left uncommitted work (`git commit -F`: git takes the first paragraph as the subject). A run
|
|
27
|
+
* that committed incrementally keeps its own commits untouched — the PR title is composed from the
|
|
28
|
+
* run either way; only the deliver phase's own commit is guaranteed to match it.
|
|
29
|
+
*/
|
|
30
|
+
/** The PR title / commit subject cap — git's conventional subject width. */
|
|
31
|
+
export const DELIVER_TITLE_MAX = 72;
|
|
32
|
+
// ── the title ──────────────────────────────────────────────────────────────────────────────────
|
|
33
|
+
/** Control characters other than newline/tab — never part of a title, a table cell or a commit. */
|
|
34
|
+
const CONTROL_CHARS = /[\u0000-\u0008\u000b-\u001f\u007f]/g;
|
|
35
|
+
/** EVERY control character, newline and tab included — for values that must stay on one line. */
|
|
36
|
+
const ALL_CONTROL_CHARS = /[\u0000-\u001f\u007f]/g;
|
|
37
|
+
/** `s` as one line: control characters (newlines included) become spaces, runs collapse, ends trim. */
|
|
38
|
+
function oneLine(s) {
|
|
39
|
+
return s.replace(ALL_CONTROL_CHARS, ' ').replace(/\s+/g, ' ').trim();
|
|
40
|
+
}
|
|
41
|
+
/** One line of intent reduced to plain words: markdown markers and links stripped, spaces collapsed. */
|
|
42
|
+
function plainLine(raw) {
|
|
43
|
+
return raw
|
|
44
|
+
.replace(CONTROL_CHARS, ' ')
|
|
45
|
+
.replace(/^\s*(?:#{1,6}\s+|[-*+]\s+|>\s+|\d+\.\s+)/, '') // heading / list / quote markers
|
|
46
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1') // [text](url) → text
|
|
47
|
+
.replace(/\*\*|__|`/g, '') // strong / code markers
|
|
48
|
+
// Paired single-marker emphasis (`*fix*`, `_fix_`), guarded by word boundaries so an identifier
|
|
49
|
+
// like `snake_case_name` or a bare `a * b` is left alone.
|
|
50
|
+
.replace(/(^|[^\w*])\*([^*\s][^*]*?)\*(?![\w*])/g, '$1$2')
|
|
51
|
+
.replace(/(^|[^\w_])_([^_\s][^_]*?)_(?![\w_])/g, '$1$2')
|
|
52
|
+
.replace(/\s+/g, ' ')
|
|
53
|
+
.trim();
|
|
54
|
+
}
|
|
55
|
+
/** The intent's first non-blank line as plain words, or `''`. */
|
|
56
|
+
function firstLine(intent) {
|
|
57
|
+
for (const raw of intent.split(/\r?\n/)) {
|
|
58
|
+
const line = plainLine(raw);
|
|
59
|
+
if (line !== '')
|
|
60
|
+
return line;
|
|
61
|
+
}
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The PR title / commit subject: the intent's first line, whole when it fits, otherwise cut at the
|
|
66
|
+
* last word boundary that leaves room for a single `…` — so the result is ≤ 72 characters and never
|
|
67
|
+
* ends mid-word (the F-3R2-014 headline `…scenario CLN-2) aga`). Dangling punctuation before the
|
|
68
|
+
* ellipsis is dropped. A blank intent names the run instead — through the SAME bounded cut, so a
|
|
69
|
+
* long caller-supplied session id (the CLI passes `--session` through) is never cut mid-id either
|
|
70
|
+
* (Copilot on #525): the body names the run id in full.
|
|
71
|
+
*/
|
|
72
|
+
export function deliverTitle(intent, runId) {
|
|
73
|
+
const line = firstLine(intent);
|
|
74
|
+
// The run id is caller-supplied too (`LaunchSchema` only requires it non-empty): a newline in it
|
|
75
|
+
// must not turn the title into two lines and break the framing (Copilot on #525).
|
|
76
|
+
return boundedTitle(line === '' ? oneLine(`wicked-crew run ${oneLine(runId)}`) : line);
|
|
77
|
+
}
|
|
78
|
+
/** `line` whole when it fits, else cut at a word boundary with a single `…` — ≤ 72 characters. */
|
|
79
|
+
function boundedTitle(line) {
|
|
80
|
+
if (line.length <= DELIVER_TITLE_MAX)
|
|
81
|
+
return line;
|
|
82
|
+
const room = DELIVER_TITLE_MAX - 1; // one character is the ellipsis
|
|
83
|
+
const head = line.slice(0, room + 1); // one past the room: a space HERE means the room ends a word
|
|
84
|
+
const cut = head.lastIndexOf(' ');
|
|
85
|
+
// A single 72+ character token has no boundary to cut at; then — and only then — it is cut hard.
|
|
86
|
+
const kept = (cut > 0 ? head.slice(0, cut) : head.slice(0, room)).replace(/[\s,;:(\-–—]+$/u, '');
|
|
87
|
+
return `${kept}…`;
|
|
88
|
+
}
|
|
89
|
+
// ── issue references ───────────────────────────────────────────────────────────────────────────
|
|
90
|
+
/** `fix issue #214`, `fixes #7`, `closes wicked-studio#3`, `resolved: #9` — a closing verb + a ref. */
|
|
91
|
+
const CLOSING_REF = /\b(?:fix(?:es|ed)?|close[sd]?|resolve[sd]?)\b(?:\s+(?:issue|bug|for))?\s*:?\s*((?:[\w.-]+\/)?[\w.-]+)?#(\d+)\b/gi;
|
|
92
|
+
/** Any `#N`, `repo#N` or `owner/repo#N` not glued to a word/path (so `a/b#1` is one ref, `#1a` none). */
|
|
93
|
+
const ANY_REF = /(?<![\w/#])((?:[\w.-]+\/)?[\w.-]+)?#(\d+)\b/g;
|
|
94
|
+
/**
|
|
95
|
+
* The issues the intent names, split into the ones it says it fixes and the rest.
|
|
96
|
+
*
|
|
97
|
+
* GitHub links and closes on `#N` (this repo) and `owner/repo#N` only. An OWNER-LESS `repo#N`
|
|
98
|
+
* does neither — so when its repo segment names the delivery repo (`repoRef`, the registered
|
|
99
|
+
* repo id the PR lands in) it is emitted as plain `#N` (review W3-K2: `fixes wicked-studio#214`
|
|
100
|
+
* on a wicked-studio delivery must close #214). Any other owner-less `repo#N` rides verbatim as
|
|
101
|
+
* information; `owner/repo#N` is left exactly as written.
|
|
102
|
+
*/
|
|
103
|
+
export function issueRefs(intent, repoRef) {
|
|
104
|
+
const normalize = (prefix, n) => {
|
|
105
|
+
if (prefix === undefined || prefix === '')
|
|
106
|
+
return `#${n}`;
|
|
107
|
+
if (!prefix.includes('/') && repoRef !== undefined && repoRef !== null && prefix === repoRef)
|
|
108
|
+
return `#${n}`;
|
|
109
|
+
return `${prefix}#${n}`;
|
|
110
|
+
};
|
|
111
|
+
const fixes = [];
|
|
112
|
+
const refs = [];
|
|
113
|
+
for (const m of intent.matchAll(CLOSING_REF)) {
|
|
114
|
+
const ref = normalize(m[1], m[2]);
|
|
115
|
+
if (!fixes.includes(ref))
|
|
116
|
+
fixes.push(ref);
|
|
117
|
+
}
|
|
118
|
+
for (const m of intent.matchAll(ANY_REF)) {
|
|
119
|
+
const ref = normalize(m[1], m[2]);
|
|
120
|
+
if (!fixes.includes(ref) && !refs.includes(ref))
|
|
121
|
+
refs.push(ref);
|
|
122
|
+
}
|
|
123
|
+
return { fixes, refs };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* How much of the intent the deliver SCRIPT carries in its embedded fallback text. The script is
|
|
127
|
+
* one `bash -lc` argument, and `LaunchSchema.problem` has no length cap, so an unbounded intent
|
|
128
|
+
* could exceed a platform's single-argument limit (Linux: 128 KiB) and fail the phase with E2BIG
|
|
129
|
+
* before it runs (Copilot on #525). The run-derived text the daemon answers is NOT bounded — it
|
|
130
|
+
* travels over HTTP, never through argv.
|
|
131
|
+
*/
|
|
132
|
+
export const EMBEDDED_INTENT_CAP = 8_000;
|
|
133
|
+
const EMBEDDED_INTENT_NOTE = '_(the intent is longer than the deliver script embeds — the full text is on the run record)_';
|
|
134
|
+
/** `intent` bounded for embedding in the script: whole when it fits, else cut and said so. */
|
|
135
|
+
export function boundIntentForEmbedding(intent) {
|
|
136
|
+
if (intent.length <= EMBEDDED_INTENT_CAP)
|
|
137
|
+
return intent;
|
|
138
|
+
return `${intent.slice(0, EMBEDDED_INTENT_CAP).trimEnd()}\n\n${EMBEDDED_INTENT_NOTE}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The launch-time FALLBACK text the deliver script embeds (crew#524; wave-3 isolation review): the
|
|
142
|
+
* intent rides BOUNDED ({@link boundIntentForEmbedding} — the script is one argv entry) but the
|
|
143
|
+
* issue references are derived from the FULL intent FIRST, so a `fixes #214` that sits past the
|
|
144
|
+
* {@link EMBEDDED_INTENT_CAP} still reaches the body as `Fixes #214` — the line GitHub acts on —
|
|
145
|
+
* when no daemon answers `GET /runs/:id/deliver-text`. The title is the intent's first line either
|
|
146
|
+
* way. The cut copy carries the "longer than the script embeds" note, so the omission is disclosed
|
|
147
|
+
* and the reference is not.
|
|
148
|
+
*/
|
|
149
|
+
export function composeEmbeddedDeliverText(f) {
|
|
150
|
+
return composeDeliverText({ ...f, intent: boundIntentForEmbedding(f.intent) }, issueRefs(f.intent, f.repoRef));
|
|
151
|
+
}
|
|
152
|
+
// ── the body ───────────────────────────────────────────────────────────────────────────────────
|
|
153
|
+
/** A markdown table cell: control characters out, pipes escaped, bounded. */
|
|
154
|
+
function cell(value, max = 200) {
|
|
155
|
+
if (value === null || value === undefined || value === '')
|
|
156
|
+
return '—';
|
|
157
|
+
const s = String(value).replace(CONTROL_CHARS, ' ').replace(/\s+/g, ' ').trim().replace(/\|/g, '\\|');
|
|
158
|
+
return s.length <= max ? s : `${s.slice(0, max - 1)}…`;
|
|
159
|
+
}
|
|
160
|
+
function code(value) {
|
|
161
|
+
if (value === null || value === undefined || value === '')
|
|
162
|
+
return '—';
|
|
163
|
+
// One line (a code span cannot span lines); backticks inside a code span would end it early, so
|
|
164
|
+
// they are dropped; pipes are escaped for the table cells this lands in.
|
|
165
|
+
const one = oneLine(value).replace(/`/g, '').replace(/\|/g, '\\|');
|
|
166
|
+
return one === '' ? '—' : `\`${one}\``;
|
|
167
|
+
}
|
|
168
|
+
function duration(ms) {
|
|
169
|
+
if (ms === null || !Number.isFinite(ms))
|
|
170
|
+
return '—';
|
|
171
|
+
return ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;
|
|
172
|
+
}
|
|
173
|
+
function exitLabel(c) {
|
|
174
|
+
if (c.exitCode !== null)
|
|
175
|
+
return String(c.exitCode);
|
|
176
|
+
if (c.timedOut)
|
|
177
|
+
return 'timed out';
|
|
178
|
+
if (c.spawnError !== null && c.spawnError !== '')
|
|
179
|
+
return `spawn error: ${c.spawnError}`;
|
|
180
|
+
return '—';
|
|
181
|
+
}
|
|
182
|
+
/** The product site — never a repo owner handle (crew bakes no account name into a script). */
|
|
183
|
+
const FOOTER_LINK = '[wicked-crew](https://wc.wickedagile.com)';
|
|
184
|
+
/**
|
|
185
|
+
* The PR title + body (and, through {@link framedDeliverText}, the commit message) for a run.
|
|
186
|
+
* Never empty: every section either carries the recorded facts or says why it does not.
|
|
187
|
+
*
|
|
188
|
+
* `links` defaults to the issue references of `f.intent`; the embedded-fallback path passes the
|
|
189
|
+
* references of the FULL intent while `f.intent` is the bounded copy ({@link composeEmbeddedDeliverText}).
|
|
190
|
+
*/
|
|
191
|
+
export function composeDeliverText(f, links = issueRefs(f.intent, f.repoRef)) {
|
|
192
|
+
const title = deliverTitle(f.intent, f.runId);
|
|
193
|
+
const { fixes, refs } = links;
|
|
194
|
+
const intent = f.intent.replace(/\r\n?/g, '\n').replace(CONTROL_CHARS, ' ').trim();
|
|
195
|
+
const out = [];
|
|
196
|
+
out.push('## Intent', '', intent === '' ? '_(the run recorded no intent)_' : intent, '');
|
|
197
|
+
if (fixes.length > 0 || refs.length > 0) {
|
|
198
|
+
for (const x of fixes)
|
|
199
|
+
out.push(`Fixes ${x}`);
|
|
200
|
+
if (refs.length > 0)
|
|
201
|
+
out.push(`Refs: ${refs.join(', ')}`);
|
|
202
|
+
out.push('');
|
|
203
|
+
}
|
|
204
|
+
out.push('## Run', '');
|
|
205
|
+
// The label is the same one-line code span as the unlinked form — a caller-supplied id cannot
|
|
206
|
+
// break the line or the Markdown (the URL half is `urlPathSegment`-encoded by `runUrlFor`).
|
|
207
|
+
out.push(f.runUrl !== null ? `- Run: [${code(f.runId)}](${f.runUrl})` : `- Run: ${code(f.runId)}`);
|
|
208
|
+
const where = [
|
|
209
|
+
f.workflowId !== null && f.workflowId !== '' ? `workflow ${code(f.workflowId)}` : null,
|
|
210
|
+
f.repoRef !== null && f.repoRef !== '' ? `repo ${code(f.repoRef)}` : null,
|
|
211
|
+
].filter((s) => s !== null);
|
|
212
|
+
if (where.length > 0)
|
|
213
|
+
out.push(`- ${where.join(' · ')}`);
|
|
214
|
+
out.push('');
|
|
215
|
+
out.push('## Phases', '');
|
|
216
|
+
if (f.source === 'workflow') {
|
|
217
|
+
out.push('_From the workflow definition at launch — the daemon could not be asked for the run record ' +
|
|
218
|
+
'when this PR opened, so seats and gate outcomes are not shown. Every phase before `deliver` ' +
|
|
219
|
+
'had passed its gate for the deliver phase to run._', '');
|
|
220
|
+
}
|
|
221
|
+
if (f.phases.length === 0) {
|
|
222
|
+
out.push('_(no phases recorded)_');
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
out.push('| phase | stage | role | seat | gate | outcome |', '|---|---|---|---|---|---|');
|
|
226
|
+
for (const p of f.phases) {
|
|
227
|
+
out.push(`| ${code(p.id)} | ${cell(p.stage)} | ${cell(p.role)} | ${cell(p.seat)} | ${cell(p.gate)} | ${cell(p.outcome)} |`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
out.push('');
|
|
231
|
+
out.push('## Repo checks', '');
|
|
232
|
+
if (f.source === 'workflow') {
|
|
233
|
+
out.push('_Not available at composition time — the run record has them._');
|
|
234
|
+
}
|
|
235
|
+
else if (f.checks === null || f.checks.length === 0) {
|
|
236
|
+
out.push('_The run recorded no repo checks (no `typecheck` / `lint` / `test` script was found, or the ' +
|
|
237
|
+
'workflow has no verify phase)._');
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
out.push('| check | command | exit | duration |', '|---|---|---|---|');
|
|
241
|
+
for (const c of f.checks) {
|
|
242
|
+
out.push(`| ${cell(c.name)} | ${code(c.command)} | ${cell(exitLabel(c))} | ${duration(c.durationMs)} |`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
out.push('');
|
|
246
|
+
out.push('## Evaluator verdict', '');
|
|
247
|
+
if (f.source === 'workflow') {
|
|
248
|
+
out.push('_Not available at composition time — the run record has it._');
|
|
249
|
+
}
|
|
250
|
+
else if (f.verdicts.length === 0) {
|
|
251
|
+
out.push('_This workflow has no evaluator phase._');
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
for (const v of f.verdicts) {
|
|
255
|
+
const reason = v.reason !== null && v.reason.trim() !== '' ? ` — ${cell(v.reason, 400)}` : '';
|
|
256
|
+
out.push(`- ${code(v.phase)} (${cell(v.seat ?? 'seat unknown')}): **${cell(v.verdict)}**${reason}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
out.push('');
|
|
260
|
+
out.push('---', '', `Delivered by ${FOOTER_LINK} run ${code(f.runId)}. Merge stays human: the phase opens the PR, never merges it.`);
|
|
261
|
+
return { title, body: out.join('\n') };
|
|
262
|
+
}
|
|
263
|
+
/** The one shape both carriers speak: title, blank line, body, trailing newline. */
|
|
264
|
+
export function framedDeliverText(text) {
|
|
265
|
+
return `${text.title}\n\n${text.body}\n`;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* The inverse of {@link framedDeliverText}, or `null` when the text is not framed that way — a
|
|
269
|
+
* non-empty title line, a blank line 2, and a body with something in it (the same three conditions
|
|
270
|
+
* the deliver script's `_framed` check applies before it accepts a daemon answer).
|
|
271
|
+
*/
|
|
272
|
+
export function parseFramedDeliverText(framed) {
|
|
273
|
+
const lines = framed.split('\n');
|
|
274
|
+
if (lines.length < 3 || lines[0].trim() === '' || lines[1] !== '')
|
|
275
|
+
return null;
|
|
276
|
+
const body = lines.slice(2).join('\n').replace(/\n$/, '');
|
|
277
|
+
if (body.trim() === '')
|
|
278
|
+
return null;
|
|
279
|
+
return { title: lines[0], body };
|
|
280
|
+
}
|
|
281
|
+
// ── facts ──────────────────────────────────────────────────────────────────────────────────────
|
|
282
|
+
/** A `GateSpec` (or the engine's loose string form) as a short label. */
|
|
283
|
+
export function gateLabel(gate) {
|
|
284
|
+
if (gate === undefined || gate === null)
|
|
285
|
+
return '—';
|
|
286
|
+
if (typeof gate === 'string')
|
|
287
|
+
return gate;
|
|
288
|
+
if ('human_confirm_if' in gate)
|
|
289
|
+
return `human if ${gate.human_confirm_if.replace(/_/g, ' ')}`;
|
|
290
|
+
if ('human_confirm' in gate)
|
|
291
|
+
return gate.human_confirm.unconditional ? 'human' : 'human (conditional)';
|
|
292
|
+
return '—';
|
|
293
|
+
}
|
|
294
|
+
/** `<run id>:<phase>` → `<phase>`; anything else is returned whole. */
|
|
295
|
+
function phaseIdOf(unit) {
|
|
296
|
+
const prefix = `${unit.session_id}:`;
|
|
297
|
+
return unit.id.startsWith(prefix) ? unit.id.slice(prefix.length) : unit.id;
|
|
298
|
+
}
|
|
299
|
+
function seatOf(unit) {
|
|
300
|
+
if (unit.routing?.method === 'tool')
|
|
301
|
+
return 'tool';
|
|
302
|
+
if (unit.assigned_cli !== null && unit.assigned_cli !== '')
|
|
303
|
+
return unit.assigned_cli;
|
|
304
|
+
const r = unit.routing;
|
|
305
|
+
if (r !== null && r !== undefined && 'winner' in r)
|
|
306
|
+
return r.winner;
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
function checksOf(unit) {
|
|
310
|
+
const rc = unit.repo_checks;
|
|
311
|
+
if (rc === null || rc === undefined || !Array.isArray(rc.checks))
|
|
312
|
+
return [];
|
|
313
|
+
return rc.checks.map((c) => ({
|
|
314
|
+
name: c.name ?? '—',
|
|
315
|
+
command: Array.isArray(c.argv) ? c.argv.join(' ') : '—',
|
|
316
|
+
exitCode: typeof c.exit_code === 'number' ? c.exit_code : null,
|
|
317
|
+
durationMs: typeof c.duration_ms === 'number' ? c.duration_ms : null,
|
|
318
|
+
timedOut: c.timed_out === true,
|
|
319
|
+
spawnError: typeof c.spawn_error === 'string' ? c.spawn_error : null,
|
|
320
|
+
}));
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* A composed per-run workflow id (`<base>-deliver-<run id>`, `<base>-verified-<run id>`; see
|
|
324
|
+
* `composeDeliverWorkflow` / `composeDeliverableFloor`) reads as its base. The composed id is
|
|
325
|
+
* capped at 128 characters, so for a long caller-supplied run id the marker's tail is CUT — the
|
|
326
|
+
* tail is therefore matched as a prefix of the sanitised run id, not whole.
|
|
327
|
+
*/
|
|
328
|
+
export function baseWorkflowId(workflowId, runId) {
|
|
329
|
+
const safeRunId = runId.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
330
|
+
let id = workflowId;
|
|
331
|
+
for (const marker of ['-deliver-', '-verified-']) {
|
|
332
|
+
const at = id.indexOf(marker);
|
|
333
|
+
if (at > 0 && safeRunId.startsWith(id.slice(at + marker.length)))
|
|
334
|
+
id = id.slice(0, at);
|
|
335
|
+
}
|
|
336
|
+
return id;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* The facts from a persisted run view — what the daemon answers on `GET /runs/:id/deliver-text`.
|
|
340
|
+
* The deliver phase itself (running while it asks) is listed as `this PR`.
|
|
341
|
+
*
|
|
342
|
+
* `resolved.workflowId` is the DEFINITION the route resolved for the run (`resolveRunWorkflow`
|
|
343
|
+
* over the full registry): the engine stores an instance id (`wf-<uuid>`) that `sessionsDetail()`
|
|
344
|
+
* patches back to a name for BUILT-INS only, so a user-registered workflow would otherwise read as
|
|
345
|
+
* `workflow wf-…` here. Absent, the view's id is used (with the per-run composition suffix cut).
|
|
346
|
+
*/
|
|
347
|
+
export function factsFromRun(view, runUrl, resolved = {}) {
|
|
348
|
+
const s = view.session;
|
|
349
|
+
const units = [...view.units].sort((a, b) => a.ord - b.ord);
|
|
350
|
+
const checks = units.flatMap(checksOf);
|
|
351
|
+
return {
|
|
352
|
+
runId: s.id,
|
|
353
|
+
intent: s.problem ?? '',
|
|
354
|
+
workflowId: resolved.workflowId ?? baseWorkflowId(s.workflow_id, s.id),
|
|
355
|
+
repoRef: s.repo_ref,
|
|
356
|
+
runUrl,
|
|
357
|
+
source: 'run',
|
|
358
|
+
phases: units.map((u) => {
|
|
359
|
+
const id = phaseIdOf(u);
|
|
360
|
+
const running = u.status === 'pending' || u.status === 'distributed'; // not yet done: it is asking
|
|
361
|
+
return {
|
|
362
|
+
id,
|
|
363
|
+
stage: u.stage,
|
|
364
|
+
role: u.role ?? 'neutral',
|
|
365
|
+
gate: gateLabel(u.gate),
|
|
366
|
+
seat: seatOf(u),
|
|
367
|
+
outcome: id === 'deliver' && running ? 'this PR' : (u.phase_status ?? u.status),
|
|
368
|
+
};
|
|
369
|
+
}),
|
|
370
|
+
checks: checks.length > 0 ? checks : null,
|
|
371
|
+
verdicts: units
|
|
372
|
+
.filter((u) => u.role === 'evaluator')
|
|
373
|
+
.map((u) => ({
|
|
374
|
+
phase: phaseIdOf(u),
|
|
375
|
+
seat: seatOf(u),
|
|
376
|
+
verdict: u.phase_status ?? u.status,
|
|
377
|
+
reason: u.denial_reason,
|
|
378
|
+
})),
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
/** What is known at LAUNCH, from the workflow definition — the script's embedded fallback. */
|
|
382
|
+
export function factsFromWorkflow(input) {
|
|
383
|
+
return {
|
|
384
|
+
runId: input.runId,
|
|
385
|
+
intent: input.intent ?? '',
|
|
386
|
+
workflowId: input.workflowId,
|
|
387
|
+
repoRef: input.repoRef,
|
|
388
|
+
runUrl: input.runUrl,
|
|
389
|
+
source: 'workflow',
|
|
390
|
+
phases: input.phases.map((p) => ({
|
|
391
|
+
id: p.id,
|
|
392
|
+
stage: p.kind,
|
|
393
|
+
role: p.role,
|
|
394
|
+
gate: gateLabel(p.gate),
|
|
395
|
+
seat: p.executor?.type === 'tool' ? 'tool' : null,
|
|
396
|
+
outcome: '—',
|
|
397
|
+
})),
|
|
398
|
+
checks: null,
|
|
399
|
+
verdicts: [],
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* `s` as ONE URL path segment, RFC 3986 strict: everything but unreserved characters is
|
|
404
|
+
* percent-encoded — `encodeURIComponent` alone leaves `!'()*` alone, and `'` in particular must not
|
|
405
|
+
* reach a single-quoted shell literal (the deliver script bakes this in; Copilot on #525).
|
|
406
|
+
*/
|
|
407
|
+
export function urlPathSegment(s) {
|
|
408
|
+
return encodeURIComponent(s).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
409
|
+
}
|
|
410
|
+
/** Is `host` (as `URL.hostname` spells it) the local machine — `127.0.0.0/8`, `::1`, `localhost`? */
|
|
411
|
+
function isLoopbackHost(host) {
|
|
412
|
+
const h = host.replace(/^\[|\]$/g, '').toLowerCase();
|
|
413
|
+
return h === 'localhost' || h === '::1' || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h);
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* The studio bookmark for a run under a daemon origin (`http://127.0.0.1:7701/runs/<id>`), or
|
|
417
|
+
* null. LOOPBACK ORIGINS ONLY (review W3-K4): a daemon bound to a LAN host or IP would otherwise
|
|
418
|
+
* put that host into a public PR body; the run id itself is always named in the text.
|
|
419
|
+
*/
|
|
420
|
+
export function runUrlFor(origin, runId) {
|
|
421
|
+
if (origin === null || origin === undefined || origin === '')
|
|
422
|
+
return null;
|
|
423
|
+
let host;
|
|
424
|
+
try {
|
|
425
|
+
host = new URL(origin).hostname;
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
if (!isLoopbackHost(host))
|
|
431
|
+
return null;
|
|
432
|
+
return `${origin.replace(/\/+$/, '')}/runs/${urlPathSegment(runId)}`;
|
|
433
|
+
}
|
|
434
|
+
//# sourceMappingURL=deliver-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver-text.js","sourceRoot":"","sources":["../../src/core/deliver-text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deliver-failure triage — wicked-core#431 follow-through (crew consumes wicked-core#433).
|
|
3
|
+
*
|
|
4
|
+
* The deliver phase is a TOOL unit: a bash script the engine spawns (`run_tool_cmd`); no CLI seat
|
|
5
|
+
* runs it. When it exits non-zero the engine still emits `stepFailed {failureKind: "workerError"}` —
|
|
6
|
+
* the Tool path has no finer kind — and hands the excerpt to its agent triage judge, which answers
|
|
7
|
+
* `escalate` (a human decides). Crew's own folds over `stepFailed` must not read that `workerError`
|
|
8
|
+
* literally: `api/seat-health.ts` used to mark the unit's ASSIGNED seat inactive on ANY
|
|
9
|
+
* `workerError`, so a `deliver: LIFT-CONFLICT` refusal blamed a CLI for a git state.
|
|
10
|
+
*
|
|
11
|
+
* Since wicked-core#433 the refusal can also be ENGINE-authored — the deliver LIFT + RE-VERIFY runs
|
|
12
|
+
* BEFORE the script (`wicked-core/src/deliver_lift.rs` `lift_and_reverify`); its texts, in order:
|
|
13
|
+
* - `deliver: the worktree's HEAD is attached to `<ref>` / is detached, not the run branch
|
|
14
|
+
* `wicked/<run>` — nothing was lifted, reset or pushed; …` (the run-branch precondition);
|
|
15
|
+
* - `deliver: the lift onto <base> (<tip>) could not be applied cleanly — …` (a partial worktree);
|
|
16
|
+
* - `deliver: LIFT-CONFLICT — lifting the run's work onto <base> (<tip>) would conflict in: …`
|
|
17
|
+
* (the worktree was left exactly as verified; carries crew's own marker ON PURPOSE so the
|
|
18
|
+
* strand derivation — `completed` + `delivery: 'stranded'`, `POST /runs/:id/deliver` — fires);
|
|
19
|
+
* - `deliver: the worktree could not be snapshotted before delivery (…); nothing was pushed …`;
|
|
20
|
+
* - `deliver: <why>, and the repository's own checks FAILED on it: …` — the RE-VERIFY the engine
|
|
21
|
+
* runs whenever the worktree's tree is not the tree the run verified (`<why>` = "the lift
|
|
22
|
+
* changed the tree" | "the worktree's tree X is not the tree the run verified (Y)" | "the run
|
|
23
|
+
* recorded no verified tree"); the worktree holds an UNVERIFIED tree — NOT a strand, a post-hoc
|
|
24
|
+
* lift would push it;
|
|
25
|
+
* - `deliver: the repository's checks passed but CHANGED the worktree while running …` /
|
|
26
|
+
* `deliver: the repository's checks passed but the worktree could not be re-snapshotted …`
|
|
27
|
+
* (a check script that edits tracked files; inspect).
|
|
28
|
+
* Every one of them — and every refusal crew's own script prints (`core/deliver.ts`: nothing to
|
|
29
|
+
* deliver, the default branch, a moved verified base, a failed `gh`) — is an OPERATOR decision,
|
|
30
|
+
* never a seat fault. This module recognises them from the excerpt the engine puts on
|
|
31
|
+
* `stepFailed.detail` / the unit's `denial_reason` — head 150 + tail 250 chars of the WHOLE Tool
|
|
32
|
+
* output (`bounded_excerpt` in `actor.rs`). The engine's refusals ARE the whole output (the command
|
|
33
|
+
* never ran) and every phrase matched here sits inside the first 150 chars of that text, so they
|
|
34
|
+
* survive in the head. The script's refusals come AFTER real fetch / install / codegen chatter, so
|
|
35
|
+
* only the tail is theirs: every script marker (`LIFT-CONFLICT`, `BASE MOVED`, `PREFLIGHT CHANGED`)
|
|
36
|
+
* TRAILS its last line and lands in the tail-250 (review F-527-001).
|
|
37
|
+
*
|
|
38
|
+
* ORDERING: this is a TEXT classifier and assumes nothing about the event stream. In particular a
|
|
39
|
+
* deliver unit refused for a wrong HEAD ref (`deliver: the worktree's HEAD is attached to …`) emits
|
|
40
|
+
* its `stepFailed` WITHOUT a preceding `deliverLiftEvaluated` — the run-branch precondition runs
|
|
41
|
+
* before any lift — so no consumer (this one, the strand derivation, seat health, the studio's
|
|
42
|
+
* delivery card) may treat the lift event as a prerequisite of a deliver failure.
|
|
43
|
+
*/
|
|
44
|
+
/** The engine's lift-conflict remedy (`LiftOutcome::Conflict`) — crew's marker plus the engine's words. */
|
|
45
|
+
export declare const ENGINE_LIFT_CONFLICT_PHRASE = "deliver: LIFT-CONFLICT \u2014 lifting the run's work onto";
|
|
46
|
+
/** The engine refused before any lift: the worktree is not on its run branch (`require_run_branch`). */
|
|
47
|
+
export declare const ENGINE_RUN_BRANCH_PHRASE = "nothing was lifted, reset or pushed; the deliver script only pushes the run branch";
|
|
48
|
+
/** The engine's apply failure (`LiftOutcome::Failed`) — the line starts `deliver: the lift onto`. */
|
|
49
|
+
export declare const ENGINE_LIFT_APPLY_FAILED_PHRASE = "could not be applied cleanly";
|
|
50
|
+
/** The engine could not identify the tree it was about to ship (pre-check snapshot failed). */
|
|
51
|
+
export declare const ENGINE_SNAPSHOT_FAILED_PHRASE = "deliver: the worktree could not be snapshotted before delivery";
|
|
52
|
+
/** The engine's re-verify: the repository's checks FAILED on the tree that would ship. */
|
|
53
|
+
export declare const ENGINE_REVERIFY_FAILED_PHRASE = "repository's own checks FAILED on";
|
|
54
|
+
/** The engine's post-check proof failing: the checks changed the tree, or it could not be re-snapshotted. */
|
|
55
|
+
export declare const ENGINE_CHECKS_MUTATED_PHRASE = "deliver: the repository's checks passed but";
|
|
56
|
+
/**
|
|
57
|
+
* What kind of deliver refusal a failed deliver unit's excerpt carries.
|
|
58
|
+
* - `lift_conflict` — the engine's lift or the script's rebase/push hit a collision (recoverable);
|
|
59
|
+
* - `run_branch_refused` — the worktree is not on its run branch; nothing was touched (engine);
|
|
60
|
+
* - `lift_apply_failed` — the lift could not be applied cleanly, partial worktree (engine);
|
|
61
|
+
* - `snapshot_failed` — the worktree could not be snapshotted before delivery (engine);
|
|
62
|
+
* - `reverify_failed` — the repository's checks FAILED on the tree that would ship (engine);
|
|
63
|
+
* - `checks_mutated` — the checks passed but changed the tree / could not be re-proven (engine);
|
|
64
|
+
* - `base_moved` — the script found origin/<default> past `WICKED_DELIVER_VERIFIED_BASE` (script);
|
|
65
|
+
* - `preflight_changed` — the crew#426 lockfile/codegen re-sync changed the verified tree (script);
|
|
66
|
+
* - `script_refusal` — any other loud `deliver: …` refusal the script prints (script).
|
|
67
|
+
*/
|
|
68
|
+
export type DeliverFailureKind = 'lift_conflict' | 'run_branch_refused' | 'lift_apply_failed' | 'snapshot_failed' | 'reverify_failed' | 'checks_mutated' | 'base_moved' | 'preflight_changed' | 'script_refusal';
|
|
69
|
+
export interface DeliverFailureTriage {
|
|
70
|
+
kind: DeliverFailureKind;
|
|
71
|
+
/** Who wrote the refusal: the engine's deliver lift, or crew's own deliver script. */
|
|
72
|
+
author: 'engine' | 'script';
|
|
73
|
+
/** Always `'escalate'`: a deliver refusal is an operator decision, never a seat (worker) fault. */
|
|
74
|
+
disposition: 'escalate';
|
|
75
|
+
/**
|
|
76
|
+
* Whether the run's work is intact and post-hoc deliverable (`POST /runs/:id/deliver` after the
|
|
77
|
+
* operator clears the collision) — `true` only for a lift conflict, the shape crew's strand
|
|
78
|
+
* derivation already keys on (`isDeliverConflictStranded`). A failed re-verify, an apply failure
|
|
79
|
+
* or a moved base must NOT be offered a post-hoc push: that would deliver a tree nobody verified.
|
|
80
|
+
*/
|
|
81
|
+
recoverable: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Classify a failed deliver unit's excerpt (`stepFailed.detail`, or the unit's `denial_reason`).
|
|
85
|
+
* `null` when the text carries no deliver refusal at all — a spawn/infra failure (`bash: gh:
|
|
86
|
+
* command not found`), or a unit that is not the deliver phase — so callers fall back to their
|
|
87
|
+
* default reading of `failureKind`.
|
|
88
|
+
*/
|
|
89
|
+
export declare function triageDeliverFailure(detail: string | null | undefined): DeliverFailureTriage | null;
|
|
90
|
+
//# sourceMappingURL=deliver-triage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver-triage.d.ts","sourceRoot":"","sources":["../../src/core/deliver-triage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAQH,2GAA2G;AAC3G,eAAO,MAAM,2BAA2B,8DAAkE,CAAC;AAC3G,wGAAwG;AACxG,eAAO,MAAM,wBAAwB,uFACiD,CAAC;AACvF,qGAAqG;AACrG,eAAO,MAAM,+BAA+B,iCAAiC,CAAC;AAC9E,+FAA+F;AAC/F,eAAO,MAAM,6BAA6B,mEAAmE,CAAC;AAC9G,0FAA0F;AAC1F,eAAO,MAAM,6BAA6B,sCAAsC,CAAC;AACjF,6GAA6G;AAC7G,eAAO,MAAM,4BAA4B,gDAAgD,CAAC;AAE1F;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,oBAAoB,GACpB,mBAAmB,GACnB,iBAAiB,GACjB,iBAAiB,GACjB,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,gBAAgB,CAAC;AAErB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,CAAC;IACzB,sFAAsF;IACtF,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,mGAAmG;IACnG,WAAW,EAAE,UAAU,CAAC;IACxB;;;;;OAKG;IACH,WAAW,EAAE,OAAO,CAAC;CACtB;AAeD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,oBAAoB,GAAG,IAAI,CAyBnG"}
|