td-ai-tools 1.0.6 → 1.0.7

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/README.md CHANGED
@@ -33,6 +33,9 @@ npx td-ai-tools install
33
33
  npx td-ai-tools install --all
34
34
  npx td-ai-tools install pr-solver
35
35
  npx td-ai-tools install pr-solver horizon-component-library
36
+ npx td-ai-tools update
37
+ npx td-ai-tools update --all
38
+ npx td-ai-tools update pr-solver
36
39
  ```
37
40
 
38
41
  The installer copies requested items into both agent layouts:
@@ -41,6 +44,8 @@ The installer copies requested items into both agent layouts:
41
44
 
42
45
  This keeps the installed assets available to both Claude-style and `.agents`-style project conventions.
43
46
 
47
+ `install` now errors when the target item already exists. Use `update` to replace an existing installed skill or agent pack.
48
+
44
49
  ## Local Verification
45
50
  Run the local smoke test to package the repo and verify installation into a throwaway project:
46
51
 
package/bin/cli.js CHANGED
@@ -44,7 +44,7 @@ function readFrontmatterField(mdPath, field) {
44
44
  return match ? match[1].trim() : '';
45
45
  }
46
46
 
47
- function installSkill(name) {
47
+ function installSkill(name, { replaceExisting = false } = {}) {
48
48
  const src = path.join(SKILLS_DIR, name);
49
49
  if (!fs.existsSync(src)) {
50
50
  console.error(` [error] Skill "${name}" not found.`);
@@ -52,13 +52,21 @@ function installSkill(name) {
52
52
  }
53
53
  for (const target of INSTALL_TARGETS) {
54
54
  const dest = path.join(TARGET_ROOT, target.root, 'skills', name);
55
+ if (fs.existsSync(dest) && !replaceExisting) {
56
+ console.error(` [error] Skill "${name}" already exists at ${target.root}/skills/${name}/ (use "update" to replace).`);
57
+ return false;
58
+ }
59
+ if (fs.existsSync(dest) && replaceExisting) {
60
+ fs.rmSync(dest, { recursive: true, force: true });
61
+ }
55
62
  copyDir(src, dest);
56
- console.log(` [skill] ${name} -> ${target.root}/skills/${name}/`);
63
+ const action = replaceExisting ? 'updated' : 'installed';
64
+ console.log(` [skill] ${name} ${action} -> ${target.root}/skills/${name}/`);
57
65
  }
58
66
  return true;
59
67
  }
60
68
 
61
- function installAgent(name) {
69
+ function installAgent(name, { replaceExisting = false } = {}) {
62
70
  const src = path.join(AGENTS_DIR, name);
63
71
  if (!fs.existsSync(src)) {
64
72
  console.error(` [error] Agent pack "${name}" not found.`);
@@ -66,8 +74,16 @@ function installAgent(name) {
66
74
  }
67
75
  for (const target of INSTALL_TARGETS) {
68
76
  const dest = path.join(TARGET_ROOT, target.root, 'agents', name);
77
+ if (fs.existsSync(dest) && !replaceExisting) {
78
+ console.error(` [error] Agent pack "${name}" already exists at ${target.root}/agents/${name}/ (use "update" to replace).`);
79
+ return false;
80
+ }
81
+ if (fs.existsSync(dest) && replaceExisting) {
82
+ fs.rmSync(dest, { recursive: true, force: true });
83
+ }
69
84
  copyDir(src, dest);
70
- console.log(` [agent] ${name} -> ${target.root}/agents/${name}/`);
85
+ const action = replaceExisting ? 'updated' : 'installed';
86
+ console.log(` [agent] ${name} ${action} -> ${target.root}/agents/${name}/`);
71
87
  }
72
88
  return true;
73
89
  }
@@ -97,14 +113,14 @@ function buildMenu() {
97
113
  return [...skills, ...agents];
98
114
  }
99
115
 
100
- function installItems(items) {
116
+ function installItems(items, options = {}) {
101
117
  for (const item of items) {
102
- if (item.type === 'skill') installSkill(item.name);
103
- else installAgent(item.name);
118
+ if (item.type === 'skill') installSkill(item.name, options);
119
+ else installAgent(item.name, options);
104
120
  }
105
121
  }
106
122
 
107
- async function interactiveInstall() {
123
+ async function interactiveInstall(mode = 'install') {
108
124
  const menu = buildMenu();
109
125
  if (menu.length === 0) {
110
126
  console.log('No skills or agent packs available.');
@@ -120,7 +136,7 @@ async function interactiveInstall() {
120
136
 
121
137
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
122
138
  return new Promise(resolve => {
123
- rl.question('Select items to install: ', answer => {
139
+ rl.question(`Select items to ${mode}: `, answer => {
124
140
  rl.close();
125
141
  const trimmed = answer.trim().toLowerCase();
126
142
  let selected;
@@ -131,7 +147,7 @@ async function interactiveInstall() {
131
147
  selected = indices.filter(i => i >= 0 && i < menu.length).map(i => menu[i]);
132
148
  }
133
149
  console.log('');
134
- installItems(selected);
150
+ installItems(selected, { replaceExisting: mode === 'update' });
135
151
  resolve();
136
152
  });
137
153
  });
@@ -164,6 +180,9 @@ Usage:
164
180
  npx td-ai-tools install Interactive install
165
181
  npx td-ai-tools install --all Install everything
166
182
  npx td-ai-tools install <name...> Install specific skills or agent packs
183
+ npx td-ai-tools update Interactive update (replaces existing items)
184
+ npx td-ai-tools update --all Update everything
185
+ npx td-ai-tools update <name...> Update specific skills or agent packs
167
186
 
168
187
  Skills are installed to: .claude/skills/<name>/
169
188
  .agents/skills/<name>/
@@ -178,7 +197,7 @@ Agent packs installed to: .claude/agents/<name>/
178
197
  console.log('------------');
179
198
 
180
199
  if (!cmd || cmd === 'install' && args.length === 1) {
181
- await interactiveInstall();
200
+ await interactiveInstall('install');
182
201
  return;
183
202
  }
184
203
 
@@ -199,6 +218,22 @@ Agent packs installed to: .claude/agents/<name>/
199
218
  return;
200
219
  }
201
220
 
221
+ if (cmd === 'update') {
222
+ const rest = args.slice(1);
223
+ if (rest.length === 0) {
224
+ await interactiveInstall('update');
225
+ return;
226
+ }
227
+ if (rest[0] === '--all') {
228
+ console.log('');
229
+ installItems(buildMenu(), { replaceExisting: true });
230
+ } else {
231
+ console.log('');
232
+ installItems(resolveNames(rest), { replaceExisting: true });
233
+ }
234
+ return;
235
+ }
236
+
202
237
  console.error(`Unknown command: "${cmd}". Run with --help for usage.`);
203
238
  process.exit(1);
204
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "td-ai-tools",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Install agent skills and packs into your project",
5
5
  "scripts": {
6
6
  "smoke:install": "./scripts/smoke-install.sh"
@@ -8,7 +8,7 @@ machine or one project clone location.
8
8
 
9
9
  - `config.toml.template` — the source of truth. Uses two placeholders:
10
10
  - `__PROJECT_ROOT__` — replaced with the absolute path to the repo root
11
- - `__CHROME_PATH__` — replaced with the absolute path to the Chrome/Chromium binary
11
+ - `__BROWSER_PATH__` — replaced with the absolute path to the Chromium/Chrome binary
12
12
  - `setup-codex.sh` — reads the template, substitutes the placeholders, writes
13
13
  `<repo>/.codex/config.toml`.
14
14
 
@@ -27,7 +27,7 @@ The script prints the values it resolved, e.g.:
27
27
  ```
