@algosuite/vo-mcp 0.1.0 → 0.2.0-beta.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/index.js CHANGED
@@ -1,4 +1,291 @@
1
1
  import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res, err) => function __init() {
5
+ if (err) throw err[0];
6
+ try {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ } catch (e) {
9
+ throw err = [e], e;
10
+ }
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // src/cloud/auth-token-source.ts
18
+ var auth_token_source_exports = {};
19
+ __export(auth_token_source_exports, {
20
+ FIREBASE_SECURETOKEN_URL: () => FIREBASE_SECURETOKEN_URL,
21
+ FIREBASE_TOKEN_REFERER: () => FIREBASE_TOKEN_REFERER,
22
+ createAuthTokenSourceFromEnv: () => createAuthTokenSourceFromEnv,
23
+ createFirebaseRefreshTokenSource: () => createFirebaseRefreshTokenSource,
24
+ createStaticTokenSource: () => createStaticTokenSource
25
+ });
26
+ function createStaticTokenSource(token, kind = "admin-token") {
27
+ const value = token.trim();
28
+ return { kind, getToken: async () => value.length > 0 ? value : null };
29
+ }
30
+ function createFirebaseRefreshTokenSource(opts) {
31
+ const refreshToken = opts.refreshToken.trim();
32
+ const apiKey = opts.apiKey.trim();
33
+ const now = opts.now ?? (() => Date.now());
34
+ const fetchFn = opts.fetchFn ?? globalThis.fetch;
35
+ let cachedToken = null;
36
+ let expiresAtMs = 0;
37
+ let inFlight = null;
38
+ async function refresh() {
39
+ try {
40
+ const res = await fetchFn(`${FIREBASE_SECURETOKEN_URL}?key=${encodeURIComponent(apiKey)}`, {
41
+ method: "POST",
42
+ headers: {
43
+ "content-type": "application/x-www-form-urlencoded",
44
+ referer: FIREBASE_TOKEN_REFERER
45
+ },
46
+ body: `grant_type=refresh_token&refresh_token=${encodeURIComponent(refreshToken)}`
47
+ });
48
+ const text = await res.text();
49
+ if (res.status < 200 || res.status >= 300) {
50
+ cachedToken = null;
51
+ return null;
52
+ }
53
+ const parsed = JSON.parse(text);
54
+ const idToken = typeof parsed.id_token === "string" ? parsed.id_token : "";
55
+ if (!idToken) {
56
+ cachedToken = null;
57
+ return null;
58
+ }
59
+ const expiresInSec = Number(parsed.expires_in);
60
+ const ttlMs = Number.isFinite(expiresInSec) && expiresInSec > 0 ? expiresInSec * 1e3 : 36e5;
61
+ cachedToken = idToken;
62
+ expiresAtMs = now() + ttlMs;
63
+ return idToken;
64
+ } catch {
65
+ cachedToken = null;
66
+ return null;
67
+ }
68
+ }
69
+ return {
70
+ kind: "firebase-refresh",
71
+ async getToken() {
72
+ if (cachedToken && now() < expiresAtMs - REFRESH_SKEW_MS) return cachedToken;
73
+ if (!inFlight) {
74
+ inFlight = refresh().finally(() => {
75
+ inFlight = null;
76
+ });
77
+ }
78
+ return inFlight;
79
+ }
80
+ };
81
+ }
82
+ function createAuthTokenSourceFromEnv(env = process.env, fetchFn, readStoredCred = () => null) {
83
+ const refreshToken = env["VO_USER_REFRESH_TOKEN"]?.trim();
84
+ const apiKey = env["VO_FIREBASE_API_KEY"]?.trim();
85
+ const idToken = env["VO_USER_ID_TOKEN"]?.trim();
86
+ const adminToken = env["VO_CONTROL_PLANE_ADMIN_TOKEN"]?.trim();
87
+ if (refreshToken || apiKey) {
88
+ if (!refreshToken || !apiKey) {
89
+ throw new Error(
90
+ "Per-user refresh auth requires BOTH VO_USER_REFRESH_TOKEN and VO_FIREBASE_API_KEY"
91
+ );
92
+ }
93
+ return createFirebaseRefreshTokenSource({
94
+ refreshToken,
95
+ apiKey,
96
+ ...fetchFn ? { fetchFn } : {}
97
+ });
98
+ }
99
+ if (idToken) return createStaticTokenSource(idToken, "firebase-id-token");
100
+ const stored = readStoredCred();
101
+ if (stored?.vo_credential && stored.vo_credential.trim()) {
102
+ return createStaticTokenSource(stored.vo_credential.trim(), "vo-credential");
103
+ }
104
+ if (stored && stored.refresh_token?.trim() && stored.api_key?.trim()) {
105
+ return createFirebaseRefreshTokenSource({
106
+ refreshToken: stored.refresh_token.trim(),
107
+ apiKey: stored.api_key.trim(),
108
+ ...fetchFn ? { fetchFn } : {}
109
+ });
110
+ }
111
+ if (adminToken) return createStaticTokenSource(adminToken, "admin-token");
112
+ return null;
113
+ }
114
+ var FIREBASE_SECURETOKEN_URL, FIREBASE_TOKEN_REFERER, REFRESH_SKEW_MS;
115
+ var init_auth_token_source = __esm({
116
+ "src/cloud/auth-token-source.ts"() {
117
+ "use strict";
118
+ FIREBASE_SECURETOKEN_URL = "https://securetoken.googleapis.com/v1/token";
119
+ FIREBASE_TOKEN_REFERER = "https://algosuite.ai/";
120
+ REFRESH_SKEW_MS = 6e4;
121
+ }
122
+ });
123
+
124
+ // src/cloud/keychain.ts
125
+ import { createRequire } from "node:module";
126
+ function loadKeyring() {
127
+ if (cached !== void 0) return cached;
128
+ try {
129
+ const req = createRequire(import.meta.url);
130
+ const mod = req("@napi-rs/keyring");
131
+ cached = mod && typeof mod.Entry === "function" ? mod : null;
132
+ } catch {
133
+ cached = null;
134
+ }
135
+ return cached;
136
+ }
137
+ function keychainAvailable() {
138
+ return loadKeyring() !== null;
139
+ }
140
+ function keychainGet() {
141
+ const k = loadKeyring();
142
+ if (!k) return null;
143
+ try {
144
+ return new k.Entry(SERVICE, ACCOUNT).getPassword();
145
+ } catch {
146
+ return null;
147
+ }
148
+ }
149
+ function keychainSet(secret) {
150
+ const k = loadKeyring();
151
+ if (!k) return false;
152
+ try {
153
+ new k.Entry(SERVICE, ACCOUNT).setPassword(secret);
154
+ return true;
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+ function keychainDelete() {
160
+ const k = loadKeyring();
161
+ if (!k) return false;
162
+ try {
163
+ return new k.Entry(SERVICE, ACCOUNT).deletePassword();
164
+ } catch {
165
+ return false;
166
+ }
167
+ }
168
+ var SERVICE, ACCOUNT, cached;
169
+ var init_keychain = __esm({
170
+ "src/cloud/keychain.ts"() {
171
+ "use strict";
172
+ SERVICE = "vo-mcp";
173
+ ACCOUNT = "refresh-credential";
174
+ }
175
+ });
176
+
177
+ // src/cloud/credential-store.ts
178
+ var credential_store_exports = {};
179
+ __export(credential_store_exports, {
180
+ KEYCHAIN_LOCATION: () => KEYCHAIN_LOCATION,
181
+ credentialPath: () => credentialPath,
182
+ readStoredCredential: () => readStoredCredential,
183
+ writeStoredCredential: () => writeStoredCredential
184
+ });
185
+ import { homedir as homedir3 } from "node:os";
186
+ import { join as join5, dirname as dirname4 } from "node:path";
187
+ import {
188
+ existsSync as existsSync3,
189
+ mkdirSync as mkdirSync2,
190
+ readFileSync as readFileSync5,
191
+ writeFileSync as writeFileSync2,
192
+ chmodSync as chmodSync2,
193
+ rmSync
194
+ } from "node:fs";
195
+ function credentialPath(env = process.env) {
196
+ const override = env["VO_MCP_CREDENTIALS_PATH"]?.trim();
197
+ if (override) return override;
198
+ return join5(homedir3(), ".config", "vo-mcp", "credentials.json");
199
+ }
200
+ function keychainEnabled(env, keychain) {
201
+ const disabled = (env["VO_MCP_DISABLE_KEYCHAIN"] ?? "").trim().toLowerCase();
202
+ if (disabled === "1" || disabled === "true" || disabled === "yes") return false;
203
+ return keychain.available();
204
+ }
205
+ function deserialize(raw) {
206
+ try {
207
+ const parsed = JSON.parse(raw);
208
+ const refresh = typeof parsed.refresh_token === "string" ? parsed.refresh_token.trim() : "";
209
+ const apiKey = typeof parsed.api_key === "string" ? parsed.api_key.trim() : "";
210
+ const voCred = typeof parsed.vo_credential === "string" ? parsed.vo_credential.trim() : "";
211
+ if (!voCred && (!refresh || !apiKey)) return null;
212
+ return {
213
+ ...refresh ? { refresh_token: refresh } : {},
214
+ ...apiKey ? { api_key: apiKey } : {},
215
+ ...voCred ? { vo_credential: voCred } : {},
216
+ ...typeof parsed.vo_credential_expires_at === "string" ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {},
217
+ ...typeof parsed.email === "string" ? { email: parsed.email } : {},
218
+ ...typeof parsed.stored_at === "string" ? { stored_at: parsed.stored_at } : {}
219
+ };
220
+ } catch {
221
+ return null;
222
+ }
223
+ }
224
+ function readFromFile(env) {
225
+ try {
226
+ const p = credentialPath(env);
227
+ if (!existsSync3(p)) return null;
228
+ return deserialize(readFileSync5(p, "utf8"));
229
+ } catch {
230
+ return null;
231
+ }
232
+ }
233
+ function readStoredCredential(env = process.env, keychain = realKeychain) {
234
+ if (keychainEnabled(env, keychain)) {
235
+ const raw = keychain.get();
236
+ const fromKeychain = raw ? deserialize(raw) : null;
237
+ if (fromKeychain) return fromKeychain;
238
+ }
239
+ return readFromFile(env);
240
+ }
241
+ function deleteFile(env) {
242
+ try {
243
+ rmSync(credentialPath(env), { force: true });
244
+ } catch {
245
+ }
246
+ }
247
+ function writeToFile(payload, env) {
248
+ const p = credentialPath(env);
249
+ mkdirSync2(dirname4(p), { recursive: true });
250
+ writeFileSync2(p, `${JSON.stringify(payload, null, 2)}
251
+ `, { mode: 384 });
252
+ try {
253
+ chmodSync2(p, 384);
254
+ } catch {
255
+ }
256
+ return p;
257
+ }
258
+ function writeStoredCredential(cred, storedAt, env = process.env, keychain = realKeychain) {
259
+ const payload = {
260
+ ...cred.refresh_token ? { refresh_token: cred.refresh_token } : {},
261
+ ...cred.api_key ? { api_key: cred.api_key } : {},
262
+ ...cred.vo_credential ? { vo_credential: cred.vo_credential } : {},
263
+ ...cred.vo_credential_expires_at ? { vo_credential_expires_at: cred.vo_credential_expires_at } : {},
264
+ ...cred.email ? { email: cred.email } : {},
265
+ stored_at: cred.stored_at ?? storedAt
266
+ };
267
+ if (keychainEnabled(env, keychain) && keychain.set(JSON.stringify(payload))) {
268
+ deleteFile(env);
269
+ return KEYCHAIN_LOCATION;
270
+ }
271
+ const p = writeToFile(payload, env);
272
+ if (keychainEnabled(env, keychain)) keychain.delete();
273
+ return p;
274
+ }
275
+ var realKeychain, KEYCHAIN_LOCATION;
276
+ var init_credential_store = __esm({
277
+ "src/cloud/credential-store.ts"() {
278
+ "use strict";
279
+ init_keychain();
280
+ realKeychain = {
281
+ available: keychainAvailable,
282
+ get: keychainGet,
283
+ set: keychainSet,
284
+ delete: keychainDelete
285
+ };
286
+ KEYCHAIN_LOCATION = 'OS keychain (service "vo-mcp")';
287
+ }
288
+ });
2
289
 
3
290
  // src/server.ts
4
291
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -987,10 +1274,10 @@ async function handleCheckAssertionStrength(deps, rawInput, _signal) {
987
1274
  const key = deps.cache.keyFor(TOOL_NAME, rawInput);
988
1275
  const excerpt = rawInput.source.slice(0, 300);
989
1276
  const inputSizeBytes = bytesOf(rawInput.source);
990
- const cached = deps.cache.get(key);
991
- if (cached) {
1277
+ const cached2 = deps.cache.get(key);
1278
+ if (cached2) {
992
1279
  const envelope2 = {
993
- ...cached.value,
1280
+ ...cached2.value,
994
1281
  cache: { hit: true, key }
995
1282
  };
996
1283
  deps.events.append({
@@ -1210,8 +1497,8 @@ async function handleCheckHollowTest(deps, rawInput, signal) {
1210
1497
  const key = deps.cache.keyFor(TOOL_NAME2, rawInput);
1211
1498
  const excerpt = rawInput.source.slice(0, 300);
1212
1499
  const inputSizeBytes = bytesOf(rawInput.source);
1213
- const cached = deps.cache.get(key);
1214
- if (cached !== null) {
1500
+ const cached2 = deps.cache.get(key);
1501
+ if (cached2 !== null) {
1215
1502
  const replayEvent = {
1216
1503
  ...buildBaseEvent({
1217
1504
  tool: TOOL_NAME2,
@@ -1222,14 +1509,14 @@ async function handleCheckHollowTest(deps, rawInput, signal) {
1222
1509
  session: deps.session,
1223
1510
  now: deps.now()
1224
1511
  }),
1225
- per_model_verdicts: cached.value.payload.per_model_verdicts,
1226
- synthesized_verdict: cached.value.payload.synthesized_verdict ?? null,
1227
- consensus_confidence: cached.value.payload.synthesized_verdict?.confidence ?? null,
1228
- consensus_engine_version: cached.value.payload.engine_version ?? null,
1512
+ per_model_verdicts: cached2.value.payload.per_model_verdicts,
1513
+ synthesized_verdict: cached2.value.payload.synthesized_verdict ?? null,
1514
+ consensus_confidence: cached2.value.payload.synthesized_verdict?.confidence ?? null,
1515
+ consensus_engine_version: cached2.value.payload.engine_version ?? null,
1229
1516
  cache_hit: true
1230
1517
  };
1231
1518
  deps.events.append(replayEvent);
1232
- return jsonContent({ ...cached.value, cache: { hit: true, key } });
1519
+ return jsonContent({ ...cached2.value, cache: { hit: true, key } });
1233
1520
  }
1234
1521
  const kbResult = findRulesByMetadata({ category: "testing" });
1235
1522
  const { topRules, truncated: kbTruncated } = prepareKBRules(kbResult.rules);
@@ -1394,8 +1681,8 @@ async function handleVerifyAnswer(deps, rawInput, signal) {
1394
1681
  const isDeep = gateType === DEEP_GATE;
1395
1682
  const kbResult = isDeep ? findRulesByMetadata({ category: "security" }) : { rules: [], error: null };
1396
1683
  const { topRules, truncated: kbTruncated } = prepareKBRules(kbResult.rules);
1397
- const cached = deps.cache.get(key);
1398
- if (cached !== null) {
1684
+ const cached2 = deps.cache.get(key);
1685
+ if (cached2 !== null) {
1399
1686
  const replayEvent = {
1400
1687
  ...buildBaseEvent({
1401
1688
  tool: TOOL_NAME3,
@@ -1406,14 +1693,14 @@ async function handleVerifyAnswer(deps, rawInput, signal) {
1406
1693
  session: deps.session,
1407
1694
  now: deps.now()
1408
1695
  }),
1409
- per_model_verdicts: cached.value.payload.per_model_verdicts,
1410
- synthesized_verdict: cached.value.payload.synthesized_verdict ?? null,
1411
- consensus_confidence: cached.value.payload.synthesized_verdict?.confidence ?? null,
1412
- consensus_engine_version: cached.value.payload.engine_version ?? null,
1696
+ per_model_verdicts: cached2.value.payload.per_model_verdicts,
1697
+ synthesized_verdict: cached2.value.payload.synthesized_verdict ?? null,
1698
+ consensus_confidence: cached2.value.payload.synthesized_verdict?.confidence ?? null,
1699
+ consensus_engine_version: cached2.value.payload.engine_version ?? null,
1413
1700
  cache_hit: true
1414
1701
  };
1415
1702
  deps.events.append(replayEvent);
1416
- return jsonContent({ ...cached.value, cache: { hit: true, key } });
1703
+ return jsonContent({ ...cached2.value, cache: { hit: true, key } });
1417
1704
  }
1418
1705
  const baseEvent = buildBaseEvent({
1419
1706
  tool: TOOL_NAME3,
@@ -1519,6 +1806,45 @@ var ALL_RECOGNIZED_GATE_TYPES = [
1519
1806
  ...KNOWN_GATE_TYPES
1520
1807
  ];
1521
1808
 
1809
+ // src/tools/consensus-judgment-source-grounded.ts
1810
+ function isStringArray(v) {
1811
+ return Array.isArray(v) && v.every((e) => typeof e === "string");
1812
+ }
1813
+ function isToolSourceGrounded(v) {
1814
+ if (typeof v !== "object" || v === null) return false;
1815
+ const o = v;
1816
+ if (o["enable_citation_grading"] !== void 0 && typeof o["enable_citation_grading"] !== "boolean") {
1817
+ return false;
1818
+ }
1819
+ if (o["escalate_below"] !== void 0 && typeof o["escalate_below"] !== "number") return false;
1820
+ return true;
1821
+ }
1822
+ function normalizeSourceGrounded(input) {
1823
+ const sourceUrls = input.source_urls !== void 0 ? input.source_urls.filter((u) => u.trim().length > 0) : [];
1824
+ const active = sourceUrls.length > 0;
1825
+ const gradingEnabled = active && input.source_grounded?.enable_citation_grading === true;
1826
+ const escalateBelow = input.source_grounded?.escalate_below;
1827
+ const config = gradingEnabled ? {
1828
+ citation_grader: {
1829
+ enabled: true,
1830
+ ...escalateBelow !== void 0 ? { escalate_below: escalateBelow } : {}
1831
+ }
1832
+ } : void 0;
1833
+ const cacheFragments = {};
1834
+ if (active) cacheFragments["source_urls"] = sourceUrls;
1835
+ if (gradingEnabled) {
1836
+ cacheFragments["citation_grading"] = true;
1837
+ if (escalateBelow !== void 0) cacheFragments["escalate_below"] = escalateBelow;
1838
+ }
1839
+ return {
1840
+ active,
1841
+ sourceUrls,
1842
+ gradingEnabled,
1843
+ ...config !== void 0 ? { config } : {},
1844
+ cacheFragments
1845
+ };
1846
+ }
1847
+
1522
1848
  // src/tools/consensus-judgment.ts
1523
1849
  var TOOL_NAME4 = "vo_consensus_judgment";
1524
1850
  var MAX_PROMPT_BYTES = 64 * 1024;
@@ -1541,6 +1867,26 @@ var inputSchema4 = {
1541
1867
  type: "object",
1542
1868
  description: "Tool-specific context (e.g. source file, diff, observed value).",
1543
1869
  additionalProperties: true
1870
+ },
1871
+ source_urls: {
1872
+ type: "array",
1873
+ items: { type: "string" },
1874
+ description: "Authoritative source URLs to ground the judgment against (Tier-4). When NON-EMPTY, the engine routes to its source-grounded path: it fetches the sources, flags low-confidence retrievals (surfaced as low_confidence_sources), and \u2014 when source_grounded.enable_citation_grading is true \u2014 grades each claim against the cited source text. When absent/empty the call uses the unchanged sourceless consensus path."
1875
+ },
1876
+ source_grounded: {
1877
+ type: "object",
1878
+ description: "Optional source-grounded behaviour toggles. Only meaningful when source_urls is non-empty.",
1879
+ properties: {
1880
+ enable_citation_grading: {
1881
+ type: "boolean",
1882
+ description: "Opt IN to deterministic citation grading (default OFF). A failing grade raises an escalation signal, so this is behaviour-changing. When true, a real claim classifier (a single cheap model call) grades each claim against the cited sources."
1883
+ },
1884
+ escalate_below: {
1885
+ type: "number",
1886
+ description: "Uncertain-claim escalation floor [0..1]; an uncertain claim with confidence below this triggers escalation. Engine default 0.85 when omitted."
1887
+ }
1888
+ },
1889
+ additionalProperties: false
1544
1890
  }
1545
1891
  },
1546
1892
  required: ["prompt"],
@@ -1552,6 +1898,8 @@ function isToolInput4(v) {
1552
1898
  const o = v;
1553
1899
  if (typeof o["prompt"] !== "string") return false;
1554
1900
  if (o["gate_type"] !== void 0 && typeof o["gate_type"] !== "string") return false;
1901
+ if (o["source_urls"] !== void 0 && !isStringArray(o["source_urls"])) return false;
1902
+ if (o["source_grounded"] !== void 0 && !isToolSourceGrounded(o["source_grounded"])) return false;
1555
1903
  return true;
1556
1904
  }
1557
1905
  function isAcceptedGateType(v) {
@@ -1577,15 +1925,20 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
1577
1925
  const rawGate = rawInput.gate_type ?? DEFAULT_GATE_TYPE;
1578
1926
  const gateType = isAcceptedGateType(rawGate) ? rawGate : DEFAULT_GATE_TYPE;
1579
1927
  const inputSizeBytes = bytesOf(rawInput.prompt) + bytesOf(contextStrForSize);
1928
+ const sg = normalizeSourceGrounded({
1929
+ ...rawInput.source_urls !== void 0 ? { source_urls: rawInput.source_urls } : {},
1930
+ ...rawInput.source_grounded !== void 0 ? { source_grounded: rawInput.source_grounded } : {}
1931
+ });
1580
1932
  const cacheInput = {
1581
1933
  prompt: rawInput.prompt,
1582
1934
  gate_type: gateType,
1583
- ...rawInput.context !== void 0 ? { context: rawInput.context } : {}
1935
+ ...rawInput.context !== void 0 ? { context: rawInput.context } : {},
1936
+ ...sg.cacheFragments
1584
1937
  };
1585
1938
  const key = deps.cache.keyFor(TOOL_NAME4, cacheInput);
1586
1939
  const excerpt = rawInput.prompt.slice(0, 300);
1587
- const cached = deps.cache.get(key);
1588
- if (cached !== null) {
1940
+ const cached2 = deps.cache.get(key);
1941
+ if (cached2 !== null) {
1589
1942
  const replayEvent = buildBaseEvent({
1590
1943
  tool: TOOL_NAME4,
1591
1944
  gateType,
@@ -1597,15 +1950,15 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
1597
1950
  });
1598
1951
  const enrichedReplay = {
1599
1952
  ...replayEvent,
1600
- per_model_verdicts: cached.value.payload.per_model_verdicts,
1601
- synthesized_verdict: cached.value.payload.synthesized_verdict ?? null,
1602
- consensus_confidence: cached.value.payload.synthesized_verdict?.confidence ?? null,
1603
- consensus_engine_version: cached.value.payload.engine_version ?? null,
1953
+ per_model_verdicts: cached2.value.payload.per_model_verdicts,
1954
+ synthesized_verdict: cached2.value.payload.synthesized_verdict ?? null,
1955
+ consensus_confidence: cached2.value.payload.synthesized_verdict?.confidence ?? null,
1956
+ consensus_engine_version: cached2.value.payload.engine_version ?? null,
1604
1957
  cache_hit: true
1605
1958
  };
1606
1959
  deps.events.append(enrichedReplay);
1607
1960
  const replayEnvelope = {
1608
- ...cached.value,
1961
+ ...cached2.value,
1609
1962
  cache: { hit: true, key }
1610
1963
  };
1611
1964
  return jsonContent(replayEnvelope);
@@ -1626,7 +1979,9 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
1626
1979
  gate_type: gateType,
1627
1980
  prompt: rawInput.prompt,
1628
1981
  ...rawInput.context !== void 0 ? { caller_context: rawInput.context } : {},
1629
- ...signal !== void 0 ? { signal } : {}
1982
+ ...signal !== void 0 ? { signal } : {},
1983
+ ...sg.active ? { source_urls: sg.sourceUrls } : {},
1984
+ ...sg.config !== void 0 ? { source_grounded: sg.config } : {}
1630
1985
  });
1631
1986
  } catch (err) {
1632
1987
  engineThrew = true;
@@ -1679,7 +2034,23 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
1679
2034
  synthesized_verdict: synthForEvent,
1680
2035
  engine_version: engineResult.engine_version,
1681
2036
  degraded: engineResult.degraded,
1682
- gate_type: gateType
2037
+ gate_type: gateType,
2038
+ // ─── Consensus-engine feature outputs (additive; 2026-06-13) ─────────────
2039
+ // Feature 2 (calibrated-confidence) — ON by default; the engine attaches
2040
+ // calibrated_confidence + confidence_badge to the synthesized verdict on the
2041
+ // plain runConsensus path. Surface them at the top level so callers don't
2042
+ // have to know the engine's internal SynthesizedVerdict shape.
2043
+ ...engineResult.synthesized_verdict.calibrated_confidence !== void 0 ? { calibrated_confidence: engineResult.synthesized_verdict.calibrated_confidence } : {},
2044
+ ...engineResult.synthesized_verdict.confidence_badge !== void 0 ? { confidence_badge: engineResult.synthesized_verdict.confidence_badge } : {},
2045
+ // Feature 1 (agreement-gate) — fan-out diagnostics (present iff the gate ran).
2046
+ ...engineResult.fan_out_diagnostics !== void 0 ? { fan_out_diagnostics: engineResult.fan_out_diagnostics } : {},
2047
+ // Source-grounded Tier-4 outputs (present iff the call was source-grounded).
2048
+ ...engineResult.source_grounded === true ? { source_grounded: true } : {},
2049
+ ...engineResult.citation_grade !== void 0 ? { citation_grade: engineResult.citation_grade } : {},
2050
+ ...engineResult.low_confidence_sources !== void 0 ? { low_confidence_sources: engineResult.low_confidence_sources } : {},
2051
+ // Escalation (from citation grade or human-tiebreak synthesizer).
2052
+ ...engineResult.escalation_required !== void 0 ? { escalation_required: engineResult.escalation_required } : {},
2053
+ ...engineResult.escalation_reason !== void 0 ? { escalation_reason: engineResult.escalation_reason } : {}
1683
2054
  };
1684
2055
  const envelope = {
1685
2056
  tool: TOOL_NAME4,
@@ -1771,8 +2142,8 @@ async function handleArchitectureReview(deps, rawInput, signal) {
1771
2142
  const key = deps.cache.keyFor(TOOL_NAME5, cacheInput);
1772
2143
  const excerpt = rawInput.diff.slice(0, 300);
1773
2144
  const inputSizeBytes = bytesOf(rawInput.diff) + (rawInput.summary !== void 0 ? bytesOf(rawInput.summary) : 0);
1774
- const cached = deps.cache.get(key);
1775
- if (cached !== null) {
2145
+ const cached2 = deps.cache.get(key);
2146
+ if (cached2 !== null) {
1776
2147
  const replayEvent = {
1777
2148
  ...buildBaseEvent({
1778
2149
  tool: TOOL_NAME5,
@@ -1783,14 +2154,14 @@ async function handleArchitectureReview(deps, rawInput, signal) {
1783
2154
  session: deps.session,
1784
2155
  now: deps.now()
1785
2156
  }),
1786
- per_model_verdicts: cached.value.payload.per_model_verdicts,
1787
- synthesized_verdict: cached.value.payload.synthesized_verdict ?? null,
1788
- consensus_confidence: cached.value.payload.synthesized_verdict?.confidence ?? null,
1789
- consensus_engine_version: cached.value.payload.engine_version ?? null,
2157
+ per_model_verdicts: cached2.value.payload.per_model_verdicts,
2158
+ synthesized_verdict: cached2.value.payload.synthesized_verdict ?? null,
2159
+ consensus_confidence: cached2.value.payload.synthesized_verdict?.confidence ?? null,
2160
+ consensus_engine_version: cached2.value.payload.engine_version ?? null,
1790
2161
  cache_hit: true
1791
2162
  };
1792
2163
  deps.events.append(replayEvent);
1793
- return jsonContent({ ...cached.value, cache: { hit: true, key } });
2164
+ return jsonContent({ ...cached2.value, cache: { hit: true, key } });
1794
2165
  }
1795
2166
  const kbResult = findRulesForDiff(rawInput.diff);
1796
2167
  const { topRules, truncated: kbTruncated } = prepareKBRules(kbResult.rules);
@@ -1902,8 +2273,11 @@ var ratchetIdSchema = z3.enum([
1902
2273
  ]);
1903
2274
  var thresholdSchema = z3.enum(["strict", "medium", "permissive"]);
1904
2275
  var userConfigSchema = z3.object({
1905
- enabled: z3.record(ratchetIdSchema, z3.boolean()).optional(),
1906
- thresholds: z3.record(ratchetIdSchema, thresholdSchema).optional(),
2276
+ // zod v4: z.record with ENUM keys validates exhaustively (every key
2277
+ // required); these are user OVERRIDE maps merged over DEFAULT_CONFIG,
2278
+ // so partial-by-design — z.partialRecord restores the v3 semantics.
2279
+ enabled: z3.partialRecord(ratchetIdSchema, z3.boolean()).optional(),
2280
+ thresholds: z3.partialRecord(ratchetIdSchema, thresholdSchema).optional(),
1907
2281
  allowlist: z3.object({
1908
2282
  paths: z3.array(z3.string()).optional(),
1909
2283
  rules: z3.array(z3.string()).optional()
@@ -3205,8 +3579,8 @@ async function handleDecomposeDispatch(deps, rawInput, signal) {
3205
3579
  const key = deps.cache.keyFor(TOOL_NAME7, cacheInput);
3206
3580
  const excerpt = rawInput.customer_goal.slice(0, 300);
3207
3581
  const inputSizeBytes = bytesOf(rawInput.customer_goal) + bytesOf(contextStrForSize);
3208
- const cached = deps.cache.get(key);
3209
- if (cached !== null) {
3582
+ const cached2 = deps.cache.get(key);
3583
+ if (cached2 !== null) {
3210
3584
  const replayEvent = {
3211
3585
  ...buildBaseEvent({
3212
3586
  tool: TOOL_NAME7,
@@ -3217,7 +3591,7 @@ async function handleDecomposeDispatch(deps, rawInput, signal) {
3217
3591
  session: deps.session,
3218
3592
  now: deps.now()
3219
3593
  }),
3220
- per_model_verdicts: cached.value.payload.per_model_plans.map((p) => ({
3594
+ per_model_verdicts: cached2.value.payload.per_model_plans.map((p) => ({
3221
3595
  model: p.model_id,
3222
3596
  model_id: p.model_id,
3223
3597
  provider: "cache-replay",
@@ -3230,12 +3604,12 @@ async function handleDecomposeDispatch(deps, rawInput, signal) {
3230
3604
  cited_sources: [],
3231
3605
  error: null
3232
3606
  })),
3233
- consensus_engine_version: cached.value.payload.engine_version ?? null,
3607
+ consensus_engine_version: cached2.value.payload.engine_version ?? null,
3234
3608
  cache_hit: true
3235
3609
  };
3236
3610
  deps.events.append(replayEvent);
3237
3611
  const replayEnvelope = {
3238
- ...cached.value,
3612
+ ...cached2.value,
3239
3613
  cache: { hit: true, key }
3240
3614
  };
3241
3615
  return jsonContent(replayEnvelope);
@@ -3343,22 +3717,9 @@ Produce the JSON dispatch plan now.`;
3343
3717
  return jsonContent(envelope);
3344
3718
  }
3345
3719
 
3346
- // src/cloud/credential-store.ts
3347
- import { homedir as homedir3 } from "node:os";
3348
- import { join as join5, dirname as dirname4 } from "node:path";
3349
- import {
3350
- existsSync as existsSync3,
3351
- mkdirSync as mkdirSync2,
3352
- readFileSync as readFileSync5,
3353
- writeFileSync as writeFileSync2,
3354
- chmodSync as chmodSync2,
3355
- rmSync
3356
- } from "node:fs";
3357
-
3358
- // src/cloud/keychain.ts
3359
- import { createRequire } from "node:module";
3360
-
3361
3720
  // src/cloud/admin-callable-client.ts
3721
+ init_auth_token_source();
3722
+ init_credential_store();
3362
3723
  var AdminCallableError = class extends Error {
3363
3724
  constructor(status, path3, message) {
3364
3725
  super(message);
@@ -4178,7 +4539,7 @@ var inputSchema19 = {
4178
4539
  additionalProperties: false
4179
4540
  };
4180
4541
  var description19 = "Reports per-session context-window utilization to VO and returns a directive: 'continue' (under 70%), 'prepare_handoff' (70-84%), or 'execute_handoff_now' (\u226585%). Implements V1 launch gate #9 (fleet context lifecycle management) per the official VO roadmap. V1 backend is stub-local \u2014 computes the directive purely from `context_used_pct` against the documented thresholds without a network call. Phase 3 wires this to the deployed vo-control-plane HTTP API; the response shape stays stable across the cutover (`backend_mode` field in the payload tells the caller which mode produced the verdict).";
4181
- function isStringArray(v, maxItems) {
4542
+ function isStringArray2(v, maxItems) {
4182
4543
  if (!Array.isArray(v)) return false;
4183
4544
  if (v.length > maxItems) return false;
4184
4545
  return v.every((item) => typeof item === "string");
@@ -4194,14 +4555,64 @@ function isToolInput19(v) {
4194
4555
  if (!Number.isFinite(o["context_used_pct"])) return false;
4195
4556
  if (o["context_used_pct"] < 0 || o["context_used_pct"] > 100) return false;
4196
4557
  if (o["current_goal"] !== void 0 && typeof o["current_goal"] !== "string") return false;
4197
- if (o["recent_files_touched"] !== void 0 && !isStringArray(o["recent_files_touched"], MAX_RECENT_FILES)) {
4558
+ if (o["recent_files_touched"] !== void 0 && !isStringArray2(o["recent_files_touched"], MAX_RECENT_FILES)) {
4198
4559
  return false;
4199
4560
  }
4200
- if (o["recent_tool_uses"] !== void 0 && !isStringArray(o["recent_tool_uses"], MAX_RECENT_TOOLS)) {
4561
+ if (o["recent_tool_uses"] !== void 0 && !isStringArray2(o["recent_tool_uses"], MAX_RECENT_TOOLS)) {
4201
4562
  return false;
4202
4563
  }
4203
4564
  return true;
4204
4565
  }
4566
+ function getCloudConfig() {
4567
+ const url = process.env["VO_CONTROL_PLANE_URL"];
4568
+ const token = process.env["VO_CONTROL_PLANE_ADMIN_TOKEN"];
4569
+ if (!url || !token) return null;
4570
+ return { url, token };
4571
+ }
4572
+ async function tryCloudReportState(cloud, input) {
4573
+ try {
4574
+ const body = {
4575
+ context_used_pct: input.context_used_pct
4576
+ };
4577
+ if (input.current_goal !== void 0) body["current_goal"] = input.current_goal;
4578
+ if (input.recent_files_touched !== void 0) {
4579
+ body["recent_files_touched"] = input.recent_files_touched;
4580
+ }
4581
+ if (input.recent_tool_uses !== void 0) {
4582
+ body["recent_tool_uses"] = input.recent_tool_uses;
4583
+ }
4584
+ const url = `${cloud.url}/api/v1/session/${input.session_id}/report-state`;
4585
+ const response = await fetch(url, {
4586
+ method: "POST",
4587
+ headers: {
4588
+ "Content-Type": "application/json",
4589
+ "Authorization": `Bearer ${cloud.token}`
4590
+ },
4591
+ body: JSON.stringify(body)
4592
+ });
4593
+ if (!response.ok) {
4594
+ return null;
4595
+ }
4596
+ const data = await response.json();
4597
+ if (!data.ok || !data.session || !data.directive) {
4598
+ return null;
4599
+ }
4600
+ return {
4601
+ directive: data.directive.action,
4602
+ message: data.directive.message,
4603
+ session_id: data.session.session_id,
4604
+ operator_id: data.session.operator_id,
4605
+ agent_type: input.agent_type,
4606
+ context_used_pct: data.session.context_used_pct,
4607
+ backend_mode: "cloud-control-plane",
4608
+ ts: data.session.last_seen_at,
4609
+ schema_version: 1,
4610
+ ...data.directive.action === "execute_handoff_now" ? { handoff_path: suggestedHandoffPath(data.session.session_id, data.session.last_seen_at) } : {}
4611
+ };
4612
+ } catch {
4613
+ return null;
4614
+ }
4615
+ }
4205
4616
  async function handleReportSessionState(deps, rawInput, _signal) {
4206
4617
  if (!isToolInput19(rawInput)) {
4207
4618
  throw invalidParams(
@@ -4209,6 +4620,13 @@ async function handleReportSessionState(deps, rawInput, _signal) {
4209
4620
  `invalid input. Required fields: operator_id (non-empty string), session_id (non-empty string), agent_type (one of: ${VALID_AGENT_TYPES.join(" | ")}), context_used_pct (number 0-100). Optional: current_goal (string \u2264${MAX_GOAL_CHARS} chars), recent_files_touched (string[] \u2264${MAX_RECENT_FILES}), recent_tool_uses (string[] \u2264${MAX_RECENT_TOOLS}).`
4210
4621
  );
4211
4622
  }
4623
+ const cloud = getCloudConfig();
4624
+ if (cloud !== null) {
4625
+ const cloudPayload = await tryCloudReportState(cloud, rawInput);
4626
+ if (cloudPayload !== null) {
4627
+ return jsonContent(cloudPayload);
4628
+ }
4629
+ }
4212
4630
  const directive = computeDirective(rawInput.context_used_pct);
4213
4631
  const ts = deps.now().toISOString();
4214
4632
  const payload = {
@@ -4226,6 +4644,141 @@ async function handleReportSessionState(deps, rawInput, _signal) {
4226
4644
  return jsonContent(payload);
4227
4645
  }
4228
4646
 
4647
+ // src/tools/session/spawn-successor.ts
4648
+ import { spawn } from "node:child_process";
4649
+ import { homedir as homedir4 } from "node:os";
4650
+ import { join as join6 } from "node:path";
4651
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
4652
+ var TOOL_NAME20 = "vo_spawn_successor";
4653
+ var MAX_HANDOFF_BYTES = 64e3;
4654
+ var inputSchema20 = {
4655
+ type: "object",
4656
+ properties: {
4657
+ handoff_path: {
4658
+ type: "string",
4659
+ description: "Path to the handoff doc to pre-inject. Default: the newest .md in ~/.vo/handoffs/."
4660
+ },
4661
+ goal: {
4662
+ type: "string",
4663
+ description: "Optional one-line goal override appended after the handoff."
4664
+ },
4665
+ cwd: {
4666
+ type: "string",
4667
+ description: "Working directory for the successor (default: the repo the handoff names, else process cwd)."
4668
+ },
4669
+ max_turns: {
4670
+ type: "number",
4671
+ description: "Optional --max-turns bound for the successor."
4672
+ }
4673
+ },
4674
+ required: [],
4675
+ additionalProperties: false
4676
+ };
4677
+ var description20 = "Mode B auto-handoff (roadmap \xA73.4): spawn a DETACHED headless `claude -p` successor with a handoff doc pre-injected into its prompt. Defaults to the newest handoff in ~/.vo/handoffs/. Returns {spawned, pid, log_path, handoff_path}. The successor works under the same gates as any session (ADR-001: verify-before-act, human merge approval) \u2014 this tool never fires autonomously.";
4678
+ function isToolInput20(v) {
4679
+ if (typeof v !== "object" || v === null) return false;
4680
+ const o = v;
4681
+ if (o["handoff_path"] !== void 0 && typeof o["handoff_path"] !== "string") return false;
4682
+ if (o["goal"] !== void 0 && typeof o["goal"] !== "string") return false;
4683
+ if (o["cwd"] !== void 0 && typeof o["cwd"] !== "string") return false;
4684
+ if (o["max_turns"] !== void 0 && typeof o["max_turns"] !== "number") return false;
4685
+ return true;
4686
+ }
4687
+ function newestHandoff(dir = join6(homedir4(), ".vo", "handoffs")) {
4688
+ try {
4689
+ const entries = readdirSync3(dir).filter((f) => f.endsWith(".md")).map((f) => ({ f, m: statSync3(join6(dir, f)).mtimeMs })).sort((a, b) => b.m - a.m);
4690
+ return entries.length > 0 && entries[0] ? join6(dir, entries[0].f) : null;
4691
+ } catch {
4692
+ return null;
4693
+ }
4694
+ }
4695
+ var MANDATORY_READS = [
4696
+ "CLAUDE.md + AGENTS.md + README.md (repo root)",
4697
+ "docs/current/virtual-office-agent-charter.md, -operating-model.md, -test-architect.md",
4698
+ "docs/current/evidence-grounded-consensus-testing.md",
4699
+ "docs/vo/ADR-001-* (verify + sign, human approves merge; no autonomous bot-merge / headless triggers) + docs/vo/vo-adr-002-two-plane-moat.md",
4700
+ "docs/vo/vo-roadmap-2026-05-26.md (read the Change log tail for current state)",
4701
+ "the operator memory index ~/.claude/projects/C--Users-greyl/memory/MEMORY.md"
4702
+ ];
4703
+ function buildSuccessorPrompt(handoffMarkdown, goal) {
4704
+ const reads = MANDATORY_READS.map((r, i) => ` ${i + 1}. ${r}`).join("\n");
4705
+ const lines = [
4706
+ "You are the SUCCESSOR agent for a Virtual Office lane. The previous session",
4707
+ "exhausted its context and wrote the handoff below. Read it fully, verify its",
4708
+ '"verification needed" items against live state (a handoff is a claim, not',
4709
+ "evidence \u2014 verify via `git show origin/main:<path>`), then continue the lane.",
4710
+ "",
4711
+ "MANDATORY READS before writing any code (NOT all auto-loaded \u2014 open them):",
4712
+ reads,
4713
+ "",
4714
+ "NON-NEGOTIABLES: multi-model consensus verification is the core; test honesty",
4715
+ "(verified-answer-only, no fake green); verify-before-act + human merge approval;",
4716
+ "never a full functions-shared deploy; Gen2 only; work in a worktree on your own",
4717
+ "branch; finish line is MERGED + DEPLOYED + LIVE-VERIFIED, and VO changes update",
4718
+ "the roadmap in the same PR.",
4719
+ "",
4720
+ "--- HANDOFF ---",
4721
+ handoffMarkdown,
4722
+ "--- END HANDOFF ---"
4723
+ ];
4724
+ if (goal && goal.trim().length > 0) lines.push("", `OPERATOR GOAL OVERRIDE: ${goal.trim()}`);
4725
+ return lines.join("\n");
4726
+ }
4727
+ function buildSuccessorArgs(maxTurns) {
4728
+ const args = ["-p", "--permission-mode", "acceptEdits"];
4729
+ if (Number.isInteger(maxTurns) && maxTurns > 0) {
4730
+ args.push("--max-turns", String(maxTurns));
4731
+ }
4732
+ return args;
4733
+ }
4734
+ async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn) {
4735
+ if (!isToolInput20(rawInput)) {
4736
+ throw invalidParams(TOOL_NAME20, "invalid input. Optional: { handoff_path, goal, cwd, max_turns }.");
4737
+ }
4738
+ const handoffPath = rawInput.handoff_path?.trim() || newestHandoff();
4739
+ if (!handoffPath || !existsSync4(handoffPath)) {
4740
+ return jsonContent({
4741
+ tool: TOOL_NAME20,
4742
+ schema_version: 1,
4743
+ payload: {
4744
+ spawned: false,
4745
+ reason: rawInput.handoff_path ? `handoff not found: ${rawInput.handoff_path}` : "no handoff docs in ~/.vo/handoffs \u2014 write one first (the 85% directive does this)"
4746
+ }
4747
+ });
4748
+ }
4749
+ const handoff = readFileSync6(handoffPath, "utf8").slice(0, MAX_HANDOFF_BYTES);
4750
+ const prompt = buildSuccessorPrompt(handoff, rawInput.goal);
4751
+ const logDir = process.env["VO_MCP_SUCCESSOR_LOG_DIR"]?.trim() || join6(homedir4(), ".vo", "successors");
4752
+ mkdirSync3(logDir, { recursive: true });
4753
+ const logPath = join6(logDir, `successor-${Date.now()}.log`);
4754
+ const logFd = openSync(logPath, "a");
4755
+ const child = spawnImpl("claude", buildSuccessorArgs(rawInput.max_turns), {
4756
+ cwd: rawInput.cwd?.trim() || process.cwd(),
4757
+ detached: true,
4758
+ stdio: ["pipe", logFd, logFd],
4759
+ // Windows: `claude` is a .cmd shim — needs a shell to resolve. The prompt
4760
+ // goes via STDIN below, never argv, so the shell never sees it.
4761
+ shell: process.platform === "win32",
4762
+ windowsHide: true
4763
+ });
4764
+ let spawnError = null;
4765
+ child.on("error", (e) => {
4766
+ spawnError = e.message;
4767
+ });
4768
+ try {
4769
+ child.stdin.write(prompt);
4770
+ child.stdin.end();
4771
+ } catch {
4772
+ }
4773
+ child.unref();
4774
+ await new Promise((r) => setTimeout(r, 150));
4775
+ return jsonContent({
4776
+ tool: TOOL_NAME20,
4777
+ schema_version: 1,
4778
+ payload: spawnError ? { spawned: false, reason: `spawn failed: ${spawnError}`, handoff_path: handoffPath } : { spawned: true, pid: child.pid ?? null, log_path: logPath, handoff_path: handoffPath }
4779
+ });
4780
+ }
4781
+
4229
4782
  // src/tools/concierge/common-concierge.ts
4230
4783
  var CONCIERGE_STUB_REASON = "cloud mode not active in this MCP runtime \u2014 set VO_CONTROL_PLANE_URL + VO_CONTROL_PLANE_ADMIN_TOKEN to enable. The server-side /api/v1/admin/concierge/dispatch endpoint IS built + deployed (vo-control-plane #5724/#5734); in cloud mode this tool returns the routed pack README + file index.";
4231
4784
  var CONCIERGE_GATE_TYPE = "concierge-dispatch";
@@ -4244,10 +4797,10 @@ function isKnownConciergePack(value) {
4244
4797
  }
4245
4798
 
4246
4799
  // src/tools/concierge/dispatch.ts
4247
- var TOOL_NAME20 = "vo_concierge_dispatch";
4800
+ var TOOL_NAME21 = "vo_concierge_dispatch";
4248
4801
  var CALLABLE_NAME10 = "voConciergeDispatch";
4249
4802
  var ADMIN_PATH10 = "/api/v1/admin/concierge/dispatch";
4250
- var inputSchema20 = {
4803
+ var inputSchema21 = {
4251
4804
  type: "object",
4252
4805
  properties: {
4253
4806
  pack: {
@@ -4262,8 +4815,8 @@ var inputSchema20 = {
4262
4815
  },
4263
4816
  additionalProperties: false
4264
4817
  };
4265
- var description20 = "Dispatches a provider-scoped knowledge pack (gcp | firebase | aws | cloudflare | vercel | netlify | tax | hybrid). Cross-vendor MCP equivalent of the /vo-concierge Claude-Code slash command. Route explicitly via `pack`, or via tenant.cloud_provider by passing `tenant_id`. Returns the pack's README (`readme_markdown`) + file index. In cloud mode, dispatches via vo-control-plane and returns `verdict: 'pass'` with the pack/directory data; without cloud config, returns `verdict: 'unimplemented'`.";
4266
- function isToolInput20(v) {
4818
+ var description21 = "Dispatches a provider-scoped knowledge pack (gcp | firebase | aws | cloudflare | vercel | netlify | tax | hybrid). Cross-vendor MCP equivalent of the /vo-concierge Claude-Code slash command. Route explicitly via `pack`, or via tenant.cloud_provider by passing `tenant_id`. Returns the pack's README (`readme_markdown`) + file index. In cloud mode, dispatches via vo-control-plane and returns `verdict: 'pass'` with the pack/directory data; without cloud config, returns `verdict: 'unimplemented'`.";
4819
+ function isToolInput21(v) {
4267
4820
  if (typeof v !== "object" || v === null) return false;
4268
4821
  const obj = v;
4269
4822
  if (obj.pack !== void 0 && typeof obj.pack !== "string") return false;
@@ -4271,15 +4824,15 @@ function isToolInput20(v) {
4271
4824
  return true;
4272
4825
  }
4273
4826
  async function handleConciergeDispatch(deps, rawInput, _signal) {
4274
- if (!isToolInput20(rawInput)) {
4827
+ if (!isToolInput21(rawInput)) {
4275
4828
  throw invalidParams(
4276
- TOOL_NAME20,
4829
+ TOOL_NAME21,
4277
4830
  "invalid input. Expected { pack?: string, tenant_id?: string }."
4278
4831
  );
4279
4832
  }
4280
4833
  if (rawInput.pack !== void 0 && rawInput.pack !== "" && !isKnownConciergePack(rawInput.pack)) {
4281
4834
  throw invalidParams(
4282
- TOOL_NAME20,
4835
+ TOOL_NAME21,
4283
4836
  `unknown pack: ${JSON.stringify(rawInput.pack)}. Known packs: ${KNOWN_CONCIERGE_PACKS.join(", ")}.`
4284
4837
  );
4285
4838
  }
@@ -4290,7 +4843,7 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
4290
4843
  if (rawInput.pack) cloudBody.pack = rawInput.pack;
4291
4844
  if (rawInput.tenant_id) cloudBody.tenantId = rawInput.tenant_id;
4292
4845
  return buildCloudOrStubResponse({
4293
- toolName: TOOL_NAME20,
4846
+ toolName: TOOL_NAME21,
4294
4847
  callableName: CALLABLE_NAME10,
4295
4848
  adminPath: ADMIN_PATH10,
4296
4849
  normalizedInput,
@@ -4307,6 +4860,254 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
4307
4860
  });
4308
4861
  }
4309
4862
 
4863
+ // src/tools/memory/sync-config.ts
4864
+ import { homedir as homedir5 } from "node:os";
4865
+ import { join as join7 } from "node:path";
4866
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "node:fs";
4867
+ var TOOL_NAME22 = "vo_sync_config";
4868
+ var inputSchema22 = {
4869
+ type: "object",
4870
+ properties: {
4871
+ action: {
4872
+ type: "string",
4873
+ enum: ["pull", "push"],
4874
+ description: "pull: download cloud memory to local files. push: upload local files to cloud."
4875
+ },
4876
+ cwd: {
4877
+ type: "string",
4878
+ description: "Working directory to derive project slug from (default: process.cwd())."
4879
+ }
4880
+ },
4881
+ required: ["action"],
4882
+ additionalProperties: false
4883
+ };
4884
+ var description22 = "Syncs memory entries between local ~/.claude/projects/<slug>/memory/ and cloud control-plane /api/v1/agent-config/memory/me. Requires operator auth (vo-mcp login). Actions: pull (cloud\u2192local), push (local\u2192cloud). Idempotent; push creates/updates as needed.";
4885
+ function isToolInput22(v) {
4886
+ if (typeof v !== "object" || v === null) return false;
4887
+ const o = v;
4888
+ if (o["action"] !== "pull" && o["action"] !== "push") return false;
4889
+ if (o["cwd"] !== void 0 && typeof o["cwd"] !== "string") return false;
4890
+ return true;
4891
+ }
4892
+ function deriveProjectSlug(cwd) {
4893
+ const normalized = cwd.replace(/\\/g, "/");
4894
+ return normalized.replace(/^([A-Z]):/i, (_, drive) => `${drive.toUpperCase()}-`).replace(/\/$/g, "").split("/").join("--").replace(/\s+/g, "-");
4895
+ }
4896
+ function getMemoryDir(cwd) {
4897
+ const slug = deriveProjectSlug(cwd);
4898
+ return join7(homedir5(), ".claude", "projects", slug, "memory");
4899
+ }
4900
+ async function pullMemory(controlPlaneUrl, token, memoryDir, sessionId, fetchFn) {
4901
+ const url = `${controlPlaneUrl}/api/v1/agent-config/memory/me`;
4902
+ const response = await fetchFn(url, {
4903
+ method: "GET",
4904
+ headers: {
4905
+ authorization: `Bearer ${token}`
4906
+ }
4907
+ });
4908
+ if (response.status !== 200) {
4909
+ const text = await response.text();
4910
+ throw new Error(`GET /api/v1/agent-config/memory/me returned HTTP ${response.status}: ${text.slice(0, 200)}`);
4911
+ }
4912
+ const data = JSON.parse(await response.text());
4913
+ if (!data.ok || !Array.isArray(data.entries)) {
4914
+ throw new Error("GET /api/v1/agent-config/memory/me response missing ok=true or entries array");
4915
+ }
4916
+ mkdirSync4(memoryDir, { recursive: true });
4917
+ const files = [];
4918
+ for (const entry of data.entries) {
4919
+ const filePath = join7(memoryDir, entry.file_name);
4920
+ writeFileSync3(filePath, entry.content, "utf8");
4921
+ files.push(entry.file_name);
4922
+ }
4923
+ return { pulled: data.entries.length, files };
4924
+ }
4925
+ async function pushMemory(controlPlaneUrl, token, memoryDir, sessionId, fetchFn) {
4926
+ if (!existsSync5(memoryDir)) {
4927
+ return { pushed: 0, created: 0, updated: 0 };
4928
+ }
4929
+ const localFiles = readdirSync4(memoryDir).filter((f) => f.endsWith(".md")).map((f) => ({
4930
+ file_name: f,
4931
+ content: readFileSync7(join7(memoryDir, f), "utf8"),
4932
+ entry_type: f === "MEMORY.md" ? "index" : "topic"
4933
+ }));
4934
+ if (localFiles.length === 0) {
4935
+ return { pushed: 0, created: 0, updated: 0 };
4936
+ }
4937
+ const getUrl = `${controlPlaneUrl}/api/v1/agent-config/memory/me`;
4938
+ const getResponse = await fetchFn(getUrl, {
4939
+ method: "GET",
4940
+ headers: {
4941
+ authorization: `Bearer ${token}`
4942
+ }
4943
+ });
4944
+ const existingMap = /* @__PURE__ */ new Map();
4945
+ if (getResponse.status === 200) {
4946
+ const getData = JSON.parse(await getResponse.text());
4947
+ if (getData.ok && Array.isArray(getData.entries)) {
4948
+ for (const entry of getData.entries) {
4949
+ existingMap.set(entry.file_name, entry.memory_id);
4950
+ }
4951
+ }
4952
+ }
4953
+ let created = 0;
4954
+ let updated = 0;
4955
+ for (const localFile of localFiles) {
4956
+ const memoryId = existingMap.get(localFile.file_name);
4957
+ if (memoryId) {
4958
+ const updateUrl = `${controlPlaneUrl}/api/v1/agent-config/memory/${memoryId}`;
4959
+ const updateBody = {
4960
+ content: localFile.content,
4961
+ session_id: sessionId
4962
+ };
4963
+ const updateResponse = await fetchFn(updateUrl, {
4964
+ method: "PUT",
4965
+ headers: {
4966
+ authorization: `Bearer ${token}`,
4967
+ "content-type": "application/json"
4968
+ },
4969
+ body: JSON.stringify(updateBody)
4970
+ });
4971
+ if (updateResponse.status !== 200) {
4972
+ const text = await updateResponse.text();
4973
+ throw new Error(
4974
+ `PUT /api/v1/agent-config/memory/${memoryId} returned HTTP ${updateResponse.status}: ${text.slice(0, 200)}`
4975
+ );
4976
+ }
4977
+ const updateData = JSON.parse(await updateResponse.text());
4978
+ if (!updateData.ok) {
4979
+ throw new Error(`PUT /api/v1/agent-config/memory/${memoryId} returned ok=false`);
4980
+ }
4981
+ updated++;
4982
+ } else {
4983
+ const createUrl = `${controlPlaneUrl}/api/v1/agent-config/memory/me`;
4984
+ const createBody = {
4985
+ entry_type: localFile.entry_type,
4986
+ file_name: localFile.file_name,
4987
+ content: localFile.content,
4988
+ session_id: sessionId
4989
+ };
4990
+ const createResponse = await fetchFn(createUrl, {
4991
+ method: "POST",
4992
+ headers: {
4993
+ authorization: `Bearer ${token}`,
4994
+ "content-type": "application/json"
4995
+ },
4996
+ body: JSON.stringify(createBody)
4997
+ });
4998
+ if (createResponse.status !== 200 && createResponse.status !== 201) {
4999
+ const text = await createResponse.text();
5000
+ throw new Error(
5001
+ `POST /api/v1/agent-config/memory/me returned HTTP ${createResponse.status}: ${text.slice(0, 200)}`
5002
+ );
5003
+ }
5004
+ const createData = JSON.parse(await createResponse.text());
5005
+ if (!createData.ok) {
5006
+ throw new Error("POST /api/v1/agent-config/memory/me returned ok=false");
5007
+ }
5008
+ created++;
5009
+ }
5010
+ }
5011
+ return { pushed: localFiles.length, created, updated };
5012
+ }
5013
+ async function handleSyncConfig(deps, rawInput, _signal, fetchFn = globalThis.fetch) {
5014
+ if (!isToolInput22(rawInput)) {
5015
+ throw invalidParams(
5016
+ TOOL_NAME22,
5017
+ 'invalid input. Required: { action: "pull" | "push" }. Optional: { cwd: "<path>" }.'
5018
+ );
5019
+ }
5020
+ const controlPlaneUrl = process.env["VO_CONTROL_PLANE_URL"];
5021
+ if (!controlPlaneUrl) {
5022
+ return jsonContent({
5023
+ tool: TOOL_NAME22,
5024
+ schema_version: 1,
5025
+ payload: {
5026
+ synced: false,
5027
+ reason: "VO_CONTROL_PLANE_URL not set \u2014 cloud mode disabled"
5028
+ }
5029
+ });
5030
+ }
5031
+ const { createAuthTokenSourceFromEnv: createAuthTokenSourceFromEnv2 } = await Promise.resolve().then(() => (init_auth_token_source(), auth_token_source_exports));
5032
+ const { readStoredCredential: readStoredCredential2 } = await Promise.resolve().then(() => (init_credential_store(), credential_store_exports));
5033
+ const tokenSource = createAuthTokenSourceFromEnv2(process.env, fetchFn, () => readStoredCredential2(process.env));
5034
+ if (!tokenSource) {
5035
+ return jsonContent({
5036
+ tool: TOOL_NAME22,
5037
+ schema_version: 1,
5038
+ payload: {
5039
+ synced: false,
5040
+ reason: "No auth configured. Run `vo-mcp login` to authenticate as an operator."
5041
+ }
5042
+ });
5043
+ }
5044
+ const token = await tokenSource.getToken();
5045
+ if (!token) {
5046
+ return jsonContent({
5047
+ tool: TOOL_NAME22,
5048
+ schema_version: 1,
5049
+ payload: {
5050
+ synced: false,
5051
+ reason: "Failed to obtain auth token. Run `vo-mcp login` to re-authenticate."
5052
+ }
5053
+ });
5054
+ }
5055
+ const cwd = rawInput.cwd?.trim() || process.cwd();
5056
+ const memoryDir = getMemoryDir(cwd);
5057
+ try {
5058
+ if (rawInput.action === "pull") {
5059
+ const result = await pullMemory(
5060
+ controlPlaneUrl.replace(/\/+$/, ""),
5061
+ token,
5062
+ memoryDir,
5063
+ deps.sessionId,
5064
+ fetchFn
5065
+ );
5066
+ return jsonContent({
5067
+ tool: TOOL_NAME22,
5068
+ schema_version: 1,
5069
+ payload: {
5070
+ synced: true,
5071
+ action: "pull",
5072
+ pulled: result.pulled,
5073
+ files: result.files,
5074
+ memory_dir: memoryDir
5075
+ }
5076
+ });
5077
+ } else {
5078
+ const result = await pushMemory(
5079
+ controlPlaneUrl.replace(/\/+$/, ""),
5080
+ token,
5081
+ memoryDir,
5082
+ deps.sessionId,
5083
+ fetchFn
5084
+ );
5085
+ return jsonContent({
5086
+ tool: TOOL_NAME22,
5087
+ schema_version: 1,
5088
+ payload: {
5089
+ synced: true,
5090
+ action: "push",
5091
+ pushed: result.pushed,
5092
+ created: result.created,
5093
+ updated: result.updated,
5094
+ memory_dir: memoryDir
5095
+ }
5096
+ });
5097
+ }
5098
+ } catch (err) {
5099
+ const message = err instanceof Error ? err.message : String(err);
5100
+ return jsonContent({
5101
+ tool: TOOL_NAME22,
5102
+ schema_version: 1,
5103
+ payload: {
5104
+ synced: false,
5105
+ reason: `Sync failed: ${message}`
5106
+ }
5107
+ });
5108
+ }
5109
+ }
5110
+
4310
5111
  // src/server.ts
4311
5112
  function buildToolRegistry() {
4312
5113
  return {
@@ -4468,7 +5269,23 @@ function buildToolRegistry() {
4468
5269
  description: description20,
4469
5270
  inputSchema: inputSchema20
4470
5271
  },
5272
+ handler: handleSpawnSuccessor
5273
+ },
5274
+ [TOOL_NAME21]: {
5275
+ definition: {
5276
+ name: TOOL_NAME21,
5277
+ description: description21,
5278
+ inputSchema: inputSchema21
5279
+ },
4471
5280
  handler: handleConciergeDispatch
5281
+ },
5282
+ [TOOL_NAME22]: {
5283
+ definition: {
5284
+ name: TOOL_NAME22,
5285
+ description: description22,
5286
+ inputSchema: inputSchema22
5287
+ },
5288
+ handler: handleSyncConfig
4472
5289
  }
4473
5290
  };
4474
5291
  }
@@ -4526,7 +5343,7 @@ function listToolNames() {
4526
5343
 
4527
5344
  // src/cache/sqlite-cache.ts
4528
5345
  import { createHash as createHash3 } from "node:crypto";
4529
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync3 } from "node:fs";
5346
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync5 } from "node:fs";
4530
5347
  import { dirname as dirname5 } from "node:path";
4531
5348
  import { DatabaseSync } from "node:sqlite";
4532
5349
 
@@ -4572,7 +5389,7 @@ function normalizeString(s) {
4572
5389
  function createSqliteCache(options) {
4573
5390
  const fileBacked = options.dbPath !== ":memory:";
4574
5391
  if (fileBacked) {
4575
- mkdirSync3(dirname5(options.dbPath), { recursive: true, mode: 448 });
5392
+ mkdirSync5(dirname5(options.dbPath), { recursive: true, mode: 448 });
4576
5393
  }
4577
5394
  const versionNamespace = options.cacheVersionNamespace ?? "";
4578
5395
  const db = new DatabaseSync(options.dbPath);
@@ -4757,6 +5574,143 @@ function createNullConsensusEngineClient(reason = NULL_CLIENT_DEFAULT_REASON) {
4757
5574
 
4758
5575
  // src/consensus/engine-client.ts
4759
5576
  import { randomUUID as randomUUID3 } from "node:crypto";
5577
+
5578
+ // src/consensus/engine-options.ts
5579
+ var AGREEMENT_GATE_ENV_VAR = "VO_CONSENSUS_AGREEMENT_GATE";
5580
+ function isTruthyFlag(raw) {
5581
+ if (raw === void 0) return false;
5582
+ const v = raw.trim().toLowerCase();
5583
+ return v === "1" || v === "true" || v === "yes" || v === "on";
5584
+ }
5585
+ function resolveAgreementGate(args) {
5586
+ const env = args.env ?? process.env;
5587
+ const enabled = args.configEnabled === true || args.configEnabled === void 0 && isTruthyFlag(env[AGREEMENT_GATE_ENV_VAR]);
5588
+ if (!enabled) return void 0;
5589
+ return {
5590
+ enabled: true,
5591
+ ...args.probeSize !== void 0 ? { probe_size: args.probeSize } : {},
5592
+ ...args.modalAgreementThreshold !== void 0 ? { modal_agreement_threshold: args.modalAgreementThreshold } : {},
5593
+ ...args.minConfidence !== void 0 ? { min_confidence: args.minConfidence } : {}
5594
+ };
5595
+ }
5596
+ function buildSourceGroundedFields(config, defaultClassifier) {
5597
+ if (config === void 0) return {};
5598
+ const out = {};
5599
+ const grader = config.citation_grader;
5600
+ if (grader !== void 0 && grader.enabled === true) {
5601
+ const classifier = grader.classifier ?? defaultClassifier;
5602
+ if (classifier !== void 0) {
5603
+ out.citation_grader = {
5604
+ enabled: true,
5605
+ classifier,
5606
+ ...grader.escalate_below !== void 0 ? { escalate_below: grader.escalate_below } : {}
5607
+ };
5608
+ }
5609
+ }
5610
+ if (config.allow_url !== void 0) {
5611
+ out.allow_url = config.allow_url;
5612
+ }
5613
+ return out;
5614
+ }
5615
+ function mapFanOutDiagnostics(fd) {
5616
+ if (fd === void 0) return void 0;
5617
+ return {
5618
+ models_called: fd.models_called,
5619
+ panel_size: fd.panel_size,
5620
+ early_exit: fd.early_exit,
5621
+ refused: fd.refused
5622
+ };
5623
+ }
5624
+ function mapCitationGrade(cg) {
5625
+ if (cg === void 0) return void 0;
5626
+ return {
5627
+ ok: cg.ok,
5628
+ unsupported_count: cg.unsupported_count,
5629
+ uncertain_count: cg.uncertain_count,
5630
+ graded_claims: cg.graded_claims.map((g) => ({
5631
+ claim: g.claim,
5632
+ label: g.label,
5633
+ confidence: g.confidence,
5634
+ cited_ids: [...g.cited_ids]
5635
+ }))
5636
+ };
5637
+ }
5638
+
5639
+ // src/consensus/claim-classifier.ts
5640
+ var CLASSIFIER_SYSTEM_PROMPT = [
5641
+ "You are a citation-grading judge. You are given a CLAIM and the full text of the SOURCES it cites.",
5642
+ "Decide whether the SOURCES directly support the CLAIM. Judge ONLY against the supplied sources \u2014 do not use outside knowledge.",
5643
+ "pass = the sources clearly support the claim; fail = the sources contradict or do not support it; uncertain = the sources are insufficient or ambiguous.",
5644
+ "After a one-sentence justification, conclude with EXACTLY one of these lines:",
5645
+ " VERDICT: pass",
5646
+ " VERDICT: fail",
5647
+ " VERDICT: uncertain",
5648
+ "Then on a new line, exactly:",
5649
+ " CONFIDENCE: <0..1>",
5650
+ "Do not include any other VERDICT or CONFIDENCE lines."
5651
+ ].join("\n");
5652
+ function verdictToLabel(verdict) {
5653
+ switch (verdict) {
5654
+ case "pass":
5655
+ return "supported";
5656
+ case "fail":
5657
+ return "unsupported";
5658
+ case "uncertain":
5659
+ return "uncertain";
5660
+ default:
5661
+ return "uncertain";
5662
+ }
5663
+ }
5664
+ function clampConfidence(raw) {
5665
+ if (!Number.isFinite(raw)) return 0;
5666
+ if (raw < 0) return 0;
5667
+ if (raw > 1) return 1;
5668
+ return raw;
5669
+ }
5670
+ function buildClassifyPrompt(claim, sources) {
5671
+ return [
5672
+ "CLAIM:",
5673
+ claim,
5674
+ "",
5675
+ "SOURCES:",
5676
+ sources,
5677
+ "",
5678
+ "Does the cited SOURCES text support the CLAIM? Reply with your verdict (pass = supported, fail = unsupported, uncertain = insufficient)."
5679
+ ].join("\n");
5680
+ }
5681
+ function createClaimClassifier(model, options = {}) {
5682
+ return {
5683
+ async classify(args) {
5684
+ try {
5685
+ const result = await model.call({
5686
+ system_prompt: CLASSIFIER_SYSTEM_PROMPT,
5687
+ user_prompt: buildClassifyPrompt(args.claim, args.sources),
5688
+ ...options.signal !== void 0 ? { abort_signal: options.signal } : {}
5689
+ });
5690
+ if (result.verdict === "error") {
5691
+ return { label: "uncertain", confidence: 0 };
5692
+ }
5693
+ return {
5694
+ label: verdictToLabel(result.verdict),
5695
+ confidence: clampConfidence(result.confidence)
5696
+ };
5697
+ } catch {
5698
+ return { label: "uncertain", confidence: 0 };
5699
+ }
5700
+ }
5701
+ };
5702
+ }
5703
+
5704
+ // src/consensus/engine-client.ts
5705
+ function raceAbort(signal) {
5706
+ return new Promise((_, reject) => {
5707
+ const onAbort = () => {
5708
+ reject(new Error("__VO_MCP_CANCELLED__"));
5709
+ };
5710
+ if (signal.aborted) onAbort();
5711
+ else signal.addEventListener("abort", onAbort, { once: true });
5712
+ });
5713
+ }
4760
5714
  async function loadEngineModule() {
4761
5715
  try {
4762
5716
  const moduleName = ["@algosuite", "consensus-engine"].join("/");
@@ -4800,36 +5754,73 @@ function createEngineConsensusClient(options) {
4800
5754
  ...adapter,
4801
5755
  call: (args) => adapter.call({ ...args, abort_signal: signal })
4802
5756
  }));
5757
+ const agreementGate = resolveAgreementGate({
5758
+ ...options.agreement_gate_enabled !== void 0 ? { configEnabled: options.agreement_gate_enabled } : {},
5759
+ ...options.env !== void 0 ? { env: options.env } : {}
5760
+ });
4803
5761
  const engineOptions = {
4804
5762
  panel,
4805
- ...options.per_model_timeout_ms !== void 0 ? { per_model_timeout_ms: options.per_model_timeout_ms } : {}
5763
+ ...options.per_model_timeout_ms !== void 0 ? { per_model_timeout_ms: options.per_model_timeout_ms } : {},
5764
+ ...agreementGate !== void 0 ? { agreement_gate: agreementGate } : {}
4806
5765
  };
4807
- const result = signal === void 0 ? await engine.runConsensus(engineRequest, engineOptions) : await Promise.race([
4808
- engine.runConsensus(engineRequest, engineOptions),
4809
- new Promise((_, reject) => {
4810
- const onAbort = () => {
4811
- reject(new Error("__VO_MCP_CANCELLED__"));
4812
- };
4813
- if (signal.aborted) onAbort();
4814
- else signal.addEventListener("abort", onAbort, { once: true });
4815
- })
4816
- ]);
4817
- if (!result.ok || result.response === void 0) {
4818
- return {
4819
- ok: false,
4820
- reason: result.error?.reason ?? "engine-returned-not-ok"
5766
+ const sources = request.source_urls;
5767
+ const useSourceGrounded = sources !== void 0 && sources.length > 0 && typeof engine.runSourceGroundedConsensus === "function";
5768
+ let response;
5769
+ let sourceExtras;
5770
+ if (useSourceGrounded) {
5771
+ const [firstAdapter] = panel;
5772
+ const classifierOptions = signal === void 0 ? {} : { signal };
5773
+ const defaultClassifier = firstAdapter === void 0 ? void 0 : createClaimClassifier(firstAdapter, classifierOptions);
5774
+ const sgFields = buildSourceGroundedFields(request.source_grounded, defaultClassifier);
5775
+ const sgOptions = {
5776
+ ...engineOptions,
5777
+ source_urls: sources,
5778
+ ...sgFields.allow_url !== void 0 ? { allow_url: sgFields.allow_url } : {},
5779
+ ...sgFields.citation_grader !== void 0 ? { citation_grader: sgFields.citation_grader } : {}
5780
+ };
5781
+ if (typeof engine.runSourceGroundedConsensus !== "function") {
5782
+ return { ok: false, reason: "source-grounded engine missing runSourceGroundedConsensus" };
5783
+ }
5784
+ const sgCall = engine.runSourceGroundedConsensus(engineRequest, sgOptions);
5785
+ const sgResult = signal === void 0 ? await sgCall : await Promise.race([sgCall, raceAbort(signal)]);
5786
+ if (!sgResult.ok) {
5787
+ return { ok: false, reason: sgResult.reason };
5788
+ }
5789
+ response = sgResult.engine.response;
5790
+ sourceExtras = {
5791
+ ...sgResult.citation_grade !== void 0 ? { citation_grade: mapCitationGrade(sgResult.citation_grade) } : {},
5792
+ ...sgResult.low_confidence_sources !== void 0 ? { low_confidence_sources: sgResult.low_confidence_sources } : {},
5793
+ ...sgResult.escalation_required !== void 0 ? { escalation_required: sgResult.escalation_required } : {},
5794
+ ...sgResult.escalation_reason !== void 0 ? { escalation_reason: sgResult.escalation_reason } : {}
4821
5795
  };
5796
+ } else {
5797
+ const result = signal === void 0 ? await engine.runConsensus(engineRequest, engineOptions) : await Promise.race([engine.runConsensus(engineRequest, engineOptions), raceAbort(signal)]);
5798
+ if (!result.ok || result.response === void 0) {
5799
+ return {
5800
+ ok: false,
5801
+ reason: result.error?.reason ?? "engine-returned-not-ok"
5802
+ };
5803
+ }
5804
+ response = result.response;
4822
5805
  }
4823
5806
  return {
4824
5807
  ok: true,
4825
- synthesized_verdict: result.response.synthesized_verdict,
4826
- per_model_verdicts: result.response.per_model_verdicts,
4827
- degraded: result.response.degraded,
4828
- duration_ms: result.response.duration_ms,
4829
- engine_version: result.response.engine_version,
4830
- // Phase 2 Lane D-1 — forward escalation signal when present.
4831
- ...result.response.escalation_required !== void 0 ? { escalation_required: result.response.escalation_required } : {},
4832
- ...result.response.escalation_reason !== void 0 ? { escalation_reason: result.response.escalation_reason } : {}
5808
+ synthesized_verdict: response.synthesized_verdict,
5809
+ per_model_verdicts: response.per_model_verdicts,
5810
+ degraded: response.degraded,
5811
+ duration_ms: response.duration_ms,
5812
+ engine_version: response.engine_version,
5813
+ // Phase 2 Lane D-1 — forward escalation signal when present. The
5814
+ // source-grounded layer's own escalation (from the citation grade)
5815
+ // takes precedence when set, else the synthesizer's.
5816
+ ...sourceExtras?.escalation_required !== void 0 ? { escalation_required: sourceExtras.escalation_required } : response.escalation_required !== void 0 ? { escalation_required: response.escalation_required } : {},
5817
+ ...sourceExtras?.escalation_reason !== void 0 ? { escalation_reason: sourceExtras.escalation_reason } : response.escalation_reason !== void 0 ? { escalation_reason: response.escalation_reason } : {},
5818
+ // Feature 1 (agreement-gate) — fan-out diagnostics (additive telemetry).
5819
+ ...mapFanOutDiagnostics(response.fan_out_diagnostics) !== void 0 ? { fan_out_diagnostics: mapFanOutDiagnostics(response.fan_out_diagnostics) } : {},
5820
+ // Source-grounded additive outputs (Tier-4 features).
5821
+ ...useSourceGrounded ? { source_grounded: true } : {},
5822
+ ...sourceExtras?.citation_grade !== void 0 ? { citation_grade: sourceExtras.citation_grade } : {},
5823
+ ...sourceExtras?.low_confidence_sources !== void 0 ? { low_confidence_sources: sourceExtras.low_confidence_sources } : {}
4833
5824
  };
4834
5825
  } catch (err) {
4835
5826
  const message = err instanceof Error ? err.message : String(err);