code-abyss 2.0.7 → 2.0.8

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.
Files changed (47) hide show
  1. package/README.md +129 -58
  2. package/bin/adapters/claude.js +16 -12
  3. package/bin/adapters/codex.js +110 -37
  4. package/bin/adapters/gemini.js +92 -0
  5. package/bin/install.js +521 -130
  6. package/bin/lib/ccline.js +18 -8
  7. package/bin/lib/gstack-claude.js +164 -0
  8. package/bin/lib/gstack-codex.js +347 -0
  9. package/bin/lib/gstack-gemini.js +140 -0
  10. package/bin/lib/pack-bootstrap.js +92 -0
  11. package/bin/lib/pack-docs.js +61 -0
  12. package/bin/lib/pack-registry.js +400 -0
  13. package/bin/lib/pack-reports.js +87 -0
  14. package/bin/lib/pack-vendor.js +82 -0
  15. package/bin/lib/style-registry.js +29 -7
  16. package/bin/lib/target-registry.js +74 -0
  17. package/bin/lib/utils.js +69 -6
  18. package/bin/lib/vendor-providers/archive.js +56 -0
  19. package/bin/lib/vendor-providers/git.js +59 -0
  20. package/bin/lib/vendor-providers/index.js +91 -0
  21. package/bin/lib/vendor-providers/local-dir.js +55 -0
  22. package/bin/lib/vendor-providers/shared.js +86 -0
  23. package/bin/packs.js +581 -0
  24. package/config/AGENTS.md +0 -2
  25. package/config/CLAUDE.md +43 -326
  26. package/config/codex-config.example.toml +26 -20
  27. package/config/gemini-settings.example.json +6 -0
  28. package/config/instruction.md +87 -0
  29. package/output-styles/abyss-command.md +7 -30
  30. package/output-styles/abyss-concise.md +11 -52
  31. package/output-styles/abyss-cultivator.md +20 -249
  32. package/output-styles/abyss-ritual.md +11 -45
  33. package/output-styles/index.json +20 -4
  34. package/package.json +26 -14
  35. package/packs/abyss/manifest.json +25 -0
  36. package/packs/gstack/manifest.json +151 -0
  37. package/skills/SKILL.md +33 -237
  38. package/skills/domains/frontend-design/agents/openai.yaml +1 -1
  39. package/skills/run_skill.js +25 -3
  40. package/skills/tools/gen-docs/agents/openai.yaml +1 -1
  41. package/skills/tools/verify-change/agents/openai.yaml +1 -1
  42. package/skills/tools/verify-module/agents/openai.yaml +1 -1
  43. package/skills/tools/verify-quality/agents/openai.yaml +1 -1
  44. package/skills/tools/verify-security/agents/openai.yaml +1 -1
  45. package/skills/tools/override-refusal/SKILL.md +0 -53
  46. package/skills/tools/override-refusal/agents/openai.yaml +0 -4
  47. package/skills/tools/override-refusal/scripts/refusal_rewriter.js +0 -226
package/bin/install.js CHANGED
@@ -15,18 +15,36 @@ if (parseInt(process.versions.node) < parseInt(MIN_NODE)) {
15
15
  process.exit(1);
16
16
  }
17
17
  const PKG_ROOT = fs.realpathSync(path.join(__dirname, '..'));
18
- const { shouldSkip, copyRecursive, rmSafe, deepMergeNew, printMergeLog } =
18
+ const { shouldSkip, copyRecursive, rmSafe, deepMergeNew, printMergeLog, formatActionableError } =
19
19
  require(path.join(__dirname, 'lib', 'utils.js'));
20
20
  const {
21
21
  collectInvocableSkills,
22
22
  } = require(path.join(__dirname, 'lib', 'skill-registry.js'));
23
+ const {
24
+ resolveProjectPacks,
25
+ selectProjectPacksForInstall,
26
+ readProjectPackLock,
27
+ } = require(path.join(__dirname, 'lib', 'pack-registry.js'));
28
+ const { syncProjectBootstrapArtifacts } = require(path.join(__dirname, 'lib', 'pack-bootstrap.js'));
29
+ const { writeReportArtifact } = require(path.join(__dirname, 'lib', 'pack-reports.js'));
30
+ const {
31
+ listInstallTargets,
32
+ listTargetNames,
33
+ isSupportedTarget,
34
+ getManagedRootRelativeDir,
35
+ formatTargetList,
36
+ } = require(path.join(__dirname, 'lib', 'target-registry.js'));
23
37
  const {
24
38
  listStyles,
25
39
  getDefaultStyle,
26
40
  resolveStyle,
27
- renderCodexAgents,
41
+ renderGeminiContext,
28
42
  } = require(path.join(__dirname, 'lib', 'style-registry.js'));
29
43
  const { detectCclineBin, installCcline: _installCcline } = require(path.join(__dirname, 'lib', 'ccline.js'));
