@technomoron/agent-run 0.99.40 → 0.99.42

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,25 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ Version 0.99.42 (2026-09-25)
5
+ ----------------------------
6
+ * Apply repository AI-file checks only to project scopes and actual repositories.
7
+ Default-scope launches from a home directory no longer scan protected Windows
8
+ folders or treat personal Codex and Claude settings as repository files.
9
+ * Skip the startup scan when the repository AI-file guard is disabled, and
10
+ preserve personal Claude settings during default-scope postflight checks.
11
+
12
+ Version 0.99.41 (2026-09-25)
13
+ ----------------------------
14
+ * Use a shared Codex home with native named profiles, keeping project
15
+ instructions, MCP configuration and same-name skills separate. Codex 0.157
16
+ profile launches avoid the automatic per-project daemon installation and
17
+ Unix socket path-length failure while using the global executable.
18
+ * Preserve old session rollouts through a non-overwriting migration; retain
19
+ original project homes and let Codex rebuild its derived session index.
20
+ * Use the native unelevated Windows sandbox by default for generated profiles
21
+ and start Codex from the source project directory.
22
+
4
23
  Version 0.99.40 (2026-09-24)
5
24
  ----------------------------
6
25
  * Add native Windows agent-brain service and MCP bridging over per-user named
package/README.md CHANGED
@@ -61,6 +61,11 @@ Example:
61
61
  ```text
62
62
  ~/.agent-run/
63
63
  agent-run.defaults.jsonc
64
+ runtime/codex/ # shared, ignored Codex home
65
+ agent-run-<id>.config.toml
66
+ skills/agent-run-<id>/
67
+ sessions/
68
+ memories/
64
69
  org/
65
70
  my-api/
66
71
  agent-run.jsonc
@@ -77,8 +82,6 @@ Example:
77
82
  codex-home/
78
83
  AGENTS.md
79
84
  config.toml
80
- memories/ # native Codex memory, local generated state
81
- skills/
82
85
  gemini/
83
86
  AGENTS.md
84
87
  settings.json
@@ -107,8 +110,10 @@ the agent config tree.
107
110
  - `overrides/`: optional per-profile template overrides
108
111
  - `notes/memory/`: durable project memory shared through the config repository
109
112
  - `live/memories/codex-home/AGENTS.md`: generated Codex instructions
110
- - `live/memories/codex-home/config.toml`: generated Codex config
111
- - `live/memories/codex-home/skills/`: generated Codex skills
113
+ - `live/memories/codex-home/config.toml`: rendered Codex template for inspection
114
+ - `<config-root>/runtime/codex/`: shared Codex home, authentication and session state
115
+ - `runtime/codex/agent-run-<id>.config.toml`: named Codex profile with project instructions and settings
116
+ - `runtime/codex/skills/agent-run-<id>/`: generated skills, enabled only for that profile
112
117
  - `live/CLAUDE.md`: generated Claude instructions
113
118
  - `live/.claude/`: generated Claude settings, MCP configuration, and local
114
119
  plugin skills
@@ -288,15 +293,30 @@ and `agent-run grok --help` pass `--help` through to the underlying tool.
288
293
  For any native agent command, use `--generate` to generate profile files
289
294
  without launching the underlying tool.
290
295
 
291
- Codex defaults to `-a on-request -s workspace-write`. `agent-run` sets
292
- `CODEX_HOME` under the private agent directory, where Codex discovers the
293
- generated `AGENTS.md`, `config.toml`, and skills natively. It starts Codex from
294
- that private directory, passes the project root with `-C`, and keeps generated
295
- guard shims on `PATH`. Use `--network` to enable network access in the
296
- workspace-write sandbox.
297
- When `~/.codex/auth.json` exists, profile-specific Codex homes link their
298
- `auth.json` to that shared login cache so changing profiles does not require a
299
- new ChatGPT login.
296
+ Codex defaults to `-a on-request -s workspace-write`. `agent-run` uses one
297
+ `CODEX_HOME` at `<config-root>/runtime/codex` and selects a generated named
298
+ profile with `--profile`. Project instructions are added through
299
+ `developer_instructions`; MCP settings and per-skill enablement stay in the
300
+ named profile. The normal global Codex executable is used. Codex 0.157.0 runs
301
+ named-profile sessions with its embedded backend, avoiding automatic daemon
302
+ package copies and the long per-project Unix socket path. Agent-run does not
303
+ add `--no-daemon`. This layout requires Codex with named profile-file support
304
+ (0.134.0 or newer); Windows and Debian are tested with 0.157.0.
305
+
306
+ Codex starts from the project root, also passed with `-C`, with generated guard
307
+ shims on `PATH`. Use `--network` to enable network access in the workspace-write
308
+ sandbox. Windows profiles default to the native unelevated sandbox unless the
309
+ profile template specifies another mode. When `~/.codex/auth.json` exists, the
310
+ shared home links that login cache (copies it when Windows cannot create file
311
+ symlinks), so changing projects does not require another login.
312
+
313
+ On first use of each old project home, agent-run copies its `sessions/` and
314
+ `archived_sessions/` rollouts into the shared home without overwriting existing
315
+ files. Codex rebuilds its derived session index. Original files, databases,
316
+ history, native memories and old daemon packages remain untouched in the old
317
+ home; databases and daemon installations are not copied. Close old agent-run
318
+ sessions before upgrading so their final turns are included. New sessions and
319
+ native memories use the shared home; durable project knowledge remains separate.
300
320
 
301
321
  ### Project Memory
302
322
 
@@ -306,7 +326,7 @@ current task. Agents may update project memory when the user explicitly requests
306
326
  authorizes a standing workflow, such as saving durable corrections and updating
307
327
  affected specs. This authorization does not permit Git or external-service writes.
308
328
 
309
- Codex's native `$CODEX_HOME/memories/` remains under ignored `live/` state. It
329
+ Codex's native `$CODEX_HOME/memories/` lives in the ignored shared home. It
310
330
  is generated, machine-local recall data and is not copied into the tracked
311
331
  project memory directory. Project memory is plain Markdown so it can be
312
332
  reviewed and shared through the Git repository that normally holds the
@@ -421,7 +441,8 @@ then rewrites generated files:
421
441
  - `live/CLAUDE.md`
422
442
  - `live/memories/codex-home/AGENTS.md`
423
443
  - `live/memories/codex-home/config.toml`
424
- - `live/memories/codex-home/skills/**`
444
+ - `<config-root>/runtime/codex/agent-run-<id>.config.toml`
445
+ - `<config-root>/runtime/codex/skills/agent-run-<id>/**`
425
446
  - `live/.claude/**`
426
447
  - `live/gemini/**`
427
448
  - `live/grok/**`
@@ -9,14 +9,15 @@ const render_settings_1 = require("../config/render-settings");
9
9
  const render_skills_1 = require("../config/render-skills");
10
10
  const environment_1 = require("../runtime/environment");
11
11
  const shared_state_1 = require("../runtime/shared-state");
12
+ const codex_profile_1 = require("../runtime/codex-profile");
12
13
  const shared_1 = require("./shared");
13
14
  function layout(context) {
14
15
  return {
15
16
  dir: context.paths.codexHomeDir,
16
17
  instructionFile: path.join(context.paths.codexHomeDir, 'AGENTS.md'),
17
- configFiles: [path.join(context.paths.codexHomeDir, 'config.toml')],
18
- skillsDir: context.paths.codexSkillsDir,
19
- requiredDirs: [context.paths.codexHomeDir, context.paths.codexSkillsDir],
18
+ configFiles: [path.join(context.paths.codexHomeDir, 'config.toml'), path.join((0, codex_profile_1.codexSharedHome)(context), `${(0, codex_profile_1.codexProfileName)(context)}.config.toml`)],
19
+ skillsDir: (0, codex_profile_1.codexProfileSkills)(context),
20
+ requiredDirs: [context.paths.codexHomeDir, (0, codex_profile_1.codexProfileSkills)(context)],
20
21
  preservedSkillNames: new Set(['.system'])
21
22
  };
22
23
  }
@@ -24,9 +25,11 @@ function generate(generation) {
24
25
  const agentLayout = layout(generation.context);
25
26
  const baseConfig = (0, render_settings_1.renderProfileConfig)(generation.env, generation.configRoot, generation.context, 'codex-config.toml.njk', 'global/tool-templates/codex-config.toml.njk', () => (0, defaults_1.defaultCodexConfigContent)(generation.context), 'Codex config.toml', generation.trace);
26
27
  const mcp = (0, render_mcp_1.renderCodexMcp)(generation.context);
28
+ const config = `${baseConfig.trimEnd()}${mcp ? `\n\n${mcp}` : '\n'}`;
27
29
  const files = [
28
30
  { path: agentLayout.instructionFile, content: generation.agentsMd },
29
- { path: agentLayout.configFiles[0] ?? '', content: `${baseConfig.trimEnd()}${mcp ? `\n\n${mcp}` : '\n'}` },
31
+ { path: agentLayout.configFiles[0] ?? '', content: config },
32
+ { path: agentLayout.configFiles[1] ?? '', content: (0, codex_profile_1.renderCodexProfile)(generation.context, config, generation.agentsMd), atomic: true },
30
33
  ...(0, render_skills_1.renderSkillFiles)(generation.context, agentLayout.skillsDir)
31
34
  ];
32
35
  return { ...agentLayout, id: 'codex', projectDir: generation.context.projectRoot, files, context: generation.context };
@@ -46,7 +49,16 @@ exports.codexAdapter = {
46
49
  layout,
47
50
  generate,
48
51
  prepare(runtime) {
49
- (0, shared_state_1.linkSharedEntry)(path.join(os.homedir(), '.codex', 'auth.json'), path.join(runtime.dir, 'auth.json'), 'profile Codex auth');
52
+ (0, shared_state_1.linkSharedEntry)(path.join(os.homedir(), '.codex', 'auth.json'), path.join((0, codex_profile_1.codexSharedHome)(runtime.context), 'auth.json'), 'shared Codex auth');
53
+ (0, codex_profile_1.migrateCodexSessions)(runtime.dir, (0, codex_profile_1.codexSharedHome)(runtime.context));
54
+ const profile = runtime.files.find((file) => file.path === runtime.configFiles[1]);
55
+ const base = runtime.files.find((file) => file.path === runtime.configFiles[0]);
56
+ const instructions = runtime.files.find((file) => file.path === runtime.instructionFile);
57
+ if (profile && base && instructions) {
58
+ profile.content = (0, codex_profile_1.renderCodexProfile)(runtime.context, base.content, instructions.content);
59
+ }
60
+ // Disable the pending skills in other profiles before making them discoverable.
61
+ (0, codex_profile_1.refreshCodexProfileSkills)(runtime.context);
50
62
  },
51
63
  spawn(runtime, options) {
52
64
  (0, shared_1.assertRuntimeFile)('codex', runtime.instructionFile, runtime.context.profileDir);
@@ -56,6 +68,7 @@ exports.codexAdapter = {
56
68
  return {
57
69
  command: options.binary,
58
70
  args: [
71
+ '--profile', (0, codex_profile_1.codexProfileName)(runtime.context),
59
72
  ...runtimeArgs,
60
73
  '--add-dir',
61
74
  runtime.context.paths.projectMemoryDir,
@@ -66,8 +79,8 @@ exports.codexAdapter = {
66
79
  : []),
67
80
  ...options.passthroughArgs
68
81
  ],
69
- cwd: runtime.dir,
70
- env: { ...(0, environment_1.buildAgentEnvironment)(runtime.context), CODEX_HOME: runtime.dir },
82
+ cwd: runtime.projectDir,
83
+ env: { ...(0, environment_1.buildAgentEnvironment)(runtime.context), CODEX_HOME: (0, codex_profile_1.codexSharedHome)(runtime.context) },
71
84
  onExit: (0, shared_1.withPostflight)(runtime, options.wrapperArgs)
72
85
  };
73
86
  },
package/dist/checks.js CHANGED
@@ -25,7 +25,7 @@ function checkProject(projectRoot) {
25
25
  return findings;
26
26
  }
27
27
  const agentDir = (0, project_1.resolveAgentDir)(projectRoot);
28
- if (profileForbidsLocalAiFiles(projectRoot, agentDir, profileResult.profile)) {
28
+ if ((0, project_1.hasProjectFileScope)(projectRoot, profileResult.profile) && profileForbidsLocalAiFiles(projectRoot, agentDir, profileResult.profile)) {
29
29
  for (const file of (0, project_1.findLocalAiFiles)(projectRoot, agentDir)) {
30
30
  findings.push({ message: `local AI file in project: ${file}`, severity: 'ERROR' });
31
31
  }
package/dist/commands.js CHANGED
@@ -187,8 +187,10 @@ function requireProfile(tool, agentDir) {
187
187
  process.exit(1);
188
188
  }
189
189
  function checkLocalAiFiles(command, projectRoot, agentDir, context, allowLocal) {
190
+ if (!context.guardrails.forbidRepoAiFiles || !(0, project_1.hasProjectFileScope)(projectRoot, context.profile))
191
+ return;
190
192
  const files = (0, project_1.findLocalAiFiles)(projectRoot, agentDir);
191
- if (!context.guardrails.forbidRepoAiFiles || files.length === 0) {
193
+ if (files.length === 0) {
192
194
  return;
193
195
  }
194
196
  if (!allowLocal) {
package/dist/constants.js CHANGED
@@ -33,6 +33,8 @@ exports.BRAIN_GITIGNORE_ENTRIES = [
33
33
  ''
34
34
  ];
35
35
  exports.GENERATED_GITIGNORE_ENTRIES = [
36
+ '# Shared machine-local Codex state',
37
+ '/runtime/codex/',
36
38
  '# Generated agent-run live profiles',
37
39
  '**/live/',
