devlyn-cli 4.3.29 → 4.3.30
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/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/bin/engines.js +7 -9
- package/bin/harness-activation.js +166 -17
- package/bin/harness-context.js +7 -7
- package/bin/instruction-templates.json +2 -0
- package/bin/skill-history.json +3 -0
- package/config/skills/_shared/engine-preflight.md +0 -2
- package/config/skills/_shared/runtime-principles.md +1 -1
- package/config/skills/_shared/task-completion.md +3 -15
- package/config/skills/devlyn-ideate/references/loop.md +2 -4
- package/config/skills/devlyn-ideate/references/package-format.md +0 -1
- package/harness/AGENTS.md +2 -2
- package/harness/CLAUDE.md +2 -2
- package/native/claude/.claude-plugin/plugin.json +1 -1
- package/native/claude/skills/_shared/engine-preflight.md +0 -2
- package/native/claude/skills/_shared/runtime-principles.md +1 -1
- package/native/claude/skills/_shared/task-completion.md +3 -15
- package/native/claude/skills/devlyn-ideate/references/loop.md +2 -4
- package/native/claude/skills/devlyn-ideate/references/package-format.md +0 -1
- package/native/codex/.agents/plugins/marketplace.json +1 -1
- package/native/codex/plugins/devlyn/.codex-plugin/plugin.json +1 -1
- package/native/codex/plugins/devlyn/skills/_shared/engine-preflight.md +0 -2
- package/native/codex/plugins/devlyn/skills/_shared/runtime-principles.md +1 -1
- package/native/codex/plugins/devlyn/skills/_shared/task-completion.md +3 -15
- package/native/codex/plugins/devlyn/skills/devlyn-ideate/references/loop.md +2 -4
- package/native/codex/plugins/devlyn/skills/devlyn-ideate/references/package-format.md +0 -1
- package/package.json +1 -1
- package/release.json +31 -31
package/AGENTS.md
CHANGED
|
@@ -27,7 +27,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
27
27
|
## Quick Start
|
|
28
28
|
|
|
29
29
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
30
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
30
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
31
31
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
32
32
|
|
|
33
33
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
package/CLAUDE.md
CHANGED
|
@@ -27,7 +27,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
27
27
|
## Quick Start
|
|
28
28
|
|
|
29
29
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
30
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
30
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
31
31
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
32
32
|
|
|
33
33
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
package/bin/engines.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// Engine IDs in the order of devlyn-os-v1/packages/contracts/src/engines.ts. An ID joins only once its
|
|
2
|
-
// channels are confirmed on the real CLI, with that examined version as its floor
|
|
2
|
+
// channels are confirmed on the real CLI, with that examined version as its floor; the planner
|
|
3
3
|
// refuses every other ID. CLI binary names (for example agy) are not engine IDs.
|
|
4
|
-
|
|
5
|
-
'claude', 'codex', 'grok', 'omp', 'antigravity', 'cursor', 'opencode', 'kimi', 'copilot', 'qwen', 'pi',
|
|
6
|
-
]);
|
|
7
|
-
|
|
4
|
+
//
|
|
8
5
|
// The versions each channel was examined on. Any newer release, a new major included, is taken as
|
|
9
6
|
// compatible: a version number is not evidence that a channel broke (omp 18 kept both flags devlyn
|
|
10
7
|
// uses), and refusing unexamined majors turned working engines off. Only a version below the examined
|
|
@@ -23,18 +20,19 @@ const ENGINE_CAPABILITIES = Object.freeze({
|
|
|
23
20
|
qwen: { minimum: '0.26.0', executor: false },
|
|
24
21
|
pi: { minimum: '1.4.0', executor: false },
|
|
25
22
|
});
|
|
23
|
+
const ENGINE_IDS = Object.freeze(Object.keys(ENGINE_CAPABILITIES));
|
|
26
24
|
|
|
27
25
|
function readableVersion(engine, version) {
|
|
28
26
|
return typeof version === 'string'
|
|
29
27
|
&& (engine === 'cursor' ? /^\d{4}\.\d{2}\.\d{2}-[0-9a-f]+$/ : /^\d+\.\d+\.\d+$/).test(version);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
// Whether `version` is at least `minimum`, the engine's floor unless a channel names a later examined one.
|
|
31
|
+
function supportedVersion(engine, version, minimum = ENGINE_CAPABILITIES[engine].minimum) {
|
|
33
32
|
if (!readableVersion(engine, version)) return false;
|
|
34
|
-
|
|
35
|
-
if (engine === 'cursor') return version.slice(0, 10).replace(/\./g, '') >= capability.minimum.slice(0, 10).replace(/\./g, '');
|
|
33
|
+
if (engine === 'cursor') return version.slice(0, 10).replace(/\./g, '') >= minimum.slice(0, 10).replace(/\./g, '');
|
|
36
34
|
const actual = version.split('.').map(Number);
|
|
37
|
-
const floor =
|
|
35
|
+
const floor = minimum.split('.').map(Number);
|
|
38
36
|
for (let i = 0; i < 3; i++) {
|
|
39
37
|
if (actual[i] !== floor[i]) return actual[i] > floor[i];
|
|
40
38
|
}
|
|
@@ -8,6 +8,10 @@ const history = require('./skill-history.json');
|
|
|
8
8
|
const { MARKER, marketplaceName, projectionPath, inspectProjection } = require('./codex-projection');
|
|
9
9
|
|
|
10
10
|
const SKILLS = ['devlyn-ideate', 'devlyn-engines'];
|
|
11
|
+
// The version an engine's run-folder channel was examined on; bin/engines.js keeps the engine's floor. An
|
|
12
|
+
// older version, and Windows (channelGate), keep the plan they had before the channel: only a first task
|
|
13
|
+
// carries the principles.
|
|
14
|
+
const CHANNEL_MINIMUM = { antigravity: '1.5.4', cursor: '2026.11.05-86047df' };
|
|
11
15
|
const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
12
16
|
const textValue = (value) => typeof value === 'string' && !value.includes('\0');
|
|
13
17
|
const strings = (value) => Array.isArray(value) && value.every(textValue);
|
|
@@ -139,6 +143,10 @@ function discoveryRoots(context, env, config) {
|
|
|
139
143
|
const roots = [...(context.skillRoots || [])];
|
|
140
144
|
const add = (base, ...parts) => { if (base) roots.push(path.resolve(base, ...parts)); };
|
|
141
145
|
const engine = context.engine;
|
|
146
|
+
// Antigravity and Cursor search the folders their examined version reads only where they get their run-folder
|
|
147
|
+
// channel; elsewhere they keep the folders searched before it.
|
|
148
|
+
const channelled = ['antigravity', 'cursor'].includes(engine) && !channelGate(context);
|
|
149
|
+
const antigravity = channelled && engine === 'antigravity';
|
|
142
150
|
const native = {
|
|
143
151
|
claude: [env.CLAUDE_CONFIG_DIR || path.join(home, '.claude'), '.claude'],
|
|
144
152
|
codex: [context.accountHome || env.CODEX_HOME || path.join(home, '.codex'), '.agents'],
|
|
@@ -153,7 +161,9 @@ function discoveryRoots(context, env, config) {
|
|
|
153
161
|
}[engine];
|
|
154
162
|
if (engine !== 'codex') add(native[0], 'skills');
|
|
155
163
|
const copilotDefaultHome = !env.COPILOT_HOME || path.resolve(env.COPILOT_HOME) === path.join(home, '.copilot');
|
|
156
|
-
if (!['claude', 'cursor'].includes(engine) && (engine !== 'copilot' || copilotDefaultHome)) add(engine === 'pi' ? pi.agentsHome : home, '.agents/skills');
|
|
164
|
+
if (!['claude', 'cursor'].includes(engine) && !antigravity && (engine !== 'copilot' || copilotDefaultHome)) add(engine === 'pi' ? pi.agentsHome : home, '.agents/skills');
|
|
165
|
+
// The examined Antigravity reads ~/.gemini/skills and its personal folder ~/.gemini/config instead.
|
|
166
|
+
if (antigravity) { add(home, '.gemini/skills'); add(home, '.gemini/config/skills'); }
|
|
157
167
|
if (['omp', 'opencode', 'grok'].includes(engine)) add(home, '.claude/skills');
|
|
158
168
|
if (engine === 'omp') {
|
|
159
169
|
add(home, '.codex/skills'); add(home, '.agent/skills');
|
|
@@ -166,12 +176,24 @@ function discoveryRoots(context, env, config) {
|
|
|
166
176
|
}
|
|
167
177
|
if (engine === 'copilot') for (const dir of (config?.skillsDirs ?? env.COPILOT_SKILLS_DIRS ?? '').split(',').filter(Boolean)) add(context.cwd, dir);
|
|
168
178
|
if (engine === 'pi') add(context.cwd, '.pi/skills');
|
|
179
|
+
const walk = [];
|
|
169
180
|
for (let dir = path.resolve(context.cwd); ; dir = path.dirname(dir)) {
|
|
181
|
+
walk.push(dir);
|
|
182
|
+
if (fs.existsSync(path.join(dir, '.git'))) break;
|
|
183
|
+
// Outside any repository the examined Antigravity reads the working directory alone.
|
|
184
|
+
if (dir === path.dirname(dir)) { if (antigravity) walk.splice(1); break; }
|
|
185
|
+
}
|
|
186
|
+
// The examined Cursor also searches nested folders below the working directory, which the planner does not.
|
|
187
|
+
const cursorFolders = channelled && engine === 'cursor' ? ['.cursor', '.agents', '.claude', '.codex', '.grok'] : [];
|
|
188
|
+
for (const folder of cursorFolders) add(home, folder, 'skills');
|
|
189
|
+
if (cursorFolders.length) add(home, '.cursor/skills-cursor');
|
|
190
|
+
for (const dir of walk) {
|
|
191
|
+
for (const folder of cursorFolders) add(dir, folder, 'skills');
|
|
170
192
|
if (native[1]) add(dir, native[1], 'skills');
|
|
171
193
|
if (!['claude', 'cursor'].includes(engine)) add(dir, '.agents/skills');
|
|
172
194
|
if (['grok', 'omp', 'opencode', 'copilot'].includes(engine)) add(dir, '.claude/skills');
|
|
173
195
|
if (['omp', 'antigravity'].includes(engine)) add(dir, '.agent/skills');
|
|
174
|
-
if (
|
|
196
|
+
if (antigravity) { add(dir, '_agents/skills'); add(dir, '_agent/skills'); }
|
|
175
197
|
}
|
|
176
198
|
return [...new Set(roots)];
|
|
177
199
|
}
|
|
@@ -377,10 +399,73 @@ function skillCatalog(release, paths = path) {
|
|
|
377
399
|
return ['Devlyn session skill catalog (read the absolute file to invoke):',
|
|
378
400
|
...SKILLS.map((name) => `${name}: ${paths.join(root, name, 'SKILL.md')}`),
|
|
379
401
|
`This session's _shared folder is ${paths.join(root, '_shared')}.`,
|
|
380
|
-
'Use that absolute folder wherever the Devlyn defaults name _shared
|
|
402
|
+
'Use that absolute folder wherever the Devlyn defaults name _shared/.',
|
|
381
403
|
].join('\n');
|
|
382
404
|
}
|
|
383
405
|
|
|
406
|
+
// A skill entry of Antigravity's run folder: the release skill's own name and description lines as
|
|
407
|
+
// written, then the release SKILL.md to follow. A copy cannot be planned (plan files are text and the
|
|
408
|
+
// skills carry scripts), and since 1.5.2 Antigravity skips a link or a manifest entry that leads outside
|
|
409
|
+
// the added folder. Each line must be one complete top-level entry, or the plan fails.
|
|
410
|
+
function antigravitySkill(release, name) {
|
|
411
|
+
const dir = path.join(release.root, 'config/skills', name);
|
|
412
|
+
const file = path.join(dir, 'SKILL.md');
|
|
413
|
+
const text = fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n');
|
|
414
|
+
const end = text.startsWith('---\n') ? text.indexOf('\n---\n', 3) : -1;
|
|
415
|
+
const lines = end < 0 ? [] : text.slice(4, end).split('\n');
|
|
416
|
+
const header = ['name', 'description'].map((field) => {
|
|
417
|
+
const at = lines.flatMap((line, index) => (line.startsWith(`${field}:`) ? [index] : []));
|
|
418
|
+
if (at.length !== 1 || !lines[at[0]].slice(field.length + 1).trim() || /^\s/.test(lines[at[0] + 1] ?? '')) {
|
|
419
|
+
fail('config-unreadable', { path: file, field }, 1);
|
|
420
|
+
}
|
|
421
|
+
return lines[at[0]];
|
|
422
|
+
});
|
|
423
|
+
return `---\n${header.join('\n')}\n---\nRead ${file} and follow it as this skill. `
|
|
424
|
+
+ `Its folder, ${dir}, is the skill's folder (DEVLYN_SKILL_DIR), not the folder of this file.\n`;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// The path with the links of its existing part resolved; parts that do not exist yet are kept as given.
|
|
428
|
+
function physicalPath(target) {
|
|
429
|
+
let parent = path.resolve(target);
|
|
430
|
+
const missing = [];
|
|
431
|
+
while (!fs.existsSync(parent)) { missing.unshift(path.basename(parent)); parent = path.dirname(parent); }
|
|
432
|
+
return path.join(fs.realpathSync(parent), ...missing);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// The reasons for the principles and the skills when neither reaches the session.
|
|
436
|
+
const withheld = (params) => [reason('principles-unavailable', params), reason('skills-unavailable', params)];
|
|
437
|
+
|
|
438
|
+
// Why an engine keeps the plan it had before its run-folder channel, as the reasons for the principles and the
|
|
439
|
+
// skills when no first task carries them, or null when it gets the channel. The channels were examined on macOS
|
|
440
|
+
// and are not planned on Windows, whatever the version: it cannot show who owns a folder, and an argument that
|
|
441
|
+
// misbehaves there would break a pane. Below the version a channel was examined on, updating the engine gets it.
|
|
442
|
+
function channelGate(context) {
|
|
443
|
+
if (process.platform === 'win32') return withheld({ detail: 'platform-unexamined' });
|
|
444
|
+
const minimum = CHANNEL_MINIMUM[context.engine];
|
|
445
|
+
if (supportedVersion(context.engine, context.version, minimum)) return null;
|
|
446
|
+
const outdated = reason('engine-version-unsupported', { minimum });
|
|
447
|
+
return [outdated, outdated];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// The first directory that makes a run-folder channel's `folder`, inside a resolved run directory (physicalPath),
|
|
451
|
+
// unsafe to hand an engine that loads what it finds there, or null. Every existing level from the folder up, the
|
|
452
|
+
// folder included, must be a real directory (a link is not one) of this user or root that no one else can write:
|
|
453
|
+
// another user could put a .git or a folder of their own there later. With `git`, no directory from the folder up
|
|
454
|
+
// may hold a .git entry of any kind: Antigravity 1.5.4 loads the agents and hooks of a Git root above an added
|
|
455
|
+
// folder with no trust check. A level that does not exist yet is skipped; a level lstat cannot read cannot be
|
|
456
|
+
// shown safe. Access-control lists are not read.
|
|
457
|
+
function unsafeRunDir(folder, git) {
|
|
458
|
+
const entry = (file) => {
|
|
459
|
+
try { return fs.lstatSync(file, { throwIfNoEntry: false }) ?? null; } catch { return false; }
|
|
460
|
+
};
|
|
461
|
+
for (let dir = folder; ; dir = path.dirname(dir)) {
|
|
462
|
+
const stats = entry(dir);
|
|
463
|
+
if (stats === false || (stats && (!stats.isDirectory() || ![process.getuid(), 0].includes(stats.uid) || stats.mode & 0o022))) return dir;
|
|
464
|
+
if (git && entry(path.join(dir, '.git')) !== null) return dir;
|
|
465
|
+
if (dir === path.dirname(dir)) return null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
384
469
|
function codexRegistrations(config, accountHome) {
|
|
385
470
|
const owned = [], errors = [];
|
|
386
471
|
for (const [key, plugin] of Object.entries(config.plugins || {})) {
|
|
@@ -478,11 +563,7 @@ function planActivation(releaseRoot, input, env = process.env) {
|
|
|
478
563
|
const catalog = skillCatalog(release);
|
|
479
564
|
const instructions = joinText(defaults, catalog);
|
|
480
565
|
const file = (relativePath, utf8) => {
|
|
481
|
-
|
|
482
|
-
const missing = [];
|
|
483
|
-
while (!fs.existsSync(parent)) { missing.unshift(path.basename(parent)); parent = path.dirname(parent); }
|
|
484
|
-
const physical = path.join(fs.realpathSync(parent), ...missing);
|
|
485
|
-
const relative = path.relative(release.root, physical);
|
|
566
|
+
const relative = path.relative(release.root, physicalPath(context.runDir));
|
|
486
567
|
if (!relative || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative))) {
|
|
487
568
|
fail('invalid-arguments', { argument: 'runDir must be outside the release' }, 2);
|
|
488
569
|
}
|
|
@@ -497,6 +578,19 @@ function planActivation(releaseRoot, input, env = process.env) {
|
|
|
497
578
|
status.invocation = { kind: 'read-file', text: `Read ${path.join(release.root, 'config/skills/devlyn-ideate/SKILL.md')}` };
|
|
498
579
|
};
|
|
499
580
|
const native = (mechanism, kind, text) => { status.skills = channel('configured', mechanism); status.invocation = { kind, text }; };
|
|
581
|
+
// Where no run-folder channel is planned, only a first task carries the principles and the catalog, ahead
|
|
582
|
+
// of its text; without one nothing reaches the session and each channel gives its reason.
|
|
583
|
+
const firstTask = ([principlesReason, skillsReason]) => {
|
|
584
|
+
if (context.initialPrompt) {
|
|
585
|
+
status.principles = channel('partial', 'initial-task', [reason('principles-task-only')]);
|
|
586
|
+
plan.prompt = { ...context.initialPrompt, text: joinText(instructions, context.initialPrompt.text) };
|
|
587
|
+
fallback();
|
|
588
|
+
} else {
|
|
589
|
+
status.principles = channel('unavailable', null, [principlesReason]);
|
|
590
|
+
status.skills = channel('unavailable', null, [skillsReason]);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
// A skill folder that cannot be inspected is also found, so every inspection error comes with a collision.
|
|
500
594
|
const collisions = found.map((entry) => reason('name-collision', { name: entry.name, path: entry.path }));
|
|
501
595
|
switch (context.engine) {
|
|
502
596
|
case 'claude': {
|
|
@@ -645,18 +739,73 @@ function planActivation(releaseRoot, input, env = process.env) {
|
|
|
645
739
|
} else fallback([...collisions, ...errors, ...kimi.errors]);
|
|
646
740
|
}
|
|
647
741
|
break;
|
|
648
|
-
case 'antigravity':
|
|
649
|
-
|
|
650
|
-
//
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
742
|
+
case 'antigravity': {
|
|
743
|
+
// Antigravity reads AGENTS.md (always on) and .agents/skills in every workspace folder, and a folder given
|
|
744
|
+
// by --add-dir is one. A conversation keeps its added folders and reads them from disk again on every
|
|
745
|
+
// launch, so the plan is the same in every launch mode and a caller hands a resumed conversation the same
|
|
746
|
+
// runDir: with another, both folders apply while the old one exists. A folder removed later only stops
|
|
747
|
+
// applying. It truncates a rule file over 24,000 bytes.
|
|
748
|
+
const gate = channelGate(context);
|
|
749
|
+
if (gate) {
|
|
750
|
+
firstTask(gate);
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
// The engine is given the resolved folder, the one the checks ran on.
|
|
754
|
+
const folder = path.join(physicalPath(context.runDir), 'antigravity');
|
|
755
|
+
const unsafe = unsafeRunDir(folder, true);
|
|
756
|
+
if (unsafe) {
|
|
757
|
+
firstTask(withheld({ detail: 'run-dir-unsafe', path: unsafe }));
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
const bytes = Buffer.byteLength(instructions), maximum = 24000;
|
|
761
|
+
if (bytes > maximum) {
|
|
762
|
+
status.principles = channel('unavailable', null, [reason('principles-unavailable', { detail: 'too-large', bytes, maximum })]);
|
|
655
763
|
} else {
|
|
656
|
-
|
|
657
|
-
|
|
764
|
+
file('antigravity/AGENTS.md', instructions);
|
|
765
|
+
principles('add-dir');
|
|
658
766
|
}
|
|
767
|
+
if (collisions.length) fallback([...collisions, ...errors], bytes <= maximum);
|
|
768
|
+
else {
|
|
769
|
+
for (const name of SKILLS) file(`antigravity/.agents/skills/${name}/SKILL.md`, antigravitySkill(release, name));
|
|
770
|
+
native('add-dir', 'slash', '/devlyn-ideate');
|
|
771
|
+
}
|
|
772
|
+
if (plan.files.length) plan.engineArgs.push('--add-dir', folder);
|
|
659
773
|
break;
|
|
774
|
+
}
|
|
775
|
+
case 'cursor': {
|
|
776
|
+
const gate = channelGate(context);
|
|
777
|
+
if (gate) {
|
|
778
|
+
firstTask(gate);
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
// A --plugin-dir folder's sessionStart command hook runs when a session is created, and Cursor puts the
|
|
782
|
+
// additional_context it prints before the model as instructions, kept with the conversation (10,200
|
|
783
|
+
// characters were delivered whole). A resumed chat runs no hook and keeps what its first launch had
|
|
784
|
+
// (measured); a fork is treated the same way, because what it gets is not established. The hook is a
|
|
785
|
+
// command Cursor runs, so it is planned only in a safe run directory, by its resolved absolute path, quoted
|
|
786
|
+
// for the shell: no lookup through PATH or the working folder. The skills come from the release, whatever
|
|
787
|
+
// the run directory.
|
|
788
|
+
const hook = path.join(physicalPath(context.runDir), 'cursor');
|
|
789
|
+
const unsafe = unsafeRunDir(hook);
|
|
790
|
+
if (unsafe || !isFile('/bin/cat')) {
|
|
791
|
+
firstTask(withheld(unsafe ? { detail: 'run-dir-unsafe', path: unsafe } : { detail: 'platform-unexamined' }));
|
|
792
|
+
} else {
|
|
793
|
+
const command = `/bin/cat '${path.join(hook, 'context.json').replace(/'/g, "'\\''")}'`;
|
|
794
|
+
file('cursor/hooks/hooks.json', JSON.stringify({ version: 1, hooks: { sessionStart: [{ command }] } }) + '\n');
|
|
795
|
+
// Every non-ASCII character escaped, so no shell or code page can change the text.
|
|
796
|
+
file('cursor/context.json', JSON.stringify({ additional_context: instructions })
|
|
797
|
+
.replace(/[\u0080-\uffff]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`) + '\n');
|
|
798
|
+
plan.engineArgs.push('--plugin-dir', hook);
|
|
799
|
+
status.principles = continuation ? channel('partial', 'session-start-hook', [reason('principles-session-start-only')])
|
|
800
|
+
: channel('configured', 'session-start-hook');
|
|
801
|
+
}
|
|
802
|
+
if (collisions.length) fallback([...collisions, ...errors], plan.files.length > 0 || plan.prompt !== null);
|
|
803
|
+
else {
|
|
804
|
+
plan.engineArgs.push('--plugin-dir', path.join(release.root, 'config'));
|
|
805
|
+
native('plugin-dir', 'slash', '/devlyn-ideate');
|
|
806
|
+
}
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
660
809
|
}
|
|
661
810
|
if (plan.engineArgs.length || Object.keys(plan.envPatch).length || plan.prompt) plan.envPatch.DEVLYN_HARNESS_ROOT = release.root;
|
|
662
811
|
return finish(plan);
|
package/bin/harness-context.js
CHANGED
|
@@ -8,7 +8,7 @@ const path = require('path');
|
|
|
8
8
|
const crypto = require('crypto');
|
|
9
9
|
const readline = require('readline');
|
|
10
10
|
const { spawn, spawnSync } = require('child_process');
|
|
11
|
-
const {
|
|
11
|
+
const { physicalRoot, materializeRelease, fail } = require('./release');
|
|
12
12
|
|
|
13
13
|
const ENGINES = Object.freeze(['claude', 'codex', 'omp']);
|
|
14
14
|
const READ_MS = 6000;
|
|
@@ -209,13 +209,13 @@ function appState(home, common) {
|
|
|
209
209
|
return { defaultRelease: state.defaultRelease || null, choice };
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
// A release chosen by a record must
|
|
212
|
+
// A release chosen by a record must be the one recorded; its own planner verifies its files.
|
|
213
213
|
function recorded(root, version, digest, source) {
|
|
214
|
-
let
|
|
215
|
-
try {
|
|
216
|
-
catch (error) { fail('release-unavailable', { source, version, detail: error.reason?.code || error.
|
|
217
|
-
if (
|
|
218
|
-
return { release, source };
|
|
214
|
+
let manifest;
|
|
215
|
+
try { root = physicalRoot(root); manifest = JSON.parse(fs.readFileSync(path.join(root, 'release.json'), 'utf8')); }
|
|
216
|
+
catch (error) { fail('release-unavailable', { source, version, detail: error.reason?.code || error.code || 'unreadable' }, 3); }
|
|
217
|
+
if (manifest?.version !== version || manifest?.digest?.value !== digest) fail('release-version-conflict', { source, version }, 3);
|
|
218
|
+
return { release: { package: 'devlyn-cli', version, digest, root }, source };
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
// The release a terminal launch plans with: an unfinished queue's bound release in this repository,
|
|
@@ -494,6 +494,7 @@
|
|
|
494
494
|
"cc8bf51efb9ef8e5fa4134743f2d25434f4fd51595128edcfd2331dbf29d7dd5",
|
|
495
495
|
"ccacf091bab4102d7156631c6227120a661bb4ec0df514e14a59db44b7bd5dfd",
|
|
496
496
|
"ce1b0d9d0621fd057e684dc18b43156d30f589c72ed20189ea1232ea4f7ce6c6",
|
|
497
|
+
"ce8c1ea5c851fed75b898759fcf8359bd95ec04b30e547ed06bdf4101a2dddd8",
|
|
497
498
|
"cebacda3b11db7aa161d96b12edd6f3f790ee2850404cd42ecdf2912ed53de08",
|
|
498
499
|
"cefad7acb7dcd92777f888081aa6585b1418aa581366736fd44db68b1bd66dd0",
|
|
499
500
|
"cf43eb0460beebdfe1efbfb1a35a39e5fe450137252ea2c83e51d978faa1f17e",
|
|
@@ -1024,6 +1025,7 @@
|
|
|
1024
1025
|
"ce351bfa301b000f0786cac24959108a3db6cdf1cad3733cb07b394c62d35227",
|
|
1025
1026
|
"ce3cceeb74119953afde95da84dbe1bd6e3da3dbde5f85dd123a0fe8afec5d36",
|
|
1026
1027
|
"ce4b307083addc337a833547cb6998cb34a38d82e572587e9a57dc2cf46d275a",
|
|
1028
|
+
"ce8c1ea5c851fed75b898759fcf8359bd95ec04b30e547ed06bdf4101a2dddd8",
|
|
1027
1029
|
"ce9c73a3305e4ec9cd559cec6fdd10b8f4a9f3124b42ea4598340dc16a575505",
|
|
1028
1030
|
"ceddbf09792093c7417e72c7e2cf08e4780e9798dcd107292cdd095b023c2a8c",
|
|
1029
1031
|
"cf04e7c73e16d8e0e561e89d4a6519a1c47b9ffa08f88d1e5bda75ad2983f4df",
|
package/bin/skill-history.json
CHANGED
|
@@ -124,6 +124,7 @@
|
|
|
124
124
|
"97e7ad89c74c609b15dfbf6f9f7ac61df8b50e97e4bc318f72922e058ecffba4",
|
|
125
125
|
"9815b6e6963e068872a6dbeae24068143bf92042bb035f67bafd1a224d65bcb0",
|
|
126
126
|
"998343c148618b937556b58b83749c05d5aa3283280d751c118da6a542fb87f2",
|
|
127
|
+
"9ca5956a73070555a93f19ecb1f92a8f57cec6fd1170a2809eeacc49cc0841be",
|
|
127
128
|
"9dd3ec225818efe0ad3726192db94ff129154e995617a9d3c150fc58ad0f9f2c",
|
|
128
129
|
"9e4d06fd466fa896040109bac0018fcfb2f1604d55abb4180ff1f1a0b665bbc8",
|
|
129
130
|
"9f14ca629e41730b1a9fb5d0ad1a39cff558fe34758d6ceccbb9de498f9f384e",
|
|
@@ -398,6 +399,7 @@
|
|
|
398
399
|
"c8e375aab574148542f392b093cbbf3f2e8dc623826b45e35df0a1a2c3862226",
|
|
399
400
|
"ce282a55328c2d071cacc377670fbebea4da4b9a7fee81b25293fb26763f17c9",
|
|
400
401
|
"cf61a917a804503ef1e26fbb1cf498181e843a0758ec001f84edb7bcac837448",
|
|
402
|
+
"d622e92c7bf32d315a5aabe2554efbc9f62790ace19a088ead9a7cef195fc715",
|
|
401
403
|
"d6433bf0f96dd9dd485c3623885255738654674b3e23cfcc1a2cfd24f3cda96e",
|
|
402
404
|
"db8d921aabf0d04811b55465a3757c62c4b39631aebaf6eecc994ca241cfbe56",
|
|
403
405
|
"e25da746dc37b2e82c658a28d9481fd69741151045683eee2119582ddaf731cd",
|
|
@@ -822,6 +824,7 @@
|
|
|
822
824
|
"4.3.28",
|
|
823
825
|
"4.3.29",
|
|
824
826
|
"4.3.3",
|
|
827
|
+
"4.3.30",
|
|
825
828
|
"4.3.4",
|
|
826
829
|
"4.3.5",
|
|
827
830
|
"4.3.6",
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Shared — Executor Pre-flight
|
|
2
2
|
|
|
3
|
-
Used by `/devlyn-ideate` and `/devlyn-engines`: one rule for which engine executes implementation work and what happens when it is missing.
|
|
4
|
-
|
|
5
3
|
## Selection
|
|
6
4
|
|
|
7
5
|
The executor is the `executor` pin in `.devlyn/engines.json` at the checkout root (set with `/devlyn-engines executor <name>`), else the CLI the user opened. A linked worktree or subdirectory has no pin unless one is set there. Only Claude and Codex can execute, so a drain from any other CLI needs a claude or codex pin. Keys earlier releases wrote for retired pipeline roles (`pair_judge_priority`, `roles`) stay as written and select nothing: a worker profile never becomes the executor.
|
|
@@ -29,7 +29,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
31
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
32
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
32
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
33
33
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
34
34
|
|
|
35
35
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
|
@@ -62,9 +62,6 @@ The repository comes from the remote's GitHub URL and the base from the reposito
|
|
|
62
62
|
A non-default base is refused at allocation.
|
|
63
63
|
Every delivery allocation owns a linked worktree; `--worktree` is required and
|
|
64
64
|
must name an absent path.
|
|
65
|
-
Cleanup removes empty parents through the exact per-repo root shown above or its legacy `.devlyn.noindex`/`.devlyn` root, keeping the shared `.devlyn-worktrees` container. Allocation also sweeps empty legacy roots for this repo.
|
|
66
|
-
On Windows, allocation marks only a newly created shared container hidden and creates the worktree not content-indexed (content only; names stay indexed); files copied in keep their own attributes.
|
|
67
|
-
A marking failure continues allocation and is reported in `warnings`.
|
|
68
65
|
Remote allocation first cleans earlier merged deliveries, then allocation refuses with `BLOCKED:disk`
|
|
69
66
|
without creating a receipt, branch or worktree when that filesystem has less than max(10 GiB, 2%) free; free space and allocate again.
|
|
70
67
|
A publication allocation normally starts at the exact fetched remote base,
|
|
@@ -122,9 +119,7 @@ Git config `devlyn.warmBuildDirs` is true, or it is unset and the Cargo workspac
|
|
|
122
119
|
Cargo.toml sets `[workspace.metadata.devlyn] warm-build-dirs = true`,
|
|
123
120
|
allocation seeds that directory from a built checkout of the repository, so
|
|
124
121
|
the first build does not rebuild every dependency; `build_dirs` in its result
|
|
125
|
-
and receipt says what it did, and a skip means an ordinary cold build.
|
|
126
|
-
Git setting takes precedence on this machine: false disables and invalid values
|
|
127
|
-
skip; global, system, include and per-worktree values are not consulted. Seeding
|
|
122
|
+
and receipt says what it did, and a skip means an ordinary cold build. Seeding
|
|
128
123
|
keeps dependency outputs that may hold the other checkout's paths, and those
|
|
129
124
|
follow that checkout's later rebuilds. `warm-build-dirs.py <worktree>` does the same for a
|
|
130
125
|
worktree made without allocation. A warmed directory leaves with the worktree
|
|
@@ -146,11 +141,7 @@ python3 "$DEVLYN_SHARED_DIR/task-complete.py" clean-scratch \
|
|
|
146
141
|
--receipt '<returned receipt.json>' --writers-stopped
|
|
147
142
|
```
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
identity for interrupted cleanup and later builds, checks live users and reports
|
|
151
|
-
the logical byte count separately from actual free disk space.
|
|
152
|
-
Unknown historical roots, source/recovery data, shared caches and terminal
|
|
153
|
-
history are never adopted or swept. A refused cleanup does not block source
|
|
144
|
+
A refused cleanup does not block source
|
|
154
145
|
delivery; it stays visible in the handoff with its receipt and retry command
|
|
155
146
|
(`CLEANUP_PENDING` after delivered source). No task is described as cleaned
|
|
156
147
|
while owned disposable files remain. On resumption, finish any pending scratch
|
|
@@ -257,9 +248,6 @@ are preserved beside it as `records.<digest>/.devlyn`, never rewriting earlier c
|
|
|
257
248
|
Non-regular files or symlinks there, partial/corrupt custody, an unreadable
|
|
258
249
|
earlier copy or a mismatched `records.<digest>` copy retain the tree for repair.
|
|
259
250
|
|
|
260
|
-
|
|
261
|
-
checked out; their checkout is never modified. Local ref deletion is guarded by
|
|
262
|
-
the expected SHA; remote deletion uses an exact force-with-lease solely as
|
|
263
|
-
compare-and-delete, never for product publication. A changed remote branch is
|
|
251
|
+
A changed remote branch is
|
|
264
252
|
retained. Retry uses the external receipt/evidence after removal. Recovery
|
|
265
253
|
refs/evidence have no automatic expiry.
|
|
@@ -55,11 +55,9 @@ Package cleanup, parent pruning and report failures appear as diagnostics under
|
|
|
55
55
|
|
|
56
56
|
## Release binding and read-only consumers
|
|
57
57
|
|
|
58
|
-
`<git-common-dir>/devlyn-loops/harness.json` is authoritative across linked worktrees: `{schemaVersion: 1, release: {package, version, digest, root}, defaults: {path, sha256}}`. Paths are absolute and hashes cover exact bytes. The queue lock covers binding before the first capture. An interrupted first add, unfinished tasks, recovery conflicts and pending delivery retain it; settlement removes it.
|
|
58
|
+
`<git-common-dir>/devlyn-loops/harness.json` is authoritative across linked worktrees: `{schemaVersion: 1, release: {package, version, digest, root}, defaults: {path, sha256}}`. Paths are absolute and hashes cover exact bytes. The queue lock covers binding before the first capture. An interrupted first add, unfinished tasks, recovery conflicts and pending delivery retain it; settlement removes it. No caller substitutes another implementation.
|
|
59
59
|
|
|
60
|
-
`queue.py inspect --repo <dir> --json` reads without cleanup, locks or writes. It returns the status summary plus `binding` (null for legacy) and `compatibility`: `compatible`, `legacy`, `reasons`, `recoveryArgv`, `taskPacket` ranges and `queueBinding` ranges. Incompatible or unreadable state is reported, never migrated.
|
|
61
|
-
|
|
62
|
-
Codex projection writers place `.devlyn-harness-projection.json` at the copied plugin root, beside `skills` and `.codex-plugin`: `{schemaVersion: 1, release: <ReleaseRef>, source: "native/codex/plugins/devlyn"}`. The reader verifies the named release and every projected file’s bytes/mode against that subtree (excluding only the marker). Symlinked skill invocations resolve through their real path. Standalone installs and existing unfinished unbound queues retain legacy behavior; new legacy packets use v2 with a null release, and their `defaults` name the invoking installation's own `_shared/runtime-principles.md` (`source: "skill"`). No engine applicability is inferred from instruction filenames: bound queues use verified release defaults with native instructions taking precedence, except a Devlyn managed block, which the defaults replace. Worker and runner paths point to the bound release, independent of a projection cache’s lifetime.
|
|
60
|
+
`queue.py inspect --repo <dir> --json` reads without cleanup, locks or writes. It returns the status summary plus `binding` (null for legacy) and `compatibility`: `compatible`, `legacy`, `reasons`, `recoveryArgv`, `taskPacket` ranges and `queueBinding` ranges. Incompatible or unreadable state is reported, never migrated. For a mismatch, `recoveryArgv` names the bound queue’s inspect invocation when handoff is allowed, and is null when the refusal names Drain in Devlyn, tasks to finish first, or a repair. Use an exact recovery argv when provided; otherwise follow the refusal.
|
|
63
61
|
|
|
64
62
|
## Executor exchange
|
|
65
63
|
|
|
@@ -107,7 +107,6 @@ Coverage proves that every obligation has evidence. Whether the checks express t
|
|
|
107
107
|
- The only legal transition turns one pending row into `[x]` or `[F]` with every other byte unchanged, so a terminal commit changes one line of its loop's file. Terminal rows are never reinterpreted or rerun. The blank lines let transitions of adjacent rows merge, and loops never share a file.
|
|
108
108
|
- Identities are unique; equal titles are fine.
|
|
109
109
|
- `docs/specs/queue.md` is the legacy queue. Its raw rows are intents: readable, never executed, never written (a row there that fully matches this grammar is ignored). `add --materialize <line>` plans one pending legacy row as a loop whose `## Intent` reproduces it verbatim (whitespace may reflow); that loop's queue file starts with `<!-- replaces docs/specs/queue.md row (occurrence <n>): <row> -->`, the row's exact text and its occurrence among equal rows, line endings aside. Every checkout, a fresh clone included, then shows the loop's rows in that row's place. A claim matching no row replaces nothing; a row two loops claim (two clones each materializing it) is hidden, neither loop taking its place, so it is never planned again.
|
|
110
|
-
- Status and drain read the legacy rows in file order, each replaced row as its loop's rows; then the other recorded loops in add order, from their captures; then loops without a record here, as in a fresh clone, from the checkout's tracked queue files in loop-id order.
|
|
111
110
|
|
|
112
111
|
## Commands
|
|
113
112
|
|
package/harness/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- devlyn:instructions:begin sha256=
|
|
1
|
+
<!-- devlyn:instructions:begin sha256=eaf6d144bcb25ac8c5e628a134dc4422f5af7641f9c34ccdb8f06d1613718c48 -->
|
|
2
2
|
Project-specific instructions outside this managed block take precedence over these defaults.
|
|
3
3
|
|
|
4
4
|
# Project Instructions
|
|
@@ -30,7 +30,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
30
30
|
## Quick Start
|
|
31
31
|
|
|
32
32
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
33
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
33
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
34
34
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
35
35
|
|
|
36
36
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
package/harness/CLAUDE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- devlyn:instructions:begin sha256=
|
|
1
|
+
<!-- devlyn:instructions:begin sha256=eaf6d144bcb25ac8c5e628a134dc4422f5af7641f9c34ccdb8f06d1613718c48 -->
|
|
2
2
|
Project-specific instructions outside this managed block take precedence over these defaults.
|
|
3
3
|
|
|
4
4
|
# Project Instructions
|
|
@@ -30,7 +30,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
30
30
|
## Quick Start
|
|
31
31
|
|
|
32
32
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
33
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
33
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
34
34
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
35
35
|
|
|
36
36
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Shared — Executor Pre-flight
|
|
2
2
|
|
|
3
|
-
Used by `/devlyn-ideate` and `/devlyn-engines`: one rule for which engine executes implementation work and what happens when it is missing.
|
|
4
|
-
|
|
5
3
|
## Selection
|
|
6
4
|
|
|
7
5
|
The executor is the `executor` pin in `.devlyn/engines.json` at the checkout root (set with `/devlyn-engines executor <name>`), else the CLI the user opened. A linked worktree or subdirectory has no pin unless one is set there. Only Claude and Codex can execute, so a drain from any other CLI needs a claude or codex pin. Keys earlier releases wrote for retired pipeline roles (`pair_judge_priority`, `roles`) stay as written and select nothing: a worker profile never becomes the executor.
|
|
@@ -29,7 +29,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
31
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
32
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
32
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
33
33
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
34
34
|
|
|
35
35
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
|
@@ -62,9 +62,6 @@ The repository comes from the remote's GitHub URL and the base from the reposito
|
|
|
62
62
|
A non-default base is refused at allocation.
|
|
63
63
|
Every delivery allocation owns a linked worktree; `--worktree` is required and
|
|
64
64
|
must name an absent path.
|
|
65
|
-
Cleanup removes empty parents through the exact per-repo root shown above or its legacy `.devlyn.noindex`/`.devlyn` root, keeping the shared `.devlyn-worktrees` container. Allocation also sweeps empty legacy roots for this repo.
|
|
66
|
-
On Windows, allocation marks only a newly created shared container hidden and creates the worktree not content-indexed (content only; names stay indexed); files copied in keep their own attributes.
|
|
67
|
-
A marking failure continues allocation and is reported in `warnings`.
|
|
68
65
|
Remote allocation first cleans earlier merged deliveries, then allocation refuses with `BLOCKED:disk`
|
|
69
66
|
without creating a receipt, branch or worktree when that filesystem has less than max(10 GiB, 2%) free; free space and allocate again.
|
|
70
67
|
A publication allocation normally starts at the exact fetched remote base,
|
|
@@ -122,9 +119,7 @@ Git config `devlyn.warmBuildDirs` is true, or it is unset and the Cargo workspac
|
|
|
122
119
|
Cargo.toml sets `[workspace.metadata.devlyn] warm-build-dirs = true`,
|
|
123
120
|
allocation seeds that directory from a built checkout of the repository, so
|
|
124
121
|
the first build does not rebuild every dependency; `build_dirs` in its result
|
|
125
|
-
and receipt says what it did, and a skip means an ordinary cold build.
|
|
126
|
-
Git setting takes precedence on this machine: false disables and invalid values
|
|
127
|
-
skip; global, system, include and per-worktree values are not consulted. Seeding
|
|
122
|
+
and receipt says what it did, and a skip means an ordinary cold build. Seeding
|
|
128
123
|
keeps dependency outputs that may hold the other checkout's paths, and those
|
|
129
124
|
follow that checkout's later rebuilds. `warm-build-dirs.py <worktree>` does the same for a
|
|
130
125
|
worktree made without allocation. A warmed directory leaves with the worktree
|
|
@@ -146,11 +141,7 @@ python3 "$DEVLYN_SHARED_DIR/task-complete.py" clean-scratch \
|
|
|
146
141
|
--receipt '<returned receipt.json>' --writers-stopped
|
|
147
142
|
```
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
identity for interrupted cleanup and later builds, checks live users and reports
|
|
151
|
-
the logical byte count separately from actual free disk space.
|
|
152
|
-
Unknown historical roots, source/recovery data, shared caches and terminal
|
|
153
|
-
history are never adopted or swept. A refused cleanup does not block source
|
|
144
|
+
A refused cleanup does not block source
|
|
154
145
|
delivery; it stays visible in the handoff with its receipt and retry command
|
|
155
146
|
(`CLEANUP_PENDING` after delivered source). No task is described as cleaned
|
|
156
147
|
while owned disposable files remain. On resumption, finish any pending scratch
|
|
@@ -257,9 +248,6 @@ are preserved beside it as `records.<digest>/.devlyn`, never rewriting earlier c
|
|
|
257
248
|
Non-regular files or symlinks there, partial/corrupt custody, an unreadable
|
|
258
249
|
earlier copy or a mismatched `records.<digest>` copy retain the tree for repair.
|
|
259
250
|
|
|
260
|
-
|
|
261
|
-
checked out; their checkout is never modified. Local ref deletion is guarded by
|
|
262
|
-
the expected SHA; remote deletion uses an exact force-with-lease solely as
|
|
263
|
-
compare-and-delete, never for product publication. A changed remote branch is
|
|
251
|
+
A changed remote branch is
|
|
264
252
|
retained. Retry uses the external receipt/evidence after removal. Recovery
|
|
265
253
|
refs/evidence have no automatic expiry.
|
|
@@ -55,11 +55,9 @@ Package cleanup, parent pruning and report failures appear as diagnostics under
|
|
|
55
55
|
|
|
56
56
|
## Release binding and read-only consumers
|
|
57
57
|
|
|
58
|
-
`<git-common-dir>/devlyn-loops/harness.json` is authoritative across linked worktrees: `{schemaVersion: 1, release: {package, version, digest, root}, defaults: {path, sha256}}`. Paths are absolute and hashes cover exact bytes. The queue lock covers binding before the first capture. An interrupted first add, unfinished tasks, recovery conflicts and pending delivery retain it; settlement removes it.
|
|
58
|
+
`<git-common-dir>/devlyn-loops/harness.json` is authoritative across linked worktrees: `{schemaVersion: 1, release: {package, version, digest, root}, defaults: {path, sha256}}`. Paths are absolute and hashes cover exact bytes. The queue lock covers binding before the first capture. An interrupted first add, unfinished tasks, recovery conflicts and pending delivery retain it; settlement removes it. No caller substitutes another implementation.
|
|
59
59
|
|
|
60
|
-
`queue.py inspect --repo <dir> --json` reads without cleanup, locks or writes. It returns the status summary plus `binding` (null for legacy) and `compatibility`: `compatible`, `legacy`, `reasons`, `recoveryArgv`, `taskPacket` ranges and `queueBinding` ranges. Incompatible or unreadable state is reported, never migrated.
|
|
61
|
-
|
|
62
|
-
Codex projection writers place `.devlyn-harness-projection.json` at the copied plugin root, beside `skills` and `.codex-plugin`: `{schemaVersion: 1, release: <ReleaseRef>, source: "native/codex/plugins/devlyn"}`. The reader verifies the named release and every projected file’s bytes/mode against that subtree (excluding only the marker). Symlinked skill invocations resolve through their real path. Standalone installs and existing unfinished unbound queues retain legacy behavior; new legacy packets use v2 with a null release, and their `defaults` name the invoking installation's own `_shared/runtime-principles.md` (`source: "skill"`). No engine applicability is inferred from instruction filenames: bound queues use verified release defaults with native instructions taking precedence, except a Devlyn managed block, which the defaults replace. Worker and runner paths point to the bound release, independent of a projection cache’s lifetime.
|
|
60
|
+
`queue.py inspect --repo <dir> --json` reads without cleanup, locks or writes. It returns the status summary plus `binding` (null for legacy) and `compatibility`: `compatible`, `legacy`, `reasons`, `recoveryArgv`, `taskPacket` ranges and `queueBinding` ranges. Incompatible or unreadable state is reported, never migrated. For a mismatch, `recoveryArgv` names the bound queue’s inspect invocation when handoff is allowed, and is null when the refusal names Drain in Devlyn, tasks to finish first, or a repair. Use an exact recovery argv when provided; otherwise follow the refusal.
|
|
63
61
|
|
|
64
62
|
## Executor exchange
|
|
65
63
|
|
|
@@ -107,7 +107,6 @@ Coverage proves that every obligation has evidence. Whether the checks express t
|
|
|
107
107
|
- The only legal transition turns one pending row into `[x]` or `[F]` with every other byte unchanged, so a terminal commit changes one line of its loop's file. Terminal rows are never reinterpreted or rerun. The blank lines let transitions of adjacent rows merge, and loops never share a file.
|
|
108
108
|
- Identities are unique; equal titles are fine.
|
|
109
109
|
- `docs/specs/queue.md` is the legacy queue. Its raw rows are intents: readable, never executed, never written (a row there that fully matches this grammar is ignored). `add --materialize <line>` plans one pending legacy row as a loop whose `## Intent` reproduces it verbatim (whitespace may reflow); that loop's queue file starts with `<!-- replaces docs/specs/queue.md row (occurrence <n>): <row> -->`, the row's exact text and its occurrence among equal rows, line endings aside. Every checkout, a fresh clone included, then shows the loop's rows in that row's place. A claim matching no row replaces nothing; a row two loops claim (two clones each materializing it) is hidden, neither loop taking its place, so it is never planned again.
|
|
110
|
-
- Status and drain read the legacy rows in file order, each replaced row as its loop's rows; then the other recorded loops in add order, from their captures; then loops without a record here, as in a fresh clone, from the checkout's tracked queue files in loop-id order.
|
|
111
110
|
|
|
112
111
|
## Commands
|
|
113
112
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Shared — Executor Pre-flight
|
|
2
2
|
|
|
3
|
-
Used by `/devlyn-ideate` and `/devlyn-engines`: one rule for which engine executes implementation work and what happens when it is missing.
|
|
4
|
-
|
|
5
3
|
## Selection
|
|
6
4
|
|
|
7
5
|
The executor is the `executor` pin in `.devlyn/engines.json` at the checkout root (set with `/devlyn-engines executor <name>`), else the CLI the user opened. A linked worktree or subdirectory has no pin unless one is set there. Only Claude and Codex can execute, so a drain from any other CLI needs a claude or codex pin. Keys earlier releases wrote for retired pipeline roles (`pair_judge_priority`, `roles`) stay as written and select nothing: a worker profile never becomes the executor.
|
|
@@ -29,7 +29,7 @@ Three discipline rules govern HOW the principles are applied:
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
31
|
- `devlyn-ideate` — loop designer and intent queue: `plan <intent or document>` writes a validated loop package, `add` queues its tasks, `status` (or no arguments) reports the queue, `drain` executes it serially.
|
|
32
|
-
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md
|
|
32
|
+
- Delivery — direct work edits the current checkout; deliver completed, verified requests with changes by project policy (default PR and merge), following `_shared/task-completion.md`. With known concurrent writers, isolate before editing; on unexplained changes, pause writes until safe or isolated. An ideate drain delivers every task. Explicit limits win; commit alone stays local.
|
|
33
33
|
- Executor — `devlyn-engines` shows it and pins it in `.devlyn/engines.json`. A pinned executor does the implementation work, direct or drained: when it is not you, delegate to it, and when it is unavailable stop with `BLOCKED:<engine>-unavailable`. Without a pin, you are the executor.
|
|
34
34
|
|
|
35
35
|
Each skill's `SKILL.md` is the source of truth for its flags and workflow.
|
|
@@ -62,9 +62,6 @@ The repository comes from the remote's GitHub URL and the base from the reposito
|
|
|
62
62
|
A non-default base is refused at allocation.
|
|
63
63
|
Every delivery allocation owns a linked worktree; `--worktree` is required and
|
|
64
64
|
must name an absent path.
|
|
65
|
-
Cleanup removes empty parents through the exact per-repo root shown above or its legacy `.devlyn.noindex`/`.devlyn` root, keeping the shared `.devlyn-worktrees` container. Allocation also sweeps empty legacy roots for this repo.
|
|
66
|
-
On Windows, allocation marks only a newly created shared container hidden and creates the worktree not content-indexed (content only; names stay indexed); files copied in keep their own attributes.
|
|
67
|
-
A marking failure continues allocation and is reported in `warnings`.
|
|
68
65
|
Remote allocation first cleans earlier merged deliveries, then allocation refuses with `BLOCKED:disk`
|
|
69
66
|
without creating a receipt, branch or worktree when that filesystem has less than max(10 GiB, 2%) free; free space and allocate again.
|
|
70
67
|
A publication allocation normally starts at the exact fetched remote base,
|
|
@@ -122,9 +119,7 @@ Git config `devlyn.warmBuildDirs` is true, or it is unset and the Cargo workspac
|
|
|
122
119
|
Cargo.toml sets `[workspace.metadata.devlyn] warm-build-dirs = true`,
|
|
123
120
|
allocation seeds that directory from a built checkout of the repository, so
|
|
124
121
|
the first build does not rebuild every dependency; `build_dirs` in its result
|
|
125
|
-
and receipt says what it did, and a skip means an ordinary cold build.
|
|
126
|
-
Git setting takes precedence on this machine: false disables and invalid values
|
|
127
|
-
skip; global, system, include and per-worktree values are not consulted. Seeding
|
|
122
|
+
and receipt says what it did, and a skip means an ordinary cold build. Seeding
|
|
128
123
|
keeps dependency outputs that may hold the other checkout's paths, and those
|
|
129
124
|
follow that checkout's later rebuilds. `warm-build-dirs.py <worktree>` does the same for a
|
|
130
125
|
worktree made without allocation. A warmed directory leaves with the worktree
|
|
@@ -146,11 +141,7 @@ python3 "$DEVLYN_SHARED_DIR/task-complete.py" clean-scratch \
|
|
|
146
141
|
--receipt '<returned receipt.json>' --writers-stopped
|
|
147
142
|
```
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
identity for interrupted cleanup and later builds, checks live users and reports
|
|
151
|
-
the logical byte count separately from actual free disk space.
|
|
152
|
-
Unknown historical roots, source/recovery data, shared caches and terminal
|
|
153
|
-
history are never adopted or swept. A refused cleanup does not block source
|
|
144
|
+
A refused cleanup does not block source
|
|
154
145
|
delivery; it stays visible in the handoff with its receipt and retry command
|
|
155
146
|
(`CLEANUP_PENDING` after delivered source). No task is described as cleaned
|
|
156
147
|
while owned disposable files remain. On resumption, finish any pending scratch
|
|
@@ -257,9 +248,6 @@ are preserved beside it as `records.<digest>/.devlyn`, never rewriting earlier c
|
|
|
257
248
|
Non-regular files or symlinks there, partial/corrupt custody, an unreadable
|
|
258
249
|
earlier copy or a mismatched `records.<digest>` copy retain the tree for repair.
|
|
259
250
|
|
|
260
|
-
|
|
261
|
-
checked out; their checkout is never modified. Local ref deletion is guarded by
|
|
262
|
-
the expected SHA; remote deletion uses an exact force-with-lease solely as
|
|
263
|
-
compare-and-delete, never for product publication. A changed remote branch is
|
|
251
|
+
A changed remote branch is
|
|
264
252
|
retained. Retry uses the external receipt/evidence after removal. Recovery
|
|
265
253
|
refs/evidence have no automatic expiry.
|
|
@@ -55,11 +55,9 @@ Package cleanup, parent pruning and report failures appear as diagnostics under
|
|
|
55
55
|
|
|
56
56
|
## Release binding and read-only consumers
|
|
57
57
|
|
|
58
|
-
`<git-common-dir>/devlyn-loops/harness.json` is authoritative across linked worktrees: `{schemaVersion: 1, release: {package, version, digest, root}, defaults: {path, sha256}}`. Paths are absolute and hashes cover exact bytes. The queue lock covers binding before the first capture. An interrupted first add, unfinished tasks, recovery conflicts and pending delivery retain it; settlement removes it.
|
|
58
|
+
`<git-common-dir>/devlyn-loops/harness.json` is authoritative across linked worktrees: `{schemaVersion: 1, release: {package, version, digest, root}, defaults: {path, sha256}}`. Paths are absolute and hashes cover exact bytes. The queue lock covers binding before the first capture. An interrupted first add, unfinished tasks, recovery conflicts and pending delivery retain it; settlement removes it. No caller substitutes another implementation.
|
|
59
59
|
|
|
60
|
-
`queue.py inspect --repo <dir> --json` reads without cleanup, locks or writes. It returns the status summary plus `binding` (null for legacy) and `compatibility`: `compatible`, `legacy`, `reasons`, `recoveryArgv`, `taskPacket` ranges and `queueBinding` ranges. Incompatible or unreadable state is reported, never migrated.
|
|
61
|
-
|
|
62
|
-
Codex projection writers place `.devlyn-harness-projection.json` at the copied plugin root, beside `skills` and `.codex-plugin`: `{schemaVersion: 1, release: <ReleaseRef>, source: "native/codex/plugins/devlyn"}`. The reader verifies the named release and every projected file’s bytes/mode against that subtree (excluding only the marker). Symlinked skill invocations resolve through their real path. Standalone installs and existing unfinished unbound queues retain legacy behavior; new legacy packets use v2 with a null release, and their `defaults` name the invoking installation's own `_shared/runtime-principles.md` (`source: "skill"`). No engine applicability is inferred from instruction filenames: bound queues use verified release defaults with native instructions taking precedence, except a Devlyn managed block, which the defaults replace. Worker and runner paths point to the bound release, independent of a projection cache’s lifetime.
|
|
60
|
+
`queue.py inspect --repo <dir> --json` reads without cleanup, locks or writes. It returns the status summary plus `binding` (null for legacy) and `compatibility`: `compatible`, `legacy`, `reasons`, `recoveryArgv`, `taskPacket` ranges and `queueBinding` ranges. Incompatible or unreadable state is reported, never migrated. For a mismatch, `recoveryArgv` names the bound queue’s inspect invocation when handoff is allowed, and is null when the refusal names Drain in Devlyn, tasks to finish first, or a repair. Use an exact recovery argv when provided; otherwise follow the refusal.
|
|
63
61
|
|
|
64
62
|
## Executor exchange
|
|
65
63
|
|
|
@@ -107,7 +107,6 @@ Coverage proves that every obligation has evidence. Whether the checks express t
|
|
|
107
107
|
- The only legal transition turns one pending row into `[x]` or `[F]` with every other byte unchanged, so a terminal commit changes one line of its loop's file. Terminal rows are never reinterpreted or rerun. The blank lines let transitions of adjacent rows merge, and loops never share a file.
|
|
108
108
|
- Identities are unique; equal titles are fine.
|
|
109
109
|
- `docs/specs/queue.md` is the legacy queue. Its raw rows are intents: readable, never executed, never written (a row there that fully matches this grammar is ignored). `add --materialize <line>` plans one pending legacy row as a loop whose `## Intent` reproduces it verbatim (whitespace may reflow); that loop's queue file starts with `<!-- replaces docs/specs/queue.md row (occurrence <n>): <row> -->`, the row's exact text and its occurrence among equal rows, line endings aside. Every checkout, a fresh clone included, then shows the loop's rows in that row's place. A claim matching no row replaces nothing; a row two loops claim (two clones each materializing it) is hidden, neither loop taking its place, so it is never planned again.
|
|
110
|
-
- Status and drain read the legacy rows in file order, each replaced row as its loop's rows; then the other recorded loops in add order, from their captures; then loops without a record here, as in a fresh clone, from the checkout's tracked queue files in loop-id order.
|
|
111
110
|
|
|
112
111
|
## Commands
|
|
113
112
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devlyn-cli",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.30",
|
|
4
4
|
"description": "Loop & harness engineering for AI coding agents (Claude Code, Codex, and any AGENTS.md-driven agent) — core engineering principles for every session 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,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "devlyn-cli",
|
|
4
|
-
"version": "4.3.
|
|
4
|
+
"version": "4.3.30",
|
|
5
5
|
"principles": {
|
|
6
6
|
"defaults": "config/skills/_shared/runtime-principles.md",
|
|
7
7
|
"memory": {
|
|
8
8
|
"claude": "harness/CLAUDE.md",
|
|
9
9
|
"agents": "harness/AGENTS.md"
|
|
10
10
|
},
|
|
11
|
-
"sourceBlockSha256": "
|
|
11
|
+
"sourceBlockSha256": "eaf6d144bcb25ac8c5e628a134dc4422f5af7641f9c34ccdb8f06d1613718c48"
|
|
12
12
|
},
|
|
13
13
|
"skills": {
|
|
14
14
|
"root": "config/skills",
|
|
@@ -99,12 +99,12 @@
|
|
|
99
99
|
"files": [
|
|
100
100
|
{
|
|
101
101
|
"path": "AGENTS.md",
|
|
102
|
-
"sha256": "
|
|
102
|
+
"sha256": "df67efd70f4760d2415c414eb96d4cc426277c20e18f17e401257f85b489eb59",
|
|
103
103
|
"executable": false
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
"path": "CLAUDE.md",
|
|
107
|
-
"sha256": "
|
|
107
|
+
"sha256": "df67efd70f4760d2415c414eb96d4cc426277c20e18f17e401257f85b489eb59",
|
|
108
108
|
"executable": false
|
|
109
109
|
},
|
|
110
110
|
{
|
|
@@ -134,17 +134,17 @@
|
|
|
134
134
|
},
|
|
135
135
|
{
|
|
136
136
|
"path": "bin/engines.js",
|
|
137
|
-
"sha256": "
|
|
137
|
+
"sha256": "7c1910a2b399d61c4dd8e576244e6bfe91215581f599cb84fc763487a3bce743",
|
|
138
138
|
"executable": false
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"path": "bin/harness-activation.js",
|
|
142
|
-
"sha256": "
|
|
142
|
+
"sha256": "e5428bf6fb2dc40e0f7bebcc834b54573c0b8c648570fea8bd51774d5e865727",
|
|
143
143
|
"executable": false
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
"path": "bin/harness-context.js",
|
|
147
|
-
"sha256": "
|
|
147
|
+
"sha256": "2d2cd812fec2db659b7bb8b40f22fa10acde1c754c16265b81994645a9bfc29f",
|
|
148
148
|
"executable": false
|
|
149
149
|
},
|
|
150
150
|
{
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
},
|
|
160
160
|
{
|
|
161
161
|
"path": "bin/instruction-templates.json",
|
|
162
|
-
"sha256": "
|
|
162
|
+
"sha256": "752cc4b023930ca696395fb071b93d17a6fabf34aec9e2b993e88f2d2d1673c9",
|
|
163
163
|
"executable": false
|
|
164
164
|
},
|
|
165
165
|
{
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
176
|
"path": "bin/skill-history.json",
|
|
177
|
-
"sha256": "
|
|
177
|
+
"sha256": "de454d15a5d1e81f0f69f5d1d781ea02d8b19554695458a993d74596d5055146",
|
|
178
178
|
"executable": false
|
|
179
179
|
},
|
|
180
180
|
{
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
},
|
|
220
220
|
{
|
|
221
221
|
"path": "config/skills/_shared/engine-preflight.md",
|
|
222
|
-
"sha256": "
|
|
222
|
+
"sha256": "d1cc430847a659fe0ea946ce09bfac30ec2596ce8707c5bf280e60f24a0771fb",
|
|
223
223
|
"executable": false
|
|
224
224
|
},
|
|
225
225
|
{
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
"path": "config/skills/_shared/runtime-principles.md",
|
|
262
|
-
"sha256": "
|
|
262
|
+
"sha256": "a8544f866db7b8e49617f14519908a601cbd8b92786cecb521cba5c28421a7f7",
|
|
263
263
|
"executable": false
|
|
264
264
|
},
|
|
265
265
|
{
|
|
@@ -279,7 +279,7 @@
|
|
|
279
279
|
},
|
|
280
280
|
{
|
|
281
281
|
"path": "config/skills/_shared/task-completion.md",
|
|
282
|
-
"sha256": "
|
|
282
|
+
"sha256": "3b75502d363ba5fa3b45c06a1f3e0de7c88e609d4f91c41d75287a0acccdd504",
|
|
283
283
|
"executable": false
|
|
284
284
|
},
|
|
285
285
|
{
|
|
@@ -314,12 +314,12 @@
|
|
|
314
314
|
},
|
|
315
315
|
{
|
|
316
316
|
"path": "config/skills/devlyn-ideate/references/loop.md",
|
|
317
|
-
"sha256": "
|
|
317
|
+
"sha256": "ad64d90fb775b05ef774c2457fc9d994b062e17e017da07054be0d93d83e533f",
|
|
318
318
|
"executable": false
|
|
319
319
|
},
|
|
320
320
|
{
|
|
321
321
|
"path": "config/skills/devlyn-ideate/references/package-format.md",
|
|
322
|
-
"sha256": "
|
|
322
|
+
"sha256": "0b7c780db5f8e3149f1da5802ad5d9def7d60b46d21699807c72c997fe2d67fc",
|
|
323
323
|
"executable": false
|
|
324
324
|
},
|
|
325
325
|
{
|
|
@@ -344,17 +344,17 @@
|
|
|
344
344
|
},
|
|
345
345
|
{
|
|
346
346
|
"path": "harness/AGENTS.md",
|
|
347
|
-
"sha256": "
|
|
347
|
+
"sha256": "68c354a51eae0b77eaa909ec2a11b1ca498c62905e133375929c73085c638d10",
|
|
348
348
|
"executable": false
|
|
349
349
|
},
|
|
350
350
|
{
|
|
351
351
|
"path": "harness/CLAUDE.md",
|
|
352
|
-
"sha256": "
|
|
352
|
+
"sha256": "68c354a51eae0b77eaa909ec2a11b1ca498c62905e133375929c73085c638d10",
|
|
353
353
|
"executable": false
|
|
354
354
|
},
|
|
355
355
|
{
|
|
356
356
|
"path": "native/claude/.claude-plugin/plugin.json",
|
|
357
|
-
"sha256": "
|
|
357
|
+
"sha256": "1c66282653ed10919933b783dbff4353b9a315340d1ceb6d9edb9caf963a23e1",
|
|
358
358
|
"executable": false
|
|
359
359
|
},
|
|
360
360
|
{
|
|
@@ -394,7 +394,7 @@
|
|
|
394
394
|
},
|
|
395
395
|
{
|
|
396
396
|
"path": "native/claude/skills/_shared/engine-preflight.md",
|
|
397
|
-
"sha256": "
|
|
397
|
+
"sha256": "d1cc430847a659fe0ea946ce09bfac30ec2596ce8707c5bf280e60f24a0771fb",
|
|
398
398
|
"executable": false
|
|
399
399
|
},
|
|
400
400
|
{
|
|
@@ -434,7 +434,7 @@
|
|
|
434
434
|
},
|
|
435
435
|
{
|
|
436
436
|
"path": "native/claude/skills/_shared/runtime-principles.md",
|
|
437
|
-
"sha256": "
|
|
437
|
+
"sha256": "a8544f866db7b8e49617f14519908a601cbd8b92786cecb521cba5c28421a7f7",
|
|
438
438
|
"executable": false
|
|
439
439
|
},
|
|
440
440
|
{
|
|
@@ -454,7 +454,7 @@
|
|
|
454
454
|
},
|
|
455
455
|
{
|
|
456
456
|
"path": "native/claude/skills/_shared/task-completion.md",
|
|
457
|
-
"sha256": "
|
|
457
|
+
"sha256": "3b75502d363ba5fa3b45c06a1f3e0de7c88e609d4f91c41d75287a0acccdd504",
|
|
458
458
|
"executable": false
|
|
459
459
|
},
|
|
460
460
|
{
|
|
@@ -489,12 +489,12 @@
|
|
|
489
489
|
},
|
|
490
490
|
{
|
|
491
491
|
"path": "native/claude/skills/devlyn-ideate/references/loop.md",
|
|
492
|
-
"sha256": "
|
|
492
|
+
"sha256": "ad64d90fb775b05ef774c2457fc9d994b062e17e017da07054be0d93d83e533f",
|
|
493
493
|
"executable": false
|
|
494
494
|
},
|
|
495
495
|
{
|
|
496
496
|
"path": "native/claude/skills/devlyn-ideate/references/package-format.md",
|
|
497
|
-
"sha256": "
|
|
497
|
+
"sha256": "0b7c780db5f8e3149f1da5802ad5d9def7d60b46d21699807c72c997fe2d67fc",
|
|
498
498
|
"executable": false
|
|
499
499
|
},
|
|
500
500
|
{
|
|
@@ -514,12 +514,12 @@
|
|
|
514
514
|
},
|
|
515
515
|
{
|
|
516
516
|
"path": "native/codex/.agents/plugins/marketplace.json",
|
|
517
|
-
"sha256": "
|
|
517
|
+
"sha256": "2b589b387dd262bbb68f68738c9da6315dd06595d0af0dc5c088151235a5a7c8",
|
|
518
518
|
"executable": false
|
|
519
519
|
},
|
|
520
520
|
{
|
|
521
521
|
"path": "native/codex/plugins/devlyn/.codex-plugin/plugin.json",
|
|
522
|
-
"sha256": "
|
|
522
|
+
"sha256": "1c66282653ed10919933b783dbff4353b9a315340d1ceb6d9edb9caf963a23e1",
|
|
523
523
|
"executable": false
|
|
524
524
|
},
|
|
525
525
|
{
|
|
@@ -559,7 +559,7 @@
|
|
|
559
559
|
},
|
|
560
560
|
{
|
|
561
561
|
"path": "native/codex/plugins/devlyn/skills/_shared/engine-preflight.md",
|
|
562
|
-
"sha256": "
|
|
562
|
+
"sha256": "d1cc430847a659fe0ea946ce09bfac30ec2596ce8707c5bf280e60f24a0771fb",
|
|
563
563
|
"executable": false
|
|
564
564
|
},
|
|
565
565
|
{
|
|
@@ -599,7 +599,7 @@
|
|
|
599
599
|
},
|
|
600
600
|
{
|
|
601
601
|
"path": "native/codex/plugins/devlyn/skills/_shared/runtime-principles.md",
|
|
602
|
-
"sha256": "
|
|
602
|
+
"sha256": "a8544f866db7b8e49617f14519908a601cbd8b92786cecb521cba5c28421a7f7",
|
|
603
603
|
"executable": false
|
|
604
604
|
},
|
|
605
605
|
{
|
|
@@ -619,7 +619,7 @@
|
|
|
619
619
|
},
|
|
620
620
|
{
|
|
621
621
|
"path": "native/codex/plugins/devlyn/skills/_shared/task-completion.md",
|
|
622
|
-
"sha256": "
|
|
622
|
+
"sha256": "3b75502d363ba5fa3b45c06a1f3e0de7c88e609d4f91c41d75287a0acccdd504",
|
|
623
623
|
"executable": false
|
|
624
624
|
},
|
|
625
625
|
{
|
|
@@ -654,12 +654,12 @@
|
|
|
654
654
|
},
|
|
655
655
|
{
|
|
656
656
|
"path": "native/codex/plugins/devlyn/skills/devlyn-ideate/references/loop.md",
|
|
657
|
-
"sha256": "
|
|
657
|
+
"sha256": "ad64d90fb775b05ef774c2457fc9d994b062e17e017da07054be0d93d83e533f",
|
|
658
658
|
"executable": false
|
|
659
659
|
},
|
|
660
660
|
{
|
|
661
661
|
"path": "native/codex/plugins/devlyn/skills/devlyn-ideate/references/package-format.md",
|
|
662
|
-
"sha256": "
|
|
662
|
+
"sha256": "0b7c780db5f8e3149f1da5802ad5d9def7d60b46d21699807c72c997fe2d67fc",
|
|
663
663
|
"executable": false
|
|
664
664
|
},
|
|
665
665
|
{
|
|
@@ -1819,12 +1819,12 @@
|
|
|
1819
1819
|
},
|
|
1820
1820
|
{
|
|
1821
1821
|
"path": "package.json",
|
|
1822
|
-
"sha256": "
|
|
1822
|
+
"sha256": "e4f8b96ad2ca5dd7298d1db30e321e3e965f76d1fa0e4fc4a3e4e1012e124822",
|
|
1823
1823
|
"executable": false
|
|
1824
1824
|
}
|
|
1825
1825
|
],
|
|
1826
1826
|
"digest": {
|
|
1827
1827
|
"algorithm": "sha256",
|
|
1828
|
-
"value": "
|
|
1828
|
+
"value": "53a2f9f2d3d8cf8cf43391dd92224aa5190e331f0a993649d0a06256ca6a417d"
|
|
1829
1829
|
}
|
|
1830
1830
|
}
|