lody 0.102.0 → 0.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,7 +51,9 @@ const DEEPSEEK_HARNESS_AGENT_PRESETS = [
51
51
  ];
52
52
  const ACP_EXTENSION_DSH_VERSION = "0.2.0";
53
53
  const DEEPSEEK_HARNESS_VERSION = "0.1.5-rc.2";
54
- const ACP_EXTENSION_DSH_PROFILE_REVISION = "v13";
54
+ const DEEPSEEK_HARNESS_PI_AI_VERSION = "0.85.1";
55
+ const DEEPSEEK_HARNESS_SCHEMASTERY_VERSION = "3.18.2";
56
+ const ACP_EXTENSION_DSH_PROFILE_REVISION = "v14";
55
57
  const ACP_EXTENSION_DSH_SESSION_ROOT_ENV = "ACP_EXTENSION_DSH_SESSION_ROOT";
56
58
  const ACP_EXTENSION_DSH_QUERY_PATH_ENV = "ACP_EXTENSION_DSH_QUERY_PATH";
57
59
  const DEEPSEEK_HARNESS_DEFAULT_SESSION_COMPRESSION = "zstd";
@@ -308,7 +310,11 @@ const DEEPSEEK_HARNESS_CORDIS_PACKAGE_VERSIONS = {
308
310
  "@deepseek-ai/cordis-plugin-timer": "1.1.4"
309
311
  };
310
312
  function createDeepSeekHarnessNpxSpecifiers(versions = DEEPSEEK_HARNESS_CORDIS_PACKAGE_VERSIONS) {
311
- return DEEPSEEK_HARNESS_NPX_PACKAGES.map((packageName) => `${packageName}@${versions[packageName] ?? DEEPSEEK_HARNESS_VERSION}`);
313
+ return [
314
+ ...DEEPSEEK_HARNESS_NPX_PACKAGES.map((packageName) => `${packageName}@${versions[packageName] ?? DEEPSEEK_HARNESS_VERSION}`),
315
+ `@earendil-works/pi-ai@${DEEPSEEK_HARNESS_PI_AI_VERSION}`,
316
+ `@deepseek-ai/schemastery@${DEEPSEEK_HARNESS_SCHEMASTERY_VERSION}`
317
+ ];
312
318
  }
