@technomoron/agent-run 0.99.19 → 0.99.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGES CHANGED
@@ -1,6 +1,17 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ Version 0.99.21 (2026-06-27)
5
+ ----------------------------
6
+ * Default project commands for `[code]/owner/repo` checkouts to `[code]/agent-config`.
7
+ * Make `update --all` map profiles under a colocated `agent-config` root back to their matching project roots.
8
+ * Expand integration coverage for the colocated config-root layout and Windows command/path behavior.
9
+
10
+ Version 0.99.20 (2026-06-03)
11
+ ----------------------------
12
+ * Add systemd unit templates and install tooling for the global AI tools updater.
13
+ * Add a login warning helper that prints a large banner when `~/.agent-config` has uncommitted changes.
14
+
4
15
  Version 0.99.19 (2026-06-03)
5
16
  ----------------------------
6
17
  * Link per-profile Codex `auth.json` files to the shared `~/.codex/auth.json` login cache when available.
package/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  Small wrapper for AI coding CLIs like Codex and Claude.
4
4
 
5
5
  It keeps agent files out of normal repos and stores them in a separate
6
- agent config tree. That tree can live anywhere; it does not need to sit
7
- inside the source tree.
6
+ agent config tree. By default, that tree lives beside owner/repo checkouts
7
+ under the same code root.
8
8
 
9
9
  ## Model
10
10
 
@@ -18,27 +18,26 @@ Example:
18
18
 
19
19
  ```text
20
20
  ~/source/
21
+ agent-config/
22
+ org/
23
+ my-api/
24
+ agent-run.jsonc
25
+ local.md.njk
26
+ overrides/
27
+ AGENTS.md
28
+ CLAUDE.md
29
+ config.toml
30
+ .agents/
31
+ .claude/
32
+ bin/
21
33
  org/
22
34
  my-api/
23
-
24
- ~/.agent-config/
25
- org/
26
- my-api/
27
- agent-run.jsonc
28
- local.md.njk
29
- overrides/
30
- AGENTS.md
31
- CLAUDE.md
32
- config.toml
33
- .agents/
34
- .claude/
35
- bin/
36
35
  ```
37
36
 
38
- If your source repo is `~/source/org/my-api`, `agent-run` can map it to:
37
+ If your source repo is `~/source/org/my-api`, `agent-run` maps it to:
39
38
 
40
39
  ```text
41
- ~/.agent-config/org/my-api
40
+ ~/source/agent-config/org/my-api
42
41
  ```
43
42
 
44
43
  The source repo stays clean. The agent files live in the matching path under
@@ -93,7 +92,7 @@ AGENT_RUN_PROFILE=org/my-api
93
92
 
94
93
  Config root:
95
94
 
96
- - default: `~/.agent-config`
95
+ - default for a project at `[code]/owner/repo`: `[code]/agent-config`
97
96
  - override with `--config-root /path/to/agent-configs`
98
97
  - override with `AGENT_CONFIG_DIR=/path/to/agent-configs`
99
98
  - override with `AGENT_CONFIG_ROOT=/path/to/agent-configs`
@@ -169,7 +168,8 @@ agent-run update --all ~/.agent-config
169
168
  ```
170
169
 
171
170
  If the config root argument is omitted, `update --all` uses the normal configured
172
- root such as `$HOME/.agent-config`.
171
+ root. Without a project path, that falls back to `$HOME/.agent-config`; for
172
+ project commands, the default is `[code]/agent-config`.
173
173
 
174
174
  You can also generate from a tool command and stop before launch:
175
175
 
@@ -255,6 +255,40 @@ review files into `reviews/`, moves loose `memory*.md` files into `memories/`,
255
255
  and moves old Codex runtime files into `memories/codex-home` when doing so does
256
256
  not overwrite existing files.
257
257
 
258
+ ## Systemd Jobs
259
+
260
+ The repo includes optional systemd units for keeping global AI tooling current.
261
+
262
+ Install the global AI tools updater:
263
+
264
+ ```sh
265
+ sudo scripts/install-systemd-jobs.sh --ai-tools
266
+ ```
267
+
268
+ This installs and enables `ai-tools-update.timer`, which runs hourly. The
269
+ package list is configurable through systemd environment overrides:
270
+
271
+ ```text
272
+ AI_TOOLS_NPM_PACKAGES="npm pnpm netlify-cli@latest @openai/codex@latest @anthropic-ai/claude-code@latest @technomoron/agent-run@latest @technomoron/repo-check@latest"
273
+ AI_TOOLS_APT_PACKAGES="gh"
274
+ ```
275
+
276
+ ## Login Warning
277
+
278
+ For user-owned machines, `scripts/agent-config-login-warning.sh` can be called
279
+ from a shell startup file to print a large warning when `~/.agent-config` is a
280
+ dirty git checkout:
281
+
282
+ ```csh
283
+ if ( -x "$HOME/bin/agent-config-login-warning" ) then
284
+ "$HOME/bin/agent-config-login-warning"
285
+ endif
286
+ ```
287
+
288
+ The helper only reads the git status and exits quietly when the checkout is
289
+ clean or absent. Set `AGENT_CONFIG_TARGET` before calling it to check a
290
+ different config tree.
291
+
258
292
  ## Install
259
293
 
260
294
  ```sh
