issue-flow 0.7.0 → 0.7.1

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 (64) hide show
  1. package/README.md +3 -1
  2. package/dist/{analyze-WRFFG2R5.js → analyze-R25HDGBJ.js} +5 -5
  3. package/dist/{chunk-EWMSQQL2.js → chunk-23WOEBGN.js} +5 -5
  4. package/dist/{chunk-OVFYJLOH.js → chunk-2AVZZAC6.js} +138 -13
  5. package/dist/chunk-2AVZZAC6.js.map +1 -0
  6. package/dist/{chunk-75K5IKAC.js → chunk-ASMCLXQ2.js} +6 -6
  7. package/dist/{chunk-JV7P6UGG.js → chunk-EHVKXFFN.js} +2 -2
  8. package/dist/{chunk-Z3UIGLZG.js → chunk-EM43T462.js} +13 -5
  9. package/dist/{chunk-Z3UIGLZG.js.map → chunk-EM43T462.js.map} +1 -1
  10. package/dist/{chunk-UX6YAVLT.js → chunk-HJ7JT777.js} +6 -6
  11. package/dist/{chunk-2Y3UO7H2.js → chunk-JNEHVQH5.js} +13 -1
  12. package/dist/chunk-JNEHVQH5.js.map +1 -0
  13. package/dist/{chunk-HS4QWZAO.js → chunk-RN2FAMUU.js} +3 -3
  14. package/dist/{chunk-KUDAY57D.js → chunk-TCOS2KFB.js} +2 -2
  15. package/dist/{chunk-CW6UE3NW.js → chunk-WHIBTNYI.js} +3 -3
  16. package/dist/{chunk-YXJPKBPV.js → chunk-YGEWIEAI.js} +10 -9
  17. package/dist/chunk-YGEWIEAI.js.map +1 -0
  18. package/dist/{chunk-VLSZFMLZ.js → chunk-YLXPLHEL.js} +2 -2
  19. package/dist/{chunk-BTBSVBE3.js → chunk-ZAEBDO3Q.js} +6 -6
  20. package/dist/cli.js +13 -13
  21. package/dist/{config-UHQ6XXX2.js → config-SJAQMFWB.js} +9 -3
  22. package/dist/execute-VZ7SHLP4.js +13 -0
  23. package/dist/{generate-DUKQCADD.js → generate-LUK3XTIP.js} +5 -5
  24. package/dist/init-5KXCG36P.js +9 -0
  25. package/dist/plan-R34SAWRK.js +15 -0
  26. package/dist/pr-P4BDQXUQ.js +15 -0
  27. package/dist/pr-review-TOSBE6ZS.js +15 -0
  28. package/dist/prd-RYLULM75.js +15 -0
  29. package/dist/review-ZSC5ELQA.js +13 -0
  30. package/dist/{run-VC647DQI.js → run-SDRQDMSZ.js} +14 -14
  31. package/package.json +1 -1
  32. package/prompts/execute.md +17 -5
  33. package/prompts/plan.md +1 -0
  34. package/prompts/review.md +2 -0
  35. package/dist/chunk-2Y3UO7H2.js.map +0 -1
  36. package/dist/chunk-OVFYJLOH.js.map +0 -1
  37. package/dist/chunk-YXJPKBPV.js.map +0 -1
  38. package/dist/execute-K5B4UMUT.js +0 -13
  39. package/dist/init-W4HBLW7R.js +0 -9
  40. package/dist/plan-NKPU45NP.js +0 -15
  41. package/dist/pr-JYGLLIEF.js +0 -15
  42. package/dist/pr-review-6H6F4XUY.js +0 -15
  43. package/dist/prd-FC2ZCEOX.js +0 -15
  44. package/dist/review-X4NGDZZI.js +0 -13
  45. /package/dist/{analyze-WRFFG2R5.js.map → analyze-R25HDGBJ.js.map} +0 -0
  46. /package/dist/{chunk-EWMSQQL2.js.map → chunk-23WOEBGN.js.map} +0 -0
  47. /package/dist/{chunk-75K5IKAC.js.map → chunk-ASMCLXQ2.js.map} +0 -0
  48. /package/dist/{chunk-JV7P6UGG.js.map → chunk-EHVKXFFN.js.map} +0 -0
  49. /package/dist/{chunk-UX6YAVLT.js.map → chunk-HJ7JT777.js.map} +0 -0
  50. /package/dist/{chunk-HS4QWZAO.js.map → chunk-RN2FAMUU.js.map} +0 -0
  51. /package/dist/{chunk-KUDAY57D.js.map → chunk-TCOS2KFB.js.map} +0 -0
  52. /package/dist/{chunk-CW6UE3NW.js.map → chunk-WHIBTNYI.js.map} +0 -0
  53. /package/dist/{chunk-VLSZFMLZ.js.map → chunk-YLXPLHEL.js.map} +0 -0
  54. /package/dist/{chunk-BTBSVBE3.js.map → chunk-ZAEBDO3Q.js.map} +0 -0
  55. /package/dist/{config-UHQ6XXX2.js.map → config-SJAQMFWB.js.map} +0 -0
  56. /package/dist/{execute-K5B4UMUT.js.map → execute-VZ7SHLP4.js.map} +0 -0
  57. /package/dist/{generate-DUKQCADD.js.map → generate-LUK3XTIP.js.map} +0 -0
  58. /package/dist/{init-W4HBLW7R.js.map → init-5KXCG36P.js.map} +0 -0
  59. /package/dist/{plan-NKPU45NP.js.map → plan-R34SAWRK.js.map} +0 -0
  60. /package/dist/{pr-JYGLLIEF.js.map → pr-P4BDQXUQ.js.map} +0 -0
  61. /package/dist/{pr-review-6H6F4XUY.js.map → pr-review-TOSBE6ZS.js.map} +0 -0
  62. /package/dist/{prd-FC2ZCEOX.js.map → prd-RYLULM75.js.map} +0 -0
  63. /package/dist/{review-X4NGDZZI.js.map → review-ZSC5ELQA.js.map} +0 -0
  64. /package/dist/{run-VC647DQI.js.map → run-SDRQDMSZ.js.map} +0 -0
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runInit
4
+ } from "./chunk-YLXPLHEL.js";
5
+ import "./chunk-JNEHVQH5.js";
6
+ export {
7
+ runInit
8
+ };
9
+ //# sourceMappingURL=init-5KXCG36P.js.map
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPlan
4
+ } from "./chunk-ASMCLXQ2.js";
5
+ import "./chunk-EHVKXFFN.js";
6
+ import "./chunk-RN2FAMUU.js";
7
+ import "./chunk-HDV3YDTG.js";
8
+ import "./chunk-TCOS2KFB.js";
9
+ import "./chunk-SLHZPB3C.js";
10
+ import "./chunk-2AVZZAC6.js";
11
+ import "./chunk-JNEHVQH5.js";
12
+ export {
13
+ runPlan
14
+ };
15
+ //# sourceMappingURL=plan-R34SAWRK.js.map
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPr
4
+ } from "./chunk-HJ7JT777.js";
5
+ import "./chunk-EHVKXFFN.js";
6
+ import "./chunk-RN2FAMUU.js";
7
+ import "./chunk-HDV3YDTG.js";
8
+ import "./chunk-TCOS2KFB.js";
9
+ import "./chunk-SLHZPB3C.js";
10
+ import "./chunk-2AVZZAC6.js";
11
+ import "./chunk-JNEHVQH5.js";
12
+ export {
13
+ runPr
14
+ };
15
+ //# sourceMappingURL=pr-P4BDQXUQ.js.map
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ exitCodeFor,
4
+ runPrReview
5
+ } from "./chunk-23WOEBGN.js";
6
+ import "./chunk-WHIBTNYI.js";
7
+ import "./chunk-TCOS2KFB.js";
8
+ import "./chunk-SLHZPB3C.js";
9
+ import "./chunk-2AVZZAC6.js";
10
+ import "./chunk-JNEHVQH5.js";
11
+ export {
12
+ exitCodeFor,
13
+ runPrReview
14
+ };
15
+ //# sourceMappingURL=pr-review-TOSBE6ZS.js.map
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPrd
4
+ } from "./chunk-ZAEBDO3Q.js";
5
+ import "./chunk-EHVKXFFN.js";
6
+ import "./chunk-RN2FAMUU.js";
7
+ import "./chunk-HDV3YDTG.js";
8
+ import "./chunk-TCOS2KFB.js";
9
+ import "./chunk-SLHZPB3C.js";
10
+ import "./chunk-2AVZZAC6.js";
11
+ import "./chunk-JNEHVQH5.js";
12
+ export {
13
+ runPrd
14
+ };
15
+ //# sourceMappingURL=prd-RYLULM75.js.map
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runReview
4
+ } from "./chunk-EM43T462.js";
5
+ import "./chunk-RN2FAMUU.js";
6
+ import "./chunk-TCOS2KFB.js";
7
+ import "./chunk-SLHZPB3C.js";
8
+ import "./chunk-2AVZZAC6.js";
9
+ import "./chunk-JNEHVQH5.js";
10
+ export {
11
+ runReview
12
+ };
13
+ //# sourceMappingURL=review-ZSC5ELQA.js.map
@@ -1,40 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runPrd
4
- } from "./chunk-BTBSVBE3.js";
4
+ } from "./chunk-ZAEBDO3Q.js";
5
5
  import {
6
6
  runReview
7
- } from "./chunk-Z3UIGLZG.js";
7
+ } from "./chunk-EM43T462.js";
8
8
  import {
9
9
  runInit
10
- } from "./chunk-VLSZFMLZ.js";
10
+ } from "./chunk-YLXPLHEL.js";
11
11
  import {
12
12
  printRunSummary,
13
13
  runExecute
14
- } from "./chunk-YXJPKBPV.js";
14
+ } from "./chunk-YGEWIEAI.js";
15
15
  import {
16
16
  runPlan
17
- } from "./chunk-75K5IKAC.js";
17
+ } from "./chunk-ASMCLXQ2.js";
18
18
  import {
19
19
  runPr
20
- } from "./chunk-UX6YAVLT.js";
21
- import "./chunk-JV7P6UGG.js";
20
+ } from "./chunk-HJ7JT777.js";
21
+ import "./chunk-EHVKXFFN.js";
22
22
  import {
23
23
  getProvider,
24
24
  resolveCommandIssue
25
- } from "./chunk-HS4QWZAO.js";
25
+ } from "./chunk-RN2FAMUU.js";
26
26
  import "./chunk-HDV3YDTG.js";
27
27
  import {
28
28
  mostRecent,
29
29
  prReviewDir,
30
30
  readPrReviewIndex,
31
31
  runPrReview
32
- } from "./chunk-EWMSQQL2.js";
32
+ } from "./chunk-23WOEBGN.js";
33
33
  import {
34
34
  listPullRequests,
35
35
  publishGitState
36
- } from "./chunk-CW6UE3NW.js";
37
- import "./chunk-KUDAY57D.js";
36
+ } from "./chunk-WHIBTNYI.js";
37
+ import "./chunk-TCOS2KFB.js";
38
38
  import {
39
39
  resolvePackageDir
40
40
  } from "./chunk-SLHZPB3C.js";
@@ -42,7 +42,7 @@ import {
42
42
  getIssueDir,
43
43
  loadIssuesConfig,
44
44
  loadWebConfig
45
- } from "./chunk-OVFYJLOH.js";
45
+ } from "./chunk-2AVZZAC6.js";
46
46
  import {
47
47
  FilePublisher,
48
48
  NullPublisher,
@@ -56,7 +56,7 @@ import {
56
56
  setOutputCallback,
57
57
  setSessionPublisher,
58
58
  setStoryUpdateCallback
59
- } from "./chunk-2Y3UO7H2.js";
59
+ } from "./chunk-JNEHVQH5.js";
60
60
 
61
61
  // src/commands/run.ts
62
62
  import { randomUUID } from "crypto";
