codymaster 4.5.4 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/README.md +86 -31
  3. package/dist/backends/viking-backend.js +235 -0
  4. package/dist/backends/viking-http-client.js +176 -0
  5. package/dist/browse-server.js +251 -0
  6. package/dist/cli/command-registry.js +26 -0
  7. package/dist/cli/commands/agent.js +120 -0
  8. package/dist/cli/commands/dashboard.js +93 -0
  9. package/dist/cli/commands/design-studio.js +111 -0
  10. package/dist/cli/commands/distro.js +25 -0
  11. package/dist/cli/commands/engineering.js +488 -0
  12. package/dist/cli/commands/project.js +324 -0
  13. package/dist/cli/commands/skill-chain.js +269 -0
  14. package/dist/cli/commands/system.js +89 -0
  15. package/dist/cli/commands/task.js +254 -0
  16. package/dist/cli/update-check.js +83 -0
  17. package/dist/cm-config.js +110 -0
  18. package/dist/cm-suggest.js +77 -0
  19. package/dist/continuity.js +8 -0
  20. package/dist/distro-validate.js +54 -0
  21. package/dist/guardian-core.js +74 -0
  22. package/dist/index.js +36 -2759
  23. package/dist/mcp-context-server.js +60 -1
  24. package/dist/mcp-skills-tools.js +81 -0
  25. package/dist/retro-summary.js +70 -0
  26. package/dist/second-opinion-providers.js +79 -0
  27. package/dist/sprint-pipeline.js +228 -0
  28. package/dist/storage-backend.js +63 -0
  29. package/dist/utils/cli-utils.js +76 -0
  30. package/dist/utils/skill-utils.js +32 -0
  31. package/install.sh +286 -58
  32. package/package.json +16 -5
  33. package/scripts/build-skills.mjs +51 -0
  34. package/scripts/gate-0-repo-hygiene.js +75 -0
  35. package/scripts/postinstall.js +56 -1
  36. package/scripts/security-scan.js +1 -1
  37. package/scripts/validate-skills.mjs +42 -0
  38. package/scripts/viking-demo.ts +105 -0
  39. package/skills/CLAUDE.md +2 -2
  40. package/skills/_shared/helpers.md +10 -0
  41. package/skills/cm-ads-tracker/SKILL.md +3 -6
  42. package/skills/cm-browse/SKILL.md +28 -0
  43. package/skills/cm-conductor-worktrees/SKILL.md +24 -0
  44. package/skills/cm-content-factory/SKILL.md +1 -1
  45. package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
  46. package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
  47. package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
  48. package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
  49. package/skills/cm-content-factory/landing/docs/content/openviking.md +33 -0
  50. package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
  51. package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
  52. package/skills/cm-content-factory/landing/docs/index.html +240 -0
  53. package/skills/cm-content-factory/landing/index.html +99 -99
  54. package/skills/cm-content-factory/landing/script.js +42 -0
  55. package/skills/cm-content-factory/landing/translations.js +400 -400
  56. package/skills/cm-continuity/SKILL.md +33 -6
  57. package/skills/cm-design-studio/SKILL.md +30 -0
  58. package/skills/cm-ecosystem-roadmap/SKILL.md +11 -0
  59. package/skills/cm-engineering-meta/SKILL.md +69 -0
  60. package/skills/cm-growth-hacking/SKILL.md +1 -12
  61. package/skills/cm-guardian-runtime/SKILL.md +22 -0
  62. package/skills/cm-mcp-engineering/SKILL.md +18 -0
  63. package/skills/cm-notebooklm/SKILL.md +1 -17
  64. package/skills/cm-post-deploy-canary/SKILL.md +18 -0
  65. package/skills/cm-qa-visual-cli/SKILL.md +18 -0
  66. package/skills/cm-retro-cli/SKILL.md +19 -0
  67. package/skills/cm-second-opinion-cli/SKILL.md +19 -0
  68. package/skills/cm-secret-shield/SKILL.md +2 -2
  69. package/skills/cm-sprint-bus/SKILL.md +29 -0
  70. package/skills/cm-start/SKILL.md +11 -2
  71. package/skills/cm-tdd/SKILL.md +61 -74
  72. package/skills/profiles/README.md +21 -0
  73. package/skills/profiles/core.txt +23 -0
  74. package/skills/profiles/design.txt +6 -0
  75. package/skills/profiles/full.txt +58 -0
  76. package/skills/profiles/growth.txt +10 -0
  77. package/skills/profiles/knowledge.txt +7 -0
  78. package/scripts/test-gemini.js +0 -13
  79. package/skills/cm-frappe-agent/SKILL.md +0 -134
  80. package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
  81. package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
  82. package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
  83. package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
  84. package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
  85. package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
  86. package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
  87. package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
  88. package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
  89. package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
  90. package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
  91. package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
  92. package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
  93. package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
  94. package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
  95. package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
  96. package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
  97. package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
  98. package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
  99. package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
  100. package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
  101. package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
  102. package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
  103. package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
  104. package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
  105. package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
  106. package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
  107. package/skills/cm-frappe-agent/docs/README.md +0 -51
  108. package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
  109. package/skills/cm-frappe-agent/docs/architecture.md +0 -149
  110. package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
  111. package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
  112. package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
  113. package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
  114. package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
  115. package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
  116. package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
  117. package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
  118. package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
  119. package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
  120. package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
  121. package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
  122. package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
  123. package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
  124. package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
  125. package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
  126. package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
  127. package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
  128. package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
  129. package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
  130. package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
  131. package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
  132. package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
  133. package/skills/frappe-app-builder.zip +0 -0
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * CodyMaster MCP Context Server
5
5
  *
