@technomoron/agent-run 0.99.10 → 0.99.12

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 CHANGED
@@ -4,6 +4,16 @@ CHANGES
4
4
  Unreleased (2026-04-24)
5
5
  -----------------------
6
6
 
7
+ Version 0.99.12 (2026-04-27)
8
+ ----------------------------
9
+ * Add `--local` for Codex and Claude runs to warn about local AI files instead of failing.
10
+ * Limit generated Claude permission allow entries to configured checks instead of broad blocked command families.
11
+ * Write agent-run's Claude settings to `.claude/agent-run-settings.json` and remove only exact legacy generated `.claude/settings.json` files.
12
+
13
+ Version 0.99.11 (2026-04-27)
14
+ ----------------------------
15
+ * Show the package version in `agent-run --help` and add `agent-run --version`.
16
+
7
17
  Version 0.99.10 (2026-04-27)
8
18
  ----------------------------
9
19
  * Add `paths.globalMemoryDir` to render context and expose it from default Codex, Claude, AGENTS, and CLAUDE templates.
package/README.md CHANGED
@@ -118,10 +118,15 @@ generated guard shims on `PATH`. Use `--sandboxed` to request Codex
118
118
  `sandbox_workspace_write.network_access=true`.
119
119
 
120
120
  Claude Code currently has no `--cd` equivalent. `agent-run` keeps Claude's
121
- process cwd at the project root, passes the generated `.claude/settings.json`
121
+ process cwd at the project root, passes the generated `.claude/agent-run-settings.json`
122
122
  with `--settings`, and allows both the project root and private agent directory
123
123
  with `--add-dir`.
124
124
 
125
+ By default, `agent-run codex` and `agent-run claude` fail when local AI files
126
+ such as `AGENTS.md`, `CLAUDE.md`, `.agents`, `.claude`, or `.codex` are present
127
+ inside the project repository. Use `--local` to warn and continue for a specific
128
+ invocation.
129
+
125
130
  Initialize mapped files for the current repo:
126
131
 
