@sema-agent/cli 1.0.7 → 1.0.8

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 +11 -11
  2. package/package.json +4 -4
  3. package/sema.js +504 -36
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sema-agent/cli",
9
- "version": "1.0.7",
9
+ "version": "1.0.8",
10
10
  "license": "BUSL-1.1",
11
11
  "dependencies": {
12
- "@sema-agent/sdk": "0.0.50",
13
- "@sema-agent/server": "1.209.0"
12
+ "@sema-agent/sdk": "0.0.51",
13
+ "@sema-agent/server": "1.211.0"
14
14
  },
15
15
  "bin": {
16
16
  "sema": "sema.js"
@@ -669,21 +669,21 @@
669
669
  }
670
670
  },
671
671
  "node_modules/@sema-agent/sdk": {
672
- "version": "0.0.50",
673
- "resolved": "https://registry.npmjs.org/@sema-agent/sdk/-/sdk-0.0.50.tgz",
674
- "integrity": "sha512-7r5sURZh5/Eqmv5/qIDHZNpWEl0b5i0EY7+LTzv3q3ULaT/urOmkmLZvUSY60yDxe74SA83mMxle24dL/iubgQ==",
672
+ "version": "0.0.51",
673
+ "resolved": "https://registry.npmjs.org/@sema-agent/sdk/-/sdk-0.0.51.tgz",
674
+ "integrity": "sha512-k51uaCuRMnms6qALarmpzxgIPlXtCYQqqHT8T9WUCnwLbmkSvWnVHswfC3ejB0z98XU5ETiihSvqMO5Vacc+MA==",
675
675
  "license": "BUSL-1.1",
676
676
  "engines": {
677
677
  "node": ">=20"
678
678
  }
679
679
  },
680
680
  "node_modules/@sema-agent/server": {
681
- "version": "1.209.0",
682
- "resolved": "https://registry.npmjs.org/@sema-agent/server/-/server-1.209.0.tgz",
683
- "integrity": "sha512-y2Uj+TYqwDLV3DELdvk7ZYxHmmrXx+sHKcN+6KWEOpWdmEW5E68yXiGzjpRJyBtTL1YOIvSu2b7SM/I5UpJtBA==",
681
+ "version": "1.211.0",
682
+ "resolved": "https://registry.npmjs.org/@sema-agent/server/-/server-1.211.0.tgz",
683
+ "integrity": "sha512-zEmVQcmSXKD02LYNw8iLUGyn+2BrIOkXJVx979wgrdJNfZbz4VyH5Ihzj+8rmE9OssFYqWoqWWSXRNg9jAiKIQ==",
684
684
  "license": "BUSL-1.1",
685
685
  "dependencies": {
686
- "@sema-agent/core": "^1.296.1",
686
+ "@sema-agent/core": "^1.298.0",
687
687
  "@sema-agent/registry-core": "^0.10.12",
688
688
  "e2b": "^2.28.0",
689
689
  "libsodium-wrappers": "^0.8.4",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
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.0.50",
25
- "@sema-agent/server": "1.209.0"
24
+ "@sema-agent/sdk": "0.0.51",
25
+ "@sema-agent/server": "1.211.0"
26
26
  },
27
27
  "overrides": {
28
28
  "@sema-agent/core": "1.298.0",
29
29
  "@sema-agent/registry-core": "0.10.12"
30
30
  },
31
- "semaEngineVersion": "server 1.209.0 / core 1.298.0 / registry-core 0.10.12",
31
+ "semaEngineVersion": "server 1.211.0 / core 1.298.0 / registry-core 0.10.12",
32
32
  "engines": {
33
33
  "node": ">=18"
34
34
  }
package/sema.js CHANGED
@@ -111598,10 +111598,12 @@ function doneToSdkResult(ev, ctx) {
111598
111598
  }
111599
111599
  const rr = r;
111600
111600
  const durationMs = elapsedMs(ctx);
111601
+ const errorCodeField = typeof rr.errorCode === "string" && rr.errorCode.length > 0 ? { errorCode: rr.errorCode } : {};
111601
111602
  if (rr.status === "failed") {
111603
+ const failedSubtype = rr.errorCode === "budget.exceeded" || rr.errorCode === "budget.precall" ? "error_max_budget_usd" : rr.errorCode === "limit.max_turns" ? "error_max_turns" : rr.errorCode === "output.invalid" ? "error_max_structured_output_retries" : "error_during_execution";
111602
111604
  return stamp(ctx, {
111603
111605
  type: "result",
111604
- subtype: "error_during_execution",
111606
+ subtype: failedSubtype,
111605
111607
  duration_ms: durationMs,
111606
111608
  // P1-5 real elapsed (stream-open → terminal)
111607
111609
  duration_api_ms: durationMs,
@@ -111619,7 +111621,51 @@ function doneToSdkResult(ev, ctx) {
111619
111621
  // 与 failedToSdkResult 的同款 append 对齐,message 后附 code 便于对账。
111620
111622
  errors: [
111621
111623
  typeof rr.errorCode === "string" && (rr.errorCode.startsWith("resume_at.") || rr.errorCode.startsWith("rewind_snapshot.")) && rr.errorMessage ? `${rr.errorMessage} (${rr.errorCode})` : rr.errorMessage ?? "run failed"
111622
- ]
111624
+ ],
111625
+ ...errorCodeField
111626
+ });
111627
+ }
111628
+ if (rr.status === "timeout") {
111629
+ const salvaged = typeof r.result === "string" && r.result.trim().length > 0 ? r.result : void 0;
111630
+ return stamp(ctx, {
111631
+ type: "result",
111632
+ subtype: "error_max_turns",
111633
+ duration_ms: durationMs,
111634
+ duration_api_ms: durationMs,
111635
+ is_error: true,
111636
+ num_turns: stats3?.turns ?? 0,
111637
+ stop_reason: null,
111638
+ total_cost_usd: costOrNull(stats3?.costUsd),
111639
+ usage,
111640
+ modelUsage,
111641
+ permission_denials: [],
111642
+ errors: [
111643
+ `${rr.errorMessage ?? "run hit its wall-clock deadline and was finalized by the engine"} (${rr.errorCode ?? "limit.timeout"})`
111644
+ ],
111645
+ ...errorCodeField,
111646
+ // 写出窗 salvage(additive seam 字段):deadline 前引擎救回的最终文本非空时随帧带出——
111647
+ // CC error 帧无 result 键,但静默丢弃已救回的答案对 -p 集成面是净损失(TB qe** 实证)。
111648
+ ...salvaged !== void 0 ? { result: salvaged } : {}
111649
+ });
111650
+ }
111651
+ if (rr.status === "blocked") {
111652
+ const blockedReason = r.blockedReason;
111653
+ return stamp(ctx, {
111654
+ type: "result",
111655
+ subtype: "error_during_execution",
111656
+ duration_ms: durationMs,
111657
+ duration_api_ms: durationMs,
111658
+ is_error: true,
111659
+ num_turns: stats3?.turns ?? 0,
111660
+ stop_reason: null,
111661
+ total_cost_usd: costOrNull(stats3?.costUsd),
111662
+ usage,
111663
+ modelUsage,
111664
+ permission_denials: [],
111665
+ errors: [
111666
+ typeof blockedReason === "string" && blockedReason.length > 0 ? `Run blocked: ${blockedReason}` : "Run blocked (the agent reported it cannot proceed)"
111667
+ ],
111668
+ ...errorCodeField
111623
111669
  });
111624
111670
  }
111625
111671
  if (rr.status === "suspended" || rr.status === "needs_review") {
@@ -111644,7 +111690,28 @@ function doneToSdkResult(ev, ctx) {
111644
111690
  permission_denials: [],
111645
111691
  errors: [
111646
111692
  `Turn suspended awaiting ${awaiting} that no one can provide in -p (non-interactive) mode${runId ? ` (run ${runId})` : ""}. ${wayOut}`
111647
- ]
111693
+ ],
111694
+ ...errorCodeField
111695
+ // [909]B1 — needs_review 帧带 review.pending,原样透传
111696
+ });
111697
+ }
111698
+ if (typeof rr.status === "string" && rr.status.length > 0 && rr.status !== "completed") {
111699
+ return stamp(ctx, {
111700
+ type: "result",
111701
+ subtype: "error_during_execution",
111702
+ duration_ms: durationMs,
111703
+ duration_api_ms: durationMs,
111704
+ is_error: true,
111705
+ num_turns: stats3?.turns ?? 0,
111706
+ stop_reason: null,
111707
+ total_cost_usd: costOrNull(stats3?.costUsd),
111708
+ usage,
111709
+ modelUsage,
111710
+ permission_denials: [],
111711
+ errors: [
111712
+ rr.errorMessage ?? `run ended with terminal status "${rr.status}" (not a success; this CLI predates that status word)`
111713
+ ],
111714
+ ...errorCodeField
111648
111715
  });
111649
111716
  }
