macca-method 1.0.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 (31) hide show
  1. package/.agents/macca-managed-skills.txt +17 -0
  2. package/.agents/skills/_shared/references/brainstorm-session.md +84 -0
  3. package/.agents/skills/_shared/references/human-loop.md +55 -0
  4. package/.agents/skills/_shared/references/output-ownership.md +31 -0
  5. package/.agents/skills/_shared/references/personas.md +39 -0
  6. package/.agents/skills/_shared/references/runtime-config.md +171 -0
  7. package/.agents/skills/_shared/references/scope-rules.md +55 -0
  8. package/.agents/skills/_shared/scripts/validate-skills.py +82 -0
  9. package/.agents/skills/add-feature/SKILL.md +190 -0
  10. package/.agents/skills/brainstorm-api/SKILL.md +313 -0
  11. package/.agents/skills/brainstorm-architecture/SKILL.md +302 -0
  12. package/.agents/skills/brainstorm-prd/SKILL.md +323 -0
  13. package/.agents/skills/brainstorm-rules/SKILL.md +302 -0
  14. package/.agents/skills/brainstorm-schema/SKILL.md +218 -0
  15. package/.agents/skills/brainstorm-styleguide/SKILL.md +273 -0
  16. package/.agents/skills/brainstorm-task/SKILL.md +279 -0
  17. package/.agents/skills/bug-fix/SKILL.md +352 -0
  18. package/.agents/skills/code-review/SKILL.md +100 -0
  19. package/.agents/skills/code-review/references/review-checklist.md +189 -0
  20. package/.agents/skills/developer/SKILL.md +117 -0
  21. package/.agents/skills/developer/references/execution-workflow.md +322 -0
  22. package/.agents/skills/help/SKILL.md +153 -0
  23. package/.agents/skills/rapat/SKILL.md +172 -0
  24. package/.agents/skills/spec-audit/SKILL.md +267 -0
  25. package/.agents/skills/spec-compliance/SKILL.md +303 -0
  26. package/.agents/skills/spec-init/SKILL.md +266 -0
  27. package/LICENSE +21 -0
  28. package/README.md +1129 -0
  29. package/bin/macca-method.js +651 -0
  30. package/package.json +35 -0
  31. package/skills-lock.json +22 -0
