issue-flow 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/{analyze-UZYJAWAP.js → analyze-7B5TORNK.js} +13 -8
  2. package/dist/analyze-7B5TORNK.js.map +1 -0
  3. package/dist/apply-WUJHDD7A.js +788 -0
  4. package/dist/apply-WUJHDD7A.js.map +1 -0
  5. package/dist/{chunk-UUY4PCWW.js → chunk-3BOHTH4V.js} +2 -2
  6. package/dist/chunk-3D4A4B46.js +2 -0
  7. package/dist/{policy-NP4ZAVF6.js → chunk-47VIN33V.js} +82 -112
  8. package/dist/chunk-47VIN33V.js.map +1 -0
  9. package/dist/{chunk-67ZO5ROQ.js → chunk-6N7LZZ5U.js} +19 -13
  10. package/dist/chunk-6N7LZZ5U.js.map +1 -0
  11. package/dist/{chunk-S67Q4I2O.js → chunk-AAY6KM7N.js} +6 -3
  12. package/dist/chunk-AAY6KM7N.js.map +1 -0
  13. package/dist/{chunk-652DJBCN.js → chunk-GANSDJV7.js} +4 -4
  14. package/dist/{chunk-V5OHFSW4.js → chunk-HC2MT7BX.js} +23 -3
  15. package/dist/chunk-HC2MT7BX.js.map +1 -0
  16. package/dist/chunk-HQYXVIH6.js +110 -0
  17. package/dist/chunk-HQYXVIH6.js.map +1 -0
  18. package/dist/{chunk-2LNQL4XH.js → chunk-JW7WLSZ6.js} +15 -11
  19. package/dist/chunk-JW7WLSZ6.js.map +1 -0
  20. package/dist/{chunk-VOKNTBOO.js → chunk-LVKQ2AKT.js} +3 -3
  21. package/dist/{chunk-EWA3OGCM.js → chunk-MKD2D7WE.js} +12 -8
  22. package/dist/chunk-MKD2D7WE.js.map +1 -0
  23. package/dist/{chunk-UH4KAJBJ.js → chunk-MSPUB635.js} +15 -11
  24. package/dist/chunk-MSPUB635.js.map +1 -0
  25. package/dist/chunk-OBLVLIUS.js +285 -0
  26. package/dist/chunk-OBLVLIUS.js.map +1 -0
  27. package/dist/{chunk-MXTGCD5C.js → chunk-PL6CNMVS.js} +2 -2
  28. package/dist/chunk-RKTEV6EG.js +246 -0
  29. package/dist/chunk-RKTEV6EG.js.map +1 -0
  30. package/dist/{chunk-SP7DD4ID.js → chunk-UBIQXCVE.js} +15 -11
  31. package/dist/chunk-UBIQXCVE.js.map +1 -0
  32. package/dist/{chunk-2Z7OEZZT.js → chunk-VCKX262Z.js} +12 -8
  33. package/dist/chunk-VCKX262Z.js.map +1 -0
  34. package/dist/{chunk-VYFKOUUR.js → chunk-VQ5VN7DF.js} +9 -5
  35. package/dist/chunk-VQ5VN7DF.js.map +1 -0
  36. package/dist/cli.js +26 -22
  37. package/dist/cli.js.map +1 -1
  38. package/dist/{config-YCF3HIKR.js → config-4THHOXNN.js} +3 -3
  39. package/dist/execute-5OEKLM5X.js +15 -0
  40. package/dist/{generate-TW6QKSW5.js → generate-6RA2MFJB.js} +99 -12
  41. package/dist/generate-6RA2MFJB.js.map +1 -0
  42. package/dist/init-PRMOTQ7N.js +9 -0
  43. package/dist/plan-KENR6MJ3.js +17 -0
  44. package/dist/policy-XQW5NUIE.js +117 -0
  45. package/dist/policy-XQW5NUIE.js.map +1 -0
  46. package/dist/pr-KDGKG4BP.js +21 -0
  47. package/dist/pr-review-CAMAB7KO.js +17 -0
  48. package/dist/prd-V3MWDIHK.js +17 -0
  49. package/dist/review-7LN47SAN.js +15 -0
  50. package/dist/review-7LN47SAN.js.map +1 -0
  51. package/dist/{run-DIBC3YKX.js → run-H75MD5BQ.js} +26 -25
  52. package/dist/{run-DIBC3YKX.js.map → run-H75MD5BQ.js.map} +1 -1
  53. package/dist/{web-O2FVOYZW.js → web-ANQQTTRD.js} +5 -5
  54. package/package.json +1 -1
  55. package/prompts/analyze.md +24 -0
  56. package/prompts/execute.md +29 -1
  57. package/prompts/generate.md +61 -7
  58. package/prompts/plan.md +24 -1
  59. package/prompts/pr-review.md +65 -4
  60. package/prompts/pr.md +37 -3
  61. package/prompts/prd.md +17 -0
  62. package/prompts/review.md +40 -0
  63. package/dist/analyze-UZYJAWAP.js.map +0 -1
  64. package/dist/chunk-2LNQL4XH.js.map +0 -1
  65. package/dist/chunk-2Z7OEZZT.js.map +0 -1
  66. package/dist/chunk-67ZO5ROQ.js.map +0 -1
  67. package/dist/chunk-EWA3OGCM.js.map +0 -1
  68. package/dist/chunk-EZMOEBLU.js +0 -135
  69. package/dist/chunk-EZMOEBLU.js.map +0 -1
  70. package/dist/chunk-PPLIXZI5.js +0 -101
  71. package/dist/chunk-PPLIXZI5.js.map +0 -1
  72. package/dist/chunk-S67Q4I2O.js.map +0 -1
  73. package/dist/chunk-SLHZPB3C.js +0 -50
  74. package/dist/chunk-SLHZPB3C.js.map +0 -1
  75. package/dist/chunk-SP7DD4ID.js.map +0 -1
  76. package/dist/chunk-UH4KAJBJ.js.map +0 -1
  77. package/dist/chunk-V5OHFSW4.js.map +0 -1
  78. package/dist/chunk-VYFKOUUR.js.map +0 -1
  79. package/dist/execute-QYXA225W.js +0 -14
  80. package/dist/generate-TW6QKSW5.js.map +0 -1
  81. package/dist/init-G57UXKDG.js +0 -9
  82. package/dist/plan-YJLGBYBQ.js +0 -16
  83. package/dist/policy-NP4ZAVF6.js.map +0 -1
  84. package/dist/pr-V5H65MRW.js +0 -20
  85. package/dist/pr-review-RCMXKXVP.js +0 -16
  86. package/dist/prd-3XR5KYJS.js +0 -16
  87. package/dist/review-ZZG3CSUO.js +0 -14
  88. /package/dist/{chunk-UUY4PCWW.js.map → chunk-3BOHTH4V.js.map} +0 -0
  89. /package/dist/{config-YCF3HIKR.js.map → chunk-3D4A4B46.js.map} +0 -0
  90. /package/dist/{chunk-652DJBCN.js.map → chunk-GANSDJV7.js.map} +0 -0
  91. /package/dist/{chunk-VOKNTBOO.js.map → chunk-LVKQ2AKT.js.map} +0 -0
  92. /package/dist/{chunk-MXTGCD5C.js.map → chunk-PL6CNMVS.js.map} +0 -0
  93. /package/dist/{execute-QYXA225W.js.map → config-4THHOXNN.js.map} +0 -0
  94. /package/dist/{init-G57UXKDG.js.map → execute-5OEKLM5X.js.map} +0 -0
  95. /package/dist/{plan-YJLGBYBQ.js.map → init-PRMOTQ7N.js.map} +0 -0
  96. /package/dist/{pr-V5H65MRW.js.map → plan-KENR6MJ3.js.map} +0 -0
  97. /package/dist/{pr-review-RCMXKXVP.js.map → pr-KDGKG4BP.js.map} +0 -0
  98. /package/dist/{prd-3XR5KYJS.js.map → pr-review-CAMAB7KO.js.map} +0 -0
  99. /package/dist/{review-ZZG3CSUO.js.map → prd-V3MWDIHK.js.map} +0 -0
  100. /package/dist/{web-O2FVOYZW.js.map → web-ANQQTTRD.js.map} +0 -0
  101. /package/web/{CLAUDE.md → AGENTS.md} +0 -0
