zelari-code 1.47.1 → 1.48.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.
@@ -20,6 +20,7 @@ import { startPermissionBroker, } from "../mcp/permissionBroker.js";
20
20
  import { createBrokerPermissionHandler, createBrokerQuestionHandler, } from "../mcp/brokerHandlers.js";
21
21
  import { createPermissionAskHandler } from "./permissionPicker.js";
22
22
  import { appendSystem } from "./messageHelpers.js";
23
+ import { armPickerTimeout, askUserTimeoutMs } from "./askUserTimeout.js";
23
24
  export function usePermissionBroker(opts) {
24
25
  const { setPicker, setMessages } = opts;
25
26
  const handleRef = useRef(null);
@@ -42,13 +43,22 @@ export function usePermissionBroker(opts) {
42
43
  return;
43
44
  }
44
45
  let settled = false;
46
+ let cancelWaitTimeout;
45
47
  const finish = (value) => {
46
48
  if (settled)
47
49
  return;
48
50
  settled = true;
51
+ cancelWaitTimeout?.();
49
52
  setPicker(null);
50
53
  resolve(value);
51
54
  };
55
+ // v1.47.x: timeout so an unseen external-agent question cannot block
56
+ // the broker client forever. Knob: ZELARI_ASK_USER_TIMEOUT_MS.
57
+ const waitTimeoutMs = askUserTimeoutMs();
58
+ cancelWaitTimeout = armPickerTimeout(() => {
59
+ appendSystem(setMessages, `[external agent] nessuna risposta entro ${Math.round(waitTimeoutMs / 1000)}s — richiesta annullata.`, Date.now());
60
+ finish(null);
61
+ }, waitTimeoutMs);
52
62
  appendSystem(setMessages, `[external agent] ${req.question}\n→ ${choices.join(" · ")}`, Date.now());
53
63
  setPicker({
54
64
  kind: "clarification",
@@ -1 +1 @@
1
- {"version":3,"file":"usePermissionBroker.js","sourceRoot":"","sources":["../../../src/cli/hooks/usePermissionBroker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"usePermissionBroker.js","sourceRoot":"","sources":["../../../src/cli/hooks/usePermissionBroker.ts"],"names":[],"mappings":"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"}
@@ -628,7 +628,12 @@ async function refreshGrokToken(options) {
628
628
  grant_type: "refresh_token",
629
629
  client_id: options.clientId,
630
630
  refresh_token: options.refreshToken
631
- }).toString()
631
+ }).toString(),
632
+ // v1.47.x: hard 30s cap. A hung auth socket used to freeze the whole
633
+ // turn on "working" forever with no error (the refresh promise never
634
+ // settled). A visible failure is strictly better: callers fall back
635
+ // to the current token and surface the error.
636
+ signal: AbortSignal.timeout(3e4)
632
637
  });
