@technomoron/agent-run 0.99.31 → 0.99.33
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 +48 -0
- package/README.md +124 -5
- package/dist/agent-run.js +1 -2
- package/dist/agents/claude.js +1 -5
- package/dist/brain/cli.js +52 -20
- package/dist/brain/git.js +8 -2
- package/dist/brain/projects.js +1 -1
- package/dist/brain/server.js +27 -6
- package/dist/brain/skills.js +2 -1
- package/dist/brain/store.js +282 -53
- package/dist/brain/todos.js +48 -8
- package/dist/cli.js +3 -12
- package/dist/commands.js +7 -9
- package/dist/config/render-instructions.js +1 -1
- package/dist/config/render-mcp.js +2 -3
- package/dist/config/render-skills.js +3 -2
- package/dist/config-tree.js +0 -22
- package/dist/constants.js +1 -2
- package/dist/guards.js +114 -8
- package/dist/process.js +0 -5
- package/dist/project.js +2 -23
- package/dist/renderer.js +7 -2
- package/dist/templates.js +35 -7
- package/dist/version.js +22 -0
- package/examples/basic-config/agent-config/starter/basic-project/agent-run.jsonc +1 -1
- package/package.json +2 -3
- package/scripts/install-systemd-jobs.sh +1 -8
- /package/examples/basic-config/agent-config/starter/basic-project/{overrides/triage.SKILL.md.njk → skills/triage/SKILL.md.njk} +0 -0
package/dist/commands.js
CHANGED
|
@@ -89,15 +89,15 @@ function runTool(parsed) {
|
|
|
89
89
|
prepareConfigRoot(configRoot);
|
|
90
90
|
requireProfile(command, agentDir);
|
|
91
91
|
migrateProfileOnStart(configRoot, agentDir, false);
|
|
92
|
-
const preview = (0, renderer_1.renderProfile)(projectRoot, agentDir, true
|
|
92
|
+
const preview = (0, renderer_1.renderProfile)(projectRoot, agentDir, true);
|
|
93
93
|
ensureToolEnabled(preview.context, command);
|
|
94
94
|
if (wrapperArgs.generate) {
|
|
95
|
-
printUpdateSummary((0, renderer_1.
|
|
95
|
+
printUpdateSummary((0, renderer_1.syncRenderedProfile)(preview));
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
checkLocalAiFiles(command, projectRoot, agentDir, preview.context, wrapperArgs.local);
|
|
99
99
|
const realBinary = (0, process_1.findRealBinary)(command);
|
|
100
|
-
const rendered = (0, renderer_1.
|
|
100
|
+
const rendered = (0, renderer_1.syncRenderedProfile)(preview);
|
|
101
101
|
const runtime = rendered.runtimes[command];
|
|
102
102
|
if (!runtime) {
|
|
103
103
|
(0, utils_1.fail)(`no generated ${command} runtime found for profile ${rendered.profile}`);
|
|
@@ -186,7 +186,7 @@ function runGenerate(parsed) {
|
|
|
186
186
|
if (projectRoot === null) {
|
|
187
187
|
return;
|
|
188
188
|
}
|
|
189
|
-
const agentDir = initializeProfileSource(projectRoot
|
|
189
|
+
const agentDir = initializeProfileSource(projectRoot);
|
|
190
190
|
migrateProfileOnStart((0, project_1.defaultConfigRoot)(projectRoot), agentDir, false);
|
|
191
191
|
printUpdateSummary((0, renderer_1.syncAgentProfile)(projectRoot, agentDir));
|
|
192
192
|
}
|
|
@@ -200,7 +200,6 @@ function runSetup(parsed) {
|
|
|
200
200
|
(0, utils_1.fail)(`starter config skeleton not found: ${sourcePath}`);
|
|
201
201
|
}
|
|
202
202
|
(0, config_tree_1.copySkeletonTree)(sourcePath, configRoot, new Set(['starter']));
|
|
203
|
-
(0, config_tree_1.ensurePortableSystemdFiles)(configRoot);
|
|
204
203
|
const agentDir = path.join(configRoot, profile);
|
|
205
204
|
migrateProfileOnStart(configRoot, agentDir, false);
|
|
206
205
|
(0, config_tree_1.copySkeletonTree)(path.join(sourcePath, 'starter', 'basic-project'), agentDir);
|
|
@@ -265,7 +264,7 @@ function runEdit(parsed) {
|
|
|
265
264
|
if (projectRoot === null) {
|
|
266
265
|
return;
|
|
267
266
|
}
|
|
268
|
-
const agentDir = initializeProfileSource(projectRoot
|
|
267
|
+
const agentDir = initializeProfileSource(projectRoot);
|
|
269
268
|
migrateProfileOnStart((0, project_1.defaultConfigRoot)(projectRoot), agentDir, false);
|
|
270
269
|
const editPath = (0, manifest_1.createDefaultLocalFile)(agentDir);
|
|
271
270
|
(0, renderer_1.syncAgentProfile)(projectRoot, agentDir);
|
|
@@ -387,7 +386,6 @@ function prepareConfigRoot(configRoot) {
|
|
|
387
386
|
(0, config_tree_1.ensureConfigRootLayout)(configRoot);
|
|
388
387
|
(0, config_tree_1.ensureConfigRootGitignore)(configRoot);
|
|
389
388
|
(0, config_tree_1.ensureDefaultGlobalTemplates)(configRoot);
|
|
390
|
-
(0, config_tree_1.ensurePortableSystemdFiles)(configRoot);
|
|
391
389
|
}
|
|
392
390
|
function activeProject(targetPath, action) {
|
|
393
391
|
const projectRoot = (0, project_1.findProjectRoot)(targetPath);
|
|
@@ -398,8 +396,8 @@ function activeProject(targetPath, action) {
|
|
|
398
396
|
process.stdout.write(`SKIP ignored ${projectRoot}\n`);
|
|
399
397
|
return null;
|
|
400
398
|
}
|
|
401
|
-
function initializeProfileSource(projectRoot
|
|
402
|
-
const configRoot = (0, project_1.defaultConfigRoot)(projectRoot
|
|
399
|
+
function initializeProfileSource(projectRoot) {
|
|
400
|
+
const configRoot = (0, project_1.defaultConfigRoot)(projectRoot);
|
|
403
401
|
const resolved = (0, project_1.resolveProfileResult)(projectRoot, configRoot, false);
|
|
404
402
|
if (!resolved.profile)
|
|
405
403
|
throw new Error(resolved.reason);
|
|
@@ -11,7 +11,7 @@ const templates_1 = require("../templates");
|
|
|
11
11
|
function buildCanonicalInstructions(env, configRoot, manifest, context, trace) {
|
|
12
12
|
const sections = [(0, templates_1.renderTemplateFile)(env, configRoot, manifest.agent.base, context, trace)];
|
|
13
13
|
for (const include of manifest.agent.includes) {
|
|
14
|
-
const includePath = (0, templates_1.resolveConfigPath)(configRoot, include, context);
|
|
14
|
+
const includePath = (0, templates_1.resolveConfigPath)(configRoot, include, context, env);
|
|
15
15
|
if (!fs.existsSync(includePath)) {
|
|
16
16
|
if (include.includes('AGENTS-MODS.md') || include.includes(constants_1.LOCAL_TEMPLATE_FILE_NAME)) {
|
|
17
17
|
continue;
|
|
@@ -45,6 +45,8 @@ function renderJsonMcp(servers, target) {
|
|
|
45
45
|
function renderTomlMcp(servers, target) {
|
|
46
46
|
const sections = [];
|
|
47
47
|
for (const [name, server] of Object.entries(servers)) {
|
|
48
|
+
if (!server.enabled)
|
|
49
|
+
continue;
|
|
48
50
|
const lines = [`[mcp_servers.${tomlKey(name)}]`];
|
|
49
51
|
if (server.transport === 'stdio') {
|
|
50
52
|
lines.push(`command = ${tomlString(server.command ?? '')}`);
|
|
@@ -64,9 +66,6 @@ function renderTomlMcp(servers, target) {
|
|
|
64
66
|
lines.push(`${target === 'codex' ? 'http_headers' : 'headers'} = ${tomlInlineTable(server.headers)}`);
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
|
-
if (!server.enabled) {
|
|
68
|
-
lines.push('enabled = false');
|
|
69
|
-
}
|
|
70
69
|
sections.push(lines.join('\n'));
|
|
71
70
|
}
|
|
72
71
|
return sections.length > 0 ? `${sections.join('\n\n')}\n` : '';
|
|
@@ -7,14 +7,15 @@ const fs = require("fs");
|
|
|
7
7
|
const path = require("path");
|
|
8
8
|
const templates_1 = require("../templates");
|
|
9
9
|
function buildCanonicalSkills(env, configRoot, manifest, context, trace) {
|
|
10
|
+
const skillEnv = (0, templates_1.createSkillNunjucksEnv)(configRoot, context.profileDir, trace);
|
|
10
11
|
return manifest.skills.install.map((name) => {
|
|
11
12
|
const canonical = `global/skills/${name}/SKILL.md`;
|
|
12
13
|
const sourceTemplate = manifest.skills.overrides[name] ?? (fs.existsSync(path.join(configRoot, canonical)) ? canonical : `${canonical}.njk`);
|
|
13
|
-
const sourcePath = (0, templates_1.resolveConfigPath)(configRoot, sourceTemplate, context);
|
|
14
|
+
const sourcePath = (0, templates_1.resolveConfigPath)(configRoot, sourceTemplate, context, env);
|
|
14
15
|
if (!fs.existsSync(sourcePath)) {
|
|
15
16
|
throw new Error(`missing skill template for ${name}: ${sourcePath}`);
|
|
16
17
|
}
|
|
17
|
-
const renderedContent = (
|
|
18
|
+
const renderedContent = skillEnv.render(path.relative(configRoot, sourcePath), context);
|
|
18
19
|
(0, templates_1.assertNoUnexpandedTemplateVars)(`skill ${name}`, renderedContent);
|
|
19
20
|
validateRenderedSkill(renderedContent, sourcePath);
|
|
20
21
|
return { name, sourcePath, renderedContent, description: extractSkillDescription(renderedContent) };
|
package/dist/config-tree.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ensureConfigRootLayout = ensureConfigRootLayout;
|
|
4
4
|
exports.ensureConfigRootGitignore = ensureConfigRootGitignore;
|
|
5
5
|
exports.ensureDefaultGlobalTemplates = ensureDefaultGlobalTemplates;
|
|
6
|
-
exports.ensurePortableSystemdFiles = ensurePortableSystemdFiles;
|
|
7
6
|
exports.migrateOldTemplates = migrateOldTemplates;
|
|
8
7
|
exports.findLegacyProfileDirs = findLegacyProfileDirs;
|
|
9
8
|
exports.findProfileDirs = findProfileDirs;
|
|
@@ -75,27 +74,6 @@ function ensureDefaultGlobalTemplates(configRoot) {
|
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
function ensurePortableSystemdFiles(configRoot) {
|
|
79
|
-
const packageRoot = path.resolve(__dirname, '..');
|
|
80
|
-
const files = new Map([
|
|
81
|
-
['install-systemd-jobs.sh', { source: 'scripts/install-systemd-jobs.sh', mode: 0o755 }],
|
|
82
|
-
['update-ai-tools.sh', { source: 'scripts/update-ai-tools.sh', mode: 0o755 }],
|
|
83
|
-
['ensure-agent-brain.sh', { source: 'scripts/ensure-agent-brain.sh', mode: 0o755 }],
|
|
84
|
-
['agent-brain.service', { source: 'ops/systemd/agent-brain.service', mode: 0o644 }],
|
|
85
|
-
['ai-tools-update.service', { source: 'ops/systemd/ai-tools-update.service', mode: 0o644 }],
|
|
86
|
-
['ai-tools-update.timer', { source: 'ops/systemd/ai-tools-update.timer', mode: 0o644 }]
|
|
87
|
-
]);
|
|
88
|
-
for (const [targetName, asset] of files) {
|
|
89
|
-
const sourcePath = path.join(packageRoot, asset.source);
|
|
90
|
-
const targetPath = path.join(configRoot, targetName);
|
|
91
|
-
if (!fs.existsSync(sourcePath)) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
fs.copyFileSync(sourcePath, targetPath);
|
|
95
|
-
fs.chmodSync(targetPath, asset.mode);
|
|
96
|
-
(0, utils_1.verbose)(`updated ${targetPath}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
77
|
function migrateOldTemplates(configRoot) {
|
|
100
78
|
const oldCodeTemplate = path.join(configRoot, 'templates', 'AGENTS-CODE.md');
|
|
101
79
|
const newCodeTemplate = path.join(configRoot, 'global', 'agents', 'code.md.njk');
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.REQUIRED_GLOBAL_TEMPLATES = exports.GENERATED_GITIGNORE_ENTRIES = exports.BRAIN_GITIGNORE_ENTRIES = exports.LOCAL_AI_DIRECTORY_NAMES = exports.LOCAL_AI_FILE_NAMES = exports.UNEXPANDED_TEMPLATE_RE = exports.
|
|
3
|
+
exports.REQUIRED_GLOBAL_TEMPLATES = exports.GENERATED_GITIGNORE_ENTRIES = exports.BRAIN_GITIGNORE_ENTRIES = exports.LOCAL_AI_DIRECTORY_NAMES = exports.LOCAL_AI_FILE_NAMES = exports.UNEXPANDED_TEMPLATE_RE = exports.VERBOSE_ENV = exports.CONFIG_DIR_ENV = exports.CONFIG_ROOT_OVERRIDE_ENV = exports.LIVE_DIR_NAME = exports.LOCAL_TEMPLATE_FILE_NAME = exports.MANIFEST_FILE_NAME = exports.CONFIG_ROOT_DEFAULTS_FILE_NAME = exports.IGNORE_FILE_NAME = exports.ENV_FILE_NAME = exports.IS_WINDOWS = void 0;
|
|
4
4
|
exports.IS_WINDOWS = process.platform === 'win32';
|
|
5
5
|
exports.ENV_FILE_NAME = '.agent-run.env';
|
|
6
6
|
exports.IGNORE_FILE_NAME = '.agent-run-ignore';
|
|
@@ -11,7 +11,6 @@ exports.LIVE_DIR_NAME = 'live';
|
|
|
11
11
|
exports.CONFIG_ROOT_OVERRIDE_ENV = 'AGENT_RUN_CONFIG_ROOT_OVERRIDE';
|
|
12
12
|
exports.CONFIG_DIR_ENV = 'AGENT_CONFIG_DIR';
|
|
13
13
|
exports.VERBOSE_ENV = 'AGENT_RUN_VERBOSE';
|
|
14
|
-
exports.PACKAGE_VERSION = '0.99.30';
|
|
15
14
|
exports.UNEXPANDED_TEMPLATE_RE = /\{\{[^}]+\}\}|\{%[^%]+%\}/;
|
|
16
15
|
exports.LOCAL_AI_FILE_NAMES = new Set([
|
|
17
16
|
'AGENTS.md',
|
package/dist/guards.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.renderGuardShims = renderGuardShims;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
|
+
const GIT_TEST_REPO_MARKER = '.agent-run-test-repo';
|
|
6
7
|
function renderGuardShims(context) {
|
|
7
8
|
const names = [];
|
|
8
9
|
if (context.guardrails.blockGitWrite) {
|
|
@@ -34,16 +35,46 @@ function posixGitShim() {
|
|
|
34
35
|
return [
|
|
35
36
|
'#!/usr/bin/env bash',
|
|
36
37
|
'set -euo pipefail',
|
|
38
|
+
'agent_run_test_repo() {',
|
|
39
|
+
' local dir="$PWD"',
|
|
40
|
+
' while [ "$#" -gt 0 ]; do',
|
|
41
|
+
' case "$1" in',
|
|
42
|
+
' -C)',
|
|
43
|
+
' [ "$#" -ge 2 ] || return 1',
|
|
44
|
+
' dir="$(cd -- "$dir" 2>/dev/null && cd -- "$2" 2>/dev/null && pwd -P)" || return 1',
|
|
45
|
+
' shift 2 ;;',
|
|
46
|
+
' -c)',
|
|
47
|
+
' [ "$#" -ge 2 ] || return 1',
|
|
48
|
+
' shift 2 ;;',
|
|
49
|
+
' --git-dir*|--work-tree*) return 1 ;;',
|
|
50
|
+
' -*) shift ;;',
|
|
51
|
+
' *) break ;;',
|
|
52
|
+
' esac',
|
|
53
|
+
' done',
|
|
54
|
+
' dir="$(cd -- "$dir" 2>/dev/null && pwd -P)" || return 1',
|
|
55
|
+
' while :; do',
|
|
56
|
+
` if [ -e "$dir/${GIT_TEST_REPO_MARKER}" ]; then return 0; fi`,
|
|
57
|
+
' [ "$dir" != "/" ] || return 1',
|
|
58
|
+
' dir="${dir%/*}"',
|
|
59
|
+
' [ -n "$dir" ] || dir="/"',
|
|
60
|
+
' done',
|
|
61
|
+
'}',
|
|
62
|
+
'blocked=""',
|
|
63
|
+
'skip_value=0',
|
|
37
64
|
'for arg in "$@"; do',
|
|
65
|
+
' if [ "$skip_value" = 1 ]; then skip_value=0; continue; fi',
|
|
38
66
|
' case "$arg" in',
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
' ;;',
|
|
67
|
+
' -C|-c|--git-dir|--work-tree|--namespace|--super-prefix|--config-env) skip_value=1; continue ;;',
|
|
68
|
+
' --help|-h|--version|-v|--html-path|--man-path|--info-path|--) break ;;',
|
|
69
|
+
' -*) continue ;;',
|
|
70
|
+
' commit|tag|push) blocked="$arg"; break ;;',
|
|
71
|
+
' *) break ;;',
|
|
45
72
|
' esac',
|
|
46
73
|
'done',
|
|
74
|
+
'if [ -n "$blocked" ] && [ "${AGENT_RUN_ALLOW_GIT_WRITE:-}" != "1" ] && ! agent_run_test_repo "$@"; then',
|
|
75
|
+
' echo "agent-run: blocked git $blocked. Review and run it manually, or set AGENT_RUN_ALLOW_GIT_WRITE=1 for this invocation." >&2',
|
|
76
|
+
' exit 42',
|
|
77
|
+
'fi',
|
|
47
78
|
...posixRunRealCommand('git'),
|
|
48
79
|
''
|
|
49
80
|
].join('\n');
|
|
@@ -105,16 +136,31 @@ function posixRunRealCommand(tool) {
|
|
|
105
136
|
function windowsShim(name) {
|
|
106
137
|
const executable = name === 'npm' || name === 'pnpm' ? `${name}.cmd` : `${name}.exe`;
|
|
107
138
|
const guard = name === 'git' ? windowsGitGuard() : name === 'gh' ? windowsGhGuard() : windowsPublishGuard(name);
|
|
139
|
+
const helpers = name === 'git' ? windowsGitTestRepo() : [];
|
|
108
140
|
return [
|
|
109
141
|
'@echo off',
|
|
142
|
+
'setlocal DisableDelayedExpansion',
|
|
110
143
|
...guard,
|
|
111
144
|
':run',
|
|
145
|
+
'for %%D in ("%~dp0.") do set "AGENT_RUN_GUARD_DIR=%%~fD"',
|
|
112
146
|
'if defined AGENT_RUN_REAL_PATH (',
|
|
113
147
|
' set "PATH=%AGENT_RUN_REAL_PATH%"',
|
|
114
148
|
') else (',
|
|
115
|
-
' for /f "tokens=1,* delims=;" %%A in ("%PATH%") do set "PATH=%%B"',
|
|
149
|
+
' for /f "tokens=1,* delims=;" %%A in ("%PATH%") do for %%D in ("%%~A\\.") do if /I "%%~fD"=="%AGENT_RUN_GUARD_DIR%" set "PATH=%%B"',
|
|
150
|
+
')',
|
|
151
|
+
'set "AGENT_RUN_COMMAND="',
|
|
152
|
+
`for %%I in (${executable}) do set "AGENT_RUN_COMMAND=%%~$PATH:I"`,
|
|
153
|
+
'if not defined AGENT_RUN_COMMAND (',
|
|
154
|
+
` echo agent-run: cannot find the real ${name} command outside the guard directory. 1>&2`,
|
|
155
|
+
' exit /b 127',
|
|
156
|
+
')',
|
|
157
|
+
'if /I "%AGENT_RUN_COMMAND%"=="%~f0" (',
|
|
158
|
+
` echo agent-run: refused recursive ${name} guard resolution. 1>&2`,
|
|
159
|
+
' exit /b 127',
|
|
116
160
|
')',
|
|
117
|
-
|
|
161
|
+
'"%AGENT_RUN_COMMAND%" %*',
|
|
162
|
+
'exit /b %ERRORLEVEL%',
|
|
163
|
+
...helpers,
|
|
118
164
|
''
|
|
119
165
|
].join('\n');
|
|
120
166
|
}
|
|
@@ -122,17 +168,77 @@ function windowsGitGuard() {
|
|
|
122
168
|
return [
|
|
123
169
|
':scan',
|
|
124
170
|
'if "%~1"=="" goto run',
|
|
171
|
+
'if "%~1"=="-C" goto skip_git_value',
|
|
172
|
+
'if "%~1"=="-c" goto skip_git_value',
|
|
173
|
+
'if "%~1"=="--git-dir" goto skip_git_value',
|
|
174
|
+
'if "%~1"=="--work-tree" goto skip_git_value',
|
|
175
|
+
'if "%~1"=="--namespace" goto skip_git_value',
|
|
176
|
+
'if "%~1"=="--super-prefix" goto skip_git_value',
|
|
177
|
+
'if "%~1"=="--config-env" goto skip_git_value',
|
|
178
|
+
'if "%~1"=="--help" goto run',
|
|
179
|
+
'if "%~1"=="-h" goto run',
|
|
180
|
+
'if "%~1"=="--version" goto run',
|
|
181
|
+
'if "%~1"=="-v" goto run',
|
|
182
|
+
'if "%~1"=="--html-path" goto run',
|
|
183
|
+
'if "%~1"=="--man-path" goto run',
|
|
184
|
+
'if "%~1"=="--info-path" goto run',
|
|
185
|
+
'if "%~1"=="--" goto run',
|
|
125
186
|
'if /I "%~1"=="commit" goto block_git',
|
|
126
187
|
'if /I "%~1"=="tag" goto block_git',
|
|
127
188
|
'if /I "%~1"=="push" goto block_git',
|
|
189
|
+
'set "ARG=%~1"',
|
|
190
|
+
'if not "%ARG:~0,1%"=="-" goto run',
|
|
191
|
+
'shift',
|
|
192
|
+
'goto scan',
|
|
193
|
+
':skip_git_value',
|
|
194
|
+
'shift',
|
|
195
|
+
'if "%~1"=="" goto run',
|
|
128
196
|
'shift',
|
|
129
197
|
'goto scan',
|
|
130
198
|
':block_git',
|
|
131
199
|
'if "%AGENT_RUN_ALLOW_GIT_WRITE%"=="1" goto run',
|
|
200
|
+
'call :agent_run_test_repo %*',
|
|
201
|
+
'if not errorlevel 1 goto run',
|
|
132
202
|
'echo agent-run: blocked git write. Review and run it manually, or set AGENT_RUN_ALLOW_GIT_WRITE=1 for this invocation. 1>&2',
|
|
133
203
|
'exit /b 42'
|
|
134
204
|
];
|
|
135
205
|
}
|
|
206
|
+
function windowsGitTestRepo() {
|
|
207
|
+
return [
|
|
208
|
+
':agent_run_test_repo',
|
|
209
|
+
'setlocal enabledelayedexpansion',
|
|
210
|
+
'set "TARGET=%CD%"',
|
|
211
|
+
':agent_run_scan',
|
|
212
|
+
'if "%~1"=="" goto agent_run_walk',
|
|
213
|
+
'if "%~1"=="-C" goto agent_run_chdir',
|
|
214
|
+
'if "%~1"=="-c" (shift & shift & goto agent_run_scan)',
|
|
215
|
+
'set "ARG=%~1"',
|
|
216
|
+
'if /I "!ARG:~0,9!"=="--git-dir" goto agent_run_deny',
|
|
217
|
+
'if /I "!ARG:~0,11!"=="--work-tree" goto agent_run_deny',
|
|
218
|
+
'if "!ARG:~0,1!"=="-" (shift & goto agent_run_scan)',
|
|
219
|
+
'goto agent_run_walk',
|
|
220
|
+
':agent_run_chdir',
|
|
221
|
+
'if "%~2"=="" goto agent_run_deny',
|
|
222
|
+
'pushd "!TARGET!" 2>nul',
|
|
223
|
+
'if errorlevel 1 goto agent_run_deny',
|
|
224
|
+
'pushd "%~2" 2>nul',
|
|
225
|
+
'if errorlevel 1 (popd & goto agent_run_deny)',
|
|
226
|
+
'set "TARGET=!CD!"',
|
|
227
|
+
'popd',
|
|
228
|
+
'popd',
|
|
229
|
+
'shift',
|
|
230
|
+
'shift',
|
|
231
|
+
'goto agent_run_scan',
|
|
232
|
+
':agent_run_walk',
|
|
233
|
+
`if exist "!TARGET!\\${GIT_TEST_REPO_MARKER}" (endlocal & exit /b 0)`,
|
|
234
|
+
'for %%D in ("!TARGET!\\..") do set "PARENT=%%~fD"',
|
|
235
|
+
'if /I "!PARENT!"=="!TARGET!" goto agent_run_deny',
|
|
236
|
+
'set "TARGET=!PARENT!"',
|
|
237
|
+
'goto agent_run_walk',
|
|
238
|
+
':agent_run_deny',
|
|
239
|
+
'endlocal & exit /b 1'
|
|
240
|
+
];
|
|
241
|
+
}
|
|
136
242
|
function windowsGhGuard() {
|
|
137
243
|
return [
|
|
138
244
|
'set "SAW_RELEASE=0"',
|
package/dist/process.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findRealBinary = findRealBinary;
|
|
4
|
-
exports.execTool = execTool;
|
|
5
4
|
exports.execCommand = execCommand;
|
|
6
5
|
exports.openEditor = openEditor;
|
|
7
6
|
exports.parseEditorCommand = parseEditorCommand;
|
|
@@ -73,10 +72,6 @@ function isAgentRunRedirectShim(filePath) {
|
|
|
73
72
|
return false;
|
|
74
73
|
}
|
|
75
74
|
}
|
|
76
|
-
function execTool(command, args) {
|
|
77
|
-
(0, utils_1.verbose)(`exec tool: ${(0, utils_1.formatCommand)(command, args)}`);
|
|
78
|
-
execCommand(command, args);
|
|
79
|
-
}
|
|
80
75
|
function execCommand(command, args, env, cwd, onExit) {
|
|
81
76
|
(0, utils_1.verbose)(`spawn: ${(0, utils_1.formatCommand)(command, args)} cwd=${cwd ?? process.cwd()}`);
|
|
82
77
|
const child = crossSpawn(command, args, { cwd, env, stdio: 'inherit' });
|
package/dist/project.js
CHANGED
|
@@ -12,7 +12,6 @@ exports.resolveProfileResult = resolveProfileResult;
|
|
|
12
12
|
exports.parseProfile = parseProfile;
|
|
13
13
|
exports.projectRootForProfile = projectRootForProfile;
|
|
14
14
|
exports.defaultConfigRoot = defaultConfigRoot;
|
|
15
|
-
exports.defaultConfigRootSearchCandidates = defaultConfigRootSearchCandidates;
|
|
16
15
|
const childProcess = require("child_process");
|
|
17
16
|
const fs = require("fs");
|
|
18
17
|
const os = require("os");
|
|
@@ -163,7 +162,7 @@ function resolveProfileResult(projectRoot, configRoot = defaultConfigRoot(projec
|
|
|
163
162
|
const named = resolved.profile ? (0, config_1.namedBrainProfile)(configRoot, resolved.profile) : null;
|
|
164
163
|
if (named)
|
|
165
164
|
return { profile: named, reason: '' };
|
|
166
|
-
if (useDefault && (0, config_1.readBrainConfig)(configRoot)?.enabled
|
|
165
|
+
if (useDefault && (0, config_1.readBrainConfig)(configRoot)?.enabled) {
|
|
167
166
|
const configured = resolved.profile !== null && ['agent-run.jsonc', 'local.md.njk', 'AGENTS-MODS.md']
|
|
168
167
|
.some((name) => fs.existsSync(path.join(configRoot, resolved.profile, name)));
|
|
169
168
|
if (!configured)
|
|
@@ -172,11 +171,6 @@ function resolveProfileResult(projectRoot, configRoot = defaultConfigRoot(projec
|
|
|
172
171
|
return resolved;
|
|
173
172
|
}
|
|
174
173
|
function resolveLegacyProfileResult(projectRoot) {
|
|
175
|
-
const envProfile = readAgentRunEnv(projectRoot).AGENT_RUN_PROFILE?.trim();
|
|
176
|
-
if (envProfile) {
|
|
177
|
-
(0, utils_1.verbose)(`using ${constants_1.ENV_FILE_NAME} AGENT_RUN_PROFILE=${envProfile}`);
|
|
178
|
-
return parseProfile(envProfile, `${constants_1.ENV_FILE_NAME} AGENT_RUN_PROFILE`);
|
|
179
|
-
}
|
|
180
174
|
const githubProfile = resolveGitHubProfile(projectRoot);
|
|
181
175
|
if (githubProfile !== null) {
|
|
182
176
|
(0, utils_1.verbose)(`using GitHub origin profile=${githubProfile}`);
|
|
@@ -321,12 +315,11 @@ function parseEnvFile(content) {
|
|
|
321
315
|
}
|
|
322
316
|
return env;
|
|
323
317
|
}
|
|
324
|
-
function defaultConfigRoot(projectRoot
|
|
318
|
+
function defaultConfigRoot(projectRoot) {
|
|
325
319
|
const explicit = explicitConfigRoot(projectRoot);
|
|
326
320
|
if (explicit !== null) {
|
|
327
321
|
return explicit;
|
|
328
322
|
}
|
|
329
|
-
void options;
|
|
330
323
|
return path.join(os.homedir(), '.agent-run');
|
|
331
324
|
}
|
|
332
325
|
function explicitConfigRoot(projectRoot) {
|
|
@@ -342,17 +335,3 @@ function explicitConfigRoot(projectRoot) {
|
|
|
342
335
|
const localValue = env[constants_1.CONFIG_DIR_ENV]?.trim();
|
|
343
336
|
return localValue ? path.resolve(projectRoot, localValue) : null;
|
|
344
337
|
}
|
|
345
|
-
function defaultConfigRootSearchCandidates(_projectRoot, options = {}) {
|
|
346
|
-
const platform = options.platform ?? process.platform;
|
|
347
|
-
const pathApi = platform === 'win32' ? path.win32 : path.posix;
|
|
348
|
-
const homeDir = options.homeDir ?? os.homedir();
|
|
349
|
-
const names = ['agent-config', 'agent-configs'];
|
|
350
|
-
if (platform === 'win32') {
|
|
351
|
-
return [pathApi.join(homeDir, 'Documents', 'code'), pathApi.join(homeDir, 'Desktop', 'code'), 'C:\\code'].flatMap((root) => names.map((name) => pathApi.join(root, name)));
|
|
352
|
-
}
|
|
353
|
-
return [
|
|
354
|
-
...names.map((name) => pathApi.join(homeDir, 'code', name)),
|
|
355
|
-
...names.map((name) => pathApi.join(homeDir, name)),
|
|
356
|
-
...names.map((name) => pathApi.join(homeDir, `.${name}`))
|
|
357
|
-
];
|
|
358
|
-
}
|
package/dist/renderer.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.renderProfile = renderProfile;
|
|
4
4
|
exports.syncAgentProfile = syncAgentProfile;
|
|
5
|
+
exports.syncRenderedProfile = syncRenderedProfile;
|
|
5
6
|
exports.checkRenderedProfile = checkRenderedProfile;
|
|
6
7
|
const fs = require("fs");
|
|
7
8
|
const path = require("path");
|
|
@@ -30,8 +31,8 @@ function renderProfile(projectRoot, agentDir, checkOnly = false, targetTool = nu
|
|
|
30
31
|
const brainEnabled = (0, config_1.readBrainConfig)(configRoot)?.enabled === true;
|
|
31
32
|
if (brainEnabled && !context.mcpServers['agent-brain']) {
|
|
32
33
|
context.mcpServers['agent-brain'] = {
|
|
33
|
-
transport: 'stdio', enabled: true, command:
|
|
34
|
-
args: [
|
|
34
|
+
transport: 'stdio', enabled: true, command: 'agent-brain',
|
|
35
|
+
args: ['mcp', '--configdir', configRoot, '--cwd', projectRoot],
|
|
35
36
|
env: {}, headers: {}
|
|
36
37
|
};
|
|
37
38
|
}
|
|
@@ -87,6 +88,10 @@ function validateManifestProfile(manifestProfile, inferredProfile, agentDir) {
|
|
|
87
88
|
}
|
|
88
89
|
function syncAgentProfile(projectRoot, agentDir, options) {
|
|
89
90
|
const rendered = renderProfile(projectRoot, agentDir, false, null, undefined, options);
|
|
91
|
+
return syncRenderedProfile(rendered);
|
|
92
|
+
}
|
|
93
|
+
function syncRenderedProfile(rendered) {
|
|
94
|
+
(0, config_tree_1.ensureConfigRootGitignore)(rendered.configRoot);
|
|
90
95
|
syncRuntimeDirs(rendered);
|
|
91
96
|
removeStaleGeneratedEntries(rendered);
|
|
92
97
|
for (const file of rendered.files) {
|
package/dist/templates.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createNunjucksEnv = createNunjucksEnv;
|
|
4
|
+
exports.createSkillNunjucksEnv = createSkillNunjucksEnv;
|
|
4
5
|
exports.buildRenderContext = buildRenderContext;
|
|
5
6
|
exports.resolveConfigPath = resolveConfigPath;
|
|
6
7
|
exports.renderTemplateFile = renderTemplateFile;
|
|
@@ -19,6 +20,33 @@ function createNunjucksEnv(configRoot) {
|
|
|
19
20
|
throwOnUndefined: true
|
|
20
21
|
});
|
|
21
22
|
}
|
|
23
|
+
function createSkillNunjucksEnv(configRoot, profileDir, trace) {
|
|
24
|
+
const roots = [path.join(configRoot, 'global', 'skills'), path.join(profileDir, 'skills')];
|
|
25
|
+
class SkillLoader extends nunjucks.Loader {
|
|
26
|
+
getSource(name) {
|
|
27
|
+
const target = path.resolve(configRoot, name);
|
|
28
|
+
if (!roots.some((root) => (0, utils_1.isSamePathOrDescendant)(target, root))) {
|
|
29
|
+
throw new Error(`Skill template must be inside an active skills directory: ${name}`);
|
|
30
|
+
}
|
|
31
|
+
let current = configRoot;
|
|
32
|
+
for (const part of path.relative(configRoot, target).split(path.sep).filter(Boolean)) {
|
|
33
|
+
current = path.join(current, part);
|
|
34
|
+
if (fs.lstatSync(current).isSymbolicLink()) {
|
|
35
|
+
throw new Error(`Symlinks are not supported in skill templates: ${current}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (fs.statSync(target).size > 1024 * 1024) {
|
|
39
|
+
throw new Error(`Skill template exceeds 1 MiB: ${target}`);
|
|
40
|
+
}
|
|
41
|
+
const src = fs.readFileSync(target, 'utf8');
|
|
42
|
+
trace?.sourceFiles.add(target);
|
|
43
|
+
return { src, path: target, noCache: true };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return new nunjucks.Environment(new SkillLoader(), {
|
|
47
|
+
autoescape: false, trimBlocks: true, lstripBlocks: true, throwOnUndefined: true
|
|
48
|
+
});
|
|
49
|
+
}
|
|
22
50
|
function buildRenderContext(projectRoot, profileDir, configRoot, manifest, env) {
|
|
23
51
|
const date = (0, utils_1.localDateString)();
|
|
24
52
|
const liveDir = path.join(profileDir, constants_1.LIVE_DIR_NAME);
|
|
@@ -84,8 +112,8 @@ function buildPermissionsAllow(manifest) {
|
|
|
84
112
|
}
|
|
85
113
|
return [...allow];
|
|
86
114
|
}
|
|
87
|
-
function resolveConfigPath(configRoot, relativePath, context) {
|
|
88
|
-
const rendered =
|
|
115
|
+
function resolveConfigPath(configRoot, relativePath, context, env) {
|
|
116
|
+
const rendered = env.renderString(relativePath, context);
|
|
89
117
|
const resolved = path.resolve(configRoot, rendered);
|
|
90
118
|
if (!(0, utils_1.isSamePathOrDescendant)(resolved, path.resolve(configRoot))) {
|
|
91
119
|
throw new Error(`config path escapes config root: ${relativePath}`);
|
|
@@ -97,20 +125,20 @@ function resolveRuntimePath(configRoot, pathTemplate, env, context) {
|
|
|
97
125
|
return path.isAbsolute(rendered) ? path.resolve(rendered) : path.resolve(configRoot, rendered);
|
|
98
126
|
}
|
|
99
127
|
function renderTemplateFile(env, configRoot, templatePath, context, trace) {
|
|
100
|
-
const resolvedPath = resolveConfigPath(configRoot, templatePath, context);
|
|
128
|
+
const resolvedPath = resolveConfigPath(configRoot, templatePath, context, env);
|
|
101
129
|
if (!fs.existsSync(resolvedPath)) {
|
|
102
130
|
throw new Error(`missing template: ${resolvedPath}`);
|
|
103
131
|
}
|
|
104
132
|
const relativePath = path.relative(configRoot, resolvedPath).replace(/\\/g, '/');
|
|
105
133
|
let content = fs.readFileSync(resolvedPath, 'utf8');
|
|
106
|
-
traceTemplateSource(configRoot, resolvedPath, content, context, trace);
|
|
134
|
+
traceTemplateSource(env, configRoot, resolvedPath, content, context, trace);
|
|
107
135
|
if (path.basename(resolvedPath) === 'AGENTS-MODS.md') {
|
|
108
136
|
content = renderLegacyAgentsMods(resolvedPath, [], trace);
|
|
109
137
|
return env.renderString(content, context);
|
|
110
138
|
}
|
|
111
139
|
return env.render(relativePath, context);
|
|
112
140
|
}
|
|
113
|
-
function traceTemplateSource(configRoot, sourcePath, content, context, trace, stack = []) {
|
|
141
|
+
function traceTemplateSource(env, configRoot, sourcePath, content, context, trace, stack = []) {
|
|
114
142
|
if (trace === undefined) {
|
|
115
143
|
return;
|
|
116
144
|
}
|
|
@@ -126,9 +154,9 @@ function traceTemplateSource(configRoot, sourcePath, content, context, trace, st
|
|
|
126
154
|
if (!includePath) {
|
|
127
155
|
continue;
|
|
128
156
|
}
|
|
129
|
-
const includedPath = resolveConfigPath(configRoot, includePath, context);
|
|
157
|
+
const includedPath = resolveConfigPath(configRoot, includePath, context, env);
|
|
130
158
|
if (fs.existsSync(includedPath)) {
|
|
131
|
-
traceTemplateSource(configRoot, includedPath, fs.readFileSync(includedPath, 'utf8'), context, trace, nextStack);
|
|
159
|
+
traceTemplateSource(env, configRoot, includedPath, fs.readFileSync(includedPath, 'utf8'), context, trace, nextStack);
|
|
132
160
|
}
|
|
133
161
|
}
|
|
134
162
|
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.packageVersion = packageVersion;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
let cached = null;
|
|
7
|
+
/**
|
|
8
|
+
* The package version, read from package.json next to the compiled output.
|
|
9
|
+
* This is the single source; nothing else in the tree hardcodes a version.
|
|
10
|
+
*/
|
|
11
|
+
function packageVersion() {
|
|
12
|
+
if (cached === null) {
|
|
13
|
+
try {
|
|
14
|
+
const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf8'));
|
|
15
|
+
cached = typeof pkg.version === 'string' && pkg.version ? pkg.version : '0.0.0';
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
cached = '0.0.0';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return cached;
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@technomoron/agent-run",
|
|
3
|
-
"version": "0.99.
|
|
3
|
+
"version": "0.99.33",
|
|
4
4
|
"packageManager": "pnpm@10.34.5",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-run": "dist/agent-run.js",
|
|
@@ -36,8 +36,7 @@
|
|
|
36
36
|
"test:integration": "bash ./scripts/test.sh",
|
|
37
37
|
"test:release": "bash ./scripts/test-release.sh",
|
|
38
38
|
"release": "bash ./scripts/release.sh",
|
|
39
|
-
"release:
|
|
40
|
-
"release:preflight": "pnpm cleanbuild && pnpm test && pnpm release:check -- --local",
|
|
39
|
+
"release:preflight": "pnpm cleanbuild && pnpm test",
|
|
41
40
|
"release:verify": "bash ./scripts/release-verify.sh"
|
|
42
41
|
},
|
|
43
42
|
"author": "Bjorn Erik Jacobsen",
|
|
@@ -19,7 +19,6 @@ USAGE
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
22
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
23
22
|
INSTALL_LIBEXEC_DIR="${INSTALL_LIBEXEC_DIR:-${INSTALL_LIB_DIR:-/usr/local/libexec/agent-run}}"
|
|
24
23
|
SYSTEMD_DIR="${SYSTEMD_DIR:-/etc/systemd/system}"
|
|
25
24
|
SYSTEMD_USER_DIR="${SYSTEMD_USER_DIR:-/etc/systemd/user}"
|
|
@@ -30,13 +29,7 @@ SERVICE_FILE="$ROOT/ops/systemd/ai-tools-update.service"
|
|
|
30
29
|
TIMER_FILE="$ROOT/ops/systemd/ai-tools-update.timer"
|
|
31
30
|
BRAIN_HELPER="$ROOT/scripts/ensure-agent-brain.sh"
|
|
32
31
|
BRAIN_SERVICE="$ROOT/ops/systemd/agent-brain.service"
|
|
33
|
-
|
|
34
|
-
UPDATE_SCRIPT="$SCRIPT_DIR/update-ai-tools.sh"
|
|
35
|
-
SERVICE_FILE="$SCRIPT_DIR/ai-tools-update.service"
|
|
36
|
-
TIMER_FILE="$SCRIPT_DIR/ai-tools-update.timer"
|
|
37
|
-
BRAIN_HELPER="$SCRIPT_DIR/ensure-agent-brain.sh"
|
|
38
|
-
BRAIN_SERVICE="$SCRIPT_DIR/agent-brain.service"
|
|
39
|
-
fi
|
|
32
|
+
|
|
40
33
|
|
|
41
34
|
INSTALL_AI_TOOLS=0
|
|
42
35
|
DRY_RUN=0
|