specrails-core 6.2.2 → 6.3.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 +2 -2
- package/dist/agent-runtime/prompts.d.ts +1 -1
- package/dist/agent-runtime/prompts.js +41 -24
- package/dist/installer/commands/framework.d.ts +7 -3
- package/dist/installer/commands/framework.js +6 -8
- package/dist/installer/commands/init.d.ts +8 -15
- package/dist/installer/commands/init.js +22 -64
- package/dist/installer/phases/install-config.d.ts +8 -2
- package/dist/installer/phases/install-config.js +24 -17
- package/dist/installer/phases/scaffold.d.ts +27 -79
- package/dist/installer/phases/scaffold.js +100 -535
- package/integration-contract.json +7 -10
- package/package.json +1 -1
- package/templates/agents/sr-architect.md +0 -29
- package/templates/agents/sr-developer.md +0 -29
- package/templates/agents/sr-reviewer.md +0 -28
- package/templates/codex-skills/rails/sr-architect/SKILL.md +0 -29
- package/templates/codex-skills/rails/sr-developer/SKILL.md +0 -29
- package/templates/codex-skills/rails/sr-reviewer/SKILL.md +0 -28
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import yaml from 'js-yaml';
|
|
3
3
|
import { FilesystemError, InstallerError } from '../util/errors.js';
|
|
4
4
|
import { pathExists, readTextFile, writeFileLf } from '../util/fs.js';
|
|
5
|
+
import { warn } from '../util/logger.js';
|
|
5
6
|
const PROVIDER_DEFAULT_MODELS = {
|
|
6
7
|
claude: 'sonnet',
|
|
7
8
|
codex: 'gpt-5.5-mini',
|
|
@@ -25,7 +26,8 @@ const SAFE_KIMI_MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._/:-]{0,127}$/;
|
|
|
25
26
|
* Resolve a preset into provider-native identifiers. Kimi currently exposes no
|
|
26
27
|
* Core-defined cost/capability tier mapping, so every named preset resolves to
|
|
27
28
|
* its explicit `k3` default. User-supplied exact identifiers are handled later
|
|
28
|
-
* and are never interpreted as Claude aliases.
|
|
29
|
+
* and are never interpreted as Claude aliases. No preset carries per-role
|
|
30
|
+
* overrides: Core ships no role ids, so `models.overrides` is Desktop's to fill.
|
|
29
31
|
*/
|
|
30
32
|
export function resolveProviderModelConfig(provider, preset = 'balanced') {
|
|
31
33
|
if (provider === 'claude') {
|
|
@@ -33,11 +35,7 @@ export function resolveProviderModelConfig(provider, preset = 'balanced') {
|
|
|
33
35
|
return { preset, defaults: { model: 'haiku' }, overrides: {} };
|
|
34
36
|
}
|
|
35
37
|
if (preset === 'max') {
|
|
36
|
-
return {
|
|
37
|
-
preset,
|
|
38
|
-
defaults: { model: 'sonnet' },
|
|
39
|
-
overrides: { 'sr-architect': 'opus' },
|
|
40
|
-
};
|
|
38
|
+
return { preset, defaults: { model: 'sonnet' }, overrides: {} };
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
41
|
return {
|
|
@@ -109,13 +107,18 @@ export function validateInstallConfig(raw) {
|
|
|
109
107
|
// NOTE: a legacy `tier` field (`full`/`quick`) may still be present in pre-v5
|
|
110
108
|
// configs. It is intentionally ignored (not rejected and not carried forward)
|
|
111
109
|
// — v5 has no install tiers.
|
|
110
|
+
// The `agents` section is OPTIONAL and deprecated: roles are runtime-defined
|
|
111
|
+
// since Core 6.3. When present it is still validated for shape (safe ids, no
|
|
112
|
+
// overlap, known preset) so a malformed file fails fast, and a non-empty
|
|
113
|
+
// selection logs one warning instead of being rejected — Desktop builds
|
|
114
|
+
// paired with an older Core still write it.
|
|
112
115
|
const agents = doc.agents;
|
|
113
116
|
let selectedAgents = [];
|
|
114
117
|
let excludedAgents;
|
|
115
|
-
if (!agents || typeof agents !== 'object') {
|
|
116
|
-
errors.push(`
|
|
118
|
+
if (doc.agents !== undefined && (!agents || typeof agents !== 'object' || Array.isArray(agents))) {
|
|
119
|
+
errors.push(`'agents' must be a mapping`);
|
|
117
120
|
}
|
|
118
|
-
else {
|
|
121
|
+
else if (agents) {
|
|
119
122
|
if (!Array.isArray(agents.selected)) {
|
|
120
123
|
errors.push(`'agents.selected' must be a list`);
|
|
121
124
|
}
|
|
@@ -182,6 +185,10 @@ export function validateInstallConfig(raw) {
|
|
|
182
185
|
if (errors.length > 0) {
|
|
183
186
|
throw new InvalidConfigError(errors);
|
|
184
187
|
}
|
|
188
|
+
if (selectedAgents.length > 0) {
|
|
189
|
+
warn(`install-config.yaml 'agents.selected' is ignored since Core 6.3: roles are ` +
|
|
190
|
+
`runtime-defined and no role file is installed (${selectedAgents.join(', ')}).`);
|
|
191
|
+
}
|
|
185
192
|
const preset = (modelPreset ?? agents?.preset ?? 'balanced');
|
|
186
193
|
const resolvedModels = resolveProviderModelConfig(provider, preset);
|
|
187
194
|
if (typeof modelDefaults?.model === 'string') {
|
|
@@ -193,18 +200,18 @@ export function validateInstallConfig(raw) {
|
|
|
193
200
|
const result = {
|
|
194
201
|
version: 1,
|
|
195
202
|
provider,
|
|
196
|
-
agents: {
|
|
197
|
-
selected: selectedAgents,
|
|
198
|
-
},
|
|
199
203
|
models: resolvedModels,
|
|
200
204
|
};
|
|
201
205
|
// NOTE: a legacy `agent_teams` field may still be present in older configs.
|
|
202
206
|
// It is intentionally ignored (not rejected) for backward compatibility.
|
|
203
|
-
if (agents
|
|
204
|
-
result.agents
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
if (agents) {
|
|
208
|
+
result.agents = { selected: selectedAgents };
|
|
209
|
+
if (agents.preset !== undefined) {
|
|
210
|
+
result.agents.preset = agents.preset;
|
|
211
|
+
}
|
|
212
|
+
if (excludedAgents !== undefined) {
|
|
213
|
+
result.agents.excluded = excludedAgents;
|
|
214
|
+
}
|
|
208
215
|
}
|
|
209
216
|
return result;
|
|
210
217
|
}
|
|
@@ -1,22 +1,4 @@
|
|
|
1
1
|
import type { Provider } from './provider-detect.js';
|
|
2
|
-
/**
|
|
3
|
-
* The three baseline agents — the COMPLETE set of agents the installer
|
|
4
|
-
* ships. The implement pipeline depends on all three. Any additional agent
|
|
5
|
-
* comes from a user-authored profile (`custom-*`), never the installer.
|
|
6
|
-
*
|
|
7
|
-
* Mirrors the required built-in roles in schemas/agent-runtime.schema.json
|
|
8
|
-
* (`agents`, with the sr- prefix in installed files); keep both in sync.
|
|
9
|
-
*/
|
|
10
|
-
export declare const CORE_AGENTS: Set<string>;
|
|
11
|
-
/**
|
|
12
|
-
* Rewrite every literal `Skill("opsx:<id>"[, …])` call in a Claude-authored agent
|
|
13
|
-
* body into the Gemini `activate_skill(name="…")` form. Positional skill input
|
|
14
|
-
* (e.g. `"<specName>"`) is dropped because `activate_skill` takes only `name` and
|
|
15
|
-
* the surrounding persona prose already carries the context. Unknown ids are left
|
|
16
|
-
* untouched (better a visible stale ref than a silent `name="undefined"`). This
|
|
17
|
-
* runs ONLY on the gemini render path; Claude/Codex keep the `Skill(...)` form.
|
|
18
|
-
*/
|
|
19
|
-
export declare function translateOpsxSkillCallsForGemini(body: string): string;
|
|
20
2
|
/**
|
|
21
3
|
* Port shared Claude-authored prose to Kimi's directory-skill contract.
|
|
22
4
|
*
|
|
@@ -28,7 +10,6 @@ export declare function translateOpsxSkillCallsForGemini(body: string): string;
|
|
|
28
10
|
* This is render-only; canonical Claude/Codex/Gemini templates stay unchanged.
|
|
29
11
|
*/
|
|
30
12
|
export declare function translateClaudeTextForKimi(body: string): string;
|
|
31
|
-
export declare function geminiAgentLimitMetadata(env?: NodeJS.ProcessEnv): string[];
|
|
32
13
|
/**
|
|
33
14
|
* Phase 2 + Phase 3 of init:
|
|
34
15
|
* - Detect prior installation state (.claude/.codex/openspec already present).
|
|
@@ -37,9 +18,11 @@ export declare function geminiAgentLimitMetadata(env?: NodeJS.ProcessEnv): strin
|
|
|
37
18
|
* staging dir that placement copies from and `update` diffs against).
|
|
38
19
|
* - Ensure `.gitignore` excludes the runtime artefacts.
|
|
39
20
|
*
|
|
40
|
-
* Placement (`placeArtefacts`) then
|
|
41
|
-
* the user's live
|
|
42
|
-
* the installer finishes in one pass — no follow-up
|
|
21
|
+
* Placement (`placeArtefacts`) then renders the staged command templates
|
|
22
|
+
* directly into the user's live provider dir (`.claude/commands/specrails/`,
|
|
23
|
+
* `.codex/skills/`, …) so the installer finishes in one pass — no follow-up
|
|
24
|
+
* wizard required. Roles are never placed: the programmatic runtime defines
|
|
25
|
+
* them (`src/agent-runtime/prompts.ts`).
|
|
43
26
|
*/
|
|
44
27
|
interface ScaffoldInput {
|
|
45
28
|
/** Absolute path to the specrails-core package (installed via npx). */
|
|
@@ -60,25 +43,6 @@ interface ScaffoldInput {
|
|
|
60
43
|
provider: Provider;
|
|
61
44
|
/** Derived directory name (`.claude` or `.codex`). */
|
|
62
45
|
providerDir: string;
|
|
63
|
-
/** Optional explicit allow-list used by config-driven installs. */
|
|
64
|
-
selectedAgents?: string[];
|
|
65
|
-
/**
|
|
66
|
-
* When false, the static-placement helpers do NOT create the per-workspace
|
|
67
|
-
* mutable seeds (agent-memory dirs, gemini headless acknowledgments). Used by
|
|
68
|
-
* `installFramework` so the SHARED framework copy stays purely provider-static
|
|
69
|
-
* — the project layer is seeded separately by `assembleProjectWorkspace`.
|
|
70
|
-
* Defaults to true (legacy in-place behaviour for `scaffoldInstallation`).
|
|
71
|
-
*/
|
|
72
|
-
seedProjectDirs?: boolean;
|
|
73
|
-
/**
|
|
74
|
-
* When true, place EVERY agent template (the full superset) regardless of
|
|
75
|
-
* `selectedAgents`. Used by `installFramework` so
|
|
76
|
-
* the SHARED framework store is a superset that ANY project's selection can
|
|
77
|
-
* link from — per-project agent filtering then happens at the workspace LINK
|
|
78
|
-
* step (`linkAgentFiles`), not at materialization. Defaults to false (legacy
|
|
79
|
-
* selection-honouring placement for in-place `scaffoldInstallation`).
|
|
80
|
-
*/
|
|
81
|
-
materializeAllAgents?: boolean;
|
|
82
46
|
}
|
|
83
47
|
interface ScaffoldResult {
|
|
84
48
|
existingSetup: boolean;
|
|
@@ -106,8 +70,6 @@ interface InstallFrameworkInput {
|
|
|
106
70
|
providerDir: string;
|
|
107
71
|
/** Framework version (the `<version>/` segment). */
|
|
108
72
|
version: string;
|
|
109
|
-
/** Optional explicit agent allow-list (kept for parity with scaffold). */
|
|
110
|
-
selectedAgents?: string[];
|
|
111
73
|
}
|
|
112
74
|
interface InstallFrameworkResult {
|
|
113
75
|
/** `<frameworkDir>/<version>/<providerDir>` — root of the static subtree. */
|
|
@@ -130,8 +92,8 @@ export declare function frameworkMaterializationProblem(versionDir: string, vers
|
|
|
130
92
|
* `<frameworkDir>/<version>/<providerDir>/` (+ `<version>/setup-templates/`).
|
|
131
93
|
* Idempotent: when the providerDir already exists with a matching stamp it is a
|
|
132
94
|
* no-op (the second workspace assemble re-uses the same copy). Writes NO
|
|
133
|
-
* per-workspace state (no
|
|
134
|
-
*
|
|
95
|
+
* per-workspace state (no project-named instruction files) — those are seeded
|
|
96
|
+
* by `assembleProjectWorkspace`.
|
|
135
97
|
*/
|
|
136
98
|
export declare function installFramework(input: InstallFrameworkInput): InstallFrameworkResult;
|
|
137
99
|
/**
|
|
@@ -150,26 +112,18 @@ interface AssembleProjectWorkspaceInput {
|
|
|
150
112
|
providerDir: string;
|
|
151
113
|
/** Framework version (used for the manifest record). */
|
|
152
114
|
version: string;
|
|
153
|
-
/** The user's real repo (drives PROJECT_NAME
|
|
115
|
+
/** The user's real repo (drives PROJECT_NAME). */
|
|
154
116
|
codeRoot: string;
|
|
155
117
|
/** specrails-core package dir (for the manifest hash sources). */
|
|
156
118
|
scriptDir: string;
|
|
157
119
|
/**
|
|
158
|
-
*
|
|
159
|
-
* into the workspace (`linkAgentFiles`) AND which agent-memory dirs are seeded.
|
|
160
|
-
* Undefined = the CORE trio only (the lean default). The SHARED framework store
|
|
161
|
-
* is always the full superset; this is where per-project filtering happens.
|
|
162
|
-
*/
|
|
163
|
-
selectedAgents?: string[];
|
|
164
|
-
/**
|
|
165
|
-
* When true, the static provider subtrees (`agents`/`commands`/`skills`/`rules`)
|
|
120
|
+
* When true, the static provider subtrees (`commands`/`skills`/`specrails`)
|
|
166
121
|
* and the settings file are COPIED as real files from the framework store into
|
|
167
122
|
* the workspace instead of SYMLINKED. Used by the in-repo standalone install
|
|
168
123
|
* (`init`/`update` with `artifactRoot === codeRoot`) so the repo gets real,
|
|
169
124
|
* committable files — a symlink into `$HOME/.specrails/framework` would be
|
|
170
125
|
* invisible to a standalone user's `claude`/`codex`/`gemini`/`kimi` running in the
|
|
171
|
-
* repo. The PROJECT layer (
|
|
172
|
-
* either way. Defaults to false (relocated workspaces symlink — the desktop /
|
|
126
|
+
* repo. The PROJECT layer (manifest, instruction files) is real either way. Defaults to false (relocated workspaces symlink — the desktop /
|
|
173
127
|
* `--relocate` path).
|
|
174
128
|
*/
|
|
175
129
|
copyStatics?: boolean;
|
|
@@ -177,34 +131,28 @@ interface AssembleProjectWorkspaceInput {
|
|
|
177
131
|
interface AssembleProjectWorkspaceResult {
|
|
178
132
|
/** Per-linked-subtree mechanism, for diagnostics (copy-fallback loses O(1) swap). */
|
|
179
133
|
links: Record<string, 'symlink' | 'junction' | 'copy'>;
|
|
180
|
-
/** Agent ids whose memory dirs were seeded as real writable dirs. */
|
|
181
|
-
seededMemoryAgents: string[];
|
|
182
134
|
}
|
|
183
135
|
/**
|
|
184
136
|
* Assemble a project workspace with NO network and NO re-materialization: (a)
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* files). `
|
|
137
|
+
* prune the framework-owned `sr-*` role artifacts an older Core linked or
|
|
138
|
+
* copied into the workspace, (b) SYMLINK the static providerDir subtrees from
|
|
139
|
+
* `<frameworkDir>/current/<providerDir>/` into `<workspace>/<providerDir>/`,
|
|
140
|
+
* then (c) seed the PROJECT layer as real writable files (the manifest,
|
|
141
|
+
* project-named instruction/settings files). Reserved `custom-*` files are
|
|
142
|
+
* never touched.
|
|
190
143
|
*/
|
|
191
144
|
export declare function assembleProjectWorkspace(input: AssembleProjectWorkspaceInput): AssembleProjectWorkspaceResult;
|
|
192
145
|
/**
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* file). Writing it at install time makes the freshly-generated agents trusted
|
|
204
|
-
* with no prompt, for both `gemini` CLI and the desktop's headless spawns. The
|
|
205
|
-
* file is MERGED — other projects' and other agents' entries are preserved.
|
|
206
|
-
* Best-effort: any failure is swallowed by the caller (agents still work once
|
|
207
|
-
* acknowledged interactively).
|
|
146
|
+
* Remove the role artifacts an older Core linked or copied into a workspace:
|
|
147
|
+
* - claude, gemini: `agents/sr-*.md` (symlink or copy-fallback regular file)
|
|
148
|
+
* - codex: `skills/rails/sr-*` and the `rails/` container once empty
|
|
149
|
+
* - kimi: `skills/sr-*`
|
|
150
|
+
*
|
|
151
|
+
* Keyed strictly by NAME, never by content: `custom-*` (the reserved
|
|
152
|
+
* user/Desktop region) and any unknown name are left byte-untouched. A
|
|
153
|
+
* subtree that is itself a symlink into the shared framework store is skipped —
|
|
154
|
+
* the store is Core-owned and rebuilt by `installFramework`, so pruning through
|
|
155
|
+
* the link would only reach into another version's files.
|
|
208
156
|
*/
|
|
209
|
-
export declare function
|
|
157
|
+
export declare function pruneStaleRoleArtifacts(workspaceProviderDir: string, provider: Provider): void;
|
|
210
158
|
export {};
|