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.
Files changed (161) hide show
  1. package/CHANGELOG.md +74 -8
  2. package/README.md +192 -95
  3. package/dist/advisory-handoff.js +89 -0
  4. package/dist/advisory-report.js +105 -0
  5. package/dist/browse-server.js +251 -0
  6. package/dist/cli/command-registry.js +34 -0
  7. package/dist/cli/commands/agent.js +120 -0
  8. package/dist/cli/commands/bench.js +69 -0
  9. package/dist/cli/commands/brain.js +108 -0
  10. package/dist/cli/commands/dashboard.js +93 -0
  11. package/dist/cli/commands/design-studio.js +111 -0
  12. package/dist/cli/commands/distro.js +25 -0
  13. package/dist/cli/commands/engineering.js +596 -0
  14. package/dist/cli/commands/evolve.js +123 -0
  15. package/dist/cli/commands/mcp-serve.js +104 -0
  16. package/dist/cli/commands/project.js +324 -0
  17. package/dist/cli/commands/skill-chain.js +269 -0
  18. package/dist/cli/commands/system.js +89 -0
  19. package/dist/cli/commands/task.js +254 -0
  20. package/dist/cli/update-check.js +83 -0
  21. package/dist/cm-config.js +92 -0
  22. package/dist/cm-suggest.js +77 -0
  23. package/dist/codybench/judges/automated.js +31 -0
  24. package/dist/codybench/runners/claude-code.js +32 -0
  25. package/dist/codybench/suites/memory-retention.js +85 -0
  26. package/dist/codybench/suites/tdd-regression.js +35 -0
  27. package/dist/codybench/suites/token-efficiency.js +55 -0
  28. package/dist/codybench/types.js +2 -0
  29. package/dist/context-db.js +157 -0
  30. package/dist/continuity.js +2 -6
  31. package/dist/distro-validate.js +54 -0
  32. package/dist/execution-analyzer.js +138 -0
  33. package/dist/guardian-core.js +74 -0
  34. package/dist/index.js +36 -2759
  35. package/dist/indexer/skills-lib.js +533 -0
  36. package/dist/indexer/skills-map.js +1374 -0
  37. package/dist/indexer/skills.js +16 -0
  38. package/dist/learning-promoter.js +246 -0
  39. package/dist/mcp-context-server.js +289 -1
  40. package/dist/mcp-skills-tools.js +81 -0
  41. package/dist/retro-summary.js +70 -0
  42. package/dist/second-opinion-providers.js +79 -0
  43. package/dist/skill-chain.js +63 -1
  44. package/dist/skill-evolver.js +456 -0
  45. package/dist/skill-execution-cache.js +254 -0
  46. package/dist/smart-brain-router.js +184 -0
  47. package/dist/sprint-pipeline.js +228 -0
  48. package/dist/storage-backend.js +14 -67
  49. package/dist/token-budget.js +88 -0
  50. package/dist/utils/cli-utils.js +76 -0
  51. package/dist/utils/skill-utils.js +32 -0
  52. package/package.json +17 -7
  53. package/scripts/build-skills.mjs +51 -0
  54. package/scripts/gate-0-repo-hygiene.js +75 -0
  55. package/scripts/postinstall.js +34 -28
  56. package/scripts/security-scan.js +1 -1
  57. package/scripts/validate-skills.mjs +42 -0
  58. package/skills/CLAUDE.md +2 -7
  59. package/skills/_shared/helpers.md +2 -8
  60. package/skills/cm-ads-tracker/SKILL.md +3 -6
  61. package/skills/cm-browse/SKILL.md +34 -0
  62. package/skills/cm-conductor-worktrees/SKILL.md +28 -0
  63. package/skills/cm-content-factory/SKILL.md +1 -1
  64. package/skills/cm-content-factory/landing/docs/content/changelog.md +36 -0
  65. package/skills/cm-content-factory/landing/docs/content/deployment.md +46 -0
  66. package/skills/cm-content-factory/landing/docs/content/execution-flow.md +67 -0
  67. package/skills/cm-content-factory/landing/docs/content/memory-system.md +38 -0
  68. package/skills/cm-content-factory/landing/docs/content/openspace.md +27 -0
  69. package/skills/cm-content-factory/landing/docs/content/use-cases.md +26 -0
  70. package/skills/cm-content-factory/landing/docs/content/v5-intro.md +28 -0
  71. package/skills/cm-content-factory/landing/docs/index.html +240 -0
  72. package/skills/cm-content-factory/landing/index.html +100 -100
  73. package/skills/cm-content-factory/landing/script.js +42 -0
  74. package/skills/cm-content-factory/landing/translations.js +400 -400
  75. package/skills/cm-continuity/SKILL.md +32 -33
  76. package/skills/cm-design-studio/SKILL.md +34 -0
  77. package/skills/cm-ecosystem-roadmap/SKILL.md +15 -0
  78. package/skills/cm-engineering-meta/SKILL.md +73 -0
  79. package/skills/cm-growth-hacking/SKILL.md +1 -12
  80. package/skills/cm-guardian-runtime/SKILL.md +26 -0
  81. package/skills/cm-mcp-engineering/SKILL.md +22 -0
  82. package/skills/cm-notebooklm/SKILL.md +1 -17
  83. package/skills/cm-post-deploy-canary/SKILL.md +22 -0
  84. package/skills/cm-project-bootstrap/SKILL.md +11 -0
  85. package/skills/cm-qa-visual-cli/SKILL.md +22 -0
  86. package/skills/cm-retro-cli/SKILL.md +23 -0
  87. package/skills/cm-second-opinion-cli/SKILL.md +23 -0
  88. package/skills/cm-secret-shield/SKILL.md +2 -2
  89. package/skills/cm-security-gate/SKILL.md +1 -0
  90. package/skills/cm-skill-chain/SKILL.md +25 -4
  91. package/skills/cm-skill-evolution/SKILL.md +83 -0
  92. package/skills/cm-skill-health/SKILL.md +83 -0
  93. package/skills/cm-skill-index/SKILL.md +11 -3
  94. package/skills/cm-skill-search/SKILL.md +49 -0
  95. package/skills/cm-skill-share/SKILL.md +58 -0
  96. package/skills/cm-sprint-bus/SKILL.md +33 -0
  97. package/skills/cm-start/SKILL.md +0 -10
  98. package/skills/cm-tdd/SKILL.md +59 -72
  99. package/skills/profiles/README.md +21 -0
  100. package/skills/profiles/core.txt +23 -0
  101. package/skills/profiles/design.txt +6 -0
  102. package/skills/profiles/full.txt +62 -0
  103. package/skills/profiles/growth.txt +10 -0
  104. package/skills/profiles/knowledge.txt +7 -0
  105. package/install.sh +0 -901
  106. package/scripts/test-gemini.js +0 -13
  107. package/skills/cm-frappe-agent/SKILL.md +0 -134
  108. package/skills/cm-frappe-agent/agents/doctype-architect.md +0 -596
  109. package/skills/cm-frappe-agent/agents/erpnext-customizer.md +0 -643
  110. package/skills/cm-frappe-agent/agents/frappe-backend.md +0 -814
  111. package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +0 -557
  112. package/skills/cm-frappe-agent/agents/frappe-debugger.md +0 -625
  113. package/skills/cm-frappe-agent/agents/frappe-fixer.md +0 -275
  114. package/skills/cm-frappe-agent/agents/frappe-frontend.md +0 -660
  115. package/skills/cm-frappe-agent/agents/frappe-installer.md +0 -158
  116. package/skills/cm-frappe-agent/agents/frappe-performance.md +0 -307
  117. package/skills/cm-frappe-agent/agents/frappe-planner.md +0 -419
  118. package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +0 -153
  119. package/skills/cm-frappe-agent/agents/github-workflow.md +0 -286
  120. package/skills/cm-frappe-agent/commands/frappe-app.md +0 -351
  121. package/skills/cm-frappe-agent/commands/frappe-backend.md +0 -162
  122. package/skills/cm-frappe-agent/commands/frappe-bench.md +0 -254
  123. package/skills/cm-frappe-agent/commands/frappe-debug.md +0 -263
  124. package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +0 -272
  125. package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +0 -310
  126. package/skills/cm-frappe-agent/commands/frappe-erpnext.md +0 -210
  127. package/skills/cm-frappe-agent/commands/frappe-fix.md +0 -59
  128. package/skills/cm-frappe-agent/commands/frappe-frontend.md +0 -210
  129. package/skills/cm-frappe-agent/commands/frappe-fullstack.md +0 -243
  130. package/skills/cm-frappe-agent/commands/frappe-github.md +0 -57
  131. package/skills/cm-frappe-agent/commands/frappe-install.md +0 -52
  132. package/skills/cm-frappe-agent/commands/frappe-plan.md +0 -442
  133. package/skills/cm-frappe-agent/commands/frappe-remote.md +0 -58
  134. package/skills/cm-frappe-agent/commands/frappe-test.md +0 -356
  135. package/skills/cm-frappe-agent/docs/README.md +0 -51
  136. package/skills/cm-frappe-agent/docs/agents-catalog.md +0 -113
  137. package/skills/cm-frappe-agent/docs/architecture.md +0 -149
  138. package/skills/cm-frappe-agent/docs/commands-catalog.md +0 -82
  139. package/skills/cm-frappe-agent/docs/resources-catalog.md +0 -66
  140. package/skills/cm-frappe-agent/docs/sitemap-urls.txt +0 -52
  141. package/skills/cm-frappe-agent/docs/sitemap.md +0 -81
  142. package/skills/cm-frappe-agent/docs/sop/user-guide.md +0 -178
  143. package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +0 -122
  144. package/skills/cm-frappe-agent/resources/7-layer-architecture.md +0 -985
  145. package/skills/cm-frappe-agent/resources/bench_commands.md +0 -73
  146. package/skills/cm-frappe-agent/resources/code-patterns-guide.md +0 -948
  147. package/skills/cm-frappe-agent/resources/common_pitfalls.md +0 -266
  148. package/skills/cm-frappe-agent/resources/doctype-registry.md +0 -158
  149. package/skills/cm-frappe-agent/resources/installation-guide.md +0 -289
  150. package/skills/cm-frappe-agent/resources/rest-api-patterns.md +0 -182
  151. package/skills/cm-frappe-agent/resources/scaffold_checklist.md +0 -82
  152. package/skills/cm-frappe-agent/resources/upgrade_patterns.md +0 -113
  153. package/skills/cm-frappe-agent/resources/web-form-patterns.md +0 -252
  154. package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +0 -621
  155. package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +0 -642
  156. package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +0 -576
  157. package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +0 -740
  158. package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +0 -47
  159. package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +0 -608
  160. package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +0 -46
  161. package/skills/frappe-app-builder.zip +0 -0
