@algosuite/vo-mcp 0.2.0-beta.58 → 0.2.0-beta.60
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/cli.js +210 -52
- package/dist/cli.js.map +4 -4
- package/dist/index.js +184 -42
- package/dist/index.js.map +4 -4
- package/dist/runner-cli.js +597 -39
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +87 -2
- package/dist/runner-supervisor.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2170,8 +2170,8 @@ import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as
|
|
|
2170
2170
|
function extractMemoryTitle(fileName, content) {
|
|
2171
2171
|
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
2172
2172
|
if (frontmatter) {
|
|
2173
|
-
const
|
|
2174
|
-
if (
|
|
2173
|
+
const description24 = frontmatter[1].match(/^description:\s*(.+)$/m);
|
|
2174
|
+
if (description24 && description24[1].trim()) return description24[1].trim().slice(0, 200);
|
|
2175
2175
|
}
|
|
2176
2176
|
const heading = content.match(/^#\s+(.+)$/m);
|
|
2177
2177
|
if (heading && heading[1].trim()) return heading[1].trim().slice(0, 200);
|
|
@@ -2284,12 +2284,12 @@ var init_memory_knowledge_bridge = __esm({
|
|
|
2284
2284
|
// src/tools/memory/sync-config.ts
|
|
2285
2285
|
var sync_config_exports = {};
|
|
2286
2286
|
__export(sync_config_exports, {
|
|
2287
|
-
TOOL_NAME: () =>
|
|
2287
|
+
TOOL_NAME: () => TOOL_NAME23,
|
|
2288
2288
|
deriveProjectSlug: () => deriveProjectSlug,
|
|
2289
|
-
description: () =>
|
|
2289
|
+
description: () => description23,
|
|
2290
2290
|
getMemoryDir: () => getMemoryDir,
|
|
2291
2291
|
handleSyncConfig: () => handleSyncConfig,
|
|
2292
|
-
inputSchema: () =>
|
|
2292
|
+
inputSchema: () => inputSchema23,
|
|
2293
2293
|
isNoopSyncReason: () => isNoopSyncReason,
|
|
2294
2294
|
runMemorySync: () => runMemorySync
|
|
2295
2295
|
});
|
|
@@ -2416,15 +2416,15 @@ async function runMemorySync(action, cwd, sessionId, fetchFn = globalThis.fetch,
|
|
|
2416
2416
|
async function handleSyncConfig(deps, rawInput, _signal, fetchFn = globalThis.fetch) {
|
|
2417
2417
|
if (!isToolInput22(rawInput)) {
|
|
2418
2418
|
throw invalidParams(
|
|
2419
|
-
|
|
2419
|
+
TOOL_NAME23,
|
|
2420
2420
|
'invalid input. Required: { action: "pull" | "push" }. Optional: { cwd: "<path>" }.'
|
|
2421
2421
|
);
|
|
2422
2422
|
}
|
|
2423
2423
|
const cwd = rawInput.cwd?.trim() || process.cwd();
|
|
2424
2424
|
const result = await runMemorySync(rawInput.action, cwd, deps.session.sessionId, fetchFn);
|
|
2425
|
-
return jsonContent({ tool:
|
|
2425
|
+
return jsonContent({ tool: TOOL_NAME23, schema_version: 1, payload: result });
|
|
2426
2426
|
}
|
|
2427
|
-
var
|
|
2427
|
+
var TOOL_NAME23, inputSchema23, description23;
|
|
2428
2428
|
var init_sync_config = __esm({
|
|
2429
2429
|
"src/tools/memory/sync-config.ts"() {
|
|
2430
2430
|
"use strict";
|
|
@@ -2434,8 +2434,8 @@ var init_sync_config = __esm({
|
|
|
2434
2434
|
init_memory_push_cache();
|
|
2435
2435
|
init_sync_lock();
|
|
2436
2436
|
init_sync_kill_switch();
|
|
2437
|
-
|
|
2438
|
-
|
|
2437
|
+
TOOL_NAME23 = "vo_sync_config";
|
|
2438
|
+
inputSchema23 = {
|
|
2439
2439
|
type: "object",
|
|
2440
2440
|
properties: {
|
|
2441
2441
|
action: {
|
|
@@ -2451,7 +2451,7 @@ var init_sync_config = __esm({
|
|
|
2451
2451
|
required: ["action"],
|
|
2452
2452
|
additionalProperties: false
|
|
2453
2453
|
};
|
|
2454
|
-
|
|
2454
|
+
description23 = "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. Serialized across concurrent sessions by an exclusive lock in the memory dir.";
|
|
2455
2455
|
}
|
|
2456
2456
|
});
|
|
2457
2457
|
|
|
@@ -5014,15 +5014,27 @@ init_common();
|
|
|
5014
5014
|
init_auth_token_source();
|
|
5015
5015
|
init_credential_store();
|
|
5016
5016
|
var AdminCallableError = class extends Error {
|
|
5017
|
-
constructor(status, path4, message) {
|
|
5017
|
+
constructor(status, path4, message, body) {
|
|
5018
5018
|
super(message);
|
|
5019
5019
|
this.status = status;
|
|
5020
5020
|
this.path = path4;
|
|
5021
|
+
this.body = body;
|
|
5021
5022
|
this.name = "AdminCallableError";
|
|
5022
5023
|
}
|
|
5023
5024
|
status;
|
|
5024
5025
|
path;
|
|
5026
|
+
body;
|
|
5025
5027
|
};
|
|
5028
|
+
function parseJsonObject(text) {
|
|
5029
|
+
try {
|
|
5030
|
+
const parsed = JSON.parse(text);
|
|
5031
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
5032
|
+
return parsed;
|
|
5033
|
+
}
|
|
5034
|
+
} catch {
|
|
5035
|
+
}
|
|
5036
|
+
return void 0;
|
|
5037
|
+
}
|
|
5026
5038
|
var HttpAdminCallableClient = class {
|
|
5027
5039
|
baseUrl;
|
|
5028
5040
|
tokenSource;
|
|
@@ -5058,21 +5070,25 @@ var HttpAdminCallableClient = class {
|
|
|
5058
5070
|
`admin proxy ${path4}: no auth token available (check VO_USER_REFRESH_TOKEN / VO_USER_ID_TOKEN / VO_CONTROL_PLANE_ADMIN_TOKEN)`
|
|
5059
5071
|
);
|
|
5060
5072
|
}
|
|
5061
|
-
const
|
|
5062
|
-
const
|
|
5063
|
-
|
|
5073
|
+
const method = opts?.method ?? "POST";
|
|
5074
|
+
const queryString = opts?.query ? new URLSearchParams(Object.entries(opts.query)).toString() : "";
|
|
5075
|
+
const url = `${this.baseUrl}${path4}${queryString ? `?${queryString}` : ""}`;
|
|
5076
|
+
const init = method === "GET" ? { method, headers: { "authorization": `Bearer ${token}` } } : {
|
|
5077
|
+
method,
|
|
5064
5078
|
headers: {
|
|
5065
5079
|
"authorization": `Bearer ${token}`,
|
|
5066
5080
|
"content-type": "application/json"
|
|
5067
5081
|
},
|
|
5068
5082
|
body: JSON.stringify(body)
|
|
5069
|
-
}
|
|
5083
|
+
};
|
|
5084
|
+
const response = await this.fetchFn(url, init);
|
|
5070
5085
|
const text = await response.text();
|
|
5071
5086
|
if (response.status < 200 || response.status >= 300) {
|
|
5072
5087
|
throw new AdminCallableError(
|
|
5073
5088
|
response.status,
|
|
5074
5089
|
path4,
|
|
5075
|
-
`admin proxy ${path4} returned HTTP ${response.status}: ${text.slice(0, 200)}
|
|
5090
|
+
`admin proxy ${path4} returned HTTP ${response.status}: ${text.slice(0, 200)}`,
|
|
5091
|
+
parseJsonObject(text)
|
|
5076
5092
|
);
|
|
5077
5093
|
}
|
|
5078
5094
|
let parsed;
|
|
@@ -5097,7 +5113,8 @@ var HttpAdminCallableClient = class {
|
|
|
5097
5113
|
throw new AdminCallableError(
|
|
5098
5114
|
response.status,
|
|
5099
5115
|
path4,
|
|
5100
|
-
`admin proxy ${path4} returned ok=false: ${JSON.stringify(obj).slice(0, 200)}
|
|
5116
|
+
`admin proxy ${path4} returned ok=false: ${JSON.stringify(obj).slice(0, 200)}`,
|
|
5117
|
+
obj
|
|
5101
5118
|
);
|
|
5102
5119
|
}
|
|
5103
5120
|
if (opts?.rawEnvelope) {
|
|
@@ -5171,11 +5188,12 @@ async function buildCloudOrStubResponse(args) {
|
|
|
5171
5188
|
args.deps.events.append(event);
|
|
5172
5189
|
return jsonContent(envelope);
|
|
5173
5190
|
}
|
|
5191
|
+
const invokeOptions = args.rawEnvelope || args.invokeOptions ? { ...args.rawEnvelope ? { rawEnvelope: true } : {}, ...args.invokeOptions } : void 0;
|
|
5174
5192
|
try {
|
|
5175
5193
|
const result = await args.deps.adminCallables.invoke(
|
|
5176
5194
|
args.adminPath,
|
|
5177
5195
|
args.cloudBody ?? args.normalizedInput,
|
|
5178
|
-
|
|
5196
|
+
invokeOptions
|
|
5179
5197
|
);
|
|
5180
5198
|
const payload = {
|
|
5181
5199
|
verdict: "pass",
|
|
@@ -5195,11 +5213,13 @@ async function buildCloudOrStubResponse(args) {
|
|
|
5195
5213
|
} catch (err) {
|
|
5196
5214
|
const status = err instanceof AdminCallableError ? err.status : void 0;
|
|
5197
5215
|
const message = err instanceof Error ? err.message : String(err);
|
|
5216
|
+
const errorBody = err instanceof AdminCallableError && err.body !== void 0 ? err.body : void 0;
|
|
5198
5217
|
const payload = {
|
|
5199
5218
|
verdict: "fail",
|
|
5200
5219
|
reason: status !== void 0 ? `vo-control-plane returned HTTP ${status}: ${message.slice(0, 300)}` : `cloud invocation failed: ${message.slice(0, 300)}`,
|
|
5201
5220
|
callable: args.callableName,
|
|
5202
|
-
normalized_input: args.normalizedInput
|
|
5221
|
+
normalized_input: args.normalizedInput,
|
|
5222
|
+
...errorBody ? { response_data: errorBody } : {}
|
|
5203
5223
|
};
|
|
5204
5224
|
const envelope = {
|
|
5205
5225
|
tool: args.toolName,
|
|
@@ -5888,6 +5908,136 @@ async function handleReviewMerge(deps, rawInput, signal) {
|
|
|
5888
5908
|
});
|
|
5889
5909
|
}
|
|
5890
5910
|
|
|
5911
|
+
// src/tools/runner/prepared-job-mode.ts
|
|
5912
|
+
init_common();
|
|
5913
|
+
var TOOL_NAME19 = "vo_prepared_job_mode";
|
|
5914
|
+
var CALLABLE_NAME10 = "GET|POST /api/v1/runner/prepared-job-mode";
|
|
5915
|
+
var PLANE_PATH = "/api/v1/runner/prepared-job-mode";
|
|
5916
|
+
var PREPARED_JOB_MODE_GATE_TYPE = "admin-action";
|
|
5917
|
+
var PREPARED_JOB_MODE_STUB_REASON = "cloud mode is not configured on this session, so vo-control-plane was not reached. Sign in with `vo-mcp login` to route this tool to the plane. This route is NOT under /api/v1/admin/*, so a tenant-scoped operator credential is the CORRECT principal for it \u2014 the target operator is derived from that principal, never from this input.";
|
|
5918
|
+
var PREPARED_JOB_MODES = ["off", "shadow", "prepared"];
|
|
5919
|
+
var MIN_REASON_CHARS = 10;
|
|
5920
|
+
var MAX_REASON_CHARS = 500;
|
|
5921
|
+
var MAX_RUNNER_ID_CHARS = 100;
|
|
5922
|
+
var inputSchema19 = {
|
|
5923
|
+
type: "object",
|
|
5924
|
+
properties: {
|
|
5925
|
+
action: {
|
|
5926
|
+
type: "string",
|
|
5927
|
+
enum: ["get", "set"],
|
|
5928
|
+
description: "Required. 'get' reads the delivered mode (read-only; stays live under VO_ADMIN_CALLABLES_READONLY). 'set' writes it (a write; gated to the stub in read-only mode)."
|
|
5929
|
+
},
|
|
5930
|
+
runner_id: {
|
|
5931
|
+
type: "string",
|
|
5932
|
+
minLength: 1,
|
|
5933
|
+
maxLength: MAX_RUNNER_ID_CHARS,
|
|
5934
|
+
description: "Required. Runner to read/configure, e.g. 'vo-code-runner-JacksPC'. Must belong to the authenticated operator \u2014 the plane scopes by principal, so another operator's runner simply reads as unset."
|
|
5935
|
+
},
|
|
5936
|
+
prepared_job_mode: {
|
|
5937
|
+
type: "string",
|
|
5938
|
+
enum: [...PREPARED_JOB_MODES],
|
|
5939
|
+
description: "Required for action='set'. 'off' = the runner's machine-local env rules; 'shadow' = compare the plane's prepared job without consuming it. 'prepared' is recognized but REFUSED by the plane with 409 prepared_mode_not_flippable (ADR-004 11.1c owns the flip)."
|
|
5940
|
+
},
|
|
5941
|
+
expected_revision: {
|
|
5942
|
+
type: "integer",
|
|
5943
|
+
minimum: 0,
|
|
5944
|
+
description: "Required for action='set'. Optimistic-concurrency revision read from a prior 'get' (use 0 when no config exists). A stale value returns 409 stale_prepared_job_revision carrying the authoritative current_revision."
|
|
5945
|
+
},
|
|
5946
|
+
reason: {
|
|
5947
|
+
type: "string",
|
|
5948
|
+
minLength: MIN_REASON_CHARS,
|
|
5949
|
+
maxLength: MAX_REASON_CHARS,
|
|
5950
|
+
description: `Required for action='set'. Audit reason stored on the config-change record; at least ${MIN_REASON_CHARS} characters after trimming.`
|
|
5951
|
+
}
|
|
5952
|
+
},
|
|
5953
|
+
required: ["action", "runner_id"],
|
|
5954
|
+
additionalProperties: false
|
|
5955
|
+
};
|
|
5956
|
+
var description19 = "Gets or sets a paired runner's plane-delivered prepared-job mode (ADR-004 \xA7 11.1) via vo-control-plane GET/POST /api/v1/runner/prepared-job-mode. action='get' returns the stored config ({prepared_job_mode, revision, reason, updated_at, updated_by}, or null when unset); action='set' writes it with optimistic concurrency and returns the new config plus an audit_id. THE TARGET OPERATOR IS DERIVED FROM THE AUTHENTICATED PRINCIPAL, never from this input \u2014 an admin token therefore writes under operator 'admin' and does NOT reach a scoped operator's runner, so use the operator credential from `vo-mcp login`. 'prepared' is refused by the plane with 409 prepared_mode_not_flippable; 'get' is read-only while 'set' is a write and is gated to a stub under VO_ADMIN_CALLABLES_READONLY. Falls back to a clearly-marked `unimplemented` envelope when cloud mode is not configured.";
|
|
5957
|
+
var SHAPE_HINT = `invalid input. Shape: { action: 'get' | 'set', runner_id: non-empty string \u2264${MAX_RUNNER_ID_CHARS} chars }. For action='set' also required: prepared_job_mode ('${PREPARED_JOB_MODES.join("' | '")}'), expected_revision (integer \u2265 0), reason (string \u2265${MIN_REASON_CHARS} chars after trim). Those three fields are NOT accepted with action='get'.`;
|
|
5958
|
+
function parseInput(v) {
|
|
5959
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) return null;
|
|
5960
|
+
const o = v;
|
|
5961
|
+
const action = o["action"];
|
|
5962
|
+
if (action !== "get" && action !== "set") return null;
|
|
5963
|
+
const rawRunnerId = o["runner_id"];
|
|
5964
|
+
if (typeof rawRunnerId !== "string") return null;
|
|
5965
|
+
const runner_id = rawRunnerId.trim();
|
|
5966
|
+
if (runner_id.length === 0 || runner_id.length > MAX_RUNNER_ID_CHARS) return null;
|
|
5967
|
+
const setOnly = ["prepared_job_mode", "expected_revision", "reason"];
|
|
5968
|
+
if (action === "get") {
|
|
5969
|
+
if (setOnly.some((key) => o[key] !== void 0)) return null;
|
|
5970
|
+
return { action, runner_id };
|
|
5971
|
+
}
|
|
5972
|
+
const mode = o["prepared_job_mode"];
|
|
5973
|
+
if (typeof mode !== "string") return null;
|
|
5974
|
+
if (!PREPARED_JOB_MODES.includes(mode)) return null;
|
|
5975
|
+
const revision = o["expected_revision"];
|
|
5976
|
+
if (typeof revision !== "number") return null;
|
|
5977
|
+
if (!Number.isInteger(revision) || revision < 0) return null;
|
|
5978
|
+
const rawReason = o["reason"];
|
|
5979
|
+
if (typeof rawReason !== "string") return null;
|
|
5980
|
+
const reason = rawReason.trim();
|
|
5981
|
+
if (reason.length < MIN_REASON_CHARS || reason.length > MAX_REASON_CHARS) return null;
|
|
5982
|
+
return {
|
|
5983
|
+
action,
|
|
5984
|
+
runner_id,
|
|
5985
|
+
prepared_job_mode: mode,
|
|
5986
|
+
expected_revision: revision,
|
|
5987
|
+
reason
|
|
5988
|
+
};
|
|
5989
|
+
}
|
|
5990
|
+
async function handlePreparedJobMode(deps, rawInput, _signal) {
|
|
5991
|
+
const input = parseInput(rawInput);
|
|
5992
|
+
if (!input) {
|
|
5993
|
+
throw invalidParams(TOOL_NAME19, SHAPE_HINT);
|
|
5994
|
+
}
|
|
5995
|
+
if (input.action === "get") {
|
|
5996
|
+
return buildCloudOrStubResponse({
|
|
5997
|
+
toolName: TOOL_NAME19,
|
|
5998
|
+
callableName: CALLABLE_NAME10,
|
|
5999
|
+
adminPath: PLANE_PATH,
|
|
6000
|
+
normalizedInput: { action: "get", runner_id: input.runner_id },
|
|
6001
|
+
// A GET carries no body; the runner id rides the query string.
|
|
6002
|
+
cloudBody: {},
|
|
6003
|
+
invokeOptions: { method: "GET", query: { runner_id: input.runner_id } },
|
|
6004
|
+
// The plane answers `{ok, config}` — not the `{ok, callable, result}`
|
|
6005
|
+
// admin-proxy envelope — so take the whole object with `ok` stripped.
|
|
6006
|
+
rawEnvelope: true,
|
|
6007
|
+
gateType: PREPARED_JOB_MODE_GATE_TYPE,
|
|
6008
|
+
stubReason: PREPARED_JOB_MODE_STUB_REASON,
|
|
6009
|
+
readOnly: true,
|
|
6010
|
+
deps
|
|
6011
|
+
});
|
|
6012
|
+
}
|
|
6013
|
+
return buildCloudOrStubResponse({
|
|
6014
|
+
toolName: TOOL_NAME19,
|
|
6015
|
+
callableName: CALLABLE_NAME10,
|
|
6016
|
+
adminPath: PLANE_PATH,
|
|
6017
|
+
normalizedInput: {
|
|
6018
|
+
action: "set",
|
|
6019
|
+
runner_id: input.runner_id,
|
|
6020
|
+
prepared_job_mode: input.prepared_job_mode,
|
|
6021
|
+
expected_revision: input.expected_revision,
|
|
6022
|
+
reason: input.reason
|
|
6023
|
+
},
|
|
6024
|
+
// Exactly the four fields of `updateRunnerPreparedJobConfigInputSchema`
|
|
6025
|
+
// (.strict()) — no `operator_id`, which the route would ignore anyway.
|
|
6026
|
+
cloudBody: {
|
|
6027
|
+
runner_id: input.runner_id,
|
|
6028
|
+
prepared_job_mode: input.prepared_job_mode,
|
|
6029
|
+
expected_revision: input.expected_revision,
|
|
6030
|
+
reason: input.reason
|
|
6031
|
+
},
|
|
6032
|
+
rawEnvelope: true,
|
|
6033
|
+
gateType: PREPARED_JOB_MODE_GATE_TYPE,
|
|
6034
|
+
stubReason: PREPARED_JOB_MODE_STUB_REASON,
|
|
6035
|
+
// A write: stays gated behind VO_ADMIN_CALLABLES_READONLY.
|
|
6036
|
+
readOnly: false,
|
|
6037
|
+
deps
|
|
6038
|
+
});
|
|
6039
|
+
}
|
|
6040
|
+
|
|
5891
6041
|
// src/tools/session/report-session-state.ts
|
|
5892
6042
|
init_common();
|
|
5893
6043
|
|
|
@@ -5924,12 +6074,12 @@ function suggestedHandoffPath(session_id, isoTimestamp) {
|
|
|
5924
6074
|
// src/tools/session/report-session-state.ts
|
|
5925
6075
|
init_auth_token_source();
|
|
5926
6076
|
init_credential_store();
|
|
5927
|
-
var
|
|
6077
|
+
var TOOL_NAME20 = "vo_report_session_state";
|
|
5928
6078
|
var VALID_AGENT_TYPES = ["claude-code", "codex", "cursor", "continue"];
|
|
5929
6079
|
var MAX_GOAL_CHARS = 500;
|
|
5930
6080
|
var MAX_RECENT_FILES = 20;
|
|
5931
6081
|
var MAX_RECENT_TOOLS = 50;
|
|
5932
|
-
var
|
|
6082
|
+
var inputSchema20 = {
|
|
5933
6083
|
type: "object",
|
|
5934
6084
|
properties: {
|
|
5935
6085
|
operator_id: {
|
|
@@ -5974,7 +6124,7 @@ var inputSchema19 = {
|
|
|
5974
6124
|
required: ["operator_id", "session_id", "agent_type", "context_used_pct"],
|
|
5975
6125
|
additionalProperties: false
|
|
5976
6126
|
};
|
|
5977
|
-
var
|
|
6127
|
+
var description20 = "Reports per-session context-window utilization to AlgoHQ 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 AlgoHQ roadmap. Cloud-control-plane mode when VO_CONTROL_PLANE_URL plus a user/scoped HQ credential (or legacy admin token) is available; auto-allocates the session on first report so interactive agents (Claude Code, Cursor, Codex, Continue) appear on the live fleet whiteboard. Stub-local fallback when cloud config is absent or fails. The response shape stays stable across modes (`backend_mode` field in the payload tells the caller which mode produced the verdict).";
|
|
5978
6128
|
function isStringArray2(v, maxItems) {
|
|
5979
6129
|
if (!Array.isArray(v)) return false;
|
|
5980
6130
|
if (v.length > maxItems) return false;
|
|
@@ -6112,7 +6262,7 @@ async function tryCloudReportState(cloud, input, fetchFn = fetch) {
|
|
|
6112
6262
|
async function handleReportSessionState(deps, rawInput, _signal) {
|
|
6113
6263
|
if (!isToolInput19(rawInput)) {
|
|
6114
6264
|
throw invalidParams(
|
|
6115
|
-
|
|
6265
|
+
TOOL_NAME20,
|
|
6116
6266
|
`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}).`
|
|
6117
6267
|
);
|
|
6118
6268
|
}
|
|
@@ -6743,9 +6893,9 @@ function checkSuccessorLiveness(child, logPath, config, deps = {}) {
|
|
|
6743
6893
|
}
|
|
6744
6894
|
|
|
6745
6895
|
// src/tools/session/spawn-successor.ts
|
|
6746
|
-
var
|
|
6896
|
+
var TOOL_NAME21 = "vo_spawn_successor";
|
|
6747
6897
|
var MAX_HANDOFF_BYTES = 64e3;
|
|
6748
|
-
var
|
|
6898
|
+
var inputSchema21 = {
|
|
6749
6899
|
type: "object",
|
|
6750
6900
|
properties: {
|
|
6751
6901
|
handoff_path: {
|
|
@@ -6773,7 +6923,7 @@ var inputSchema20 = {
|
|
|
6773
6923
|
additionalProperties: false
|
|
6774
6924
|
};
|
|
6775
6925
|
var RETIRED_COUNTER_INPUT = "spawns_so_far";
|
|
6776
|
-
var
|
|
6926
|
+
var description21 = "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/. Verifies the child is actually alive (survives an early-exit window; an optional log-output window is off by default) before reporting success. 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.";
|
|
6777
6927
|
function isToolInput20(v) {
|
|
6778
6928
|
if (typeof v !== "object" || v === null) return false;
|
|
6779
6929
|
const o = v;
|
|
@@ -6831,14 +6981,14 @@ function buildSuccessorPrompt(handoffMarkdown, goal) {
|
|
|
6831
6981
|
}
|
|
6832
6982
|
async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn, overrides = {}) {
|
|
6833
6983
|
const retired = retiredCounterRefusal(rawInput);
|
|
6834
|
-
if (retired !== null) throw invalidParams(
|
|
6984
|
+
if (retired !== null) throw invalidParams(TOOL_NAME21, retired);
|
|
6835
6985
|
if (!isToolInput20(rawInput)) {
|
|
6836
|
-
throw invalidParams(
|
|
6986
|
+
throw invalidParams(TOOL_NAME21, "invalid input. Optional: { handoff_path, goal, cwd, max_turns, agent }.");
|
|
6837
6987
|
}
|
|
6838
6988
|
const handoffPath = rawInput.handoff_path?.trim() || newestHandoff();
|
|
6839
6989
|
if (!handoffPath || !existsSync5(handoffPath)) {
|
|
6840
6990
|
return jsonContent({
|
|
6841
|
-
tool:
|
|
6991
|
+
tool: TOOL_NAME21,
|
|
6842
6992
|
schema_version: 1,
|
|
6843
6993
|
payload: {
|
|
6844
6994
|
spawned: false,
|
|
@@ -6851,7 +7001,7 @@ async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn,
|
|
|
6851
7001
|
const plan = resolveSpawnPlan(process.env, rawInput, (/* @__PURE__ */ new Date()).toISOString());
|
|
6852
7002
|
if (!plan.ok) {
|
|
6853
7003
|
return jsonContent({
|
|
6854
|
-
tool:
|
|
7004
|
+
tool: TOOL_NAME21,
|
|
6855
7005
|
schema_version: 1,
|
|
6856
7006
|
payload: {
|
|
6857
7007
|
spawned: false,
|
|
@@ -6867,7 +7017,7 @@ async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn,
|
|
|
6867
7017
|
const resolution = resolveNativeWindowsExecutable(plan.bin, process.env, overrides.resolveWindowsExecutable);
|
|
6868
7018
|
if (!resolution.ok) {
|
|
6869
7019
|
return jsonContent({
|
|
6870
|
-
tool:
|
|
7020
|
+
tool: TOOL_NAME21,
|
|
6871
7021
|
schema_version: 1,
|
|
6872
7022
|
payload: {
|
|
6873
7023
|
spawned: false,
|
|
@@ -6916,7 +7066,7 @@ async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn,
|
|
|
6916
7066
|
await new Promise((r) => setTimeout(r, 150));
|
|
6917
7067
|
if (spawnError) {
|
|
6918
7068
|
return jsonContent({
|
|
6919
|
-
tool:
|
|
7069
|
+
tool: TOOL_NAME21,
|
|
6920
7070
|
schema_version: 1,
|
|
6921
7071
|
payload: {
|
|
6922
7072
|
spawned: false,
|
|
@@ -6931,7 +7081,7 @@ async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn,
|
|
|
6931
7081
|
const liveness = await checkLiveness(child, logPath);
|
|
6932
7082
|
if (!liveness.ok) {
|
|
6933
7083
|
return jsonContent({
|
|
6934
|
-
tool:
|
|
7084
|
+
tool: TOOL_NAME21,
|
|
6935
7085
|
schema_version: 1,
|
|
6936
7086
|
payload: {
|
|
6937
7087
|
spawned: false,
|
|
@@ -6945,7 +7095,7 @@ async function handleSpawnSuccessor(_deps, rawInput, _signal, spawnImpl = spawn,
|
|
|
6945
7095
|
});
|
|
6946
7096
|
}
|
|
6947
7097
|
return jsonContent({
|
|
6948
|
-
tool:
|
|
7098
|
+
tool: TOOL_NAME21,
|
|
6949
7099
|
schema_version: 1,
|
|
6950
7100
|
payload: {
|
|
6951
7101
|
spawned: true,
|
|
@@ -6988,10 +7138,10 @@ function isKnownConciergePack(value) {
|
|
|
6988
7138
|
}
|
|
6989
7139
|
|
|
6990
7140
|
// src/tools/concierge/dispatch.ts
|
|
6991
|
-
var
|
|
6992
|
-
var
|
|
7141
|
+
var TOOL_NAME22 = "vo_concierge_dispatch";
|
|
7142
|
+
var CALLABLE_NAME11 = "voConciergeDispatch";
|
|
6993
7143
|
var ADMIN_PATH10 = "/api/v1/admin/concierge/dispatch";
|
|
6994
|
-
var
|
|
7144
|
+
var inputSchema22 = {
|
|
6995
7145
|
type: "object",
|
|
6996
7146
|
properties: {
|
|
6997
7147
|
pack: {
|
|
@@ -7006,7 +7156,7 @@ var inputSchema21 = {
|
|
|
7006
7156
|
},
|
|
7007
7157
|
additionalProperties: false
|
|
7008
7158
|
};
|
|
7009
|
-
var
|
|
7159
|
+
var description22 = "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'`.";
|
|
7010
7160
|
function isToolInput21(v) {
|
|
7011
7161
|
if (typeof v !== "object" || v === null) return false;
|
|
7012
7162
|
const obj = v;
|
|
@@ -7017,13 +7167,13 @@ function isToolInput21(v) {
|
|
|
7017
7167
|
async function handleConciergeDispatch(deps, rawInput, _signal) {
|
|
7018
7168
|
if (!isToolInput21(rawInput)) {
|
|
7019
7169
|
throw invalidParams(
|
|
7020
|
-
|
|
7170
|
+
TOOL_NAME22,
|
|
7021
7171
|
"invalid input. Expected { pack?: string, tenant_id?: string }."
|
|
7022
7172
|
);
|
|
7023
7173
|
}
|
|
7024
7174
|
if (rawInput.pack !== void 0 && rawInput.pack !== "" && !isKnownConciergePack(rawInput.pack)) {
|
|
7025
7175
|
throw invalidParams(
|
|
7026
|
-
|
|
7176
|
+
TOOL_NAME22,
|
|
7027
7177
|
`unknown pack: ${JSON.stringify(rawInput.pack)}. Known packs: ${KNOWN_CONCIERGE_PACKS.join(", ")}.`
|
|
7028
7178
|
);
|
|
7029
7179
|
}
|
|
@@ -7034,8 +7184,8 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
|
|
|
7034
7184
|
if (rawInput.pack) cloudBody.pack = rawInput.pack;
|
|
7035
7185
|
if (rawInput.tenant_id) cloudBody.tenantId = rawInput.tenant_id;
|
|
7036
7186
|
return buildCloudOrStubResponse({
|
|
7037
|
-
toolName:
|
|
7038
|
-
callableName:
|
|
7187
|
+
toolName: TOOL_NAME22,
|
|
7188
|
+
callableName: CALLABLE_NAME11,
|
|
7039
7189
|
adminPath: ADMIN_PATH10,
|
|
7040
7190
|
normalizedInput,
|
|
7041
7191
|
cloudBody,
|
|
@@ -7402,7 +7552,7 @@ ${FRONTMATTER_DELIMITER}
|
|
|
7402
7552
|
${FRONTMATTER_DELIMITER}
|
|
7403
7553
|
`.length);
|
|
7404
7554
|
let name = "";
|
|
7405
|
-
let
|
|
7555
|
+
let description24 = "";
|
|
7406
7556
|
for (const line of frontmatterText.split("\n")) {
|
|
7407
7557
|
const trimmed = line.trim();
|
|
7408
7558
|
if (trimmed.length === 0) continue;
|
|
@@ -7411,15 +7561,15 @@ ${FRONTMATTER_DELIMITER}
|
|
|
7411
7561
|
const key = trimmed.slice(0, colonIdx).trim();
|
|
7412
7562
|
const value = trimmed.slice(colonIdx + 1).trim();
|
|
7413
7563
|
if (key === "name") name = value;
|
|
7414
|
-
else if (key === "description")
|
|
7564
|
+
else if (key === "description") description24 = value;
|
|
7415
7565
|
}
|
|
7416
7566
|
if (name.length === 0) {
|
|
7417
7567
|
throw new InvalidSkillFrontmatterError(sourcePath, 'missing required field "name"');
|
|
7418
7568
|
}
|
|
7419
|
-
if (
|
|
7569
|
+
if (description24.length === 0) {
|
|
7420
7570
|
throw new InvalidSkillFrontmatterError(sourcePath, 'missing required field "description"');
|
|
7421
7571
|
}
|
|
7422
|
-
return { name, description:
|
|
7572
|
+
return { name, description: description24, body };
|
|
7423
7573
|
}
|
|
7424
7574
|
function loadSkillsFromDir(skillsDir) {
|
|
7425
7575
|
const entries = readdirSync6(skillsDir);
|
|
@@ -7440,8 +7590,8 @@ function loadSkillsFromDir(skillsDir) {
|
|
|
7440
7590
|
} catch {
|
|
7441
7591
|
continue;
|
|
7442
7592
|
}
|
|
7443
|
-
const { name, description:
|
|
7444
|
-
skills.push({ name, description:
|
|
7593
|
+
const { name, description: description24, body } = parseFrontmatter(raw, skillFile);
|
|
7594
|
+
skills.push({ name, description: description24, body, sourcePath: skillFile });
|
|
7445
7595
|
}
|
|
7446
7596
|
return [...skills].sort((a, b) => a.name.localeCompare(b.name));
|
|
7447
7597
|
}
|
|
@@ -7709,7 +7859,7 @@ function buildToolRegistry() {
|
|
|
7709
7859
|
description: description19,
|
|
7710
7860
|
inputSchema: inputSchema19
|
|
7711
7861
|
},
|
|
7712
|
-
handler:
|
|
7862
|
+
handler: handlePreparedJobMode
|
|
7713
7863
|
},
|
|
7714
7864
|
[TOOL_NAME20]: {
|
|
7715
7865
|
definition: {
|
|
@@ -7717,7 +7867,7 @@ function buildToolRegistry() {
|
|
|
7717
7867
|
description: description20,
|
|
7718
7868
|
inputSchema: inputSchema20
|
|
7719
7869
|
},
|
|
7720
|
-
handler:
|
|
7870
|
+
handler: handleReportSessionState
|
|
7721
7871
|
},
|
|
7722
7872
|
[TOOL_NAME21]: {
|
|
7723
7873
|
definition: {
|
|
@@ -7725,7 +7875,7 @@ function buildToolRegistry() {
|
|
|
7725
7875
|
description: description21,
|
|
7726
7876
|
inputSchema: inputSchema21
|
|
7727
7877
|
},
|
|
7728
|
-
handler:
|
|
7878
|
+
handler: handleSpawnSuccessor
|
|
7729
7879
|
},
|
|
7730
7880
|
[TOOL_NAME22]: {
|
|
7731
7881
|
definition: {
|
|
@@ -7733,6 +7883,14 @@ function buildToolRegistry() {
|
|
|
7733
7883
|
description: description22,
|
|
7734
7884
|
inputSchema: inputSchema22
|
|
7735
7885
|
},
|
|
7886
|
+
handler: handleConciergeDispatch
|
|
7887
|
+
},
|
|
7888
|
+
[TOOL_NAME23]: {
|
|
7889
|
+
definition: {
|
|
7890
|
+
name: TOOL_NAME23,
|
|
7891
|
+
description: description23,
|
|
7892
|
+
inputSchema: inputSchema23
|
|
7893
|
+
},
|
|
7736
7894
|
handler: handleSyncConfig
|
|
7737
7895
|
},
|
|
7738
7896
|
[UPSERT_TOOL_NAME]: {
|