44
+ const { installGstackClaudePack } = require(path.join(__dirname, 'lib', 'gstack-claude.js'));
45
+ const { installGstackGeminiPack } = require(path.join(__dirname, 'lib', 'gstack-gemini.js'));
46
+
47
+ const { installGstackCodexPack } = require(path.join(__dirname, 'lib', 'gstack-codex.js'));
30
48
  const {
31
49
  detectCodexAuth: detectCodexAuthImpl,
32
50
  getCodexCoreFiles,
@@ -38,6 +56,12 @@ const {
38
56
  detectClaudeAuth: detectClaudeAuthImpl,
39
57
  postClaude: postClaudeFlow,
40
58
  } = require(path.join(__dirname, 'adapters', 'claude.js'));
59
+ const {
60
+ GEMINI_SETTINGS_TEMPLATE,
61
+ getGeminiCoreFiles,
62
+ detectGeminiAuth: detectGeminiAuthImpl,
63
+ postGemini: postGeminiFlow,
64
+ } = require(path.join(__dirname, 'adapters', 'gemini.js'));
41
65
 
42
66
  // ── ANSI ──
43
67
 
@@ -93,7 +117,41 @@ function detectCodexAuth() {
93
117
  return detectCodexAuthImpl({ HOME, warn });
94
118
  }
95
119
 
96
- // ── 模板 ──
120
+ function detectGeminiAuth(settings) {
121
+ return detectGeminiAuthImpl({ settings, HOME, warn });
122
+ }
123
+
124
+ function resolveManagedRootDir(tgt, rootName = tgt) {
125
+ return path.join(HOME, getManagedRootRelativeDir(rootName));
126
+ }
127
+
128
+ function normalizeManifestEntry(entry, defaultRoot) {
129
+ if (typeof entry === 'string') return { root: defaultRoot, path: entry };
130
+ if (entry && typeof entry === 'object' && typeof entry.path === 'string') {
131
+ return { root: entry.root || defaultRoot, path: entry.path };
132
+ }
133
+ throw new Error('manifest 条目格式无效');
134
+ }
135
+
136
+ function pushManifestEntry(list, rootName, relPath) {
137
+ list.push({ root: rootName, path: relPath });
138
+ }
139
+
140
+ function pushPackReport(manifest, report) {
141
+ if (!manifest.pack_reports) manifest.pack_reports = [];
142
+ manifest.pack_reports.push(report);
143
+ }
144
+
145
+ function resolveEffectivePackSource(sourceMode, installResult) {
146
+ return (installResult && installResult.sourceMode) || sourceMode || 'pinned';
147
+ }
148
+
149
+ function manifestLabel(entry, defaultRoot) {
150
+ const normalized = normalizeManifestEntry(entry, defaultRoot);
151
+ return normalized.root === defaultRoot
152
+ ? normalized.path
153
+ : `${normalized.root}/${normalized.path}`;
154
+ }
97
155
 
98
156
  // ── CLI 参数 ──
99
157
 
@@ -115,8 +173,8 @@ for (let i = 0; i < args.length; i++) {
115
173
  console.log(`${c.b('用法:')} npx code-abyss [选项]
116
174
 
117
175
  ${c.b('选项:')}
118
- --target ${c.cyn('<claude|codex>')} 安装目标
119
- --uninstall ${c.cyn('<claude|codex>')} 卸载目标
176
+ --target ${c.cyn(`<${formatTargetList('|')}>`)} 安装目标
177
+ --uninstall ${c.cyn(`<${formatTargetList('|')}>`)} 卸载目标
120
178
  --style ${c.cyn('<slug>')} 指定输出风格
121
179
  --list-styles 列出可用输出风格
122
180
  --yes, -y 全自动模式
@@ -137,27 +195,51 @@ ${c.b('示例:')}
137
195
  // ── 卸载 ──
138
196
 
139
197
  function runUninstall(tgt) {
140
- if (!['claude', 'codex'].includes(tgt)) { fail('--uninstall 必须是 claude 或 codex'); process.exit(1); }
141
- const targetDir = path.join(HOME, `.${tgt}`);
198
+ if (!isSupportedTarget(tgt)) {
199
+ fail(formatActionableError(`--uninstall 必须是 ${listTargetNames().join('、')}`, 'Try: npx code-abyss --uninstall claude'));
200
+ process.exit(1);
201
+ }
202
+ const targetDir = resolveManagedRootDir(tgt);
142
203
  const backupDir = path.join(targetDir, '.sage-backup');
143
204
  const manifestPath = path.join(backupDir, 'manifest.json');
144
205
  if (!fs.existsSync(manifestPath)) { fail(`未找到安装记录: ${manifestPath}`); process.exit(1); }
145
206
 
146
207
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
147
- if (manifest.manifest_version && manifest.manifest_version > 1) {
208
+ if (manifest.manifest_version && manifest.manifest_version > 2) {
148
209
  fail(`manifest 版本 ${manifest.manifest_version} 不兼容,请升级 code-abyss 后再卸载`);
149
210
  process.exit(1);
150
211
  }
151
212
  divider(`卸载 Code Abyss v${manifest.version}`);
213
+ if (Array.isArray(manifest.pack_reports) && manifest.pack_reports.length > 0) {
214
+ console.log(` ${c.b('Packs:')}`);
215
+ manifest.pack_reports.forEach((report) => {
216
+ const source = report.source ? ` source=${report.source}` : '';
217
+ const reason = report.reason ? ` reason=${report.reason}` : '';
218
+ console.log(` ${report.pack}@${report.host} ${report.status || 'installed'}${source}${reason}`);
219
+ });
220
+ }
152
221
 
153
- (manifest.installed || []).forEach(f => {
154
- const p = path.join(targetDir, f);
155
- if (fs.existsSync(p)) { rmSafe(p); console.log(` ${c.red('✘')} ${f}`); }
222
+ (manifest.installed || []).forEach((entry) => {
223
+ const normalized = normalizeManifestEntry(entry, tgt);
224
+ const installRoot = resolveManagedRootDir(tgt, normalized.root);
225
+ const targetPath = path.join(installRoot, normalized.path);
226
+ if (fs.existsSync(targetPath)) {
227
+ rmSafe(targetPath);
228
+ console.log(` ${c.red('✘')} ${manifestLabel(entry, tgt)}`);
229
+ }
156
230
  });
157
- (manifest.backups || []).forEach(f => {
158
- const bp = path.join(backupDir, f);
159
- const tp = path.join(targetDir, f);
160
- if (fs.existsSync(bp)) { fs.renameSync(bp, tp); ok(`恢复: ${f}`); }
231
+ (manifest.backups || []).forEach((entry) => {
232
+ const normalized = normalizeManifestEntry(entry, tgt);
233
+ const backupPath = path.join(backupDir, normalized.root, normalized.path);
234
+ const legacyBackupPath = path.join(backupDir, normalized.path);
235
+ const sourcePath = fs.existsSync(backupPath) ? backupPath : legacyBackupPath;
236
+ const restoreRoot = resolveManagedRootDir(tgt, normalized.root);
237
+ const restorePath = path.join(restoreRoot, normalized.path);
238
+ if (fs.existsSync(sourcePath)) {
239
+ fs.mkdirSync(path.dirname(restorePath), { recursive: true });
240
+ fs.renameSync(sourcePath, restorePath);
241
+ ok(`恢复: ${manifestLabel(entry, tgt)}`);
242
+ }
161
243
  });
162
244
 
163
245
  rmSafe(backupDir);
@@ -173,24 +255,17 @@ function scanInvocableSkills(skillsDir) {
173
255
  return collectInvocableSkills(skillsDir);
174
256
  }
175
257
 
176
- const INVOCABLE_TARGETS = {
177
- claude: {
178
- dir: 'commands',
179
- label: '斜杠命令',
180
- skillRoot: '~/.claude/skills',
181
- },
182
- codex: {
183
- dir: 'prompts',
184
- label: 'custom prompts',
185
- skillRoot: '~/.codex/skills',
186
- },
258
+ const CLAUDE_COMMAND_TARGET = {
259
+ dir: 'commands',
260
+ label: '斜杠命令',
261
+ skillRoot: '~/.claude/skills',
187
262
  };
188
263
 
189
- function getInvocableTarget(targetName) {
190
- const targetCfg = INVOCABLE_TARGETS[targetName];
191
- if (!targetCfg) throw new Error(`不支持的 invocable target: ${targetName}`);
192
- return targetCfg;
193
- }
264
+ const GEMINI_COMMAND_TARGET = {
265
+ dir: 'commands',
266
+ label: 'Gemini commands',
267
+ skillRoot: '~/.gemini/skills',
268
+ };
194
269
 
195
270
  function getSkillPath(skillRoot, skillRelPath) {
196
271
  return skillRelPath
@@ -212,23 +287,20 @@ function buildCommandFrontmatter(skill) {
212
287
  return lines;
213
288
  }
214
289
 
215
- function buildSkillArtifactSpec(skill, targetName) {
216
- const targetCfg = getInvocableTarget(targetName);
290
+ function buildClaudeCommandSpec(skill) {
217
291
  const runtimeType = skill.runtimeType || 'knowledge';
218
292
  const allowedTools = Array.isArray(skill.allowedTools)
219
293
  ? skill.allowedTools.join(', ')
220
294
  : (skill.allowedTools || 'Read');
221
295
  return {
222
- targetName,
223
- targetCfg,
224
296
  name: skill.name,
225
297
  description: skill.description,
226
298
  argumentHint: skill.argumentHint || '',
227
299
  allowedTools,
228
300
  relPath: skill.relPath,
229
301
  runtimeType,
230
- scriptRunner: `node ${targetCfg.skillRoot}/run_skill.js ${skill.name} $ARGUMENTS`,
231
- skillPath: getSkillPath(targetCfg.skillRoot, skill.relPath),
302
+ scriptRunner: `node ${CLAUDE_COMMAND_TARGET.skillRoot}/run_skill.js ${skill.name} $ARGUMENTS`,
303
+ skillPath: getSkillPath(CLAUDE_COMMAND_TARGET.skillRoot, skill.relPath),
232
304
  };
233
305
  }
234
306
 
@@ -248,31 +320,6 @@ function buildClaudeBody(spec) {
248
320
  return lines;
249
321
  }
250
322
 
251
- function buildCodexPromptBody(spec) {
252
- const lines = [];
253
- if (spec.argumentHint) lines.push(`Arguments: ${spec.argumentHint}`, '');
254
- lines.push(`Read \`${spec.skillPath}\` before acting.`, '');
255
- if (spec.runtimeType === 'scripted') {
256
- lines.push(`Then run \`${spec.scriptRunner}\`.`);
257
- lines.push('Do not stop between steps unless blocked by permissions or missing required inputs.');
258
- lines.push('Use the skill guidance plus script output to complete the task end-to-end.');
259
- return lines;
260
- }
261
-
262
- lines.push('Use that skill as the authoritative playbook for the task.');
263
- lines.push('Respond with concrete actions instead of generic advice.');
264
- return lines;
265
- }
266
-
267
- function generateInvocableContent(skill, targetName) {
268
- const spec = buildSkillArtifactSpec(skill, targetName);
269
- const lines = targetName === 'claude' ? buildCommandFrontmatter(spec) : [];
270
- const body = targetName === 'claude'
271
- ? buildClaudeBody(spec)
272
- : buildCodexPromptBody(spec);
273
- return [...lines, ...body, ''].join('\n');
274
- }
275
-
276
323
  function normalizeGeneratedSkill(meta, skillRelPath, runtimeType) {
277
324
  return {
278
325
  ...meta,
@@ -285,19 +332,67 @@ function normalizeGeneratedSkill(meta, skillRelPath, runtimeType) {
285
332
  }
286
333
 
287
334
  function generateCommandContent(meta, skillRelPath, runtimeType = 'knowledge') {
288
- return generateInvocableContent(normalizeGeneratedSkill(meta, skillRelPath, runtimeType), 'claude');
335
+ const skill = normalizeGeneratedSkill(meta, skillRelPath, runtimeType);
336
+ const spec = buildClaudeCommandSpec(skill);
337
+ return [...buildCommandFrontmatter(spec), ...buildClaudeBody(spec), ''].join('\n');
289
338
  }
290
339
 
291
- function generatePromptContent(meta, skillRelPath, runtimeType = 'knowledge') {
292
- return generateInvocableContent(normalizeGeneratedSkill(meta, skillRelPath, runtimeType), 'codex');
340
+ function buildGeminiCommandSpec(skill) {
341
+ const runtimeType = skill.runtimeType || 'knowledge';
342
+ return {
343
+ name: skill.name,
344
+ description: skill.description || '',
345
+ relPath: skill.relPath,
346
+ runtimeType,
347
+ scriptRunner: `node ${GEMINI_COMMAND_TARGET.skillRoot}/run_skill.js ${skill.name}`,
348
+ skillPath: getSkillPath(GEMINI_COMMAND_TARGET.skillRoot, skill.relPath),
349
+ };
350
+ }
351
+
352
+ function escapeTomlMultiline(value) {
353
+ return String(value || '').replace(/"""/g, '\"\"\"').trim();
293
354
  }
294
355
 
295
- function installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest, targetName) {
356
+ function buildGeminiPromptBody(spec) {
357
+ const lines = [
358
+ `Read \`${spec.skillPath}\` before acting.`,
359
+ '',
360
+ 'If Gemini CLI appended the raw command invocation after these instructions, parse any extra arguments from that appended invocation before acting.',
361
+ '',
362
+ ];
363
+
364
+ if (spec.runtimeType === 'scripted') {
365
+ lines.push(`Then run \`${spec.scriptRunner} <parsed-arguments>\` and complete the task end-to-end.`);
366
+ lines.push('Do not stop between steps unless blocked by permissions or missing required input.');
367
+ } else {
368
+ lines.push('Use that skill as the authoritative playbook for the task.');
369
+ lines.push('Respond with concrete actions instead of generic advice.');
370
+ }
371
+
372
+ return lines.join('\n').trim();
373
+ }
374
+
375
+ function generateGeminiCommandContent(meta, skillRelPath, runtimeType = 'knowledge') {
376
+ const skill = normalizeGeneratedSkill(meta, skillRelPath, runtimeType);
377
+ const spec = buildGeminiCommandSpec(skill);
378
+ const description = escapeTomlMultiline(spec.description).replace(/"/g, '\\"');
379
+ const prompt = escapeTomlMultiline(buildGeminiPromptBody(spec));
380
+ return [
381
+ `description = "${description}"`,
382
+ 'prompt = """',
383
+ prompt,
384
+ '"""',
385
+ '',
386
+ ].join('\n');
387
+ }
388
+
389
+
390
+ function installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest) {
296
391
  const skills = collectInvocableSkills(skillsSrcDir);
297
392
  if (skills.length === 0) return 0;
393
+ const rootName = manifest.target || 'claude';
298
394
 
299
- const targetCfg = getInvocableTarget(targetName);
300
- const installDir = path.join(targetDir, targetCfg.dir);
395
+ const installDir = path.join(targetDir, CLAUDE_COMMAND_TARGET.dir);
301
396
  fs.mkdirSync(installDir, { recursive: true });
302
397
 
303
398
  let totalFiles = 0;
@@ -309,53 +404,95 @@ function installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest,
309
404
  names.forEach((cmdName) => {
310
405
  const fileName = `${cmdName}.md`;
311
406
  const destFile = path.join(installDir, fileName);
312
- const relFile = path.posix.join(targetCfg.dir, fileName);
407
+ const relFile = path.posix.join(CLAUDE_COMMAND_TARGET.dir, fileName);
313
408
 
314
409
  if (fs.existsSync(destFile)) {
315
- const backupSubdir = path.join(backupDir, targetCfg.dir);
410
+ const backupSubdir = path.join(backupDir, rootName, CLAUDE_COMMAND_TARGET.dir);
316
411
  fs.mkdirSync(backupSubdir, { recursive: true });
317
412
  fs.copyFileSync(destFile, path.join(backupSubdir, fileName));
318
- manifest.backups.push(relFile);
413
+ pushManifestEntry(manifest.backups, rootName, relFile);
319
414
  info(`备份: ${c.d(relFile)}`);
320
415
  }
321
416
 
322
- const content = generateInvocableContent(skill, targetName);
417
+ const content = generateCommandContent(skill, skill.relPath, skill.runtimeType);
323
418
  fs.writeFileSync(destFile, content);
324
- manifest.installed.push(relFile);
419
+ pushManifestEntry(manifest.installed, rootName, relFile);
325
420
  totalFiles++;
326
421
  });
327
422
  });
328
423
 
329
- ok(`${targetCfg.dir}/ ${c.d(`(自动生成 ${totalFiles} 个 ${targetCfg.label})`)}`);
424
+ ok(`${CLAUDE_COMMAND_TARGET.dir}/ ${c.d(`(自动生成 ${totalFiles} 个 ${CLAUDE_COMMAND_TARGET.label})`)}`);
330
425
  return skills.length;
331
426
  }
332
427
 
333
428
  function installGeneratedCommands(skillsSrcDir, targetDir, backupDir, manifest) {
334
- return installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest, 'claude');
429
+ return installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest);
335
430
  }
