@technomoron/agent-run 0.99.25 → 0.99.27

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
@@ -1,6 +1,24 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ Version 0.99.27 (2026-08-11)
5
+ ----------------------------
6
+ * Rename the unattended-run option from `--danger` to `--yolo` for Codex and
7
+ Claude.
8
+ * Add `agent-run setup [config-root]` to create the packaged starter agent
9
+ configuration files without overwriting local edits.
10
+ * Resolve plain directories without Git metadata or a package name as
11
+ `[parent]/[current]` profiles.
12
+
13
+ Version 0.99.26 (2026-07-31)
14
+ ----------------------------
15
+ * Add `--danger` support for Claude so unattended runs pass
16
+ `--dangerously-skip-permissions`.
17
+ * Remove Claude's generated `.claude/settings.local.json` after guarded runs,
18
+ while preserving project-local settings when `--local` is used.
19
+ * Keep nested command-guard tests independent of an outer agent-run session's
20
+ executable search path.
21
+
4
22
  Version 0.99.25 (2026-07-11)
5
23
  ----------------------------
6
24
  * Add config-root `agent-run.defaults.jsonc` inheritance so project manifests
package/README.md CHANGED
@@ -97,6 +97,7 @@ The mapped path is:
97
97
  1. `AGENT_RUN_PROFILE` in `.agent-run.env`
98
98
  2. GitHub `origin` remote
99
99
  3. `package.json.name`
100
+ 4. the project path as `[parent]/[current]`
100
101
 
101
102
  Examples:
102
103
 
@@ -104,11 +105,13 @@ Examples:
104
105
  - `AGENT_RUN_PROFILE=unrelated/hello` -> `unrelated/hello`
105
106
  - `package.json.name = "@org/my-api"` -> `org/my-api`
106
107
  - `package.json.name = "my-api"` -> `my-api`
108
+ - `/work/org/my-api` with none of the above -> `org/my-api`
107
109
 
108
110
  `AGENT_RUN_PROFILE` is relative to the config root. It is not a filesystem
109
111
  path, so values like `/tmp/foo`, `C:/tmp/foo`, or `../foo` are rejected.
110
112
 
111
- If neither exists, `agent-run` fails instead of guessing.
113
+ The path fallback lets plain directories work without a Git repository or a
114
+ `package.json`. The explicit profile sources above always take precedence.
112
115
 
113
116
  ## Overrides
114
117
 
@@ -154,9 +157,8 @@ Codex defaults to `-a on-request -s workspace-write`. `agent-run` sets
154
157
  `CODEX_HOME` under the private agent directory, where Codex discovers the
155
158
  generated `AGENTS.md`, `config.toml`, and skills natively. It starts Codex from
156
159
  that private directory, passes the project root with `-C`, and keeps generated
157
- guard shims on `PATH`. Use `--danger` explicitly for
158
- `-a never -s danger-full-access`; use `--network` to enable network access in
159
- the workspace-write sandbox.
160
+ guard shims on `PATH`. Use `--network` to enable network access in the
161
+ workspace-write sandbox.
160
162
  When `~/.codex/auth.json` exists, profile-specific Codex homes link their
161
163
  `auth.json` to that shared login cache so changing profiles does not require a
162
164
  new ChatGPT login.
@@ -165,7 +167,16 @@ Claude Code currently has no `--cd` equivalent. `agent-run` keeps Claude's
165
167
  process cwd at the project root, appends the generated `CLAUDE.md` with
166
168
  `--append-system-prompt-file`, passes generated settings with `--settings`, and
167
169
  loads generated skills from a local plugin with `--plugin-dir`. It does not
