@technomoron/agent-run 0.99.11 → 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,12 @@ 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
+
7
13
  Version 0.99.11 (2026-04-27)
8
14
  ----------------------------
9
15
  * Show the package version in `agent-run --help` and add `agent-run --version`.
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
@@ -216,6 +216,7 @@ function parseRunCommand(command, inputArgs) {
216
216
  const wrapperArgs = {
217
217
  none: false,
218
218
  create: false,
219
+ local: false,
219
220
  codexSandboxMode: null,
220
221
  codexNetwork: false
221
222
  };
@@ -238,6 +239,10 @@ function parseRunCommand(command, inputArgs) {
238
239
  wrapperArgs.create = true;
239
240
  continue;
240
241
  }
242
+ if (arg === '--local') {
243
+ wrapperArgs.local = true;
244
+ continue;
245
+ }
241
246
  if (arg === '--danger') {
242
247
  if (command !== 'codex') {
243
248
  fail('--danger is only supported for agent-run codex');
@@ -412,9 +417,10 @@ function renderHelp(topic) {
412
417
  ' agent-run --init [config-root]',
413
418
  '',
414
419
  'Commands:',
415
- ' codex [--none] [--create] [--danger|--sandboxed] [--network] [args...]',
420
+ ' codex [--none] [--create] [--local] [--danger|--sandboxed] [--network] [args...]',
416
421
  ' Run codex with generated private config',
417
- ' claude [--none] [--create] [args...] Run claude with generated private config',
422
+ ' claude [--none] [--create] [--local] [args...]',
423
+ ' Run claude with generated private config',
418
424
  ' check [--all] [path] Validate generated profile output',
419
425
  ' init [path] Create profile source files and render output',
420
426
  ' edit [path] Open local.md.njk or legacy AGENTS-MODS.md',
@@ -429,6 +435,7 @@ function renderHelp(topic) {
429
435
  ' --init [DIR] Copy the packaged starter config root to DIR (default ~/.agent-config)',
430
436
  '',
431
437
  'Codex wrapper options:',
438
+ ' --local Warn about local AI files instead of failing',
432
439
  ' --danger Run Codex with no sandbox: -a never -s danger-full-access (default)',
433
440
  ' --sandboxed Run Codex with workspace-write sandbox',
434
441
  ' --network Enable network for --sandboxed via config override',
@@ -495,7 +502,10 @@ function runTool(parsed) {
495
502
  const excludedDir = profileResult.profile === null ? null : resolveAgentDir(projectRoot);
496
503
  const localAiFiles = findLocalAiFiles(projectRoot, excludedDir);
497
504
  if (localAiFiles.length > 0) {
498
- failForLocalAiFiles(command, projectRoot, localAiFiles);
505
+ if (!wrapperArgs.local) {
506
+ failForLocalAiFiles(command, projectRoot, localAiFiles);
507
+ }
508
+ warnForLocalAiFiles(command, projectRoot, localAiFiles);
499
509
  }
500
510
  if (profileResult.profile === null) {
501
511
  fail(profileResult.reason);
@@ -512,7 +522,7 @@ function runTool(parsed) {
512
522
  runCodex(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs);
513
523
  return;
514
524
  }
515
- runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot);
525
+ runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs);
516
526
  }
517
527
  function runInit(parsed) {
518
528
  const projectRoot = findProjectRoot(parsed.targetPath);
@@ -1009,10 +1019,21 @@ function buildRenderContext(projectRoot, agentDir, configRoot, manifest, env) {
1009
1019
  return {
1010
1020
  ...baseContext,
1011
1021
  paths,
1022
+ permissionsAllow: buildPermissionsAllow(manifest),
1012
1023
  skills: [],
1013
1024
  renderedAgentSections: []
1014
1025
  };
1015
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
+ }
1016
1037
  function resolveConfigPath(configRoot, relativePath, context) {
1017
1038
  const env = createNunjucksEnv(configRoot);
1018
1039
  const rendered = renderInlineTemplate(env, relativePath, context);
@@ -1118,7 +1139,7 @@ function renderProfile(projectRoot, agentDir, checkOnly = false) {
1118
1139
  files.push({ path: path.join(agentDir, 'CLAUDE.md'), content: claudeContent });
1119
1140
  files.push({ path: path.join(agentDir, '.claude', 'CLAUDE.md'), content: claudeContent });
1120
1141
  files.push({ path: path.join(agentDir, 'config.toml'), content: renderCodexConfig(env, configRoot, context) });
1121
- 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) });
1122
1143
  files.push(...renderNativeSkillFiles(context));
1123
1144
  files.push(...renderGuardShims(context));
1124
1145
  return {
@@ -1136,8 +1157,21 @@ function syncAgentProfile(projectRoot, agentDir) {
1136
1157
  for (const file of rendered.files) {
1137
1158
  writeGeneratedFile(file.path, file.content, file.executable ?? false);
1138
1159
  }
1160
+ removeLegacyGeneratedClaudeSettings(rendered.context);
1139
1161
  return rendered;
1140
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
+ }
1141
1175
  function checkRenderedProfile(projectRoot, agentDir) {
1142
1176
  const findings = [];
1143
1177
  const configRoot = defaultConfigRoot(projectRoot);
@@ -1517,7 +1551,7 @@ function runCodex(realBinary, permissionArgs, agentDir, configRoot, args, projec
1517
1551
  ? ['--config', 'sandbox_workspace_write.network_access=true']
1518
1552
  : []),
1519
1553
  ...args
1520
- ], shouldUseShell(realBinary), env, codexHomeDir, (code) => postflightProjectCheck(projectRoot, agentDir, code));
1554
+ ], shouldUseShell(realBinary), env, codexHomeDir, (code) => postflightProjectCheck(projectRoot, agentDir, wrapperArgs.local, code));
1521
1555
  }
1522
1556
  function buildCodexRuntimeArgs(wrapperArgs) {
1523
1557
  const mode = wrapperArgs.codexSandboxMode ?? 'danger';
@@ -1526,7 +1560,7 @@ function buildCodexRuntimeArgs(wrapperArgs) {
1526
1560
  }
1527
1561
  return ['-a', 'never', '-s', 'danger-full-access'];
1528
1562
  }
1529
- function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot) {
1563
+ function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, projectRoot, wrapperArgs) {
1530
1564
  const claudePath = path.join(agentDir, 'CLAUDE.md');
1531
1565
  if (!fs.existsSync(claudePath)) {
1532
1566
  failMissingConfig('claude', agentDir);
@@ -1543,14 +1577,14 @@ function runClaude(realBinary, permissionArgs, agentDir, configRoot, args, proje
1543
1577
  execCommand(realBinary, [
1544
1578
  ...permissionArgs,
1545
1579
  '--settings',
1546
- path.join(claudeConfigDir, 'settings.json'),
1580
+ path.join(claudeConfigDir, 'agent-run-settings.json'),
1547
1581
  '--add-dir',
1548
1582
  projectRoot,
1549
1583
  '--add-dir',
1550
1584
  agentDir,
1551
1585
  ...globalMemoryArgs(configRoot),
1552
1586
  ...args
1553
- ], shouldUseShell(realBinary), env, projectRoot, (code) => postflightProjectCheck(projectRoot, agentDir, code));
1587
+ ], shouldUseShell(realBinary), env, projectRoot, (code) => postflightProjectCheck(projectRoot, agentDir, wrapperArgs.local, code));
1554
1588
  }