111650
111717
  return stamp(ctx, {
@@ -111701,7 +111768,10 @@ function failedToSdkResult(ev, ctx) {
111701
111768
  // 用户可自解的操作性错误(选错目标/回退过根/快照缺失),code 附在 message 后便于对账。
111702
111769
  errors: [
111703
111770
  typeof ev.errorCode === "string" && (ev.errorCode.startsWith("resume_at.") || ev.errorCode.startsWith("rewind_snapshot.")) && ev.errorMessage ? `${ev.errorMessage} (${ev.errorCode})` : ev.errorMessage ?? ev.errorCode ?? "run failed"
111704
- ]
111771
+ ],
111772
+ // [909]B1 — errorCode 透传(additive seam 字段;done 臂同款):`failed` 事件的 cancelled/
111773
+ // budget.* 等引擎值原样给集成面。
111774
+ ...typeof ev.errorCode === "string" && ev.errorCode.length > 0 ? { errorCode: ev.errorCode } : {}
111705
111775
  });
111706
111776
  }
111707
111777
  function terminalToSdkResult(ev, ctx) {
@@ -156991,7 +157061,13 @@ function permissionModeField(mode, opts) {
156991
157061
  var KNOWN;
156992
157062
  var init_permissionWireCaps = __esm({
156993
157063
  "build-src/src/sema/permissionWireCaps.ts"() {
156994
- KNOWN = /* @__PURE__ */ new Set(["default", "plan", "acceptEdits", "bypassPermissions"]);
157064
+ KNOWN = /* @__PURE__ */ new Set([
157065
+ "default",
157066
+ "plan",
157067
+ "acceptEdits",
157068
+ "bypassPermissions",
157069
+ "auto"
157070
+ ]);
156995
157071
  }
156996
157072
  });
156997
157073
 
@@ -157770,11 +157846,18 @@ var init_engineTarget = __esm({
157770
157846
  });
157771
157847
 
157772
157848
  // build-src/src/sema/userMessageSelect.ts
157849
+ function isToolResultUserMessage(m2) {
157850
+ if (!m2 || typeof m2 !== "object") return false;
157851
+ const c2 = m2;
157852
+ const content = c2.message?.content ?? m2.content;
157853
+ return Array.isArray(content) && content[0]?.type === "tool_result";
157854
+ }
157773
157855
  function isProjectableUserMessage(m2) {
157774
157856
  if (!m2 || typeof m2 !== "object") return false;
157775
157857
  const c2 = m2;
157776
157858
  if (c2.type !== "user" && c2.type !== void 0) return false;
157777
157859
  if (c2.isMeta === true || c2.isCompactSummary === true || c2.isVisibleInTranscriptOnly === true) return false;
157860
+ if (isToolResultUserMessage(m2)) return false;
157778
157861
  return true;
157779
157862
  }
157780
157863
  function lastProjectableUserMessage(msgs) {
@@ -157783,6 +157866,26 @@ function lastProjectableUserMessage(msgs) {
157783
157866
  }
157784
157867
  return void 0;
157785
157868
  }
157869
+ function trailingStandaloneMetaUserMessages(msgs) {
157870
+ let i = msgs.length - 1;
157871
+ const isRider = (m2) => {
157872
+ const t2 = m2?.type;
157873
+ return t2 === "attachment" || t2 === "system" || t2 === "progress";
157874
+ };
157875
+ while (i >= 0 && isRider(msgs[i])) i--;
157876
+ const run2 = [];
157877
+ while (i >= 0) {
157878
+ const m2 = msgs[i];
157879
+ const isMetaUser = !!m2 && typeof m2 === "object" && (m2.type === "user" || m2.type === void 0) && m2.isMeta === true;
157880
+ if (!isMetaUser) break;
157881
+ run2.unshift(msgs[i]);
157882
+ i--;
157883
+ }
157884
+ if (run2.length === 0) return [];
157885
+ while (i >= 0 && isRider(msgs[i])) i--;
157886
+ const boundary = i >= 0 ? msgs[i] : void 0;
157887
+ return boundary !== void 0 && isProjectableUserMessage(boundary) ? [] : run2;
157888
+ }
157786
157889
  var init_userMessageSelect = __esm({
157787
157890
  "build-src/src/sema/userMessageSelect.ts"() {
157788
157891
  }
@@ -330920,9 +331023,9 @@ function streamingTailWrap(unstableSuffix) {
330920
331023
  var import_compiler_runtime43, import_react43, import_jsx_runtime53, TOKEN_CACHE_MAX, tokenCache, MD_SYNTAX_RE;
330921
331024
  var init_Markdown = __esm({
330922
331025
  "build-src/src/components/Markdown.tsx"() {
330923
- import_compiler_runtime43 = __toESM(require_compiler_runtime());
331026
+ import_compiler_runtime43 = __toESM(require_compiler_runtime(), 1);
330924
331027
  init_marked_esm();
330925
- import_react43 = __toESM(require_react());
331028
+ import_react43 = __toESM(require_react(), 1);
330926
331029
  init_useSettings();
330927
331030
  init_ink2();
330928
331031
  init_cliHighlight();
@@ -330930,7 +331033,7 @@ var init_Markdown = __esm({
330930
331033
  init_markdown();
330931
331034
  init_messages4();
330932
331035
  init_MarkdownTable();
330933
- import_jsx_runtime53 = __toESM(require_jsx_runtime());
331036
+ import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
330934
331037
  TOKEN_CACHE_MAX = 500;
330935
331038
  tokenCache = /* @__PURE__ */ new Map();
330936
331039
  MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
@@ -331598,6 +331701,39 @@ var init_trustedDevice = __esm({
331598
331701
  }
331599
331702
  });
331600
331703
 
331704
+ // build-src/src/utils/stdoutDrain.ts
331705
+ var stdoutDrain_exports = {};
331706
+ __export(stdoutDrain_exports, {
331707
+ drainStdoutBounded: () => drainStdoutBounded,
331708
+ setPipedStdoutBlocking: () => setPipedStdoutBlocking
331709
+ });
331710
+ function setPipedStdoutBlocking() {
331711
+ try {
331712
+ if (process.stdout.isTTY) return false;
331713
+ const h = process.stdout._handle;
331714
+ if (h && typeof h.setBlocking === "function") {
331715
+ h.setBlocking(true);
331716
+ return true;
331717
+ }
331718
+ } catch {
331719
+ }
331720
+ return false;
331721
+ }
331722
+ async function drainStdoutBounded(maxMs = 2e3) {
331723
+ try {
331724
+ const s = process.stdout;
331725
+ const start = Date.now();
331726
+ while (!s.destroyed && typeof s.writableLength === "number" && s.writableLength > 0 && Date.now() - start < maxMs) {
331727
+ await new Promise((r) => setTimeout(r, 10));
331728
+ }
331729
+ } catch {
331730
+ }
331731
+ }
331732
+ var init_stdoutDrain = __esm({
331733
+ "build-src/src/utils/stdoutDrain.ts"() {
331734
+ }
331735
+ });
331736
+
331601
331737
  // build-src/src/utils/gracefulShutdown.ts
331602
331738
  import { writeSync as writeSync3 } from "fs";
331603
331739
  function cleanupTerminalModes() {
@@ -331772,6 +331908,11 @@ async function gracefulShutdown(exitCode = 0, reason = "other", options) {
331772
331908
  } catch {
331773
331909
  }
331774
331910
  }
331911
+ try {
331912
+ const { drainStdoutBounded: drainStdoutBounded2 } = await Promise.resolve().then(() => (init_stdoutDrain(), stdoutDrain_exports));
331913
+ await drainStdoutBounded2();
331914
+ } catch {
331915
+ }
331775
331916
  forceExit(exitCode);
331776
331917
  }
331777
331918
  var resumeHintPrinted, setupGracefulShutdown, shutdownInProgress, failsafeTimer, orphanCheckInterval, pendingShutdown, CleanupTimeoutError;
@@ -431874,13 +432015,29 @@ function toTaskRequest(params) {
431874
432015
  }
431875
432016
  }
431876
432017
  }
432018
+ const standaloneMeta = trailingStandaloneMetaUserMessages(msgs);
432019
+ let metaIsSubmission = false;
432020
+ if (standaloneMeta.length > 0) {
432021
+ const metaTexts = standaloneMeta.map((m2) => objectiveFromMessage(m2)).filter((t2) => t2.length > 0);
432022
+ if (metaTexts.length > 0) {
432023
+ objective = metaTexts.join("\n");
432024
+ metaIsSubmission = true;
432025
+ if (process.env.SEMA_DEBUG) {
432026
+ console.error(`[sema][seamQuery] injected-meta wire: ${metaTexts.length} standalone meta message(s) (${objective.length} chars) \u2192 objective`);
432027
+ }
432028
+ }
432029
+ }
431877
432030
  if (objective.length === 0 && !submitted && msgs.length > 0) {
431878
432031
  objective = objectiveFromMessage(msgs[msgs.length - 1]);
431879
432032
  }
431880
- const images = submitted ? imagesFromMessage(submitted) : [];
432033
+ const images = submitted && !metaIsSubmission ? imagesFromMessage(submitted) : [];
431881
432034
  if (images.length > 0 && process.env.SEMA_DEBUG) {
431882
432035
  console.error(`[sema][seamQuery] images wire: ${images.length} image(s) \u2192 TaskRequest.images`);
431883
432036
  }
432037
+ if (objective.trim().length === 0 && images.length === 0) {
432038
+ console.error("[sema][seamQuery] EMPTY objective guard tripped \u2014 substituting NO_CONTENT_MESSAGE (a submission path produced no text; report this)");
432039
+ objective = NO_CONTENT_MESSAGE;
432040
+ }
431884
432041
  const sysPrompt = params.systemPrompt;
431885
432042
  const scenario2 = selectScenario(objective);
431886
432043
  let reasoningEffort;
@@ -432142,9 +432299,8 @@ Setup looks unfinished (no model was saved). Run \`sema onboard\` to finish setu
432142
432299
  noteEngineTurnStart();
432143
432300
  const sessionId = req.sessionId ?? mockClientIds.sessionId;
432144
432301
  try {
432145
- const submitted = lastProjectableUserMessage(
432146
- params.messages
432147
- );
432302
+ const metaRun = trailingStandaloneMetaUserMessages(params.messages);
432303
+ const submitted = metaRun.length > 0 ? void 0 : lastProjectableUserMessage(params.messages);
432148
432304
  if (submitted && typeof submitted.uuid === "string") recordPendingUserMessage(submitted.uuid);
432149
432305
  if (process.env.SEMA_LIVE_BASEURL) {
432150
432306
  disarmAssistantCommit();
@@ -432352,6 +432508,7 @@ var init_seamQuery = __esm({
432352
432508
  init_engineTarget();
432353
432509
  init_userMessageSelect();
432354
432510
  init_rewindAnchorStore();
432511
+ init_messages3();
432355
432512
  init_sessionStorage();
432356
432513
  init_turnCommitSignal();
432357
432514
  init_mockClient();
@@ -449274,7 +449431,7 @@ function Settings({
449274
449431
  var import_react113, import_jsx_runtime191;
449275
449432
  var init_cmd_config = __esm({
449276
449433
  "build-src/src/sema/overrides/cmd-config.tsx"() {
449277
- import_react113 = __toESM(require_react(), 1);
449434
+ import_react113 = __toESM(require_react());
449278
449435
  init_useKeybinding();
449279
449436
  init_useExitOnCtrlCDWithKeybindings();
449280
449437
  init_useTerminalSize();
@@ -449285,7 +449442,7 @@ var init_cmd_config = __esm({
449285
449442
  init_Config();
449286
449443
  init_settings_usage();
449287
449444
  init_Stats();
449288
- import_jsx_runtime191 = __toESM(require_jsx_runtime(), 1);
449445
+ import_jsx_runtime191 = __toESM(require_jsx_runtime());
449289
449446
  }
449290
449447
  });
449291
449448
 
@@ -478135,8 +478292,8 @@ var init_sema_brand = __esm({
478135
478292
  "Slash-command gating wired to the fleet capability handshake"
478136
478293
  ]
478137
478294
  },
478138
- productVersion: "1.0.7",
478139
- announcement: "sema 1.0.7 \u2014 headless -p now reconnects through stream blips instead of dying (bounded retry + result recovery), a dead SEMA_ENGINE_URL gets a clear three-step diagnosis in both REPL and -p, and one corrupt config.d file no longer silently drops your whole model catalog"
478295
+ productVersion: "1.0.8",
478296
+ announcement: "sema 1.0.8 \u2014 self-wakeups no longer poison the session (empty-message guards everywhere + the \u273B resuming marker line), stream-json finally tells the truth about every failure (timeouts, blocked runs, tool errors), and giant outputs near a deadline flush completely before exit"
478140
478297
  };
478141
478298
  }
478142
478299
  });
@@ -481075,8 +481232,8 @@ var require_sema_brand = __commonJS({
481075
481232
  "Slash-command gating wired to the fleet capability handshake"
481076
481233
  ]
481077
481234
  },
481078
- productVersion: "1.0.7",
481079
- announcement: "sema 1.0.7 \u2014 headless -p now reconnects through stream blips instead of dying (bounded retry + result recovery), a dead SEMA_ENGINE_URL gets a clear three-step diagnosis in both REPL and -p, and one corrupt config.d file no longer silently drops your whole model catalog"
481235
+ productVersion: "1.0.8",
481236
+ announcement: "sema 1.0.8 \u2014 self-wakeups no longer poison the session (empty-message guards everywhere + the \u273B resuming marker line), stream-json finally tells the truth about every failure (timeouts, blocked runs, tool errors), and giant outputs near a deadline flush completely before exit"
481080
481237
  };
481081
481238
  }
481082
481239
  });
@@ -498209,6 +498366,11 @@ var init_thinkback_play2 = __esm({
498209
498366
  });
498210
498367
 
498211
498368
  // build-src/src/utils/autoModeDenials.ts
498369
+ var autoModeDenials_exports = {};
498370
+ __export(autoModeDenials_exports, {
498371
+ getAutoModeDenials: () => getAutoModeDenials,
498372
+ recordAutoModeDenial: () => recordAutoModeDenial
498373
+ });
498212
498374
  function recordAutoModeDenial(denial) {
498213
498375
  if (false) return;
498214
498376
  DENIALS = [denial, ...DENIALS.slice(0, MAX_DENIALS - 1)];
@@ -537620,7 +537782,7 @@ async function* runStreamInner(events3, ctx, handle = {}) {
537620
537782
  }
537621
537783
  if (ev.type === "done" || ev.type === "failed") {
537622
537784
  const failedResult = ev.type === "done" ? ev.result : null;
537623
- const errText = ev.type === "failed" ? ev.errorMessage ?? ev.errorCode ?? "run failed" : failedResult?.status === "failed" ? failedResult.errorMessage ?? failedResult.errorCode ?? "run failed" : null;
537785
+ const errText = ev.type === "failed" ? ev.errorMessage ?? ev.errorCode ?? "run failed" : failedResult?.status === "failed" ? failedResult.errorMessage ?? failedResult.errorCode ?? "run failed" : failedResult?.status === "timeout" ? failedResult.errorMessage ?? "run hit its wall-clock deadline and was finalized by the engine" : failedResult?.status === "blocked" ? failedResult.blockedReason ? `Run blocked: ${failedResult.blockedReason}` : "Run blocked (the agent reported it cannot proceed)" : null;
537624
537786
  if (errText) {
537625
537787
  const activeTaskId = failedResult?.activeTaskId ?? (ev.type === "failed" ? ev.activeTaskId : void 0);
537626
537788
  const isActiveRunBusy = errText === "session already has an active run" || typeof activeTaskId === "string";
@@ -537992,7 +538154,7 @@ var init_controlRouter = __esm({
537992
538154
  /** Project the session context + the typed turn into the `@sema-ai` `TaskRequest` wire shape. Secret
537993
538155
  * discipline (types.ts:54-58): NEVER put tokens in `objective`/`systemPrompt`. */
537994
538156
  buildTaskRequest(text2) {
537995
- const req = { objective: text2 };
538157
+ const req = { objective: text2.trim().length > 0 ? text2 : "(no content)" };
537996
538158
  if (this.sessionId !== void 0) req.sessionId = this.sessionId;
537997
538159
  if (this.jobId !== void 0) req.jobId = this.jobId;
537998
538160
  if (this.scenario !== void 0) req.scenario = this.scenario;
@@ -612727,6 +612889,23 @@ var init_processUserInput = __esm({
612727
612889
  }
612728
612890
  });
612729
612891
 
612892
+ // build-src/src/sema/scheduler/wakeupMarker.ts
612893
+ var wakeupMarker_exports = {};
612894
+ __export(wakeupMarker_exports, {
612895
+ formatScheduledFireTime: () => formatScheduledFireTime,
612896
+ scheduledFireMarkerText: () => scheduledFireMarkerText
612897
+ });
612898
+ function formatScheduledFireTime(d2) {
612899
+ return d2.toLocaleString("en-US", { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }).replace(/,? at |, /, " ").replace(/ ([AP]M)/, (_m, r) => r.toLowerCase());
612900
+ }
612901
+ function scheduledFireMarkerText(kind, now2 = /* @__PURE__ */ new Date()) {
612902
+ return kind === "loop" ? `Sema resuming /loop wakeup (${formatScheduledFireTime(now2)})` : `Running scheduled task (${formatScheduledFireTime(now2)})`;
612903
+ }
612904
+ var init_wakeupMarker = __esm({
612905
+ "build-src/src/sema/scheduler/wakeupMarker.ts"() {
612906
+ }
612907
+ });
612908
+
612730
612909
  // build-src/src/utils/handlePromptSubmit.ts
612731
612910
  function exit2() {
612732
612911
  gracefulShutdownSync(0);
@@ -612994,6 +613173,15 @@ async function executeUserInput(params) {
612994
613173
  if (m2.type === "user") m2.origin = origin2;
612995
613174
  }
612996
613175
  }
613176
+ if (isFirst && origin2?.kind === "scheduled-task") {
613177
+ try {
613178
+ const cronKind = origin2.cronKind === "loop" ? "loop" : "task";
613179
+ const { createScheduledTaskFireMessage: createScheduledTaskFireMessage2 } = await Promise.resolve().then(() => (init_messages4(), messages_exports2));
613180
+ const { scheduledFireMarkerText: scheduledFireMarkerText2 } = await Promise.resolve().then(() => (init_wakeupMarker(), wakeupMarker_exports));
613181
+ newMessages.push(createScheduledTaskFireMessage2(scheduledFireMarkerText2(cronKind)));
613182
+ } catch {
613183
+ }
613184
+ }
612997
613185
  newMessages.push(...result.messages);
612998
613186
  if (isFirst) {
612999
613187
  shouldQuery = result.shouldQuery;
@@ -640031,6 +640219,88 @@ var init_liveToolApprovalWire = __esm({
640031
640219
  }
640032
640220
  });
640033
640221
 
640222
+ // build-src/src/sema/classifierVerdictWire.ts
640223
+ function textFromWireOutput(output) {
640224
+ if (typeof output === "string") return output;
640225
+ const blocks = Array.isArray(output) ? output : output !== null && typeof output === "object" && Array.isArray(output.content) ? output.content : void 0;
640226
+ if (!blocks) return void 0;
640227
+ const texts = blocks.map((b3) => b3 !== null && typeof b3 === "object" && typeof b3.text === "string" ? b3.text : void 0).filter((t2) => t2 !== void 0);
640228
+ return texts.length > 0 ? texts.join("\n") : void 0;
640229
+ }
640230
+ function unwrapSystemReminder(text2) {
640231
+ const m2 = /^\s*<system-reminder>\s*\n?([\s\S]*?)\n?\s*<\/system-reminder>\s*$/.exec(text2);
640232
+ return m2 ? m2[1] : text2;
640233
+ }
640234
+ function classifierDenyFromToolEnd(ev) {
640235
+ if (!ev || ev.type !== "tool_end" || ev.isError !== true) return void 0;
640236
+ const raw2 = textFromWireOutput(ev.output);
640237
+ if (raw2 === void 0) return void 0;
640238
+ const message = unwrapSystemReminder(raw2).trim();
640239
+ if (!message.startsWith(CLASSIFIER_DENY_SIGNATURE)) return void 0;
640240
+ const tail = message.slice(CLASSIFIER_DENY_SIGNATURE.length);
640241
+ const reason = tail.startsWith(": ") ? tail.slice(2).trim() : void 0;
640242
+ return { message, ...reason !== void 0 && reason.length > 0 ? { reason } : {} };
640243
+ }
640244
+ function classifierDenyNoticeText(toolName2, reason) {
640245
+ let r = reason ?? "";
640246
+ if (r.length > NOTICE_REASON_MAX) r = `${r.slice(0, NOTICE_REASON_MAX - 1)}\u2026`;
640247
+ const name = toolName2.length > 0 ? toolName2.toLowerCase() : "tool";
640248
+ return `${name} denied by auto mode${r ? ` \xB7 ${r}` : ""} \xB7 /permissions`;
640249
+ }
640250
+ function surfaceClassifierDeny(toolName2, verdict) {
640251
+ try {
640252
+ const denials = (init_autoModeDenials(), __toCommonJS(autoModeDenials_exports));
640253
+ denials.recordAutoModeDenial?.({
640254
+ toolName: toolName2,
640255
+ // display:wire 的 tool_end 不带 args(args 在 tool_start;本桥只为 ask/fs 工具留存),
640256
+ // 克制起见用 toolName 兜底 —— 裁决 reason 单列一栏,信息不丢。
640257
+ display: toolName2,
640258
+ reason: verdict.reason ?? verdict.message,
640259
+ timestamp: Date.now()
640260
+ });
640261
+ } catch (e) {
640262
+ logForDebugging(`classifierVerdictWire: recordAutoModeDenial failed (fail-soft): ${String(e)}`);
640263
+ }
640264
+ try {
640265
+ const store = getAppStateStoreRef();
640266
+ if (!store) return;
640267
+ store.setState((prev) => ({
640268
+ ...prev,
640269
+ notifications: {
640270
+ current: {
640271
+ key: NOTICE_KEY,
640272
+ text: classifierDenyNoticeText(toolName2, verdict.reason),
640273
+ color: "warning",
640274
+ priority: "immediate",
640275
+ timeoutMs: NOTICE_TIMEOUT_MS
640276
+ },
640277
+ queue: prev.notifications.queue
640278
+ }
640279
+ }));
640280
+ const timer2 = setTimeout(() => {
640281
+ try {
640282
+ store.setState(
640283
+ (prev) => prev.notifications.current?.key === NOTICE_KEY ? { ...prev, notifications: { current: null, queue: prev.notifications.queue } } : prev
640284
+ );
640285
+ } catch {
640286
+ }
640287
+ }, NOTICE_TIMEOUT_MS);
640288
+ timer2.unref?.();
640289
+ } catch {
640290
+ }
640291
+ }
640292
+ var CLASSIFIER_DENY_SIGNATURE, NOTICE_REASON_MAX, NOTICE_KEY, NOTICE_TIMEOUT_MS;
640293
+ var init_classifierVerdictWire = __esm({
640294
+ "build-src/src/sema/classifierVerdictWire.ts"() {
640295
+ init_appStateRef();
640296
+ init_debug();
640297
+ CLASSIFIER_DENY_SIGNATURE = "auto-mode classifier blocked this call";
640298
+ NOTICE_REASON_MAX = 80;
640299
+ NOTICE_KEY = "auto-mode-denied";
640300
+ NOTICE_TIMEOUT_MS = 1e4;
640301
+ }
640302
+ });
640303
+
640034
640304
  // build-src/src/sema/liveHitlAskWire.ts
640035
640305
  function rejectMessageForRender() {
640036
640306
  try {
@@ -640255,6 +640525,19 @@ async function* bridgeAskUserQuestionGates(source, deps2, opts) {
640255
640525
  const pi = pendingFsCalls.indexOf(ev.toolCallId);
640256
640526
  if (pi !== -1) pendingFsCalls.splice(pi, 1);
640257
640527
  }
640528
+ if (ev.isError === true && !deniedCalls.has(ev.toolCallId)) {
640529
+ const verdict = classifierDenyFromToolEnd(ev);
640530
+ if (verdict) {
640531
+ endedCalls.add(ev.toolCallId);
640532
+ heldAskEnds.delete(ev.toolCallId);
640533
+ surfaceClassifierDeny(typeof ev.toolName === "string" ? ev.toolName : "tool", verdict);
640534
+ logForDebugging(
640535
+ `liveHitlAskWire: classifier deny verdict on ${ev.toolCallId} (${String(ev.toolName)}) \u2014 labeled render + notice`
640536
+ );
640537
+ yield { ...ev, output: verdict.message, structured: void 0 };
640538
+ continue;
640539
+ }
640540
+ }
640258
640541
  if (ev.isError === true && typeof ev.toolName === "string" && toolNameIsFsWrite(ev.toolName) && denyStampNextFsEnd && !deniedCalls.has(ev.toolCallId)) {
640259
640542
  denyStampNextFsEnd = false;
640260
640543
  endedCalls.add(ev.toolCallId);
@@ -640381,6 +640664,7 @@ var init_liveHitlAskWire = __esm({
640381
640664
  init_debug();
640382
640665
  init_appStateRef();
640383
640666
  init_liveToolApprovalWire();
640667
+ init_classifierVerdictWire();
640384
640668
  MAX_GATE_HOPS = 24;
640385
640669
  CANCEL_DENY_BUDGET_MS = 2e3;
640386
640670
  CANCEL_DENY_WARN_TEXT = "could not cancel the pending question \u2014 the session may stay locked; the run may need engine-side recovery";
@@ -640976,7 +641260,7 @@ function debugLog(msg) {
640976
641260
  }
640977
641261
  function terminalEventFromRunRow(row2) {
640978
641262
  if (!row2 || typeof row2.status !== "string") return null;
640979
- if (row2.status === "completed" || row2.status === "failed") {
641263
+ if (RUN_ROW_TERMINAL_STATUSES.has(row2.status)) {
640980
641264
  if (row2.result && typeof row2.result === "object") {
640981
641265
  return { type: "done", result: row2.result };
640982
641266
  }
@@ -641052,11 +641336,19 @@ async function* withHeadlessR1Reconnect(live, deps2) {
641052
641336
  }
641053
641337
  }
641054
641338
  }
641055
- var HEADLESS_RECONNECT_MAX;
641339
+ var HEADLESS_RECONNECT_MAX, RUN_ROW_TERMINAL_STATUSES;
641056
641340
  var init_headlessReconnectWire = __esm({
641057
641341
  "build-src/src/sema/headlessReconnectWire.ts"() {
641058
641342
  init_sseIdleTriage();
641059
641343
  HEADLESS_RECONNECT_MAX = 2;
641344
+ RUN_ROW_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
641345
+ "completed",
641346
+ "failed",
641347
+ "timeout",
641348
+ "blocked",
641349
+ "suspended",
641350
+ "needs_review"
641351
+ ]);
641060
641352
  }
641061
641353
  });
641062
641354
 
@@ -641618,12 +641910,70 @@ var init_headlessPermissionModeWire = __esm({
641618
641910
  "default",
641619
641911
  "plan",
641620
641912
  "acceptEdits",
641621
- "bypassPermissions"
641913
+ "bypassPermissions",
641914
+ "auto"
641622
641915
  ];
641623
641916
  warnedInvalidEnv = false;
641624
641917
  }
641625
641918
  });
641626
641919
 
641920
+ // build-src/src/sema/interactiveToolsWire.ts
641921
+ var interactiveToolsWire_exports = {};
641922
+ __export(interactiveToolsWire_exports, {
641923
+ HEADLESS_INTERACTIVE_TOOLS_ENV: () => HEADLESS_INTERACTIVE_TOOLS_ENV,
641924
+ _resetInteractiveToolsWireForTest: () => _resetInteractiveToolsWireForTest,
641925
+ planModeExplicitlyRequested: () => planModeExplicitlyRequested,
641926
+ resolveHeadlessInteractiveTools: () => resolveHeadlessInteractiveTools
641927
+ });
641928
+ function planModeExplicitlyRequested(argv) {
641929
+ let mode;
641930
+ for (let i = 0; i < argv.length; i++) {
641931
+ const a = argv[i];
641932
+ if (a === "--permission-mode") {
641933
+ const v2 = argv[i + 1];
641934
+ if (typeof v2 === "string" && !v2.startsWith("-")) {
641935
+ mode = v2;
641936
+ i++;
641937
+ }
641938
+ } else if (a?.startsWith("--permission-mode=")) {
641939
+ mode = a.slice("--permission-mode=".length);
641940
+ } else if (a === "--") {
641941
+ break;
641942
+ }
641943
+ }
641944
+ return mode === "plan";
641945
+ }
641946
+ function resolveHeadlessInteractiveTools(argv, env5 = process.env) {
641947
+ if (planModeExplicitlyRequested(argv)) {
641948
+ return { fields: {}, source: "plan-flag" };
641949
+ }
641950
+ const raw2 = env5[HEADLESS_INTERACTIVE_TOOLS_ENV]?.trim();
641951
+ if (raw2 !== void 0 && raw2 !== "") {
641952
+ if (raw2 === "true" || raw2 === "1") return { fields: {}, source: "env" };
641953
+ if (raw2 === "false" || raw2 === "0") return { fields: { interactiveTools: false }, source: "env" };
641954
+ const resolution = {
641955
+ fields: { interactiveTools: false },
641956
+ source: "default"
641957
+ };
641958
+ if (!warnedInvalidEnv2) {
641959
+ warnedInvalidEnv2 = true;
641960
+ resolution.warning = `sema: ${HEADLESS_INTERACTIVE_TOOLS_ENV}="${raw2}" is not a boolean (expected true/1/false/0) \u2014 ignoring it, headless -p keeps interactive tools OFF by default`;
641961
+ }
641962
+ return resolution;
641963
+ }
641964
+ return { fields: { interactiveTools: false }, source: "default" };
641965
+ }
641966
+ function _resetInteractiveToolsWireForTest() {
641967
+ warnedInvalidEnv2 = false;
641968
+ }
641969
+ var HEADLESS_INTERACTIVE_TOOLS_ENV, warnedInvalidEnv2;
641970
+ var init_interactiveToolsWire = __esm({
641971
+ "build-src/src/sema/interactiveToolsWire.ts"() {
641972
+ HEADLESS_INTERACTIVE_TOOLS_ENV = "SEMA_HEADLESS_INTERACTIVE_TOOLS";
641973
+ warnedInvalidEnv2 = false;
641974
+ }
641975
+ });
641976
+
641627
641977
  // build-src/src/sema/printStreamJsonContract.ts
641628
641978
  var printStreamJsonContract_exports = {};
641629
641979
  __export(printStreamJsonContract_exports, {
@@ -641875,6 +642225,62 @@ var init_printStreamJsonContract = __esm({
641875
642225
  }
641876
642226
  });
641877
642227
 
642228
+ // build-src/src/sema/printToolResultFrame.ts
642229
+ var printToolResultFrame_exports = {};
642230
+ __export(printToolResultFrame_exports, {
642231
+ flattenToolOutput: () => flattenToolOutput,
642232
+ toolEndResultToUserFrame: () => toolEndResultToUserFrame
642233
+ });
642234
+ function flattenToolOutput(output) {
642235
+ if (typeof output === "string") return output;
642236
+ if (Array.isArray(output)) {
642237
+ const parts = [];
642238
+ for (const block2 of output) {
642239
+ if (block2 && typeof block2 === "object") {
642240
+ const b3 = block2;
642241
+ if (b3.type === "text" && typeof b3.text === "string") parts.push(b3.text);
642242
+ else if (b3.type === "image") parts.push("[image]");
642243
+ }
642244
+ }
642245
+ return parts.join("");
642246
+ }
642247
+ return "";
642248
+ }
642249
+ function bashExitCodeFailed(toolName2, text2) {
642250
+ if (typeof toolName2 !== "string" || toolName2.toLowerCase() !== "bash") return false;
642251
+ const m2 = /^exit code: (\d+)\b/.exec(text2);
642252
+ return m2 !== null && m2[1] !== "0";
642253
+ }
642254
+ function toolEndResultToUserFrame(arm) {
642255
+ if (typeof arm.toolCallId !== "string" || arm.toolCallId.length === 0) return null;
642256
+ const text2 = flattenToolOutput(arm.output);
642257
+ return {
642258
+ type: "user",
642259
+ message: {
642260
+ role: "user",
642261
+ content: [
642262
+ {
642263
+ type: "tool_result",
642264
+ tool_use_id: arm.toolCallId,
642265
+ // truncated 输出如实标注(观察面注记;截断体绝不回喂模型——upstreamBridge 同款)。
642266
+ content: arm.truncated === true ? `${text2}
642267
+ \u2026(truncated)` : text2,
642268
+ is_error: arm.isError === true || bashExitCodeFailed(arm.toolName, text2)
642269
+ }
642270
+ ]
642271
+ },
642272
+ parent_tool_use_id: typeof arm.parentToolCallId === "string" ? arm.parentToolCallId : null,
642273
+ // eventToSdkMessage 已 stamp 的 uuid/session_id 原样骑帧(uuid = core-minted eventId 优先级
642274
+ // 在 stamp 里已定);缺失时留 undefined,print 面容忍(CC 消费者按可选读)。
642275
+ uuid: arm.uuid,
642276
+ session_id: arm.session_id
642277
+ };
642278
+ }
642279
+ var init_printToolResultFrame = __esm({
642280
+ "build-src/src/sema/printToolResultFrame.ts"() {
642281
+ }
642282
+ });
642283
+
641878
642284
  // build-src/src/sema/seamQueryEngine.ts
641879
642285
  var seamQueryEngine_exports = {};
641880
642286
  __export(seamQueryEngine_exports, {
@@ -641952,7 +642358,8 @@ async function* ask(params) {
641952
642358
  );
641953
642359
  process.exit(1);
641954
642360
  }
641955
- const objective = promptToObjective(params?.prompt);
642361
+ const rawObjective = promptToObjective(params?.prompt);
642362
+ const objective = rawObjective.trim().length > 0 ? rawObjective : "(no content)";
641956
642363
  const webSearch = process.env.SEMA_LIVE_BASEURL ? webSearchFromEnv() : void 0;
641957
642364
  if (webSearch && process.env.SEMA_DEBUG) {
641958
642365
  console.error(
@@ -642081,6 +642488,24 @@ async function* ask(params) {
642081
642488
  if (process.env.SEMA_DEBUG) console.error("[sema] print-mode ask permission wire soft-failed:", ePerm);
642082
642489
  }
642083
642490
  }
642491
+ let interactiveToolsField = {};
642492
+ if (process.env.SEMA_LIVE_BASEURL) {
642493
+ try {
642494
+ const itw = await Promise.resolve().then(() => (init_interactiveToolsWire(), interactiveToolsWire_exports));
642495
+ const r = itw.resolveHeadlessInteractiveTools(process.argv.slice(2), process.env);
642496
+ if (r.warning) {
642497
+ console.error(r.warning);
642498
+ }
642499
+ interactiveToolsField = r.fields;
642500
+ if (process.env.SEMA_DEBUG) {
642501
+ console.error(
642502
+ `[sema] print-mode ask: interactive-tools wire \u2192 ${r.fields.interactiveTools === false ? "TaskRequest.interactiveTools=false" : "not stamped"} (source=${r.source})`
642503
+ );
642504
+ }
642505
+ } catch (eIt) {
642506
+ if (process.env.SEMA_DEBUG) console.error("[sema] print-mode ask interactive-tools wire soft-failed:", eIt);
642507
+ }
642508
+ }
642084
642509
  let detachHeaders;
642085
642510
  if (process.env.SEMA_LIVE_BASEURL) {
642086
642511
  try {
@@ -642129,6 +642554,9 @@ async function* ask(params) {
642129
642554
  ...sandboxFields,
642130
642555
  // SEMA_HEADLESS_PERMISSION_MODE 旋钮(flag > env > absent;live-gated;空 = 现状 absent-mode)。
642131
642556
  ...headlessPermissionField,
642557
+ // [909]B 件3:interactiveTools:false(live-gated;SDK TaskRequest 类型暂无此字段 ——
642558
+ // limits/finalVerification 同款短期窄 cast;server 白名单半场已另行派单)。
642559
+ ...interactiveToolsField.interactiveTools === false ? { interactiveTools: false } : {},
642132
642560
  ...webSearch || wireHooks ? { settings: { ...webSearch ? { webSearch } : {}, ...wireHooks ? { hooks: wireHooks } : {} } } : {},
642133
642561
  ...selfOrchestration ? { selfOrchestration } : {},
642134
642562
  ...enableFork !== void 0 ? { enableFork } : {},
@@ -642152,7 +642580,13 @@ async function* ask(params) {
642152
642580
  for await (const msg of sdk) {
642153
642581
  if (signal?.aborted) break;
642154
642582
  const t2 = msg.type;
642155
- if (t2 === "tool_end_result" || t2 === "retry_status" || t2 === "turn_usage" || t2 === "task_progress") {
642583
+ if (t2 === "tool_end_result") {
642584
+ const { toolEndResultToUserFrame: toolEndResultToUserFrame2 } = await Promise.resolve().then(() => (init_printToolResultFrame(), printToolResultFrame_exports));
642585
+ const frame = toolEndResultToUserFrame2(msg);
642586
+ if (frame) yield frame;
642587
+ continue;
642588
+ }
642589
+ if (t2 === "retry_status" || t2 === "turn_usage" || t2 === "task_progress") {
642156
642590
  continue;
642157
642591
  }
642158
642592
  if (t2 === "workflow_complete") {
@@ -645820,6 +646254,8 @@ Startup time: ${Math.round(process.uptime() * 1e3)}ms
645820
646254
  if (options.outputFormat === "stream-json") {
645821
646255
  installStreamJsonSignalTailFrame();
645822
646256
  }
646257
+ const { setPipedStdoutBlocking: setPipedStdoutBlocking2 } = await Promise.resolve().then(() => (init_stdoutDrain(), stdoutDrain_exports));
646258
+ setPipedStdoutBlocking2();
645823
646259
  if (false) {
645824
646260
  void downloadUserSettings();
645825
646261
  }
@@ -646145,16 +646581,22 @@ Error: sandbox required but unavailable: ${sandboxUnavailableReason}
646145
646581
  );
646146
646582
  break;
646147
646583
  }
646584
+ // [909]B2 nit + B1 语义:这三臂此前 (a) 缺尾换行(TB「exit rc= 标记与上一行粘连」的
646585
+ // 文本形态源之一),(b) 只会渲本地 loop 语义的模板句 —— 引擎终帧(timeout→error_max_turns、
646586
+ // budget、output.invalid)带 errors[] 引擎原话时优先如实渲它(--deadline 的 timeout 若渲
646587
+ // "Reached max turns (undefined)" 是撒谎)。errors[] 缺席时维持 CC 模板句(补 \n)。
646148
646588
  case "error_max_turns":
646149
- writeToStdout(`Error: Reached max turns (${options.maxTurns})`);
646150
- break;
646151
646589
  case "error_max_budget_usd":
646152
- writeToStdout(`Error: Exceeded USD budget (${options.maxBudgetUsd})`);
646590
+ case "error_max_structured_output_retries": {
646591
+ const engineErrors = lastMessage.errors;
646592
+ if (Array.isArray(engineErrors) && engineErrors.length > 0) {
646593
+ process.stderr.write(formatTextModeExecutionError(engineErrors) + "\n");
646594
+ break;
646595
+ }
646596
+ const template = lastMessage.subtype === "error_max_turns" ? `Error: Reached max turns (${options.maxTurns})` : lastMessage.subtype === "error_max_budget_usd" ? `Error: Exceeded USD budget (${options.maxBudgetUsd})` : `Error: Failed to provide valid structured output after maximum retries`;
646597
+ writeToStdout(template + "\n");
646153
646598
  break;
646154
- case "error_max_structured_output_retries":
646155
- writeToStdout(
646156
- `Error: Failed to provide valid structured output after maximum retries`
646157
- );
646599
+ }
646158
646600
  }
646159
646601
  }
646160
646602
  logHeadlessProfilerTurn();
@@ -666219,7 +666661,7 @@ Auth: unix socket -R \u2192 local proxy`, "info");
666219
666661
  pendingHookMessages
666220
666662
  }, renderAndRun);
666221
666663
  }
666222
- }).version("sema 1.0.7", "-v, --version", "Output the version number");
666664
+ }).version("sema 1.0.8", "-v, --version", "Output the version number");
666223
666665
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
666224
666666
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
666225
666667
  if (canUserConfigureAdvisor()) {
@@ -670100,6 +670542,21 @@ var init_node4 = __esm({
670100
670542
  }
670101
670543
  });
