issue-flow 0.15.0 → 0.17.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 (169) hide show
  1. package/dist/agent-TB6W7PT7.js +30 -0
  2. package/dist/{analyze-O2PYDIFK.js → analyze-6M3KEOX7.js} +22 -22
  3. package/dist/{apply-SSU6QCD4.js → apply-ADB3ZK7W.js} +14 -14
  4. package/dist/{bench-ODFPAGW6.js → bench-FM7I7EIV.js} +23 -23
  5. package/dist/{chunk-BMHGRYL6.js → chunk-2SUFAE6X.js} +67 -24
  6. package/dist/chunk-2SUFAE6X.js.map +1 -0
  7. package/dist/{chunk-QRCGW2ZO.js → chunk-32JSYXEK.js} +8 -8
  8. package/dist/chunk-3R27MJ5R.js +25 -0
  9. package/dist/chunk-3R27MJ5R.js.map +1 -0
  10. package/dist/{chunk-MGCOQU6N.js → chunk-6YQT3SSM.js} +4 -4
  11. package/dist/chunk-6YQT3SSM.js.map +1 -0
  12. package/dist/{chunk-A35HE4V7.js → chunk-7F7LGMVO.js} +3 -3
  13. package/dist/{chunk-RPXDBX6R.js → chunk-A4H7P7T7.js} +102 -102
  14. package/dist/chunk-A4H7P7T7.js.map +1 -0
  15. package/dist/{chunk-2ZAM45PZ.js → chunk-ANI2NTR4.js} +9 -9
  16. package/dist/{chunk-ZPIVCM7Q.js → chunk-B3TSS7BT.js} +3 -3
  17. package/dist/chunk-C5TL7T4V.js +27 -0
  18. package/dist/chunk-C5TL7T4V.js.map +1 -0
  19. package/dist/chunk-D6ZBGJ3L.js +321 -0
  20. package/dist/chunk-D6ZBGJ3L.js.map +1 -0
  21. package/dist/{chunk-ZXPASFHG.js → chunk-DGRTJD5R.js} +3 -3
  22. package/dist/{chunk-6QYMSNVA.js → chunk-DUS5ZNKL.js} +476 -362
  23. package/dist/chunk-DUS5ZNKL.js.map +1 -0
  24. package/dist/{chunk-VR34TXHF.js → chunk-DV7HUC4Z.js} +7 -7
  25. package/dist/{chunk-6SRE4KD7.js → chunk-E6KXCV3T.js} +4 -4
  26. package/dist/{chunk-HGSYD57B.js → chunk-HJBF4WD2.js} +1656 -1070
  27. package/dist/chunk-HJBF4WD2.js.map +1 -0
  28. package/dist/{chunk-PCN7ZQND.js → chunk-HLAPOUEM.js} +8 -8
  29. package/dist/{chunk-WM3Y7Q4A.js → chunk-HY5HLFDU.js} +630 -571
  30. package/dist/chunk-HY5HLFDU.js.map +1 -0
  31. package/dist/{chunk-XDKGA6UX.js → chunk-ICM463EO.js} +64 -14
  32. package/dist/chunk-ICM463EO.js.map +1 -0
  33. package/dist/{chunk-MEFY4B7T.js → chunk-ISZ54SVE.js} +9 -9
  34. package/dist/{chunk-ARWNYXFL.js → chunk-KZ5EY5XX.js} +12 -12
  35. package/dist/{chunk-ZFIXEYUJ.js → chunk-KZXQWC7U.js} +32 -20
  36. package/dist/chunk-KZXQWC7U.js.map +1 -0
  37. package/dist/{chunk-KAHQ6F5C.js → chunk-LPWPFIIB.js} +11 -11
  38. package/dist/{chunk-FK4IDY6P.js → chunk-MI5TREN3.js} +9 -9
  39. package/dist/{chunk-UNQYMR3H.js → chunk-PPZ3K4YM.js} +2 -2
  40. package/dist/{chunk-F4OK7KEP.js → chunk-QMIQR7EE.js} +10 -10
  41. package/dist/{chunk-AYYMW33T.js → chunk-QPGEFLMY.js} +2 -2
  42. package/dist/chunk-RCZJQUTC.js +196 -0
  43. package/dist/chunk-RCZJQUTC.js.map +1 -0
  44. package/dist/{chunk-MROS3SKL.js → chunk-RNFUVKC3.js} +3 -3
  45. package/dist/{chunk-RWEXK55D.js → chunk-RYOUZ6EK.js} +2 -2
  46. package/dist/{chunk-6E2PEBFT.js → chunk-SGTTR4XW.js} +10 -10
  47. package/dist/{chunk-XQHFC62U.js → chunk-SOM4QA6C.js} +3 -3
  48. package/dist/{chunk-5ZKBIXET.js → chunk-UK4E2FUA.js} +132 -34
  49. package/dist/chunk-UK4E2FUA.js.map +1 -0
  50. package/dist/{chunk-6FXOU2KR.js → chunk-UWDCIFTP.js} +7 -7
  51. package/dist/{chunk-XG2NYDRA.js → chunk-VE3IYNDN.js} +3 -3
  52. package/dist/{chunk-3BWZO4YI.js → chunk-WCCZJL7W.js} +2 -2
  53. package/dist/{chunk-NVZMBXTE.js → chunk-XZUEFTUP.js} +6 -6
  54. package/dist/{chunk-TBDP6QPJ.js → chunk-YII4U7ZD.js} +10 -10
  55. package/dist/{chunk-TBDP6QPJ.js.map → chunk-YII4U7ZD.js.map} +1 -1
  56. package/dist/{chunk-4RXYFWP7.js → chunk-YUNBOUQH.js} +6 -6
  57. package/dist/{chunk-GSZCQUCY.js → chunk-YVPZUN6X.js} +2 -2
  58. package/dist/{chunk-XRLRKTQA.js → chunk-Z5O2XBWA.js} +14 -14
  59. package/dist/cli.js +61 -52
  60. package/dist/cli.js.map +1 -1
  61. package/dist/{config-UMP6DBJB.js → config-KGZUPAUP.js} +13 -13
  62. package/dist/{conventions-DKH7AE4T.js → conventions-RYN7OXJN.js} +15 -15
  63. package/dist/{diagnostics-GOGCLTRS.js → diagnostics-HTCWF7F4.js} +7 -7
  64. package/dist/execute-QL3ZQIAP.js +37 -0
  65. package/dist/{generate-AGBT7EHX.js → generate-CX6KNHZS.js} +22 -22
  66. package/dist/{git-AC542GU2.js → git-A2IP32PQ.js} +2 -2
  67. package/dist/init-PDVQDRS6.js +24 -0
  68. package/dist/{operations-JQYK2EMT.js → operations-CAKIT2BO.js} +15 -15
  69. package/dist/{permissions-6HL52K54.js → permissions-G4XCAESF.js} +4 -4
  70. package/dist/plan-PRORGS3L.js +34 -0
  71. package/dist/{policy-IMRXGG7X.js → policy-WX6O2JID.js} +14 -14
  72. package/dist/pr-27RMQI5F.js +39 -0
  73. package/dist/pr-review-VNESMAMT.js +32 -0
  74. package/dist/prd-ZNC4T5BS.js +33 -0
  75. package/dist/{ps-KUUZ6TUL.js → ps-76L6ZAZL.js} +12 -12
  76. package/dist/{recorder-BJ2KIAWT.js → recorder-N7U66HCO.js} +7 -7
  77. package/dist/{registry-SB7XTMGE.js → registry-XLHHYLTR.js} +5 -5
  78. package/dist/{resume-QNLQSCR5.js → resume-VLWIE264.js} +40 -38
  79. package/dist/{resume-QNLQSCR5.js.map → resume-VLWIE264.js.map} +1 -1
  80. package/dist/review-7CREJDKB.js +35 -0
  81. package/dist/routing-VCDYHSXA.js +33 -0
  82. package/dist/run-3MPORLF5.js +56 -0
  83. package/dist/{session-publisher-T7EI3CIP.js → session-publisher-KAJQRHNZ.js} +3 -2
  84. package/dist/{state-manager-ZEPWTCA6.js → state-manager-UPHO2EA2.js} +4 -4
  85. package/dist/state-manager-UPHO2EA2.js.map +1 -0
  86. package/dist/{usage-QL563I7F.js → usage-U7QNGCPK.js} +12 -12
  87. package/dist/{web-PPSMNTQ6.js → web-HUNDHCJ4.js} +21 -18
  88. package/dist/{web-PPSMNTQ6.js.map → web-HUNDHCJ4.js.map} +1 -1
  89. package/package.json +6 -5
  90. package/web/AGENTS.md +15 -11
  91. package/web/public/app.css +51 -0
  92. package/web/public/app.js +325 -56
  93. package/web/public/index.html +6 -2
  94. package/dist/agent-AT64RXTA.js +0 -30
  95. package/dist/chunk-5ZKBIXET.js.map +0 -1
  96. package/dist/chunk-6QYMSNVA.js.map +0 -1
  97. package/dist/chunk-7Z4Y3VKM.js +0 -26
  98. package/dist/chunk-7Z4Y3VKM.js.map +0 -1
  99. package/dist/chunk-BMHGRYL6.js.map +0 -1
  100. package/dist/chunk-HGSYD57B.js.map +0 -1
  101. package/dist/chunk-MGCOQU6N.js.map +0 -1
  102. package/dist/chunk-RPXDBX6R.js.map +0 -1
  103. package/dist/chunk-WM3Y7Q4A.js.map +0 -1
  104. package/dist/chunk-XDKGA6UX.js.map +0 -1
  105. package/dist/chunk-XLVGPXNL.js +0 -180
  106. package/dist/chunk-XLVGPXNL.js.map +0 -1
  107. package/dist/chunk-ZFIXEYUJ.js.map +0 -1
  108. package/dist/execute-E3BRMDAQ.js +0 -35
  109. package/dist/init-LLBVJNPE.js +0 -24
  110. package/dist/plan-HSLWDJEZ.js +0 -34
  111. package/dist/pr-6TCZXG6K.js +0 -39
  112. package/dist/pr-review-6MWJO2NP.js +0 -32
  113. package/dist/prd-D6YDYAFX.js +0 -33
  114. package/dist/review-3KJ4BH2V.js +0 -35
  115. package/dist/routing-TN7GLMGU.js +0 -94
  116. package/dist/routing-TN7GLMGU.js.map +0 -1
  117. package/dist/run-5EHIFF2V.js +0 -54
  118. /package/dist/{agent-AT64RXTA.js.map → agent-TB6W7PT7.js.map} +0 -0
  119. /package/dist/{analyze-O2PYDIFK.js.map → analyze-6M3KEOX7.js.map} +0 -0
  120. /package/dist/{apply-SSU6QCD4.js.map → apply-ADB3ZK7W.js.map} +0 -0
  121. /package/dist/{bench-ODFPAGW6.js.map → bench-FM7I7EIV.js.map} +0 -0
  122. /package/dist/{chunk-QRCGW2ZO.js.map → chunk-32JSYXEK.js.map} +0 -0
  123. /package/dist/{chunk-A35HE4V7.js.map → chunk-7F7LGMVO.js.map} +0 -0
  124. /package/dist/{chunk-2ZAM45PZ.js.map → chunk-ANI2NTR4.js.map} +0 -0
  125. /package/dist/{chunk-ZPIVCM7Q.js.map → chunk-B3TSS7BT.js.map} +0 -0
  126. /package/dist/{chunk-ZXPASFHG.js.map → chunk-DGRTJD5R.js.map} +0 -0
  127. /package/dist/{chunk-VR34TXHF.js.map → chunk-DV7HUC4Z.js.map} +0 -0
  128. /package/dist/{chunk-6SRE4KD7.js.map → chunk-E6KXCV3T.js.map} +0 -0
  129. /package/dist/{chunk-PCN7ZQND.js.map → chunk-HLAPOUEM.js.map} +0 -0
  130. /package/dist/{chunk-MEFY4B7T.js.map → chunk-ISZ54SVE.js.map} +0 -0
  131. /package/dist/{chunk-ARWNYXFL.js.map → chunk-KZ5EY5XX.js.map} +0 -0
  132. /package/dist/{chunk-KAHQ6F5C.js.map → chunk-LPWPFIIB.js.map} +0 -0
  133. /package/dist/{chunk-FK4IDY6P.js.map → chunk-MI5TREN3.js.map} +0 -0
  134. /package/dist/{chunk-UNQYMR3H.js.map → chunk-PPZ3K4YM.js.map} +0 -0
  135. /package/dist/{chunk-F4OK7KEP.js.map → chunk-QMIQR7EE.js.map} +0 -0
  136. /package/dist/{chunk-AYYMW33T.js.map → chunk-QPGEFLMY.js.map} +0 -0
  137. /package/dist/{chunk-MROS3SKL.js.map → chunk-RNFUVKC3.js.map} +0 -0
  138. /package/dist/{chunk-RWEXK55D.js.map → chunk-RYOUZ6EK.js.map} +0 -0
  139. /package/dist/{chunk-6E2PEBFT.js.map → chunk-SGTTR4XW.js.map} +0 -0
  140. /package/dist/{chunk-XQHFC62U.js.map → chunk-SOM4QA6C.js.map} +0 -0
  141. /package/dist/{chunk-6FXOU2KR.js.map → chunk-UWDCIFTP.js.map} +0 -0
  142. /package/dist/{chunk-XG2NYDRA.js.map → chunk-VE3IYNDN.js.map} +0 -0
  143. /package/dist/{chunk-3BWZO4YI.js.map → chunk-WCCZJL7W.js.map} +0 -0
  144. /package/dist/{chunk-NVZMBXTE.js.map → chunk-XZUEFTUP.js.map} +0 -0
  145. /package/dist/{chunk-4RXYFWP7.js.map → chunk-YUNBOUQH.js.map} +0 -0
  146. /package/dist/{chunk-GSZCQUCY.js.map → chunk-YVPZUN6X.js.map} +0 -0
  147. /package/dist/{chunk-XRLRKTQA.js.map → chunk-Z5O2XBWA.js.map} +0 -0
  148. /package/dist/{config-UMP6DBJB.js.map → config-KGZUPAUP.js.map} +0 -0
  149. /package/dist/{conventions-DKH7AE4T.js.map → conventions-RYN7OXJN.js.map} +0 -0
  150. /package/dist/{diagnostics-GOGCLTRS.js.map → diagnostics-HTCWF7F4.js.map} +0 -0
  151. /package/dist/{execute-E3BRMDAQ.js.map → execute-QL3ZQIAP.js.map} +0 -0
  152. /package/dist/{generate-AGBT7EHX.js.map → generate-CX6KNHZS.js.map} +0 -0
  153. /package/dist/{git-AC542GU2.js.map → git-A2IP32PQ.js.map} +0 -0
  154. /package/dist/{init-LLBVJNPE.js.map → init-PDVQDRS6.js.map} +0 -0
  155. /package/dist/{operations-JQYK2EMT.js.map → operations-CAKIT2BO.js.map} +0 -0
  156. /package/dist/{permissions-6HL52K54.js.map → permissions-G4XCAESF.js.map} +0 -0
  157. /package/dist/{plan-HSLWDJEZ.js.map → plan-PRORGS3L.js.map} +0 -0
  158. /package/dist/{policy-IMRXGG7X.js.map → policy-WX6O2JID.js.map} +0 -0
  159. /package/dist/{pr-6TCZXG6K.js.map → pr-27RMQI5F.js.map} +0 -0
  160. /package/dist/{pr-review-6MWJO2NP.js.map → pr-review-VNESMAMT.js.map} +0 -0
  161. /package/dist/{prd-D6YDYAFX.js.map → prd-ZNC4T5BS.js.map} +0 -0
  162. /package/dist/{ps-KUUZ6TUL.js.map → ps-76L6ZAZL.js.map} +0 -0
  163. /package/dist/{recorder-BJ2KIAWT.js.map → recorder-N7U66HCO.js.map} +0 -0
  164. /package/dist/{registry-SB7XTMGE.js.map → registry-XLHHYLTR.js.map} +0 -0
  165. /package/dist/{review-3KJ4BH2V.js.map → review-7CREJDKB.js.map} +0 -0
  166. /package/dist/{run-5EHIFF2V.js.map → routing-VCDYHSXA.js.map} +0 -0
  167. /package/dist/{session-publisher-T7EI3CIP.js.map → run-3MPORLF5.js.map} +0 -0
  168. /package/dist/{state-manager-ZEPWTCA6.js.map → session-publisher-KAJQRHNZ.js.map} +0 -0
  169. /package/dist/{usage-QL563I7F.js.map → usage-U7QNGCPK.js.map} +0 -0
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ MODEL_CATALOG_VERSION,
4
+ PRIORS_VERSION,
5
+ RECOMMENDED_POLICY_VERSION,
6
+ decideRouting
7
+ } from "./chunk-D6ZBGJ3L.js";
8
+ import {
9
+ GLOBAL_CONFIG_FILENAME,
10
+ loadRoutingConfig
11
+ } from "./chunk-HY5HLFDU.js";
12
+ import {
13
+ resolveIssuePaths
14
+ } from "./chunk-DV7HUC4Z.js";
15
+ import {
16
+ printError,
17
+ printInfo,
18
+ printSuccess
19
+ } from "./chunk-XZUEFTUP.js";
20
+ import {
21
+ getGlobalRoot
22
+ } from "./chunk-HAKDLR6N.js";
23
+ import {
24
+ getProjectRoot
25
+ } from "./chunk-YVPZUN6X.js";
26
+ import {
27
+ loadTaskPlan
28
+ } from "./chunk-SOM4QA6C.js";
29
+ import {
30
+ AGENT_PHASES,
31
+ routingConfigInputSchema
32
+ } from "./chunk-ICM463EO.js";
33
+ import {
34
+ writeFileAtomic
35
+ } from "./chunk-3R27MJ5R.js";
36
+
37
+ // src/commands/routing.ts
38
+ import { mkdir, readFile } from "fs/promises";
39
+ import { dirname, join } from "path";
40
+ var ROUTING_COMMAND_SCHEMA_VERSION = 1;
41
+ function targetLabel(target) {
42
+ if (target === void 0) return "\u2014";
43
+ if (typeof target === "string") return target;
44
+ const tier = target.tier ? `:${target.tier}` : "";
45
+ const model = target.model ? ` \xB7 ${target.model}` : "";
46
+ return `${target.provider}${tier}${model}`;
47
+ }
48
+ function targetKey(target) {
49
+ if (target === void 0) return "\u2014";
50
+ if (typeof target === "string") return target;
51
+ return `${target.harness}:${target.provider}:${target.model ?? ""}`;
52
+ }
53
+ async function runRoutingInspect(options) {
54
+ const config = await loadRoutingConfig();
55
+ const sample = decideRouting({
56
+ phase: "execute",
57
+ actualHarness: "claude-code",
58
+ mode: config.mode,
59
+ profile: config.profile
60
+ });
61
+ if (options.json === true) {
62
+ console.log(
63
+ JSON.stringify(
64
+ {
65
+ schemaVersion: ROUTING_COMMAND_SCHEMA_VERSION,
66
+ priorsVersion: PRIORS_VERSION,
67
+ modelCatalogVersion: MODEL_CATALOG_VERSION,
68
+ recommendedPolicyVersion: RECOMMENDED_POLICY_VERSION,
69
+ config,
70
+ sample
71
+ },
72
+ null,
73
+ 2
74
+ )
75
+ );
76
+ return 0;
77
+ }
78
+ printInfo(`routing.mode: ${config.mode} (default shadow \u2014 records, does not act)`);
79
+ printInfo(`routing.profile: ${config.profile}`);
80
+ if (sample) {
81
+ printInfo(
82
+ `sample selected=${targetLabel(sample.selected)} actual=${targetLabel(sample.actual)} class=${sample.taskClass}`
83
+ );
84
+ }
85
+ return 0;
86
+ }
87
+ async function runRoutingReport(options) {
88
+ if (options.issue === void 0) {
89
+ printInfo("Pass --issue N to compare selected vs actual on that plan.");
90
+ return 0;
91
+ }
92
+ const paths = await resolveIssuePaths(options.issue);
93
+ const plan = await loadTaskPlan(paths.tasksFile);
94
+ const records = plan.executions ?? [];
95
+ let agree = 0;
96
+ let total = 0;
97
+ for (const record of records) {
98
+ const decision = record.routingDecision;
99
+ if (decision === void 0 || decision === null) continue;
100
+ total += 1;
101
+ if (targetKey(decision.selected) === targetKey(decision.actual)) agree += 1;
102
+ }
103
+ const rate = total === 0 ? 0 : agree / total;
104
+ if (options.json === true) {
105
+ console.log(
106
+ JSON.stringify({ schemaVersion: ROUTING_COMMAND_SCHEMA_VERSION, total, agree, rate })
107
+ );
108
+ return 0;
109
+ }
110
+ printInfo(`shadow agreement: ${agree}/${total} (${(rate * 100).toFixed(0)}%)`);
111
+ return 0;
112
+ }
113
+ async function runRoutingExplain(options = {}) {
114
+ const config = await loadRoutingConfig();
115
+ const phases = AGENT_PHASES.map((phase) => {
116
+ const decision = decideRouting({
117
+ phase,
118
+ actualHarness: "claude-code",
119
+ actualProvider: "claude",
120
+ mode: config.mode === "off" ? "shadow" : config.mode,
121
+ profile: config.profile,
122
+ policy: config.policy
123
+ });
124
+ return {
125
+ phase,
126
+ target: decision?.selected ?? null,
127
+ origin: config.policy === "recommended" ? "recommended policy" : "adaptive score"
128
+ };
129
+ });
130
+ if (options.json === true) {
131
+ console.log(
132
+ JSON.stringify({ schemaVersion: ROUTING_COMMAND_SCHEMA_VERSION, config, phases }, null, 2)
133
+ );
134
+ return 0;
135
+ }
136
+ printInfo(`routing policy: ${config.policy ?? "adaptive"} (${config.mode})`);
137
+ for (const phase of phases) {
138
+ printInfo(
139
+ `${phase.phase.padEnd(12)} ${targetLabel(phase.target ?? void 0)} (${phase.origin})`
140
+ );
141
+ }
142
+ return 0;
143
+ }
144
+ async function writeRoutingPreference(input) {
145
+ const parsed = routingConfigInputSchema.safeParse(input.values);
146
+ if (!parsed.success || Object.keys(parsed.data).length === 0) {
147
+ throw new Error(
148
+ parsed.success ? "At least one routing setting is required." : `Invalid routing setting: ${parsed.error.issues[0]?.message ?? "invalid value"}.`
149
+ );
150
+ }
151
+ const path = input.target === "global" ? join(getGlobalRoot(), GLOBAL_CONFIG_FILENAME) : join(input.projectRoot ?? await getProjectRoot(), ".issue-flow.json");
152
+ let existing = {};
153
+ try {
154
+ const value = JSON.parse(await readFile(path, "utf-8"));
155
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
156
+ existing = value;
157
+ }
158
+ } catch (error) {
159
+ if (error.code !== "ENOENT") {
160
+ throw new Error(`Could not read ${path}: ${error.message}`);
161
+ }
162
+ }
163
+ const current = existing.routing !== null && typeof existing.routing === "object" && !Array.isArray(existing.routing) ? existing.routing : {};
164
+ existing.routing = { ...current, ...parsed.data };
165
+ await mkdir(dirname(path), { recursive: true });
166
+ await writeFileAtomic(path, `${JSON.stringify(existing, null, 2)}
167
+ `);
168
+ return path;
169
+ }
170
+ async function runRoutingUse(policy, options = {}) {
171
+ if (policy !== "recommended") {
172
+ printError(`Unknown routing policy '${policy}'. Valid policy: recommended.`);
173
+ return 1;
174
+ }
175
+ try {
176
+ const file = await writeRoutingPreference({
177
+ target: options.project === true ? "project" : "global",
178
+ values: { policy: "recommended" }
179
+ });
180
+ printSuccess(`Wrote recommended routing policy to ${file}`);
181
+ return 0;
182
+ } catch (error) {
183
+ printError(error instanceof Error ? error.message : String(error));
184
+ return 1;
185
+ }
186
+ }
187
+
188
+ export {
189
+ ROUTING_COMMAND_SCHEMA_VERSION,
190
+ runRoutingInspect,
191
+ runRoutingReport,
192
+ runRoutingExplain,
193
+ writeRoutingPreference,
194
+ runRoutingUse
195
+ };
196
+ //# sourceMappingURL=chunk-RCZJQUTC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/routing.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { AGENT_PHASES } from '../agents/types.js';\nimport { GLOBAL_CONFIG_FILENAME, loadRoutingConfig } from '../config.js';\nimport { loadTaskPlan } from '../core/state-manager.js';\nimport { decideRouting } from '../routing/decide.js';\nimport { MODEL_CATALOG_VERSION } from '../routing/models.js';\nimport { RECOMMENDED_POLICY_VERSION } from '../routing/policy.js';\nimport { PRIORS_VERSION } from '../routing/priors.js';\nimport { type RoutingConfigInput, routingConfigInputSchema } from '../schemas.js';\nimport { getGlobalRoot } from '../storage/paths.js';\nimport { resolveIssuePaths } from '../storage/resolve.js';\nimport { printError, printInfo, printSuccess } from '../ui/logger.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { getProjectRoot } from '../utils/git.js';\n\nexport const ROUTING_COMMAND_SCHEMA_VERSION = 1;\n\nfunction targetLabel(\n target:\n | { harness: string; provider: string; model?: string | null; tier?: string }\n | string\n | undefined,\n): string {\n if (target === undefined) return '—';\n if (typeof target === 'string') return target;\n const tier = target.tier ? `:${target.tier}` : '';\n const model = target.model ? ` · ${target.model}` : '';\n return `${target.provider}${tier}${model}`;\n}\n\nfunction targetKey(\n target:\n | { harness: string; provider: string; model?: string | null; tier?: string }\n | string\n | undefined,\n): string {\n if (target === undefined) return '—';\n if (typeof target === 'string') return target;\n return `${target.harness}:${target.provider}:${target.model ?? ''}`;\n}\n\nexport async function runRoutingInspect(options: { json?: boolean }): Promise<number> {\n const config = await loadRoutingConfig();\n const sample = decideRouting({\n phase: 'execute',\n actualHarness: 'claude-code',\n mode: config.mode,\n profile: config.profile,\n });\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n schemaVersion: ROUTING_COMMAND_SCHEMA_VERSION,\n priorsVersion: PRIORS_VERSION,\n modelCatalogVersion: MODEL_CATALOG_VERSION,\n recommendedPolicyVersion: RECOMMENDED_POLICY_VERSION,\n config,\n sample,\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n printInfo(`routing.mode: ${config.mode} (default shadow — records, does not act)`);\n printInfo(`routing.profile: ${config.profile}`);\n if (sample) {\n printInfo(\n `sample selected=${targetLabel(sample.selected)} actual=${targetLabel(sample.actual)} class=${sample.taskClass}`,\n );\n }\n return 0;\n}\n\nexport async function runRoutingReport(options: {\n issue?: string;\n json?: boolean;\n}): Promise<number> {\n if (options.issue === undefined) {\n printInfo('Pass --issue N to compare selected vs actual on that plan.');\n return 0;\n }\n const paths = await resolveIssuePaths(options.issue);\n const plan = await loadTaskPlan(paths.tasksFile);\n const records = plan.executions ?? [];\n let agree = 0;\n let total = 0;\n for (const record of records) {\n const decision = record.routingDecision;\n if (decision === undefined || decision === null) continue;\n total += 1;\n if (targetKey(decision.selected) === targetKey(decision.actual)) agree += 1;\n }\n const rate = total === 0 ? 0 : agree / total;\n if (options.json === true) {\n console.log(\n JSON.stringify({ schemaVersion: ROUTING_COMMAND_SCHEMA_VERSION, total, agree, rate }),\n );\n return 0;\n }\n printInfo(`shadow agreement: ${agree}/${total} (${(rate * 100).toFixed(0)}%)`);\n return 0;\n}\n\nexport async function runRoutingExplain(options: { json?: boolean } = {}): Promise<number> {\n const config = await loadRoutingConfig();\n const phases = AGENT_PHASES.map((phase) => {\n const decision = decideRouting({\n phase,\n actualHarness: 'claude-code',\n actualProvider: 'claude',\n mode: config.mode === 'off' ? 'shadow' : config.mode,\n profile: config.profile,\n policy: config.policy,\n });\n return {\n phase,\n target: decision?.selected ?? null,\n origin: config.policy === 'recommended' ? 'recommended policy' : 'adaptive score',\n };\n });\n if (options.json === true) {\n console.log(\n JSON.stringify({ schemaVersion: ROUTING_COMMAND_SCHEMA_VERSION, config, phases }, null, 2),\n );\n return 0;\n }\n printInfo(`routing policy: ${config.policy ?? 'adaptive'} (${config.mode})`);\n for (const phase of phases) {\n printInfo(\n `${phase.phase.padEnd(12)} ${targetLabel(phase.target ?? undefined)} (${phase.origin})`,\n );\n }\n return 0;\n}\n\nexport async function writeRoutingPreference(input: {\n target: 'global' | 'project';\n values: RoutingConfigInput;\n projectRoot?: string;\n}): Promise<string> {\n const parsed = routingConfigInputSchema.safeParse(input.values);\n if (!parsed.success || Object.keys(parsed.data).length === 0) {\n throw new Error(\n parsed.success\n ? 'At least one routing setting is required.'\n : `Invalid routing setting: ${parsed.error.issues[0]?.message ?? 'invalid value'}.`,\n );\n }\n const path =\n input.target === 'global'\n ? join(getGlobalRoot(), GLOBAL_CONFIG_FILENAME)\n : join(input.projectRoot ?? (await getProjectRoot()), '.issue-flow.json');\n let existing: Record<string, unknown> = {};\n try {\n const value: unknown = JSON.parse(await readFile(path, 'utf-8'));\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n existing = value as Record<string, unknown>;\n }\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(`Could not read ${path}: ${(error as Error).message}`);\n }\n }\n const current =\n existing.routing !== null &&\n typeof existing.routing === 'object' &&\n !Array.isArray(existing.routing)\n ? (existing.routing as Record<string, unknown>)\n : {};\n existing.routing = { ...current, ...parsed.data };\n await mkdir(dirname(path), { recursive: true });\n await writeFileAtomic(path, `${JSON.stringify(existing, null, 2)}\\n`);\n return path;\n}\n\nexport async function runRoutingUse(\n policy: string,\n options: { global?: boolean; project?: boolean } = {},\n): Promise<number> {\n if (policy !== 'recommended') {\n printError(`Unknown routing policy '${policy}'. Valid policy: recommended.`);\n return 1;\n }\n try {\n const file = await writeRoutingPreference({\n target: options.project === true ? 'project' : 'global',\n values: { policy: 'recommended' },\n });\n printSuccess(`Wrote recommended routing policy to ${file}`);\n return 0;\n } catch (error) {\n printError(error instanceof Error ? error.message : String(error));\n return 1;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readSessionFile
4
- } from "./chunk-RWEXK55D.js";
4
+ } from "./chunk-RYOUZ6EK.js";
5
5
  import {
6
6
  PROJECTS_DIR_NAME,
7
7
  RUN_LOCK_FILENAME,
@@ -12,7 +12,7 @@ import {
12
12
  isProcessAlive,
13
13
  isRunLockStale,
14
14
  readRunLock
15
- } from "./chunk-XDKGA6UX.js";
15
+ } from "./chunk-ICM463EO.js";
16
16
 
