@technomoron/agent-run 0.99.18 → 0.99.19
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/CHANGES +5 -0
- package/README.md +13 -0
- package/dist/agent-run.js +126 -8
- package/package.json +1 -1
package/CHANGES
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
CHANGES
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
Version 0.99.19 (2026-06-03)
|
|
5
|
+
----------------------------
|
|
6
|
+
* Link per-profile Codex `auth.json` files to the shared `~/.codex/auth.json` login cache when available.
|
|
7
|
+
* Add `agent-run update --all [config-root]` to regenerate every profile from the config tree without requiring code checkouts.
|
|
8
|
+
|
|
4
9
|
Version 0.99.18 (2026-05-26)
|
|
5
10
|
----------------------------
|
|
6
11
|
* Remove extensionless Node command shim lookup on Windows so generated guard shims resolve real executables correctly.
|
package/README.md
CHANGED
|
@@ -119,6 +119,9 @@ from that private directory, passes the project root with `-C`, and keeps
|
|
|
119
119
|
generated guard shims on `PATH`. Use `--sandboxed` to request Codex
|
|
120
120
|
`workspace-write`; add `--network` with `--sandboxed` to set
|
|
121
121
|
`sandbox_workspace_write.network_access=true`.
|
|
122
|
+
When `~/.codex/auth.json` exists, profile-specific Codex homes link their
|
|
123
|
+
`auth.json` to that shared login cache so changing profiles does not require a
|
|
124
|
+
new ChatGPT login.
|
|
122
125
|
|
|
123
126
|
Claude Code currently has no `--cd` equivalent. `agent-run` keeps Claude's
|
|
124
127
|
process cwd at the project root, passes the generated `.claude/agent-run-settings.json`
|
|
@@ -158,6 +161,16 @@ Regenerate the generated files for the current repo:
|
|
|
158
161
|
agent-run update
|
|
159
162
|
```
|
|
160
163
|
|
|
164
|
+
Regenerate every profile under the config root without requiring matching code
|
|
165
|
+
checkouts:
|
|
166
|
+
|
|
167
|
+
```sh
|
|
168
|
+
agent-run update --all ~/.agent-config
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
If the config root argument is omitted, `update --all` uses the normal configured
|
|
172
|
+
root such as `$HOME/.agent-config`.
|
|
173
|
+
|
|
161
174
|
You can also generate from a tool command and stop before launch:
|
|
162
175
|
|
|
163
176
|
```sh
|
package/dist/agent-run.js
CHANGED
|
@@ -318,17 +318,22 @@ function parseEditCommand(inputArgs) {
|
|
|
318
318
|
return { command: 'edit', targetPath: path.resolve(targetPath) };
|
|
319
319
|
}
|
|
320
320
|
function parseUpdateCommand(inputArgs) {
|
|
321
|
+
let all = false;
|
|
321
322
|
let targetPath = process.cwd();
|
|
322
323
|
for (const arg of inputArgs) {
|
|
323
324
|
if (isHelpFlag(arg)) {
|
|
324
325
|
printHelp('update');
|
|
325
326
|
}
|
|
327
|
+
if (arg === '--all') {
|
|
328
|
+
all = true;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
326
331
|
if (arg.startsWith('--')) {
|
|
327
332
|
fail(`unknown update option: ${arg}`);
|
|
328
333
|
}
|
|
329
334
|
targetPath = arg;
|
|
330
335
|
}
|
|
331
|
-
return { command: 'update', targetPath: path.resolve(targetPath) };
|
|
336
|
+
return { all, command: 'update', targetPath: path.resolve(targetPath) };
|
|
332
337
|
}
|
|
333
338
|
function parseMigrateConfigCommand(inputArgs) {
|
|
334
339
|
let configRoot = defaultConfigRoot();
|
|
@@ -390,9 +395,10 @@ function renderHelp(topic) {
|
|
|
390
395
|
case 'update':
|
|
391
396
|
return [
|
|
392
397
|
'Usage:',
|
|
393
|
-
' agent-run update [path]',
|
|
398
|
+
' agent-run update [--all] [path]',
|
|
394
399
|
'',
|
|
395
400
|
'Render generated files, native skills, config, and guard shims for the repo at path.',
|
|
401
|
+
'With --all, render every profile found under the config root without requiring code checkouts.',
|
|
396
402
|
''
|
|
397
403
|
].join('\n');
|
|
398
404
|
case 'migrate-config':
|
|
@@ -420,7 +426,7 @@ function renderHelp(topic) {
|
|
|
420
426
|
' check [--all] [path] Validate generated profile output',
|
|
421
427
|
' init [path] Create profile source files and render output',
|
|
422
428
|
' edit [path] Open local.md.njk or legacy AGENTS-MODS.md',
|
|
423
|
-
' update [path]
|
|
429
|
+
' update [--all] [path] Regenerate profile output',
|
|
424
430
|
' migrate-config [config-root] Convert existing config tree layout',
|
|
425
431
|
'',
|
|
426
432
|
'Global options:',
|
|
@@ -632,6 +638,10 @@ function runEdit(parsed) {
|
|
|
632
638
|
openEditor(editPath);
|
|
633
639
|
}
|
|
634
640
|
function runUpdate(parsed) {
|
|
641
|
+
if (parsed.all) {
|
|
642
|
+
runUpdateAll(parsed.targetPath);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
635
645
|
const projectRoot = findProjectRoot(parsed.targetPath);
|
|
636
646
|
verbose(`update target=${parsed.targetPath} projectRoot=${projectRoot}`);
|
|
637
647
|
if (isIgnoredDir(projectRoot)) {
|
|
@@ -652,6 +662,31 @@ function runUpdate(parsed) {
|
|
|
652
662
|
const rendered = syncAgentProfile(projectRoot, agentDir);
|
|
653
663
|
printUpdateSummary(rendered);
|
|
654
664
|
}
|
|
665
|
+
function runUpdateAll(targetPath) {
|
|
666
|
+
const configRoot = targetPath === path.resolve(process.cwd()) ? defaultConfigRoot() : path.resolve(targetPath);
|
|
667
|
+
verbose(`update --all configRoot=${configRoot}`);
|
|
668
|
+
if (!fs.existsSync(configRoot)) {
|
|
669
|
+
fail(`missing config root: ${configRoot}`);
|
|
670
|
+
}
|
|
671
|
+
ensureConfigRootLayout(configRoot);
|
|
672
|
+
ensureConfigRootGitignore(configRoot);
|
|
673
|
+
ensureDefaultGlobalTemplates(configRoot);
|
|
674
|
+
const profileDirs = findProfileDirs(configRoot);
|
|
675
|
+
let updated = 0;
|
|
676
|
+
for (const agentDir of profileDirs) {
|
|
677
|
+
const profile = path.relative(configRoot, agentDir).replace(/\\/g, '/');
|
|
678
|
+
const projectRoot = projectRootForProfile(profile);
|
|
679
|
+
verbose(`update --all profile=${profile} syntheticProjectRoot=${projectRoot}`);
|
|
680
|
+
ensureProfileOverridesDir(agentDir);
|
|
681
|
+
convertLegacyProfileIfNeeded(configRoot, agentDir, profile);
|
|
682
|
+
createDefaultManifestFile(agentDir, profile);
|
|
683
|
+
createDefaultLocalFile(agentDir, profile);
|
|
684
|
+
syncAgentProfile(projectRoot, agentDir, { configRoot, profile });
|
|
685
|
+
process.stdout.write(`OK ${profile}\n`);
|
|
686
|
+
updated += 1;
|
|
687
|
+
}
|
|
688
|
+
process.stdout.write(`Updated profiles: ${updated}\n`);
|
|
689
|
+
}
|
|
655
690
|
function runMigrateConfig(parsed) {
|
|
656
691
|
const configRoot = parsed.configRoot;
|
|
657
692
|
verbose(`migrate config root=${configRoot}`);
|
|
@@ -796,6 +831,23 @@ function findLegacyProfileDirs(configRoot) {
|
|
|
796
831
|
});
|
|
797
832
|
return dirs.sort();
|
|
798
833
|
}
|
|
834
|
+
function findProfileDirs(configRoot) {
|
|
835
|
+
const dirs = [];
|
|
836
|
+
walkConfigTree(configRoot, 0, (fullPath, entry) => {
|
|
837
|
+
if (!entry.isDirectory()) {
|
|
838
|
+
return undefined;
|
|
839
|
+
}
|
|
840
|
+
if (shouldPruneConfigEntry(entry)) {
|
|
841
|
+
return 'skip';
|
|
842
|
+
}
|
|
843
|
+
if (fs.existsSync(path.join(fullPath, MANIFEST_FILE_NAME)) || fs.existsSync(path.join(fullPath, LOCAL_TEMPLATE_FILE_NAME))) {
|
|
844
|
+
dirs.push(fullPath);
|
|
845
|
+
return 'skip';
|
|
846
|
+
}
|
|
847
|
+
return undefined;
|
|
848
|
+
});
|
|
849
|
+
return dirs.sort();
|
|
850
|
+
}
|
|
799
851
|
function walkConfigTree(dir, depth, visitor) {
|
|
800
852
|
const entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
801
853
|
for (const entry of entries) {
|
|
@@ -1210,9 +1262,9 @@ function copySkeletonTree(sourceDir, targetDir) {
|
|
|
1210
1262
|
fs.copyFileSync(sourcePath, targetPath);
|
|
1211
1263
|
}
|
|
1212
1264
|
}
|
|
1213
|
-
function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = null, trace) {
|
|
1214
|
-
const configRoot = defaultConfigRoot(projectRoot);
|
|
1215
|
-
const profile = resolveProfile(projectRoot);
|
|
1265
|
+
function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = null, trace, options) {
|
|
1266
|
+
const configRoot = options?.configRoot ?? defaultConfigRoot(projectRoot);
|
|
1267
|
+
const profile = options?.profile ?? resolveProfile(projectRoot);
|
|
1216
1268
|
const env = createNunjucksEnv(configRoot);
|
|
1217
1269
|
const manifest = normalizeManifest(loadManifest(configRoot, agentDir, profile, trace), profile);
|
|
1218
1270
|
if (manifest.profile !== profile) {
|
|
@@ -1269,8 +1321,8 @@ function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = nu
|
|
|
1269
1321
|
skills: context.skills
|
|
1270
1322
|
};
|
|
1271
1323
|
}
|
|
1272
|
-
function syncAgentProfile(projectRoot, agentDir) {
|
|
1273
|
-
const rendered = renderProfile(projectRoot, agentDir, false);
|
|
1324
|
+
function syncAgentProfile(projectRoot, agentDir, options) {
|
|
1325
|
+
const rendered = renderProfile(projectRoot, agentDir, false, null, undefined, options);
|
|
1274
1326
|
syncRuntimeDirs(rendered.context);
|
|
1275
1327
|
for (const file of rendered.files) {
|
|
1276
1328
|
writeGeneratedFile(file.path, file.content, file.executable ?? false);
|
|
@@ -1449,6 +1501,69 @@ function syncRuntimeDirs(context) {
|
|
|
1449
1501
|
migrateLiveReviewFiles(context);
|
|
1450
1502
|
removeLegacyCodexSkillDirs(context);
|
|
1451
1503
|
removeLegacyCodeReviewSkillDirs(context);
|
|
1504
|
+
ensureSharedCodexAuth(context.paths.codexHomeDir);
|
|
1505
|
+
}
|
|
1506
|
+
function ensureSharedCodexAuth(codexHomeDir) {
|
|
1507
|
+
const sharedAuthPath = path.join(os.homedir(), '.codex', 'auth.json');
|
|
1508
|
+
if (!fs.existsSync(sharedAuthPath)) {
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
const profileAuthPath = path.join(codexHomeDir, 'auth.json');
|
|
1512
|
+
if (path.resolve(profileAuthPath) === path.resolve(sharedAuthPath)) {
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
if (fs.existsSync(profileAuthPath) || isSymlink(profileAuthPath)) {
|
|
1516
|
+
if (isSymlinkTo(profileAuthPath, sharedAuthPath)) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
const backupPath = nextBackupPath(profileAuthPath);
|
|
1520
|
+
fs.renameSync(profileAuthPath, backupPath);
|
|
1521
|
+
verbose(`backed up profile Codex auth ${profileAuthPath} -> ${backupPath}`);
|
|
1522
|
+
}
|
|
1523
|
+
fs.mkdirSync(path.dirname(profileAuthPath), { recursive: true });
|
|
1524
|
+
try {
|
|
1525
|
+
fs.symlinkSync(sharedAuthPath, profileAuthPath);
|
|
1526
|
+
verbose(`linked profile Codex auth ${profileAuthPath} -> ${sharedAuthPath}`);
|
|
1527
|
+
}
|
|
1528
|
+
catch (error) {
|
|
1529
|
+
if (IS_WINDOWS) {
|
|
1530
|
+
fs.copyFileSync(sharedAuthPath, profileAuthPath);
|
|
1531
|
+
verbose(`copied shared Codex auth ${sharedAuthPath} -> ${profileAuthPath}`);
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
throw error;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function isSymlink(filePath) {
|
|
1538
|
+
try {
|
|
1539
|
+
return fs.lstatSync(filePath).isSymbolicLink();
|
|
1540
|
+
}
|
|
1541
|
+
catch {
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function isSymlinkTo(filePath, targetPath) {
|
|
1546
|
+
try {
|
|
1547
|
+
if (!fs.lstatSync(filePath).isSymbolicLink()) {
|
|
1548
|
+
return false;
|
|
1549
|
+
}
|
|
1550
|
+
const linkTarget = fs.readlinkSync(filePath);
|
|
1551
|
+
const resolvedTarget = path.resolve(path.dirname(filePath), linkTarget);
|
|
1552
|
+
return path.resolve(resolvedTarget) === path.resolve(targetPath);
|
|
1553
|
+
}
|
|
1554
|
+
catch {
|
|
1555
|
+
return false;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
function nextBackupPath(filePath) {
|
|
1559
|
+
const timestamp = new Date().toISOString().replace(/[-:TZ.]/g, '').slice(0, 14);
|
|
1560
|
+
let candidate = `${filePath}.bak.${timestamp}`;
|
|
1561
|
+
let index = 1;
|
|
1562
|
+
while (fs.existsSync(candidate) || isSymlink(candidate)) {
|
|
1563
|
+
candidate = `${filePath}.bak.${timestamp}.${index}`;
|
|
1564
|
+
index += 1;
|
|
1565
|
+
}
|
|
1566
|
+
return candidate;
|
|
1452
1567
|
}
|
|
1453
1568
|
function removeLegacyCodexSkillDirs(context) {
|
|
1454
1569
|
const legacyCodexSkillsDir = path.join(context.paths.liveDir, '.agents', 'skills');
|
|
@@ -2071,6 +2186,9 @@ function parseProfile(profile, source) {
|
|
|
2071
2186
|
}
|
|
2072
2187
|
return { profile: segments.join('/'), reason: '' };
|
|
2073
2188
|
}
|
|
2189
|
+
function projectRootForProfile(profile) {
|
|
2190
|
+
return path.join(os.homedir(), ...profile.split('/'));
|
|
2191
|
+
}
|
|
2074
2192
|
function readAgentRunEnv(dir) {
|
|
2075
2193
|
const resolvedDir = path.resolve(dir);
|
|
2076
2194
|
const cached = agentRunEnvCache.get(resolvedDir);
|