670102
670544
 
670545
+ // build-src/src/sema/scheduler/firePrompt.ts
670546
+ function effectiveFirePrompt(fire) {
670547
+ const raw2 = fire.prompt;
670548
+ if (typeof raw2 === "string" && raw2.trim().length > 0) return { prompt: raw2, substituted: false };
670549
+ const what = fire.mode === "session-wakeup" ? "wakeup" : "task";
670550
+ return {
670551
+ prompt: `A scheduled ${what} fired (record ${fire.recordId}), but its stored prompt was empty. Tell the user the scheduled prompt was lost, and use recent conversation context to decide whether anything needs doing.`,
670552
+ substituted: true
670553
+ };
670554
+ }
670555
+ var init_firePrompt = __esm({
670556
+ "build-src/src/sema/scheduler/firePrompt.ts"() {
670557
+ }
670558
+ });
670559
+
670103
670560
  // build-src/src/sema/scheduler/schedulerDaemonWire.ts
670104
670561
  import { join as join201 } from "node:path";
670105
670562
  import { homedir as homedir57 } from "node:os";
@@ -670116,6 +670573,7 @@ var init_schedulerDaemonWire = __esm({
670116
670573
  "build-src/src/sema/scheduler/schedulerDaemonWire.ts"() {
670117
670574
  init_node4();
670118
670575
  init_schedulerDaemon();
670576
+ init_firePrompt();
670119
670577
  }
670120
670578
  });
