codymaster 4.5.4 β†’ 4.8.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 (133) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/README.md +86 -31
  3. package/dist/backends/viking-backend.js +235 -0
  4. package/dist/backends/viking-http-client.js +176 -0
  5. package/dist/browse-server.js +251 -0
  6. package/dist/cli/command-registry.js +26 -0
  7. package/dist/cli/commands/agent.js +120 -0
  8. package/dist/cli/commands/dashboard.js +93 -0
  9. package/dist/cli/commands/design-studio.js +111 -0
  10. package/dist/cli/commands/distro.js +25 -0
  11. package/dist/cli/commands/engineering.js +488 -0
  12. package/dist/cli/commands/project.js +324 -0
  13. package/dist/cli/commands/skill-chain.js +269 -0
  14. package/dist/cli/commands/system.js +89 -0
  15. package/dist/cli/commands/task.js +254 -0
  16. package/dist/cli/update-check.js +83 -0
  17. package/dist/cm-config.js +110 -0
  18. package/dist/cm-suggest.js +77 -0
  19. package/dist/continuity.js +8 -0
  20. package/dist/distro-validate.js +54 -0
  21. package/dist/guardian-core.js +74 -0
  22. package/dist/index.js +36 -2759
  23. package/dist/mcp-context-server.js +60 -1
  24. package/dist/mcp-skills-tools.js +81 -0
  25. package/dist/retro-summary.js +70 -0
  26. package/dist/second-opinion-providers.js +79 -0
  27. package/dist/sprint-pipeline.js +228 -0
  28. package/dist/storage-backend.js +63 -0
  29. package/dist/utils/cli-utils.js +76 -0
  30. package/dist/utils/skill-utils.js +32 -0
  31. package/install.sh +286 -58
  32. package/package.json +16 -5
  33. package/scripts/build-skills.mjs +51 -0
  34. package/scripts/gate-0-repo-hygiene.js +75 -0
  35. package/scripts/postinstall.js +56 -1
  36. package/scripts/security-scan.js +1 -1
  37. package/scripts/validate-skills.mjs +42 -0
  38. package/scripts/viking-demo.ts +105 -0
  39. package/skills/CLAUDE.md +2 -2
  40. package/skills/_shared/helpers.md +10 -0
  41. package/skills/cm-ads-tracker/SKILL.md +3 -6
  42. package/skills/cm-browse/SKILL.md +28 -0
  43. package/skills/cm-conductor-worktrees/SKILL.md +24 -0
  44. package/skills/cm-content-factory/SKILL.md +1 -1
  45. package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
  46. package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
  47. package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
  48. package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
  49. package/skills/cm-content-factory/landing/docs/content/openviking.md +33 -0
  50. package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
  51. package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
  52. package/skills/cm-content-factory/landing/docs/index.html +240 -0
  53. package/skills/cm-content-factory/landing/index.html +99 -99
  54. package/skills/cm-content-factory/landing/script.js +42 -0
  55. package/skills/cm-content-factory/landing/translations.js +400 -400
  56. package/skills/cm-continuity/SKILL.md +33 -6
  57. package/skills/cm-design-studio/SKILL.md +30 -0
  58. package/skills/cm-ecosystem-roadmap/SKILL.md +11 -0
  59. package/skills/cm-engineering-meta/SKILL.md +69 -0
  60. package/skills/cm-growth-hacking/SKILL.md +1 -12
  61. package/skills/cm-guardian-runtime/SKILL.md +22 -0
  62. package/skills/cm-mcp-engineering/SKILL.md +18 -0
  63. package/skills/cm-notebooklm/SKILL.md +1 -17
  64. package/skills/cm-post-deploy-canary/SKILL.md +18 -0
  65. package/skills/cm-qa-visual-cli/SKILL.md +18 -0
  66. package/skills/cm-retro-cli/SKILL.md +19 -0
  67. package/skills/cm-second-opinion-cli/SKILL.md +19 -0
  68. package/skills/cm-secret-shield/SKILL.md +2 -2
  69. package/skills/cm-sprint-bus/SKILL.md +29 -0
  70. package/skills/cm-start/SKILL.md +11 -2
  71. package/skills/cm-tdd/SKILL.md +61 -74
  72. package/skills/profiles/README.md +21 -0
  73. package/skills/profiles/core.txt +23 -0
  74. package/skills/profiles/design.txt +6 -0
  75. package/skills/profiles/full.txt +58 -0
  76. package/skills/profiles/growth.txt +10 -0
  77. package/skills/profiles/knowledge.txt +7 -0
  78. package/scripts/test-gemini.js +0 -13
  79. package/skills/cm-frappe-agent/SKILL.md +0 -134
  80. package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
  81. package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
  82. package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
  83. package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
  84. package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
  85. package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
  86. package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
  87. package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
  88. package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
  89. package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
  90. package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
  91. package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
  92. package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
  93. package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
  94. package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
  95. package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
  96. package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
  97. package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
  98. package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
  99. package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
  100. package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
  101. package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
  102. package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
  103. package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
  104. package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
  105. package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
  106. package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
  107. package/skills/cm-frappe-agent/docs/README.md +0 -51
  108. package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
  109. package/skills/cm-frappe-agent/docs/architecture.md +0 -149
  110. package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
  111. package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
  112. package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
  113. package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
  114. package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
  115. package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
  116. package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
  117. package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
  118. package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
  119. package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
  120. package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
  121. package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
  122. package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
  123. package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
  124. package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
  125. package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
  126. package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
  127. package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
  128. package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
  129. package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
  130. package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
  131. package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
  132. package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
  133. package/skills/frappe-app-builder.zip +0 -0
package/dist/index.js CHANGED
@@ -1,38 +1,5 @@
1
1
  #!/usr/bin/env node
2
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
3
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
4
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
5
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -47,2733 +14,43 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
47
14
  };
48
15
  Object.defineProperty(exports, "__esModule", { value: true });
49
16
  const commander_1 = require("commander");
50
- const chalk_1 = __importDefault(require("chalk"));
51
- const crypto_1 = __importDefault(require("crypto"));
52
17
  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 l0_indexer_1 = require("./l0-indexer");
58
- const context_bus_1 = require("./context-bus");
59
- const token_budget_1 = require("./token-budget");
60
- const migrate_json_to_sqlite_1 = require("./migrate-json-to-sqlite");
61
- const uri_resolver_1 = require("./uri-resolver");
62
- const judge_1 = require("./judge");
63
- const skill_chain_1 = require("./skill-chain");
64
18
  const path_1 = __importDefault(require("path"));
