@algosuite/vo-mcp 0.2.0-beta.49 → 0.2.0-beta.50
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/README.md +2 -0
- package/dist/cli.js +169 -18
- package/dist/cli.js.map +4 -4
- package/dist/index.js +46 -8
- package/dist/index.js.map +2 -2
- package/dist/runner-cli.js +443 -93
- package/dist/runner-cli.js.map +4 -4
- package/dist/runner-supervisor.js +55 -29
- package/dist/runner-supervisor.js.map +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @algosuite/vo-mcp
|
|
2
2
|
|
|
3
|
+
> **Architecture mandate (ADR-004, 2026-08-16): thin runner, cloud brain.** This package must shrink to a thin executor + shim — spawn the agent, manage worktrees/pushes, hold credentials, carry the local half of the MCP transport. Prompt composition, routing, watcher/merge/repair decisions, policy tables and the consensus engine belong in `cloud-run/vo-control-plane` / `cloud-run/vo-moat-plane`, not here (this package is on the PUBLIC npm registry). Fixes may land here when that is the fastest way to unblock the loop, but every decision-making module in this bundle is migration debt: record it in the ADR-004 ledger and move it to the plane (HQ roadmap Phase 11). Do not add new decision logic here without a ledger row.
|
|
4
|
+
|
|
3
5
|
AlgoHQ MCP server — the open protocol surface that exposes HQ's consensus and ratchet tool family to any MCP-capable LLM client (Claude Code, Claude Desktop, Cursor, Continue, Codex, etc.).
|
|
4
6
|
|
|
5
7
|
The live AlgoHQ whiteboard is available to every MCP client through
|
package/dist/cli.js
CHANGED
|
@@ -1023,7 +1023,16 @@ function assertWithinByteCap(toolName, fieldName, value, maxBytes) {
|
|
|
1023
1023
|
);
|
|
1024
1024
|
}
|
|
1025
1025
|
}
|
|
1026
|
+
function subjectFromEnv(env = process.env) {
|
|
1027
|
+
const code_task_id = (env["VO_CODE_TASK_ID"] ?? "").trim().slice(0, 120);
|
|
1028
|
+
const repo = (env["VO_CODE_TASK_REPO"] ?? "").trim();
|
|
1029
|
+
const subject = {};
|
|
1030
|
+
if (code_task_id) subject.code_task_id = code_task_id;
|
|
1031
|
+
if (repo && REPO_RE.test(repo) && repo.length <= 200) subject.repo = repo;
|
|
1032
|
+
return subject.code_task_id || subject.repo ? subject : null;
|
|
1033
|
+
}
|
|
1026
1034
|
function buildBaseEvent(args) {
|
|
1035
|
+
const subject = args.subject === void 0 ? subjectFromEnv() : args.subject;
|
|
1027
1036
|
return {
|
|
1028
1037
|
schema_version: 1,
|
|
1029
1038
|
event_id: args.eventId ?? randomUUID(),
|
|
@@ -1049,7 +1058,12 @@ function buildBaseEvent(args) {
|
|
|
1049
1058
|
downstream_outcome: null,
|
|
1050
1059
|
vo_mcp_version: VO_MCP_VERSION,
|
|
1051
1060
|
consensus_engine_version: null,
|
|
1052
|
-
cache_hit: false
|
|
1061
|
+
cache_hit: false,
|
|
1062
|
+
// OMIT the key when there is no subject (rather than `subject: null`): the
|
|
1063
|
+
// ingest schema is `.strict()`, so an event with no subject stays valid on a
|
|
1064
|
+
// sink that has not learned the field yet — only subject-carrying events
|
|
1065
|
+
// depend on the sink being current (deploy ordering: sink before producer).
|
|
1066
|
+
...subject ? { subject } : {}
|
|
1053
1067
|
};
|
|
1054
1068
|
}
|
|
1055
1069
|
function jsonContent(value) {
|
|
@@ -1115,6 +1129,16 @@ function aggregateEventTokenUsage(src, engineUsage) {
|
|
|
1115
1129
|
total_cost_usd: anyCost ? costMicroUsd / 1e6 : null
|
|
1116
1130
|
};
|
|
1117
1131
|
}
|
|
1132
|
+
function trajectoryFromEngine(result, known = {}) {
|
|
1133
|
+
const rounds = typeof result.token_usage?.rounds_counted === "number" && Number.isInteger(result.token_usage.rounds_counted) && result.token_usage.rounds_counted >= 0 ? result.token_usage.rounds_counted : null;
|
|
1134
|
+
const called = result.fan_out_diagnostics?.models_called;
|
|
1135
|
+
const turns = typeof called === "number" && Number.isInteger(called) && called >= 0 ? called : rounds !== null && rounds > 0 ? result.per_model_verdicts.length * rounds : null;
|
|
1136
|
+
const sourceGrounded = result.citation_grade !== void 0 || result.low_confidence_sources !== void 0;
|
|
1137
|
+
const tool_calls = typeof known.tool_calls === "number" && Number.isInteger(known.tool_calls) && known.tool_calls >= 0 ? known.tool_calls : sourceGrounded ? null : 0;
|
|
1138
|
+
if (rounds === null && turns === null && tool_calls === null) return {};
|
|
1139
|
+
const trajectory = { rounds, turns, tool_calls };
|
|
1140
|
+
return { trajectory };
|
|
1141
|
+
}
|
|
1118
1142
|
function toEventSynthesizedVerdict(src) {
|
|
1119
1143
|
return {
|
|
1120
1144
|
verdict: src.verdict,
|
|
@@ -1122,12 +1146,13 @@ function toEventSynthesizedVerdict(src) {
|
|
|
1122
1146
|
reasoning_excerpt: sanitizeExcerpt(src.reasoning_excerpt)
|
|
1123
1147
|
};
|
|
1124
1148
|
}
|
|
1125
|
-
var VO_MCP_VERSION;
|
|
1149
|
+
var VO_MCP_VERSION, REPO_RE;
|
|
1126
1150
|
var init_common = __esm({
|
|
1127
1151
|
"src/tools/common.ts"() {
|
|
1128
1152
|
"use strict";
|
|
1129
1153
|
init_events_writer();
|
|
1130
1154
|
VO_MCP_VERSION = readVoMcpVersion();
|
|
1155
|
+
REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u;
|
|
1131
1156
|
}
|
|
1132
1157
|
});
|
|
1133
1158
|
|
|
@@ -2431,9 +2456,9 @@ var init_sync_config = __esm({
|
|
|
2431
2456
|
});
|
|
2432
2457
|
|
|
2433
2458
|
// src/cli.ts
|
|
2434
|
-
import { homedir as
|
|
2459
|
+
import { homedir as homedir9, hostname as hostname2 } from "node:os";
|
|
2435
2460
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
2436
|
-
import { join as
|
|
2461
|
+
import { join as join15 } from "node:path";
|
|
2437
2462
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2438
2463
|
|
|
2439
2464
|
// src/server.ts
|
|
@@ -2815,7 +2840,8 @@ async function handleCheckHollowTest(deps, rawInput, signal) {
|
|
|
2815
2840
|
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
2816
2841
|
duration_ms: engineResult.duration_ms,
|
|
2817
2842
|
consensus_engine_version: engineResult.engine_version,
|
|
2818
|
-
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage)
|
|
2843
|
+
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage),
|
|
2844
|
+
...trajectoryFromEngine(engineResult)
|
|
2819
2845
|
};
|
|
2820
2846
|
const payload = {
|
|
2821
2847
|
verdict: engineResult.synthesized_verdict.verdict,
|
|
@@ -2999,7 +3025,8 @@ async function handleVerifyAnswer(deps, rawInput, signal) {
|
|
|
2999
3025
|
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
3000
3026
|
duration_ms: engineResult.duration_ms,
|
|
3001
3027
|
consensus_engine_version: engineResult.engine_version,
|
|
3002
|
-
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage)
|
|
3028
|
+
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage),
|
|
3029
|
+
...trajectoryFromEngine(engineResult)
|
|
3003
3030
|
};
|
|
3004
3031
|
const payload = {
|
|
3005
3032
|
verdict: engineResult.synthesized_verdict.verdict,
|
|
@@ -3268,7 +3295,8 @@ async function handleConsensusJudgment(deps, rawInput, signal) {
|
|
|
3268
3295
|
consensus_engine_version: engineResult.engine_version,
|
|
3269
3296
|
per_model_verdicts: perModelForEvent,
|
|
3270
3297
|
synthesized_verdict: synthForEvent,
|
|
3271
|
-
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage)
|
|
3298
|
+
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage),
|
|
3299
|
+
...trajectoryFromEngine(engineResult)
|
|
3272
3300
|
};
|
|
3273
3301
|
const payload = {
|
|
3274
3302
|
verdict: engineResult.synthesized_verdict.verdict,
|
|
@@ -3483,7 +3511,8 @@ async function handleArchitectureReview(deps, rawInput, signal) {
|
|
|
3483
3511
|
consensus_confidence: engineResult.synthesized_verdict.confidence,
|
|
3484
3512
|
duration_ms: engineResult.duration_ms,
|
|
3485
3513
|
consensus_engine_version: engineResult.engine_version,
|
|
3486
|
-
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage)
|
|
3514
|
+
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage),
|
|
3515
|
+
...trajectoryFromEngine(engineResult)
|
|
3487
3516
|
};
|
|
3488
3517
|
const escalationRequired = engineResult.escalation_required === true || engineResult.escalation_required === void 0 && engineResult.synthesized_verdict.dissent_summary !== null;
|
|
3489
3518
|
const escalationReason = engineResult.escalation_reason ?? engineResult.synthesized_verdict.dissent_summary ?? "";
|
|
@@ -4971,7 +5000,8 @@ Produce the JSON dispatch plan now.`;
|
|
|
4971
5000
|
consensus_engine_version: engineResult.engine_version,
|
|
4972
5001
|
per_model_verdicts: toEventPerModelVerdicts(engineResult.per_model_verdicts),
|
|
4973
5002
|
synthesized_verdict: toEventSynthesizedVerdict(engineResult.synthesized_verdict),
|
|
4974
|
-
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage)
|
|
5003
|
+
...aggregateEventTokenUsage(engineResult.per_model_verdicts, engineResult.token_usage),
|
|
5004
|
+
...trajectoryFromEngine(engineResult)
|
|
4975
5005
|
};
|
|
4976
5006
|
deps.events.append(enrichedEvent);
|
|
4977
5007
|
return jsonContent(envelope);
|
|
@@ -5673,6 +5703,7 @@ async function handleRejectAndRetry(deps, rawInput, _signal) {
|
|
|
5673
5703
|
init_common();
|
|
5674
5704
|
var TOOL_NAME18 = "vo_review_merge";
|
|
5675
5705
|
var LIST_PATH = "/api/v1/admin/pr/list";
|
|
5706
|
+
var DEFAULT_REVIEW_REPO = "Algosuite-ai/Nexus";
|
|
5676
5707
|
var ENGINE_GATE = "final-deep-verify";
|
|
5677
5708
|
var EVENT_GATE = "merge-review";
|
|
5678
5709
|
var UNAVAILABLE_REASON = "vo_review_merge needs cloud mode to fetch PR context \u2014 set VO_CONTROL_PLANE_URL + VO_CONTROL_PLANE_ADMIN_TOKEN in the MCP env. (It is read-only; it never merges.)";
|
|
@@ -5737,6 +5768,11 @@ async function handleReviewMerge(deps, rawInput, signal) {
|
|
|
5737
5768
|
if (rawInput.notes !== void 0) normalizedInput.notes = rawInput.notes;
|
|
5738
5769
|
const inputJson = JSON.stringify(normalizedInput);
|
|
5739
5770
|
const key = deps.cache.keyFor(TOOL_NAME18, normalizedInput);
|
|
5771
|
+
const subject = {
|
|
5772
|
+
...subjectFromEnv() ?? {},
|
|
5773
|
+
repo: subjectFromEnv()?.repo ?? DEFAULT_REVIEW_REPO,
|
|
5774
|
+
pr_number: prNumber
|
|
5775
|
+
};
|
|
5740
5776
|
const baseEvent = buildBaseEvent({
|
|
5741
5777
|
tool: TOOL_NAME18,
|
|
5742
5778
|
gateType: EVENT_GATE,
|
|
@@ -5744,7 +5780,8 @@ async function handleReviewMerge(deps, rawInput, signal) {
|
|
|
5744
5780
|
inputExcerpt: inputJson.slice(0, 300),
|
|
5745
5781
|
inputSizeBytes: bytesOf(inputJson),
|
|
5746
5782
|
session: deps.session,
|
|
5747
|
-
now: deps.now()
|
|
5783
|
+
now: deps.now(),
|
|
5784
|
+
subject
|
|
5748
5785
|
});
|
|
5749
5786
|
const emit = (payload2, eventExtra) => {
|
|
5750
5787
|
deps.events.append(eventExtra ? { ...baseEvent, ...eventExtra } : baseEvent);
|
|
@@ -5846,7 +5883,8 @@ async function handleReviewMerge(deps, rawInput, signal) {
|
|
|
5846
5883
|
consensus_engine_version: result.engine_version,
|
|
5847
5884
|
per_model_verdicts: perModel,
|
|
5848
5885
|
synthesized_verdict: synth,
|
|
5849
|
-
...aggregateEventTokenUsage(result.per_model_verdicts, result.token_usage)
|
|
5886
|
+
...aggregateEventTokenUsage(result.per_model_verdicts, result.token_usage),
|
|
5887
|
+
...trajectoryFromEngine(result)
|
|
5850
5888
|
});
|
|
5851
5889
|
}
|
|
5852
5890
|
|
|
@@ -8396,6 +8434,109 @@ function createConsensusFallbackClient(primary, fallback, options = {}) {
|
|
|
8396
8434
|
};
|
|
8397
8435
|
}
|
|
8398
8436
|
|
|
8437
|
+
// src/consensus/shadow-client.ts
|
|
8438
|
+
import { appendFileSync as appendFileSync2, chmodSync as chmodSync4, mkdirSync as mkdirSync8, renameSync, statSync as statSync7 } from "node:fs";
|
|
8439
|
+
import { homedir as homedir8 } from "node:os";
|
|
8440
|
+
import { dirname as dirname7, join as join14 } from "node:path";
|
|
8441
|
+
var DEFAULT_SHADOW_TIMEOUT_MS = 2e4;
|
|
8442
|
+
var SHADOW_RECEIPT_MAX_BYTES = 20 * 1024 * 1024;
|
|
8443
|
+
function defaultShadowReceiptPath(env = process.env) {
|
|
8444
|
+
const p = (env["VO_MCP_MOAT_SHADOW_PATH"] ?? "").trim();
|
|
8445
|
+
return p || join14(homedir8(), ".claude", "vo-mcp-moat-shadow.jsonl");
|
|
8446
|
+
}
|
|
8447
|
+
function appendShadowReceipt(receipt, path3 = defaultShadowReceiptPath()) {
|
|
8448
|
+
try {
|
|
8449
|
+
mkdirSync8(dirname7(path3), { recursive: true, mode: 448 });
|
|
8450
|
+
try {
|
|
8451
|
+
if (statSync7(path3).size > SHADOW_RECEIPT_MAX_BYTES) renameSync(path3, `${path3}.1`);
|
|
8452
|
+
} catch {
|
|
8453
|
+
}
|
|
8454
|
+
appendFileSync2(path3, `${JSON.stringify(receipt)}
|
|
8455
|
+
`, "utf8");
|
|
8456
|
+
try {
|
|
8457
|
+
chmodSync4(path3, 384);
|
|
8458
|
+
} catch {
|
|
8459
|
+
}
|
|
8460
|
+
} catch {
|
|
8461
|
+
}
|
|
8462
|
+
}
|
|
8463
|
+
function summarize(result) {
|
|
8464
|
+
if (result.ok) {
|
|
8465
|
+
return {
|
|
8466
|
+
ok: true,
|
|
8467
|
+
verdict: result.synthesized_verdict.verdict,
|
|
8468
|
+
confidence: result.synthesized_verdict.confidence,
|
|
8469
|
+
...result.receipt_id ? { receipt_id: result.receipt_id } : {}
|
|
8470
|
+
};
|
|
8471
|
+
}
|
|
8472
|
+
return { ok: false, reason: result.reason };
|
|
8473
|
+
}
|
|
8474
|
+
async function runMoat(shadow, request, timeoutMs, linkCallerSignal) {
|
|
8475
|
+
const callerSignal = linkCallerSignal ? request.signal : void 0;
|
|
8476
|
+
if (callerSignal?.aborted) return { ok: false, reason: CANCELLED_REASON };
|
|
8477
|
+
const controller = new AbortController();
|
|
8478
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
8479
|
+
const onCallerAbort = () => controller.abort();
|
|
8480
|
+
callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
8481
|
+
try {
|
|
8482
|
+
const { signal: _ignored, ...rest } = request;
|
|
8483
|
+
void _ignored;
|
|
8484
|
+
return await shadow.run({ ...rest, signal: controller.signal });
|
|
8485
|
+
} catch (err) {
|
|
8486
|
+
return { ok: false, reason: `moat-shadow-threw: ${err instanceof Error ? err.message : String(err)}`.slice(0, 200) };
|
|
8487
|
+
} finally {
|
|
8488
|
+
clearTimeout(timer);
|
|
8489
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
8490
|
+
}
|
|
8491
|
+
}
|
|
8492
|
+
function createConsensusShadowClient(primary, shadow, options = {}) {
|
|
8493
|
+
const authoritative = options.authoritative === true;
|
|
8494
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_SHADOW_TIMEOUT_MS;
|
|
8495
|
+
const now = options.now ?? (() => Date.now());
|
|
8496
|
+
const random = options.random ?? Math.random;
|
|
8497
|
+
const samplePct = Math.min(100, Math.max(0, options.samplePct ?? 100));
|
|
8498
|
+
const onReceipt = options.onReceipt ?? ((r) => appendShadowReceipt(r));
|
|
8499
|
+
function receiptFor(request, local, moat, startedAt) {
|
|
8500
|
+
const l = summarize(local);
|
|
8501
|
+
const m = summarize(moat);
|
|
8502
|
+
return {
|
|
8503
|
+
ts: new Date(now()).toISOString(),
|
|
8504
|
+
gate_type: request.gate_type,
|
|
8505
|
+
mode: authoritative ? "authoritative" : "shadow",
|
|
8506
|
+
local: l,
|
|
8507
|
+
moat: m,
|
|
8508
|
+
agree: l.ok && m.ok ? l.verdict === m.verdict : null,
|
|
8509
|
+
duration_ms: Math.max(0, now() - startedAt)
|
|
8510
|
+
};
|
|
8511
|
+
}
|
|
8512
|
+
return {
|
|
8513
|
+
async run(request) {
|
|
8514
|
+
const startedAt = now();
|
|
8515
|
+
const primaryResult = await primary.run(request);
|
|
8516
|
+
if (request.signal?.aborted || !primaryResult.ok && primaryResult.reason === CANCELLED_REASON) {
|
|
8517
|
+
return primaryResult;
|
|
8518
|
+
}
|
|
8519
|
+
if (!primaryResult.ok || primaryResult.receipt_id) return primaryResult;
|
|
8520
|
+
if (authoritative) {
|
|
8521
|
+
const moatResult = await runMoat(shadow, request, timeoutMs, true);
|
|
8522
|
+
try {
|
|
8523
|
+
onReceipt(receiptFor(request, primaryResult, moatResult, startedAt));
|
|
8524
|
+
} catch {
|
|
8525
|
+
}
|
|
8526
|
+
return moatResult.ok ? moatResult : primaryResult;
|
|
8527
|
+
}
|
|
8528
|
+
if (samplePct < 100 && random() * 100 >= samplePct) return primaryResult;
|
|
8529
|
+
void runMoat(shadow, request, timeoutMs, false).then((moatResult) => {
|
|
8530
|
+
try {
|
|
8531
|
+
onReceipt(receiptFor(request, primaryResult, moatResult, startedAt));
|
|
8532
|
+
} catch {
|
|
8533
|
+
}
|
|
8534
|
+
});
|
|
8535
|
+
return primaryResult;
|
|
8536
|
+
}
|
|
8537
|
+
};
|
|
8538
|
+
}
|
|
8539
|
+
|
|
8399
8540
|
// src/consensus/local-credential-env.ts
|
|
8400
8541
|
import { createRequire as createRequire2 } from "node:module";
|
|
8401
8542
|
var require2 = createRequire2(import.meta.url);
|
|
@@ -8629,7 +8770,7 @@ init_common();
|
|
|
8629
8770
|
function defaultCacheDbPath() {
|
|
8630
8771
|
const env = process.env["VO_MCP_DB_PATH"];
|
|
8631
8772
|
if (env && env.length > 0) return env;
|
|
8632
|
-
return
|
|
8773
|
+
return join15(homedir9(), ".claude", "vo-mcp-cache.db");
|
|
8633
8774
|
}
|
|
8634
8775
|
async function probeEngineVersion() {
|
|
8635
8776
|
try {
|
|
@@ -8717,6 +8858,16 @@ async function main() {
|
|
|
8717
8858
|
consensus = createConsensusFallbackClient(localConsensus, cloudConsensus, {
|
|
8718
8859
|
onFallback: (reason) => console.error(`[vo-mcp] local consensus unavailable (${reason}); using cloud moat fallback`)
|
|
8719
8860
|
});
|
|
8861
|
+
const moatAuthoritative = process.env["VO_CONSENSUS_MOAT_AUTHORITATIVE"] === "1";
|
|
8862
|
+
if (moatAuthoritative || process.env["VO_CONSENSUS_MOAT_SHADOW"] === "1") {
|
|
8863
|
+
const pctRaw = Number(process.env["VO_CONSENSUS_MOAT_SHADOW_PCT"] ?? "100");
|
|
8864
|
+
const samplePct = Number.isFinite(pctRaw) ? Math.min(100, Math.max(0, pctRaw)) : 100;
|
|
8865
|
+
const shadowedLocal = createConsensusShadowClient(localConsensus, cloudConsensus, { authoritative: moatAuthoritative, samplePct });
|
|
8866
|
+
consensus = createConsensusFallbackClient(shadowedLocal, cloudConsensus, {
|
|
8867
|
+
onFallback: (reason) => console.error(`[vo-mcp] local consensus unavailable (${reason}); using cloud moat fallback`)
|
|
8868
|
+
});
|
|
8869
|
+
console.error(`[vo-mcp] moat ${moatAuthoritative ? "AUTHORITATIVE" : `SHADOW (${samplePct}%)`} active \u2014 local verdicts also reach the moat verify path (receipts: ${defaultShadowReceiptPath()})`);
|
|
8870
|
+
}
|
|
8720
8871
|
} else if (!testClient && cloudConsensus) {
|
|
8721
8872
|
console.error("[vo-mcp] fewer than 2 linked local providers; cloud moat consensus active");
|
|
8722
8873
|
consensus = cloudConsensus;
|
|
@@ -8785,12 +8936,12 @@ if (process.argv[2] === "login") {
|
|
|
8785
8936
|
const sessionId = randomUUID6();
|
|
8786
8937
|
const appendSyncLog = async (line) => {
|
|
8787
8938
|
try {
|
|
8788
|
-
const { appendFileSync:
|
|
8789
|
-
const { join:
|
|
8790
|
-
const { homedir:
|
|
8791
|
-
const dir =
|
|
8792
|
-
|
|
8793
|
-
|
|
8939
|
+
const { appendFileSync: appendFileSync3, mkdirSync: mkdirSync9 } = await import("node:fs");
|
|
8940
|
+
const { join: join16 } = await import("node:path");
|
|
8941
|
+
const { homedir: homedir10 } = await import("node:os");
|
|
8942
|
+
const dir = join16(homedir10(), ".claude");
|
|
8943
|
+
mkdirSync9(dir, { recursive: true });
|
|
8944
|
+
appendFileSync3(join16(dir, "vo-mcp-sync.log"), `${line}
|
|
8794
8945
|
`, "utf8");
|
|
8795
8946
|
} catch {
|
|
8796
8947
|
}
|