zelari-code 2.34.1 → 2.36.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.
Files changed (37) hide show
  1. package/dist/cli/anthropicOAuth.js +1 -1
  2. package/dist/cli/anthropicOAuth.js.map +1 -1
  3. package/dist/cli/browser/tools.js +23 -1
  4. package/dist/cli/browser/tools.js.map +1 -1
  5. package/dist/cli/desktopConfig.js +18 -3
  6. package/dist/cli/desktopConfig.js.map +1 -1
  7. package/dist/cli/hooks/useSlashDispatch.js +1 -0
  8. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  9. package/dist/cli/keyStore.js +3 -7
  10. package/dist/cli/keyStore.js.map +1 -1
  11. package/dist/cli/main.bundled.js +933 -465
  12. package/dist/cli/main.bundled.js.map +4 -4
  13. package/dist/cli/provider/chatgpt.js +1 -1
  14. package/dist/cli/provider/chatgpt.js.map +1 -1
  15. package/dist/cli/provider/openai-compatible.js +53 -24
  16. package/dist/cli/provider/openai-compatible.js.map +1 -1
  17. package/dist/cli/provider/resolveStream.js +8 -0
  18. package/dist/cli/provider/resolveStream.js.map +1 -1
  19. package/dist/cli/provider/responsesApi.js +281 -0
  20. package/dist/cli/provider/responsesApi.js.map +1 -0
  21. package/dist/cli/providerConfig.js +49 -0
  22. package/dist/cli/providerConfig.js.map +1 -1
  23. package/dist/cli/refreshRegistry.js +78 -0
  24. package/dist/cli/refreshRegistry.js.map +1 -1
  25. package/dist/cli/slashCommands.js +18 -0
  26. package/dist/cli/slashCommands.js.map +1 -1
  27. package/dist/cli/slashHandlers/provider.js +11 -1
  28. package/dist/cli/slashHandlers/provider.js.map +1 -1
  29. package/dist/cli/thinking.js +5 -4
  30. package/dist/cli/thinking.js.map +1 -1
  31. package/dist/cli/thinkingCapability.js +7 -2
  32. package/dist/cli/thinkingCapability.js.map +1 -1
  33. package/dist/cli/toolRegistry.js +12 -0
  34. package/dist/cli/toolRegistry.js.map +1 -1
  35. package/dist/cli/tools/screenshotTool.js +111 -0
  36. package/dist/cli/tools/screenshotTool.js.map +1 -0
  37. package/package.json +2 -2
