@sema-agent/cli 1.0.57 → 1.0.58

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 (3) hide show
  1. package/npm-shrinkwrap.json +12 -12
  2. package/package.json +5 -5
  3. package/sema.js +154 -131
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.57",
3
+ "version": "1.0.58",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sema-agent/cli",
9
- "version": "1.0.57",
9
+ "version": "1.0.58",
10
10
  "license": "BUSL-1.1",
11
11
  "dependencies": {
12
- "@sema-agent/sdk": "0.1.0",
12
+ "@sema-agent/sdk": "0.1.7",
13
13
  "@sema-agent/server": "1.303.0"
14
14
  },
15
15
  "bin": {
@@ -620,9 +620,9 @@
620
620
  }
621
621
  },
622
622
  "node_modules/@sema-agent/core": {
623
- "version": "1.449.0",
624
- "resolved": "https://registry.npmjs.org/@sema-agent/core/-/core-1.449.0.tgz",
625
- "integrity": "sha512-96/xytGODYAZZ3A1hz+5DyknCVegqHREl/VmjSwI9dbNacwsEzm5Fb+t7Emq0L0MCMNs57p6ehL7JK7Ip1YMyg==",
623
+ "version": "1.452.0",
624
+ "resolved": "https://registry.npmjs.org/@sema-agent/core/-/core-1.452.0.tgz",
625
+ "integrity": "sha512-bF//hcLf7dkhFmwPnSe6UOccUJvd/SljrtdRsSsq0SAyTDnmKIuVZnzQqRDp+W7aX/b7TZ5ZhL1pSNTiwtRRZg==",
626
626
  "license": "BUSL-1.1",
627
627
  "dependencies": {
628
628
  "@modelcontextprotocol/sdk": "1.29.0",
@@ -639,9 +639,9 @@
639
639
  }
640
640
  },
641
641
  "node_modules/@sema-agent/registry-core": {
642
- "version": "0.10.22",
643
- "resolved": "https://registry.npmjs.org/@sema-agent/registry-core/-/registry-core-0.10.22.tgz",
644
- "integrity": "sha512-89x+ezW1HmifLJsikhUjyOF8FxOh/lzj7fibOTC1fFjDhItHgn1Hqbz0aEyHgPbBVqPgmpHlK+J0+7vEeqepMQ==",
642
+ "version": "0.10.23",
643
+ "resolved": "https://registry.npmjs.org/@sema-agent/registry-core/-/registry-core-0.10.23.tgz",
644
+ "integrity": "sha512-hFPL5YtNCOUG7zp+NkZSynVwqMoScjuTshH2XYi6816zcALajgSmOvEoTZR1X/Ter9DNcMaGAlaS5OnNtPTuhQ==",
645
645
  "license": "BUSL-1.1",
646
646
  "dependencies": {
647
647
  "zod": "^3.24.0"
@@ -663,9 +663,9 @@
663
663
  }
664
664
  },
665
665
  "node_modules/@sema-agent/sdk": {
666
- "version": "0.1.0",
667
- "resolved": "https://registry.npmjs.org/@sema-agent/sdk/-/sdk-0.1.0.tgz",
668
- "integrity": "sha512-7niJe+whPlC7IBpgTXq5rxTYZfmVvU3Zigjt9Dq4sYnhvQAieNZBEIjOYQNoS/xQDJIEE5E7z4iJLjYM4cmdjA==",
666
+ "version": "0.1.7",
667
+ "resolved": "https://registry.npmjs.org/@sema-agent/sdk/-/sdk-0.1.7.tgz",
668
+ "integrity": "sha512-/jEvBEQyPl2a+5v6laH/VevjpQ3LZqPWAM5OqJ5I/3JbYy5nYQFXjRsTtKLcJ+/0MF6ioE+I9KnHN7pa+zXBJQ==",
669
669
  "license": "BUSL-1.1",
670
670
  "engines": {
671
671
  "node": ">=20"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.57",
3
+ "version": "1.0.58",
4
4
  "description": "Sema — your own Claude Code-grade coding agent, in the terminal.",
5
5
  "license": "BUSL-1.1",
6
6
  "bin": {
@@ -21,14 +21,14 @@
21
21
  "sema"
22
22
  ],
23
23
  "dependencies": {
24
- "@sema-agent/sdk": "0.1.0",
24
+ "@sema-agent/sdk": "0.1.7",
25
25
  "@sema-agent/server": "1.303.0"
26
26
  },
27
27
  "overrides": {
28
- "@sema-agent/core": "1.449.0",
29
- "@sema-agent/registry-core": "0.10.22"
28
+ "@sema-agent/core": "1.452.0",
29
+ "@sema-agent/registry-core": "0.10.23"
30
30
  },
31
- "semaEngineVersion": "server 1.303.0 / core 1.449.0 / registry-core 0.10.22",
31
+ "semaEngineVersion": "server 1.303.0 / core 1.452.0 / registry-core 0.10.23",
32
32
  "engines": {
33
33
  "node": ">=18"
34
34
  }
package/sema.js CHANGED
@@ -70694,9 +70694,12 @@ function flattenToolOutput(output) {
70694
70694
  }
70695
70695
  return "";
70696
70696
  }
70697
- function bashExitCodeFailed(toolName2, text2) {
70697
+ function bashExitCodeFailed(toolName2, text2, structured) {
70698
70698
  if (typeof toolName2 !== "string" || toolName2.toLowerCase() !== "bash")
70699
70699
  return false;
70700
+ const ec2 = structured?.exitCode;
70701
+ if (typeof ec2 === "number")
70702
+ return ec2 !== 0;
70700
70703
  const m2 = /^exit code: (\d+)\b/.exec(text2);
70701
70704
  return m2 !== null && m2[1] !== "0";
70702
70705
  }
@@ -70715,7 +70718,7 @@ function toolEndResultToUserFrame(arm) {
70715
70718
  // truncated 输出如实标注(观察面注记;截断体绝不回喂模型——upstreamBridge 同款)。
70716
70719
  content: arm.truncated === true ? `${text2}
70717
70720
  \u2026(truncated)` : text2,
70718
- is_error: arm.isError === true || bashExitCodeFailed(arm.toolName, text2)
70721
+ is_error: arm.isError === true || bashExitCodeFailed(arm.toolName, text2, arm.structured)
70719
70722
  }
70720
70723
  ]
70721
70724
  },
