@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/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, command);
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.syncAgentProfile)(projectRoot, agentDir));
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.syncAgentProfile)(projectRoot, agentDir);
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, true);
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, false);
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, preferProjectConfigRoot) {
402
- const configRoot = (0, project_1.defaultConfigRoot)(projectRoot, { preferProjectRoot: preferProjectConfigRoot });
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 = (0, templates_1.renderTemplateFile)(env, configRoot, sourceTemplate, context, trace);
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) };
@@ -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.PACKAGE_VERSION = 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;
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
- ' commit|tag|push)',
40
- ' if [ "${AGENT_RUN_ALLOW_GIT_WRITE:-}" != "1" ]; then',
41
- ' echo "agent-run: blocked git $arg. Review and run it manually, or set AGENT_RUN_ALLOW_GIT_WRITE=1 for this invocation." >&2',
42
- ' exit 42',
43
- ' fi',
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
- `${executable} %*`,
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 && !readAgentRunEnv(projectRoot).AGENT_RUN_PROFILE?.trim()) {
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, options = {}) {
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: process.execPath,
34
- args: [path.join(__dirname, 'agent-brain.js'), 'mcp', '--configdir', configRoot, '--cwd', projectRoot, '--socket', (0, config_1.defaultSocketPath)(configRoot)],
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 = createNunjucksEnv(configRoot).renderString(relativePath, context);
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
  }
@@ -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
+ }
@@ -14,7 +14,7 @@
14
14
  "triage"
15
15
  ],
16
16
  "overrides": {
17
- "triage": "{{ profile }}/overrides/triage.SKILL.md.njk"
17
+ "triage": "{{ profile }}/skills/triage/SKILL.md.njk"
18
18
  }
19
19
  },
20
20
  "mcp": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/agent-run",
3
- "version": "0.99.31",
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:check": "bash ./scripts/release-check.sh",
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
- if [ ! -f "$UPDATE_SCRIPT" ]; then
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