@@ -1,29 +1,38 @@
1
1
  #!/usr/bin/env node
2
+ import "./chunk-3D4A4B46.js";
2
3
  import {
3
4
  ensureProvidersRegistered,
4
5
  getProvider,
5
6
  localIssueRef
6
- } from "./chunk-S67Q4I2O.js";
7
+ } from "./chunk-AAY6KM7N.js";
7
8
  import {
8
9
  runHeadless
9
- } from "./chunk-MXTGCD5C.js";
10
+ } from "./chunk-PL6CNMVS.js";
10
11
  import {
11
- publishPhaseMetrics
12
- } from "./chunk-PPLIXZI5.js";
12
+ publishPhaseMetrics,
13
+ resolvePolicyPlaceholders
14
+ } from "./chunk-OBLVLIUS.js";
13
15
  import {
14
16
  applyPlaceholders,
15
17
  loadPrompt
16
- } from "./chunk-SLHZPB3C.js";
18
+ } from "./chunk-HQYXVIH6.js";
19
+ import {
20
+ loadRepositoryPolicy
21
+ } from "./chunk-47VIN33V.js";
17
22
  import {
18
23
  loadIssuesConfig,
19
- resolveProjectPaths
20
- } from "./chunk-VYFKOUUR.js";
24
+ loadPolicyConfig,
25
+ resolveProjectPaths,
26
+ run
27
+ } from "./chunk-VQ5VN7DF.js";
21
28
  import {
22
29
  getGlobalTimeout,
23
30
  isoNow,
24
31
  printError,
25
- printSuccess
26
- } from "./chunk-V5OHFSW4.js";
32
+ printInfo,
33
+ printSuccess,
34
+ printWarning
35
+ } from "./chunk-HC2MT7BX.js";
27
36
 
28
37
  // src/issues/draft.ts
29
38
  var DRAFT_TAG = "issue-draft";
@@ -62,7 +71,51 @@ function parseIssueDraft(output) {
62
71
  if (body.length === 0) {
63
72
  throw new IssueDraftParseError(`The <${DRAFT_TAG}> block has no <body>.`);
64
73
  }
65
- return { title, body, labels: parseLabels(extractTag(block, "labels")) };
74
+ const type = (extractTag(block, "type") ?? "").trim();
75
+ const template = (extractTag(block, "template") ?? "").trim();
76
+ return {
77
+ title,
78
+ body,
79
+ labels: parseLabels(extractTag(block, "labels")),
80
+ ...type === "" || type.toLowerCase() === "(none)" ? {} : { type },
81
+ ...template === "" || template.toLowerCase() === "(none)" ? {} : { template }
82
+ };
83
+ }
84
+
85
+ // src/issues/label-policy.ts
86
+ function reconcileLabels(suggested, known) {
87
+ if (known.length === 0) {
88
+ return { labels: [...suggested], missing: [] };
89
+ }
90
+ const canonical = new Map(known.map((label) => [label.name.toLowerCase(), label.name]));
91
+ const labels = [];
92
+ const missing = [];
93
+ for (const suggestion of suggested) {
94
+ const match = canonical.get(suggestion.trim().toLowerCase());
95
+ if (match === void 0) {
96
+ if (!missing.includes(suggestion)) missing.push(suggestion);
97
+ continue;
98
+ }
99
+ if (!labels.includes(match)) labels.push(match);
100
+ }
101
+ return { labels, missing };
102
+ }
103
+ async function createMissingLabels(names, warn) {
104
+ const created = [];
105
+ for (const name of names) {
106
+ const result = await run("gh", ["label", "create", name]);
107
+ if (result.exitCode === 0) {
108
+ created.push(name);
109
+ continue;
110
+ }
111
+ const detail = (result.stderr || result.stdout).trim();
112
+ if (/already exists/i.test(detail)) {
113
+ created.push(name);
114
+ continue;
115
+ }
116
+ warn(`Could not create label "${name}": ${detail || "gh label create failed"}`);
117
+ }
118
+ return created;
66
119
  }
