@reposkein/mcp 0.2.7 → 0.4.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/README.md +73 -1
- package/binary-digests.json +4 -4
- package/dist/SKILL.md +63 -1
- package/dist/cli/adr.d.ts +37 -0
- package/dist/cli/adr.js +231 -0
- package/dist/cli/adr.js.map +1 -0
- package/dist/cli/agentAdapters.d.ts +68 -0
- package/dist/cli/agentAdapters.js +223 -0
- package/dist/cli/agentAdapters.js.map +1 -0
- package/dist/cli/ansi.d.ts +24 -0
- package/dist/cli/ansi.js +40 -0
- package/dist/cli/ansi.js.map +1 -0
- package/dist/cli/doctor.d.ts +34 -2
- package/dist/cli/doctor.js +53 -5
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/doctorDecisions.d.ts +5 -0
- package/dist/cli/doctorDecisions.js +83 -0
- package/dist/cli/doctorDecisions.js.map +1 -0
- package/dist/cli/doctorFreshness.d.ts +43 -0
- package/dist/cli/doctorFreshness.js +111 -0
- package/dist/cli/doctorFreshness.js.map +1 -0
- package/dist/cli/doctorSummaries.d.ts +2 -0
- package/dist/cli/doctorSummaries.js +95 -0
- package/dist/cli/doctorSummaries.js.map +1 -0
- package/dist/cli/federatedDiscovery.d.ts +16 -0
- package/dist/cli/federatedDiscovery.js +75 -0
- package/dist/cli/federatedDiscovery.js.map +1 -0
- package/dist/cli/init.d.ts +69 -6
- package/dist/cli/init.js +194 -28
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/sourceSlices.d.ts +17 -0
- package/dist/cli/sourceSlices.js +59 -0
- package/dist/cli/sourceSlices.js.map +1 -0
- package/dist/cli/stats.d.ts +29 -0
- package/dist/cli/stats.js +180 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/view.d.ts +71 -3
- package/dist/cli/view.js +147 -12
- package/dist/cli/view.js.map +1 -1
- package/dist/guard/decisionValidation.d.ts +29 -0
- package/dist/guard/decisionValidation.js +51 -0
- package/dist/guard/decisionValidation.js.map +1 -0
- package/dist/guard/summaryValidation.d.ts +3 -0
- package/dist/guard/summaryValidation.js +5 -3
- package/dist/guard/summaryValidation.js.map +1 -1
- package/dist/index.d.ts +48 -0
- package/dist/index.js +355 -78
- package/dist/index.js.map +1 -1
- package/dist/indexer/decisionsAffected.d.ts +42 -0
- package/dist/indexer/decisionsAffected.js +149 -0
- package/dist/indexer/decisionsAffected.js.map +1 -0
- package/dist/indexer/fetchBinary.d.ts +14 -0
- package/dist/indexer/fetchBinary.js +81 -40
- package/dist/indexer/fetchBinary.js.map +1 -1
- package/dist/indexer/runIndexer.d.ts +3 -2
- package/dist/indexer/runIndexer.js +8 -4
- package/dist/indexer/runIndexer.js.map +1 -1
- package/dist/profile/decisions.d.ts +37 -0
- package/dist/profile/decisions.js +112 -0
- package/dist/profile/decisions.js.map +1 -0
- package/dist/profile/types.d.ts +8 -0
- package/dist/store/GraphStore.d.ts +5 -0
- package/dist/store/JsonlGraphStore.d.ts +14 -3
- package/dist/store/JsonlGraphStore.js +66 -19
- package/dist/store/JsonlGraphStore.js.map +1 -1
- package/dist/store/decisions.d.ts +131 -0
- package/dist/store/decisions.js +321 -0
- package/dist/store/decisions.js.map +1 -0
- package/dist/store/indexedAt.d.ts +18 -0
- package/dist/store/indexedAt.js +56 -0
- package/dist/store/indexedAt.js.map +1 -0
- package/dist/store/instrumentTool.d.ts +40 -0
- package/dist/store/instrumentTool.js +82 -0
- package/dist/store/instrumentTool.js.map +1 -0
- package/dist/store/repoContextCache.d.ts +15 -0
- package/dist/store/repoContextCache.js +26 -0
- package/dist/store/repoContextCache.js.map +1 -0
- package/dist/store/repoSession.d.ts +63 -0
- package/dist/store/repoSession.js +123 -0
- package/dist/store/repoSession.js.map +1 -0
- package/dist/store/resolveRepoPath.d.ts +31 -0
- package/dist/store/resolveRepoPath.js +85 -0
- package/dist/store/resolveRepoPath.js.map +1 -0
- package/dist/store/sessionLog.d.ts +98 -0
- package/dist/store/sessionLog.js +216 -0
- package/dist/store/sessionLog.js.map +1 -0
- package/dist/store/sessionStats.d.ts +55 -0
- package/dist/store/sessionStats.js +140 -0
- package/dist/store/sessionStats.js.map +1 -0
- package/dist/store/sidecar.d.ts +39 -3
- package/dist/store/sidecar.js +89 -5
- package/dist/store/sidecar.js.map +1 -1
- package/dist/store/summaryShards.d.ts +117 -0
- package/dist/store/summaryShards.js +291 -0
- package/dist/store/summaryShards.js.map +1 -0
- package/dist/store/teamConfig.d.ts +13 -0
- package/dist/store/teamConfig.js +49 -0
- package/dist/store/teamConfig.js.map +1 -0
- package/dist/tools/getContextProfile.d.ts +1 -1
- package/dist/tools/getContextProfile.js +9 -1
- package/dist/tools/getContextProfile.js.map +1 -1
- package/dist/tools/getDecision.d.ts +6 -0
- package/dist/tools/getDecision.js +59 -0
- package/dist/tools/getDecision.js.map +1 -0
- package/dist/tools/impact.d.ts +1 -1
- package/dist/tools/impact.js +13 -1
- package/dist/tools/impact.js.map +1 -1
- package/dist/tools/indexerTools.d.ts +16 -2
- package/dist/tools/indexerTools.js +44 -5
- package/dist/tools/indexerTools.js.map +1 -1
- package/dist/tools/listDecisions.d.ts +19 -0
- package/dist/tools/listDecisions.js +93 -0
- package/dist/tools/listDecisions.js.map +1 -0
- package/dist/tools/reaffirmDecision.d.ts +11 -0
- package/dist/tools/reaffirmDecision.js +55 -0
- package/dist/tools/reaffirmDecision.js.map +1 -0
- package/dist/tools/recordDecision.d.ts +24 -0
- package/dist/tools/recordDecision.js +135 -0
- package/dist/tools/recordDecision.js.map +1 -0
- package/dist/tools/semanticFind.d.ts +9 -2
- package/dist/tools/semanticFind.js +44 -2
- package/dist/tools/semanticFind.js.map +1 -1
- package/dist/tools/setDecisionStatus.d.ts +8 -0
- package/dist/tools/setDecisionStatus.js +34 -0
- package/dist/tools/setDecisionStatus.js.map +1 -0
- package/dist/viz/assets/{graph.worker-CC7BeE-8.js → graph.worker-DkH6-lMU.js} +1 -1
- package/dist/viz/assets/index-CxqeGuRS.css +1 -0
- package/dist/viz/assets/index-DiNZyrXx.js +9 -0
- package/dist/viz/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/viz/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/dist/viz/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
- package/dist/viz/assets/r3f-BZY3QR6_.js +336 -0
- package/dist/viz/assets/tanstack-CjXr-L-s.js +62 -0
- package/dist/viz/assets/three-Cpu5RUEM.js +4116 -0
- package/dist/viz/index.html +5 -4
- package/package.json +5 -4
- package/dist/viz/assets/index-C_8UkiJ8.js +0 -9
- package/dist/viz/assets/r3f-Cku1OhB-.js +0 -277
- package/dist/viz/assets/tanstack-DyXcNRWk.js +0 -77
- package/dist/viz/assets/three-Z8XaLGmf.js +0 -3839
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { spawnIndexer, parseJsonStats,
|
|
1
|
+
import { spawnIndexer, parseJsonStats, shouldLoadNeo4j, } from "../indexer/runIndexer.js";
|
|
2
2
|
import { ensureIndexerBinary } from "../indexer/fetchBinary.js";
|
|
3
|
+
import { decisionsAffectedBy, mergeDeltas, readPendingDelta, } from "../indexer/decisionsAffected.js";
|
|
3
4
|
/** Default runner: run the index/reindex verb with --json, then load into Neo4j
|
|
4
5
|
* unless we're in JSONL mode (shouldLoadNeo4j() === false). */
|
|
5
6
|
function defaultRun(repoId, indexPath, opts) {
|
|
@@ -26,17 +27,47 @@ function defaultRun(repoId, indexPath, opts) {
|
|
|
26
27
|
edges: stats.edges,
|
|
27
28
|
files: stats.files,
|
|
28
29
|
warnings: stats.warnings ?? [],
|
|
30
|
+
...(stats.graph_delta ? { graph_delta: stats.graph_delta } : {}),
|
|
29
31
|
};
|
|
30
32
|
})();
|
|
31
33
|
}
|
|
34
|
+
/** Combines this run's delta with the pending one hook-driven indexes parked
|
|
35
|
+
* (their stdout is discarded — post-merge drift would otherwise vanish), and
|
|
36
|
+
* cross-references the decision log. `root` MUST be the repo that was
|
|
37
|
+
* actually indexed: consulting the env repo's decisions (or consuming its
|
|
38
|
+
* pending delta) while indexing some other path would cross the streams.
|
|
39
|
+
* Returns {} when there is no drift. */
|
|
40
|
+
function driftFields(root, repoId, runDelta) {
|
|
41
|
+
const pending = readPendingDelta(root);
|
|
42
|
+
let delta = runDelta ?? null;
|
|
43
|
+
if (pending)
|
|
44
|
+
delta = delta ? mergeDeltas(delta, pending) : pending;
|
|
45
|
+
if (!delta)
|
|
46
|
+
return {};
|
|
47
|
+
const affected = decisionsAffectedBy(root, delta, repoId);
|
|
48
|
+
return {
|
|
49
|
+
graph_delta: delta,
|
|
50
|
+
...(affected.length > 0 ? { decisions_affected: affected } : {}),
|
|
51
|
+
// A truncated delta dropped ids past the cap, so an empty/short
|
|
52
|
+
// decisions_affected is NOT proof of no drift — say so instead of
|
|
53
|
+
// reading as "checked everything".
|
|
54
|
+
...(delta.truncated ? { decisions_check_incomplete: true } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
32
57
|
function makeRunner(repoId, deps) {
|
|
33
58
|
const run = deps?.run ?? ((id, path, opts) => defaultRun(id, path, opts));
|
|
34
59
|
return run;
|
|
35
60
|
}
|
|
36
|
-
|
|
61
|
+
/** `path` (the repo to index) MUST come from the caller's already-resolved
|
|
62
|
+
* active repo (mcp/src/store/repoSession.ts), not re-derived here — this
|
|
63
|
+
* tool used to default to REPOSKEIN_REPO_PATH/cwd internally via
|
|
64
|
+
* runIndexer.js's `repoPath()`, which bypassed session.select_repo entirely
|
|
65
|
+
* and could index the wrong repo in workspace mode. Args-supplied `path`
|
|
66
|
+
* still wins, matching the original "explicit arg beats everything" rule. */
|
|
67
|
+
export function makeInitCpgSkeleton(repoId, repoPath, deps) {
|
|
37
68
|
const run = makeRunner(repoId, deps);
|
|
38
69
|
return async (args) => {
|
|
39
|
-
const indexPath = args?.path ?? repoPath
|
|
70
|
+
const indexPath = args?.path ?? repoPath;
|
|
40
71
|
const start = Date.now();
|
|
41
72
|
const r = await run(repoId, indexPath);
|
|
42
73
|
if (!r.ok) {
|
|
@@ -52,18 +83,25 @@ export function makeInitCpgSkeleton(repoId, deps) {
|
|
|
52
83
|
files: r.files,
|
|
53
84
|
duration_ms: Date.now() - start,
|
|
54
85
|
warnings: r.warnings,
|
|
86
|
+
...driftFields(indexPath, repoId, r.graph_delta),
|
|
55
87
|
}),
|
|
56
88
|
}],
|
|
57
89
|
};
|
|
58
90
|
};
|
|
59
91
|
}
|
|
60
|
-
|
|
92
|
+
/** `path` has no override — `reindex_file`'s args only carry the file being
|
|
93
|
+
* reindexed, not a repo root — so this ALWAYS targets the caller's resolved
|
|
94
|
+
* active repo. Same reasoning as `makeInitCpgSkeleton` above: previously
|
|
95
|
+
* this read REPOSKEIN_REPO_PATH/cwd internally, independent of
|
|
96
|
+
* session.select_repo — the exact "reindex the wrong repo" bug class this
|
|
97
|
+
* parameter exists to close. */
|
|
98
|
+
export function makeReindexFile(repoId, repoPath, deps) {
|
|
61
99
|
const run = makeRunner(repoId, deps);
|
|
62
100
|
return async (args) => {
|
|
63
101
|
if (!args || !args.path) {
|
|
64
102
|
return { content: [{ type: "text", text: "reindex_file requires a 'path'" }], isError: true };
|
|
65
103
|
}
|
|
66
|
-
const indexPath = repoPath
|
|
104
|
+
const indexPath = repoPath;
|
|
67
105
|
const start = Date.now();
|
|
68
106
|
const r = await run(repoId, indexPath, { verb: "reindex", file: args.path });
|
|
69
107
|
if (!r.ok) {
|
|
@@ -81,6 +119,7 @@ export function makeReindexFile(repoId, deps) {
|
|
|
81
119
|
duration_ms: Date.now() - start,
|
|
82
120
|
loaded: shouldLoadNeo4j(),
|
|
83
121
|
warnings: r.warnings,
|
|
122
|
+
...driftFields(indexPath, repoId, r.graph_delta),
|
|
84
123
|
}),
|
|
85
124
|
}],
|
|
86
125
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexerTools.js","sourceRoot":"","sources":["../../src/tools/indexerTools.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"indexerTools.js","sourceRoot":"","sources":["../../src/tools/indexerTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { GraphStore } from "../store/GraphStore.js";
|
|
2
|
+
import type { ToolResult } from "./readCypher.js";
|
|
3
|
+
import { type DecisionRecord, type DecisionStatus } from "../store/decisions.js";
|
|
4
|
+
export interface ListDecisionsArgs {
|
|
5
|
+
status?: DecisionStatus;
|
|
6
|
+
/** A node_id (matched against anchors) or a file path (matched against
|
|
7
|
+
* anchor paths and decision path prefixes). Disambiguation: anything
|
|
8
|
+
* starting "rs1:" is a node_id; everything else is a path. */
|
|
9
|
+
anchor?: string;
|
|
10
|
+
/** Case-insensitive substring over title + context + decision. */
|
|
11
|
+
q?: string;
|
|
12
|
+
limit?: number;
|
|
13
|
+
}
|
|
14
|
+
/** True when the decision governs the given file path — an anchor records it
|
|
15
|
+
* exactly, or a decision path prefix (dir ending "/") contains it. */
|
|
16
|
+
export declare function governsPath(rec: DecisionRecord, filePath: string): boolean;
|
|
17
|
+
/** Deterministic order: decided_at desc, id asc within a day. */
|
|
18
|
+
export declare function sortDecisions(decisions: DecisionRecord[]): DecisionRecord[];
|
|
19
|
+
export declare function makeListDecisions(store: GraphStore, repoId: string, repoPath: string): (args: ListDecisionsArgs) => Promise<ToolResult>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { neutralizeSummary } from "../guard/summaryValidation.js";
|
|
2
|
+
import { anchorRepoIds, loadDecisions, nodeIdSuffix, resolveAnchorStates, } from "../store/decisions.js";
|
|
3
|
+
const err = (text) => ({ content: [{ type: "text", text }], isError: true });
|
|
4
|
+
function neutralize(s) {
|
|
5
|
+
return neutralizeSummary(s) ?? "";
|
|
6
|
+
}
|
|
7
|
+
/** True when the decision governs the given file path — an anchor records it
|
|
8
|
+
* exactly, or a decision path prefix (dir ending "/") contains it. */
|
|
9
|
+
export function governsPath(rec, filePath) {
|
|
10
|
+
for (const a of rec.anchors) {
|
|
11
|
+
if (a.path === filePath)
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
for (const p of rec.paths) {
|
|
15
|
+
if (p === filePath)
|
|
16
|
+
return true;
|
|
17
|
+
if (p.endsWith("/") && filePath.startsWith(p))
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function matchesAnchor(rec, anchor) {
|
|
23
|
+
if (anchor.startsWith("rs1:")) {
|
|
24
|
+
// Suffix-tolerant, like every other decision surface — anchors recorded
|
|
25
|
+
// in a fork/clone carry a different repo_id for the same node.
|
|
26
|
+
const suffix = nodeIdSuffix(anchor);
|
|
27
|
+
return rec.anchors.some((a) => a.node_id === anchor || (suffix !== null && nodeIdSuffix(a.node_id) === suffix));
|
|
28
|
+
}
|
|
29
|
+
return governsPath(rec, anchor);
|
|
30
|
+
}
|
|
31
|
+
function matchesText(rec, q) {
|
|
32
|
+
const needle = q.toLowerCase();
|
|
33
|
+
return (rec.title.toLowerCase().includes(needle) ||
|
|
34
|
+
rec.context.toLowerCase().includes(needle) ||
|
|
35
|
+
rec.decision.toLowerCase().includes(needle));
|
|
36
|
+
}
|
|
37
|
+
/** Deterministic order: decided_at desc, id asc within a day. */
|
|
38
|
+
export function sortDecisions(decisions) {
|
|
39
|
+
return [...decisions].sort((a, b) => {
|
|
40
|
+
if (a.decided_at !== b.decided_at)
|
|
41
|
+
return a.decided_at < b.decided_at ? 1 : -1;
|
|
42
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export function makeListDecisions(store, repoId, repoPath) {
|
|
46
|
+
return async (args) => {
|
|
47
|
+
try {
|
|
48
|
+
const limit = Math.min(Math.max(args.limit ?? 25, 1), 50);
|
|
49
|
+
const { decisions, warnings } = loadDecisions(repoPath);
|
|
50
|
+
let filtered = decisions;
|
|
51
|
+
if (args.status)
|
|
52
|
+
filtered = filtered.filter((d) => d.status === args.status);
|
|
53
|
+
if (args.anchor)
|
|
54
|
+
filtered = filtered.filter((d) => matchesAnchor(d, args.anchor));
|
|
55
|
+
if (args.q)
|
|
56
|
+
filtered = filtered.filter((d) => matchesText(d, args.q));
|
|
57
|
+
const ordered = sortDecisions(filtered);
|
|
58
|
+
const page = ordered.slice(0, limit);
|
|
59
|
+
const repoIds = await anchorRepoIds(store, repoId);
|
|
60
|
+
const rows = [];
|
|
61
|
+
for (const d of page) {
|
|
62
|
+
const states = await resolveAnchorStates(store, repoIds, d.anchors);
|
|
63
|
+
const counts = { current: 0, stale: 0, moved: 0, orphaned: 0 };
|
|
64
|
+
for (const s of states)
|
|
65
|
+
counts[s.state]++;
|
|
66
|
+
rows.push({
|
|
67
|
+
id: d.id,
|
|
68
|
+
title: neutralize(d.title),
|
|
69
|
+
status: d.status,
|
|
70
|
+
decided_at: d.decided_at,
|
|
71
|
+
anchor_counts: counts,
|
|
72
|
+
...(d.superseded_by ? { superseded_by: d.superseded_by } : {}),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: JSON.stringify({
|
|
80
|
+
decisions: rows,
|
|
81
|
+
truncated: ordered.length > page.length,
|
|
82
|
+
...(warnings.length ? { warnings } : {}),
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
return err(e.message);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=listDecisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listDecisions.js","sourceRoot":"","sources":["../../src/tools/listDecisions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GraphStore } from "../store/GraphStore.js";
|
|
2
|
+
import type { ToolResult } from "./readCypher.js";
|
|
3
|
+
export interface ReaffirmDecisionArgs {
|
|
4
|
+
decision_id: string;
|
|
5
|
+
}
|
|
6
|
+
/** "This decision is still correct": re-stamps every anchor from the live
|
|
7
|
+
* graph — stale anchors get the current hash, moved anchors are rebound to
|
|
8
|
+
* their recovered node — clearing review flags without supersede spam. The
|
|
9
|
+
* prose body never changes; body_hash is re-signed because rebinding an
|
|
10
|
+
* anchor updates the governed node list it covers. */
|
|
11
|
+
export declare function makeReaffirmDecision(store: GraphStore, repoId: string, repoPath: string): (args: ReaffirmDecisionArgs) => Promise<ToolResult>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { anchorRepoIds, computeBodyHash, loadDecisions, resolveAnchorStates, writeDecision, } from "../store/decisions.js";
|
|
2
|
+
const err = (text) => ({ content: [{ type: "text", text }], isError: true });
|
|
3
|
+
/** "This decision is still correct": re-stamps every anchor from the live
|
|
4
|
+
* graph — stale anchors get the current hash, moved anchors are rebound to
|
|
5
|
+
* their recovered node — clearing review flags without supersede spam. The
|
|
6
|
+
* prose body never changes; body_hash is re-signed because rebinding an
|
|
7
|
+
* anchor updates the governed node list it covers. */
|
|
8
|
+
export function makeReaffirmDecision(store, repoId, repoPath) {
|
|
9
|
+
return async (args) => {
|
|
10
|
+
try {
|
|
11
|
+
const { decisions } = loadDecisions(repoPath);
|
|
12
|
+
const rec = decisions.find((d) => d.id === args.decision_id);
|
|
13
|
+
if (!rec)
|
|
14
|
+
return err(`unknown decision: ${args.decision_id}`);
|
|
15
|
+
const repoIds = await anchorRepoIds(store, repoId);
|
|
16
|
+
const resolved = await resolveAnchorStates(store, repoIds, rec.anchors);
|
|
17
|
+
const anchors = [];
|
|
18
|
+
const results = [];
|
|
19
|
+
for (const r of resolved) {
|
|
20
|
+
results.push({ node_id: r.node_id, state: r.state });
|
|
21
|
+
if (r.state === "orphaned" || !r.resolved_node_id) {
|
|
22
|
+
anchors.push({ node_id: r.node_id, path: r.path, name: r.name, kind: r.kind, hash: r.hash });
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const live = await store.getNode(repoIds, r.resolved_node_id);
|
|
26
|
+
if (!live) {
|
|
27
|
+
anchors.push({ node_id: r.node_id, path: r.path, name: r.name, kind: r.kind, hash: r.hash });
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
anchors.push({
|
|
31
|
+
node_id: live.id,
|
|
32
|
+
path: live.file_path,
|
|
33
|
+
name: live.qualified_name || live.name,
|
|
34
|
+
kind: live.labels[0] ?? r.kind,
|
|
35
|
+
hash: live.content_hash,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const updated = { ...rec, anchors, body_hash: "" };
|
|
39
|
+
updated.body_hash = computeBodyHash(updated);
|
|
40
|
+
writeDecision(repoPath, updated);
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: "text",
|
|
45
|
+
text: JSON.stringify({ ok: true, decision_id: rec.id, anchors: results }),
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
return err(e.message);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=reaffirmDecision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reaffirmDecision.js","sourceRoot":"","sources":["../../src/tools/reaffirmDecision.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GraphStore } from "../store/GraphStore.js";
|
|
2
|
+
import type { ToolResult } from "./readCypher.js";
|
|
3
|
+
export interface RecordDecisionArgs {
|
|
4
|
+
title: string;
|
|
5
|
+
context: string;
|
|
6
|
+
decision: string;
|
|
7
|
+
consequences?: string;
|
|
8
|
+
alternatives?: string;
|
|
9
|
+
/** Default "proposed" — agents record, humans (or an explicit instruction)
|
|
10
|
+
* ratify. Honest provenance: the committing party is often the agent. */
|
|
11
|
+
status?: "proposed" | "accepted";
|
|
12
|
+
anchor_node_ids?: string[];
|
|
13
|
+
/** Literal file paths or directory prefixes ending "/". No globs. */
|
|
14
|
+
anchor_paths?: string[];
|
|
15
|
+
supersedes?: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface DecisionToolDeps {
|
|
18
|
+
/** Best-effort graph refresh before stamping anchor hashes, so a decision
|
|
19
|
+
* recorded right after an edit isn't born stale (the store reads the last
|
|
20
|
+
* index snapshot). Failures are swallowed — recording must not break. */
|
|
21
|
+
refresh?: () => Promise<void>;
|
|
22
|
+
today?: () => string;
|
|
23
|
+
}
|
|
24
|
+
export declare function makeRecordDecision(store: GraphStore, repoId: string, repoPath: string, deps?: DecisionToolDeps): (args: RecordDecisionArgs) => Promise<ToolResult>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { sanitizeDecisionFields } from "../guard/decisionValidation.js";
|
|
2
|
+
import { anchorRepoIds, computeBodyHash, loadDecisions, mintDecisionId, takenDecisionIds, writeDecision, } from "../store/decisions.js";
|
|
3
|
+
import { removeFromPendingDelta } from "../indexer/decisionsAffected.js";
|
|
4
|
+
function isoToday() {
|
|
5
|
+
// Day-precision ISO date (PRD §6.2.5: no wall-clock timestamps in output).
|
|
6
|
+
return new Date().toISOString().slice(0, 10);
|
|
7
|
+
}
|
|
8
|
+
const err = (text) => ({ content: [{ type: "text", text }], isError: true });
|
|
9
|
+
const ok = (obj) => ({ content: [{ type: "text", text: JSON.stringify(obj) }] });
|
|
10
|
+
/** A path anchor is a literal file path or a dir prefix ending "/" — never a
|
|
11
|
+
* glob (deterministic matching, no glob engine dependency). */
|
|
12
|
+
function invalidPath(p) {
|
|
13
|
+
return p.includes("*") || p.includes("?") || p.includes("[") || p.trim() === "";
|
|
14
|
+
}
|
|
15
|
+
export function makeRecordDecision(store, repoId, repoPath, deps = {}) {
|
|
16
|
+
const today = deps.today ?? isoToday;
|
|
17
|
+
return async (args) => {
|
|
18
|
+
const prose = sanitizeDecisionFields({
|
|
19
|
+
title: args.title,
|
|
20
|
+
context: args.context,
|
|
21
|
+
decision: args.decision,
|
|
22
|
+
consequences: args.consequences,
|
|
23
|
+
alternatives: args.alternatives,
|
|
24
|
+
});
|
|
25
|
+
if (!prose.ok)
|
|
26
|
+
return err(prose.error);
|
|
27
|
+
const anchorIds = args.anchor_node_ids ?? [];
|
|
28
|
+
const paths = args.anchor_paths ?? [];
|
|
29
|
+
const supersedes = args.supersedes ?? [];
|
|
30
|
+
if (anchorIds.length > 20)
|
|
31
|
+
return err("at most 20 anchor_node_ids");
|
|
32
|
+
if (paths.length > 20)
|
|
33
|
+
return err("at most 20 anchor_paths");
|
|
34
|
+
if (supersedes.length > 5)
|
|
35
|
+
return err("at most 5 supersedes");
|
|
36
|
+
const badPath = paths.find(invalidPath);
|
|
37
|
+
if (badPath !== undefined) {
|
|
38
|
+
return err(`anchor_paths must be literal paths or dir prefixes ending "/" (no globs): ${badPath}`);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const { decisions } = loadDecisions(repoPath);
|
|
42
|
+
const byId = new Map(decisions.map((d) => [d.id, d]));
|
|
43
|
+
// Validate supersedes before writing anything (atomic refusal on typo).
|
|
44
|
+
for (const sid of supersedes) {
|
|
45
|
+
const target = byId.get(sid);
|
|
46
|
+
if (!target)
|
|
47
|
+
return err(`supersedes references unknown decision: ${sid}`);
|
|
48
|
+
if (target.status === "superseded") {
|
|
49
|
+
return err(`decision ${sid} is already superseded by ${target.superseded_by ?? "another decision"}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Refresh the graph before stamping so anchors reflect the working tree.
|
|
53
|
+
if (deps.refresh) {
|
|
54
|
+
try {
|
|
55
|
+
await deps.refresh();
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// best-effort
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const repoIds = await anchorRepoIds(store, repoId);
|
|
62
|
+
const anchors = [];
|
|
63
|
+
const unresolved = [];
|
|
64
|
+
for (const nodeId of anchorIds) {
|
|
65
|
+
const live = await store.getNode(repoIds, nodeId);
|
|
66
|
+
if (!live) {
|
|
67
|
+
unresolved.push(nodeId);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
anchors.push({
|
|
71
|
+
node_id: live.id,
|
|
72
|
+
path: live.file_path,
|
|
73
|
+
name: live.qualified_name || live.name,
|
|
74
|
+
kind: live.labels[0] ?? "",
|
|
75
|
+
hash: live.content_hash,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const date = today();
|
|
79
|
+
// Filename-aware taken set: a damaged file's id must not be re-minted,
|
|
80
|
+
// or writeDecision would rename over the hand-recoverable record.
|
|
81
|
+
//
|
|
82
|
+
// The salt is the decision's own prose, so two branches recording a
|
|
83
|
+
// same-day decision under the same title mint DIFFERENT ids (and
|
|
84
|
+
// therefore different files) instead of colliding on `<slug>.1` — which
|
|
85
|
+
// would put the conflict right back into a store that exists to avoid it.
|
|
86
|
+
const id = mintDecisionId(date, prose.value.title, takenDecisionIds(repoPath), `${prose.value.context}\n${prose.value.decision}`);
|
|
87
|
+
const trigger = { kind: "manual" };
|
|
88
|
+
const rec = {
|
|
89
|
+
id,
|
|
90
|
+
title: prose.value.title,
|
|
91
|
+
status: args.status ?? "proposed",
|
|
92
|
+
context: prose.value.context,
|
|
93
|
+
decision: prose.value.decision,
|
|
94
|
+
anchors,
|
|
95
|
+
paths,
|
|
96
|
+
supersedes,
|
|
97
|
+
decided_at: date,
|
|
98
|
+
decided_by: process.env.REPOSKEIN_AGENT ?? "agent",
|
|
99
|
+
trigger,
|
|
100
|
+
body_hash: "",
|
|
101
|
+
};
|
|
102
|
+
if (prose.value.consequences !== undefined)
|
|
103
|
+
rec.consequences = prose.value.consequences;
|
|
104
|
+
if (prose.value.alternatives !== undefined)
|
|
105
|
+
rec.alternatives = prose.value.alternatives;
|
|
106
|
+
rec.body_hash = computeBodyHash(rec);
|
|
107
|
+
writeDecision(repoPath, rec);
|
|
108
|
+
// Flip superseded records after the new record exists; superseded_by
|
|
109
|
+
// makes the chain walkable in both directions.
|
|
110
|
+
for (const sid of supersedes) {
|
|
111
|
+
const target = byId.get(sid);
|
|
112
|
+
const flipped = { ...target, status: "superseded", superseded_by: id };
|
|
113
|
+
writeDecision(repoPath, flipped);
|
|
114
|
+
}
|
|
115
|
+
// The refresh above (or the agent's own pre-record edit + hook index)
|
|
116
|
+
// parked a drift delta that includes the very nodes this decision was
|
|
117
|
+
// just stamped against. Subtract them so the next reindex doesn't flag
|
|
118
|
+
// the freshly recorded decision as drifted; unrelated pending drift is
|
|
119
|
+
// preserved.
|
|
120
|
+
removeFromPendingDelta(repoPath, anchors.map((a) => a.node_id));
|
|
121
|
+
return ok({
|
|
122
|
+
ok: true,
|
|
123
|
+
decision_id: id,
|
|
124
|
+
status: rec.status,
|
|
125
|
+
anchors: anchors.map((a) => ({ node_id: a.node_id, path: a.path, kind: a.kind })),
|
|
126
|
+
unresolved,
|
|
127
|
+
superseded: supersedes,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
return err(e.message);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=recordDecision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordDecision.js","sourceRoot":"","sources":["../../src/tools/recordDecision.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@ import type { EmbeddingProvider } from "../embed/provider.js";
|
|
|
22
22
|
export interface SemanticFindArgs {
|
|
23
23
|
query: string;
|
|
24
24
|
limit?: number;
|
|
25
|
-
kind?: "Function" | "Class" | "Interface" | "Enum";
|
|
25
|
+
kind?: "Function" | "Class" | "Interface" | "Enum" | "Decision";
|
|
26
26
|
federated?: boolean;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
@@ -33,5 +33,12 @@ export interface SemanticFindArgs {
|
|
|
33
33
|
* @param repoPath File system path to the repo root (for the embedding cache).
|
|
34
34
|
* @param providerOverride Inject a provider directly (for tests — avoids env/network).
|
|
35
35
|
* Pass null to force pure-lexical. Pass undefined to use env config.
|
|
36
|
+
* @param opts.decisions Include the decision log in the corpus (default true).
|
|
37
|
+
* Callers without a REAL configured repoPath must pass
|
|
38
|
+
* false — repoPath falls back to "." for the embed
|
|
39
|
+
* cache, and reading <cwd>/.reposkein/decisions/ would
|
|
40
|
+
* inject another project's decision log.
|
|
36
41
|
*/
|
|
37
|
-
export declare function makeSemanticFind(store: GraphStore, repoId: string, repoPath?: string, providerOverride?: EmbeddingProvider | null
|
|
42
|
+
export declare function makeSemanticFind(store: GraphStore, repoId: string, repoPath?: string, providerOverride?: EmbeddingProvider | null, opts?: {
|
|
43
|
+
decisions?: boolean;
|
|
44
|
+
}): (args: SemanticFindArgs) => Promise<ToolResult>;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* and Neo4j backends. No Neo4j vector index used.
|
|
18
18
|
*/
|
|
19
19
|
import { federationIds } from "../store/federation.js";
|
|
20
|
+
import { loadDecisions } from "../store/decisions.js";
|
|
20
21
|
import { rankCorpus } from "../search/bm25f.js";
|
|
21
22
|
import { providerFromEnv } from "../embed/provider.js";
|
|
22
23
|
import { embedCorpus } from "../embed/cache.js";
|
|
@@ -24,6 +25,26 @@ import { cosineRank, rrf } from "../embed/hybrid.js";
|
|
|
24
25
|
import { neutralizeSummary } from "../guard/summaryValidation.js";
|
|
25
26
|
const DEFAULT_LIMIT = 10;
|
|
26
27
|
const MAX_LIMIT = 25;
|
|
28
|
+
/** Cap for the displayed rationale on Decision rows (the full record is one
|
|
29
|
+
* get_decision away; the search text itself is unbounded). */
|
|
30
|
+
const DECISION_SUMMARY_DISPLAY = 240;
|
|
31
|
+
/** Decision records as corpus pseudo-nodes: title is the name, and the
|
|
32
|
+
* searchable/embeddable text is title + context + decision — the schema was
|
|
33
|
+
* shaped for exactly this. All statuses are included (history is the point);
|
|
34
|
+
* rows carry `status` so superseded rationale is recognizable. Bodies are
|
|
35
|
+
* immutable, so the embedding cache never re-embeds a decision. */
|
|
36
|
+
function decisionCorpus(decisions, repoId) {
|
|
37
|
+
return decisions.map((d) => ({
|
|
38
|
+
id: d.id,
|
|
39
|
+
kind: "Decision",
|
|
40
|
+
name: d.title,
|
|
41
|
+
qualified_name: d.title,
|
|
42
|
+
signature: "",
|
|
43
|
+
summary: `${d.context} ${d.decision}`,
|
|
44
|
+
file_path: d.paths[0] ?? d.anchors[0]?.path ?? "",
|
|
45
|
+
repo_id: repoId,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
27
48
|
/**
|
|
28
49
|
* Factory for the semantic_find handler.
|
|
29
50
|
*
|
|
@@ -32,8 +53,14 @@ const MAX_LIMIT = 25;
|
|
|
32
53
|
* @param repoPath File system path to the repo root (for the embedding cache).
|
|
33
54
|
* @param providerOverride Inject a provider directly (for tests — avoids env/network).
|
|
34
55
|
* Pass null to force pure-lexical. Pass undefined to use env config.
|
|
56
|
+
* @param opts.decisions Include the decision log in the corpus (default true).
|
|
57
|
+
* Callers without a REAL configured repoPath must pass
|
|
58
|
+
* false — repoPath falls back to "." for the embed
|
|
59
|
+
* cache, and reading <cwd>/.reposkein/decisions/ would
|
|
60
|
+
* inject another project's decision log.
|
|
35
61
|
*/
|
|
36
|
-
export function makeSemanticFind(store, repoId, repoPath = ".", providerOverride) {
|
|
62
|
+
export function makeSemanticFind(store, repoId, repoPath = ".", providerOverride, opts = {}) {
|
|
63
|
+
const includeDecisions = opts.decisions ?? true;
|
|
37
64
|
return async (args) => {
|
|
38
65
|
const { query, kind, federated } = args;
|
|
39
66
|
const limit = Math.min(Math.max(1, args.limit ?? DEFAULT_LIMIT), MAX_LIMIT);
|
|
@@ -47,6 +74,15 @@ export function makeSemanticFind(store, repoId, repoPath = ".", providerOverride
|
|
|
47
74
|
const repoIds = federated ? await federationIds(store, repoId) : [repoId];
|
|
48
75
|
// Fetch the corpus from the store (both backends return nodes sorted by id)
|
|
49
76
|
let corpus = await store.searchCorpus(repoIds);
|
|
77
|
+
// Decision records join the corpus as pseudo-nodes (gated like every
|
|
78
|
+
// decision surface — see opts.decisions).
|
|
79
|
+
const decisionStatusById = new Map();
|
|
80
|
+
if (includeDecisions) {
|
|
81
|
+
const { decisions } = loadDecisions(repoPath);
|
|
82
|
+
corpus = [...corpus, ...decisionCorpus(decisions, repoId)];
|
|
83
|
+
for (const d of decisions)
|
|
84
|
+
decisionStatusById.set(d.id, d.status);
|
|
85
|
+
}
|
|
50
86
|
// Apply optional kind filter before ranking (design §4)
|
|
51
87
|
if (kind) {
|
|
52
88
|
corpus = corpus.filter((n) => n.kind === kind);
|
|
@@ -129,10 +165,16 @@ export function makeSemanticFind(store, repoId, repoPath = ".", providerOverride
|
|
|
129
165
|
if (via !== undefined) {
|
|
130
166
|
result["via"] = via;
|
|
131
167
|
}
|
|
168
|
+
if (node.kind === "Decision") {
|
|
169
|
+
result["status"] = decisionStatusById.get(node.id);
|
|
170
|
+
}
|
|
132
171
|
// Include summary only when present (keeps payload lean; absence is informative).
|
|
133
172
|
// Neutralize on the READ path to close the injection bypass: summaries from
|
|
134
173
|
// git-pulled nodes.jsonl or hand-edited files never passed the write guard.
|
|
135
|
-
|
|
174
|
+
let neutralized = neutralizeSummary(node.summary || null);
|
|
175
|
+
if (neutralized && node.kind === "Decision" && neutralized.length > DECISION_SUMMARY_DISPLAY) {
|
|
176
|
+
neutralized = neutralized.slice(0, DECISION_SUMMARY_DISPLAY) + "…";
|
|
177
|
+
}
|
|
136
178
|
if (neutralized) {
|
|
137
179
|
result["summary"] = neutralized;
|
|
138
180
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semanticFind.js","sourceRoot":"","sources":["../../src/tools/semanticFind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,GAAG,EAAgB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AASlE,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB
|
|
1
|
+
{"version":3,"file":"semanticFind.js","sourceRoot":"","sources":["../../src/tools/semanticFind.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ToolResult } from "./readCypher.js";
|
|
2
|
+
export interface SetDecisionStatusArgs {
|
|
3
|
+
decision_id: string;
|
|
4
|
+
/** "superseded" is deliberately absent — it only happens via
|
|
5
|
+
* record_decision's supersedes, which links both directions. */
|
|
6
|
+
status: "accepted" | "rejected" | "deprecated";
|
|
7
|
+
}
|
|
8
|
+
export declare function makeSetDecisionStatus(repoPath: string): (args: SetDecisionStatusArgs) => Promise<ToolResult>;
|