6
- * Exposes 7 tools over JSON-RPC 2.0 / stdio (Content-Length framing):
6
+ * Exposes 13 tools over JSON-RPC 2.0 / stdio (Content-Length framing):
7
7
  * cm_query — FTS5 search across learnings + decisions
8
8
  * cm_resolve — resolve a cm:// URI at L0/L1/L2
9
9
  * cm_bus_read — read context bus state
@@ -11,6 +11,7 @@
11
11
  * cm_budget_check — check token budget for a category
12
12
  * cm_memory_decay — TTL cleanup for learnings
13
13
  * cm_index_refresh — regenerate L0 indexes
14
+ * cm_plan / cm_review / cm_qa / cm_deploy / cm_search / cm_memory_query — engineering kit bridge
14
15
  *
15
16
  * Usage (stdio MCP):
16
17
  * node dist/mcp-context-server.js --project /path/to/project
@@ -44,6 +45,7 @@ const uri_resolver_1 = require("./uri-resolver");
44
45
  const context_bus_1 = require("./context-bus");
45
46
  const token_budget_1 = require("./token-budget");
46
47
  const l0_indexer_1 = require("./l0-indexer");
48
+ const mcp_skills_tools_1 = require("./mcp-skills-tools");
47
49
  // ─── Config ──────────────────────────────────────────────────────────────────
48
50
  const SERVER_NAME = 'cm-context';
49
51
  const SERVER_VERSION = '1.0.0';
@@ -295,6 +297,51 @@ const TOOLS = [
295
297
  },
296
298
  },
297
299
  },
300
+ {
301
+ name: 'cm_plan',
302
+ description: 'Sprint + context bus snapshot: pipeline state, next skill hint, artifact paths.',
303
+ inputSchema: { type: 'object', properties: {} },
304
+ },
305
+ {
306
+ name: 'cm_review',
307
+ description: 'Read sprint review artifact preview if present; points to cm-code-review workflow.',
308
+ inputSchema: { type: 'object', properties: {} },
309
+ },
310
+ {
311
+ name: 'cm_qa',
312
+ description: 'QA hints: browse daemon, visual QA CLI, quality gates.',
313
+ inputSchema: { type: 'object', properties: {} },
314
+ },
315
+ {
316
+ name: 'cm_deploy',
317
+ description: 'Deploy workflow hints (cm-safe-deploy, canary).',
318
+ inputSchema: { type: 'object', properties: {} },
319
+ },
320
+ {
321
+ name: 'cm_search',
322
+ description: 'Search learnings + decisions (same backing store as cm_query).',
323
+ inputSchema: {
324
+ type: 'object',
325
+ properties: {
326
+ query: { type: 'string' },
327
+ scope: { type: 'string', enum: ['learnings', 'decisions', 'all'] },
328
+ limit: { type: 'number' },
329
+ },
330
+ required: ['query'],
331
+ },
332
+ },
333
+ {
334
+ name: 'cm_memory_query',
335
+ description: 'Alias-style memory search across learnings and decisions.',
336
+ inputSchema: {
337
+ type: 'object',
338
+ properties: {
339
+ query: { type: 'string' },
340
+ limit: { type: 'number' },
341
+ },
342
+ required: ['query'],
343
+ },
344
+ },
298
345
  ];
