devlyn-cli 4.2.13 → 4.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,6 +37,8 @@ In a project, AGENTS.md readers load the skills from `.agents/skills/`; Claude C
37
37
 
38
38
  Without prompts, `npx devlyn-cli -y` installs AGENTS.md + `.agents/skills/` plus every target this project already has; add `--claude` for Claude Code. With `--global` it installs for every project on this machine, plus `~/.claude/skills/` with `--claude` or when it already has a devlyn install. After a project install or update, the installer names the changed files to commit, including installed files a `.gitignore` hides, so teammates and `/devlyn-ideate` drains can use them.
39
39
 
40
+ `npx devlyn-cli update` — Update every devlyn install already here (this project and your global skill folders) to this version; installs nothing new.
41
+
40
42
  ---
41
43
 
42
44
  ## How It Works — Principles and Loops
@@ -102,8 +104,9 @@ files and rules outside managed blocks retain their contents. Unknown old text
102
104
  is kept conservatively, even when it may contain obsolete defaults.
103
105
  Malformed or duplicate managed markers still stop with an exact `.backup`, new
104
106
  defaults in `.incoming`, and a `.merge.md` guide; the original remains unchanged.
105
- Release packaging refreshes the offline fingerprints from Git history using
106
- `node scripts/update-instruction-templates.js`; installation needs no Git or network.
107
+ Portability refreshes the offline fingerprints from Git history using
108
+ `node scripts/update-instruction-templates.js` before testing; publish ships that tested tarball.
109
+ Installation needs no Git or network.
107
110
  Use 3.1.3 or newer consistently: older installers still overwrite `CLAUDE.md`.
108
111
 
109
112
  Upgrading to 4.1.0: `npx devlyn-cli -y` in a 4.x project keeps its Claude Code install
@@ -215,7 +218,7 @@ Selected during install. Run `npx devlyn-cli` again to add more.
215
218
 
216
219
  ---
217
220
 
218
- Installer updates preserve user work: before writing any selected target, devlyn refuses to replace or remove edited skills, directories with extra files (including hidden files), links, or unknown copies. `-y` does not bypass this check. Unedited copies from every published version upgrade automatically, including committed copies, historical install-path stamps and generated Python bytecode caches. Release packaging derives the offline skill history from Git with `node scripts/update-skill-history.js`. Move conflicting folders to a backup and migrate them manually; also remove conflicting tracked paths from the Git index before rerunning.
221
+ Installer updates preserve user work: before writing any selected target, devlyn refuses to replace or remove edited skills, directories with extra files (including hidden files), links, or unknown copies. `-y` does not bypass this check. Unedited copies from every published version upgrade automatically, including committed copies, historical install-path stamps and generated Python bytecode caches. Portability derives the offline skill history from Git with `node scripts/update-skill-history.js` before testing; publish ships that tested tarball. Move conflicting folders to a backup and migrate them manually; also remove conflicting tracked paths from the Git index before rerunning.
219
222
 
220
223
  Only `__pycache__` directories containing exclusively regular `*.pyc` files count as generated Python caches. Other entries make the directory ordinary content; links and special files are refused. Standalone `*.pyc` files count as content: none of the 113 published versions through 4.2.5 shipped them. Historical path normalization applies only to the escaped absolute assignment defaults written into Markdown by the 2.8.0–4.0.0 installers.
221
224
 
package/bin/devlyn.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
+ const crypto = require('crypto');
6
7
  const { execSync, spawnSync } = require('child_process');
7
8
 
8
9
  const CONFIG_SOURCE = path.join(__dirname, '..', 'config');
@@ -29,6 +30,7 @@ const RENAMED_SKILLS = {
29
30
  'devlyn:reap': 'devlyn-reap',
30
31
  };
31
32
  const DEVLYN_INSTALL_MARKER = '.devlyn-install.json';
33
+ const DEVLYN_INSTALL_LOCK = '.devlyn-install.lock';
32
34
  // Project settings earlier releases added for the retired pipeline.
33
35
  const RETIRED_STOP_HOOK = 'python3 "$CLAUDE_PROJECT_DIR/.claude/skills/_shared/resolve-stop-hook.py"';
34
36
  const RETIRED_ENV = ['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'];
