specrails-core 5.5.1 → 6.0.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 (276) hide show
  1. package/README.md +27 -145
  2. package/bin/specrails-core.mjs +12 -554
  3. package/dist/agent-runtime/capabilities.js +0 -1
  4. package/dist/agent-runtime/cli-executor.d.ts +1 -1
  5. package/dist/agent-runtime/cli-executor.js +4 -3
  6. package/dist/agent-runtime/cli-process.js +0 -1
  7. package/dist/agent-runtime/cli.d.ts +8 -0
  8. package/dist/agent-runtime/cli.js +31 -5
  9. package/dist/agent-runtime/codex-schema.js +0 -1
  10. package/dist/agent-runtime/compact/architect.d.ts +3 -272
  11. package/dist/agent-runtime/compact/architect.js +8 -9
  12. package/dist/agent-runtime/compact/chat-client.d.ts +3 -3
  13. package/dist/agent-runtime/compact/chat-client.js +1 -2
  14. package/dist/agent-runtime/compact/developer.d.ts +3 -70
  15. package/dist/agent-runtime/compact/developer.js +13 -14
  16. package/dist/agent-runtime/compact/environment.d.ts +4 -5
  17. package/dist/agent-runtime/compact/environment.js +1 -2
  18. package/dist/agent-runtime/compact/exit-code-honesty.d.ts +2 -1
  19. package/dist/agent-runtime/compact/exit-code-honesty.js +0 -1
  20. package/dist/agent-runtime/compact/guarded-loop.d.ts +2 -18
  21. package/dist/agent-runtime/compact/guarded-loop.js +7 -8
  22. package/dist/agent-runtime/compact/prompt-inputs.d.ts +0 -2
  23. package/dist/agent-runtime/compact/prompt-inputs.js +1 -2
  24. package/dist/agent-runtime/compact/reviewer.d.ts +0 -13
  25. package/dist/agent-runtime/compact/reviewer.js +5 -6
  26. package/dist/agent-runtime/compact/step.d.ts +0 -1
  27. package/dist/agent-runtime/compact/step.js +1 -2
  28. package/dist/agent-runtime/compact/test-reachability.js +0 -1
  29. package/dist/agent-runtime/config.js +0 -1
  30. package/dist/agent-runtime/core-host.d.ts +1 -1
  31. package/dist/agent-runtime/core-host.js +5 -3
  32. package/dist/agent-runtime/durable-store.d.ts +0 -1
  33. package/dist/agent-runtime/durable-store.js +1 -2
  34. package/dist/agent-runtime/efficiency-summary.d.ts +2 -2
  35. package/dist/agent-runtime/efficiency-summary.js +1 -2
  36. package/dist/agent-runtime/efficiency-types.js +0 -1
  37. package/dist/agent-runtime/efficiency.js +0 -1
  38. package/dist/agent-runtime/evaluation-corpus.js +0 -1
  39. package/dist/agent-runtime/evaluation.d.ts +2 -1
  40. package/dist/agent-runtime/evaluation.js +1 -2
  41. package/dist/agent-runtime/executor-types.d.ts +1 -1
  42. package/dist/agent-runtime/executor-types.js +0 -1
  43. package/dist/agent-runtime/executors.js +0 -1
  44. package/dist/agent-runtime/gemini-policy.js +0 -1
  45. package/dist/agent-runtime/graph/artifacts.d.ts +1 -1
  46. package/dist/agent-runtime/graph/artifacts.js +11 -5
  47. package/dist/agent-runtime/graph/nodes.d.ts +1 -1
  48. package/dist/agent-runtime/graph/nodes.js +1 -2
  49. package/dist/agent-runtime/graph/review-policy.js +0 -1
  50. package/dist/agent-runtime/graph/roles.d.ts +2 -5
  51. package/dist/agent-runtime/graph/roles.js +2 -8
  52. package/dist/agent-runtime/graph/state.d.ts +1 -1
  53. package/dist/agent-runtime/graph/state.js +0 -1
  54. package/dist/agent-runtime/graph-checkpointer.d.ts +2 -1
  55. package/dist/agent-runtime/graph-checkpointer.js +0 -1
  56. package/dist/agent-runtime/guardrails.d.ts +3 -3
  57. package/dist/agent-runtime/guardrails.js +1 -2
  58. package/dist/agent-runtime/index.d.ts +2 -1
  59. package/dist/agent-runtime/index.js +2 -2
  60. package/dist/agent-runtime/kimi-acp.js +1 -2
  61. package/dist/agent-runtime/kimi-model.d.ts +6 -0
  62. package/dist/agent-runtime/kimi-model.js +12 -0
  63. package/dist/agent-runtime/openai-executor.d.ts +0 -9
  64. package/dist/agent-runtime/openai-executor.js +6 -7
  65. package/dist/agent-runtime/openspec-tool-server.js +1 -2
  66. package/dist/agent-runtime/openspec.d.ts +0 -2
  67. package/dist/agent-runtime/openspec.js +3 -7
  68. package/dist/agent-runtime/prompts.d.ts +4 -3
  69. package/dist/agent-runtime/prompts.js +0 -1
  70. package/dist/agent-runtime/provider-diagnostic.js +1 -2
  71. package/dist/agent-runtime/recovery.d.ts +46 -0
  72. package/dist/agent-runtime/recovery.js +169 -0
  73. package/dist/agent-runtime/repository-context.d.ts +1 -1
  74. package/dist/agent-runtime/repository-context.js +0 -1
  75. package/dist/agent-runtime/review-context.d.ts +1 -1
  76. package/dist/agent-runtime/review-context.js +0 -1
  77. package/dist/agent-runtime/role-routing.js +0 -1
  78. package/dist/agent-runtime/role-state.js +0 -1
  79. package/dist/agent-runtime/runtime-identity.js +1 -2
  80. package/dist/agent-runtime/tool-event.js +0 -1
  81. package/dist/agent-runtime/verification-plan.d.ts +5 -4
  82. package/dist/agent-runtime/verification-plan.js +1 -2
  83. package/dist/agent-runtime/workflow-types.js +0 -1
  84. package/dist/agent-runtime/workflow.js +0 -1
  85. package/dist/agent-runtime/workspace-tools.d.ts +2 -2
  86. package/dist/agent-runtime/workspace-tools.js +1 -2
  87. package/dist/installer/cli.d.ts +3 -32
  88. package/dist/installer/cli.js +26 -101
  89. package/dist/installer/commands/framework.d.ts +4 -3
  90. package/dist/installer/commands/framework.js +0 -1
  91. package/dist/installer/commands/init.d.ts +4 -25
  92. package/dist/installer/commands/init.js +5 -8
  93. package/dist/installer/phases/framework-lifecycle.d.ts +3 -17
  94. package/dist/installer/phases/framework-lifecycle.js +2 -3
  95. package/dist/installer/phases/install-config.d.ts +7 -8
  96. package/dist/installer/phases/install-config.js +2 -7
  97. package/dist/installer/phases/manifest.d.ts +6 -7
  98. package/dist/installer/phases/manifest.js +2 -7
  99. package/dist/installer/phases/prereqs.d.ts +6 -7
  100. package/dist/installer/phases/prereqs.js +4 -6
  101. package/dist/installer/phases/provider-detect.d.ts +6 -7
  102. package/dist/installer/phases/provider-detect.js +2 -4
  103. package/dist/installer/phases/scaffold.d.ts +9 -10
  104. package/dist/installer/phases/scaffold.js +82 -805
  105. package/dist/installer/util/errors.js +0 -1
  106. package/dist/installer/util/exec.d.ts +3 -2
  107. package/dist/installer/util/exec.js +0 -1
  108. package/dist/installer/util/fs.d.ts +0 -10
  109. package/dist/installer/util/fs.js +1 -2
  110. package/dist/installer/util/git.js +0 -1
  111. package/dist/installer/util/install-transaction.d.ts +2 -2
  112. package/dist/installer/util/install-transaction.js +1 -2
  113. package/dist/installer/util/logger.d.ts +1 -3
  114. package/dist/installer/util/logger.js +0 -1
  115. package/dist/installer/util/paths.js +0 -1
  116. package/dist/installer/util/registry.d.ts +4 -8
  117. package/dist/installer/util/registry.js +2 -3
  118. package/dist/{installer/runtime → pipeline}/pipeline-state.js +0 -3
  119. package/dist/shared/args.d.ts +18 -0
  120. package/dist/shared/args.js +53 -0
  121. package/integration-contract.json +10 -46
  122. package/package.json +3 -10
  123. package/templates/agents/sr-architect.md +15 -310
  124. package/templates/agents/sr-developer.md +15 -269
  125. package/templates/agents/sr-reviewer.md +13 -367
  126. package/templates/codex-skills/rails/sr-architect/SKILL.md +14 -308
  127. package/templates/codex-skills/rails/sr-developer/SKILL.md +14 -201
  128. package/templates/codex-skills/rails/sr-reviewer/SKILL.md +15 -289
  129. package/templates/kimi/specrails/run-skill.mjs +91 -2173
  130. package/bin/tui-installer.mjs +0 -430
  131. package/commands/doctor.md +0 -62
  132. package/dist/agent-runtime/capabilities.js.map +0 -1
  133. package/dist/agent-runtime/cli-executor.js.map +0 -1
  134. package/dist/agent-runtime/cli-process.js.map +0 -1
  135. package/dist/agent-runtime/cli.js.map +0 -1
  136. package/dist/agent-runtime/codex-schema.js.map +0 -1
  137. package/dist/agent-runtime/compact/architect.js.map +0 -1
  138. package/dist/agent-runtime/compact/chat-client.js.map +0 -1
  139. package/dist/agent-runtime/compact/developer.js.map +0 -1
  140. package/dist/agent-runtime/compact/environment.js.map +0 -1
  141. package/dist/agent-runtime/compact/exit-code-honesty.js.map +0 -1
  142. package/dist/agent-runtime/compact/guarded-loop.js.map +0 -1
  143. package/dist/agent-runtime/compact/prompt-inputs.js.map +0 -1
  144. package/dist/agent-runtime/compact/reviewer.js.map +0 -1
  145. package/dist/agent-runtime/compact/step.js.map +0 -1
  146. package/dist/agent-runtime/compact/test-reachability.js.map +0 -1
  147. package/dist/agent-runtime/config.js.map +0 -1
  148. package/dist/agent-runtime/core-host.js.map +0 -1
  149. package/dist/agent-runtime/durable-store.js.map +0 -1
  150. package/dist/agent-runtime/efficiency-summary.js.map +0 -1
  151. package/dist/agent-runtime/efficiency-types.js.map +0 -1
  152. package/dist/agent-runtime/efficiency.js.map +0 -1
  153. package/dist/agent-runtime/evaluation-corpus.js.map +0 -1
  154. package/dist/agent-runtime/evaluation.js.map +0 -1
  155. package/dist/agent-runtime/executor-types.js.map +0 -1
  156. package/dist/agent-runtime/executors.js.map +0 -1
  157. package/dist/agent-runtime/gemini-policy.js.map +0 -1
  158. package/dist/agent-runtime/graph/artifacts.js.map +0 -1
  159. package/dist/agent-runtime/graph/nodes.js.map +0 -1
  160. package/dist/agent-runtime/graph/review-policy.js.map +0 -1
  161. package/dist/agent-runtime/graph/roles.js.map +0 -1
  162. package/dist/agent-runtime/graph/state.js.map +0 -1
  163. package/dist/agent-runtime/graph-checkpointer.js.map +0 -1
  164. package/dist/agent-runtime/guardrails.js.map +0 -1
  165. package/dist/agent-runtime/index.js.map +0 -1
  166. package/dist/agent-runtime/kimi-acp.js.map +0 -1
  167. package/dist/agent-runtime/openai-executor.js.map +0 -1
  168. package/dist/agent-runtime/openspec-tool-server.js.map +0 -1
  169. package/dist/agent-runtime/openspec.js.map +0 -1
  170. package/dist/agent-runtime/prompts.js.map +0 -1
  171. package/dist/agent-runtime/provider-diagnostic.js.map +0 -1
  172. package/dist/agent-runtime/repository-context.js.map +0 -1
  173. package/dist/agent-runtime/review-context.js.map +0 -1
  174. package/dist/agent-runtime/role-routing.js.map +0 -1
  175. package/dist/agent-runtime/role-state.js.map +0 -1
  176. package/dist/agent-runtime/runtime-identity.js.map +0 -1
  177. package/dist/agent-runtime/tool-event.js.map +0 -1
  178. package/dist/agent-runtime/verification-plan.js.map +0 -1
  179. package/dist/agent-runtime/workflow-types.js.map +0 -1
  180. package/dist/agent-runtime/workflow.js.map +0 -1
  181. package/dist/agent-runtime/workspace-tools.js.map +0 -1
  182. package/dist/installer/cli.js.map +0 -1
  183. package/dist/installer/commands/doctor.d.ts +0 -27
  184. package/dist/installer/commands/doctor.js +0 -615
  185. package/dist/installer/commands/doctor.js.map +0 -1
  186. package/dist/installer/commands/framework.js.map +0 -1
  187. package/dist/installer/commands/init.js.map +0 -1
  188. package/dist/installer/commands/update.d.ts +0 -56
  189. package/dist/installer/commands/update.js +0 -257
  190. package/dist/installer/commands/update.js.map +0 -1
  191. package/dist/installer/commands/v5-migration.d.ts +0 -32
  192. package/dist/installer/commands/v5-migration.js +0 -133
  193. package/dist/installer/commands/v5-migration.js.map +0 -1
  194. package/dist/installer/phases/framework-lifecycle.js.map +0 -1
  195. package/dist/installer/phases/install-config.js.map +0 -1
  196. package/dist/installer/phases/manifest.js.map +0 -1
  197. package/dist/installer/phases/prereqs.js.map +0 -1
  198. package/dist/installer/phases/provider-detect.js.map +0 -1
  199. package/dist/installer/phases/scaffold.js.map +0 -1
  200. package/dist/installer/runtime/kimi.d.ts +0 -84
  201. package/dist/installer/runtime/kimi.js +0 -255
  202. package/dist/installer/runtime/kimi.js.map +0 -1
  203. package/dist/installer/runtime/pipeline-state.js.map +0 -1
  204. package/dist/installer/util/errors.js.map +0 -1
  205. package/dist/installer/util/exec.js.map +0 -1
  206. package/dist/installer/util/fs.js.map +0 -1
  207. package/dist/installer/util/git.js.map +0 -1
  208. package/dist/installer/util/install-transaction.js.map +0 -1
  209. package/dist/installer/util/logger.js.map +0 -1
  210. package/dist/installer/util/paths.js.map +0 -1
  211. package/dist/installer/util/prompts.d.ts +0 -23
  212. package/dist/installer/util/prompts.js +0 -49
  213. package/dist/installer/util/prompts.js.map +0 -1
  214. package/dist/installer/util/registry.js.map +0 -1
  215. package/dist/installer/util/template.d.ts +0 -23
  216. package/dist/installer/util/template.js +0 -60
  217. package/dist/installer/util/template.js.map +0 -1
  218. package/docs/README.md +0 -40
  219. package/docs/agent-runtime-efficiency.md +0 -65
  220. package/docs/agent-runtime.md +0 -347
  221. package/docs/agents.md +0 -315
  222. package/docs/changelog.md +0 -168
  223. package/docs/ci-cd.md +0 -60
  224. package/docs/concepts.md +0 -183
  225. package/docs/customization.md +0 -363
  226. package/docs/deployment.md +0 -234
  227. package/docs/getting-started.md +0 -122
  228. package/docs/installation.md +0 -395
  229. package/docs/local-tickets.md +0 -191
  230. package/docs/migration-guide.md +0 -140
  231. package/docs/playbook-oss-maintainer.md +0 -112
  232. package/docs/playbook-parallel-dev.md +0 -124
  233. package/docs/playbook-product-discovery.md +0 -115
  234. package/docs/plugin-architecture.md +0 -144
  235. package/docs/research/codex-compatibility-analysis.md +0 -365
  236. package/docs/research/mcp-feasibility-analysis.md +0 -382
  237. package/docs/testing/test-matrix-codex.md +0 -130
  238. package/docs/updating.md +0 -89
  239. package/docs/user-docs/cli-reference.md +0 -428
  240. package/docs/user-docs/codex-vs-claude-code.md +0 -23
  241. package/docs/user-docs/core-updates.md +0 -70
  242. package/docs/user-docs/faq.md +0 -146
  243. package/docs/user-docs/getting-started-codex.md +0 -194
  244. package/docs/user-docs/getting-started-kimi.md +0 -423
  245. package/docs/user-docs/installation.md +0 -237
  246. package/docs/user-docs/provider-pipelines.md +0 -96
  247. package/docs/user-docs/quick-start.md +0 -161
  248. package/docs/windows.md +0 -78
  249. package/docs/workflows.md +0 -463
  250. package/schemas/profile.v1.json +0 -207
  251. package/templates/claude-md/CLAUDE-quickstart.md +0 -54
  252. package/templates/claude-md/root.md +0 -50
  253. package/templates/codex-skills/batch-implement/SKILL.md +0 -38
  254. package/templates/codex-skills/implement/SKILL.md +0 -38
  255. package/templates/codex-skills/retry/SKILL.md +0 -16
  256. package/templates/commands/specrails/compat-check.md +0 -271
  257. package/templates/commands/specrails/doctor.md +0 -62
  258. package/templates/commands/specrails/explore-spec.md +0 -173
  259. package/templates/commands/specrails/health-check.md +0 -527
  260. package/templates/commands/specrails/memory-inspect.md +0 -261
  261. package/templates/commands/specrails/opsx-diff.md +0 -419
  262. package/templates/commands/specrails/propose-spec.md +0 -102
  263. package/templates/commands/specrails/refactor-recommender.md +0 -169
  264. package/templates/commands/specrails/telemetry.md +0 -552
  265. package/templates/commands/specrails/why.md +0 -96
  266. package/templates/gemini-commands/batch-implement.toml +0 -37
  267. package/templates/gemini-commands/implement.toml +0 -37
  268. package/templates/gemini-commands/retry.toml +0 -15
  269. package/templates/profiles/default.json +0 -14
  270. package/templates/profiles/kimi-default.json +0 -15
  271. package/templates/rules/layer.md +0 -8
  272. package/templates/runtime/provider-pipeline.md +0 -113
  273. package/templates/security/security-exemptions.yaml +0 -20
  274. package/templates/settings/confidence-config.json +0 -17
  275. package/templates/settings/settings.json +0 -15
  276. /package/dist/{installer/runtime → pipeline}/pipeline-state.d.ts +0 -0
