@izagood/avcs 0.20.0 → 0.22.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/dist/api/repo.d.ts +10 -0
- package/dist/api/repo.d.ts.map +1 -1
- package/dist/api/repo.js +11 -0
- package/dist/api/repo.js.map +1 -1
- package/dist/mcp/context.d.ts +10 -0
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +148 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/guide.d.ts.map +1 -1
- package/dist/mcp/guide.js +1 -2
- package/dist/mcp/guide.js.map +1 -1
- package/dist/mcp/prompts.d.ts +15 -0
- package/dist/mcp/prompts.d.ts.map +1 -0
- package/dist/mcp/prompts.js +89 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/resources.d.ts +17 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +80 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +132 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/watch.d.ts +39 -0
- package/dist/mcp/watch.d.ts.map +1 -0
- package/dist/mcp/watch.js +107 -0
- package/dist/mcp/watch.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Phase 16 M3 (docs/18 §M3) — ContextPack.
|
|
2
|
+
//
|
|
3
|
+
// Without this an agent reconstructs its working context by hand — blame here, history
|
|
4
|
+
// there, decisions somewhere else — and pays a round trip for each. context.build assembles
|
|
5
|
+
// the whole picture once, under a byte budget.
|
|
6
|
+
//
|
|
7
|
+
// Two decisions shape it:
|
|
8
|
+
//
|
|
9
|
+
// - **No content.** Symbols carry provenance and a blobOid, never the file text. Text is
|
|
10
|
+
// the one thing an agent can fetch precisely (object.show with lines/maxBytes), so
|
|
11
|
+
// spending the pack's budget on it would crowd out the things it cannot cheaply derive.
|
|
12
|
+
//
|
|
13
|
+
// - **Deterministic truncation.** Section priority is fixed, ordering inside a section is
|
|
14
|
+
// fixed, and the greedy fill measures compact serialization bytes. The same input
|
|
15
|
+
// therefore yields byte-identical output — the same determinism AVCS demands of reduce,
|
|
16
|
+
// applied to context. What was dropped is recorded in `budget.truncated`, never silently
|
|
17
|
+
// missing: an agent that cannot tell a thin repo from a truncated pack will make
|
|
18
|
+
// confident decisions on partial information.
|
|
19
|
+
import { keysOf } from "../reducer/reducer.js";
|
|
20
|
+
/** Section fill order = priority order. Risks first: a pack that omits "someone else holds
|
|
21
|
+
* a lease on this key" is worse than no pack, because it reads as an all-clear. History is
|
|
22
|
+
* last because it is the most reconstructible from other tools. */
|
|
23
|
+
const SECTIONS = ["risks", "decisions", "policies", "symbols", "evidence", "history", "suggestedOps"];
|
|
24
|
+
export async function buildContextPack(repo, args) {
|
|
25
|
+
const view = args.view ?? "main";
|
|
26
|
+
const maxBytes = Math.max(1, Math.floor(args.maxBytes ?? 8192));
|
|
27
|
+
const keys = await resolveScope(repo, args);
|
|
28
|
+
if (!keys.length) {
|
|
29
|
+
throw new Error("context.build needs a scope: pass intentOid, entityKeys or paths. " +
|
|
30
|
+
"Refusing to pack the whole repo — an unbounded context is the problem this tool exists to solve.");
|
|
31
|
+
}
|
|
32
|
+
const res = await repo.materialize(view);
|
|
33
|
+
const [leases, policies, quarantined] = await Promise.all([
|
|
34
|
+
repo.activeLeases(),
|
|
35
|
+
repo.learnedPolicies(),
|
|
36
|
+
repo.quarantinedOps(view).catch(() => []),
|
|
37
|
+
]);
|
|
38
|
+
const quarantinedSet = new Set(quarantined);
|
|
39
|
+
const symbols = [];
|
|
40
|
+
const decisions = [];
|
|
41
|
+
const risks = [];
|
|
42
|
+
const history = [];
|
|
43
|
+
const evidence = [];
|
|
44
|
+
for (const key of keys) {
|
|
45
|
+
const blame = await repo.blame(key, view);
|
|
46
|
+
if (blame) {
|
|
47
|
+
symbols.push({
|
|
48
|
+
key,
|
|
49
|
+
blobOid: res.tree.get(key.replace(/^file:/, "")) ?? null,
|
|
50
|
+
owner: blame.actor.id,
|
|
51
|
+
intent: blame.intentTitle ?? null,
|
|
52
|
+
purpose: blame.purpose,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
for (const d of await repo.recallDecisions(key)) {
|
|
56
|
+
decisions.push({ key, reason: d.reason, futurePolicy: d.futurePolicy ?? null, by: d.decidedBy });
|
|
57
|
+
}
|
|
58
|
+
// Recency-first, then oid — a total order, so the greedy fill is reproducible.
|
|
59
|
+
const hist = (await repo.historyOf(key)).slice(-3).reverse();
|
|
60
|
+
for (const op of hist) {
|
|
61
|
+
history.push({ key, op: op.oid, actor: op.actor.id, purpose: op.declaredPurpose });
|
|
62
|
+
if (quarantinedSet.has(op.oid)) {
|
|
63
|
+
risks.push({ kind: "quarantine", key, detail: `op ${String(op.oid).slice(0, 16)} is quarantined pending review` });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const c of res.conflicts) {
|
|
67
|
+
if (c.key === key)
|
|
68
|
+
risks.push({ kind: "conflict", key, detail: c.reason });
|
|
69
|
+
}
|
|
70
|
+
for (const l of leases) {
|
|
71
|
+
if (l.writeScopes.some((s) => s === key)) {
|
|
72
|
+
risks.push({ kind: "lease", key, detail: `held by ${l.actor.id} until ${l.expiresAt}` });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Byte sizes must be read off the same tree the pack is pinned to.
|
|
77
|
+
const files = await repo.materializedBytes(res).catch(() => []);
|
|
78
|
+
const sizeOf = new Map(files.map((f) => [f.path, f.bytes.length]));
|
|
79
|
+
for (const s of symbols)
|
|
80
|
+
s.bytes = sizeOf.get(String(s.key).replace(/^file:/, "")) ?? null;
|
|
81
|
+
// v1 is deliberately thin (docs/18 §3.1): derived from learned policies and failed
|
|
82
|
+
// evidence, not invented. A confident wrong suggestion is worse than none.
|
|
83
|
+
const suggestedOps = policies.map((p) => `learned policy: ${p}`);
|
|
84
|
+
const built = {
|
|
85
|
+
risks: dedupe(risks),
|
|
86
|
+
decisions,
|
|
87
|
+
policies,
|
|
88
|
+
symbols,
|
|
89
|
+
evidence,
|
|
90
|
+
history,
|
|
91
|
+
suggestedOps,
|
|
92
|
+
};
|
|
93
|
+
// Greedy fill in priority order over COMPACT bytes — the same serialization the transport
|
|
94
|
+
// will send, so the budget means what it says.
|
|
95
|
+
const out = { v: 1, view, treeHash: res.treeHash };
|
|
96
|
+
const truncated = [];
|
|
97
|
+
const envelopeCost = JSON.stringify({ ...out, budget: { maxBytes, usedBytes: maxBytes, truncated: SECTIONS } }).length;
|
|
98
|
+
let used = envelopeCost;
|
|
99
|
+
for (const name of SECTIONS) {
|
|
100
|
+
const cost = JSON.stringify(built[name]).length + name.length + 4;
|
|
101
|
+
if (used + cost <= maxBytes) {
|
|
102
|
+
out[name] = built[name];
|
|
103
|
+
used += cost;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
out[name] = [];
|
|
107
|
+
if (built[name].length)
|
|
108
|
+
truncated.push(name);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
out.budget = { maxBytes, usedBytes: JSON.stringify(out).length, truncated };
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
/** Resolve the requested scope to entity keys, sorted for a stable fill order. */
|
|
115
|
+
async function resolveScope(repo, args) {
|
|
116
|
+
const keys = new Set(args.entityKeys ?? []);
|
|
117
|
+
for (const p of args.paths ?? [])
|
|
118
|
+
keys.add(`file:${p}`);
|
|
119
|
+
if (args.intentOid) {
|
|
120
|
+
// The intent's declared scopes, plus what its sessions' ops ACTUALLY touched — the
|
|
121
|
+
// declaration is the plan, the ops are the reality, and an agent needs both.
|
|
122
|
+
const intent = await repo.readIntent(args.intentOid).catch(() => null);
|
|
123
|
+
for (const s of intent?.allowedScopes ?? [])
|
|
124
|
+
keys.add(String(s));
|
|
125
|
+
const sessions = await repo.store.collect("session");
|
|
126
|
+
const mine = new Set(sessions.filter((s) => s.intentOid === args.intentOid).map((s) => s.oid));
|
|
127
|
+
for (const op of await repo.store.collect("operation")) {
|
|
128
|
+
if (op.sessionOid && mine.has(op.sessionOid))
|
|
129
|
+
for (const k of keysOf(op))
|
|
130
|
+
keys.add(k);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return [...keys].sort();
|
|
134
|
+
}
|
|
135
|
+
/** Stable de-dup preserving first occurrence — two sources can report the same risk. */
|
|
136
|
+
function dedupe(rows) {
|
|
137
|
+
const seen = new Set();
|
|
138
|
+
const out = [];
|
|
139
|
+
for (const r of rows) {
|
|
140
|
+
const k = JSON.stringify(r);
|
|
141
|
+
if (seen.has(k))
|
|
142
|
+
continue;
|
|
143
|
+
seen.add(k);
|
|
144
|
+
out.push(r);
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/mcp/context.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,uFAAuF;AACvF,4FAA4F;AAC5F,+CAA+C;AAC/C,EAAE;AACF,0BAA0B;AAC1B,EAAE;AACF,0FAA0F;AAC1F,sFAAsF;AACtF,2FAA2F;AAC3F,EAAE;AACF,2FAA2F;AAC3F,qFAAqF;AACrF,2FAA2F;AAC3F,4FAA4F;AAC5F,oFAAoF;AACpF,iDAAiD;AAEjD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAY/C;;oEAEoE;AACpE,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,CAAU,CAAC;AAG/G,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAU,EAAE,IAAqB;IACtE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,oEAAoE;YAClE,kGAAkG,CACrG,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACxD,IAAI,CAAC,YAAY,EAAE;QACnB,IAAI,CAAC,eAAe,EAAE;QACtB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAc,CAAC;KACtD,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAE5C,MAAM,OAAO,GAA8B,EAAE,CAAC;IAC9C,MAAM,SAAS,GAA8B,EAAE,CAAC;IAChD,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAA8B,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAA8B,EAAE,CAAC;IAE/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC;gBACX,GAAG;gBACH,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI;gBACxD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE;gBACrB,MAAM,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;gBACjC,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;YAChD,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QACnG,CAAC;QACD,+EAA+E;QAC/E,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC7D,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;YACnF,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,GAAa,CAAC,EAAE,CAAC;gBACzC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,gCAAgC,EAAE,CAAC,CAAC;YACrH,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;gBACzC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAuC,CAAC,CAAC;IACrG,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACnE,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC;IAE3F,mFAAmF;IACnF,2EAA2E;IAC3E,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;IAEjE,MAAM,KAAK,GAA+B;QACxC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;QACpB,SAAS;QACT,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,OAAO;QACP,YAAY;KACb,CAAC;IAEF,0FAA0F;IAC1F,+CAA+C;IAC/C,MAAM,GAAG,GAA4B,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC5E,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;IACvH,IAAI,IAAI,GAAG,YAAY,CAAC;IACxB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAClE,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACxB,IAAI,IAAI,IAAI,CAAC;QACf,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACf,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;gBAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,GAAG,CAAC,MAAM,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAC5E,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,KAAK,UAAU,YAAY,CAAC,IAAU,EAAE,IAAqB;IAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAExD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,mFAAmF;QACnF,6EAA6E;QAC7E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAqB,CAAC,CAAC;QACxF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,aAAa,IAAI,EAAE;YAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,SAAS,CAAC,CAAC;QAC9D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAa,CAAC,CAAC,CAAC;QACzG,KAAK,MAAM,EAAE,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,WAAW,CAAC,EAAE,CAAC;YAClE,IAAI,EAAE,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC;gBAAE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC;oBAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,wFAAwF;AACxF,SAAS,MAAM,CAAC,IAA+B;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAA8B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QAC1B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/mcp/guide.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide.d.ts","sourceRoot":"","sources":["../../src/mcp/guide.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"guide.d.ts","sourceRoot":"","sources":["../../src/mcp/guide.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAsC5E,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqBpF"}
|
package/dist/mcp/guide.js
CHANGED
|
@@ -14,12 +14,11 @@ import { RECOVERY } from "./respond.js";
|
|
|
14
14
|
* tool that does not exist teaches the agent to fail, and unlike prose an agent would skim,
|
|
15
15
|
* a step it is told to run fails for certain. A test pins this against the live table.
|
|
16
16
|
*
|
|
17
|
-
* Phase 16 M3 inserts `avcs.context.build` after intent.read.
|
|
18
17
|
*/
|
|
19
18
|
const LOOP = [
|
|
20
19
|
{ step: 1, tool: "avcs.intent.read", why: "learn the declared goal and the scopes you may touch" },
|
|
21
20
|
{ step: 2, tool: "avcs.session.start", why: "bind your work to that intent under your actor identity" },
|
|
22
|
-
{ step: 3, tool: "avcs.
|
|
21
|
+
{ step: 3, tool: "avcs.context.build", why: "get provenance, prior decisions and live risks for your scope in one bounded call" },
|
|
23
22
|
{ step: 4, tool: "avcs.lease.request", why: "claim the scopes you are about to write" },
|
|
24
23
|
{ step: 5, tool: "avcs.operation.propose", why: "submit the change as an operation; never write final files yourself" },
|
|
25
24
|
{ step: 6, tool: "avcs.validate.run", why: "produce evidence; a behaviour change is not acceptable without it" },
|
package/dist/mcp/guide.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/mcp/guide.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,2FAA2F;AAC3F,oFAAoF;AACpF,yFAAyF;AACzF,4FAA4F;AAC5F,EAAE;AACF,wFAAwF;AACxF,4FAA4F;AAC5F,0FAA0F;AAE1F,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAKxC
|
|
1
|
+
{"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/mcp/guide.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Repo } from "../api/repo.ts";
|
|
2
|
+
import type { ToolDef } from "./server.ts";
|
|
3
|
+
export interface PromptDef {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
arguments: {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
export declare const PROMPTS: PromptDef[];
|
|
13
|
+
/** Render a prompt with its facts already resolved. Throws on an unknown name. */
|
|
14
|
+
export declare function buildPrompt(repo: Repo, name: string, args: Record<string, unknown>, tools?: ToolDef[]): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/mcp/prompts.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACxE;AAED,eAAO,MAAM,OAAO,EAAE,SAAS,EA2B9B,CAAC;AAEF,kFAAkF;AAClF,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,GAAE,OAAO,EAAO,GACpB,OAAO,CAAC,MAAM,CAAC,CAuDjB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Phase 16 M4.2 (docs/18 §4.2) — MCP prompts.
|
|
2
|
+
//
|
|
3
|
+
// A prompt is a client-invocable template that arrives with its facts already inlined. The
|
|
4
|
+
// point is round trips: `avcs.propose-change` carries the intent's own constraints in the
|
|
5
|
+
// text, so the agent does not have to fetch them and then remember to honour them. The
|
|
6
|
+
// constraint an agent never read is a constraint it will break.
|
|
7
|
+
import { buildGuide } from "./guide.js";
|
|
8
|
+
export const PROMPTS = [
|
|
9
|
+
{
|
|
10
|
+
name: "avcs.onboard",
|
|
11
|
+
description: "Teach the AVCS loop, rules and error recovery — the guide, inlined.",
|
|
12
|
+
arguments: [],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "avcs.propose-change",
|
|
16
|
+
description: "Draft a change under an intent, with that intent's constraints and scopes inlined.",
|
|
17
|
+
arguments: [
|
|
18
|
+
{ name: "intentOid", description: "the intent to work under", required: true },
|
|
19
|
+
{ name: "paths", description: "comma-separated paths you expect to touch" },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "avcs.resolve-repair",
|
|
24
|
+
description: "Repair operations whose validation failed, with the repair packet inlined.",
|
|
25
|
+
arguments: [{ name: "ops", description: "comma-separated operation oids", required: true }],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "avcs.review-change",
|
|
29
|
+
description: "Review a checkpoint: changed paths, evidence and the view's protection, inlined.",
|
|
30
|
+
arguments: [
|
|
31
|
+
{ name: "view", description: "view name; default main" },
|
|
32
|
+
{ name: "checkpointOid", description: "the checkpoint under review" },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
/** Render a prompt with its facts already resolved. Throws on an unknown name. */
|
|
37
|
+
export async function buildPrompt(repo, name, args, tools = []) {
|
|
38
|
+
switch (name) {
|
|
39
|
+
case "avcs.onboard":
|
|
40
|
+
return [
|
|
41
|
+
"You are working in an AVCS repository. Follow this loop and these rules.",
|
|
42
|
+
JSON.stringify(buildGuide(tools), null, 2),
|
|
43
|
+
].join("\n\n");
|
|
44
|
+
case "avcs.propose-change": {
|
|
45
|
+
const intent = await repo.readIntent(String(args.intentOid));
|
|
46
|
+
const lines = [
|
|
47
|
+
`Intent: ${intent.title}`,
|
|
48
|
+
intent.constraints?.length ? `Constraints (do not violate):\n${intent.constraints.map((c) => ` - ${c}`).join("\n")}` : "",
|
|
49
|
+
intent.successCriteria?.length ? `Success criteria:\n${intent.successCriteria.map((c) => ` - ${c}`).join("\n")}` : "",
|
|
50
|
+
intent.allowedScopes?.length ? `Allowed scopes:\n${intent.allowedScopes.map((s) => ` - ${s}`).join("\n")}` : "",
|
|
51
|
+
typeof args.paths === "string" && args.paths ? `Paths you expect to touch: ${args.paths}` : "",
|
|
52
|
+
"",
|
|
53
|
+
"Start with avcs.context.build on this intent. Author changes with avcs.operation.propose —",
|
|
54
|
+
"never write final files yourself. Declare effects honestly. Land with avcs.sync.land.",
|
|
55
|
+
];
|
|
56
|
+
return lines.filter(Boolean).join("\n");
|
|
57
|
+
}
|
|
58
|
+
case "avcs.resolve-repair": {
|
|
59
|
+
const ops = String(args.ops ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
60
|
+
const packet = await repo.repairContext(ops);
|
|
61
|
+
return [
|
|
62
|
+
"These operations failed validation. Repair them, then re-run avcs.validate.run.",
|
|
63
|
+
JSON.stringify(packet, null, 2),
|
|
64
|
+
].join("\n\n");
|
|
65
|
+
}
|
|
66
|
+
case "avcs.review-change": {
|
|
67
|
+
const view = typeof args.view === "string" ? args.view : "main";
|
|
68
|
+
const [protection, head, res] = await Promise.all([
|
|
69
|
+
repo.getProtection(view),
|
|
70
|
+
repo.protectedHead(view),
|
|
71
|
+
repo.materialize(view),
|
|
72
|
+
]);
|
|
73
|
+
const cp = typeof args.checkpointOid === "string" ? args.checkpointOid : head;
|
|
74
|
+
const approvals = cp ? await repo.approvalsFor(cp) : [];
|
|
75
|
+
return [
|
|
76
|
+
`Review of view "${view}" (head ${head ?? "none"}, tree ${res.treeHash}).`,
|
|
77
|
+
`Protection: ${JSON.stringify(protection)}`,
|
|
78
|
+
`Approvals so far: ${JSON.stringify(approvals)}`,
|
|
79
|
+
`Open conflicts: ${res.conflicts.length}`,
|
|
80
|
+
"",
|
|
81
|
+
"Read the diff with avcs.diff format:patch, check evidence, then record a verdict",
|
|
82
|
+
"with avcs.approval.record.",
|
|
83
|
+
].join("\n");
|
|
84
|
+
}
|
|
85
|
+
default:
|
|
86
|
+
throw new Error(`unknown prompt: ${name}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/mcp/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Repo } from "../api/repo.ts";
|
|
2
|
+
import type { ToolDef } from "./server.ts";
|
|
3
|
+
export interface ResourceDef {
|
|
4
|
+
uri: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
mimeType: string;
|
|
8
|
+
}
|
|
9
|
+
/** Advertised resources. `{view}` is a template segment filled by the client. */
|
|
10
|
+
export declare const RESOURCES: ResourceDef[];
|
|
11
|
+
/**
|
|
12
|
+
* Read one resource. Returns the serialized body; throws on an unknown URI rather than
|
|
13
|
+
* returning an empty document — a client that asked for something that does not exist has
|
|
14
|
+
* a bug, and an empty body would read as "nothing here", which is a different fact.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readResource(repo: Repo, uri: string, tools?: ToolDef[]): Promise<string>;
|
|
17
|
+
//# sourceMappingURL=resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../src/mcp/resources.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,iFAAiF;AACjF,eAAO,MAAM,SAAS,EAAE,WAAW,EAyBlC,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAgClG"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Phase 16 M4.1 (docs/18 §4.1) — MCP resources.
|
|
2
|
+
//
|
|
3
|
+
// Tools are the parameterized main path. Resources exist for one thing tools cannot do:
|
|
4
|
+
// be SUBSCRIBED to. A client that subscribes to `avcs://view/main/head` is told when the
|
|
5
|
+
// head moves instead of asking every few seconds.
|
|
6
|
+
//
|
|
7
|
+
// Every read goes through the same repo calls the equivalent tool uses, so a resource can
|
|
8
|
+
// never disagree with the tool that backs it — one source of truth, two doors to it.
|
|
9
|
+
import { buildGuide } from "./guide.js";
|
|
10
|
+
import { buildContextPack } from "./context.js";
|
|
11
|
+
import { keysOf } from "../reducer/reducer.js";
|
|
12
|
+
/** Advertised resources. `{view}` is a template segment filled by the client. */
|
|
13
|
+
export const RESOURCES = [
|
|
14
|
+
{
|
|
15
|
+
uri: "avcs://view/{view}/head",
|
|
16
|
+
name: "view head",
|
|
17
|
+
description: "The protected head of a view and the tree it resolves to. Subscribe to learn when it advances.",
|
|
18
|
+
mimeType: "application/json",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
uri: "avcs://view/{view}/conflicts",
|
|
22
|
+
name: "open conflicts",
|
|
23
|
+
description: "Conflicts awaiting a human decision on a view. Subscribe to learn when one opens.",
|
|
24
|
+
mimeType: "application/json",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
uri: "avcs://view/{view}/context",
|
|
28
|
+
name: "view context",
|
|
29
|
+
description: "A default ContextPack scoped to the keys currently in play on the view.",
|
|
30
|
+
mimeType: "application/json",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
uri: "avcs://guide",
|
|
34
|
+
name: "guide",
|
|
35
|
+
description: "The canonical loop, agent rules, tool index and error recovery.",
|
|
36
|
+
mimeType: "application/json",
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Read one resource. Returns the serialized body; throws on an unknown URI rather than
|
|
41
|
+
* returning an empty document — a client that asked for something that does not exist has
|
|
42
|
+
* a bug, and an empty body would read as "nothing here", which is a different fact.
|
|
43
|
+
*/
|
|
44
|
+
export async function readResource(repo, uri, tools = []) {
|
|
45
|
+
if (uri === "avcs://guide")
|
|
46
|
+
return JSON.stringify(buildGuide(tools));
|
|
47
|
+
const m = /^avcs:\/\/view\/([^/]+)\/(head|conflicts|context)$/.exec(uri);
|
|
48
|
+
if (!m)
|
|
49
|
+
throw new Error(`unknown resource uri: ${uri}`);
|
|
50
|
+
const view = decodeURIComponent(m[1]);
|
|
51
|
+
switch (m[2]) {
|
|
52
|
+
case "head": {
|
|
53
|
+
const [head, res] = await Promise.all([repo.protectedHead(view), repo.materialize(view)]);
|
|
54
|
+
return JSON.stringify({ view, head, treeHash: res.treeHash });
|
|
55
|
+
}
|
|
56
|
+
case "conflicts": {
|
|
57
|
+
const res = await repo.materialize(view);
|
|
58
|
+
return JSON.stringify(res.conflicts);
|
|
59
|
+
}
|
|
60
|
+
default: {
|
|
61
|
+
// context.build refuses an unscoped call by design, so a VIEW-level pack has to name
|
|
62
|
+
// its own scope: the keys actually in play — anything contended, plus what the most
|
|
63
|
+
// recent operations touched. That is the set an agent arriving at this view needs.
|
|
64
|
+
const res = await repo.materialize(view);
|
|
65
|
+
const keys = new Set(res.conflicts.map((c) => c.key));
|
|
66
|
+
const ops = await repo.store.collect("operation");
|
|
67
|
+
const recent = ops
|
|
68
|
+
.filter((o) => (o.line ?? "main") === view)
|
|
69
|
+
.sort((a, b) => a.lamport - b.lamport || String(a.oid).localeCompare(String(b.oid)))
|
|
70
|
+
.slice(-20);
|
|
71
|
+
for (const op of recent)
|
|
72
|
+
for (const k of keysOf(op))
|
|
73
|
+
keys.add(k);
|
|
74
|
+
if (!keys.size)
|
|
75
|
+
return JSON.stringify({ v: 1, view, treeHash: res.treeHash, budget: { maxBytes: 8192, usedBytes: 0, truncated: [] }, symbols: [], decisions: [], policies: [], risks: [], evidence: [], history: [], suggestedOps: [] });
|
|
76
|
+
return JSON.stringify(await buildContextPack(repo, { entityKeys: [...keys], view, maxBytes: 8192 }));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/mcp/resources.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAuBtC,OAAO,KAAK,EAAE,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAuBlE,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wFAAwF;AACxF,MAAM,WAAW,OAAO;IACtB,kEAAkE;IAClE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CAChG;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1F;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAG7D;AA+BD;qFACqF;AACrF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASpE;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,CAAC,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAQ3E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,GACjC,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED,eAAO,MAAM,KAAK,EAAE,OAAO,EAmvB1B,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAkLpD"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -23,6 +23,10 @@ import { serializeResult, errorEnvelope, boundedLimit } from "./respond.js";
|
|
|
23
23
|
import { unifiedDiff } from "../query/diff.js";
|
|
24
24
|
import { buildGuide } from "./guide.js";
|
|
25
25
|
import { land } from "./land.js";
|
|
26
|
+
import { buildContextPack } from "./context.js";
|
|
27
|
+
import { RESOURCES, readResource } from "./resources.js";
|
|
28
|
+
import { PROMPTS, buildPrompt } from "./prompts.js";
|
|
29
|
+
import { RepoWatcher, watchIntervalMs } from "./watch.js";
|
|
26
30
|
/** The hub's governance refs (`head:<view>`, policy, …). Empty when unreachable — a head
|
|
27
31
|
* comparison is informational, so a dead hub degrades the answer instead of failing it. */
|
|
28
32
|
async function fetchHubRefs(url) {
|
|
@@ -179,6 +183,83 @@ export const TOOLS = [
|
|
|
179
183
|
},
|
|
180
184
|
handler: async (_repo, i) => buildGuide(TOOLS, typeof i.topic === "string" ? i.topic : undefined),
|
|
181
185
|
},
|
|
186
|
+
{
|
|
187
|
+
// ── M4 governance/review subset (docs/18 §4.4) ──
|
|
188
|
+
name: "avcs.governance.status",
|
|
189
|
+
description: "Read-only review state for a view: protection rules, head, your role, and the effective approvals.",
|
|
190
|
+
inputSchema: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
view: { type: "string", description: "default 'main'" },
|
|
194
|
+
as: { type: "string", description: "actor id whose role to report" },
|
|
195
|
+
checkpointOid: { type: "string", description: "report approvals for this checkpoint instead of the head" },
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
handler: async (repo, i) => {
|
|
199
|
+
const view = i.view ?? "main";
|
|
200
|
+
const [protection, head] = await Promise.all([repo.getProtection(view), repo.protectedHead(view)]);
|
|
201
|
+
const me = i.as ?? (await repo.localActorId());
|
|
202
|
+
const target = i.checkpointOid ?? head;
|
|
203
|
+
return {
|
|
204
|
+
view,
|
|
205
|
+
protection,
|
|
206
|
+
head,
|
|
207
|
+
myRole: me ? await repo.roleOf(me) : null,
|
|
208
|
+
approvals: target ? await repo.approvalsFor(target) : [],
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: "avcs.approval.record",
|
|
214
|
+
description: "Record a reviewer verdict on a checkpoint, signed with the reviewer's local key. Requires role >= reviewer.",
|
|
215
|
+
inputSchema: {
|
|
216
|
+
type: "object",
|
|
217
|
+
properties: {
|
|
218
|
+
checkpointOid: { type: "string" },
|
|
219
|
+
verdict: { type: "string", enum: ["approve", "request_changes"] },
|
|
220
|
+
by: { type: "string", description: "reviewer actor id" },
|
|
221
|
+
reason: { type: "string" },
|
|
222
|
+
},
|
|
223
|
+
required: ["checkpointOid", "by"],
|
|
224
|
+
},
|
|
225
|
+
// No human elicitation gate here, unlike decision.record: an approval is already gated
|
|
226
|
+
// downstream by role and signature, so a reviewer bot holding a key is the intended user.
|
|
227
|
+
handler: async (repo, i) => repo.approve(String(i.checkpointOid), String(i.by), i.verdict ?? "approve", typeof i.reason === "string" ? { reason: i.reason } : {}),
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
// ── M3 ContextPack (docs/18 §M3) ──
|
|
231
|
+
name: "avcs.context.build",
|
|
232
|
+
description: "Assemble working context for a scope under a byte budget: provenance, decisions, risks, history. Deterministic truncation.",
|
|
233
|
+
inputSchema: {
|
|
234
|
+
type: "object",
|
|
235
|
+
properties: {
|
|
236
|
+
intentOid: { type: "string", description: "scope = the intent's allowed scopes plus what its sessions actually touched" },
|
|
237
|
+
entityKeys: { type: "array", items: { type: "string" }, description: "explicit keys, e.g. ['file:src/a.ts']" },
|
|
238
|
+
paths: { type: "array", items: { type: "string" }, description: "file paths, resolved to file: keys" },
|
|
239
|
+
view: { type: "string", description: "default 'main'" },
|
|
240
|
+
maxBytes: { type: "number", description: "budget for the compact response; default 8192. Dropped sections are listed in budget.truncated." },
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
handler: (repo, i) => buildContextPack(repo, {
|
|
244
|
+
intentOid: i.intentOid,
|
|
245
|
+
entityKeys: i.entityKeys,
|
|
246
|
+
paths: i.paths,
|
|
247
|
+
view: i.view,
|
|
248
|
+
maxBytes: i.maxBytes,
|
|
249
|
+
}),
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "avcs.decision.recall",
|
|
253
|
+
description: "Prior human decisions for a conflict key plus the policies they taught. Read precedent before re-deciding.",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties: { conflictKey: { type: "string", description: "entity key, e.g. 'file:src/a.ts'" } },
|
|
257
|
+
},
|
|
258
|
+
handler: async (repo, i) => ({
|
|
259
|
+
decisions: typeof i.conflictKey === "string" ? await repo.recallDecisions(i.conflictKey) : [],
|
|
260
|
+
policies: await repo.learnedPolicies(),
|
|
261
|
+
}),
|
|
262
|
+
},
|
|
182
263
|
{
|
|
183
264
|
// ── M2 sync surface (docs/18 §M2): an agent never pulls by hand ──
|
|
184
265
|
name: "avcs.sync.pull",
|
|
@@ -850,7 +931,9 @@ export async function startMcpServer() {
|
|
|
850
931
|
process.exit(1);
|
|
851
932
|
}
|
|
852
933
|
const bootVersion = readPackageVersion();
|
|
853
|
-
|
|
934
|
+
// Phase 16 M4: resources are advertised as subscribable so a client can be TOLD the head
|
|
935
|
+
// moved instead of polling for it; prompts carry their facts pre-inlined.
|
|
936
|
+
const server = new sdk.Server({ name: "avcs", version: bootVersion ?? "0.0.0" }, { capabilities: { tools: {}, resources: { subscribe: true }, prompts: {} } });
|
|
854
937
|
server.setRequestHandler(typesMod.ListToolsRequestSchema, async () => ({
|
|
855
938
|
tools: TOOLS.map((t) => ({
|
|
856
939
|
name: t.name,
|
|
@@ -920,12 +1003,59 @@ export async function startMcpServer() {
|
|
|
920
1003
|
},
|
|
921
1004
|
};
|
|
922
1005
|
try {
|
|
923
|
-
|
|
1006
|
+
const out = await runTool(tool, repo, argsIn, ctx);
|
|
1007
|
+
// Phase 16 M4.3: what this client authored on IS the hot set worth interrupting it
|
|
1008
|
+
// for. A stdio server is one process per client, so this scope is exactly right.
|
|
1009
|
+
if (!out.isError && tool.name === "avcs.operation.propose" && typeof argsIn.path === "string") {
|
|
1010
|
+
watchers.get(await resolveRepoDir(callCwd, clientRoots))?.trackKeys([`file:${argsIn.path}`]);
|
|
1011
|
+
}
|
|
1012
|
+
return out;
|
|
924
1013
|
}
|
|
925
1014
|
finally {
|
|
926
1015
|
inFlight--;
|
|
927
1016
|
}
|
|
928
1017
|
});
|
|
1018
|
+
// ── M4.1/4.2: resources (subscribable) and prompts ──
|
|
1019
|
+
server.setRequestHandler(typesMod.ListResourcesRequestSchema, async () => ({ resources: RESOURCES }));
|
|
1020
|
+
server.setRequestHandler(typesMod.ReadResourceRequestSchema, async (req) => {
|
|
1021
|
+
const repo = await openRepo(undefined);
|
|
1022
|
+
return { contents: [{ uri: req.params.uri, mimeType: "application/json", text: await readResource(repo, req.params.uri, TOOLS) }] };
|
|
1023
|
+
});
|
|
1024
|
+
server.setRequestHandler(typesMod.ListPromptsRequestSchema, async () => ({ prompts: PROMPTS }));
|
|
1025
|
+
server.setRequestHandler(typesMod.GetPromptRequestSchema, async (req) => {
|
|
1026
|
+
const repo = await openRepo(undefined);
|
|
1027
|
+
const text = await buildPrompt(repo, req.params.name, req.params.arguments ?? {}, TOOLS);
|
|
1028
|
+
return { messages: [{ role: "user", content: { type: "text", text } }] };
|
|
1029
|
+
});
|
|
1030
|
+
// ── M4.3: local watcher → notifications ──
|
|
1031
|
+
// Polling is the correctness path (fs.watch drops events per-platform, and a missed head
|
|
1032
|
+
// advance is the failure this prevents). Set AVCS_MCP_WATCH_MS=0 to disable.
|
|
1033
|
+
const watchers = new Map();
|
|
1034
|
+
const watchMs = watchIntervalMs();
|
|
1035
|
+
if (watchMs > 0) {
|
|
1036
|
+
const tick = setInterval(() => {
|
|
1037
|
+
void (async () => {
|
|
1038
|
+
for (const [dir, repo] of repos) {
|
|
1039
|
+
let w = watchers.get(dir);
|
|
1040
|
+
if (!w) {
|
|
1041
|
+
w = new RepoWatcher(repo);
|
|
1042
|
+
watchers.set(dir, w);
|
|
1043
|
+
}
|
|
1044
|
+
for (const ev of await w.poll()) {
|
|
1045
|
+
// Subscribed clients get the resource-updated signal; everyone else still sees
|
|
1046
|
+
// the event as a log message, so a client without subscriptions is not blind.
|
|
1047
|
+
const uri = ev.type === "head-advanced" ? `avcs://view/${ev.view}/head`
|
|
1048
|
+
: ev.type === "conflict-opened" ? `avcs://view/main/conflicts`
|
|
1049
|
+
: null;
|
|
1050
|
+
if (uri)
|
|
1051
|
+
server.notification({ method: "notifications/resources/updated", params: { uri } }).catch(() => { });
|
|
1052
|
+
server.notification({ method: "notifications/message", params: { level: "info", logger: "avcs", data: ev } }).catch(() => { });
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
})();
|
|
1056
|
+
}, watchMs);
|
|
1057
|
+
tick.unref?.();
|
|
1058
|
+
}
|
|
929
1059
|
// Reload-on-update: a long-lived stdio server holds the code it was spawned with, so
|
|
930
1060
|
// an `npm i -g @izagood/avcs@latest` (or any update) does not reach a running process.
|
|
931
1061
|
// We can't hot-swap the loaded module, so instead we watch the installed package
|