@@ -1473,7 +1473,7 @@ var init_anthropicOAuth = __esm({
1473
1473
  init_grokOAuth();
1474
1474
  DEFAULT_ANTHROPIC_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
1475
1475
  ANTHROPIC_AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
1476
- ANTHROPIC_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
1476
+ ANTHROPIC_TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
1477
1477
  ANTHROPIC_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
1478
1478
  ANTHROPIC_SCOPE = "org:create_api_key user:profile user:inference";
1479
1479
  AnthropicOAuthError = class extends Error {
@@ -1495,7 +1495,35 @@ function registerDefaultRefreshImpls() {
1495
1495
  if (!registry.has("chatgpt")) registry.set("chatgpt", chatgptRefreshAdapter);
1496
1496
  if (!registry.has("anthropic")) registry.set("anthropic", anthropicRefreshAdapter);
1497
1497
  }
1498
- var registry, grokRefreshAdapter, chatgptRefreshAdapter, anthropicRefreshAdapter;
1498
+ function normalizeRefreshError(providerId, err) {
1499
+ const code = err?.code;
1500
+ const message = err instanceof Error ? err.message : String(err);
1501
+ if (code === "invalid_grant" || message.includes("invalid_grant")) {
1502
+ return new RefreshRejectedError(
1503
+ `${providerId}: refresh token rejected (invalid_grant) \u2014 run /login ${providerId} to re-authenticate`,
1504
+ providerId,
1505
+ err
1506
+ );
1507
+ }
1508
+ return err;
1509
+ }
1510
+ async function runRefreshImpl(id3, refreshToken) {
1511
+ const existing = inflightRefresh.get(id3);
1512
+ if (existing) return existing;
1513
+ const impl = getRefreshImpl(id3);
1514
+ if (!impl) {
1515
+ throw new Error(`No refresh impl registered for provider "${id3}"`);
1516
+ }
1517
+ const run = Promise.resolve().then(() => impl(id3, refreshToken)).catch((err) => {
1518
+ throw normalizeRefreshError(id3, err);
1519
+ });
1520
+ inflightRefresh.set(id3, run);
1521
+ void run.finally(() => {
1522
+ if (inflightRefresh.get(id3) === run) inflightRefresh.delete(id3);
1523
+ }).catch(() => void 0);
1524
+ return run;
1525
+ }
1526
+ var registry, grokRefreshAdapter, chatgptRefreshAdapter, anthropicRefreshAdapter, RefreshRejectedError, inflightRefresh;
1499
1527
  var init_refreshRegistry = __esm({
1500
1528
  "src/cli/refreshRegistry.ts"() {
1501
1529
  "use strict";
@@ -1514,6 +1542,17 @@ var init_refreshRegistry = __esm({
1514
1542
  anthropicRefreshAdapter = async (_providerId, refreshToken) => {
1515
1543
  return refreshAnthropicToken({ refreshToken });
1516
1544
  };
1545
+ RefreshRejectedError = class extends Error {
1546
+ constructor(message, providerId, cause) {
1547
+ super(message);
1548
+ this.providerId = providerId;
1549
+ this.cause = cause;
1550
+ this.name = "RefreshRejectedError";
1551
+ }
1552
+ /** Marker callers can check without importing the class. */
1553
+ reloginRequired = true;
1554
+ };
1555
+ inflightRefresh = /* @__PURE__ */ new Map();
1517
1556
  }
1518
1557
  });
1519
1558
 
@@ -1742,11 +1781,7 @@ var init_keyStore = __esm({
1742
1781
  "anthropic"
1743
1782
  ];
1744
1783
  defaultRefreshImpl = async (providerId, refreshToken) => {
1745
- const impl = getRefreshImpl(providerId);
1746
- if (!impl) {
1747
- throw new Error(`No refresh impl registered for provider "${providerId}"`);
1748
- }
1749
- return impl(providerId, refreshToken);
1784
+ return runRefreshImpl(providerId, refreshToken);
1750
1785
  };
1751
1786
  }
1752
1787
  });
@@ -1767,10 +1802,11 @@ function effortLevelsFor(id3, model) {
1767
1802
  const m = (model ?? "").trim();
1768
1803
  switch (id3) {
1769
1804
  case "grok":
1770
- case "openai-compatible":
1771
- case "custom":
1772
1805
  if (grokHasXhigh(m)) return [...BASE_EFFORTS, "xhigh"];
1773
1806
  return [...BASE_EFFORTS];
1807
+ case "openai-compatible":
1808
+ case "custom":
1809
+ return [...BASE_EFFORTS, "xhigh", "max"];
1774
1810
  case "chatgpt":
1775
1811
  if (gptHasMax(m)) return [...BASE_EFFORTS, "xhigh", "max"];
1776
1812
  if (gptHasXhigh(m)) return [...BASE_EFFORTS, "xhigh"];
@@ -1983,13 +2019,14 @@ function translateOpenAiCompatibleThinking(providerId, spec, model) {
1983
2019
  };
1984
2020
  }
1985
2021
  }
1986
- function translateResponsesThinking(spec, model) {
2022
+ function translateResponsesThinking(spec, model, providerId) {
1987
2023
  if (spec === "auto") return { patch: {}, degraded: false };
2024
+ const id3 = providerId ?? "chatgpt";
1988
2025
  switch (spec.kind) {
1989
2026
  case "off":
1990
2027
  return { patch: { reasoning: { effort: "minimal" } }, degraded: false };
1991
2028
  case "effort": {
1992
- const resolved = clampEffort("chatgpt", model, spec.effort);
2029
+ const resolved = clampEffort(id3, model, spec.effort);
1993
2030
  return withClampNote(
1994
2031
  { reasoning: { effort: resolved.effort } },
1995
2032
  resolved.clamped,
@@ -1997,7 +2034,7 @@ function translateResponsesThinking(spec, model) {
1997
2034
  );
1998
2035
  }
1999
2036
  case "budget":
2000
- return degrade('thinking "budget" is not supported for chatgpt \u2014 use low/medium/high/xhigh/max');
2037
+ return degrade(`thinking "budget" is not supported on the Responses API for "${id3}" \u2014 use low/medium/high/xhigh/max`);
2001
2038
  }
2002
2039
  }
2003
2040
  function translateAnthropicThinking(spec, model) {
@@ -2046,6 +2083,7 @@ __export(providerConfig_exports, {
2046
2083
  clearKrakenVerifier: () => clearKrakenVerifier,
2047
2084
  getActiveModel: () => getActiveModel,
2048
2085
  getActiveProvider: () => getActiveProvider,
2086
+ getApiStyleFor: () => getApiStyleFor,
2049
2087
  getCustomEndpoint: () => getCustomEndpoint,
2050
2088
  getKrakenVerifierOverride: () => getKrakenVerifierOverride,
2051
2089
  getModelForProvider: () => getModelForProvider,
@@ -2054,6 +2092,7 @@ __export(providerConfig_exports, {
2054
2092
  getThinkingForProvider: () => getThinkingForProvider,
2055
2093
  loadProviderConfig: () => loadProviderConfig,
2056
2094
  setActiveProviderId: () => setActiveProviderId,
2095
+ setApiStyleFor: () => setApiStyleFor,
2057
2096
  setCustomEndpoint: () => setCustomEndpoint,
2058
2097
  setKrakenVerifier: () => setKrakenVerifier,
2059
2098
  setModelForProvider: () => setModelForProvider,
@@ -2071,6 +2110,7 @@ function mergeStoredProviderConfig(parsed) {
2071
2110
  modelByProvider: { ...DEFAULTS.modelByProvider, ...parsed.modelByProvider },
2072
2111
  thinkingByProvider: { ...DEFAULTS.thinkingByProvider, ...parsed.thinkingByProvider },
2073
2112
  customEndpoints: mergeCustomEndpoints(parsed.customEndpoints),
2113
+ apiStyleByProvider: mergeApiStyles(parsed.apiStyleByProvider),
2074
2114
  krakenVerifier: mergeKrakenVerifier(parsed.krakenVerifier)
2075
2115
  };
2076
2116
  }
@@ -2084,6 +2124,17 @@ function cloneDefaults() {
2084
2124
  customEndpoints: { ...DEFAULTS.customEndpoints }
2085
2125
  };
2086
2126
  }
2127
+ function mergeApiStyles(raw) {
2128
+ if (!raw || typeof raw !== "object") return {};
2129
+ const result = {};
2130
+ const validIds = new Set(PROVIDERS.map((p3) => p3.id));
2131
+ for (const [key, value] of Object.entries(raw)) {
2132
+ if (!validIds.has(key)) continue;
2133
+ if (value !== "responses") continue;
2134
+ result[key] = "responses";
2135
+ }
2136
+ return result;
2137
+ }
2087
2138
  function applyEnvOverrides(config2) {
2088
2139
  const envActive = process.env.ANATHEMA_ACTIVE_PROVIDER;
2089
2140
  const envModel = process.env.OPENAI_MODEL;
@@ -2155,6 +2206,23 @@ function clearCustomEndpoint(id3) {
2155
2206
  delete config2.customEndpoints[id3];
2156
2207
  writeProviderConfig(config2);
2157
2208
  }
2209
+ function getApiStyleFor(id3) {
2210
+ return getProviderConfig().apiStyleByProvider?.[id3] === "responses" ? "responses" : "chat";
2211
+ }
2212
+ function setApiStyleFor(id3, style) {
2213
+ const spec = PROVIDERS.find((p3) => p3.id === id3);
2214
+ if (!spec) {
2215
+ throw new Error(`Unknown provider id: "${id3}". Available: ${PROVIDERS.map((p3) => p3.id).join(", ")}`);
2216
+ }
2217
+ if (style !== "chat" && style !== "responses") {
2218
+ throw new Error(`Invalid api style: "${style}". Use 'chat' or 'responses'.`);
2219
+ }
2220
+ const config2 = getProviderConfig();
2221
+ if (!config2.apiStyleByProvider) config2.apiStyleByProvider = {};
2222
+ if (style === "chat") delete config2.apiStyleByProvider[id3];
2223
+ else config2.apiStyleByProvider[id3] = "responses";
2224
+ writeProviderConfig(config2);
2225
+ }
2158
2226
  function mergeKrakenVerifier(raw) {
2159
2227
  if (!raw || typeof raw !== "object") return void 0;
2160
2228
  const provider = typeof raw.provider === "string" ? raw.provider.trim() : "";
@@ -2362,23 +2430,23 @@ async function resolveAuthToken(provider, options) {
2362
2430
  return resolved?.apiKey;
2363
2431
  }
2364
2432
  async function resolveDiscoveryHeaders(provider, authToken) {
2365
- const headers2 = { Accept: "application/json" };
2366
- if (!authToken) return headers2;
2433
+ const headers3 = { Accept: "application/json" };
2434
+ if (!authToken) return headers3;
2367
2435
  if (provider === "anthropic") {
2368
- headers2.Authorization = `Bearer ${authToken}`;
2369
- headers2["x-api-key"] = authToken;
2370
- headers2["anthropic-version"] = "2023-06-01";
2371
- headers2["anthropic-beta"] = "oauth-2025-04-20";
2372
- return headers2;
2436
+ headers3.Authorization = `Bearer ${authToken}`;
2437
+ headers3["x-api-key"] = authToken;
2438
+ headers3["anthropic-version"] = "2023-06-01";
2439
+ headers3["anthropic-beta"] = "oauth-2025-04-20";
2440
+ return headers3;
2373
2441
  }
2374
- headers2.Authorization = `Bearer ${authToken}`;
2442
+ headers3.Authorization = `Bearer ${authToken}`;
2375
2443
  if (provider === "chatgpt") {
2376
2444
  const { getOAuthToken: getOAuthToken2 } = await Promise.resolve().then(() => (init_keyStore(), keyStore_exports));
2377
2445
  const accountId = getOAuthToken2("chatgpt")?.accountId;
2378
- if (accountId) headers2["ChatGPT-Account-Id"] = accountId;
2379
- headers2["OpenAI-Beta"] = "responses=experimental";
2446
+ if (accountId) headers3["ChatGPT-Account-Id"] = accountId;
2447
+ headers3["OpenAI-Beta"] = "responses=experimental";
2380
2448
  }
2381
- return headers2;
2449
+ return headers3;
2382
2450
  }
2383
2451
  function parseAnthropicModelsResponse(json3) {
2384
2452
  if (!json3 || typeof json3 !== "object") return [];
@@ -2430,8 +2498,8 @@ async function discoverModelsForProvider(provider, options = {}) {
2430
2498
  const fetchImpl = options.fetchImpl ?? fetch;
2431
2499
  let response;
2432
2500
  try {
2433
- const headers2 = await resolveDiscoveryHeaders(provider, authToken);
2434
- response = await fetchImpl(url2, { method: "GET", headers: headers2 });
2501
+ const headers3 = await resolveDiscoveryHeaders(provider, authToken);
2502
+ response = await fetchImpl(url2, { method: "GET", headers: headers3 });
2435
2503
  } catch (err) {
2436
2504
  throw new ModelDiscoveryError(
2437
2505
  `Network error contacting ${url2}: ${err instanceof Error ? err.message : String(err)}`,
@@ -3414,10 +3482,10 @@ function mergeDefs(...defs) {
3414
3482
  function cloneDef(schema) {
3415
3483
  return mergeDefs(schema._zod.def);
3416
3484
  }
3417
- function getElementAtPath(obj, path99) {
3418
- if (!path99)
3485
+ function getElementAtPath(obj, path100) {
3486
+ if (!path100)
3419
3487
  return obj;
3420
- return path99.reduce((acc, key) => acc?.[key], obj);
3488
+ return path100.reduce((acc, key) => acc?.[key], obj);
3421
3489
  }
3422
3490
  function promiseAllObject(promisesObj) {
3423
3491
  const keys = Object.keys(promisesObj);
@@ -3745,11 +3813,11 @@ function explicitlyAborted(x, startIndex = 0) {
3745
3813
  }
3746
3814
  return false;
3747
3815
  }
3748
- function prefixIssues(path99, issues) {
3816
+ function prefixIssues(path100, issues) {
3749
3817
  return issues.map((iss) => {
3750
3818
  var _a3;
3751
3819
  (_a3 = iss).path ?? (_a3.path = []);
3752
- iss.path.unshift(path99);
3820
+ iss.path.unshift(path100);
3753
3821
  return iss;
3754
3822
  });
3755
3823
  }
@@ -3967,16 +4035,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
3967
4035
  }
3968
4036
  function formatError(error51, mapper = (issue2) => issue2.message) {
3969
4037
  const fieldErrors = { _errors: [] };
3970
- const processError = (error52, path99 = []) => {
4038
+ const processError = (error52, path100 = []) => {
3971
4039
  for (const issue2 of error52.issues) {
3972
4040
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3973
- issue2.errors.map((issues) => processError({ issues }, [...path99, ...issue2.path]));
4041
+ issue2.errors.map((issues) => processError({ issues }, [...path100, ...issue2.path]));
3974
4042
  } else if (issue2.code === "invalid_key") {
3975
- processError({ issues: issue2.issues }, [...path99, ...issue2.path]);
4043
+ processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
3976
4044
  } else if (issue2.code === "invalid_element") {
3977
- processError({ issues: issue2.issues }, [...path99, ...issue2.path]);
4045
+ processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
3978
4046
  } else {
3979
- const fullpath = [...path99, ...issue2.path];
4047
+ const fullpath = [...path100, ...issue2.path];
3980
4048
  if (fullpath.length === 0) {
3981
4049
  fieldErrors._errors.push(mapper(issue2));
3982
4050
  } else {
@@ -4003,17 +4071,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
4003
4071
  }
4004
4072
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
4005
4073
  const result = { errors: [] };
4006
- const processError = (error52, path99 = []) => {
4074
+ const processError = (error52, path100 = []) => {
4007
4075
  var _a3, _b;
4008
4076
  for (const issue2 of error52.issues) {
4009
4077
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4010
- issue2.errors.map((issues) => processError({ issues }, [...path99, ...issue2.path]));
4078
+ issue2.errors.map((issues) => processError({ issues }, [...path100, ...issue2.path]));
4011
4079
  } else if (issue2.code === "invalid_key") {
4012
- processError({ issues: issue2.issues }, [...path99, ...issue2.path]);
4080
+ processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4013
4081
  } else if (issue2.code === "invalid_element") {
4014
- processError({ issues: issue2.issues }, [...path99, ...issue2.path]);
4082
+ processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4015
4083
  } else {
4016
- const fullpath = [...path99, ...issue2.path];
4084
+ const fullpath = [...path100, ...issue2.path];
4017
4085
  if (fullpath.length === 0) {
4018
4086
  result.errors.push(mapper(issue2));
4019
4087
  continue;
@@ -4045,8 +4113,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
4045
4113
  }
4046
4114
  function toDotPath(_path) {
4047
4115
  const segs = [];
4048
- const path99 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4049
- for (const seg of path99) {
4116
+ const path100 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
+ for (const seg of path100) {
4050
4118
  if (typeof seg === "number")
4051
4119
  segs.push(`[${seg}]`);
4052
4120
  else if (typeof seg === "symbol")
@@ -17549,13 +17617,13 @@ function resolveRef(ref, ctx) {
17549
17617
  if (!ref.startsWith("#")) {
17550
17618
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17551
17619
  }
17552
- const path99 = ref.slice(1).split("/").filter(Boolean);
17553
- if (path99.length === 0) {
17620
+ const path100 = ref.slice(1).split("/").filter(Boolean);
17621
+ if (path100.length === 0) {
17554
17622
  return ctx.rootSchema;
17555
17623
  }
17556
17624
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17557
- if (path99[0] === defsKey) {
17558
- const key = path99[1];
17625
+ if (path100[0] === defsKey) {
17626
+ const key = path100[1];
17559
17627
  if (!key || !ctx.defs[key]) {
17560
17628
  throw new Error(`Reference not found: ${ref}`);
17561
17629
  }
@@ -18327,7 +18395,9 @@ var init_zod = __esm({
18327
18395
  });
18328
18396
 
18329
18397
  // packages/core/dist/core/tools/toolTypes.js
18330
- function typedOk(value, meta3) {
18398
+ function typedOk(value, meta3, images) {
18399
+ if (images && images.length > 0)
18400
+ return { ok: true, value, meta: meta3, images };
18331
18401
  return meta3 ? { ok: true, value, meta: meta3 } : { ok: true, value };
18332
18402
  }
18333
18403
  function typedErr(error51, meta3) {
@@ -18387,17 +18457,17 @@ var init_newlines = __esm({
18387
18457
  });
18388
18458
 
18389
18459
  // packages/core/dist/core/tools/builtin/fileEvents.js
18390
- function fileReadEvent(path99, snapshotId) {
18391
- return { kind: "file.read", actor: { type: "tool" }, data: { path: path99, snapshotId } };
18460
+ function fileReadEvent(path100, snapshotId) {
18461
+ return { kind: "file.read", actor: { type: "tool" }, data: { path: path100, snapshotId } };
18392
18462
  }
18393
- function fileAppliedEvent(path99, snapshotId, bytes) {
18394
- return { kind: "file.applied", actor: { type: "tool" }, data: { path: path99, snapshotId, bytes } };
18463
+ function fileAppliedEvent(path100, snapshotId, bytes) {
18464
+ return { kind: "file.applied", actor: { type: "tool" }, data: { path: path100, snapshotId, bytes } };
18395
18465
  }
18396
- function fileRejectedEvent(path99, reason, hint) {
18466
+ function fileRejectedEvent(path100, reason, hint) {
18397
18467
  return {
18398
18468
  kind: "file.rejected",
18399
18469
  actor: { type: "tool" },
18400
- data: hint === void 0 ? { path: path99, reason } : { path: path99, reason, hint }
18470
+ data: hint === void 0 ? { path: path100, reason } : { path: path100, reason, hint }
18401
18471
  };
18402
18472
  }
18403
18473
  function reReadHint(reject) {
@@ -19313,8 +19383,8 @@ async function searchFile(absPath, relPath, regex, contextLines, remainingSlots)
19313
19383
  }
19314
19384
  async function isDirectory(p3) {
19315
19385
  try {
19316
- const stat7 = await fs7.stat(p3);
19317
- return stat7.isDirectory();
19386
+ const stat8 = await fs7.stat(p3);
19387
+ return stat8.isDirectory();
19318
19388
  } catch {
19319
19389
  return false;
19320
19390
  }
@@ -20266,11 +20336,11 @@ var init_tools = __esm({
20266
20336
  if (!ctx.addDocument)
20267
20337
  return "Knowledge vault tool not available.";
20268
20338
  const title = args["title"] || "New Document";
20269
- const path99 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20339
+ const path100 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20270
20340
  const content = args["content"] || "";
20271
20341
  const tags = args["tags"] || [];
20272
20342
  ctx.addDocument({
20273
- path: path99,
20343
+ path: path100,
20274
20344
  title,
20275
20345
  content,
20276
20346
  format: "markdown",
@@ -20279,7 +20349,7 @@ var init_tools = __esm({
20279
20349
  workspaceId: ctx.workspaceId
20280
20350
  });
20281
20351
  ctx.addActivity("vault", "created document", title);
20282
- return `Document "${title}" created at "${path99}".`;
20352
+ return `Document "${title}" created at "${path100}".`;
20283
20353
  }
20284
20354
  }
20285
20355
  ];
@@ -25104,16 +25174,16 @@ function runRetentionFromEnv() {
25104
25174
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
25105
25175
  };
25106
25176
  }
25107
- async function dirSize(path99) {
25177
+ async function dirSize(path100) {
25108
25178
  let total = 0;
25109
25179
  let entries;
25110
25180
  try {
25111
- entries = await readdir(path99, { withFileTypes: true });
25181
+ entries = await readdir(path100, { withFileTypes: true });
25112
25182
  } catch {
25113
25183
  return 0;
25114
25184
  }
25115
25185
  for (const entry of entries) {
25116
- const child = join3(path99, entry.name);
25186
+ const child = join3(path100, entry.name);
25117
25187
  if (entry.isDirectory())
25118
25188
  total += await dirSize(child);
25119
25189
  else {
@@ -25140,19 +25210,19 @@ async function enforceRunRetention(runsDir, options = {}) {
25140
25210
  for (const entry of entries) {
25141
25211
  if (!entry.isDirectory())
25142
25212
  continue;
25143
- const path99 = join3(runsDir, entry.name);
25213
+ const path100 = join3(runsDir, entry.name);
25144
25214
  let startedAt = 0;
25145
25215
  let endedAt;
25146
25216
  let completed = false;
25147
25217
  try {
25148
- const manifest = JSON.parse(await readFile(join3(path99, "manifest.json"), "utf8"));
25218
+ const manifest = JSON.parse(await readFile(join3(path100, "manifest.json"), "utf8"));
25149
25219
  startedAt = manifest.startedAt ?? 0;
25150
25220
  endedAt = manifest.endedAt;
25151
25221
  completed = Boolean(endedAt) && manifest.status !== "running";
25152
25222
  } catch {
25153
25223
  completed = false;
25154
25224
  }
25155
- infos.push({ name: entry.name, path: path99, startedAt, endedAt, completed, bytes: await dirSize(path99) });
25225
+ infos.push({ name: entry.name, path: path100, startedAt, endedAt, completed, bytes: await dirSize(path100) });
25156
25226
  }
25157
25227
  const remove = async (info) => {
25158
25228
  await rm(info.path, { recursive: true, force: true });
@@ -25639,12 +25709,12 @@ var init_engine = __esm({
25639
25709
  * content digest) and the returned ref carries the event seq when the
25640
25710
  * emitter resolved one.
25641
25711
  */
25642
- async fsEvidence(observation, path99, sha256, content, extra = {}) {
25712
+ async fsEvidence(observation, path100, sha256, content, extra = {}) {
25643
25713
  const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
25644
- const seq = await this.emitEvidence({ observation, path: path99, ...extra, ...digest ? { digest } : {} });
25714
+ const seq = await this.emitEvidence({ observation, path: path100, ...extra, ...digest ? { digest } : {} });
25645
25715
  return {
25646
25716
  tier: "fs-observation",
25647
- ref: path99,
25717
+ ref: path100,
25648
25718
  capturedAt: Date.now(),
25649
25719
  ...digest ? { digest } : {},
25650
25720
  ...seq !== void 0 ? { seq } : {}
@@ -29106,7 +29176,8 @@ ${shared.content}`,
29106
29176
  return {
29107
29177
  content: resultStr,
29108
29178
  isError: !result.ok,
29109
- durationMs: Date.now() - startMs
29179
+ durationMs: Date.now() - startMs,
29180
+ ...result.ok && result.images && result.images.length > 0 ? { images: result.images } : {}
29110
29181
  };
29111
29182
  })();
29112
29183
  inflight.set(callKey, prom);
@@ -29127,7 +29198,8 @@ ${shared.content}`,
29127
29198
  toolCallId: p3.toolCallId,
29128
29199
  content: r.content,
29129
29200
  isError: r.isError,
29130
- endEvent
29201
+ endEvent,
29202
+ ...r.images ? { images: r.images } : {}
29131
29203
  // Cache already written in invokeOne; no need to re-set.
29132
29204
  };
29133
29205
  };
@@ -29679,7 +29751,8 @@ ${cached2}`
29679
29751
  yield item.endEvent;
29680
29752
  turnToolResults.push({
29681
29753
  toolCallId: item.toolCallId,
29682
- content: item.content
29754
+ content: item.content,
29755
+ ...item.images ? { images: item.images } : {}
29683
29756
  });
29684
29757
  if (item.cacheKey && item.content && !item.isError) {
29685
29758
  this.toolCallCache.set(item.cacheKey, item.content);
@@ -29859,7 +29932,8 @@ ${cached2}`
29859
29932
  this.config.messages.push({
29860
29933
  role: "tool",
29861
29934
  toolCallId: tr.toolCallId,
29862
- content: tr.content
29935
+ content: tr.content,
29936
+ ...tr.images ? { images: tr.images } : {}
29863
29937
  });
29864
29938
  }
29865
29939
  if (truncatedToolCall) {
@@ -31660,11 +31734,11 @@ var init_synthesisAudit = __esm({
31660
31734
  import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
31661
31735
  import { join as join5 } from "node:path";
31662
31736
  function loadNfrSpec(zelariRoot) {
31663
- const path99 = join5(zelariRoot, "nfr-spec.json");
31664
- if (!existsSync10(path99))
31737
+ const path100 = join5(zelariRoot, "nfr-spec.json");
31738
+ if (!existsSync10(path100))
31665
31739
  return null;
31666
31740
  try {
31667
- const raw = JSON.parse(readFileSync9(path99, "utf8"));
31741
+ const raw = JSON.parse(readFileSync9(path100, "utf8"));
31668
31742
  if (raw.version !== 1 || !Array.isArray(raw.targets))
31669
31743
  return null;
31670
31744
  return raw;
@@ -34047,9 +34121,9 @@ var init_types9 = __esm({
34047
34121
  import { readFileSync as readFileSync14 } from "node:fs";
34048
34122
  import { join as join11 } from "node:path";
34049
34123
  function readLessonsDeduped(zelariRoot) {
34050
- const path99 = join11(zelariRoot, LESSONS_FILE);
34124
+ const path100 = join11(zelariRoot, LESSONS_FILE);
34051
34125
  try {
34052
- const raw = readFileSync14(path99, "utf8");
34126
+ const raw = readFileSync14(path100, "utf8");
34053
34127
  const byId = /* @__PURE__ */ new Map();
34054
34128
  for (const line of raw.split(/\r?\n/)) {
34055
34129
  if (!line.trim())
@@ -34150,8 +34224,8 @@ function keywordsFrom(check2, signature) {
34150
34224
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
34151
34225
  }
34152
34226
  function writeLesson(zelariRoot, lesson) {
34153
- const path99 = join12(zelariRoot, LESSONS_FILE);
34154
- appendFileSync(path99, `${JSON.stringify(lesson)}
34227
+ const path100 = join12(zelariRoot, LESSONS_FILE);
34228
+ appendFileSync(path100, `${JSON.stringify(lesson)}
34155
34229
  `, "utf8");
34156
34230
  }
34157
34231
  function findSimilar(lessons, signature) {
@@ -36118,9 +36192,9 @@ function findCycle(nodes) {
36118
36192
  if (color.get(start) !== WHITE)
36119
36193
  continue;
36120
36194
  const stack = [[start, 0]];
36121
- const path99 = [];
36195
+ const path100 = [];
36122
36196
  color.set(start, GRAY);
36123
- path99.push(start);
36197
+ path100.push(start);
36124
36198
  while (stack.length > 0) {
36125
36199
  const top = stack[stack.length - 1];
36126
36200
  const [id3, idx] = top;
@@ -36133,17 +36207,17 @@ function findCycle(nodes) {
36133
36207
  continue;
36134
36208
  const c = color.get(dep);
36135
36209
  if (c === GRAY) {
36136
- const at = path99.indexOf(dep);
36137
- return [...path99.slice(at), dep];
36210
+ const at = path100.indexOf(dep);
36211
+ return [...path100.slice(at), dep];
36138
36212
  }
36139
36213
  if (c === WHITE) {
36140
36214
  color.set(dep, GRAY);
36141
- path99.push(dep);
36215
+ path100.push(dep);
36142
36216
  stack.push([dep, 0]);
36143
36217
  }
36144
36218
  } else {
36145
36219
  color.set(id3, BLACK);
36146
- path99.pop();
36220
+ path100.pop();
36147
36221
  stack.pop();
36148
36222
  }
36149
36223
  }
@@ -37063,8 +37137,8 @@ var init_runner = __esm({
37063
37137
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
37064
37138
  pending: []
37065
37139
  };
37066
- const path99 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37067
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path99}`);
37140
+ const path100 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37141
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path100}`);
37068
37142
  return snapshot;
37069
37143
  }
37070
37144
  callLog(msg, data) {
@@ -38215,7 +38289,7 @@ var CORE_VERSION;
38215
38289
  var init_version = __esm({
38216
38290
  "packages/core/dist/version.js"() {
38217
38291
  "use strict";
38218
- CORE_VERSION = "2.34.1";
38292
+ CORE_VERSION = "2.36.0";
38219
38293
  }
38220
38294
  });
38221
38295
 
@@ -40673,9 +40747,9 @@ function spillToolOutput(fullText, meta3) {
40673
40747
  const rnd = randomBytes3(3).toString("hex");
40674
40748
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
40675
40749
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
40676
- const path99 = join14(dir, file2);
40677
- writeFileSync12(path99, fullText, "utf8");
40678
- return path99;
40750
+ const path100 = join14(dir, file2);
40751
+ writeFileSync12(path100, fullText, "utf8");
40752
+ return path100;
40679
40753
  } catch {
40680
40754
  return null;
40681
40755
  }
@@ -40721,10 +40795,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
40721
40795
  ${tail2}`;
40722
40796
  }
40723
40797
  if (doSpill) {
40724
- const path99 = spillToolOutput(text, { toolName: opts.toolName });
40725
- if (path99) {
40798
+ const path100 = spillToolOutput(text, { toolName: opts.toolName });
40799
+ if (path100) {
40726
40800
  const spillNote = `
40727
- \u2026 [full output spilled to: ${path99} \u2014 re-read with read_file if you need the complete text] \u2026`;
40801
+ \u2026 [full output spilled to: ${path100} \u2014 re-read with read_file if you need the complete text] \u2026`;
40728
40802
  if (preview.includes("] \u2026\n")) {
40729
40803
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
40730
40804
  `);
@@ -41495,28 +41569,28 @@ var init_storage = __esm({
41495
41569
  VALID_SCALARS = /^(true|false|null|~)$/i;
41496
41570
  Storage = class {
41497
41571
  /** Read a Markdown file with frontmatter. Throws if not found. */
41498
- read(path99) {
41499
- if (!existsSync19(path99)) {
41500
- throw new Error(`File not found: ${path99}`);
41572
+ read(path100) {
41573
+ if (!existsSync19(path100)) {
41574
+ throw new Error(`File not found: ${path100}`);
41501
41575
  }
41502
- const md = readFileSync17(path99, "utf8");
41576
+ const md = readFileSync17(path100, "utf8");
41503
41577
  return parseFrontmatter(md);
41504
41578
  }
41505
41579
  /** Read a Markdown file; returns null if not found. */
41506
- readIfExists(path99) {
41507
- if (!existsSync19(path99)) return null;
41508
- return this.read(path99);
41580
+ readIfExists(path100) {
41581
+ if (!existsSync19(path100)) return null;
41582
+ return this.read(path100);
41509
41583
  }
41510
41584
  /**
41511
41585
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
41512
41586
  * The meta object is serialized as YAML frontmatter; body as Markdown.
41513
41587
  */
41514
- write(path99, meta3, body) {
41515
- mkdirSync10(dirname2(path99), { recursive: true });
41516
- const tmp = path99 + ".tmp-" + process.pid;
41588
+ write(path100, meta3, body) {
41589
+ mkdirSync10(dirname2(path100), { recursive: true });
41590
+ const tmp = path100 + ".tmp-" + process.pid;
41517
41591
  const md = serializeFrontmatter(meta3, body);
41518
41592
  writeFileSync14(tmp, md, "utf8");
41519
- renameSync2(tmp, path99);
41593
+ renameSync2(tmp, path100);
41520
41594
  }
41521
41595
  /** List all .md files in a directory (non-recursive). */
41522
41596
  listMarkdown(dir) {
@@ -41591,8 +41665,8 @@ function nextPlanTaskId(store6) {
41591
41665
  return `t${store6.counter}`;
41592
41666
  }
41593
41667
  function writePlanTaskArtifact(rootDir, task) {
41594
- const path99 = join17(rootDir, "plan-tasks", `${task.id}.md`);
41595
- mkdirSync11(dirname3(path99), { recursive: true });
41668
+ const path100 = join17(rootDir, "plan-tasks", `${task.id}.md`);
41669
+ mkdirSync11(dirname3(path100), { recursive: true });
41596
41670
  const meta3 = {
41597
41671
  kind: "task",
41598
41672
  id: task.id,
@@ -41613,7 +41687,7 @@ function writePlanTaskArtifact(rootDir, task) {
41613
41687
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
41614
41688
  ""
41615
41689
  ].filter((l) => l !== null).join("\n");
41616
- new Storage().write(path99, meta3, body);
41690
+ new Storage().write(path100, meta3, body);
41617
41691
  }
41618
41692
  function loadHandle(rootDir) {
41619
41693
  const jsonPath = join17(rootDir, "plan.json");
@@ -50815,12 +50889,9 @@ function backoffDelay(attempt, retryAfterHeader) {
50815
50889
  }
50816
50890
  return Math.min(BACKOFF_BASE_MS * 2 ** attempt, BACKOFF_CAP_MS);
50817
50891
  }
50818
- function modelSupportsVision(model) {
50892
+ function modelSupportsVision(_model) {
50819
50893
  const force = process.env.ZELARI_VISION;
50820
- if (force === "1" || force === "true" || force === "on") return true;
50821
- if (force === "0" || force === "false" || force === "off") return false;
50822
- const m = model.toLowerCase();
50823
- return VISION_MODEL_HINTS.some((hint) => m.includes(hint));
50894
+ return !(force === "0" || force === "false" || force === "off");
50824
50895
  }
50825
50896
  function dataUriFromImage(img) {
50826
50897
  return `data:${img.mime};base64,${img.dataBase64}`;
@@ -50915,6 +50986,22 @@ ${notes}
50915
50986
  }
50916
50987
  return { role: m.role, content: m.content };
50917
50988
  }
50989
+ function imagesFollowUpMessage(images) {
50990
+ const labels = images.map((img) => img.alt ?? img.mime).join(", ");
50991
+ return {
50992
+ role: "user",
50993
+ content: [
50994
+ {
50995
+ type: "text",
50996
+ text: `[Immagine(i) dal tool: ${labels} \u2014 usa questi pixel per l'analisi visiva.]`
50997
+ },
50998
+ ...images.map((img) => ({
50999
+ type: "image_url",
51000
+ image_url: { url: dataUriFromImage(img) }
51001
+ }))
51002
+ ]
51003
+ };
51004
+ }
50918
51005
  function positiveEnvInt(name) {
50919
51006
  const raw = process.env[name];
50920
51007
  if (!raw) return void 0;
@@ -50925,15 +51012,27 @@ function openaiCompatibleProvider(config2) {
50925
51012
  return async function* (params) {
50926
51013
  const capabilities = capabilitiesFor(params.model, config2.providerId);
50927
51014
  const vision = modelSupportsVision(params.model);
50928
- const messages = params.messages.map((m) => {
51015
+ const msgsIn = params.messages;
51016
+ let toolRunImages = [];
51017
+ const messages = msgsIn.flatMap((m, i) => {
50929
51018
  const cacheable = !(m.role === "user" && m.images && m.images.length > 0);
50930
51019
  if (cacheable) {
50931
51020
  const cached2 = messageMappingCache.get(m);
50932
- if (cached2) return cached2;
51021
+ if (cached2) return [cached2];
50933
51022
  }
50934
51023
  const mapped = mapAgentMessage(m, vision);
50935
51024
  if (cacheable) messageMappingCache.set(m, mapped);
50936
- return mapped;
51025
+ if (m.role === "tool") {
51026
+ if (m.images && m.images.length > 0) toolRunImages.push(...m.images);
51027
+ const next = msgsIn[i + 1];
51028
+ const runEnds = !next || next.role !== "tool";
51029
+ if (runEnds && vision && toolRunImages.length > 0) {
51030
+ const followUp = imagesFollowUpMessage(toolRunImages);
51031
+ toolRunImages = [];
51032
+ return [mapped, followUp];
51033
+ }
51034
+ }
51035
+ return [mapped];
50937
51036
  });
50938
51037
  const generation = params.generation;
50939
51038
  const body = {
@@ -50985,7 +51084,7 @@ function openaiCompatibleProvider(config2) {
50985
51084
  const forceRecoveryTool = generation?.toolChoice === "required" && capabilities.buildRecovery.forceToolChoice && recoveryAttempt <= capabilities.buildRecovery.maxForcedTurns;
50986
51085
  body.tool_choice = forceRecoveryTool ? "required" : "auto";
50987
51086
  }
50988
- const headers2 = {
51087
+ const headers3 = {
50989
51088
  "Content-Type": "application/json",
50990
51089
  Authorization: `Bearer ${config2.apiKey}`,
50991
51090
  ...config2.extraHeaders ?? {}
@@ -50993,7 +51092,7 @@ function openaiCompatibleProvider(config2) {
50993
51092
  const affinityHeader = capabilities.promptCache.conversationAffinityHeader;
50994
51093
  const conversationId = params.conversationId?.trim();
50995
51094
  if (affinityHeader && conversationId && conversationId.length <= 256 && !/[\u0000-\u001f\u007f]/.test(conversationId)) {
50996
- headers2[affinityHeader] = conversationId;
51095
+ headers3[affinityHeader] = conversationId;
50997
51096
  }
50998
51097
  let response;
50999
51098
  let lastErrText = "";
@@ -51018,7 +51117,7 @@ function openaiCompatibleProvider(config2) {
51018
51117
  try {
51019
51118
  response = await fetch(`${config2.baseUrl}/chat/completions`, {
51020
51119
  method: "POST",
51021
- headers: headers2,
51120
+ headers: headers3,
51022
51121
  body: JSON.stringify(body),
51023
51122
  // Cancel aborts the HTTP request; stream idle is enforced below
51024
51123
  // per-chunk so active multi-minute streams are not killed.
@@ -51257,7 +51356,7 @@ async function providerConfigFor(providerId) {
51257
51356
  ...extraFromStored(providerId)
51258
51357
  };
51259
51358
  }
51260
- var RETRYABLE_STATUSES, MAX_RETRIES, BACKOFF_BASE_MS, BACKOFF_CAP_MS, PROVIDER_CONNECT_TIMEOUT_MS, PROVIDER_STREAM_IDLE_MS, PROVIDER_STREAM_MAX_MS, VISION_MODEL_HINTS, PROVIDER_ENDPOINTS, messageMappingCache;
51359
+ var RETRYABLE_STATUSES, MAX_RETRIES, BACKOFF_BASE_MS, BACKOFF_CAP_MS, PROVIDER_CONNECT_TIMEOUT_MS, PROVIDER_STREAM_IDLE_MS, PROVIDER_STREAM_MAX_MS, PROVIDER_ENDPOINTS, messageMappingCache;
51261
51360
  var init_openai_compatible = __esm({
51262
51361
  "src/cli/provider/openai-compatible.ts"() {
51263
51362
  "use strict";
@@ -51288,33 +51387,6 @@ var init_openai_compatible = __esm({
51288
51387
  const n = raw ? Number.parseInt(raw, 10) : 18e5;
51289
51388
  return Number.isFinite(n) && n >= 6e4 ? n : 18e5;
51290
51389
  })();
51291
- VISION_MODEL_HINTS = [
51292
- "grok-4",
51293
- "grok-3",
51294
- "grok-2-vision",
51295
- "grok-vision",
51296
- "glm-4v",
51297
- "glm-4.5v",
51298
- "glm-4.1v",
51299
- "glm-5v",
51300
- "qwen-vl",
51301
- "qwen2-vl",
51302
- "qwen2.5-vl",
51303
- "qwen3-vl",
51304
- "gpt-4o",
51305
- "gpt-4.1",
51306
- "gpt-4.5",
51307
- "gpt-4-vision",
51308
- "gpt-5",
51309
- "claude-3",
51310
- "claude-4",
51311
- "gemini-",
51312
- "gemini/",
51313
- "minimax-m1",
51314
- "minimax-m2",
51315
- "minimax-m3",
51316
- "deepseek-vl"
51317
- ];
51318
51390
  PROVIDER_ENDPOINTS = {
51319
51391
  "openai-compatible": "https://api.x.ai/v1",
51320
51392
  "minimax": "https://api.minimax.io/v1",
@@ -51709,6 +51781,16 @@ var init_driver = __esm({
51709
51781
  // src/cli/browser/tools.ts
51710
51782
  import path56 from "node:path";
51711
51783
  import os3 from "node:os";
51784
+ import { readFile as readFile7 } from "node:fs/promises";
51785
+ async function loadImageBlock(filePath) {
51786
+ try {
51787
+ const buf = await readFile7(filePath);
51788
+ if (buf.byteLength > SCREENSHOT_MAX_BYTES) return void 0;
51789
+ return { mime: "image/png", dataBase64: buf.toString("base64"), alt: path56.basename(filePath) };
51790
+ } catch {
51791
+ return void 0;
51792
+ }
51793
+ }
51712
51794
  function createBrowserTool(deps = {}) {
51713
51795
  return {
51714
51796
  name: "browser_check",
@@ -51761,17 +51843,23 @@ function createBrowserTool(deps = {}) {
51761
51843
  note: "Weak smoke only: no selector/text/evaluate assertions. No console/page errors is necessary but not sufficient to claim a logic fix. Add waitForSelector, waitForText, or evaluate (DOM/read hooks) for stronger evidence.",
51762
51844
  smokeStrength: "weak"
51763
51845
  } : { smokeStrength: "asserted" }
51764
- });
51846
+ }, void 0, await toolImages(result.screenshotPath));
51765
51847
  }
51766
51848
  };
51767
51849
  }
51768
- var ActionSchema;
51850
+ async function toolImages(screenshotPath) {
51851
+ if (!screenshotPath) return void 0;
51852
+ const image = await loadImageBlock(screenshotPath);
51853
+ return image ? [image] : void 0;
51854
+ }
51855
+ var SCREENSHOT_MAX_BYTES, ActionSchema;
51769
51856
  var init_tools5 = __esm({
51770
51857
  "src/cli/browser/tools.ts"() {
51771
51858
  "use strict";
51772
51859
  init_zod();
51773
51860
  init_toolTypes();
51774
51861
  init_driver();
51862
+ SCREENSHOT_MAX_BYTES = 8 * 1024 * 1024;
51775
51863
  ActionSchema = external_exports.discriminatedUnion("type", [
51776
51864
  external_exports.object({ type: external_exports.literal("click"), selector: external_exports.string().min(1) }),
51777
51865
  external_exports.object({ type: external_exports.literal("fill"), selector: external_exports.string().min(1), value: external_exports.string() }),
@@ -51796,6 +51884,92 @@ var init_tools5 = __esm({
51796
51884
  }
51797
51885
  });
51798
51886
 
51887
+ // src/cli/tools/screenshotTool.ts
51888
+ import { execFile as execFile5 } from "node:child_process";
51889
+ import { mkdir as mkdir3, readFile as readFile8, stat as stat7 } from "node:fs/promises";
51890
+ import path57 from "node:path";
51891
+ import { promisify as promisify4 } from "node:util";
51892
+ async function captureWindows(target) {
51893
+ const script = `Add-Type -AssemblyName System.Windows.Forms,System.Drawing;$b=[System.Windows.Forms.SystemInformation]::VirtualScreen;$bmp=New-Object System.Drawing.Bitmap $b.Width,$b.Height;$g=[System.Drawing.Graphics]::FromImage($bmp);$g.CopyFromScreen($b.Left,$b.Top,0,0,$bmp.Size);$g.Dispose(); $bmp.Save('${target.replace(/'/g, "''")}'); $bmp.Dispose();`;
51894
+ await execFileAsync4("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
51895
+ timeout: 12e3,
51896
+ windowsHide: true
51897
+ });
51898
+ }
51899
+ async function captureUnixLike(target) {
51900
+ const attempts = process.platform === "darwin" ? [["screencapture", ["-x", target]]] : [
51901
+ ["gnome-screenshot", ["-f", target]],
51902
+ ["scrot", [target]],
51903
+ ["import", ["-window", "root", target]]
51904
+ ];
51905
+ let lastErr = null;
51906
+ for (const [bin, args] of attempts) {
51907
+ try {
51908
+ await execFileAsync4(bin, args, { timeout: 12e3 });
51909
+ return;
51910
+ } catch (e) {
51911
+ lastErr = e;
51912
+ }
51913
+ }
51914
+ throw lastErr ?? new Error("no screen-capture utility available");
51915
+ }
51916
+ function createScreenshotTool(deps = {}) {
51917
+ return {
51918
+ name: "screenshot",
51919
+ description: "Capture a screenshot of the user screen(s) as PNG. Use it when the user asks to see/check something on screen (running app, game, dialog, error window) or when you need to LOOK at the current UI state to debug it. The image is returned to you as pixels (vision) and saved to disk; give the path back to the user so they can open it.",
51920
+ permissions: ["ui"],
51921
+ timeoutMs: 2e4,
51922
+ inputSchema: external_exports.object({
51923
+ note: external_exports.string().max(200).optional().describe("Why you are capturing (shown to the user with the permission prompt).")
51924
+ }),
51925
+ execute: async (args, ctx) => {
51926
+ const a = args;
51927
+ const dir = deps.outDir ?? path57.join(ctx.cwd ?? process.cwd(), ".zelari", "screenshots");
51928
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
51929
+ const target = path57.join(dir, `screenshot-${stamp}.png`);
51930
+ const capture = deps.capture ?? (process.platform === "win32" ? captureWindows : captureUnixLike);
51931
+ try {
51932
+ await mkdir3(dir, { recursive: true });
51933
+ await capture(target);
51934
+ const meta3 = await stat7(target);
51935
+ if (meta3.size === 0) return typedErr(`capture produced an empty file: ${target}`);
51936
+ const buf = await readFile8(target);
51937
+ const image = {
51938
+ mime: "image/png",
51939
+ dataBase64: buf.toString("base64"),
51940
+ alt: path57.basename(target)
51941
+ };
51942
+ const attachable = meta3.size <= SCREENSHOT_MAX_BYTES2;
51943
+ return typedOk(
51944
+ {
51945
+ ok: true,
51946
+ path: target,
51947
+ bytes: meta3.size,
51948
+ ...a.note ? { note: a.note } : {},
51949
+ ...attachable ? {} : { warning: "PNG over 8MB: pixels not attached to the model context; open the path instead." }
51950
+ },
51951
+ void 0,
51952
+ attachable ? [image] : void 0
51953
+ );
51954
+ } catch (e) {
51955
+ return typedErr(
51956
+ `screen capture failed on ${process.platform}: ${e instanceof Error ? e.message : String(e)}`
51957
+ );
51958
+ }
51959
+ }
51960
+ };
51961
+ }
51962
+ var execFileAsync4, SCREENSHOT_MAX_BYTES2;
51963
+ var init_screenshotTool = __esm({
51964
+ "src/cli/tools/screenshotTool.ts"() {
51965
+ "use strict";
51966
+ init_zod();
51967
+ init_toolTypes();
51968
+ execFileAsync4 = promisify4(execFile5);
51969
+ SCREENSHOT_MAX_BYTES2 = 8 * 1024 * 1024;
51970
+ }
51971
+ });
51972
+
51799
51973
  // src/cli/ssh/targets.ts
51800
51974
  var targets_exports = {};
51801
51975
  __export(targets_exports, {
@@ -51837,21 +52011,21 @@ function normalizeAuth(auth) {
51837
52011
  return "agent";
51838
52012
  }
51839
52013
  function readSecrets() {
51840
- const path99 = getSshSecretsPath();
51841
- if (!existsSync30(path99)) return {};
52014
+ const path100 = getSshSecretsPath();
52015
+ if (!existsSync30(path100)) return {};
51842
52016
  try {
51843
- return JSON.parse(readFileSync22(path99, "utf8"));
52017
+ return JSON.parse(readFileSync22(path100, "utf8"));
51844
52018
  } catch {
51845
52019
  return {};
51846
52020
  }
51847
52021
  }
51848
52022
  function writeSecrets(data) {
51849
- const path99 = getSshSecretsPath();
51850
- mkdirSync13(dirname4(path99), { recursive: true });
51851
- writeFileSync16(path99, `${JSON.stringify(data, null, 2)}
52023
+ const path100 = getSshSecretsPath();
52024
+ mkdirSync13(dirname4(path100), { recursive: true });
52025
+ writeFileSync16(path100, `${JSON.stringify(data, null, 2)}
51852
52026
  `, "utf8");
51853
52027
  try {
51854
- chmodSync(path99, 384);
52028
+ chmodSync(path100, 384);
51855
52029
  } catch {
51856
52030
  }
51857
52031
  }
@@ -51880,10 +52054,10 @@ function deleteSshPassword(id3) {
51880
52054
  writeSecrets({ passwords });
51881
52055
  }
51882
52056
  function readStore2() {
51883
- const path99 = getSshTargetsPath();
51884
- if (!existsSync30(path99)) return [];
52057
+ const path100 = getSshTargetsPath();
52058
+ if (!existsSync30(path100)) return [];
51885
52059
  try {
51886
- const parsed = JSON.parse(readFileSync22(path99, "utf8"));
52060
+ const parsed = JSON.parse(readFileSync22(path100, "utf8"));
51887
52061
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
51888
52062
  return list.filter(
51889
52063
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -51898,11 +52072,11 @@ function readStore2() {
51898
52072
  }
51899
52073
  }
51900
52074
  function writeStore2(targets) {
51901
- const path99 = getSshTargetsPath();
51902
- mkdirSync13(dirname4(path99), { recursive: true });
52075
+ const path100 = getSshTargetsPath();
52076
+ mkdirSync13(dirname4(path100), { recursive: true });
51903
52077
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
51904
52078
  writeFileSync16(
51905
- path99,
52079
+ path100,
51906
52080
  `${JSON.stringify({ targets: clean }, null, 2)}
51907
52081
  `,
51908
52082
  "utf8"
@@ -52148,11 +52322,11 @@ function formatSshTargetsForPrompt() {
52148
52322
  ];
52149
52323
  for (const t of targets) {
52150
52324
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
52151
- const path99 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52325
+ const path100 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52152
52326
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
52153
52327
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
52154
52328
  lines.push(
52155
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path99}${tags}${allow}`
52329
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path100}${tags}${allow}`
52156
52330
  );
52157
52331
  }
52158
52332
  return lines.join("\n");
@@ -52852,6 +53026,244 @@ var init_chatgpt = __esm({
52852
53026
  }
52853
53027
  });
52854
53028
 
53029
+ // src/cli/provider/responsesApi.ts
53030
+ function backoffDelay2(attempt, retryAfterHeader) {
53031
+ if (retryAfterHeader) {
53032
+ const seconds = Number.parseFloat(retryAfterHeader);
53033
+ if (Number.isFinite(seconds) && seconds >= 0) {
53034
+ return Math.min(seconds * 1e3, BACKOFF_CAP_MS2);
53035
+ }
53036
+ }
53037
+ return Math.min(BACKOFF_BASE_MS2 * 2 ** attempt, BACKOFF_CAP_MS2);
53038
+ }
53039
+ function abortableSleep2(ms, signal) {
53040
+ return new Promise((resolve9) => {
53041
+ if (signal?.aborted) return resolve9();
53042
+ const t = setTimeout(resolve9, ms);
53043
+ signal?.addEventListener(
53044
+ "abort",
53045
+ () => {
53046
+ clearTimeout(t);
53047
+ resolve9();
53048
+ },
53049
+ { once: true }
53050
+ );
53051
+ });
53052
+ }
53053
+ function headers2(config2) {
53054
+ const h = {
53055
+ "Content-Type": "application/json",
53056
+ Accept: "text/event-stream",
53057
+ Authorization: `Bearer ${config2.apiKey}`
53058
+ };
53059
+ if (config2.extraHeaders) Object.assign(h, config2.extraHeaders);
53060
+ return h;
53061
+ }
53062
+ function responsesApiProvider(config2) {
53063
+ return async function* (params) {
53064
+ const capabilities = capabilitiesFor(params.model, config2.providerId);
53065
+ const { instructions, input } = toInput(params.messages);
53066
+ const body = {
53067
+ model: params.model,
53068
+ stream: true,
53069
+ input
53070
+ };
53071
+ if (instructions) body.instructions = instructions;
53072
+ if (params.tools && params.tools.length > 0) {
53073
+ body.tools = params.tools.map((t) => ({
53074
+ type: "function",
53075
+ name: t.name,
53076
+ description: t.description,
53077
+ parameters: t.parameters
53078
+ }));
53079
+ }
53080
+ const generation = params.generation;
53081
+ body.temperature = generation?.temperature ?? capabilities.sampling.temperature;
53082
+ const maxTokens = generation?.maxTokens ?? capabilities.maxOutputTokens;
53083
+ if (typeof maxTokens === "number" && maxTokens > 0) {
53084
+ body.max_output_tokens = maxTokens;
53085
+ }
53086
+ const thinkingSpec = config2.thinking ?? "auto";
53087
+ if (thinkingSpec !== "auto") {
53088
+ const t = translateResponsesThinking(thinkingSpec, config2.model, config2.providerId);
53089
+ if (t.degraded) {
53090
+ console.warn(`[thinking] ${t.note ?? "unsupported"} \u2014 falling back to provider default.`);
53091
+ } else {
53092
+ Object.assign(body, t.patch);
53093
+ }
53094
+ }
53095
+ const base2 = config2.baseUrl.replace(/\/$/, "");
53096
+ const url2 = `${base2}/responses`;
53097
+ let response;
53098
+ let lastStatus = 0;
53099
+ let lastErrText = "";
53100
+ for (let attempt = 0; ; attempt++) {
53101
+ const connectController = new AbortController();
53102
+ const connectTimer = setTimeout(
53103
+ () => connectController.abort(
53104
+ new Error(
53105
+ `Provider connect timeout after ${Math.round(PROVIDER_CONNECT_TIMEOUT_MS / 1e3)}s (no response headers). Override ZELARI_PROVIDER_CONNECT_TIMEOUT_MS.`
53106
+ )
53107
+ ),
53108
+ PROVIDER_CONNECT_TIMEOUT_MS
53109
+ );
53110
+ const signals = [connectController.signal];
53111
+ if (params.signal) signals.push(params.signal);
53112
+ try {
53113
+ response = await fetch(url2, {
53114
+ method: "POST",
53115
+ headers: headers2(config2),
53116
+ body: JSON.stringify(body),
53117
+ signal: signals.length === 1 ? signals[0] : AbortSignal.any(signals)
53118
+ });
53119
+ } catch (err) {
53120
+ lastStatus = 0;
53121
+ lastErrText = err instanceof Error ? err.message : String(err);
53122
+ if (params.signal?.aborted) {
53123
+ yield { kind: "error", message: "aborted" };
53124
+ return;
53125
+ }
53126
+ if (attempt < MAX_RETRIES2) {
53127
+ await abortableSleep2(backoffDelay2(attempt, null), params.signal);
53128
+ continue;
53129
+ }
53130
+ yield { kind: "error", message: `Network error: ${lastErrText}` };
53131
+ return;
53132
+ } finally {
53133
+ clearTimeout(connectTimer);
53134
+ }
53135
+ if (response.ok && response.body) break;
53136
+ lastStatus = response.status;
53137
+ lastErrText = await response.text().catch(() => "");
53138
+ if (!RETRYABLE_STATUSES2.has(response.status) || attempt >= MAX_RETRIES2) break;
53139
+ await abortableSleep2(backoffDelay2(attempt, response.headers.get("retry-after")), params.signal);
53140
+ if (params.signal?.aborted) {
53141
+ yield { kind: "error", message: "aborted" };
53142
+ return;
53143
+ }
53144
+ }
53145
+ if (!response || !response.ok || !response.body) {
53146
+ const msg = lastStatus === 0 ? `Network error: ${lastErrText}` : `HTTP ${lastStatus}: ${lastErrText.slice(0, 240)}`;
53147
+ yield { kind: "error", message: msg };
53148
+ return;
53149
+ }
53150
+ const reader = response.body.getReader();
53151
+ const decoder = new TextDecoder();
53152
+ let buffer = "";
53153
+ const tools = /* @__PURE__ */ new Map();
53154
+ let emittedTool = false;
53155
+ const flush = function* (id3) {
53156
+ const t = tools.get(id3);
53157
+ if (!t?.name) return;
53158
+ let args = {};
53159
+ try {
53160
+ args = JSON.parse(t.argsJson || "{}");
53161
+ } catch {
53162
+ args = {};
53163
+ }
53164
+ tools.delete(id3);
53165
+ emittedTool = true;
53166
+ yield { kind: "tool_call", toolCallId: t.id, toolName: t.name, args };
53167
+ };
53168
+ const streamStartedAt = Date.now();
53169
+ let lastUsefulAt = streamStartedAt;
53170
+ const streamDeadline = streamStartedAt + PROVIDER_STREAM_MAX_MS;
53171
+ try {
53172
+ while (true) {
53173
+ const { value, done } = await readChunkWithTimeout(reader, {
53174
+ idleMs: PROVIDER_STREAM_IDLE_MS,
53175
+ deadlineMs: streamDeadline,
53176
+ signal: params.signal,
53177
+ lastUsefulAt: () => lastUsefulAt
53178
+ });
53179
+ if (done) break;
53180
+ buffer += decoder.decode(value, { stream: true });
53181
+ const lines = buffer.split("\n");
53182
+ buffer = lines.pop() ?? "";
53183
+ for (const line of lines) {
53184
+ const trimmed = line.trim();
53185
+ if (!trimmed.startsWith("data:")) continue;
53186
+ const data = trimmed.slice(5).trim();
53187
+ if (!data || data === "[DONE]") continue;
53188
+ let ev;
53189
+ try {
53190
+ ev = JSON.parse(data);
53191
+ } catch {
53192
+ continue;
53193
+ }
53194
+ const type = typeof ev.type === "string" ? ev.type : "";
53195
+ if (type) lastUsefulAt = Date.now();
53196
+ if (type === "response.output_text.delta" && typeof ev.delta === "string") {
53197
+ yield { kind: "text", delta: ev.delta };
53198
+ } else if (type === "response.reasoning_text.delta" && typeof ev.delta === "string") {
53199
+ yield { kind: "thinking", delta: ev.delta };
53200
+ } else if (type === "response.output_item.added") {
53201
+ const item = ev.item;
53202
+ if (item?.type === "function_call") {
53203
+ const id3 = String(item.call_id ?? item.id ?? `fc-${tools.size}`);
53204
+ tools.set(id3, {
53205
+ id: id3,
53206
+ name: typeof item.name === "string" ? item.name : "",
53207
+ argsJson: typeof item.arguments === "string" ? item.arguments : ""
53208
+ });
53209
+ }
53210
+ } else if (type === "response.function_call_arguments.delta") {
53211
+ const itemId = String(ev.item_id ?? ev.call_id ?? "");
53212
+ const existing = itemId ? tools.get(itemId) : [...tools.values()].at(-1);
53213
+ if (existing && typeof ev.delta === "string") existing.argsJson += ev.delta;
53214
+ } else if (type === "response.output_item.done") {
53215
+ const item = ev.item;
53216
+ if (item?.type === "function_call") {
53217
+ const id3 = String(item.call_id ?? item.id ?? "");
53218
+ if (id3) yield* flush(id3);
53219
+ }
53220
+ } else if (type === "response.completed") {
53221
+ const usage = ev.response?.usage;
53222
+ if (usage) {
53223
+ yield {
53224
+ kind: "usage",
53225
+ usage: {
53226
+ promptTokens: usage.input_tokens ?? usage.prompt_tokens ?? 0,
53227
+ completionTokens: usage.output_tokens ?? usage.completion_tokens ?? 0,
53228
+ totalTokens: usage.total_tokens ?? (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0)
53229
+ }
53230
+ };
53231
+ }
53232
+ yield { kind: "finish", reason: emittedTool ? "tool_calls" : "stop" };
53233
+ return;
53234
+ } else if (type === "response.failed" || type === "error") {
53235
+ const msg = typeof ev.message === "string" ? ev.message : JSON.stringify(ev.error ?? ev).slice(0, 200);
53236
+ yield { kind: "error", message: msg };
53237
+ return;
53238
+ }
53239
+ }
53240
+ }
53241
+ for (const id3 of [...tools.keys()]) yield* flush(id3);
53242
+ yield { kind: "finish", reason: emittedTool ? "tool_calls" : "stop" };
53243
+ } finally {
53244
+ reader.releaseLock();
53245
+ }
53246
+ };
53247
+ }
53248
+ var RETRYABLE_STATUSES2, MAX_RETRIES2, BACKOFF_BASE_MS2, BACKOFF_CAP_MS2;
53249
+ var init_responsesApi = __esm({
53250
+ "src/cli/provider/responsesApi.ts"() {
53251
+ "use strict";
53252
+ init_openai_compatible();
53253
+ init_chatgpt();
53254
+ init_thinking();
53255
+ init_capabilities();
53256
+ RETRYABLE_STATUSES2 = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
53257
+ MAX_RETRIES2 = (() => {
53258
+ const raw = process.env.ZELARI_PROVIDER_MAX_RETRIES;
53259
+ const n = raw ? Number.parseInt(raw, 10) : 3;
53260
+ return Number.isFinite(n) && n >= 0 ? n : 3;
53261
+ })();
53262
+ BACKOFF_BASE_MS2 = 500;
53263
+ BACKOFF_CAP_MS2 = 8e3;
53264
+ }
53265
+ });
53266
+
52855
53267
  // src/cli/provider/resolveStream.ts
52856
53268
  var resolveStream_exports = {};
52857
53269
  __export(resolveStream_exports, {
@@ -52860,6 +53272,9 @@ __export(resolveStream_exports, {
52860
53272
  function buildProviderStream(config2) {
52861
53273
  if (config2.providerId === "anthropic") return anthropicMessagesProvider(config2);
52862
53274
  if (config2.providerId === "chatgpt") return chatgptResponsesProvider(config2);
53275
+ if (getApiStyleFor(config2.providerId) === "responses") {
53276
+ return responsesApiProvider(config2);
53277
+ }
52863
53278
  return openaiCompatibleProvider(config2);
52864
53279
  }
52865
53280
  var init_resolveStream = __esm({
@@ -52868,6 +53283,8 @@ var init_resolveStream = __esm({
52868
53283
  init_openai_compatible();
52869
53284
  init_anthropic();
52870
53285
  init_chatgpt();
53286
+ init_responsesApi();
53287
+ init_providerConfig();
52871
53288
  }
52872
53289
  });
52873
53290
 
@@ -53138,12 +53555,12 @@ __export(folderTrust_exports, {
53138
53555
  untrustFolder: () => untrustFolder
53139
53556
  });
53140
53557
  import { existsSync as existsSync31, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync17 } from "node:fs";
53141
- import path57 from "node:path";
53558
+ import path58 from "node:path";
53142
53559
  function trustStorePath() {
53143
53560
  return _overrideStorePath ?? trustConfigPath();
53144
53561
  }
53145
53562
  function normalize6(p3) {
53146
- const resolved = path57.resolve(p3);
53563
+ const resolved = path58.resolve(p3);
53147
53564
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
53148
53565
  }
53149
53566
  function readStore3() {
@@ -53159,7 +53576,7 @@ function readStore3() {
53159
53576
  function writeStore3(store6) {
53160
53577
  const p3 = trustStorePath();
53161
53578
  try {
53162
- mkdirSync14(path57.dirname(p3), { recursive: true });
53579
+ mkdirSync14(path58.dirname(p3), { recursive: true });
53163
53580
  writeFileSync17(p3, JSON.stringify(store6, null, 2), "utf8");
53164
53581
  } catch (err) {
53165
53582
  throw new Error(
@@ -53185,7 +53602,7 @@ function isFolderTrusted(folderPath) {
53185
53602
  }
53186
53603
  function trustFolder(folderPath) {
53187
53604
  const store6 = readStore3();
53188
- const normalized = path57.resolve(folderPath);
53605
+ const normalized = path58.resolve(folderPath);
53189
53606
  if (!store6.folders.some((f) => normalize6(f.path) === normalize6(normalized))) {
53190
53607
  store6.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
53191
53608
  writeStore3(store6);
@@ -53311,7 +53728,7 @@ var init_lifecycleHooks = __esm({
53311
53728
 
53312
53729
  // src/cli/safety/astGate.ts
53313
53730
  import { promises as fs23 } from "node:fs";
53314
- import path58 from "node:path";
53731
+ import path59 from "node:path";
53315
53732
  function astGateEnabled() {
53316
53733
  return process.env.ZELARI_AST_GATE !== "0";
53317
53734
  }
@@ -53346,9 +53763,9 @@ function wrapWithAstGate(original, opts) {
53346
53763
  const containedPathOf = (args) => {
53347
53764
  const raw = args["path"];
53348
53765
  if (typeof raw !== "string" || raw.length === 0) return null;
53349
- const absPath = path58.isAbsolute(raw) ? raw : path58.join(opts.root, raw);
53350
- const rel2 = path58.relative(opts.root, absPath);
53351
- if (rel2.startsWith("..") || path58.isAbsolute(rel2)) return null;
53766
+ const absPath = path59.isAbsolute(raw) ? raw : path59.join(opts.root, raw);
53767
+ const rel2 = path59.relative(opts.root, absPath);
53768
+ if (rel2.startsWith("..") || path59.isAbsolute(rel2)) return null;
53352
53769
  return absPath;
53353
53770
  };
53354
53771
  return {
@@ -53373,7 +53790,7 @@ function wrapWithAstGate(original, opts) {
53373
53790
  if (!result.ok) return result;
53374
53791
  if (gateTarget !== null && !isAstSupported(gateTarget)) {
53375
53792
  process.stderr.write(
53376
- `[ast_gate] LOUD SKIP (unsupported-extension): ${original.name} ${gateTarget} \u2014 ${path58.extname(gateTarget) || "(no extension)"} is outside the AST surface; write KEPT, NOT syntax-gated.
53793
+ `[ast_gate] LOUD SKIP (unsupported-extension): ${original.name} ${gateTarget} \u2014 ${path59.extname(gateTarget) || "(no extension)"} is outside the AST surface; write KEPT, NOT syntax-gated.
53377
53794
  `
53378
53795
  );
53379
53796
  return result;
@@ -53390,7 +53807,7 @@ function wrapWithAstGate(original, opts) {
53390
53807
  return result;
53391
53808
  }
53392
53809
  const post = await fs23.readFile(absPath, "utf8");
53393
- const syntaxError = firstSyntaxError(ts, path58.basename(absPath), post);
53810
+ const syntaxError = firstSyntaxError(ts, path59.basename(absPath), post);
53394
53811
  if (!syntaxError) return result;
53395
53812
  const parseError = `${syntaxError.message} (line ${syntaxError.line}, col ${syntaxError.character})`;
53396
53813
  let revertedTo;
@@ -53401,7 +53818,7 @@ function wrapWithAstGate(original, opts) {
53401
53818
  await fs23.writeFile(absPath, preContent, "utf8");
53402
53819
  revertedTo = snapshotIdOf(preContent);
53403
53820
  }
53404
- const relLabel = path58.relative(opts.root, absPath) || path58.basename(absPath);
53821
+ const relLabel = path59.relative(opts.root, absPath) || path59.basename(absPath);
53405
53822
  return typedErr(
53406
53823
  `[ast_gate_reverted] ${original.name}: ${absPath} written but the file no longer parses \u2014 write REVERTED (revertedTo=${revertedTo}). ${parseError}. Fix the syntax and re-apply (read_file first for a fresh snapshotId).`,
53407
53824
  {
@@ -53826,7 +54243,7 @@ var init_resourceClaims = __esm({
53826
54243
  // src/cli/toolResultCache.ts
53827
54244
  import { createHash as createHash15 } from "node:crypto";
53828
54245
  import { promises as fs24 } from "node:fs";
53829
- import path59 from "node:path";
54246
+ import path60 from "node:path";
53830
54247
  function isToolCacheEnabled() {
53831
54248
  const raw = process.env.ZELARI_TOOL_CACHE;
53832
54249
  return raw !== "0" && raw !== "false" && raw !== "off";
@@ -53911,7 +54328,7 @@ async function statKey(toolName, input, ctx) {
53911
54328
  if (!input || typeof input !== "object") return null;
53912
54329
  const rawPath = input.path;
53913
54330
  if (typeof rawPath !== "string" || rawPath.length === 0) return null;
53914
- const abs = path59.isAbsolute(rawPath) ? rawPath : path59.join(ctx.cwd, rawPath);
54331
+ const abs = path60.isAbsolute(rawPath) ? rawPath : path60.join(ctx.cwd, rawPath);
53915
54332
  try {
53916
54333
  const st = await fs24.stat(abs);
53917
54334
  return hashKey({
@@ -53967,7 +54384,7 @@ __export(toolRegistry_exports, {
53967
54384
  wrapWithSandbox: () => wrapWithSandbox
53968
54385
  });
53969
54386
  import { existsSync as existsSync32 } from "node:fs";
53970
- import path60 from "node:path";
54387
+ import path61 from "node:path";
53971
54388
  function createBuiltinToolRegistry(options = {}) {
53972
54389
  const root = options.root ?? process.cwd();
53973
54390
  const audit = options.audit ?? new AuditLogger();
@@ -54192,6 +54609,15 @@ function createBuiltinToolRegistry(options = {}) {
54192
54609
  permissions: browserTool.permissions ?? []
54193
54610
  });
54194
54611
  }
54612
+ if (!readOnly && !gauntletParent && process.env.ZELARI_SCREENSHOT !== "0") {
54613
+ const screenshotTool = createScreenshotTool();
54614
+ registry4.register(screenshotTool);
54615
+ tools.push({
54616
+ name: screenshotTool.name,
54617
+ description: screenshotTool.description,
54618
+ permissions: screenshotTool.permissions ?? []
54619
+ });
54620
+ }
54195
54621
  if (!readOnly && !gauntletParent && process.env.ZELARI_SSH !== "0") {
54196
54622
  for (const t of createSshTools()) {
54197
54623
  registry4.register(t);
@@ -54576,14 +55002,14 @@ function wrapWithDiagnostics(original, root, runner) {
54576
55002
  function claimedSourcePath(token, args, root) {
54577
55003
  const cleaned = token.replace(/^["']|["']$/g, "");
54578
55004
  if (!cleaned || cleaned.startsWith("-")) return null;
54579
- if (!DIAG_SOURCE_EXTENSIONS.has(path60.extname(cleaned).toLowerCase())) return null;
55005
+ if (!DIAG_SOURCE_EXTENSIONS.has(path61.extname(cleaned).toLowerCase())) return null;
54580
55006
  const bases = [root];
54581
55007
  const cwd = args["cwd"];
54582
55008
  if (typeof cwd === "string" && cwd.length > 0) {
54583
- bases.unshift(path60.isAbsolute(cwd) ? cwd : path60.resolve(root, cwd));
55009
+ bases.unshift(path61.isAbsolute(cwd) ? cwd : path61.resolve(root, cwd));
54584
55010
  }
54585
55011
  for (const base2 of bases) {
54586
- const candidate = path60.isAbsolute(cleaned) ? path60.normalize(cleaned) : path60.resolve(base2, cleaned);
55012
+ const candidate = path61.isAbsolute(cleaned) ? path61.normalize(cleaned) : path61.resolve(base2, cleaned);
54587
55013
  try {
54588
55014
  const contained = resolveSandboxedPath(candidate, { root });
54589
55015
  if (existsSync32(contained)) return contained;
@@ -54853,6 +55279,7 @@ var init_toolRegistry = __esm({
54853
55279
  init_tools3();
54854
55280
  init_tools4();
54855
55281
  init_tools5();
55282
+ init_screenshotTool();
54856
55283
  init_tools6();
54857
55284
  init_worldModel();
54858
55285
  init_openai_compatible();
@@ -54899,7 +55326,7 @@ var init_toolRegistry = __esm({
54899
55326
 
54900
55327
  // src/cli/metrics.ts
54901
55328
  import { promises as fs25, existsSync as existsSync33, statSync as statSync4, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync15 } from "node:fs";
54902
- import path61 from "node:path";
55329
+ import path62 from "node:path";
54903
55330
  async function readMetrics(file2) {
54904
55331
  let raw = "";
54905
55332
  try {
@@ -54949,7 +55376,7 @@ var init_metrics3 = __esm({
54949
55376
  writeQueue = Promise.resolve();
54950
55377
  constructor(file2) {
54951
55378
  this.file = file2 ?? metricsPath();
54952
- mkdirSync15(path61.dirname(this.file), { recursive: true });
55379
+ mkdirSync15(path62.dirname(this.file), { recursive: true });
54953
55380
  }
54954
55381
  /** Metrics file path — doctor/summary readers use this. */
54955
55382
  get filePath() {
@@ -54986,8 +55413,8 @@ var init_metrics3 = __esm({
54986
55413
  maybeRotate() {
54987
55414
  if (!existsSync33(this.file)) return;
54988
55415
  try {
54989
- const stat7 = statSync4(this.file);
54990
- if (stat7.size >= METRICS_ROTATE_BYTES) {
55416
+ const stat8 = statSync4(this.file);
55417
+ if (stat8.size >= METRICS_ROTATE_BYTES) {
54991
55418
  const rotated = this.file.replace(/\.jsonl$/, ".1.jsonl");
54992
55419
  renameSync4(this.file, rotated);
54993
55420
  }
@@ -55281,15 +55708,15 @@ __export(completionProofProbe_exports, {
55281
55708
  gatherGitAttestation: () => gatherGitAttestation,
55282
55709
  harnessManifest: () => harnessManifest
55283
55710
  });
55284
- import { execFile as execFile5 } from "node:child_process";
55285
- import { promisify as promisify4 } from "node:util";
55711
+ import { execFile as execFile6 } from "node:child_process";
55712
+ import { promisify as promisify5 } from "node:util";
55286
55713
  async function readHarnessVersion() {
55287
55714
  if (cachedHarnessVersion !== null) return cachedHarnessVersion;
55288
55715
  try {
55289
- const { readFile: readFile9 } = await import("node:fs/promises");
55716
+ const { readFile: readFile11 } = await import("node:fs/promises");
55290
55717
  const { fileURLToPath: fileURLToPath4 } = await import("node:url");
55291
55718
  const pkgPath = fileURLToPath4(new URL("../../../package.json", import.meta.url));
55292
- const parsed = JSON.parse(await readFile9(pkgPath, "utf8"));
55719
+ const parsed = JSON.parse(await readFile11(pkgPath, "utf8"));
55293
55720
  if (typeof parsed.version === "string" && parsed.version.length > 0) {
55294
55721
  return cachedHarnessVersion = parsed.version;
55295
55722
  }
@@ -55313,7 +55740,7 @@ async function harnessManifest(env = process.env) {
55313
55740
  }
55314
55741
  async function git5(cwd, args) {
55315
55742
  try {
55316
- const { stdout } = await execFileAsync4("git", ["-C", cwd, ...args], {
55743
+ const { stdout } = await execFileAsync5("git", ["-C", cwd, ...args], {
55317
55744
  maxBuffer: 32 * 1024 * 1024,
55318
55745
  windowsHide: true
55319
55746
  });
@@ -55355,7 +55782,7 @@ function activeTaskContractSnapshot() {
55355
55782
  return void 0;
55356
55783
  }
55357
55784
  }
55358
- var HARNESS_VERSION_FALLBACK, ADAPTER_IDS, cachedHarnessVersion, execFileAsync4;
55785
+ var HARNESS_VERSION_FALLBACK, ADAPTER_IDS, cachedHarnessVersion, execFileAsync5;
55359
55786
  var init_completionProofProbe = __esm({
55360
55787
  "src/cli/kraken/completionProofProbe.ts"() {
55361
55788
  "use strict";
@@ -55363,7 +55790,7 @@ var init_completionProofProbe = __esm({
55363
55790
  HARNESS_VERSION_FALLBACK = "2.13.0";
55364
55791
  ADAPTER_IDS = ["node", "python", "rust", "go", "java", "dotnet"];
55365
55792
  cachedHarnessVersion = null;
55366
- execFileAsync4 = promisify4(execFile5);
55793
+ execFileAsync5 = promisify5(execFile6);
55367
55794
  }
55368
55795
  });
55369
55796
 
@@ -55467,7 +55894,7 @@ var init_completionProofAttestation = __esm({
55467
55894
  // src/cli/kraken/completionProofPersist.ts
55468
55895
  import { open, rename as rename2, rm as rm2 } from "node:fs/promises";
55469
55896
  import { randomBytes as randomBytes5 } from "node:crypto";
55470
- import path62 from "node:path";
55897
+ import path63 from "node:path";
55471
55898
  function isTruthyFlag2(v) {
55472
55899
  const n = v?.trim().toLowerCase();
55473
55900
  return n === "1" || n === "true" || n === "yes" || n === "on";
@@ -55509,8 +55936,8 @@ function isWindowsRenameBlock(err) {
55509
55936
  return code === "EPERM" || code === "ENOTEMPTY" || code === "EEXIST";
55510
55937
  }
55511
55938
  async function writeFileAtomic(target, data) {
55512
- const dir = path62.dirname(target);
55513
- const tmp = path62.join(dir, `.${path62.basename(target)}.${randomBytes5(6).toString("hex")}.tmp`);
55939
+ const dir = path63.dirname(target);
55940
+ const tmp = path63.join(dir, `.${path63.basename(target)}.${randomBytes5(6).toString("hex")}.tmp`);
55514
55941
  let fh = null;
55515
55942
  try {
55516
55943
  fh = await open(tmp, "w");
@@ -55555,8 +55982,8 @@ var init_completionProofPersist = __esm({
55555
55982
  });
55556
55983
 
55557
55984
  // src/cli/kraken/completionProof.ts
55558
- import { mkdir as mkdir3 } from "node:fs/promises";
55559
- import path63 from "node:path";
55985
+ import { mkdir as mkdir4 } from "node:fs/promises";
55986
+ import path64 from "node:path";
55560
55987
  function verdictOf(evaluation) {
55561
55988
  return evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS");
55562
55989
  }
@@ -55701,8 +56128,8 @@ async function writeCompletionProofDetailed(evaluation, options = {}) {
55701
56128
  const mode = options.persistenceMode ?? activeProofPersistenceMode();
55702
56129
  try {
55703
56130
  const baseDir = options.baseDir ?? process.cwd();
55704
- const dir = path63.join(baseDir, ".zelari");
55705
- await mkdir3(dir, { recursive: true });
56131
+ const dir = path64.join(baseDir, ".zelari");
56132
+ await mkdir4(dir, { recursive: true });
55706
56133
  const requested = options.attestation ?? {};
55707
56134
  const plan = requested.skipProbes || requested.verificationPlan !== void 0 ? void 0 : await defaultVerificationPlanSnapshot(baseDir);
55708
56135
  const wrapper = await buildAttestedWrapper(
@@ -55721,8 +56148,8 @@ async function writeCompletionProofDetailed(evaluation, options = {}) {
55721
56148
  baseDir
55722
56149
  );
55723
56150
  const rendered = renderCompletionProof(evaluation, options.meta ?? {}, wrapper.attestation);
55724
- const markdownPath = path63.join(dir, "completion-proof.md");
55725
- const jsonPath = path63.join(dir, "completion-proof.json");
56151
+ const markdownPath = path64.join(dir, "completion-proof.md");
56152
+ const jsonPath = path64.join(dir, "completion-proof.json");
55726
56153
  await writeFileAtomic(markdownPath, rendered.markdown);
55727
56154
  await writeFileAtomic(jsonPath, rendered.json);
55728
56155
  return { paths: { markdownPath, jsonPath }, mode, requiredBlockReason: null };
@@ -55832,12 +56259,12 @@ var init_askUserTimeout = __esm({
55832
56259
  // src/cli/state/fileStateStore.ts
55833
56260
  import { createHash as createHash17, randomUUID as randomUUID5 } from "node:crypto";
55834
56261
  import { promises as fs26 } from "node:fs";
55835
- import * as path64 from "node:path";
56262
+ import * as path65 from "node:path";
55836
56263
  function shortId() {
55837
56264
  return randomUUID5().replace(/-/g, "").slice(0, 12);
55838
56265
  }
55839
56266
  async function writeJsonAtomic(filePath, data) {
55840
- await fs26.mkdir(path64.dirname(filePath), { recursive: true });
56267
+ await fs26.mkdir(path65.dirname(filePath), { recursive: true });
55841
56268
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
55842
56269
  await fs26.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
55843
56270
  await fs26.rename(tmp, filePath);
@@ -55898,11 +56325,11 @@ var init_fileStateStore = __esm({
55898
56325
  indexPath = "";
55899
56326
  async init(projectRoot) {
55900
56327
  this.root = projectRoot;
55901
- this.stateDir = path64.join(projectRoot, ".zelari", "state");
55902
- this.commitsDir = path64.join(this.stateDir, "commits");
55903
- this.artifactsDir = path64.join(this.stateDir, "artifacts");
55904
- this.headPath = path64.join(this.stateDir, "HEAD.json");
55905
- this.indexPath = path64.join(this.stateDir, "index.jsonl");
56328
+ this.stateDir = path65.join(projectRoot, ".zelari", "state");
56329
+ this.commitsDir = path65.join(this.stateDir, "commits");
56330
+ this.artifactsDir = path65.join(this.stateDir, "artifacts");
56331
+ this.headPath = path65.join(this.stateDir, "HEAD.json");
56332
+ this.indexPath = path65.join(this.stateDir, "index.jsonl");
55906
56333
  await fs26.mkdir(this.commitsDir, { recursive: true });
55907
56334
  await fs26.mkdir(this.artifactsDir, { recursive: true });
55908
56335
  }
@@ -55915,13 +56342,13 @@ var init_fileStateStore = __esm({
55915
56342
  const discoveries = input.discoveries ?? [];
55916
56343
  const parent = await this.head();
55917
56344
  const id3 = shortId();
55918
- const artifactRel = path64.join("artifacts", id3);
55919
- const artifactAbs = path64.join(this.artifactsDir, id3);
56345
+ const artifactRel = path65.join("artifacts", id3);
56346
+ const artifactAbs = path65.join(this.artifactsDir, id3);
55920
56347
  await fs26.mkdir(artifactAbs, { recursive: true });
55921
56348
  const summary = defaultSummary(input, discoveries);
55922
- await fs26.writeFile(path64.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
55923
- await writeJsonAtomic(path64.join(artifactAbs, "discoveries.json"), discoveries);
55924
- await writeJsonAtomic(path64.join(artifactAbs, "verification.json"), input.verification);
56349
+ await fs26.writeFile(path65.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
56350
+ await writeJsonAtomic(path65.join(artifactAbs, "discoveries.json"), discoveries);
56351
+ await writeJsonAtomic(path65.join(artifactAbs, "verification.json"), input.verification);
55925
56352
  const meta3 = {
55926
56353
  id: id3,
55927
56354
  parentId: parent?.id ?? null,
@@ -55933,14 +56360,14 @@ var init_fileStateStore = __esm({
55933
56360
  workspaceCheckpointId: input.workspaceCheckpointId,
55934
56361
  verification: {
55935
56362
  ...input.verification,
55936
- reportPath: input.verification.reportPath ?? path64.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
56363
+ reportPath: input.verification.reportPath ?? path65.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
55937
56364
  },
55938
56365
  changedPaths: input.changedPaths ?? [],
55939
56366
  stablePromptHash: input.stablePromptHash,
55940
56367
  discoveryCount: discoveries.length,
55941
56368
  artifactDir: artifactRel.replace(/\\/g, "/")
55942
56369
  };
55943
- await writeJsonAtomic(path64.join(this.commitsDir, `${id3}.json`), meta3);
56370
+ await writeJsonAtomic(path65.join(this.commitsDir, `${id3}.json`), meta3);
55944
56371
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
55945
56372
  await fs26.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
55946
56373
  return stripStored(meta3);
@@ -55951,7 +56378,7 @@ var init_fileStateStore = __esm({
55951
56378
  return this.get(head.id);
55952
56379
  }
55953
56380
  async get(id3) {
55954
- const stored = await readJsonFile(path64.join(this.commitsDir, `${id3}.json`));
56381
+ const stored = await readJsonFile(path65.join(this.commitsDir, `${id3}.json`));
55955
56382
  return stored ? stripStored(stored) : null;
55956
56383
  }
55957
56384
  async list(limit = 20) {
@@ -55990,9 +56417,9 @@ var init_fileStateStore = __esm({
55990
56417
  async loadDiscoveries(id3) {
55991
56418
  const meta3 = id3 ? await this.get(id3) : await this.head();
55992
56419
  if (!meta3) return [];
55993
- const stored = await readJsonFile(path64.join(this.commitsDir, `${meta3.id}.json`));
56420
+ const stored = await readJsonFile(path65.join(this.commitsDir, `${meta3.id}.json`));
55994
56421
  if (!stored?.artifactDir) return [];
55995
- const discPath = path64.join(this.stateDir, stored.artifactDir, "discoveries.json");
56422
+ const discPath = path65.join(this.stateDir, stored.artifactDir, "discoveries.json");
55996
56423
  return await readJsonFile(discPath) ?? [];
55997
56424
  }
55998
56425
  async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
@@ -56595,10 +57022,10 @@ var init_mode = __esm({
56595
57022
 
56596
57023
  // src/cli/headless.ts
56597
57024
  import { readFileSync as readFileSync24 } from "node:fs";
56598
- import path65 from "node:path";
57025
+ import path66 from "node:path";
56599
57026
  function resolveHeadlessCwd(opts) {
56600
57027
  const raw = typeof opts.cwd === "string" ? opts.cwd.trim() : "";
56601
- return path65.resolve(raw.length > 0 ? raw : process.cwd());
57028
+ return path66.resolve(raw.length > 0 ? raw : process.cwd());
56602
57029
  }
56603
57030
  function defaultProfileForMode(mode) {
56604
57031
  switch (mode) {
@@ -57700,7 +58127,7 @@ var init_planDetect = __esm({
57700
58127
  // src/cli/memory/legacyImport.ts
57701
58128
  import { createHash as createHash18 } from "node:crypto";
57702
58129
  import { promises as fs27 } from "node:fs";
57703
- import * as path66 from "node:path";
58130
+ import * as path67 from "node:path";
57704
58131
  function sourceId(fact, line) {
57705
58132
  return `jsonl:${fact.id ?? createHash18("sha256").update(line).digest("hex")}`;
57706
58133
  }
@@ -57718,7 +58145,7 @@ function timestamp(value) {
57718
58145
  }
57719
58146
  async function importLegacyMemoryLog(backend, service) {
57720
58147
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
57721
- const logPath = path66.join(path66.dirname(backend.databasePath), "log.jsonl");
58148
+ const logPath = path67.join(path67.dirname(backend.databasePath), "log.jsonl");
57722
58149
  let raw;
57723
58150
  try {
57724
58151
  raw = await fs27.readFile(logPath, "utf8");
@@ -57901,7 +58328,7 @@ var init_sqliteCodec = __esm({
57901
58328
  // src/cli/memory/sqliteRpc.ts
57902
58329
  import { existsSync as existsSync36 } from "node:fs";
57903
58330
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
57904
- import * as path67 from "node:path";
58331
+ import * as path68 from "node:path";
57905
58332
  import { Worker } from "node:worker_threads";
57906
58333
  function isBusy(error51) {
57907
58334
  const candidate = error51;
@@ -57910,10 +58337,10 @@ function isBusy(error51) {
57910
58337
  );
57911
58338
  }
57912
58339
  function resolveWorkerUrl() {
57913
- const here = path67.dirname(fileURLToPath2(import.meta.url));
57914
- const direct = path67.join(here, "sqliteWorker.mjs");
58340
+ const here = path68.dirname(fileURLToPath2(import.meta.url));
58341
+ const direct = path68.join(here, "sqliteWorker.mjs");
57915
58342
  if (existsSync36(direct)) return pathToFileURL2(direct);
57916
- return pathToFileURL2(path67.join(here, "memory", "sqliteWorker.mjs"));
58343
+ return pathToFileURL2(path68.join(here, "memory", "sqliteWorker.mjs"));
57917
58344
  }
57918
58345
  var SqliteWorkerRpc;
57919
58346
  var init_sqliteRpc = __esm({
@@ -58202,7 +58629,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
58202
58629
  // src/cli/memory/sqliteBackend.ts
58203
58630
  import { createHash as createHash19, randomUUID as randomUUID6 } from "node:crypto";
58204
58631
  import { promises as fs28 } from "node:fs";
58205
- import * as path68 from "node:path";
58632
+ import * as path69 from "node:path";
58206
58633
  function boundedLimit(value, fallback = 50) {
58207
58634
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
58208
58635
  }
@@ -58264,20 +58691,20 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58264
58691
  try {
58265
58692
  resolved = await fs28.realpath(projectRoot);
58266
58693
  } catch {
58267
- resolved = path68.resolve(projectRoot);
58694
+ resolved = path69.resolve(projectRoot);
58268
58695
  }
58269
58696
  if (this.initialized && resolved === this.projectRoot) return;
58270
58697
  if (this.initialized) await this.close();
58271
58698
  const filename = this.options.filename ?? "memory.db";
58272
- if (path68.basename(filename) !== filename || filename === "." || filename === "..") {
58699
+ if (path69.basename(filename) !== filename || filename === "." || filename === "..") {
58273
58700
  throw new Error("SQLite memory filename must not contain a path.");
58274
58701
  }
58275
- const zelariDirectory = path68.join(resolved, ".zelari");
58276
- const directory = path68.join(zelariDirectory, "memory");
58702
+ const zelariDirectory = path69.join(resolved, ".zelari");
58703
+ const directory = path69.join(zelariDirectory, "memory");
58277
58704
  for (const candidate of [zelariDirectory, directory]) {
58278
- let stat7;
58705
+ let stat8;
58279
58706
  try {
58280
- stat7 = await fs28.lstat(candidate);
58707
+ stat8 = await fs28.lstat(candidate);
58281
58708
  } catch (error51) {
58282
58709
  if (error51.code !== "ENOENT") throw error51;
58283
58710
  try {
@@ -58285,19 +58712,19 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58285
58712
  } catch (mkdirError) {
58286
58713
  if (mkdirError.code !== "EEXIST") throw mkdirError;
58287
58714
  }
58288
- stat7 = await fs28.lstat(candidate);
58715
+ stat8 = await fs28.lstat(candidate);
58289
58716
  }
58290
- if (stat7.isSymbolicLink() || !stat7.isDirectory()) {
58717
+ if (stat8.isSymbolicLink() || !stat8.isDirectory()) {
58291
58718
  throw new Error(`Memory directory is not a real directory: ${candidate}`);
58292
58719
  }
58293
58720
  }
58294
58721
  const canonicalDirectory = await fs28.realpath(directory);
58295
- const relativeDirectory = path68.relative(resolved, canonicalDirectory);
58296
- if (relativeDirectory.startsWith("..") || path68.isAbsolute(relativeDirectory)) {
58722
+ const relativeDirectory = path69.relative(resolved, canonicalDirectory);
58723
+ if (relativeDirectory.startsWith("..") || path69.isAbsolute(relativeDirectory)) {
58297
58724
  throw new Error("SQLite memory directory resolves outside the active project.");
58298
58725
  }
58299
58726
  this.projectRoot = resolved;
58300
- this.databasePath = path68.join(canonicalDirectory, filename);
58727
+ this.databasePath = path69.join(canonicalDirectory, filename);
58301
58728
  const opened = await this.rpc.open({
58302
58729
  dbPath: this.databasePath,
58303
58730
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -58830,7 +59257,7 @@ __export(serviceFactory_exports, {
58830
59257
  });
58831
59258
  import { createHash as createHash20 } from "node:crypto";
58832
59259
  import { promises as fs29 } from "node:fs";
58833
- import * as path69 from "node:path";
59260
+ import * as path70 from "node:path";
58834
59261
  function isMemoryV2Enabled(env = process.env) {
58835
59262
  if (env.ZELARI_MEMORY === "0") return false;
58836
59263
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -58851,7 +59278,7 @@ async function canonicalProjectId(projectRoot) {
58851
59278
  try {
58852
59279
  canonical = await fs29.realpath(projectRoot);
58853
59280
  } catch {
58854
- canonical = path69.resolve(projectRoot);
59281
+ canonical = path70.resolve(projectRoot);
58855
59282
  }
58856
59283
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
58857
59284
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -59553,8 +59980,8 @@ function readPlan(ctx) {
59553
59980
  } catch {
59554
59981
  }
59555
59982
  }
59556
- const path99 = workspaceFile(ctx.rootDir, "plan");
59557
- const doc = ctx.storage.readIfExists(path99);
59983
+ const path100 = workspaceFile(ctx.rootDir, "plan");
59984
+ const doc = ctx.storage.readIfExists(path100);
59558
59985
  if (!doc) return { phases: [], tasks: [], milestones: [] };
59559
59986
  const meta3 = doc.meta;
59560
59987
  return {
@@ -59735,7 +60162,7 @@ function addMilestoneRecord(ctx, summary, input) {
59735
60162
  dueDate: input.dueDate,
59736
60163
  targetVersion: version2
59737
60164
  });
59738
- const path99 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60165
+ const path100 = join31(ctx.rootDir, "milestones", `${id3}.md`);
59739
60166
  const meta3 = {
59740
60167
  kind: "milestone",
59741
60168
  id: id3,
@@ -59752,7 +60179,7 @@ function addMilestoneRecord(ctx, summary, input) {
59752
60179
  `Target version: ${version2}`,
59753
60180
  ""
59754
60181
  ].join("\n");
59755
- ctx.storage.write(path99, meta3, body);
60182
+ ctx.storage.write(path100, meta3, body);
59756
60183
  return { id: id3, created: true };
59757
60184
  }
59758
60185
  function readPlanSummary(ctx) {
@@ -59956,7 +60383,7 @@ function addIdeaStub(ctx) {
59956
60383
  const tags = args["tags"] ?? [];
59957
60384
  const category = args["category"] ?? "General";
59958
60385
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
59959
- const path99 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60386
+ const path100 = workspaceArtifact(ctx.rootDir, "decisions", id3);
59960
60387
  const meta3 = {
59961
60388
  kind: "adr",
59962
60389
  status: "proposed",
@@ -59982,7 +60409,7 @@ function addIdeaStub(ctx) {
59982
60409
  ...consequences.map((c) => `- ${c}`),
59983
60410
  ""
59984
60411
  ].join("\n");
59985
- ctx.storage.write(path99, meta3, body);
60412
+ ctx.storage.write(path100, meta3, body);
59986
60413
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
59987
60414
  });
59988
60415
  }
@@ -60064,14 +60491,14 @@ function createDocumentStub(ctx) {
60064
60491
  ctx.storage.write(risksPath, riskMeta, content);
60065
60492
  return `Document "${title}" created at risks.md (workspace root).`;
60066
60493
  }
60067
- const path99 = workspaceArtifact(ctx.rootDir, "docs", slug);
60494
+ const path100 = workspaceArtifact(ctx.rootDir, "docs", slug);
60068
60495
  const meta3 = {
60069
60496
  kind: "doc",
60070
60497
  id: slug,
60071
60498
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
60072
60499
  tags
60073
60500
  };
60074
- ctx.storage.write(path99, meta3, content);
60501
+ ctx.storage.write(path100, meta3, content);
60075
60502
  return `Document "${title}" created at docs/${slug}.md.`;
60076
60503
  });
60077
60504
  }
@@ -60324,11 +60751,11 @@ var init_httpTransport = __esm({
60324
60751
  const sid = this.sessionId;
60325
60752
  this.sessionId = null;
60326
60753
  if (!sid) return;
60327
- const headers2 = {
60754
+ const headers3 = {
60328
60755
  ...this.opts.headers ?? {},
60329
60756
  "mcp-session-id": sid
60330
60757
  };
60331
- void fetch(this.opts.url, { method: "DELETE", headers: headers2 }).catch(() => {
60758
+ void fetch(this.opts.url, { method: "DELETE", headers: headers3 }).catch(() => {
60332
60759
  });
60333
60760
  }
60334
60761
  // ── internals ────────────────────────────────────────────────────────
@@ -60338,15 +60765,15 @@ var init_httpTransport = __esm({
60338
60765
  const timer = setTimeout(() => ac.abort(), timeoutMs2 + ABORT_GRACE_MS);
60339
60766
  const hadSession = this.sessionId !== null;
60340
60767
  try {
60341
- const headers2 = {
60768
+ const headers3 = {
60342
60769
  "content-type": "application/json",
60343
60770
  accept: "application/json, text/event-stream",
60344
60771
  ...this.opts.headers ?? {}
60345
60772
  };
60346
- if (this.sessionId) headers2["mcp-session-id"] = this.sessionId;
60773
+ if (this.sessionId) headers3["mcp-session-id"] = this.sessionId;
60347
60774
  const res = await fetch(this.opts.url, {
60348
60775
  method: "POST",
60349
- headers: headers2,
60776
+ headers: headers3,
60350
60777
  signal: ac.signal,
60351
60778
  body: JSON.stringify({ jsonrpc: "2.0", ...msg })
60352
60779
  });
@@ -60696,10 +61123,10 @@ function getUserMcpPath() {
60696
61123
  function getProjectMcpPath(projectRoot) {
60697
61124
  return join32(projectRoot, ".zelari", "mcp.json");
60698
61125
  }
60699
- function readFile7(path99) {
60700
- if (!existsSync42(path99)) return {};
61126
+ function readFile9(path100) {
61127
+ if (!existsSync42(path100)) return {};
60701
61128
  try {
60702
- const parsed = JSON.parse(readFileSync30(path99, "utf8"));
61129
+ const parsed = JSON.parse(readFileSync30(path100, "utf8"));
60703
61130
  const out = {};
60704
61131
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
60705
61132
  const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
@@ -60721,17 +61148,17 @@ function readFile7(path99) {
60721
61148
  return {};
60722
61149
  }
60723
61150
  }
60724
- function writeFile3(path99, servers) {
60725
- mkdirSync17(dirname9(path99), { recursive: true });
61151
+ function writeFile3(path100, servers) {
61152
+ mkdirSync17(dirname9(path100), { recursive: true });
60726
61153
  const body = { mcpServers: servers };
60727
- writeFileSync19(path99, `${JSON.stringify(body, null, 2)}
61154
+ writeFileSync19(path100, `${JSON.stringify(body, null, 2)}
60728
61155
  `, "utf8");
60729
61156
  }
60730
61157
  function listMcpServers(projectRoot) {
60731
61158
  const userPath = getUserMcpPath();
60732
- const userServers = readFile7(userPath);
61159
+ const userServers = readFile9(userPath);
60733
61160
  const projectPath = projectRoot && projectRoot.trim() ? getProjectMcpPath(projectRoot.trim()) : null;
60734
- const projectServers = projectPath ? readFile7(projectPath) : {};
61161
+ const projectServers = projectPath ? readFile9(projectPath) : {};
60735
61162
  const servers = [];
60736
61163
  for (const [name, cfg] of Object.entries(userServers)) {
60737
61164
  servers.push({ name, ...cfg, scope: "user", path: userPath });
@@ -60762,9 +61189,9 @@ function upsertMcpServer(opts) {
60762
61189
  error: "either command (stdio) or url (http) is required"
60763
61190
  };
60764
61191
  }
60765
- let path99;
61192
+ let path100;
60766
61193
  if (opts.scope === "user") {
60767
- path99 = getUserMcpPath();
61194
+ path100 = getUserMcpPath();
60768
61195
  } else {
60769
61196
  const root = opts.projectRoot?.trim();
60770
61197
  if (!root) {
@@ -60773,9 +61200,9 @@ function upsertMcpServer(opts) {
60773
61200
  error: "projectRoot required for project scope (Open Folder first)"
60774
61201
  };
60775
61202
  }
60776
- path99 = getProjectMcpPath(root);
61203
+ path100 = getProjectMcpPath(root);
60777
61204
  }
60778
- const current = readFile7(path99);
61205
+ const current = readFile9(path100);
60779
61206
  current[name] = {
60780
61207
  command: hasCommand ? opts.config.command.trim() : void 0,
60781
61208
  args: opts.config.args,
@@ -60786,21 +61213,21 @@ function upsertMcpServer(opts) {
60786
61213
  serial: opts.config.serial,
60787
61214
  enabled: opts.config.enabled !== false
60788
61215
  };
60789
- writeFile3(path99, current);
60790
- return { ok: true, path: path99 };
61216
+ writeFile3(path100, current);
61217
+ return { ok: true, path: path100 };
60791
61218
  }
60792
61219
  function removeMcpServer(opts) {
60793
- const path99 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
60794
- if (!path99) {
61220
+ const path100 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61221
+ if (!path100) {
60795
61222
  return { ok: false, error: "projectRoot required for project scope" };
60796
61223
  }
60797
- const current = readFile7(path99);
61224
+ const current = readFile9(path100);
60798
61225
  if (!(opts.name in current)) {
60799
- return { ok: false, error: `Server "${opts.name}" not found in ${path99}` };
61226
+ return { ok: false, error: `Server "${opts.name}" not found in ${path100}` };
60800
61227
  }
60801
61228
  delete current[opts.name];
60802
- writeFile3(path99, current);
60803
- return { ok: true, path: path99 };
61229
+ writeFile3(path100, current);
61230
+ return { ok: true, path: path100 };
60804
61231
  }
60805
61232
  var init_mcpConfigIo = __esm({
60806
61233
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -61269,12 +61696,12 @@ __export(agentsMd_exports, {
61269
61696
  import { existsSync as existsSync44, readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "node:fs";
61270
61697
  import { createHash as createHash21 } from "node:crypto";
61271
61698
  import { join as join34 } from "node:path";
61272
- import { readFile as readFile8 } from "node:fs/promises";
61699
+ import { readFile as readFile10 } from "node:fs/promises";
61273
61700
  async function readPackageJson3(projectRoot) {
61274
- const path99 = join34(projectRoot, "package.json");
61275
- if (!existsSync44(path99)) return null;
61701
+ const path100 = join34(projectRoot, "package.json");
61702
+ if (!existsSync44(path100)) return null;
61276
61703
  try {
61277
- return JSON.parse(await readFile8(path99, "utf8"));
61704
+ return JSON.parse(await readFile10(path100, "utf8"));
61278
61705
  } catch {
61279
61706
  return null;
61280
61707
  }
@@ -61356,9 +61783,9 @@ async function genBuild(ctx) {
61356
61783
  ].join("\n");
61357
61784
  }
61358
61785
  async function genOpenQuestions(ctx) {
61359
- const path99 = join34(ctx.rootDir, "risks.md");
61360
- if (!existsSync44(path99)) return "_No open questions._";
61361
- const content = readFileSync32(path99, "utf8");
61786
+ const path100 = join34(ctx.rootDir, "risks.md");
61787
+ if (!existsSync44(path100)) return "_No open questions._";
61788
+ const content = readFileSync32(path100, "utf8");
61362
61789
  const lines = content.split("\n");
61363
61790
  const questions = [];
61364
61791
  let currentTitle = "";
@@ -61632,9 +62059,9 @@ function versionKey(value) {
61632
62059
  function firstString2(v) {
61633
62060
  return typeof v === "string" && v.trim().length > 0 ? v : null;
61634
62061
  }
61635
- function readFileSyncSafe(path99) {
62062
+ function readFileSyncSafe(path100) {
61636
62063
  try {
61637
- return readFileSync33(path99, "utf8");
62064
+ return readFileSync33(path100, "utf8");
61638
62065
  } catch {
61639
62066
  return null;
61640
62067
  }
@@ -61882,7 +62309,7 @@ __export(evidenceFromSpine_exports, {
61882
62309
  evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
61883
62310
  });
61884
62311
  import { existsSync as existsSync47, readFileSync as readFileSync35 } from "node:fs";
61885
- import path70 from "node:path";
62312
+ import path71 from "node:path";
61886
62313
  function asRecord2(v) {
61887
62314
  return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
61888
62315
  }
@@ -61920,7 +62347,7 @@ function evidenceRefsFromEventLines(lines) {
61920
62347
  }
61921
62348
  function collectSessionEvidenceRefs(sessionId2) {
61922
62349
  try {
61923
- const file2 = path70.join(sessionsDir(), sessionId2, "events.jsonl");
62350
+ const file2 = path71.join(sessionsDir(), sessionId2, "events.jsonl");
61924
62351
  if (!existsSync47(file2)) return [];
61925
62352
  return evidenceRefsFromEventLines(readFileSync35(file2, "utf8").split("\n"));
61926
62353
  } catch {
@@ -62170,8 +62597,8 @@ async function runPostCouncilHook(ctx, options) {
62170
62597
  sources: scope.sources
62171
62598
  } : void 0
62172
62599
  });
62173
- const path99 = writeCouncilCompletion(ctx.rootDir, completion);
62174
- completionHook = { ran: true, path: path99, completion };
62600
+ const path100 = writeCouncilCompletion(ctx.rootDir, completion);
62601
+ completionHook = { ran: true, path: path100, completion };
62175
62602
  } catch (err) {
62176
62603
  completionHook = {
62177
62604
  ran: true,
@@ -62216,7 +62643,7 @@ import {
62216
62643
  writeFileSync as writeFileSync22,
62217
62644
  mkdirSync as mkdirSync18
62218
62645
  } from "node:fs";
62219
- import path71 from "node:path";
62646
+ import path72 from "node:path";
62220
62647
  var FeedbackStore;
62221
62648
  var init_councilFeedback = __esm({
62222
62649
  "src/cli/councilFeedback.ts"() {
@@ -62333,7 +62760,7 @@ var init_councilFeedback = __esm({
62333
62760
  }
62334
62761
  }
62335
62762
  save() {
62336
- mkdirSync18(path71.dirname(this.file), { recursive: true });
62763
+ mkdirSync18(path72.dirname(this.file), { recursive: true });
62337
62764
  writeFileSync22(
62338
62765
  this.file,
62339
62766
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -62408,12 +62835,12 @@ __export(ledger_exports, {
62408
62835
  readLedger: () => readLedger
62409
62836
  });
62410
62837
  import { appendFileSync as appendFileSync4, existsSync as existsSync50, mkdirSync as mkdirSync19, readFileSync as readFileSync38 } from "node:fs";
62411
- import path72 from "node:path";
62838
+ import path73 from "node:path";
62412
62839
  function evolutionMode(env = process.env) {
62413
62840
  return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
62414
62841
  }
62415
62842
  function ledgerPath(cwd) {
62416
- return path72.join(cwd, LEDGER_REL);
62843
+ return path73.join(cwd, LEDGER_REL);
62417
62844
  }
62418
62845
  function appendLedgerEntry(cwd, entry) {
62419
62846
  if (evolutionMode() === "0") {
@@ -62421,7 +62848,7 @@ function appendLedgerEntry(cwd, entry) {
62421
62848
  }
62422
62849
  try {
62423
62850
  const file2 = ledgerPath(cwd);
62424
- mkdirSync19(path72.dirname(file2), { recursive: true });
62851
+ mkdirSync19(path73.dirname(file2), { recursive: true });
62425
62852
  appendFileSync4(file2, `${JSON.stringify(entry)}
62426
62853
  `, "utf8");
62427
62854
  return { written: true, path: file2 };
@@ -62522,7 +62949,7 @@ var init_ledger = __esm({
62522
62949
  "src/cli/evolution/ledger.ts"() {
62523
62950
  "use strict";
62524
62951
  EVOLUTION_ENV = "ZELARI_EVOLUTION";
62525
- LEDGER_REL = path72.join(".zelari", "evolution", "ledger.jsonl");
62952
+ LEDGER_REL = path73.join(".zelari", "evolution", "ledger.jsonl");
62526
62953
  TIER_WEIGHTS = {
62527
62954
  build: 1,
62528
62955
  "tool-output": 1,
@@ -62664,7 +63091,7 @@ __export(fileBackend_exports, {
62664
63091
  });
62665
63092
  import { randomUUID as randomUUID7 } from "node:crypto";
62666
63093
  import { promises as fs31 } from "node:fs";
62667
- import * as path73 from "node:path";
63094
+ import * as path74 from "node:path";
62668
63095
  function tokenize2(text) {
62669
63096
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
62670
63097
  }
@@ -62717,8 +63144,8 @@ var init_fileBackend = __esm({
62717
63144
  logPath = "";
62718
63145
  memoryDir = "";
62719
63146
  async init(projectRoot) {
62720
- this.memoryDir = path73.join(projectRoot, ".zelari", "memory");
62721
- this.logPath = path73.join(this.memoryDir, "log.jsonl");
63147
+ this.memoryDir = path74.join(projectRoot, ".zelari", "memory");
63148
+ this.logPath = path74.join(this.memoryDir, "log.jsonl");
62722
63149
  await fs31.mkdir(this.memoryDir, { recursive: true });
62723
63150
  }
62724
63151
  async add(content, metadata2 = {}, graph) {
@@ -62791,12 +63218,12 @@ var init_fileBackend = __esm({
62791
63218
 
62792
63219
  // src/cli/traceStore.ts
62793
63220
  import { promises as fs32 } from "node:fs";
62794
- import * as path74 from "node:path";
63221
+ import * as path75 from "node:path";
62795
63222
  function traceDir(projectRoot) {
62796
- return path74.join(projectRoot, ".zelari", "trace");
63223
+ return path75.join(projectRoot, ".zelari", "trace");
62797
63224
  }
62798
63225
  function tracePath(projectRoot, missionId) {
62799
- return path74.join(traceDir(projectRoot), `${missionId}.json`);
63226
+ return path75.join(traceDir(projectRoot), `${missionId}.json`);
62800
63227
  }
62801
63228
  async function saveTrace(projectRoot, missionId, entries) {
62802
63229
  const dir = traceDir(projectRoot);
@@ -62833,7 +63260,7 @@ __export(zelariMission_exports, {
62833
63260
  });
62834
63261
  import { randomUUID as randomUUID8 } from "node:crypto";
62835
63262
  import { promises as fs33 } from "node:fs";
62836
- import * as path75 from "node:path";
63263
+ import * as path76 from "node:path";
62837
63264
  function resolveMaxIterations(env = process.env) {
62838
63265
  const raw = env.ZELARI_MISSION_MAX_ITER;
62839
63266
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -62876,10 +63303,10 @@ function isMissionAutoStart(env = process.env) {
62876
63303
  return env.ZELARI_MISSION_AUTO === "1";
62877
63304
  }
62878
63305
  async function writeMissionState(projectRoot, state3) {
62879
- const dir = path75.join(projectRoot, ".zelari");
63306
+ const dir = path76.join(projectRoot, ".zelari");
62880
63307
  await fs33.mkdir(dir, { recursive: true });
62881
63308
  await fs33.writeFile(
62882
- path75.join(dir, "mission-state.json"),
63309
+ path76.join(dir, "mission-state.json"),
62883
63310
  JSON.stringify(state3, null, 2) + "\n",
62884
63311
  "utf8"
62885
63312
  );
@@ -63568,7 +63995,7 @@ function safeSocketPath(socketPath) {
63568
63995
  return socketPath.trim();
63569
63996
  }
63570
63997
  function startPermissionBroker(socketPath, handlers, opts) {
63571
- const path99 = safeSocketPath(socketPath);
63998
+ const path100 = safeSocketPath(socketPath);
63572
63999
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
63573
64000
  const sockets = /* @__PURE__ */ new Set();
63574
64001
  const server = createServer2((socket) => {
@@ -63668,10 +64095,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
63668
64095
  return new Promise((resolve9, reject) => {
63669
64096
  const onError = (err) => reject(err);
63670
64097
  server.once("error", onError);
63671
- server.listen(path99, () => {
64098
+ server.listen(path100, () => {
63672
64099
  server.removeListener("error", onError);
63673
64100
  resolve9({
63674
- socketPath: path99,
64101
+ socketPath: path100,
63675
64102
  stop: () => new Promise((res) => {
63676
64103
  for (const s of sockets) s.destroy();
63677
64104
  sockets.clear();
@@ -63682,7 +64109,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
63682
64109
  if (done) return;
63683
64110
  done = true;
63684
64111
  if (process.platform !== "win32") {
63685
- unlink(path99, () => res());
64112
+ unlink(path100, () => res());
63686
64113
  } else {
63687
64114
  res();
63688
64115
  }
@@ -63695,11 +64122,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
63695
64122
  });
63696
64123
  }
63697
64124
  function requestBrokerAsk(socketPath, ask, opts) {
63698
- const path99 = safeSocketPath(socketPath);
64125
+ const path100 = safeSocketPath(socketPath);
63699
64126
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
63700
64127
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
63701
64128
  return new Promise((resolve9, reject) => {
63702
- const socket = connect(path99);
64129
+ const socket = connect(path100);
63703
64130
  let buffer = "";
63704
64131
  let settled = false;
63705
64132
  const settle = (fn) => {
@@ -63714,7 +64141,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
63714
64141
  settle(
63715
64142
  () => reject(
63716
64143
  new Error(
63717
- `permission broker unavailable at "${path99}" (connect timed out after ${connectTimeoutMs}ms)`
64144
+ `permission broker unavailable at "${path100}" (connect timed out after ${connectTimeoutMs}ms)`
63718
64145
  )
63719
64146
  )
63720
64147
  );
@@ -64903,7 +65330,7 @@ var init_prereqChecks = __esm({
64903
65330
 
64904
65331
  // src/cli/plugins/prefs.ts
64905
65332
  import { existsSync as existsSync53, readFileSync as readFileSync40, writeFileSync as writeFileSync23, mkdirSync as mkdirSync20 } from "node:fs";
64906
- import path81 from "node:path";
65333
+ import path82 from "node:path";
64907
65334
  function getPluginPrefsPath() {
64908
65335
  return pluginsPrefsPath();
64909
65336
  }
@@ -64926,7 +65353,7 @@ function getPluginPrefs() {
64926
65353
  }
64927
65354
  function writePluginPrefs(prefs) {
64928
65355
  const file2 = getPluginPrefsPath();
64929
- mkdirSync20(path81.dirname(file2), { recursive: true });
65356
+ mkdirSync20(path82.dirname(file2), { recursive: true });
64930
65357
  writeFileSync23(file2, JSON.stringify(prefs, null, 2), {
64931
65358
  encoding: "utf-8",
64932
65359
  mode: 384
@@ -64964,7 +65391,7 @@ __export(registry_exports, {
64964
65391
  isBinaryOnPath: () => isBinaryOnPath
64965
65392
  });
64966
65393
  import { existsSync as existsSync54 } from "node:fs";
64967
- import path82 from "node:path";
65394
+ import path83 from "node:path";
64968
65395
  function detectLocalBin(bin) {
64969
65396
  return (cwd) => {
64970
65397
  try {
@@ -64982,7 +65409,7 @@ function isBinaryOnPath(bin, opts = {}) {
64982
65409
  const platform = opts.platform ?? process.platform;
64983
65410
  const exists = opts.exists ?? existsSync54;
64984
65411
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
64985
- const pathMod = platform === "win32" ? path82.win32 : path82.posix;
65412
+ const pathMod = platform === "win32" ? path83.win32 : path83.posix;
64986
65413
  const sep4 = platform === "win32" ? ";" : ":";
64987
65414
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
64988
65415
  const candidates = [bin];
@@ -65378,6 +65805,16 @@ function handleProviderPicker(ctx, openPicker) {
65378
65805
  function handleProviderCustom(ctx, opts) {
65379
65806
  const id3 = ctx.activeProviderSpec.id;
65380
65807
  try {
65808
+ if (opts.apiStyle) {
65809
+ if (id3 === "chatgpt" || id3 === "anthropic") {
65810
+ appendSystem(ctx.setMessages, `[provider] ${id3} has a fixed transport \u2014 nothing to select.`);
65811
+ return;
65812
+ }
65813
+ setApiStyleFor(id3, opts.apiStyle);
65814
+ const target = opts.apiStyle === "responses" ? "POST /responses" : "POST /chat/completions";
65815
+ appendSystem(ctx.setMessages, `[provider] ${id3} endpoint style set to ${opts.apiStyle} (${target})`);
65816
+ return;
65817
+ }
65381
65818
  if (opts.clear) {
65382
65819
  clearCustomEndpoint(id3);
65383
65820
  appendSystem(ctx.setMessages, `[provider] cleared custom endpoint for ${id3} \u2014 falling back to default`);
@@ -66077,7 +66514,7 @@ var init_policy = __esm({
66077
66514
 
66078
66515
  // src/cli/orchestration/facts.ts
66079
66516
  import { promises as fs43 } from "node:fs";
66080
- import path86 from "node:path";
66517
+ import path87 from "node:path";
66081
66518
  async function collectRepoFileCount(root = process.cwd()) {
66082
66519
  try {
66083
66520
  await fs43.readdir(root);
@@ -66097,7 +66534,7 @@ async function collectRepoFileCount(root = process.cwd()) {
66097
66534
  }
66098
66535
  for (const e of entries) {
66099
66536
  if (e.isDirectory()) {
66100
- if (!SKIP_DIRS.has(e.name)) queue.push(path86.join(dir, e.name));
66537
+ if (!SKIP_DIRS.has(e.name)) queue.push(path87.join(dir, e.name));
66101
66538
  } else if (e.isFile()) {
66102
66539
  count++;
66103
66540
  if (count > MAX_WALK_FILES) return count;
@@ -66195,7 +66632,7 @@ var init_streamScrub = __esm({
66195
66632
  });
66196
66633
 
66197
66634
  // src/cli/harnessState.ts
66198
- import path87 from "node:path";
66635
+ import path88 from "node:path";
66199
66636
  function asString4(v) {
66200
66637
  return typeof v === "string" ? v : "";
66201
66638
  }
@@ -66370,7 +66807,7 @@ function contractFor(t) {
66370
66807
  };
66371
66808
  }
66372
66809
  async function readHarnessState(sessionDir) {
66373
- const report = await readSessionLog(path87.join(sessionDir, "events.jsonl"));
66810
+ const report = await readSessionLog(path88.join(sessionDir, "events.jsonl"));
66374
66811
  return deriveHarnessState(report.events);
66375
66812
  }
66376
66813
  var init_harnessState = __esm({
@@ -66381,12 +66818,12 @@ var init_harnessState = __esm({
66381
66818
  });
66382
66819
 
66383
66820
  // src/cli/headless/harnessStateEmit.ts
66384
- import path88 from "node:path";
66821
+ import path89 from "node:path";
66385
66822
  async function emitHarnessStateEvent(opts) {
66386
66823
  if (opts.output !== "json") return;
66387
66824
  try {
66388
66825
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
66389
- const state3 = await readHarnessState(path88.join(sessionsDir2, opts.spine.sessionId));
66826
+ const state3 = await readHarnessState(path89.join(sessionsDir2, opts.spine.sessionId));
66390
66827
  opts.emitEvent({ type: "harness_state", ...state3 });
66391
66828
  } catch (err) {
66392
66829
  const msg = err instanceof Error ? err.message : String(err);
@@ -66943,13 +67380,13 @@ var init_verifierLifecycle = __esm({
66943
67380
 
66944
67381
  // src/cli/extensions/sandboxedFs.ts
66945
67382
  import { promises as fsp } from "node:fs";
66946
- import path89 from "node:path";
67383
+ import path90 from "node:path";
66947
67384
  function errText(prefix, p3, err) {
66948
67385
  const msg = err instanceof Error ? err.message : String(err);
66949
67386
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
66950
67387
  }
66951
67388
  function bindSandboxedFs(root) {
66952
- const resolvedRoot = path89.resolve(root);
67389
+ const resolvedRoot = path90.resolve(root);
66953
67390
  return {
66954
67391
  root: resolvedRoot,
66955
67392
  async readFile(relativePath) {
@@ -66965,7 +67402,7 @@ function bindSandboxedFs(root) {
66965
67402
  try {
66966
67403
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
66967
67404
  verifyContainment(target, { root: resolvedRoot });
66968
- await fsp.mkdir(path89.dirname(target), { recursive: true });
67405
+ await fsp.mkdir(path90.dirname(target), { recursive: true });
66969
67406
  await fsp.writeFile(target, data, "utf8");
66970
67407
  return typedOk({ path: target });
66971
67408
  } catch (err) {
@@ -67150,7 +67587,7 @@ var init_loader = __esm({
67150
67587
 
67151
67588
  // src/cli/headless/runOneTurn.ts
67152
67589
  import { promises as fs44 } from "node:fs";
67153
- import path90 from "node:path";
67590
+ import path91 from "node:path";
67154
67591
  function planModeFromOpts(opts) {
67155
67592
  return (opts.phase ?? "build") === "plan";
67156
67593
  }
@@ -67717,7 +68154,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
67717
68154
  if (json3) {
67718
68155
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
67719
68156
  else {
67720
- await fs44.mkdir(path90.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68157
+ await fs44.mkdir(path91.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
67721
68158
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
67722
68159
  }
67723
68160
  }
@@ -68696,9 +69133,9 @@ __export(triggerLock_exports, {
68696
69133
  releaseLock: () => releaseLock
68697
69134
  });
68698
69135
  import { promises as fs45 } from "node:fs";
68699
- import * as path91 from "node:path";
69136
+ import * as path92 from "node:path";
68700
69137
  function lockPath(projectRoot) {
68701
- return path91.join(projectRoot, ".zelari", "trigger.lock");
69138
+ return path92.join(projectRoot, ".zelari", "trigger.lock");
68702
69139
  }
68703
69140
  function isPidAlive(pid) {
68704
69141
  try {
@@ -68711,7 +69148,7 @@ function isPidAlive(pid) {
68711
69148
  }
68712
69149
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
68713
69150
  const lp = lockPath(projectRoot);
68714
- const dir = path91.dirname(lp);
69151
+ const dir = path92.dirname(lp);
68715
69152
  await fs45.mkdir(dir, { recursive: true });
68716
69153
  try {
68717
69154
  const raw = await fs45.readFile(lp, "utf8");
@@ -68743,7 +69180,7 @@ var init_triggerLock = __esm({
68743
69180
 
68744
69181
  // src/cli/runHeadless.ts
68745
69182
  import { promises as fs46 } from "node:fs";
68746
- import path92 from "node:path";
69183
+ import path93 from "node:path";
68747
69184
  import { randomUUID as randomUUID10 } from "node:crypto";
68748
69185
  async function runHeadless(opts) {
68749
69186
  resetTaskSpawnCount();
@@ -68987,7 +69424,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
68987
69424
  try {
68988
69425
  let preflightGraph;
68989
69426
  if (opts.runPlan && opts.runPlan.trim() !== "") {
68990
- const planPath = path92.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69427
+ const planPath = path93.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
68991
69428
  log(`loading pre-flight plan: ${planPath}`);
68992
69429
  let raw;
68993
69430
  try {
@@ -69030,8 +69467,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69030
69467
  log(formatKrakenGraphAscii2(graph));
69031
69468
  if (opts.planOnly) {
69032
69469
  const planId = randomUUID10();
69033
- const planDir = path92.join(cwd, ".zelari", "radio");
69034
- const planPath = path92.join(planDir, `plan-${planId}.json`);
69470
+ const planDir = path93.join(cwd, ".zelari", "radio");
69471
+ const planPath = path93.join(planDir, `plan-${planId}.json`);
69035
69472
  await fs46.mkdir(planDir, { recursive: true });
69036
69473
  await fs46.writeFile(
69037
69474
  planPath,
@@ -69409,7 +69846,7 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69409
69846
  if (json3) {
69410
69847
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
69411
69848
  else {
69412
- await fs46.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
69849
+ await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
69413
69850
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
69414
69851
  }
69415
69852
  }
@@ -69860,7 +70297,7 @@ ${ragContext}` : slicePrompt;
69860
70297
  if (json3) {
69861
70298
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
69862
70299
  else {
69863
- await fs46.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70300
+ await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
69864
70301
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
69865
70302
  }
69866
70303
  }
@@ -69979,6 +70416,7 @@ function parseSetConfigFlags(argv) {
69979
70416
  let model;
69980
70417
  let endpoint;
69981
70418
  let thinking;
70419
+ let apiStyle;
69982
70420
  let endpointClear = false;
69983
70421
  let verifierProvider;
69984
70422
  let verifierModel;
@@ -69997,6 +70435,9 @@ function parseSetConfigFlags(argv) {
69997
70435
  } else if (arg === "--thinking") {
69998
70436
  thinking = argv[i + 1];
69999
70437
  i++;
70438
+ } else if (arg === "--api-style") {
70439
+ apiStyle = argv[i + 1];
70440
+ i++;
70000
70441
  } else if (arg === "--endpoint-clear") {
70001
70442
  endpointClear = true;
70002
70443
  } else if (arg === "--verifier-provider") {
@@ -70009,7 +70450,7 @@ function parseSetConfigFlags(argv) {
70009
70450
  verifierClear = true;
70010
70451
  }
70011
70452
  }
70012
- if (!provider && !model && !endpoint && !endpointClear && !thinking && !verifierProvider && !verifierModel && !verifierClear) {
70453
+ if (!provider && !model && !endpoint && !endpointClear && !thinking && !apiStyle && !verifierProvider && !verifierModel && !verifierClear) {
70013
70454
  return {
70014
70455
  request: null,
70015
70456
  error: "--set-config: nothing to update \u2014 provide at least one of --provider, --model, --endpoint, --thinking, --verifier-provider + --verifier-model, --verifier-clear, or --endpoint-clear"
@@ -70024,6 +70465,9 @@ function parseSetConfigFlags(argv) {
70024
70465
  if (endpoint !== void 0 && endpoint.trim().length === 0) {
70025
70466
  return { request: null, error: "--endpoint cannot be empty" };
70026
70467
  }
70468
+ if (apiStyle !== void 0 && apiStyle !== "chat" && apiStyle !== "responses") {
70469
+ return { request: null, error: "invalid --api-style " + apiStyle + " (use chat or responses)" };
70470
+ }
70027
70471
  if (verifierClear && (verifierProvider || verifierModel)) {
70028
70472
  return { request: null, error: "--verifier-clear conflicts with --verifier-provider/--verifier-model" };
70029
70473
  }
@@ -70048,6 +70492,7 @@ function parseSetConfigFlags(argv) {
70048
70492
  model: model?.trim(),
70049
70493
  endpoint: endpoint?.trim(),
70050
70494
  endpointClear: endpointClear || void 0,
70495
+ apiStyle,
70051
70496
  thinking: thinking?.trim().toLowerCase(),
70052
70497
  verifierProvider: verifierProvider?.trim(),
70053
70498
  verifierModel: verifierModel?.trim(),
@@ -70127,6 +70572,7 @@ function buildDesktopConfigSnapshot() {
70127
70572
  models,
70128
70573
  defaultModel,
70129
70574
  endpoint: custom2 ?? null,
70575
+ apiStyle: p3.id === "anthropic" || p3.id === "chatgpt" ? void 0 : getApiStyleFor(p3.id),
70130
70576
  baseUrl: custom2 ?? builtin,
70131
70577
  authKind: !hasKey ? "none" : oauth ? "oauth" : "api_key",
70132
70578
  expiresAt: stored?.expiresAt ?? null,
@@ -70173,6 +70619,9 @@ function applySetConfig(req) {
70173
70619
  if (req.endpoint) {
70174
70620
  setCustomEndpoint(targetProvider, req.endpoint);
70175
70621
  }
70622
+ if (req.apiStyle) {
70623
+ setApiStyleFor(targetProvider, req.apiStyle);
70624
+ }
70176
70625
  if (req.model) {
70177
70626
  setModelForProvider(targetProvider, req.model);
70178
70627
  }
@@ -70473,7 +70922,7 @@ function upsertSkill(opts) {
70473
70922
  }
70474
70923
  dir = getProjectSkillsDir(root);
70475
70924
  }
70476
- const path99 = skillFilePath(dir, name);
70925
+ const path100 = skillFilePath(dir, name);
70477
70926
  const content = serializeSkillMd({
70478
70927
  name,
70479
70928
  description,
@@ -70482,13 +70931,13 @@ function upsertSkill(opts) {
70482
70931
  tools: opts.tools,
70483
70932
  cost: opts.cost
70484
70933
  });
70485
- const parsed = parseSkillMd(content, path99);
70934
+ const parsed = parseSkillMd(content, path100);
70486
70935
  if (!parsed) {
70487
70936
  return { ok: false, error: "Generated SKILL.md failed validation" };
70488
70937
  }
70489
- mkdirSync23(dirname13(path99), { recursive: true });
70490
- writeFileSync25(path99, content, "utf8");
70491
- return { ok: true, path: path99 };
70938
+ mkdirSync23(dirname13(path100), { recursive: true });
70939
+ writeFileSync25(path100, content, "utf8");
70940
+ return { ok: true, path: path100 };
70492
70941
  }
70493
70942
  function removeSkill(opts) {
70494
70943
  const name = opts.name.trim().toLowerCase();
@@ -70506,8 +70955,8 @@ function removeSkill(opts) {
70506
70955
  dir = getProjectSkillsDir(root);
70507
70956
  }
70508
70957
  const skillDir = join46(dir, name);
70509
- const path99 = skillFilePath(dir, name);
70510
- if (!existsSync59(path99) && !existsSync59(skillDir)) {
70958
+ const path100 = skillFilePath(dir, name);
70959
+ if (!existsSync59(path100) && !existsSync59(skillDir)) {
70511
70960
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
70512
70961
  }
70513
70962
  try {
@@ -70518,7 +70967,7 @@ function removeSkill(opts) {
70518
70967
  error: err instanceof Error ? err.message : String(err)
70519
70968
  };
70520
70969
  }
70521
- return { ok: true, path: path99 };
70970
+ return { ok: true, path: path100 };
70522
70971
  }
70523
70972
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
70524
70973
  var init_skillConfigIo = __esm({
@@ -70639,7 +71088,7 @@ var init_jsonApi = __esm({
70639
71088
  });
70640
71089
 
70641
71090
  // src/cli/memory/mcpAdapter.ts
70642
- import * as path93 from "node:path";
71091
+ import * as path94 from "node:path";
70643
71092
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
70644
71093
  var init_mcpAdapter = __esm({
70645
71094
  "src/cli/memory/mcpAdapter.ts"() {
@@ -70809,8 +71258,8 @@ var init_mcpAdapter = __esm({
70809
71258
  this.takeWrite();
70810
71259
  const externalFile = args.source?.file;
70811
71260
  if (externalFile) {
70812
- const normalized = path93.normalize(externalFile);
70813
- if (path93.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path93.sep}`)) {
71261
+ const normalized = path94.normalize(externalFile);
71262
+ if (path94.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path94.sep}`)) {
70814
71263
  throw new Error("source.file must be project-relative and cannot escape the project");
70815
71264
  }
70816
71265
  }
@@ -71337,12 +71786,12 @@ function ensureHome() {
71337
71786
  }
71338
71787
  }
71339
71788
  function loadCompanionConfig() {
71340
- const path99 = getCompanionConfigPath();
71341
- if (!existsSync60(path99)) {
71789
+ const path100 = getCompanionConfigPath();
71790
+ if (!existsSync60(path100)) {
71342
71791
  return { projects: [] };
71343
71792
  }
71344
71793
  try {
71345
- const raw = JSON.parse(readFileSync45(path99, "utf8"));
71794
+ const raw = JSON.parse(readFileSync45(path100, "utf8"));
71346
71795
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
71347
71796
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
71348
71797
  ).map((p3) => ({
@@ -71380,16 +71829,16 @@ function loadOrCreateToken(explicit) {
71380
71829
  return { token: explicit.trim(), created: false };
71381
71830
  }
71382
71831
  ensureHome();
71383
- const path99 = getCompanionTokenPath();
71384
- if (existsSync60(path99)) {
71385
- const t = readFileSync45(path99, "utf8").trim();
71832
+ const path100 = getCompanionTokenPath();
71833
+ if (existsSync60(path100)) {
71834
+ const t = readFileSync45(path100, "utf8").trim();
71386
71835
  if (t) return { token: t, created: false };
71387
71836
  }
71388
71837
  const token = randomBytes7(24).toString("base64url");
71389
- writeFileSync26(path99, token + "\n", "utf8");
71838
+ writeFileSync26(path100, token + "\n", "utf8");
71390
71839
  try {
71391
71840
  const fs48 = __require("node:fs");
71392
- fs48.chmodSync?.(path99, 384);
71841
+ fs48.chmodSync?.(path100, 384);
71393
71842
  } catch {
71394
71843
  }
71395
71844
  return { token, created: true };
@@ -71414,17 +71863,17 @@ function mergeProjects(cfg, extraPaths) {
71414
71863
  byId.set(p3.id, p3);
71415
71864
  }
71416
71865
  for (const raw of extraPaths) {
71417
- const path99 = raw.trim();
71418
- if (!path99) continue;
71419
- let id3 = slugFromPath(path99);
71866
+ const path100 = raw.trim();
71867
+ if (!path100) continue;
71868
+ let id3 = slugFromPath(path100);
71420
71869
  let n = 2;
71421
- while (byId.has(id3) && byId.get(id3).path !== path99) {
71422
- id3 = `${slugFromPath(path99)}-${n++}`;
71870
+ while (byId.has(id3) && byId.get(id3).path !== path100) {
71871
+ id3 = `${slugFromPath(path100)}-${n++}`;
71423
71872
  }
71424
71873
  byId.set(id3, {
71425
71874
  id: id3,
71426
- name: slugFromPath(path99),
71427
- path: path99
71875
+ name: slugFromPath(path100),
71876
+ path: path100
71428
71877
  });
71429
71878
  }
71430
71879
  return [...byId.values()];
@@ -71667,7 +72116,7 @@ var init_askUserBridge = __esm({
71667
72116
 
71668
72117
  // src/cli/serve/spineLockSweep.ts
71669
72118
  import { promises as fs47 } from "node:fs";
71670
- import path94 from "node:path";
72119
+ import path95 from "node:path";
71671
72120
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
71672
72121
  const dir = sessionsDir2 ?? resolveSessionsDir();
71673
72122
  const onSwept = options.onSwept ?? ((sessionId2, reason) => {
@@ -71685,7 +72134,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
71685
72134
  return result;
71686
72135
  }
71687
72136
  for (const sessionId2 of entries) {
71688
- const lockPath2 = path94.join(dir, sessionId2, "writer.lock");
72137
+ const lockPath2 = path95.join(dir, sessionId2, "writer.lock");
71689
72138
  try {
71690
72139
  const raw = await fs47.readFile(lockPath2, "utf-8");
71691
72140
  let lockInfo = {};
@@ -72682,9 +73131,9 @@ async function runCompanionServe(opts = {}) {
72682
73131
  return;
72683
73132
  }
72684
73133
  const url2 = parseUrl(req);
72685
- const path99 = url2.pathname.replace(/\/+$/, "") || "/";
73134
+ const path100 = url2.pathname.replace(/\/+$/, "") || "/";
72686
73135
  try {
72687
- if (req.method === "GET" && (path99 === "/health" || path99 === "/v1/health")) {
73136
+ if (req.method === "GET" && (path100 === "/health" || path100 === "/v1/health")) {
72688
73137
  sendJson2(res, 200, {
72689
73138
  ok: true,
72690
73139
  service: "zelari-companion",
@@ -72696,18 +73145,18 @@ async function runCompanionServe(opts = {}) {
72696
73145
  });
72697
73146
  return;
72698
73147
  }
72699
- if (path99.startsWith("/v1")) {
73148
+ if (path100.startsWith("/v1")) {
72700
73149
  if (!tokenMatches(token, getBearer(req))) {
72701
73150
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
72702
73151
  return;
72703
73152
  }
72704
73153
  }
72705
- if (req.method === "GET" && path99 === "/v1/config") {
73154
+ if (req.method === "GET" && path100 === "/v1/config") {
72706
73155
  const snap = buildDesktopConfigSnapshot();
72707
73156
  sendJson2(res, 200, { ok: true, ...snap });
72708
73157
  return;
72709
73158
  }
72710
- if (req.method === "GET" && path99 === "/v1/projects") {
73159
+ if (req.method === "GET" && path100 === "/v1/projects") {
72711
73160
  sendJson2(res, 200, {
72712
73161
  ok: true,
72713
73162
  projects: projects.map((p3) => ({
@@ -72718,7 +73167,7 @@ async function runCompanionServe(opts = {}) {
72718
73167
  });
72719
73168
  return;
72720
73169
  }
72721
- if (req.method === "GET" && path99 === "/v1/runs") {
73170
+ if (req.method === "GET" && path100 === "/v1/runs") {
72722
73171
  sendJson2(res, 200, {
72723
73172
  ok: true,
72724
73173
  active: runs.getActive(),
@@ -72736,7 +73185,7 @@ async function runCompanionServe(opts = {}) {
72736
73185
  });
72737
73186
  return;
72738
73187
  }
72739
- if (req.method === "POST" && path99 === "/v1/runs") {
73188
+ if (req.method === "POST" && path100 === "/v1/runs") {
72740
73189
  const raw = await readBody(req);
72741
73190
  let body = {};
72742
73191
  try {
@@ -72784,7 +73233,7 @@ async function runCompanionServe(opts = {}) {
72784
73233
  });
72785
73234
  return;
72786
73235
  }
72787
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path99);
73236
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path100);
72788
73237
  if (req.method === "GET" && eventsMatch) {
72789
73238
  const runId = eventsMatch[1];
72790
73239
  const run = runs.getRun(runId);
@@ -72849,7 +73298,7 @@ async function runCompanionServe(opts = {}) {
72849
73298
  }, 500);
72850
73299
  return;
72851
73300
  }
72852
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path99);
73301
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path100);
72853
73302
  if (req.method === "POST" && cancelMatch) {
72854
73303
  const runId = cancelMatch[1];
72855
73304
  const result = runs.cancel(runId);
@@ -72860,7 +73309,7 @@ async function runCompanionServe(opts = {}) {
72860
73309
  sendJson2(res, 200, { ok: true, cancelled: runId });
72861
73310
  return;
72862
73311
  }
72863
- const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path99);
73312
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path100);
72864
73313
  if (req.method === "POST" && steerMatch) {
72865
73314
  const runId = steerMatch[1];
72866
73315
  const raw = await readBody(req);
@@ -73029,11 +73478,11 @@ import { execSync as execSync2 } from "node:child_process";
73029
73478
  import { existsSync as existsSync62, readFileSync as readFileSync46, readlinkSync, statSync as statSync10 } from "node:fs";
73030
73479
  import { createRequire as createRequire3 } from "node:module";
73031
73480
  import { fileURLToPath as fileURLToPath3 } from "node:url";
73032
- import path95 from "node:path";
73481
+ import path96 from "node:path";
73033
73482
  function findPackageRoot(start) {
73034
73483
  let dir = start;
73035
73484
  for (let i = 0; i < 6; i += 1) {
73036
- const candidate = path95.join(dir, "package.json");
73485
+ const candidate = path96.join(dir, "package.json");
73037
73486
  if (existsSync62(candidate)) {
73038
73487
  try {
73039
73488
  const pkg = JSON.parse(readFileSync46(candidate, "utf8"));
@@ -73041,11 +73490,11 @@ function findPackageRoot(start) {
73041
73490
  } catch {
73042
73491
  }
73043
73492
  }
73044
- const parent = path95.dirname(dir);
73493
+ const parent = path96.dirname(dir);
73045
73494
  if (parent === dir) break;
73046
73495
  dir = parent;
73047
73496
  }
73048
- return path95.resolve(__dirname3, "..", "..", "..");
73497
+ return path96.resolve(__dirname3, "..", "..", "..");
73049
73498
  }
73050
73499
  function tryExec(cmd) {
73051
73500
  try {
@@ -73059,7 +73508,7 @@ function tryExec(cmd) {
73059
73508
  }
73060
73509
  function readPackageJson4() {
73061
73510
  try {
73062
- const pkgPath = path95.join(packageRoot, "package.json");
73511
+ const pkgPath = path96.join(packageRoot, "package.json");
73063
73512
  return JSON.parse(readFileSync46(pkgPath, "utf8"));
73064
73513
  } catch {
73065
73514
  return null;
@@ -73071,7 +73520,7 @@ function getGlobalPrefix() {
73071
73520
  return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
73072
73521
  }
73073
73522
  function isSourceCheckout() {
73074
- return existsSync62(path95.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path95.join(packageRoot, "apps", "desktop", "package.json"));
73523
+ return existsSync62(path96.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path96.join(packageRoot, "apps", "desktop", "package.json"));
73075
73524
  }
73076
73525
  function checkShim(pkgName) {
73077
73526
  const prefix = getGlobalPrefix();
@@ -73080,9 +73529,9 @@ function checkShim(pkgName) {
73080
73529
  }
73081
73530
  const isWin = process.platform === "win32";
73082
73531
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
73083
- const shimPath = path95.join(prefix, shimName);
73532
+ const shimPath = path96.join(prefix, shimName);
73084
73533
  if (!existsSync62(shimPath)) {
73085
- const localBin = path95.join(packageRoot, "bin", "zelari-code.js");
73534
+ const localBin = path96.join(packageRoot, "bin", "zelari-code.js");
73086
73535
  if (isSourceCheckout() && existsSync62(localBin)) {
73087
73536
  return WARN(
73088
73537
  `global shim not found at ${shimPath}
@@ -73116,8 +73565,8 @@ function checkShim(pkgName) {
73116
73565
  fix: npm install -g ${pkgName}@latest --force`
73117
73566
  );
73118
73567
  }
73119
- const resolved = path95.resolve(path95.dirname(shimPath), target);
73120
- const expected = path95.join(
73568
+ const resolved = path96.resolve(path96.dirname(shimPath), target);
73569
+ const expected = path96.join(
73121
73570
  prefix,
73122
73571
  "node_modules",
73123
73572
  pkgName,
@@ -73159,7 +73608,7 @@ function checkNode(pkg) {
73159
73608
  return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
73160
73609
  }
73161
73610
  function checkBundle() {
73162
- const bundle = path95.join(packageRoot, "dist", "cli", "main.bundled.js");
73611
+ const bundle = path96.join(packageRoot, "dist", "cli", "main.bundled.js");
73163
73612
  if (!existsSync62(bundle)) {
73164
73613
  return FAIL(
73165
73614
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -73180,7 +73629,7 @@ function checkRuntimeDeps() {
73180
73629
  const missing = [];
73181
73630
  for (const dep of required2) {
73182
73631
  try {
73183
- const localReq = createRequire3(path95.join(packageRoot, "package.json"));
73632
+ const localReq = createRequire3(path96.join(packageRoot, "package.json"));
73184
73633
  localReq.resolve(dep);
73185
73634
  } catch {
73186
73635
  missing.push(dep);
@@ -73457,7 +73906,7 @@ var init_doctor = __esm({
73457
73906
  init_metrics3();
73458
73907
  init_contextGrowthSummary();
73459
73908
  require3 = createRequire3(import.meta.url);
73460
- __dirname3 = path95.dirname(fileURLToPath3(import.meta.url));
73909
+ __dirname3 = path96.dirname(fileURLToPath3(import.meta.url));
73461
73910
  packageRoot = findPackageRoot(__dirname3);
73462
73911
  OK = (message) => ({
73463
73912
  ok: true,
@@ -73566,7 +74015,7 @@ __export(userSettings_exports, {
73566
74015
  settingsOverrides: () => settingsOverrides
73567
74016
  });
73568
74017
  import { existsSync as existsSync63, readFileSync as readFileSync47 } from "node:fs";
73569
- import path96 from "node:path";
74018
+ import path97 from "node:path";
73570
74019
  function parseBool(raw) {
73571
74020
  const v = raw.trim().toLowerCase();
73572
74021
  if (["1", "true", "yes", "on"].includes(v)) return true;
@@ -73633,8 +74082,8 @@ function envValueFor(key, env) {
73633
74082
  function resolveUserSettings(opts = {}) {
73634
74083
  const cwd = opts.cwd ?? process.cwd();
73635
74084
  const env = opts.env ?? process.env;
73636
- const userPath = path96.join(zelariHome(), SETTINGS_FILE_NAME);
73637
- const projectPath = path96.join(cwd, ".zelari", SETTINGS_FILE_NAME);
74085
+ const userPath = path97.join(zelariHome(), SETTINGS_FILE_NAME);
74086
+ const projectPath = path97.join(cwd, ".zelari", SETTINGS_FILE_NAME);
73638
74087
  const warnings = [];
73639
74088
  const userLayer = loadFileLayer(userPath, "user", warnings);
73640
74089
  const projectLayer = loadFileLayer(projectPath, "project", warnings);
@@ -73848,7 +74297,7 @@ __export(inspectSession_exports, {
73848
74297
  renderInspectReport: () => renderInspectReport,
73849
74298
  runInspectSession: () => runInspectSession
73850
74299
  });
73851
- import path97 from "node:path";
74300
+ import path98 from "node:path";
73852
74301
  import { existsSync as existsSync64 } from "node:fs";
73853
74302
  function formatLimit(limit) {
73854
74303
  return `${Math.round(limit / 1e3)}k`;
@@ -73882,8 +74331,8 @@ function renderInspectReport(state3) {
73882
74331
  }
73883
74332
  async function runInspectSession(opts) {
73884
74333
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
73885
- const sessionDir = path97.join(sessionsDir2, opts.sessionId);
73886
- const eventsPath = path97.join(sessionDir, "events.jsonl");
74334
+ const sessionDir = path98.join(sessionsDir2, opts.sessionId);
74335
+ const eventsPath = path98.join(sessionDir, "events.jsonl");
73887
74336
  if (!existsSync64(sessionDir)) {
73888
74337
  console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
73889
74338
  return 1;
@@ -73917,14 +74366,14 @@ __export(inspect_exports, {
73917
74366
  collectInspectReport: () => collectInspectReport,
73918
74367
  runInspect: () => runInspect
73919
74368
  });
73920
- import path98 from "node:path";
74369
+ import path99 from "node:path";
73921
74370
  import { existsSync as existsSync65, readFileSync as readFileSync48, readdirSync as readdirSync13 } from "node:fs";
73922
74371
  async function collectInspectReport(cwd = process.cwd()) {
73923
74372
  ensureBuiltinSkillsLoadedSync();
73924
74373
  const snap = listSkillsSnapshot(cwd);
73925
74374
  const mcp = listMcpServers(cwd);
73926
- const userMcpPath = path98.join(zelariHome(), "mcp.json");
73927
- const projectMcpPath = path98.join(cwd, ".zelari", "mcp.json");
74375
+ const userMcpPath = path99.join(zelariHome(), "mcp.json");
74376
+ const projectMcpPath = path99.join(cwd, ".zelari", "mcp.json");
73928
74377
  const globalHooks = globalHooksDir();
73929
74378
  const projectHooks = projectHooksDir(cwd);
73930
74379
  const projectTrusted = isFolderTrusted(cwd);
@@ -73952,9 +74401,9 @@ async function collectInspectReport(cwd = process.cwd()) {
73952
74401
  configSources: [
73953
74402
  { path: userMcpPath, exists: existsSync65(userMcpPath) },
73954
74403
  { path: projectMcpPath, exists: existsSync65(projectMcpPath) },
73955
- { path: path98.join(zelariHome(), "provider.json"), exists: existsSync65(path98.join(zelariHome(), "provider.json")) },
73956
- { path: path98.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path98.join(cwd, ".zelari", "AGENTS.md")) },
73957
- { path: path98.join(cwd, "AGENTS.md"), exists: existsSync65(path98.join(cwd, "AGENTS.md")) }
74404
+ { path: path99.join(zelariHome(), "provider.json"), exists: existsSync65(path99.join(zelariHome(), "provider.json")) },
74405
+ { path: path99.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path99.join(cwd, ".zelari", "AGENTS.md")) },
74406
+ { path: path99.join(cwd, "AGENTS.md"), exists: existsSync65(path99.join(cwd, "AGENTS.md")) }
73958
74407
  ],
73959
74408
  skills: {
73960
74409
  total: snap.skills.length,
@@ -73994,8 +74443,8 @@ function listJsonFiles(dir) {
73994
74443
  }
73995
74444
  function findAgentsMd(cwd) {
73996
74445
  const candidates = [
73997
- path98.join(cwd, "AGENTS.md"),
73998
- path98.join(cwd, ".zelari", "AGENTS.md")
74446
+ path99.join(cwd, "AGENTS.md"),
74447
+ path99.join(cwd, ".zelari", "AGENTS.md")
73999
74448
  ];
74000
74449
  const found = [];
74001
74450
  for (const c of candidates) {
@@ -79250,10 +79699,10 @@ init_ledger();
79250
79699
 
79251
79700
  // src/cli/evolution/proposals.ts
79252
79701
  import { existsSync as existsSync51, readFileSync as readFileSync39 } from "node:fs";
79253
- import path76 from "node:path";
79254
- var PROPOSALS_REL = path76.join(".zelari", "evolution", "proposals.jsonl");
79702
+ import path77 from "node:path";
79703
+ var PROPOSALS_REL = path77.join(".zelari", "evolution", "proposals.jsonl");
79255
79704
  function proposalsPath(cwd) {
79256
- return path76.join(cwd, PROPOSALS_REL);
79705
+ return path77.join(cwd, PROPOSALS_REL);
79257
79706
  }
79258
79707
  function readProposalStore(cwd) {
79259
79708
  const file2 = proposalsPath(cwd);
@@ -79541,6 +79990,24 @@ ${formatSkillList(availableSkills)}`
79541
79990
  customEndpoint: url2
79542
79991
  };
79543
79992
  }
79993
+ if (subcommand === "api") {
79994
+ const target = args[1];
79995
+ if (!target || target === "show") {
79996
+ return {
79997
+ handled: true,
79998
+ kind: "provider_custom",
79999
+ message: "Usage: /provider api chat \u2014 POST /chat/completions (default)\n /provider api responses \u2014 POST /responses (OpenAI Responses API)\nApplies to the active provider; chatgpt/anthropic have a fixed transport."
80000
+ };
80001
+ }
80002
+ if (target !== "chat" && target !== "responses") {
80003
+ return {
80004
+ handled: true,
80005
+ kind: "provider_custom",
80006
+ message: `[provider] unknown api style: ${target}. Use: chat | responses`
80007
+ };
80008
+ }
80009
+ return { handled: true, kind: "provider_custom", apiStyle: target };
80010
+ }
79544
80011
  const providerId = subcommand;
79545
80012
  const sub = args[1];
79546
80013
  if (sub === "refresh") {
@@ -80345,11 +80812,11 @@ function handleCacheStats(ctx) {
80345
80812
  init_messageHelpers();
80346
80813
  init_serviceFactory();
80347
80814
  import { promises as fs35 } from "node:fs";
80348
- import * as path78 from "node:path";
80815
+ import * as path79 from "node:path";
80349
80816
 
80350
80817
  // src/cli/memory/promotion.ts
80351
80818
  import { promises as fs34 } from "node:fs";
80352
- import * as path77 from "node:path";
80819
+ import * as path78 from "node:path";
80353
80820
  var START = "<!-- zelari:memory-promotions:start -->";
80354
80821
  var END = "<!-- zelari:memory-promotions:end -->";
80355
80822
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -80360,16 +80827,16 @@ function lineFor(node) {
80360
80827
  }
80361
80828
  async function promoteMemoryToAgentsMd(projectRoot, node) {
80362
80829
  if (node.status !== "active") {
80363
- return { added: false, path: path77.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
80830
+ return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
80364
80831
  }
80365
80832
  if (!DURABLE_KINDS.has(node.kind)) {
80366
- return { added: false, path: path77.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
80833
+ return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
80367
80834
  }
80368
- const root = await fs34.realpath(projectRoot).catch(() => path77.resolve(projectRoot));
80369
- const target = path77.join(root, "AGENTS.md");
80835
+ const root = await fs34.realpath(projectRoot).catch(() => path78.resolve(projectRoot));
80836
+ const target = path78.join(root, "AGENTS.md");
80370
80837
  try {
80371
- const stat7 = await fs34.lstat(target);
80372
- if (stat7.isSymbolicLink() || !stat7.isFile()) throw new Error("AGENTS.md must be a regular project file.");
80838
+ const stat8 = await fs34.lstat(target);
80839
+ if (stat8.isSymbolicLink() || !stat8.isFile()) throw new Error("AGENTS.md must be a regular project file.");
80373
80840
  } catch (error51) {
80374
80841
  if (error51.code !== "ENOENT") throw error51;
80375
80842
  }
@@ -80431,25 +80898,25 @@ function sourceLine(source2) {
80431
80898
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
80432
80899
  }
80433
80900
  function isInside(root, target) {
80434
- const relative6 = path78.relative(root, target);
80435
- return relative6 === "" || !relative6.startsWith("..") && !path78.isAbsolute(relative6);
80901
+ const relative6 = path79.relative(root, target);
80902
+ return relative6 === "" || !relative6.startsWith("..") && !path79.isAbsolute(relative6);
80436
80903
  }
80437
80904
  async function safeExportPath(cwd, requested) {
80438
- const lexicalRoot = path78.resolve(cwd);
80905
+ const lexicalRoot = path79.resolve(cwd);
80439
80906
  const root = await fs35.realpath(lexicalRoot).catch(() => lexicalRoot);
80440
- const fallback = path78.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
80441
- const target = requested?.trim() ? path78.resolve(root, requested.trim()) : fallback;
80907
+ const fallback = path79.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
80908
+ const target = requested?.trim() ? path79.resolve(root, requested.trim()) : fallback;
80442
80909
  if (!isInside(root, target)) {
80443
80910
  throw new Error("Export path must stay inside the active project.");
80444
80911
  }
80445
- const parent = path78.dirname(target);
80446
- const relativeParent = path78.relative(root, parent);
80912
+ const parent = path79.dirname(target);
80913
+ const relativeParent = path79.relative(root, parent);
80447
80914
  let cursor = root;
80448
- for (const segment of relativeParent.split(path78.sep).filter(Boolean)) {
80449
- cursor = path78.join(cursor, segment);
80915
+ for (const segment of relativeParent.split(path79.sep).filter(Boolean)) {
80916
+ cursor = path79.join(cursor, segment);
80450
80917
  try {
80451
- const stat7 = await fs35.lstat(cursor);
80452
- if (stat7.isSymbolicLink()) {
80918
+ const stat8 = await fs35.lstat(cursor);
80919
+ if (stat8.isSymbolicLink()) {
80453
80920
  throw new Error("Export path must not traverse a symbolic link.");
80454
80921
  }
80455
80922
  } catch (error51) {
@@ -80618,9 +81085,9 @@ ${message}` : message
80618
81085
  }
80619
81086
  case "export": {
80620
81087
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
80621
- await fs35.mkdir(path78.dirname(target), { recursive: true });
80622
- const root = await fs35.realpath(ctx.cwd).catch(() => path78.resolve(ctx.cwd));
80623
- const realParent = await fs35.realpath(path78.dirname(target));
81088
+ await fs35.mkdir(path79.dirname(target), { recursive: true });
81089
+ const root = await fs35.realpath(ctx.cwd).catch(() => path79.resolve(ctx.cwd));
81090
+ const realParent = await fs35.realpath(path79.dirname(target));
80624
81091
  if (!isInside(root, realParent)) {
80625
81092
  throw new Error("Export path resolves outside the active project.");
80626
81093
  }
@@ -80835,7 +81302,7 @@ import { promises as fs37 } from "node:fs";
80835
81302
  init_zod();
80836
81303
  init_taskTool();
80837
81304
  import { promises as fs36 } from "node:fs";
80838
- import path79 from "node:path";
81305
+ import path80 from "node:path";
80839
81306
  import { randomBytes as randomBytes6 } from "node:crypto";
80840
81307
  var CsvFanoutArgsSchema = external_exports.object({
80841
81308
  csv_path: external_exports.string().min(1),
@@ -80897,27 +81364,27 @@ function parseCsv(text) {
80897
81364
  records.pop();
80898
81365
  }
80899
81366
  if (records.length === 0) return { headers: [], rows: [] };
80900
- const headers2 = records[0];
81367
+ const headers3 = records[0];
80901
81368
  const rows = records.slice(1).map((r) => {
80902
81369
  const obj = {};
80903
- for (let i = 0; i < headers2.length; i++) obj[headers2[i]] = r[i] ?? "";
81370
+ for (let i = 0; i < headers3.length; i++) obj[headers3[i]] = r[i] ?? "";
80904
81371
  return obj;
80905
81372
  });
80906
- return { headers: headers2, rows };
81373
+ return { headers: headers3, rows };
80907
81374
  }
80908
81375
  function applyTemplate(template, row) {
80909
81376
  return template.replace(/\{([a-zA-Z_][\w-]*)\}/g, (_, k) => row[k] ?? "");
80910
81377
  }
80911
- function serializeCsv(headers2, rows) {
81378
+ function serializeCsv(headers3, rows) {
80912
81379
  const escape = (v) => {
80913
81380
  if (v.includes(",") || v.includes("\n") || v.includes('"')) {
80914
81381
  return `"${v.replace(/"/g, '""')}"`;
80915
81382
  }
80916
81383
  return v;
80917
81384
  };
80918
- const out = [headers2.map(escape).join(",")];
81385
+ const out = [headers3.map(escape).join(",")];
80919
81386
  for (const row of rows) {
80920
- out.push(headers2.map((h) => escape(row[h] ?? "")).join(","));
81387
+ out.push(headers3.map((h) => escape(row[h] ?? "")).join(","));
80921
81388
  }
80922
81389
  return out.join("\n") + "\n";
80923
81390
  }
@@ -80929,23 +81396,23 @@ function resolveMaxConcurrency(env = process.env) {
80929
81396
  }
80930
81397
  async function runCsvFanout(args, deps, opts) {
80931
81398
  const start = Date.now();
80932
- const absCsv = path79.isAbsolute(args.csv_path) ? args.csv_path : path79.join(opts.parentCwd, args.csv_path);
80933
- const absOut = path79.isAbsolute(args.output_csv_path) ? args.output_csv_path : path79.join(opts.parentCwd, args.output_csv_path);
80934
- const { headers: headers2, rows } = await readCsv(absCsv);
80935
- if (headers2.length === 0) {
81399
+ const absCsv = path80.isAbsolute(args.csv_path) ? args.csv_path : path80.join(opts.parentCwd, args.csv_path);
81400
+ const absOut = path80.isAbsolute(args.output_csv_path) ? args.output_csv_path : path80.join(opts.parentCwd, args.output_csv_path);
81401
+ const { headers: headers3, rows } = await readCsv(absCsv);
81402
+ if (headers3.length === 0) {
80936
81403
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
80937
81404
  }
80938
81405
  if (!args.id_column) {
80939
81406
  throw new Error("kraken_csv_fanout: id_column is required");
80940
81407
  }
80941
- if (!headers2.includes(args.id_column)) {
80942
- throw new Error(`kraken_csv_fanout: id_column "${args.id_column}" not in CSV header [${headers2.join(", ")}]`);
81408
+ if (!headers3.includes(args.id_column)) {
81409
+ throw new Error(`kraken_csv_fanout: id_column "${args.id_column}" not in CSV header [${headers3.join(", ")}]`);
80943
81410
  }
80944
81411
  const concurrency = args.max_concurrency ?? resolveMaxConcurrency();
80945
81412
  opts.onLog?.(`csv fanout: ${rows.length} rows \xD7 ${args.agent_kind} @ concurrency=${concurrency}`);
80946
81413
  const perRowMs = args.max_runtime_seconds !== void 0 ? args.max_runtime_seconds * 1e3 : args.agent_kind === "general" ? TASK_TOOL_TIMEOUT_MS : 3e5;
80947
81414
  const outputRecords = rows.map((r) => ({ ...r, status: "pending", result: "", error: "" }));
80948
- const outHeaders = [...headers2, "status", "result", "error"];
81415
+ const outHeaders = [...headers3, "status", "result", "error"];
80949
81416
  let writeChain2 = Promise.resolve();
80950
81417
  function queueWrite(contents) {
80951
81418
  const next = writeChain2.then(() => atomicWrite(absOut, contents));
@@ -80986,7 +81453,7 @@ async function runCsvFanout(args, deps, opts) {
80986
81453
  errored += 1;
80987
81454
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
80988
81455
  }
80989
- await fs36.mkdir(path79.dirname(absOut), { recursive: true });
81456
+ await fs36.mkdir(path80.dirname(absOut), { recursive: true });
80990
81457
  await queueWrite(serializeCsv(outHeaders, outputRecords));
80991
81458
  }
80992
81459
  }
@@ -81181,7 +81648,7 @@ function splitArgs(s) {
81181
81648
  // src/cli/slashHandlers/krakenWorkbench.ts
81182
81649
  init_messageHelpers();
81183
81650
  import { promises as fs38 } from "node:fs";
81184
- import path80 from "node:path";
81651
+ import path81 from "node:path";
81185
81652
 
81186
81653
  // src/cli/kraken/workbenchView.ts
81187
81654
  var EMPTY = {
@@ -81298,17 +81765,17 @@ function formatWorkbenchForTerminal(p3) {
81298
81765
 
81299
81766
  // src/cli/slashHandlers/krakenWorkbench.ts
81300
81767
  async function handleKrakenWorkbench(ctx) {
81301
- const dir = path80.join(ctx.cwd, ".zelari", "radio");
81768
+ const dir = path81.join(ctx.cwd, ".zelari", "radio");
81302
81769
  let latest = null;
81303
81770
  let latestMtime = 0;
81304
81771
  try {
81305
81772
  const files = await fs38.readdir(dir);
81306
81773
  for (const f of files) {
81307
81774
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
81308
- const full = path80.join(dir, f);
81309
- const stat7 = await fs38.stat(full);
81310
- if (stat7.mtimeMs > latestMtime) {
81311
- latestMtime = stat7.mtimeMs;
81775
+ const full = path81.join(dir, f);
81776
+ const stat8 = await fs38.stat(full);
81777
+ if (stat8.mtimeMs > latestMtime) {
81778
+ latestMtime = stat8.mtimeMs;
81312
81779
  latest = full;
81313
81780
  }
81314
81781
  }
@@ -81322,10 +81789,10 @@ async function handleKrakenWorkbench(ctx) {
81322
81789
  const parsed = parseWorkbench(content);
81323
81790
  const rendered = formatWorkbenchForTerminal(parsed);
81324
81791
  if (!rendered.trim()) {
81325
- appendSystem(ctx.setMessages, `[kraken workbench] ${path80.basename(latest)}: (no nodes / no events yet)`);
81792
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}: (no nodes / no events yet)`);
81326
81793
  return;
81327
81794
  }
81328
- appendSystem(ctx.setMessages, `[kraken workbench] ${path80.basename(latest)}:
81795
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}:
81329
81796
  ${rendered}`);
81330
81797
  }
81331
81798
 
@@ -81633,14 +82100,14 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
81633
82100
  init_messageHelpers();
81634
82101
  init_paths();
81635
82102
  import { promises as fs39 } from "node:fs";
81636
- import path83 from "node:path";
82103
+ import path84 from "node:path";
81637
82104
  async function handlePromoteMember(ctx, memberId) {
81638
82105
  try {
81639
82106
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
81640
82107
  const { skill, markdown } = promoteMember2(memberId);
81641
82108
  const skillDir = skillsDir();
81642
82109
  await fs39.mkdir(skillDir, { recursive: true });
81643
- const filePath = path83.join(skillDir, `${skill.id}.md`);
82110
+ const filePath = path84.join(skillDir, `${skill.id}.md`);
81644
82111
  const previous = await fs39.readFile(filePath, "utf8").catch(() => null);
81645
82112
  const { createHash: createHash24 } = await import("node:crypto");
81646
82113
  const sha = (s) => createHash24("sha256").update(s, "utf8").digest("hex");
@@ -81666,7 +82133,7 @@ ${lineage}
81666
82133
  // src/cli/branchManager.ts
81667
82134
  init_paths();
81668
82135
  import { promises as fs40, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
81669
- import path84 from "node:path";
82136
+ import path85 from "node:path";
81670
82137
  var META_FILENAME = "meta.json";
81671
82138
  var SESSIONS_SUBDIR = "sessions";
81672
82139
  function getBranchesBaseDir() {
@@ -81676,13 +82143,13 @@ function getSessionsBaseDir() {
81676
82143
  return sessionsDir();
81677
82144
  }
81678
82145
  function branchPathFor(name, baseDir) {
81679
- return path84.join(baseDir, name);
82146
+ return path85.join(baseDir, name);
81680
82147
  }
81681
82148
  function metaPathFor(name, baseDir) {
81682
- return path84.join(baseDir, name, META_FILENAME);
82149
+ return path85.join(baseDir, name, META_FILENAME);
81683
82150
  }
81684
82151
  function sessionsPathFor(name, baseDir) {
81685
- return path84.join(baseDir, name, SESSIONS_SUBDIR);
82152
+ return path85.join(baseDir, name, SESSIONS_SUBDIR);
81686
82153
  }
81687
82154
  function readBranchMeta(name, baseDir) {
81688
82155
  const metaPath = metaPathFor(name, baseDir);
@@ -81707,7 +82174,7 @@ function readBranchMeta(name, baseDir) {
81707
82174
  }
81708
82175
  function writeBranchMeta(name, baseDir, meta3) {
81709
82176
  const metaPath = metaPathFor(name, baseDir);
81710
- mkdirSync21(path84.dirname(metaPath), { recursive: true });
82177
+ mkdirSync21(path85.dirname(metaPath), { recursive: true });
81711
82178
  writeFileSync24(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
81712
82179
  }
81713
82180
  async function countSessions(name, baseDir) {
@@ -81758,14 +82225,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
81758
82225
  if (branchExists(name, baseDir)) {
81759
82226
  throw new BranchAlreadyExistsError(name);
81760
82227
  }
81761
- const sourcePath = path84.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82228
+ const sourcePath = path85.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
81762
82229
  if (!existsSync55(sourcePath)) {
81763
82230
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
81764
82231
  }
81765
82232
  const branchPath = branchPathFor(name, baseDir);
81766
82233
  const branchSessionsPath = sessionsPathFor(name, baseDir);
81767
82234
  mkdirSync21(branchSessionsPath, { recursive: true });
81768
- const destPath = path84.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82235
+ const destPath = path85.join(branchSessionsPath, `${fromSessionId}.jsonl`);
81769
82236
  await fs40.copyFile(sourcePath, destPath);
81770
82237
  const meta3 = {
81771
82238
  name,
@@ -81869,14 +82336,14 @@ async function handleBranchCheckout(ctx, branchName) {
81869
82336
  // src/cli/slashHandlers/workspace.ts
81870
82337
  init_messageHelpers();
81871
82338
  import { promises as fs41 } from "node:fs";
81872
- import path85 from "node:path";
82339
+ import path86 from "node:path";
81873
82340
  async function handleWorkspaceShow(ctx, what) {
81874
82341
  try {
81875
- const zelari = path85.join(process.cwd(), ".zelari");
82342
+ const zelari = path86.join(process.cwd(), ".zelari");
81876
82343
  let content;
81877
82344
  switch (what) {
81878
82345
  case "plan": {
81879
- const planPath = path85.join(zelari, "plan.md");
82346
+ const planPath = path86.join(zelari, "plan.md");
81880
82347
  try {
81881
82348
  content = await fs41.readFile(planPath, "utf-8");
81882
82349
  } catch {
@@ -81885,7 +82352,7 @@ async function handleWorkspaceShow(ctx, what) {
81885
82352
  break;
81886
82353
  }
81887
82354
  case "decisions": {
81888
- const decisionsDir = path85.join(zelari, "decisions");
82355
+ const decisionsDir = path86.join(zelari, "decisions");
81889
82356
  try {
81890
82357
  const files = (await fs41.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
81891
82358
  if (files.length === 0) {
@@ -81895,7 +82362,7 @@ async function handleWorkspaceShow(ctx, what) {
81895
82362
  `];
81896
82363
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
81897
82364
  for (const f of files) {
81898
- const raw = await fs41.readFile(path85.join(decisionsDir, f), "utf-8");
82365
+ const raw = await fs41.readFile(path86.join(decisionsDir, f), "utf-8");
81899
82366
  const { meta: meta3, body } = parseFrontmatter2(raw);
81900
82367
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
81901
82368
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -81908,7 +82375,7 @@ async function handleWorkspaceShow(ctx, what) {
81908
82375
  break;
81909
82376
  }
81910
82377
  case "risks": {
81911
- const risksPath = path85.join(zelari, "risks.md");
82378
+ const risksPath = path86.join(zelari, "risks.md");
81912
82379
  try {
81913
82380
  content = await fs41.readFile(risksPath, "utf-8");
81914
82381
  } catch {
@@ -81917,7 +82384,7 @@ async function handleWorkspaceShow(ctx, what) {
81917
82384
  break;
81918
82385
  }
81919
82386
  case "agents": {
81920
- const agentsPath = path85.join(process.cwd(), "AGENTS.MD");
82387
+ const agentsPath = path86.join(process.cwd(), "AGENTS.MD");
81921
82388
  try {
81922
82389
  content = await fs41.readFile(agentsPath, "utf-8");
81923
82390
  } catch {
@@ -81926,7 +82393,7 @@ async function handleWorkspaceShow(ctx, what) {
81926
82393
  break;
81927
82394
  }
81928
82395
  case "docs": {
81929
- const docsDir = path85.join(zelari, "docs");
82396
+ const docsDir = path86.join(zelari, "docs");
81930
82397
  try {
81931
82398
  const files = (await fs41.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
81932
82399
  content = files.length ? `# Docs (${files.length})
@@ -81968,7 +82435,7 @@ async function handleWorkspaceReset(ctx, force) {
81968
82435
  return;
81969
82436
  }
81970
82437
  try {
81971
- const target = path85.join(process.cwd(), ".zelari");
82438
+ const target = path86.join(process.cwd(), ".zelari");
81972
82439
  await fs41.rm(target, { recursive: true, force: true });
81973
82440
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
81974
82441
  } catch (err) {
@@ -82306,6 +82773,7 @@ function useSlashDispatch(params) {
82306
82773
  handleProviderCustom(providerCtx, {
82307
82774
  endpoint: result.customEndpoint,
82308
82775
  clear: result.customClear,
82776
+ apiStyle: result.apiStyle,
82309
82777
  message: result.message
82310
82778
  });
82311
82779
  setInput("");
@@ -83851,8 +84319,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
83851
84319
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
83852
84320
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
83853
84321
  try {
83854
- const path99 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
83855
- name = path99 && /^[a-z0-9]/.test(path99) ? path99 : "imported-skill";
84322
+ const path100 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
84323
+ name = path100 && /^[a-z0-9]/.test(path100) ? path100 : "imported-skill";
83856
84324
  } catch {
83857
84325
  name = "imported-skill";
83858
84326
  }