package/dist/agent-run.js CHANGED
@@ -675,7 +675,7 @@ function runUpdateAll(targetPath) {
675
675
  let updated = 0;
676
676
  for (const agentDir of profileDirs) {
677
677
  const profile = path.relative(configRoot, agentDir).replace(/\\/g, '/');
678
- const projectRoot = projectRootForProfile(profile);
678
+ const projectRoot = projectRootForProfile(profile, configRoot);
679
679
  verbose(`update --all profile=${profile} syntheticProjectRoot=${projectRoot}`);
680
680
  ensureProfileOverridesDir(agentDir);
681
681
  convertLegacyProfileIfNeeded(configRoot, agentDir, profile);
@@ -2186,7 +2186,10 @@ function parseProfile(profile, source) {
2186
2186
  }
2187
2187
  return { profile: segments.join('/'), reason: '' };
2188
2188
  }
2189
- function projectRootForProfile(profile) {
2189
+ function projectRootForProfile(profile, configRoot) {
2190
+ if (configRoot && path.basename(configRoot) === 'agent-config') {
2191
+ return path.join(path.dirname(configRoot), ...profile.split('/'));
2192
+ }
2190
2193
  return path.join(os.homedir(), ...profile.split('/'));
2191
2194
  }
2192
2195
  function readAgentRunEnv(dir) {
@@ -2251,8 +2254,20 @@ function defaultConfigRoot(projectRoot) {
2251
2254
  return path.resolve(projectRoot, localConfigRoot);
2252
2255
  }
2253
2256
  }
2257
+ if (projectRoot) {
2258
+ return defaultCodeConfigRoot(projectRoot);
2259
+ }
2254
2260
  return path.join(os.homedir(), '.agent-config');
2255
2261
  }
2262
+ function defaultCodeConfigRoot(projectRoot) {
2263
+ const resolvedProjectRoot = path.resolve(projectRoot);
2264
+ const ownerDir = path.dirname(resolvedProjectRoot);
2265
+ const codeRoot = path.dirname(ownerDir);
2266
+ if (ownerDir === resolvedProjectRoot || codeRoot === ownerDir) {
2267
+ return path.join(os.homedir(), '.agent-config');
2268
+ }
2269
+ return path.join(codeRoot, 'agent-config');
2270
+ }
2256
2271
  function findRealBinary(tool) {
2257
2272
  const pathValue = process.env.PATH || '';
2258
2273
  const pathDirs = pathValue.split(path.delimiter).filter((entry) => entry.length > 0);
@@ -0,0 +1,11 @@
1
+ [Unit]
2
+ Description=Update global AI and developer CLI packages
3
+ After=network-online.target
4
+ Wants=network-online.target
5
+
6
+ [Service]
7
+ Type=oneshot
8
+ Environment=HOME=/root
9
+ Environment=NPM_CONFIG_PREFIX=/usr
10
+ Environment=PNPM_HOME=/usr/local/bin
11
+ ExecStart=/usr/local/lib/agent-run/update-ai-tools.sh
@@ -0,0 +1,11 @@
1
+ [Unit]
2
+ Description=Run AI tool updater hourly
3
+
4
+ [Timer]
5
+ OnBootSec=10m
6
+ OnUnitActiveSec=1h
7
+ AccuracySec=5m
8
+ Unit=ai-tools-update.service
9
+
10
+ [Install]
11
+ WantedBy=timers.target
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/agent-run",
3
- "version": "0.99.19",
3
+ "version": "0.99.21",
4
4
  "packageManager": "pnpm@10.28.1",
5
5
  "bin": {
6
6
  "agent-run": "dist/agent-run.js"
@@ -8,6 +8,10 @@
8
8
  "files": [
9
9
  "dist/",
10
10
  "examples/",
11
+ "ops/",
12
+ "scripts/agent-config-login-warning.sh",
13
+ "scripts/install-systemd-jobs.sh",
14
+ "scripts/update-ai-tools.sh",
11
15
  "README.md",
12
16
  "LICENSE",
13
17
  "CHANGES"
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env sh
2
+ set -u
3
+
4
+ target="${AGENT_CONFIG_TARGET:-$HOME/.agent-config}"
5
+
6
+ [ -d "$target/.git" ] || exit 0
7
+ command -v git >/dev/null 2>&1 || exit 0
8
+
9
+ status="$(git -C "$target" status --short 2>/dev/null)" || exit 0
10
+ [ -n "$status" ] || exit 0
11
+
12
+ cat <<'BANNER'
13
+
14
+ ###############################################################################
15
+ ###############################################################################
16
+ ## ##
17
+ ## WARNING: ~/.agent-config HAS UNCOMMITTED LOCAL CHANGES ##
18
+ ## ##
19
+ ## agent-run config updates should not pull over this tree. ##
20
+ ## Commit, stash, or remove these changes before updating configs. ##
21
+ ## ##
22
+ ###############################################################################
23
+ ###############################################################################
24
+
25
+ BANNER
26
+
27
+ printf '%s\n' "$status" | sed 's/^/ /'
28
+ printf '\n'
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ usage() {
5
+ cat <<'USAGE'
6
+ Usage:
7
+ install-systemd-jobs.sh [options]
8
+
9
+ Options:
10
+ --ai-tools Install and enable ai-tools-update.timer.
11
+ --all Install all repo-provided systemd jobs.
12
+ --dry-run Print actions without writing system files.
13
+ -h, --help Show this help.
14
+
15
+ Examples:
16
+ sudo scripts/install-systemd-jobs.sh --ai-tools
17
+ sudo scripts/install-systemd-jobs.sh --all
18
+ USAGE
19
+ }
20
+
21
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
22
+ INSTALL_LIB_DIR="${INSTALL_LIB_DIR:-/usr/local/lib/agent-run}"
23
+ SYSTEMD_DIR="${SYSTEMD_DIR:-/etc/systemd/system}"
24
+ ORIGINAL_ARGS=("$@")
25
+
26
+ INSTALL_AI_TOOLS=0
27
+ INSTALL_ALL=0
28
+ DRY_RUN=0
29
+
30
+ while [ "$#" -gt 0 ]; do
31
+ case "$1" in
32
+ --ai-tools)
33
+ INSTALL_AI_TOOLS=1
34
+ shift
35
+ ;;
36
+ --all)
37
+ INSTALL_ALL=1
38
+ INSTALL_AI_TOOLS=1
39
+ shift
40
+ ;;
41
+ --dry-run)
42
+ DRY_RUN=1
43
+ shift
44
+ ;;
45
+ -h|--help)
46
+ usage
47
+ exit 0
48
+ ;;
49
+ *)
50
+ echo "Unknown option: $1" >&2
51
+ usage >&2
52
+ exit 2
53
+ ;;
54
+ esac
55
+ done
56
+
57
+ if [ "$INSTALL_AI_TOOLS" -eq 0 ]; then
58
+ usage >&2
59
+ exit 2
60
+ fi
61
+
62
+ if [ "$DRY_RUN" -eq 0 ] && [ "${EUID:-$(id -u)}" -ne 0 ]; then
63
+ exec sudo "$0" "${ORIGINAL_ARGS[@]}"
64
+ fi
65
+
66
+ run() {
67
+ if [ "$DRY_RUN" -eq 1 ]; then
68
+ printf '+'
69
+ printf ' %q' "$@"
70
+ printf '\n'
71
+ return 0
72
+ fi
73
+ "$@"
74
+ }
75
+
76
+ run install -d -m 0755 "$INSTALL_LIB_DIR" "$SYSTEMD_DIR"
77
+ run install -m 0755 "$ROOT/scripts/update-ai-tools.sh" "$INSTALL_LIB_DIR/update-ai-tools.sh"
78
+ run install -m 0644 "$ROOT/ops/systemd/ai-tools-update.service" "$SYSTEMD_DIR/ai-tools-update.service"
79
+ run install -m 0644 "$ROOT/ops/systemd/ai-tools-update.timer" "$SYSTEMD_DIR/ai-tools-update.timer"
80
+
81
+ if [ "$INSTALL_AI_TOOLS" -eq 1 ]; then
82
+ run systemctl daemon-reload
83
+ run systemctl enable --now ai-tools-update.timer
84
+ fi
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ export HOME="${HOME:-/root}"
5
+ export NPM_CONFIG_PREFIX="${NPM_CONFIG_PREFIX:-/usr}"
6
+ export PNPM_HOME="${PNPM_HOME:-/usr/local/bin}"
7
+ export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH:-}"
8
+
9
+ NPM_BIN="${AI_TOOLS_NPM_BIN:-/usr/bin/npm}"
10
+ APT_GET_BIN="${AI_TOOLS_APT_GET_BIN:-/usr/bin/apt-get}"
11
+
12
+ AI_TOOLS_NPM_PACKAGES="${AI_TOOLS_NPM_PACKAGES:-npm pnpm netlify-cli@latest @openai/codex@latest @anthropic-ai/claude-code@latest @technomoron/agent-run@latest @technomoron/repo-check@latest}"
13
+ AI_TOOLS_APT_PACKAGES="${AI_TOOLS_APT_PACKAGES:-gh}"
14
+
15
+ if [ -n "$AI_TOOLS_NPM_PACKAGES" ]; then
16
+ # shellcheck disable=SC2086
17
+ "$NPM_BIN" install -g --force $AI_TOOLS_NPM_PACKAGES
18
+ fi
19
+
20
+ if [ -n "$AI_TOOLS_APT_PACKAGES" ] && command -v "$APT_GET_BIN" >/dev/null 2>&1; then
21
+ # shellcheck disable=SC2086
22
+ "$APT_GET_BIN" install --only-upgrade -y $AI_TOOLS_APT_PACKAGES
23
+ fi