@opengsd/gsd-core 1.5.0-rc.2 → 1.5.0-rc.3
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-mempalace-curator.md +47 -0
- package/bin/install.js +25 -7
- 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/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +110 -92
- 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 +31 -18
- 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 +1 -2
- package/gsd-core/bin/lib/core.cjs +5 -2
- package/gsd-core/bin/lib/init.cjs +8 -5
- package/gsd-core/bin/lib/install-profiles.cjs +2 -1
- 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 +71 -11
- 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.cjs +97 -7
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +1700 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +20 -28
- 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 +221 -35
- package/gsd-core/bin/lib/verify.cjs +19 -4
- 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/loop-hook-dispatch.md +61 -0
- package/gsd-core/templates/config.json +1 -1
- 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/discuss-phase.md +14 -0
- package/gsd-core/workflows/execute-phase.md +82 -143
- package/gsd-core/workflows/help/modes/full.md +3 -1
- package/gsd-core/workflows/new-project.md +3 -3
- package/gsd-core/workflows/plan-phase.md +89 -221
- package/gsd-core/workflows/profile-user.md +3 -1
- package/gsd-core/workflows/progress.md +58 -1
- package/gsd-core/workflows/quick.md +9 -6
- 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/ship.md +57 -0
- package/gsd-core/workflows/validate-phase.md +4 -2
- package/gsd-core/workflows/verify-work.md +27 -11
- package/package.json +3 -2
- package/scripts/affected-tests-lib.cjs +16 -4
- package/scripts/gen-capability-registry.cjs +359 -48
- 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 +326 -0
- package/scripts/lint-allow-test-rule-refs.cjs +162 -0
- package/scripts/lint-test-file-count.allowlist.json +8 -0
- package/scripts/release-tarball-smoke.cjs +7 -1
- package/scripts/run-tests.cjs +74 -14
|
@@ -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
|
|
@@ -20,6 +20,9 @@ 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
22
|
const { stageSkillsForProfile, stageAgentsForProfile, 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) {
|
|
@@ -157,8 +152,7 @@ function kimiAgentsKind(destSubpath, prefix, configDir) {
|
|
|
157
152
|
destSubpath,
|
|
158
153
|
prefix,
|
|
159
154
|
stage: (resolved) => {
|
|
160
|
-
const
|
|
161
|
-
const buildKimiAgentArtifacts = installExports['buildKimiAgentArtifacts'];
|
|
155
|
+
const buildKimiAgentArtifacts = conversionExports['buildKimiAgentArtifacts'];
|
|
162
156
|
const stagedAgents = stageAgentsForProfile(findAgentsSourceRoot(configDir), resolved);
|
|
163
157
|
const subagents = [];
|
|
164
158
|
if (node_fs_1.default.existsSync(stagedAgents)) {
|
|
@@ -193,7 +187,7 @@ function kimiAgentsKind(destSubpath, prefix, configDir) {
|
|
|
193
187
|
*
|
|
194
188
|
* @param destSubpath
|
|
195
189
|
* @param prefix
|
|
196
|
-
* @param converterName name of converter function in
|
|
190
|
+
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
|
197
191
|
* @param runtime canonical runtime ID (gates Hermes/Qwen branding in converter)
|
|
198
192
|
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
|
199
193
|
* @param nested if true, nest concrete skills under their ns-* routers (#69)
|
|
@@ -208,15 +202,16 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
208
202
|
destSubpath,
|
|
209
203
|
prefix,
|
|
210
204
|
stage: (resolved) => {
|
|
211
|
-
const
|
|
212
|
-
const realConverter = installExports[converterName];
|
|
205
|
+
const realConverter = conversionExports[converterName];
|
|
213
206
|
// Compute cmdNames once per stage call for performance (#3583).
|
|
214
207
|
// Extra trailing args are ignored by converters that don't need them. The
|
|
215
208
|
// isGlobal flag is the 5th positional (NOT the 3rd): the 3rd positional is
|
|
216
209
|
// `runtime` for the claude/kimi/cline converters, so the scope-aware
|
|
217
210
|
// converters (antigravity, copilot) read isGlobal from position 5 to avoid
|
|
218
211
|
// colliding with `runtime` and always taking the global branch.
|
|
219
|
-
const cmdNames =
|
|
212
|
+
const cmdNames = conversionExports.readGsdCommandNames
|
|
213
|
+
? conversionExports.readGsdCommandNames()
|
|
214
|
+
: [];
|
|
220
215
|
const isGlobal = scope === 'global';
|
|
221
216
|
const wrappedConverter = (content, skillName) => realConverter(content, skillName, runtime, cmdNames, isGlobal);
|
|
222
217
|
return stageSkillsForRuntimeAsSkills(findInstallSourceRoot(configDir), resolved, wrappedConverter, prefix, nested);
|
|
@@ -228,7 +223,7 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
228
223
|
* commands directory with per-file conversion (e.g. Cursor 1.6 slash commands).
|
|
229
224
|
*
|
|
230
225
|
* Unlike `commandsKind` (which passes raw source files through), this kind
|
|
231
|
-
* applies `converterName` from
|
|
226
|
+
* applies `converterName` from Runtime Artifact Conversion exports to each file during
|
|
232
227
|
* staging, writing flat `${prefix}${stem}.md` files to the staged directory.
|
|
233
228
|
*
|
|
234
229
|
* The staged files are then written by `_copyStaged` (commands branch) which
|
|
@@ -236,7 +231,7 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
236
231
|
*
|
|
237
232
|
* @param destSubpath destination subpath within configDir (e.g. 'commands')
|
|
238
233
|
* @param prefix filename prefix, e.g. 'gsd-'
|
|
239
|
-
* @param converterName name of converter function in
|
|
234
|
+
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
|
240
235
|
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
|
241
236
|
*/
|
|
242
237
|
function convertedCommandsKind(destSubpath, prefix, converterName, configDir) {
|
|
@@ -245,13 +240,11 @@ function convertedCommandsKind(destSubpath, prefix, converterName, configDir) {
|
|
|
245
240
|
destSubpath,
|
|
246
241
|
prefix,
|
|
247
242
|
stage: (resolved) => {
|
|
248
|
-
const
|
|
249
|
-
const converter = installExports[converterName];
|
|
243
|
+
const converter = conversionExports[converterName];
|
|
250
244
|
return stageCommandsForRuntimeFlat(findInstallSourceRoot(configDir), resolved, converter, prefix);
|
|
251
245
|
},
|
|
252
246
|
};
|
|
253
247
|
}
|
|
254
|
-
/** Lazy registry accessor — mirrors pattern from 5b/5c (runtime-homes.cts). */
|
|
255
248
|
function getRegistry() {
|
|
256
249
|
return _require('./capability-registry.cjs');
|
|
257
250
|
}
|
|
@@ -288,22 +281,21 @@ function dispatchKindEntry(entry, runtime, configDir, scope) {
|
|
|
288
281
|
* instead of a hardcoded switch statement.
|
|
289
282
|
*/
|
|
290
283
|
function resolveRuntimeArtifactLayout(runtime, configDir, scope = 'global') {
|
|
284
|
+
return resolveRuntimeArtifactLayoutFromRegistry(getRegistry(), runtime, configDir, scope);
|
|
285
|
+
}
|
|
286
|
+
function resolveRuntimeArtifactLayoutFromRegistry(registry, runtime, configDir, scope = 'global') {
|
|
291
287
|
if (typeof configDir !== 'string' || configDir === '') {
|
|
292
288
|
throw new TypeError('configDir must be a non-empty string');
|
|
293
289
|
}
|
|
294
290
|
if (scope !== 'local' && scope !== 'global') {
|
|
295
291
|
throw new TypeError('scope must be "local" or "global"');
|
|
296
292
|
}
|
|
297
|
-
|
|
298
|
-
throw new TypeError(`Unknown runtime: '${runtime}' — add to runtime-artifact-layout.cjs table`);
|
|
299
|
-
}
|
|
300
|
-
const desc = getRegistry().runtimes[runtime]?.runtime?.artifactLayout;
|
|
293
|
+
const desc = registry.runtimes[runtime]?.runtime?.artifactLayout;
|
|
301
294
|
if (!desc) {
|
|
302
|
-
// Runtime is in ALLOWED_RUNTIMES but has no descriptor — reproduce old default: throw.
|
|
303
295
|
throw new TypeError(`Unknown runtime: '${runtime}' — add to runtime-artifact-layout.cjs table`);
|
|
304
296
|
}
|
|
305
297
|
const entries = desc[scope] ?? [];
|
|
306
298
|
const kinds = entries.map((entry) => dispatchKindEntry(entry, runtime, configDir, scope));
|
|
307
299
|
return { runtime, configDir, scope, kinds };
|
|
308
300
|
}
|
|
309
|
-
module.exports = { resolveRuntimeArtifactLayout, findInstallSourceRoot, getInstallExports };
|
|
301
|
+
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) {
|