@@ -101,6 +103,26 @@ function skillRoots(target, global) {
101
103
  return dirs.map((dir) => path.join(global ? os.homedir() : projectDir(), dir, 'skills'));
102
104
  }
103
105
 
106
+ // Core and historical skills count, as does an install in progress. _shared is not
107
+ // unique to devlyn, and a marker alone can outlive its skills; optional addons stand alone.
108
+ function hasDevlynInstall(root) {
109
+ try {
110
+ const stat = (name) => fs.lstatSync(name, { throwIfNoEntry: false });
111
+ if (!stat(root)?.isDirectory()) return false;
112
+ const optional = new Set(OPTIONAL_ADDONS.map((addon) => addon.name));
113
+ const names = [...DEVLYN_CORE_SKILLS, ...DEPRECATED_DIRS.map((name) => path.basename(name)),
114
+ ...Object.keys(RENAMED_SKILLS)].filter((name) => name.startsWith('devlyn')
115
+ && !optional.has(name.replace(/[:\uF03A]/g, '-')));
116
+ return !!stat(path.join(root, DEVLYN_INSTALL_LOCK))
117
+ || names.some((name) => [...legacySkillPaths(root, name.replace(/^devlyn-/, 'devlyn:')),
118
+ path.join(root, name.replace(/:/g, '-'))].some((full) => stat(full)?.isDirectory()))
119
+ || (!!stat(path.join(root, DEVLYN_INSTALL_MARKER)) && stat(path.join(root, '_shared'))?.isDirectory());
120
+ } catch (error) {
121
+ if (error.code === 'ENOTDIR') return false;
122
+ throw new InstructionError(`Cannot inspect ${root}: ${error.message}. Check its permissions and run again.`);
123
+ }
124
+ }
125
+
104
126
  // A devlyn Claude install in this scope. Globally only the marker a `--global --claude` run
105
127
  // writes counts; in a project also a devlyn skill (0.6.0 and later), command (0.2-0.5) or
106
128
  // CLAUDE.md with devlyn defaults, held or imported from AGENTS.md, which a team may commit
@@ -914,6 +936,76 @@ function installClaudeCore(installedSkills = new Map()) {
914
936
  return written;
915
937
  }
916
938
 
939
+ // Shared user roots need one writer from ownership checks through the last addon write.
940
+ // Never reap a foreign lock: PID reuse and slow installs make age/liveness unsafe evidence.
941
+ function withUserSkillLocks(roots, action) {
942
+ const locks = [];
943
+ const createdDirs = [];
944
+ try {
945
+ for (const root of roots) {
946
+ const lock = path.join(root, DEVLYN_INSTALL_LOCK);
947
+ try {
948
+ for (const dir of [path.dirname(root), root]) {
949
+ const stat = fs.lstatSync(dir, { throwIfNoEntry: false });
950
+ if (stat && !stat.isDirectory()) throw new Error(`not a real directory: ${dir}`);
951
+ }
952
+ const missing = [];
953
+ for (let dir = root; !fs.existsSync(dir); dir = path.dirname(dir)) {
954
+ missing.push(dir);
955
+ if (path.dirname(dir) === dir) break;
956
+ }
957
+ fs.mkdirSync(root, { recursive: true });
958
+ createdDirs.push(...missing);
959
+ const token = crypto.randomBytes(16).toString('hex');
960
+ const fd = fs.openSync(lock, 'wx', 0o600);
961
+ try {
962
+ fs.writeFileSync(fd, JSON.stringify({ pid: process.pid, token }) + '\n');
963
+ locks.push({ lock, token });
964
+ } catch (error) {
965
+ // A failed initial write may not leave parseable JSON; verify the open file's identity.
966
+ const opened = fs.fstatSync(fd);
967
+ const current = fs.lstatSync(lock, { throwIfNoEntry: false });
968
+ if (current?.dev === opened.dev && current?.ino === opened.ino) fs.unlinkSync(lock);
969
+ throw error;
970
+ } finally {
971
+ fs.closeSync(fd);
972
+ }
973
+ } catch (error) {
974
+ if (error.code === 'EEXIST') {
975
+ let owner;
976
+ try {
977
+ owner = `pid ${JSON.parse(fs.readFileSync(lock, 'utf8')).pid}`;
978
+ } catch (readError) {
979
+ owner = `cannot read lock owner: ${readError.message}`;
980
+ }
981
+ throw new InstructionError(`Another devlyn-cli is changing ${root} (${owner}). `
982
+ + `If none is running, delete ${lock} and run again.`);
983
+ }
984
+ throw new InstructionError(`Cannot lock ${root}: ${error.message}. Check ${lock} and run again.`);
985
+ }
986
+ }
987
+ return action();
988
+ } finally {
989
+ const errors = [];
990
+ for (const { lock, token } of locks.reverse()) {
991
+ try {
992
+ if (JSON.parse(fs.readFileSync(lock, 'utf8')).token === token) fs.unlinkSync(lock);
993
+ } catch (error) {
994
+ if (error.code !== 'ENOENT') errors.push(`${lock}: ${error.message}`);
995
+ }
996
+ }
997
+ // Refusal must not leave empty roots created just to acquire their locks.
998
+ for (const dir of createdDirs) {
999
+ try {
1000
+ fs.rmdirSync(dir);
1001
+ } catch (error) {
1002
+ if (!['ENOTEMPTY', 'EEXIST', 'ENOENT'].includes(error.code)) errors.push(`${dir}: ${error.message}`);
1003
+ }
1004
+ }
1005
+ if (errors.length) throw new InstructionError(`Cannot release install locks; check these paths:\n${errors.join('\n')}`);
1006
+ }
1007
+ }
1008
+
917
1009
  // Installs the targets in one scope; returns the skill roots written.
