@laitszkin/apollo-toolkit 3.2.2 → 3.3.1
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 +12 -4
- package/CHANGELOG.md +26 -2
- package/README.md +39 -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/katex/scripts/__pycache__/render_katex.cpython-312.pyc +0 -0
- package/lib/cli.js +260 -24
- package/lib/installer.js +181 -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/lib/installer.js
CHANGED
|
@@ -13,6 +13,7 @@ const TARGET_DEFINITIONS = Object.freeze([
|
|
|
13
13
|
const VALID_MODES = TARGET_DEFINITIONS.map(({ id }) => id);
|
|
14
14
|
const COPY_FILES = new Set(['AGENTS.md', 'CHANGELOG.md', 'LICENSE', 'README.md', 'package.json']);
|
|
15
15
|
const COPY_DIRS = new Set(['scripts']);
|
|
16
|
+
const MANIFEST_FILENAME = '.apollo-toolkit-manifest.json';
|
|
16
17
|
|
|
17
18
|
function resolveHomeDirectory(env = process.env) {
|
|
18
19
|
return env.HOME || env.USERPROFILE || os.homedir();
|
|
@@ -82,7 +83,6 @@ async function listSkillNames(rootDir, modes = []) {
|
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
// For codex mode, also include codex-specific skills
|
|
86
86
|
if (modes.includes('codex')) {
|
|
87
87
|
const codexDir = path.join(rootDir, 'codex');
|
|
88
88
|
if (fs.existsSync(codexDir)) {
|
|
@@ -111,8 +111,81 @@ async function listCodexSkillNames(rootDir) {
|
|
|
111
111
|
.sort();
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
// Read manifest from a target directory, returning { skills, historicalSkills, linkMode } or null.
|
|
115
|
+
async function readManifest(targetRoot) {
|
|
116
|
+
const manifestPath = path.join(targetRoot, MANIFEST_FILENAME);
|
|
117
|
+
try {
|
|
118
|
+
const raw = await fsp.readFile(manifestPath, 'utf8');
|
|
119
|
+
return JSON.parse(raw);
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isSafeSkillName(skillName) {
|
|
126
|
+
return typeof skillName === 'string'
|
|
127
|
+
&& skillName.length > 0
|
|
128
|
+
&& !skillName.includes('\0')
|
|
129
|
+
&& !skillName.includes('/')
|
|
130
|
+
&& !skillName.includes('\\')
|
|
131
|
+
&& !path.isAbsolute(skillName)
|
|
132
|
+
&& !path.win32.isAbsolute(skillName)
|
|
133
|
+
&& skillName !== '.'
|
|
134
|
+
&& skillName !== '..';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function getManifestSkillNames(manifest) {
|
|
138
|
+
return [...new Set([
|
|
139
|
+
...(Array.isArray(manifest.historicalSkills) ? manifest.historicalSkills : []),
|
|
140
|
+
...(Array.isArray(manifest.skills) ? manifest.skills : []),
|
|
141
|
+
])].filter(isSafeSkillName).sort();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Write manifest to a target directory.
|
|
145
|
+
async function writeManifest(targetRoot, { version, linkMode, skills, previousSkills = [] }) {
|
|
146
|
+
const historicalSkills = [...new Set([...previousSkills, ...skills])].sort();
|
|
147
|
+
const manifest = {
|
|
148
|
+
version,
|
|
149
|
+
installedAt: new Date().toISOString(),
|
|
150
|
+
linkMode,
|
|
151
|
+
skills: [...skills].sort(),
|
|
152
|
+
historicalSkills,
|
|
153
|
+
};
|
|
154
|
+
await fsp.mkdir(targetRoot, { recursive: true });
|
|
155
|
+
await fsp.writeFile(
|
|
156
|
+
path.join(targetRoot, MANIFEST_FILENAME),
|
|
157
|
+
`${JSON.stringify(manifest, null, 2)}\n`,
|
|
158
|
+
'utf8',
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Read all current + historically appeared skill names with deduplication.
|
|
163
|
+
async function listAllKnownSkillNames({ toolkitHome, modes = [], env = process.env }) {
|
|
164
|
+
const allNames = new Set();
|
|
165
|
+
|
|
166
|
+
// Current skills from toolkit home
|
|
167
|
+
const currentSkills = await listSkillNames(toolkitHome, modes).catch(() => []);
|
|
168
|
+
for (const name of currentSkills) {
|
|
169
|
+
allNames.add(name);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Historical skills from all target manifests
|
|
173
|
+
const targets = await getUninstallTargetRoots(modes, env);
|
|
174
|
+
for (const target of targets) {
|
|
175
|
+
const manifest = await readManifest(target.root);
|
|
176
|
+
if (manifest && manifest.historicalSkills) {
|
|
177
|
+
for (const name of getManifestSkillNames(manifest)) {
|
|
178
|
+
allNames.add(name);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return [...allNames].sort();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function getTargetSkillNames({ targetMode, sharedSkillNames, codexSkillNames, includeExclusiveSkills = false }) {
|
|
187
|
+
const includeCodexSkills = targetMode === 'codex' || includeExclusiveSkills;
|
|
188
|
+
if (!includeCodexSkills || codexSkillNames.length === 0) {
|
|
116
189
|
return sharedSkillNames;
|
|
117
190
|
}
|
|
118
191
|
|
|
@@ -289,6 +362,21 @@ async function getTargetRoots(modes, env = process.env) {
|
|
|
289
362
|
return targets;
|
|
290
363
|
}
|
|
291
364
|
|
|
365
|
+
async function getUninstallTargetRoots(modes = VALID_MODES, env = process.env) {
|
|
366
|
+
const targets = [];
|
|
367
|
+
|
|
368
|
+
for (const mode of normalizeModes(modes)) {
|
|
369
|
+
try {
|
|
370
|
+
targets.push(...await getTargetRoots([mode], env));
|
|
371
|
+
} catch {
|
|
372
|
+
// Uninstall is best-effort across agents. A missing OpenClaw workspace
|
|
373
|
+
// must not prevent cleanup from Codex, Trae, Agents, or Claude Code.
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return targets;
|
|
378
|
+
}
|
|
379
|
+
|
|
292
380
|
async function ensureDirectory(dirPath) {
|
|
293
381
|
await fsp.mkdir(dirPath, { recursive: true });
|
|
294
382
|
}
|
|
@@ -299,10 +387,23 @@ async function replaceWithCopy(sourcePath, targetPath) {
|
|
|
299
387
|
await fsp.cp(sourcePath, targetPath, { recursive: true, force: true });
|
|
300
388
|
}
|
|
301
389
|
|
|
302
|
-
async function
|
|
390
|
+
async function replaceWithSymlink(sourcePath, targetPath) {
|
|
391
|
+
await fsp.rm(targetPath, { recursive: true, force: true });
|
|
392
|
+
await ensureDirectory(path.dirname(targetPath));
|
|
393
|
+
await fsp.symlink(sourcePath, targetPath, process.platform === 'win32' ? 'junction' : 'dir');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Install skills into target directories.
|
|
397
|
+
// linkMode: 'copy' (default) or 'symlink'
|
|
398
|
+
// includeExclusiveSkills: when true, non-codex targets also receive codex-exclusive skills.
|
|
399
|
+
async function installLinks({ toolkitHome, modes, env = process.env, previousSkillNames = [], linkMode = 'copy', includeExclusiveSkills = false }) {
|
|
303
400
|
const normalizedModes = normalizeModes(modes);
|
|
401
|
+
// Always collect codex skill names (needed when includeExclusiveSkills is true even
|
|
402
|
+
// when codex isn't in the target list).
|
|
403
|
+
const codexSkillNames = (normalizedModes.includes('codex') || includeExclusiveSkills)
|
|
404
|
+
? await listCodexSkillNames(toolkitHome)
|
|
405
|
+
: [];
|
|
304
406
|
const sharedSkillNames = await listSkillNames(toolkitHome);
|
|
305
|
-
const codexSkillNames = normalizedModes.includes('codex') ? await listCodexSkillNames(toolkitHome) : [];
|
|
306
407
|
const skillNames = normalizedModes.includes('codex')
|
|
307
408
|
? [...new Set([...sharedSkillNames, ...codexSkillNames])].sort()
|
|
308
409
|
: sharedSkillNames;
|
|
@@ -314,8 +415,18 @@ async function installLinks({ toolkitHome, modes, env = process.env, previousSki
|
|
|
314
415
|
targetMode: target.mode,
|
|
315
416
|
sharedSkillNames,
|
|
316
417
|
codexSkillNames,
|
|
418
|
+
includeExclusiveSkills,
|
|
317
419
|
});
|
|
318
|
-
|
|
420
|
+
|
|
421
|
+
// Read existing manifest to carry forward historical skills
|
|
422
|
+
const existingManifest = await readManifest(target.root);
|
|
423
|
+
const allPreviousSkills = existingManifest
|
|
424
|
+
? [...new Set([...getManifestSkillNames(existingManifest), ...previousSkillNames.filter(isSafeSkillName)])]
|
|
425
|
+
: previousSkillNames.filter(isSafeSkillName);
|
|
426
|
+
|
|
427
|
+
const staleSkillNames = allPreviousSkills.filter(
|
|
428
|
+
(skillName) => !targetSkillNames.includes(skillName),
|
|
429
|
+
);
|
|
319
430
|
|
|
320
431
|
await ensureDirectory(target.root);
|
|
321
432
|
for (const staleSkillName of staleSkillNames) {
|
|
@@ -329,27 +440,89 @@ async function installLinks({ toolkitHome, modes, env = process.env, previousSki
|
|
|
329
440
|
codexSkillNames,
|
|
330
441
|
});
|
|
331
442
|
const targetPath = path.join(target.root, skillName);
|
|
332
|
-
|
|
333
|
-
|
|
443
|
+
|
|
444
|
+
if (linkMode === 'symlink') {
|
|
445
|
+
await replaceWithSymlink(sourcePath, targetPath);
|
|
446
|
+
} else {
|
|
447
|
+
await replaceWithCopy(sourcePath, targetPath);
|
|
448
|
+
}
|
|
449
|
+
copiedPaths.push({ target: target.label, path: targetPath, skillName, linkMode });
|
|
334
450
|
}
|
|
451
|
+
|
|
452
|
+
// Persist manifest for future uninstall / dedup
|
|
453
|
+
await writeManifest(target.root, {
|
|
454
|
+
version: existingManifest?.version || 'unknown',
|
|
455
|
+
linkMode,
|
|
456
|
+
skills: targetSkillNames,
|
|
457
|
+
previousSkills: allPreviousSkills,
|
|
458
|
+
});
|
|
335
459
|
}
|
|
336
460
|
|
|
337
461
|
return {
|
|
338
462
|
skillNames,
|
|
339
463
|
targets,
|
|
340
464
|
copiedPaths,
|
|
465
|
+
linkMode,
|
|
341
466
|
};
|
|
342
467
|
}
|
|
343
468
|
|
|
469
|
+
// Uninstall all skills from all target directories that have manifests.
|
|
470
|
+
async function uninstallSkills({ env = process.env, modes = null } = {}) {
|
|
471
|
+
const normalizedModes = modes ? normalizeModes(modes) : VALID_MODES;
|
|
472
|
+
const targets = await getUninstallTargetRoots(normalizedModes, env);
|
|
473
|
+
const results = [];
|
|
474
|
+
|
|
475
|
+
for (const target of targets) {
|
|
476
|
+
const manifest = await readManifest(target.root);
|
|
477
|
+
if (!manifest) {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const skillNames = getManifestSkillNames(manifest);
|
|
482
|
+
const removedSkills = [];
|
|
483
|
+
for (const skillName of skillNames) {
|
|
484
|
+
const skillPath = path.join(target.root, skillName);
|
|
485
|
+
try {
|
|
486
|
+
await fsp.rm(skillPath, { recursive: true, force: true });
|
|
487
|
+
removedSkills.push(skillName);
|
|
488
|
+
} catch {
|
|
489
|
+
// Skip skills that couldn't be removed
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Remove the manifest itself
|
|
494
|
+
try {
|
|
495
|
+
await fsp.rm(path.join(target.root, MANIFEST_FILENAME), { force: true });
|
|
496
|
+
} catch {
|
|
497
|
+
// ok if already gone
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
results.push({
|
|
501
|
+
target: target.label,
|
|
502
|
+
root: target.root,
|
|
503
|
+
removedSkills,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return results;
|
|
508
|
+
}
|
|
509
|
+
|
|
344
510
|
module.exports = {
|
|
345
511
|
expandUserPath,
|
|
346
512
|
TARGET_DEFINITIONS,
|
|
347
513
|
VALID_MODES,
|
|
514
|
+
MANIFEST_FILENAME,
|
|
348
515
|
getTargetRoots,
|
|
516
|
+
getUninstallTargetRoots,
|
|
349
517
|
installLinks,
|
|
518
|
+
listAllKnownSkillNames,
|
|
519
|
+
listCodexSkillNames,
|
|
350
520
|
listSkillNames,
|
|
351
521
|
normalizeModes,
|
|
522
|
+
readManifest,
|
|
352
523
|
resolveHomeDirectory,
|
|
353
524
|
resolveToolkitHome,
|
|
354
525
|
syncToolkitHome,
|
|
526
|
+
uninstallSkills,
|
|
527
|
+
writeManifest,
|
|
355
528
|
};
|
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|