issue-flow 0.12.0 → 0.14.0
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 +79 -274
- package/dist/agent-OX3KPHE4.js +30 -0
- package/dist/{analyze-OEET7KGE.js → analyze-WIND2SEB.js} +31 -16
- package/dist/analyze-WIND2SEB.js.map +1 -0
- package/dist/{apply-ZIA3C52S.js → apply-JNOI2LR4.js} +18 -7
- package/dist/{apply-ZIA3C52S.js.map → apply-JNOI2LR4.js.map} +1 -1
- package/dist/bench-B4VZON7E.js +910 -0
- package/dist/bench-B4VZON7E.js.map +1 -0
- package/dist/{chunk-FADTCQGM.js → chunk-2IQ6M4ZE.js} +94 -32
- package/dist/chunk-2IQ6M4ZE.js.map +1 -0
- package/dist/chunk-3BWZO4YI.js +141 -0
- package/dist/chunk-3BWZO4YI.js.map +1 -0
- package/dist/chunk-3WFZETIM.js +163 -0
- package/dist/chunk-3WFZETIM.js.map +1 -0
- package/dist/chunk-67YIU2VB.js +362 -0
- package/dist/chunk-67YIU2VB.js.map +1 -0
- package/dist/{chunk-QCPGHBSZ.js → chunk-6BENHR2I.js} +63 -21
- package/dist/chunk-6BENHR2I.js.map +1 -0
- package/dist/{chunk-BYZDPR7N.js → chunk-6QYMSNVA.js} +194 -235
- package/dist/chunk-6QYMSNVA.js.map +1 -0
- package/dist/{chunk-Y5ZDJ4PJ.js → chunk-76MMPJ53.js} +20 -10
- package/dist/chunk-76MMPJ53.js.map +1 -0
- package/dist/chunk-7Z4Y3VKM.js +26 -0
- package/dist/chunk-7Z4Y3VKM.js.map +1 -0
- package/dist/{chunk-3QHK4YQA.js → chunk-B72RQZBV.js} +346 -119
- package/dist/chunk-B72RQZBV.js.map +1 -0
- package/dist/chunk-BEZ5BA5U.js +625 -0
- package/dist/chunk-BEZ5BA5U.js.map +1 -0
- package/dist/chunk-BRCNQXYQ.js +74 -0
- package/dist/chunk-BRCNQXYQ.js.map +1 -0
- package/dist/chunk-CGKLE6WR.js +1203 -0
- package/dist/chunk-CGKLE6WR.js.map +1 -0
- package/dist/chunk-CRGIQFUQ.js +83 -0
- package/dist/chunk-CRGIQFUQ.js.map +1 -0
- package/dist/{chunk-NS6R37II.js → chunk-F6TOYSYY.js} +141 -12
- package/dist/chunk-F6TOYSYY.js.map +1 -0
- package/dist/chunk-G5EK2XRN.js +25 -0
- package/dist/chunk-G5EK2XRN.js.map +1 -0
- package/dist/chunk-HAKDLR6N.js +134 -0
- package/dist/chunk-HAKDLR6N.js.map +1 -0
- package/dist/chunk-J3SOTUVI.js +298 -0
- package/dist/chunk-J3SOTUVI.js.map +1 -0
- package/dist/chunk-JN6D3MY6.js +30 -0
- package/dist/chunk-JN6D3MY6.js.map +1 -0
- package/dist/{chunk-LAFNLLQP.js → chunk-KMRFRXIT.js} +5 -5
- package/dist/chunk-KT7JKOXB.js +72 -0
- package/dist/chunk-KT7JKOXB.js.map +1 -0
- package/dist/chunk-L6HSKTQE.js +77 -0
- package/dist/chunk-L6HSKTQE.js.map +1 -0
- package/dist/chunk-LBGHI4S2.js +1264 -0
- package/dist/chunk-LBGHI4S2.js.map +1 -0
- package/dist/chunk-LEW4QM74.js +180 -0
- package/dist/chunk-LEW4QM74.js.map +1 -0
- package/dist/{chunk-FJP3UQGD.js → chunk-LFEQIZLB.js} +115 -20
- package/dist/chunk-LFEQIZLB.js.map +1 -0
- package/dist/chunk-OOVG2KBY.js +77 -0
- package/dist/chunk-OOVG2KBY.js.map +1 -0
- package/dist/{chunk-56KS3TFQ.js → chunk-OR43364P.js} +115 -160
- package/dist/chunk-OR43364P.js.map +1 -0
- package/dist/chunk-P3LRUNC6.js +16 -0
- package/dist/chunk-P3LRUNC6.js.map +1 -0
- package/dist/{chunk-TSOLWK7Y.js → chunk-PBTA3QQX.js} +8 -7
- package/dist/{chunk-TSOLWK7Y.js.map → chunk-PBTA3QQX.js.map} +1 -1
- package/dist/{chunk-MJULIKQU.js → chunk-PHW2YV6N.js} +23 -47
- package/dist/chunk-PHW2YV6N.js.map +1 -0
- package/dist/{chunk-73ATPIYX.js → chunk-PZTWU277.js} +36 -71
- package/dist/chunk-PZTWU277.js.map +1 -0
- package/dist/{chunk-M5UCXTIT.js → chunk-QD4VOILZ.js} +22 -18
- package/dist/chunk-QD4VOILZ.js.map +1 -0
- package/dist/chunk-QJ5UZAH5.js +2718 -0
- package/dist/chunk-QJ5UZAH5.js.map +1 -0
- package/dist/chunk-QK7WUO7A.js +283 -0
- package/dist/chunk-QK7WUO7A.js.map +1 -0
- package/dist/{chunk-A4SLHOW7.js → chunk-QZVKRDJY.js} +27 -19
- package/dist/chunk-QZVKRDJY.js.map +1 -0
- package/dist/chunk-REO3PXXO.js +71 -0
- package/dist/chunk-REO3PXXO.js.map +1 -0
- package/dist/{chunk-EZATO3DW.js → chunk-RVO7L4FX.js} +594 -17
- package/dist/chunk-RVO7L4FX.js.map +1 -0
- package/dist/{chunk-XQUSIEKA.js → chunk-SZMHCEYV.js} +63 -14
- package/dist/chunk-SZMHCEYV.js.map +1 -0
- package/dist/chunk-TYRNTSPJ.js +243 -0
- package/dist/chunk-TYRNTSPJ.js.map +1 -0
- package/dist/chunk-UJ3L2MS7.js +238 -0
- package/dist/chunk-UJ3L2MS7.js.map +1 -0
- package/dist/chunk-V7MO5EDS.js +120 -0
- package/dist/chunk-V7MO5EDS.js.map +1 -0
- package/dist/chunk-WB2X37MO.js +415 -0
- package/dist/chunk-WB2X37MO.js.map +1 -0
- package/dist/{chunk-NTMMF5UD.js → chunk-X44FKNKP.js} +525 -252
- package/dist/chunk-X44FKNKP.js.map +1 -0
- package/dist/chunk-XEYH6ZZI.js +289 -0
- package/dist/chunk-XEYH6ZZI.js.map +1 -0
- package/dist/cli.js +267 -44
- package/dist/cli.js.map +1 -1
- package/dist/{config-PRJGWW7J.js → config-HMFMCY2M.js} +31 -5
- package/dist/contract-JH2WBIO6.js +8 -0
- package/dist/conventions-NJF2OPVQ.js +146 -0
- package/dist/conventions-NJF2OPVQ.js.map +1 -0
- package/dist/diagnostics-THH42ZMP.js +23 -0
- package/dist/execute-KFNNZZHI.js +35 -0
- package/dist/{generate-EGB4KV2B.js → generate-FW5C6NP7.js} +37 -20
- package/dist/{generate-EGB4KV2B.js.map → generate-FW5C6NP7.js.map} +1 -1
- package/dist/git-W72QQ6GT.js +33 -0
- package/dist/init-HTN4V67Q.js +24 -0
- package/dist/{operations-BYT626KQ.js → operations-BCFOBH42.js} +27 -15
- package/dist/{operations-BYT626KQ.js.map → operations-BCFOBH42.js.map} +1 -1
- package/dist/permissions-4AKNQZHK.js +18 -0
- package/dist/plan-SIZLGA4V.js +34 -0
- package/dist/{policy-6S4GFC76.js → policy-DT6Q6ZVM.js} +20 -6
- package/dist/policy-DT6Q6ZVM.js.map +1 -0
- package/dist/pr-OMWCGUOW.js +39 -0
- package/dist/pr-review-N24CZPKR.js +32 -0
- package/dist/pr-review-N24CZPKR.js.map +1 -0
- package/dist/prd-5OFTZAHJ.js +33 -0
- package/dist/prd-5OFTZAHJ.js.map +1 -0
- package/dist/ps-RFORTCUD.js +93 -0
- package/dist/ps-RFORTCUD.js.map +1 -0
- package/dist/recorder-KCCPMKQG.js +32 -0
- package/dist/recorder-KCCPMKQG.js.map +1 -0
- package/dist/registry-GLPXOMFG.js +15 -0
- package/dist/registry-GLPXOMFG.js.map +1 -0
- package/dist/{resume-PPCNQVVV.js → resume-M5RLKP4I.js} +55 -34
- package/dist/{resume-PPCNQVVV.js.map → resume-M5RLKP4I.js.map} +1 -1
- package/dist/review-YM4JAABY.js +35 -0
- package/dist/review-YM4JAABY.js.map +1 -0
- package/dist/routing-NNT5WKGX.js +94 -0
- package/dist/routing-NNT5WKGX.js.map +1 -0
- package/dist/run-PZUKHPQK.js +54 -0
- package/dist/run-PZUKHPQK.js.map +1 -0
- package/dist/session-publisher-T7EI3CIP.js +11 -0
- package/dist/session-publisher-T7EI3CIP.js.map +1 -0
- package/dist/{state-manager-2EDVDBAR.js → state-manager-GQH32C44.js} +4 -2
- package/dist/state-manager-GQH32C44.js.map +1 -0
- package/dist/usage-V2CHE5PY.js +177 -0
- package/dist/usage-V2CHE5PY.js.map +1 -0
- package/dist/{web-EF5WIIGG.js → web-EA3KGNFN.js} +45 -30
- package/dist/web-EA3KGNFN.js.map +1 -0
- package/package.json +6 -2
- package/prompts/execute.md +7 -8
- package/prompts/plan.md +4 -5
- package/prompts/pr.md +2 -2
- package/web/AGENTS.md +152 -13
- package/web/public/app.css +380 -109
- package/web/public/app.js +525 -25
- package/web/public/index.html +68 -1
- package/dist/analyze-OEET7KGE.js.map +0 -1
- package/dist/chunk-3QHK4YQA.js.map +0 -1
- package/dist/chunk-42PJFMAR.js +0 -605
- package/dist/chunk-42PJFMAR.js.map +0 -1
- package/dist/chunk-4JSOYE4G.js +0 -368
- package/dist/chunk-4JSOYE4G.js.map +0 -1
- package/dist/chunk-56KS3TFQ.js.map +0 -1
- package/dist/chunk-73ATPIYX.js.map +0 -1
- package/dist/chunk-A4SLHOW7.js.map +0 -1
- package/dist/chunk-BAUPQXPE.js +0 -173
- package/dist/chunk-BAUPQXPE.js.map +0 -1
- package/dist/chunk-BYZDPR7N.js.map +0 -1
- package/dist/chunk-CD5ULRVC.js +0 -615
- package/dist/chunk-CD5ULRVC.js.map +0 -1
- package/dist/chunk-DIDUVL6O.js +0 -1365
- package/dist/chunk-DIDUVL6O.js.map +0 -1
- package/dist/chunk-EZATO3DW.js.map +0 -1
- package/dist/chunk-FADTCQGM.js.map +0 -1
- package/dist/chunk-FJP3UQGD.js.map +0 -1
- package/dist/chunk-LWRSMTTZ.js +0 -18
- package/dist/chunk-LWRSMTTZ.js.map +0 -1
- package/dist/chunk-M5UCXTIT.js.map +0 -1
- package/dist/chunk-M66SJHQQ.js +0 -206
- package/dist/chunk-M66SJHQQ.js.map +0 -1
- package/dist/chunk-MJULIKQU.js.map +0 -1
- package/dist/chunk-NS6R37II.js.map +0 -1
- package/dist/chunk-NTMMF5UD.js.map +0 -1
- package/dist/chunk-QCPGHBSZ.js.map +0 -1
- package/dist/chunk-XQUSIEKA.js.map +0 -1
- package/dist/chunk-Y5ZDJ4PJ.js.map +0 -1
- package/dist/execute-XBNVL753.js +0 -18
- package/dist/init-AJHCXJBP.js +0 -10
- package/dist/plan-QOZ3RIO6.js +0 -21
- package/dist/policy-6S4GFC76.js.map +0 -1
- package/dist/pr-EBBHD2ZX.js +0 -26
- package/dist/pr-review-VVMW5PO4.js +0 -20
- package/dist/prd-JQSZF7PR.js +0 -21
- package/dist/review-3F6MARWH.js +0 -19
- package/dist/run-RXE5GDQO.js +0 -36
- package/dist/web-EF5WIIGG.js.map +0 -1
- /package/dist/{config-PRJGWW7J.js.map → agent-OX3KPHE4.js.map} +0 -0
- /package/dist/{chunk-LAFNLLQP.js.map → chunk-KMRFRXIT.js.map} +0 -0
- /package/dist/{execute-XBNVL753.js.map → config-HMFMCY2M.js.map} +0 -0
- /package/dist/{init-AJHCXJBP.js.map → contract-JH2WBIO6.js.map} +0 -0
- /package/dist/{plan-QOZ3RIO6.js.map → diagnostics-THH42ZMP.js.map} +0 -0
- /package/dist/{pr-EBBHD2ZX.js.map → execute-KFNNZZHI.js.map} +0 -0
- /package/dist/{pr-review-VVMW5PO4.js.map → git-W72QQ6GT.js.map} +0 -0
- /package/dist/{prd-JQSZF7PR.js.map → init-HTN4V67Q.js.map} +0 -0
- /package/dist/{review-3F6MARWH.js.map → permissions-4AKNQZHK.js.map} +0 -0
- /package/dist/{run-RXE5GDQO.js.map → plan-SIZLGA4V.js.map} +0 -0
- /package/dist/{state-manager-2EDVDBAR.js.map → pr-OMWCGUOW.js.map} +0 -0
|
@@ -3,148 +3,17 @@ import {
|
|
|
3
3
|
emptyRelations,
|
|
4
4
|
uniqueIds
|
|
5
5
|
} from "./chunk-KMMASOA6.js";
|
|
6
|
-
import {
|
|
7
|
-
executionPlanSchema
|
|
8
|
-
} from "./chunk-DIDUVL6O.js";
|
|
9
|
-
import {
|
|
10
|
-
MemoryPublisher
|
|
11
|
-
} from "./chunk-BYZDPR7N.js";
|
|
12
6
|
import {
|
|
13
7
|
isoNow,
|
|
14
8
|
loadTaskPlan,
|
|
15
|
-
saveTaskPlan
|
|
9
|
+
saveTaskPlan
|
|
10
|
+
} from "./chunk-J3SOTUVI.js";
|
|
11
|
+
import {
|
|
12
|
+
executionPlanSchema
|
|
13
|
+
} from "./chunk-LBGHI4S2.js";
|
|
14
|
+
import {
|
|
16
15
|
writeFileAtomic
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
|
|
19
|
-
// src/core/journal.ts
|
|
20
|
-
import { appendFile, mkdir, rename, stat, unlink } from "fs/promises";
|
|
21
|
-
import { dirname } from "path";
|
|
22
|
-
var DEFAULT_JOURNAL_MAX_BYTES = 10 * 1024 * 1024;
|
|
23
|
-
var JournalPublisher = class extends MemoryPublisher {
|
|
24
|
-
filePath;
|
|
25
|
-
rotatedPath;
|
|
26
|
-
maxFileBytes;
|
|
27
|
-
seq = 0;
|
|
28
|
-
writeChain = Promise.resolve();
|
|
29
|
-
closed = false;
|
|
30
|
-
/** Bytes in the current file. `null` until the first write measures it. */
|
|
31
|
-
bytes = null;
|
|
32
|
-
constructor(filePath, rotatedPath, options = {}) {
|
|
33
|
-
super(options);
|
|
34
|
-
this.filePath = filePath;
|
|
35
|
-
this.rotatedPath = rotatedPath;
|
|
36
|
-
this.maxFileBytes = options.maxFileBytes ?? DEFAULT_JOURNAL_MAX_BYTES;
|
|
37
|
-
}
|
|
38
|
-
afterPublish(event) {
|
|
39
|
-
if (this.closed) return;
|
|
40
|
-
this.seq++;
|
|
41
|
-
const line = `${JSON.stringify({ seq: this.seq, event })}
|
|
42
|
-
`;
|
|
43
|
-
this.enqueue(line);
|
|
44
|
-
}
|
|
45
|
-
enqueue(line) {
|
|
46
|
-
this.writeChain = this.writeChain.then(async () => {
|
|
47
|
-
try {
|
|
48
|
-
await this.appendLine(line);
|
|
49
|
-
} catch (err) {
|
|
50
|
-
this.warnOnce(err);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
async appendLine(line) {
|
|
55
|
-
const size = Buffer.byteLength(line);
|
|
56
|
-
if (this.bytes === null) {
|
|
57
|
-
await mkdir(dirname(this.filePath), { recursive: true });
|
|
58
|
-
this.bytes = await currentSize(this.filePath);
|
|
59
|
-
}
|
|
60
|
-
if (this.maxFileBytes > 0 && this.bytes > 0 && this.bytes + size > this.maxFileBytes) {
|
|
61
|
-
await this.rotate();
|
|
62
|
-
}
|
|
63
|
-
await appendFile(this.filePath, line, "utf-8");
|
|
64
|
-
this.bytes += size;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Keep exactly one previous generation.
|
|
68
|
-
*
|
|
69
|
-
* Deliberately not a numbered cascade: two files bound the disk cost at
|
|
70
|
-
* `2 * maxFileBytes`, and a run long enough to fill 10 MB twice has already
|
|
71
|
-
* put everything a human would look for in the current file. A caller that
|
|
72
|
-
* needs full retention sets `maxFileBytes: 0` and rotates on its own terms.
|
|
73
|
-
*/
|
|
74
|
-
async rotate() {
|
|
75
|
-
try {
|
|
76
|
-
await unlink(this.rotatedPath);
|
|
77
|
-
} catch {
|
|
78
|
-
}
|
|
79
|
-
await rename(this.filePath, this.rotatedPath);
|
|
80
|
-
this.bytes = 0;
|
|
81
|
-
}
|
|
82
|
-
async flush() {
|
|
83
|
-
await this.writeChain;
|
|
84
|
-
}
|
|
85
|
-
async close() {
|
|
86
|
-
await this.flush();
|
|
87
|
-
this.closed = true;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
async function currentSize(path) {
|
|
91
|
-
try {
|
|
92
|
-
return (await stat(path)).size;
|
|
93
|
-
} catch {
|
|
94
|
-
return 0;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function parseJournal(content) {
|
|
98
|
-
const entries = [];
|
|
99
|
-
for (const line of content.split("\n")) {
|
|
100
|
-
const trimmed = line.trim();
|
|
101
|
-
if (trimmed === "") continue;
|
|
102
|
-
let parsed;
|
|
103
|
-
try {
|
|
104
|
-
parsed = JSON.parse(trimmed);
|
|
105
|
-
} catch {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
if (!isEntry(parsed)) continue;
|
|
109
|
-
entries.push(parsed);
|
|
110
|
-
}
|
|
111
|
-
return entries;
|
|
112
|
-
}
|
|
113
|
-
function isEntry(value) {
|
|
114
|
-
if (typeof value !== "object" || value === null) return false;
|
|
115
|
-
const candidate = value;
|
|
116
|
-
if (typeof candidate.seq !== "number") return false;
|
|
117
|
-
const event = candidate.event;
|
|
118
|
-
return typeof event === "object" && event !== null && typeof event.type === "string";
|
|
119
|
-
}
|
|
120
|
-
var MultiPublisher = class {
|
|
121
|
-
members;
|
|
122
|
-
primary;
|
|
123
|
-
constructor(members) {
|
|
124
|
-
if (members.length === 0) {
|
|
125
|
-
throw new Error("MultiPublisher needs at least one member");
|
|
126
|
-
}
|
|
127
|
-
this.members = members;
|
|
128
|
-
this.primary = members[0];
|
|
129
|
-
}
|
|
130
|
-
publish(event) {
|
|
131
|
-
for (const member of this.members) {
|
|
132
|
-
member.publish(event);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
snapshot() {
|
|
136
|
-
return this.primary.snapshot();
|
|
137
|
-
}
|
|
138
|
-
version() {
|
|
139
|
-
return this.primary.version();
|
|
140
|
-
}
|
|
141
|
-
async flush() {
|
|
142
|
-
await Promise.all(this.members.map((member) => member.flush()));
|
|
143
|
-
}
|
|
144
|
-
async close() {
|
|
145
|
-
await Promise.all(this.members.map((member) => member.close()));
|
|
146
|
-
}
|
|
147
|
-
};
|
|
16
|
+
} from "./chunk-7Z4Y3VKM.js";
|
|
148
17
|
|
|
149
18
|
// src/core/pipeline.ts
|
|
150
19
|
var PIPELINE_PHASES = ["init", "prd", "plan", "execute", "review", "pr"];
|
|
@@ -240,10 +109,56 @@ var PipelineManager = class {
|
|
|
240
109
|
};
|
|
241
110
|
|
|
242
111
|
// src/execution/plan.ts
|
|
243
|
-
import { mkdir
|
|
244
|
-
import { dirname
|
|
112
|
+
import { mkdir, readFile } from "fs/promises";
|
|
113
|
+
import { dirname } from "path";
|
|
245
114
|
import { ZodError } from "zod";
|
|
246
115
|
|
|
116
|
+
// src/execution/containers.ts
|
|
117
|
+
var DEFAULT_CONTAINER_CONFIG = {
|
|
118
|
+
detect: ["children"],
|
|
119
|
+
issueTypes: ["Epic"],
|
|
120
|
+
labels: ["epic"],
|
|
121
|
+
titlePrefixes: ["[Epic]"]
|
|
122
|
+
};
|
|
123
|
+
function enabled(config, signal) {
|
|
124
|
+
return config.detect.includes(signal);
|
|
125
|
+
}
|
|
126
|
+
function hasTitlePrefix(title, prefixes) {
|
|
127
|
+
const trimmed = title.trim();
|
|
128
|
+
return prefixes.some((prefix) => trimmed.toLowerCase().startsWith(prefix.toLowerCase()));
|
|
129
|
+
}
|
|
130
|
+
function isContainer(probe, config = DEFAULT_CONTAINER_CONFIG) {
|
|
131
|
+
if (enabled(config, "children") && probe.children.length > 0) return true;
|
|
132
|
+
const issue = probe.issue;
|
|
133
|
+
if (issue === null) return false;
|
|
134
|
+
if (enabled(config, "issue-type")) {
|
|
135
|
+
const type = issue.type?.trim();
|
|
136
|
+
if (type !== void 0 && type !== "" && config.issueTypes.some((name) => name.toLowerCase() === type.toLowerCase())) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (enabled(config, "label")) {
|
|
141
|
+
const labels = new Set(issue.labels.map((label) => label.toLowerCase()));
|
|
142
|
+
if (config.labels.some((label) => labels.has(label.toLowerCase()))) return true;
|
|
143
|
+
}
|
|
144
|
+
if (enabled(config, "title-prefix") && hasTitlePrefix(issue.title, config.titlePrefixes)) {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
function collectCascadeIds(graph, roots) {
|
|
150
|
+
const ids = /* @__PURE__ */ new Set();
|
|
151
|
+
const walk = (id) => {
|
|
152
|
+
if (ids.has(id)) return;
|
|
153
|
+
ids.add(id);
|
|
154
|
+
for (const child of graph.nodes.get(id)?.relations.children ?? []) {
|
|
155
|
+
walk(child);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
for (const root of roots) walk(root);
|
|
159
|
+
return [...ids];
|
|
160
|
+
}
|
|
161
|
+
|
|
247
162
|
// src/issues/graph.ts
|
|
248
163
|
var DEFAULT_MAX_NODES = 25;
|
|
249
164
|
var DEFAULT_MAX_DEPTH = 3;
|
|
@@ -432,14 +347,14 @@ function priorityOf(labels) {
|
|
|
432
347
|
}
|
|
433
348
|
return null;
|
|
434
349
|
}
|
|
435
|
-
function hierarchyDepth(id,
|
|
350
|
+
function hierarchyDepth(id, parentOf2, selected) {
|
|
436
351
|
let depth = 0;
|
|
437
|
-
let current =
|
|
352
|
+
let current = parentOf2.get(id) ?? null;
|
|
438
353
|
const seen = /* @__PURE__ */ new Set([id]);
|
|
439
354
|
while (current !== null && selected.has(current) && !seen.has(current)) {
|
|
440
355
|
depth++;
|
|
441
356
|
seen.add(current);
|
|
442
|
-
current =
|
|
357
|
+
current = parentOf2.get(current) ?? null;
|
|
443
358
|
}
|
|
444
359
|
return depth;
|
|
445
360
|
}
|
|
@@ -447,11 +362,11 @@ function computeExecutionOrder(graph, options = {}) {
|
|
|
447
362
|
const selected = new Set(
|
|
448
363
|
(options.include ?? [...graph.nodes.keys()]).filter((id) => graph.nodes.has(id))
|
|
449
364
|
);
|
|
450
|
-
const
|
|
365
|
+
const parentOf2 = /* @__PURE__ */ new Map();
|
|
451
366
|
const priority = /* @__PURE__ */ new Map();
|
|
452
367
|
for (const id of selected) {
|
|
453
368
|
const node = graph.nodes.get(id);
|
|
454
|
-
|
|
369
|
+
parentOf2.set(id, node?.relations.parent ?? null);
|
|
455
370
|
priority.set(id, priorityOf(node?.issue?.labels ?? []));
|
|
456
371
|
}
|
|
457
372
|
const incoming = /* @__PURE__ */ new Map();
|
|
@@ -467,7 +382,7 @@ function computeExecutionOrder(graph, options = {}) {
|
|
|
467
382
|
}
|
|
468
383
|
const depth = /* @__PURE__ */ new Map();
|
|
469
384
|
for (const id of selected) {
|
|
470
|
-
depth.set(id, hierarchyDepth(id,
|
|
385
|
+
depth.set(id, hierarchyDepth(id, parentOf2, selected));
|
|
471
386
|
}
|
|
472
387
|
const rank = (id) => {
|
|
473
388
|
const value = priority.get(id) ?? null;
|
|
@@ -507,6 +422,12 @@ function describeCycles(cycles) {
|
|
|
507
422
|
}
|
|
508
423
|
|
|
509
424
|
// src/execution/plan.ts
|
|
425
|
+
function parentOf(graph, id) {
|
|
426
|
+
for (const node of graph.nodes.values()) {
|
|
427
|
+
if (node.relations.children.includes(id)) return node.id;
|
|
428
|
+
}
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
510
431
|
function describeIssue(issue, id) {
|
|
511
432
|
const parsed = Number.parseInt(id, 10);
|
|
512
433
|
return {
|
|
@@ -525,6 +446,11 @@ function buildExecutionPlan(input) {
|
|
|
525
446
|
const node = input.graph.nodes.get(id);
|
|
526
447
|
const relations = node?.relations;
|
|
527
448
|
const described = describeIssue(node?.issue ?? null, id);
|
|
449
|
+
const children = relations?.children ?? [];
|
|
450
|
+
const role = isContainer({
|
|
451
|
+
issue: node?.issue ?? null,
|
|
452
|
+
children
|
|
453
|
+
}) ? "container" : "executable";
|
|
528
454
|
return {
|
|
529
455
|
id,
|
|
530
456
|
number: described.number,
|
|
@@ -534,10 +460,14 @@ function buildExecutionPlan(input) {
|
|
|
534
460
|
position: index + 1,
|
|
535
461
|
status: "pending",
|
|
536
462
|
origin: requested.has(id) ? "requested" : "discovered",
|
|
463
|
+
role,
|
|
464
|
+
externalDependencies: (relations?.blockedBy ?? []).filter(
|
|
465
|
+
(blocker) => !scheduled.has(blocker)
|
|
466
|
+
),
|
|
537
467
|
// Only the constraints that survive inside the queue: a blocker left out
|
|
538
468
|
// of it is reported in `excluded`, not enforced as a dependency.
|
|
539
469
|
dependsOn: (relations?.blockedBy ?? []).filter((blocker) => scheduled.has(blocker)),
|
|
540
|
-
parent: relations?.parent ??
|
|
470
|
+
parent: relations?.parent ?? parentOf(input.graph, id),
|
|
541
471
|
priority: priorityOf(node?.issue?.labels ?? []),
|
|
542
472
|
heuristic: (relations?.heuristic.length ?? 0) > 0,
|
|
543
473
|
failedPhase: null,
|
|
@@ -590,7 +520,7 @@ ${issues}`);
|
|
|
590
520
|
}
|
|
591
521
|
}
|
|
592
522
|
async function saveExecutionPlan(path, plan, now = isoNow) {
|
|
593
|
-
await
|
|
523
|
+
await mkdir(dirname(path), { recursive: true });
|
|
594
524
|
const stamped = { ...plan, updatedAt: now() };
|
|
595
525
|
await writeFileAtomic(path, `${JSON.stringify(stamped, null, 2)}
|
|
596
526
|
`);
|
|
@@ -598,12 +528,14 @@ async function saveExecutionPlan(path, plan, now = isoNow) {
|
|
|
598
528
|
function dependenciesSatisfied(plan, entry) {
|
|
599
529
|
return entry.dependsOn.every((id) => {
|
|
600
530
|
const dependency = plan.issues.find((candidate) => candidate.id === id);
|
|
601
|
-
|
|
531
|
+
if (dependency === void 0) return true;
|
|
532
|
+
if (dependency.role === "container") return true;
|
|
533
|
+
return dependency.status === "completed";
|
|
602
534
|
});
|
|
603
535
|
}
|
|
604
536
|
function nextQueueIssue(plan, options = {}) {
|
|
605
537
|
const exclude = options.exclude ?? /* @__PURE__ */ new Set();
|
|
606
|
-
const eligible = (status) => (entry) => entry.status === status && !exclude.has(entry.id) && dependenciesSatisfied(plan, entry);
|
|
538
|
+
const eligible = (status) => (entry) => entry.role !== "container" && entry.status === status && !exclude.has(entry.id) && dependenciesSatisfied(plan, entry);
|
|
607
539
|
return plan.issues.find(eligible("in_progress")) ?? plan.issues.find(eligible("failed")) ?? plan.issues.find(eligible("pending")) ?? plan.issues.find(eligible("skipped")) ?? null;
|
|
608
540
|
}
|
|
609
541
|
function queueStatus(plan) {
|
|
@@ -633,13 +565,38 @@ function markQueueIssueInProgress(plan, id, now = isoNow) {
|
|
|
633
565
|
lastError: null
|
|
634
566
|
});
|
|
635
567
|
}
|
|
568
|
+
function completeResolvedContainers(plan, now) {
|
|
569
|
+
let next = plan;
|
|
570
|
+
let changed = true;
|
|
571
|
+
while (changed) {
|
|
572
|
+
changed = false;
|
|
573
|
+
for (const entry of next.issues) {
|
|
574
|
+
if (entry.role !== "container" || entry.status === "completed") continue;
|
|
575
|
+
const children = next.issues.filter((candidate) => candidate.parent === entry.id);
|
|
576
|
+
if (children.length === 0) continue;
|
|
577
|
+
if (children.every((child) => child.status === "completed")) {
|
|
578
|
+
next = updateIssue(next, entry.id, {
|
|
579
|
+
status: "completed",
|
|
580
|
+
completedAt: now(),
|
|
581
|
+
failedPhase: null,
|
|
582
|
+
lastError: null
|
|
583
|
+
});
|
|
584
|
+
changed = true;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return next;
|
|
589
|
+
}
|
|
636
590
|
function markQueueIssueCompleted(plan, id, now = isoNow) {
|
|
637
|
-
return
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
591
|
+
return completeResolvedContainers(
|
|
592
|
+
updateIssue(plan, id, {
|
|
593
|
+
status: "completed",
|
|
594
|
+
completedAt: now(),
|
|
595
|
+
failedPhase: null,
|
|
596
|
+
lastError: null
|
|
597
|
+
}),
|
|
598
|
+
now
|
|
599
|
+
);
|
|
643
600
|
}
|
|
644
601
|
function markQueueIssueFailed(plan, id, failure) {
|
|
645
602
|
const current = plan.issues.find((entry) => entry.id === id);
|
|
@@ -677,13 +634,11 @@ function setQueuePullRequest(plan, pullRequest) {
|
|
|
677
634
|
}
|
|
678
635
|
|
|
679
636
|
export {
|
|
680
|
-
JournalPublisher,
|
|
681
|
-
parseJournal,
|
|
682
|
-
MultiPublisher,
|
|
683
637
|
PIPELINE_PHASES,
|
|
684
638
|
PIPELINE_PHASES_WITH_PR_REVIEW,
|
|
685
639
|
PIPELINE_PHASES_NO_BRANCH,
|
|
686
640
|
PipelineManager,
|
|
641
|
+
collectCascadeIds,
|
|
687
642
|
buildDependencyGraph,
|
|
688
643
|
computeExecutionOrder,
|
|
689
644
|
describeCycles,
|
|
@@ -700,4 +655,4 @@ export {
|
|
|
700
655
|
setQueueBranch,
|
|
701
656
|
setQueuePullRequest
|
|
702
657
|
};
|
|
703
|
-
//# sourceMappingURL=chunk-
|
|
658
|
+
//# sourceMappingURL=chunk-OR43364P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/pipeline.ts","../src/execution/plan.ts","../src/execution/containers.ts","../src/issues/graph.ts","../src/execution/order.ts"],"sourcesContent":["import type { PipelineState, TaskPlan } from '../types.js';\nimport { loadTaskPlan, saveTaskPlan } from './state-manager.js';\n\n/**\n * Ordered pipeline phases. Each phase must complete before the next can start.\n *\n * `pr-review` is deliberately NOT here: it is opt-in via `--pr-review`. Adding\n * it to the default set would make every existing `tasks.json` (which has no\n * `prReviewCompleted`) look unfinished, so `getNextPhase()` would resume into a\n * phase the user never asked for.\n */\nexport const PIPELINE_PHASES = ['init', 'prd', 'plan', 'execute', 'review', 'pr'] as const;\n\n/**\n * The default set plus the opt-in `pr-review` phase, used when the user passes\n * `--pr-review` (or the flag was persisted in `plan.prReview.enabled`).\n */\nexport const PIPELINE_PHASES_WITH_PR_REVIEW = [...PIPELINE_PHASES, 'pr-review'] as const;\n\nexport type PipelinePhase = (typeof PIPELINE_PHASES_WITH_PR_REVIEW)[number];\n\n/**\n * Pipeline phases excluding the 'pr' phase, for --no-branch mode.\n * `pr-review` is excluded too: without a branch there is no PR to review.\n */\nexport const PIPELINE_PHASES_NO_BRANCH = PIPELINE_PHASES.filter(\n (p): p is Exclude<PipelinePhase, 'pr' | 'pr-review'> => p !== 'pr',\n);\n\n/**\n * Map pipeline phases to their corresponding PipelineState field.\n * 'init' has no persisted state — it's a runtime-only check.\n */\nconst PHASE_TO_FIELD: Record<PipelinePhase, keyof PipelineState | null> = {\n init: null,\n prd: 'prdCompleted',\n plan: 'jsonCompleted',\n execute: 'executionCompleted',\n review: 'reviewCompleted',\n pr: 'prCreated',\n 'pr-review': 'prReviewCompleted',\n};\n\nexport class PipelineManager {\n private tasksJsonPath: string;\n private plan: TaskPlan;\n private activePhases: readonly PipelinePhase[];\n\n constructor(plan: TaskPlan, tasksJsonPath: string, activePhases?: readonly PipelinePhase[]) {\n this.plan = plan;\n this.tasksJsonPath = tasksJsonPath;\n this.activePhases = activePhases ?? PIPELINE_PHASES;\n }\n\n /**\n * Reload state from disk.\n */\n async reload(): Promise<void> {\n this.plan = await loadTaskPlan(this.tasksJsonPath);\n }\n\n /**\n * Check if a phase is complete.\n */\n isPhaseComplete(phase: PipelinePhase): boolean {\n const field = PHASE_TO_FIELD[phase];\n if (field === null) return true; // init is always \"complete\" after running\n return this.plan.pipeline?.[field] ?? false;\n }\n\n /**\n * Get the first incomplete phase in the pipeline.\n * Returns null if all phases are complete.\n */\n getNextPhase(): PipelinePhase | null {\n for (const phase of this.activePhases) {\n if (!this.isPhaseComplete(phase)) {\n return phase;\n }\n }\n return null;\n }\n\n /**\n * Get the current phase (alias for getNextPhase).\n */\n getCurrentPhase(): PipelinePhase | null {\n return this.getNextPhase();\n }\n\n /**\n * Check whether we can resume from a specific phase.\n * All prerequisite phases must be complete.\n */\n canResume(fromPhase: PipelinePhase): boolean {\n const idx = this.activePhases.indexOf(fromPhase);\n if (idx < 0) return false;\n\n // All active phases before fromPhase must be complete\n for (let i = 0; i < idx; i++) {\n if (!this.isPhaseComplete(this.activePhases[i])) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Mark a phase as complete and persist to disk.\n */\n async markPhaseComplete(phase: PipelinePhase): Promise<void> {\n const field = PHASE_TO_FIELD[phase];\n if (field === null) return; // init has no persisted state\n\n this.plan = {\n ...this.plan,\n pipeline: {\n ...(this.plan.pipeline ?? {\n prdCompleted: false,\n jsonCompleted: false,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n }),\n [field]: true,\n },\n };\n\n await saveTaskPlan(this.tasksJsonPath, this.plan);\n }\n}\n","import { mkdir, readFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { ZodError } from 'zod';\nimport { isoNow } from '../core/state-manager.js';\nimport type { DependencyGraph } from '../issues/graph.js';\nimport type { Issue } from '../issues/types.js';\nimport { executionPlanSchema } from '../storage/schemas.js';\nimport type { LastError, PullRequestRef } from '../types.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { isContainer } from './containers.js';\nimport { priorityOf } from './order.js';\nimport type {\n ExecutionPlan,\n ExecutionPlanExcluded,\n ExecutionPlanIssue,\n QueueIssueRole,\n QueueIssueStatus,\n QueueStatus,\n} from './types.js';\n\n/**\n * Building, reading, writing and advancing the execution plan of a queue.\n *\n * The plan is the only state a multi-issue run adds to the storage tree, and it\n * is written **only** for a queue with more than one Issue — a single-issue run\n * leaves the layout exactly as it was.\n */\n\nexport interface BuildExecutionPlanInput {\n /** Project id of the global storage tree. */\n projectId: string;\n /** Identifiers the user asked for, in order; the first one names the queue. */\n requested: readonly string[];\n graph: DependencyGraph;\n /** Ids to run, already ordered by `computeExecutionOrder`. */\n order: readonly string[];\n noBranch?: boolean;\n prReview?: boolean;\n /** Injectable clock, so tests can assert `createdAt` vs `updatedAt`. */\n now?: () => string;\n}\n\nfunction parentOf(graph: DependencyGraph, id: string): string | null {\n for (const node of graph.nodes.values()) {\n if (node.relations.children.includes(id)) return node.id;\n }\n return null;\n}\n\n/** Title/url/number of a node, falling back to what the id alone tells us. */\nfunction describeIssue(\n issue: Issue | null,\n id: string,\n): {\n number: number | null;\n title: string;\n url: string | null;\n source: string;\n} {\n const parsed = Number.parseInt(id, 10);\n return {\n number: issue?.number ?? (Number.isNaN(parsed) ? null : parsed),\n title: issue?.title ?? '',\n url: issue?.remoteRef ?? null,\n source: issue?.source ?? 'github',\n };\n}\n\n/**\n * Turn a graph plus an order into the persisted plan.\n *\n * Every Issue of the graph that is *not* in the order becomes an `excluded`\n * entry: the consolidated Pull Request reports them as known pending work, so a\n * hierarchy the user chose to trim never disappears silently.\n */\nexport function buildExecutionPlan(input: BuildExecutionPlanInput): ExecutionPlan {\n const now = input.now ?? isoNow;\n const at = now();\n const scheduled = new Set(input.order);\n const requested = new Set(input.requested);\n\n const issues: ExecutionPlanIssue[] = input.order.map((id, index) => {\n const node = input.graph.nodes.get(id);\n const relations = node?.relations;\n const described = describeIssue(node?.issue ?? null, id);\n const children = relations?.children ?? [];\n const role: QueueIssueRole = isContainer({\n issue: node?.issue ?? null,\n children,\n })\n ? 'container'\n : 'executable';\n\n return {\n id,\n number: described.number,\n title: described.title,\n url: described.url,\n source: described.source,\n position: index + 1,\n status: 'pending',\n origin: requested.has(id) ? 'requested' : 'discovered',\n role,\n externalDependencies: (relations?.blockedBy ?? []).filter(\n (blocker) => !scheduled.has(blocker),\n ),\n // Only the constraints that survive inside the queue: a blocker left out\n // of it is reported in `excluded`, not enforced as a dependency.\n dependsOn: (relations?.blockedBy ?? []).filter((blocker) => scheduled.has(blocker)),\n parent: relations?.parent ?? parentOf(input.graph, id),\n priority: priorityOf(node?.issue?.labels ?? []),\n heuristic: (relations?.heuristic.length ?? 0) > 0,\n failedPhase: null,\n lastError: null,\n attempts: 0,\n blockedReason: null,\n startedAt: null,\n completedAt: null,\n };\n });\n\n const excluded: ExecutionPlanExcluded[] = [];\n for (const node of input.graph.nodes.values()) {\n if (scheduled.has(node.id)) continue;\n const described = describeIssue(node.issue, node.id);\n excluded.push({\n id: node.id,\n number: described.number,\n title: described.title,\n url: described.url,\n reason: 'Discovered in the hierarchy but not selected for this run',\n });\n }\n\n return {\n schemaVersion: 1,\n id: input.requested[0] ?? (input.order[0] as string),\n project: input.projectId,\n requested: [...input.requested],\n branchName: null,\n noBranch: input.noBranch ?? false,\n prReview: input.prReview ?? false,\n status: 'pending',\n createdAt: at,\n updatedAt: at,\n truncated: input.graph.truncated,\n issues,\n excluded,\n };\n}\n\n/** Read a persisted plan. Throws with the offending fields on invalid content. */\nexport async function loadExecutionPlan(path: string): Promise<ExecutionPlan> {\n const raw: unknown = JSON.parse(await readFile(path, 'utf-8'));\n\n try {\n return executionPlanSchema.parse(raw) as ExecutionPlan;\n } catch (err) {\n if (err instanceof ZodError) {\n const issues = err.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`).join('\\n');\n throw new Error(`Invalid execution-plan.json at ${path}:\\n${issues}`);\n }\n throw err;\n }\n}\n\n/**\n * Persist a plan atomically, creating the queue directory on first write.\n *\n * `updatedAt` is stamped here so no call site can forget it — the file is the\n * only record of how far a queue got, and a stale timestamp on it is worse than\n * none.\n */\nexport async function saveExecutionPlan(\n path: string,\n plan: ExecutionPlan,\n now: () => string = isoNow,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const stamped: ExecutionPlan = { ...plan, updatedAt: now() };\n await writeFileAtomic(path, `${JSON.stringify(stamped, null, 2)}\\n`);\n}\n\n/**\n * The Issue the queue should work on next, or `null` when every one of them is\n * completed.\n *\n * The order of the lookups *is* the resume policy: an interrupted issue\n * (`in_progress`) and a failed one are retried before the queue moves on, and\n * each of them picks up from its own `tasks.json` (phase-level resume) rather\n * than from the start. A `completed` issue is never revisited — that is the\n * whole point of persisting the queue.\n */\nexport interface NextQueueIssueOptions {\n /**\n * Ids this invocation is done with, however they ended. A queue that skips a\n * failing Issue and comes back to it needs a way to say \"not this one again\",\n * or \"come back later\" becomes \"come back forever\".\n */\n exclude?: ReadonlySet<string>;\n}\n\n/**\n * Whether every dependency this Issue declares *inside the queue* is finished.\n *\n * The execution order already places dependencies first, so this only bites\n * once an entry stops being `completed` — skipped, blocked or failed. Handing\n * out an Issue whose blocker was skipped is how a queue produces work that\n * cannot compile.\n */\nfunction dependenciesSatisfied(plan: ExecutionPlan, entry: ExecutionPlanIssue): boolean {\n return entry.dependsOn.every((id) => {\n const dependency = plan.issues.find((candidate) => candidate.id === id);\n if (dependency === undefined) return true;\n // A container is not work: waiting on it would deadlock the children\n // that complete it.\n if (dependency.role === 'container') return true;\n return dependency.status === 'completed';\n });\n}\n\n/**\n * The Issue to work on next.\n *\n * The order of the four lookups is the resumption policy:\n * an interrupted Issue first (it was mid-flight), then one that failed on a\n * previous invocation, then the untouched ones, and only at the end the ones\n * this queue deliberately set aside — which is what \"go on with the\n * independent work and come back to it\" means in one line.\n *\n * `blocked` is absent on purpose: it needs a human, and no ordering of the\n * queue changes that.\n */\nexport function nextQueueIssue(\n plan: ExecutionPlan,\n options: NextQueueIssueOptions = {},\n): ExecutionPlanIssue | null {\n const exclude = options.exclude ?? new Set<string>();\n const eligible = (status: QueueIssueStatus) => (entry: ExecutionPlanIssue) =>\n entry.role !== 'container' &&\n entry.status === status &&\n !exclude.has(entry.id) &&\n dependenciesSatisfied(plan, entry);\n\n return (\n plan.issues.find(eligible('in_progress')) ??\n plan.issues.find(eligible('failed')) ??\n plan.issues.find(eligible('pending')) ??\n plan.issues.find(eligible('skipped')) ??\n null\n );\n}\n\n/**\n * Status of the queue derived from its entries.\n *\n * `skipped` is *not* terminal — the queue means to come back to it — so a queue\n * holding one is still `in_progress`. `blocked` is: nothing the queue can do\n * moves it, so a queue that ends with one ends `failed`, which is what a person\n * needs to see.\n */\nexport function queueStatus(plan: ExecutionPlan): QueueStatus {\n if (plan.issues.some((entry) => entry.status === 'failed' || entry.status === 'blocked')) {\n return 'failed';\n }\n if (plan.issues.every((entry) => entry.status === 'completed')) return 'completed';\n if (plan.issues.some((entry) => entry.status !== 'pending')) return 'in_progress';\n return 'pending';\n}\n\n/** Whether every Issue of the queue has been resolved. */\nexport function isQueueComplete(plan: ExecutionPlan): boolean {\n return plan.issues.every((entry) => entry.status === 'completed');\n}\n\n/** Apply `patch` to one entry and recompute the queue status. Pure. */\nfunction updateIssue(\n plan: ExecutionPlan,\n id: string,\n patch: Partial<ExecutionPlanIssue>,\n): ExecutionPlan {\n const issues = plan.issues.map((entry) => (entry.id === id ? { ...entry, ...patch } : entry));\n const next: ExecutionPlan = { ...plan, issues };\n return { ...next, status: queueStatus(next) };\n}\n\nexport function markQueueIssueInProgress(\n plan: ExecutionPlan,\n id: string,\n now: () => string = isoNow,\n): ExecutionPlan {\n const current = plan.issues.find((entry) => entry.id === id);\n return updateIssue(plan, id, {\n status: 'in_progress',\n // Preserved across a resume: the queue reports when the work on this Issue\n // really began, not when it was last picked up.\n startedAt: current?.startedAt ?? now(),\n failedPhase: null,\n lastError: null,\n });\n}\n\nfunction completeResolvedContainers(plan: ExecutionPlan, now: () => string): ExecutionPlan {\n let next = plan;\n let changed = true;\n while (changed) {\n changed = false;\n for (const entry of next.issues) {\n if (entry.role !== 'container' || entry.status === 'completed') continue;\n const children = next.issues.filter((candidate) => candidate.parent === entry.id);\n if (children.length === 0) continue;\n if (children.every((child) => child.status === 'completed')) {\n next = updateIssue(next, entry.id, {\n status: 'completed',\n completedAt: now(),\n failedPhase: null,\n lastError: null,\n });\n changed = true;\n }\n }\n }\n return next;\n}\n\nexport function markQueueIssueCompleted(\n plan: ExecutionPlan,\n id: string,\n now: () => string = isoNow,\n): ExecutionPlan {\n return completeResolvedContainers(\n updateIssue(plan, id, {\n status: 'completed',\n completedAt: now(),\n failedPhase: null,\n lastError: null,\n }),\n now,\n );\n}\n\nexport function markQueueIssueFailed(\n plan: ExecutionPlan,\n id: string,\n failure: { phase: string | null; error: LastError | null },\n): ExecutionPlan {\n const current = plan.issues.find((entry) => entry.id === id);\n return updateIssue(plan, id, {\n status: 'failed',\n failedPhase: failure.phase,\n lastError: failure.error,\n attempts: (current?.attempts ?? 0) + 1,\n });\n}\n\n/**\n * Set an Issue aside and come back to it later.\n *\n * The difference from `failed` is the whole point of `--on-issue-failure skip`:\n * a failure that stopped this attempt is not a verdict on the eleven other\n * Issues in the queue, and `skipped` is the status that says \"not now\" rather\n * than \"not at all\". `attempts` is incremented here because the counter is what\n * keeps \"come back later\" from becoming \"come back forever\".\n */\nexport function markQueueIssueSkipped(\n plan: ExecutionPlan,\n id: string,\n failure: { phase: string | null; error: LastError | null },\n): ExecutionPlan {\n const current = plan.issues.find((entry) => entry.id === id);\n return updateIssue(plan, id, {\n status: 'skipped',\n failedPhase: failure.phase,\n lastError: failure.error,\n attempts: (current?.attempts ?? 0) + 1,\n });\n}\n\n/**\n * Stop working on an Issue until a person looks at it.\n *\n * `blocked` is never handed back out by `nextQueueIssue`: waiting cannot fix\n * a missing credential or a repository mid-rebase, and a queue that could\n * unblock itself would spin on the same cause forever.\n */\nexport function markQueueIssueBlocked(\n plan: ExecutionPlan,\n id: string,\n reason: string,\n failure: { phase: string | null; error: LastError | null },\n): ExecutionPlan {\n const current = plan.issues.find((entry) => entry.id === id);\n return updateIssue(plan, id, {\n status: 'blocked',\n blockedReason: reason,\n failedPhase: failure.phase,\n lastError: failure.error,\n attempts: (current?.attempts ?? 0) + 1,\n });\n}\n\n/** Record the branch every Issue of the queue shares. */\nexport function setQueueBranch(plan: ExecutionPlan, branchName: string): ExecutionPlan {\n return { ...plan, branchName };\n}\n\n/** Record the single Pull Request that consolidated the queue. */\nexport function setQueuePullRequest(\n plan: ExecutionPlan,\n pullRequest: PullRequestRef,\n): ExecutionPlan {\n return { ...plan, pullRequest };\n}\n","import type { DependencyGraph } from '../issues/graph.js';\nimport type { Issue } from '../issues/types.js';\n\nexport const CONTAINER_SIGNALS = ['children', 'issue-type', 'label', 'title-prefix'] as const;\n\nexport type ContainerSignal = (typeof CONTAINER_SIGNALS)[number];\n\nexport interface ContainerConfig {\n detect: readonly ContainerSignal[];\n issueTypes: readonly string[];\n labels: readonly string[];\n titlePrefixes: readonly string[];\n}\n\n/** Unconfigured repos: only the universal signal. */\nexport const DEFAULT_CONTAINER_CONFIG: ContainerConfig = {\n detect: ['children'],\n issueTypes: ['Epic'],\n labels: ['epic'],\n titlePrefixes: ['[Epic]'],\n};\n\nexport interface ContainerProbe {\n issue: Pick<Issue, 'title' | 'labels' | 'type'> | null;\n children: readonly string[];\n}\n\nfunction enabled(config: ContainerConfig, signal: ContainerSignal): boolean {\n return config.detect.includes(signal);\n}\n\nfunction hasTitlePrefix(title: string, prefixes: readonly string[]): boolean {\n const trimmed = title.trim();\n return prefixes.some((prefix) => trimmed.toLowerCase().startsWith(prefix.toLowerCase()));\n}\n\n/**\n * Precedence: children > issue type > label > title prefix.\n * Having children always wins when that signal is enabled.\n */\nexport function isContainer(\n probe: ContainerProbe,\n config: ContainerConfig = DEFAULT_CONTAINER_CONFIG,\n): boolean {\n if (enabled(config, 'children') && probe.children.length > 0) return true;\n\n const issue = probe.issue;\n if (issue === null) return false;\n\n if (enabled(config, 'issue-type')) {\n const type = issue.type?.trim();\n if (\n type !== undefined &&\n type !== '' &&\n config.issueTypes.some((name) => name.toLowerCase() === type.toLowerCase())\n ) {\n return true;\n }\n }\n\n if (enabled(config, 'label')) {\n const labels = new Set(issue.labels.map((label) => label.toLowerCase()));\n if (config.labels.some((label) => labels.has(label.toLowerCase()))) return true;\n }\n\n if (enabled(config, 'title-prefix') && hasTitlePrefix(issue.title, config.titlePrefixes)) {\n return true;\n }\n\n return false;\n}\n\n/** Root plus every descendant reached through `children`. */\nexport function collectCascadeIds(graph: DependencyGraph, roots: readonly string[]): string[] {\n const ids = new Set<string>();\n const walk = (id: string): void => {\n if (ids.has(id)) return;\n ids.add(id);\n for (const child of graph.nodes.get(id)?.relations.children ?? []) {\n walk(child);\n }\n };\n for (const root of roots) walk(root);\n return [...ids];\n}\n","import { emptyRelations, uniqueIds } from './relations.js';\nimport type { Issue, IssueRelations } from './types.js';\n\n/**\n * Dependency graph of a set of Issues, built by walking the relations every\n * provider exposes through `fetchRelations`.\n *\n * The traversal is deliberately *structural*: it follows hierarchy\n * (parent/children) and dependencies (blockedBy/blocking) and stops there. Plain\n * mentions are recorded on each node but never expanded — a body citing \"see\n * also #12\" would otherwise drag an unrelated Issue into an execution plan the\n * user is about to confirm.\n */\n\nexport interface DependencyGraphNode {\n id: string;\n relations: IssueRelations;\n /** Distance from the closest root, in traversal hops. */\n depth: number;\n /** The Issue itself, when the caller supplied a way to read it. */\n issue: Issue | null;\n /** True when the node was requested by the user rather than discovered. */\n root: boolean;\n}\n\nexport interface DependencyGraph {\n /** Ids the traversal started from, in the order they were requested. */\n roots: string[];\n /** Every discovered node, keyed by id, in discovery order. */\n nodes: Map<string, DependencyGraphNode>;\n /**\n * Dependency cycles found among the discovered nodes, each listed once,\n * starting at its smallest member. Reported rather than thrown: discovery\n * must still answer, and it is the ordering layer that refuses to run.\n */\n cycles: string[][];\n /** True when a limit stopped the traversal before it was exhausted. */\n truncated: boolean;\n limits: { maxNodes: number; maxDepth: number };\n}\n\n/**\n * Conservative defaults: a real hierarchy is a handful of Issues, and each node\n * costs several API calls. A malformed (or simply huge) graph must not turn a\n * `run` into a rate-limit incident.\n */\nexport const DEFAULT_MAX_NODES = 25;\nexport const DEFAULT_MAX_DEPTH = 3;\n\nexport interface BuildDependencyGraphOptions {\n maxNodes?: number;\n maxDepth?: number;\n /** Issues the caller already resolved, so the traversal does not re-read them. */\n known?: Iterable<Issue>;\n /** Reader for the Issues the traversal discovers. Optional. */\n fetchIssue?: (id: string) => Promise<Issue | null>;\n /** Warning sink for a source that failed. Silent by default. */\n warn?: (message: string) => void;\n}\n\n/** Edge `from` → `to`, meaning \"`from` must be resolved before `to`\". */\nexport interface DependencyEdge {\n from: string;\n to: string;\n}\n\n/**\n * Ordering constraints of a graph: only hierarchy-free, explicit dependencies.\n *\n * `blockedBy`/`blocking` are the two spellings of the same fact, so both are\n * normalized into a single direction here. Parent/child is **not** a constraint\n * — it is a presentation and tie-breaking concern (see `computeExecutionOrder`),\n * because a parent is usually an umbrella that neither blocks nor is blocked by\n * its children.\n *\n * Edges pointing outside the graph are dropped: an Issue the traversal never\n * reached cannot be scheduled, so a constraint against it is unenforceable.\n */\nexport function dependencyEdges(graph: DependencyGraph): DependencyEdge[] {\n const edges: DependencyEdge[] = [];\n const seen = new Set<string>();\n\n const add = (from: string, to: string): void => {\n if (from === to || !graph.nodes.has(from) || !graph.nodes.has(to)) return;\n const key = `${from}->${to}`;\n if (seen.has(key)) return;\n seen.add(key);\n edges.push({ from, to });\n };\n\n for (const node of graph.nodes.values()) {\n for (const blocker of node.relations.blockedBy) {\n add(blocker, node.id);\n }\n for (const blocked of node.relations.blocking) {\n add(node.id, blocked);\n }\n }\n\n return edges;\n}\n\n/** Every cycle of the dependency edges, each reported once. */\nexport function findCycles(graph: DependencyGraph): string[][] {\n const adjacency = new Map<string, string[]>();\n for (const { from, to } of dependencyEdges(graph)) {\n const list = adjacency.get(from);\n if (list === undefined) {\n adjacency.set(from, [to]);\n } else {\n list.push(to);\n }\n }\n\n const cycles: string[][] = [];\n const reported = new Set<string>();\n const state = new Map<string, 'visiting' | 'done'>();\n const stack: string[] = [];\n\n const record = (cycle: string[]): void => {\n // Rotate to the smallest member so the same cycle found from two entry\n // points is reported once.\n let pivot = 0;\n for (let i = 1; i < cycle.length; i++) {\n if (compareIds(cycle[i] as string, cycle[pivot] as string) < 0) pivot = i;\n }\n const normalized = [...cycle.slice(pivot), ...cycle.slice(0, pivot)];\n const key = normalized.join('->');\n if (reported.has(key)) return;\n reported.add(key);\n cycles.push(normalized);\n };\n\n const visit = (id: string): void => {\n state.set(id, 'visiting');\n stack.push(id);\n\n for (const next of adjacency.get(id) ?? []) {\n const status = state.get(next);\n if (status === 'visiting') {\n record(stack.slice(stack.indexOf(next)));\n continue;\n }\n if (status === undefined) {\n visit(next);\n }\n }\n\n stack.pop();\n state.set(id, 'done');\n };\n\n for (const id of graph.nodes.keys()) {\n if (!state.has(id)) visit(id);\n }\n\n return cycles;\n}\n\n/** Numeric when both ids are numbers, lexicographic otherwise. */\nexport function compareIds(a: string, b: string): number {\n const na = Number(a);\n const nb = Number(b);\n if (Number.isInteger(na) && Number.isInteger(nb)) {\n return na - nb;\n }\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** Ids a node links to structurally, in traversal order. */\nfunction neighbours(relations: IssueRelations): string[] {\n return uniqueIds(\n [\n ...(relations.parent === null ? [] : [relations.parent]),\n ...relations.children,\n ...relations.blockedBy,\n ...relations.blocking,\n ],\n relations.id,\n );\n}\n\n/**\n * Walk the relations of `roots` breadth-first and return the whole structure.\n *\n * Failures never abort the walk: a node whose relations cannot be read enters\n * the graph with empty relations (and a warning), exactly like an Issue that\n * genuinely relates to nothing. That keeps a partially unavailable API from\n * costing the user the Issues that *were* discovered.\n *\n * Breadth-first is what makes `depth` meaningful under a limit: when the walk is\n * truncated, what is missing is the far edge of the graph, not a random subset.\n */\nexport async function buildDependencyGraph(\n roots: readonly string[],\n fetchRelations: (id: string) => Promise<IssueRelations | null>,\n options: BuildDependencyGraphOptions = {},\n): Promise<DependencyGraph> {\n const maxNodes = options.maxNodes ?? DEFAULT_MAX_NODES;\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;\n const warn = options.warn ?? ((): void => {});\n\n const known = new Map<string, Issue>();\n for (const issue of options.known ?? []) {\n known.set(issue.id, issue);\n }\n\n const rootIds = uniqueIds(roots);\n const nodes = new Map<string, DependencyGraphNode>();\n const queued = new Set<string>(rootIds);\n let truncated = false;\n\n let frontier: { id: string; depth: number }[] = rootIds.map((id) => ({ id, depth: 0 }));\n\n while (frontier.length > 0) {\n const next: { id: string; depth: number }[] = [];\n\n for (const { id, depth } of frontier) {\n if (nodes.size >= maxNodes) {\n truncated = true;\n break;\n }\n\n let relations: IssueRelations | null = null;\n try {\n relations = await fetchRelations(id);\n } catch (err) {\n warn(\n `Could not read the relations of issue '${id}': ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n let issue = known.get(id) ?? null;\n if (issue === null && options.fetchIssue !== undefined) {\n try {\n issue = await options.fetchIssue(id);\n } catch (err) {\n warn(`Could not read issue '${id}': ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n const resolved = relations ?? emptyRelations(id);\n nodes.set(id, { id, relations: resolved, depth, issue, root: rootIds.includes(id) });\n\n if (depth >= maxDepth) {\n // Only a node that actually has unexplored neighbours truncates the\n // graph; a leaf at max depth explored everything there was.\n if (neighbours(resolved).some((neighbour) => !queued.has(neighbour))) {\n truncated = true;\n }\n continue;\n }\n\n for (const neighbour of neighbours(resolved)) {\n if (queued.has(neighbour)) continue;\n queued.add(neighbour);\n next.push({ id: neighbour, depth: depth + 1 });\n }\n }\n\n if (nodes.size >= maxNodes && next.length > 0) {\n truncated = true;\n break;\n }\n frontier = next;\n }\n\n const graph: DependencyGraph = {\n roots: rootIds,\n nodes,\n cycles: [],\n truncated,\n limits: { maxNodes, maxDepth },\n };\n\n linkReferencedBy(graph);\n graph.cycles = findCycles(graph);\n\n return graph;\n}\n\n/**\n * Complete `referencedBy` with the inverse of `references` among the discovered\n * nodes.\n *\n * The origin only reports the citations it can see (GitHub's timeline covers\n * cross-references but not, for instance, a mention added by the textual\n * heuristic); inverting what the graph already holds costs no API call and\n * keeps the two directions consistent inside it.\n */\nfunction linkReferencedBy(graph: DependencyGraph): void {\n for (const node of graph.nodes.values()) {\n for (const cited of node.relations.references) {\n const target = graph.nodes.get(cited);\n if (target === undefined || target.id === node.id) continue;\n target.relations.referencedBy = uniqueIds(\n [...target.relations.referencedBy, node.id],\n target.id,\n );\n }\n }\n}\n","import { compareIds, type DependencyGraph, dependencyEdges, findCycles } from '../issues/graph.js';\nimport type { IssuePriority } from './types.js';\n\n/**\n * Turning a dependency graph into the order the queue runs in.\n *\n * The criteria are applied in the exact precedence the initiative specifies:\n *\n * 1. **dependencies and blocks** — hard constraints; an Issue never starts\n * before something it depends on has finished. This is the topological part\n * and the only one that can make the computation fail (a cycle);\n * 2. **hierarchy** — with two Issues both ready to run, the ancestor goes\n * first, so an umbrella Issue frames the work of its sub-issues;\n * 3. **priority** — the GitHub labels `high`, `medium` and `low`;\n * 4. **logical order** — the identifier, numerically when it is a number.\n *\n * Everything below the first item is a *tie-break among Issues that are already\n * free to run*, never a constraint: a `high` Issue that depends on a `low` one\n * still runs second, which is the whole point of the feature.\n */\n\nconst PRIORITY_LABELS: Record<string, IssuePriority> = {\n high: 'high',\n medium: 'medium',\n low: 'low',\n};\n\n/** Ranking of a priority; an Issue with no label sorts after every labelled one. */\nconst PRIORITY_RANK: Record<IssuePriority, number> = { high: 0, medium: 1, low: 2 };\nconst NO_PRIORITY_RANK = 3;\n\n/**\n * Priority carried by a label set, or `null` when there is none.\n *\n * Both the bare labels used by this repository (`high`) and the qualified\n * spellings other projects use (`priority: high`, `priority/high`, `P-high`)\n * are accepted; anything else is simply not a priority. The absence of a label\n * is never an error — most Issues have none.\n */\nexport function priorityOf(labels: readonly string[]): IssuePriority | null {\n for (const label of labels) {\n const normalized = label.trim().toLowerCase();\n const direct = PRIORITY_LABELS[normalized];\n if (direct !== undefined) return direct;\n\n const qualified = /^(?:priority|prio|p)\\s*[:/-]\\s*(high|medium|low)$/.exec(normalized);\n const matched = qualified?.[1];\n if (matched !== undefined) return PRIORITY_LABELS[matched] as IssuePriority;\n }\n return null;\n}\n\nexport interface ExecutionOrderOptions {\n /**\n * Subset of the graph to schedule. Defaults to every node — the \"run the\n * whole hierarchy\" answer; the \"only the ones I asked for\" answer passes the\n * requested ids.\n */\n include?: readonly string[];\n}\n\nexport type ExecutionOrderResult =\n | { ok: true; order: string[] }\n | { ok: false; cycles: string[][] };\n\n/** Number of ancestors of `id` inside the selection: 0 for a top-level Issue. */\nfunction hierarchyDepth(\n id: string,\n parentOf: Map<string, string | null>,\n selected: Set<string>,\n): number {\n let depth = 0;\n let current = parentOf.get(id) ?? null;\n const seen = new Set<string>([id]);\n\n while (current !== null && selected.has(current) && !seen.has(current)) {\n depth++;\n seen.add(current);\n current = parentOf.get(current) ?? null;\n }\n\n return depth;\n}\n\n/**\n * Order the selected Issues of a graph.\n *\n * Kahn's algorithm with a deterministic tie-break, so the same graph always\n * produces the same order — a plan the user confirmed must not reshuffle itself\n * on the next run.\n *\n * A cycle is reported, never worked around: an arbitrary order would silently\n * implement an Issue before its dependency, which is exactly the failure this\n * whole feature exists to prevent. Constraints pointing outside the selection\n * are dropped — an Issue that is not going to run cannot block anything.\n */\nexport function computeExecutionOrder(\n graph: DependencyGraph,\n options: ExecutionOrderOptions = {},\n): ExecutionOrderResult {\n const selected = new Set(\n (options.include ?? [...graph.nodes.keys()]).filter((id) => graph.nodes.has(id)),\n );\n\n const parentOf = new Map<string, string | null>();\n const priority = new Map<string, IssuePriority | null>();\n for (const id of selected) {\n const node = graph.nodes.get(id);\n parentOf.set(id, node?.relations.parent ?? null);\n priority.set(id, priorityOf(node?.issue?.labels ?? []));\n }\n\n const incoming = new Map<string, Set<string>>();\n const outgoing = new Map<string, string[]>();\n for (const id of selected) {\n incoming.set(id, new Set());\n outgoing.set(id, []);\n }\n for (const { from, to } of dependencyEdges(graph)) {\n if (!selected.has(from) || !selected.has(to) || from === to) continue;\n incoming.get(to)?.add(from);\n outgoing.get(from)?.push(to);\n }\n\n const depth = new Map<string, number>();\n for (const id of selected) {\n depth.set(id, hierarchyDepth(id, parentOf, selected));\n }\n\n const rank = (id: string): number => {\n const value = priority.get(id) ?? null;\n return value === null ? NO_PRIORITY_RANK : PRIORITY_RANK[value];\n };\n\n const better = (a: string, b: string): number => {\n const byHierarchy = (depth.get(a) ?? 0) - (depth.get(b) ?? 0);\n if (byHierarchy !== 0) return byHierarchy;\n const byPriority = rank(a) - rank(b);\n if (byPriority !== 0) return byPriority;\n return compareIds(a, b);\n };\n\n const ready = [...selected].filter((id) => (incoming.get(id)?.size ?? 0) === 0);\n const order: string[] = [];\n\n while (ready.length > 0) {\n ready.sort(better);\n const next = ready.shift() as string;\n order.push(next);\n\n for (const dependent of outgoing.get(next) ?? []) {\n const pending = incoming.get(dependent);\n if (pending === undefined) continue;\n pending.delete(next);\n if (pending.size === 0) {\n ready.push(dependent);\n }\n }\n }\n\n if (order.length !== selected.size) {\n // Prefer the cycles the graph already recorded; recompute only if the\n // selection is what closed the loop.\n const cycles = graph.cycles.length > 0 ? graph.cycles : findCycles(graph);\n const relevant = cycles.filter((cycle) => cycle.every((id) => selected.has(id)));\n return { ok: false, cycles: relevant.length > 0 ? relevant : cycles };\n }\n\n return { ok: true, order };\n}\n\n/** One-line description of the cycles, for an error message. */\nexport function describeCycles(cycles: readonly string[][]): string {\n return cycles.map((cycle) => [...cycle, cycle[0]].map((id) => `#${id}`).join(' → ')).join('; ');\n}\n"],"mappings":"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","names":["parentOf"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/telemetry/session-id.ts
|
|
4
|
+
var activeSessionId = null;
|
|
5
|
+
function setTelemetrySessionId(sessionId) {
|
|
6
|
+
activeSessionId = sessionId;
|
|
7
|
+
}
|
|
8
|
+
function getTelemetrySessionId() {
|
|
9
|
+
return activeSessionId;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
setTelemetrySessionId,
|
|
14
|
+
getTelemetrySessionId
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=chunk-P3LRUNC6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/telemetry/session-id.ts"],"sourcesContent":["let activeSessionId: string | null = null;\n\n/** Last `session:start` id, so an execution can correlate without being bound late. */\nexport function setTelemetrySessionId(sessionId: string | null): void {\n activeSessionId = sessionId;\n}\n\nexport function getTelemetrySessionId(): string | null {\n return activeSessionId;\n}\n"],"mappings":";;;AAAA,IAAI,kBAAiC;AAG9B,SAAS,sBAAsB,WAAgC;AACpE,oBAAkB;AACpB;AAEO,SAAS,wBAAuC;AACrD,SAAO;AACT;","names":[]}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
NullPublisher
|
|
4
|
+
} from "./chunk-6QYMSNVA.js";
|
|
2
5
|
import {
|
|
3
6
|
getBaseBranch,
|
|
4
7
|
getCommitsSince,
|
|
@@ -9,13 +12,10 @@ import {
|
|
|
9
12
|
normalizeRemoteUrl,
|
|
10
13
|
run,
|
|
11
14
|
stripRemoteUrlCredentials
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import {
|
|
14
|
-
NullPublisher
|
|
15
|
-
} from "./chunk-BYZDPR7N.js";
|
|
15
|
+
} from "./chunk-BEZ5BA5U.js";
|
|
16
16
|
import {
|
|
17
17
|
isoNow
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-J3SOTUVI.js";
|
|
19
19
|
|
|
20
20
|
// src/core/session-git.ts
|
|
21
21
|
async function listPullRequests(branch, options = {}) {
|
|
@@ -80,8 +80,9 @@ async function publishGitState(publisher, sources = {}) {
|
|
|
80
80
|
try {
|
|
81
81
|
const branch = await src.currentBranch();
|
|
82
82
|
const baseBranch = await src.baseBranch();
|
|
83
|
+
const commitBaseline = publisher.snapshot().git.branchCreated === false ? publisher.snapshot().git.startCommit ?? baseBranch : baseBranch;
|
|
83
84
|
const [commits, pullRequests, remoteUrl, headCommit, repositoryRoot] = await Promise.all([
|
|
84
|
-
src.commitsSince(
|
|
85
|
+
src.commitsSince(commitBaseline),
|
|
85
86
|
src.pullRequests(branch),
|
|
86
87
|
collect(() => src.remoteUrl()),
|
|
87
88
|
collect(() => src.headCommit()),
|
|
@@ -111,4 +112,4 @@ export {
|
|
|
111
112
|
listPullRequests,
|
|
112
113
|
publishGitState
|
|
113
114
|
};
|
|
114
|
-
//# sourceMappingURL=chunk-
|
|
115
|
+
//# sourceMappingURL=chunk-PBTA3QQX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/session-git.ts"],"sourcesContent":["import {\n getBaseBranch,\n getCommitsSince,\n getCurrentBranch,\n getHeadCommit,\n getProjectRoot,\n getRemoteUrl,\n normalizeRemoteUrl,\n stripRemoteUrlCredentials,\n} from '../utils/git.js';\nimport { run } from '../utils/shell.js';\nimport {\n NullPublisher,\n type SessionCommit,\n type SessionPublisher,\n type SessionPullRequest,\n} from './session-state.js';\nimport { isoNow } from './state-manager.js';\n\n/**\n * Low-frequency enrichment of the session snapshot with git commits and pull\n * requests. Called only at phase boundaries (run.ts) and at the end of each\n * iteration (engine.ts) — never per HTTP request: the server (US-006) serves\n * the in-memory snapshot as-is.\n *\n * Like every monitoring surface, this must never affect the pipeline: with\n * the NullPublisher installed it returns before spawning any subprocess, and\n * every failure is swallowed.\n */\n\n/** Data sources, injectable for tests. */\nexport interface GitStateSources {\n currentBranch(): Promise<string>;\n baseBranch(): Promise<string>;\n commitsSince(base: string): Promise<SessionCommit[]>;\n pullRequests(branch: string): Promise<SessionPullRequest[]>;\n /** URL of the origin remote, or null when none is configured. */\n remoteUrl(): Promise<string | null>;\n /** Abbreviated hash of HEAD, or null when there is none. */\n headCommit(): Promise<string | null>;\n /** Working directory of the run; falls back to process.cwd(). */\n projectRoot(): Promise<string | null>;\n now(): string;\n}\n\n/**\n * List PRs whose head is the given branch via the GitHub CLI. Never throws;\n * returns [] when gh is unavailable, unauthenticated or returns bad JSON.\n */\nexport interface ListPullRequestsOptions {\n /**\n * `all` — the default, and what the session snapshot reports — or `open`,\n * which is the question \"is there already a Pull Request I would be\n * duplicating\".\n */\n state?: 'all' | 'open';\n}\n\nexport async function listPullRequests(\n branch: string,\n options: ListPullRequestsOptions = {},\n): Promise<SessionPullRequest[]> {\n if (!branch) return [];\n\n const result = await run('gh', [\n 'pr',\n 'list',\n '--head',\n branch,\n '--state',\n options.state ?? 'all',\n '--json',\n 'number,url,title',\n '--limit',\n '10',\n ]);\n if (result.exitCode !== 0) return [];\n\n try {\n const parsed: unknown = JSON.parse(result.stdout || '[]');\n if (!Array.isArray(parsed)) return [];\n return parsed\n .filter(\n (pr): pr is { number: number; url: string; title: string } =>\n typeof pr === 'object' &&\n pr !== null &&\n typeof (pr as { number?: unknown }).number === 'number' &&\n typeof (pr as { url?: unknown }).url === 'string' &&\n typeof (pr as { title?: unknown }).title === 'string',\n )\n .map((pr) => ({ number: pr.number, url: pr.url, title: pr.title }));\n } catch {\n return [];\n }\n}\n\nconst defaultSources: GitStateSources = {\n currentBranch: getCurrentBranch,\n baseBranch: getBaseBranch,\n commitsSince: getCommitsSince,\n pullRequests: listPullRequests,\n remoteUrl: () => getRemoteUrl(),\n headCommit: () => getHeadCommit(),\n // getProjectRoot() throws outside a git repository; the directory the run\n // happens in is still worth reporting, so fall back to it.\n projectRoot: async () => {\n try {\n return await getProjectRoot();\n } catch {\n return process.cwd();\n }\n },\n now: isoNow,\n};\n\n/**\n * Run a source in isolation: its failure yields null instead of aborting the\n * whole publication, so one unavailable field never hides the others.\n */\nasync function collect<T>(source: () => Promise<T | null>): Promise<T | null> {\n try {\n return await source();\n } catch {\n return null;\n }\n}\n\n/**\n * Reduce an origin URL to the `owner/repo` identity, dropping the host that\n * normalizeRemoteUrl() prepends. Returns null without a remote.\n *\n * Known limitation inherited from normalizeRemoteUrl(): the result is\n * lowercased, so a repository whose path has uppercase letters is reported in\n * lowercase.\n */\nfunction deriveRepositoryName(remoteUrl: string | null): string | null {\n const normalized = normalizeRemoteUrl(remoteUrl);\n if (normalized === null) return null;\n const slash = normalized.indexOf('/');\n return slash === -1 ? null : normalized.slice(slash + 1);\n}\n\n/**\n * Gather branch, base branch, commits, PRs and repository identity, then\n * publish a single git:update event. Never throws.\n */\nexport async function publishGitState(\n publisher: SessionPublisher,\n sources: Partial<GitStateSources> = {},\n): Promise<void> {\n if (publisher instanceof NullPublisher) return;\n const src: GitStateSources = { ...defaultSources, ...sources };\n\n try {\n const branch = await src.currentBranch();\n const baseBranch = await src.baseBranch();\n const [commits, pullRequests, remoteUrl, headCommit, repositoryRoot] = await Promise.all([\n src.commitsSince(
|
|
1
|
+
{"version":3,"sources":["../src/core/session-git.ts"],"sourcesContent":["import {\n getBaseBranch,\n getCommitsSince,\n getCurrentBranch,\n getHeadCommit,\n getProjectRoot,\n getRemoteUrl,\n normalizeRemoteUrl,\n stripRemoteUrlCredentials,\n} from '../utils/git.js';\nimport { run } from '../utils/shell.js';\nimport {\n NullPublisher,\n type SessionCommit,\n type SessionPublisher,\n type SessionPullRequest,\n} from './session-state.js';\nimport { isoNow } from './state-manager.js';\n\n/**\n * Low-frequency enrichment of the session snapshot with git commits and pull\n * requests. Called only at phase boundaries (run.ts) and at the end of each\n * iteration (engine.ts) — never per HTTP request: the server (US-006) serves\n * the in-memory snapshot as-is.\n *\n * Like every monitoring surface, this must never affect the pipeline: with\n * the NullPublisher installed it returns before spawning any subprocess, and\n * every failure is swallowed.\n */\n\n/** Data sources, injectable for tests. */\nexport interface GitStateSources {\n currentBranch(): Promise<string>;\n baseBranch(): Promise<string>;\n commitsSince(base: string): Promise<SessionCommit[]>;\n pullRequests(branch: string): Promise<SessionPullRequest[]>;\n /** URL of the origin remote, or null when none is configured. */\n remoteUrl(): Promise<string | null>;\n /** Abbreviated hash of HEAD, or null when there is none. */\n headCommit(): Promise<string | null>;\n /** Working directory of the run; falls back to process.cwd(). */\n projectRoot(): Promise<string | null>;\n now(): string;\n}\n\n/**\n * List PRs whose head is the given branch via the GitHub CLI. Never throws;\n * returns [] when gh is unavailable, unauthenticated or returns bad JSON.\n */\nexport interface ListPullRequestsOptions {\n /**\n * `all` — the default, and what the session snapshot reports — or `open`,\n * which is the question \"is there already a Pull Request I would be\n * duplicating\".\n */\n state?: 'all' | 'open';\n}\n\nexport async function listPullRequests(\n branch: string,\n options: ListPullRequestsOptions = {},\n): Promise<SessionPullRequest[]> {\n if (!branch) return [];\n\n const result = await run('gh', [\n 'pr',\n 'list',\n '--head',\n branch,\n '--state',\n options.state ?? 'all',\n '--json',\n 'number,url,title',\n '--limit',\n '10',\n ]);\n if (result.exitCode !== 0) return [];\n\n try {\n const parsed: unknown = JSON.parse(result.stdout || '[]');\n if (!Array.isArray(parsed)) return [];\n return parsed\n .filter(\n (pr): pr is { number: number; url: string; title: string } =>\n typeof pr === 'object' &&\n pr !== null &&\n typeof (pr as { number?: unknown }).number === 'number' &&\n typeof (pr as { url?: unknown }).url === 'string' &&\n typeof (pr as { title?: unknown }).title === 'string',\n )\n .map((pr) => ({ number: pr.number, url: pr.url, title: pr.title }));\n } catch {\n return [];\n }\n}\n\nconst defaultSources: GitStateSources = {\n currentBranch: getCurrentBranch,\n baseBranch: getBaseBranch,\n commitsSince: getCommitsSince,\n pullRequests: listPullRequests,\n remoteUrl: () => getRemoteUrl(),\n headCommit: () => getHeadCommit(),\n // getProjectRoot() throws outside a git repository; the directory the run\n // happens in is still worth reporting, so fall back to it.\n projectRoot: async () => {\n try {\n return await getProjectRoot();\n } catch {\n return process.cwd();\n }\n },\n now: isoNow,\n};\n\n/**\n * Run a source in isolation: its failure yields null instead of aborting the\n * whole publication, so one unavailable field never hides the others.\n */\nasync function collect<T>(source: () => Promise<T | null>): Promise<T | null> {\n try {\n return await source();\n } catch {\n return null;\n }\n}\n\n/**\n * Reduce an origin URL to the `owner/repo` identity, dropping the host that\n * normalizeRemoteUrl() prepends. Returns null without a remote.\n *\n * Known limitation inherited from normalizeRemoteUrl(): the result is\n * lowercased, so a repository whose path has uppercase letters is reported in\n * lowercase.\n */\nfunction deriveRepositoryName(remoteUrl: string | null): string | null {\n const normalized = normalizeRemoteUrl(remoteUrl);\n if (normalized === null) return null;\n const slash = normalized.indexOf('/');\n return slash === -1 ? null : normalized.slice(slash + 1);\n}\n\n/**\n * Gather branch, base branch, commits, PRs and repository identity, then\n * publish a single git:update event. Never throws.\n */\nexport async function publishGitState(\n publisher: SessionPublisher,\n sources: Partial<GitStateSources> = {},\n): Promise<void> {\n if (publisher instanceof NullPublisher) return;\n const src: GitStateSources = { ...defaultSources, ...sources };\n\n try {\n const branch = await src.currentBranch();\n const baseBranch = await src.baseBranch();\n const commitBaseline =\n publisher.snapshot().git.branchCreated === false\n ? (publisher.snapshot().git.startCommit ?? baseBranch)\n : baseBranch;\n const [commits, pullRequests, remoteUrl, headCommit, repositoryRoot] = await Promise.all([\n src.commitsSince(commitBaseline),\n src.pullRequests(branch),\n collect(() => src.remoteUrl()),\n collect(() => src.headCommit()),\n collect(() => src.projectRoot()),\n ]);\n\n publisher.publish({\n type: 'git:update',\n at: src.now(),\n branch,\n baseBranch,\n commits,\n pullRequests,\n repositoryName: deriveRepositoryName(remoteUrl),\n // Never publish the raw remote: an HTTPS remote configured for\n // automation commonly embeds a token (user:token@host), and this event\n // is served unauthenticated by the web monitor and persisted to\n // session.json.\n remoteUrl: stripRemoteUrlCredentials(remoteUrl),\n headCommit,\n repositoryRoot,\n });\n } catch {\n // Monitoring enrichment must never propagate errors to the pipeline.\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0DA,eAAsB,iBACpB,QACA,UAAmC,CAAC,GACL;AAC/B,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAM,SAAS,MAAM,IAAI,MAAM;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AAEnC,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,OAAO,UAAU,IAAI;AACxD,QAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO,CAAC;AACpC,WAAO,OACJ;AAAA,MACC,CAAC,OACC,OAAO,OAAO,YACd,OAAO,QACP,OAAQ,GAA4B,WAAW,YAC/C,OAAQ,GAAyB,QAAQ,YACzC,OAAQ,GAA2B,UAAU;AAAA,IACjD,EACC,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,KAAK,GAAG,KAAK,OAAO,GAAG,MAAM,EAAE;AAAA,EACtE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,IAAM,iBAAkC;AAAA,EACtC,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,cAAc;AAAA,EACd,WAAW,MAAM,aAAa;AAAA,EAC9B,YAAY,MAAM,cAAc;AAAA;AAAA;AAAA,EAGhC,aAAa,YAAY;AACvB,QAAI;AACF,aAAO,MAAM,eAAe;AAAA,IAC9B,QAAQ;AACN,aAAO,QAAQ,IAAI;AAAA,IACrB;AAAA,EACF;AAAA,EACA,KAAK;AACP;AAMA,eAAe,QAAW,QAAoD;AAC5E,MAAI;AACF,WAAO,MAAM,OAAO;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUA,SAAS,qBAAqB,WAAyC;AACrE,QAAM,aAAa,mBAAmB,SAAS;AAC/C,MAAI,eAAe,KAAM,QAAO;AAChC,QAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,SAAO,UAAU,KAAK,OAAO,WAAW,MAAM,QAAQ,CAAC;AACzD;AAMA,eAAsB,gBACpB,WACA,UAAoC,CAAC,GACtB;AACf,MAAI,qBAAqB,cAAe;AACxC,QAAM,MAAuB,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAE7D,MAAI;AACF,UAAM,SAAS,MAAM,IAAI,cAAc;AACvC,UAAM,aAAa,MAAM,IAAI,WAAW;AACxC,UAAM,iBACJ,UAAU,SAAS,EAAE,IAAI,kBAAkB,QACtC,UAAU,SAAS,EAAE,IAAI,eAAe,aACzC;AACN,UAAM,CAAC,SAAS,cAAc,WAAW,YAAY,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvF,IAAI,aAAa,cAAc;AAAA,MAC/B,IAAI,aAAa,MAAM;AAAA,MACvB,QAAQ,MAAM,IAAI,UAAU,CAAC;AAAA,MAC7B,QAAQ,MAAM,IAAI,WAAW,CAAC;AAAA,MAC9B,QAAQ,MAAM,IAAI,YAAY,CAAC;AAAA,IACjC,CAAC;AAED,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,IAAI,IAAI,IAAI;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,qBAAqB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,MAK9C,WAAW,0BAA0B,SAAS;AAAA,MAC9C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;","names":[]}
|