127
132
  ```sh
package/dist/agent-run.js CHANGED
@@ -22,6 +22,7 @@ const CONFIG_DIR_ENV = 'AGENT_CONFIG_DIR';
22
22
  const VERBOSE_ENV = 'AGENT_RUN_VERBOSE';
23
23
  const MANIFEST_FILE_NAME = 'agent-run.jsonc';
24
24
  const LOCAL_TEMPLATE_FILE_NAME = 'local.md.njk';
25
+ const PACKAGE_VERSION = '0.99.10';
25
26
  const UNEXPANDED_TEMPLATE_RE = /\{\{[^}]+\}\}|\{%[^%]+%\}/;
26
27
  const agentRunEnvCache = new Map();
27
28
  const GENERATED_GITIGNORE_ENTRIES = [
@@ -114,6 +115,9 @@ function parseInvocation(invokedTool, argv) {
114
115
  if (isHelpFlag(firstArg)) {
115
116
  printHelp('general');
116
117
  }
118
+ if (isVersionFlag(firstArg)) {
119
+ printVersion();
120
+ }
117
121
  const commandIndex = findCommandArgIndex(inputArgs);
118
122
  if (commandIndex === -1) {
119
123
  fail(`unknown command: ${firstArg ?? ''} (run with --help for usage)`);
@@ -212,6 +216,7 @@ function parseRunCommand(command, inputArgs) {
212
216
  const wrapperArgs = {
213
217
  none: false,
214
218
  create: false,
219
+ local: false,
215
220
  codexSandboxMode: null,
216
221
  codexNetwork: false
217
222
  };
@@ -234,6 +239,10 @@ function parseRunCommand(command, inputArgs) {
234
239
  wrapperArgs.create = true;
235
240
  continue;
236
241
  }
242
+ if (arg === '--local') {
243
+ wrapperArgs.local = true;
244
+ continue;
245
+ }
237
246
  if (arg === '--danger') {
238
247
  if (command !== 'codex') {
239
248
  fail('--danger is only supported for agent-run codex');
@@ -341,6 +350,13 @@ function parseMigrateConfigCommand(inputArgs) {
341
350
  function isHelpFlag(value) {
342
351
  return value === '-h' || value === '--help';
343
352
  }
353
+ function isVersionFlag(value) {
354
+ return value === '-V' || value === '--version';
355
+ }
356
+ function printVersion() {
357
+ process.stdout.write(`agent-run ${agentRunVersion()}\n`);
358
+ process.exit(0);
359
+ }
344
360
  function printHelp(topic) {
345
361
  process.stdout.write(renderHelp(topic));
346
362
  process.exit(0);
@@ -394,14 +410,17 @@ function renderHelp(topic) {
394
410
  case 'general':
395
411
  default:
396
412
  return [
413
+ `agent-run ${agentRunVersion()}`,
414
+ '',
397
415
  'Usage:',
398
416
  ' agent-run <codex|claude|check|init|edit|update> [options]',
399
417
  ' agent-run --init [config-root]',
400
418
  '',
401
419
  'Commands:',
402
- ' codex [--none] [--create] [--danger|--sandboxed] [--network] [args...]',
420
+ ' codex [--none] [--create] [--local] [--danger|--sandboxed] [--network] [args...]',
403
421
  ' Run codex with generated private config',
404
- ' claude [--none] [--create] [args...] Run claude with generated private config',
422
+ ' claude [--none] [--create] [--local] [args...]',
423
+ ' Run claude with generated private config',
405
424
  ' check [--all] [path] Validate generated profile output',
406
425
  ' init [path] Create profile source files and render output',
407
426
  ' edit [path] Open local.md.njk or legacy AGENTS-MODS.md',
@@ -410,11 +429,13 @@ function renderHelp(topic) {
410
429
  '',
411
430
  'Global options:',
412
431
  ' -h, --help Show this help text',
432
+ ' -V, --version Show the agent-run version',
413
433
  ' -v, --verbose Print path resolution and wrapper actions',
414
434
  ' --config-root DIR Override the agent-config root',
415
435
  ' --init [DIR] Copy the packaged starter config root to DIR (default ~/.agent-config)',
416
436
  '',
417
437
  'Codex wrapper options:',
438
+ ' --local Warn about local AI files instead of failing',
418
439
  ' --danger Run Codex with no sandbox: -a never -s danger-full-access (default)',
419
440
  ' --sandboxed Run Codex with workspace-write sandbox',
420
441
  ' --network Enable network for --sandboxed via config override',
@@ -422,6 +443,19 @@ function renderHelp(topic) {
422
443
  ].join('\n');
423
444
  }
424
445
  }
446
+ function agentRunVersion() {
447
+ const packagePath = path.resolve(__dirname, '..', 'package.json');
448
+ try {
449
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
450
+ if (typeof pkg.version === 'string' && pkg.version.length > 0) {
451
+ return pkg.version;
452
+ }
453
+ }
454
+ catch {
455
+ return PACKAGE_VERSION;
456
+ }
457
+ return PACKAGE_VERSION;
458
+ }
425
459
  function normalizeCommandName(value) {
426
460
  if (!value) {
427
461
  return null;
@@ -468,7 +502,10 @@ function runTool(parsed) {
468
502
  const excludedDir = profileResult.profile === null ? null : resolveAgentDir(projectRoot);
469
503
  const localAiFiles = findLocalAiFiles(projectRoot, excludedDir);
470
504
  if (localAiFiles.length > 0) {
471
- failForLocalAiFiles(command, projectRoot, localAiFiles);
505
+ if (!wrapperArgs.local) {
506
+ failForLocalAiFiles(command, projectRoot, localAiFiles);
507
+ }
508
+ warnForLocalAiFiles(command, projectRoot, localAiFiles);
472
509
  }
473
510
  if (profileResult.profile === null) {
474
511
  fail(profileResult.reason);
@@ -485,7 +522,7 @@ function runTool(parsed) {
485
522
  runCodex(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs);
486
523
  return;
487
524
  }
488
- runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot);
525
+ runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs);
489
526
  }
490
527
  function runInit(parsed) {
491
528
  const projectRoot = findProjectRoot(parsed.targetPath);
@@ -982,10 +1019,21 @@ function buildRenderContext(projectRoot, agentDir, configRoot, manifest, env) {
982
1019
  return {
983
1020
  ...baseContext,
984
1021
  paths,
1022
+ permissionsAllow: buildPermissionsAllow(manifest),
985
1023
  skills: [],
986
1024
  renderedAgentSections: []
987
1025
  };
988
1026
  }
1027
+ function buildPermissionsAllow(manifest) {
1028
+ const allow = new Set();
1029
+ for (const check of manifest.checks) {
1030
+ const normalizedCheck = check.trim();
1031
+ if (normalizedCheck) {
1032
+ allow.add(`Bash(${normalizedCheck})`);
1033
+ }
1034
+ }
1035
+ return [...allow];
1036
+ }
989
1037
  function resolveConfigPath(configRoot, relativePath, context) {
990
1038
  const env = createNunjucksEnv(configRoot);
991
1039
  const rendered = renderInlineTemplate(env, relativePath, context);
@@ -1091,7 +1139,7 @@ function renderProfile(projectRoot, agentDir, checkOnly = false) {
1091
1139
  files.push({ path: path.join(agentDir, 'CLAUDE.md'), content: claudeContent });
1092
1140
  files.push({ path: path.join(agentDir, '.claude', 'CLAUDE.md'), content: claudeContent });
1093
1141
  files.push({ path: path.join(agentDir, 'config.toml'), content: renderCodexConfig(env, configRoot, context) });
1094
- files.push({ path: path.join(agentDir, '.claude', 'settings.json'), content: renderClaudeSettings(env, configRoot, context) });
1142
+ files.push({ path: path.join(agentDir, '.claude', 'agent-run-settings.json'), content: renderClaudeSettings(env, configRoot, context) });
1095
1143
  files.push(...renderNativeSkillFiles(context));
1096
1144
  files.push(...renderGuardShims(context));
1097
1145
  return {
@@ -1109,8 +1157,21 @@ function syncAgentProfile(projectRoot, agentDir) {
1109
1157
  for (const file of rendered.files) {
1110
1158
  writeGeneratedFile(file.path, file.content, file.executable ?? false);
1111
1159
  }
1160
+ removeLegacyGeneratedClaudeSettings(rendered.context);
1112
1161
  return rendered;
1113
1162
  }
1163
+ function removeLegacyGeneratedClaudeSettings(context) {
1164
+ const legacyPath = path.join(context.agentDir, '.claude', 'settings.json');
1165
+ if (!fs.existsSync(legacyPath)) {
1166
+ return;
1167
+ }
1168
+ const actual = fs.readFileSync(legacyPath, 'utf8').replace(/\r\n/g, '\n');
1169
+ const legacyGeneratedContent = legacyDefaultClaudeSettingsContent(context);
1170
+ if (actual === legacyGeneratedContent) {
1171
+ fs.rmSync(legacyPath);
1172
+ verbose(`removed legacy generated Claude settings ${legacyPath}`);
1173
+ }
1174
+ }
1114
1175
  function checkRenderedProfile(projectRoot, agentDir) {
1115
1176
  const findings = [];
1116
1177
  const configRoot = defaultConfigRoot(projectRoot);
@@ -1490,7 +1551,7 @@ function runCodex(realBinary, permissionArgs, agentDir, configRoot, args, projec
1490
1551
  ? ['--config', 'sandbox_workspace_write.network_access=true']
1491
1552
  : []),
1492
1553
  ...args
1493
- ], shouldUseShell(realBinary), env, codexHomeDir, (code) => postflightProjectCheck(projectRoot, agentDir, code));
1554
+ ], shouldUseShell(realBinary), env, codexHomeDir, (code) => postflightProjectCheck(projectRoot, agentDir, wrapperArgs.local, code));
1494
1555
  }
1495
1556
  function buildCodexRuntimeArgs(wrapperArgs) {
1496
1557
  const mode = wrapperArgs.codexSandboxMode ?? 'danger';
@@ -1499,7 +1560,7 @@ function buildCodexRuntimeArgs(wrapperArgs) {
1499
1560
  }
1500
1561
  return ['-a', 'never', '-s', 'danger-full-access'];
1501
1562
  }
1502
- function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot) {
1563
+ function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs) {
1503
1564
  const claudePath = path.join(agentDir, 'CLAUDE.md');
1504
1565
  if (!fs.existsSync(claudePath)) {
1505
1566
  failMissingConfig('claude', agentDir);
@@ -1516,14 +1577,14 @@ function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, proje
1516
1577
  execCommand(realBinary, [
1517
1578
  ...permissionArgs,
1518
1579
  '--settings',
1519
- path.join(claudeConfigDir, 'settings.json'),
1580
+ path.join(claudeConfigDir, 'agent-run-settings.json'),
1520
1581
  '--add-dir',
1521
1582
  projectRoot,
1522
1583
  '--add-dir',
1523
1584
  agentDir,
1524
1585
  ...globalMemoryArgs(configRoot),
1525
1586
  ...args
1526
- ], shouldUseShell(realBinary), env, projectRoot, (code) => postflightProjectCheck(projectRoot, agentDir, code));
1587
+ ], shouldUseShell(realBinary), env, projectRoot, (code) => postflightProjectCheck(projectRoot, agentDir, wrapperArgs.local, code));
1527
1588
  }
1528
1589
  function globalMemoryArgs(configRoot) {
1529
1590
  const memoryDir = globalMemoryDir(configRoot);
@@ -1532,16 +1593,15 @@ function globalMemoryArgs(configRoot) {
1532
1593
  function globalMemoryDir(configRoot) {
1533
1594
  return path.join(configRoot, 'notes', 'memory');
1534
1595
  }
1535
- function postflightProjectCheck(projectRoot, agentDir, code) {
1596
+ function postflightProjectCheck(projectRoot, agentDir, allowLocal, code) {
1536
1597
  const localAiFiles = findLocalAiFiles(projectRoot, agentDir);
1537
- if (localAiFiles.length === 0) {
1538
- return code;
1539
- }
1540
- process.stderr.write(`agent-run: postflight found local AI files in project root ${projectRoot}\n`);
1541
- for (const file of localAiFiles) {
1542
- process.stderr.write(`agent-run: ${file}\n`);
1598
+ if (localAiFiles.length > 0) {
1599
+ warnForLocalAiFiles(null, projectRoot, localAiFiles);
1600
+ if (!allowLocal) {
1601
+ return 1;
1602
+ }
1543
1603
  }
1544
- return 1;
1604
+ return code;
1545
1605
  }
1546
1606
  function failMissingConfig(tool, agentDir) {
1547
1607
  process.stderr.write(`agent-run: no ${tool} config found for this project: ${agentDir}\n`);
@@ -1621,6 +1681,7 @@ function isSamePathOrDescendant(candidatePath, parentPath) {
1621
1681
  function shouldPruneProjectEntry(entry) {
1622
1682
  return (entry.isDirectory() &&
1623
1683
  (entry.name === '.git' ||
1684
+ entry.name === '.claude' ||
1624
1685
  entry.name === 'node_modules' ||
1625
1686
  entry.name === '.pnpm-store' ||
1626
1687
  entry.name === 'dist' ||
@@ -1639,13 +1700,21 @@ function isIgnoredDir(dir) {
1639
1700
  const env = readAgentRunEnv(dir);
1640
1701
  return parseBooleanEnv(env.AGENT_RUN_IGNORE);
1641
1702
  }
1703
+ function warnForLocalAiFiles(tool, projectRoot, localAiFiles) {
1704
+ process.stderr.write(`WARNING: local AI files found in project root ${projectRoot}\n`);
1705
+ for (const file of localAiFiles) {
1706
+ process.stderr.write(`WARNING: ${path.relative(projectRoot, file)}\n`);
1707
+ }
1708
+ if (tool !== null) {
1709
+ process.stderr.write(`WARNING: consider moving these files out of the project, or run \`agent-run ${tool} --none\` to bypass the wrapper.\n`);
1710
+ }
1711
+ }
1642
1712
  function failForLocalAiFiles(tool, projectRoot, localAiFiles) {
1643
1713
  process.stderr.write(`agent-run: found local AI files in project root ${projectRoot}\n`);
1644
1714
  for (const file of localAiFiles) {
1645
1715
  process.stderr.write(`agent-run: ${file}\n`);
1646
1716
  }
1647
- process.stderr.write(`agent-run: move these files manually out of the project, or run \`${tool}\` directly if you want to use the local files.\n`);
1648
- process.stderr.write(`agent-run: run \`agent-run ${tool} --none\` to bypass the wrapper for this invocation.\n`);
1717
+ process.stderr.write(`agent-run: move these files manually out of the project, run \`agent-run ${tool} --local\` to warn and continue, or run \`agent-run ${tool} --none\` to bypass the wrapper for this invocation.\n`);
1649
1718
  process.exit(1);
1650
1719
  }
