@opengsd/gsd-core 1.5.0-rc.2 → 1.5.0-rc.4
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/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-advisor-researcher.md +1 -1
- package/agents/gsd-assumptions-analyzer.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.md +1 -1
- package/agents/gsd-codebase-mapper.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-writer.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +1 -1
- package/agents/gsd-integration-checker.md +1 -1
- package/agents/gsd-mempalace-curator.md +47 -0
- package/agents/gsd-nyquist-auditor.md +1 -0
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +1 -1
- package/agents/gsd-planner.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.md +55 -2
- package/agents/gsd-security-auditor.md +1 -0
- package/agents/gsd-ui-auditor.md +1 -1
- package/agents/gsd-ui-checker.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +13 -2
- package/bin/install.js +61 -64
- package/commands/gsd/mempalace-capture.md +71 -0
- package/commands/gsd/mempalace-recall.md +102 -0
- package/commands/gsd/ns-context.md +4 -2
- package/commands/gsd/progress.md +2 -1
- package/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +277 -95
- package/gsd-core/bin/lib/active-workstream-store.cjs +6 -0
- package/gsd-core/bin/lib/capability-activation.cjs +86 -0
- package/gsd-core/bin/lib/capability-registry.cjs +1468 -11
- package/gsd-core/bin/lib/capability-state.cjs +128 -21
- package/gsd-core/bin/lib/capability-writer.cjs +354 -0
- package/gsd-core/bin/lib/check-command-router.cjs +328 -1
- package/gsd-core/bin/lib/clusters.cjs +2 -0
- package/gsd-core/bin/lib/command-roster.cjs +19 -0
- package/gsd-core/bin/lib/commands.cjs +33 -10
- package/gsd-core/bin/lib/config-loader.cjs +7 -8
- package/gsd-core/bin/lib/config-schema.cjs +32 -3
- package/gsd-core/bin/lib/config.cjs +81 -26
- package/gsd-core/bin/lib/core.cjs +5 -2
- package/gsd-core/bin/lib/edge-probe.cjs +25 -2
- package/gsd-core/bin/lib/frontmatter.cjs +53 -1
- package/gsd-core/bin/lib/git-base-branch.cjs +194 -0
- package/gsd-core/bin/lib/init.cjs +36 -11
- package/gsd-core/bin/lib/install-profiles.cjs +57 -1
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +157 -16
- package/gsd-core/bin/lib/model-resolver.cjs +47 -5
- package/gsd-core/bin/lib/phase.cjs +99 -23
- package/gsd-core/bin/lib/plan-drift-guard.cjs +117 -0
- package/gsd-core/bin/lib/probe-core.cjs +117 -1
- package/gsd-core/bin/lib/profile-output.cjs +45 -4
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +13 -3
- package/gsd-core/bin/lib/roadmap.cjs +97 -7
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +1946 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +54 -30
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +27 -19
- package/gsd-core/bin/lib/runtime-homes.cjs +26 -20
- package/gsd-core/bin/lib/state-command-router.cjs +15 -3
- package/gsd-core/bin/lib/state-document.cjs +46 -1
- package/gsd-core/bin/lib/state.cjs +461 -94
- package/gsd-core/bin/lib/verify.cjs +92 -8
- package/gsd-core/bin/lib/worktree-safety.cjs +2 -1
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -2
- package/gsd-core/bin/shared/config-schema.manifest.json +0 -18
- package/gsd-core/bin/shared/model-catalog.json +1 -0
- package/gsd-core/references/edge-probe.md +11 -0
- package/gsd-core/references/loop-hook-dispatch.md +61 -0
- package/gsd-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
- package/gsd-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
- package/gsd-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
- package/gsd-core/references/prohibition-probe.md +248 -0
- package/gsd-core/templates/config.json +1 -1
- package/gsd-core/templates/spec.md +14 -0
- package/gsd-core/workflows/audit-milestone.md +5 -3
- package/gsd-core/workflows/autonomous.md +10 -5
- package/gsd-core/workflows/code-review-fix.md +9 -7
- package/gsd-core/workflows/code-review.md +8 -6
- package/gsd-core/workflows/complete-milestone.md +1 -5
- package/gsd-core/workflows/discuss-phase.md +14 -0
- package/gsd-core/workflows/execute-phase.md +86 -146
- package/gsd-core/workflows/execute-plan.md +21 -6
- package/gsd-core/workflows/help/modes/full.md +7 -1
- package/gsd-core/workflows/new-project.md +3 -3
- package/gsd-core/workflows/next.md +50 -2
- package/gsd-core/workflows/pause-work.md +7 -1
- package/gsd-core/workflows/plan-phase.md +91 -221
- package/gsd-core/workflows/plan-review-convergence.md +14 -4
- package/gsd-core/workflows/pr-branch.md +4 -2
- package/gsd-core/workflows/profile-user.md +3 -1
- package/gsd-core/workflows/progress.md +58 -1
- package/gsd-core/workflows/quick.md +12 -8
- package/gsd-core/workflows/resume-project.md +17 -1
- package/gsd-core/workflows/review.md +19 -2
- package/gsd-core/workflows/secure-phase.md +4 -2
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/settings.md +27 -1
- package/gsd-core/workflows/ship.md +58 -5
- package/gsd-core/workflows/spec-phase.md +75 -0
- package/gsd-core/workflows/validate-phase.md +4 -2
- package/gsd-core/workflows/verify-phase.md +14 -4
- package/gsd-core/workflows/verify-work.md +27 -11
- package/hooks/dist/gsd-ensure-canonical-path.js +305 -0
- package/hooks/dist/gsd-statusline.js +1 -1
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-ensure-canonical-path.js +305 -0
- package/hooks/gsd-statusline.js +1 -1
- package/hooks/hooks.json +1 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +5 -4
- package/scripts/affected-tests-lib.cjs +16 -4
- package/scripts/build-hooks.js +7 -0
- package/scripts/changeset/new.cjs +17 -3
- package/scripts/fix-slash-commands.cjs +15 -3
- package/scripts/gen-capability-registry.cjs +373 -49
- package/scripts/gen-inventory-manifest.cjs +1 -4
- package/scripts/gen-loop-host-contract.cjs +55 -0
- package/scripts/issue-version-gate.cjs +140 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +327 -0
- package/scripts/lint-allow-test-rule-refs.cjs +162 -0
- package/scripts/lint-test-file-count.allowlist.json +14 -0
- package/scripts/mutation-matrix.cjs +108 -7
- package/scripts/pr-target-policy.cjs +63 -0
- package/scripts/release-tarball-smoke.cjs +7 -1
- package/scripts/research-profiles.cjs +5 -5
- package/scripts/run-tests.cjs +178 -17
|
@@ -6,9 +6,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
* Runtime artifact layout module — resolves the artifact directory shapes
|
|
7
7
|
* (commands, agents, skills) for each supported runtime.
|
|
8
8
|
*
|
|
9
|
-
* grok is intentionally absent: it is in runtime-homes.cjs but
|
|
10
|
-
*
|
|
11
|
-
* runtime was added
|
|
9
|
+
* grok is intentionally absent: it is in runtime-homes.cjs but has no runtime
|
|
10
|
+
* capability descriptor. The TypeError on unknown runtime is the loud-fail
|
|
11
|
+
* signal that a runtime was added without an artifact layout descriptor.
|
|
12
12
|
*
|
|
13
13
|
* ADR-457 build-at-publish: the hand-written bin/lib/runtime-artifact-layout.cjs
|
|
14
14
|
* collapsed to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
|
|
@@ -19,7 +19,10 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
19
19
|
const node_os_1 = __importDefault(require("node:os"));
|
|
20
20
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
21
21
|
const installProfiles = require("./install-profiles.cjs");
|
|
22
|
-
const { stageSkillsForProfile, stageAgentsForProfile, stageSkillsForRuntimeAsSkills, stageCommandsForRuntimeFlat, } = installProfiles;
|
|
22
|
+
const { stageSkillsForProfile, stageAgentsForProfile, stageAgentsForRuntimeWithConverter, stageSkillsForRuntimeAsSkills, stageCommandsForRuntimeFlat, } = installProfiles;
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
24
|
+
const runtimeArtifactConversion = require("./runtime-artifact-conversion.cjs");
|
|
25
|
+
const conversionExports = runtimeArtifactConversion;
|
|
23
26
|
// In .cts (CommonJS output) files, `require` is available as a global.
|
|
24
27
|
const _require = require;
|
|
25
28
|
/**
|
|
@@ -125,14 +128,6 @@ function findAgentsSourceRoot(runtimeConfigDir) {
|
|
|
125
128
|
throw new Error(`findAgentsSourceRoot: could not locate agents/ from ${__dirname}`);
|
|
126
129
|
}
|
|
127
130
|
// ---------------------------------------------------------------------------
|
|
128
|
-
// Allowlisted runtimes
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
const ALLOWED_RUNTIMES = new Set([
|
|
131
|
-
'claude', 'cursor', 'gemini', 'codex', 'copilot', 'antigravity',
|
|
132
|
-
'windsurf', 'augment', 'trae', 'qwen', 'hermes', 'codebuddy',
|
|
133
|
-
'cline', 'kimi', 'opencode', 'kilo',
|
|
134
|
-
]);
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
131
|
// Layout table builders
|
|
137
132
|
// ---------------------------------------------------------------------------
|
|
138
133
|
function commandsKind(destSubpath, prefix, configDir) {
|
|
@@ -151,14 +146,42 @@ function agentsKind(destSubpath, prefix, configDir) {
|
|
|
151
146
|
stage: (resolved) => stageAgentsForProfile(findAgentsSourceRoot(configDir), resolved),
|
|
152
147
|
};
|
|
153
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a converted-agents kind descriptor for runtimes whose agent `.md` files
|
|
151
|
+
* need runtime-specific frontmatter/body conversion (e.g. Copilot, Cursor, Codex).
|
|
152
|
+
*
|
|
153
|
+
* Unlike `agentsKind` (which raw-copies source files), this kind applies
|
|
154
|
+
* `converterName` from Runtime Artifact Conversion exports to each agent file
|
|
155
|
+
* during staging, writing flat `${name}.md` files to the staged directory.
|
|
156
|
+
*
|
|
157
|
+
* Agent filenames are preserved verbatim (the prefix is already embedded in the
|
|
158
|
+
* agent stem — e.g. `gsd-planner.md`).
|
|
159
|
+
*
|
|
160
|
+
* Mirrors the `convertedCommandsKind` pattern (#785).
|
|
161
|
+
*
|
|
162
|
+
* @param destSubpath destination subpath within configDir (e.g. 'agents')
|
|
163
|
+
* @param prefix filename prefix (informational; not applied here)
|
|
164
|
+
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
|
165
|
+
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
|
166
|
+
*/
|
|
167
|
+
function convertedAgentsKind(destSubpath, prefix, converterName, configDir) {
|
|
168
|
+
return {
|
|
169
|
+
kind: 'agents',
|
|
170
|
+
destSubpath,
|
|
171
|
+
prefix,
|
|
172
|
+
stage: (resolved) => {
|
|
173
|
+
const converter = conversionExports[converterName];
|
|
174
|
+
return stageAgentsForRuntimeWithConverter(findAgentsSourceRoot(configDir), resolved, converter);
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
154
178
|
function kimiAgentsKind(destSubpath, prefix, configDir) {
|
|
155
179
|
return {
|
|
156
180
|
kind: 'kimi-agents',
|
|
157
181
|
destSubpath,
|
|
158
182
|
prefix,
|
|
159
183
|
stage: (resolved) => {
|
|
160
|
-
const
|
|
161
|
-
const buildKimiAgentArtifacts = installExports['buildKimiAgentArtifacts'];
|
|
184
|
+
const buildKimiAgentArtifacts = conversionExports['buildKimiAgentArtifacts'];
|
|
162
185
|
const stagedAgents = stageAgentsForProfile(findAgentsSourceRoot(configDir), resolved);
|
|
163
186
|
const subagents = [];
|
|
164
187
|
if (node_fs_1.default.existsSync(stagedAgents)) {
|
|
@@ -193,7 +216,7 @@ function kimiAgentsKind(destSubpath, prefix, configDir) {
|
|
|
193
216
|
*
|
|
194
217
|
* @param destSubpath
|
|
195
218
|
* @param prefix
|
|
196
|
-
* @param converterName name of converter function in
|
|
219
|
+
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
|
197
220
|
* @param runtime canonical runtime ID (gates Hermes/Qwen branding in converter)
|
|
198
221
|
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
|
199
222
|
* @param nested if true, nest concrete skills under their ns-* routers (#69)
|
|
@@ -208,15 +231,16 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
208
231
|
destSubpath,
|
|
209
232
|
prefix,
|
|
210
233
|
stage: (resolved) => {
|
|
211
|
-
const
|
|
212
|
-
const realConverter = installExports[converterName];
|
|
234
|
+
const realConverter = conversionExports[converterName];
|
|
213
235
|
// Compute cmdNames once per stage call for performance (#3583).
|
|
214
236
|
// Extra trailing args are ignored by converters that don't need them. The
|
|
215
237
|
// isGlobal flag is the 5th positional (NOT the 3rd): the 3rd positional is
|
|
216
238
|
// `runtime` for the claude/kimi/cline converters, so the scope-aware
|
|
217
239
|
// converters (antigravity, copilot) read isGlobal from position 5 to avoid
|
|
218
240
|
// colliding with `runtime` and always taking the global branch.
|
|
219
|
-
const cmdNames =
|
|
241
|
+
const cmdNames = conversionExports.readGsdCommandNames
|
|
242
|
+
? conversionExports.readGsdCommandNames()
|
|
243
|
+
: [];
|
|
220
244
|
const isGlobal = scope === 'global';
|
|
221
245
|
const wrappedConverter = (content, skillName) => realConverter(content, skillName, runtime, cmdNames, isGlobal);
|
|
222
246
|
return stageSkillsForRuntimeAsSkills(findInstallSourceRoot(configDir), resolved, wrappedConverter, prefix, nested);
|
|
@@ -228,7 +252,7 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
228
252
|
* commands directory with per-file conversion (e.g. Cursor 1.6 slash commands).
|
|
229
253
|
*
|
|
230
254
|
* Unlike `commandsKind` (which passes raw source files through), this kind
|
|
231
|
-
* applies `converterName` from
|
|
255
|
+
* applies `converterName` from Runtime Artifact Conversion exports to each file during
|
|
232
256
|
* staging, writing flat `${prefix}${stem}.md` files to the staged directory.
|
|
233
257
|
*
|
|
234
258
|
* The staged files are then written by `_copyStaged` (commands branch) which
|
|
@@ -236,7 +260,7 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
236
260
|
*
|
|
237
261
|
* @param destSubpath destination subpath within configDir (e.g. 'commands')
|
|
238
262
|
* @param prefix filename prefix, e.g. 'gsd-'
|
|
239
|
-
* @param converterName name of converter function in
|
|
263
|
+
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
|
240
264
|
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
|
241
265
|
*/
|
|
242
266
|
function convertedCommandsKind(destSubpath, prefix, converterName, configDir) {
|
|
@@ -245,13 +269,11 @@ function convertedCommandsKind(destSubpath, prefix, converterName, configDir) {
|
|
|
245
269
|
destSubpath,
|
|
246
270
|
prefix,
|
|
247
271
|
stage: (resolved) => {
|
|
248
|
-
const
|
|
249
|
-
const converter = installExports[converterName];
|
|
272
|
+
const converter = conversionExports[converterName];
|
|
250
273
|
return stageCommandsForRuntimeFlat(findInstallSourceRoot(configDir), resolved, converter, prefix);
|
|
251
274
|
},
|
|
252
275
|
};
|
|
253
276
|
}
|
|
254
|
-
/** Lazy registry accessor — mirrors pattern from 5b/5c (runtime-homes.cts). */
|
|
255
277
|
function getRegistry() {
|
|
256
278
|
return _require('./capability-registry.cjs');
|
|
257
279
|
}
|
|
@@ -269,7 +291,10 @@ function dispatchKindEntry(entry, runtime, configDir, scope) {
|
|
|
269
291
|
}
|
|
270
292
|
return convertedCommandsKind(destSubpath, prefix, converter, configDir);
|
|
271
293
|
case 'agents':
|
|
272
|
-
|
|
294
|
+
if (converter == null) {
|
|
295
|
+
return agentsKind(destSubpath, prefix, configDir);
|
|
296
|
+
}
|
|
297
|
+
return convertedAgentsKind(destSubpath, prefix, converter, configDir);
|
|
273
298
|
case 'skills':
|
|
274
299
|
if (converter == null) {
|
|
275
300
|
throw new TypeError(`resolveRuntimeArtifactLayout: skills entry for '${runtime}' has converter=null (converter is required for skills)`);
|
|
@@ -288,22 +313,21 @@ function dispatchKindEntry(entry, runtime, configDir, scope) {
|
|
|
288
313
|
* instead of a hardcoded switch statement.
|
|
289
314
|
*/
|
|
290
315
|
function resolveRuntimeArtifactLayout(runtime, configDir, scope = 'global') {
|
|
316
|
+
return resolveRuntimeArtifactLayoutFromRegistry(getRegistry(), runtime, configDir, scope);
|
|
317
|
+
}
|
|
318
|
+
function resolveRuntimeArtifactLayoutFromRegistry(registry, runtime, configDir, scope = 'global') {
|
|
291
319
|
if (typeof configDir !== 'string' || configDir === '') {
|
|
292
320
|
throw new TypeError('configDir must be a non-empty string');
|
|
293
321
|
}
|
|
294
322
|
if (scope !== 'local' && scope !== 'global') {
|
|
295
323
|
throw new TypeError('scope must be "local" or "global"');
|
|
296
324
|
}
|
|
297
|
-
|
|
298
|
-
throw new TypeError(`Unknown runtime: '${runtime}' — add to runtime-artifact-layout.cjs table`);
|
|
299
|
-
}
|
|
300
|
-
const desc = getRegistry().runtimes[runtime]?.runtime?.artifactLayout;
|
|
325
|
+
const desc = registry.runtimes[runtime]?.runtime?.artifactLayout;
|
|
301
326
|
if (!desc) {
|
|
302
|
-
// Runtime is in ALLOWED_RUNTIMES but has no descriptor — reproduce old default: throw.
|
|
303
327
|
throw new TypeError(`Unknown runtime: '${runtime}' — add to runtime-artifact-layout.cjs table`);
|
|
304
328
|
}
|
|
305
329
|
const entries = desc[scope] ?? [];
|
|
306
330
|
const kinds = entries.map((entry) => dispatchKindEntry(entry, runtime, configDir, scope));
|
|
307
331
|
return { runtime, configDir, scope, kinds };
|
|
308
332
|
}
|
|
309
|
-
module.exports = { resolveRuntimeArtifactLayout, findInstallSourceRoot, getInstallExports };
|
|
333
|
+
module.exports = { resolveRuntimeArtifactLayout, resolveRuntimeArtifactLayoutFromRegistry, findInstallSourceRoot, getInstallExports };
|
|
@@ -27,9 +27,8 @@
|
|
|
27
27
|
*/
|
|
28
28
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
29
|
const { runtimes } = require('./capability-registry.cjs');
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
30
|
+
/** Valid sandboxTier enum values — mirrors the gen-capability-registry validator vocabulary. */
|
|
31
|
+
const VALID_SANDBOX_TIERS = new Set(['none', 'codex-agent-sandbox']);
|
|
33
32
|
/** The complete set of 16 supported runtimes for config-adapter dispatch. */
|
|
34
33
|
const ALLOWED_CONFIG_RUNTIMES = new Set(Object.entries(runtimes)
|
|
35
34
|
.filter(([, cap]) => cap && cap.runtime && typeof cap.runtime['installSurface'] === 'string')
|
|
@@ -63,6 +62,29 @@ function resolveRuntimeConfigIntent(runtime) {
|
|
|
63
62
|
finishPermissionWriter: permissionWriter == null ? null : permissionWriter,
|
|
64
63
|
};
|
|
65
64
|
}
|
|
65
|
+
function resolveInstallPlanFromRuntimes(runtimeDescriptors, runtime) {
|
|
66
|
+
const desc = runtimeDescriptors[runtime]?.runtime;
|
|
67
|
+
if (!desc)
|
|
68
|
+
throw new TypeError(`Unknown runtime for install plan: ${runtime}`);
|
|
69
|
+
if (desc['hooksSurface'] == null) {
|
|
70
|
+
throw new TypeError(`runtime.hooksSurface is required for install plan: ${runtime}`);
|
|
71
|
+
}
|
|
72
|
+
const sandboxTier = desc['sandboxTier'];
|
|
73
|
+
if (typeof sandboxTier !== 'string' || !VALID_SANDBOX_TIERS.has(sandboxTier)) {
|
|
74
|
+
throw new TypeError(`Runtime '${runtime}' has a missing or invalid sandboxTier descriptor axis: ${JSON.stringify(sandboxTier)}`);
|
|
75
|
+
}
|
|
76
|
+
const permissionWriter = desc['permissionWriter'];
|
|
77
|
+
return {
|
|
78
|
+
runtime,
|
|
79
|
+
installSurface: desc['installSurface'],
|
|
80
|
+
writesSharedSettings: desc['writesSharedSettings'],
|
|
81
|
+
finishPermissionWriter: permissionWriter == null ? null : permissionWriter,
|
|
82
|
+
hookEvents: desc['hookEvents'],
|
|
83
|
+
extendedHookEvents: Array.isArray(desc['extendedHookEvents']) ? [...desc['extendedHookEvents']] : [],
|
|
84
|
+
hooksSurface: desc['hooksSurface'],
|
|
85
|
+
sandboxTier,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
66
88
|
/**
|
|
67
89
|
* Resolve the complete install plan for a given runtime.
|
|
68
90
|
*
|
|
@@ -76,20 +98,6 @@ function resolveRuntimeConfigIntent(runtime) {
|
|
|
76
98
|
* @throws {TypeError} if runtime is not a known supported runtime.
|
|
77
99
|
*/
|
|
78
100
|
function resolveInstallPlan(runtime) {
|
|
79
|
-
|
|
80
|
-
if (!desc)
|
|
81
|
-
throw new TypeError(`Unknown runtime for install plan: ${runtime}`);
|
|
82
|
-
const configIntent = resolveRuntimeConfigIntent(runtime);
|
|
83
|
-
return {
|
|
84
|
-
runtime,
|
|
85
|
-
installSurface: configIntent.installSurface,
|
|
86
|
-
writesSharedSettings: configIntent.writesSharedSettings,
|
|
87
|
-
finishPermissionWriter: configIntent.finishPermissionWriter,
|
|
88
|
-
hookEvents: desc['hookEvents'],
|
|
89
|
-
extendedHookEvents: Array.isArray(desc['extendedHookEvents']) ? desc['extendedHookEvents'] : [],
|
|
90
|
-
hooksSurface: desc['hooksSurface'] != null
|
|
91
|
-
? desc['hooksSurface']
|
|
92
|
-
: ((runtime === 'opencode' || runtime === 'kilo') ? 'none' : 'settings-json'),
|
|
93
|
-
};
|
|
101
|
+
return resolveInstallPlanFromRuntimes(runtimes, runtime);
|
|
94
102
|
}
|
|
95
|
-
module.exports = { resolveRuntimeConfigIntent, resolveInstallPlan, ALLOWED_CONFIG_RUNTIMES, INSTALL_SURFACES };
|
|
103
|
+
module.exports = { resolveRuntimeConfigIntent, resolveInstallPlan, resolveInstallPlanFromRuntimes, ALLOWED_CONFIG_RUNTIMES, INSTALL_SURFACES };
|
|
@@ -38,6 +38,7 @@ exports.resolveConfigHomeFromDescriptor = resolveConfigHomeFromDescriptor;
|
|
|
38
38
|
exports.resolveAntigravityGlobalDir = resolveAntigravityGlobalDir;
|
|
39
39
|
exports.resolveKimiGlobalDir = resolveKimiGlobalDir;
|
|
40
40
|
exports.getGlobalConfigDir = getGlobalConfigDir;
|
|
41
|
+
exports.resolveSkillsBaseFromDescriptor = resolveSkillsBaseFromDescriptor;
|
|
41
42
|
exports.getGlobalSkillsBase = getGlobalSkillsBase;
|
|
42
43
|
exports.getGlobalSkillDir = getGlobalSkillDir;
|
|
43
44
|
exports.getGlobalSkillDisplayPath = getGlobalSkillDisplayPath;
|
|
@@ -54,6 +55,17 @@ function expandTilde(p) {
|
|
|
54
55
|
return node_path_1.default.join(node_os_1.default.homedir(), p.slice(1));
|
|
55
56
|
return p;
|
|
56
57
|
}
|
|
58
|
+
function resolveDescriptorWithOptions(configHome) {
|
|
59
|
+
return resolveConfigHomeFromDescriptor(configHome, {
|
|
60
|
+
env: process.env,
|
|
61
|
+
home: node_os_1.default.homedir(),
|
|
62
|
+
existsSync: node_fs_1.default.existsSync,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function getRegistry() {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
67
|
+
return require('./capability-registry.cjs');
|
|
68
|
+
}
|
|
57
69
|
/**
|
|
58
70
|
* Resolve a configHome descriptor to an absolute directory path.
|
|
59
71
|
*
|
|
@@ -209,15 +221,10 @@ function getGlobalConfigDir(runtime, explicitDir) {
|
|
|
209
221
|
return env['GROK_AGENTS_HOME'] ? expandTilde(env['GROK_AGENTS_HOME']) : node_path_1.default.join(node_os_1.default.homedir(), '.agents');
|
|
210
222
|
}
|
|
211
223
|
// ── Descriptor-driven: look up in capability-registry ────────────────────
|
|
212
|
-
|
|
213
|
-
const { runtimes } = require('./capability-registry.cjs');
|
|
224
|
+
const { runtimes } = getRegistry();
|
|
214
225
|
const runtimeEntry = runtimes[runtime];
|
|
215
226
|
if (runtimeEntry?.runtime?.configHome) {
|
|
216
|
-
return
|
|
217
|
-
env: process.env,
|
|
218
|
-
home: node_os_1.default.homedir(),
|
|
219
|
-
existsSync: node_fs_1.default.existsSync,
|
|
220
|
-
});
|
|
227
|
+
return resolveDescriptorWithOptions(runtimeEntry.runtime.configHome);
|
|
221
228
|
}
|
|
222
229
|
// ── Default (unknown runtime → Claude fallback) ───────────────────────────
|
|
223
230
|
const env = process.env;
|
|
@@ -225,22 +232,21 @@ function getGlobalConfigDir(runtime, explicitDir) {
|
|
|
225
232
|
}
|
|
226
233
|
/**
|
|
227
234
|
* Return the global skills base directory for the given runtime.
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* Cline ≥ v3.48.0: <configDir>/skills (SKILL.md-based global skills — #782)
|
|
235
|
+
* Descriptor-backed runtimes derive the base home from configHome.skillsHome
|
|
236
|
+
* when present, then append the first global skills artifact destSubpath.
|
|
231
237
|
*/
|
|
238
|
+
function resolveSkillsBaseFromDescriptor(configHome, opts = {}, skillsDestSubpath = 'skills') {
|
|
239
|
+
const baseDescriptor = configHome.skillsHome ?? configHome;
|
|
240
|
+
const base = resolveConfigHomeFromDescriptor(baseDescriptor, opts);
|
|
241
|
+
return node_path_1.default.join(base, skillsDestSubpath);
|
|
242
|
+
}
|
|
232
243
|
function getGlobalSkillsBase(runtime) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
244
|
+
const runtimeEntry = getRegistry().runtimes[runtime];
|
|
245
|
+
const descriptor = runtimeEntry?.runtime;
|
|
246
|
+
const globalSkillsKind = descriptor?.artifactLayout?.global?.find((entry) => entry.kind === 'skills');
|
|
247
|
+
if (descriptor?.configHome && globalSkillsKind?.destSubpath) {
|
|
248
|
+
return resolveSkillsBaseFromDescriptor(descriptor.configHome, { env: process.env, home: node_os_1.default.homedir(), existsSync: node_fs_1.default.existsSync }, globalSkillsKind.destSubpath);
|
|
236
249
|
}
|
|
237
|
-
// Kilo Code discovers global skills from ~/.kilo/skills/ (HOME-relative),
|
|
238
|
-
// independent of the XDG-based config dir (~/.config/kilo) used for commands.
|
|
239
|
-
// See: https://kilo.ai/docs/customize/skills
|
|
240
|
-
// "Global skills are located in the `.kilo` directory within your Home
|
|
241
|
-
// directory: ~/.kilo/skills/"
|
|
242
|
-
if (runtime === 'kilo')
|
|
243
|
-
return node_path_1.default.join(node_os_1.default.homedir(), '.kilo', 'skills');
|
|
244
250
|
const configDir = getGlobalConfigDir(runtime);
|
|
245
251
|
return node_path_1.default.join(configDir, 'skills');
|
|
246
252
|
}
|
|
@@ -42,9 +42,10 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
42
42
|
args,
|
|
43
43
|
subcommands: ['load', 'complete-phase', ...command_aliases_cjs_1.STATE_SUBCOMMANDS.filter((s) => s !== 'load')],
|
|
44
44
|
defaultSubcommand: 'load',
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
// No SDK-only state subcommands remain: add-roadmap-evolution was the last
|
|
46
|
+
// holdout after the SDK retirement (ADR-0174) and is now implemented in CJS
|
|
47
|
+
// (handler below). See #1140.
|
|
48
|
+
unsupported: {},
|
|
48
49
|
error,
|
|
49
50
|
cwd,
|
|
50
51
|
raw,
|
|
@@ -113,6 +114,17 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
113
114
|
const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['text', 'text-file']);
|
|
114
115
|
state.cmdStateAddBlocker(cwd, { text: strArg(a, 'text'), text_file: strArg(a, 'text-file') }, raw);
|
|
115
116
|
},
|
|
117
|
+
'add-roadmap-evolution': () => {
|
|
118
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['phase', 'action', 'after', 'note', 'note-file'], ['urgent']);
|
|
119
|
+
state.cmdStateAddRoadmapEvolution(cwd, {
|
|
120
|
+
phase: strArg(a, 'phase'),
|
|
121
|
+
action: strArg(a, 'action'),
|
|
122
|
+
after: strArg(a, 'after'),
|
|
123
|
+
note: strArg(a, 'note'),
|
|
124
|
+
note_file: strArg(a, 'note-file'),
|
|
125
|
+
urgent: a['urgent'] === true,
|
|
126
|
+
}, raw);
|
|
127
|
+
},
|
|
116
128
|
'resolve-blocker': () => state.cmdStateResolveBlocker(cwd, strArg((0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['text']), 'text'), raw),
|
|
117
129
|
'record-session': () => {
|
|
118
130
|
const a = (0, command_arg_projection_cjs_1.parseNamedArgs)(args, ['stopped-at', 'resume-file']);
|
|
@@ -31,26 +31,71 @@ function existingProgressExceedsDerived(existingProgress, derivedProgress, key)
|
|
|
31
31
|
const derived = toFiniteNumber(derivedProgress[key]);
|
|
32
32
|
return existing !== null && derived !== null && existing > derived;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Return true if a pipe-table row's first cell is a separator cell (`---`
|
|
36
|
+
* variants) rather than a field name. Prevents the separator row
|
|
37
|
+
* `| --- | --- |` from being treated as a field named "---".
|
|
38
|
+
*/
|
|
39
|
+
function isTableSeparatorRow(firstCell) {
|
|
40
|
+
// A separator cell contains only dashes, colons (alignment hints), and whitespace.
|
|
41
|
+
return /^[\s\-:]+$/.test(firstCell.trim());
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a regex that matches a pipe-table row `| FieldName | value |` for the
|
|
45
|
+
* given (already-escaped) field name. The match is case-insensitive and
|
|
46
|
+
* tolerates variable amounts of whitespace around the cell contents.
|
|
47
|
+
*
|
|
48
|
+
* Capture group 1: leading pipe + whitespace before the field cell
|
|
49
|
+
* Capture group 2: the field name cell text (trimmed)
|
|
50
|
+
* Capture group 3: whitespace between field cell and separator pipe
|
|
51
|
+
* Capture group 4: the value cell text (trimmed)
|
|
52
|
+
* Capture group 5: trailing whitespace + closing pipe(s)
|
|
53
|
+
*
|
|
54
|
+
* We use a single-line match (`m` flag so ^ anchors work on each line) to
|
|
55
|
+
* avoid cross-row replacement.
|
|
56
|
+
*/
|
|
57
|
+
function tableRowPattern(escapedFieldName) {
|
|
58
|
+
return new RegExp(`^(\\|[ \\t]*)(${escapedFieldName})([ \\t]*\\|[ \\t]*)([^|\\n]*?)([ \\t]*\\|[ \\t]*)$`, 'im');
|
|
59
|
+
}
|
|
34
60
|
function stateExtractField(content, fieldName) {
|
|
35
61
|
const escaped = escapeRegex(fieldName);
|
|
62
|
+
// Bold inline format: **FieldName:** value
|
|
36
63
|
const boldPattern = new RegExp(`\\*\\*${escaped}:\\*\\*[ \\t]*(.+)`, 'i');
|
|
37
64
|
const boldMatch = content.match(boldPattern);
|
|
38
65
|
if (boldMatch)
|
|
39
66
|
return boldMatch[1].trim();
|
|
67
|
+
// Plain line-start format: FieldName: value
|
|
40
68
|
const plainPattern = new RegExp(`^${escaped}:[ \\t]*(.+)`, 'im');
|
|
41
69
|
const plainMatch = content.match(plainPattern);
|
|
42
|
-
|
|
70
|
+
if (plainMatch)
|
|
71
|
+
return plainMatch[1].trim();
|
|
72
|
+
// Pipe-table format: | FieldName | value |
|
|
73
|
+
// (Separator rows such as `| --- | --- |` are excluded.)
|
|
74
|
+
const tableMatch = content.match(tableRowPattern(escaped));
|
|
75
|
+
if (tableMatch && !isTableSeparatorRow(tableMatch[2]))
|
|
76
|
+
return tableMatch[4].trim();
|
|
77
|
+
return null;
|
|
43
78
|
}
|
|
44
79
|
function stateReplaceField(content, fieldName, newValue) {
|
|
45
80
|
const escaped = escapeRegex(fieldName);
|
|
81
|
+
// Bold inline format: **FieldName:** value
|
|
46
82
|
const boldPattern = new RegExp(`(\\*\\*${escaped}:\\*\\*\\s*)(.*)`, 'i');
|
|
47
83
|
if (boldPattern.test(content)) {
|
|
48
84
|
return content.replace(boldPattern, (_match, prefix) => `${prefix}${newValue}`);
|
|
49
85
|
}
|
|
86
|
+
// Plain line-start format: FieldName: value
|
|
50
87
|
const plainPattern = new RegExp(`(^${escaped}:\\s*)(.*)`, 'im');
|
|
51
88
|
if (plainPattern.test(content)) {
|
|
52
89
|
return content.replace(plainPattern, (_match, prefix) => `${prefix}${newValue}`);
|
|
53
90
|
}
|
|
91
|
+
// Pipe-table format: | FieldName | value |
|
|
92
|
+
// Preserve the surrounding pipe/whitespace structure; only swap the value cell.
|
|
93
|
+
const tblPat = tableRowPattern(escaped);
|
|
94
|
+
const tblMatch = content.match(tblPat);
|
|
95
|
+
if (tblMatch && !isTableSeparatorRow(tblMatch[2])) {
|
|
96
|
+
// Reconstruct the row, preserving the original surrounding whitespace/pipes.
|
|
97
|
+
return content.replace(tblPat, (_m, leadPipe, fieldCell, midPipe, _oldVal, trailPipe) => `${leadPipe}${fieldCell}${midPipe}${newValue}${trailPipe}`);
|
|
98
|
+
}
|
|
54
99
|
return null;
|
|
55
100
|
}
|
|
56
101
|
function stateReplaceFieldWithFallback(content, primary, fallback, value) {
|