@@ -0,0 +1,651 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ const fs = require("node:fs");
6
+ const os = require("node:os");
7
+ const path = require("node:path");
8
+ const readline = require("node:readline");
9
+
10
+ const PACKAGE_ROOT = path.resolve(__dirname, "..");
11
+ const SOURCE_AGENTS_DIR = path.join(PACKAGE_ROOT, ".agents");
12
+ const SOURCE_SKILLS_DIR = path.join(SOURCE_AGENTS_DIR, "skills");
13
+ const SOURCE_MANAGED_SKILLS_FILE = path.join(SOURCE_AGENTS_DIR, "macca-managed-skills.txt");
14
+ const SOURCE_LOCK_FILE = path.join(PACKAGE_ROOT, "skills-lock.json");
15
+
16
+ const TOOL_DEFINITIONS = [
17
+ {
18
+ key: "copilot",
19
+ aliases: ["github-copilot"],
20
+ label: "GitHub Copilot",
21
+ destination: (targetDir) => path.join(targetDir, ".github", "skills"),
22
+ displayDestination: ".github/skills/"
23
+ },
24
+ {
25
+ key: "cursor",
26
+ aliases: [],
27
+ label: "Cursor",
28
+ destination: (targetDir) => path.join(targetDir, ".cursor", "skills"),
29
+ displayDestination: ".cursor/skills/"
30
+ },
31
+ {
32
+ key: "claude",
33
+ aliases: ["claude-code"],
34
+ label: "Claude Code",
35
+ destination: (targetDir) => path.join(targetDir, ".claude", "skills"),
36
+ displayDestination: ".claude/skills/"
37
+ },
38
+ {
39
+ key: "windsurf",
40
+ aliases: [],
41
+ label: "Windsurf",
42
+ destination: (targetDir) => path.join(targetDir, ".windsurf", "skills"),
43
+ displayDestination: ".windsurf/skills/"
44
+ },
45
+ {
46
+ key: "gemini",
47
+ aliases: ["gemini-cli"],
48
+ label: "Gemini CLI",
49
+ destination: (targetDir) => path.join(targetDir, ".gemini", "skills"),
50
+ displayDestination: ".gemini/skills/"
51
+ },
52
+ {
53
+ key: "opencode",
54
+ aliases: [],
55
+ label: "OpenCode",
56
+ destination: (targetDir) => path.join(targetDir, ".opencode", "skill"),
57
+ displayDestination: ".opencode/skill/"
58
+ },
59
+ {
60
+ key: "kilo",
61
+ aliases: ["kilo-code"],
62
+ label: "Kilo Code",
63
+ destination: (targetDir) => path.join(targetDir, ".kilo", "skills"),
64
+ displayDestination: ".kilo/skills/"
65
+ },
66
+ {
67
+ key: "codex",
68
+ aliases: ["openai-codex"],
69
+ label: "Codex (OpenAI)",
70
+ destination: (targetDir) => path.join(targetDir, ".agents", "skills"),
71
+ displayDestination: ".agents/skills/"
72
+ },
73
+ {
74
+ key: "kimi",
75
+ aliases: ["kimi-cli"],
76
+ label: "Kimi CLI",
77
+ destination: () => {
78
+ if (process.platform === "win32") {
79
+ return path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "agents", "skills");
80
+ }
81
+
82
+ return path.join(os.homedir(), ".config", "agents", "skills");
83
+ },
84
+ displayDestination: process.platform === "win32" ? "%APPDATA%\\agents\\skills\\" : "~/.config/agents/skills/"
85
+ }
86
+ ];
87
+
88
+ const TOOL_BY_KEY = new Map(TOOL_DEFINITIONS.map((tool) => [tool.key, tool]));
89
+ const TOOL_LOOKUP = new Map();
90
+ for (const tool of TOOL_DEFINITIONS) {
91
+ TOOL_LOOKUP.set(tool.key, tool.key);
92
+ for (const alias of tool.aliases) {
93
+ TOOL_LOOKUP.set(alias, tool.key);
94
+ }
95
+ }
96
+
97
+ function main() {
98
+ try {
99
+ const args = parseArgs(process.argv.slice(2));
100
+ const command = args._[0] || "help";
101
+
102
+ if (args.version) {
103
+ const packageJson = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, "package.json"), "utf8"));
104
+ process.stdout.write(`${packageJson.version}\n`);
105
+ return;
106
+ }
107
+
108
+ if (args.help || command === "help") {
109
+ printHelp();
110
+ return;
111
+ }
112
+
113
+ if (args.listTools) {
114
+ printToolList();
115
+ return;
116
+ }
117
+
118
+ ensurePackagedFiles();
119
+
120
+ if (command === "install") {
121
+ runInstall(args).catch((error) => exitWithError(error.message));
122
+ return;
123
+ }
124
+
125
+ if (command === "upgrade") {
126
+ runUpgrade(args);
127
+ return;
128
+ }
129
+
130
+ exitWithError(`Unknown command: ${command}`);
131
+ } catch (error) {
132
+ exitWithError(error.message);
133
+ }
134
+ }
135
+
136
+ function parseArgs(argv) {
137
+ const args = {
138
+ _: [],
139
+ tools: []
140
+ };
141
+
142
+ for (let index = 0; index < argv.length; index += 1) {
143
+ const token = argv[index];
144
+
145
+ if (token === "-h" || token === "--help") {
146
+ args.help = true;
147
+ continue;
148
+ }
149
+
150
+ if (token === "-v" || token === "--version") {
151
+ args.version = true;
152
+ continue;
153
+ }
154
+
155
+ if (token === "-y" || token === "--yes") {
156
+ args.yes = true;
157
+ continue;
158
+ }
159
+
160
+ if (token === "--list-tools") {
161
+ args.listTools = true;
162
+ continue;
163
+ }
164
+
165
+ if (token === "-t" || token === "--tool" || token === "--tools") {
166
+ const result = takeValue(argv, index, token);
167
+ args.tools.push(result.value);
168
+ index = result.index;
169
+ continue;
170
+ }
171
+
172
+ if (token.startsWith("--tool=") || token.startsWith("--tools=")) {
173
+ args.tools.push(token.slice(token.indexOf("=") + 1));
174
+ continue;
175
+ }
176
+
177
+ if (token === "-d" || token === "--directory") {
178
+ const result = takeValue(argv, index, token);
179
+ args.directory = result.value;
180
+ index = result.index;
181
+ continue;
182
+ }
183
+
184
+ if (token.startsWith("--directory=")) {
185
+ args.directory = token.slice(token.indexOf("=") + 1);
186
+ continue;
187
+ }
188
+
189
+ if (token === "--name") {
190
+ const result = takeValue(argv, index, token);
191
+ args.name = result.value;
192
+ index = result.index;
193
+ continue;
194
+ }
195
+
196
+ if (token.startsWith("--name=")) {
197
+ args.name = token.slice(token.indexOf("=") + 1);
198
+ continue;
199
+ }
200
+
201
+ if (token === "--project") {
202
+ const result = takeValue(argv, index, token);
203
+ args.project = result.value;
204
+ index = result.index;
205
+ continue;
206
+ }
207
+
208
+ if (token.startsWith("--project=")) {
209
+ args.project = token.slice(token.indexOf("=") + 1);
210
+ continue;
211
+ }
212
+
213
+ if (token === "--communication-language") {
214
+ const result = takeValue(argv, index, token);
215
+ args.communicationLanguage = result.value;
216
+ index = result.index;
217
+ continue;
218
+ }
219
+
220
+ if (token.startsWith("--communication-language=")) {
221
+ args.communicationLanguage = token.slice(token.indexOf("=") + 1);
222
+ continue;
223
+ }
224
+
225
+ if (token === "--document-language" || token === "--documents-language") {
226
+ const result = takeValue(argv, index, token);
227
+ args.documentLanguage = result.value;
228
+ index = result.index;
229
+ continue;
230
+ }
231
+
232
+ if (token.startsWith("--document-language=") || token.startsWith("--documents-language=")) {
233
+ args.documentLanguage = token.slice(token.indexOf("=") + 1);
234
+ continue;
235
+ }
236
+
237
+ if (token.startsWith("-")) {
238
+ throw new Error(`Unknown option: ${token}`);
239
+ }
240
+
241
+ args._.push(token);
242
+ }
243
+
244
+ return args;
245
+ }
246
+
247
+ function takeValue(argv, index, flag) {
248
+ const value = argv[index + 1];
249
+ if (value === undefined) {
250
+ throw new Error(`Missing value for ${flag}`);
251
+ }
252
+
253
+ return {
254
+ value,
255
+ index: index + 1
256
+ };
257
+ }
258
+
259
+ function ensurePackagedFiles() {
260
+ if (!fs.existsSync(SOURCE_SKILLS_DIR)) {
261
+ throw new Error("Packaged skills directory is missing. Reinstall the package or run from the repository root.");
262
+ }
263
+
264
+ if (!fs.existsSync(SOURCE_LOCK_FILE)) {
265
+ throw new Error("skills-lock.json is missing from the package.");
266
+ }
267
+ }
268
+
269
+ function printHelp() {
270
+ process.stdout.write(
271
+ [
272
+ "MACCA CLI",
273
+ "",
274
+ "Usage:",
275
+ " npx macca-method install [options]",
276
+ " npx macca-method upgrade [options]",
277
+ " npx macca-method --list-tools",
278
+ "",
279
+ "Install options:",
280
+ " -t, --tool <name> Repeatable. Also accepts comma-separated values.",
281
+ " -d, --directory <path> Target project directory. Defaults to the current directory.",
282
+ " -y, --yes Skip prompts and use defaults where needed.",
283
+ " --name <value> Developer name.",
284
+ " --project <value> Project name.",
285
+ " --communication-language <value>",
286
+ " --document-language <value>",
287
+ "",
288
+ "Examples:",
289
+ " npx macca-method install",
290
+ " npx macca-method install --tool github-copilot --tool codex --yes",
291
+ " npx macca-method upgrade",
292
+ ""
293
+ ].join("\n")
294
+ );
295
+ }
296
+
297
+ function printToolList() {
298
+ process.stdout.write("Supported tools:\n");
299
+ TOOL_DEFINITIONS.forEach((tool, index) => {
300
+ const aliases = tool.aliases.length > 0 ? ` (aliases: ${tool.aliases.join(", ")})` : "";
301
+ process.stdout.write(` ${index + 1}. ${tool.key} -> ${tool.label}${aliases}\n`);
302
+ });
303
+ }
304
+
305
+ function resolveTargetDirectory(rawDirectory) {
306
+ if (!rawDirectory) {
307
+ return process.cwd();
308
+ }
309
+
310
+ return path.resolve(process.cwd(), rawDirectory);
311
+ }
312
+
313
+ function readNonEmptyLines(filePath) {
314
+ if (!fs.existsSync(filePath)) {
315
+ return [];
316
+ }
317
+
318
+ return fs
319
+ .readFileSync(filePath, "utf8")
320
+ .split(/\r?\n/)
321
+ .map((line) => line.trim())
322
+ .filter(Boolean);
323
+ }
324
+
325
+ function unique(values) {
326
+ return [...new Set(values)];
327
+ }
328
+
329
+ function getSourceManagedSkills() {
330
+ const managedSkills = readNonEmptyLines(SOURCE_MANAGED_SKILLS_FILE);
331
+ if (managedSkills.length > 0) {
332
+ return managedSkills;
333
+ }
334
+
335
+ return fs
336
+ .readdirSync(SOURCE_SKILLS_DIR, { withFileTypes: true })
337
+ .filter((entry) => entry.isDirectory())
338
+ .map((entry) => entry.name)
339
+ .sort();
340
+ }
341
+
342
+ function normalizeLanguage(value) {
343
+ const trimmed = String(value || "").trim();
344
+ const lowered = trimmed.toLowerCase();
345
+
346
+ switch (lowered) {
347
+ case "":
348
+ case "id":
349
+ case "indo":
350
+ case "indonesia":
351
+ case "indonesian":
352
+ case "bahasa indonesia":
353
+ return "indonesian";
354
+ case "en":
355
+ case "eng":
356
+ case "english":
357
+ case "inggris":
358
+ case "bahasa inggris":
359
+ return "english";
360
+ default:
361
+ return lowered;
362
+ }
363
+ }
364
+
365
+ function ensureDirectory(directoryPath) {
366
+ fs.mkdirSync(directoryPath, { recursive: true });
367
+ }
368
+
369
+ function writeTextFile(filePath, content) {
370
+ ensureDirectory(path.dirname(filePath));
371
+ fs.writeFileSync(filePath, content, "utf8");
372
+ }
373
+
374
+ function copyFile(sourcePath, targetPath) {
375
+ ensureDirectory(path.dirname(targetPath));
376
+ fs.copyFileSync(sourcePath, targetPath);
377
+ }
378
+
379
+ function copyDirectory(sourcePath, targetPath) {
380
+ ensureDirectory(path.dirname(targetPath));
381
+ fs.rmSync(targetPath, { recursive: true, force: true });
382
+ fs.cpSync(sourcePath, targetPath, { recursive: true });
383
+ }
384
+
385
+ function normalizeToolList(values) {
386
+ const rawTokens = [];
387
+ for (const value of values) {
388
+ rawTokens.push(...String(value).split(","));
389
+ }
390
+
391
+ const resolved = [];
392
+ for (const token of rawTokens) {
393
+ const trimmed = token.trim().toLowerCase();
394
+ if (!trimmed) {
395
+ continue;
396
+ }
397
+
398
+ const key = TOOL_LOOKUP.get(trimmed);
399
+ if (!key) {
400
+ throw new Error(`Unknown tool: ${token}`);
401
+ }
402
+
403
+ resolved.push(key);
404
+ }
405
+
406
+ return unique(resolved);
407
+ }
408
+
409
+ function buildDeveloperConfig(options) {
410
+ return {
411
+ name: options.name,
412
+ project: options.project,
413
+ languagePreferences: {
414
+ communication: {
415
+ raw: options.communicationLanguage,
416
+ normalized: normalizeLanguage(options.communicationLanguage)
417
+ },
418
+ documents: {
419
+ raw: options.documentLanguage,
420
+ normalized: normalizeLanguage(options.documentLanguage)
421
+ }
422
+ }
423
+ };
424
+ }
425
+
426
+ function createPrompt() {
427
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
428
+ throw new Error("Interactive install requires a TTY. Use --yes and explicit flags in non-interactive environments.");
429
+ }
430
+
431
+ return readline.createInterface({
432
+ input: process.stdin,
433
+ output: process.stdout
434
+ });
435
+ }
436
+
437
+ function askQuestion(prompt, question) {
438
+ return new Promise((resolve) => {
439
+ prompt.question(question, resolve);
440
+ });
441
+ }
442
+
443
+ async function promptForTools() {
444
+ const prompt = createPrompt();
445
+
446
+ try {
447
+ process.stdout.write("\nPilih AI tool yang mau dipasang:\n");
448
+ TOOL_DEFINITIONS.forEach((tool, index) => {
449
+ process.stdout.write(` ${index + 1}. ${tool.label} -> ${tool.displayDestination}\n`);
450
+ });
451
+ process.stdout.write("\n");
452
+
453
+ while (true) {
454
+ const answer = await askQuestion(prompt, "Masukkan nomor/nama tool (pisahkan dengan koma, 'all', kosong = codex): ");
455
+ const parsed = parseInteractiveToolSelection(answer);
456
+ if (parsed.error) {
457
+ process.stdout.write(` ${parsed.error}\n`);
458
+ continue;
459
+ }
460
+
461
+ return parsed.tools;
462
+ }
463
+ } finally {
464
+ prompt.close();
465
+ }
466
+ }
467
+
468
+ function parseInteractiveToolSelection(answer) {
469
+ const trimmed = String(answer || "").trim();
470
+ if (!trimmed) {
471
+ return { tools: ["codex"] };
472
+ }
473
+
474
+ if (trimmed.toLowerCase() === "all") {
475
+ return { tools: TOOL_DEFINITIONS.map((tool) => tool.key) };
476
+ }
477
+
478
+ const tools = [];
479
+ for (const part of trimmed.split(",")) {
480
+ const token = part.trim();
481
+ if (!token) {
482
+ continue;
483
+ }
484
+
485
+ if (/^\d+$/.test(token)) {
486
+ const index = Number(token) - 1;
487
+ if (index < 0 || index >= TOOL_DEFINITIONS.length) {
488
+ return { error: `Pilihan nomor tidak valid: ${token}` };
489
+ }
490
+
491
+ tools.push(TOOL_DEFINITIONS[index].key);
492
+ continue;
493
+ }
494
+
495
+ const key = TOOL_LOOKUP.get(token.toLowerCase());
496
+ if (!key) {
497
+ return { error: `Nama tool tidak dikenal: ${token}` };
498
+ }
499
+
500
+ tools.push(key);
501
+ }
502
+
503
+ return { tools: unique(tools) };
504
+ }
505
+
506
+ async function promptForMetadata(seed) {
507
+ const prompt = createPrompt();
508
+
509
+ try {
510
+ const name = seed.name !== undefined ? seed.name : await askQuestion(prompt, "Kamu mau dipanggil apa? (Kosong = Skip): ");
511
+ const project = seed.project !== undefined ? seed.project : await askQuestion(prompt, "Nama project ini apa? (Kosong = Skip): ");
512
+ const communication = seed.communicationLanguage !== undefined
513
+ ? seed.communicationLanguage
514
+ : await askQuestion(prompt, "Bahasa komunikasi yang anda inginkan? (Kosong = Bahasa Indonesia): ");
515
+ const documents = seed.documentLanguage !== undefined
516
+ ? seed.documentLanguage
517
+ : await askQuestion(prompt, "Bahasa dokumen yang dihasilkan? (Kosong = Bahasa Indonesia): ");
518
+
519
+ return {
520
+ name: name || "",
521
+ project: project || "",
522
+ communicationLanguage: communication || "Bahasa Indonesia",
523
+ documentLanguage: documents || "Bahasa Indonesia"
524
+ };
525
+ } finally {
526
+ prompt.close();
527
+ }
528
+ }
529
+
530
+ function applyInstall(targetDir, tools, metadata) {
531
+ const managedSkills = getSourceManagedSkills();
532
+ const agentsDirectory = path.join(targetDir, ".agents");
533
+ ensureDirectory(targetDir);
534
+ ensureDirectory(agentsDirectory);
535
+
536
+ if (fs.existsSync(SOURCE_MANAGED_SKILLS_FILE)) {
537
+ copyFile(SOURCE_MANAGED_SKILLS_FILE, path.join(agentsDirectory, "macca-managed-skills.txt"));
538
+ } else {
539
+ writeTextFile(path.join(agentsDirectory, "macca-managed-skills.txt"), `${managedSkills.join("\n")}\n`);
540
+ }
541
+
542
+ copyFile(SOURCE_LOCK_FILE, path.join(targetDir, "skills-lock.json"));
543
+
544
+ for (const toolKey of tools) {
545
+ const tool = TOOL_BY_KEY.get(toolKey);
546
+ const destination = tool.destination(targetDir);
547
+ ensureDirectory(destination);
548
+
549
+ for (const skillName of managedSkills) {
550
+ copyDirectory(path.join(SOURCE_SKILLS_DIR, skillName), path.join(destination, skillName));
551
+ }
552
+ }
553
+
554
+ if (!tools.includes("codex")) {
555
+ fs.rmSync(path.join(agentsDirectory, "skills"), { recursive: true, force: true });
556
+ }
557
+
558
+ writeTextFile(path.join(agentsDirectory, "macca-tools.txt"), `${tools.join("\n")}\n`);
559
+ writeTextFile(
560
+ path.join(agentsDirectory, "developer-config.json"),
561
+ `${JSON.stringify(buildDeveloperConfig(metadata), null, 2)}\n`
562
+ );
563
+ }
564
+
565
+ function applyUpgrade(targetDir) {
566
+ const agentsDirectory = path.join(targetDir, ".agents");
567
+ const tools = readNonEmptyLines(path.join(agentsDirectory, "macca-tools.txt"));
568
+ if (tools.length === 0) {
569
+ throw new Error(".agents/macca-tools.txt was not found. Run install first so MACCA knows which tools to update.");
570
+ }
571
+
572
+ const previousManagedSkills = readNonEmptyLines(path.join(agentsDirectory, "macca-managed-skills.txt"));
573
+ const nextManagedSkills = getSourceManagedSkills();
574
+ const skillsToClean = unique([...previousManagedSkills, ...nextManagedSkills]);
575
+
576
+ for (const toolKey of tools) {
577
+ const tool = TOOL_BY_KEY.get(toolKey);
578
+ if (!tool) {
579
+ throw new Error(`Unsupported tool in .agents/macca-tools.txt: ${toolKey}`);
580
+ }
581
+
582
+ const destination = tool.destination(targetDir);
583
+ ensureDirectory(destination);
584
+
585
+ for (const skillName of skillsToClean) {
586
+ fs.rmSync(path.join(destination, skillName), { recursive: true, force: true });
587
+ }
588
+
589
+ for (const skillName of nextManagedSkills) {
590
+ copyDirectory(path.join(SOURCE_SKILLS_DIR, skillName), path.join(destination, skillName));
591
+ }
592
+ }
593
+
594
+ if (!tools.includes("codex")) {
595
+ fs.rmSync(path.join(agentsDirectory, "skills"), { recursive: true, force: true });
596
+ }
597
+
598
+ if (fs.existsSync(SOURCE_MANAGED_SKILLS_FILE)) {
599
+ copyFile(SOURCE_MANAGED_SKILLS_FILE, path.join(agentsDirectory, "macca-managed-skills.txt"));
600
+ } else {
601
+ writeTextFile(path.join(agentsDirectory, "macca-managed-skills.txt"), `${nextManagedSkills.join("\n")}\n`);
602
+ }
603
+
604
+ copyFile(SOURCE_LOCK_FILE, path.join(targetDir, "skills-lock.json"));
605
+ }
606
+
607
+ function printInstallSummary(action, tools) {
608
+ process.stdout.write(`\n MACCA ${action} untuk:\n`);
609
+ for (const toolKey of tools) {
610
+ const tool = TOOL_BY_KEY.get(toolKey);
611
+ process.stdout.write(` ✓ ${tool.label.padEnd(16)} -> ${tool.displayDestination}\n`);
612
+ }
613
+ process.stdout.write("\n");
614
+ }
615
+
616
+ async function runInstall(args) {
617
+ let tools = normalizeToolList(args.tools);
618
+ if (tools.length === 0) {
619
+ tools = args.yes ? ["codex"] : await promptForTools();
620
+ }
621
+
622
+ const metadata = args.yes
623
+ ? {
624
+ name: args.name || "",
625
+ project: args.project || "",
626
+ communicationLanguage: args.communicationLanguage || "Bahasa Indonesia",
627
+ documentLanguage: args.documentLanguage || "Bahasa Indonesia"
628
+ }
629
+ : await promptForMetadata(args);
630
+
631
+ const targetDir = resolveTargetDirectory(args.directory);
632
+ applyInstall(targetDir, tools, metadata);
633
+
634
+ printInstallSummary("installed", tools);
635
+ process.stdout.write(` Target project: ${targetDir}\n\n`);
636
+ }
637
+
638
+ function runUpgrade(args) {
639
+ const targetDir = resolveTargetDirectory(args.directory);
640
+ const tools = readNonEmptyLines(path.join(targetDir, ".agents", "macca-tools.txt"));
641
+ applyUpgrade(targetDir);
642
+ printInstallSummary("updated", tools);
643
+ process.stdout.write(` Target project: ${targetDir}\n\n`);
644
+ }
645
+
646
+ function exitWithError(message) {
647
+ process.stderr.write(`\nError: ${message}\n`);
648
+ process.exit(1);
649
+ }
650
+
651
+ main();
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "macca-method",
3
+ "version": "1.0.0",
4
+ "description": "CLI installer for MACCA AI spec-driven development skills.",
5
+ "license": "MIT",
6
+ "scripts": {
7
+ "test:install": "bash ./test-install.sh",
8
+ "test:install:published": "bash ./test-install.sh --published"
9
+ },
10
+ "bin": {
11
+ "macca-method": "bin/macca-method.js"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ ".agents/",
16
+ "README.md",
17
+ "LICENSE",
18
+ "skills-lock.json"
19
+ ],
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "keywords": [
24
+ "ai",
25
+ "agents",
26
+ "skills",
27
+ "spec-driven-development",
28
+ "macca"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/firdaus12p/MACCA-METHOD.git"
33
+ },
34
+ "homepage": "https://github.com/firdaus12p/MACCA-METHOD#readme"
35
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "skills": [
4
+ "_shared",
5
+ "add-feature",
6
+ "brainstorm-api",
7
+ "brainstorm-architecture",
8
+ "brainstorm-prd",
9
+ "brainstorm-rules",
10
+ "brainstorm-schema",
11
+ "brainstorm-styleguide",
12
+ "brainstorm-task",
13
+ "bug-fix",
14
+ "code-review",
15
+ "developer",
16
+ "help",
17
+ "rapat",
18
+ "spec-audit",
19
+ "spec-compliance",
20
+ "spec-init"
21
+ ]
22
+ }