168
- replace the user's normal `CLAUDE_CONFIG_DIR`.
170
+ replace the user's normal `CLAUDE_CONFIG_DIR`. If Claude writes remembered
171
+ permissions to `.claude/settings.local.json`, `agent-run` removes that file
172
+ after the session unless `--local` was used.
173
+
174
+ `--yolo` runs either tool unattended, with no approval prompts: Codex with
175
+ `-a never -s danger-full-access`, Claude with `--dangerously-skip-permissions`.
176
+ Only use it when the agent may change or delete anything it can reach. Claude
177
+ refuses `--dangerously-skip-permissions` when it runs as root, so run it as a
178
+ normal user. `--sandboxed` and `--network` stay Codex-only because Claude has no
179
+ matching sandbox.
169
180
 
170
181
  By default, `agent-run codex` and `agent-run claude` fail when local AI files
171
182
  such as `AGENTS.md`, `CLAUDE.md`, `CLAUDE.local.md`, `.mcp.json`, `.agents`,
@@ -242,16 +253,16 @@ snippets, profile-local templates, skill templates, a personal memory skill,
242
253
  profile skill overrides, tool config overrides, guardrails, checks, and
243
254
  generated runtime paths.
244
255
 
245
- To copy the packaged starter config root into your default config location:
256
+ To create the packaged starter agent files in your resolved config root:
246
257
 
247
258
  ```sh
248
- agent-run --init
259
+ agent-run setup
249
260
  ```
250
261
 
251
262
  Or choose a destination:
252
263
 
253
264
  ```sh
254
- agent-run --init ~/.agent-config
265
+ agent-run setup ~/.agent-config
255
266
  ```
256
267
 
257
268
  The copy skips files that already exist, so local edits are preserved.