67
120
 
68
121
  // src/commands/generate.ts
@@ -73,6 +126,9 @@ async function draftIssue(promptText) {
73
126
  const { issuesDir } = await resolveProjectPaths();
74
127
  const template = await loadPrompt("generate");
75
128
  const prompt = applyPlaceholders(template, {
129
+ // The repository's own conventions. Empty when it declares none, which is
130
+ // what keeps the rendered prompt identical to the pre-policy one.
131
+ ...await resolvePolicyPlaceholders(),
76
132
  __USER_PROMPT__: promptText,
77
133
  __LOCAL_ISSUES_DIR__: issuesDir
78
134
  });
@@ -123,6 +179,30 @@ async function createIssues(target, draft) {
123
179
  }
124
180
  return [await getProvider(target).create(draft)];
125
181
  }
182
+ async function applyLabelPolicy(draft) {
183
+ let known;
184
+ let allowCreation;
185
+ try {
186
+ const policy = await loadRepositoryPolicy();
187
+ known = policy.issues.labels;
188
+ const config = await loadPolicyConfig({ projectRoot: policy.root });
189
+ allowCreation = config.issues.allowLabelCreation ?? false;
190
+ } catch {
191
+ return draft;
192
+ }
193
+ const { labels, missing } = reconcileLabels(draft.labels, known);
194
+ if (missing.length === 0) {
195
+ return { ...draft, labels };
196
+ }
197
+ if (!allowCreation) {
198
+ printWarning(
199
+ `Dropping ${missing.length} label(s) this repository does not have: ${missing.join(", ")}. Issue Flow does not create labels; set policy.issues.allowLabelCreation to change that.`
200
+ );
201
+ return { ...draft, labels };
202
+ }
203
+ const created = await createMissingLabels(missing, printWarning);
204
+ return { ...draft, labels: [...labels, ...created] };
205
+ }
126
206
  async function runGenerate(promptText, target) {
127
207
  const config = await loadIssuesConfig();
128
208
  const destination = target ?? config.defaultGenerateTarget;
@@ -138,9 +218,16 @@ async function runGenerate(promptText, target) {
138
218
  }
139
219
  return 1;
140
220
  }
221
+ const finalDraft = await applyLabelPolicy(draft);
222
+ if (finalDraft.template !== void 0) {
223
+ printInfo(`Following the repository's Issue Template: ${finalDraft.template}`);
224
+ }
225
+ if (finalDraft.type !== void 0) {
226
+ printInfo(`Issue Type: ${finalDraft.type}`);
227
+ }
141
228
  let created;
