@sema-agent/cli 1.0.6 → 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.
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) {
@@ -114152,7 +114222,7 @@ var require_diagnostics = __commonJS({
114152
114222
  proxyConnected: diagnosticsChannel.channel("undici:proxy:connected")
114153
114223
  };
114154
114224
  var isTrackingClientEvents = false;
114155
- function trackClientEvents(debugLog = undiciDebugLog) {
114225
+ function trackClientEvents(debugLog2 = undiciDebugLog) {
114156
114226
  if (isTrackingClientEvents) {
114157
114227
  return;
114158
114228
  }
@@ -114167,7 +114237,7 @@ var require_diagnostics = __commonJS({
114167
114237
  const {
114168
114238
  connectParams: { version: version5, protocol, port, host }
114169
114239
  } = evt;
114170
- debugLog(
114240
+ debugLog2(
114171
114241
  "connecting to %s%s using %s%s",
114172
114242
  host,
114173
114243
  port ? `:${port}` : "",
@@ -114182,7 +114252,7 @@ var require_diagnostics = __commonJS({
114182
114252
  const {
114183
114253
  connectParams: { version: version5, protocol, port, host }
114184
114254
  } = evt;
114185
- debugLog(
114255
+ debugLog2(
114186
114256
  "connected to %s%s using %s%s",
114187
114257
  host,
114188
114258
  port ? `:${port}` : "",
@@ -114198,7 +114268,7 @@ var require_diagnostics = __commonJS({
114198
114268
  connectParams: { version: version5, protocol, port, host },
114199
114269
  error: error52
114200
114270
  } = evt;
114201
- debugLog(
114271
+ debugLog2(
114202
114272
  "connection to %s%s using %s%s errored - %s",
114203
114273
  host,
114204
114274
  port ? `:${port}` : "",
@@ -114214,12 +114284,12 @@ var require_diagnostics = __commonJS({
114214
114284
  const {
114215
114285
  request: { method, path: path27, origin: origin2 }
114216
114286
  } = evt;
114217
- debugLog("sending request to %s %s%s", method, origin2, path27);
114287
+ debugLog2("sending request to %s %s%s", method, origin2, path27);
114218
114288
  }
114219
114289
  );
114220
114290
  }
114221
114291
  var isTrackingRequestEvents = false;
114222
- function trackRequestEvents(debugLog = undiciDebugLog) {
114292
+ function trackRequestEvents(debugLog2 = undiciDebugLog) {
114223
114293
  if (isTrackingRequestEvents) {
114224
114294
  return;
114225
114295
  }
@@ -114235,7 +114305,7 @@ var require_diagnostics = __commonJS({
114235
114305
  request: { method, path: path27, origin: origin2 },
114236
114306
  response: { statusCode }
114237
114307
  } = evt;
114238
- debugLog(
114308
+ debugLog2(
114239
114309
  "received response to %s %s%s - HTTP %d",
114240
114310
  method,
114241
114311
  origin2,
@@ -114250,7 +114320,7 @@ var require_diagnostics = __commonJS({
114250
114320
  const {
114251
114321
  request: { method, path: path27, origin: origin2 }
114252
114322
  } = evt;
114253
- debugLog("trailers received from %s %s%s", method, origin2, path27);
114323
+ debugLog2("trailers received from %s %s%s", method, origin2, path27);
114254
114324
  }
114255
114325
  );
114256
114326
  diagnosticsChannel.subscribe(
@@ -114260,7 +114330,7 @@ var require_diagnostics = __commonJS({
114260
114330
  request: { method, path: path27, origin: origin2 },
114261
114331
  error: error52
114262
114332
  } = evt;
114263
- debugLog(
114333
+ debugLog2(
114264
114334
  "request to %s %s%s errored - %s",
114265
114335
  method,
114266
114336
  origin2,
@@ -114271,7 +114341,7 @@ var require_diagnostics = __commonJS({
114271
114341
  );
114272
114342
  }
114273
114343
  var isTrackingWebSocketEvents = false;
114274
- function trackWebSocketEvents(debugLog = websocketDebuglog) {
114344
+ function trackWebSocketEvents(debugLog2 = websocketDebuglog) {
114275
114345
  if (isTrackingWebSocketEvents) {
114276
114346
  return;
114277
114347
  }
@@ -114285,9 +114355,9 @@ var require_diagnostics = __commonJS({
114285
114355
  (evt) => {
114286
114356
  if (evt.address != null) {
114287
114357
  const { address, port } = evt.address;
114288
- debugLog("connection opened %s%s", address, port ? `:${port}` : "");
114358
+ debugLog2("connection opened %s%s", address, port ? `:${port}` : "");
114289
114359
  } else {
114290
- debugLog("connection opened");
114360
+ debugLog2("connection opened");
114291
114361
  }
114292
114362
  }
114293
114363
  );
@@ -114295,7 +114365,7 @@ var require_diagnostics = __commonJS({
114295
114365
  "undici:websocket:close",
114296
114366
  (evt) => {
114297
114367
  const { websocket, code: code2, reason } = evt;
114298
- debugLog(
114368
+ debugLog2(
114299
114369
  "closed connection to %s - %s %s",
114300
114370
  websocket.url,
114301
114371
  code2,
@@ -114306,19 +114376,19 @@ var require_diagnostics = __commonJS({
114306
114376
  diagnosticsChannel.subscribe(
114307
114377
  "undici:websocket:socket_error",
114308
114378
  (err8) => {
114309
- debugLog("connection errored - %s", err8.message);
114379
+ debugLog2("connection errored - %s", err8.message);
114310
114380
  }
114311
114381
  );
114312
114382
  diagnosticsChannel.subscribe(
114313
114383
  "undici:websocket:ping",
114314
114384
  (evt) => {
114315
- debugLog("ping received");
114385
+ debugLog2("ping received");
114316
114386
  }
114317
114387
  );
114318
114388
  diagnosticsChannel.subscribe(
114319
114389
  "undici:websocket:pong",
114320
114390
  (evt) => {
114321
- debugLog("pong received");
114391
+ debugLog2("pong received");
114322
114392
  }
114323
114393
  );
114324
114394
  }
@@ -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
 
@@ -157421,6 +157497,7 @@ __export(engineTarget_exports, {
157421
157497
  engineRoutingRefusalActive: () => engineRoutingRefusalActive,
157422
157498
  evaluateEngineRouting: () => evaluateEngineRouting,
157423
157499
  execAxisReading: () => execAxisReading,
157500
+ isEngineTransportError: () => isEngineTransportError,
157424
157501
  isLoopbackEngineUrl: () => isLoopbackEngineUrl,
157425
157502
  isTrustedEngineHost: () => isTrustedEngineHost,
157426
157503
  normalizeEngineUrl: () => normalizeEngineUrl,
@@ -157576,9 +157653,19 @@ function enginePinUnreachableHint(pin) {
157576
157653
  const settingsPath = join34(getClaudeConfigHomeDir(), "settings.json");
157577
157654
  const where = pin.source === "settings" ? `${ENGINE_URL_ENV} in ${settingsPath} (env block)` : `the ${ENGINE_URL_ENV} environment variable`;
157578
157655
  const removal = pin.source === "settings" ? `remove the "${ENGINE_URL_ENV}" key from ${settingsPath} (or run \`sema cloud engine disconnect\`)` : `unset it in your shell (e.g. \`unset ${ENGINE_URL_ENV}\`)`;
157579
- return `The engine target is pinned to ${pin.url} by ${where}, so sema did not start a local engine.
157580
- \xB7 Intentional remote engine? Start it at that address, then send your message again.
157581
- \xB7 Leftover from an older install? ${removal} \u2014 the next launch self-spawns a local engine.`;
157656
+ return `The engine at ${ENGINE_URL_ENV}=${pin.url} is unreachable \u2014 that pin comes from ${where}, so sema did not start a local engine.
157657
+ \xB7 Intentional remote engine? Check it is running and the port is right, then send your message again.
157658
+ \xB7 Leftover from an older install, or want the shell-managed engine back? ${removal} \u2014 the next launch self-spawns a local engine.
157659
+ \xB7 Not sure? Run \`sema doctor\` to see the engine status.`;
157660
+ }
157661
+ function isEngineTransportError(err8) {
157662
+ const e = err8;
157663
+ if (typeof e?.status === "number") return false;
157664
+ const cause = e?.cause;
157665
+ const detail = typeof cause?.message === "string" && cause.message.length > 0 && cause.message || typeof e?.message === "string" && e.message.length > 0 && e.message || String(err8);
157666
+ return e?.cause !== void 0 || /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EHOSTUNREACH|ENETUNREACH|EPIPE|socket hang up|UND_ERR|terminated|other side closed/i.test(
157667
+ detail
157668
+ );
157582
157669
  }
157583
157670
  function noteEnginePinUnreachable(pin) {
157584
157671
  enginePinUnreachable = pin;
@@ -157759,11 +157846,18 @@ var init_engineTarget = __esm({
157759
157846
  });
157760
157847
 
157761
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
+ }
157762
157855
  function isProjectableUserMessage(m2) {
157763
157856
  if (!m2 || typeof m2 !== "object") return false;
157764
157857
  const c2 = m2;
157765
157858
  if (c2.type !== "user" && c2.type !== void 0) return false;
157766
157859
  if (c2.isMeta === true || c2.isCompactSummary === true || c2.isVisibleInTranscriptOnly === true) return false;
157860
+ if (isToolResultUserMessage(m2)) return false;
157767
157861
  return true;
157768
157862
  }
157769
157863
  function lastProjectableUserMessage(msgs) {
@@ -157772,6 +157866,26 @@ function lastProjectableUserMessage(msgs) {
157772
157866
  }
157773
157867
  return void 0;
157774
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
+ }
157775
157889
  var init_userMessageSelect = __esm({
157776
157890
  "build-src/src/sema/userMessageSelect.ts"() {
157777
157891
  }
@@ -330909,9 +331023,9 @@ function streamingTailWrap(unstableSuffix) {
330909
331023
  var import_compiler_runtime43, import_react43, import_jsx_runtime53, TOKEN_CACHE_MAX, tokenCache, MD_SYNTAX_RE;
330910
331024
  var init_Markdown = __esm({
330911
331025
  "build-src/src/components/Markdown.tsx"() {
330912
- import_compiler_runtime43 = __toESM(require_compiler_runtime());
331026
+ import_compiler_runtime43 = __toESM(require_compiler_runtime(), 1);
330913
331027
  init_marked_esm();
330914
- import_react43 = __toESM(require_react());
331028
+ import_react43 = __toESM(require_react(), 1);
330915
331029
  init_useSettings();
330916
331030
  init_ink2();
330917
331031
  init_cliHighlight();
@@ -330919,7 +331033,7 @@ var init_Markdown = __esm({
330919
331033
  init_markdown();
330920
331034
  init_messages4();
330921
331035
  init_MarkdownTable();
330922
- import_jsx_runtime53 = __toESM(require_jsx_runtime());
331036
+ import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
330923
331037
  TOKEN_CACHE_MAX = 500;
330924
331038
  tokenCache = /* @__PURE__ */ new Map();
330925
331039
  MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
@@ -331587,6 +331701,39 @@ var init_trustedDevice = __esm({
331587
331701
  }
331588
331702
  });
331589
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
+
331590
331737
  // build-src/src/utils/gracefulShutdown.ts
331591
331738
  import { writeSync as writeSync3 } from "fs";
331592
331739
  function cleanupTerminalModes() {
@@ -331761,6 +331908,11 @@ async function gracefulShutdown(exitCode = 0, reason = "other", options) {
331761
331908
  } catch {
331762
331909
  }
331763
331910
  }
331911
+ try {
331912
+ const { drainStdoutBounded: drainStdoutBounded2 } = await Promise.resolve().then(() => (init_stdoutDrain(), stdoutDrain_exports));
331913
+ await drainStdoutBounded2();
331914
+ } catch {
331915
+ }
331764
331916
  forceExit(exitCode);
331765
331917
  }
331766
331918
  var resumeHintPrinted, setupGracefulShutdown, shutdownInProgress, failsafeTimer, orphanCheckInterval, pendingShutdown, CleanupTimeoutError;
@@ -431863,13 +432015,29 @@ function toTaskRequest(params) {
431863
432015
  }
431864
432016
  }
431865
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
+ }
431866
432030
  if (objective.length === 0 && !submitted && msgs.length > 0) {
431867
432031
  objective = objectiveFromMessage(msgs[msgs.length - 1]);
431868
432032
  }
431869
- const images = submitted ? imagesFromMessage(submitted) : [];
432033
+ const images = submitted && !metaIsSubmission ? imagesFromMessage(submitted) : [];
431870
432034
  if (images.length > 0 && process.env.SEMA_DEBUG) {
431871
432035
  console.error(`[sema][seamQuery] images wire: ${images.length} image(s) \u2192 TaskRequest.images`);
431872
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
+ }
431873
432041
  const sysPrompt = params.systemPrompt;
431874
432042
  const scenario2 = selectScenario(objective);
431875
432043
  let reasoningEffort;
@@ -432131,9 +432299,8 @@ Setup looks unfinished (no model was saved). Run \`sema onboard\` to finish setu
432131
432299
  noteEngineTurnStart();
432132
432300
  const sessionId = req.sessionId ?? mockClientIds.sessionId;
432133
432301
  try {
432134
- const submitted = lastProjectableUserMessage(
432135
- params.messages
432136
- );
432302
+ const metaRun = trailingStandaloneMetaUserMessages(params.messages);
432303
+ const submitted = metaRun.length > 0 ? void 0 : lastProjectableUserMessage(params.messages);
432137
432304
  if (submitted && typeof submitted.uuid === "string") recordPendingUserMessage(submitted.uuid);
432138
432305
  if (process.env.SEMA_LIVE_BASEURL) {
432139
432306
  disarmAssistantCommit();
@@ -432341,6 +432508,7 @@ var init_seamQuery = __esm({
432341
432508
  init_engineTarget();
432342
432509
  init_userMessageSelect();
432343
432510
  init_rewindAnchorStore();
432511
+ init_messages3();
432344
432512
  init_sessionStorage();
432345
432513
  init_turnCommitSignal();
432346
432514
  init_mockClient();
@@ -454558,7 +454726,9 @@ var init_init_verifiers = __esm({
454558
454726
  return [
454559
454727
  {
454560
454728
  type: "text",
454561
- text: `Use the TodoWrite tool to track your progress through this multi-step task.
454729
+ // CC209 对表(2026-07-16):交互 roster 的追踪工具是 TaskCreate/TaskUpdate(TodoV2 恒开;
454730
+ // 引擎 core 1.296+ 同款默认,TodoWrite 默认不装载)——别指名模型摸不到的工具。
454731
+ text: `Use the task tracking tools (TaskCreate/TaskUpdate) to track your progress through this multi-step task.
454562
454732
 
454563
454733
  ## Goal
454564
454734
 
@@ -478122,8 +478292,8 @@ var init_sema_brand = __esm({
478122
478292
  "Slash-command gating wired to the fleet capability handshake"
478123
478293
  ]
478124
478294
  },
478125
- productVersion: "1.0.6",
478126
- announcement: "sema 1.0.6 \u2014 custom subagents in .sema/agents/ now run on your chosen model end-to-end, -p exits honestly instead of silently succeeding when a question parks the run, onboarding gets big step titles, and the code scenario (full engineering persona) is the new default"
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"
478127
478297
  };
478128
478298
  }
478129
478299
  });
@@ -481062,8 +481232,8 @@ var require_sema_brand = __commonJS({
481062
481232
  "Slash-command gating wired to the fleet capability handshake"
481063
481233
  ]
481064
481234
  },
481065
- productVersion: "1.0.6",
481066
- announcement: "sema 1.0.6 \u2014 custom subagents in .sema/agents/ now run on your chosen model end-to-end, -p exits honestly instead of silently succeeding when a question parks the run, onboarding gets big step titles, and the code scenario (full engineering persona) is the new default"
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"
481067
481237
  };
481068
481238
  }
481069
481239
  });
@@ -498196,6 +498366,11 @@ var init_thinkback_play2 = __esm({
498196
498366
  });
498197
498367
 
498198
498368
  // build-src/src/utils/autoModeDenials.ts
498369
+ var autoModeDenials_exports = {};
498370
+ __export(autoModeDenials_exports, {
498371
+ getAutoModeDenials: () => getAutoModeDenials,
498372
+ recordAutoModeDenial: () => recordAutoModeDenial
498373
+ });
498199
498374
  function recordAutoModeDenial(denial) {
498200
498375
  if (false) return;
498201
498376
  DENIALS = [denial, ...DENIALS.slice(0, MAX_DENIALS - 1)];
@@ -537607,7 +537782,7 @@ async function* runStreamInner(events3, ctx, handle = {}) {
537607
537782
  }
537608
537783
  if (ev.type === "done" || ev.type === "failed") {
537609
537784
  const failedResult = ev.type === "done" ? ev.result : null;
537610
- 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;
537611
537786
  if (errText) {
537612
537787
  const activeTaskId = failedResult?.activeTaskId ?? (ev.type === "failed" ? ev.activeTaskId : void 0);
537613
537788
  const isActiveRunBusy = errText === "session already has an active run" || typeof activeTaskId === "string";
@@ -537979,7 +538154,7 @@ var init_controlRouter = __esm({
537979
538154
  /** Project the session context + the typed turn into the `@sema-ai` `TaskRequest` wire shape. Secret
537980
538155
  * discipline (types.ts:54-58): NEVER put tokens in `objective`/`systemPrompt`. */
537981
538156
  buildTaskRequest(text2) {
537982
- const req = { objective: text2 };
538157
+ const req = { objective: text2.trim().length > 0 ? text2 : "(no content)" };
537983
538158
  if (this.sessionId !== void 0) req.sessionId = this.sessionId;
537984
538159
  if (this.jobId !== void 0) req.jobId = this.jobId;
537985
538160
  if (this.scenario !== void 0) req.scenario = this.scenario;
@@ -612714,6 +612889,23 @@ var init_processUserInput = __esm({
612714
612889
  }
612715
612890
  });
612716
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
+
612717
612909
  // build-src/src/utils/handlePromptSubmit.ts
612718
612910
  function exit2() {
612719
612911
  gracefulShutdownSync(0);
@@ -612981,6 +613173,15 @@ async function executeUserInput(params) {
612981
613173
  if (m2.type === "user") m2.origin = origin2;
612982
613174
  }
612983
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
+ }
612984
613185
  newMessages.push(...result.messages);
612985
613186
  if (isFirst) {
612986
613187
  shouldQuery = result.shouldQuery;
@@ -620491,8 +620692,8 @@ function _temp161() {
620491
620692
  var import_compiler_runtime316, import_react313, SETTINGS_ERRORS_NOTIFICATION_KEY;
620492
620693
  var init_useSettingsErrors = __esm({
620493
620694
  "build-src/src/hooks/notifs/useSettingsErrors.tsx"() {
620494
- import_compiler_runtime316 = __toESM(require_compiler_runtime());
620495
- import_react313 = __toESM(require_react());
620695
+ import_compiler_runtime316 = __toESM(require_compiler_runtime(), 1);
620696
+ import_react313 = __toESM(require_react(), 1);
620496
620697
  init_notifications();
620497
620698
  init_state();
620498
620699
  init_allErrors();
@@ -640018,6 +640219,88 @@ var init_liveToolApprovalWire = __esm({
640018
640219
  }
640019
640220
  });
640020
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
+
640021
640304
  // build-src/src/sema/liveHitlAskWire.ts
640022
640305
  function rejectMessageForRender() {
640023
640306
  try {
@@ -640242,6 +640525,19 @@ async function* bridgeAskUserQuestionGates(source, deps2, opts) {
640242
640525
  const pi = pendingFsCalls.indexOf(ev.toolCallId);
640243
640526
  if (pi !== -1) pendingFsCalls.splice(pi, 1);
640244
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
+ }
640245
640541
  if (ev.isError === true && typeof ev.toolName === "string" && toolNameIsFsWrite(ev.toolName) && denyStampNextFsEnd && !deniedCalls.has(ev.toolCallId)) {
640246
640542
  denyStampNextFsEnd = false;
640247
640543
  endedCalls.add(ev.toolCallId);
@@ -640368,6 +640664,7 @@ var init_liveHitlAskWire = __esm({
640368
640664
  init_debug();
640369
640665
  init_appStateRef();
640370
640666
  init_liveToolApprovalWire();
640667
+ init_classifierVerdictWire();
640371
640668
  MAX_GATE_HOPS = 24;
640372
640669
  CANCEL_DENY_BUDGET_MS = 2e3;
640373
640670
  CANCEL_DENY_WARN_TEXT = "could not cancel the pending question \u2014 the session may stay locked; the run may need engine-side recovery";
@@ -640696,6 +640993,365 @@ var init_agentsWire = __esm({
640696
640993
  }
640697
640994
  });
640698
640995
 
640996
+ // build-src/src/sema/limitsWire.ts
640997
+ var limitsWire_exports = {};
640998
+ __export(limitsWire_exports, {
640999
+ DEADLINE_SEC_MAX: () => DEADLINE_SEC_MAX,
641000
+ DEADLINE_SEC_MIN: () => DEADLINE_SEC_MIN,
641001
+ HEADLESS_DEADLINE_ENV: () => HEADLESS_DEADLINE_ENV,
641002
+ HEADLESS_MAX_TURNS_ENV: () => HEADLESS_MAX_TURNS_ENV,
641003
+ LIMITS_WIRE_MIN_ENGINE: () => LIMITS_WIRE_MIN_ENGINE,
641004
+ MAX_TURNS_MAX: () => MAX_TURNS_MAX,
641005
+ MAX_TURNS_MIN: () => MAX_TURNS_MIN,
641006
+ engineLimitsSupportWarning: () => engineLimitsSupportWarning,
641007
+ headlessLimitsFromEnv: () => headlessLimitsFromEnv,
641008
+ limitsForPrint: () => limitsForPrint,
641009
+ parseLimitsArgv: () => parseLimitsArgv,
641010
+ versionSupportsLimits: () => versionSupportsLimits
641011
+ });
641012
+ function lastFlagValue(argv, name) {
641013
+ const eq2 = `${name}=`;
641014
+ let present = false;
641015
+ let raw2;
641016
+ let valueMissing = false;
641017
+ for (let i = 0; i < argv.length; i++) {
641018
+ const a = argv[i];
641019
+ if (a === "--") break;
641020
+ if (a === name) {
641021
+ present = true;
641022
+ const nxt = argv[i + 1];
641023
+ if (nxt === void 0 || nxt.startsWith("-")) {
641024
+ valueMissing = true;
641025
+ raw2 = void 0;
641026
+ continue;
641027
+ }
641028
+ valueMissing = false;
641029
+ raw2 = nxt;
641030
+ i++;
641031
+ } else if (a.startsWith(eq2)) {
641032
+ present = true;
641033
+ valueMissing = false;
641034
+ raw2 = a.slice(eq2.length);
641035
+ }
641036
+ }
641037
+ if (present && (valueMissing || raw2 === void 0)) return { present: true };
641038
+ return present ? { present: true, raw: raw2 } : { present: false };
641039
+ }
641040
+ function parseIntInDomain(raw2, min, max2) {
641041
+ const v2 = raw2.trim();
641042
+ if (!INT_RE.test(v2)) return null;
641043
+ const n2 = Number(v2);
641044
+ if (!Number.isSafeInteger(n2) || n2 < min || n2 > max2) return null;
641045
+ return n2;
641046
+ }
641047
+ function parseLimitsArgv(argv) {
641048
+ const limits = {};
641049
+ const flaggedFlags = [];
641050
+ const dl = lastFlagValue(argv, "--deadline");
641051
+ if (dl.present) {
641052
+ const n2 = dl.raw !== void 0 ? parseIntInDomain(dl.raw, DEADLINE_SEC_MIN, DEADLINE_SEC_MAX) : null;
641053
+ if (n2 === null) return { ok: false, error: DEADLINE_USAGE };
641054
+ limits.timeoutSec = n2;
641055
+ flaggedFlags.push("--deadline");
641056
+ }
641057
+ const mt2 = lastFlagValue(argv, "--max-turns");
641058
+ if (mt2.present) {
641059
+ const n2 = mt2.raw !== void 0 ? parseIntInDomain(mt2.raw, MAX_TURNS_MIN, MAX_TURNS_MAX) : null;
641060
+ if (n2 === null) return { ok: false, error: MAX_TURNS_USAGE };
641061
+ limits.maxTurns = n2;
641062
+ flaggedFlags.push("--max-turns");
641063
+ }
641064
+ return {
641065
+ ok: true,
641066
+ ...flaggedFlags.length > 0 ? { limits } : {},
641067
+ flaggedFlags
641068
+ };
641069
+ }
641070
+ function headlessLimitsFromEnv(env5 = process.env) {
641071
+ const out6 = {};
641072
+ const dl = env5[HEADLESS_DEADLINE_ENV]?.trim();
641073
+ if (dl) {
641074
+ const n2 = parseIntInDomain(dl, DEADLINE_SEC_MIN, DEADLINE_SEC_MAX);
641075
+ if (n2 !== null) out6.timeoutSec = n2;
641076
+ else if (env5.SEMA_DEBUG) {
641077
+ console.error(`[sema] ${HEADLESS_DEADLINE_ENV}="${dl}" is not an integer in ${DEADLINE_SEC_MIN}..${DEADLINE_SEC_MAX} \u2014 ignoring the settings default`);
641078
+ }
641079
+ }
641080
+ const mt2 = env5[HEADLESS_MAX_TURNS_ENV]?.trim();
641081
+ if (mt2) {
641082
+ const n2 = parseIntInDomain(mt2, MAX_TURNS_MIN, MAX_TURNS_MAX);
641083
+ if (n2 !== null) out6.maxTurns = n2;
641084
+ else if (env5.SEMA_DEBUG) {
641085
+ console.error(`[sema] ${HEADLESS_MAX_TURNS_ENV}="${mt2}" is not an integer in ${MAX_TURNS_MIN}..${MAX_TURNS_MAX} \u2014 ignoring the settings default`);
641086
+ }
641087
+ }
641088
+ return out6.timeoutSec !== void 0 || out6.maxTurns !== void 0 ? out6 : void 0;
641089
+ }
641090
+ function limitsForPrint(argv, env5 = process.env) {
641091
+ const parsed = parseLimitsArgv(argv);
641092
+ if (!parsed.ok) return parsed;
641093
+ const fromEnv = headlessLimitsFromEnv(env5);
641094
+ const merged = { ...fromEnv ?? {}, ...parsed.limits ?? {} };
641095
+ const any3 = merged.timeoutSec !== void 0 || merged.maxTurns !== void 0;
641096
+ return { ok: true, ...any3 ? { limits: merged } : {}, flaggedFlags: parsed.flaggedFlags };
641097
+ }
641098
+ function versionSupportsLimits(v2) {
641099
+ const m2 = v2 ? /^(\d+)\.(\d+)\.(\d+)/.exec(v2) : null;
641100
+ if (!m2) return false;
641101
+ const [a, b3, c2] = [Number(m2[1]), Number(m2[2]), Number(m2[3])];
641102
+ const [ma, mb, mc] = LIMITS_WIRE_MIN_ENGINE;
641103
+ if (a !== ma) return a > ma;
641104
+ if (b3 !== mb) return b3 > mb;
641105
+ return c2 >= mc;
641106
+ }
641107
+ async function engineLimitsSupportWarning(baseUrl, flaggedFlags, opts) {
641108
+ const fetchImpl = opts?.fetchImpl ?? fetch;
641109
+ const controller = new AbortController();
641110
+ const timer2 = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
641111
+ try {
641112
+ const res = await fetchImpl(`${baseUrl.replace(/\/+$/, "")}/health`, {
641113
+ method: "GET",
641114
+ signal: controller.signal
641115
+ });
641116
+ if (!res.ok) return void 0;
641117
+ const body = await res.json();
641118
+ const version5 = typeof body?.version === "string" ? body.version : void 0;
641119
+ if (versionSupportsLimits(version5)) return void 0;
641120
+ const flags = flaggedFlags.length > 0 ? flaggedFlags.join("/") : "--deadline/--max-turns";
641121
+ return `[sema] engine ${version5 ?? "(unversioned, pre-1.96)"} does not support ${flags} (needs \u22651.196.0); the flag will be ignored by the engine`;
641122
+ } catch {
641123
+ return void 0;
641124
+ } finally {
641125
+ clearTimeout(timer2);
641126
+ }
641127
+ }
641128
+ var HEADLESS_DEADLINE_ENV, HEADLESS_MAX_TURNS_ENV, DEADLINE_SEC_MIN, DEADLINE_SEC_MAX, MAX_TURNS_MIN, MAX_TURNS_MAX, LIMITS_WIRE_MIN_ENGINE, DEADLINE_USAGE, MAX_TURNS_USAGE, INT_RE;
641129
+ var init_limitsWire = __esm({
641130
+ "build-src/src/sema/limitsWire.ts"() {
641131
+ HEADLESS_DEADLINE_ENV = "SEMA_HEADLESS_DEADLINE_SEC";
641132
+ HEADLESS_MAX_TURNS_ENV = "SEMA_HEADLESS_MAX_TURNS";
641133
+ DEADLINE_SEC_MIN = 30;
641134
+ DEADLINE_SEC_MAX = 86400;
641135
+ MAX_TURNS_MIN = 1;
641136
+ MAX_TURNS_MAX = 1e3;
641137
+ LIMITS_WIRE_MIN_ENGINE = [1, 196, 0];
641138
+ DEADLINE_USAGE = `sema: --deadline expects a whole number of seconds between ${DEADLINE_SEC_MIN} and ${DEADLINE_SEC_MAX}.
641139
+ --deadline <sec> soft wall-clock budget for this run (sema superset \u2014 no upstream equivalent):
641140
+ the engine paces itself (nudges + call caps) and finalizes gracefully near the deadline
641141
+ (no flag) no deadline \u2014 today's behaviour`;
641142
+ MAX_TURNS_USAGE = `sema: --max-turns expects a whole number of turns between ${MAX_TURNS_MIN} and ${MAX_TURNS_MAX}.
641143
+ --max-turns <n> maximum number of agentic turns for this run (upstream-aligned flag,
641144
+ enforced engine-side on the sema seam)
641145
+ (no flag) no turn cap \u2014 today's behaviour`;
641146
+ INT_RE = /^\d+$/;
641147
+ }
641148
+ });
641149
+
641150
+ // build-src/src/sema/detachWire.ts
641151
+ var detachWire_exports = {};
641152
+ __export(detachWire_exports, {
641153
+ DETACH_DURABLE_OFF_400_ANCHOR: () => DETACH_DURABLE_OFF_400_ANCHOR,
641154
+ DETACH_HEADER: () => DETACH_HEADER,
641155
+ DETACH_WIRE_MIN_ENGINE: () => DETACH_WIRE_MIN_ENGINE,
641156
+ HEADLESS_DETACH_ENV: () => HEADLESS_DETACH_ENV,
641157
+ _resetDetachWireForTest: () => _resetDetachWireForTest,
641158
+ armDetachCancel: () => armDetachCancel,
641159
+ detachDurableOffHint: () => detachDurableOffHint,
641160
+ detachedTaskId: () => detachedTaskId,
641161
+ engineSupportsDetach: () => engineSupportsDetach,
641162
+ fireBestEffortDetachCancel: () => fireBestEffortDetachCancel,
641163
+ headlessDetachDisabledByEnv: () => headlessDetachDisabledByEnv,
641164
+ isDetachArmed: () => isDetachArmed,
641165
+ resolveHeadlessDetach: () => resolveHeadlessDetach,
641166
+ versionSupportsDetach: () => versionSupportsDetach
641167
+ });
641168
+ function headlessDetachDisabledByEnv(env5 = process.env) {
641169
+ const v2 = env5[HEADLESS_DETACH_ENV]?.trim().toLowerCase();
641170
+ return v2 === "false" || v2 === "0";
641171
+ }
641172
+ async function engineSupportsDetach(baseUrl, opts) {
641173
+ const fetchImpl = opts?.fetchImpl ?? fetch;
641174
+ const controller = new AbortController();
641175
+ const timer2 = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
641176
+ try {
641177
+ const res = await fetchImpl(`${baseUrl.replace(/\/+$/, "")}/health`, {
641178
+ method: "GET",
641179
+ signal: controller.signal
641180
+ });
641181
+ if (!res.ok) return true;
641182
+ const body = await res.json();
641183
+ const version5 = typeof body?.version === "string" ? body.version : void 0;
641184
+ return versionSupportsDetach(version5);
641185
+ } catch {
641186
+ return true;
641187
+ } finally {
641188
+ clearTimeout(timer2);
641189
+ }
641190
+ }
641191
+ async function resolveHeadlessDetach(baseUrl, env5 = process.env, opts) {
641192
+ if (headlessDetachDisabledByEnv(env5)) return { on: false, reason: "env-off" };
641193
+ if (env5.SEMA_ENGINE_URL) {
641194
+ const ok2 = await engineSupportsDetach(baseUrl, opts);
641195
+ if (!ok2) return { on: false, reason: "old-engine" };
641196
+ }
641197
+ return { on: true, reason: "default-on" };
641198
+ }
641199
+ function detachDurableOffHint(err8) {
641200
+ if (!isDetachArmed()) return null;
641201
+ const e = err8;
641202
+ if (e?.status !== 400) return null;
641203
+ const msg = typeof e?.message === "string" ? e.message : "";
641204
+ if (!msg.includes(DETACH_DURABLE_OFF_400_ANCHOR)) return null;
641205
+ return "engine has durable runs disabled \u2014 detach-on-disconnect unavailable; interrupted turns will abort (SEMA_HEADLESS_DETACH=false to silence)";
641206
+ }
641207
+ function armDetachCancel(arm) {
641208
+ cancelArm = arm;
641209
+ }
641210
+ function isDetachArmed() {
641211
+ return cancelArm !== null;
641212
+ }
641213
+ function detachedTaskId() {
641214
+ return cancelArm?.getTaskId() ?? null;
641215
+ }
641216
+ function _resetDetachWireForTest() {
641217
+ cancelArm = null;
641218
+ }
641219
+ function fireBestEffortDetachCancel(fetchImpl = fetch) {
641220
+ const arm = cancelArm;
641221
+ if (!arm) return false;
641222
+ const taskId = arm.getTaskId();
641223
+ if (!taskId) return false;
641224
+ try {
641225
+ const controller = new AbortController();
641226
+ const timer2 = setTimeout(() => controller.abort(), 1500);
641227
+ timer2.unref?.();
641228
+ void fetchImpl(`${arm.baseUrl.replace(/\/+$/, "")}/v1/runs/${encodeURIComponent(taskId)}/cancel`, {
641229
+ method: "POST",
641230
+ headers: {
641231
+ authorization: `Bearer ${arm.authToken}`,
641232
+ "x-agent-principal": arm.principal
641233
+ },
641234
+ signal: controller.signal
641235
+ }).catch(() => {
641236
+ }).finally(() => clearTimeout(timer2));
641237
+ return true;
641238
+ } catch {
641239
+ return false;
641240
+ }
641241
+ }
641242
+ var DETACH_HEADER, HEADLESS_DETACH_ENV, DETACH_WIRE_MIN_ENGINE, versionSupportsDetach, DETACH_DURABLE_OFF_400_ANCHOR, cancelArm;
641243
+ var init_detachWire = __esm({
641244
+ "build-src/src/sema/detachWire.ts"() {
641245
+ init_limitsWire();
641246
+ DETACH_HEADER = "x-detach-on-disconnect";
641247
+ HEADLESS_DETACH_ENV = "SEMA_HEADLESS_DETACH";
641248
+ DETACH_WIRE_MIN_ENGINE = [1, 196, 0];
641249
+ versionSupportsDetach = versionSupportsLimits;
641250
+ DETACH_DURABLE_OFF_400_ANCHOR = "x-detach-on-disconnect requires a durable run";
641251
+ cancelArm = null;
641252
+ }
641253
+ });
641254
+
641255
+ // build-src/src/sema/headlessReconnectWire.ts
641256
+ function debugLog(msg) {
641257
+ if (process.env.SEMA_DEBUG) {
641258
+ console.error(`[sema] headless reconnect: ${msg}`);
641259
+ }
641260
+ }
641261
+ function terminalEventFromRunRow(row2) {
641262
+ if (!row2 || typeof row2.status !== "string") return null;
641263
+ if (RUN_ROW_TERMINAL_STATUSES.has(row2.status)) {
641264
+ if (row2.result && typeof row2.result === "object") {
641265
+ return { type: "done", result: row2.result };
641266
+ }
641267
+ if (row2.status === "failed") {
641268
+ return {
641269
+ type: "failed",
641270
+ ...row2.errorCode ? { errorCode: row2.errorCode } : {},
641271
+ errorMessage: row2.error ?? "run failed"
641272
+ };
641273
+ }
641274
+ }
641275
+ return null;
641276
+ }
641277
+ async function* withHeadlessR1Reconnect(live, deps2) {
641278
+ let originalTearErr;
641279
+ try {
641280
+ for await (const ev of live) {
641281
+ yield ev;
641282
+ const t2 = ev?.type;
641283
+ if (t2 === "done" || t2 === "failed") return;
641284
+ }
641285
+ return;
641286
+ } catch (e) {
641287
+ originalTearErr = e;
641288
+ }
641289
+ let attempts = 0;
641290
+ let lastSeenSeq;
641291
+ const probe3 = deps2.probeAlive ?? probeEngineAlive;
641292
+ for (; ; ) {
641293
+ if (deps2.signal?.aborted) throw originalTearErr;
641294
+ if (!isSseIdleError(originalTearErr)) throw originalTearErr;
641295
+ const taskId = deps2.getTaskId();
641296
+ if (!taskId) throw originalTearErr;
641297
+ if (attempts >= HEADLESS_RECONNECT_MAX) {
641298
+ debugLog(`budget exhausted (${attempts}/${HEADLESS_RECONNECT_MAX}) \u2014 falling to the honest death path`);
641299
+ throw originalTearErr;
641300
+ }
641301
+ attempts++;
641302
+ if (!await probe3(deps2.baseUrl)) throw originalTearErr;
641303
+ debugLog(`attempt ${attempts}/${HEADLESS_RECONNECT_MAX} \u2014 switching to runs.events(${taskId}${lastSeenSeq !== void 0 ? `, Last-Event-ID ${lastSeenSeq}` : ""})`);
641304
+ try {
641305
+ const cont = deps2.openEvents(taskId, lastSeenSeq !== void 0 ? String(lastSeenSeq) : void 0);
641306
+ for await (const ev of cont) {
641307
+ if (deps2.signal?.aborted) return;
641308
+ const rec = ev;
641309
+ const t2 = rec?.type;
641310
+ if (t2 === void 0) continue;
641311
+ if (t2 === "error") {
641312
+ debugLog(`runs.events lane frame type=error code=${String(rec?.code ?? "")} \u2014 SDK resumes with Last-Event-ID internally`);
641313
+ continue;
641314
+ }
641315
+ const seq = typeof rec?.id === "string" && /^\d+$/.test(rec.id) ? Number(rec.id) : void 0;
641316
+ if (seq !== void 0) {
641317
+ if (lastSeenSeq !== void 0 && seq <= lastSeenSeq) continue;
641318
+ lastSeenSeq = seq;
641319
+ }
641320
+ if (t2 === "done" || t2 === "failed") debugLog(`resumed to terminal (${String(t2)}) after ${attempts} reconnect(s)`);
641321
+ yield ev;
641322
+ if (t2 === "done" || t2 === "failed") return;
641323
+ }
641324
+ if (deps2.signal?.aborted) return;
641325
+ debugLog("runs.events continuation ended without a terminal frame");
641326
+ } catch (contErr) {
641327
+ debugLog(`runs.events continuation failed: ${contErr instanceof Error ? contErr.message : String(contErr)}`);
641328
+ if (deps2.signal?.aborted) throw originalTearErr;
641329
+ const row2 = await deps2.getRun(taskId).catch(() => null);
641330
+ const terminal = terminalEventFromRunRow(row2);
641331
+ if (terminal) {
641332
+ debugLog(`run row terminal (${String(row2?.status)}) \u2014 synthesizing the terminal frame (R1b)`);
641333
+ yield terminal;
641334
+ return;
641335
+ }
641336
+ }
641337
+ }
641338
+ }
641339
+ var HEADLESS_RECONNECT_MAX, RUN_ROW_TERMINAL_STATUSES;
641340
+ var init_headlessReconnectWire = __esm({
641341
+ "build-src/src/sema/headlessReconnectWire.ts"() {
641342
+ init_sseIdleTriage();
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
+ ]);
641352
+ }
641353
+ });
641354
+
640699
641355
  // build-src/src/sema/liveClient.ts
640700
641356
  var liveClient_exports = {};
640701
641357
  __export(liveClient_exports, {
@@ -640863,6 +641519,7 @@ function createLiveConversationClient(config5) {
640863
641519
  stream(req, opts) {
640864
641520
  const open20 = () => {
640865
641521
  let headerAcquired = false;
641522
+ let earlyTaskId = null;
640866
641523
  const heartbeatGraceMs = resolveSseHeartbeatGraceMs();
640867
641524
  const live = client4.tasks.stream(toLiveRequest(req, getLiveSessionId()), {
640868
641525
  ...opts,
@@ -640875,6 +641532,7 @@ function createLiveConversationClient(config5) {
640875
641532
  const early = res.headers?.get?.("x-task-id");
640876
641533
  if (typeof early === "string" && early.length > 0) {
640877
641534
  headerAcquired = true;
641535
+ earlyTaskId = early;
640878
641536
  bindTaskIdEarly(early);
640879
641537
  persistEngineTaskId(early);
640880
641538
  setActiveEngineTaskId(early);
@@ -640885,13 +641543,29 @@ function createLiveConversationClient(config5) {
640885
641543
  }
640886
641544
  }
640887
641545
  });
641546
+ const source = opts?.headers?.[DETACH_HEADER] === "true" ? withHeadlessR1Reconnect(live, {
641547
+ baseUrl: baseUrlTrimmed,
641548
+ getTaskId: () => earlyTaskId,
641549
+ openEvents: (taskId, lastEventId) => client4.runs.events(taskId, {
641550
+ ...lastEventId !== void 0 ? { lastEventId } : {},
641551
+ ...opts?.signal ? { signal: opts.signal } : {}
641552
+ }),
641553
+ getRun: async (taskId) => {
641554
+ try {
641555
+ return await client4.runs.get(taskId, opts?.signal ? { signal: opts.signal } : void 0);
641556
+ } catch {
641557
+ return null;
641558
+ }
641559
+ },
641560
+ ...opts?.signal ? { signal: opts.signal } : {}
641561
+ }) : live;
640888
641562
  return diagnoseSseIdleTear(
640889
641563
  normalizeToolNames(
640890
641564
  captureSessionId(
640891
641565
  // §4④ engine 1.163 — AskUserQuestion parks the run `suspended` (no `question` frames anymore);
640892
641566
  // the bridge turns that park into dialog → approvals.decide → runs.events continuation, INSIDE
640893
641567
  // this same generator, so the turn keeps flowing to its real terminal (liveHitlAskWire.ts).
640894
- bridgeAskUserQuestionGates(demuxQuestionFrames(live), hitlDeps, {
641568
+ bridgeAskUserQuestionGates(demuxQuestionFrames(source), hitlDeps, {
640895
641569
  ...opts?.signal ? { signal: opts.signal } : {}
640896
641570
  }),
640897
641571
  (sid) => {
@@ -640990,6 +641664,8 @@ var init_liveClient = __esm({
640990
641664
  init_appStateRef();
640991
641665
  init_sseIdleTriage();
640992
641666
  init_agentsWire();
641667
+ init_detachWire();
641668
+ init_headlessReconnectWire();
640993
641669
  init_mockClient();
640994
641670
  ENGINE_TO_CC_TOOL = {
640995
641671
  bash: "Bash",
@@ -641168,160 +641844,6 @@ var init_finalVerifyWire = __esm({
641168
641844
  }
641169
641845
  });
641170
641846
 
641171
- // build-src/src/sema/limitsWire.ts
641172
- var limitsWire_exports = {};
641173
- __export(limitsWire_exports, {
641174
- DEADLINE_SEC_MAX: () => DEADLINE_SEC_MAX,
641175
- DEADLINE_SEC_MIN: () => DEADLINE_SEC_MIN,
641176
- HEADLESS_DEADLINE_ENV: () => HEADLESS_DEADLINE_ENV,
641177
- HEADLESS_MAX_TURNS_ENV: () => HEADLESS_MAX_TURNS_ENV,
641178
- LIMITS_WIRE_MIN_ENGINE: () => LIMITS_WIRE_MIN_ENGINE,
641179
- MAX_TURNS_MAX: () => MAX_TURNS_MAX,
641180
- MAX_TURNS_MIN: () => MAX_TURNS_MIN,
641181
- engineLimitsSupportWarning: () => engineLimitsSupportWarning,
641182
- headlessLimitsFromEnv: () => headlessLimitsFromEnv,
641183
- limitsForPrint: () => limitsForPrint,
641184
- parseLimitsArgv: () => parseLimitsArgv,
641185
- versionSupportsLimits: () => versionSupportsLimits
641186
- });
641187
- function lastFlagValue(argv, name) {
641188
- const eq2 = `${name}=`;
641189
- let present = false;
641190
- let raw2;
641191
- let valueMissing = false;
641192
- for (let i = 0; i < argv.length; i++) {
641193
- const a = argv[i];
641194
- if (a === "--") break;
641195
- if (a === name) {
641196
- present = true;
641197
- const nxt = argv[i + 1];
641198
- if (nxt === void 0 || nxt.startsWith("-")) {
641199
- valueMissing = true;
641200
- raw2 = void 0;
641201
- continue;
641202
- }
641203
- valueMissing = false;
641204
- raw2 = nxt;
641205
- i++;
641206
- } else if (a.startsWith(eq2)) {
641207
- present = true;
641208
- valueMissing = false;
641209
- raw2 = a.slice(eq2.length);
641210
- }
641211
- }
641212
- if (present && (valueMissing || raw2 === void 0)) return { present: true };
641213
- return present ? { present: true, raw: raw2 } : { present: false };
641214
- }
641215
- function parseIntInDomain(raw2, min, max2) {
641216
- const v2 = raw2.trim();
641217
- if (!INT_RE.test(v2)) return null;
641218
- const n2 = Number(v2);
641219
- if (!Number.isSafeInteger(n2) || n2 < min || n2 > max2) return null;
641220
- return n2;
641221
- }
641222
- function parseLimitsArgv(argv) {
641223
- const limits = {};
641224
- const flaggedFlags = [];
641225
- const dl = lastFlagValue(argv, "--deadline");
641226
- if (dl.present) {
641227
- const n2 = dl.raw !== void 0 ? parseIntInDomain(dl.raw, DEADLINE_SEC_MIN, DEADLINE_SEC_MAX) : null;
641228
- if (n2 === null) return { ok: false, error: DEADLINE_USAGE };
641229
- limits.timeoutSec = n2;
641230
- flaggedFlags.push("--deadline");
641231
- }
641232
- const mt2 = lastFlagValue(argv, "--max-turns");
641233
- if (mt2.present) {
641234
- const n2 = mt2.raw !== void 0 ? parseIntInDomain(mt2.raw, MAX_TURNS_MIN, MAX_TURNS_MAX) : null;
641235
- if (n2 === null) return { ok: false, error: MAX_TURNS_USAGE };
641236
- limits.maxTurns = n2;
641237
- flaggedFlags.push("--max-turns");
641238
- }
641239
- return {
641240
- ok: true,
641241
- ...flaggedFlags.length > 0 ? { limits } : {},
641242
- flaggedFlags
641243
- };
641244
- }
641245
- function headlessLimitsFromEnv(env5 = process.env) {
641246
- const out6 = {};
641247
- const dl = env5[HEADLESS_DEADLINE_ENV]?.trim();
641248
- if (dl) {
641249
- const n2 = parseIntInDomain(dl, DEADLINE_SEC_MIN, DEADLINE_SEC_MAX);
641250
- if (n2 !== null) out6.timeoutSec = n2;
641251
- else if (env5.SEMA_DEBUG) {
641252
- console.error(`[sema] ${HEADLESS_DEADLINE_ENV}="${dl}" is not an integer in ${DEADLINE_SEC_MIN}..${DEADLINE_SEC_MAX} \u2014 ignoring the settings default`);
641253
- }
641254
- }
641255
- const mt2 = env5[HEADLESS_MAX_TURNS_ENV]?.trim();
641256
- if (mt2) {
641257
- const n2 = parseIntInDomain(mt2, MAX_TURNS_MIN, MAX_TURNS_MAX);
641258
- if (n2 !== null) out6.maxTurns = n2;
641259
- else if (env5.SEMA_DEBUG) {
641260
- console.error(`[sema] ${HEADLESS_MAX_TURNS_ENV}="${mt2}" is not an integer in ${MAX_TURNS_MIN}..${MAX_TURNS_MAX} \u2014 ignoring the settings default`);
641261
- }
641262
- }
641263
- return out6.timeoutSec !== void 0 || out6.maxTurns !== void 0 ? out6 : void 0;
641264
- }
641265
- function limitsForPrint(argv, env5 = process.env) {
641266
- const parsed = parseLimitsArgv(argv);
641267
- if (!parsed.ok) return parsed;
641268
- const fromEnv = headlessLimitsFromEnv(env5);
641269
- const merged = { ...fromEnv ?? {}, ...parsed.limits ?? {} };
641270
- const any3 = merged.timeoutSec !== void 0 || merged.maxTurns !== void 0;
641271
- return { ok: true, ...any3 ? { limits: merged } : {}, flaggedFlags: parsed.flaggedFlags };
641272
- }
641273
- function versionSupportsLimits(v2) {
641274
- const m2 = v2 ? /^(\d+)\.(\d+)\.(\d+)/.exec(v2) : null;
641275
- if (!m2) return false;
641276
- const [a, b3, c2] = [Number(m2[1]), Number(m2[2]), Number(m2[3])];
641277
- const [ma, mb, mc] = LIMITS_WIRE_MIN_ENGINE;
641278
- if (a !== ma) return a > ma;
641279
- if (b3 !== mb) return b3 > mb;
641280
- return c2 >= mc;
641281
- }
641282
- async function engineLimitsSupportWarning(baseUrl, flaggedFlags, opts) {
641283
- const fetchImpl = opts?.fetchImpl ?? fetch;
641284
- const controller = new AbortController();
641285
- const timer2 = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
641286
- try {
641287
- const res = await fetchImpl(`${baseUrl.replace(/\/+$/, "")}/health`, {
641288
- method: "GET",
641289
- signal: controller.signal
641290
- });
641291
- if (!res.ok) return void 0;
641292
- const body = await res.json();
641293
- const version5 = typeof body?.version === "string" ? body.version : void 0;
641294
- if (versionSupportsLimits(version5)) return void 0;
641295
- const flags = flaggedFlags.length > 0 ? flaggedFlags.join("/") : "--deadline/--max-turns";
641296
- return `[sema] engine ${version5 ?? "(unversioned, pre-1.96)"} does not support ${flags} (needs \u22651.196.0); the flag will be ignored by the engine`;
641297
- } catch {
641298
- return void 0;
641299
- } finally {
641300
- clearTimeout(timer2);
641301
- }
641302
- }
641303
- var HEADLESS_DEADLINE_ENV, HEADLESS_MAX_TURNS_ENV, DEADLINE_SEC_MIN, DEADLINE_SEC_MAX, MAX_TURNS_MIN, MAX_TURNS_MAX, LIMITS_WIRE_MIN_ENGINE, DEADLINE_USAGE, MAX_TURNS_USAGE, INT_RE;
641304
- var init_limitsWire = __esm({
641305
- "build-src/src/sema/limitsWire.ts"() {
641306
- HEADLESS_DEADLINE_ENV = "SEMA_HEADLESS_DEADLINE_SEC";
641307
- HEADLESS_MAX_TURNS_ENV = "SEMA_HEADLESS_MAX_TURNS";
641308
- DEADLINE_SEC_MIN = 30;
641309
- DEADLINE_SEC_MAX = 86400;
641310
- MAX_TURNS_MIN = 1;
641311
- MAX_TURNS_MAX = 1e3;
641312
- LIMITS_WIRE_MIN_ENGINE = [1, 196, 0];
641313
- DEADLINE_USAGE = `sema: --deadline expects a whole number of seconds between ${DEADLINE_SEC_MIN} and ${DEADLINE_SEC_MAX}.
641314
- --deadline <sec> soft wall-clock budget for this run (sema superset \u2014 no upstream equivalent):
641315
- the engine paces itself (nudges + call caps) and finalizes gracefully near the deadline
641316
- (no flag) no deadline \u2014 today's behaviour`;
641317
- MAX_TURNS_USAGE = `sema: --max-turns expects a whole number of turns between ${MAX_TURNS_MIN} and ${MAX_TURNS_MAX}.
641318
- --max-turns <n> maximum number of agentic turns for this run (upstream-aligned flag,
641319
- enforced engine-side on the sema seam)
641320
- (no flag) no turn cap \u2014 today's behaviour`;
641321
- INT_RE = /^\d+$/;
641322
- }
641323
- });
641324
-
641325
641847
  // build-src/src/sema/headlessPermissionModeWire.ts
641326
641848
  var headlessPermissionModeWire_exports = {};
641327
641849
  __export(headlessPermissionModeWire_exports, {
@@ -641388,114 +641910,67 @@ var init_headlessPermissionModeWire = __esm({
641388
641910
  "default",
641389
641911
  "plan",
641390
641912
  "acceptEdits",
641391
- "bypassPermissions"
641913
+ "bypassPermissions",
641914
+ "auto"
641392
641915
  ];
641393
641916
  warnedInvalidEnv = false;
641394
641917
  }
641395
641918
  });
641396
641919
 
641397
- // build-src/src/sema/detachWire.ts
641398
- var detachWire_exports = {};
641399
- __export(detachWire_exports, {
641400
- DETACH_DURABLE_OFF_400_ANCHOR: () => DETACH_DURABLE_OFF_400_ANCHOR,
641401
- DETACH_HEADER: () => DETACH_HEADER,
641402
- DETACH_WIRE_MIN_ENGINE: () => DETACH_WIRE_MIN_ENGINE,
641403
- HEADLESS_DETACH_ENV: () => HEADLESS_DETACH_ENV,
641404
- _resetDetachWireForTest: () => _resetDetachWireForTest,
641405
- armDetachCancel: () => armDetachCancel,
641406
- detachDurableOffHint: () => detachDurableOffHint,
641407
- detachedTaskId: () => detachedTaskId,
641408
- engineSupportsDetach: () => engineSupportsDetach,
641409
- fireBestEffortDetachCancel: () => fireBestEffortDetachCancel,
641410
- headlessDetachDisabledByEnv: () => headlessDetachDisabledByEnv,
641411
- isDetachArmed: () => isDetachArmed,
641412
- resolveHeadlessDetach: () => resolveHeadlessDetach,
641413
- versionSupportsDetach: () => versionSupportsDetach
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
641414
641927
  });
641415
- function headlessDetachDisabledByEnv(env5 = process.env) {
641416
- const v2 = env5[HEADLESS_DETACH_ENV]?.trim().toLowerCase();
641417
- return v2 === "false" || v2 === "0";
641418
- }
641419
- async function engineSupportsDetach(baseUrl, opts) {
641420
- const fetchImpl = opts?.fetchImpl ?? fetch;
641421
- const controller = new AbortController();
641422
- const timer2 = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
641423
- try {
641424
- const res = await fetchImpl(`${baseUrl.replace(/\/+$/, "")}/health`, {
641425
- method: "GET",
641426
- signal: controller.signal
641427
- });
641428
- if (!res.ok) return true;
641429
- const body = await res.json();
641430
- const version5 = typeof body?.version === "string" ? body.version : void 0;
641431
- return versionSupportsDetach(version5);
641432
- } catch {
641433
- return true;
641434
- } finally {
641435
- clearTimeout(timer2);
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
+ }
641436
641943
  }
641944
+ return mode === "plan";
641437
641945
  }
641438
- async function resolveHeadlessDetach(baseUrl, env5 = process.env, opts) {
641439
- if (headlessDetachDisabledByEnv(env5)) return { on: false, reason: "env-off" };
641440
- if (env5.SEMA_ENGINE_URL) {
641441
- const ok2 = await engineSupportsDetach(baseUrl, opts);
641442
- if (!ok2) return { on: false, reason: "old-engine" };
641946
+ function resolveHeadlessInteractiveTools(argv, env5 = process.env) {
641947
+ if (planModeExplicitlyRequested(argv)) {
641948
+ return { fields: {}, source: "plan-flag" };
641443
641949
  }
641444
- return { on: true, reason: "default-on" };
641445
- }
641446
- function detachDurableOffHint(err8) {
641447
- if (!isDetachArmed()) return null;
641448
- const e = err8;
641449
- if (e?.status !== 400) return null;
641450
- const msg = typeof e?.message === "string" ? e.message : "";
641451
- if (!msg.includes(DETACH_DURABLE_OFF_400_ANCHOR)) return null;
641452
- return "engine has durable runs disabled \u2014 detach-on-disconnect unavailable; interrupted turns will abort (SEMA_HEADLESS_DETACH=false to silence)";
641453
- }
641454
- function armDetachCancel(arm) {
641455
- cancelArm = arm;
641456
- }
641457
- function isDetachArmed() {
641458
- return cancelArm !== null;
641459
- }
641460
- function detachedTaskId() {
641461
- return cancelArm?.getTaskId() ?? null;
641462
- }
641463
- function _resetDetachWireForTest() {
641464
- cancelArm = null;
641465
- }
641466
- function fireBestEffortDetachCancel(fetchImpl = fetch) {
641467
- const arm = cancelArm;
641468
- if (!arm) return false;
641469
- const taskId = arm.getTaskId();
641470
- if (!taskId) return false;
641471
- try {
641472
- const controller = new AbortController();
641473
- const timer2 = setTimeout(() => controller.abort(), 1500);
641474
- timer2.unref?.();
641475
- void fetchImpl(`${arm.baseUrl.replace(/\/+$/, "")}/v1/runs/${encodeURIComponent(taskId)}/cancel`, {
641476
- method: "POST",
641477
- headers: {
641478
- authorization: `Bearer ${arm.authToken}`,
641479
- "x-agent-principal": arm.principal
641480
- },
641481
- signal: controller.signal
641482
- }).catch(() => {
641483
- }).finally(() => clearTimeout(timer2));
641484
- return true;
641485
- } catch {
641486
- return false;
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;
641487
641963
  }
641964
+ return { fields: { interactiveTools: false }, source: "default" };
641488
641965
  }
641489
- var DETACH_HEADER, HEADLESS_DETACH_ENV, DETACH_WIRE_MIN_ENGINE, versionSupportsDetach, DETACH_DURABLE_OFF_400_ANCHOR, cancelArm;
641490
- var init_detachWire = __esm({
641491
- "build-src/src/sema/detachWire.ts"() {
641492
- init_limitsWire();
641493
- DETACH_HEADER = "x-detach-on-disconnect";
641494
- HEADLESS_DETACH_ENV = "SEMA_HEADLESS_DETACH";
641495
- DETACH_WIRE_MIN_ENGINE = [1, 196, 0];
641496
- versionSupportsDetach = versionSupportsLimits;
641497
- DETACH_DURABLE_OFF_400_ANCHOR = "x-detach-on-disconnect requires a durable run";
641498
- cancelArm = null;
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;
641499
641974
  }
641500
641975
  });
641501
641976
 
@@ -641750,6 +642225,62 @@ var init_printStreamJsonContract = __esm({
641750
642225
  }
641751
642226
  });
641752
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
+
641753
642284
  // build-src/src/sema/seamQueryEngine.ts
641754
642285
  var seamQueryEngine_exports = {};
641755
642286
  __export(seamQueryEngine_exports, {
@@ -641827,7 +642358,8 @@ async function* ask(params) {
641827
642358
  );
641828
642359
  process.exit(1);
641829
642360
  }
641830
- const objective = promptToObjective(params?.prompt);
642361
+ const rawObjective = promptToObjective(params?.prompt);
642362
+ const objective = rawObjective.trim().length > 0 ? rawObjective : "(no content)";
641831
642363
  const webSearch = process.env.SEMA_LIVE_BASEURL ? webSearchFromEnv() : void 0;
641832
642364
  if (webSearch && process.env.SEMA_DEBUG) {
641833
642365
  console.error(
@@ -641956,6 +642488,24 @@ async function* ask(params) {
641956
642488
  if (process.env.SEMA_DEBUG) console.error("[sema] print-mode ask permission wire soft-failed:", ePerm);
641957
642489
  }
641958
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
+ }
641959
642509
  let detachHeaders;
641960
642510
  if (process.env.SEMA_LIVE_BASEURL) {
641961
642511
  try {
@@ -642004,6 +642554,9 @@ async function* ask(params) {
642004
642554
  ...sandboxFields,
642005
642555
  // SEMA_HEADLESS_PERMISSION_MODE 旋钮(flag > env > absent;live-gated;空 = 现状 absent-mode)。
642006
642556
  ...headlessPermissionField,
642557
+ // [909]B 件3:interactiveTools:false(live-gated;SDK TaskRequest 类型暂无此字段 ——
642558
+ // limits/finalVerification 同款短期窄 cast;server 白名单半场已另行派单)。
642559
+ ...interactiveToolsField.interactiveTools === false ? { interactiveTools: false } : {},
642007
642560
  ...webSearch || wireHooks ? { settings: { ...webSearch ? { webSearch } : {}, ...wireHooks ? { hooks: wireHooks } : {} } } : {},
642008
642561
  ...selfOrchestration ? { selfOrchestration } : {},
642009
642562
  ...enableFork !== void 0 ? { enableFork } : {},
@@ -642027,7 +642580,13 @@ async function* ask(params) {
642027
642580
  for await (const msg of sdk) {
642028
642581
  if (signal?.aborted) break;
642029
642582
  const t2 = msg.type;
642030
- 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") {
642031
642590
  continue;
642032
642591
  }
642033
642592
  if (t2 === "workflow_complete") {
@@ -642133,6 +642692,17 @@ async function* ask(params) {
642133
642692
  }
642134
642693
  } catch {
642135
642694
  }
642695
+ try {
642696
+ const { activeEnginePin: activeEnginePin2, enginePinUnreachableHint: enginePinUnreachableHint2, isEngineTransportError: isEngineTransportError2 } = await Promise.resolve().then(() => (init_engineTarget(), engineTarget_exports));
642697
+ const { engineAliveIdleElapsedMs: engineAliveIdleElapsedMs2 } = await Promise.resolve().then(() => (init_sseIdleTriage(), sseIdleTriage_exports));
642698
+ if (engineAliveIdleElapsedMs2(streamErr) === void 0 && isEngineTransportError2(streamErr)) {
642699
+ const pin = activeEnginePin2();
642700
+ if (pin) {
642701
+ console.error(enginePinUnreachableHint2(pin));
642702
+ }
642703
+ }
642704
+ } catch {
642705
+ }
642136
642706
  try {
642137
642707
  const dw = await Promise.resolve().then(() => (init_detachWire(), detachWire_exports));
642138
642708
  const dHint = dw.detachDurableOffHint(streamErr);
@@ -645684,6 +646254,8 @@ Startup time: ${Math.round(process.uptime() * 1e3)}ms
645684
646254
  if (options.outputFormat === "stream-json") {
645685
646255
  installStreamJsonSignalTailFrame();
645686
646256
  }
646257
+ const { setPipedStdoutBlocking: setPipedStdoutBlocking2 } = await Promise.resolve().then(() => (init_stdoutDrain(), stdoutDrain_exports));
646258
+ setPipedStdoutBlocking2();
645687
646259
  if (false) {
645688
646260
  void downloadUserSettings();
645689
646261
  }
@@ -646009,16 +646581,22 @@ Error: sandbox required but unavailable: ${sandboxUnavailableReason}
646009
646581
  );
646010
646582
  break;
646011
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)。
646012
646588
  case "error_max_turns":
646013
- writeToStdout(`Error: Reached max turns (${options.maxTurns})`);
646014
- break;
646015
646589
  case "error_max_budget_usd":
646016
- 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");
646017
646598
  break;
646018
- case "error_max_structured_output_retries":
646019
- writeToStdout(
646020
- `Error: Failed to provide valid structured output after maximum retries`
646021
- );
646599
+ }
646022
646600
  }
646023
646601
  }
646024
646602
  logHeadlessProfilerTurn();
@@ -666083,7 +666661,7 @@ Auth: unix socket -R \u2192 local proxy`, "info");
666083
666661
  pendingHookMessages
666084
666662
  }, renderAndRun);
666085
666663
  }
666086
- }).version("sema 1.0.6", "-v, --version", "Output the version number");
666664
+ }).version("sema 1.0.8", "-v, --version", "Output the version number");
666087
666665
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
666088
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.");
666089
666667
  if (canUserConfigureAdvisor()) {
@@ -669964,6 +670542,21 @@ var init_node4 = __esm({
669964
670542
  }
669965
670543
  });
669966
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
+
669967
670560
  // build-src/src/sema/scheduler/schedulerDaemonWire.ts
669968
670561
  import { join as join201 } from "node:path";
669969
670562
  import { homedir as homedir57 } from "node:os";
@@ -669980,6 +670573,7 @@ var init_schedulerDaemonWire = __esm({
669980
670573
  "build-src/src/sema/scheduler/schedulerDaemonWire.ts"() {
669981
670574
  init_node4();
669982
670575
  init_schedulerDaemon();
670576
+ init_firePrompt();
669983
670577
  }
669984
670578
  });
669985
670579
 
@@ -669996,22 +670590,31 @@ function ownsScheduledRecord(r) {
669996
670590
  const current3 = getLiveSessionId() ?? String(getSessionId());
669997
670591
  return r.sessionId === current3;
669998
670592
  }
669999
- function submitViaQueue() {
670593
+ function submitViaQueue(onWarn) {
670000
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
+ }
670001
670599
  enqueuePendingNotification({
670002
- value: fire.prompt,
670600
+ value: prompt,
670003
670601
  mode: "prompt",
670004
670602
  priority: "later",
670005
670603
  // never starve real user input (CC cron precedent)
670006
670604
  isMeta: true,
670007
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" },
670008
670611
  workload: WORKLOAD_CRON
670009
670612
  });
670010
670613
  };
670011
670614
  }
670012
670615
  function createReplSchedulerDaemon(opts = {}) {
670013
670616
  const storePath = opts.storePath ?? schedulerStorePath();
670014
- return new SchedulerDaemon(fileSchedulerStoreIO(storePath), submitViaQueue(), {
670617
+ return new SchedulerDaemon(fileSchedulerStoreIO(storePath), submitViaQueue((m2) => opts.onError?.(new Error(m2))), {
670015
670618
  intervalMs: opts.intervalMs ?? REPL_SCHEDULER_TICK_MS,
670016
670619
  owns: ownsScheduledRecord,
670017
670620
  ...opts.now ? { now: opts.now } : {},
@@ -670027,6 +670630,7 @@ var init_schedulerQueueSubmit = __esm({
670027
670630
  init_liveSessionStore();
670028
670631
  init_schedulerDaemon();
670029
670632
  init_schedulerDaemonWire();
670633
+ init_firePrompt();
670030
670634
  REPL_SCHEDULER_TICK_MS = 5e3;
670031
670635
  }
670032
670636
  });