17
17
  // src/execution/registry.ts
18
18
  import { readdir } from "fs/promises";
@@ -69,4 +69,4 @@ export {
69
69
  classifyRunLock,
70
70
  listLiveRuns
71
71
  };
72
- //# sourceMappingURL=chunk-MROS3SKL.js.map
72
+ //# sourceMappingURL=chunk-RNFUVKC3.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  sessionSnapshotSchema
4
- } from "./chunk-XDKGA6UX.js";
4
+ } from "./chunk-ICM463EO.js";
5
5
 
6
6
  // src/storage/session-file.ts
7
7
  import { readFile, stat as statFile } from "fs/promises";
@@ -27,4 +27,4 @@ async function readSessionFile(filePath) {
27
27
  export {
28
28
  readSessionFile
29
29
  };
30
- //# sourceMappingURL=chunk-RWEXK55D.js.map
30
+ //# sourceMappingURL=chunk-RYOUZ6EK.js.map
@@ -5,32 +5,32 @@ import {
5
5
  import {
6
6
  DEFAULT_HEADLESS_TIMEOUT_MS,
7
7
  runHeadless
8
- } from "./chunk-5ZKBIXET.js";
8
+ } from "./chunk-UK4E2FUA.js";
9
9
  import {
10
10
  getRegisteredProviders,
11
11
  loadVerifyConfig,
12
12
  probeAgent,
13
13
  resolveAgentFor
14
- } from "./chunk-WM3Y7Q4A.js";
15
- import {
16
- getSessionPublisher
17
- } from "./chunk-6QYMSNVA.js";
14
+ } from "./chunk-HY5HLFDU.js";
18
15
  import {
19
16
  VERIFY_FILENAME
20
17
  } from "./chunk-HAKDLR6N.js";