package/dist/cli.js CHANGED
@@ -10,15 +10,6 @@ function parseInvocation(invokedTool, argv) {
10
10
  let command = normalizeCommandName(invokedTool);
11
11
  const options = extractGlobalOptions(argv);
12
12
  applyGlobalOptions(options);
13
- if (options.initConfig) {
14
- if (options.args.length > 0) {
15
- (0, utils_1.fail)('--init cannot be combined with a command');
16
- }
17
- return {
18
- command: 'init-config',
19
- targetPath: path.resolve(options.initConfigTargetPath ?? (0, project_1.defaultConfigRoot)())
20
- };
21
- }
22
13
  if (command === null) {
23
14
  command = extractCommand(options.args);
24
15
  }
@@ -59,6 +50,8 @@ function parseCommand(command, args) {
59
50
  return parseCheckCommand(args);
60
51
  case 'init':
61
52
  return parseInitCommand(args);
53
+ case 'setup':
54
+ return parseSetupCommand(args);
62
55
  case 'edit':
63
56
  return parseEditCommand(args);
64
57
  case 'update':
@@ -73,8 +66,6 @@ function extractGlobalOptions(argv) {
73
66
  const options = {
74
67
  args: [],
75
68
  configRootOverride: null,
76
- initConfig: false,
77
- initConfigTargetPath: null,
78
69
  verbose: false
79
70
  };
80
71
  let passthrough = false;
@@ -94,14 +85,6 @@ function extractGlobalOptions(argv) {
94
85
  else if (arg === '-v' || arg === '--verbose') {
95
86
  options.verbose = true;
96
87
  }
97
- else if (arg === '--init') {
98
- options.initConfig = true;
99
- const nextArg = argv[index + 1];
100
- if (nextArg !== undefined && !nextArg.startsWith('-')) {
101
- options.initConfigTargetPath = nextArg;
102
- index += 1;
103
- }
104
- }
105
88
  else if (arg === '--config-root') {
106
89
  const nextArg = argv[index + 1];
107
90
  if (nextArg === undefined) {
@@ -130,7 +113,7 @@ function parseRunCommand(command, inputArgs) {
130
113
  local: false,
131
114
  show: false,
132
115
  generate: false,
133
- codexSandboxMode: null,
116
+ sandboxMode: null,
134
117
  codexNetwork: false
135
118
  };
136
119
  const args = [];
@@ -148,13 +131,13 @@ function parseRunCommand(command, inputArgs) {
148
131
  if (applyCommonRunOption(arg, wrapperArgs)) {
149
132
  continue;
150
133
  }
151
- if (applyCodexRunOption(command, arg, wrapperArgs)) {
134
+ if (applySandboxRunOption(command, arg, wrapperArgs)) {
152
135
  continue;
153
136
  }
154
137
  args.push(arg);
155
138
  }
156
- if (wrapperArgs.codexNetwork && wrapperArgs.codexSandboxMode === 'danger') {
157
- (0, utils_1.fail)('--network cannot be combined with agent-run codex --danger');
139
+ if (wrapperArgs.codexNetwork && wrapperArgs.sandboxMode === 'danger') {
140
+ (0, utils_1.fail)('--network cannot be combined with agent-run codex --yolo');
158
141
  }
159
142
  return { args, command, wrapperArgs };
160
143
  }
@@ -173,22 +156,22 @@ function applyCommonRunOption(arg, options) {
173
156
  options[field] = true;
174
157
  return true;
175
158
  }
176
- function applyCodexRunOption(command, arg, options) {
177
- if (!['--danger', '--sandboxed', '--network'].includes(arg)) {
159
+ function applySandboxRunOption(command, arg, options) {
160
+ if (!['--yolo', '--sandboxed', '--network'].includes(arg)) {
178
161
  return false;
179
162
  }
180
- if (command !== 'codex') {
163
+ if (arg !== '--yolo' && command !== 'codex') {
181
164
  (0, utils_1.fail)(`${arg} is only supported for agent-run codex`);
182
165
  }
183
166
  if (arg === '--network') {
184
167
  options.codexNetwork = true;
185
168
  return true;
186
169
  }
187
- const mode = arg === '--danger' ? 'danger' : 'sandboxed';
188
- if (options.codexSandboxMode !== null && options.codexSandboxMode !== mode) {
189
- (0, utils_1.fail)('cannot combine --danger and --sandboxed');
170
+ const mode = arg === '--yolo' ? 'danger' : 'sandboxed';
171
+ if (options.sandboxMode !== null && options.sandboxMode !== mode) {
172
+ (0, utils_1.fail)('cannot combine --yolo and --sandboxed');
190
173
  }
191
- options.codexSandboxMode = mode;
174
+ options.sandboxMode = mode;
192
175
  return true;
193
176
  }
194
177
  function parseCheckCommand(inputArgs) {
@@ -213,11 +196,14 @@ function parseCheckCommand(inputArgs) {
213
196
  function parseInitCommand(inputArgs) {
214
197
  return { command: 'init', targetPath: parseSinglePath(inputArgs, 'init') };
215
198
  }
199
+ function parseSetupCommand(inputArgs) {
200
+ return { command: 'setup', targetPath: parseSinglePath(inputArgs, 'setup', (0, project_1.defaultConfigRoot)()) };
201
+ }
216
202
  function parseEditCommand(inputArgs) {
217
203
  return { command: 'edit', targetPath: parseSinglePath(inputArgs, 'edit') };
218
204
  }
219
- function parseSinglePath(inputArgs, command) {
220
- let targetPath = process.cwd();
205
+ function parseSinglePath(inputArgs, command, defaultPath = process.cwd()) {
206
+ let targetPath = defaultPath;
221
207
  for (const arg of inputArgs) {
222
208
  if (isHelpFlag(arg)) {
223
209
  printHelp(command);
@@ -289,6 +275,7 @@ function renderHelp(topic) {
289
275
  ''
290
276
  ],
291
277
  init: ['Usage:', ' agent-run init [path]', '', 'Create a minimal mapped profile marker and render generated files.', ''],
278
+ setup: ['Usage:', ' agent-run setup [config-root]', '', 'Create starter agent configuration files in the config root.', ''],
292
279
  edit: ['Usage:', ' agent-run edit [path]', '', 'Create or open the editable local profile template.', ''],
293
280
  update: [
294
281
  'Usage:',
@@ -313,14 +300,14 @@ function renderHelp(topic) {
313
300
  `agent-run ${agentRunVersion()}`,
314
301
  '',
315
302
  'Usage:',
316
- ' agent-run <codex|claude|check|init|edit|update> [options]',
317
- ' agent-run --init [config-root]',
303
+ ' agent-run <codex|claude|check|setup|init|edit|update> [options]',
318
304
  '',
319
305
  'Commands:',
320
- ' codex [--none] [--create] [--local] [--show] [--generate] [--danger|--sandboxed] [--network] [args...]',
306
+ ' codex [--none] [--create] [--local] [--show] [--generate] [--yolo|--sandboxed] [--network] [args...]',
321
307
  ' Run codex with generated private config',
322
- ' claude [--none] [--create] [--local] [--show] [--generate] [args...]',
308
+ ' claude [--none] [--create] [--local] [--show] [--generate] [--yolo] [args...]',
323
309
  ' Run claude with generated private config',
310
+ ' setup [config-root] Create starter files in the agent-config root',
324
311
  ' check [--all] [path] Validate generated profile output',
325
312
  ' init [path] Create a sparse profile marker and render output',
326
313
  ' edit [path] Create or open local.md.njk',
@@ -332,15 +319,16 @@ function renderHelp(topic) {
332
319
  ' -V, --version Show the agent-run version',
333
320
  ' -v, --verbose Print path resolution and wrapper actions',
334
321
  ' --config-root DIR Override the agent-config root',
335
- ' --init [DIR] Copy the packaged starter config root to DIR (default ~/.agent-config)',
336
322
  '',
337
323
  'Run wrapper options:',
338
324
  ' --local Warn about local AI files instead of failing',
339
325
  ' --show Show read/include and generated files without running the tool',
340
326
  ' --generate Generate files without running the tool',
327
+ ' --yolo Run unattended without approval prompts:',
328
+ ' Codex with -a never -s danger-full-access,',
329
+ ' Claude with --dangerously-skip-permissions',
341
330
  '',
342
331
  'Codex wrapper options:',
343
- ' --danger Run Codex with no sandbox: -a never -s danger-full-access',
344
332
  ' --sandboxed Run Codex with workspace-write sandbox (default)',
345
333
  ' --network Enable network for the workspace-write sandbox',
346
334
  ''
@@ -363,7 +351,7 @@ function normalizeCommandName(value) {
363
351
  if (base === 'agent-run') {
364
352
  return null;
365
353
  }
366
- return ['codex', 'claude', 'check', 'init', 'edit', 'update', 'migrate-config'].includes(base)
354
+ return ['codex', 'claude', 'check', 'setup', 'init', 'edit', 'update', 'migrate-config'].includes(base)
367
355
  ? base
368
356
  : null;
369
357
  }
package/dist/commands.js CHANGED
@@ -24,8 +24,8 @@ function dispatch(command) {
24
24
  case 'init':
25
25
  runInit(command);
26
26
  return;
27
- case 'init-config':
28
- runInitConfig(command);
27
+ case 'setup':
28
+ runSetup(command);
29
29
  return;
30
30
  case 'edit':
31
31
  runEdit(command);
@@ -47,7 +47,8 @@ function runTool(parsed) {
47
47
  validateRunModes(parsed, projectRoot);
48
48
  if (wrapperArgs.none || (0, project_1.isIgnoredDir)(projectRoot)) {
49
49
  (0, utils_1.verbose)(`wrapper bypassed for ${command}${wrapperArgs.none ? ' via --none' : ' because project is ignored'}`);
50
- (0, process_1.execTool)((0, process_1.findRealBinary)(command), [...(0, tools_1.getPermissionArgs)(command), ...args]);
50
+ const runtimeArgs = wrapperArgs.sandboxMode === 'danger' ? (0, tools_1.getDangerArgs)(command) : (0, tools_1.getPermissionArgs)(command);
51
+ (0, process_1.execTool)((0, process_1.findRealBinary)(command), [...runtimeArgs, ...args]);
51
52
  return;
52
53
  }
53
54
  const profileResult = (0, project_1.resolveProfileResult)(projectRoot);
@@ -153,13 +154,13 @@ function runInit(parsed) {
153
154
  const agentDir = initializeProfileSource(projectRoot, true);
154
155
  printUpdateSummary((0, renderer_1.syncAgentProfile)(projectRoot, agentDir));
155
156
  }
156
- function runInitConfig(parsed) {
157
+ function runSetup(parsed) {
157
158
  const sourcePath = (0, config_tree_1.starterConfigRootPath)();
158
159
  if (!fs.existsSync(sourcePath)) {
159
160
  (0, utils_1.fail)(`starter config skeleton not found: ${sourcePath}`);
160
161
  }
161
162
  (0, config_tree_1.copySkeletonTree)(sourcePath, path.resolve(parsed.targetPath));
162
- process.stdout.write(`OK copied starter config to ${path.resolve(parsed.targetPath)}\n`);
163
+ process.stdout.write(`OK created starter agent config in ${path.resolve(parsed.targetPath)}\n`);
163
164
  }
164
165
  function runEdit(parsed) {
165
166
  const projectRoot = activeProject(parsed.targetPath, 'edit');
package/dist/project.js CHANGED
@@ -173,10 +173,15 @@ function profileFromPackage(projectRoot) {
173
173
  return { profile: null, reason: `cannot parse package.json: ${packagePath}` };
174
174
  }
175
175
  }
176
- return {
177
- profile: null,
178
- reason: `cannot resolve agent profile for ${projectRoot}; add ${constants_1.ENV_FILE_NAME} with AGENT_RUN_PROFILE=<org/project>, add a GitHub origin remote, or set package.json.name`
179
- };
176
+ const current = path.basename(projectRoot);
177
+ const parentDir = path.dirname(projectRoot);
178
+ const parent = path.basename(parentDir);
179
+ if (current && parent && parentDir !== projectRoot) {
180
+ const inferredProfile = `${parent}/${current}`;
181
+ (0, utils_1.verbose)(`using project path profile=${inferredProfile}`);
182
+ return parseProfile(inferredProfile, 'project parent and directory name');
183
+ }
184
+ return { profile: null, reason: `cannot resolve agent profile from project path: ${projectRoot}` };
180
185
  }
181
186
  function resolveGitHubProfile(projectRoot) {
182
187
  const result = childProcess.spawnSync('git', ['-C', projectRoot, 'config', '--get', 'remote.origin.url'], {
package/dist/tools.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runCodex = runCodex;
4
4
  exports.runClaude = runClaude;
5
+ exports.getDangerArgs = getDangerArgs;
5
6
  exports.getPermissionArgs = getPermissionArgs;
6
7
  const fs = require("fs");
7
8
  const path = require("path");
@@ -25,15 +26,13 @@ function runCodex(realBinary, permissionArgs, context, args, wrapperArgs) {
25
26
  AGENT_RUN_REAL_PATH: realPath,
26
27
  PATH: `${path.join(liveDir, 'bin')}${path.delimiter}${realPath}`
27
28
  };
28
- const runtimeArgs = wrapperArgs.codexSandboxMode === 'danger'
29
- ? ['-a', 'never', '-s', 'danger-full-access']
30
- : ['-a', 'on-request', '-s', 'workspace-write'];
29
+ const runtimeArgs = wrapperArgs.sandboxMode === 'danger' ? getDangerArgs('codex') : ['-a', 'on-request', '-s', 'workspace-write'];
31
30
  (0, process_1.execCommand)(realBinary, [
32
31
  ...permissionArgs,
33
32
  ...runtimeArgs,
34
33
  '-C',
35
34
  projectRoot,
36
- ...(wrapperArgs.codexSandboxMode !== 'danger' && wrapperArgs.codexNetwork
35
+ ...(wrapperArgs.sandboxMode !== 'danger' && wrapperArgs.codexNetwork
37
36
  ? ['--config', 'sandbox_workspace_write.network_access=true']
38
37
  : []),
39
38
  ...args
@@ -55,8 +54,9 @@ function runClaude(realBinary, permissionArgs, context, args, wrapperArgs) {
55
54
  AGENT_RUN_REAL_PATH: realPath,
56
55
  PATH: `${path.join(liveDir, 'bin')}${path.delimiter}${realPath}`
57
56
  };
57
+ const runtimeArgs = wrapperArgs.sandboxMode === 'danger' ? getDangerArgs('claude') : permissionArgs;
58
58
  (0, process_1.execCommand)(realBinary, [
59
- ...permissionArgs,
59
+ ...runtimeArgs,
60
60
  '--append-system-prompt-file',
61
61
  claudePath,
62
62
  '--settings',
@@ -70,6 +70,9 @@ function postflightProjectCheck(context, allowLocal, code) {
70
70
  if (!context.guardrails.forbidRepoAiFiles) {
71
71
  return code;
72
72
  }
73
+ if (!allowLocal) {
74
+ removeClaudeLocalSettings(context.projectRoot);
75
+ }
73
76
  const localAiFiles = (0, project_1.findLocalAiFiles)(context.projectRoot, context.profileDir);
74
77
  if (localAiFiles.length === 0) {
75
78
  return code;
@@ -77,11 +80,34 @@ function postflightProjectCheck(context, allowLocal, code) {
77
80
  (0, project_1.warnForLocalAiFiles)(null, context.projectRoot, localAiFiles);
78
81
  return allowLocal ? code : 1;
79
82
  }
83
+ function removeClaudeLocalSettings(projectRoot) {
84
+ const claudeDir = path.join(projectRoot, '.claude');
85
+ const localSettingsPath = path.join(claudeDir, 'settings.local.json');
86
+ if (!fs.existsSync(localSettingsPath)) {
87
+ return;
88
+ }
89
+ fs.rmSync(localSettingsPath);
90
+ try {
91
+ fs.rmdirSync(claudeDir);
92
+ }
93
+ catch (error) {
94
+ if (!isDirectoryNotEmptyError(error)) {
95
+ throw error;
96
+ }
97
+ }
98
+ process.stderr.write(`agent-run: removed Claude's project-local settings: ${localSettingsPath}\n`);
99
+ }
100
+ function isDirectoryNotEmptyError(error) {
101
+ return error instanceof Error && 'code' in error && error.code === 'ENOTEMPTY';
102
+ }
80
103
  function failMissingConfig(tool, agentDir) {
81
104
  process.stderr.write(`agent-run: no ${tool} config found for this project: ${agentDir}\n`);
82
105
  process.stderr.write(`agent-run: run \`agent-run ${tool} --none\` to bypass agent setup, or \`agent-run ${tool} --create\` to create profile files.\n`);
83
106
  process.exit(1);
84
107
  }
108
+ function getDangerArgs(tool) {
109
+ return tool === 'codex' ? ['-a', 'never', '-s', 'danger-full-access'] : ['--dangerously-skip-permissions'];
110
+ }
85
111
  function getPermissionArgs(tool) {
86
112
  if (process.env.AGENT_WRAPPER_FORCE_PERMISSIVE !== '1') {
87
113
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/agent-run",
3
- "version": "0.99.25",
3
+ "version": "0.99.27",
4
4
  "packageManager": "pnpm@10.28.1",
5
5
  "bin": {
6
6
  "agent-run": "dist/agent-run.js"