38
40
  '',
package/dist/project.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveAgentDir = resolveAgentDir;
4
4
  exports.findLocalAiFiles = findLocalAiFiles;
5
5
  exports.findSourceRepos = findSourceRepos;
6
+ exports.hasProjectFileScope = hasProjectFileScope;
6
7
  exports.isIgnoredDir = isIgnoredDir;
7
8
  exports.warnForLocalAiFiles = warnForLocalAiFiles;
8
9
  exports.failForLocalAiFiles = failForLocalAiFiles;
@@ -74,6 +75,11 @@ function findSourceRepos(rootPath) {
74
75
  function looksLikeRepoRoot(dir) {
75
76
  return fs.existsSync(path.join(dir, '.git')) || fs.existsSync(path.join(dir, 'package.json'));
76
77
  }
78
+ function hasProjectFileScope(projectRoot, profile) {
79
+ // The default brain scope also serves home directories and other non-project
80
+ // folders. Personal tool configuration there is not repository-local state.
81
+ return profile !== 'default' || looksLikeRepoRoot(projectRoot);
82
+ }
77
83
  function isIgnoredDir(dir) {
78
84
  if (fs.existsSync(path.join(dir, constants_1.IGNORE_FILE_NAME))) {
79
85
  return true;
package/dist/renderer.js CHANGED
@@ -18,6 +18,7 @@ const project_1 = require("./project");
18
18
  const templates_1 = require("./templates");
19
19
  const utils_1 = require("./utils");
20
20
  const config_1 = require("./brain/config");
21
+ const codex_profile_1 = require("./runtime/codex-profile");
21
22
  function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = null, trace, options) {
22
23
  const configRoot = options?.configRoot ?? (0, project_1.defaultConfigRoot)(projectRoot);
23
24
  const profile = options?.profile ?? (0, project_1.resolveProfile)(projectRoot);
@@ -92,11 +93,14 @@ function syncAgentProfile(projectRoot, agentDir, options) {
92
93
  return syncRenderedProfile(rendered);
93
94
  }
94
95
  function syncRenderedProfile(rendered) {
96
+ return (0, codex_profile_1.withCodexProfileLock)(rendered.context, () => writeRenderedProfile(rendered));
97
+ }
98
+ function writeRenderedProfile(rendered) {
95
99
  (0, config_tree_1.ensureConfigRootGitignore)(rendered.configRoot);
96
100
  syncRuntimeDirs(rendered);
97
101
  removeStaleGeneratedEntries(rendered);
98
102
  for (const file of rendered.files) {
99
- writeGeneratedFile(file.path, file.content, file.executable ?? false);
103
+ writeGeneratedFile(file.path, file.content, file.executable ?? false, file.atomic ?? false);
100
104
  }
101
105
  removeLegacyGeneratedCodexFiles(rendered.context);
102
106
  removeLegacyGeneratedClaudeSettings(rendered.context);
@@ -129,11 +133,14 @@ function syncRuntimeDirs(rendered) {
129
133
  }
130
134
  }
131
135
  }
132
- function writeGeneratedFile(filePath, content, executable) {
136
+ function writeGeneratedFile(filePath, content, executable, atomic) {
133
137
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
134
138
  const unchanged = fs.existsSync(filePath) && fs.readFileSync(filePath, 'utf8') === content;
135
139
  if (!unchanged) {
136
- fs.writeFileSync(filePath, content, 'utf8');
140
+ if (atomic)
141
+ (0, codex_profile_1.writeCodexProfileFile)(filePath, content);
142
+ else
143
+ fs.writeFileSync(filePath, content, 'utf8');
137
144
  (0, utils_1.verbose)(`write ${filePath}`);
138
145
  }
139
146
  if (executable && !constants_1.IS_WINDOWS) {
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codexSharedHome = codexSharedHome;
4
+ exports.codexProfileName = codexProfileName;
5
+ exports.codexProfileSkills = codexProfileSkills;
6
+ exports.renderCodexProfile = renderCodexProfile;
7
+ exports.refreshCodexProfileSkills = refreshCodexProfileSkills;
8
+ exports.writeCodexProfileFile = writeCodexProfileFile;
9
+ exports.withCodexProfileLock = withCodexProfileLock;
10
+ exports.migrateCodexSessions = migrateCodexSessions;
11
+ const fs = require("fs");
12
+ const path = require("path");
13
+ const crypto_1 = require("crypto");
14
+ const smol_toml_1 = require("smol-toml");
15
+ function codexSharedHome(context) {
16
+ return path.join(context.configRoot, 'runtime', 'codex');
17
+ }
18
+ function codexProfileName(context) {
19
+ const identity = path.resolve(context.profileDir);
20
+ const canonical = process.platform === 'win32' ? identity.toLowerCase() : identity;
21
+ return `agent-run-${(0, crypto_1.createHash)('sha256').update(canonical).digest('hex').slice(0, 20)}`;
22
+ }
23
+ function codexProfileSkills(context) {
24
+ return path.join(codexSharedHome(context), 'skills', codexProfileName(context));
25
+ }
26
+ // Only scan agent-run's generated skills. Personal/system skills keep their native settings.
27
+ function generatedSkills(home) {
28
+ const root = path.join(home, 'skills');
29
+ if (!fs.existsSync(root))
30
+ return [];
31
+ const files = [];
32
+ for (const profile of fs.readdirSync(root, { withFileTypes: true })) {
33
+ if (!profile.isDirectory() || !/^agent-run-[a-f0-9]{20}$/.test(profile.name))
34
+ continue;
35
+ const dir = path.join(root, profile.name);
36
+ for (const skill of fs.readdirSync(dir, { withFileTypes: true })) {
37
+ const file = path.join(dir, skill.name, 'SKILL.md');
38
+ if (skill.isDirectory() && fs.existsSync(file))
39
+ files.push(file);
40
+ }
41
+ }
42
+ return files.sort();
43
+ }
44
+ function configureSkills(config, home, profile, files) {
45
+ const settings = (config.skills ?? {});
46
+ const existing = (settings.config ?? []);
47
+ const generatedRoot = path.join(home, 'skills') + path.sep;
48
+ const isGenerated = (file) => {
49
+ const relative = path.resolve(file).slice(generatedRoot.length);
50
+ return path.resolve(file).startsWith(generatedRoot) && /^agent-run-[a-f0-9]{20}[\\/]/.test(relative);
51
+ };
52
+ settings.config = [
53
+ ...existing.filter((entry) => !isGenerated(entry.path)),
54
+ ...files.map((file) => ({
55
+ path: file,
56
+ enabled: path.dirname(path.dirname(file)) === path.join(home, 'skills', profile)
57
+ && (existing.find((entry) => entry.path === file)?.enabled ?? true)
58
+ }))
59
+ ];
60
+ config.skills = settings;
61
+ }
62
+ function renderCodexProfile(context, base, instructions) {
63
+ const config = (0, smol_toml_1.parse)(base);
64
+ config.developer_instructions = [config.developer_instructions, instructions].filter(Boolean).join('\n\n');
65
+ if (process.platform === 'win32') {
66
+ // A fresh home otherwise silently downgrades workspace-write to read-only.
67
+ config.windows = { sandbox: 'unelevated', ...(config.windows ?? {}) };
68
+ }
69
+ configureSkills(config, codexSharedHome(context), codexProfileName(context), pendingSkills(context));
70
+ return (0, smol_toml_1.stringify)(config) + '\n';
71
+ }
72
+ function pendingSkills(context) {
73
+ const ownDir = codexProfileSkills(context);
74
+ const others = generatedSkills(codexSharedHome(context)).filter((file) => path.dirname(path.dirname(file)) !== ownDir);
75
+ const own = context.skills.map((skill) => path.join(ownDir, skill.name, 'SKILL.md'));
76
+ return [...new Set([...others, ...own])].sort();
77
+ }
78
+ // Refresh older generated profiles too: newly generated project skills must not
79
+ // become enabled in another profile merely because they share a discovery root.
80
+ function refreshCodexProfileSkills(context) {
81
+ const home = codexSharedHome(context);
82
+ const files = pendingSkills(context);
83
+ for (const entry of fs.readdirSync(home)) {
84
+ if (!/^agent-run-[a-f0-9]{20}\.config\.toml$/.test(entry))
85
+ continue;
86
+ const file = path.join(home, entry);
87
+ const original = fs.readFileSync(file, 'utf8');
88
+ const config = (0, smol_toml_1.parse)(original);
89
+ configureSkills(config, home, entry.replace('.config.toml', ''), files);
90
+ const content = (0, smol_toml_1.stringify)(config) + '\n';
91
+ if (content !== original)
92
+ writeCodexProfileFile(file, content);
93
+ }
94
+ }
95
+ function writeCodexProfileFile(file, content) {
96
+ const temporary = `${file}.${(0, crypto_1.randomUUID)()}.tmp`;
97
+ try {
98
+ fs.writeFileSync(temporary, content, { encoding: 'utf8', mode: 0o600 });
99
+ fs.renameSync(temporary, file);
100
+ }
101
+ finally {
102
+ fs.rmSync(temporary, { force: true });
103
+ }
104
+ }
105
+ // Profile refresh, skill publication and session migration share one writer.
106
+ // Codex readers see complete profile files through atomic rename.
107
+ function withCodexProfileLock(context, run) {
108
+ const home = codexSharedHome(context);
109
+ fs.mkdirSync(home, { recursive: true });
110
+ const lock = path.join(home, '.agent-run-sync.lock');
111
+ const deadline = Date.now() + 30000;
112
+ let descriptor;
113
+ for (;;) {
114
+ try {
115
+ descriptor = fs.openSync(lock, 'wx', 0o600);
116
+ break;
117
+ }
118
+ catch (error) {
119
+ if (error.code !== 'EEXIST')
120
+ throw error;
121
+ try {
122
+ const owner = Number(fs.readFileSync(lock, 'utf8'));
123
+ if (Number.isInteger(owner) && owner > 0) {
124
+ try {
125
+ process.kill(owner, 0);
126
+ }
127
+ catch (probe) {
128
+ if (probe.code === 'ESRCH') {
129
+ fs.rmSync(lock, { force: true });
130
+ continue;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ catch (readError) {
136
+ if (readError.code === 'ENOENT')
137
+ continue;
138
+ throw readError;
139
+ }
140
+ if (Date.now() >= deadline)
141
+ throw new Error(`Timed out waiting for Codex profile generation: ${lock}`);
142
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
143
+ }
144
+ }
145
+ try {
146
+ fs.writeFileSync(descriptor, String(process.pid));
147
+ return run();
148
+ }
149
+ finally {
150
+ fs.closeSync(descriptor);
151
+ fs.rmSync(lock, { force: true });
152
+ }
153
+ }
154
+ function migrateCodexSessions(legacyHome, sharedHome) {
155
+ const marker = path.join(sharedHome, 'agent-run-migrations', `${(0, crypto_1.createHash)('sha256').update(path.resolve(legacyHome)).digest('hex')}.json`);
156
+ if (fs.existsSync(marker))
157
+ return;
158
+ // Rollouts are Codex's durable session source. Let Codex rebuild its derived
159
+ // database; never merge SQLite files or copy daemon installs, sockets or locks.
160
+ function copyMissing(source, target) {
161
+ if (!fs.existsSync(source))
162
+ return;
163
+ for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
164
+ const from = path.join(source, entry.name);
165
+ const to = path.join(target, entry.name);
166
+ if (entry.isDirectory())
167
+ copyMissing(from, to);
168
+ else if (entry.isFile() && entry.name.endsWith('.jsonl')) {
169
+ fs.mkdirSync(target, { recursive: true });
170
+ try {
171
+ fs.copyFileSync(from, to, fs.constants.COPYFILE_EXCL);
172
+ }
173
+ catch (error) {
174
+ if (error.code !== 'EEXIST')
175
+ throw error;
176
+ }
177
+ }
178
+ }
179
+ }
180
+ for (const dir of ['sessions', 'archived_sessions'])
181
+ copyMissing(path.join(legacyHome, dir), path.join(sharedHome, dir));
182
+ fs.mkdirSync(path.dirname(marker), { recursive: true });
183
+ fs.writeFileSync(marker, JSON.stringify({ source: legacyHome, migrated: new Date().toISOString() }) + '\n');
184
+ }
@@ -5,7 +5,7 @@ const fs = require("fs");
5
5
  const path = require("path");
6
6
  const project_1 = require("../project");
7
7
  function postflightProjectCheck(context, allowLocal, code) {
8
- if (!context.guardrails.forbidRepoAiFiles) {
8
+ if (!context.guardrails.forbidRepoAiFiles || !(0, project_1.hasProjectFileScope)(context.projectRoot, context.profile)) {
9
9
  return code;
10
10
  }
11
11
  if (!allowLocal) {
package/dist/templates.js CHANGED
@@ -12,6 +12,7 @@ const nunjucks = require("nunjucks");
12
12
  const constants_1 = require("./constants");
13
13
  const utils_1 = require("./utils");
14
14
  const config_1 = require("./brain/config");
15
+ const codex_profile_1 = require("./runtime/codex-profile");
15
16
  function createNunjucksEnv(configRoot) {
16
17
  return new nunjucks.Environment(new nunjucks.FileSystemLoader(configRoot, { noCache: true }), {
17
18
  autoescape: false,
@@ -82,10 +83,10 @@ function buildRenderContext(projectRoot, profileDir, configRoot, manifest, env)
82
83
  memoriesDir,
83
84
  globalMemoryDir: (0, config_1.readBrainConfig)(configRoot)?.enabled ? path.join(configRoot, 'global', 'memory') : path.join(configRoot, 'notes', 'memory'),
84
85
  projectMemoryDir,
85
- nativeMemoryDir: path.join(codexHomeDir, 'memories'),
86
+ nativeMemoryDir: path.join(configRoot, 'runtime', 'codex', 'memories'),
86
87
  codexHomeDir,
87
88
  overridesDir: path.join(profileDir, 'overrides'),
88
- codexSkillsDir: path.join(codexHomeDir, 'skills'),
89
+ codexSkillsDir: (0, codex_profile_1.codexProfileSkills)(baseContext),
89
90
  claudeSkillsDir: path.join(liveDir, '.claude', 'skills'),
90
91
  geminiRuntimeDir,
91
92
  geminiHomeDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/agent-run",
3
- "version": "0.99.40",
3
+ "version": "0.99.42",
4
4
  "packageManager": "pnpm@10.34.5",
5
5
  "bin": {
6
6
  "agent-run": "dist/agent-run.js",
@@ -35,7 +35,8 @@
35
35
  "clean:dist": "rimraf ./dist/",
36
36
  "cleanbuild": "run-s clean:dist build",
37
37
  "prepack": "run-s build",
38
- "test": "run-s build test:integration test:release",
38
+ "test": "run-s build test:codex-profiles test:integration test:release",
39
+ "test:codex-profiles": "node --test scripts/test-codex-profiles.cjs",
39
40
  "test:brain": "node --test scripts/test-brain.cjs",
40
41
  "test:integration": "bash ./scripts/test.sh",
41
42
  "test:release": "bash ./scripts/test-release.sh",
@@ -65,6 +66,7 @@
65
66
  "cross-spawn": "^7.0.6",
66
67
  "jsonc-parser": "^3.3.1",
67
68
  "nunjucks": "^3.2.4",
69
+ "smol-toml": "^1.9.0",
68
70
  "yaml": "^2.9.0",
69
71
  "zod": "^4.5.4"
70
72
  }