670121
670579
 
@@ -670132,22 +670590,31 @@ function ownsScheduledRecord(r) {
670132
670590
  const current3 = getLiveSessionId() ?? String(getSessionId());
670133
670591
  return r.sessionId === current3;
670134
670592
  }
670135
- function submitViaQueue() {
670593
+ function submitViaQueue(onWarn) {
670136
670594
  return async (fire) => {
670595
+ const { prompt, substituted } = effectiveFirePrompt(fire);
670596
+ if (substituted) {
670597
+ onWarn?.(`scheduler: record ${fire.recordId} fired with an EMPTY prompt \u2014 substituted a placeholder (never inject empty user content)`);
670598
+ }
670137
670599
  enqueuePendingNotification({
670138
- value: fire.prompt,
670600
+ value: prompt,
670139
670601
  mode: "prompt",
670140
670602
  priority: "later",
670141
670603
  // never starve real user input (CC cron precedent)
670142
670604
  isMeta: true,
670143
670605
  // hidden injected prompt, visible assistant wake turn (CC useScheduledTasks precedent)
670606
+ skipSlashCommands: true,
670607
+ // CC 207 逐字位:fired prompt 是纯文本,不走本地 slash 命令路由
670608
+ // 件A 标记行驱动(handlePromptSubmit 按 origin.kind 渲 `✳ …` scheduled_task_fire 行;
670609
+ // 'loop' = session-wakeup(ScheduleWakeup 续班),'task' = cron/one-shot 排程。
670610
+ origin: { kind: "scheduled-task", cronKind: fire.mode === "session-wakeup" ? "loop" : "task" },
670144
670611
  workload: WORKLOAD_CRON
670145
670612
  });
670146
670613
  };
670147
670614
  }
670148
670615
  function createReplSchedulerDaemon(opts = {}) {
670149
670616
  const storePath = opts.storePath ?? schedulerStorePath();
670150
- return new SchedulerDaemon(fileSchedulerStoreIO(storePath), submitViaQueue(), {
670617
+ return new SchedulerDaemon(fileSchedulerStoreIO(storePath), submitViaQueue((m2) => opts.onError?.(new Error(m2))), {
670151
670618
  intervalMs: opts.intervalMs ?? REPL_SCHEDULER_TICK_MS,
670152
670619
  owns: ownsScheduledRecord,
670153
670620
  ...opts.now ? { now: opts.now } : {},
@@ -670163,6 +670630,7 @@ var init_schedulerQueueSubmit = __esm({
670163
670630
  init_liveSessionStore();
670164
670631
  init_schedulerDaemon();
670165
670632
  init_schedulerDaemonWire();
670633
+ init_firePrompt();
670166
670634
  REPL_SCHEDULER_TICK_MS = 5e3;
670167
670635
  }
670168
670636
  });