specrails-core 5.6.0 → 6.0.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 (279) 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/change-scope.d.ts +63 -0
  5. package/dist/agent-runtime/change-scope.js +297 -0
  6. package/dist/agent-runtime/cli-executor.d.ts +1 -1
  7. package/dist/agent-runtime/cli-executor.js +1 -2
  8. package/dist/agent-runtime/cli-process.js +0 -1
  9. package/dist/agent-runtime/cli.js +4 -5
  10. package/dist/agent-runtime/codex-schema.js +0 -1
  11. package/dist/agent-runtime/compact/architect.d.ts +3 -272
  12. package/dist/agent-runtime/compact/architect.js +8 -9
  13. package/dist/agent-runtime/compact/chat-client.d.ts +3 -3
  14. package/dist/agent-runtime/compact/chat-client.js +1 -2
  15. package/dist/agent-runtime/compact/developer.d.ts +3 -70
  16. package/dist/agent-runtime/compact/developer.js +13 -14
  17. package/dist/agent-runtime/compact/environment.d.ts +16 -5
  18. package/dist/agent-runtime/compact/environment.js +32 -3
  19. package/dist/agent-runtime/compact/exit-code-honesty.d.ts +2 -1
  20. package/dist/agent-runtime/compact/exit-code-honesty.js +0 -1
  21. package/dist/agent-runtime/compact/guarded-loop.d.ts +2 -18
  22. package/dist/agent-runtime/compact/guarded-loop.js +7 -8
  23. package/dist/agent-runtime/compact/prompt-inputs.d.ts +0 -2
  24. package/dist/agent-runtime/compact/prompt-inputs.js +1 -2
  25. package/dist/agent-runtime/compact/reviewer.d.ts +0 -13
  26. package/dist/agent-runtime/compact/reviewer.js +5 -6
  27. package/dist/agent-runtime/compact/step.d.ts +0 -1
  28. package/dist/agent-runtime/compact/step.js +1 -2
  29. package/dist/agent-runtime/compact/test-reachability.js +6 -3
  30. package/dist/agent-runtime/config.js +0 -1
  31. package/dist/agent-runtime/core-host.d.ts +2 -2
  32. package/dist/agent-runtime/core-host.js +2 -3
  33. package/dist/agent-runtime/durable-store.d.ts +0 -1
  34. package/dist/agent-runtime/durable-store.js +1 -2
  35. package/dist/agent-runtime/efficiency-summary.d.ts +2 -2
  36. package/dist/agent-runtime/efficiency-summary.js +1 -2
  37. package/dist/agent-runtime/efficiency-types.js +0 -1
  38. package/dist/agent-runtime/efficiency.js +0 -1
  39. package/dist/agent-runtime/evaluation-corpus.js +0 -1
  40. package/dist/agent-runtime/evaluation.d.ts +2 -1
  41. package/dist/agent-runtime/evaluation.js +1 -2
  42. package/dist/agent-runtime/executor-types.d.ts +1 -1
  43. package/dist/agent-runtime/executor-types.js +0 -1
  44. package/dist/agent-runtime/executors.js +0 -1
  45. package/dist/agent-runtime/gemini-policy.js +0 -1
  46. package/dist/agent-runtime/graph/artifacts.d.ts +1 -1
  47. package/dist/agent-runtime/graph/artifacts.js +5 -3
  48. package/dist/agent-runtime/graph/convergence.d.ts +26 -0
  49. package/dist/agent-runtime/graph/convergence.js +62 -0
  50. package/dist/agent-runtime/graph/nodes.d.ts +1 -1
  51. package/dist/agent-runtime/graph/nodes.js +170 -24
  52. package/dist/agent-runtime/graph/review-policy.js +0 -1
  53. package/dist/agent-runtime/graph/roles.d.ts +2 -5
  54. package/dist/agent-runtime/graph/roles.js +2 -8
  55. package/dist/agent-runtime/graph/state.d.ts +6 -1
  56. package/dist/agent-runtime/graph/state.js +2 -1
  57. package/dist/agent-runtime/graph-checkpointer.d.ts +2 -1
  58. package/dist/agent-runtime/graph-checkpointer.js +0 -1
  59. package/dist/agent-runtime/guardrails.d.ts +3 -3
  60. package/dist/agent-runtime/guardrails.js +1 -2
  61. package/dist/agent-runtime/index.d.ts +1 -1
  62. package/dist/agent-runtime/index.js +1 -2
  63. package/dist/agent-runtime/kimi-acp.js +1 -2
  64. package/dist/agent-runtime/kimi-model.d.ts +6 -0
  65. package/dist/agent-runtime/kimi-model.js +12 -0
  66. package/dist/agent-runtime/openai-executor.d.ts +0 -9
  67. package/dist/agent-runtime/openai-executor.js +6 -7
  68. package/dist/agent-runtime/openspec-tool-server.js +1 -2
  69. package/dist/agent-runtime/openspec.d.ts +0 -2
  70. package/dist/agent-runtime/openspec.js +1 -6
  71. package/dist/agent-runtime/prompts.d.ts +11 -5
  72. package/dist/agent-runtime/prompts.js +46 -17
  73. package/dist/agent-runtime/provider-diagnostic.js +1 -2
  74. package/dist/agent-runtime/recovery.js +1 -2
  75. package/dist/agent-runtime/repository-context.d.ts +1 -1
  76. package/dist/agent-runtime/repository-context.js +19 -1
  77. package/dist/agent-runtime/review-context.d.ts +1 -1
  78. package/dist/agent-runtime/review-context.js +0 -1
  79. package/dist/agent-runtime/role-routing.js +0 -1
  80. package/dist/agent-runtime/role-state.js +0 -1
  81. package/dist/agent-runtime/runtime-identity.js +1 -2
  82. package/dist/agent-runtime/tool-event.js +0 -1
  83. package/dist/agent-runtime/verification-plan.d.ts +5 -4
  84. package/dist/agent-runtime/verification-plan.js +9 -5
  85. package/dist/agent-runtime/workflow-types.js +0 -1
  86. package/dist/agent-runtime/workflow.js +0 -1
  87. package/dist/agent-runtime/workspace-tools.d.ts +2 -2
  88. package/dist/agent-runtime/workspace-tools.js +1 -2
  89. package/dist/installer/cli.d.ts +3 -32
  90. package/dist/installer/cli.js +26 -101
  91. package/dist/installer/commands/framework.d.ts +4 -3
  92. package/dist/installer/commands/framework.js +0 -1
  93. package/dist/installer/commands/init.d.ts +4 -25
  94. package/dist/installer/commands/init.js +5 -8
  95. package/dist/installer/phases/framework-lifecycle.d.ts +3 -17
  96. package/dist/installer/phases/framework-lifecycle.js +2 -3
  97. package/dist/installer/phases/install-config.d.ts +7 -8
  98. package/dist/installer/phases/install-config.js +2 -7
  99. package/dist/installer/phases/manifest.d.ts +6 -7
  100. package/dist/installer/phases/manifest.js +2 -7
  101. package/dist/installer/phases/prereqs.d.ts +6 -7
  102. package/dist/installer/phases/prereqs.js +4 -6
  103. package/dist/installer/phases/provider-detect.d.ts +6 -7
  104. package/dist/installer/phases/provider-detect.js +2 -4
  105. package/dist/installer/phases/scaffold.d.ts +9 -10
  106. package/dist/installer/phases/scaffold.js +82 -805
  107. package/dist/installer/util/errors.js +0 -1
  108. package/dist/installer/util/exec.d.ts +3 -2
  109. package/dist/installer/util/exec.js +0 -1
  110. package/dist/installer/util/fs.d.ts +0 -10
  111. package/dist/installer/util/fs.js +1 -2
  112. package/dist/installer/util/git.js +0 -1
  113. package/dist/installer/util/install-transaction.d.ts +2 -2
  114. package/dist/installer/util/install-transaction.js +1 -2
  115. package/dist/installer/util/logger.d.ts +1 -3
  116. package/dist/installer/util/logger.js +0 -1
  117. package/dist/installer/util/paths.js +0 -1
  118. package/dist/installer/util/registry.d.ts +4 -8
  119. package/dist/installer/util/registry.js +2 -3
  120. package/dist/{installer/runtime → pipeline}/pipeline-state.d.ts +11 -0
  121. package/dist/{installer/runtime → pipeline}/pipeline-state.js +56 -5
  122. package/dist/shared/args.d.ts +18 -0
  123. package/dist/shared/args.js +53 -0
  124. package/integration-contract.json +11 -47
  125. package/package.json +3 -10
  126. package/templates/agents/sr-architect.md +15 -310
  127. package/templates/agents/sr-developer.md +15 -269
  128. package/templates/agents/sr-reviewer.md +13 -367
  129. package/templates/codex-skills/rails/sr-architect/SKILL.md +14 -308
  130. package/templates/codex-skills/rails/sr-developer/SKILL.md +14 -201
  131. package/templates/codex-skills/rails/sr-reviewer/SKILL.md +15 -289
  132. package/templates/kimi/specrails/run-skill.mjs +91 -2173
  133. package/bin/tui-installer.mjs +0 -430
  134. package/commands/doctor.md +0 -62
  135. package/dist/agent-runtime/capabilities.js.map +0 -1
  136. package/dist/agent-runtime/cli-executor.js.map +0 -1
  137. package/dist/agent-runtime/cli-process.js.map +0 -1
  138. package/dist/agent-runtime/cli.js.map +0 -1
  139. package/dist/agent-runtime/codex-schema.js.map +0 -1
  140. package/dist/agent-runtime/compact/architect.js.map +0 -1
  141. package/dist/agent-runtime/compact/chat-client.js.map +0 -1
  142. package/dist/agent-runtime/compact/developer.js.map +0 -1
  143. package/dist/agent-runtime/compact/environment.js.map +0 -1
  144. package/dist/agent-runtime/compact/exit-code-honesty.js.map +0 -1
  145. package/dist/agent-runtime/compact/guarded-loop.js.map +0 -1
  146. package/dist/agent-runtime/compact/prompt-inputs.js.map +0 -1
  147. package/dist/agent-runtime/compact/reviewer.js.map +0 -1
  148. package/dist/agent-runtime/compact/step.js.map +0 -1
  149. package/dist/agent-runtime/compact/test-reachability.js.map +0 -1
  150. package/dist/agent-runtime/config.js.map +0 -1
  151. package/dist/agent-runtime/core-host.js.map +0 -1
  152. package/dist/agent-runtime/durable-store.js.map +0 -1
  153. package/dist/agent-runtime/efficiency-summary.js.map +0 -1
  154. package/dist/agent-runtime/efficiency-types.js.map +0 -1
  155. package/dist/agent-runtime/efficiency.js.map +0 -1
  156. package/dist/agent-runtime/evaluation-corpus.js.map +0 -1
  157. package/dist/agent-runtime/evaluation.js.map +0 -1
  158. package/dist/agent-runtime/executor-types.js.map +0 -1
  159. package/dist/agent-runtime/executors.js.map +0 -1
  160. package/dist/agent-runtime/gemini-policy.js.map +0 -1
  161. package/dist/agent-runtime/graph/artifacts.js.map +0 -1
  162. package/dist/agent-runtime/graph/nodes.js.map +0 -1
  163. package/dist/agent-runtime/graph/review-policy.js.map +0 -1
  164. package/dist/agent-runtime/graph/roles.js.map +0 -1
  165. package/dist/agent-runtime/graph/state.js.map +0 -1
  166. package/dist/agent-runtime/graph-checkpointer.js.map +0 -1
  167. package/dist/agent-runtime/guardrails.js.map +0 -1
  168. package/dist/agent-runtime/index.js.map +0 -1
  169. package/dist/agent-runtime/kimi-acp.js.map +0 -1
  170. package/dist/agent-runtime/openai-executor.js.map +0 -1
  171. package/dist/agent-runtime/openspec-tool-server.js.map +0 -1
  172. package/dist/agent-runtime/openspec.js.map +0 -1
  173. package/dist/agent-runtime/prompts.js.map +0 -1
  174. package/dist/agent-runtime/provider-diagnostic.js.map +0 -1
  175. package/dist/agent-runtime/recovery.js.map +0 -1
  176. package/dist/agent-runtime/repository-context.js.map +0 -1
  177. package/dist/agent-runtime/review-context.js.map +0 -1
  178. package/dist/agent-runtime/role-routing.js.map +0 -1
  179. package/dist/agent-runtime/role-state.js.map +0 -1
  180. package/dist/agent-runtime/runtime-identity.js.map +0 -1
  181. package/dist/agent-runtime/tool-event.js.map +0 -1
  182. package/dist/agent-runtime/verification-plan.js.map +0 -1
  183. package/dist/agent-runtime/workflow-types.js.map +0 -1
  184. package/dist/agent-runtime/workflow.js.map +0 -1
  185. package/dist/agent-runtime/workspace-tools.js.map +0 -1
  186. package/dist/installer/cli.js.map +0 -1
  187. package/dist/installer/commands/doctor.d.ts +0 -27
  188. package/dist/installer/commands/doctor.js +0 -615
  189. package/dist/installer/commands/doctor.js.map +0 -1
  190. package/dist/installer/commands/framework.js.map +0 -1
  191. package/dist/installer/commands/init.js.map +0 -1
  192. package/dist/installer/commands/update.d.ts +0 -56
  193. package/dist/installer/commands/update.js +0 -257
  194. package/dist/installer/commands/update.js.map +0 -1
  195. package/dist/installer/commands/v5-migration.d.ts +0 -32
  196. package/dist/installer/commands/v5-migration.js +0 -133
  197. package/dist/installer/commands/v5-migration.js.map +0 -1
  198. package/dist/installer/phases/framework-lifecycle.js.map +0 -1
  199. package/dist/installer/phases/install-config.js.map +0 -1
  200. package/dist/installer/phases/manifest.js.map +0 -1
  201. package/dist/installer/phases/prereqs.js.map +0 -1
  202. package/dist/installer/phases/provider-detect.js.map +0 -1
  203. package/dist/installer/phases/scaffold.js.map +0 -1
  204. package/dist/installer/runtime/kimi.d.ts +0 -84
  205. package/dist/installer/runtime/kimi.js +0 -255
  206. package/dist/installer/runtime/kimi.js.map +0 -1
  207. package/dist/installer/runtime/pipeline-state.js.map +0 -1
  208. package/dist/installer/util/errors.js.map +0 -1
  209. package/dist/installer/util/exec.js.map +0 -1
  210. package/dist/installer/util/fs.js.map +0 -1
  211. package/dist/installer/util/git.js.map +0 -1
  212. package/dist/installer/util/install-transaction.js.map +0 -1
  213. package/dist/installer/util/logger.js.map +0 -1
  214. package/dist/installer/util/paths.js.map +0 -1
  215. package/dist/installer/util/prompts.d.ts +0 -23
  216. package/dist/installer/util/prompts.js +0 -49
  217. package/dist/installer/util/prompts.js.map +0 -1
  218. package/dist/installer/util/registry.js.map +0 -1
  219. package/dist/installer/util/template.d.ts +0 -23
  220. package/dist/installer/util/template.js +0 -60
  221. package/dist/installer/util/template.js.map +0 -1
  222. package/docs/README.md +0 -40
  223. package/docs/agent-runtime-efficiency.md +0 -65
  224. package/docs/agent-runtime.md +0 -393
  225. package/docs/agents.md +0 -315
  226. package/docs/changelog.md +0 -168
  227. package/docs/ci-cd.md +0 -60
  228. package/docs/concepts.md +0 -183
  229. package/docs/customization.md +0 -363
  230. package/docs/deployment.md +0 -234
  231. package/docs/getting-started.md +0 -122
  232. package/docs/installation.md +0 -395
  233. package/docs/local-tickets.md +0 -191
  234. package/docs/migration-guide.md +0 -140
  235. package/docs/playbook-oss-maintainer.md +0 -112
  236. package/docs/playbook-parallel-dev.md +0 -124
  237. package/docs/playbook-product-discovery.md +0 -115
  238. package/docs/plugin-architecture.md +0 -144
  239. package/docs/research/codex-compatibility-analysis.md +0 -365
  240. package/docs/research/mcp-feasibility-analysis.md +0 -382
  241. package/docs/testing/test-matrix-codex.md +0 -130
  242. package/docs/updating.md +0 -89
  243. package/docs/user-docs/cli-reference.md +0 -428
  244. package/docs/user-docs/codex-vs-claude-code.md +0 -23
  245. package/docs/user-docs/core-updates.md +0 -70
  246. package/docs/user-docs/faq.md +0 -146
  247. package/docs/user-docs/getting-started-codex.md +0 -194
  248. package/docs/user-docs/getting-started-kimi.md +0 -423
  249. package/docs/user-docs/installation.md +0 -237
  250. package/docs/user-docs/provider-pipelines.md +0 -96
  251. package/docs/user-docs/quick-start.md +0 -161
  252. package/docs/windows.md +0 -78
  253. package/docs/workflows.md +0 -463
  254. package/schemas/profile.v1.json +0 -207
  255. package/templates/claude-md/CLAUDE-quickstart.md +0 -54
  256. package/templates/claude-md/root.md +0 -50
  257. package/templates/codex-skills/batch-implement/SKILL.md +0 -38
  258. package/templates/codex-skills/implement/SKILL.md +0 -38
  259. package/templates/codex-skills/retry/SKILL.md +0 -16
  260. package/templates/commands/specrails/compat-check.md +0 -271
  261. package/templates/commands/specrails/doctor.md +0 -62
  262. package/templates/commands/specrails/explore-spec.md +0 -173
  263. package/templates/commands/specrails/health-check.md +0 -527
  264. package/templates/commands/specrails/memory-inspect.md +0 -261
  265. package/templates/commands/specrails/opsx-diff.md +0 -419
  266. package/templates/commands/specrails/propose-spec.md +0 -102
  267. package/templates/commands/specrails/refactor-recommender.md +0 -169
  268. package/templates/commands/specrails/telemetry.md +0 -553
  269. package/templates/commands/specrails/why.md +0 -96
  270. package/templates/gemini-commands/batch-implement.toml +0 -37
  271. package/templates/gemini-commands/implement.toml +0 -37
  272. package/templates/gemini-commands/retry.toml +0 -15
  273. package/templates/profiles/default.json +0 -14
  274. package/templates/profiles/kimi-default.json +0 -15
  275. package/templates/rules/layer.md +0 -8
  276. package/templates/runtime/provider-pipeline.md +0 -113
  277. package/templates/security/security-exemptions.yaml +0 -20
  278. package/templates/settings/confidence-config.json +0 -17
  279. package/templates/settings/settings.json +0 -15
