@uniswap/ai-toolkit-nx-claude 0.5.30-next.1 → 0.5.30-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -27
- package/dist/cli-generator.cjs +4 -10
- package/dist/generators/addons/CLAUDE.md +91 -91
- package/dist/generators/addons/generator.cjs +13 -338
- package/dist/generators/addons/schema.json +1 -32
- package/dist/index.cjs +25 -1180
- package/dist/packages/ai-toolkit-nx-claude/src/cli-generator.d.ts +1 -2
- package/dist/packages/ai-toolkit-nx-claude/src/cli-generator.d.ts.map +1 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/addons/addon-registry.d.ts.map +1 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/addons/aws-log-analyzer-setup.d.ts.map +1 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/addons/generator.d.ts.map +1 -1
- package/dist/packages/ai-toolkit-nx-claude/src/index.d.ts +0 -1
- package/dist/packages/ai-toolkit-nx-claude/src/index.d.ts.map +1 -1
- package/generators.json +0 -5
- package/package.json +2 -3
- package/dist/generators/hooks/CLAUDE.md +0 -378
- package/dist/generators/hooks/README.md +0 -220
- package/dist/generators/hooks/generator.cjs +0 -1265
- package/dist/generators/hooks/schema.json +0 -41
- package/dist/packages/ai-toolkit-nx-claude/src/generators/addons/spec-workflow-setup.d.ts +0 -52
- package/dist/packages/ai-toolkit-nx-claude/src/generators/addons/spec-workflow-setup.d.ts.map +0 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/cli-parser.d.ts +0 -2
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/cli-parser.d.ts.map +0 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/dependency-checker.d.ts +0 -46
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/dependency-checker.d.ts.map +0 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/generator.d.ts +0 -9
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/generator.d.ts.map +0 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/install-orchestrator.d.ts +0 -55
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/install-orchestrator.d.ts.map +0 -1
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/repo-manager.d.ts +0 -63
- package/dist/packages/ai-toolkit-nx-claude/src/generators/hooks/repo-manager.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -131,10 +131,10 @@ async function validateAddonRequirements(addonId) {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
if (addon.requirements?.commands) {
|
|
134
|
-
const { execSync:
|
|
134
|
+
const { execSync: execSync3 } = require("child_process");
|
|
135
135
|
for (const cmd of addon.requirements.commands) {
|
|
136
136
|
try {
|
|
137
|
-
|
|
137
|
+
execSync3(`which ${cmd}`, { stdio: "ignore" });
|
|
138
138
|
} catch {
|
|
139
139
|
errors.push(`Required command '${cmd}' not found`);
|
|
140
140
|
}
|
|
@@ -153,53 +153,6 @@ var init_addon_registry = __esm({
|
|
|
153
153
|
import_path = require("path");
|
|
154
154
|
import_os = require("os");
|
|
155
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
156
|
{
|
|
204
157
|
id: "slack-mcp",
|
|
205
158
|
name: "Slack MCP",
|
|
@@ -216,30 +169,6 @@ var init_addon_registry = __esm({
|
|
|
216
169
|
}
|
|
217
170
|
}
|
|
218
171
|
},
|
|
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
172
|
{
|
|
244
173
|
id: "github-mcp",
|
|
245
174
|
name: "GitHub MCP",
|
|
@@ -267,19 +196,6 @@ var init_addon_registry = __esm({
|
|
|
267
196
|
url: "https://mcp.figma.com/mcp"
|
|
268
197
|
}
|
|
269
198
|
},
|
|
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
199
|
{
|
|
284
200
|
id: "vercel-mcp",
|
|
285
201
|
name: "Vercel MCP",
|
|
@@ -350,7 +266,7 @@ var require_schema = __commonJS({
|
|
|
350
266
|
items: [
|
|
351
267
|
{
|
|
352
268
|
value: "all",
|
|
353
|
-
label: "All recommended MCP servers (
|
|
269
|
+
label: "All recommended MCP servers (6 servers)"
|
|
354
270
|
},
|
|
355
271
|
{
|
|
356
272
|
value: "specific",
|
|
@@ -365,18 +281,10 @@ var require_schema = __commonJS({
|
|
|
365
281
|
items: {
|
|
366
282
|
type: "string",
|
|
367
283
|
enum: [
|
|
368
|
-
"spec-workflow-mcp",
|
|
369
|
-
"graphite-mcp",
|
|
370
|
-
"nx-mcp",
|
|
371
284
|
"slack-mcp",
|
|
372
|
-
"universe-mcp",
|
|
373
|
-
"linear-mcp",
|
|
374
|
-
"notion-mcp",
|
|
375
285
|
"github-mcp",
|
|
376
286
|
"figma-mcp",
|
|
377
|
-
"chrome-devtools-mcp",
|
|
378
287
|
"vercel-mcp",
|
|
379
|
-
"supabase-mcp",
|
|
380
288
|
"aws-log-analyzer-mcp",
|
|
381
289
|
"pulumi-mcp"
|
|
382
290
|
]
|
|
@@ -385,24 +293,6 @@ var require_schema = __commonJS({
|
|
|
385
293
|
"prompt-type": "multiselect",
|
|
386
294
|
"prompt-message": "\u{1F50C} Select MCP servers to install"
|
|
387
295
|
},
|
|
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
296
|
force: {
|
|
407
297
|
type: "boolean",
|
|
408
298
|
description: "Force installation even if already exists",
|
|
@@ -413,11 +303,6 @@ var require_schema = __commonJS({
|
|
|
413
303
|
description: "Skip installation verification",
|
|
414
304
|
default: false
|
|
415
305
|
},
|
|
416
|
-
projectPath: {
|
|
417
|
-
type: "string",
|
|
418
|
-
description: "Path to the project where spec-workflow should be installed",
|
|
419
|
-
"x-skip-prompt": true
|
|
420
|
-
},
|
|
421
306
|
dry: {
|
|
422
307
|
type: "boolean",
|
|
423
308
|
description: "Dry run mode",
|
|
@@ -456,14 +341,12 @@ var require_schema = __commonJS({
|
|
|
456
341
|
// packages/ai-toolkit-nx-claude/src/index.ts
|
|
457
342
|
var index_exports = {};
|
|
458
343
|
__export(index_exports, {
|
|
459
|
-
addonsGenerator: () => generator
|
|
460
|
-
hooksGenerator: () => generator_default
|
|
344
|
+
addonsGenerator: () => generator
|
|
461
345
|
});
|
|
462
346
|
module.exports = __toCommonJS(index_exports);
|
|
463
347
|
|
|
464
|
-
// packages/ai-toolkit-nx-claude/src/generators/
|
|
465
|
-
var
|
|
466
|
-
var path3 = __toESM(require("path"));
|
|
348
|
+
// packages/ai-toolkit-nx-claude/src/generators/addons/generator.ts
|
|
349
|
+
var import_devkit = require("@nx/devkit");
|
|
467
350
|
|
|
468
351
|
// packages/ai-toolkit-nx-claude/src/utils/prompt-utils.ts
|
|
469
352
|
var import_enquirer = require("enquirer");
|
|
@@ -841,708 +724,7 @@ function evaluateSingleCondition(condition, context) {
|
|
|
841
724
|
}
|
|
842
725
|
}
|
|
843
726
|
|
|
844
|
-
// packages/ai-toolkit-nx-claude/src/generators/hooks/dependency-checker.ts
|
|
845
|
-
var import_child_process = require("child_process");
|
|
846
|
-
var import_devkit = require("@nx/devkit");
|
|
847
|
-
function commandExists(command) {
|
|
848
|
-
try {
|
|
849
|
-
(0, import_child_process.execSync)(`which ${command}`, { stdio: "ignore" });
|
|
850
|
-
return true;
|
|
851
|
-
} catch {
|
|
852
|
-
return false;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
function getCommandVersion(command, versionFlag = "--version") {
|
|
856
|
-
try {
|
|
857
|
-
const output = (0, import_child_process.execSync)(`${command} ${versionFlag}`, {
|
|
858
|
-
encoding: "utf-8",
|
|
859
|
-
stdio: "pipe"
|
|
860
|
-
}).trim();
|
|
861
|
-
const versionMatch = output.match(/(\d+\.\d+\.\d+)/);
|
|
862
|
-
return versionMatch ? versionMatch[1] : output.split("\n")[0];
|
|
863
|
-
} catch {
|
|
864
|
-
return void 0;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
function checkDependencies() {
|
|
868
|
-
const status = {
|
|
869
|
-
hasNode: false,
|
|
870
|
-
hasNpm: false,
|
|
871
|
-
hasGit: false,
|
|
872
|
-
missingDependencies: []
|
|
873
|
-
};
|
|
874
|
-
if (commandExists("node")) {
|
|
875
|
-
status.hasNode = true;
|
|
876
|
-
status.nodeVersion = getCommandVersion("node");
|
|
877
|
-
} else {
|
|
878
|
-
status.missingDependencies.push("Node.js");
|
|
879
|
-
}
|
|
880
|
-
if (commandExists("npm")) {
|
|
881
|
-
status.hasNpm = true;
|
|
882
|
-
status.npmVersion = getCommandVersion("npm");
|
|
883
|
-
} else {
|
|
884
|
-
status.missingDependencies.push("npm");
|
|
885
|
-
}
|
|
886
|
-
if (commandExists("git")) {
|
|
887
|
-
status.hasGit = true;
|
|
888
|
-
status.gitVersion = getCommandVersion("git");
|
|
889
|
-
} else {
|
|
890
|
-
status.missingDependencies.push("Git");
|
|
891
|
-
}
|
|
892
|
-
return status;
|
|
893
|
-
}
|
|
894
|
-
function logDependencyStatus(status) {
|
|
895
|
-
import_devkit.logger.info("\u{1F4CB} Dependency Check Results:");
|
|
896
|
-
if (status.hasNode) {
|
|
897
|
-
import_devkit.logger.info(` \u2705 Node.js: ${status.nodeVersion || "installed"}`);
|
|
898
|
-
} else {
|
|
899
|
-
import_devkit.logger.error(" \u274C Node.js: not found");
|
|
900
|
-
}
|
|
901
|
-
if (status.hasNpm) {
|
|
902
|
-
import_devkit.logger.info(` \u2705 npm: ${status.npmVersion || "installed"}`);
|
|
903
|
-
} else {
|
|
904
|
-
import_devkit.logger.error(" \u274C npm: not found");
|
|
905
|
-
}
|
|
906
|
-
if (status.hasGit) {
|
|
907
|
-
import_devkit.logger.info(` \u2705 Git: ${status.gitVersion || "installed"}`);
|
|
908
|
-
} else {
|
|
909
|
-
import_devkit.logger.error(" \u274C Git: not found");
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
function hasAllDependencies(status) {
|
|
913
|
-
return status.missingDependencies.length === 0;
|
|
914
|
-
}
|
|
915
|
-
function getInstallInstructions(missingDeps) {
|
|
916
|
-
const instructions = [];
|
|
917
|
-
if (missingDeps.includes("Node.js") || missingDeps.includes("npm")) {
|
|
918
|
-
instructions.push(
|
|
919
|
-
"\u{1F4E6} Node.js and npm:",
|
|
920
|
-
" \u2022 macOS: brew install node",
|
|
921
|
-
" \u2022 Linux: sudo apt-get install nodejs npm",
|
|
922
|
-
" \u2022 Windows: Download from https://nodejs.org/",
|
|
923
|
-
""
|
|
924
|
-
);
|
|
925
|
-
}
|
|
926
|
-
if (missingDeps.includes("Git")) {
|
|
927
|
-
instructions.push(
|
|
928
|
-
"\u{1F4E6} Git:",
|
|
929
|
-
" \u2022 macOS: brew install git",
|
|
930
|
-
" \u2022 Linux: sudo apt-get install git",
|
|
931
|
-
" \u2022 Windows: Download from https://git-scm.com/",
|
|
932
|
-
""
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
|
-
return instructions.join("\n");
|
|
936
|
-
}
|
|
937
|
-
function validateVersions(status) {
|
|
938
|
-
const MIN_NODE_VERSION = "16.0.0";
|
|
939
|
-
const MIN_NPM_VERSION = "7.0.0";
|
|
940
|
-
const MIN_GIT_VERSION = "2.0.0";
|
|
941
|
-
const compareVersions = (current, minimum) => {
|
|
942
|
-
if (!current) return false;
|
|
943
|
-
const currentParts = current.split(".").map(Number);
|
|
944
|
-
const minimumParts = minimum.split(".").map(Number);
|
|
945
|
-
for (let i = 0; i < minimumParts.length; i++) {
|
|
946
|
-
if (currentParts[i] > minimumParts[i]) return true;
|
|
947
|
-
if (currentParts[i] < minimumParts[i]) return false;
|
|
948
|
-
}
|
|
949
|
-
return true;
|
|
950
|
-
};
|
|
951
|
-
if (status.hasNode && !compareVersions(status.nodeVersion, MIN_NODE_VERSION)) {
|
|
952
|
-
import_devkit.logger.warn(
|
|
953
|
-
`\u26A0\uFE0F Node.js version ${status.nodeVersion} is below minimum required version ${MIN_NODE_VERSION}`
|
|
954
|
-
);
|
|
955
|
-
return false;
|
|
956
|
-
}
|
|
957
|
-
if (status.hasNpm && !compareVersions(status.npmVersion, MIN_NPM_VERSION)) {
|
|
958
|
-
import_devkit.logger.warn(
|
|
959
|
-
`\u26A0\uFE0F npm version ${status.npmVersion} is below minimum required version ${MIN_NPM_VERSION}`
|
|
960
|
-
);
|
|
961
|
-
return false;
|
|
962
|
-
}
|
|
963
|
-
if (status.hasGit && !compareVersions(status.gitVersion, MIN_GIT_VERSION)) {
|
|
964
|
-
import_devkit.logger.warn(
|
|
965
|
-
`\u26A0\uFE0F Git version ${status.gitVersion} is below minimum required version ${MIN_GIT_VERSION}`
|
|
966
|
-
);
|
|
967
|
-
return false;
|
|
968
|
-
}
|
|
969
|
-
return true;
|
|
970
|
-
}
|
|
971
|
-
async function checkAndValidateDependencies() {
|
|
972
|
-
const status = checkDependencies();
|
|
973
|
-
logDependencyStatus(status);
|
|
974
|
-
if (!hasAllDependencies(status)) {
|
|
975
|
-
import_devkit.logger.error("\n\u274C Missing required dependencies:");
|
|
976
|
-
import_devkit.logger.info(getInstallInstructions(status.missingDependencies));
|
|
977
|
-
return false;
|
|
978
|
-
}
|
|
979
|
-
if (!validateVersions(status)) {
|
|
980
|
-
import_devkit.logger.error(
|
|
981
|
-
"\n\u274C Some dependencies do not meet minimum version requirements"
|
|
982
|
-
);
|
|
983
|
-
import_devkit.logger.info("Please update the affected tools to continue.");
|
|
984
|
-
return false;
|
|
985
|
-
}
|
|
986
|
-
import_devkit.logger.info("\n\u2705 All dependencies satisfied!");
|
|
987
|
-
return true;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
// packages/ai-toolkit-nx-claude/src/generators/hooks/repo-manager.ts
|
|
991
|
-
var import_child_process2 = require("child_process");
|
|
992
|
-
var import_devkit2 = require("@nx/devkit");
|
|
993
|
-
var fs2 = __toESM(require("fs"));
|
|
994
|
-
var path = __toESM(require("path"));
|
|
995
|
-
var os = __toESM(require("os"));
|
|
996
|
-
var DEFAULT_REPO_URL = "https://github.com/pascalporedda/awesome-claude-code.git";
|
|
997
|
-
function getRepoPath(customPath) {
|
|
998
|
-
if (customPath) {
|
|
999
|
-
return customPath;
|
|
1000
|
-
}
|
|
1001
|
-
return path.join(os.tmpdir(), "claude-hooks-temp");
|
|
1002
|
-
}
|
|
1003
|
-
function isGitRepository(repoPath) {
|
|
1004
|
-
try {
|
|
1005
|
-
if (!fs2.existsSync(repoPath)) {
|
|
1006
|
-
return false;
|
|
1007
|
-
}
|
|
1008
|
-
(0, import_child_process2.execSync)("git rev-parse --git-dir", {
|
|
1009
|
-
cwd: repoPath,
|
|
1010
|
-
stdio: "ignore"
|
|
1011
|
-
});
|
|
1012
|
-
return true;
|
|
1013
|
-
} catch {
|
|
1014
|
-
return false;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
function getCurrentBranch(repoPath) {
|
|
1018
|
-
try {
|
|
1019
|
-
const branch = (0, import_child_process2.execSync)("git rev-parse --abbrev-ref HEAD", {
|
|
1020
|
-
cwd: repoPath,
|
|
1021
|
-
encoding: "utf-8"
|
|
1022
|
-
}).trim();
|
|
1023
|
-
return branch;
|
|
1024
|
-
} catch {
|
|
1025
|
-
return void 0;
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
function getLastCommit(repoPath) {
|
|
1029
|
-
try {
|
|
1030
|
-
const commit = (0, import_child_process2.execSync)("git rev-parse HEAD", {
|
|
1031
|
-
cwd: repoPath,
|
|
1032
|
-
encoding: "utf-8"
|
|
1033
|
-
}).trim();
|
|
1034
|
-
return commit.substring(0, 7);
|
|
1035
|
-
} catch {
|
|
1036
|
-
return void 0;
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
function isDirty(repoPath) {
|
|
1040
|
-
try {
|
|
1041
|
-
const status = (0, import_child_process2.execSync)("git status --porcelain", {
|
|
1042
|
-
cwd: repoPath,
|
|
1043
|
-
encoding: "utf-8"
|
|
1044
|
-
}).trim();
|
|
1045
|
-
return status.length > 0;
|
|
1046
|
-
} catch {
|
|
1047
|
-
return false;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
function getRemoteUrl(repoPath) {
|
|
1051
|
-
try {
|
|
1052
|
-
const url = (0, import_child_process2.execSync)("git config --get remote.origin.url", {
|
|
1053
|
-
cwd: repoPath,
|
|
1054
|
-
encoding: "utf-8"
|
|
1055
|
-
}).trim();
|
|
1056
|
-
return url;
|
|
1057
|
-
} catch {
|
|
1058
|
-
return void 0;
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
function getRepoStatus(repoPath) {
|
|
1062
|
-
const exists = fs2.existsSync(repoPath);
|
|
1063
|
-
const isGit = exists && isGitRepository(repoPath);
|
|
1064
|
-
const status = {
|
|
1065
|
-
exists,
|
|
1066
|
-
path: repoPath,
|
|
1067
|
-
isGitRepo: isGit
|
|
1068
|
-
};
|
|
1069
|
-
if (isGit) {
|
|
1070
|
-
status.currentBranch = getCurrentBranch(repoPath);
|
|
1071
|
-
status.lastCommit = getLastCommit(repoPath);
|
|
1072
|
-
status.isDirty = isDirty(repoPath);
|
|
1073
|
-
status.remoteUrl = getRemoteUrl(repoPath);
|
|
1074
|
-
}
|
|
1075
|
-
return status;
|
|
1076
|
-
}
|
|
1077
|
-
async function cloneRepository(repoUrl = DEFAULT_REPO_URL, targetPath, verbose = false) {
|
|
1078
|
-
const repoPath = getRepoPath(targetPath);
|
|
1079
|
-
try {
|
|
1080
|
-
if (fs2.existsSync(repoPath)) {
|
|
1081
|
-
import_devkit2.logger.warn(`Directory already exists: ${repoPath}`);
|
|
1082
|
-
if (isGitRepository(repoPath)) {
|
|
1083
|
-
import_devkit2.logger.info("Existing git repository found");
|
|
1084
|
-
return true;
|
|
1085
|
-
} else {
|
|
1086
|
-
import_devkit2.logger.info("Removing non-git directory...");
|
|
1087
|
-
fs2.rmSync(repoPath, { recursive: true, force: true });
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
import_devkit2.logger.info(`\u{1F4E5} Downloading notification hooks...`);
|
|
1091
|
-
try {
|
|
1092
|
-
(0, import_child_process2.execSync)(`git clone ${repoUrl} "${repoPath}"`, {
|
|
1093
|
-
stdio: verbose ? "inherit" : "ignore"
|
|
1094
|
-
});
|
|
1095
|
-
import_devkit2.logger.info("\u2705 Download complete");
|
|
1096
|
-
return true;
|
|
1097
|
-
} catch (httpsError) {
|
|
1098
|
-
if (repoUrl === DEFAULT_REPO_URL) {
|
|
1099
|
-
import_devkit2.logger.warn("HTTPS clone failed, trying SSH...");
|
|
1100
|
-
const sshUrl = "git@github.com:pascalporedda/awesome-claude-code.git";
|
|
1101
|
-
try {
|
|
1102
|
-
(0, import_child_process2.execSync)(`git clone ${sshUrl} "${repoPath}"`, {
|
|
1103
|
-
stdio: verbose ? "inherit" : "ignore"
|
|
1104
|
-
});
|
|
1105
|
-
import_devkit2.logger.info("\u2705 Download complete via SSH");
|
|
1106
|
-
return true;
|
|
1107
|
-
} catch (sshError) {
|
|
1108
|
-
import_devkit2.logger.error("\u274C Both HTTPS and SSH clone attempts failed");
|
|
1109
|
-
throw sshError;
|
|
1110
|
-
}
|
|
1111
|
-
} else {
|
|
1112
|
-
throw httpsError;
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
} catch (error) {
|
|
1116
|
-
import_devkit2.logger.error(`\u274C Failed to download hooks: ${error}`);
|
|
1117
|
-
return false;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
async function updateRepository(repoPath, verbose = false) {
|
|
1121
|
-
try {
|
|
1122
|
-
if (!isGitRepository(repoPath)) {
|
|
1123
|
-
import_devkit2.logger.error("Not a git repository");
|
|
1124
|
-
return false;
|
|
1125
|
-
}
|
|
1126
|
-
if (isDirty(repoPath)) {
|
|
1127
|
-
import_devkit2.logger.warn("\u26A0\uFE0F Repository has uncommitted changes");
|
|
1128
|
-
import_devkit2.logger.info("Stashing changes...");
|
|
1129
|
-
(0, import_child_process2.execSync)("git stash", {
|
|
1130
|
-
cwd: repoPath,
|
|
1131
|
-
stdio: verbose ? "inherit" : "ignore"
|
|
1132
|
-
});
|
|
1133
|
-
}
|
|
1134
|
-
import_devkit2.logger.info("\u{1F4E5} Updating to latest version...");
|
|
1135
|
-
(0, import_child_process2.execSync)("git fetch origin", {
|
|
1136
|
-
cwd: repoPath,
|
|
1137
|
-
stdio: verbose ? "inherit" : "ignore"
|
|
1138
|
-
});
|
|
1139
|
-
(0, import_child_process2.execSync)("git pull origin main", {
|
|
1140
|
-
cwd: repoPath,
|
|
1141
|
-
stdio: verbose ? "inherit" : "ignore"
|
|
1142
|
-
});
|
|
1143
|
-
import_devkit2.logger.info("\u2705 Update complete");
|
|
1144
|
-
return true;
|
|
1145
|
-
} catch (error) {
|
|
1146
|
-
import_devkit2.logger.error(`\u274C Failed to update: ${error}`);
|
|
1147
|
-
return false;
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
function cleanupRepository(repoPath) {
|
|
1151
|
-
try {
|
|
1152
|
-
if (fs2.existsSync(repoPath)) {
|
|
1153
|
-
fs2.rmSync(repoPath, { recursive: true, force: true });
|
|
1154
|
-
import_devkit2.logger.info("\u{1F9F9} Temporary files cleaned up");
|
|
1155
|
-
return true;
|
|
1156
|
-
}
|
|
1157
|
-
return true;
|
|
1158
|
-
} catch (error) {
|
|
1159
|
-
import_devkit2.logger.error(`\u274C Failed to cleanup: ${error}`);
|
|
1160
|
-
return false;
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
async function ensureRepository(options) {
|
|
1164
|
-
const repoUrl = options.repoUrl || DEFAULT_REPO_URL;
|
|
1165
|
-
const repoPath = getRepoPath(options.targetPath);
|
|
1166
|
-
const status = getRepoStatus(repoPath);
|
|
1167
|
-
if (options.verbose) {
|
|
1168
|
-
import_devkit2.logger.info("Repository status:");
|
|
1169
|
-
import_devkit2.logger.info(` Path: ${status.path}`);
|
|
1170
|
-
import_devkit2.logger.info(` Exists: ${status.exists}`);
|
|
1171
|
-
import_devkit2.logger.info(` Is Git Repo: ${status.isGitRepo}`);
|
|
1172
|
-
if (status.isGitRepo) {
|
|
1173
|
-
import_devkit2.logger.info(` Branch: ${status.currentBranch}`);
|
|
1174
|
-
import_devkit2.logger.info(` Last Commit: ${status.lastCommit}`);
|
|
1175
|
-
import_devkit2.logger.info(` Has Changes: ${status.isDirty}`);
|
|
1176
|
-
import_devkit2.logger.info(` Remote URL: ${status.remoteUrl}`);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
if (status.exists && status.isGitRepo) {
|
|
1180
|
-
if (status.remoteUrl && !status.remoteUrl.includes("awesome-claude-code")) {
|
|
1181
|
-
cleanupRepository(repoPath);
|
|
1182
|
-
const cloned2 = await cloneRepository(
|
|
1183
|
-
DEFAULT_REPO_URL,
|
|
1184
|
-
options.targetPath,
|
|
1185
|
-
options.verbose
|
|
1186
|
-
);
|
|
1187
|
-
if (!cloned2) {
|
|
1188
|
-
return null;
|
|
1189
|
-
}
|
|
1190
|
-
return repoPath;
|
|
1191
|
-
}
|
|
1192
|
-
const updated = await updateRepository(repoPath, options.verbose);
|
|
1193
|
-
if (!updated) {
|
|
1194
|
-
import_devkit2.logger.warn("\u26A0\uFE0F Failed to update, using existing version");
|
|
1195
|
-
}
|
|
1196
|
-
return repoPath;
|
|
1197
|
-
}
|
|
1198
|
-
const cloned = await cloneRepository(
|
|
1199
|
-
repoUrl,
|
|
1200
|
-
options.targetPath,
|
|
1201
|
-
options.verbose
|
|
1202
|
-
);
|
|
1203
|
-
if (!cloned) {
|
|
1204
|
-
return null;
|
|
1205
|
-
}
|
|
1206
|
-
return repoPath;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
// packages/ai-toolkit-nx-claude/src/generators/hooks/install-orchestrator.ts
|
|
1210
|
-
var import_child_process3 = require("child_process");
|
|
1211
|
-
var import_devkit3 = require("@nx/devkit");
|
|
1212
|
-
var path2 = __toESM(require("path"));
|
|
1213
|
-
var fs3 = __toESM(require("fs"));
|
|
1214
|
-
var os2 = __toESM(require("os"));
|
|
1215
|
-
var ROOT_CLAUDE_DIR = path2.join(os2.homedir(), ".claude");
|
|
1216
|
-
var HOOKS_DIR = path2.join(ROOT_CLAUDE_DIR, "hooks");
|
|
1217
|
-
function backupExistingHooks(verbose = false) {
|
|
1218
|
-
if (!fs3.existsSync(HOOKS_DIR)) {
|
|
1219
|
-
if (verbose) {
|
|
1220
|
-
import_devkit3.logger.info("No existing hooks to backup");
|
|
1221
|
-
}
|
|
1222
|
-
return null;
|
|
1223
|
-
}
|
|
1224
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1225
|
-
const backupDir = path2.join(ROOT_CLAUDE_DIR, `hooks-backup-${timestamp}`);
|
|
1226
|
-
try {
|
|
1227
|
-
if (verbose) {
|
|
1228
|
-
import_devkit3.logger.info(`\u{1F4E6} Creating backup at: ${backupDir}`);
|
|
1229
|
-
}
|
|
1230
|
-
fs3.mkdirSync(backupDir, { recursive: true });
|
|
1231
|
-
(0, import_child_process3.execSync)(`cp -r "${HOOKS_DIR}"/* "${backupDir}"/`, {
|
|
1232
|
-
stdio: verbose ? "inherit" : "ignore"
|
|
1233
|
-
});
|
|
1234
|
-
const settingsPath = path2.join(ROOT_CLAUDE_DIR, "settings.json");
|
|
1235
|
-
if (fs3.existsSync(settingsPath)) {
|
|
1236
|
-
const backupSettingsPath = path2.join(backupDir, "settings.json.backup");
|
|
1237
|
-
fs3.copyFileSync(settingsPath, backupSettingsPath);
|
|
1238
|
-
}
|
|
1239
|
-
import_devkit3.logger.info(`\u2705 Backup created at: ${backupDir}`);
|
|
1240
|
-
return backupDir;
|
|
1241
|
-
} catch (error) {
|
|
1242
|
-
import_devkit3.logger.error(`\u274C Failed to create backup: ${error}`);
|
|
1243
|
-
return null;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
async function executeInstallScript(scriptPath, options) {
|
|
1247
|
-
return new Promise((resolve) => {
|
|
1248
|
-
try {
|
|
1249
|
-
if (options.dryRun) {
|
|
1250
|
-
import_devkit3.logger.info("\u{1F50D} DRY RUN: Would execute install script with defaults");
|
|
1251
|
-
resolve(true);
|
|
1252
|
-
return;
|
|
1253
|
-
}
|
|
1254
|
-
import_devkit3.logger.info("\u{1F680} Running hook installation...");
|
|
1255
|
-
const repoDir = path2.dirname(scriptPath);
|
|
1256
|
-
const child = (0, import_child_process3.spawn)("bash", [scriptPath], {
|
|
1257
|
-
stdio: ["pipe", options.verbose ? "inherit" : "pipe", "inherit"],
|
|
1258
|
-
shell: true,
|
|
1259
|
-
cwd: repoDir
|
|
1260
|
-
// Set working directory to the repo directory
|
|
1261
|
-
});
|
|
1262
|
-
if (child.stdin) {
|
|
1263
|
-
child.stdin.write("1\n");
|
|
1264
|
-
child.stdin.end();
|
|
1265
|
-
}
|
|
1266
|
-
child.on("close", (code) => {
|
|
1267
|
-
if (code === 0) {
|
|
1268
|
-
import_devkit3.logger.info("\u2705 Installation script completed successfully");
|
|
1269
|
-
resolve(true);
|
|
1270
|
-
} else {
|
|
1271
|
-
import_devkit3.logger.error(`\u274C Installation script exited with code ${code}`);
|
|
1272
|
-
resolve(false);
|
|
1273
|
-
}
|
|
1274
|
-
});
|
|
1275
|
-
child.on("error", (error) => {
|
|
1276
|
-
import_devkit3.logger.error(`\u274C Failed to execute install script: ${error}`);
|
|
1277
|
-
resolve(false);
|
|
1278
|
-
});
|
|
1279
|
-
} catch (error) {
|
|
1280
|
-
import_devkit3.logger.error(`\u274C Error executing install script: ${error}`);
|
|
1281
|
-
resolve(false);
|
|
1282
|
-
}
|
|
1283
|
-
});
|
|
1284
|
-
}
|
|
1285
|
-
function fixHookPaths(verbose = false) {
|
|
1286
|
-
const settingsPath = path2.join(ROOT_CLAUDE_DIR, "settings.json");
|
|
1287
|
-
if (!fs3.existsSync(settingsPath)) {
|
|
1288
|
-
if (verbose) {
|
|
1289
|
-
import_devkit3.logger.warn("\u26A0\uFE0F settings.json not found - cannot fix paths");
|
|
1290
|
-
}
|
|
1291
|
-
return false;
|
|
1292
|
-
}
|
|
1293
|
-
try {
|
|
1294
|
-
const settings = JSON.parse(fs3.readFileSync(settingsPath, "utf-8"));
|
|
1295
|
-
if (!settings.hooks) {
|
|
1296
|
-
if (verbose) {
|
|
1297
|
-
import_devkit3.logger.warn("\u26A0\uFE0F No hooks configuration found in settings.json");
|
|
1298
|
-
}
|
|
1299
|
-
return false;
|
|
1300
|
-
}
|
|
1301
|
-
const homeDir = os2.homedir();
|
|
1302
|
-
let modified = false;
|
|
1303
|
-
const fixPathInHooks = (hookArray) => {
|
|
1304
|
-
for (const hookConfig of hookArray) {
|
|
1305
|
-
if (hookConfig.hooks && Array.isArray(hookConfig.hooks)) {
|
|
1306
|
-
for (const hook of hookConfig.hooks) {
|
|
1307
|
-
if (hook.command && typeof hook.command === "string") {
|
|
1308
|
-
if (hook.command.includes(homeDir)) {
|
|
1309
|
-
hook.command = hook.command.replace(homeDir, "~");
|
|
1310
|
-
modified = true;
|
|
1311
|
-
}
|
|
1312
|
-
const pathMatch = hook.command.match(/\/(Users|home)\/[^/]+\/\.claude\/hooks\//);
|
|
1313
|
-
if (pathMatch) {
|
|
1314
|
-
hook.command = hook.command.replace(pathMatch[0], "~/.claude/hooks/");
|
|
1315
|
-
modified = true;
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
};
|
|
1322
|
-
const hookTypes = ["Notification", "Stop", "SubagentStop", "PreToolUse", "PostToolUse"];
|
|
1323
|
-
for (const hookType of hookTypes) {
|
|
1324
|
-
if (settings.hooks[hookType] && Array.isArray(settings.hooks[hookType])) {
|
|
1325
|
-
fixPathInHooks(settings.hooks[hookType]);
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
if (modified) {
|
|
1329
|
-
fs3.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
1330
|
-
if (verbose) {
|
|
1331
|
-
import_devkit3.logger.info("\u2705 Fixed hook paths to use ~ expansion for Docker compatibility");
|
|
1332
|
-
}
|
|
1333
|
-
return true;
|
|
1334
|
-
}
|
|
1335
|
-
return true;
|
|
1336
|
-
} catch (error) {
|
|
1337
|
-
import_devkit3.logger.error(`\u274C Failed to fix hook paths: ${error}`);
|
|
1338
|
-
return false;
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
function verifyInstallation() {
|
|
1342
|
-
const expectedFiles = ["notification.ts", "stop.ts", "subagent_stop.ts"];
|
|
1343
|
-
const installedFiles = [];
|
|
1344
|
-
const missingFiles = [];
|
|
1345
|
-
for (const file of expectedFiles) {
|
|
1346
|
-
const filePath = path2.join(HOOKS_DIR, file);
|
|
1347
|
-
if (fs3.existsSync(filePath)) {
|
|
1348
|
-
installedFiles.push(filePath);
|
|
1349
|
-
} else {
|
|
1350
|
-
missingFiles.push(file);
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
if (missingFiles.length > 0) {
|
|
1354
|
-
import_devkit3.logger.warn(`\u26A0\uFE0F Missing expected files: ${missingFiles.join(", ")}`);
|
|
1355
|
-
return null;
|
|
1356
|
-
}
|
|
1357
|
-
const settingsPath = path2.join(ROOT_CLAUDE_DIR, "settings.json");
|
|
1358
|
-
if (!fs3.existsSync(settingsPath)) {
|
|
1359
|
-
import_devkit3.logger.warn("\u26A0\uFE0F settings.json not found");
|
|
1360
|
-
return null;
|
|
1361
|
-
}
|
|
1362
|
-
try {
|
|
1363
|
-
const settings = JSON.parse(fs3.readFileSync(settingsPath, "utf-8"));
|
|
1364
|
-
if (!settings.hooks) {
|
|
1365
|
-
import_devkit3.logger.warn("\u26A0\uFE0F No hooks configuration found in settings.json");
|
|
1366
|
-
return null;
|
|
1367
|
-
}
|
|
1368
|
-
import_devkit3.logger.info("\u2705 Installation verified successfully");
|
|
1369
|
-
return installedFiles;
|
|
1370
|
-
} catch (error) {
|
|
1371
|
-
import_devkit3.logger.error(`\u274C Failed to verify settings.json: ${error}`);
|
|
1372
|
-
return null;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
async function runInstallation(repoPath, options) {
|
|
1376
|
-
const result = {
|
|
1377
|
-
success: false,
|
|
1378
|
-
installedPath: HOOKS_DIR
|
|
1379
|
-
};
|
|
1380
|
-
try {
|
|
1381
|
-
const installScriptPath = path2.join(repoPath, "install-global.sh");
|
|
1382
|
-
if (!fs3.existsSync(installScriptPath)) {
|
|
1383
|
-
throw new Error(`Install script not found at: ${installScriptPath}`);
|
|
1384
|
-
}
|
|
1385
|
-
(0, import_child_process3.execSync)(`chmod +x "${installScriptPath}"`, { stdio: "ignore" });
|
|
1386
|
-
if (options.backupExisting) {
|
|
1387
|
-
const backupPath = backupExistingHooks(options.verbose);
|
|
1388
|
-
if (backupPath) {
|
|
1389
|
-
result.backupPath = backupPath;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
const installSuccess = await executeInstallScript(
|
|
1393
|
-
installScriptPath,
|
|
1394
|
-
options
|
|
1395
|
-
);
|
|
1396
|
-
if (!installSuccess) {
|
|
1397
|
-
throw new Error("Installation script failed");
|
|
1398
|
-
}
|
|
1399
|
-
const installedFiles = verifyInstallation();
|
|
1400
|
-
if (!installedFiles) {
|
|
1401
|
-
throw new Error("Installation verification failed");
|
|
1402
|
-
}
|
|
1403
|
-
fixHookPaths(options.verbose);
|
|
1404
|
-
result.success = true;
|
|
1405
|
-
result.installedFiles = installedFiles;
|
|
1406
|
-
import_devkit3.logger.info("\n\u{1F4CB} Installation Summary:");
|
|
1407
|
-
import_devkit3.logger.info(` \u2705 Hooks installed to: ${result.installedPath}`);
|
|
1408
|
-
if (result.backupPath) {
|
|
1409
|
-
import_devkit3.logger.info(` \u2705 Backup created at: ${result.backupPath}`);
|
|
1410
|
-
}
|
|
1411
|
-
import_devkit3.logger.info(` \u2705 Files installed: ${installedFiles.length}`);
|
|
1412
|
-
return result;
|
|
1413
|
-
} catch (error) {
|
|
1414
|
-
result.error = error instanceof Error ? error.message : String(error);
|
|
1415
|
-
import_devkit3.logger.error(`\u274C Installation failed: ${result.error}`);
|
|
1416
|
-
if (result.backupPath && !options.dryRun) {
|
|
1417
|
-
import_devkit3.logger.info("\u{1F504} Attempting to restore backup...");
|
|
1418
|
-
await restoreBackup(result.backupPath);
|
|
1419
|
-
}
|
|
1420
|
-
return result;
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
async function restoreBackup(backupPath) {
|
|
1424
|
-
try {
|
|
1425
|
-
if (fs3.existsSync(HOOKS_DIR)) {
|
|
1426
|
-
fs3.rmSync(HOOKS_DIR, { recursive: true, force: true });
|
|
1427
|
-
}
|
|
1428
|
-
fs3.mkdirSync(HOOKS_DIR, { recursive: true });
|
|
1429
|
-
(0, import_child_process3.execSync)(`cp -r "${backupPath}"/* "${HOOKS_DIR}"/`, {
|
|
1430
|
-
stdio: "ignore"
|
|
1431
|
-
});
|
|
1432
|
-
const backupSettingsPath = path2.join(backupPath, "settings.json.backup");
|
|
1433
|
-
if (fs3.existsSync(backupSettingsPath)) {
|
|
1434
|
-
const settingsPath = path2.join(ROOT_CLAUDE_DIR, "settings.json");
|
|
1435
|
-
fs3.copyFileSync(backupSettingsPath, settingsPath);
|
|
1436
|
-
}
|
|
1437
|
-
import_devkit3.logger.info("\u2705 Backup restored successfully");
|
|
1438
|
-
return true;
|
|
1439
|
-
} catch (error) {
|
|
1440
|
-
import_devkit3.logger.error(`\u274C Failed to restore backup: ${error}`);
|
|
1441
|
-
return false;
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
|
-
async function testHooks() {
|
|
1445
|
-
try {
|
|
1446
|
-
import_devkit3.logger.info("\u{1F9EA} Testing installed hooks...");
|
|
1447
|
-
const testPayload = {
|
|
1448
|
-
hook_event_name: "Notification",
|
|
1449
|
-
session_id: "test-session",
|
|
1450
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1451
|
-
cwd: process.cwd()
|
|
1452
|
-
};
|
|
1453
|
-
const notificationHook = path2.join(HOOKS_DIR, "notification.ts");
|
|
1454
|
-
if (!fs3.existsSync(notificationHook)) {
|
|
1455
|
-
import_devkit3.logger.error("\u274C Notification hook not found");
|
|
1456
|
-
return false;
|
|
1457
|
-
}
|
|
1458
|
-
const command = `echo '${JSON.stringify(
|
|
1459
|
-
testPayload
|
|
1460
|
-
)}' | npx tsx "${notificationHook}" --notify`;
|
|
1461
|
-
import_devkit3.logger.info("\u{1F514} Triggering test notification...");
|
|
1462
|
-
(0, import_child_process3.execSync)(command, { stdio: "inherit" });
|
|
1463
|
-
import_devkit3.logger.info("\u2705 Hook test completed successfully");
|
|
1464
|
-
import_devkit3.logger.info("You should have heard a notification sound/speech");
|
|
1465
|
-
return true;
|
|
1466
|
-
} catch (error) {
|
|
1467
|
-
import_devkit3.logger.error(`\u274C Hook test failed: ${error}`);
|
|
1468
|
-
return false;
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
727
|
// packages/ai-toolkit-nx-claude/src/utils/cli-parser.ts
|
|
1473
|
-
function getExplicitlyProvidedOptions(options) {
|
|
1474
|
-
const providedOptions = /* @__PURE__ */ new Map();
|
|
1475
|
-
const args = process.argv;
|
|
1476
|
-
for (let i = 0; i < args.length; i++) {
|
|
1477
|
-
const arg = args[i];
|
|
1478
|
-
if (arg.startsWith("--")) {
|
|
1479
|
-
if (arg.includes("=")) {
|
|
1480
|
-
const [flagPart, ...valueParts] = arg.split("=");
|
|
1481
|
-
const flagName = flagPart.slice(2);
|
|
1482
|
-
const value = valueParts.join("=");
|
|
1483
|
-
const camelCaseName = flagName.replace(
|
|
1484
|
-
/-([a-z])/g,
|
|
1485
|
-
(_, letter) => letter.toUpperCase()
|
|
1486
|
-
);
|
|
1487
|
-
const parsedValue = parseValue(value);
|
|
1488
|
-
providedOptions.set(flagName, parsedValue);
|
|
1489
|
-
providedOptions.set(camelCaseName, parsedValue);
|
|
1490
|
-
} else {
|
|
1491
|
-
const flagName = arg.slice(2);
|
|
1492
|
-
const camelCaseName = flagName.replace(
|
|
1493
|
-
/-([a-z])/g,
|
|
1494
|
-
(_, letter) => letter.toUpperCase()
|
|
1495
|
-
);
|
|
1496
|
-
if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
1497
|
-
const value = args[i + 1];
|
|
1498
|
-
const parsedValue = parseValue(value);
|
|
1499
|
-
providedOptions.set(flagName, parsedValue);
|
|
1500
|
-
providedOptions.set(camelCaseName, parsedValue);
|
|
1501
|
-
i++;
|
|
1502
|
-
} else {
|
|
1503
|
-
providedOptions.set(flagName, true);
|
|
1504
|
-
providedOptions.set(camelCaseName, true);
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
} else if (arg.startsWith("-") && !arg.startsWith("--") && arg.length === 2) {
|
|
1508
|
-
const shortFlagMap = {
|
|
1509
|
-
d: "dry-run",
|
|
1510
|
-
v: "verbose",
|
|
1511
|
-
f: "force",
|
|
1512
|
-
h: "help"
|
|
1513
|
-
};
|
|
1514
|
-
const shortFlag = arg.slice(1);
|
|
1515
|
-
if (shortFlagMap[shortFlag]) {
|
|
1516
|
-
const longFlag = shortFlagMap[shortFlag];
|
|
1517
|
-
const camelCaseName = longFlag.replace(
|
|
1518
|
-
/-([a-z])/g,
|
|
1519
|
-
(_, letter) => letter.toUpperCase()
|
|
1520
|
-
);
|
|
1521
|
-
providedOptions.set(longFlag, true);
|
|
1522
|
-
providedOptions.set(camelCaseName, true);
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
if (options) {
|
|
1527
|
-
for (const [key, value] of Object.entries(options)) {
|
|
1528
|
-
providedOptions.set(key, value);
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
return providedOptions;
|
|
1532
|
-
}
|
|
1533
|
-
function parseValue(value) {
|
|
1534
|
-
if (value === "true") return true;
|
|
1535
|
-
if (value === "false") return false;
|
|
1536
|
-
if (/^-?\d+$/.test(value)) {
|
|
1537
|
-
return parseInt(value, 10);
|
|
1538
|
-
}
|
|
1539
|
-
if (/^-?\d*\.\d+$/.test(value)) {
|
|
1540
|
-
return parseFloat(value);
|
|
1541
|
-
}
|
|
1542
|
-
if (value === "null") return null;
|
|
1543
|
-
if (value === "undefined") return void 0;
|
|
1544
|
-
return value;
|
|
1545
|
-
}
|
|
1546
728
|
function isNxDryRunProvided() {
|
|
1547
729
|
const args = process.argv;
|
|
1548
730
|
return (
|
|
@@ -1563,142 +745,16 @@ function isNxNoInteractiveProvided() {
|
|
|
1563
745
|
);
|
|
1564
746
|
}
|
|
1565
747
|
|
|
1566
|
-
// packages/ai-toolkit-nx-claude/src/generators/hooks/generator.ts
|
|
1567
|
-
async function hooksGenerator(tree, options) {
|
|
1568
|
-
import_devkit4.logger.info("\u{1F3AF} Claude Code Hooks Generator");
|
|
1569
|
-
import_devkit4.logger.info("Installing notification hooks for Claude Code...\n");
|
|
1570
|
-
import_devkit4.logger.info("\u{1F4CB} Step 1: Checking dependencies...");
|
|
1571
|
-
const depsOk = await checkAndValidateDependencies();
|
|
1572
|
-
if (!depsOk && !options.force) {
|
|
1573
|
-
import_devkit4.logger.error(
|
|
1574
|
-
"\u274C Missing required dependencies. Install them and try again."
|
|
1575
|
-
);
|
|
1576
|
-
import_devkit4.logger.info("Use --force to skip dependency checks (not recommended)");
|
|
1577
|
-
return;
|
|
1578
|
-
}
|
|
1579
|
-
const schemaPath = path3.join(__dirname, "schema.json");
|
|
1580
|
-
let normalizedOptions;
|
|
1581
|
-
if (options.installMode === "default") {
|
|
1582
|
-
normalizedOptions = {
|
|
1583
|
-
backup: options.backup !== false,
|
|
1584
|
-
// Default to true unless explicitly false
|
|
1585
|
-
dry: options.dry || false,
|
|
1586
|
-
force: options.force || false,
|
|
1587
|
-
verbose: options.verbose || false,
|
|
1588
|
-
installMode: "default"
|
|
1589
|
-
};
|
|
1590
|
-
} else {
|
|
1591
|
-
const explicitlyProvided = getExplicitlyProvidedOptions(options);
|
|
1592
|
-
const nxDryRunProvided = isNxDryRunProvided();
|
|
1593
|
-
if (nxDryRunProvided) {
|
|
1594
|
-
options.dry = true;
|
|
1595
|
-
explicitlyProvided.set("dry", true);
|
|
1596
|
-
}
|
|
1597
|
-
const nxNoInteractiveProvided = isNxNoInteractiveProvided();
|
|
1598
|
-
const optionsWithNoInteractive = {
|
|
1599
|
-
...options,
|
|
1600
|
-
"no-interactive": nxNoInteractiveProvided
|
|
1601
|
-
};
|
|
1602
|
-
try {
|
|
1603
|
-
normalizedOptions = await promptForMissingOptions(
|
|
1604
|
-
optionsWithNoInteractive,
|
|
1605
|
-
schemaPath,
|
|
1606
|
-
{},
|
|
1607
|
-
// context for multi-select (not used here)
|
|
1608
|
-
explicitlyProvided
|
|
1609
|
-
// pass the explicitly provided options
|
|
1610
|
-
);
|
|
1611
|
-
} catch (error) {
|
|
1612
|
-
if (error.message?.includes("Installation cancelled")) {
|
|
1613
|
-
import_devkit4.logger.warn(`\u274C ${error.message}`);
|
|
1614
|
-
return;
|
|
1615
|
-
}
|
|
1616
|
-
throw error;
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
const isDryRun = normalizedOptions.dry;
|
|
1620
|
-
if (isDryRun) {
|
|
1621
|
-
import_devkit4.logger.info("\n\u{1F50D} DRY RUN MODE - No changes will be made");
|
|
1622
|
-
import_devkit4.logger.info("The following would be performed:");
|
|
1623
|
-
import_devkit4.logger.info(` 1. Download latest notification hooks`);
|
|
1624
|
-
import_devkit4.logger.info(` 2. Configure notification hooks`);
|
|
1625
|
-
import_devkit4.logger.info(` 3. Install hooks to ~/.claude/hooks/`);
|
|
1626
|
-
import_devkit4.logger.info(` 4. Update ~/.claude/settings.json`);
|
|
1627
|
-
if (normalizedOptions.backup) {
|
|
1628
|
-
import_devkit4.logger.info(` 5. Create backup of existing configuration`);
|
|
1629
|
-
}
|
|
1630
|
-
return;
|
|
1631
|
-
}
|
|
1632
|
-
import_devkit4.logger.info("\n\u{1F4E6} Step 2: Downloading notification hooks...");
|
|
1633
|
-
const repoPath = await ensureRepository({
|
|
1634
|
-
update: true,
|
|
1635
|
-
// Always update to latest
|
|
1636
|
-
verbose: normalizedOptions.verbose
|
|
1637
|
-
});
|
|
1638
|
-
if (!repoPath) {
|
|
1639
|
-
import_devkit4.logger.error("\u274C Failed to prepare repository");
|
|
1640
|
-
return;
|
|
1641
|
-
}
|
|
1642
|
-
import_devkit4.logger.info(`\u2705 Repository ready at: ${repoPath}`);
|
|
1643
|
-
import_devkit4.logger.info("\n\u{1F680} Step 3: Installing hooks...");
|
|
1644
|
-
const installResult = await runInstallation(repoPath, {
|
|
1645
|
-
backupExisting: normalizedOptions.backup !== false,
|
|
1646
|
-
verbose: normalizedOptions.verbose || false,
|
|
1647
|
-
dryRun: isDryRun
|
|
1648
|
-
});
|
|
1649
|
-
if (!installResult.success) {
|
|
1650
|
-
import_devkit4.logger.error("\u274C Installation failed");
|
|
1651
|
-
if (installResult.error) {
|
|
1652
|
-
import_devkit4.logger.error(`Error: ${installResult.error}`);
|
|
1653
|
-
}
|
|
1654
|
-
if (!normalizedOptions.verbose) {
|
|
1655
|
-
cleanupRepository(repoPath);
|
|
1656
|
-
}
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
const shouldTest = !isDryRun && normalizedOptions.verbose;
|
|
1660
|
-
if (shouldTest) {
|
|
1661
|
-
import_devkit4.logger.info("\n\u{1F9EA} Step 4: Testing installation...");
|
|
1662
|
-
const { prompt: prompt2 } = await import("enquirer");
|
|
1663
|
-
const { runTest } = await prompt2({
|
|
1664
|
-
type: "confirm",
|
|
1665
|
-
name: "runTest",
|
|
1666
|
-
message: "Would you like to test the hooks now?",
|
|
1667
|
-
initial: true
|
|
1668
|
-
});
|
|
1669
|
-
if (runTest) {
|
|
1670
|
-
await testHooks();
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
if (!normalizedOptions.verbose) {
|
|
1674
|
-
import_devkit4.logger.info("\n\u{1F9F9} Cleaning up temporary files...");
|
|
1675
|
-
cleanupRepository(repoPath);
|
|
1676
|
-
}
|
|
1677
|
-
await (0, import_devkit4.formatFiles)(tree);
|
|
1678
|
-
import_devkit4.logger.info("\n\u2728 SUCCESS! Claude Code hooks installed successfully!");
|
|
1679
|
-
import_devkit4.logger.info("\n\u{1F4DA} Next Steps:");
|
|
1680
|
-
import_devkit4.logger.info(" 1. Start a Claude Code session");
|
|
1681
|
-
import_devkit4.logger.info(" 2. When Claude needs your input, you'll hear a notification");
|
|
1682
|
-
import_devkit4.logger.info(" 3. Check ~/.claude/logs/ for event logs (if enabled)");
|
|
1683
|
-
if (installResult.backupPath) {
|
|
1684
|
-
import_devkit4.logger.info(`
|
|
1685
|
-
\u{1F4BE} Backup saved at: ${installResult.backupPath}`);
|
|
1686
|
-
}
|
|
1687
|
-
import_devkit4.logger.info("\n\u{1F389} Happy coding with Claude!");
|
|
1688
|
-
}
|
|
1689
|
-
var generator_default = hooksGenerator;
|
|
1690
|
-
|
|
1691
748
|
// packages/ai-toolkit-nx-claude/src/generators/addons/generator.ts
|
|
1692
|
-
var import_devkit5 = require("@nx/devkit");
|
|
1693
749
|
init_addon_registry();
|
|
1694
750
|
|
|
1695
751
|
// packages/ai-toolkit-nx-claude/src/generators/addons/claude-mcp-installer.ts
|
|
1696
|
-
var
|
|
752
|
+
var import_child_process = require("child_process");
|
|
1697
753
|
init_addon_registry();
|
|
1698
754
|
async function installMcpServer(options) {
|
|
1699
755
|
const { addon, additionalArgs = [], dryRun = false, installationType = "global" } = options;
|
|
1700
756
|
try {
|
|
1701
|
-
(0,
|
|
757
|
+
(0, import_child_process.execSync)("claude --version", { stdio: "ignore" });
|
|
1702
758
|
} catch {
|
|
1703
759
|
return {
|
|
1704
760
|
success: false,
|
|
@@ -1753,7 +809,7 @@ async function installMcpServer(options) {
|
|
|
1753
809
|
try {
|
|
1754
810
|
console.log(`
|
|
1755
811
|
\u{1F527} Installing MCP server (attempt ${attempts}/${maxAttempts})...`);
|
|
1756
|
-
const output = (0,
|
|
812
|
+
const output = (0, import_child_process.execSync)(command, {
|
|
1757
813
|
encoding: "utf-8",
|
|
1758
814
|
stdio: "pipe"
|
|
1759
815
|
});
|
|
@@ -1797,97 +853,17 @@ async function installMcpServer(options) {
|
|
|
1797
853
|
};
|
|
1798
854
|
}
|
|
1799
855
|
|
|
1800
|
-
// packages/ai-toolkit-nx-claude/src/generators/addons/
|
|
1801
|
-
var
|
|
856
|
+
// packages/ai-toolkit-nx-claude/src/generators/addons/aws-log-analyzer-setup.ts
|
|
857
|
+
var import_child_process2 = require("child_process");
|
|
1802
858
|
var import_fs2 = require("fs");
|
|
1803
859
|
var import_path2 = require("path");
|
|
1804
860
|
var import_os2 = require("os");
|
|
1805
|
-
|
|
1806
|
-
async function setupSpecWorkflow(projectPath, options) {
|
|
1807
|
-
const targetPath = projectPath || process.cwd();
|
|
1808
|
-
const targetDir = (0, import_path2.join)(targetPath, ".spec-workflow");
|
|
1809
|
-
console.log(`
|
|
1810
|
-
\u{1F4C1} Setting up spec-workflow in: ${targetPath}`);
|
|
1811
|
-
const isUpdate = (0, import_fs2.existsSync)(targetDir);
|
|
1812
|
-
if (options.dryRun) {
|
|
1813
|
-
console.log("[DRY-RUN] Would create/update directory: " + targetDir);
|
|
1814
|
-
console.log("[DRY-RUN] Would clone repository: @uniswap/spec-workflow-mcp");
|
|
1815
|
-
console.log("[DRY-RUN] Would copy/update configuration files");
|
|
1816
|
-
console.log("[DRY-RUN] Would add .spec-workflow/ to .gitignore");
|
|
1817
|
-
return {
|
|
1818
|
-
success: true,
|
|
1819
|
-
message: "[DRY-RUN] Spec-workflow setup simulated successfully",
|
|
1820
|
-
projectPath: targetPath
|
|
1821
|
-
};
|
|
1822
|
-
}
|
|
1823
|
-
if (isUpdate) {
|
|
1824
|
-
if (!options.force) {
|
|
1825
|
-
const { confirm } = await require("enquirer").prompt({
|
|
1826
|
-
type: "confirm",
|
|
1827
|
-
name: "confirm",
|
|
1828
|
-
message: `.spec-workflow directory already exists. Update configuration files from repository?`,
|
|
1829
|
-
initial: true
|
|
1830
|
-
});
|
|
1831
|
-
if (!confirm) {
|
|
1832
|
-
return {
|
|
1833
|
-
success: false,
|
|
1834
|
-
message: "Installation cancelled by user",
|
|
1835
|
-
projectPath: targetPath
|
|
1836
|
-
};
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
console.log(
|
|
1840
|
-
"\u{1F4DD} Updating configuration files in existing .spec-workflow directory..."
|
|
1841
|
-
);
|
|
1842
|
-
} else {
|
|
1843
|
-
console.log("\u{1F4C1} Creating .spec-workflow directory...");
|
|
1844
|
-
(0, import_fs2.mkdirSync)(targetDir, { recursive: true });
|
|
1845
|
-
}
|
|
1846
|
-
const tempDir = (0, import_path2.join)((0, import_os2.tmpdir)(), `spec-workflow-${Date.now()}`);
|
|
1847
|
-
console.log("\u{1F504} Cloning spec-workflow repository...");
|
|
1848
|
-
const cloneResult = await cloneRepository2(
|
|
1849
|
-
"https://github.com/Uniswap/spec-workflow-mcp.git",
|
|
1850
|
-
tempDir
|
|
1851
|
-
);
|
|
1852
|
-
if (!cloneResult.success) {
|
|
1853
|
-
return {
|
|
1854
|
-
success: false,
|
|
1855
|
-
message: cloneResult.error || "Failed to clone repository",
|
|
1856
|
-
projectPath: targetPath
|
|
1857
|
-
};
|
|
1858
|
-
}
|
|
1859
|
-
console.log("\u{1F4CB} Copying configuration files...");
|
|
1860
|
-
const configSourcePath = (0, import_path2.join)(tempDir, "configs");
|
|
1861
|
-
const copyResult = await copyConfigFiles(configSourcePath, targetDir);
|
|
1862
|
-
console.log("\u{1F9F9} Cleaning up temporary files...");
|
|
1863
|
-
(0, import_fs2.rmSync)(tempDir, { recursive: true, force: true });
|
|
1864
|
-
if (!copyResult.success) {
|
|
1865
|
-
return {
|
|
1866
|
-
success: false,
|
|
1867
|
-
message: copyResult.error || "Failed to copy configuration files",
|
|
1868
|
-
projectPath: targetPath
|
|
1869
|
-
};
|
|
1870
|
-
}
|
|
1871
|
-
console.log("\u{1F4DD} Updating .gitignore...");
|
|
1872
|
-
const gitignoreResult = await updateGitignore(targetPath, ".spec-workflow/");
|
|
1873
|
-
if (!gitignoreResult.success) {
|
|
1874
|
-
console.warn("\u26A0\uFE0F Warning:", gitignoreResult.message);
|
|
1875
|
-
} else {
|
|
1876
|
-
console.log("\u2705", gitignoreResult.message);
|
|
1877
|
-
}
|
|
1878
|
-
return {
|
|
1879
|
-
success: true,
|
|
1880
|
-
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",
|
|
1881
|
-
projectPath: targetPath,
|
|
1882
|
-
createdFiles: copyResult.copiedFiles
|
|
1883
|
-
};
|
|
1884
|
-
}
|
|
1885
|
-
async function cloneRepository2(repositoryUrl, targetDir) {
|
|
861
|
+
async function cloneRepository(repositoryUrl, targetDir) {
|
|
1886
862
|
try {
|
|
1887
863
|
if (!(0, import_fs2.existsSync)(targetDir)) {
|
|
1888
864
|
(0, import_fs2.mkdirSync)(targetDir, { recursive: true });
|
|
1889
865
|
}
|
|
1890
|
-
(0,
|
|
866
|
+
(0, import_child_process2.execSync)(`git clone --depth 1 "${repositoryUrl}" "${targetDir}"`, {
|
|
1891
867
|
stdio: "pipe",
|
|
1892
868
|
encoding: "utf8"
|
|
1893
869
|
});
|
|
@@ -1924,97 +900,12 @@ async function cloneRepository2(repositoryUrl, targetDir) {
|
|
|
1924
900
|
};
|
|
1925
901
|
}
|
|
1926
902
|
}
|
|
1927
|
-
async function updateGitignore(projectPath, pattern) {
|
|
1928
|
-
const gitignorePath = (0, import_path2.join)(projectPath, ".gitignore");
|
|
1929
|
-
try {
|
|
1930
|
-
let gitignoreContent = "";
|
|
1931
|
-
if ((0, import_fs2.existsSync)(gitignorePath)) {
|
|
1932
|
-
gitignoreContent = (0, import_fs2.readFileSync)(gitignorePath, "utf8");
|
|
1933
|
-
}
|
|
1934
|
-
const lines = gitignoreContent.split("\n");
|
|
1935
|
-
const patternExists = lines.some((line) => {
|
|
1936
|
-
const trimmedLine = line.trim();
|
|
1937
|
-
return trimmedLine === pattern || trimmedLine === pattern.replace(/\/$/, "");
|
|
1938
|
-
});
|
|
1939
|
-
if (patternExists) {
|
|
1940
|
-
return {
|
|
1941
|
-
success: true,
|
|
1942
|
-
message: `.gitignore already contains ${pattern}`
|
|
1943
|
-
};
|
|
1944
|
-
}
|
|
1945
|
-
const updatedContent = gitignoreContent.trim() === "" ? pattern : `${gitignoreContent.trim()}
|
|
1946
|
-
|
|
1947
|
-
# Spec workflow configuration
|
|
1948
|
-
${pattern}`;
|
|
1949
|
-
(0, import_fs2.writeFileSync)(gitignorePath, updatedContent + "\n", "utf8");
|
|
1950
|
-
return {
|
|
1951
|
-
success: true,
|
|
1952
|
-
message: `Added ${pattern} to .gitignore`
|
|
1953
|
-
};
|
|
1954
|
-
} catch (error) {
|
|
1955
|
-
console.error("\u274C Failed to update .gitignore:", error.message);
|
|
1956
|
-
return {
|
|
1957
|
-
success: false,
|
|
1958
|
-
message: `Failed to update .gitignore: ${error.message}`
|
|
1959
|
-
};
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
async function copyConfigFiles(sourceDir, targetDir) {
|
|
1963
|
-
try {
|
|
1964
|
-
let listFiles2 = function(dir, baseDir = dir, sourceBase = sourceDir) {
|
|
1965
|
-
const files = fs4.readdirSync(dir);
|
|
1966
|
-
for (const file of files) {
|
|
1967
|
-
const filePath = (0, import_path2.join)(dir, file);
|
|
1968
|
-
const stat = fs4.statSync(filePath);
|
|
1969
|
-
if (stat.isDirectory()) {
|
|
1970
|
-
listFiles2(filePath, baseDir, sourceBase);
|
|
1971
|
-
} else {
|
|
1972
|
-
const relativePath = filePath.replace(baseDir + "/", "");
|
|
1973
|
-
const sourceFile = (0, import_path2.join)(sourceBase, relativePath);
|
|
1974
|
-
if ((0, import_fs2.existsSync)(sourceFile)) {
|
|
1975
|
-
copiedFiles.push(relativePath);
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1979
|
-
};
|
|
1980
|
-
var listFiles = listFiles2;
|
|
1981
|
-
if (!(0, import_fs2.existsSync)(sourceDir)) {
|
|
1982
|
-
return {
|
|
1983
|
-
success: false,
|
|
1984
|
-
message: "Source directory not found",
|
|
1985
|
-
error: `The configs directory was not found in the cloned repository`
|
|
1986
|
-
};
|
|
1987
|
-
}
|
|
1988
|
-
(0, import_fs3.cpSync)(sourceDir, targetDir, { recursive: true });
|
|
1989
|
-
const fs4 = require("fs");
|
|
1990
|
-
const copiedFiles = [];
|
|
1991
|
-
listFiles2(targetDir, targetDir, sourceDir);
|
|
1992
|
-
return {
|
|
1993
|
-
success: true,
|
|
1994
|
-
message: "Configuration files copied successfully",
|
|
1995
|
-
copiedFiles
|
|
1996
|
-
};
|
|
1997
|
-
} catch (error) {
|
|
1998
|
-
console.error("\u274C File copy failed:", error.message);
|
|
1999
|
-
return {
|
|
2000
|
-
success: false,
|
|
2001
|
-
message: "Failed to copy configuration files",
|
|
2002
|
-
error: error.message
|
|
2003
|
-
};
|
|
2004
|
-
}
|
|
2005
|
-
}
|
|
2006
|
-
|
|
2007
|
-
// packages/ai-toolkit-nx-claude/src/generators/addons/aws-log-analyzer-setup.ts
|
|
2008
|
-
var import_child_process6 = require("child_process");
|
|
2009
|
-
var import_fs4 = require("fs");
|
|
2010
|
-
var import_path3 = require("path");
|
|
2011
|
-
var import_os3 = require("os");
|
|
2012
903
|
async function setupAwsLogAnalyzer(options) {
|
|
2013
|
-
const targetPath = (0,
|
|
2014
|
-
const serverPath = (0,
|
|
904
|
+
const targetPath = (0, import_path2.join)((0, import_os2.homedir)(), ".aws-log-analyzer-mcp");
|
|
905
|
+
const serverPath = (0, import_path2.join)(targetPath, "src", "cw-mcp-server");
|
|
2015
906
|
console.log(`
|
|
2016
907
|
\u{1F4C1} Setting up AWS Log Analyzer MCP in: ${targetPath}`);
|
|
2017
|
-
const isUpdate = (0,
|
|
908
|
+
const isUpdate = (0, import_fs2.existsSync)(targetPath);
|
|
2018
909
|
if (options.dryRun) {
|
|
2019
910
|
console.log("[DRY-RUN] Would clone repository to: " + targetPath);
|
|
2020
911
|
console.log("[DRY-RUN] MCP server would run from: " + serverPath);
|
|
@@ -2045,12 +936,12 @@ async function setupAwsLogAnalyzer(options) {
|
|
|
2045
936
|
}
|
|
2046
937
|
}
|
|
2047
938
|
console.log("\u{1F504} Updating AWS Log Analyzer repository...");
|
|
2048
|
-
(0,
|
|
939
|
+
(0, import_fs2.rmSync)(targetPath, { recursive: true, force: true });
|
|
2049
940
|
}
|
|
2050
941
|
console.log("\u{1F4C1} Creating installation directory...");
|
|
2051
|
-
(0,
|
|
942
|
+
(0, import_fs2.mkdirSync)(targetPath, { recursive: true });
|
|
2052
943
|
console.log("\u{1F504} Cloning AWS Log Analyzer repository...");
|
|
2053
|
-
const cloneResult = await
|
|
944
|
+
const cloneResult = await cloneRepository(
|
|
2054
945
|
"https://github.com/awslabs/Log-Analyzer-with-MCP.git",
|
|
2055
946
|
targetPath
|
|
2056
947
|
);
|
|
@@ -2063,7 +954,7 @@ async function setupAwsLogAnalyzer(options) {
|
|
|
2063
954
|
}
|
|
2064
955
|
console.log("\u{1F4E6} Installing Python dependencies with uv...");
|
|
2065
956
|
try {
|
|
2066
|
-
(0,
|
|
957
|
+
(0, import_child_process2.execSync)("uv sync", {
|
|
2067
958
|
cwd: targetPath,
|
|
2068
959
|
stdio: "inherit",
|
|
2069
960
|
encoding: "utf8"
|
|
@@ -2082,10 +973,10 @@ async function setupAwsLogAnalyzer(options) {
|
|
|
2082
973
|
};
|
|
2083
974
|
}
|
|
2084
975
|
function getAwsLogAnalyzerPath() {
|
|
2085
|
-
return (0,
|
|
976
|
+
return (0, import_path2.join)((0, import_os2.homedir)(), ".aws-log-analyzer-mcp");
|
|
2086
977
|
}
|
|
2087
978
|
function getAwsLogAnalyzerServerPath() {
|
|
2088
|
-
return (0,
|
|
979
|
+
return (0, import_path2.join)(getAwsLogAnalyzerPath(), "src", "cw-mcp-server");
|
|
2089
980
|
}
|
|
2090
981
|
|
|
2091
982
|
// packages/ai-toolkit-nx-claude/src/generators/addons/generator.ts
|
|
@@ -2113,8 +1004,6 @@ async function generator(tree, schema) {
|
|
|
2113
1004
|
selectionMode: schema.selectionMode || "all",
|
|
2114
1005
|
force: schema.force || false,
|
|
2115
1006
|
skipVerification: schema.skipVerification || false,
|
|
2116
|
-
dashboardMode: schema.dashboardMode || "always",
|
|
2117
|
-
port: schema.port || 0,
|
|
2118
1007
|
dry: schema.dry || false,
|
|
2119
1008
|
installMode: "default",
|
|
2120
1009
|
installationType: schema.installationType || "global",
|
|
@@ -2136,7 +1025,7 @@ async function generator(tree, schema) {
|
|
|
2136
1025
|
return;
|
|
2137
1026
|
}
|
|
2138
1027
|
await installSelectedAddons(tree, options);
|
|
2139
|
-
await (0,
|
|
1028
|
+
await (0, import_devkit.formatFiles)(tree);
|
|
2140
1029
|
}
|
|
2141
1030
|
async function installSelectedAddons(tree, options) {
|
|
2142
1031
|
const selectedAddonIds = options.addons || [];
|
|
@@ -2180,31 +1069,6 @@ async function installSelectedAddons(tree, options) {
|
|
|
2180
1069
|
continue;
|
|
2181
1070
|
}
|
|
2182
1071
|
await installMcpAddon(addon, options);
|
|
2183
|
-
if (addon.id === "spec-workflow-mcp" && addon.projectSetup && i === selectedAddons.length - 1) {
|
|
2184
|
-
const { setupProject } = await require("enquirer").prompt({
|
|
2185
|
-
type: "confirm",
|
|
2186
|
-
name: "setupProject",
|
|
2187
|
-
message: "\u{1F4C1} Would you like to set up spec-workflow configuration for a particular project?",
|
|
2188
|
-
initial: true
|
|
2189
|
-
});
|
|
2190
|
-
if (setupProject) {
|
|
2191
|
-
const { projectPath } = await require("enquirer").prompt({
|
|
2192
|
-
type: "input",
|
|
2193
|
-
name: "projectPath",
|
|
2194
|
-
message: "\u{1F4C1} Enter the project path where spec-workflow config should be added:",
|
|
2195
|
-
initial: process.cwd(),
|
|
2196
|
-
result: (value) => value || process.cwd()
|
|
2197
|
-
});
|
|
2198
|
-
options.projectPath = projectPath;
|
|
2199
|
-
if (options.dryRun) {
|
|
2200
|
-
console.log(`
|
|
2201
|
-
\u{1F4C1} [DRY-RUN] Would set up project configuration at: ${projectPath}`);
|
|
2202
|
-
}
|
|
2203
|
-
await installProjectSetup(addon, options);
|
|
2204
|
-
} else if (options.dryRun) {
|
|
2205
|
-
console.log("\n\u{1F4C1} [DRY-RUN] Skipping project configuration (user chose not to set up)");
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
1072
|
results.push({ addon, success: true });
|
|
2209
1073
|
} catch (error) {
|
|
2210
1074
|
console.error(` \u274C Failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -2315,14 +1179,6 @@ async function installMcpAddon(addon, options) {
|
|
|
2315
1179
|
console.log("\n\u{1F527} Installing MCP server...");
|
|
2316
1180
|
}
|
|
2317
1181
|
const additionalArgs = [];
|
|
2318
|
-
if (addon.id === "spec-workflow-mcp") {
|
|
2319
|
-
if (options.dashboardMode === "always") {
|
|
2320
|
-
additionalArgs.push("--AutoStartDashboard");
|
|
2321
|
-
}
|
|
2322
|
-
if (options.port && options.port > 0) {
|
|
2323
|
-
additionalArgs.push(`--Port=${options.port}`);
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
1182
|
const installResult = await installMcpServer({
|
|
2327
1183
|
addon,
|
|
2328
1184
|
additionalArgs,
|
|
@@ -2334,16 +1190,6 @@ async function installMcpAddon(addon, options) {
|
|
|
2334
1190
|
}
|
|
2335
1191
|
console.log(`\u2705 ${installResult.message}`);
|
|
2336
1192
|
}
|
|
2337
|
-
async function installProjectSetup(addon, options) {
|
|
2338
|
-
console.log("\n\u{1F527} Setting up project configuration...");
|
|
2339
|
-
const projectPath = options.projectPath || process.cwd();
|
|
2340
|
-
console.log(`\u{1F4CD} Using project directory: ${projectPath}`);
|
|
2341
|
-
const result = await setupSpecWorkflow(projectPath, options);
|
|
2342
|
-
if (!result.success) {
|
|
2343
|
-
throw new Error(result.message);
|
|
2344
|
-
}
|
|
2345
|
-
console.log(`\u2705 ${result.message}`);
|
|
2346
|
-
}
|
|
2347
1193
|
function showGeneralMcpInstructions(installedAddons) {
|
|
2348
1194
|
console.log("\n\u{1F4DA} Getting Started with Your MCPs");
|
|
2349
1195
|
console.log("==================================\n");
|
|
@@ -2357,7 +1203,7 @@ function showGeneralMcpInstructions(installedAddons) {
|
|
|
2357
1203
|
console.log(" https://linear.app/docs/mcp#claude");
|
|
2358
1204
|
console.log(" (Most MCPs follow a similar authentication flow)\n");
|
|
2359
1205
|
const needsAuth = installedAddons.filter(
|
|
2360
|
-
(addon) => addon.id === "slack-mcp" || addon.id === "github-mcp" || addon.id === "aws-log-analyzer-mcp" || addon.id === "
|
|
1206
|
+
(addon) => addon.id === "slack-mcp" || addon.id === "github-mcp" || addon.id === "aws-log-analyzer-mcp" || addon.id === "pulumi-mcp"
|
|
2361
1207
|
);
|
|
2362
1208
|
if (needsAuth.length > 0) {
|
|
2363
1209
|
console.log("\u{1F510} MCPs requiring authentication:");
|
|
@@ -2406,6 +1252,5 @@ function showGeneralMcpInstructions(installedAddons) {
|
|
|
2406
1252
|
}
|
|
2407
1253
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2408
1254
|
0 && (module.exports = {
|
|
2409
|
-
addonsGenerator
|
|
2410
|
-
hooksGenerator
|
|
1255
|
+
addonsGenerator
|
|
2411
1256
|
});
|