918
1010
  function install(targets, global, optionalNames = []) {
919
1011
  // In the home folder CLAUDE.md, AGENTS.md (agents read a parent folder's too) and
@@ -926,23 +1018,25 @@ function install(targets, global, optionalNames = []) {
926
1018
  + 'would apply to every project. Run from a project folder, or use --global for skills only.');
927
1019
  }
928
1020
  const roots = targets.flatMap((target) => skillRoots(target, global));
929
- const written = [];
930
- const installedSkills = new Map();
931
- if (!global) readProjectGitignore();
932
- preflightSkills(roots, optionalNames,
933
- !global && targets.includes('claude') ? path.dirname(skillRoots('claude', false)[0]) : null);
934
- // AGENTS.md first, whatever order the menu gave: a new CLAUDE.md holds the block only when AGENTS.md does not.
935
- for (const target of ['agents', 'claude'].filter((name) => targets.includes(name))) {
936
- if (global) skillRoots(target, true).forEach((root) => installCoreSkills(root));
937
- else if (target === 'agents') written.push(...installAgentsProject(targets.includes('claude'), installedSkills));
938
- else written.push(...installClaudeCore(installedSkills));
939
- }
940
- for (const name of optionalNames) installLocalSkill(name, roots, written, installedSkills);
941
- log(`\n✅ devlyn ${PKG.version} installed`, 'green');
942
- if (global) log('The principles block installs per project: run npx devlyn-cli in the project without --global.');
943
- else noticeProjectChanges(written, installedSkills);
944
- noticeGlobalDrift(roots);
945
- return roots;
1021
+ return withUserSkillLocks(global ? roots : [], () => {
1022
+ const written = [];
1023
+ const installedSkills = new Map();
1024
+ if (!global) readProjectGitignore();
1025
+ preflightSkills(roots, optionalNames,
1026
+ !global && targets.includes('claude') ? path.dirname(skillRoots('claude', false)[0]) : null);
1027
+ // AGENTS.md first, whatever order the menu gave: a new CLAUDE.md holds the block only when AGENTS.md does not.
1028
+ for (const target of ['agents', 'claude'].filter((name) => targets.includes(name))) {
1029
+ if (global) skillRoots(target, true).forEach((root) => installCoreSkills(root));
1030
+ else if (target === 'agents') written.push(...installAgentsProject(targets.includes('claude'), installedSkills));
1031
+ else written.push(...installClaudeCore(installedSkills));
1032
+ }
1033
+ for (const name of optionalNames) installLocalSkill(name, roots, written, installedSkills);
1034
+ log(`\n✅ devlyn ${PKG.version} installed`, 'green');
1035
+ if (global) log('The principles block installs per project: run npx devlyn-cli in the project without --global.');
1036
+ noticeGlobalDrift(roots);
1037
+ if (!global) noticeProjectChanges(written, installedSkills);
1038
+ return roots;
1039
+ });
946
1040
  }