21
18
  import {
22
19
  getProjectRoot,
23
20
  run
24
- } from "./chunk-GSZCQUCY.js";
21
+ } from "./chunk-YVPZUN6X.js";
22
+ import {
23
+ getSessionPublisher
24
+ } from "./chunk-DUS5ZNKL.js";
25
25
  import {
26
26
  attachVerdict
27
- } from "./chunk-TBDP6QPJ.js";
27
+ } from "./chunk-YII4U7ZD.js";
28
28
  import {
29
29
  redactSecrets
30
- } from "./chunk-UNQYMR3H.js";
30
+ } from "./chunk-PPZ3K4YM.js";
31
31
  import {
32
32
  isoNow
33
- } from "./chunk-XQHFC62U.js";
33
+ } from "./chunk-SOM4QA6C.js";
34
34
 
35
35
  // src/verify/run-issue.ts
36
36
  import { join } from "path";
@@ -412,4 +412,4 @@ async function runAcceptance(options) {
412
412
  export {
413
413
  runAcceptance
414
414
  };
415
- //# sourceMappingURL=chunk-6E2PEBFT.js.map
415
+ //# sourceMappingURL=chunk-SGTTR4XW.js.map
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  isProcessAlive,
4
4
  taskPlanSchema
5
- } from "./chunk-XDKGA6UX.js";
5
+ } from "./chunk-ICM463EO.js";
6
6
  import {
7
7
  writeFileAtomic
8
- } from "./chunk-7Z4Y3VKM.js";
8
+ } from "./chunk-3R27MJ5R.js";
9
9
 
