@uniswap/ai-toolkit-nx-claude 0.5.28 → 0.5.30-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/cli-generator.cjs +28 -59
  2. package/dist/packages/ai-toolkit-nx-claude/src/cli-generator.d.ts +8 -10
  3. package/dist/packages/ai-toolkit-nx-claude/src/cli-generator.d.ts.map +1 -1
  4. package/dist/packages/ai-toolkit-nx-claude/src/index.d.ts +0 -1
  5. package/dist/packages/ai-toolkit-nx-claude/src/index.d.ts.map +1 -1
  6. package/generators.json +0 -15
  7. package/package.json +4 -35
  8. package/dist/content/agents/agnostic/CLAUDE.md +0 -282
  9. package/dist/content/agents/agnostic/agent-capability-analyst.md +0 -575
  10. package/dist/content/agents/agnostic/agent-optimizer.md +0 -396
  11. package/dist/content/agents/agnostic/agent-orchestrator.md +0 -475
  12. package/dist/content/agents/agnostic/cicd-agent.md +0 -301
  13. package/dist/content/agents/agnostic/claude-agent-discovery.md +0 -304
  14. package/dist/content/agents/agnostic/claude-docs-fact-checker.md +0 -435
  15. package/dist/content/agents/agnostic/claude-docs-initializer.md +0 -782
  16. package/dist/content/agents/agnostic/claude-docs-manager.md +0 -595
  17. package/dist/content/agents/agnostic/code-explainer.md +0 -269
  18. package/dist/content/agents/agnostic/code-generator.md +0 -785
  19. package/dist/content/agents/agnostic/commit-message-generator.md +0 -101
  20. package/dist/content/agents/agnostic/context-loader.md +0 -432
  21. package/dist/content/agents/agnostic/debug-assistant.md +0 -321
  22. package/dist/content/agents/agnostic/doc-writer.md +0 -536
  23. package/dist/content/agents/agnostic/feedback-collector.md +0 -165
  24. package/dist/content/agents/agnostic/infrastructure-agent.md +0 -406
  25. package/dist/content/agents/agnostic/migration-assistant.md +0 -489
  26. package/dist/content/agents/agnostic/pattern-learner.md +0 -481
  27. package/dist/content/agents/agnostic/performance-analyzer.md +0 -528
  28. package/dist/content/agents/agnostic/plan-reviewer.md +0 -173
  29. package/dist/content/agents/agnostic/planner.md +0 -235
  30. package/dist/content/agents/agnostic/pr-creator.md +0 -498
  31. package/dist/content/agents/agnostic/pr-reviewer.md +0 -142
  32. package/dist/content/agents/agnostic/prompt-engineer.md +0 -541
  33. package/dist/content/agents/agnostic/refactorer.md +0 -311
  34. package/dist/content/agents/agnostic/researcher.md +0 -349
  35. package/dist/content/agents/agnostic/security-analyzer.md +0 -1087
  36. package/dist/content/agents/agnostic/stack-splitter.md +0 -642
  37. package/dist/content/agents/agnostic/style-enforcer.md +0 -568
  38. package/dist/content/agents/agnostic/test-runner.md +0 -481
  39. package/dist/content/agents/agnostic/test-writer.md +0 -292
  40. package/dist/content/commands/agnostic/CLAUDE.md +0 -207
  41. package/dist/content/commands/agnostic/address-pr-issues.md +0 -205
  42. package/dist/content/commands/agnostic/auto-spec.md +0 -386
  43. package/dist/content/commands/agnostic/claude-docs.md +0 -409
  44. package/dist/content/commands/agnostic/claude-init-plus.md +0 -439
  45. package/dist/content/commands/agnostic/create-pr.md +0 -79
  46. package/dist/content/commands/agnostic/daily-standup.md +0 -185
  47. package/dist/content/commands/agnostic/deploy.md +0 -441
  48. package/dist/content/commands/agnostic/execute-plan.md +0 -167
  49. package/dist/content/commands/agnostic/explain-file.md +0 -303
  50. package/dist/content/commands/agnostic/explore.md +0 -82
  51. package/dist/content/commands/agnostic/fix-bug.md +0 -273
  52. package/dist/content/commands/agnostic/gen-tests.md +0 -185
  53. package/dist/content/commands/agnostic/generate-commit-message.md +0 -92
  54. package/dist/content/commands/agnostic/git-worktree-orchestrator.md +0 -647
  55. package/dist/content/commands/agnostic/implement-spec.md +0 -270
  56. package/dist/content/commands/agnostic/monitor.md +0 -581
  57. package/dist/content/commands/agnostic/perf-analyze.md +0 -214
  58. package/dist/content/commands/agnostic/plan.md +0 -453
  59. package/dist/content/commands/agnostic/refactor.md +0 -315
  60. package/dist/content/commands/agnostic/refine-linear-task.md +0 -575
  61. package/dist/content/commands/agnostic/research.md +0 -49
  62. package/dist/content/commands/agnostic/review-code.md +0 -321
  63. package/dist/content/commands/agnostic/review-plan.md +0 -109
  64. package/dist/content/commands/agnostic/review-pr.md +0 -393
  65. package/dist/content/commands/agnostic/split-stack.md +0 -705
  66. package/dist/content/commands/agnostic/update-claude-md.md +0 -401
  67. package/dist/content/commands/agnostic/work-through-pr-comments.md +0 -873
  68. package/dist/generators/add-agent/CLAUDE.md +0 -130
  69. package/dist/generators/add-agent/files/__name__.md.template +0 -37
  70. package/dist/generators/add-agent/generator.cjs +0 -640
  71. package/dist/generators/add-agent/schema.json +0 -59
  72. package/dist/generators/add-command/CLAUDE.md +0 -131
  73. package/dist/generators/add-command/files/__name__.md.template +0 -46
  74. package/dist/generators/add-command/generator.cjs +0 -643
  75. package/dist/generators/add-command/schema.json +0 -50
  76. package/dist/generators/files/src/index.ts.template +0 -1
  77. package/dist/generators/init/CLAUDE.md +0 -520
  78. package/dist/generators/init/generator.cjs +0 -3304
  79. package/dist/generators/init/schema.json +0 -180
  80. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-agent/generator.d.ts +0 -5
  81. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-agent/generator.d.ts.map +0 -1
  82. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-command/generator.d.ts +0 -5
  83. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-command/generator.d.ts.map +0 -1
  84. package/dist/packages/ai-toolkit-nx-claude/src/generators/init/generator.d.ts +0 -5
  85. package/dist/packages/ai-toolkit-nx-claude/src/generators/init/generator.d.ts.map +0 -1
  86. package/dist/packages/ai-toolkit-nx-claude/src/utils/auto-update-utils.d.ts +0 -30
  87. package/dist/packages/ai-toolkit-nx-claude/src/utils/auto-update-utils.d.ts.map +0 -1
