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.
Files changed (197) hide show
  1. package/README.md +79 -274
  2. package/dist/agent-OX3KPHE4.js +30 -0
  3. package/dist/{analyze-OEET7KGE.js → analyze-WIND2SEB.js} +31 -16
  4. package/dist/analyze-WIND2SEB.js.map +1 -0
  5. package/dist/{apply-ZIA3C52S.js → apply-JNOI2LR4.js} +18 -7
  6. package/dist/{apply-ZIA3C52S.js.map → apply-JNOI2LR4.js.map} +1 -1
  7. package/dist/bench-B4VZON7E.js +910 -0
  8. package/dist/bench-B4VZON7E.js.map +1 -0
  9. package/dist/{chunk-FADTCQGM.js → chunk-2IQ6M4ZE.js} +94 -32
  10. package/dist/chunk-2IQ6M4ZE.js.map +1 -0
  11. package/dist/chunk-3BWZO4YI.js +141 -0
  12. package/dist/chunk-3BWZO4YI.js.map +1 -0
  13. package/dist/chunk-3WFZETIM.js +163 -0
  14. package/dist/chunk-3WFZETIM.js.map +1 -0
  15. package/dist/chunk-67YIU2VB.js +362 -0
  16. package/dist/chunk-67YIU2VB.js.map +1 -0
  17. package/dist/{chunk-QCPGHBSZ.js → chunk-6BENHR2I.js} +63 -21
  18. package/dist/chunk-6BENHR2I.js.map +1 -0
  19. package/dist/{chunk-BYZDPR7N.js → chunk-6QYMSNVA.js} +194 -235
  20. package/dist/chunk-6QYMSNVA.js.map +1 -0
  21. package/dist/{chunk-Y5ZDJ4PJ.js → chunk-76MMPJ53.js} +20 -10
  22. package/dist/chunk-76MMPJ53.js.map +1 -0
  23. package/dist/chunk-7Z4Y3VKM.js +26 -0
  24. package/dist/chunk-7Z4Y3VKM.js.map +1 -0
  25. package/dist/{chunk-3QHK4YQA.js → chunk-B72RQZBV.js} +346 -119
  26. package/dist/chunk-B72RQZBV.js.map +1 -0
  27. package/dist/chunk-BEZ5BA5U.js +625 -0
  28. package/dist/chunk-BEZ5BA5U.js.map +1 -0
  29. package/dist/chunk-BRCNQXYQ.js +74 -0
  30. package/dist/chunk-BRCNQXYQ.js.map +1 -0
  31. package/dist/chunk-CGKLE6WR.js +1203 -0
  32. package/dist/chunk-CGKLE6WR.js.map +1 -0
  33. package/dist/chunk-CRGIQFUQ.js +83 -0
  34. package/dist/chunk-CRGIQFUQ.js.map +1 -0
  35. package/dist/{chunk-NS6R37II.js → chunk-F6TOYSYY.js} +141 -12
  36. package/dist/chunk-F6TOYSYY.js.map +1 -0
  37. package/dist/chunk-G5EK2XRN.js +25 -0
  38. package/dist/chunk-G5EK2XRN.js.map +1 -0
  39. package/dist/chunk-HAKDLR6N.js +134 -0
  40. package/dist/chunk-HAKDLR6N.js.map +1 -0
  41. package/dist/chunk-J3SOTUVI.js +298 -0
  42. package/dist/chunk-J3SOTUVI.js.map +1 -0
  43. package/dist/chunk-JN6D3MY6.js +30 -0
  44. package/dist/chunk-JN6D3MY6.js.map +1 -0
  45. package/dist/{chunk-LAFNLLQP.js → chunk-KMRFRXIT.js} +5 -5
  46. package/dist/chunk-KT7JKOXB.js +72 -0
  47. package/dist/chunk-KT7JKOXB.js.map +1 -0
  48. package/dist/chunk-L6HSKTQE.js +77 -0
  49. package/dist/chunk-L6HSKTQE.js.map +1 -0
  50. package/dist/chunk-LBGHI4S2.js +1264 -0
  51. package/dist/chunk-LBGHI4S2.js.map +1 -0
  52. package/dist/chunk-LEW4QM74.js +180 -0
  53. package/dist/chunk-LEW4QM74.js.map +1 -0
  54. package/dist/{chunk-FJP3UQGD.js → chunk-LFEQIZLB.js} +115 -20
  55. package/dist/chunk-LFEQIZLB.js.map +1 -0
  56. package/dist/chunk-OOVG2KBY.js +77 -0
  57. package/dist/chunk-OOVG2KBY.js.map +1 -0
  58. package/dist/{chunk-56KS3TFQ.js → chunk-OR43364P.js} +115 -160
  59. package/dist/chunk-OR43364P.js.map +1 -0
  60. package/dist/chunk-P3LRUNC6.js +16 -0
  61. package/dist/chunk-P3LRUNC6.js.map +1 -0
  62. package/dist/{chunk-TSOLWK7Y.js → chunk-PBTA3QQX.js} +8 -7
  63. package/dist/{chunk-TSOLWK7Y.js.map → chunk-PBTA3QQX.js.map} +1 -1
  64. package/dist/{chunk-MJULIKQU.js → chunk-PHW2YV6N.js} +23 -47
  65. package/dist/chunk-PHW2YV6N.js.map +1 -0
  66. package/dist/{chunk-73ATPIYX.js → chunk-PZTWU277.js} +36 -71
  67. package/dist/chunk-PZTWU277.js.map +1 -0
  68. package/dist/{chunk-M5UCXTIT.js → chunk-QD4VOILZ.js} +22 -18
  69. package/dist/chunk-QD4VOILZ.js.map +1 -0
  70. package/dist/chunk-QJ5UZAH5.js +2718 -0
  71. package/dist/chunk-QJ5UZAH5.js.map +1 -0
  72. package/dist/chunk-QK7WUO7A.js +283 -0
  73. package/dist/chunk-QK7WUO7A.js.map +1 -0
  74. package/dist/{chunk-A4SLHOW7.js → chunk-QZVKRDJY.js} +27 -19
  75. package/dist/chunk-QZVKRDJY.js.map +1 -0
  76. package/dist/chunk-REO3PXXO.js +71 -0
  77. package/dist/chunk-REO3PXXO.js.map +1 -0
  78. package/dist/{chunk-EZATO3DW.js → chunk-RVO7L4FX.js} +594 -17
  79. package/dist/chunk-RVO7L4FX.js.map +1 -0
  80. package/dist/{chunk-XQUSIEKA.js → chunk-SZMHCEYV.js} +63 -14
  81. package/dist/chunk-SZMHCEYV.js.map +1 -0
  82. package/dist/chunk-TYRNTSPJ.js +243 -0
  83. package/dist/chunk-TYRNTSPJ.js.map +1 -0
  84. package/dist/chunk-UJ3L2MS7.js +238 -0
  85. package/dist/chunk-UJ3L2MS7.js.map +1 -0
  86. package/dist/chunk-V7MO5EDS.js +120 -0
  87. package/dist/chunk-V7MO5EDS.js.map +1 -0
  88. package/dist/chunk-WB2X37MO.js +415 -0
  89. package/dist/chunk-WB2X37MO.js.map +1 -0
  90. package/dist/{chunk-NTMMF5UD.js → chunk-X44FKNKP.js} +525 -252
  91. package/dist/chunk-X44FKNKP.js.map +1 -0
  92. package/dist/chunk-XEYH6ZZI.js +289 -0
  93. package/dist/chunk-XEYH6ZZI.js.map +1 -0
  94. package/dist/cli.js +267 -44
  95. package/dist/cli.js.map +1 -1
  96. package/dist/{config-PRJGWW7J.js → config-HMFMCY2M.js} +31 -5
  97. package/dist/contract-JH2WBIO6.js +8 -0
  98. package/dist/conventions-NJF2OPVQ.js +146 -0
  99. package/dist/conventions-NJF2OPVQ.js.map +1 -0
  100. package/dist/diagnostics-THH42ZMP.js +23 -0
  101. package/dist/execute-KFNNZZHI.js +35 -0
  102. package/dist/{generate-EGB4KV2B.js → generate-FW5C6NP7.js} +37 -20
  103. package/dist/{generate-EGB4KV2B.js.map → generate-FW5C6NP7.js.map} +1 -1
  104. package/dist/git-W72QQ6GT.js +33 -0
  105. package/dist/init-HTN4V67Q.js +24 -0
  106. package/dist/{operations-BYT626KQ.js → operations-BCFOBH42.js} +27 -15
  107. package/dist/{operations-BYT626KQ.js.map → operations-BCFOBH42.js.map} +1 -1
  108. package/dist/permissions-4AKNQZHK.js +18 -0
  109. package/dist/plan-SIZLGA4V.js +34 -0
  110. package/dist/{policy-6S4GFC76.js → policy-DT6Q6ZVM.js} +20 -6
  111. package/dist/policy-DT6Q6ZVM.js.map +1 -0
  112. package/dist/pr-OMWCGUOW.js +39 -0
  113. package/dist/pr-review-N24CZPKR.js +32 -0
  114. package/dist/pr-review-N24CZPKR.js.map +1 -0
  115. package/dist/prd-5OFTZAHJ.js +33 -0
  116. package/dist/prd-5OFTZAHJ.js.map +1 -0
  117. package/dist/ps-RFORTCUD.js +93 -0
  118. package/dist/ps-RFORTCUD.js.map +1 -0
  119. package/dist/recorder-KCCPMKQG.js +32 -0
  120. package/dist/recorder-KCCPMKQG.js.map +1 -0
  121. package/dist/registry-GLPXOMFG.js +15 -0
  122. package/dist/registry-GLPXOMFG.js.map +1 -0
  123. package/dist/{resume-PPCNQVVV.js → resume-M5RLKP4I.js} +55 -34
  124. package/dist/{resume-PPCNQVVV.js.map → resume-M5RLKP4I.js.map} +1 -1
  125. package/dist/review-YM4JAABY.js +35 -0
  126. package/dist/review-YM4JAABY.js.map +1 -0
  127. package/dist/routing-NNT5WKGX.js +94 -0
  128. package/dist/routing-NNT5WKGX.js.map +1 -0
  129. package/dist/run-PZUKHPQK.js +54 -0
  130. package/dist/run-PZUKHPQK.js.map +1 -0
  131. package/dist/session-publisher-T7EI3CIP.js +11 -0
  132. package/dist/session-publisher-T7EI3CIP.js.map +1 -0
  133. package/dist/{state-manager-2EDVDBAR.js → state-manager-GQH32C44.js} +4 -2
  134. package/dist/state-manager-GQH32C44.js.map +1 -0
  135. package/dist/usage-V2CHE5PY.js +177 -0
  136. package/dist/usage-V2CHE5PY.js.map +1 -0
  137. package/dist/{web-EF5WIIGG.js → web-EA3KGNFN.js} +45 -30
  138. package/dist/web-EA3KGNFN.js.map +1 -0
  139. package/package.json +6 -2
  140. package/prompts/execute.md +7 -8
  141. package/prompts/plan.md +4 -5
  142. package/prompts/pr.md +2 -2
  143. package/web/AGENTS.md +152 -13
  144. package/web/public/app.css +380 -109
  145. package/web/public/app.js +525 -25
  146. package/web/public/index.html +68 -1
  147. package/dist/analyze-OEET7KGE.js.map +0 -1
  148. package/dist/chunk-3QHK4YQA.js.map +0 -1
  149. package/dist/chunk-42PJFMAR.js +0 -605
  150. package/dist/chunk-42PJFMAR.js.map +0 -1
  151. package/dist/chunk-4JSOYE4G.js +0 -368
  152. package/dist/chunk-4JSOYE4G.js.map +0 -1
  153. package/dist/chunk-56KS3TFQ.js.map +0 -1
  154. package/dist/chunk-73ATPIYX.js.map +0 -1
  155. package/dist/chunk-A4SLHOW7.js.map +0 -1
  156. package/dist/chunk-BAUPQXPE.js +0 -173
  157. package/dist/chunk-BAUPQXPE.js.map +0 -1
  158. package/dist/chunk-BYZDPR7N.js.map +0 -1
  159. package/dist/chunk-CD5ULRVC.js +0 -615
  160. package/dist/chunk-CD5ULRVC.js.map +0 -1
  161. package/dist/chunk-DIDUVL6O.js +0 -1365
  162. package/dist/chunk-DIDUVL6O.js.map +0 -1
  163. package/dist/chunk-EZATO3DW.js.map +0 -1
  164. package/dist/chunk-FADTCQGM.js.map +0 -1
  165. package/dist/chunk-FJP3UQGD.js.map +0 -1
  166. package/dist/chunk-LWRSMTTZ.js +0 -18
  167. package/dist/chunk-LWRSMTTZ.js.map +0 -1
  168. package/dist/chunk-M5UCXTIT.js.map +0 -1
  169. package/dist/chunk-M66SJHQQ.js +0 -206
  170. package/dist/chunk-M66SJHQQ.js.map +0 -1
  171. package/dist/chunk-MJULIKQU.js.map +0 -1
  172. package/dist/chunk-NS6R37II.js.map +0 -1
  173. package/dist/chunk-NTMMF5UD.js.map +0 -1
  174. package/dist/chunk-QCPGHBSZ.js.map +0 -1
  175. package/dist/chunk-XQUSIEKA.js.map +0 -1
  176. package/dist/chunk-Y5ZDJ4PJ.js.map +0 -1
  177. package/dist/execute-XBNVL753.js +0 -18
  178. package/dist/init-AJHCXJBP.js +0 -10
  179. package/dist/plan-QOZ3RIO6.js +0 -21
  180. package/dist/policy-6S4GFC76.js.map +0 -1
  181. package/dist/pr-EBBHD2ZX.js +0 -26
  182. package/dist/pr-review-VVMW5PO4.js +0 -20
  183. package/dist/prd-JQSZF7PR.js +0 -21
  184. package/dist/review-3F6MARWH.js +0 -19
  185. package/dist/run-RXE5GDQO.js +0 -36
  186. package/dist/web-EF5WIIGG.js.map +0 -1
  187. /package/dist/{config-PRJGWW7J.js.map → agent-OX3KPHE4.js.map} +0 -0
  188. /package/dist/{chunk-LAFNLLQP.js.map → chunk-KMRFRXIT.js.map} +0 -0
  189. /package/dist/{execute-XBNVL753.js.map → config-HMFMCY2M.js.map} +0 -0
  190. /package/dist/{init-AJHCXJBP.js.map → contract-JH2WBIO6.js.map} +0 -0
  191. /package/dist/{plan-QOZ3RIO6.js.map → diagnostics-THH42ZMP.js.map} +0 -0
  192. /package/dist/{pr-EBBHD2ZX.js.map → execute-KFNNZZHI.js.map} +0 -0
  193. /package/dist/{pr-review-VVMW5PO4.js.map → git-W72QQ6GT.js.map} +0 -0
  194. /package/dist/{prd-JQSZF7PR.js.map → init-HTN4V67Q.js.map} +0 -0
  195. /package/dist/{review-3F6MARWH.js.map → permissions-4AKNQZHK.js.map} +0 -0
  196. /package/dist/{run-RXE5GDQO.js.map → plan-SIZLGA4V.js.map} +0 -0
  197. /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-CD5ULRVC.js";
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 as mkdir2, readFile } from "fs/promises";
244
- import { dirname as dirname2 } from "path";
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, parentOf, selected) {
350
+ function hierarchyDepth(id, parentOf2, selected) {
436
351
  let depth = 0;
437
- let current = parentOf.get(id) ?? null;
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 = parentOf.get(current) ?? null;
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 parentOf = /* @__PURE__ */ new Map();
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
- parentOf.set(id, node?.relations.parent ?? null);
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, parentOf, selected));
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 ?? null,
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 mkdir2(dirname2(path), { recursive: true });
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
- return dependency === void 0 || dependency.status === "completed";
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 updateIssue(plan, id, {
638
- status: "completed",
639
- completedAt: now(),
640
- failedPhase: null,
641
- lastError: null
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-56KS3TFQ.js.map
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-DIDUVL6O.js";
13
- import {
14
- NullPublisher
15
- } from "./chunk-BYZDPR7N.js";
15
+ } from "./chunk-BEZ5BA5U.js";
16
16
  import {
17
17
  isoNow
18
- } from "./chunk-CD5ULRVC.js";
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(baseBranch),
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-TSOLWK7Y.js.map
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(baseBranch),\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,CAAC,SAAS,cAAc,WAAW,YAAY,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvF,IAAI,aAAa,UAAU;AAAA,MAC3B,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":[]}
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":[]}