wicked-crew 0.7.28 → 0.7.30
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 +12 -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 +728 -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 +171 -0
- package/dist/api/governance-health.d.ts.map +1 -0
- package/dist/api/governance-health.js +379 -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 +70 -12
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +375 -60
- package/dist/api/routes.js.map +1 -1
- package/dist/api/seat-health.d.ts +38 -0
- package/dist/api/seat-health.d.ts.map +1 -1
- package/dist/api/seat-health.js +88 -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/seat-standing.d.ts +101 -0
- package/dist/api/seat-standing.d.ts.map +1 -0
- package/dist/api/seat-standing.js +138 -0
- package/dist/api/seat-standing.js.map +1 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +37 -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 +102 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/adapter.d.ts +99 -1
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +149 -8
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-path.d.ts +21 -0
- package/dist/core/bridge-path.d.ts.map +1 -1
- package/dist/core/bridge-path.js +37 -0
- package/dist/core/bridge-path.js.map +1 -1
- package/dist/core/bridge-reaper.d.ts.map +1 -1
- package/dist/core/bridge-reaper.js +11 -4
- 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 +219 -0
- package/dist/core/governance-store.d.ts.map +1 -0
- package/dist/core/governance-store.js +290 -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 +29 -24
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +74 -7
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/interactive/chat-events.d.ts.map +1 -1
- package/dist/interactive/chat-events.js +5 -2
- package/dist/interactive/chat-events.js.map +1 -1
- package/dist/interactive/council-outcome.d.ts +28 -0
- package/dist/interactive/council-outcome.d.ts.map +1 -0
- package/dist/interactive/council-outcome.js +57 -0
- package/dist/interactive/council-outcome.js.map +1 -0
- package/dist/interactive/demo-events.d.ts.map +1 -1
- package/dist/interactive/demo-events.js +5 -2
- package/dist/interactive/demo-events.js.map +1 -1
- package/dist/interactive/doc-delete-routes.d.ts.map +1 -1
- package/dist/interactive/doc-delete-routes.js +3 -2
- package/dist/interactive/doc-delete-routes.js.map +1 -1
- package/dist/interactive/draft-events.d.ts.map +1 -1
- package/dist/interactive/draft-events.js +5 -2
- package/dist/interactive/draft-events.js.map +1 -1
- package/dist/interactive/edit-events.d.ts.map +1 -1
- package/dist/interactive/edit-events.js +5 -2
- package/dist/interactive/edit-events.js.map +1 -1
- package/dist/projects/auto-refresh.d.ts +54 -0
- package/dist/projects/auto-refresh.d.ts.map +1 -0
- package/dist/projects/auto-refresh.js +76 -0
- package/dist/projects/auto-refresh.js.map +1 -0
- 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 +20 -6
- package/dist/projects/graph.d.ts.map +1 -1
- package/dist/projects/graph.js +40 -13
- package/dist/projects/graph.js.map +1 -1
- package/dist/projects/routes.d.ts.map +1 -1
- package/dist/projects/routes.js +30 -11
- package/dist/projects/routes.js.map +1 -1
- package/dist/projects/state-home.d.ts +6 -0
- package/dist/projects/state-home.d.ts.map +1 -1
- package/dist/projects/state-home.js +9 -1
- package/dist/projects/state-home.js.map +1 -1
- package/dist/skills/guards.d.ts +17 -6
- package/dist/skills/guards.d.ts.map +1 -1
- package/dist/skills/guards.js +42 -15
- package/dist/skills/guards.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/skills/refs.d.ts +181 -17
- package/dist/skills/refs.d.ts.map +1 -1
- package/dist/skills/refs.js +345 -26
- package/dist/skills/refs.js.map +1 -1
- package/dist/skills/store.d.ts +22 -1
- package/dist/skills/store.d.ts.map +1 -1
- package/dist/skills/store.js +161 -23
- package/dist/skills/store.js.map +1 -1
- package/dist/studio/assets/index-CWUS9Ump.js +542 -0
- package/dist/studio/assets/{index-CK1uJWs2.css → index-_ydd-jKd.css} +1 -1
- package/dist/studio/index.html +2 -2
- package/dist/studio/testid-inventory.json +567 -6
- package/endpoint-manifest.json +67 -14
- package/package.json +4 -4
- package/dist/studio/assets/index-CdmCMh2f.js +0 -539
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
import type { GateSpec, PhaseDef, SessionView } from './types.js';
|
|
31
|
+
/** The PR title / commit subject cap — git's conventional subject width. */
|
|
32
|
+
export declare const DELIVER_TITLE_MAX = 72;
|
|
33
|
+
/** One phase of the run, with as much as is known about it at composition time. */
|
|
34
|
+
export interface DeliverPhaseFact {
|
|
35
|
+
id: string;
|
|
36
|
+
stage: string;
|
|
37
|
+
role: string;
|
|
38
|
+
gate: string;
|
|
39
|
+
/** The seat that did the work — `null` when unknown (launch time) or when the phase is tooling. */
|
|
40
|
+
seat: string | null;
|
|
41
|
+
/** The recorded gate outcome / unit status, or `—` at launch time. */
|
|
42
|
+
outcome: string;
|
|
43
|
+
}
|
|
44
|
+
/** One repo check the verify phase ran (`typecheck` / `lint` / `test`), as the engine recorded it. */
|
|
45
|
+
export interface DeliverCheckFact {
|
|
46
|
+
name: string;
|
|
47
|
+
command: string;
|
|
48
|
+
exitCode: number | null;
|
|
49
|
+
durationMs: number | null;
|
|
50
|
+
timedOut: boolean;
|
|
51
|
+
spawnError: string | null;
|
|
52
|
+
}
|
|
53
|
+
/** An evaluator-role phase's recorded verdict. */
|
|
54
|
+
export interface DeliverVerdictFact {
|
|
55
|
+
phase: string;
|
|
56
|
+
seat: string | null;
|
|
57
|
+
verdict: string;
|
|
58
|
+
reason: string | null;
|
|
59
|
+
}
|
|
60
|
+
/** Everything the composer needs. Built by {@link factsFromRun} or {@link factsFromWorkflow}. */
|
|
61
|
+
export interface DeliverTextFacts {
|
|
62
|
+
runId: string;
|
|
63
|
+
intent: string;
|
|
64
|
+
workflowId: string | null;
|
|
65
|
+
repoRef: string | null;
|
|
66
|
+
/** The studio bookmark for the run (`<daemon origin>/runs/<id>`), when the origin is known. */
|
|
67
|
+
runUrl: string | null;
|
|
68
|
+
/** `run`: from the persisted run view; `workflow`: from the definition at launch (no runtime facts). */
|
|
69
|
+
source: 'run' | 'workflow';
|
|
70
|
+
phases: DeliverPhaseFact[];
|
|
71
|
+
/** Recorded repo checks; `null` when the run recorded none. Ignored when `source` is `workflow`. */
|
|
72
|
+
checks: DeliverCheckFact[] | null;
|
|
73
|
+
verdicts: DeliverVerdictFact[];
|
|
74
|
+
}
|
|
75
|
+
export interface DeliverText {
|
|
76
|
+
/** ≤ {@link DELIVER_TITLE_MAX} characters, one line, never cut mid-word. */
|
|
77
|
+
title: string;
|
|
78
|
+
/** Markdown; never empty. */
|
|
79
|
+
body: string;
|
|
80
|
+
}
|
|
81
|
+
export interface IssueRefs {
|
|
82
|
+
/** `#N` (or `repo#N`) mentions the intent pairs with a closing verb — emitted as `Fixes …`. */
|
|
83
|
+
fixes: string[];
|
|
84
|
+
/** Every other issue mention — emitted as `Refs: …`. */
|
|
85
|
+
refs: string[];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The PR title / commit subject: the intent's first line, whole when it fits, otherwise cut at the
|
|
89
|
+
* last word boundary that leaves room for a single `…` — so the result is ≤ 72 characters and never
|
|
90
|
+
* ends mid-word (the F-3R2-014 headline `…scenario CLN-2) aga`). Dangling punctuation before the
|
|
91
|
+
* ellipsis is dropped. A blank intent names the run instead — through the SAME bounded cut, so a
|
|
92
|
+
* long caller-supplied session id (the CLI passes `--session` through) is never cut mid-id either
|
|
93
|
+
* (Copilot on #525): the body names the run id in full.
|
|
94
|
+
*/
|
|
95
|
+
export declare function deliverTitle(intent: string, runId: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* The issues the intent names, split into the ones it says it fixes and the rest.
|
|
98
|
+
*
|
|
99
|
+
* GitHub links and closes on `#N` (this repo) and `owner/repo#N` only. An OWNER-LESS `repo#N`
|
|
100
|
+
* does neither — so when its repo segment names the delivery repo (`repoRef`, the registered
|
|
101
|
+
* repo id the PR lands in) it is emitted as plain `#N` (review W3-K2: `fixes wicked-studio#214`
|
|
102
|
+
* on a wicked-studio delivery must close #214). Any other owner-less `repo#N` rides verbatim as
|
|
103
|
+
* information; `owner/repo#N` is left exactly as written.
|
|
104
|
+
*/
|
|
105
|
+
export declare function issueRefs(intent: string, repoRef?: string | null): IssueRefs;
|
|
106
|
+
/**
|
|
107
|
+
* How much of the intent the deliver SCRIPT carries in its embedded fallback text. The script is
|
|
108
|
+
* one `bash -lc` argument, and `LaunchSchema.problem` has no length cap, so an unbounded intent
|
|
109
|
+
* could exceed a platform's single-argument limit (Linux: 128 KiB) and fail the phase with E2BIG
|
|
110
|
+
* before it runs (Copilot on #525). The run-derived text the daemon answers is NOT bounded — it
|
|
111
|
+
* travels over HTTP, never through argv.
|
|
112
|
+
*/
|
|
113
|
+
export declare const EMBEDDED_INTENT_CAP = 8000;
|
|
114
|
+
/** `intent` bounded for embedding in the script: whole when it fits, else cut and said so. */
|
|
115
|
+
export declare function boundIntentForEmbedding(intent: string): string;
|
|
116
|
+
/**
|
|
117
|
+
* The launch-time FALLBACK text the deliver script embeds (crew#524; wave-3 isolation review): the
|
|
118
|
+
* intent rides BOUNDED ({@link boundIntentForEmbedding} — the script is one argv entry) but the
|
|
119
|
+
* issue references are derived from the FULL intent FIRST, so a `fixes #214` that sits past the
|
|
120
|
+
* {@link EMBEDDED_INTENT_CAP} still reaches the body as `Fixes #214` — the line GitHub acts on —
|
|
121
|
+
* when no daemon answers `GET /runs/:id/deliver-text`. The title is the intent's first line either
|
|
122
|
+
* way. The cut copy carries the "longer than the script embeds" note, so the omission is disclosed
|
|
123
|
+
* and the reference is not.
|
|
124
|
+
*/
|
|
125
|
+
export declare function composeEmbeddedDeliverText(f: DeliverTextFacts): DeliverText;
|
|
126
|
+
/**
|
|
127
|
+
* The PR title + body (and, through {@link framedDeliverText}, the commit message) for a run.
|
|
128
|
+
* Never empty: every section either carries the recorded facts or says why it does not.
|
|
129
|
+
*
|
|
130
|
+
* `links` defaults to the issue references of `f.intent`; the embedded-fallback path passes the
|
|
131
|
+
* references of the FULL intent while `f.intent` is the bounded copy ({@link composeEmbeddedDeliverText}).
|
|
132
|
+
*/
|
|
133
|
+
export declare function composeDeliverText(f: DeliverTextFacts, links?: IssueRefs): DeliverText;
|
|
134
|
+
/** The one shape both carriers speak: title, blank line, body, trailing newline. */
|
|
135
|
+
export declare function framedDeliverText(text: DeliverText): string;
|
|
136
|
+
/**
|
|
137
|
+
* The inverse of {@link framedDeliverText}, or `null` when the text is not framed that way — a
|
|
138
|
+
* non-empty title line, a blank line 2, and a body with something in it (the same three conditions
|
|
139
|
+
* the deliver script's `_framed` check applies before it accepts a daemon answer).
|
|
140
|
+
*/
|
|
141
|
+
export declare function parseFramedDeliverText(framed: string): DeliverText | null;
|
|
142
|
+
/** A `GateSpec` (or the engine's loose string form) as a short label. */
|
|
143
|
+
export declare function gateLabel(gate: GateSpec | string | undefined): string;
|
|
144
|
+
/**
|
|
145
|
+
* A composed per-run workflow id (`<base>-deliver-<run id>`, `<base>-verified-<run id>`; see
|
|
146
|
+
* `composeDeliverWorkflow` / `composeDeliverableFloor`) reads as its base. The composed id is
|
|
147
|
+
* capped at 128 characters, so for a long caller-supplied run id the marker's tail is CUT — the
|
|
148
|
+
* tail is therefore matched as a prefix of the sanitised run id, not whole.
|
|
149
|
+
*/
|
|
150
|
+
export declare function baseWorkflowId(workflowId: string, runId: string): string;
|
|
151
|
+
/**
|
|
152
|
+
* The facts from a persisted run view — what the daemon answers on `GET /runs/:id/deliver-text`.
|
|
153
|
+
* The deliver phase itself (running while it asks) is listed as `this PR`.
|
|
154
|
+
*
|
|
155
|
+
* `resolved.workflowId` is the DEFINITION the route resolved for the run (`resolveRunWorkflow`
|
|
156
|
+
* over the full registry): the engine stores an instance id (`wf-<uuid>`) that `sessionsDetail()`
|
|
157
|
+
* patches back to a name for BUILT-INS only, so a user-registered workflow would otherwise read as
|
|
158
|
+
* `workflow wf-…` here. Absent, the view's id is used (with the per-run composition suffix cut).
|
|
159
|
+
*/
|
|
160
|
+
export declare function factsFromRun(view: SessionView, runUrl: string | null, resolved?: {
|
|
161
|
+
workflowId?: string | null;
|
|
162
|
+
}): DeliverTextFacts;
|
|
163
|
+
/** What is known at LAUNCH, from the workflow definition — the script's embedded fallback. */
|
|
164
|
+
export declare function factsFromWorkflow(input: {
|
|
165
|
+
runId: string;
|
|
166
|
+
intent: string | undefined;
|
|
167
|
+
workflowId: string | null;
|
|
168
|
+
repoRef: string | null;
|
|
169
|
+
phases: PhaseDef[];
|
|
170
|
+
runUrl: string | null;
|
|
171
|
+
}): DeliverTextFacts;
|
|
172
|
+
/**
|
|
173
|
+
* `s` as ONE URL path segment, RFC 3986 strict: everything but unreserved characters is
|
|
174
|
+
* percent-encoded — `encodeURIComponent` alone leaves `!'()*` alone, and `'` in particular must not
|
|
175
|
+
* reach a single-quoted shell literal (the deliver script bakes this in; Copilot on #525).
|
|
176
|
+
*/
|
|
177
|
+
export declare function urlPathSegment(s: string): string;
|
|
178
|
+
/**
|
|
179
|
+
* The studio bookmark for a run under a daemon origin (`http://127.0.0.1:7701/runs/<id>`), or
|
|
180
|
+
* null. LOOPBACK ORIGINS ONLY (review W3-K4): a daemon bound to a LAN host or IP would otherwise
|
|
181
|
+
* put that host into a public PR body; the run id itself is always named in the text.
|
|
182
|
+
*/
|
|
183
|
+
export declare function runUrlFor(origin: string | null | undefined, runId: string): string | null;
|
|
184
|
+
//# sourceMappingURL=deliver-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver-text.d.ts","sourceRoot":"","sources":["../../src/core/deliver-text.ts"],"names":[],"mappings":"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"}
|
|
@@ -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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"}
|