10
10
  // src/core/state-manager.ts
11
11
  import { readFile } from "fs/promises";
@@ -295,4 +295,4 @@ export {
295
295
  clearLastError,
296
296
  trimErrorMessage
297
297
  };
298
- //# sourceMappingURL=chunk-XQHFC62U.js.map
298
+ //# sourceMappingURL=chunk-SOM4QA6C.js.map
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- decideRouting
4
- } from "./chunk-XLVGPXNL.js";
5
2
  import {
6
3
  parseJournal
7
- } from "./chunk-3BWZO4YI.js";
4
+ } from "./chunk-WCCZJL7W.js";
8
5
  import {
9
6
  ensureCursorStorageGrant
10
- } from "./chunk-ZXPASFHG.js";
7
+ } from "./chunk-DGRTJD5R.js";
8
+ import {
9
+ decideRouting
10
+ } from "./chunk-D6ZBGJ3L.js";
11
11
  import {
12
12
  ensureRunnersRegistered,
13
13
  getActiveResilienceConfig,
@@ -18,13 +18,14 @@ import {
18
18
  loadAgentConfig,
19
19
  loadRoutingConfig,
20
20
  peekHarnessVersion,
21
+ probeAgent,
21
22
  resolveAgentFor,
22
23
  resolveAntigravityTimeoutMs,
23
24
  runnerFor
24
- } from "./chunk-WM3Y7Q4A.js";
25
+ } from "./chunk-HY5HLFDU.js";
25
26
  import {
26
27
  resolveProjectPaths
27
- } from "./chunk-VR34TXHF.js";
28
+ } from "./chunk-DV7HUC4Z.js";
28
29
  import {
29
30
  ElapsedTimer,
30
31
  createSpinner,
@@ -34,40 +35,45 @@ import {
34
35
  getInactivityTimeout,
35
36
  getOutputCallback,
36
37
  isVerbose,
38
+ printInfo,
37
39
  useColor
38
- } from "./chunk-NVZMBXTE.js";
39
- import {
40
- getSessionPublisher
41
- } from "./chunk-6QYMSNVA.js";
40
+ } from "./chunk-XZUEFTUP.js";
42
41
  import {
43
42
  bindDiagnosticContext,
44
43
  writeDiagnostic
45
- } from "./chunk-AYYMW33T.js";
44
+ } from "./chunk-QPGEFLMY.js";
46
45
  import {
47
46
  abortableDelay,
48
47
  resolvePolicy,
49
48
  shouldFailover,
50
49
  withRetry
51
- } from "./chunk-GSZCQUCY.js";
50
+ } from "./chunk-YVPZUN6X.js";
51
+ import {
52
+ getSessionPublisher
53
+ } from "./chunk-DUS5ZNKL.js";
52
54
  import {
53
55
  beginExecution,
54
56
  endExecution
55
- } from "./chunk-TBDP6QPJ.js";
57
+ } from "./chunk-YII4U7ZD.js";
56
58
  import {
57
59
  redactSecrets
58
- } from "./chunk-UNQYMR3H.js";
60
+ } from "./chunk-PPZ3K4YM.js";
59
61
  import {
60
62
  isoNow,
61
63
  sumUsage
62
- } from "./chunk-XQHFC62U.js";
64
+ } from "./chunk-SOM4QA6C.js";
63
65
  import {
64
66
  isAgentProviderId,
65
67
  providersHealthSchema
66
- } from "./chunk-XDKGA6UX.js";
68
+ } from "./chunk-ICM463EO.js";
67
69
  import {
68
70
  classify
69
71
  } from "./chunk-XEYH6ZZI.js";
