@laitszkin/apollo-toolkit 3.2.1 → 3.3.0
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/AGENTS.md +11 -4
- package/CHANGELOG.md +19 -1
- package/README.md +35 -8
- package/analyse-app-logs/scripts/__pycache__/filter_logs_by_time.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/__pycache__/log_cli_utils.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/__pycache__/search_logs.cpython-312.pyc +0 -0
- package/docs-to-voice/scripts/__pycache__/docs_to_voice.cpython-312.pyc +0 -0
- package/generate-spec/scripts/__pycache__/create-specscpython-312.pyc +0 -0
- package/implement-specs-with-worktree/SKILL.md +3 -1
- package/katex/scripts/__pycache__/render_katex.cpython-312.pyc +0 -0
- package/lib/cli.js +190 -9
- package/lib/installer.js +147 -8
- package/open-github-issue/scripts/__pycache__/open_github_issue.cpython-312.pyc +0 -0
- package/package.json +1 -1
- package/read-github-issue/scripts/__pycache__/find_issues.cpython-312.pyc +0 -0
- package/read-github-issue/scripts/__pycache__/read_issue.cpython-312.pyc +0 -0
- package/resolve-review-comments/scripts/__pycache__/review_threads.cpython-312.pyc +0 -0
- package/scripts/install_skills.ps1 +488 -108
- package/scripts/install_skills.sh +429 -15
- package/text-to-short-video/scripts/__pycache__/enforce_video_aspect_ratio.cpython-312.pyc +0 -0
package/AGENTS.md
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
- This repository is a skill catalog: each top-level skill lives in its own directory and is installable when that directory contains `SKILL.md`.
|
|
6
6
|
- Typical skill layout is lightweight and consistent: `SKILL.md`, `README.md`, `LICENSE`, plus optional `agents/`, `references/`, and `scripts/`.
|
|
7
|
-
- The npm package exposes an `apollo-toolkit` CLI that stages a managed copy under `~/.apollo-toolkit` and copies each skill folder into selected target directories.
|
|
8
|
-
-
|
|
7
|
+
- The npm package exposes an `apollo-toolkit` CLI that stages a managed copy under `~/.apollo-toolkit` and copies or symlinks each skill folder into selected target directories.
|
|
8
|
+
- The installer writes a `.apollo-toolkit-manifest.json` per target directory to track installed skills, historical skill names, and install mode for future uninstall and deduplication.
|
|
9
|
+
- `scripts/install_skills.sh` and `scripts/install_skills.ps1` remain available for local/curl installs and mirror the managed-home install behavior with symlink/copy choice and uninstall support.
|
|
9
10
|
|
|
10
11
|
## Core Business Flow
|
|
11
12
|
|
|
@@ -20,7 +21,9 @@ This repository enables users to install and run a curated set of reusable agent
|
|
|
20
21
|
- Users can research a topic deeply and produce evidence-based deliverables.
|
|
21
22
|
- Users can research the latest completed market week and produce a PDF watchlist of tradeable instruments for the coming week.
|
|
22
23
|
- Users can turn a marked weekly finance PDF into a concise evidence-based financial event report.
|
|
23
|
-
- Users can install Apollo Toolkit through npm or npx and interactively choose one or more target skill directories to populate with copied skills.
|
|
24
|
+
- Users can install Apollo Toolkit through npm or npx and interactively choose one or more target skill directories to populate with copied or symlinked skills, with the option to include codex-exclusive skills in non-codex targets.
|
|
25
|
+
- Users can uninstall all Apollo Toolkit-installed skills from all targets or specific targets via `apltk uninstall`.
|
|
26
|
+
- Users can choose between symlink mode (auto-update via git pull) and copy mode (stable snapshot) with `--symlink` / `--copy` flags.
|
|
24
27
|
- Users can run bundled helper tools through `apltk tools` and direct `apltk <tool>` commands for selected packaged skill scripts.
|
|
25
28
|
- Users can design and implement new features through a spec-first workflow.
|
|
26
29
|
- Users can generate shared feature planning artifacts for approval-gated workflows, including parallel multi-spec batches coordinated through one batch-level `coordination.md`.
|
|
@@ -72,7 +75,11 @@ This repository enables users to install and run a curated set of reusable agent
|
|
|
72
75
|
- `python3 scripts/validate_skill_frontmatter.py` - 驗證所有頂層技能 `SKILL.md` 的 frontmatter。
|
|
73
76
|
- `python3 scripts/validate_openai_agent_config.py` - 驗證所有技能 `agents/openai.yaml` 設定。
|
|
74
77
|
- `./scripts/install_skills.sh codex` - 用本地安裝腳本把技能安裝到 Codex 目錄。
|
|
75
|
-
- `./scripts/install_skills.sh
|
|
78
|
+
- `./scripts/install_skills.sh codex --symlink` - 以 symlink 模式安裝(推薦)。
|
|
79
|
+
- `./scripts/install_skills.sh all --copy` - 以複製模式安裝到所有支援目標。
|
|
80
|
+
- `./scripts/install_skills.sh uninstall` - 從所有目標移除已安裝的技能。
|
|
81
|
+
- `./scripts/install_skills.sh uninstall codex` - 只從 codex 目標移除。
|
|
82
|
+
- `node bin/apollo-toolkit.js uninstall` - 透過 CLI 移除所有已安裝技能。
|
|
76
83
|
|
|
77
84
|
## Core Project Purpose
|
|
78
85
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,26 @@ All notable changes to this repository are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
### Added
|
|
8
|
+
- (None yet)
|
|
9
|
+
|
|
10
|
+
## [v3.3.0] - 2026-04-26
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Add `apltk uninstall` command to remove all installed skills from all targets (or specific targets) via manifest-based cleanup.
|
|
14
|
+
- Add symlink install mode (`--symlink`) so skills auto-update when `git pull` runs in `~/.apollo-toolkit`, removing the need to re-run the installer after patch updates.
|
|
15
|
+
- Add `--copy` flag to explicitly select copy mode when symlink is not desired.
|
|
16
|
+
- Add interactive prompt during install that explains symlink pros/cons and lets the user choose between symlink and copy mode.
|
|
17
|
+
- Add interactive prompt to optionally install codex-exclusive skills into non-codex targets during global install.
|
|
18
|
+
- Add `.apollo-toolkit-manifest.json` per target directory to track installed skills, historical skill names, and install mode for future uninstall and deduplication.
|
|
19
|
+
- Add `listAllKnownSkillNames()` to combine current and historically-appeared skill names with automatic deduplication.
|
|
20
|
+
- Add `uninstall` subcommand to `scripts/install_skills.sh` and `scripts/install_skills.ps1`.
|
|
21
|
+
- Add `--symlink` / `--copy` flags to both shell and PowerShell install scripts.
|
|
22
|
+
|
|
23
|
+
## [v3.2.2] - 2026-04-25
|
|
24
|
+
|
|
7
25
|
### Changed
|
|
8
|
-
-
|
|
26
|
+
- Tighten `implement-specs-with-worktree` so targeted Rust verification must avoid multi-filter `cargo test` invocations and rerun any zero-test selector before treating the worktree spec as validated.
|
|
9
27
|
|
|
10
28
|
## [v3.2.1] - 2026-04-24
|
|
11
29
|
|
package/README.md
CHANGED
|
@@ -65,9 +65,26 @@ The interactive installer:
|
|
|
65
65
|
- shows a branded `Apollo Toolkit` terminal welcome screen with a short staged reveal
|
|
66
66
|
- installs a managed copy into `~/.apollo-toolkit`
|
|
67
67
|
- lets you multi-select `codex`, `openclaw`, `trae`, `agents`, `claude-code`, or `all`
|
|
68
|
-
-
|
|
68
|
+
- asks whether to install skills as **symlinks** (recommended) or **file copies**
|
|
69
|
+
- lets you choose whether to include codex-exclusive skills in non-codex targets
|
|
70
|
+
- copies or symlinks `~/.apollo-toolkit/<skill>` into each selected target
|
|
69
71
|
- removes stale previously installed skill directories that existed in the previous installed version but no longer exist in the current package skill list
|
|
70
72
|
- replaces legacy symlink-based installs created by older Apollo Toolkit installers with real copied directories
|
|
73
|
+
- writes a manifest (`.apollo-toolkit-manifest.json`) per target for future uninstall and skill tracking
|
|
74
|
+
|
|
75
|
+
### Symlink vs Copy
|
|
76
|
+
|
|
77
|
+
| Mode | Pro | Con |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| **Symlink** (recommended) | Auto-updates when you `git pull` in `~/.apollo-toolkit`; no need to re-run installer after patch updates | Changes pushed to the repo automatically reflect in your skills — you may receive updates you did not intend to accept |
|
|
80
|
+
| **Copy** | Stable snapshot; won't change until you re-run the installer | Must manually re-run `apltk` after each toolkit update to get the latest skills |
|
|
81
|
+
|
|
82
|
+
### Uninstall
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
apltk uninstall # Remove all installed skills from all targets
|
|
86
|
+
apltk uninstall codex # Remove only from codex
|
|
87
|
+
```
|
|
71
88
|
|
|
72
89
|
### Global install
|
|
73
90
|
|
|
@@ -98,6 +115,13 @@ npx @laitszkin/apollo-toolkit codex openclaw
|
|
|
98
115
|
npx @laitszkin/apollo-toolkit all
|
|
99
116
|
```
|
|
100
117
|
|
|
118
|
+
Add `--symlink` (recommended) or `--copy` to skip the interactive prompt:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npx @laitszkin/apollo-toolkit codex --symlink
|
|
122
|
+
npx @laitszkin/apollo-toolkit all --copy
|
|
123
|
+
```
|
|
124
|
+
|
|
101
125
|
### Optional overrides
|
|
102
126
|
|
|
103
127
|
```bash
|
|
@@ -121,24 +145,27 @@ Installers still live in `scripts/` for local repository usage and curl / iwr in
|
|
|
121
145
|
```bash
|
|
122
146
|
./scripts/install_skills.sh
|
|
123
147
|
./scripts/install_skills.sh codex
|
|
124
|
-
./scripts/install_skills.sh
|
|
125
|
-
./scripts/install_skills.sh
|
|
126
|
-
./scripts/install_skills.sh
|
|
127
|
-
./scripts/install_skills.sh
|
|
148
|
+
./scripts/install_skills.sh codex --symlink
|
|
149
|
+
./scripts/install_skills.sh all --copy
|
|
150
|
+
./scripts/install_skills.sh uninstall
|
|
151
|
+
./scripts/install_skills.sh uninstall codex trae
|
|
128
152
|
```
|
|
129
153
|
|
|
130
154
|
```powershell
|
|
131
155
|
./scripts/install_skills.ps1
|
|
132
156
|
./scripts/install_skills.ps1 codex
|
|
133
|
-
./scripts/install_skills.ps1 agents
|
|
134
|
-
./scripts/install_skills.ps1 all
|
|
157
|
+
./scripts/install_skills.ps1 agents --symlink
|
|
158
|
+
./scripts/install_skills.ps1 all --copy
|
|
159
|
+
./scripts/install_skills.ps1 uninstall
|
|
160
|
+
./scripts/install_skills.ps1 uninstall codex trae
|
|
135
161
|
```
|
|
136
162
|
|
|
137
163
|
### Curl / iwr one-liners
|
|
138
164
|
|
|
139
165
|
```bash
|
|
140
166
|
curl -fsSL https://raw.githubusercontent.com/LaiTszKin/apollo-toolkit/main/scripts/install_skills.sh | bash
|
|
141
|
-
curl -fsSL https://raw.githubusercontent.com/LaiTszKin/apollo-toolkit/main/scripts/install_skills.sh | bash -s -- codex
|
|
167
|
+
curl -fsSL https://raw.githubusercontent.com/LaiTszKin/apollo-toolkit/main/scripts/install_skills.sh | bash -s -- codex --symlink
|
|
168
|
+
curl -fsSL https://raw.githubusercontent.com/LaiTszKin/apollo-toolkit/main/scripts/install_skills.sh | bash -s -- uninstall
|
|
142
169
|
```
|
|
143
170
|
|
|
144
171
|
```powershell
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -25,7 +25,7 @@ description: >-
|
|
|
25
25
|
|
|
26
26
|
- Evidence: Read and understand the complete specs set before starting implementation, identify the authoritative parent branch that the worktree should inherit from, verify whether the requested scope is already implemented on that parent branch or current main working tree, and when the requested plan path is missing from the current worktree verify where the authoritative copy actually lives before substituting any nearby spec.
|
|
27
27
|
- Execution: Create or use an isolated worktree for implementation only when the requested spec still needs work, sync the exact approved plan set into that worktree when it is missing there, create the worktree branch from the same parent branch as the worktree base, use the spec-set name as the canonical branch/worktree name, prefer direct `git` ref checks over brittle shell inference when deciding whether a branch or worktree already exists, and commit to a local branch when done.
|
|
28
|
-
- Quality: Complete all planned tasks, run relevant tests, backfill the spec documents with actual completion status, avoid dragging unrelated sibling specs into the worktree just because they share a batch directory, revert unrelated formatter-only noise outside the spec-owned scope before committing,
|
|
28
|
+
- Quality: Complete all planned tasks, run relevant tests, backfill the spec documents with actual completion status, avoid dragging unrelated sibling specs into the worktree just because they share a batch directory, revert unrelated formatter-only noise outside the spec-owned scope before committing, if branch/worktree creation reports ambiguous state re-check the actual git refs and worktree list before retrying, and when using targeted Rust `cargo test` selectors remember Cargo accepts only one positional test filter so each distinct selector needs its own confirmed command.
|
|
29
29
|
- Output: Keep the worktree branch clean with only the intended implementation commits.
|
|
30
30
|
|
|
31
31
|
## Goal
|
|
@@ -109,6 +109,8 @@ Use branch naming from `references/branch-naming.md`.
|
|
|
109
109
|
- E2E tests for key user-visible paths
|
|
110
110
|
- Adversarial tests for abuse paths
|
|
111
111
|
- Run relevant tests and fix failures.
|
|
112
|
+
- When using targeted Rust `cargo test` commands, pass at most one positional test filter per invocation; if multiple selectors are needed, run separate commands or a broader confirmed selector.
|
|
113
|
+
- Treat any targeted test command that executes zero tests as non-verification and rerun with a selector that proves the intended coverage actually ran.
|
|
112
114
|
- Do not skip testing even for seemingly small changes.
|
|
113
115
|
|
|
114
116
|
### 5) Backfill completion status
|
|
Binary file
|
package/lib/cli.js
CHANGED
|
@@ -6,9 +6,12 @@ const {
|
|
|
6
6
|
TARGET_DEFINITIONS,
|
|
7
7
|
VALID_MODES,
|
|
8
8
|
installLinks,
|
|
9
|
+
listAllKnownSkillNames,
|
|
10
|
+
listCodexSkillNames,
|
|
9
11
|
normalizeModes,
|
|
10
12
|
resolveToolkitHome,
|
|
11
13
|
syncToolkitHome,
|
|
14
|
+
uninstallSkills,
|
|
12
15
|
getTargetRoots,
|
|
13
16
|
} = require('./installer');
|
|
14
17
|
const { formatToolList, getToolCommand, runTool } = require('./tool-runner');
|
|
@@ -41,7 +44,7 @@ function color(text, code, enabled) {
|
|
|
41
44
|
return text;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
return
|
|
47
|
+
return `[${code}m${text}[0m`;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
function sleep(ms) {
|
|
@@ -134,6 +137,7 @@ function buildHelpText({ version, colorEnabled }) {
|
|
|
134
137
|
'Usage:',
|
|
135
138
|
` apltk [install] [${buildModeUsagePattern()}]...`,
|
|
136
139
|
` apollo-toolkit [install] [${buildModeUsagePattern()}]...`,
|
|
140
|
+
' apltk uninstall',
|
|
137
141
|
' apltk tools',
|
|
138
142
|
' apltk <tool> [...args]',
|
|
139
143
|
' apltk tools <tool> [...args]',
|
|
@@ -143,6 +147,7 @@ function buildHelpText({ version, colorEnabled }) {
|
|
|
143
147
|
'Examples:',
|
|
144
148
|
' apltk',
|
|
145
149
|
' apltk codex openclaw',
|
|
150
|
+
' apltk uninstall',
|
|
146
151
|
' npx @laitszkin/apollo-toolkit',
|
|
147
152
|
' npx @laitszkin/apollo-toolkit codex openclaw',
|
|
148
153
|
' npm i -g @laitszkin/apollo-toolkit',
|
|
@@ -194,8 +199,24 @@ function parseArguments(argv) {
|
|
|
194
199
|
toolkitHome: null,
|
|
195
200
|
toolName: null,
|
|
196
201
|
toolArgs: [],
|
|
202
|
+
linkMode: null, // 'copy' | 'symlink' | null (prompt)
|
|
197
203
|
};
|
|
198
204
|
|
|
205
|
+
if (args[0] === 'uninstall') {
|
|
206
|
+
result.command = 'uninstall';
|
|
207
|
+
args.shift();
|
|
208
|
+
// remaining args could be specific modes
|
|
209
|
+
while (args.length > 0) {
|
|
210
|
+
const arg = args.shift();
|
|
211
|
+
if (arg === '--help' || arg === '-h') {
|
|
212
|
+
result.showHelp = true;
|
|
213
|
+
} else {
|
|
214
|
+
result.modes.push(arg);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
|
|
199
220
|
if (args[0] === 'tools' || args[0] === 'tool') {
|
|
200
221
|
args.shift();
|
|
201
222
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
@@ -234,6 +255,16 @@ function parseArguments(argv) {
|
|
|
234
255
|
continue;
|
|
235
256
|
}
|
|
236
257
|
|
|
258
|
+
if (arg === '--symlink') {
|
|
259
|
+
result.linkMode = 'symlink';
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (arg === '--copy') {
|
|
264
|
+
result.linkMode = 'copy';
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
|
|
237
268
|
if (arg === 'install') {
|
|
238
269
|
continue;
|
|
239
270
|
}
|
|
@@ -246,7 +277,7 @@ function parseArguments(argv) {
|
|
|
246
277
|
|
|
247
278
|
function clearScreen(output) {
|
|
248
279
|
if (output.isTTY) {
|
|
249
|
-
output.write('
|
|
280
|
+
output.write('[2J[H');
|
|
250
281
|
}
|
|
251
282
|
}
|
|
252
283
|
|
|
@@ -315,20 +346,20 @@ async function promptForModes({ stdin, stdout, version, env }) {
|
|
|
315
346
|
|
|
316
347
|
const onData = (chunk) => {
|
|
317
348
|
const value = chunk.toString('utf8');
|
|
318
|
-
if (value === '
|
|
349
|
+
if (value === '') {
|
|
319
350
|
cleanup();
|
|
320
351
|
reject(new Error('Installation cancelled.'));
|
|
321
352
|
return;
|
|
322
353
|
}
|
|
323
354
|
|
|
324
|
-
if (value === '
|
|
355
|
+
if (value === '[A' || value === 'k') {
|
|
325
356
|
cursor = (cursor - 1 + TARGET_OPTIONS.length) % TARGET_OPTIONS.length;
|
|
326
357
|
message = '';
|
|
327
358
|
renderSelectionScreen({ output: stdout, version, cursor, selected, message, env });
|
|
328
359
|
return;
|
|
329
360
|
}
|
|
330
361
|
|
|
331
|
-
if (value === '
|
|
362
|
+
if (value === '[B' || value === 'j') {
|
|
332
363
|
cursor = (cursor + 1) % TARGET_OPTIONS.length;
|
|
333
364
|
message = '';
|
|
334
365
|
renderSelectionScreen({ output: stdout, version, cursor, selected, message, env });
|
|
@@ -349,7 +380,7 @@ async function promptForModes({ stdin, stdout, version, env }) {
|
|
|
349
380
|
return;
|
|
350
381
|
}
|
|
351
382
|
|
|
352
|
-
if (value.toLowerCase() === 'q' || value === '
|
|
383
|
+
if (value.toLowerCase() === 'q' || value === '') {
|
|
353
384
|
cleanup();
|
|
354
385
|
reject(new Error('Installation cancelled.'));
|
|
355
386
|
return;
|
|
@@ -374,11 +405,77 @@ async function promptForModes({ stdin, stdout, version, env }) {
|
|
|
374
405
|
});
|
|
375
406
|
}
|
|
376
407
|
|
|
377
|
-
async function
|
|
408
|
+
async function promptYesNo({ stdin, stdout, env, question, defaultYes = true }) {
|
|
409
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
410
|
+
return defaultYes;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
414
|
+
try {
|
|
415
|
+
const hint = defaultYes ? '[Y/n]' : '[y/N]';
|
|
416
|
+
const answer = await rl.question(`${question} ${hint} `);
|
|
417
|
+
const trimmed = answer.trim().toLowerCase();
|
|
418
|
+
if (trimmed === '') {
|
|
419
|
+
return defaultYes;
|
|
420
|
+
}
|
|
421
|
+
return trimmed === 'y' || trimmed === 'yes';
|
|
422
|
+
} finally {
|
|
423
|
+
rl.close();
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function buildSymlinkInfo({ colorEnabled }) {
|
|
428
|
+
return [
|
|
429
|
+
'',
|
|
430
|
+
color('Symlink mode:', '1', colorEnabled),
|
|
431
|
+
` ${color('Pro:', '1;32', colorEnabled)} Skills auto-update when you ${color('git pull', '1;33', colorEnabled)} in ~/.apollo-toolkit`,
|
|
432
|
+
` ${color('Pro:', '1;32', colorEnabled)} No need to re-run installer after patch updates`,
|
|
433
|
+
` ${color('Con:', '1;31', colorEnabled)} Changes pushed to the repo automatically reflect in your skills -`,
|
|
434
|
+
` you may receive updates you did not intend to accept`,
|
|
435
|
+
'',
|
|
436
|
+
].join('\n');
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async function promptSymlinkChoice({ stdin, stdout, env, colorEnabled }) {
|
|
440
|
+
stdout.write(buildSymlinkInfo({ colorEnabled }));
|
|
441
|
+
return promptYesNo({
|
|
442
|
+
stdin,
|
|
443
|
+
stdout,
|
|
444
|
+
env,
|
|
445
|
+
question: 'Install skills as symlinks (recommended)?',
|
|
446
|
+
defaultYes: true,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Ask user whether to include codex-exclusive skills in non-codex targets.
|
|
451
|
+
async function promptIncludeExclusiveSkills({ stdin, stdout, env, colorEnabled, codexSkillNames, nonCodexModes }) {
|
|
452
|
+
if (codexSkillNames.length === 0 || nonCodexModes.length === 0) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
stdout.write([
|
|
457
|
+
'',
|
|
458
|
+
color('Exclusive skills detected:', '1;33', colorEnabled),
|
|
459
|
+
` The following skills are exclusive to codex: ${codexSkillNames.join(', ')}`,
|
|
460
|
+
` Your selected non-codex targets: ${nonCodexModes.join(', ')}`,
|
|
461
|
+
'',
|
|
462
|
+
].join('\n'));
|
|
463
|
+
|
|
464
|
+
return promptYesNo({
|
|
465
|
+
stdin,
|
|
466
|
+
stdout,
|
|
467
|
+
env,
|
|
468
|
+
question: `Install codex-exclusive skills to ${nonCodexModes.join(', ')} as well?`,
|
|
469
|
+
defaultYes: false,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async function confirmInstall({ stdin, stdout, version, toolkitHome, modes, linkMode, env }) {
|
|
378
474
|
const colorEnabled = supportsColor(stdout, env);
|
|
379
475
|
stdout.write(`${buildBanner({ version, colorEnabled })}\n\n`);
|
|
380
476
|
stdout.write(`Apollo Toolkit home: ${toolkitHome}\n`);
|
|
381
|
-
stdout.write(`Targets: ${modes.join(', ')}\n
|
|
477
|
+
stdout.write(`Targets: ${modes.join(', ')}\n`);
|
|
478
|
+
stdout.write(`Install mode: ${linkMode === 'symlink' ? 'symlink (auto-update via git pull)' : 'copy (manual reinstall for updates)'}\n\n`);
|
|
382
479
|
|
|
383
480
|
const targets = await getTargetRoots(modes, env).catch((error) => {
|
|
384
481
|
throw error;
|
|
@@ -408,6 +505,7 @@ function printSummary({ stdout, version, toolkitHome, modes, installResult, env
|
|
|
408
505
|
stdout.write('\n');
|
|
409
506
|
stdout.write(`Apollo Toolkit home: ${toolkitHome}\n`);
|
|
410
507
|
stdout.write(`Installed skills: ${installResult.skillNames.length}\n`);
|
|
508
|
+
stdout.write(`Install mode: ${installResult.linkMode === 'symlink' ? 'symlink' : 'copy'}\n`);
|
|
411
509
|
stdout.write(`Targets: ${modes.join(', ')}\n\n`);
|
|
412
510
|
|
|
413
511
|
for (const target of installResult.targets) {
|
|
@@ -415,6 +513,22 @@ function printSummary({ stdout, version, toolkitHome, modes, installResult, env
|
|
|
415
513
|
}
|
|
416
514
|
}
|
|
417
515
|
|
|
516
|
+
function printUninstallSummary({ stdout, uninstallResult, env }) {
|
|
517
|
+
const colorEnabled = supportsColor(stdout, env);
|
|
518
|
+
|
|
519
|
+
if (uninstallResult.length === 0) {
|
|
520
|
+
stdout.write(color('No Apollo Toolkit installations found.\n', '1;33', colorEnabled));
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
stdout.write(color('Uninstall complete.', '1;32', colorEnabled));
|
|
525
|
+
stdout.write('\n\n');
|
|
526
|
+
for (const result of uninstallResult) {
|
|
527
|
+
stdout.write(`${color(result.target, '1', colorEnabled)} (${result.root})\n`);
|
|
528
|
+
stdout.write(` Removed: ${result.removedSkills.join(', ')}\n`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
418
532
|
async function run(argv, context = {}) {
|
|
419
533
|
const sourceRoot = context.sourceRoot || path.resolve(__dirname, '..');
|
|
420
534
|
const stdout = context.stdout || process.stdout;
|
|
@@ -425,14 +539,17 @@ async function run(argv, context = {}) {
|
|
|
425
539
|
|
|
426
540
|
try {
|
|
427
541
|
const parsed = parseArguments(argv);
|
|
542
|
+
|
|
428
543
|
if (parsed.showHelp) {
|
|
429
544
|
stdout.write(`${buildHelpText({ version: packageJson.version, colorEnabled: supportsColor(stdout, env) })}\n`);
|
|
430
545
|
return 0;
|
|
431
546
|
}
|
|
547
|
+
|
|
432
548
|
if (parsed.showToolsHelp) {
|
|
433
549
|
stdout.write(`${buildToolsHelp({ version: packageJson.version, colorEnabled: supportsColor(stdout, env) })}\n`);
|
|
434
550
|
return 0;
|
|
435
551
|
}
|
|
552
|
+
|
|
436
553
|
if (parsed.command === 'tool') {
|
|
437
554
|
return (context.runTool || runTool)(parsed.toolName, parsed.toolArgs, {
|
|
438
555
|
sourceRoot,
|
|
@@ -443,6 +560,39 @@ async function run(argv, context = {}) {
|
|
|
443
560
|
});
|
|
444
561
|
}
|
|
445
562
|
|
|
563
|
+
// --- Uninstall flow ---
|
|
564
|
+
if (parsed.command === 'uninstall') {
|
|
565
|
+
const toolkitHome = parsed.toolkitHome || resolveToolkitHome(env);
|
|
566
|
+
const modes = parsed.modes.length > 0 ? normalizeModes(parsed.modes) : null;
|
|
567
|
+
|
|
568
|
+
// Show what will be removed
|
|
569
|
+
const allKnown = await listAllKnownSkillNames({ toolkitHome, modes: modes || [], env });
|
|
570
|
+
stdout.write(color(`Apollo Toolkit home: ${toolkitHome}\n`, '2', supportsColor(stdout, env)));
|
|
571
|
+
|
|
572
|
+
const confirmed = await promptYesNo({
|
|
573
|
+
stdin,
|
|
574
|
+
stdout,
|
|
575
|
+
env,
|
|
576
|
+
question: `This will remove all Apollo Toolkit-installed skills${modes ? ` from: ${modes.join(', ')}` : ' from all targets'}. Continue?`,
|
|
577
|
+
defaultYes: false,
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
if (!confirmed) {
|
|
581
|
+
stdout.write('Uninstall cancelled.\n');
|
|
582
|
+
return 1;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const uninstallResult = await uninstallSkills({ env, modes });
|
|
586
|
+
printUninstallSummary({ stdout, uninstallResult, env });
|
|
587
|
+
|
|
588
|
+
if (allKnown.length > 0) {
|
|
589
|
+
stdout.write(`\nPreviously known skills (may still exist elsewhere): ${allKnown.join(', ')}\n`);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return 0;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// --- Install flow ---
|
|
446
596
|
const updateResult = await checkForPackageUpdate({
|
|
447
597
|
packageName: packageJson.name,
|
|
448
598
|
currentVersion: packageJson.version,
|
|
@@ -463,12 +613,39 @@ async function run(argv, context = {}) {
|
|
|
463
613
|
? normalizeModes(parsed.modes)
|
|
464
614
|
: normalizeModes(await promptForModes({ stdin, stdout, version: packageJson.version, env }));
|
|
465
615
|
|
|
616
|
+
const colorEnabled = supportsColor(stdout, env);
|
|
617
|
+
|
|
618
|
+
// Determine link mode
|
|
619
|
+
let linkMode = parsed.linkMode;
|
|
620
|
+
if (!linkMode) {
|
|
621
|
+
linkMode = (await promptSymlinkChoice({ stdin, stdout, env, colorEnabled })) ? 'symlink' : 'copy';
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// Determine whether to include exclusive (codex) skills in non-codex targets
|
|
625
|
+
const nonCodexModes = modes.filter((m) => m !== 'codex');
|
|
626
|
+
const codexSkillNames = await listCodexSkillNames(toolkitHome).catch(() => []);
|
|
627
|
+
const includeExclusiveSkills = await promptIncludeExclusiveSkills({
|
|
628
|
+
stdin,
|
|
629
|
+
stdout,
|
|
630
|
+
env,
|
|
631
|
+
colorEnabled,
|
|
632
|
+
codexSkillNames,
|
|
633
|
+
nonCodexModes,
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// syncToolkitHome needs to include the codex container when exclusive skills
|
|
637
|
+
// are requested, so the source files are available for symlink/copy.
|
|
638
|
+
const effectiveModes = includeExclusiveSkills
|
|
639
|
+
? [...new Set([...modes, 'codex'])]
|
|
640
|
+
: modes;
|
|
641
|
+
|
|
466
642
|
const confirmed = await confirmInstall({
|
|
467
643
|
stdin,
|
|
468
644
|
stdout,
|
|
469
645
|
version: packageJson.version,
|
|
470
646
|
toolkitHome,
|
|
471
647
|
modes,
|
|
648
|
+
linkMode,
|
|
472
649
|
env,
|
|
473
650
|
});
|
|
474
651
|
|
|
@@ -481,13 +658,15 @@ async function run(argv, context = {}) {
|
|
|
481
658
|
sourceRoot,
|
|
482
659
|
toolkitHome,
|
|
483
660
|
version: packageJson.version,
|
|
484
|
-
modes,
|
|
661
|
+
modes: effectiveModes,
|
|
485
662
|
});
|
|
486
663
|
|
|
487
664
|
const installResult = await installLinks({
|
|
488
665
|
toolkitHome,
|
|
489
666
|
modes,
|
|
490
667
|
previousSkillNames: syncResult.previousSkillNames,
|
|
668
|
+
linkMode,
|
|
669
|
+
includeExclusiveSkills,
|
|
491
670
|
env: {
|
|
492
671
|
...env,
|
|
493
672
|
APOLLO_TOOLKIT_HOME: toolkitHome,
|
|
@@ -509,6 +688,8 @@ module.exports = {
|
|
|
509
688
|
buildToolsHelp,
|
|
510
689
|
parseArguments,
|
|
511
690
|
promptForModes,
|
|
691
|
+
promptSymlinkChoice,
|
|
692
|
+
promptIncludeExclusiveSkills,
|
|
512
693
|
readPackageJson,
|
|
513
694
|
run,
|
|
514
695
|
};
|