specrails-core 5.6.0 → 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.
- package/README.md +27 -145
- package/bin/specrails-core.mjs +12 -554
- package/dist/agent-runtime/capabilities.js +0 -1
- 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 +3 -4
- 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 +4 -5
- package/dist/agent-runtime/compact/environment.js +1 -2
- 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 +0 -1
- package/dist/agent-runtime/config.js +0 -1
- package/dist/agent-runtime/core-host.d.ts +1 -1
- package/dist/agent-runtime/core-host.js +1 -2
- 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 +1 -2
- package/dist/agent-runtime/graph/nodes.d.ts +1 -1
- package/dist/agent-runtime/graph/nodes.js +1 -2
- 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 +1 -1
- package/dist/agent-runtime/graph/state.js +0 -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 +4 -3
- package/dist/agent-runtime/prompts.js +0 -1
- 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 +0 -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 +1 -2
- 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.js +0 -3
- package/dist/shared/args.d.ts +18 -0
- package/dist/shared/args.js +53 -0
- package/integration-contract.json +10 -46
- 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/dist/{installer/runtime → pipeline}/pipeline-state.d.ts +0 -0
|
@@ -149,31 +149,13 @@ export function geminiAgentLimitMetadata(env = process.env) {
|
|
|
149
149
|
const SKILL_FROM_COMMAND = {
|
|
150
150
|
'sr-implement': {
|
|
151
151
|
command: 'implement',
|
|
152
|
-
description: 'sr:implement — Full OpenSpec lifecycle with specialized agents: architect designs, developer implements, reviewer validates. Use for implementing
|
|
152
|
+
description: 'sr:implement — Full OpenSpec lifecycle with specialized agents: architect designs, developer implements, reviewer validates. Use for implementing frozen specs or feature descriptions.',
|
|
153
153
|
},
|
|
154
154
|
'sr-batch-implement': {
|
|
155
155
|
command: 'batch-implement',
|
|
156
156
|
description: 'sr:batch-implement — Run multiple frozen specs as one programmatic agent workflow.',
|
|
157
157
|
},
|
|
158
|
-
'sr-compat-check': {
|
|
159
|
-
command: 'compat-check',
|
|
160
|
-
description: 'sr:compat-check — Snapshot the API surface and detect breaking changes against a prior baseline. Generates a migration guide when breaking changes are found.',
|
|
161
|
-
},
|
|
162
|
-
'sr-refactor-recommender': {
|
|
163
|
-
command: 'refactor-recommender',
|
|
164
|
-
description: 'sr:refactor-recommender — Scan the codebase for refactoring opportunities ranked by impact/effort ratio. Optionally creates GitHub Issues for tracking.',
|
|
165
|
-
},
|
|
166
|
-
'sr-why': {
|
|
167
|
-
command: 'why',
|
|
168
|
-
description: 'sr:why — Search explanation records written by specrails agents during the OpenSpec implementation pipeline.',
|
|
169
|
-
},
|
|
170
158
|
};
|
|
171
|
-
/**
|
|
172
|
-
* Agents that write "explanation" memory records. When any of them
|
|
173
|
-
* ships we also need a shared `.claude/agent-memory/explanations/`
|
|
174
|
-
* directory alongside the per-agent memory dirs.
|
|
175
|
-
*/
|
|
176
|
-
const EXPLANATION_AUTHORS = new Set(['sr-architect', 'sr-reviewer']);
|
|
177
159
|
/**
|
|
178
160
|
* Provider-static subtrees inside a providerDir that are SHARED via symlink from
|
|
179
161
|
* the framework copy into each workspace. `agent-memory/` is deliberately absent
|
|
@@ -185,14 +167,14 @@ const EXPLANATION_AUTHORS = new Set(['sr-architect', 'sr-reviewer']);
|
|
|
185
167
|
* `assembleProjectWorkspace`.
|
|
186
168
|
*/
|
|
187
169
|
const LINKED_PROVIDER_SUBTREES = {
|
|
188
|
-
claude: ['agents', 'commands', 'skills'
|
|
170
|
+
claude: ['agents', 'commands', 'skills'],
|
|
189
171
|
codex: ['skills'],
|
|
190
172
|
gemini: ['agents', 'commands'],
|
|
191
173
|
// Kimi skills are linked one directory at a time so direct-child OpenSpec
|
|
192
174
|
// skills and user-owned custom-* roles can coexist. The self-contained
|
|
193
175
|
// headless runner and its vendored parser are Core-owned and linked as a
|
|
194
176
|
// separate static subtree.
|
|
195
|
-
kimi: ['
|
|
177
|
+
kimi: ['specrails'],
|
|
196
178
|
};
|
|
197
179
|
const KIMI_RUNNER_RELATIVE_FILES = [
|
|
198
180
|
'run-skill.mjs',
|
|
@@ -202,9 +184,7 @@ const KIMI_RUNNER_RELATIVE_FILES = [
|
|
|
202
184
|
];
|
|
203
185
|
/**
|
|
204
186
|
* Returns true iff any of the provider directories already contains
|
|
205
|
-
* content.
|
|
206
|
-
* assumes `--yes`; the CLI dispatcher (bin/specrails-core.cjs) should
|
|
207
|
-
* have prompted before entering this phase.
|
|
187
|
+
* content.
|
|
208
188
|
*/
|
|
209
189
|
export function detectExistingSetup(input) {
|
|
210
190
|
const roots = [
|
|
@@ -238,7 +218,6 @@ export function scaffoldInstallation(input) {
|
|
|
238
218
|
// Codex skills live under <providerDir>/skills/ (e.g. .codex/skills/).
|
|
239
219
|
// The pre-§18 code wrote to `.agents/skills/` which codex doesn't read;
|
|
240
220
|
// that was a placeholder name from the gated state.
|
|
241
|
-
mk(path.join(input.artifactRoot, input.providerDir, 'skills', 'doctor'));
|
|
242
221
|
mk(path.join(input.artifactRoot, input.providerDir, 'skills', 'rails'));
|
|
243
222
|
}
|
|
244
223
|
else if (input.provider === 'gemini') {
|
|
@@ -251,7 +230,6 @@ export function scaffoldInstallation(input) {
|
|
|
251
230
|
else if (input.provider === 'kimi') {
|
|
252
231
|
mk(path.join(input.artifactRoot, input.providerDir, 'skills'));
|
|
253
232
|
mk(path.join(input.artifactRoot, input.providerDir, 'specrails'));
|
|
254
|
-
mk(path.join(input.artifactRoot, input.providerDir, 'rules'));
|
|
255
233
|
}
|
|
256
234
|
else {
|
|
257
235
|
mk(path.join(input.artifactRoot, input.providerDir, 'commands', 'specrails'));
|
|
@@ -261,8 +239,6 @@ export function scaffoldInstallation(input) {
|
|
|
261
239
|
mk(path.join(setupTemplates, 'agents'));
|
|
262
240
|
mk(path.join(setupTemplates, 'commands'));
|
|
263
241
|
mk(path.join(setupTemplates, 'skills'));
|
|
264
|
-
mk(path.join(setupTemplates, 'rules'));
|
|
265
|
-
mk(path.join(setupTemplates, 'claude-md'));
|
|
266
242
|
mk(path.join(setupTemplates, 'settings'));
|
|
267
243
|
// --- .gitignore hygiene ---
|
|
268
244
|
// Under relocate-always (artifactRoot !== codeRoot) NOTHING Specrails-owned
|
|
@@ -274,7 +250,7 @@ export function scaffoldInstallation(input) {
|
|
|
274
250
|
if (input.provider === 'gemini')
|
|
275
251
|
gitignoreEntries.push('.gemini/agent-memory/');
|
|
276
252
|
if (input.provider === 'kimi') {
|
|
277
|
-
gitignoreEntries.push('.kimi-code/agent-memory/'
|
|
253
|
+
gitignoreEntries.push('.kimi-code/agent-memory/');
|
|
278
254
|
}
|
|
279
255
|
ensureGitignore(input.codeRoot, gitignoreEntries);
|
|
280
256
|
}
|
|
@@ -297,8 +273,6 @@ export function scaffoldInstallation(input) {
|
|
|
297
273
|
else {
|
|
298
274
|
warn(`templates/ not found at ${templatesSrc} — skipping template copy`);
|
|
299
275
|
}
|
|
300
|
-
// --- Write bundled commands (doctor.md) ---
|
|
301
|
-
copyBundledCommands({ ...input, copiedIncrement: (n) => (copiedFiles += n) });
|
|
302
276
|
pruneLegacyArtifacts(input);
|
|
303
277
|
copiedFiles += placePipelineRuntime(input);
|
|
304
278
|
if (input.provider === 'kimi') {
|
|
@@ -307,9 +281,8 @@ export function scaffoldInstallation(input) {
|
|
|
307
281
|
// --- Direct placement (the only path) ---
|
|
308
282
|
{
|
|
309
283
|
const placed = placeArtefacts({ ...input });
|
|
310
|
-
copiedFiles += placed.agents + placed.commands
|
|
311
|
-
info(`Placed ${placed.agents} agent(s) + ${placed.commands} command(s)
|
|
312
|
-
`${placed.rules} rule file(s) directly into ${input.providerDir}/`);
|
|
284
|
+
copiedFiles += placed.agents + placed.commands;
|
|
285
|
+
info(`Placed ${placed.agents} agent(s) + ${placed.commands} command(s) directly into ${input.providerDir}/`);
|
|
313
286
|
}
|
|
314
287
|
// --- Skills placement (both tiers, both providers) ---
|
|
315
288
|
// Claude: top-level `sr-*` skills are generated from their canonical
|
|
@@ -407,8 +380,7 @@ function hashFrameworkTrees(roots, options = {}) {
|
|
|
407
380
|
function frameworkSourceHash(scriptDir, provider) {
|
|
408
381
|
const treeHash = hashFrameworkTrees([
|
|
409
382
|
{ label: 'templates', dir: path.join(scriptDir, 'templates') },
|
|
410
|
-
{ label: '
|
|
411
|
-
{ label: 'pipeline-runtime', dir: path.join(scriptDir, 'dist', 'installer', 'runtime') },
|
|
383
|
+
{ label: 'pipeline-runtime', dir: path.join(scriptDir, 'dist', 'pipeline') },
|
|
412
384
|
{ label: 'installer-renderers', dir: path.join(scriptDir, 'dist', 'installer', 'phases') },
|
|
413
385
|
], { ignorePackageNoise: true });
|
|
414
386
|
return `sha256:${createHash('sha256')
|
|
@@ -636,6 +608,10 @@ export function assembleProjectWorkspace(input) {
|
|
|
636
608
|
links[sub] = symlinkOrCopy(target, dest, preferCopy);
|
|
637
609
|
}
|
|
638
610
|
}
|
|
611
|
+
// Core no longer ships `rules/`; drop the dangling link an older version left.
|
|
612
|
+
const retiredRules = path.join(workspaceProviderDir, 'rules');
|
|
613
|
+
if (isSymlink(retiredRules) && !pathExists(path.join(currentProviderDir, 'rules')))
|
|
614
|
+
removePath(retiredRules);
|
|
639
615
|
if (input.provider === 'kimi') {
|
|
640
616
|
const kimiSkillsTarget = path.join(currentProviderDir, 'skills');
|
|
641
617
|
const kimiSkillsDest = path.join(workspaceProviderDir, 'skills');
|
|
@@ -706,9 +682,6 @@ function seedProjectLayer(input, currentProviderDir) {
|
|
|
706
682
|
for (const id of placedAgentIds) {
|
|
707
683
|
mkdirp(path.join(input.workspace, '.claude', 'agent-memory', id));
|
|
708
684
|
seededMemoryAgents.push(id);
|
|
709
|
-
if (EXPLANATION_AUTHORS.has(id)) {
|
|
710
|
-
mkdirp(path.join(input.workspace, '.claude', 'agent-memory', 'explanations'));
|
|
711
|
-
}
|
|
712
685
|
}
|
|
713
686
|
}
|
|
714
687
|
else if (input.provider === 'gemini') {
|
|
@@ -751,20 +724,11 @@ function seedProjectLayer(input, currentProviderDir) {
|
|
|
751
724
|
for (const id of placedAgentIds) {
|
|
752
725
|
mkdirp(path.join(input.workspace, '.kimi-code', 'agent-memory', id));
|
|
753
726
|
seededMemoryAgents.push(id);
|
|
754
|
-
if (EXPLANATION_AUTHORS.has(id)) {
|
|
755
|
-
mkdirp(path.join(input.workspace, '.kimi-code', 'agent-memory', 'explanations'));
|
|
756
|
-
}
|
|
757
727
|
}
|
|
758
728
|
seedInstructionFile(path.join(input.workspace, '.kimi-code', 'AGENTS.md'), renderInitialKimiAgentsMd(input.codeRoot));
|
|
759
729
|
seedKimiMcpFile(path.join(input.workspace, '.kimi-code', 'mcp.json'));
|
|
760
730
|
if (input.workspace === input.codeRoot) {
|
|
761
|
-
ensureGitignore(input.codeRoot, [
|
|
762
|
-
'.kimi-code/agent-memory/',
|
|
763
|
-
'.kimi-code/pipeline-state/',
|
|
764
|
-
'.kimi-code/.dry-run/',
|
|
765
|
-
'.kimi-code/telemetry/',
|
|
766
|
-
'.specrails/',
|
|
767
|
-
]);
|
|
731
|
+
ensureGitignore(input.codeRoot, ['.kimi-code/agent-memory/', '.specrails/']);
|
|
768
732
|
}
|
|
769
733
|
}
|
|
770
734
|
return seededMemoryAgents;
|
|
@@ -980,84 +944,6 @@ function seedInstructionFile(filePath, content) {
|
|
|
980
944
|
if (next !== existing)
|
|
981
945
|
writeFileLf(filePath, next);
|
|
982
946
|
}
|
|
983
|
-
function copyBundledCommands(input) {
|
|
984
|
-
const commandsSrc = path.join(input.scriptDir, 'commands');
|
|
985
|
-
if (!isDir(commandsSrc))
|
|
986
|
-
return;
|
|
987
|
-
// Kimi's complete workflow catalog is rendered from the canonical
|
|
988
|
-
// templates/commands/specrails sources in placeKimiSkills. Do not let this
|
|
989
|
-
// generic bundled-command pass fall through to Claude's file layout.
|
|
990
|
-
if (input.provider === 'kimi')
|
|
991
|
-
return;
|
|
992
|
-
if (input.provider === 'codex') {
|
|
993
|
-
// Codex: each bundled command ships as a SKILL under
|
|
994
|
-
// `.codex/skills/<name>/SKILL.md`. A codex-native override (spawn_agent
|
|
995
|
-
// semantics + correct `.codex/skills/rails/` layout) wins; otherwise the
|
|
996
|
-
// claude body is ported with frontmatter re-emitted in codex shape.
|
|
997
|
-
let count = 0;
|
|
998
|
-
const codexOverrides = path.join(input.scriptDir, 'templates', 'codex-skills');
|
|
999
|
-
for (const entry of listDir(commandsSrc)) {
|
|
1000
|
-
const name = path.basename(entry);
|
|
1001
|
-
if (!name.endsWith('.md'))
|
|
1002
|
-
continue;
|
|
1003
|
-
if (name === 'setup.md')
|
|
1004
|
-
continue;
|
|
1005
|
-
const skillName = name.replace(/\.md$/, '');
|
|
1006
|
-
const destDir = path.join(input.artifactRoot, input.providerDir, 'skills', skillName);
|
|
1007
|
-
// A codex-native override (written for spawn_agent semantics + the
|
|
1008
|
-
// correct `.codex/skills/rails/` layout) wins over the claude port.
|
|
1009
|
-
// This is the ONLY codex command-placement pass, so without the override
|
|
1010
|
-
// check codex users get the claude body with no codex-native semantics.
|
|
1011
|
-
const overrideSkill = path.join(codexOverrides, skillName, 'SKILL.md');
|
|
1012
|
-
if (pathExists(overrideSkill)) {
|
|
1013
|
-
copyDir(path.join(codexOverrides, skillName), destDir);
|
|
1014
|
-
}
|
|
1015
|
-
else {
|
|
1016
|
-
writeCodexSkillFromCommand({
|
|
1017
|
-
src: entry,
|
|
1018
|
-
dest: path.join(destDir, 'SKILL.md'),
|
|
1019
|
-
name: skillName,
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
count++;
|
|
1023
|
-
}
|
|
1024
|
-
input.copiedIncrement(count);
|
|
1025
|
-
return;
|
|
1026
|
-
}
|
|
1027
|
-
if (input.provider === 'gemini') {
|
|
1028
|
-
// Gemini: each bundled command becomes a TOML custom command under
|
|
1029
|
-
// .gemini/commands/specrails/<name>.toml.
|
|
1030
|
-
const destDir = path.join(input.artifactRoot, input.providerDir, 'commands', 'specrails');
|
|
1031
|
-
let count = 0;
|
|
1032
|
-
for (const entry of listDir(commandsSrc)) {
|
|
1033
|
-
const name = path.basename(entry);
|
|
1034
|
-
if (!name.endsWith('.md'))
|
|
1035
|
-
continue;
|
|
1036
|
-
if (name === 'setup.md')
|
|
1037
|
-
continue;
|
|
1038
|
-
writeGeminiCommandFromCommand({
|
|
1039
|
-
src: entry,
|
|
1040
|
-
dest: path.join(destDir, `${name.replace(/\.md$/, '')}.toml`),
|
|
1041
|
-
});
|
|
1042
|
-
count++;
|
|
1043
|
-
}
|
|
1044
|
-
input.copiedIncrement(count);
|
|
1045
|
-
return;
|
|
1046
|
-
}
|
|
1047
|
-
// Claude: all bundled commands land under <providerDir>/commands/specrails/.
|
|
1048
|
-
const destDir = path.join(input.artifactRoot, input.providerDir, 'commands', 'specrails');
|
|
1049
|
-
let count = 0;
|
|
1050
|
-
for (const entry of listDir(commandsSrc)) {
|
|
1051
|
-
const name = path.basename(entry);
|
|
1052
|
-
if (!name.endsWith('.md'))
|
|
1053
|
-
continue;
|
|
1054
|
-
if (name === 'setup.md')
|
|
1055
|
-
continue;
|
|
1056
|
-
copyFile(entry, path.join(destDir, name));
|
|
1057
|
-
count++;
|
|
1058
|
-
}
|
|
1059
|
-
input.copiedIncrement(count);
|
|
1060
|
-
}
|
|
1061
947
|
/**
|
|
1062
948
|
* Convert a claude slash-command markdown file into a codex SKILL.md.
|
|
1063
949
|
*
|
|
@@ -1142,458 +1028,35 @@ function writeClaudeSkillFromCommand(args) {
|
|
|
1142
1028
|
].join('\n');
|
|
1143
1029
|
writeFileLf(args.dest, frontmatter + body);
|
|
1144
1030
|
}
|
|
1145
|
-
const KIMI_ROLE_EXECUTION_CONTRACT = [
|
|
1146
|
-
'## Kimi role execution contract',
|
|
1147
|
-
'',
|
|
1148
|
-
'These rules override later Claude-specific `role_skill`, `isolation`, and',
|
|
1149
|
-
'`run_in_background` notation. When this workflow asks for one role or a',
|
|
1150
|
-
'parallel group, submit exactly one foreground role wave. The managed helper',
|
|
1151
|
-
'starts one external Kimi CLI per role, runs the wave concurrently, attributes',
|
|
1152
|
-
'every output event, and waits for every required role. Never emulate a role',
|
|
1153
|
-
'in the orchestrator and never start concurrent helper commands.',
|
|
1154
|
-
'',
|
|
1155
|
-
'First use the structured WriteFile tool (never Shell, a heredoc, `printf`,',
|
|
1156
|
-
'or `echo`) to write `.specrails/kimi-role-wave.json`. Choose one lowercase',
|
|
1157
|
-
'letters/digits/hyphens run id (1–64 characters) and reuse it for the whole',
|
|
1158
|
-
'workflow. The file must have exactly this shape (1–32 roles):',
|
|
1159
|
-
'',
|
|
1160
|
-
'```json',
|
|
1161
|
-
'{',
|
|
1162
|
-
' "run": "<stable-run-id>",',
|
|
1163
|
-
' "roles": [',
|
|
1164
|
-
' {',
|
|
1165
|
-
' "key": "<unique-role-call-id>",',
|
|
1166
|
-
' "skill": "<role-skill>",',
|
|
1167
|
-
' "model": "<exact profile model or k3>",',
|
|
1168
|
-
' "profile": "inherit",',
|
|
1169
|
-
' "args": "<complete role context>",',
|
|
1170
|
-
' "workspace": "current"',
|
|
1171
|
-
' }',
|
|
1172
|
-
' ]',
|
|
1173
|
-
'}',
|
|
1174
|
-
'```',
|
|
1175
|
-
'',
|
|
1176
|
-
'Every `key`, profile stem, and worktree id uses the same 1–64 character grammar as `run`.',
|
|
1177
|
-
'Use `"current"` for roles that target the orchestrator repository. The',
|
|
1178
|
-
'helper gives each such role a private execution directory while setting its',
|
|
1179
|
-
'`SPECRAILS_REPO_DIR` to that repository. The child preserves the absolute',
|
|
1180
|
-
'`SPECRAILS_EXECUTION_CONTEXT`, `SPECRAILS_BACKLOG_PATH` and pipeline helper.',
|
|
1181
|
-
'Read the frozen specs there; never infer task scope from the child cwd. Nested calls do not',
|
|
1182
|
-
'collide. Where later instructions request `isolation: worktree`, use',
|
|
1183
|
-
'`"worktree:<feature-id>"`; reuse that exact value for the developer, test,',
|
|
1184
|
-
'documentation, and other sequential roles belonging to the same feature.',
|
|
1185
|
-
'Never put two roles for the same worktree in one wave.',
|
|
1186
|
-
'',
|
|
1187
|
-
'Resolve each role model in the orchestrator and encode all context as JSON;',
|
|
1188
|
-
'set `profile` to `inherit`, or to a validated profile filename stem for a',
|
|
1189
|
-
'per-rail override under `.specrails/profiles/<stem>.json`. The helper passes',
|
|
1190
|
-
'that absolute profile path only to that child process.',
|
|
1191
|
-
'do not place any model or context text in a shell command. Then run this',
|
|
1192
|
-
'exact static command in the foreground:',
|
|
1193
|
-
'',
|
|
1194
|
-
'```sh',
|
|
1195
|
-
'node .kimi-code/specrails/run-skill.mjs \\',
|
|
1196
|
-
' --role-wave-file .specrails/kimi-role-wave.json \\',
|
|
1197
|
-
' --add-dir "${SPECRAILS_REPO_DIR:-.}"',
|
|
1198
|
-
'```',
|
|
1199
|
-
'',
|
|
1200
|
-
'The helper accepts only that fixed, regular, non-symlink one-shot file,',
|
|
1201
|
-
'bounds it to 1 MiB, validates the exact schema and every identifier, and',
|
|
1202
|
-
'deletes it before creating a worktree or process. For an isolated role it',
|
|
1203
|
-
'creates or reuses a detached git worktree from a synthetic baseline commit',
|
|
1204
|
-
'that snapshots the starting tracked and non-ignored untracked workspace,',
|
|
1205
|
-
'exposes the',
|
|
1206
|
-
'managed `.kimi-code`, and sets the child repository root to that worktree.',
|
|
1207
|
-
'It persists the base commit and key/path mapping under',
|
|
1208
|
-
'`.specrails/kimi-role-worktrees/<run>.json` and emits',
|
|
1209
|
-
'`specrails.role.workspace` frames. Replace every later',
|
|
1210
|
-
'`<worktree-path>` placeholder with that emitted `repoDir`; compare against',
|
|
1211
|
-
'the manifest `baseCommit`, not a hard-coded `main` ref.',
|
|
1212
|
-
'',
|
|
1213
|
-
'The helper frames child stdout/stderr with its role key, emits one completion',
|
|
1214
|
-
'frame per role, and exits nonzero after the whole wave if any role failed.',
|
|
1215
|
-
'A termination signal is forwarded to every live child. Partial failures',
|
|
1216
|
-
'leave completed worktrees and the manifest available for retry; newly',
|
|
1217
|
-
'created partial worktrees are removed only when setup itself fails. Apply',
|
|
1218
|
-
'the workflow cleanup step after merge using the exact static command',
|
|
1219
|
-
'`node .kimi-code/specrails/run-skill.mjs --role-wave-cleanup <run>`.',
|
|
1220
|
-
'Cleanup removes registered worktrees, execution state, the manifest, and',
|
|
1221
|
-
'the private synthetic-baseline ref; never clean up a failed run before retry.',
|
|
1222
|
-
'The helper normalizes only the three',
|
|
1223
|
-
'official short model ids (`k3` launches as `kimi-code/k3`); safe custom',
|
|
1224
|
-
'aliases pass through unchanged.',
|
|
1225
|
-
'There is no SpecRails-owned Kimi server or bundled Kimi binary.',
|
|
1226
|
-
'',
|
|
1227
|
-
].join('\n');
|
|
1228
|
-
const KIMI_NESTED_SKILL_CONTRACT = [
|
|
1229
|
-
'## Kimi nested skill activation',
|
|
1230
|
-
'',
|
|
1231
|
-
'When these instructions show `Skill(skill="<id>", args="<raw args>")`, call',
|
|
1232
|
-
'Kimi\'s built-in `Skill` tool with those `skill` and `args` fields. Do not',
|
|
1233
|
-
'print the notation as prose and do not send an interactive slash command as',
|
|
1234
|
-
'model text. This native tool path preserves Kimi\'s nested-skill behavior and',
|
|
1235
|
-
'skill activation telemetry.',
|
|
1236
|
-
'',
|
|
1237
|
-
].join('\n');
|
|
1238
|
-
const KIMI_RUNTIME_CONTEXT_CONTRACT = [
|
|
1239
|
-
'## Kimi runtime context contract',
|
|
1240
|
-
'',
|
|
1241
|
-
'SpecRails deliberately resolves project-specific context at activation time;',
|
|
1242
|
-
'the Kimi enrich workflow does not rewrite framework-owned role or workflow',
|
|
1243
|
-
'SKILL.md files. Resolve every `KIMI_RUNTIME_*`, `KIMI_BACKLOG_*`, and',
|
|
1244
|
-
'`KIMI_PR_CREATE` marker below before acting. These are semantic markers,',
|
|
1245
|
-
'never executable command names; do not pass them to Shell.',
|
|
1246
|
-
'',
|
|
1247
|
-
'Use `${SPECRAILS_REPO_DIR}` when set as the code repository, otherwise the',
|
|
1248
|
-
'current repository. Read `.kimi-code/project-context.md` for stack, layers,',
|
|
1249
|
-
'CI commands, conventions, warnings, architecture, and important paths; when',
|
|
1250
|
-
'a field is absent, inspect package/build/CI files and report the inferred',
|
|
1251
|
-
'value explicitly. Scan `.kimi-code/personas/*.md` at runtime and read only',
|
|
1252
|
-
'regular non-symlink files; derive persona names, roles, score columns, and',
|
|
1253
|
-
'VPC sections from that live inventory. An empty inventory means “no personas',
|
|
1254
|
-
'configured”, never fabricated rows or scores.',
|
|
1255
|
-
'',
|
|
1256
|
-
'For every `KIMI_BACKLOG_*` marker, first read and validate',
|
|
1257
|
-
'`${SPECRAILS_BACKLOG_ROOT}/.specrails/backlog-config.json` when configured.',
|
|
1258
|
-
'The frozen execution context takes priority. Route `local` through',
|
|
1259
|
-
'`${SPECRAILS_BACKLOG_PATH}` only when ownership allows writes; route `github` through the',
|
|
1260
|
-
'approved `gh issue` operation; route `jira` only through the configured',
|
|
1261
|
-
'project/base URL and credentials. Honour read-only mode and never perform a',
|
|
1262
|
-
'write operation when configuration is missing, invalid, or read-only.',
|
|
1263
|
-
'Arguments shown after a marker describe the operation; they are not shell',
|
|
1264
|
-
'argv. Resolve `KIMI_PR_CREATE` with the repository’s configured PR workflow',
|
|
1265
|
-
'and ask before publishing when the active workflow requires confirmation.',
|
|
1266
|
-
'',
|
|
1267
|
-
].join('\n');
|
|
1268
|
-
const KIMI_RUNTIME_PLACEHOLDERS = {
|
|
1269
|
-
ARCHITECTURE_DIAGRAM: 'KIMI_RUNTIME_ARCHITECTURE_DIAGRAM',
|
|
1270
|
-
AREA_TABLE: 'KIMI_RUNTIME_AREA_TABLE',
|
|
1271
|
-
BACKEND_ARCHITECTURE_DIAGRAM: 'KIMI_RUNTIME_BACKEND_ARCHITECTURE_DIAGRAM',
|
|
1272
|
-
BACKEND_CRITICAL_RULES: 'KIMI_RUNTIME_BACKEND_CRITICAL_RULES',
|
|
1273
|
-
BACKEND_EXPERTISE: 'KIMI_RUNTIME_BACKEND_EXPERTISE',
|
|
1274
|
-
BACKEND_LAYER_CONVENTIONS: 'KIMI_RUNTIME_BACKEND_LAYER_CONVENTIONS',
|
|
1275
|
-
BACKEND_STACK: 'KIMI_RUNTIME_BACKEND_STACK',
|
|
1276
|
-
BACKEND_TECH_LIST: 'KIMI_RUNTIME_BACKEND_TECH_LIST',
|
|
1277
|
-
BACKLOG_COMMENT_CMD: 'KIMI_BACKLOG_COMMENT',
|
|
1278
|
-
BACKLOG_CREATE_CMD: 'KIMI_BACKLOG_CREATE',
|
|
1279
|
-
BACKLOG_DELETE_CMD: 'KIMI_BACKLOG_DELETE',
|
|
1280
|
-
BACKLOG_FETCH_ALL_CMD: 'KIMI_BACKLOG_FETCH_ALL',
|
|
1281
|
-
BACKLOG_FETCH_CLOSED_CMD: 'KIMI_BACKLOG_FETCH_CLOSED',
|
|
1282
|
-
BACKLOG_FETCH_CMD: 'KIMI_BACKLOG_FETCH',
|
|
1283
|
-
BACKLOG_INIT_LABELS_CMD: 'KIMI_BACKLOG_INIT_LABELS',
|
|
1284
|
-
BACKLOG_PARTIAL_COMMENT_CMD: 'KIMI_BACKLOG_PARTIAL_COMMENT',
|
|
1285
|
-
BACKLOG_PREFLIGHT: 'KIMI_BACKLOG_PREFLIGHT',
|
|
1286
|
-
BACKLOG_PROVIDER_NAME: 'KIMI_RUNTIME_BACKLOG_PROVIDER_NAME',
|
|
1287
|
-
BACKLOG_UPDATE_CMD: 'KIMI_BACKLOG_UPDATE',
|
|
1288
|
-
BACKLOG_VIEW_CMD: 'KIMI_BACKLOG_VIEW',
|
|
1289
|
-
CI_CHECK_TABLE_ROWS: 'KIMI_RUNTIME_CI_CHECK_TABLE_ROWS',
|
|
1290
|
-
CI_COMMANDS: 'KIMI_RUNTIME_CI_COMMANDS',
|
|
1291
|
-
CI_COMMANDS_BACKEND: 'KIMI_RUNTIME_CI_COMMANDS_BACKEND',
|
|
1292
|
-
CI_COMMANDS_FRONTEND: 'KIMI_RUNTIME_CI_COMMANDS_FRONTEND',
|
|
1293
|
-
CI_COMMANDS_FULL: 'KIMI_RUNTIME_CI_COMMANDS_FULL',
|
|
1294
|
-
CI_COMMON_PITFALLS: 'KIMI_RUNTIME_CI_COMMON_PITFALLS',
|
|
1295
|
-
CI_CRITICAL_WARNINGS: 'KIMI_RUNTIME_CI_CRITICAL_WARNINGS',
|
|
1296
|
-
CI_KNOWN_GAPS: 'KIMI_RUNTIME_CI_KNOWN_GAPS',
|
|
1297
|
-
CODE_QUALITY_CHECKLIST: 'KIMI_RUNTIME_CODE_QUALITY_CHECKLIST',
|
|
1298
|
-
CODE_QUALITY_STANDARDS: 'KIMI_RUNTIME_CODE_QUALITY_STANDARDS',
|
|
1299
|
-
COMPETITIVE_LANDSCAPE: 'KIMI_RUNTIME_COMPETITIVE_LANDSCAPE',
|
|
1300
|
-
DEPENDENCY_CHECK_COMMANDS: 'KIMI_RUNTIME_DEPENDENCY_CHECK_COMMANDS',
|
|
1301
|
-
DOMAIN_EXPERTISE: 'KIMI_RUNTIME_DOMAIN_EXPERTISE',
|
|
1302
|
-
DOMAIN_KNOWLEDGE: 'KIMI_RUNTIME_DOMAIN_KNOWLEDGE',
|
|
1303
|
-
FRONTEND_ARCHITECTURE_DIAGRAM: 'KIMI_RUNTIME_FRONTEND_ARCHITECTURE_DIAGRAM',
|
|
1304
|
-
FRONTEND_CRITICAL_RULES: 'KIMI_RUNTIME_FRONTEND_CRITICAL_RULES',
|
|
1305
|
-
FRONTEND_EXPERTISE: 'KIMI_RUNTIME_FRONTEND_EXPERTISE',
|
|
1306
|
-
FRONTEND_LAYER_CONVENTIONS: 'KIMI_RUNTIME_FRONTEND_LAYER_CONVENTIONS',
|
|
1307
|
-
FRONTEND_STACK: 'KIMI_RUNTIME_FRONTEND_STACK',
|
|
1308
|
-
FRONTEND_TECH_LIST: 'KIMI_RUNTIME_FRONTEND_TECH_LIST',
|
|
1309
|
-
GIT_ACCESS: 'KIMI_RUNTIME_GIT_ACCESS',
|
|
1310
|
-
JIRA_BASE_URL: 'KIMI_RUNTIME_JIRA_BASE_URL',
|
|
1311
|
-
JIRA_PROJECT_KEY: 'KIMI_RUNTIME_JIRA_PROJECT_KEY',
|
|
1312
|
-
KEY_FILE_PATHS: 'KIMI_RUNTIME_KEY_FILE_PATHS',
|
|
1313
|
-
LAYER_CLAUDE_MD_PATHS: 'KIMI_RUNTIME_LAYER_CONTEXT_PATHS',
|
|
1314
|
-
LAYER_CONVENTIONS: 'KIMI_RUNTIME_LAYER_CONVENTIONS',
|
|
1315
|
-
LAYER_LIST: 'KIMI_RUNTIME_LAYER_LIST',
|
|
1316
|
-
LAYER_NAME: 'KIMI_RUNTIME_LAYER_NAME',
|
|
1317
|
-
LAYER_PATH: 'KIMI_RUNTIME_LAYER_PATH',
|
|
1318
|
-
LAYER_TAGS: 'KIMI_RUNTIME_LAYER_TAGS',
|
|
1319
|
-
MAINTAINER_PERSONA_LINE: 'KIMI_RUNTIME_MAINTAINER_PERSONA_LINE',
|
|
1320
|
-
MAX_SCORE: 'KIMI_RUNTIME_PERSONA_MAX_SCORE',
|
|
1321
|
-
PERSONA_COUNT: 'KIMI_RUNTIME_PERSONA_COUNT',
|
|
1322
|
-
PERSONA_FILES: 'KIMI_RUNTIME_PERSONA_FILES',
|
|
1323
|
-
PERSONA_FILE_LIST: 'KIMI_RUNTIME_PERSONA_FILE_LIST',
|
|
1324
|
-
PERSONA_FILE_READ_LIST: 'KIMI_RUNTIME_PERSONA_FILE_READ_LIST',
|
|
1325
|
-
PERSONA_FIT_FORMAT: 'KIMI_RUNTIME_PERSONA_FIT_FORMAT',
|
|
1326
|
-
PERSONA_NAMES: 'KIMI_RUNTIME_PERSONA_NAMES',
|
|
1327
|
-
PERSONA_NAMES_WITH_ROLES: 'KIMI_RUNTIME_PERSONA_NAMES_WITH_ROLES',
|
|
1328
|
-
PERSONA_SCORE_FORMAT: 'KIMI_RUNTIME_PERSONA_SCORE_FORMAT',
|
|
1329
|
-
PERSONA_SCORE_HEADERS: 'KIMI_RUNTIME_PERSONA_SCORE_HEADERS',
|
|
1330
|
-
PERSONA_SCORE_SEPARATORS: 'KIMI_RUNTIME_PERSONA_SCORE_SEPARATORS',
|
|
1331
|
-
PERSONA_VPC_SECTIONS: 'KIMI_RUNTIME_PERSONA_VPC_SECTIONS',
|
|
1332
|
-
PR_CREATE_CMD: 'KIMI_PR_CREATE',
|
|
1333
|
-
PROJECT_CONTEXT: 'KIMI_RUNTIME_PROJECT_CONTEXT',
|
|
1334
|
-
TECH_EXPERTISE: 'KIMI_RUNTIME_TECH_EXPERTISE',
|
|
1335
|
-
TEST_QUALITY_CHECKLIST: 'KIMI_RUNTIME_TEST_QUALITY_CHECKLIST',
|
|
1336
|
-
TEST_RUNNER_CHECK: 'KIMI_RUNTIME_TEST_RUNNER_CHECK',
|
|
1337
|
-
WARNINGS: 'KIMI_RUNTIME_WARNINGS',
|
|
1338
|
-
};
|
|
1339
1031
|
function writeKimiWorkflowSkill(args) {
|
|
1340
1032
|
if (!pathExists(args.src))
|
|
1341
1033
|
return;
|
|
1342
1034
|
const { body, description } = stripFrontmatter(readTextFile(args.src));
|
|
1343
|
-
const
|
|
1344
|
-
const providerNeutral = renderPlaceholders(body, {
|
|
1345
|
-
...KIMI_RUNTIME_PLACEHOLDERS,
|
|
1346
|
-
...args.placeholders,
|
|
1347
|
-
MEMORY_PATH: '.kimi-code/agent-memory/',
|
|
1348
|
-
}).replaceAll('.specrails/profiles/project-default.json', '.specrails/profiles/kimi-default.json');
|
|
1349
|
-
const rendered = translateClaudeTextForKimi(adaptKimiWorkflowBody(args.commandName, providerNeutral)).replaceAll('.specrails/local-tickets.json', '${SPECRAILS_BACKLOG_PATH}');
|
|
1035
|
+
const values = { PROJECT_NAME: args.projectName };
|
|
1350
1036
|
const frontmatter = [
|
|
1351
1037
|
'---',
|
|
1352
|
-
`name:
|
|
1353
|
-
`description: ${JSON.stringify(translateClaudeTextForKimi(renderPlaceholders(description ?? `SpecRails ${args.commandName} workflow for Kimi Code.`,
|
|
1354
|
-
...KIMI_RUNTIME_PLACEHOLDERS,
|
|
1355
|
-
...args.placeholders,
|
|
1356
|
-
})))}`,
|
|
1038
|
+
`name: specrails-${args.commandName}`,
|
|
1039
|
+
`description: ${JSON.stringify(translateClaudeTextForKimi(renderPlaceholders(description ?? `SpecRails ${args.commandName} workflow for Kimi Code.`, values)))}`,
|
|
1357
1040
|
'type: prompt',
|
|
1358
1041
|
'---',
|
|
1359
1042
|
'',
|
|
1360
1043
|
].join('\n');
|
|
1361
|
-
writeFileLf(args.dest, frontmatter +
|
|
1362
|
-
(['implement', 'batch-implement', 'retry'].includes(args.commandName) ? rendered :
|
|
1363
|
-
(pathExists(path.join(path.dirname(args.src), '..', '..', 'runtime', 'provider-pipeline.md'))
|
|
1364
|
-
? readTextFile(path.join(path.dirname(args.src), '..', '..', 'runtime', 'provider-pipeline.md')) + '\n' : '') +
|
|
1365
|
-
KIMI_NESTED_SKILL_CONTRACT +
|
|
1366
|
-
KIMI_ROLE_EXECUTION_CONTRACT +
|
|
1367
|
-
KIMI_RUNTIME_CONTEXT_CONTRACT +
|
|
1368
|
-
rendered));
|
|
1369
|
-
}
|
|
1370
|
-
function adaptKimiWorkflowBody(commandName, body) {
|
|
1371
|
-
if (commandName === 'auto-propose-backlog-specs') {
|
|
1372
|
-
return adaptKimiAutoPropose(body);
|
|
1373
|
-
}
|
|
1374
|
-
if (commandName === 'enrich') {
|
|
1375
|
-
return renderKimiEnrichWorkflow();
|
|
1376
|
-
}
|
|
1377
|
-
if (commandName === 'reconfig') {
|
|
1378
|
-
return renderKimiReconfigWorkflow();
|
|
1379
|
-
}
|
|
1380
|
-
if (commandName === 'telemetry') {
|
|
1381
|
-
return renderKimiTelemetryWorkflow();
|
|
1382
|
-
}
|
|
1383
|
-
return body;
|
|
1384
|
-
}
|
|
1385
|
-
function adaptKimiAutoPropose(body) {
|
|
1386
|
-
return body
|
|
1387
|
-
.replace('Launch a **single** explorer subagent (`subagent_type: Explore`, `run_in_background: true`) for product discovery.', [
|
|
1388
|
-
'Launch one **sr-product-analyst** role in a foreground Kimi role wave.',
|
|
1389
|
-
'Use `skill:"sr-product-analyst"`, `workspace:"current"`,',
|
|
1390
|
-
'`profile:"inherit"`, and pass the complete discovery prompt below as',
|
|
1391
|
-
'`args`. Before writing the wave, enumerate regular non-symlink',
|
|
1392
|
-
'`.kimi-code/personas/*.md` files and include their exact paths plus',
|
|
1393
|
-
'contents in that context; stop with guidance to run',
|
|
1394
|
-
'`Skill(skill="specrails-enrich", args="")` when none exist. Wait for its attributed',
|
|
1395
|
-
'completion/output frames. Kimi has no Claude Explore subagent type;',
|
|
1396
|
-
'never select a non-existent Explore role.',
|
|
1397
|
-
].join(' '))
|
|
1398
|
-
.replaceAll('The Explore agent receives this prompt:', 'The sr-product-analyst role receives this prompt:')
|
|
1399
|
-
.replaceAll('After the Explore agent completes:', 'After the sr-product-analyst role completes:');
|
|
1400
|
-
}
|
|
1401
|
-
function renderKimiEnrichWorkflow() {
|
|
1402
|
-
return [
|
|
1403
|
-
'# Enrich SpecRails for Kimi Code',
|
|
1404
|
-
'',
|
|
1405
|
-
'Refresh the Kimi-native SpecRails installation, analyze this repository,',
|
|
1406
|
-
'and maintain project context/personas without generating Claude artifacts.',
|
|
1407
|
-
'Kimi skills are managed provider artifacts; never rewrite their SKILL.md',
|
|
1408
|
-
'frontmatter or create Claude-style command/agent trees.',
|
|
1409
|
-
'',
|
|
1410
|
-
'## Mode selection',
|
|
1411
|
-
'',
|
|
1412
|
-
'Parse `$ARGUMENTS`: `--update`, `--quick`, and `--from-config` are mutually',
|
|
1413
|
-
'exclusive. With no flag run interactive full mode.',
|
|
1414
|
-
'',
|
|
1415
|
-
'1. Resolve the repository as `${SPECRAILS_REPO_DIR:-.}` and verify',
|
|
1416
|
-
' `.kimi-code/specrails/run-skill.mjs` plus',
|
|
1417
|
-
' `.specrails/install-config.yaml` exist.',
|
|
1418
|
-
'2. Read install config and require provider `kimi` (or an explicitly',
|
|
1419
|
-
' provider-neutral legacy config). Refuse a different provider.',
|
|
1420
|
-
'3. Refresh managed provider artifacts with the installed Core CLI:',
|
|
1421
|
-
' `npx specrails-core update --provider kimi --root-dir "${SPECRAILS_REPO_DIR:-.}"`.',
|
|
1422
|
-
' Use the process result as a hard gate. This provider-aware materializer',
|
|
1423
|
-
' regenerates direct-child workflows/roles, rules, runner, OpenSpec skills,',
|
|
1424
|
-
' settings, manifest, and framework links. Do not reproduce its templates',
|
|
1425
|
-
' with model-authored file copying.',
|
|
1426
|
-
'4. Validate `.specrails/profiles/kimi-default.json`: schemaVersion 1,',
|
|
1427
|
-
' provider `kimi`, required architect/developer/reviewer, unique role ids,',
|
|
1428
|
-
' safe model ids, and valid routing. Preserve exact model identifiers.',
|
|
1429
|
-
'',
|
|
1430
|
-
'## Quick mode',
|
|
1431
|
-
'',
|
|
1432
|
-
'Inspect package/build metadata and the top-level source tree. Atomically',
|
|
1433
|
-
'write `.kimi-code/project-context.md` with stack, architecture, test/lint/',
|
|
1434
|
-
'build commands, repository conventions, and the UTC refresh time. Preserve',
|
|
1435
|
-
'existing `.kimi-code/personas/`. Report that full mode can add VPC personas.',
|
|
1436
|
-
'',
|
|
1437
|
-
'## From-config mode',
|
|
1438
|
-
'',
|
|
1439
|
-
'Do not ask questions. Apply the tier, selected agents, backlog, git, and',
|
|
1440
|
-
'model choices already present in install config/profile; the Core update is',
|
|
1441
|
-
'the only artifact-generation authority. For quick tier run Quick mode. For',
|
|
1442
|
-
'full tier perform the same repository analysis as Full mode, retain existing',
|
|
1443
|
-
'personas when present, and generate conservative personas only when the',
|
|
1444
|
-
'config enables product roles and the persona directory is empty.',
|
|
1445
|
-
'',
|
|
1446
|
-
'## Update mode',
|
|
1447
|
-
'',
|
|
1448
|
-
'Run the provider-aware refresh, re-analyze commands/conventions, and',
|
|
1449
|
-
'atomically refresh only `.kimi-code/project-context.md`. Keep user personas,',
|
|
1450
|
-
'custom-* skills, agent memory, profiles, MCP configuration, and security',
|
|
1451
|
-
'exemptions byte-for-byte. Report stale/missing persona references but do not',
|
|
1452
|
-
'invent replacements.',
|
|
1453
|
-
'',
|
|
1454
|
-
'## Full mode',
|
|
1455
|
-
'',
|
|
1456
|
-
'Analyze the complete codebase and present findings. Ask concise questions',
|
|
1457
|
-
'about target users, pains, gains, product goals, and repository shipping',
|
|
1458
|
-
'policy. Research externally only with user-approved network tooling.',
|
|
1459
|
-
'Generate 2–4 Value Proposition Canvas personas as real Markdown files under',
|
|
1460
|
-
'`.kimi-code/personas/<safe-kebab-id>.md`; include jobs, pains, gains,',
|
|
1461
|
-
'behavior, success criteria, and evidence/assumptions. On OSS projects also',
|
|
1462
|
-
'materialize the bundled maintainer persona from setup templates. Never',
|
|
1463
|
-
'overwrite an existing persona without showing the proposed change.',
|
|
1464
|
-
'',
|
|
1465
|
-
'Refresh `.kimi-code/project-context.md` and ensure every selected product',
|
|
1466
|
-
'role has an agent-memory directory. Workflows discover persona files at',
|
|
1467
|
-
'runtime, so do not fork or mutate framework-owned skills to embed a static',
|
|
1468
|
-
'persona list.',
|
|
1469
|
-
'',
|
|
1470
|
-
'## Verification and report',
|
|
1471
|
-
'',
|
|
1472
|
-
'Run `npx specrails-core doctor --provider kimi --root-dir',
|
|
1473
|
-
'"${SPECRAILS_REPO_DIR:-.}"`. Verify every immediate skill directory has one',
|
|
1474
|
-
'valid SKILL.md, no role is nested under `skills/rails`, no unresolved',
|
|
1475
|
-
'template token remains, the Kimi profile validates, and no Claude model',
|
|
1476
|
-
'alias/path was generated. Report mode, provider version, context/persona',
|
|
1477
|
-
'files, selected roles, exact models, and doctor result.',
|
|
1478
|
-
'',
|
|
1479
|
-
].join('\n');
|
|
1480
|
-
}
|
|
1481
|
-
function renderKimiReconfigWorkflow() {
|
|
1482
|
-
return [
|
|
1483
|
-
'# Reconfig: apply Kimi models to a provider profile',
|
|
1484
|
-
'',
|
|
1485
|
-
'Kimi role skills do not carry per-role model frontmatter. Reconfiguration',
|
|
1486
|
-
'updates a provider-bound profile; workflows read that profile and put each',
|
|
1487
|
-
'exact model id in the structured role wave.',
|
|
1488
|
-
'',
|
|
1489
|
-
'1. Parse `$ARGUMENTS` as optional `--profile <safe-name>`; default to the',
|
|
1490
|
-
' active `SPECRAILS_PROFILE_PATH`, then',
|
|
1491
|
-
' `.specrails/profiles/kimi-default.json`.',
|
|
1492
|
-
'2. Require a regular non-symlink JSON file inside `.specrails/profiles/`.',
|
|
1493
|
-
' Validate it against profile schema v1, require `provider:"kimi"`, unique',
|
|
1494
|
-
' agents, the baseline trio, valid routing references, and Kimi-safe model',
|
|
1495
|
-
' ids (`^[A-Za-z0-9][A-Za-z0-9._/:-]*$`, maximum 128 characters).',
|
|
1496
|
-
'3. Read `.specrails/agents.yaml` only as an optional legacy input. Ask for',
|
|
1497
|
-
' confirmation before migrating its defaults/per-agent model values. Claude',
|
|
1498
|
-
' aliases `opus`, `sonnet`, and `haiku` are not Kimi models and must never',
|
|
1499
|
-
' be translated silently; require an explicit Kimi replacement.',
|
|
1500
|
-
'4. Present the orchestrator and per-role old→new model table. Apply approved',
|
|
1501
|
-
' edits to a complete in-memory profile object, validate again, then use',
|
|
1502
|
-
' structured WriteFile for one atomic logical replacement. Preserve name,',
|
|
1503
|
-
' description, required flags, agent order, and routing.',
|
|
1504
|
-
'5. Re-read and validate the result. Report changed/unchanged/skipped roles.',
|
|
1505
|
-
'',
|
|
1506
|
-
'Never edit any role SKILL.md under `.kimi-code/skills/`, never create Claude agent files,',
|
|
1507
|
-
'and never put a model id in a shell command.',
|
|
1508
|
-
'',
|
|
1509
|
-
].join('\n');
|
|
1510
|
-
}
|
|
1511
|
-
function renderKimiTelemetryWorkflow() {
|
|
1512
|
-
return [
|
|
1513
|
-
'# Kimi agent telemetry',
|
|
1514
|
-
'',
|
|
1515
|
-
'Analyze real Kimi Code session usage for this repository. Accepted flags:',
|
|
1516
|
-
'`--period today|week|all` (default `week`), `--agent <id>`,',
|
|
1517
|
-
'`--format markdown|json`, and `--save`. Cost is not derivable from Kimi logs and must remain',
|
|
1518
|
-
'`null`/`unavailable`; never apply a Claude or invented rate card.',
|
|
1519
|
-
'',
|
|
1520
|
-
'## Discover and validate sessions',
|
|
1521
|
-
'',
|
|
1522
|
-
'Read `~/.kimi-code/session_index.jsonl` line by line. Ignore only a final',
|
|
1523
|
-
'truncated JSON line; warn on any other malformed line. Fold records by',
|
|
1524
|
-
'`sessionId`, keeping the latest valid entry and honoring an explicit latest',
|
|
1525
|
-
'deletion/tombstone record. A live entry provides `sessionId`, `sessionDir`,',
|
|
1526
|
-
'and `workDir`. Require safe scalar strings, match canonical `workDir` to',
|
|
1527
|
-
'`${SPECRAILS_REPO_DIR:-.}`, and require canonical `sessionDir` to remain',
|
|
1528
|
-
'inside `~/.kimi-code/sessions/`. Reject symlinks/path traversal and ignore',
|
|
1529
|
-
'missing or deleted session directories.',
|
|
1530
|
-
'',
|
|
1531
|
-
'For each accepted session, read its regular non-symlink `state.json` and',
|
|
1532
|
-
'validate its `workDir`, timestamps, and title. Then scan only regular',
|
|
1533
|
-
'`agents/*/wire.jsonl` files within that same session directory. Tolerate a',
|
|
1534
|
-
'truncated final line; count and warn on other malformed records.',
|
|
1535
|
-
'',
|
|
1536
|
-
'## Usage schema and attribution',
|
|
1537
|
-
'',
|
|
1538
|
-
'Consume only records with `type:"usage.record"` and a safe `model` plus',
|
|
1539
|
-
'`usage:{inputOther,output,inputCacheRead,inputCacheCreation}`. Treat absent',
|
|
1540
|
-
'numeric counters as zero; reject negative/non-finite values. Preserve',
|
|
1541
|
-
'`usageScope` and aggregate input-other, output, cache-read, cache-creation,',
|
|
1542
|
-
'and total tokens per model/session.',
|
|
1543
|
-
'',
|
|
1544
|
-
'Attribute an external role session by canonical workDir: first use its',
|
|
1545
|
-
'`.specrails-role-workspace.json` marker; otherwise match `repoDir` in valid',
|
|
1546
|
-
'`.specrails/kimi-role-worktrees/*.json` manifests. Attribute the top-level',
|
|
1547
|
-
'session to `orchestrator`; use `unknown` only when no verified mapping',
|
|
1548
|
-
'exists. Apply period and agent filters after attribution. Deduplicate by',
|
|
1549
|
-
'session id + agent wire path + record position.',
|
|
1550
|
-
'',
|
|
1551
|
-
'Duration comes only from validated state timestamps. The wire schema does',
|
|
1552
|
-
'not provide a trustworthy role success/failure outcome, so expose that',
|
|
1553
|
-
'metric as unavailable rather than inferring it from the last event.',
|
|
1554
|
-
'',
|
|
1555
|
-
'## Output',
|
|
1556
|
-
'',
|
|
1557
|
-
'Show session/run count, duration, exact models, and all four token counters',
|
|
1558
|
-
'per role plus totals and cache ratio. In JSON use',
|
|
1559
|
-
'`cost_usd:null`, `avg_cost_per_run_usd:null`, and',
|
|
1560
|
-
'`success_rate:null` with `unavailable_reason`. In Markdown print',
|
|
1561
|
-
'`Cost: unavailable (Kimi logs contain usage, not billing rates)`.',
|
|
1562
|
-
'Recommendations may discuss token/cache/runtime outliers only.',
|
|
1563
|
-
'',
|
|
1564
|
-
'With `--save`, write the same JSON object under',
|
|
1565
|
-
'`.kimi-code/telemetry/<UTC-date>-<period>.json` using structured WriteFile;',
|
|
1566
|
-
'never include prompt text, credentials, raw wire records, or paths outside',
|
|
1567
|
-
'the repository/session identifiers.',
|
|
1568
|
-
'',
|
|
1569
|
-
].join('\n');
|
|
1044
|
+
writeFileLf(args.dest, frontmatter + translateClaudeTextForKimi(renderPlaceholders(body, values)));
|
|
1570
1045
|
}
|
|
1571
1046
|
function writeKimiRoleSkill(args) {
|
|
1572
1047
|
if (!pathExists(args.src))
|
|
1573
1048
|
return;
|
|
1574
1049
|
const { body, description } = stripFrontmatter(readTextFile(args.src));
|
|
1575
|
-
const
|
|
1576
|
-
...KIMI_RUNTIME_PLACEHOLDERS,
|
|
1577
|
-
...args.placeholders,
|
|
1578
|
-
MEMORY_PATH: `.kimi-code/agent-memory/${args.roleId}/`,
|
|
1579
|
-
}));
|
|
1050
|
+
const values = { PROJECT_NAME: args.projectName };
|
|
1580
1051
|
const frontmatter = [
|
|
1581
1052
|
'---',
|
|
1582
1053
|
`name: ${args.roleId}`,
|
|
1583
|
-
`description: ${JSON.stringify(translateClaudeTextForKimi(renderPlaceholders(description ?? `SpecRails ${args.roleId} role for Kimi Code.`,
|
|
1584
|
-
...KIMI_RUNTIME_PLACEHOLDERS,
|
|
1585
|
-
...args.placeholders,
|
|
1586
|
-
})))}`,
|
|
1054
|
+
`description: ${JSON.stringify(translateClaudeTextForKimi(renderPlaceholders(description ?? `SpecRails ${args.roleId} role for Kimi Code.`, values)))}`,
|
|
1587
1055
|
'type: prompt',
|
|
1588
1056
|
'---',
|
|
1589
1057
|
'',
|
|
1590
1058
|
].join('\n');
|
|
1591
|
-
writeFileLf(args.dest, frontmatter +
|
|
1592
|
-
(pathExists(path.join(path.dirname(args.src), '..', '..', 'runtime', 'provider-pipeline.md'))
|
|
1593
|
-
? readTextFile(path.join(path.dirname(args.src), '..', '..', 'runtime', 'provider-pipeline.md')) + '\n' : '') +
|
|
1594
|
-
KIMI_NESTED_SKILL_CONTRACT +
|
|
1595
|
-
KIMI_RUNTIME_CONTEXT_CONTRACT +
|
|
1596
|
-
rendered);
|
|
1059
|
+
writeFileLf(args.dest, frontmatter + translateClaudeTextForKimi(renderPlaceholders(body, values)));
|
|
1597
1060
|
}
|
|
1598
1061
|
/**
|
|
1599
1062
|
* Strip a leading `---`-delimited YAML frontmatter block and return the
|
|
@@ -1650,7 +1113,7 @@ function writeGeminiCommandFromCommand(args) {
|
|
|
1650
1113
|
* Emit a gemini subagent (`.gemini/agents/<id>.md`) from a claude persona
|
|
1651
1114
|
* template. Re-emits gemini YAML frontmatter (name/description/model/tools),
|
|
1652
1115
|
* dropping claude `color:`/`memory:`; the persona body is reused, `.claude/`
|
|
1653
|
-
* paths rewritten
|
|
1116
|
+
* paths rewritten.
|
|
1654
1117
|
*/
|
|
1655
1118
|
function writeGeminiAgentFromTemplate(args) {
|
|
1656
1119
|
if (!pathExists(args.src))
|
|
@@ -1667,10 +1130,7 @@ function writeGeminiAgentFromTemplate(args) {
|
|
|
1667
1130
|
'---',
|
|
1668
1131
|
'',
|
|
1669
1132
|
].join('\n');
|
|
1670
|
-
const renderedBody = translateOpsxSkillCallsForGemini(renderPlaceholders(body,
|
|
1671
|
-
...args.placeholders,
|
|
1672
|
-
MEMORY_PATH: `.gemini/agent-memory/${args.agentId}/`,
|
|
1673
|
-
}).replace(/\.claude\//g, '.gemini/'));
|
|
1133
|
+
const renderedBody = translateOpsxSkillCallsForGemini(renderPlaceholders(body, args.placeholders).replace(/\.claude\//g, '.gemini/'));
|
|
1674
1134
|
writeFileLf(path.join(args.artifactRoot, '.gemini', 'agents', `${args.agentId}.md`), frontmatter + renderedBody);
|
|
1675
1135
|
if (args.seedProjectDirs !== false) {
|
|
1676
1136
|
mkdirp(path.join(args.artifactRoot, '.gemini', 'agent-memory', args.agentId));
|
|
@@ -1689,10 +1149,7 @@ function placeGeminiAgents(input) {
|
|
|
1689
1149
|
const selectedAgents = input.selectedAgents
|
|
1690
1150
|
? new Set([...input.selectedAgents, ...CORE_AGENTS])
|
|
1691
1151
|
: new Set([...CORE_AGENTS]);
|
|
1692
|
-
const placeholders = {
|
|
1693
|
-
PROJECT_NAME: path.basename(input.codeRoot),
|
|
1694
|
-
SECURITY_EXEMPTIONS_PATH: '.gemini/security-exemptions.yaml',
|
|
1695
|
-
};
|
|
1152
|
+
const placeholders = { PROJECT_NAME: path.basename(input.codeRoot) };
|
|
1696
1153
|
const placedIds = [];
|
|
1697
1154
|
for (const src of listDir(agentsSrc)) {
|
|
1698
1155
|
const name = path.basename(src);
|
|
@@ -1878,21 +1335,16 @@ function renderInitialKimiAgentsMd(repoRoot) {
|
|
|
1878
1335
|
'',
|
|
1879
1336
|
'This project uses SpecRails skills under `.kimi-code/skills/`.',
|
|
1880
1337
|
'Kimi discovers only direct child skill directories. Interactive TUI sessions',
|
|
1881
|
-
'invoke workflows as `/skill:specrails-<command
|
|
1882
|
-
'
|
|
1883
|
-
'
|
|
1884
|
-
'
|
|
1885
|
-
'separate helper-managed `kimi -p --output-format stream-json` processes.',
|
|
1886
|
-
'Inside a programmatic runtime role, follow the supplied OpenSpec tools and',
|
|
1887
|
-
'frozen scope instead; never start a nested implementation workflow.',
|
|
1338
|
+
'invoke workflows as `/skill:specrails-<command>`; headless automation uses',
|
|
1339
|
+
'`.kimi-code/specrails/run-skill.mjs --skill <id>`. Inside a programmatic',
|
|
1340
|
+
'runtime role, follow the supplied OpenSpec tools and frozen scope instead;',
|
|
1341
|
+
'never start a nested implementation workflow.',
|
|
1888
1342
|
'',
|
|
1889
1343
|
'## Conventions',
|
|
1890
1344
|
'',
|
|
1891
1345
|
'- Read project source, `.git`, and `openspec/**` from',
|
|
1892
1346
|
' `${SPECRAILS_REPO_DIR:-.}`.',
|
|
1893
|
-
'-
|
|
1894
|
-
' `.kimi-code/agent-memory/`.',
|
|
1895
|
-
'- Preserve model ids from provider-aware profiles exactly. The Kimi CLI',
|
|
1347
|
+
'- Preserve configured model ids exactly. The Kimi CLI',
|
|
1896
1348
|
' accepts configured aliases; official short ids use the `kimi-code/`',
|
|
1897
1349
|
' prefix at launch (for example `kimi-code/k3`).',
|
|
1898
1350
|
'- OpenSpec workflows are invoked as `/skill:openspec-*`.',
|
|
@@ -1911,12 +1363,12 @@ function assertPipelineRuntimeSource(scriptDir) {
|
|
|
1911
1363
|
if (!pathExists(contractFile))
|
|
1912
1364
|
return;
|
|
1913
1365
|
const contract = JSON.parse(readTextFile(contractFile));
|
|
1914
|
-
if (contract.execution?.runtime && !pathExists(path.join(scriptDir, 'dist', '
|
|
1366
|
+
if (contract.execution?.runtime && !pathExists(path.join(scriptDir, 'dist', 'pipeline', 'pipeline-state.js'))) {
|
|
1915
1367
|
throw new Error('Core declares a pipeline runtime but its compiled module is missing; rebuild or reinstall this Core package before refreshing providers');
|
|
1916
1368
|
}
|
|
1917
1369
|
}
|
|
1918
1370
|
function placePipelineRuntime(input) {
|
|
1919
|
-
const source = path.join(input.scriptDir, 'dist', '
|
|
1371
|
+
const source = path.join(input.scriptDir, 'dist', 'pipeline', 'pipeline-state.js');
|
|
1920
1372
|
// Source-only fixture installations may not include a compiled runtime.
|
|
1921
1373
|
if (!pathExists(source))
|
|
1922
1374
|
return 0;
|
|
@@ -1927,7 +1379,7 @@ function placePipelineRuntime(input) {
|
|
|
1927
1379
|
const runtime = path.join(input.scriptDir, 'dist', 'agent-runtime', 'cli.js');
|
|
1928
1380
|
if (pathExists(runtime)) {
|
|
1929
1381
|
writeFileLf(path.join(dest, 'agent-runtime.mjs'), `import { runRuntimeCommand } from ${JSON.stringify(pathToFileURL(runtime).href)}\n` +
|
|
1930
|
-
`import { parseArgs } from ${JSON.stringify(pathToFileURL(path.join(input.scriptDir, 'dist', '
|
|
1382
|
+
`import { parseArgs } from ${JSON.stringify(pathToFileURL(path.join(input.scriptDir, 'dist', 'shared', 'args.js')).href)}\n` +
|
|
1931
1383
|
"const { subcommand, flags, positionals } = parseArgs(process.argv.slice(2))\n" +
|
|
1932
1384
|
"try { process.exitCode = await runRuntimeCommand(flags, [subcommand, ...positionals].filter(Boolean)) } catch (error) { console.error(error.message); process.exitCode = 1 }\n");
|
|
1933
1385
|
const configPath = path.join(input.artifactRoot, '.specrails', 'agent-runtime.json');
|
|
@@ -1995,138 +1447,37 @@ function pruneLegacyArtifacts(input) {
|
|
|
1995
1447
|
}
|
|
1996
1448
|
}
|
|
1997
1449
|
/**
|
|
1998
|
-
* Direct placement
|
|
1999
|
-
*
|
|
2000
|
-
*
|
|
2001
|
-
*
|
|
2002
|
-
*
|
|
2003
|
-
* Source is setup-templates/ (not scriptDir/templates/) so the pipeline
|
|
2004
|
-
* is: scriptDir/templates/ → setup-templates/ (earlier scaffold step)
|
|
2005
|
-
* → <providerDir>/ (this function). The intermediate hop lets downstream
|
|
2006
|
-
* consumers (specrails-desktop's deployTemplates, update flow) read from a
|
|
2007
|
-
* single canonical staging dir.
|
|
1450
|
+
* Direct placement of the staged templates (`.specrails/setup-templates/`)
|
|
1451
|
+
* into the live provider directory. Claude receives agents + slash commands;
|
|
1452
|
+
* Codex receives each command as a skill; Gemini receives TOML commands. Kimi
|
|
1453
|
+
* roles and workflows are rendered as skills by `placeSkills`.
|
|
2008
1454
|
*/
|
|
2009
1455
|
function placeArtefacts(input) {
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
1456
|
+
const setupTemplates = path.join(input.artifactRoot, '.specrails', 'setup-templates');
|
|
1457
|
+
const commandsSrc = path.join(setupTemplates, 'commands', 'specrails');
|
|
1458
|
+
const providerDirAbs = path.join(input.artifactRoot, input.providerDir);
|
|
1459
|
+
const commandSources = isDir(commandsSrc) ? listDir(commandsSrc).filter((src) => src.endsWith('.md')) : [];
|
|
1460
|
+
const commandName = (src) => path.basename(src).slice(0, -3);
|
|
1461
|
+
if (input.provider === 'kimi')
|
|
1462
|
+
return { agents: 0, commands: 0 };
|
|
2017
1463
|
if (input.provider === 'codex') {
|
|
2018
|
-
const
|
|
2019
|
-
|
|
2020
|
-
// Codex-native skill overrides live at `templates/codex-skills/<name>/`.
|
|
2021
|
-
// When one exists for a given slash-command name (e.g. `implement`), the
|
|
2022
|
-
// scaffold writes that file verbatim instead of porting the claude
|
|
2023
|
-
// command body. Use these to ship skills written for codex's
|
|
2024
|
-
// single-agent model (no `subagent_type`, no `.claude/agent-memory/`,
|
|
2025
|
-
// codex-shape spawn semantics).
|
|
2026
|
-
const codexOverridesSrc = path.join(input.scriptDir, 'templates', 'codex-skills');
|
|
2027
|
-
let commandsPlaced = 0;
|
|
2028
|
-
if (isDir(commandsSrc)) {
|
|
2029
|
-
for (const src of listDir(commandsSrc)) {
|
|
2030
|
-
const name = path.basename(src);
|
|
2031
|
-
if (!name.endsWith('.md'))
|
|
2032
|
-
continue;
|
|
2033
|
-
if (name === 'setup.md')
|
|
2034
|
-
continue;
|
|
2035
|
-
const skillName = name.slice(0, -3);
|
|
2036
|
-
const dest = path.join(input.artifactRoot, input.providerDir, 'skills', skillName, 'SKILL.md');
|
|
2037
|
-
// If a codex-native override exists, ship it verbatim and skip the
|
|
2038
|
-
// ported claude body entirely. Mirrors a directory copy in case the
|
|
2039
|
-
// override ships sibling assets.
|
|
2040
|
-
const overrideDir = path.join(codexOverridesSrc, skillName);
|
|
2041
|
-
const overrideSkill = path.join(overrideDir, 'SKILL.md');
|
|
2042
|
-
if (pathExists(overrideSkill)) {
|
|
2043
|
-
copyDir(overrideDir, path.dirname(dest));
|
|
2044
|
-
commandsPlaced++;
|
|
2045
|
-
continue;
|
|
2046
|
-
}
|
|
2047
|
-
writeCodexSkillFromCommand({
|
|
2048
|
-
src,
|
|
2049
|
-
dest,
|
|
2050
|
-
name: skillName,
|
|
2051
|
-
});
|
|
2052
|
-
commandsPlaced++;
|
|
2053
|
-
}
|
|
1464
|
+
for (const src of commandSources) {
|
|
1465
|
+
writeCodexSkillFromCommand({ src, dest: path.join(providerDirAbs, 'skills', commandName(src), 'SKILL.md'), name: commandName(src) });
|
|
2054
1466
|
}
|
|
2055
|
-
return { agents: 0, commands:
|
|
1467
|
+
return { agents: 0, commands: commandSources.length };
|
|
2056
1468
|
}
|
|
2057
1469
|
if (input.provider === 'gemini') {
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
// batch-implement) under templates/gemini-commands/ win verbatim. Agents
|
|
2061
|
-
// are placed by placeSkills → placeGeminiAgents (both tiers).
|
|
2062
|
-
const geminiSetupTemplates = path.join(input.artifactRoot, '.specrails', 'setup-templates');
|
|
2063
|
-
const commandsSrc = path.join(geminiSetupTemplates, 'commands', 'specrails');
|
|
2064
|
-
const overridesSrc = path.join(input.scriptDir, 'templates', 'gemini-commands');
|
|
2065
|
-
let commandsPlaced = 0;
|
|
2066
|
-
if (isDir(commandsSrc)) {
|
|
2067
|
-
for (const src of listDir(commandsSrc)) {
|
|
2068
|
-
const name = path.basename(src);
|
|
2069
|
-
if (!name.endsWith('.md'))
|
|
2070
|
-
continue;
|
|
2071
|
-
if (name === 'setup.md')
|
|
2072
|
-
continue;
|
|
2073
|
-
const cmdName = name.slice(0, -3);
|
|
2074
|
-
const dest = path.join(input.artifactRoot, input.providerDir, 'commands', 'specrails', `${cmdName}.toml`);
|
|
2075
|
-
const overrideToml = path.join(overridesSrc, `${cmdName}.toml`);
|
|
2076
|
-
if (pathExists(overrideToml)) {
|
|
2077
|
-
copyFile(overrideToml, dest);
|
|
2078
|
-
}
|
|
2079
|
-
else {
|
|
2080
|
-
writeGeminiCommandFromCommand({ src, dest });
|
|
2081
|
-
}
|
|
2082
|
-
commandsPlaced++;
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
return { agents: 0, commands: commandsPlaced, rules: 0, skippedAgents: 0 };
|
|
2086
|
-
}
|
|
2087
|
-
if (input.provider === 'kimi') {
|
|
2088
|
-
const setupTemplates = path.join(input.artifactRoot, '.specrails', 'setup-templates');
|
|
2089
|
-
const rulesSrc = path.join(setupTemplates, 'rules');
|
|
2090
|
-
const rulesDest = path.join(input.artifactRoot, input.providerDir, 'rules');
|
|
2091
|
-
let rulesPlaced = 0;
|
|
2092
|
-
if (isDir(rulesSrc)) {
|
|
2093
|
-
mkdirp(rulesDest);
|
|
2094
|
-
for (const src of listDir(rulesSrc)) {
|
|
2095
|
-
const name = path.basename(src);
|
|
2096
|
-
if (!name.endsWith('.md'))
|
|
2097
|
-
continue;
|
|
2098
|
-
const rendered = translateClaudeTextForKimi(renderPlaceholders(readTextFile(src), {
|
|
2099
|
-
...KIMI_RUNTIME_PLACEHOLDERS,
|
|
2100
|
-
PROJECT_NAME: path.basename(input.codeRoot),
|
|
2101
|
-
SECURITY_EXEMPTIONS_PATH: '.kimi-code/security-exemptions.yaml',
|
|
2102
|
-
PERSONA_DIR: '.kimi-code/personas/',
|
|
2103
|
-
}));
|
|
2104
|
-
writeFileLf(path.join(rulesDest, name), rendered);
|
|
2105
|
-
rulesPlaced++;
|
|
2106
|
-
}
|
|
1470
|
+
for (const src of commandSources) {
|
|
1471
|
+
writeGeminiCommandFromCommand({ src, dest: path.join(providerDirAbs, 'commands', 'specrails', `${commandName(src)}.toml`) });
|
|
2107
1472
|
}
|
|
2108
|
-
return { agents: 0, commands:
|
|
1473
|
+
return { agents: 0, commands: commandSources.length };
|
|
2109
1474
|
}
|
|
2110
|
-
const setupTemplates = path.join(input.artifactRoot, '.specrails', 'setup-templates');
|
|
2111
1475
|
// PROJECT_NAME is the real repo's basename, not the relocated workspace dir.
|
|
2112
|
-
const
|
|
2113
|
-
const providerDirAbs = path.join(input.artifactRoot, input.providerDir);
|
|
2114
|
-
const placeholders = {
|
|
2115
|
-
PROJECT_NAME: projectName,
|
|
2116
|
-
SECURITY_EXEMPTIONS_PATH: `${input.providerDir}/security-exemptions.yaml`,
|
|
2117
|
-
};
|
|
2118
|
-
// --- Agents ---
|
|
1476
|
+
const placeholders = { PROJECT_NAME: path.basename(input.codeRoot) };
|
|
2119
1477
|
const agentsSrc = path.join(setupTemplates, 'agents');
|
|
2120
1478
|
const agentsDest = path.join(providerDirAbs, 'agents');
|
|
1479
|
+
const selectedAgents = new Set([...(input.selectedAgents ?? []), ...CORE_AGENTS]);
|
|
2121
1480
|
let agentsPlaced = 0;
|
|
2122
|
-
const agentsSkipped = 0;
|
|
2123
|
-
// The only shipped agents are the three core agents. A profile-driven
|
|
2124
|
-
// install may pass a selection; anything outside CORE_AGENTS has no template
|
|
2125
|
-
// to place, so the intersection is always the core trio (extension happens
|
|
2126
|
-
// via user-owned custom-*.md agents, never through the installer).
|
|
2127
|
-
const selectedAgents = input.selectedAgents
|
|
2128
|
-
? new Set([...input.selectedAgents, ...CORE_AGENTS])
|
|
2129
|
-
: new Set([...CORE_AGENTS]);
|
|
2130
1481
|
if (isDir(agentsSrc)) {
|
|
2131
1482
|
mkdirp(agentsDest);
|
|
2132
1483
|
for (const src of listDir(agentsSrc)) {
|
|
@@ -2135,66 +1486,22 @@ function placeArtefacts(input) {
|
|
|
2135
1486
|
continue;
|
|
2136
1487
|
const agentId = name.slice(0, -3);
|
|
2137
1488
|
// Superset materialization (installFramework) places EVERY agent so any
|
|
2138
|
-
// project's selection can later link from the shared store
|
|
2139
|
-
|
|
2140
|
-
if (!input.materializeAllAgents && selectedAgents && !selectedAgents.has(agentId))
|
|
1489
|
+
// project's selection can later link from the shared store.
|
|
1490
|
+
if (!input.materializeAllAgents && !selectedAgents.has(agentId))
|
|
2141
1491
|
continue;
|
|
2142
|
-
|
|
2143
|
-
const rendered = renderPlaceholders(readTextFile(src), {
|
|
2144
|
-
...placeholders,
|
|
2145
|
-
MEMORY_PATH: `.claude/agent-memory/${agentId}/`,
|
|
2146
|
-
});
|
|
2147
|
-
writeFileLf(dest, rendered);
|
|
1492
|
+
writeFileLf(path.join(agentsDest, name), renderPlaceholders(readTextFile(src), placeholders));
|
|
2148
1493
|
agentsPlaced++;
|
|
2149
|
-
//
|
|
2150
|
-
|
|
2151
|
-
// framework (`seedProjectDirs === false`): agent-memory is per-workspace
|
|
2152
|
-
// mutable state seeded later by `seedProjectLayer`, NEVER part of the
|
|
2153
|
-
// read-only framework copy that workspaces symlink.
|
|
2154
|
-
if (input.seedProjectDirs !== false) {
|
|
1494
|
+
// agent-memory is per-workspace mutable state, never part of the shared framework copy.
|
|
1495
|
+
if (input.seedProjectDirs !== false)
|
|
2155
1496
|
mkdirp(path.join(input.artifactRoot, '.claude', 'agent-memory', agentId));
|
|
2156
|
-
if (EXPLANATION_AUTHORS.has(agentId)) {
|
|
2157
|
-
mkdirp(path.join(input.artifactRoot, '.claude', 'agent-memory', 'explanations'));
|
|
2158
|
-
}
|
|
2159
|
-
}
|
|
2160
1497
|
}
|
|
2161
1498
|
}
|
|
2162
|
-
// --- Commands ---
|
|
2163
|
-
const commandsSrc = path.join(setupTemplates, 'commands', 'specrails');
|
|
2164
1499
|
const commandsDest = path.join(providerDirAbs, 'commands', 'specrails');
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
for (const src of listDir(commandsSrc)) {
|
|
2169
|
-
const name = path.basename(src);
|
|
2170
|
-
if (!name.endsWith('.md'))
|
|
2171
|
-
continue;
|
|
2172
|
-
const dest = path.join(commandsDest, name);
|
|
2173
|
-
const rendered = renderPlaceholders(readTextFile(src), {
|
|
2174
|
-
...placeholders,
|
|
2175
|
-
MEMORY_PATH: '.claude/agent-memory/',
|
|
2176
|
-
});
|
|
2177
|
-
writeFileLf(dest, rendered);
|
|
2178
|
-
commandsPlaced++;
|
|
2179
|
-
}
|
|
1500
|
+
mkdirp(commandsDest);
|
|
1501
|
+
for (const src of commandSources) {
|
|
1502
|
+
writeFileLf(path.join(commandsDest, path.basename(src)), renderPlaceholders(readTextFile(src), placeholders));
|
|
2180
1503
|
}
|
|
2181
|
-
|
|
2182
|
-
const rulesSrc = path.join(setupTemplates, 'rules');
|
|
2183
|
-
const rulesDest = path.join(providerDirAbs, 'rules');
|
|
2184
|
-
let rulesPlaced = 0;
|
|
2185
|
-
if (isDir(rulesSrc)) {
|
|
2186
|
-
mkdirp(rulesDest);
|
|
2187
|
-
for (const src of listDir(rulesSrc)) {
|
|
2188
|
-
const name = path.basename(src);
|
|
2189
|
-
if (!name.endsWith('.md'))
|
|
2190
|
-
continue;
|
|
2191
|
-
const dest = path.join(rulesDest, name);
|
|
2192
|
-
const rendered = renderPlaceholders(readTextFile(src), placeholders);
|
|
2193
|
-
writeFileLf(dest, rendered);
|
|
2194
|
-
rulesPlaced++;
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
return { agents: agentsPlaced, commands: commandsPlaced, rules: rulesPlaced, skippedAgents: agentsSkipped };
|
|
1504
|
+
return { agents: agentsPlaced, commands: commandSources.length };
|
|
2198
1505
|
}
|
|
2199
1506
|
/**
|
|
2200
1507
|
* Codex-specific provider settings. Writes `.codex/config.toml` (model +
|
|
@@ -2364,57 +1671,29 @@ function placeSkills(input) {
|
|
|
2364
1671
|
const setupRoot = path.join(input.artifactRoot, '.specrails', 'setup-templates');
|
|
2365
1672
|
const commandsSrc = path.join(setupRoot, 'commands', 'specrails');
|
|
2366
1673
|
const agentsSrc = path.join(setupRoot, 'agents');
|
|
2367
|
-
const selectedAgents = input.selectedAgents
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
const roleId = name.slice(0, -3);
|
|
2382
|
-
if (!input.materializeAllAgents && !selectedAgents.has(roleId))
|
|
2383
|
-
continue;
|
|
2384
|
-
writeKimiRoleSkill({
|
|
2385
|
-
src,
|
|
2386
|
-
dest: path.join(destBase, roleId, 'SKILL.md'),
|
|
2387
|
-
roleId,
|
|
2388
|
-
placeholders,
|
|
2389
|
-
});
|
|
2390
|
-
placedRoleIds.add(roleId);
|
|
2391
|
-
result.placed++;
|
|
2392
|
-
result.filesCopied++;
|
|
2393
|
-
if (input.seedProjectDirs !== false) {
|
|
2394
|
-
mkdirp(path.join(input.artifactRoot, input.providerDir, 'agent-memory', roleId));
|
|
2395
|
-
}
|
|
2396
|
-
}
|
|
1674
|
+
const selectedAgents = new Set([...(input.selectedAgents ?? []), ...CORE_AGENTS]);
|
|
1675
|
+
const projectName = path.basename(input.codeRoot);
|
|
1676
|
+
for (const src of isDir(agentsSrc) ? listDir(agentsSrc) : []) {
|
|
1677
|
+
const name = path.basename(src);
|
|
1678
|
+
if (!name.endsWith('.md'))
|
|
1679
|
+
continue;
|
|
1680
|
+
const roleId = name.slice(0, -3);
|
|
1681
|
+
if (!input.materializeAllAgents && !selectedAgents.has(roleId))
|
|
1682
|
+
continue;
|
|
1683
|
+
writeKimiRoleSkill({ src, dest: path.join(destBase, roleId, 'SKILL.md'), roleId, projectName });
|
|
1684
|
+
result.placed++;
|
|
1685
|
+
result.filesCopied++;
|
|
1686
|
+
if (input.seedProjectDirs !== false)
|
|
1687
|
+
mkdirp(path.join(input.artifactRoot, input.providerDir, 'agent-memory', roleId));
|
|
2397
1688
|
}
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
const commandName = name.slice(0, -3);
|
|
2407
|
-
if (excludedCommands.has(commandName))
|
|
2408
|
-
continue;
|
|
2409
|
-
writeKimiWorkflowSkill({
|
|
2410
|
-
src,
|
|
2411
|
-
dest: path.join(destBase, `specrails-${commandName}`, 'SKILL.md'),
|
|
2412
|
-
commandName,
|
|
2413
|
-
placeholders,
|
|
2414
|
-
});
|
|
2415
|
-
result.placed++;
|
|
2416
|
-
result.filesCopied++;
|
|
2417
|
-
}
|
|
1689
|
+
for (const src of isDir(commandsSrc) ? listDir(commandsSrc) : []) {
|
|
1690
|
+
const name = path.basename(src);
|
|
1691
|
+
if (!name.endsWith('.md'))
|
|
1692
|
+
continue;
|
|
1693
|
+
const commandName = name.slice(0, -3);
|
|
1694
|
+
writeKimiWorkflowSkill({ src, dest: path.join(destBase, `specrails-${commandName}`, 'SKILL.md'), commandName, projectName });
|
|
1695
|
+
result.placed++;
|
|
1696
|
+
result.filesCopied++;
|
|
2418
1697
|
}
|
|
2419
1698
|
}
|
|
2420
1699
|
return result;
|
|
@@ -2422,8 +1701,7 @@ function placeSkills(input) {
|
|
|
2422
1701
|
/**
|
|
2423
1702
|
* Substitutes `{{KEY}}` tokens in the input text with the provided
|
|
2424
1703
|
* values, then strips any remaining `{{UNKNOWN}}` tokens (replacing
|
|
2425
|
-
* them with the empty string).
|
|
2426
|
-
* `sed` pipeline byte-for-byte for the documented token set.
|
|
1704
|
+
* them with the empty string).
|
|
2427
1705
|
*/
|
|
2428
1706
|
function renderPlaceholders(text, values) {
|
|
2429
1707
|
let out = text;
|
|
@@ -2460,4 +1738,3 @@ function countFiles(dir) {
|
|
|
2460
1738
|
}
|
|
2461
1739
|
return n;
|
|
2462
1740
|
}
|
|
2463
|
-
//# sourceMappingURL=scaffold.js.map
|