@alook/daemon 0.1.25 → 0.1.26
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/index.js +461 -141
- package/dist/index.js +449 -129
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -17536,7 +17536,7 @@ var REASONING_EFFORT_RE = /^[A-Za-z0-9._-]+$/;
|
|
|
17536
17536
|
var COMMUNITY_REASONING_EFFORT_MAX = 32;
|
|
17537
17537
|
var COMMUNITY_REASONING_DESCRIPTION_MAX = 256;
|
|
17538
17538
|
var COMMUNITY_REASONING_OPTIONS_MAX = 16;
|
|
17539
|
-
var COMMUNITY_REASONING_MODELS_MAX =
|
|
17539
|
+
var COMMUNITY_REASONING_MODELS_MAX = 512;
|
|
17540
17540
|
var ReasoningEffortSchema = exports_external.string().min(1).max(COMMUNITY_REASONING_EFFORT_MAX).regex(REASONING_EFFORT_RE, "invalid reasoning effort charset");
|
|
17541
17541
|
var RuntimeReasoningOptionSchema = exports_external.object({
|
|
17542
17542
|
value: ReasoningEffortSchema,
|
|
@@ -17544,6 +17544,7 @@ var RuntimeReasoningOptionSchema = exports_external.object({
|
|
|
17544
17544
|
});
|
|
17545
17545
|
var RuntimeReasoningModelSchema = exports_external.object({
|
|
17546
17546
|
id: exports_external.string().min(1).max(100),
|
|
17547
|
+
displayName: exports_external.string().min(1).max(COMMUNITY_REASONING_DESCRIPTION_MAX).optional().catch(undefined),
|
|
17547
17548
|
supportedReasoningEfforts: exports_external.array(exports_external.unknown()).max(COMMUNITY_REASONING_OPTIONS_MAX).transform((options) => {
|
|
17548
17549
|
const seen = new Set;
|
|
17549
17550
|
return options.flatMap((candidate) => {
|
|
@@ -20338,8 +20339,8 @@ function resolveLaunchFieldsOrDefault(input) {
|
|
|
20338
20339
|
const envVars = Object.fromEntries(Object.entries(normalized.environment ?? {}).filter(([key]) => !controlled.has(key)));
|
|
20339
20340
|
const providerEnv = {};
|
|
20340
20341
|
const model = normalized.model.kind === "default" ? undefined : normalized.model.name;
|
|
20341
|
-
if (
|
|
20342
|
-
providerEnv.ANTHROPIC_CUSTOM_MODEL_OPTION =
|
|
20342
|
+
if (model && normalized.provider?.kind === "custom_endpoint") {
|
|
20343
|
+
providerEnv.ANTHROPIC_CUSTOM_MODEL_OPTION = model;
|
|
20343
20344
|
}
|
|
20344
20345
|
if (normalized.provider?.kind === "custom_endpoint") {
|
|
20345
20346
|
providerEnv.ANTHROPIC_BASE_URL = normalized.provider.apiUrl;
|
|
@@ -20674,6 +20675,7 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
20674
20675
|
import * as fs5 from "fs";
|
|
20675
20676
|
import * as path5 from "path";
|
|
20676
20677
|
var PROBE_TIMEOUT_MS = 5000;
|
|
20678
|
+
var PROBE_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
20677
20679
|
function resolveCommandOnPath(command, deps = {}) {
|
|
20678
20680
|
if (deps.which)
|
|
20679
20681
|
return deps.which(command);
|
|
@@ -20724,6 +20726,23 @@ function probeCommandVersion(command, args = [], deps = {}, platform = process.p
|
|
|
20724
20726
|
return { ok: false, error: String(code) };
|
|
20725
20727
|
}
|
|
20726
20728
|
}
|
|
20729
|
+
function probeCommandOutput(command, args, platform = process.platform) {
|
|
20730
|
+
try {
|
|
20731
|
+
const output = execFileSync2(command, args, {
|
|
20732
|
+
encoding: "utf8",
|
|
20733
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
20734
|
+
maxBuffer: PROBE_OUTPUT_MAX_BYTES,
|
|
20735
|
+
shell: needsWindowsShimShell(command, platform),
|
|
20736
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
20737
|
+
input: "",
|
|
20738
|
+
env: { ...process.env, CI: "1" }
|
|
20739
|
+
});
|
|
20740
|
+
return { ok: true, output };
|
|
20741
|
+
} catch (err) {
|
|
20742
|
+
const code = err?.code ?? "command_probe_failed";
|
|
20743
|
+
return { ok: false, error: String(code) };
|
|
20744
|
+
}
|
|
20745
|
+
}
|
|
20727
20746
|
function resolveHomePath(relativePath, deps = {}) {
|
|
20728
20747
|
return path5.join(deps.homeDir || process.env.HOME || ".", relativePath);
|
|
20729
20748
|
}
|
|
@@ -20830,6 +20849,14 @@ class ClaudeTurnProtocol {
|
|
|
20830
20849
|
}
|
|
20831
20850
|
|
|
20832
20851
|
// agent-driver/dist/adapters/claude/index.js
|
|
20852
|
+
var CLAUDE_MODEL_CATALOG = {
|
|
20853
|
+
updateMode: "unsupported",
|
|
20854
|
+
models: ["opus", "sonnet", "haiku"].map((id) => ({
|
|
20855
|
+
id,
|
|
20856
|
+
supportedReasoningEfforts: []
|
|
20857
|
+
}))
|
|
20858
|
+
};
|
|
20859
|
+
|
|
20833
20860
|
class ClaudeDriver {
|
|
20834
20861
|
id = "claude";
|
|
20835
20862
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
@@ -20846,10 +20873,11 @@ class ClaudeDriver {
|
|
|
20846
20873
|
}
|
|
20847
20874
|
probe(command) {
|
|
20848
20875
|
const explicit = command?.trim();
|
|
20849
|
-
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
20876
|
+
const base = explicit ? (() => {
|
|
20877
|
+
const result = probeCommandVersion(explicit);
|
|
20878
|
+
return result.ok ? { status: "healthy", version: result.version } : { status: "unhealthy", lastError: result.error };
|
|
20879
|
+
})() : probeClaude();
|
|
20880
|
+
return base.status === "healthy" ? { ...base, reasoning: CLAUDE_MODEL_CATALOG } : base;
|
|
20853
20881
|
}
|
|
20854
20882
|
async openLane(ctx, options) {
|
|
20855
20883
|
return createProcessLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
|
|
@@ -21416,10 +21444,59 @@ function stableErrorCode(value, fallback) {
|
|
|
21416
21444
|
return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
|
|
21417
21445
|
}
|
|
21418
21446
|
|
|
21447
|
+
// agent-driver/dist/internal/modelCatalog.js
|
|
21448
|
+
var RUNTIME_MODEL_CATALOG_MAX = 512;
|
|
21449
|
+
var RUNTIME_MODEL_ID_MAX = 100;
|
|
21450
|
+
function normalizeRuntimeModelId(value) {
|
|
21451
|
+
if (typeof value !== "string")
|
|
21452
|
+
return;
|
|
21453
|
+
const id = value.trim();
|
|
21454
|
+
if (!id || id.length > RUNTIME_MODEL_ID_MAX || /\s/.test(id))
|
|
21455
|
+
return;
|
|
21456
|
+
return id;
|
|
21457
|
+
}
|
|
21458
|
+
function catalogFromIds(ids) {
|
|
21459
|
+
const seen = new Set;
|
|
21460
|
+
const models = [];
|
|
21461
|
+
for (const rawId of ids) {
|
|
21462
|
+
const id = normalizeRuntimeModelId(rawId);
|
|
21463
|
+
if (!id || seen.has(id))
|
|
21464
|
+
continue;
|
|
21465
|
+
if (models.length >= RUNTIME_MODEL_CATALOG_MAX)
|
|
21466
|
+
return;
|
|
21467
|
+
seen.add(id);
|
|
21468
|
+
models.push({ id, supportedReasoningEfforts: [] });
|
|
21469
|
+
}
|
|
21470
|
+
if (models.length === 0)
|
|
21471
|
+
return;
|
|
21472
|
+
return { updateMode: "unsupported", models };
|
|
21473
|
+
}
|
|
21474
|
+
function parseOpenCodeModelCatalog(output) {
|
|
21475
|
+
const ids = output.split(/\r?\n/).flatMap((line) => {
|
|
21476
|
+
const id = normalizeRuntimeModelId(line);
|
|
21477
|
+
return id && /^[^/]+\/.+$/.test(id) ? [id] : [];
|
|
21478
|
+
});
|
|
21479
|
+
return catalogFromIds(ids);
|
|
21480
|
+
}
|
|
21481
|
+
function parsePiModelCatalog(values) {
|
|
21482
|
+
if (!Array.isArray(values))
|
|
21483
|
+
return;
|
|
21484
|
+
const ids = values.flatMap((value) => {
|
|
21485
|
+
if (!value || typeof value !== "object")
|
|
21486
|
+
return [];
|
|
21487
|
+
const model = value;
|
|
21488
|
+
const provider = normalizeRuntimeModelId(model.provider);
|
|
21489
|
+
const id = normalizeRuntimeModelId(model.id);
|
|
21490
|
+
return provider && id && !provider.includes("/") ? [`${provider}/${id}`] : [];
|
|
21491
|
+
});
|
|
21492
|
+
return catalogFromIds(ids);
|
|
21493
|
+
}
|
|
21494
|
+
|
|
21419
21495
|
// agent-driver/dist/adapters/codex/index.js
|
|
21420
21496
|
var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
|
|
21421
21497
|
var MODEL_LIST_TIMEOUT_MS = 5000;
|
|
21422
|
-
var
|
|
21498
|
+
var MODEL_LIST_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
21499
|
+
var MODEL_LIST_MAX = RUNTIME_MODEL_CATALOG_MAX;
|
|
21423
21500
|
var MODEL_EFFORT_MAX = 16;
|
|
21424
21501
|
function isCodexMissingRolloutError(message2) {
|
|
21425
21502
|
return /\bno\s+rollout\s+found\b/i.test(message2) || /\bmissing\s+rollout\b/i.test(message2) || /\brollout\b.*\b(not found|missing)\b/i.test(message2) || /\b(not found|missing)\b.*\brollout\b/i.test(message2);
|
|
@@ -21495,11 +21572,13 @@ class CodexDriver {
|
|
|
21495
21572
|
return new Promise((resolve2) => {
|
|
21496
21573
|
let settled = false;
|
|
21497
21574
|
let buffer = "";
|
|
21575
|
+
let outputBytes = 0;
|
|
21498
21576
|
let nextId = 0;
|
|
21499
21577
|
let initializeId = 0;
|
|
21500
21578
|
let listId = 0;
|
|
21501
21579
|
const models = [];
|
|
21502
21580
|
const seenModels = new Set;
|
|
21581
|
+
let overflow = false;
|
|
21503
21582
|
let defaultModelId;
|
|
21504
21583
|
const finish = (catalog) => {
|
|
21505
21584
|
if (settled)
|
|
@@ -21517,12 +21596,16 @@ class CodexDriver {
|
|
|
21517
21596
|
`);
|
|
21518
21597
|
};
|
|
21519
21598
|
const consumeModel = (value) => {
|
|
21520
|
-
if (!value || typeof value !== "object"
|
|
21599
|
+
if (!value || typeof value !== "object")
|
|
21521
21600
|
return;
|
|
21522
21601
|
const model = value;
|
|
21523
|
-
const id =
|
|
21524
|
-
if (!id ||
|
|
21602
|
+
const id = normalizeRuntimeModelId(model.id);
|
|
21603
|
+
if (!id || seenModels.has(id))
|
|
21525
21604
|
return;
|
|
21605
|
+
if (models.length >= MODEL_LIST_MAX) {
|
|
21606
|
+
overflow = true;
|
|
21607
|
+
return;
|
|
21608
|
+
}
|
|
21526
21609
|
const rawOptions = Array.isArray(model.supportedReasoningEfforts) ? model.supportedReasoningEfforts : [];
|
|
21527
21610
|
const seenEfforts = new Set;
|
|
21528
21611
|
const supportedReasoningEfforts = rawOptions.flatMap((raw) => {
|
|
@@ -21566,9 +21649,15 @@ class CodexDriver {
|
|
|
21566
21649
|
const result = message2.result;
|
|
21567
21650
|
for (const model of Array.isArray(result.data) ? result.data : [])
|
|
21568
21651
|
consumeModel(model);
|
|
21652
|
+
if (overflow)
|
|
21653
|
+
return finish();
|
|
21569
21654
|
const cursor = typeof result.nextCursor === "string" ? result.nextCursor : undefined;
|
|
21570
|
-
if (cursor && models.length
|
|
21655
|
+
if (cursor && models.length >= MODEL_LIST_MAX)
|
|
21656
|
+
return finish();
|
|
21657
|
+
if (cursor)
|
|
21571
21658
|
return requestModelPage(cursor);
|
|
21659
|
+
if (models.length === 0)
|
|
21660
|
+
return finish();
|
|
21572
21661
|
finish({
|
|
21573
21662
|
updateMode: "live_next_turn",
|
|
21574
21663
|
...defaultModelId ? { defaultModelId } : {},
|
|
@@ -21578,7 +21667,11 @@ class CodexDriver {
|
|
|
21578
21667
|
const timer = setTimeout(() => finish(), MODEL_LIST_TIMEOUT_MS);
|
|
21579
21668
|
timer.unref?.();
|
|
21580
21669
|
proc.stdout?.on("data", (chunk2) => {
|
|
21581
|
-
|
|
21670
|
+
const text2 = chunk2.toString();
|
|
21671
|
+
outputBytes += Buffer.byteLength(text2);
|
|
21672
|
+
if (outputBytes > MODEL_LIST_OUTPUT_MAX_BYTES)
|
|
21673
|
+
return finish();
|
|
21674
|
+
buffer += text2;
|
|
21582
21675
|
const lines = buffer.split(`
|
|
21583
21676
|
`);
|
|
21584
21677
|
buffer = lines.pop() ?? "";
|
|
@@ -21781,9 +21874,189 @@ class CodexDriver {
|
|
|
21781
21874
|
|
|
21782
21875
|
// agent-driver/dist/adapters/cursor/acp-lane.js
|
|
21783
21876
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
21877
|
+
|
|
21878
|
+
// agent-driver/dist/adapters/cursor/catalog-probe.js
|
|
21784
21879
|
var ACP_PROTOCOL_VERSION = 1;
|
|
21785
|
-
var HANDSHAKE_TIMEOUT_MS = 15000;
|
|
21786
21880
|
var AUTH_METHOD_ID = "cursor_login";
|
|
21881
|
+
var CATALOG_PROBE_TIMEOUT_MS = 15000;
|
|
21882
|
+
var CATALOG_PROBE_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
21883
|
+
var MODEL_DISPLAY_NAME_MAX = 256;
|
|
21884
|
+
var MODEL_OPTION_NESTING_MAX = 16;
|
|
21885
|
+
function record2(value) {
|
|
21886
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
21887
|
+
}
|
|
21888
|
+
function normalizeDisplayName(value) {
|
|
21889
|
+
if (typeof value !== "string")
|
|
21890
|
+
return;
|
|
21891
|
+
const displayName = value.trim();
|
|
21892
|
+
return displayName && displayName.length <= MODEL_DISPLAY_NAME_MAX ? displayName : undefined;
|
|
21893
|
+
}
|
|
21894
|
+
function flattenCursorAcpSelectOptions(value, depth = 0) {
|
|
21895
|
+
if (!Array.isArray(value) || depth > MODEL_OPTION_NESTING_MAX)
|
|
21896
|
+
return [];
|
|
21897
|
+
const options = [];
|
|
21898
|
+
for (const item of value) {
|
|
21899
|
+
if (Array.isArray(item)) {
|
|
21900
|
+
options.push(...flattenCursorAcpSelectOptions(item, depth + 1));
|
|
21901
|
+
continue;
|
|
21902
|
+
}
|
|
21903
|
+
const candidate = record2(item);
|
|
21904
|
+
if (!candidate)
|
|
21905
|
+
continue;
|
|
21906
|
+
const exactValue = normalizeRuntimeModelId(candidate.value);
|
|
21907
|
+
if (exactValue) {
|
|
21908
|
+
const name = normalizeDisplayName(candidate.name);
|
|
21909
|
+
options.push({ value: exactValue, ...name ? { name } : {} });
|
|
21910
|
+
}
|
|
21911
|
+
if (Array.isArray(candidate.options)) {
|
|
21912
|
+
options.push(...flattenCursorAcpSelectOptions(candidate.options, depth + 1));
|
|
21913
|
+
}
|
|
21914
|
+
}
|
|
21915
|
+
return options;
|
|
21916
|
+
}
|
|
21917
|
+
function parseCursorAcpModelCatalog(session2) {
|
|
21918
|
+
const payload = record2(session2);
|
|
21919
|
+
const configOptions = Array.isArray(payload?.configOptions) ? payload.configOptions : [];
|
|
21920
|
+
const modelConfig = configOptions.map(record2).find((option) => option?.id === "model") ?? null;
|
|
21921
|
+
if (!modelConfig)
|
|
21922
|
+
return;
|
|
21923
|
+
const seen = new Set;
|
|
21924
|
+
const models = [];
|
|
21925
|
+
for (const option of flattenCursorAcpSelectOptions(modelConfig.options)) {
|
|
21926
|
+
if (option.value === "default[]" || seen.has(option.value))
|
|
21927
|
+
continue;
|
|
21928
|
+
if (models.length >= RUNTIME_MODEL_CATALOG_MAX)
|
|
21929
|
+
return;
|
|
21930
|
+
seen.add(option.value);
|
|
21931
|
+
models.push({
|
|
21932
|
+
id: option.value,
|
|
21933
|
+
...option.name ? { displayName: option.name } : {},
|
|
21934
|
+
supportedReasoningEfforts: []
|
|
21935
|
+
});
|
|
21936
|
+
}
|
|
21937
|
+
return models.length > 0 ? { updateMode: "unsupported", models } : undefined;
|
|
21938
|
+
}
|
|
21939
|
+
async function cleanupProbeProcess(process3) {
|
|
21940
|
+
if (process3.pid) {
|
|
21941
|
+
await killProcessTree(process3.pid, { graceMs: 250 }).catch(() => {});
|
|
21942
|
+
return;
|
|
21943
|
+
}
|
|
21944
|
+
if (process3.exitCode === null && process3.signalCode === null)
|
|
21945
|
+
process3.kill("SIGTERM");
|
|
21946
|
+
}
|
|
21947
|
+
async function probeCursorAcpCatalog(command, options = {}) {
|
|
21948
|
+
const cwd = options.cwd ?? process.cwd();
|
|
21949
|
+
const spec = resolveSpawnSpec("cursor-agent", ["acp"], command);
|
|
21950
|
+
let processHandle;
|
|
21951
|
+
try {
|
|
21952
|
+
processHandle = (options.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
|
|
21953
|
+
cwd,
|
|
21954
|
+
env: { ...process.env, CI: "1" },
|
|
21955
|
+
shell: spec.shell
|
|
21956
|
+
});
|
|
21957
|
+
} catch {
|
|
21958
|
+
return;
|
|
21959
|
+
}
|
|
21960
|
+
return new Promise((resolve2) => {
|
|
21961
|
+
let settled = false;
|
|
21962
|
+
let buffer = "";
|
|
21963
|
+
let outputBytes = 0;
|
|
21964
|
+
let requestId = 0;
|
|
21965
|
+
let expectedId = 0;
|
|
21966
|
+
let expectedMethod = "";
|
|
21967
|
+
const finish = (catalog) => {
|
|
21968
|
+
if (settled)
|
|
21969
|
+
return;
|
|
21970
|
+
settled = true;
|
|
21971
|
+
clearTimeout(timer);
|
|
21972
|
+
const cleanup = options.cleanup ?? cleanupProbeProcess;
|
|
21973
|
+
Promise.resolve().then(() => cleanup(processHandle)).catch(() => {}).finally(() => resolve2(catalog));
|
|
21974
|
+
};
|
|
21975
|
+
const request = (method, params) => {
|
|
21976
|
+
if (settled)
|
|
21977
|
+
return;
|
|
21978
|
+
const stdin = processHandle.stdin;
|
|
21979
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
21980
|
+
return finish();
|
|
21981
|
+
expectedId = ++requestId;
|
|
21982
|
+
expectedMethod = method;
|
|
21983
|
+
try {
|
|
21984
|
+
stdin.write(`${jsonRpcRequest(method, params, expectedId)}
|
|
21985
|
+
`);
|
|
21986
|
+
} catch {
|
|
21987
|
+
finish();
|
|
21988
|
+
}
|
|
21989
|
+
};
|
|
21990
|
+
const onLine = (line) => {
|
|
21991
|
+
const parsed = tryParseJsonLine(line);
|
|
21992
|
+
const message2 = record2(parsed);
|
|
21993
|
+
if (!message2)
|
|
21994
|
+
return finish();
|
|
21995
|
+
if (message2.id !== expectedId)
|
|
21996
|
+
return;
|
|
21997
|
+
if (message2.error !== undefined)
|
|
21998
|
+
return finish();
|
|
21999
|
+
if (!Object.prototype.hasOwnProperty.call(message2, "result"))
|
|
22000
|
+
return finish();
|
|
22001
|
+
if (expectedMethod === "authenticate") {
|
|
22002
|
+
request("session/new", { cwd, mcpServers: [] });
|
|
22003
|
+
return;
|
|
22004
|
+
}
|
|
22005
|
+
const result = record2(message2.result);
|
|
22006
|
+
if (!result)
|
|
22007
|
+
return finish();
|
|
22008
|
+
if (expectedMethod === "initialize") {
|
|
22009
|
+
const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
|
|
22010
|
+
if (result.protocolVersion !== ACP_PROTOCOL_VERSION || !authMethods.some((method) => record2(method)?.id === AUTH_METHOD_ID))
|
|
22011
|
+
return finish();
|
|
22012
|
+
request("authenticate", { methodId: AUTH_METHOD_ID });
|
|
22013
|
+
return;
|
|
22014
|
+
}
|
|
22015
|
+
if (expectedMethod !== "session/new" || typeof result.sessionId !== "string" || !result.sessionId.trim())
|
|
22016
|
+
return finish();
|
|
22017
|
+
finish(parseCursorAcpModelCatalog(result));
|
|
22018
|
+
};
|
|
22019
|
+
const timer = setTimeout(() => finish(), options.timeoutMs ?? CATALOG_PROBE_TIMEOUT_MS);
|
|
22020
|
+
timer.unref?.();
|
|
22021
|
+
processHandle.stdout?.on("data", (chunk2) => {
|
|
22022
|
+
if (settled)
|
|
22023
|
+
return;
|
|
22024
|
+
const text2 = chunk2.toString();
|
|
22025
|
+
outputBytes += Buffer.byteLength(text2);
|
|
22026
|
+
if (outputBytes > (options.outputMaxBytes ?? CATALOG_PROBE_OUTPUT_MAX_BYTES))
|
|
22027
|
+
return finish();
|
|
22028
|
+
buffer += text2;
|
|
22029
|
+
const lines = buffer.split(`
|
|
22030
|
+
`);
|
|
22031
|
+
buffer = lines.pop() ?? "";
|
|
22032
|
+
for (const line of lines)
|
|
22033
|
+
if (line.trim())
|
|
22034
|
+
onLine(line);
|
|
22035
|
+
});
|
|
22036
|
+
processHandle.stderr?.on("data", (chunk2) => {
|
|
22037
|
+
if (settled)
|
|
22038
|
+
return;
|
|
22039
|
+
outputBytes += Buffer.byteLength(chunk2.toString());
|
|
22040
|
+
if (outputBytes > (options.outputMaxBytes ?? CATALOG_PROBE_OUTPUT_MAX_BYTES))
|
|
22041
|
+
finish();
|
|
22042
|
+
});
|
|
22043
|
+
processHandle.on("error", () => finish());
|
|
22044
|
+
processHandle.on("exit", () => finish());
|
|
22045
|
+
request("initialize", {
|
|
22046
|
+
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
22047
|
+
clientCapabilities: {
|
|
22048
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
22049
|
+
terminal: false
|
|
22050
|
+
},
|
|
22051
|
+
clientInfo: { name: "alook-agent-driver-probe", version: "0.1.25" }
|
|
22052
|
+
});
|
|
22053
|
+
});
|
|
22054
|
+
}
|
|
22055
|
+
|
|
22056
|
+
// agent-driver/dist/adapters/cursor/acp-lane.js
|
|
22057
|
+
var ACP_PROTOCOL_VERSION2 = 1;
|
|
22058
|
+
var HANDSHAKE_TIMEOUT_MS = 15000;
|
|
22059
|
+
var AUTH_METHOD_ID2 = "cursor_login";
|
|
21787
22060
|
var PROMPT_STOP_REASONS = new Set([
|
|
21788
22061
|
"end_turn",
|
|
21789
22062
|
"max_tokens",
|
|
@@ -21807,16 +22080,16 @@ class CursorAcpRpcError extends Error {
|
|
|
21807
22080
|
this.code = code;
|
|
21808
22081
|
}
|
|
21809
22082
|
}
|
|
21810
|
-
function
|
|
22083
|
+
function record3(value) {
|
|
21811
22084
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
21812
22085
|
}
|
|
21813
22086
|
function safeLabel(value) {
|
|
21814
22087
|
return typeof value === "string" && /^[a-z0-9_-]{1,64}$/i.test(value) ? value : "unknown";
|
|
21815
22088
|
}
|
|
21816
22089
|
function rpcErrorMessage(error51) {
|
|
21817
|
-
const payload =
|
|
22090
|
+
const payload = record3(error51);
|
|
21818
22091
|
const message2 = typeof payload?.message === "string" && payload.message.trim() ? payload.message : "Cursor ACP request failed";
|
|
21819
|
-
const data =
|
|
22092
|
+
const data = record3(payload?.data);
|
|
21820
22093
|
const detail = typeof data?.message === "string" && data.message.trim() ? data.message : undefined;
|
|
21821
22094
|
return detail ? `${message2}: ${detail}` : message2;
|
|
21822
22095
|
}
|
|
@@ -21824,26 +22097,6 @@ function isMissingSessionError(error51) {
|
|
|
21824
22097
|
const message2 = error51 instanceof Error ? error51.message : String(error51);
|
|
21825
22098
|
return /\bsession\b.*\b(not found|missing|unknown|invalid)\b/i.test(message2) || /\b(not found|missing|unknown|invalid)\b.*\bsession\b/i.test(message2);
|
|
21826
22099
|
}
|
|
21827
|
-
function flattenSelectOptions(value) {
|
|
21828
|
-
if (!Array.isArray(value))
|
|
21829
|
-
return [];
|
|
21830
|
-
const out = [];
|
|
21831
|
-
for (const item of value) {
|
|
21832
|
-
if (Array.isArray(item)) {
|
|
21833
|
-
out.push(...flattenSelectOptions(item));
|
|
21834
|
-
continue;
|
|
21835
|
-
}
|
|
21836
|
-
const candidate = record2(item);
|
|
21837
|
-
if (!candidate)
|
|
21838
|
-
continue;
|
|
21839
|
-
if (typeof candidate.value === "string") {
|
|
21840
|
-
out.push({ value: candidate.value, ...typeof candidate.name === "string" ? { name: candidate.name } : {} });
|
|
21841
|
-
}
|
|
21842
|
-
if (Array.isArray(candidate.options))
|
|
21843
|
-
out.push(...flattenSelectOptions(candidate.options));
|
|
21844
|
-
}
|
|
21845
|
-
return out;
|
|
21846
|
-
}
|
|
21847
22100
|
|
|
21848
22101
|
class CursorAcpLane {
|
|
21849
22102
|
factory;
|
|
@@ -21967,30 +22220,30 @@ class CursorAcpLane {
|
|
|
21967
22220
|
}
|
|
21968
22221
|
}
|
|
21969
22222
|
async handshake(ctx) {
|
|
21970
|
-
const initialize =
|
|
21971
|
-
protocolVersion:
|
|
22223
|
+
const initialize = record3(await this.call("initialize", {
|
|
22224
|
+
protocolVersion: ACP_PROTOCOL_VERSION2,
|
|
21972
22225
|
clientCapabilities: {
|
|
21973
22226
|
fs: { readTextFile: false, writeTextFile: false },
|
|
21974
22227
|
terminal: false
|
|
21975
22228
|
},
|
|
21976
22229
|
clientInfo: { name: "alook-agent-driver", version: "0.1.14" }
|
|
21977
22230
|
}));
|
|
21978
|
-
if (initialize?.protocolVersion !==
|
|
22231
|
+
if (initialize?.protocolVersion !== ACP_PROTOCOL_VERSION2) {
|
|
21979
22232
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not support protocol version 1");
|
|
21980
22233
|
}
|
|
21981
|
-
const capabilities =
|
|
22234
|
+
const capabilities = record3(initialize.agentCapabilities);
|
|
21982
22235
|
if (capabilities?.loadSession !== true) {
|
|
21983
22236
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not support persistent session loading");
|
|
21984
22237
|
}
|
|
21985
22238
|
const authMethods = Array.isArray(initialize.authMethods) ? initialize.authMethods : [];
|
|
21986
|
-
if (!authMethods.some((method) =>
|
|
22239
|
+
if (!authMethods.some((method) => record3(method)?.id === AUTH_METHOD_ID2)) {
|
|
21987
22240
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not expose Cursor login authentication");
|
|
21988
22241
|
}
|
|
21989
|
-
await this.call("authenticate", { methodId:
|
|
22242
|
+
await this.call("authenticate", { methodId: AUTH_METHOD_ID2 });
|
|
21990
22243
|
let session2;
|
|
21991
22244
|
if (ctx.config.sessionId) {
|
|
21992
22245
|
try {
|
|
21993
|
-
session2 =
|
|
22246
|
+
session2 = record3(await this.call("session/load", {
|
|
21994
22247
|
sessionId: ctx.config.sessionId,
|
|
21995
22248
|
cwd: ctx.workingDirectory,
|
|
21996
22249
|
mcpServers: []
|
|
@@ -22002,15 +22255,25 @@ class CursorAcpLane {
|
|
|
22002
22255
|
throw error51;
|
|
22003
22256
|
}
|
|
22004
22257
|
} else {
|
|
22005
|
-
session2 =
|
|
22258
|
+
session2 = record3(await this.call("session/new", { cwd: ctx.workingDirectory, mcpServers: [] }));
|
|
22006
22259
|
}
|
|
22007
|
-
if (!session2
|
|
22260
|
+
if (!session2)
|
|
22261
|
+
throw new Error("Cursor ACP did not return a valid session response");
|
|
22262
|
+
const returnedSessionId = session2.sessionId;
|
|
22263
|
+
if (returnedSessionId !== undefined && (typeof returnedSessionId !== "string" || !returnedSessionId.trim())) {
|
|
22008
22264
|
throw new Error("Cursor ACP did not return a valid session id");
|
|
22009
22265
|
}
|
|
22010
|
-
if (ctx.config.sessionId
|
|
22011
|
-
|
|
22266
|
+
if (ctx.config.sessionId) {
|
|
22267
|
+
if (returnedSessionId !== undefined && returnedSessionId !== ctx.config.sessionId) {
|
|
22268
|
+
throw new CursorAcpResetRequiredError("Cursor ACP loaded a different session; reset this agent before continuing");
|
|
22269
|
+
}
|
|
22270
|
+
this.sessionId = ctx.config.sessionId;
|
|
22271
|
+
} else {
|
|
22272
|
+
if (typeof returnedSessionId !== "string") {
|
|
22273
|
+
throw new Error("Cursor ACP did not return a valid session id");
|
|
22274
|
+
}
|
|
22275
|
+
this.sessionId = returnedSessionId;
|
|
22012
22276
|
}
|
|
22013
|
-
this.sessionId = session2.sessionId;
|
|
22014
22277
|
await this.configureModel(session2, ctx);
|
|
22015
22278
|
}
|
|
22016
22279
|
async configureModel(session2, ctx) {
|
|
@@ -22018,24 +22281,30 @@ class CursorAcpLane {
|
|
|
22018
22281
|
if (!requestedModel)
|
|
22019
22282
|
return;
|
|
22020
22283
|
const configOptions = Array.isArray(session2.configOptions) ? session2.configOptions : [];
|
|
22021
|
-
const modelConfig = configOptions.map(
|
|
22284
|
+
const modelConfig = configOptions.map(record3).find((option) => option?.id === "model") ?? null;
|
|
22022
22285
|
if (!modelConfig) {
|
|
22023
22286
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not support model configuration");
|
|
22024
22287
|
}
|
|
22025
|
-
const options =
|
|
22026
|
-
const match = options.find((option) => option.value === requestedModel)
|
|
22288
|
+
const options = flattenCursorAcpSelectOptions(modelConfig.options);
|
|
22289
|
+
const match = options.find((option) => option.value === requestedModel);
|
|
22027
22290
|
if (!match) {
|
|
22028
22291
|
throw new CursorAcpIncompatibleError(`Configured Cursor model is unavailable through ACP: ${requestedModel}`);
|
|
22029
22292
|
}
|
|
22293
|
+
let response;
|
|
22030
22294
|
try {
|
|
22031
|
-
await this.call("session/set_config_option", {
|
|
22295
|
+
response = record3(await this.call("session/set_config_option", {
|
|
22032
22296
|
sessionId: this.sessionId,
|
|
22033
22297
|
configId: "model",
|
|
22034
22298
|
value: match.value
|
|
22035
|
-
});
|
|
22299
|
+
}));
|
|
22036
22300
|
} catch {
|
|
22037
22301
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP rejected model configuration");
|
|
22038
22302
|
}
|
|
22303
|
+
const confirmedOptions = Array.isArray(response?.configOptions) ? response.configOptions : [];
|
|
22304
|
+
const confirmedModel = confirmedOptions.map(record3).find((option) => option?.id === "model") ?? null;
|
|
22305
|
+
if (confirmedModel?.currentValue !== match.value) {
|
|
22306
|
+
throw new CursorAcpIncompatibleError("Cursor ACP did not confirm the exact configured model");
|
|
22307
|
+
}
|
|
22039
22308
|
}
|
|
22040
22309
|
admitPrompt(text2) {
|
|
22041
22310
|
if (!this.sessionId)
|
|
@@ -22071,7 +22340,7 @@ class CursorAcpLane {
|
|
|
22071
22340
|
completePrompt(active, value) {
|
|
22072
22341
|
if (this.activePrompt?.requestId !== active.requestId)
|
|
22073
22342
|
return;
|
|
22074
|
-
const result =
|
|
22343
|
+
const result = record3(value);
|
|
22075
22344
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
22076
22345
|
this.failPrompt(active, new Error("Cursor ACP prompt response did not contain a supported stopReason"));
|
|
22077
22346
|
return;
|
|
@@ -22213,7 +22482,7 @@ class CursorAcpLane {
|
|
|
22213
22482
|
});
|
|
22214
22483
|
}
|
|
22215
22484
|
handleMessage(value) {
|
|
22216
|
-
const message2 =
|
|
22485
|
+
const message2 = record3(value);
|
|
22217
22486
|
if (!message2 || message2.jsonrpc !== "2.0") {
|
|
22218
22487
|
this.protocolFailure("Cursor ACP emitted an invalid JSON-RPC message");
|
|
22219
22488
|
return;
|
|
@@ -22241,7 +22510,7 @@ class CursorAcpLane {
|
|
|
22241
22510
|
if (pending.kind === "prompt") {
|
|
22242
22511
|
this.pending.delete(id);
|
|
22243
22512
|
if (message2.error !== undefined) {
|
|
22244
|
-
const payload =
|
|
22513
|
+
const payload = record3(message2.error);
|
|
22245
22514
|
this.failPrompt(pending.active, new CursorAcpRpcError(pending.method, typeof payload?.code === "number" ? payload.code : undefined, rpcErrorMessage(message2.error)));
|
|
22246
22515
|
} else if (!("result" in message2)) {
|
|
22247
22516
|
this.failPrompt(pending.active, new Error("Cursor ACP response omitted result"));
|
|
@@ -22251,7 +22520,7 @@ class CursorAcpLane {
|
|
|
22251
22520
|
return;
|
|
22252
22521
|
}
|
|
22253
22522
|
if (message2.error !== undefined) {
|
|
22254
|
-
const payload =
|
|
22523
|
+
const payload = record3(message2.error);
|
|
22255
22524
|
this.settleRequest(id, false, new CursorAcpRpcError(pending.method, typeof payload?.code === "number" ? payload.code : undefined, rpcErrorMessage(message2.error)));
|
|
22256
22525
|
return;
|
|
22257
22526
|
}
|
|
@@ -22283,9 +22552,9 @@ class CursorAcpLane {
|
|
|
22283
22552
|
this.diagnostic("warning", `Unsupported Cursor ACP client request: ${safeLabel(method)}`);
|
|
22284
22553
|
return;
|
|
22285
22554
|
}
|
|
22286
|
-
const payload =
|
|
22555
|
+
const payload = record3(params);
|
|
22287
22556
|
const sameSession = payload?.sessionId === this.sessionId;
|
|
22288
|
-
const options = Array.isArray(payload?.options) ? payload.options.map(
|
|
22557
|
+
const options = Array.isArray(payload?.options) ? payload.options.map(record3).filter(Boolean) : [];
|
|
22289
22558
|
const allowOnce = options.find((option) => option.kind === "allow_once" && typeof option.optionId === "string" && option.optionId.trim().length > 0);
|
|
22290
22559
|
if (!this.ready || !this.activePrompt || !sameSession || !allowOnce) {
|
|
22291
22560
|
this.write({ jsonrpc: "2.0", id, result: { outcome: { outcome: "cancelled" } } });
|
|
@@ -22306,7 +22575,7 @@ class CursorAcpLane {
|
|
|
22306
22575
|
this.diagnostic("warning", `Unsupported Cursor ACP notification: ${safeLabel(method)}`);
|
|
22307
22576
|
}
|
|
22308
22577
|
handleSessionUpdate(params) {
|
|
22309
|
-
const payload =
|
|
22578
|
+
const payload = record3(params);
|
|
22310
22579
|
if (!payload || payload.sessionId !== this.sessionId) {
|
|
22311
22580
|
this.diagnostic("warning", "Cursor ACP emitted an update for a different session");
|
|
22312
22581
|
return;
|
|
@@ -22315,18 +22584,18 @@ class CursorAcpLane {
|
|
|
22315
22584
|
this.diagnostic("warning", "Cursor ACP emitted a session update without an active prompt");
|
|
22316
22585
|
return;
|
|
22317
22586
|
}
|
|
22318
|
-
const update =
|
|
22587
|
+
const update = record3(payload.update) ?? {};
|
|
22319
22588
|
const updateType = update?.sessionUpdate;
|
|
22320
22589
|
switch (updateType) {
|
|
22321
22590
|
case "agent_message_chunk": {
|
|
22322
|
-
const content =
|
|
22591
|
+
const content = record3(update.content);
|
|
22323
22592
|
if (content?.type === "text" && typeof content.text === "string") {
|
|
22324
22593
|
this.events.emit("runtime_event", { kind: "assistant_message_delta", text: content.text });
|
|
22325
22594
|
}
|
|
22326
22595
|
return;
|
|
22327
22596
|
}
|
|
22328
22597
|
case "agent_thought_chunk": {
|
|
22329
|
-
const content =
|
|
22598
|
+
const content = record3(update.content);
|
|
22330
22599
|
if (content?.type === "text" && typeof content.text === "string") {
|
|
22331
22600
|
this.events.emit("runtime_event", { kind: "assistant_reasoning_delta", text: content.text });
|
|
22332
22601
|
}
|
|
@@ -22398,6 +22667,7 @@ class CursorAcpLane {
|
|
|
22398
22667
|
|
|
22399
22668
|
// agent-driver/dist/adapters/cursor/index.js
|
|
22400
22669
|
class CursorDriver {
|
|
22670
|
+
catalogProbe;
|
|
22401
22671
|
id = "cursor";
|
|
22402
22672
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
22403
22673
|
execution = {
|
|
@@ -22406,8 +22676,23 @@ class CursorDriver {
|
|
|
22406
22676
|
wakeStart: "immediate",
|
|
22407
22677
|
terminalOwnership: "transport_request"
|
|
22408
22678
|
};
|
|
22409
|
-
|
|
22410
|
-
|
|
22679
|
+
constructor(catalogProbe = probeCursorAcpCatalog) {
|
|
22680
|
+
this.catalogProbe = catalogProbe;
|
|
22681
|
+
}
|
|
22682
|
+
async probe(command) {
|
|
22683
|
+
const result = probeCliRuntime("cursor-agent", {}, command);
|
|
22684
|
+
if (result.status !== "healthy")
|
|
22685
|
+
return result;
|
|
22686
|
+
let reasoning;
|
|
22687
|
+
try {
|
|
22688
|
+
reasoning = await this.catalogProbe(command);
|
|
22689
|
+
} catch {
|
|
22690
|
+
reasoning = undefined;
|
|
22691
|
+
}
|
|
22692
|
+
return {
|
|
22693
|
+
...result,
|
|
22694
|
+
reasoning
|
|
22695
|
+
};
|
|
22411
22696
|
}
|
|
22412
22697
|
async openLane(ctx, options) {
|
|
22413
22698
|
return new CursorAcpLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
|
|
@@ -22464,7 +22749,7 @@ class OpenCodeHttpError extends Error {
|
|
|
22464
22749
|
this.status = status;
|
|
22465
22750
|
}
|
|
22466
22751
|
}
|
|
22467
|
-
function
|
|
22752
|
+
function record4(value) {
|
|
22468
22753
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22469
22754
|
}
|
|
22470
22755
|
function safeLabel2(value) {
|
|
@@ -22511,7 +22796,7 @@ function parseModelRef(model) {
|
|
|
22511
22796
|
return { providerID: model.slice(0, slash), id: model.slice(slash + 1) };
|
|
22512
22797
|
}
|
|
22513
22798
|
function messageFromError(value) {
|
|
22514
|
-
const payload =
|
|
22799
|
+
const payload = record4(value);
|
|
22515
22800
|
const message2 = typeof payload?.message === "string" && payload.message.trim() ? payload.message : undefined;
|
|
22516
22801
|
return message2 ? "OpenCode turn failed" : "OpenCode reported an inconsistent turn outcome";
|
|
22517
22802
|
}
|
|
@@ -22845,7 +23130,7 @@ class OpenCodeServiceLane {
|
|
|
22845
23130
|
const healthTimeoutMs = Math.max(1, Math.min(1000, deadline - Date.now(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS));
|
|
22846
23131
|
const { response, body } = await this.fetchJsonWithTimeout("/global/health", { method: "GET" }, "health", healthTimeoutMs);
|
|
22847
23132
|
if (response.ok) {
|
|
22848
|
-
const health =
|
|
23133
|
+
const health = record4(body);
|
|
22849
23134
|
if (health?.healthy !== true || health.version !== SUPPORTED_VERSION) {
|
|
22850
23135
|
throw new OpenCodeIncompatibleError(`Installed OpenCode service must be version ${SUPPORTED_VERSION}`);
|
|
22851
23136
|
}
|
|
@@ -22866,8 +23151,8 @@ class OpenCodeServiceLane {
|
|
|
22866
23151
|
const { response, body } = await this.fetchJsonWithTimeout("/doc", { method: "GET" }, "OpenAPI");
|
|
22867
23152
|
if (!response.ok)
|
|
22868
23153
|
throw new OpenCodeIncompatibleError("Installed OpenCode service does not expose its OpenAPI document");
|
|
22869
|
-
const document =
|
|
22870
|
-
const paths =
|
|
23154
|
+
const document = record4(body);
|
|
23155
|
+
const paths = record4(document?.paths);
|
|
22871
23156
|
const required2 = [
|
|
22872
23157
|
"/api/session",
|
|
22873
23158
|
"/api/session/active",
|
|
@@ -22880,7 +23165,7 @@ class OpenCodeServiceLane {
|
|
|
22880
23165
|
"/api/session/{sessionID}/permission/{requestID}/reply",
|
|
22881
23166
|
"/api/event"
|
|
22882
23167
|
];
|
|
22883
|
-
if (!paths || required2.some((path7) => !
|
|
23168
|
+
if (!paths || required2.some((path7) => !record4(paths[path7]))) {
|
|
22884
23169
|
throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
|
|
22885
23170
|
}
|
|
22886
23171
|
}
|
|
@@ -22893,7 +23178,7 @@ class OpenCodeServiceLane {
|
|
|
22893
23178
|
}
|
|
22894
23179
|
if (!response2.ok)
|
|
22895
23180
|
throw new OpenCodeHttpError(response2.status, "session resume");
|
|
22896
|
-
const session3 =
|
|
23181
|
+
const session3 = record4(record4(body2)?.data);
|
|
22897
23182
|
if (session3?.id !== resumeId) {
|
|
22898
23183
|
throw new OpenCodeResetRequiredError("OpenCode v2 returned a different resumed session; reset this agent before continuing");
|
|
22899
23184
|
}
|
|
@@ -22914,8 +23199,8 @@ class OpenCodeServiceLane {
|
|
|
22914
23199
|
}, "session create");
|
|
22915
23200
|
if (!response.ok)
|
|
22916
23201
|
throw new OpenCodeHttpError(response.status, "session create");
|
|
22917
|
-
const payload =
|
|
22918
|
-
const session2 =
|
|
23202
|
+
const payload = record4(responseBody);
|
|
23203
|
+
const session2 = record4(payload?.data);
|
|
22919
23204
|
if (typeof session2?.id !== "string" || !/^ses/.test(session2.id)) {
|
|
22920
23205
|
throw new Error("OpenCode v2 did not return a valid session id");
|
|
22921
23206
|
}
|
|
@@ -23072,7 +23357,7 @@ class OpenCodeServiceLane {
|
|
|
23072
23357
|
const { response, body: responseBody } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/history?after=${historyCursor}&limit=${HISTORY_PAGE_LIMIT}`, { method: "GET" }, "session history");
|
|
23073
23358
|
if (!response.ok)
|
|
23074
23359
|
throw new OpenCodeHttpError(response.status, "session history");
|
|
23075
|
-
const body =
|
|
23360
|
+
const body = record4(responseBody);
|
|
23076
23361
|
if (!Array.isArray(body?.data) || typeof body.hasMore !== "boolean") {
|
|
23077
23362
|
throw new OpenCodeProtocolError("OpenCode session history returned an invalid page");
|
|
23078
23363
|
}
|
|
@@ -23090,9 +23375,9 @@ class OpenCodeServiceLane {
|
|
|
23090
23375
|
return run;
|
|
23091
23376
|
}
|
|
23092
23377
|
async handleDurableEvent(value, project) {
|
|
23093
|
-
const event =
|
|
23094
|
-
const durable =
|
|
23095
|
-
const data =
|
|
23378
|
+
const event = record4(value);
|
|
23379
|
+
const durable = record4(event?.durable);
|
|
23380
|
+
const data = record4(event?.data);
|
|
23096
23381
|
if (!event || typeof event.id !== "string" || typeof event.type !== "string" || !durable || durable.aggregateID !== this.sessionId || !Number.isInteger(durable.seq) || Number(durable.seq) < 0 || data?.sessionID !== this.sessionId) {
|
|
23097
23382
|
throw new OpenCodeProtocolError("OpenCode session stream emitted an invalid durable event");
|
|
23098
23383
|
}
|
|
@@ -23182,9 +23467,9 @@ class OpenCodeServiceLane {
|
|
|
23182
23467
|
...!successful ? { message: "OpenCode reported an unsupported final step outcome" } : {}
|
|
23183
23468
|
});
|
|
23184
23469
|
}
|
|
23185
|
-
const tokens =
|
|
23470
|
+
const tokens = record4(data.tokens);
|
|
23186
23471
|
if (tokens && data.finish !== "tool-calls") {
|
|
23187
|
-
const cache =
|
|
23472
|
+
const cache = record4(tokens.cache);
|
|
23188
23473
|
const metric2 = (value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0 ? value2 : null;
|
|
23189
23474
|
const cacheParts = [cache?.read, cache?.write].filter((value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0);
|
|
23190
23475
|
const cacheTotal = cacheParts.reduce((sum, value2) => sum + value2, 0);
|
|
@@ -23211,8 +23496,8 @@ class OpenCodeServiceLane {
|
|
|
23211
23496
|
return seq;
|
|
23212
23497
|
}
|
|
23213
23498
|
async handleLiveEvent(value) {
|
|
23214
|
-
const event =
|
|
23215
|
-
const data =
|
|
23499
|
+
const event = record4(value);
|
|
23500
|
+
const data = record4(event?.data);
|
|
23216
23501
|
if (event?.type !== "permission.v2.asked" || data?.sessionID !== this.sessionId)
|
|
23217
23502
|
return;
|
|
23218
23503
|
if (typeof data.id !== "string" || !/^per/.test(data.id)) {
|
|
@@ -23226,11 +23511,11 @@ class OpenCodeServiceLane {
|
|
|
23226
23511
|
const { response, body: responseBody } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/permission`, { method: "GET" }, "permission list");
|
|
23227
23512
|
if (!response.ok)
|
|
23228
23513
|
throw new OpenCodeHttpError(response.status, "permission list");
|
|
23229
|
-
const body =
|
|
23514
|
+
const body = record4(responseBody);
|
|
23230
23515
|
if (!Array.isArray(body?.data))
|
|
23231
23516
|
throw new OpenCodeProtocolError("OpenCode permission list returned invalid data");
|
|
23232
23517
|
for (const item of body.data) {
|
|
23233
|
-
const permission =
|
|
23518
|
+
const permission = record4(item);
|
|
23234
23519
|
if (permission?.sessionID === this.sessionId && typeof permission.id === "string") {
|
|
23235
23520
|
await this.replyPermission(permission.id);
|
|
23236
23521
|
}
|
|
@@ -23297,8 +23582,8 @@ class OpenCodeServiceLane {
|
|
|
23297
23582
|
}, "prompt admission");
|
|
23298
23583
|
if (!response.ok)
|
|
23299
23584
|
throw new OpenCodeHttpError(response.status, "prompt admission");
|
|
23300
|
-
const body =
|
|
23301
|
-
const admitted =
|
|
23585
|
+
const body = record4(responseBody);
|
|
23586
|
+
const admitted = record4(body?.data);
|
|
23302
23587
|
if (admitted?.id !== messageId || admitted.sessionID !== this.sessionId || admitted.delivery !== delivery || !Number.isInteger(admitted.admittedSeq) || Number(admitted.admittedSeq) < 0) {
|
|
23303
23588
|
throw new OpenCodeProtocolError("OpenCode prompt admission returned an invalid receipt");
|
|
23304
23589
|
}
|
|
@@ -23365,8 +23650,8 @@ class OpenCodeServiceLane {
|
|
|
23365
23650
|
const { response, body: responseBody } = await this.fetchJsonWithTimeout("/api/session/active", { method: "GET" }, "active session query");
|
|
23366
23651
|
if (!response.ok)
|
|
23367
23652
|
throw new OpenCodeHttpError(response.status, "active session query");
|
|
23368
|
-
const body =
|
|
23369
|
-
const active =
|
|
23653
|
+
const body = record4(responseBody);
|
|
23654
|
+
const active = record4(body?.data);
|
|
23370
23655
|
if (!active)
|
|
23371
23656
|
throw new OpenCodeProtocolError("OpenCode active session query returned invalid data");
|
|
23372
23657
|
if (!this.barrierStillCurrent(root, identity, generation))
|
|
@@ -23571,6 +23856,7 @@ function createOpenCodeMessageId() {
|
|
|
23571
23856
|
}
|
|
23572
23857
|
|
|
23573
23858
|
class OpenCodeDriver {
|
|
23859
|
+
outputProbe;
|
|
23574
23860
|
id = "opencode";
|
|
23575
23861
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
23576
23862
|
execution = {
|
|
@@ -23579,8 +23865,19 @@ class OpenCodeDriver {
|
|
|
23579
23865
|
wakeStart: "immediate",
|
|
23580
23866
|
terminalOwnership: "transport_request"
|
|
23581
23867
|
};
|
|
23868
|
+
constructor(outputProbe = probeCommandOutput) {
|
|
23869
|
+
this.outputProbe = outputProbe;
|
|
23870
|
+
}
|
|
23582
23871
|
probe(command) {
|
|
23583
|
-
|
|
23872
|
+
const result = probeCliRuntime("opencode", {}, command);
|
|
23873
|
+
if (result.status !== "healthy")
|
|
23874
|
+
return result;
|
|
23875
|
+
const spec = resolveSpawnSpec("opencode", ["models", "--pure"], command);
|
|
23876
|
+
const output = this.outputProbe(spec.command, spec.args);
|
|
23877
|
+
return {
|
|
23878
|
+
...result,
|
|
23879
|
+
reasoning: output.ok ? parseOpenCodeModelCatalog(output.output) : undefined
|
|
23880
|
+
};
|
|
23584
23881
|
}
|
|
23585
23882
|
beginTurn() {
|
|
23586
23883
|
return createOpenCodeMessageId();
|
|
@@ -23834,6 +24131,7 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
|
|
|
23834
24131
|
|
|
23835
24132
|
// agent-driver/dist/adapters/pi/index.js
|
|
23836
24133
|
var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
|
|
24134
|
+
var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
|
|
23837
24135
|
function isPiSdkPackageJson(pkgJsonPath) {
|
|
23838
24136
|
if (!existsSync3(pkgJsonPath))
|
|
23839
24137
|
return false;
|
|
@@ -23942,6 +24240,8 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
23942
24240
|
|
|
23943
24241
|
class PiDriver {
|
|
23944
24242
|
dependenciesFor;
|
|
24243
|
+
loadSdk;
|
|
24244
|
+
readVersion;
|
|
23945
24245
|
id = "pi";
|
|
23946
24246
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
23947
24247
|
execution = {
|
|
@@ -23952,15 +24252,36 @@ class PiDriver {
|
|
|
23952
24252
|
};
|
|
23953
24253
|
sessionId = null;
|
|
23954
24254
|
terminalSequence = 0;
|
|
23955
|
-
constructor(dependenciesFor = createPiSessionDependencies) {
|
|
24255
|
+
constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
|
|
23956
24256
|
this.dependenciesFor = dependenciesFor;
|
|
24257
|
+
this.loadSdk = loadSdk;
|
|
24258
|
+
this.readVersion = readVersion;
|
|
23957
24259
|
}
|
|
23958
|
-
probe() {
|
|
23959
|
-
const version3 =
|
|
24260
|
+
async probe() {
|
|
24261
|
+
const version3 = this.readVersion();
|
|
23960
24262
|
if (!version3) {
|
|
23961
24263
|
return { status: "unhealthy", lastError: "sdk_not_installed" };
|
|
23962
24264
|
}
|
|
23963
|
-
|
|
24265
|
+
let timer;
|
|
24266
|
+
try {
|
|
24267
|
+
const reasoning = await Promise.race([
|
|
24268
|
+
this.loadSdk().then(async (sdk) => {
|
|
24269
|
+
const authStorage = sdk.AuthStorage.create();
|
|
24270
|
+
const registry2 = sdk.ModelRegistry.create(authStorage);
|
|
24271
|
+
return parsePiModelCatalog(await registry2.getAvailable());
|
|
24272
|
+
}),
|
|
24273
|
+
new Promise((resolve3) => {
|
|
24274
|
+
timer = setTimeout(() => resolve3(undefined), PI_MODEL_PROBE_TIMEOUT_MS);
|
|
24275
|
+
timer.unref?.();
|
|
24276
|
+
})
|
|
24277
|
+
]);
|
|
24278
|
+
return { status: "healthy", version: version3, reasoning };
|
|
24279
|
+
} catch {
|
|
24280
|
+
return { status: "healthy", version: version3, reasoning: undefined };
|
|
24281
|
+
} finally {
|
|
24282
|
+
if (timer)
|
|
24283
|
+
clearTimeout(timer);
|
|
24284
|
+
}
|
|
23964
24285
|
}
|
|
23965
24286
|
async openLane(ctx) {
|
|
23966
24287
|
const deps = this.dependenciesFor(ctx);
|
|
@@ -25868,14 +26189,14 @@ function createLogger2(options = {}) {
|
|
|
25868
26189
|
`));
|
|
25869
26190
|
const err = options.err ?? ((line) => process.stderr.write(line + `
|
|
25870
26191
|
`));
|
|
25871
|
-
const
|
|
26192
|
+
const record5 = options.record;
|
|
25872
26193
|
const emit = (level, message2, data) => {
|
|
25873
26194
|
if (LEVEL_RANK[level] < minRank)
|
|
25874
26195
|
return;
|
|
25875
26196
|
const time3 = now();
|
|
25876
26197
|
const line = `${time3} ${header} ${level.toUpperCase().padEnd(5)} ${message2}${formatData(data)}`;
|
|
25877
26198
|
try {
|
|
25878
|
-
|
|
26199
|
+
record5?.({ time: time3, header, level, message: message2, fields: recordFields(data) });
|
|
25879
26200
|
} catch {}
|
|
25880
26201
|
(level === "warn" || level === "error" ? err : out)(line);
|
|
25881
26202
|
};
|
|
@@ -27019,20 +27340,20 @@ function parseLocalMessageReminderBody(body, agentId) {
|
|
|
27019
27340
|
}
|
|
27020
27341
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
27021
27342
|
return null;
|
|
27022
|
-
const
|
|
27023
|
-
if (Object.keys(
|
|
27343
|
+
const record5 = value;
|
|
27344
|
+
if (Object.keys(record5).sort().join(",") !== "channel,remindAfterMs,sentSeq")
|
|
27024
27345
|
return null;
|
|
27025
|
-
if (typeof
|
|
27346
|
+
if (typeof record5.channel !== "string" || !isCanonicalChannelScope(record5.channel))
|
|
27026
27347
|
return null;
|
|
27027
|
-
if (!Number.isSafeInteger(
|
|
27348
|
+
if (!Number.isSafeInteger(record5.sentSeq) || record5.sentSeq < 1)
|
|
27028
27349
|
return null;
|
|
27029
|
-
if (!Number.isSafeInteger(
|
|
27350
|
+
if (!Number.isSafeInteger(record5.remindAfterMs) || record5.remindAfterMs !== 0 && record5.remindAfterMs < LOCAL_MESSAGE_REMINDER_MIN_MS || record5.remindAfterMs > LOCAL_MESSAGE_REMINDER_MAX_MS)
|
|
27030
27351
|
return null;
|
|
27031
27352
|
return {
|
|
27032
27353
|
agentId,
|
|
27033
|
-
channel:
|
|
27034
|
-
sentSeq:
|
|
27035
|
-
remindAfterMs:
|
|
27354
|
+
channel: record5.channel,
|
|
27355
|
+
sentSeq: record5.sentSeq,
|
|
27356
|
+
remindAfterMs: record5.remindAfterMs
|
|
27036
27357
|
};
|
|
27037
27358
|
}
|
|
27038
27359
|
async function handleLocalMessageReminder(req, res, agentId, onArm) {
|
|
@@ -27378,13 +27699,13 @@ function reduceManager(state, event) {
|
|
|
27378
27699
|
const existing = state.agents[event.agentId];
|
|
27379
27700
|
if (!existing || existing.execution.sessionInstanceId !== event.sessionInstanceId)
|
|
27380
27701
|
return { state, effects: [] };
|
|
27381
|
-
const
|
|
27382
|
-
if (!
|
|
27702
|
+
const record5 = existing.pendingAdmissions.find((entry) => entry.sessionInstanceId === event.sessionInstanceId && entry.commandId === event.commandId);
|
|
27703
|
+
if (!record5)
|
|
27383
27704
|
return { state, effects: [] };
|
|
27384
27705
|
const agent2 = clone2(existing);
|
|
27385
27706
|
agent2.pendingAdmissions = agent2.pendingAdmissions.filter((entry) => entry.sessionInstanceId !== event.sessionInstanceId || entry.commandId !== event.commandId);
|
|
27386
27707
|
syncExecutionProjection(agent2);
|
|
27387
|
-
return commit(state, agent2, event.outcome === "failed" ? recoveryEffects(agent2, [
|
|
27708
|
+
return commit(state, agent2, event.outcome === "failed" ? recoveryEffects(agent2, [record5]) : []);
|
|
27388
27709
|
}
|
|
27389
27710
|
case "admission_acknowledged": {
|
|
27390
27711
|
const existing = state.agents[event.agentId];
|
|
@@ -27902,11 +28223,11 @@ function syncExecutionProjection(agent2) {
|
|
|
27902
28223
|
agent2.lastDeliverAt = agent2.pendingAdmissions.length > 0 ? Math.max(...agent2.pendingAdmissions.map((entry) => entry.admittedAt)) : null;
|
|
27903
28224
|
}
|
|
27904
28225
|
function recoveryEffects(agent2, records) {
|
|
27905
|
-
return records.filter((
|
|
28226
|
+
return records.filter((record5) => record5.requeueOnFailure).map((record5) => ({
|
|
27906
28227
|
type: "requeue_delivery",
|
|
27907
28228
|
agentId: agent2.agentId,
|
|
27908
|
-
message:
|
|
27909
|
-
mode:
|
|
28229
|
+
message: record5.exactAgentMsg,
|
|
28230
|
+
mode: record5.mode
|
|
27910
28231
|
}));
|
|
27911
28232
|
}
|
|
27912
28233
|
function commit(state, agent2, effects) {
|
|
@@ -28052,8 +28373,8 @@ async function readClaudeQuota(options) {
|
|
|
28052
28373
|
if (!body || typeof body !== "object") {
|
|
28053
28374
|
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28054
28375
|
}
|
|
28055
|
-
const
|
|
28056
|
-
const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key,
|
|
28376
|
+
const record5 = body;
|
|
28377
|
+
const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key, record5[key])).filter((limit) => limit !== null);
|
|
28057
28378
|
if (limits.length === 0) {
|
|
28058
28379
|
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28059
28380
|
}
|
|
@@ -30228,11 +30549,10 @@ class AgentRouter {
|
|
|
30228
30549
|
return;
|
|
30229
30550
|
if (existing.status === "healthy" && !existing.lastError && !existing.lastErrorAt)
|
|
30230
30551
|
return;
|
|
30231
|
-
|
|
30232
|
-
|
|
30233
|
-
|
|
30234
|
-
|
|
30235
|
-
});
|
|
30552
|
+
const healthy = { ...existing, status: "healthy" };
|
|
30553
|
+
delete healthy.lastError;
|
|
30554
|
+
delete healthy.lastErrorAt;
|
|
30555
|
+
this.runtimes.set(id, healthy);
|
|
30236
30556
|
this.log.info("runtime marked healthy again", { runtimeId: id });
|
|
30237
30557
|
this.scheduleReadyFrameResend();
|
|
30238
30558
|
}
|
|
@@ -31813,15 +32133,15 @@ class MessageReminderScheduler {
|
|
|
31813
32133
|
const startedAt = this.now();
|
|
31814
32134
|
const dueAt = startedAt + input.remindAfterMs;
|
|
31815
32135
|
const sentRef = `${input.channel}#${input.sentSeq}`;
|
|
31816
|
-
const
|
|
32136
|
+
const record5 = {
|
|
31817
32137
|
...input,
|
|
31818
32138
|
sentRef,
|
|
31819
32139
|
startedAt,
|
|
31820
32140
|
dueAt,
|
|
31821
32141
|
timer: undefined
|
|
31822
32142
|
};
|
|
31823
|
-
|
|
31824
|
-
if (this.reminders.get(key) !==
|
|
32143
|
+
record5.timer = this.setTimer(() => {
|
|
32144
|
+
if (this.reminders.get(key) !== record5)
|
|
31825
32145
|
return;
|
|
31826
32146
|
this.reminders.delete(key);
|
|
31827
32147
|
try {
|
|
@@ -31832,8 +32152,8 @@ class MessageReminderScheduler {
|
|
|
31832
32152
|
Promise.resolve(delivery).catch(() => {});
|
|
31833
32153
|
} catch {}
|
|
31834
32154
|
}, input.remindAfterMs);
|
|
31835
|
-
|
|
31836
|
-
this.reminders.set(key,
|
|
32155
|
+
record5.timer.unref?.();
|
|
32156
|
+
this.reminders.set(key, record5);
|
|
31837
32157
|
return { armed: true, dueAt };
|
|
31838
32158
|
}
|
|
31839
32159
|
observe(agentId, channel2, latestSeq) {
|
|
@@ -34128,11 +34448,11 @@ async function strictOutcome(response, allowed) {
|
|
|
34128
34448
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
34129
34449
|
return { kind: "retryable" };
|
|
34130
34450
|
}
|
|
34131
|
-
const
|
|
34132
|
-
if (Object.keys(
|
|
34451
|
+
const record5 = value;
|
|
34452
|
+
if (Object.keys(record5).length !== 2 || record5.kind !== "terminal") {
|
|
34133
34453
|
return { kind: "retryable" };
|
|
34134
34454
|
}
|
|
34135
|
-
const status =
|
|
34455
|
+
const status = record5.status;
|
|
34136
34456
|
if (status !== "uploaded" && status !== "failed" || allowed[status] !== response.status) {
|
|
34137
34457
|
return { kind: "retryable" };
|
|
34138
34458
|
}
|
|
@@ -34626,7 +34946,7 @@ function createDaemonProcessLogger(daemonDir, foreground) {
|
|
|
34626
34946
|
`) : quiet,
|
|
34627
34947
|
err: foreground ? (line2) => process.stderr.write(line2 + `
|
|
34628
34948
|
`) : quiet,
|
|
34629
|
-
record: (
|
|
34949
|
+
record: (record5) => sink.write(JSON.stringify(record5))
|
|
34630
34950
|
});
|
|
34631
34951
|
return { logger, logPath, sink };
|
|
34632
34952
|
}
|
|
@@ -35369,18 +35689,18 @@ function readCredentialFile(filePath) {
|
|
|
35369
35689
|
} catch {}
|
|
35370
35690
|
return null;
|
|
35371
35691
|
}
|
|
35372
|
-
function writeCredentialFile(filePath,
|
|
35373
|
-
writePrivateJsonAtomic2(filePath,
|
|
35692
|
+
function writeCredentialFile(filePath, record5) {
|
|
35693
|
+
writePrivateJsonAtomic2(filePath, record5);
|
|
35374
35694
|
}
|
|
35375
35695
|
function readDaemonLaunchRecord(baseDir, machineId) {
|
|
35376
|
-
const
|
|
35377
|
-
if (!
|
|
35696
|
+
const record5 = readCredentialFile(credentialFilePathByMachineId(baseDir, machineId));
|
|
35697
|
+
if (!record5 || !("schemaVersion" in record5) || record5.schemaVersion !== 1 || !parseReleaseVersion(record5.daemonVersion)) {
|
|
35378
35698
|
throw new Error("daemon launch record is missing or requires a manual start upgrade");
|
|
35379
35699
|
}
|
|
35380
|
-
validateMachineId(
|
|
35381
|
-
if (
|
|
35700
|
+
validateMachineId(record5.machineId);
|
|
35701
|
+
if (record5.machineId !== machineId)
|
|
35382
35702
|
throw new Error("daemon launch record machine mismatch");
|
|
35383
|
-
return
|
|
35703
|
+
return record5;
|
|
35384
35704
|
}
|
|
35385
35705
|
function findExistingCredentialForBearer(baseDir, bearer) {
|
|
35386
35706
|
const dir = daemonsDir(baseDir);
|
|
@@ -35545,23 +35865,23 @@ async function daemonResume(opts) {
|
|
|
35545
35865
|
if (!/^[A-Za-z0-9_-]{16,128}$/.test(opts.requestId))
|
|
35546
35866
|
throw new Error("invalid replacement request id");
|
|
35547
35867
|
const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
|
|
35548
|
-
const
|
|
35868
|
+
const record5 = readDaemonLaunchRecord(baseDir, opts.id);
|
|
35549
35869
|
if (false) {}
|
|
35550
35870
|
await daemonStart({
|
|
35551
|
-
machineKey:
|
|
35552
|
-
serverUrl:
|
|
35553
|
-
wsUrl:
|
|
35871
|
+
machineKey: record5.credential,
|
|
35872
|
+
serverUrl: record5.serverUrl,
|
|
35873
|
+
wsUrl: record5.wsUrl,
|
|
35554
35874
|
baseDir,
|
|
35555
35875
|
resumeRequestId: opts.requestId
|
|
35556
35876
|
});
|
|
35557
35877
|
}
|
|
35558
35878
|
async function daemonStartById(opts) {
|
|
35559
35879
|
const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
|
|
35560
|
-
const
|
|
35880
|
+
const record5 = readDaemonLaunchRecord(baseDir, opts.id);
|
|
35561
35881
|
await daemonStart({
|
|
35562
|
-
machineKey:
|
|
35563
|
-
serverUrl:
|
|
35564
|
-
wsUrl:
|
|
35882
|
+
machineKey: record5.credential,
|
|
35883
|
+
serverUrl: record5.serverUrl,
|
|
35884
|
+
wsUrl: record5.wsUrl,
|
|
35565
35885
|
baseDir,
|
|
35566
35886
|
foreground: opts.foreground
|
|
35567
35887
|
});
|