@@ -2,7 +2,7 @@ import { guardrailEnabled } from '../guardrails.js';
2
2
  import { addDeveloperChecks, bindPlan, expandedPlanCommands, initializeVerificationPlan, readVerificationPlan, validateProposedChecks } from '../verification-plan.js';
3
3
  import path from 'node:path';
4
4
  import { OpenSpecTools } from '../openspec.js';
5
- import { candidateManifest, fingerprintCandidate, frozenAcceptanceCriteria, recordAcceptance, transitionPipeline, validateAcceptanceReport, verifyPipeline, } from '../../installer/runtime/pipeline-state.js';
5
+ import { candidateManifest, fingerprintCandidate, frozenAcceptanceCriteria, recordAcceptance, transitionPipeline, validateAcceptanceReport, verifyPipeline, } from '../../pipeline/pipeline-state.js';
6
6
  import { ARCHITECT_OUTPUT_SCHEMA, DEVELOPER_OUTPUT_SCHEMA, REVIEW_OUTPUT_SCHEMA, correctionInstructions, deepenInstructions, roleInstructions } from '../prompts.js';
7
7
  import { archive, child, journal, object, parseArchitecture, proposedVerification, write, writeDesignConfidence } from './artifacts.js';
8
8
  import { evaluateReview } from './review-policy.js';