1555
1589
  function globalMemoryArgs(configRoot) {
1556
1590
  const memoryDir = globalMemoryDir(configRoot);
@@ -1559,16 +1593,15 @@ function globalMemoryArgs(configRoot) {
1559
1593
  function globalMemoryDir(configRoot) {
1560
1594
  return path.join(configRoot, 'notes', 'memory');
1561
1595
  }
1562
- function postflightProjectCheck(projectRoot, agentDir, code) {
1596
+ function postflightProjectCheck(projectRoot, agentDir, allowLocal, code) {
1563
1597
  const localAiFiles = findLocalAiFiles(projectRoot, agentDir);
1564
- if (localAiFiles.length === 0) {
1565
- return code;
1566
- }
1567
- process.stderr.write(`agent-run: postflight found local AI files in project root ${projectRoot}\n`);
1568
- for (const file of localAiFiles) {
1569
- process.stderr.write(`agent-run: ${file}\n`);
1598
+ if (localAiFiles.length > 0) {
1599
+ warnForLocalAiFiles(null, projectRoot, localAiFiles);
1600
+ if (!allowLocal) {
1601
+ return 1;
1602
+ }
1570
1603
  }
1571
- return 1;
1604
+ return code;
1572
1605
  }
1573
1606
  function failMissingConfig(tool, agentDir) {
1574
1607
  process.stderr.write(`agent-run: no ${tool} config found for this project: ${agentDir}\n`);
@@ -1648,6 +1681,7 @@ function isSamePathOrDescendant(candidatePath, parentPath) {
1648
1681
  function shouldPruneProjectEntry(entry) {
1649
1682
  return (entry.isDirectory() &&
1650
1683
  (entry.name === '.git' ||
1684
+ entry.name === '.claude' ||
1651
1685
  entry.name === 'node_modules' ||
1652
1686
  entry.name === '.pnpm-store' ||
1653
1687
  entry.name === 'dist' ||
@@ -1666,13 +1700,21 @@ function isIgnoredDir(dir) {
1666
1700
  const env = readAgentRunEnv(dir);
1667
1701
  return parseBooleanEnv(env.AGENT_RUN_IGNORE);
1668
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
+ }
1669
1712
  function failForLocalAiFiles(tool, projectRoot, localAiFiles) {
1670
1713
  process.stderr.write(`agent-run: found local AI files in project root ${projectRoot}\n`);
1671
1714
  for (const file of localAiFiles) {
1672
1715
  process.stderr.write(`agent-run: ${file}\n`);
1673
1716
  }
1674
- 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`);
1675
- 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`);
1676
1718
  process.exit(1);
1677
1719
  }
1678
1720
  function findProjectRoot(cwd) {
@@ -2296,15 +2338,26 @@ function defaultCodexConfigTemplate() {
2296
2338
  ].join('\n');
2297
2339
  }
2298
2340
  function defaultClaudeSettingsTemplate() {
2299
- return [
2300
- '{',
2341
+ const envBlock = [
2301
2342
  ' "env": {',
2302
2343
  ' "AGENT_DIR": "{{ agentDir }}",',
2303
2344
  ' "AGENT_RUN_PROJECT_ROOT": "{{ projectRoot }}",',
2304
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
+ ' ]',
2305
2355
  ' }',
2306
2356
  '}',
2307
- ''
2357
+ '{% else %}{',
2358
+ envBlock,
2359
+ '}',
2360
+ '{% endif %}'
2308
2361
  ].join('\n');
2309
2362
  }
2310
2363
  function defaultCodexConfigContent(context) {
@@ -2325,6 +2378,19 @@ function defaultCodexConfigContent(context) {
2325
2378
  ].join('\n');
2326
2379
  }
2327
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) {
2328
2394
  return `${JSON.stringify({
2329
2395
  env: {
2330
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.11",
3
+ "version": "0.99.12",
4
4
  "packageManager": "pnpm@10.28.1",
5
5
  "bin": {
6
6
  "agent-run": "dist/agent-run.js"