codymaster 4.1.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 (193) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +285 -0
  3. package/adapters/antigravity.js +15 -0
  4. package/adapters/claude-code.js +17 -0
  5. package/adapters/cursor.js +16 -0
  6. package/commands/bootstrap.md +49 -0
  7. package/commands/build.md +48 -0
  8. package/commands/content.md +48 -0
  9. package/commands/continuity.md +60 -0
  10. package/commands/debug.md +51 -0
  11. package/commands/demo.md +96 -0
  12. package/commands/deploy.md +51 -0
  13. package/commands/plan.md +42 -0
  14. package/commands/review.md +55 -0
  15. package/commands/track.md +46 -0
  16. package/commands/ux.md +46 -0
  17. package/dist/agent-dispatch.js +161 -0
  18. package/dist/chains/builtin.js +85 -0
  19. package/dist/continuity.js +385 -0
  20. package/dist/dashboard.js +926 -0
  21. package/dist/data.js +122 -0
  22. package/dist/index.js +2434 -0
  23. package/dist/judge.js +252 -0
  24. package/dist/parallel-dispatch.js +359 -0
  25. package/dist/parallel-quality.js +172 -0
  26. package/dist/skill-chain.js +258 -0
  27. package/install.sh +513 -0
  28. package/package.json +79 -0
  29. package/skills/.content-factory-state.json +132 -0
  30. package/skills/.git 2/logs/refs/heads/main +1 -0
  31. package/skills/.git 2/logs/refs/remotes/origin/main +1 -0
  32. package/skills/.git 2/objects/02/fb0956734b5f8ba3f918b7defd04a89cfe0076 +0 -0
  33. package/skills/.git 2/objects/08/1e129d75dc6feac6c02037272e6bd1a04e3324 +0 -0
  34. package/skills/.git 2/objects/0c/5393416f3c5e01c9a655a802bff0dd52f76f0a +0 -0
  35. package/skills/.git 2/objects/10/0b9be46978a946a77188f68be725098a122001 +0 -0
  36. package/skills/.git 2/objects/10/cf041167fc9843610eb3d90259ef3396315fdc +0 -0
  37. package/skills/.git 2/objects/12/5e19538dd6e1338ffe74f6c4c165b00435bf48 +0 -0
  38. package/skills/.git 2/objects/16/a9b9d0088d5c1347628b45a2620b479d8ad57c +0 -0
  39. package/skills/.git 2/objects/17/8c2a9ef93c33ae4eec9d58e82321f9229843a1 +0 -0
  40. package/skills/.git 2/objects/25/397ae41d09104d763bdcac2695209d85cdea89 +0 -0
  41. package/skills/.git 2/objects/2f/a836b7947f2d458e1f639788bf4bb0983a3305 +0 -0
  42. package/skills/.git 2/objects/3a/baaaf0a1c0909c0828335791557125fba911e0 +0 -0
  43. package/skills/.git 2/objects/42/2924221b81f5ce3c4e4daac9a64a24f9b01f9a +0 -0
  44. package/skills/.git 2/objects/42/ec0ce707447dc11446a34c9995fb8533801731 +0 -0
  45. package/skills/.git 2/objects/46/e43ce92866d56ce74b1d750db307cfe6154a15 +0 -0
  46. package/skills/.git 2/objects/48/5e41b633c63f55b8277bcc59f44f67681f671a +0 -0
  47. package/skills/.git 2/objects/49/49c596a3a89fa240642acd95dd3258e261eb09 +0 -0
  48. package/skills/.git 2/objects/50/9d42d8412ef8eaf7f7e138476bac2e4d10ce60 +0 -0
  49. package/skills/.git 2/objects/55/0c8c389d981b463ef849aeb792d8be3ccb6ec8 +0 -0
  50. package/skills/.git 2/objects/5d/82d3b18410cdda3ace3677436f0cb599dbe2d2 +0 -0
  51. package/skills/.git 2/objects/60/0617c58e871a38b33bf29e282d132bb3c381ad +0 -0
  52. package/skills/.git 2/objects/6a/8369a99c687b7245c92ffaf0e0f0dab9014504 +0 -0
  53. package/skills/.git 2/objects/79/bea435d40ab531c1aaf6be0432c6a5b7aaed21 +0 -0
  54. package/skills/.git 2/objects/7e/5ebd79251c2f14e4aceb86c74b6b6daae6b500 +0 -0
  55. package/skills/.git 2/objects/81/98a822a60178d6d5023ddb3e222cddf048742e +0 -0
  56. package/skills/.git 2/objects/86/0a0e1943dfe53411d2e499a1f16f46a96ef758 +0 -0
  57. package/skills/.git 2/objects/86/971fb55fdc081fdbae52376f0f13e57a4e9b04 +0 -0
  58. package/skills/.git 2/objects/88/b89dd609a0a03f8d4fe8bfde20d5b8fc1d326d +0 -0
  59. package/skills/.git 2/objects/90/8737edb6b7809e32cc01590b4e08ba42a9d40d +0 -0
  60. package/skills/.git 2/objects/93/d5a8a9a7d4fb7f11491cb596a6880528725118 +0 -0
  61. package/skills/.git 2/objects/98/46a2ab81d0c3b3eb00ef88fc56989aa7e9f316 +0 -0
  62. package/skills/.git 2/objects/9b/d8dd1e49cf274eaf9c555f3ab39dce7af5715e +0 -0
  63. package/skills/.git 2/objects/a1/13329fb0cec96ae78b222d33a24c3b5bc7fa1f +0 -0
  64. package/skills/.git 2/objects/a9/e6effe626e8a3aea3a8fc3364b492191c6e7d0 +0 -0
  65. package/skills/.git 2/objects/ad/6de7e48d9782cca9353d1ff0aa1aab7fe1df85 +0 -0
  66. package/skills/.git 2/objects/af/54ae316f771ff692e299ffcd8bf2f06b413b59 +0 -0
  67. package/skills/.git 2/objects/b0/4cb8b0b00dad633e731c1472161419e738d674 +0 -0
  68. package/skills/.git 2/objects/b3/094abb0b9ed46419b269e4a4e36a459690e3b0 +0 -0
  69. package/skills/.git 2/objects/b9/435c5d4baac2cfc5c83009ddd27b46b60db5f1 +0 -0
  70. package/skills/.git 2/objects/ba/5da17dbaec5ec2dcfdfd126aead518d1171d5c +0 -0
  71. package/skills/.git 2/objects/c0/bf58703aa258ba5dd63083bebaec8f223d844c +0 -0
  72. package/skills/.git 2/objects/c4/701a34edf1fc1bad58ccc57bd03f9426acb59a +0 -0
  73. package/skills/.git 2/objects/c7/5ccce9a4e5cc74d9b3174550cf6d993ca43638 +0 -0
  74. package/skills/.git 2/objects/c7/710d59b5a35b0f1f0a0399386643a0bd94c929 +0 -0
  75. package/skills/.git 2/objects/d1/fe58237112e953e5fec52da22cf38e08be3df9 +5 -0
  76. package/skills/.git 2/objects/d2/2bbe9fd2f74c95bc5583e803f5e435f1e2cd86 +0 -0
  77. package/skills/.git 2/objects/d7/e72852ea2bff74581dbf247d400120086229f4 +0 -0
  78. package/skills/.git 2/objects/d8/d4c3b5553e4fd72807e1d4b49ef07d9ef3ac35 +0 -0
  79. package/skills/.git 2/objects/dc/75050c2876f6a02ae2a53a3c886f395b622977 +0 -0
  80. package/skills/.git 2/objects/ee/e8546f95acec500187c08a28a8b9ee02db0dec +0 -0
  81. package/skills/.git 2/objects/ef/263c059208b416c2146434f10cb2b9fabcba16 +0 -0
  82. package/skills/.git 2/objects/f3/ae597e84d9a59b88acd21c99bde2eaf686d785 +0 -0
  83. package/skills/.git 2/objects/f3/f6f5673c821d3d8e76fa267a9e882e7a5387ea +0 -0
  84. package/skills/.git 2/objects/f9/6e6d0ad02624dd11d5848594d056caef7a5e8b +0 -0
  85. package/skills/.git 2/objects/ff/278988fc1edf0db3abcf18de795f4cc0b4f3e1 +0 -0
  86. package/skills/.git 2/refs/heads/main +1 -0
  87. package/skills/.git 2/refs/remotes/origin/main +1 -0
  88. package/skills/.pytest_cache 2/v/cache/nodeids +76 -0
  89. package/skills/.pytest_cache 2/v/cache/stepwise +1 -0
  90. package/skills/_shared/helpers.md +123 -0
  91. package/skills/_shared/outputs-convention.md +24 -0
  92. package/skills/cm-ads-tracker/SKILL.md +109 -0
  93. package/skills/cm-ads-tracker/evals/evals.json +55 -0
  94. package/skills/cm-ads-tracker/references/gtm-architecture.md +321 -0
  95. package/skills/cm-ads-tracker/references/industry-events.md +294 -0
  96. package/skills/cm-ads-tracker/references/platforms-api.md +238 -0
  97. package/skills/cm-ads-tracker/templates/capi-payload.md +79 -0
  98. package/skills/cm-ads-tracker/templates/datalayer-push.js +104 -0
  99. package/skills/cm-ads-tracker/templates/gtm-variables.js +56 -0
  100. package/skills/cm-brainstorm-idea/SKILL.md +423 -0
  101. package/skills/cm-code-review/SKILL.md +151 -0
  102. package/skills/cm-content-factory/SKILL.md +416 -0
  103. package/skills/cm-continuity/SKILL.md +399 -0
  104. package/skills/cm-dashboard/SKILL.md +533 -0
  105. package/skills/cm-dashboard/ui/app.js +1270 -0
  106. package/skills/cm-dashboard/ui/index.html +206 -0
  107. package/skills/cm-dashboard/ui/style.css +440 -0
  108. package/skills/cm-debugging/SKILL.md +412 -0
  109. package/skills/cm-deep-search/SKILL.md +242 -0
  110. package/skills/cm-design-system/SKILL.md +97 -0
  111. package/skills/cm-design-system/resources/halo-modern.md +40 -0
  112. package/skills/cm-design-system/resources/lunaris-advanced.md +40 -0
  113. package/skills/cm-design-system/resources/nitro-enterprise.md +39 -0
  114. package/skills/cm-design-system/resources/shadcn-default.md +37 -0
  115. package/skills/cm-dockit/README.md +100 -0
  116. package/skills/cm-dockit/SKILL.md +302 -0
  117. package/skills/cm-dockit/index.html +443 -0
  118. package/skills/cm-dockit/package-lock.json +1850 -0
  119. package/skills/cm-dockit/package.json +14 -0
  120. package/skills/cm-dockit/prompts/analysis.md +34 -0
  121. package/skills/cm-dockit/prompts/api-reference.md +24 -0
  122. package/skills/cm-dockit/prompts/architecture.md +21 -0
  123. package/skills/cm-dockit/prompts/data-flow.md +20 -0
  124. package/skills/cm-dockit/prompts/database.md +21 -0
  125. package/skills/cm-dockit/prompts/deployment.md +22 -0
  126. package/skills/cm-dockit/prompts/flows.md +21 -0
  127. package/skills/cm-dockit/prompts/jtbd.md +20 -0
  128. package/skills/cm-dockit/prompts/personas.md +24 -0
  129. package/skills/cm-dockit/prompts/sop-modules.md +40 -0
  130. package/skills/cm-dockit/scripts/doc-gen.sh +121 -0
  131. package/skills/cm-dockit/scripts/dockit-dashboard.sh +142 -0
  132. package/skills/cm-dockit/scripts/dockit-runner.sh +607 -0
  133. package/skills/cm-dockit/scripts/dockit-task.sh +166 -0
  134. package/skills/cm-dockit/skills/analyze-codebase.md +174 -0
  135. package/skills/cm-dockit/skills/api-reference.md +237 -0
  136. package/skills/cm-dockit/skills/changelog-guide.md +195 -0
  137. package/skills/cm-dockit/skills/content-guidelines.md +190 -0
  138. package/skills/cm-dockit/skills/sop-guide.md +184 -0
  139. package/skills/cm-dockit/skills/tech-docs.md +287 -0
  140. package/skills/cm-dockit/templates/markdown/structure.md +60 -0
  141. package/skills/cm-dockit/templates/vitepress-premium/.vitepress/config.mts +110 -0
  142. package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/custom.css +189 -0
  143. package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/index.ts +4 -0
  144. package/skills/cm-dockit/templates/vitepress-premium/package.json +19 -0
  145. package/skills/cm-dockit/templates/vitepress-premium/tests/frontend.test.ts +45 -0
  146. package/skills/cm-dockit/tests/runner.test.ts +66 -0
  147. package/skills/cm-dockit/workflows/export-markdown.md +82 -0
  148. package/skills/cm-dockit/workflows/generate-docs.md +68 -0
  149. package/skills/cm-dockit/workflows/setup-vitepress.md +181 -0
  150. package/skills/cm-example/SKILL.md +26 -0
  151. package/skills/cm-execution/SKILL.md +268 -0
  152. package/skills/cm-git-worktrees/SKILL.md +164 -0
  153. package/skills/cm-how-it-work/SKILL.md +189 -0
  154. package/skills/cm-identity-guard/SKILL.md +412 -0
  155. package/skills/cm-jtbd/SKILL.md +98 -0
  156. package/skills/cm-planning/SKILL.md +130 -0
  157. package/skills/cm-project-bootstrap/SKILL.md +161 -0
  158. package/skills/cm-project-bootstrap/templates/AGENTS.md +42 -0
  159. package/skills/cm-project-bootstrap/templates/frontend-safety.test.js +51 -0
  160. package/skills/cm-project-bootstrap/templates/i18n-sync.test.js +38 -0
  161. package/skills/cm-project-bootstrap/templates/pr-template.md +12 -0
  162. package/skills/cm-project-bootstrap/templates/project-identity.json +29 -0
  163. package/skills/cm-project-bootstrap/templates/vitest.config.js +10 -0
  164. package/skills/cm-quality-gate/SKILL.md +218 -0
  165. package/skills/cm-readit/SKILL.md +289 -0
  166. package/skills/cm-readit/audio-player.md +206 -0
  167. package/skills/cm-readit/examples/blog-reader.js +352 -0
  168. package/skills/cm-readit/examples/voice-cro.js +390 -0
  169. package/skills/cm-readit/tts-engine.md +262 -0
  170. package/skills/cm-readit/ui-patterns.md +362 -0
  171. package/skills/cm-readit/voice-cro.md +223 -0
  172. package/skills/cm-safe-deploy/SKILL.md +120 -0
  173. package/skills/cm-safe-deploy/templates/deploy.sh +89 -0
  174. package/skills/cm-safe-i18n/SKILL.md +473 -0
  175. package/skills/cm-secret-shield/SKILL.md +580 -0
  176. package/skills/cm-skill-chain/SKILL.md +78 -0
  177. package/skills/cm-skill-index/SKILL.md +318 -0
  178. package/skills/cm-skill-mastery/SKILL.md +169 -0
  179. package/skills/cm-start/SKILL.md +65 -0
  180. package/skills/cm-status/SKILL.md +12 -0
  181. package/skills/cm-tdd/SKILL.md +370 -0
  182. package/skills/cm-terminal/SKILL.md +177 -0
  183. package/skills/cm-test-gate/SKILL.md +242 -0
  184. package/skills/cm-ui-preview/SKILL.md +291 -0
  185. package/skills/cm-ux-master/DESIGN_STANDARD_TEMPLATE.md +54 -0
  186. package/skills/cm-ux-master/SKILL.md +114 -0
  187. package/skills/cro-methodology/SKILL.md +98 -0
  188. package/skills/cro-methodology/references/COPYWRITING.md +178 -0
  189. package/skills/cro-methodology/references/OBJECTIONS.md +135 -0
  190. package/skills/cro-methodology/references/PERSUASION.md +158 -0
  191. package/skills/cro-methodology/references/RESEARCH.md +220 -0
  192. package/skills/cro-methodology/references/funnel-analysis.md +365 -0
  193. package/skills/cro-methodology/references/testing-methodology.md +330 -0
