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.
- package/README.md +27 -145
- package/bin/specrails-core.mjs +12 -554
- package/dist/agent-runtime/capabilities.js +0 -1
- package/dist/agent-runtime/change-scope.d.ts +63 -0
- package/dist/agent-runtime/change-scope.js +297 -0
- package/dist/agent-runtime/cli-executor.d.ts +1 -1
- package/dist/agent-runtime/cli-executor.js +1 -2
- package/dist/agent-runtime/cli-process.js +0 -1
- package/dist/agent-runtime/cli.js +4 -5
- package/dist/agent-runtime/codex-schema.js +0 -1
- package/dist/agent-runtime/compact/architect.d.ts +3 -272
- package/dist/agent-runtime/compact/architect.js +8 -9
- package/dist/agent-runtime/compact/chat-client.d.ts +3 -3
- package/dist/agent-runtime/compact/chat-client.js +1 -2
- package/dist/agent-runtime/compact/developer.d.ts +3 -70
- package/dist/agent-runtime/compact/developer.js +13 -14
- package/dist/agent-runtime/compact/environment.d.ts +16 -5
- package/dist/agent-runtime/compact/environment.js +32 -3
- package/dist/agent-runtime/compact/exit-code-honesty.d.ts +2 -1
- package/dist/agent-runtime/compact/exit-code-honesty.js +0 -1
- package/dist/agent-runtime/compact/guarded-loop.d.ts +2 -18
- package/dist/agent-runtime/compact/guarded-loop.js +7 -8
- package/dist/agent-runtime/compact/prompt-inputs.d.ts +0 -2
- package/dist/agent-runtime/compact/prompt-inputs.js +1 -2
- package/dist/agent-runtime/compact/reviewer.d.ts +0 -13
- package/dist/agent-runtime/compact/reviewer.js +5 -6
- package/dist/agent-runtime/compact/step.d.ts +0 -1
- package/dist/agent-runtime/compact/step.js +1 -2
- package/dist/agent-runtime/compact/test-reachability.js +6 -3
- package/dist/agent-runtime/config.js +0 -1
- package/dist/agent-runtime/core-host.d.ts +2 -2
- package/dist/agent-runtime/core-host.js +2 -3
- package/dist/agent-runtime/durable-store.d.ts +0 -1
- package/dist/agent-runtime/durable-store.js +1 -2
- package/dist/agent-runtime/efficiency-summary.d.ts +2 -2
- package/dist/agent-runtime/efficiency-summary.js +1 -2
- package/dist/agent-runtime/efficiency-types.js +0 -1
- package/dist/agent-runtime/efficiency.js +0 -1
- package/dist/agent-runtime/evaluation-corpus.js +0 -1
- package/dist/agent-runtime/evaluation.d.ts +2 -1
- package/dist/agent-runtime/evaluation.js +1 -2
- package/dist/agent-runtime/executor-types.d.ts +1 -1
- package/dist/agent-runtime/executor-types.js +0 -1
- package/dist/agent-runtime/executors.js +0 -1
- package/dist/agent-runtime/gemini-policy.js +0 -1
- package/dist/agent-runtime/graph/artifacts.d.ts +1 -1
- package/dist/agent-runtime/graph/artifacts.js +5 -3
- package/dist/agent-runtime/graph/convergence.d.ts +26 -0
- package/dist/agent-runtime/graph/convergence.js +62 -0
- package/dist/agent-runtime/graph/nodes.d.ts +1 -1
- package/dist/agent-runtime/graph/nodes.js +170 -24
- package/dist/agent-runtime/graph/review-policy.js +0 -1
- package/dist/agent-runtime/graph/roles.d.ts +2 -5
- package/dist/agent-runtime/graph/roles.js +2 -8
- package/dist/agent-runtime/graph/state.d.ts +6 -1
- package/dist/agent-runtime/graph/state.js +2 -1
- package/dist/agent-runtime/graph-checkpointer.d.ts +2 -1
- package/dist/agent-runtime/graph-checkpointer.js +0 -1
- package/dist/agent-runtime/guardrails.d.ts +3 -3
- package/dist/agent-runtime/guardrails.js +1 -2
- package/dist/agent-runtime/index.d.ts +1 -1
- package/dist/agent-runtime/index.js +1 -2
- package/dist/agent-runtime/kimi-acp.js +1 -2
- package/dist/agent-runtime/kimi-model.d.ts +6 -0
- package/dist/agent-runtime/kimi-model.js +12 -0
- package/dist/agent-runtime/openai-executor.d.ts +0 -9
- package/dist/agent-runtime/openai-executor.js +6 -7
- package/dist/agent-runtime/openspec-tool-server.js +1 -2
- package/dist/agent-runtime/openspec.d.ts +0 -2
- package/dist/agent-runtime/openspec.js +1 -6
- package/dist/agent-runtime/prompts.d.ts +11 -5
- package/dist/agent-runtime/prompts.js +46 -17
- package/dist/agent-runtime/provider-diagnostic.js +1 -2
- package/dist/agent-runtime/recovery.js +1 -2
- package/dist/agent-runtime/repository-context.d.ts +1 -1
- package/dist/agent-runtime/repository-context.js +19 -1
- package/dist/agent-runtime/review-context.d.ts +1 -1
- package/dist/agent-runtime/review-context.js +0 -1
- package/dist/agent-runtime/role-routing.js +0 -1
- package/dist/agent-runtime/role-state.js +0 -1
- package/dist/agent-runtime/runtime-identity.js +1 -2
- package/dist/agent-runtime/tool-event.js +0 -1
- package/dist/agent-runtime/verification-plan.d.ts +5 -4
- package/dist/agent-runtime/verification-plan.js +9 -5
- package/dist/agent-runtime/workflow-types.js +0 -1
- package/dist/agent-runtime/workflow.js +0 -1
- package/dist/agent-runtime/workspace-tools.d.ts +2 -2
- package/dist/agent-runtime/workspace-tools.js +1 -2
- package/dist/installer/cli.d.ts +3 -32
- package/dist/installer/cli.js +26 -101
- package/dist/installer/commands/framework.d.ts +4 -3
- package/dist/installer/commands/framework.js +0 -1
- package/dist/installer/commands/init.d.ts +4 -25
- package/dist/installer/commands/init.js +5 -8
- package/dist/installer/phases/framework-lifecycle.d.ts +3 -17
- package/dist/installer/phases/framework-lifecycle.js +2 -3
- package/dist/installer/phases/install-config.d.ts +7 -8
- package/dist/installer/phases/install-config.js +2 -7
- package/dist/installer/phases/manifest.d.ts +6 -7
- package/dist/installer/phases/manifest.js +2 -7
- package/dist/installer/phases/prereqs.d.ts +6 -7
- package/dist/installer/phases/prereqs.js +4 -6
- package/dist/installer/phases/provider-detect.d.ts +6 -7
- package/dist/installer/phases/provider-detect.js +2 -4
- package/dist/installer/phases/scaffold.d.ts +9 -10
- package/dist/installer/phases/scaffold.js +82 -805
- package/dist/installer/util/errors.js +0 -1
- package/dist/installer/util/exec.d.ts +3 -2
- package/dist/installer/util/exec.js +0 -1
- package/dist/installer/util/fs.d.ts +0 -10
- package/dist/installer/util/fs.js +1 -2
- package/dist/installer/util/git.js +0 -1
- package/dist/installer/util/install-transaction.d.ts +2 -2
- package/dist/installer/util/install-transaction.js +1 -2
- package/dist/installer/util/logger.d.ts +1 -3
- package/dist/installer/util/logger.js +0 -1
- package/dist/installer/util/paths.js +0 -1
- package/dist/installer/util/registry.d.ts +4 -8
- package/dist/installer/util/registry.js +2 -3
- package/dist/{installer/runtime → pipeline}/pipeline-state.d.ts +11 -0
- package/dist/{installer/runtime → pipeline}/pipeline-state.js +56 -5
- package/dist/shared/args.d.ts +18 -0
- package/dist/shared/args.js +53 -0
- package/integration-contract.json +11 -47
- package/package.json +3 -10
- package/templates/agents/sr-architect.md +15 -310
- package/templates/agents/sr-developer.md +15 -269
- package/templates/agents/sr-reviewer.md +13 -367
- package/templates/codex-skills/rails/sr-architect/SKILL.md +14 -308
- package/templates/codex-skills/rails/sr-developer/SKILL.md +14 -201
- package/templates/codex-skills/rails/sr-reviewer/SKILL.md +15 -289
- package/templates/kimi/specrails/run-skill.mjs +91 -2173
- package/bin/tui-installer.mjs +0 -430
- package/commands/doctor.md +0 -62
- package/dist/agent-runtime/capabilities.js.map +0 -1
- package/dist/agent-runtime/cli-executor.js.map +0 -1
- package/dist/agent-runtime/cli-process.js.map +0 -1
- package/dist/agent-runtime/cli.js.map +0 -1
- package/dist/agent-runtime/codex-schema.js.map +0 -1
- package/dist/agent-runtime/compact/architect.js.map +0 -1
- package/dist/agent-runtime/compact/chat-client.js.map +0 -1
- package/dist/agent-runtime/compact/developer.js.map +0 -1
- package/dist/agent-runtime/compact/environment.js.map +0 -1
- package/dist/agent-runtime/compact/exit-code-honesty.js.map +0 -1
- package/dist/agent-runtime/compact/guarded-loop.js.map +0 -1
- package/dist/agent-runtime/compact/prompt-inputs.js.map +0 -1
- package/dist/agent-runtime/compact/reviewer.js.map +0 -1
- package/dist/agent-runtime/compact/step.js.map +0 -1
- package/dist/agent-runtime/compact/test-reachability.js.map +0 -1
- package/dist/agent-runtime/config.js.map +0 -1
- package/dist/agent-runtime/core-host.js.map +0 -1
- package/dist/agent-runtime/durable-store.js.map +0 -1
- package/dist/agent-runtime/efficiency-summary.js.map +0 -1
- package/dist/agent-runtime/efficiency-types.js.map +0 -1
- package/dist/agent-runtime/efficiency.js.map +0 -1
- package/dist/agent-runtime/evaluation-corpus.js.map +0 -1
- package/dist/agent-runtime/evaluation.js.map +0 -1
- package/dist/agent-runtime/executor-types.js.map +0 -1
- package/dist/agent-runtime/executors.js.map +0 -1
- package/dist/agent-runtime/gemini-policy.js.map +0 -1
- package/dist/agent-runtime/graph/artifacts.js.map +0 -1
- package/dist/agent-runtime/graph/nodes.js.map +0 -1
- package/dist/agent-runtime/graph/review-policy.js.map +0 -1
- package/dist/agent-runtime/graph/roles.js.map +0 -1
- package/dist/agent-runtime/graph/state.js.map +0 -1
- package/dist/agent-runtime/graph-checkpointer.js.map +0 -1
- package/dist/agent-runtime/guardrails.js.map +0 -1
- package/dist/agent-runtime/index.js.map +0 -1
- package/dist/agent-runtime/kimi-acp.js.map +0 -1
- package/dist/agent-runtime/openai-executor.js.map +0 -1
- package/dist/agent-runtime/openspec-tool-server.js.map +0 -1
- package/dist/agent-runtime/openspec.js.map +0 -1
- package/dist/agent-runtime/prompts.js.map +0 -1
- package/dist/agent-runtime/provider-diagnostic.js.map +0 -1
- package/dist/agent-runtime/recovery.js.map +0 -1
- package/dist/agent-runtime/repository-context.js.map +0 -1
- package/dist/agent-runtime/review-context.js.map +0 -1
- package/dist/agent-runtime/role-routing.js.map +0 -1
- package/dist/agent-runtime/role-state.js.map +0 -1
- package/dist/agent-runtime/runtime-identity.js.map +0 -1
- package/dist/agent-runtime/tool-event.js.map +0 -1
- package/dist/agent-runtime/verification-plan.js.map +0 -1
- package/dist/agent-runtime/workflow-types.js.map +0 -1
- package/dist/agent-runtime/workflow.js.map +0 -1
- package/dist/agent-runtime/workspace-tools.js.map +0 -1
- package/dist/installer/cli.js.map +0 -1
- package/dist/installer/commands/doctor.d.ts +0 -27
- package/dist/installer/commands/doctor.js +0 -615
- package/dist/installer/commands/doctor.js.map +0 -1
- package/dist/installer/commands/framework.js.map +0 -1
- package/dist/installer/commands/init.js.map +0 -1
- package/dist/installer/commands/update.d.ts +0 -56
- package/dist/installer/commands/update.js +0 -257
- package/dist/installer/commands/update.js.map +0 -1
- package/dist/installer/commands/v5-migration.d.ts +0 -32
- package/dist/installer/commands/v5-migration.js +0 -133
- package/dist/installer/commands/v5-migration.js.map +0 -1
- package/dist/installer/phases/framework-lifecycle.js.map +0 -1
- package/dist/installer/phases/install-config.js.map +0 -1
- package/dist/installer/phases/manifest.js.map +0 -1
- package/dist/installer/phases/prereqs.js.map +0 -1
- package/dist/installer/phases/provider-detect.js.map +0 -1
- package/dist/installer/phases/scaffold.js.map +0 -1
- package/dist/installer/runtime/kimi.d.ts +0 -84
- package/dist/installer/runtime/kimi.js +0 -255
- package/dist/installer/runtime/kimi.js.map +0 -1
- package/dist/installer/runtime/pipeline-state.js.map +0 -1
- package/dist/installer/util/errors.js.map +0 -1
- package/dist/installer/util/exec.js.map +0 -1
- package/dist/installer/util/fs.js.map +0 -1
- package/dist/installer/util/git.js.map +0 -1
- package/dist/installer/util/install-transaction.js.map +0 -1
- package/dist/installer/util/logger.js.map +0 -1
- package/dist/installer/util/paths.js.map +0 -1
- package/dist/installer/util/prompts.d.ts +0 -23
- package/dist/installer/util/prompts.js +0 -49
- package/dist/installer/util/prompts.js.map +0 -1
- package/dist/installer/util/registry.js.map +0 -1
- package/dist/installer/util/template.d.ts +0 -23
- package/dist/installer/util/template.js +0 -60
- package/dist/installer/util/template.js.map +0 -1
- package/docs/README.md +0 -40
- package/docs/agent-runtime-efficiency.md +0 -65
- package/docs/agent-runtime.md +0 -393
- package/docs/agents.md +0 -315
- package/docs/changelog.md +0 -168
- package/docs/ci-cd.md +0 -60
- package/docs/concepts.md +0 -183
- package/docs/customization.md +0 -363
- package/docs/deployment.md +0 -234
- package/docs/getting-started.md +0 -122
- package/docs/installation.md +0 -395
- package/docs/local-tickets.md +0 -191
- package/docs/migration-guide.md +0 -140
- package/docs/playbook-oss-maintainer.md +0 -112
- package/docs/playbook-parallel-dev.md +0 -124
- package/docs/playbook-product-discovery.md +0 -115
- package/docs/plugin-architecture.md +0 -144
- package/docs/research/codex-compatibility-analysis.md +0 -365
- package/docs/research/mcp-feasibility-analysis.md +0 -382
- package/docs/testing/test-matrix-codex.md +0 -130
- package/docs/updating.md +0 -89
- package/docs/user-docs/cli-reference.md +0 -428
- package/docs/user-docs/codex-vs-claude-code.md +0 -23
- package/docs/user-docs/core-updates.md +0 -70
- package/docs/user-docs/faq.md +0 -146
- package/docs/user-docs/getting-started-codex.md +0 -194
- package/docs/user-docs/getting-started-kimi.md +0 -423
- package/docs/user-docs/installation.md +0 -237
- package/docs/user-docs/provider-pipelines.md +0 -96
- package/docs/user-docs/quick-start.md +0 -161
- package/docs/windows.md +0 -78
- package/docs/workflows.md +0 -463
- package/schemas/profile.v1.json +0 -207
- package/templates/claude-md/CLAUDE-quickstart.md +0 -54
- package/templates/claude-md/root.md +0 -50
- package/templates/codex-skills/batch-implement/SKILL.md +0 -38
- package/templates/codex-skills/implement/SKILL.md +0 -38
- package/templates/codex-skills/retry/SKILL.md +0 -16
- package/templates/commands/specrails/compat-check.md +0 -271
- package/templates/commands/specrails/doctor.md +0 -62
- package/templates/commands/specrails/explore-spec.md +0 -173
- package/templates/commands/specrails/health-check.md +0 -527
- package/templates/commands/specrails/memory-inspect.md +0 -261
- package/templates/commands/specrails/opsx-diff.md +0 -419
- package/templates/commands/specrails/propose-spec.md +0 -102
- package/templates/commands/specrails/refactor-recommender.md +0 -169
- package/templates/commands/specrails/telemetry.md +0 -553
- package/templates/commands/specrails/why.md +0 -96
- package/templates/gemini-commands/batch-implement.toml +0 -37
- package/templates/gemini-commands/implement.toml +0 -37
- package/templates/gemini-commands/retry.toml +0 -15
- package/templates/profiles/default.json +0 -14
- package/templates/profiles/kimi-default.json +0 -15
- package/templates/rules/layer.md +0 -8
- package/templates/runtime/provider-pipeline.md +0 -113
- package/templates/security/security-exemptions.yaml +0 -20
- package/templates/settings/confidence-config.json +0 -17
- package/templates/settings/settings.json +0 -15
package/bin/specrails-core.mjs
CHANGED
|
@@ -1,561 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
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
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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)
|
|
@@ -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 {};
|