336
431
 
337
- function installGeneratedPrompts(skillsSrcDir, targetDir, backupDir, manifest) {
338
- return installGeneratedArtifacts(skillsSrcDir, targetDir, backupDir, manifest, 'codex');
432
+ function installGeneratedGeminiCommands(skillsSrcDir, targetDir, backupDir, manifest) {
433
+ const skills = collectInvocableSkills(skillsSrcDir);
434
+ if (skills.length === 0) return 0;
435
+
436
+ const installDir = path.join(targetDir, GEMINI_COMMAND_TARGET.dir);
437
+ fs.mkdirSync(installDir, { recursive: true });
438
+ let totalFiles = 0;
439
+
440
+ skills.forEach((skill) => {
441
+ const names = [skill.name, ...(skill.aliases || [])];
442
+ names.forEach((cmdName) => {
443
+ const fileName = `${cmdName}.toml`;
444
+ const destFile = path.join(installDir, fileName);
445
+ const relFile = path.posix.join(GEMINI_COMMAND_TARGET.dir, fileName);
446
+
447
+ if (fs.existsSync(destFile)) {
448
+ const backupSubdir = path.join(backupDir, 'gemini', GEMINI_COMMAND_TARGET.dir);
449
+ fs.mkdirSync(backupSubdir, { recursive: true });
450
+ fs.copyFileSync(destFile, path.join(backupSubdir, fileName));
451
+ pushManifestEntry(manifest.backups, 'gemini', relFile);
452
+ info(`备份: ${c.d(relFile)}`);
453
+ }
454
+
455
+ const content = generateGeminiCommandContent(skill, skill.relPath, skill.runtimeType);
456
+ fs.writeFileSync(destFile, content);
457
+ pushManifestEntry(manifest.installed, 'gemini', relFile);
458
+ totalFiles++;
459
+ });
460
+ });
461
+
462
+ ok(`${GEMINI_COMMAND_TARGET.dir}/ ${c.d(`(自动生成 ${totalFiles} 个 ${GEMINI_COMMAND_TARGET.label})`)}`);
463
+ return totalFiles;
464
+ }
465
+
466
+ function installGeminiContext(targetDir, backupDir, manifest, selectedStyle) {
467
+ const relPath = 'GEMINI.md';
468
+ backupManagedPathIfExists('gemini', 'gemini', backupDir, relPath, manifest);
469
+ const destPath = path.join(targetDir, relPath);
470
+ const content = renderGeminiContext(PKG_ROOT, selectedStyle.slug);
471
+ fs.writeFileSync(destPath, content);
472
+ pushManifestEntry(manifest.installed, 'gemini', relPath);
473
+ ok(`${relPath} ${c.d(`(动态生成: ${selectedStyle.slug})`)}`);
339
474
  }
340
475
 
341
- function backupPathIfExists(targetDir, backupDir, relPath, manifest) {
342
- const targetPath = path.join(targetDir, relPath);
476
+
477
+ function backupManagedPathIfExists(tgt, rootName, backupDir, relPath, manifest) {
478
+ const targetRoot = resolveManagedRootDir(tgt, rootName);
479
+ const targetPath = path.join(targetRoot, relPath);
343
480
  if (!fs.existsSync(targetPath)) return false;
344
481
 
345
- const backupPath = path.join(backupDir, relPath);
482
+ const backupPath = path.join(backupDir, rootName, relPath);
346
483
  rmSafe(backupPath);
347
484
  copyRecursive(targetPath, backupPath);
348
- manifest.backups.push(relPath);
349
- info(`备份: ${c.d(relPath)}`);
485
+ pushManifestEntry(manifest.backups, rootName, relPath);
486
+ info(`备份: ${c.d(rootName === tgt ? relPath : `${rootName}/${relPath}`)}`);
350
487
  return true;
351
488
  }
352
489
 
353
- function pruneLegacyCodexSettings(targetDir, backupDir, manifest) {
490
+ function pruneLegacyCodexSettings(tgt, backupDir, manifest) {
354
491
  const relPath = 'settings.json';
355
- const settingsPath = path.join(targetDir, relPath);
492
+ const settingsPath = path.join(resolveManagedRootDir(tgt, 'codex'), relPath);
356
493
  if (!fs.existsSync(settingsPath)) return null;
357
494
 
358
- backupPathIfExists(targetDir, backupDir, relPath, manifest);
495
+ backupManagedPathIfExists(tgt, 'codex', backupDir, relPath, manifest);
359
496
  rmSafe(settingsPath);
360
497
  warn('移除 legacy settings.json(Codex 已改用 config.toml)');
361
498
  return settingsPath;
@@ -374,7 +511,56 @@ function printStyleCatalog() {
374
511
  console.log('');
375
512
  }
376
513
 
514
+ async function resolveProjectPackPlan(targetName) {
515
+ const projectPacks = resolveProjectPacks(process.cwd(), targetName);
516
+ if (!projectPacks.path) {
517
+ return {
518
+ ...projectPacks,
519
+ selected: [],
520
+ optionalSelected: [],
521
+ sources: {},
522
+ };
523
+ }
524
+
525
+ let confirmOptional = null;
526
+ if (projectPacks.optionalPolicy === 'prompt' && projectPacks.optional.length > 0 && !autoYes) {
527
+ const { confirm } = await import('@inquirer/prompts');
528
+ confirmOptional = async (optionalPacks) => confirm({
529
+ message: `当前仓库声明了 optional packs: ${optionalPacks.join(', ')},是否一并安装?`,
530
+ default: true,
531
+ });
532
+ }
533
+
534
+ const selection = await selectProjectPacksForInstall(projectPacks, {
535
+ autoYes,
536
+ confirm: confirmOptional,
537
+ });
538
+
539
+ return {
540
+ ...projectPacks,
541
+ ...selection,
542
+ };
543
+ }
544
+
377
545
  async function resolveInstallStyle(targetName) {
546
+ if (targetName === 'codex') {
547
+ if (requestedStyleSlug) {
548
+ warn('Codex 已改为 skills-only,忽略 --style(不再生成 ~/.codex/AGENTS.md)');
549
+ }
550
+ return getDefaultStyle(PKG_ROOT, 'claude');
551
+ }
552
+
553
+ if (targetName === 'gemini') {
554
+ if (requestedStyleSlug) {
555
+ const requested = resolveStyle(PKG_ROOT, requestedStyleSlug, 'gemini') || resolveStyle(PKG_ROOT, requestedStyleSlug, 'claude');
556
+ if (!requested) {
557
+ throw new Error(`未知输出风格: ${requestedStyleSlug}`);
558
+ }
559
+ return requested;
560
+ }
561
+ return getDefaultStyle(PKG_ROOT, 'claude');
562
+ }
563
+
378
564
  if (requestedStyleSlug) {
379
565
  const style = resolveStyle(PKG_ROOT, requestedStyleSlug, targetName);
380
566
  if (!style) {
@@ -401,36 +587,36 @@ async function resolveInstallStyle(targetName) {
401
587
  return resolveStyle(PKG_ROOT, slug, targetName);
402
588
  }
403
589
 
404
- function installCodexAgents(targetDir, backupDir, manifest, selectedStyle) {
405
- const relPath = 'AGENTS.md';
406
- backupPathIfExists(targetDir, backupDir, relPath, manifest);
407
- const destPath = path.join(targetDir, relPath);
408
- const content = renderCodexAgents(PKG_ROOT, selectedStyle.slug);
409
- fs.writeFileSync(destPath, content);
410
- manifest.installed.push(relPath);
411
- ok(`${relPath} ${c.d(`(动态生成: ${selectedStyle.slug})`)}`);
412
- }
413
-
414
- function installCore(tgt, selectedStyle) {
415
- const targetDir = path.join(HOME, `.${tgt}`);
590
+ function installCore(tgt, selectedStyle, packPlan) {
591
+ const targetDir = resolveManagedRootDir(tgt);
416
592
  const backupDir = path.join(targetDir, '.sage-backup');
417
593
  const manifestPath = path.join(backupDir, 'manifest.json');
418
594
 
419
- step(1, 3, `安装核心文件 ${c.cyn(targetDir)}`);
595
+ const installSummary = tgt === 'codex'
596
+ ? `${c.cyn(resolveManagedRootDir(tgt, 'codex'))} + ${c.cyn(resolveManagedRootDir(tgt, 'agents'))}`
597
+ : c.cyn(targetDir);
598
+ step(1, 3, `安装核心文件 → ${installSummary}`);
420
599
  fs.mkdirSync(backupDir, { recursive: true });
421
600
 
422
601
  const filesToInstall = tgt === 'codex'
423
602
  ? getCodexCoreFiles()
424
- : getClaudeCoreFiles();
603
+ : tgt === 'gemini'
604
+ ? getGeminiCoreFiles()
605
+ : getClaudeCoreFiles();
425
606
 
426
607
  const manifest = {
427
- manifest_version: 1, version: VERSION, target: tgt,
428
- timestamp: new Date().toISOString(), style: selectedStyle.slug, installed: [], backups: []
608
+ manifest_version: 2, version: VERSION, target: tgt,
609
+ timestamp: new Date().toISOString(), style: selectedStyle.slug, installed: [], backups: [],
610
+ project_packs: packPlan.selected,
611
+ optional_policy: packPlan.optionalPolicy || 'auto',
612
+ pack_reports: [],
429
613
  };
430
614
 
431
- filesToInstall.forEach(({ src, dest }) => {
615
+ filesToInstall.forEach(({ src, dest, root }) => {
616
+ const rootName = root || tgt;
432
617
  const srcPath = path.join(PKG_ROOT, src);
433
- const destPath = path.join(targetDir, dest);
618
+ const destRoot = resolveManagedRootDir(tgt, rootName);
619
+ const destPath = path.join(destRoot, dest);
434
620
  if (!fs.existsSync(srcPath)) {
435
621
  if (src === 'skills') {
436
622
  fail(`核心文件缺失: ${srcPath}\n 请尝试: npm cache clean --force && npx code-abyss`);
@@ -440,22 +626,125 @@ function installCore(tgt, selectedStyle) {
440
626
  }
441
627
 
442
628
  if (fs.existsSync(destPath)) {
443
- const bp = path.join(backupDir, dest);
444
- rmSafe(bp); copyRecursive(destPath, bp); manifest.backups.push(dest);
445
- info(`备份: ${c.d(dest)}`);
629
+ const backupPath = path.join(backupDir, rootName, dest);
630
+ rmSafe(backupPath);
631
+ copyRecursive(destPath, backupPath);
632
+ pushManifestEntry(manifest.backups, rootName, dest);
633
+ info(`备份: ${c.d(rootName === tgt ? dest : `${rootName}/${dest}`)}`);
446
634
  }
447
- ok(dest);
448
- rmSafe(destPath); copyRecursive(srcPath, destPath); manifest.installed.push(dest);
635
+ ok(rootName === tgt ? dest : `${rootName}/${dest}`);
636
+ rmSafe(destPath);
637
+ copyRecursive(srcPath, destPath);
638
+ pushManifestEntry(manifest.installed, rootName, dest);
639
+ });
640
+
641
+ pushPackReport(manifest, {
642
+ pack: 'abyss',
643
+ host: tgt,
644
+ status: 'installed',
645
+ source: 'bundled',
449
646
  });
450
647
 
451
648
  // 为目标 CLI 自动生成 user-invocable artifacts
452
649
  if (tgt === 'claude') {
453
650
  const skillsSrc = path.join(PKG_ROOT, 'skills');
454
651
  installGeneratedCommands(skillsSrc, targetDir, backupDir, manifest);
652
+ if (packPlan.selected.includes('gstack')) {
653
+ const sourceMode = (packPlan.sources && packPlan.sources.gstack) || 'pinned';
654
+ const result = installGstackClaudePack({
655
+ HOME,
656
+ backupDir,
657
+ manifest,
658
+ info,
659
+ ok,
660
+ warn,
661
+ sourceMode,
662
+ projectRoot: packPlan.root,
663
+ fallback: true,
664
+ });
665
+ pushPackReport(manifest, {
666
+ pack: 'gstack',
667
+ host: 'claude',
668
+ status: result.installed ? 'installed' : 'skipped',
669
+ source: resolveEffectivePackSource(sourceMode, result),
670
+ reason: result.reason || null,
671
+ });
672
+ } else if (packPlan.required.includes('gstack') || packPlan.optional.includes('gstack')) {
673
+ const sourceMode = (packPlan.sources && packPlan.sources.gstack) || 'pinned';
674
+ pushPackReport(manifest, {
675
+ pack: 'gstack',
676
+ host: 'claude',
677
+ status: sourceMode === 'disabled' ? 'disabled' : 'skipped',
678
+ source: sourceMode,
679
+ reason: sourceMode === 'disabled' ? 'source-disabled' : `optional-policy-${packPlan.optionalPolicy || 'auto'}`,
680
+ });
681
+ }
455
682
  } else if (tgt === 'codex') {
456
- // Codex 0.117.0+ 已移除 custom prompts,skills 通过 agents/openai.yaml 注册
457
- // 不再生成 prompts/ 目录
458
- installCodexAgents(targetDir, backupDir, manifest, selectedStyle);
683
+ // Codex skills-only:不再生成 ~/.codex/AGENTS.md,项目声明的 pack 自动装入 ~/.agents/skills/
684
+ if (packPlan.selected.includes('gstack')) {
685
+ const sourceMode = (packPlan.sources && packPlan.sources.gstack) || 'pinned';
686
+ const result = installGstackCodexPack({
687
+ HOME,
688
+ backupDir,
689
+ manifest,
690
+ info,
691
+ ok,
692
+ warn,
693
+ sourceMode,
694
+ projectRoot: packPlan.root,
695
+ fallback: true,
696
+ });
697
+ pushPackReport(manifest, {
698
+ pack: 'gstack',
699
+ host: 'codex',
700
+ status: result.installed ? 'installed' : 'skipped',
701
+ source: resolveEffectivePackSource(sourceMode, result),
702
+ reason: result.reason || null,
703
+ });
704
+ } else if (packPlan.required.includes('gstack') || packPlan.optional.includes('gstack')) {
705
+ const sourceMode = (packPlan.sources && packPlan.sources.gstack) || 'pinned';
706
+ pushPackReport(manifest, {
707
+ pack: 'gstack',
708
+ host: 'codex',
709
+ status: sourceMode === 'disabled' ? 'disabled' : 'skipped',
710
+ source: sourceMode,
711
+ reason: sourceMode === 'disabled' ? 'source-disabled' : `optional-policy-${packPlan.optionalPolicy || 'auto'}`,
712
+ });
713
+ }
714
+ } else if (tgt === 'gemini') {
715
+ const skillsSrc = path.join(PKG_ROOT, 'skills');
716
+ installGeneratedGeminiCommands(skillsSrc, targetDir, backupDir, manifest);
717
+ installGeminiContext(targetDir, backupDir, manifest, selectedStyle);
718
+ if (packPlan.selected.includes('gstack')) {
719
+ const sourceMode = (packPlan.sources && packPlan.sources.gstack) || 'pinned';
720
+ const result = installGstackGeminiPack({
721
+ HOME,
722
+ backupDir,
723
+ manifest,
724
+ info,
725
+ ok,
726
+ warn,
727
+ sourceMode,
728
+ projectRoot: packPlan.root,
729
+ fallback: true,
730
+ });
731
+ pushPackReport(manifest, {
732
+ pack: 'gstack',
733
+ host: 'gemini',
734
+ status: result.installed ? 'installed' : 'skipped',
735
+ source: resolveEffectivePackSource(sourceMode, result),
736
+ reason: result.reason || null,
737
+ });
738
+ } else if (packPlan.required.includes('gstack') || packPlan.optional.includes('gstack')) {
739
+ const sourceMode = (packPlan.sources && packPlan.sources.gstack) || 'pinned';
740
+ pushPackReport(manifest, {
741
+ pack: 'gstack',
742
+ host: 'gemini',
743
+ status: sourceMode === 'disabled' ? 'disabled' : 'skipped',
744
+ source: sourceMode,
745
+ reason: sourceMode === 'disabled' ? 'source-disabled' : `optional-policy-${packPlan.optionalPolicy || 'auto'}`,
746
+ });
747
+ }
459
748
  }
460
749
 
461
750
  let settingsPath = null;
@@ -469,15 +758,31 @@ function installCore(tgt, selectedStyle) {
469
758
  warn('settings.json 解析失败,将使用空配置');
470
759
  settings = {};
471
760
  }
472
- fs.copyFileSync(settingsPath, path.join(backupDir, 'settings.json'));
473
- manifest.backups.push('settings.json');
761
+ fs.mkdirSync(path.join(backupDir, 'claude'), { recursive: true });
762
+ fs.copyFileSync(settingsPath, path.join(backupDir, 'claude', 'settings.json'));
763
+ pushManifestEntry(manifest.backups, 'claude', 'settings.json');
474
764
  }
475
765
  settings.outputStyle = selectedStyle.slug;
476
766
  ok(`outputStyle = ${c.mag(selectedStyle.slug)}`);
477
767
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
478
- manifest.installed.push('settings.json');
768
+ pushManifestEntry(manifest.installed, 'claude', 'settings.json');
769
+ } else if (tgt === 'gemini') {
770
+ settingsPath = path.join(targetDir, 'settings.json');
771
+ if (fs.existsSync(settingsPath)) {
772
+ try {
773
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
774
+ } catch (e) {
775
+ warn('Gemini settings.json 解析失败,将使用空配置');
776
+ settings = {};
777
+ }
778
+ fs.mkdirSync(path.join(backupDir, 'gemini'), { recursive: true });
779
+ fs.copyFileSync(settingsPath, path.join(backupDir, 'gemini', 'settings.json'));
780
+ pushManifestEntry(manifest.backups, 'gemini', 'settings.json');
781
+ }
782
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
783
+ pushManifestEntry(manifest.installed, 'gemini', 'settings.json');
479
784
  } else {
480
- pruneLegacyCodexSettings(targetDir, backupDir, manifest);
785
+ pruneLegacyCodexSettings(tgt, backupDir, manifest);
481
786
  }
482
787
 
483
788
  fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
@@ -486,7 +791,7 @@ function installCore(tgt, selectedStyle) {
486
791
  const uDest = path.join(targetDir, '.sage-uninstall.js');
487
792
  if (fs.existsSync(uSrc)) { fs.copyFileSync(uSrc, uDest); fs.chmodSync(uDest, '755'); }
488
793
 
489
- return { targetDir, settingsPath, settings, manifest, manifestPath };
794
+ return { targetDir, settingsPath, settings, manifest, manifestPath, packPlan };
490
795
  }
491
796
 
492
797
  // ── Claude 后续 ──
@@ -523,6 +828,21 @@ async function postCodex() {
523
828
  });
524
829
  }
525
830
 
831
+ async function postGemini(ctx) {
832
+ await postGeminiFlow({
833
+ settingsPath: ctx.settingsPath,
834
+ settings: ctx.settings,
835
+ autoYes,
836
+ HOME,
837
+ PKG_ROOT,
838
+ step,
839
+ ok,
840
+ warn,
841
+ info,
842
+ c,
843
+ });
844
+ }
845
+
526
846
  // ── 主流程 ──
527
847
 
528
848
  async function main() {
@@ -536,12 +856,20 @@ async function main() {
536
856
  banner();
537
857
 
538
858
  if (target) {
539
- if (!['claude', 'codex'].includes(target)) { fail('--target 必须是 claude 或 codex'); process.exit(1); }
859
+ if (!isSupportedTarget(target)) {
860
+ fail(formatActionableError(`--target 必须是 ${listTargetNames().join('、')}`, 'Try: node bin/install.js --target claude'));
861
+ process.exit(1);
862
+ }
540
863
  const style = await resolveInstallStyle(target);
864
+ const packPlan = await resolveProjectPackPlan(target);
541
865
  info(`输出风格: ${c.mag(style.slug)} (${style.label})`);
542
- const ctx = installCore(target, style);
866
+ if (packPlan.path) {
867
+ info(`项目 packs: required=[${packPlan.required.join(', ')}] optional=[${packPlan.optional.join(', ')}] policy=${packPlan.optionalPolicy}`);
868
+ }
869
+ const ctx = installCore(target, style, packPlan);
543
870
  if (target === 'claude') await postClaude(ctx);
544
- else await postCodex();
871
+ else if (target === 'codex') await postCodex();
872
+ else await postGemini(ctx);
545
873
  finish(ctx);
546
874
  return;
547
875
  }
@@ -549,43 +877,106 @@ async function main() {
549
877
  const { select } = await import('@inquirer/prompts');
550
878
  const action = await select({
551
879
  message: '请选择操作',
552
- choices: [
553
- { name: `安装到 Claude Code ${c.d('(~/.claude/')}${c.d(')')}`, value: 'install-claude' },
554
- { name: `安装到 Codex CLI ${c.d('(~/.codex/')}${c.d(')')}`, value: 'install-codex' },
555
- { name: `${c.red('卸载')} Claude Code`, value: 'uninstall-claude' },
556
- { name: `${c.red('卸载')} Codex CLI`, value: 'uninstall-codex' },
557
- ],
880
+ choices: listInstallTargets().flatMap((targetMeta) => {
881
+ const targetDir = resolveManagedRootDir(targetMeta.name);
882
+ return [
883
+ { name: `安装到 ${targetMeta.actionLabel} ${c.d(`(${targetDir})`)}`, value: `install-${targetMeta.name}` },
884
+ { name: `${c.red('卸载')} ${targetMeta.actionLabel}`, value: `uninstall-${targetMeta.name}` },
885
+ ];
886
+ }),
558
887
  });
559
888
 
560
889
  switch (action) {
561
890
  case 'install-claude': {
562
891
  const style = await resolveInstallStyle('claude');
892
+ const packPlan = await resolveProjectPackPlan('claude');
563
893
  info(`输出风格: ${c.mag(style.slug)} (${style.label})`);
564
- const ctx = installCore('claude', style);
894
+ if (packPlan.path) {
895
+ info(`项目 packs: required=[${packPlan.required.join(', ')}] optional=[${packPlan.optional.join(', ')}] policy=${packPlan.optionalPolicy}`);
896
+ }
897
+ const ctx = installCore('claude', style, packPlan);
565
898
  await postClaude(ctx);
566
899
  finish(ctx); break;
567
900
  }
568
901
  case 'install-codex': {
569
902
  const style = await resolveInstallStyle('codex');
903
+ const packPlan = await resolveProjectPackPlan('codex');
570
904
  info(`输出风格: ${c.mag(style.slug)} (${style.label})`);
571
- const ctx = installCore('codex', style);
905
+ if (packPlan.path) {
906
+ info(`项目 packs: required=[${packPlan.required.join(', ')}] optional=[${packPlan.optional.join(', ')}] policy=${packPlan.optionalPolicy}`);
907
+ }
908
+ const ctx = installCore('codex', style, packPlan);
572
909
  await postCodex();
573
910
  finish(ctx); break;
574
911
  }
912
+ case 'install-gemini': {
913
+ const style = await resolveInstallStyle('gemini');
914
+ const packPlan = await resolveProjectPackPlan('gemini');
915
+ info(`输出风格: ${c.mag(style.slug)} (${style.label})`);
916
+ const ctx = installCore('gemini', style, packPlan);
917
+ await postGemini(ctx);
918
+ finish(ctx); break;
919
+ }
575
920
  case 'uninstall-claude': runUninstall('claude'); break;
576
921
  case 'uninstall-codex': runUninstall('codex'); break;
922
+ case 'uninstall-gemini': runUninstall('gemini'); break;
577
923
  }
578
924
  }
579
925
 
580
926
  function finish(ctx) {
581
927
  const tgt = ctx.manifest.target;
928
+ let reportPath = null;
929
+ if (ctx.packPlan && ctx.packPlan.root) {
930
+ reportPath = writeReportArtifact(ctx.packPlan.root, `install-${tgt}`, {
931
+ version: VERSION,
932
+ target: tgt,
933
+ timestamp: new Date().toISOString(),
934
+ cwd: process.cwd(),
935
+ pack_plan: {
936
+ required: ctx.packPlan.required,
937
+ optional: ctx.packPlan.optional,
938
+ selected: ctx.packPlan.selected,
939
+ optional_policy: ctx.packPlan.optionalPolicy,
940
+ sources: ctx.packPlan.sources,
941
+ },
942
+ pack_reports: ctx.manifest.pack_reports || [],
943
+ installed: ctx.manifest.installed || [],
944
+ backups: ctx.manifest.backups || [],
945
+ });
946
+ }
582
947
  divider('安装完成');
583
948
  console.log('');
584
949
  console.log(` ${c.b('目标:')} ${c.cyn(ctx.targetDir)}`);
585
950
  console.log(` ${c.b('版本:')} v${VERSION}`);
586
- if (ctx.manifest.style) {
951
+ if (ctx.manifest.style && tgt !== 'codex') {
587
952
  console.log(` ${c.b('风格:')} ${c.mag(ctx.manifest.style)}`);
588
953
  }
954
+ if (Array.isArray(ctx.manifest.project_packs) && ctx.manifest.project_packs.length > 0) {
955
+ console.log(` ${c.b('Packs:')} ${ctx.manifest.project_packs.join(', ')}`);
956
+ }
957
+ if (ctx.manifest.optional_policy) {
958
+ console.log(` ${c.b('Pack策略:')} ${ctx.manifest.optional_policy}`);
959
+ }
960
+ if (Array.isArray(ctx.manifest.pack_reports) && ctx.manifest.pack_reports.length > 0) {
961
+ ctx.manifest.pack_reports.forEach((report) => {
962
+ const source = report.source ? ` source=${report.source}` : '';
963
+ const reason = report.reason ? ` reason=${report.reason}` : '';
964
+ console.log(` ${c.b('Pack报告:')} ${report.pack}@${report.host} ${report.status}${source}${reason}`);
965
+ });
966
+ }
967
+ if (ctx.packPlan && ctx.packPlan.root) {
968
+ const projectLock = readProjectPackLock(ctx.packPlan.root);
969
+ if (projectLock) {
970
+ const bootstrap = syncProjectBootstrapArtifacts(ctx.packPlan.root, projectLock.lock);
971
+ const updatedDocs = bootstrap.docs.filter((entry) => entry.action !== 'skipped');
972
+ if (updatedDocs.length > 0) {
973
+ updatedDocs.forEach((entry) => console.log(` ${c.b('文档同步:')} ${entry.action} ${entry.filePath}`));
974
+ }
975
+ }
976
+ }
977
+ if (reportPath) {
978
+ console.log(` ${c.b('Report:')} ${reportPath}`);
979
+ }
589
980
  console.log(` ${c.b('文件:')} ${ctx.manifest.installed.length} 个安装, ${ctx.manifest.backups.length} 个备份`);
590
981
  console.log(` ${c.b('卸载:')} ${c.d(`npx code-abyss --uninstall ${tgt}`)}`);
591
982
  console.log('');
@@ -601,7 +992,7 @@ module.exports = {
601
992
  detectCclineBin, copyRecursive, shouldSkip, SETTINGS_TEMPLATE,
602
993
  scanInvocableSkills,
603
994
  generateCommandContent,
604
- generatePromptContent,
995
+ generateGeminiCommandContent,
605
996
  installGeneratedCommands,
606
- installGeneratedPrompts,
997
+ installGeneratedGeminiCommands,
607
998
  };