package/dist/index.js ADDED
@@ -0,0 +1,2434 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __importDefault = (this && this.__importDefault) || function (mod) {
46
+ return (mod && mod.__esModule) ? mod : { "default": mod };
47
+ };
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ const commander_1 = require("commander");
50
+ const chalk_1 = __importDefault(require("chalk"));
51
+ const crypto_1 = __importDefault(require("crypto"));
52
+ const fs_1 = __importDefault(require("fs"));
53
+ const data_1 = require("./data");
54
+ const dashboard_1 = require("./dashboard");
55
+ const agent_dispatch_1 = require("./agent-dispatch");
56
+ const continuity_1 = require("./continuity");
57
+ const judge_1 = require("./judge");
58
+ const skill_chain_1 = require("./skill-chain");
59
+ const path_1 = __importDefault(require("path"));
60
+ const os_1 = __importDefault(require("os"));
61
+ const https_1 = __importDefault(require("https"));
62
+ const VERSION = '3.4.0';
63
+ // ─── Branding ───────────────────────────────────────────────────────────────
64
+ function showBanner() {
65
+ const cPath = process.cwd().replace(os_1.default.homedir(), '~');
66
+ const bg = chalk_1.default.bgHex('#F59E0B');
67
+ console.log('');
68
+ console.log(` ${bg(' ')} ${chalk_1.default.bold.white('CodyMaster')} ${chalk_1.default.gray(`v${VERSION}`)}`);
69
+ console.log(` ${bg.black.bold(' CM ')} ${chalk_1.default.gray('34 Skills. Ship 10x faster.')}`);
70
+ console.log(` ${bg(' ')} ${chalk_1.default.gray(cPath)}`);
71
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(46)));
72
+ }
73
+ // ─── Utility ────────────────────────────────────────────────────────────────
74
+ const COL_COLORS = {
75
+ 'backlog': chalk_1.default.gray, 'in-progress': chalk_1.default.blue, 'review': chalk_1.default.yellow, 'done': chalk_1.default.green,
76
+ };
77
+ const PRIORITY_COLORS = {
78
+ 'low': chalk_1.default.green, 'medium': chalk_1.default.yellow, 'high': chalk_1.default.red, 'urgent': chalk_1.default.magenta,
79
+ };
80
+ const STATUS_COLORS = {
81
+ 'success': chalk_1.default.green, 'failed': chalk_1.default.red, 'pending': chalk_1.default.yellow,
82
+ 'running': chalk_1.default.blue, 'rolled_back': chalk_1.default.magenta,
83
+ };
84
+ function padRight(str, len) {
85
+ return str.length >= len ? str.substring(0, len) : str + ' '.repeat(len - str.length);
86
+ }
87
+ function openUrl(url) {
88
+ const { execFile } = require('child_process');
89
+ const [cmd, ...args] = process.platform === 'darwin' ? ['open', url] :
90
+ process.platform === 'win32' ? ['cmd', '/c', 'start', url] :
91
+ ['xdg-open', url];
92
+ execFile(cmd, args, () => { });
93
+ }
94
+ // ─── Post-install Onboarding ─────────────────────────────────────────────────
95
+ function postInstallOnboarding(platform) {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ console.log();
98
+ console.log(chalk_1.default.green('╔══════════════════════════════════════════════════╗'));
99
+ console.log(chalk_1.default.green('║ 🎉 You\'re all set! What would you like to do? ║'));
100
+ console.log(chalk_1.default.green('╚══════════════════════════════════════════════════╝'));
101
+ console.log();
102
+ const p = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
103
+ const invoke = platform === 'claude' ? '/cm:demo (type in Claude Code)' :
104
+ platform === 'gemini' ? '@[/cm-planning] in Gemini CLI' :
105
+ platform === 'cursor' ? '@cm-planning in Cursor Agent' :
106
+ '@cm-planning in your AI tool';
107
+ const resp = yield p({
108
+ type: 'select',
109
+ name: 'action',
110
+ message: 'Choose an action:',
111
+ choices: [
112
+ {
113
+ title: chalk_1.default.cyan('📊 Launch Dashboard'), value: 'dashboard',
114
+ description: `Open Mission Control → http://localhost:${data_1.DEFAULT_PORT}`
115
+ },
116
+ {
117
+ title: chalk_1.default.magenta('🚀 Start in ' + platform.charAt(0).toUpperCase() + platform.slice(1)), value: 'invoke',
118
+ description: invoke
119
+ },
120
+ {
121
+ title: chalk_1.default.white('🧩 Browse all 34 skills'), value: 'skills',
122
+ description: 'See every skill, domain, and usage'
123
+ },
124
+ {
125
+ title: chalk_1.default.yellow('⚡ Install `cm` globally'), value: 'global',
126
+ description: 'Add cody / cm / codymaster to your PATH'
127
+ },
128
+ { title: chalk_1.default.gray('✅ Done'), value: 'done' },
129
+ ],
130
+ hint: '↑↓ navigate · Enter select · Ctrl+C exit',
131
+ });
132
+ switch (resp === null || resp === void 0 ? void 0 : resp.action) {
133
+ case 'dashboard': {
134
+ console.log();
135
+ if (!isDashboardRunning()) {
136
+ (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
137
+ yield new Promise(r => setTimeout(r, 800)); // let server start
138
+ }
139
+ console.log(chalk_1.default.cyan(`🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...`));
140
+ openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
141
+ console.log(chalk_1.default.gray(' Dashboard is running. Press Ctrl+C to stop.\n'));
142
+ break;
143
+ }
144
+ case 'invoke':
145
+ console.log();
146
+ if (platform === 'claude') {
147
+ console.log(chalk_1.default.white('Open Claude Code and type:\n'));
148
+ console.log(chalk_1.default.cyan(' /cm:demo'));
149
+ console.log(chalk_1.default.gray('\n This will run an interactive tour of all 34 skills.\n'));
150
+ }
151
+ else {
152
+ console.log(chalk_1.default.cyan(` ${invoke}\n`));
153
+ }
154
+ break;
155
+ case 'skills':
156
+ console.log();
157
+ skillList();
158
+ break;
159
+ case 'global':
160
+ console.log();
161
+ console.log(chalk_1.default.white('Run this to install the `cm` CLI globally:\n'));
162
+ console.log(chalk_1.default.cyan(' npm install -g codymaster'));
163
+ console.log(chalk_1.default.gray('\nThen use:'));
164
+ console.log(chalk_1.default.cyan(' cm task add "My task"'));
165
+ console.log(chalk_1.default.cyan(' cm dashboard'));
166
+ console.log(chalk_1.default.cyan(' cm status\n'));
167
+ break;
168
+ default:
169
+ console.log(chalk_1.default.gray('\nRun `npx codymaster` any time to open the menu.\n'));
170
+ }
171
+ });
172
+ }
173
+ // ─── Interactive Quick Menu (no-args entry point) ─────────────────────────────
174
+ function showInteractiveMenu() {
175
+ return __awaiter(this, void 0, void 0, function* () {
176
+ showBanner();
177
+ const dashStatus = isDashboardRunning()
178
+ ? chalk_1.default.green('● RUNNING') + chalk_1.default.gray(` http://localhost:${data_1.DEFAULT_PORT}`)
179
+ : chalk_1.default.gray('○ stopped');
180
+ console.log(chalk_1.default.gray(` Dashboard: ${dashStatus}`));
181
+ console.log();
182
+ const p = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
183
+ const resp = yield p({
184
+ type: 'select',
185
+ name: 'action',
186
+ message: 'Quick menu:',
187
+ choices: [
188
+ {
189
+ title: chalk_1.default.cyan('📊 Dashboard'), value: 'dashboard',
190
+ description: isDashboardRunning() ? 'Open in browser' : 'Start & open in browser'
191
+ },
192
+ {
193
+ title: chalk_1.default.white('📋 My Tasks'), value: 'tasks',
194
+ description: 'View all tasks across projects'
195
+ },
196
+ {
197
+ title: chalk_1.default.white('📈 Status'), value: 'status',
198
+ description: 'Project health snapshot'
199
+ },
200
+ {
201
+ title: chalk_1.default.magenta('🧩 Browse Skills'), value: 'skills',
202
+ description: 'All 34 skills by domain'
203
+ },
204
+ {
205
+ title: chalk_1.default.yellow('➕ Add a Task'), value: 'addtask',
206
+ description: 'Quickly add a task to backlog'
207
+ },
208
+ {
209
+ title: chalk_1.default.green('⚡ Install/Update Skills'), value: 'install',
210
+ description: 'npx codymaster add --all'
211
+ },
212
+ { title: chalk_1.default.gray('❓ Help'), value: 'help' },
213
+ ],
214
+ hint: '↑↓ navigate · Enter select · Ctrl+C exit',
215
+ });
216
+ console.log();
217
+ switch (resp === null || resp === void 0 ? void 0 : resp.action) {
218
+ case 'dashboard':
219
+ if (!isDashboardRunning()) {
220
+ (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
221
+ yield new Promise(r => setTimeout(r, 800));
222
+ }
223
+ console.log(chalk_1.default.cyan(`🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...`));
224
+ openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
225
+ console.log(chalk_1.default.gray('Dashboard is running. Ctrl+C to stop.\n'));
226
+ break;
227
+ case 'tasks':
228
+ // Inline task list
229
+ require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'list'], { stdio: 'inherit' });
230
+ break;
231
+ case 'status':
232
+ require('child_process').spawnSync(process.execPath, [process.argv[1], 'status'], { stdio: 'inherit' });
233
+ break;
234
+ case 'skills':
235
+ skillList();
236
+ break;
237
+ case 'addtask': {
238
+ const t = yield p({ type: 'text', name: 'title', message: 'Task title:' });
239
+ if (t === null || t === void 0 ? void 0 : t.title) {
240
+ require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'add', t.title], { stdio: 'inherit' });
241
+ }
242
+ break;
243
+ }
244
+ case 'install':
245
+ console.log(chalk_1.default.cyan('Run: npx codymaster add --all\n'));
246
+ break;
247
+ case 'help':
248
+ default:
249
+ console.log(chalk_1.default.white('Usage: cm <command> [options]\n'));
250
+ console.log(chalk_1.default.gray(' cm dashboard Open Mission Control'));
251
+ console.log(chalk_1.default.gray(' cm status Project overview'));
252
+ console.log(chalk_1.default.gray(' cm task add "Title" Add a task'));
253
+ console.log(chalk_1.default.gray(' cm task list View tasks'));
254
+ console.log(chalk_1.default.gray(' cm list Browse 34 skills'));
255
+ console.log(chalk_1.default.gray(' cm deploy staging Record deployment'));
256
+ console.log(chalk_1.default.gray(' npx codymaster add --all Install/update skills\n'));
257
+ }
258
+ });
259
+ }
260
+ // ─── Program ────────────────────────────────────────────────────────────────
261
+ const program = new commander_1.Command();
262
+ program
263
+ .name('cm')
264
+ .description('Cody — 34 Skills. Ship 10x faster.')
265
+ .version(VERSION, '-v, --version', 'Show version')
266
+ .action(() => __awaiter(void 0, void 0, void 0, function* () {
267
+ // Interactive quick menu (Amp-style)
268
+ yield showInteractiveMenu();
269
+ }));
270
+ // ─── Dashboard Command ─────────────────────────────────────────────────────
271
+ program
272
+ .command('dashboard [cmd]')
273
+ .alias('dash')
274
+ .description('Dashboard server (start|stop|status|open)')
275
+ .option('-p, --port <port>', 'Port number', String(data_1.DEFAULT_PORT))
276
+ .action((cmd, opts) => {
277
+ const port = parseInt(opts.port) || data_1.DEFAULT_PORT;
278
+ switch (cmd) {
279
+ case 'start':
280
+ case undefined:
281
+ if (isDashboardRunning()) {
282
+ console.log(chalk_1.default.yellow('⚠️ Dashboard already running.'));
283
+ console.log(chalk_1.default.gray(` URL: http://localhost:${port}`));
284
+ return;
285
+ }
286
+ (0, dashboard_1.launchDashboard)(port);
287
+ break;
288
+ case 'stop':
289
+ stopDashboard();
290
+ break;
291
+ case 'status':
292
+ dashboardStatus(port);
293
+ break;
294
+ case 'open':
295
+ console.log(chalk_1.default.blue(`🌐 Opening http://localhost:${port} ...`));
296
+ openUrl(`http://localhost:${port}`);
297
+ break;
298
+ case 'url':
299
+ console.log(`http://localhost:${port}`);
300
+ break;
301
+ default:
302
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
303
+ console.log(chalk_1.default.gray('Available: start, stop, status, open, url'));
304
+ }
305
+ });
306
+ function isDashboardRunning() {
307
+ try {
308
+ if (!fs_1.default.existsSync(data_1.PID_FILE))
309
+ return false;
310
+ const pid = parseInt(fs_1.default.readFileSync(data_1.PID_FILE, 'utf-8').trim());
311
+ process.kill(pid, 0);
312
+ return true;
313
+ }
314
+ catch (_a) {
315
+ try {
316
+ fs_1.default.unlinkSync(data_1.PID_FILE);
317
+ }
318
+ catch (_b) { }
319
+ return false;
320
+ }
321
+ }
322
+ function stopDashboard() {
323
+ try {
324
+ if (!fs_1.default.existsSync(data_1.PID_FILE)) {
325
+ console.log(chalk_1.default.yellow('⚠️ No dashboard running.'));
326
+ return;
327
+ }
328
+ const pid = parseInt(fs_1.default.readFileSync(data_1.PID_FILE, 'utf-8').trim());
329
+ process.kill(pid, 'SIGTERM');
330
+ try {
331
+ fs_1.default.unlinkSync(data_1.PID_FILE);
332
+ }
333
+ catch (_a) { }
334
+ console.log(chalk_1.default.green(`✅ Dashboard stopped (PID ${pid}).`));
335
+ }
336
+ catch (err) {
337
+ console.log(chalk_1.default.red(`Failed to stop: ${err.message}`));
338
+ try {
339
+ fs_1.default.unlinkSync(data_1.PID_FILE);
340
+ }
341
+ catch (_b) { }
342
+ }
343
+ }
344
+ function dashboardStatus(port) {
345
+ if (isDashboardRunning()) {
346
+ const pid = fs_1.default.readFileSync(data_1.PID_FILE, 'utf-8').trim();
347
+ console.log(chalk_1.default.green(`✅ Dashboard RUNNING`));
348
+ console.log(chalk_1.default.gray(` PID: ${pid}`));
349
+ console.log(chalk_1.default.gray(` URL: http://localhost:${port}`));
350
+ }
351
+ else {
352
+ console.log(chalk_1.default.yellow('⚫ Dashboard NOT running'));
353
+ console.log(chalk_1.default.gray(' Start with: cm dashboard start'));
354
+ }
355
+ }
356
+ // ─── Task Command ───────────────────────────────────────────────────────────
357
+ program
358
+ .command('task <cmd> [args...]')
359
+ .alias('t')
360
+ .description('Task management (add|list|move|done|rm)')
361
+ .option('-p, --project <name>', 'Project name or ID')
362
+ .option('-c, --column <column>', 'Column (backlog|in-progress|review|done)', 'backlog')
363
+ .option('--priority <level>', 'Priority (low|medium|high|urgent)', 'medium')
364
+ .option('--agent <agent>', 'Agent name')
365
+ .option('--skill <skill>', 'Skill name')
366
+ .option('--all', 'Show all projects')
367
+ .option('--force', 'Force re-dispatch')
368
+ .action((cmd, args, opts) => {
369
+ switch (cmd) {
370
+ case 'add':
371
+ taskAdd(args.join(' '), opts);
372
+ break;
373
+ case 'list':
374
+ case 'ls':
375
+ taskList(opts);
376
+ break;
377
+ case 'move':
378
+ taskMove(args[0], args[1]);
379
+ break;
380
+ case 'done':
381
+ taskDone(args[0]);
382
+ break;
383
+ case 'rm':
384
+ case 'delete':
385
+ taskRemove(args[0]);
386
+ break;
387
+ case 'dispatch':
388
+ taskDispatch(args[0], opts);
389
+ break;
390
+ case 'stuck':
391
+ taskStuck(opts);
392
+ break;
393
+ default:
394
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
395
+ console.log(chalk_1.default.gray('Available: add, list, move, done, rm, dispatch, stuck'));
396
+ }
397
+ });
398
+ function taskAdd(title, opts) {
399
+ if (!title) {
400
+ console.log(chalk_1.default.red('❌ Title required. Usage: cm task add "My task"'));
401
+ return;
402
+ }
403
+ const data = (0, data_1.loadData)();
404
+ let projectId;
405
+ if (opts.project) {
406
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
407
+ if (!project) {
408
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
409
+ return;
410
+ }
411
+ projectId = project.id;
412
+ }
413
+ else if (data.projects.length > 0) {
414
+ projectId = data.projects[0].id;
415
+ }
416
+ else {
417
+ const dp = { id: crypto_1.default.randomUUID(), name: 'Default Project', path: process.cwd(), agents: [], createdAt: new Date().toISOString() };
418
+ data.projects.push(dp);
419
+ projectId = dp.id;
420
+ }
421
+ const now = new Date().toISOString();
422
+ const column = opts.column || 'backlog';
423
+ const ct = data.tasks.filter(t => t.column === column && t.projectId === projectId);
424
+ const mo = ct.length > 0 ? Math.max(...ct.map(t => t.order)) : -1;
425
+ const task = { id: crypto_1.default.randomUUID(), projectId: projectId, title: title.trim(), description: '', column, order: mo + 1, priority: opts.priority || 'medium', agent: opts.agent || '', skill: opts.skill || '', createdAt: now, updatedAt: now };
426
+ data.tasks.push(task);
427
+ (0, data_1.logActivity)(data, 'task_created', `Task "${task.title}" created via CLI`, projectId, opts.agent || '');
428
+ (0, data_1.saveData)(data);
429
+ const project = data.projects.find(p => p.id === projectId);
430
+ console.log(chalk_1.default.green(`✅ Task created: ${title}`));
431
+ console.log(chalk_1.default.gray(` ID: ${(0, data_1.shortId)(task.id)} | Project: ${(project === null || project === void 0 ? void 0 : project.name) || 'Default'} | ${column} | ${opts.priority || 'medium'}`));
432
+ }
433
+ function taskList(opts) {
434
+ const data = (0, data_1.loadData)();
435
+ let tasks = data.tasks;
436
+ if (opts.project && !opts.all) {
437
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
438
+ if (!project) {
439
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
440
+ return;
441
+ }
442
+ tasks = tasks.filter(t => t.projectId === project.id);
443
+ console.log(chalk_1.default.cyan(`\n📋 Tasks — ${project.name}\n`));
444
+ }
445
+ else {
446
+ console.log(chalk_1.default.cyan('\n📋 All Tasks\n'));
447
+ }
448
+ if (tasks.length === 0) {
449
+ console.log(chalk_1.default.gray(' No tasks found.\n'));
450
+ return;
451
+ }
452
+ console.log(chalk_1.default.gray(' ' + padRight('ID', 10) + padRight('Title', 36) + padRight('Column', 14) + padRight('Priority', 10) + padRight('Agent', 14) + 'Project'));
453
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(100)));
454
+ const co = ['backlog', 'in-progress', 'review', 'done'];
455
+ tasks.sort((a, b) => co.indexOf(a.column) - co.indexOf(b.column) || a.order - b.order);
456
+ for (const task of tasks) {
457
+ const cc = COL_COLORS[task.column] || chalk_1.default.white;
458
+ const pc = PRIORITY_COLORS[task.priority] || chalk_1.default.white;
459
+ const project = data.projects.find(p => p.id === task.projectId);
460
+ console.log(' ' + chalk_1.default.gray(padRight((0, data_1.shortId)(task.id), 10)) + padRight(task.title.substring(0, 34), 36) + cc(padRight(task.column, 14)) + pc(padRight(task.priority, 10)) + chalk_1.default.gray(padRight(task.agent || '—', 14)) + chalk_1.default.gray((project === null || project === void 0 ? void 0 : project.name) || '—'));
461
+ }
462
+ console.log(chalk_1.default.gray(`\n Total: ${tasks.length} tasks\n`));
463
+ }
464
+ function taskMove(idPrefix, targetColumn) {
465
+ if (!idPrefix || !targetColumn) {
466
+ console.log(chalk_1.default.red('❌ Usage: cm task move <id> <column>'));
467
+ return;
468
+ }
469
+ const vc = ['backlog', 'in-progress', 'review', 'done'];
470
+ if (!vc.includes(targetColumn)) {
471
+ console.log(chalk_1.default.red(`❌ Invalid column: ${targetColumn}. Valid: ${vc.join(', ')}`));
472
+ return;
473
+ }
474
+ const data = (0, data_1.loadData)();
475
+ const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
476
+ if (!task) {
477
+ console.log(chalk_1.default.red(`❌ Task not found: ${idPrefix}`));
478
+ return;
479
+ }
480
+ const oldCol = task.column;
481
+ // Validate transition
482
+ const VALID_TRANSITIONS = {
483
+ 'backlog': ['in-progress'],
484
+ 'in-progress': ['review', 'done', 'backlog'],
485
+ 'review': ['done', 'in-progress'],
486
+ 'done': ['backlog'],
487
+ };
488
+ const allowed = VALID_TRANSITIONS[oldCol] || [];
489
+ if (oldCol !== targetColumn && !allowed.includes(targetColumn)) {
490
+ console.log(chalk_1.default.red(`❌ Invalid transition: ${oldCol} → ${targetColumn}`));
491
+ console.log(chalk_1.default.gray(` Allowed transitions: ${allowed.join(', ')}`));
492
+ return;
493
+ }
494
+ if (oldCol === targetColumn) {
495
+ console.log(chalk_1.default.gray(` Task already in ${targetColumn}.`));
496
+ return;
497
+ }
498
+ task.column = targetColumn;
499
+ task.updatedAt = new Date().toISOString();
500
+ task.stuckSince = undefined;
501
+ (0, data_1.logActivity)(data, targetColumn === 'done' ? 'task_done' : 'task_transitioned', `Task "${task.title}" moved: ${oldCol} → ${targetColumn} (CLI)`, task.projectId, task.agent, { from: oldCol, to: targetColumn });
502
+ (0, data_1.saveData)(data);
503
+ console.log(chalk_1.default.green(`✅ Moved "${task.title}"`));
504
+ console.log(chalk_1.default.gray(` ${oldCol} → `) + (COL_COLORS[targetColumn] || chalk_1.default.white)(targetColumn));
505
+ }
506
+ function taskStuck(opts) {
507
+ const data = (0, data_1.loadData)();
508
+ const thresholdMin = 30;
509
+ const now = Date.now();
510
+ let tasks = data.tasks.filter(t => t.column === 'in-progress');
511
+ if (opts.project) {
512
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
513
+ if (!project) {
514
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
515
+ return;
516
+ }
517
+ tasks = tasks.filter(t => t.projectId === project.id);
518
+ }
519
+ const stuck = tasks.filter(t => {
520
+ const elapsed = now - new Date(t.updatedAt).getTime();
521
+ return elapsed > thresholdMin * 60 * 1000;
522
+ }).sort((a, b) => new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime());
523
+ if (stuck.length === 0) {
524
+ console.log(chalk_1.default.green(`\n ✅ No stuck tasks! All in-progress tasks updated within ${thresholdMin}m.\n`));
525
+ return;
526
+ }
527
+ console.log(chalk_1.default.yellow(`\n⚠️ ${stuck.length} Stuck Tasks (>${thresholdMin}m in progress)\n`));
528
+ console.log(chalk_1.default.gray(' ' + padRight('ID', 10) + padRight('Title', 36) + padRight('Stuck For', 12) + padRight('Agent', 14) + 'Priority'));
529
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(86)));
530
+ for (const task of stuck) {
531
+ const elapsed = now - new Date(task.updatedAt).getTime();
532
+ const minutes = Math.round(elapsed / 60000);
533
+ const timeStr = minutes < 60 ? `${minutes}m` : `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
534
+ const project = data.projects.find(p => p.id === task.projectId);
535
+ const pc = PRIORITY_COLORS[task.priority] || chalk_1.default.white;
536
+ console.log(' ' + chalk_1.default.gray(padRight((0, data_1.shortId)(task.id), 10)) + padRight(task.title.substring(0, 34), 36) + chalk_1.default.yellow(padRight(timeStr, 12)) + chalk_1.default.gray(padRight(task.agent || '—', 14)) + pc(task.priority));
537
+ }
538
+ console.log();
539
+ console.log(chalk_1.default.gray(' Tip: Move tasks with: cm task move <id> review|done|backlog'));
540
+ console.log();
541
+ }
542
+ function taskDone(idPrefix) {
543
+ if (!idPrefix) {
544
+ console.log(chalk_1.default.red('❌ Usage: cm task done <id>'));
545
+ return;
546
+ }
547
+ taskMove(idPrefix, 'done');
548
+ }
549
+ function taskRemove(idPrefix) {
550
+ if (!idPrefix) {
551
+ console.log(chalk_1.default.red('❌ Usage: cm task rm <id>'));
552
+ return;
553
+ }
554
+ const data = (0, data_1.loadData)();
555
+ const idx = data.tasks.findIndex(t => t.id === idPrefix || t.id.startsWith(idPrefix));
556
+ if (idx === -1) {
557
+ console.log(chalk_1.default.red(`❌ Task not found: ${idPrefix}`));
558
+ return;
559
+ }
560
+ const [removed] = data.tasks.splice(idx, 1);
561
+ (0, data_1.logActivity)(data, 'task_deleted', `Task "${removed.title}" deleted via CLI`, removed.projectId, removed.agent);
562
+ (0, data_1.saveData)(data);
563
+ console.log(chalk_1.default.green(`✅ Deleted: "${removed.title}" (${(0, data_1.shortId)(removed.id)})`));
564
+ }
565
+ function taskDispatch(idPrefix, opts) {
566
+ if (!idPrefix) {
567
+ console.log(chalk_1.default.red('❌ Usage: cm task dispatch <id> [--force]'));
568
+ return;
569
+ }
570
+ const data = (0, data_1.loadData)();
571
+ const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
572
+ if (!task) {
573
+ console.log(chalk_1.default.red(`❌ Task not found: ${idPrefix}`));
574
+ return;
575
+ }
576
+ const project = data.projects.find(p => p.id === task.projectId);
577
+ const result = (0, agent_dispatch_1.dispatchTaskToAgent)(task, project, opts.force || false);
578
+ if (result.success) {
579
+ task.dispatchStatus = 'dispatched';
580
+ task.dispatchedAt = new Date().toISOString();
581
+ task.dispatchError = undefined;
582
+ task.updatedAt = task.dispatchedAt;
583
+ (0, data_1.logActivity)(data, 'task_dispatched', `Task "${task.title}" dispatched to ${task.agent} via CLI`, task.projectId, task.agent, {
584
+ taskId: task.id, filePath: result.filePath, force: opts.force || false,
585
+ });
586
+ (0, data_1.saveData)(data);
587
+ console.log(chalk_1.default.green(`\n🚀 Task dispatched to ${task.agent}!`));
588
+ console.log(chalk_1.default.gray(` Task: ${task.title}`));
589
+ console.log(chalk_1.default.gray(` Agent: ${task.agent}`));
590
+ if (task.skill)
591
+ console.log(chalk_1.default.gray(` Skill: ${task.skill}`));
592
+ console.log(chalk_1.default.gray(` File: ${result.filePath}`));
593
+ console.log();
594
+ }
595
+ else {
596
+ task.dispatchStatus = 'failed';
597
+ task.dispatchError = result.error;
598
+ task.updatedAt = new Date().toISOString();
599
+ (0, data_1.saveData)(data);
600
+ console.log(chalk_1.default.red(`❌ Dispatch failed: ${result.error}`));
601
+ }
602
+ }
603
+ // ─── Project Command ────────────────────────────────────────────────────────
604
+ program
605
+ .command('project <cmd> [args...]')
606
+ .alias('p')
607
+ .description('Project management (add|list|rm)')
608
+ .option('--path <path>', 'Workspace path')
609
+ .action((cmd, args, opts) => {
610
+ switch (cmd) {
611
+ case 'add':
612
+ projectAdd(args.join(' '), opts);
613
+ break;
614
+ case 'list':
615
+ case 'ls':
616
+ projectList();
617
+ break;
618
+ case 'rm':
619
+ case 'delete':
620
+ projectRemove(args[0]);
621
+ break;
622
+ default:
623
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
624
+ console.log(chalk_1.default.gray('Available: add, list, rm'));
625
+ }
626
+ });
627
+ function projectAdd(name, opts) {
628
+ if (!name) {
629
+ console.log(chalk_1.default.red('❌ Usage: cm project add "my-project"'));
630
+ return;
631
+ }
632
+ const data = (0, data_1.loadData)();
633
+ const project = { id: crypto_1.default.randomUUID(), name: name.trim(), path: opts.path || process.cwd(), agents: [], createdAt: new Date().toISOString() };
634
+ data.projects.push(project);
635
+ (0, data_1.logActivity)(data, 'project_created', `Project "${project.name}" created via CLI`, project.id);
636
+ (0, data_1.saveData)(data);
637
+ console.log(chalk_1.default.green(`✅ Project created: ${name}`));
638
+ console.log(chalk_1.default.gray(` ID: ${(0, data_1.shortId)(project.id)} | Path: ${project.path}`));
639
+ }
640
+ function projectList() {
641
+ const data = (0, data_1.loadData)();
642
+ if (data.projects.length === 0) {
643
+ console.log(chalk_1.default.gray('\n No projects.\n'));
644
+ return;
645
+ }
646
+ console.log(chalk_1.default.cyan('\n📦 Projects\n'));
647
+ console.log(chalk_1.default.gray(' ' + padRight('ID', 10) + padRight('Name', 24) + padRight('Tasks', 8) + padRight('Agents', 20) + 'Path'));
648
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(90)));
649
+ for (const project of data.projects) {
650
+ const pt = data.tasks.filter(t => t.projectId === project.id);
651
+ const agents = [...new Set(pt.map(t => t.agent).filter(Boolean))];
652
+ const done = pt.filter(t => t.column === 'done').length;
653
+ console.log(' ' + chalk_1.default.gray(padRight((0, data_1.shortId)(project.id), 10)) + chalk_1.default.white(padRight(project.name, 24)) + chalk_1.default.gray(padRight(`${done}/${pt.length}`, 8)) + chalk_1.default.gray(padRight(agents.join(', ') || '—', 20)) + chalk_1.default.gray(project.path || '—'));
654
+ }
655
+ console.log();
656
+ }
657
+ function projectRemove(query) {
658
+ if (!query) {
659
+ console.log(chalk_1.default.red('❌ Usage: cm project rm <name-or-id>'));
660
+ return;
661
+ }
662
+ const data = (0, data_1.loadData)();
663
+ const project = (0, data_1.findProjectByNameOrId)(data, query);
664
+ if (!project) {
665
+ console.log(chalk_1.default.red(`❌ Project not found: ${query}`));
666
+ return;
667
+ }
668
+ const tc = data.tasks.filter(t => t.projectId === project.id).length;
669
+ data.projects = data.projects.filter(p => p.id !== project.id);
670
+ data.tasks = data.tasks.filter(t => t.projectId !== project.id);
671
+ (0, data_1.logActivity)(data, 'project_deleted', `Project "${project.name}" deleted via CLI`, project.id);
672
+ (0, data_1.saveData)(data);
673
+ console.log(chalk_1.default.green(`✅ Deleted project "${project.name}" and ${tc} tasks.`));
674
+ }
675
+ // ─── Deploy Command ─────────────────────────────────────────────────────────
676
+ program
677
+ .command('deploy <cmd> [args...]')
678
+ .alias('d')
679
+ .description('Deploy management (staging|production|list)')
680
+ .option('-p, --project <name>', 'Project name or ID')
681
+ .option('-m, --message <msg>', 'Deploy message')
682
+ .option('--commit <hash>', 'Git commit hash')
683
+ .option('--branch <branch>', 'Git branch', 'main')
684
+ .option('--agent <agent>', 'Agent name')
685
+ .action((cmd, args, opts) => {
686
+ switch (cmd) {
687
+ case 'staging':
688
+ deployRecord('staging', opts);
689
+ break;
690
+ case 'production':
691
+ case 'prod':
692
+ deployRecord('production', opts);
693
+ break;
694
+ case 'list':
695
+ case 'ls':
696
+ deployList(opts);
697
+ break;
698
+ default:
699
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
700
+ console.log(chalk_1.default.gray('Available: staging, production, list'));
701
+ }
702
+ });
703
+ function deployRecord(env, opts) {
704
+ const data = (0, data_1.loadData)();
705
+ let projectId;
706
+ if (opts.project) {
707
+ const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
708
+ if (!p) {
709
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
710
+ return;
711
+ }
712
+ projectId = p.id;
713
+ }
714
+ else if (data.projects.length > 0) {
715
+ projectId = data.projects[0].id;
716
+ }
717
+ else {
718
+ console.log(chalk_1.default.red('❌ No projects. Create one first: cm project add "my-project"'));
719
+ return;
720
+ }
721
+ const now = new Date().toISOString();
722
+ const dep = {
723
+ id: crypto_1.default.randomUUID(), projectId: projectId, env, status: 'success',
724
+ commit: opts.commit || '', branch: opts.branch || 'main',
725
+ agent: opts.agent || '', message: opts.message || `Deploy to ${env}`,
726
+ startedAt: now, finishedAt: now,
727
+ };
728
+ data.deployments.unshift(dep);
729
+ (0, data_1.logActivity)(data, env === 'staging' ? 'deploy_staging' : 'deploy_production', `Deployed to ${env}: ${dep.message}`, projectId, opts.agent || '', { deploymentId: dep.id });
730
+ (0, data_1.saveData)(data);
731
+ const envColor = env === 'production' ? chalk_1.default.green : chalk_1.default.yellow;
732
+ const project = data.projects.find(p => p.id === projectId);
733
+ console.log(chalk_1.default.green(`\n🚀 Deployment recorded!`));
734
+ console.log(chalk_1.default.gray(` ID: ${(0, data_1.shortId)(dep.id)}`));
735
+ console.log(` Env: ${envColor(env)}`);
736
+ console.log(chalk_1.default.gray(` Project: ${(project === null || project === void 0 ? void 0 : project.name) || '—'}`));
737
+ console.log(chalk_1.default.gray(` Message: ${dep.message}`));
738
+ if (dep.commit)
739
+ console.log(chalk_1.default.gray(` Commit: ${dep.commit}`));
740
+ console.log(chalk_1.default.gray(` Branch: ${dep.branch}`));
741
+ console.log();
742
+ }
743
+ function deployList(opts) {
744
+ const data = (0, data_1.loadData)();
745
+ let deps = data.deployments;
746
+ if (opts.project) {
747
+ const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
748
+ if (!p) {
749
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
750
+ return;
751
+ }
752
+ deps = deps.filter(d => d.projectId === p.id);
753
+ }
754
+ if (deps.length === 0) {
755
+ console.log(chalk_1.default.gray('\n No deployments yet.\n'));
756
+ return;
757
+ }
758
+ console.log(chalk_1.default.cyan('\n🚀 Deployment History\n'));
759
+ console.log(chalk_1.default.gray(' ' + padRight('ID', 10) + padRight('Env', 12) + padRight('Status', 14) + padRight('Message', 32) + padRight('Branch', 12) + 'Time'));
760
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(100)));
761
+ for (const dep of deps.slice(0, 20)) {
762
+ const sc = STATUS_COLORS[dep.status] || chalk_1.default.white;
763
+ const ec = dep.env === 'production' ? chalk_1.default.green : chalk_1.default.yellow;
764
+ const timeAgo = formatTimeAgoCli(dep.startedAt);
765
+ const rollbackFlag = dep.rollbackOf ? ' ⏪' : '';
766
+ console.log(' ' + chalk_1.default.gray(padRight((0, data_1.shortId)(dep.id), 10)) + ec(padRight(dep.env, 12)) + sc(padRight(dep.status.replace('_', ' ') + rollbackFlag, 14)) + padRight(dep.message.substring(0, 30), 32) + chalk_1.default.gray(padRight(dep.branch || '—', 12)) + chalk_1.default.gray(timeAgo));
767
+ }
768
+ console.log(chalk_1.default.gray(`\n Total: ${deps.length} deployments\n`));
769
+ }
770
+ // ─── Rollback Command ───────────────────────────────────────────────────────
771
+ program
772
+ .command('rollback <deployId>')
773
+ .alias('rb')
774
+ .description('Rollback a deployment')
775
+ .option('--agent <agent>', 'Agent name')
776
+ .action((deployId, opts) => {
777
+ const data = (0, data_1.loadData)();
778
+ const dep = data.deployments.find(d => d.id === deployId || d.id.startsWith(deployId));
779
+ if (!dep) {
780
+ console.log(chalk_1.default.red(`❌ Deployment not found: ${deployId}`));
781
+ return;
782
+ }
783
+ if (dep.status === 'rolled_back') {
784
+ console.log(chalk_1.default.yellow('⚠️ Already rolled back.'));
785
+ return;
786
+ }
787
+ dep.status = 'rolled_back';
788
+ const now = new Date().toISOString();
789
+ const rollback = {
790
+ id: crypto_1.default.randomUUID(), projectId: dep.projectId, env: dep.env, status: 'success',
791
+ commit: '', branch: dep.branch, agent: opts.agent || '', message: `Rollback of ${(0, data_1.shortId)(dep.id)}`,
792
+ startedAt: now, finishedAt: now, rollbackOf: dep.id,
793
+ };
794
+ data.deployments.unshift(rollback);
795
+ (0, data_1.logActivity)(data, 'rollback', `Rolled back ${dep.env} deploy: ${dep.message}`, dep.projectId, opts.agent || '', { originalDeployId: dep.id, rollbackId: rollback.id });
796
+ (0, data_1.saveData)(data);
797
+ console.log(chalk_1.default.magenta(`\n⏪ Rollback complete!`));
798
+ console.log(chalk_1.default.gray(` Original deploy: ${(0, data_1.shortId)(dep.id)} (${dep.env})`));
799
+ console.log(chalk_1.default.gray(` Rollback ID: ${(0, data_1.shortId)(rollback.id)}`));
800
+ console.log(chalk_1.default.gray(` Status: ${dep.message} → rolled back\n`));
801
+ });
802
+ // ─── History Command ────────────────────────────────────────────────────────
803
+ program
804
+ .command('history')
805
+ .alias('h')
806
+ .description('Show activity history')
807
+ .option('-n, --limit <n>', 'Number of entries', '20')
808
+ .option('-p, --project <name>', 'Filter by project')
809
+ .action((opts) => {
810
+ const data = (0, data_1.loadData)();
811
+ let acts = data.activities;
812
+ if (opts.project) {
813
+ const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
814
+ if (!p) {
815
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
816
+ return;
817
+ }
818
+ acts = acts.filter(a => a.projectId === p.id);
819
+ }
820
+ const limit = parseInt(opts.limit) || 20;
821
+ acts = acts.slice(0, limit);
822
+ if (acts.length === 0) {
823
+ console.log(chalk_1.default.gray('\n No activity yet.\n'));
824
+ return;
825
+ }
826
+ const ICONS = {
827
+ 'task_created': '✨', 'task_moved': '↔️', 'task_done': '✅', 'task_deleted': '🗑️', 'task_updated': '✏️',
828
+ 'project_created': '📦', 'project_deleted': '🗑️',
829
+ 'deploy_staging': '🟡', 'deploy_production': '🚀', 'deploy_failed': '❌', 'rollback': '⏪',
830
+ 'git_push': '📤', 'changelog_added': '📝',
831
+ };
832
+ console.log(chalk_1.default.cyan(`\n📜 Activity History (latest ${acts.length})\n`));
833
+ for (const a of acts) {
834
+ const icon = ICONS[a.type] || '📌';
835
+ const proj = data.projects.find(p => p.id === a.projectId);
836
+ const projTag = proj ? chalk_1.default.gray(` [${proj.name}]`) : '';
837
+ const agentTag = a.agent ? chalk_1.default.gray(` @${a.agent}`) : '';
838
+ const time = formatTimeAgoCli(a.createdAt);
839
+ console.log(` ${icon} ${a.message}${projTag}${agentTag} ${chalk_1.default.gray(`← ${time}`)}`);
840
+ }
841
+ console.log();
842
+ });
843
+ // ─── Changelog Command ─────────────────────────────────────────────────────
844
+ program
845
+ .command('changelog <cmd> [args...]')
846
+ .alias('cl')
847
+ .description('Changelog management (add|list)')
848
+ .option('-p, --project <name>', 'Project name or ID')
849
+ .option('--agent <agent>', 'Agent name')
850
+ .action((cmd, args, opts) => {
851
+ switch (cmd) {
852
+ case 'add':
853
+ changelogAdd(args, opts);
854
+ break;
855
+ case 'list':
856
+ case 'ls':
857
+ changelogList(opts);
858
+ break;
859
+ default:
860
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
861
+ console.log(chalk_1.default.gray('Available: add, list'));
862
+ }
863
+ });
864
+ function changelogAdd(args, opts) {
865
+ if (args.length < 2) {
866
+ console.log(chalk_1.default.red('❌ Usage: cm changelog add <version> "<title>" [changes...]'));
867
+ return;
868
+ }
869
+ const data = (0, data_1.loadData)();
870
+ let projectId = '';
871
+ if (opts.project) {
872
+ const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
873
+ if (!p) {
874
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
875
+ return;
876
+ }
877
+ projectId = p.id;
878
+ }
879
+ else if (data.projects.length > 0) {
880
+ projectId = data.projects[0].id;
881
+ }
882
+ const version = args[0];
883
+ const title = args[1];
884
+ const changes = args.slice(2);
885
+ const entry = {
886
+ id: crypto_1.default.randomUUID(), projectId, version, title, changes,
887
+ agent: opts.agent || '', createdAt: new Date().toISOString(),
888
+ };
889
+ data.changelog.unshift(entry);
890
+ (0, data_1.logActivity)(data, 'changelog_added', `Changelog ${version}: ${title}`, projectId, opts.agent || '');
891
+ (0, data_1.saveData)(data);
892
+ console.log(chalk_1.default.green(`\n📝 Changelog entry added!`));
893
+ console.log(chalk_1.default.gray(` Version: ${version}`));
894
+ console.log(chalk_1.default.gray(` Title: ${title}`));
895
+ if (changes.length > 0) {
896
+ changes.forEach(c => console.log(chalk_1.default.gray(` • ${c}`)));
897
+ }
898
+ console.log();
899
+ }
900
+ function changelogList(opts) {
901
+ const data = (0, data_1.loadData)();
902
+ let entries = data.changelog;
903
+ if (opts.project) {
904
+ const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
905
+ if (!p) {
906
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
907
+ return;
908
+ }
909
+ entries = entries.filter(c => c.projectId === p.id);
910
+ }
911
+ if (entries.length === 0) {
912
+ console.log(chalk_1.default.gray('\n No changelog entries.\n'));
913
+ return;
914
+ }
915
+ console.log(chalk_1.default.cyan('\n📝 Changelog\n'));
916
+ for (const entry of entries) {
917
+ const proj = data.projects.find(p => p.id === entry.projectId);
918
+ console.log(chalk_1.default.blue(` ${entry.version}`) + chalk_1.default.white(` — ${entry.title}`) + chalk_1.default.gray(` (${formatTimeAgoCli(entry.createdAt)})${proj ? ' [' + proj.name + ']' : ''}`));
919
+ if (entry.changes.length > 0) {
920
+ entry.changes.forEach(c => console.log(chalk_1.default.gray(` • ${c}`)));
921
+ }
922
+ }
923
+ console.log();
924
+ }
925
+ // ─── Status Command ─────────────────────────────────────────────────────────
926
+ program
927
+ .command('status')
928
+ .alias('s')
929
+ .description('Show task & project summary')
930
+ .action(() => {
931
+ const data = (0, data_1.loadData)();
932
+ showBanner();
933
+ console.log(chalk_1.default.white('📊 Status Overview\n'));
934
+ // Projects
935
+ console.log(chalk_1.default.cyan(` Projects: ${data.projects.length}`));
936
+ for (const p of data.projects) {
937
+ const pt = data.tasks.filter(t => t.projectId === p.id);
938
+ const done = pt.filter(t => t.column === 'done').length;
939
+ const pct = pt.length > 0 ? Math.round((done / pt.length) * 100) : 0;
940
+ console.log(chalk_1.default.gray(` 📦 ${padRight(p.name, 20)} ${progressBar(pct)} ${done}/${pt.length} (${pct}%)`));
941
+ }
942
+ // Tasks
943
+ const total = data.tasks.length;
944
+ const byCol = { backlog: 0, 'in-progress': 0, review: 0, done: 0 };
945
+ data.tasks.forEach(t => { byCol[t.column] = (byCol[t.column] || 0) + 1; });
946
+ console.log();
947
+ console.log(chalk_1.default.white(` Tasks: ${total}`));
948
+ console.log(chalk_1.default.gray(` ⚪ Backlog: ${byCol.backlog}`));
949
+ console.log(chalk_1.default.blue(` 🔵 In Progress: ${byCol['in-progress']}`));
950
+ console.log(chalk_1.default.yellow(` 🟡 Review: ${byCol.review}`));
951
+ console.log(chalk_1.default.green(` 🟢 Done: ${byCol.done}`));
952
+ // Deploys
953
+ if (data.deployments.length > 0) {
954
+ console.log();
955
+ console.log(chalk_1.default.white(` Deployments: ${data.deployments.length}`));
956
+ const latest = data.deployments[0];
957
+ const sc = STATUS_COLORS[latest.status] || chalk_1.default.white;
958
+ console.log(chalk_1.default.gray(` Latest: ${latest.env} — ${sc(latest.status)} — ${latest.message} (${formatTimeAgoCli(latest.startedAt)})`));
959
+ }
960
+ // Agents
961
+ const agentCounts = {};
962
+ data.tasks.forEach(t => { if (t.agent)
963
+ agentCounts[t.agent] = (agentCounts[t.agent] || 0) + 1; });
964
+ const agentNames = Object.keys(agentCounts);
965
+ if (agentNames.length > 0) {
966
+ console.log();
967
+ console.log(chalk_1.default.white(` Active Agents: ${agentNames.length}`));
968
+ for (const agent of agentNames.sort()) {
969
+ console.log(chalk_1.default.gray(` 🤖 ${padRight(agent, 16)} ${agentCounts[agent]} tasks`));
970
+ }
971
+ }
972
+ // Dashboard
973
+ console.log();
974
+ if (isDashboardRunning()) {
975
+ console.log(chalk_1.default.green(` 🚀 Dashboard: RUNNING at http://codymaster.localhost:${data_1.DEFAULT_PORT}`));
976
+ }
977
+ else {
978
+ console.log(chalk_1.default.gray(` ⚫ Dashboard: not running (start with: cm dashboard)`));
979
+ }
980
+ console.log();
981
+ });
982
+ function progressBar(pct) {
983
+ const total = 12;
984
+ const filled = Math.round((pct / 100) * total);
985
+ return chalk_1.default.green('█'.repeat(filled)) + chalk_1.default.gray('░'.repeat(total - filled));
986
+ }
987
+ function formatTimeAgoCli(dateStr) {
988
+ const ms = Date.now() - new Date(dateStr).getTime();
989
+ const m = Math.floor(ms / 60000), h = Math.floor(ms / 3600000), d = Math.floor(ms / 86400000);
990
+ if (m < 1)
991
+ return 'just now';
992
+ if (m < 60)
993
+ return `${m}m ago`;
994
+ if (h < 24)
995
+ return `${h}h ago`;
996
+ if (d < 7)
997
+ return `${d}d ago`;
998
+ return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
999
+ }
1000
+ // ─── Install Command ────────────────────────────────────────────────────────
1001
+ program
1002
+ .command('install <skill>')
1003
+ .description('Install an agent skill')
1004
+ .option('-p, --platform <platform>', 'Target platform (gemini|claude|cursor|windsurf|cline)')
1005
+ .action((skill, opts) => __awaiter(void 0, void 0, void 0, function* () {
1006
+ console.log(chalk_1.default.blue(`Installing skill: ${skill}...`));
1007
+ if (!opts.platform) {
1008
+ const prompts = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
1009
+ const response = yield prompts({
1010
+ type: 'select', name: 'platform', message: 'Which platform?',
1011
+ choices: [
1012
+ { title: 'Google Antigravity', value: 'gemini' },
1013
+ { title: 'Claude Code', value: 'claude' },
1014
+ { title: 'Cursor', value: 'cursor' },
1015
+ { title: 'Windsurf', value: 'windsurf' },
1016
+ { title: 'Cline / RooCode', value: 'cline' },
1017
+ ]
1018
+ });
1019
+ opts.platform = response.platform;
1020
+ }
1021
+ console.log(chalk_1.default.green(`\n✅ Skill '${skill}' installed for ${opts.platform}!`));
1022
+ }));
1023
+ // ─── Add Command (npx codymaster add --skill cm-debugging) ───────────────────
1024
+ const ALL_SKILLS = [
1025
+ // Engineering
1026
+ 'cm-tdd', 'cm-debugging', 'cm-quality-gate', 'cm-test-gate', 'cm-code-review',
1027
+ // Operations
1028
+ 'cm-safe-deploy', 'cm-identity-guard', 'cm-git-worktrees', 'cm-terminal', 'cm-secret-shield', 'cm-safe-i18n',
1029
+ // Product
1030
+ 'cm-planning', 'cm-ux-master', 'cm-ui-preview', 'cm-brainstorm-idea', 'cm-jtbd', 'cm-dockit', 'cm-project-bootstrap', 'cm-readit',
1031
+ // Growth
1032
+ 'cm-content-factory', 'cm-ads-tracker', 'cro-methodology', 'cm-deep-search',
1033
+ // Orchestration
1034
+ 'cm-execution', 'cm-continuity', 'cm-skill-index', 'cm-skill-mastery', 'cm-skill-chain',
1035
+ // Workflow
1036
+ 'cm-start', 'cm-dashboard', 'cm-status', 'cm-how-it-work', 'cm-example',
1037
+ ];
1038
+ const PLATFORM_TARGETS = {
1039
+ gemini: { dir: '.gemini/skills', invoke: '@[/<skill>]', note: 'or ~/.gemini/antigravity/skills/ for global' },
1040
+ cursor: { dir: '.cursor/rules', invoke: '@<skill>', note: 'Cursor rules directory' },
1041
+ windsurf: { dir: '.windsurf/rules', invoke: '@<skill>', note: 'Windsurf rules directory' },
1042
+ cline: { dir: '.cline/skills', invoke: '@<skill>', note: 'Cline / RooCode skills directory' },
1043
+ opencode: { dir: '.opencode/skills', invoke: '@[/<skill>]', note: 'OpenCode skills directory' },
1044
+ kiro: { dir: '.kiro/steering', invoke: '@<skill>', note: 'Kiro steering documents' },
1045
+ copilot: { dir: '.github', invoke: '(auto-context)', note: 'Added to copilot-instructions.md' },
1046
+ };
1047
+ const RAW_BASE = 'https://raw.githubusercontent.com/tody-agent/codymaster/main';
1048
+ function autoDetectPlatform() {
1049
+ const { execFileSync } = require('child_process');
1050
+ try {
1051
+ execFileSync('claude', ['--version'], { stdio: 'pipe' });
1052
+ return 'claude';
1053
+ }
1054
+ catch (_a) { }
1055
+ try {
1056
+ execFileSync('gemini', ['--version'], { stdio: 'pipe' });
1057
+ return 'gemini';
1058
+ }
1059
+ catch (_b) { }
1060
+ if (fs_1.default.existsSync(path_1.default.join(os_1.default.homedir(), '.cursor')))
1061
+ return 'cursor';
1062
+ if (fs_1.default.existsSync(path_1.default.join(os_1.default.homedir(), '.windsurf')))
1063
+ return 'windsurf';
1064
+ return 'manual';
1065
+ }
1066
+ function downloadFile(url, dest) {
1067
+ return new Promise((resolve) => {
1068
+ try {
1069
+ fs_1.default.mkdirSync(path_1.default.dirname(dest), { recursive: true });
1070
+ const file = fs_1.default.createWriteStream(dest);
1071
+ https_1.default.get(url, (res) => {
1072
+ if (res.statusCode !== 200) {
1073
+ file.close();
1074
+ try {
1075
+ fs_1.default.unlinkSync(dest);
1076
+ }
1077
+ catch (_a) { }
1078
+ resolve(false);
1079
+ return;
1080
+ }
1081
+ res.pipe(file);
1082
+ file.on('finish', () => { file.close(); resolve(true); });
1083
+ }).on('error', () => { file.close(); resolve(false); });
1084
+ }
1085
+ catch (_a) {
1086
+ resolve(false);
1087
+ }
1088
+ });
1089
+ }
1090
+ function doAddSkills(skills, platform) {
1091
+ return __awaiter(this, void 0, void 0, function* () {
1092
+ console.log();
1093
+ const { execFileSync } = require('child_process');
1094
+ if (platform === 'claude') {
1095
+ console.log(chalk_1.default.magenta('🟣 Claude Code — Installing via plugin system'));
1096
+ console.log(chalk_1.default.gray(' (Claude installs all 34 skills as one bundle)\n'));
1097
+ // Step 1: Register marketplace — "already installed" is OK, just continue
1098
+ console.log(chalk_1.default.gray(' $ claude plugin marketplace add tody-agent/codymaster'));
1099
+ try {
1100
+ // Use 'pipe' so we can inspect output on failure; print stdout ourselves
1101
+ const r1 = require('child_process').spawnSync('claude', ['plugin', 'marketplace', 'add', 'tody-agent/codymaster'], { encoding: 'utf8' });
1102
+ if (r1.stdout)
1103
+ process.stdout.write(r1.stdout);
1104
+ if (r1.stderr)
1105
+ process.stderr.write(r1.stderr);
1106
+ const combined = String(r1.stdout || '') + String(r1.stderr || '');
1107
+ if (r1.status !== 0 && !combined.includes('already installed') && !combined.includes('already exists')) {
1108
+ console.log(chalk_1.default.yellow(' ⚠️ Marketplace warning — continuing anyway'));
1109
+ }
1110
+ else if (combined.includes('already installed') || combined.includes('already exists')) {
1111
+ console.log(chalk_1.default.gray(' ℹ️ Marketplace already registered'));
1112
+ }
1113
+ }
1114
+ catch (_a) {
1115
+ console.log(chalk_1.default.yellow(' ⚠️ Could not reach marketplace — continuing'));
1116
+ }
1117
+ // Step 2: Install / update the plugin
1118
+ console.log(chalk_1.default.gray(' $ claude plugin install codymaster@codymaster'));
1119
+ try {
1120
+ execFileSync('claude', ['plugin', 'install', 'codymaster@codymaster'], { stdio: 'inherit' });
1121
+ console.log('\n' + chalk_1.default.green('✅ All 34 skills installed!'));
1122
+ yield postInstallOnboarding('claude');
1123
+ }
1124
+ catch (_b) {
1125
+ console.log(chalk_1.default.yellow('\n⚠️ Plugin install failed. Run manually:\n'));
1126
+ console.log(chalk_1.default.cyan(' claude plugin install codymaster@codymaster'));
1127
+ console.log(chalk_1.default.gray('\n Or one-liner:'));
1128
+ console.log(chalk_1.default.cyan(' bash <(curl -fsSL https://raw.githubusercontent.com/tody-agent/codymaster/main/install.sh) --claude'));
1129
+ }
1130
+ return;
1131
+ }
1132
+ if (platform === 'gemini') {
1133
+ console.log(chalk_1.default.cyan('💻 Gemini CLI — Installing via extensions'));
1134
+ try {
1135
+ execFileSync('gemini', ['extensions', 'install', 'https://github.com/tody-agent/codymaster'], { stdio: 'inherit' });
1136
+ console.log('\n' + chalk_1.default.green('✅ All 34 skills installed for Gemini CLI!'));
1137
+ yield postInstallOnboarding('gemini');
1138
+ }
1139
+ catch (_c) {
1140
+ console.log(chalk_1.default.yellow('💡 Run this in your terminal:\n'));
1141
+ console.log(chalk_1.default.cyan(' gemini extensions install https://github.com/tody-agent/codymaster\n'));
1142
+ }
1143
+ return;
1144
+ }
1145
+ const target = PLATFORM_TARGETS[platform];
1146
+ if (!target) {
1147
+ console.log(chalk_1.default.red(`❌ Unknown platform: ${platform}`));
1148
+ console.log(chalk_1.default.gray(` Supported: claude, gemini, cursor, windsurf, cline, opencode, kiro, copilot`));
1149
+ return;
1150
+ }
1151
+ if (platform === 'copilot') {
1152
+ const instrFile = path_1.default.join('.github', 'copilot-instructions.md');
1153
+ fs_1.default.mkdirSync('.github', { recursive: true });
1154
+ const header = '\n\n## Cody Master Skills\nThe following AI skills are available — reference them by name:\n';
1155
+ const lines = skills.map(s => `- **${s}**: see https://github.com/tody-agent/codymaster/blob/main/skills/${s}/SKILL.md`).join('\n');
1156
+ const existing = fs_1.default.existsSync(instrFile) ? fs_1.default.readFileSync(instrFile, 'utf-8') : '';
1157
+ if (!existing.includes('Cody Master Skills')) {
1158
+ fs_1.default.appendFileSync(instrFile, header + lines + '\n');
1159
+ }
1160
+ console.log(chalk_1.default.green(`✅ ${skills.length} skills referenced in ${instrFile}`));
1161
+ console.log(chalk_1.default.gray(' GitHub Copilot will use these as context automatically.'));
1162
+ return;
1163
+ }
1164
+ const icons = { cursor: '🔵', windsurf: '🟠', cline: '⚫', opencode: '📦', kiro: '🔶' };
1165
+ const icon = icons[platform] || '📦';
1166
+ const label = skills.length === ALL_SKILLS.length ? 'all 34 skills' : skills.join(', ');
1167
+ console.log(`${icon} ${platform} — Installing ${label}`);
1168
+ console.log(chalk_1.default.gray(` Target: ./${target.dir}/\n`));
1169
+ let ok = 0, fail = 0;
1170
+ for (const skill of skills) {
1171
+ const url = `${RAW_BASE}/skills/${skill}/SKILL.md`;
1172
+ const dest = path_1.default.join(target.dir, skill, 'SKILL.md');
1173
+ const success = yield downloadFile(url, dest);
1174
+ if (success) {
1175
+ process.stdout.write(chalk_1.default.green(` ✅ ${skill}\n`));
1176
+ ok++;
1177
+ }
1178
+ else {
1179
+ process.stdout.write(chalk_1.default.red(` ❌ ${skill}\n`));
1180
+ fail++;
1181
+ }
1182
+ }
1183
+ console.log();
1184
+ if (ok > 0) {
1185
+ console.log(chalk_1.default.green(`✅ ${ok} skill${ok > 1 ? 's' : ''} installed → ./${target.dir}/`));
1186
+ const invoke = target.invoke.replace('<skill>', skills[0]);
1187
+ console.log(chalk_1.default.cyan(`📖 Usage: ${invoke} Your prompt here`));
1188
+ if (target.note)
1189
+ console.log(chalk_1.default.gray(` Note: ${target.note}`));
1190
+ yield postInstallOnboarding(platform);
1191
+ }
1192
+ if (fail > 0) {
1193
+ console.log(chalk_1.default.yellow(`⚠️ ${fail} failed — check connection or clone manually:`));
1194
+ console.log(chalk_1.default.gray(` git clone https://github.com/tody-agent/codymaster.git`));
1195
+ }
1196
+ });
1197
+ }
1198
+ program
1199
+ .command('add')
1200
+ .description('Add skills to your AI agent (npx codymaster add --skill cm-debugging)')
1201
+ .option('--skill <name>', 'Specific skill to add (e.g. cm-debugging)')
1202
+ .option('--all', 'Add all 34 skills')
1203
+ .option('--platform <platform>', 'Target: claude|gemini|cursor|windsurf|cline|opencode|kiro|copilot')
1204
+ .option('--list', 'Show available skills and exit')
1205
+ .action((opts) => __awaiter(void 0, void 0, void 0, function* () {
1206
+ showBanner();
1207
+ if (opts.list) {
1208
+ skillList();
1209
+ return;
1210
+ }
1211
+ // Resolve skills array
1212
+ let skills = null;
1213
+ if (opts.all) {
1214
+ skills = ALL_SKILLS;
1215
+ }
1216
+ else if (opts.skill) {
1217
+ if (!ALL_SKILLS.includes(opts.skill)) {
1218
+ console.log(chalk_1.default.red(`❌ Unknown skill: ${opts.skill}`));
1219
+ console.log(chalk_1.default.gray(' Run: npx codymaster add --list'));
1220
+ return;
1221
+ }
1222
+ skills = [opts.skill];
1223
+ }
1224
+ // Detect or prompt platform
1225
+ let platform = opts.platform || autoDetectPlatform();
1226
+ if (platform === 'manual') {
1227
+ const prompts = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
1228
+ const resp = yield prompts({
1229
+ type: 'select', name: 'platform', message: 'Select your AI coding platform:',
1230
+ choices: [
1231
+ { title: '🟣 Claude Code (recommended)', value: 'claude' },
1232
+ { title: '💻 Gemini CLI', value: 'gemini' },
1233
+ { title: '🔵 Cursor', value: 'cursor' },
1234
+ { title: '🟠 Windsurf', value: 'windsurf' },
1235
+ { title: '⚫ Cline / RooCode', value: 'cline' },
1236
+ { title: '📦 OpenCode', value: 'opencode' },
1237
+ { title: '🔶 Kiro (AWS)', value: 'kiro' },
1238
+ { title: '🐙 GitHub Copilot', value: 'copilot' },
1239
+ ],
1240
+ });
1241
+ if (!resp.platform)
1242
+ return;
1243
+ platform = resp.platform;
1244
+ }
1245
+ // If no skills chosen yet, prompt
1246
+ if (!skills) {
1247
+ if (platform === 'claude' || platform === 'gemini') {
1248
+ skills = ALL_SKILLS;
1249
+ }
1250
+ else {
1251
+ const prompts = (yield Promise.resolve().then(() => __importStar(require('prompts')))).default;
1252
+ const resp = yield prompts({
1253
+ type: 'select', name: 'mode', message: 'What to install?',
1254
+ choices: [
1255
+ { title: 'All 34 skills (full kit)', value: 'all' },
1256
+ { title: 'Search & pick one skill', value: 'pick' },
1257
+ ],
1258
+ });
1259
+ if (resp.mode === 'all') {
1260
+ skills = ALL_SKILLS;
1261
+ }
1262
+ else {
1263
+ const pick = yield prompts({
1264
+ type: 'autocomplete', name: 'skill', message: 'Type to search skill:',
1265
+ choices: ALL_SKILLS.map(s => ({ title: s, value: s })),
1266
+ });
1267
+ if (!pick.skill)
1268
+ return;
1269
+ skills = [pick.skill];
1270
+ }
1271
+ }
1272
+ }
1273
+ yield doAddSkills(skills, platform);
1274
+ }));
1275
+ // ─── List Command (quick alias for `cody skill list`) ─────────────────────────
1276
+ program
1277
+ .command('list')
1278
+ .alias('ls')
1279
+ .description('List all 34 available skills')
1280
+ .option('-d, --domain <domain>', 'Filter by domain')
1281
+ .action((opts) => {
1282
+ skillList(opts.domain);
1283
+ });
1284
+ // ─── Continuity Command (Working Memory) ────────────────────────────────────
1285
+ program
1286
+ .command('continuity [cmd]')
1287
+ .alias('ctx')
1288
+ .description('Working memory (init|status|reset|learnings|decisions)')
1289
+ .option('--path <path>', 'Project path', process.cwd())
1290
+ .action((cmd, opts) => {
1291
+ const projectPath = opts.path || process.cwd();
1292
+ switch (cmd) {
1293
+ case 'init':
1294
+ continuityInit(projectPath);
1295
+ break;
1296
+ case 'status':
1297
+ case undefined:
1298
+ continuityStatus(projectPath);
1299
+ break;
1300
+ case 'reset':
1301
+ continuityReset(projectPath);
1302
+ break;
1303
+ case 'learnings':
1304
+ case 'learn':
1305
+ continuityLearnings(projectPath);
1306
+ break;
1307
+ case 'decisions':
1308
+ case 'dec':
1309
+ continuityDecisions(projectPath);
1310
+ break;
1311
+ default:
1312
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
1313
+ console.log(chalk_1.default.gray('Available: init, status, reset, learnings, decisions'));
1314
+ }
1315
+ });
1316
+ function continuityInit(projectPath) {
1317
+ if ((0, continuity_1.hasCmDir)(projectPath)) {
1318
+ console.log(chalk_1.default.yellow('⚠️ .cm/ directory already exists.'));
1319
+ console.log(chalk_1.default.gray(` Path: ${projectPath}/.cm/`));
1320
+ return;
1321
+ }
1322
+ (0, continuity_1.ensureCmDir)(projectPath);
1323
+ console.log(chalk_1.default.green('✅ Working memory initialized!'));
1324
+ console.log(chalk_1.default.gray(` Created: ${projectPath}/.cm/`));
1325
+ console.log(chalk_1.default.gray(' ├── CONTINUITY.md (working memory)'));
1326
+ console.log(chalk_1.default.gray(' ├── config.yaml (RARV settings)'));
1327
+ console.log(chalk_1.default.gray(' └── memory/'));
1328
+ console.log(chalk_1.default.gray(' ├── learnings.json (error patterns)'));
1329
+ console.log(chalk_1.default.gray(' └── decisions.json (architecture decisions)'));
1330
+ console.log();
1331
+ console.log(chalk_1.default.cyan('💡 Protocol: Read CONTINUITY.md at session start, update at session end.'));
1332
+ }
1333
+ function continuityStatus(projectPath) {
1334
+ const status = (0, continuity_1.getContinuityStatus)(projectPath);
1335
+ if (!status.initialized) {
1336
+ console.log(chalk_1.default.yellow('⚫ Working memory not initialized.'));
1337
+ console.log(chalk_1.default.gray(' Run: cm continuity init'));
1338
+ return;
1339
+ }
1340
+ console.log(chalk_1.default.cyan('\n🧠 Working Memory Status\n'));
1341
+ console.log(` ${chalk_1.default.white('Project:')} ${status.project}`);
1342
+ console.log(` ${chalk_1.default.white('Phase:')} ${phaseColor(status.phase)(status.phase)}`);
1343
+ console.log(` ${chalk_1.default.white('Iteration:')} ${status.iteration}`);
1344
+ if (status.activeGoal) {
1345
+ console.log(` ${chalk_1.default.white('Goal:')} ${status.activeGoal}`);
1346
+ }
1347
+ if (status.currentTask) {
1348
+ console.log(` ${chalk_1.default.white('Task:')} ${status.currentTask}`);
1349
+ }
1350
+ console.log();
1351
+ console.log(chalk_1.default.gray(` ✅ Completed: ${status.completedCount} | 🚧 Blockers: ${status.blockerCount}`));
1352
+ console.log(chalk_1.default.gray(` 📚 Learnings: ${status.learningCount} | 📋 Decisions: ${status.decisionCount}`));
1353
+ if (status.lastUpdated) {
1354
+ console.log(chalk_1.default.gray(` 🕐 Updated: ${formatTimeAgoCli(status.lastUpdated)}`));
1355
+ }
1356
+ console.log();
1357
+ }
1358
+ function phaseColor(phase) {
1359
+ const colors = {
1360
+ planning: chalk_1.default.blue, executing: chalk_1.default.yellow, testing: chalk_1.default.magenta,
1361
+ deploying: chalk_1.default.green, reviewing: chalk_1.default.cyan, idle: chalk_1.default.gray,
1362
+ };
1363
+ return colors[phase] || chalk_1.default.white;
1364
+ }
1365
+ function continuityReset(projectPath) {
1366
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1367
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found.'));
1368
+ return;
1369
+ }
1370
+ (0, continuity_1.resetContinuity)(projectPath);
1371
+ console.log(chalk_1.default.green('✅ Working memory reset.'));
1372
+ console.log(chalk_1.default.gray(' CONTINUITY.md cleared. Learnings preserved.'));
1373
+ }
1374
+ function continuityLearnings(projectPath) {
1375
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1376
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found. Run: cm continuity init'));
1377
+ return;
1378
+ }
1379
+ const learnings = (0, continuity_1.getLearnings)(projectPath);
1380
+ if (learnings.length === 0) {
1381
+ console.log(chalk_1.default.gray('\n No learnings captured yet. 🎉\n'));
1382
+ return;
1383
+ }
1384
+ console.log(chalk_1.default.cyan(`\n📚 Mistakes & Learnings (${learnings.length})\n`));
1385
+ for (const l of learnings.slice(-10)) {
1386
+ console.log(chalk_1.default.red(` ❌ ${l.whatFailed}`));
1387
+ console.log(chalk_1.default.gray(` Why: ${l.whyFailed}`));
1388
+ console.log(chalk_1.default.green(` Fix: ${l.howToPrevent}`));
1389
+ console.log(chalk_1.default.gray(` ${formatTimeAgoCli(l.timestamp)} | ${l.agent || 'unknown'}\n`));
1390
+ }
1391
+ }
1392
+ function continuityDecisions(projectPath) {
1393
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1394
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found. Run: cm continuity init'));
1395
+ return;
1396
+ }
1397
+ const decisions = (0, continuity_1.getDecisions)(projectPath);
1398
+ if (decisions.length === 0) {
1399
+ console.log(chalk_1.default.gray('\n No decisions recorded yet.\n'));
1400
+ return;
1401
+ }
1402
+ console.log(chalk_1.default.cyan(`\n📋 Key Decisions (${decisions.length})\n`));
1403
+ for (const d of decisions.slice(-10)) {
1404
+ console.log(chalk_1.default.white(` 📌 ${d.decision}`));
1405
+ console.log(chalk_1.default.gray(` Rationale: ${d.rationale}`));
1406
+ console.log(chalk_1.default.gray(` ${formatTimeAgoCli(d.timestamp)} | ${d.agent || 'unknown'}\n`));
1407
+ }
1408
+ }
1409
+ // ─── Brain Command (Enhanced Memory Explorer) ────────────────────────────────
1410
+ program
1411
+ .command('brain [cmd]')
1412
+ .alias('b')
1413
+ .description('Memory explorer (status|learnings|decisions|delete|stats|export)')
1414
+ .option('--path <path>', 'Project path', process.cwd())
1415
+ .option('--search <query>', 'Search learnings')
1416
+ .option('--last <n>', 'Show last N items')
1417
+ .option('--format <fmt>', 'Export format: json|md', 'json')
1418
+ .action((cmd, opts) => {
1419
+ const projectPath = opts.path || process.cwd();
1420
+ switch (cmd) {
1421
+ case 'status':
1422
+ case undefined:
1423
+ brainStatus(projectPath);
1424
+ break;
1425
+ case 'learnings':
1426
+ case 'learn':
1427
+ case 'l':
1428
+ brainLearnings(projectPath, opts);
1429
+ break;
1430
+ case 'decisions':
1431
+ case 'dec':
1432
+ case 'd':
1433
+ brainDecisions(projectPath, opts);
1434
+ break;
1435
+ case 'delete':
1436
+ case 'del':
1437
+ case 'rm':
1438
+ console.log(chalk_1.default.gray('Usage: cm brain delete <type> <id>'));
1439
+ console.log(chalk_1.default.gray(' type: learning | decision'));
1440
+ console.log(chalk_1.default.gray(' id: first 8 chars of the ID'));
1441
+ break;
1442
+ case 'stats':
1443
+ brainStats(projectPath);
1444
+ break;
1445
+ case 'export':
1446
+ brainExport(projectPath, opts);
1447
+ break;
1448
+ default:
1449
+ // Try as delete: cm brain learning <id> or cm brain decision <id>
1450
+ if (cmd === 'learning' || cmd === 'decision') {
1451
+ console.log(chalk_1.default.gray(`Did you mean: cm brain ${cmd}s ?`));
1452
+ }
1453
+ else {
1454
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
1455
+ console.log(chalk_1.default.gray('Available: status, learnings, decisions, delete, stats, export'));
1456
+ }
1457
+ }
1458
+ });
1459
+ program
1460
+ .command('brain-delete <type> <id>')
1461
+ .description('Delete a learning or decision by ID prefix')
1462
+ .option('--path <path>', 'Project path', process.cwd())
1463
+ .action((type, id, opts) => {
1464
+ const projectPath = opts.path || process.cwd();
1465
+ brainDelete(projectPath, type, id);
1466
+ });
1467
+ function brainStatus(projectPath) {
1468
+ const status = (0, continuity_1.getContinuityStatus)(projectPath);
1469
+ if (!status.initialized) {
1470
+ console.log(chalk_1.default.yellow('\n⚫ Working memory not initialized.'));
1471
+ console.log(chalk_1.default.gray(' Run: cm continuity init'));
1472
+ return;
1473
+ }
1474
+ showBanner();
1475
+ console.log(chalk_1.default.cyan('\n🧠 Brain — Memory Status\n'));
1476
+ // Stats row
1477
+ console.log(chalk_1.default.white(' ┌──────────────┬──────────────┬──────────────┬──────────────┐'));
1478
+ console.log(chalk_1.default.white(' │') + chalk_1.default.red(` ❤ Learn: ${padRight(String(status.learningCount), 4)}`) +
1479
+ chalk_1.default.white(' │') + chalk_1.default.blue(` 📋 Decide: ${padRight(String(status.decisionCount), 3)}`) +
1480
+ chalk_1.default.white(' │') + phaseColor(status.phase)(` ● ${padRight(status.phase, 9)}`) +
1481
+ chalk_1.default.white(' │') + chalk_1.default.gray(` #${padRight(String(status.iteration), 10)}`) + chalk_1.default.white('│'));
1482
+ console.log(chalk_1.default.white(' └──────────────┴──────────────┴──────────────┴──────────────┘'));
1483
+ console.log();
1484
+ console.log(` ${chalk_1.default.white('Project:')} ${status.project}`);
1485
+ if (status.activeGoal)
1486
+ console.log(` ${chalk_1.default.white('Goal:')} ${status.activeGoal}`);
1487
+ if (status.currentTask)
1488
+ console.log(` ${chalk_1.default.white('Task:')} ${status.currentTask}`);
1489
+ console.log(` ${chalk_1.default.white('Completed:')} ${status.completedCount} items`);
1490
+ console.log(` ${chalk_1.default.white('Blockers:')} ${status.blockerCount > 0 ? chalk_1.default.yellow(`🚧 ${status.blockerCount}`) : chalk_1.default.green('✅ None')}`);
1491
+ if (status.lastUpdated)
1492
+ console.log(` ${chalk_1.default.white('Updated:')} ${formatTimeAgoCli(status.lastUpdated)}`);
1493
+ console.log();
1494
+ console.log(chalk_1.default.gray(' Commands:'));
1495
+ console.log(chalk_1.default.gray(' cm brain learnings — View mistakes & lessons'));
1496
+ console.log(chalk_1.default.gray(' cm brain decisions — View architecture decisions'));
1497
+ console.log(chalk_1.default.gray(' cm brain stats — Memory statistics'));
1498
+ console.log(chalk_1.default.gray(' cm brain export — Export memory data'));
1499
+ console.log();
1500
+ }
1501
+ function brainLearnings(projectPath, opts) {
1502
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1503
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found. Run: cm continuity init'));
1504
+ return;
1505
+ }
1506
+ let learnings = (0, continuity_1.getLearnings)(projectPath);
1507
+ // Search filter
1508
+ if (opts.search) {
1509
+ const q = opts.search.toLowerCase();
1510
+ learnings = learnings.filter(l => (l.whatFailed || '').toLowerCase().includes(q) ||
1511
+ (l.whyFailed || '').toLowerCase().includes(q) ||
1512
+ (l.howToPrevent || '').toLowerCase().includes(q));
1513
+ }
1514
+ // Last N
1515
+ const limit = opts.last ? parseInt(opts.last) : 15;
1516
+ const display = learnings.slice(-limit);
1517
+ if (display.length === 0) {
1518
+ console.log(chalk_1.default.gray(`\n No learnings ${opts.search ? 'matching "' + opts.search + '"' : 'captured yet'}. 🎉\n`));
1519
+ return;
1520
+ }
1521
+ console.log(chalk_1.default.cyan(`\n📚 Learnings (${display.length}${learnings.length > limit ? '/' + learnings.length : ''})\n`));
1522
+ for (const l of display) {
1523
+ const shortId = l.id ? l.id.substring(0, 8) : '???';
1524
+ console.log(chalk_1.default.red(` ❌ ${l.whatFailed}`) + chalk_1.default.gray(` [${shortId}]`));
1525
+ if (l.whyFailed)
1526
+ console.log(chalk_1.default.gray(` Why: ${l.whyFailed}`));
1527
+ if (l.howToPrevent)
1528
+ console.log(chalk_1.default.green(` Fix: ${l.howToPrevent}`));
1529
+ console.log(chalk_1.default.gray(` ${formatTimeAgoCli(l.timestamp)} | ${l.agent || 'unknown'}${l.module ? ' | 📦 ' + l.module : ''}\n`));
1530
+ }
1531
+ }
1532
+ function brainDecisions(projectPath, opts) {
1533
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1534
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found. Run: cm continuity init'));
1535
+ return;
1536
+ }
1537
+ const decisions = (0, continuity_1.getDecisions)(projectPath);
1538
+ const limit = opts.last ? parseInt(opts.last) : 15;
1539
+ const display = decisions.slice(-limit);
1540
+ if (display.length === 0) {
1541
+ console.log(chalk_1.default.gray('\n No decisions recorded yet.\n'));
1542
+ return;
1543
+ }
1544
+ console.log(chalk_1.default.cyan(`\n📋 Key Decisions (${display.length}${decisions.length > limit ? '/' + decisions.length : ''})\n`));
1545
+ for (const d of display) {
1546
+ const shortId = d.id ? d.id.substring(0, 8) : '???';
1547
+ console.log(chalk_1.default.white(` 📌 ${d.decision}`) + chalk_1.default.gray(` [${shortId}]`));
1548
+ if (d.rationale)
1549
+ console.log(chalk_1.default.gray(` Rationale: ${d.rationale}`));
1550
+ console.log(chalk_1.default.gray(` ${formatTimeAgoCli(d.timestamp)} | ${d.agent || 'unknown'}\n`));
1551
+ }
1552
+ }
1553
+ function brainDelete(projectPath, type, id) {
1554
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1555
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found.'));
1556
+ return;
1557
+ }
1558
+ if (type === 'learning' || type === 'l') {
1559
+ const learnings = (0, continuity_1.getLearnings)(projectPath);
1560
+ const target = learnings.find(l => l.id && l.id.startsWith(id));
1561
+ if (!target) {
1562
+ console.log(chalk_1.default.red(`❌ Learning not found with ID prefix: ${id}`));
1563
+ return;
1564
+ }
1565
+ const success = (0, continuity_1.deleteLearning)(projectPath, target.id);
1566
+ if (success) {
1567
+ console.log(chalk_1.default.green(`✅ Deleted learning: ${target.whatFailed}`));
1568
+ }
1569
+ else {
1570
+ console.log(chalk_1.default.red('❌ Failed to delete'));
1571
+ }
1572
+ }
1573
+ else if (type === 'decision' || type === 'd') {
1574
+ const decisions = (0, continuity_1.getDecisions)(projectPath);
1575
+ const target = decisions.find(d => d.id && d.id.startsWith(id));
1576
+ if (!target) {
1577
+ console.log(chalk_1.default.red(`❌ Decision not found with ID prefix: ${id}`));
1578
+ return;
1579
+ }
1580
+ const success = (0, continuity_1.deleteDecision)(projectPath, target.id);
1581
+ if (success) {
1582
+ console.log(chalk_1.default.green(`✅ Deleted decision: ${target.decision}`));
1583
+ }
1584
+ else {
1585
+ console.log(chalk_1.default.red('❌ Failed to delete'));
1586
+ }
1587
+ }
1588
+ else {
1589
+ console.log(chalk_1.default.red(`❌ Unknown type: ${type}`));
1590
+ console.log(chalk_1.default.gray(' Use: cm brain-delete learning <id> | cm brain-delete decision <id>'));
1591
+ }
1592
+ }
1593
+ function brainStats(projectPath) {
1594
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1595
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found. Run: cm continuity init'));
1596
+ return;
1597
+ }
1598
+ const status = (0, continuity_1.getContinuityStatus)(projectPath);
1599
+ const learnings = (0, continuity_1.getLearnings)(projectPath);
1600
+ const decisions = (0, continuity_1.getDecisions)(projectPath);
1601
+ console.log(chalk_1.default.cyan('\n📊 Brain Statistics\n'));
1602
+ console.log(` ${chalk_1.default.white('Learnings:')} ${learnings.length}`);
1603
+ console.log(` ${chalk_1.default.white('Decisions:')} ${decisions.length}`);
1604
+ console.log(` ${chalk_1.default.white('Completed:')} ${status.completedCount} items`);
1605
+ console.log(` ${chalk_1.default.white('Blockers:')} ${status.blockerCount}`);
1606
+ console.log(` ${chalk_1.default.white('Iteration:')} #${status.iteration}`);
1607
+ // Agent breakdown
1608
+ const agentMap = {};
1609
+ learnings.forEach(l => { if (l.agent)
1610
+ agentMap[l.agent] = (agentMap[l.agent] || 0) + 1; });
1611
+ decisions.forEach(d => { if (d.agent)
1612
+ agentMap[d.agent] = (agentMap[d.agent] || 0) + 1; });
1613
+ const agents = Object.entries(agentMap).sort((a, b) => b[1] - a[1]);
1614
+ if (agents.length > 0) {
1615
+ console.log();
1616
+ console.log(chalk_1.default.white(' Agents:'));
1617
+ for (const [agent, count] of agents) {
1618
+ console.log(chalk_1.default.gray(` 🤖 ${padRight(agent, 20)} ${count} entries`));
1619
+ }
1620
+ }
1621
+ // Module breakdown
1622
+ const moduleMap = {};
1623
+ learnings.forEach(l => { if (l.module)
1624
+ moduleMap[l.module] = (moduleMap[l.module] || 0) + 1; });
1625
+ const modules = Object.entries(moduleMap).sort((a, b) => b[1] - a[1]);
1626
+ if (modules.length > 0) {
1627
+ console.log();
1628
+ console.log(chalk_1.default.white(' Modules (most error-prone):'));
1629
+ for (const [mod, count] of modules.slice(0, 5)) {
1630
+ console.log(chalk_1.default.gray(` 📦 ${padRight(mod, 20)} ${count} learnings`));
1631
+ }
1632
+ }
1633
+ // Time range
1634
+ const allTimestamps = [...learnings.map(l => l.timestamp), ...decisions.map(d => d.timestamp)].filter(Boolean).sort();
1635
+ if (allTimestamps.length > 0) {
1636
+ console.log();
1637
+ console.log(chalk_1.default.gray(` First entry: ${formatTimeAgoCli(allTimestamps[0])}`));
1638
+ console.log(chalk_1.default.gray(` Latest: ${formatTimeAgoCli(allTimestamps[allTimestamps.length - 1])}`));
1639
+ }
1640
+ console.log();
1641
+ }
1642
+ function brainExport(projectPath, opts) {
1643
+ if (!(0, continuity_1.hasCmDir)(projectPath)) {
1644
+ console.log(chalk_1.default.yellow('⚠️ No .cm/ directory found.'));
1645
+ return;
1646
+ }
1647
+ const learnings = (0, continuity_1.getLearnings)(projectPath);
1648
+ const decisions = (0, continuity_1.getDecisions)(projectPath);
1649
+ const status = (0, continuity_1.getContinuityStatus)(projectPath);
1650
+ const format = opts.format || 'json';
1651
+ if (format === 'json') {
1652
+ const data = { status, learnings, decisions, exportedAt: new Date().toISOString() };
1653
+ const outFile = `brain-export-${new Date().toISOString().slice(0, 10)}.json`;
1654
+ fs_1.default.writeFileSync(outFile, JSON.stringify(data, null, 2));
1655
+ console.log(chalk_1.default.green(`✅ Exported to ${outFile}`));
1656
+ console.log(chalk_1.default.gray(` ${learnings.length} learnings, ${decisions.length} decisions`));
1657
+ }
1658
+ else if (format === 'md') {
1659
+ let md = `# Brain Export\n\n**Project:** ${status.project || 'Unknown'}\n**Exported:** ${new Date().toISOString()}\n\n`;
1660
+ md += `## Learnings (${learnings.length})\n\n`;
1661
+ for (const l of learnings) {
1662
+ md += `### ❌ ${l.whatFailed}\n- **Why:** ${l.whyFailed || 'N/A'}\n- **Fix:** ${l.howToPrevent || 'N/A'}\n- **Agent:** ${l.agent || 'unknown'} | **Date:** ${l.timestamp || 'N/A'}\n\n`;
1663
+ }
1664
+ md += `## Decisions (${decisions.length})\n\n`;
1665
+ for (const d of decisions) {
1666
+ md += `### 📌 ${d.decision}\n- **Rationale:** ${d.rationale || 'N/A'}\n- **Agent:** ${d.agent || 'unknown'} | **Date:** ${d.timestamp || 'N/A'}\n\n`;
1667
+ }
1668
+ const outFile = `brain-export-${new Date().toISOString().slice(0, 10)}.md`;
1669
+ fs_1.default.writeFileSync(outFile, md);
1670
+ console.log(chalk_1.default.green(`✅ Exported to ${outFile}`));
1671
+ console.log(chalk_1.default.gray(` ${learnings.length} learnings, ${decisions.length} decisions`));
1672
+ }
1673
+ else {
1674
+ console.log(chalk_1.default.red(`❌ Unknown format: ${format}`));
1675
+ console.log(chalk_1.default.gray(' Use: --format json | --format md'));
1676
+ }
1677
+ }
1678
+ // ─── Skill Command ──────────────────────────────────────────────────────────
1679
+ const SKILL_CATALOG = {
1680
+ engineering: {
1681
+ icon: '🔧',
1682
+ skills: [
1683
+ { name: 'cm-tdd', desc: 'Red-Green-Refactor cycle — test before code' },
1684
+ { name: 'cm-debugging', desc: '5-phase root cause investigation' },
1685
+ { name: 'cm-quality-gate', desc: '6-gate verification system' },
1686
+ { name: 'cm-test-gate', desc: 'Setup 4-layer test infrastructure' },
1687
+ { name: 'cm-code-review', desc: 'Professional PR review lifecycle' },
1688
+ ],
1689
+ },
1690
+ operations: {
1691
+ icon: '⚙️',
1692
+ skills: [
1693
+ { name: 'cm-safe-deploy', desc: 'Multi-gate deploy pipeline with rollback' },
1694
+ { name: 'cm-identity-guard', desc: 'Prevent wrong-account deploys' },
1695
+ { name: 'cm-git-worktrees', desc: 'Isolated feature branches without context-switch' },
1696
+ { name: 'cm-terminal', desc: 'Safe terminal execution with logging' },
1697
+ { name: 'cm-secret-shield', desc: 'Scan & block secrets before commit/deploy' },
1698
+ { name: 'cm-safe-i18n', desc: 'Multi-pass translation with 8 audit gates' },
1699
+ ],
1700
+ },
1701
+ product: {
1702
+ icon: '🎨',
1703
+ skills: [
1704
+ { name: 'cm-planning', desc: 'Intent → design → structured plan' },
1705
+ { name: 'cm-ux-master', desc: '48 UX Laws + 37 Design Tests' },
1706
+ { name: 'cm-ui-preview', desc: 'Browser-previewed UI prototypes' },
1707
+ { name: 'cm-brainstorm-idea', desc: 'Multi-lens ideation with scoring' },
1708
+ { name: 'cm-jtbd', desc: 'Jobs-To-Be-Done framework & canvas' },
1709
+ { name: 'cm-dockit', desc: 'Complete knowledge base from codebase' },
1710
+ { name: 'cm-project-bootstrap', desc: 'Full project setup: design → CI → deploy' },
1711
+ { name: 'cm-readit', desc: 'Web audio TTS reader & MP3 player' },
1712
+ ],
1713
+ },
1714
+ growth: {
1715
+ icon: '📈',
1716
+ skills: [
1717
+ { name: 'cm-content-factory', desc: 'AI content engine: research → deploy' },
1718
+ { name: 'cm-ads-tracker', desc: 'Facebook/TikTok/Google pixel setup' },
1719
+ { name: 'cro-methodology', desc: 'Conversion audit + A/B test design' },
1720
+ { name: 'cm-deep-search', desc: 'Multi-source deep research synthesis' },
1721
+ ],
1722
+ },
1723
+ orchestration: {
1724
+ icon: '🎯',
1725
+ skills: [
1726
+ { name: 'cm-execution', desc: 'Execute plans: batch, parallel, RARV' },
1727
+ { name: 'cm-continuity', desc: 'Working memory: read/update per session' },
1728
+ { name: 'cm-skill-index', desc: 'Progressive skill discovery & routing' },
1729
+ { name: 'cm-skill-mastery', desc: 'Meta: when/how to invoke skills' },
1730
+ { name: 'cm-skill-chain', desc: 'Multi-skill pipeline execution' },
1731
+ ],
1732
+ },
1733
+ workflow: {
1734
+ icon: '⚡',
1735
+ skills: [
1736
+ { name: 'cm-start', desc: 'Onboarding & session kick-off wizard' },
1737
+ { name: 'cm-dashboard', desc: 'Project status & task Kanban board' },
1738
+ { name: 'cm-status', desc: 'Quick project health snapshot' },
1739
+ { name: 'cm-how-it-work', desc: 'Interactive explainer for all 34 skills' },
1740
+ { name: 'cm-example', desc: 'Minimal template for new skills' },
1741
+ ],
1742
+ },
1743
+ };
1744
+ program
1745
+ .command('skill [cmd] [name]')
1746
+ .alias('sk')
1747
+ .description('Skill management (list|info|domains)')
1748
+ .action((cmd, name) => {
1749
+ switch (cmd) {
1750
+ case 'list':
1751
+ case 'ls':
1752
+ case undefined:
1753
+ skillList();
1754
+ break;
1755
+ case 'info':
1756
+ if (!name) {
1757
+ console.log(chalk_1.default.red('❌ Usage: cm skill info <skill-name>'));
1758
+ return;
1759
+ }
1760
+ skillInfo(name);
1761
+ break;
1762
+ case 'domains':
1763
+ skillDomains();
1764
+ break;
1765
+ default:
1766
+ // Treat cmd as skill name for `cody skill cm-tdd`
1767
+ skillInfo(cmd);
1768
+ }
1769
+ });
1770
+ function skillList(filterDomain) {
1771
+ const entries = filterDomain
1772
+ ? Object.entries(SKILL_CATALOG).filter(([d]) => d.toLowerCase().startsWith(filterDomain.toLowerCase()))
1773
+ : Object.entries(SKILL_CATALOG);
1774
+ if (entries.length === 0) {
1775
+ console.log(chalk_1.default.red(`❌ Domain not found: ${filterDomain}`));
1776
+ console.log(chalk_1.default.gray(' Domains: engineering, operations, product, growth, orchestration, workflow'));
1777
+ return;
1778
+ }
1779
+ console.log(chalk_1.default.cyan('\n🧩 Cody Master — 34 Skills\n'));
1780
+ let total = 0;
1781
+ for (const [domain, data] of entries) {
1782
+ console.log(chalk_1.default.white(` ${data.icon} ${domain.charAt(0).toUpperCase() + domain.slice(1)}`));
1783
+ for (const skill of data.skills) {
1784
+ console.log(` ${chalk_1.default.cyan(padRight(skill.name, 26))} ${chalk_1.default.gray(skill.desc)}`);
1785
+ total++;
1786
+ }
1787
+ console.log();
1788
+ }
1789
+ console.log(chalk_1.default.gray(` ${total} skills across ${entries.length} domains`));
1790
+ console.log(chalk_1.default.gray(` Install: npx codymaster add --all`));
1791
+ console.log(chalk_1.default.gray(` Add one: npx codymaster add --skill <name>\n`));
1792
+ }
1793
+ function skillInfo(name) {
1794
+ for (const [domain, data] of Object.entries(SKILL_CATALOG)) {
1795
+ const skill = data.skills.find(s => s.name === name);
1796
+ if (skill) {
1797
+ console.log(chalk_1.default.cyan(`\n🧩 Skill: ${skill.name}\n`));
1798
+ console.log(` ${chalk_1.default.white('Domain:')} ${domain}`);
1799
+ console.log(` ${chalk_1.default.white('Description:')} ${skill.desc}`);
1800
+ const agents = (0, judge_1.suggestAgentsForSkill)(skill.name);
1801
+ console.log(` ${chalk_1.default.white('Best Agents:')} ${agents.join(', ')}`);
1802
+ console.log(` ${chalk_1.default.white('Invoke:')} @[/${skill.name}] (Antigravity/Gemini)`);
1803
+ console.log(` /${skill.name} (Claude Code)`);
1804
+ console.log(` @${skill.name} (Cursor/Windsurf/Cline)`);
1805
+ console.log();
1806
+ return;
1807
+ }
1808
+ }
1809
+ console.log(chalk_1.default.red(`❌ Skill not found: ${name}`));
1810
+ console.log(chalk_1.default.gray(' Use "cm skill list" to see all available skills.'));
1811
+ }
1812
+ function skillDomains() {
1813
+ console.log(chalk_1.default.cyan('\n🎯 Skill Domains\n'));
1814
+ let total = 0;
1815
+ for (const [domain, data] of Object.entries(SKILL_CATALOG)) {
1816
+ console.log(` ${data.icon} ${chalk_1.default.white(padRight(domain.charAt(0).toUpperCase() + domain.slice(1), 16))} ${chalk_1.default.gray(`${data.skills.length} skills`)}`);
1817
+ total += data.skills.length;
1818
+ }
1819
+ console.log(chalk_1.default.gray(`\n Total: ${total} skills across ${Object.keys(SKILL_CATALOG).length} domains`));
1820
+ console.log();
1821
+ }
1822
+ // ─── Judge Command ──────────────────────────────────────────────────────────
1823
+ program
1824
+ .command('judge [taskId]')
1825
+ .alias('j')
1826
+ .description('Judge agent decisions for tasks')
1827
+ .option('-p, --project <name>', 'Filter by project')
1828
+ .action((taskId, opts) => {
1829
+ const data = (0, data_1.loadData)();
1830
+ if (taskId) {
1831
+ // Single task evaluation
1832
+ const task = (0, data_1.findTaskByIdPrefix)(data, taskId);
1833
+ if (!task) {
1834
+ console.log(chalk_1.default.red(`❌ Task not found: ${taskId}`));
1835
+ return;
1836
+ }
1837
+ const project = data.projects.find(p => p.id === task.projectId);
1838
+ let learnings = [];
1839
+ if ((project === null || project === void 0 ? void 0 : project.path) && (0, continuity_1.hasCmDir)(project.path)) {
1840
+ learnings = (0, continuity_1.getLearnings)(project.path);
1841
+ }
1842
+ const decision = (0, judge_1.evaluateTaskState)(task, data.tasks, learnings);
1843
+ console.log(chalk_1.default.cyan(`\n🤖 Judge Decision\n`));
1844
+ console.log(` ${chalk_1.default.white('Task:')} ${task.title}`);
1845
+ console.log(` ${chalk_1.default.white('Column:')} ${task.column}`);
1846
+ console.log(` ${chalk_1.default.white('Action:')} ${decision.badge} ${decision.action}`);
1847
+ console.log(` ${chalk_1.default.white('Reason:')} ${decision.reason}`);
1848
+ console.log(` ${chalk_1.default.white('Confidence:')} ${Math.round(decision.confidence * 100)}%`);
1849
+ if (decision.suggestedNextSkill) {
1850
+ console.log(` ${chalk_1.default.white('Suggested:')} ${decision.suggestedNextSkill}`);
1851
+ }
1852
+ console.log();
1853
+ }
1854
+ else {
1855
+ // All active tasks
1856
+ let tasks = data.tasks;
1857
+ if (opts.project) {
1858
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
1859
+ if (!project) {
1860
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
1861
+ return;
1862
+ }
1863
+ tasks = tasks.filter(t => t.projectId === project.id);
1864
+ }
1865
+ let allLearnings = [];
1866
+ for (const project of data.projects) {
1867
+ if (project.path && (0, continuity_1.hasCmDir)(project.path)) {
1868
+ allLearnings = allLearnings.concat((0, continuity_1.getLearnings)(project.path));
1869
+ }
1870
+ }
1871
+ const decisions = (0, judge_1.evaluateAllTasks)(tasks, allLearnings);
1872
+ if (decisions.size === 0) {
1873
+ console.log(chalk_1.default.gray('\n No active tasks to evaluate.\n'));
1874
+ return;
1875
+ }
1876
+ console.log(chalk_1.default.cyan(`\n🤖 Judge Decisions (${decisions.size} active tasks)\n`));
1877
+ console.log(chalk_1.default.gray(' ' + padRight('Badge', 8) + padRight('Action', 12) + padRight('Confidence', 12) + 'Task'));
1878
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(70)));
1879
+ for (const [tid, dec] of decisions) {
1880
+ const task = tasks.find(t => t.id === tid);
1881
+ const actionColor = dec.action === 'CONTINUE' ? chalk_1.default.green
1882
+ : dec.action === 'COMPLETE' ? chalk_1.default.blue
1883
+ : dec.action === 'ESCALATE' ? chalk_1.default.yellow
1884
+ : chalk_1.default.magenta;
1885
+ console.log(' ' + padRight(dec.badge, 8) + actionColor(padRight(dec.action, 12)) + chalk_1.default.gray(padRight(`${Math.round(dec.confidence * 100)}%`, 12)) + ((task === null || task === void 0 ? void 0 : task.title) || tid.substring(0, 8)));
1886
+ }
1887
+ console.log();
1888
+ }
1889
+ });
1890
+ // ─── Init Command ───────────────────────────────────────────────────────────
1891
+ program
1892
+ .command('init')
1893
+ .description('Initialize project from current directory')
1894
+ .option('-n, --name <name>', 'Project name')
1895
+ .option('--path <path>', 'Workspace path', process.cwd())
1896
+ .action((opts) => {
1897
+ const data = (0, data_1.loadData)();
1898
+ const projectName = opts.name || path_1.default.basename(opts.path || process.cwd());
1899
+ const projectPath = opts.path || process.cwd();
1900
+ // Check if already exists
1901
+ const existing = data.projects.find(p => p.path === projectPath || p.name === projectName);
1902
+ if (existing) {
1903
+ console.log(chalk_1.default.yellow(`⚠️ Project already exists: ${existing.name}`));
1904
+ console.log(chalk_1.default.gray(` ID: ${(0, data_1.shortId)(existing.id)} | Path: ${existing.path}`));
1905
+ return;
1906
+ }
1907
+ const project = {
1908
+ id: crypto_1.default.randomUUID(),
1909
+ name: projectName,
1910
+ path: projectPath,
1911
+ agents: [],
1912
+ createdAt: new Date().toISOString(),
1913
+ };
1914
+ data.projects.push(project);
1915
+ (0, data_1.logActivity)(data, 'project_created', `Project "${project.name}" initialized via CLI`, project.id);
1916
+ (0, data_1.saveData)(data);
1917
+ // Also init working memory
1918
+ (0, continuity_1.ensureCmDir)(projectPath);
1919
+ console.log(chalk_1.default.green(`\n✅ Project initialized: ${projectName}`));
1920
+ console.log(chalk_1.default.gray(` ID: ${(0, data_1.shortId)(project.id)}`));
1921
+ console.log(chalk_1.default.gray(` Path: ${projectPath}`));
1922
+ console.log(chalk_1.default.gray(` .cm/ Working memory created`));
1923
+ console.log();
1924
+ if (!isDashboardRunning()) {
1925
+ (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT);
1926
+ console.log(chalk_1.default.green(` 🚀 Dashboard auto-started! You can track progress at http://codymaster.localhost:${data_1.DEFAULT_PORT}`));
1927
+ }
1928
+ console.log(chalk_1.default.cyan('💡 Next steps:'));
1929
+ console.log(chalk_1.default.gray(' cm task add "My first task"'));
1930
+ console.log(chalk_1.default.gray(' cm open'));
1931
+ console.log();
1932
+ });
1933
+ // ─── Open Command ───────────────────────────────────────────────────────────
1934
+ program
1935
+ .command('open')
1936
+ .alias('o')
1937
+ .description('Open dashboard in browser')
1938
+ .option('-p, --port <port>', 'Port number', String(data_1.DEFAULT_PORT))
1939
+ .action((opts) => {
1940
+ const port = parseInt(opts.port) || data_1.DEFAULT_PORT;
1941
+ if (!isDashboardRunning()) {
1942
+ console.log(chalk_1.default.yellow('⚠️ Dashboard not running. Starting it first...'));
1943
+ (0, dashboard_1.launchDashboard)(port);
1944
+ setTimeout(() => openUrl(`http://codymaster.localhost:${port}`), 1500);
1945
+ }
1946
+ else {
1947
+ console.log(chalk_1.default.blue(`🌐 Opening http://codymaster.localhost:${port} ...`));
1948
+ openUrl(`http://codymaster.localhost:${port}`);
1949
+ }
1950
+ });
1951
+ // ─── Config Command ─────────────────────────────────────────────────────────
1952
+ program
1953
+ .command('config')
1954
+ .alias('cfg')
1955
+ .description('Show configuration & data paths')
1956
+ .action(() => {
1957
+ console.log(chalk_1.default.cyan(`\n⚙️ Cody Configuration\n`));
1958
+ console.log(` ${chalk_1.default.white('Version:')} ${VERSION}`);
1959
+ console.log(` ${chalk_1.default.white('Data Dir:')} ${data_1.DATA_DIR}`);
1960
+ console.log(` ${chalk_1.default.white('Data File:')} ${data_1.DATA_FILE}`);
1961
+ console.log(` ${chalk_1.default.white('PID File:')} ${data_1.PID_FILE}`);
1962
+ console.log(` ${chalk_1.default.white('Port:')} ${data_1.DEFAULT_PORT}`);
1963
+ console.log(` ${chalk_1.default.white('CLI Names:')} cm | cm | codymaster`);
1964
+ console.log();
1965
+ // Show data stats
1966
+ const data = (0, data_1.loadData)();
1967
+ console.log(chalk_1.default.white(' Data Stats:'));
1968
+ console.log(chalk_1.default.gray(` Projects: ${data.projects.length}`));
1969
+ console.log(chalk_1.default.gray(` Tasks: ${data.tasks.length}`));
1970
+ console.log(chalk_1.default.gray(` Deploys: ${data.deployments.length}`));
1971
+ console.log(chalk_1.default.gray(` Activities: ${data.activities.length}`));
1972
+ console.log(chalk_1.default.gray(` Changelog: ${data.changelog.length}`));
1973
+ console.log();
1974
+ // Dashboard status
1975
+ if (isDashboardRunning()) {
1976
+ console.log(chalk_1.default.green(` 🚀 Dashboard: RUNNING at http://codymaster.localhost:${data_1.DEFAULT_PORT}`));
1977
+ }
1978
+ else {
1979
+ console.log(chalk_1.default.gray(` ⚫ Dashboard: not running`));
1980
+ }
1981
+ console.log();
1982
+ });
1983
+ // ─── Agents Command ─────────────────────────────────────────────────────────
1984
+ const AGENT_LIST = [
1985
+ { id: 'antigravity', name: 'Google Antigravity', icon: '🟢' },
1986
+ { id: 'claude-code', name: 'Claude Code', icon: '🟣' },
1987
+ { id: 'cursor', name: 'Cursor', icon: '🔵' },
1988
+ { id: 'gemini-cli', name: 'Gemini CLI', icon: '💻' },
1989
+ { id: 'windsurf', name: 'Windsurf', icon: '🟠' },
1990
+ { id: 'cline', name: 'Cline / RooCode', icon: '🟤' },
1991
+ { id: 'copilot', name: 'GitHub Copilot', icon: '🐈' },
1992
+ ];
1993
+ program
1994
+ .command('agents [skill]')
1995
+ .alias('ag')
1996
+ .description('List agents or suggest best agent for a skill')
1997
+ .action((skill) => {
1998
+ if (skill) {
1999
+ // Suggest best agents for skill
2000
+ const domain = (0, judge_1.getSkillDomain)(skill);
2001
+ const agents = (0, judge_1.suggestAgentsForSkill)(skill);
2002
+ console.log(chalk_1.default.cyan(`\n🤖 Agent Suggestions for ${chalk_1.default.white(skill)}\n`));
2003
+ console.log(chalk_1.default.gray(` Domain: ${domain}\n`));
2004
+ agents.forEach((agentId, index) => {
2005
+ const agent = AGENT_LIST.find(a => a.id === agentId);
2006
+ const affinity = index === 0 ? chalk_1.default.green('★ BEST') : index === 1 ? chalk_1.default.yellow('● GOOD') : chalk_1.default.gray('○ OK');
2007
+ console.log(` ${(agent === null || agent === void 0 ? void 0 : agent.icon) || '🤖'} ${padRight((agent === null || agent === void 0 ? void 0 : agent.name) || agentId, 24)} ${affinity}`);
2008
+ });
2009
+ console.log();
2010
+ }
2011
+ else {
2012
+ // List all agents
2013
+ console.log(chalk_1.default.cyan('\n🤖 Available Agents\n'));
2014
+ for (const agent of AGENT_LIST) {
2015
+ console.log(` ${agent.icon} ${chalk_1.default.white(padRight(agent.name, 24))} ${chalk_1.default.gray(agent.id)}`);
2016
+ }
2017
+ console.log();
2018
+ console.log(chalk_1.default.gray(' 💡 Tip: cm agents <skill-name> to see best agents for a skill'));
2019
+ console.log();
2020
+ }
2021
+ });
2022
+ // ─── Sync Command ───────────────────────────────────────────────────────────
2023
+ program
2024
+ .command('sync <file>')
2025
+ .description('Bulk import tasks from JSON file')
2026
+ .option('-p, --project <name>', 'Target project')
2027
+ .option('--agent <agent>', 'Agent name')
2028
+ .option('--skill <skill>', 'Skill name')
2029
+ .action((file, opts) => {
2030
+ const filePath = path_1.default.resolve(file);
2031
+ if (!fs_1.default.existsSync(filePath)) {
2032
+ console.log(chalk_1.default.red(`❌ File not found: ${filePath}`));
2033
+ return;
2034
+ }
2035
+ let tasks;
2036
+ try {
2037
+ const content = fs_1.default.readFileSync(filePath, 'utf-8');
2038
+ const parsed = JSON.parse(content);
2039
+ tasks = Array.isArray(parsed) ? parsed : parsed.tasks;
2040
+ if (!Array.isArray(tasks))
2041
+ throw new Error('Invalid format');
2042
+ }
2043
+ catch (err) {
2044
+ console.log(chalk_1.default.red(`❌ Invalid JSON file: ${err.message}`));
2045
+ console.log(chalk_1.default.gray(' Expected format: [{"title": "...", "priority": "...", "column": "..."}]'));
2046
+ return;
2047
+ }
2048
+ const data = (0, data_1.loadData)();
2049
+ let projectId;
2050
+ if (opts.project) {
2051
+ const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
2052
+ if (!p) {
2053
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
2054
+ return;
2055
+ }
2056
+ projectId = p.id;
2057
+ }
2058
+ else if (data.projects.length > 0) {
2059
+ projectId = data.projects[0].id;
2060
+ }
2061
+ else {
2062
+ const dp = { id: crypto_1.default.randomUUID(), name: 'Default Project', path: process.cwd(), agents: [], createdAt: new Date().toISOString() };
2063
+ data.projects.push(dp);
2064
+ projectId = dp.id;
2065
+ }
2066
+ const now = new Date().toISOString();
2067
+ let count = 0;
2068
+ for (const t of tasks) {
2069
+ const col = t.column || 'backlog';
2070
+ const ct = data.tasks.filter(tk => tk.column === col && tk.projectId === projectId);
2071
+ const mo = ct.length > 0 ? Math.max(...ct.map(tk => tk.order)) : -1;
2072
+ const task = {
2073
+ id: crypto_1.default.randomUUID(), projectId: projectId,
2074
+ title: String(t.title || '').trim(),
2075
+ description: String(t.description || '').trim(),
2076
+ column: col, order: mo + 1,
2077
+ priority: t.priority || 'medium',
2078
+ agent: opts.agent || t.agent || '',
2079
+ skill: opts.skill || t.skill || '',
2080
+ createdAt: now, updatedAt: now,
2081
+ };
2082
+ data.tasks.push(task);
2083
+ count++;
2084
+ }
2085
+ (0, data_1.logActivity)(data, 'task_created', `Synced ${count} tasks from ${path_1.default.basename(filePath)}`, projectId, opts.agent || '', { count, file: filePath });
2086
+ (0, data_1.saveData)(data);
2087
+ const project = data.projects.find(p => p.id === projectId);
2088
+ console.log(chalk_1.default.green(`\n✅ Synced ${count} tasks!`));
2089
+ console.log(chalk_1.default.gray(` Project: ${(project === null || project === void 0 ? void 0 : project.name) || 'Default'}`));
2090
+ console.log(chalk_1.default.gray(` Source: ${filePath}`));
2091
+ if (opts.agent)
2092
+ console.log(chalk_1.default.gray(` Agent: ${opts.agent}`));
2093
+ console.log();
2094
+ });
2095
+ // ─── Chain Command ──────────────────────────────────────────────────────────
2096
+ // TRIZ #40 Composite Materials — skills compose into pipelines
2097
+ program
2098
+ .command('chain <cmd> [args...]')
2099
+ .alias('ch')
2100
+ .description('Skill chain pipelines (list|info|start|status|advance|skip|abort|auto|history)')
2101
+ .option('-p, --project <name>', 'Project name or ID')
2102
+ .option('--agent <agent>', 'Agent name', 'antigravity')
2103
+ .action((cmd, args, opts) => {
2104
+ switch (cmd) {
2105
+ case 'list':
2106
+ case 'ls':
2107
+ chainList();
2108
+ break;
2109
+ case 'info':
2110
+ chainInfo(args[0]);
2111
+ break;
2112
+ case 'start':
2113
+ chainStart(args[0], args.slice(1).join(' '), opts);
2114
+ break;
2115
+ case 'status':
2116
+ case 'st':
2117
+ chainStatus(args[0]);
2118
+ break;
2119
+ case 'advance':
2120
+ case 'next':
2121
+ chainAdvance(args[0], args.slice(1).join(' '));
2122
+ break;
2123
+ case 'skip':
2124
+ chainSkip(args[0], args.slice(1).join(' '));
2125
+ break;
2126
+ case 'abort':
2127
+ chainAbort(args[0], args.slice(1).join(' '));
2128
+ break;
2129
+ case 'auto':
2130
+ chainAuto(args.join(' '), opts);
2131
+ break;
2132
+ case 'history':
2133
+ case 'hist':
2134
+ chainHistory();
2135
+ break;
2136
+ default:
2137
+ console.log(chalk_1.default.red(`Unknown: ${cmd}`));
2138
+ console.log(chalk_1.default.gray('Available: list, info, start, status, advance, skip, abort, auto, history'));
2139
+ }
2140
+ });
2141
+ function chainList() {
2142
+ const chains = (0, skill_chain_1.listChains)();
2143
+ console.log(chalk_1.default.cyan('\n🔗 Available Skill Chains\n'));
2144
+ for (const chain of chains) {
2145
+ console.log(` ${chain.icon} ${chalk_1.default.white(padRight(chain.name, 24))} ${chalk_1.default.gray(chain.description)}`);
2146
+ console.log(chalk_1.default.gray(` ID: ${chain.id} | Steps: ${chain.steps.length} | Triggers: ${chain.triggers.slice(0, 4).join(', ')}...`));
2147
+ console.log();
2148
+ }
2149
+ console.log(chalk_1.default.gray(` Total: ${chains.length} chains\n`));
2150
+ console.log(chalk_1.default.cyan('💡 Quick start:'));
2151
+ console.log(chalk_1.default.gray(' cm chain auto "Build user authentication" # Auto-detect chain'));
2152
+ console.log(chalk_1.default.gray(' cm chain start feature-development "My task" # Start specific chain'));
2153
+ console.log();
2154
+ }
2155
+ function chainInfo(chainId) {
2156
+ if (!chainId) {
2157
+ console.log(chalk_1.default.red('❌ Usage: cm chain info <chain-id>'));
2158
+ return;
2159
+ }
2160
+ const chain = (0, skill_chain_1.findChain)(chainId);
2161
+ if (!chain) {
2162
+ console.log(chalk_1.default.red(`❌ Chain not found: ${chainId}`));
2163
+ console.log(chalk_1.default.gray(' Use "cm chain list" to see available chains.'));
2164
+ return;
2165
+ }
2166
+ console.log(chalk_1.default.cyan(`\n${chain.icon} Chain: ${chain.name}\n`));
2167
+ console.log(` ${chalk_1.default.white('ID:')} ${chain.id}`);
2168
+ console.log(` ${chalk_1.default.white('Description:')} ${chain.description}`);
2169
+ console.log(` ${chalk_1.default.white('Steps:')} ${chain.steps.length}`);
2170
+ console.log(` ${chalk_1.default.white('Triggers:')} ${chain.triggers.join(', ')}`);
2171
+ console.log();
2172
+ console.log(chalk_1.default.white(' Pipeline:'));
2173
+ for (let i = 0; i < chain.steps.length; i++) {
2174
+ const step = chain.steps[i];
2175
+ const condBadge = step.condition === 'always' ? chalk_1.default.green('ALWAYS') : step.condition === 'if-complex' ? chalk_1.default.yellow('IF-COMPLEX') : chalk_1.default.blue('IF-READY');
2176
+ const optBadge = step.optional ? chalk_1.default.gray(' (optional)') : '';
2177
+ const connector = i < chain.steps.length - 1 ? ' │' : ' ';
2178
+ console.log(` ${chalk_1.default.cyan(`${i + 1}.`)} ${padRight(step.skill, 24)} ${condBadge}${optBadge}`);
2179
+ console.log(chalk_1.default.gray(` ${connector} ${step.description}`));
2180
+ if (i < chain.steps.length - 1)
2181
+ console.log(chalk_1.default.gray(' │'));
2182
+ }
2183
+ console.log();
2184
+ }
2185
+ function chainStart(chainId, taskTitle, opts) {
2186
+ var _a, _b, _c;
2187
+ if (!chainId) {
2188
+ console.log(chalk_1.default.red('❌ Usage: cm chain start <chain-id> "Task title"'));
2189
+ return;
2190
+ }
2191
+ if (!taskTitle) {
2192
+ console.log(chalk_1.default.red('❌ Task title required. Usage: cm chain start <chain-id> "My task"'));
2193
+ return;
2194
+ }
2195
+ const chain = (0, skill_chain_1.findChain)(chainId);
2196
+ if (!chain) {
2197
+ console.log(chalk_1.default.red(`❌ Chain not found: ${chainId}`));
2198
+ return;
2199
+ }
2200
+ const data = (0, data_1.loadData)();
2201
+ let projectId;
2202
+ if (opts.project) {
2203
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
2204
+ if (!project) {
2205
+ console.log(chalk_1.default.red(`❌ Project not found: ${opts.project}`));
2206
+ return;
2207
+ }
2208
+ projectId = project.id;
2209
+ }
2210
+ else if (data.projects.length > 0) {
2211
+ projectId = data.projects[0].id;
2212
+ }
2213
+ else {
2214
+ console.log(chalk_1.default.red('❌ No projects. Create one first: cm init'));
2215
+ return;
2216
+ }
2217
+ const agent = opts.agent || 'antigravity';
2218
+ const execution = (0, skill_chain_1.createChainExecution)(chain, projectId, taskTitle, agent);
2219
+ data.chainExecutions.push(execution);
2220
+ // Create a task linked to this chain
2221
+ const now = new Date().toISOString();
2222
+ const task = {
2223
+ id: crypto_1.default.randomUUID(), projectId, title: taskTitle, description: `Chain: ${chain.name}`,
2224
+ column: 'in-progress', order: 0, priority: 'medium', agent, skill: ((_a = execution.steps[0]) === null || _a === void 0 ? void 0 : _a.skill) || '',
2225
+ createdAt: now, updatedAt: now, chainId: chain.id, chainExecutionId: execution.id,
2226
+ };
2227
+ data.tasks.push(task);
2228
+ (0, data_1.logActivity)(data, 'chain_started', `Chain "${chain.name}" started: "${taskTitle}"`, projectId, agent, {
2229
+ chainId: chain.id, executionId: execution.id, steps: chain.steps.length,
2230
+ });
2231
+ (0, data_1.saveData)(data);
2232
+ const project = data.projects.find(p => p.id === projectId);
2233
+ console.log(chalk_1.default.green(`\n🔗 Chain started!`));
2234
+ console.log(chalk_1.default.gray(` Chain: ${chain.icon} ${chain.name}`));
2235
+ console.log(chalk_1.default.gray(` Task: ${taskTitle}`));
2236
+ console.log(chalk_1.default.gray(` Project: ${(project === null || project === void 0 ? void 0 : project.name) || '—'}`));
2237
+ console.log(chalk_1.default.gray(` Agent: ${agent}`));
2238
+ console.log(chalk_1.default.gray(` Steps: ${chain.steps.length}`));
2239
+ console.log(chalk_1.default.gray(` Exec ID: ${(0, data_1.shortId)(execution.id)}`));
2240
+ console.log();
2241
+ console.log(chalk_1.default.cyan(` ▶ Current step: ${(_b = execution.steps[0]) === null || _b === void 0 ? void 0 : _b.skill} — ${(_c = execution.steps[0]) === null || _c === void 0 ? void 0 : _c.description}`));
2242
+ console.log();
2243
+ console.log(chalk_1.default.gray(` Next: cm chain advance ${(0, data_1.shortId)(execution.id)} "output summary"`));
2244
+ console.log();
2245
+ }
2246
+ function chainStatus(execIdPrefix) {
2247
+ const data = (0, data_1.loadData)();
2248
+ if (execIdPrefix) {
2249
+ // Show specific execution
2250
+ const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2251
+ if (!exec) {
2252
+ console.log(chalk_1.default.red(`❌ Chain execution not found: ${execIdPrefix}`));
2253
+ return;
2254
+ }
2255
+ console.log();
2256
+ console.log((0, skill_chain_1.formatChainProgress)(exec));
2257
+ console.log();
2258
+ return;
2259
+ }
2260
+ // Show all active executions
2261
+ const active = data.chainExecutions.filter(e => e.status === 'running' || e.status === 'paused');
2262
+ if (active.length === 0) {
2263
+ console.log(chalk_1.default.gray('\n No active chain executions.'));
2264
+ console.log(chalk_1.default.gray(' Start one with: cm chain auto "task description"\n'));
2265
+ return;
2266
+ }
2267
+ console.log(chalk_1.default.cyan(`\n🔗 Active Chains (${active.length})\n`));
2268
+ for (const exec of active) {
2269
+ const project = data.projects.find(p => p.id === exec.projectId);
2270
+ const currentSkill = (0, skill_chain_1.getCurrentSkill)(exec);
2271
+ const progressBar = (0, skill_chain_1.formatChainProgressBar)(exec);
2272
+ console.log(` ${chalk_1.default.white(exec.chainName)} — "${exec.taskTitle}"`);
2273
+ console.log(chalk_1.default.gray(` ${progressBar} | Step ${exec.currentStepIndex + 1}/${exec.steps.length}: ${currentSkill || 'done'}`));
2274
+ console.log(chalk_1.default.gray(` ID: ${(0, data_1.shortId)(exec.id)} | Agent: ${exec.agent} | Project: ${(project === null || project === void 0 ? void 0 : project.name) || '—'}`));
2275
+ console.log();
2276
+ }
2277
+ }
2278
+ function chainAdvance(execIdPrefix, output) {
2279
+ if (!execIdPrefix) {
2280
+ console.log(chalk_1.default.red('❌ Usage: cm chain advance <exec-id> ["output summary"]'));
2281
+ return;
2282
+ }
2283
+ const data = (0, data_1.loadData)();
2284
+ const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2285
+ if (!exec) {
2286
+ console.log(chalk_1.default.red(`❌ Chain execution not found: ${execIdPrefix}`));
2287
+ return;
2288
+ }
2289
+ if (exec.status !== 'running') {
2290
+ console.log(chalk_1.default.yellow(`⚠️ Chain is ${exec.status}, cannot advance.`));
2291
+ return;
2292
+ }
2293
+ const completedStep = exec.steps[exec.currentStepIndex];
2294
+ const result = (0, skill_chain_1.advanceChain)(exec, output);
2295
+ // Update linked task's current skill
2296
+ const linkedTask = data.tasks.find(t => t.chainExecutionId === exec.id);
2297
+ if (linkedTask && result.nextSkill) {
2298
+ linkedTask.skill = result.nextSkill;
2299
+ linkedTask.updatedAt = new Date().toISOString();
2300
+ }
2301
+ if (result.completed) {
2302
+ if (linkedTask) {
2303
+ linkedTask.column = 'review';
2304
+ linkedTask.updatedAt = new Date().toISOString();
2305
+ }
2306
+ (0, data_1.logActivity)(data, 'chain_completed', `Chain "${exec.chainName}" completed: "${exec.taskTitle}"`, exec.projectId, exec.agent, {
2307
+ executionId: exec.id, totalSteps: exec.steps.length,
2308
+ });
2309
+ (0, data_1.saveData)(data);
2310
+ console.log(chalk_1.default.green(`\n✅ Chain completed! All ${exec.steps.length} steps done.`));
2311
+ console.log(chalk_1.default.gray(` Chain: ${exec.chainName}`));
2312
+ console.log(chalk_1.default.gray(` Task: ${exec.taskTitle}`));
2313
+ console.log();
2314
+ }
2315
+ else {
2316
+ (0, data_1.logActivity)(data, 'chain_step_completed', `Chain step completed: ${completedStep === null || completedStep === void 0 ? void 0 : completedStep.skill} → next: ${result.nextSkill}`, exec.projectId, exec.agent, {
2317
+ executionId: exec.id, completedSkill: completedStep === null || completedStep === void 0 ? void 0 : completedStep.skill, nextSkill: result.nextSkill,
2318
+ });
2319
+ (0, data_1.saveData)(data);
2320
+ const nextStep = exec.steps[exec.currentStepIndex];
2321
+ console.log(chalk_1.default.green(`\n✅ Step completed: ${completedStep === null || completedStep === void 0 ? void 0 : completedStep.skill}`));
2322
+ console.log(chalk_1.default.cyan(` ▶ Next step: ${result.nextSkill} — ${nextStep === null || nextStep === void 0 ? void 0 : nextStep.description}`));
2323
+ console.log(chalk_1.default.gray(` Progress: ${(0, skill_chain_1.formatChainProgressBar)(exec)}`));
2324
+ console.log();
2325
+ }
2326
+ }
2327
+ function chainSkip(execIdPrefix, reason) {
2328
+ if (!execIdPrefix) {
2329
+ console.log(chalk_1.default.red('❌ Usage: cm chain skip <exec-id> ["reason"]'));
2330
+ return;
2331
+ }
2332
+ const data = (0, data_1.loadData)();
2333
+ const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2334
+ if (!exec) {
2335
+ console.log(chalk_1.default.red(`❌ Chain execution not found: ${execIdPrefix}`));
2336
+ return;
2337
+ }
2338
+ if (exec.status !== 'running') {
2339
+ console.log(chalk_1.default.yellow(`⚠️ Chain is ${exec.status}, cannot skip.`));
2340
+ return;
2341
+ }
2342
+ const skippedStep = exec.steps[exec.currentStepIndex];
2343
+ const result = (0, skill_chain_1.skipChainStep)(exec, reason);
2344
+ (0, data_1.saveData)(data);
2345
+ console.log(chalk_1.default.yellow(` ⏭️ Skipped: ${skippedStep === null || skippedStep === void 0 ? void 0 : skippedStep.skill}`));
2346
+ if (result.completed) {
2347
+ console.log(chalk_1.default.green(` ✅ Chain completed!`));
2348
+ }
2349
+ else {
2350
+ console.log(chalk_1.default.cyan(` ▶ Next: ${result.nextSkill}`));
2351
+ }
2352
+ console.log();
2353
+ }
2354
+ function chainAbort(execIdPrefix, reason) {
2355
+ if (!execIdPrefix) {
2356
+ console.log(chalk_1.default.red('❌ Usage: cm chain abort <exec-id> ["reason"]'));
2357
+ return;
2358
+ }
2359
+ const data = (0, data_1.loadData)();
2360
+ const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2361
+ if (!exec) {
2362
+ console.log(chalk_1.default.red(`❌ Chain execution not found: ${execIdPrefix}`));
2363
+ return;
2364
+ }
2365
+ if (exec.status !== 'running' && exec.status !== 'paused') {
2366
+ console.log(chalk_1.default.yellow(`⚠️ Chain already ${exec.status}.`));
2367
+ return;
2368
+ }
2369
+ (0, skill_chain_1.abortChain)(exec, reason);
2370
+ (0, data_1.logActivity)(data, 'chain_aborted', `Chain "${exec.chainName}" aborted: ${reason || 'no reason'}`, exec.projectId, exec.agent, {
2371
+ executionId: exec.id,
2372
+ });
2373
+ (0, data_1.saveData)(data);
2374
+ console.log(chalk_1.default.red(`\n🛑 Chain aborted: ${exec.chainName}`));
2375
+ if (reason)
2376
+ console.log(chalk_1.default.gray(` Reason: ${reason}`));
2377
+ console.log();
2378
+ }
2379
+ function chainAuto(taskTitle, opts) {
2380
+ if (!taskTitle) {
2381
+ console.log(chalk_1.default.red('❌ Usage: cm chain auto "task description"'));
2382
+ console.log(chalk_1.default.gray(' Example: cm chain auto "Build user authentication"'));
2383
+ return;
2384
+ }
2385
+ const chain = (0, skill_chain_1.matchChain)(taskTitle);
2386
+ if (!chain) {
2387
+ console.log(chalk_1.default.yellow(`\n⚠️ No matching chain found for: "${taskTitle}"`));
2388
+ console.log(chalk_1.default.gray(' Available chains:'));
2389
+ for (const c of (0, skill_chain_1.listChains)()) {
2390
+ console.log(chalk_1.default.gray(` ${c.icon} ${c.id}: ${c.triggers.slice(0, 3).join(', ')}...`));
2391
+ }
2392
+ console.log(chalk_1.default.gray('\n Use "cm chain start <chain-id> <title>" to start manually.'));
2393
+ return;
2394
+ }
2395
+ console.log(chalk_1.default.cyan(`\n🤖 Auto-detected chain: ${chain.icon} ${chain.name}`));
2396
+ console.log(chalk_1.default.gray(` Matched from: "${taskTitle}"`));
2397
+ console.log();
2398
+ // Delegate to chainStart
2399
+ chainStart(chain.id, taskTitle, opts);
2400
+ }
2401
+ function chainHistory() {
2402
+ const data = (0, data_1.loadData)();
2403
+ const execs = data.chainExecutions;
2404
+ if (execs.length === 0) {
2405
+ console.log(chalk_1.default.gray('\n No chain executions yet.\n'));
2406
+ return;
2407
+ }
2408
+ const STATUS_ICONS = {
2409
+ pending: '⚪', running: '🔵', paused: '⏸️', completed: '✅', failed: '❌', aborted: '🛑',
2410
+ };
2411
+ console.log(chalk_1.default.cyan(`\n🔗 Chain History (${execs.length})\n`));
2412
+ console.log(chalk_1.default.gray(' ' + padRight('Status', 8) + padRight('Chain', 24) + padRight('Task', 30) + padRight('Progress', 14) + 'Time'));
2413
+ console.log(chalk_1.default.gray(' ' + '─'.repeat(86)));
2414
+ for (const exec of execs.slice(0, 20)) {
2415
+ const icon = STATUS_ICONS[exec.status] || '❓';
2416
+ const completed = exec.steps.filter(s => s.status === 'completed' || s.status === 'skipped').length;
2417
+ const progress = `${completed}/${exec.steps.length} steps`;
2418
+ const time = formatTimeAgoCli(exec.startedAt);
2419
+ console.log(' ' + padRight(icon, 8) + padRight(exec.chainName.substring(0, 22), 24) + padRight(exec.taskTitle.substring(0, 28), 30) + chalk_1.default.gray(padRight(progress, 14)) + chalk_1.default.gray(time));
2420
+ }
2421
+ console.log();
2422
+ }
2423
+ // ─── Parse ──────────────────────────────────────────────────────────────────
2424
+ // Auto-start dashboard in background for project commands
2425
+ // Skip for: add, list, install, help, version, --help, -v
2426
+ const SKIP_DASHBOARD_CMDS = new Set(['add', 'list', 'ls', 'install', 'help', '--help', '-h', '-v', '--version', 'version']);
2427
+ const firstArg = process.argv[2] || '';
2428
+ if (!SKIP_DASHBOARD_CMDS.has(firstArg) && firstArg !== '' && !firstArg.startsWith('-')) {
2429
+ if (!isDashboardRunning()) {
2430
+ // Silent background start — no banner, just ensure it's running
2431
+ (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, true);
2432
+ }
2433
+ }
2434
+ program.parse(process.argv);