@holmes-lab/holmes-kit 0.1.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 +22 -0
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/bin/holmes-hook-antigravity.js +31 -0
- package/bin/holmes-kit.js +23 -0
- package/bin/holmes-mcp.js +34 -0
- package/bin/holmes-stop-antigravity.js +29 -0
- package/dist/.build-id +1 -0
- package/dist/holmes/cli/agents.js +168 -0
- package/dist/holmes/cli/doctor.js +625 -0
- package/dist/holmes/cli/gitignore-merge.js +84 -0
- package/dist/holmes/cli/governed-precondition.js +157 -0
- package/dist/holmes/cli/index.js +384 -0
- package/dist/holmes/cli/init.js +462 -0
- package/dist/holmes/cli/playbook-skills.js +711 -0
- package/dist/holmes/cli/roles-readme.js +134 -0
- package/dist/holmes/cli/settings-merge.js +122 -0
- package/dist/holmes/config/config.js +70 -0
- package/dist/holmes/context/bundler.js +114 -0
- package/dist/holmes/context/render.js +29 -0
- package/dist/holmes/context/tiers.js +110 -0
- package/dist/holmes/context/tokens.js +8 -0
- package/dist/holmes/cpg/cpg-scanner.js +213 -0
- package/dist/holmes/cpg/hash-cache.js +86 -0
- package/dist/holmes/cpg/language-parser-walk.js +917 -0
- package/dist/holmes/cpg/language-parser-worker.js +81 -0
- package/dist/holmes/cpg/language-parser.js +234 -0
- package/dist/holmes/cpg/scan-cache.js +108 -0
- package/dist/holmes/cpg/source-path.js +44 -0
- package/dist/holmes/cpg/test-files.js +84 -0
- package/dist/holmes/governance/constitution-debt.js +73 -0
- package/dist/holmes/governance/constitution-report.js +25 -0
- package/dist/holmes/governance/constitution.js +129 -0
- package/dist/holmes/governance/identity.js +30 -0
- package/dist/holmes/governance/ledger-lock.js +165 -0
- package/dist/holmes/governance/ledger-store.conformance.js +90 -0
- package/dist/holmes/governance/ledger-store.js +106 -0
- package/dist/holmes/governance/progress-ledger.js +83 -0
- package/dist/holmes/governance/provenance-chain.js +365 -0
- package/dist/holmes/governance/provenance-ledger.js +0 -0
- package/dist/holmes/governance/provenance-schema.js +47 -0
- package/dist/holmes/governance/replica-id.js +106 -0
- package/dist/holmes/governance/role-policy.js +137 -0
- package/dist/holmes/governance/trust-score.js +43 -0
- package/dist/holmes/guardrail/anchors.js +31 -0
- package/dist/holmes/guardrail/blind-spots.js +38 -0
- package/dist/holmes/guardrail/decision-ledger.js +107 -0
- package/dist/holmes/guardrail/executable-artifact.js +129 -0
- package/dist/holmes/guardrail/governance-history.js +101 -0
- package/dist/holmes/guardrail/phase.js +169 -0
- package/dist/holmes/guardrail/risk-classifier.js +450 -0
- package/dist/holmes/guardrail/risk-gate.js +160 -0
- package/dist/holmes/guardrail/risk-types.js +6 -0
- package/dist/holmes/guardrail/tspec-state.js +392 -0
- package/dist/holmes/guardrail/write-target.js +224 -0
- package/dist/holmes/hooks/adapters/antigravity.js +194 -0
- package/dist/holmes/hooks/pre-tool-use.js +1262 -0
- package/dist/holmes/hooks/stop.js +416 -0
- package/dist/holmes/mcp/basis.js +162 -0
- package/dist/holmes/mcp/handlers.js +1831 -0
- package/dist/holmes/mcp/server.js +71 -0
- package/dist/holmes/mcp/stdio-client.js +165 -0
- package/dist/holmes/mcp/supervisor.js +178 -0
- package/dist/holmes/mcp/tool-schemas.js +394 -0
- package/dist/holmes/mcp/validate-args.js +281 -0
- package/dist/holmes/messages/registry.js +50 -0
- package/dist/holmes/project/baseline.js +210 -0
- package/dist/holmes/project/change-source.js +233 -0
- package/dist/holmes/project/ignore.js +145 -0
- package/dist/holmes/project/root.js +113 -0
- package/dist/holmes/reverse/anchor.js +162 -0
- package/dist/holmes/reverse/cluster.js +187 -0
- package/dist/holmes/reverse/draft.js +151 -0
- package/dist/holmes/reverse/dynamic-wiring.js +47 -0
- package/dist/holmes/reverse/scan.js +194 -0
- package/dist/holmes/reverse/surface.js +154 -0
- package/dist/holmes/reverse/test-map.js +263 -0
- package/dist/holmes/review/coverage.js +33 -0
- package/dist/holmes/review/findings.js +123 -0
- package/dist/holmes/review/package.js +40 -0
- package/dist/holmes/review/review-targets.js +92 -0
- package/dist/holmes/review/scope.js +57 -0
- package/dist/holmes/review/test-evidence.js +77 -0
- package/dist/holmes/review/test-runner.js +572 -0
- package/dist/holmes/rtm/dataflow-taint.js +262 -0
- package/dist/holmes/rtm/gap-analyzer.js +27 -0
- package/dist/holmes/rtm/git-changes.js +72 -0
- package/dist/holmes/rtm/incremental.js +45 -0
- package/dist/holmes/rtm/localize.js +100 -0
- package/dist/holmes/rtm/rtm-builder.js +191 -0
- package/dist/holmes/rtm/rtm-check.js +89 -0
- package/dist/holmes/rtm/rtm-graph.js +232 -0
- package/dist/holmes/rtm/taint.js +92 -0
- package/dist/holmes/rtm/test-scope.js +336 -0
- package/dist/holmes/spec/approval-blockers.js +204 -0
- package/dist/holmes/spec/breaking-change.js +89 -0
- package/dist/holmes/spec/legacy-format.js +87 -0
- package/dist/holmes/spec/spec-digest.js +71 -0
- package/dist/holmes/spec/spec-parser.js +106 -0
- package/dist/holmes/spec/spec-store.conformance.js +118 -0
- package/dist/holmes/spec/spec-store.js +331 -0
- package/dist/holmes/spec/spec-types.js +177 -0
- package/dist/holmes/spec/validator.js +280 -0
- package/package.json +76 -0
- package/playbooks/adopt/PLAYBOOK.md +125 -0
- package/playbooks/author-slice/PLAYBOOK.md +119 -0
- package/playbooks/promote-slice/PLAYBOOK.md +134 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readReviewNeeded = readReviewNeeded;
|
|
37
|
+
exports.anchoredForReview = anchoredForReview;
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
/**
|
|
40
|
+
* Read the outstanding `review-needed` signals off the provenance chain. P4 does not auto-clear, so
|
|
41
|
+
* every recorded signal is currently "outstanding" — the surface lists them so a reviewer knows what
|
|
42
|
+
* moved and which files to examine. A missing/unreadable chain → [] (nothing to route), never a throw.
|
|
43
|
+
*/
|
|
44
|
+
function readReviewNeeded(ledgerFile) {
|
|
45
|
+
// @implements A-SPEC-148
|
|
46
|
+
// Reads EVERY replica chain. Bound to the legacy filename this returned nothing once writes moved
|
|
47
|
+
// to the per-replica chain — a routing signal that silently stops arriving is worse than one that
|
|
48
|
+
// never existed, because the absence looks like "no review needed".
|
|
49
|
+
let events;
|
|
50
|
+
try {
|
|
51
|
+
const { FileLedgerStore } = require('../governance/ledger-store');
|
|
52
|
+
events = new FileLedgerStore(path.dirname(ledgerFile)).loadAll();
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const out = [];
|
|
58
|
+
for (const evt of events) {
|
|
59
|
+
if (evt.kind === 'review-needed' && Array.isArray(evt.inputs) && evt.inputs.length >= 3) {
|
|
60
|
+
const [spec, from, to, ...files] = evt.inputs;
|
|
61
|
+
out.push({ spec, from, to, files });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The deterministic set of source files a targeted adversarial review must re-examine when a spec's
|
|
68
|
+
* approved content MOVES (P4). This is a ROUTING computation, not a verdict: it names WHERE to look,
|
|
69
|
+
* never whether the code is right — that judgment stays with the review layer / a human, which is the
|
|
70
|
+
* whole point of P4 (the decision layer checks form/existence/execution, never meaning).
|
|
71
|
+
*
|
|
72
|
+
* - An A-SPEC's targets are the source files whose scanned `@implements` names it (its direct anchors).
|
|
73
|
+
* - A REQ's or H-SPEC's targets are the union of its APPROVED direct A-SPEC children's anchors (one
|
|
74
|
+
* hop): a moved parent implicates the code under the approved slices beneath it.
|
|
75
|
+
*
|
|
76
|
+
* Pure, deduped, path-sorted — same (spec, anchor graph) → same set.
|
|
77
|
+
*/
|
|
78
|
+
function anchoredForReview(specId, scanned, specs) {
|
|
79
|
+
const self = specs.find((s) => s.id === specId);
|
|
80
|
+
const collectDirect = (aspecId) => scanned.filter((f) => f.implementsSpecs.includes(aspecId)).map((f) => f.sourcePath);
|
|
81
|
+
let files;
|
|
82
|
+
if (self && (self.type === 'REQ' || self.type === 'H-SPEC')) {
|
|
83
|
+
// one hop: approved direct A-SPEC children
|
|
84
|
+
const children = specs.filter((s) => s.type === 'A-SPEC' && s.status === 'approved' && s.dependsOn.includes(specId));
|
|
85
|
+
files = children.flatMap((c) => collectDirect(c.id));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// A-SPEC (or an unknown id): its own direct anchors
|
|
89
|
+
files = collectDirect(specId);
|
|
90
|
+
}
|
|
91
|
+
return [...new Set(files)].sort();
|
|
92
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeReviewScope = computeReviewScope;
|
|
4
|
+
const rtm_builder_1 = require("../rtm/rtm-builder");
|
|
5
|
+
const ACCEPTANCE_SECTION_BY_TYPE = {
|
|
6
|
+
'A-SPEC': 'Done When',
|
|
7
|
+
'H-SPEC': 'Acceptance Criteria',
|
|
8
|
+
REQ: 'Success Criteria',
|
|
9
|
+
};
|
|
10
|
+
function stripSpecPrefix(specNodeId) {
|
|
11
|
+
return specNodeId.startsWith('SPEC:') ? specNodeId.slice('SPEC:'.length) : specNodeId;
|
|
12
|
+
}
|
|
13
|
+
// @implements A-SPEC-102.1
|
|
14
|
+
function computeReviewScope(graph, specs, changedSymbols) {
|
|
15
|
+
const specById = new Map();
|
|
16
|
+
for (const s of specs) {
|
|
17
|
+
specById.set(s.id, s);
|
|
18
|
+
}
|
|
19
|
+
const dedupedChangedSymbols = [...new Set(changedSymbols)].sort();
|
|
20
|
+
const impactedSpecs = [...new Set((0, rtm_builder_1.impactedBy)(graph, dedupedChangedSymbols))].sort();
|
|
21
|
+
const acceptanceCriteria = [];
|
|
22
|
+
for (const specNodeId of impactedSpecs) {
|
|
23
|
+
const specId = stripSpecPrefix(specNodeId);
|
|
24
|
+
const spec = specById.get(specId);
|
|
25
|
+
if (!spec)
|
|
26
|
+
continue;
|
|
27
|
+
const sectionName = ACCEPTANCE_SECTION_BY_TYPE[spec.type];
|
|
28
|
+
if (!sectionName)
|
|
29
|
+
continue;
|
|
30
|
+
const criteria = spec.sections[sectionName];
|
|
31
|
+
if (!criteria)
|
|
32
|
+
continue;
|
|
33
|
+
acceptanceCriteria.push({ specId, criteria });
|
|
34
|
+
}
|
|
35
|
+
acceptanceCriteria.sort((a, b) => (a.specId < b.specId ? -1 : a.specId > b.specId ? 1 : 0));
|
|
36
|
+
const unrequestedSymbols = dedupedChangedSymbols
|
|
37
|
+
.filter((qn) => !(0, rtm_builder_1.impactedBy)(graph, [qn]).some((id) => id.startsWith('SPEC:')))
|
|
38
|
+
.sort();
|
|
39
|
+
const coverageGaps = [];
|
|
40
|
+
for (const specNodeId of impactedSpecs) {
|
|
41
|
+
if (!specNodeId.startsWith('SPEC:A-SPEC-'))
|
|
42
|
+
continue;
|
|
43
|
+
const aSpecId = stripSpecPrefix(specNodeId);
|
|
44
|
+
const hasTSpecChild = specs.some((s) => s.type === 'T-SPEC' && s.dependsOn.includes(aSpecId));
|
|
45
|
+
if (!hasTSpecChild) {
|
|
46
|
+
coverageGaps.push(aSpecId);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
coverageGaps.sort();
|
|
50
|
+
return {
|
|
51
|
+
changedSymbols: dedupedChangedSymbols,
|
|
52
|
+
impactedSpecs,
|
|
53
|
+
acceptanceCriteria,
|
|
54
|
+
unrequestedSymbols,
|
|
55
|
+
coverageGaps,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EVIDENCE_FILE = void 0;
|
|
37
|
+
exports.computeExecutedByAspec = computeExecutedByAspec;
|
|
38
|
+
exports.isFresh = isFresh;
|
|
39
|
+
exports.writeTestEvidence = writeTestEvidence;
|
|
40
|
+
exports.readTestEvidence = readTestEvidence;
|
|
41
|
+
// @implements A-SPEC-102.1
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
/** Map per-test-file executed counts onto the A-SPECs those files @implement (pure). */
|
|
45
|
+
function computeExecutedByAspec(executedByFile, testAnchors) {
|
|
46
|
+
const out = {};
|
|
47
|
+
for (const [file, n] of Object.entries(executedByFile)) {
|
|
48
|
+
for (const id of testAnchors[file] ?? [])
|
|
49
|
+
out[id] = (out[id] ?? 0) + n;
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
/** Evidence is usable only for the exact commit it was produced at (pure). */
|
|
54
|
+
function isFresh(ev, currentHead) {
|
|
55
|
+
return !!ev && !!ev.head && ev.head === currentHead;
|
|
56
|
+
}
|
|
57
|
+
exports.EVIDENCE_FILE = path.join('.ax', 'ledger', 'test-evidence.json');
|
|
58
|
+
function writeTestEvidence(root, ev) {
|
|
59
|
+
try {
|
|
60
|
+
const file = path.join(root, exports.EVIDENCE_FILE);
|
|
61
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
62
|
+
fs.writeFileSync(file, JSON.stringify(ev, null, 2), 'utf8');
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
} // evidence recording must never break a run
|
|
68
|
+
}
|
|
69
|
+
function readTestEvidence(root) {
|
|
70
|
+
try {
|
|
71
|
+
const ev = JSON.parse(fs.readFileSync(path.join(root, exports.EVIDENCE_FILE), 'utf8'));
|
|
72
|
+
return ev && typeof ev.head === 'string' && ev.executedByAspec && typeof ev.executedByAspec === 'object' ? ev : undefined;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|