142
229
  try {
143
- created = await createIssues(destination, draft);
230
+ created = await createIssues(destination, finalDraft);
144
231
  } catch (err) {
145
232
  printError(err instanceof Error ? err.message : String(err));
146
233
  return 1;
@@ -153,4 +240,4 @@ async function runGenerate(promptText, target) {
153
240
  export {
154
241
  runGenerate
155
242
  };
156
- //# sourceMappingURL=generate-TW6QKSW5.js.map
243
+ //# sourceMappingURL=generate-6RA2MFJB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/issues/draft.ts","../src/issues/label-policy.ts","../src/commands/generate.ts"],"sourcesContent":["import type { IssueDraft } from './types.js';\n\n/**\n * Structured Issue draft emitted by the `generate` prompt.\n *\n * The agent no longer creates the Issue itself: it returns the content and the\n * providers persist it, so the same draft can reach GitHub, the local files, or\n * both. Capturing the result therefore has to be exact — the old approach of\n * fishing an issue URL out of free-form prose only ever worked for GitHub.\n *\n * The block mirrors the `<issue-body>` convention already used by the phase\n * templates, which keeps a multi-line markdown body readable and free of the\n * escaping a JSON payload would demand.\n */\n\n/** Wrapper the agent must emit around the draft. */\nexport const DRAFT_TAG = 'issue-draft';\n\n/** Failure to capture a draft from the agent output. */\nexport class IssueDraftParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'IssueDraftParseError';\n }\n}\n\n/**\n * Last occurrence of `<tag>...</tag>` in `source`, or `null`.\n *\n * The last one wins: an agent that shows the format before filling it in (or\n * restates the draft after a correction) would otherwise have its first,\n * throwaway attempt captured. The closing tag is searched from the end for the\n * same reason a body may legitimately quote one.\n */\nfunction extractTag(source: string, tag: string): string | null {\n const open = `<${tag}>`;\n const close = `</${tag}>`;\n\n const start = source.lastIndexOf(open);\n if (start === -1) return null;\n\n const end = source.lastIndexOf(close);\n if (end === -1 || end < start) return null;\n\n return source.slice(start + open.length, end);\n}\n\nfunction parseLabels(raw: string | null): string[] {\n if (raw === null) return [];\n return raw\n .split(',')\n .map((label) => label.trim())\n .filter((label) => label.length > 0 && label.toLowerCase() !== '(none)');\n}\n\n/**\n * Read the draft the agent produced.\n *\n * @throws IssueDraftParseError when the block is absent or has no usable\n * title/body, so a malformed answer fails loudly instead of creating an empty\n * Issue.\n */\nexport function parseIssueDraft(output: string): IssueDraft {\n const normalized = output.replace(/\\r\\n?/g, '\\n');\n const block = extractTag(normalized, DRAFT_TAG);\n\n if (block === null) {\n throw new IssueDraftParseError(\n `The agent did not emit an <${DRAFT_TAG}> block, so there is no Issue to create. ` +\n `Output was: ${normalized.trim().slice(0, 300) || '(empty)'}`,\n );\n }\n\n const title = (extractTag(block, 'title') ?? '').trim();\n const body = (extractTag(block, 'body') ?? '').trim();\n\n if (title.length === 0) {\n throw new IssueDraftParseError(`The <${DRAFT_TAG}> block has no <title>.`);\n }\n if (body.length === 0) {\n throw new IssueDraftParseError(`The <${DRAFT_TAG}> block has no <body>.`);\n }\n\n // Optional, and deliberately so: a repository with no Issue Types and no\n // templates emits neither, and the draft is exactly what it was before.\n const type = (extractTag(block, 'type') ?? '').trim();\n const template = (extractTag(block, 'template') ?? '').trim();\n\n return {\n title,\n body,\n labels: parseLabels(extractTag(block, 'labels')),\n ...(type === '' || type.toLowerCase() === '(none)' ? {} : { type }),\n ...(template === '' || template.toLowerCase() === '(none)' ? {} : { template }),\n };\n}\n","import type { LabelDefinition } from '../policy/types.js';\nimport { run } from '../utils/shell.js';\n\n/**\n * Reconciling the labels an agent suggested with the ones the repository\n * actually has.\n *\n * A workflow tool has no business changing a repository's taxonomy. Labels are\n * governance: a team that deleted `high`/`medium`/`low` in favour of a native\n * priority field, or `bug`/`enhancement` in favour of Issue Types, made a\n * decision — and a generator that silently recreates them undoes it, quietly and\n * repository-wide.\n *\n * So the default is to **validate, never create**. `policy.issues.allowLabelCreation`\n * restores the old behaviour for repositories that want it.\n */\n\nexport interface LabelReconciliation {\n /** Labels to apply, in the repository's own casing. */\n labels: string[];\n /** Suggested labels the repository does not have. */\n missing: string[];\n}\n\n/**\n * Intersect the suggested labels with the repository's real ones.\n *\n * Matching is case-insensitive and the result carries the **repository's**\n * casing: `gh issue create --label Bug` fails on a repository whose label is\n * `bug`, and an agent has no way to know which one it is.\n *\n * An empty `known` means the labels could not be read at all — no policy, no\n * `gh`, no network. That is not evidence the labels do not exist, so the\n * suggestions pass through untouched and the behaviour is the one that shipped\n * before this layer. Refusing to label an issue because discovery was offline\n * would be the wrong failure.\n */\nexport function reconcileLabels(\n suggested: string[],\n known: LabelDefinition[],\n): LabelReconciliation {\n if (known.length === 0) {\n return { labels: [...suggested], missing: [] };\n }\n\n const canonical = new Map(known.map((label) => [label.name.toLowerCase(), label.name]));\n\n const labels: string[] = [];\n const missing: string[] = [];\n for (const suggestion of suggested) {\n const match = canonical.get(suggestion.trim().toLowerCase());\n if (match === undefined) {\n if (!missing.includes(suggestion)) missing.push(suggestion);\n continue;\n }\n if (!labels.includes(match)) labels.push(match);\n }\n\n return { labels, missing };\n}\n\n/**\n * Create the labels the repository is missing, for\n * `policy.issues.allowLabelCreation: true`.\n *\n * Best-effort per label: one that cannot be created is reported and skipped, so\n * a single failure does not cost the Issue. Returns the labels that now exist.\n */\nexport async function createMissingLabels(\n names: string[],\n warn: (message: string) => void,\n): Promise<string[]> {\n const created: string[] = [];\n\n for (const name of names) {\n const result = await run('gh', ['label', 'create', name]);\n if (result.exitCode === 0) {\n created.push(name);\n continue;\n }\n // gh answers \"already exists\" when a label was created between the\n // discovery and now, which is a success for our purposes.\n const detail = (result.stderr || result.stdout).trim();\n if (/already exists/i.test(detail)) {\n created.push(name);\n continue;\n }\n warn(`Could not create label \"${name}\": ${detail || 'gh label create failed'}`);\n }\n\n return created;\n}\n","import { loadIssuesConfig, loadPolicyConfig } from '../config.js';\nimport { runHeadless } from '../core/headless.js';\nimport { applyPlaceholders, loadPrompt } from '../core/prompt-resolver.js';\nimport { publishPhaseMetrics } from '../core/session-metrics.js';\nimport { isoNow } from '../core/state-manager.js';\nimport { getGlobalTimeout } from '../core/verbose.js';\nimport { ensureProvidersRegistered } from '../issues/bootstrap.js';\nimport { localIssueRef } from '../issues/context.js';\nimport { IssueDraftParseError, parseIssueDraft } from '../issues/draft.js';\nimport { createMissingLabels, reconcileLabels } from '../issues/label-policy.js';\nimport { getProvider } from '../issues/registry.js';\nimport type { Issue, IssueDraft, IssueGenerateTarget } from '../issues/types.js';\nimport { loadRepositoryPolicy } from '../policy/index.js';\nimport { resolvePolicyPlaceholders } from '../policy/placeholders.js';\nimport { resolveProjectPaths } from '../storage/resolve.js';\nimport { printError, printInfo, printSuccess, printWarning } from '../ui/logger.js';\n\n/** Human-readable pointer to a created Issue. */\nfunction issueLocation(issue: Issue): string {\n return issue.remoteRef ?? localIssueRef(issue.id);\n}\n\n/**\n * Ask the agent for the Issue content.\n *\n * The agent only drafts: creation belongs to the providers, so the same draft\n * can be persisted to GitHub, to the local files, or to both.\n */\nasync function draftIssue(promptText: string): Promise<IssueDraft> {\n // The duplicate check reads the local issues, which live in the global\n // storage: the path has to be handed over (and allowed) explicitly, since it\n // is outside the working directory the agent is started in.\n const { issuesDir } = await resolveProjectPaths();\n\n const template = await loadPrompt('generate');\n const prompt = applyPlaceholders(template, {\n // The repository's own conventions. Empty when it declares none, which is\n // what keeps the rendered prompt identical to the pre-policy one.\n ...(await resolvePolicyPlaceholders()),\n __USER_PROMPT__: promptText,\n __LOCAL_ISSUES_DIR__: issuesDir,\n });\n\n const startedAtMs = Date.now();\n const result = await runHeadless({\n prompt,\n maxTurns: 15,\n timeout: getGlobalTimeout() ?? 300_000,\n // json (not text) so the CLI reports usage: the envelope's `result` field\n // carries the same assistant text parseIssueDraft() already consumed.\n outputFormat: 'json',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep'],\n addDirs: [issuesDir],\n statusMessage: 'Drafting issue...',\n });\n // Before the success check: the tokens were spent either way.\n publishPhaseMetrics('generate', result.cost, startedAtMs);\n\n if (!result.success) {\n throw new Error(`Issue creation failed: ${result.error}`);\n }\n\n return parseIssueDraft(result.result);\n}\n\n/**\n * Create the GitHub Issue and mirror it locally.\n *\n * The remote comes first on purpose: it owns the identifier, and the mirror has\n * to reuse it so both copies describe one demand. A remote failure therefore\n * leaves nothing behind, and a mirror failure is reported with the remote\n * reference that already exists.\n */\nasync function createBoth(draft: IssueDraft): Promise<Issue[]> {\n const remote = await getProvider('github').create(draft);\n\n try {\n const mirror = await getProvider('local').create({\n ...draft,\n id: remote.id,\n ...(remote.remoteRef\n ? {\n remote: {\n provider: 'github' as const,\n ref: remote.remoteRef,\n syncedAt: isoNow(),\n syncedContentHash: remote.contentHash,\n },\n }\n : {}),\n });\n return [remote, mirror];\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `GitHub issue created at ${issueLocation(remote)}, but the local mirror was not written: ` +\n `${message}. Nothing else was persisted; re-run with --local to create the mirror.`,\n );\n }\n}\n\nasync function createIssues(target: IssueGenerateTarget, draft: IssueDraft): Promise<Issue[]> {\n if (target === 'both') {\n return createBoth(draft);\n }\n return [await getProvider(target).create(draft)];\n}\n\n/**\n * Reconcile the draft's labels with the ones the repository really has.\n *\n * Two failures are being prevented here, and only one of them is cosmetic.\n * GitHub rejects an issue whose label does not exist, so an invented label costs\n * the whole Issue. And a tool that creates the label instead rewrites a taxonomy\n * the team may have curated deliberately — which is worse, because it succeeds.\n *\n * Never throws: a policy that could not be resolved leaves the draft untouched.\n */\nasync function applyLabelPolicy(draft: IssueDraft): Promise<IssueDraft> {\n let known: Awaited<ReturnType<typeof loadRepositoryPolicy>>['issues']['labels'];\n let allowCreation: boolean;\n try {\n const policy = await loadRepositoryPolicy();\n known = policy.issues.labels;\n const config = await loadPolicyConfig({ projectRoot: policy.root });\n allowCreation = config.issues.allowLabelCreation ?? false;\n } catch {\n return draft;\n }\n\n const { labels, missing } = reconcileLabels(draft.labels, known);\n if (missing.length === 0) {\n return { ...draft, labels };\n }\n\n if (!allowCreation) {\n printWarning(\n `Dropping ${missing.length} label(s) this repository does not have: ${missing.join(', ')}. ` +\n 'Issue Flow does not create labels; set policy.issues.allowLabelCreation to change that.',\n );\n return { ...draft, labels };\n }\n\n const created = await createMissingLabels(missing, printWarning);\n return { ...draft, labels: [...labels, ...created] };\n}\n\nexport async function runGenerate(\n promptText: string,\n target?: IssueGenerateTarget,\n): Promise<number> {\n const config = await loadIssuesConfig();\n const destination = target ?? config.defaultGenerateTarget;\n\n ensureProvidersRegistered();\n\n let draft: IssueDraft;\n try {\n draft = await draftIssue(promptText);\n } catch (err) {\n if (err instanceof IssueDraftParseError) {\n printError(`Could not read the generated Issue draft: ${err.message}`);\n } else {\n printError(err instanceof Error ? err.message : String(err));\n }\n return 1;\n }\n\n const finalDraft = await applyLabelPolicy(draft);\n if (finalDraft.template !== undefined) {\n printInfo(`Following the repository's Issue Template: ${finalDraft.template}`);\n }\n if (finalDraft.type !== undefined) {\n printInfo(`Issue Type: ${finalDraft.type}`);\n }\n\n let created: Issue[];\n try {\n created = await createIssues(destination, finalDraft);\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n return 1;\n }\n\n for (const issue of created) {\n printSuccess(`Issue created (${issue.source}): ${issueLocation(issue)}`);\n }\n return 0;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runInit
4
+ } from "./chunk-RKTEV6EG.js";
5
+ import "./chunk-HC2MT7BX.js";
6
+ export {
7
+ runInit
8
+ };
9
+ //# sourceMappingURL=init-PRMOTQ7N.js.map
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPlan
4
+ } from "./chunk-UBIQXCVE.js";
5
+ import "./chunk-3BOHTH4V.js";
6
+ import "./chunk-AAY6KM7N.js";
7
+ import "./chunk-PL6CNMVS.js";
8
+ import "./chunk-HDV3YDTG.js";
9
+ import "./chunk-OBLVLIUS.js";
10
+ import "./chunk-HQYXVIH6.js";
11
+ import "./chunk-47VIN33V.js";
12
+ import "./chunk-VQ5VN7DF.js";
13
+ import "./chunk-HC2MT7BX.js";
14
+ export {
15
+ runPlan
16
+ };
17
+ //# sourceMappingURL=plan-KENR6MJ3.js.map
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-3D4A4B46.js";
3
+ import {
4
+ loadRepositoryPolicy
5
+ } from "./chunk-47VIN33V.js";
6
+ import "./chunk-VQ5VN7DF.js";
7
+ import {
8
+ printError,
9
+ printInfo,
10
+ printWarning
11
+ } from "./chunk-HC2MT7BX.js";
12
+
13
+ // src/commands/policy.ts
14
+ function groupSources(sources) {
15
+ const grouped = /* @__PURE__ */ new Map();
16
+ for (const source of sources) {
17
+ const bucket = grouped.get(source.kind);
18
+ if (bucket === void 0) {
19
+ grouped.set(source.kind, [source]);
20
+ } else {
21
+ bucket.push(source);
22
+ }
23
+ }
24
+ return grouped;
25
+ }
26
+ function describeSource(source) {
27
+ const where = source.path ?? source.origin;
28
+ const detail = source.detail === null ? "" : ` \u2014 ${source.detail}`;
29
+ return `${source.status === "found" ? "" : `[${source.status}] `}${where}${detail}`;
30
+ }
31
+ function render(policy) {
32
+ const lines = [];
33
+ const push = (line = "") => {
34
+ lines.push(line);
35
+ };
36
+ push(`Repository: ${policy.root}`);
37
+ push(`Scope: ${policy.scope ?? "(root)"}`);
38
+ if (!policy.enabled) {
39
+ push();
40
+ push("Policy discovery is disabled (policy.enabled = false).");
41
+ console.log(lines.join("\n"));
42
+ return;
43
+ }
44
+ push();
45
+ push("Issues");
46
+ push(` templates: ${policy.issues.templates.length}`);
47
+ for (const template of policy.issues.templates) {
48
+ const labels = template.labels.length > 0 ? ` labels=[${template.labels.join(", ")}]` : "";
49
+ const type = template.type === null ? "" : ` type=${template.type}`;
50
+ push(` - ${template.path} (${template.format}, ${template.origin})${type}${labels}`);
51
+ }
52
+ push(` types: ${policy.issues.types.length > 0 ? policy.issues.types.join(", ") : "(none)"}`);
53
+ push(` labels: ${policy.issues.labels.length}`);
54
+ for (const label of policy.issues.labels) {
55
+ push(` - ${label.name}${label.description === null ? "" : ` \u2014 ${label.description}`}`);
56
+ }
57
+ push(` titleConvention: ${policy.issues.titleConvention ?? "(none)"}`);
58
+ push();
59
+ push("Pull Requests");
60
+ push(` template: ${policy.pullRequests.templates[0]?.path ?? "(none)"}`);
61
+ for (const template of policy.pullRequests.templates.slice(1)) {
62
+ push(` - ${template.path}`);
63
+ }
64
+ push(` baseBranch: ${policy.pullRequests.baseBranch ?? "(none)"}`);
65
+ push(` titleConvention: ${policy.pullRequests.titleConvention ?? "(none)"}`);
66
+ push();
67
+ push("Git");
68
+ push(` branchConvention: ${policy.git.branchConvention ?? "(none)"}`);
69
+ push(` commitConvention: ${policy.git.commitConvention ?? "(none)"}`);
70
+ push();
71
+ push(`Documents: ${policy.docs.length}`);
72
+ for (const doc of policy.docs) {
73
+ const scope = doc.scope === "" ? "root" : doc.scope;
74
+ const from = doc.referencedFrom === null ? "" : ` \u2190 ${doc.referencedFrom}`;
75
+ push(` - ${doc.path} (${doc.kind}, scope=${scope})${from}`);
76
+ }
77
+ push();
78
+ push(`CODEOWNERS: ${policy.codeowners === null ? "(none)" : "found"}`);
79
+ push();
80
+ push("Sources");
81
+ for (const [kind, entries] of groupSources(policy.sources)) {
82
+ push(` ${kind}`);
83
+ for (const entry of entries) {
84
+ push(` - ${describeSource(entry)}`);
85
+ }
86
+ }
87
+ console.log(lines.join("\n"));
88
+ }
89
+ async function runPolicy(options = {}) {
90
+ let policy;
91
+ try {
92
+ policy = await loadRepositoryPolicy({ scope: options.scope ?? null });
93
+ } catch (err) {
94
+ printError(err instanceof Error ? err.message : String(err));
95
+ return 1;
96
+ }
97
+ if (options.json === true) {
98
+ console.log(JSON.stringify(policy, null, 2));
99
+ return 0;
100
+ }
101
+ render(policy);
102
+ const unavailable = policy.sources.filter((source) => source.status === "unavailable");
103
+ if (unavailable.length > 0) {
104
+ console.log("");
105
+ printWarning(
106
+ `${unavailable.length} source(s) could not be consulted; the policy above is incomplete.`
107
+ );
108
+ } else if (policy.sources.length === 0) {
109
+ console.log("");
110
+ printInfo("This repository declares no policy sources; Issue Flow defaults apply.");
111
+ }
112
+ return 0;
113
+ }
114
+ export {
115
+ runPolicy
116
+ };
117
+ //# sourceMappingURL=policy-XQW5NUIE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/policy.ts"],"sourcesContent":["import type { PolicySource, RepositoryPolicy } from '../policy/index.js';\nimport { loadRepositoryPolicy } from '../policy/index.js';\nimport { printError, printInfo, printWarning } from '../ui/logger.js';\n\n/**\n * `issue-flow policy [--scope <dir>] [--json]`.\n *\n * The inspection surface of the policy layer, and the only one for now: this\n * issue delivers the foundation, so no prompt and no skill consumes\n * `loadRepositoryPolicy()` yet.\n *\n * It exists for two audiences. A human debugging a wrong discovery reads the\n * default output, where every section names the files it came from. The Agent\n * Skills read `--json`: they are markdown and cannot import TypeScript, so a\n * versioned JSON document on stdout is the only bridge available to them —\n * which is why `schemaVersion` is part of the payload rather than of the CLI.\n *\n * That makes `--json` a **published contract**, not a debugging convenience.\n * `skills/_shared/repository-policy.md` documents the payload, and\n * `policy-parity.test.ts` pins the fields the skills read: renaming or dropping\n * one silently makes every skill fall back to its defaults, and nothing would\n * fail — the two paths would simply start deciding differently. Adding a field\n * is safe (readers ignore what they do not know); removing or renaming one\n * bumps `schemaVersion`.\n */\n\nexport interface PolicyCommandOptions {\n scope?: string;\n json?: boolean;\n}\n\n/** Group the provenance entries by kind, preserving discovery order. */\nfunction groupSources(sources: PolicySource[]): Map<PolicySource['kind'], PolicySource[]> {\n const grouped = new Map<PolicySource['kind'], PolicySource[]>();\n for (const source of sources) {\n const bucket = grouped.get(source.kind);\n if (bucket === undefined) {\n grouped.set(source.kind, [source]);\n } else {\n bucket.push(source);\n }\n }\n return grouped;\n}\n\nfunction describeSource(source: PolicySource): string {\n const where = source.path ?? source.origin;\n const detail = source.detail === null ? '' : ` — ${source.detail}`;\n return `${source.status === 'found' ? '' : `[${source.status}] `}${where}${detail}`;\n}\n\n/**\n * Human-readable rendering.\n *\n * Content is deliberately never printed: a resolved policy carries whole\n * `AGENTS.md` and template bodies, and dumping them would bury the one thing\n * this view is for — which file each value came from. `--json` is where the\n * content lives.\n */\nfunction render(policy: RepositoryPolicy): void {\n const lines: string[] = [];\n const push = (line = ''): void => {\n lines.push(line);\n };\n\n push(`Repository: ${policy.root}`);\n push(`Scope: ${policy.scope ?? '(root)'}`);\n if (!policy.enabled) {\n push();\n push('Policy discovery is disabled (policy.enabled = false).');\n console.log(lines.join('\\n'));\n return;\n }\n\n push();\n push('Issues');\n push(` templates: ${policy.issues.templates.length}`);\n for (const template of policy.issues.templates) {\n const labels = template.labels.length > 0 ? ` labels=[${template.labels.join(', ')}]` : '';\n const type = template.type === null ? '' : ` type=${template.type}`;\n push(` - ${template.path} (${template.format}, ${template.origin})${type}${labels}`);\n }\n push(` types: ${policy.issues.types.length > 0 ? policy.issues.types.join(', ') : '(none)'}`);\n push(` labels: ${policy.issues.labels.length}`);\n for (const label of policy.issues.labels) {\n push(` - ${label.name}${label.description === null ? '' : ` — ${label.description}`}`);\n }\n push(` titleConvention: ${policy.issues.titleConvention ?? '(none)'}`);\n\n push();\n push('Pull Requests');\n push(` template: ${policy.pullRequests.templates[0]?.path ?? '(none)'}`);\n for (const template of policy.pullRequests.templates.slice(1)) {\n push(` - ${template.path}`);\n }\n push(` baseBranch: ${policy.pullRequests.baseBranch ?? '(none)'}`);\n push(` titleConvention: ${policy.pullRequests.titleConvention ?? '(none)'}`);\n\n push();\n push('Git');\n push(` branchConvention: ${policy.git.branchConvention ?? '(none)'}`);\n push(` commitConvention: ${policy.git.commitConvention ?? '(none)'}`);\n\n push();\n push(`Documents: ${policy.docs.length}`);\n for (const doc of policy.docs) {\n const scope = doc.scope === '' ? 'root' : doc.scope;\n const from = doc.referencedFrom === null ? '' : ` ← ${doc.referencedFrom}`;\n push(` - ${doc.path} (${doc.kind}, scope=${scope})${from}`);\n }\n\n push();\n push(`CODEOWNERS: ${policy.codeowners === null ? '(none)' : 'found'}`);\n\n push();\n push('Sources');\n for (const [kind, entries] of groupSources(policy.sources)) {\n push(` ${kind}`);\n for (const entry of entries) {\n push(` - ${describeSource(entry)}`);\n }\n }\n\n console.log(lines.join('\\n'));\n}\n\n/**\n * Resolve and print the repository policy. Returns the process exit code.\n *\n * Only a repository that cannot be located at all is a failure: an empty policy\n * is a legitimate — and common — answer, printed like any other.\n */\nexport async function runPolicy(options: PolicyCommandOptions = {}): Promise<number> {\n let policy: RepositoryPolicy;\n try {\n policy = await loadRepositoryPolicy({ scope: options.scope ?? null });\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n return 1;\n }\n\n if (options.json === true) {\n console.log(JSON.stringify(policy, null, 2));\n return 0;\n }\n\n render(policy);\n\n const unavailable = policy.sources.filter((source) => source.status === 'unavailable');\n if (unavailable.length > 0) {\n console.log('');\n printWarning(\n `${unavailable.length} source(s) could not be consulted; the policy above is incomplete.`,\n );\n } else if (policy.sources.length === 0) {\n console.log('');\n printInfo('This repository declares no policy sources; Issue Flow defaults apply.');\n }\n\n return 0;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ issueClosesLines,
4
+ multiIssueContext,
5
+ runPr
6
+ } from "./chunk-JW7WLSZ6.js";
7
+ import "./chunk-3BOHTH4V.js";
8
+ import "./chunk-AAY6KM7N.js";
9
+ import "./chunk-PL6CNMVS.js";
10
+ import "./chunk-HDV3YDTG.js";
11
+ import "./chunk-OBLVLIUS.js";
12
+ import "./chunk-HQYXVIH6.js";
13
+ import "./chunk-47VIN33V.js";
14
+ import "./chunk-VQ5VN7DF.js";
15
+ import "./chunk-HC2MT7BX.js";
16
+ export {
17
+ issueClosesLines,
18
+ multiIssueContext,
19
+ runPr
20
+ };
21
+ //# sourceMappingURL=pr-KDGKG4BP.js.map
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ exitCodeFor,
4
+ runPrReview
5
+ } from "./chunk-MKD2D7WE.js";
6
+ import "./chunk-LVKQ2AKT.js";
7
+ import "./chunk-PL6CNMVS.js";
8
+ import "./chunk-OBLVLIUS.js";
9
+ import "./chunk-HQYXVIH6.js";
10
+ import "./chunk-47VIN33V.js";
11
+ import "./chunk-VQ5VN7DF.js";
12
+ import "./chunk-HC2MT7BX.js";
13
+ export {
14
+ exitCodeFor,
15
+ runPrReview
16
+ };
17
+ //# sourceMappingURL=pr-review-CAMAB7KO.js.map
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPrd
4
+ } from "./chunk-MSPUB635.js";
5
+ import "./chunk-3BOHTH4V.js";
6
+ import "./chunk-AAY6KM7N.js";
7
+ import "./chunk-PL6CNMVS.js";
8
+ import "./chunk-HDV3YDTG.js";
9
+ import "./chunk-OBLVLIUS.js";
10
+ import "./chunk-HQYXVIH6.js";
11
+ import "./chunk-47VIN33V.js";
12
+ import "./chunk-VQ5VN7DF.js";
13
+ import "./chunk-HC2MT7BX.js";
14
+ export {
15
+ runPrd
16
+ };
17
+ //# sourceMappingURL=prd-V3MWDIHK.js.map
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runReview
4
+ } from "./chunk-VCKX262Z.js";
5
+ import "./chunk-AAY6KM7N.js";
6
+ import "./chunk-PL6CNMVS.js";
7
+ import "./chunk-OBLVLIUS.js";
8
+ import "./chunk-HQYXVIH6.js";
9
+ import "./chunk-47VIN33V.js";
10
+ import "./chunk-VQ5VN7DF.js";
11
+ import "./chunk-HC2MT7BX.js";
12
+ export {
13
+ runReview
14
+ };
15
+ //# sourceMappingURL=review-7LN47SAN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,51 +1,52 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ mostRecent,
4
+ prReviewDir,
5
+ readPrReviewIndex,
6
+ runPrReview
7
+ } from "./chunk-MKD2D7WE.js";
2
8
  import {
3
9
  runPrd
4
- } from "./chunk-UH4KAJBJ.js";
10
+ } from "./chunk-MSPUB635.js";
5
11
  import {
6
12
  runReview
7
- } from "./chunk-2Z7OEZZT.js";
13
+ } from "./chunk-VCKX262Z.js";
8
14
  import {
9
15
  ensureWebMonitor
10
- } from "./chunk-652DJBCN.js";
16
+ } from "./chunk-GANSDJV7.js";
11
17
  import {
12
18
  runInit
13
- } from "./chunk-EZMOEBLU.js";
19
+ } from "./chunk-RKTEV6EG.js";
14
20
  import {
15
21
  printQueueSummary,
16
22
  printRunSummary,
17
23
  runExecute
18
- } from "./chunk-67ZO5ROQ.js";
24
+ } from "./chunk-6N7LZZ5U.js";
25
+ import {
26
+ listPullRequests,
27
+ publishGitState
28
+ } from "./chunk-LVKQ2AKT.js";
19
29
  import {
20
30
  runPlan
21
- } from "./chunk-SP7DD4ID.js";
31
+ } from "./chunk-UBIQXCVE.js";
22
32
  import {
23
33
  runPr
24
- } from "./chunk-2LNQL4XH.js";
25
- import "./chunk-UUY4PCWW.js";
34
+ } from "./chunk-JW7WLSZ6.js";
35
+ import "./chunk-3BOHTH4V.js";
26
36
  import {
27
37
  emptyRelations,
28
38
  getProvider,
29
39
  resolveCommandIssue,
30
40
  uniqueIds
31
- } from "./chunk-S67Q4I2O.js";
41
+ } from "./chunk-AAY6KM7N.js";
42
+ import "./chunk-PL6CNMVS.js";
32
43
  import "./chunk-HDV3YDTG.js";