28
28
  wrote /home/you/code/lio/.codex/config.toml
29
29
  PROJECT_ROOT=/home/you/code/lio
30
- CHROME_PATH=/usr/bin/google-chrome
30
+ BROWSER_PATH=/usr/bin/chromium
31
31
  ```
32
32
 
33
33
  Re-run it any time the template changes or you move the repo.
@@ -41,17 +41,19 @@ Re-run it any time the template changes or you move the repo.
41
41
  2. Falls back to walking three directories up from the script
42
42
  (`.agents/skills/playwright-cli` → repo root) if the repo isn't a git checkout
43
43
 
44
- **`CHROME_PATH`** — derived in this order:
44
+ **`BROWSER_PATH`** — derived in this order:
45
45
 
46
- 1. The `CHROME_PATH` environment variable, if set
47
- 2. First match from `PATH` of: `google-chrome`, `google-chrome-stable`, `chromium`,
48
- `chromium-browser`
49
- 3. Falls back to `/usr/bin/google-chrome` with a warning if nothing is found
46
+ 1. The `BROWSER_PATH` environment variable, if set
47
+ 2. The legacy `CHROME_PATH` environment variable, if set (kept for backwards compat)
48
+ 3. First match from `PATH` of: `chromium`, `chromium-browser`, `google-chrome`,
49
+ `google-chrome-stable` Chromium is preferred because Chrome is often missing
50
+ on WSL shells
51
+ 4. Falls back to `/usr/bin/chromium` with a warning if nothing is found
50
52
 
51
- Override the Chrome binary explicitly when needed:
53
+ Override the browser binary explicitly when needed:
52
54
 
53
55
  ```bash