633
638
  } catch (err) {
634
639
  throw new GrokOAuthError(
@@ -2873,15 +2878,90 @@ var init_advancedTools = __esm({
2873
2878
 
2874
2879
  // packages/core/dist/core/tools/zodBridge.js
2875
2880
  function zodToJsonSchema(schema) {
2881
+ let out;
2876
2882
  if (typeof schema.toJSONSchema === "function") {
2877
2883
  const res = schema.toJSONSchema();
2878
2884
  if (res && typeof res === "object") {
2879
2885
  const copy = { ...res };
2880
2886
  delete copy["$schema"];
2881
- return copy;
2887
+ out = copy;
2888
+ } else {
2889
+ out = _convert(schema);
2890
+ }
2891
+ } else {
2892
+ out = _convert(schema);
2893
+ }
2894
+ return ensureRootObjectType(out);
2895
+ }
2896
+ function ensureRootObjectType(schema) {
2897
+ if (schema.type === "object")
2898
+ return schema;
2899
+ const variants = schema.anyOf ?? schema.oneOf;
2900
+ if (!Array.isArray(variants) || variants.length === 0)
2901
+ return schema;
2902
+ const branches = [];
2903
+ for (const v of variants) {
2904
+ if (!v || typeof v !== "object" || Array.isArray(v) || v.type !== "object") {
2905
+ return schema;
2906
+ }
2907
+ branches.push(v);
2908
+ }
2909
+ const distinct = /* @__PURE__ */ new Map();
2910
+ for (const b of branches) {
2911
+ const props = b.properties ?? {};
2912
+ for (const [key, val] of Object.entries(props)) {
2913
+ const list = distinct.get(key) ?? [];
2914
+ if (!list.some((s) => JSON.stringify(s) === JSON.stringify(val)))
2915
+ list.push(val);
2916
+ distinct.set(key, list);
2917
+ }
2918
+ }
2919
+ const properties = {};
2920
+ for (const [key, schemas] of distinct) {
2921
+ if (schemas.length === 1) {
2922
+ properties[key] = schemas[0];
2923
+ continue;
2924
+ }
2925
+ const consts = [];
2926
+ let allConst = true;
2927
+ for (const s of schemas) {
2928
+ if (s && typeof s === "object" && "const" in s) {
2929
+ consts.push(s.const);
2930
+ } else {
2931
+ allConst = false;
2932
+ break;
2933
+ }
2934
+ }
2935
+ if (allConst) {
2936
+ const merged2 = { enum: consts };
2937
+ const t = typeof consts[0];
2938
+ if (consts.every((c) => typeof c === t)) {
2939
+ if (t === "string")
2940
+ merged2.type = "string";
2941
+ else if (t === "boolean")
2942
+ merged2.type = "boolean";
2943
+ else if (t === "number")
2944
+ merged2.type = Number.isInteger(consts[0]) ? "integer" : "number";
2945
+ }
2946
+ properties[key] = merged2;
2947
+ } else {
2948
+ properties[key] = { anyOf: schemas };
2882
2949
  }
2883
2950
  }
2884
- return _convert(schema);
2951
+ let required2;
2952
+ for (const b of branches) {
2953
+ const req = Array.isArray(b.required) ? b.required.filter((k) => typeof k === "string") : [];
2954
+ required2 = required2 === void 0 ? [...req] : required2.filter((k) => req.includes(k));
2955
+ }
2956
+ const merged = {
2957
+ type: "object",
2958
+ properties,
2959
+ required: required2 ?? []
2960
+ };
2961
+ if (branches.every((b) => b.additionalProperties === false)) {
2962
+ merged.additionalProperties = false;
2963
+ }
2964
+ return merged;
2885
2965
  }
2886
2966
  function _convert(schema) {
2887
2967
  const def = schema._def;
@@ -19444,7 +19524,7 @@ var init_web = __esm({
19444
19524
 
19445
19525
  // packages/core/dist/agents/harnessToolBridge.js
19446
19526
  function toEnhanced(tool) {
19447
- const schema = zodToJsonSchema(tool.inputSchema);
19527
+ const schema = tool.jsonSchema ?? zodToJsonSchema(tool.inputSchema);
19448
19528
  return {
19449
19529
  name: tool.name,
19450
19530
  description: tool.description,
@@ -32815,6 +32895,7 @@ function createInspectCommandTool(rootOrDeps) {
32815
32895
  permissions: ["read"],
32816
32896
  timeoutMs: 9e4,
32817
32897
  inputSchema: inspectInputSchema,
32898
+ jsonSchema: inspectJsonSchema,
32818
32899
  execute: async (input, ctx) => {
32819
32900
  const op = input;
32820
32901
  const cwd = ctx?.cwd ?? deps.root;
@@ -32847,7 +32928,7 @@ function createInspectCommandTool(rootOrDeps) {
32847
32928
  };
32848
32929
  return tool;
32849
32930
  }
32850
- var MAX_OUTPUT_CHARS, SPAWN_TIMEOUT_MS, TYPECHECK_TIMEOUT_MS, inspectInputSchema;
32931
+ var MAX_OUTPUT_CHARS, SPAWN_TIMEOUT_MS, TYPECHECK_TIMEOUT_MS, inspectInputSchema, INSPECT_OPERATIONS, inspectJsonSchema;
32851
32932
  var init_inspectCommand = __esm({
32852
32933
  "src/cli/tools/inspectCommand.ts"() {
32853
32934
  "use strict";
@@ -32878,6 +32959,29 @@ var init_inspectCommand = __esm({
32878
32959
  external_exports.object({ operation: external_exports.literal("npm_outdated") }),
32879
32960
  external_exports.object({ operation: external_exports.literal("npm_view"), package: external_exports.string().min(1) })
32880
32961
  ]);
32962
+ INSPECT_OPERATIONS = inspectInputSchema.options.map(
32963
+ (variant) => variant.shape.operation.value
32964
+ );
32965
+ inspectJsonSchema = {
32966
+ type: "object",
32967
+ properties: {
32968
+ operation: {
32969
+ type: "string",
32970
+ enum: INSPECT_OPERATIONS,
32971
+ description: "Inspection to run \u2014 pick from the menu instead of writing a command."
32972
+ },
32973
+ short: { type: "boolean", description: "git_status only: --short form." },
32974
+ limit: { type: "integer", minimum: 1, maximum: 200, description: "git_log only: max commits (default 20)." },
32975
+ oneline: { type: "boolean", description: "git_log only: one line per commit." },
32976
+ staged: { type: "boolean", description: "git_diff only: staged changes." },
32977
+ path: { type: "string", description: "git_diff only: limit the diff to this path." },
32978
+ ref: { type: "string", description: "git_show only (required there): commit or ref to show." },
32979
+ project: { type: "string", description: "typecheck only: subdirectory containing tsconfig.json." },
32980
+ package: { type: "string", description: "npm_view only (required there): package name." }
32981
+ },
32982
+ required: ["operation"],
32983
+ additionalProperties: false
32984
+ };
32881
32985
  }
32882
32986
  });
32883
32987
 
@@ -48296,9 +48400,17 @@ function WorkingIndicator({
48296
48400
  // src/cli/components/LiveRegion.tsx
48297
48401
  var LIVE_STREAM_TAIL_LINES = 10;
48298
48402
  var MAX_LIVE_TOOLS = 4;
48299
- function LiveRegion({ live, busy, elapsedMs = null }) {
48403
+ function LiveRegion({
48404
+ live,
48405
+ busy,
48406
+ elapsedMs = null,
48407
+ waitingForUser = false,
48408
+ waitingSinceMs = 0
48409
+ }) {
48300
48410
  const { streaming, runningTools } = live;
48301
- if (!streaming && runningTools.length === 0 && !busy) return null;
48411
+ if (!streaming && runningTools.length === 0 && !busy && !waitingForUser) {
48412
+ return null;
48413
+ }
48302
48414
  const visibleTools = runningTools.slice(0, MAX_LIVE_TOOLS);
48303
48415
  const hiddenTools = runningTools.length - visibleTools.length;
48304
48416
  return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingX: 1 }, streaming && streaming.role === "assistant" && /* @__PURE__ */ React5.createElement(
@@ -48310,7 +48422,7 @@ function LiveRegion({ live, busy, elapsedMs = null }) {
48310
48422
  memberName: streaming.memberName,
48311
48423
  memberId: streaming.memberId
48312
48424
  }
48313
- ), visibleTools.map((t) => /* @__PURE__ */ React5.createElement(Box4, { key: t.id, flexDirection: "column" }, renderMessage(t, true))), hiddenTools > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2026 +", hiddenTools, " more tools") : null, busy && runningTools.length === 0 && !streaming && /* @__PURE__ */ React5.createElement(WorkingIndicator, { elapsedMs }));
48425
+ ), visibleTools.map((t) => /* @__PURE__ */ React5.createElement(Box4, { key: t.id, flexDirection: "column" }, renderMessage(t, true))), hiddenTools > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2026 +", hiddenTools, " more tools") : null, waitingForUser && /* @__PURE__ */ React5.createElement(Text5, { color: "yellow", bold: true }, "\u23F8 In attesa della TUA risposta", waitingSinceMs > 0 ? ` (${Math.floor(Math.max(0, Date.now() - waitingSinceMs) / 1e3)}s)` : "", " \u2014 \u2191/\u2193 + Invio \xB7 Esc = annulla"), busy && runningTools.length === 0 && !streaming && !waitingForUser && /* @__PURE__ */ React5.createElement(WorkingIndicator, { elapsedMs }));
48314
48426
  }
48315
48427
  function StreamingTail(m) {
48316
48428
  const lines = m.content.split("\n");
@@ -51160,6 +51272,22 @@ init_taskTool();
51160
51272
 
51161
51273
  // src/cli/hooks/permissionPicker.ts
51162
51274
  init_toolPermissions();
51275
+
51276
+ // src/cli/hooks/askUserTimeout.ts
51277
+ function askUserTimeoutMs() {
51278
+ const raw = process.env.ZELARI_ASK_USER_TIMEOUT_MS?.trim();
51279
+ if (!raw) return 3e5;
51280
+ const n = Number.parseInt(raw, 10);
51281
+ if (!Number.isFinite(n) || n < 0) return 3e5;
51282
+ return n;
51283
+ }
51284
+ function armPickerTimeout(onFire, ms) {
51285
+ if (ms <= 0) return () => void 0;
51286
+ const id = setTimeout(onFire, ms);
51287
+ return () => clearTimeout(id);
51288
+ }
51289
+
51290
+ // src/cli/hooks/permissionPicker.ts
51163
51291
  function createPermissionAskHandler(opts) {
51164
51292
  const { setPicker: setPicker2, appendSystem: appendSystem2 } = opts;
51165
51293
  return (req) => new Promise((resolve3) => {
@@ -51174,13 +51302,25 @@ ${detail}
51174
51302
  Date.now()
51175
51303
  );
51176
51304
  let settled = false;
51305
+ const askTimeoutMs = askUserTimeoutMs();
51306
+ let cancelAskTimeout = () => void 0;
51177
51307
  const finish = (ok, note) => {
51178
51308
  if (settled) return;
51179
51309
  settled = true;
51310
+ cancelAskTimeout();
51180
51311
  setPicker2(null);
51181
51312
  if (note) appendSystem2?.(note, Date.now());
51182
51313
  resolve3(ok);
51183
51314
  };
51315
+ cancelAskTimeout = armPickerTimeout(
51316
+ () => finish(
51317
+ false,
51318
+ `[permission] ask for "${req.toolName}" timed out after ${Math.round(
51319
+ askTimeoutMs / 1e3
51320
+ )}s \u2014 denied (tool can be re-run). Knob: ZELARI_ASK_USER_TIMEOUT_MS.`
51321
+ ),
51322
+ askTimeoutMs
51323
+ );
51184
51324
  const items = [
51185
51325
  { value: "allow", label: "Allow once" },
51186
51326
  {
@@ -51530,12 +51670,28 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
51530
51670
  Date.now()
51531
51671
  );
51532
51672
  let settled = false;
51673
+ const askTimeoutMs = askUserTimeoutMs();
51674
+ let cancelAskTimeout = () => void 0;
51533
51675
  const finish = (value) => {
51534
51676
  if (settled) return;
51535
51677
  settled = true;
51678
+ cancelAskTimeout();
51536
51679
  setPicker2(null);
51537
51680
  resolve3(value);
51538
51681
  };
51682
+ cancelAskTimeout = armPickerTimeout(
51683
+ () => {
51684
+ appendSystem(
51685
+ setMessages,
51686
+ `[ask_user] nessuna risposta entro ${Math.round(
51687
+ askTimeoutMs / 1e3
51688
+ )}s \u2014 proseguo con assunzione documentata (ZELARI_ASK_USER_TIMEOUT_MS).`,
51689
+ Date.now()
51690
+ );
51691
+ finish(null);
51692
+ },
51693
+ askTimeoutMs
51694
+ );
51539
51695
  setPicker2({
51540
51696
  kind: "clarification",
51541
51697
  title: req.question,
@@ -52245,12 +52401,28 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
52245
52401
  Date.now()
52246
52402
  );
52247
52403
  let settled = false;
52404
+ const askTimeoutMs = askUserTimeoutMs();
52405
+ let cancelAskTimeout = () => void 0;
52248
52406
  const finish = (value) => {
52249
52407
  if (settled) return;
52250
52408
  settled = true;
52409
+ cancelAskTimeout();
52251
52410
  setPicker2(null);
52252
52411
  resolve3(value);
52253
52412
  };
52413
+ cancelAskTimeout = armPickerTimeout(
52414
+ () => {
52415
+ appendSystem(
52416
+ setMessages,
52417
+ `[council ask_user] nessuna risposta entro ${Math.round(
52418
+ askTimeoutMs / 1e3
52419
+ )}s \u2014 il membro prosegue con assunzione documentata (ZELARI_ASK_USER_TIMEOUT_MS).`,
52420
+ Date.now()
52421
+ );
52422
+ finish(null);
52423
+ },
52424
+ askTimeoutMs
52425
+ );
52254
52426
  setPicker2({
52255
52427
  kind: "clarification",
52256
52428
  title: req.question,
@@ -53015,12 +53187,25 @@ function usePermissionBroker(opts) {
53015
53187
  return;
53016
53188
  }
53017
53189
  let settled = false;
53190
+ let cancelWaitTimeout;
53018
53191
  const finish = (value) => {
53019
53192
  if (settled) return;
53020
53193
  settled = true;
53194
+ cancelWaitTimeout?.();
53021
53195
  setPicker2(null);
53022
53196
  resolve3(value);
53023
53197
  };
53198
+ const waitTimeoutMs = askUserTimeoutMs();
53199
+ cancelWaitTimeout = armPickerTimeout(() => {
53200
+ appendSystem(
53201
+ setMessages,
53202
+ `[external agent] nessuna risposta entro ${Math.round(
53203
+ waitTimeoutMs / 1e3
53204
+ )}s \u2014 richiesta annullata.`,
53205
+ Date.now()
53206
+ );
53207
+ finish(null);
53208
+ }, waitTimeoutMs);
53024
53209
  appendSystem(
53025
53210
  setMessages,
53026
53211
  `[external agent] ${req.question}
@@ -56296,6 +56481,11 @@ function App() {
56296
56481
  const [mode, setMode] = useState8("kraken");
56297
56482
  const [phase2, setPhaseUi] = useState8("build");
56298
56483
  const [picker, setPicker2] = useState8(null);
56484
+ const [pickerSince, setPickerSince] = useState8(0);
56485
+ useEffect8(() => {
56486
+ if (picker) setPickerSince((s) => s > 0 ? s : Date.now());
56487
+ else setPickerSince(0);
56488
+ }, [picker]);
56299
56489
  const activeProviderSpec = getActiveProvider();
56300
56490
  const activeModel = providerConfig.modelByProvider[activeProviderSpec.id];
56301
56491
  const session = useSession();
@@ -56420,7 +56610,16 @@ function App() {
56420
56610
  columns: size.columns || 80,
56421
56611
  rows: size.rows || 24
56422
56612
  }
56423
- ) : renderMessage(item)), /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", flexGrow: 1, paddingX: 1 }, /* @__PURE__ */ React10.createElement(LiveRegion, { live: session.live, busy, elapsedMs: timer.elapsedMs }), picker ? /* @__PURE__ */ React10.createElement(
56613
+ ) : renderMessage(item)), /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "row" }, /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", flexGrow: 1, paddingX: 1 }, /* @__PURE__ */ React10.createElement(
56614
+ LiveRegion,
56615
+ {
56616
+ live: session.live,
56617
+ busy,
56618
+ elapsedMs: timer.elapsedMs,
56619
+ waitingForUser: picker !== null,
56620
+ waitingSinceMs: pickerSince
56621
+ }
56622
+ ), picker ? /* @__PURE__ */ React10.createElement(
56424
56623
  SelectList,
56425
56624
  {
56426
56625
  title: picker.title,