@technomoron/agent-run 0.99.29 → 0.99.30
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 +13 -0
- package/README.md +131 -20
- package/dist/agents/claude.js +93 -0
- package/dist/agents/codex.js +77 -0
- package/dist/agents/gemini.js +112 -0
- package/dist/agents/grok.js +73 -0
- package/dist/agents/registry.js +26 -0
- package/dist/agents/shared.js +17 -0
- package/dist/agents/types.js +4 -0
- package/dist/cli.js +31 -7
- package/dist/commands.js +33 -9
- package/dist/config/render-instructions.js +54 -0
- package/dist/config/render-mcp.js +88 -0
- package/dist/config/render-settings.js +35 -0
- package/dist/config/render-skills.js +51 -0
- package/dist/constants.js +5 -2
- package/dist/defaults.js +31 -5
- package/dist/manifest.js +37 -1
- package/dist/renderer.js +80 -245
- package/dist/runtime/environment.js +17 -0
- package/dist/runtime/postflight.js +40 -0
- package/dist/runtime/shared-state.js +44 -0
- package/dist/runtime/spawn-agent.js +7 -0
- package/dist/templates.js +9 -0
- package/examples/basic-config/agent-config/agent-run.defaults.jsonc +6 -1
- package/examples/basic-config/agent-config/global/tool-templates/gemini-settings.json.njk +5 -0
- package/examples/basic-config/agent-config/global/tool-templates/grok-config.toml.njk +1 -0
- package/examples/basic-config/agent-config/starter/basic-project/agent-run.jsonc +20 -0
- package/package.json +1 -1
- package/scripts/update-ai-tools.sh +25 -49
- package/dist/tools.js +0 -125
package/dist/renderer.js
CHANGED
|
@@ -4,8 +4,10 @@ exports.renderProfile = renderProfile;
|
|
|
4
4
|
exports.syncAgentProfile = syncAgentProfile;
|
|
5
5
|
exports.checkRenderedProfile = checkRenderedProfile;
|
|
6
6
|
const fs = require("fs");
|
|
7
|
-
const os = require("os");
|
|
8
7
|
const path = require("path");
|
|
8
|
+
const registry_1 = require("./agents/registry");
|
|
9
|
+
const render_instructions_1 = require("./config/render-instructions");
|
|
10
|
+
const render_skills_1 = require("./config/render-skills");
|
|
9
11
|
const constants_1 = require("./constants");
|
|
10
12
|
const config_tree_1 = require("./config-tree");
|
|
11
13
|
const defaults_1 = require("./defaults");
|
|
@@ -24,10 +26,32 @@ function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = nu
|
|
|
24
26
|
(0, config_tree_1.ensureConfigRootGitignore)(configRoot);
|
|
25
27
|
}
|
|
26
28
|
const context = (0, templates_1.buildRenderContext)(projectRoot, agentDir, configRoot, manifest, env);
|
|
27
|
-
|
|
28
|
-
context.
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const canonicalInstructions = (0, render_instructions_1.buildCanonicalInstructions)(env, configRoot, manifest, context, trace);
|
|
30
|
+
context.renderedAgentSections = canonicalInstructions.sections;
|
|
31
|
+
context.skills = (0, render_skills_1.buildCanonicalSkills)(env, configRoot, manifest, context, trace);
|
|
32
|
+
const adapters = (0, registry_1.enabledAgentAdapters)(context).filter((adapter) => targetTool === null || adapter.id === targetTool);
|
|
33
|
+
const agentsMd = adapters.some((adapter) => adapter.id !== 'claude')
|
|
34
|
+
? (0, render_instructions_1.writeAgentsMd)(env, configRoot, context, trace)
|
|
35
|
+
: '';
|
|
36
|
+
const claudeMd = adapters.some((adapter) => adapter.id === 'claude')
|
|
37
|
+
? (0, render_instructions_1.writeClaudeMd)(env, configRoot, context, trace)
|
|
38
|
+
: '';
|
|
39
|
+
const runtimes = {};
|
|
40
|
+
for (const adapter of adapters) {
|
|
41
|
+
runtimes[adapter.id] = adapter.generate({
|
|
42
|
+
context,
|
|
43
|
+
configRoot,
|
|
44
|
+
env,
|
|
45
|
+
trace,
|
|
46
|
+
agentsMd,
|
|
47
|
+
claudeMd
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const files = [
|
|
51
|
+
...Object.values(runtimes).flatMap((runtime) => runtime?.files ?? []),
|
|
52
|
+
...(0, guards_1.renderGuardShims)(context)
|
|
53
|
+
];
|
|
54
|
+
return { agentDir, configRoot, profile, context, files, skills: context.skills, runtimes };
|
|
31
55
|
}
|
|
32
56
|
function validateManifestProfile(manifestProfile, inferredProfile, agentDir) {
|
|
33
57
|
if (manifestProfile === inferredProfile) {
|
|
@@ -39,70 +63,9 @@ function validateManifestProfile(manifestProfile, inferredProfile, agentDir) {
|
|
|
39
63
|
}
|
|
40
64
|
throw new Error(`${path.join(agentDir, constants_1.MANIFEST_FILE_NAME)} profile must match inferred profile ${inferredProfile}`);
|
|
41
65
|
}
|
|
42
|
-
function renderAgentSections(env, configRoot, manifest, context, trace) {
|
|
43
|
-
const sections = [(0, templates_1.renderTemplateFile)(env, configRoot, manifest.agent.base, context, trace)];
|
|
44
|
-
for (const include of manifest.agent.includes) {
|
|
45
|
-
const includePath = (0, templates_1.resolveConfigPath)(configRoot, include, context);
|
|
46
|
-
if (!fs.existsSync(includePath)) {
|
|
47
|
-
if (include.includes('AGENTS-MODS.md') || include.includes(constants_1.LOCAL_TEMPLATE_FILE_NAME)) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
throw new Error(`missing template: ${includePath}`);
|
|
51
|
-
}
|
|
52
|
-
sections.push((0, templates_1.renderTemplateFile)(env, configRoot, include, context, trace));
|
|
53
|
-
}
|
|
54
|
-
const renderedSections = sections.map((section, index) => {
|
|
55
|
-
const label = index === 0 ? manifest.agent.base : manifest.agent.includes[index - 1] ?? `section ${index}`;
|
|
56
|
-
(0, templates_1.assertNoUnexpandedTemplateVars)(label, section);
|
|
57
|
-
return section.trimEnd();
|
|
58
|
-
});
|
|
59
|
-
renderedSections.push(projectMemoryInstructions(context));
|
|
60
|
-
return renderedSections;
|
|
61
|
-
}
|
|
62
|
-
function projectMemoryInstructions(context) {
|
|
63
|
-
return [
|
|
64
|
-
'## Project Memory',
|
|
65
|
-
'',
|
|
66
|
-
`Project memory is stored in ${context.paths.projectMemoryDir}.`,
|
|
67
|
-
'Read README.md there before starting work when prior project context may matter, then read only the linked files relevant to the task.',
|
|
68
|
-
'Do not store secrets, raw chat transcripts, or temporary task state there.',
|
|
69
|
-
'Update project memory only when the user explicitly asks you to remember or update something for this project.'
|
|
70
|
-
].join('\n');
|
|
71
|
-
}
|
|
72
|
-
function renderProfileFiles(env, configRoot, context, targetTool, trace) {
|
|
73
|
-
const files = [];
|
|
74
|
-
if (context.tools.codex && (targetTool === null || targetTool === 'codex')) {
|
|
75
|
-
files.push({
|
|
76
|
-
path: path.join(context.paths.codexHomeDir, 'AGENTS.md'),
|
|
77
|
-
content: renderToolInstructions('AGENTS.md', env, configRoot, context, false, trace)
|
|
78
|
-
});
|
|
79
|
-
files.push({
|
|
80
|
-
path: path.join(context.paths.codexHomeDir, 'config.toml'),
|
|
81
|
-
content: renderCodexConfig(env, configRoot, context, trace)
|
|
82
|
-
});
|
|
83
|
-
files.push(...renderNativeSkillFiles(context, 'codex'));
|
|
84
|
-
}
|
|
85
|
-
if (context.tools.claude && (targetTool === null || targetTool === 'claude')) {
|
|
86
|
-
files.push({
|
|
87
|
-
path: path.join(context.paths.liveDir, 'CLAUDE.md'),
|
|
88
|
-
content: renderToolInstructions('CLAUDE.md', env, configRoot, context, true, trace)
|
|
89
|
-
});
|
|
90
|
-
files.push({
|
|
91
|
-
path: path.join(context.paths.liveDir, '.claude', 'agent-run-settings.json'),
|
|
92
|
-
content: renderClaudeSettings(env, configRoot, context, trace)
|
|
93
|
-
});
|
|
94
|
-
files.push({
|
|
95
|
-
path: path.join(context.paths.liveDir, '.claude', '.claude-plugin', 'plugin.json'),
|
|
96
|
-
content: claudePluginManifestContent(context)
|
|
97
|
-
});
|
|
98
|
-
files.push(...renderNativeSkillFiles(context, 'claude'));
|
|
99
|
-
}
|
|
100
|
-
files.push(...(0, guards_1.renderGuardShims)(context));
|
|
101
|
-
return files;
|
|
102
|
-
}
|
|
103
66
|
function syncAgentProfile(projectRoot, agentDir, options) {
|
|
104
67
|
const rendered = renderProfile(projectRoot, agentDir, false, null, undefined, options);
|
|
105
|
-
syncRuntimeDirs(rendered
|
|
68
|
+
syncRuntimeDirs(rendered);
|
|
106
69
|
removeStaleGeneratedEntries(rendered);
|
|
107
70
|
for (const file of rendered.files) {
|
|
108
71
|
writeGeneratedFile(file.path, file.content, file.executable ?? false);
|
|
@@ -111,6 +74,33 @@ function syncAgentProfile(projectRoot, agentDir, options) {
|
|
|
111
74
|
removeLegacyGeneratedClaudeSettings(rendered.context);
|
|
112
75
|
return rendered;
|
|
113
76
|
}
|
|
77
|
+
function syncRuntimeDirs(rendered) {
|
|
78
|
+
const context = rendered.context;
|
|
79
|
+
const runtimeDirs = Object.values(rendered.runtimes).flatMap((runtime) => runtime?.requiredDirs ?? []);
|
|
80
|
+
for (const dir of [
|
|
81
|
+
context.paths.reviewDir,
|
|
82
|
+
context.paths.projectMemoryDir,
|
|
83
|
+
context.paths.memoriesDir,
|
|
84
|
+
context.paths.liveDir,
|
|
85
|
+
context.paths.binDir,
|
|
86
|
+
...runtimeDirs
|
|
87
|
+
]) {
|
|
88
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
const projectMemoryIndex = path.join(context.paths.projectMemoryDir, 'README.md');
|
|
91
|
+
if (!fs.existsSync(projectMemoryIndex)) {
|
|
92
|
+
fs.writeFileSync(projectMemoryIndex, (0, defaults_1.defaultProjectMemoryIndex)(), 'utf8');
|
|
93
|
+
(0, utils_1.verbose)(`created ${projectMemoryIndex}`);
|
|
94
|
+
}
|
|
95
|
+
migrateLiveReviewFiles(context);
|
|
96
|
+
removeLegacyCodexSkillDirs(context);
|
|
97
|
+
removeLegacyCodeReviewSkillDirs(context);
|
|
98
|
+
for (const runtime of Object.values(rendered.runtimes)) {
|
|
99
|
+
if (runtime) {
|
|
100
|
+
(0, registry_1.getAgentAdapter)(runtime.id).prepare?.(runtime);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
114
104
|
function writeGeneratedFile(filePath, content, executable) {
|
|
115
105
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
116
106
|
const unchanged = fs.existsSync(filePath) && fs.readFileSync(filePath, 'utf8') === content;
|
|
@@ -128,24 +118,24 @@ function writeGeneratedFile(filePath, content, executable) {
|
|
|
128
118
|
}
|
|
129
119
|
function removeStaleGeneratedEntries(rendered) {
|
|
130
120
|
const expectedFiles = new Set(rendered.files.map((file) => path.resolve(file.path)));
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
121
|
+
for (const adapter of (0, registry_1.listAgentAdapters)()) {
|
|
122
|
+
const agentLayout = adapter.layout(rendered.context);
|
|
123
|
+
for (const filePath of [agentLayout.instructionFile, ...agentLayout.configFiles]) {
|
|
124
|
+
if (!expectedFiles.has(path.resolve(filePath))) {
|
|
125
|
+
fs.rmSync(filePath, { force: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const expectedSkills = rendered.context.tools[adapter.id]
|
|
129
|
+
? new Set(rendered.skills.map((skill) => skill.name))
|
|
130
|
+
: new Set();
|
|
131
|
+
removeStaleGeneratedSkills(agentLayout.skillsDir, expectedSkills, agentLayout.preservedSkillNames ?? new Set());
|
|
132
|
+
}
|
|
133
|
+
for (const name of ['git', 'git.cmd', 'npm', 'npm.cmd', 'pnpm', 'pnpm.cmd', 'gh', 'gh.cmd']) {
|
|
134
|
+
const filePath = path.join(rendered.context.paths.binDir, name);
|
|
142
135
|
if (!expectedFiles.has(path.resolve(filePath))) {
|
|
143
136
|
fs.rmSync(filePath, { force: true });
|
|
144
137
|
}
|
|
145
138
|
}
|
|
146
|
-
const skillNames = new Set(rendered.skills.map((skill) => skill.name));
|
|
147
|
-
removeStaleGeneratedSkills(context.paths.codexSkillsDir, context.tools.codex ? skillNames : new Set(), new Set(['.system']));
|
|
148
|
-
removeStaleGeneratedSkills(context.paths.claudeSkillsDir, context.tools.claude ? skillNames : new Set());
|
|
149
139
|
}
|
|
150
140
|
function removeStaleGeneratedSkills(dir, expectedNames, preservedNames = new Set()) {
|
|
151
141
|
if (!fs.existsSync(dir)) {
|
|
@@ -158,10 +148,7 @@ function removeStaleGeneratedSkills(dir, expectedNames, preservedNames = new Set
|
|
|
158
148
|
}
|
|
159
149
|
}
|
|
160
150
|
function removeLegacyGeneratedCodexFiles(context) {
|
|
161
|
-
for (const legacyPath of [
|
|
162
|
-
path.join(context.paths.liveDir, 'AGENTS.md'),
|
|
163
|
-
path.join(context.paths.liveDir, 'config.toml')
|
|
164
|
-
]) {
|
|
151
|
+
for (const legacyPath of [path.join(context.paths.liveDir, 'AGENTS.md'), path.join(context.paths.liveDir, 'config.toml')]) {
|
|
165
152
|
if (fs.existsSync(legacyPath)) {
|
|
166
153
|
fs.rmSync(legacyPath);
|
|
167
154
|
(0, utils_1.verbose)(`removed legacy generated Codex file ${legacyPath}`);
|
|
@@ -193,9 +180,9 @@ function checkRenderedProfile(projectRoot, agentDir) {
|
|
|
193
180
|
try {
|
|
194
181
|
const rendered = renderProfile(projectRoot, agentDir, true);
|
|
195
182
|
checkRenderedFiles(rendered, findings);
|
|
196
|
-
checkRuntimeDirectories(rendered
|
|
183
|
+
checkRuntimeDirectories(rendered, findings);
|
|
197
184
|
for (const skill of rendered.skills) {
|
|
198
|
-
validateRenderedSkill(skill.renderedContent, skill.sourcePath);
|
|
185
|
+
(0, render_skills_1.validateRenderedSkill)(skill.renderedContent, skill.sourcePath);
|
|
199
186
|
}
|
|
200
187
|
}
|
|
201
188
|
catch (error) {
|
|
@@ -219,16 +206,16 @@ function checkRenderedFiles(rendered, findings) {
|
|
|
219
206
|
}
|
|
220
207
|
}
|
|
221
208
|
}
|
|
222
|
-
function checkRuntimeDirectories(
|
|
209
|
+
function checkRuntimeDirectories(rendered, findings) {
|
|
210
|
+
const context = rendered.context;
|
|
211
|
+
const runtimeDirs = Object.values(rendered.runtimes).flatMap((runtime) => runtime?.requiredDirs ?? []);
|
|
223
212
|
for (const dir of [
|
|
224
213
|
context.paths.reviewDir,
|
|
225
214
|
context.paths.projectMemoryDir,
|
|
226
215
|
context.paths.memoriesDir,
|
|
227
|
-
context.paths.codexHomeDir,
|
|
228
216
|
context.paths.liveDir,
|
|
229
|
-
context.paths.
|
|
230
|
-
|
|
231
|
-
context.paths.binDir
|
|
217
|
+
context.paths.binDir,
|
|
218
|
+
...runtimeDirs
|
|
232
219
|
]) {
|
|
233
220
|
if (!fs.existsSync(dir)) {
|
|
234
221
|
findings.push({ message: `missing generated runtime directory: ${dir}`, severity: 'ERROR' });
|
|
@@ -248,133 +235,6 @@ function checkConfigGitignore(configRoot, findings) {
|
|
|
248
235
|
}
|
|
249
236
|
}
|
|
250
237
|
}
|
|
251
|
-
function renderSkills(env, configRoot, manifest, context, trace) {
|
|
252
|
-
return manifest.skills.install.map((name) => {
|
|
253
|
-
const sourceTemplate = manifest.skills.overrides[name] ?? `global/skills/${name}/SKILL.md.njk`;
|
|
254
|
-
const sourcePath = (0, templates_1.resolveConfigPath)(configRoot, sourceTemplate, context);
|
|
255
|
-
if (!fs.existsSync(sourcePath)) {
|
|
256
|
-
throw new Error(`missing skill template for ${name}: ${sourcePath}`);
|
|
257
|
-
}
|
|
258
|
-
const renderedContent = (0, templates_1.renderTemplateFile)(env, configRoot, sourceTemplate, context, trace);
|
|
259
|
-
(0, templates_1.assertNoUnexpandedTemplateVars)(`skill ${name}`, renderedContent);
|
|
260
|
-
validateRenderedSkill(renderedContent, sourcePath);
|
|
261
|
-
return { name, sourcePath, renderedContent, description: extractSkillDescription(renderedContent) };
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
function renderNativeSkillFiles(context, targetTool) {
|
|
265
|
-
const targetDir = targetTool === 'codex' ? context.paths.codexSkillsDir : context.paths.claudeSkillsDir;
|
|
266
|
-
return context.skills.map((skill) => ({
|
|
267
|
-
path: path.join(targetDir, skill.name, 'SKILL.md'),
|
|
268
|
-
content: skill.renderedContent
|
|
269
|
-
}));
|
|
270
|
-
}
|
|
271
|
-
function renderToolInstructions(templateName, env, configRoot, context, isClaude, trace) {
|
|
272
|
-
const templatePath = `global/tool-templates/${templateName}.njk`;
|
|
273
|
-
const content = fs.existsSync(path.join(configRoot, templatePath))
|
|
274
|
-
? (0, templates_1.renderTemplateFile)(env, configRoot, templatePath, context, trace)
|
|
275
|
-
: env.renderString((0, defaults_1.defaultToolInstructionsTemplate)(isClaude), context);
|
|
276
|
-
(0, templates_1.assertNoUnexpandedTemplateVars)(templateName, content);
|
|
277
|
-
return content.replace(/\n*$/, '\n');
|
|
278
|
-
}
|
|
279
|
-
function renderCodexConfig(env, configRoot, context, trace) {
|
|
280
|
-
const templatePath = resolveProfileOverrideTemplate(configRoot, context, 'codex-config.toml.njk', 'global/tool-templates/codex-config.toml.njk');
|
|
281
|
-
const content = templatePath
|
|
282
|
-
? (0, templates_1.renderTemplateFile)(env, configRoot, templatePath, context, trace)
|
|
283
|
-
: (0, defaults_1.defaultCodexConfigContent)(context);
|
|
284
|
-
(0, templates_1.assertNoUnexpandedTemplateVars)('config.toml', content);
|
|
285
|
-
return content.replace(/\n*$/, '\n');
|
|
286
|
-
}
|
|
287
|
-
function renderClaudeSettings(env, configRoot, context, trace) {
|
|
288
|
-
const templatePath = resolveProfileOverrideTemplate(configRoot, context, 'claude-settings.json.njk', 'global/tool-templates/claude-settings.json.njk');
|
|
289
|
-
const content = templatePath
|
|
290
|
-
? (0, templates_1.renderTemplateFile)(env, configRoot, templatePath, context, trace)
|
|
291
|
-
: (0, defaults_1.defaultClaudeSettingsContent)(context);
|
|
292
|
-
(0, templates_1.assertNoUnexpandedTemplateVars)('claude settings.json', content);
|
|
293
|
-
try {
|
|
294
|
-
JSON.parse(content);
|
|
295
|
-
}
|
|
296
|
-
catch (error) {
|
|
297
|
-
throw new Error(`invalid generated Claude settings JSON: ${(0, utils_1.formatError)(error)}`);
|
|
298
|
-
}
|
|
299
|
-
return content.replace(/\n*$/, '\n');
|
|
300
|
-
}
|
|
301
|
-
function claudePluginManifestContent(context) {
|
|
302
|
-
return `${JSON.stringify({
|
|
303
|
-
name: 'agent-run-profile',
|
|
304
|
-
description: `Generated skills for agent-run profile ${context.profile}`,
|
|
305
|
-
version: '1.0.0',
|
|
306
|
-
author: { name: 'Technomoron' }
|
|
307
|
-
}, null, 2)}\n`;
|
|
308
|
-
}
|
|
309
|
-
function resolveProfileOverrideTemplate(configRoot, context, overrideFileName, globalTemplatePath) {
|
|
310
|
-
const overridePath = `${context.profile}/overrides/${overrideFileName}`;
|
|
311
|
-
if (fs.existsSync(path.join(configRoot, overridePath))) {
|
|
312
|
-
return overridePath;
|
|
313
|
-
}
|
|
314
|
-
return fs.existsSync(path.join(configRoot, globalTemplatePath)) ? globalTemplatePath : null;
|
|
315
|
-
}
|
|
316
|
-
function syncRuntimeDirs(context) {
|
|
317
|
-
for (const dir of [
|
|
318
|
-
context.paths.reviewDir,
|
|
319
|
-
context.paths.projectMemoryDir,
|
|
320
|
-
context.paths.memoriesDir,
|
|
321
|
-
context.paths.codexHomeDir,
|
|
322
|
-
context.paths.codexSkillsDir,
|
|
323
|
-
context.paths.claudeSkillsDir,
|
|
324
|
-
context.paths.binDir,
|
|
325
|
-
path.join(context.paths.liveDir, '.claude')
|
|
326
|
-
]) {
|
|
327
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
328
|
-
}
|
|
329
|
-
const projectMemoryIndex = path.join(context.paths.projectMemoryDir, 'README.md');
|
|
330
|
-
if (!fs.existsSync(projectMemoryIndex)) {
|
|
331
|
-
fs.writeFileSync(projectMemoryIndex, (0, defaults_1.defaultProjectMemoryIndex)(), 'utf8');
|
|
332
|
-
(0, utils_1.verbose)(`created ${projectMemoryIndex}`);
|
|
333
|
-
}
|
|
334
|
-
migrateLiveReviewFiles(context);
|
|
335
|
-
removeLegacyCodexSkillDirs(context);
|
|
336
|
-
removeLegacyCodeReviewSkillDirs(context);
|
|
337
|
-
ensureSharedCodexAuth(context.paths.codexHomeDir);
|
|
338
|
-
}
|
|
339
|
-
function ensureSharedCodexAuth(codexHomeDir) {
|
|
340
|
-
const sharedAuthPath = path.join(os.homedir(), '.codex', 'auth.json');
|
|
341
|
-
if (!fs.existsSync(sharedAuthPath)) {
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
const profileAuthPath = path.join(codexHomeDir, 'auth.json');
|
|
345
|
-
if (path.resolve(profileAuthPath) === path.resolve(sharedAuthPath) || isSymlinkTo(profileAuthPath, sharedAuthPath)) {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
if (fs.existsSync(profileAuthPath) || (0, utils_1.isSymlink)(profileAuthPath)) {
|
|
349
|
-
const backupPath = (0, utils_1.nextBackupPath)(profileAuthPath);
|
|
350
|
-
fs.renameSync(profileAuthPath, backupPath);
|
|
351
|
-
(0, utils_1.verbose)(`backed up profile Codex auth ${profileAuthPath} -> ${backupPath}`);
|
|
352
|
-
}
|
|
353
|
-
fs.mkdirSync(path.dirname(profileAuthPath), { recursive: true });
|
|
354
|
-
try {
|
|
355
|
-
fs.symlinkSync(sharedAuthPath, profileAuthPath);
|
|
356
|
-
(0, utils_1.verbose)(`linked profile Codex auth ${profileAuthPath} -> ${sharedAuthPath}`);
|
|
357
|
-
}
|
|
358
|
-
catch (error) {
|
|
359
|
-
if (!constants_1.IS_WINDOWS) {
|
|
360
|
-
throw error;
|
|
361
|
-
}
|
|
362
|
-
fs.copyFileSync(sharedAuthPath, profileAuthPath);
|
|
363
|
-
(0, utils_1.verbose)(`copied shared Codex auth ${sharedAuthPath} -> ${profileAuthPath}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
function isSymlinkTo(filePath, targetPath) {
|
|
367
|
-
try {
|
|
368
|
-
if (!fs.lstatSync(filePath).isSymbolicLink()) {
|
|
369
|
-
return false;
|
|
370
|
-
}
|
|
371
|
-
const linkTarget = fs.readlinkSync(filePath);
|
|
372
|
-
return path.resolve(path.dirname(filePath), linkTarget) === path.resolve(targetPath);
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
238
|
function removeLegacyCodexSkillDirs(context) {
|
|
379
239
|
const legacyCodexDir = path.join(context.paths.liveDir, '.agents');
|
|
380
240
|
if (!(0, utils_1.isSamePathOrDescendant)(context.paths.codexSkillsDir, legacyCodexDir)) {
|
|
@@ -387,8 +247,7 @@ function removeLegacyCodeReviewSkillDirs(context) {
|
|
|
387
247
|
}
|
|
388
248
|
for (const dir of [
|
|
389
249
|
path.join(context.paths.liveDir, '.agents', 'skills', 'code-review'),
|
|
390
|
-
path.join(context.
|
|
391
|
-
path.join(context.paths.claudeSkillsDir, 'code-review')
|
|
250
|
+
...(0, registry_1.listAgentAdapters)().map((adapter) => path.join(adapter.layout(context).skillsDir, 'code-review'))
|
|
392
251
|
]) {
|
|
393
252
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
394
253
|
}
|
|
@@ -441,27 +300,3 @@ function moveFile(sourcePath, targetPath) {
|
|
|
441
300
|
fs.rmSync(sourcePath);
|
|
442
301
|
}
|
|
443
302
|
}
|
|
444
|
-
function validateRenderedSkill(content, sourcePath) {
|
|
445
|
-
const frontMatter = /^---\n([\s\S]*?)\n---\n/.exec(content.replace(/\r\n/g, '\n'));
|
|
446
|
-
if (frontMatter === null) {
|
|
447
|
-
throw new Error(`generated skill missing YAML front matter: ${sourcePath}`);
|
|
448
|
-
}
|
|
449
|
-
const yaml = frontMatter[1] ?? '';
|
|
450
|
-
if (!/^name:\s*\S+/m.test(yaml)) {
|
|
451
|
-
throw new Error(`generated skill missing name: ${sourcePath}`);
|
|
452
|
-
}
|
|
453
|
-
if (!/^description:\s*(?:\S|>\s*$)/m.test(yaml)) {
|
|
454
|
-
throw new Error(`generated skill missing description: ${sourcePath}`);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
function extractSkillDescription(content) {
|
|
458
|
-
const normalized = content.replace(/\r\n/g, '\n');
|
|
459
|
-
const simple = /^description:\s*['"]?(.+?)['"]?\s*$/m.exec(normalized);
|
|
460
|
-
if (simple?.[1]) {
|
|
461
|
-
return simple[1].trim();
|
|
462
|
-
}
|
|
463
|
-
const folded = /^description:\s*>\s*\n((?:[ \t]+.+\n?)+)/m.exec(normalized);
|
|
464
|
-
return folded?.[1]
|
|
465
|
-
? folded[1].split('\n').map((line) => line.trim()).filter(Boolean).join(' ')
|
|
466
|
-
: '';
|
|
467
|
-
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAgentEnvironment = buildAgentEnvironment;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
function buildAgentEnvironment(context) {
|
|
6
|
+
const realPath = process.env.AGENT_RUN_REAL_PATH ?? process.env.PATH ?? '';
|
|
7
|
+
return {
|
|
8
|
+
...process.env,
|
|
9
|
+
AGENT_DIR: context.paths.liveDir,
|
|
10
|
+
AGENT_PROFILE_DIR: context.profileDir,
|
|
11
|
+
AGENT_RUN_PROJECT_ROOT: context.projectRoot,
|
|
12
|
+
AGENT_PROJECT_MEMORY_DIR: context.paths.projectMemoryDir,
|
|
13
|
+
AGENT_GLOBAL_MEMORY_DIR: context.paths.globalMemoryDir,
|
|
14
|
+
AGENT_RUN_REAL_PATH: realPath,
|
|
15
|
+
PATH: `${context.paths.binDir}${path.delimiter}${realPath}`
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.postflightProjectCheck = postflightProjectCheck;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const project_1 = require("../project");
|
|
7
|
+
function postflightProjectCheck(context, allowLocal, code) {
|
|
8
|
+
if (!context.guardrails.forbidRepoAiFiles) {
|
|
9
|
+
return code;
|
|
10
|
+
}
|
|
11
|
+
if (!allowLocal) {
|
|
12
|
+
removeClaudeLocalSettings(context.projectRoot);
|
|
13
|
+
}
|
|
14
|
+
const localAiFiles = (0, project_1.findLocalAiFiles)(context.projectRoot, context.profileDir);
|
|
15
|
+
if (localAiFiles.length === 0) {
|
|
16
|
+
return code;
|
|
17
|
+
}
|
|
18
|
+
(0, project_1.warnForLocalAiFiles)(null, context.projectRoot, localAiFiles);
|
|
19
|
+
return allowLocal ? code : 1;
|
|
20
|
+
}
|
|
21
|
+
function removeClaudeLocalSettings(projectRoot) {
|
|
22
|
+
const claudeDir = path.join(projectRoot, '.claude');
|
|
23
|
+
const localSettingsPath = path.join(claudeDir, 'settings.local.json');
|
|
24
|
+
if (!fs.existsSync(localSettingsPath)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
fs.rmSync(localSettingsPath);
|
|
28
|
+
try {
|
|
29
|
+
fs.rmdirSync(claudeDir);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (!isDirectoryNotEmptyError(error)) {
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
process.stderr.write(`agent-run: removed Claude's project-local settings: ${localSettingsPath}\n`);
|
|
37
|
+
}
|
|
38
|
+
function isDirectoryNotEmptyError(error) {
|
|
39
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOTEMPTY';
|
|
40
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.linkSharedEntry = linkSharedEntry;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
function linkSharedEntry(sourcePath, targetPath, label) {
|
|
9
|
+
if (!fs.existsSync(sourcePath) && !(0, utils_1.isSymlink)(sourcePath)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (path.resolve(sourcePath) === path.resolve(targetPath) || isSymlinkTo(targetPath, sourcePath)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (fs.existsSync(targetPath) || (0, utils_1.isSymlink)(targetPath)) {
|
|
16
|
+
const backupPath = (0, utils_1.nextBackupPath)(targetPath);
|
|
17
|
+
fs.renameSync(targetPath, backupPath);
|
|
18
|
+
(0, utils_1.verbose)(`backed up ${label} ${targetPath} -> ${backupPath}`);
|
|
19
|
+
}
|
|
20
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
21
|
+
try {
|
|
22
|
+
fs.symlinkSync(sourcePath, targetPath, fs.statSync(sourcePath).isDirectory() ? 'junction' : 'file');
|
|
23
|
+
(0, utils_1.verbose)(`linked ${label} ${targetPath} -> ${sourcePath}`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (!constants_1.IS_WINDOWS || fs.statSync(sourcePath).isDirectory()) {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
30
|
+
(0, utils_1.verbose)(`copied ${label} ${sourcePath} -> ${targetPath}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function isSymlinkTo(filePath, targetPath) {
|
|
34
|
+
try {
|
|
35
|
+
if (!fs.lstatSync(filePath).isSymbolicLink()) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const linkTarget = fs.readlinkSync(filePath);
|
|
39
|
+
return path.resolve(path.dirname(filePath), linkTarget) === path.resolve(targetPath);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.spawnAgent = spawnAgent;
|
|
4
|
+
const process_1 = require("../process");
|
|
5
|
+
function spawnAgent(spec) {
|
|
6
|
+
(0, process_1.execCommand)(spec.command, spec.args, spec.env, spec.cwd, spec.onExit);
|
|
7
|
+
}
|
package/dist/templates.js
CHANGED
|
@@ -31,12 +31,16 @@ function buildRenderContext(projectRoot, profileDir, configRoot, manifest, env)
|
|
|
31
31
|
date,
|
|
32
32
|
checks: manifest.checks,
|
|
33
33
|
tools: manifest.tools,
|
|
34
|
+
mcpServers: manifest.mcpServers,
|
|
34
35
|
guardrails: manifest.guardrails
|
|
35
36
|
};
|
|
36
37
|
const reviewDir = resolveRuntimePath(configRoot, manifest.paths.reviewDir, env, baseContext);
|
|
37
38
|
const memoriesDir = resolveRuntimePath(configRoot, manifest.paths.memoriesDir, env, baseContext);
|
|
38
39
|
const projectMemoryDir = resolveRuntimePath(configRoot, manifest.paths.projectMemoryDir, env, baseContext);
|
|
39
40
|
const codexHomeDir = path.join(memoriesDir, 'codex-home');
|
|
41
|
+
const geminiRuntimeDir = path.join(liveDir, 'gemini');
|
|
42
|
+
const geminiHomeDir = path.join(geminiRuntimeDir, 'home');
|
|
43
|
+
const grokRuntimeDir = path.join(liveDir, 'grok');
|
|
40
44
|
const paths = {
|
|
41
45
|
profileDir,
|
|
42
46
|
liveDir,
|
|
@@ -54,6 +58,11 @@ function buildRenderContext(projectRoot, profileDir, configRoot, manifest, env)
|
|
|
54
58
|
overridesDir: path.join(profileDir, 'overrides'),
|
|
55
59
|
codexSkillsDir: path.join(codexHomeDir, 'skills'),
|
|
56
60
|
claudeSkillsDir: path.join(liveDir, '.claude', 'skills'),
|
|
61
|
+
geminiRuntimeDir,
|
|
62
|
+
geminiHomeDir,
|
|
63
|
+
geminiSkillsDir: path.join(geminiHomeDir, '.agents', 'skills'),
|
|
64
|
+
grokRuntimeDir,
|
|
65
|
+
grokSkillsDir: path.join(grokRuntimeDir, 'skills'),
|
|
57
66
|
binDir: path.join(liveDir, 'bin')
|
|
58
67
|
};
|
|
59
68
|
return {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Generated by agent-run. Do not edit directly.
|
|
@@ -17,6 +17,26 @@
|
|
|
17
17
|
"triage": "{{ profile }}/overrides/triage.SKILL.md.njk"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
+
"mcp": {
|
|
21
|
+
"servers": {
|
|
22
|
+
"example-stdio": {
|
|
23
|
+
"command": "node",
|
|
24
|
+
"args": ["tools/example-mcp.js"],
|
|
25
|
+
"env": {
|
|
26
|
+
"EXAMPLE_TOKEN": "${EXAMPLE_TOKEN}"
|
|
27
|
+
},
|
|
28
|
+
"enabled": false
|
|
29
|
+
},
|
|
30
|
+
"example-http": {
|
|
31
|
+
"transport": "http",
|
|
32
|
+
"url": "https://example.invalid/mcp",
|
|
33
|
+
"headers": {
|
|
34
|
+
"Authorization": "Bearer ${EXAMPLE_TOKEN}"
|
|
35
|
+
},
|
|
36
|
+
"enabled": false
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
20
40
|
"checks": [
|
|
21
41
|
"agent-run check .",
|
|
22
42
|
"pnpm test"
|