@@ -425,4 +425,3 @@ function archiveNode(deps) {
425
425
  export function coreNodes(deps) {
426
426
  return { architect: architectNode(deps), developer: developerNode(deps), fixer: fixerNode(deps), verify: verifyNode(deps), reviewer: reviewerNode(deps), archive: archiveNode(deps) };
427
427
  }
428
- //# sourceMappingURL=nodes.js.map
@@ -29,4 +29,3 @@ export function evaluateReview(raw, policy) {
29
29
  && REVIEW_ASPECTS.every(name => scored[name] >= policy.aspects[name]);
30
30
  return { record: { approved: raw.approved, summary: raw.summary, issues: raw.issues, score: raw.score, aspects: scored }, approved };
31
31
  }
32
- //# sourceMappingURL=review-policy.js.map
@@ -1,10 +1,8 @@
1
1
  import { type InvocationKind } from '../role-routing.js';
2
- import { type PipelineContext } from '../../installer/runtime/pipeline-state.js';
2
+ import { type PipelineContext } from '../../pipeline/pipeline-state.js';
3
3
  import type { ExecutorRegistry } from '../executors.js';
4
- import { type AgentEvent, type AgentEventRole, type AgentResult, type AgentRole, type AgentUsage, type RuntimeConfig, type RuntimeAgentConfig } from '../executor-types.js';
4
+ import { type AgentEvent, type AgentEventRole, type AgentResult, type AgentRole, type RuntimeConfig, type RuntimeAgentConfig } from '../executor-types.js';
5
5
  import type { WorkflowStepContext } from '../workflow-types.js';
6
- /** Executor failures that mean "this session cannot be continued", not "the role failed". */
7
- export declare const SESSION_FALLBACK_CODES: Set<string>;
8
6
  export interface InvokeOptions {
9
7
  kind?: InvocationKind;
10
8
  prompt: string;
@@ -41,7 +39,6 @@ export interface RoleInvokerDeps {
41
39
  /** `fixer` labels the developer step's events during a correction round on the fixer stance, so a log reader sees who is acting. */
42
40
  onAgentEvent?: (role: AgentEventRole, event: AgentEvent) => void;
43
41
  }
44
- export declare function sumUsage(a: AgentUsage, b: AgentUsage): AgentUsage;
45
42
  /**
46
43
  * One role turn against the configured executor: budget-aware request, live
47
44
  * event forwarding with repository-relative paths, structured parsing with a
@@ -5,18 +5,13 @@ import { selectRoleRoute } from '../role-routing.js';
5
5
  import { ROLE_SKILLS, OPENSPEC_VERSION, OpenSpecTools, OpenSpecParticipationError, openSpecRepairPrompt } from '../openspec.js';
6
6
  import path from 'node:path';
7
7
  import { performance } from 'node:perf_hooks';
8
- import { frozenAcceptanceCriteria, pipelineStateDirectory } from '../../installer/runtime/pipeline-state.js';
8
+ import { frozenAcceptanceCriteria, pipelineStateDirectory } from '../../pipeline/pipeline-state.js';
9
9
  import { AgentExecutionError, unknownUsage } from '../executor-types.js';
10
- import { sumCacheUsage } from '../efficiency-types.js';
11
10
  import { ROLE_INSTRUCTIONS_VERSION, repairInstructions } from '../prompts.js';
12
11
  import { parseAgentObject } from './artifacts.js';
13
12
  /** Executor failures that mean "this session cannot be continued", not "the role failed". */
14
- export const SESSION_FALLBACK_CODES = new Set(['session_not_found', 'session_expired', 'session_unsupported']);
13
+ const SESSION_FALLBACK_CODES = new Set(['session_not_found', 'session_expired', 'session_unsupported']);
15
14
  const REPAIRABLE = /Invalid|Expected|requires|Duplicate|malformed/i;
16
- export function sumUsage(a, b) {
17
- const add = (x, y) => x === null || y === null ? null : x + y;
18
- return { inputTokens: add(a.inputTokens, b.inputTokens), outputTokens: add(a.outputTokens, b.outputTokens), costUsd: add(a.costUsd, b.costUsd), ...sumCacheUsage([a, b]) };
19
- }
20
15
  /**
21
16
  * One role turn against the configured executor: budget-aware request, live
22
17
  * event forwarding with repository-relative paths, structured parsing with a
@@ -195,4 +190,3 @@ export function createRoleInvoker(deps) {
195
190
  }
196
191
  };
197
192
  }
198
- //# sourceMappingURL=roles.js.map
@@ -1,4 +1,4 @@
1
- import type { VerificationCommand } from '../../installer/runtime/pipeline-state.js';
1
+ import type { VerificationCommand } from '../../pipeline/pipeline-state.js';
2
2
  export type DesignConfidence = 'high' | 'medium' | 'low';
3
3
  export interface ArchitectureRecord {
4
4
  planningDepth?: 'focused' | 'full';
@@ -21,4 +21,3 @@ export const CoreState = Annotation.Root({
21
21
  });
22
22
  /** Graph order. `fixer` is the correction node: verify (failed, tasks ticked) and reviewer (rejected) route there; it hands back to verify. */
23
23
  export const CORE_NODE_ORDER = ['architect', 'developer', 'fixer', 'verify', 'reviewer', 'archive'];
24
- //# sourceMappingURL=state.js.map
@@ -1,7 +1,7 @@
1
1
  import { BaseCheckpointSaver, type ChannelVersions, type Checkpoint, type CheckpointListOptions, type CheckpointMetadata, type CheckpointTuple, type PendingWrite } from '@langchain/langgraph-checkpoint';
2
2
  import type { RunnableConfig } from '@langchain/core/runnables';
3
3
  /** One serialized LangGraph value: the serializer's type tag plus base64 bytes. */
4
- export interface SerializedBlob {
4
+ interface SerializedBlob {
5
5
  type: string;
6
6
  data: string;
7
7
  }
@@ -59,3 +59,4 @@ export declare class FileCheckpointSaver extends BaseCheckpointSaver {
59
59
  putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void>;
60
60
  deleteThread(threadId: string): Promise<void>;
61
61
  }
62
+ export {};
@@ -134,4 +134,3 @@ export class FileCheckpointSaver extends BaseCheckpointSaver {
134
134
  await this.persist();
135
135
  }
136
136
  }
137
- //# sourceMappingURL=graph-checkpointer.js.map
@@ -1,15 +1,15 @@
1
1
  export declare const GUARDRAIL_IDS: readonly ["plan-validation", "genuine-blocking-question", "plan-language-hint", "frozen-plan-writes", "primary-language", "duplicate-sibling", "one-test-per-module", "empty-write", "evidence-gated-ticking", "inventory-retry", "synthetic-corrections", "silent-group-closure", "verify-per-group", "test-reachability", "exit-code-honesty", "environment-repair", "lockfile-repair", "verify-idle-timeout"];
2
2
  export type GuardrailId = (typeof GUARDRAIL_IDS)[number];
3
- export type GuardrailPhase = 'architect' | 'developer' | 'host';
4
- export interface GuardrailDescriptor {
3
+ type GuardrailPhase = 'architect' | 'developer' | 'host';
4
+ interface GuardrailDescriptor {
5
5
  id: GuardrailId;
6
6
  phase: GuardrailPhase;
7
7
  }
8
8
  export type GuardrailSettings = Partial<Record<GuardrailId, boolean>>;
9
9
  /** Stable catalog (phase order = pipeline order); labels/descriptions live in the host UI so they can be localized. */
10
10
  export declare const GUARDRAIL_CATALOG: readonly GuardrailDescriptor[];
11
- export declare function isGuardrailId(value: unknown): value is GuardrailId;
12
11
  /** A guardrail is on unless the settings say `false` explicitly. */
13
12
  export declare function guardrailEnabled(settings: GuardrailSettings | undefined, id: GuardrailId): boolean;
14
13
  /** Validates a raw `guardrails` object: only known ids, only booleans. Returns the normalized settings (unset ⇒ omitted). */
15
14
  export declare function validateGuardrailSettings(value: unknown, path?: string): GuardrailSettings;
15
+ export {};
@@ -52,7 +52,7 @@ export const GUARDRAIL_CATALOG = [
52
52
  { id: 'lockfile-repair', phase: 'host' },
53
53
  { id: 'verify-idle-timeout', phase: 'host' },
54
54
  ];
55
- export function isGuardrailId(value) {
55
+ function isGuardrailId(value) {
56
56
  return typeof value === 'string' && GUARDRAIL_IDS.includes(value);
57
57
  }
58
58
  /** A guardrail is on unless the settings say `false` explicitly. */
@@ -73,4 +73,3 @@ export function validateGuardrailSettings(value, path = 'guardrails') {
73
73
  }
74
74
  return out;
75
75
  }
76
- //# sourceMappingURL=guardrails.js.map
@@ -17,4 +17,5 @@ export { FileCheckpointSaver, type GraphStoreIO, type SerializedGraphStore } fro
17
17
  export { ARCHITECT_OUTPUT_SCHEMA, DEVELOPER_OUTPUT_SCHEMA, REVIEW_OUTPUT_SCHEMA, ROLE_INSTRUCTIONS_VERSION, rolePromptDefaults, correctionInstructions, deepenInstructions, repairInstructions, roleInstructions, type FrozenCriterion, type RoleFeedback, type RoleInstructionOptions, } from './prompts.js';
18
18
  export { OPENSPEC_VERSION, ROLE_SKILLS, type OpenSpecRoleContext } from './openspec.js';
19
19
  export * from './efficiency-summary.js';
20
- export { readVerificationEvidence, type VerificationEvidenceQuery } from '../installer/runtime/pipeline-state.js';
20
+ export { readVerificationEvidence, type VerificationEvidenceQuery } from '../pipeline/pipeline-state.js';
21
+ export { runRecovery, recoveryRequestSchema, type RecoveryRequest } from './recovery.js';
@@ -17,5 +17,5 @@ export { FileCheckpointSaver } from './graph-checkpointer.js';
17
17
  export { ARCHITECT_OUTPUT_SCHEMA, DEVELOPER_OUTPUT_SCHEMA, REVIEW_OUTPUT_SCHEMA, ROLE_INSTRUCTIONS_VERSION, rolePromptDefaults, correctionInstructions, deepenInstructions, repairInstructions, roleInstructions, } from './prompts.js';
18
18
  export { OPENSPEC_VERSION, ROLE_SKILLS } from './openspec.js';
19
19
  export * from './efficiency-summary.js';
20
- export { readVerificationEvidence } from '../installer/runtime/pipeline-state.js';
21
- //# sourceMappingURL=index.js.map
20
+ export { readVerificationEvidence } from '../pipeline/pipeline-state.js';
21
+ export { runRecovery, recoveryRequestSchema } from './recovery.js';
@@ -1,5 +1,5 @@
1
1
  import { toolEvent } from './tool-event.js';
2
- import { normalizeKimiCliModel } from '../installer/runtime/kimi.js';
2
+ import { normalizeKimiCliModel } from './kimi-model.js';
3
3
  import { AgentExecutionError, unknownUsage, validateAgentRequest } from './executor-types.js';
4
4
  import { runCliProcess } from './cli-process.js';
5
5
  import { parseStructuredText } from './openai-executor.js';
@@ -187,4 +187,3 @@ export async function executeKimiReadonlyAcp(request, options = {}) {
187
187
  request.onEvent?.({ kind: 'usage', usage });
188
188
  return { text, usage, sessionId, structured: parseStructuredText(text) };
189
189
  }
190
- //# sourceMappingURL=kimi-acp.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Configurations keep raw provider ids. At the CLI boundary only the managed
3
+ * Kimi aliases gain their documented `kimi-code/` namespace; custom and
4
+ * already-qualified ids stay byte-identical.
5
+ */
6
+ export declare function normalizeKimiCliModel(model: string): string;
@@ -0,0 +1,12 @@
1
+ const OFFICIAL_SHORT_MODEL_IDS = new Set(['k3', 'kimi-for-coding', 'kimi-for-coding-highspeed']);
2
+ const SAFE_MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._/:-]{0,127}$/;
3
+ /**
4
+ * Configurations keep raw provider ids. At the CLI boundary only the managed
5
+ * Kimi aliases gain their documented `kimi-code/` namespace; custom and
6
+ * already-qualified ids stay byte-identical.
7
+ */
8
+ export function normalizeKimiCliModel(model) {
9
+ if (!SAFE_MODEL_ID.test(model))
10
+ throw new Error('Kimi model id must be 1-128 characters and match [A-Za-z0-9][A-Za-z0-9._/:-]*');
11
+ return OFFICIAL_SHORT_MODEL_IDS.has(model) ? `kimi-code/${model}` : model;
12
+ }
@@ -9,15 +9,6 @@ export interface OpenAICompatibleOptions {
9
9
  idleTimeoutMs?: number;
10
10
  }
11
11
  export declare function parseStructuredText(text: string): Record<string, unknown> | undefined;
12
- /** The agent loop an openai-compatible provider runs: compact host-driven pipelines by default. */
13
- /** The OpenAI `reasoning_effort` tiers a compatible endpoint accepts. */
14
- export declare const OPENAI_EFFORTS: readonly ["low", "medium", "high"];
15
- export declare function resolveAgentLoop(provider: ApiProvider): 'compact' | 'free';
16
- /** Compact runs: abort when NOTHING happens for this long (no tool call, reply or usage) — the real hang detector now that the wall clock is per task group. A non-streaming 16k reply at 20 tok/s is ~13 min, hence the margin. */
17
- export declare const IDLE_TIMEOUT_MS: number;
18
- export declare function resolveContextWindow(provider: ApiProvider): number;
19
- /** The per-turn output budget the connection declares; undefined keeps the loop's default. */
20
- export declare function resolveOutputBudget(provider: ApiProvider): number | undefined;
21
12
  /** No SDK, gateway, tracing backend, paid probe, or mandatory key. */
22
13
  export declare class OpenAICompatibleExecutor implements AgentExecutor {
23
14
  private readonly provider;
@@ -1,4 +1,4 @@
1
- import { readVerificationEvidence } from '../installer/runtime/pipeline-state.js';
1
+ import { readVerificationEvidence } from '../pipeline/pipeline-state.js';
2
2
  import { assertEffortSupported, unknownCapabilities } from './capabilities.js';
3
3
  import { OpenSpecTools, OPENSPEC_TOOL_DEFINITION, openSpecPrompt } from './openspec.js';
4
4
  import { AgentExecutionError, unknownUsage, validateAgentRequest } from './executor-types.js';
@@ -19,13 +19,13 @@ export function parseStructuredText(text) {
19
19
  }
20
20
  /** The agent loop an openai-compatible provider runs: compact host-driven pipelines by default. */
21
21
  /** The OpenAI `reasoning_effort` tiers a compatible endpoint accepts. */
22
- export const OPENAI_EFFORTS = ['low', 'medium', 'high'];
23
- export function resolveAgentLoop(provider) { return provider.agentLoop ?? 'compact'; }
22
+ const OPENAI_EFFORTS = ['low', 'medium', 'high'];
23
+ function resolveAgentLoop(provider) { return provider.agentLoop ?? 'compact'; }
24
24
  /** Compact runs: abort when NOTHING happens for this long (no tool call, reply or usage) — the real hang detector now that the wall clock is per task group. A non-streaming 16k reply at 20 tok/s is ~13 min, hence the margin. */
25
- export const IDLE_TIMEOUT_MS = 20 * 60_000;
26
- export function resolveContextWindow(provider) { return provider.contextWindowTokens ?? DEFAULT_CONTEXT_WINDOW_TOKENS; }
25
+ const IDLE_TIMEOUT_MS = 20 * 60_000;
26
+ function resolveContextWindow(provider) { return provider.contextWindowTokens ?? DEFAULT_CONTEXT_WINDOW_TOKENS; }
27
27
  /** The per-turn output budget the connection declares; undefined keeps the loop's default. */
28
- export function resolveOutputBudget(provider) { return provider.maxOutputTokens; }
28
+ function resolveOutputBudget(provider) { return provider.maxOutputTokens; }
29
29
  /** No SDK, gateway, tracing backend, paid probe, or mandatory key. */
30
30
  export class OpenAICompatibleExecutor {
31
31
  provider;
@@ -134,4 +134,3 @@ export class OpenAICompatibleExecutor {
134
134
  }
135
135
  }
136
136
  }
137
- //# sourceMappingURL=openai-executor.js.map
@@ -1,4 +1,4 @@
1
- import { readVerificationEvidence } from '../installer/runtime/pipeline-state.js';
1
+ import { readVerificationEvidence } from '../pipeline/pipeline-state.js';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -34,4 +34,3 @@ if (context.evidenceScope && context.role !== 'architect')
34
34
  }
35
35
  });
