wicked-crew 0.7.10 → 0.7.12
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/dist/api/delivery-index.d.ts +21 -0
- package/dist/api/delivery-index.d.ts.map +1 -1
- package/dist/api/delivery-index.js +35 -0
- package/dist/api/delivery-index.js.map +1 -1
- package/dist/api/group-index.d.ts +59 -0
- package/dist/api/group-index.d.ts.map +1 -0
- package/dist/api/group-index.js +100 -0
- package/dist/api/group-index.js.map +1 -0
- package/dist/api/post-hoc-deliver.d.ts +27 -0
- package/dist/api/post-hoc-deliver.d.ts.map +1 -1
- package/dist/api/post-hoc-deliver.js +54 -0
- package/dist/api/post-hoc-deliver.js.map +1 -1
- package/dist/api/retry-index.d.ts +6 -0
- package/dist/api/retry-index.d.ts.map +1 -1
- package/dist/api/retry-index.js +13 -6
- package/dist/api/retry-index.js.map +1 -1
- package/dist/api/routes.d.ts +55 -2
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +188 -17
- package/dist/api/routes.js.map +1 -1
- package/dist/api/seat-health.d.ts +11 -0
- package/dist/api/seat-health.d.ts.map +1 -1
- package/dist/api/seat-health.js +23 -0
- package/dist/api/seat-health.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +19 -5
- package/dist/api/server.js.map +1 -1
- package/dist/api/testing.d.ts.map +1 -1
- package/dist/api/testing.js +11 -27
- package/dist/api/testing.js.map +1 -1
- package/dist/campaigns/rollup.d.ts +39 -0
- package/dist/campaigns/rollup.d.ts.map +1 -0
- package/dist/campaigns/rollup.js +84 -0
- package/dist/campaigns/rollup.js.map +1 -0
- package/dist/campaigns/routes.d.ts +10 -3
- package/dist/campaigns/routes.d.ts.map +1 -1
- package/dist/campaigns/routes.js +27 -5
- package/dist/campaigns/routes.js.map +1 -1
- package/dist/cli/index.js +13 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/core/adapter.d.ts +0 -12
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +0 -14
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/daemon-signal-log.d.ts +44 -0
- package/dist/core/daemon-signal-log.d.ts.map +1 -0
- package/dist/core/daemon-signal-log.js +57 -0
- package/dist/core/daemon-signal-log.js.map +1 -0
- package/dist/core/deliver.d.ts +20 -3
- package/dist/core/deliver.d.ts.map +1 -1
- package/dist/core/deliver.js +82 -9
- package/dist/core/deliver.js.map +1 -1
- package/dist/studio/assets/{index-gtE6scX0.js → index-DuU8RZg9.js} +95 -95
- package/dist/studio/index.html +1 -1
- package/dist/studio/testid-inventory.json +47 -17
- package/endpoint-manifest.json +4 -3
- package/package.json +3 -3
- package/dist/campaigns/worktrees.d.ts +0 -39
- package/dist/campaigns/worktrees.d.ts.map +0 -1
- package/dist/campaigns/worktrees.js +0 -95
- package/dist/campaigns/worktrees.js.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process signal receipt log (crew#411).
|
|
3
|
+
*
|
|
4
|
+
* Node's `process.on('SIGTERM'/'SIGINT')` callbacks receive no sender pid —
|
|
5
|
+
* there is no SA_SIGINFO equivalent in the JS runtime. The best-effort record
|
|
6
|
+
* is therefore: signal name + epoch-ms timestamp.
|
|
7
|
+
*
|
|
8
|
+
* The log is read by `SeatHealthTracker` when an ACP bridge dies silently
|
|
9
|
+
* (`acpFallback` with `fallbackKind: session_died`) to distinguish:
|
|
10
|
+
*
|
|
11
|
+
* - "daemon also received SIGTERM at T" → likely a group/terminal signal that
|
|
12
|
+
* killed both the bridge and the daemon together
|
|
13
|
+
* - "no daemon signal within ±5s" → a pid-targeted external signal sent
|
|
14
|
+
* directly to the bridge, or a transport close (neither woke the daemon)
|
|
15
|
+
*
|
|
16
|
+
* The ring is bounded (64 entries) because signals are rare and the entries are
|
|
17
|
+
* tiny; the oldest entry is dropped once the cap is exceeded.
|
|
18
|
+
*/
|
|
19
|
+
export interface SignalEntry {
|
|
20
|
+
signal: 'SIGTERM' | 'SIGINT';
|
|
21
|
+
at: number;
|
|
22
|
+
}
|
|
23
|
+
/** Half-width of the default correlation window used by `findInWindow`. */
|
|
24
|
+
export declare const SIGNAL_CORRELATION_WINDOW_MS = 5000;
|
|
25
|
+
export declare class DaemonSignalLog {
|
|
26
|
+
private readonly _entries;
|
|
27
|
+
private static readonly MAX;
|
|
28
|
+
/**
|
|
29
|
+
* Append a signal receipt. `at` defaults to `Date.now()`; injectable so tests
|
|
30
|
+
* can set exact timestamps without mocking the clock process-wide.
|
|
31
|
+
*/
|
|
32
|
+
record(signal: 'SIGTERM' | 'SIGINT', at?: number): void;
|
|
33
|
+
/**
|
|
34
|
+
* Return the closest entry within [`aroundMs` ± `halfWindowMs`], or
|
|
35
|
+
* `undefined` when no entry falls in that interval.
|
|
36
|
+
* `halfWindowMs` defaults to `SIGNAL_CORRELATION_WINDOW_MS` (5 s).
|
|
37
|
+
*/
|
|
38
|
+
findInWindow(aroundMs: number, halfWindowMs?: number): SignalEntry | undefined;
|
|
39
|
+
/** All recorded entries, oldest first — a defensive copy, so a caller cannot mutate the ring. */
|
|
40
|
+
entries(): readonly SignalEntry[];
|
|
41
|
+
}
|
|
42
|
+
/** The daemon-wide singleton. The CLI records into it; the seat-health tracker reads from it. */
|
|
43
|
+
export declare const daemonSignalLog: DaemonSignalLog;
|
|
44
|
+
//# sourceMappingURL=daemon-signal-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-signal-log.d.ts","sourceRoot":"","sources":["../../src/core/daemon-signal-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,2EAA2E;AAC3E,eAAO,MAAM,4BAA4B,OAAQ,CAAC;AAElD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAM;IAEjC;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE,EAAE,SAAa,GAAG,IAAI;IAM3D;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,SAA+B,GAAG,WAAW,GAAG,SAAS;IAapG,iGAAiG;IACjG,OAAO,IAAI,SAAS,WAAW,EAAE;CAGlC;AAED,iGAAiG;AACjG,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process signal receipt log (crew#411).
|
|
3
|
+
*
|
|
4
|
+
* Node's `process.on('SIGTERM'/'SIGINT')` callbacks receive no sender pid —
|
|
5
|
+
* there is no SA_SIGINFO equivalent in the JS runtime. The best-effort record
|
|
6
|
+
* is therefore: signal name + epoch-ms timestamp.
|
|
7
|
+
*
|
|
8
|
+
* The log is read by `SeatHealthTracker` when an ACP bridge dies silently
|
|
9
|
+
* (`acpFallback` with `fallbackKind: session_died`) to distinguish:
|
|
10
|
+
*
|
|
11
|
+
* - "daemon also received SIGTERM at T" → likely a group/terminal signal that
|
|
12
|
+
* killed both the bridge and the daemon together
|
|
13
|
+
* - "no daemon signal within ±5s" → a pid-targeted external signal sent
|
|
14
|
+
* directly to the bridge, or a transport close (neither woke the daemon)
|
|
15
|
+
*
|
|
16
|
+
* The ring is bounded (64 entries) because signals are rare and the entries are
|
|
17
|
+
* tiny; the oldest entry is dropped once the cap is exceeded.
|
|
18
|
+
*/
|
|
19
|
+
/** Half-width of the default correlation window used by `findInWindow`. */
|
|
20
|
+
export const SIGNAL_CORRELATION_WINDOW_MS = 5_000;
|
|
21
|
+
export class DaemonSignalLog {
|
|
22
|
+
_entries = [];
|
|
23
|
+
static MAX = 64;
|
|
24
|
+
/**
|
|
25
|
+
* Append a signal receipt. `at` defaults to `Date.now()`; injectable so tests
|
|
26
|
+
* can set exact timestamps without mocking the clock process-wide.
|
|
27
|
+
*/
|
|
28
|
+
record(signal, at = Date.now()) {
|
|
29
|
+
this._entries.push({ signal, at });
|
|
30
|
+
if (this._entries.length > DaemonSignalLog.MAX)
|
|
31
|
+
this._entries.splice(0, this._entries.length - DaemonSignalLog.MAX);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Return the closest entry within [`aroundMs` ± `halfWindowMs`], or
|
|
35
|
+
* `undefined` when no entry falls in that interval.
|
|
36
|
+
* `halfWindowMs` defaults to `SIGNAL_CORRELATION_WINDOW_MS` (5 s).
|
|
37
|
+
*/
|
|
38
|
+
findInWindow(aroundMs, halfWindowMs = SIGNAL_CORRELATION_WINDOW_MS) {
|
|
39
|
+
let best;
|
|
40
|
+
let bestDelta = Infinity;
|
|
41
|
+
for (const e of this._entries) {
|
|
42
|
+
const delta = Math.abs(e.at - aroundMs);
|
|
43
|
+
if (delta <= halfWindowMs && delta < bestDelta) {
|
|
44
|
+
best = e;
|
|
45
|
+
bestDelta = delta;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return best;
|
|
49
|
+
}
|
|
50
|
+
/** All recorded entries, oldest first — a defensive copy, so a caller cannot mutate the ring. */
|
|
51
|
+
entries() {
|
|
52
|
+
return [...this._entries];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** The daemon-wide singleton. The CLI records into it; the seat-health tracker reads from it. */
|
|
56
|
+
export const daemonSignalLog = new DaemonSignalLog();
|
|
57
|
+
//# sourceMappingURL=daemon-signal-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-signal-log.js","sourceRoot":"","sources":["../../src/core/daemon-signal-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAC;AAElD,MAAM,OAAO,eAAe;IACT,QAAQ,GAAkB,EAAE,CAAC;IACtC,MAAM,CAAU,GAAG,GAAG,EAAE,CAAC;IAEjC;;;OAGG;IACH,MAAM,CAAC,MAA4B,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;QAClD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,eAAe,CAAC,GAAG;YAC5C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,QAAgB,EAAE,YAAY,GAAG,4BAA4B;QACxE,IAAI,IAA6B,CAAC;QAClC,IAAI,SAAS,GAAG,QAAQ,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC;YACxC,IAAI,KAAK,IAAI,YAAY,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;gBAC/C,IAAI,GAAG,CAAC,CAAC;gBACT,SAAS,GAAG,KAAK,CAAC;YACpB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iGAAiG;IACjG,OAAO;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;;AAGH,iGAAiG;AACjG,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
|
package/dist/core/deliver.d.ts
CHANGED
|
@@ -12,9 +12,13 @@
|
|
|
12
12
|
* (b) the script REFUSES to push `main`/`master` (or an empty/detached branch name) — the
|
|
13
13
|
* deliver phase only ever pushes run branches;
|
|
14
14
|
* (c) it STAGES AND COMMITS the run's work, then rebases onto origin's default branch before
|
|
15
|
-
* pushing
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* pushing. A conflict whose conflicted paths are ALL `CHANGELOG.md` is union-merged (both
|
|
16
|
+
* sides' additive lines kept) and the rebase continues — the crew#418 collision magnet, made
|
|
17
|
+
* to just deliver; ANY other conflict aborts the rebase (pushing nothing) and exits carrying
|
|
18
|
+
* {@link DELIVER_LIFT_CONFLICT_MARKER}, which crew reads as a recoverable STRAND, never a
|
|
19
|
+
* pushed conflicted tree;
|
|
20
|
+
* (d) `git push -u origin <branch>` — a non-fast-forward rejection carries the same lift-conflict
|
|
21
|
+
* marker (the remote branch moved), every other push failure stays a loud plain failure;
|
|
18
22
|
* (e) `gh pr create --head <branch> --fill`, with gh's output and exit status captured
|
|
19
23
|
* SEPARATELY so a gh failure fails the phase carrying gh's own message;
|
|
20
24
|
* (f) the PR URL is the last line of the phase output.
|
|
@@ -57,6 +61,19 @@
|
|
|
57
61
|
import type { PhaseDef, WorkflowDef } from './types.js';
|
|
58
62
|
/** The id of the appended phase — also the collision probe when a def already delivers. */
|
|
59
63
|
export declare const DELIVER_PHASE_ID = "deliver";
|
|
64
|
+
/**
|
|
65
|
+
* The sentinel the deliver script prints when it refuses on a LIFT COLLISION (crew#418) — a
|
|
66
|
+
* rebase conflict it could not union-resolve, or a non-fast-forward push. The run's WORK is
|
|
67
|
+
* complete and committed on its `wicked/<id>` branch; only the lift into origin collided.
|
|
68
|
+
*
|
|
69
|
+
* crew keys the "stranded, recoverable" reinterpretation on this EXACT substring appearing in
|
|
70
|
+
* the deliver unit's `denial_reason` (which carries the head+TAIL excerpt of the script's
|
|
71
|
+
* output, and the marker is always the script's last line — see {@link isDeliverConflictStranded}
|
|
72
|
+
* in `api/delivery-index.ts`). The script's OTHER loud refusals — wrong worktree branch, nothing
|
|
73
|
+
* to deliver, `gh` failure — and a spawn/infra failure deliberately OMIT the marker, so they stay
|
|
74
|
+
* terminal run failures exactly as before (the crew#400 refusal-vs-infra posture).
|
|
75
|
+
*/
|
|
76
|
+
export declare const DELIVER_LIFT_CONFLICT_MARKER = "deliver: LIFT-CONFLICT";
|
|
60
77
|
/**
|
|
61
78
|
* The hardened deliver script, run as `bash -lc <script>` (login shell so the operator's PATH —
|
|
62
79
|
* where `gh` lives — is loaded, same as the field overlay).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/core/deliver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/core/deliver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAExD,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,2BAA2B,CAAC;AA0BrE;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA6HvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAAC,SAAS,GAAE,MAAM,EAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAgBlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,WAAW,CAmBb"}
|
package/dist/core/deliver.js
CHANGED
|
@@ -12,9 +12,13 @@
|
|
|
12
12
|
* (b) the script REFUSES to push `main`/`master` (or an empty/detached branch name) — the
|
|
13
13
|
* deliver phase only ever pushes run branches;
|
|
14
14
|
* (c) it STAGES AND COMMITS the run's work, then rebases onto origin's default branch before
|
|
15
|
-
* pushing
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* pushing. A conflict whose conflicted paths are ALL `CHANGELOG.md` is union-merged (both
|
|
16
|
+
* sides' additive lines kept) and the rebase continues — the crew#418 collision magnet, made
|
|
17
|
+
* to just deliver; ANY other conflict aborts the rebase (pushing nothing) and exits carrying
|
|
18
|
+
* {@link DELIVER_LIFT_CONFLICT_MARKER}, which crew reads as a recoverable STRAND, never a
|
|
19
|
+
* pushed conflicted tree;
|
|
20
|
+
* (d) `git push -u origin <branch>` — a non-fast-forward rejection carries the same lift-conflict
|
|
21
|
+
* marker (the remote branch moved), every other push failure stays a loud plain failure;
|
|
18
22
|
* (e) `gh pr create --head <branch> --fill`, with gh's output and exit status captured
|
|
19
23
|
* SEPARATELY so a gh failure fails the phase carrying gh's own message;
|
|
20
24
|
* (f) the PR URL is the last line of the phase output.
|
|
@@ -56,6 +60,19 @@
|
|
|
56
60
|
*/
|
|
57
61
|
/** The id of the appended phase — also the collision probe when a def already delivers. */
|
|
58
62
|
export const DELIVER_PHASE_ID = 'deliver';
|
|
63
|
+
/**
|
|
64
|
+
* The sentinel the deliver script prints when it refuses on a LIFT COLLISION (crew#418) — a
|
|
65
|
+
* rebase conflict it could not union-resolve, or a non-fast-forward push. The run's WORK is
|
|
66
|
+
* complete and committed on its `wicked/<id>` branch; only the lift into origin collided.
|
|
67
|
+
*
|
|
68
|
+
* crew keys the "stranded, recoverable" reinterpretation on this EXACT substring appearing in
|
|
69
|
+
* the deliver unit's `denial_reason` (which carries the head+TAIL excerpt of the script's
|
|
70
|
+
* output, and the marker is always the script's last line — see {@link isDeliverConflictStranded}
|
|
71
|
+
* in `api/delivery-index.ts`). The script's OTHER loud refusals — wrong worktree branch, nothing
|
|
72
|
+
* to deliver, `gh` failure — and a spawn/infra failure deliberately OMIT the marker, so they stay
|
|
73
|
+
* terminal run failures exactly as before (the crew#400 refusal-vs-infra posture).
|
|
74
|
+
*/
|
|
75
|
+
export const DELIVER_LIFT_CONFLICT_MARKER = 'deliver: LIFT-CONFLICT';
|
|
59
76
|
/** How much of the run's intent rides in the commit subject before it is truncated. */
|
|
60
77
|
const INTENT_SUBJECT_CAP = 72;
|
|
61
78
|
/**
|
|
@@ -134,16 +151,72 @@ export function deliverPrScript(intent) {
|
|
|
134
151
|
// remote is touched: an empty ref pushed under a run id is worse than a failed phase.
|
|
135
152
|
'A=$(git rev-list --count "$D..$B")',
|
|
136
153
|
'[ "$A" -ge 1 ] || { echo "deliver: nothing to deliver — the run produced no committed change ($B is not ahead of $D); nothing was pushed"; exit 1; }',
|
|
137
|
-
// (c3) Rebase onto origin's default branch so the PR opens mergeable.
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
|
|
154
|
+
// (c3) Rebase onto origin's default branch so the PR opens mergeable.
|
|
155
|
+
//
|
|
156
|
+
// crew#418 B — the CHANGELOG collision magnet: two runs that both append to CHANGELOG's
|
|
157
|
+
// `[Unreleased]` section conflict on the rebase BY CONSTRUCTION, though their added bullet
|
|
158
|
+
// lines never truly disagree. A conflict whose conflicted paths are ALL `CHANGELOG.md`
|
|
159
|
+
// (matched by basename) is resolved automatically with a UNION merge — `git merge-file
|
|
160
|
+
// --union` keeps BOTH sides' lines, no markers — and the rebase continues. This is scoped to
|
|
161
|
+
// the changelog and touches NOTHING else: a conflict in any other file is left exactly as
|
|
162
|
+
// loud as before (the "never weaken rebase loudness for non-changelog files" rule).
|
|
163
|
+
//
|
|
164
|
+
// crew#418 A — a conflict that is NOT changelog-only (or a changelog union that fails) is a
|
|
165
|
+
// real LIFT collision: abort the rebase (nothing pushed; the abort leaves the worktree on the
|
|
166
|
+
// pre-rebase branch tip, not mid-rebase) and exit carrying DELIVER_LIFT_CONFLICT_MARKER. The
|
|
167
|
+
// run's committed work is safe on its branch, so crew reinterprets THIS refusal as `completed`
|
|
168
|
+
// + `delivery: 'stranded'` (recoverable via POST /runs/:id/deliver) rather than a run failure.
|
|
169
|
+
'_rebasing() { [ -d "$(git rev-parse --git-path rebase-merge 2>/dev/null)" ] || [ -d "$(git rev-parse --git-path rebase-apply 2>/dev/null)" ]; }',
|
|
170
|
+
'if ! git rebase "$D" "$B"; then',
|
|
171
|
+
// A rebase that failed WITHOUT leaving in-progress state never started — a preflight error
|
|
172
|
+
// (bad ref, unexpected worktree state), not a conflict. Fail LOUD rather than fall through to
|
|
173
|
+
// the push as if the rebase had succeeded; nothing was pushed.
|
|
174
|
+
' if ! _rebasing; then echo "deliver: git rebase of $B onto $D failed before it started (preflight error); nothing was pushed"; exit 1; fi',
|
|
175
|
+
' while _rebasing; do',
|
|
176
|
+
' CF=$(git diff --name-only --diff-filter=U || true)',
|
|
177
|
+
' [ -n "$CF" ] || break',
|
|
178
|
+
// Any conflicted path that is not a CHANGELOG.md → a real collision; stop resolving and strand.
|
|
179
|
+
' if printf "%s\\n" "$CF" | grep -qvE "(^|/)CHANGELOG\\.md$"; then break; fi',
|
|
180
|
+
// Union-merge every conflicted changelog — but ONLY when the two sides differ SOLELY within
|
|
181
|
+
// the `## [Unreleased]` section. A union keeps both sides of every conflict hunk, so a
|
|
182
|
+
// whole-file union of two edits to the SAME released-version line would silently combine
|
|
183
|
+
// them; we refuse that. Guard: strip the [Unreleased] block (from `## [Unreleased]` up to the
|
|
184
|
+
// next `## [` heading) from both stage-2 (ours) and stage-3 (theirs); if the remainder is not
|
|
185
|
+
// byte-identical, the divergence is outside [Unreleased] → a real conflict → break (strand).
|
|
186
|
+
// When they ARE identical outside it, the only conflicting hunks are within [Unreleased], so
|
|
187
|
+
// the whole-file --union affects nothing else. A missing base stage (add/add) unions against
|
|
188
|
+
// an empty base; any git failure breaks out to the loud abort below.
|
|
189
|
+
' if ! printf "%s\\n" "$CF" | while IFS= read -r F; do',
|
|
190
|
+
' [ -n "$F" ] || continue;',
|
|
191
|
+
' TB=$(mktemp); TO=$(mktemp); TT=$(mktemp);',
|
|
192
|
+
' git show ":1:$F" >"$TB" 2>/dev/null || : >"$TB";',
|
|
193
|
+
' git show ":2:$F" >"$TO" 2>/dev/null || { rm -f "$TB" "$TO" "$TT"; exit 1; };',
|
|
194
|
+
' git show ":3:$F" >"$TT" 2>/dev/null || { rm -f "$TB" "$TO" "$TT"; exit 1; };',
|
|
195
|
+
" _strip='/^## \\[Unreleased\\]/{s=1;next} s&&/^## \\[/{s=0} !s{print}';",
|
|
196
|
+
' SO=$(awk "$_strip" "$TO"); ST=$(awk "$_strip" "$TT");',
|
|
197
|
+
' if [ "$SO" != "$ST" ]; then rm -f "$TB" "$TO" "$TT"; exit 1; fi;',
|
|
198
|
+
' git merge-file -q --union "$TO" "$TB" "$TT" || { rm -f "$TB" "$TO" "$TT"; exit 1; };',
|
|
199
|
+
' cat "$TO" >"$F"; git add -- "$F"; rm -f "$TB" "$TO" "$TT";',
|
|
200
|
+
' done; then break; fi',
|
|
201
|
+
' GIT_EDITOR=true git -c core.editor=true rebase --continue >/dev/null 2>&1 || break;',
|
|
202
|
+
' done',
|
|
203
|
+
` if _rebasing; then git rebase --abort >/dev/null 2>&1 || true; echo "${DELIVER_LIFT_CONFLICT_MARKER} — rebase of $B onto $D hit conflicts outside the changelog; resolve on the branch and re-run; nothing was pushed"; exit 1; fi`,
|
|
204
|
+
'fi',
|
|
141
205
|
// Re-derive after the rebase: it drops commits already upstream (patch-id equal), so a branch
|
|
142
206
|
// that WAS ahead can come out of a rebase carrying nothing of its own.
|
|
143
207
|
'A=$(git rev-list --count "$D..$B")',
|
|
144
208
|
'[ "$A" -ge 1 ] || { echo "deliver: nothing to deliver — the run produced no committed change (after rebasing onto $D, $B carries no commit of its own); nothing was pushed"; exit 1; }',
|
|
145
|
-
// (d) Push.
|
|
146
|
-
|
|
209
|
+
// (d) Push. A non-fast-forward rejection (the remote run branch moved under us) is the
|
|
210
|
+
// push-side twin of the rebase collision — mark it LIFT-CONFLICT so crew strands the run
|
|
211
|
+
// recoverably; ANY other push failure (auth, network, a rejecting remote hook) stays a loud
|
|
212
|
+
// terminal failure with git's own words.
|
|
213
|
+
'if PUSHOUT=$(git push -u origin "$B" 2>&1); then echo "$PUSHOUT"; else',
|
|
214
|
+
' echo "$PUSHOUT"',
|
|
215
|
+
' case "$PUSHOUT" in',
|
|
216
|
+
` *non-fast-forward*|*"fetch first"*|*"[rejected]"*|*"Updates were rejected"*) echo "${DELIVER_LIFT_CONFLICT_MARKER} — push of $B was rejected because the remote branch moved (non-fast-forward); rebase and re-run; nothing was pushed"; exit 1;;`,
|
|
217
|
+
' *) echo "deliver: git push of $B failed — nothing was pushed"; exit 1;;',
|
|
218
|
+
' esac',
|
|
219
|
+
'fi',
|
|
147
220
|
// (e) Open the PR with gh's OUTPUT and EXIT STATUS captured separately (crew#317). The old
|
|
148
221
|
// `| tail -1` threw away everything gh said but one line and made the phase's verdict a
|
|
149
222
|
// property of a shell option; a gh failure now fails the phase carrying gh's own message.
|
package/dist/core/deliver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../src/core/deliver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../src/core/deliver.ts"],"names":[],"mappings":"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"}
|