@rpamis/comet 0.4.0-beta.4 → 0.4.0-beta.6
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/LICENSE +21 -21
- package/README.md +11 -4
- package/assets/manifest.json +1 -1
- package/assets/skills/comet/SKILL.md +30 -28
- package/assets/skills/comet/reference/auto-transition.md +1 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +8 -4
- package/assets/skills/comet/reference/context-recovery.md +2 -2
- package/assets/skills/comet/reference/decision-point.md +11 -0
- package/assets/skills/comet/reference/subagent-dispatch.md +6 -5
- package/assets/skills/comet/rules/comet-phase-guard.en.md +23 -28
- package/assets/skills/comet/rules/comet-phase-guard.md +22 -28
- package/assets/skills/comet/scripts/comet-runtime.mjs +682 -309
- package/assets/skills/comet-any/SKILL.md +1 -1
- package/assets/skills/comet-any/reference/authored-zone-example.md +10 -5
- package/assets/skills/comet-any/reference/subagents/pause-points-author.md +14 -11
- package/assets/skills/comet-any/reference/subagents/skill-reviewer.md +2 -0
- package/assets/skills/comet-any/reference/subagents/workflow-entry-author.md +5 -4
- package/assets/skills/comet-archive/SKILL.md +33 -13
- package/assets/skills/comet-build/SKILL.md +37 -29
- package/assets/skills/comet-design/SKILL.md +23 -22
- package/assets/skills/comet-hotfix/SKILL.md +46 -31
- package/assets/skills/comet-open/SKILL.md +97 -58
- package/assets/skills/comet-tweak/SKILL.md +34 -19
- package/assets/skills/comet-verify/SKILL.md +37 -59
- package/assets/skills-zh/comet/SKILL.md +30 -28
- package/assets/skills-zh/comet/reference/auto-transition.md +1 -1
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +8 -4
- package/assets/skills-zh/comet/reference/context-recovery.md +2 -2
- package/assets/skills-zh/comet/reference/decision-point.md +11 -0
- package/assets/skills-zh/comet/reference/subagent-dispatch.md +6 -5
- package/assets/skills-zh/comet-any/SKILL.md +1 -1
- package/assets/skills-zh/comet-any/reference/authored-zone-example.md +10 -5
- package/assets/skills-zh/comet-any/reference/subagents/pause-points-author.md +14 -12
- package/assets/skills-zh/comet-any/reference/subagents/skill-reviewer.md +2 -0
- package/assets/skills-zh/comet-any/reference/subagents/workflow-entry-author.md +5 -4
- package/assets/skills-zh/comet-archive/SKILL.md +33 -13
- package/assets/skills-zh/comet-build/SKILL.md +37 -29
- package/assets/skills-zh/comet-design/SKILL.md +23 -22
- package/assets/skills-zh/comet-hotfix/SKILL.md +45 -30
- package/assets/skills-zh/comet-open/SKILL.md +96 -57
- package/assets/skills-zh/comet-tweak/SKILL.md +33 -18
- package/assets/skills-zh/comet-verify/SKILL.md +37 -59
- package/dist/app/commands/doctor.d.ts.map +1 -1
- package/dist/app/commands/doctor.js +62 -15
- package/dist/app/commands/doctor.js.map +1 -1
- package/dist/app/commands/init.d.ts +1 -1
- package/dist/app/commands/init.d.ts.map +1 -1
- package/dist/app/commands/init.js +58 -14
- package/dist/app/commands/init.js.map +1 -1
- package/dist/app/commands/status.d.ts +1 -0
- package/dist/app/commands/status.d.ts.map +1 -1
- package/dist/app/commands/status.js +10 -0
- package/dist/app/commands/status.js.map +1 -1
- package/dist/app/commands/uninstall.d.ts +3 -0
- package/dist/app/commands/uninstall.d.ts.map +1 -1
- package/dist/app/commands/uninstall.js +70 -36
- package/dist/app/commands/uninstall.js.map +1 -1
- package/dist/app/commands/update.d.ts.map +1 -1
- package/dist/app/commands/update.js +213 -34
- package/dist/app/commands/update.js.map +1 -1
- package/dist/domains/bundle/bundle-platform.d.ts +1 -0
- package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
- package/dist/domains/bundle/bundle-platform.js +6 -2
- package/dist/domains/bundle/bundle-platform.js.map +1 -1
- package/dist/domains/comet-classic/classic-branch-binding.d.ts +51 -0
- package/dist/domains/comet-classic/classic-branch-binding.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-branch-binding.js +107 -0
- package/dist/domains/comet-classic/classic-branch-binding.js.map +1 -0
- package/dist/domains/comet-classic/classic-current-change.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-current-change.js +37 -20
- package/dist/domains/comet-classic/classic-current-change.js.map +1 -1
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-guard.js +50 -16
- package/dist/domains/comet-classic/classic-guard.js.map +1 -1
- package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-hook-guard.js +138 -21
- package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -1
- package/dist/domains/comet-classic/classic-resolver.js +1 -1
- package/dist/domains/comet-classic/classic-resolver.js.map +1 -1
- package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state-command.js +113 -14
- package/dist/domains/comet-classic/classic-state-command.js.map +1 -1
- package/dist/domains/comet-classic/classic-state-events.d.ts +1 -1
- package/dist/domains/comet-classic/classic-state-events.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state.d.ts +4 -2
- package/dist/domains/comet-classic/classic-state.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state.js +16 -1
- package/dist/domains/comet-classic/classic-state.js.map +1 -1
- package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-transitions.js +17 -2
- package/dist/domains/comet-classic/classic-transitions.js.map +1 -1
- package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-validate-command.js +13 -1
- package/dist/domains/comet-classic/classic-validate-command.js.map +1 -1
- package/dist/domains/dashboard/web/assets/_commonjsHelpers-CqkleIqs.js +1 -0
- package/dist/domains/dashboard/web/assets/arc-TGVUG2WN.js +1 -0
- package/dist/domains/dashboard/web/assets/architectureDiagram-3BPJPVTR-ASHmiHoP.js +36 -0
- package/dist/domains/dashboard/web/assets/blockDiagram-GPEHLZMM-CwASxBKe.js +132 -0
- package/dist/domains/dashboard/web/assets/c4Diagram-AAUBKEIU-BU8z_WNk.js +10 -0
- package/dist/domains/dashboard/web/assets/channel-kp6Ng2JJ.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-2J33WTMH-CBGlUx4_.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-4BX2VUAB-CS-iGcFz.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-55IACEB6-BUtCVJat.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-727SXJPM-C94tj_pf.js +206 -0
- package/dist/domains/dashboard/web/assets/chunk-AQP2D5EJ-BFOKcpdG.js +231 -0
- package/dist/domains/dashboard/web/assets/chunk-FMBD7UC4-Dmx8B-st.js +15 -0
- package/dist/domains/dashboard/web/assets/chunk-ND2GUHAM-DYV00CNn.js +1 -0
- package/dist/domains/dashboard/web/assets/chunk-QZHKN3VN-DMJJyQnw.js +1 -0
- package/dist/domains/dashboard/web/assets/classDiagram-4FO5ZUOK-yBDjgMY_.js +1 -0
- package/dist/domains/dashboard/web/assets/classDiagram-v2-Q7XG4LA2-yBDjgMY_.js +1 -0
- package/dist/domains/dashboard/web/assets/cose-bilkent-S5V4N54A-P4nE2rea.js +1 -0
- package/dist/domains/dashboard/web/assets/cynefin-VYW2F7L2-C-R1HXDv.js +166 -0
- package/dist/domains/dashboard/web/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
- package/dist/domains/dashboard/web/assets/dagre-BM42HDAG-BH8d-C9z.js +4 -0
- package/dist/domains/dashboard/web/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/domains/dashboard/web/assets/diagram-2AECGRRQ-DpXTgQIH.js +43 -0
- package/dist/domains/dashboard/web/assets/diagram-5GNKFQAL-DSiFJzSw.js +10 -0
- package/dist/domains/dashboard/web/assets/diagram-KO2AKTUF-DULMkben.js +3 -0
- package/dist/domains/dashboard/web/assets/diagram-LMA3HP47-Pi8m_NO9.js +24 -0
- package/dist/domains/dashboard/web/assets/diagram-OG6HWLK6-BSe6bCWm.js +24 -0
- package/dist/domains/dashboard/web/assets/erDiagram-TEJ5UH35-zb-FEcbq.js +85 -0
- package/dist/domains/dashboard/web/assets/flowDiagram-I6XJVG4X-Dr-Gk0z2.js +162 -0
- package/dist/domains/dashboard/web/assets/ganttDiagram-6RSMTGT7-qs6Zb2A6.js +292 -0
- package/dist/domains/dashboard/web/assets/gitGraphDiagram-PVQCEYII-BQ314orT.js +106 -0
- package/dist/domains/dashboard/web/assets/graph--OzhPTMs.js +1 -0
- package/dist/domains/dashboard/web/assets/index-BLAfkNTu.css +1 -0
- package/dist/domains/dashboard/web/assets/index-DlSYK56b.js +139 -0
- package/dist/domains/dashboard/web/assets/index-DtLUOcAW.js +24 -0
- package/dist/domains/dashboard/web/assets/index-QO0z6F4w.js +10 -0
- package/dist/domains/dashboard/web/assets/infoDiagram-5YYISTIA-O0bQp98A.js +2 -0
- package/dist/domains/dashboard/web/assets/init-Gi6I4Gst.js +1 -0
- package/dist/domains/dashboard/web/assets/ishikawaDiagram-YF4QCWOH-BPC7wbKh.js +70 -0
- package/dist/domains/dashboard/web/assets/journeyDiagram-JHISSGLW-ohViOd4b.js +139 -0
- package/dist/domains/dashboard/web/assets/kanban-definition-UN3LZRKU-CHleNdbG.js +89 -0
- package/dist/domains/dashboard/web/assets/katex-HP8lGamR.js +257 -0
- package/dist/domains/dashboard/web/assets/layout-SsrduOYp.js +1 -0
- package/dist/domains/dashboard/web/assets/linear-CyqiW--Q.js +1 -0
- package/dist/domains/dashboard/web/assets/marked.esm-DECB3bxB.js +64 -0
- package/dist/domains/dashboard/web/assets/mermaid.core-qS9XvtaK.js +301 -0
- package/dist/domains/dashboard/web/assets/mindmap-definition-RKZ34NQL-oaGkqO9l.js +96 -0
- package/dist/domains/dashboard/web/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/domains/dashboard/web/assets/pieDiagram-4H26LBE5-CPcB-AFh.js +30 -0
- package/dist/domains/dashboard/web/assets/purify.es-VaSPOPhr.js +3 -0
- package/dist/domains/dashboard/web/assets/quadrantDiagram-W4KKPZXB-LFy52Qtj.js +7 -0
- package/dist/domains/dashboard/web/assets/requirementDiagram-4Y6WPE33-BdjeaYP_.js +84 -0
- package/dist/domains/dashboard/web/assets/sankeyDiagram-5OEKKPKP-DDJ4styL.js +40 -0
- package/dist/domains/dashboard/web/assets/sequenceDiagram-3UESZ5HK-BL5bFNoz.js +162 -0
- package/dist/domains/dashboard/web/assets/stateDiagram-AJRCARHV-BNUfikui.js +1 -0
- package/dist/domains/dashboard/web/assets/stateDiagram-v2-BHNVJYJU-DGrsmWts.js +1 -0
- package/dist/domains/dashboard/web/assets/timeline-definition-PNZ67QCA--ps2uu6L.js +120 -0
- package/dist/domains/dashboard/web/assets/vennDiagram-CIIHVFJN-C2q8q26c.js +34 -0
- package/dist/domains/dashboard/web/assets/wardleyDiagram-YWT4CUSO-BUH9gXqd.js +78 -0
- package/dist/domains/dashboard/web/assets/xychartDiagram-2RQKCTM6-B-DielEy.js +7 -0
- package/dist/domains/dashboard/web/index.html +16 -16
- package/dist/domains/factory/package.d.ts.map +1 -1
- package/dist/domains/factory/package.js +20 -6
- package/dist/domains/factory/package.js.map +1 -1
- package/dist/domains/integrations/openspec.d.ts +4 -1
- package/dist/domains/integrations/openspec.d.ts.map +1 -1
- package/dist/domains/integrations/openspec.js +56 -4
- package/dist/domains/integrations/openspec.js.map +1 -1
- package/dist/domains/skill/find.d.ts.map +1 -1
- package/dist/domains/skill/find.js +7 -1
- package/dist/domains/skill/find.js.map +1 -1
- package/dist/domains/skill/json-object.d.ts +13 -0
- package/dist/domains/skill/json-object.d.ts.map +1 -0
- package/dist/domains/skill/json-object.js +24 -0
- package/dist/domains/skill/json-object.js.map +1 -0
- package/dist/domains/skill/platform-inspect.d.ts +9 -0
- package/dist/domains/skill/platform-inspect.d.ts.map +1 -0
- package/dist/domains/skill/platform-inspect.js +149 -0
- package/dist/domains/skill/platform-inspect.js.map +1 -0
- package/dist/domains/skill/platform-install.d.ts +16 -6
- package/dist/domains/skill/platform-install.d.ts.map +1 -1
- package/dist/domains/skill/platform-install.js +277 -144
- package/dist/domains/skill/platform-install.js.map +1 -1
- package/dist/domains/skill/uninstall.d.ts.map +1 -1
- package/dist/domains/skill/uninstall.js +204 -141
- package/dist/domains/skill/uninstall.js.map +1 -1
- package/dist/platform/fs/file-system.d.ts +3 -3
- package/dist/platform/fs/file-system.d.ts.map +1 -1
- package/dist/platform/fs/file-system.js +21 -11
- package/dist/platform/fs/file-system.js.map +1 -1
- package/dist/platform/install/platforms.d.ts +4 -0
- package/dist/platform/install/platforms.d.ts.map +1 -1
- package/dist/platform/install/platforms.js +2 -0
- package/dist/platform/install/platforms.js.map +1 -1
- package/dist/platform/install/project-registry.d.ts +1 -0
- package/dist/platform/install/project-registry.d.ts.map +1 -1
- package/dist/platform/install/project-registry.js +9 -1
- package/dist/platform/install/project-registry.js.map +1 -1
- package/dist/platform/install/skill-root-owner.d.ts +15 -0
- package/dist/platform/install/skill-root-owner.d.ts.map +1 -0
- package/dist/platform/install/skill-root-owner.js +68 -0
- package/dist/platform/install/skill-root-owner.js.map +1 -0
- package/package.json +6 -1
- package/dist/domains/dashboard/web/assets/index-CIvN-PL8.js +0 -22
- package/dist/domains/dashboard/web/assets/index-DcyRPBnT.css +0 -1
- package/eval/.env +0 -28
|
@@ -7,6 +7,7 @@ import { fileExists, readJson, copyFile, ensureDir } from '../../platform/fs/fil
|
|
|
7
7
|
import { getPlatformConfigDir, getPlatformSkillsDir, } from '../../platform/install/platforms.js';
|
|
8
8
|
import { formatSupportedArtifactLanguages, resolveArtifactLanguage } from './languages.js';
|
|
9
9
|
import { installCometProjectInstructions } from './project-instructions.js';
|
|
10
|
+
import { readJsonObjectFile } from './json-object.js';
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = path.dirname(__filename);
|
|
12
13
|
function planSkillDirectoryCopy(files, destinationRoot) {
|
|
@@ -190,11 +191,11 @@ async function installSkillsAsSymlink(baseDir, platform, overwrite, languageSkil
|
|
|
190
191
|
const sourceDir = isScript ? 'skills' : languageSkillsDir;
|
|
191
192
|
const src = path.join(assetsDir, sourceDir, skillRelPath);
|
|
192
193
|
const centralDest = path.join(centralDir, 'skills', skillRelPath);
|
|
193
|
-
if (!overwrite && (await fileExists(centralDest))) {
|
|
194
|
-
skippedCount++;
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
194
|
try {
|
|
195
|
+
if (!overwrite && (await fileExists(centralDest))) {
|
|
196
|
+
skippedCount++;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
198
199
|
await copyFile(src, centralDest);
|
|
199
200
|
copied++;
|
|
200
201
|
}
|
|
@@ -218,12 +219,14 @@ async function installSkillsAsSymlink(baseDir, platform, overwrite, languageSkil
|
|
|
218
219
|
const result = await createOpenCodeCommands(baseDir, platform, manifest.skills, overwrite, scope, languageSkillsDir);
|
|
219
220
|
copied += result.copied;
|
|
220
221
|
skippedCount += result.skipped;
|
|
222
|
+
failedCount += result.failed;
|
|
221
223
|
}
|
|
222
224
|
// Handle Pi platform command extension
|
|
223
225
|
if (platform.id === 'pi') {
|
|
224
226
|
const result = await createPiCommandExtension(baseDir, platform, manifest.skills, overwrite, scope);
|
|
225
227
|
copied += result.copied;
|
|
226
228
|
skippedCount += result.skipped;
|
|
229
|
+
failedCount += result.failed;
|
|
227
230
|
}
|
|
228
231
|
return { copied, skipped: skippedCount, failed: failedCount };
|
|
229
232
|
}
|
|
@@ -248,11 +251,11 @@ async function copyCometSkillsForPlatform(baseDir, platform, overwrite, language
|
|
|
248
251
|
const sourceDir = isScript ? 'skills' : languageSkillsDir;
|
|
249
252
|
const src = path.join(assetsDir, sourceDir, skillRelPath);
|
|
250
253
|
const dest = path.join(baseDir, getPlatformSkillsDir(platform, scope), 'skills', skillRelPath);
|
|
251
|
-
if (!overwrite && (await fileExists(dest))) {
|
|
252
|
-
skippedCount++;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
254
|
try {
|
|
255
|
+
if (!overwrite && (await fileExists(dest))) {
|
|
256
|
+
skippedCount++;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
256
259
|
await copyFile(src, dest);
|
|
257
260
|
copied++;
|
|
258
261
|
}
|
|
@@ -269,11 +272,13 @@ async function copyCometSkillsForPlatform(baseDir, platform, overwrite, language
|
|
|
269
272
|
const result = await createOpenCodeCommands(baseDir, platform, manifest.skills, overwrite, scope, languageSkillsDir);
|
|
270
273
|
copied += result.copied;
|
|
271
274
|
skippedCount += result.skipped;
|
|
275
|
+
failedCount += result.failed;
|
|
272
276
|
}
|
|
273
277
|
if (platform.id === 'pi') {
|
|
274
278
|
const result = await createPiCommandExtension(baseDir, platform, manifest.skills, overwrite, scope);
|
|
275
279
|
copied += result.copied;
|
|
276
280
|
skippedCount += result.skipped;
|
|
281
|
+
failedCount += result.failed;
|
|
277
282
|
}
|
|
278
283
|
return { copied, skipped: skippedCount, failed: failedCount };
|
|
279
284
|
}
|
|
@@ -304,37 +309,46 @@ async function createPiCommandExtension(baseDir, platform, skillPaths, overwrite
|
|
|
304
309
|
const platformBase = path.join(baseDir, getPlatformSkillsDir(platform, scope));
|
|
305
310
|
const settingsPath = path.join(platformBase, 'settings.json');
|
|
306
311
|
const extensionPath = path.join(platformBase, 'extensions', PI_COMMAND_EXTENSION_FILE);
|
|
307
|
-
let
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
let copied = 0;
|
|
313
|
+
let skipped = 0;
|
|
314
|
+
let failed = 0;
|
|
315
|
+
try {
|
|
316
|
+
let settings = {};
|
|
317
|
+
if (await fileExists(settingsPath)) {
|
|
310
318
|
const parsed = JSON.parse(await readFile(settingsPath, 'utf-8'));
|
|
311
319
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
312
320
|
throw new Error('expected a JSON object');
|
|
313
321
|
}
|
|
314
322
|
settings = parsed;
|
|
315
323
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
324
|
+
if (settings.enableSkillCommands !== true) {
|
|
325
|
+
settings.enableSkillCommands = true;
|
|
326
|
+
await ensureDir(path.dirname(settingsPath));
|
|
327
|
+
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
328
|
+
copied++;
|
|
320
329
|
}
|
|
321
330
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
settings.enableSkillCommands = true;
|
|
326
|
-
await ensureDir(path.dirname(settingsPath));
|
|
327
|
-
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
328
|
-
copied++;
|
|
331
|
+
catch (err) {
|
|
332
|
+
failed++;
|
|
333
|
+
console.error(` Failed to update Pi settings at ${settingsPath}: ${err.message}`);
|
|
329
334
|
}
|
|
330
|
-
if (
|
|
331
|
-
skipped
|
|
332
|
-
|
|
335
|
+
if (failed > 0)
|
|
336
|
+
return { copied, skipped, failed };
|
|
337
|
+
try {
|
|
338
|
+
if (!overwrite && (await fileExists(extensionPath))) {
|
|
339
|
+
skipped++;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
await ensureDir(path.dirname(extensionPath));
|
|
343
|
+
await writeFile(extensionPath, renderPiCommandExtension(getTopLevelSkillNames(skillPaths)), 'utf-8');
|
|
344
|
+
copied++;
|
|
345
|
+
}
|
|
333
346
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
347
|
+
catch (err) {
|
|
348
|
+
failed++;
|
|
349
|
+
console.error(` Failed to write Pi command extension at ${extensionPath}: ${err.message}`);
|
|
350
|
+
}
|
|
351
|
+
return { copied, skipped, failed };
|
|
338
352
|
}
|
|
339
353
|
function stripFrontmatter(content) {
|
|
340
354
|
if (!content.startsWith('---\n') && !content.startsWith('---\r\n')) {
|
|
@@ -349,6 +363,7 @@ function stripFrontmatter(content) {
|
|
|
349
363
|
async function createOpenCodeCommands(baseDir, platform, skillPaths, overwrite, scope, languageSkillsDir) {
|
|
350
364
|
let copied = 0;
|
|
351
365
|
let skipped = 0;
|
|
366
|
+
let failed = 0;
|
|
352
367
|
const assetsDir = getAssetsDir();
|
|
353
368
|
const commandsDir = path.join(baseDir, getPlatformSkillsDir(platform, scope), 'commands');
|
|
354
369
|
for (const skillPath of skillPaths) {
|
|
@@ -357,17 +372,18 @@ async function createOpenCodeCommands(baseDir, platform, skillPaths, overwrite,
|
|
|
357
372
|
continue;
|
|
358
373
|
const skillName = parts[0];
|
|
359
374
|
const dest = path.join(commandsDir, `${skillName}.md`);
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
375
|
+
try {
|
|
376
|
+
if (!overwrite && (await fileExists(dest))) {
|
|
377
|
+
skipped++;
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
await ensureDir(path.dirname(dest));
|
|
381
|
+
let skillSourcePath = path.join(assetsDir, languageSkillsDir, skillPath);
|
|
382
|
+
if (!(await fileExists(skillSourcePath))) {
|
|
383
|
+
skillSourcePath = path.join(assetsDir, 'skills', skillPath);
|
|
384
|
+
}
|
|
385
|
+
const skillBody = stripFrontmatter(await readFile(skillSourcePath, 'utf-8'));
|
|
386
|
+
const content = `${OPENCODE_COMMAND_HEADER.replace('{skillName}', skillName)}
|
|
371
387
|
Equivalent Comet skill: \`${skillName}\`
|
|
372
388
|
Command name: \`/${skillName}\`
|
|
373
389
|
|
|
@@ -379,10 +395,15 @@ $ARGUMENTS
|
|
|
379
395
|
|
|
380
396
|
${skillBody}
|
|
381
397
|
`;
|
|
382
|
-
|
|
383
|
-
|
|
398
|
+
await writeFile(dest, content, 'utf-8');
|
|
399
|
+
copied++;
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
failed++;
|
|
403
|
+
console.error(` Failed to create OpenCode command ${dest}: ${err.message}`);
|
|
404
|
+
}
|
|
384
405
|
}
|
|
385
|
-
return { copied, skipped };
|
|
406
|
+
return { copied, skipped, failed };
|
|
386
407
|
}
|
|
387
408
|
async function readManifest() {
|
|
388
409
|
const assetsDir = getAssetsDir();
|
|
@@ -429,12 +450,12 @@ function selectRulePathsForLanguage(rulePaths, languageId) {
|
|
|
429
450
|
}
|
|
430
451
|
async function copyCometRulesForPlatform(baseDir, platform, overwrite, languageId, scope = 'project') {
|
|
431
452
|
if (!platform.rulesDir || !platform.rulesFormat) {
|
|
432
|
-
return { copied: 0, skipped: 0 };
|
|
453
|
+
return { copied: 0, skipped: 0, failed: 0 };
|
|
433
454
|
}
|
|
434
455
|
const manifest = await readManifest();
|
|
435
456
|
const rulePaths = selectRulePathsForLanguage(manifest.rules ?? [], languageId);
|
|
436
457
|
if (!rulePaths || rulePaths.length === 0) {
|
|
437
|
-
return { copied: 0, skipped: 0 };
|
|
458
|
+
return { copied: 0, skipped: 0, failed: 0 };
|
|
438
459
|
}
|
|
439
460
|
const assetsDir = getAssetsDir();
|
|
440
461
|
// Support platforms whose rules live outside the skills config dir
|
|
@@ -446,22 +467,24 @@ async function copyCometRulesForPlatform(baseDir, platform, overwrite, languageI
|
|
|
446
467
|
: path.join(baseDir, getPlatformSkillsDir(platform, scope));
|
|
447
468
|
let copied = 0;
|
|
448
469
|
let skippedCount = 0;
|
|
470
|
+
let failed = 0;
|
|
449
471
|
for (const ruleRelPath of rulePaths) {
|
|
450
472
|
const src = path.join(assetsDir, 'skills', ruleRelPath);
|
|
451
|
-
if (!(await fileExists(src))) {
|
|
452
|
-
console.error(` Rule source not found: ${ruleRelPath}`);
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
// Normalize the `.en` infix away so the installed file name is the same
|
|
456
|
-
// regardless of which language variant was selected.
|
|
457
|
-
const ruleFileName = toRuleBaseName(path.basename(ruleRelPath));
|
|
458
|
-
const rulesDestDir = path.join(rulesBase, platform.rulesDir);
|
|
459
|
-
const dest = computeRuleDestPath(rulesDestDir, ruleFileName, platform.rulesFormat);
|
|
460
|
-
if (!overwrite && (await fileExists(dest))) {
|
|
461
|
-
skippedCount++;
|
|
462
|
-
continue;
|
|
463
|
-
}
|
|
464
473
|
try {
|
|
474
|
+
if (!(await fileExists(src))) {
|
|
475
|
+
console.error(` Rule source not found: ${ruleRelPath}`);
|
|
476
|
+
failed++;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
// Normalize the `.en` infix away so the installed file name is the same
|
|
480
|
+
// regardless of which language variant was selected.
|
|
481
|
+
const ruleFileName = toRuleBaseName(path.basename(ruleRelPath));
|
|
482
|
+
const rulesDestDir = path.join(rulesBase, platform.rulesDir);
|
|
483
|
+
const dest = computeRuleDestPath(rulesDestDir, ruleFileName, platform.rulesFormat);
|
|
484
|
+
if (!overwrite && (await fileExists(dest))) {
|
|
485
|
+
skippedCount++;
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
465
488
|
const content = await readFile(src, 'utf-8');
|
|
466
489
|
await ensureDir(path.dirname(dest));
|
|
467
490
|
const formatted = formatRuleContent(content, ruleFileName, platform.rulesFormat);
|
|
@@ -470,9 +493,10 @@ async function copyCometRulesForPlatform(baseDir, platform, overwrite, languageI
|
|
|
470
493
|
}
|
|
471
494
|
catch (err) {
|
|
472
495
|
console.error(` Failed to copy rule ${ruleRelPath}: ${err.message}`);
|
|
496
|
+
failed++;
|
|
473
497
|
}
|
|
474
498
|
}
|
|
475
|
-
return { copied, skipped: skippedCount };
|
|
499
|
+
return { copied, skipped: skippedCount, failed };
|
|
476
500
|
}
|
|
477
501
|
function computeRuleDestPath(rulesDestDir, ruleFileName, rulesFormat) {
|
|
478
502
|
if (rulesFormat === 'mdc') {
|
|
@@ -509,7 +533,8 @@ ${content}`;
|
|
|
509
533
|
/**
|
|
510
534
|
* Install Comet hooks for platforms that support them.
|
|
511
535
|
* Supports multiple hook formats:
|
|
512
|
-
* 'claude-code' —
|
|
536
|
+
* 'claude-code' — Claude-shaped JSON with PreToolUse array; defaults to settings.local.json,
|
|
537
|
+
* with platform metadata able to override the filename
|
|
513
538
|
* 'qwen' — settings.json with PreToolUse/hooks array (Qwen Code)
|
|
514
539
|
* 'qoder' — settings.json with PreToolUse/hooks array (Qoder)
|
|
515
540
|
* 'codebuddy' — settings.json with PreToolUse/hooks array (CodeBuddy Code)
|
|
@@ -519,39 +544,57 @@ ${content}`;
|
|
|
519
544
|
* 'kiro' — hooks/*.kiro.hook JSON files
|
|
520
545
|
*/
|
|
521
546
|
async function installCometHooksForPlatform(baseDir, platform, scope = 'project') {
|
|
522
|
-
if (!platform.supportsHooks
|
|
523
|
-
return {
|
|
547
|
+
if (!platform.supportsHooks) {
|
|
548
|
+
return { status: 'skipped', reason: 'platform does not support hooks' };
|
|
524
549
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
550
|
+
if (!platform.hookFormat) {
|
|
551
|
+
return {
|
|
552
|
+
status: 'failed',
|
|
553
|
+
reason: 'hook-capable platform does not declare a hook format',
|
|
554
|
+
};
|
|
529
555
|
}
|
|
530
|
-
const hookFormat = platform.hookFormat;
|
|
531
|
-
const skillsDir = getPlatformSkillsDir(platform, scope);
|
|
532
|
-
const platformBase = path.join(baseDir, getPlatformConfigDir(platform, scope));
|
|
533
556
|
try {
|
|
557
|
+
const manifest = await readManifest();
|
|
558
|
+
const hooksConfig = manifest.hooks;
|
|
559
|
+
if (!hooksConfig || Object.keys(hooksConfig).length === 0) {
|
|
560
|
+
return { status: 'skipped', reason: 'no hooks defined in manifest' };
|
|
561
|
+
}
|
|
562
|
+
const hookFormat = platform.hookFormat;
|
|
563
|
+
const skillsDir = getPlatformSkillsDir(platform, scope);
|
|
564
|
+
const platformBase = path.join(baseDir, getPlatformConfigDir(platform, scope));
|
|
534
565
|
switch (hookFormat) {
|
|
535
|
-
case 'claude-code':
|
|
536
|
-
|
|
566
|
+
case 'claude-code': {
|
|
567
|
+
const result = await installClaudeCodeHooks(baseDir, platformBase, skillsDir, hooksConfig, platform.hookConfigFile ?? 'settings.local.json', platform.name);
|
|
568
|
+
if (result.status === 'installed') {
|
|
569
|
+
for (const legacyFile of platform.legacyHookConfigFiles ?? []) {
|
|
570
|
+
try {
|
|
571
|
+
await removeManagedHooksFromJsonFile(path.join(platformBase, legacyFile), Object.keys(hooksConfig));
|
|
572
|
+
}
|
|
573
|
+
catch {
|
|
574
|
+
// Historical Hook cleanup is best-effort after canonical install succeeds.
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return result;
|
|
579
|
+
}
|
|
537
580
|
case 'qwen':
|
|
538
581
|
case 'qoder':
|
|
539
582
|
case 'codebuddy':
|
|
540
|
-
return await installQwenStyleHooks(baseDir, platformBase, skillsDir, hooksConfig,
|
|
583
|
+
return await installQwenStyleHooks(baseDir, platformBase, skillsDir, hooksConfig, platform.name);
|
|
541
584
|
case 'gemini':
|
|
542
|
-
return await installGeminiHooks(baseDir, platformBase, skillsDir, hooksConfig);
|
|
585
|
+
return await installGeminiHooks(baseDir, platformBase, skillsDir, hooksConfig, platform.name);
|
|
543
586
|
case 'windsurf':
|
|
544
|
-
return await installWindsurfHooks(baseDir, platformBase, skillsDir, hooksConfig);
|
|
587
|
+
return await installWindsurfHooks(baseDir, platformBase, skillsDir, hooksConfig, platform.name);
|
|
545
588
|
case 'copilot':
|
|
546
589
|
return await installCopilotHooks(baseDir, platformBase, skillsDir, hooksConfig);
|
|
547
590
|
case 'kiro':
|
|
548
591
|
return await installKiroHooks(baseDir, platformBase, skillsDir, hooksConfig);
|
|
549
592
|
default:
|
|
550
|
-
return {
|
|
593
|
+
return { status: 'failed', reason: `unsupported hook format: ${hookFormat}` };
|
|
551
594
|
}
|
|
552
595
|
}
|
|
553
596
|
catch (err) {
|
|
554
|
-
return {
|
|
597
|
+
return { status: 'failed', reason: err.message };
|
|
555
598
|
}
|
|
556
599
|
}
|
|
557
600
|
function quoteCommandArg(value) {
|
|
@@ -563,34 +606,96 @@ function buildHookCommand(baseDir, skillsDir, scriptRelPath) {
|
|
|
563
606
|
const scriptPath = path.join(projectRoot, skillsDir, 'skills', ...scriptRelPath.split('/'));
|
|
564
607
|
return `node ${quoteCommandArg(scriptPath)} --project-root ${quoteCommandArg(projectRoot)}`;
|
|
565
608
|
}
|
|
609
|
+
function parseCommandTokens(command) {
|
|
610
|
+
const tokens = [];
|
|
611
|
+
let current = '';
|
|
612
|
+
let quote;
|
|
613
|
+
let tokenStarted = false;
|
|
614
|
+
let quoteClosed = false;
|
|
615
|
+
for (let index = 0; index < command.length; index++) {
|
|
616
|
+
const character = command[index];
|
|
617
|
+
if (quote) {
|
|
618
|
+
if (character === quote) {
|
|
619
|
+
quote = undefined;
|
|
620
|
+
quoteClosed = true;
|
|
621
|
+
}
|
|
622
|
+
else if (character === '\\' && command[index + 1] === quote) {
|
|
623
|
+
current += quote;
|
|
624
|
+
index++;
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
current += character;
|
|
628
|
+
}
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
if (character === '\r' || character === '\n' || ';|&<>`'.includes(character)) {
|
|
632
|
+
return undefined;
|
|
633
|
+
}
|
|
634
|
+
if (/\s/u.test(character)) {
|
|
635
|
+
if (tokenStarted) {
|
|
636
|
+
tokens.push(current);
|
|
637
|
+
current = '';
|
|
638
|
+
tokenStarted = false;
|
|
639
|
+
quoteClosed = false;
|
|
640
|
+
}
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (quoteClosed)
|
|
644
|
+
return undefined;
|
|
645
|
+
if (character === '"' || character === "'") {
|
|
646
|
+
if (tokenStarted)
|
|
647
|
+
return undefined;
|
|
648
|
+
quote = character;
|
|
649
|
+
tokenStarted = true;
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
current += character;
|
|
653
|
+
tokenStarted = true;
|
|
654
|
+
}
|
|
655
|
+
if (quote)
|
|
656
|
+
return undefined;
|
|
657
|
+
if (tokenStarted)
|
|
658
|
+
tokens.push(current);
|
|
659
|
+
return tokens;
|
|
660
|
+
}
|
|
566
661
|
function isManagedHookCommand(command, scriptRelPaths) {
|
|
567
662
|
if (typeof command !== 'string')
|
|
568
663
|
return false;
|
|
569
664
|
// Match both the current `node .../comet-hook-guard.mjs` form and the legacy
|
|
570
665
|
// `bash .../comet-hook-guard.sh` form so uninstall also cleans up hooks
|
|
571
666
|
// written by older Comet releases. Compare basenames without extension.
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
.match(/^(?:node|bash|sh)\s+["']?([^"'\s]+)["']?(?:\s|$)/)?.[1]
|
|
575
|
-
?.replace(/\\/g, '/');
|
|
576
|
-
if (!commandPath)
|
|
667
|
+
const tokens = parseCommandTokens(command.trim());
|
|
668
|
+
if (!tokens || tokens.length < 2 || !['node', 'bash', 'sh'].includes(tokens[0]))
|
|
577
669
|
return false;
|
|
670
|
+
const commandPath = tokens[1].replace(/\\/g, '/');
|
|
578
671
|
const normalize = (value) => value.replace(/\.(?:sh|mjs)$/u, '');
|
|
579
672
|
return scriptRelPaths.some((scriptRelPath) => normalize(commandPath).endsWith(`/skills/${normalize(scriptRelPath.replace(/\\/g, '/'))}`));
|
|
580
673
|
}
|
|
581
674
|
function mergeHookGroups(existingGroups, newGroups, scriptRelPaths) {
|
|
582
|
-
const mergedGroups = existingGroups.
|
|
583
|
-
if (!Array.isArray(group
|
|
584
|
-
return
|
|
585
|
-
const
|
|
586
|
-
if (
|
|
587
|
-
return
|
|
588
|
-
|
|
675
|
+
const mergedGroups = existingGroups.map((group) => {
|
|
676
|
+
if (!group || typeof group !== 'object' || Array.isArray(group))
|
|
677
|
+
return group;
|
|
678
|
+
const record = group;
|
|
679
|
+
if (!Array.isArray(record.hooks))
|
|
680
|
+
return record;
|
|
681
|
+
const hooks = record.hooks.filter((hook) => {
|
|
682
|
+
const command = hook && typeof hook === 'object' ? hook.command : undefined;
|
|
683
|
+
return !isManagedHookCommand(command, scriptRelPaths);
|
|
684
|
+
});
|
|
685
|
+
return { ...record, hooks };
|
|
589
686
|
});
|
|
590
687
|
for (const newGroup of newGroups) {
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
688
|
+
const existingGroupIndex = mergedGroups.findIndex((group) => Boolean(group) &&
|
|
689
|
+
typeof group === 'object' &&
|
|
690
|
+
!Array.isArray(group) &&
|
|
691
|
+
group.matcher === newGroup.matcher &&
|
|
692
|
+
Array.isArray(group.hooks));
|
|
693
|
+
if (existingGroupIndex >= 0) {
|
|
694
|
+
const existingGroup = mergedGroups[existingGroupIndex];
|
|
695
|
+
mergedGroups[existingGroupIndex] = {
|
|
696
|
+
...existingGroup,
|
|
697
|
+
hooks: [...existingGroup.hooks, ...newGroup.hooks],
|
|
698
|
+
};
|
|
594
699
|
}
|
|
595
700
|
else {
|
|
596
701
|
mergedGroups.push(newGroup);
|
|
@@ -606,28 +711,77 @@ function mergeHookGroups(existingGroups, newGroups, scriptRelPaths) {
|
|
|
606
711
|
function asHookGroup(value) {
|
|
607
712
|
return Array.isArray(value) ? value : [];
|
|
608
713
|
}
|
|
609
|
-
async function
|
|
714
|
+
async function removeManagedHooksFromJsonFile(settingsPath, scriptRelPaths) {
|
|
610
715
|
if (!(await fileExists(settingsPath)))
|
|
611
|
-
return {};
|
|
716
|
+
return { removed: 0, failed: 0 };
|
|
717
|
+
let source;
|
|
612
718
|
try {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
}
|
|
617
|
-
return parsed;
|
|
719
|
+
source = await readFile(settingsPath, 'utf-8');
|
|
720
|
+
}
|
|
721
|
+
catch {
|
|
722
|
+
return { removed: 0, failed: 1 };
|
|
618
723
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
724
|
+
let settings;
|
|
725
|
+
try {
|
|
726
|
+
const parsed = JSON.parse(source);
|
|
727
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
728
|
+
return { removed: 0, failed: 1 };
|
|
729
|
+
}
|
|
730
|
+
settings = parsed;
|
|
731
|
+
}
|
|
732
|
+
catch {
|
|
733
|
+
return { removed: 0, failed: 1 };
|
|
734
|
+
}
|
|
735
|
+
const existingHooks = settings.hooks;
|
|
736
|
+
const existingPreToolUse = existingHooks?.PreToolUse;
|
|
737
|
+
if (!existingHooks || !Array.isArray(existingPreToolUse)) {
|
|
738
|
+
return { removed: 0, failed: 0 };
|
|
739
|
+
}
|
|
740
|
+
let removed = 0;
|
|
741
|
+
const filtered = existingPreToolUse.map((group) => {
|
|
742
|
+
if (!group || typeof group !== 'object')
|
|
743
|
+
return group;
|
|
744
|
+
const record = group;
|
|
745
|
+
if (!Array.isArray(record.hooks))
|
|
746
|
+
return record;
|
|
747
|
+
const handlers = record.hooks.filter((handler) => {
|
|
748
|
+
const command = handler && typeof handler === 'object'
|
|
749
|
+
? handler.command
|
|
750
|
+
: undefined;
|
|
751
|
+
const managed = isManagedHookCommand(command, scriptRelPaths);
|
|
752
|
+
if (managed)
|
|
753
|
+
removed++;
|
|
754
|
+
return !managed;
|
|
622
755
|
});
|
|
756
|
+
return { ...record, hooks: handlers };
|
|
757
|
+
});
|
|
758
|
+
if (removed === 0)
|
|
759
|
+
return { removed: 0, failed: 0 };
|
|
760
|
+
existingHooks.PreToolUse = filtered;
|
|
761
|
+
try {
|
|
762
|
+
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
623
763
|
}
|
|
764
|
+
catch {
|
|
765
|
+
return { removed: 0, failed: 1 };
|
|
766
|
+
}
|
|
767
|
+
return { removed, failed: 0 };
|
|
768
|
+
}
|
|
769
|
+
async function readSettingsJsonObject(settingsPath, platformName) {
|
|
770
|
+
const result = await readJsonObjectFile(settingsPath);
|
|
771
|
+
if (result.status === 'missing')
|
|
772
|
+
return {};
|
|
773
|
+
if (result.status === 'present')
|
|
774
|
+
return result.value;
|
|
775
|
+
throw new Error(`Invalid ${platformName} settings at ${settingsPath}: ${result.error.message}`, {
|
|
776
|
+
cause: result.error,
|
|
777
|
+
});
|
|
624
778
|
}
|
|
625
779
|
/**
|
|
626
|
-
* Claude Code, Codex, Amazon Q
|
|
627
|
-
*
|
|
780
|
+
* Claude-shaped JSON format used by Claude Code, Codex, and Amazon Q.
|
|
781
|
+
* Defaults to settings.local.json; platform metadata may override the filename.
|
|
628
782
|
*/
|
|
629
|
-
async function installClaudeCodeHooks(baseDir, platformBase, skillsDir, hooksConfig) {
|
|
630
|
-
const settingsPath = path.join(platformBase,
|
|
783
|
+
async function installClaudeCodeHooks(baseDir, platformBase, skillsDir, hooksConfig, configFile, platformName) {
|
|
784
|
+
const settingsPath = path.join(platformBase, configFile);
|
|
631
785
|
// Group by matcher so hooks sharing the same matcher are merged
|
|
632
786
|
const matcherGroups = {};
|
|
633
787
|
for (const [scriptRelPath, config] of Object.entries(hooksConfig)) {
|
|
@@ -638,28 +792,20 @@ async function installClaudeCodeHooks(baseDir, platformBase, skillsDir, hooksCon
|
|
|
638
792
|
matcherGroups[config.matcher].push({ type: 'command', command });
|
|
639
793
|
}
|
|
640
794
|
const newEntries = Object.entries(matcherGroups).map(([matcher, hooks]) => ({ matcher, hooks }));
|
|
641
|
-
|
|
642
|
-
if (await fileExists(settingsPath)) {
|
|
643
|
-
try {
|
|
644
|
-
settings = JSON.parse(await readFile(settingsPath, 'utf-8'));
|
|
645
|
-
}
|
|
646
|
-
catch {
|
|
647
|
-
settings = {};
|
|
648
|
-
}
|
|
649
|
-
}
|
|
795
|
+
const settings = await readSettingsJsonObject(settingsPath, platformName);
|
|
650
796
|
const existingHooks = settings.hooks ?? {};
|
|
651
797
|
const existingPreToolUse = asHookGroup(existingHooks.PreToolUse);
|
|
652
798
|
const merged = mergeHookGroups(existingPreToolUse, newEntries, Object.keys(hooksConfig));
|
|
653
799
|
settings.hooks = { ...existingHooks, PreToolUse: merged };
|
|
654
800
|
await ensureDir(path.dirname(settingsPath));
|
|
655
801
|
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
656
|
-
return {
|
|
802
|
+
return { status: 'installed' };
|
|
657
803
|
}
|
|
658
804
|
/**
|
|
659
805
|
* Qwen Code / Qoder / CodeBuddy format:
|
|
660
806
|
* Writes to settings.json with { hooks: { PreToolUse: [{ matcher, hooks: [{ type, command }] }] } }
|
|
661
807
|
*/
|
|
662
|
-
async function installQwenStyleHooks(baseDir, platformBase, skillsDir, hooksConfig,
|
|
808
|
+
async function installQwenStyleHooks(baseDir, platformBase, skillsDir, hooksConfig, platformName) {
|
|
663
809
|
const settingsPath = path.join(platformBase, 'settings.json');
|
|
664
810
|
// Group by matcher
|
|
665
811
|
const matcherGroups = {};
|
|
@@ -677,20 +823,20 @@ async function installQwenStyleHooks(baseDir, platformBase, skillsDir, hooksConf
|
|
|
677
823
|
matcher,
|
|
678
824
|
hooks,
|
|
679
825
|
}));
|
|
680
|
-
const settings = await readSettingsJsonObject(settingsPath,
|
|
826
|
+
const settings = await readSettingsJsonObject(settingsPath, platformName);
|
|
681
827
|
const existingHooks = settings.hooks ?? {};
|
|
682
828
|
const existingPreToolUse = asHookGroup(existingHooks.PreToolUse);
|
|
683
829
|
const merged = mergeHookGroups(existingPreToolUse, preToolUseEntries, Object.keys(hooksConfig));
|
|
684
830
|
settings.hooks = { ...existingHooks, PreToolUse: merged };
|
|
685
831
|
await ensureDir(path.dirname(settingsPath));
|
|
686
832
|
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
687
|
-
return {
|
|
833
|
+
return { status: 'installed' };
|
|
688
834
|
}
|
|
689
835
|
/**
|
|
690
836
|
* Gemini CLI format:
|
|
691
837
|
* Writes to .gemini/settings.json with { hooks: { BeforeTool: [{ matcher, hooks: [{ type, command }] }] } }
|
|
692
838
|
*/
|
|
693
|
-
async function installGeminiHooks(baseDir, platformBase, skillsDir, hooksConfig) {
|
|
839
|
+
async function installGeminiHooks(baseDir, platformBase, skillsDir, hooksConfig, platformName) {
|
|
694
840
|
const settingsPath = path.join(platformBase, 'settings.json');
|
|
695
841
|
const entries = [];
|
|
696
842
|
for (const [scriptRelPath, config] of Object.entries(hooksConfig)) {
|
|
@@ -705,28 +851,20 @@ async function installGeminiHooks(baseDir, platformBase, skillsDir, hooksConfig)
|
|
|
705
851
|
],
|
|
706
852
|
});
|
|
707
853
|
}
|
|
708
|
-
|
|
709
|
-
if (await fileExists(settingsPath)) {
|
|
710
|
-
try {
|
|
711
|
-
settings = JSON.parse(await readFile(settingsPath, 'utf-8'));
|
|
712
|
-
}
|
|
713
|
-
catch {
|
|
714
|
-
settings = {};
|
|
715
|
-
}
|
|
716
|
-
}
|
|
854
|
+
const settings = await readSettingsJsonObject(settingsPath, platformName);
|
|
717
855
|
const existingHooks = settings.hooks ?? {};
|
|
718
856
|
const existingBeforeTool = asHookGroup(existingHooks.BeforeTool);
|
|
719
857
|
const merged = mergeHookGroups(existingBeforeTool, entries, Object.keys(hooksConfig));
|
|
720
858
|
settings.hooks = { ...existingHooks, BeforeTool: merged };
|
|
721
859
|
await ensureDir(path.dirname(settingsPath));
|
|
722
860
|
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
723
|
-
return {
|
|
861
|
+
return { status: 'installed' };
|
|
724
862
|
}
|
|
725
863
|
/**
|
|
726
864
|
* Windsurf format:
|
|
727
865
|
* Writes to .windsurf/hooks.json with { hooks: { pre_write_code: [{ command }] } }
|
|
728
866
|
*/
|
|
729
|
-
async function installWindsurfHooks(baseDir, platformBase, skillsDir, hooksConfig) {
|
|
867
|
+
async function installWindsurfHooks(baseDir, platformBase, skillsDir, hooksConfig, platformName) {
|
|
730
868
|
const hooksPath = path.join(platformBase, 'hooks.json');
|
|
731
869
|
const entries = [];
|
|
732
870
|
for (const [scriptRelPath] of Object.entries(hooksConfig)) {
|
|
@@ -735,23 +873,18 @@ async function installWindsurfHooks(baseDir, platformBase, skillsDir, hooksConfi
|
|
|
735
873
|
show_output: true,
|
|
736
874
|
});
|
|
737
875
|
}
|
|
738
|
-
|
|
739
|
-
if (await fileExists(hooksPath)) {
|
|
740
|
-
try {
|
|
741
|
-
hooksFile = JSON.parse(await readFile(hooksPath, 'utf-8'));
|
|
742
|
-
}
|
|
743
|
-
catch {
|
|
744
|
-
hooksFile = {};
|
|
745
|
-
}
|
|
746
|
-
}
|
|
876
|
+
const hooksFile = await readSettingsJsonObject(hooksPath, platformName);
|
|
747
877
|
const existingHooks = hooksFile.hooks ?? {};
|
|
748
878
|
const existingPreWrite = asHookGroup(existingHooks.pre_write_code);
|
|
749
|
-
const merged = existingPreWrite.filter((entry) =>
|
|
879
|
+
const merged = existingPreWrite.filter((entry) => {
|
|
880
|
+
const command = entry && typeof entry === 'object' ? entry.command : undefined;
|
|
881
|
+
return !isManagedHookCommand(command, Object.keys(hooksConfig));
|
|
882
|
+
});
|
|
750
883
|
merged.push(...entries);
|
|
751
884
|
hooksFile.hooks = { ...existingHooks, pre_write_code: merged };
|
|
752
885
|
await ensureDir(path.dirname(hooksPath));
|
|
753
886
|
await writeFile(hooksPath, JSON.stringify(hooksFile, null, 2) + '\n', 'utf-8');
|
|
754
|
-
return {
|
|
887
|
+
return { status: 'installed' };
|
|
755
888
|
}
|
|
756
889
|
/**
|
|
757
890
|
* GitHub Copilot format:
|
|
@@ -774,7 +907,7 @@ async function installCopilotHooks(baseDir, platformBase, skillsDir, hooksConfig
|
|
|
774
907
|
};
|
|
775
908
|
await ensureDir(hooksDir);
|
|
776
909
|
await writeFile(hookFilePath, JSON.stringify(hookConfig, null, 2) + '\n', 'utf-8');
|
|
777
|
-
return {
|
|
910
|
+
return { status: 'installed' };
|
|
778
911
|
}
|
|
779
912
|
/**
|
|
780
913
|
* Kiro format:
|
|
@@ -804,7 +937,7 @@ async function installKiroHooks(baseDir, platformBase, skillsDir, hooksConfig) {
|
|
|
804
937
|
await ensureDir(hooksDir);
|
|
805
938
|
await writeFile(hookFilePath, JSON.stringify(hookConfig, null, 2) + '\n', 'utf-8');
|
|
806
939
|
}
|
|
807
|
-
return {
|
|
940
|
+
return { status: 'installed' };
|
|
808
941
|
}
|
|
809
942
|
function managedConfigFields(language = 'en') {
|
|
810
943
|
const artifactLanguage = resolveArtifactLanguage(language);
|
|
@@ -885,5 +1018,5 @@ async function createWorkingDirs(projectPath, language = 'en') {
|
|
|
885
1018
|
await mergeProjectConfig(projectPath, language);
|
|
886
1019
|
await installCometProjectInstructions(projectPath, language === 'zh-CN' ? 'zh' : 'en');
|
|
887
1020
|
}
|
|
888
|
-
export { copyCometSkillsForPlatform, copyCometRulesForPlatform, installCometHooksForPlatform, readManifest, getManagedSkillPaths, getManifestSkills, getUserFacingSkillNames, createWorkingDirs, getAssetsDir, computeRuleDestPath, formatRuleContent, isManagedHookCommand, planSkillDirectoryCopy, mergeProjectConfig, parseProjectConfigOverrides, renderProjectConfig, getCentralSkillsDir, installSkillsAsSymlink, };
|
|
1021
|
+
export { copyCometSkillsForPlatform, copyCometRulesForPlatform, installCometHooksForPlatform, readManifest, getManagedSkillPaths, getManifestSkills, getUserFacingSkillNames, createWorkingDirs, getAssetsDir, computeRuleDestPath, formatRuleContent, isManagedHookCommand, buildHookCommand, removeManagedHooksFromJsonFile, planSkillDirectoryCopy, mergeProjectConfig, parseProjectConfigOverrides, renderProjectConfig, getCentralSkillsDir, installSkillsAsSymlink, };
|
|
889
1022
|
//# sourceMappingURL=platform-install.js.map
|