@@ -70803,7 +70806,7 @@ function errCodes(e) {
70803
70806
  if (!e || typeof e !== "object")
70804
70807
  return {};
70805
70808
  const o = e;
70806
- return { code: o.errorCode ?? o.code, name: o.name, status: o.status ?? o.statusCode };
70809
+ return { code: o.errorCode, name: o.name, status: o.status ?? o.statusCode };
70807
70810
  }
70808
70811
  function isSteeringNotRunning(e) {
70809
70812
  const { code: code2, name } = errCodes(e);
@@ -76769,7 +76772,7 @@ function isBindingMismatch(e) {
76769
76772
  if (!e || typeof e !== "object")
76770
76773
  return false;
76771
76774
  const o = e;
76772
- const code2 = o.errorCode ?? o.code;
76775
+ const code2 = o.errorCode;
76773
76776
  if (code2 === "approval_binding_mismatch")
76774
76777
  return true;
76775
76778
  if (typeof o.name === "string" && o.name === "ApprovalBindingMismatchError")
@@ -223628,12 +223631,7 @@ function toTaskRequest(params) {
223628
223631
  if (wireHooks && process.env.SEMA_DEBUG) {
223629
223632
  console.error(`[sema][seamQuery] hooks wire: ${Object.keys(wireHooks).join("+")} \u2192 TaskRequest.settings.hooks`);
223630
223633
  }
223631
- const settingsOut = seamSettings || webSearch || ultracode || wireHooks ? {
223632
- ...seamSettings ?? {},
223633
- ...webSearch ? { webSearch } : {},
223634
- ...ultracode ? { ultracode } : {},
223635
- ...wireHooks ? { hooks: wireHooks } : {}
223636
- } : void 0;
223634
+ const clientContextFields = clientContextField(getTimeZone());
223637
223635
  const selfOrchestration = process.env.SEMA_LIVE_BASEURL ? selfOrchestrationFromEnv() : void 0;
223638
223636
  if (selfOrchestration && process.env.SEMA_DEBUG) {
223639
223637
  console.error("[sema][seamQuery] selfOrchestration wire: SEMA_SELF_ORCHESTRATION \u2192 TaskRequest.selfOrchestration=true (run_workflow)");
@@ -223695,70 +223693,79 @@ ${objective}`;
223695
223693
  console.error("[sema][seamQuery] sandbox wire: --sandbox auto advisory \u2192 objective (one-shot; model drives SelectEnvironment)");
223696
223694
  }
223697
223695
  }
223698
- return {
223699
- objective,
223700
- // SINGLE NAMESPACE (TP-A Step 2): stamp the SHELL's own sessionId (STATE.sessionId) — NOT the fixed mock
223701
- // constant — so the engine's session === the shell's session (engineSessionId === shellSessionId). The
223702
- // engine accepts a caller-supplied sessionId (server.ts:3565 LENGTH-ONLY ≤64; spec.sessionId → acquire →
223703
- // openOrCreate uses it verbatim), so the first turn's done.result.sessionId echoes back getSessionId().
223704
- // /fork, /rewind, events.jsonl and the shell's <sessionId>.jsonl all align on ONE id with no mapping.
223705
- // On the MOCK (offline) path this id is echoed straight back (mockClient: done.sessionId = req.sessionId).
223706
- // On the LIVE path liveClient.toLiveRequest preserves it (first turn) or reuses the captured id (continuity).
223707
- sessionId: getSessionId(),
223708
- ...scenario2 ? { scenario: scenario2 } : {},
223709
- ...typeof sysPrompt === "string" ? { systemPrompt: sysPrompt } : {},
223710
- ...reasoningEffort ? { reasoningEffort } : {},
223711
- // The loaded on-disk skills (.sema/skills/SKILL.md), projected to SkillSpec[] and server-capped
223712
- // (skillsWire.ts). Present ONLY when launchReplProduction loaded + injected them on the live path; unset
223713
- // on the mock path and on a skill-less live launch, so neither the mock nor a no-skills request changes
223714
- // shape. liveClient.toLiveRequest spreads {...req}, so this survives to the live engine untouched.
223715
- ...seamSkills ? { skills: seamSkills } : {},
223716
- // The local .mcp.json servers (CC parity), projected to McpServerSpec[] (mcpWire.ts). Present ONLY when
223717
- // launchReplProduction loaded them on the live path. liveClient.toLiveRequest spreads {...req} so this
223718
- // survives to the engine, where the SERVICE single-user gate (1.20.0) decides whether to honor it.
223719
- ...seamMcp ? { mcpServers: seamMcp } : {},
223720
- // CC Rewind (E18): per-turn capture flag (rewindFiles:true) on normal turns, or a one-shot restore
223721
- // (resumeAt/rewindFiles/rewindFilesTo) when /rewind armed it. Empty ⇒ no stamp (capture disabled + no arm).
223722
- ...rewindFields,
223723
- // CC permission mode (R4): the raw permissionMode intent (service interprets, tighten-only); empty on default.
223724
- ...permissionFields,
223725
- // CC /model (WIRE-1): the per-turn selected model; service resolveTaskModel catalog-gates it. Empty on default.
223726
- ...modelFields,
223727
- // imagesWire (CC paste-image): the submitted user message's image blocks → engine ImageInput[]. Omit if none.
223728
- ...images.length > 0 ? { images } : {},
223729
- // Workflow super-set: the top-level selfOrchestration flag (SEMA_SELF_ORCHESTRATION env opt-in, live-gated).
223730
- // Present ⇒ the SERVICE mounts core run_workflow (gated on its deployment/tenant policy); absent ⇒ no stamp.
223731
- ...selfOrchestration ? { selfOrchestration } : {},
223732
- // Workflow deferred-disclosure ([1052]①): absent = fully exposed (activation turn / opt-out); present =
223733
- // core 1.314 placeholder-on-wire, schema bytes out of the cache prefix, ToolSearch-activatable.
223734
- ...deferTools ? { deferTools } : {},
223735
- ...retainBackground ? { retainBackgroundProcesses: retainBackground } : {},
223736
- ...promptProfile ? { promptProfile } : {},
223737
- // Fork super-set: the top-level enableFork flag — EXPLICIT boolean on live (core ≥1.257 treats absent
223738
- // as granted; the shell's default-OFF product decision must be spelled out). Mock path stays unstamped.
223739
- ...enableFork !== void 0 ? { enableFork } : {},
223740
- // Turn-boundary attachments (design/133 + G1): default-on G1 pair on the live path; service → core opt-in.
223741
- ...attachments ? { attachments } : {},
223742
- // The resolver's effective settings (hooks/env/model + resolved permissions, live + SEMA_SEND_SETTINGS opt-in)
223743
- // MERGED with the WebSearch backend config (SEMA_WEBSEARCH_* env / settings.json, its own live-only opt-in) →
223744
- // the engine's TOB-fleet 透传 field. Both absent ⇒ no `settings` (mock parity + default live behaviour preserved).
223745
- ...settingsOut ? { settings: settingsOut } : {},
223746
- // clientContext (clientContextWireCaps, design/112 — core 1.181): the user's LOCAL identity facts (IANA
223747
- // timeZone from utils/intl `getTimeZone()`, + optional SEMA_USER_EMAIL). The SERVICE relays it to core
223748
- // `TaskSpec.clientContext` → core localizes the `# Environment` block's "today" to the user's zone (+ a
223749
- // `(Asia/Tokyo)`-style annotation); absent ⇒ core annotates `(UTC)` so the model knows it's container time.
223750
- // Benign metadata (no secret), always-derivable ⇒ stamped on every request (mock ignores it; core 1.186
223751
- // validates the zone and only `timeZone`+`userEmail` are live — `locale` was deleted, never set here).
223752
- ...clientContextField(getTimeZone()),
223753
- // [686]② `--sandbox <profile>` (EXPLICIT): the per-task image PROFILE (never a digest — the server
223754
- // re-resolves fail-closed with the caller's principal). Absent on default/auto/mock (b 口径:缺省不发).
223755
- ...sandboxFields,
223756
- // scratchpad 域([816] 壳侧承诺③ / [820]③,scratchpadWireCaps):vendored getScratchpadDir 的
223757
- // per-session 路径 → TaskRequest.scratchpadDir(server 半场填 envFacts.scratchpadDir + 工厂
223758
- // exemptDirs;没到货时引擎忽略=无害 additive)。gate off ⇒ 无 stamp;live-gated 同 webSearch
223759
- // 使 mock 请求形状不变。
223760
- ...process.env.SEMA_LIVE_BASEURL ? scratchpadDirField() : {}
223761
- };
223696
+ return buildTaskRequest(
223697
+ {
223698
+ objective,
223699
+ // SINGLE NAMESPACE (TP-A Step 2): stamp the SHELL's own sessionId (STATE.sessionId) — NOT the fixed mock
223700
+ // constant — so the engine's session === the shell's session (engineSessionId === shellSessionId). The
223701
+ // engine accepts a caller-supplied sessionId (server.ts:3565 LENGTH-ONLY ≤64; spec.sessionId → acquire →
223702
+ // openOrCreate uses it verbatim), so the first turn's done.result.sessionId echoes back getSessionId().
223703
+ // /fork, /rewind, events.jsonl and the shell's <sessionId>.jsonl all align on ONE id with no mapping.
223704
+ // On the MOCK (offline) path this id is echoed straight back (mockClient: done.sessionId = req.sessionId).
223705
+ // On the LIVE path liveClient.toLiveRequest preserves it (first turn) or reuses the captured id (continuity).
223706
+ sessionId: getSessionId(),
223707
+ live: Boolean(process.env.SEMA_LIVE_BASEURL),
223708
+ ...scenario2 ? { scenario: scenario2 } : {},
223709
+ ...typeof sysPrompt === "string" ? { systemPrompt: sysPrompt } : {},
223710
+ ...reasoningEffort ? { reasoningEffort } : {},
223711
+ // CC /model (WIRE-1): the per-turn selected model; service resolveTaskModel catalog-gates it. Empty on default.
223712
+ ...modelFields,
223713
+ // imagesWire (CC paste-image): the submitted user message's image blocks → engine ImageInput[]. Omit if none.
223714
+ ...images.length > 0 ? { images } : {},
223715
+ // The loaded on-disk skills (.sema/skills/SKILL.md), projected to SkillSpec[] and server-capped
223716
+ // (skillsWire.ts). Present ONLY when launchReplProduction loaded + injected them on the live path; unset
223717
+ // on the mock path and on a skill-less live launch, so neither the mock nor a no-skills request changes
223718
+ // shape. liveClient.toLiveRequest spreads {...req}, so this survives to the live engine untouched.
223719
+ ...seamSkills ? { skills: seamSkills } : {},
223720
+ // The local .mcp.json servers (CC parity), projected to McpServerSpec[] (mcpWire.ts). Present ONLY when
223721
+ // launchReplProduction loaded them on the live path. liveClient.toLiveRequest spreads {...req} so this
223722
+ // survives to the engine, where the SERVICE single-user gate (1.20.0) decides whether to honor it.
223723
+ ...seamMcp ? { mcpServers: seamMcp } : {},
223724
+ // CC Rewind (E18): per-turn capture flag (rewindFiles:true) on normal turns, or a one-shot restore
223725
+ // (resumeAt/rewindFiles/rewindFilesTo) when /rewind armed it. Empty ⇒ no stamp (capture disabled + no arm).
223726
+ ...Object.keys(rewindFields).length > 0 ? { rewind: rewindFields } : {},
223727
+ // CC permission mode (R4): the raw permissionMode intent (service interprets, tighten-only); empty on default.
223728
+ ...permissionFields,
223729
+ // [686]② `--sandbox <profile>` (EXPLICIT): the per-task image PROFILE (never a digest — the server
223730
+ // re-resolves fail-closed with the caller's principal). Absent on default/auto/mock (b 口径:缺省不发).
223731
+ ...sandboxFields,
223732
+ // Workflow super-set: the top-level selfOrchestration flag (SEMA_SELF_ORCHESTRATION env opt-in, live-gated).
223733
+ // Present ⇒ the SERVICE mounts core run_workflow (gated on its deployment/tenant policy); absent ⇒ no stamp.
223734
+ ...selfOrchestration ? { selfOrchestration } : {},
223735
+ // Workflow deferred-disclosure ([1052]①): absent = fully exposed (activation turn / opt-out); present =
223736
+ // core 1.314 placeholder-on-wire, schema bytes out of the cache prefix, ToolSearch-activatable.
223737
+ ...deferTools ? { deferTools } : {},
223738
+ ...retainBackground ? { retainBackgroundProcesses: retainBackground } : {},
223739
+ ...promptProfile ? { promptProfile } : {},
223740
+ // Fork super-set: the top-level enableFork flag — EXPLICIT boolean on live (core ≥1.257 treats absent
223741
+ // as granted; the shell's default-OFF product decision must be spelled out). Mock path stays unstamped.
223742
+ ...enableFork !== void 0 ? { enableFork } : {},
223743
+ // Turn-boundary attachments (design/133 + G1): default-on G1 pair on the live path; service → core opt-in.
223744
+ ...attachments ? { attachments } : {},
223745
+ // clientContext (clientContextWireCaps, design/112 — core 1.181): the user's LOCAL identity facts (IANA
223746
+ // timeZone from utils/intl `getTimeZone()`, + optional SEMA_USER_EMAIL). The SERVICE relays it to core
223747
+ // `TaskSpec.clientContext` → core localizes the `# Environment` block's "today" to the user's zone (+ a
223748
+ // `(Asia/Tokyo)`-style annotation); absent ⇒ core annotates `(UTC)` so the model knows it's container time.
223749
+ // Benign metadata (no secret), always-derivable ⇒ stamped on every request (mock ignores it; core 1.186
223750
+ // validates the zone and only `timeZone`+`userEmail` are live — `locale` was deleted, never set here).
223751
+ // (包的 input 面按结构收 `Record<string, unknown>`;`ClientContext` 是具名接口无索引签名,故转型。)
223752
+ ...clientContextFields.clientContext ? { clientContext: clientContextFields.clientContext } : {},
223753
+ // scratchpad 域([816] 壳侧承诺③ / [820]③,scratchpadWireCaps):vendored getScratchpadDir 的
223754
+ // per-session 路径 → TaskRequest.scratchpadDir(server 半场填 envFacts.scratchpadDir + 工厂
223755
+ // exemptDirs;没到货时引擎忽略=无害 additive)。gate off ⇒ 无 stamp;端侧保留 live 判读避免在
223756
+ // mock 车道白做一次目录解析(包内 live 门同样兜着)。
223757
+ ...process.env.SEMA_LIVE_BASEURL ? scratchpadDirField() : {},
223758
+ // settings 四源(端各自解析,合并序与「全空则不 stamp」归包):resolver 的 effective 快照 +
223759
+ // WebSearch 后端配置 + ultracode 预设 + 用户 settings 文件 hooks。
223760
+ settings: {
223761
+ ...seamSettings ? { resolved: seamSettings } : {},
223762
+ ...webSearch ? { webSearch } : {},
223763
+ ...ultracode ? { ultracode } : {},
223764
+ ...wireHooks ? { hooks: wireHooks } : {}
223765
+ }
223766
+ },
223767
+ "interactive"
223768
+ );
223762
223769
  }
223763
223770
  function semaApiErrorContent(err8, requestedScenario) {
223764
223771
  const e = err8;
@@ -224071,6 +224078,7 @@ var BG_TEAR_MAX_RESENDS, BG_RECOVERY_WAIT_MS, DRAINING_MAX_RETRIES, DEFAULT_DRAI
224071
224078
  var init_seamQuery = __esm({
224072
224079
  "build-src/src/sema/seamQuery.ts"() {
224073
224080
  init_adapter();
224081
+ init_dist();
224074
224082
  init_effortWire2();
224075
224083
  init_rewindWireCaps2();
224076
224084
  init_permissionWireCaps2();
@@ -361268,9 +361276,9 @@ function streamingTailWrap(unstableSuffix) {
361268
361276
  var import_compiler_runtime52, import_react48, import_jsx_runtime65, TOKEN_CACHE_MAX, tokenCache, MD_SYNTAX_RE;
361269
361277
  var init_Markdown = __esm({
361270
361278
  "build-src/src/components/Markdown.tsx"() {
361271
- import_compiler_runtime52 = __toESM(require_compiler_runtime());
361279
+ import_compiler_runtime52 = __toESM(require_compiler_runtime(), 1);
361272
361280
  init_marked_esm();
361273
- import_react48 = __toESM(require_react());
361281
+ import_react48 = __toESM(require_react(), 1);
361274
361282
  init_useSettings();
361275
361283
  init_ink2();
361276
361284
  init_cliHighlight();
@@ -361278,7 +361286,7 @@ var init_Markdown = __esm({
361278
361286
  init_markdown();
361279
361287
  init_messages4();
361280
361288
  init_MarkdownTable();
361281
- import_jsx_runtime65 = __toESM(require_jsx_runtime());
361289
+ import_jsx_runtime65 = __toESM(require_jsx_runtime(), 1);
361282
361290
  TOKEN_CACHE_MAX = 500;
361283
361291
  tokenCache = /* @__PURE__ */ new Map();
361284
361292
  MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
@@ -384297,7 +384305,7 @@ var init_classifierApprovalsHook = __esm({
384297
384305
  var React31, TypedComponent, SentryErrorBoundary;
384298
384306
  var init_SentryErrorBoundary = __esm({
384299
384307
  "build-src/src/components/SentryErrorBoundary.ts"() {
384300
- React31 = __toESM(require_react(), 1);
384308
+ React31 = __toESM(require_react());
384301
384309
  TypedComponent = React31.Component;
384302
384310
  SentryErrorBoundary = class extends TypedComponent {
384303
384311
  constructor(props) {
@@ -496402,14 +496410,13 @@ var init_sema_brand = __esm({
496402
496410
  _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). \u{1F534} SHAPE: {version, notes[]} \u2014 a bare array silently kills welcome What's-new + /release-notes + changelog pin (2026-07-27 \u6848).",
496403
496411
  version: "2.1.187",
496404
496412
  notes: [
496405
- "WebFetch answers your question instead of dumping the raw page (engine 1.301+, ~660x less context per fetch)",
496406
- "--setting-sources '' now truly disables the settings.json env block (matching Claude Code)",
496407
- "Registry calls now ride the official SDK client (device login names the app correctly on the consent screen)",
496408
- "The stream-json init frame now lists ToolSearch, matching what the engine actually mounts"
496413
+ "Bash failures now carry is_error in -p stream-json even when output spills to persisted storage (structured exitCode is authoritative)",
496414
+ "sema cloud config no longer hangs forever on an unresponsive registry (SDK client with timeout + auth refresh)",
496415
+ "cloud doctor's worker health check now rejects impostor services on the port (HTTP 200 must also say status ok)"
496409
496416
  ]
496410
496417
  },
496411
- productVersion: "1.0.57",
496412
- announcement: "sema 1.0.57 \u2014 Fix batch: WebFetch now truly summarizes (engine-side wiring, ~660x less context per fetch), --setting-sources '' really disables the settings env block, registry calls ride the official SDK, and the init frame reports ToolSearch."
496418
+ productVersion: "1.0.58",
496419
+ announcement: "sema 1.0.58 \u2014 Fix batch: Bash failure flagging survives large-output spills (structured exitCode wins over text sniffing), cloud config gets real timeouts, and doctor spots port impostors."
496413
496420
  };
496414
496421
  }
496415
496422
  });
@@ -502689,14 +502696,13 @@ var require_sema_brand = __commonJS({
502689
502696
  _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). \u{1F534} SHAPE: {version, notes[]} \u2014 a bare array silently kills welcome What's-new + /release-notes + changelog pin (2026-07-27 \u6848).",
502690
502697
  version: "2.1.187",
502691
502698
  notes: [
502692
- "WebFetch answers your question instead of dumping the raw page (engine 1.301+, ~660x less context per fetch)",
502693
- "--setting-sources '' now truly disables the settings.json env block (matching Claude Code)",
502694
- "Registry calls now ride the official SDK client (device login names the app correctly on the consent screen)",
502695
- "The stream-json init frame now lists ToolSearch, matching what the engine actually mounts"
502699
+ "Bash failures now carry is_error in -p stream-json even when output spills to persisted storage (structured exitCode is authoritative)",
502700
+ "sema cloud config no longer hangs forever on an unresponsive registry (SDK client with timeout + auth refresh)",
502701
+ "cloud doctor's worker health check now rejects impostor services on the port (HTTP 200 must also say status ok)"
502696
502702
  ]
502697
502703
  },
502698
- productVersion: "1.0.57",
502699
- announcement: "sema 1.0.57 \u2014 Fix batch: WebFetch now truly summarizes (engine-side wiring, ~660x less context per fetch), --setting-sources '' really disables the settings env block, registry calls ride the official SDK, and the init frame reports ToolSearch."
502704
+ productVersion: "1.0.58",
502705
+ announcement: "sema 1.0.58 \u2014 Fix batch: Bash failure flagging survives large-output spills (structured exitCode wins over text sniffing), cloud config gets real timeouts, and doctor spots port impostors."
502700
502706
  };
502701
502707
  }
502702
502708
  });
@@ -636683,8 +636689,8 @@ async function collectAxesRows(opts, deps2) {
636683
636689
  });
636684
636690
  return rows2;
636685
636691
  }
636686
- const probeHealth2 = deps2?.probeHealth ?? ((url3) => engineTarget.probeEngineHealthUrl(url3));
636687
- const health = await probeHealth2(remote);
636692
+ const probeHealth3 = deps2?.probeHealth ?? ((url3) => engineTarget.probeEngineHealthUrl(url3));
636693
+ const health = await probeHealth3(remote);
636688
636694
  if (!health) {
636689
636695
  rows2.push({
636690
636696
  label: "Remote health",
@@ -643779,7 +643785,7 @@ async function* ask(params) {
643779
643785
  if (frame) yield frame;
643780
643786
  continue;
643781
643787
  }
643782
- if (t2 === "retry_status" || t2 === "turn_usage" || t2 === "task_progress") {
643788
+ if (t2 === "retry_status" || t2 === "turn_usage" || t2 === "task_progress" || t2 === "steering_injected") {
643783
643789
  continue;
643784
643790
  }
643785
643791
  if (t2 === "prompt_suggestions") {
@@ -649846,7 +649852,7 @@ async function probeEngineActiveBgTasksForCli(deps2) {
649846
649852
  if (Array.isArray(drained2)) return { kind: "tasks", engine: remote, tasks: drained2 };
649847
649853
  return { kind: "unavailable", engine: remote, reason: `fleet snapshot failed: ${drained2.error}` };
649848
649854
  }
649849
- const { getEnginePortFilePath: getEnginePortFilePath2, getEngineTokenFilePath: getEngineTokenFilePath2, isProcessAlive: isProcessAlive2, probeHealth: probeHealth2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
649855
+ const { getEnginePortFilePath: getEnginePortFilePath2, getEngineTokenFilePath: getEngineTokenFilePath2, isProcessAlive: isProcessAlive2, probeHealth: probeHealth3 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
649850
649856
  let anchor = null;
649851
649857
  try {
649852
649858
  const parsed = JSON.parse(readFileSync41(getEnginePortFilePath2(), "utf8"));
@@ -649855,7 +649861,7 @@ async function probeEngineActiveBgTasksForCli(deps2) {
649855
649861
  }
649856
649862
  if (!anchor || !isProcessAlive2(anchor.pid)) return { kind: "no-engine" };
649857
649863
  const engine = `127.0.0.1:${anchor.port}`;
649858
- const health = await probeHealth2(anchor.port);
649864
+ const health = await probeHealth3(anchor.port);
649859
649865
  if (!health) {
649860
649866
  return { kind: "unavailable", engine, reason: `engine anchor alive (pid ${anchor.pid}) but GET /health failed` };
649861
649867
  }
@@ -650044,12 +650050,11 @@ function domainSummary(names) {
650044
650050
  }
650045
650051
  async function cloudConfig(options) {
650046
650052
  try {
650047
- const { profileName, registryUrl, accessToken } = await getValidAccessToken(options.profile);
650053
+ const { profileName, registryUrl } = await getValidAccessToken(options.profile);
650054
+ const client4 = registryClientForProfile(registryUrl, profileName, { timeoutMs: 3e4 });
650048
650055
  let res;
650049
650056
  try {
650050
- res = await fetch(`${registryUrl}/api/v1/effective`, {
650051
- headers: { authorization: `Bearer ${accessToken}` }
650052
- });
650057
+ res = await client4.requestRaw({ method: "GET", path: "/api/v1/effective" });
650053
650058
  } catch (e) {
650054
650059
  err3(`Error: cannot reach registry at ${registryUrl}: ${e instanceof Error ? e.message : String(e)}`);
650055
650060
  process.exit(1);
@@ -650059,16 +650064,13 @@ async function cloudConfig(options) {
650059
650064
  out("This registry does not serve /api/v1/effective yet \u2014 upgrade the registry to a version with API v1 to use `sema cloud config`.");
650060
650065
  return;
650061
650066
  }
650062
- if (!res.ok) {
650067
+ if (res.status < 200 || res.status >= 300) {
650063
650068
  err3(`Error: registry returned HTTP ${res.status} for /api/v1/effective`);
650064
650069
  process.exit(1);
650065
650070
  }
650066
- const text2 = await res.text();
650067
- let body;
650068
- try {
650069
- body = JSON.parse(text2);
650070
- } catch {
650071
- err3(`Error: registry returned a non-JSON body for /api/v1/effective`);
650071
+ const body = res.body ?? {};
650072
+ if (typeof body !== "object" || Array.isArray(body)) {
650073
+ err3(`Error: registry returned a non-object body for /api/v1/effective`);
650072
650074
  process.exit(1);
650073
650075
  }
650074
650076
  if (options.json) {
@@ -650396,6 +650398,7 @@ var init_cloud = __esm({
650396
650398
  "build-src/src/cli/handlers/cloud.ts"() {
650397
650399
  init_cloudProfile();
650398
650400
  init_cloudAuth();
650401
+ init_registrySdkClient();
650399
650402
  out = (line) => process.stdout.write(`${line}
650400
650403
  `);
650401
650404
  err3 = (line) => process.stderr.write(`${line}
@@ -652476,7 +652479,7 @@ __export(cloudResources_exports, {
652476
652479
  import { createHash as createHash26 } from "node:crypto";
652477
652480
  import { existsSync as existsSync32, readdirSync as readdirSync12, readFileSync as readFileSync45, statSync as statSync14 } from "node:fs";
652478
652481
  import { basename as basename68, dirname as dirname86, isAbsolute as isAbsolute33, join as join194, resolve as resolve49 } from "node:path";
652479
- import { getEffective as getEffective2, OAuthFlowError as OAuthFlowError3 } from "@sema-agent/sdk/registry";
652482
+ import { getEffective as getEffective2, getMeConfig, getScopeConfigDraft as getScopeConfigDraft2, OAuthFlowError as OAuthFlowError3, RegistryApiError as RegistryApiError3 } from "@sema-agent/sdk/registry";
652480
652483
  function fail4(e) {
652481
652484
  err6(`Error: ${e instanceof Error ? e.message : String(e)}`);
652482
652485
  process.exit(1);
@@ -652537,26 +652540,34 @@ async function personalFetch(auth2, path28, init2) {
652537
652540
  }
652538
652541
  }
652539
652542
  async function meConfigGet(auth2, domain2, forUser) {
652540
- const { status: status3, json: json2 } = await personalFetch(auth2, personalPath(domain2, forUser));
652541
- if (forUser) {
652542
- const managed = managedLaneError(forUser, status3, json2);
652543
- if (managed) throw managed;
652544
- }
652545
- if (status3 === 404 || status3 === 501) {
652546
- throw new CloudAuthError(
652547
- `this registry does not serve ${personalPath(domain2, forUser).replace(`/${domain2}`, "")} yet (HTTP ${status3}) \u2014 upgrade the registry to a version with the ${forUser ? "admin-managed" : ""} personal config layer`,
652548
- void 0,
652549
- status3
652550
- );
652551
- }
652552
- if (status3 !== 200) {
652553
- throw new CloudAuthError(
652554
- `registry rejected the personal-config read (HTTP ${status3}${typeof json2.error === "string" ? `: ${json2.error}` : ""})`,
652555
- typeof json2.error === "string" ? json2.error : void 0,
652556
- status3
652557
- );
652543
+ const client4 = registryClientForProfile(auth2.registryUrl, auth2.profileName, { timeoutMs: 3e4 });
652544
+ try {
652545
+ return await getMeConfig(client4, domain2, forUser ? { forUser } : {});
652546
+ } catch (e) {
652547
+ if (e instanceof OAuthFlowError3) {
652548
+ throw new CloudAuthError(`the registry rejected your session (${e.code}) \u2014 sign in again: sema cloud login`, e.code, 401);
652549
+ }
652550
+ if (e instanceof RegistryApiError3) {
652551
+ const json2 = asRec3(e.body) ?? {};
652552
+ if (forUser) {
652553
+ const managed = managedLaneError(forUser, e.status, json2);
652554
+ if (managed) throw managed;
652555
+ }
652556
+ if (e.status === 404 || e.status === 501) {
652557
+ throw new CloudAuthError(
652558
+ `this registry does not serve ${personalPath(domain2, forUser).replace(`/${domain2}`, "")} yet (HTTP ${e.status}) \u2014 upgrade the registry to a version with the ${forUser ? "admin-managed" : ""} personal config layer`,
652559
+ void 0,
652560
+ e.status
652561
+ );
652562
+ }
652563
+ throw new CloudAuthError(
652564
+ `registry rejected the personal-config read (HTTP ${e.status}${typeof json2.error === "string" ? `: ${json2.error}` : ""})`,
652565
+ typeof json2.error === "string" ? json2.error : void 0,
652566
+ e.status
652567
+ );
652568
+ }
652569
+ throw new CloudAuthError(`cannot reach registry at ${auth2.registryUrl}: ${e instanceof Error ? e.message : String(e)}`);
652558
652570
  }
652559
- return { value: json2.value ?? null, updatedAt: typeof json2.updatedAt === "string" ? json2.updatedAt : null };
652560
652571
  }
652561
652572
  async function meConfigPut(auth2, domain2, value, summary, baseUpdatedAt, forUser) {
652562
652573
  const { status: status3, json: json2 } = await personalFetch(auth2, personalPath(domain2, forUser), {
@@ -652672,9 +652683,17 @@ async function teamFetch(ctx, path28, init2) {
652672
652683
  }
652673
652684
  }
652674
652685
  async function teamConfigGetDraft(ctx, domain2) {
652675
- const { status: status3, json: json2 } = await teamFetch(ctx, teamConfigPath(ctx, domain2));
652676
- if (status3 !== 200) throw await teamHttpError(ctx, status3, json2, `reading the team ${domain2} config`, "member (any role)");
652677
- return { value: json2.value ?? null, version: typeof json2.version === "number" ? json2.version : 0 };
652686
+ try {
652687
+ return await getScopeConfigDraft2(ctx.client, ctx.space, domain2);
652688
+ } catch (e) {
652689
+ if (e instanceof OAuthFlowError3) {
652690
+ throw new CloudAuthError(`the registry rejected your session (${e.code}) \u2014 sign in again: sema cloud login`, e.code, 401);
652691
+ }
652692
+ if (e instanceof RegistryApiError3) {
652693
+ throw await teamHttpError(ctx, e.status, asRec3(e.body) ?? {}, `reading the team ${domain2} config`, "member (any role)");
652694
+ }
652695
+ throw new CloudAuthError(`cannot reach registry at ${ctx.registryUrl}: ${e instanceof Error ? e.message : String(e)}`);
652696
+ }
652678
652697
  }
652679
652698
  async function teamConfigGetPublished(ctx, domain2) {
652680
652699
  const { status: status3, json: json2 } = await teamFetch(ctx, `${teamConfigPath(ctx, domain2)}?source=published`);
@@ -653839,6 +653858,7 @@ import { createRequire as createRequire4 } from "module";
653839
653858
  import { createInterface as createInterface3 } from "readline";
653840
653859
  import { dirname as dirname87, join as join195, resolve as resolve50 } from "path";
653841
653860
  import { getEffective as getEffective3, probeRegistryHealth } from "@sema-agent/sdk/registry";
653861
+ import { probeHealth as probeHealth2 } from "@sema-agent/sdk";
653842
653862
  function fail5(e) {
653843
653863
  err7(`Error: ${e instanceof Error ? e.message : String(e)}`);
653844
653864
  process.exit(1);
@@ -654104,7 +654124,10 @@ async function cloudSmoke(options) {
654104
654124
  printRow("registry /api/v1/effective (auth)", effective);
654105
654125
  const workerUrl = options.worker ?? resolved.profile.workerUrl;
654106
654126
  if (workerUrl) {
654107
- const w2 = await probe2(() => httpCheck(`${normalizeRegistryUrl(workerUrl)}/health`));
654127
+ const w2 = await probe2(async () => {
654128
+ const r = await probeHealth2(normalizeRegistryUrl(workerUrl), 8e3);
654129
+ return r.alive ? { pass: true, detail: `HTTP 200 status=ok${r.health.version ? `, v${r.health.version}` : ""}` } : { pass: false, detail: "status" in r ? `${r.reason} (HTTP ${r.status})` : r.reason };
654130
+ });
654108
654131
  printRow(`worker /health (${workerUrl})`, w2);
654109
654132
  if (!w2.pass) failures++;
654110
654133
  } else {
@@ -667711,7 +667734,7 @@ Auth: unix socket -R \u2192 local proxy`, "info");
667711
667734
  pendingHookMessages
667712
667735
  }, renderAndRun);
667713
667736
  }
667714
- }).version("sema 1.0.57", "-v, --version", "Output the version number");
667737
+ }).version("sema 1.0.58", "-v, --version", "Output the version number");
667715
667738
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
667716
667739
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
667717
667740
  if (canUserConfigureAdvisor()) {