65
- const os_1 = __importDefault(require("os"));
66
- const https_1 = __importDefault(require("https"));
67
- // 🐹 Hamster Shell UI modules
68
- const theme_1 = require("./ui/theme");
69
- const box_1 = require("./ui/box");
70
- const hamster_1 = require("./ui/hamster");
71
- const hooks_1 = require("./ui/hooks");
72
- const onboarding_1 = require("./ui/onboarding");
73
- const VERSION = require('../package.json').version;
74
- let ALL_SKILLS = [];
75
- try {
76
- const distSkillsDir = path_1.default.join(__dirname, '..', 'skills');
77
- if (fs_1.default.existsSync(distSkillsDir)) {
78
- ALL_SKILLS = fs_1.default.readdirSync(distSkillsDir).filter(f => {
79
- const fullPath = path_1.default.join(distSkillsDir, f);
80
- return fs_1.default.statSync(fullPath).isDirectory() && fs_1.default.existsSync(path_1.default.join(fullPath, 'SKILL.md'));
81
- });
82
- }
83
- }
84
- catch (e) {
85
- // Silent fallback
86
- }
87
- if (ALL_SKILLS.length === 0) {
88
- ALL_SKILLS = [
89
- 'cm-tdd', 'cm-debugging', 'cm-quality-gate', 'cm-test-gate', 'cm-code-review',
90
- 'cm-safe-deploy', 'cm-identity-guard', 'cm-git-worktrees', 'cm-terminal', 'cm-secret-shield', 'cm-security-gate', 'cm-safe-i18n',
91
- 'cm-planning', 'cm-ux-master', 'cm-ui-preview', 'cm-brainstorm-idea', 'cm-jtbd', 'cm-dockit', 'cm-project-bootstrap', 'cm-readit',
92
- 'cm-content-factory', 'cm-ads-tracker', 'cro-methodology', 'cm-deep-search',
93
- 'cm-execution', 'cm-continuity', 'cm-skill-index', 'cm-skill-mastery', 'cm-skill-chain',
94
- 'cm-start', 'cm-dashboard', 'cm-status', 'cm-how-it-work', 'cm-example',
95
- ];
96
- }
97
- const SKILL_COUNT = ALL_SKILLS.length;
98
- // ─── Update Check ───────────────────────────────────────────────────────────
99
- let _updateMessage = '';
100
- function checkForUpdates() {
19
+ const update_check_1 = require("./cli/update-check");
20
+ const command_registry_1 = require("./cli/command-registry");
21
+ // Load version from package.json
22
+ const pkg = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', 'package.json'), 'utf-8'));
23
+ const VERSION = pkg.version;
24
+ function main() {
101
25
  return __awaiter(this, void 0, void 0, function* () {
102
- try {
103
- const cacheDir = path_1.default.join(os_1.default.homedir(), '.codymaster');
104
- const cacheFile = path_1.default.join(cacheDir, '.update-check');
105
- // Check cache (24h TTL)
106
- try {
107
- if (fs_1.default.existsSync(cacheFile)) {
108
- const stat = fs_1.default.statSync(cacheFile);
109
- const age = Date.now() - stat.mtimeMs;
110
- if (age < 24 * 60 * 60 * 1000) {
111
- const cached = fs_1.default.readFileSync(cacheFile, 'utf-8').trim();
112
- if (cached && cached !== VERSION) {
113
- _updateMessage = cached;
114
- }
115
- return;
116
- }
117
- }
118
- }
119
- catch ( /* ignore cache errors */_a) { /* ignore cache errors */ }
120
- // Fetch latest version from npm (2s timeout)
121
- const latestVersion = yield new Promise((resolve, reject) => {
122
- const timer = setTimeout(() => reject(new Error('timeout')), 2000);
123
- https_1.default.get('https://registry.npmjs.org/codymaster/latest', { headers: { 'Accept': 'application/json' } }, (res) => {
124
- let data = '';
125
- res.on('data', (chunk) => { data += chunk; });
126
- res.on('end', () => {
127
- clearTimeout(timer);
128
- try {
129
- const json = JSON.parse(data);
130
- resolve(json.version || VERSION);
131
- }
132
- catch (_a) {
133
- resolve(VERSION);
134
- }
135
- });
136
- }).on('error', () => { clearTimeout(timer); reject(new Error('fetch failed')); });
137
- });
138
- // Cache result
139
- try {
140
- if (!fs_1.default.existsSync(cacheDir))
141
- fs_1.default.mkdirSync(cacheDir, { recursive: true });
142
- fs_1.default.writeFileSync(cacheFile, latestVersion);
143
- }
144
- catch ( /* ignore */_b) { /* ignore */ }
145
- if (latestVersion !== VERSION) {
146
- _updateMessage = latestVersion;
147
- }
148
- }
149
- catch ( /* silently skip β€” offline or timeout */_c) { /* silently skip β€” offline or timeout */ }
150
- });
151
- }
152
- function printUpdateNotice() {
153
- if (_updateMessage) {
154
- console.log(chalk_1.default.yellow(` ⚠️ Update available: ${VERSION} β†’ ${_updateMessage}`) + chalk_1.default.gray(' Run: ') + chalk_1.default.cyan('npm i -g codymaster'));
155
- }
156
- }
157
- // ─── Branding ───────────────────────────────────────────────────────────────
158
- function showBanner() {
159
- const cPath = process.cwd().replace(os_1.default.homedir(), '~');
160
- const profile = (0, hooks_1.loadProfile)();
161
- console.log((0, hamster_1.renderHamsterBanner)(profile.userName || undefined, VERSION, cPath, SKILL_COUNT));
162
- printUpdateNotice();
163
- }
164
- // ─── Utility ────────────────────────────────────────────────────────────────
165
- // Color maps now imported from ./ui/theme (COL, PRI, STATUS)
166
- const COL_COLORS = theme_1.COL;
167
- const PRIORITY_COLORS = theme_1.PRI;
168
- const STATUS_COLORS = theme_1.STATUS;
169
- function padRight(str, len) {
170
- return str.length >= len ? str.substring(0, len) : str + ' '.repeat(len - str.length);
171
- }
172
- function openUrl(url) {
173
- const { execFile } = require('child_process');
174
- const [cmd, ...args] = process.platform === 'darwin' ? ['open', url] :
175
- process.platform === 'win32' ? ['cmd', '/c', 'start', url] :
176
- ['xdg-open', url];
177
- execFile(cmd, args, () => { });
178
- }
179
- // ─── Post-install Onboarding ─────────────────────────────────────────────────
180
- function postInstallOnboarding(platform) {
181
- return __awaiter(this, void 0, void 0, function* () {
182
- // Run the self-onboarding wizard
183
- const profile = (0, hooks_1.loadProfile)();
184
- if (!profile.onboardingComplete) {
185
- // Set platform from install if not already set
186
- if (platform && !profile.platform) {
187
- profile.platform = platform;
188
- (0, hooks_1.saveProfile)(profile);
189
- }
190
- yield (0, onboarding_1.runOnboarding)(VERSION);
191
- }
192
- else {
193
- // Already onboarded β€” show returning welcome
194
- const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
195
- console.log('');
196
- console.log((0, hamster_1.getHamsterArt)('celebrating'));
197
- console.log('');
198
- console.log(` ${(0, theme_1.success)('πŸŽ‰')} ${(0, theme_1.brandBold)(`Welcome back, ${profile.userName || 'friend'}!`)}`);
199
- console.log('');
200
- const action = yield p.select({
201
- message: 'What would you like to do?',
202
- options: [
203
- { label: `${theme_1.ICONS.dashboard} Launch Dashboard`, value: 'dashboard', hint: `localhost:${data_1.DEFAULT_PORT}` },
204
- { label: `${theme_1.ICONS.skill} Browse all ${SKILL_COUNT} skills`, value: 'skills' },
205
- { label: `${theme_1.ICONS.deploy} Start with your AI`, value: 'invoke', hint: profile.platform || 'any agent' },
206
- { label: `${(0, theme_1.success)('βœ“')} Done`, value: 'done' },
207
- ],
208
- });
209
- if (p.isCancel(action))
210
- return;
211
- switch (action) {
212
- case 'dashboard':
213
- if (!isDashboardRunning()) {
214
- (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
215
- yield new Promise(r => setTimeout(r, 800));
216
- }
217
- console.log((0, theme_1.info)(`\n 🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...\n`));
218
- openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
219
- break;
220
- case 'skills':
221
- console.log('');
222
- skillList();
223
- break;
224
- case 'invoke':
225
- console.log('');
226
- const invoke = profile.platform === 'claude' ? '/cm:demo' :
227
- profile.platform === 'gemini' ? '@[/cm-planning]' :
228
- '@cm-planning';
229
- console.log(` ${(0, theme_1.brand)('β†’')} Type ${(0, theme_1.brandBold)(invoke)} in your AI agent\n`);
230
- break;
231
- default:
232
- console.log((0, theme_1.dim)('\n Run cm any time! 🐹\n'));
233
- }
234
- }
235
- });
236
- }
237
- // ─── Interactive Quick Menu (no-args entry point) ─────────────────────────────
238
- function showInteractiveMenu() {
239
- return __awaiter(this, void 0, void 0, function* () {
240
- const profile = (0, hooks_1.loadProfile)();
241
- // 🎳 First Run β†’ Start onboarding wizard
242
- if (!profile.onboardingComplete) {
243
- yield (0, onboarding_1.runOnboarding)(VERSION);
244
- return;
245
- }
246
- // πŸͺ Hook: Record command + check achievements
247
- (0, hooks_1.recordCommand)(profile, 'menu');
248
- const newAchievements = (0, hooks_1.checkAchievements)(profile);
249
- (0, hooks_1.saveProfile)(profile);
250
- // Show banner with hamster
251
- showBanner();
252
- // πŸͺ Hook: Contextual trigger
253
- const data = (0, data_1.loadData)();
254
- const taskCounts = {
255
- tasksInProgress: data.tasks.filter(t => t.column === 'in-progress').length,
256
- tasksInReview: data.tasks.filter(t => t.column === 'review').length,
257
- tasksDone: data.tasks.filter(t => t.column === 'done').length,
258
- totalTasks: data.tasks.length,
259
- };
260
- const trigger = (0, hooks_1.getContextualTrigger)(profile, taskCounts);
261
- console.log(` ${(0, theme_1.brand)(theme_1.ICONS.hamster)} ${(0, theme_1.dim)(trigger)}`);
262
- // Dashboard status
263
- const dashStatus = isDashboardRunning()
264
- ? (0, theme_1.success)(`${theme_1.ICONS.dot} RUNNING`) + (0, theme_1.dim)(` http://localhost:${data_1.DEFAULT_PORT}`)
265
- : (0, theme_1.muted)(`${theme_1.ICONS.dotEmpty} stopped`);
266
- console.log(` ${(0, theme_1.dim)('Dashboard:')} ${dashStatus}`);
267
- console.log('');
268
- // Show new achievements
269
- for (const id of newAchievements) {
270
- console.log((0, hooks_1.formatAchievement)(id));
271
- }
272
- if (newAchievements.length > 0)
273
- console.log('');
274
- // Level indicator
275
- console.log(` ${(0, theme_1.dim)('Level:')} ${(0, hooks_1.getLevelDisplay)(profile.level)} ${(0, theme_1.dim)('β€’')} ${(0, theme_1.dim)('Streak:')} ${profile.streak > 0 ? (0, theme_1.brand)(`${theme_1.ICONS.fire} ${profile.streak}d`) : (0, theme_1.muted)('β€”')}`);
276
- console.log('');
277
- // Quick menu with @clack/prompts
278
- const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
279
- const action = yield p.select({
280
- message: 'Quick menu',
281
- options: [
282
- { label: `${theme_1.ICONS.dashboard} Dashboard`, value: 'dashboard', hint: isDashboardRunning() ? 'Open' : 'Start & open' },
283
- { label: `${theme_1.ICONS.task} My Tasks`, value: 'tasks', hint: `${taskCounts.totalTasks} total` },
284
- { label: `πŸ“ˆ Status`, value: 'status', hint: 'Health snapshot' },
285
- { label: `${theme_1.ICONS.skill} Browse Skills`, value: 'skills', hint: `${SKILL_COUNT} skills` },
286
- { label: `βž• Add a Task`, value: 'addtask', hint: 'Quick add' },
287
- { label: `⚑ Install Skills`, value: 'install', hint: 'Update all' },
288
- { label: `${theme_1.ICONS.hamster} My Profile`, value: 'profile', hint: `${profile.level}` },
289
- { label: `❓ Help`, value: 'help' },
290
- ],
291
- });
292
- if (p.isCancel(action)) {
293
- console.log((0, theme_1.dim)('\n See you soon! 🐹\n'));
294
- return;
295
- }
296
- console.log('');
297
- switch (action) {
298
- case 'dashboard':
299
- if (!isDashboardRunning()) {
300
- (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, false);
301
- yield new Promise(r => setTimeout(r, 800));
302
- }
303
- console.log((0, theme_1.info)(` 🌐 Opening http://localhost:${data_1.DEFAULT_PORT} ...`));
304
- openUrl(`http://localhost:${data_1.DEFAULT_PORT}`);
305
- console.log((0, theme_1.dim)(' Dashboard is running. Ctrl+C to stop.\n'));
306
- break;
307
- case 'tasks':
308
- require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'list'], { stdio: 'inherit' });
309
- break;
310
- case 'status':
311
- require('child_process').spawnSync(process.execPath, [process.argv[1], 'status'], { stdio: 'inherit' });
312
- break;
313
- case 'skills':
314
- skillList();
315
- break;
316
- case 'addtask': {
317
- const title = yield p.text({
318
- message: 'Task title:',
319
- placeholder: 'What are you working on?',
320
- validate: (val) => {
321
- if (!val || val.trim().length === 0)
322
- return 'Give your task a title!';
323
- return undefined;
324
- },
325
- });
326
- if (!p.isCancel(title) && title) {
327
- require('child_process').spawnSync(process.execPath, [process.argv[1], 'task', 'add', title], { stdio: 'inherit' });
328
- }
329
- break;
330
- }
331
- case 'install':
332
- console.log(` ${(0, theme_1.brand)('β†’')} Run: ${(0, theme_1.brandBold)('bash <(curl -fsSL https://raw.githubusercontent.com/tody-agent/codymaster/main/install.sh) --all')}\n`);
333
- break;
334
- case 'profile':
335
- console.log((0, hooks_1.formatProfileSummary)(profile));
336
- break;
337
- case 'help':
338
- default: {
339
- const helpItems = [
340
- `${(0, theme_1.brand)('cm')} ${(0, theme_1.dim)('Quick menu')}`,
341
- `${(0, theme_1.brand)('cm task add')} ${(0, theme_1.dim)('"..."')} ${(0, theme_1.dim)('Add a task')}`,
342
- `${(0, theme_1.brand)('cm task list')} ${(0, theme_1.dim)('View tasks')}`,
343
- `${(0, theme_1.brand)('cm status')} ${(0, theme_1.dim)('Project health')}`,
344
- `${(0, theme_1.brand)('cm dashboard')} ${(0, theme_1.dim)('Mission Control')}`,
345
- `${(0, theme_1.brand)('cm list')} ${(0, theme_1.dim)(`Browse ${SKILL_COUNT} skills`)}`,
346
- `${(0, theme_1.brand)('cm deploy')} ${(0, theme_1.dim)('<env>')} ${(0, theme_1.dim)('Record deploy')}`,
347
- `${(0, theme_1.brand)('cm profile')} ${(0, theme_1.dim)('Your stats')}`,
348
- ];
349
- console.log((0, box_1.renderBox)(helpItems, { title: 'Commands', width: 52 }));
350
- console.log('');
351
- }
352
- }
353
- });
354
- }
355
- // ─── Program ────────────────────────────────────────────────────────────────
356
- const program = new commander_1.Command();
357
- program
358
- .name('cm')
359
- .description(`Cody β€” ${SKILL_COUNT} Skills. Ship 10x faster.`)
360
- .version(VERSION, '-v, --version', 'Show version')
361
- .argument('[cmd]', 'Command to run', '')
362
- .action((cmd) => __awaiter(void 0, void 0, void 0, function* () {
363
- if (cmd && cmd !== 'help') {
364
- console.log(chalk_1.default.red(`\n ❌ Unknown command: ${cmd}\n`));
365
- program.help();
366
- return;
367
- }
368
- else if (cmd === 'help') {
369
- program.help();
370
- return;
371
- }
372
- // Interactive quick menu (Amp-style)
373
- yield showInteractiveMenu();
374
- }));
375
- // ─── Dashboard Command ─────────────────────────────────────────────────────
376
- program
377
- .command('dashboard [cmd]')
378
- .alias('dash')
379
- .description('Dashboard server (start|stop|status|open)')
380
- .option('-p, --port <port>', 'Port number', String(data_1.DEFAULT_PORT))
381
- .action((cmd, opts) => {
382
- const port = parseInt(opts.port) || data_1.DEFAULT_PORT;
383
- switch (cmd) {
384
- case 'start':
385
- case undefined:
386
- if (isDashboardRunning()) {
387
- console.log((0, box_1.renderResult)('warning', 'Dashboard already running.', [`${(0, theme_1.dim)('URL:')} ${(0, theme_1.brand)(`http://localhost:${port}`)}`]));
388
- return;
389
- }
390
- (0, dashboard_1.launchDashboard)(port);
391
- break;
392
- case 'stop':
393
- stopDashboard();
394
- break;
395
- case 'status':
396
- dashboardStatus(port);
397
- break;
398
- case 'open':
399
- console.log((0, box_1.renderResult)('info', `Opening http://localhost:${port} ...`));
400
- openUrl(`http://localhost:${port}`);
401
- break;
402
- case 'url':
403
- console.log(`http://localhost:${port}`);
404
- break;
405
- default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: start, stop, status, open, url')]));
406
- }
407
- });
408
- function isDashboardRunning() {
409
- try {
410
- if (!fs_1.default.existsSync(data_1.PID_FILE))
411
- return false;
412
- const pid = parseInt(fs_1.default.readFileSync(data_1.PID_FILE, 'utf-8').trim());
413
- process.kill(pid, 0);
414
- return true;
415
- }
416
- catch (_a) {
417
- try {
418
- fs_1.default.unlinkSync(data_1.PID_FILE);
419
- }
420
- catch (_b) { }
421
- return false;
422
- }
423
- }
424
- function stopDashboard() {
425
- try {
426
- if (!fs_1.default.existsSync(data_1.PID_FILE)) {
427
- console.log((0, box_1.renderResult)('warning', 'No dashboard running.'));
428
- return;
429
- }
430
- const pid = parseInt(fs_1.default.readFileSync(data_1.PID_FILE, 'utf-8').trim());
431
- process.kill(pid, 'SIGTERM');
432
- try {
433
- fs_1.default.unlinkSync(data_1.PID_FILE);
434
- }
435
- catch (_a) { }
436
- console.log((0, box_1.renderResult)('success', `Dashboard stopped (PID ${pid}).`));
437
- }
438
- catch (err) {
439
- console.log((0, box_1.renderResult)('error', `Failed to stop: ${err.message}`));
440
- try {
441
- fs_1.default.unlinkSync(data_1.PID_FILE);
442
- }
443
- catch (_b) { }
444
- }
445
- }
446
- function dashboardStatus(port) {
447
- if (isDashboardRunning()) {
448
- const pid = fs_1.default.readFileSync(data_1.PID_FILE, 'utf-8').trim();
449
- console.log((0, box_1.renderResult)('success', 'Dashboard RUNNING', [`${(0, theme_1.dim)('PID:')} ${(0, theme_1.brand)(pid)}`, `${(0, theme_1.dim)('URL:')} ${(0, theme_1.brand)(`http://localhost:${port}`)}`]));
450
- }
451
- else {
452
- console.log((0, box_1.renderResult)('warning', 'Dashboard NOT running', [(0, theme_1.dim)('Start with: cm dashboard start')]));
453
- }
454
- }
455
- // ─── Task Command ───────────────────────────────────────────────────────────
456
- program
457
- .command('task <cmd> [args...]')
458
- .alias('t')
459
- .description('Task management (add|list|move|done|rm)')
460
- .option('-p, --project <name>', 'Project name or ID')
461
- .option('-c, --column <column>', 'Column (backlog|in-progress|review|done)', 'backlog')
462
- .option('--priority <level>', 'Priority (low|medium|high|urgent)', 'medium')
463
- .option('--agent <agent>', 'Agent name')
464
- .option('--skill <skill>', 'Skill name')
465
- .option('--all', 'Show all projects')
466
- .option('--force', 'Force re-dispatch')
467
- .action((cmd, args, opts) => {
468
- switch (cmd) {
469
- case 'add':
470
- taskAdd(args.join(' '), opts);
471
- break;
472
- case 'list':
473
- case 'ls':
474
- taskList(opts);
475
- break;
476
- case 'move':
477
- taskMove(args[0], args[1]);
478
- break;
479
- case 'done':
480
- taskDone(args[0]);
481
- break;
482
- case 'rm':
483
- case 'delete':
484
- taskRemove(args[0]);
485
- break;
486
- case 'dispatch':
487
- taskDispatch(args[0], opts);
488
- break;
489
- case 'stuck':
490
- taskStuck(opts);
491
- break;
492
- default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list, move, done, rm, dispatch, stuck')]));
493
- }
494
- });
495
- function taskAdd(title, opts) {
496
- if (!title) {
497
- console.log((0, box_1.renderResult)('error', 'Title required. Usage: cm task add "My task"'));
498
- return;
499
- }
500
- const data = (0, data_1.loadData)();
501
- let projectId;
502
- if (opts.project) {
503
- const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
504
- if (!project) {
505
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
506
- return;
507
- }
508
- projectId = project.id;
509
- }
510
- else if (data.projects.length > 0) {
511
- projectId = data.projects[0].id;
512
- }
513
- else {
514
- const dp = { id: crypto_1.default.randomUUID(), name: 'Default Project', path: process.cwd(), agents: [], createdAt: new Date().toISOString() };
515
- data.projects.push(dp);
516
- projectId = dp.id;
517
- }
518
- const now = new Date().toISOString();
519
- const column = opts.column || 'backlog';
520
- const ct = data.tasks.filter(t => t.column === column && t.projectId === projectId);
521
- const mo = ct.length > 0 ? Math.max(...ct.map(t => t.order)) : -1;
522
- 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 };
523
- data.tasks.push(task);
524
- (0, data_1.logActivity)(data, 'task_created', `Task "${task.title}" created via CLI`, projectId, opts.agent || '');
525
- (0, data_1.saveData)(data);
526
- const project = data.projects.find(p => p.id === projectId);
527
- console.log((0, box_1.renderResult)('success', `Task created: ${title}`, [
528
- `${(0, theme_1.dim)('ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(task.id))} ${(0, theme_1.dim)('|')} ${(0, theme_1.dim)('Project:')} ${(0, theme_1.brand)((project === null || project === void 0 ? void 0 : project.name) || 'Default')} ${(0, theme_1.dim)('|')} ${(0, theme_1.dim)(column)} ${(0, theme_1.dim)('|')} ${(0, theme_1.dim)(opts.priority || 'medium')}`,
529
- ]));
530
- }
531
- function taskList(opts) {
532
- const data = (0, data_1.loadData)();
533
- let tasks = data.tasks;
534
- if (opts.project && !opts.all) {
535
- const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
536
- if (!project) {
537
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
538
- return;
539
- }
540
- tasks = tasks.filter(t => t.projectId === project.id);
541
- console.log((0, box_1.renderCommandHeader)(`Tasks β€” ${project.name}`, 'πŸ“‹'));
542
- }
543
- else {
544
- console.log((0, box_1.renderCommandHeader)('All Tasks', 'πŸ“‹'));
545
- }
546
- if (tasks.length === 0) {
547
- console.log(` ${(0, theme_1.dim)('No tasks found.')}\n`);
548
- return;
549
- }
550
- console.log((0, theme_1.dim)(' ' + padRight('ID', 10) + padRight('Title', 36) + padRight('Column', 14) + padRight('Priority', 10) + padRight('Agent', 14) + 'Project'));
551
- console.log((0, theme_1.dim)(' ' + '─'.repeat(100)));
552
- const co = ['backlog', 'in-progress', 'review', 'done'];
553
- tasks.sort((a, b) => co.indexOf(a.column) - co.indexOf(b.column) || a.order - b.order);
554
- for (const task of tasks) {
555
- const cc = COL_COLORS[task.column] || chalk_1.default.white;
556
- const pc = PRIORITY_COLORS[task.priority] || chalk_1.default.white;
557
- const project = data.projects.find(p => p.id === task.projectId);
558
- console.log(' ' + (0, theme_1.dim)(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)) + (0, theme_1.dim)(padRight(task.agent || 'β€”', 14)) + (0, theme_1.dim)((project === null || project === void 0 ? void 0 : project.name) || 'β€”'));
559
- }
560
- console.log((0, theme_1.dim)(`\n Total: ${tasks.length} tasks\n`));
561
- }
562
- function taskMove(idPrefix, targetColumn) {
563
- if (!idPrefix || !targetColumn) {
564
- console.log((0, box_1.renderResult)('error', 'Usage: cm task move <id> <column>'));
565
- return;
566
- }
567
- const vc = ['backlog', 'in-progress', 'review', 'done'];
568
- if (!vc.includes(targetColumn)) {
569
- console.log((0, box_1.renderResult)('error', `Invalid column: ${targetColumn}`, [(0, theme_1.dim)(`Valid: ${vc.join(', ')}`)]));
570
- return;
571
- }
572
- const data = (0, data_1.loadData)();
573
- const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
574
- if (!task) {
575
- console.log((0, box_1.renderResult)('error', `Task not found: ${idPrefix}`));
576
- return;
577
- }
578
- const oldCol = task.column;
579
- // Validate transition
580
- const VALID_TRANSITIONS = {
581
- 'backlog': ['in-progress'],
582
- 'in-progress': ['review', 'done', 'backlog'],
583
- 'review': ['done', 'in-progress'],
584
- 'done': ['backlog'],
585
- };
586
- const allowed = VALID_TRANSITIONS[oldCol] || [];
587
- if (oldCol !== targetColumn && !allowed.includes(targetColumn)) {
588
- console.log((0, box_1.renderResult)('error', `Invalid transition: ${oldCol} β†’ ${targetColumn}`, [(0, theme_1.dim)(`Allowed: ${allowed.join(', ')}`)]));
589
- return;
590
- }
591
- if (oldCol === targetColumn) {
592
- console.log(` ${(0, theme_1.dim)(`Task already in ${targetColumn}.`)}`);
593
- return;
594
- }
595
- task.column = targetColumn;
596
- task.updatedAt = new Date().toISOString();
597
- task.stuckSince = undefined;
598
- (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 });
599
- (0, data_1.saveData)(data);
600
- console.log((0, box_1.renderResult)('success', `Moved "${task.title}"`, [
601
- `${(0, theme_1.dim)(oldCol)} ${(0, theme_1.brand)('β†’')} ${(COL_COLORS[targetColumn] || chalk_1.default.white)(targetColumn)}`,
602
- ]));
603
- }
604
- function taskStuck(opts) {
605
- const data = (0, data_1.loadData)();
606
- const thresholdMin = 30;
607
- const now = Date.now();
608
- let tasks = data.tasks.filter(t => t.column === 'in-progress');
609
- if (opts.project) {
610
- const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
611
- if (!project) {
612
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
613
- return;
614
- }
615
- tasks = tasks.filter(t => t.projectId === project.id);
616
- }
617
- const stuck = tasks.filter(t => {
618
- const elapsed = now - new Date(t.updatedAt).getTime();
619
- return elapsed > thresholdMin * 60 * 1000;
620
- }).sort((a, b) => new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime());
621
- if (stuck.length === 0) {
622
- console.log((0, box_1.renderResult)('success', `No stuck tasks! All in-progress tasks updated within ${thresholdMin}m.`));
623
- return;
624
- }
625
- console.log((0, box_1.renderCommandHeader)(`${stuck.length} Stuck Tasks (>${thresholdMin}m in progress)`, '⚠️'));
626
- console.log((0, theme_1.dim)(' ' + padRight('ID', 10) + padRight('Title', 36) + padRight('Stuck For', 12) + padRight('Agent', 14) + 'Priority'));
627
- console.log((0, theme_1.dim)(' ' + '─'.repeat(86)));
628
- for (const task of stuck) {
629
- const elapsed = now - new Date(task.updatedAt).getTime();
630
- const minutes = Math.round(elapsed / 60000);
631
- const timeStr = minutes < 60 ? `${minutes}m` : `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
632
- const project = data.projects.find(p => p.id === task.projectId);
633
- const pc = PRIORITY_COLORS[task.priority] || chalk_1.default.white;
634
- console.log(' ' + (0, theme_1.dim)(padRight((0, data_1.shortId)(task.id), 10)) + padRight(task.title.substring(0, 34), 36) + (0, theme_1.warning)(padRight(timeStr, 12)) + (0, theme_1.dim)(padRight(task.agent || 'β€”', 14)) + pc(task.priority));
635
- }
636
- console.log();
637
- console.log((0, theme_1.dim)(' Tip: Move tasks with: cm task move <id> review|done|backlog'));
638
- console.log();
639
- }
640
- function taskDone(idPrefix) {
641
- if (!idPrefix) {
642
- console.log((0, box_1.renderResult)('error', 'Usage: cm task done <id>'));
643
- return;
644
- }
645
- taskMove(idPrefix, 'done');
646
- }
647
- function taskRemove(idPrefix) {
648
- if (!idPrefix) {
649
- console.log((0, box_1.renderResult)('error', 'Usage: cm task rm <id>'));
650
- return;
651
- }
652
- const data = (0, data_1.loadData)();
653
- const idx = data.tasks.findIndex(t => t.id === idPrefix || t.id.startsWith(idPrefix));
654
- if (idx === -1) {
655
- console.log((0, box_1.renderResult)('error', `Task not found: ${idPrefix}`));
656
- return;
657
- }
658
- const [removed] = data.tasks.splice(idx, 1);
659
- (0, data_1.logActivity)(data, 'task_deleted', `Task "${removed.title}" deleted via CLI`, removed.projectId, removed.agent);
660
- (0, data_1.saveData)(data);
661
- console.log((0, box_1.renderResult)('success', `Deleted: "${removed.title}" (${(0, data_1.shortId)(removed.id)})`));
662
- }
663
- function taskDispatch(idPrefix, opts) {
664
- if (!idPrefix) {
665
- console.log((0, box_1.renderResult)('error', 'Usage: cm task dispatch <id> [--force]'));
666
- return;
667
- }
668
- const data = (0, data_1.loadData)();
669
- const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
670
- if (!task) {
671
- console.log((0, box_1.renderResult)('error', `Task not found: ${idPrefix}`));
672
- return;
673
- }
674
- const project = data.projects.find(p => p.id === task.projectId);
675
- const result = (0, agent_dispatch_1.dispatchTaskToAgent)(task, project, opts.force || false);
676
- if (result.success) {
677
- task.dispatchStatus = 'dispatched';
678
- task.dispatchedAt = new Date().toISOString();
679
- task.dispatchError = undefined;
680
- task.updatedAt = task.dispatchedAt;
681
- (0, data_1.logActivity)(data, 'task_dispatched', `Task "${task.title}" dispatched to ${task.agent} via CLI`, task.projectId, task.agent, {
682
- taskId: task.id, filePath: result.filePath, force: opts.force || false,
683
- });
684
- (0, data_1.saveData)(data);
685
- const details = [
686
- `${(0, theme_1.dim)('Task:')} ${(0, theme_1.brand)(task.title)}`,
687
- `${(0, theme_1.dim)('Agent:')} ${(0, theme_1.brand)(task.agent)}`,
688
- ];
689
- if (task.skill)
690
- details.push(`${(0, theme_1.dim)('Skill:')} ${(0, theme_1.brand)(task.skill)}`);
691
- details.push(`${(0, theme_1.dim)('File:')} ${(0, theme_1.brand)(result.filePath)}`);
692
- console.log((0, box_1.renderResult)('success', `Task dispatched to ${task.agent}!`, details));
693
- }
694
- else {
695
- task.dispatchStatus = 'failed';
696
- task.dispatchError = result.error;
697
- task.updatedAt = new Date().toISOString();
698
- (0, data_1.saveData)(data);
699
- console.log((0, box_1.renderResult)('error', `Dispatch failed: ${result.error}`));
700
- }
701
- }
702
- // ─── Project Command ────────────────────────────────────────────────────────
703
- program
704
- .command('project <cmd> [args...]')
705
- .alias('p')
706
- .description('Project management (add|list|rm)')
707
- .option('--path <path>', 'Workspace path')
708
- .action((cmd, args, opts) => {
709
- switch (cmd) {
710
- case 'add':
711
- projectAdd(args.join(' '), opts);
712
- break;
713
- case 'list':
714
- case 'ls':
715
- projectList();
716
- break;
717
- case 'rm':
718
- case 'delete':
719
- projectRemove(args[0]);
720
- break;
721
- default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list, rm')]));
722
- }
723
- });
724
- function projectAdd(name, opts) {
725
- if (!name) {
726
- console.log((0, box_1.renderResult)('error', 'Usage: cm project add "my-project"'));
727
- return;
728
- }
729
- const data = (0, data_1.loadData)();
730
- const project = { id: crypto_1.default.randomUUID(), name: name.trim(), path: opts.path || process.cwd(), agents: [], createdAt: new Date().toISOString() };
731
- data.projects.push(project);
732
- (0, data_1.logActivity)(data, 'project_created', `Project "${project.name}" created via CLI`, project.id);
733
- (0, data_1.saveData)(data);
734
- console.log((0, box_1.renderResult)('success', `Project created: ${name}`, [
735
- `${(0, theme_1.dim)('ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(project.id))} ${(0, theme_1.dim)('|')} ${(0, theme_1.dim)('Path:')} ${(0, theme_1.brand)(project.path)}`,
736
- ]));
737
- }
738
- function projectList() {
739
- const data = (0, data_1.loadData)();
740
- if (data.projects.length === 0) {
741
- console.log(`\n ${(0, theme_1.dim)('No projects.')}\n`);
742
- return;
743
- }
744
- console.log((0, box_1.renderCommandHeader)('Projects', 'πŸ“¦'));
745
- console.log((0, theme_1.dim)(' ' + padRight('ID', 10) + padRight('Name', 24) + padRight('Tasks', 8) + padRight('Agents', 20) + 'Path'));
746
- console.log((0, theme_1.dim)(' ' + '─'.repeat(90)));
747
- for (const project of data.projects) {
748
- const pt = data.tasks.filter(t => t.projectId === project.id);
749
- const agents = [...new Set(pt.map(t => t.agent).filter(Boolean))];
750
- const done = pt.filter(t => t.column === 'done').length;
751
- console.log(' ' + (0, theme_1.dim)(padRight((0, data_1.shortId)(project.id), 10)) + (0, theme_1.brand)(padRight(project.name, 24)) + (0, theme_1.dim)(padRight(`${done}/${pt.length}`, 8)) + (0, theme_1.dim)(padRight(agents.join(', ') || 'β€”', 20)) + (0, theme_1.dim)(project.path || 'β€”'));
752
- }
753
- console.log();
754
- }
755
- function projectRemove(query) {
756
- if (!query) {
757
- console.log((0, box_1.renderResult)('error', 'Usage: cm project rm <name-or-id>'));
758
- return;
759
- }
760
- const data = (0, data_1.loadData)();
761
- const project = (0, data_1.findProjectByNameOrId)(data, query);
762
- if (!project) {
763
- console.log((0, box_1.renderResult)('error', `Project not found: ${query}`));
764
- return;
765
- }
766
- const tc = data.tasks.filter(t => t.projectId === project.id).length;
767
- data.projects = data.projects.filter(p => p.id !== project.id);
768
- data.tasks = data.tasks.filter(t => t.projectId !== project.id);
769
- (0, data_1.logActivity)(data, 'project_deleted', `Project "${project.name}" deleted via CLI`, project.id);
770
- (0, data_1.saveData)(data);
771
- console.log((0, box_1.renderResult)('success', `Deleted project "${project.name}" and ${tc} tasks.`));
772
- }
773
- // ─── Deploy Command ─────────────────────────────────────────────────────────
774
- program
775
- .command('deploy <cmd> [args...]')
776
- .alias('d')
777
- .description('Deploy management (staging|production|list)')
778
- .option('-p, --project <name>', 'Project name or ID')
779
- .option('-m, --message <msg>', 'Deploy message')
780
- .option('--commit <hash>', 'Git commit hash')
781
- .option('--branch <branch>', 'Git branch', 'main')
782
- .option('--agent <agent>', 'Agent name')
783
- .action((cmd, args, opts) => {
784
- switch (cmd) {
785
- case 'staging':
786
- deployRecord('staging', opts);
787
- break;
788
- case 'production':
789
- case 'prod':
790
- deployRecord('production', opts);
791
- break;
792
- case 'list':
793
- case 'ls':
794
- deployList(opts);
795
- break;
796
- default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: staging, production, list')]));
797
- }
798
- });
799
- function deployRecord(env, opts) {
800
- const data = (0, data_1.loadData)();
801
- let projectId;
802
- if (opts.project) {
803
- const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
804
- if (!p) {
805
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
806
- return;
807
- }
808
- projectId = p.id;
809
- }
810
- else if (data.projects.length > 0) {
811
- projectId = data.projects[0].id;
812
- }
813
- else {
814
- console.log((0, box_1.renderResult)('error', 'No projects. Create one first: cm project add "my-project"'));
815
- return;
816
- }
817
- const now = new Date().toISOString();
818
- const dep = {
819
- id: crypto_1.default.randomUUID(), projectId: projectId, env, status: 'success',
820
- commit: opts.commit || '', branch: opts.branch || 'main',
821
- agent: opts.agent || '', message: opts.message || `Deploy to ${env}`,
822
- startedAt: now, finishedAt: now,
823
- };
824
- data.deployments.unshift(dep);
825
- (0, data_1.logActivity)(data, env === 'staging' ? 'deploy_staging' : 'deploy_production', `Deployed to ${env}: ${dep.message}`, projectId, opts.agent || '', { deploymentId: dep.id });
826
- (0, data_1.saveData)(data);
827
- const envColor = env === 'production' ? theme_1.success : theme_1.warning;
828
- const project = data.projects.find(p => p.id === projectId);
829
- const details = [
830
- `${(0, theme_1.dim)('ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(dep.id))}`,
831
- `${(0, theme_1.dim)('Env:')} ${envColor(env)}`,
832
- `${(0, theme_1.dim)('Project:')} ${(0, theme_1.brand)((project === null || project === void 0 ? void 0 : project.name) || 'β€”')}`,
833
- `${(0, theme_1.dim)('Message:')} ${dep.message}`,
834
- ];
835
- if (dep.commit)
836
- details.push(`${(0, theme_1.dim)('Commit:')} ${(0, theme_1.brand)(dep.commit)}`);
837
- details.push(`${(0, theme_1.dim)('Branch:')} ${(0, theme_1.brand)(dep.branch)}`);
838
- console.log((0, box_1.renderResult)('success', 'Deployment recorded!', details));
839
- }
840
- function deployList(opts) {
841
- const data = (0, data_1.loadData)();
842
- let deps = data.deployments;
843
- if (opts.project) {
844
- const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
845
- if (!p) {
846
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
847
- return;
848
- }
849
- deps = deps.filter(d => d.projectId === p.id);
850
- }
851
- if (deps.length === 0) {
852
- console.log(`\n ${(0, theme_1.dim)('No deployments yet.')}\n`);
853
- return;
854
- }
855
- console.log((0, box_1.renderCommandHeader)('Deployment History', 'πŸš€'));
856
- console.log((0, theme_1.dim)(' ' + padRight('ID', 10) + padRight('Env', 12) + padRight('Status', 14) + padRight('Message', 32) + padRight('Branch', 12) + 'Time'));
857
- console.log((0, theme_1.dim)(' ' + '─'.repeat(100)));
858
- for (const dep of deps.slice(0, 20)) {
859
- const sc = STATUS_COLORS[dep.status] || chalk_1.default.white;
860
- const ec = dep.env === 'production' ? theme_1.success : theme_1.warning;
861
- const timeAgo = formatTimeAgoCli(dep.startedAt);
862
- const rollbackFlag = dep.rollbackOf ? ' βͺ' : '';
863
- console.log(' ' + (0, theme_1.dim)(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) + (0, theme_1.dim)(padRight(dep.branch || 'β€”', 12)) + (0, theme_1.dim)(timeAgo));
864
- }
865
- console.log((0, theme_1.dim)(`\n Total: ${deps.length} deployments\n`));
866
- }
867
- // ─── Rollback Command ───────────────────────────────────────────────────────
868
- program
869
- .command('rollback <deployId>')
870
- .alias('rb')
871
- .description('Rollback a deployment')
872
- .option('--agent <agent>', 'Agent name')
873
- .action((deployId, opts) => {
874
- const data = (0, data_1.loadData)();
875
- const dep = data.deployments.find(d => d.id === deployId || d.id.startsWith(deployId));
876
- if (!dep) {
877
- console.log((0, box_1.renderResult)('error', `Deployment not found: ${deployId}`));
878
- return;
879
- }
880
- if (dep.status === 'rolled_back') {
881
- console.log((0, box_1.renderResult)('warning', 'Already rolled back.'));
882
- return;
883
- }
884
- dep.status = 'rolled_back';
885
- const now = new Date().toISOString();
886
- const rollback = {
887
- id: crypto_1.default.randomUUID(), projectId: dep.projectId, env: dep.env, status: 'success',
888
- commit: '', branch: dep.branch, agent: opts.agent || '', message: `Rollback of ${(0, data_1.shortId)(dep.id)}`,
889
- startedAt: now, finishedAt: now, rollbackOf: dep.id,
890
- };
891
- data.deployments.unshift(rollback);
892
- (0, data_1.logActivity)(data, 'rollback', `Rolled back ${dep.env} deploy: ${dep.message}`, dep.projectId, opts.agent || '', { originalDeployId: dep.id, rollbackId: rollback.id });
893
- (0, data_1.saveData)(data);
894
- console.log((0, box_1.renderResult)('success', 'Rollback complete!', [
895
- `${(0, theme_1.dim)('Original:')} ${(0, theme_1.brand)((0, data_1.shortId)(dep.id))} ${(0, theme_1.dim)(`(${dep.env})`)}`,
896
- `${(0, theme_1.dim)('Rollback ID:')} ${(0, theme_1.brand)((0, data_1.shortId)(rollback.id))}`,
897
- `${(0, theme_1.dim)('Status:')} ${dep.message} β†’ rolled back`,
898
- ]));
899
- });
900
- // ─── History Command ────────────────────────────────────────────────────────
901
- program
902
- .command('history')
903
- .alias('h')
904
- .description('Show activity history')
905
- .option('-n, --limit <n>', 'Number of entries', '20')
906
- .option('-p, --project <name>', 'Filter by project')
907
- .action((opts) => {
908
- const data = (0, data_1.loadData)();
909
- let acts = data.activities;
910
- if (opts.project) {
911
- const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
912
- if (!p) {
913
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
914
- return;
915
- }
916
- acts = acts.filter(a => a.projectId === p.id);
917
- }
918
- const limit = parseInt(opts.limit) || 20;
919
- acts = acts.slice(0, limit);
920
- if (acts.length === 0) {
921
- console.log(`\n ${(0, theme_1.dim)('No activity yet.')}\n`);
922
- return;
923
- }
924
- const ACT_ICONS = {
925
- 'task_created': '✨', 'task_moved': '↔️', 'task_done': 'βœ…', 'task_deleted': 'πŸ—‘οΈ', 'task_updated': '✏️',
926
- 'project_created': 'πŸ“¦', 'project_deleted': 'πŸ—‘οΈ',
927
- 'deploy_staging': '🟑', 'deploy_production': 'πŸš€', 'deploy_failed': '❌', 'rollback': 'βͺ',
928
- 'git_push': 'πŸ“€', 'changelog_added': 'πŸ“',
929
- };
930
- console.log((0, box_1.renderCommandHeader)(`Activity History (latest ${acts.length})`, 'πŸ“œ'));
931
- for (const a of acts) {
932
- const icon = ACT_ICONS[a.type] || 'πŸ“Œ';
933
- const proj = data.projects.find(p => p.id === a.projectId);
934
- const projTag = proj ? (0, theme_1.dim)(` [${proj.name}]`) : '';
935
- const agentTag = a.agent ? (0, theme_1.dim)(` @${a.agent}`) : '';
936
- const time = formatTimeAgoCli(a.createdAt);
937
- console.log(` ${icon} ${a.message}${projTag}${agentTag} ${(0, theme_1.dim)(`← ${time}`)}`);
938
- }
939
- console.log();
940
- });
941
- // ─── Changelog Command ─────────────────────────────────────────────────────
942
- program
943
- .command('changelog <cmd> [args...]')
944
- .alias('cl')
945
- .description('Changelog management (add|list)')
946
- .option('-p, --project <name>', 'Project name or ID')
947
- .option('--agent <agent>', 'Agent name')
948
- .action((cmd, args, opts) => {
949
- switch (cmd) {
950
- case 'add':
951
- changelogAdd(args, opts);
952
- break;
953
- case 'list':
954
- case 'ls':
955
- changelogList(opts);
956
- break;
957
- default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list')]));
958
- }
959
- });
960
- function changelogAdd(args, opts) {
961
- if (args.length < 2) {
962
- console.log((0, box_1.renderResult)('error', 'Usage: cm changelog add <version> "<title>" [changes...]'));
963
- return;
964
- }
965
- const data = (0, data_1.loadData)();
966
- let projectId = '';
967
- if (opts.project) {
968
- const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
969
- if (!p) {
970
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
971
- return;
972
- }
973
- projectId = p.id;
974
- }
975
- else if (data.projects.length > 0) {
976
- projectId = data.projects[0].id;
977
- }
978
- const version = args[0];
979
- const title = args[1];
980
- const changes = args.slice(2);
981
- const entry = {
982
- id: crypto_1.default.randomUUID(), projectId, version, title, changes,
983
- agent: opts.agent || '', createdAt: new Date().toISOString(),
984
- };
985
- data.changelog.unshift(entry);
986
- (0, data_1.logActivity)(data, 'changelog_added', `Changelog ${version}: ${title}`, projectId, opts.agent || '');
987
- (0, data_1.saveData)(data);
988
- const details = [`${(0, theme_1.dim)('Version:')} ${(0, theme_1.brand)(version)}`, `${(0, theme_1.dim)('Title:')} ${title}`];
989
- if (changes.length > 0) {
990
- changes.forEach(c => details.push(`${(0, theme_1.dim)('β€’')} ${c}`));
991
- }
992
- console.log((0, box_1.renderResult)('success', 'Changelog entry added!', details));
993
- }
994
- function changelogList(opts) {
995
- const data = (0, data_1.loadData)();
996
- let entries = data.changelog;
997
- if (opts.project) {
998
- const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
999
- if (!p) {
1000
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
1001
- return;
1002
- }
1003
- entries = entries.filter(c => c.projectId === p.id);
1004
- }
1005
- if (entries.length === 0) {
1006
- console.log(`\n ${(0, theme_1.dim)('No changelog entries.')}\n`);
1007
- return;
1008
- }
1009
- console.log((0, box_1.renderCommandHeader)('Changelog', 'πŸ“'));
1010
- for (const entry of entries) {
1011
- const proj = data.projects.find(p => p.id === entry.projectId);
1012
- console.log((0, theme_1.brand)(` ${entry.version}`) + ` β€” ${entry.title}` + (0, theme_1.dim)(` (${formatTimeAgoCli(entry.createdAt)})${proj ? ' [' + proj.name + ']' : ''}`));
1013
- if (entry.changes.length > 0) {
1014
- entry.changes.forEach(c => console.log((0, theme_1.dim)(` β€’ ${c}`)));
1015
- }
1016
- }
1017
- console.log();
1018
- }
1019
- // ─── Status Command ─────────────────────────────────────────────────────────
1020
- program
1021
- .command('status')
1022
- .alias('s')
1023
- .description('Show task & project summary')
1024
- .action(() => {
1025
- const data = (0, data_1.loadData)();
1026
- showBanner();
1027
- console.log((0, box_1.renderCommandHeader)('Status Overview', 'πŸ“Š'));
1028
- // Projects
1029
- console.log((0, theme_1.brand)(` Projects: ${data.projects.length}`));
1030
- for (const p of data.projects) {
1031
- const pt = data.tasks.filter(t => t.projectId === p.id);
1032
- const done = pt.filter(t => t.column === 'done').length;
1033
- const pct = pt.length > 0 ? Math.round((done / pt.length) * 100) : 0;
1034
- console.log((0, theme_1.dim)(` πŸ“¦ ${padRight(p.name, 20)} ${progressBar(pct)} ${done}/${pt.length} (${pct}%)`));
1035
- }
1036
- // Tasks
1037
- const total = data.tasks.length;
1038
- const byCol = { backlog: 0, 'in-progress': 0, review: 0, done: 0 };
1039
- data.tasks.forEach(t => { byCol[t.column] = (byCol[t.column] || 0) + 1; });
1040
- console.log();
1041
- console.log((0, theme_1.brand)(` Tasks: ${total}`));
1042
- console.log((0, theme_1.dim)(` βšͺ Backlog: ${byCol.backlog}`));
1043
- console.log((0, theme_1.info)(` 🟒 In Progress: ${byCol['in-progress']}`));
1044
- console.log((0, theme_1.warning)(` 🟑 Review: ${byCol.review}`));
1045
- console.log((0, theme_1.success)(` 🟒 Done: ${byCol.done}`));
1046
- // Deploys
1047
- if (data.deployments.length > 0) {
1048
- console.log();
1049
- console.log((0, theme_1.brand)(` Deployments: ${data.deployments.length}`));
1050
- const latest = data.deployments[0];
1051
- const sc = STATUS_COLORS[latest.status] || chalk_1.default.white;
1052
- console.log((0, theme_1.dim)(` Latest: ${latest.env} β€” ${sc(latest.status)} β€” ${latest.message} (${formatTimeAgoCli(latest.startedAt)})`));
1053
- }
1054
- // Agents
1055
- const agentCounts = {};
1056
- data.tasks.forEach(t => { if (t.agent)
1057
- agentCounts[t.agent] = (agentCounts[t.agent] || 0) + 1; });
1058
- const agentNames = Object.keys(agentCounts);
1059
- if (agentNames.length > 0) {
1060
- console.log();
1061
- console.log((0, theme_1.brand)(` Active Agents: ${agentNames.length}`));
1062
- for (const agent of agentNames.sort()) {
1063
- console.log((0, theme_1.dim)(` πŸ€– ${padRight(agent, 16)} ${agentCounts[agent]} tasks`));
1064
- }
1065
- }
1066
- // Dashboard
1067
- console.log();
1068
- if (isDashboardRunning()) {
1069
- console.log((0, theme_1.success)(` πŸš€ Dashboard: RUNNING at http://codymaster.localhost:${data_1.DEFAULT_PORT}`));
1070
- }
1071
- else {
1072
- console.log((0, theme_1.dim)(` ⚫ Dashboard: not running (start with: cm dashboard)`));
1073
- }
1074
- console.log();
1075
- });
1076
- function progressBar(pct) {
1077
- const total = 12;
1078
- const filled = Math.round((pct / 100) * total);
1079
- return chalk_1.default.green('β–ˆ'.repeat(filled)) + chalk_1.default.gray('β–‘'.repeat(total - filled));
1080
- }
1081
- function formatTimeAgoCli(dateStr) {
1082
- const ms = Date.now() - new Date(dateStr).getTime();
1083
- const m = Math.floor(ms / 60000), h = Math.floor(ms / 3600000), d = Math.floor(ms / 86400000);
1084
- if (m < 1)
1085
- return 'just now';
1086
- if (m < 60)
1087
- return `${m}m ago`;
1088
- if (h < 24)
1089
- return `${h}h ago`;
1090
- if (d < 7)
1091
- return `${d}d ago`;
1092
- return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
1093
- }
1094
- // ─── Install Command ────────────────────────────────────────────────────────
1095
- program
1096
- .command('install <skill>')
1097
- .description('Install an agent skill')
1098
- .option('-p, --platform <platform>', 'Target platform (gemini|claude|cursor|windsurf|cline)')
1099
- .action((skill, opts) => __awaiter(void 0, void 0, void 0, function* () {
1100
- console.log((0, theme_1.brand)(` Installing skill: ${skill}...`));
1101
- if (!opts.platform) {
1102
- const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
1103
- const platform = yield p.select({
1104
- message: 'Which platform?',
1105
- options: [
1106
- { label: '🟒 Google Antigravity', value: 'gemini' },
1107
- { label: '🟣 Claude Code', value: 'claude' },
1108
- { label: 'πŸ”΅ Cursor', value: 'cursor' },
1109
- { label: '🟠 Windsurf', value: 'windsurf' },
1110
- { label: '🟀 Cline / RooCode', value: 'cline' },
1111
- ],
1112
- });
1113
- if (p.isCancel(platform))
1114
- return;
1115
- opts.platform = platform;
1116
- }
1117
- console.log((0, box_1.renderResult)('success', `Skill '${skill}' installed for ${opts.platform}!`));
1118
- }));
1119
- // ─── Add Command (npx codymaster add --skill cm-debugging) ───────────────────
1120
- const PLATFORM_TARGETS = {
1121
- gemini: { dir: '.gemini/skills', invoke: '@[/<skill>]', note: 'or ~/.gemini/antigravity/skills/ for global' },
1122
- cursor: { dir: '.cursor/rules', invoke: '@<skill>', note: 'Cursor rules directory' },
1123
- windsurf: { dir: '.windsurf/rules', invoke: '@<skill>', note: 'Windsurf rules directory' },
1124
- cline: { dir: '.cline/skills', invoke: '@<skill>', note: 'Cline / RooCode skills directory' },
1125
- opencode: { dir: '.opencode/skills', invoke: '@[/<skill>]', note: 'OpenCode skills directory' },
1126
- kiro: { dir: '.kiro/steering', invoke: '@<skill>', note: 'Kiro steering documents' },
1127
- copilot: { dir: '.github', invoke: '(auto-context)', note: 'Added to copilot-instructions.md' },
1128
- aider: { dir: '.aider/skills', invoke: '@[/<skill>]', note: 'Aider skills directory (reference in .aider.conf.yml)' },
1129
- continue: { dir: '.continue/rules', invoke: '@<skill>', note: 'Continue.dev rules directory' },
1130
- amazonq: { dir: '.aws/amazonq/skills', invoke: '@<skill>', note: 'Amazon Q skills directory' },
1131
- amp: { dir: '.amp/skills', invoke: '@<skill>', note: 'Amp skills directory' },
1132
- };
1133
- const RAW_BASE = 'https://raw.githubusercontent.com/tody-agent/codymaster/main';
1134
- function autoDetectPlatform() {
1135
- const { execFileSync } = require('child_process');
1136
- try {
1137
- execFileSync('claude', ['--version'], { stdio: 'pipe' });
1138
- return 'claude';
1139
- }
1140
- catch (_a) { }
1141
- try {
1142
- execFileSync('gemini', ['--version'], { stdio: 'pipe' });
1143
- return 'gemini';
1144
- }
1145
- catch (_b) { }
1146
- if (fs_1.default.existsSync(path_1.default.join(os_1.default.homedir(), '.cursor')))
1147
- return 'cursor';
1148
- if (fs_1.default.existsSync(path_1.default.join(os_1.default.homedir(), '.windsurf')))
1149
- return 'windsurf';
1150
- return 'manual';
1151
- }
1152
- function downloadFile(url, dest) {
1153
- return new Promise((resolve) => {
1154
- try {
1155
- fs_1.default.mkdirSync(path_1.default.dirname(dest), { recursive: true });
1156
- const file = fs_1.default.createWriteStream(dest);
1157
- https_1.default.get(url, (res) => {
1158
- if (res.statusCode !== 200) {
1159
- file.close();
1160
- try {
1161
- fs_1.default.unlinkSync(dest);
1162
- }
1163
- catch (_a) { }
1164
- resolve(false);
1165
- return;
1166
- }
1167
- res.pipe(file);
1168
- file.on('finish', () => { file.close(); resolve(true); });
1169
- }).on('error', () => { file.close(); resolve(false); });
1170
- }
1171
- catch (_a) {
1172
- resolve(false);
1173
- }
1174
- });
1175
- }
1176
- function doAddSkills(skills, platform) {
1177
- return __awaiter(this, void 0, void 0, function* () {
1178
- console.log();
1179
- const { execFileSync } = require('child_process');
1180
- if (platform === 'claude') {
1181
- console.log((0, theme_1.brand)('🟣 Claude Code β€” Installing via plugin system'));
1182
- console.log((0, theme_1.dim)(' (Claude installs all ${SKILL_COUNT} skills as one bundle)\n'));
1183
- // Step 1: Register marketplace
1184
- console.log((0, theme_1.dim)(' $ claude plugin marketplace add tody-agent/codymaster'));
1185
- try {
1186
- const r1 = require('child_process').spawnSync('claude', ['plugin', 'marketplace', 'add', 'tody-agent/codymaster'], { encoding: 'utf8' });
1187
- if (r1.stdout)
1188
- process.stdout.write(r1.stdout);
1189
- if (r1.stderr)
1190
- process.stderr.write(r1.stderr);
1191
- const combined = String(r1.stdout || '') + String(r1.stderr || '');
1192
- if (r1.status !== 0 && !combined.includes('already installed') && !combined.includes('already exists')) {
1193
- console.log((0, box_1.renderResult)('warning', 'Marketplace warning β€” continuing anyway'));
1194
- }
1195
- else if (combined.includes('already installed') || combined.includes('already exists')) {
1196
- console.log((0, theme_1.dim)(' ℹ️ Marketplace already registered'));
1197
- }
1198
- }
1199
- catch (_a) {
1200
- console.log((0, box_1.renderResult)('warning', 'Could not reach marketplace β€” continuing'));
1201
- }
1202
- // Step 2: Install / update the plugin
1203
- console.log((0, theme_1.dim)(' $ claude plugin install codymaster@codymaster'));
1204
- try {
1205
- execFileSync('claude', ['plugin', 'install', 'codymaster@codymaster'], { stdio: 'inherit' });
1206
- console.log((0, box_1.renderResult)('success', `All ${SKILL_COUNT} skills installed!`));
1207
- yield postInstallOnboarding('claude');
1208
- }
1209
- catch (_b) {
1210
- console.log((0, box_1.renderResult)('warning', 'Plugin install failed. Run manually:'));
1211
- console.log((0, theme_1.brand)(' claude plugin install codymaster@codymaster'));
1212
- console.log((0, theme_1.dim)('\n Or one-liner:'));
1213
- console.log((0, theme_1.brand)(' bash <(curl -fsSL https://raw.githubusercontent.com/tody-agent/codymaster/main/install.sh) --claude'));
1214
- }
1215
- return;
1216
- }
1217
- // Removed the fictional gemini extensions install block.
1218
- // Gemini now falls through to the standard file-cloning logic below.
1219
- const target = PLATFORM_TARGETS[platform];
1220
- if (!target) {
1221
- console.log((0, box_1.renderResult)('error', `Unknown platform: ${platform}`, [(0, theme_1.dim)('Supported: claude, gemini, cursor, windsurf, cline, opencode, kiro, copilot')]));
1222
- return;
1223
- }
1224
- if (platform === 'copilot') {
1225
- const instrFile = path_1.default.join('.github', 'copilot-instructions.md');
1226
- fs_1.default.mkdirSync('.github', { recursive: true });
1227
- const header = '\n\n## Cody Master Skills\nThe following AI skills are available β€” reference them by name:\n';
1228
- const lines = skills.map(s => `- **${s}**: see https://github.com/tody-agent/codymaster/blob/main/skills/${s}/SKILL.md`).join('\n');
1229
- const existing = fs_1.default.existsSync(instrFile) ? fs_1.default.readFileSync(instrFile, 'utf-8') : '';
1230
- if (!existing.includes('Cody Master Skills')) {
1231
- fs_1.default.appendFileSync(instrFile, header + lines + '\n');
1232
- }
1233
- console.log((0, box_1.renderResult)('success', `${skills.length} skills referenced in ${instrFile}`, [(0, theme_1.dim)('GitHub Copilot will use these as context automatically.')]));
1234
- return;
1235
- }
1236
- const icons = { cursor: 'πŸ”΅', windsurf: '🟠', cline: '⚫', opencode: 'πŸ“¦', kiro: 'πŸ”Ά' };
1237
- const icon = icons[platform] || 'πŸ“¦';
1238
- const label = skills.length === ALL_SKILLS.length ? `all ${SKILL_COUNT} skills` : skills.join(', ');
1239
- console.log(`${icon} ${(0, theme_1.brand)(`${platform} β€” Installing ${label}`)}`);
1240
- console.log((0, theme_1.dim)(` Target: ./${target.dir}/\n`));
1241
- let ok = 0, fail = 0;
1242
- for (const skill of skills) {
1243
- const url = `${RAW_BASE}/skills/${skill}/SKILL.md`;
1244
- let dest = path_1.default.join(target.dir, skill, 'SKILL.md');
1245
- // Formatting logic to adapt to specific IDE required formats
1246
- if (platform === 'cursor') {
1247
- dest = path_1.default.join(target.dir, `${skill}.mdc`);
1248
- }
1249
- else if (platform === 'continue') {
1250
- dest = path_1.default.join(target.dir, `${skill}.md`);
1251
- }
1252
- const ok_result = yield downloadFile(url, dest);
1253
- // Prepend Cursor MDC glob formatting
1254
- if (ok_result && platform === 'cursor') {
1255
- try {
1256
- const content = fs_1.default.readFileSync(dest, 'utf-8');
1257
- if (!content.startsWith('---')) {
1258
- const yamlFrontmatter = `---\ndescription: ${skill}\nglobs: *\n---\n`;
1259
- fs_1.default.writeFileSync(dest, yamlFrontmatter + content);
1260
- }
1261
- else if (!content.includes('globs:')) {
1262
- const newContent = content.replace(/^---/, '---\nglobs: *');
1263
- fs_1.default.writeFileSync(dest, newContent);
1264
- }
1265
- }
1266
- catch (err) { }
1267
- }
1268
- if (ok_result) {
1269
- process.stdout.write((0, theme_1.success)(` βœ… ${skill}\n`));
1270
- ok++;
1271
- }
1272
- else {
1273
- process.stdout.write((0, theme_1.error)(` ❌ ${skill}\n`));
1274
- fail++;
1275
- }
1276
- }
1277
- console.log();
1278
- if (ok > 0) {
1279
- console.log((0, box_1.renderResult)('success', `${ok} skill${ok > 1 ? 's' : ''} installed β†’ ./${target.dir}/`));
1280
- const invoke = target.invoke.replace('<skill>', skills[0]);
1281
- console.log((0, theme_1.brand)(` πŸ“– Usage: ${invoke} Your prompt here`));
1282
- if (target.note)
1283
- console.log((0, theme_1.dim)(` Note: ${target.note}`));
1284
- yield postInstallOnboarding(platform);
1285
- }
1286
- if (fail > 0) {
1287
- console.log((0, box_1.renderResult)('warning', `${fail} failed β€” check connection or clone manually:`, [(0, theme_1.dim)('git clone https://github.com/tody-agent/codymaster.git')]));
1288
- }
1289
- });
1290
- }
1291
- program
1292
- .command('add')
1293
- .description('Add skills to your AI agent (npx codymaster add --skill cm-debugging)')
1294
- .option('--skill <name>', 'Specific skill to add (e.g. cm-debugging)')
1295
- .option('--all', `Add all ${SKILL_COUNT} skills`)
1296
- .option('--platform <platform>', 'Target: claude|gemini|cursor|windsurf|cline|opencode|kiro|copilot')
1297
- .option('--list', 'Show available skills and exit')
1298
- .action((opts) => __awaiter(void 0, void 0, void 0, function* () {
1299
- showBanner();
1300
- if (opts.list) {
1301
- skillList();
1302
- return;
1303
- }
1304
- // Resolve skills array
1305
- let skills = null;
1306
- if (opts.all) {
1307
- skills = ALL_SKILLS;
1308
- }
1309
- else if (opts.skill) {
1310
- if (!ALL_SKILLS.includes(opts.skill)) {
1311
- console.log((0, box_1.renderResult)('error', `Unknown skill: ${opts.skill}`, [(0, theme_1.dim)('Run: npx codymaster add --list')]));
1312
- return;
1313
- return;
1314
- }
1315
- skills = [opts.skill];
1316
- }
1317
- // Detect or prompt platform
1318
- let platform = opts.platform || autoDetectPlatform();
1319
- if (platform === 'manual') {
1320
- const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
1321
- const platform_choice = yield p.select({
1322
- message: 'Select your AI coding platform:',
1323
- options: [
1324
- { label: '🟣 Claude Code (recommended)', value: 'claude' },
1325
- { label: 'πŸ’» Gemini CLI & Antigravity', value: 'gemini' },
1326
- { label: 'πŸ”΅ Cursor', value: 'cursor' },
1327
- { label: '🟠 Windsurf', value: 'windsurf' },
1328
- { label: '⚫ Cline / RooCode', value: 'cline' },
1329
- { label: 'πŸ“¦ OpenCode', value: 'opencode' },
1330
- { label: 'πŸ”Ά Kiro (AWS)', value: 'kiro' },
1331
- { label: 'πŸ™ GitHub Copilot', value: 'copilot' },
1332
- { label: 'πŸ€– Aider', value: 'aider' },
1333
- { label: 'πŸ”— Continue.dev', value: 'continue' },
1334
- { label: '☁️ Amazon Q', value: 'amazonq' },
1335
- { label: '⚑ Amp', value: 'amp' },
1336
- ],
1337
- });
1338
- if (p.isCancel(platform_choice))
1339
- return;
1340
- platform = platform_choice;
1341
- }
1342
- // If no skills chosen yet, prompt
1343
- if (!skills) {
1344
- if (platform === 'claude' || platform === 'gemini') {
1345
- skills = ALL_SKILLS;
1346
- }
1347
- else {
1348
- const p = yield Promise.resolve().then(() => __importStar(require('@clack/prompts')));
1349
- const mode = yield p.select({
1350
- message: 'What to install?',
1351
- options: [
1352
- { label: `All ${SKILL_COUNT} skills (full kit)`, value: 'all' },
1353
- { label: 'Search & pick one skill', value: 'pick' },
1354
- ],
1355
- });
1356
- if (p.isCancel(mode))
1357
- return;
1358
- if (mode === 'all') {
1359
- skills = ALL_SKILLS;
1360
- }
1361
- else {
1362
- const pick = yield p.select({
1363
- message: 'Select a skill:',
1364
- options: ALL_SKILLS.map(s => ({ label: s, value: s })),
1365
- });
1366
- if (p.isCancel(pick))
1367
- return;
1368
- skills = [pick];
1369
- }
1370
- }
1371
- }
1372
- yield doAddSkills(skills, platform);
1373
- }));
1374
- // ─── List Command (quick alias for `cody skill list`) ─────────────────────────
1375
- program
1376
- .command('list')
1377
- .alias('ls')
1378
- .description(`List all ${SKILL_COUNT} available skills`)
1379
- .option('-d, --domain <domain>', 'Filter by domain')
1380
- .action((opts) => {
1381
- skillList(opts.domain);
1382
- });
1383
- // ─── Profile Command ──────────────────────────────────────────────────────────
1384
- program
1385
- .command('profile')
1386
- .description('View your CodyMaster profile, stats, and achievements')
1387
- .action(() => {
1388
- const profile = (0, hooks_1.loadProfile)();
1389
- if (!profile.onboardingComplete) {
1390
- console.log((0, theme_1.dim)('\n Run cm first to complete setup! 🐹\n'));
1391
- return;
1392
- }
1393
- (0, hooks_1.recordCommand)(profile, 'profile');
1394
- const newAchievements = (0, hooks_1.checkAchievements)(profile);
1395
- (0, hooks_1.saveProfile)(profile);
1396
- console.log((0, hooks_1.formatProfileSummary)(profile));
1397
- for (const id of newAchievements) {
1398
- console.log((0, hooks_1.formatAchievement)(id));
1399
- }
26
+ const program = new commander_1.Command();
27
+ program
28
+ .name('cm')
29
+ .description('CodyMaster CLI β€” The Hamster-Powered AI Agent Framework')
30
+ .version(VERSION);
31
+ // ─── Registration ──────────────────────────────────────────────────────────
32
+ // Register all modular commands
33
+ (0, command_registry_1.registerAllCommands)(program);
34
+ // ─── Update Check ──────────────────────────────────────────────────────────
35
+ // Run update check in background (non-blocking)
36
+ (0, update_check_1.checkForUpdates)().catch(() => { });
37
+ // ─── Execution ─────────────────────────────────────────────────────────────
38
+ // Parse arguments and execute
39
+ program.parse(process.argv);
40
+ // Default to 'status' if no command provided
41
+ if (process.argv.length <= 2) {
42
+ program.help();
43
+ }
44
+ });
45
+ }
46
+ // Error handling for uncaught exceptions
47
+ process.on('uncaughtException', (err) => {
48
+ console.error('\n πŸ›‘ UNCAUGHT ERROR:', err.message);
49
+ if (process.env.DEBUG)
50
+ console.error(err.stack);
51
+ process.exit(1);
52
+ });
53
+ main().catch((err) => {
54
+ console.error('\n πŸ›‘ FATAL ERROR:', err.message);
55
+ process.exit(1);
1400
56
  });
1401
- // ─── Continuity Command (Working Memory) ────────────────────────────────────
1402
- program
1403
- .command('continuity [cmd]')
1404
- .alias('ctx')
1405
- .description('Working memory (init|status|reset|learnings|decisions)')
1406
- .option('--path <path>', 'Project path', process.cwd())
1407
- .action((cmd, opts) => {
1408
- const projectPath = opts.path || process.cwd();
1409
- switch (cmd) {
1410
- case 'init':
1411
- continuityInit(projectPath);
1412
- break;
1413
- case 'status':
1414
- case undefined:
1415
- continuityStatus(projectPath);
1416
- break;
1417
- case 'reset':
1418
- continuityReset(projectPath);
1419
- break;
1420
- case 'learnings':
1421
- case 'learn':
1422
- continuityLearnings(projectPath);
1423
- break;
1424
- case 'decisions':
1425
- case 'dec':
1426
- continuityDecisions(projectPath);
1427
- break;
1428
- case 'index':
1429
- continuityIndex(projectPath);
1430
- break;
1431
- case 'budget':
1432
- continuityBudget(projectPath);
1433
- break;
1434
- case 'bus':
1435
- continuityBus(projectPath);
1436
- break;
1437
- case 'mcp':
1438
- continuityMcp(projectPath);
1439
- break;
1440
- case 'migrate':
1441
- continuityMigrate(projectPath);
1442
- break;
1443
- case 'export':
1444
- continuityExport(projectPath);
1445
- break;
1446
- default:
1447
- console.log(chalk_1.default.red(`Unknown: ${cmd}`));
1448
- console.log(chalk_1.default.gray('Available: init, status, reset, learnings, decisions, index, budget, bus, mcp, migrate, export'));
1449
- }
1450
- });
1451
- function continuityInit(projectPath) {
1452
- if ((0, continuity_1.hasCmDir)(projectPath)) {
1453
- console.log((0, box_1.renderResult)('warning', '.cm/ directory already exists.', [(0, theme_1.dim)(`Path: ${projectPath}/.cm/`)]));
1454
- return;
1455
- }
1456
- (0, continuity_1.ensureCmDir)(projectPath);
1457
- console.log((0, box_1.renderResult)('success', 'Working memory initialized!', [
1458
- (0, theme_1.dim)(`Created: ${projectPath}/.cm/`),
1459
- (0, theme_1.dim)('β”œβ”€β”€ CONTINUITY.md (working memory)'),
1460
- (0, theme_1.dim)('β”œβ”€β”€ config.yaml (RARV settings)'),
1461
- (0, theme_1.dim)('└── memory/'),
1462
- (0, theme_1.dim)(' β”œβ”€β”€ learnings.json (error patterns)'),
1463
- (0, theme_1.dim)(' └── decisions.json (architecture decisions)'),
1464
- ]));
1465
- console.log((0, theme_1.info)('πŸ’‘ Protocol: Read CONTINUITY.md at session start, update at session end.'));
1466
- }
1467
- function continuityStatus(projectPath) {
1468
- const status = (0, continuity_1.getContinuityStatus)(projectPath);
1469
- if (!status.initialized) {
1470
- console.log((0, box_1.renderResult)('warning', 'Working memory not initialized.', [(0, theme_1.dim)('Run: cm continuity init')]));
1471
- return;
1472
- }
1473
- console.log((0, box_1.renderCommandHeader)('Working Memory Status', '🧠'));
1474
- console.log((0, box_1.renderKeyValue)([
1475
- ['Project', String(status.project)],
1476
- ['Phase', phaseColor(status.phase)(status.phase)],
1477
- ['Iteration', String(status.iteration)],
1478
- ...(status.activeGoal ? [['Goal', String(status.activeGoal)]] : []),
1479
- ...(status.currentTask ? [['Task', String(status.currentTask)]] : []),
1480
- ]));
1481
- console.log((0, theme_1.dim)(` βœ… Completed: ${status.completedCount} | 🚧 Blockers: ${status.blockerCount}`));
1482
- console.log((0, theme_1.dim)(` πŸ“š Learnings: ${status.learningCount} | πŸ“‹ Decisions: ${status.decisionCount}`));
1483
- if (status.lastUpdated) {
1484
- console.log((0, theme_1.dim)(` πŸ• Updated: ${formatTimeAgoCli(status.lastUpdated)}`));
1485
- }
1486
- console.log();
1487
- }
1488
- function phaseColor(phase) {
1489
- const colors = {
1490
- planning: chalk_1.default.blue, executing: chalk_1.default.yellow, testing: chalk_1.default.magenta,
1491
- deploying: chalk_1.default.green, reviewing: chalk_1.default.cyan, idle: chalk_1.default.gray,
1492
- };
1493
- return colors[phase] || chalk_1.default.white;
1494
- }
1495
- function continuityReset(projectPath) {
1496
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1497
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found.'));
1498
- return;
1499
- }
1500
- (0, continuity_1.resetContinuity)(projectPath);
1501
- console.log((0, box_1.renderResult)('success', 'Working memory reset.', [(0, theme_1.dim)('CONTINUITY.md cleared. Learnings preserved.')]));
1502
- }
1503
- function continuityLearnings(projectPath) {
1504
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1505
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1506
- return;
1507
- }
1508
- const learnings = (0, continuity_1.getLearnings)(projectPath);
1509
- if (learnings.length === 0) {
1510
- console.log(`\n ${(0, theme_1.dim)('No learnings captured yet. πŸŽ‰')}\n`);
1511
- return;
1512
- }
1513
- console.log((0, box_1.renderCommandHeader)(`Mistakes & Learnings (${learnings.length})`, 'πŸ“š'));
1514
- for (const l of learnings.slice(-10)) {
1515
- console.log((0, theme_1.error)(` ❌ ${l.whatFailed}`));
1516
- console.log((0, theme_1.dim)(` Why: ${l.whyFailed}`));
1517
- console.log((0, theme_1.success)(` Fix: ${l.howToPrevent}`));
1518
- console.log((0, theme_1.dim)(` ${formatTimeAgoCli(l.timestamp)} | ${l.agent || 'unknown'}\n`));
1519
- }
1520
- }
1521
- function continuityDecisions(projectPath) {
1522
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1523
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1524
- return;
1525
- }
1526
- const decisions = (0, continuity_1.getDecisions)(projectPath);
1527
- if (decisions.length === 0) {
1528
- console.log(`\n ${(0, theme_1.dim)('No decisions recorded yet.')}\n`);
1529
- return;
1530
- }
1531
- console.log((0, box_1.renderCommandHeader)(`Key Decisions (${decisions.length})`, 'πŸ“‹'));
1532
- for (const d of decisions.slice(-10)) {
1533
- console.log((0, theme_1.brand)(` πŸ“Œ ${d.decision}`));
1534
- console.log((0, theme_1.dim)(` Rationale: ${d.rationale}`));
1535
- console.log((0, theme_1.dim)(` ${formatTimeAgoCli(d.timestamp)} | ${d.agent || 'unknown'}\n`));
1536
- }
1537
- }
1538
- function continuityIndex(projectPath) {
1539
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1540
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1541
- return;
1542
- }
1543
- console.log((0, box_1.renderCommandHeader)('Refreshing L0 Indexes', 'πŸ—‚οΈ'));
1544
- const result = (0, l0_indexer_1.refreshAllIndexes)(projectPath);
1545
- const learningsLines = result.learnings.split('\n').length;
1546
- const skeletonLines = result.skeleton.split('\n').length;
1547
- console.log((0, theme_1.success)(` βœ… learnings-index.md (${learningsLines} lines)`));
1548
- console.log((0, theme_1.success)(` βœ… skeleton-index.md (${skeletonLines} lines)`));
1549
- console.log((0, theme_1.success)(' βœ… Continuity abstract generated'));
1550
- console.log((0, theme_1.dim)(`\n Files written to .cm/`));
1551
- }
1552
- function continuityBudget(projectPath) {
1553
- const budget = (0, token_budget_1.loadBudget)(projectPath);
1554
- console.log((0, box_1.renderCommandHeader)('Token Budget', 'πŸ’°'));
1555
- console.log('\n' + (0, token_budget_1.generateBudgetReport)(budget) + '\n');
1556
- }
1557
- function continuityBus(projectPath) {
1558
- const bus = (0, context_bus_1.readBus)(projectPath);
1559
- if (!bus) {
1560
- console.log((0, box_1.renderResult)('info', 'No active context bus. Start a chain to initialize.'));
1561
- return;
1562
- }
1563
- console.log((0, box_1.renderCommandHeader)(`Context Bus β€” ${bus.pipeline}`, '🚌'));
1564
- console.log((0, theme_1.dim)(` Session: ${bus.session_id}`));
1565
- console.log((0, theme_1.dim)(` Step: ${bus.current_step || '(none)'}`));
1566
- console.log((0, theme_1.dim)(` Started: ${bus.started_at}`));
1567
- console.log((0, theme_1.dim)(` Updated: ${bus.updated_at}`));
1568
- const steps = Object.keys(bus.shared_context);
1569
- if (steps.length > 0) {
1570
- console.log((0, theme_1.brand)('\n Completed Steps:'));
1571
- for (const skill of steps) {
1572
- const out = bus.shared_context[skill];
1573
- console.log((0, theme_1.success)(` βœ… ${skill}`) + ((out === null || out === void 0 ? void 0 : out.summary) ? (0, theme_1.dim)(` β€” ${out.summary}`) : ''));
1574
- }
1575
- }
1576
- console.log((0, theme_1.dim)('\n Resource State:'));
1577
- for (const [k, v] of Object.entries(bus.resource_state)) {
1578
- console.log((0, theme_1.dim)(` ${k}: ${v || 'not indexed'}`));
1579
- }
1580
- }
1581
- function continuityMigrate(projectPath) {
1582
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1583
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1584
- return;
1585
- }
1586
- console.log((0, box_1.renderCommandHeader)('Migrate JSON β†’ SQLite', 'πŸ—ƒοΈ'));
1587
- console.log((0, theme_1.dim)(' Reading learnings.json + decisions.json β†’ .cm/context.db\n'));
1588
- try {
1589
- const result = (0, migrate_json_to_sqlite_1.migrateJsonToSqlite)(projectPath);
1590
- console.log((0, theme_1.success)(` βœ… Learnings migrated: ${result.learnings.migrated} (skipped: ${result.learnings.skipped})`));
1591
- console.log((0, theme_1.success)(` βœ… Decisions migrated: ${result.decisions.migrated} (skipped: ${result.decisions.skipped})`));
1592
- if (result.backupCreated)
1593
- console.log((0, theme_1.dim)(' πŸ“¦ Backups created: learnings.json.backup, decisions.json.backup'));
1594
- console.log((0, theme_1.dim)(`\n DB: ${result.dbPath}`));
1595
- }
1596
- catch (err) {
1597
- console.log((0, theme_1.error)(` ❌ Migration failed: ${err.message}`));
1598
- }
1599
- }
1600
- function continuityExport(projectPath) {
1601
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1602
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1603
- return;
1604
- }
1605
- console.log((0, box_1.renderCommandHeader)('Export SQLite β†’ JSON', 'πŸ“€'));
1606
- try {
1607
- const result = (0, migrate_json_to_sqlite_1.exportSqliteToJson)(projectPath);
1608
- console.log((0, theme_1.success)(` βœ… Learnings exported: ${result.learnings} β†’ ${result.learningsPath}`));
1609
- console.log((0, theme_1.success)(` βœ… Decisions exported: ${result.decisions} β†’ ${result.decisionsPath}`));
1610
- }
1611
- catch (err) {
1612
- console.log((0, theme_1.error)(` ❌ Export failed: ${err.message}`));
1613
- }
1614
- }
1615
- function continuityMcp(projectPath) {
1616
- const mcpPath = path_1.default.join(__dirname, 'mcp-context-server.js');
1617
- console.log((0, box_1.renderCommandHeader)('MCP Context Server', 'πŸ”Œ'));
1618
- console.log((0, theme_1.dim)(' Runs as a stdio MCP server exposing 7 context tools.\n'));
1619
- console.log((0, box_1.renderKeyValue)([
1620
- ['Binary', mcpPath],
1621
- ['Project', projectPath],
1622
- ['Tools', 'cm_query, cm_resolve, cm_bus_read, cm_bus_write, cm_budget_check, cm_memory_decay, cm_index_refresh'],
1623
- ]));
1624
- console.log((0, theme_1.brand)('\n Claude Desktop config snippet:'));
1625
- console.log((0, theme_1.dim)(` {
1626
- "mcpServers": {
1627
- "cm-context": {
1628
- "command": "node",
1629
- "args": ["${mcpPath}", "--project", "${projectPath}"]
1630
- }
1631
- }
1632
- }`));
1633
- console.log((0, theme_1.info)('\n πŸ’‘ Add the above to ~/Library/Application Support/Claude/claude_desktop_config.json'));
1634
- }
1635
- // ─── Resolve Command ──────────────────────────────────────────────────────────
1636
- program
1637
- .command('resolve <uri>')
1638
- .description('Resolve a cm:// URI and print content (e.g. cm://memory/learnings)')
1639
- .option('-d, --depth <depth>', 'Loading depth: L0 | L1 | L2', 'L1')
1640
- .option('-p, --project <path>', 'Project path (default: cwd)')
1641
- .action((uri, opts) => {
1642
- var _a;
1643
- const projectPath = path_1.default.resolve(opts.project || process.cwd());
1644
- const depth = (['L0', 'L1', 'L2'].includes((_a = opts.depth) !== null && _a !== void 0 ? _a : '') ? opts.depth : 'L1');
1645
- try {
1646
- const resolved = (0, uri_resolver_1.resolve)(uri, projectPath, depth);
1647
- console.log((0, box_1.renderCommandHeader)(`cm:// Resolver β€” ${depth}`, 'πŸ”—'));
1648
- console.log((0, box_1.renderKeyValue)([
1649
- ['URI', resolved.uri],
1650
- ['Depth', resolved.depth],
1651
- ['Found', String(resolved.found)],
1652
- ['Tokens', String(resolved.tokenEstimate)],
1653
- ]));
1654
- if (resolved.found) {
1655
- console.log((0, theme_1.brand)('\n Content:\n'));
1656
- console.log(resolved.content);
1657
- }
1658
- else {
1659
- console.log((0, theme_1.warning)('\n Not found β€” no content available at this URI.'));
1660
- }
1661
- }
1662
- catch (err) {
1663
- console.log((0, theme_1.error)(` ❌ ${err.message}`));
1664
- }
1665
- });
1666
- // ─── Brain Command (Enhanced Memory Explorer) ────────────────────────────────
1667
- program
1668
- .command('brain [cmd]')
1669
- .alias('b')
1670
- .description('Memory explorer (status|learnings|decisions|delete|stats|export)')
1671
- .option('--path <path>', 'Project path', process.cwd())
1672
- .option('--search <query>', 'Search learnings')
1673
- .option('--last <n>', 'Show last N items')
1674
- .option('--format <fmt>', 'Export format: json|md', 'json')
1675
- .action((cmd, opts) => {
1676
- const projectPath = opts.path || process.cwd();
1677
- switch (cmd) {
1678
- case 'status':
1679
- case undefined:
1680
- brainStatus(projectPath);
1681
- break;
1682
- case 'learnings':
1683
- case 'learn':
1684
- case 'l':
1685
- brainLearnings(projectPath, opts);
1686
- break;
1687
- case 'decisions':
1688
- case 'dec':
1689
- case 'd':
1690
- brainDecisions(projectPath, opts);
1691
- break;
1692
- case 'delete':
1693
- case 'del':
1694
- case 'rm':
1695
- console.log(chalk_1.default.gray('Usage: cm brain delete <type> <id>'));
1696
- console.log(chalk_1.default.gray(' type: learning | decision'));
1697
- console.log(chalk_1.default.gray(' id: first 8 chars of the ID'));
1698
- break;
1699
- case 'stats':
1700
- brainStats(projectPath);
1701
- break;
1702
- case 'export':
1703
- brainExport(projectPath, opts);
1704
- break;
1705
- default:
1706
- if (cmd === 'learning' || cmd === 'decision') {
1707
- console.log((0, theme_1.dim)(`Did you mean: cm brain ${cmd}s ?`));
1708
- }
1709
- else {
1710
- console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: status, learnings, decisions, delete, stats, export')]));
1711
- }
1712
- }
1713
- });
1714
- program
1715
- .command('brain-delete <type> <id>')
1716
- .description('Delete a learning or decision by ID prefix')
1717
- .option('--path <path>', 'Project path', process.cwd())
1718
- .action((type, id, opts) => {
1719
- const projectPath = opts.path || process.cwd();
1720
- brainDelete(projectPath, type, id);
1721
- });
1722
- function brainStatus(projectPath) {
1723
- const status = (0, continuity_1.getContinuityStatus)(projectPath);
1724
- if (!status.initialized) {
1725
- console.log((0, box_1.renderResult)('warning', 'Working memory not initialized.', [(0, theme_1.dim)('Run: cm continuity init')]));
1726
- return;
1727
- }
1728
- showBanner();
1729
- console.log((0, box_1.renderCommandHeader)('Brain β€” Memory Status', '🧠'));
1730
- // Stats row
1731
- console.log((0, theme_1.brand)(' β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”'));
1732
- console.log((0, theme_1.brand)(' β”‚') + (0, theme_1.error)(` ❀ Learn: ${padRight(String(status.learningCount), 4)}`) +
1733
- (0, theme_1.brand)(' β”‚') + (0, theme_1.brand)(` πŸ“‹ Decide: ${padRight(String(status.decisionCount), 3)}`) +
1734
- (0, theme_1.brand)(' β”‚') + phaseColor(status.phase)(` ● ${padRight(status.phase, 9)}`) +
1735
- (0, theme_1.brand)(' β”‚') + (0, theme_1.dim)(` #${padRight(String(status.iteration), 10)}`) + (0, theme_1.brand)('β”‚'));
1736
- console.log((0, theme_1.brand)(' β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜'));
1737
- console.log();
1738
- console.log((0, box_1.renderKeyValue)([
1739
- ['Project', String(status.project)],
1740
- ...(status.activeGoal ? [['Goal', String(status.activeGoal)]] : []),
1741
- ...(status.currentTask ? [['Task', String(status.currentTask)]] : []),
1742
- ['Completed', `${status.completedCount} items`],
1743
- ['Blockers', status.blockerCount > 0 ? (0, theme_1.warning)(`🚧 ${status.blockerCount}`) : (0, theme_1.success)('βœ… None')],
1744
- ...(status.lastUpdated ? [['Updated', formatTimeAgoCli(status.lastUpdated)]] : []),
1745
- ]));
1746
- console.log();
1747
- console.log((0, theme_1.dim)(' Commands:'));
1748
- console.log((0, theme_1.dim)(' cm brain learnings β€” View mistakes & lessons'));
1749
- console.log((0, theme_1.dim)(' cm brain decisions β€” View architecture decisions'));
1750
- console.log((0, theme_1.dim)(' cm brain stats β€” Memory statistics'));
1751
- console.log((0, theme_1.dim)(' cm brain export β€” Export memory data'));
1752
- console.log();
1753
- }
1754
- function brainLearnings(projectPath, opts) {
1755
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1756
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1757
- return;
1758
- }
1759
- let learnings = (0, continuity_1.getLearnings)(projectPath);
1760
- // Search filter
1761
- if (opts.search) {
1762
- const q = opts.search.toLowerCase();
1763
- learnings = learnings.filter(l => (l.whatFailed || '').toLowerCase().includes(q) ||
1764
- (l.whyFailed || '').toLowerCase().includes(q) ||
1765
- (l.howToPrevent || '').toLowerCase().includes(q));
1766
- }
1767
- // Last N
1768
- const limit = opts.last ? parseInt(opts.last) : 15;
1769
- const display = learnings.slice(-limit);
1770
- if (display.length === 0) {
1771
- console.log(`\n ${(0, theme_1.dim)(`No learnings ${opts.search ? 'matching "' + opts.search + '"' : 'captured yet'}. πŸŽ‰`)}\n`);
1772
- return;
1773
- }
1774
- console.log((0, box_1.renderCommandHeader)(`Learnings (${display.length}${learnings.length > limit ? '/' + learnings.length : ''})`, 'πŸ“š'));
1775
- for (const l of display) {
1776
- const shortId = l.id ? l.id.substring(0, 8) : '???';
1777
- console.log((0, theme_1.error)(` ❌ ${l.whatFailed}`) + (0, theme_1.dim)(` [${shortId}]`));
1778
- if (l.whyFailed)
1779
- console.log((0, theme_1.dim)(` Why: ${l.whyFailed}`));
1780
- if (l.howToPrevent)
1781
- console.log((0, theme_1.success)(` Fix: ${l.howToPrevent}`));
1782
- console.log((0, theme_1.dim)(` ${formatTimeAgoCli(l.timestamp)} | ${l.agent || 'unknown'}${l.module ? ' | πŸ“¦ ' + l.module : ''}\n`));
1783
- }
1784
- }
1785
- function brainDecisions(projectPath, opts) {
1786
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1787
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1788
- return;
1789
- }
1790
- const decisions = (0, continuity_1.getDecisions)(projectPath);
1791
- const limit = opts.last ? parseInt(opts.last) : 15;
1792
- const display = decisions.slice(-limit);
1793
- if (display.length === 0) {
1794
- console.log(`\n ${(0, theme_1.dim)('No decisions recorded yet.')}\n`);
1795
- return;
1796
- }
1797
- console.log((0, box_1.renderCommandHeader)(`Key Decisions (${display.length}${decisions.length > limit ? '/' + decisions.length : ''})`, 'πŸ“‹'));
1798
- for (const d of display) {
1799
- const shortId = d.id ? d.id.substring(0, 8) : '???';
1800
- console.log((0, theme_1.brand)(` πŸ“Œ ${d.decision}`) + (0, theme_1.dim)(` [${shortId}]`));
1801
- if (d.rationale)
1802
- console.log((0, theme_1.dim)(` Rationale: ${d.rationale}`));
1803
- console.log((0, theme_1.dim)(` ${formatTimeAgoCli(d.timestamp)} | ${d.agent || 'unknown'}\n`));
1804
- }
1805
- }
1806
- function brainDelete(projectPath, type, id) {
1807
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1808
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found.'));
1809
- return;
1810
- }
1811
- if (type === 'learning' || type === 'l') {
1812
- const learnings = (0, continuity_1.getLearnings)(projectPath);
1813
- const target = learnings.find(l => l.id && l.id.startsWith(id));
1814
- if (!target) {
1815
- console.log((0, box_1.renderResult)('error', `Learning not found with ID prefix: ${id}`));
1816
- return;
1817
- }
1818
- const del_success = (0, continuity_1.deleteLearning)(projectPath, target.id);
1819
- if (del_success) {
1820
- console.log((0, box_1.renderResult)('success', `Deleted learning: ${target.whatFailed}`));
1821
- }
1822
- else {
1823
- console.log((0, box_1.renderResult)('error', 'Failed to delete'));
1824
- }
1825
- }
1826
- else if (type === 'decision' || type === 'd') {
1827
- const decisions = (0, continuity_1.getDecisions)(projectPath);
1828
- const target = decisions.find(d => d.id && d.id.startsWith(id));
1829
- if (!target) {
1830
- console.log((0, box_1.renderResult)('error', `Decision not found with ID prefix: ${id}`));
1831
- return;
1832
- }
1833
- const del_success = (0, continuity_1.deleteDecision)(projectPath, target.id);
1834
- if (del_success) {
1835
- console.log((0, box_1.renderResult)('success', `Deleted decision: ${target.decision}`));
1836
- }
1837
- else {
1838
- console.log((0, box_1.renderResult)('error', 'Failed to delete'));
1839
- }
1840
- }
1841
- else {
1842
- console.log((0, box_1.renderResult)('error', `Unknown type: ${type}`, [(0, theme_1.dim)('Use: cm brain-delete learning <id> | cm brain-delete decision <id>')]));
1843
- }
1844
- }
1845
- function brainStats(projectPath) {
1846
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1847
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found. Run: cm continuity init'));
1848
- return;
1849
- }
1850
- const status = (0, continuity_1.getContinuityStatus)(projectPath);
1851
- const learnings = (0, continuity_1.getLearnings)(projectPath);
1852
- const decisions = (0, continuity_1.getDecisions)(projectPath);
1853
- console.log((0, box_1.renderCommandHeader)('Brain Statistics', 'πŸ“Š'));
1854
- console.log((0, box_1.renderKeyValue)([
1855
- ['Learnings', String(learnings.length)],
1856
- ['Decisions', String(decisions.length)],
1857
- ['Completed', `${status.completedCount} items`],
1858
- ['Blockers', String(status.blockerCount)],
1859
- ['Iteration', `#${status.iteration}`],
1860
- ]));
1861
- // Agent breakdown
1862
- const agentMap = {};
1863
- learnings.forEach(l => { if (l.agent)
1864
- agentMap[l.agent] = (agentMap[l.agent] || 0) + 1; });
1865
- decisions.forEach(d => { if (d.agent)
1866
- agentMap[d.agent] = (agentMap[d.agent] || 0) + 1; });
1867
- const agents = Object.entries(agentMap).sort((a, b) => b[1] - a[1]);
1868
- if (agents.length > 0) {
1869
- console.log();
1870
- console.log((0, theme_1.brand)(' Agents:'));
1871
- for (const [agent, count] of agents) {
1872
- console.log((0, theme_1.dim)(` πŸ€– ${padRight(agent, 20)} ${count} entries`));
1873
- }
1874
- }
1875
- // Module breakdown
1876
- const moduleMap = {};
1877
- learnings.forEach(l => { if (l.module)
1878
- moduleMap[l.module] = (moduleMap[l.module] || 0) + 1; });
1879
- const modules = Object.entries(moduleMap).sort((a, b) => b[1] - a[1]);
1880
- if (modules.length > 0) {
1881
- console.log();
1882
- console.log((0, theme_1.brand)(' Modules (most error-prone):'));
1883
- for (const [mod, count] of modules.slice(0, 5)) {
1884
- console.log((0, theme_1.dim)(` πŸ“¦ ${padRight(mod, 20)} ${count} learnings`));
1885
- }
1886
- }
1887
- // Time range
1888
- const allTimestamps = [...learnings.map(l => l.timestamp), ...decisions.map(d => d.timestamp)].filter(Boolean).sort();
1889
- if (allTimestamps.length > 0) {
1890
- console.log();
1891
- console.log((0, theme_1.dim)(` First entry: ${formatTimeAgoCli(allTimestamps[0])}`));
1892
- console.log((0, theme_1.dim)(` Latest: ${formatTimeAgoCli(allTimestamps[allTimestamps.length - 1])}`));
1893
- }
1894
- console.log();
1895
- }
1896
- function brainExport(projectPath, opts) {
1897
- if (!(0, continuity_1.hasCmDir)(projectPath)) {
1898
- console.log((0, box_1.renderResult)('warning', 'No .cm/ directory found.'));
1899
- return;
1900
- }
1901
- const learnings = (0, continuity_1.getLearnings)(projectPath);
1902
- const decisions = (0, continuity_1.getDecisions)(projectPath);
1903
- const status = (0, continuity_1.getContinuityStatus)(projectPath);
1904
- const format = opts.format || 'json';
1905
- if (format === 'json') {
1906
- const data = { status, learnings, decisions, exportedAt: new Date().toISOString() };
1907
- const outFile = `brain-export-${new Date().toISOString().slice(0, 10)}.json`;
1908
- fs_1.default.writeFileSync(outFile, JSON.stringify(data, null, 2));
1909
- console.log((0, box_1.renderResult)('success', `Exported to ${outFile}`, [(0, theme_1.dim)(`${learnings.length} learnings, ${decisions.length} decisions`)]));
1910
- }
1911
- else if (format === 'md') {
1912
- let md = `# Brain Export\n\n**Project:** ${status.project || 'Unknown'}\n**Exported:** ${new Date().toISOString()}\n\n`;
1913
- md += `## Learnings (${learnings.length})\n\n`;
1914
- for (const l of learnings) {
1915
- 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`;
1916
- }
1917
- md += `## Decisions (${decisions.length})\n\n`;
1918
- for (const d of decisions) {
1919
- md += `### πŸ“Œ ${d.decision}\n- **Rationale:** ${d.rationale || 'N/A'}\n- **Agent:** ${d.agent || 'unknown'} | **Date:** ${d.timestamp || 'N/A'}\n\n`;
1920
- }
1921
- const outFile = `brain-export-${new Date().toISOString().slice(0, 10)}.md`;
1922
- fs_1.default.writeFileSync(outFile, md);
1923
- console.log((0, box_1.renderResult)('success', `Exported to ${outFile}`, [(0, theme_1.dim)(`${learnings.length} learnings, ${decisions.length} decisions`)]));
1924
- }
1925
- else {
1926
- console.log((0, box_1.renderResult)('error', `Unknown format: ${format}`, [(0, theme_1.dim)('Use: --format json | --format md')]));
1927
- }
1928
- }
1929
- // ─── Skill Command ──────────────────────────────────────────────────────────
1930
- const SKILL_CATALOG = {
1931
- engineering: {
1932
- icon: 'πŸ”§',
1933
- skills: [
1934
- { name: 'cm-tdd', desc: 'Red-Green-Refactor cycle β€” test before code' },
1935
- { name: 'cm-debugging', desc: '5-phase root cause investigation' },
1936
- { name: 'cm-quality-gate', desc: '6-gate verification system' },
1937
- { name: 'cm-test-gate', desc: 'Setup 4-layer test infrastructure' },
1938
- { name: 'cm-code-review', desc: 'Professional PR review lifecycle' },
1939
- ],
1940
- },
1941
- operations: {
1942
- icon: 'βš™οΈ',
1943
- skills: [
1944
- { name: 'cm-safe-deploy', desc: 'Multi-gate deploy pipeline with rollback' },
1945
- { name: 'cm-identity-guard', desc: 'Prevent wrong-account deploys' },
1946
- { name: 'cm-git-worktrees', desc: 'Isolated feature branches without context-switch' },
1947
- { name: 'cm-terminal', desc: 'Safe terminal execution with logging' },
1948
- { name: 'cm-secret-shield', desc: 'Scan & block secrets before commit/deploy' },
1949
- { name: 'cm-security-gate', desc: 'Pre-production vulnerability audit (Snyk/Aikido)' },
1950
- { name: 'cm-safe-i18n', desc: 'Multi-pass translation with 8 audit gates' },
1951
- ],
1952
- },
1953
- product: {
1954
- icon: '🎨',
1955
- skills: [
1956
- { name: 'cm-planning', desc: 'Intent β†’ design β†’ structured plan' },
1957
- { name: 'cm-ux-master', desc: '48 UX Laws + 37 Design Tests' },
1958
- { name: 'cm-ui-preview', desc: 'Browser-previewed UI prototypes' },
1959
- { name: 'cm-brainstorm-idea', desc: 'Multi-lens ideation with scoring' },
1960
- { name: 'cm-jtbd', desc: 'Jobs-To-Be-Done framework & canvas' },
1961
- { name: 'cm-dockit', desc: 'Complete knowledge base from codebase' },
1962
- { name: 'cm-project-bootstrap', desc: 'Full project setup: design β†’ CI β†’ deploy' },
1963
- { name: 'cm-readit', desc: 'Web audio TTS reader & MP3 player' },
1964
- ],
1965
- },
1966
- growth: {
1967
- icon: 'πŸ“ˆ',
1968
- skills: [
1969
- { name: 'cm-content-factory', desc: 'AI content engine: research β†’ deploy' },
1970
- { name: 'cm-ads-tracker', desc: 'Facebook/TikTok/Google pixel setup' },
1971
- { name: 'cro-methodology', desc: 'Conversion audit + A/B test design' },
1972
- { name: 'cm-deep-search', desc: 'Multi-source deep research synthesis' },
1973
- ],
1974
- },
1975
- orchestration: {
1976
- icon: '🎯',
1977
- skills: [
1978
- { name: 'cm-execution', desc: 'Execute plans: batch, parallel, RARV' },
1979
- { name: 'cm-continuity', desc: 'Working memory: read/update per session' },
1980
- { name: 'cm-skill-index', desc: 'Progressive skill discovery & routing' },
1981
- { name: 'cm-skill-mastery', desc: 'Meta: when/how to invoke skills' },
1982
- { name: 'cm-skill-chain', desc: 'Multi-skill pipeline execution' },
1983
- ],
1984
- },
1985
- workflow: {
1986
- icon: '⚑',
1987
- skills: [
1988
- { name: 'cm-start', desc: 'Onboarding & session kick-off wizard' },
1989
- { name: 'cm-dashboard', desc: 'Project status & task Kanban board' },
1990
- { name: 'cm-status', desc: 'Quick project health snapshot' },
1991
- { name: 'cm-how-it-work', desc: `Interactive explainer for all ${SKILL_COUNT} skills` },
1992
- { name: 'cm-example', desc: 'Minimal template for new skills' },
1993
- ],
1994
- },
1995
- };
1996
- program
1997
- .command('skill [cmd] [name]')
1998
- .alias('sk')
1999
- .description('Skill management (list|info|domains|create)')
2000
- .action((cmd, name) => {
2001
- switch (cmd) {
2002
- case 'create':
2003
- if (!name) {
2004
- console.log((0, box_1.renderResult)('error', 'Usage: cm skill create "skill-name"'));
2005
- return;
2006
- }
2007
- console.log((0, box_1.renderResult)('success', `Scaffolding new skill: ${name}`, [(0, theme_1.dim)('Triggers skill-creator-ultra pipeline.')]));
2008
- break;
2009
- case 'list':
2010
- case 'ls':
2011
- case undefined:
2012
- skillList();
2013
- break;
2014
- case 'info':
2015
- if (!name) {
2016
- console.log((0, box_1.renderResult)('error', 'Usage: cm skill info <skill-name>'));
2017
- return;
2018
- }
2019
- skillInfo(name);
2020
- break;
2021
- case 'domains':
2022
- skillDomains();
2023
- break;
2024
- default:
2025
- // Treat cmd as skill name for `cody skill cm-tdd`
2026
- skillInfo(cmd);
2027
- }
2028
- });
2029
- function skillList(filterDomain) {
2030
- const entries = filterDomain
2031
- ? Object.entries(SKILL_CATALOG).filter(([d]) => d.toLowerCase().startsWith(filterDomain.toLowerCase()))
2032
- : Object.entries(SKILL_CATALOG);
2033
- if (entries.length === 0) {
2034
- console.log((0, box_1.renderResult)('error', `Domain not found: ${filterDomain}`, [(0, theme_1.dim)('Domains: engineering, operations, product, growth, orchestration, workflow')]));
2035
- return;
2036
- }
2037
- console.log((0, box_1.renderCommandHeader)(`Cody Master β€” ${SKILL_COUNT} Skills`, '🧩'));
2038
- let total = 0;
2039
- for (const [domain, data] of entries) {
2040
- console.log((0, theme_1.brand)(` ${data.icon} ${domain.charAt(0).toUpperCase() + domain.slice(1)}`));
2041
- for (const skill of data.skills) {
2042
- console.log(` ${(0, theme_1.brand)(padRight(skill.name, 26))} ${(0, theme_1.dim)(skill.desc)}`);
2043
- total++;
2044
- }
2045
- console.log();
2046
- }
2047
- console.log((0, theme_1.dim)(` ${total} skills across ${entries.length} domains`));
2048
- console.log((0, theme_1.dim)(` Install: npx codymaster add --all`));
2049
- console.log((0, theme_1.dim)(` Add one: npx codymaster add --skill <name>\n`));
2050
- }
2051
- function skillInfo(name) {
2052
- for (const [domain, data] of Object.entries(SKILL_CATALOG)) {
2053
- const skill = data.skills.find(s => s.name === name);
2054
- if (skill) {
2055
- console.log((0, box_1.renderCommandHeader)(`Skill: ${skill.name}`, '🧩'));
2056
- const agents = (0, judge_1.suggestAgentsForSkill)(skill.name);
2057
- console.log((0, box_1.renderKeyValue)([
2058
- ['Domain', domain],
2059
- ['Description', skill.desc],
2060
- ['Best Agents', agents.join(', ')],
2061
- ['Invoke', `@[/${skill.name}] (Antigravity/Gemini)`],
2062
- ['', `/${skill.name} (Claude Code)`],
2063
- ['', `@${skill.name} (Cursor/Windsurf/Cline)`],
2064
- ]));
2065
- console.log();
2066
- return;
2067
- }
2068
- }
2069
- console.log((0, box_1.renderResult)('error', `Skill not found: ${name}`, [(0, theme_1.dim)('Use "cm skill list" to see all available skills.')]));
2070
- }
2071
- function skillDomains() {
2072
- console.log((0, box_1.renderCommandHeader)('Skill Domains', '🎯'));
2073
- let total = 0;
2074
- for (const [domain, data] of Object.entries(SKILL_CATALOG)) {
2075
- console.log(` ${data.icon} ${(0, theme_1.brand)(padRight(domain.charAt(0).toUpperCase() + domain.slice(1), 16))} ${(0, theme_1.dim)(`${data.skills.length} skills`)}`);
2076
- total += data.skills.length;
2077
- }
2078
- console.log((0, theme_1.dim)(`\n Total: ${total} skills across ${Object.keys(SKILL_CATALOG).length} domains\n`));
2079
- }
2080
- // ─── Judge Command ──────────────────────────────────────────────────────────
2081
- program
2082
- .command('judge [taskId]')
2083
- .alias('j')
2084
- .description('Judge agent decisions for tasks')
2085
- .option('-p, --project <name>', 'Filter by project')
2086
- .action((taskId, opts) => {
2087
- const data = (0, data_1.loadData)();
2088
- if (taskId) {
2089
- // Single task evaluation
2090
- const task = (0, data_1.findTaskByIdPrefix)(data, taskId);
2091
- if (!task) {
2092
- console.log((0, box_1.renderResult)('error', `Task not found: ${taskId}`));
2093
- return;
2094
- }
2095
- const project = data.projects.find(p => p.id === task.projectId);
2096
- let learnings = [];
2097
- if ((project === null || project === void 0 ? void 0 : project.path) && (0, continuity_1.hasCmDir)(project.path)) {
2098
- learnings = (0, continuity_1.getLearnings)(project.path);
2099
- }
2100
- const decision = (0, judge_1.evaluateTaskState)(task, data.tasks, learnings);
2101
- console.log((0, box_1.renderCommandHeader)('Judge Decision', 'πŸ€–'));
2102
- const details = [
2103
- ['Task', task.title],
2104
- ['Column', task.column],
2105
- ['Action', `${decision.badge} ${decision.action}`],
2106
- ['Reason', decision.reason],
2107
- ['Confidence', `${Math.round(decision.confidence * 100)}%`],
2108
- ];
2109
- if (decision.suggestedNextSkill)
2110
- details.push(['Suggested', decision.suggestedNextSkill]);
2111
- console.log((0, box_1.renderKeyValue)(details));
2112
- console.log();
2113
- }
2114
- else {
2115
- // All active tasks
2116
- let tasks = data.tasks;
2117
- if (opts.project) {
2118
- const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
2119
- if (!project) {
2120
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
2121
- return;
2122
- }
2123
- tasks = tasks.filter(t => t.projectId === project.id);
2124
- }
2125
- let allLearnings = [];
2126
- for (const project of data.projects) {
2127
- if (project.path && (0, continuity_1.hasCmDir)(project.path)) {
2128
- allLearnings = allLearnings.concat((0, continuity_1.getLearnings)(project.path));
2129
- }
2130
- }
2131
- const decisions = (0, judge_1.evaluateAllTasks)(tasks, allLearnings);
2132
- if (decisions.size === 0) {
2133
- console.log(`\n ${(0, theme_1.dim)('No active tasks to evaluate.')}\n`);
2134
- return;
2135
- }
2136
- console.log((0, box_1.renderCommandHeader)(`Judge Decisions (${decisions.size} active tasks)`, 'πŸ€–'));
2137
- console.log((0, theme_1.dim)(' ' + padRight('Badge', 8) + padRight('Action', 12) + padRight('Confidence', 12) + 'Task'));
2138
- console.log((0, theme_1.dim)(' ' + '─'.repeat(70)));
2139
- for (const [tid, dec] of decisions) {
2140
- const task = tasks.find(t => t.id === tid);
2141
- const actionColor = dec.action === 'CONTINUE' ? theme_1.success
2142
- : dec.action === 'COMPLETE' ? theme_1.brand
2143
- : dec.action === 'ESCALATE' ? theme_1.warning
2144
- : theme_1.brand;
2145
- console.log(' ' + padRight(dec.badge, 8) + actionColor(padRight(dec.action, 12)) + (0, theme_1.dim)(padRight(`${Math.round(dec.confidence * 100)}%`, 12)) + ((task === null || task === void 0 ? void 0 : task.title) || tid.substring(0, 8)));
2146
- }
2147
- console.log();
2148
- }
2149
- });
2150
- // ─── Init Command ───────────────────────────────────────────────────────────
2151
- program
2152
- .command('init')
2153
- .description('Initialize project from current directory')
2154
- .option('-n, --name <name>', 'Project name')
2155
- .option('--path <path>', 'Workspace path', process.cwd())
2156
- .action((opts) => {
2157
- const data = (0, data_1.loadData)();
2158
- const projectName = opts.name || path_1.default.basename(opts.path || process.cwd());
2159
- const projectPath = opts.path || process.cwd();
2160
- // Check if already exists
2161
- const existing = data.projects.find(p => p.path === projectPath || p.name === projectName);
2162
- if (existing) {
2163
- console.log((0, box_1.renderResult)('warning', `Project already exists: ${existing.name}`, [(0, theme_1.dim)(`ID: ${(0, data_1.shortId)(existing.id)} | Path: ${existing.path}`)]));
2164
- return;
2165
- }
2166
- const project = {
2167
- id: crypto_1.default.randomUUID(),
2168
- name: projectName,
2169
- path: projectPath,
2170
- agents: [],
2171
- createdAt: new Date().toISOString(),
2172
- };
2173
- data.projects.push(project);
2174
- (0, data_1.logActivity)(data, 'project_created', `Project "${project.name}" initialized via CLI`, project.id);
2175
- (0, data_1.saveData)(data);
2176
- // Also init working memory
2177
- (0, continuity_1.ensureCmDir)(projectPath);
2178
- console.log((0, box_1.renderResult)('success', `Project initialized: ${projectName}`, [
2179
- (0, theme_1.dim)(`ID: ${(0, data_1.shortId)(project.id)}`),
2180
- (0, theme_1.dim)(`Path: ${projectPath}`),
2181
- (0, theme_1.dim)(`.cm/ Working memory created`),
2182
- ]));
2183
- console.log();
2184
- if (!isDashboardRunning()) {
2185
- (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT);
2186
- console.log((0, theme_1.success)(` πŸš€ Dashboard auto-started! You can track progress at http://codymaster.localhost:${data_1.DEFAULT_PORT}`));
2187
- }
2188
- console.log((0, theme_1.info)('πŸ’‘ Next steps:'));
2189
- console.log((0, theme_1.dim)(' cm task add "My first task"'));
2190
- console.log((0, theme_1.dim)(' cm open\n'));
2191
- });
2192
- // ─── Open Command ───────────────────────────────────────────────────────────
2193
- program
2194
- .command('open')
2195
- .alias('o')
2196
- .description('Open dashboard in browser')
2197
- .option('-p, --port <port>', 'Port number', String(data_1.DEFAULT_PORT))
2198
- .action((opts) => {
2199
- const port = parseInt(opts.port) || data_1.DEFAULT_PORT;
2200
- if (!isDashboardRunning()) {
2201
- console.log((0, box_1.renderResult)('warning', 'Dashboard not running. Starting it first...'));
2202
- (0, dashboard_1.launchDashboard)(port);
2203
- setTimeout(() => openUrl(`http://codymaster.localhost:${port}`), 1500);
2204
- }
2205
- else {
2206
- console.log((0, theme_1.info)(`🌐 Opening http://codymaster.localhost:${port} ...`));
2207
- openUrl(`http://codymaster.localhost:${port}`);
2208
- }
2209
- });
2210
- // ─── Config Command ─────────────────────────────────────────────────────────
2211
- program
2212
- .command('config')
2213
- .alias('cfg')
2214
- .description('Show configuration & data paths')
2215
- .action(() => {
2216
- console.log((0, box_1.renderCommandHeader)('Cody Configuration', 'βš™οΈ'));
2217
- console.log((0, box_1.renderKeyValue)([
2218
- ['Version', VERSION],
2219
- ['Data Dir', data_1.DATA_DIR],
2220
- ['Data File', data_1.DATA_FILE],
2221
- ['PID File', data_1.PID_FILE],
2222
- ['Port', String(data_1.DEFAULT_PORT)],
2223
- ['CLI Names', 'cm | cm | codymaster'],
2224
- ]));
2225
- console.log();
2226
- // Show data stats
2227
- const data = (0, data_1.loadData)();
2228
- console.log((0, theme_1.brand)(' Data Stats:'));
2229
- console.log((0, theme_1.dim)(` Projects: ${data.projects.length}`));
2230
- console.log((0, theme_1.dim)(` Tasks: ${data.tasks.length}`));
2231
- console.log((0, theme_1.dim)(` Deploys: ${data.deployments.length}`));
2232
- console.log((0, theme_1.dim)(` Activities: ${data.activities.length}`));
2233
- console.log((0, theme_1.dim)(` Changelog: ${data.changelog.length}`));
2234
- console.log();
2235
- // Dashboard status
2236
- if (isDashboardRunning()) {
2237
- console.log((0, theme_1.success)(` πŸš€ Dashboard: RUNNING at http://codymaster.localhost:${data_1.DEFAULT_PORT}\n`));
2238
- }
2239
- else {
2240
- console.log((0, theme_1.dim)(` ⚫ Dashboard: not running\n`));
2241
- }
2242
- });
2243
- // ─── Agents Command ─────────────────────────────────────────────────────────
2244
- const AGENT_LIST = [
2245
- { id: 'antigravity', name: 'Google Antigravity', icon: '🟒' },
2246
- { id: 'claude-code', name: 'Claude Code', icon: '🟣' },
2247
- { id: 'cursor', name: 'Cursor', icon: 'πŸ”΅' },
2248
- { id: 'gemini-cli', name: 'Gemini CLI', icon: 'πŸ’»' },
2249
- { id: 'windsurf', name: 'Windsurf', icon: '🟠' },
2250
- { id: 'cline', name: 'Cline / RooCode', icon: '🟀' },
2251
- { id: 'copilot', name: 'GitHub Copilot', icon: '🐈' },
2252
- ];
2253
- program
2254
- .command('agents [skill]')
2255
- .alias('ag')
2256
- .description('List agents or suggest best agent for a skill')
2257
- .action((skill) => {
2258
- if (skill) {
2259
- // Suggest best agents for skill
2260
- const domain = (0, judge_1.getSkillDomain)(skill);
2261
- const agents = (0, judge_1.suggestAgentsForSkill)(skill);
2262
- console.log((0, box_1.renderCommandHeader)(`Agent Suggestions for ${skill}`, 'πŸ€–'));
2263
- console.log((0, theme_1.dim)(` Domain: ${domain}\n`));
2264
- agents.forEach((agentId, index) => {
2265
- const agent = AGENT_LIST.find(a => a.id === agentId);
2266
- const affinity = index === 0 ? (0, theme_1.success)('β˜… BEST') : index === 1 ? (0, theme_1.warning)('● GOOD') : (0, theme_1.dim)('β—‹ OK');
2267
- console.log(` ${(agent === null || agent === void 0 ? void 0 : agent.icon) || 'πŸ€–'} ${padRight((agent === null || agent === void 0 ? void 0 : agent.name) || agentId, 24)} ${affinity}`);
2268
- });
2269
- console.log();
2270
- }
2271
- else {
2272
- // List all agents
2273
- console.log((0, box_1.renderCommandHeader)('Available Agents', 'πŸ€–'));
2274
- for (const agent of AGENT_LIST) {
2275
- console.log(` ${agent.icon} ${(0, theme_1.brand)(padRight(agent.name, 24))} ${(0, theme_1.dim)(agent.id)}`);
2276
- }
2277
- console.log();
2278
- console.log((0, theme_1.dim)(' πŸ’‘ Tip: cm agents <skill-name> to see best agents for a skill\n'));
2279
- }
2280
- });
2281
- // ─── Sync Command ───────────────────────────────────────────────────────────
2282
- program
2283
- .command('sync <file>')
2284
- .description('Bulk import tasks from JSON file')
2285
- .option('-p, --project <name>', 'Target project')
2286
- .option('--agent <agent>', 'Agent name')
2287
- .option('--skill <skill>', 'Skill name')
2288
- .action((file, opts) => {
2289
- const filePath = path_1.default.resolve(file);
2290
- if (!fs_1.default.existsSync(filePath)) {
2291
- console.log((0, box_1.renderResult)('error', `File not found: ${filePath}`));
2292
- return;
2293
- }
2294
- let tasks;
2295
- try {
2296
- const content = fs_1.default.readFileSync(filePath, 'utf-8');
2297
- const parsed = JSON.parse(content);
2298
- tasks = Array.isArray(parsed) ? parsed : parsed.tasks;
2299
- if (!Array.isArray(tasks))
2300
- throw new Error('Invalid format');
2301
- }
2302
- catch (err) {
2303
- console.log((0, box_1.renderResult)('error', `Invalid JSON file: ${err.message}`, [(0, theme_1.dim)('Expected format: [{"title": "...", "priority": "...", "column": "..."}]')]));
2304
- return;
2305
- }
2306
- const data = (0, data_1.loadData)();
2307
- let projectId;
2308
- if (opts.project) {
2309
- const p = (0, data_1.findProjectByNameOrId)(data, opts.project);
2310
- if (!p) {
2311
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
2312
- return;
2313
- }
2314
- projectId = p.id;
2315
- }
2316
- else if (data.projects.length > 0) {
2317
- projectId = data.projects[0].id;
2318
- }
2319
- else {
2320
- const dp = { id: crypto_1.default.randomUUID(), name: 'Default Project', path: process.cwd(), agents: [], createdAt: new Date().toISOString() };
2321
- data.projects.push(dp);
2322
- projectId = dp.id;
2323
- }
2324
- const now = new Date().toISOString();
2325
- let count = 0;
2326
- for (const t of tasks) {
2327
- const col = t.column || 'backlog';
2328
- const ct = data.tasks.filter(tk => tk.column === col && tk.projectId === projectId);
2329
- const mo = ct.length > 0 ? Math.max(...ct.map(tk => tk.order)) : -1;
2330
- const task = {
2331
- id: crypto_1.default.randomUUID(), projectId: projectId,
2332
- title: String(t.title || '').trim(),
2333
- description: String(t.description || '').trim(),
2334
- column: col, order: mo + 1,
2335
- priority: t.priority || 'medium',
2336
- agent: opts.agent || t.agent || '',
2337
- skill: opts.skill || t.skill || '',
2338
- createdAt: now, updatedAt: now,
2339
- };
2340
- data.tasks.push(task);
2341
- count++;
2342
- }
2343
- (0, data_1.logActivity)(data, 'task_created', `Synced ${count} tasks from ${path_1.default.basename(filePath)}`, projectId, opts.agent || '', { count, file: filePath });
2344
- (0, data_1.saveData)(data);
2345
- const project = data.projects.find(p => p.id === projectId);
2346
- console.log((0, box_1.renderResult)('success', `Synced ${count} tasks!`, [
2347
- (0, theme_1.dim)(`Project: ${(project === null || project === void 0 ? void 0 : project.name) || 'Default'}`),
2348
- (0, theme_1.dim)(`Source: ${filePath}`),
2349
- ...(opts.agent ? [(0, theme_1.dim)(`Agent: ${opts.agent}`)] : []),
2350
- ]));
2351
- });
2352
- // ─── Chain Command ──────────────────────────────────────────────────────────
2353
- // TRIZ #40 Composite Materials β€” skills compose into pipelines
2354
- program
2355
- .command('chain <cmd> [args...]')
2356
- .alias('ch')
2357
- .description('Skill chain pipelines (list|info|start|status|advance|skip|abort|auto|history)')
2358
- .option('-p, --project <name>', 'Project name or ID')
2359
- .option('--agent <agent>', 'Agent name', 'antigravity')
2360
- .action((cmd, args, opts) => {
2361
- switch (cmd) {
2362
- case 'list':
2363
- case 'ls':
2364
- chainList();
2365
- break;
2366
- case 'info':
2367
- chainInfo(args[0]);
2368
- break;
2369
- case 'start':
2370
- chainStart(args[0], args.slice(1).join(' '), opts);
2371
- break;
2372
- case 'status':
2373
- case 'st':
2374
- chainStatus(args[0]);
2375
- break;
2376
- case 'advance':
2377
- case 'next':
2378
- chainAdvance(args[0], args.slice(1).join(' '));
2379
- break;
2380
- case 'skip':
2381
- chainSkip(args[0], args.slice(1).join(' '));
2382
- break;
2383
- case 'abort':
2384
- chainAbort(args[0], args.slice(1).join(' '));
2385
- break;
2386
- case 'auto':
2387
- chainAuto(args.join(' '), opts);
2388
- break;
2389
- case 'history':
2390
- case 'hist':
2391
- chainHistory();
2392
- break;
2393
- default:
2394
- console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: list, info, start, status, advance, skip, abort, auto, history')]));
2395
- }
2396
- });
2397
- function chainList() {
2398
- const chains = (0, skill_chain_1.listChains)();
2399
- console.log((0, box_1.renderCommandHeader)('Available Skill Chains', 'πŸ”—'));
2400
- for (const chain of chains) {
2401
- console.log(` ${chain.icon} ${(0, theme_1.brand)(padRight(chain.name, 24))} ${(0, theme_1.dim)(chain.description)}`);
2402
- console.log((0, theme_1.dim)(` ID: ${chain.id} | Steps: ${chain.steps.length} | Triggers: ${chain.triggers.slice(0, 4).join(', ')}...`));
2403
- console.log();
2404
- }
2405
- console.log((0, theme_1.dim)(` Total: ${chains.length} chains\n`));
2406
- console.log((0, theme_1.info)('πŸ’‘ Quick start:'));
2407
- console.log((0, theme_1.dim)(' cm chain auto "Build user authentication" # Auto-detect chain'));
2408
- console.log((0, theme_1.dim)(' cm chain start feature-development "My task" # Start specific chain\n'));
2409
- }
2410
- function chainInfo(chainId) {
2411
- if (!chainId) {
2412
- console.log((0, box_1.renderResult)('error', 'Usage: cm chain info <chain-id>'));
2413
- return;
2414
- }
2415
- const chain = (0, skill_chain_1.findChain)(chainId);
2416
- if (!chain) {
2417
- console.log((0, box_1.renderResult)('error', `Chain not found: ${chainId}`, [(0, theme_1.dim)('Use "cm chain list" to see available chains.')]));
2418
- return;
2419
- }
2420
- console.log((0, box_1.renderCommandHeader)(`Chain: ${chain.name}`, chain.icon));
2421
- console.log((0, box_1.renderKeyValue)([
2422
- ['ID', chain.id],
2423
- ['Description', chain.description],
2424
- ['Steps', String(chain.steps.length)],
2425
- ['Triggers', chain.triggers.join(', ')],
2426
- ]));
2427
- console.log();
2428
- console.log((0, theme_1.brand)(' Pipeline:'));
2429
- for (let i = 0; i < chain.steps.length; i++) {
2430
- const step = chain.steps[i];
2431
- const condBadge = step.condition === 'always' ? (0, theme_1.success)('ALWAYS') : step.condition === 'if-complex' ? (0, theme_1.warning)('IF-COMPLEX') : (0, theme_1.brand)('IF-READY');
2432
- const optBadge = step.optional ? (0, theme_1.dim)(' (optional)') : '';
2433
- const connector = i < chain.steps.length - 1 ? ' β”‚' : ' ';
2434
- console.log(` ${(0, theme_1.brand)(`${i + 1}.`)} ${padRight(step.skill, 24)} ${condBadge}${optBadge}`);
2435
- console.log((0, theme_1.dim)(` ${connector} ${step.description}`));
2436
- if (i < chain.steps.length - 1)
2437
- console.log((0, theme_1.dim)(' β”‚'));
2438
- }
2439
- console.log();
2440
- }
2441
- function chainStart(chainId, taskTitle, opts) {
2442
- var _a, _b, _c;
2443
- if (!chainId) {
2444
- console.log((0, box_1.renderResult)('error', 'Usage: cm chain start <chain-id> "Task title"'));
2445
- return;
2446
- }
2447
- if (!taskTitle) {
2448
- console.log((0, box_1.renderResult)('error', 'Task title required. Usage: cm chain start <chain-id> "My task"'));
2449
- return;
2450
- }
2451
- const chain = (0, skill_chain_1.findChain)(chainId);
2452
- if (!chain) {
2453
- console.log((0, box_1.renderResult)('error', `Chain not found: ${chainId}`));
2454
- return;
2455
- }
2456
- const data = (0, data_1.loadData)();
2457
- let projectId;
2458
- if (opts.project) {
2459
- const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
2460
- if (!project) {
2461
- console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
2462
- return;
2463
- }
2464
- projectId = project.id;
2465
- }
2466
- else if (data.projects.length > 0) {
2467
- projectId = data.projects[0].id;
2468
- }
2469
- else {
2470
- console.log((0, box_1.renderResult)('error', 'No projects. Create one first: cm init'));
2471
- return;
2472
- }
2473
- const agent = opts.agent || 'antigravity';
2474
- const execution = (0, skill_chain_1.createChainExecution)(chain, projectId, taskTitle, agent);
2475
- data.chainExecutions.push(execution);
2476
- // Create a task linked to this chain
2477
- const now = new Date().toISOString();
2478
- const task = {
2479
- id: crypto_1.default.randomUUID(), projectId, title: taskTitle, description: `Chain: ${chain.name}`,
2480
- column: 'in-progress', order: 0, priority: 'medium', agent, skill: ((_a = execution.steps[0]) === null || _a === void 0 ? void 0 : _a.skill) || '',
2481
- createdAt: now, updatedAt: now, chainId: chain.id, chainExecutionId: execution.id,
2482
- };
2483
- data.tasks.push(task);
2484
- (0, data_1.logActivity)(data, 'chain_started', `Chain "${chain.name}" started: "${taskTitle}"`, projectId, agent, {
2485
- chainId: chain.id, executionId: execution.id, steps: chain.steps.length,
2486
- });
2487
- (0, data_1.saveData)(data);
2488
- const project = data.projects.find(p => p.id === projectId);
2489
- console.log((0, box_1.renderResult)('success', 'Chain started!', [
2490
- (0, theme_1.dim)(`Chain: ${chain.icon} ${chain.name}`),
2491
- (0, theme_1.dim)(`Task: ${taskTitle}`),
2492
- (0, theme_1.dim)(`Project: ${(project === null || project === void 0 ? void 0 : project.name) || 'β€”'}`),
2493
- (0, theme_1.dim)(`Agent: ${agent}`),
2494
- (0, theme_1.dim)(`Steps: ${chain.steps.length}`),
2495
- (0, theme_1.dim)(`Exec ID: ${(0, data_1.shortId)(execution.id)}`),
2496
- ]));
2497
- console.log((0, theme_1.brand)(` β–Ά 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}`));
2498
- console.log((0, theme_1.dim)(`\n Next: cm chain advance ${(0, data_1.shortId)(execution.id)} "output summary"\n`));
2499
- }
2500
- function chainStatus(execIdPrefix) {
2501
- const data = (0, data_1.loadData)();
2502
- if (execIdPrefix) {
2503
- // Show specific execution
2504
- const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2505
- if (!exec) {
2506
- console.log((0, box_1.renderResult)('error', `Chain execution not found: ${execIdPrefix}`));
2507
- return;
2508
- }
2509
- console.log();
2510
- console.log((0, skill_chain_1.formatChainProgress)(exec));
2511
- console.log();
2512
- return;
2513
- }
2514
- // Show all active executions
2515
- const active = data.chainExecutions.filter(e => e.status === 'running' || e.status === 'paused');
2516
- if (active.length === 0) {
2517
- console.log(`\n ${(0, theme_1.dim)('No active chain executions.')}`);
2518
- console.log(` ${(0, theme_1.dim)('Start one with: cm chain auto "task description"')}\n`);
2519
- return;
2520
- }
2521
- console.log((0, box_1.renderCommandHeader)(`Active Chains (${active.length})`, 'πŸ”—'));
2522
- for (const exec of active) {
2523
- const project = data.projects.find(p => p.id === exec.projectId);
2524
- const currentSkill = (0, skill_chain_1.getCurrentSkill)(exec);
2525
- const progressBar = (0, skill_chain_1.formatChainProgressBar)(exec);
2526
- console.log(` ${(0, theme_1.brand)(exec.chainName)} β€” "${exec.taskTitle}"`);
2527
- console.log((0, theme_1.dim)(` ${progressBar} | Step ${exec.currentStepIndex + 1}/${exec.steps.length}: ${currentSkill || 'done'}`));
2528
- console.log((0, theme_1.dim)(` ID: ${(0, data_1.shortId)(exec.id)} | Agent: ${exec.agent} | Project: ${(project === null || project === void 0 ? void 0 : project.name) || 'β€”'}\n`));
2529
- }
2530
- }
2531
- function chainAdvance(execIdPrefix, output) {
2532
- if (!execIdPrefix) {
2533
- console.log((0, box_1.renderResult)('error', 'Usage: cm chain advance <exec-id> ["output summary"]'));
2534
- return;
2535
- }
2536
- const data = (0, data_1.loadData)();
2537
- const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2538
- if (!exec) {
2539
- console.log((0, box_1.renderResult)('error', `Chain execution not found: ${execIdPrefix}`));
2540
- return;
2541
- }
2542
- if (exec.status !== 'running') {
2543
- console.log((0, box_1.renderResult)('warning', `Chain is ${exec.status}, cannot advance.`));
2544
- return;
2545
- }
2546
- const completedStep = exec.steps[exec.currentStepIndex];
2547
- const result = (0, skill_chain_1.advanceChain)(exec, output);
2548
- // Update linked task's current skill
2549
- const linkedTask = data.tasks.find(t => t.chainExecutionId === exec.id);
2550
- if (linkedTask && result.nextSkill) {
2551
- linkedTask.skill = result.nextSkill;
2552
- linkedTask.updatedAt = new Date().toISOString();
2553
- }
2554
- if (result.completed) {
2555
- if (linkedTask) {
2556
- linkedTask.column = 'review';
2557
- linkedTask.updatedAt = new Date().toISOString();
2558
- }
2559
- (0, data_1.logActivity)(data, 'chain_completed', `Chain "${exec.chainName}" completed: "${exec.taskTitle}"`, exec.projectId, exec.agent, {
2560
- executionId: exec.id, totalSteps: exec.steps.length,
2561
- });
2562
- (0, data_1.saveData)(data);
2563
- console.log((0, box_1.renderResult)('success', `Chain completed! All ${exec.steps.length} steps done.`, [
2564
- (0, theme_1.dim)(`Chain: ${exec.chainName}`),
2565
- (0, theme_1.dim)(`Task: ${exec.taskTitle}`),
2566
- ]));
2567
- }
2568
- else {
2569
- (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, {
2570
- executionId: exec.id, completedSkill: completedStep === null || completedStep === void 0 ? void 0 : completedStep.skill, nextSkill: result.nextSkill,
2571
- });
2572
- (0, data_1.saveData)(data);
2573
- const nextStep = exec.steps[exec.currentStepIndex];
2574
- console.log((0, box_1.renderResult)('success', `Step completed: ${completedStep === null || completedStep === void 0 ? void 0 : completedStep.skill}`));
2575
- console.log((0, theme_1.brand)(` β–Ά Next step: ${result.nextSkill} β€” ${nextStep === null || nextStep === void 0 ? void 0 : nextStep.description}`));
2576
- console.log((0, theme_1.dim)(` Progress: ${(0, skill_chain_1.formatChainProgressBar)(exec)}\n`));
2577
- }
2578
- }
2579
- function chainSkip(execIdPrefix, reason) {
2580
- if (!execIdPrefix) {
2581
- console.log((0, box_1.renderResult)('error', 'Usage: cm chain skip <exec-id> ["reason"]'));
2582
- return;
2583
- }
2584
- const data = (0, data_1.loadData)();
2585
- const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2586
- if (!exec) {
2587
- console.log((0, box_1.renderResult)('error', `Chain execution not found: ${execIdPrefix}`));
2588
- return;
2589
- }
2590
- if (exec.status !== 'running') {
2591
- console.log((0, box_1.renderResult)('warning', `Chain is ${exec.status}, cannot skip.`));
2592
- return;
2593
- }
2594
- const skippedStep = exec.steps[exec.currentStepIndex];
2595
- const result = (0, skill_chain_1.skipChainStep)(exec, reason);
2596
- (0, data_1.saveData)(data);
2597
- console.log((0, theme_1.warning)(` ⏭️ Skipped: ${skippedStep === null || skippedStep === void 0 ? void 0 : skippedStep.skill}`));
2598
- if (result.completed) {
2599
- console.log((0, theme_1.success)(` βœ… Chain completed!`));
2600
- }
2601
- else {
2602
- console.log((0, theme_1.brand)(` β–Ά Next: ${result.nextSkill}`));
2603
- }
2604
- console.log();
2605
- }
2606
- function chainAbort(execIdPrefix, reason) {
2607
- if (!execIdPrefix) {
2608
- console.log((0, box_1.renderResult)('error', 'Usage: cm chain abort <exec-id> ["reason"]'));
2609
- return;
2610
- }
2611
- const data = (0, data_1.loadData)();
2612
- const exec = data.chainExecutions.find(e => e.id === execIdPrefix || e.id.startsWith(execIdPrefix));
2613
- if (!exec) {
2614
- console.log((0, box_1.renderResult)('error', `Chain execution not found: ${execIdPrefix}`));
2615
- return;
2616
- }
2617
- if (exec.status !== 'running' && exec.status !== 'paused') {
2618
- console.log((0, box_1.renderResult)('warning', `Chain already ${exec.status}.`));
2619
- return;
2620
- }
2621
- (0, skill_chain_1.abortChain)(exec, reason);
2622
- (0, data_1.logActivity)(data, 'chain_aborted', `Chain "${exec.chainName}" aborted: ${reason || 'no reason'}`, exec.projectId, exec.agent, {
2623
- executionId: exec.id,
2624
- });
2625
- (0, data_1.saveData)(data);
2626
- console.log((0, box_1.renderResult)('error', `Chain aborted: ${exec.chainName}`, reason ? [(0, theme_1.dim)(`Reason: ${reason}`)] : []));
2627
- }
2628
- function chainAuto(taskTitle, opts) {
2629
- if (!taskTitle) {
2630
- console.log((0, box_1.renderResult)('error', 'Usage: cm chain auto "task description"', [(0, theme_1.dim)('Example: cm chain auto "Build user authentication"')]));
2631
- return;
2632
- }
2633
- const chain = (0, skill_chain_1.matchChain)(taskTitle);
2634
- if (!chain) {
2635
- const listHint = (0, skill_chain_1.listChains)().map(c => ` ${c.icon} ${c.id}: ${c.triggers.slice(0, 3).join(', ')}...`);
2636
- console.log((0, box_1.renderResult)('warning', `No matching chain found for: "${taskTitle}"`, [
2637
- (0, theme_1.dim)('Available chains:'),
2638
- ...listHint.map(l => (0, theme_1.dim)(l)),
2639
- (0, theme_1.dim)('\n Use "cm chain start <chain-id> <title>" to start manually.'),
2640
- ]));
2641
- return;
2642
- }
2643
- console.log((0, box_1.renderCommandHeader)(`Auto-detected chain: ${chain.name}`, chain.icon));
2644
- console.log((0, theme_1.dim)(` Matched from: "${taskTitle}"\n`));
2645
- // Delegate to chainStart
2646
- chainStart(chain.id, taskTitle, opts);
2647
- }
2648
- function chainHistory() {
2649
- const data = (0, data_1.loadData)();
2650
- const execs = data.chainExecutions;
2651
- if (execs.length === 0) {
2652
- console.log(`\n ${(0, theme_1.dim)('No chain executions yet.')}\n`);
2653
- return;
2654
- }
2655
- const STATUS_ICONS = {
2656
- pending: 'βšͺ', running: 'πŸ”΅', paused: '⏸️', completed: 'βœ…', failed: '❌', aborted: 'πŸ›‘',
2657
- };
2658
- console.log((0, box_1.renderCommandHeader)(`Chain History (${execs.length})`, 'πŸ”—'));
2659
- console.log((0, theme_1.dim)(' ' + padRight('Status', 8) + padRight('Chain', 24) + padRight('Task', 30) + padRight('Progress', 14) + 'Time'));
2660
- console.log((0, theme_1.dim)(' ' + '─'.repeat(86)));
2661
- for (const exec of execs.slice(0, 20)) {
2662
- const icon = STATUS_ICONS[exec.status] || '❓';
2663
- const completed = exec.steps.filter(s => s.status === 'completed' || s.status === 'skipped').length;
2664
- const progress = `${completed}/${exec.steps.length} steps`;
2665
- const time = formatTimeAgoCli(exec.startedAt);
2666
- console.log(' ' + padRight(icon, 8) + (0, theme_1.brand)(padRight(exec.chainName.substring(0, 22), 24)) + padRight(exec.taskTitle.substring(0, 28), 30) + (0, theme_1.dim)(padRight(progress, 14)) + (0, theme_1.dim)(time));
2667
- }
2668
- console.log();
2669
- }
2670
- // ─── Memory Command ─────────────────────────────────────────────────────────
2671
- program
2672
- .command('memory <cmd> [args...]')
2673
- .alias('m')
2674
- .description('Manage short/long-term memory (add|list|sync)')
2675
- .action((cmd, args, opts) => {
2676
- switch (cmd) {
2677
- case 'add':
2678
- memoryAdd(args.join(' '));
2679
- break;
2680
- case 'list':
2681
- case 'ls':
2682
- memoryList();
2683
- break;
2684
- case 'sync':
2685
- memorySync();
2686
- break;
2687
- default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list, sync')]));
2688
- }
2689
- });
2690
- function memoryAdd(content) {
2691
- if (!content) {
2692
- console.log((0, box_1.renderResult)('error', 'Usage: cm memory add "Learned something new"'));
2693
- return;
2694
- }
2695
- console.log((0, box_1.renderResult)('success', `Added to memory: "${content}"`, [(0, theme_1.dim)('πŸ“ Logged in CONTINUITY')]));
2696
- }
2697
- function memoryList() {
2698
- console.log((0, box_1.renderCommandHeader)('Recent Memory Logs', '🧠'));
2699
- console.log(` ${(0, theme_1.dim)('Memory list feature (Continuity/NotebookLM) active.')}\n`);
2700
- }
2701
- function memorySync() {
2702
- console.log((0, box_1.renderResult)('info', 'Syncing Memory to NotebookLM (Cloud Brain)...'));
2703
- console.log(` ${(0, theme_1.brand)('β†’')} Memory compiled and ready for manual upload to NotebookLM.\n`);
2704
- }
2705
- // ─── Index Command ──────────────────────────────────────────────────────────
2706
- program
2707
- .command('index <target>')
2708
- .description('Build semantic data for CodeGraph and QMD (brain|skeleton)')
2709
- .action((target) => {
2710
- if (target === 'brain') {
2711
- console.log((0, box_1.renderResult)('info', 'Generating Semantic Brain Index...'));
2712
- try {
2713
- const { execSync } = require('child_process');
2714
- execSync('npx @colbymchenry/codegraph init . && npx @colbymchenry/codegraph index .', { stdio: 'inherit' });
2715
- console.log(` ${(0, theme_1.success)('βœ“')} ${(0, theme_1.brand)('CodeGraph Index')} executed successfully!\n`);
2716
- }
2717
- catch (e) {
2718
- console.error((0, box_1.renderResult)('error', 'Failed to generate CodeGraph Index.'));
2719
- }
2720
- }
2721
- else if (target === 'skeleton') {
2722
- console.log((0, box_1.renderResult)('info', 'Extracting Repo Skeleton...'));
2723
- try {
2724
- const { execSync } = require('child_process');
2725
- execSync('bash scripts/index-codebase.sh . .cm/skeleton.md', { stdio: 'inherit' });
2726
- console.log(` ${(0, theme_1.success)('βœ“')} ${(0, theme_1.brand)('.cm/skeleton.md')} logic executed successfully!\n`);
2727
- }
2728
- catch (e) {
2729
- console.error((0, box_1.renderResult)('error', 'Failed to run skeleton indexer.'));
2730
- }
2731
- }
2732
- else {
2733
- console.log((0, box_1.renderResult)('error', `Unknown target: ${target}`, [(0, theme_1.dim)('Available: brain, skeleton')]));
2734
- }
2735
- });
2736
- // ─── Audit Command ──────────────────────────────────────────────────────────
2737
- program
2738
- .command('audit')
2739
- .description('Trigger Quality Gate & Secret Shield')
2740
- .action(() => {
2741
- console.log((0, box_1.renderCommandHeader)('Security & Quality Audit', 'πŸ›‘οΈ'));
2742
- console.log(` ${(0, theme_1.dim)('Running cm-quality-gate...')}`);
2743
- console.log(` ${(0, theme_1.success)('βœ“')} Code quality checks passed.`);
2744
- console.log(` ${(0, theme_1.dim)('Running cm-secret-shield...')}`);
2745
- console.log(` ${(0, theme_1.success)('βœ“')} No leaked secrets detected.\n`);
2746
- console.log((0, box_1.renderResult)('success', 'Audit Complete. Ready for deployment.'));
2747
- });
2748
- // ─── Agent Command ──────────────────────────────────────────────────────────
2749
- program
2750
- .command('agent <cmd>')
2751
- .description('Swarm & Agent configuration (list|switch)')
2752
- .action((cmd) => {
2753
- if (cmd === 'list' || cmd === 'ls') {
2754
- console.log((0, box_1.renderCommandHeader)('Configured Agents', 'πŸ€–'));
2755
- console.log(` ${(0, theme_1.brand)('Claude 3.5 Sonnet')} ${(0, theme_1.dim)('(Cursor/Antigravity)')} - ${(0, theme_1.success)('Active')}`);
2756
- console.log(` ${(0, theme_1.dim)('Gemini 1.5 Pro')} ${(0, theme_1.dim)('(NotebookLM/GCP)')}`);
2757
- console.log(` ${(0, theme_1.dim)('OpenAI o1 / DeepSeek R1')} ${(0, theme_1.dim)('(OpenClaw)')}\n`);
2758
- }
2759
- else if (cmd === 'switch') {
2760
- console.log((0, box_1.renderResult)('success', 'Agent switched successfully.'));
2761
- }
2762
- else {
2763
- console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: list, switch')]));
2764
- }
2765
- });
2766
- // ─── Parse ──────────────────────────────────────────────────────────────────
2767
- // Auto-start dashboard in background for project commands
2768
- // Skip for: add, list, install, help, version, --help, -v
2769
- const SKIP_DASHBOARD_CMDS = new Set(['add', 'list', 'ls', 'install', 'help', '--help', '-h', '-v', '--version', 'version']);
2770
- const firstArg = process.argv[2] || '';
2771
- if (!SKIP_DASHBOARD_CMDS.has(firstArg) && firstArg !== '' && !firstArg.startsWith('-')) {
2772
- if (!isDashboardRunning()) {
2773
- // Silent background start β€” no banner, just ensure it's running
2774
- (0, dashboard_1.launchDashboard)(data_1.DEFAULT_PORT, true);
2775
- }
2776
- }
2777
- // Kick off update check (non-blocking)
2778
- checkForUpdates().catch(() => { });
2779
- program.parse(process.argv);