codymaster 4.6.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +80 -30
  3. package/dist/browse-server.js +251 -0
  4. package/dist/cli/command-registry.js +26 -0
  5. package/dist/cli/commands/agent.js +120 -0
  6. package/dist/cli/commands/dashboard.js +93 -0
  7. package/dist/cli/commands/design-studio.js +111 -0
  8. package/dist/cli/commands/distro.js +25 -0
  9. package/dist/cli/commands/engineering.js +488 -0
  10. package/dist/cli/commands/project.js +324 -0
  11. package/dist/cli/commands/skill-chain.js +269 -0
  12. package/dist/cli/commands/system.js +89 -0
  13. package/dist/cli/commands/task.js +254 -0
  14. package/dist/cli/update-check.js +83 -0
  15. package/dist/cm-config.js +110 -0
  16. package/dist/cm-suggest.js +77 -0
  17. package/dist/distro-validate.js +54 -0
  18. package/dist/guardian-core.js +74 -0
  19. package/dist/index.js +36 -2759
  20. package/dist/mcp-context-server.js +60 -1
  21. package/dist/mcp-skills-tools.js +81 -0
  22. package/dist/retro-summary.js +70 -0
  23. package/dist/second-opinion-providers.js +79 -0
  24. package/dist/sprint-pipeline.js +228 -0
  25. package/dist/storage-backend.js +5 -60
  26. package/dist/utils/cli-utils.js +76 -0
  27. package/dist/utils/skill-utils.js +32 -0
  28. package/install.sh +274 -50
  29. package/package.json +16 -5
  30. package/scripts/build-skills.mjs +51 -0
  31. package/scripts/gate-0-repo-hygiene.js +75 -0
  32. package/scripts/postinstall.js +55 -0
  33. package/scripts/security-scan.js +1 -1
  34. package/scripts/validate-skills.mjs +42 -0
  35. package/scripts/viking-demo.ts +105 -0
  36. package/skills/CLAUDE.md +2 -2
  37. package/skills/cm-ads-tracker/SKILL.md +3 -6
  38. package/skills/cm-browse/SKILL.md +28 -0
  39. package/skills/cm-conductor-worktrees/SKILL.md +24 -0
  40. package/skills/cm-content-factory/SKILL.md +1 -1
  41. package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
  42. package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
  43. package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
  44. package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
  45. package/skills/cm-content-factory/landing/docs/content/openviking.md +33 -0
  46. package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
  47. package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
  48. package/skills/cm-content-factory/landing/docs/index.html +240 -0
  49. package/skills/cm-content-factory/landing/index.html +99 -99
  50. package/skills/cm-content-factory/landing/script.js +42 -0
  51. package/skills/cm-content-factory/landing/translations.js +400 -400
  52. package/skills/cm-design-studio/SKILL.md +30 -0
  53. package/skills/cm-ecosystem-roadmap/SKILL.md +11 -0
  54. package/skills/cm-engineering-meta/SKILL.md +69 -0
  55. package/skills/cm-growth-hacking/SKILL.md +1 -12
  56. package/skills/cm-guardian-runtime/SKILL.md +22 -0
  57. package/skills/cm-mcp-engineering/SKILL.md +18 -0
  58. package/skills/cm-notebooklm/SKILL.md +1 -17
  59. package/skills/cm-post-deploy-canary/SKILL.md +18 -0
  60. package/skills/cm-qa-visual-cli/SKILL.md +18 -0
  61. package/skills/cm-retro-cli/SKILL.md +19 -0
  62. package/skills/cm-second-opinion-cli/SKILL.md +19 -0
  63. package/skills/cm-secret-shield/SKILL.md +2 -2
  64. package/skills/cm-sprint-bus/SKILL.md +29 -0
  65. package/skills/cm-tdd/SKILL.md +61 -74
  66. package/skills/profiles/README.md +21 -0
  67. package/skills/profiles/core.txt +23 -0
  68. package/skills/profiles/design.txt +6 -0
  69. package/skills/profiles/full.txt +58 -0
  70. package/skills/profiles/growth.txt +10 -0
  71. package/skills/profiles/knowledge.txt +7 -0
  72. package/scripts/test-gemini.js +0 -13
  73. package/skills/cm-frappe-agent/SKILL.md +0 -134
  74. package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
  75. package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
  76. package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
  77. package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
  78. package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
  79. package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
  80. package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
  81. package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
  82. package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
  83. package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
  84. package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
  85. package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
  86. package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
  87. package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
  88. package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
  89. package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
  90. package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
  91. package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
  92. package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
  93. package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
  94. package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
  95. package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
  96. package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
  97. package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
  98. package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
  99. package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
  100. package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
  101. package/skills/cm-frappe-agent/docs/README.md +0 -51
  102. package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
  103. package/skills/cm-frappe-agent/docs/architecture.md +0 -149
  104. package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
  105. package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
  106. package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
  107. package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
  108. package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
  109. package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
  110. package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
  111. package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
  112. package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
  113. package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
  114. package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
  115. package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
  116. package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
  117. package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
  118. package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
  119. package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
  120. package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
  121. package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
  122. package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
  123. package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
  124. package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
  125. package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
  126. package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
  127. package/skills/frappe-app-builder.zip +0 -0
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerSystemCommands = registerSystemCommands;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const data_1 = require("../../data");
12
+ const theme_1 = require("../../ui/theme");
13
+ const box_1 = require("../../ui/box");
14
+ const hamster_1 = require("../../ui/hamster");
15
+ const skill_utils_1 = require("../../utils/skill-utils");
16
+ const cli_utils_1 = require("../../utils/cli-utils");
17
+ const pkg = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', '..', '..', 'package.json'), 'utf-8'));
18
+ const VERSION = pkg.version;
19
+ function registerSystemCommands(program) {
20
+ // ─── Status Command ────────────────────────────────────────────────────────
21
+ program
22
+ .command('status')
23
+ .alias('s')
24
+ .description('Show task & project summary')
25
+ .action(() => {
26
+ const data = (0, data_1.loadData)();
27
+ showBanner();
28
+ console.log((0, box_1.renderCommandHeader)('Status Overview', '📊'));
29
+ // Projects
30
+ console.log((0, theme_1.brand)(` Projects: ${data.projects.length}`));
31
+ for (const p of data.projects) {
32
+ const pt = data.tasks.filter(t => t.projectId === p.id);
33
+ const done = pt.filter(t => t.column === 'done').length;
34
+ const pct = pt.length > 0 ? Math.round((done / pt.length) * 100) : 0;
35
+ console.log((0, theme_1.dim)(` 📦 ${(0, cli_utils_1.padRight)(p.name, 20)} ${(0, cli_utils_1.progressBar)(pct)} ${done}/${pt.length} (${pct}%)`));
36
+ }
37
+ // Tasks
38
+ const total = data.tasks.length;
39
+ const byCol = { backlog: 0, 'in-progress': 0, review: 0, done: 0 };
40
+ data.tasks.forEach(t => { byCol[t.column] = (byCol[t.column] || 0) + 1; });
41
+ console.log();
42
+ console.log((0, theme_1.brand)(` Tasks: ${total}`));
43
+ console.log((0, theme_1.dim)(` ⚪ Backlog: ${byCol.backlog}`));
44
+ console.log((0, theme_1.info)(` 🟢 In Progress: ${byCol['in-progress']}`));
45
+ console.log((0, theme_1.warning)(` 🟡 Review: ${byCol.review}`));
46
+ console.log((0, theme_1.success)(` 🟢 Done: ${byCol.done}`));
47
+ // Deploys
48
+ if (data.deployments.length > 0) {
49
+ console.log();
50
+ console.log((0, theme_1.brand)(` Deployments: ${data.deployments.length}`));
51
+ const latest = data.deployments[0];
52
+ const sc = theme_1.STATUS[latest.status] || chalk_1.default.white;
53
+ console.log((0, theme_1.dim)(` Latest: ${latest.env} — ${sc(latest.status)} — ${latest.message} (${(0, cli_utils_1.formatTimeAgoCli)(latest.startedAt)})`));
54
+ }
55
+ console.log();
56
+ });
57
+ // ─── Config Command ────────────────────────────────────────────────────────
58
+ program
59
+ .command('config [key] [value]')
60
+ .description('Get or set configuration')
61
+ .action((key, value) => {
62
+ if (!key) {
63
+ console.log((0, box_1.renderCommandHeader)('Configuration', '⚙️'));
64
+ console.log((0, theme_1.dim)(' Run cm config <key> <value> to set a value.\n'));
65
+ return;
66
+ }
67
+ if (value) {
68
+ console.log((0, box_1.renderResult)('success', `Config set: ${key} = ${value}`));
69
+ }
70
+ else {
71
+ console.log((0, box_1.renderResult)('info', `Config: ${key} = (not set)`));
72
+ }
73
+ });
74
+ // ─── Open Command ───────────────────────────────────────────────────────────
75
+ program
76
+ .command('open')
77
+ .description('Open dashboard in browser')
78
+ .action(() => {
79
+ const url = `http://localhost:${data_1.DEFAULT_PORT}`;
80
+ console.log((0, box_1.renderResult)('info', `Opening ${url}...`));
81
+ (0, cli_utils_1.openUrl)(url);
82
+ });
83
+ }
84
+ function showBanner() {
85
+ const cPath = process.cwd().replace(os_1.default.homedir(), '~');
86
+ const skillCount = (0, skill_utils_1.getSkillCount)();
87
+ // Using a default/mocked profile for now (profile logic is being refactored)
88
+ console.log((0, hamster_1.renderHamsterBanner)(undefined, VERSION, cPath, skillCount));
89
+ }
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.registerTaskCommands = registerTaskCommands;
16
+ const crypto_1 = __importDefault(require("crypto"));
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const data_1 = require("../../data");
19
+ const agent_dispatch_1 = require("../../agent-dispatch");
20
+ const theme_1 = require("../../ui/theme");
21
+ const box_1 = require("../../ui/box");
22
+ const cli_utils_1 = require("../../utils/cli-utils");
23
+ const COL_COLORS = theme_1.COL;
24
+ const PRIORITY_COLORS = theme_1.PRI;
25
+ function registerTaskCommands(program) {
26
+ program
27
+ .command('task <cmd> [args...]')
28
+ .alias('t')
29
+ .description('Task management (add|list|move|done|rm|dispatch|stuck)')
30
+ .option('-p, --project <name>', 'Project name or ID')
31
+ .option('-c, --column <column>', 'Column (backlog|in-progress|review|done)', 'backlog')
32
+ .option('--priority <level>', 'Priority (low|medium|high|urgent)', 'medium')
33
+ .option('--agent <agent>', 'Agent name')
34
+ .option('--skill <skill>', 'Skill name')
35
+ .option('--all', 'Show all projects')
36
+ .option('--force', 'Force re-dispatch')
37
+ .action((cmd, args, opts) => {
38
+ switch (cmd) {
39
+ case 'add':
40
+ taskAdd(args.join(' '), opts);
41
+ break;
42
+ case 'list':
43
+ case 'ls':
44
+ taskList(opts);
45
+ break;
46
+ case 'move':
47
+ taskMove(args[0], args[1]);
48
+ break;
49
+ case 'done':
50
+ taskDone(args[0]);
51
+ break;
52
+ case 'rm':
53
+ case 'delete':
54
+ taskRemove(args[0]);
55
+ break;
56
+ case 'dispatch':
57
+ taskDispatch(args[0], opts);
58
+ break;
59
+ case 'stuck':
60
+ taskStuck(opts);
61
+ break;
62
+ default: console.log((0, box_1.renderResult)('error', `Unknown: ${cmd}`, [(0, theme_1.dim)('Available: add, list, move, done, rm, dispatch, stuck')]));
63
+ }
64
+ });
65
+ }
66
+ function taskAdd(title, opts) {
67
+ if (!title) {
68
+ console.log((0, box_1.renderResult)('error', 'Title required. Usage: cm task add "My task"'));
69
+ return;
70
+ }
71
+ const data = (0, data_1.loadData)();
72
+ let projectId;
73
+ if (opts.project) {
74
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
75
+ if (!project) {
76
+ console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
77
+ return;
78
+ }
79
+ projectId = project.id;
80
+ }
81
+ else if (data.projects.length > 0) {
82
+ projectId = data.projects[0].id;
83
+ }
84
+ else {
85
+ const dp = {
86
+ id: crypto_1.default.randomUUID(),
87
+ name: 'Default Project',
88
+ path: process.cwd(),
89
+ agents: [],
90
+ createdAt: new Date().toISOString()
91
+ };
92
+ data.projects.push(dp);
93
+ projectId = dp.id;
94
+ }
95
+ const now = new Date().toISOString();
96
+ const column = (opts.column || 'backlog');
97
+ const ct = data.tasks.filter((t) => t.column === column && t.projectId === projectId);
98
+ const mo = ct.length > 0 ? Math.max(...ct.map((t) => t.order)) : -1;
99
+ const task = {
100
+ id: crypto_1.default.randomUUID(),
101
+ projectId: projectId,
102
+ title: title.trim(),
103
+ description: '',
104
+ column,
105
+ order: mo + 1,
106
+ priority: (opts.priority || 'medium'),
107
+ agent: opts.agent || '',
108
+ skill: opts.skill || '',
109
+ createdAt: now,
110
+ updatedAt: now
111
+ };
112
+ data.tasks.push(task);
113
+ (0, data_1.logActivity)(data, 'task_created', `Task "${task.title}" created via CLI`, projectId, opts.agent || '');
114
+ (0, data_1.saveData)(data);
115
+ const project = data.projects.find((p) => p.id === projectId);
116
+ console.log((0, box_1.renderResult)('success', `Task created: ${title}`, [
117
+ `${(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')}`,
118
+ ]));
119
+ }
120
+ function taskList(opts) {
121
+ const data = (0, data_1.loadData)();
122
+ let tasks = data.tasks;
123
+ if (opts.project && !opts.all) {
124
+ const project = (0, data_1.findProjectByNameOrId)(data, opts.project);
125
+ if (!project) {
126
+ console.log((0, box_1.renderResult)('error', `Project not found: ${opts.project}`));
127
+ return;
128
+ }
129
+ tasks = tasks.filter((t) => t.projectId === project.id);
130
+ console.log((0, box_1.renderCommandHeader)(`Tasks — ${project.name}`, '📋'));
131
+ }
132
+ else {
133
+ console.log((0, box_1.renderCommandHeader)('All Tasks', '📋'));
134
+ }
135
+ if (tasks.length === 0) {
136
+ console.log(` ${(0, theme_1.dim)('No tasks found.')}\n`);
137
+ return;
138
+ }
139
+ console.log((0, theme_1.dim)(' ' + (0, cli_utils_1.padRight)('ID', 10) + (0, cli_utils_1.padRight)('Title', 36) + (0, cli_utils_1.padRight)('Column', 14) + (0, cli_utils_1.padRight)('Priority', 10) + (0, cli_utils_1.padRight)('Agent', 14) + 'Project'));
140
+ console.log((0, theme_1.dim)(' ' + '─'.repeat(100)));
141
+ const co = ['backlog', 'in-progress', 'review', 'done'];
142
+ tasks.sort((a, b) => co.indexOf(a.column) - co.indexOf(b.column) || a.order - b.order);
143
+ for (const task of tasks) {
144
+ const cc = COL_COLORS[task.column] || chalk_1.default.white;
145
+ const pc = PRIORITY_COLORS[task.priority] || chalk_1.default.white;
146
+ const project = data.projects.find((p) => p.id === task.projectId);
147
+ console.log(' ' + (0, theme_1.dim)((0, cli_utils_1.padRight)((0, data_1.shortId)(task.id), 10)) + (0, cli_utils_1.padRight)(task.title.substring(0, 34), 36) + cc((0, cli_utils_1.padRight)(task.column, 14)) + pc((0, cli_utils_1.padRight)(task.priority, 10)) + (0, theme_1.dim)((0, cli_utils_1.padRight)(task.agent || '—', 14)) + (0, theme_1.dim)((project === null || project === void 0 ? void 0 : project.name) || '—'));
148
+ }
149
+ console.log((0, theme_1.dim)(`\n Total: ${tasks.length} tasks\n`));
150
+ }
151
+ function taskMove(idPrefix, targetColumn) {
152
+ if (!idPrefix || !targetColumn) {
153
+ console.log((0, box_1.renderResult)('error', 'Usage: cm task move <id> <column>'));
154
+ return;
155
+ }
156
+ const vc = ['backlog', 'in-progress', 'review', 'done'];
157
+ if (!vc.includes(targetColumn)) {
158
+ console.log((0, box_1.renderResult)('error', `Invalid column: ${targetColumn}`, [(0, theme_1.dim)(`Valid: ${vc.join(', ')}`)]));
159
+ return;
160
+ }
161
+ const data = (0, data_1.loadData)();
162
+ const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
163
+ if (!task) {
164
+ console.log((0, box_1.renderResult)('error', `Task not found: ${idPrefix}`));
165
+ return;
166
+ }
167
+ const oldCol = task.column;
168
+ // Validate transition
169
+ const VALID_TRANSITIONS = {
170
+ 'backlog': ['in-progress'],
171
+ 'in-progress': ['review', 'done', 'backlog'],
172
+ 'review': ['done', 'in-progress'],
173
+ 'done': ['backlog'],
174
+ };
175
+ const allowed = VALID_TRANSITIONS[oldCol] || [];
176
+ if (oldCol !== targetColumn && !allowed.includes(targetColumn)) {
177
+ console.log((0, box_1.renderResult)('error', `Invalid transition: ${oldCol} → ${targetColumn}`, [(0, theme_1.dim)(`Allowed: ${allowed.join(', ')}`)]));
178
+ return;
179
+ }
180
+ if (oldCol === targetColumn) {
181
+ console.log(` ${(0, theme_1.dim)(`Task already in ${targetColumn}.`)}`);
182
+ return;
183
+ }
184
+ task.column = targetColumn;
185
+ task.updatedAt = new Date().toISOString();
186
+ (0, data_1.saveData)(data);
187
+ (0, data_1.logActivity)(data, 'task_moved', `Task "${task.title}" moved ${oldCol} → ${targetColumn}`, task.projectId);
188
+ console.log((0, box_1.renderResult)('success', `Task moved: ${(0, data_1.shortId)(task.id)}`, [`${(0, theme_1.dim)('New column:')} ${(0, theme_1.brand)(targetColumn)}`]));
189
+ }
190
+ function taskDone(idPrefix) {
191
+ taskMove(idPrefix, 'done');
192
+ }
193
+ function taskRemove(idPrefix) {
194
+ if (!idPrefix) {
195
+ console.log((0, box_1.renderResult)('error', 'Usage: cm task rm <id>'));
196
+ return;
197
+ }
198
+ const data = (0, data_1.loadData)();
199
+ const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
200
+ if (!task) {
201
+ console.log((0, box_1.renderResult)('error', `Task not found: ${idPrefix}`));
202
+ return;
203
+ }
204
+ data.tasks = data.tasks.filter((t) => t.id !== task.id);
205
+ (0, data_1.logActivity)(data, 'task_deleted', `Task "${task.title}" deleted`, task.projectId);
206
+ (0, data_1.saveData)(data);
207
+ console.log((0, box_1.renderResult)('success', `Task deleted: ${task.title}`));
208
+ }
209
+ function taskDispatch(idPrefix, opts) {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ if (!idPrefix) {
212
+ console.log((0, box_1.renderResult)('error', 'Usage: cm task dispatch <id>'));
213
+ return;
214
+ }
215
+ const data = (0, data_1.loadData)();
216
+ const task = (0, data_1.findTaskByIdPrefix)(data, idPrefix);
217
+ if (!task) {
218
+ console.log((0, box_1.renderResult)('error', `Task not found: ${idPrefix}`));
219
+ return;
220
+ }
221
+ const project = data.projects.find((p) => p.id === task.projectId);
222
+ if (!project) {
223
+ console.log((0, box_1.renderResult)('error', `Project not found for task: ${task.id}`));
224
+ return;
225
+ }
226
+ console.log((0, box_1.renderResult)('info', `Dispatching task: ${task.title}...`));
227
+ const success = yield (0, agent_dispatch_1.dispatchTaskToAgent)(task, project, opts.force);
228
+ if (success) {
229
+ task.column = 'in-progress';
230
+ task.updatedAt = new Date().toISOString();
231
+ (0, data_1.saveData)(data);
232
+ }
233
+ });
234
+ }
235
+ function taskStuck(opts) {
236
+ const data = (0, data_1.loadData)();
237
+ const now = new Date().getTime();
238
+ const STUCK_THRESHOLD = 30 * 60 * 1000; // 30 mins
239
+ const stuckTasks = data.tasks.filter((t) => {
240
+ if (t.column !== 'in-progress')
241
+ return false;
242
+ const lastUpdate = new Date(t.updatedAt).getTime();
243
+ return (now - lastUpdate) > STUCK_THRESHOLD;
244
+ });
245
+ if (stuckTasks.length === 0) {
246
+ console.log((0, box_1.renderResult)('success', 'No stuck tasks detected.'));
247
+ return;
248
+ }
249
+ console.log((0, box_1.renderCommandHeader)('Stuck Tasks Detected', '⚠️'));
250
+ for (const t of stuckTasks) {
251
+ const project = data.projects.find((p) => p.id === t.projectId);
252
+ console.log(` ${(0, theme_1.dim)((0, data_1.shortId)(t.id))} ${(0, cli_utils_1.padRight)(t.title, 40)} ${(0, theme_1.brand)((project === null || project === void 0 ? void 0 : project.name) || '—')} ${(0, theme_1.dim)('Stuck for ' + Math.round((now - new Date(t.updatedAt).getTime()) / 60000) + 'm')}`);
253
+ }
254
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports._updateMessage = void 0;
16
+ exports.checkForUpdates = checkForUpdates;
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const path_1 = __importDefault(require("path"));
19
+ const os_1 = __importDefault(require("os"));
20
+ const https_1 = __importDefault(require("https"));
21
+ const pkg = JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(__dirname, '..', '..', 'package.json'), 'utf-8'));
22
+ const VERSION = pkg.version;
23
+ exports._updateMessage = '';
24
+ /**
25
+ * Checks for updates to CodyMaster on the npm registry.
26
+ * Caches results for 24 hours to avoid frequent network calls.
27
+ */
28
+ function checkForUpdates() {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ try {
31
+ const cacheDir = path_1.default.join(os_1.default.homedir(), '.codymaster');
32
+ const cacheFile = path_1.default.join(cacheDir, '.update-check');
33
+ // Ensure cache directory exists
34
+ if (!fs_1.default.existsSync(cacheDir)) {
35
+ fs_1.default.mkdirSync(cacheDir, { recursive: true });
36
+ }
37
+ // Check cache (24h TTL)
38
+ try {
39
+ if (fs_1.default.existsSync(cacheFile)) {
40
+ const stat = fs_1.default.statSync(cacheFile);
41
+ const age = Date.now() - stat.mtimeMs;
42
+ if (age < 24 * 60 * 60 * 1000) {
43
+ const cached = fs_1.default.readFileSync(cacheFile, 'utf-8').trim();
44
+ if (cached && cached !== VERSION) {
45
+ exports._updateMessage = cached;
46
+ }
47
+ return;
48
+ }
49
+ }
50
+ }
51
+ catch ( /* ignore cache errors */_a) { /* ignore cache errors */ }
52
+ // Fetch latest version from npm (2s timeout)
53
+ const latestVersion = yield new Promise((resolve, reject) => {
54
+ const timer = setTimeout(() => reject(new Error('timeout')), 2000);
55
+ https_1.default.get('https://registry.npmjs.org/codymaster/latest', { headers: { 'Accept': 'application/json' } }, (res) => {
56
+ let data = '';
57
+ res.on('data', (chunk) => { data += chunk; });
58
+ res.on('end', () => {
59
+ clearTimeout(timer);
60
+ try {
61
+ const json = JSON.parse(data);
62
+ resolve(json.version || VERSION);
63
+ }
64
+ catch (_a) {
65
+ resolve(VERSION);
66
+ }
67
+ });
68
+ }).on('error', () => { clearTimeout(timer); reject(new Error('fetch failed')); });
69
+ });
70
+ // Cache result
71
+ if (latestVersion && latestVersion !== VERSION) {
72
+ exports._updateMessage = latestVersion;
73
+ fs_1.default.writeFileSync(cacheFile, latestVersion);
74
+ }
75
+ else {
76
+ fs_1.default.writeFileSync(cacheFile, '');
77
+ }
78
+ }
79
+ catch (e) {
80
+ // Silent failure for update checks
81
+ }
82
+ });
83
+ }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ /**
3
+ * Shared loader for `.cm/config.yaml` — storage, browse daemon, guardian, canary.
4
+ * Uses the `yaml` package; unknown keys are ignored.
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.loadCmConfig = loadCmConfig;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const yaml_1 = require("yaml");
14
+ function asRecord(v) {
15
+ if (!v || typeof v !== 'object' || Array.isArray(v))
16
+ return null;
17
+ return v;
18
+ }
19
+ function str(v) {
20
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
21
+ }
22
+ /** Scalars only (e.g. storage.backend may be unquoted in YAML). */
23
+ function scalarStr(v) {
24
+ if (v === null || v === undefined)
25
+ return undefined;
26
+ if (typeof v === 'string')
27
+ return v.trim() || undefined;
28
+ if (typeof v === 'number' || typeof v === 'boolean')
29
+ return String(v);
30
+ return undefined;
31
+ }
32
+ function num(v) {
33
+ if (typeof v === 'number' && Number.isFinite(v))
34
+ return v;
35
+ if (typeof v === 'string' && v.trim() && !Number.isNaN(Number(v)))
36
+ return Number(v);
37
+ return undefined;
38
+ }
39
+ function strArray(v) {
40
+ if (Array.isArray(v)) {
41
+ const a = v.map((x) => String(x).trim()).filter(Boolean);
42
+ return a.length ? a : undefined;
43
+ }
44
+ if (typeof v === 'string') {
45
+ const a = v.split(',').map((s) => s.trim()).filter(Boolean);
46
+ return a.length ? a : undefined;
47
+ }
48
+ return undefined;
49
+ }
50
+ function loadCmConfig(projectPath) {
51
+ const configPath = path_1.default.join(projectPath, '.cm', 'config.yaml');
52
+ if (!fs_1.default.existsSync(configPath))
53
+ return {};
54
+ try {
55
+ const doc = (0, yaml_1.parseDocument)(fs_1.default.readFileSync(configPath, 'utf8'));
56
+ const root = doc.toJSON();
57
+ const o = asRecord(root);
58
+ if (!o)
59
+ return {};
60
+ const out = {};
61
+ const storageRaw = asRecord(o.storage);
62
+ if (storageRaw) {
63
+ out.storage = { backend: scalarStr(storageRaw.backend) };
64
+ const vikingRaw = asRecord(storageRaw.viking);
65
+ if (vikingRaw) {
66
+ const viking = {};
67
+ const h = str(vikingRaw.host);
68
+ const ws = str(vikingRaw.workspace);
69
+ const p = num(vikingRaw.port);
70
+ const t = num(vikingRaw.timeout);
71
+ if (h !== undefined)
72
+ viking.host = h;
73
+ if (ws !== undefined)
74
+ viking.workspace = ws;
75
+ if (p !== undefined)
76
+ viking.port = p;
77
+ if (t !== undefined)
78
+ viking.timeout = t;
79
+ if (Object.keys(viking).length)
80
+ out.storage.viking = viking;
81
+ }
82
+ }
83
+ const browseRaw = asRecord(o.browse);
84
+ if (browseRaw) {
85
+ out.browse = {
86
+ port: num(browseRaw.port),
87
+ host: str(browseRaw.host),
88
+ token: str(browseRaw.token),
89
+ };
90
+ }
91
+ const guardianRaw = asRecord(o.guardian);
92
+ if (guardianRaw) {
93
+ out.guardian = {
94
+ whitelist_prefixes: strArray(guardianRaw.whitelist_prefixes),
95
+ freeze_roots: strArray(guardianRaw.freeze_roots),
96
+ };
97
+ }
98
+ const canaryRaw = asRecord(o.canary);
99
+ if (canaryRaw) {
100
+ out.canary = {
101
+ browse_port: num(canaryRaw.browse_port),
102
+ token: str(canaryRaw.token),
103
+ };
104
+ }
105
+ return out;
106
+ }
107
+ catch (_a) {
108
+ return {};
109
+ }
110
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Proactive skill hints from git status + sprint state (`cm suggest`).
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.gitPorcelain = gitPorcelain;
10
+ exports.suggestFromContext = suggestFromContext;
11
+ const child_process_1 = require("child_process");
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const sprint_pipeline_1 = require("./sprint-pipeline");
15
+ function dedupe(s) {
16
+ const seen = new Set();
17
+ const out = [];
18
+ for (const x of s) {
19
+ const k = x.skill.toLowerCase();
20
+ if (seen.has(k))
21
+ continue;
22
+ seen.add(k);
23
+ out.push(x);
24
+ }
25
+ return out;
26
+ }
27
+ function gitPorcelain(projectPath) {
28
+ try {
29
+ return (0, child_process_1.execFileSync)('git', ['status', '--porcelain'], {
30
+ cwd: projectPath,
31
+ encoding: 'utf8',
32
+ maxBuffer: 2000000,
33
+ });
34
+ }
35
+ catch (_a) {
36
+ return '';
37
+ }
38
+ }
39
+ function suggestFromContext(projectPath) {
40
+ const root = path_1.default.resolve(projectPath);
41
+ const out = [];
42
+ const porcelain = gitPorcelain(root);
43
+ const lines = porcelain.split('\n').filter(Boolean);
44
+ const paths = lines.map((l) => l.slice(3).trim()).filter(Boolean);
45
+ const joined = paths.join('\n');
46
+ if (/\.test\.(ts|tsx|js|jsx)\b/m.test(joined)) {
47
+ out.push({ skill: 'cm-tdd', reason: 'Modified or untracked test files in git status.' });
48
+ }
49
+ if (/\.(md|mdx)\b/m.test(joined)) {
50
+ out.push({ skill: 'cm-dockit', reason: 'Markdown/docs paths changed.' });
51
+ }
52
+ if (/(package\.json|package-lock\.json|pnpm-lock|yarn\.lock)/m.test(joined)) {
53
+ out.push({ skill: 'cm-test-gate', reason: 'Dependency lockfiles changed; run the test gate.' });
54
+ }
55
+ if (/(\.github\/workflows\/|Dockerfile|fly\.toml|wrangler)/m.test(joined)) {
56
+ out.push({ skill: 'cm-safe-deploy', reason: 'CI or deploy config changed.' });
57
+ }
58
+ if (lines.length > 8) {
59
+ out.push({ skill: 'cm-git-worktrees', reason: 'Many working-tree changes; consider an isolated worktree.' });
60
+ }
61
+ const sprint = (0, sprint_pipeline_1.readSprintState)(root);
62
+ if (sprint && sprint.current_index >= 0 && sprint.current_index < sprint.pipeline.length) {
63
+ const step = sprint.pipeline[sprint.current_index];
64
+ const skill = (0, sprint_pipeline_1.skillMappingForStep)(step);
65
+ out.push({
66
+ skill,
67
+ reason: `Active sprint step: **${step}** (index ${sprint.current_index + 1}/${sprint.pipeline.length}).`,
68
+ });
69
+ }
70
+ if (fs_1.default.existsSync(path_1.default.join(root, '.cm', 'config.yaml'))) {
71
+ out.push({
72
+ skill: 'cm-engineering-meta',
73
+ reason: '`.cm/config.yaml` present; engineering commands honor shared config.',
74
+ });
75
+ }
76
+ return dedupe(out);
77
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Validate skill pack layout for future `cm install` / `cm distro` (ADR 003).
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.validateSkillPackDir = validateSkillPackDir;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const META_KEYS = ['name', 'description'];
13
+ function validateSkillPackDir(dir) {
14
+ const errors = [];
15
+ const warnings = [];
16
+ const abs = path_1.default.resolve(dir);
17
+ if (!fs_1.default.existsSync(abs) || !fs_1.default.statSync(abs).isDirectory()) {
18
+ return { ok: false, errors: [`Not a directory: ${abs}`], warnings: [] };
19
+ }
20
+ const skillMd = path_1.default.join(abs, 'SKILL.md');
21
+ const tmpl = path_1.default.join(abs, 'SKILL.md.tmpl');
22
+ const metaPath = path_1.default.join(abs, 'meta.json');
23
+ if (!fs_1.default.existsSync(skillMd) && !fs_1.default.existsSync(tmpl)) {
24
+ errors.push('Missing SKILL.md or SKILL.md.tmpl');
25
+ }
26
+ if (fs_1.default.existsSync(metaPath)) {
27
+ let raw;
28
+ try {
29
+ raw = JSON.parse(fs_1.default.readFileSync(metaPath, 'utf8'));
30
+ }
31
+ catch (_a) {
32
+ errors.push('meta.json is not valid JSON');
33
+ return { ok: errors.length === 0, errors, warnings };
34
+ }
35
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
36
+ errors.push('meta.json must be a JSON object');
37
+ }
38
+ else {
39
+ const o = raw;
40
+ for (const k of META_KEYS) {
41
+ if (typeof o[k] !== 'string' || !o[k].trim()) {
42
+ errors.push(`meta.json missing or invalid string field: ${k}`);
43
+ }
44
+ }
45
+ }
46
+ if (fs_1.default.existsSync(tmpl) && !fs_1.default.existsSync(skillMd)) {
47
+ warnings.push('SKILL.md.tmpl without generated SKILL.md — run npm run build:skills');
48
+ }
49
+ }
50
+ else if (fs_1.default.existsSync(tmpl)) {
51
+ warnings.push('SKILL.md.tmpl present but no meta.json (optional for local-only skills)');
52
+ }
53
+ return { ok: errors.length === 0, errors, warnings };
54
+ }