@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.
@@ -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":"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"}
@@ -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;AAuC5E,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqBpF"}
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.contention.check", why: "see other actors' live work on your keys before you edit, not at finalize" },
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" },
@@ -1 +1 @@
1
- {"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/mcp/guide.ts"],"names":[],"mappings":"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"}
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":"AAAA,8CAA8C;AAC9C,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,uFAAuF;AACvF,gEAAgE;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUxC,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,qEAAqE;QAClF,SAAS,EAAE,EAAE;KACd;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EAAE,oFAAoF;QACjG,SAAS,EAAE;YACT,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,0BAA0B,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC9E,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,2CAA2C,EAAE;SAC5E;KACF;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EAAE,4EAA4E;QACzF,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,gCAAgC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;KAC5F;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,kFAAkF;QAC/F,SAAS,EAAE;YACT,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,yBAAyB,EAAE;YACxD,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,6BAA6B,EAAE;SACtE;KACF;CACF,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAU,EACV,IAAY,EACZ,IAA6B,EAC7B,QAAmB,EAAE;IAErB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,cAAc;YACjB,OAAO;gBACL,0EAA0E;gBAC1E,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;aAC3C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjB,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAC7D,MAAM,KAAK,GAAG;gBACZ,WAAW,MAAM,CAAC,KAAK,EAAE;gBACzB,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,kCAAkC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;gBAC1H,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,sBAAsB,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;gBACtH,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,oBAAoB,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;gBAChH,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,8BAA8B,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;gBAC9F,EAAE;gBACF,4FAA4F;gBAC5F,uFAAuF;aACxF,CAAC;YACF,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QAED,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACnF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YAC7C,OAAO;gBACL,iFAAiF;gBACjF,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;aAChC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC;QAED,KAAK,oBAAoB,CAAC,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;YAChE,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAChD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;gBACxB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;gBACxB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;aACvB,CAAC,CAAC;YACH,MAAM,EAAE,GAAG,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9E,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,OAAO;gBACL,mBAAmB,IAAI,WAAW,IAAI,IAAI,MAAM,UAAU,GAAG,CAAC,QAAQ,IAAI;gBAC1E,eAAe,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;gBAC3C,qBAAqB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;gBAChD,mBAAmB,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;gBACzC,EAAE;gBACF,kFAAkF;gBAClF,4BAA4B;aAC7B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;QAED;YACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -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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"}
@@ -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;AAmBtC,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,EA+pB1B,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA6HpD"}
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"}
@@ -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
- const server = new sdk.Server({ name: "avcs", version: bootVersion ?? "0.0.0" }, { capabilities: { tools: {} } });
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
- return await runTool(tool, repo, argsIn, ctx);
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