70
72
 
73
+ // src/core/headless.ts
74
+ import { readFile as readFile2 } from "fs/promises";
75
+ import chalk from "chalk";
76
+
71
77
  // src/routing/budget.ts
72
78
  var DEFAULT_CEILINGS = {
73
79
  maxCostUsdPerIssue: null,
@@ -304,6 +310,71 @@ async function acquireHalfOpenProbe(filePath, provider, options = {}) {
304
310
  return { acquired, record };
305
311
  }
306
312
 
313
+ // src/agents/routing-application.ts
314
+ function routingRecommendationLine(decision, phase) {
315
+ if (decision === null || decision.mode !== "recommend" || decision.reasonCodes.includes("EXPLICIT_CONFIG")) {
316
+ return null;
317
+ }
318
+ const tier = decision.selected.tier ? ` (${decision.selected.tier})` : "";
319
+ return `Routing suggests ${decision.selected.provider}:${decision.selected.model ?? "default"}${tier} for ${phase} (${decision.reasonCodes.join(", ")}) \xB7 apply with routing.mode active`;
320
+ }
321
+ async function applyRoutingDecision(original, decision, phase, options = {}) {
322
+ if (decision === null || decision.mode !== "active" || decision.reasonCodes.includes("EXPLICIT_CONFIG") || original.failover) {
323
+ return { selection: original, applied: false, warning: null };
324
+ }
325
+ const target = decision.selected;
326
+ if (!isAgentProviderId(target.provider)) {
327
+ return {
328
+ selection: original,
329
+ applied: false,
330
+ warning: `Routing target '${target.provider}' is not a registered provider for ${phase}; using ${original.provider}.`
331
+ };
332
+ }
333
+ const selectedCandidate = decision.candidates.find(
334
+ (candidate) => candidate.eligible && candidate.harness === target.harness && candidate.provider === target.provider && candidate.model === (target.model ?? null)
335
+ );
336
+ if (selectedCandidate === void 0) {
337
+ return {
338
+ selection: original,
339
+ applied: false,
340
+ warning: `Routing target ${target.provider}:${target.model ?? "default"} is not an eligible catalog entry for ${phase}; using ${original.provider}.`
341
+ };
342
+ }
343
+ if (target.model !== null && target.model !== void 0 && !runnerFor(target.provider).capabilities.modelSelection) {
344
+ return {
345
+ selection: original,
346
+ applied: false,
347
+ warning: `Routing target ${target.provider} rejects model selection for ${phase}; using ${original.provider}.`
348
+ };
349
+ }
350
+ const availability = await (options.probe ?? probeAgent)(target.provider);
351
+ if (!availability.installed || !availability.authenticated) {
352
+ return {
353
+ selection: original,
354
+ applied: false,
355
+ warning: `Routing target ${target.provider} is ${availability.installed ? "not authenticated" : "not installed"} for ${phase}; using ${original.provider}.`
356
+ };
357
+ }
358
+ return {
359
+ applied: true,
360
+ warning: null,
361
+ selection: {
362
+ ...original,
363
+ primary: target.provider,
364
+ provider: target.provider,
365
+ settings: {
366
+ ...original.settings,
367
+ provider: target.provider,
368
+ model: target.model ?? null,
369
+ origin: { provider: "default", model: "default" }
370
+ },
371
+ failover: false,
372
+ reason: null,
373
+ cooldownUntil: null
374
+ }
375
+ };
376
+ }
377
+
307
378
  // src/agents/select.ts
308
379
  var AgentSelectionBlockedError = class extends Error {
309
380
  provider;
@@ -538,7 +609,36 @@ function resetAgentInvocationState() {
538
609
  }
539
610
  async function invokeSelectedAgent(invocation) {
540
611
  const config = getActiveResilienceConfig();
541
- const selection = invocation.forceProvider === void 0 ? await selectAgentForInvocation(invocation.phase, { config }) : await selectionForForced(invocation);
612
+ let selection = invocation.forceProvider === void 0 ? await selectAgentForInvocation(invocation.phase, { config }) : await selectionForForced(invocation);
613
+ const originalIdentity = declaredAgentIdentity(selection.provider);
614
+ const routingCfg = await loadRoutingConfig();
615
+ const agentCfg = await loadAgentConfig();
616
+ const routingDecision = decideRouting({
617
+ phase: invocation.phase,
618
+ actualHarness: originalIdentity.harness,
619
+ actualProvider: selection.provider,
620
+ actualModel: selection.settings.model,
621
+ mode: routingCfg.mode,
622
+ profile: routingCfg.profile,
623
+ policy: routingCfg.policy,
624
+ skipScore: hasExplicitAgentSelection(agentCfg, getAgentCliOverrides(), invocation.phase),
625
+ requiresExtraDirectories: (invocation.addDirs?.length ?? 0) > 0
626
+ });
627
+ const recommendation = routingRecommendationLine(routingDecision, invocation.phase);
628
+ if (recommendation !== null) printInfo(recommendation);
629
+ const routed = await applyRoutingDecision(selection, routingDecision, invocation.phase);
630
+ selection = routed.selection;
631
+ if (routed.warning !== null) {
632
+ writeDiagnostic({
633
+ level: "warning",
634
+ message: routed.warning,
635
+ fields: {
636
+ phase: invocation.phase,
637
+ harness: originalIdentity.harness,
638
+ model: selection.settings.model
639
+ }
640
+ });
641
+ }
542
642
  const attempt = nextAttempt(invocation.phase);
543
643
  const publisher = getSessionPublisher();
544
644
  publisher.publish({
@@ -571,16 +671,14 @@ async function invokeSelectedAgent(invocation) {
571
671
  }
572
672
  const identity = declaredAgentIdentity(selection.provider);
573
673
  const requested = selection.settings.model;
574
- const routingCfg = await loadRoutingConfig();
575
- const agentCfg = await loadAgentConfig();
576
- const routingDecision = decideRouting({
577
- phase: invocation.phase,
578
- actualHarness: identity.harness,
579
- mode: routingCfg.mode,
580
- profile: routingCfg.profile,
581
- skipScore: hasExplicitAgentSelection(agentCfg, getAgentCliOverrides()),
582
- requiresExtraDirectories: (invocation.addDirs?.length ?? 0) > 0
583
- });
674
+ const recordedRoutingDecision = routingDecision !== null && routed.applied ? {
675
+ ...routingDecision,
676
+ actual: {
677
+ harness: identity.harness,
678
+ provider: selection.provider,
679
+ model: requested
680
+ }
681
+ } : routingDecision;
584
682
  const executionId = await beginExecution({
585
683
  purpose: invocation.purpose ?? invocation.phase,
586
684
  attempt,
@@ -591,11 +689,13 @@ async function invokeSelectedAgent(invocation) {
591
689
  harnessVersion: peekHarnessVersion(selection.provider) ?? null,
592
690
  modelRequested: requested,
593
691
  modelResolved: null,
594
- modelSource: requested ? "config" : "unavailable",
692
+ modelSource: requested ? routed.applied ? "routing" : "config" : "unavailable",
595
693
  ...invocation.iteration === void 0 ? {} : { iteration: invocation.iteration },
596
694
  ...invocation.correctionCycle === void 0 ? {} : { correctionCycle: invocation.correctionCycle },
597
695
  ...invocation.storyIds === void 0 ? {} : { storyIds: invocation.storyIds },
598
- ...routingDecision === null ? {} : { routingDecision }
696
+ ...recordedRoutingDecision === null ? {} : {
697
+ routingDecision: recordedRoutingDecision
698
+ }
599
699
  });
600
700
  bindDiagnosticContext({
601
701
  executionId,
@@ -775,7 +875,7 @@ async function invokeSelectedAgent(invocation) {
775
875
  error: failure === null ? null : run.error ?? run.rawOutput,
776
876
  exitCode: run.exitCode,
777
877
  modelResolved: run.agent.model,
778
- modelSource: run.agent.model ? requested ? "config" : "provider" : requested ? "config" : "unavailable",
878
+ modelSource: run.agent.model ? requested ? routed.applied ? "routing" : "config" : "provider" : requested ? routed.applied ? "routing" : "config" : "unavailable",
779
879
  harnessVersion: run.harnessVersion ?? peekHarnessVersion(selection.provider) ?? null,
780
880
  providerSessionId: run.sessionId ?? null,
781
881
  storyIds: invocation.storyIds
@@ -970,8 +1070,6 @@ function buildDecompositionReport(input) {
970
1070
  }
971
1071
 
972
1072
  // src/core/headless.ts
973
- import { readFile as readFile2 } from "fs/promises";
974
- import chalk from "chalk";
975
1073
  var DEFAULT_HEADLESS_TIMEOUT_MS = 9e5;
976
1074
  async function escalatedTimeout(timeoutMs, history) {
977
1075
  if (timeoutMs === 0 || history === void 0) return timeoutMs;
@@ -1200,4 +1298,4 @@ export {
1200
1298
  DEFAULT_HEADLESS_TIMEOUT_MS,
1201
1299
  runHeadless
1202
1300
  };
1203
- //# sourceMappingURL=chunk-5ZKBIXET.js.map
1301
+ //# sourceMappingURL=chunk-UK4E2FUA.js.map