36
36
  await server.connect(new StdioServerTransport());
37
- //# sourceMappingURL=openspec-tool-server.js.map
@@ -62,7 +62,6 @@ export declare const IMPLEMENTATION_PROGRESS_SCHEMA: z.ZodObject<{
62
62
  }, z.core.$strict>>;
63
63
  blockers: z.ZodArray<z.ZodString>;
64
64
  }, z.core.$strict>;
65
- export declare function renderProgressHandoff(context: OpenSpecRoleContext): string;
66
65
  export declare function hash(text: string): string;
67
66
  export declare function resolveOpenSpecCli(): string;
68
67
  export declare function runOpenSpec(cli: string, root: string, args: string[], signal?: AbortSignal): Promise<string>;
@@ -98,7 +97,6 @@ export declare class OpenSpecTools {
98
97
  assertParticipation(after?: number): void;
99
98
  assertReady(): Promise<OpenSpecApply>;
100
99
  }
101
- export declare const OPENSPEC_BRIDGE_ENTRY: string;
102
100
  export declare const OPENSPEC_TOOL_ACTIONS: readonly ["load_skill", "new", "status", "instructions", "validate", "write_artifact", "read_progress", "write_progress"];
103
101
  export declare const OPENSPEC_TOOL_DEFINITION: {
104
102
  type: string;
@@ -36,10 +36,6 @@ function readProgress(context) {
36
36
  return { notice: PROGRESS_NOTICE + ' Saved progress is unavailable or invalid; inspect the current diff and tasks before continuing.', record: null };
37
37
  }
38
38
  }
