agentplane 0.2.25 → 0.3.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 (221) hide show
  1. package/README.md +3 -1
  2. package/assets/AGENTS.md +123 -526
  3. package/assets/agents/UPGRADER.json +10 -9
  4. package/assets/framework.manifest.json +112 -7
  5. package/assets/policy/check-routing.mjs +180 -0
  6. package/assets/policy/dod.code.md +25 -0
  7. package/assets/policy/dod.core.md +32 -0
  8. package/assets/policy/dod.docs.md +32 -0
  9. package/assets/policy/examples/migration-note.md +6 -0
  10. package/assets/policy/examples/pr-note.md +16 -0
  11. package/assets/policy/examples/unit-test-pattern.md +19 -0
  12. package/assets/policy/governance.md +37 -0
  13. package/assets/policy/incidents.md +36 -0
  14. package/assets/policy/security.must.md +7 -0
  15. package/assets/policy/workflow.branch_pr.md +34 -0
  16. package/assets/policy/workflow.direct.md +46 -0
  17. package/assets/policy/workflow.md +9 -0
  18. package/assets/policy/workflow.release.md +31 -0
  19. package/assets/policy/workflow.upgrade.md +20 -0
  20. package/bin/agentplane.js +47 -57
  21. package/bin/dist-guard.js +124 -0
  22. package/dist/.build-manifest.json +11 -0
  23. package/dist/agents/agents-template.d.ts +7 -0
  24. package/dist/agents/agents-template.d.ts.map +1 -1
  25. package/dist/agents/agents-template.js +41 -2
  26. package/dist/backends/task-backend/local-backend.d.ts +2 -0
  27. package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
  28. package/dist/backends/task-backend/local-backend.js +12 -1
  29. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
  30. package/dist/backends/task-backend/redmine/mapping.js +26 -1
  31. package/dist/backends/task-backend/redmine-backend.d.ts +4 -0
  32. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
  33. package/dist/backends/task-backend/redmine-backend.js +92 -9
  34. package/dist/backends/task-backend/shared/types.d.ts +1 -0
  35. package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
  36. package/dist/backends/task-index.d.ts.map +1 -1
  37. package/dist/backends/task-index.js +8 -1
  38. package/dist/cli/command-guide.d.ts.map +1 -1
  39. package/dist/cli/command-guide.js +39 -17
  40. package/dist/cli/command-snippets.d.ts +24 -0
  41. package/dist/cli/command-snippets.d.ts.map +1 -0
  42. package/dist/cli/command-snippets.js +23 -0
  43. package/dist/cli/reason-codes.d.ts +9 -0
  44. package/dist/cli/reason-codes.d.ts.map +1 -0
  45. package/dist/cli/reason-codes.js +79 -0
  46. package/dist/cli/recipes-bundled.d.ts +1 -0
  47. package/dist/cli/recipes-bundled.d.ts.map +1 -1
  48. package/dist/cli/recipes-bundled.js +4 -1
  49. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  50. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  51. package/dist/cli/run-cli/command-catalog.js +40 -1
  52. package/dist/cli/run-cli/commands/config.d.ts +5 -0
  53. package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
  54. package/dist/cli/run-cli/commands/config.js +86 -1
  55. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  56. package/dist/cli/run-cli/commands/core.js +57 -2
  57. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
  58. package/dist/cli/run-cli/commands/ide.js +8 -3
  59. package/dist/cli/run-cli/commands/init/recipes.d.ts +5 -1
  60. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
  61. package/dist/cli/run-cli/commands/init/recipes.js +24 -4
  62. package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
  63. package/dist/cli/run-cli/commands/init/ui.js +1 -2
  64. package/dist/cli/run-cli/commands/init/write-agents.d.ts +2 -0
  65. package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
  66. package/dist/cli/run-cli/commands/init/write-agents.js +24 -5
  67. package/dist/cli/run-cli/commands/init/write-workflow.d.ts +12 -0
  68. package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -0
  69. package/dist/cli/run-cli/commands/init/write-workflow.js +58 -0
  70. package/dist/cli/run-cli/commands/init.d.ts +4 -1
  71. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  72. package/dist/cli/run-cli/commands/init.js +126 -48
  73. package/dist/cli/run-cli.d.ts.map +1 -1
  74. package/dist/cli/run-cli.js +195 -8
  75. package/dist/commands/backend/sync.command.d.ts.map +1 -1
  76. package/dist/commands/backend/sync.command.js +7 -6
  77. package/dist/commands/backend.d.ts.map +1 -1
  78. package/dist/commands/backend.js +2 -0
  79. package/dist/commands/doctor.run.d.ts.map +1 -1
  80. package/dist/commands/doctor.run.js +107 -16
  81. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  82. package/dist/commands/guard/impl/commands.js +12 -6
  83. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  84. package/dist/commands/recipes/impl/commands/install.js +36 -13
  85. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
  86. package/dist/commands/recipes/impl/scenario.js +25 -0
  87. package/dist/commands/recipes/impl/types.d.ts +4 -0
  88. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  89. package/dist/commands/release/apply.command.d.ts.map +1 -1
  90. package/dist/commands/release/apply.command.js +9 -4
  91. package/dist/commands/release/plan.command.d.ts.map +1 -1
  92. package/dist/commands/release/plan.command.js +9 -3
  93. package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
  94. package/dist/commands/scenario/impl/commands.js +74 -3
  95. package/dist/commands/scenario/impl/report.d.ts +8 -0
  96. package/dist/commands/scenario/impl/report.d.ts.map +1 -1
  97. package/dist/commands/scenario/impl/report.js +1 -0
  98. package/dist/commands/shared/reconcile-check.d.ts +7 -0
  99. package/dist/commands/shared/reconcile-check.d.ts.map +1 -0
  100. package/dist/commands/shared/reconcile-check.js +60 -0
  101. package/dist/commands/sync.command.d.ts.map +1 -1
  102. package/dist/commands/sync.command.js +9 -2
  103. package/dist/commands/task/add.d.ts.map +1 -1
  104. package/dist/commands/task/add.js +32 -0
  105. package/dist/commands/task/doc.command.d.ts.map +1 -1
  106. package/dist/commands/task/doc.command.js +1 -0
  107. package/dist/commands/task/finish.d.ts.map +1 -1
  108. package/dist/commands/task/finish.js +11 -1
  109. package/dist/commands/task/list.d.ts.map +1 -1
  110. package/dist/commands/task/list.js +2 -1
  111. package/dist/commands/task/list.spec.d.ts.map +1 -1
  112. package/dist/commands/task/list.spec.js +7 -0
  113. package/dist/commands/task/new.d.ts.map +1 -1
  114. package/dist/commands/task/new.js +41 -4
  115. package/dist/commands/task/next.d.ts.map +1 -1
  116. package/dist/commands/task/next.js +2 -1
  117. package/dist/commands/task/next.spec.d.ts.map +1 -1
  118. package/dist/commands/task/next.spec.js +7 -0
  119. package/dist/commands/task/plan.d.ts.map +1 -1
  120. package/dist/commands/task/plan.js +7 -1
  121. package/dist/commands/task/search.d.ts.map +1 -1
  122. package/dist/commands/task/search.js +2 -1
  123. package/dist/commands/task/search.spec.d.ts.map +1 -1
  124. package/dist/commands/task/search.spec.js +7 -0
  125. package/dist/commands/task/shared.d.ts +14 -0
  126. package/dist/commands/task/shared.d.ts.map +1 -1
  127. package/dist/commands/task/shared.js +58 -1
  128. package/dist/commands/task/start-ready.js +1 -1
  129. package/dist/commands/task/verify-record.d.ts.map +1 -1
  130. package/dist/commands/task/verify-record.js +2 -0
  131. package/dist/commands/upgrade.command.d.ts.map +1 -1
  132. package/dist/commands/upgrade.command.js +2 -2
  133. package/dist/commands/upgrade.d.ts.map +1 -1
  134. package/dist/commands/upgrade.js +263 -294
  135. package/dist/commands/workflow-build.command.d.ts +8 -0
  136. package/dist/commands/workflow-build.command.d.ts.map +1 -0
  137. package/dist/commands/workflow-build.command.js +103 -0
  138. package/dist/commands/workflow-playbook.command.d.ts +10 -0
  139. package/dist/commands/workflow-playbook.command.d.ts.map +1 -0
  140. package/dist/commands/workflow-playbook.command.js +173 -0
  141. package/dist/commands/workflow-restore.command.d.ts +5 -0
  142. package/dist/commands/workflow-restore.command.d.ts.map +1 -0
  143. package/dist/commands/workflow-restore.command.js +30 -0
  144. package/dist/commands/workflow.command.d.ts +6 -0
  145. package/dist/commands/workflow.command.d.ts.map +1 -0
  146. package/dist/commands/workflow.command.js +36 -0
  147. package/dist/harness/dynamic-tool-contract.d.ts +29 -0
  148. package/dist/harness/dynamic-tool-contract.d.ts.map +1 -0
  149. package/dist/harness/dynamic-tool-contract.js +86 -0
  150. package/dist/harness/hooks-lifecycle.d.ts +27 -0
  151. package/dist/harness/hooks-lifecycle.d.ts.map +1 -0
  152. package/dist/harness/hooks-lifecycle.js +67 -0
  153. package/dist/harness/index.d.ts +9 -0
  154. package/dist/harness/index.d.ts.map +1 -0
  155. package/dist/harness/index.js +8 -0
  156. package/dist/harness/reconcile.d.ts +37 -0
  157. package/dist/harness/reconcile.d.ts.map +1 -0
  158. package/dist/harness/reconcile.js +42 -0
  159. package/dist/harness/retry-policy.d.ts +31 -0
  160. package/dist/harness/retry-policy.d.ts.map +1 -0
  161. package/dist/harness/retry-policy.js +33 -0
  162. package/dist/harness/scheduler.d.ts +18 -0
  163. package/dist/harness/scheduler.d.ts.map +1 -0
  164. package/dist/harness/scheduler.js +55 -0
  165. package/dist/harness/state-machine.d.ts +17 -0
  166. package/dist/harness/state-machine.d.ts.map +1 -0
  167. package/dist/harness/state-machine.js +70 -0
  168. package/dist/harness/token-accounting.d.ts +19 -0
  169. package/dist/harness/token-accounting.d.ts.map +1 -0
  170. package/dist/harness/token-accounting.js +77 -0
  171. package/dist/harness/workspace-safety.d.ts +14 -0
  172. package/dist/harness/workspace-safety.d.ts.map +1 -0
  173. package/dist/harness/workspace-safety.js +62 -0
  174. package/dist/recipes/bundled-recipes.d.ts +4 -0
  175. package/dist/recipes/bundled-recipes.d.ts.map +1 -1
  176. package/dist/recipes/bundled-recipes.js +11 -0
  177. package/dist/shared/errors.d.ts +6 -0
  178. package/dist/shared/errors.d.ts.map +1 -1
  179. package/dist/shared/errors.js +1 -0
  180. package/dist/shared/policy-gateway.d.ts +15 -0
  181. package/dist/shared/policy-gateway.d.ts.map +1 -0
  182. package/dist/shared/policy-gateway.js +49 -0
  183. package/dist/shared/protected-paths.d.ts.map +1 -1
  184. package/dist/shared/protected-paths.js +1 -0
  185. package/dist/shared/runtime-artifacts.d.ts +2 -2
  186. package/dist/shared/runtime-artifacts.d.ts.map +1 -1
  187. package/dist/shared/runtime-artifacts.js +4 -0
  188. package/dist/workflow-runtime/build.d.ts +4 -0
  189. package/dist/workflow-runtime/build.d.ts.map +1 -0
  190. package/dist/workflow-runtime/build.js +126 -0
  191. package/dist/workflow-runtime/enforcement.d.ts +3 -0
  192. package/dist/workflow-runtime/enforcement.d.ts.map +1 -0
  193. package/dist/workflow-runtime/enforcement.js +10 -0
  194. package/dist/workflow-runtime/file-ops.d.ts +11 -0
  195. package/dist/workflow-runtime/file-ops.d.ts.map +1 -0
  196. package/dist/workflow-runtime/file-ops.js +248 -0
  197. package/dist/workflow-runtime/fix.d.ts +9 -0
  198. package/dist/workflow-runtime/fix.d.ts.map +1 -0
  199. package/dist/workflow-runtime/fix.js +107 -0
  200. package/dist/workflow-runtime/index.d.ts +11 -0
  201. package/dist/workflow-runtime/index.d.ts.map +1 -0
  202. package/dist/workflow-runtime/index.js +10 -0
  203. package/dist/workflow-runtime/markdown.d.ts +10 -0
  204. package/dist/workflow-runtime/markdown.d.ts.map +1 -0
  205. package/dist/workflow-runtime/markdown.js +147 -0
  206. package/dist/workflow-runtime/observability.d.ts +12 -0
  207. package/dist/workflow-runtime/observability.d.ts.map +1 -0
  208. package/dist/workflow-runtime/observability.js +14 -0
  209. package/dist/workflow-runtime/paths.d.ts +3 -0
  210. package/dist/workflow-runtime/paths.d.ts.map +1 -0
  211. package/dist/workflow-runtime/paths.js +11 -0
  212. package/dist/workflow-runtime/template.d.ts +7 -0
  213. package/dist/workflow-runtime/template.d.ts.map +1 -0
  214. package/dist/workflow-runtime/template.js +94 -0
  215. package/dist/workflow-runtime/types.d.ts +68 -0
  216. package/dist/workflow-runtime/types.d.ts.map +1 -0
  217. package/dist/workflow-runtime/types.js +1 -0
  218. package/dist/workflow-runtime/validate.d.ts +8 -0
  219. package/dist/workflow-runtime/validate.d.ts.map +1 -0
  220. package/dist/workflow-runtime/validate.js +331 -0
  221. package/package.json +3 -3