@@ -1,561 +1,19 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * specrails-core CLI — thin ESM dispatcher.
4
- *
5
- * All installer subcommands (init, update, doctor) execute
6
- * in-process via the Node installer under dist/installer/. This file
7
- * only keeps logic that is local to the dispatcher:
8
- * - `profile validate` / `profile show` — schema validation via ajv.
9
- * - `init` TUI short-circuit — spawns tui-installer.mjs
10
- * then re-enters init with
11
- * --from-config.
12
- *
13
- * Nothing in this file shells out to bash.
14
- */
15
-
16
- import { spawnSync } from 'node:child_process'
17
- import { existsSync, readFileSync } from 'node:fs'
18
- import { createRequire } from 'node:module'
2
+ // Thin npm bin entry: every command lives in dist/installer/cli.js.
3
+ import { existsSync } from 'node:fs'
19
4
  import path from 'node:path'
20
5
  import { fileURLToPath, pathToFileURL } from 'node:url'
21
6
 
22
- const __filename = fileURLToPath(import.meta.url)
23
- const __dirname = path.dirname(__filename)
24
- const ROOT = path.resolve(__dirname, '..')
25
- const require_ = createRequire(import.meta.url)
26
-
27
- const args = process.argv.slice(2)
28
- const subcommand = args[0]
29
-
30
- // ─── Global --version / -V flag ──────────────────────────────────────────────
31
-
32
- // Treat version as a GLOBAL flag only when it is the command itself. Offline
33
- // lifecycle commands also carry a required `--version <target>` option; scanning
34
- // the whole argv would intercept `swap-current --version 4.12.0` here and exit 0
35
- // without ever validating or moving the framework pointer.
36
- if (subcommand === '--version' || subcommand === '-V') {
37
- const pkg = require_(path.resolve(ROOT, 'package.json'))
38
- console.log(`specrails-core v${pkg.version}`)
39
- process.exit(0)
40
- }
41
-
42
- // ─── Usage screen (no subcommand) ────────────────────────────────────────────
43
-
44
- if (!subcommand) {
45
- printUsage()
46
- process.exit(0)
47
- }
48
-
49
- // ─── Removed-in-v5 subcommands (clear error, not a generic "unknown") ────────
50
-
51
- const REMOVED_SUBCOMMANDS = new Set(['enrich'])
52
-
53
- if (REMOVED_SUBCOMMANDS.has(subcommand)) {
54
- console.error(`${subcommand} was removed in v5 — init now installs everything directly.`)
55
- process.exit(1)
56
- }
57
-
58
- // ─── Subcommand allowlist (kept for backwards compatibility) ─────────────────
59
-
60
- const KNOWN_SUBCOMMANDS = new Set([
61
- 'init',
62
- 'update',
63
- 'doctor',
64
- 'pipeline',
65
- 'runtime',
66
- 'install-framework',
67
- 'swap-current',
68
- 'assemble',
69
- 'version',
70
- 'profile',
71
- 'help',
72
- ])
73
-
74
- if (!KNOWN_SUBCOMMANDS.has(subcommand)) {
75
- console.error(`Unknown command: ${subcommand}\n`)
76
- console.error(
77
- 'Available commands: init, update, doctor, install-framework, swap-current, assemble, version, profile, pipeline, help',
78
- )
79
- process.exit(1)
80
- }
81
-
82
- // ─── Removed-in-v5 flags (clear error) ───────────────────────────────────────
83
-
84
- if (args.includes('--quick') || args.includes('--lite')) {
85
- console.error('--quick was removed in v5 — init now installs everything directly.')
86
- process.exit(1)
87
- }
88
-
89
- const subargs = args.slice(1)
90
-
91
- // ─── help / version handled by the dispatcher ────────────────────────────────
92
-
93
- if (subcommand === 'help') {
94
- printUsage()
95
- process.exit(0)
96
- }
97
-
98
- if (subcommand === 'version') {
99
- const pkg = require_(path.resolve(ROOT, 'package.json'))
100
- console.log(`specrails-core v${pkg.version}`)
101
- process.exit(0)
102
- }
103
-
104
- // ─── profile validate / show ─────────────────────────────────────────────────
105
- // Pure Node logic; no installer touch.
106
-
107
- if (subcommand === 'profile') {
108
- await runProfile(subargs)
109
- process.exit(0)
110
- }
111
-
112
- // ─── init: optional TUI short-circuit ────────────────────────────────────────
113
- // Default flow runs the TUI to collect agent/model configuration and
114
- // write .specrails/install-config.yaml, then falls through to the Node
115
- // init command with --from-config. Skipped when --no-tui / --from-config
116
- // / --yes is passed.
117
-
118
- if (subcommand === 'init') {
119
- const hasNoTui =
120
- subargs.includes('--no-tui') ||
121
- subargs.includes('--no-direct') ||
122
- subargs.includes('--from-config')
123
- const autoYes = subargs.includes('--yes') || subargs.includes('-y')
124
- const useTui = !hasNoTui && !autoYes
125
-
126
- if (useTui) {
127
- const rootDirIdx = subargs.indexOf('--root-dir')
128
- const rootDir =
129
- rootDirIdx >= 0 && subargs[rootDirIdx + 1]
130
- ? path.resolve(subargs[rootDirIdx + 1])
131
- : process.cwd()
132
-
133
- // Forward --provider so the TUI can honour an explicit choice and
134
- // skip the interactive picker. Other flags stay with the Node CLI step.
135
- const providerIdx = subargs.indexOf('--provider')
136
- const providerVal = providerIdx >= 0 ? subargs[providerIdx + 1] : null
137
- const providerEqArg = subargs.find((a) => a.startsWith('--provider='))
138
- const tuiArgs = [path.resolve(ROOT, 'bin', 'tui-installer.mjs'), rootDir]
139
- if (providerVal) tuiArgs.push('--provider', providerVal)
140
- else if (providerEqArg) tuiArgs.push(providerEqArg)
141
- if (subargs.includes('--with-profiles')) tuiArgs.push('--with-profiles')
142
- const tuiResult = spawnSync('node', tuiArgs, {
143
- stdio: 'inherit',
144
- cwd: process.cwd(),
145
- shell: process.platform === 'win32',
146
- })
147
-
148
- if (tuiResult.error) {
149
- console.error(
150
- '\nFailed to launch TUI installer:',
151
- tuiResult.error.message,
152
- '\nRun: npm install or pass --no-tui to skip the TUI.\n',
153
- )
154
- process.exit(1)
155
- }
156
- if (tuiResult.status !== 0) {
157
- process.exit(tuiResult.status ?? 1)
158
- }
159
-
160
- // TUI succeeded — re-enter init with --from-config so the Node
161
- // command reads provider/agents from install-config.yaml.
162
- const nextArgs = subargs
163
- .filter((a) => a !== '--no-tui' && a !== '--no-direct')
164
- .concat(['--yes', '--from-config'])
165
- await runNodeCli(['init', ...nextArgs])
166
- // runNodeCli calls process.exit itself; the following line is
167
- // defensive.
168
- process.exit(0)
169
- }
170
-
171
- // Direct mode — strip internal --no-tui / --no-direct flags and go.
172
- const cleanArgs = subargs.filter((a) => a !== '--no-tui' && a !== '--no-direct')
173
- await runNodeCli(['init', ...cleanArgs])
174
- process.exit(0)
175
- }
176
-
177
- // ─── update / doctor — direct dispatch to Node CLI ───────────────────────────
178
-
179
- await runNodeCli([subcommand, ...subargs])
180
- process.exit(0)
181
-
182
- // ─────────────────────────────────────────────────────────────────────────────
183
- // Helpers
184
- // ─────────────────────────────────────────────────────────────────────────────
185
-
186
- function printUsage() {
187
- console.log(`specrails-core — Provider-independent AI agent workflow system
188
-
189
- Usage:
190
- specrails-core init [--root-dir <path>] [--yes|-y] [--no-tui] Install into a repository
191
- specrails-core update [--only <component>] [--dry-run] Update an existing installation
192
- specrails-core pipeline <init|status|phase|verify|archive-check|preview|apply-preview> [--context <path>]
193
- specrails-core doctor Run health checks
194
- specrails-core install-framework --framework-dir <path> --provider <value> --version <value>
195
- Materialize an offline framework version
196
- specrails-core swap-current --framework-dir <path> --version <value> [--providers <csv>]
197
- Validate and atomically expose a framework version
198
- specrails-core assemble --workspace <path> --framework-dir <path> Assemble a workspace from the framework
199
- specrails-core profile <validate|show> [<path>] Validate or pretty-print a profile JSON
200
- specrails-core version Show installed version
201
-
202
- Flags for init:
203
- --root-dir <path> Target repository path (default: current directory)
204
- --yes | -y Non-interactive; use defaults, skip TUI
205
- --provider <value> Force provider: claude, codex, gemini, or kimi
206
- --no-tui Skip TUI; use defaults / flags directly
207
- --from-config Skip TUI; use existing .specrails/install-config.yaml
208
-
209
- Global flags:
210
- --version | -V Show installed version
211
-
212
- More info: https://github.com/fjpulidop/specrails-core`)
213
- }
214
-
215
- function resolveEnrichOptions(cwd, argv, artifactRoot = cwd) {
216
- const workflowArgs = []
217
- let explicitProvider
218
- let model
219
- for (let index = 0; index < argv.length; index++) {
220
- const token = argv[index]
221
- if (token === '--provider' || token === '--model') {
222
- const value = argv[++index]
223
- if (!value) {
224
- console.error(`${token} requires a value`)
225
- process.exit(1)
226
- }
227
- if (token === '--provider') explicitProvider = value
228
- else model = value
229
- continue
230
- }
231
- if (token.startsWith('--provider=')) {
232
- explicitProvider = token.slice('--provider='.length)
233
- continue
234
- }
235
- if (token.startsWith('--model=')) {
236
- model = token.slice('--model='.length)
237
- continue
238
- }
239
- workflowArgs.push(token)
240
- }
241
-
242
- const supported = new Set(['claude', 'codex', 'gemini', 'kimi'])
243
- if (explicitProvider && !supported.has(explicitProvider)) {
244
- console.error(
245
- `Unsupported provider "${explicitProvider}". Expected claude, codex, gemini, or kimi.`,
246
- )
247
- process.exit(1)
248
- }
249
-
250
- let provider = explicitProvider
251
- if (!provider) {
252
- for (const root of [cwd, artifactRoot]) {
253
- const manifestPath = path.join(
254
- root,
255
- '.specrails',
256
- 'specrails-manifest.json',
257
- )
258
- if (existsSync(manifestPath)) {
259
- try {
260
- const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
261
- if (supported.has(manifest.primary_provider)) {
262
- provider = manifest.primary_provider
263
- break
264
- }
265
- } catch {
266
- // A malformed manifest is diagnosed by `specrails-core doctor`;
267
- // enrich continues to config/directory fallback.
268
- }
269
- }
270
- }
271
- }
272
- if (!provider) {
273
- for (const root of [cwd, artifactRoot]) {
274
- const configPath = path.join(root, '.specrails', 'install-config.yaml')
275
- if (!existsSync(configPath)) continue
276
- const match = readFileSync(configPath, 'utf8').match(
277
- /^provider:\s*(claude|codex|gemini|kimi)\s*$/m,
278
- )
279
- if (match) {
280
- provider = match[1]
281
- break
282
- }
283
- }
284
- }
285
- if (!provider) {
286
- provider =
287
- ['claude', 'codex', 'gemini', 'kimi'].find((candidate) =>
288
- existsSync(
289
- path.join(
290
- artifactRoot,
291
- candidate === 'kimi' ? '.kimi-code' : `.${candidate}`,
292
- ),
293
- ),
294
- ) ?? 'claude'
295
- }
296
- return { provider, model, workflowArgs }
297
- }
298
-
299
- async function resolveEnrichWorkspace(cwd) {
300
- const registryModulePath = path.resolve(
301
- ROOT,
302
- 'dist',
303
- 'installer',
304
- 'util',
305
- 'registry.js',
306
- )
307
- if (!existsSync(registryModulePath)) {
308
- return { artifactRoot: cwd, codeRoot: cwd }
309
- }
310
- try {
311
- const registry = await import(pathToFileURL(registryModulePath).href)
312
- const resolution = registry.resolveArtifacts(cwd, { allocate: false })
313
- return {
314
- artifactRoot: path.resolve(resolution.artifactRoot),
315
- codeRoot: path.resolve(resolution.codeRoot),
316
- }
317
- } catch {
318
- // Doctor reports malformed registry state. Enrich retains the legacy
319
- // in-repository fallback instead of guessing another relocated workspace.
320
- return { artifactRoot: cwd, codeRoot: cwd }
321
- }
322
- }
323
-
324
- function resolveConfiguredEnrichModel(codeRoot, artifactRoot) {
325
- const activeProfile = process.env.SPECRAILS_PROFILE_PATH
326
- if (activeProfile) {
327
- const activePath = path.isAbsolute(activeProfile)
328
- ? activeProfile
329
- : path.resolve(codeRoot, activeProfile)
330
- const activeModel = readProfileOrchestratorModel(activePath)
331
- if (activeModel) return activeModel
332
- }
333
- const configCandidates = [
334
- path.join(codeRoot, '.specrails', 'install-config.yaml'),
335
- path.join(artifactRoot, '.specrails', 'install-config.yaml'),
336
- ]
337
- for (const configPath of configCandidates) {
338
- if (!existsSync(configPath)) continue
339
- try {
340
- const config = require_('js-yaml').load(readFileSync(configPath, 'utf8'))
341
- const configured = config?.models?.defaults?.model
342
- if (typeof configured === 'string' && configured.trim() !== '') {
343
- return configured.trim()
344
- }
345
- } catch {
346
- // The installer/doctor owns full config diagnostics. Continue to a
347
- // provider profile rather than extracting a value from malformed YAML.
348
- }
349
- }
350
- const profileCandidates = [
351
- path.join(artifactRoot, '.specrails', 'profiles', 'kimi-default.json'),
352
- path.join(codeRoot, '.specrails', 'profiles', 'kimi-default.json'),
353
- ]
354
- for (const profilePath of profileCandidates) {
355
- const configured = readProfileOrchestratorModel(profilePath)
356
- if (configured) return configured
357
- }
358
- return null
359
- }
360
-
361
- function readProfileOrchestratorModel(profilePath) {
362
- if (!existsSync(profilePath)) return null
363
- try {
364
- const profile = JSON.parse(readFileSync(profilePath, 'utf8'))
365
- const configured = profile?.orchestrator?.model
366
- return typeof configured === 'string' && configured.trim() !== ''
367
- ? configured.trim()
368
- : null
369
- } catch {
370
- // Profile validation provides the actionable error. Fall through.
371
- return null
372
- }
373
- }
374
-
375
- function serializeWorkflowArgs(argv) {
376
- return argv
377
- .map((value) =>
378
- value === '' || /\s|["']/u.test(value) ? JSON.stringify(value) : value,
379
- )
380
- .join(' ')
381
- }
382
-
383
- /**
384
- * Loads the compiled Node CLI (dist/installer/cli.js) and invokes its
385
- * `main` function with the given argv array. Propagates the returned
386
- * exit code via process.exit.
387
- */
388
- async function runNodeCli(argv) {
389
- const cliPath = path.resolve(ROOT, 'dist', 'installer', 'cli.js')
390
- if (!existsSync(cliPath)) {
391
- console.error(
392
- `Installer runtime not found at ${cliPath}. ` +
393
- `If you are running from a source checkout, run: npm run build`,
394
- )
395
- process.exit(1)
396
- }
397
- const mod = await import(pathToFileURL(cliPath).href)
398
- if (typeof mod.main !== 'function') {
399
- console.error('Installer runtime is missing the expected main() export — corrupt install?')
400
- process.exit(1)
401
- }
402
- const code = await mod.main(argv)
403
- // Let pipe writes drain before exiting; runtime status can exceed a pipe buffer.
404
- await Promise.all([process.stdout, process.stderr].map(stream =>
405
- new Promise((resolve, reject) => stream.write('', error => error ? reject(error) : resolve()))
406
- ))
407
- process.exit(code)
408
- }
409
-
410
- async function runProfile(subargs) {
411
- const action = subargs[0]
412
- const pathArg = subargs[1]
413
- if (!action || (action !== 'validate' && action !== 'show')) {
414
- console.error('Usage: specrails-core profile validate [<path>]')
415
- console.error(' specrails-core profile show [<path>]')
416
- process.exit(1)
417
- }
418
-
419
- const workspace = await resolveEnrichWorkspace(process.cwd())
420
- const resolveProfilePath = () => {
421
- if (pathArg) return path.resolve(pathArg)
422
- if (process.env.SPECRAILS_PROFILE_PATH) return path.resolve(process.env.SPECRAILS_PROFILE_PATH)
423
- const configRoots = [workspace.codeRoot, workspace.artifactRoot]
424
- let provider
425
- for (const root of configRoots) {
426
- const configPath = path.join(root, '.specrails', 'install-config.yaml')
427
- if (!existsSync(configPath)) continue
428
- const match = readFileSync(configPath, 'utf8').match(
429
- /^provider:\s*(claude|codex|gemini|kimi)\s*$/m,
430
- )
431
- if (match) {
432
- provider = match[1]
433
- break
434
- }
435
- }
436
- const names =
437
- provider === 'kimi'
438
- ? ['kimi-default.json', 'project-default.json']
439
- : ['project-default.json', 'kimi-default.json']
440
- for (const root of [workspace.artifactRoot, workspace.codeRoot]) {
441
- for (const name of names) {
442
- const candidate = path.join(root, '.specrails', 'profiles', name)
443
- if (existsSync(candidate)) return candidate
444
- }
445
- }
446
- return null
447
- }
448
-
449
- const profilePath = resolveProfilePath()
450
- if (!profilePath) {
451
- console.error('No profile path given and none could be resolved.')
452
- console.error('Pass an explicit path or set SPECRAILS_PROFILE_PATH, or place a profile at')
453
- console.error(
454
- ' .specrails/profiles/project-default.json (or kimi-default.json for Kimi)',
455
- )
456
- process.exit(1)
457
- }
458
- if (!existsSync(profilePath)) {
459
- console.error(`Profile file not found: ${profilePath}`)
460
- process.exit(1)
461
- }
462
-
463
- let profile
464
- try {
465
- profile = JSON.parse(readFileSync(profilePath, 'utf8'))
466
- } catch (e) {
467
- console.error(`Profile is not valid JSON: ${e.message}`)
468
- process.exit(1)
469
- }
470
-
471
- if (action === 'show') {
472
- console.log(JSON.stringify(profile, null, 2))
473
- process.exit(0)
474
- }
475
-
476
- // action === 'validate'
477
- const schemaPath = path.resolve(ROOT, 'schemas', 'profile.v1.json')
478
- if (!existsSync(schemaPath)) {
479
- console.error(`Schema not found at ${schemaPath} — install may be corrupt`)
480
- process.exit(1)
481
- }
482
-
483
- let Ajv
484
- try {
485
- const mod = await import('ajv/dist/2020.js')
486
- Ajv = mod.default
487
- } catch {
488
- console.error(
489
- "'ajv' is not installed. Run `npm install` in the specrails-core package directory first.",
490
- )
491
- process.exit(1)
492
- }
493
-
494
- const schema = JSON.parse(readFileSync(schemaPath, 'utf8'))
495
- const ajv = new Ajv({ allErrors: true, strict: false })
496
- const validate = ajv.compile(schema)
497
- const schemaValid = validate(profile)
498
- const semanticErrors = schemaValid
499
- ? validateProfileSemantics(profile)
500
- : []
501
-
502
- if (schemaValid && semanticErrors.length === 0) {
503
- console.log(`✓ ${profilePath} is a valid v1 profile.`)
504
- process.exit(0)
505
- }
506
- console.error(`✗ ${profilePath} failed validation:`)
507
- for (const err of validate.errors || []) {
508
- console.error(` ${err.instancePath || '/'} ${err.message} (${JSON.stringify(err.params)})`)
509
- }
510
- for (const err of semanticErrors) {
511
- console.error(` ${err}`)
512
- }
7
+ const cli = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'dist', 'installer', 'cli.js')
8
+ if (!existsSync(cli)) {
9
+ console.error(`Installer runtime not found at ${cli}. From a source checkout, run: npm run build`)
513
10
  process.exit(1)
514
11
  }
515
12
 
516
- /**
517
- * JSON Schema validates each profile entry in isolation. These invariants span
518
- * multiple array entries and therefore require a second, semantic validation
519
- * pass after AJV has established the profile's structural shape.
520
- */
521
- function validateProfileSemantics(profile) {
522
- const errors = []
523
- const firstAgentIndex = new Map()
524
-
525
- for (const [index, agent] of profile.agents.entries()) {
526
- const previous = firstAgentIndex.get(agent.id)
527
- if (previous !== undefined) {
528
- errors.push(
529
- `/agents/${index}/id duplicates agent id "${agent.id}" first declared at /agents/${previous}/id`,
530
- )
531
- } else {
532
- firstAgentIndex.set(agent.id, index)
533
- }
534
- }
535
-
536
- const knownAgents = new Set(firstAgentIndex.keys())
537
- const defaultIndices = []
538
- for (const [index, rule] of profile.routing.entries()) {
539
- if (!knownAgents.has(rule.agent)) {
540
- errors.push(
541
- `/routing/${index}/agent references unknown agent "${rule.agent}"`,
542
- )
543
- }
544
- if (rule.default === true) {
545
- defaultIndices.push(index)
546
- }
547
- }
548
-
549
- if (defaultIndices.length > 1) {
550
- errors.push(
551
- `/routing must contain at most one default rule (found ${defaultIndices.length})`,
552
- )
553
- }
554
- for (const index of defaultIndices) {
555
- if (index !== profile.routing.length - 1) {
556
- errors.push(`/routing/${index} default rule must be the last routing entry`)
557
- }
558
- }
559
-
560
- return errors
561
- }
13
+ const { main } = await import(pathToFileURL(cli).href)
14
+ const code = await main(process.argv.slice(2))
15
+ // Let pipe writes drain before exiting; runtime status can exceed a pipe buffer.
16
+ await Promise.all([process.stdout, process.stderr].map((stream) =>
17
+ new Promise((resolve, reject) => stream.write('', (error) => (error ? reject(error) : resolve()))),
18
+ ))
19
+ process.exit(code)
@@ -78,4 +78,3 @@ export async function configuredCapabilities(config, registry) {
78
78
  }
79
79
  return { schemaVersion: 1, roles };
80
80
  }