39
- export function renderProgressHandoff(context) {
40
- const saved = readProgress(context);
41
- return saved.record ? `\n## Saved implementation progress\n${saved.notice}\n${JSON.stringify(saved.record)}\n` : saved.notice.includes('unavailable') ? '\n' + saved.notice + '\n' : '';
42
- }
43
39
  function writeProgress(context, input) {
44
40
  if (context.role !== 'developer')
45
41
  throw new Error('Only the developer may write implementation progress');
@@ -78,7 +74,8 @@ export async function runOpenSpec(cli, root, args, signal) {
78
74
  }
79
75
  catch (error) {
80
76
  const result = error;
81
- throw new Error(`OpenSpec ${args[0]} failed (${result.status ?? 'process error'}): ${String(result.stderr || result.stdout || '').slice(-6000)}`);
77
+ const detail = [result.stdout, result.stderr].filter(Boolean).join('\n').slice(-6000);
78
+ throw new Error(`OpenSpec ${args[0]} failed (${result.status ?? result.code ?? 'process error'}): ${detail}`);
82
79
  }
83
80
  }
84
81
  /** Reject symlink traversal even when the final destination does not exist. */
@@ -300,7 +297,7 @@ export class OpenSpecTools {
300
297
  return apply;
301
298
  }
302
299
  }