@@ -0,0 +1,37 @@
1
+ import type { OrchestrationState } from "./state-machine.js";
2
+ export type ReconcileRunningEntry = {
3
+ issueId: string;
4
+ issueIdentifier: string;
5
+ state: string;
6
+ orchestrationState: OrchestrationState;
7
+ startedAt: Date;
8
+ lastActivityAt: Date;
9
+ };
10
+ export type ReconcileObservedIssue = {
11
+ id: string;
12
+ state: string;
13
+ assignedToWorker: boolean;
14
+ };
15
+ export type ReconcileConfig = {
16
+ activeStates: string[];
17
+ terminalStates: string[];
18
+ stallTimeoutMs: number;
19
+ };
20
+ export type ReconcileAction = {
21
+ type: "stop_running";
22
+ issueId: string;
23
+ reason: "terminal" | "non_active" | "not_routed";
24
+ } | {
25
+ type: "restart_stalled";
26
+ issueId: string;
27
+ elapsedMs: number;
28
+ } | {
29
+ type: "keep_running";
30
+ issueId: string;
31
+ };
32
+ export type ReconcileResult = {
33
+ nextRunning: ReconcileRunningEntry[];
34
+ actions: ReconcileAction[];
35
+ };
36
+ export declare function reconcileFirst(running: readonly ReconcileRunningEntry[], observed: readonly ReconcileObservedIssue[], config: ReconcileConfig, now: Date): ReconcileResult;
37
+ //# sourceMappingURL=reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../src/harness/reconcile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,SAAS,EAAE,IAAI,CAAC;IAChB,cAAc,EAAE,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,YAAY,CAAA;CAAE,GAC3F;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,EAAE,qBAAqB,EAAE,CAAC;IACrC,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAAC;AAWF,wBAAgB,cAAc,CAC5B,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,EAC3C,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,IAAI,GACR,eAAe,CA0CjB"}
@@ -0,0 +1,42 @@
1
+ function normalizeState(value) {
2
+ return value.trim().toLowerCase();
3
+ }
4
+ function isStateInSet(value, set) {
5
+ const normalized = normalizeState(value);
6
+ return set.some((item) => normalizeState(item) === normalized);
7
+ }
8
+ export function reconcileFirst(running, observed, config, now) {
9
+ const observedById = new Map(observed.map((issue) => [issue.id, issue]));
10
+ const nextRunning = [];
11
+ const actions = [];
12
+ for (const entry of running) {
13
+ const observedIssue = observedById.get(entry.issueId);
14
+ if (!observedIssue) {
15
+ actions.push({ type: "stop_running", issueId: entry.issueId, reason: "non_active" });
16
+ continue;
17
+ }
18
+ if (isStateInSet(observedIssue.state, config.terminalStates)) {
19
+ actions.push({ type: "stop_running", issueId: entry.issueId, reason: "terminal" });
20
+ continue;
21
+ }
22
+ if (!observedIssue.assignedToWorker) {
23
+ actions.push({ type: "stop_running", issueId: entry.issueId, reason: "not_routed" });
24
+ continue;
25
+ }
26
+ if (!isStateInSet(observedIssue.state, config.activeStates)) {
27
+ actions.push({ type: "stop_running", issueId: entry.issueId, reason: "non_active" });
28
+ continue;
29
+ }
30
+ const elapsedMs = Math.max(0, now.getTime() - entry.lastActivityAt.getTime());
31
+ if (config.stallTimeoutMs > 0 && elapsedMs > config.stallTimeoutMs) {
32
+ actions.push({ type: "restart_stalled", issueId: entry.issueId, elapsedMs });
33
+ continue;
34
+ }
35
+ actions.push({ type: "keep_running", issueId: entry.issueId });
36
+ nextRunning.push({ ...entry, state: observedIssue.state });
37
+ }
38
+ return {
39
+ nextRunning,
40
+ actions,
41
+ };
42
+ }
@@ -0,0 +1,31 @@
1
+ export type RetryReasonCode = "continuation_needed" | "worker_exit_abnormal" | "worker_spawn_failed" | "stalled_timeout" | "poll_failed" | "no_slots" | "reconcile_conflict";
2
+ export type RetryDelayType = "continuation" | "failure";
3
+ export type RetryPolicy = {
4
+ continuationDelayMs: number;
5
+ failureBaseDelayMs: number;
6
+ maxBackoffMs: number;
7
+ maxAttempts: number;
8
+ };
9
+ export type RetryEntry = {
10
+ issueId: string;
11
+ attempt: number;
12
+ dueAtMs: number;
13
+ reasonCode: RetryReasonCode;
14
+ reasonMessage?: string;
15
+ delayType: RetryDelayType;
16
+ };
17
+ export declare function computeRetryDelayMs(attempt: number, delayType: RetryDelayType, policy?: RetryPolicy): number;
18
+ export declare function scheduleRetryEntry(opts: {
19
+ issueId: string;
20
+ attempt: number;
21
+ reasonCode: RetryReasonCode;
22
+ reasonMessage?: string;
23
+ delayType: RetryDelayType;
24
+ nowMs: number;
25
+ policy?: RetryPolicy;
26
+ }): RetryEntry;
27
+ export declare function canRetry(attempt: number, policy?: RetryPolicy): {
28
+ allowed: boolean;
29
+ terminal: boolean;
30
+ };
31
+ //# sourceMappingURL=retry-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-policy.d.ts","sourceRoot":"","sources":["../../src/harness/retry-policy.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,qBAAqB,GACrB,sBAAsB,GACtB,qBAAqB,GACrB,iBAAiB,GACjB,aAAa,GACb,UAAU,GACV,oBAAoB,CAAC;AAEzB,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,SAAS,CAAC;AAExD,MAAM,MAAM,WAAW,GAAG;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,eAAe,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,cAAc,CAAC;CAC3B,CAAC;AASF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,cAAc,EACzB,MAAM,GAAE,WAA4B,GACnC,MAAM,CAOR;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,eAAe,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,UAAU,CAYb;AAED,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,WAA4B,GACnC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAKzC"}
@@ -0,0 +1,33 @@
1
+ const DEFAULT_POLICY = {
2
+ continuationDelayMs: 1000,
3
+ failureBaseDelayMs: 10_000,
4
+ maxBackoffMs: 300_000,
5
+ maxAttempts: 5,
6
+ };
7
+ export function computeRetryDelayMs(attempt, delayType, policy = DEFAULT_POLICY) {
8
+ if (delayType === "continuation" && attempt <= 1) {
9
+ return policy.continuationDelayMs;
10
+ }
11
+ const power = Math.max(0, Math.min(attempt - 1, 10));
12
+ const delayed = policy.failureBaseDelayMs * 2 ** power;
13
+ return Math.min(delayed, policy.maxBackoffMs);
14
+ }
15
+ export function scheduleRetryEntry(opts) {
16
+ const policy = opts.policy ?? DEFAULT_POLICY;
17
+ const safeAttempt = Math.max(1, opts.attempt);
18
+ const delayMs = computeRetryDelayMs(safeAttempt, opts.delayType, policy);
19
+ return {
20
+ issueId: opts.issueId,
21
+ attempt: safeAttempt,
22
+ dueAtMs: opts.nowMs + delayMs,
23
+ reasonCode: opts.reasonCode,
24
+ reasonMessage: opts.reasonMessage,
25
+ delayType: opts.delayType,
26
+ };
27
+ }
28
+ export function canRetry(attempt, policy = DEFAULT_POLICY) {
29
+ if (attempt < policy.maxAttempts) {
30
+ return { allowed: true, terminal: false };
31
+ }
32
+ return { allowed: false, terminal: true };
33
+ }
@@ -0,0 +1,18 @@
1
+ export type SchedulerIssue = {
2
+ id: string;
3
+ state: string;
4
+ priority?: number | null;
5
+ createdAt?: string | null;
6
+ };
7
+ export type SchedulerEntry = {
8
+ issue: SchedulerIssue;
9
+ workerId: string;
10
+ };
11
+ export type SchedulerLimits = {
12
+ maxConcurrent: number;
13
+ maxConcurrentByState?: Record<string, number>;
14
+ };
15
+ export declare function sortIssuesForDispatch(issues: readonly SchedulerIssue[]): SchedulerIssue[];
16
+ export declare function canDispatchIssue(issue: SchedulerIssue, running: readonly SchedulerEntry[], limits: SchedulerLimits): boolean;
17
+ export declare function planDispatch(candidates: readonly SchedulerIssue[], running: readonly SchedulerEntry[], limits: SchedulerLimits): SchedulerIssue[];
18
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/harness/scheduler.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C,CAAC;AAoBF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,GAAG,cAAc,EAAE,CAYzF;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,MAAM,EAAE,eAAe,GACtB,OAAO,CAaT;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,cAAc,EAAE,EACrC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,MAAM,EAAE,eAAe,GACtB,cAAc,EAAE,CAYlB"}
@@ -0,0 +1,55 @@
1
+ function normalizeState(value) {
2
+ return value.trim().toLowerCase();
3
+ }
4
+ function createdAtMicros(value) {
5
+ if (!value)
6
+ return Number.MAX_SAFE_INTEGER;
7
+ const parsed = Date.parse(value);
8
+ if (Number.isNaN(parsed))
9
+ return Number.MAX_SAFE_INTEGER;
10
+ return parsed * 1000;
11
+ }
12
+ function priorityRank(priority) {
13
+ if (typeof priority !== "number")
14
+ return 5;
15
+ if (!Number.isInteger(priority))
16
+ return 5;
17
+ if (priority < 1 || priority > 4)
18
+ return 5;
19
+ return priority;
20
+ }
21
+ export function sortIssuesForDispatch(issues) {
22
+ return issues.toSorted((a, b) => {
23
+ const aPriority = priorityRank(a.priority);
24
+ const bPriority = priorityRank(b.priority);
25
+ if (aPriority !== bPriority)
26
+ return aPriority - bPriority;
27
+ const aCreated = createdAtMicros(a.createdAt);
28
+ const bCreated = createdAtMicros(b.createdAt);
29
+ if (aCreated !== bCreated)
30
+ return aCreated - bCreated;
31
+ return a.id.localeCompare(b.id);
32
+ });
33
+ }
34
+ export function canDispatchIssue(issue, running, limits) {
35
+ const totalRunning = running.length;
36
+ if (totalRunning >= limits.maxConcurrent)
37
+ return false;
38
+ const stateKey = normalizeState(issue.state);
39
+ const stateLimitRaw = limits.maxConcurrentByState?.[stateKey];
40
+ const stateLimit = typeof stateLimitRaw === "number" && stateLimitRaw > 0 ? stateLimitRaw : limits.maxConcurrent;
41
+ const stateUsed = running.filter((entry) => normalizeState(entry.issue.state) === stateKey).length;
42
+ return stateUsed < stateLimit;
43
+ }
44
+ export function planDispatch(candidates, running, limits) {
45
+ const ordered = sortIssuesForDispatch(candidates);
46
+ const accepted = [];
47
+ const shadowRunning = [...running];
48
+ for (const issue of ordered) {
49
+ if (!canDispatchIssue(issue, shadowRunning, limits))
50
+ continue;
51
+ accepted.push(issue);
52
+ shadowRunning.push({ issue, workerId: `planned:${issue.id}` });
53
+ }
54
+ return accepted;
55
+ }
@@ -0,0 +1,17 @@
1
+ export type OrchestrationState = "unclaimed" | "claimed" | "running" | "retry_queued" | "released";
2
+ export type OrchestrationEvent = "claim" | "start" | "queue_retry" | "release" | "mark_released" | "reset";
3
+ export type TransitionResult = {
4
+ ok: true;
5
+ next: OrchestrationState;
6
+ } | {
7
+ ok: false;
8
+ code: "ORCH_INVALID_TRANSITION";
9
+ message: string;
10
+ current: OrchestrationState;
11
+ event: OrchestrationEvent;
12
+ };
13
+ export declare function transitionOrchestrationState(current: OrchestrationState, event: OrchestrationEvent, opts?: {
14
+ strict?: boolean;
15
+ }): TransitionResult;
16
+ export declare function assertTransitionOrThrow(current: OrchestrationState, event: OrchestrationEvent): OrchestrationState;
17
+ //# sourceMappingURL=state-machine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-machine.d.ts","sourceRoot":"","sources":["../../src/harness/state-machine.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,GAAG,UAAU,CAAC;AAEnG,MAAM,MAAM,kBAAkB,GAC1B,OAAO,GACP,OAAO,GACP,aAAa,GACb,SAAS,GACT,eAAe,GACf,OAAO,CAAC;AAEZ,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,GACtC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,CAAC;CAC3B,CAAC;AAqDN,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,KAAK,EAAE,kBAAkB,EACzB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1B,gBAAgB,CAalB;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,CAMpB"}
@@ -0,0 +1,70 @@
1
+ const TRANSITIONS = {
2
+ unclaimed: {
3
+ claim: "claimed",
4
+ start: "unclaimed",
5
+ queue_retry: "unclaimed",
6
+ release: "released",
7
+ mark_released: "released",
8
+ reset: "unclaimed",
9
+ },
10
+ claimed: {
11
+ claim: "claimed",
12
+ start: "running",
13
+ queue_retry: "retry_queued",
14
+ release: "released",
15
+ mark_released: "released",
16
+ reset: "unclaimed",
17
+ },
18
+ running: {
19
+ claim: "running",
20
+ start: "running",
21
+ queue_retry: "retry_queued",
22
+ release: "released",
23
+ mark_released: "released",
24
+ reset: "unclaimed",
25
+ },
26
+ retry_queued: {
27
+ claim: "claimed",
28
+ start: "running",
29
+ queue_retry: "retry_queued",
30
+ release: "released",
31
+ mark_released: "released",
32
+ reset: "unclaimed",
33
+ },
34
+ released: {
35
+ claim: "claimed",
36
+ start: "released",
37
+ queue_retry: "released",
38
+ release: "released",
39
+ mark_released: "released",
40
+ reset: "unclaimed",
41
+ },
42
+ };
43
+ const STRICT_ALLOWED = {
44
+ unclaimed: ["claim", "mark_released", "reset"],
45
+ claimed: ["start", "queue_retry", "release", "reset"],
46
+ running: ["queue_retry", "release", "reset"],
47
+ retry_queued: ["claim", "start", "release", "reset"],
48
+ released: ["claim", "reset"],
49
+ };
50
+ export function transitionOrchestrationState(current, event, opts) {
51
+ const strict = opts?.strict ?? true;
52
+ if (strict && !STRICT_ALLOWED[current].includes(event)) {
53
+ return {
54
+ ok: false,
55
+ code: "ORCH_INVALID_TRANSITION",
56
+ message: `Invalid transition: ${current} --${event}--> ?`,
57
+ current,
58
+ event,
59
+ };
60
+ }
61
+ const next = TRANSITIONS[current][event];
62
+ return { ok: true, next };
63
+ }
64
+ export function assertTransitionOrThrow(current, event) {
65
+ const result = transitionOrchestrationState(current, event, { strict: true });
66
+ if (!result.ok) {
67
+ throw new Error(`${result.code}: ${result.message}`);
68
+ }
69
+ return result.next;
70
+ }
@@ -0,0 +1,19 @@
1
+ export type TokenTotals = {
2
+ inputTokens: number;
3
+ outputTokens: number;
4
+ totalTokens: number;
5
+ };
6
+ export type TokenUsageEvent = {
7
+ threadId: string;
8
+ payload: Record<string, unknown>;
9
+ };
10
+ export type TokenAccumulator = {
11
+ byThread: Record<string, TokenTotals>;
12
+ global: TokenTotals;
13
+ };
14
+ export declare function createTokenAccumulator(): TokenAccumulator;
15
+ export declare function applyTokenUsageEvent(state: TokenAccumulator, event: TokenUsageEvent): {
16
+ state: TokenAccumulator;
17
+ accepted: boolean;
18
+ };
19
+ //# sourceMappingURL=token-accounting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-accounting.d.ts","sourceRoot":"","sources":["../../src/harness/token-accounting.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAwDF,wBAAgB,sBAAsB,IAAI,gBAAgB,CAKzD;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,eAAe,GACrB;IAAE,KAAK,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAuBhD"}
@@ -0,0 +1,77 @@
1
+ const ZERO_TOTALS = {
2
+ inputTokens: 0,
3
+ outputTokens: 0,
4
+ totalTokens: 0,
5
+ };
6
+ function safeInt(value) {
7
+ if (typeof value === "number" && Number.isFinite(value))
8
+ return Math.trunc(value);
9
+ if (typeof value === "string" && /^\d+$/.test(value))
10
+ return Number.parseInt(value, 10);
11
+ return null;
12
+ }
13
+ function extractAbsoluteTotals(payload) {
14
+ const tokenUsage = payload.tokenUsage;
15
+ if (tokenUsage && typeof tokenUsage === "object" && !Array.isArray(tokenUsage)) {
16
+ const total = tokenUsage.total;
17
+ if (total && typeof total === "object" && !Array.isArray(total)) {
18
+ const totalObj = total;
19
+ const input = safeInt(totalObj.inputTokens);
20
+ const output = safeInt(totalObj.outputTokens);
21
+ const all = safeInt(totalObj.totalTokens);
22
+ if (input !== null && output !== null && all !== null) {
23
+ return { inputTokens: input, outputTokens: output, totalTokens: all };
24
+ }
25
+ }
26
+ }
27
+ const info = payload.info;
28
+ if (info && typeof info === "object" && !Array.isArray(info)) {
29
+ const totalUsage = info.total_token_usage;
30
+ if (totalUsage && typeof totalUsage === "object" && !Array.isArray(totalUsage)) {
31
+ const usage = totalUsage;
32
+ const input = safeInt(usage.input_tokens);
33
+ const output = safeInt(usage.output_tokens);
34
+ const all = safeInt(usage.total_tokens);
35
+ if (input !== null && output !== null && all !== null) {
36
+ return { inputTokens: input, outputTokens: output, totalTokens: all };
37
+ }
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ function mergeGlobal(byThread) {
43
+ const global = { ...ZERO_TOTALS };
44
+ for (const totals of Object.values(byThread)) {
45
+ global.inputTokens += totals.inputTokens;
46
+ global.outputTokens += totals.outputTokens;
47
+ global.totalTokens += totals.totalTokens;
48
+ }
49
+ return global;
50
+ }
51
+ export function createTokenAccumulator() {
52
+ return {
53
+ byThread: {},
54
+ global: { ...ZERO_TOTALS },
55
+ };
56
+ }
57
+ export function applyTokenUsageEvent(state, event) {
58
+ const absolute = extractAbsoluteTotals(event.payload);
59
+ if (!absolute) {
60
+ return { state, accepted: false };
61
+ }
62
+ const prev = state.byThread[event.threadId] ?? { ...ZERO_TOTALS };
63
+ if (absolute.totalTokens < prev.totalTokens) {
64
+ return { state, accepted: false };
65
+ }
66
+ const nextByThread = {
67
+ ...state.byThread,
68
+ [event.threadId]: absolute,
69
+ };
70
+ return {
71
+ accepted: true,
72
+ state: {
73
+ byThread: nextByThread,
74
+ global: mergeGlobal(nextByThread),
75
+ },
76
+ };
77
+ }
@@ -0,0 +1,14 @@
1
+ export declare function sanitizeWorkspaceKey(raw: string): string;
2
+ export declare function resolveWorkspacePath(root: string, key: string): string;
3
+ export declare function validateWorkspacePathInvariants(opts: {
4
+ root: string;
5
+ workspacePath: string;
6
+ }): Promise<{
7
+ ok: true;
8
+ } | {
9
+ ok: false;
10
+ code: "WORKSPACE_EQUALS_ROOT" | "WORKSPACE_OUTSIDE_ROOT" | "WORKSPACE_SYMLINK_ESCAPE" | "WORKSPACE_PATH_UNREADABLE";
11
+ path: string;
12
+ message: string;
13
+ }>;
14
+ //# sourceMappingURL=workspace-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-safety.d.ts","sourceRoot":"","sources":["../../src/harness/workspace-safety.ts"],"names":[],"mappings":"AAGA,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAsB,+BAA+B,CAAC,IAAI,EAAE;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CACP;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EACA,uBAAuB,GACvB,wBAAwB,GACxB,0BAA0B,GAC1B,2BAA2B,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CACJ,CAqDA"}
@@ -0,0 +1,62 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export function sanitizeWorkspaceKey(raw) {
4
+ const normalized = raw.trim();
5
+ if (normalized.length === 0)
6
+ return "issue";
7
+ return normalized.replaceAll(/[^a-zA-Z0-9._-]/g, "_");
8
+ }
9
+ export function resolveWorkspacePath(root, key) {
10
+ return path.join(path.resolve(root), sanitizeWorkspaceKey(key));
11
+ }
12
+ export async function validateWorkspacePathInvariants(opts) {
13
+ const root = path.resolve(opts.root);
14
+ const workspace = path.resolve(opts.workspacePath);
15
+ const rootPrefix = `${root}${path.sep}`;
16
+ if (workspace === root) {
17
+ return {
18
+ ok: false,
19
+ code: "WORKSPACE_EQUALS_ROOT",
20
+ path: workspace,
21
+ message: "Workspace path must not equal workspace root.",
22
+ };
23
+ }
24
+ if (!(workspace === root || workspace.startsWith(rootPrefix))) {
25
+ return {
26
+ ok: false,
27
+ code: "WORKSPACE_OUTSIDE_ROOT",
28
+ path: workspace,
29
+ message: "Workspace path escapes configured workspace root.",
30
+ };
31
+ }
32
+ const relative = path.relative(root, workspace);
33
+ const segments = relative.split(path.sep).filter((s) => s.length > 0);
34
+ let cursor = root;
35
+ for (const segment of segments) {
36
+ cursor = path.join(cursor, segment);
37
+ try {
38
+ const stat = await fs.lstat(cursor);
39
+ if (stat.isSymbolicLink()) {
40
+ return {
41
+ ok: false,
42
+ code: "WORKSPACE_SYMLINK_ESCAPE",
43
+ path: cursor,
44
+ message: "Workspace path contains a symlink component.",
45
+ };
46
+ }
47
+ }
48
+ catch (error) {
49
+ const err = error;
50
+ if (err.code === "ENOENT") {
51
+ return { ok: true };
52
+ }
53
+ return {
54
+ ok: false,
55
+ code: "WORKSPACE_PATH_UNREADABLE",
56
+ path: cursor,
57
+ message: `Workspace path cannot be validated: ${err.message}`,
58
+ };
59
+ }
60
+ }
61
+ return { ok: true };
62
+ }
@@ -4,10 +4,14 @@ export type BundledRecipesCatalog = {
4
4
  id: string;
5
5
  summary: string;
6
6
  description?: string;
7
+ source_path?: string;
7
8
  versions: {
8
9
  version: string;
9
10
  }[];
10
11
  }[];
11
12
  };
13
+ export type BundledRecipeEntry = BundledRecipesCatalog["recipes"][number];
12
14
  export declare const BUNDLED_RECIPES_CATALOG: BundledRecipesCatalog;
15
+ export declare function resolveBundledRecipeSourcePath(recipeId: string): string | null;
16
+ export declare function getBundledRecipeEntry(recipeId: string): BundledRecipeEntry | null;
13
17
  //# sourceMappingURL=bundled-recipes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundled-recipes.d.ts","sourceRoot":"","sources":["../../src/recipes/bundled-recipes.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,CAAC,CAAC;IAClB,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KACjC,EAAE,CAAC;CACL,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,qBAGrC,CAAC"}
1
+ {"version":3,"file":"bundled-recipes.d.ts","sourceRoot":"","sources":["../../src/recipes/bundled-recipes.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,CAAC,CAAC;IAClB,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KACjC,EAAE,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,eAAO,MAAM,uBAAuB,EAAE,qBAGrC,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK9E;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAEjF"}
@@ -1,4 +1,15 @@
1
+ import { fileURLToPath } from "node:url";
1
2
  export const BUNDLED_RECIPES_CATALOG = {
2
3
  schema_version: 1,
3
4
  recipes: [],
4
5
  };
6
+ export function resolveBundledRecipeSourcePath(recipeId) {
7
+ const entry = getBundledRecipeEntry(recipeId);
8
+ const sourcePath = entry?.source_path?.trim();
9
+ if (!sourcePath)
10
+ return null;
11
+ return fileURLToPath(new URL(`../../assets/${sourcePath.replace(/^\/+/, "")}`, import.meta.url));
12
+ }
13
+ export function getBundledRecipeEntry(recipeId) {
14
+ return BUNDLED_RECIPES_CATALOG.recipes.find((recipe) => recipe.id === recipeId) ?? null;
15
+ }
@@ -17,6 +17,12 @@ export type JsonErrorGuidance = {
17
17
  reason: string;
18
18
  reasonCode?: string;
19
19
  };
20
+ reasonDecode?: {
21
+ code: string;
22
+ category: string;
23
+ summary: string;
24
+ action: string;
25
+ };
20
26
  };
21
27
  export declare function formatJsonError(err: CliError, guidance?: JsonErrorGuidance): string;
22
28
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/shared/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,cAAc,GACd,MAAM,GACN,OAAO,GACP,WAAW,GACX,WAAW,GACX,YAAY,CAAC;AAEjB,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,IAAI,EAAE,SAAS,CAAC;IAChC,SAAgB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEtC,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,SAAS,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC;CAMF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AAEF,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAcnF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/shared/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,cAAc,GACd,MAAM,GACN,OAAO,GACP,WAAW,GACX,WAAW,GACX,YAAY,CAAC;AAEjB,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,IAAI,EAAE,SAAS,CAAC;IAChC,SAAgB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEtC,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,SAAS,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC;CAMF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AAEF,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAenF"}
@@ -17,6 +17,7 @@ export function formatJsonError(err, guidance) {
17
17
  context: err.context ?? undefined,
18
18
  hint: guidance?.hint,
19
19
  next_action: guidance?.nextAction,
20
+ reason_decode: guidance?.reasonDecode,
20
21
  },
21
22
  }, null, 2);
