@algosuite/vo-mcp 0.1.0 → 0.2.0-beta.1
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/bin/vo-mcp +2 -5
- package/dist/cli.js +1087 -319
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1083 -92
- package/dist/index.js.map +4 -4
- package/dist/install-cli.js +12 -7
- package/dist/install-cli.js.map +2 -2
- package/dist/login-cli.js +9 -5
- package/dist/login-cli.js.map +2 -2
- package/dist/runner-cli.js +1940 -0
- package/dist/runner-cli.js.map +7 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,296 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __esm = (fn, res, err) => function __init() {
|
|
6
|
+
if (err) throw err[0];
|
|
7
|
+
try {
|
|
8
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
9
|
+
} catch (e) {
|
|
10
|
+
throw err = [e], e;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/cloud/auth-token-source.ts
|
|
19
|
+
var auth_token_source_exports = {};
|
|
20
|
+
__export(auth_token_source_exports, {
|
|
21
|
+
FIREBASE_SECURETOKEN_URL: () => FIREBASE_SECURETOKEN_URL,
|
|
22
|
+
FIREBASE_TOKEN_REFERER: () => FIREBASE_TOKEN_REFERER,
|
|
23
|
+
createAuthTokenSourceFromEnv: () => createAuthTokenSourceFromEnv,
|
|
24
|
+
createFirebaseRefreshTokenSource: () => createFirebaseRefreshTokenSource,
|
|
25
|
+
createStaticTokenSource: () => createStaticTokenSource
|
|
26
|
+
});
|
|
27
|
+
function createStaticTokenSource(token, kind = "admin-token") {
|
|
28
|
+
const value = token.trim();
|
|
29
|
+
return { kind, getToken: async () => value.length > 0 ? value : null };
|
|
30
|
+
}
|
|
31
|
+
function createFirebaseRefreshTokenSource(opts) {
|
|
32
|
+
const refreshToken = opts.refreshToken.trim();
|
|
33
|
+
const apiKey = opts.apiKey.trim();
|
|
34
|
+
const now = opts.now ?? (() => Date.now());
|
|
35
|
+
const fetchFn = opts.fetchFn ?? globalThis.fetch;
|
|
36
|
+
let cachedToken = null;
|
|
37
|
+
let expiresAtMs = 0;
|
|
38
|
+
let inFlight = null;
|
|
39
|
+
async function refresh() {
|
|
40
|
+
try {
|
|
41
|
+
const res = await fetchFn(`${FIREBASE_SECURETOKEN_URL}?key=${encodeURIComponent(apiKey)}`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: {
|
|
44
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
45
|
+
referer: FIREBASE_TOKEN_REFERER
|
|
46
|
+
},
|
|
47
|
+
body: `grant_type=refresh_token&refresh_token=${encodeURIComponent(refreshToken)}`
|
|
48
|
+
});
|
|
49
|
+
const text = await res.text();
|
|
50
|
+
if (res.status < 200 || res.status >= 300) {
|
|
51
|
+
cachedToken = null;
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const parsed = JSON.parse(text);
|
|
55
|
+
const idToken = typeof parsed.id_token === "string" ? parsed.id_token : "";
|
|
56
|
+
if (!idToken) {
|
|
57
|
+
cachedToken = null;
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const expiresInSec = Number(parsed.expires_in);
|
|
61
|
+
const ttlMs = Number.isFinite(expiresInSec) && expiresInSec > 0 ? expiresInSec * 1e3 : 36e5;
|
|
62
|
+
cachedToken = idToken;
|
|
63
|
+
expiresAtMs = now() + ttlMs;
|
|
64
|
+
return idToken;
|
|
65
|
+
} catch {
|
|
66
|
+
cachedToken = null;
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
kind: "firebase-refresh",
|
|
72
|
+
async getToken() {
|
|
73
|
+
if (cachedToken && now() < expiresAtMs - REFRESH_SKEW_MS) return cachedToken;
|
|
74
|
+
if (!inFlight) {
|
|
75
|
+
inFlight = refresh().finally(() => {
|
|
76
|
+
inFlight = null;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return inFlight;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function createAuthTokenSourceFromEnv(env = process.env, fetchFn, readStoredCred = () => null) {
|
|
84
|
+
const refreshToken = env["VO_USER_REFRESH_TOKEN"]?.trim();
|
|
85
|
+
const apiKey = env["VO_FIREBASE_API_KEY"]?.trim();
|
|
86
|
+
const idToken = env["VO_USER_ID_TOKEN"]?.trim();
|
|
87
|
+
const adminToken = env["VO_CONTROL_PLANE_ADMIN_TOKEN"]?.trim();
|
|
88
|
+
if (refreshToken || apiKey) {
|
|
89
|
+
if (!refreshToken || !apiKey) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
"Per-user refresh auth requires BOTH VO_USER_REFRESH_TOKEN and VO_FIREBASE_API_KEY"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return createFirebaseRefreshTokenSource({
|
|
95
|
+
refreshToken,
|
|
96
|
+
apiKey,
|
|
97
|
+
...fetchFn ? { fetchFn } : {}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (idToken) return createStaticTokenSource(idToken, "firebase-id-token");
|
|
101
|
+
const stored = readStoredCred();
|
|
102
|
+
if (stored?.vo_credential && stored.vo_credential.trim()) {
|
|
103
|
+
return createStaticTokenSource(stored.vo_credential.trim(), "vo-credential");
|
|
104
|
+
}
|
|
105
|
+
if (stored && stored.refresh_token?.trim() && stored.api_key?.trim()) {
|
|
106
|
+
return createFirebaseRefreshTokenSource({
|
|
107
|
+
refreshToken: stored.refresh_token.trim(),
|
|
108
|
+
apiKey: stored.api_key.trim(),
|
|
109
|
+
...fetchFn ? { fetchFn } : {}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (adminToken) return createStaticTokenSource(adminToken, "admin-token");
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
var FIREBASE_SECURETOKEN_URL, FIREBASE_TOKEN_REFERER, REFRESH_SKEW_MS;
|
|
116
|
+
var init_auth_token_source = __esm({
|
|
117
|
+
"src/cloud/auth-token-source.ts"() {
|
|
118
|
+
"use strict";
|
|
119
|
+
FIREBASE_SECURETOKEN_URL = "https://securetoken.googleapis.com/v1/token";
|
|
120
|
+
FIREBASE_TOKEN_REFERER = "https://algosuite.ai/";
|
|
121
|
+
REFRESH_SKEW_MS = 6e4;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// src/cloud/keychain.ts
|
|
126
|
+
import { createRequire } from "node:module";
|
|
127
|
+
function loadKeyring() {
|
|
128
|
+
if (cached !== void 0) return cached;
|
|
129
|
+
try {
|
|
130
|
+
const req = createRequire(import.meta.url);
|
|
131
|
+
const mod = req("@napi-rs/keyring");
|
|
132
|
+
cached = mod && typeof mod.Entry === "function" ? mod : null;
|
|
133
|
+
} catch {
|
|
134
|
+
cached = null;
|
|
135
|
+
}
|
|
136
|
+
return cached;
|
|
137
|
+
}
|
|
138
|
+
function keychainAvailable() {
|
|
139
|
+
return loadKeyring() !== null;
|
|
140
|
+
}
|
|
141
|
+
function keychainGet() {
|
|
142
|
+
const k = loadKeyring();
|
|
143
|
+
if (!k) return null;
|
|
144
|
+
try {
|
|
145
|
+
return new k.Entry(SERVICE, ACCOUNT).getPassword();
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function keychainSet(secret) {
|
|
151
|
+
const k = loadKeyring();
|
|
152
|
+
if (!k) return false;
|
|
153
|
+
try {
|
|
154
|
+
new k.Entry(SERVICE, ACCOUNT).setPassword(secret);
|
|
155
|
+
return true;
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function keychainDelete() {
|
|
161
|
+
const k = loadKeyring();
|
|
162
|
+
if (!k) return false;
|
|
163
|
+
try {
|
|
164
|
+
return new k.Entry(SERVICE, ACCOUNT).deletePassword();
|
|
165
|
+
} catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
var SERVICE, ACCOUNT, cached;
|
|
170
|
+
var init_keychain = __esm({
|
|
171
|
+
"src/cloud/keychain.ts"() {
|
|
172
|
+
"use strict";
|
|
173
|
+
SERVICE = "vo-mcp";
|
|
174
|
+
ACCOUNT = "refresh-credential";
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// src/cloud/credential-store.ts
|
|
179
|
+
var credential_store_exports = {};
|
|
180
|
+
__export(credential_store_exports, {
|
|
181
|
+
KEYCHAIN_LOCATION: () => KEYCHAIN_LOCATION,
|
|
182
|
+
credentialPath: () => credentialPath,
|
|
183
|
+
readStoredCredential: () => readStoredCredential,
|
|
184
|
+
writeStoredCredential: () => writeStoredCredential
|
|
185
|
+
});
|
|
186
|
+
import { homedir as homedir3 } from "node:os";
|
|
187
|
+
import { join as join5, dirname as dirname4 } from "node:path";
|
|
188
|
+
import {
|
|
189
|
+
existsSync as existsSync3,
|
|
190
|
+
mkdirSync as mkdirSync2,
|
|
191
|
+
readFileSync as readFileSync5,
|
|
192
|
+
writeFileSync as writeFileSync2,
|
|
193
|
+
chmodSync as chmodSync2,
|
|
194
|
+
rmSync
|
|
195
|
+
} from "node:fs";
|
|
196
|
+
function credentialPath(env = process.env) {
|
|
197
|
+
const override = env["VO_MCP_CREDENTIALS_PATH"]?.trim();
|
|
198
|
+
if (override) return override;
|
|
199
|
+
return join5(homedir3(), ".config", "vo-mcp", "credentials.json");
|
|
200
|
+
}
|
|
201
|
+
function keychainEnabled(env, keychain) {
|
|
202
|
+
const disabled = (env["VO_MCP_DISABLE_KEYCHAIN"] ?? "").trim().toLowerCase();
|
|
203
|
+
if (disabled === "1" || disabled === "true" || disabled === "yes") return false;
|
|
204
|
+
return keychain.available();
|
|
205
|
+
}
|
|
206
|
+
function deserialize(raw) {
|
|
207
|
+
try {
|
|
208
|
+
const parsed = JSON.parse(raw);
|
|
209
|
+
const refresh = typeof parsed.refresh_token === "string" ? parsed.refresh_token.trim() : "";
|
|
210
|
+
const apiKey = typeof parsed.api_key === "string" ? parsed.api_key.trim() : "";
|
|
211
|
+
const voCred = typeof parsed.vo_credential === "string" ? parsed.vo_credential.trim() : "";
|
|
212
|
+
if (!voCred && (!refresh || !apiKey)) return null;
|
|
213
|
+
return {
|
|
214
|
+
...refresh ? { refresh_token: refresh } : {},
|
|
215
|
+
...apiKey ? { api_key: apiKey } : {},
|
|
216
|
+
...voCred ? { vo_credential: voCred } : {},
|
|
217
|
+
...typeof parsed.vo_credential_expires_at === "string" ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {},
|
|
218
|
+
...typeof parsed.email === "string" ? { email: parsed.email } : {},
|
|
219
|
+
...typeof parsed.stored_at === "string" ? { stored_at: parsed.stored_at } : {}
|
|
220
|
+
};
|
|
221
|
+
} catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function readFromFile(env) {
|
|
226
|
+
try {
|
|
227
|
+
const p = credentialPath(env);
|
|
228
|
+
if (!existsSync3(p)) return null;
|
|
229
|
+
return deserialize(readFileSync5(p, "utf8"));
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function readStoredCredential(env = process.env, keychain = realKeychain) {
|
|
235
|
+
if (keychainEnabled(env, keychain)) {
|
|
236
|
+
const raw = keychain.get();
|
|
237
|
+
const fromKeychain = raw ? deserialize(raw) : null;
|
|
238
|
+
if (fromKeychain) return fromKeychain;
|
|
239
|
+
}
|
|
240
|
+
return readFromFile(env);
|
|
241
|
+
}
|
|
242
|
+
function deleteFile(env) {
|
|
243
|
+
try {
|
|
244
|
+
rmSync(credentialPath(env), { force: true });
|
|
245
|
+
} catch {
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function writeToFile(payload, env) {
|
|
249
|
+
const p = credentialPath(env);
|
|
250
|
+
mkdirSync2(dirname4(p), { recursive: true });
|
|
251
|
+
writeFileSync2(p, `${JSON.stringify(payload, null, 2)}
|
|
252
|
+
`, { mode: 384 });
|
|
253
|
+
try {
|
|
254
|
+
chmodSync2(p, 384);
|
|
255
|
+
} catch {
|
|
256
|
+
}
|
|
257
|
+
return p;
|
|
258
|
+
}
|
|
259
|
+
function writeStoredCredential(cred, storedAt, env = process.env, keychain = realKeychain) {
|
|
260
|
+
const payload = {
|
|
261
|
+
...cred.refresh_token ? { refresh_token: cred.refresh_token } : {},
|
|
262
|
+
...cred.api_key ? { api_key: cred.api_key } : {},
|
|
263
|
+
...cred.vo_credential ? { vo_credential: cred.vo_credential } : {},
|
|
264
|
+
...cred.vo_credential_expires_at ? { vo_credential_expires_at: cred.vo_credential_expires_at } : {},
|
|
265
|
+
...cred.email ? { email: cred.email } : {},
|
|
266
|
+
stored_at: cred.stored_at ?? storedAt
|
|
267
|
+
};
|
|
268
|
+
if (keychainEnabled(env, keychain) && keychain.set(JSON.stringify(payload))) {
|
|
269
|
+
deleteFile(env);
|
|
270
|
+
return KEYCHAIN_LOCATION;
|
|
271
|
+
}
|
|
272
|
+
const p = writeToFile(payload, env);
|
|
273
|
+
if (keychainEnabled(env, keychain)) keychain.delete();
|
|
274
|
+
return p;
|
|
275
|
+
}
|
|
276
|
+
var realKeychain, KEYCHAIN_LOCATION;
|
|
277
|
+
var init_credential_store = __esm({
|
|
278
|
+
"src/cloud/credential-store.ts"() {
|
|
279
|
+
"use strict";
|
|
280
|
+
init_keychain();
|
|
281
|
+
realKeychain = {
|
|
282
|
+
available: keychainAvailable,
|
|
283
|
+
get: keychainGet,
|
|
284
|
+
set: keychainSet,
|
|
285
|
+
delete: keychainDelete
|
|
286
|
+
};
|
|
287
|
+
KEYCHAIN_LOCATION = 'OS keychain (service "vo-mcp")';
|
|
288
|
+
}
|
|
289
|
+
});
|
|
3
290
|
|
|
4
291
|
// src/cli.ts
|
|
5
|
-
import { homedir as
|
|
6
|
-
import { join as
|
|
292
|
+
import { homedir as homedir6, hostname } from "node:os";
|
|
293
|
+
import { join as join8 } from "node:path";
|
|
7
294
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
295
|
|
|
9
296
|
// src/server.ts
|
|
@@ -1511,6 +1798,45 @@ var ALL_RECOGNIZED_GATE_TYPES = [
|
|
|
1511
1798
|
...KNOWN_GATE_TYPES
|
|
1512
1799
|
];
|
|
1513
1800
|
|
|
1801
|
+
// src/tools/consensus-judgment-source-grounded.ts
|
|
1802
|
+
function isStringArray(v) {
|
|
1803
|
+
return Array.isArray(v) && v.every((e) => typeof e === "string");
|
|
1804
|
+
}
|
|
1805
|
+
function isToolSourceGrounded(v) {
|
|
1806
|
+
if (typeof v !== "object" || v === null) return false;
|
|
1807
|
+
const o = v;
|
|
1808
|
+
if (o["enable_citation_grading"] !== void 0 && typeof o["enable_citation_grading"] !== "boolean") {
|
|
1809
|
+
return false;
|
|
1810
|
+
}
|
|
1811
|
+
if (o["escalate_below"] !== void 0 && typeof o["escalate_below"] !== "number") return false;
|
|
1812
|
+
return true;
|
|
1813
|
+
}
|
|
1814
|
+
function normalizeSourceGrounded(input) {
|
|
1815
|
+
const sourceUrls = input.source_urls !== void 0 ? input.source_urls.filter((u) => u.trim().length > 0) : [];
|
|
1816
|
+
const active = sourceUrls.length > 0;
|
|
1817
|
+
const gradingEnabled = active && input.source_grounded?.enable_citation_grading === true;
|
|
1818
|
+
const escalateBelow = input.source_grounded?.escalate_below;
|
|
1819
|
+
const config = gradingEnabled ? {
|
|
1820
|
+
citation_grader: {
|
|
1821
|
+
enabled: true,
|
|
1822
|
+
...escalateBelow !== void 0 ? { escalate_below: escalateBelow } : {}
|
|
1823
|
+
}
|
|
1824
|
+
} : void 0;
|
|
1825
|
+
const cacheFragments = {};
|
|
1826
|
+
if (active) cacheFragments["source_urls"] = sourceUrls;
|
|
1827
|
+
if (gradingEnabled) {
|
|
1828
|
+
cacheFragments["citation_grading"] = true;
|
|
1829
|
+
if (escalateBelow !== void 0) cacheFragments["escalate_below"] = escalateBelow;
|
|
1830
|
+
}
|
|
1831
|
+
return {
|
|
1832
|
+
active,
|
|
1833
|
+
sourceUrls,
|
|
1834
|
+
gradingEnabled,
|
|
1835
|
+
...config !== void 0 ? { config } : {},
|
|
1836
|
+
cacheFragments
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1514
1840
|
// src/tools/consensus-judgment.ts
|
|
1515
1841
|
var TOOL_NAME4 = "vo_consensus_judgment";
|
|
1516
1842
|
var MAX_PROMPT_BYTES = 64 * 1024;
|
|
@@ -1533,6 +1859,26 @@ var inputSchema4 = {
|
|
|
1533
1859
|
type: "object",
|
|
1534
1860
|
description: "Tool-specific context (e.g. source file, diff, observed value).",
|
|
1535
1861
|
additionalProperties: true
|
|
1862
|
+
},
|
|
1863
|
+
source_urls: {
|
|
1864
|
+
type: "array",
|
|
1865
|
+
items: { type: "string" },
|
|
1866
|
+
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."
|
|
1867
|
+
},
|
|
1868
|
+
source_grounded: {
|
|
1869
|
+
type: "object",
|
|
1870
|
+
description: "Optional source-grounded behaviour toggles. Only meaningful when source_urls is non-empty.",
|
|
1871
|
+
properties: {
|
|
1872
|
+
enable_citation_grading: {
|
|
1873
|
+
type: "boolean",
|
|
1874
|
+
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."
|
|
1875
|
+
},
|
|
1876
|
+
escalate_below: {
|
|
1877
|
+
type: "number",
|
|
1878
|
+
description: "Uncertain-claim escalation floor [0..1]; an uncertain claim with confidence below this triggers escalation. Engine default 0.85 when omitted."
|
|
1879
|
+
}
|
|
1880
|
+
},
|
|
1881
|
+
additionalProperties: false
|
|
1536
1882
|
}
|
|
1537
1883
|
},
|
|
1538
1884
|
required: ["prompt"],
|
|
@@ -1544,6 +1890,8 @@ function isToolInput4(v) {
|
|
|
1544
1890
|
const o = v;
|
|
1545
1891
|
if (typeof o["prompt"] !== "string") return false;
|
|
1546
1892
|
if (o["gate_type"] !== void 0 && typeof o["gate_type"] !== "string") return false;
|
|
1893
|
+
if (o["source_urls"] !== void 0 && !isStringArray(o["source_urls"])) return false;
|
|
1894
|
+
if (o["source_grounded"] !== void 0 && !isToolSourceGrounded(o["source_grounded"])) return false;
|
|
1547
1895
|
return true;
|
|
1548
1896
|
}
|
|
1549
1897
|
function isAcceptedGateType(v) {
|
|
@@ -1569,10 +1917,15 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
|
|
|
1569
1917
|
const rawGate = rawInput.gate_type ?? DEFAULT_GATE_TYPE;
|
|
1570
1918
|
const gateType = isAcceptedGateType(rawGate) ? rawGate : DEFAULT_GATE_TYPE;
|
|
1571
1919
|
const inputSizeBytes = bytesOf(rawInput.prompt) + bytesOf(contextStrForSize);
|
|
1920
|
+
const sg = normalizeSourceGrounded({
|
|
1921
|
+
...rawInput.source_urls !== void 0 ? { source_urls: rawInput.source_urls } : {},
|
|
1922
|
+
...rawInput.source_grounded !== void 0 ? { source_grounded: rawInput.source_grounded } : {}
|
|
1923
|
+
});
|
|
1572
1924
|
const cacheInput = {
|
|
1573
1925
|
prompt: rawInput.prompt,
|
|
1574
1926
|
gate_type: gateType,
|
|
1575
|
-
...rawInput.context !== void 0 ? { context: rawInput.context } : {}
|
|
1927
|
+
...rawInput.context !== void 0 ? { context: rawInput.context } : {},
|
|
1928
|
+
...sg.cacheFragments
|
|
1576
1929
|
};
|
|
1577
1930
|
const key = deps.cache.keyFor(TOOL_NAME4, cacheInput);
|
|
1578
1931
|
const excerpt = rawInput.prompt.slice(0, 300);
|
|
@@ -1618,7 +1971,9 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
|
|
|
1618
1971
|
gate_type: gateType,
|
|
1619
1972
|
prompt: rawInput.prompt,
|
|
1620
1973
|
...rawInput.context !== void 0 ? { caller_context: rawInput.context } : {},
|
|
1621
|
-
...signal !== void 0 ? { signal } : {}
|
|
1974
|
+
...signal !== void 0 ? { signal } : {},
|
|
1975
|
+
...sg.active ? { source_urls: sg.sourceUrls } : {},
|
|
1976
|
+
...sg.config !== void 0 ? { source_grounded: sg.config } : {}
|
|
1622
1977
|
});
|
|
1623
1978
|
} catch (err) {
|
|
1624
1979
|
engineThrew = true;
|
|
@@ -1671,7 +2026,23 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
|
|
|
1671
2026
|
synthesized_verdict: synthForEvent,
|
|
1672
2027
|
engine_version: engineResult.engine_version,
|
|
1673
2028
|
degraded: engineResult.degraded,
|
|
1674
|
-
gate_type: gateType
|
|
2029
|
+
gate_type: gateType,
|
|
2030
|
+
// ─── Consensus-engine feature outputs (additive; 2026-06-13) ─────────────
|
|
2031
|
+
// Feature 2 (calibrated-confidence) — ON by default; the engine attaches
|
|
2032
|
+
// calibrated_confidence + confidence_badge to the synthesized verdict on the
|
|
2033
|
+
// plain runConsensus path. Surface them at the top level so callers don't
|
|
2034
|
+
// have to know the engine's internal SynthesizedVerdict shape.
|
|
2035
|
+
...engineResult.synthesized_verdict.calibrated_confidence !== void 0 ? { calibrated_confidence: engineResult.synthesized_verdict.calibrated_confidence } : {},
|
|
2036
|
+
...engineResult.synthesized_verdict.confidence_badge !== void 0 ? { confidence_badge: engineResult.synthesized_verdict.confidence_badge } : {},
|
|
2037
|
+
// Feature 1 (agreement-gate) — fan-out diagnostics (present iff the gate ran).
|
|
2038
|
+
...engineResult.fan_out_diagnostics !== void 0 ? { fan_out_diagnostics: engineResult.fan_out_diagnostics } : {},
|
|
2039
|
+
// Source-grounded Tier-4 outputs (present iff the call was source-grounded).
|
|
2040
|
+
...engineResult.source_grounded === true ? { source_grounded: true } : {},
|
|
2041
|
+
...engineResult.citation_grade !== void 0 ? { citation_grade: engineResult.citation_grade } : {},
|
|
2042
|
+
...engineResult.low_confidence_sources !== void 0 ? { low_confidence_sources: engineResult.low_confidence_sources } : {},
|
|
2043
|
+
// Escalation (from citation grade or human-tiebreak synthesizer).
|
|
2044
|
+
...engineResult.escalation_required !== void 0 ? { escalation_required: engineResult.escalation_required } : {},
|
|
2045
|
+
...engineResult.escalation_reason !== void 0 ? { escalation_reason: engineResult.escalation_reason } : {}
|
|
1675
2046
|
};
|
|
1676
2047
|
const envelope = {
|
|
1677
2048
|
tool: TOOL_NAME4,
|
|
@@ -1894,8 +2265,11 @@ var ratchetIdSchema = z3.enum([
|
|
|
1894
2265
|
]);
|
|
1895
2266
|
var thresholdSchema = z3.enum(["strict", "medium", "permissive"]);
|
|
1896
2267
|
var userConfigSchema = z3.object({
|
|
1897
|
-
|
|
1898
|
-
|
|
2268
|
+
// zod v4: z.record with ENUM keys validates exhaustively (every key
|
|
2269
|
+
// required); these are user OVERRIDE maps merged over DEFAULT_CONFIG,
|
|
2270
|
+
// so partial-by-design — z.partialRecord restores the v3 semantics.
|
|
2271
|
+
enabled: z3.partialRecord(ratchetIdSchema, z3.boolean()).optional(),
|
|
2272
|
+
thresholds: z3.partialRecord(ratchetIdSchema, thresholdSchema).optional(),
|
|
1899
2273
|
allowlist: z3.object({
|
|
1900
2274
|
paths: z3.array(z3.string()).optional(),
|
|
1901
2275
|
rules: z3.array(z3.string()).optional()
|
|
@@ -3301,279 +3675,43 @@ Produce the JSON dispatch plan now.`;
|
|
|
3301
3675
|
plan_text: v.raw_response_excerpt,
|
|
3302
3676
|
confidence: v.confidence,
|
|
3303
3677
|
parse_ok: parsed !== null
|
|
3304
|
-
};
|
|
3305
|
-
});
|
|
3306
|
-
const synthText = engineResult.synthesized_verdict.reasoning_excerpt;
|
|
3307
|
-
const synthPlan = tryParseDispatchPlan(synthText);
|
|
3308
|
-
const payload = {
|
|
3309
|
-
verdict: synthPlan !== null ? "pass" : "uncertain",
|
|
3310
|
-
reason: synthPlan !== null ? "Synthesized dispatch plan parsed successfully" : "Synthesized verdict did not parse as a valid dispatch plan JSON \u2014 see per_model_plans for raw outputs",
|
|
3311
|
-
dispatch_plan: synthPlan,
|
|
3312
|
-
...synthPlan === null ? { parse_error: "synthesized verdict text was not valid dispatch-plan JSON" } : {},
|
|
3313
|
-
per_model_plans: perModelPlans,
|
|
3314
|
-
synthesized_reasoning: synthText,
|
|
3315
|
-
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
3316
|
-
engine_version: engineResult.engine_version,
|
|
3317
|
-
...engineResult.per_model_verdicts.length < 3 ? { degraded: true } : {}
|
|
3318
|
-
};
|
|
3319
|
-
const envelope = {
|
|
3320
|
-
tool: TOOL_NAME7,
|
|
3321
|
-
schema_version: 1,
|
|
3322
|
-
cache: { hit: false, key },
|
|
3323
|
-
payload
|
|
3324
|
-
};
|
|
3325
|
-
deps.cache.set(key, envelope);
|
|
3326
|
-
const enrichedEvent = {
|
|
3327
|
-
...baseEvent,
|
|
3328
|
-
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
3329
|
-
duration_ms: engineResult.duration_ms,
|
|
3330
|
-
consensus_engine_version: engineResult.engine_version,
|
|
3331
|
-
per_model_verdicts: toEventPerModelVerdicts(engineResult.per_model_verdicts),
|
|
3332
|
-
synthesized_verdict: toEventSynthesizedVerdict(engineResult.synthesized_verdict)
|
|
3333
|
-
};
|
|
3334
|
-
deps.events.append(enrichedEvent);
|
|
3335
|
-
return jsonContent(envelope);
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
// src/cloud/auth-token-source.ts
|
|
3339
|
-
var FIREBASE_SECURETOKEN_URL = "https://securetoken.googleapis.com/v1/token";
|
|
3340
|
-
var REFRESH_SKEW_MS = 6e4;
|
|
3341
|
-
function createStaticTokenSource(token, kind = "admin-token") {
|
|
3342
|
-
const value = token.trim();
|
|
3343
|
-
return { kind, getToken: async () => value.length > 0 ? value : null };
|
|
3344
|
-
}
|
|
3345
|
-
function createFirebaseRefreshTokenSource(opts) {
|
|
3346
|
-
const refreshToken = opts.refreshToken.trim();
|
|
3347
|
-
const apiKey = opts.apiKey.trim();
|
|
3348
|
-
const now = opts.now ?? (() => Date.now());
|
|
3349
|
-
const fetchFn = opts.fetchFn ?? globalThis.fetch;
|
|
3350
|
-
let cachedToken = null;
|
|
3351
|
-
let expiresAtMs = 0;
|
|
3352
|
-
let inFlight = null;
|
|
3353
|
-
async function refresh() {
|
|
3354
|
-
try {
|
|
3355
|
-
const res = await fetchFn(`${FIREBASE_SECURETOKEN_URL}?key=${encodeURIComponent(apiKey)}`, {
|
|
3356
|
-
method: "POST",
|
|
3357
|
-
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
3358
|
-
body: `grant_type=refresh_token&refresh_token=${encodeURIComponent(refreshToken)}`
|
|
3359
|
-
});
|
|
3360
|
-
const text = await res.text();
|
|
3361
|
-
if (res.status < 200 || res.status >= 300) {
|
|
3362
|
-
cachedToken = null;
|
|
3363
|
-
return null;
|
|
3364
|
-
}
|
|
3365
|
-
const parsed = JSON.parse(text);
|
|
3366
|
-
const idToken = typeof parsed.id_token === "string" ? parsed.id_token : "";
|
|
3367
|
-
if (!idToken) {
|
|
3368
|
-
cachedToken = null;
|
|
3369
|
-
return null;
|
|
3370
|
-
}
|
|
3371
|
-
const expiresInSec = Number(parsed.expires_in);
|
|
3372
|
-
const ttlMs = Number.isFinite(expiresInSec) && expiresInSec > 0 ? expiresInSec * 1e3 : 36e5;
|
|
3373
|
-
cachedToken = idToken;
|
|
3374
|
-
expiresAtMs = now() + ttlMs;
|
|
3375
|
-
return idToken;
|
|
3376
|
-
} catch {
|
|
3377
|
-
cachedToken = null;
|
|
3378
|
-
return null;
|
|
3379
|
-
}
|
|
3380
|
-
}
|
|
3381
|
-
return {
|
|
3382
|
-
kind: "firebase-refresh",
|
|
3383
|
-
async getToken() {
|
|
3384
|
-
if (cachedToken && now() < expiresAtMs - REFRESH_SKEW_MS) return cachedToken;
|
|
3385
|
-
if (!inFlight) {
|
|
3386
|
-
inFlight = refresh().finally(() => {
|
|
3387
|
-
inFlight = null;
|
|
3388
|
-
});
|
|
3389
|
-
}
|
|
3390
|
-
return inFlight;
|
|
3391
|
-
}
|
|
3392
|
-
};
|
|
3393
|
-
}
|
|
3394
|
-
function createAuthTokenSourceFromEnv(env = process.env, fetchFn, readStoredCred = () => null) {
|
|
3395
|
-
const refreshToken = env["VO_USER_REFRESH_TOKEN"]?.trim();
|
|
3396
|
-
const apiKey = env["VO_FIREBASE_API_KEY"]?.trim();
|
|
3397
|
-
const idToken = env["VO_USER_ID_TOKEN"]?.trim();
|
|
3398
|
-
const adminToken = env["VO_CONTROL_PLANE_ADMIN_TOKEN"]?.trim();
|
|
3399
|
-
if (refreshToken || apiKey) {
|
|
3400
|
-
if (!refreshToken || !apiKey) {
|
|
3401
|
-
throw new Error(
|
|
3402
|
-
"Per-user refresh auth requires BOTH VO_USER_REFRESH_TOKEN and VO_FIREBASE_API_KEY"
|
|
3403
|
-
);
|
|
3404
|
-
}
|
|
3405
|
-
return createFirebaseRefreshTokenSource({
|
|
3406
|
-
refreshToken,
|
|
3407
|
-
apiKey,
|
|
3408
|
-
...fetchFn ? { fetchFn } : {}
|
|
3409
|
-
});
|
|
3410
|
-
}
|
|
3411
|
-
if (idToken) return createStaticTokenSource(idToken, "firebase-id-token");
|
|
3412
|
-
const stored = readStoredCred();
|
|
3413
|
-
if (stored?.vo_credential && stored.vo_credential.trim()) {
|
|
3414
|
-
return createStaticTokenSource(stored.vo_credential.trim(), "vo-credential");
|
|
3415
|
-
}
|
|
3416
|
-
if (stored && stored.refresh_token?.trim() && stored.api_key?.trim()) {
|
|
3417
|
-
return createFirebaseRefreshTokenSource({
|
|
3418
|
-
refreshToken: stored.refresh_token.trim(),
|
|
3419
|
-
apiKey: stored.api_key.trim(),
|
|
3420
|
-
...fetchFn ? { fetchFn } : {}
|
|
3421
|
-
});
|
|
3422
|
-
}
|
|
3423
|
-
if (adminToken) return createStaticTokenSource(adminToken, "admin-token");
|
|
3424
|
-
return null;
|
|
3425
|
-
}
|
|
3426
|
-
|
|
3427
|
-
// src/cloud/credential-store.ts
|
|
3428
|
-
import { homedir as homedir3 } from "node:os";
|
|
3429
|
-
import { join as join5, dirname as dirname4 } from "node:path";
|
|
3430
|
-
import {
|
|
3431
|
-
existsSync as existsSync3,
|
|
3432
|
-
mkdirSync as mkdirSync2,
|
|
3433
|
-
readFileSync as readFileSync5,
|
|
3434
|
-
writeFileSync as writeFileSync2,
|
|
3435
|
-
chmodSync as chmodSync2,
|
|
3436
|
-
rmSync
|
|
3437
|
-
} from "node:fs";
|
|
3438
|
-
|
|
3439
|
-
// src/cloud/keychain.ts
|
|
3440
|
-
import { createRequire } from "node:module";
|
|
3441
|
-
var SERVICE = "vo-mcp";
|
|
3442
|
-
var ACCOUNT = "refresh-credential";
|
|
3443
|
-
var cached;
|
|
3444
|
-
function loadKeyring() {
|
|
3445
|
-
if (cached !== void 0) return cached;
|
|
3446
|
-
try {
|
|
3447
|
-
const req = createRequire(import.meta.url);
|
|
3448
|
-
const mod = req("@napi-rs/keyring");
|
|
3449
|
-
cached = mod && typeof mod.Entry === "function" ? mod : null;
|
|
3450
|
-
} catch {
|
|
3451
|
-
cached = null;
|
|
3452
|
-
}
|
|
3453
|
-
return cached;
|
|
3454
|
-
}
|
|
3455
|
-
function keychainAvailable() {
|
|
3456
|
-
return loadKeyring() !== null;
|
|
3457
|
-
}
|
|
3458
|
-
function keychainGet() {
|
|
3459
|
-
const k = loadKeyring();
|
|
3460
|
-
if (!k) return null;
|
|
3461
|
-
try {
|
|
3462
|
-
return new k.Entry(SERVICE, ACCOUNT).getPassword();
|
|
3463
|
-
} catch {
|
|
3464
|
-
return null;
|
|
3465
|
-
}
|
|
3466
|
-
}
|
|
3467
|
-
function keychainSet(secret) {
|
|
3468
|
-
const k = loadKeyring();
|
|
3469
|
-
if (!k) return false;
|
|
3470
|
-
try {
|
|
3471
|
-
new k.Entry(SERVICE, ACCOUNT).setPassword(secret);
|
|
3472
|
-
return true;
|
|
3473
|
-
} catch {
|
|
3474
|
-
return false;
|
|
3475
|
-
}
|
|
3476
|
-
}
|
|
3477
|
-
function keychainDelete() {
|
|
3478
|
-
const k = loadKeyring();
|
|
3479
|
-
if (!k) return false;
|
|
3480
|
-
try {
|
|
3481
|
-
return new k.Entry(SERVICE, ACCOUNT).deletePassword();
|
|
3482
|
-
} catch {
|
|
3483
|
-
return false;
|
|
3484
|
-
}
|
|
3485
|
-
}
|
|
3486
|
-
|
|
3487
|
-
// src/cloud/credential-store.ts
|
|
3488
|
-
var realKeychain = {
|
|
3489
|
-
available: keychainAvailable,
|
|
3490
|
-
get: keychainGet,
|
|
3491
|
-
set: keychainSet,
|
|
3492
|
-
delete: keychainDelete
|
|
3493
|
-
};
|
|
3494
|
-
var KEYCHAIN_LOCATION = 'OS keychain (service "vo-mcp")';
|
|
3495
|
-
function credentialPath(env = process.env) {
|
|
3496
|
-
const override = env["VO_MCP_CREDENTIALS_PATH"]?.trim();
|
|
3497
|
-
if (override) return override;
|
|
3498
|
-
return join5(homedir3(), ".config", "vo-mcp", "credentials.json");
|
|
3499
|
-
}
|
|
3500
|
-
function keychainEnabled(env, keychain) {
|
|
3501
|
-
const disabled = (env["VO_MCP_DISABLE_KEYCHAIN"] ?? "").trim().toLowerCase();
|
|
3502
|
-
if (disabled === "1" || disabled === "true" || disabled === "yes") return false;
|
|
3503
|
-
return keychain.available();
|
|
3504
|
-
}
|
|
3505
|
-
function deserialize(raw) {
|
|
3506
|
-
try {
|
|
3507
|
-
const parsed = JSON.parse(raw);
|
|
3508
|
-
const refresh = typeof parsed.refresh_token === "string" ? parsed.refresh_token.trim() : "";
|
|
3509
|
-
const apiKey = typeof parsed.api_key === "string" ? parsed.api_key.trim() : "";
|
|
3510
|
-
const voCred = typeof parsed.vo_credential === "string" ? parsed.vo_credential.trim() : "";
|
|
3511
|
-
if (!voCred && (!refresh || !apiKey)) return null;
|
|
3512
|
-
return {
|
|
3513
|
-
...refresh ? { refresh_token: refresh } : {},
|
|
3514
|
-
...apiKey ? { api_key: apiKey } : {},
|
|
3515
|
-
...voCred ? { vo_credential: voCred } : {},
|
|
3516
|
-
...typeof parsed.vo_credential_expires_at === "string" ? { vo_credential_expires_at: parsed.vo_credential_expires_at } : {},
|
|
3517
|
-
...typeof parsed.email === "string" ? { email: parsed.email } : {},
|
|
3518
|
-
...typeof parsed.stored_at === "string" ? { stored_at: parsed.stored_at } : {}
|
|
3519
|
-
};
|
|
3520
|
-
} catch {
|
|
3521
|
-
return null;
|
|
3522
|
-
}
|
|
3523
|
-
}
|
|
3524
|
-
function readFromFile(env) {
|
|
3525
|
-
try {
|
|
3526
|
-
const p = credentialPath(env);
|
|
3527
|
-
if (!existsSync3(p)) return null;
|
|
3528
|
-
return deserialize(readFileSync5(p, "utf8"));
|
|
3529
|
-
} catch {
|
|
3530
|
-
return null;
|
|
3531
|
-
}
|
|
3532
|
-
}
|
|
3533
|
-
function readStoredCredential(env = process.env, keychain = realKeychain) {
|
|
3534
|
-
if (keychainEnabled(env, keychain)) {
|
|
3535
|
-
const raw = keychain.get();
|
|
3536
|
-
const fromKeychain = raw ? deserialize(raw) : null;
|
|
3537
|
-
if (fromKeychain) return fromKeychain;
|
|
3538
|
-
}
|
|
3539
|
-
return readFromFile(env);
|
|
3540
|
-
}
|
|
3541
|
-
function deleteFile(env) {
|
|
3542
|
-
try {
|
|
3543
|
-
rmSync(credentialPath(env), { force: true });
|
|
3544
|
-
} catch {
|
|
3545
|
-
}
|
|
3546
|
-
}
|
|
3547
|
-
function writeToFile(payload, env) {
|
|
3548
|
-
const p = credentialPath(env);
|
|
3549
|
-
mkdirSync2(dirname4(p), { recursive: true });
|
|
3550
|
-
writeFileSync2(p, `${JSON.stringify(payload, null, 2)}
|
|
3551
|
-
`, { mode: 384 });
|
|
3552
|
-
try {
|
|
3553
|
-
chmodSync2(p, 384);
|
|
3554
|
-
} catch {
|
|
3555
|
-
}
|
|
3556
|
-
return p;
|
|
3557
|
-
}
|
|
3558
|
-
function writeStoredCredential(cred, storedAt, env = process.env, keychain = realKeychain) {
|
|
3678
|
+
};
|
|
3679
|
+
});
|
|
3680
|
+
const synthText = engineResult.synthesized_verdict.reasoning_excerpt;
|
|
3681
|
+
const synthPlan = tryParseDispatchPlan(synthText);
|
|
3559
3682
|
const payload = {
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
...
|
|
3564
|
-
|
|
3565
|
-
|
|
3683
|
+
verdict: synthPlan !== null ? "pass" : "uncertain",
|
|
3684
|
+
reason: synthPlan !== null ? "Synthesized dispatch plan parsed successfully" : "Synthesized verdict did not parse as a valid dispatch plan JSON \u2014 see per_model_plans for raw outputs",
|
|
3685
|
+
dispatch_plan: synthPlan,
|
|
3686
|
+
...synthPlan === null ? { parse_error: "synthesized verdict text was not valid dispatch-plan JSON" } : {},
|
|
3687
|
+
per_model_plans: perModelPlans,
|
|
3688
|
+
synthesized_reasoning: synthText,
|
|
3689
|
+
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
3690
|
+
engine_version: engineResult.engine_version,
|
|
3691
|
+
...engineResult.per_model_verdicts.length < 3 ? { degraded: true } : {}
|
|
3566
3692
|
};
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3693
|
+
const envelope = {
|
|
3694
|
+
tool: TOOL_NAME7,
|
|
3695
|
+
schema_version: 1,
|
|
3696
|
+
cache: { hit: false, key },
|
|
3697
|
+
payload
|
|
3698
|
+
};
|
|
3699
|
+
deps.cache.set(key, envelope);
|
|
3700
|
+
const enrichedEvent = {
|
|
3701
|
+
...baseEvent,
|
|
3702
|
+
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
3703
|
+
duration_ms: engineResult.duration_ms,
|
|
3704
|
+
consensus_engine_version: engineResult.engine_version,
|
|
3705
|
+
per_model_verdicts: toEventPerModelVerdicts(engineResult.per_model_verdicts),
|
|
3706
|
+
synthesized_verdict: toEventSynthesizedVerdict(engineResult.synthesized_verdict)
|
|
3707
|
+
};
|
|
3708
|
+
deps.events.append(enrichedEvent);
|
|
3709
|
+
return jsonContent(envelope);
|
|
3574
3710
|
}
|
|
3575
3711
|
|
|
3576
3712
|
// src/cloud/admin-callable-client.ts
|
|
3713
|
+
init_auth_token_source();
|
|
3714
|
+
init_credential_store();
|
|
3577
3715
|
var AdminCallableError = class extends Error {
|
|
3578
3716
|
constructor(status, path3, message) {
|
|
3579
3717
|
super(message);
|
|
@@ -4507,7 +4645,7 @@ var inputSchema19 = {
|
|
|
4507
4645
|
additionalProperties: false
|
|
4508
4646
|
};
|
|
4509
4647
|
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).";
|
|
4510
|
-
function
|
|
4648
|
+
function isStringArray2(v, maxItems) {
|
|
4511
4649
|
if (!Array.isArray(v)) return false;
|
|
4512
4650
|
if (v.length > maxItems) return false;
|
|
4513
4651
|
return v.every((item) => typeof item === "string");
|
|
@@ -4523,14 +4661,64 @@ function isToolInput19(v) {
|
|
|
4523
4661
|
if (!Number.isFinite(o["context_used_pct"])) return false;
|
|
4524
4662
|
if (o["context_used_pct"] < 0 || o["context_used_pct"] > 100) return false;
|
|
4525
4663
|
if (o["current_goal"] !== void 0 && typeof o["current_goal"] !== "string") return false;
|
|
4526
|
-
if (o["recent_files_touched"] !== void 0 && !
|
|
4664
|
+
if (o["recent_files_touched"] !== void 0 && !isStringArray2(o["recent_files_touched"], MAX_RECENT_FILES)) {
|
|
4527
4665
|
return false;
|
|
4528
4666
|
}
|
|
4529
|
-
if (o["recent_tool_uses"] !== void 0 && !
|
|
4667
|
+
if (o["recent_tool_uses"] !== void 0 && !isStringArray2(o["recent_tool_uses"], MAX_RECENT_TOOLS)) {
|
|
4530
4668
|
return false;
|
|
4531
4669
|
}
|
|
4532
4670
|
return true;
|
|
4533
4671
|
}
|
|
4672
|
+
function getCloudConfig() {
|
|
4673
|
+
const url = process.env["VO_CONTROL_PLANE_URL"];
|
|
4674
|
+
const token = process.env["VO_CONTROL_PLANE_ADMIN_TOKEN"];
|
|
4675
|
+
if (!url || !token) return null;
|
|
4676
|
+
return { url, token };
|
|
4677
|
+
}
|
|
4678
|
+
async function tryCloudReportState(cloud, input) {
|
|
4679
|
+
try {
|
|
4680
|
+
const body = {
|
|
4681
|
+
context_used_pct: input.context_used_pct
|
|
4682
|
+
};
|
|
4683
|
+
if (input.current_goal !== void 0) body["current_goal"] = input.current_goal;
|
|
4684
|
+
if (input.recent_files_touched !== void 0) {
|
|
4685
|
+
body["recent_files_touched"] = input.recent_files_touched;
|
|
4686
|
+
}
|
|
4687
|
+
if (input.recent_tool_uses !== void 0) {
|
|
4688
|
+
body["recent_tool_uses"] = input.recent_tool_uses;
|
|
4689
|
+
}
|
|
4690
|
+
const url = `${cloud.url}/api/v1/session/${input.session_id}/report-state`;
|
|
4691
|
+
const response = await fetch(url, {
|
|
4692
|
+
method: "POST",
|
|
4693
|
+
headers: {
|
|
4694
|
+
"Content-Type": "application/json",
|
|
4695
|
+
"Authorization": `Bearer ${cloud.token}`
|
|
4696
|
+
},
|
|
4697
|
+
body: JSON.stringify(body)
|
|
4698
|
+
});
|
|
4699
|
+
if (!response.ok) {
|
|
4700
|
+
return null;
|
|
4701
|
+
}
|
|
4702
|
+
const data = await response.json();
|
|
4703
|
+
if (!data.ok || !data.session || !data.directive) {
|
|
4704
|
+
return null;
|
|
4705
|
+
}
|
|
4706
|
+
return {
|
|
4707
|
+
directive: data.directive.action,
|
|
4708
|
+
message: data.directive.message,
|
|
4709
|
+
session_id: data.session.session_id,
|
|
4710
|
+
operator_id: data.session.operator_id,
|
|
4711
|
+
agent_type: input.agent_type,
|
|
4712
|
+
context_used_pct: data.session.context_used_pct,
|
|
4713
|
+
backend_mode: "cloud-control-plane",
|
|
4714
|
+
ts: data.session.last_seen_at,
|
|
4715
|
+
schema_version: 1,
|
|
4716
|
+
...data.directive.action === "execute_handoff_now" ? { handoff_path: suggestedHandoffPath(data.session.session_id, data.session.last_seen_at) } : {}
|
|
4717
|
+
};
|
|
4718
|
+
} catch {
|
|
4719
|
+
return null;
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4534
4722
|
async function handleReportSessionState(deps, rawInput, _signal) {
|
|
4535
4723
|
if (!isToolInput19(rawInput)) {
|
|
4536
4724
|
throw invalidParams(
|
|
@@ -4538,6 +4726,13 @@ async function handleReportSessionState(deps, rawInput, _signal) {
|
|
|
4538
4726
|
`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}).`
|
|
4539
4727
|
);
|
|
4540
4728
|
}
|
|
4729
|
+
const cloud = getCloudConfig();
|
|
4730
|
+
if (cloud !== null) {
|
|
4731
|
+
const cloudPayload = await tryCloudReportState(cloud, rawInput);
|
|
4732
|
+
if (cloudPayload !== null) {
|
|
4733
|
+
return jsonContent(cloudPayload);
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4541
4736
|
const directive = computeDirective(rawInput.context_used_pct);
|
|
4542
4737
|
const ts = deps.now().toISOString();
|
|
4543
4738
|
const payload = {
|
|
@@ -4555,6 +4750,141 @@ async function handleReportSessionState(deps, rawInput, _signal) {
|
|
|
4555
4750
|
return jsonContent(payload);
|
|
4556
4751
|
}
|
|
4557
4752
|
|
|
4753
|
+
// src/tools/session/spawn-successor.ts
|
|
4754
|
+
import { spawn } from "node:child_process";
|
|
4755
|
+
import { homedir as homedir4 } from "node:os";
|
|
4756
|
+
import { join as join6 } from "node:path";
|
|
4757
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
|
|
4758
|
+
var TOOL_NAME20 = "vo_spawn_successor";
|
|
4759
|
+
var MAX_HANDOFF_BYTES = 64e3;
|
|
4760
|
+
var inputSchema20 = {
|
|
4761
|
+
type: "object",
|
|
4762
|
+
properties: {
|
|
4763
|
+
handoff_path: {
|
|
4764
|
+
type: "string",
|
|
4765
|
+
description: "Path to the handoff doc to pre-inject. Default: the newest .md in ~/.vo/handoffs/."
|
|
4766
|
+
},
|
|
4767
|
+
goal: {
|
|
4768
|
+
type: "string",
|
|
4769
|
+
description: "Optional one-line goal override appended after the handoff."
|
|
4770
|
+
},
|
|
4771
|
+
cwd: {
|
|
4772
|
+
type: "string",
|
|
4773
|
+
description: "Working directory for the successor (default: the repo the handoff names, else process cwd)."
|
|
4774
|
+
},
|
|
4775
|
+
max_turns: {
|
|
4776
|
+
type: "number",
|
|
4777
|
+
description: "Optional --max-turns bound for the successor."
|
|
4778
|
+
}
|
|
4779
|
+
},
|
|
4780
|
+
required: [],
|
|
4781
|
+
additionalProperties: false
|
|
4782
|
+
};
|
|
4783
|
+
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.";
|
|
4784
|
+
function isToolInput20(v) {
|
|
4785
|
+
if (typeof v !== "object" || v === null) return false;
|
|
4786
|
+
const o = v;
|
|
4787
|
+
if (o["handoff_path"] !== void 0 && typeof o["handoff_path"] !== "string") return false;
|
|
4788
|
+
if (o["goal"] !== void 0 && typeof o["goal"] !== "string") return false;
|
|
4789
|
+
if (o["cwd"] !== void 0 && typeof o["cwd"] !== "string") return false;
|
|
4790
|
+
if (o["max_turns"] !== void 0 && typeof o["max_turns"] !== "number") return false;
|
|
4791
|
+
return true;
|
|
4792
|
+
}
|
|
4793
|
+
function newestHandoff(dir = join6(homedir4(), ".vo", "handoffs")) {
|
|
4794
|
+
try {
|
|
4795
|
+
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);
|
|
4796
|
+
return entries.length > 0 && entries[0] ? join6(dir, entries[0].f) : null;
|
|
4797
|
+
} catch {
|
|
4798
|
+
return null;
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4801
|
+
var MANDATORY_READS = [
|
|
4802
|
+
"CLAUDE.md + AGENTS.md + README.md (repo root)",
|
|
4803
|
+
"docs/current/virtual-office-agent-charter.md, -operating-model.md, -test-architect.md",
|
|
4804
|
+
"docs/current/evidence-grounded-consensus-testing.md",
|
|
4805
|
+
"docs/vo/ADR-001-* (verify + sign, human approves merge; no autonomous bot-merge / headless triggers) + docs/vo/vo-adr-002-two-plane-moat.md",
|
|
4806
|
+
"docs/vo/vo-roadmap-2026-05-26.md (read the Change log tail for current state)",
|
|
4807
|
+
"the operator memory index ~/.claude/projects/C--Users-greyl/memory/MEMORY.md"
|
|
4808
|
+
];
|
|
4809
|
+
function buildSuccessorPrompt(handoffMarkdown, goal) {
|
|
4810
|
+
const reads = MANDATORY_READS.map((r, i) => ` ${i + 1}. ${r}`).join("\n");
|
|
4811
|
+
const lines = [
|
|
4812
|
+
"You are the SUCCESSOR agent for a Virtual Office lane. The previous session",
|
|
4813
|
+
"exhausted its context and wrote the handoff below. Read it fully, verify its",
|
|
4814
|
+
'"verification needed" items against live state (a handoff is a claim, not',
|
|
4815
|
+
"evidence \u2014 verify via `git show origin/main:<path>`), then continue the lane.",
|
|
4816
|
+
"",
|
|
4817
|
+
"MANDATORY READS before writing any code (NOT all auto-loaded \u2014 open them):",
|
|
4818
|
+
reads,
|
|
4819
|
+
"",
|
|
4820
|
+
"NON-NEGOTIABLES: multi-model consensus verification is the core; test honesty",
|
|
4821
|
+
"(verified-answer-only, no fake green); verify-before-act + human merge approval;",
|
|
4822
|
+
"never a full functions-shared deploy; Gen2 only; work in a worktree on your own",
|
|
4823
|
+
"branch; finish line is MERGED + DEPLOYED + LIVE-VERIFIED, and VO changes update",
|
|
4824
|
+
"the roadmap in the same PR.",
|
|
4825
|
+
"",
|
|
4826
|
+
"--- HANDOFF ---",
|
|
4827
|
+
handoffMarkdown,
|
|
4828
|
+
"--- END HANDOFF ---"
|
|
4829
|
+
];
|
|
4830
|
+
if (goal && goal.trim().length > 0) lines.push("", `OPERATOR GOAL OVERRIDE: ${goal.trim()}`);
|
|
4831
|
+
return lines.join("\n");
|
|
4832
|
+
}
|
|
4833
|
+
function buildSuccessorArgs(maxTurns) {
|
|
4834
|
+
const args = ["-p", "--permission-mode", "acceptEdits"];
|
|
4835
|
+
if (Number.isInteger(maxTurns) && maxTurns > 0) {
|
|
4836
|
+
args.push("--max-turns", String(maxTurns));
|
|
4837
|
+
}
|
|
4838
|
+
return args;
|
|
4839
|
+
}
|
|
4840
|
+
async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn) {
|
|
4841
|
+
if (!isToolInput20(rawInput)) {
|
|
4842
|
+
throw invalidParams(TOOL_NAME20, "invalid input. Optional: { handoff_path, goal, cwd, max_turns }.");
|
|
4843
|
+
}
|
|
4844
|
+
const handoffPath = rawInput.handoff_path?.trim() || newestHandoff();
|
|
4845
|
+
if (!handoffPath || !existsSync4(handoffPath)) {
|
|
4846
|
+
return jsonContent({
|
|
4847
|
+
tool: TOOL_NAME20,
|
|
4848
|
+
schema_version: 1,
|
|
4849
|
+
payload: {
|
|
4850
|
+
spawned: false,
|
|
4851
|
+
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)"
|
|
4852
|
+
}
|
|
4853
|
+
});
|
|
4854
|
+
}
|
|
4855
|
+
const handoff = readFileSync6(handoffPath, "utf8").slice(0, MAX_HANDOFF_BYTES);
|
|
4856
|
+
const prompt = buildSuccessorPrompt(handoff, rawInput.goal);
|
|
4857
|
+
const logDir = process.env["VO_MCP_SUCCESSOR_LOG_DIR"]?.trim() || join6(homedir4(), ".vo", "successors");
|
|
4858
|
+
mkdirSync3(logDir, { recursive: true });
|
|
4859
|
+
const logPath = join6(logDir, `successor-${Date.now()}.log`);
|
|
4860
|
+
const logFd = openSync(logPath, "a");
|
|
4861
|
+
const child = spawnImpl("claude", buildSuccessorArgs(rawInput.max_turns), {
|
|
4862
|
+
cwd: rawInput.cwd?.trim() || process.cwd(),
|
|
4863
|
+
detached: true,
|
|
4864
|
+
stdio: ["pipe", logFd, logFd],
|
|
4865
|
+
// Windows: `claude` is a .cmd shim — needs a shell to resolve. The prompt
|
|
4866
|
+
// goes via STDIN below, never argv, so the shell never sees it.
|
|
4867
|
+
shell: process.platform === "win32",
|
|
4868
|
+
windowsHide: true
|
|
4869
|
+
});
|
|
4870
|
+
let spawnError = null;
|
|
4871
|
+
child.on("error", (e) => {
|
|
4872
|
+
spawnError = e.message;
|
|
4873
|
+
});
|
|
4874
|
+
try {
|
|
4875
|
+
child.stdin.write(prompt);
|
|
4876
|
+
child.stdin.end();
|
|
4877
|
+
} catch {
|
|
4878
|
+
}
|
|
4879
|
+
child.unref();
|
|
4880
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
4881
|
+
return jsonContent({
|
|
4882
|
+
tool: TOOL_NAME20,
|
|
4883
|
+
schema_version: 1,
|
|
4884
|
+
payload: spawnError ? { spawned: false, reason: `spawn failed: ${spawnError}`, handoff_path: handoffPath } : { spawned: true, pid: child.pid ?? null, log_path: logPath, handoff_path: handoffPath }
|
|
4885
|
+
});
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4558
4888
|
// src/tools/concierge/common-concierge.ts
|
|
4559
4889
|
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.";
|
|
4560
4890
|
var CONCIERGE_GATE_TYPE = "concierge-dispatch";
|
|
@@ -4573,10 +4903,10 @@ function isKnownConciergePack(value) {
|
|
|
4573
4903
|
}
|
|
4574
4904
|
|
|
4575
4905
|
// src/tools/concierge/dispatch.ts
|
|
4576
|
-
var
|
|
4906
|
+
var TOOL_NAME21 = "vo_concierge_dispatch";
|
|
4577
4907
|
var CALLABLE_NAME10 = "voConciergeDispatch";
|
|
4578
4908
|
var ADMIN_PATH10 = "/api/v1/admin/concierge/dispatch";
|
|
4579
|
-
var
|
|
4909
|
+
var inputSchema21 = {
|
|
4580
4910
|
type: "object",
|
|
4581
4911
|
properties: {
|
|
4582
4912
|
pack: {
|
|
@@ -4591,8 +4921,8 @@ var inputSchema20 = {
|
|
|
4591
4921
|
},
|
|
4592
4922
|
additionalProperties: false
|
|
4593
4923
|
};
|
|
4594
|
-
var
|
|
4595
|
-
function
|
|
4924
|
+
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'`.";
|
|
4925
|
+
function isToolInput21(v) {
|
|
4596
4926
|
if (typeof v !== "object" || v === null) return false;
|
|
4597
4927
|
const obj = v;
|
|
4598
4928
|
if (obj.pack !== void 0 && typeof obj.pack !== "string") return false;
|
|
@@ -4600,15 +4930,15 @@ function isToolInput20(v) {
|
|
|
4600
4930
|
return true;
|
|
4601
4931
|
}
|
|
4602
4932
|
async function handleConciergeDispatch(deps, rawInput, _signal) {
|
|
4603
|
-
if (!
|
|
4933
|
+
if (!isToolInput21(rawInput)) {
|
|
4604
4934
|
throw invalidParams(
|
|
4605
|
-
|
|
4935
|
+
TOOL_NAME21,
|
|
4606
4936
|
"invalid input. Expected { pack?: string, tenant_id?: string }."
|
|
4607
4937
|
);
|
|
4608
4938
|
}
|
|
4609
4939
|
if (rawInput.pack !== void 0 && rawInput.pack !== "" && !isKnownConciergePack(rawInput.pack)) {
|
|
4610
4940
|
throw invalidParams(
|
|
4611
|
-
|
|
4941
|
+
TOOL_NAME21,
|
|
4612
4942
|
`unknown pack: ${JSON.stringify(rawInput.pack)}. Known packs: ${KNOWN_CONCIERGE_PACKS.join(", ")}.`
|
|
4613
4943
|
);
|
|
4614
4944
|
}
|
|
@@ -4619,7 +4949,7 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
|
|
|
4619
4949
|
if (rawInput.pack) cloudBody.pack = rawInput.pack;
|
|
4620
4950
|
if (rawInput.tenant_id) cloudBody.tenantId = rawInput.tenant_id;
|
|
4621
4951
|
return buildCloudOrStubResponse({
|
|
4622
|
-
toolName:
|
|
4952
|
+
toolName: TOOL_NAME21,
|
|
4623
4953
|
callableName: CALLABLE_NAME10,
|
|
4624
4954
|
adminPath: ADMIN_PATH10,
|
|
4625
4955
|
normalizedInput,
|
|
@@ -4636,6 +4966,254 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
|
|
|
4636
4966
|
});
|
|
4637
4967
|
}
|
|
4638
4968
|
|
|
4969
|
+
// src/tools/memory/sync-config.ts
|
|
4970
|
+
import { homedir as homedir5 } from "node:os";
|
|
4971
|
+
import { join as join7 } from "node:path";
|
|
4972
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "node:fs";
|
|
4973
|
+
var TOOL_NAME22 = "vo_sync_config";
|
|
4974
|
+
var inputSchema22 = {
|
|
4975
|
+
type: "object",
|
|
4976
|
+
properties: {
|
|
4977
|
+
action: {
|
|
4978
|
+
type: "string",
|
|
4979
|
+
enum: ["pull", "push"],
|
|
4980
|
+
description: "pull: download cloud memory to local files. push: upload local files to cloud."
|
|
4981
|
+
},
|
|
4982
|
+
cwd: {
|
|
4983
|
+
type: "string",
|
|
4984
|
+
description: "Working directory to derive project slug from (default: process.cwd())."
|
|
4985
|
+
}
|
|
4986
|
+
},
|
|
4987
|
+
required: ["action"],
|
|
4988
|
+
additionalProperties: false
|
|
4989
|
+
};
|
|
4990
|
+
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.";
|
|
4991
|
+
function isToolInput22(v) {
|
|
4992
|
+
if (typeof v !== "object" || v === null) return false;
|
|
4993
|
+
const o = v;
|
|
4994
|
+
if (o["action"] !== "pull" && o["action"] !== "push") return false;
|
|
4995
|
+
if (o["cwd"] !== void 0 && typeof o["cwd"] !== "string") return false;
|
|
4996
|
+
return true;
|
|
4997
|
+
}
|
|
4998
|
+
function deriveProjectSlug(cwd) {
|
|
4999
|
+
const normalized = cwd.replace(/\\/g, "/");
|
|
5000
|
+
return normalized.replace(/^([A-Z]):/i, (_, drive) => `${drive.toUpperCase()}-`).replace(/\/$/g, "").split("/").join("--").replace(/\s+/g, "-");
|
|
5001
|
+
}
|
|
5002
|
+
function getMemoryDir(cwd) {
|
|
5003
|
+
const slug = deriveProjectSlug(cwd);
|
|
5004
|
+
return join7(homedir5(), ".claude", "projects", slug, "memory");
|
|
5005
|
+
}
|
|
5006
|
+
async function pullMemory(controlPlaneUrl, token, memoryDir, sessionId, fetchFn) {
|
|
5007
|
+
const url = `${controlPlaneUrl}/api/v1/agent-config/memory/me`;
|
|
5008
|
+
const response = await fetchFn(url, {
|
|
5009
|
+
method: "GET",
|
|
5010
|
+
headers: {
|
|
5011
|
+
authorization: `Bearer ${token}`
|
|
5012
|
+
}
|
|
5013
|
+
});
|
|
5014
|
+
if (response.status !== 200) {
|
|
5015
|
+
const text = await response.text();
|
|
5016
|
+
throw new Error(`GET /api/v1/agent-config/memory/me returned HTTP ${response.status}: ${text.slice(0, 200)}`);
|
|
5017
|
+
}
|
|
5018
|
+
const data = JSON.parse(await response.text());
|
|
5019
|
+
if (!data.ok || !Array.isArray(data.entries)) {
|
|
5020
|
+
throw new Error("GET /api/v1/agent-config/memory/me response missing ok=true or entries array");
|
|
5021
|
+
}
|
|
5022
|
+
mkdirSync4(memoryDir, { recursive: true });
|
|
5023
|
+
const files = [];
|
|
5024
|
+
for (const entry of data.entries) {
|
|
5025
|
+
const filePath = join7(memoryDir, entry.file_name);
|
|
5026
|
+
writeFileSync3(filePath, entry.content, "utf8");
|
|
5027
|
+
files.push(entry.file_name);
|
|
5028
|
+
}
|
|
5029
|
+
return { pulled: data.entries.length, files };
|
|
5030
|
+
}
|
|
5031
|
+
async function pushMemory(controlPlaneUrl, token, memoryDir, sessionId, fetchFn) {
|
|
5032
|
+
if (!existsSync5(memoryDir)) {
|
|
5033
|
+
return { pushed: 0, created: 0, updated: 0 };
|
|
5034
|
+
}
|
|
5035
|
+
const localFiles = readdirSync4(memoryDir).filter((f) => f.endsWith(".md")).map((f) => ({
|
|
5036
|
+
file_name: f,
|
|
5037
|
+
content: readFileSync7(join7(memoryDir, f), "utf8"),
|
|
5038
|
+
entry_type: f === "MEMORY.md" ? "index" : "topic"
|
|
5039
|
+
}));
|
|
5040
|
+
if (localFiles.length === 0) {
|
|
5041
|
+
return { pushed: 0, created: 0, updated: 0 };
|
|
5042
|
+
}
|
|
5043
|
+
const getUrl = `${controlPlaneUrl}/api/v1/agent-config/memory/me`;
|
|
5044
|
+
const getResponse = await fetchFn(getUrl, {
|
|
5045
|
+
method: "GET",
|
|
5046
|
+
headers: {
|
|
5047
|
+
authorization: `Bearer ${token}`
|
|
5048
|
+
}
|
|
5049
|
+
});
|
|
5050
|
+
const existingMap = /* @__PURE__ */ new Map();
|
|
5051
|
+
if (getResponse.status === 200) {
|
|
5052
|
+
const getData = JSON.parse(await getResponse.text());
|
|
5053
|
+
if (getData.ok && Array.isArray(getData.entries)) {
|
|
5054
|
+
for (const entry of getData.entries) {
|
|
5055
|
+
existingMap.set(entry.file_name, entry.memory_id);
|
|
5056
|
+
}
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
let created = 0;
|
|
5060
|
+
let updated = 0;
|
|
5061
|
+
for (const localFile of localFiles) {
|
|
5062
|
+
const memoryId = existingMap.get(localFile.file_name);
|
|
5063
|
+
if (memoryId) {
|
|
5064
|
+
const updateUrl = `${controlPlaneUrl}/api/v1/agent-config/memory/${memoryId}`;
|
|
5065
|
+
const updateBody = {
|
|
5066
|
+
content: localFile.content,
|
|
5067
|
+
session_id: sessionId
|
|
5068
|
+
};
|
|
5069
|
+
const updateResponse = await fetchFn(updateUrl, {
|
|
5070
|
+
method: "PUT",
|
|
5071
|
+
headers: {
|
|
5072
|
+
authorization: `Bearer ${token}`,
|
|
5073
|
+
"content-type": "application/json"
|
|
5074
|
+
},
|
|
5075
|
+
body: JSON.stringify(updateBody)
|
|
5076
|
+
});
|
|
5077
|
+
if (updateResponse.status !== 200) {
|
|
5078
|
+
const text = await updateResponse.text();
|
|
5079
|
+
throw new Error(
|
|
5080
|
+
`PUT /api/v1/agent-config/memory/${memoryId} returned HTTP ${updateResponse.status}: ${text.slice(0, 200)}`
|
|
5081
|
+
);
|
|
5082
|
+
}
|
|
5083
|
+
const updateData = JSON.parse(await updateResponse.text());
|
|
5084
|
+
if (!updateData.ok) {
|
|
5085
|
+
throw new Error(`PUT /api/v1/agent-config/memory/${memoryId} returned ok=false`);
|
|
5086
|
+
}
|
|
5087
|
+
updated++;
|
|
5088
|
+
} else {
|
|
5089
|
+
const createUrl = `${controlPlaneUrl}/api/v1/agent-config/memory/me`;
|
|
5090
|
+
const createBody = {
|
|
5091
|
+
entry_type: localFile.entry_type,
|
|
5092
|
+
file_name: localFile.file_name,
|
|
5093
|
+
content: localFile.content,
|
|
5094
|
+
session_id: sessionId
|
|
5095
|
+
};
|
|
5096
|
+
const createResponse = await fetchFn(createUrl, {
|
|
5097
|
+
method: "POST",
|
|
5098
|
+
headers: {
|
|
5099
|
+
authorization: `Bearer ${token}`,
|
|
5100
|
+
"content-type": "application/json"
|
|
5101
|
+
},
|
|
5102
|
+
body: JSON.stringify(createBody)
|
|
5103
|
+
});
|
|
5104
|
+
if (createResponse.status !== 200 && createResponse.status !== 201) {
|
|
5105
|
+
const text = await createResponse.text();
|
|
5106
|
+
throw new Error(
|
|
5107
|
+
`POST /api/v1/agent-config/memory/me returned HTTP ${createResponse.status}: ${text.slice(0, 200)}`
|
|
5108
|
+
);
|
|
5109
|
+
}
|
|
5110
|
+
const createData = JSON.parse(await createResponse.text());
|
|
5111
|
+
if (!createData.ok) {
|
|
5112
|
+
throw new Error("POST /api/v1/agent-config/memory/me returned ok=false");
|
|
5113
|
+
}
|
|
5114
|
+
created++;
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
return { pushed: localFiles.length, created, updated };
|
|
5118
|
+
}
|
|
5119
|
+
async function handleSyncConfig(deps, rawInput, _signal, fetchFn = globalThis.fetch) {
|
|
5120
|
+
if (!isToolInput22(rawInput)) {
|
|
5121
|
+
throw invalidParams(
|
|
5122
|
+
TOOL_NAME22,
|
|
5123
|
+
'invalid input. Required: { action: "pull" | "push" }. Optional: { cwd: "<path>" }.'
|
|
5124
|
+
);
|
|
5125
|
+
}
|
|
5126
|
+
const controlPlaneUrl = process.env["VO_CONTROL_PLANE_URL"];
|
|
5127
|
+
if (!controlPlaneUrl) {
|
|
5128
|
+
return jsonContent({
|
|
5129
|
+
tool: TOOL_NAME22,
|
|
5130
|
+
schema_version: 1,
|
|
5131
|
+
payload: {
|
|
5132
|
+
synced: false,
|
|
5133
|
+
reason: "VO_CONTROL_PLANE_URL not set \u2014 cloud mode disabled"
|
|
5134
|
+
}
|
|
5135
|
+
});
|
|
5136
|
+
}
|
|
5137
|
+
const { createAuthTokenSourceFromEnv: createAuthTokenSourceFromEnv2 } = await Promise.resolve().then(() => (init_auth_token_source(), auth_token_source_exports));
|
|
5138
|
+
const { readStoredCredential: readStoredCredential2 } = await Promise.resolve().then(() => (init_credential_store(), credential_store_exports));
|
|
5139
|
+
const tokenSource = createAuthTokenSourceFromEnv2(process.env, fetchFn, () => readStoredCredential2(process.env));
|
|
5140
|
+
if (!tokenSource) {
|
|
5141
|
+
return jsonContent({
|
|
5142
|
+
tool: TOOL_NAME22,
|
|
5143
|
+
schema_version: 1,
|
|
5144
|
+
payload: {
|
|
5145
|
+
synced: false,
|
|
5146
|
+
reason: "No auth configured. Run `vo-mcp login` to authenticate as an operator."
|
|
5147
|
+
}
|
|
5148
|
+
});
|
|
5149
|
+
}
|
|
5150
|
+
const token = await tokenSource.getToken();
|
|
5151
|
+
if (!token) {
|
|
5152
|
+
return jsonContent({
|
|
5153
|
+
tool: TOOL_NAME22,
|
|
5154
|
+
schema_version: 1,
|
|
5155
|
+
payload: {
|
|
5156
|
+
synced: false,
|
|
5157
|
+
reason: "Failed to obtain auth token. Run `vo-mcp login` to re-authenticate."
|
|
5158
|
+
}
|
|
5159
|
+
});
|
|
5160
|
+
}
|
|
5161
|
+
const cwd = rawInput.cwd?.trim() || process.cwd();
|
|
5162
|
+
const memoryDir = getMemoryDir(cwd);
|
|
5163
|
+
try {
|
|
5164
|
+
if (rawInput.action === "pull") {
|
|
5165
|
+
const result = await pullMemory(
|
|
5166
|
+
controlPlaneUrl.replace(/\/+$/, ""),
|
|
5167
|
+
token,
|
|
5168
|
+
memoryDir,
|
|
5169
|
+
deps.sessionId,
|
|
5170
|
+
fetchFn
|
|
5171
|
+
);
|
|
5172
|
+
return jsonContent({
|
|
5173
|
+
tool: TOOL_NAME22,
|
|
5174
|
+
schema_version: 1,
|
|
5175
|
+
payload: {
|
|
5176
|
+
synced: true,
|
|
5177
|
+
action: "pull",
|
|
5178
|
+
pulled: result.pulled,
|
|
5179
|
+
files: result.files,
|
|
5180
|
+
memory_dir: memoryDir
|
|
5181
|
+
}
|
|
5182
|
+
});
|
|
5183
|
+
} else {
|
|
5184
|
+
const result = await pushMemory(
|
|
5185
|
+
controlPlaneUrl.replace(/\/+$/, ""),
|
|
5186
|
+
token,
|
|
5187
|
+
memoryDir,
|
|
5188
|
+
deps.sessionId,
|
|
5189
|
+
fetchFn
|
|
5190
|
+
);
|
|
5191
|
+
return jsonContent({
|
|
5192
|
+
tool: TOOL_NAME22,
|
|
5193
|
+
schema_version: 1,
|
|
5194
|
+
payload: {
|
|
5195
|
+
synced: true,
|
|
5196
|
+
action: "push",
|
|
5197
|
+
pushed: result.pushed,
|
|
5198
|
+
created: result.created,
|
|
5199
|
+
updated: result.updated,
|
|
5200
|
+
memory_dir: memoryDir
|
|
5201
|
+
}
|
|
5202
|
+
});
|
|
5203
|
+
}
|
|
5204
|
+
} catch (err) {
|
|
5205
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5206
|
+
return jsonContent({
|
|
5207
|
+
tool: TOOL_NAME22,
|
|
5208
|
+
schema_version: 1,
|
|
5209
|
+
payload: {
|
|
5210
|
+
synced: false,
|
|
5211
|
+
reason: `Sync failed: ${message}`
|
|
5212
|
+
}
|
|
5213
|
+
});
|
|
5214
|
+
}
|
|
5215
|
+
}
|
|
5216
|
+
|
|
4639
5217
|
// src/server.ts
|
|
4640
5218
|
function buildToolRegistry() {
|
|
4641
5219
|
return {
|
|
@@ -4797,7 +5375,23 @@ function buildToolRegistry() {
|
|
|
4797
5375
|
description: description20,
|
|
4798
5376
|
inputSchema: inputSchema20
|
|
4799
5377
|
},
|
|
5378
|
+
handler: handleSpawnSuccessor
|
|
5379
|
+
},
|
|
5380
|
+
[TOOL_NAME21]: {
|
|
5381
|
+
definition: {
|
|
5382
|
+
name: TOOL_NAME21,
|
|
5383
|
+
description: description21,
|
|
5384
|
+
inputSchema: inputSchema21
|
|
5385
|
+
},
|
|
4800
5386
|
handler: handleConciergeDispatch
|
|
5387
|
+
},
|
|
5388
|
+
[TOOL_NAME22]: {
|
|
5389
|
+
definition: {
|
|
5390
|
+
name: TOOL_NAME22,
|
|
5391
|
+
description: description22,
|
|
5392
|
+
inputSchema: inputSchema22
|
|
5393
|
+
},
|
|
5394
|
+
handler: handleSyncConfig
|
|
4801
5395
|
}
|
|
4802
5396
|
};
|
|
4803
5397
|
}
|
|
@@ -4852,7 +5446,7 @@ function createServer(options) {
|
|
|
4852
5446
|
|
|
4853
5447
|
// src/cache/sqlite-cache.ts
|
|
4854
5448
|
import { createHash as createHash3 } from "node:crypto";
|
|
4855
|
-
import { chmodSync as chmodSync3, mkdirSync as
|
|
5449
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync5 } from "node:fs";
|
|
4856
5450
|
import { dirname as dirname5 } from "node:path";
|
|
4857
5451
|
import { DatabaseSync } from "node:sqlite";
|
|
4858
5452
|
|
|
@@ -4898,7 +5492,7 @@ function normalizeString(s) {
|
|
|
4898
5492
|
function createSqliteCache(options) {
|
|
4899
5493
|
const fileBacked = options.dbPath !== ":memory:";
|
|
4900
5494
|
if (fileBacked) {
|
|
4901
|
-
|
|
5495
|
+
mkdirSync5(dirname5(options.dbPath), { recursive: true, mode: 448 });
|
|
4902
5496
|
}
|
|
4903
5497
|
const versionNamespace = options.cacheVersionNamespace ?? "";
|
|
4904
5498
|
const db = new DatabaseSync(options.dbPath);
|
|
@@ -5084,7 +5678,142 @@ function createNullConsensusEngineClient(reason = NULL_CLIENT_DEFAULT_REASON) {
|
|
|
5084
5678
|
};
|
|
5085
5679
|
}
|
|
5086
5680
|
|
|
5681
|
+
// src/consensus/engine-options.ts
|
|
5682
|
+
var AGREEMENT_GATE_ENV_VAR = "VO_CONSENSUS_AGREEMENT_GATE";
|
|
5683
|
+
function isTruthyFlag(raw) {
|
|
5684
|
+
if (raw === void 0) return false;
|
|
5685
|
+
const v = raw.trim().toLowerCase();
|
|
5686
|
+
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
5687
|
+
}
|
|
5688
|
+
function resolveAgreementGate(args) {
|
|
5689
|
+
const env = args.env ?? process.env;
|
|
5690
|
+
const enabled = args.configEnabled === true || args.configEnabled === void 0 && isTruthyFlag(env[AGREEMENT_GATE_ENV_VAR]);
|
|
5691
|
+
if (!enabled) return void 0;
|
|
5692
|
+
return {
|
|
5693
|
+
enabled: true,
|
|
5694
|
+
...args.probeSize !== void 0 ? { probe_size: args.probeSize } : {},
|
|
5695
|
+
...args.modalAgreementThreshold !== void 0 ? { modal_agreement_threshold: args.modalAgreementThreshold } : {},
|
|
5696
|
+
...args.minConfidence !== void 0 ? { min_confidence: args.minConfidence } : {}
|
|
5697
|
+
};
|
|
5698
|
+
}
|
|
5699
|
+
function buildSourceGroundedFields(config, defaultClassifier) {
|
|
5700
|
+
if (config === void 0) return {};
|
|
5701
|
+
const out = {};
|
|
5702
|
+
const grader = config.citation_grader;
|
|
5703
|
+
if (grader !== void 0 && grader.enabled === true) {
|
|
5704
|
+
const classifier = grader.classifier ?? defaultClassifier;
|
|
5705
|
+
if (classifier !== void 0) {
|
|
5706
|
+
out.citation_grader = {
|
|
5707
|
+
enabled: true,
|
|
5708
|
+
classifier,
|
|
5709
|
+
...grader.escalate_below !== void 0 ? { escalate_below: grader.escalate_below } : {}
|
|
5710
|
+
};
|
|
5711
|
+
}
|
|
5712
|
+
}
|
|
5713
|
+
if (config.allow_url !== void 0) {
|
|
5714
|
+
out.allow_url = config.allow_url;
|
|
5715
|
+
}
|
|
5716
|
+
return out;
|
|
5717
|
+
}
|
|
5718
|
+
function mapFanOutDiagnostics(fd) {
|
|
5719
|
+
if (fd === void 0) return void 0;
|
|
5720
|
+
return {
|
|
5721
|
+
models_called: fd.models_called,
|
|
5722
|
+
panel_size: fd.panel_size,
|
|
5723
|
+
early_exit: fd.early_exit,
|
|
5724
|
+
refused: fd.refused
|
|
5725
|
+
};
|
|
5726
|
+
}
|
|
5727
|
+
function mapCitationGrade(cg) {
|
|
5728
|
+
if (cg === void 0) return void 0;
|
|
5729
|
+
return {
|
|
5730
|
+
ok: cg.ok,
|
|
5731
|
+
unsupported_count: cg.unsupported_count,
|
|
5732
|
+
uncertain_count: cg.uncertain_count,
|
|
5733
|
+
graded_claims: cg.graded_claims.map((g) => ({
|
|
5734
|
+
claim: g.claim,
|
|
5735
|
+
label: g.label,
|
|
5736
|
+
confidence: g.confidence,
|
|
5737
|
+
cited_ids: [...g.cited_ids]
|
|
5738
|
+
}))
|
|
5739
|
+
};
|
|
5740
|
+
}
|
|
5741
|
+
|
|
5742
|
+
// src/consensus/claim-classifier.ts
|
|
5743
|
+
var CLASSIFIER_SYSTEM_PROMPT = [
|
|
5744
|
+
"You are a citation-grading judge. You are given a CLAIM and the full text of the SOURCES it cites.",
|
|
5745
|
+
"Decide whether the SOURCES directly support the CLAIM. Judge ONLY against the supplied sources \u2014 do not use outside knowledge.",
|
|
5746
|
+
"pass = the sources clearly support the claim; fail = the sources contradict or do not support it; uncertain = the sources are insufficient or ambiguous.",
|
|
5747
|
+
"After a one-sentence justification, conclude with EXACTLY one of these lines:",
|
|
5748
|
+
" VERDICT: pass",
|
|
5749
|
+
" VERDICT: fail",
|
|
5750
|
+
" VERDICT: uncertain",
|
|
5751
|
+
"Then on a new line, exactly:",
|
|
5752
|
+
" CONFIDENCE: <0..1>",
|
|
5753
|
+
"Do not include any other VERDICT or CONFIDENCE lines."
|
|
5754
|
+
].join("\n");
|
|
5755
|
+
function verdictToLabel(verdict) {
|
|
5756
|
+
switch (verdict) {
|
|
5757
|
+
case "pass":
|
|
5758
|
+
return "supported";
|
|
5759
|
+
case "fail":
|
|
5760
|
+
return "unsupported";
|
|
5761
|
+
case "uncertain":
|
|
5762
|
+
return "uncertain";
|
|
5763
|
+
default:
|
|
5764
|
+
return "uncertain";
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
function clampConfidence(raw) {
|
|
5768
|
+
if (!Number.isFinite(raw)) return 0;
|
|
5769
|
+
if (raw < 0) return 0;
|
|
5770
|
+
if (raw > 1) return 1;
|
|
5771
|
+
return raw;
|
|
5772
|
+
}
|
|
5773
|
+
function buildClassifyPrompt(claim, sources) {
|
|
5774
|
+
return [
|
|
5775
|
+
"CLAIM:",
|
|
5776
|
+
claim,
|
|
5777
|
+
"",
|
|
5778
|
+
"SOURCES:",
|
|
5779
|
+
sources,
|
|
5780
|
+
"",
|
|
5781
|
+
"Does the cited SOURCES text support the CLAIM? Reply with your verdict (pass = supported, fail = unsupported, uncertain = insufficient)."
|
|
5782
|
+
].join("\n");
|
|
5783
|
+
}
|
|
5784
|
+
function createClaimClassifier(model, options = {}) {
|
|
5785
|
+
return {
|
|
5786
|
+
async classify(args) {
|
|
5787
|
+
try {
|
|
5788
|
+
const result = await model.call({
|
|
5789
|
+
system_prompt: CLASSIFIER_SYSTEM_PROMPT,
|
|
5790
|
+
user_prompt: buildClassifyPrompt(args.claim, args.sources),
|
|
5791
|
+
...options.signal !== void 0 ? { abort_signal: options.signal } : {}
|
|
5792
|
+
});
|
|
5793
|
+
if (result.verdict === "error") {
|
|
5794
|
+
return { label: "uncertain", confidence: 0 };
|
|
5795
|
+
}
|
|
5796
|
+
return {
|
|
5797
|
+
label: verdictToLabel(result.verdict),
|
|
5798
|
+
confidence: clampConfidence(result.confidence)
|
|
5799
|
+
};
|
|
5800
|
+
} catch {
|
|
5801
|
+
return { label: "uncertain", confidence: 0 };
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5804
|
+
};
|
|
5805
|
+
}
|
|
5806
|
+
|
|
5087
5807
|
// src/consensus/engine-client.ts
|
|
5808
|
+
function raceAbort(signal) {
|
|
5809
|
+
return new Promise((_, reject) => {
|
|
5810
|
+
const onAbort = () => {
|
|
5811
|
+
reject(new Error("__VO_MCP_CANCELLED__"));
|
|
5812
|
+
};
|
|
5813
|
+
if (signal.aborted) onAbort();
|
|
5814
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
5815
|
+
});
|
|
5816
|
+
}
|
|
5088
5817
|
async function loadEngineModule() {
|
|
5089
5818
|
try {
|
|
5090
5819
|
const moduleName = ["@algosuite", "consensus-engine"].join("/");
|
|
@@ -5128,36 +5857,73 @@ function createEngineConsensusClient(options) {
|
|
|
5128
5857
|
...adapter,
|
|
5129
5858
|
call: (args) => adapter.call({ ...args, abort_signal: signal })
|
|
5130
5859
|
}));
|
|
5860
|
+
const agreementGate = resolveAgreementGate({
|
|
5861
|
+
...options.agreement_gate_enabled !== void 0 ? { configEnabled: options.agreement_gate_enabled } : {},
|
|
5862
|
+
...options.env !== void 0 ? { env: options.env } : {}
|
|
5863
|
+
});
|
|
5131
5864
|
const engineOptions = {
|
|
5132
5865
|
panel,
|
|
5133
|
-
...options.per_model_timeout_ms !== void 0 ? { per_model_timeout_ms: options.per_model_timeout_ms } : {}
|
|
5866
|
+
...options.per_model_timeout_ms !== void 0 ? { per_model_timeout_ms: options.per_model_timeout_ms } : {},
|
|
5867
|
+
...agreementGate !== void 0 ? { agreement_gate: agreementGate } : {}
|
|
5134
5868
|
};
|
|
5135
|
-
const
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5869
|
+
const sources = request.source_urls;
|
|
5870
|
+
const useSourceGrounded = sources !== void 0 && sources.length > 0 && typeof engine.runSourceGroundedConsensus === "function";
|
|
5871
|
+
let response;
|
|
5872
|
+
let sourceExtras;
|
|
5873
|
+
if (useSourceGrounded) {
|
|
5874
|
+
const [firstAdapter] = panel;
|
|
5875
|
+
const classifierOptions = signal === void 0 ? {} : { signal };
|
|
5876
|
+
const defaultClassifier = firstAdapter === void 0 ? void 0 : createClaimClassifier(firstAdapter, classifierOptions);
|
|
5877
|
+
const sgFields = buildSourceGroundedFields(request.source_grounded, defaultClassifier);
|
|
5878
|
+
const sgOptions = {
|
|
5879
|
+
...engineOptions,
|
|
5880
|
+
source_urls: sources,
|
|
5881
|
+
...sgFields.allow_url !== void 0 ? { allow_url: sgFields.allow_url } : {},
|
|
5882
|
+
...sgFields.citation_grader !== void 0 ? { citation_grader: sgFields.citation_grader } : {}
|
|
5883
|
+
};
|
|
5884
|
+
if (typeof engine.runSourceGroundedConsensus !== "function") {
|
|
5885
|
+
return { ok: false, reason: "source-grounded engine missing runSourceGroundedConsensus" };
|
|
5886
|
+
}
|
|
5887
|
+
const sgCall = engine.runSourceGroundedConsensus(engineRequest, sgOptions);
|
|
5888
|
+
const sgResult = signal === void 0 ? await sgCall : await Promise.race([sgCall, raceAbort(signal)]);
|
|
5889
|
+
if (!sgResult.ok) {
|
|
5890
|
+
return { ok: false, reason: sgResult.reason };
|
|
5891
|
+
}
|
|
5892
|
+
response = sgResult.engine.response;
|
|
5893
|
+
sourceExtras = {
|
|
5894
|
+
...sgResult.citation_grade !== void 0 ? { citation_grade: mapCitationGrade(sgResult.citation_grade) } : {},
|
|
5895
|
+
...sgResult.low_confidence_sources !== void 0 ? { low_confidence_sources: sgResult.low_confidence_sources } : {},
|
|
5896
|
+
...sgResult.escalation_required !== void 0 ? { escalation_required: sgResult.escalation_required } : {},
|
|
5897
|
+
...sgResult.escalation_reason !== void 0 ? { escalation_reason: sgResult.escalation_reason } : {}
|
|
5149
5898
|
};
|
|
5899
|
+
} else {
|
|
5900
|
+
const result = signal === void 0 ? await engine.runConsensus(engineRequest, engineOptions) : await Promise.race([engine.runConsensus(engineRequest, engineOptions), raceAbort(signal)]);
|
|
5901
|
+
if (!result.ok || result.response === void 0) {
|
|
5902
|
+
return {
|
|
5903
|
+
ok: false,
|
|
5904
|
+
reason: result.error?.reason ?? "engine-returned-not-ok"
|
|
5905
|
+
};
|
|
5906
|
+
}
|
|
5907
|
+
response = result.response;
|
|
5150
5908
|
}
|
|
5151
5909
|
return {
|
|
5152
5910
|
ok: true,
|
|
5153
|
-
synthesized_verdict:
|
|
5154
|
-
per_model_verdicts:
|
|
5155
|
-
degraded:
|
|
5156
|
-
duration_ms:
|
|
5157
|
-
engine_version:
|
|
5158
|
-
// Phase 2 Lane D-1 — forward escalation signal when present.
|
|
5159
|
-
|
|
5160
|
-
|
|
5911
|
+
synthesized_verdict: response.synthesized_verdict,
|
|
5912
|
+
per_model_verdicts: response.per_model_verdicts,
|
|
5913
|
+
degraded: response.degraded,
|
|
5914
|
+
duration_ms: response.duration_ms,
|
|
5915
|
+
engine_version: response.engine_version,
|
|
5916
|
+
// Phase 2 Lane D-1 — forward escalation signal when present. The
|
|
5917
|
+
// source-grounded layer's own escalation (from the citation grade)
|
|
5918
|
+
// takes precedence when set, else the synthesizer's.
|
|
5919
|
+
...sourceExtras?.escalation_required !== void 0 ? { escalation_required: sourceExtras.escalation_required } : response.escalation_required !== void 0 ? { escalation_required: response.escalation_required } : {},
|
|
5920
|
+
...sourceExtras?.escalation_reason !== void 0 ? { escalation_reason: sourceExtras.escalation_reason } : response.escalation_reason !== void 0 ? { escalation_reason: response.escalation_reason } : {},
|
|
5921
|
+
// Feature 1 (agreement-gate) — fan-out diagnostics (additive telemetry).
|
|
5922
|
+
...mapFanOutDiagnostics(response.fan_out_diagnostics) !== void 0 ? { fan_out_diagnostics: mapFanOutDiagnostics(response.fan_out_diagnostics) } : {},
|
|
5923
|
+
// Source-grounded additive outputs (Tier-4 features).
|
|
5924
|
+
...useSourceGrounded ? { source_grounded: true } : {},
|
|
5925
|
+
...sourceExtras?.citation_grade !== void 0 ? { citation_grade: sourceExtras.citation_grade } : {},
|
|
5926
|
+
...sourceExtras?.low_confidence_sources !== void 0 ? { low_confidence_sources: sourceExtras.low_confidence_sources } : {}
|
|
5161
5927
|
};
|
|
5162
5928
|
} catch (err) {
|
|
5163
5929
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -5405,10 +6171,11 @@ function tryCreateMoatConsensusClientFromEnv(env = process.env, fetchFn) {
|
|
|
5405
6171
|
}
|
|
5406
6172
|
|
|
5407
6173
|
// src/cloud/login.ts
|
|
6174
|
+
init_credential_store();
|
|
5408
6175
|
import { createServer as createServer2 } from "node:http";
|
|
5409
6176
|
import { randomBytes } from "node:crypto";
|
|
5410
|
-
import { spawn } from "node:child_process";
|
|
5411
|
-
var DEFAULT_DASHBOARD_URL = "https://
|
|
6177
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
6178
|
+
var DEFAULT_DASHBOARD_URL = "https://algosuite.ai";
|
|
5412
6179
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
5413
6180
|
var MAX_BODY_BYTES = 16384;
|
|
5414
6181
|
function processCapture(rawBody, expectedState, store) {
|
|
@@ -5453,17 +6220,17 @@ function captureHtml() {
|
|
|
5453
6220
|
function defaultOpenBrowser(url) {
|
|
5454
6221
|
const platform = process.platform;
|
|
5455
6222
|
if (platform === "win32") {
|
|
5456
|
-
|
|
6223
|
+
spawn2("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
|
|
5457
6224
|
} else if (platform === "darwin") {
|
|
5458
|
-
|
|
6225
|
+
spawn2("open", [url], { detached: true, stdio: "ignore" }).unref();
|
|
5459
6226
|
} else {
|
|
5460
|
-
|
|
6227
|
+
spawn2("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
|
|
5461
6228
|
}
|
|
5462
6229
|
}
|
|
5463
6230
|
async function runLogin(opts = {}) {
|
|
5464
|
-
const dashboardUrl = (opts.dashboardUrl ?? DEFAULT_DASHBOARD_URL).replace(/\/+$/, "");
|
|
5465
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
5466
6231
|
const env = opts.env ?? process.env;
|
|
6232
|
+
const dashboardUrl = (opts.dashboardUrl ?? env["VO_DASHBOARD_URL"]?.trim() ?? DEFAULT_DASHBOARD_URL).replace(/\/+$/, "") || DEFAULT_DASHBOARD_URL;
|
|
6233
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
5467
6234
|
const log = opts.log ?? ((m) => console.error(m));
|
|
5468
6235
|
const nowIso = opts.nowIso ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
5469
6236
|
const openBrowser = opts.openBrowser ?? defaultOpenBrowser;
|
|
@@ -5558,6 +6325,7 @@ async function runLogin(opts = {}) {
|
|
|
5558
6325
|
}
|
|
5559
6326
|
|
|
5560
6327
|
// src/cloud/vo-credential-exchange.ts
|
|
6328
|
+
init_auth_token_source();
|
|
5561
6329
|
async function exchangeForVoCredential(opts) {
|
|
5562
6330
|
const base = opts.controlPlaneUrl.replace(/\/+$/, "");
|
|
5563
6331
|
if (!base) return null;
|
|
@@ -5589,7 +6357,7 @@ async function exchangeForVoCredential(opts) {
|
|
|
5589
6357
|
function defaultCacheDbPath() {
|
|
5590
6358
|
const env = process.env["VO_MCP_DB_PATH"];
|
|
5591
6359
|
if (env && env.length > 0) return env;
|
|
5592
|
-
return
|
|
6360
|
+
return join8(homedir6(), ".claude", "vo-mcp-cache.db");
|
|
5593
6361
|
}
|
|
5594
6362
|
async function probeEngineVersion() {
|
|
5595
6363
|
try {
|