303
- export const OPENSPEC_BRIDGE_ENTRY = fileURLToPath(new URL('./openspec-tool-server.js', import.meta.url));
300
+ const OPENSPEC_BRIDGE_ENTRY = fileURLToPath(new URL('./openspec-tool-server.js', import.meta.url));
304
301
  export const OPENSPEC_TOOL_ACTIONS = ['load_skill', 'new', 'status', 'instructions', 'validate', 'write_artifact', 'read_progress', 'write_progress'];
305
302
  export const OPENSPEC_TOOL_DEFINITION = { type: 'function', function: { name: 'openspec_workflow', description: 'Run the official OpenSpec role workflow. Load the skill first (developer/reviewer also receive real status, apply context and saved progress), then use its CLI instructions and write artifacts within the fixed change. Developer may save a bounded advisory handoff with write_progress; read_progress refreshes it. Progress never substitutes for verification.', parameters: { type: 'object', additionalProperties: false, required: ['action'], properties: { action: { type: 'string', enum: OPENSPEC_TOOL_ACTIONS }, artifact: { type: 'string' }, path: { type: 'string' }, content: { type: 'string' }, progress: {
306
303
  type: 'object', additionalProperties: false, required: ['summary', 'completedTasks', 'nextTasks', 'checks', 'blockers'], properties: {
@@ -326,4 +323,3 @@ export function openSpecRepairPrompt(context) {
326
323
  return `The previous ${context.role} result cannot be accepted because you omitted the required official OpenSpec workflow. Do not merely resend the JSON. Continue this same role with the work already available. Load ${ROLE_SKILLS[context.role]} using the scoped workflow tool (action=load_skill), consult status and instructions ${context.role === 'architect' ? 'tasks' : 'apply'}, and execute the complete returned skill procedure against the current artifacts and code. Reconcile your previous conclusions with that procedure; correct your report if necessary. Do not rerun the implementation or the host verification commands. ${context.role === 'reviewer' ? 'Stay read-only; do not modify code or artifacts.' : 'Keep already-correct work and respect the same frozen scope.'} Finish with the originally requested JSON report.
327
324
  `;
328
325
  }
329
- //# sourceMappingURL=openspec.js.map
@@ -1,5 +1,5 @@
1
1
  import type { AgentRole } from './executor-types.js';
2
- import type { PipelineContext, VerificationCommand } from '../installer/runtime/pipeline-state.js';
2
+ import type { PipelineContext, VerificationCommand } from '../pipeline/pipeline-state.js';
3
3
  import { type ReviewPolicy } from './graph/review-policy.js';
4
4
  import type { DeveloperRecord } from './graph/state.js';
5
5
  /** Bump whenever the wording changes: the version is part of the frozen run identity. */
@@ -15,7 +15,7 @@ export interface FrozenCriterion {
15
15
  requirement: string;
16
16
  }
17
17
  /** Roles with an editable definition: the three pipeline agents plus the FIXER stance the developer role takes on a correction round. */
18
- export type PromptRole = AgentRole | 'fixer';
18
+ type PromptRole = AgentRole | 'fixer';
19
19
  export interface RoleInstructionOptions {
20
20
  definition?: string;
21
21
  /** `fixer`: the developer invocation is a correction round on the fixer stance (own definition, no plan dump). */
@@ -39,7 +39,7 @@ export declare const DEVELOPER_OUTPUT_SCHEMA: Record<string, unknown>;
39
39
  export declare const REVIEW_OUTPUT_SCHEMA: Record<string, unknown>;
40
40
  /** Actual editable task definitions; dynamic scope and output contracts are assembled separately. */
41
41
  export declare function rolePromptDefaults(): Record<PromptRole, string>;
42
- export interface ReReviewContext {
42
+ interface ReReviewContext {
43
43
  changes: Array<{
44
44
  repositoryId: string;
45
45
  path: string;
@@ -61,3 +61,4 @@ export declare function correctionInstructions(role: AgentRole, feedback: RoleFe
61
61
  export declare function deepenInstructions(question: string | undefined): string;
62
62
  /** Asks a structured role to resend a malformed reply without repeating its work. */
63
63
  export declare function repairInstructions(role: AgentRole, problem: string): string;
64
+ export {};
@@ -357,4 +357,3 @@ export function deepenInstructions(question) {
357
357
  export function repairInstructions(role, problem) {
358
358
  return `Your previous reply could not be used: ${problem}\n\nDo not redo the ${role} work. Reply again with exactly one JSON object matching the output contract, with no prose before or after it and no Markdown fence.\n`;
359
359
  }
360
- //# sourceMappingURL=prompts.js.map
@@ -1,4 +1,4 @@
1
- import { redactRuntimeText } from '../installer/runtime/pipeline-state.js';
1
+ import { redactRuntimeText } from '../pipeline/pipeline-state.js';
2
2
  import { stripVTControlCharacters } from 'node:util';
3
3
  /** Keep provider errors visible without dumping full output, prompts or credentials. */
4
4
  export function providerDiagnostic(stdout, stderr, env = process.env) {
@@ -22,4 +22,3 @@ export function providerDiagnostic(stdout, stderr, env = process.env) {
22
22
  message = stripVTControlCharacters(message);
23
23
  return redactRuntimeText(message, env).replace(/\s+/g, ' ').slice(0, 1200).trim();
24
24
  }
25
- //# sourceMappingURL=provider-diagnostic.js.map
@@ -0,0 +1,46 @@
1
+ import { z } from 'zod';
2
+ export declare const recoveryRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3
+ action: z.ZodLiteral<"inspect">;
4
+ }, z.core.$strict>, z.ZodObject<{
5
+ action: z.ZodLiteral<"history">;
6
+ offset: z.ZodOptional<z.ZodNumber>;
7
+ }, z.core.$strict>, z.ZodObject<{
8
+ repositoryId: z.ZodString;
9
+ path: z.ZodString;
10
+ action: z.ZodLiteral<"list_files">;
11
+ }, z.core.$strict>, z.ZodObject<{
12
+ startLine: z.ZodOptional<z.ZodNumber>;
13
+ endLine: z.ZodOptional<z.ZodNumber>;
14
+ repositoryId: z.ZodString;
15
+ path: z.ZodString;
16
+ action: z.ZodLiteral<"read_file">;
17
+ }, z.core.$strict>, z.ZodObject<{
18
+ repositoryId: z.ZodString;
19
+ path: z.ZodString;
20
+ action: z.ZodLiteral<"diff">;
21
+ }, z.core.$strict>, z.ZodObject<{
22
+ expectedHash: z.ZodString;
23
+ oldText: z.ZodString;
24
+ newText: z.ZodString;
25
+ operationId: z.ZodString;
26
+ reason: z.ZodString;
27
+ acknowledgeInterrupted: z.ZodOptional<z.ZodBoolean>;
28
+ changedPrecondition: z.ZodOptional<z.ZodString>;
29
+ repositoryId: z.ZodString;
30
+ path: z.ZodString;
31
+ action: z.ZodLiteral<"patch">;
32
+ }, z.core.$strict>, z.ZodObject<{
33
+ kind: z.ZodEnum<{
34
+ openspec: "openspec";
35
+ verification: "verification";
36
+ }>;
37
+ checkId: z.ZodOptional<z.ZodString>;
38
+ operationId: z.ZodString;
39
+ reason: z.ZodString;
40
+ acknowledgeInterrupted: z.ZodOptional<z.ZodBoolean>;
41
+ changedPrecondition: z.ZodOptional<z.ZodString>;
42
+ action: z.ZodLiteral<"check">;
43
+ }, z.core.$strict>], "action">;
44
+ export type RecoveryRequest = z.infer<typeof recoveryRequestSchema>;
45
+ /** Uses the SAME cross-process lease as resume. No provider calls or checkpoint editing. */
46
+ export declare function runRecovery(contextInput: unknown, input: unknown, signal?: AbortSignal): Promise<unknown>;
@@ -0,0 +1,169 @@
1
+ import { z } from 'zod';
2
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { acquireWorkflowLease, fingerprint, readWorkflowState } from './durable-store.js';
5
+ import { WorkspaceTools } from './workspace-tools.js';
6
+ import { artifactPath, hash, resolveOpenSpecCli, runOpenSpec } from './openspec.js';
7
+ import { write } from './graph/artifacts.js';
8
+ import { expandedPlanCommands, readVerificationPlan } from './verification-plan.js';
9
+ import { inspectPipeline, pipelineStateDirectory, validatePipelineContext, verifyPipeline } from '../pipeline/pipeline-state.js';
10
+ const file = { repositoryId: z.string().min(1).max(128), path: z.string().min(1).max(1024) };
11
+ const operation = { operationId: z.string().uuid(), reason: z.string().trim().min(1).max(2000), acknowledgeInterrupted: z.boolean().optional(), changedPrecondition: z.string().trim().min(1).max(2000).optional() };
12
+ export const recoveryRequestSchema = z.discriminatedUnion('action', [
13
+ z.object({ action: z.literal('inspect') }).strict(),
14
+ z.object({ action: z.literal('history'), offset: z.number().int().nonnegative().optional() }).strict(),
15
+ z.object({ action: z.literal('list_files'), ...file }).strict(),
16
+ z.object({ action: z.literal('read_file'), ...file, startLine: z.number().int().positive().optional(), endLine: z.number().int().positive().optional() }).strict(),
17
+ z.object({ action: z.literal('diff'), ...file }).strict(),
18
+ z.object({ action: z.literal('patch'), ...file, ...operation, expectedHash: z.string().regex(/^[a-f0-9]{64}$/), oldText: z.string().min(1).max(16_384), newText: z.string().max(16_384) }).strict(),
19
+ z.object({ action: z.literal('check'), ...operation, kind: z.enum(['openspec', 'verification']), checkId: z.string().min(1).max(256).optional() }).strict(),
20
+ ]);
21
+ /** Recovery never accepts absolute paths or aliases for control/secret files. */
22
+ function safePath(raw, mutation) {
23
+ const parts = raw.split('/');
24
+ if (raw !== '.' && (path.isAbsolute(raw) || raw.includes('\\') || raw.includes(':') || parts.some(p => !p || p === '.' || p === '..' || /[\x00-\x1f]/.test(p) || /[. ]$/.test(p) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(p))))
25
+ throw new Error('Recovery needs a repository-relative path without traversal or platform aliases');
26
+ const lower = parts.map(p => p.toLowerCase());
27
+ if (lower.some(p => ['.git', '.specrails', '.claude', '.codex', '.gemini', '.kimi-code', '.agents', '.ssh', '.aws', 'node_modules'].includes(p) || /^\.env(?:\.|$)/.test(p)))
28
+ throw new Error('Recovery cannot access runtime metadata, dependencies or secret files');
29
+ if (mutation && (lower[0] === 'openspec' && lower[1] !== 'specs' || lower.some(p => ['agents.md', 'claude.md', 'gemini.md'].includes(p))))
30
+ throw new Error('Recovery cannot change frozen plans, archives or agent instructions');
31
+ return raw;
32
+ }
33
+ /** Uses the SAME cross-process lease as resume. No provider calls or checkpoint editing. */
34
+ export async function runRecovery(contextInput, input, signal) {
35
+ const context = validatePipelineContext(contextInput), request = recoveryRequestSchema.parse(input);
36
+ const directory = pipelineStateDirectory(context), workflowDirectory = path.join(directory, 'agent-workflow');
37
+ if (!await readWorkflowState(workflowDirectory, context.runId))
38
+ throw new Error('Recovery requires an existing saved run');
39
+ const release = await acquireWorkflowLease(workflowDirectory, context.runId);
40
+ try {
41
+ const state = (await readWorkflowState(workflowDirectory, context.runId));
42
+ const inspection = inspectPipeline(context); // verifies the frozen scope against the journal
43
+ const historyPath = artifactPath(directory, 'recovery-history.json');
44
+ const history = existsSync(historyPath) ? JSON.parse(readFileSync(historyPath, 'utf8')) : [];
45
+ if (!Array.isArray(history) || history.length > 100)
46
+ throw new Error('Invalid recovery history');
47
+ const plan = readVerificationPlan(context);
48
+ if (request.action === 'history') {
49
+ const offset = request.offset ?? 0, ordered = [...history].reverse();
50
+ return { attempts: ordered.slice(offset, offset + 20), total: history.length, ...(offset + 20 < history.length ? { nextOffset: offset + 20 } : {}) };
51
+ }
52
+ if (request.action === 'inspect')
53
+ return {
54
+ runId: context.runId, status: state.status, nextStep: state.nextStep, repositories: context.repositories,
55
+ verification: { valid: inspection.verification.valid, reasons: inspection.verification.reasons },
56
+ checks: plan?.entries.map(entry => ({ id: entry.id, label: entry.label, repositoryId: entry.command.repositoryId, command: entry.command.command, args: entry.command.args, cwd: entry.command.cwd })) ?? [],
57
+ attempts: history.slice(-10),
58
+ };
59
+ let workspace;
60
+ if ('repositoryId' in request) {
61
+ const repository = context.repositories.find(repo => repo.id === request.repositoryId);
62
+ if (!repository)
63
+ throw new Error('Repository does not belong to this run');
64
+ safePath(request.path, request.action === 'patch');
65
+ const target = path.join(repository.path, request.path);
66
+ if (existsSync(target))
67
+ safePath(path.relative(repository.path, realpathSync(target)).split(path.sep).join('/') || '.', request.action === 'patch');
68
+ workspace = new WorkspaceTools(repository.path, [repository.path], 'developer');
69
+ }
70
+ if (request.action === 'read_file')
71
+ return JSON.parse(workspace.execute('read_lines', { path: request.path, ...(request.startLine ? { startLine: request.startLine } : {}), ...(request.endLine ? { endLine: request.endLine } : {}) }));
72
+ if (request.action === 'diff')
73
+ return JSON.parse(workspace.execute('get_diff', { path: request.path }));
74
+ if (request.action === 'list_files') {
75
+ const result = JSON.parse(workspace.execute('list_files', { path: request.path }));
76
+ result.entries = result.entries.filter(entry => { try {
77
+ safePath(request.path === '.' ? entry.name : request.path + '/' + entry.name, false);
78
+ return true;
79
+ }
80
+ catch {
81
+ return false;
82
+ } });
83
+ return result;
84
+ }
85
+ if (state.status === 'succeeded' || inspection.phases.archive.status === 'done')
86
+ throw new Error('Completed or archived runs cannot be repaired; inspect their delivery instead');
87
+ if ((state.status === 'running' || Object.values(state.steps).some(step => ['running', 'interrupted'].includes(step.status))) && !request.acknowledgeInterrupted)
88
+ throw new Error('Inspect interrupted writes and explicitly acknowledge them before repairing');
89
+ if (request.action === 'check' && (request.kind === 'verification' ? !request.checkId : request.checkId !== undefined))
90
+ throw new Error('Verification requires a saved checkId; OpenSpec validation does not accept one');
91
+ const save = () => write(historyPath, JSON.stringify(history, null, 2) + '\n');
92
+ const requestHash = fingerprint(request);
93
+ const previous = history.find(attempt => attempt.operationId === request.operationId);
94
+ if (previous) {
95
+ if (previous.requestHash !== requestHash)
96
+ throw new Error('operationId was already used for a different request');
97
+ if (previous.status === 'pending') {
98
+ // Crash after atomic file publication but before recording completion.
99
+ if (request.action === 'patch') {
100
+ const current = JSON.parse(workspace.execute('read_lines', { path: request.path, endLine: 1 }));
101
+ previous.status = current.hash === previous.afterHash ? 'applied' : 'interrupted';
102
+ }
103
+ else
104
+ previous.status = 'interrupted';
105
+ previous.completedAt = new Date().toISOString();
106
+ save();
107
+ }
108
+ return { ...previous, replayed: true, notice: 'Recorded outcome; inspect current files/evidence before continuing.' };
109
+ }
110
+ if (history.length >= 100)
111
+ throw new Error('Recovery attempt limit reached; inspect the history before continuing manually');
112
+ const checkId = request.action === 'check' ? request.checkId ?? 'openspec' : undefined;
113
+ const lastCheck = history.filter(attempt => attempt.action === 'check' && attempt.checkId === checkId && attempt.candidateHash === inspection.candidateHash).at(-1);
114
+ if (request.action === 'check' && lastCheck && ['failed', 'interrupted', 'pending'].includes(lastCheck.status) && !request.changedPrecondition)
115
+ throw new Error('This check already failed or was interrupted on this candidate; state the changed precondition before retrying');
116
+ const attempt = { operationId: request.operationId, requestHash, action: request.action, reason: request.reason,
117
+ startedAt: new Date().toISOString(), status: 'pending', candidateHash: inspection.candidateHash,
118
+ ...(checkId ? { checkId } : {}), ...(request.changedPrecondition ? { changedPrecondition: request.changedPrecondition } : {}),
119
+ };
120
+ if (request.action === 'patch') {
121
+ const before = workspace.execute('read_file', { path: request.path });
122
+ if (hash(before) !== request.expectedHash)
123
+ throw new Error('File changed since inspection; read it again before patching');
124
+ const at = before.indexOf(request.oldText);
125
+ if (at < 0 || before.indexOf(request.oldText, at + 1) >= 0 || request.oldText === request.newText)
126
+ throw new Error('Patch requires exactly one matching fragment and an actual change');
127
+ const after = before.slice(0, at) + request.newText + before.slice(at + request.oldText.length);
128
+ Object.assign(attempt, { repositoryId: request.repositoryId, path: request.path, beforeHash: request.expectedHash, afterHash: hash(after) });
129
+ }
130
+ history.push(attempt);
131
+ save(); // write-ahead record: an uncertain attempt is never blindly replayed
132
+ try {
133
+ signal?.throwIfAborted();
134
+ if (request.action === 'patch') {
135
+ workspace.execute('apply_patch', { path: request.path, expectedHash: request.expectedHash, oldText: request.oldText, newText: request.newText });
136
+ attempt.status = 'applied';
137
+ }
138
+ else if (request.kind === 'openspec') {
139
+ const output = await runOpenSpec(resolveOpenSpecCli(), context.artifactRoot, ['validate', '--all', '--strict', '--no-interactive', '--json'], signal);
140
+ attempt.output = output.slice(-16_000);
141
+ const report = JSON.parse(output);
142
+ if (!report.items?.length || report.items.some(item => item.valid !== true) || report.summary?.totals?.failed !== 0)
143
+ throw new Error('OpenSpec did not report successful validation of any specs/changes; inspect the saved output');
144
+ attempt.status = 'passed';
145
+ }
146
+ else {
147
+ if (!plan)
148
+ throw new Error('No saved verification plan is available');
149
+ const command = expandedPlanCommands(context, plan).find(item => item.key === request.checkId);
150
+ if (!command)
151
+ throw new Error('checkId does not belong to the saved verification plan');
152
+ const receipt = await verifyPipeline(context, { kind: 'scoped', planHash: plan.planHash, commands: [command] }, text => { attempt.output = ((attempt.output ?? '') + text).slice(-16_000); }, signal, { deadline: Date.now() + 45_000 });
153
+ attempt.status = receipt.valid ? 'passed' : 'failed';
154
+ if (!receipt.valid)
155
+ attempt.error = receipt.reason ?? 'Verification failed';
156
+ }
157
+ }
158
+ catch (error) {
159
+ attempt.status = 'failed';
160
+ attempt.error = (error instanceof Error ? error.message : String(error)).slice(-6000);
161
+ }
162
+ attempt.completedAt = new Date().toISOString();
163
+ save();
164
+ return { ...attempt, notice: 'A repair/check is not workflow completion. Resume revalidates all required gates in the original run.' };
165
+ }
166
+ finally {
167
+ await release();
168
+ }
169
+ }
@@ -1,4 +1,4 @@
1
- import type { PipelineContext } from '../installer/runtime/pipeline-state.js';
1
+ import type { PipelineContext } from '../pipeline/pipeline-state.js';
2
2
  /** Small, provider-independent map of facts from the admitted checkout. Never
3
3
  * follows a documentation link out of scope or invents verification commands. */
4
4
  export interface RepositoryContextEntry {
@@ -124,4 +124,3 @@ export function renderRepositoryContext(current, previous) {
124
124
  ].join('\n\n');
125
125
  }
126
126
  export function repositoryContext(context) { return renderRepositoryContext(repositoryContextSnapshot(context)); }
127
- //# sourceMappingURL=repository-context.js.map
@@ -1,4 +1,4 @@
1
- import type { CandidateManifest } from '../installer/runtime/pipeline-state.js';
1
+ import type { CandidateManifest } from '../pipeline/pipeline-state.js';
2
2
  export interface ReviewManifest extends CandidateManifest {
3
3
  truncated: boolean;
4
4
  }
@@ -38,4 +38,3 @@ export function reviewChanges(previous, current) {
38
38
  const transversal = changes.some(change => TRANSVERSAL.test(change.path));
39
39
  return { mode: transversal ? 'full' : 'incremental', reason: transversal ? 'A shared contract, build, dependency or security input changed' : 'Changes since the previous reviewed candidate', changes };
40
40
  }
41
- //# sourceMappingURL=review-context.js.map
@@ -27,4 +27,3 @@ export function selectRoleRoute(role, selected, kind, checkpoint, previous) {
27
27
  ...(selected.escalation.effort === undefined ? {} : { effort: selected.escalation.effort }),
28
28
  } };
29
29
  }
30
- //# sourceMappingURL=role-routing.js.map
@@ -21,4 +21,3 @@ export function writeRoleState(directory, data) {
21
21
  throw new Error('Role execution state exceeds its size limit');
22
22
  write(path.join(directory, 'role-execution.json'), content);
23
23
  }
24
- //# sourceMappingURL=role-state.js.map