@@ -14,6 +14,10 @@ exports.upsertIndex = upsertIndex;
14
14
  exports.getIndex = getIndex;
15
15
  exports.writeSkillOutput = writeSkillOutput;
16
16
  exports.getSkillOutputs = getSkillOutputs;
17
+ exports.recordExecutionAnalysis = recordExecutionAnalysis;
18
+ exports.getExecutionAnalyses = getExecutionAnalyses;
19
+ exports.getSkillMetric = getSkillMetric;
20
+ exports.listSkillMetrics = listSkillMetrics;
17
21
  exports.getDbPath = getDbPath;
18
22
  const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
19
23
  const path_1 = __importDefault(require("path"));
@@ -116,6 +120,38 @@ CREATE TABLE IF NOT EXISTS token_usage (
116
120
  tokens_used INTEGER NOT NULL,
117
121
  timestamp TEXT NOT NULL
118
122
  );
123
+
124
+ CREATE TABLE IF NOT EXISTS execution_analyses (
125
+ id TEXT PRIMARY KEY,
126
+ task_title TEXT NOT NULL,
127
+ status TEXT NOT NULL,
128
+ summary TEXT NOT NULL DEFAULT '',
129
+ source_task_type TEXT,
130
+ session_id TEXT,
131
+ chain_id TEXT,
132
+ selected_skills_json TEXT NOT NULL DEFAULT '[]',
133
+ token_estimate INTEGER DEFAULT 0,
134
+ latency_bucket TEXT,
135
+ bus_snapshot TEXT,
136
+ retro_summary TEXT,
137
+ recommended_action TEXT,
138
+ confidence REAL,
139
+ skill_judgments_json TEXT NOT NULL DEFAULT '[]',
140
+ created_at TEXT NOT NULL
141
+ );
142
+
143
+ CREATE TABLE IF NOT EXISTS skill_metrics (
144
+ skill TEXT PRIMARY KEY,
145
+ selections INTEGER NOT NULL DEFAULT 0,
146
+ applications INTEGER NOT NULL DEFAULT 0,
147
+ task_completions INTEGER NOT NULL DEFAULT 0,
148
+ fallbacks INTEGER NOT NULL DEFAULT 0,
149
+ total_token_estimate INTEGER NOT NULL DEFAULT 0,
150
+ last_task_type TEXT,
151
+ last_recommended_action TEXT,
152
+ last_used_at TEXT NOT NULL,
153
+ updated_at TEXT NOT NULL
154
+ );
119
155
  `;
120
156
  // ─── Open / Close ────────────────────────────────────────────────────────────
121
157
  function openDb(dbPath) {
@@ -259,6 +295,127 @@ function getSkillOutputs(dbPath, sessionId) {
259
295
  const db = openDb(dbPath);
260
296
  return db.prepare('SELECT * FROM skill_outputs WHERE session_id = ? ORDER BY id ASC').all(sessionId);
261
297
  }
298
+ // ─── Execution Analyses ─────────────────────────────────────────────────────
299
+ function safeParseJsonArray(raw) {
300
+ if (!raw)
301
+ return [];
302
+ try {
303
+ const parsed = JSON.parse(raw);
304
+ return Array.isArray(parsed) ? parsed : [];
305
+ }
306
+ catch (_a) {
307
+ return [];
308
+ }
309
+ }
310
+ function rowToExecutionAnalysis(row) {
311
+ var _a;
312
+ return {
313
+ id: String(row.id),
314
+ task_title: String(row.task_title),
315
+ status: row.status,
316
+ summary: String((_a = row.summary) !== null && _a !== void 0 ? _a : ''),
317
+ source_task_type: typeof row.source_task_type === 'string' ? row.source_task_type : undefined,
318
+ session_id: typeof row.session_id === 'string' ? row.session_id : undefined,
319
+ chain_id: typeof row.chain_id === 'string' ? row.chain_id : undefined,
320
+ selected_skills: safeParseJsonArray(row.selected_skills_json),
321
+ token_estimate: typeof row.token_estimate === 'number' ? row.token_estimate : undefined,
322
+ latency_bucket: typeof row.latency_bucket === 'string' ? row.latency_bucket : undefined,
323
+ bus_snapshot: typeof row.bus_snapshot === 'string' ? row.bus_snapshot : undefined,
324
+ retro_summary: typeof row.retro_summary === 'string' ? row.retro_summary : undefined,
325
+ recommended_action: row.recommended_action,
326
+ confidence: typeof row.confidence === 'number' ? row.confidence : undefined,
327
+ skill_judgments: safeParseJsonArray(row.skill_judgments_json),
328
+ created_at: String(row.created_at),
329
+ };
330
+ }
331
+ function recordExecutionAnalysis(dbPath, analysis) {
332
+ var _a, _b;
333
+ const db = openDb(dbPath);
334
+ const now = analysis.created_at || new Date().toISOString();
335
+ const selectedSkills = JSON.stringify((_a = analysis.selected_skills) !== null && _a !== void 0 ? _a : []);
336
+ const skillJudgments = JSON.stringify((_b = analysis.skill_judgments) !== null && _b !== void 0 ? _b : []);
337
+ const insertAnalysis = db.prepare(`
338
+ INSERT OR REPLACE INTO execution_analyses
339
+ (id, task_title, status, summary, source_task_type, session_id, chain_id,
340
+ selected_skills_json, token_estimate, latency_bucket, bus_snapshot,
341
+ retro_summary, recommended_action, confidence, skill_judgments_json, created_at)
342
+ VALUES
343
+ (@id, @task_title, @status, @summary, @source_task_type, @session_id, @chain_id,
344
+ @selected_skills_json, @token_estimate, @latency_bucket, @bus_snapshot,
345
+ @retro_summary, @recommended_action, @confidence, @skill_judgments_json, @created_at)
346
+ `);
347
+ const upsertMetric = db.prepare(`
348
+ INSERT INTO skill_metrics
349
+ (skill, selections, applications, task_completions, fallbacks, total_token_estimate,
350
+ last_task_type, last_recommended_action, last_used_at, updated_at)
351
+ VALUES
352
+ (@skill, @selections, @applications, @task_completions, @fallbacks, @total_token_estimate,
353
+ @last_task_type, @last_recommended_action, @last_used_at, @updated_at)
354
+ ON CONFLICT(skill) DO UPDATE SET
355
+ selections = skill_metrics.selections + excluded.selections,
356
+ applications = skill_metrics.applications + excluded.applications,
357
+ task_completions = skill_metrics.task_completions + excluded.task_completions,
358
+ fallbacks = skill_metrics.fallbacks + excluded.fallbacks,
359
+ total_token_estimate = skill_metrics.total_token_estimate + excluded.total_token_estimate,
360
+ last_task_type = COALESCE(excluded.last_task_type, skill_metrics.last_task_type),
361
+ last_recommended_action = COALESCE(excluded.last_recommended_action, skill_metrics.last_recommended_action),
362
+ last_used_at = excluded.last_used_at,
363
+ updated_at = excluded.updated_at
364
+ `);
365
+ const txn = db.transaction(() => {
366
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
367
+ insertAnalysis.run({
368
+ id: analysis.id,
369
+ task_title: analysis.task_title,
370
+ status: analysis.status,
371
+ summary: analysis.summary,
372
+ source_task_type: (_a = analysis.source_task_type) !== null && _a !== void 0 ? _a : null,
373
+ session_id: (_b = analysis.session_id) !== null && _b !== void 0 ? _b : null,
374
+ chain_id: (_c = analysis.chain_id) !== null && _c !== void 0 ? _c : null,
375
+ selected_skills_json: selectedSkills,
376
+ token_estimate: (_d = analysis.token_estimate) !== null && _d !== void 0 ? _d : 0,
377
+ latency_bucket: (_e = analysis.latency_bucket) !== null && _e !== void 0 ? _e : null,
378
+ bus_snapshot: (_f = analysis.bus_snapshot) !== null && _f !== void 0 ? _f : null,
379
+ retro_summary: (_g = analysis.retro_summary) !== null && _g !== void 0 ? _g : null,
380
+ recommended_action: (_h = analysis.recommended_action) !== null && _h !== void 0 ? _h : null,
381
+ confidence: (_j = analysis.confidence) !== null && _j !== void 0 ? _j : null,
382
+ skill_judgments_json: skillJudgments,
383
+ created_at: now,
384
+ });
385
+ for (const judgment of (_k = analysis.skill_judgments) !== null && _k !== void 0 ? _k : []) {
386
+ const skill = (_l = judgment.skill) === null || _l === void 0 ? void 0 : _l.trim();
387
+ if (!skill)
388
+ continue;
389
+ upsertMetric.run({
390
+ skill,
391
+ selections: judgment.selected ? 1 : 0,
392
+ applications: judgment.applied ? 1 : 0,
393
+ task_completions: judgment.task_completed ? 1 : 0,
394
+ fallbacks: judgment.fallback_used ? 1 : 0,
395
+ total_token_estimate: (_m = judgment.token_estimate) !== null && _m !== void 0 ? _m : 0,
396
+ last_task_type: (_o = analysis.source_task_type) !== null && _o !== void 0 ? _o : null,
397
+ last_recommended_action: (_p = analysis.recommended_action) !== null && _p !== void 0 ? _p : null,
398
+ last_used_at: now,
399
+ updated_at: now,
400
+ });
401
+ }
402
+ });
403
+ txn();
404
+ }
405
+ function getExecutionAnalyses(dbPath, limit = 20) {
406
+ const db = openDb(dbPath);
407
+ const rows = db.prepare('SELECT * FROM execution_analyses ORDER BY created_at DESC LIMIT ?').all(limit);
408
+ return rows.map(rowToExecutionAnalysis);
409
+ }
410
+ function getSkillMetric(dbPath, skill) {
411
+ var _a;
412
+ const db = openDb(dbPath);
413
+ return (_a = db.prepare('SELECT * FROM skill_metrics WHERE skill = ?').get(skill)) !== null && _a !== void 0 ? _a : null;
414
+ }
415
+ function listSkillMetrics(dbPath, limit = 50) {
416
+ const db = openDb(dbPath);
417
+ return db.prepare('SELECT * FROM skill_metrics ORDER BY updated_at DESC LIMIT ?').all(limit);
418
+ }
262
419
  // ─── DB Path Helper ──────────────────────────────────────────────────────────
263
420
  function getDbPath(projectPath) {
264
421
  return path_1.default.join(projectPath, '.cm', 'context.db');
@@ -109,12 +109,8 @@ quality:
109
109
  anti_sycophancy: false # Enable anti-sycophancy check (Phase 2)
110
110
 
111
111
  storage:
112
- backend: sqlite # sqlite | viking
113
- # viking: # Uncomment to use OpenViking (pip install openviking)
114
- # host: localhost # OpenViking server host
115
- # port: 1933 # OpenViking server port (default: 1933)
116
- # workspace: codymaster # Workspace name inside OpenViking
117
- # timeout: 60000 # Request timeout in ms
112
+ backend: sqlite # supported default
113
+ # Legacy note: older configs may still say "viking"; CodyMaster now falls back to sqlite.
118
114
  `;
