devlyn-cli 4.3.7 → 4.3.9
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/bin/harness-activation.js +66 -12
- package/bin/skill-history.json +3 -1
- package/native/claude/.claude-plugin/plugin.json +1 -1
- package/native/codex/.agents/plugins/marketplace.json +1 -1
- package/native/codex/plugins/devlyn/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/release.json +8 -8
|
@@ -89,14 +89,15 @@ function effectiveConfig(context) {
|
|
|
89
89
|
const keys = {
|
|
90
90
|
claude: ['appendSystemPrompt', 'pluginDirs'], codex: ['developer_instructions', 'skills', 'marketplaces', 'plugins'],
|
|
91
91
|
grok: ['rules'], omp: ['appendSystemPrompt', 'skills'], antigravity: [], cursor: [],
|
|
92
|
-
opencode: ['inlineConfig'], kimi: ['ownerAgent'], copilot: ['skillsDirs'], qwen: ['appendSystemPrompt'],
|
|
92
|
+
opencode: ['inlineConfig', 'skillsPaths'], kimi: ['ownerAgent'], copilot: ['skillsDirs', 'instructionsDirs'], qwen: ['appendSystemPrompt'],
|
|
93
93
|
}[context.engine];
|
|
94
94
|
if (!object(config) || Object.keys(config).some((key) => !keys.includes(key))) return null;
|
|
95
|
-
for (const field of ['appendSystemPrompt', 'developer_instructions', 'rules', 'inlineConfig', 'skillsDirs']) {
|
|
95
|
+
for (const field of ['appendSystemPrompt', 'developer_instructions', 'rules', 'inlineConfig', 'skillsDirs', 'instructionsDirs']) {
|
|
96
96
|
if (config[field] !== undefined && config[field] !== null && !textValue(config[field])) return null;
|
|
97
97
|
}
|
|
98
98
|
if (context.engine === 'kimi' && typeof config.ownerAgent !== 'boolean') return null;
|
|
99
99
|
if (config.pluginDirs !== undefined && (!strings(config.pluginDirs) || !config.pluginDirs.every(path.isAbsolute))) return null;
|
|
100
|
+
if (config.skillsPaths != null && !strings(config.skillsPaths)) return null;
|
|
100
101
|
if (context.engine === 'codex') {
|
|
101
102
|
for (const key of ['marketplaces', 'plugins', 'skills']) if (config[key] != null && !object(config[key])) return null;
|
|
102
103
|
if (config.skills?.config !== undefined && (!Array.isArray(config.skills.config)
|
|
@@ -144,7 +145,10 @@ function discoveryRoots(context, env, config) {
|
|
|
144
145
|
for (const dir of config?.skills?.customDirectories || []) add(context.cwd, dir);
|
|
145
146
|
}
|
|
146
147
|
if (engine === 'codex' && process.platform !== 'win32') add('/etc/codex', 'skills');
|
|
147
|
-
if (engine === 'opencode')
|
|
148
|
+
if (engine === 'opencode') {
|
|
149
|
+
add(env.OPENCODE_CONFIG_DIR, 'skills');
|
|
150
|
+
for (const dir of config?.skillsPaths || []) add(context.cwd, dir);
|
|
151
|
+
}
|
|
148
152
|
if (engine === 'copilot') for (const dir of (config?.skillsDirs ?? env.COPILOT_SKILLS_DIRS ?? '').split(',').filter(Boolean)) add(context.cwd, dir);
|
|
149
153
|
for (let dir = path.resolve(context.cwd); ; dir = path.dirname(dir)) {
|
|
150
154
|
if (native[1]) add(dir, native[1], 'skills');
|
|
@@ -156,9 +160,38 @@ function discoveryRoots(context, env, config) {
|
|
|
156
160
|
return [...new Set(roots)];
|
|
157
161
|
}
|
|
158
162
|
|
|
159
|
-
function
|
|
163
|
+
function kimiSkillRoots(context, env) {
|
|
164
|
+
const home = env.HOME || env.USERPROFILE || os.homedir();
|
|
165
|
+
let project = path.resolve(context.cwd);
|
|
166
|
+
const roots = new Set(), errors = [];
|
|
167
|
+
for (let dir = project; ; dir = path.dirname(dir)) {
|
|
168
|
+
const git = path.join(dir, '.git');
|
|
169
|
+
try {
|
|
170
|
+
if (fs.statSync(git, { throwIfNoEntry: false })) { project = dir; break; }
|
|
171
|
+
} catch (error) {
|
|
172
|
+
errors.push(reason('config-unreadable', { path: git, detail: error.message }));
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
if (dir === path.dirname(dir)) break;
|
|
176
|
+
}
|
|
177
|
+
// --skills-dir replaces auto discovery and makes every root user-priority:
|
|
178
|
+
// first-name wins, so preserve workspace precedence by putting it first.
|
|
179
|
+
for (const root of [path.join(project, '.kimi-code/skills'), path.join(project, '.agents/skills'),
|
|
180
|
+
path.resolve(env.KIMI_CODE_HOME || path.join(home, '.kimi-code'), 'skills'), path.resolve(home, '.agents/skills')]) {
|
|
181
|
+
try {
|
|
182
|
+
if (fs.statSync(root, { throwIfNoEntry: false })?.isDirectory()) roots.add(fs.realpathSync(root));
|
|
183
|
+
} catch (error) {
|
|
184
|
+
errors.push(reason('config-unreadable', { path: root, detail: error.message }));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { roots: [...roots], errors };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function inspectSkills(context, release, env, config, active) {
|
|
160
191
|
const found = [], errors = [], hashes = new Map();
|
|
161
192
|
for (const root of discoveryRoots(context, env, config)) {
|
|
193
|
+
// Reusing the selected, verified release is not a competing OpenCode source.
|
|
194
|
+
if (active && context.engine === 'opencode' && config?.skillsPaths && root === path.join(release.root, 'config/skills')) continue;
|
|
162
195
|
for (const name of SKILLS) {
|
|
163
196
|
const dir = path.join(root, name);
|
|
164
197
|
try {
|
|
@@ -227,7 +260,7 @@ function planActivation(releaseRoot, input, env = process.env) {
|
|
|
227
260
|
fail('release-version-conflict', { version: context.recordedRelease.version }, 3);
|
|
228
261
|
}
|
|
229
262
|
const config = effectiveConfig(context);
|
|
230
|
-
const { found, errors } = inspectSkills(context, release, env, config);
|
|
263
|
+
const { found, errors } = inspectSkills(context, release, env, config, !off);
|
|
231
264
|
if (errors.length) status.hide = channel('partial', null, errors);
|
|
232
265
|
status.inheritedDevlyn = found.filter((entry) => entry.owned).map((entry) => entry.path);
|
|
233
266
|
const supported = supportedVersion(context.engine, context.version);
|
|
@@ -368,19 +401,35 @@ function planActivation(releaseRoot, input, env = process.env) {
|
|
|
368
401
|
let inline;
|
|
369
402
|
try { inline = config.inlineConfig == null ? {} : JSON.parse(config.inlineConfig); }
|
|
370
403
|
catch (error) { if (!(error instanceof SyntaxError)) throw error; inline = null; }
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
404
|
+
const invalidField = !object(inline) || (inline.instructions !== undefined && !strings(inline.instructions))
|
|
405
|
+
? 'inlineConfig.instructions'
|
|
406
|
+
: config.skillsPaths != null && inline.skills !== undefined && !object(inline.skills) ? 'inlineConfig.skills' : null;
|
|
407
|
+
if (invalidField) {
|
|
408
|
+
status.principles = channel('partial', null, [reason('config-unreadable', { field: invalidField })]);
|
|
409
|
+
status.skills = channel('partial', null, [reason('config-unreadable', { field: invalidField })]);
|
|
374
410
|
break;
|
|
375
411
|
}
|
|
412
|
+
if (Array.isArray(config.skillsPaths) && !collisions.length && !errors.length) {
|
|
413
|
+
inline.skills = { ...inline.skills, paths: [...new Set([...config.skillsPaths, path.join(release.root, 'config/skills')])] };
|
|
414
|
+
native('skills.paths', 'read-file', `Read ${path.join(release.root, 'config/skills/devlyn-ideate/SKILL.md')}`);
|
|
415
|
+
} else fallback(config.skillsPaths == null ? [] : [...collisions, ...errors]);
|
|
376
416
|
plan.envPatch.OPENCODE_CONFIG_CONTENT = JSON.stringify({ ...inline,
|
|
377
417
|
instructions: [...(inline.instructions || []), file('devlyn-instructions.md', instructions)] });
|
|
378
|
-
principles('OPENCODE_CONFIG_CONTENT.instructions');
|
|
418
|
+
principles('OPENCODE_CONFIG_CONTENT.instructions');
|
|
379
419
|
break;
|
|
380
420
|
}
|
|
381
421
|
case 'copilot': {
|
|
382
|
-
|
|
383
|
-
|
|
422
|
+
if (!context.committedBlockApplies) {
|
|
423
|
+
const directory = path.join(context.runDir, 'copilot');
|
|
424
|
+
if (directory.includes(',')) {
|
|
425
|
+
status.principles = channel('unavailable', null, [reason('principles-unavailable', { detail: 'comma-in-path' })]);
|
|
426
|
+
} else {
|
|
427
|
+
file('copilot/devlyn.instructions.md', '---\napplyTo: "**"\n---\n' + instructions);
|
|
428
|
+
const dirs = config.instructionsDirs ?? env.COPILOT_CUSTOM_INSTRUCTIONS_DIRS ?? '';
|
|
429
|
+
plan.envPatch.COPILOT_CUSTOM_INSTRUCTIONS_DIRS = dirs.split(',').includes(directory) ? dirs : (dirs ? `${dirs},${directory}` : directory);
|
|
430
|
+
principles('COPILOT_CUSTOM_INSTRUCTIONS_DIRS');
|
|
431
|
+
}
|
|
432
|
+
}
|
|
384
433
|
const root = path.join(release.root, 'config/skills');
|
|
385
434
|
if (root.includes(',') || collisions.length || errors.length) {
|
|
386
435
|
status.skills = channel('partial', null, root.includes(',') ? [reason('skills-unavailable', { detail: 'comma-in-path' })] : [...collisions, ...errors]);
|
|
@@ -398,7 +447,12 @@ function planActivation(releaseRoot, input, env = process.env) {
|
|
|
398
447
|
status.skills = channel('partial', null, [reason('skills-unavailable', { launchMode: context.launchMode, ownerAgent: config.ownerAgent })]);
|
|
399
448
|
} else {
|
|
400
449
|
plan.engineArgs.push('--agent-file', file('devlyn-kimi.md', joinText('${base_prompt}', instructions)));
|
|
401
|
-
principles('agent-file');
|
|
450
|
+
principles('agent-file');
|
|
451
|
+
const kimi = kimiSkillRoots(context, env);
|
|
452
|
+
if (!collisions.length && !errors.length && !kimi.errors.length) {
|
|
453
|
+
for (const root of [...kimi.roots, path.join(release.root, 'config/skills')]) plan.engineArgs.push('--skills-dir', root);
|
|
454
|
+
native('--skills-dir', 'read-file', `Read ${path.join(release.root, 'config/skills/devlyn-ideate/SKILL.md')}`);
|
|
455
|
+
} else fallback([...collisions, ...errors, ...kimi.errors]);
|
|
402
456
|
}
|
|
403
457
|
break;
|
|
404
458
|
case 'antigravity':
|
package/bin/skill-history.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devlyn-cli",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.9",
|
|
4
4
|
"description": "Loop & harness engineering for AI coding agents (Claude Code, Codex, and any AGENTS.md-driven agent) — core engineering principles for CLAUDE.md/AGENTS.md and a loop designer that splits one intent into tasks agents drain hands-free",
|
|
5
5
|
"homepage": "https://github.com/fysoul17/devlyn-cli#readme",
|
|
6
6
|
"bin": {
|
package/release.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "devlyn-cli",
|
|
4
|
-
"version": "4.3.
|
|
4
|
+
"version": "4.3.9",
|
|
5
5
|
"principles": {
|
|
6
6
|
"defaults": "config/skills/_shared/runtime-principles.md",
|
|
7
7
|
"memory": {
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"path": "bin/harness-activation.js",
|
|
142
|
-
"sha256": "
|
|
142
|
+
"sha256": "fecb47b04e7f6e72735a9ea50b6aa524eca611d42c6db1b03c1260ddf2259bbc",
|
|
143
143
|
"executable": false
|
|
144
144
|
},
|
|
145
145
|
{
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
166
|
"path": "bin/skill-history.json",
|
|
167
|
-
"sha256": "
|
|
167
|
+
"sha256": "947ec7e9dead4b4e9ebb234219c7aaea76b0561fde997c95d53c67f6babbdb3a",
|
|
168
168
|
"executable": false
|
|
169
169
|
},
|
|
170
170
|
{
|
|
@@ -309,7 +309,7 @@
|
|
|
309
309
|
},
|
|
310
310
|
{
|
|
311
311
|
"path": "native/claude/.claude-plugin/plugin.json",
|
|
312
|
-
"sha256": "
|
|
312
|
+
"sha256": "5aa927b9eb784e0a246571e8c747607390c7dc89207a66b9bc8759281429b259",
|
|
313
313
|
"executable": false
|
|
314
314
|
},
|
|
315
315
|
{
|
|
@@ -439,12 +439,12 @@
|
|
|
439
439
|
},
|
|
440
440
|
{
|
|
441
441
|
"path": "native/codex/.agents/plugins/marketplace.json",
|
|
442
|
-
"sha256": "
|
|
442
|
+
"sha256": "39a9e1bcfd87ffca63ce3e6a7b38d280b8bf4db725a28683c2f1f60cdb792730",
|
|
443
443
|
"executable": false
|
|
444
444
|
},
|
|
445
445
|
{
|
|
446
446
|
"path": "native/codex/plugins/devlyn/.codex-plugin/plugin.json",
|
|
447
|
-
"sha256": "
|
|
447
|
+
"sha256": "5aa927b9eb784e0a246571e8c747607390c7dc89207a66b9bc8759281429b259",
|
|
448
448
|
"executable": false
|
|
449
449
|
},
|
|
450
450
|
{
|
|
@@ -1619,12 +1619,12 @@
|
|
|
1619
1619
|
},
|
|
1620
1620
|
{
|
|
1621
1621
|
"path": "package.json",
|
|
1622
|
-
"sha256": "
|
|
1622
|
+
"sha256": "9c67dfff676ecd8d7597146398ab5304c6ecac12d870b1ff1924478060614acc",
|
|
1623
1623
|
"executable": false
|
|
1624
1624
|
}
|
|
1625
1625
|
],
|
|
1626
1626
|
"digest": {
|
|
1627
1627
|
"algorithm": "sha256",
|
|
1628
|
-
"value": "
|
|
1628
|
+
"value": "de2c9dba7a92d6c9844f3434fbdb21c8236e58b5e64e5f475fcca0dfb4b11c3f"
|
|
1629
1629
|
}
|
|
1630
1630
|
}
|