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