22
23
  }
@@ -0,0 +1,15 @@
1
+ export type PolicyGatewayFlavor = "codex" | "claude";
2
+ export type PolicyGatewayFileName = "AGENTS.md" | "CLAUDE.md";
3
+ export declare const POLICY_GATEWAY_FILE_BY_FLAVOR: Record<PolicyGatewayFlavor, PolicyGatewayFileName>;
4
+ export type PolicyGatewayResolution = {
5
+ flavor: PolicyGatewayFlavor;
6
+ fileName: PolicyGatewayFileName;
7
+ absPath: string;
8
+ };
9
+ export declare function policyGatewayFileName(flavor: PolicyGatewayFlavor): PolicyGatewayFileName;
10
+ export declare function renderPolicyGatewayTemplateText(text: string, fileName: PolicyGatewayFileName): string;
11
+ export declare function resolvePolicyGatewayForRepo(opts: {
12
+ gitRoot: string;
13
+ fallbackFlavor?: PolicyGatewayFlavor;
14
+ }): Promise<PolicyGatewayResolution>;
15
+ //# sourceMappingURL=policy-gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-gateway.d.ts","sourceRoot":"","sources":["../../src/shared/policy-gateway.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,QAAQ,CAAC;AACrD,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,WAAW,CAAC;AAE9D,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,mBAAmB,EAAE,qBAAqB,CAG5F,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAWF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,mBAAmB,GAAG,qBAAqB,CAExF;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,qBAAqB,GAC9B,MAAM,CAUR;AAED,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAoBnC"}
@@ -0,0 +1,49 @@
1
+ import { access } from "node:fs/promises";
2
+ import path from "node:path";
3
+ export const POLICY_GATEWAY_FILE_BY_FLAVOR = {
4
+ codex: "AGENTS.md",
5
+ claude: "CLAUDE.md",
6
+ };
7
+ async function exists(absPath) {
8
+ try {
9
+ await access(absPath);
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ export function policyGatewayFileName(flavor) {
17
+ return POLICY_GATEWAY_FILE_BY_FLAVOR[flavor];
18
+ }
19
+ export function renderPolicyGatewayTemplateText(text, fileName) {
20
+ const collapsed = text
21
+ .replaceAll("{{POLICY_GATEWAY_FILE}}", fileName)
22
+ .replaceAll("AGENTS.md or CLAUDE.md", fileName)
23
+ .replaceAll("AGENTS.md and CLAUDE.md", fileName)
24
+ .replaceAll("AGENTS.md|CLAUDE.md", fileName);
25
+ if (fileName === "AGENTS.md")
26
+ return collapsed;
27
+ return collapsed
28
+ .replaceAll("AGENTS.md", "CLAUDE.md")
29
+ .replaceAll("AGENTS_POLICY", "CLAUDE_POLICY");
30
+ }
31
+ export async function resolvePolicyGatewayForRepo(opts) {
32
+ const codexPath = path.join(opts.gitRoot, POLICY_GATEWAY_FILE_BY_FLAVOR.codex);
33
+ const claudePath = path.join(opts.gitRoot, POLICY_GATEWAY_FILE_BY_FLAVOR.claude);
34
+ const hasCodex = await exists(codexPath);
35
+ const hasClaude = await exists(claudePath);
36
+ if (hasCodex) {
37
+ return { flavor: "codex", fileName: "AGENTS.md", absPath: codexPath };
38
+ }
39
+ if (hasClaude) {
40
+ return { flavor: "claude", fileName: "CLAUDE.md", absPath: claudePath };
41
+ }
42
+ const fallback = opts.fallbackFlavor ?? "codex";
43
+ const fileName = policyGatewayFileName(fallback);
44
+ return {
45
+ flavor: fallback,
46
+ fileName,
47
+ absPath: path.join(opts.gitRoot, fileName),
48
+ };
49
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"protected-paths.d.ts","sourceRoot":"","sources":["../../src/shared/protected-paths.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAQF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,qBAAqB,CAkBvF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,iBAAiB,GAAG,IAAI,CA6B3B"}
1
+ {"version":3,"file":"protected-paths.d.ts","sourceRoot":"","sources":["../../src/shared/protected-paths.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAQF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,qBAAqB,CAkBvF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,iBAAiB,GAAG,IAAI,CA8B3B"}