1651
1720
  function findProjectRoot(cwd) {
@@ -2269,15 +2338,26 @@ function defaultCodexConfigTemplate() {
2269
2338
  ].join('\n');
2270
2339
  }
2271
2340
  function defaultClaudeSettingsTemplate() {
2272
- return [
2273
- '{',
2341
+ const envBlock = [
2274
2342
  ' "env": {',
2275
2343
  ' "AGENT_DIR": "{{ agentDir }}",',
2276
2344
  ' "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",',
2277
2345
  ' "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}"',
2346
+ ' }'
2347
+ ].join('\n');
2348
+ return [
2349
+ '{% if permissionsAllow.length %}{',
2350
+ envBlock + ',',
2351
+ ' "permissions": {',
2352
+ ' "allow": [',
2353
+ ' "{{ permissionsAllow | join(\'",\\n "\') }}"',
2354
+ ' ]',
2278
2355
  ' }',
2279
2356
  '}',
2280
- ''
2357
+ '{% else %}{',
2358
+ envBlock,
2359
+ '}',
2360
+ '{% endif %}'
2281
2361
  ].join('\n');
2282
2362
  }
2283
2363
  function defaultCodexConfigContent(context) {
@@ -2298,6 +2378,19 @@ function defaultCodexConfigContent(context) {
2298
2378
  ].join('\n');
2299
2379
  }
2300
2380
  function defaultClaudeSettingsContent(context) {
2381
+ const settings = {
2382
+ env: {
2383
+ AGENT_DIR: context.agentDir,
2384
+ AGENT_RUN_PROJECT_ROOT: context.projectRoot,
2385
+ AGENT_GLOBAL_MEMORY_DIR: context.paths.globalMemoryDir
2386
+ }
2387
+ };
2388
+ if (context.permissionsAllow.length > 0) {
2389
+ settings.permissions = { allow: context.permissionsAllow };
2390
+ }
2391
+ return `${JSON.stringify(settings, null, 2)}\n`;
2392
+ }
2393
+ function legacyDefaultClaudeSettingsContent(context) {
2301
2394
  return `${JSON.stringify({
2302
2395
  env: {
2303
2396
  AGENT_DIR: context.agentDir,
@@ -1,8 +1,22 @@
1
- {
1
+ {% if permissionsAllow.length %}{
2
2
  "env": {
3
3
  "AGENT_DIR": "{{ agentDir }}",
4
4
  "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
5
5
  "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
6
6
  "STARTER_PROFILE": "{{ profile }}"
7
+ },
8
+ "permissions": {
9
+ "allow": [
10
+ "{{ permissionsAllow | join('",\n "') }}"
11
+ ]
7
12
  }
8
13
  }
14
+ {% else %}{
15
+ "env": {
16
+ "AGENT_DIR": "{{ agentDir }}",
17
+ "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
18
+ "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
19
+ "STARTER_PROFILE": "{{ profile }}"
20
+ }
21
+ }
22
+ {% endif %}
@@ -1,9 +1,24 @@
1
- {
1
+ {% if permissionsAllow.length %}{
2
2
  "env": {
3
3
  "AGENT_DIR": "{{ agentDir }}",
4
4
  "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
5
5
  "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
6
6
  "STARTER_PROFILE": "{{ profile }}",
7
7
  "STARTER_OVERRIDE": "true"
8
+ },
9
+ "permissions": {
10
+ "allow": [
11
+ "{{ permissionsAllow | join('",\n "') }}"
12
+ ]
8
13
  }
9
14
  }
15
+ {% else %}{
16
+ "env": {
17
+ "AGENT_DIR": "{{ agentDir }}",
18
+ "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",
19
+ "AGENT_GLOBAL_MEMORY_DIR": "{{ paths.globalMemoryDir }}",
20
+ "STARTER_PROFILE": "{{ profile }}",
21
+ "STARTER_OVERRIDE": "true"
22
+ }
23
+ }
24
+ {% endif %}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/agent-run",
3
- "version": "0.99.10",
3
+ "version": "0.99.12",
4
4
  "packageManager": "pnpm@10.28.1",
5
5
  "bin": {
6
6
  "agent-run": "dist/agent-run.js"