@@ -1,3304 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
- var __commonJS = (cb, mod) => function __require() {
12
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
- };
14
- var __export = (target, all) => {
15
- for (var name in all)
16
- __defProp(target, name, { get: all[name], enumerable: true });
17
- };
18
- var __copyProps = (to, from, except, desc) => {
19
- if (from && typeof from === "object" || typeof from === "function") {
20
- for (let key of __getOwnPropNames(from))
21
- if (!__hasOwnProp.call(to, key) && key !== except)
22
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
- }
24
- return to;
25
- };
26
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
27
- // If the importer is in node compatibility mode or this is not an ESM
28
- // file that has been converted to a CommonJS file using a Babel-
29
- // compatible transform (i.e. "__esModule" has not been set), then set
30
- // "default" to the CommonJS "module.exports" for node compatibility.
31
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
32
- mod
33
- ));
34
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
-
36
- // packages/ai-toolkit-nx-claude/src/generators/addons/addon-registry.ts
37
- var addon_registry_exports = {};
38
- __export(addon_registry_exports, {
39
- getAddonById: () => getAddonById,
40
- getAvailableAddons: () => getAvailableAddons,
41
- getInstalledAddonConfig: () => getInstalledAddonConfig,
42
- isAddonInstalled: () => isAddonInstalled,
43
- isCommandMcpServer: () => isCommandMcpServer,
44
- isRemoteHostedMcpServer: () => isRemoteHostedMcpServer,
45
- validateAddonRequirements: () => validateAddonRequirements
46
- });
47
- function isCommandMcpServer(mcp) {
48
- return "command" in mcp;
49
- }
50
- function isRemoteHostedMcpServer(mcp) {
51
- return "transport" in mcp;
52
- }
53
- function getAvailableAddons() {
54
- return ADDON_REGISTRY;
55
- }
56
- function getAddonById(id) {
57
- return ADDON_REGISTRY.find((addon) => addon.id === id);
58
- }
59
- async function isAddonInstalled(addonId) {
60
- const addon = getAddonById(addonId);
61
- if (!addon) {
62
- return false;
63
- }
64
- const configs = [
65
- (0, import_path.join)((0, import_os.homedir)(), ".claude", "config.json"),
66
- (0, import_path.join)(process.cwd(), ".claude", "config.json")
67
- ];
68
- for (const configPath of configs) {
69
- if ((0, import_fs.existsSync)(configPath)) {
70
- try {
71
- const config = require(configPath);
72
- if (addon.type === "mcp-server" && config.mcpServers) {
73
- for (const [, serverConfig] of Object.entries(config.mcpServers)) {
74
- if (serverConfig && typeof serverConfig === "object" && "command" in serverConfig) {
75
- const command = serverConfig.command;
76
- const args = serverConfig.args || [];
77
- if (isCommandMcpServer(addon.mcp) && command === addon.mcp.command && args.some((arg) => arg.includes(addon.packageName))) {
78
- return true;
79
- }
80
- }
81
- }
82
- }
83
- } catch {
84
- continue;
85
- }
86
- }
87
- }
88
- return false;
89
- }
90
- async function getInstalledAddonConfig(addonId) {
91
- const addon = getAddonById(addonId);
92
- if (!addon) {
93
- return void 0;
94
- }
95
- const configs = [
96
- (0, import_path.join)((0, import_os.homedir)(), ".claude", "config.json"),
97
- (0, import_path.join)(process.cwd(), ".claude", "config.json")
98
- ];
99
- for (const configPath of configs) {
100
- if ((0, import_fs.existsSync)(configPath)) {
101
- try {
102
- const config = require(configPath);
103
- if (addon.type === "mcp-server" && config.mcpServers) {
104
- for (const [, serverConfig] of Object.entries(config.mcpServers)) {
105
- if (serverConfig && typeof serverConfig === "object" && "command" in serverConfig) {
106
- const command = serverConfig.command;
107
- const args = serverConfig.args || [];
108
- if (isCommandMcpServer(addon.mcp) && command === addon.mcp.command && args.some((arg) => arg.includes(addon.packageName))) {
109
- return serverConfig;
110
- }
111
- }
112
- }
113
- }
114
- } catch {
115
- continue;
116
- }
117
- }
118
- }
119
- return void 0;
120
- }
121
- async function validateAddonRequirements(addonId) {
122
- const addon = getAddonById(addonId);
123
- if (!addon) {
124
- return { valid: false, errors: [`Unknown addon: ${addonId}`] };
125
- }
126
- const errors = [];
127
- if (addon.requirements?.node) {
128
- const nodeVersion = process.version;
129
- if (!nodeVersion.match(/v1[89]\.\d+\.\d+/) && !nodeVersion.match(/v2\d+\.\d+\.\d+/)) {
130
- errors.push(`Node.js ${addon.requirements.node} required, found ${nodeVersion}`);
131
- }
132
- }
133
- if (addon.requirements?.commands) {
134
- const { execSync: execSync8 } = require("child_process");
135
- for (const cmd of addon.requirements.commands) {
136
- try {
137
- execSync8(`which ${cmd}`, { stdio: "ignore" });
138
- } catch {
139
- errors.push(`Required command '${cmd}' not found`);
140
- }
141
- }
142
- }
143
- return {
144
- valid: errors.length === 0,
145
- errors
146
- };
147
- }
148
- var import_fs, import_path, import_os, ADDON_REGISTRY;
149
- var init_addon_registry = __esm({
150
- "packages/ai-toolkit-nx-claude/src/generators/addons/addon-registry.ts"() {
151
- "use strict";
152
- import_fs = require("fs");
153
- import_path = require("path");
154
- import_os = require("os");
155
- ADDON_REGISTRY = [
156
- {
157
- id: "spec-workflow-mcp",
158
- name: "Spec Workflow MCP",
159
- description: "MCP server for spec-driven development workflow with dashboard support",
160
- type: "mcp-server",
161
- packageName: "@uniswap/spec-workflow-mcp",
162
- mcp: {
163
- serverName: "spec-workflow",
164
- command: "npx",
165
- args: ["@uniswap/spec-workflow-mcp@latest"],
166
- supportsDashboard: true,
167
- defaultPort: 50014
168
- },
169
- projectSetup: {
170
- repositoryUrl: "https://github.com/Uniswap/spec-workflow-mcp.git",
171
- configSourcePath: "configs",
172
- targetDirectory: ".spec-workflow"
173
- },
174
- requirements: {
175
- node: ">=22.0.0",
176
- commands: ["git", "npm"]
177
- }
178
- },
179
- {
180
- id: "graphite-mcp",
181
- name: "Graphite MCP",
182
- description: "MCP server for Graphite stacked pull request workflows",
183
- type: "mcp-server",
184
- packageName: "gt",
185
- mcp: {
186
- serverName: "graphite",
187
- command: "gt",
188
- args: ["mcp"]
189
- }
190
- },
191
- {
192
- id: "nx-mcp",
193
- name: "Nx MCP",
194
- description: "MCP server for Nx monorepo workspace management",
195
- type: "mcp-server",
196
- packageName: "nx-mcp",
197
- mcp: {
198
- serverName: "nx-mcp",
199
- command: "npx",
200
- args: ["-y", "nx-mcp@latest"]
201
- }
202
- },
203
- {
204
- id: "slack-mcp",
205
- name: "Slack MCP",
206
- description: "MCP server for Slack workspace integration",
207
- type: "mcp-server",
208
- packageName: "slack-mcp",
209
- mcp: {
210
- serverName: "slack",
211
- command: "npx",
212
- args: ["-y", "-p", "@zencoderai/slack-mcp-server", "slack-mcp"],
213
- env: {
214
- SLACK_BOT_TOKEN: "PROMPT_TO_INSERT_SLACK_BOT_TOKEN",
215
- SLACK_TEAM_ID: "TKZBCKUJJ"
216
- }
217
- }
218
- },
219
- {
220
- id: "notion-mcp",
221
- name: "Notion MCP",
222
- description: "MCP server for Notion workspace management (HTTP)",
223
- type: "mcp-server",
224
- packageName: "notion",
225
- mcp: {
226
- serverName: "notion",
227
- transport: "http",
228
- url: "https://mcp.notion.com/mcp"
229
- }
230
- },
231
- {
232
- id: "linear-mcp",
233
- name: "Linear MCP",
234
- description: "MCP server for Linear issue tracking (HTTP)",
235
- type: "mcp-server",
236
- packageName: "linear",
237
- mcp: {
238
- serverName: "linear",
239
- transport: "http",
240
- url: "https://mcp.linear.app/mcp"
241
- }
242
- },
243
- {
244
- id: "github-mcp",
245
- name: "GitHub MCP",
246
- description: "MCP server for GitHub repository access",
247
- type: "mcp-server",
248
- packageName: "@modelcontextprotocol/server-github",
249
- mcp: {
250
- serverName: "github",
251
- command: "npx",
252
- args: ["-y", "@modelcontextprotocol/server-github"],
253
- env: {
254
- GITHUB_PERSONAL_ACCESS_TOKEN: "PROMPT_TO_INSERT_GITHUB_PERSONAL_ACCESS_TOKEN"
255
- }
256
- }
257
- },
258
- {
259
- id: "figma-mcp",
260
- name: "Figma MCP",
261
- description: "MCP server for Figma design file access",
262
- type: "mcp-server",
263
- packageName: "figma",
264
- mcp: {
265
- serverName: "figma",
266
- transport: "http",
267
- url: "https://mcp.figma.com/mcp"
268
- }
269
- },
270
- {
271
- id: "chrome-devtools-mcp",
272
- name: "Chrome DevTools MCP",
273
- description: "MCP server for Chrome DevTools Protocol",
274
- type: "mcp-server",
275
- packageName: "chrome-devtools-mcp",
276
- mcp: {
277
- serverName: "chrome-devtools",
278
- command: "npx",
279
- args: ["chrome-devtools-mcp@latest"],
280
- env: {}
281
- }
282
- },
283
- {
284
- id: "vercel-mcp",
285
- name: "Vercel MCP",
286
- description: "MCP server for Vercel deployment management (HTTP)",
287
- type: "mcp-server",
288
- packageName: "vercel",
289
- mcp: {
290
- serverName: "vercel",
291
- transport: "http",
292
- url: "https://mcp.vercel.com"
293
- }
294
- },
295
- {
296
- id: "aws-log-analyzer-mcp",
297
- name: "AWS Log Analyzer MCP",
298
- description: "MCP server for AWS CloudWatch Logs analysis, searching, and correlation",
299
- type: "mcp-server",
300
- packageName: "Log-Analyzer-with-MCP",
301
- mcp: {
302
- serverName: "cw-mcp-server",
303
- command: "uv",
304
- args: []
305
- // Note: args will be dynamically set during installation to include the cloned repo path
306
- },
307
- projectSetup: {
308
- repositoryUrl: "https://github.com/awslabs/Log-Analyzer-with-MCP.git",
309
- configSourcePath: "src/cw-mcp-server",
310
- targetDirectory: ".aws-log-analyzer-mcp"
311
- },
312
- requirements: {
313
- commands: ["git", "uv", "python3"]
314
- }
315
- },
316
- {
317
- id: "pulumi-mcp",
318
- name: "Pulumi MCP",
319
- description: "MCP server for Pulumi infrastructure as code management (HTTP)",
320
- type: "mcp-server",
321
- packageName: "pulumi",
322
- mcp: {
323
- serverName: "pulumi",
324
- transport: "http",
325
- url: "https://mcp.ai.pulumi.com/mcp"
326
- }
327
- }
328
- ];
329
- }
330
- });
331
-
332
- // packages/ai-toolkit-nx-claude/src/generators/addons/schema.json
333
- var require_schema = __commonJS({
334
- "packages/ai-toolkit-nx-claude/src/generators/addons/schema.json"(exports2, module2) {
335
- module2.exports = {
336
- $schema: "https://json-schema.org/schema",
337
- $id: "SchemaForAddons",
338
- title: "Addons Installation",
339
- type: "object",
340
- description: "Install and configure Claude Code addons including MCP servers.",
341
- properties: {
342
- selectionMode: {
343
- type: "string",
344
- description: "Selection mode for which addons to install",
345
- enum: ["all", "specific"],
346
- default: "all",
347
- "x-prompt": {
348
- message: "\u{1F3AF} What would you like to install?",
349
- type: "list",
350
- items: [
351
- {
352
- value: "all",
353
- label: "All recommended MCP servers (12 servers)"
354
- },
355
- {
356
- value: "specific",
357
- label: "Select specific MCP servers"
358
- }
359
- ]
360
- }
361
- },
362
- addons: {
363
- type: "array",
364
- description: "The addons to install",
365
- items: {
366
- type: "string",
367
- enum: [
368
- "spec-workflow-mcp",
369
- "graphite-mcp",
370
- "nx-mcp",
371
- "slack-mcp",
372
- "universe-mcp",
373
- "linear-mcp",
374
- "notion-mcp",
375
- "github-mcp",
376
- "figma-mcp",
377
- "chrome-devtools-mcp",
378
- "vercel-mcp",
379
- "supabase-mcp",
380
- "aws-log-analyzer-mcp",
381
- "pulumi-mcp"
382
- ]
383
- },
384
- "prompt-when": "selectionMode === 'specific'",
385
- "prompt-type": "multiselect",
386
- "prompt-message": "\u{1F50C} Select MCP servers to install"
387
- },
388
- dashboardMode: {
389
- type: "string",
390
- description: "Dashboard startup mode",
391
- enum: ["always", "manual"],
392
- default: "always",
393
- "prompt-message": "\u{1F4CA} When should the spec-workflow dashboard start?",
394
- "prompt-type": "select",
395
- "prompt-items": [
396
- { value: "always", label: "Always (auto-start on Claude launch)" },
397
- { value: "manual", label: "Manual (start via command only)" }
398
- ]
399
- },
400
- port: {
401
- type: "number",
402
- description: "Dashboard port (default: auto)",
403
- default: 0,
404
- "prompt-message": "\u{1F50C} Dashboard port (0 for auto)"
405
- },
406
- force: {
407
- type: "boolean",
408
- description: "Force installation even if already exists",
409
- default: false
410
- },
411
- skipVerification: {
412
- type: "boolean",
413
- description: "Skip installation verification",
414
- default: false
415
- },
416
- projectPath: {
417
- type: "string",
418
- description: "Path to the project where spec-workflow should be installed",
419
- "x-skip-prompt": true
420
- },
421
- dry: {
422
- type: "boolean",
423
- description: "Dry run mode",
424
- default: false
425
- },
426
- installMode: {
427
- type: "string",
428
- description: "Installation mode from parent generator (default or custom)",
429
- enum: ["default", "custom"],
430
- hidden: true,
431
- "x-skip-prompt": true
432
- },
433
- installationType: {
434
- type: "string",
435
- description: "Installation location for MCP servers",
436
- enum: ["global", "local"],
437
- "prompt-message": "\u{1F4CD} Where should MCP servers be installed?",
438
- "prompt-type": "list",
439
- "prompt-items": [
440
- {
441
- value: "global",
442
- label: "Global (~/.claude) - Available in all projects"
443
- },
444
- {
445
- value: "local",
446
- label: "Local (./.claude) - Project-specific configuration"
447
- }
448
- ]
449
- }
450
- },
451
- required: []
452
- };
453
- }
454
- });
455
-
456
- // packages/ai-toolkit-nx-claude/src/generators/init/generator.ts
457
- var generator_exports = {};
458
- __export(generator_exports, {
459
- default: () => generator_default2,
460
- initGenerator: () => initGenerator
461
- });
462
- module.exports = __toCommonJS(generator_exports);
463
- var import_devkit7 = require("@nx/devkit");
464
- var import_enquirer2 = require("enquirer");
465
- var path5 = __toESM(require("path"));
466
- var fs5 = __toESM(require("fs"));
467
- var os4 = __toESM(require("os"));
468
- var import_child_process7 = require("child_process");
469
-
470
- // packages/ai-toolkit-nx-claude/src/utils/prompt-utils.ts
471
- var import_enquirer = require("enquirer");
472
- var fs = __toESM(require("fs"));
473
- async function promptForMissingOptions(options, schemaPath, context = {}, explicitlyProvidedOptions) {
474
- let schema;
475
- if (typeof schemaPath === "string") {
476
- const schemaContent = fs.readFileSync(schemaPath, "utf-8");
477
- schema = JSON.parse(schemaContent);
478
- } else {
479
- schema = schemaPath;
480
- }
481
- const result = { ...options };
482
- if (result["no-interactive"] || result.noInteractive || result["non-interactive"] || result.nonInteractive) {
483
- for (const [key, property] of Object.entries(schema.properties)) {
484
- if (result[key] === void 0 && property.default !== void 0) {
485
- result[key] = property.default;
486
- }
487
- }
488
- return result;
489
- }
490
- for (const [key, property] of Object.entries(schema.properties)) {
491
- let wasExplicitlyProvided = false;
492
- if (explicitlyProvidedOptions) {
493
- if (explicitlyProvidedOptions instanceof Map) {
494
- wasExplicitlyProvided = explicitlyProvidedOptions.has(key) || explicitlyProvidedOptions.has(key.replace(/-/g, ""));
495
- } else {
496
- wasExplicitlyProvided = explicitlyProvidedOptions.has(key) || explicitlyProvidedOptions.has(key.replace(/-/g, ""));
497
- }
498
- }
499
- if (property["x-skip-prompt"]) {
500
- if (result[key] === void 0 && property.default !== void 0) {
501
- result[key] = property.default;
502
- }
503
- continue;
504
- }
505
- const shouldPrompt = property["always-prompt"] ? (
506
- // For always-prompt fields, only skip if value was explicitly provided
507
- !wasExplicitlyProvided
508
- ) : (
509
- // For regular fields (backward compatibility with x-prompt),
510
- // skip if value exists at all (provided or defaulted)
511
- (result[key] === void 0 || result[key] === null) && !wasExplicitlyProvided
512
- );
513
- if (!shouldPrompt) {
514
- continue;
515
- }
516
- if (key === "confirmLocalPath") {
517
- if (result.installationType !== "local") {
518
- continue;
519
- }
520
- }
521
- if (key === "nonInteractive" || key === "non-interactive" || key === "no-interactive" || key === "noInteractive") {
522
- continue;
523
- }
524
- if (key === "force") {
525
- continue;
526
- }
527
- if (property["prompt-when"]) {
528
- const shouldShow = evaluatePromptCondition(property["prompt-when"], result);
529
- if (!shouldShow) {
530
- continue;
531
- }
532
- }
533
- const promptResult = await promptForProperty(key, property, context, result);
534
- if (promptResult !== void 0) {
535
- result[key] = promptResult;
536
- if (key === "installMode" && promptResult === "default") {
537
- result.installationType = "global";
538
- result.installCommands = true;
539
- result.installAgents = true;
540
- result.installHooks = true;
541
- result.hooksMode = "sound";
542
- result.installAddons = true;
543
- result.dry = false;
544
- result.commandSelectionMode = "all";
545
- result.agentSelectionMode = "all";
546
- result.addonSelectionMode = "all";
547
- if (context.defaultCommands) {
548
- result.commands = context.defaultCommands;
549
- }
550
- if (context.defaultAgents) {
551
- result.agents = context.defaultAgents;
552
- }
553
- if (explicitlyProvidedOptions instanceof Map) {
554
- explicitlyProvidedOptions.set("installMode", "default");
555
- explicitlyProvidedOptions.set("installationType", "global");
556
- explicitlyProvidedOptions.set("installCommands", true);
557
- explicitlyProvidedOptions.set("installAgents", true);
558
- explicitlyProvidedOptions.set("installHooks", true);
559
- explicitlyProvidedOptions.set("hooksMode", "sound");
560
- explicitlyProvidedOptions.set("installAddons", true);
561
- explicitlyProvidedOptions.set("dry", false);
562
- explicitlyProvidedOptions.set("commandSelectionMode", "all");
563
- explicitlyProvidedOptions.set("agentSelectionMode", "all");
564
- explicitlyProvidedOptions.set("addonSelectionMode", "all");
565
- if (context.defaultCommands) {
566
- explicitlyProvidedOptions.set("commands", context.defaultCommands);
567
- }
568
- if (context.defaultAgents) {
569
- explicitlyProvidedOptions.set("agents", context.defaultAgents);
570
- }
571
- }
572
- }
573
- if (key === "confirmLocalPath" && result.installationType === "local" && promptResult === false) {
574
- throw new Error("Installation cancelled - please run from your project root");
575
- }
576
- }
577
- }
578
- return result;
579
- }
580
- async function promptForProperty(key, property, context, currentValues) {
581
- const promptMessage = getPromptMessage(key, property);
582
- const promptType = property["prompt-type"] || (property.type === "boolean" ? "confirm" : property.enum ? "select" : property.type === "string" ? "input" : null);
583
- if (promptType === "confirm" || property.type === "boolean") {
584
- const { value } = await (0, import_enquirer.prompt)({
585
- type: "confirm",
586
- name: "value",
587
- message: promptMessage,
588
- initial: property.default ?? false
589
- });
590
- return value;
591
- }
592
- if (promptType === "list" && property["prompt-items"]) {
593
- const { value } = await (0, import_enquirer.prompt)({
594
- type: "select",
595
- name: "value",
596
- message: promptMessage,
597
- choices: property["prompt-items"].map((item) => ({
598
- name: item.value,
599
- value: item.value,
600
- message: item.label
601
- }))
602
- });
603
- return value;
604
- }
605
- if (property.enum || key === "package" && context.availablePackages) {
606
- const choices = property.enum || context.availablePackages || [];
607
- const { value } = await (0, import_enquirer.prompt)({
608
- type: "select",
609
- name: "value",
610
- message: promptMessage,
611
- choices: choices.map((choice) => {
612
- if (key === "package" && choice === "__create_new__") {
613
- return {
614
- name: "__create_new__",
615
- value: "__create_new__",
616
- message: "\u2795 Create new package"
617
- };
618
- }
619
- if (key === "package") {
620
- return { name: choice, value: choice, message: `\u{1F4E6} ${choice}` };
621
- }
622
- return { name: choice, value: choice };
623
- })
624
- });
625
- return value;
626
- }
627
- if (property.type === "array") {
628
- if (key === "commands" && context.availableCommands) {
629
- const installationType = currentValues?.installationType;
630
- let existingSet;
631
- let otherLocationSet;
632
- if (installationType === "global") {
633
- existingSet = context.globalExistingCommands;
634
- otherLocationSet = context.localExistingCommands;
635
- } else if (installationType === "local") {
636
- existingSet = context.localExistingCommands;
637
- otherLocationSet = context.globalExistingCommands;
638
- }
639
- return await promptMultiSelectWithAll(
640
- promptMessage,
641
- context.availableCommands,
642
- "commands",
643
- context.commandDescriptions,
644
- existingSet,
645
- otherLocationSet,
646
- installationType
647
- );
648
- }
649
- if (key === "agents" && context.availableAgents) {
650
- const installationType = currentValues?.installationType;
651
- let existingSet;
652
- let otherLocationSet;
653
- if (installationType === "global") {
654
- existingSet = context.globalExistingAgents;
655
- otherLocationSet = context.localExistingAgents;
656
- } else if (installationType === "local") {
657
- existingSet = context.localExistingAgents;
658
- otherLocationSet = context.globalExistingAgents;
659
- }
660
- return await promptMultiSelectWithAll(
661
- promptMessage,
662
- context.availableAgents,
663
- "agents",
664
- context.agentDescriptions,
665
- existingSet,
666
- otherLocationSet,
667
- installationType
668
- );
669
- }
670
- if (key === "skills" && context.availableSkills) {
671
- const installationType = currentValues?.installationType;
672
- let existingSet;
673
- let otherLocationSet;
674
- if (installationType === "global") {
675
- existingSet = context.globalExistingSkills;
676
- otherLocationSet = context.localExistingSkills;
677
- } else if (installationType === "local") {
678
- existingSet = context.localExistingSkills;
679
- otherLocationSet = context.globalExistingSkills;
680
- }
681
- return await promptMultiSelectWithAll(
682
- promptMessage,
683
- context.availableSkills,
684
- "skills",
685
- context.skillDescriptions,
686
- existingSet,
687
- otherLocationSet,
688
- installationType
689
- );
690
- }
691
- if (key === "addons" && context.availableAddons) {
692
- return await promptMultiSelectWithAll(
693
- promptMessage,
694
- context.availableAddons,
695
- "addons",
696
- context.addonDescriptions,
697
- void 0,
698
- // No existing set for addons
699
- void 0,
700
- // No other location set for addons
701
- void 0
702
- // No installation type for addons
703
- );
704
- }
705
- return [];
706
- }
707
- if (property.type === "string") {
708
- if (key === "targetPath") {
709
- const { value: value2 } = await (0, import_enquirer.prompt)({
710
- type: "input",
711
- name: "value",
712
- message: promptMessage,
713
- initial: process.cwd()
714
- });
715
- return value2;
716
- }
717
- const { value } = await (0, import_enquirer.prompt)({
718
- type: "input",
719
- name: "value",
720
- message: promptMessage,
721
- initial: property.default ?? ""
722
- });
723
- return value;
724
- }
725
- return void 0;
726
- }
727
- async function promptMultiSelectWithAll(message, choices, type, descriptions, existingItems, otherLocationItems, installationType) {
728
- const displayChoices = choices.map((choice) => {
729
- let display = descriptions?.[choice] ? `${choice}: ${descriptions[choice]}` : choice;
730
- const indicators = [];
731
- if (existingItems?.has(choice)) {
732
- indicators.push("will overwrite");
733
- }
734
- if (otherLocationItems?.has(choice)) {
735
- const otherLocation = installationType === "global" ? "locally" : "globally";
736
- indicators.push(`exists ${otherLocation}`);
737
- }
738
- if (indicators.length > 0) {
739
- display += ` (${indicators.join(", ")})`;
740
- }
741
- return display;
742
- });
743
- const response = await (0, import_enquirer.prompt)({
744
- type: "multiselect",
745
- name: "selected",
746
- message,
747
- choices: displayChoices,
748
- initial: displayChoices.map((_, index) => index),
749
- // Select all by default
750
- hint: "Use <space> to select, <a> to toggle all, <return> to submit",
751
- validate: (value) => {
752
- if (value.length === 0) {
753
- return `Please select at least one ${type.slice(0, -1)}`;
754
- }
755
- return true;
756
- }
757
- });
758
- const selected = response.selected || [];
759
- const actualSelections = [];
760
- for (const selection of selected) {
761
- const colonIndex = selection.indexOf(":");
762
- const parenIndex = selection.indexOf("(");
763
- let endIndex = selection.length;
764
- if (colonIndex > -1 && (parenIndex === -1 || colonIndex < parenIndex)) {
765
- endIndex = colonIndex;
766
- } else if (parenIndex > -1 && (colonIndex === -1 || parenIndex < colonIndex)) {
767
- endIndex = parenIndex;
768
- }
769
- const name = selection.substring(0, endIndex).trim();
770
- if (name && !actualSelections.includes(name)) {
771
- actualSelections.push(name);
772
- }
773
- }
774
- return actualSelections;
775
- }
776
- function getPromptMessage(key, property) {
777
- if (property["prompt-message"]) {
778
- return property["prompt-message"];
779
- }
780
- if (property["x-prompt"]) {
781
- if (typeof property["x-prompt"] === "string") {
782
- return property["x-prompt"];
783
- }
784
- if (property["x-prompt"].message) {
785
- return property["x-prompt"].message;
786
- }
787
- }
788
- const description = property.description || "";
789
- switch (key) {
790
- case "installationType":
791
- return "Would you like to install agents and commands globally or locally?";
792
- case "confirmLocalPath":
793
- return "Are you running this from the root of your project?";
794
- case "commands":
795
- return "Select commands to install (use <space> to select, <a> to toggle all):";
796
- case "agents":
797
- return "Select agents to install (use <space> to select, <a> to toggle all):";
798
- case "force":
799
- return "Overwrite existing installation?";
800
- default:
801
- return description || `Enter value for ${key}:`;
802
- }
803
- }
804
- function evaluatePromptCondition(condition, context) {
805
- if (condition.includes(" && ")) {
806
- const parts = condition.split(" && ");
807
- return parts.every((part) => evaluateSingleCondition(part.trim(), context));
808
- }
809
- if (condition.includes(" || ")) {
810
- const parts = condition.split(" || ");
811
- return parts.some((part) => evaluateSingleCondition(part.trim(), context));
812
- }
813
- return evaluateSingleCondition(condition, context);
814
- }
815
- function evaluateSingleCondition(condition, context) {
816
- const parts = condition.split(" ");
817
- if (parts.length < 3) {
818
- return false;
819
- }
820
- const field = parts[0];
821
- const operator = parts[1];
822
- const value = parts.slice(2).join(" ").replace(/['"]/g, "");
823
- const fieldValue = context[field];
824
- switch (operator) {
825
- case "===":
826
- if (value === "true") {
827
- return fieldValue === true;
828
- }
829
- if (value === "false") {
830
- return fieldValue === false;
831
- }
832
- return String(fieldValue) === value;
833
- case "!==":
834
- if (value === "true") {
835
- return fieldValue !== true;
836
- }
837
- if (value === "false") {
838
- return fieldValue !== false;
839
- }
840
- return String(fieldValue) !== value;
841
- default:
842
- return false;
843
- }
844
- }
845
-
846
- // packages/ai-toolkit-nx-claude/src/utils/cli-parser.ts
847
- function getExplicitlyProvidedOptions(options) {
848
- const providedOptions = /* @__PURE__ */ new Map();
849
- const args = process.argv;
850
- for (let i = 0; i < args.length; i++) {
851
- const arg = args[i];
852
- if (arg.startsWith("--")) {
853
- if (arg.includes("=")) {
854
- const [flagPart, ...valueParts] = arg.split("=");
855
- const flagName = flagPart.slice(2);
856
- const value = valueParts.join("=");
857
- const camelCaseName = flagName.replace(
858
- /-([a-z])/g,
859
- (_, letter) => letter.toUpperCase()
860
- );
861
- const parsedValue = parseValue(value);
862
- providedOptions.set(flagName, parsedValue);
863
- providedOptions.set(camelCaseName, parsedValue);
864
- } else {
865
- const flagName = arg.slice(2);
866
- const camelCaseName = flagName.replace(
867
- /-([a-z])/g,
868
- (_, letter) => letter.toUpperCase()
869
- );
870
- if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
871
- const value = args[i + 1];
872
- const parsedValue = parseValue(value);
873
- providedOptions.set(flagName, parsedValue);
874
- providedOptions.set(camelCaseName, parsedValue);
875
- i++;
876
- } else {
877
- providedOptions.set(flagName, true);
878
- providedOptions.set(camelCaseName, true);
879
- }
880
- }
881
- } else if (arg.startsWith("-") && !arg.startsWith("--") && arg.length === 2) {
882
- const shortFlagMap = {
883
- d: "dry-run",
884
- v: "verbose",
885
- f: "force",
886
- h: "help"
887
- };
888
- const shortFlag = arg.slice(1);
889
- if (shortFlagMap[shortFlag]) {
890
- const longFlag = shortFlagMap[shortFlag];
891
- const camelCaseName = longFlag.replace(
892
- /-([a-z])/g,
893
- (_, letter) => letter.toUpperCase()
894
- );
895
- providedOptions.set(longFlag, true);
896
- providedOptions.set(camelCaseName, true);
897
- }
898
- }
899
- }
900
- if (options) {
901
- for (const [key, value] of Object.entries(options)) {
902
- providedOptions.set(key, value);
903
- }
904
- }
905
- return providedOptions;
906
- }
907
- function parseValue(value) {
908
- if (value === "true") return true;
909
- if (value === "false") return false;
910
- if (/^-?\d+$/.test(value)) {
911
- return parseInt(value, 10);
912
- }
913
- if (/^-?\d*\.\d+$/.test(value)) {
914
- return parseFloat(value);
915
- }
916
- if (value === "null") return null;
917
- if (value === "undefined") return void 0;
918
- return value;
919
- }
920
- function isNxDryRunProvided() {
921
- const args = process.argv;
922
- return (
923
- // Check for --dry-run
924
- args.some((a) => a === "--dry-run") || args.some((a) => a.startsWith("--dry-run=") && !a.endsWith("=false")) || // Check for --dryRun
925
- args.some((a) => a === "--dryRun") || args.some((a) => a.startsWith("--dryRun=") && !a.endsWith("=false")) || // Check for short form -d
926
- args.some((a) => a === "-d")
927
- );
928
- }
929
- function isNxNoInteractiveProvided() {
930
- const args = process.argv;
931
- return (
932
- // Check for --no-interactive
933
- args.some((a) => a === "--no-interactive") || args.some(
934
- (a) => a.startsWith("--no-interactive=") && !a.endsWith("=false")
935
- ) || // Check for --noInteractive
936
- args.some((a) => a === "--noInteractive") || args.some((a) => a.startsWith("--noInteractive=") && !a.endsWith("=false"))
937
- );
938
- }
939
-
940
- // packages/ai-toolkit-nx-claude/src/utils/auto-update-utils.ts
941
- var fs2 = __toESM(require("fs"));
942
- var path = __toESM(require("path"));
943
- var os = __toESM(require("os"));
944
- var import_devkit = require("@nx/devkit");
945
- function getCurrentToolkitVersion() {
946
- try {
947
- const packageJsonPath = path.join(__dirname, "..", "..", "package.json");
948
- const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
949
- return packageJson.version;
950
- } catch (error) {
951
- import_devkit.logger.info("checking parent directory for package.json");
952
- const packageJsonPath = path.join(__dirname, "..", "..", "..", "package.json");
953
- const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
954
- return packageJson.version;
955
- }
956
- }
957
- function detectShell() {
958
- const shell = process.env.SHELL || "";
959
- if (shell.includes("zsh")) return "zsh";
960
- if (shell.includes("fish")) return "fish";
961
- return "bash";
962
- }
963
- function getShellConfigPath(shell) {
964
- const homeDir = os.homedir();
965
- const configs = {
966
- bash: path.join(homeDir, ".bashrc"),
967
- zsh: path.join(homeDir, ".zshrc"),
968
- fish: path.join(homeDir, ".config/fish/config.fish")
969
- };
970
- return configs[shell];
971
- }
972
- function generateAutoUpdateSnippet(version) {
973
- return `# AUTOMATED BY AI_TOOLKIT_UPDATE_CHECK v${version}
974
- _ai_toolkit_check_updates() {
975
- [ -n "$AI_TOOLKIT_SKIP_UPDATE_CHECK" ] && return
976
-
977
- local cache="\${HOME}/.uniswap-ai-toolkit/.last-update-check"
978
- local cache_dir="\${HOME}/.uniswap-ai-toolkit"
979
-
980
- # Create cache directory if it doesn't exist
981
- [ ! -d "$cache_dir" ] && mkdir -p "$cache_dir"
982
-
983
- # Check once per week
984
- if [ -f "$cache" ]; then
985
- local last_check=$(cat "$cache" 2>/dev/null || echo 0)
986
- local now=$(date +%s)
987
- [ $((now - last_check)) -lt 604800 ] && return
988
- fi
989
-
990
- echo "\u23F3 Checking for AI Toolkit updates..."
991
- echo " Disable these checks with: export AI_TOOLKIT_SKIP_UPDATE_CHECK=1
992
- "
993
-
994
- # Extract version from this script's comment
995
- local current=$(grep --max-count=1 "# AUTOMATED BY AI_TOOLKIT_UPDATE_CHECK" "\${BASH_SOURCE[0]:-$HOME/.zshrc}" 2>/dev/null | sed 's/.*v\\([0-9][^ ]*\\).*/\\1/')
996
-
997
- # Get latest version from npm registry and display a message if an update is available
998
- if command -v npm >/dev/null 2>&1; then
999
- if ! npm view @uniswap/ai-toolkit-nx-claude@latest version >/dev/null 2>&1; then
1000
- echo "\u26A0\uFE0F Failed to check for AI Toolkit updates (npm registry unavailable)"
1001
- echo "\u{1F41E} Please report this bug at https://github.com/Uniswap/ai-toolkit/issues"
1002
- return
1003
- fi
1004
-
1005
- local latest=$(npm view @uniswap/ai-toolkit-nx-claude@latest version 2>/dev/null)
1006
-
1007
- if [ -n "$latest" ] && [ -n "$current" ] && [ "$current" != "$latest" ]; then
1008
- echo "\u{1F4E6} AI Toolkit update available: $current \u2192 $latest"
1009
- echo " Run: npx @uniswap/ai-toolkit-nx-claude@latest"
1010
- echo " Disable these checks: export AI_TOOLKIT_SKIP_UPDATE_CHECK=1"
1011
- fi
1012
- fi
1013
-
1014
- date +%s > "$cache" 2>/dev/null
1015
- }
1016
-
1017
- _ai_toolkit_check_updates
1018
- # END AI_TOOLKIT_UPDATE_CHECK`;
1019
- }
1020
- function generateFishAutoUpdateSnippet(version) {
1021
- return `# AUTOMATED BY AI_TOOLKIT_UPDATE_CHECK v${version}
1022
- function _ai_toolkit_check_updates
1023
- if set -q AI_TOOLKIT_SKIP_UPDATE_CHECK
1024
- return
1025
- end
1026
-
1027
- set -l cache "$HOME/.uniswap-ai-toolkit/.last-update-check"
1028
- set -l cache_dir "$HOME/.uniswap-ai-toolkit"
1029
-
1030
- # Create cache directory if it doesn't exist
1031
- if not test -d "$cache_dir"
1032
- mkdir -p "$cache_dir"
1033
- end
1034
-
1035
- # Check once per week
1036
- if test -f "$cache"
1037
- set -l last_check (cat "$cache" 2>/dev/null; or echo 0)
1038
- set -l now (date +%s)
1039
- if test (math "$now - $last_check") -lt 604800
1040
- return
1041
- end
1042
- end
1043
-
1044
- echo "\u23F3 Checking for AI Toolkit updates..."
1045
- echo " Disable these checks with: export AI_TOOLKIT_SKIP_UPDATE_CHECK=1
1046
- "
1047
-
1048
- # Check the latest version of the toolkit in npmjs registry and
1049
- # display a message if an update is available
1050
- set -l current (grep --max-count=1 "# AUTOMATED BY AI_TOOLKIT_UPDATE_CHECK" ~/.config/fish/config.fish 2>/dev/null | sed "s/.*v\\([0-9][^ ]*\\).*/\\1/")
1051
-
1052
- if command -v npm >/dev/null 2>&1
1053
- if not npm view @uniswap/ai-toolkit-nx-claude@latest version >/dev/null 2>&1
1054
- echo "\u26A0\uFE0F Failed to check for AI Toolkit updates (npm registry unavailable)"
1055
- echo "\u{1F41E} Please report this bug at https://github.com/Uniswap/ai-toolkit/issues"
1056
- return
1057
- end
1058
-
1059
- set -l latest (npm view @uniswap/ai-toolkit-nx-claude@latest version 2>/dev/null)
1060
-
1061
- if test -n "$latest" -a -n "$current" -a "$current" != "$latest"
1062
- echo "\u{1F4E6} AI Toolkit update available: $current \u2192 $latest"
1063
- echo " Run: npx @uniswap/ai-toolkit-nx-claude@latest"
1064
- echo " Disable these checks: set -x AI_TOOLKIT_SKIP_UPDATE_CHECK 1"
1065
- end
1066
- end
1067
-
1068
- date +%s > "$cache" 2>/dev/null
1069
- end
1070
-
1071
- _ai_toolkit_check_updates
1072
- # END AI_TOOLKIT_UPDATE_CHECK`;
1073
- }
1074
- function installUpdateChecker(shell, version) {
1075
- const configPath = getShellConfigPath(shell);
1076
- if (fs2.existsSync(configPath)) {
1077
- const backupPath = `${configPath}.backup-${Date.now()}`;
1078
- fs2.copyFileSync(configPath, backupPath);
1079
- import_devkit.logger.info(`\u{1F4CB} Backed up ${configPath} to ${backupPath}`);
1080
- } else {
1081
- fs2.writeFileSync(configPath, "");
1082
- import_devkit.logger.info(`\u{1F4DD} Created ${configPath}`);
1083
- }
1084
- let configContent = fs2.readFileSync(configPath, "utf-8");
1085
- const startMarker = "# AUTOMATED BY AI_TOOLKIT_UPDATE_CHECK";
1086
- const endMarker = "# END AI_TOOLKIT_UPDATE_CHECK";
1087
- const blockRegex = new RegExp(`${startMarker}[\\s\\S]*?${endMarker}\\n?`, "g");
1088
- configContent = configContent.replace(blockRegex, "");
1089
- const snippet = shell === "fish" ? generateFishAutoUpdateSnippet(version) : generateAutoUpdateSnippet(version);
1090
- const prefix = configContent.trim() ? "\n\n" : "";
1091
- const updatedContent = configContent + prefix + snippet + "\n";
1092
- fs2.writeFileSync(configPath, updatedContent);
1093
- import_devkit.logger.info(`\u2705 Update checker installed to ${configPath}`);
1094
- import_devkit.logger.info(` Checks once per week, disable with: export AI_TOOLKIT_SKIP_UPDATE_CHECK=1`);
1095
- }
1096
-
1097
- // packages/commands/agnostic/dist/src/index.js
1098
- var commands = {
1099
- "address-pr-issues": {
1100
- description: "Reviews a GitHub PR, addresses comments, and fixes CI issues",
1101
- filePath: "./address-pr-issues.md"
1102
- },
1103
- "auto-spec": {
1104
- description: "Autonomously create and implement a complete spec workflow with multi-agent collaboration, bypassing manual review steps through intelligent consensus-building",
1105
- filePath: "./auto-spec.md"
1106
- },
1107
- "claude-docs": {
1108
- description: "Initialize or update CLAUDE.md documentation files based on context and changes",
1109
- filePath: "./claude-docs.md"
1110
- },
1111
- "claude-init-plus": {
1112
- description: "Initialize or update CLAUDE.md files at all core nodes in the workspace",
1113
- filePath: "./claude-init-plus.md"
1114
- },
1115
- "create-pr": {
1116
- description: "Create or update a Graphite PR with auto-generated conventional commit messages and comprehensive descriptions based on code diffs.",
1117
- filePath: "./create-pr.md"
1118
- },
1119
- "daily-standup": {
1120
- description: "This provides a daily standup, checking GitHub and Linear over the past day and providing a summary of what you&#39;ve been working on and what you will continue to work on.",
1121
- filePath: "./daily-standup.md"
1122
- },
1123
- deploy: {
1124
- description: "Orchestrate deployment pipelines, infrastructure setup, and CI/CD configuration using specialized deployment agents.",
1125
- filePath: "./deploy.md"
1126
- },
1127
- "execute-plan": {
1128
- description: "Execute implementation plans step-by-step",
1129
- filePath: "./execute-plan.md"
1130
- },
1131
- "explain-file": {
1132
- description: "Comprehensive code explanation using multi-agent analysis for architecture, patterns, security, and performance insights.",
1133
- filePath: "./explain-file.md"
1134
- },
1135
- explore: {
1136
- description: "Deep dive into a codebase area to build comprehensive understanding before creating and implementing a plan.",
1137
- filePath: "./explore.md"
1138
- },
1139
- "fix-bug": {
1140
- description: "Comprehensively diagnose bugs with root cause analysis, systematic fixes, regression tests, and prevention strategies.",
1141
- filePath: "./fix-bug.md"
1142
- },
1143
- "gen-tests": {
1144
- description: "Generate comprehensive tests with advanced testing strategies, scenario generation, and edge case identification using the enhanced test-writer agent.",
1145
- filePath: "./gen-tests.md"
1146
- },
1147
- "generate-commit-message": {
1148
- description: "Generate a structured git commit message based on current changes and repository patterns",
1149
- filePath: "./generate-commit-message.md"
1150
- },
1151
- "git-worktree-orchestrator": {
1152
- description: "Create and manage a git worktree based on the current directory and a branch name, with optional spec-workflow setup, Graphite integration, and Linear task automation.",
1153
- filePath: "./git-worktree-orchestrator.md"
1154
- },
1155
- "implement-spec": {
1156
- description: "Orchestrate implementation of spec-workflow tasks using intelligent agent coordination, parallel execution, and quality gates.",
1157
- filePath: "./implement-spec.md"
1158
- },
1159
- monitor: {
1160
- description: "Set up comprehensive monitoring for applications with automated metrics identification, alerting, and dashboard configuration",
1161
- filePath: "./monitor.md"
1162
- },
1163
- "perf-analyze": {
1164
- description: "O(1) Chain-of-Thought Performance Analyzer - Systematic complexity analysis with optimization paths, bottleneck identification, and performance proofs",
1165
- filePath: "./perf-analyze.md"
1166
- },
1167
- plan: {
1168
- description: "Create clear, actionable implementation plans for any task, feature, refactor, or architectural change through collaborative multi-agent refinement",
1169
- filePath: "./plan.md"
1170
- },
1171
- refactor: {
1172
- description: "Orchestrate comprehensive refactoring with architectural analysis, pattern application, and incremental safety checks.",
1173
- filePath: "./refactor.md"
1174
- },
1175
- "refine-linear-task": {
1176
- description: "Refine and enhance Linear task descriptions for improved clarity, completeness, and actionability",
1177
- filePath: "./refine-linear-task.md"
1178
- },
1179
- research: {
1180
- description: "Research a topic by combining web search with codebase analysis for comprehensive understanding.",
1181
- filePath: "./research.md"
1182
- },
1183
- "review-code": {
1184
- description: "Comprehensive code review using multiple specialized agents for architecture, security, performance, and style analysis.",
1185
- filePath: "./review-code.md"
1186
- },
1187
- "review-plan": {
1188
- description: "Critically review an implementation plan for completeness, feasibility, and alignment with codebase patterns",
1189
- filePath: "./review-plan.md"
1190
- },
1191
- "review-pr": {
1192
- description: "Orchestrate comprehensive pull request review using specialized agents for architecture, security, performance, testing, and maintainability analysis.",
1193
- filePath: "./review-pr.md"
1194
- },
1195
- "split-stack": {
1196
- description: "Automatically split a monolithic branch with many changes into a logical, reviewable stack of PRs using semantic analysis and Graphite.",
1197
- filePath: "./split-stack.md"
1198
- },
1199
- "update-claude-md": {
1200
- description: "Intelligently update CLAUDE.md files based on detected code changes",
1201
- filePath: "./update-claude-md.md"
1202
- },
1203
- "work-through-pr-comments": {
1204
- description: "Methodically work through GitHub pull request comments in a conversational workflow, analyzing each comment, presenting solution options, gathering your decisions, and implementing approved changes.",
1205
- filePath: "./work-through-pr-comments.md"
1206
- }
1207
- };
1208
-
1209
- // packages/agents/agnostic/dist/src/index.js
1210
- var agents = {
1211
- "agent-capability-analyst": {
1212
- description: "Advanced specialist in AI agent capability analysis with enhanced scoring algorithms, semantic matching for natural language tasks, and team composition recommendations for complex workflows",
1213
- filePath: "./agent-capability-analyst.md"
1214
- },
1215
- "agent-optimizer": {
1216
- description: "Meta-agent that analyzes, optimizes, and continuously improves the performance of other AI agents through systematic refinement strategies",
1217
- filePath: "./agent-optimizer.md"
1218
- },
1219
- "agent-orchestrator": {
1220
- description: "Intelligent orchestrator that coordinates other AI agents for complex software development workflows, matching tasks to specialists based on capabilities",
1221
- filePath: "./agent-orchestrator.md"
1222
- },
1223
- "cicd-agent": {
1224
- description: "CI/CD pipeline specialist for automated deployment setup, workflow configuration, and release management",
1225
- filePath: "./cicd-agent.md"
1226
- },
1227
- "claude-agent-discovery": {
1228
- description: "Specialized agent for discovering and cataloging all available agents and commands from Claude Code directories, including local project and global user configurations",
1229
- filePath: "./claude-agent-discovery.md"
1230
- },
1231
- "claude-docs-fact-checker": {
1232
- description: "Verify CLAUDE.md documentation accuracy against actual codebase state. Use this agent proactively after claude-docs-manager or claude-docs-initializer generate documentation content to verify accuracy before files are written. This prevents hallucinations in CLAUDE.md files.",
1233
- filePath: "./claude-docs-fact-checker.md"
1234
- },
1235
- "claude-docs-initializer": {
1236
- description: "Discover repository structure and create initial CLAUDE.md documentation at all appropriate levels",
1237
- filePath: "./claude-docs-initializer.md"
1238
- },
1239
- "claude-docs-manager": {
1240
- description: "Analyze code changes and update all affected CLAUDE.md documentation files",
1241
- filePath: "./claude-docs-manager.md"
1242
- },
1243
- "code-explainer": {
1244
- description: "Advanced code analysis agent that explains purpose, architecture, dependencies, security vulnerabilities, and performance implications with deep pattern recognition",
1245
- filePath: "./code-explainer.md"
1246
- },
1247
- "code-generator": {
1248
- description: "Comprehensive code generation specialist that creates production-ready code with tests, following best practices and existing patterns",
1249
- filePath: "./code-generator.md"
1250
- },
1251
- "commit-message-generator": {
1252
- description: "Generate well-structured git commit messages that clearly communicate the WHAT and WHY of code changes. Your messages should help future developers (including the author) understand the purpose and context of the commit.",
1253
- filePath: "./commit-message-generator.md"
1254
- },
1255
- "context-loader": {
1256
- description: "Advanced context management system for deep codebase understanding, intelligent summarization, and cross-agent context sharing.",
1257
- filePath: "./context-loader.md"
1258
- },
1259
- "debug-assistant": {
1260
- description: "Advanced debugging specialist with root cause analysis, error pattern recognition, fix validation, and prevention recommendations",
1261
- filePath: "./debug-assistant.md"
1262
- },
1263
- "doc-writer": {
1264
- description: "Advanced documentation specialist for API docs, README generation, architecture documentation, and interactive examples with quality analysis",
1265
- filePath: "./doc-writer.md"
1266
- },
1267
- "feedback-collector": {
1268
- description: "A comprehensive agent for gathering, analyzing, and transforming execution feedback into actionable insights for continuous improvement",
1269
- filePath: "./feedback-collector.md"
1270
- },
1271
- "infrastructure-agent": {
1272
- description: "Infrastructure automation specialist for cloud architecture, scaling strategies, and cost optimization",
1273
- filePath: "./infrastructure-agent.md"
1274
- },
1275
- "migration-assistant": {
1276
- description: "Migration specialist for guiding version upgrades, compatibility checking, rollback strategies, and validation steps",
1277
- filePath: "./migration-assistant.md"
1278
- },
1279
- "pattern-learner": {
1280
- description: "Specializes in learning from agent executions, extracting reusable patterns, and providing recommendations for pattern application across different contexts",
1281
- filePath: "./pattern-learner.md"
1282
- },
1283
- "performance-analyzer": {
1284
- description: "Comprehensive performance analysis agent for identifying bottlenecks, analyzing complexity, and providing optimization strategies with measurable impact estimates",
1285
- filePath: "./performance-analyzer.md"
1286
- },
1287
- "plan-reviewer": {
1288
- description: "Critically analyze implementation plans for completeness, feasibility, and alignment with codebase patterns",
1289
- filePath: "./plan-reviewer.md"
1290
- },
1291
- planner: {
1292
- description: "Create clear, actionable implementation plans without writing code",
1293
- filePath: "./planner.md"
1294
- },
1295
- "pr-creator": {
1296
- description: "Creates or updates Graphite PRs with auto-generated conventional commit messages and comprehensive PR descriptions based on diffs",
1297
- filePath: "./pr-creator.md"
1298
- },
1299
- "pr-reviewer": {
1300
- description: "Reviews PRs, addresses comments with plans or code changes, and fixes CI pipeline issues",
1301
- filePath: "./pr-reviewer.md"
1302
- },
1303
- "prompt-engineer": {
1304
- description: "Expert in analyzing, optimizing, and testing prompts for AI agents and LLMs to maximize clarity, effectiveness, and efficiency",
1305
- filePath: "./prompt-engineer.md"
1306
- },
1307
- refactorer: {
1308
- description: "Advanced refactoring agent with architectural analysis, safe incremental strategies, and performance optimization capabilities.",
1309
- filePath: "./refactorer.md"
1310
- },
1311
- researcher: {
1312
- description: "Conduct comprehensive research including architectural patterns, technology comparison, security analysis, and codebase pattern extraction.",
1313
- filePath: "./researcher.md"
1314
- },
1315
- "security-analyzer": {
1316
- description: "Comprehensive security analysis agent for vulnerability assessment, threat modeling, and compliance checking",
1317
- filePath: "./security-analyzer.md"
1318
- },
1319
- "stack-splitter": {
1320
- description: "Semantic analysis agent for splitting monolithic branches into logical, reviewable PR stacks. Analyzes git history, file changes, and code semantics to propose optimal split boundaries.",
1321
- filePath: "./stack-splitter.md"
1322
- },
1323
- "style-enforcer": {
1324
- description: "Advanced style and convention enforcement with multi-language support, pattern detection, automated fixes, and comprehensive reporting.",
1325
- filePath: "./style-enforcer.md"
1326
- },
1327
- "test-runner": {
1328
- description: "Automated agent testing specialist that validates agent behaviors, tests prompt variations, detects regressions, and provides comprehensive test reporting with performance metrics.",
1329
- filePath: "./test-runner.md"
1330
- },
1331
- "test-writer": {
1332
- description: "Generate comprehensive, deterministic tests with advanced testing strategies, scenario generation, and edge case identification.",
1333
- filePath: "./test-writer.md"
1334
- }
1335
- };
1336
-
1337
- // packages/ai-toolkit-nx-claude/src/generators/hooks/generator.ts
1338
- var import_devkit5 = require("@nx/devkit");
1339
- var path4 = __toESM(require("path"));
1340
-
1341
- // packages/ai-toolkit-nx-claude/src/generators/hooks/dependency-checker.ts
1342
- var import_child_process = require("child_process");
1343
- var import_devkit2 = require("@nx/devkit");
1344
- function commandExists(command) {
1345
- try {
1346
- (0, import_child_process.execSync)(`which ${command}`, { stdio: "ignore" });
1347
- return true;
1348
- } catch {
1349
- return false;
1350
- }
1351
- }
1352
- function getCommandVersion(command, versionFlag = "--version") {
1353
- try {
1354
- const output = (0, import_child_process.execSync)(`${command} ${versionFlag}`, {
1355
- encoding: "utf-8",
1356
- stdio: "pipe"
1357
- }).trim();
1358
- const versionMatch = output.match(/(\d+\.\d+\.\d+)/);
1359
- return versionMatch ? versionMatch[1] : output.split("\n")[0];
1360
- } catch {
1361
- return void 0;
1362
- }
1363
- }
1364
- function checkDependencies() {
1365
- const status = {
1366
- hasNode: false,
1367
- hasNpm: false,
1368
- hasGit: false,
1369
- missingDependencies: []
1370
- };
1371
- if (commandExists("node")) {
1372
- status.hasNode = true;
1373
- status.nodeVersion = getCommandVersion("node");
1374
- } else {
1375
- status.missingDependencies.push("Node.js");
1376
- }
1377
- if (commandExists("npm")) {
1378
- status.hasNpm = true;
1379
- status.npmVersion = getCommandVersion("npm");
1380
- } else {
1381
- status.missingDependencies.push("npm");
1382
- }
1383
- if (commandExists("git")) {
1384
- status.hasGit = true;
1385
- status.gitVersion = getCommandVersion("git");
1386
- } else {
1387
- status.missingDependencies.push("Git");
1388
- }
1389
- return status;
1390
- }
1391
- function logDependencyStatus(status) {
1392
- import_devkit2.logger.info("\u{1F4CB} Dependency Check Results:");
1393
- if (status.hasNode) {
1394
- import_devkit2.logger.info(` \u2705 Node.js: ${status.nodeVersion || "installed"}`);
1395
- } else {
1396
- import_devkit2.logger.error(" \u274C Node.js: not found");
1397
- }
1398
- if (status.hasNpm) {
1399
- import_devkit2.logger.info(` \u2705 npm: ${status.npmVersion || "installed"}`);
1400
- } else {
1401
- import_devkit2.logger.error(" \u274C npm: not found");
1402
- }
1403
- if (status.hasGit) {
1404
- import_devkit2.logger.info(` \u2705 Git: ${status.gitVersion || "installed"}`);
1405
- } else {
1406
- import_devkit2.logger.error(" \u274C Git: not found");
1407
- }
1408
- }
1409
- function hasAllDependencies(status) {
1410
- return status.missingDependencies.length === 0;
1411
- }
1412
- function getInstallInstructions(missingDeps) {
1413
- const instructions = [];
1414
- if (missingDeps.includes("Node.js") || missingDeps.includes("npm")) {
1415
- instructions.push(
1416
- "\u{1F4E6} Node.js and npm:",
1417
- " \u2022 macOS: brew install node",
1418
- " \u2022 Linux: sudo apt-get install nodejs npm",
1419
- " \u2022 Windows: Download from https://nodejs.org/",
1420
- ""
1421
- );
1422
- }
1423
- if (missingDeps.includes("Git")) {
1424
- instructions.push(
1425
- "\u{1F4E6} Git:",
1426
- " \u2022 macOS: brew install git",
1427
- " \u2022 Linux: sudo apt-get install git",
1428
- " \u2022 Windows: Download from https://git-scm.com/",
1429
- ""
1430
- );
1431
- }
1432
- return instructions.join("\n");
1433
- }
1434
- function validateVersions(status) {
1435
- const MIN_NODE_VERSION = "16.0.0";
1436
- const MIN_NPM_VERSION = "7.0.0";
1437
- const MIN_GIT_VERSION = "2.0.0";
1438
- const compareVersions = (current, minimum) => {
1439
- if (!current) return false;
1440
- const currentParts = current.split(".").map(Number);
1441
- const minimumParts = minimum.split(".").map(Number);
1442
- for (let i = 0; i < minimumParts.length; i++) {
1443
- if (currentParts[i] > minimumParts[i]) return true;
1444
- if (currentParts[i] < minimumParts[i]) return false;
1445
- }
1446
- return true;
1447
- };
1448
- if (status.hasNode && !compareVersions(status.nodeVersion, MIN_NODE_VERSION)) {
1449
- import_devkit2.logger.warn(
1450
- `\u26A0\uFE0F Node.js version ${status.nodeVersion} is below minimum required version ${MIN_NODE_VERSION}`
1451
- );
1452
- return false;
1453
- }
1454
- if (status.hasNpm && !compareVersions(status.npmVersion, MIN_NPM_VERSION)) {
1455
- import_devkit2.logger.warn(
1456
- `\u26A0\uFE0F npm version ${status.npmVersion} is below minimum required version ${MIN_NPM_VERSION}`
1457
- );
1458
- return false;
1459
- }
1460
- if (status.hasGit && !compareVersions(status.gitVersion, MIN_GIT_VERSION)) {
1461
- import_devkit2.logger.warn(
1462
- `\u26A0\uFE0F Git version ${status.gitVersion} is below minimum required version ${MIN_GIT_VERSION}`
1463
- );
1464
- return false;
1465
- }
1466
- return true;
1467
- }
1468
- async function checkAndValidateDependencies() {
1469
- const status = checkDependencies();
1470
- logDependencyStatus(status);
1471
- if (!hasAllDependencies(status)) {
1472
- import_devkit2.logger.error("\n\u274C Missing required dependencies:");
1473
- import_devkit2.logger.info(getInstallInstructions(status.missingDependencies));
1474
- return false;
1475
- }
1476
- if (!validateVersions(status)) {
1477
- import_devkit2.logger.error(
1478
- "\n\u274C Some dependencies do not meet minimum version requirements"
1479
- );
1480
- import_devkit2.logger.info("Please update the affected tools to continue.");
1481
- return false;
1482
- }
1483
- import_devkit2.logger.info("\n\u2705 All dependencies satisfied!");
1484
- return true;
1485
- }
1486
-
1487
- // packages/ai-toolkit-nx-claude/src/generators/hooks/repo-manager.ts
1488
- var import_child_process2 = require("child_process");
1489
- var import_devkit3 = require("@nx/devkit");
1490
- var fs3 = __toESM(require("fs"));
1491
- var path2 = __toESM(require("path"));
1492
- var os2 = __toESM(require("os"));
1493
- var DEFAULT_REPO_URL = "https://github.com/pascalporedda/awesome-claude-code.git";
1494
- function getRepoPath(customPath) {
1495
- if (customPath) {
1496
- return customPath;
1497
- }
1498
- return path2.join(os2.tmpdir(), "claude-hooks-temp");
1499
- }
1500
- function isGitRepository(repoPath) {
1501
- try {
1502
- if (!fs3.existsSync(repoPath)) {
1503
- return false;
1504
- }
1505
- (0, import_child_process2.execSync)("git rev-parse --git-dir", {
1506
- cwd: repoPath,
1507
- stdio: "ignore"
1508
- });
1509
- return true;
1510
- } catch {
1511
- return false;
1512
- }
1513
- }
1514
- function getCurrentBranch(repoPath) {
1515
- try {
1516
- const branch = (0, import_child_process2.execSync)("git rev-parse --abbrev-ref HEAD", {
1517
- cwd: repoPath,
1518
- encoding: "utf-8"
1519
- }).trim();
1520
- return branch;
1521
- } catch {
1522
- return void 0;
1523
- }
1524
- }
1525
- function getLastCommit(repoPath) {
1526
- try {
1527
- const commit = (0, import_child_process2.execSync)("git rev-parse HEAD", {
1528
- cwd: repoPath,
1529
- encoding: "utf-8"
1530
- }).trim();
1531
- return commit.substring(0, 7);
1532
- } catch {
1533
- return void 0;
1534
- }
1535
- }
1536
- function isDirty(repoPath) {
1537
- try {
1538
- const status = (0, import_child_process2.execSync)("git status --porcelain", {
1539
- cwd: repoPath,
1540
- encoding: "utf-8"
1541
- }).trim();
1542
- return status.length > 0;
1543
- } catch {
1544
- return false;
1545
- }
1546
- }
1547
- function getRemoteUrl(repoPath) {
1548
- try {
1549
- const url = (0, import_child_process2.execSync)("git config --get remote.origin.url", {
1550
- cwd: repoPath,
1551
- encoding: "utf-8"
1552
- }).trim();
1553
- return url;
1554
- } catch {
1555
- return void 0;
1556
- }
1557
- }
1558
- function getRepoStatus(repoPath) {
1559
- const exists = fs3.existsSync(repoPath);
1560
- const isGit = exists && isGitRepository(repoPath);
1561
- const status = {
1562
- exists,
1563
- path: repoPath,
1564
- isGitRepo: isGit
1565
- };
1566
- if (isGit) {
1567
- status.currentBranch = getCurrentBranch(repoPath);
1568
- status.lastCommit = getLastCommit(repoPath);
1569
- status.isDirty = isDirty(repoPath);
1570
- status.remoteUrl = getRemoteUrl(repoPath);
1571
- }
1572
- return status;
1573
- }
1574
- async function cloneRepository(repoUrl = DEFAULT_REPO_URL, targetPath, verbose = false) {
1575
- const repoPath = getRepoPath(targetPath);
1576
- try {
1577
- if (fs3.existsSync(repoPath)) {
1578
- import_devkit3.logger.warn(`Directory already exists: ${repoPath}`);
1579
- if (isGitRepository(repoPath)) {
1580
- import_devkit3.logger.info("Existing git repository found");
1581
- return true;
1582
- } else {
1583
- import_devkit3.logger.info("Removing non-git directory...");
1584
- fs3.rmSync(repoPath, { recursive: true, force: true });
1585
- }
1586
- }
1587
- import_devkit3.logger.info(`\u{1F4E5} Downloading notification hooks...`);
1588
- try {
1589
- (0, import_child_process2.execSync)(`git clone ${repoUrl} "${repoPath}"`, {
1590
- stdio: verbose ? "inherit" : "ignore"
1591
- });
1592
- import_devkit3.logger.info("\u2705 Download complete");
1593
- return true;
1594
- } catch (httpsError) {
1595
- if (repoUrl === DEFAULT_REPO_URL) {
1596
- import_devkit3.logger.warn("HTTPS clone failed, trying SSH...");
1597
- const sshUrl = "git@github.com:pascalporedda/awesome-claude-code.git";
1598
- try {
1599
- (0, import_child_process2.execSync)(`git clone ${sshUrl} "${repoPath}"`, {
1600
- stdio: verbose ? "inherit" : "ignore"
1601
- });
1602
- import_devkit3.logger.info("\u2705 Download complete via SSH");
1603
- return true;
1604
- } catch (sshError) {
1605
- import_devkit3.logger.error("\u274C Both HTTPS and SSH clone attempts failed");
1606
- throw sshError;
1607
- }
1608
- } else {
1609
- throw httpsError;
1610
- }
1611
- }
1612
- } catch (error) {
1613
- import_devkit3.logger.error(`\u274C Failed to download hooks: ${error}`);
1614
- return false;
1615
- }
1616
- }
1617
- async function updateRepository(repoPath, verbose = false) {
1618
- try {
1619
- if (!isGitRepository(repoPath)) {
1620
- import_devkit3.logger.error("Not a git repository");
1621
- return false;
1622
- }
1623
- if (isDirty(repoPath)) {
1624
- import_devkit3.logger.warn("\u26A0\uFE0F Repository has uncommitted changes");
1625
- import_devkit3.logger.info("Stashing changes...");
1626
- (0, import_child_process2.execSync)("git stash", {
1627
- cwd: repoPath,
1628
- stdio: verbose ? "inherit" : "ignore"
1629
- });
1630
- }
1631
- import_devkit3.logger.info("\u{1F4E5} Updating to latest version...");
1632
- (0, import_child_process2.execSync)("git fetch origin", {
1633
- cwd: repoPath,
1634
- stdio: verbose ? "inherit" : "ignore"
1635
- });
1636
- (0, import_child_process2.execSync)("git pull origin main", {
1637
- cwd: repoPath,
1638
- stdio: verbose ? "inherit" : "ignore"
1639
- });
1640
- import_devkit3.logger.info("\u2705 Update complete");
1641
- return true;
1642
- } catch (error) {
1643
- import_devkit3.logger.error(`\u274C Failed to update: ${error}`);
1644
- return false;
1645
- }
1646
- }
1647
- function cleanupRepository(repoPath) {
1648
- try {
1649
- if (fs3.existsSync(repoPath)) {
1650
- fs3.rmSync(repoPath, { recursive: true, force: true });
1651
- import_devkit3.logger.info("\u{1F9F9} Temporary files cleaned up");
1652
- return true;
1653
- }
1654
- return true;
1655
- } catch (error) {
1656
- import_devkit3.logger.error(`\u274C Failed to cleanup: ${error}`);
1657
- return false;
1658
- }
1659
- }
1660
- async function ensureRepository(options) {
1661
- const repoUrl = options.repoUrl || DEFAULT_REPO_URL;
1662
- const repoPath = getRepoPath(options.targetPath);
1663
- const status = getRepoStatus(repoPath);
1664
- if (options.verbose) {
1665
- import_devkit3.logger.info("Repository status:");
1666
- import_devkit3.logger.info(` Path: ${status.path}`);
1667
- import_devkit3.logger.info(` Exists: ${status.exists}`);
1668
- import_devkit3.logger.info(` Is Git Repo: ${status.isGitRepo}`);
1669
- if (status.isGitRepo) {
1670
- import_devkit3.logger.info(` Branch: ${status.currentBranch}`);
1671
- import_devkit3.logger.info(` Last Commit: ${status.lastCommit}`);
1672
- import_devkit3.logger.info(` Has Changes: ${status.isDirty}`);
1673
- import_devkit3.logger.info(` Remote URL: ${status.remoteUrl}`);
1674
- }
1675
- }
1676
- if (status.exists && status.isGitRepo) {
1677
- if (status.remoteUrl && !status.remoteUrl.includes("awesome-claude-code")) {
1678
- cleanupRepository(repoPath);
1679
- const cloned2 = await cloneRepository(
1680
- DEFAULT_REPO_URL,
1681
- options.targetPath,
1682
- options.verbose
1683
- );
1684
- if (!cloned2) {
1685
- return null;
1686
- }
1687
- return repoPath;
1688
- }
1689
- const updated = await updateRepository(repoPath, options.verbose);
1690
- if (!updated) {
1691
- import_devkit3.logger.warn("\u26A0\uFE0F Failed to update, using existing version");
1692
- }
1693
- return repoPath;
1694
- }
1695
- const cloned = await cloneRepository(
1696
- repoUrl,
1697
- options.targetPath,
1698
- options.verbose
1699
- );
1700
- if (!cloned) {
1701
- return null;
1702
- }
1703
- return repoPath;
1704
- }
1705
-
1706
- // packages/ai-toolkit-nx-claude/src/generators/hooks/install-orchestrator.ts
1707
- var import_child_process3 = require("child_process");
1708
- var import_devkit4 = require("@nx/devkit");
1709
- var path3 = __toESM(require("path"));
1710
- var fs4 = __toESM(require("fs"));
1711
- var os3 = __toESM(require("os"));
1712
- var ROOT_CLAUDE_DIR = path3.join(os3.homedir(), ".claude");
1713
- var HOOKS_DIR = path3.join(ROOT_CLAUDE_DIR, "hooks");
1714
- function backupExistingHooks(verbose = false) {
1715
- if (!fs4.existsSync(HOOKS_DIR)) {
1716
- if (verbose) {
1717
- import_devkit4.logger.info("No existing hooks to backup");
1718
- }
1719
- return null;
1720
- }
1721
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1722
- const backupDir = path3.join(ROOT_CLAUDE_DIR, `hooks-backup-${timestamp}`);
1723
- try {
1724
- if (verbose) {
1725
- import_devkit4.logger.info(`\u{1F4E6} Creating backup at: ${backupDir}`);
1726
- }
1727
- fs4.mkdirSync(backupDir, { recursive: true });
1728
- (0, import_child_process3.execSync)(`cp -r "${HOOKS_DIR}"/* "${backupDir}"/`, {
1729
- stdio: verbose ? "inherit" : "ignore"
1730
- });
1731
- const settingsPath = path3.join(ROOT_CLAUDE_DIR, "settings.json");
1732
- if (fs4.existsSync(settingsPath)) {
1733
- const backupSettingsPath = path3.join(backupDir, "settings.json.backup");
1734
- fs4.copyFileSync(settingsPath, backupSettingsPath);
1735
- }
1736
- import_devkit4.logger.info(`\u2705 Backup created at: ${backupDir}`);
1737
- return backupDir;
1738
- } catch (error) {
1739
- import_devkit4.logger.error(`\u274C Failed to create backup: ${error}`);
1740
- return null;
1741
- }
1742
- }
1743
- async function executeInstallScript(scriptPath, options) {
1744
- return new Promise((resolve) => {
1745
- try {
1746
- if (options.dryRun) {
1747
- import_devkit4.logger.info("\u{1F50D} DRY RUN: Would execute install script with defaults");
1748
- resolve(true);
1749
- return;
1750
- }
1751
- import_devkit4.logger.info("\u{1F680} Running hook installation...");
1752
- const repoDir = path3.dirname(scriptPath);
1753
- const child = (0, import_child_process3.spawn)("bash", [scriptPath], {
1754
- stdio: ["pipe", options.verbose ? "inherit" : "pipe", "inherit"],
1755
- shell: true,
1756
- cwd: repoDir
1757
- // Set working directory to the repo directory
1758
- });
1759
- if (child.stdin) {
1760
- child.stdin.write("1\n");
1761
- child.stdin.end();
1762
- }
1763
- child.on("close", (code) => {
1764
- if (code === 0) {
1765
- import_devkit4.logger.info("\u2705 Installation script completed successfully");
1766
- resolve(true);
1767
- } else {
1768
- import_devkit4.logger.error(`\u274C Installation script exited with code ${code}`);
1769
- resolve(false);
1770
- }
1771
- });
1772
- child.on("error", (error) => {
1773
- import_devkit4.logger.error(`\u274C Failed to execute install script: ${error}`);
1774
- resolve(false);
1775
- });
1776
- } catch (error) {
1777
- import_devkit4.logger.error(`\u274C Error executing install script: ${error}`);
1778
- resolve(false);
1779
- }
1780
- });
1781
- }
1782
- function fixHookPaths(verbose = false) {
1783
- const settingsPath = path3.join(ROOT_CLAUDE_DIR, "settings.json");
1784
- if (!fs4.existsSync(settingsPath)) {
1785
- if (verbose) {
1786
- import_devkit4.logger.warn("\u26A0\uFE0F settings.json not found - cannot fix paths");
1787
- }
1788
- return false;
1789
- }
1790
- try {
1791
- const settings = JSON.parse(fs4.readFileSync(settingsPath, "utf-8"));
1792
- if (!settings.hooks) {
1793
- if (verbose) {
1794
- import_devkit4.logger.warn("\u26A0\uFE0F No hooks configuration found in settings.json");
1795
- }
1796
- return false;
1797
- }
1798
- const homeDir = os3.homedir();
1799
- let modified = false;
1800
- const fixPathInHooks = (hookArray) => {
1801
- for (const hookConfig of hookArray) {
1802
- if (hookConfig.hooks && Array.isArray(hookConfig.hooks)) {
1803
- for (const hook of hookConfig.hooks) {
1804
- if (hook.command && typeof hook.command === "string") {
1805
- if (hook.command.includes(homeDir)) {
1806
- hook.command = hook.command.replace(homeDir, "~");
1807
- modified = true;
1808
- }
1809
- const pathMatch = hook.command.match(/\/(Users|home)\/[^/]+\/\.claude\/hooks\//);
1810
- if (pathMatch) {
1811
- hook.command = hook.command.replace(pathMatch[0], "~/.claude/hooks/");
1812
- modified = true;
1813
- }
1814
- }
1815
- }
1816
- }
1817
- }
1818
- };
1819
- const hookTypes = ["Notification", "Stop", "SubagentStop", "PreToolUse", "PostToolUse"];
1820
- for (const hookType of hookTypes) {
1821
- if (settings.hooks[hookType] && Array.isArray(settings.hooks[hookType])) {
1822
- fixPathInHooks(settings.hooks[hookType]);
1823
- }
1824
- }
1825
- if (modified) {
1826
- fs4.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
1827
- if (verbose) {
1828
- import_devkit4.logger.info("\u2705 Fixed hook paths to use ~ expansion for Docker compatibility");
1829
- }
1830
- return true;
1831
- }
1832
- return true;
1833
- } catch (error) {
1834
- import_devkit4.logger.error(`\u274C Failed to fix hook paths: ${error}`);
1835
- return false;
1836
- }
1837
- }
1838
- function verifyInstallation() {
1839
- const expectedFiles = ["notification.ts", "stop.ts", "subagent_stop.ts"];
1840
- const installedFiles = [];
1841
- const missingFiles = [];
1842
- for (const file of expectedFiles) {
1843
- const filePath = path3.join(HOOKS_DIR, file);
1844
- if (fs4.existsSync(filePath)) {
1845
- installedFiles.push(filePath);
1846
- } else {
1847
- missingFiles.push(file);
1848
- }
1849
- }
1850
- if (missingFiles.length > 0) {
1851
- import_devkit4.logger.warn(`\u26A0\uFE0F Missing expected files: ${missingFiles.join(", ")}`);
1852
- return null;
1853
- }
1854
- const settingsPath = path3.join(ROOT_CLAUDE_DIR, "settings.json");
1855
- if (!fs4.existsSync(settingsPath)) {
1856
- import_devkit4.logger.warn("\u26A0\uFE0F settings.json not found");
1857
- return null;
1858
- }
1859
- try {
1860
- const settings = JSON.parse(fs4.readFileSync(settingsPath, "utf-8"));
1861
- if (!settings.hooks) {
1862
- import_devkit4.logger.warn("\u26A0\uFE0F No hooks configuration found in settings.json");
1863
- return null;
1864
- }
1865
- import_devkit4.logger.info("\u2705 Installation verified successfully");
1866
- return installedFiles;
1867
- } catch (error) {
1868
- import_devkit4.logger.error(`\u274C Failed to verify settings.json: ${error}`);
1869
- return null;
1870
- }
1871
- }
1872
- async function runInstallation(repoPath, options) {
1873
- const result = {
1874
- success: false,
1875
- installedPath: HOOKS_DIR
1876
- };
1877
- try {
1878
- const installScriptPath = path3.join(repoPath, "install-global.sh");
1879
- if (!fs4.existsSync(installScriptPath)) {
1880
- throw new Error(`Install script not found at: ${installScriptPath}`);
1881
- }
1882
- (0, import_child_process3.execSync)(`chmod +x "${installScriptPath}"`, { stdio: "ignore" });
1883
- if (options.backupExisting) {
1884
- const backupPath = backupExistingHooks(options.verbose);
1885
- if (backupPath) {
1886
- result.backupPath = backupPath;
1887
- }
1888
- }
1889
- const installSuccess = await executeInstallScript(
1890
- installScriptPath,
1891
- options
1892
- );
1893
- if (!installSuccess) {
1894
- throw new Error("Installation script failed");
1895
- }
1896
- const installedFiles = verifyInstallation();
1897
- if (!installedFiles) {
1898
- throw new Error("Installation verification failed");
1899
- }
1900
- fixHookPaths(options.verbose);
1901
- result.success = true;
1902
- result.installedFiles = installedFiles;
1903
- import_devkit4.logger.info("\n\u{1F4CB} Installation Summary:");
1904
- import_devkit4.logger.info(` \u2705 Hooks installed to: ${result.installedPath}`);
1905
- if (result.backupPath) {
1906
- import_devkit4.logger.info(` \u2705 Backup created at: ${result.backupPath}`);
1907
- }
1908
- import_devkit4.logger.info(` \u2705 Files installed: ${installedFiles.length}`);
1909
- return result;
1910
- } catch (error) {
1911
- result.error = error instanceof Error ? error.message : String(error);
1912
- import_devkit4.logger.error(`\u274C Installation failed: ${result.error}`);
1913
- if (result.backupPath && !options.dryRun) {
1914
- import_devkit4.logger.info("\u{1F504} Attempting to restore backup...");
1915
- await restoreBackup(result.backupPath);
1916
- }
1917
- return result;
1918
- }
1919
- }
1920
- async function restoreBackup(backupPath) {
1921
- try {
1922
- if (fs4.existsSync(HOOKS_DIR)) {
1923
- fs4.rmSync(HOOKS_DIR, { recursive: true, force: true });
1924
- }
1925
- fs4.mkdirSync(HOOKS_DIR, { recursive: true });
1926
- (0, import_child_process3.execSync)(`cp -r "${backupPath}"/* "${HOOKS_DIR}"/`, {
1927
- stdio: "ignore"
1928
- });
1929
- const backupSettingsPath = path3.join(backupPath, "settings.json.backup");
1930
- if (fs4.existsSync(backupSettingsPath)) {
1931
- const settingsPath = path3.join(ROOT_CLAUDE_DIR, "settings.json");
1932
- fs4.copyFileSync(backupSettingsPath, settingsPath);
1933
- }
1934
- import_devkit4.logger.info("\u2705 Backup restored successfully");
1935
- return true;
1936
- } catch (error) {
1937
- import_devkit4.logger.error(`\u274C Failed to restore backup: ${error}`);
1938
- return false;
1939
- }
1940
- }
1941
- async function testHooks() {
1942
- try {
1943
- import_devkit4.logger.info("\u{1F9EA} Testing installed hooks...");
1944
- const testPayload = {
1945
- hook_event_name: "Notification",
1946
- session_id: "test-session",
1947
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1948
- cwd: process.cwd()
1949
- };
1950
- const notificationHook = path3.join(HOOKS_DIR, "notification.ts");
1951
- if (!fs4.existsSync(notificationHook)) {
1952
- import_devkit4.logger.error("\u274C Notification hook not found");
1953
- return false;
1954
- }
1955
- const command = `echo '${JSON.stringify(
1956
- testPayload
1957
- )}' | npx tsx "${notificationHook}" --notify`;
1958
- import_devkit4.logger.info("\u{1F514} Triggering test notification...");
1959
- (0, import_child_process3.execSync)(command, { stdio: "inherit" });
1960
- import_devkit4.logger.info("\u2705 Hook test completed successfully");
1961
- import_devkit4.logger.info("You should have heard a notification sound/speech");
1962
- return true;
1963
- } catch (error) {
1964
- import_devkit4.logger.error(`\u274C Hook test failed: ${error}`);
1965
- return false;
1966
- }
1967
- }
1968
-
1969
- // packages/ai-toolkit-nx-claude/src/generators/hooks/generator.ts
1970
- async function hooksGenerator(tree, options) {
1971
- import_devkit5.logger.info("\u{1F3AF} Claude Code Hooks Generator");
1972
- import_devkit5.logger.info("Installing notification hooks for Claude Code...\n");
1973
- import_devkit5.logger.info("\u{1F4CB} Step 1: Checking dependencies...");
1974
- const depsOk = await checkAndValidateDependencies();
1975
- if (!depsOk && !options.force) {
1976
- import_devkit5.logger.error(
1977
- "\u274C Missing required dependencies. Install them and try again."
1978
- );
1979
- import_devkit5.logger.info("Use --force to skip dependency checks (not recommended)");
1980
- return;
1981
- }
1982
- const schemaPath = path4.join(__dirname, "schema.json");
1983
- let normalizedOptions;
1984
- if (options.installMode === "default") {
1985
- normalizedOptions = {
1986
- backup: options.backup !== false,
1987
- // Default to true unless explicitly false
1988
- dry: options.dry || false,
1989
- force: options.force || false,
1990
- verbose: options.verbose || false,
1991
- installMode: "default"
1992
- };
1993
- } else {
1994
- const explicitlyProvided = getExplicitlyProvidedOptions(options);
1995
- const nxDryRunProvided = isNxDryRunProvided();
1996
- if (nxDryRunProvided) {
1997
- options.dry = true;
1998
- explicitlyProvided.set("dry", true);
1999
- }
2000
- const nxNoInteractiveProvided = isNxNoInteractiveProvided();
2001
- const optionsWithNoInteractive = {
2002
- ...options,
2003
- "no-interactive": nxNoInteractiveProvided
2004
- };
2005
- try {
2006
- normalizedOptions = await promptForMissingOptions(
2007
- optionsWithNoInteractive,
2008
- schemaPath,
2009
- {},
2010
- // context for multi-select (not used here)
2011
- explicitlyProvided
2012
- // pass the explicitly provided options
2013
- );
2014
- } catch (error) {
2015
- if (error.message?.includes("Installation cancelled")) {
2016
- import_devkit5.logger.warn(`\u274C ${error.message}`);
2017
- return;
2018
- }
2019
- throw error;
2020
- }
2021
- }
2022
- const isDryRun = normalizedOptions.dry;
2023
- if (isDryRun) {
2024
- import_devkit5.logger.info("\n\u{1F50D} DRY RUN MODE - No changes will be made");
2025
- import_devkit5.logger.info("The following would be performed:");
2026
- import_devkit5.logger.info(` 1. Download latest notification hooks`);
2027
- import_devkit5.logger.info(` 2. Configure notification hooks`);
2028
- import_devkit5.logger.info(` 3. Install hooks to ~/.claude/hooks/`);
2029
- import_devkit5.logger.info(` 4. Update ~/.claude/settings.json`);
2030
- if (normalizedOptions.backup) {
2031
- import_devkit5.logger.info(` 5. Create backup of existing configuration`);
2032
- }
2033
- return;
2034
- }
2035
- import_devkit5.logger.info("\n\u{1F4E6} Step 2: Downloading notification hooks...");
2036
- const repoPath = await ensureRepository({
2037
- update: true,
2038
- // Always update to latest
2039
- verbose: normalizedOptions.verbose
2040
- });
2041
- if (!repoPath) {
2042
- import_devkit5.logger.error("\u274C Failed to prepare repository");
2043
- return;
2044
- }
2045
- import_devkit5.logger.info(`\u2705 Repository ready at: ${repoPath}`);
2046
- import_devkit5.logger.info("\n\u{1F680} Step 3: Installing hooks...");
2047
- const installResult = await runInstallation(repoPath, {
2048
- backupExisting: normalizedOptions.backup !== false,
2049
- verbose: normalizedOptions.verbose || false,
2050
- dryRun: isDryRun
2051
- });
2052
- if (!installResult.success) {
2053
- import_devkit5.logger.error("\u274C Installation failed");
2054
- if (installResult.error) {
2055
- import_devkit5.logger.error(`Error: ${installResult.error}`);
2056
- }
2057
- if (!normalizedOptions.verbose) {
2058
- cleanupRepository(repoPath);
2059
- }
2060
- return;
2061
- }
2062
- const shouldTest = !isDryRun && normalizedOptions.verbose;
2063
- if (shouldTest) {
2064
- import_devkit5.logger.info("\n\u{1F9EA} Step 4: Testing installation...");
2065
- const { prompt: prompt3 } = await import("enquirer");
2066
- const { runTest } = await prompt3({
2067
- type: "confirm",
2068
- name: "runTest",
2069
- message: "Would you like to test the hooks now?",
2070
- initial: true
2071
- });
2072
- if (runTest) {
2073
- await testHooks();
2074
- }
2075
- }
2076
- if (!normalizedOptions.verbose) {
2077
- import_devkit5.logger.info("\n\u{1F9F9} Cleaning up temporary files...");
2078
- cleanupRepository(repoPath);
2079
- }
2080
- await (0, import_devkit5.formatFiles)(tree);
2081
- import_devkit5.logger.info("\n\u2728 SUCCESS! Claude Code hooks installed successfully!");
2082
- import_devkit5.logger.info("\n\u{1F4DA} Next Steps:");
2083
- import_devkit5.logger.info(" 1. Start a Claude Code session");
2084
- import_devkit5.logger.info(" 2. When Claude needs your input, you'll hear a notification");
2085
- import_devkit5.logger.info(" 3. Check ~/.claude/logs/ for event logs (if enabled)");
2086
- if (installResult.backupPath) {
2087
- import_devkit5.logger.info(`
2088
- \u{1F4BE} Backup saved at: ${installResult.backupPath}`);
2089
- }
2090
- import_devkit5.logger.info("\n\u{1F389} Happy coding with Claude!");
2091
- }
2092
- var generator_default = hooksGenerator;
2093
-
2094
- // packages/ai-toolkit-nx-claude/src/generators/addons/generator.ts
2095
- var import_devkit6 = require("@nx/devkit");
2096
- init_addon_registry();
2097
-
2098
- // packages/ai-toolkit-nx-claude/src/generators/addons/claude-mcp-installer.ts
2099
- var import_child_process4 = require("child_process");
2100
- init_addon_registry();
2101
- async function installMcpServer(options) {
2102
- const { addon, additionalArgs = [], dryRun = false, installationType = "global" } = options;
2103
- try {
2104
- (0, import_child_process4.execSync)("claude --version", { stdio: "ignore" });
2105
- } catch {
2106
- return {
2107
- success: false,
2108
- message: "Claude CLI not found",
2109
- error: "Please install Claude CLI first. Visit https://claude.ai/download"
2110
- };
2111
- }
2112
- const serverName = addon.mcp?.serverName;
2113
- const scope = installationType === "local" ? "project" : "user";
2114
- let command = `claude mcp add ${serverName} --scope ${scope}`;
2115
- if (addon.mcp?.env && Object.keys(addon.mcp.env).length > 0) {
2116
- for (const [key, value] of Object.entries(addon.mcp.env)) {
2117
- command += ` --env ${key}=${value}`;
2118
- }
2119
- }
2120
- if (isCommandMcpServer(addon.mcp)) {
2121
- const mcpMetadata = addon.mcp;
2122
- command += " --";
2123
- if (mcpMetadata.command) {
2124
- command += ` ${mcpMetadata.command}`;
2125
- if (mcpMetadata.args && mcpMetadata.args.length > 0) {
2126
- command += ` ${mcpMetadata.args.join(" ")}`;
2127
- } else {
2128
- command += ` ${addon.packageName}@latest`;
2129
- }
2130
- if (addon.registry) {
2131
- command += ` ${addon.registry}`;
2132
- }
2133
- }
2134
- } else if (isRemoteHostedMcpServer(addon.mcp)) {
2135
- const mcpMetadata = addon.mcp;
2136
- command += ` --transport ${mcpMetadata.transport} ${mcpMetadata.url}`;
2137
- } else {
2138
- throw new Error(`Unsupported MCP addon with configuration: ${addon.mcp}`);
2139
- }
2140
- if (additionalArgs.length > 0) {
2141
- command += ` ${additionalArgs.join(" ")}`;
2142
- }
2143
- if (dryRun) {
2144
- console.log("\n\u{1F4CB} Would execute:");
2145
- console.log(command);
2146
- return {
2147
- success: true,
2148
- message: "Dry-run completed"
2149
- };
2150
- }
2151
- let attempts = 0;
2152
- const maxAttempts = 3;
2153
- let lastError;
2154
- while (attempts < maxAttempts) {
2155
- attempts++;
2156
- try {
2157
- console.log(`
2158
- \u{1F527} Installing MCP server (attempt ${attempts}/${maxAttempts})...`);
2159
- const output = (0, import_child_process4.execSync)(command, {
2160
- encoding: "utf-8",
2161
- stdio: "pipe"
2162
- });
2163
- if (output.includes("successfully") || output.includes("added")) {
2164
- return {
2165
- success: true,
2166
- message: "MCP server installed successfully"
2167
- };
2168
- }
2169
- console.log("Output:", output);
2170
- } catch (error) {
2171
- lastError = error;
2172
- if (error.message?.includes("already exists")) {
2173
- return {
2174
- success: true,
2175
- message: "MCP server already installed",
2176
- error: "Use --force to overwrite existing installation"
2177
- };
2178
- }
2179
- if (error.message?.includes("permission denied")) {
2180
- return {
2181
- success: false,
2182
- message: "Permission denied",
2183
- error: "Try running with administrator privileges"
2184
- };
2185
- }
2186
- if (error.message?.includes("network") || error.message?.includes("ENOTFOUND")) {
2187
- if (attempts < maxAttempts) {
2188
- console.log("Network error, retrying...");
2189
- await new Promise((resolve) => setTimeout(resolve, 2e3));
2190
- continue;
2191
- }
2192
- }
2193
- break;
2194
- }
2195
- }
2196
- return {
2197
- success: false,
2198
- message: "Failed to install MCP server",
2199
- error: lastError?.message || "Unknown error occurred"
2200
- };
2201
- }
2202
-
2203
- // packages/ai-toolkit-nx-claude/src/generators/addons/spec-workflow-setup.ts
2204
- var import_child_process5 = require("child_process");
2205
- var import_fs2 = require("fs");
2206
- var import_path2 = require("path");
2207
- var import_os2 = require("os");
2208
- var import_fs3 = require("fs");
2209
- async function setupSpecWorkflow(projectPath, options) {
2210
- const targetPath = projectPath || process.cwd();
2211
- const targetDir = (0, import_path2.join)(targetPath, ".spec-workflow");
2212
- console.log(`
2213
- \u{1F4C1} Setting up spec-workflow in: ${targetPath}`);
2214
- const isUpdate = (0, import_fs2.existsSync)(targetDir);
2215
- if (options.dryRun) {
2216
- console.log("[DRY-RUN] Would create/update directory: " + targetDir);
2217
- console.log("[DRY-RUN] Would clone repository: @uniswap/spec-workflow-mcp");
2218
- console.log("[DRY-RUN] Would copy/update configuration files");
2219
- console.log("[DRY-RUN] Would add .spec-workflow/ to .gitignore");
2220
- return {
2221
- success: true,
2222
- message: "[DRY-RUN] Spec-workflow setup simulated successfully",
2223
- projectPath: targetPath
2224
- };
2225
- }
2226
- if (isUpdate) {
2227
- if (!options.force) {
2228
- const { confirm } = await require("enquirer").prompt({
2229
- type: "confirm",
2230
- name: "confirm",
2231
- message: `.spec-workflow directory already exists. Update configuration files from repository?`,
2232
- initial: true
2233
- });
2234
- if (!confirm) {
2235
- return {
2236
- success: false,
2237
- message: "Installation cancelled by user",
2238
- projectPath: targetPath
2239
- };
2240
- }
2241
- }
2242
- console.log(
2243
- "\u{1F4DD} Updating configuration files in existing .spec-workflow directory..."
2244
- );
2245
- } else {
2246
- console.log("\u{1F4C1} Creating .spec-workflow directory...");
2247
- (0, import_fs2.mkdirSync)(targetDir, { recursive: true });
2248
- }
2249
- const tempDir = (0, import_path2.join)((0, import_os2.tmpdir)(), `spec-workflow-${Date.now()}`);
2250
- console.log("\u{1F504} Cloning spec-workflow repository...");
2251
- const cloneResult = await cloneRepository2(
2252
- "https://github.com/Uniswap/spec-workflow-mcp.git",
2253
- tempDir
2254
- );
2255
- if (!cloneResult.success) {
2256
- return {
2257
- success: false,
2258
- message: cloneResult.error || "Failed to clone repository",
2259
- projectPath: targetPath
2260
- };
2261
- }
2262
- console.log("\u{1F4CB} Copying configuration files...");
2263
- const configSourcePath = (0, import_path2.join)(tempDir, "configs");
2264
- const copyResult = await copyConfigFiles(configSourcePath, targetDir);
2265
- console.log("\u{1F9F9} Cleaning up temporary files...");
2266
- (0, import_fs2.rmSync)(tempDir, { recursive: true, force: true });
2267
- if (!copyResult.success) {
2268
- return {
2269
- success: false,
2270
- message: copyResult.error || "Failed to copy configuration files",
2271
- projectPath: targetPath
2272
- };
2273
- }
2274
- console.log("\u{1F4DD} Updating .gitignore...");
2275
- const gitignoreResult = await updateGitignore(targetPath, ".spec-workflow/");
2276
- if (!gitignoreResult.success) {
2277
- console.warn("\u26A0\uFE0F Warning:", gitignoreResult.message);
2278
- } else {
2279
- console.log("\u2705", gitignoreResult.message);
2280
- }
2281
- return {
2282
- success: true,
2283
- message: isUpdate ? "The spec-workflow configuration has been updated with the latest templates and settings" : "The spec-workflow package has been added to the project with automatic agent orchestration enabled",
2284
- projectPath: targetPath,
2285
- createdFiles: copyResult.copiedFiles
2286
- };
2287
- }
2288
- async function cloneRepository2(repositoryUrl, targetDir) {
2289
- try {
2290
- if (!(0, import_fs2.existsSync)(targetDir)) {
2291
- (0, import_fs2.mkdirSync)(targetDir, { recursive: true });
2292
- }
2293
- (0, import_child_process5.execSync)(`git clone --depth 1 "${repositoryUrl}" "${targetDir}"`, {
2294
- stdio: "pipe",
2295
- encoding: "utf8"
2296
- });
2297
- return {
2298
- success: true,
2299
- message: "Repository cloned successfully",
2300
- clonePath: targetDir
2301
- };
2302
- } catch (error) {
2303
- console.error("\u274C Git clone failed:", error.message);
2304
- if (error.message.includes("not found")) {
2305
- return {
2306
- success: false,
2307
- message: "Repository not found",
2308
- error: "The repository URL may be incorrect or you may not have access"
2309
- };
2310
- } else if (error.message.includes("Authentication")) {
2311
- return {
2312
- success: false,
2313
- message: "Authentication failed",
2314
- error: "Please check your git credentials"
2315
- };
2316
- } else if (error.message.includes("network")) {
2317
- return {
2318
- success: false,
2319
- message: "Network error",
2320
- error: "Please check your internet connection"
2321
- };
2322
- }
2323
- return {
2324
- success: false,
2325
- message: "Git clone failed",
2326
- error: error.message
2327
- };
2328
- }
2329
- }
2330
- async function updateGitignore(projectPath, pattern) {
2331
- const gitignorePath = (0, import_path2.join)(projectPath, ".gitignore");
2332
- try {
2333
- let gitignoreContent = "";
2334
- if ((0, import_fs2.existsSync)(gitignorePath)) {
2335
- gitignoreContent = (0, import_fs2.readFileSync)(gitignorePath, "utf8");
2336
- }
2337
- const lines = gitignoreContent.split("\n");
2338
- const patternExists = lines.some((line) => {
2339
- const trimmedLine = line.trim();
2340
- return trimmedLine === pattern || trimmedLine === pattern.replace(/\/$/, "");
2341
- });
2342
- if (patternExists) {
2343
- return {
2344
- success: true,
2345
- message: `.gitignore already contains ${pattern}`
2346
- };
2347
- }
2348
- const updatedContent = gitignoreContent.trim() === "" ? pattern : `${gitignoreContent.trim()}
2349
-
2350
- # Spec workflow configuration
2351
- ${pattern}`;
2352
- (0, import_fs2.writeFileSync)(gitignorePath, updatedContent + "\n", "utf8");
2353
- return {
2354
- success: true,
2355
- message: `Added ${pattern} to .gitignore`
2356
- };
2357
- } catch (error) {
2358
- console.error("\u274C Failed to update .gitignore:", error.message);
2359
- return {
2360
- success: false,
2361
- message: `Failed to update .gitignore: ${error.message}`
2362
- };
2363
- }
2364
- }
2365
- async function copyConfigFiles(sourceDir, targetDir) {
2366
- try {
2367
- let listFiles2 = function(dir, baseDir = dir, sourceBase = sourceDir) {
2368
- const files = fs6.readdirSync(dir);
2369
- for (const file of files) {
2370
- const filePath = (0, import_path2.join)(dir, file);
2371
- const stat = fs6.statSync(filePath);
2372
- if (stat.isDirectory()) {
2373
- listFiles2(filePath, baseDir, sourceBase);
2374
- } else {
2375
- const relativePath = filePath.replace(baseDir + "/", "");
2376
- const sourceFile = (0, import_path2.join)(sourceBase, relativePath);
2377
- if ((0, import_fs2.existsSync)(sourceFile)) {
2378
- copiedFiles.push(relativePath);
2379
- }
2380
- }
2381
- }
2382
- };
2383
- var listFiles = listFiles2;
2384
- if (!(0, import_fs2.existsSync)(sourceDir)) {
2385
- return {
2386
- success: false,
2387
- message: "Source directory not found",
2388
- error: `The configs directory was not found in the cloned repository`
2389
- };
2390
- }
2391
- (0, import_fs3.cpSync)(sourceDir, targetDir, { recursive: true });
2392
- const fs6 = require("fs");
2393
- const copiedFiles = [];
2394
- listFiles2(targetDir, targetDir, sourceDir);
2395
- return {
2396
- success: true,
2397
- message: "Configuration files copied successfully",
2398
- copiedFiles
2399
- };
2400
- } catch (error) {
2401
- console.error("\u274C File copy failed:", error.message);
2402
- return {
2403
- success: false,
2404
- message: "Failed to copy configuration files",
2405
- error: error.message
2406
- };
2407
- }
2408
- }
2409
-
2410
- // packages/ai-toolkit-nx-claude/src/generators/addons/aws-log-analyzer-setup.ts
2411
- var import_child_process6 = require("child_process");
2412
- var import_fs4 = require("fs");
2413
- var import_path3 = require("path");
2414
- var import_os3 = require("os");
2415
- async function setupAwsLogAnalyzer(options) {
2416
- const targetPath = (0, import_path3.join)((0, import_os3.homedir)(), ".aws-log-analyzer-mcp");
2417
- const serverPath = (0, import_path3.join)(targetPath, "src", "cw-mcp-server");
2418
- console.log(`
2419
- \u{1F4C1} Setting up AWS Log Analyzer MCP in: ${targetPath}`);
2420
- const isUpdate = (0, import_fs4.existsSync)(targetPath);
2421
- if (options.dryRun) {
2422
- console.log("[DRY-RUN] Would clone repository to: " + targetPath);
2423
- console.log("[DRY-RUN] MCP server would run from: " + serverPath);
2424
- console.log("[DRY-RUN] Would run: uv sync to install Python dependencies");
2425
- return {
2426
- success: true,
2427
- message: "[DRY-RUN] AWS Log Analyzer setup simulated successfully",
2428
- clonedPath: targetPath,
2429
- serverPath
2430
- };
2431
- }
2432
- if (isUpdate) {
2433
- if (!options.force) {
2434
- const { confirm } = await require("enquirer").prompt({
2435
- type: "confirm",
2436
- name: "confirm",
2437
- message: `AWS Log Analyzer repository already exists at ${targetPath}. Update to latest version?`,
2438
- initial: true
2439
- });
2440
- if (!confirm) {
2441
- console.log("\u2705 Using existing installation at:", targetPath);
2442
- return {
2443
- success: true,
2444
- message: "Using existing AWS Log Analyzer installation",
2445
- clonedPath: targetPath,
2446
- serverPath
2447
- };
2448
- }
2449
- }
2450
- console.log("\u{1F504} Updating AWS Log Analyzer repository...");
2451
- (0, import_fs4.rmSync)(targetPath, { recursive: true, force: true });
2452
- }
2453
- console.log("\u{1F4C1} Creating installation directory...");
2454
- (0, import_fs4.mkdirSync)(targetPath, { recursive: true });
2455
- console.log("\u{1F504} Cloning AWS Log Analyzer repository...");
2456
- const cloneResult = await cloneRepository2(
2457
- "https://github.com/awslabs/Log-Analyzer-with-MCP.git",
2458
- targetPath
2459
- );
2460
- if (!cloneResult.success) {
2461
- return {
2462
- success: false,
2463
- message: "Failed to clone AWS Log Analyzer repository",
2464
- error: cloneResult.error || cloneResult.message
2465
- };
2466
- }
2467
- console.log("\u{1F4E6} Installing Python dependencies with uv...");
2468
- try {
2469
- (0, import_child_process6.execSync)("uv sync", {
2470
- cwd: targetPath,
2471
- stdio: "inherit",
2472
- encoding: "utf8"
2473
- });
2474
- console.log("\u2705 Python dependencies installed successfully");
2475
- } catch (error) {
2476
- console.warn("\u26A0\uFE0F Warning: Failed to install Python dependencies");
2477
- console.warn(' You may need to run "uv sync" manually in:', targetPath);
2478
- console.warn(" Error:", error.message);
2479
- }
2480
- return {
2481
- success: true,
2482
- message: isUpdate ? "AWS Log Analyzer has been updated to the latest version" : "AWS Log Analyzer has been installed successfully",
2483
- clonedPath: targetPath,
2484
- serverPath
2485
- };
2486
- }
2487
- function getAwsLogAnalyzerPath() {
2488
- return (0, import_path3.join)((0, import_os3.homedir)(), ".aws-log-analyzer-mcp");
2489
- }
2490
- function getAwsLogAnalyzerServerPath() {
2491
- return (0, import_path3.join)(getAwsLogAnalyzerPath(), "src", "cw-mcp-server");
2492
- }
2493
-
2494
- // packages/ai-toolkit-nx-claude/src/generators/addons/generator.ts
2495
- async function generator(tree, schema) {
2496
- console.log("\n\u{1F3AF} Claude Code Addons Installer");
2497
- console.log("================================\n");
2498
- const dryRunFlagProvided = isNxDryRunProvided() ?? schema.dry;
2499
- const noInteractive = isNxNoInteractiveProvided();
2500
- let isDryRun = dryRunFlagProvided;
2501
- if (isDryRun === void 0 && !noInteractive) {
2502
- const { runDryRun } = await require("enquirer").prompt({
2503
- type: "confirm",
2504
- name: "runDryRun",
2505
- message: "\u{1F50D} Would you like to run in dry-run mode (preview changes without making them)?",
2506
- initial: false
2507
- });
2508
- isDryRun = runDryRun;
2509
- }
2510
- if (isDryRun) {
2511
- console.log("\u{1F50D} Dry-run mode activated\n");
2512
- }
2513
- let options;
2514
- if (schema.installMode === "default") {
2515
- options = {
2516
- selectionMode: schema.selectionMode || "all",
2517
- force: schema.force || false,
2518
- skipVerification: schema.skipVerification || false,
2519
- dashboardMode: schema.dashboardMode || "always",
2520
- port: schema.port || 0,
2521
- dry: schema.dry || false,
2522
- installMode: "default",
2523
- installationType: schema.installationType || "global",
2524
- dryRun: isDryRun
2525
- };
2526
- } else {
2527
- const availableAddons = getAvailableAddons();
2528
- options = await promptForMissingOptions(schema, require_schema(), {
2529
- availableAddons: availableAddons.map((a) => a.id),
2530
- addonDescriptions: availableAddons.reduce((acc, a) => {
2531
- acc[a.id] = `${a.name}: ${a.description}`;
2532
- return acc;
2533
- }, {})
2534
- });
2535
- options.dryRun = isDryRun;
2536
- }
2537
- if (options.selectionMode === "all") {
2538
- await installAllAddons(tree, options);
2539
- return;
2540
- }
2541
- await installSelectedAddons(tree, options);
2542
- await (0, import_devkit6.formatFiles)(tree);
2543
- }
2544
- async function installSelectedAddons(tree, options) {
2545
- const selectedAddonIds = options.addons || [];
2546
- if (selectedAddonIds.length === 0) {
2547
- console.log("\n\u26A0\uFE0F No addons selected for installation");
2548
- return;
2549
- }
2550
- const selectedAddons = selectedAddonIds.map((id) => getAddonById(id)).filter((addon) => addon !== void 0);
2551
- if (selectedAddons.length === 0) {
2552
- throw new Error("No valid addons found in selection");
2553
- }
2554
- console.log("\n\u{1F4E6} Installing Selected MCP Servers");
2555
- console.log("===================================\n");
2556
- console.log(`Installing ${selectedAddons.length} MCP server(s)
2557
- `);
2558
- const results = [];
2559
- for (let i = 0; i < selectedAddons.length; i++) {
2560
- const addon = selectedAddons[i];
2561
- console.log(`
2562
- [${i + 1}/${selectedAddons.length}] Installing: ${addon.name}`);
2563
- console.log(` ${addon.description}`);
2564
- try {
2565
- if (!options.force && !options.dryRun) {
2566
- const installed = await isAddonInstalled(addon.id);
2567
- if (installed) {
2568
- console.log(" \u2705 Already installed, skipping");
2569
- results.push({ addon, success: true });
2570
- continue;
2571
- }
2572
- }
2573
- const validation = await validateAddonRequirements(addon.id);
2574
- if (!validation.valid && !options.force) {
2575
- console.log(" \u26A0\uFE0F Requirements not met:");
2576
- validation.errors.forEach((error) => console.log(` \u2022 ${error}`));
2577
- console.log(" \u23ED\uFE0F Skipping (use --force to override)");
2578
- results.push({
2579
- addon,
2580
- success: false,
2581
- error: "Requirements not met"
2582
- });
2583
- continue;
2584
- }
2585
- await installMcpAddon(addon, options);
2586
- if (addon.id === "spec-workflow-mcp" && addon.projectSetup && i === selectedAddons.length - 1) {
2587
- const { setupProject } = await require("enquirer").prompt({
2588
- type: "confirm",
2589
- name: "setupProject",
2590
- message: "\u{1F4C1} Would you like to set up spec-workflow configuration for a particular project?",
2591
- initial: true
2592
- });
2593
- if (setupProject) {
2594
- const { projectPath } = await require("enquirer").prompt({
2595
- type: "input",
2596
- name: "projectPath",
2597
- message: "\u{1F4C1} Enter the project path where spec-workflow config should be added:",
2598
- initial: process.cwd(),
2599
- result: (value) => value || process.cwd()
2600
- });
2601
- options.projectPath = projectPath;
2602
- if (options.dryRun) {
2603
- console.log(`
2604
- \u{1F4C1} [DRY-RUN] Would set up project configuration at: ${projectPath}`);
2605
- }
2606
- await installProjectSetup(addon, options);
2607
- } else if (options.dryRun) {
2608
- console.log("\n\u{1F4C1} [DRY-RUN] Skipping project configuration (user chose not to set up)");
2609
- }
2610
- }
2611
- results.push({ addon, success: true });
2612
- } catch (error) {
2613
- console.error(` \u274C Failed: ${error instanceof Error ? error.message : String(error)}`);
2614
- results.push({
2615
- addon,
2616
- success: false,
2617
- error: error instanceof Error ? error.message : String(error)
2618
- });
2619
- }
2620
- }
2621
- console.log("\n\n\u{1F4CA} Installation Summary");
2622
- console.log("======================\n");
2623
- const successful = results.filter((r) => r.success);
2624
- const failed = results.filter((r) => !r.success);
2625
- console.log(`\u2705 Successfully installed: ${successful.length}`);
2626
- successful.forEach((r) => console.log(` \u2022 ${r.addon.name}`));
2627
- if (failed.length > 0) {
2628
- console.log(`
2629
- \u274C Failed to install: ${failed.length}`);
2630
- failed.forEach((r) => console.log(` \u2022 ${r.addon.name} - ${r.error || "Unknown error"}`));
2631
- }
2632
- if (options.dryRun) {
2633
- console.log("\n\u2728 Dry-run complete! No changes were made.\n");
2634
- showGeneralMcpInstructions(selectedAddons);
2635
- } else {
2636
- console.log("\n\u2728 Installation complete!\n");
2637
- showGeneralMcpInstructions(successful.map((r) => r.addon));
2638
- }
2639
- }
2640
- async function installAllAddons(tree, options) {
2641
- const allAddons = (init_addon_registry(), __toCommonJS(addon_registry_exports)).getAvailableAddons();
2642
- console.log("\n\u{1F4E6} Installing All Recommended MCP Servers");
2643
- console.log("==========================================\n");
2644
- console.log(`Found ${allAddons.length} MCP servers to install
2645
- `);
2646
- const results = [];
2647
- for (let i = 0; i < allAddons.length; i++) {
2648
- const addon = allAddons[i];
2649
- console.log(`
2650
- [${i + 1}/${allAddons.length}] Installing: ${addon.name}`);
2651
- console.log(` ${addon.description}`);
2652
- try {
2653
- if (!options.force && !options.dryRun) {
2654
- const installed = await isAddonInstalled(addon.id);
2655
- if (installed) {
2656
- console.log(" \u2705 Already installed, skipping");
2657
- results.push({ addon, success: true });
2658
- continue;
2659
- }
2660
- }
2661
- const validation = await validateAddonRequirements(addon.id);
2662
- if (!validation.valid && !options.force) {
2663
- console.log(" \u26A0\uFE0F Requirements not met:");
2664
- validation.errors.forEach((error) => console.log(` \u2022 ${error}`));
2665
- console.log(" \u23ED\uFE0F Skipping (use --force to override)");
2666
- results.push({
2667
- addon,
2668
- success: false,
2669
- error: "Requirements not met"
2670
- });
2671
- continue;
2672
- }
2673
- await installMcpAddon(addon, options);
2674
- results.push({ addon, success: true });
2675
- } catch (error) {
2676
- console.error(` \u274C Failed: ${error instanceof Error ? error.message : String(error)}`);
2677
- results.push({
2678
- addon,
2679
- success: false,
2680
- error: error instanceof Error ? error.message : String(error)
2681
- });
2682
- }
2683
- }
2684
- console.log("\n\n\u{1F4CA} Installation Summary");
2685
- console.log("======================\n");
2686
- const successful = results.filter((r) => r.success);
2687
- const failed = results.filter((r) => !r.success);
2688
- console.log(`\u2705 Successfully installed: ${successful.length}`);
2689
- successful.forEach((r) => console.log(` \u2022 ${r.addon.name}`));
2690
- if (failed.length > 0) {
2691
- console.log(`
2692
- \u274C Failed to install: ${failed.length}`);
2693
- failed.forEach((r) => console.log(` \u2022 ${r.addon.name} - ${r.error || "Unknown error"}`));
2694
- }
2695
- if (options.dryRun) {
2696
- console.log("\n\u2728 Dry-run complete! No changes were made.\n");
2697
- showGeneralMcpInstructions(allAddons);
2698
- } else {
2699
- console.log("\n\u2728 Batch installation complete!\n");
2700
- showGeneralMcpInstructions(successful.map((r) => r.addon));
2701
- }
2702
- }
2703
- async function installMcpAddon(addon, options) {
2704
- if (addon.id === "aws-log-analyzer-mcp") {
2705
- console.log("\n\u{1F4E6} AWS Log Analyzer requires repository setup...");
2706
- const setupResult = await setupAwsLogAnalyzer(options);
2707
- if (!setupResult.success) {
2708
- throw new Error(setupResult.error || setupResult.message);
2709
- }
2710
- console.log(`\u2705 ${setupResult.message}`);
2711
- const serverPath = setupResult.serverPath || getAwsLogAnalyzerServerPath();
2712
- addon.mcp.args = ["--directory", serverPath, "run", "server.py"];
2713
- console.log(`\u{1F4CD} Server path: ${serverPath}`);
2714
- }
2715
- if (options.dryRun) {
2716
- console.log("\n\u{1F527} [DRY-RUN] Simulating MCP server installation...");
2717
- } else {
2718
- console.log("\n\u{1F527} Installing MCP server...");
2719
- }
2720
- const additionalArgs = [];
2721
- if (addon.id === "spec-workflow-mcp") {
2722
- if (options.dashboardMode === "always") {
2723
- additionalArgs.push("--AutoStartDashboard");
2724
- }
2725
- if (options.port && options.port > 0) {
2726
- additionalArgs.push(`--Port=${options.port}`);
2727
- }
2728
- }
2729
- const installResult = await installMcpServer({
2730
- addon,
2731
- additionalArgs,
2732
- dryRun: options.dryRun,
2733
- installationType: options.installationType || "global"
2734
- });
2735
- if (!installResult.success) {
2736
- throw new Error(installResult.error || installResult.message);
2737
- }
2738
- console.log(`\u2705 ${installResult.message}`);
2739
- }
2740
- async function installProjectSetup(addon, options) {
2741
- console.log("\n\u{1F527} Setting up project configuration...");
2742
- const projectPath = options.projectPath || process.cwd();
2743
- console.log(`\u{1F4CD} Using project directory: ${projectPath}`);
2744
- const result = await setupSpecWorkflow(projectPath, options);
2745
- if (!result.success) {
2746
- throw new Error(result.message);
2747
- }
2748
- console.log(`\u2705 ${result.message}`);
2749
- }
2750
- function showGeneralMcpInstructions(installedAddons) {
2751
- console.log("\n\u{1F4DA} Getting Started with Your MCPs");
2752
- console.log("==================================\n");
2753
- console.log("Most MCPs require authentication before use. Here's how:");
2754
- console.log("\n1. Start a new Claude Code session");
2755
- console.log("2. Run the `/mcp` slash command");
2756
- console.log("3. Select the MCP you want to configure");
2757
- console.log("4. Follow the authentication instructions");
2758
- console.log("5. Once authenticated, you can use the MCP in Claude Code\n");
2759
- console.log("\u{1F4D6} Example: Linear MCP Authentication");
2760
- console.log(" https://linear.app/docs/mcp#claude");
2761
- console.log(" (Most MCPs follow a similar authentication flow)\n");
2762
- const needsAuth = installedAddons.filter(
2763
- (addon) => addon.id === "slack-mcp" || addon.id === "github-mcp" || addon.id === "aws-log-analyzer-mcp" || addon.id === "linear-mcp" || addon.id === "notion-mcp" || addon.id === "supabase-mcp" || addon.id === "pulumi-mcp"
2764
- );
2765
- if (needsAuth.length > 0) {
2766
- console.log("\u{1F510} MCPs requiring authentication:");
2767
- needsAuth.forEach((addon) => {
2768
- console.log(` \u2022 ${addon.name}`);
2769
- });
2770
- console.log("");
2771
- }
2772
- const hasSlack = installedAddons.some((addon) => addon.id === "slack-mcp");
2773
- const hasGithub = installedAddons.some((addon) => addon.id === "github-mcp");
2774
- const hasPulumi = installedAddons.some((addon) => addon.id === "pulumi-mcp");
2775
- const hasAws = installedAddons.some((addon) => addon.id === "aws-log-analyzer-mcp");
2776
- if (hasSlack || hasGithub || hasAws || hasPulumi) {
2777
- console.log("\u{1F4CB} Specific Authentication Instructions:\n");
2778
- if (hasSlack) {
2779
- console.log("\u{1F510} Slack MCP:");
2780
- console.log(
2781
- " \u{1F4D6} Documentation: https://www.notion.so/uniswaplabs/Using-a-Slack-MCP-with-Claude-Claude-Code-249c52b2548b8052b901dc05d90e57fc"
2782
- );
2783
- console.log(
2784
- " This guide contains detailed instructions on how to obtain your Slack bot token.\n"
2785
- );
2786
- }
2787
- if (hasGithub) {
2788
- console.log("\u{1F510} GitHub MCP:");
2789
- console.log(" You can obtain your GitHub Personal Access Token using:");
2790
- console.log(" $ gh auth token");
2791
- console.log(" (Requires GitHub CLI to be installed and authenticated)\n");
2792
- }
2793
- if (hasAws) {
2794
- console.log("\u{1F510} AWS Log Analyzer MCP:");
2795
- console.log(" Requires AWS credentials with CloudWatchLogsReadOnlyAccess");
2796
- console.log(" \u{1F4D6} Documentation: https://github.com/awslabs/Log-Analyzer-with-MCP\n");
2797
- }
2798
- if (hasPulumi) {
2799
- console.log("\u{1F510} Pulumi MCP:");
2800
- console.log(
2801
- " When authenticating for the first time, you will need to create a Pulumi Personal Access Token (PAT)."
2802
- );
2803
- console.log(
2804
- " \u{1F4D6} Documentation: https://www.pulumi.com/docs/iac/guides/ai-integration/mcp-server/"
2805
- );
2806
- console.log(" Create your PAT at: https://app.pulumi.com/account/tokens\n");
2807
- }
2808
- }
2809
- }
2810
-
2811
- // packages/ai-toolkit-nx-claude/src/generators/init/generator.ts
2812
- var DEFAULT_COMMANDS = ["explore", "plan", "review-plan", "execute-plan", "address-pr-issues"];
2813
- var DEFAULT_AGENTS = [
2814
- "context-loader",
2815
- "planner",
2816
- "plan-reviewer",
2817
- "test-writer",
2818
- "doc-writer",
2819
- "pr-reviewer"
2820
- ];
2821
- function checkExistingFiles(targetDir, subDir, items) {
2822
- const existing = /* @__PURE__ */ new Set();
2823
- const dir = path5.join(targetDir, subDir);
2824
- for (const item of items) {
2825
- const filePath = path5.join(dir, `${item}.md`);
2826
- if (fs5.existsSync(filePath)) {
2827
- existing.add(item);
2828
- }
2829
- }
2830
- return existing;
2831
- }
2832
- async function initGenerator(tree, options) {
2833
- const explicitlyProvided = getExplicitlyProvidedOptions();
2834
- const nxDryRunProvided = isNxDryRunProvided();
2835
- if (nxDryRunProvided) {
2836
- options.dry = true;
2837
- explicitlyProvided.set("dry", true);
2838
- }
2839
- const nxNoInteractiveProvided = isNxNoInteractiveProvided();
2840
- let isDryRun = options.dry;
2841
- if (!nxNoInteractiveProvided && !options.nonInteractive && !isDryRun) {
2842
- const isClaudeInstalled = checkClaudeInstalled();
2843
- if (!isClaudeInstalled) {
2844
- import_devkit7.logger.warn("\u26A0\uFE0F Claude CLI is not installed");
2845
- const shouldInstall = await promptInstallClaude();
2846
- if (shouldInstall) {
2847
- await installClaude();
2848
- }
2849
- } else {
2850
- import_devkit7.logger.info("\u2705 Claude CLI is installed");
2851
- }
2852
- } else if (isDryRun && !checkClaudeInstalled()) {
2853
- import_devkit7.logger.info("\u{1F50D} DRY RUN: Claude CLI is not installed");
2854
- import_devkit7.logger.info("Would attempt installation in this order:");
2855
- import_devkit7.logger.info(" 1. curl -fsSL https://claude.ai/install.sh | bash");
2856
- import_devkit7.logger.info(" 2. npm install -g @anthropic-ai/claude-code (if curl fails)");
2857
- import_devkit7.logger.info(" 3. Manual instructions (if both fail)");
2858
- }
2859
- const installMode = options.installMode;
2860
- if (installMode === "default") {
2861
- import_devkit7.logger.info("\u{1F4E6} Default Installation Mode");
2862
- import_devkit7.logger.info(" Installing recommended setup with pre-selected components\n");
2863
- options.installMode = "default";
2864
- options.installationType = "global";
2865
- options.commands = DEFAULT_COMMANDS;
2866
- options.agents = DEFAULT_AGENTS;
2867
- options.installCommands = true;
2868
- options.installAgents = true;
2869
- options.installHooks = true;
2870
- options.hooksMode = "sound";
2871
- options.installAddons = true;
2872
- options.dry = false;
2873
- import_devkit7.logger.info("\u{1F4CD} Location: Global (~/.claude)");
2874
- import_devkit7.logger.info(`\u{1F4DD} Commands: ${DEFAULT_COMMANDS.length} pre-selected`);
2875
- import_devkit7.logger.info(`\u{1F916} Agents: ${DEFAULT_AGENTS.length} pre-selected`);
2876
- import_devkit7.logger.info(`\u{1F50C} MCPs: All recommended servers will be installed
2877
- `);
2878
- explicitlyProvided.set("installMode", "default");
2879
- explicitlyProvided.set("installationType", "global");
2880
- explicitlyProvided.set("installCommands", true);
2881
- explicitlyProvided.set("installAgents", true);
2882
- explicitlyProvided.set("installHooks", true);
2883
- explicitlyProvided.set("hooksMode", "sound");
2884
- explicitlyProvided.set("installAddons", true);
2885
- explicitlyProvided.set("dry", false);
2886
- explicitlyProvided.set("commands", DEFAULT_COMMANDS);
2887
- explicitlyProvided.set("agents", DEFAULT_AGENTS);
2888
- }
2889
- const schemaPath = path5.join(__dirname, "schema.json");
2890
- const commandDescriptions = Object.fromEntries(
2891
- Object.entries(commands).map(([key, value]) => [key, value.description])
2892
- );
2893
- const agentDescriptions = Object.fromEntries(
2894
- Object.entries(agents).map(([key, value]) => [key, value.description])
2895
- );
2896
- const homeDir = os4.homedir();
2897
- const globalDir = path5.join(homeDir, ".claude");
2898
- const localDir = path5.join(process.cwd(), ".claude");
2899
- const globalExistingCommands = checkExistingFiles(
2900
- globalDir,
2901
- "commands",
2902
- Object.keys(commands)
2903
- );
2904
- const globalExistingAgents = checkExistingFiles(globalDir, "agents", Object.keys(agents));
2905
- const localExistingCommands = checkExistingFiles(
2906
- localDir,
2907
- "commands",
2908
- Object.keys(commands)
2909
- );
2910
- const localExistingAgents = checkExistingFiles(localDir, "agents", Object.keys(agents));
2911
- const optionsWithNoInteractive = {
2912
- ...options,
2913
- "no-interactive": nxNoInteractiveProvided || options.nonInteractive
2914
- };
2915
- let normalizedOptions;
2916
- try {
2917
- normalizedOptions = await promptForMissingOptions(
2918
- optionsWithNoInteractive,
2919
- schemaPath,
2920
- {
2921
- availableCommands: Object.keys(commands),
2922
- availableAgents: Object.keys(agents),
2923
- commandDescriptions,
2924
- agentDescriptions,
2925
- globalExistingCommands,
2926
- globalExistingAgents,
2927
- localExistingCommands,
2928
- localExistingAgents,
2929
- defaultCommands: DEFAULT_COMMANDS,
2930
- defaultAgents: DEFAULT_AGENTS
2931
- },
2932
- explicitlyProvided
2933
- );
2934
- } catch (error) {
2935
- if (error.message?.includes("Installation cancelled")) {
2936
- import_devkit7.logger.warn(`\u274C ${error.message}`);
2937
- return;
2938
- }
2939
- throw error;
2940
- }
2941
- isDryRun = normalizedOptions.dry || false;
2942
- if (isDryRun) {
2943
- import_devkit7.logger.info("\u{1F50D} DRY RUN MODE - No files will be modified");
2944
- }
2945
- if (normalizedOptions.commandSelectionMode === "all") {
2946
- normalizedOptions.commands = Object.keys(commands);
2947
- import_devkit7.logger.info(`\u{1F4DD} All commands selected (${normalizedOptions.commands.length} total)`);
2948
- }
2949
- if (normalizedOptions.agentSelectionMode === "all") {
2950
- normalizedOptions.agents = Object.keys(agents);
2951
- import_devkit7.logger.info(`\u{1F916} All agents selected (${normalizedOptions.agents.length} total)`);
2952
- }
2953
- if (normalizedOptions.installCommands === false) {
2954
- normalizedOptions.commands = [];
2955
- }
2956
- if (normalizedOptions.installAgents === false) {
2957
- normalizedOptions.agents = [];
2958
- }
2959
- const isGlobalInstall = normalizedOptions.installationType === "global";
2960
- const workspaceRoot = process.cwd();
2961
- const targetDir = isGlobalInstall ? path5.join(homeDir, ".claude") : path5.join(workspaceRoot, ".claude");
2962
- const relativeTargetDir = isGlobalInstall ? path5.relative(workspaceRoot, targetDir) : ".claude";
2963
- const relativeManifestPath = path5.join(relativeTargetDir, "manifest.json");
2964
- if (!isDryRun) {
2965
- if (tree.exists(relativeManifestPath)) {
2966
- if (!normalizedOptions.force) {
2967
- if (normalizedOptions.nonInteractive) {
2968
- import_devkit7.logger.warn(
2969
- "Installation cancelled - existing Claude configuration found. Use --force to overwrite."
2970
- );
2971
- return;
2972
- }
2973
- }
2974
- }
2975
- }
2976
- const commandsDir = path5.join(targetDir, "commands");
2977
- const agentsDir = path5.join(targetDir, "agents");
2978
- const relativeCommandsDir = path5.join(relativeTargetDir, "commands");
2979
- const relativeAgentsDir = path5.join(relativeTargetDir, "agents");
2980
- const installedCommands = [];
2981
- const installedAgents = [];
2982
- const installedFiles = [];
2983
- const commandsToInstall = normalizedOptions.commands || [];
2984
- for (const commandName of commandsToInstall) {
2985
- let sourcePath = null;
2986
- const bundledContentDir = path5.join(__dirname, "..", "..", "content", "commands");
2987
- if (fs5.existsSync(bundledContentDir)) {
2988
- const contentSubDirs = fs5.readdirSync(bundledContentDir).filter((item) => {
2989
- const itemPath = path5.join(bundledContentDir, item);
2990
- return fs5.statSync(itemPath).isDirectory();
2991
- });
2992
- for (const subDir of contentSubDirs) {
2993
- const potentialPath = path5.join(bundledContentDir, subDir, `${commandName}.md`);
2994
- if (fs5.existsSync(potentialPath)) {
2995
- sourcePath = potentialPath;
2996
- break;
2997
- }
2998
- }
2999
- }
3000
- if (!sourcePath) {
3001
- const commandsBaseDir = path5.join(workspaceRoot, "packages/commands");
3002
- if (fs5.existsSync(commandsBaseDir)) {
3003
- const commandSubDirs = fs5.readdirSync(commandsBaseDir).filter((item) => {
3004
- const itemPath = path5.join(commandsBaseDir, item);
3005
- return fs5.statSync(itemPath).isDirectory();
3006
- });
3007
- for (const subDir of commandSubDirs) {
3008
- const potentialPath = path5.join(commandsBaseDir, subDir, "src", `${commandName}.md`);
3009
- if (fs5.existsSync(potentialPath)) {
3010
- sourcePath = potentialPath;
3011
- break;
3012
- }
3013
- }
3014
- }
3015
- }
3016
- const destPath = path5.join(commandsDir, `${commandName}.md`);
3017
- const relativeDestPath = path5.join(relativeCommandsDir, `${commandName}.md`);
3018
- try {
3019
- if (sourcePath && fs5.existsSync(sourcePath)) {
3020
- const content = fs5.readFileSync(sourcePath, "utf-8");
3021
- if (!isDryRun) {
3022
- tree.write(relativeDestPath, content);
3023
- }
3024
- installedCommands.push(commandName);
3025
- installedFiles.push(path5.relative(targetDir, destPath));
3026
- } else {
3027
- import_devkit7.logger.warn(`Command file not found: ${commandName}`);
3028
- }
3029
- } catch (error) {
3030
- import_devkit7.logger.warn(`Error reading command ${commandName}: ${error}`);
3031
- }
3032
- }
3033
- const agentsToInstall = normalizedOptions.agents || [];
3034
- for (const agentName of agentsToInstall) {
3035
- let sourcePath = null;
3036
- const bundledContentDir = path5.join(__dirname, "..", "..", "content", "agents");
3037
- if (fs5.existsSync(bundledContentDir)) {
3038
- const contentSubDirs = fs5.readdirSync(bundledContentDir).filter((item) => {
3039
- const itemPath = path5.join(bundledContentDir, item);
3040
- return fs5.statSync(itemPath).isDirectory();
3041
- });
3042
- for (const subDir of contentSubDirs) {
3043
- const potentialPath = path5.join(bundledContentDir, subDir, `${agentName}.md`);
3044
- if (fs5.existsSync(potentialPath)) {
3045
- sourcePath = potentialPath;
3046
- break;
3047
- }
3048
- }
3049
- }
3050
- if (!sourcePath) {
3051
- const agentsBaseDir = path5.join(workspaceRoot, "packages/agents");
3052
- if (fs5.existsSync(agentsBaseDir)) {
3053
- const agentSubDirs = fs5.readdirSync(agentsBaseDir).filter((item) => {
3054
- const itemPath = path5.join(agentsBaseDir, item);
3055
- return fs5.statSync(itemPath).isDirectory();
3056
- });
3057
- for (const subDir of agentSubDirs) {
3058
- const potentialPath = path5.join(agentsBaseDir, subDir, "src", `${agentName}.md`);
3059
- if (fs5.existsSync(potentialPath)) {
3060
- sourcePath = potentialPath;
3061
- break;
3062
- }
3063
- }
3064
- }
3065
- }
3066
- const destPath = path5.join(agentsDir, `${agentName}.md`);
3067
- const relativeDestPath = path5.join(relativeAgentsDir, `${agentName}.md`);
3068
- try {
3069
- if (sourcePath && fs5.existsSync(sourcePath)) {
3070
- const content = fs5.readFileSync(sourcePath, "utf-8");
3071
- if (!isDryRun) {
3072
- tree.write(relativeDestPath, content);
3073
- }
3074
- installedAgents.push(agentName);
3075
- installedFiles.push(path5.relative(targetDir, destPath));
3076
- } else {
3077
- import_devkit7.logger.warn(`Agent file not found: ${agentName}`);
3078
- }
3079
- } catch (error) {
3080
- import_devkit7.logger.warn(`Error reading agent ${agentName}: ${error}`);
3081
- }
3082
- }
3083
- import_devkit7.logger.info("\u{1F4E6} Installation Plan:");
3084
- import_devkit7.logger.info(
3085
- ` Location: ${normalizedOptions.installationType === "global" ? `Global (${targetDir})` : `Local (${targetDir})`}`
3086
- );
3087
- import_devkit7.logger.info(` Commands: ${installedCommands.length} selected`);
3088
- import_devkit7.logger.info(` Agents: ${installedAgents.length} selected`);
3089
- if (isDryRun) {
3090
- import_devkit7.logger.info("\n\u{1F4CB} Would install:");
3091
- installedFiles.forEach((file) => {
3092
- import_devkit7.logger.info(` - ${file}`);
3093
- });
3094
- import_devkit7.logger.info("\n\u{1F504} Would also set up auto-update checker:");
3095
- import_devkit7.logger.info(" - Auto-detect your shell (bash, zsh, or fish)");
3096
- import_devkit7.logger.info(" - Add update check script to your shell configuration");
3097
- import_devkit7.logger.info(" - Checks once per week for new versions");
3098
- import_devkit7.logger.info(" - Runs in background (non-blocking)");
3099
- import_devkit7.logger.info(" - Can be disabled with: export AI_TOOLKIT_SKIP_UPDATE_CHECK=1");
3100
- return;
3101
- }
3102
- if (!isDryRun) {
3103
- const manifest = {
3104
- version: "1.0.0",
3105
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
3106
- commands: installedCommands,
3107
- agents: installedAgents,
3108
- files: installedFiles
3109
- };
3110
- (0, import_devkit7.writeJson)(tree, relativeManifestPath, manifest);
3111
- await (0, import_devkit7.formatFiles)(tree);
3112
- }
3113
- if (!isDryRun) {
3114
- import_devkit7.logger.info("\u2705 Claude Code configuration installed successfully!");
3115
- import_devkit7.logger.info(`\u{1F4C1} Location: ${targetDir}`);
3116
- import_devkit7.logger.info(`\u{1F4DD} Use these in Claude Code immediately`);
3117
- try {
3118
- import_devkit7.logger.info("\n\u{1F504} Installing auto-update checker...");
3119
- const shell = detectShell();
3120
- const version = getCurrentToolkitVersion();
3121
- installUpdateChecker(shell, version);
3122
- } catch (error) {
3123
- import_devkit7.logger.warn(`\u26A0\uFE0F Failed to install update checker: ${error}`);
3124
- import_devkit7.logger.info(
3125
- "This is a bug in ai-toolkit, please report it at https://github.com/Uniswap/ai-toolkit/issues"
3126
- );
3127
- }
3128
- if (normalizedOptions.installHooks) {
3129
- try {
3130
- import_devkit7.logger.info("\n\u{1F514} Installing notification hooks...");
3131
- if (!generator_default) {
3132
- throw new Error("hooksGenerator export not found");
3133
- }
3134
- await generator_default(tree, {
3135
- force: normalizedOptions.force || false,
3136
- dry: false,
3137
- backup: true,
3138
- verbose: false,
3139
- installMode: "default"
3140
- // Always use 'default' to prevent re-prompting
3141
- });
3142
- import_devkit7.logger.info("\u2705 Notification hooks installed successfully");
3143
- } catch (error) {
3144
- import_devkit7.logger.error("\u274C Failed to install notification hooks");
3145
- import_devkit7.logger.error(error.message);
3146
- import_devkit7.logger.info(" Continuing with installation...");
3147
- }
3148
- }
3149
- let addonsInstalled = false;
3150
- const shouldInstallAddons = normalizedOptions.installAddons === true;
3151
- if (shouldInstallAddons) {
3152
- try {
3153
- import_devkit7.logger.info("\n\u{1F50C} Installing addons...");
3154
- if (!generator) {
3155
- throw new Error("addonsGenerator export not found");
3156
- }
3157
- const addonInstallMode = normalizedOptions.installMode === "default" || normalizedOptions.addonSelectionMode === "all" ? "all" : "specific";
3158
- await generator(tree, {
3159
- dry: normalizedOptions.dry || false,
3160
- selectionMode: addonInstallMode,
3161
- force: normalizedOptions.force || false,
3162
- skipVerification: false,
3163
- dashboardMode: "always",
3164
- port: 0,
3165
- installMode: normalizedOptions.addonSelectionMode === "specific" ? "custom" : "default",
3166
- installationType: normalizedOptions.installationType || "global"
3167
- });
3168
- import_devkit7.logger.info("\u2705 Addons installed successfully");
3169
- addonsInstalled = true;
3170
- } catch (error) {
3171
- import_devkit7.logger.error("\u274C Failed to install addons");
3172
- import_devkit7.logger.error(error.message);
3173
- import_devkit7.logger.info(" Continuing with installation...");
3174
- }
3175
- }
3176
- import_devkit7.logger.info("\n\u2728 Installation complete!");
3177
- if (installedCommands.length > 0) {
3178
- import_devkit7.logger.info(` Commands: ${installedCommands.join(", ")}`);
3179
- }
3180
- if (installedAgents.length > 0) {
3181
- import_devkit7.logger.info(` Agents: ${installedAgents.join(", ")}`);
3182
- }
3183
- if (normalizedOptions.installHooks) {
3184
- import_devkit7.logger.info(" Hooks: \u2705 Installed");
3185
- }
3186
- if (addonsInstalled) {
3187
- import_devkit7.logger.info(" Addons: \u2705 Installed");
3188
- }
3189
- } else {
3190
- if (normalizedOptions.installHooks) {
3191
- import_devkit7.logger.info("\n\u{1F50D} DRY RUN: Would install notification hooks (sound mode)");
3192
- }
3193
- const installAddonsExplicit = explicitlyProvided.has("installAddons") || explicitlyProvided.has("install-addons");
3194
- if (normalizedOptions.installMode === "custom" && !installAddonsExplicit && !normalizedOptions.nonInteractive) {
3195
- import_devkit7.logger.info("\n\u{1F50D} DRY RUN: Would prompt to install spec-mcp-workflow addon after hooks");
3196
- } else if (normalizedOptions.installAddons) {
3197
- import_devkit7.logger.info("\n\u{1F50D} DRY RUN: Would install spec-mcp-workflow addon");
3198
- }
3199
- }
3200
- }
3201
- function checkClaudeInstalled() {
3202
- try {
3203
- (0, import_child_process7.execSync)("which claude", { stdio: "ignore" });
3204
- return true;
3205
- } catch {
3206
- return false;
3207
- }
3208
- }
3209
- async function promptInstallClaude() {
3210
- const { install } = await (0, import_enquirer2.prompt)({
3211
- type: "confirm",
3212
- name: "install",
3213
- message: "Would you like to install Claude CLI?",
3214
- initial: true
3215
- });
3216
- return install;
3217
- }
3218
- async function installClaude() {
3219
- const platform = process.platform;
3220
- if (platform !== "darwin") {
3221
- import_devkit7.logger.warn(
3222
- "\u26A0\uFE0F Note: Claude CLI installation may require additional steps on non-macOS platforms"
3223
- );
3224
- }
3225
- import_devkit7.logger.info("\u{1F4E6} Installing Claude CLI...");
3226
- const curlSuccess = await installViaCurl();
3227
- if (curlSuccess) {
3228
- await verifyInstallation2("curl");
3229
- return;
3230
- }
3231
- import_devkit7.logger.info("Curl method failed, falling back to npm installation...");
3232
- const npmSuccess = await installViaNpm();
3233
- if (npmSuccess) {
3234
- await verifyInstallation2("npm");
3235
- return;
3236
- }
3237
- provideManualInstructions();
3238
- }
3239
- async function installViaCurl() {
3240
- import_devkit7.logger.info("Attempting installation via curl...");
3241
- try {
3242
- (0, import_child_process7.execSync)("which curl", { stdio: "ignore" });
3243
- (0, import_child_process7.execSync)("curl -fsSL https://claude.ai/install.sh | bash", {
3244
- stdio: "inherit",
3245
- shell: "/bin/bash",
3246
- timeout: 3e5
3247
- // 5 minute timeout
3248
- });
3249
- import_devkit7.logger.info("\u2705 Claude CLI installed successfully via curl!");
3250
- return true;
3251
- } catch (error) {
3252
- import_devkit7.logger.warn("Curl installation failed, attempting npm fallback...");
3253
- import_devkit7.logger.debug(`Curl error details: ${error.message}`);
3254
- return false;
3255
- }
3256
- }
3257
- async function installViaNpm() {
3258
- import_devkit7.logger.info("Installing via npm: npm install -g @anthropic-ai/claude-code");
3259
- try {
3260
- (0, import_child_process7.execSync)("which npm", { stdio: "ignore" });
3261
- (0, import_child_process7.execSync)("npm install -g @anthropic-ai/claude-code", {
3262
- stdio: "inherit",
3263
- timeout: 3e5
3264
- // 5 minute timeout
3265
- });
3266
- import_devkit7.logger.info("\u2705 Claude CLI installed successfully via npm!");
3267
- return true;
3268
- } catch (error) {
3269
- if (error.code === "ENOENT") {
3270
- import_devkit7.logger.error("\u274C npm not found. Please install Node.js and npm first.");
3271
- import_devkit7.logger.info("Visit https://nodejs.org/ to install Node.js");
3272
- } else if (error.message?.includes("permission") || error.message?.includes("EACCES")) {
3273
- import_devkit7.logger.error("\u274C npm installation failed due to permissions.");
3274
- import_devkit7.logger.info("Try running: npm install -g @anthropic-ai/claude-code");
3275
- import_devkit7.logger.info("Then run: claude migrate-installer");
3276
- } else {
3277
- import_devkit7.logger.error(`\u274C npm installation failed: ${error.message}`);
3278
- }
3279
- return false;
3280
- }
3281
- }
3282
- async function verifyInstallation2(method) {
3283
- try {
3284
- (0, import_child_process7.execSync)("which claude", { stdio: "ignore" });
3285
- import_devkit7.logger.info(`\u2705 Claude CLI found (installed via ${method})`);
3286
- import_devkit7.logger.info('You can also run "claude --version" to verify');
3287
- } catch {
3288
- import_devkit7.logger.warn("\u26A0\uFE0F Claude CLI not found in PATH");
3289
- import_devkit7.logger.info("You may need to restart your terminal or add Claude to your PATH");
3290
- }
3291
- }
3292
- function provideManualInstructions() {
3293
- import_devkit7.logger.error("\u274C Automatic installation failed");
3294
- import_devkit7.logger.info("\n\u{1F4DA} Manual Installation Instructions:");
3295
- import_devkit7.logger.info("1. Via curl: curl -fsSL https://claude.ai/install.sh | bash");
3296
- import_devkit7.logger.info("2. Via npm: npm install -g @anthropic-ai/claude-code");
3297
- import_devkit7.logger.info("3. Visit: https://claude.ai/download for platform-specific instructions");
3298
- import_devkit7.logger.info('\nFor troubleshooting, run "claude doctor" after manual installation');
3299
- }
3300
- var generator_default2 = initGenerator;
3301
- // Annotate the CommonJS export names for ESM import in node:
3302
- 0 && (module.exports = {
3303
- initGenerator
3304
- });