54
- CHROME_PATH=/opt/google/chrome/chrome .agents/skills/playwright-cli/setup-codex.sh
56
+ BROWSER_PATH=/usr/bin/chromium .agents/skills/playwright-cli/setup-codex.sh
55
57
  ```
56
58
 
57
59
  ## Why a generator instead of variable expansion
@@ -158,6 +158,7 @@ playwright-cli video-stop video.webm
158
158
  ## Open parameters
159
159
  ```bash
160
160
  # Use specific browser when creating session
161
+ playwright-cli open --browser=chromium
161
162
  playwright-cli open --browser=chrome
162
163
  playwright-cli open --browser=firefox
163
164
  playwright-cli open --browser=webkit
@@ -19,10 +19,10 @@ inherit = "all"
19
19
 
20
20
  [shell_environment_policy.set]
21
21
  PLAYWRIGHT_BROWSERS_PATH = "__PROJECT_ROOT__/.artifacts/playwright/ms-playwright"
22
- PLAYWRIGHT_MCP_BROWSER = "chrome"
23
- PLAYWRIGHT_MCP_EXECUTABLE_PATH = "__CHROME_PATH__"
24
- PLAYWRIGHT_DAEMON_SOCKETS_DIR = "__PROJECT_ROOT__/.pw"
25
- BROWSER = "google-chrome"
22
+ PLAYWRIGHT_MCP_BROWSER = "chromium"
23
+ PLAYWRIGHT_MCP_EXECUTABLE_PATH = "__BROWSER_PATH__"
24
+ PLAYWRIGHT_DAEMON_SOCKETS_DIR = "__PROJECT_ROOT__/.tmp/codex-playwright/sockets"
25
+ BROWSER = "chromium"
26
26
  HOME = "__PROJECT_ROOT__/.tmp/codex-playwright/home"
27
27
  XDG_CONFIG_HOME = "__PROJECT_ROOT__/.tmp/codex-playwright/config"
28
28
  XDG_STATE_HOME = "__PROJECT_ROOT__/.tmp/codex-playwright/state"
@@ -11,19 +11,19 @@ else
11
11
  fi
12
12
  OUTPUT="$PROJECT_ROOT/.codex/config.toml"
13
13
 
14
- CHROME_PATH="${CHROME_PATH:-$(command -v google-chrome || command -v google-chrome-stable || command -v chromium || command -v chromium-browser || true)}"
15
- if [ -z "$CHROME_PATH" ]; then
16
- echo "warning: no Chrome/Chromium binary found on PATH; set CHROME_PATH=/path/to/chrome and rerun" >&2
17
- CHROME_PATH="/usr/bin/google-chrome"
14
+ BROWSER_PATH="${BROWSER_PATH:-${CHROME_PATH:-$(command -v chromium || command -v chromium-browser || command -v google-chrome || command -v google-chrome-stable || true)}}"
15
+ if [ -z "$BROWSER_PATH" ]; then
16
+ echo "warning: no Chromium/Chrome binary found on PATH; set BROWSER_PATH=/path/to/browser and rerun" >&2
17
+ BROWSER_PATH="/usr/bin/chromium"
18
18
  fi
19
19
 
20
20
  mkdir -p "$(dirname "$OUTPUT")"
21
21
 
22
22
  sed \
23
23
  -e "s|__PROJECT_ROOT__|$PROJECT_ROOT|g" \
24
- -e "s|__CHROME_PATH__|$CHROME_PATH|g" \
24
+ -e "s|__BROWSER_PATH__|$BROWSER_PATH|g" \
25
25
  "$TEMPLATE" > "$OUTPUT"
26
26
 
27
27
  echo "wrote $OUTPUT"
28
28
  echo " PROJECT_ROOT=$PROJECT_ROOT"
29
- echo " CHROME_PATH=$CHROME_PATH"
29
+ echo " BROWSER_PATH=$BROWSER_PATH"