33
- import {
34
- mostRecent,
35
- prReviewDir,
36
- readPrReviewIndex,
37
- runPrReview
38
- } from "./chunk-EWA3OGCM.js";
39
- import {
40
- listPullRequests,
41
- publishGitState
42
- } from "./chunk-VOKNTBOO.js";
43
- import "./chunk-MXTGCD5C.js";
44
44
  import {
45
45
  beginUsageScope,
46
46
  getRunUsageTotals
47
- } from "./chunk-PPLIXZI5.js";
48
- import "./chunk-SLHZPB3C.js";
47
+ } from "./chunk-OBLVLIUS.js";
48
+ import "./chunk-HQYXVIH6.js";
49
+ import "./chunk-47VIN33V.js";
49
50
  import {
50
51
  executionPlanSchema,
51
52
  loadIssuesConfig,
@@ -53,7 +54,7 @@ import {
53
54
  resolveIssuePaths,
54
55
  resolveProjectPaths,
55
56
  resolveQueuePaths
56
- } from "./chunk-VYFKOUUR.js";
57
+ } from "./chunk-VQ5VN7DF.js";
57
58
  import {
58
59
  FilePublisher,
59
60
  NullPublisher,
@@ -70,7 +71,7 @@ import {
70
71
  setStoryStageCallback,
71
72
  setStoryUpdateCallback,
72
73
  writeFileAtomic
73
- } from "./chunk-V5OHFSW4.js";
74
+ } from "./chunk-HC2MT7BX.js";
74
75
 
75
76
  // src/commands/run.ts
76
77
  import { randomUUID } from "crypto";
@@ -1857,4 +1858,4 @@ export {
1857
1858
  publishStorySeed,
1858
1859
  runPipeline
1859
1860
  };
1860
- //# sourceMappingURL=run-DIBC3YKX.js.map
1861
+ //# sourceMappingURL=run-H75MD5BQ.js.map