119
115
  }
120
116
  // ─── CONTINUITY.md Read/Write ───────────────────────────────────────────────
@@ -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
+ }
@@ -0,0 +1,138 @@
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.ExecutionAnalyzer = void 0;
7
+ exports.qualityWeight = qualityWeight;
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const context_bus_1 = require("./context-bus");
11
+ const storage_backend_1 = require("./storage-backend");
12
+ const retro_summary_1 = require("./retro-summary");
13
+ function bucketLatency(latencyMs) {
14
+ if (latencyMs === undefined || latencyMs < 0)
15
+ return undefined;
16
+ if (latencyMs < 1000)
17
+ return 'subsecond';
18
+ if (latencyMs < 5000)
19
+ return 'fast';
20
+ if (latencyMs < 15000)
21
+ return 'medium';
22
+ return 'slow';
23
+ }
24
+ function buildRetroSummary(projectPath, limit = 3) {
25
+ const retroPath = path_1.default.join(projectPath, '.cm', 'operational-learnings.jsonl');
26
+ const entries = (0, retro_summary_1.loadRetroEntries)(retroPath).slice(-limit);
27
+ if (entries.length === 0)
28
+ return undefined;
29
+ return entries.map((entry) => `- [${entry.tool}] ${entry.note}`).join('\n');
30
+ }
31
+ function normalizeJudgments(input) {
32
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
33
+ const map = new Map();
34
+ for (const skill of (_a = input.selectedSkills) !== null && _a !== void 0 ? _a : []) {
35
+ map.set(skill, {
36
+ skill,
37
+ selected: true,
38
+ applied: true,
39
+ task_completed: input.taskStatus === 'completed',
40
+ fallback_used: false,
41
+ });
42
+ }
43
+ for (const observation of (_b = input.skillObservations) !== null && _b !== void 0 ? _b : []) {
44
+ const current = (_c = map.get(observation.skill)) !== null && _c !== void 0 ? _c : { skill: observation.skill };
45
+ map.set(observation.skill, {
46
+ skill: observation.skill,
47
+ selected: (_e = (_d = observation.selected) !== null && _d !== void 0 ? _d : current.selected) !== null && _e !== void 0 ? _e : false,
48
+ applied: (_g = (_f = observation.applied) !== null && _f !== void 0 ? _f : current.applied) !== null && _g !== void 0 ? _g : ((_j = (_h = observation.selected) !== null && _h !== void 0 ? _h : current.selected) !== null && _j !== void 0 ? _j : false),
49
+ task_completed: input.taskStatus === 'completed',
50
+ fallback_used: (_l = (_k = observation.fallbackUsed) !== null && _k !== void 0 ? _k : current.fallback_used) !== null && _l !== void 0 ? _l : false,
51
+ token_estimate: (_m = observation.tokenEstimate) !== null && _m !== void 0 ? _m : current.token_estimate,
52
+ note: (_o = observation.note) !== null && _o !== void 0 ? _o : current.note,
53
+ relevance_score: (_p = observation.relevanceScore) !== null && _p !== void 0 ? _p : current.relevance_score,
54
+ });
55
+ }
56
+ return Array.from(map.values());
57
+ }
58
+ function qualityWeight(metric) {
59
+ if (!metric)
60
+ return 0.5;
61
+ const base = Math.max(metric.selections, 1);
62
+ const applicationRate = metric.applications / base;
63
+ const completionRate = metric.task_completions / base;
64
+ const fallbackPenalty = metric.fallbacks / base;
65
+ const weighted = (applicationRate * 0.35) + (completionRate * 0.5) + ((1 - fallbackPenalty) * 0.15);
66
+ return Math.max(0, Math.min(1, weighted));
67
+ }
68
+ function buildAdvisory(taskStatus, judgments, backend) {
69
+ const activeSkills = judgments.filter((judgment) => judgment.selected || judgment.applied).map((judgment) => judgment.skill);
70
+ const fallbackSkills = judgments.filter((judgment) => judgment.fallback_used).map((judgment) => judgment.skill);
71
+ if (taskStatus !== 'completed' && activeSkills.length > 0) {
72
+ const weakest = activeSkills
73
+ .map((skill) => ({ skill, weight: qualityWeight(backend.getSkillMetric(skill)) }))
74
+ .sort((a, b) => a.weight - b.weight)[0];
75
+ const targetSkills = weakest ? [weakest.skill] : activeSkills.slice(0, 1);
76
+ return {
77
+ action: 'FIX',
78
+ confidence: weakest ? Math.max(0.68, 0.82 - weakest.weight * 0.2) : 0.72,
79
+ reason: 'Task did not complete successfully while selected skills were active.',
80
+ targetSkills,
81
+ };
82
+ }
83
+ if (taskStatus === 'completed' && activeSkills.length === 0) {
84
+ return {
85
+ action: 'CAPTURED',
86
+ confidence: 0.76,
87
+ reason: 'Task completed without any tracked skill usage, suggesting a reusable pattern worth capturing.',
88
+ targetSkills: [],
89
+ };
90
+ }
91
+ if (taskStatus === 'completed' && fallbackSkills.length > 0) {
92
+ return {
93
+ action: 'DERIVED',
94
+ confidence: 0.74,
95
+ reason: 'Task completed, but fallback handling suggests the current skill may need a specialized derived variant.',
96
+ targetSkills: fallbackSkills,
97
+ };
98
+ }
99
+ return {
100
+ reason: 'No evolution action recommended from the current execution signal.',
101
+ targetSkills: [],
102
+ };
103
+ }
104
+ class ExecutionAnalyzer {
105
+ constructor(projectPath, backend) {
106
+ this.projectPath = projectPath;
107
+ this.backend = backend !== null && backend !== void 0 ? backend : (0, storage_backend_1.getBackend)(projectPath);
108
+ this.backend.initialize();
109
+ }
110
+ analyzeExecution(input) {
111
+ var _a, _b, _c;
112
+ const judgments = normalizeJudgments(input);
113
+ const bus = (0, context_bus_1.readBus)(this.projectPath);
114
+ const retroSummary = buildRetroSummary(this.projectPath);
115
+ const advisory = buildAdvisory(input.taskStatus, judgments, this.backend);
116
+ const analysis = {
117
+ id: crypto_1.default.randomUUID(),
118
+ task_title: input.taskTitle,
119
+ status: input.taskStatus,
120
+ summary: (_a = input.summary) !== null && _a !== void 0 ? _a : `${input.taskStatus.toUpperCase()}: ${input.taskTitle}`,
121
+ source_task_type: input.sourceTaskType,
122
+ session_id: (_b = input.sessionId) !== null && _b !== void 0 ? _b : bus === null || bus === void 0 ? void 0 : bus.session_id,
123
+ chain_id: input.chainId,
124
+ selected_skills: (_c = input.selectedSkills) !== null && _c !== void 0 ? _c : judgments.filter((judgment) => judgment.selected).map((judgment) => judgment.skill),
125
+ token_estimate: input.tokenEstimate,
126
+ latency_bucket: bucketLatency(input.latencyMs),
127
+ bus_snapshot: bus ? JSON.stringify(bus.shared_context) : undefined,
128
+ retro_summary: retroSummary,
129
+ recommended_action: advisory.action,
130
+ confidence: advisory.confidence,
131
+ skill_judgments: judgments,
132
+ created_at: new Date().toISOString(),
133
+ };
134
+ this.backend.recordExecutionAnalysis(analysis);
135
+ return analysis;
136
+ }
137
+ }
138
+ exports.ExecutionAnalyzer = ExecutionAnalyzer;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Runtime safety patterns for `cm guardian` (careful / freeze / guard style).
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.checkShellCommand = checkShellCommand;
10
+ exports.normalizeRoots = normalizeRoots;
11
+ exports.isPathUnderRoots = isPathUnderRoots;
12
+ exports.appendGuardianLog = appendGuardianLog;
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const DESTRUCTIVE_PATTERNS = [
16
+ /\brm\s+(-[rfFR]+\s*)+.*(\/\s*$|\/\*|\s\/\s)/,
17
+ /\brm\s+-rf\b/i,
18
+ /\bmkfs\./,
19
+ /\bdd\s+if=/,
20
+ />\s*\/dev\/sd/,
21
+ /\bDROP\s+DATABASE\b/i,
22
+ /\bDROP\s+TABLE\b/i,
23
+ /\bTRUNCATE\s+TABLE\b/i,
24
+ /\bgit\s+push\s+.*--force/i,
25
+ /\bgit\s+push\s+-f\b/,
26
+ /\bgit\s+reset\s+--hard\b/,
27
+ /\bgit\s+clean\s+-fdx\b/,
28
+ /\bcurl\s+.*\|\s*(ba)?sh\b/i,
29
+ /\bwget\s+.*\|\s*(ba)?sh\b/i,
30
+ /\bmysqladmin\s+drop\b/i,
31
+ /\bredis-cli\s+.*FLUSHALL/i,
32
+ ];
33
+ const DEFAULT_WHITELIST_PREFIXES = ['npm run build', 'npm test', 'npm run test', 'npx vitest'];
34
+ function checkShellCommand(cmd, options) {
35
+ var _a;
36
+ const trimmed = cmd.trim();
37
+ if (!trimmed)
38
+ return { safe: true };
39
+ const whitelist = [...DEFAULT_WHITELIST_PREFIXES, ...((_a = options === null || options === void 0 ? void 0 : options.extraWhitelist) !== null && _a !== void 0 ? _a : [])];
40
+ for (const w of whitelist) {
41
+ if (trimmed.startsWith(w))
42
+ return { safe: true };
43
+ }
44
+ for (const re of DESTRUCTIVE_PATTERNS) {
45
+ if (re.test(trimmed)) {
46
+ return {
47
+ safe: false,
48
+ reason: 'Command matches a destructive pattern. Confirm intent or use a safer alternative.',
49
+ matchedPattern: re.source,
50
+ };
51
+ }
52
+ }
53
+ return { safe: true };
54
+ }
55
+ function normalizeRoots(cwd, roots) {
56
+ return roots.map((r) => path_1.default.resolve(cwd, r));
57
+ }
58
+ /** Returns true if `targetPath` is under one of `roots` (after resolve). */
59
+ function isPathUnderRoots(targetPath, roots) {
60
+ const abs = path_1.default.resolve(targetPath);
61
+ for (const root of roots) {
62
+ const r = path_1.default.resolve(root);
63
+ if (abs === r || abs.startsWith(r + path_1.default.sep))
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ function appendGuardianLog(projectPath, line) {
69
+ const dir = path_1.default.join(projectPath, '.cm');
70
+ if (!fs_1.default.existsSync(dir))
71
+ fs_1.default.mkdirSync(dir, { recursive: true });
72
+ const logPath = path_1.default.join(dir, 'guardian.log');
73
+ fs_1.default.appendFileSync(logPath, `[${new Date().toISOString()}] ${line}\n`, 'utf8');
74
+ }