@@ -869,4 +869,4 @@ async function runPipelinePhases(issueNumber, issueDir, mode, publisher, from, n
869
869
  export {
870
870
  runPipeline
871
871
  };
872
- //# sourceMappingURL=run-VC647DQI.js.map
872
+ //# sourceMappingURL=run-SDRQDMSZ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issue-flow",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,8 +7,8 @@ You are an autonomous coding agent working on a software project.
7
7
  1. Read the PRD at `__PRD_FILE__`
8
8
  2. Read the progress log at `__PROGRESS_FILE__` (check Codebase Patterns section first)
9
9
  3. Check you're on the correct branch from PRD `branchName`. If not, check it out or create from main.
10
- 4. Treat the issue as unresolved unless **every** `userStories[].passes` value is `true`
11
- 5. Pick the **highest priority** user story where `passes: false`
10
+ 4. Treat the issue as unresolved if **any** `userStories[].passes` is `false`, **or** if the PRD's top-level `lastReviewFindings` is non-null — that second condition holds even when every story already passes (see "Correction Findings from a Failed Review" below).
11
+ 5. If `lastReviewFindings` is non-null, address it first (see below); otherwise pick the **highest priority** user story where `passes: false`
12
12
  6. Implement that single user story
13
13
  7. Run quality checks (e.g., typecheck, lint, test - use whatever your project requires)
14
14
  8. Update CLAUDE.md files if you discover reusable patterns (see below)
@@ -16,6 +16,18 @@ You are an autonomous coding agent working on a software project.
16
16
  10. Update the PRD to set `passes: true` for the completed story
17
17
  11. Append your progress to `__PROGRESS_FILE__`
18
18
 
19
+ ## Correction Findings from a Failed Review
20
+
21
+ A prior automated review may have already run against this same code and found it wanting — its findings are persisted verbatim in the PRD's top-level `lastReviewFindings` field. When that field is non-null:
22
+
23
+ - Treat it as **the** priority for this iteration, ahead of any story whose `passes` is still `false`.
24
+ - The findings describe concrete defects in code that was already implemented and marked `passes: true` — they are not a new story. Do **not** re-implement stories from scratch; make the smallest correct change that addresses every finding.
25
+ - Run the project's quality checks (typecheck, lint, test) to confirm the fix, exactly as for a normal story.
26
+ - Commit the fix with message `fix: address review findings` (or a more specific message naming what was fixed).
27
+ - Once every finding has been addressed, set `lastReviewFindings` back to `null` in the PRD before finishing this iteration. Leaving it non-null means the orchestrator will treat the issue as still uncorrected and loop again.
28
+ - If a finding turns out to be a false positive or already fixed, still clear `lastReviewFindings` to `null`, but say so explicitly in the progress log entry so a human can double-check.
29
+ - If you cannot fully resolve the findings in this iteration, leave `lastReviewFindings` as-is (do not clear it) and record what you did and what remains in the progress log — the orchestrator will invoke another iteration.
30
+
19
31
  ## Progress Report Format
20
32
 
21
33
  APPEND to `__PROGRESS_FILE__` (never replace, always append):
@@ -101,9 +113,9 @@ If these fields don't exist in the task plan (older format), ignore them — the
101
113
 
102
114
  ## Stop Condition
103
115
 
104
- After completing a user story, check if ALL stories have `passes: true`.
116
+ After completing a user story or addressing `lastReviewFindings`, check if ALL stories have `passes: true` **and** `lastReviewFindings` is `null`.
105
117
 
106
- If ALL stories are complete and passing, first update the task plan metadata:
118
+ If ALL stories are complete and passing and there are no pending review findings, first update the task plan metadata:
107
119
  - Set `issueStatus` to `completed`
108
120
  - Set `completedAt` to the current ISO timestamp
109
121
  - Set `lastAttemptAt` to the current ISO timestamp
@@ -113,7 +125,7 @@ If ALL stories are complete and passing, first update the task plan metadata:
113
125
  Then reply with:
114
126
  <promise>COMPLETE</promise>
115
127
 
116
- If there are still stories with `passes: false`, end your response normally (another iteration will pick up the next story).
128
+ If there are still stories with `passes: false`, or `lastReviewFindings` is still non-null, end your response normally (another iteration will pick up the next story, or continue addressing the findings).
117
129
  If you need to stop for user guidance or another non-transient blocker, record it in top-level `lastError` and do not clear it.
118
130
 
119
131
  ## Important
package/prompts/plan.md CHANGED
@@ -31,6 +31,7 @@ Create a tasks.json file at __TASKS_PATH__ with this exact structure:
31
31
  "lastError": null,
32
32
  "correctionCycle": 0,
33
33
  "maxCorrectionCycles": 3,
34
+ "lastReviewFindings": null,
34
35
  "pipeline": {
35
36
  "analyzeCompleted": true,
36
37
  "prdCompleted": true,
package/prompts/review.md CHANGED
@@ -37,3 +37,5 @@ FINDINGS:
37
37
  </review-result>
38
38
 
39
39
  IMPORTANT: You MUST include the <review-result> block in your output.
40
+
41
+ IMPORTANT: On FAIL, these FINDINGS are saved verbatim and handed to a correction iteration that has no other context about this review session — it only sees this text. Write each finding as a self-contained, actionable defect report: name the exact file and line, describe what is wrong and why, and state (or strongly imply) what a correct fix looks like. Avoid vague findings like "tests could be improved" — either the codebase fails an acceptance criterion or a regression, or it doesn't.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/schemas.ts","../src/core/session-state.ts","../src/core/session-publisher.ts","../src/core/state-manager.ts","../src/utils/fs.ts","../src/core/verbose.ts","../src/ui/logger.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { SessionSnapshot } from './core/session-state.js';\nimport type { IssueMetadata, IssuesConfig } from './issues/types.js';\n\n/**\n * Zod schemas for validating tasks.json structure, Issue metadata, headless\n * invocation outputs, the web monitoring session snapshot and the web\n * configuration.\n */\n\nexport const userStorySchema = z.object({\n id: z.string(),\n title: z.string(),\n description: z.string(),\n acceptanceCriteria: z.array(z.string()),\n priority: z.number().int().positive(),\n passes: z.boolean(),\n notes: z.string(),\n});\n\nexport const pipelineStateSchema = z.object({\n analyzeCompleted: z.boolean().optional(),\n prdCompleted: z.boolean(),\n jsonCompleted: z.boolean(),\n executionCompleted: z.boolean(),\n reviewCompleted: z.boolean(),\n prCreated: z.boolean(),\n prReviewCompleted: z.boolean().optional(),\n});\n\n/**\n * Pull Request opened by the `pr` phase. Optional on the plan: plans written\n * before the field existed (and runs with `--no-branch`) simply omit it.\n */\nexport const pullRequestRefSchema = z.object({\n number: z.number().int().positive(),\n url: z.string(),\n headBranch: z.string(),\n createdAt: z.string(),\n});\n\nexport const prReviewRecommendationSchema = z.enum([\n 'APPROVE',\n 'APPROVE_WITH_SUGGESTIONS',\n 'REQUEST_CHANGES',\n]);\n\n/**\n * State of the opt-in `pr-review` phase. `enabled` and `rounds` carry defaults\n * so a partially written object still parses instead of invalidating the plan.\n */\nexport const prReviewStateSchema = z.object({\n enabled: z.boolean().default(false),\n pullRequestNumber: z.number().int().positive().optional(),\n rounds: z.number().int().min(0).default(0),\n lastRecommendation: prReviewRecommendationSchema.optional(),\n lastReviewedAt: z.string().optional(),\n});\n\nconst lastErrorSchema = z.object({\n category: z.string(),\n message: z.string(),\n at: z.string(),\n});\n\n/**\n * Persisted metadata for an Issue stored on disk (issues/<id>/metadata.json).\n * `satisfies` keeps this schema in lockstep with the IssueMetadata interface in\n * src/issues/types.ts — changing one without the other fails the typecheck.\n */\nexport const issueMetadataSchema = z.object({\n schemaVersion: z.literal(1),\n id: z.string().min(1),\n number: z.number().int().positive().nullable(),\n source: z.enum(['github', 'local']),\n title: z.string(),\n labels: z.array(z.string()),\n state: z.enum(['open', 'closed']),\n createdAt: z.string(),\n updatedAt: z.string(),\n contentHash: z.string(),\n remote: z\n .object({\n provider: z.enum(['github', 'local']),\n ref: z.string(),\n syncedAt: z.string(),\n syncedContentHash: z.string(),\n })\n .optional(),\n}) satisfies z.ZodType<IssueMetadata>;\n\n/**\n * tasks.json structure. Deliberately permissive: plans written by older\n * versions must keep loading, so `issueUrl` is optional (Issues with no remote\n * have no URL) and `issueNumber` accepts non-numeric local identifiers.\n */\nexport const taskPlanSchema = z.object({\n project: z.string(),\n issueNumber: z.union([z.number().int().positive(), z.string().min(1)]),\n issueUrl: z.string().optional().default(''),\n branchName: z.string(),\n noBranch: z.boolean().optional().default(false),\n description: z.string(),\n issueStatus: z.enum(['pending', 'in_progress', 'completed']),\n completedAt: z.string().nullable(),\n lastAttemptAt: z.string().nullable(),\n lastError: lastErrorSchema.nullable(),\n correctionCycle: z.number().int().min(0),\n maxCorrectionCycles: z.number().int().min(0),\n pipeline: pipelineStateSchema,\n pullRequest: pullRequestRefSchema.optional(),\n prReview: prReviewStateSchema.optional(),\n userStories: z.array(userStorySchema),\n});\n\nexport const headlessResultSchema = z.object({\n success: z.boolean(),\n result: z.string(),\n cost: z\n .object({\n inputTokens: z.number().optional(),\n outputTokens: z.number().optional(),\n })\n .nullable(),\n error: z.string().nullable(),\n});\n\nconst sessionLogEntrySchema = z.object({\n at: z.string(),\n level: z.enum(['info', 'warn', 'error']),\n message: z.string(),\n});\n\nconst sessionPhaseSchema = z.object({\n name: z.string(),\n status: z.enum(['pending', 'running', 'completed', 'failed']),\n startedAt: z.string().nullable(),\n endedAt: z.string().nullable(),\n durationSeconds: z.number().nullable(),\n error: z.string().nullable(),\n});\n\nconst sessionStorySchema = z.object({\n id: z.string(),\n title: z.string(),\n priority: z.number(),\n passes: z.boolean(),\n completedAt: z.string().nullable(),\n});\n\n/**\n * Session snapshot served by the web monitoring mode (session.json and the\n * HTTP endpoint). `satisfies` keeps this schema in lockstep with the\n * SessionSnapshot interface in src/core/session-state.ts — changing one\n * without the other fails the typecheck.\n */\nexport const sessionSnapshotSchema = z.object({\n schemaVersion: z.literal(1),\n sessionId: z.string().nullable(),\n readOnly: z.literal(true),\n capabilities: z.array(z.string()),\n issue: z.object({ number: z.number().nullable(), url: z.string().nullable() }),\n status: z.enum(['idle', 'running', 'completed', 'failed']),\n startedAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n endedAt: z.string().nullable(),\n elapsedSeconds: z.number().nullable(),\n estimatedRemainingSeconds: z.number().nullable(),\n progress: z.object({\n percent: z.number(),\n phasesCompleted: z.number(),\n phasesTotal: z.number(),\n storiesCompleted: z.number(),\n storiesTotal: z.number(),\n }),\n currentPhase: z.string().nullable(),\n currentActivity: z\n .object({\n story: z.string().nullable(),\n tool: z.string().nullable(),\n detail: z.string().nullable(),\n since: z.string(),\n })\n .nullable(),\n phases: z.array(sessionPhaseSchema),\n stories: z.array(sessionStorySchema),\n execution: z.object({\n iteration: z.number(),\n retries: z.number(),\n correctionCycle: z.number(),\n maxCorrectionCycles: z.number().nullable(),\n }),\n git: z.object({\n branch: z.string().nullable(),\n baseBranch: z.string().nullable(),\n commits: z.array(z.object({ hash: z.string(), subject: z.string() })),\n }),\n pullRequests: z.array(z.object({ number: z.number(), url: z.string(), title: z.string() })),\n logs: z.array(sessionLogEntrySchema),\n errors: z.array(sessionLogEntrySchema),\n warnings: z.array(sessionLogEntrySchema),\n lastError: z.object({ message: z.string(), at: z.string() }).nullable(),\n nextSteps: z.array(z.string()),\n environment: z.object({ node: z.string(), platform: z.string() }).nullable(),\n}) satisfies z.ZodType<SessionSnapshot>;\n\n/**\n * Resolved web monitoring configuration. Every field has a default, so\n * parsing a partial object (e.g. the `web` key of .issue-flow.json) fills in\n * the documented defaults.\n */\nexport const webConfigSchema = z.object({\n enabled: z.boolean().default(false),\n port: z.number().int().min(1).max(65535).default(3737),\n host: z.string().min(1).default('0.0.0.0'),\n refreshSeconds: z.number().positive().default(5),\n logLimit: z.number().int().positive().default(200),\n includeLogs: z.boolean().default(true),\n});\n\n/**\n * Resolved Issue provider configuration. Every field has a default that keeps\n * the GitHub-only behaviour, so parsing an empty object yields the exact\n * behaviour of releases without the provider layer.\n */\nexport const issuesConfigSchema = z.object({\n defaultGenerateTarget: z.enum(['github', 'local', 'both']).default('github'),\n preferredProvider: z.enum(['github', 'local']).default('github'),\n conflictPolicy: z.enum(['ask', 'prefer-local', 'prefer-github']).default('ask'),\n requireConfirmation: z.boolean().default(true),\n}) satisfies z.ZodType<IssuesConfig>;\n\n/**\n * Resolved `pr-review` configuration (the `prReview` key of .issue-flow.json).\n *\n * `publisher` selects the implementation `createPrReviewPublisher()` builds. v1\n * ships only the local one, so the enum has a single member on purpose: adding\n * a GitHub adapter is a new entry here plus a new factory, never a change to\n * the phase.\n */\nexport const prReviewConfigSchema = z.object({\n publisher: z.enum(['local']).default('local'),\n});\n\nexport type ValidatedTaskPlan = z.infer<typeof taskPlanSchema>;\nexport type ValidatedIssueMetadata = z.infer<typeof issueMetadataSchema>;\nexport type ValidatedHeadlessResult = z.infer<typeof headlessResultSchema>;\nexport type ValidatedSessionSnapshot = z.infer<typeof sessionSnapshotSchema>;\nexport type WebConfig = z.infer<typeof webConfigSchema>;\nexport type PrReviewConfig = z.infer<typeof prReviewConfigSchema>;\n","import { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { stripVTControlCharacters } from 'node:util';\nimport type { UserStory } from '../types.js';\n\n/**\n * Session state publishing layer for the optional web monitoring mode.\n *\n * Instrumentation points call publish() with SessionEvents; a pure reducer\n * folds each event into an in-memory SessionSnapshot that any surface\n * (file, HTTP endpoint, future webhooks) can consume in a single format.\n *\n * Monitoring must never affect the pipeline: publish() is synchronous and\n * never throws, and all publisher I/O failures are swallowed after a\n * single warning.\n */\n\nexport type SessionLogLevel = 'info' | 'warn' | 'error';\nexport type SessionStatus = 'idle' | 'running' | 'completed' | 'failed';\nexport type SessionPhaseStatus = 'pending' | 'running' | 'completed' | 'failed';\n\n/** Default max entries retained in the logs ring buffer. */\nexport const DEFAULT_LOG_LIMIT = 200;\n\n/** Default minimum interval between FilePublisher disk writes. */\nexport const DEFAULT_THROTTLE_MS = 1000;\n\nexport type SessionEvent =\n | {\n type: 'session:start';\n at: string;\n sessionId: string;\n /** `null` for local identifiers that are not numbers. */\n issueNumber: number | null;\n issueUrl?: string;\n branch?: string;\n baseBranch?: string;\n phases: string[];\n environment?: SessionEnvironment;\n }\n | { type: 'phase:start'; at: string; phase: string }\n | { type: 'phase:end'; at: string; phase: string; success: boolean; error?: string }\n | { type: 'iteration:start'; at: string; iteration: number }\n | { type: 'iteration:end'; at: string; iteration: number }\n | { type: 'retry'; at: string; attempt: number; delaySeconds?: number; reason?: string }\n | { type: 'stories:update'; at: string; stories: UserStory[] }\n | { type: 'activity'; at: string; story?: string; tool?: string; detail?: string }\n | { type: 'log'; at: string; level: SessionLogLevel; message: string }\n | { type: 'correction:cycle'; at: string; cycle: number; maxCycles: number }\n | {\n type: 'git:update';\n at: string;\n branch?: string;\n baseBranch?: string;\n commits?: SessionCommit[];\n pullRequests?: SessionPullRequest[];\n }\n | { type: 'session:end'; at: string; status: 'completed' | 'failed'; error?: string };\n\nexport interface SessionEnvironment {\n node: string;\n platform: string;\n}\n\nexport interface SessionLogEntry {\n at: string;\n level: SessionLogLevel;\n message: string;\n}\n\nexport interface SessionPhaseSnapshot {\n name: string;\n status: SessionPhaseStatus;\n startedAt: string | null;\n endedAt: string | null;\n durationSeconds: number | null;\n error: string | null;\n}\n\nexport interface SessionStorySnapshot {\n id: string;\n title: string;\n priority: number;\n passes: boolean;\n /**\n * When the story flipped to passing during this session; null for stories\n * that were already passing at session start (their duration is unknown).\n */\n completedAt: string | null;\n}\n\nexport interface SessionActivity {\n story: string | null;\n tool: string | null;\n detail: string | null;\n since: string;\n}\n\nexport interface SessionCommit {\n hash: string;\n subject: string;\n}\n\nexport interface SessionPullRequest {\n number: number;\n url: string;\n title: string;\n}\n\nexport interface SessionSnapshot {\n schemaVersion: 1;\n sessionId: string | null;\n readOnly: true;\n capabilities: string[];\n issue: { number: number | null; url: string | null };\n status: SessionStatus;\n startedAt: string | null;\n updatedAt: string | null;\n endedAt: string | null;\n elapsedSeconds: number | null;\n estimatedRemainingSeconds: number | null;\n progress: {\n percent: number;\n phasesCompleted: number;\n phasesTotal: number;\n storiesCompleted: number;\n storiesTotal: number;\n };\n currentPhase: string | null;\n currentActivity: SessionActivity | null;\n phases: SessionPhaseSnapshot[];\n stories: SessionStorySnapshot[];\n execution: {\n iteration: number;\n retries: number;\n correctionCycle: number;\n maxCorrectionCycles: number | null;\n };\n git: { branch: string | null; baseBranch: string | null; commits: SessionCommit[] };\n pullRequests: SessionPullRequest[];\n logs: SessionLogEntry[];\n errors: SessionLogEntry[];\n warnings: SessionLogEntry[];\n lastError: { message: string; at: string } | null;\n nextSteps: string[];\n environment: SessionEnvironment | null;\n}\n\nexport interface SessionReducerOptions {\n /** Max entries retained in the logs ring buffer. */\n logLimit?: number;\n}\n\nexport function createInitialSnapshot(): SessionSnapshot {\n return {\n schemaVersion: 1,\n sessionId: null,\n readOnly: true,\n capabilities: [],\n issue: { number: null, url: null },\n status: 'idle',\n startedAt: null,\n updatedAt: null,\n endedAt: null,\n elapsedSeconds: null,\n estimatedRemainingSeconds: null,\n progress: {\n percent: 0,\n phasesCompleted: 0,\n phasesTotal: 0,\n storiesCompleted: 0,\n storiesTotal: 0,\n },\n currentPhase: null,\n currentActivity: null,\n phases: [],\n stories: [],\n execution: { iteration: 0, retries: 0, correctionCycle: 0, maxCorrectionCycles: null },\n git: { branch: null, baseBranch: null, commits: [] },\n pullRequests: [],\n logs: [],\n errors: [],\n warnings: [],\n lastError: null,\n nextSteps: [],\n environment: null,\n };\n}\n\n/**\n * Seconds between two ISO timestamps, or null when either is unparsable.\n */\nfunction secondsBetween(from: string | null, to: string): number | null {\n if (from === null) return null;\n const fromMs = Date.parse(from);\n const toMs = Date.parse(to);\n if (Number.isNaN(fromMs) || Number.isNaN(toMs)) return null;\n return Math.max(0, Math.round((toMs - fromMs) / 1000));\n}\n\nfunction computePercent(phasesCompleted: number, phasesTotal: number): number {\n if (phasesTotal === 0) return 0;\n return Math.round((phasesCompleted / phasesTotal) * 100);\n}\n\n/**\n * Estimated seconds until all stories pass: average duration of the stories\n * completed during this session × pending stories. Durations are the gaps\n * between consecutive completions (the first is measured from startedAt).\n * Published as null with fewer than two samples.\n */\nfunction estimateRemainingSeconds(snapshot: SessionSnapshot): number | null {\n const completions = snapshot.stories\n .map((story) => (story.completedAt === null ? Number.NaN : Date.parse(story.completedAt)))\n .filter((ms) => !Number.isNaN(ms))\n .sort((a, b) => a - b);\n if (completions.length < 2) return null;\n\n const startMs = snapshot.startedAt === null ? Number.NaN : Date.parse(snapshot.startedAt);\n const boundaries = Number.isNaN(startMs) ? completions : [startMs, ...completions];\n const durations: number[] = [];\n for (let i = 1; i < boundaries.length; i++) {\n durations.push(Math.max(0, boundaries[i] - boundaries[i - 1]));\n }\n if (durations.length === 0) return null;\n\n const averageMs = durations.reduce((sum, d) => sum + d, 0) / durations.length;\n const pending = snapshot.stories.filter((story) => !story.passes).length;\n return Math.round((averageMs * pending) / 1000);\n}\n\n/**\n * Remaining pipeline phases, in order. The phase list originates from the\n * session:start event, whose caller passes PIPELINE_PHASES (or\n * PIPELINE_PHASES_NO_BRANCH in --no-branch mode) from src/core/pipeline.ts.\n */\nfunction deriveNextSteps(snapshot: SessionSnapshot): string[] {\n if (snapshot.status === 'completed') return [];\n return snapshot.phases.filter((phase) => phase.status === 'pending').map((phase) => phase.name);\n}\n\n/**\n * Fold a SessionEvent into a SessionSnapshot. Pure: never mutates the input\n * and performs no I/O. Unknown event types return the snapshot unchanged.\n *\n * errors/warnings are derived slices of the logs ring buffer, recomputed on\n * each reduction — they are never accumulated separately. The same applies\n * to estimatedRemainingSeconds and nextSteps.\n */\nexport function reduceSessionEvent(\n snapshot: SessionSnapshot,\n event: SessionEvent,\n options?: SessionReducerOptions,\n): SessionSnapshot {\n const next = applyEvent(snapshot, event, options);\n if (next === snapshot) return snapshot;\n\n const elapsedSeconds = secondsBetween(next.startedAt, event.at) ?? next.elapsedSeconds;\n return {\n ...next,\n updatedAt: event.at,\n elapsedSeconds,\n estimatedRemainingSeconds: estimateRemainingSeconds(next),\n errors: next.logs.filter((entry) => entry.level === 'error'),\n warnings: next.logs.filter((entry) => entry.level === 'warn'),\n nextSteps: deriveNextSteps(next),\n };\n}\n\nfunction applyEvent(\n snapshot: SessionSnapshot,\n event: SessionEvent,\n options?: SessionReducerOptions,\n): SessionSnapshot {\n switch (event.type) {\n case 'session:start': {\n const initial = createInitialSnapshot();\n return {\n ...initial,\n sessionId: event.sessionId,\n issue: { number: event.issueNumber, url: event.issueUrl ?? null },\n status: 'running',\n startedAt: event.at,\n progress: {\n ...initial.progress,\n phasesTotal: event.phases.length,\n },\n phases: event.phases.map((name) => ({\n name,\n status: 'pending' as const,\n startedAt: null,\n endedAt: null,\n durationSeconds: null,\n error: null,\n })),\n git: { branch: event.branch ?? null, baseBranch: event.baseBranch ?? null, commits: [] },\n environment: event.environment ?? null,\n };\n }\n\n case 'phase:start': {\n const known = snapshot.phases.some((p) => p.name === event.phase);\n const phases = known\n ? snapshot.phases.map((p) =>\n p.name === event.phase\n ? {\n ...p,\n status: 'running' as const,\n startedAt: event.at,\n endedAt: null,\n error: null,\n }\n : p,\n )\n : [\n ...snapshot.phases,\n {\n name: event.phase,\n status: 'running' as const,\n startedAt: event.at,\n endedAt: null,\n durationSeconds: null,\n error: null,\n },\n ];\n return {\n ...snapshot,\n currentPhase: event.phase,\n phases,\n progress: known ? snapshot.progress : { ...snapshot.progress, phasesTotal: phases.length },\n };\n }\n\n case 'phase:end': {\n const phases = snapshot.phases.map((p) =>\n p.name === event.phase\n ? {\n ...p,\n status: event.success ? ('completed' as const) : ('failed' as const),\n endedAt: event.at,\n durationSeconds: secondsBetween(p.startedAt, event.at),\n error: event.error ? stripVTControlCharacters(event.error) : null,\n }\n : p,\n );\n const phasesCompleted = phases.filter((p) => p.status === 'completed').length;\n return {\n ...snapshot,\n currentPhase: snapshot.currentPhase === event.phase ? null : snapshot.currentPhase,\n currentActivity: null,\n phases,\n progress: {\n ...snapshot.progress,\n phasesCompleted,\n percent: computePercent(phasesCompleted, snapshot.progress.phasesTotal),\n },\n };\n }\n\n case 'iteration:start':\n return {\n ...snapshot,\n execution: { ...snapshot.execution, iteration: event.iteration },\n };\n\n case 'iteration:end':\n return { ...snapshot, currentActivity: null };\n\n case 'retry':\n return {\n ...snapshot,\n execution: { ...snapshot.execution, retries: snapshot.execution.retries + 1 },\n };\n\n case 'stories:update': {\n const previous = new Map(snapshot.stories.map((story) => [story.id, story]));\n const stories = event.stories.map((story) => {\n const before = previous.get(story.id);\n // Stamp the flip to passing; stories already passing when first seen\n // keep null (completed before this session, duration unknown).\n const completedAt = !story.passes\n ? null\n : before && !before.passes\n ? event.at\n : (before?.completedAt ?? null);\n return {\n id: story.id,\n title: story.title,\n priority: story.priority,\n passes: story.passes,\n completedAt,\n };\n });\n return {\n ...snapshot,\n stories,\n progress: {\n ...snapshot.progress,\n storiesCompleted: stories.filter((s) => s.passes).length,\n storiesTotal: stories.length,\n },\n };\n }\n\n case 'activity': {\n const story = event.story ?? null;\n const tool = event.tool ?? null;\n const detail = event.detail ?? null;\n const current = snapshot.currentActivity;\n // Same activity repeated: keep `since` so the UI can show \"for how long\".\n const since =\n current && current.story === story && current.tool === tool && current.detail === detail\n ? current.since\n : event.at;\n return { ...snapshot, currentActivity: { story, tool, detail, since } };\n }\n\n case 'log': {\n const limit = options?.logLimit ?? DEFAULT_LOG_LIMIT;\n const entry: SessionLogEntry = {\n at: event.at,\n level: event.level,\n message: stripVTControlCharacters(event.message),\n };\n const logs = [...snapshot.logs, entry].slice(-Math.max(1, limit));\n return { ...snapshot, logs };\n }\n\n case 'git:update':\n return {\n ...snapshot,\n git: {\n branch: event.branch ?? snapshot.git.branch,\n baseBranch: event.baseBranch ?? snapshot.git.baseBranch,\n commits: event.commits ?? snapshot.git.commits,\n },\n pullRequests: event.pullRequests ?? snapshot.pullRequests,\n };\n\n case 'correction:cycle':\n return {\n ...snapshot,\n execution: {\n ...snapshot.execution,\n correctionCycle: event.cycle,\n maxCorrectionCycles: event.maxCycles,\n },\n };\n\n case 'session:end':\n return {\n ...snapshot,\n status: event.status,\n endedAt: event.at,\n currentPhase: null,\n currentActivity: null,\n lastError: event.error\n ? { message: stripVTControlCharacters(event.error), at: event.at }\n : snapshot.lastError,\n };\n\n default:\n return snapshot;\n }\n}\n\nexport interface SessionPublisher {\n /**\n * Publish an event. Synchronous, never throws, never returns a promise —\n * safe to call from any instrumentation point without affecting execution.\n */\n publish(event: SessionEvent): void;\n /** Current in-memory snapshot. */\n snapshot(): SessionSnapshot;\n /** Monotonic counter, bumped on every applied event (basis for ETags). */\n version(): number;\n /** Force any pending output to be written. Never rejects. */\n flush(): Promise<void>;\n /** Flush and release resources. Never rejects. */\n close(): Promise<void>;\n}\n\n/**\n * Default publisher when monitoring is off: every call is a no-op, so each\n * instrumentation point costs a method call that returns immediately.\n */\nexport class NullPublisher implements SessionPublisher {\n private readonly empty = createInitialSnapshot();\n\n publish(_event: SessionEvent): void {}\n\n snapshot(): SessionSnapshot {\n return this.empty;\n }\n\n version(): number {\n return 0;\n }\n\n async flush(): Promise<void> {}\n\n async close(): Promise<void> {}\n}\n\nexport interface MemoryPublisherOptions extends SessionReducerOptions {\n /** Called at most once, on the first internal failure. */\n onWarn?: (message: string) => void;\n /**\n * When false, log events are dropped before reaching the snapshot, so no\n * log line is ever published (session.json or HTTP). Default true.\n */\n includeLogs?: boolean;\n}\n\n/**\n * In-memory publisher: reduces events over a snapshot and tracks a monotonic\n * version. Base class for publishers with an output surface (file, HTTP).\n */\nexport class MemoryPublisher implements SessionPublisher {\n protected state: SessionSnapshot = createInitialSnapshot();\n protected versionCounter = 0;\n private warned = false;\n private readonly onWarn: (message: string) => void;\n private readonly reducerOptions: SessionReducerOptions;\n private readonly includeLogs: boolean;\n\n constructor(options: MemoryPublisherOptions = {}) {\n this.onWarn = options.onWarn ?? ((message) => process.stderr.write(`${message}\\n`));\n this.reducerOptions = { logLimit: options.logLimit };\n this.includeLogs = options.includeLogs ?? true;\n }\n\n publish(event: SessionEvent): void {\n if (event.type === 'log' && !this.includeLogs) return;\n try {\n this.state = reduceSessionEvent(this.state, event, this.reducerOptions);\n this.versionCounter++;\n this.afterPublish(event);\n } catch (err) {\n this.warnOnce(err);\n }\n }\n\n /** Hook for subclasses; runs inside publish()'s try/catch. */\n protected afterPublish(_event: SessionEvent): void {}\n\n snapshot(): SessionSnapshot {\n return this.state;\n }\n\n version(): number {\n return this.versionCounter;\n }\n\n async flush(): Promise<void> {}\n\n async close(): Promise<void> {}\n\n protected warnOnce(err: unknown): void {\n if (this.warned) return;\n this.warned = true;\n const message = err instanceof Error ? err.message : String(err);\n try {\n this.onWarn(\n `issue-flow: web monitoring hit an error (will keep retrying silently): ${message}`,\n );\n } catch {\n // Even a failing warn callback must not propagate to the pipeline.\n }\n }\n}\n\nexport interface FilePublisherOptions extends MemoryPublisherOptions {\n /** Minimum interval between disk writes (ms). Default 1000. */\n throttleMs?: number;\n}\n\n/**\n * Publisher that mirrors the snapshot to issues/N/session.json.\n *\n * Writes are atomic (write-to-temp + rename) and throttled; terminal events\n * (phase:end, session:end) force an immediate write. All I/O failures are\n * swallowed after a single warning.\n */\nexport class FilePublisher extends MemoryPublisher {\n private readonly filePath: string;\n private readonly throttleMs: number;\n private timer: NodeJS.Timeout | null = null;\n private lastWriteStartedAt = 0;\n private lastWrittenVersion = 0;\n private writeChain: Promise<void> = Promise.resolve();\n private closed = false;\n\n constructor(filePath: string, options: FilePublisherOptions = {}) {\n super(options);\n this.filePath = filePath;\n this.throttleMs = options.throttleMs ?? DEFAULT_THROTTLE_MS;\n }\n\n protected override afterPublish(event: SessionEvent): void {\n if (this.closed) return;\n const terminal = event.type === 'phase:end' || event.type === 'session:end';\n this.scheduleWrite(terminal);\n }\n\n private scheduleWrite(force: boolean): void {\n if (force) {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n this.enqueueWrite();\n return;\n }\n if (this.timer !== null) return;\n const wait = Math.max(0, this.throttleMs - (Date.now() - this.lastWriteStartedAt));\n if (wait === 0) {\n this.enqueueWrite();\n return;\n }\n this.timer = setTimeout(() => {\n this.timer = null;\n this.enqueueWrite();\n }, wait);\n this.timer.unref();\n }\n\n private enqueueWrite(): void {\n this.lastWriteStartedAt = Date.now();\n this.writeChain = this.writeChain.then(async () => {\n const version = this.versionCounter;\n if (version === this.lastWrittenVersion) return;\n const payload = `${JSON.stringify(this.state, null, 2)}\\n`;\n try {\n await atomicWriteFile(this.filePath, payload);\n this.lastWrittenVersion = version;\n } catch (err) {\n this.warnOnce(err);\n }\n });\n }\n\n override async flush(): Promise<void> {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n if (this.versionCounter !== this.lastWrittenVersion) {\n this.enqueueWrite();\n }\n await this.writeChain;\n }\n\n override async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n }\n}\n\n/**\n * Atomic write: write to a temp file next to the target, then rename. The\n * same-directory temp keeps the rename on a single filesystem (rename is\n * atomic; no EXDEV fallback needed, unlike an os.tmpdir() temp on Linux\n * tmpfs) and leaves nothing behind. The FilePublisher write chain is the\n * single writer, so the fixed .tmp name never races.\n *\n * The target directory (issues/N/) may not exist yet the first time a fresh\n * issue publishes — pipeline phases create it lazily, and this can be the\n * very first write. mkdir recursive is idempotent, so it's cheap to ensure\n * on every write rather than relying on call order elsewhere.\n */\nasync function atomicWriteFile(path: string, content: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpFile = `${path}.tmp`;\n await writeFile(tmpFile, content, 'utf-8');\n await rename(tmpFile, path);\n}\n","import { NullPublisher, type SessionPublisher } from './session-state.js';\n\n/**\n * Global slot for the active SessionPublisher, following the same pattern as\n * setVerbose in verbose.ts. Instrumentation points (logger, engine, headless)\n * read the slot via getSessionPublisher(); run.ts installs a FilePublisher\n * when web monitoring is enabled. The default NullPublisher makes every\n * instrumentation point a no-op when monitoring is off.\n */\n\nconst NULL_PUBLISHER = new NullPublisher();\n\nlet _publisher: SessionPublisher = NULL_PUBLISHER;\n\n/**\n * Install the active session publisher. Pass undefined to reset to the\n * default NullPublisher.\n */\nexport function setSessionPublisher(publisher: SessionPublisher | undefined): void {\n _publisher = publisher ?? NULL_PUBLISHER;\n}\n\nexport function getSessionPublisher(): SessionPublisher {\n return _publisher;\n}\n","import { readFile } from 'node:fs/promises';\nimport { ZodError } from 'zod';\nimport { taskPlanSchema } from '../schemas.js';\nimport type { LastError, PipelineState, TaskPlan } from '../types.js';\nimport { writeFileAtomic } from '../utils/fs.js';\n\n/**\n * Get the current ISO timestamp.\n */\nexport function isoNow(): string {\n return new Date().toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * Load and parse a tasks.json file.\n * Validates that it has the expected structure.\n */\nexport async function loadTaskPlan(path: string): Promise<TaskPlan> {\n const content = await readFile(path, 'utf-8');\n const raw = JSON.parse(content);\n\n try {\n return taskPlanSchema.parse(raw) as TaskPlan;\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 tasks.json at ${path}:\\n${issues}`);\n }\n throw err;\n }\n}\n\n/**\n * Save a TaskPlan to disk atomically (write-to-temp + rename).\n * This prevents corruption if the process is interrupted during write.\n */\nexport async function saveTaskPlan(path: string, plan: TaskPlan): Promise<void> {\n await writeFileAtomic(path, `${JSON.stringify(plan, null, 2)}\\n`);\n}\n\n/**\n * Initialize default state fields on a TaskPlan.\n * Fills in missing fields with defaults, matching the Bash script behavior.\n *\n * The opt-in fields (`pullRequest`, `prReview`, `pipeline.prReviewCompleted`)\n * are deliberately absent from the defaults: they ride along on the spread when\n * present and stay out of the file entirely when the phases never ran.\n */\nexport function initializeState(plan: TaskPlan): TaskPlan {\n const defaultPipeline: PipelineState = {\n prdCompleted: false,\n jsonCompleted: false,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n };\n\n return {\n ...plan,\n issueStatus: plan.issueStatus ?? 'pending',\n completedAt: plan.completedAt ?? null,\n lastAttemptAt: plan.lastAttemptAt ?? null,\n lastError: plan.lastError ?? null,\n correctionCycle: plan.correctionCycle ?? 0,\n maxCorrectionCycles: plan.maxCorrectionCycles ?? 3,\n pipeline: plan.pipeline ? { ...defaultPipeline, ...plan.pipeline } : defaultPipeline,\n };\n}\n\n/**\n * Check if all user stories have passes=true.\n * Returns false if there are no stories.\n */\nexport function allStoriesPass(plan: TaskPlan): boolean {\n if (plan.userStories.length === 0) {\n return false;\n }\n\n return plan.userStories.every((story) => story.passes === true);\n}\n\n/**\n * Mark a specific story as passing.\n */\nexport function markStoryPassing(plan: TaskPlan, storyId: string): TaskPlan {\n return {\n ...plan,\n userStories: plan.userStories.map((story) =>\n story.id === storyId ? { ...story, passes: true } : story,\n ),\n };\n}\n\n/**\n * Mark the issue as in_progress.\n */\nexport function markIssueInProgress(plan: TaskPlan, timestamp?: string): TaskPlan {\n const ts = timestamp ?? isoNow();\n return {\n ...plan,\n issueStatus: 'in_progress',\n completedAt: null,\n lastAttemptAt: ts,\n };\n}\n\n/**\n * Mark the issue as completed.\n */\nexport function markIssueCompleted(plan: TaskPlan): TaskPlan {\n const ts = isoNow();\n return {\n ...plan,\n issueStatus: 'completed',\n completedAt: ts,\n lastAttemptAt: ts,\n lastError: null,\n pipeline: plan.pipeline ? { ...plan.pipeline, executionCompleted: true } : plan.pipeline,\n };\n}\n\n/**\n * Set the lastError field on the task plan.\n */\nexport function setLastError(plan: TaskPlan, category: string, message: string): TaskPlan {\n const ts = isoNow();\n const error: LastError = {\n category,\n message,\n at: ts,\n };\n\n return {\n ...plan,\n lastAttemptAt: ts,\n lastError: error,\n };\n}\n\n/**\n * Clear the lastError field, but only if it was set before the attempt started.\n * This prevents clearing errors that were set during the current attempt.\n */\nexport function clearLastError(plan: TaskPlan, attemptStartedAt: string): TaskPlan {\n const ts = isoNow();\n\n // If the error was set after the attempt started, keep it\n if (plan.lastError && plan.lastError.at > attemptStartedAt) {\n return {\n ...plan,\n lastAttemptAt: ts,\n };\n }\n\n return {\n ...plan,\n lastAttemptAt: ts,\n lastError: null,\n };\n}\n\n/**\n * Trim an error message to at most 8 non-empty lines.\n */\nexport function trimErrorMessage(message: string): string {\n return message\n .split('\\n')\n .filter((line) => line.trim().length > 0)\n .slice(0, 8)\n .join('\\n');\n}\n","import { copyFile, mkdtemp, rename, unlink, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\n\n/**\n * Write a file atomically (write-to-temp + rename).\n *\n * A crash mid-write leaves the previous content untouched instead of a\n * truncated file, which matters for every artifact the pipeline reloads on the\n * next run (tasks.json, metadata.json).\n */\nexport async function writeFileAtomic(path: string, content: string): Promise<void> {\n const tmpDir = await mkdtemp(join(tmpdir(), 'issue-flow-'));\n const tmpFile = join(tmpDir, basename(path));\n\n await writeFile(tmpFile, content, 'utf-8');\n\n try {\n await rename(tmpFile, path);\n } catch (err: unknown) {\n // EXDEV: rename fails across different devices/drives (common on Windows)\n if ((err as NodeJS.ErrnoException).code === 'EXDEV') {\n await copyFile(tmpFile, path);\n await unlink(tmpFile);\n } else {\n throw err;\n }\n }\n}\n","let _verbose = false;\n\nexport function setVerbose(enabled: boolean): void {\n _verbose = enabled;\n}\n\nexport function isVerbose(): boolean {\n return _verbose;\n}\n\nlet _onOutput: ((line: string) => void) | undefined;\n\n/**\n * Set a global output callback for routing verbose output (e.g., through listr2 task.output).\n * Pass undefined to clear and fall back to direct stderr writes.\n */\nexport function setOutputCallback(callback: ((line: string) => void) | undefined): void {\n _onOutput = callback;\n}\n\nexport function getOutputCallback(): ((line: string) => void) | undefined {\n return _onOutput;\n}\n\nlet _onStoryUpdate: ((stories: import('../types.js').UserStory[]) => void) | undefined;\n\n/**\n * Set a global callback for story progress updates during engine execution.\n * Called after each iteration with the latest user stories state.\n * Pass undefined to clear.\n */\nexport function setStoryUpdateCallback(\n callback: ((stories: import('../types.js').UserStory[]) => void) | undefined,\n): void {\n _onStoryUpdate = callback;\n}\n\nexport function getStoryUpdateCallback():\n | ((stories: import('../types.js').UserStory[]) => void)\n | undefined {\n return _onStoryUpdate;\n}\n\nlet _globalTimeout: number | undefined;\n\nexport function setGlobalTimeout(ms: number): void {\n _globalTimeout = ms;\n}\n\nexport function getGlobalTimeout(): number | undefined {\n return _globalTimeout;\n}\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\nimport { getSessionPublisher } from '../core/session-publisher.js';\nimport type { SessionLogLevel } from '../core/session-state.js';\nimport { isoNow } from '../core/state-manager.js';\nimport { getOutputCallback } from '../core/verbose.js';\n\n/**\n * Detect if unicode output is supported.\n */\nexport function useUnicode(): boolean {\n if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\n/**\n * Detect if color output is supported.\n */\nexport function useColor(): boolean {\n if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\nexport interface Icons {\n success: string;\n fail: string;\n pending: string;\n retry: string;\n warn: string;\n start: string;\n end: string;\n notReached: string;\n tool: string;\n connector: string;\n}\n\nexport function getIcons(): Icons {\n if (useUnicode()) {\n return {\n success: '\\u2713',\n fail: '\\u2717',\n pending: '\\u23F3',\n retry: '\\u21BB',\n warn: '\\u26A0',\n start: '\\u25B6',\n end: '\\u25A0',\n notReached: '\\u25CB',\n tool: '\\u25B8',\n connector: '\\u2502',\n };\n }\n return {\n success: '[OK]',\n fail: '[FAIL]',\n pending: '[...]',\n retry: '[RETRY]',\n warn: '[WARN]',\n start: '[START]',\n end: '[END]',\n notReached: '[ ]',\n tool: '>',\n connector: '|',\n };\n}\n\n/**\n * Get the terminal width.\n */\nexport function getTermWidth(): number {\n return process.stdout.columns ?? 80;\n}\n\n/**\n * Emit a line of output. Routes through the global output callback when\n * running inside a listr2 task context, otherwise falls back to console.log.\n *\n * Also forwards the line to the session publisher with its structured level;\n * ANSI codes are stripped by the reducer, so terminal output stays untouched.\n */\nfunction emit(line: string, level: SessionLogLevel = 'info'): void {\n getSessionPublisher().publish({ type: 'log', at: isoNow(), level, message: line });\n const cb = getOutputCallback();\n if (cb) {\n cb(line);\n } else {\n console.log(line);\n }\n}\n\nexport function printSuccess(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.green(`${icons.success} ${message}`));\n } else {\n emit(`${icons.success} ${message}`);\n }\n}\n\nexport function printError(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.red(`${icons.fail} ${message}`), 'error');\n } else {\n emit(`${icons.fail} ${message}`, 'error');\n }\n}\n\nexport function printWarning(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.yellow(`${icons.warn} ${message}`), 'warn');\n } else {\n emit(`${icons.warn} ${message}`, 'warn');\n }\n}\n\nexport function printRetry(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.yellow(`${icons.retry} ${message}`), 'warn');\n } else {\n emit(`${icons.retry} ${message}`, 'warn');\n }\n}\n\nexport function printInfo(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.blue(`${icons.start} ${message}`));\n } else {\n emit(`${icons.start} ${message}`);\n }\n}\n\n/**\n * Create an ora spinner with consistent styling.\n */\nexport function createSpinner(message: string): Ora {\n return ora({\n text: message,\n color: 'blue',\n spinner: 'dots',\n });\n}\n\n/**\n * Format a duration in seconds to a human-readable string.\n */\nexport function formatDuration(totalSeconds: number): string {\n const hours = Math.floor(totalSeconds / 3600);\n const mins = Math.floor((totalSeconds % 3600) / 60);\n const secs = totalSeconds % 60;\n\n if (hours > 0) {\n return `${hours}h ${mins}m ${secs}s`;\n }\n if (mins > 0) {\n return `${mins}m ${secs}s`;\n }\n return `${secs}s`;\n}\n\n/**\n * Timer that calls a callback every second with the formatted elapsed time.\n */\nexport class ElapsedTimer {\n private startTime: number;\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private cleanup = () => this.stop();\n\n constructor(private onTick: (elapsed: string) => void) {\n this.startTime = Date.now();\n }\n\n start(): this {\n this.startTime = Date.now();\n this.intervalId = setInterval(() => {\n const seconds = Math.floor((Date.now() - this.startTime) / 1000);\n this.onTick(formatDuration(seconds));\n }, 1_000);\n // Prevent the timer from keeping the process alive\n if (this.intervalId && typeof this.intervalId === 'object' && 'unref' in this.intervalId) {\n this.intervalId.unref();\n }\n process.on('exit', this.cleanup);\n return this;\n }\n\n getElapsedSeconds(): number {\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n stop(): number {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n process.removeListener('exit', this.cleanup);\n return this.getElapsedSeconds();\n }\n}\n"],"mappings":"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","names":["rename","writeFile"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config.ts","../src/utils/git.ts","../src/utils/shell.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { platform } from 'node:os';\nimport { join } from 'node:path';\nimport type { IssuesConfig } from './issues/types.js';\nimport {\n issuesConfigSchema,\n type PrReviewConfig,\n prReviewConfigSchema,\n type WebConfig,\n webConfigSchema,\n} from './schemas.js';\nimport type { EngineConfig, ResolvedPaths } from './types.js';\nimport { printWarning } from './ui/logger.js';\nimport { getProjectRoot } from './utils/git.js';\nimport { run } from './utils/shell.js';\n\n/**\n * Default configuration values — matching the Bash script exactly.\n */\nexport const DEFAULTS = {\n retryLimit: 10,\n retryForever: false,\n backoffBaseSeconds: 30,\n backoffMaxSeconds: 900,\n} as const;\n\n/**\n * Create a EngineConfig with defaults merged with provided options.\n */\nexport function createConfig(options: Partial<EngineConfig>): EngineConfig {\n return {\n issueNumber: options.issueNumber,\n maxIterations: options.maxIterations,\n retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,\n retryForever: options.retryForever ?? DEFAULTS.retryForever,\n backoffBaseSeconds: options.backoffBaseSeconds ?? DEFAULTS.backoffBaseSeconds,\n backoffMaxSeconds: options.backoffMaxSeconds ?? DEFAULTS.backoffMaxSeconds,\n };\n}\n\n/**\n * Resolve file paths based on issue number and project root.\n *\n * With --issue N:\n * prdFile = {projectRoot}/issues/{N}/tasks.json\n * progressFile = {projectRoot}/issues/{N}/progress.txt\n *\n * Standalone:\n * prdFile = {projectRoot}/prd.json\n * progressFile = {projectRoot}/progress.txt\n */\nexport async function resolvePaths(\n config: EngineConfig,\n scriptDir?: string,\n): Promise<ResolvedPaths> {\n const projectRoot = await getProjectRoot();\n\n if (config.issueNumber) {\n const issueDir = join(projectRoot, 'issues', config.issueNumber);\n return {\n prdFile: join(issueDir, 'tasks.json'),\n progressFile: join(issueDir, 'progress.txt'),\n archiveDir: join(issueDir, 'archive'),\n lastBranchFile: join(issueDir, '.last-branch'),\n projectRoot,\n };\n }\n\n // Standalone mode — use scriptDir if available, otherwise projectRoot\n const base = scriptDir ?? projectRoot;\n return {\n prdFile: join(base, 'prd.json'),\n progressFile: join(base, 'progress.txt'),\n archiveDir: join(base, 'archive'),\n lastBranchFile: join(base, '.last-branch'),\n projectRoot,\n };\n}\n\n/**\n * Return a platform-appropriate install hint for a given package.\n */\nexport function getInstallHint(pkg: string): string {\n const os = platform();\n\n if (os === 'darwin') {\n return `brew install ${pkg}`;\n }\n if (os === 'linux') {\n return `apt install ${pkg} (or your distro's package manager)`;\n }\n if (os === 'win32') {\n return `winget install ${pkg} (or choco install ${pkg})`;\n }\n\n return `install ${pkg} using your system package manager`;\n}\n\n/**\n * Validate that required external dependencies are available.\n * Returns an array of error messages (empty if all deps are found).\n */\nexport async function validateDependencies(): Promise<string[]> {\n const errors: string[] = [];\n\n // Check git\n const gitResult = await run('git', ['--version']);\n if (gitResult.exitCode !== 0) {\n errors.push(` - git (install with: ${getInstallHint('git')})`);\n }\n\n // Check claude\n const claudeResult = await run('claude', ['--version']);\n if (claudeResult.exitCode !== 0) {\n errors.push(' - claude (install with: npm install -g @anthropic-ai/claude-code)');\n }\n\n // Note: jq is NOT required — the TypeScript CLI handles JSON natively\n\n return errors;\n}\n\n// ── Per-project configuration file ──────────────────────────────────────────\n\n/** Optional per-project configuration file, read from the project root. */\nexport const PROJECT_CONFIG_FILENAME = '.issue-flow.json';\n\n/** Historical alias kept for the web monitoring call sites. */\nexport const WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;\n\n/**\n * Read and parse .issue-flow.json from the project root.\n *\n * Never throws: an absent file, unreadable path, invalid JSON or a non-object\n * root all degrade to `null` (with a warning for the malformed cases), so every\n * consumer falls back to its own defaults.\n */\nasync function readProjectConfigFile(\n projectRoot: string | undefined,\n warn: (message: string) => void,\n): Promise<Record<string, unknown> | null> {\n let root = projectRoot;\n if (root === undefined) {\n try {\n root = await getProjectRoot();\n } catch {\n return null;\n }\n }\n\n const filePath = join(root, PROJECT_CONFIG_FILENAME);\n let raw: string;\n try {\n raw = await readFile(filePath, 'utf-8');\n } catch {\n // The file is entirely optional — absence is the common case.\n return null;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: invalid JSON.`);\n return null;\n }\n\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: expected a JSON object.`);\n return null;\n }\n\n return parsed as Record<string, unknown>;\n}\n\n// ── Web monitoring configuration ────────────────────────────────────────────\n\n/**\n * CLI overrides captured by the preAction hook in cli.ts. Highest-precedence\n * source consumed by loadWebConfig().\n */\nlet webCliOverrides: Partial<WebConfig> = {};\n\nexport function setWebCliOverrides(overrides: Partial<WebConfig>): void {\n webCliOverrides = overrides;\n}\n\nexport interface LoadWebConfigOptions {\n /** CLI flag overrides. Defaults to the values set via setWebCliOverrides(). */\n cli?: Partial<WebConfig>;\n /** Environment source. Defaults to process.env. */\n env?: NodeJS.ProcessEnv;\n /** Directory containing .issue-flow.json. Defaults to the git project root. */\n projectRoot?: string;\n /** Warning sink. Defaults to printWarning. */\n warn?: (message: string) => void;\n}\n\nconst FALSY_ENV_VALUES = new Set(['', '0', 'false', 'no', 'off']);\n\nfunction parseBooleanEnv(value: string): boolean {\n return !FALSY_ENV_VALUES.has(value.trim().toLowerCase());\n}\n\nfunction readNumberEnv(\n env: NodeJS.ProcessEnv,\n name: string,\n warn: (message: string) => void,\n): number | undefined {\n const raw = env[name];\n if (raw === undefined) {\n return undefined;\n }\n const parsed = Number(raw);\n if (!Number.isFinite(parsed)) {\n warn(`Ignoring ${name}=\"${raw}\": not a number.`);\n return undefined;\n }\n return parsed;\n}\n\nfunction readWebConfigEnv(\n env: NodeJS.ProcessEnv,\n warn: (message: string) => void,\n): Partial<WebConfig> {\n const layer: Partial<WebConfig> = {};\n if (env.ISSUE_FLOW_WEB !== undefined) {\n layer.enabled = parseBooleanEnv(env.ISSUE_FLOW_WEB);\n }\n const port = readNumberEnv(env, 'ISSUE_FLOW_WEB_PORT', warn);\n if (port !== undefined) {\n layer.port = port;\n }\n if (env.ISSUE_FLOW_WEB_HOST !== undefined) {\n layer.host = env.ISSUE_FLOW_WEB_HOST;\n }\n const refresh = readNumberEnv(env, 'ISSUE_FLOW_WEB_REFRESH', warn);\n if (refresh !== undefined) {\n layer.refreshSeconds = refresh;\n }\n const logLimit = readNumberEnv(env, 'ISSUE_FLOW_WEB_LOG_LIMIT', warn);\n if (logLimit !== undefined) {\n layer.logLimit = logLimit;\n }\n return layer;\n}\n\nasync function readWebConfigFile(\n projectRoot: string | undefined,\n warn: (message: string) => void,\n): Promise<Partial<WebConfig>> {\n const file = await readProjectConfigFile(projectRoot, warn);\n const web = file?.web;\n if (web === undefined) {\n return {};\n }\n\n const result = webConfigSchema.partial().safeParse(web);\n if (!result.success) {\n warn(\n `Ignoring \"web\" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? 'invalid value'}.`,\n );\n return {};\n }\n return result.data;\n}\n\n/**\n * Resolve the web monitoring configuration with the documented precedence:\n * CLI flag > environment variable > .issue-flow.json > defaults.\n *\n * Never throws: missing or invalid sources degrade to the defaults with a\n * warning.\n */\nexport async function loadWebConfig(options: LoadWebConfigOptions = {}): Promise<WebConfig> {\n const warn = options.warn ?? printWarning;\n const cli = options.cli ?? webCliOverrides;\n const env = options.env ?? process.env;\n\n const fileLayer = await readWebConfigFile(options.projectRoot, warn);\n const envLayer = readWebConfigEnv(env, warn);\n const merged = { ...fileLayer, ...envLayer, ...cli };\n\n const result = webConfigSchema.safeParse(merged);\n if (result.success) {\n return result.data;\n }\n warn(\n `Invalid web monitoring configuration (${result.error.issues[0]?.message ?? 'invalid value'}); using defaults.`,\n );\n return webConfigSchema.parse({});\n}\n\n// ── Issue provider configuration ────────────────────────────────────────────\n\n/**\n * CLI overrides captured by the preAction hook in cli.ts (--local, --github,\n * --prefer-local, --prefer-github, --ask). Highest-precedence source consumed\n * by loadIssuesConfig().\n */\nlet issuesCliOverrides: Partial<IssuesConfig> = {};\n\nexport function setIssuesCliOverrides(overrides: Partial<IssuesConfig>): void {\n issuesCliOverrides = overrides;\n}\n\nexport interface LoadIssuesConfigOptions {\n /** CLI flag overrides. Defaults to the values set via setIssuesCliOverrides(). */\n cli?: Partial<IssuesConfig>;\n /** Directory containing .issue-flow.json. Defaults to the git project root. */\n projectRoot?: string;\n /** Warning sink. Defaults to printWarning. */\n warn?: (message: string) => void;\n}\n\nasync function readIssuesConfigFile(\n projectRoot: string | undefined,\n warn: (message: string) => void,\n): Promise<Partial<IssuesConfig>> {\n const file = await readProjectConfigFile(projectRoot, warn);\n const issues = file?.issues;\n if (issues === undefined) {\n return {};\n }\n\n const result = issuesConfigSchema.partial().safeParse(issues);\n if (!result.success) {\n warn(\n `Ignoring \"issues\" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? 'invalid value'}.`,\n );\n return {};\n }\n return result.data;\n}\n\n/**\n * Resolve the Issue provider configuration with the documented precedence:\n * CLI flag > .issue-flow.json > defaults.\n *\n * Never throws: missing or invalid sources degrade to the defaults with a\n * warning, and the defaults reproduce the GitHub-only behaviour.\n */\nexport async function loadIssuesConfig(\n options: LoadIssuesConfigOptions = {},\n): Promise<IssuesConfig> {\n const warn = options.warn ?? printWarning;\n const cli = options.cli ?? issuesCliOverrides;\n\n const fileLayer = await readIssuesConfigFile(options.projectRoot, warn);\n const merged = { ...fileLayer, ...cli };\n\n const result = issuesConfigSchema.safeParse(merged);\n if (result.success) {\n return result.data;\n }\n warn(\n `Invalid Issue provider configuration (${result.error.issues[0]?.message ?? 'invalid value'}); using defaults.`,\n );\n return issuesConfigSchema.parse({});\n}\n\n// ── PR review configuration ─────────────────────────────────────────────────\n\nexport interface LoadPrReviewConfigOptions {\n /** Highest-precedence layer, for a future `--publisher` flag. */\n cli?: Partial<PrReviewConfig>;\n /** Environment source. Defaults to process.env. */\n env?: NodeJS.ProcessEnv;\n /** Directory containing .issue-flow.json. Defaults to the git project root. */\n projectRoot?: string;\n /** Warning sink. Defaults to printWarning. */\n warn?: (message: string) => void;\n}\n\nfunction readPrReviewConfigEnv(env: NodeJS.ProcessEnv): Partial<PrReviewConfig> {\n const publisher = env.ISSUE_FLOW_PR_REVIEW_PUBLISHER;\n // An unknown value is not dropped here: it goes through the schema below, so\n // the user gets the same warning a bad config file would produce.\n return publisher === undefined ? {} : { publisher: publisher as PrReviewConfig['publisher'] };\n}\n\nasync function readPrReviewConfigFile(\n projectRoot: string | undefined,\n warn: (message: string) => void,\n): Promise<Partial<PrReviewConfig>> {\n const file = await readProjectConfigFile(projectRoot, warn);\n const prReview = file?.prReview;\n if (prReview === undefined) {\n return {};\n }\n\n const result = prReviewConfigSchema.partial().safeParse(prReview);\n if (!result.success) {\n warn(\n `Ignoring \"prReview\" key of ${PROJECT_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? 'invalid value'}.`,\n );\n return {};\n }\n return result.data;\n}\n\n/**\n * Resolve the `pr-review` configuration with the documented precedence:\n * CLI flag > environment variable > .issue-flow.json > defaults.\n *\n * Never throws: an absent, malformed or unknown value degrades to the default\n * publisher with a warning, so a typo in .issue-flow.json costs a warning\n * rather than the review.\n */\nexport async function loadPrReviewConfig(\n options: LoadPrReviewConfigOptions = {},\n): Promise<PrReviewConfig> {\n const warn = options.warn ?? printWarning;\n const env = options.env ?? process.env;\n\n const fileLayer = await readPrReviewConfigFile(options.projectRoot, warn);\n const envLayer = readPrReviewConfigEnv(env);\n const merged = { ...fileLayer, ...envLayer, ...(options.cli ?? {}) };\n\n const result = prReviewConfigSchema.safeParse(merged);\n if (result.success) {\n return result.data;\n }\n warn(\n `Invalid PR review configuration (${result.error.issues[0]?.message ?? 'invalid value'}); using defaults.`,\n );\n return prReviewConfigSchema.parse({});\n}\n","import { join } from 'node:path';\nimport { run } from './shell.js';\n\n/**\n * Get the root directory of the current git repository.\n * Throws if not inside a git repository.\n */\nexport async function getProjectRoot(): Promise<string> {\n const result = await run('git', ['rev-parse', '--show-toplevel']);\n\n if (result.exitCode !== 0) {\n throw new Error(\n 'Not inside a git repository. Please run issue-flow from within a git project.',\n );\n }\n\n return result.stdout.trim();\n}\n\n/**\n * Resolve `issues/<issueNumber>/`, always anchored to the git repository\n * root — never to `process.cwd()`.\n *\n * Every command must go through this instead of `join('issues', issueNumber)`:\n * a plain CWD-relative join means the pipeline resolves a different directory\n * depending on which subdirectory of the repo the command was launched from,\n * which is exactly what let `plan` write to `<subdir>/issues/<N>/` while\n * `execute` (already anchored to the project root via `resolvePaths()` in\n * config.ts) looked for it at `<repoRoot>/issues/<N>/` and failed. Anchoring\n * every command the same way makes the outcome identical regardless of CWD,\n * so there is nothing left for a user to get wrong by running from a\n * subdirectory.\n */\nexport async function getIssueDir(issueNumber: string): Promise<string> {\n return join(await getProjectRoot(), 'issues', issueNumber);\n}\n\n/**\n * Get the current git branch name.\n * Returns an empty string if in detached HEAD state.\n */\nexport async function getCurrentBranch(): Promise<string> {\n const result = await run('git', ['branch', '--show-current']);\n\n if (result.exitCode !== 0) {\n throw new Error(\n 'Failed to detect git branch. Ensure git is installed and you are inside a repository.',\n );\n }\n\n return result.stdout.trim();\n}\n\nexport interface CommitInfo {\n hash: string;\n subject: string;\n}\n\n/**\n * Get the base branch of the repository: the remote HEAD (origin/HEAD) when\n * available, otherwise the first of main/master that exists locally.\n * Never throws; defaults to 'main'.\n */\nexport async function getBaseBranch(): Promise<string> {\n const remoteHead = await run('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD']);\n if (remoteHead.exitCode === 0) {\n const name = remoteHead.stdout.trim().replace(/^origin\\//, '');\n if (name) return name;\n }\n\n for (const candidate of ['main', 'master']) {\n const check = await run('git', ['rev-parse', '--verify', '--quiet', `refs/heads/${candidate}`]);\n if (check.exitCode === 0) return candidate;\n }\n\n return 'main';\n}\n\n/**\n * List commits on HEAD that are not on the given base branch (base..HEAD),\n * most recent first. Never throws; returns [] when the range cannot be\n * resolved (e.g. unknown base branch or shallow clone).\n */\nexport async function getCommitsSince(base: string): Promise<CommitInfo[]> {\n const result = await run('git', ['log', '--pretty=format:%h%x09%s', `${base}..HEAD`]);\n if (result.exitCode !== 0) return [];\n\n return result.stdout\n .split('\\n')\n .filter((line) => line.trim() !== '')\n .map((line) => {\n const tab = line.indexOf('\\t');\n return tab === -1\n ? { hash: line.trim(), subject: '' }\n : { hash: line.slice(0, tab), subject: line.slice(tab + 1) };\n });\n}\n","import { type Options as ExecaOptions, execa } from 'execa';\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Execute a command with arguments and capture its output.\n * Uses execa which calls execFile internally (no shell injection risk).\n * Does not throw on non-zero exit codes.\n */\nexport async function run(\n command: string,\n args: string[] = [],\n options?: ExecaOptions,\n): Promise<ExecResult> {\n const result = await execa(command, args, {\n reject: false,\n ...options,\n });\n\n return {\n stdout: result.stdout?.toString() ?? '',\n stderr: result.stderr?.toString() ?? '',\n exitCode: result.exitCode ?? 1,\n };\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,QAAAA,aAAY;;;ACFrB,SAAS,YAAY;;;ACArB,SAAuC,aAAa;AAapD,eAAsB,IACpB,SACA,OAAiB,CAAC,GAClB,SACqB;AACrB,QAAM,SAAS,MAAM,MAAM,SAAS,MAAM;AAAA,IACxC,QAAQ;AAAA,IACR,GAAG;AAAA,EACL,CAAC;AAED,SAAO;AAAA,IACL,QAAQ,OAAO,QAAQ,SAAS,KAAK;AAAA,IACrC,QAAQ,OAAO,QAAQ,SAAS,KAAK;AAAA,IACrC,UAAU,OAAO,YAAY;AAAA,EAC/B;AACF;;;ADrBA,eAAsB,iBAAkC;AACtD,QAAM,SAAS,MAAM,IAAI,OAAO,CAAC,aAAa,iBAAiB,CAAC;AAEhE,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,KAAK;AAC5B;AAgBA,eAAsB,YAAY,aAAsC;AACtE,SAAO,KAAK,MAAM,eAAe,GAAG,UAAU,WAAW;AAC3D;AAMA,eAAsB,mBAAoC;AACxD,QAAM,SAAS,MAAM,IAAI,OAAO,CAAC,UAAU,gBAAgB,CAAC;AAE5D,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,KAAK;AAC5B;AAYA,eAAsB,gBAAiC;AACrD,QAAM,aAAa,MAAM,IAAI,OAAO,CAAC,gBAAgB,WAAW,0BAA0B,CAAC;AAC3F,MAAI,WAAW,aAAa,GAAG;AAC7B,UAAM,OAAO,WAAW,OAAO,KAAK,EAAE,QAAQ,aAAa,EAAE;AAC7D,QAAI,KAAM,QAAO;AAAA,EACnB;AAEA,aAAW,aAAa,CAAC,QAAQ,QAAQ,GAAG;AAC1C,UAAM,QAAQ,MAAM,IAAI,OAAO,CAAC,aAAa,YAAY,WAAW,cAAc,SAAS,EAAE,CAAC;AAC9F,QAAI,MAAM,aAAa,EAAG,QAAO;AAAA,EACnC;AAEA,SAAO;AACT;AAOA,eAAsB,gBAAgB,MAAqC;AACzE,QAAM,SAAS,MAAM,IAAI,OAAO,CAAC,OAAO,4BAA4B,GAAG,IAAI,QAAQ,CAAC;AACpF,MAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AAEnC,SAAO,OAAO,OACX,MAAM,IAAI,EACV,OAAO,CAAC,SAAS,KAAK,KAAK,MAAM,EAAE,EACnC,IAAI,CAAC,SAAS;AACb,UAAM,MAAM,KAAK,QAAQ,GAAI;AAC7B,WAAO,QAAQ,KACX,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,GAAG,IACjC,EAAE,MAAM,KAAK,MAAM,GAAG,GAAG,GAAG,SAAS,KAAK,MAAM,MAAM,CAAC,EAAE;AAAA,EAC/D,CAAC;AACL;;;AD7EO,IAAM,WAAW;AAAA,EACtB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,mBAAmB;AACrB;AAKO,SAAS,aAAa,SAA8C;AACzE,SAAO;AAAA,IACL,aAAa,QAAQ;AAAA,IACrB,eAAe,QAAQ;AAAA,IACvB,YAAY,QAAQ,cAAc,SAAS;AAAA,IAC3C,cAAc,QAAQ,gBAAgB,SAAS;AAAA,IAC/C,oBAAoB,QAAQ,sBAAsB,SAAS;AAAA,IAC3D,mBAAmB,QAAQ,qBAAqB,SAAS;AAAA,EAC3D;AACF;AAaA,eAAsB,aACpB,QACA,WACwB;AACxB,QAAM,cAAc,MAAM,eAAe;AAEzC,MAAI,OAAO,aAAa;AACtB,UAAM,WAAWC,MAAK,aAAa,UAAU,OAAO,WAAW;AAC/D,WAAO;AAAA,MACL,SAASA,MAAK,UAAU,YAAY;AAAA,MACpC,cAAcA,MAAK,UAAU,cAAc;AAAA,MAC3C,YAAYA,MAAK,UAAU,SAAS;AAAA,MACpC,gBAAgBA,MAAK,UAAU,cAAc;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAGA,QAAM,OAAO,aAAa;AAC1B,SAAO;AAAA,IACL,SAASA,MAAK,MAAM,UAAU;AAAA,IAC9B,cAAcA,MAAK,MAAM,cAAc;AAAA,IACvC,YAAYA,MAAK,MAAM,SAAS;AAAA,IAChC,gBAAgBA,MAAK,MAAM,cAAc;AAAA,IACzC;AAAA,EACF;AACF;AAKO,SAAS,eAAe,KAAqB;AAClD,QAAM,KAAK,SAAS;AAEpB,MAAI,OAAO,UAAU;AACnB,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AACA,MAAI,OAAO,SAAS;AAClB,WAAO,eAAe,GAAG;AAAA,EAC3B;AACA,MAAI,OAAO,SAAS;AAClB,WAAO,kBAAkB,GAAG,uBAAuB,GAAG;AAAA,EACxD;AAEA,SAAO,WAAW,GAAG;AACvB;AAMA,eAAsB,uBAA0C;AAC9D,QAAM,SAAmB,CAAC;AAG1B,QAAM,YAAY,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC;AAChD,MAAI,UAAU,aAAa,GAAG;AAC5B,WAAO,KAAK,2BAA2B,eAAe,KAAK,CAAC,GAAG;AAAA,EACjE;AAGA,QAAM,eAAe,MAAM,IAAI,UAAU,CAAC,WAAW,CAAC;AACtD,MAAI,aAAa,aAAa,GAAG;AAC/B,WAAO,KAAK,sEAAsE;AAAA,EACpF;AAIA,SAAO;AACT;AAKO,IAAM,0BAA0B;AAGhC,IAAM,sBAAsB;AASnC,eAAe,sBACb,aACA,MACyC;AACzC,MAAI,OAAO;AACX,MAAI,SAAS,QAAW;AACtB,QAAI;AACF,aAAO,MAAM,eAAe;AAAA,IAC9B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,WAAWA,MAAK,MAAM,uBAAuB;AACnD,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,SAAS,UAAU,OAAO;AAAA,EACxC,QAAQ;AAEN,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,SAAK,YAAY,uBAAuB,iBAAiB;AACzD,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAC1E,SAAK,YAAY,uBAAuB,2BAA2B;AACnE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAQA,IAAI,kBAAsC,CAAC;AAEpC,SAAS,mBAAmB,WAAqC;AACtE,oBAAkB;AACpB;AAaA,IAAM,mBAAmB,oBAAI,IAAI,CAAC,IAAI,KAAK,SAAS,MAAM,KAAK,CAAC;AAEhE,SAAS,gBAAgB,OAAwB;AAC/C,SAAO,CAAC,iBAAiB,IAAI,MAAM,KAAK,EAAE,YAAY,CAAC;AACzD;AAEA,SAAS,cACP,KACA,MACA,MACoB;AACpB,QAAM,MAAM,IAAI,IAAI;AACpB,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,EACT;AACA,QAAM,SAAS,OAAO,GAAG;AACzB,MAAI,CAAC,OAAO,SAAS,MAAM,GAAG;AAC5B,SAAK,YAAY,IAAI,KAAK,GAAG,kBAAkB;AAC/C,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,iBACP,KACA,MACoB;AACpB,QAAM,QAA4B,CAAC;AACnC,MAAI,IAAI,mBAAmB,QAAW;AACpC,UAAM,UAAU,gBAAgB,IAAI,cAAc;AAAA,EACpD;AACA,QAAM,OAAO,cAAc,KAAK,uBAAuB,IAAI;AAC3D,MAAI,SAAS,QAAW;AACtB,UAAM,OAAO;AAAA,EACf;AACA,MAAI,IAAI,wBAAwB,QAAW;AACzC,UAAM,OAAO,IAAI;AAAA,EACnB;AACA,QAAM,UAAU,cAAc,KAAK,0BAA0B,IAAI;AACjE,MAAI,YAAY,QAAW;AACzB,UAAM,iBAAiB;AAAA,EACzB;AACA,QAAM,WAAW,cAAc,KAAK,4BAA4B,IAAI;AACpE,MAAI,aAAa,QAAW;AAC1B,UAAM,WAAW;AAAA,EACnB;AACA,SAAO;AACT;AAEA,eAAe,kBACb,aACA,MAC6B;AAC7B,QAAM,OAAO,MAAM,sBAAsB,aAAa,IAAI;AAC1D,QAAM,MAAM,MAAM;AAClB,MAAI,QAAQ,QAAW;AACrB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,gBAAgB,QAAQ,EAAE,UAAU,GAAG;AACtD,MAAI,CAAC,OAAO,SAAS;AACnB;AAAA,MACE,yBAAyB,uBAAuB,KAAK,OAAO,MAAM,OAAO,CAAC,GAAG,WAAW,eAAe;AAAA,IACzG;AACA,WAAO,CAAC;AAAA,EACV;AACA,SAAO,OAAO;AAChB;AASA,eAAsB,cAAc,UAAgC,CAAC,GAAuB;AAC1F,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,MAAM,QAAQ,OAAO;AAC3B,QAAM,MAAM,QAAQ,OAAO,QAAQ;AAEnC,QAAM,YAAY,MAAM,kBAAkB,QAAQ,aAAa,IAAI;AACnE,QAAM,WAAW,iBAAiB,KAAK,IAAI;AAC3C,QAAM,SAAS,EAAE,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI;AAEnD,QAAM,SAAS,gBAAgB,UAAU,MAAM;AAC/C,MAAI,OAAO,SAAS;AAClB,WAAO,OAAO;AAAA,EAChB;AACA;AAAA,IACE,yCAAyC,OAAO,MAAM,OAAO,CAAC,GAAG,WAAW,eAAe;AAAA,EAC7F;AACA,SAAO,gBAAgB,MAAM,CAAC,CAAC;AACjC;AASA,IAAI,qBAA4C,CAAC;AAE1C,SAAS,sBAAsB,WAAwC;AAC5E,uBAAqB;AACvB;AAWA,eAAe,qBACb,aACA,MACgC;AAChC,QAAM,OAAO,MAAM,sBAAsB,aAAa,IAAI;AAC1D,QAAM,SAAS,MAAM;AACrB,MAAI,WAAW,QAAW;AACxB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,mBAAmB,QAAQ,EAAE,UAAU,MAAM;AAC5D,MAAI,CAAC,OAAO,SAAS;AACnB;AAAA,MACE,4BAA4B,uBAAuB,KAAK,OAAO,MAAM,OAAO,CAAC,GAAG,WAAW,eAAe;AAAA,IAC5G;AACA,WAAO,CAAC;AAAA,EACV;AACA,SAAO,OAAO;AAChB;AASA,eAAsB,iBACpB,UAAmC,CAAC,GACb;AACvB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,MAAM,QAAQ,OAAO;AAE3B,QAAM,YAAY,MAAM,qBAAqB,QAAQ,aAAa,IAAI;AACtE,QAAM,SAAS,EAAE,GAAG,WAAW,GAAG,IAAI;AAEtC,QAAM,SAAS,mBAAmB,UAAU,MAAM;AAClD,MAAI,OAAO,SAAS;AAClB,WAAO,OAAO;AAAA,EAChB;AACA;AAAA,IACE,yCAAyC,OAAO,MAAM,OAAO,CAAC,GAAG,WAAW,eAAe;AAAA,EAC7F;AACA,SAAO,mBAAmB,MAAM,CAAC,CAAC;AACpC;AAeA,SAAS,sBAAsB,KAAiD;AAC9E,QAAM,YAAY,IAAI;AAGtB,SAAO,cAAc,SAAY,CAAC,IAAI,EAAE,UAAoD;AAC9F;AAEA,eAAe,uBACb,aACA,MACkC;AAClC,QAAM,OAAO,MAAM,sBAAsB,aAAa,IAAI;AAC1D,QAAM,WAAW,MAAM;AACvB,MAAI,aAAa,QAAW;AAC1B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,qBAAqB,QAAQ,EAAE,UAAU,QAAQ;AAChE,MAAI,CAAC,OAAO,SAAS;AACnB;AAAA,MACE,8BAA8B,uBAAuB,KAAK,OAAO,MAAM,OAAO,CAAC,GAAG,WAAW,eAAe;AAAA,IAC9G;AACA,WAAO,CAAC;AAAA,EACV;AACA,SAAO,OAAO;AAChB;AAUA,eAAsB,mBACpB,UAAqC,CAAC,GACb;AACzB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,MAAM,QAAQ,OAAO,QAAQ;AAEnC,QAAM,YAAY,MAAM,uBAAuB,QAAQ,aAAa,IAAI;AACxE,QAAM,WAAW,sBAAsB,GAAG;AAC1C,QAAM,SAAS,EAAE,GAAG,WAAW,GAAG,UAAU,GAAI,QAAQ,OAAO,CAAC,EAAG;AAEnE,QAAM,SAAS,qBAAqB,UAAU,MAAM;AACpD,MAAI,OAAO,SAAS;AAClB,WAAO,OAAO;AAAA,EAChB;AACA;AAAA,IACE,oCAAoC,OAAO,MAAM,OAAO,CAAC,GAAG,WAAW,eAAe;AAAA,EACxF;AACA,SAAO,qBAAqB,MAAM,CAAC,CAAC;AACtC;","names":["join","join"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/engine.ts","../src/ui/progress.ts","../src/ui/summary.ts","../src/core/executor.ts","../src/commands/execute.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { cp, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EngineConfig, ResolvedPaths, TaskPlan } from '../types.js';\nimport { printError, printInfo, printRetry, printSuccess, printWarning } from '../ui/logger.js';\nimport { printIterationHeader } from '../ui/progress.js';\nimport { printStartupHeader, printSummaryBox } from '../ui/summary.js';\nimport { isTransientFailure, retryDelaySeconds, sleep } from '../utils/retry.js';\nimport { executeClaude } from './executor.js';\nimport { applyPlaceholders, loadPrompt } from './prompt-resolver.js';\nimport { publishGitState } from './session-git.js';\nimport { getSessionPublisher } from './session-publisher.js';\nimport {\n allStoriesPass,\n clearLastError,\n initializeState,\n isoNow,\n loadTaskPlan,\n markIssueCompleted,\n markIssueInProgress,\n saveTaskPlan,\n setLastError,\n trimErrorMessage,\n} from './state-manager.js';\nimport { getOutputCallback, getStoryUpdateCallback, isVerbose } from './verbose.js';\n\n/**\n * Emit a message through the output callback if available, otherwise console.log.\n * Used for bare console.log calls in engine functions so they route through listr2.\n */\nfunction emitLog(message: string): void {\n const cb = getOutputCallback();\n if (cb) {\n // Skip empty lines in listr2 context — they don't render meaningfully\n if (message) {\n cb(message);\n }\n } else {\n console.log(message);\n }\n}\n\n/**\n * Initialize the progress file if it doesn't exist.\n */\nasync function ensureProgressFile(progressFile: string): Promise<void> {\n if (!existsSync(progressFile)) {\n const content = `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`;\n await writeFile(progressFile, content, 'utf-8');\n }\n}\n\n/**\n * Archive previous run artifacts if the branch has changed.\n */\nasync function archiveIfBranchChanged(plan: TaskPlan, paths: ResolvedPaths): Promise<void> {\n const { lastBranchFile, archiveDir, prdFile, progressFile } = paths;\n\n if (!existsSync(lastBranchFile)) {\n return;\n }\n\n const currentBranch = plan.branchName ?? '';\n let lastBranch = '';\n\n try {\n lastBranch = (await readFile(lastBranchFile, 'utf-8')).trim();\n } catch {\n return;\n }\n\n if (currentBranch && lastBranch && currentBranch !== lastBranch) {\n const dateStr = new Date().toISOString().split('T')[0];\n const folderName = lastBranch.replace(/^issue\\//, '').replace(/[<>:\"|?*\\\\]/g, '_');\n const archiveFolder = join(archiveDir, `${dateStr}-${folderName}`);\n\n printInfo(`Archiving previous run: ${lastBranch}`);\n await mkdir(archiveFolder, { recursive: true });\n\n if (existsSync(prdFile)) {\n await cp(prdFile, join(archiveFolder, 'tasks.json'));\n }\n if (existsSync(progressFile)) {\n await cp(progressFile, join(archiveFolder, 'progress.txt'));\n }\n\n printInfo(` Archived to: ${archiveFolder}`);\n\n // Reset progress file for new run\n await writeFile(\n progressFile,\n `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`,\n 'utf-8',\n );\n }\n}\n\n/**\n * Write the current branch to the last-branch tracking file.\n */\nasync function trackBranch(plan: TaskPlan, lastBranchFile: string): Promise<void> {\n const branch = plan.branchName ?? '';\n if (branch) {\n await writeFile(lastBranchFile, `${branch}\\n`, 'utf-8');\n }\n}\n\n/**\n * Run the issue-flow engine loop.\n *\n * This replicates the full execution flow:\n * 1. Load and initialize task plan state\n * 2. Check for early exit (already complete)\n * 3. Archive previous run if branch changed\n * 4. Resolve prompt\n * 5. Main loop: iterate, execute Claude, handle results\n * 6. Print summary\n */\nexport async function runEngine(config: EngineConfig, paths: ResolvedPaths): Promise<number> {\n // Load task plan\n if (!existsSync(paths.prdFile)) {\n printError(`PRD file not found at ${paths.prdFile}`);\n if (config.issueNumber) {\n emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);\n }\n return 1;\n }\n\n let plan = await loadTaskPlan(paths.prdFile);\n plan = initializeState(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Check if already completed\n if (plan.issueStatus === 'completed' && allStoriesPass(plan)) {\n emitLog(`Issue already marked complete in ${paths.prdFile}`);\n return 0;\n }\n\n // Warn if marked complete but stories still pending\n if (plan.issueStatus === 'completed' && !allStoriesPass(plan)) {\n printWarning(\n 'Issue marked completed but some stories are still pending. Resetting to in_progress.',\n );\n plan = markIssueInProgress(plan);\n plan = setLastError(\n plan,\n 'invalid_completion_state',\n 'tasks.json claimed the issue was completed before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n }\n\n // Check if all stories already pass\n if (allStoriesPass(plan)) {\n emitLog('All user stories already pass. Marking issue as completed.');\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n return 0;\n }\n\n // Archive previous run if branch changed\n await archiveIfBranchChanged(plan, paths);\n\n // Track current branch\n await trackBranch(plan, paths.lastBranchFile);\n\n // Initialize progress file\n await ensureProgressFile(paths.progressFile);\n\n // Load prompt template\n const promptTemplate = await loadPrompt('execute');\n\n // Print startup header\n printStartupHeader(config, plan);\n\n const startTime = Date.now();\n let i = 0;\n let retryCount = 0;\n let totalRetryCount = 0;\n\n // Main loop\n while (true) {\n // Check iteration limit\n if (config.maxIterations !== undefined && i >= config.maxIterations) {\n break;\n }\n\n i++;\n getSessionPublisher().publish({ type: 'iteration:start', at: isoNow(), iteration: i });\n\n // Re-read plan to get latest state\n plan = await loadTaskPlan(paths.prdFile);\n\n if (isVerbose()) {\n printIterationHeader(i, config.maxIterations, plan.userStories);\n }\n\n // Apply placeholders to prompt\n const prompt = applyPlaceholders(promptTemplate, {\n __PRD_FILE__: paths.prdFile,\n __PROGRESS_FILE__: paths.progressFile,\n });\n\n const iterationStartedAt = isoNow();\n plan = markIssueInProgress(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Execute Claude\n const result = await executeClaude(prompt);\n\n if (result.exitCode !== 0) {\n const errorMessage = trimErrorMessage(result.output);\n\n if (isTransientFailure(result.exitCode, result.output)) {\n retryCount++;\n totalRetryCount++;\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'transient_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n\n if (!config.retryForever && retryCount > config.retryLimit) {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n `Exceeded retry limit (${config.retryLimit}) on transient errors`,\n );\n return result.exitCode;\n }\n\n const delaySeconds = retryDelaySeconds(\n retryCount,\n config.backoffBaseSeconds,\n config.backoffMaxSeconds,\n );\n getSessionPublisher().publish({\n type: 'retry',\n at: isoNow(),\n attempt: retryCount,\n delaySeconds,\n reason: 'transient_claude_failure',\n });\n\n if (isVerbose()) {\n emitLog('');\n }\n printRetry(\n `Transient Claude failure on iteration ${i} (attempt ${retryCount}). Retrying in ${delaySeconds}s.`,\n );\n\n // Stay within current iteration budget\n i--;\n await sleep(delaySeconds);\n continue;\n }\n\n // Fatal failure\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'fatal_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n `Claude CLI failed with exit code ${result.exitCode}`,\n );\n return result.exitCode;\n }\n\n // Success — reset retry counter\n retryCount = 0;\n plan = await loadTaskPlan(paths.prdFile);\n plan = clearLastError(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Notify story progress listeners (e.g., listr2 subtasks)\n const storyUpdateCb = getStoryUpdateCallback();\n if (storyUpdateCb) {\n storyUpdateCb(plan.userStories);\n }\n getSessionPublisher().publish({\n type: 'stories:update',\n at: isoNow(),\n stories: plan.userStories,\n });\n getSessionPublisher().publish({ type: 'iteration:end', at: isoNow(), iteration: i });\n // Low-frequency commit/PR enrichment: iteration end is one of the only\n // two sanctioned points (the other is phase boundaries in run.ts).\n await publishGitState(getSessionPublisher());\n\n // Check for completion signal\n if (result.output.includes('<promise>COMPLETE</promise>')) {\n plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox('success', i, totalRetryCount, elapsed, plan);\n return 0;\n }\n\n plan = setLastError(\n plan,\n 'invalid_completion_signal',\n 'Claude returned <promise>COMPLETE</promise> before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n\n emitLog('');\n printWarning(\n 'Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing.',\n );\n }\n\n if (isVerbose()) {\n printSuccess(`Iteration ${i} complete. Continuing...`);\n }\n await sleep(2);\n }\n\n // Reached max iterations\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'incomplete',\n config.maxIterations ?? i,\n totalRetryCount,\n elapsed,\n plan,\n 'Reached max iterations without completing all tasks.',\n );\n return 1;\n}\n","import chalk from 'chalk';\nimport { getOutputCallback } from '../core/verbose.js';\nimport type { UserStory } from '../types.js';\nimport { getIcons, useColor, useUnicode } from './logger.js';\n\n/**\n * Print a visual progress bar showing passed/total stories.\n */\nexport function printProgressBar(passed: number, total: number): string {\n const barWidth = 20;\n let pct = 0;\n let filled = 0;\n\n if (total > 0) {\n pct = Math.floor((passed * 100) / total);\n filled = Math.floor((passed * barWidth) / total);\n }\n\n const empty = barWidth - filled;\n const fillChar = useUnicode() ? '\\u2588' : '#';\n const emptyChar = useUnicode() ? '\\u2591' : '-';\n\n const bar = fillChar.repeat(filled) + emptyChar.repeat(empty);\n const text = `${passed}/${total} (${pct}%)`;\n\n if (useColor()) {\n return `${chalk.green(bar)} ${text}`;\n }\n return `${bar} ${text}`;\n}\n\n/**\n * Print the iteration header showing story statuses and progress bar.\n *\n * When a global output callback is set (e.g., inside a listr2 task),\n * output is routed through it instead of console.log.\n */\nexport function printIterationHeader(\n iteration: number,\n maxIter: number | undefined,\n stories: UserStory[],\n): void {\n const icons = getIcons();\n const colored = useColor();\n const cb = getOutputCallback();\n\n const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;\n\n const total = stories.length;\n const passed = stories.filter((s) => s.passes).length;\n\n const lines: string[] = [];\n\n if (colored) {\n lines.push(chalk.blue(`\\u2501\\u2501\\u2501 ${icons.start} ${iterLabel} \\u2501\\u2501\\u2501`));\n } else {\n lines.push(`--- ${icons.start} ${iterLabel} ---`);\n }\n\n // Display each story status\n let foundFirstPending = false;\n for (const story of stories) {\n let icon: string;\n let colorFn: (s: string) => string;\n\n if (story.passes) {\n icon = icons.success;\n colorFn = colored ? chalk.green : (s: string) => s;\n } else if (!foundFirstPending) {\n // First non-passing story = current in-progress\n icon = icons.pending;\n colorFn = colored ? chalk.yellow : (s: string) => s;\n foundFirstPending = true;\n } else {\n // Not yet reached\n icon = icons.notReached;\n colorFn = colored ? chalk.gray : (s: string) => s;\n }\n\n lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));\n }\n\n lines.push(` ${printProgressBar(passed, total)}`);\n\n if (cb) {\n // Send as single output to listr2 task context\n cb(lines.join('\\n'));\n } else {\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n console.log('');\n }\n}\n","import chalk from 'chalk';\nimport type { EngineConfig, PrReviewRecommendation, TaskPlan } from '../types.js';\nimport {\n formatDuration,\n getIcons,\n getTermWidth,\n printSuccess,\n printWarning,\n useColor,\n useUnicode,\n} from './logger.js';\n\n/**\n * Truncate or pad a string to fit within a given width.\n */\nfunction fitLine(text: string, width: number): string {\n if (text.length > width) {\n return text.substring(0, width);\n }\n return text.padEnd(width);\n}\n\n/**\n * Print a box with border characters around content lines.\n * Lines equal to \"---\" render as separator rows.\n */\nexport function printBox(lines: string[]): void {\n const colored = useColor();\n const unicode = useUnicode();\n const termWidth = getTermWidth();\n\n // Find max content width\n let maxContentWidth = 0;\n for (const line of lines) {\n if (line !== '---' && line.length > maxContentWidth) {\n maxContentWidth = line.length;\n }\n }\n\n // Cap to terminal width (border + padding = 4 chars)\n const available = termWidth - 4;\n if (maxContentWidth > available) {\n maxContentWidth = available;\n }\n if (maxContentWidth < 20) {\n maxContentWidth = 20;\n }\n\n // Box drawing characters\n const tl = unicode ? '\\u256D' : '+';\n const tr = unicode ? '\\u256E' : '+';\n const bl = unicode ? '\\u2570' : '+';\n const br = unicode ? '\\u256F' : '+';\n const h = unicode ? '\\u2500' : '-';\n const v = unicode ? '\\u2502' : '|';\n const sepL = unicode ? '\\u251C' : '+';\n const sepR = unicode ? '\\u2524' : '+';\n\n const hrule = h.repeat(maxContentWidth + 2);\n\n const blue = colored ? chalk.blue : (s: string) => s;\n const _reset = (s: string) => s;\n\n // Top border\n console.log(blue(`${tl}${hrule}${tr}`));\n\n // Content lines\n for (const line of lines) {\n if (line === '---') {\n console.log(blue(`${sepL}${hrule}${sepR}`));\n } else {\n const fitted = fitLine(line, maxContentWidth);\n console.log(`${blue(v)} ${fitted} ${blue(v)}`);\n }\n }\n\n // Bottom border\n console.log(blue(`${bl}${hrule}${br}`));\n}\n\n/**\n * Print the startup header box showing engine configuration.\n */\nexport function printStartupHeader(config: EngineConfig, plan: TaskPlan): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const branchName = plan.branchName ?? 'N/A';\n\n const issueLabel = config.issueNumber ? `Issue #${config.issueNumber}` : 'Standalone mode';\n\n const maxIterLabel =\n config.maxIterations !== undefined ? String(config.maxIterations) : 'unlimited';\n\n const retryLabel = config.retryForever\n ? 'unlimited retries'\n : `${config.retryLimit} consecutive retries`;\n\n printBox([\n `${icons.start} Issue Flow`,\n '---',\n `Issue: ${issueLabel}`,\n `Branch: ${branchName}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${maxIterLabel}`,\n `Retries: ${retryLabel}`,\n ]);\n}\n\n// Re-export formatDuration from logger to maintain backwards compatibility\nexport { formatDuration } from './logger.js';\n\n/**\n * Print the final summary box.\n */\nexport function printSummaryBox(\n status: 'success' | 'incomplete' | 'failed',\n iterations: number,\n totalRetries: number,\n elapsedSeconds: number,\n plan: TaskPlan,\n extraInfo?: string,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const duration = formatDuration(elapsedSeconds);\n\n let statusIcon: string;\n let statusLabel: string;\n\n switch (status) {\n case 'success':\n statusIcon = icons.success;\n statusLabel = 'Completed';\n break;\n case 'incomplete':\n statusIcon = icons.warn;\n statusLabel = 'Incomplete';\n break;\n case 'failed':\n statusIcon = icons.fail;\n statusLabel = 'Failed';\n break;\n }\n\n const boxLines = [\n `${icons.end} Issue Flow Summary`,\n '---',\n `Status: ${statusIcon} ${statusLabel}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${iterations}`,\n `Duration: ${duration}`,\n `Retries: ${totalRetries}`,\n ];\n\n if (extraInfo) {\n boxLines.push('---');\n boxLines.push(extraInfo);\n }\n\n console.log('');\n printBox(boxLines);\n}\n\n/**\n * What the optional `pr-review` phase produced, as far as the summary cares.\n * `null` in `recommendation` means the verdict could not be recovered from\n * disk — the exit code still told us whether changes were requested.\n */\nexport interface RunSummaryPrReview {\n requestedChanges: boolean;\n recommendation: PrReviewRecommendation | null;\n reportPath: string | null;\n}\n\n/**\n * Everything the final `run` summary prints, already resolved by the caller.\n */\nexport interface RunSummaryInfo {\n issueNumber: string;\n /** 'unknown' when the branch could not be detected. */\n branchName: string;\n /** Pipelines run with --no-branch open no Pull Request. */\n noBranch: boolean;\n storyCount: number;\n elapsedSeconds: number;\n /** 'unknown' when no Pull Request could be resolved. */\n prUrl: string;\n /** Only set when the pr-review phase actually ran. */\n prReview?: RunSummaryPrReview | null;\n}\n\n/**\n * Detail lines of the final `run` summary (everything below the headline).\n *\n * Kept separate from the printing so the shape is testable without capturing\n * stdout. Without `prReview` the lines are exactly the ones the pipeline has\n * always printed.\n */\nexport function buildRunSummaryLines(info: RunSummaryInfo): string[] {\n const lines = [\n ` Branch: ${info.branchName}${info.noBranch ? ' (current)' : ''}`,\n ` Stories: ${info.storyCount}`,\n ` Duration: ${formatDuration(info.elapsedSeconds)}`,\n ];\n\n if (!info.noBranch) {\n lines.push(` PR: ${info.prUrl}`);\n }\n\n const review = info.prReview;\n if (review) {\n // The exit code is the source of truth for the verdict, so a report whose\n // recommendation could not be read still reports REQUEST_CHANGES.\n const verdict =\n review.recommendation ?? (review.requestedChanges ? 'REQUEST_CHANGES' : 'unknown');\n lines.push(` Review: ${verdict}`);\n if (review.reportPath !== null) {\n lines.push(` Report: ${review.reportPath}`);\n }\n }\n\n return lines;\n}\n\n/**\n * Print the final summary of a `run` (the flat listing, not the box used by\n * the execute engine).\n */\nexport function printRunSummary(info: RunSummaryInfo): void {\n console.log('');\n if (info.prReview?.requestedChanges) {\n printWarning(\n `Pipeline finished for issue #${info.issueNumber}, but the PR review requested changes.`,\n );\n } else {\n printSuccess(`Pipeline complete for issue #${info.issueNumber}!`);\n }\n for (const line of buildRunSummaryLines(info)) {\n console.log(line);\n }\n}\n","import { execa } from 'execa';\nimport type { ClaudeResult } from '../types.js';\nimport { getOutputCallback } from './verbose.js';\n\n/**\n * Execute Claude CLI with a prompt piped to stdin.\n *\n * Runs: echo $PROMPT | claude --dangerously-skip-permissions --print\n *\n * Captures combined stdout+stderr output. Does not throw on non-zero exit codes.\n * Output is returned via ClaudeResult and routed through the output callback infrastructure.\n */\nexport async function executeClaude(prompt: string): Promise<ClaudeResult> {\n const result = await execa('claude', ['--dangerously-skip-permissions', '--print'], {\n input: prompt,\n reject: false,\n timeout: 0, // No timeout — let the engine handle iteration limits\n stripFinalNewline: false,\n });\n\n // Combine stdout and stderr to match Bash's 2>&1 behavior\n const stdout = result.stdout?.toString() ?? '';\n const stderr = result.stderr?.toString() ?? '';\n const output = stdout + (stderr ? `\\n${stderr}` : '');\n\n // Forward output through the global callback (listr2 renderer) when active\n const onOutput = getOutputCallback();\n if (onOutput) {\n const trimmed = output.trim();\n if (trimmed) {\n onOutput(trimmed);\n }\n }\n\n return {\n exitCode: result.exitCode ?? 1,\n output,\n };\n}\n","import { createConfig, resolvePaths, validateDependencies } from '../config.js';\nimport { runEngine } from '../core/engine.js';\nimport { allStoriesPass, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { printError } from '../ui/logger.js';\n\nexport interface ExecuteOptions {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n}\n\nexport async function runExecute(\n positionalMaxIter: number | undefined,\n options: ExecuteOptions,\n): Promise<number> {\n const errors = await validateDependencies();\n if (errors.length > 0) {\n printError('The following required tools are not installed:');\n for (const err of errors) {\n console.log(err);\n }\n return 1;\n }\n\n const maxIterations = options.maxIterations ?? positionalMaxIter;\n\n const config = createConfig({\n issueNumber: options.issue,\n maxIterations,\n retryLimit: options.retryLimit,\n retryForever: options.retryForever,\n });\n\n const paths = await resolvePaths(config);\n const exitCode = await runEngine(config, paths);\n\n // Update pipeline state if all stories pass\n if (exitCode === 0 && config.issueNumber) {\n try {\n const plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan.pipeline.executionCompleted = true;\n await saveTaskPlan(paths.prdFile, plan);\n }\n } catch {\n // Non-critical — engine already handled state\n }\n }\n\n return exitCode;\n}\n"],"mappings":"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","names":["chalk","chalk","elapsed"]}
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- runExecute
4
- } from "./chunk-YXJPKBPV.js";
5
- import "./chunk-HDV3YDTG.js";
6
- import "./chunk-CW6UE3NW.js";
7
- import "./chunk-SLHZPB3C.js";
8
- import "./chunk-OVFYJLOH.js";
9
- import "./chunk-2Y3UO7H2.js";
10
- export {
11
- runExecute
12
- };
13
- //# sourceMappingURL=execute-K5B4UMUT.js.map
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- runInit
4
- } from "./chunk-VLSZFMLZ.js";
5
- import "./chunk-2Y3UO7H2.js";
6
- export {
7
- runInit
8
- };
9
- //# sourceMappingURL=init-W4HBLW7R.js.map
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- runPlan
4
- } from "./chunk-75K5IKAC.js";
5
- import "./chunk-JV7P6UGG.js";
6
- import "./chunk-HS4QWZAO.js";
7
- import "./chunk-HDV3YDTG.js";
8
- import "./chunk-KUDAY57D.js";
9
- import "./chunk-SLHZPB3C.js";
10
- import "./chunk-OVFYJLOH.js";
11
- import "./chunk-2Y3UO7H2.js";
12
- export {
13
- runPlan
14
- };
15
- //# sourceMappingURL=plan-NKPU45NP.js.map
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- runPr
4
- } from "./chunk-UX6YAVLT.js";
5
- import "./chunk-JV7P6UGG.js";
6
- import "./chunk-HS4QWZAO.js";
7
- import "./chunk-HDV3YDTG.js";
8
- import "./chunk-KUDAY57D.js";
9
- import "./chunk-SLHZPB3C.js";
10
- import "./chunk-OVFYJLOH.js";
11
- import "./chunk-2Y3UO7H2.js";
12
- export {
13
- runPr
14
- };
15
- //# sourceMappingURL=pr-JYGLLIEF.js.map