947
1041
 
948
1042
  // Advisory only: a successful install stays successful when Git is unavailable or fails.
@@ -1023,12 +1117,92 @@ function noticeGlobalDrift(installed) {
1023
1117
  } catch (error) {
1024
1118
  version = `(unreadable marker: ${error.message})`;
1025
1119
  }
1120
+ if (dir !== '.grok' && version === PKG.version) continue;
1026
1121
  // 4.0's Grok root; Grok now reads ~/.agents/skills, so --global never refreshes it.
1027
1122
  const advice = dir === '.grok' ? 'delete it' : 'refresh it with --global, or delete it';
1028
1123
  log(`Global devlyn ${version} in ${root.replace(os.homedir(), '~')} — ${advice}.`, 'yellow');
1029
1124
  }
1030
1125
  }
1031
1126
 
1127
+ // Skip project setup in the home folder, where instructions would affect every project.
1128
+ // Lock user roots, preflight all roots, check versions, then write; user roots go first
1129
+ // so the project's commit guidance remains the last output.
1130
+ function update() {
1131
+ showLogo();
1132
+ log('─'.repeat(44), 'dim');
1133
+
1134
+ const userCandidates = [...skillRoots('agents', true), ...skillRoots('claude', true)];
1135
+ const linkedRoots = new Set();
1136
+ const linkNotices = [];
1137
+ for (const root of new Set([...userCandidates, ...skillRoots('agents', false), ...skillRoots('claude', false)])) {
1138
+ try {
1139
+ if (![path.dirname(root), root].some((dir) => fs.lstatSync(dir, { throwIfNoEntry: false })?.isSymbolicLink())) continue;
1140
+ linkedRoots.add(root);
1141
+ // Follow only for discovery; linked roots never enter the write/lock/preflight paths.
1142
+ if (!fs.statSync(root, { throwIfNoEntry: false })?.isDirectory()) continue;
1143
+ if (!fs.statSync(path.join(root, DEVLYN_INSTALL_MARKER), { throwIfNoEntry: false })
1144
+ && !fs.readdirSync(root).some((name) => name.startsWith('devlyn')
1145
+ && fs.statSync(path.join(root, name), { throwIfNoEntry: false })?.isDirectory())) continue;
1146
+ const notice = `Not updated: ${root} is a link — devlyn-cli does not write through links. `
1147
+ + 'Update the folder it points to, or replace the link with a folder.';
1148
+ linkNotices.push(notice);
1149
+ log(notice, 'yellow');
1150
+ } catch (error) {
1151
+ if (error.code === 'ENOTDIR') continue;
1152
+ throw new InstructionError(`Cannot inspect ${root}: ${error.message}. Check its permissions and run again.`);
1153
+ }
1154
+ }
1155
+ const userRoots = userCandidates.filter((root) => !linkedRoots.has(root) && hasDevlynInstall(root));
1156
+ const home = fs.statSync(os.homedir(), { bigint: true, throwIfNoEntry: false });
1157
+ const here = fs.statSync(projectDir(), { bigint: true });
1158
+ const targets = [];
1159
+ if (home?.dev !== here.dev || home?.ino !== here.ino) {
1160
+ if (!linkedRoots.has(skillRoots('agents', false)[0]) && hasDevlynInstall(skillRoots('agents', false)[0])) targets.push('agents');
1161
+ if (!linkedRoots.has(skillRoots('claude', false)[0]) && hasDevlynClaude(false)) targets.push('claude');
1162
+ }
1163
+ const projectRoots = targets.flatMap((target) => skillRoots(target, false));
1164
+ const roots = [...userRoots, ...projectRoots];
1165
+ if (!roots.length) {
1166
+ throw new InstructionError(['No devlyn install here to update. Run npx devlyn-cli to install.', ...linkNotices].join('\n'));
1167
+ }
1168
+
1169
+ return withUserSkillLocks(userRoots, () => {
1170
+ if (targets.length) {
1171
+ readProjectGitignore();
1172
+ preflightSkills(projectRoots, [], targets.includes('claude') ? path.dirname(skillRoots('claude', false)[0]) : null);
1173
+ }
1174
+ preflightSkills(userRoots);
1175
+ // Ownership preflight has already refused unreadable or invalid markers.
1176
+ const current = PKG.version.split('.').map(BigInt);
1177
+ const newer = roots.flatMap((root) => {
1178
+ const marker = path.join(root, DEVLYN_INSTALL_MARKER);
1179
+ if (!fs.existsSync(marker)) return [];
1180
+ const { version } = JSON.parse(fs.readFileSync(marker, 'utf8'));
1181
+ // SemVer 2.0.0's numbered-group regex: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
1182
+ const parsed = typeof version === 'string' && version.match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/);
1183
+ if (!parsed || parsed[0] !== version) {
1184
+ throw new InstructionError(`Update refused; nothing was changed. ${root}: cannot tell which devlyn-cli wrote it `
1185
+ + '(missing or malformed marker version). Restore the original install marker and run again.');
1186
+ }
1187
+ // This package is a plain release: equal-core prereleases are older, and build metadata is ignored.
1188
+ const parts = parsed.slice(1, 4).map(BigInt);
1189
+ const difference = parts.findIndex((part, index) => part !== current[index]);
1190
+ return difference !== -1 && parts[difference] > current[difference] ? [` - ${root}: ${version}`] : [];
1191
+ });
1192
+ if (newer.length) {
1193
+ throw new InstructionError('Update refused; nothing was changed. Newer devlyn installs:\n'
1194
+ + newer.join('\n') + '\nRun npx devlyn-cli@latest update.');
1195
+ }
1196
+
1197
+ userRoots.forEach((root) => installCoreSkills(root));
1198
+ if (targets.length) install(targets, false);
1199
+ else {
1200
+ log(`\n✅ devlyn ${PKG.version} installed`, 'green');
1201
+ noticeGlobalDrift(userRoots);
1202
+ }
1203
+ });
1204
+ }
1205
+
1032
1206
  async function init({ yes, claude, global }) {
1033
1207
  showLogo();
1034
1208
  log('─'.repeat(44), 'dim');
@@ -1090,6 +1264,7 @@ function showHelp() {
1090
1264
  showLogo();
1091
1265
  log('Usage:', 'green');
1092
1266
  log(' npx devlyn-cli Install/update devlyn: choose what (AGENTS.md, CLAUDE.md) and where (this project or global)');
1267
+ log(' npx devlyn-cli update Update every devlyn install already here (this project and your global skill folders) to this version; installs nothing new');
1093
1268
  log(' npx devlyn-cli -y Without prompts: AGENTS.md + .agents/skills, plus CLAUDE.md + .claude/ if this project has them');
1094
1269
  log(' npx devlyn-cli -y --claude Also install CLAUDE.md + .claude/ for Claude Code');
1095
1270
  log(' npx devlyn-cli -y --global Skills only, for every project on this machine (~/.agents/skills, ~/.codex/skills; ~/.claude/skills with --claude, or when it already has a devlyn install)');
@@ -1133,13 +1308,17 @@ switch (command) {
1133
1308
  process.exitCode = 1;
1134
1309
  break;
1135
1310
  default: {
1136
- const flags = command === 'init' ? args.slice(1) : args;
1137
- const unknown = flags.find((flag) => !INSTALL_FLAGS.includes(flag));
1311
+ const flags = command === 'init' || command === 'update' ? args.slice(1) : args;
1312
+ const unknown = command === 'update' ? flags[0] : flags.find((flag) => !INSTALL_FLAGS.includes(flag));
1138
1313
  if (unknown !== undefined) {
1139
1314
  log(`Unknown command: ${unknown}`, 'yellow');
1140
1315
  showHelp();
1141
1316
  process.exit(1);
1142
1317
  }
1318
+ if (command === 'update') {
1319
+ update();
1320
+ break;
1321
+ }
1143
1322
  await init({ yes: flags.includes('-y') || flags.includes('--yes'), claude: flags.includes('--claude'), global: flags.includes('--global') });
1144
1323
  }
1145
1324
  }
@@ -82,6 +82,7 @@
82
82
  "paragraphs": {
83
83
  "AGENTS.md": [
84
84
  "00044037bbe954aacee48c5edbe01b53aabef90fbe3f0c28c9136dc428fdd7df",
85
+ "0031285b60a5cf5e965df50482969315e5e62b163bb706695622fb4ed63f3dda",
85
86
  "0042d7a45818c8e1c451ac255502ee014fda81a2dbd2a4c04e75a66bc3493940",
86
87
  "0144d44eb6a0537211159e5f15baf2cacf11cc3275490ac5d295917df22cff27",
87
88
  "01e073f6a5722534affe03ab334fe4a394347f13de5ce191b757a0b7c6f51904",
@@ -91,6 +92,7 @@
91
92
  "03d85ed66f64ea52f2f96d9fb203b05ac6afc0ba634a4dfb3585429ce1531c44",
92
93
  "0467080d13d933b663362006ae5f5a0ad73baaed51ad50faf3f0d3d9f92244a3",
93
94
  "0634a245075d1a5aac4e58c1345f40f5f4c3b4909315f86aacd7ab239ea3ce61",
95
+ "072b63f736ee80f28550aec03277f033268a232e349ac86c3f1cab4bad9006c0",
94
96
  "0869633a322da8f8d800b1d2c23becc52f5ff592f0823533ea24f09de465c53a",
95
97
  "090f003bb30b98e6979865f3eb9bbc66eaa8f0cd74a89ff2eea5ef38cbee13b5",
96
98
  "0926622dde30d21c6cafe6b69b0bb0608b31e2528655615c7edbdedc6ae43d7c",
@@ -163,6 +165,7 @@
163
165
  "3e87f3023f1ee4810c769a27f63244a4c4825fa3c78417abd8a1a4bfb6350134",
164
166
  "3efd55e3caac3e3488b81921446bc9ca4ec92ac766abbcfefafeb183b21464a1",
165
167
  "3f05e197006cf9715612c67cb8709690e053262e9a0702723e69798ad29a2c08",
168
+ "3fde1f80f1d0e17ba79a674cb1124b8034df92801e9615c8fa443ce7c7a7672b",
166
169
  "41323b1c12be256f604edf8c49ff505acbaa75b6a1b938b76286d5eebec1ce95",
167
170
  "41660630582e14f984686f201e6af130e29bbd3fadc3c76a3c6055a7a8f78c4f",
168
171
  "41d2ff119ff97961c64e5eb57632c2d04b22794b50eb9227506c4ed763ebca3f",
@@ -374,6 +377,7 @@
374
377
  "e237f12ed08800ccc4c6eb4ae57cdd59d61198711f6a3b02dcb668aa08fddb93",
375
378
  "e289dbab99dadb30d8315b32b8243154148c82955f238936bce4c1fe1c3ae525",
376
379
  "e2bac40f3ff0b39726f95caaa9b19aa3b21596f165ac7a9dc68ebf42681d58cb",
380
+ "e389e1e77cc2da32214e95451b25b45402b1b586b26f5688bb373c492db3fcfb",
377
381
  "e3ee2da50e961046da3f5b68b0c328570307fb21a93424ae22536b8f216b55a3",
378
382
  "e43e4b5b86044fbf7be8d7fd1e3e27cd2089bfc8243e07dc2c3fc034c19794ea",
379
383
  "e44015948c7d04e60f3fed7e348c2052538e7784d8fe7ea3edf9f52de07448dd",
@@ -652,6 +656,7 @@
652
656
  "6170d780ab4f3cb5e2ea7d2757f9239d35dbbc1f9398e73877a95d5ef4c582ee",
653
657
  "624becc31a3b8619bab2b863a469b8bc6b19fc48acaa7d59a455057ff8d7cce1",
654
658
  "635097bbe52855009ba78ab992a905aad63b755a4b5c688179d8d597d5c9da01",
659
+ "65997521bd2bee492eeadc8570bf71f374cf1a05856d4acca499350b3db0dc7c",
655
660
  "65b903f779d8879f04e427a400a04bd29ab982ab28a62c2c172620773518242b",
656
661
  "6639e9e9622eca3d978923f26bf6f6ba1a95be4059206cc27c62e9deb026146a",
657
662
  "6693baa07666a5853ea606c25812f70550d28f6182d9c9dbfc1421270f1ec544",
@@ -665,6 +670,7 @@
665
670
  "6a08a11aea6a1dfaa99823a73bc8730e8fff9c483ec8989aaeca669cfc7b3ed6",
666
671
  "6a27907ba14fae9ddcacd551007b783b2f813c51c118828c74fd2174e09a7d41",
667
672
  "6a5ea10aa15a05ac992bd118adc3c0de48c85cea504aef655065d9678f93717c",
673
+ "6b098e67dbcdbec4569fb950f2067e4c4843a3b5f26a4e8886820102542eddee",
668
674
  "6b26d02b3f87d53a964b6fe405992104dd2ee85f8c1b3048951ece574d9005a8",
669
675
  "6b65f3883cfca3d531ab716c069c88f3a7d964657c5e026bda25eacdb37f16c5",
670
676
  "6b726d35cdc0851401769b6de9c422cfa475dbe7c0d036726706439a2cdbb02a",
@@ -699,6 +705,7 @@
699
705
  "7b47b07e3062f3dc839f11397bc3265120e01a35b0fda094d738e28a6729e6c3",
700
706
  "7bb5c341115c56592c0d1b5903d01321ce9c324136bc53babf9d438389796d94",
701
707
  "7c0dacd603b4381539d6d3cf21f5fe625cf54b05eb4aa750fce658529b11d81d",
708
+ "7c6c98c3dc37aa0760796051b0b81ac10b9ebad7c9d7da3615b3fd764e589766",
702
709
  "7c79750557c7d7156df6f135fb582ec09cc5f4987ac8e2af0f5113e42c117224",
703
710
  "7d083db061c678113c12453eb73299caa9e207dd6418ad63406154fd330f3309",
704
711
  "7d2239e2cd4893c57ac0bf1373a2ef46419f614d0ce18a12df51222bc7795327",
@@ -916,6 +923,7 @@
916
923
  "e2070548ec9a6244c569ef0b9a43c2e5dd99cf9c0fa4540a21fd0595b291e444",
917
924
  "e29fec7d54a144ea4867a3764fccdee6849d58d0f32eacdd56b2c317863fa1c6",
918
925
  "e2e0fc585321ee2013cccaed95d47c49fbca71b54c67abad9080d19d70e3c1a5",
926
+ "e389e1e77cc2da32214e95451b25b45402b1b586b26f5688bb373c492db3fcfb",
919
927
  "e3b2f7be15a793f07cbe8e51aa2feeac51d4c67077b94e5e20bad2e14be07fc5",
920
928
  "e468c242cc38c390f9679fca61f355848f58d51570249dfbb65b4f2e26a9dfb1",
921
929
  "e4bafa0f553e899b65f05feabf4cbe86d8246c57cbba745eb79e6aa858f40a6b",
@@ -59,6 +59,7 @@
59
59
  "59f0ecc2c1fd9620e4cac06be370e0bf9965a35c20616047445dbc42da6a1677",
60
60
  "5be2e643f96b6ce503ae8d631c67729f0c24b6c5d2b431c087161b520ccbe417",
61
61
  "61ec4c0435a2f0b307df8e88d81d9862c3abc1bf758648f2c18039581596659b",
62
+ "628a40e873d156e9179fd5a6bb3da9f910b6dde0886055804a506cdf8a631aaa",
62
63
  "628ee7de57717804cb2b4f4c9357751578276f241eb3ab53fdee49ae92d57513",
63
64
  "6320c0d8a5cb5ae82fc08c9c05c9151b00366ef759c824c16d4b777ccc30c771",
64
65
  "640500e3ada3d81645c293ddc956e9757f0c4ba0a06e3f914c9bdad4968cbc66",
@@ -35,7 +35,7 @@
35
35
  # 6. Preserves codex's exact exit code.
36
36
  #
37
37
  # USAGE:
38
- # bash codex-monitored.sh -C <repo> -s read-only -c model_reasoning_effort=xhigh "<prompt>"
38
+ # bash codex-monitored.sh -C <repo> -s read-only "<prompt>"
39
39
  # bash codex-monitored.sh resume --last
40
40
  # (Args after the script name are passed verbatim to `codex exec`.)
41
41
  #
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devlyn-cli",
3
- "version": "4.2.13",
3
+ "version": "4.2.15",
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": {