81
- //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1,63 @@
1
+ import { type PipelineContext, type PipelineRepository } from '../pipeline/pipeline-state.js';
2
+ export interface ChangedFile {
3
+ path: string;
4
+ status: 'added' | 'modified' | 'deleted';
5
+ }
6
+ export interface RepositoryChangeSet {
7
+ repositoryId: string;
8
+ scope?: string[];
9
+ files: ChangedFile[];
10
+ truncated: boolean;
11
+ }
12
+ /** An out-of-scope edit Core undid after a role turn. */
13
+ export interface DiscardedEdit {
14
+ repositoryId: string;
15
+ path: string;
16
+ restored: 'base' | 'previous' | 'removed';
17
+ }
18
+ /** A command without `cwd` runs in its repository's scope directory, never at the root of a larger checkout. */
19
+ export declare function withScopeDefault<T extends {
20
+ repositoryId: string;
21
+ cwd?: string;
22
+ }>(context: PipelineContext, command: T): T;
23
+ /** Model-proposed checks stay inside the repository scope: they prove the change, not the whole checkout. */
24
+ export declare function assertProposalInScope(context: PipelineContext, command: {
25
+ repositoryId: string;
26
+ cwd?: string;
27
+ }, what?: string): void;
28
+ /** Base commit per repository id; the first call records it. */
29
+ export declare function changeBases(context: PipelineContext): Record<string, string>;
30
+ /** Every path that differs from the base: tracked edits (staged or not), deletions and new untracked files. */
31
+ export declare function repositoryChanges(context: PipelineContext, repository: PipelineRepository, base: string, change?: string): ChangedFile[];
32
+ /** What this run changed, per repository and bounded: untracked files that predate the run are not part of it. */
33
+ export declare function changeSet(context: PipelineContext, change?: string, limit?: number): RepositoryChangeSet[];
34
+ /** Changes outside the repository scope (none when the whole checkout is the repository). */
35
+ export declare function outOfScope(repository: PipelineRepository, files: readonly ChangedFile[]): ChangedFile[];
36
+ interface SavedState {
37
+ fingerprint: string;
38
+ content?: Buffer;
39
+ mode?: number;
40
+ link?: string;
41
+ }
42
+ /** The out-of-scope state before a role turn: the host undoes only what that turn did. */
43
+ export interface ScopeGuard {
44
+ change?: string;
45
+ repositories: Array<{
46
+ id: string;
47
+ base: string;
48
+ before: Map<string, SavedState>;
49
+ }>;
50
+ }
51
+ export declare function captureOutOfScope(context: PipelineContext, change?: string): ScopeGuard;
52
+ /**
53
+ * Undoes every out-of-scope edit made since `guard` was captured. A path the
54
+ * turn changed outside the scope returns to its state before the turn: its
55
+ * base content, its earlier out-of-scope content, or absence. In-scope work,
56
+ * ignored files and out-of-scope state that predates the turn stay untouched.
57
+ */
58
+ export declare function discardOutOfScopeEdits(context: PipelineContext, guard: ScopeGuard): DiscardedEdit[];
59
+ /** Bounded prompt lines for a change set; repository ids prefix the paths only when several repositories are in scope. */
60
+ export declare function renderChangeSet(sets: readonly RepositoryChangeSet[], limit?: number): string[];
61
+ /** One human line naming discarded edits, bounded. */
62
+ export declare function describeDiscarded(edits: readonly DiscardedEdit[], multiple: boolean, limit?: number): string;
63
+ export {};