299
346
  // ─── MCP stdio protocol (JSON-RPC 2.0, Content-Length framing) ───────────────
300
347
  function sendMessage(msg) {
@@ -344,6 +391,18 @@ function handleRequest(msg) {
344
391
  result = cmMemoryDecay(a);
345
392
  else if (name === 'cm_index_refresh')
346
393
  result = cmIndexRefresh(a);
394
+ else if (name === 'cm_plan')
395
+ result = (0, mcp_skills_tools_1.cmPlanTool)(PROJECT_PATH);
396
+ else if (name === 'cm_review')
397
+ result = (0, mcp_skills_tools_1.cmReviewTool)(PROJECT_PATH);
398
+ else if (name === 'cm_qa')
399
+ result = (0, mcp_skills_tools_1.cmQaTool)(PROJECT_PATH);
400
+ else if (name === 'cm_deploy')
401
+ result = (0, mcp_skills_tools_1.cmDeployTool)(PROJECT_PATH);
402
+ else if (name === 'cm_search')
403
+ result = (0, mcp_skills_tools_1.cmSearchTool)(PROJECT_PATH, a);
404
+ else if (name === 'cm_memory_query')
405
+ result = (0, mcp_skills_tools_1.cmMemoryQueryTool)(PROJECT_PATH, a);
347
406
  else
348
407
  throw new Error(`Unknown tool: ${name}`);
349
408
  respond(id, {
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * Extra MCP tool handlers: plan/review/qa/deploy/search — bridge to sprint + memory.
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.cmPlanTool = cmPlanTool;
10
+ exports.cmReviewTool = cmReviewTool;
11
+ exports.cmQaTool = cmQaTool;
12
+ exports.cmDeployTool = cmDeployTool;
13
+ exports.cmSearchTool = cmSearchTool;
14
+ exports.cmMemoryQueryTool = cmMemoryQueryTool;
15
+ const fs_1 = __importDefault(require("fs"));
16
+ const path_1 = __importDefault(require("path"));
17
+ const context_bus_1 = require("./context-bus");
18
+ const sprint_pipeline_1 = require("./sprint-pipeline");
19
+ const context_db_1 = require("./context-db");
20
+ function cmPlanTool(projectPath) {
21
+ const sprint = (0, sprint_pipeline_1.readSprintState)(projectPath);
22
+ const bus = (0, context_bus_1.readBus)(projectPath);
23
+ const preview = (0, sprint_pipeline_1.sprintArtifactPreviewFromDisk)(projectPath);
24
+ return {
25
+ sprint_active: !!sprint,
26
+ sprint: sprint !== null && sprint !== void 0 ? sprint : null,
27
+ context_bus: bus,
28
+ default_pipeline: sprint_pipeline_1.SPRINT_STEPS,
29
+ next_skill_hint: sprint
30
+ ? sprint.current_index >= sprint.pipeline.length
31
+ ? '(sprint complete — run cm-retro)'
32
+ : (0, sprint_pipeline_1.skillMappingForStep)(sprint.pipeline[sprint.current_index])
33
+ : 'cm-planning',
34
+ artifact_paths: preview.artifacts,
35
+ };
36
+ }
37
+ function cmReviewTool(projectPath) {
38
+ const artDir = path_1.default.join(projectPath, '.cm', 'sprint', 'artifacts', 'review.md');
39
+ let review = '';
40
+ if (fs_1.default.existsSync(artDir))
41
+ review = fs_1.default.readFileSync(artDir, 'utf8');
42
+ return {
43
+ review_artifact: artDir,
44
+ has_content: review.length > 0,
45
+ preview: review.slice(0, 4000),
46
+ hint: 'Use cm-code-review skill for full checklist; paste diff + requirements.',
47
+ };
48
+ }
49
+ function cmQaTool(projectPath) {
50
+ return {
51
+ browse_daemon: 'Run: cm browse start --token <secret> then POST /session/start',
52
+ visual: 'cm qa-visual --url http://localhost:3000',
53
+ gates: ['cm-quality-gate', 'cm-test-gate'],
54
+ };
55
+ }
56
+ function cmDeployTool(projectPath) {
57
+ return {
58
+ hint: 'Use cm-safe-deploy skill; after ship run cm canary --url <prod>',
59
+ project: projectPath,
60
+ };
61
+ }
62
+ function cmSearchTool(projectPath, args) {
63
+ const { query, scope = 'all', limit = 10 } = args;
64
+ const dbPath = (0, context_db_1.getDbPath)(projectPath);
65
+ (0, context_db_1.openDb)(dbPath);
66
+ const results = [];
67
+ if (scope === 'all' || scope === 'learnings') {
68
+ for (const l of (0, context_db_1.queryLearnings)(dbPath, query, undefined, limit)) {
69
+ results.push(Object.assign({ type: 'learning' }, l));
70
+ }
71
+ }
72
+ if (scope === 'all' || scope === 'decisions') {
73
+ for (const d of (0, context_db_1.queryDecisions)(dbPath, query, limit)) {
74
+ results.push(Object.assign({ type: 'decision' }, d));
75
+ }
76
+ }
77
+ return { query, scope, count: results.length, results };
78
+ }
79
+ function cmMemoryQueryTool(projectPath, args) {
80
+ return cmSearchTool(projectPath, Object.assign(Object.assign({}, args), { scope: 'all' }));
81
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ /**
3
+ * Aggregate `.cm/operational-learnings.jsonl` for `cm retro summary`.
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.loadRetroEntries = loadRetroEntries;
10
+ exports.filterSince = filterSince;
11
+ exports.countByTool = countByTool;
12
+ exports.formatRetroMarkdown = formatRetroMarkdown;
13
+ exports.formatRetroJson = formatRetroJson;
14
+ const fs_1 = __importDefault(require("fs"));
15
+ function loadRetroEntries(filePath) {
16
+ if (!fs_1.default.existsSync(filePath))
17
+ return [];
18
+ const out = [];
19
+ for (const line of fs_1.default.readFileSync(filePath, 'utf8').split('\n')) {
20
+ const t = line.trim();
21
+ if (!t)
22
+ continue;
23
+ try {
24
+ const o = JSON.parse(t);
25
+ if (typeof o.ts === 'string' && typeof o.note === 'string') {
26
+ out.push({
27
+ ts: o.ts,
28
+ tool: typeof o.tool === 'string' ? o.tool : 'unknown',
29
+ note: o.note,
30
+ });
31
+ }
32
+ }
33
+ catch (_a) {
34
+ /* skip malformed line */
35
+ }
36
+ }
37
+ return out;
38
+ }
39
+ function filterSince(entries, sinceIso) {
40
+ const t0 = new Date(sinceIso).getTime();
41
+ if (Number.isNaN(t0))
42
+ return entries;
43
+ return entries.filter((e) => new Date(e.ts).getTime() >= t0);
44
+ }
45
+ function countByTool(entries) {
46
+ const m = {};
47
+ for (const e of entries) {
48
+ m[e.tool] = (m[e.tool] || 0) + 1;
49
+ }
50
+ return m;
51
+ }
52
+ function formatRetroMarkdown(entries, byTool) {
53
+ const lines = ['# Retro summary', '', `**Total entries:** ${entries.length}`, ''];
54
+ lines.push('## By tool');
55
+ for (const [tool, n] of Object.entries(byTool).sort((a, b) => b[1] - a[1])) {
56
+ lines.push(`- **${tool}:** ${n}`);
57
+ }
58
+ lines.push('', '## Entries (chronological)');
59
+ for (const e of entries.sort((a, b) => a.ts.localeCompare(b.ts))) {
60
+ lines.push(`- \`${e.ts}\` [${e.tool}] ${e.note}`);
61
+ }
62
+ return lines.join('\n');
63
+ }
64
+ function formatRetroJson(entries, byTool) {
65
+ return JSON.stringify({
66
+ total: entries.length,
67
+ by_tool: byTool,
68
+ entries: entries.sort((a, b) => a.ts.localeCompare(b.ts)),
69
+ }, null, 2);
70
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * Redaction + secondary-model review for `cm second-opinion`.
4
+ */
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.redactDiffForReview = redactDiffForReview;
16
+ exports.reviewWithOpenAI = reviewWithOpenAI;
17
+ exports.reviewWithAnthropic = reviewWithAnthropic;
18
+ const SYSTEM = 'You are a senior reviewer. List risks, bugs, and missing tests. Be concise. Do not restate the entire diff.';
19
+ function redactDiffForReview(text, maxLen = 120000) {
20
+ let t = text.slice(0, maxLen);
21
+ t = t.replace(/^(\s*(?:#\s*)?(?:API_KEY|API_SECRET|SECRET|PASSWORD|ACCESS_TOKEN|AUTH_TOKEN|BEARER|Authorization)\s*[:=]\s*)\S+.*$/gim, '$1[REDACTED]');
22
+ t = t.replace(/\b(sk-[a-zA-Z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|ghp_[A-Za-z0-9]{36,}|gho_[A-Za-z0-9]{36,}|AKIA[0-9A-Z]{16})\b/g, '[REDACTED_TOKEN]');
23
+ return t;
24
+ }
25
+ function reviewWithOpenAI(diffText) {
26
+ return __awaiter(this, void 0, void 0, function* () {
27
+ var _a, _b, _c, _d;
28
+ const key = process.env.OPENAI_API_KEY;
29
+ if (!key)
30
+ throw new Error('OPENAI_API_KEY is not set');
31
+ const model = process.env.CM_SECOND_OPINION_MODEL || 'gpt-4o-mini';
32
+ const res = yield fetch('https://api.openai.com/v1/chat/completions', {
33
+ method: 'POST',
34
+ headers: {
35
+ 'Content-Type': 'application/json',
36
+ Authorization: `Bearer ${key}`,
37
+ },
38
+ body: JSON.stringify({
39
+ model,
40
+ messages: [
41
+ { role: 'system', content: SYSTEM },
42
+ { role: 'user', content: `Review this diff:\n\n${diffText}` },
43
+ ],
44
+ }),
45
+ });
46
+ if (!res.ok)
47
+ throw new Error(yield res.text());
48
+ const data = (yield res.json());
49
+ return (_d = (_c = (_b = (_a = data.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) !== null && _d !== void 0 ? _d : '';
50
+ });
51
+ }
52
+ function reviewWithAnthropic(diffText) {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ var _a, _b;
55
+ const key = process.env.ANTHROPIC_API_KEY;
56
+ if (!key)
57
+ throw new Error('ANTHROPIC_API_KEY is not set');
58
+ const model = process.env.CM_ANTHROPIC_MODEL || 'claude-3-5-haiku-20241022';
59
+ const res = yield fetch('https://api.anthropic.com/v1/messages', {
60
+ method: 'POST',
61
+ headers: {
62
+ 'Content-Type': 'application/json',
63
+ 'x-api-key': key,
64
+ 'anthropic-version': '2023-06-01',
65
+ },
66
+ body: JSON.stringify({
67
+ model,
68
+ max_tokens: 4096,
69
+ system: SYSTEM,
70
+ messages: [{ role: 'user', content: `Review this diff:\n\n${diffText}` }],
71
+ }),
72
+ });
73
+ if (!res.ok)
74
+ throw new Error(yield res.text());
75
+ const data = (yield res.json());
76
+ const block = (_a = data.content) === null || _a === void 0 ? void 0 : _a.find((c) => c.type === 'text');
77
+ return (_b = block === null || block === void 0 ? void 0 : block.text) !== null && _b !== void 0 ? _b : '';
78
+ });
79
+ }
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /**
3
+ * Opinionated sprint pipeline + Context Bus files under `.cm/sprint/`.
4
+ * Complements root `context-bus.json` with step artifacts (ADR 002).
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.SPRINT_STEPS = void 0;
11
+ exports.readSprintState = readSprintState;
12
+ exports.writeSprintState = writeSprintState;
13
+ exports.initSprint = initSprint;
14
+ exports.completeSprintStep = completeSprintStep;
15
+ exports.skipSprintStep = skipSprintStep;
16
+ exports.resetSprint = resetSprint;
17
+ exports.sprintDryRun = sprintDryRun;
18
+ exports.sprintArtifactPreviewFromDisk = sprintArtifactPreviewFromDisk;
19
+ exports.skillMappingForStep = skillMappingForStep;
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const path_1 = __importDefault(require("path"));
22
+ exports.SPRINT_STEPS = [
23
+ 'brainstorm',
24
+ 'plan',
25
+ 'design',
26
+ 'tdd',
27
+ 'build',
28
+ 'review',
29
+ 'qa',
30
+ 'security',
31
+ 'ship',
32
+ 'monitor',
33
+ 'retro',
34
+ ];
35
+ function sprintDir(projectPath) {
36
+ return path_1.default.join(projectPath, '.cm', 'sprint');
37
+ }
38
+ function statePath(projectPath) {
39
+ return path_1.default.join(sprintDir(projectPath), 'state.json');
40
+ }
41
+ function ensureSprintDir(projectPath) {
42
+ const d = sprintDir(projectPath);
43
+ const art = path_1.default.join(d, 'artifacts');
44
+ if (!fs_1.default.existsSync(art))
45
+ fs_1.default.mkdirSync(art, { recursive: true });
46
+ }
47
+ function normalizeSprintState(raw) {
48
+ var _a;
49
+ return Object.assign(Object.assign({}, raw), { version: raw.version === 2 ? 2 : 1, skipped: (_a = raw.skipped) !== null && _a !== void 0 ? _a : [] });
50
+ }
51
+ function readSprintState(projectPath) {
52
+ const p = statePath(projectPath);
53
+ if (!fs_1.default.existsSync(p))
54
+ return null;
55
+ try {
56
+ const raw = JSON.parse(fs_1.default.readFileSync(p, 'utf8'));
57
+ return normalizeSprintState(raw);
58
+ }
59
+ catch (_a) {
60
+ return null;
61
+ }
62
+ }
63
+ function writeSprintState(projectPath, state) {
64
+ ensureSprintDir(projectPath);
65
+ fs_1.default.writeFileSync(statePath(projectPath), JSON.stringify(state, null, 2), 'utf8');
66
+ }
67
+ function initSprint(projectPath, fromStep) {
68
+ ensureSprintDir(projectPath);
69
+ const now = new Date().toISOString();
70
+ let pipeline = [...exports.SPRINT_STEPS];
71
+ let startIdx = 0;
72
+ if (fromStep) {
73
+ const i = pipeline.indexOf(fromStep);
74
+ if (i >= 0)
75
+ startIdx = i;
76
+ }
77
+ const state = {
78
+ version: 2,
79
+ pipeline,
80
+ current_index: startIdx,
81
+ completed: [],
82
+ skipped: [],
83
+ started_at: now,
84
+ updated_at: now,
85
+ artifacts_dir: path_1.default.join(sprintDir(projectPath), 'artifacts'),
86
+ };
87
+ writeSprintState(projectPath, state);
88
+ appendEvent(projectPath, { type: 'init', from: fromStep !== null && fromStep !== void 0 ? fromStep : null, at: now });
89
+ return state;
90
+ }
91
+ function completeSprintStep(projectPath, step, artifactBody) {
92
+ let state = readSprintState(projectPath);
93
+ if (!state)
94
+ state = initSprint(projectPath);
95
+ if (state.current_index >= state.pipeline.length) {
96
+ throw new Error('Sprint pipeline already finished');
97
+ }
98
+ const expected = state.pipeline[state.current_index];
99
+ if (expected !== step) {
100
+ throw new Error(`Expected step "${expected}", got "${step}"`);
101
+ }
102
+ const artFile = path_1.default.join(state.artifacts_dir, `${step}.md`);
103
+ fs_1.default.writeFileSync(artFile, artifactBody, 'utf8');
104
+ state.completed.push(step);
105
+ state.current_index = Math.min(state.current_index + 1, state.pipeline.length);
106
+ state.updated_at = new Date().toISOString();
107
+ state.version = 2;
108
+ writeSprintState(projectPath, state);
109
+ appendEvent(projectPath, { type: 'complete', step, at: state.updated_at });
110
+ return state;
111
+ }
112
+ const SKIP_STUB = (step, at) => `# ${step}\n\n_Skipped via \`cm sprint skip\` at ${at}._\n`;
113
+ function skipSprintStep(projectPath, step) {
114
+ let state = readSprintState(projectPath);
115
+ if (!state)
116
+ state = initSprint(projectPath);
117
+ if (state.current_index >= state.pipeline.length) {
118
+ throw new Error('Sprint pipeline already finished');
119
+ }
120
+ const expected = state.pipeline[state.current_index];
121
+ if (expected !== step) {
122
+ throw new Error(`Expected step "${expected}", got "${step}"`);
123
+ }
124
+ const at = new Date().toISOString();
125
+ const artFile = path_1.default.join(state.artifacts_dir, `${step}.md`);
126
+ fs_1.default.writeFileSync(artFile, SKIP_STUB(step, at), 'utf8');
127
+ state.skipped.push(step);
128
+ state.current_index = Math.min(state.current_index + 1, state.pipeline.length);
129
+ state.updated_at = at;
130
+ state.version = 2;
131
+ writeSprintState(projectPath, state);
132
+ appendEvent(projectPath, { type: 'skip', step, at });
133
+ return state;
134
+ }
135
+ function backupDirName() {
136
+ return new Date().toISOString().replace(/:/g, '-');
137
+ }
138
+ /** Remove sprint state; optional backup under `.cm/sprint/backup/<timestamp>/`. */
139
+ function resetSprint(projectPath, options) {
140
+ const backup = (options === null || options === void 0 ? void 0 : options.backup) !== false;
141
+ const sd = sprintDir(projectPath);
142
+ const st = statePath(projectPath);
143
+ const ev = eventsPath(projectPath);
144
+ const art = path_1.default.join(sd, 'artifacts');
145
+ const hasState = fs_1.default.existsSync(st);
146
+ let hasEvents = false;
147
+ if (fs_1.default.existsSync(ev)) {
148
+ try {
149
+ hasEvents = fs_1.default.statSync(ev).size > 0;
150
+ }
151
+ catch (_a) {
152
+ hasEvents = false;
153
+ }
154
+ }
155
+ let hasArtifacts = false;
156
+ if (fs_1.default.existsSync(art)) {
157
+ try {
158
+ hasArtifacts = fs_1.default.readdirSync(art).length > 0;
159
+ }
160
+ catch (_b) {
161
+ hasArtifacts = false;
162
+ }
163
+ }
164
+ if (!hasState && !hasEvents && !hasArtifacts) {
165
+ return { ok: false, reason: 'no_sprint_data' };
166
+ }
167
+ let backupPath;
168
+ if (backup) {
169
+ const stamp = backupDirName();
170
+ backupPath = path_1.default.join(sd, 'backup', stamp);
171
+ fs_1.default.mkdirSync(backupPath, { recursive: true });
172
+ if (hasState)
173
+ fs_1.default.copyFileSync(st, path_1.default.join(backupPath, 'state.json'));
174
+ if (fs_1.default.existsSync(ev))
175
+ fs_1.default.copyFileSync(ev, path_1.default.join(backupPath, 'events.jsonl'));
176
+ if (fs_1.default.existsSync(art)) {
177
+ const destArt = path_1.default.join(backupPath, 'artifacts');
178
+ fs_1.default.cpSync(art, destArt, { recursive: true });
179
+ }
180
+ }
181
+ fs_1.default.rmSync(st, { force: true });
182
+ fs_1.default.rmSync(ev, { force: true });
183
+ fs_1.default.rmSync(art, { recursive: true, force: true });
184
+ fs_1.default.mkdirSync(art, { recursive: true });
185
+ return { ok: true, backupDir: backupPath };
186
+ }
187
+ function sprintDryRun(projectPath) {
188
+ var _a;
189
+ const state = (_a = readSprintState(projectPath)) !== null && _a !== void 0 ? _a : initSprint(projectPath);
190
+ return sprintArtifactPreview(state);
191
+ }
192
+ /** Read-only preview without creating files (for MCP / status). */
193
+ function sprintArtifactPreviewFromDisk(projectPath) {
194
+ const state = readSprintState(projectPath);
195
+ if (!state) {
196
+ const base = path_1.default.join(projectPath, '.cm', 'sprint', 'artifacts');
197
+ const artifacts = exports.SPRINT_STEPS.map((s) => path_1.default.join(base, `${s}.md`));
198
+ return { steps: [...exports.SPRINT_STEPS], artifacts };
199
+ }
200
+ return sprintArtifactPreview(state);
201
+ }
202
+ function sprintArtifactPreview(state) {
203
+ const artifacts = state.pipeline.map((s) => path_1.default.join(state.artifacts_dir, `${s}.md`));
204
+ return { steps: [...state.pipeline], artifacts };
205
+ }
206
+ function eventsPath(projectPath) {
207
+ return path_1.default.join(sprintDir(projectPath), 'events.jsonl');
208
+ }
209
+ function appendEvent(projectPath, rec) {
210
+ ensureSprintDir(projectPath);
211
+ fs_1.default.appendFileSync(eventsPath(projectPath), JSON.stringify(rec) + '\n', 'utf8');
212
+ }
213
+ function skillMappingForStep(step) {
214
+ const map = {
215
+ brainstorm: 'cm-brainstorm-idea',
216
+ plan: 'cm-planning',
217
+ design: 'cm-ui-preview / cm-design-system',
218
+ tdd: 'cm-tdd',
219
+ build: 'cm-execution',
220
+ review: 'cm-code-review',
221
+ qa: 'cm-quality-gate / cm-test-gate',
222
+ security: 'cm-secret-shield / cm-security-gate',
223
+ ship: 'cm-safe-deploy',
224
+ monitor: 'cm-canary (post-deploy)',
225
+ retro: 'cm-retro',
226
+ };
227
+ return map[step];
228
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VikingBackend = exports.SqliteBackend = void 0;
4
+ exports.getBackend = getBackend;
5
+ const context_db_1 = require("./context-db");
6
+ const viking_backend_1 = require("./backends/viking-backend");
7
+ Object.defineProperty(exports, "VikingBackend", { enumerable: true, get: function () { return viking_backend_1.VikingBackend; } });
8
+ const viking_http_client_1 = require("./backends/viking-http-client");
9
+ const cm_config_1 = require("./cm-config");
10
+ // ─── SqliteBackend ────────────────────────────────────────────────────────────
11
+ /**
12
+ * Default backend — thin wrapper around context-db.ts (better-sqlite3 + FTS5).
13
+ * context-db.ts is NOT modified; this class is purely additive.
14
+ */
15
+ class SqliteBackend {
16
+ constructor(projectPath) {
17
+ this.dbPath = (0, context_db_1.getDbPath)(projectPath);
18
+ }
19
+ initialize() { (0, context_db_1.openDb)(this.dbPath); }
20
+ close() { (0, context_db_1.closeDb)(this.dbPath); }
21
+ insertLearning(l) { (0, context_db_1.insertLearning)(this.dbPath, l); }
22
+ getLearningById(id) { return (0, context_db_1.getLearningById)(this.dbPath, id); }
23
+ queryLearnings(q, scope, limit = 10) {
24
+ return (0, context_db_1.queryLearnings)(this.dbPath, q, scope, limit);
25
+ }
26
+ insertDecision(d) { (0, context_db_1.insertDecision)(this.dbPath, d); }
27
+ queryDecisions(q, limit = 10) { return (0, context_db_1.queryDecisions)(this.dbPath, q, limit); }
28
+ upsertIndex(resource, level, content, sourceHash) {
29
+ (0, context_db_1.upsertIndex)(this.dbPath, resource, level, content, sourceHash);
30
+ }
31
+ getIndex(resource, level) {
32
+ return (0, context_db_1.getIndex)(this.dbPath, resource, level);
33
+ }
34
+ writeSkillOutput(o) { (0, context_db_1.writeSkillOutput)(this.dbPath, o); }
35
+ getSkillOutputs(sessionId) { return (0, context_db_1.getSkillOutputs)(this.dbPath, sessionId); }
36
+ }
37
+ exports.SqliteBackend = SqliteBackend;
38
+ // ─── Factory ─────────────────────────────────────────────────────────────────
39
+ /**
40
+ * Returns the configured StorageBackend for the given project.
41
+ *
42
+ * Reads `.cm/config.yaml → storage.backend` via `loadCmConfig` (default: `sqlite`).
43
+ * For `viking` backend, reads `storage.viking.*` for connection config.
44
+ *
45
+ * Usage:
46
+ * const backend = getBackend('/path/to/project');
47
+ * backend.initialize();
48
+ * const results = backend.queryLearnings('i18n locale');
49
+ */
50
+ function getBackend(projectPath) {
51
+ var _a, _b, _c;
52
+ const cfg = (0, cm_config_1.loadCmConfig)(projectPath);
53
+ const engine = ((_b = (_a = cfg.storage) === null || _a === void 0 ? void 0 : _a.backend) !== null && _b !== void 0 ? _b : 'sqlite').toLowerCase();
54
+ switch (engine) {
55
+ case 'viking': {
56
+ const vikingConfig = Object.assign(Object.assign({}, viking_http_client_1.DEFAULT_VIKING_CONFIG), (_c = cfg.storage) === null || _c === void 0 ? void 0 : _c.viking);
57
+ return new viking_backend_1.VikingBackend(vikingConfig);
58
+ }
59
+ case 'sqlite':
60
+ default:
61
+ return new SqliteBackend(projectPath);
62
+ }
63
+ }