@sema-agent/cli 1.0.42 → 1.0.43

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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.42",
3
+ "version": "1.0.43",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sema-agent/cli",
9
- "version": "1.0.42",
9
+ "version": "1.0.43",
10
10
  "license": "BUSL-1.1",
11
11
  "dependencies": {
12
12
  "@sema-agent/sdk": "0.0.63",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.42",
3
+ "version": "1.0.43",
4
4
  "description": "Sema — your own Claude Code-grade coding agent, in the terminal.",
5
5
  "license": "BUSL-1.1",
6
6
  "bin": {
package/sema.js CHANGED
@@ -244614,13 +244614,17 @@ __export(engineSideChannel_exports, {
244614
244614
  });
244615
244615
  import { readFileSync as readFileSync23 } from "node:fs";
244616
244616
  import { join as join73 } from "node:path";
244617
- async function sideQueryCapable(client4, baseUrl, signal) {
244617
+ async function sideQueryCapable(client4, baseUrl, budget, signal) {
244618
244618
  const hit = sideQueryCapByBase.get(baseUrl);
244619
- if (hit !== void 0) return hit;
244619
+ if (hit && (hit.ok || Date.now() - hit.at < CAP_FALSE_RETRY_TTL_MS)) return hit.ok;
244620
244620
  try {
244621
- const caps = await withTimeoutSignal(CAPS_PROBE_TIMEOUT_MS, signal, (s) => client4.capabilities({ signal: s }));
244621
+ const caps = await withTimeoutSignal(
244622
+ Math.min(CAPS_PROBE_TIMEOUT_MS, budget.remaining()),
244623
+ signal,
244624
+ (s) => client4.capabilities({ signal: s })
244625
+ );
244622
244626
  const ok2 = caps.sideQuery === true;
244623
- sideQueryCapByBase.set(baseUrl, ok2);
244627
+ sideQueryCapByBase.set(baseUrl, { ok: ok2, at: Date.now() });
244624
244628
  return ok2;
244625
244629
  } catch {
244626
244630
  return false;
@@ -244686,7 +244690,11 @@ async function resolvePoolModelRef(callerModel) {
244686
244690
  return void 0;
244687
244691
  }
244688
244692
  }
244689
- async function engineUtilityText(opts) {
244693
+ function makeBudget(totalMs) {
244694
+ const start = Date.now();
244695
+ return { remaining: () => Math.max(1, totalMs - (Date.now() - start)) };
244696
+ }
244697
+ async function engineUtilityCall(opts) {
244690
244698
  const baseUrl = process.env.SEMA_LIVE_BASEURL;
244691
244699
  if (!baseUrl) return null;
244692
244700
  const token = resolveEngineToken();
@@ -244696,117 +244704,90 @@ async function engineUtilityText(opts) {
244696
244704
  principal: process.env.SEMA_LIVE_PRINCIPAL ?? "anon:shell-live"
244697
244705
  });
244698
244706
  if (!client4) throw new Error("sema engine side-channel: wire client unavailable");
244699
- const cheap = process.env.MODEL_CHEAP_ID?.trim() || void 0;
244700
- const timeoutMs = opts.timeoutMs ?? SIDE_CHANNEL_TIMEOUT_MS;
244707
+ const cheap = opts.cheapSlot ? process.env.MODEL_CHEAP_ID?.trim() || void 0 : void 0;
244708
+ const budget = makeBudget(opts.timeoutMs ?? SIDE_CHANNEL_TIMEOUT_MS);
244709
+ const firstModel = opts.modelRef ?? cheap;
244701
244710
  const statusOf2 = (e) => {
244702
244711
  const s = e?.status;
244703
244712
  return typeof s === "number" ? s : void 0;
244704
244713
  };
244705
- const firstModel = opts.modelRef ?? cheap;
244706
- if (await sideQueryCapable(client4, baseUrl, opts.signal)) {
244707
- const query2 = (model) => withTimeoutSignal(
244708
- timeoutMs,
244714
+ const tasksArm = async () => {
244715
+ const submit = (model) => withTimeoutSignal(
244716
+ budget.remaining(),
244709
244717
  opts.signal,
244710
- (signal) => client4.sideQuery.query(
244718
+ (signal) => client4.tasks.submit(
244711
244719
  {
244712
- messages: [{ role: "user", content: opts.objective }],
244720
+ objective: opts.objective,
244721
+ sessionId: mintSideSessionId(),
244722
+ // 独立 session:utility 提示词绝不进主会话历史
244713
244723
  ...model ? { model } : {},
244714
- ...opts.maxTokens ? { maxOutputTokens: opts.maxTokens } : {}
244724
+ ...opts.maxTokens ? { maxTokens: opts.maxTokens } : {},
244725
+ ...opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {},
244726
+ ...opts.excludeTools ? { excludeTools: [...opts.excludeTools] } : {}
244715
244727
  },
244716
- { signal }
244728
+ { signal, idempotencyKey: null }
244717
244729
  )
244718
244730
  );
244719
- let r;
244731
+ let data;
244720
244732
  try {
244721
- r = await query2(firstModel);
244733
+ data = await submit(firstModel);
244722
244734
  } catch (e) {
244723
244735
  const status3 = statusOf2(e);
244724
244736
  if (opts.noFallback || status3 === void 0 || !firstModel || !CATALOG_GATE_STATUSES.has(status3)) throw e;
244725
- logForDebugging(`[side-channel] side-query ${status3} with model=${firstModel} \u2014 retrying on the default model`);
244726
- r = await query2(void 0);
244727
- }
244728
- return sideQueryTextOf(r);
244729
- }
244730
- const submit = (model) => withTimeoutSignal(
244731
- timeoutMs,
244732
- opts.signal,
244733
- (signal) => client4.tasks.submit(
244734
- {
244735
- objective: opts.objective,
244736
- sessionId: mintSideSessionId(),
244737
- // 独立 session:utility 提示词绝不进主会话历史
244738
- ...model ? { model } : {},
244739
- ...opts.maxTokens ? { maxTokens: opts.maxTokens } : {}
244740
- },
244741
- { signal, idempotencyKey: null }
244742
- )
244743
- );
244744
- let data;
244745
- try {
244746
- data = await submit(firstModel);
244747
- } catch (e) {
244748
- const status3 = statusOf2(e);
244749
- if (opts.noFallback || status3 === void 0 || !firstModel || !CATALOG_GATE_STATUSES.has(status3)) throw e;
244750
- logForDebugging(`[side-channel] engine ${status3} with model=${firstModel} \u2014 retrying on the default model`);
244751
- data = await submit(void 0);
244752
- }
244753
- const text2 = typeof data.result === "string" ? data.result.trim() : "";
244754
- if (!text2) throw new Error("sema engine side-channel: empty result");
244755
- return text2;
244756
- }
244757
- async function engineUtilityTask(opts) {
244758
- const baseUrl = process.env.SEMA_LIVE_BASEURL;
244759
- if (!baseUrl) throw new Error("sema engine side-channel: not active");
244760
- const token = resolveEngineToken();
244761
- const client4 = makeEngineWireClient({
244762
- baseUrl,
244763
- ...token ? { token } : {},
244764
- principal: process.env.SEMA_LIVE_PRINCIPAL ?? "anon:shell-live"
244765
- });
244766
- if (!client4) throw new Error("sema engine side-channel: wire client unavailable");
244767
- const timeoutMs = opts.timeoutMs ?? SIDE_CHANNEL_TIMEOUT_MS;
244768
- if (await sideQueryCapable(client4, baseUrl, opts.signal)) {
244769
- const r = await withTimeoutSignal(
244770
- timeoutMs,
244737
+ logForDebugging(`[side-channel] engine ${status3} with model=${firstModel} \u2014 retrying on the default model`);
244738
+ data = await submit(void 0);
244739
+ }
244740
+ const text2 = typeof data.result === "string" ? data.result.trim() : "";
244741
+ if (!text2) throw new Error("sema engine side-channel: empty result");
244742
+ const st2 = data.stats;
244743
+ const usage = st2 ? {
244744
+ input_tokens: st2.promptTokens ?? st2.totalInputTokens ?? 0,
244745
+ output_tokens: st2.outputTokens ?? 0,
244746
+ cache_creation_input_tokens: st2.cacheWriteTokens ?? 0,
244747
+ cache_read_input_tokens: st2.cachedTokens ?? 0
244748
+ } : null;
244749
+ return { text: text2, usage };
244750
+ };
244751
+ if (await sideQueryCapable(client4, baseUrl, budget, opts.signal)) {
244752
+ const query2 = (model) => withTimeoutSignal(
244753
+ budget.remaining(),
244771
244754
  opts.signal,
244772
244755
  (signal) => client4.sideQuery.query(
244773
244756
  {
244774
244757
  messages: [{ role: "user", content: opts.objective }],
244775
- ...opts.modelRef ? { model: opts.modelRef } : {},
244758
+ ...model ? { model } : {},
244776
244759
  ...opts.maxTokens ? { maxOutputTokens: opts.maxTokens } : {},
244777
244760
  ...opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {}
244778
244761
  },
244779
244762
  { signal }
244780
244763
  )
244781
244764
  );
244765
+ let r;
244766
+ try {
244767
+ r = await query2(firstModel);
244768
+ } catch (e) {
244769
+ const status3 = statusOf2(e);
244770
+ if (status3 !== void 0 && ENDPOINT_GONE_STATUSES.has(status3)) {
244771
+ sideQueryCapByBase.set(baseUrl, { ok: false, at: Date.now() });
244772
+ logForDebugging(`[side-channel] side-query endpoint gone (${status3}) \u2014 falling back to tasks`);
244773
+ return await tasksArm();
244774
+ }
244775
+ if (opts.noFallback || status3 === void 0 || !firstModel || !SIDEQUERY_MODEL_GATE_STATUSES.has(status3)) throw e;
244776
+ logForDebugging(`[side-channel] side-query ${status3} with model=${firstModel} \u2014 retrying on the default model`);
244777
+ r = await query2(void 0);
244778
+ }
244782
244779
  return { text: sideQueryTextOf(r), usage: usageFromSideQuery(r) };
244783
244780
  }
244784
- const data = await withTimeoutSignal(
244785
- timeoutMs,
244786
- opts.signal,
244787
- (signal) => client4.tasks.submit(
244788
- {
244789
- objective: opts.objective,
244790
- sessionId: mintSideSessionId(),
244791
- // 独立 session:utility 提示词绝不进主会话历史
244792
- ...opts.modelRef ? { model: opts.modelRef } : {},
244793
- ...opts.maxTokens ? { maxTokens: opts.maxTokens } : {},
244794
- ...opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {},
244795
- ...opts.excludeTools ? { excludeTools: [...opts.excludeTools] } : {}
244796
- },
244797
- { signal, idempotencyKey: null }
244798
- )
244799
- );
244800
- const text2 = typeof data.result === "string" ? data.result.trim() : "";
244801
- if (!text2) throw new Error("sema engine side-channel: empty result");
244802
- const st2 = data.stats;
244803
- const usage = st2 ? {
244804
- input_tokens: st2.promptTokens ?? st2.totalInputTokens ?? 0,
244805
- output_tokens: st2.outputTokens ?? 0,
244806
- cache_creation_input_tokens: st2.cacheWriteTokens ?? 0,
244807
- cache_read_input_tokens: st2.cachedTokens ?? 0
244808
- } : null;
244809
- return { text: text2, usage };
244781
+ return await tasksArm();
244782
+ }
244783
+ async function engineUtilityText(opts) {
244784
+ const r = await engineUtilityCall({ ...opts, cheapSlot: true });
244785
+ return r === null ? null : r.text;
244786
+ }
244787
+ async function engineUtilityTask(opts) {
244788
+ const r = await engineUtilityCall(opts);
244789
+ if (r === null) throw new Error("sema engine side-channel: not active");
244790
+ return r;
244810
244791
  }
244811
244792
  function extractJsonObjectText(text2) {
244812
244793
  const m2 = text2.match(/\{[\s\S]*\}/);
@@ -244824,7 +244805,7 @@ function jsonDisciplineSuffix(schema) {
244824
244805
  Return ONLY a JSON object (no prose, no markdown code fences) that matches this JSON Schema:
244825
244806
  ${JSON.stringify(schema)}`;
244826
244807
  }
244827
- var SIDE_CHANNEL_TIMEOUT_MS, sideQueryCapByBase, CAPS_PROBE_TIMEOUT_MS, CATALOG_GATE_STATUSES, UTILITY_EXCLUDE_ALL_TOOLS;
244808
+ var SIDE_CHANNEL_TIMEOUT_MS, sideQueryCapByBase, CAPS_PROBE_TIMEOUT_MS, CAP_FALSE_RETRY_TTL_MS, CATALOG_GATE_STATUSES, SIDEQUERY_MODEL_GATE_STATUSES, ENDPOINT_GONE_STATUSES, UTILITY_EXCLUDE_ALL_TOOLS;
244828
244809
  var init_engineSideChannel = __esm({
244829
244810
  "build-src/src/sema/engineSideChannel.ts"() {
244830
244811
  init_debug();
@@ -244833,7 +244814,10 @@ var init_engineSideChannel = __esm({
244833
244814
  SIDE_CHANNEL_TIMEOUT_MS = 6e4;
244834
244815
  sideQueryCapByBase = /* @__PURE__ */ new Map();
244835
244816
  CAPS_PROBE_TIMEOUT_MS = 5e3;
244817
+ CAP_FALSE_RETRY_TTL_MS = 5 * 6e4;
244836
244818
  CATALOG_GATE_STATUSES = /* @__PURE__ */ new Set([400, 404, 422]);
244819
+ SIDEQUERY_MODEL_GATE_STATUSES = /* @__PURE__ */ new Set([400, 422]);
244820
+ ENDPOINT_GONE_STATUSES = /* @__PURE__ */ new Set([404, 405, 501]);
244837
244821
  UTILITY_EXCLUDE_ALL_TOOLS = [
244838
244822
  "Bash",
244839
244823
  "PowerShell",
@@ -272431,14 +272415,16 @@ async function semaSideQueryViaEngine(opts, side) {
272431
272415
  else if (opts.output_format?.schema) objective += side.jsonDisciplineSuffix(opts.output_format.schema);
272432
272416
  const isModelValidation = opts.querySource === "model_validation";
272433
272417
  const modelRef = await side.resolvePoolModelRef(opts.model) ?? (isModelValidation ? opts.model : void 0);
272434
- const text2 = await side.engineUtilityText({
272418
+ const r = await side.engineUtilityTask({
272435
272419
  objective,
272436
272420
  signal: opts.signal,
272437
272421
  // validateModel 类 1-token ping 在任务语义下会空转 → 托底 16,verdict 仍由成功/失败承载
272438
272422
  maxTokens: Math.max(16, opts.max_tokens ?? 1024),
272439
272423
  modelRef,
272440
- noFallback: isModelValidation
272441
- }) ?? "";
272424
+ noFallback: isModelValidation,
272425
+ cheapSlot: true
272426
+ });
272427
+ const text2 = r.text;
272442
272428
  const stamp2 = Date.now().toString(36);
272443
272429
  let content;
272444
272430
  if (forcedTool) {
@@ -272465,7 +272451,8 @@ async function semaSideQueryViaEngine(opts, side) {
272465
272451
  content,
272466
272452
  stop_reason: "end_turn",
272467
272453
  stop_sequence: null,
272468
- usage: {
272454
+ // 对抗复审批 #3:verb 臂权威 usage / tasks 臂 TaskStats 映射;引擎无账时诚实零
272455
+ usage: r.usage ?? {
272469
272456
  input_tokens: 0,
272470
272457
  output_tokens: 0,
272471
272458
  cache_creation_input_tokens: 0,
@@ -355994,7 +355981,7 @@ function useClaudeAiLimits() {
355994
355981
  var import_react64;
355995
355982
  var init_claudeAiLimitsHook = __esm({
355996
355983
  "build-src/src/services/claudeAiLimitsHook.ts"() {
355997
- import_react64 = __toESM(require_react(), 1);
355984
+ import_react64 = __toESM(require_react());
355998
355985
  init_claudeAiLimits();
355999
355986
  }
356000
355987
  });
@@ -451647,7 +451634,7 @@ function Settings({
451647
451634
  var import_react113, import_jsx_runtime193;
451648
451635
  var init_cmd_config = __esm({
451649
451636
  "build-src/src/sema/overrides/cmd-config.tsx"() {
451650
- import_react113 = __toESM(require_react(), 1);
451637
+ import_react113 = __toESM(require_react());
451651
451638
  init_useKeybinding();
451652
451639
  init_useExitOnCtrlCDWithKeybindings();
451653
451640
  init_useTerminalSize();
@@ -451658,7 +451645,7 @@ var init_cmd_config = __esm({
451658
451645
  init_Config();
451659
451646
  init_settings_usage();
451660
451647
  init_Stats();
451661
- import_jsx_runtime193 = __toESM(require_jsx_runtime(), 1);
451648
+ import_jsx_runtime193 = __toESM(require_jsx_runtime());
451662
451649
  }
451663
451650
  });
451664
451651
 
@@ -480451,13 +480438,13 @@ var init_sema_brand = __esm({
480451
480438
  _doc: "Rendered as the 'What's new' feed (createWhatsNewFeed). Top version MUST be >= current app version (2.1.187) and newer than config.lastReleaseNotesSeen so the notes display and full-logo mode triggers. Pinned == app version (2.1.187) + lastReleaseNotesSeen (loginState.ts) so getRecentReleaseNotes()===[] \u2192 condensed logo (matches refs/chrome.empty-input.json).",
480452
480439
  version: "2.1.187",
480453
480440
  notes: [
480454
- "/btw and background utilities now use the engine's dedicated side-query channel \u2014 no session storage residue at all (previously each call left a small side-session file)",
480455
- "Utility calls on the new channel have no tool surface whatsoever \u2014 isolation is structural, not instruction-based",
480456
- "Older engines are detected automatically and keep the previous isolated-session behavior"
480441
+ "Utility channel now adapts live to engine upgrades/rollbacks \u2014 no restarts needed, no stuck calls",
480442
+ "Background utility calls enforce a single strict time budget (probe + retry + transport)",
480443
+ "Token usage from background utilities is now reported accurately (no more zeros in accounting)"
480457
480444
  ]
480458
480445
  },
480459
- productVersion: "1.0.42",
480460
- announcement: "sema 1.0.42 \u2014 background utility calls (/btw, session titles, recaps) now run through the engine's new side-query channel: zero session files left behind, tool access structurally impossible, and accurate token accounting."
480446
+ productVersion: "1.0.43",
480447
+ announcement: "sema 1.0.43 \u2014 hardening for the new side-query channel: engine rollbacks/upgrades are now detected live (no stuck utilities), strict time budgets, and real token accounting flows through every background utility call."
480461
480448
  };
480462
480449
  }
480463
480450
  });
@@ -483386,13 +483373,13 @@ var require_sema_brand = __commonJS({
483386
483373
  _doc: "Rendered as the 'What's new' feed (createWhatsNewFeed). Top version MUST be >= current app version (2.1.187) and newer than config.lastReleaseNotesSeen so the notes display and full-logo mode triggers. Pinned == app version (2.1.187) + lastReleaseNotesSeen (loginState.ts) so getRecentReleaseNotes()===[] \u2192 condensed logo (matches refs/chrome.empty-input.json).",
483387
483374
  version: "2.1.187",
483388
483375
  notes: [
483389
- "/btw and background utilities now use the engine's dedicated side-query channel \u2014 no session storage residue at all (previously each call left a small side-session file)",
483390
- "Utility calls on the new channel have no tool surface whatsoever \u2014 isolation is structural, not instruction-based",
483391
- "Older engines are detected automatically and keep the previous isolated-session behavior"
483376
+ "Utility channel now adapts live to engine upgrades/rollbacks \u2014 no restarts needed, no stuck calls",
483377
+ "Background utility calls enforce a single strict time budget (probe + retry + transport)",
483378
+ "Token usage from background utilities is now reported accurately (no more zeros in accounting)"
483392
483379
  ]
483393
483380
  },
483394
- productVersion: "1.0.42",
483395
- announcement: "sema 1.0.42 \u2014 background utility calls (/btw, session titles, recaps) now run through the engine's new side-query channel: zero session files left behind, tool access structurally impossible, and accurate token accounting."
483381
+ productVersion: "1.0.43",
483382
+ announcement: "sema 1.0.43 \u2014 hardening for the new side-query channel: engine rollbacks/upgrades are now detected live (no stuck utilities), strict time budgets, and real token accounting flows through every background utility call."
483396
483383
  };
483397
483384
  }
483398
483385
  });
@@ -530605,16 +530592,20 @@ async function semaEngineNonStreamingLeg({
530605
530592
  if (options.outputFormat?.schema) {
530606
530593
  objective += side.jsonDisciplineSuffix(options.outputFormat.schema);
530607
530594
  }
530608
- const text2 = await side.engineUtilityText({
530595
+ const r = await side.engineUtilityTask({
530609
530596
  objective,
530610
530597
  signal,
530611
530598
  maxTokens: options.maxOutputTokensOverride,
530599
+ cheapSlot: true,
530612
530600
  // 池内模型透传(A2 兜底):queryWithModel/advisor 显式选池模型时按所选路由;CC 名走 cheap/默认
530613
530601
  modelRef: await side.resolvePoolModelRef(options.model)
530614
530602
  });
530615
- if (text2 === null) return null;
530603
+ const text2 = r.text;
530616
530604
  const content = options.outputFormat?.schema ? side.extractJsonObjectText(text2) ?? text2 : text2;
530617
- return createAssistantMessage({ content });
530605
+ return createAssistantMessage({
530606
+ content,
530607
+ ...r.usage ? { usage: r.usage } : {}
530608
+ });
530618
530609
  }
530619
530610
  async function queryModelWithoutStreaming({
530620
530611
  messages,
@@ -609355,8 +609346,8 @@ function _temp161() {
609355
609346
  var import_compiler_runtime316, import_react314, SETTINGS_ERRORS_NOTIFICATION_KEY;
609356
609347
  var init_useSettingsErrors = __esm({
609357
609348
  "build-src/src/hooks/notifs/useSettingsErrors.tsx"() {
609358
- import_compiler_runtime316 = __toESM(require_compiler_runtime(), 1);
609359
- import_react314 = __toESM(require_react(), 1);
609349
+ import_compiler_runtime316 = __toESM(require_compiler_runtime());
609350
+ import_react314 = __toESM(require_react());
609360
609351
  init_notifications();
609361
609352
  init_state();
609362
609353
  init_allErrors();
@@ -655599,7 +655590,7 @@ Auth: unix socket -R \u2192 local proxy`, "info");
655599
655590
  pendingHookMessages
655600
655591
  }, renderAndRun);
655601
655592
  }
655602
- }).version("sema 1.0.42", "-v, --version", "Output the version number");
655593
+ }).version("sema 1.0.43", "-v, --version", "Output the version number");
655603
655594
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
655604
655595
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
655605
655596
  if (canUserConfigureAdvisor()) {