codymaster 4.6.0 β 5.2.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.
- package/CHANGELOG.md +74 -8
- package/README.md +192 -95
- package/dist/advisory-handoff.js +89 -0
- package/dist/advisory-report.js +105 -0
- package/dist/browse-server.js +251 -0
- package/dist/cli/command-registry.js +34 -0
- package/dist/cli/commands/agent.js +120 -0
- package/dist/cli/commands/bench.js +69 -0
- package/dist/cli/commands/brain.js +108 -0
- package/dist/cli/commands/dashboard.js +93 -0
- package/dist/cli/commands/design-studio.js +111 -0
- package/dist/cli/commands/distro.js +25 -0
- package/dist/cli/commands/engineering.js +596 -0
- package/dist/cli/commands/evolve.js +123 -0
- package/dist/cli/commands/mcp-serve.js +104 -0
- package/dist/cli/commands/project.js +324 -0
- package/dist/cli/commands/skill-chain.js +269 -0
- package/dist/cli/commands/system.js +89 -0
- package/dist/cli/commands/task.js +254 -0
- package/dist/cli/update-check.js +83 -0
- package/dist/cm-config.js +92 -0
- package/dist/cm-suggest.js +77 -0
- package/dist/codybench/judges/automated.js +31 -0
- package/dist/codybench/runners/claude-code.js +32 -0
- package/dist/codybench/suites/memory-retention.js +85 -0
- package/dist/codybench/suites/tdd-regression.js +35 -0
- package/dist/codybench/suites/token-efficiency.js +55 -0
- package/dist/codybench/types.js +2 -0
- package/dist/context-db.js +157 -0
- package/dist/continuity.js +2 -6
- package/dist/distro-validate.js +54 -0
- package/dist/execution-analyzer.js +138 -0
- package/dist/guardian-core.js +74 -0
- package/dist/index.js +36 -2759
- package/dist/indexer/skills-lib.js +533 -0
- package/dist/indexer/skills-map.js +1374 -0
- package/dist/indexer/skills.js +16 -0
- package/dist/learning-promoter.js +246 -0
- package/dist/mcp-context-server.js +289 -1
- package/dist/mcp-skills-tools.js +81 -0
- package/dist/retro-summary.js +70 -0
- package/dist/second-opinion-providers.js +79 -0
- package/dist/skill-chain.js +63 -1
- package/dist/skill-evolver.js +456 -0
- package/dist/skill-execution-cache.js +254 -0
- package/dist/smart-brain-router.js +184 -0
- package/dist/sprint-pipeline.js +228 -0
- package/dist/storage-backend.js +14 -67
- package/dist/token-budget.js +88 -0
- package/dist/utils/cli-utils.js +76 -0
- package/dist/utils/skill-utils.js +32 -0
- package/package.json +17 -7
- package/scripts/build-skills.mjs +51 -0
- package/scripts/gate-0-repo-hygiene.js +75 -0
- package/scripts/postinstall.js +34 -28
- package/scripts/security-scan.js +1 -1
- package/scripts/validate-skills.mjs +42 -0
- package/skills/CLAUDE.md +2 -7
- package/skills/_shared/helpers.md +2 -8
- package/skills/cm-ads-tracker/SKILL.md +3 -6
- package/skills/cm-browse/SKILL.md +34 -0
- package/skills/cm-conductor-worktrees/SKILL.md +28 -0
- package/skills/cm-content-factory/SKILL.md +1 -1
- package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
- package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
- package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
- package/skills/cm-content-factory/landing/docs/content/memory-system.md +38 -0
- package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
- package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
- package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
- package/skills/cm-content-factory/landing/docs/index.html +240 -0
- package/skills/cm-content-factory/landing/index.html +100 -100
- package/skills/cm-content-factory/landing/script.js +42 -0
- package/skills/cm-content-factory/landing/translations.js +400 -400
- package/skills/cm-continuity/SKILL.md +32 -33
- package/skills/cm-design-studio/SKILL.md +34 -0
- package/skills/cm-ecosystem-roadmap/SKILL.md +15 -0
- package/skills/cm-engineering-meta/SKILL.md +73 -0
- package/skills/cm-growth-hacking/SKILL.md +1 -12
- package/skills/cm-guardian-runtime/SKILL.md +26 -0
- package/skills/cm-mcp-engineering/SKILL.md +22 -0
- package/skills/cm-notebooklm/SKILL.md +1 -17
- package/skills/cm-post-deploy-canary/SKILL.md +22 -0
- package/skills/cm-project-bootstrap/SKILL.md +11 -0
- package/skills/cm-qa-visual-cli/SKILL.md +22 -0
- package/skills/cm-retro-cli/SKILL.md +23 -0
- package/skills/cm-second-opinion-cli/SKILL.md +23 -0
- package/skills/cm-secret-shield/SKILL.md +2 -2
- package/skills/cm-security-gate/SKILL.md +1 -0
- package/skills/cm-skill-chain/SKILL.md +25 -4
- package/skills/cm-skill-evolution/SKILL.md +83 -0
- package/skills/cm-skill-health/SKILL.md +83 -0
- package/skills/cm-skill-index/SKILL.md +11 -3
- package/skills/cm-skill-search/SKILL.md +49 -0
- package/skills/cm-skill-share/SKILL.md +58 -0
- package/skills/cm-sprint-bus/SKILL.md +33 -0
- package/skills/cm-start/SKILL.md +0 -10
- package/skills/cm-tdd/SKILL.md +59 -72
- package/skills/profiles/README.md +21 -0
- package/skills/profiles/core.txt +23 -0
- package/skills/profiles/design.txt +6 -0
- package/skills/profiles/full.txt +62 -0
- package/skills/profiles/growth.txt +10 -0
- package/skills/profiles/knowledge.txt +7 -0
- package/install.sh +0 -901
- package/scripts/test-gemini.js +0 -13
- package/skills/cm-frappe-agent/SKILL.md +0 -134
- package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
- package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
- package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
- package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
- package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
- package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
- package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
- package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
- package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
- package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
- package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
- package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
- package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
- package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
- package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
- package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
- package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
- package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
- package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
- package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
- package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
- package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
- package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
- package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
- package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
- package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
- package/skills/cm-frappe-agent/docs/README.md +0 -51
- package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
- package/skills/cm-frappe-agent/docs/architecture.md +0 -149
- package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
- package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
- package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
- package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
- package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
- package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
- package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
- package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
- package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
- package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
- package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
- package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
- package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
- package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
- package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
- package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
- package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
- package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
- package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
- package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
- package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
- package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
- package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
- 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
|
|
66
|
-
const
|
|
67
|
-
//
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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);
|