313
319
  function toAdapterModuleSpecifier(adapterPath, windows = process.platform === "win32") {
314
320
  if (adapterPath.startsWith("file:"))
@@ -369,6 +375,14 @@ function createDeepSeekHarnessProfileFiles(config) {
369
375
  provider: ${JSON.stringify(provider)}
370
376
  model: ${JSON.stringify(model)}
371
377
 
378
+ # Dormant until llm-pi-ai.providers in settings.yaml declares a route. The
379
+ # upstream adapter owns profile validation, route lifecycle, and credentials.
380
+ - id: llm-pi-ai
381
+ name: '@deepseek-ai/dsh-llm-pi-ai'
382
+ inject: [settings]
383
+ config:
384
+ providers: {}
385
+
372
386
  # Preserve the product's three permission modes with client-facing labels.
373
387
  - id: permission
374
388
  config:
@@ -4929,4 +4943,4 @@ export {
4929
4943
  DEEPSEEK_HARNESS_DEFAULT_MODEL as q,
4930
4944
  DEEPSEEK_HARNESS_PROVIDER as r
4931
4945
  };
4932
- //# sourceMappingURL=acp-Bsd2Lmd6.js.map
4946
+ //# sourceMappingURL=acp-BzvviK-N.js.map
@@ -28,7 +28,7 @@ import "node:fs/promises";
28
28
  import "node:zlib";
29
29
  import "child_process";
30
30
  import "./plan-mode-D0D5cnMs.js";
31
- import "./acp-Bsd2Lmd6.js";
31
+ import "./acp-BzvviK-N.js";
32
32
  import "node:url";
33
33
  import "./subagent-events-BJ9JwZva.js";
34
34
  import "./loro_wasm_bg-DIxpLA2J.js";
@@ -94,4 +94,4 @@ async function executeDaemonSessionTool(context, name, args) {
94
94
  export {
95
95
  executeDaemonSessionTool
96
96
  };
97
- //# sourceMappingURL=daemon-session-tools-BeXk1A1E.js.map
97
+ //# sourceMappingURL=daemon-session-tools-DESvdAeY.js.map
@@ -27455,7 +27455,7 @@ var package_default = {
27455
27455
  },
27456
27456
  dependencies: {
27457
27457
  "@agentclientprotocol/sdk": "^1.4.0",
27458
- "@openai/codex": "^0.156.0",
27458
+ "@openai/codex": "^0.159.2",
27459
27459
  "acp-extension-core": "0.1.9",
27460
27460
  diff: "^9.0.0",
27461
27461
  open: "^11.0.1",
@@ -35224,4 +35224,4 @@ function startAcpServer() {
35224
35224
  }
35225
35225
  createCodexAcpApp({ name: package_default.name, createAgent }).connect(acpJsonStream);
35226
35226
  }
35227
- //# sourceMappingURL=index-C0n6fro1.js.map
35227
+ //# sourceMappingURL=index-DEdPzgH7.js.map
@@ -28,7 +28,7 @@ import "node:util";
28
28
  import "node:zlib";
29
29
  import "child_process";
30
30
  import "./plan-mode-D0D5cnMs.js";
31
- import "./acp-Bsd2Lmd6.js";
31
+ import "./acp-BzvviK-N.js";
32
32
  import "node:url";
33
33
  import "./subagent-events-BJ9JwZva.js";
34
34
  import "./loro_wasm_bg-DIxpLA2J.js";
@@ -68,7 +68,7 @@ import "node:timers/promises";
68
68
  import "node:module";
69
69
  import "node:v8";
70
70
  import "http2";
71
- const reviewViewerVersion = "0.102.0";
71
+ const reviewViewerVersion = "0.103.0";
72
72
  const reviewViewerSha256 = "d1ba5702aa0bd441b40492bd916d6412f8b970e92683f7073878a36efbdb0649";
73
73
  const reviewViewerFileName = "standalone.html";
74
74
  const DEFAULT_CDN_BASES = ["https://cdn.jsdelivr.net/npm", "https://unpkg.com"];
@@ -143,4 +143,4 @@ async function resolveReviewViewerTemplate() {
143
143
  export {
144
144
  resolveReviewViewerTemplate
145
145
  };
146
- //# sourceMappingURL=review-viewer-B6wZ9fN1.js.map
146
+ //# sourceMappingURL=review-viewer-BZiXmQnJ.js.map
package/dist/codex-acp.js CHANGED
@@ -2,5 +2,5 @@ if (!process.env.CODEX_PATH?.trim()) {
2
2
  console.error("CODEX_PATH is required for the bundled Codex ACP adapter.");
3
3
  process.exit(1);
4
4
  }
5
- await import("./chunks/index-C0n6fro1.js");
5
+ await import("./chunks/index-DEdPzgH7.js");
6
6
  //# sourceMappingURL=codex-acp.js.map
@@ -3,7 +3,7 @@ import { o as object, s as string, b as boolean, c as array, l as literal, u as
3
3
  import { S as SessionUsageAccumulator, L as LODY_EXTENSION_METHODS, e as supportsLodySubagentEvents, d as LODY_SUBAGENT_EVENT_METHOD } from "./chunks/subagent-events-BJ9JwZva.js";
4
4
  import { randomUUID, createHash } from "node:crypto";
5
5
  import { Readable, Writable } from "node:stream";
6
- import { j as DEEPSEEK_HARNESS_BASE_URL_ENV, l as DEEPSEEK_HARNESS_API_KEY_ENV, n as ndJsonStream, o as AgentSideConnection, a as DEEPSEEK_HARNESS_AGENT_PRESETS, R as RequestError, p as ACP_EXTENSION_DSH_VERSION, P as PROTOCOL_VERSION, q as DEEPSEEK_HARNESS_DEFAULT_MODEL, r as DEEPSEEK_HARNESS_PROVIDER } from "./chunks/acp-Bsd2Lmd6.js";
6
+ import { j as DEEPSEEK_HARNESS_BASE_URL_ENV, l as DEEPSEEK_HARNESS_API_KEY_ENV, n as ndJsonStream, o as AgentSideConnection, a as DEEPSEEK_HARNESS_AGENT_PRESETS, R as RequestError, p as ACP_EXTENSION_DSH_VERSION, P as PROTOCOL_VERSION, q as DEEPSEEK_HARNESS_DEFAULT_MODEL, r as DEEPSEEK_HARNESS_PROVIDER } from "./chunks/acp-BzvviK-N.js";
7
7
  import { c as createPlanModeConfigOption, L as LODY_PLAN_MODE_CONFIG_ID } from "./chunks/plan-mode-D0D5cnMs.js";
8
8
  import { L as LodySubagentEmitter } from "./chunks/subagent-emitter-BsTuVPDw.js";
9
9
  import "node:url";
@@ -432,6 +432,7 @@ const MODEL_DISCOVERY_TIMEOUT_MS = 15e3;
432
432
  const MODEL_DISCOVERY_MAX_BYTES = 1024 * 1024;
433
433
  const MODEL_DISCOVERY_MAX_MODELS = 1e3;
434
434
  const MODEL_ID_MAX_LENGTH = 512;
435
+ const ACP_MODEL_ID_PREFIX = "dsh-route:";
435
436
  const INVALID_MCP_SERVER_NAME_CHARS = /[^A-Za-z0-9_-]/gu;
436
437
  const IMAGE_MEDIA_TYPES = [
437
438
  "image/png",
@@ -470,33 +471,60 @@ function resolveAdapterConfig(config) {
470
471
  ...config?.stream ? { stream: config.stream } : {}
471
472
  };
472
473
  }
473
- async function loadHarnessModels(llm, provider, configuredModel, endpoint) {
474
- const listed = endpoint ? (await discoverDeepSeekModelIds(endpoint.baseUrl, endpoint.apiKey)).map((id) => ({
475
- provider,
476
- id
477
- })) : await llm.listModels(provider);
478
- const modelIds = [];
479
- const ids = /* @__PURE__ */ new Set();
480
- for (const model of listed) {
481
- if (model.provider !== provider || !model.id.trim())
482
- continue;
483
- if (ids.has(model.id)) {
484
- throw new Error(`acp-extension-dsh: duplicate model ${JSON.stringify(model.id)} for provider ${JSON.stringify(provider)}`);
474
+ async function loadHarnessModels(llm, defaultProvider, configuredModel, endpoint) {
475
+ const providers = llm.listProviders?.() ?? [{ id: defaultProvider, name: defaultProvider }];
476
+ if (!providers.some(({ id }) => id === defaultProvider)) {
477
+ throw new Error(`configured provider ${JSON.stringify(defaultProvider)} is unavailable`);
478
+ }
479
+ const identities = [];
480
+ for (const { id: provider } of providers) {
481
+ const listed = endpoint && provider === defaultProvider ? (await discoverDeepSeekModelIds(endpoint.baseUrl, endpoint.apiKey)).map((id) => ({
482
+ provider,
483
+ id
484
+ })) : await llm.listModels(provider);
485
+ const ids = /* @__PURE__ */ new Set();
486
+ for (const model of listed) {
487
+ if (model.provider !== provider || !model.id.trim())
488
+ continue;
489
+ if (ids.has(model.id)) {
490
+ throw new Error(`acp-extension-dsh: duplicate model ${JSON.stringify(model.id)} for provider ${JSON.stringify(provider)}`);
491
+ }
492
+ ids.add(model.id);
493
+ identities.push({ provider, model: model.id });
494
+ }
495
+ if (endpoint && provider === defaultProvider && ids.size === 0) {
496
+ throw new Error("the endpoint returned no usable models");
497
+ }
498
+ if (provider === defaultProvider && !endpoint && !ids.has(configuredModel)) {
499
+ identities.unshift({ provider, model: configuredModel });
485
500
  }
486
- ids.add(model.id);
487
- modelIds.push(model.id);
488
501
  }
489
- if (endpoint && modelIds.length === 0) {
502
+ const initialSelection = endpoint ? identities.find(({ provider }) => provider === defaultProvider) : { provider: defaultProvider, model: configuredModel };
503
+ if (!initialSelection)
490
504
  throw new Error("the endpoint returned no usable models");
491
- }
492
- if (!endpoint && !ids.has(configuredModel))
493
- modelIds.unshift(configuredModel);
494
- const initialModel = endpoint ? modelIds[0] : configuredModel;
495
505
  return {
496
- models: await Promise.all(modelIds.map((modelId) => resolveHarnessModel(llm, provider, modelId))),
497
- initialModel
506
+ models: await Promise.all(identities.map(({ provider, model }) => resolveHarnessModel(llm, provider, model))),
507
+ initialSelection
498
508
  };
499
509
  }
510
+ function encodeAcpModelId(provider, model) {
511
+ return `${ACP_MODEL_ID_PREFIX}${Buffer.from(JSON.stringify([provider, model])).toString("base64url")}`;
512
+ }
513
+ function decodeAcpModelId(value, legacyProvider) {
514
+ if (!value.startsWith(ACP_MODEL_ID_PREFIX))
515
+ return { provider: legacyProvider, model: value };
516
+ try {
517
+ const decoded = JSON.parse(Buffer.from(value.slice(ACP_MODEL_ID_PREFIX.length), "base64url").toString("utf8"));
518
+ if (Array.isArray(decoded) && decoded.length === 2 && decoded.every((part) => typeof part === "string" && part.trim())) {
519
+ return { provider: decoded[0], model: decoded[1] };
520
+ }
521
+ } catch {
522
+ }
523
+ throw invalidParams("model route id is invalid");
524
+ }
525
+ function selectedModel(record2) {
526
+ return record2.models.find((candidate) => candidate.provider === record2.selection.current.provider && candidate.id === record2.selection.current.model);
527
+ }
500
528
  function modelDiscoveryUrl(baseUrl) {
501
529
  const url = new URL(baseUrl);
502
530
  url.pathname = `${url.pathname.replace(/\/+$/u, "")}/models`;
@@ -727,13 +755,13 @@ function configOptions(record2) {
727
755
  {
728
756
  id: MODEL_CONFIG_ID,
729
757
  name: "Model",
730
- description: "DeepSeek model used for the session",
758
+ description: "Provider route and model used for the session",
731
759
  category: "model",
732
760
  type: "select",
733
- currentValue: record2.selection.current.model,
761
+ currentValue: encodeAcpModelId(record2.selection.current.provider, record2.selection.current.model),
734
762
  options: record2.models.map((model2) => ({
735
- value: model2.id,
736
- name: model2.name,
763
+ value: encodeAcpModelId(model2.provider, model2.id),
764
+ name: `${model2.name} (${model2.provider})`,
737
765
  description: model2.description ?? null
738
766
  }))
739
767
  }
@@ -743,7 +771,7 @@ function configOptions(record2) {
743
771
  const state = plan.get(record2.agent);
744
772
  options.push(createPlanModeConfigOption(state.pending ?? state.active));
745
773
  }
746
- const model = record2.models.find((candidate) => candidate.id === record2.selection.current.model);
774
+ const model = selectedModel(record2);
747
775
  if (model?.reasoning && record2.selection.current.reasoningEffort) {
748
776
  options.push({
749
777
  id: REASONING_EFFORT_CONFIG_ID,
@@ -763,16 +791,16 @@ function configOptions(record2) {
763
791
  }
764
792
  function legacyModels(record2) {
765
793
  return {
766
- currentModelId: record2.selection.current.model,
794
+ currentModelId: encodeAcpModelId(record2.selection.current.provider, record2.selection.current.model),
767
795
  availableModels: record2.models.flatMap((model) => [
768
796
  {
769
- modelId: model.id,
770
- name: model.name,
797
+ modelId: encodeAcpModelId(model.provider, model.id),
798
+ name: `${model.name} (${model.provider})`,
771
799
  description: model.description ?? null
772
800
  },
773
801
  ...model.reasoning?.efforts.map((effort) => ({
774
- modelId: `${model.id}[${effort.id}]`,
775
- name: `${model.name} (${effort.name})`,
802
+ modelId: `${encodeAcpModelId(model.provider, model.id)}[${effort.id}]`,
803
+ name: `${model.name} (${model.provider}, ${effort.name})`,
776
804
  description: model.description ?? null
777
805
  })) ?? []
778
806
  ])
@@ -1440,26 +1468,27 @@ function apply(ctx, rawConfig) {
1440
1468
  throw invalidParams(`failed to select agent preset ${JSON.stringify(value)}: ${errorChain(error)}`);
1441
1469
  });
1442
1470
  } else if (params.configId === MODEL_CONFIG_ID) {
1443
- return resolveHarnessModel(llm, record2.selection.current.provider, value).then((model) => {
1444
- const index = record2.models.findIndex((candidate) => candidate.id === value);
1471
+ const selected = decodeAcpModelId(value, record2.selection.current.provider);
1472
+ return resolveHarnessModel(llm, selected.provider, selected.model).then((model) => {
1473
+ const index = record2.models.findIndex((candidate) => candidate.provider === selected.provider && candidate.id === selected.model);
1445
1474
  if (index === -1)
1446
1475
  record2.models.push(model);
1447
1476
  else
1448
1477
  record2.models[index] = model;
1449
1478
  const reasoningEffort = resolveReasoningEffort(model, record2.selection.current.reasoningEffort && model.reasoning?.efforts.some((effort) => effort.id === record2.selection.current.reasoningEffort) ? record2.selection.current.reasoningEffort : void 0);
1450
1479
  record2.selection.current = {
1451
- provider: record2.selection.current.provider,
1452
- model: value,
1480
+ provider: selected.provider,
1481
+ model: selected.model,
1453
1482
  ...reasoningEffort ? { reasoningEffort } : {}
1454
1483
  };
1455
1484
  return { configOptions: configOptions(record2) };
1456
1485
  }).catch((error) => {
1457
1486
  if (error instanceof RequestError)
1458
1487
  throw error;
1459
- throw invalidParams(`failed to resolve model ${JSON.stringify(value)}: ${errorChain(error)}`);
1488
+ throw invalidParams(`failed to resolve model route ${JSON.stringify(selected.provider)} / ${JSON.stringify(selected.model)}: ${errorChain(error)}`);
1460
1489
  });
1461
1490
  } else if (params.configId === REASONING_EFFORT_CONFIG_ID) {
1462
- const model = record2.models.find((candidate) => candidate.id === record2.selection.current.model);
1491
+ const model = selectedModel(record2);
1463
1492
  if (!model)
1464
1493
  throw internalError("selected model metadata is unavailable");
1465
1494
  const reasoningEffort = resolveReasoningEffort(model, value);
@@ -1519,17 +1548,17 @@ function apply(ctx, rawConfig) {
1519
1548
  } catch (error) {
1520
1549
  throw internalError(`failed to discover models: ${errorChain(error)}`);
1521
1550
  }
1522
- const { models, initialModel: initialModelId } = catalog;
1551
+ const { models, initialSelection } = catalog;
1523
1552
  const sessionId = randomUUID();
1524
1553
  const questions = new UserQuestionBridge(sessionId, (request) => conn.unstable_createElicitation(request), () => questionCapabilities);
1525
- const initialModel = models.find((model) => model.id === initialModelId);
1554
+ const initialModel = models.find((model) => model.provider === initialSelection.provider && model.id === initialSelection.model);
1526
1555
  if (!initialModel)
1527
1556
  throw internalError("initial model metadata is unavailable");
1528
1557
  const reasoningEffort = resolveReasoningEffort(initialModel, config.reasoningEffort);
1529
1558
  const selection = {
1530
1559
  current: {
1531
- provider: config.provider,
1532
- model: initialModelId,
1560
+ provider: initialSelection.provider,
1561
+ model: initialSelection.model,
1533
1562
  ...reasoningEffort ? { reasoningEffort } : {}
1534
1563
  }
1535
1564
  };
@@ -1545,7 +1574,10 @@ function apply(ctx, rawConfig) {
1545
1574
  handle = await ctx.agents.create({
1546
1575
  sessionId,
1547
1576
  meta: { cwd: params.cwd, agentPreset: requestedPreset },
1548
- agentOptions: { provider: config.provider, model: initialModelId },
1577
+ agentOptions: {
1578
+ provider: initialSelection.provider,
1579
+ model: initialSelection.model
1580
+ },
1549
1581
  setup: async (agentContext) => {
1550
1582
  if (subagentEvents && !carrierKeyOf) {
1551
1583
  const scope = await agentContext.loader.import("@deepseek-ai/dsh-scope");
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ import fs__default$2, { readFile, readdir, rm, mkdir as mkdir$1, mkdtemp, chmod,
37
37
  import zlib__default, { gzip, gunzip as gunzip$1, gunzipSync, brotliDecompressSync } from "node:zlib";
38
38
  import require$$1$8, { exec, execFile as execFile$1, spawn as spawn$2 } from "child_process";
39
39
  import { c as createPlanModeConfigOption, L as LODY_PLAN_MODE_CONFIG_ID } from "./chunks/plan-mode-D0D5cnMs.js";
40
- import { D as DEEPSEEK_HARNESS_PERMISSION_MODES, a as DEEPSEEK_HARNESS_AGENT_PRESETS, A as ACP_EXTENSION_DSH_CAPABILITY_SOURCE_VERSION, c as createDeepSeekHarnessProfileFiles, b as DEEPSEEK_HARNESS_PROFILE_NAME, d as DEEPSEEK_HARNESS_PROFILE_FILENAMES, e as ACP_EXTENSION_DSH_QUERY_PATH_ENV, f as ACP_EXTENSION_DSH_SESSION_ROOT_ENV, g as createDeepSeekHarnessNpxSpecifiers, h as DEEPSEEK_HARNESS_DEFAULT_SESSION_COMPRESSION, i as DEEPSEEK_HARNESS_VERSION, j as DEEPSEEK_HARNESS_BASE_URL_ENV, R as RequestError$1, C as ClientSideConnection, P as PROTOCOL_VERSION, n as ndJsonStream, k as client$2, m as methods$1 } from "./chunks/acp-Bsd2Lmd6.js";
40
+ import { D as DEEPSEEK_HARNESS_PERMISSION_MODES, a as DEEPSEEK_HARNESS_AGENT_PRESETS, A as ACP_EXTENSION_DSH_CAPABILITY_SOURCE_VERSION, c as createDeepSeekHarnessProfileFiles, b as DEEPSEEK_HARNESS_PROFILE_NAME, d as DEEPSEEK_HARNESS_PROFILE_FILENAMES, e as ACP_EXTENSION_DSH_QUERY_PATH_ENV, f as ACP_EXTENSION_DSH_SESSION_ROOT_ENV, g as createDeepSeekHarnessNpxSpecifiers, h as DEEPSEEK_HARNESS_DEFAULT_SESSION_COMPRESSION, i as DEEPSEEK_HARNESS_VERSION, j as DEEPSEEK_HARNESS_BASE_URL_ENV, R as RequestError$1, C as ClientSideConnection, P as PROTOCOL_VERSION, n as ndJsonStream, k as client$2, m as methods$1 } from "./chunks/acp-BzvviK-N.js";
41
41
  import { i as isLodySubagentProgress, a as isLodySubagentSnapshot, b as isLodySubagentEvent, c as isLodySubagentOutput, L as LODY_EXTENSION_METHODS, M as MAX_USAGE_SCOPE_ID_LENGTH, n as normalizeLodyExtensionMethod, d as LODY_SUBAGENT_EVENT_METHOD } from "./chunks/subagent-events-BJ9JwZva.js";
42
42
  import { i as imports, _ as __wbg_set_wasm$1, r as rawWasm, L as LoroDoc, E as EphemeralStoreWasm, U as UndoManager, a as isValidContainerId, c as callPendingEvents$3, b as LoroTree, d as LoroText, e as LoroMovableList, f as LoroList, g as LoroMap, V as VersionVector, h as __vite__initWasm, j as decodeImportBlobMeta } from "./chunks/loro_wasm_bg-DIxpLA2J.js";
43
43
  import { performance as performance$1 } from "perf_hooks";
@@ -4317,7 +4317,7 @@ function resolvePlatformKind(raw2) {
4317
4317
  }
4318
4318
  const name$3 = "lody";
4319
4319
  const name$2 = "@lody/cli-cloud";
4320
- const version$d = "0.102.0";
4320
+ const version$d = "0.103.0";
4321
4321
  const type = "module";
4322
4322
  const scripts = { "dev": "node dev.mjs", "dev:staging": "LODY_ENV=staging NODE_ENV=production node dev.mjs", "build": "node build.mjs", "prepare:publish": "node prepare-publish.js", "test": "node --test pnpm-runner.test.mjs vite-config.test.mjs" };
4323
4323
  const devDependencies = { "dotenv": "^16.6.1", "vite": "^7.0.0", "vite-plugin-wasm": "catalog:" };
@@ -4512,7 +4512,7 @@ async function getOrCreateStableMachineIdAsync() {
4512
4512
  if (machineId) return machineId;
4513
4513
  return createMachineId(crypto__default.randomUUID());
4514
4514
  }
4515
- function isRecord$g(value) {
4515
+ function isRecord$h(value) {
4516
4516
  return typeof value === "object" && value !== null;
4517
4517
  }
4518
4518
  const LODY_CLAUDE_TASK_LIFECYCLE_RAW_INPUT_KEY = "lodyClaudeTaskLifecycle";
@@ -4572,7 +4572,7 @@ const LodyTaskMetaSchema = object({
4572
4572
  skipTranscript: boolean().optional()
4573
4573
  });
4574
4574
  const parseLodyTaskMeta = (meta) => {
4575
- if (!isRecord$g(meta) || !isRecord$g(meta.lody)) return null;
4575
+ if (!isRecord$h(meta) || !isRecord$h(meta.lody)) return null;
4576
4576
  const parsed = LodyTaskMetaSchema.safeParse(meta.lody.task);
4577
4577
  if (!parsed.success) return null;
4578
4578
  const task = parsed.data;
@@ -4596,9 +4596,9 @@ const parseLodyTaskMeta = (meta) => {
4596
4596
  };
4597
4597
  };
4598
4598
  const parseSubagentTaskWire = (rawInput) => {
4599
- if (!isRecord$g(rawInput)) return null;
4599
+ if (!isRecord$h(rawInput)) return null;
4600
4600
  const carrier = rawInput[LODY_SUBAGENT_TASK_LIFECYCLE_RAW_INPUT_KEY] ?? rawInput[LODY_CLAUDE_TASK_LIFECYCLE_RAW_INPUT_KEY];
4601
- if (!isRecord$g(carrier)) return null;
4601
+ if (!isRecord$h(carrier)) return null;
4602
4602
  const parsed = SubagentTaskPayloadSchema.safeParse(carrier);
4603
4603
  return parsed.success ? parsed.data : null;
4604
4604
  };
@@ -5286,7 +5286,7 @@ const MESSAGE_TEXT_SPAN_KINDS = [
5286
5286
  ];
5287
5287
  const MAX_MESSAGE_TEXT_SPAN_MARK_LENGTH = 16;
5288
5288
  const SPAN_KINDS = new Set(MESSAGE_TEXT_SPAN_KINDS);
5289
- const isRecord$f = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5289
+ const isRecord$g = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5290
5290
  const isTextOffset = (value) => typeof value === "number" && Number.isInteger(value) && value >= 0;
5291
5291
  const isOffset = isTextOffset;
5292
5292
  const dropOverlappingRanges = (ranges) => {
@@ -5304,7 +5304,7 @@ const sanitizeMessageTextSpans = (text, spans) => {
5304
5304
  if (!Array.isArray(spans) || spans.length === 0) return void 0;
5305
5305
  const candidates = [];
5306
5306
  for (const span2 of spans) {
5307
- if (!isRecord$f(span2)) continue;
5307
+ if (!isRecord$g(span2)) continue;
5308
5308
  const { start: start2, end: end2, kind: kind2, label: label2, target, mark: mark2 } = span2;
5309
5309
  if (!isOffset(start2) || !isOffset(end2)) continue;
5310
5310
  if (end2 <= start2 || end2 > text.length) continue;
@@ -5329,7 +5329,7 @@ const reanchorMessageTextSpansForTrim = (originalText, trimmedText, spans) => {
5329
5329
  const leading = originalText.length - originalText.trimStart().length;
5330
5330
  if (leading === 0) return sanitizeMessageTextSpans(trimmedText, spans);
5331
5331
  const shifted = spans.map(
5332
- (span2) => isRecord$f(span2) && isOffset(span2.start) && isOffset(span2.end) ? { ...span2, start: span2.start - leading, end: span2.end - leading } : span2
5332
+ (span2) => isRecord$g(span2) && isOffset(span2.start) && isOffset(span2.end) ? { ...span2, start: span2.start - leading, end: span2.end - leading } : span2
5333
5333
  );
5334
5334
  return sanitizeMessageTextSpans(trimmedText, shifted);
5335
5335
  };
@@ -5514,12 +5514,12 @@ function resolveBaseBranchPreference(options) {
5514
5514
  const isMcpTransport = (value) => value === "stdio" || value === "http";
5515
5515
  const ENV_VAR_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
5516
5516
  const ENV_VAR_PATTERN = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
5517
- const isRecord$e = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5518
- const isStringRecord$2 = (value) => isRecord$e(value) && Object.values(value).every((entry) => typeof entry === "string");
5517
+ const isRecord$f = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5518
+ const isStringRecord$2 = (value) => isRecord$f(value) && Object.values(value).every((entry) => typeof entry === "string");
5519
5519
  const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
5520
5520
  const isOptionalString = (value) => value === void 0 || typeof value === "string";
5521
5521
  const isMcpConnectionSpec = (value) => {
5522
- if (!isRecord$e(value) || !isMcpTransport(value.transport)) {
5522
+ if (!isRecord$f(value) || !isMcpTransport(value.transport)) {
5523
5523
  return false;
5524
5524
  }
5525
5525
  if (value.transport === "stdio") {
@@ -5528,7 +5528,7 @@ const isMcpConnectionSpec = (value) => {
5528
5528
  return typeof value.url === "string" && isOptionalString(value.bearerToken) && (value.headers === void 0 || isStringRecord$2(value.headers));
5529
5529
  };
5530
5530
  const isWorkspaceMcpServerMeta = (value) => {
5531
- if (!isRecord$e(value) || typeof value.id !== "string" || value.id.trim().length === 0 || typeof value.name !== "string" || value.name.trim().length === 0 || !isMcpTransport(value.transport) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt) || value.description !== void 0 && typeof value.description !== "string" || value.enabledByDefault !== void 0 && typeof value.enabledByDefault !== "boolean" || value.createdBy !== void 0 && typeof value.createdBy !== "string") {
5531
+ if (!isRecord$f(value) || typeof value.id !== "string" || value.id.trim().length === 0 || typeof value.name !== "string" || value.name.trim().length === 0 || !isMcpTransport(value.transport) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt) || value.description !== void 0 && typeof value.description !== "string" || value.enabledByDefault !== void 0 && typeof value.enabledByDefault !== "boolean" || value.createdBy !== void 0 && typeof value.createdBy !== "string") {
5532
5532
  return false;
5533
5533
  }
5534
5534
  return value.connection === void 0 || isMcpConnectionSpec(value.connection) && value.connection.transport === value.transport;
@@ -8336,7 +8336,7 @@ const MessageContentSchema = union$7([NonSystemNoticeMessageContentSchema, Syste
8336
8336
  });
8337
8337
  const LEGACY_DEFAULT_BRANCH = "main";
8338
8338
  const LEGACY_BUILTIN_CLI_TYPES = /* @__PURE__ */ new Set(["claude", "codex"]);
8339
- function isRecord$d(value) {
8339
+ function isRecord$e(value) {
8340
8340
  return typeof value === "object" && value !== null;
8341
8341
  }
8342
8342
  function getTrimmedString(value) {
@@ -8353,7 +8353,7 @@ function isAgentConfigCliTypeString(value) {
8353
8353
  return value === "builtin" || value === "registry" || value === "custom";
8354
8354
  }
8355
8355
  function normalizeLegacyProjectRef(value) {
8356
- if (!isRecord$d(value)) {
8356
+ if (!isRecord$e(value)) {
8357
8357
  return value;
8358
8358
  }
8359
8359
  const kind2 = value.kind;
@@ -8367,13 +8367,13 @@ function normalizeLegacyProjectRef(value) {
8367
8367
  normalized.branch = existingBranch;
8368
8368
  } else {
8369
8369
  const legacyBranchFromString = getTrimmedString(legacyProject);
8370
- const legacyBranchFromObject = isRecord$d(legacyProject) ? getTrimmedString(legacyProject.branch) ?? getTrimmedString(legacyProject.project) : void 0;
8370
+ const legacyBranchFromObject = isRecord$e(legacyProject) ? getTrimmedString(legacyProject.branch) ?? getTrimmedString(legacyProject.project) : void 0;
8371
8371
  const resolvedBranch = legacyBranchFromString ?? legacyBranchFromObject;
8372
8372
  if (resolvedBranch) {
8373
8373
  normalized.branch = resolvedBranch;
8374
8374
  }
8375
8375
  }
8376
- if (isRecord$d(legacyProject)) {
8376
+ if (isRecord$e(legacyProject)) {
8377
8377
  if (kind2 === "github" && !getTrimmedString(normalized.repoFullName)) {
8378
8378
  const repoFullName = getTrimmedString(legacyProject.repoFullName);
8379
8379
  if (repoFullName) {
@@ -8408,7 +8408,7 @@ function normalizeLegacySessionProject(message) {
8408
8408
  const normalized = { ...message };
8409
8409
  normalized.project = normalizeLegacyProjectRef(normalized.project);
8410
8410
  const currentProject = normalized.project;
8411
- const projectRecord = isRecord$d(currentProject) ? currentProject : void 0;
8411
+ const projectRecord = isRecord$e(currentProject) ? currentProject : void 0;
8412
8412
  const explicitBranch = getTrimmedString(normalized.branch) ?? getTrimmedString(currentProject) ?? (projectRecord ? getTrimmedString(projectRecord.branch) ?? getTrimmedString(projectRecord.project) : void 0);
8413
8413
  const repoFullName = (projectRecord ? getTrimmedString(projectRecord.repoFullName) : void 0) ?? getTrimmedString(normalized.repoFullName) ?? getTrimmedString(normalized.githubRepo);
8414
8414
  const localProjectId = (projectRecord ? getTrimmedString(projectRecord.localProjectId) : void 0) ?? getTrimmedString(normalized.localProjectId);
@@ -8442,7 +8442,7 @@ function normalizeLegacySessionProject(message) {
8442
8442
  return normalized;
8443
8443
  }
8444
8444
  function normalizeLegacyAcpSessionConfig(value) {
8445
- if (!isRecord$d(value)) {
8445
+ if (!isRecord$e(value)) {
8446
8446
  return value;
8447
8447
  }
8448
8448
  const normalized = { ...value };
@@ -8475,13 +8475,13 @@ function normalizeLegacyAcpSessionConfig(value) {
8475
8475
  return normalized;
8476
8476
  }
8477
8477
  function normalizeLegacySessionMessage(parsed) {
8478
- if (!isRecord$d(parsed)) {
8478
+ if (!isRecord$e(parsed)) {
8479
8479
  return parsed;
8480
8480
  }
8481
8481
  const messageType = parsed.type;
8482
8482
  if (messageType === "session/create" || messageType === "session/chat") {
8483
8483
  const normalized = normalizeLegacySessionProject(parsed);
8484
- if (!isRecord$d(normalized)) {
8484
+ if (!isRecord$e(normalized)) {
8485
8485
  return normalized;
8486
8486
  }
8487
8487
  normalized.acpSessionConfig = normalizeLegacyAcpSessionConfig(normalized.acpSessionConfig);
@@ -13894,8 +13894,8 @@ const parseRateLimitEntryKey = (key2) => {
13894
13894
  };
13895
13895
  };
13896
13896
  const historyItemAnySchema = schema.Any({ defaultLoroText: false });
13897
- const isRecord$c = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
13898
- const isWorktreeScriptHistoryStep = (value) => isRecord$c(value) && typeof value.command === "string" && (value.status === "in_progress" || value.status === "completed" || value.status === "failed") && typeof value.output === "string";
13897
+ const isRecord$d = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
13898
+ const isWorktreeScriptHistoryStep = (value) => isRecord$d(value) && typeof value.command === "string" && (value.status === "in_progress" || value.status === "completed" || value.status === "failed") && typeof value.output === "string";
13899
13899
  const historyNestedPayloadSchema = schema.Any({ defaultLoroText: false });
13900
13900
  const historyToolContentSchema = schema.LoroMap({
13901
13901
  type: schema.String({ required: false }),
@@ -13990,7 +13990,7 @@ const historyMessageItemSchema = schema.LoroMap(
13990
13990
  return typeof v2.name === "string" ? true : "Missing name";
13991
13991
  case "operation_progress":
13992
13992
  return typeof v2.operationId === "string" && (v2.operationKind === "session_create" || v2.operationKind === "session_create_many") && Array.isArray(v2.items) && v2.items.every(
13993
- (item) => isRecord$c(item) && isRecord$c(item.target) && typeof item.target.sessionId === "string" && typeof item.target.userTurnId === "string" && (item.label === void 0 || typeof item.label === "string") && typeof item.status === "string" && ["created", "running", "succeeded", "failed", "cancelled"].includes(item.status)
13993
+ (item) => isRecord$d(item) && isRecord$d(item.target) && typeof item.target.sessionId === "string" && typeof item.target.userTurnId === "string" && (item.label === void 0 || typeof item.label === "string") && typeof item.status === "string" && ["created", "running", "succeeded", "failed", "cancelled"].includes(item.status)
13994
13994
  ) ? true : "Missing operation progress metadata";
13995
13995
  case "operation_completion":
13996
13996
  return typeof v2.deliveryId === "string" && typeof v2.operationId === "string" && typeof v2.operationKind === "string" && typeof v2.completion === "object" && v2.completion !== null ? true : "Missing operation completion metadata";
@@ -14440,7 +14440,7 @@ function assertHistoryJson(value, path2 = [], ancestors = /* @__PURE__ */ new Se
14440
14440
  ancestors.delete(value);
14441
14441
  }
14442
14442
  const CID_KEY$1 = "$cid";
14443
- const isRecord$b = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp) && typeof value !== "function";
14443
+ const isRecord$c = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp) && typeof value !== "function";
14444
14444
  const isMapSchema = (schema2) => schema2?.type === "loro-map";
14445
14445
  const isListSchema = (schema2) => schema2?.type === "loro-list" || schema2?.type === "loro-movable-list";
14446
14446
  const isAnySchema = (schema2) => schema2?.type === "any";
@@ -14469,7 +14469,7 @@ function applySchemaToInfer(schema2, base) {
14469
14469
  return next2;
14470
14470
  }
14471
14471
  function inferContainerType(value, infer) {
14472
- if (isRecord$b(value)) return "Map";
14472
+ if (isRecord$c(value)) return "Map";
14473
14473
  if (Array.isArray(value)) return infer?.defaultMovableList ? "MovableList" : "List";
14474
14474
  if (typeof value === "string") return infer?.defaultLoroText ? "Text" : void 0;
14475
14475
  return void 0;
@@ -14477,7 +14477,7 @@ function inferContainerType(value, infer) {
14477
14477
  function matchesContainerType(type2, value) {
14478
14478
  switch (type2) {
14479
14479
  case "Map":
14480
- return isRecord$b(value);
14480
+ return isRecord$c(value);
14481
14481
  case "List":
14482
14482
  case "MovableList":
14483
14483
  case "Tree":
@@ -14536,7 +14536,7 @@ function insertContainerIntoList(list2, schema2, index, value, infer) {
14536
14536
  function populateContainer(container2, schema2, value, infer) {
14537
14537
  const kind2 = container2.kind();
14538
14538
  if (kind2 === "Map") {
14539
- if (!isRecord$b(value)) return;
14539
+ if (!isRecord$c(value)) return;
14540
14540
  populateMap(container2, isMapSchema(schema2) ? schema2 : void 0, value, infer);
14541
14541
  } else if (kind2 === "List" || kind2 === "MovableList") {
14542
14542
  if (!Array.isArray(value)) return;
@@ -14653,7 +14653,7 @@ function diffHistoryContainer(container2, schema2, oldValue, newValue, infer) {
14653
14653
  const effective = applySchemaToInfer(schema2, infer);
14654
14654
  const kind2 = container2.kind();
14655
14655
  if (kind2 === "Map") {
14656
- if (!isRecord$b(oldValue) || !isRecord$b(newValue)) {
14656
+ if (!isRecord$c(oldValue) || !isRecord$c(newValue)) {
14657
14657
  throw new Error("Failed to diff container(map). Old and new state must be objects");
14658
14658
  }
14659
14659
  diffMap(
@@ -16584,6 +16584,80 @@ function collectScheduleIds(roomIds, rows) {
16584
16584
  }
16585
16585
  return [...ids2].sort();
16586
16586
  }
16587
+ const isRecord$b = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16588
+ const parseModelControls = (value) => {
16589
+ if (!isRecord$b(value)) return void 0;
16590
+ const controls = {};
16591
+ if (value.effortValues !== void 0) {
16592
+ if (!Array.isArray(value.effortValues) || !value.effortValues.every((effort) => typeof effort === "string")) {
16593
+ return void 0;
16594
+ }
16595
+ controls.effortValues = [...value.effortValues];
16596
+ }
16597
+ if (value.fastMode !== void 0) {
16598
+ if (typeof value.fastMode !== "boolean") return void 0;
16599
+ controls.fastMode = value.fastMode;
16600
+ }
16601
+ return controls;
16602
+ };
16603
+ const parseModels = (value) => {
16604
+ if (!isRecord$b(value)) return void 0;
16605
+ const models = {};
16606
+ for (const [modelId, controls] of Object.entries(value)) {
16607
+ const parsed = parseModelControls(controls);
16608
+ if (!parsed) return void 0;
16609
+ models[modelId] = parsed;
16610
+ }
16611
+ return Object.keys(models).length > 0 ? models : void 0;
16612
+ };
16613
+ const readAcpModelCapabilitiesMeta = (sessionResponse) => {
16614
+ if (!isRecord$b(sessionResponse) || !isRecord$b(sessionResponse._meta)) return void 0;
16615
+ const lody = sessionResponse._meta.lody;
16616
+ if (!isRecord$b(lody) || !isRecord$b(lody.modelCapabilities)) return void 0;
16617
+ const declaration = lody.modelCapabilities;
16618
+ return declaration.version === 1 ? parseModels(declaration.models) : void 0;
16619
+ };
16620
+ const isAcpModelCapabilities = (value) => isRecord$b(value) && value.version === 1 && typeof value.sourceVersion === "string" && parseModels(value.models) !== void 0;
16621
+ const getDeclaredModelControls = (entry, modelId) => modelId ? entry?.declaredModelControls?.[modelId] : void 0;
16622
+ const BUILTIN_MODEL_CONTROL_BINDINGS = {
16623
+ claude: {
16624
+ effortConfigId: "effort",
16625
+ effortLabel: "Effort",
16626
+ providerDefaultEffort: "default",
16627
+ omittedEffortMeansUnsupported: true,
16628
+ fastConfigId: "fast"
16629
+ },
16630
+ codex: {
16631
+ effortConfigId: "reasoning_effort",
16632
+ effortLabel: "Reasoning effort",
16633
+ omittedEffortMeansUnsupported: false,
16634
+ fastConfigId: "fast-mode"
16635
+ }
16636
+ };
16637
+ const getBuiltinModelControlBinding = (agent2) => agent2?.cliType === "builtin" && agent2.agentType ? BUILTIN_MODEL_CONTROL_BINDINGS[agent2.agentType.toLowerCase()] : void 0;
16638
+ const defaultEffortValue = (values) => values.includes("medium") ? "medium" : values[0] ?? "";
16639
+ const resolveDeclaredEffortSupport = (entry, modelId) => {
16640
+ const controls = getDeclaredModelControls(entry, modelId);
16641
+ if (!controls) return { state: "unknown" };
16642
+ const binding = getBuiltinModelControlBinding(entry);
16643
+ const levels2 = controls.effortValues;
16644
+ if (levels2 === void 0) {
16645
+ return binding?.omittedEffortMeansUnsupported ? { state: "unsupported" } : { state: "unknown" };
16646
+ }
16647
+ if (levels2.length === 0) return { state: "unsupported" };
16648
+ const providerDefault = binding?.providerDefaultEffort;
16649
+ return {
16650
+ state: "supported",
16651
+ values: providerDefault ? [providerDefault, ...levels2] : [...levels2],
16652
+ fallbackValue: providerDefault ?? defaultEffortValue(levels2)
16653
+ };
16654
+ };
16655
+ const getModelEffortChoices = (entry, modelId) => {
16656
+ const declared = resolveDeclaredEffortSupport(entry, modelId);
16657
+ if (declared.state === "supported") return declared.values;
16658
+ if (declared.state === "unsupported") return [];
16659
+ return modelId ? entry?.modelReasoningEfforts?.[modelId] : void 0;
16660
+ };
16587
16661
  const ACP_FAST_MODE_CONFIG_IDS = ["fast-mode", "fast"];
16588
16662
  const ACP_COLLABORATION_MODE_CONFIG_ID = "collaboration_mode";
16589
16663
  const ACP_COLLABORATION_MODE_DEFAULT_VALUE = "default";
@@ -16669,11 +16743,10 @@ const listModels = (capability) => {
16669
16743
  return (capability?.models ?? []).map((model) => ({ id: model.modelId, name: model.name }));
16670
16744
  };
16671
16745
  const summarizeAgentRunConfigCapabilities = (capability) => {
16672
- const perModelEfforts = capability?.modelReasoningEfforts;
16673
16746
  const measuredForModelId = findCurrentModelId(capability);
16674
16747
  return {
16675
16748
  models: listModels(capability).map((model) => {
16676
- const efforts = perModelEfforts?.[model.id];
16749
+ const efforts = getModelEffortChoices(capability, model.id);
16677
16750
  return { ...model, ...efforts ? { reasoningEffortValues: efforts } : {} };
16678
16751
  }),
16679
16752
  reasoningEffortValues: (findReasoningEffortOption(capability)?.options ?? []).map(
@@ -16702,11 +16775,14 @@ const resolveAgentRunConfigSelection = (selection, capability) => {
16702
16775
  let modeId;
16703
16776
  if (selection.reasoningEffort !== void 0) {
16704
16777
  const option2 = findReasoningEffortOption(capability);
16705
- const targetModelEfforts = targetModelId ? capability.modelReasoningEfforts?.[targetModelId] : void 0;
16778
+ const targetModelEfforts = getModelEffortChoices(capability, targetModelId);
16706
16779
  if (!option2 && !targetModelEfforts) {
16707
16780
  throw new Error("The selected agent does not offer a reasoning effort option.");
16708
16781
  }
16709
- const configId = option2?.id ?? ACP_REASONING_EFFORT_CONFIG_ID;
16782
+ if (targetModelEfforts?.length === 0) {
16783
+ throw new Error(`Model ${targetModelId} does not offer a reasoning effort option.`);
16784
+ }
16785
+ const configId = option2?.id ?? getBuiltinModelControlBinding(capability)?.effortConfigId ?? ACP_REASONING_EFFORT_CONFIG_ID;
16710
16786
  if (targetModelEfforts) {
16711
16787
  if (!targetModelEfforts.includes(selection.reasoningEffort)) {
16712
16788
  throw new Error(
@@ -16722,11 +16798,20 @@ const resolveAgentRunConfigSelection = (selection, capability) => {
16722
16798
  }
16723
16799
  if (selection.fastMode !== void 0) {
16724
16800
  const option2 = findFastModeOption(capability);
16725
- if (!option2) {
16801
+ const declaredFast = getDeclaredModelControls(capability, targetModelId)?.fastMode;
16802
+ const builtinFastId = getBuiltinModelControlBinding(capability)?.fastConfigId;
16803
+ if (declaredFast === false) {
16804
+ if (selection.fastMode) throw new Error(`Model ${targetModelId} does not offer fast mode.`);
16805
+ } else if (option2) {
16806
+ configOptionValues[option2.id] = toggleValue(option2, selection.fastMode);
16807
+ if (declaredFast) validatedConfigIds.push(option2.id);
16808
+ } else if (declaredFast && builtinFastId) {
16809
+ configOptionValues[builtinFastId] = selection.fastMode;
16810
+ validatedConfigIds.push(builtinFastId);
16811
+ } else {
16726
16812
  throw new Error("The selected agent does not offer a fast mode option.");
16727
16813
  }
16728
- configOptionValues[option2.id] = toggleValue(option2, selection.fastMode);
16729
- if (switchesModel) {
16814
+ if (switchesModel && declaredFast === void 0) {
16730
16815
  unverifiedSelections.push(`fastMode=${selection.fastMode}`);
16731
16816
  }
16732
16817
  }
@@ -19074,7 +19159,7 @@ const DevinSubagentContextSchema = object({
19074
19159
  parentAgentId: string$1().min(1)
19075
19160
  });
19076
19161
  const parseDevinSubagentTaskMeta = (meta) => {
19077
- if (!isRecord$g(meta)) return null;
19162
+ if (!isRecord$h(meta)) return null;
19078
19163
  const completed = DevinSubagentCompletedSchema.safeParse(meta[DEVIN_SUBAGENT_COMPLETED_META_KEY]);
19079
19164
  if (completed.success) {
19080
19165
  const c = completed.data;
@@ -19106,12 +19191,12 @@ const parseDevinSubagentTaskMeta = (meta) => {
19106
19191
  return null;
19107
19192
  };
19108
19193
  const getDevinSubagentContextId = (meta) => {
19109
- if (!isRecord$g(meta)) return null;
19194
+ if (!isRecord$h(meta)) return null;
19110
19195
  const parsed = DevinSubagentContextSchema.safeParse(meta[DEVIN_SUBAGENT_CONTEXT_META_KEY]);
19111
19196
  if (!parsed.success || parsed.data.parentAgentId === "root") return null;
19112
19197
  return parsed.data.parentAgentId;
19113
19198
  };
19114
- const hasOtherDevinSubagentMeta = (meta) => isRecord$g(meta) && Object.keys(meta).some(
19199
+ const hasOtherDevinSubagentMeta = (meta) => isRecord$h(meta) && Object.keys(meta).some(
19115
19200
  (key2) => key2.startsWith("cognition.ai/subagent") && key2 !== DEVIN_SUBAGENT_CONTEXT_META_KEY
19116
19201
  );
19117
19202
  const zMeta = record$3(string$1(), unknown()).nullish();
@@ -25997,6 +26082,10 @@ const machineFlockKeys = {
25997
26082
  "acpCapability",
25998
26083
  configId
25999
26084
  ],
26085
+ acpModelCapability: (configId) => [
26086
+ "acpModelCapability",
26087
+ configId
26088
+ ],
26000
26089
  rateLimit: (cliType, limitId) => [
26001
26090
  "rateLimit",
26002
26091
  cliType,
@@ -26080,6 +26169,14 @@ const parseMachineFlockKey = (key2) => {
26080
26169
  agentConfigId
26081
26170
  };
26082
26171
  }
26172
+ if (key2.length === 2 && key2[0] === "acpModelCapability" && isNonEmptyString$2(key2[1])) {
26173
+ const configId = key2[1];
26174
+ return {
26175
+ kind: "acpModelCapability",
26176
+ key: machineFlockKeys.acpModelCapability(configId),
26177
+ configId
26178
+ };
26179
+ }
26083
26180
  if (key2.length === 2 && key2[0] === "acpCapability" && isNonEmptyString$2(key2[1])) {
26084
26181
  const configId = key2[1];
26085
26182
  return {
@@ -26125,6 +26222,7 @@ const MACHINE_FLOCK_ROW_FAMILY_PREFIXES = {
26125
26222
  providerSetupCancellation: ["providerSetupCancellation"],
26126
26223
  agentConfigIndex: ["agentConfigIndex"],
26127
26224
  acpCapability: ["acpCapability"],
26225
+ acpModelCapability: ["acpModelCapability"],
26128
26226
  rateLimit: ["rateLimit"],
26129
26227
  builtinAgentOptOut: ["builtinAgentOptOut"],
26130
26228
  sessionLaunchConfig: ["sessionLaunchConfig"]
@@ -26161,6 +26259,7 @@ function readMachineFlockRowsFromFlock(flock, options) {
26161
26259
  const isMachineFlockLocalProjectRow = (row) => row.key[0] === "localProject";
26162
26260
  const isMachineFlockDeleteLocalProjectCommandRow = (row) => row.key[0] === "cmd" && row.key[1] === "deleteLocalProject";
26163
26261
  const isMachineFlockAcpCapabilityRow = (row) => row.key[0] === "acpCapability";
26262
+ const isMachineFlockAcpModelCapabilityRow = (row) => row.key[0] === "acpModelCapability";
26164
26263
  const isMachineFlockAgentConfigRow = (row) => row.key[0] === "agentConfig";
26165
26264
  const isMachineFlockProviderSetupRow = (row) => row.key[0] === "providerSetup";
26166
26265
  const isMachineFlockProviderSetupCancellationRow = (row) => row.key[0] === "providerSetupCancellation";
@@ -26188,13 +26287,35 @@ function getMachineFlockDeleteLocalProjectEntries(rows) {
26188
26287
  }
26189
26288
  return entries;
26190
26289
  }
26290
+ const ACP_CAPABILITY_ROW_FAMILIES = ["acpCapability", "acpModelCapability"];
26291
+ const mergedAcpCapabilityEntries = /* @__PURE__ */ new WeakMap();
26292
+ const withDeclaredModelControls = (entry, declaration) => {
26293
+ let byDeclaration = mergedAcpCapabilityEntries.get(entry);
26294
+ if (!byDeclaration) {
26295
+ byDeclaration = /* @__PURE__ */ new WeakMap();
26296
+ mergedAcpCapabilityEntries.set(entry, byDeclaration);
26297
+ }
26298
+ let merged = byDeclaration.get(declaration);
26299
+ if (!merged) {
26300
+ merged = { ...entry, declaredModelControls: declaration.models };
26301
+ byDeclaration.set(declaration, merged);
26302
+ }
26303
+ return merged;
26304
+ };
26191
26305
  function getMachineFlockAcpCapabilities(rows) {
26192
26306
  const capabilities = {};
26193
26307
  for (const row of Object.values(rows)) {
26194
- if (!isMachineFlockAcpCapabilityRow(row)) {
26195
- continue;
26308
+ if (isMachineFlockAcpCapabilityRow(row)) {
26309
+ capabilities[getAcpCapabilityCacheKey(row.key[1])] = row.value;
26310
+ }
26311
+ }
26312
+ for (const row of Object.values(rows)) {
26313
+ if (!isMachineFlockAcpModelCapabilityRow(row)) continue;
26314
+ const key2 = getAcpCapabilityCacheKey(row.key[1]);
26315
+ const entry = capabilities[key2];
26316
+ if (entry && entry.sourceVersion === row.value.sourceVersion) {
26317
+ capabilities[key2] = withDeclaredModelControls(entry, row.value);
26196
26318
  }
26197
- capabilities[getAcpCapabilityCacheKey(row.key[1])] = row.value;
26198
26319
  }
26199
26320
  return capabilities;
26200
26321
  }
@@ -26471,6 +26592,8 @@ function parseMachineFlockRow(key2, value) {
26471
26592
  }
26472
26593
  case "acpCapability":
26473
26594
  return isAcpCapabilityCacheEntry(value) ? { key: parsedKey.key, value } : void 0;
26595
+ case "acpModelCapability":
26596
+ return isAcpModelCapabilities(value) ? { key: parsedKey.key, value } : void 0;
26474
26597
  case "rateLimit":
26475
26598
  return isRecord$8(value) ? { key: parsedKey.key, value } : void 0;
26476
26599
  case "builtinAgentOptOut": {
@@ -112583,18 +112706,20 @@ class MachineDocument {
112583
112706
  const existing = getMachineFlockAcpCapabilities(
112584
112707
  readMachineFlockRowsFromFlock(handle.flock, { families: ["acpCapability"] })
112585
112708
  )[capabilityKey];
112586
- if (existing && serializeAcpCapabilityWithoutFetchTime(existing) === serializeAcpCapabilityWithoutFetchTime(entry) && // Unchanged content is still rewritten once it is old enough: the refresh
112709
+ const modelCapabilitiesChanged = options.modelCapabilities !== void 0 && writeMachineFlockRowToFlock(handle.flock, {
112710
+ key: machineFlockKeys.acpModelCapability(configId),
112711
+ value: { version: 1, sourceVersion: sourceVersion2, models: options.modelCapabilities }
112712
+ });
112713
+ const capabilityUnchanged = existing && serializeAcpCapabilityWithoutFetchTime(existing) === serializeAcpCapabilityWithoutFetchTime(entry) && // Unchanged content is still rewritten once it is old enough: the refresh
112587
112714
  // cache trusts `fetchedAt`, and an entry never renewed would expire once
112588
112715
  // and then miss on every later request, re-probing forever.
112589
- !shouldRenewAcpCapabilityFetchTime(existing, entry.fetchedAt)) {
112590
- return existing;
112591
- }
112716
+ !shouldRenewAcpCapabilityFetchTime(existing, entry.fetchedAt);
112592
112717
  options.signal?.throwIfAborted();
112593
- const changed = writeMachineFlockRowToFlock(handle.flock, {
112718
+ const changed = !capabilityUnchanged && writeMachineFlockRowToFlock(handle.flock, {
112594
112719
  key: machineFlockKeys.acpCapability(configId),
112595
112720
  value: entry
112596
112721
  });
112597
- if (changed) {
112722
+ if (changed || modelCapabilitiesChanged) {
112598
112723
  await this.repo.flush();
112599
112724
  if (this.markMachineFlockDirty) {
112600
112725
  this.markMachineFlockDirty("acp-capability-update");
@@ -112602,7 +112727,7 @@ class MachineDocument {
112602
112727
  await handle.syncOnce().catch(() => void 0);
112603
112728
  }
112604
112729
  }
112605
- return entry;
112730
+ return (capabilityUnchanged ? existing : void 0) ?? entry;
112606
112731
  }
112607
112732
  async getAcpCapabilities(configId) {
112608
112733
  const key2 = getAcpCapabilityCacheKey(configId);
@@ -122461,7 +122586,7 @@ async function decompressStream(input2, options) {
122461
122586
  }, new ByteLengthQueuingStrategy({ highWaterMark }));
122462
122587
  }
122463
122588
  const version$b = "1.12.0";
122464
- const dependencies = { "@openai/codex": "^0.156.0" };
122589
+ const dependencies = { "@openai/codex": "^0.159.2" };
122465
122590
  const codexPackageJson = {
122466
122591
  version: version$b,
122467
122592
  dependencies
@@ -122494,8 +122619,8 @@ const claudeRuntimeManifestJson = {
122494
122619
  version: version$6,
122495
122620
  artifacts: artifacts$2
122496
122621
  };
122497
- const version$5 = "0.156.0";
122498
- const artifacts$1 = { "darwin-arm64": { "fileName": "codex-package-aarch64-apple-darwin.tar.zst", "sha256": "27a4c6ad8d63ab0988eb2a6699fb092d999b78845c75edad1eef674064a026de", "size": 91943742 }, "darwin-x64": { "fileName": "codex-package-x86_64-apple-darwin.tar.zst", "sha256": "545de467983f6d1fa1ee67266b0df4fcdd864bf1e8681254ee3691a48ea296fd", "size": 101404952 }, "linux-arm64": { "fileName": "codex-package-aarch64-unknown-linux-musl.tar.zst", "sha256": "cb2573ebaa76503f763cf2ac858219114c69a2000961ca14330e5a4a9ebd734f", "size": 100178344 }, "linux-x64": { "fileName": "codex-package-x86_64-unknown-linux-musl.tar.zst", "sha256": "30933220521da2a9eef5ca7be5cbb215edcb088835d0a55ba7488168da5b341f", "size": 106005443 }, "win32-arm64": { "fileName": "codex-package-aarch64-pc-windows-msvc.tar.zst", "sha256": "3041dfb02eff1f8e68bbbcc7603534b02ee0bb55b7b93bdd522b12dc3e12162f", "size": 106301619 }, "win32-x64": { "fileName": "codex-package-x86_64-pc-windows-msvc.tar.zst", "sha256": "887cc9593dbb59b3122afe4c8520c32e633ab644d685c95bcba23e115e56fcaf", "size": 115013735 } };
122622
+ const version$5 = "0.159.2";
122623
+ const artifacts$1 = { "darwin-arm64": { "fileName": "codex-package-aarch64-apple-darwin.tar.zst", "sha256": "2958825ae590c52093e13dc5e00bdeab5d84947d9a1c76c91f3c42338444909b", "size": 93587821 }, "darwin-x64": { "fileName": "codex-package-x86_64-apple-darwin.tar.zst", "sha256": "22609e143919c817c642c0a801ad67874b5395dfdd118e077b5699697629618b", "size": 102536488 }, "linux-arm64": { "fileName": "codex-package-aarch64-unknown-linux-musl.tar.zst", "sha256": "1017b8175e4c4c6529866ed4b67c8e93ad7f0169ad89888068f0ad9707c5999d", "size": 109213770 }, "linux-x64": { "fileName": "codex-package-x86_64-unknown-linux-musl.tar.zst", "sha256": "fbca2d1e23dc9f827fe6eb19cbca2942140f99a48769f62355d647f5d75ee91e", "size": 115217118 }, "win32-arm64": { "fileName": "codex-package-aarch64-pc-windows-msvc.tar.zst", "sha256": "47d79aa012f3f04fc89a70a9a3ad555def7c83384b3f24d8ba1d3ac5610cb25f", "size": 108217158 }, "win32-x64": { "fileName": "codex-package-x86_64-pc-windows-msvc.tar.zst", "sha256": "57133a65c41976304cfcd24367c4b7e297562ffe2efe4a6ebe560c9a8843aeb8", "size": 116901172 } };
122499
122624
  const codexRuntimeManifestJson = {
122500
122625
  version: version$5,
122501
122626
  artifacts: artifacts$1
@@ -125658,9 +125783,27 @@ const readManagedCandidate = async (repoFullName, source, invalidatedPersonalTok
125658
125783
  }, 15000);
125659
125784
  if (!response || !response.ok) throw new Error('GitHub credential service is unavailable; no operation was attempted.');
125660
125785
  const body = await response.json();
125661
- if (body.available === false) return null;
125786
+ if (body.available === false) return { token: null, reason: typeof body.reason === 'string' ? body.reason : null };
125662
125787
  if (!body.token || body.tokenSource !== source) throw new Error('Invalid GitHub credential response.');
125663
- return body.token;
125788
+ return { token: body.token, reason: null };
125789
+ };
125790
+
125791
+ // Why the personal identity was skipped, in words the user can act on. Never
125792
+ // includes token material; reasons are backend policy codes or preflight states.
125793
+ const describePersonalUnavailable = (repo, reason) => {
125794
+ switch (reason) {
125795
+ case 'personal_auth_missing':
125796
+ return 'your personal GitHub account is not authorized yet (Settings > Integrations > GitHub > Authorize)';
125797
+ case 'personal_token_expired':
125798
+ case 'personal_token_refresh_failed':
125799
+ return 'your personal GitHub authorization has expired or been revoked; re-authorize in Settings > Integrations > GitHub';
125800
+ case 'no_repository_access':
125801
+ return 'your GitHub account cannot access ' + repo + ' with the required permission';
125802
+ case 'token_invalid':
125803
+ return 'GitHub rejected your personal token; re-authorize in Settings > Integrations > GitHub';
125804
+ default:
125805
+ return reason ? 'personal access is unavailable (' + reason + ')' : 'personal access is unavailable';
125806
+ }
125664
125807
  };
125665
125808
 
125666
125809
  // Read-only preflight. Never replay an actual write with another identity.
@@ -125688,33 +125831,38 @@ const checkRepositoryCredential = async (token, repo, requireWrite, requirePubli
125688
125831
  };
125689
125832
 
125690
125833
  const selectGitHubCredential = async (repo, policy, localCandidate, requireWrite, anonymousCandidate) => {
125691
- let personalUnavailable = false;
125834
+ let personalUnavailable = null;
125692
125835
  if (policy.personalEnabled) {
125693
- let token = await readManagedCandidate(repo, 'personal');
125836
+ let candidate = await readManagedCandidate(repo, 'personal');
125837
+ let token = candidate.token;
125838
+ personalUnavailable = candidate.reason;
125694
125839
  if (token) {
125695
125840
  let status = await checkRepositoryCredential(token, repo, requireWrite);
125696
125841
  if (status === 'invalid') {
125697
- token = await readManagedCandidate(repo, 'personal', token);
125842
+ candidate = await readManagedCandidate(repo, 'personal', token);
125843
+ token = candidate.token;
125844
+ personalUnavailable = candidate.reason ?? 'token_invalid';
125698
125845
  if (token) status = await checkRepositoryCredential(token, repo, requireWrite);
125699
125846
  }
125700
125847
  if (token && status === 'usable') return { token, source: 'personal' };
125848
+ if (token) personalUnavailable = status === 'invalid' ? 'token_invalid' : 'no_repository_access';
125701
125849
  }
125702
- personalUnavailable = true;
125850
+ personalUnavailable = describePersonalUnavailable(repo, personalUnavailable);
125703
125851
  }
125704
125852
  if (policy.allowLocalAuth) {
125705
125853
  const local = await localCandidate();
125706
125854
  if (local) {
125707
- if (personalUnavailable) console.error('[Lody] Personal GitHub access is unavailable for ' + repo + '; using machine-local credentials.');
125855
+ if (personalUnavailable) console.error('[Lody] Using machine-local GitHub credentials for ' + repo + ': ' + personalUnavailable + '.');
125708
125856
  return { ...local, source: 'local' };
125709
125857
  }
125710
125858
  }
125711
- const token = await readManagedCandidate(repo, 'app');
125859
+ const token = (await readManagedCandidate(repo, 'app')).token;
125712
125860
  if (!token && !requireWrite && anonymousCandidate && await anonymousCandidate()) {
125713
125861
  console.error('[Lody] Reading public GitHub repository ' + repo + ' anonymously (no applicable credential).');
125714
125862
  return { token: null, source: 'anonymous' };
125715
125863
  }
125716
125864
  if (!token) throw new Error('No GitHub credential is available for ' + repo + '.');
125717
- console.error('[Lody] Using GitHub App identity for ' + repo + (personalUnavailable ? ' (personal access unavailable).' : '.'));
125865
+ console.error('[Lody] Using GitHub App identity for ' + repo + (personalUnavailable ? ': ' + personalUnavailable + '.' : '.'));
125718
125866
  return { token, source: 'app' };
125719
125867
  };
125720
125868
  `;
@@ -136683,6 +136831,7 @@ function normalizeAcpSessionCapabilities(sessionResponse, lifecycleCapabilities
136683
136831
  const legacyModels = readLegacySessionModelState(sessionResponse)?.availableModels ?? [];
136684
136832
  const models = modelsFromConfigOptions.length > 0 ? modelsFromConfigOptions : legacyModels;
136685
136833
  const availableCommands = readSessionAvailableCommands(sessionResponse);
136834
+ const modelCapabilities = readAcpModelCapabilitiesMeta(sessionResponse);
136686
136835
  const modelReasoningEfforts = {
136687
136836
  ...readLodyModelReasoningEfforts(sessionResponse),
136688
136837
  ...usesCodexModelEffortIds(lifecycleCapabilities.agent) ? deriveModelReasoningEffortsFromLegacyModelIds(legacyModels.map((model) => model.modelId)) : void 0
@@ -136696,7 +136845,8 @@ function normalizeAcpSessionCapabilities(sessionResponse, lifecycleCapabilities
136696
136845
  acknowledgedSteer: lifecycleCapabilities.acknowledgedSteer === true,
136697
136846
  sessionTitle: lifecycleCapabilities.sessionTitle === true,
136698
136847
  ...lifecycleCapabilities.goalActions?.length ? { goalActions: lifecycleCapabilities.goalActions } : {},
136699
- ...Object.keys(modelReasoningEfforts).length > 0 ? { modelReasoningEfforts } : {}
136848
+ ...Object.keys(modelReasoningEfforts).length > 0 ? { modelReasoningEfforts } : {},
136849
+ ...modelCapabilities ? { modelCapabilities } : {}
136700
136850
  };
136701
136851
  }
136702
136852
  const MAX_LISTED_IDS = 12;
@@ -150953,13 +151103,18 @@ class SessionExecutionService {
150953
151103
  let staleAcpPromptRecoveryAttempted = false;
150954
151104
  let baseCommitHash = null;
150955
151105
  let turnStartWorkingTreeDiff = null;
151106
+ const gitIdentityOptions = yield* self2.tryPromise(async () => {
151107
+ try {
151108
+ return await self2.deps.sessionManager.resolveGitIdentityOptions(message.userId);
151109
+ } catch {
151110
+ return { preferMachineIdentity: message.userId === self2.deps.userId };
151111
+ }
151112
+ });
150956
151113
  const bindReadySession = (nextSession) => {
150957
151114
  activeSession = nextSession;
150958
151115
  session2 = nextSession;
150959
151116
  ctx.bindSession(nextSession);
150960
- nextSession.updateGitIdentity(userName, userEmail, message.userId, {
150961
- preferMachineIdentity: message.userId === self2.deps.userId
150962
- });
151117
+ nextSession.updateGitIdentity(userName, userEmail, message.userId, gitIdentityOptions);
150963
151118
  };
150964
151119
  const sessionInputBlocks = normalizeSessionInputBlocks(
150965
151120
  acpSessionConfig.inputBlocks,
@@ -152014,7 +152169,10 @@ class SessionExecutionService {
152014
152169
  capabilities.modelReasoningEfforts,
152015
152170
  capabilities.acknowledgedSteer,
152016
152171
  capabilities.goalActions,
152017
- { sessionTitle: capabilities.sessionTitle }
152172
+ {
152173
+ sessionTitle: capabilities.sessionTitle,
152174
+ modelCapabilities: capabilities.modelCapabilities
152175
+ }
152018
152176
  );
152019
152177
  this.acpCapabilityLaunchInputFingerprints.set(
152020
152178
  agentConfigId,
@@ -152444,6 +152602,7 @@ class SessionExecutionService {
152444
152602
  sessionTitle,
152445
152603
  goalActions,
152446
152604
  modelReasoningEfforts,
152605
+ modelCapabilities,
152447
152606
  capabilitySourceVersion
152448
152607
  } = await this.deps.fetchAcpCapabilities(
152449
152608
  message.cliType,
@@ -152483,7 +152642,7 @@ class SessionExecutionService {
152483
152642
  modelReasoningEfforts,
152484
152643
  acknowledgedSteer,
152485
152644
  goalActions,
152486
- { signal: options.signal, sessionTitle }
152645
+ { signal: options.signal, sessionTitle, modelCapabilities }
152487
152646
  );
152488
152647
  this.acpCapabilityLaunchInputFingerprints.set(
152489
152648
  message.configId,
@@ -155183,10 +155342,9 @@ const normalizeName$1 = (name2, email2) => {
155183
155342
  }
155184
155343
  return email2;
155185
155344
  };
155186
- const readGitConfig = (key2, cwd) => {
155345
+ const readGitConfig = (key2) => {
155187
155346
  try {
155188
- const output = execFileSync("git", ["config", key2], {
155189
- cwd,
155347
+ const output = execFileSync("git", ["config", "--global", key2], {
155190
155348
  encoding: "utf8",
155191
155349
  stdio: ["ignore", "pipe", "ignore"],
155192
155350
  windowsHide: true
@@ -155196,13 +155354,18 @@ const readGitConfig = (key2, cwd) => {
155196
155354
  return void 0;
155197
155355
  }
155198
155356
  };
155199
- const readHostDefaultGitIdentity = (cwd) => ({
155200
- name: trimNonEmpty$1(process.env.GIT_AUTHOR_NAME) ?? trimNonEmpty$1(process.env.GIT_COMMITTER_NAME) ?? readGitConfig("user.name", cwd),
155201
- email: trimNonEmpty$1(process.env.GIT_AUTHOR_EMAIL) ?? trimNonEmpty$1(process.env.GIT_COMMITTER_EMAIL) ?? readGitConfig("user.email", cwd)
155357
+ const readHostDefaultGitIdentity = () => ({
155358
+ name: trimNonEmpty$1(process.env.GIT_AUTHOR_NAME) ?? trimNonEmpty$1(process.env.GIT_COMMITTER_NAME) ?? readGitConfig("user.name"),
155359
+ email: trimNonEmpty$1(process.env.GIT_AUTHOR_EMAIL) ?? trimNonEmpty$1(process.env.GIT_COMMITTER_EMAIL) ?? readGitConfig("user.email")
155202
155360
  });
155203
155361
  const resolveSessionGitIdentity = (requested, options) => {
155362
+ const requestedEmail = trimNonEmpty$1(requested.email);
155363
+ const requestedIdentity = isUsableEmail(requestedEmail) ? { name: normalizeName$1(trimNonEmpty$1(requested.name), requestedEmail), email: requestedEmail } : void 0;
155364
+ if (options.personalIdentityEnabled && requestedIdentity) {
155365
+ return requestedIdentity;
155366
+ }
155204
155367
  if (options.preferMachineIdentity) {
155205
- const machineIdentity = options.machineIdentity ?? readHostDefaultGitIdentity(options.cwd);
155368
+ const machineIdentity = options.machineIdentity ?? readHostDefaultGitIdentity();
155206
155369
  const machineEmail = trimNonEmpty$1(machineIdentity.email);
155207
155370
  if (isUsableEmail(machineEmail)) {
155208
155371
  return {
@@ -155211,12 +155374,8 @@ const resolveSessionGitIdentity = (requested, options) => {
155211
155374
  };
155212
155375
  }
155213
155376
  }
155214
- const requestedEmail = trimNonEmpty$1(requested.email);
155215
- if (isUsableEmail(requestedEmail)) {
155216
- return {
155217
- name: normalizeName$1(trimNonEmpty$1(requested.name), requestedEmail),
155218
- email: requestedEmail
155219
- };
155377
+ if (requestedIdentity) {
155378
+ return requestedIdentity;
155220
155379
  }
155221
155380
  return {
155222
155381
  name: DEFAULT_AI_GIT_AUTHOR_NAME,
@@ -167726,6 +167885,11 @@ const PRICE_DATA = {
167726
167885
  cacheReadInputTokenCost: 1e-6,
167727
167886
  outputCostPerToken: 5e-5
167728
167887
  },
167888
+ "gpt-6.1-sol": {
167889
+ inputCostPerToken: 2e-6,
167890
+ cacheReadInputTokenCost: 1e-7,
167891
+ outputCostPerToken: 1e-5
167892
+ },
167729
167893
  "gpt-6-sol": {
167730
167894
  inputCostPerToken: 2e-6,
167731
167895
  cacheReadInputTokenCost: 2e-7,
@@ -168060,8 +168224,13 @@ class GitHubTokenManager {
168060
168224
  })
168061
168225
  );
168062
168226
  if (!result.success) {
168063
- if (result.errorCode === "repo_not_linked" || source2 === "personal" && result.errorCode === "personal_unavailable")
168064
- return null;
168227
+ if (result.errorCode === "repo_not_linked") return null;
168228
+ if (source2 === "personal" && result.errorCode === "personal_unavailable") {
168229
+ this.logger.debug(
168230
+ `[github-token] Personal GitHub identity unavailable for ${repoFullName} (requester ${context2.requesterUserId}): ${result.errorMessage}`
168231
+ );
168232
+ return { available: false, reason: result.errorMessage };
168233
+ }
168065
168234
  throw new GitHubTokenFetchError(result.errorCode, result.errorMessage);
168066
168235
  }
168067
168236
  return { token: result.token, tokenSource: result.tokenSource ?? "app" };
@@ -172872,11 +173041,10 @@ function validateModelDependentTurnConfigOptionValues(values, capability, target
172872
173041
  const optionsById = new Map(
172873
173042
  (capability.configOptions ?? []).map((option2) => [option2.id, option2])
172874
173043
  );
173044
+ const efforts = getModelEffortChoices(capability, targetModelId);
173045
+ const declaredFast = getDeclaredModelControls(capability, targetModelId)?.fastMode;
172875
173046
  for (const [id2, value] of Object.entries(values)) {
172876
- const option2 = optionsById.get(id2);
172877
- const isEffort = isAcpThoughtLevelConfigOption(option2 ?? { id: id2 }) || id2 === "effort";
172878
- if (isEffort) {
172879
- const efforts = capability.modelReasoningEfforts?.[targetModelId];
173047
+ if (isTurnEffortEntry(optionsById, id2)) {
172880
173048
  if (efforts !== void 0) {
172881
173049
  if (typeof value !== "string" || !efforts.includes(value)) {
172882
173050
  throw new Error(
@@ -172887,12 +173055,20 @@ function validateModelDependentTurnConfigOptionValues(values, capability, target
172887
173055
  } else if (targetModelId !== probedModelId) {
172888
173056
  validatedIds.add(id2);
172889
173057
  }
172890
- } else if (isAcpFastModeConfigId(id2) && targetModelId !== probedModelId) {
172891
- validatedIds.add(id2);
173058
+ } else if (isAcpFastModeConfigId(id2)) {
173059
+ if (declaredFast === false && (value === true || value === ACP_CONFIG_OPTION_ON_VALUE)) {
173060
+ throw new Error(`Model ${targetModelId} does not offer fast mode.`);
173061
+ }
173062
+ if (declaredFast !== void 0 || targetModelId !== probedModelId) {
173063
+ validatedIds.add(id2);
173064
+ }
172892
173065
  }
172893
173066
  }
172894
173067
  return validatedIds;
172895
173068
  }
173069
+ function isTurnEffortEntry(optionsById, id2) {
173070
+ return isAcpThoughtLevelConfigOption(optionsById.get(id2) ?? { id: id2 }) || id2 === "effort";
173071
+ }
172896
173072
  function filterCompatibleTurnConfigOptionValues(values, capability, targetModelId) {
172897
173073
  if (!values || !capability) {
172898
173074
  return void 0;
@@ -172900,24 +173076,24 @@ function filterCompatibleTurnConfigOptionValues(values, capability, targetModelI
172900
173076
  const optionsById = new Map(
172901
173077
  (capability.configOptions ?? []).map((option2) => [option2.id, option2])
172902
173078
  );
172903
- const probedModelId = capability.configOptions?.find(
172904
- (option2) => option2.category === "model"
172905
- )?.currentValue;
173079
+ const probedModelId = findTurnConfigOptionByCategory(capability, "model")?.currentValue;
173080
+ const efforts = getModelEffortChoices(capability, targetModelId);
173081
+ const declared = getDeclaredModelControls(capability, targetModelId);
173082
+ const keepUnverified = targetModelId !== probedModelId || declared !== void 0;
172906
173083
  const compatible = Object.fromEntries(
172907
173084
  Object.entries(values).filter(([id2, value]) => {
172908
- const option2 = optionsById.get(id2);
172909
173085
  if (targetModelId) {
172910
- const isEffort = isAcpThoughtLevelConfigOption(option2 ?? { id: id2 }) || id2 === "effort";
172911
- if (isEffort) {
172912
- const efforts = capability.modelReasoningEfforts?.[targetModelId];
173086
+ if (isTurnEffortEntry(optionsById, id2)) {
172913
173087
  if (efforts !== void 0) return typeof value === "string" && efforts.includes(value);
172914
- }
172915
- if (targetModelId !== probedModelId) {
172916
- if (isEffort) return typeof value === "string";
172917
- if (isAcpFastModeConfigId(id2))
172918
- return typeof value === "boolean" || value === "on" || value === "off";
173088
+ if (keepUnverified) return typeof value === "string";
173089
+ } else if (isAcpFastModeConfigId(id2)) {
173090
+ if (declared?.fastMode === false) return false;
173091
+ if (keepUnverified) {
173092
+ return typeof value === "boolean" || value === ACP_CONFIG_OPTION_ON_VALUE || value === ACP_CONFIG_OPTION_OFF_VALUE;
173093
+ }
172919
173094
  }
172920
173095
  }
173096
+ const option2 = optionsById.get(id2);
172921
173097
  return option2 !== void 0 && validateConfigOptionValue(option2, value) === void 0;
172922
173098
  })
172923
173099
  );
@@ -172978,7 +173154,9 @@ async function readAgentAcpCapability(args2) {
172978
173154
  getMachineFlockDocId(args2.workspaceId, args2.machineId)
172979
173155
  );
172980
173156
  const capabilities = getMachineFlockAcpCapabilities(
172981
- readMachineFlockRowsFromFlock(handle.flock, { families: ["acpCapability"] })
173157
+ readMachineFlockRowsFromFlock(handle.flock, {
173158
+ families: ACP_CAPABILITY_ROW_FAMILIES
173159
+ })
172982
173160
  );
172983
173161
  return capabilities[getAcpCapabilityCacheKey(args2.agentConfigId)];
172984
173162
  }
@@ -189920,7 +190098,7 @@ class MessageHandler {
189920
190098
  const { sessionId, name: name2, arguments: args2 } = request2.params;
189921
190099
  if (request2.workspaceId !== this.workspaceId || request2.machineId !== this.machineId || request2.ownerSessionId !== sessionId)
189922
190100
  throw new Error("Session tool scope mismatch");
189923
- const { executeDaemonSessionTool } = await import("./chunks/daemon-session-tools-BeXk1A1E.js");
190101
+ const { executeDaemonSessionTool } = await import("./chunks/daemon-session-tools-DESvdAeY.js");
189924
190102
  return this.withSessionCommandEnvironment(
189925
190103
  () => executeDaemonSessionTool(
189926
190104
  {
@@ -194822,7 +195000,9 @@ const createGitCredentialBrokerHandler = (options) => {
194822
195000
  if (!isContextCurrent()) return;
194823
195001
  res.writeHead(200, { "Content-Type": "application/json" });
194824
195002
  res.end(
194825
- JSON.stringify(candidate ? { ...candidate, available: true } : { available: false })
195003
+ JSON.stringify(
195004
+ candidate && "token" in candidate ? { ...candidate, available: true } : { available: false, ...candidate?.reason ? { reason: candidate.reason } : {} }
195005
+ )
194826
195006
  );
194827
195007
  return;
194828
195008
  }
@@ -196512,12 +196692,15 @@ class Session extends EventEmitter {
196512
196692
  const configEnv = this.config.env ?? {};
196513
196693
  if (this.config.githubCredentialPolicy) {
196514
196694
  this.config.githubCredentialPolicy.allowLocalAuth = options.preferMachineIdentity;
196695
+ if (options.personalIdentityEnabled !== void 0) {
196696
+ this.config.githubCredentialPolicy.personalEnabled = options.personalIdentityEnabled;
196697
+ }
196515
196698
  }
196516
196699
  const { name: name2, email: email2 } = resolveSessionGitIdentity(
196517
196700
  { name: userName, email: userEmail },
196518
196701
  {
196519
196702
  preferMachineIdentity: options.preferMachineIdentity,
196520
- cwd: this.getWorkdir()
196703
+ personalIdentityEnabled: options.personalIdentityEnabled ?? this.config.githubCredentialPolicy?.personalEnabled ?? false
196521
196704
  }
196522
196705
  );
196523
196706
  configEnv.GIT_AUTHOR_NAME = name2;
@@ -198221,9 +198404,12 @@ class SessionManager extends EventEmitter {
198221
198404
  "session.createSessionInner.prepared",
198222
198405
  sessionId
198223
198406
  );
198224
- session2.updateGitIdentity(config2.userName, config2.userEmail, config2.requesterUserId, {
198225
- preferMachineIdentity: config2.requesterUserId === this.cloudPort.identity.userId
198226
- });
198407
+ session2.updateGitIdentity(
198408
+ config2.userName,
198409
+ config2.userEmail,
198410
+ config2.requesterUserId,
198411
+ await this.resolveGitIdentityOptions(config2.requesterUserId)
198412
+ );
198227
198413
  const acpSessionId = await prepared.agentResult;
198228
198414
  const sessionDoc = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
198229
198415
  await sessionDoc.setACPSessionId(acpSessionId);
@@ -198340,9 +198526,12 @@ class SessionManager extends EventEmitter {
198340
198526
  );
198341
198527
  const sessionId = config2.sessionId;
198342
198528
  this.logger.debug(`[${sessionId}] Session workdir resolved: ${session2.getWorkdir()}`);
198343
- session2.updateGitIdentity(config2.userName, config2.userEmail, config2.requesterUserId, {
198344
- preferMachineIdentity: config2.requesterUserId === this.cloudPort.identity.userId
198345
- });
198529
+ session2.updateGitIdentity(
198530
+ config2.userName,
198531
+ config2.userEmail,
198532
+ config2.requesterUserId,
198533
+ await this.resolveGitIdentityOptions(config2.requesterUserId)
198534
+ );
198346
198535
  let acpSessionId;
198347
198536
  const launchResolutionStartedAt = performance.now();
198348
198537
  let managedRuntimeReadyLogged = false;
@@ -198494,6 +198683,29 @@ class SessionManager extends EventEmitter {
198494
198683
  runtimeOverrides: config2.runtimeOverrides
198495
198684
  });
198496
198685
  }
198686
+ /**
198687
+ * Commit identity follows the same precedence as GitHub credentials: a
198688
+ * requester who enabled "Act as you" commits as themselves; otherwise the
198689
+ * machine owner may use the machine's global Git identity. Policy lookup
198690
+ * failures degrade to "not enabled" rather than blocking the turn.
198691
+ */
198692
+ async resolveGitIdentityOptions(requesterUserId) {
198693
+ const preferMachineIdentity = requesterUserId === this.cloudPort.identity.userId;
198694
+ const tokenManager = this.getGitHubTokenManager();
198695
+ if (!tokenManager) return { preferMachineIdentity, personalIdentityEnabled: false };
198696
+ try {
198697
+ const policy = await tokenManager.getCredentialPolicy({
198698
+ requesterUserId,
198699
+ machineId: this.machineId
198700
+ });
198701
+ return { preferMachineIdentity, personalIdentityEnabled: policy.personalEnabled };
198702
+ } catch (error2) {
198703
+ this.logger.warn(
198704
+ `Could not read the GitHub identity preference for ${requesterUserId}; committing without personal identity: ${formatErrorMessage(error2)}`
198705
+ );
198706
+ return { preferMachineIdentity, personalIdentityEnabled: false };
198707
+ }
198708
+ }
198497
198709
  async prepareGitHubRepoSessionConfig(config2) {
198498
198710
  if (config2.project?.kind === "local") return;
198499
198711
  const githubRepo = config2.githubRepo ?? tryDeriveGitHubRepoFromUrl(config2.githubRepoUrl);
@@ -233168,7 +233380,7 @@ function mergeRateLimits(legacyRateLimits, flockRateLimits) {
233168
233380
  async function mergeMachineFlockJsonState(repo, workspaceId, machine, includeAcpCapabilities) {
233169
233381
  const handle = await repo.openFlockDoc(getMachineFlockDocId(workspaceId, machine.id));
233170
233382
  const rows = readMachineFlockRowsFromFlock(handle.flock, {
233171
- families: includeAcpCapabilities ? ["acpCapability", "rateLimit"] : ["rateLimit"]
233383
+ families: includeAcpCapabilities ? [...ACP_CAPABILITY_ROW_FAMILIES, "rateLimit"] : ["rateLimit"]
233172
233384
  });
233173
233385
  const acpCapabilities = includeAcpCapabilities ? getMachineFlockAcpCapabilities(rows) : {};
233174
233386
  const rateLimits = getMachineFlockRateLimits(rows);
@@ -234136,7 +234348,7 @@ async function runRender(file2, options) {
234136
234348
  data = createReviewBundleSnapshot(bundle);
234137
234349
  }
234138
234350
  const { injectReviewSnapshot } = await import("./chunks/index-BeRTvYK1.js");
234139
- const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-B6wZ9fN1.js");
234351
+ const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-BZiXmQnJ.js");
234140
234352
  const template = await resolveReviewViewerTemplate();
234141
234353
  const html = injectReviewSnapshot(template, data);
234142
234354
  const outputPath = options.output ? path__default.resolve(options.output) : defaultHtmlOutputPath(inputPath);
@@ -253927,7 +254139,9 @@ const assertDifferentMcpSession = (source2, target) => {
253927
254139
  const readMachineAcpCapabilities = async (manager, workspaceId, machineId) => {
253928
254140
  const handle = await manager.repo.openFlockDoc(getMachineFlockDocId(workspaceId, machineId));
253929
254141
  return getMachineFlockAcpCapabilities(
253930
- readMachineFlockRowsFromFlock(handle.flock, { families: ["acpCapability"] })
254142
+ readMachineFlockRowsFromFlock(handle.flock, {
254143
+ families: ACP_CAPABILITY_ROW_FAMILIES
254144
+ })
253931
254145
  );
253932
254146
  };
253933
254147
  const buildSessionWorkContext = async (manager, workspaceId, session2) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lody",
3
- "version": "0.102.0",
3
+ "version": "0.103.0",
4
4
  "description": "Lody Agent CLI tool for managing remote command execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",