@sema-agent/cli 1.0.1 → 1.0.3

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 (2) hide show
  1. package/package.json +2 -2
  2. package/sema.js +1561 -780
package/sema.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { createRequire as __semaCreateRequire } from 'node:module';
3
3
  const require = __semaCreateRequire(import.meta.url);
4
4
  process.env.SEMA_FULL_REPL = process.env.SEMA_FULL_REPL || "1";
5
+ process.env.NODE_ENV = process.env.NODE_ENV || "production";
5
6
  // Sema shell (built from a re-syncable CC v2.1.187 copy; telemetry no-op-aliased, no Anthropic backend)
6
7
 
7
8
  var __create = Object.create;
@@ -11235,10 +11236,10 @@ async function setupSkills(ctx) {
11235
11236
  try {
11236
11237
  const versionId = await resolveSkillVersion(client4, skill.skill_id, skill.version);
11237
11238
  const version5 = await client4.beta.skills.versions.retrieve(versionId, { skill_id: skill.skill_id });
11238
- let dirname88 = path3.basename(version5.name.trim());
11239
- if (dirname88 === "" || dirname88 === "." || dirname88 === "..")
11240
- dirname88 = skill.skill_id;
11241
- const dest = path3.resolve(skillsRoot, dirname88);
11239
+ let dirname89 = path3.basename(version5.name.trim());
11240
+ if (dirname89 === "" || dirname89 === "." || dirname89 === "..")
11241
+ dirname89 = skill.skill_id;
11242
+ const dest = path3.resolve(skillsRoot, dirname89);
11242
11243
  if (dest !== skillsRoot && !dest.startsWith(skillsRoot + path3.sep)) {
11243
11244
  log2.warn("skill name escapes the skills dir; skipping", {
11244
11245
  component: "agent-tool-context",
@@ -19764,7 +19765,7 @@ var require_cross_spawn = __commonJS({
19764
19765
  enoent.hookChildProcess(spawned, parsed);
19765
19766
  return spawned;
19766
19767
  }
19767
- function spawnSync12(command8, args, options) {
19768
+ function spawnSync13(command8, args, options) {
19768
19769
  const parsed = parse14(command8, args, options);
19769
19770
  const result = cp2.spawnSync(parsed.command, parsed.args, parsed.options);
19770
19771
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
@@ -19772,7 +19773,7 @@ var require_cross_spawn = __commonJS({
19772
19773
  }
19773
19774
  module2.exports = spawn17;
19774
19775
  module2.exports.spawn = spawn17;
19775
- module2.exports.sync = spawnSync12;
19776
+ module2.exports.sync = spawnSync13;
19776
19777
  module2.exports._parse = parse14;
19777
19778
  module2.exports._enoent = enoent;
19778
19779
  }
@@ -126443,7 +126444,7 @@ var require_snapshot_recorder = __commonJS({
126443
126444
  "node_modules/undici/lib/mock/snapshot-recorder.js"(exports2, module2) {
126444
126445
  "use strict";
126445
126446
  var { writeFile: writeFile54, readFile: readFile59, mkdir: mkdir51 } = __require("node:fs/promises");
126446
- var { dirname: dirname88, resolve: resolve53 } = __require("node:path");
126447
+ var { dirname: dirname89, resolve: resolve53 } = __require("node:path");
126447
126448
  var { setTimeout: setTimeout3, clearTimeout: clearTimeout2 } = __require("node:timers");
126448
126449
  var { InvalidArgumentError: InvalidArgumentError2, UndiciError } = require_errors();
126449
126450
  var { hashId, isUrlExcludedFactory, normalizeHeaders: normalizeHeaders3, createHeaderFilters } = require_snapshot_utils();
@@ -126689,7 +126690,7 @@ var require_snapshot_recorder = __commonJS({
126689
126690
  throw new InvalidArgumentError2("Snapshot path is required");
126690
126691
  }
126691
126692
  const resolvedPath = resolve53(path27);
126692
- await mkdir51(dirname88(resolvedPath), { recursive: true });
126693
+ await mkdir51(dirname89(resolvedPath), { recursive: true });
126693
126694
  const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot2]) => ({
126694
126695
  hash: hash2,
126695
126696
  snapshot: snapshot2
@@ -155228,9 +155229,9 @@ var init_handler = __esm({
155228
155229
  if (this.fsw.closed) {
155229
155230
  return;
155230
155231
  }
155231
- const dirname88 = sp.dirname(file2);
155232
+ const dirname89 = sp.dirname(file2);
155232
155233
  const basename67 = sp.basename(file2);
155233
- const parent2 = this.fsw._getWatchedDir(dirname88);
155234
+ const parent2 = this.fsw._getWatchedDir(dirname89);
155234
155235
  let prevStats = stats3;
155235
155236
  if (parent2.has(basename67))
155236
155237
  return;
@@ -155257,7 +155258,7 @@ var init_handler = __esm({
155257
155258
  prevStats = newStats2;
155258
155259
  }
155259
155260
  } catch (error52) {
155260
- this.fsw._remove(dirname88, basename67);
155261
+ this.fsw._remove(dirname89, basename67);
155261
155262
  }
155262
155263
  } else if (parent2.has(basename67)) {
155263
155264
  const at = newStats.atimeMs;
@@ -162087,6 +162088,13 @@ var init_engineTaskListSync = __esm({
162087
162088
  });
162088
162089
 
162089
162090
  // build-src/src/sema/upstreamBridge.ts
162091
+ function engineTaskNotificationDedupKey(n2) {
162092
+ const taskId = typeof n2.task_id === "string" ? n2.task_id : "";
162093
+ const rawStatus = typeof n2.status === "string" ? n2.status : "completed";
162094
+ const seq = typeof n2.seq === "number" || typeof n2.seq === "string" ? String(n2.seq) : "";
162095
+ const lane = n2.task_type === "external" ? "external:" : "";
162096
+ return `${lane}${taskId}:${rawStatus}${seq ? `:${seq}` : ""}`;
162097
+ }
162090
162098
  function deriveNotificationResidualLines(n2) {
162091
162099
  const out6 = [];
162092
162100
  if (Array.isArray(n2.recentSteps)) {
@@ -163160,8 +163168,7 @@ async function* sdkMessagesToCcEvents(sdk, meta4) {
163160
163168
  const taskId = typeof n2.task_id === "string" ? n2.task_id : void 0;
163161
163169
  if (taskId === void 0) break;
163162
163170
  const rawStatus = typeof n2.status === "string" ? n2.status : "completed";
163163
- const seq = typeof n2.seq === "number" || typeof n2.seq === "string" ? String(n2.seq) : "";
163164
- const dedupKey = `${taskId}:${rawStatus}${seq ? `:${seq}` : ""}`;
163171
+ const dedupKey = engineTaskNotificationDedupKey(n2);
163165
163172
  if (renderedEngineTaskNotifications.has(dedupKey)) break;
163166
163173
  renderedEngineTaskNotifications.add(dedupKey);
163167
163174
  markEngineWorkflowNotified(taskId);
@@ -185465,7 +185472,7 @@ var require_dist4 = __commonJS({
185465
185472
  var src_exports = {};
185466
185473
  __export2(src_exports, {
185467
185474
  Socks5Server: () => Socks5Server,
185468
- createServer: () => createServer9,
185475
+ createServer: () => createServer10,
185469
185476
  defaultConnectionHandler: () => connectionHandler_default
185470
185477
  });
185471
185478
  module2.exports = __toCommonJS2(src_exports);
@@ -185668,12 +185675,12 @@ var require_dist4 = __commonJS({
185668
185675
  this.socket.resume();
185669
185676
  }
185670
185677
  };
185671
- var import_net6 = __toESM2(__require("net"));
185678
+ var import_net7 = __toESM2(__require("net"));
185672
185679
  function connectionHandler_default(connection, sendStatus) {
185673
185680
  if (connection.command !== "connect") return sendStatus("COMMAND_NOT_SUPPORTED");
185674
185681
  connection.socket.on("error", () => {
185675
185682
  });
185676
- const stream5 = import_net6.default.createConnection({
185683
+ const stream5 = import_net7.default.createConnection({
185677
185684
  host: connection.destAddress,
185678
185685
  port: connection.destPort
185679
185686
  });
@@ -185756,7 +185763,7 @@ var require_dist4 = __commonJS({
185756
185763
  return this;
185757
185764
  }
185758
185765
  };
185759
- function createServer9(opts) {
185766
+ function createServer10(opts) {
185760
185767
  const server = new Socks5Server();
185761
185768
  if (opts?.auth) server.setAuthHandler((conn) => {
185762
185769
  return conn.username === opts.auth.username && conn.password === opts.auth.password;
@@ -186357,8 +186364,8 @@ function generateProxyEnvVars(httpProxyPort, socksProxyPort, caCertPath, proxyAu
186357
186364
  const auth3 = proxyAuthToken2 ? `srt:${proxyAuthToken2}@` : "";
186358
186365
  const envVars = [`SANDBOX_RUNTIME=1`];
186359
186366
  if (!skipTmpdir) {
186360
- const tmpdir16 = process.env.CLAUDE_CODE_TMPDIR || process.env.CLAUDE_TMPDIR || "/tmp/claude";
186361
- envVars.push(`TMPDIR=${tmpdir16}`);
186367
+ const tmpdir17 = process.env.CLAUDE_CODE_TMPDIR || process.env.CLAUDE_TMPDIR || "/tmp/claude";
186368
+ envVars.push(`TMPDIR=${tmpdir17}`);
186362
186369
  }
186363
186370
  if (caCertPath) {
186364
186371
  for (const v2 of CA_TRUST_VARS) {
@@ -227307,11 +227314,11 @@ async function createBashShellProvider(shellPath, options) {
227307
227314
  }
227308
227315
  lastSnapshotFilePath = snapshotFilePath;
227309
227316
  currentSandboxTmpDir = opts.sandboxTmpDir;
227310
- const tmpdir16 = osTmpdir();
227317
+ const tmpdir17 = osTmpdir();
227311
227318
  const isWindows2 = getPlatform() === "windows";
227312
- const shellTmpdir = isWindows2 ? windowsPathToPosixPath(tmpdir16) : tmpdir16;
227319
+ const shellTmpdir = isWindows2 ? windowsPathToPosixPath(tmpdir17) : tmpdir17;
227313
227320
  const shellCwdFilePath = opts.useSandbox ? posixJoin(opts.sandboxTmpDir, `cwd-${opts.id}`) : posixJoin(shellTmpdir, `claude-${opts.id}-cwd`);
227314
- const cwdFilePath = opts.useSandbox ? posixJoin(opts.sandboxTmpDir, `cwd-${opts.id}`) : nativeJoin(tmpdir16, `claude-${opts.id}-cwd`);
227321
+ const cwdFilePath = opts.useSandbox ? posixJoin(opts.sandboxTmpDir, `cwd-${opts.id}`) : nativeJoin(tmpdir17, `claude-${opts.id}-cwd`);
227315
227322
  const normalizedCommand = rewriteWindowsNullRedirect(command8);
227316
227323
  const addStdinRedirect = shouldAddStdinRedirect(normalizedCommand);
227317
227324
  let quotedCommand = quoteShellCommand(normalizedCommand, addStdinRedirect);
@@ -266876,7 +266883,7 @@ var require_websocket2 = __commonJS({
266876
266883
  var http3 = __require("http");
266877
266884
  var net = __require("net");
266878
266885
  var tls = __require("tls");
266879
- var { randomBytes: randomBytes26, createHash: createHash26 } = __require("crypto");
266886
+ var { randomBytes: randomBytes26, createHash: createHash27 } = __require("crypto");
266880
266887
  var { Duplex, Readable: Readable5 } = __require("stream");
266881
266888
  var { URL: URL6 } = __require("url");
266882
266889
  var PerMessageDeflate2 = require_permessage_deflate2();
@@ -267544,7 +267551,7 @@ var require_websocket2 = __commonJS({
267544
267551
  abortHandshake(websocket, socket, "Invalid Upgrade header");
267545
267552
  return;
267546
267553
  }
267547
- const digest = createHash26("sha1").update(key + GUID).digest("base64");
267554
+ const digest = createHash27("sha1").update(key + GUID).digest("base64");
267548
267555
  if (res.headers["sec-websocket-accept"] !== digest) {
267549
267556
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
267550
267557
  return;
@@ -267913,7 +267920,7 @@ var require_websocket_server = __commonJS({
267913
267920
  var EventEmitter5 = __require("events");
267914
267921
  var http3 = __require("http");
267915
267922
  var { Duplex } = __require("stream");
267916
- var { createHash: createHash26 } = __require("crypto");
267923
+ var { createHash: createHash27 } = __require("crypto");
267917
267924
  var extension2 = require_extension();
267918
267925
  var PerMessageDeflate2 = require_permessage_deflate2();
267919
267926
  var subprotocol2 = require_subprotocol();
@@ -268220,7 +268227,7 @@ var require_websocket_server = __commonJS({
268220
268227
  );
268221
268228
  }
268222
268229
  if (this._state > RUNNING) return abortHandshake(socket, 503);
268223
- const digest = createHash26("sha1").update(key + GUID).digest("base64");
268230
+ const digest = createHash27("sha1").update(key + GUID).digest("base64");
268224
268231
  const headers = [
268225
268232
  "HTTP/1.1 101 Switching Protocols",
268226
268233
  "Upgrade: websocket",
@@ -329814,9 +329821,9 @@ function streamingTailWrap(unstableSuffix) {
329814
329821
  var import_compiler_runtime43, import_react43, import_jsx_runtime53, TOKEN_CACHE_MAX, tokenCache, MD_SYNTAX_RE;
329815
329822
  var init_Markdown = __esm({
329816
329823
  "build-src/src/components/Markdown.tsx"() {
329817
- import_compiler_runtime43 = __toESM(require_compiler_runtime());
329824
+ import_compiler_runtime43 = __toESM(require_compiler_runtime(), 1);
329818
329825
  init_marked_esm();
329819
- import_react43 = __toESM(require_react());
329826
+ import_react43 = __toESM(require_react(), 1);
329820
329827
  init_useSettings();
329821
329828
  init_ink2();
329822
329829
  init_cliHighlight();
@@ -329824,7 +329831,7 @@ var init_Markdown = __esm({
329824
329831
  init_markdown();
329825
329832
  init_messages4();
329826
329833
  init_MarkdownTable();
329827
- import_jsx_runtime53 = __toESM(require_jsx_runtime());
329834
+ import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
329828
329835
  TOKEN_CACHE_MAX = 500;
329829
329836
  tokenCache = /* @__PURE__ */ new Map();
329830
329837
  MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
@@ -351681,7 +351688,7 @@ function useClaudeAiLimits() {
351681
351688
  var import_react64;
351682
351689
  var init_claudeAiLimitsHook = __esm({
351683
351690
  "build-src/src/services/claudeAiLimitsHook.ts"() {
351684
- import_react64 = __toESM(require_react(), 1);
351691
+ import_react64 = __toESM(require_react());
351685
351692
  init_claudeAiLimits();
351686
351693
  }
351687
351694
  });
@@ -361974,6 +361981,7 @@ __export(state_exports2, {
361974
361981
  import { spawnSync as spawnSync6 } from "child_process";
361975
361982
  import { createHash as createHash18, randomBytes as randomBytes13 } from "crypto";
361976
361983
  import { chmod as chmod9, mkdir as mkdir23, readdir as readdir17, readFile as readFile28, rename as rename8, unlink as unlink13, writeFile as writeFile21 } from "fs/promises";
361984
+ import { tmpdir as tmpdir9 } from "os";
361977
361985
  import { join as join93 } from "path";
361978
361986
  function isTerminalJobState(state3) {
361979
361987
  return state3 === "done" || state3 === "failed" || state3 === "stopped";
@@ -362123,11 +362131,13 @@ function getDaemonJsonPath() {
362123
362131
  return join93(getClaudeConfigHomeDir(), "daemon.json");
362124
362132
  }
362125
362133
  function getDaemonSocketPath() {
362134
+ const h = createHash18("sha256").update(getClaudeConfigHomeDir()).digest("hex").slice(0, 12);
362126
362135
  if (process.platform === "win32") {
362127
- const h = createHash18("sha256").update(getClaudeConfigHomeDir()).digest("hex").slice(0, 12);
362128
362136
  return `\\\\.\\pipe\\sema-daemon-${h}`;
362129
362137
  }
362130
- return join93(getClaudeConfigHomeDir(), "daemon.sock");
362138
+ let dir = join93(tmpdir9(), `sema-d-${h}`);
362139
+ if (join93(dir, "d.sock").length > 100) dir = `/tmp/sema-d-${h}`;
362140
+ return join93(dir, "d.sock");
362131
362141
  }
362132
362142
  function getDaemonLogPath() {
362133
362143
  return join93(getClaudeConfigHomeDir(), "daemon.log");
@@ -362233,7 +362243,7 @@ __export(client_exports2, {
362233
362243
  dispatchJob: () => dispatchJob,
362234
362244
  ensureDaemonRunning: () => ensureDaemonRunning
362235
362245
  });
362236
- import { spawn as spawn8 } from "child_process";
362246
+ import { spawn as spawn8, spawnSync as spawnSync7 } from "child_process";
362237
362247
  import { randomUUID as randomUUID17 } from "crypto";
362238
362248
  import { mkdir as mkdir24, rename as rename9, writeFile as writeFile22 } from "fs/promises";
362239
362249
  import { createConnection as createConnection2 } from "net";
@@ -362278,18 +362288,54 @@ async function pingOk(info) {
362278
362288
  return false;
362279
362289
  }
362280
362290
  }
362291
+ function spawnDaemonViaWmi() {
362292
+ const script = process.argv[1];
362293
+ if (!script) return false;
362294
+ const cmdLine = [
362295
+ `"${process.execPath}"`,
362296
+ `"${script}"`,
362297
+ "daemon",
362298
+ "run",
362299
+ "--origin",
362300
+ "transient",
362301
+ "--config-dir",
362302
+ `"${getClaudeConfigHomeDir()}"`
362303
+ ].join(" ");
362304
+ const psCmdLine = cmdLine.replace(/'/g, "''");
362305
+ const ps = `$si = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property @{ShowWindow=[UInt16]0};$r = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine='${psCmdLine}'; ProcessStartupInformation=$si};if ($r.ReturnValue -eq 0) { exit 0 } else { exit 1 }`;
362306
+ const r = spawnSync7(
362307
+ "powershell",
362308
+ [
362309
+ "-NoProfile",
362310
+ "-NonInteractive",
362311
+ // -EncodedCommand: the script carries quotes/braces — never trust cmd-line re-quoting
362312
+ "-EncodedCommand",
362313
+ Buffer.from(ps, "utf16le").toString("base64")
362314
+ ],
362315
+ { stdio: "ignore", windowsHide: true, timeout: 15e3 }
362316
+ );
362317
+ return !r.error && r.status === 0;
362318
+ }
362281
362319
  async function ensureDaemonRunning() {
362282
362320
  let info = await readDaemonInfo();
362283
362321
  if (info && isDaemonAlive(info) && await pingOk(info)) return info;
362284
- const child = spawn8(
362285
- process.execPath,
362286
- [process.argv[1], "daemon", "run", "--origin", "transient"],
362287
- // detached: survives this CLI (POSIX setsid; win32 DETACHED_PROCESS — the supervisor must
362288
- // outlive its spawner on both). windowsHide keeps win32 from flashing a console window
362289
- // (no-op elsewhere; core host-platform precedent).
362290
- { detached: true, stdio: "ignore", env: process.env, windowsHide: true }
362291
- );
362292
- child.unref();
362322
+ const wmiSpawned = process.platform === "win32" && spawnDaemonViaWmi();
362323
+ if (!wmiSpawned) {
362324
+ if (process.platform === "win32") {
362325
+ console.error(
362326
+ "sema: WMI spawn unavailable \u2014 background tasks may not survive this session (daemon inherits the session Job object)"
362327
+ );
362328
+ }
362329
+ const child = spawn8(
362330
+ process.execPath,
362331
+ [process.argv[1], "daemon", "run", "--origin", "transient"],
362332
+ // detached: survives this CLI (POSIX setsid; win32 DETACHED_PROCESS — the supervisor must
362333
+ // outlive its spawner on both). windowsHide keeps win32 from flashing a console window
362334
+ // (no-op elsewhere; core host-platform precedent).
362335
+ { detached: true, stdio: "ignore", env: process.env, windowsHide: true }
362336
+ );
362337
+ child.unref();
362338
+ }
362293
362339
  for (let i = 0; i < 40; i++) {
362294
362340
  await sleep4(150);
362295
362341
  info = await readDaemonInfo();
@@ -362307,7 +362353,13 @@ function mapResponse(r) {
362307
362353
  }
362308
362354
  async function dispatchJob(job) {
362309
362355
  let info = await ensureDaemonRunning();
362310
- if (!info) return { ok: false, code: "daemon-unreachable" };
362356
+ if (!info) {
362357
+ return {
362358
+ ok: false,
362359
+ code: "daemon-unreachable",
362360
+ message: "the daemon was spawned but never came up (it likely crashed on boot)"
362361
+ };
362362
+ }
362311
362363
  const nonce = randomUUID17();
362312
362364
  for (let attempt = 0; attempt < 3; attempt++) {
362313
362365
  try {
@@ -362365,6 +362417,7 @@ async function dispatchJob(job) {
362365
362417
  var MAX_RPC_BYTES, sleep4;
362366
362418
  var init_client7 = __esm({
362367
362419
  "build-src/src/daemon/client.ts"() {
362420
+ init_envUtils();
362368
362421
  init_state2();
362369
362422
  MAX_RPC_BYTES = 1048576;
362370
362423
  sleep4 = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -362844,7 +362897,7 @@ __export(bg_exports, {
362844
362897
  stripLogAnsi: () => stripLogAnsi,
362845
362898
  tmuxSessionName: () => tmuxSessionName
362846
362899
  });
362847
- import { spawnSync as spawnSync7 } from "child_process";
362900
+ import { spawnSync as spawnSync8 } from "child_process";
362848
362901
  import { randomUUID as randomUUID18 } from "crypto";
362849
362902
  import { chmod as chmod10, mkdir as mkdir25, readdir as readdir18, readFile as readFile29, rm as rmrf, unlink as unlink14, writeFile as writeFile23 } from "fs/promises";
362850
362903
  import { join as join95 } from "path";
@@ -362878,6 +362931,13 @@ async function listSessions() {
362878
362931
  }
362879
362932
  try {
362880
362933
  const rec = JSON.parse(await readFile29(join95(dir, file2), "utf8"));
362934
+ if (rec.startedAt !== void 0 && processStartedAfter2(pid, rec.startedAt + 15e3) === true) {
362935
+ if (getPlatform() !== "wsl") {
362936
+ await unlink14(join95(dir, file2)).catch(() => {
362937
+ });
362938
+ }
362939
+ continue;
362940
+ }
362881
362941
  out6.push({ ...rec, pid });
362882
362942
  } catch {
362883
362943
  }
@@ -363107,9 +363167,9 @@ async function attachHandler(id, extraArgs = []) {
363107
363167
  if (!rec) return;
363108
363168
  const short = shortId(rec);
363109
363169
  const tmuxName = tmuxSessionName(rec);
363110
- const has2 = spawnSync7("tmux", ["has-session", "-t", `=${tmuxName}`], { stdio: "ignore" });
363170
+ const has2 = spawnSync8("tmux", ["has-session", "-t", `=${tmuxName}`], { stdio: "ignore" });
363111
363171
  if (has2.status === 0) {
363112
- const r2 = spawnSync7("tmux", ["attach-session", "-t", `=${tmuxName}`], { stdio: "inherit" });
363172
+ const r2 = spawnSync8("tmux", ["attach-session", "-t", `=${tmuxName}`], { stdio: "inherit" });
363113
363173
  process.exitCode = r2.status ?? 0;
363114
363174
  return;
363115
363175
  }
@@ -363123,7 +363183,7 @@ async function attachHandler(id, extraArgs = []) {
363123
363183
  }
363124
363184
  process.stderr.write(`no tmux session for ${short} \u2014 resuming ${rec.sessionId} in this terminal instead
363125
363185
  `);
363126
- const r = spawnSync7(
363186
+ const r = spawnSync8(
363127
363187
  process.execPath,
363128
363188
  [process.argv[1], "--resume", rec.sessionId],
363129
363189
  {
@@ -363136,13 +363196,7 @@ async function attachHandler(id, extraArgs = []) {
363136
363196
  process.exitCode = r.status ?? 0;
363137
363197
  }
363138
363198
  function processStartedAfter2(pid, epochMs) {
363139
- const r = spawnSync7("ps", ["-p", String(pid), "-o", "etime="], { encoding: "utf8" });
363140
- if (r.error || r.status !== 0) return null;
363141
- const m2 = /^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)$/.exec((r.stdout ?? "").trim());
363142
- if (!m2) return null;
363143
- const [, d2, h, min, s] = m2;
363144
- const elapsedMs2 = (((Number(d2 ?? 0) * 24 + Number(h ?? 0)) * 60 + Number(min)) * 60 + Number(s)) * 1e3;
363145
- return Date.now() - elapsedMs2 > epochMs;
363199
+ return processStartedAfter(pid, epochMs);
363146
363200
  }
363147
363201
  function assessKillIdentity(rec, freshText) {
363148
363202
  if (freshText === null) return "gone";
@@ -363215,7 +363269,7 @@ async function legacyKill(resolved) {
363215
363269
  const freshText = await readFile29(pidFile, "utf8").catch(() => null);
363216
363270
  const identity3 = assessKillIdentity(rec, freshText);
363217
363271
  if (identity3 === "gone") {
363218
- spawnSync7("tmux", ["kill-session", "-t", `=${tmuxSessionName(rec)}`], { stdio: "ignore" });
363272
+ spawnSync8("tmux", ["kill-session", "-t", `=${tmuxSessionName(rec)}`], { stdio: "ignore" });
363219
363273
  process.stdout.write(`stopped ${short}
363220
363274
  `);
363221
363275
  return;
@@ -363244,7 +363298,7 @@ async function legacyKill(resolved) {
363244
363298
  }
363245
363299
  await unlink14(pidFile).catch(() => {
363246
363300
  });
363247
- spawnSync7("tmux", ["kill-session", "-t", `=${tmuxSessionName(rec)}`], { stdio: "ignore" });
363301
+ spawnSync8("tmux", ["kill-session", "-t", `=${tmuxSessionName(rec)}`], { stdio: "ignore" });
363248
363302
  process.stdout.write(`stopped ${short}
363249
363303
  `);
363250
363304
  }
@@ -363370,14 +363424,14 @@ async function rmHandler(id, extraArgs = []) {
363370
363424
  let keptWorktree;
363371
363425
  let keptReason;
363372
363426
  if (st2?.worktreePath) {
363373
- const dirty2 = spawnSync7("git", ["-C", st2.worktreePath, "status", "--porcelain"], {
363427
+ const dirty2 = spawnSync8("git", ["-C", st2.worktreePath, "status", "--porcelain"], {
363374
363428
  encoding: "utf8"
363375
363429
  });
363376
363430
  if (dirty2.status === 0 && (dirty2.stdout ?? "").trim().length > 0) {
363377
363431
  keptWorktree = st2.worktreePath;
363378
363432
  keptReason = "dirty";
363379
363433
  } else if (dirty2.status === 0) {
363380
- const removed = spawnSync7("git", ["-C", st2.cwd, "worktree", "remove", "--force", st2.worktreePath], {
363434
+ const removed = spawnSync8("git", ["-C", st2.cwd, "worktree", "remove", "--force", st2.worktreePath], {
363381
363435
  stdio: "ignore"
363382
363436
  });
363383
363437
  if (removed.status !== 0) {
@@ -363543,7 +363597,15 @@ async function handleBgFlagDaemon(rest, head) {
363543
363597
  } else if (result.code === "stale-short") {
363544
363598
  process.stderr.write("Previous session is still shutting down \u2014 try again in a moment\n");
363545
363599
  } else {
363600
+ const { getDaemonLogPath: getDaemonLogPath2 } = await Promise.resolve().then(() => (init_state2(), state_exports2));
363546
363601
  process.stderr.write("Couldn't reach the daemon (not running)\n");
363602
+ if (result.message) process.stderr.write(` cause: ${result.message}
363603
+ `);
363604
+ process.stderr.write(
363605
+ ` The task was NOT started. Check ${getDaemonLogPath2()} for the daemon's crash log,
363606
+ or run \`sema daemon run\` in a terminal to see the failure live, then retry \`sema --bg\`.
363607
+ `
363608
+ );
363547
363609
  }
363548
363610
  process.exitCode = 1;
363549
363611
  return;
@@ -363596,7 +363658,7 @@ async function handleBgFlag(args) {
363596
363658
  await handleBgFlagDaemon(rest, head);
363597
363659
  return;
363598
363660
  }
363599
- const tmuxOk = spawnSync7("tmux", ["-V"], { stdio: "ignore" });
363661
+ const tmuxOk = spawnSync8("tmux", ["-V"], { stdio: "ignore" });
363600
363662
  if (tmuxOk.error || tmuxOk.status !== 0) {
363601
363663
  process.stderr.write("Couldn't start the session \u2014 --bg requires tmux (not found on PATH)\n");
363602
363664
  process.exitCode = 1;
@@ -363633,7 +363695,7 @@ async function handleBgFlag(args) {
363633
363695
  await chmod10(envFile, 384);
363634
363696
  const inner = `. ${shq(envFile)}; rm -f ${shq(envFile)}; exec ${shq(process.execPath)} ${childArgs.map(shq).join(" ")}`;
363635
363697
  const cmd = `exec sh -c ${shq(inner)}`;
363636
- const spawned = spawnSync7(
363698
+ const spawned = spawnSync8(
363637
363699
  "tmux",
363638
363700
  ["new-session", "-d", "-s", tmuxName, "-c", process.cwd(), cmd],
363639
363701
  { stdio: ["ignore", "ignore", "pipe"] }
@@ -363647,10 +363709,10 @@ async function handleBgFlag(args) {
363647
363709
  process.exitCode = 1;
363648
363710
  return;
363649
363711
  }
363650
- spawnSync7("tmux", ["pipe-pane", "-t", `=${tmuxName}:`, "-o", `cat >> ${shq(logPath)}`], {
363712
+ spawnSync8("tmux", ["pipe-pane", "-t", `=${tmuxName}:`, "-o", `cat >> ${shq(logPath)}`], {
363651
363713
  stdio: "ignore"
363652
363714
  });
363653
- const paneOut = spawnSync7(
363715
+ const paneOut = spawnSync8(
363654
363716
  "tmux",
363655
363717
  ["display-message", "-p", "-t", `=${tmuxName}:`, "#{pane_pid}"],
363656
363718
  { encoding: "utf8" }
@@ -363681,6 +363743,7 @@ var LOGS_TAIL_LINES, killHandler;
363681
363743
  var init_bg2 = __esm({
363682
363744
  "build-src/src/cli/bg.ts"() {
363683
363745
  init_source2();
363746
+ init_state2();
363684
363747
  init_envUtils();
363685
363748
  init_genericProcessUtils();
363686
363749
  init_platform();
@@ -364371,11 +364434,11 @@ var init_filesApi = __esm({
364371
364434
 
364372
364435
  // build-src/src/utils/tempfile.ts
364373
364436
  import { createHash as createHash19, randomUUID as randomUUID20 } from "crypto";
364374
- import { tmpdir as tmpdir9 } from "os";
364437
+ import { tmpdir as tmpdir10 } from "os";
364375
364438
  import { join as join97 } from "path";
364376
364439
  function generateTempFilePath(prefix = "claude-prompt", extension2 = ".md", options) {
364377
364440
  const id = options?.contentHash ? createHash19("sha256").update(options.contentHash).digest("hex").slice(0, 16) : randomUUID20();
364378
- return join97(tmpdir9(), `${prefix}-${id}${extension2}`);
364441
+ return join97(tmpdir10(), `${prefix}-${id}${extension2}`);
364379
364442
  }
364380
364443
  var init_tempfile = __esm({
364381
364444
  "build-src/src/utils/tempfile.ts"() {
@@ -409305,33 +409368,44 @@ function drainPendingMessages(taskId, getAppState, setAppState) {
409305
409368
  }));
409306
409369
  return drained;
409307
409370
  }
409308
- function enqueueAgentNotification({
409371
+ function agentHasLiveBackgroundChildren(agentId, tasks3) {
409372
+ for (const t2 of Object.values(tasks3)) {
409373
+ if (isLocalAgentTask(t2) && t2.ownerAgentId === agentId && (t2.status === "running" || t2.status === "pending")) {
409374
+ return true;
409375
+ }
409376
+ }
409377
+ return false;
409378
+ }
409379
+ function flushDeferredOwnerNotification(ownerAgentId, setAppState) {
409380
+ if (!ownerAgentId || !deferredOwnerNotifications.has(ownerAgentId)) {
409381
+ return;
409382
+ }
409383
+ let tasksSnapshot;
409384
+ setAppState((prev) => {
409385
+ tasksSnapshot = prev.tasks;
409386
+ return prev;
409387
+ });
409388
+ if (!tasksSnapshot) return;
409389
+ if (agentHasLiveBackgroundChildren(ownerAgentId, tasksSnapshot)) return;
409390
+ const message = deferredOwnerNotifications.get(ownerAgentId);
409391
+ if (!message) return;
409392
+ deferredOwnerNotifications.delete(ownerAgentId);
409393
+ enqueuePendingNotification({
409394
+ value: message,
409395
+ mode: "task-notification"
409396
+ });
409397
+ }
409398
+ function buildAgentNotificationMessage({
409309
409399
  taskId,
409310
409400
  description,
409311
409401
  status: status3,
409312
409402
  error: error52,
409313
- setAppState,
409314
409403
  finalMessage,
409315
409404
  usage,
409316
409405
  toolUseId,
409317
409406
  worktreePath,
409318
409407
  worktreeBranch
409319
409408
  }) {
409320
- let shouldEnqueue = false;
409321
- updateTaskState(taskId, setAppState, (task) => {
409322
- if (task.notified) {
409323
- return task;
409324
- }
409325
- shouldEnqueue = true;
409326
- return {
409327
- ...task,
409328
- notified: true
409329
- };
409330
- });
409331
- if (!shouldEnqueue) {
409332
- return;
409333
- }
409334
- abortSpeculation(setAppState);
409335
409409
  const summary = status3 === "completed" ? `Agent "${description}" completed` : status3 === "failed" ? `Agent "${description}" failed: ${error52 || "Unknown error"}` : `Agent "${description}" was stopped`;
409336
409410
  const outputPath = getTaskOutputPath(taskId);
409337
409411
  const toolUseIdLine = toolUseId ? `
@@ -409342,12 +409416,65 @@ function enqueueAgentNotification({
409342
409416
  <usage><total_tokens>${usage.totalTokens}</total_tokens><tool_uses>${usage.toolUses}</tool_uses><duration_ms>${usage.durationMs}</duration_ms></usage>` : "";
409343
409417
  const worktreeSection = worktreePath ? `
409344
409418
  <${WORKTREE_TAG}><${WORKTREE_PATH_TAG}>${worktreePath}</${WORKTREE_PATH_TAG}>${worktreeBranch ? `<${WORKTREE_BRANCH_TAG}>${worktreeBranch}</${WORKTREE_BRANCH_TAG}>` : ""}</${WORKTREE_TAG}>` : "";
409345
- const message = `<${TASK_NOTIFICATION_TAG}>
409419
+ return `<${TASK_NOTIFICATION_TAG}>
409346
409420
  <${TASK_ID_TAG}>${taskId}</${TASK_ID_TAG}>${toolUseIdLine}
409347
409421
  <${OUTPUT_FILE_TAG}>${outputPath}</${OUTPUT_FILE_TAG}>
409348
409422
  <${STATUS_TAG}>${status3}</${STATUS_TAG}>
409349
- <${SUMMARY_TAG}>${summary}</${SUMMARY_TAG}>${resultSection}${usageSection}${worktreeSection}
409423
+ <${SUMMARY_TAG}>${summary}</${SUMMARY_TAG}>
409424
+ <note>${TASK_NOTIFICATION_NOTE}</note>${resultSection}${usageSection}${worktreeSection}
409350
409425
  </${TASK_NOTIFICATION_TAG}>`;
409426
+ }
409427
+ function enqueueAgentNotification({
409428
+ taskId,
409429
+ description,
409430
+ status: status3,
409431
+ error: error52,
409432
+ setAppState,
409433
+ finalMessage,
409434
+ usage,
409435
+ toolUseId,
409436
+ worktreePath,
409437
+ worktreeBranch
409438
+ }) {
409439
+ let decision = "skip";
409440
+ setAppState((prev) => {
409441
+ const task = prev.tasks?.[taskId];
409442
+ if (!isLocalAgentTask(task)) {
409443
+ return prev;
409444
+ }
409445
+ if (task.notified) {
409446
+ decision = "skip";
409447
+ return prev;
409448
+ }
409449
+ const parkOnChildren = status3 === "completed" && agentHasLiveBackgroundChildren(taskId, prev.tasks);
409450
+ decision = parkOnChildren ? "defer" : "enqueue";
409451
+ return {
409452
+ ...prev,
409453
+ tasks: {
409454
+ ...prev.tasks,
409455
+ [taskId]: { ...task, notified: true }
409456
+ }
409457
+ };
409458
+ });
409459
+ if (decision === "skip") {
409460
+ return;
409461
+ }
409462
+ abortSpeculation(setAppState);
409463
+ const message = buildAgentNotificationMessage({
409464
+ taskId,
409465
+ description,
409466
+ status: status3,
409467
+ error: error52,
409468
+ finalMessage,
409469
+ usage,
409470
+ toolUseId,
409471
+ worktreePath,
409472
+ worktreeBranch
409473
+ });
409474
+ if (decision === "defer") {
409475
+ deferredOwnerNotifications.set(taskId, message);
409476
+ return;
409477
+ }
409351
409478
  enqueuePendingNotification({
409352
409479
  value: message,
409353
409480
  mode: "task-notification"
@@ -409355,11 +409482,13 @@ function enqueueAgentNotification({
409355
409482
  }
409356
409483
  function killAsyncAgent(taskId, setAppState) {
409357
409484
  let killed = false;
409485
+ let ownerAgentId;
409358
409486
  updateTaskState(taskId, setAppState, (task) => {
409359
409487
  if (task.status !== "running") {
409360
409488
  return task;
409361
409489
  }
409362
409490
  killed = true;
409491
+ ownerAgentId = task.ownerAgentId;
409363
409492
  task.abortController?.abort();
409364
409493
  task.unregisterCleanup?.();
409365
409494
  return {
@@ -409374,6 +409503,7 @@ function killAsyncAgent(taskId, setAppState) {
409374
409503
  });
409375
409504
  if (killed) {
409376
409505
  void evictTaskOutput(taskId);
409506
+ flushDeferredOwnerNotification(ownerAgentId, setAppState);
409377
409507
  }
409378
409508
  }
409379
409509
  function killAllRunningAgentTasks(tasks3, setAppState) {
@@ -409451,10 +409581,12 @@ function updateAgentSummary(taskId, summary, setAppState) {
409451
409581
  }
409452
409582
  function completeAgentTask(result, setAppState) {
409453
409583
  const taskId = result.agentId;
409584
+ let ownerAgentId;
409454
409585
  updateTaskState(taskId, setAppState, (task) => {
409455
409586
  if (task.status !== "running") {
409456
409587
  return task;
409457
409588
  }
409589
+ ownerAgentId = task.ownerAgentId;
409458
409590
  task.unregisterCleanup?.();
409459
409591
  return {
409460
409592
  ...task,
@@ -409468,12 +409600,15 @@ function completeAgentTask(result, setAppState) {
409468
409600
  };
409469
409601
  });
409470
409602
  void evictTaskOutput(taskId);
409603
+ flushDeferredOwnerNotification(ownerAgentId, setAppState);
409471
409604
  }
409472
409605
  function failAgentTask(taskId, error52, setAppState) {
409606
+ let ownerAgentId;
409473
409607
  updateTaskState(taskId, setAppState, (task) => {
409474
409608
  if (task.status !== "running") {
409475
409609
  return task;
409476
409610
  }
409611
+ ownerAgentId = task.ownerAgentId;
409477
409612
  task.unregisterCleanup?.();
409478
409613
  return {
409479
409614
  ...task,
@@ -409487,6 +409622,7 @@ function failAgentTask(taskId, error52, setAppState) {
409487
409622
  };
409488
409623
  });
409489
409624
  void evictTaskOutput(taskId);
409625
+ flushDeferredOwnerNotification(ownerAgentId, setAppState);
409490
409626
  }
409491
409627
  function registerAsyncAgent({
409492
409628
  agentId,
@@ -409499,11 +409635,13 @@ function registerAsyncAgent({
409499
409635
  }) {
409500
409636
  void initTaskOutputAsSymlink(agentId, getAgentTranscriptPath(asAgentId(agentId)));
409501
409637
  const abortController = parentAbortController ? createChildAbortController(parentAbortController) : createAbortController();
409638
+ const ownerAgentId = getAgentContext()?.agentId;
409502
409639
  const taskState = {
409503
409640
  ...createTaskStateBase(agentId, "local_agent", description, toolUseId),
409504
409641
  type: "local_agent",
409505
409642
  status: "running",
409506
409643
  agentId,
409644
+ ownerAgentId,
409507
409645
  prompt,
409508
409646
  selectedAgent,
409509
409647
  agentType: selectedAgent.agentType ?? "general-purpose",
@@ -409538,11 +409676,13 @@ function registerAgentForeground({
409538
409676
  const unregisterCleanup2 = registerCleanup(async () => {
409539
409677
  killAsyncAgent(agentId, setAppState);
409540
409678
  });
409679
+ const ownerAgentId = getAgentContext()?.agentId;
409541
409680
  const taskState = {
409542
409681
  ...createTaskStateBase(agentId, "local_agent", description, toolUseId),
409543
409682
  type: "local_agent",
409544
409683
  status: "running",
409545
409684
  agentId,
409685
+ ownerAgentId,
409546
409686
  prompt,
409547
409687
  selectedAgent,
409548
409688
  agentType: selectedAgent.agentType ?? "general-purpose",
@@ -409645,7 +409785,7 @@ function unregisterAgentForeground(taskId, setAppState) {
409645
409785
  });
409646
409786
  cleanupFn?.();
409647
409787
  }
409648
- var MAX_RECENT_ACTIVITIES2, LocalAgentTask, backgroundSignalResolvers;
409788
+ var MAX_RECENT_ACTIVITIES2, TASK_NOTIFICATION_NOTE, deferredOwnerNotifications, LocalAgentTask, backgroundSignalResolvers;
409649
409789
  var init_LocalAgentTask = __esm({
409650
409790
  "build-src/src/tasks/LocalAgentTask/LocalAgentTask.tsx"() {
409651
409791
  init_state();
@@ -409656,6 +409796,7 @@ var init_LocalAgentTask = __esm({
409656
409796
  init_SyntheticOutputTool();
409657
409797
  init_ids();
409658
409798
  init_abortController();
409799
+ init_agentContext();
409659
409800
  init_cleanupRegistry();
409660
409801
  init_collapseReadSearch();
409661
409802
  init_messageQueueManager();
@@ -409664,6 +409805,8 @@ var init_LocalAgentTask = __esm({
409664
409805
  init_framework();
409665
409806
  init_sdkProgress();
409666
409807
  MAX_RECENT_ACTIVITIES2 = 5;
409808
+ TASK_NOTIFICATION_NOTE = "A task-notification fires each time this agent stops with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.";
409809
+ deferredOwnerNotifications = /* @__PURE__ */ new Map();
409667
409810
  LocalAgentTask = {
409668
409811
  name: "LocalAgentTask",
409669
409812
  type: "local_agent",
@@ -426781,6 +426924,24 @@ var init_engineRuntimeStatus = __esm({
426781
426924
  }
426782
426925
  });
426783
426926
 
426927
+ // build-src/src/sema/enginePortDerive.ts
426928
+ import { createHash as createHash21 } from "crypto";
426929
+ function derivedDefaultEnginePort(configHome = getClaudeConfigHomeDir()) {
426930
+ const h = createHash21("sha256").update(configHome).digest();
426931
+ return DERIVED_ENGINE_PORT_BASE + h.readUInt32BE(0) % DERIVED_ENGINE_PORT_SPAN;
426932
+ }
426933
+ function derivedPortCandidate(base, i) {
426934
+ return DERIVED_ENGINE_PORT_BASE + (base - DERIVED_ENGINE_PORT_BASE + i) % DERIVED_ENGINE_PORT_SPAN;
426935
+ }
426936
+ var DERIVED_ENGINE_PORT_BASE, DERIVED_ENGINE_PORT_SPAN;
426937
+ var init_enginePortDerive = __esm({
426938
+ "build-src/src/sema/enginePortDerive.ts"() {
426939
+ init_envUtils();
426940
+ DERIVED_ENGINE_PORT_BASE = 43e3;
426941
+ DERIVED_ENGINE_PORT_SPAN = 2e3;
426942
+ }
426943
+ });
426944
+
426784
426945
  // build-src/src/sema/cloudProfile.ts
426785
426946
  import { existsSync as existsSync12, mkdirSync as mkdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync9, chmodSync as chmodSync4 } from "fs";
426786
426947
  import { homedir as homedir30 } from "os";
@@ -427374,7 +427535,7 @@ function configuredEnginePort() {
427374
427535
  if (Number.isInteger(p) && p > 0 && p < 65536) {
427375
427536
  return { port: p, source: fromSettings !== void 0 ? "settings" : "env" };
427376
427537
  }
427377
- return { port: 47362, source: "default" };
427538
+ return { port: derivedDefaultEnginePort(), source: "default" };
427378
427539
  }
427379
427540
  function configuredPort() {
427380
427541
  return configuredEnginePort().port;
@@ -427433,6 +427594,7 @@ var ENGINE_URL_ENV, TRUSTED_ENGINE_HOSTS_KEY, SYNC_ENGINE_URL_ENV, AUTO_SYNC_SOU
427433
427594
  var init_engineTarget = __esm({
427434
427595
  "build-src/src/sema/engineTarget.ts"() {
427435
427596
  init_envUtils();
427597
+ init_enginePortDerive();
427436
427598
  init_cloudExecutionPolicy();
427437
427599
  ENGINE_URL_ENV = "SEMA_ENGINE_URL";
427438
427600
  TRUSTED_ENGINE_HOSTS_KEY = "trustedEngineHosts";
@@ -427733,7 +427895,7 @@ __export(cloudConfigWire_exports, {
427733
427895
  refreshCloudConfigNow: () => refreshCloudConfigNow,
427734
427896
  shadowModelsExists: () => shadowModelsExists
427735
427897
  });
427736
- import { createHash as createHash21 } from "node:crypto";
427898
+ import { createHash as createHash22 } from "node:crypto";
427737
427899
  import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync24, writeFileSync as writeFileSync11 } from "node:fs";
427738
427900
  import { dirname as dirname55, join as join117 } from "node:path";
427739
427901
  function cloudConfigEnabled() {
@@ -427780,7 +427942,7 @@ function writeShadowModels(profileName, modelsDoc) {
427780
427942
  }
427781
427943
  }
427782
427944
  function sha256Address(content) {
427783
- return `sha256:${createHash21("sha256").update(content, "utf8").digest("hex")}`;
427945
+ return `sha256:${createHash22("sha256").update(content, "utf8").digest("hex")}`;
427784
427946
  }
427785
427947
  async function getJson(url4, accessToken, headers = {}) {
427786
427948
  const res = await fetch(url4, {
@@ -427999,7 +428161,6 @@ var init_cloudConfigWire = __esm({
427999
428161
  // build-src/src/sema/engineLifecycleManager.ts
428000
428162
  var engineLifecycleManager_exports = {};
428001
428163
  __export(engineLifecycleManager_exports, {
428002
- DEFAULT_ENGINE_PORT: () => DEFAULT_ENGINE_PORT,
428003
428164
  applyOpenAiEnvAliases: () => applyOpenAiEnvAliases,
428004
428165
  assembleChildEnv: () => assembleChildEnv,
428005
428166
  describeEngineInitFailure: () => describeEngineInitFailure,
@@ -428012,28 +428173,38 @@ __export(engineLifecycleManager_exports, {
428012
428173
  getServiceAuthToken: () => getServiceAuthToken,
428013
428174
  hasManageableLocalEngine: () => hasManageableLocalEngine,
428014
428175
  initEngineLifecycle: () => initEngineLifecycle,
428176
+ installEngineExitTeardown: () => installEngineExitTeardown,
428015
428177
  isLocalEngineActive: () => isLocalEngineActive,
428016
428178
  isProcessAlive: () => isProcessAlive,
428179
+ isShellHostDead: () => isShellHostDead,
428180
+ pickFreeEnginePort: () => pickFreeEnginePort,
428181
+ pinnedEnginePort: () => pinnedEnginePort,
428017
428182
  probeHealth: () => probeHealth,
428018
428183
  probeLocalEngineHealth: () => probeLocalEngineHealth,
428019
428184
  readMemorySyncSettings: () => readMemorySyncSettings,
428020
428185
  readWorkflowSizeGuidelineSetting: () => readWorkflowSizeGuidelineSetting,
428186
+ requestEngineRetryNow: () => requestEngineRetryNow,
428021
428187
  resetDeadRespawnStateForTests: () => resetDeadRespawnStateForTests,
428188
+ resetEngineExitTeardownForTests: () => resetEngineExitTeardownForTests,
428022
428189
  resolveEngineEntry: () => resolveEngineEntry,
428023
428190
  respawnOnConfigDrift: () => respawnOnConfigDrift,
428024
428191
  restartEngine: () => restartEngine,
428025
428192
  runEngineDeadRespawn: () => runEngineDeadRespawn,
428193
+ setLocalEngineActiveForTests: () => setLocalEngineActiveForTests,
428026
428194
  setOnOwnedEngineExit: () => setOnOwnedEngineExit,
428027
428195
  shutdownEngine: () => shutdownEngine,
428028
- startHealthCheckLoop: () => startHealthCheckLoop
428196
+ startHealthCheckLoop: () => startHealthCheckLoop,
428197
+ teardownOwnedEngineSync: () => teardownOwnedEngineSync
428029
428198
  });
428030
428199
  import { spawn as spawn10 } from "child_process";
428200
+ import { createServer as createServer7 } from "net";
428031
428201
  import {
428032
428202
  closeSync as closeSync7,
428033
428203
  existsSync as existsSync15,
428034
428204
  fsyncSync as fsyncSync5,
428035
428205
  mkdirSync as mkdirSync13,
428036
428206
  openSync as openSync8,
428207
+ readdirSync as readdirSync7,
428037
428208
  readFileSync as readFileSync25,
428038
428209
  realpathSync as realpathSync6,
428039
428210
  renameSync as renameSync5,
@@ -428428,13 +428599,70 @@ async function reapStaleEngine(portFile, opts) {
428428
428599
  }
428429
428600
  }
428430
428601
  }
428431
- function selectPort() {
428602
+ function otherSessionsMidTurn() {
428603
+ const dir = join118(getClaudeConfigHomeDir(), "sessions");
428604
+ let files2;
428605
+ try {
428606
+ files2 = readdirSync7(dir);
428607
+ } catch {
428608
+ return 0;
428609
+ }
428610
+ let busy = 0;
428611
+ for (const f of files2) {
428612
+ if (!/^\d+\.json$/.test(f)) continue;
428613
+ const pid = Number.parseInt(f.slice(0, -5), 10);
428614
+ if (pid === process.pid || !isProcessAlive(pid)) continue;
428615
+ try {
428616
+ const rec = JSON.parse(readFileSync25(join118(dir, f), "utf8"));
428617
+ if (rec.kind === "daemon") continue;
428618
+ if (rec.status !== "busy" && rec.status !== "waiting") continue;
428619
+ if (rec.startedAt !== void 0 && processStartedAfter(pid, rec.startedAt + 15e3) === true) {
428620
+ continue;
428621
+ }
428622
+ busy++;
428623
+ } catch {
428624
+ }
428625
+ }
428626
+ return busy;
428627
+ }
428628
+ function pinnedEnginePort() {
428432
428629
  const override = process.env.SEMA_ENGINE_PORT;
428433
428630
  if (override) {
428434
428631
  const p = Number.parseInt(override, 10);
428435
428632
  if (Number.isInteger(p) && p > 0 && p < 65536) return p;
428436
428633
  }
428437
- return DEFAULT_ENGINE_PORT;
428634
+ return null;
428635
+ }
428636
+ function portIsFree(port) {
428637
+ return new Promise((resolve53) => {
428638
+ const srv = createServer7();
428639
+ srv.once("error", () => resolve53(false));
428640
+ try {
428641
+ srv.listen({ port, host: "127.0.0.1", exclusive: true }, () => {
428642
+ srv.close(() => resolve53(true));
428643
+ });
428644
+ } catch {
428645
+ resolve53(false);
428646
+ }
428647
+ });
428648
+ }
428649
+ async function pickFreeEnginePort(configHome = getClaudeConfigHomeDir()) {
428650
+ const base = derivedDefaultEnginePort(configHome);
428651
+ for (let i = 0; i < DERIVED_PORT_PROBE_MAX; i++) {
428652
+ const candidate = derivedPortCandidate(base, i);
428653
+ if (await portIsFree(candidate)) {
428654
+ if (candidate !== base) {
428655
+ logForDebugging(
428656
+ `[engine-lifecycle] derived default port ${base} is busy \u2014 linear-probed to free port ${candidate}`
428657
+ );
428658
+ }
428659
+ return candidate;
428660
+ }
428661
+ }
428662
+ logForDebugging(
428663
+ `[engine-lifecycle] no free port within ${DERIVED_PORT_PROBE_MAX} probes from derived ${base} \u2014 falling back to ${base} (handshake gate reports honestly)`
428664
+ );
428665
+ return base;
428438
428666
  }
428439
428667
  async function initEngineLifecycle() {
428440
428668
  return recordInitResult(await initEngineLifecycleInner());
@@ -428482,10 +428710,21 @@ async function initEngineLifecycleInner() {
428482
428710
  const wantVersion = localEngineVersion();
428483
428711
  const versionStale = health2 !== null && wantVersion !== void 0 && health2.version !== wantVersion;
428484
428712
  const sourceStale = (existing.configSource ?? "local") !== engineConfigSource;
428485
- const desiredPort = selectPort();
428486
- const portStale = existing.port !== desiredPort;
428713
+ const desiredPort = pinnedEnginePort();
428714
+ const portStale = desiredPort !== null && existing.port !== desiredPort;
428487
428715
  const pidStale = health2 !== null && typeof health2.pid === "number" && health2.pid !== existing.pid;
428488
- if (health2 && !versionStale && !sourceStale && !portStale && !pidStale && healthIdentityMatches(health2, expectedDataRoot)) {
428716
+ const engineCompatible = health2 !== null && !versionStale && !sourceStale && !pidStale && healthIdentityMatches(health2, expectedDataRoot);
428717
+ let portMoveDeferred = false;
428718
+ if (engineCompatible && portStale) {
428719
+ const midTurn = otherSessionsMidTurn();
428720
+ if (midTurn > 0) {
428721
+ portMoveDeferred = true;
428722
+ logForDebugging(
428723
+ `[engine-lifecycle] port-config mismatch (anchor port=${existing.port} != configured ${desiredPort}) but ${midTurn} local session(s) are mid-turn \u2014 deferring the restart, reusing the engine on port ${existing.port} (the port moves on a later launch when no turn is in flight)`
428724
+ );
428725
+ }
428726
+ }
428727
+ if (engineCompatible && (!portStale || portMoveDeferred)) {
428489
428728
  const baseUrl2 = `http://127.0.0.1:${existing.port}`;
428490
428729
  const instance2 = {
428491
428730
  port: existing.port,
@@ -428513,7 +428752,7 @@ async function initEngineLifecycleInner() {
428513
428752
  await reapStaleEngine(existing, { killPid: false });
428514
428753
  }
428515
428754
  }
428516
- const port = selectPort();
428755
+ const port = pinnedEnginePort() ?? await pickFreeEnginePort(configHome);
428517
428756
  const entry = resolveEngineEntry();
428518
428757
  if (!entry) {
428519
428758
  logForDebugging(
@@ -428783,8 +429022,73 @@ function attachOwnedEngineExitWatch(instance) {
428783
429022
  function resetDeadRespawnStateForTests() {
428784
429023
  deadRespawnInFlight = false;
428785
429024
  recentDeathTimestamps = [];
429025
+ cooldownRetryPending = false;
429026
+ cooldownRetryLevel = 0;
429027
+ cooldownRetryFire = void 0;
429028
+ cooldownRetryAt = 0;
429029
+ if (cooldownRetryTimer) clearTimeout(cooldownRetryTimer);
429030
+ cooldownRetryTimer = void 0;
429031
+ }
429032
+ function nextCooldownDelayMs() {
429033
+ return Math.min(CRASH_LOOP_COOLDOWN_BASE_MS * 2 ** cooldownRetryLevel, CRASH_LOOP_COOLDOWN_CAP_MS);
429034
+ }
429035
+ function stampFailedNextRetryAt() {
429036
+ try {
429037
+ const cur = getEngineRuntimeStatus();
429038
+ if (cur.phase === "failed" && cooldownRetryAt > Date.now()) {
429039
+ setEngineRuntimeStatus({ phase: "failed", detail: cur.detail, nextRetryAt: cooldownRetryAt });
429040
+ }
429041
+ } catch {
429042
+ }
429043
+ }
429044
+ function scheduleCooldownRetry(deps2) {
429045
+ if (cooldownRetryPending) {
429046
+ stampFailedNextRetryAt();
429047
+ return;
429048
+ }
429049
+ cooldownRetryPending = true;
429050
+ const delay = nextCooldownDelayMs();
429051
+ cooldownRetryLevel++;
429052
+ logForDebugging(
429053
+ `[engine-lifecycle] engine auto-restart parked \u2014 cooldown retry scheduled in ${Math.round(delay / 1e3)}s`
429054
+ );
429055
+ const fire = () => {
429056
+ cooldownRetryPending = false;
429057
+ cooldownRetryFire = void 0;
429058
+ cooldownRetryAt = 0;
429059
+ if (cooldownRetryTimer) {
429060
+ clearTimeout(cooldownRetryTimer);
429061
+ cooldownRetryTimer = void 0;
429062
+ }
429063
+ recentDeathTimestamps = [];
429064
+ void runEngineDeadRespawn(deps2).catch(() => {
429065
+ });
429066
+ };
429067
+ cooldownRetryFire = fire;
429068
+ cooldownRetryAt = Date.now() + delay;
429069
+ stampFailedNextRetryAt();
429070
+ if (deps2.scheduleRetry) {
429071
+ deps2.scheduleRetry(fire, delay);
429072
+ return;
429073
+ }
429074
+ cooldownRetryTimer = setTimeout(fire, delay);
429075
+ if (typeof cooldownRetryTimer.unref === "function") cooldownRetryTimer.unref();
429076
+ }
429077
+ function requestEngineRetryNow() {
429078
+ if (!cooldownRetryPending || !cooldownRetryFire) return false;
429079
+ if (deadRespawnInFlight) return false;
429080
+ logForDebugging("[engine-lifecycle] manual retry-now requested \u2014 firing the parked cooldown retry immediately");
429081
+ cooldownRetryFire();
429082
+ return true;
428786
429083
  }
428787
429084
  async function runEngineDeadRespawn(deps2) {
429085
+ if (isShellHostDead()) {
429086
+ logForDebugging(
429087
+ "[engine-lifecycle] host terminal is gone \u2014 refusing engine respawn, shutting down the orphaned shell"
429088
+ );
429089
+ teardownOwnedEngineSync("orphan-respawn-guard");
429090
+ process.exit(129);
429091
+ }
428788
429092
  if (deadRespawnInFlight) return false;
428789
429093
  deadRespawnInFlight = true;
428790
429094
  const now2 = deps2.now ?? Date.now;
@@ -428795,13 +429099,17 @@ async function runEngineDeadRespawn(deps2) {
428795
429099
  recentDeathTimestamps = recentDeathTimestamps.filter((d2) => t2 - d2 < CRASH_LOOP_WINDOW_MS);
428796
429100
  recentDeathTimestamps.push(t2);
428797
429101
  if (recentDeathTimestamps.length > CRASH_LOOP_MAX_DEATHS) {
429102
+ const retryInS = Math.round(nextCooldownDelayMs() / 1e3);
428798
429103
  logForDebugging(
428799
- `[engine-lifecycle] engine died ${recentDeathTimestamps.length} times inside ${CRASH_LOOP_WINDOW_MS / 6e4}min \u2014 crash loop, auto-restart paused`
429104
+ `[engine-lifecycle] engine died ${recentDeathTimestamps.length} times inside ${CRASH_LOOP_WINDOW_MS / 6e4}min \u2014 crash loop, auto-restart paused (cooldown retry in ${retryInS}s)`
428800
429105
  );
428801
429106
  setEngineRuntimeStatus({
428802
429107
  phase: "failed",
428803
- detail: `engine crashed ${recentDeathTimestamps.length} times in ${CRASH_LOOP_WINDOW_MS / 6e4} minutes \u2014 auto-restart paused; check the engine log or run sema doctor`
429108
+ // detail 保留「retrying automatically in ~Ns」静态估计(headless bg 的 state.json 只见 detail);
429109
+ // 交互 footer 另有 nextRetryAt 活倒计时(渲染时剥掉这里的静态估计,不双报)。
429110
+ detail: `engine crashed ${recentDeathTimestamps.length} times in ${CRASH_LOOP_WINDOW_MS / 6e4} minutes \u2014 auto-restart paused; retrying automatically in ~${retryInS}s (or run sema doctor)`
428804
429111
  });
429112
+ scheduleCooldownRetry(deps2);
428805
429113
  return false;
428806
429114
  }
428807
429115
  for (let i = 0; i < backoff3.length; i++) {
@@ -428814,6 +429122,7 @@ async function runEngineDeadRespawn(deps2) {
428814
429122
  }
428815
429123
  if (ok2) {
428816
429124
  logForDebugging(`[engine-lifecycle] dead-respawn succeeded on attempt ${i + 1}/${backoff3.length}`);
429125
+ cooldownRetryLevel = 0;
428817
429126
  setEngineRuntimeStatus({ phase: "recovered" });
428818
429127
  return true;
428819
429128
  }
@@ -428824,13 +429133,146 @@ async function runEngineDeadRespawn(deps2) {
428824
429133
  }
428825
429134
  setEngineRuntimeStatus({
428826
429135
  phase: "failed",
428827
- detail: `automatic engine restart failed after ${backoff3.length} attempts \u2014 run sema doctor or restart sema`
429136
+ detail: `automatic engine restart failed after ${backoff3.length} attempts \u2014 retrying automatically in ${Math.round(nextCooldownDelayMs() / 1e3)}s (or run sema doctor / restart sema)`
428828
429137
  });
429138
+ scheduleCooldownRetry(deps2);
428829
429139
  return false;
428830
429140
  } finally {
428831
429141
  deadRespawnInFlight = false;
428832
429142
  }
428833
429143
  }
429144
+ function orphanWatchEligible() {
429145
+ if (process.env.SEMA_CODE_SESSION_KIND) return false;
429146
+ if (process.env.SEMA_JOB_DIR) return false;
429147
+ return process.stdin.isTTY === true && process.stdout.isTTY === true;
429148
+ }
429149
+ function isShellHostDead() {
429150
+ if (!orphanWatchEligible()) return false;
429151
+ return !process.stdout.writable || !process.stdin.readable;
429152
+ }
429153
+ function otherLiveSemaSessions() {
429154
+ const dir = join118(getClaudeConfigHomeDir(), "sessions");
429155
+ let files2;
429156
+ try {
429157
+ files2 = readdirSync7(dir);
429158
+ } catch {
429159
+ return 0;
429160
+ }
429161
+ let live = 0;
429162
+ for (const f of files2) {
429163
+ if (!/^\d+\.json$/.test(f)) continue;
429164
+ const pid = Number.parseInt(f.slice(0, -5), 10);
429165
+ if (pid === process.pid || !isProcessAlive(pid)) continue;
429166
+ try {
429167
+ const rec = JSON.parse(readFileSync25(join118(dir, f), "utf8"));
429168
+ if (rec.kind === "daemon") continue;
429169
+ if (rec.startedAt !== void 0 && processStartedAfter(pid, rec.startedAt + 15e3) === true) {
429170
+ continue;
429171
+ }
429172
+ live++;
429173
+ } catch {
429174
+ }
429175
+ }
429176
+ return live;
429177
+ }
429178
+ function pickTeardownTarget() {
429179
+ const inst = teardownGetInstance ? teardownGetInstance() : null;
429180
+ if (inst && inst.ownedByThisShell && isProcessAlive(inst.pid)) {
429181
+ return { pid: inst.pid, why: "owned" };
429182
+ }
429183
+ if (!localEngineActive) return null;
429184
+ const anchor = readPortFile(getEnginePortFilePath());
429185
+ if (!anchor || !isProcessAlive(anchor.pid)) return null;
429186
+ if (anchor.startedAt && processStartedAfter(anchor.pid, anchor.startedAt + 15e3) === true) {
429187
+ return null;
429188
+ }
429189
+ return { pid: anchor.pid, why: "anchor(last-session)" };
429190
+ }
429191
+ function cleanupAnchorForPid(pid) {
429192
+ try {
429193
+ const portPath = getEnginePortFilePath();
429194
+ const current3 = readPortFile(portPath);
429195
+ if (current3 && current3.pid === pid) {
429196
+ unlinkSync6(portPath);
429197
+ removeEngineTokenFile(getClaudeConfigHomeDir());
429198
+ }
429199
+ } catch {
429200
+ }
429201
+ }
429202
+ function teardownOwnedEngineSync(reason) {
429203
+ if (teardownDone) return;
429204
+ teardownDone = true;
429205
+ try {
429206
+ const target = pickTeardownTarget();
429207
+ if (!target) return;
429208
+ const peers = otherLiveSemaSessions();
429209
+ if (peers > 0) {
429210
+ logForDebugging(
429211
+ `[engine-lifecycle] exit teardown (${reason}): ${peers} other live sema session(s) still use the engine \u2014 leaving pid=${target.pid} running`
429212
+ );
429213
+ return;
429214
+ }
429215
+ logForDebugging(
429216
+ `[engine-lifecycle] exit teardown (${reason}): reaping ${target.why} engine pid=${target.pid} (no other live sessions)`
429217
+ );
429218
+ markEngineExitExpected(target.pid);
429219
+ try {
429220
+ process.kill(target.pid, "SIGTERM");
429221
+ } catch {
429222
+ }
429223
+ cleanupAnchorForPid(target.pid);
429224
+ } catch (e) {
429225
+ logForDebugging(`[engine-lifecycle] exit teardown (${reason}) error: ${String(e)}`);
429226
+ }
429227
+ }
429228
+ function resetEngineExitTeardownForTests() {
429229
+ teardownDone = false;
429230
+ }
429231
+ function setLocalEngineActiveForTests(v2) {
429232
+ localEngineActive = v2;
429233
+ }
429234
+ function installEngineExitTeardown(getInstance2) {
429235
+ teardownGetInstance = getInstance2;
429236
+ if (teardownInstalled) return;
429237
+ teardownInstalled = true;
429238
+ process.once("exit", () => teardownOwnedEngineSync("process-exit"));
429239
+ const onSignal = (sig, code2) => {
429240
+ let fired2 = false;
429241
+ process.on(sig, () => {
429242
+ if (fired2) return;
429243
+ fired2 = true;
429244
+ teardownOwnedEngineSync(`signal:${sig}`);
429245
+ setImmediate(() => {
429246
+ try {
429247
+ process.removeAllListeners(sig);
429248
+ process.kill(process.pid, sig);
429249
+ } catch {
429250
+ }
429251
+ setTimeout(() => {
429252
+ process.exit(code2);
429253
+ }, 200);
429254
+ });
429255
+ });
429256
+ };
429257
+ onSignal("SIGTERM", 143);
429258
+ onSignal("SIGHUP", 129);
429259
+ onSignal("SIGINT", 130);
429260
+ if (orphanWatchEligible()) {
429261
+ const pollMs = (() => {
429262
+ const v2 = Number.parseInt(process.env.SEMA_ORPHAN_POLL_MS ?? "", 10);
429263
+ return Number.isInteger(v2) && v2 >= 200 ? v2 : 15e3;
429264
+ })();
429265
+ const orphanTimer = setInterval(() => {
429266
+ if (isShellHostDead()) {
429267
+ clearInterval(orphanTimer);
429268
+ logForDebugging("[engine-lifecycle] TTY revoked (terminal closed) \u2014 teardown + exit");
429269
+ teardownOwnedEngineSync("tty-orphan");
429270
+ process.exit(129);
429271
+ }
429272
+ }, pollMs);
429273
+ if (typeof orphanTimer.unref === "function") orphanTimer.unref();
429274
+ }
429275
+ }
428834
429276
  async function shutdownEngine(instance) {
428835
429277
  if (!instance) return;
428836
429278
  if (!instance.ownedByThisShell) {
@@ -428926,15 +429368,16 @@ async function waitForExit(pid, timeoutMs) {
428926
429368
  }
428927
429369
  return !isProcessAlive(pid);
428928
429370
  }
428929
- var DEFAULT_ENGINE_PORT, PORT_FILE_VERSION, HEALTH_POLL_INTERVAL_MS, HEALTH_POLL_MAX_ATTEMPTS, HEALTH_FETCH_TIMEOUT_MS, HEARTBEAT_INTERVAL_MS2, HEARTBEAT_MAX_MISSES, SHUTDOWN_GRACE_MS, SHUTDOWN_SECOND_TERM_GRACE_MS, LOCK_OPTS3, WORKFLOW_SIZE_GUIDELINE_VALUES, lastServiceAuthToken, lastInitFailureReason, lastInitFailureDetail, localEngineActive, expectedExitPids, onOwnedEngineExitCb, deadRespawnInFlight, CRASH_LOOP_WINDOW_MS, CRASH_LOOP_MAX_DEATHS, recentDeathTimestamps;
429371
+ var PORT_FILE_VERSION, HEALTH_POLL_INTERVAL_MS, HEALTH_POLL_MAX_ATTEMPTS, HEALTH_FETCH_TIMEOUT_MS, HEARTBEAT_INTERVAL_MS2, HEARTBEAT_MAX_MISSES, SHUTDOWN_GRACE_MS, SHUTDOWN_SECOND_TERM_GRACE_MS, LOCK_OPTS3, WORKFLOW_SIZE_GUIDELINE_VALUES, lastServiceAuthToken, lastInitFailureReason, lastInitFailureDetail, localEngineActive, DERIVED_PORT_PROBE_MAX, expectedExitPids, onOwnedEngineExitCb, deadRespawnInFlight, CRASH_LOOP_WINDOW_MS, CRASH_LOOP_MAX_DEATHS, recentDeathTimestamps, CRASH_LOOP_COOLDOWN_BASE_MS, CRASH_LOOP_COOLDOWN_CAP_MS, cooldownRetryPending, cooldownRetryLevel, cooldownRetryFire, cooldownRetryTimer, cooldownRetryAt, teardownGetInstance, teardownInstalled, teardownDone;
428930
429372
  var init_engineLifecycleManager = __esm({
428931
429373
  "build-src/src/sema/engineLifecycleManager.ts"() {
429374
+ init_state2();
428932
429375
  init_envUtils();
429376
+ init_enginePortDerive();
428933
429377
  init_ccConfigFallback();
428934
429378
  init_engineRuntimeStatus();
428935
429379
  init_lockfile();
428936
429380
  init_debug();
428937
- DEFAULT_ENGINE_PORT = 47362;
428938
429381
  PORT_FILE_VERSION = 1;
428939
429382
  HEALTH_POLL_INTERVAL_MS = 200;
428940
429383
  HEALTH_POLL_MAX_ATTEMPTS = 75;
@@ -428946,12 +429389,519 @@ var init_engineLifecycleManager = __esm({
428946
429389
  LOCK_OPTS3 = { stale: 1e4, retries: { retries: 3, minTimeout: 50 } };
428947
429390
  WORKFLOW_SIZE_GUIDELINE_VALUES = ["unrestricted", "small", "medium", "large"];
428948
429391
  localEngineActive = false;
429392
+ DERIVED_PORT_PROBE_MAX = 32;
428949
429393
  expectedExitPids = /* @__PURE__ */ new Set();
428950
429394
  onOwnedEngineExitCb = null;
428951
429395
  deadRespawnInFlight = false;
428952
429396
  CRASH_LOOP_WINDOW_MS = 5 * 6e4;
428953
429397
  CRASH_LOOP_MAX_DEATHS = 3;
428954
429398
  recentDeathTimestamps = [];
429399
+ CRASH_LOOP_COOLDOWN_BASE_MS = 6e4;
429400
+ CRASH_LOOP_COOLDOWN_CAP_MS = 10 * 6e4;
429401
+ cooldownRetryPending = false;
429402
+ cooldownRetryLevel = 0;
429403
+ cooldownRetryAt = 0;
429404
+ teardownGetInstance = null;
429405
+ teardownInstalled = false;
429406
+ teardownDone = false;
429407
+ }
429408
+ });
429409
+
429410
+ // build-src/src/utils/sessionState.ts
429411
+ function setSessionStateChangedListener(cb) {
429412
+ stateListener = cb;
429413
+ }
429414
+ function setSessionMetadataChangedListener(cb) {
429415
+ metadataListener = cb;
429416
+ }
429417
+ function setPermissionModeChangedListener(cb) {
429418
+ permissionModeListener = cb;
429419
+ }
429420
+ function getSessionState() {
429421
+ return currentState;
429422
+ }
429423
+ function notifySessionStateChanged(state3, details) {
429424
+ currentState = state3;
429425
+ stateListener?.(state3, details);
429426
+ if (state3 === "requires_action" && details) {
429427
+ hasPendingAction = true;
429428
+ metadataListener?.({
429429
+ pending_action: details
429430
+ });
429431
+ } else if (hasPendingAction) {
429432
+ hasPendingAction = false;
429433
+ metadataListener?.({ pending_action: null });
429434
+ }
429435
+ if (state3 === "idle") {
429436
+ metadataListener?.({ task_summary: null });
429437
+ }
429438
+ if (isEnvTruthy(process.env.SEMA_CODE_EMIT_SESSION_STATE_EVENTS)) {
429439
+ enqueueSdkEvent({
429440
+ type: "system",
429441
+ subtype: "session_state_changed",
429442
+ state: state3
429443
+ });
429444
+ }
429445
+ }
429446
+ function notifySessionMetadataChanged(metadata2) {
429447
+ metadataListener?.(metadata2);
429448
+ }
429449
+ function notifyPermissionModeChanged(mode) {
429450
+ permissionModeListener?.(mode);
429451
+ }
429452
+ var stateListener, metadataListener, permissionModeListener, hasPendingAction, currentState;
429453
+ var init_sessionState = __esm({
429454
+ "build-src/src/utils/sessionState.ts"() {
429455
+ init_envUtils();
429456
+ init_sdkEventQueue();
429457
+ stateListener = null;
429458
+ metadataListener = null;
429459
+ permissionModeListener = null;
429460
+ hasPendingAction = false;
429461
+ currentState = "idle";
429462
+ }
429463
+ });
429464
+
429465
+ // build-src/src/utils/taskSummary.ts
429466
+ var taskSummary_exports = {};
429467
+ __export(taskSummary_exports, {
429468
+ bgJobShort: () => bgJobShort,
429469
+ blockedSummaryFor: () => blockedSummaryFor,
429470
+ classifiedToPostTurnSummary: () => classifiedToPostTurnSummary,
429471
+ classifierSummaryEnabled: () => classifierSummaryEnabled,
429472
+ classifyTurnTail: () => classifyTurnTail,
429473
+ emitTurnEndSummary: () => emitTurnEndSummary,
429474
+ heuristicFallback: () => heuristicFallback,
429475
+ notifySessionActivityForSummary: () => notifySessionActivityForSummary,
429476
+ preClassifyTail: () => preClassifyTail,
429477
+ reportBgEngineDown: () => reportBgEngineDown,
429478
+ runClassifierSummaryForBlocked: () => runClassifierSummaryForBlocked,
429479
+ turnTail: () => turnTail
429480
+ });
429481
+ import { basename as basename35 } from "path";
429482
+ function classifierSummaryEnabled() {
429483
+ const v2 = process.env.SEMA_CODE_CLASSIFIER_SUMMARY ?? process.env[CLASSIFIER_SUMMARY_ENV];
429484
+ if (v2 === void 0) return true;
429485
+ return !/^(0|false|off|no|none)$/i.test(v2.trim());
429486
+ }
429487
+ function bgJobShort() {
429488
+ const dir = process.env.SEMA_JOB_DIR;
429489
+ if (!dir) return null;
429490
+ const short = basename35(dir);
429491
+ return short.length > 0 ? short : null;
429492
+ }
429493
+ function truncateDetail(s, max2 = DETAIL_MAX) {
429494
+ if (s.length <= max2) return s;
429495
+ let r = max2 - 1;
429496
+ const c2 = s.charCodeAt(r - 1);
429497
+ if (c2 >= 55296 && c2 <= 56319) r--;
429498
+ return s.slice(0, r) + "\u2026";
429499
+ }
429500
+ function insideCodeFence(e, t2) {
429501
+ let open20 = null;
429502
+ let openLen = 0;
429503
+ let o = 0;
429504
+ while (o < t2) {
429505
+ const i = e.indexOf("```", o);
429506
+ const s = e.indexOf("~~~", o);
429507
+ const a = i === -1 ? s : s === -1 ? i : Math.min(i, s);
429508
+ if (a === -1 || a >= t2) break;
429509
+ const ch2 = e[a];
429510
+ let c2 = a - 1;
429511
+ let u3 = 0;
429512
+ while (c2 >= 0 && e[c2] === " " && u3 < 3) {
429513
+ c2--;
429514
+ u3++;
429515
+ }
429516
+ const atLineStart = c2 < 0 || e[c2] === "\n";
429517
+ let len = 3;
429518
+ o = a + 3;
429519
+ while (e[o] === ch2) {
429520
+ o++;
429521
+ len++;
429522
+ }
429523
+ if (!atLineStart) continue;
429524
+ if (open20 === null) {
429525
+ open20 = ch2;
429526
+ openLen = len;
429527
+ } else if (open20 === ch2 && len >= openLen) {
429528
+ open20 = null;
429529
+ openLen = 0;
429530
+ }
429531
+ }
429532
+ return open20 !== null;
429533
+ }
429534
+ function latestMarker(full, window2, windowStart) {
429535
+ let best;
429536
+ const table = [
429537
+ ["failed", FAILED_MARKER],
429538
+ ["blocked", NEEDS_INPUT_MARKER],
429539
+ ["blocked", BLOCKED_MARKER],
429540
+ ["blocked", IM_BLOCKED_MARKER]
429541
+ ];
429542
+ for (const [state3, re] of table) {
429543
+ for (const m2 of window2.matchAll(re)) {
429544
+ if (insideCodeFence(full, windowStart + m2.index)) continue;
429545
+ if (!best || m2.index > best.index) {
429546
+ best = {
429547
+ state: state3,
429548
+ capture: m2[1].trim(),
429549
+ index: m2.index,
429550
+ end: m2.index + m2[0].length
429551
+ };
429552
+ }
429553
+ }
429554
+ }
429555
+ return best;
429556
+ }
429557
+ function preClassifyTail(text2) {
429558
+ const t2 = text2.trim();
429559
+ if (!t2) return null;
429560
+ let window2 = t2.slice(-800);
429561
+ let windowStart = t2.length - window2.length;
429562
+ let resultMatch;
429563
+ for (const m2 of window2.matchAll(/(?:^|\n)\s*result:\s*(.+?)\s*(?:\n|$)/gi)) {
429564
+ if (!insideCodeFence(t2, windowStart + m2.index)) resultMatch = m2;
429565
+ }
429566
+ if (resultMatch) {
429567
+ const after = resultMatch.index + resultMatch[0].length;
429568
+ window2 = window2.slice(after);
429569
+ windowStart += after;
429570
+ }
429571
+ const marker = latestMarker(t2, window2, windowStart);
429572
+ if (resultMatch && !marker) {
429573
+ const detail = truncateDetail(resultMatch[1]);
429574
+ const hasNext = [...window2.matchAll(/(?:^|\n)\s*next:\s*\S/gi)].some(
429575
+ (m2) => !insideCodeFence(t2, windowStart + m2.index)
429576
+ );
429577
+ if (hasNext) return { branch: "result-then-next", state: "working", tempo: "idle", detail };
429578
+ return { branch: "result-marker", state: "done", tempo: "idle", detail };
429579
+ }
429580
+ if (marker?.state === "failed") {
429581
+ return { branch: "failed-marker", state: "failed", tempo: "idle", detail: truncateDetail(marker.capture) };
429582
+ }
429583
+ if (marker?.state === "blocked") {
429584
+ const after = window2.slice(marker.end);
429585
+ const paras = after.split(/\n\s*\n/).filter((p) => p.trim().length > 0).length;
429586
+ if (paras >= 3) return null;
429587
+ if (!/\bnothing (?:needed|required) from you\b|\bno(?: user)? action (?:needed|required)\b/i.test(
429588
+ window2
429589
+ )) {
429590
+ const m2 = truncateDetail(marker.capture);
429591
+ return { branch: "blocked-marker", state: "blocked", tempo: "blocked", needs: m2, detail: m2 };
429592
+ }
429593
+ return null;
429594
+ }
429595
+ const tail800 = t2.slice(-800);
429596
+ if (/[??]\s*$/.test(tail800) && tail800.replace(/[??\s]+$/, "").length >= 4) {
429597
+ const f = Math.max(
429598
+ tail800.lastIndexOf("\n"),
429599
+ tail800.lastIndexOf(". "),
429600
+ tail800.lastIndexOf("! "),
429601
+ tail800.lastIndexOf("? ", tail800.length - 2)
429602
+ );
429603
+ if (!insideCodeFence(t2, t2.length - tail800.length + f)) {
429604
+ const q2 = truncateDetail(tail800.slice(f + 1).trim());
429605
+ if (!OPTIONAL_OFFER.test(q2)) {
429606
+ return { branch: "trailing-q", state: "blocked", tempo: "blocked", needs: q2, detail: q2 };
429607
+ }
429608
+ return null;
429609
+ }
429610
+ }
429611
+ const a = Math.max(
429612
+ 0,
429613
+ tail800.lastIndexOf(". "),
429614
+ tail800.lastIndexOf("! "),
429615
+ tail800.lastIndexOf("? "),
429616
+ tail800.lastIndexOf("\n")
429617
+ );
429618
+ const l3 = tail800.slice(a).replace(/^[.!?\s]+/, "");
429619
+ const fenced = insideCodeFence(t2, t2.length - tail800.length + a);
429620
+ const waitExt = WAIT_EXTERNAL.exec(l3);
429621
+ if (waitExt && !fenced) {
429622
+ return { branch: "wait-external", state: "working", tempo: "idle", detail: truncateDetail(waitExt[0]) };
429623
+ }
429624
+ const awaiting = AWAITING_USER.exec(l3);
429625
+ if (awaiting && !fenced) {
429626
+ const f = truncateDetail(l3.slice(awaiting.index).trim());
429627
+ return { branch: "awaiting-user", state: "blocked", tempo: "blocked", needs: f, detail: f };
429628
+ }
429629
+ const ask2 = ASK_VERB.exec(l3);
429630
+ if (ask2 && !fenced) {
429631
+ const f = truncateDetail(l3.slice(ask2.index).trim());
429632
+ return { branch: "ask-verb", state: "blocked", tempo: "blocked", needs: f, detail: f };
429633
+ }
429634
+ if (!fenced && AUTH_PROSE.test(l3)) {
429635
+ return {
429636
+ branch: "auth-prose",
429637
+ state: "blocked",
429638
+ tempo: "blocked",
429639
+ needs: truncateDetail(l3),
429640
+ detail: "authentication required"
429641
+ };
429642
+ }
429643
+ if (!fenced && WORKING_VERB.test(l3) && !NOT_FORWARD_INTENT.test(l3)) {
429644
+ return { branch: "working-verb", state: "working", tempo: "active", detail: truncateDetail(l3) };
429645
+ }
429646
+ if (!fenced && AGENTS_STATUS.test(l3)) {
429647
+ return { branch: "agents-status", state: "working", tempo: "idle", detail: truncateDetail(l3) };
429648
+ }
429649
+ if (!fenced && WILL_CHECK_BACK.test(l3)) {
429650
+ return { branch: "will-check-back", state: "working", tempo: "idle", detail: truncateDetail(l3) };
429651
+ }
429652
+ if (!fenced && CANT_PROCEED.test(l3)) {
429653
+ const f = truncateDetail(l3);
429654
+ return { branch: "cant-proceed", state: "blocked", tempo: "blocked", detail: f, needs: f };
429655
+ }
429656
+ if (!fenced && GIVING_UP.test(l3)) {
429657
+ return { branch: "giving-up", state: "failed", tempo: "idle", detail: truncateDetail(l3) };
429658
+ }
429659
+ if (!fenced && PUSHED_COMMITTED.test(l3)) {
429660
+ return { branch: "pushed-committed", state: "done", tempo: "idle", detail: truncateDetail(l3) };
429661
+ }
429662
+ if (!fenced && READY_FOR.test(l3)) {
429663
+ return { branch: "ready-for", state: "done", tempo: "idle", detail: truncateDetail(l3) };
429664
+ }
429665
+ if (!fenced && VERDICT_MARKER.test(l3)) {
429666
+ return { branch: "verdict-marker", state: "done", tempo: "idle", detail: truncateDetail(l3) };
429667
+ }
429668
+ if (!fenced && PLEASE_DO_X.test(l3)) {
429669
+ const f = truncateDetail(l3);
429670
+ return { branch: "please-do-x", state: "blocked", tempo: "blocked", detail: f, needs: f };
429671
+ }
429672
+ if (!fenced && STOPPING_HERE.test(l3)) {
429673
+ const f = truncateDetail(l3);
429674
+ return { branch: "stopping-here", state: "blocked", tempo: "blocked", detail: f, needs: f };
429675
+ }
429676
+ return null;
429677
+ }
429678
+ function heuristicFallback(text2) {
429679
+ const line = text2.split("\n").map((l3) => l3.trim()).findLast(Boolean);
429680
+ return {
429681
+ branch: "heuristic",
429682
+ state: "working",
429683
+ tempo: "idle",
429684
+ detail: line ? truncateDetail(line) : "\u2014"
429685
+ };
429686
+ }
429687
+ function classifyTurnTail(text2) {
429688
+ const c2 = preClassifyTail(text2) ?? heuristicFallback(text2);
429689
+ if (c2.tempo === "active" && c2.state === "working") return { ...c2, tempo: "idle" };
429690
+ return c2;
429691
+ }
429692
+ function classifiedToPostTurnSummary(c2) {
429693
+ return {
429694
+ status_category: c2.state === "blocked" ? "blocked" : "review_ready",
429695
+ status_detail: c2.detail,
429696
+ needs_action: c2.state === "blocked" ? c2.needs ?? "" : ""
429697
+ };
429698
+ }
429699
+ function assistantText(m2) {
429700
+ const c2 = m2.message?.content;
429701
+ if (typeof c2 === "string") return c2.trim();
429702
+ if (!Array.isArray(c2)) return "";
429703
+ return c2.map((b3) => b3?.type === "text" && typeof b3.text === "string" ? b3.text : "").filter(Boolean).join("\n").trim();
429704
+ }
429705
+ function turnTail(messages) {
429706
+ const msgs = messages;
429707
+ let start = 0;
429708
+ for (let i = msgs.length - 1; i >= 0; i--) {
429709
+ const m2 = msgs[i];
429710
+ if (m2.type === "user" && !m2.isMeta && typeof m2.message?.content === "string") {
429711
+ start = i + 1;
429712
+ break;
429713
+ }
429714
+ }
429715
+ const parts = [];
429716
+ let lastAssistantUuid = "";
429717
+ for (let i = start; i < msgs.length; i++) {
429718
+ const m2 = msgs[i];
429719
+ if (m2.type !== "assistant" || m2.isApiErrorMessage) continue;
429720
+ const text2 = assistantText(m2);
429721
+ if (text2) parts.push(text2);
429722
+ if (typeof m2.uuid === "string") lastAssistantUuid = m2.uuid;
429723
+ }
429724
+ return { text: parts.join("\n\n"), lastAssistantUuid };
429725
+ }
429726
+ function chainBgWrite(fn2) {
429727
+ bgWriteChain = bgWriteChain.then(fn2).catch(() => {
429728
+ });
429729
+ return bgWriteChain;
429730
+ }
429731
+ async function writeBgTurnEnd(short, c2) {
429732
+ bgBlockedByActivity = false;
429733
+ const cur = await readJobState(short);
429734
+ if (!cur) return;
429735
+ const curTerminal = isTerminalJobState(cur.state);
429736
+ const nextTerminal = c2.state === "done" || c2.state === "failed";
429737
+ const terminal = curTerminal || nextTerminal;
429738
+ await patchJobState(short, {
429739
+ state: curTerminal ? cur.state : c2.state,
429740
+ detail: c2.detail,
429741
+ tempo: terminal ? "idle" : c2.tempo,
429742
+ needs: c2.tempo === "blocked" && !terminal ? c2.needs : void 0,
429743
+ ...terminal && !cur.firstTerminalAt ? { firstTerminalAt: Date.now() } : {}
429744
+ });
429745
+ }
429746
+ function reportBgEngineDown(detail) {
429747
+ const short = bgJobShort();
429748
+ if (!short) return;
429749
+ void chainBgWrite(async () => {
429750
+ const cur = await readJobState(short);
429751
+ if (!cur || isTerminalJobState(cur.state)) return;
429752
+ await patchJobState(short, {
429753
+ state: "failed",
429754
+ detail: `engine down \u2014 ${detail}`,
429755
+ tempo: "idle",
429756
+ needs: void 0,
429757
+ firstTerminalAt: cur.firstTerminalAt ?? Date.now()
429758
+ });
429759
+ });
429760
+ }
429761
+ function emitForegroundSummary(c2, summarizesUuid) {
429762
+ const y2 = classifiedToPostTurnSummary(c2);
429763
+ notifySessionMetadataChanged({ post_turn_summary: y2 });
429764
+ enqueueSdkEvent({
429765
+ type: "system",
429766
+ subtype: "post_turn_summary",
429767
+ summarizes_uuid: summarizesUuid,
429768
+ status_category: y2.status_category,
429769
+ status_detail: y2.status_detail,
429770
+ needs_action: y2.needs_action,
429771
+ is_noteworthy: false,
429772
+ title: "",
429773
+ description: "",
429774
+ recent_action: "",
429775
+ artifact_urls: []
429776
+ });
429777
+ }
429778
+ async function emitTurnEndSummary(messages) {
429779
+ if (!classifierSummaryEnabled()) return;
429780
+ const { text: text2, lastAssistantUuid } = turnTail(messages);
429781
+ if (!/[\p{L}\p{N}]/u.test(text2)) return;
429782
+ const classified = classifyTurnTail(text2);
429783
+ const short = bgJobShort();
429784
+ if (short) {
429785
+ await chainBgWrite(() => writeBgTurnEnd(short, classified));
429786
+ return;
429787
+ }
429788
+ emitForegroundSummary(classified, lastAssistantUuid);
429789
+ }
429790
+ function blockedSummaryFor(details) {
429791
+ if (details.tool_name.startsWith("dialog:")) {
429792
+ return {
429793
+ status_category: "blocked",
429794
+ status_detail: "Waiting on a user dialog",
429795
+ needs_action: details.action_description ?? ""
429796
+ };
429797
+ }
429798
+ return {
429799
+ status_category: "blocked",
429800
+ status_detail: `Waiting on permission: ${details.tool_name}`,
429801
+ needs_action: `Approve or deny ${details.tool_name}`
429802
+ };
429803
+ }
429804
+ function runClassifierSummaryForBlocked(details) {
429805
+ if (!classifierSummaryEnabled()) return;
429806
+ if (bgJobShort()) return;
429807
+ notifySessionMetadataChanged({ post_turn_summary: blockedSummaryFor(details) });
429808
+ }
429809
+ async function writeBgBlocked(short, summary) {
429810
+ const cur = await readJobState(short);
429811
+ if (!cur || isTerminalJobState(cur.state)) return;
429812
+ if (cur.tempo === "blocked" && cur.needs === summary.needs_action) return;
429813
+ await patchJobState(short, {
429814
+ state: "blocked",
429815
+ tempo: "blocked",
429816
+ detail: summary.status_detail,
429817
+ needs: summary.needs_action || summary.status_detail
429818
+ });
429819
+ }
429820
+ async function writeBgUnblocked(short, busy) {
429821
+ const cur = await readJobState(short);
429822
+ if (!cur) return;
429823
+ if (busy) {
429824
+ bgBlockedByActivity = false;
429825
+ if (cur.tempo === "active" && !isTerminalJobState(cur.state) && cur.state !== "blocked") return;
429826
+ const reviving = isTerminalJobState(cur.state);
429827
+ await patchJobState(
429828
+ short,
429829
+ {
429830
+ state: reviving || cur.state === "blocked" ? "working" : cur.state,
429831
+ tempo: "active",
429832
+ needs: void 0,
429833
+ ...reviving ? { firstTerminalAt: void 0 } : {}
429834
+ },
429835
+ { allowRevive: true }
429836
+ );
429837
+ return;
429838
+ }
429839
+ if (!bgBlockedByActivity) return;
429840
+ bgBlockedByActivity = false;
429841
+ if (cur.tempo !== "blocked" || isSettledJobState(cur)) return;
429842
+ await patchJobState(short, {
429843
+ state: cur.state === "blocked" ? "working" : cur.state,
429844
+ tempo: "idle",
429845
+ needs: void 0
429846
+ });
429847
+ }
429848
+ function notifySessionActivityForSummary(input) {
429849
+ if (!classifierSummaryEnabled()) return;
429850
+ const prev = prevActivityStatus;
429851
+ prevActivityStatus = input.status;
429852
+ const short = bgJobShort();
429853
+ if (input.status === "waiting") {
429854
+ const w2 = input.waitingFor ?? "";
429855
+ const details = w2.startsWith("approve ") ? { tool_name: w2.slice("approve ".length), action_description: w2 } : { tool_name: "dialog:" + (w2 || "input"), action_description: w2 || "input needed" };
429856
+ const summary = blockedSummaryFor(details);
429857
+ if (short) {
429858
+ bgBlockedByActivity = true;
429859
+ void chainBgWrite(() => writeBgBlocked(short, summary));
429860
+ } else {
429861
+ notifySessionMetadataChanged({ post_turn_summary: summary });
429862
+ }
429863
+ return;
429864
+ }
429865
+ if (input.status === "idle" && prev === "busy" && input.getMessages) {
429866
+ const messages = input.getMessages();
429867
+ void emitTurnEndSummary(messages);
429868
+ return;
429869
+ }
429870
+ if (short) {
429871
+ void chainBgWrite(() => writeBgUnblocked(short, input.status === "busy"));
429872
+ }
429873
+ }
429874
+ var CLASSIFIER_SUMMARY_ENV, DETAIL_MAX, FAILED_MARKER, NEEDS_INPUT_MARKER, BLOCKED_MARKER, IM_BLOCKED_MARKER, OPTIONAL_OFFER, WORKING_VERB, NOT_FORWARD_INTENT, AGENTS_STATUS, WILL_CHECK_BACK, CANT_PROCEED, GIVING_UP, PUSHED_COMMITTED, READY_FOR, VERDICT_MARKER, PLEASE_DO_X, STOPPING_HERE, WAIT_EXTERNAL, AWAITING_USER, ASK_VERB, AUTH_PROSE, bgWriteChain, bgBlockedByActivity, prevActivityStatus;
429875
+ var init_taskSummary = __esm({
429876
+ "build-src/src/utils/taskSummary.ts"() {
429877
+ init_state2();
429878
+ init_sdkEventQueue();
429879
+ init_sessionState();
429880
+ CLASSIFIER_SUMMARY_ENV = "CLAUDE_CODE_CLASSIFIER_SUMMARY";
429881
+ DETAIL_MAX = 800;
429882
+ FAILED_MARKER = /(?:^|\n)\s*failed\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
429883
+ NEEDS_INPUT_MARKER = /(?:^|\n)\s*needs input\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
429884
+ BLOCKED_MARKER = /(?:^|\n)\s*blocked\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
429885
+ IM_BLOCKED_MARKER = /\bI'?m blocked\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
429886
+ OPTIONAL_OFFER = /\b(?:want|like) me to\b|\b(?:shall|should) I also\b/i;
429887
+ WORKING_VERB = /^(?:(?:Now|Next|Then|Alright|OK|Okay|Right|Good|First|Also),?\s+)?(?:Let me (?!know\b)|(?:I(?:'?ll| will) |I'?m going to |Going to )(?!need\b|require\b|wait\b|leave\b|hold\b|skip\b|stop\b)|Proceeding |Moving (?:on|to)\b|Continuing |Starting |Trying |Checking |Looking |Searching |Reading |Investigating |Running |Re-?running |Building |Rebuilding |Installing |Fetching |Applying |Fixing |Patching |Updating |Adding |Removing |Deleting |Importing |Refactoring |Rewriting |Writing |Grepping |Scanning |Wrapping |Switching |Testing |Verifying |Regenerating |Pushing |Pulling |Reviewing |Examining |Loading |Compiling |Parsing |Analyzing |Tracing |Exploring )/i;
429888
+ NOT_FORWARD_INTENT = /\b(?:once |when |after |until |as soon as )(?:you|it|the|that|this|they)\b|\bagain in\b|\bcheck back\b|\bin ~?\d+\s*(?:s(?:ec(?:ond)?s?)?|m(?:in(?:ute)?s?)?|h(?:ours?|rs?)?)\b|\bthen\.?\s*$|\bwhichever you\b|\bhold(?:ing)? for your\b|\b(?:to|and) wait for\b|\bgive it (?:more |some )?time\b|\bif (?:you(?:'d| want| prefer| need|'re)?|that(?:'s| helps| works)?|useful|needed|helpful|desired)\b|\b(?:isn'?t|not|won'?t) going to work\b/i;
429889
+ AGENTS_STATUS = /^(?:(?:\*\*)?[1-9]\d* (?:agent|cron|task|fork|job|worker|PR|check)s? (?:in flight|remaining|active|still (?:running|working)|pending|running|launched)\b|(?:Continuous )?(?:[Ll]oop|[Cc]rons?|[Bb]abysit) (?:active|healthy|continuing|running|will keep|continues)\b|Waiting for (?:the )?(?:agent|cron|task|fork|worker|job|remaining|them)s?\b|Agents? will report back\b|Waiting\.?$)/;
429890
+ WILL_CHECK_BACK = /^(?:I will|I'll|Will) (?:check back|re-?check|poll|look again|retry|re-?run|try again) (?:(?:when|once|after|until) (?!your?\b)|in\b|again\b)/i;
429891
+ CANT_PROCEED = /^I (?:can(?:'?t|not)|am unable to) (?:proceed|continue|make (?:any )?progress|complete|fix this)\b/i;
429892
+ GIVING_UP = /^(?:Giving up|I(?:'m| am) giving up|The task is not actionable)\b/i;
429893
+ PUSHED_COMMITTED = /^(?:Pushed (?:to `|`[0-9a-f]{7,})|Committed as `?[0-9a-f]{7,}\b|Commit: `?[0-9a-f]{7,}\b|(?:Opened|Created) PR #?\d)/;
429894
+ READY_FOR = /^Ready (?:for review|to (?:upload|merge|ship|land))\b/;
429895
+ VERDICT_MARKER = /^VERDICT: (?:PASS|FAIL)\b/;
429896
+ PLEASE_DO_X = /^Please (?:start|run|provide|grant|export|add|install|configure|give me|paste|point me|set (?:the |up |`?[A-Z][A-Z0-9_]+\b))/;
429897
+ STOPPING_HERE = /^(?:Stopping here|I've stopped here|Parked (?:the|this) branch|Paused here)(?:\.|$| —| -| until| pending| since| because)/i;
429898
+ WAIT_EXTERNAL = /\b(?:waiting (?:for|on)|pending)\s+(?:the\s+)?(?:CI|build|tests?|reviewer|deploy(?:ment)?|workflow|checks?|rollout|merge queue)\b/i;
429899
+ AWAITING_USER = /\b(?:awaiting|waiting (?:for|on)|pending)\s+(?:your\s+(?:feedback|input|decision|response|approval|direction|guidance|go-ahead)|you\b|the user\b)/i;
429900
+ ASK_VERB = /\b(please (?:run|provide|confirm|clarify|choose|let me know)|let me know (?:which|what|how|when)|which (?:option|approach|one)|should I (?:proceed|continue|use))\b/i;
429901
+ AUTH_PROSE = /\b(not logged in|please run \/login|authentication failed|invalid api key|oauth token (?:expired|revoked)|credit balance (?:is )?too low|usage limit reached|mcp (?:server )?(?:authentication|auth|authorization|unauthorized)|mcp (?:server )?(?:credential|token) (?:missing|expired|invalid)|401 unauthorized|403 forbidden|token (?:has )?expired|bad credentials|gh auth login|gcloud auth login|aws (?:sso )?login)\b/i;
429902
+ bgWriteChain = Promise.resolve();
429903
+ bgBlockedByActivity = false;
429904
+ prevActivityStatus = "idle";
428955
429905
  }
428956
429906
  });
428957
429907
 
@@ -428961,7 +429911,7 @@ import {
428961
429911
  existsSync as existsSync16,
428962
429912
  mkdirSync as mkdirSync14,
428963
429913
  renameSync as renameSync6,
428964
- readdirSync as readdirSync7,
429914
+ readdirSync as readdirSync8,
428965
429915
  statSync as statSync8,
428966
429916
  writeFileSync as writeFileSync13
428967
429917
  } from "node:fs";
@@ -429023,7 +429973,7 @@ function copyTreeSkipExisting(srcDir, destDir, onlyTopNames) {
429023
429973
  if (!existsSync16(srcDir)) return { copied, skipped };
429024
429974
  let entries;
429025
429975
  try {
429026
- entries = readdirSync7(srcDir);
429976
+ entries = readdirSync8(srcDir);
429027
429977
  } catch {
429028
429978
  return { copied, skipped };
429029
429979
  }
@@ -429571,6 +430521,40 @@ __export(seamQuery_exports, {
429571
430521
  setSeamWebSearch: () => setSeamWebSearch,
429572
430522
  toTaskRequest: () => toTaskRequest
429573
430523
  });
430524
+ function isBgHeadlessWorker() {
430525
+ return process.env.SEMA_CODE_SESSION_KIND === "bg" && !!process.env.SEMA_JOB_DIR && !!process.env.SEMA_LIVE_BASEURL;
430526
+ }
430527
+ async function probeLiveEngineOk() {
430528
+ const base = process.env.SEMA_LIVE_BASEURL;
430529
+ if (!base) return false;
430530
+ try {
430531
+ const ctl = new AbortController();
430532
+ const t2 = setTimeout(() => ctl.abort(), 2e3);
430533
+ const res = await fetch(`${base}/health`, { signal: ctl.signal });
430534
+ clearTimeout(t2);
430535
+ if (!res.ok) return false;
430536
+ const body = await res.json();
430537
+ return body?.status === "ok";
430538
+ } catch {
430539
+ return false;
430540
+ }
430541
+ }
430542
+ async function waitForBgEngineRecovery(signal) {
430543
+ const until = Date.now() + BG_RECOVERY_WAIT_MS;
430544
+ let lastProbe = 0;
430545
+ while (Date.now() < until) {
430546
+ if (signal?.aborted) return false;
430547
+ const st2 = getEngineRuntimeStatus();
430548
+ if (st2.phase === "failed") return false;
430549
+ if (st2.phase === "recovered") return true;
430550
+ if (Date.now() - lastProbe >= 2e3) {
430551
+ lastProbe = Date.now();
430552
+ if (await probeLiveEngineOk()) return true;
430553
+ }
430554
+ await new Promise((r) => setTimeout(r, 500));
430555
+ }
430556
+ return false;
430557
+ }
429574
430558
  function uuid5() {
429575
430559
  const g5 = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
429576
430560
  if (g5 && typeof g5.randomUUID === "function") return g5.randomUUID();
@@ -429887,6 +430871,13 @@ ${sandboxHint}`;
429887
430871
  return `${API_ERROR_PREFIX}: ${detail} \xB7 the engine is unreachable \u2014 your message did not run; check the engine is up, then send it again.`;
429888
430872
  }
429889
430873
  async function* query(params) {
430874
+ try {
430875
+ if (getEngineRuntimeStatus().phase === "failed") {
430876
+ const { requestEngineRetryNow: requestEngineRetryNow2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
430877
+ requestEngineRetryNow2();
430878
+ }
430879
+ } catch {
430880
+ }
429890
430881
  if (!clientExplicitlySet && !process.env.SEMA_LIVE_BASEURL && !process.env.SEMA_SCENARIO) {
429891
430882
  let why = "engine autostart did not run";
429892
430883
  try {
@@ -429894,6 +430885,13 @@ async function* query(params) {
429894
430885
  why = describeEngineInitFailure2(getLastEngineInitFailure2());
429895
430886
  } catch {
429896
430887
  }
430888
+ if (process.env.SEMA_CODE_SESSION_KIND === "bg" && process.env.SEMA_JOB_DIR) {
430889
+ try {
430890
+ const { reportBgEngineDown: reportBgEngineDown2 } = await Promise.resolve().then(() => (init_taskSummary(), taskSummary_exports));
430891
+ reportBgEngineDown2(`engine unavailable \u2014 ${why}`);
430892
+ } catch {
430893
+ }
430894
+ }
429897
430895
  yield createAssistantAPIErrorMessage({
429898
430896
  content: `The sema engine is not running, so this message was NOT sent to any model.
429899
430897
  Why: ${why}.
@@ -430005,26 +431003,60 @@ Setup looks unfinished (no model was saved). Run \`sema onboard\` to finish setu
430005
431003
  }
430006
431004
  }
430007
431005
  };
430008
- try {
430009
- const sdk = makeAdapterQuery(client2.tasks.stream(req, { signal }), { sessionId });
430010
- for await (const ccEvent of sdkMessagesToCcEvents(sdk, { sessionId, uuid: uuid5, signal })) {
430011
- trackToolLifecycle(ccEvent);
430012
- yield ccEvent;
430013
- }
430014
- } catch (err8) {
430015
- if (!signal?.aborted) {
430016
- logError(err8);
430017
- if (process.env.SEMA_DEBUG) {
430018
- console.error("[sema][seamQuery] live submit failed \u2014 rendering CC API-error row:", err8);
431006
+ let bgTearResends = 0;
431007
+ let retryStream = true;
431008
+ while (retryStream) {
431009
+ retryStream = false;
431010
+ try {
431011
+ const sdk = makeAdapterQuery(client2.tasks.stream(req, { signal }), { sessionId });
431012
+ for await (const ccEvent of sdkMessagesToCcEvents(sdk, { sessionId, uuid: uuid5, signal })) {
431013
+ trackToolLifecycle(ccEvent);
431014
+ yield ccEvent;
430019
431015
  }
430020
- if (process.env.SEMA_LIVE_BASEURL) {
430021
- logTurnJournal({ type: "turn_aborted", reason: "engine_error" });
431016
+ } catch (err8) {
431017
+ if (!signal?.aborted) {
431018
+ logError(err8);
431019
+ if (process.env.SEMA_DEBUG) {
431020
+ console.error("[sema][seamQuery] live submit failed \u2014 rendering CC API-error row:", err8);
431021
+ }
431022
+ if (process.env.SEMA_LIVE_BASEURL) {
431023
+ logTurnJournal({ type: "turn_aborted", reason: "engine_error" });
431024
+ }
431025
+ const tearVerdict = await classifyStreamTear().catch(() => "not-restart");
431026
+ if (isBgHeadlessWorker() && (tearVerdict === "restarted" || tearVerdict === "engine-down") && bgTearResends < BG_TEAR_MAX_RESENDS) {
431027
+ bgTearResends++;
431028
+ yield createAssistantAPIErrorMessage({
431029
+ content: tearVerdict === "restarted" ? `Engine restarted while this turn was streaming. This background session will resend the interrupted prompt automatically (attempt ${bgTearResends}/${BG_TEAR_MAX_RESENDS}).` : `The local engine stopped responding mid-turn. This background session is waiting for the engine to come back and will resend the interrupted prompt automatically (attempt ${bgTearResends}/${BG_TEAR_MAX_RESENDS}).`,
431030
+ error: "unknown"
431031
+ });
431032
+ const back = tearVerdict === "restarted" ? true : await waitForBgEngineRecovery(signal);
431033
+ if (back && !signal?.aborted) {
431034
+ if (setInProgress && engineOpenToolIds.size > 0) {
431035
+ const leftover = [...engineOpenToolIds];
431036
+ engineOpenToolIds.clear();
431037
+ setInProgress((prev) => {
431038
+ const next = new Set(prev);
431039
+ for (const id of leftover) next.delete(id);
431040
+ return next;
431041
+ });
431042
+ }
431043
+ retryStream = true;
431044
+ continue;
431045
+ }
431046
+ try {
431047
+ const { reportBgEngineDown: reportBgEngineDown2 } = await Promise.resolve().then(() => (init_taskSummary(), taskSummary_exports));
431048
+ const st2 = getEngineRuntimeStatus();
431049
+ reportBgEngineDown2(
431050
+ st2.phase === "failed" ? st2.detail ?? "automatic engine restart failed" : "engine did not come back within the auto-resend window"
431051
+ );
431052
+ } catch {
431053
+ }
431054
+ }
431055
+ yield createAssistantAPIErrorMessage({
431056
+ content: tearVerdict === "restarted" ? "Engine restarted while this turn was streaming (likely an update). The session is intact \u2014 press \u2191 then enter to resend the interrupted prompt." : tearVerdict === "engine-down" ? "The local engine stopped responding mid-turn (it may have crashed). The session is intact \u2014 sema is restarting the engine automatically; watch the engine status line above the input and resend once it shows the engine is back." : semaApiErrorContent(err8, req.scenario),
431057
+ error: "unknown"
431058
+ });
430022
431059
  }
430023
- const tearVerdict = await classifyStreamTear().catch(() => "not-restart");
430024
- yield createAssistantAPIErrorMessage({
430025
- content: tearVerdict === "restarted" ? "Engine restarted while this turn was streaming (likely an update). The session is intact \u2014 press \u2191 then enter to resend the interrupted prompt." : tearVerdict === "engine-down" ? "The local engine stopped responding mid-turn (it may have crashed). The session is intact \u2014 sema is restarting the engine automatically; watch the engine status line above the input and resend once it shows the engine is back." : semaApiErrorContent(err8, req.scenario),
430026
- error: "unknown"
430027
- });
430028
431060
  }
430029
431061
  }
430030
431062
  publishEngineAgentPanelEvent({ kind: "sweep" });
@@ -430087,7 +431119,7 @@ async function cancelEngineRun(taskId) {
430087
431119
  } catch {
430088
431120
  }
430089
431121
  }
430090
- var client2, clientExplicitlySet, seamSettings, seamWebSearch, seamSkills, seamMcp, seamRewindCapture, seamPendingRewind, INTERRUPT_WIRE_MARKER, seamPendingInterrupt, seamHistorySeedPending, seamSandbox, seamAutoSandboxInjected, HISTORY_SEED_MAX_CHARS, SCENARIO_KEYS, API_ERROR_PREFIX, defaultGatePrompt, canUseTool;
431122
+ var BG_TEAR_MAX_RESENDS, BG_RECOVERY_WAIT_MS, client2, clientExplicitlySet, seamSettings, seamWebSearch, seamSkills, seamMcp, seamRewindCapture, seamPendingRewind, INTERRUPT_WIRE_MARKER, seamPendingInterrupt, seamHistorySeedPending, seamSandbox, seamAutoSandboxInjected, HISTORY_SEED_MAX_CHARS, SCENARIO_KEYS, API_ERROR_PREFIX, defaultGatePrompt, canUseTool;
430091
431123
  var init_seamQuery = __esm({
430092
431124
  "build-src/src/sema/seamQuery.ts"() {
430093
431125
  init_adapter();
@@ -430120,6 +431152,9 @@ var init_seamQuery = __esm({
430120
431152
  init_scenarioNotAllowedCopy();
430121
431153
  init_messages4();
430122
431154
  init_log2();
431155
+ init_engineRuntimeStatus();
431156
+ BG_TEAR_MAX_RESENDS = 2;
431157
+ BG_RECOVERY_WAIT_MS = 12e4;
430123
431158
  client2 = makeMockClient();
430124
431159
  clientExplicitlySet = false;
430125
431160
  seamRewindCapture = true;
@@ -432591,14 +433626,14 @@ var init_terminalSetup = __esm({
432591
433626
  });
432592
433627
 
432593
433628
  // build-src/src/utils/pasteStore.ts
432594
- import { createHash as createHash22 } from "crypto";
433629
+ import { createHash as createHash23 } from "crypto";
432595
433630
  import { mkdir as mkdir31, readdir as readdir22, readFile as readFile36, stat as stat36, unlink as unlink18, writeFile as writeFile31 } from "fs/promises";
432596
433631
  import { join as join124 } from "path";
432597
433632
  function getPasteStoreDir() {
432598
433633
  return join124(getClaudeConfigHomeDir(), PASTE_STORE_DIR);
432599
433634
  }
432600
433635
  function hashPastedText(content) {
432601
- return createHash22("sha256").update(content).digest("hex").slice(0, 16);
433636
+ return createHash23("sha256").update(content).digest("hex").slice(0, 16);
432602
433637
  }
432603
433638
  function getPastePath(hash2) {
432604
433639
  return join124(getPasteStoreDir(), `${hash2}.txt`);
@@ -434504,7 +435539,7 @@ var init_pasteReturnBuffer = __esm({
434504
435539
  });
434505
435540
 
434506
435541
  // build-src/src/hooks/usePasteHandler.ts
434507
- import { basename as basename35 } from "path";
435542
+ import { basename as basename36 } from "path";
434508
435543
  function usePasteHandler({
434509
435544
  onPaste,
434510
435545
  onInput,
@@ -434582,7 +435617,7 @@ function usePasteHandler({
434582
435617
  );
434583
435618
  if (validImages.length > 0) {
434584
435619
  for (const imageData of validImages) {
434585
- const filename = basename35(imageData.path);
435620
+ const filename = basename36(imageData.path);
434586
435621
  onImagePaste2(
434587
435622
  imageData.base64,
434588
435623
  imageData.mediaType,
@@ -435182,7 +436217,7 @@ var init_TextInput = __esm({
435182
436217
  });
435183
436218
 
435184
436219
  // build-src/src/utils/suggestions/directoryCompletion.ts
435185
- import { basename as basename36, dirname as dirname60, join as join126, sep as sep27 } from "path";
436220
+ import { basename as basename37, dirname as dirname60, join as join126, sep as sep27 } from "path";
435186
436221
  function parsePartialPath(partialPath, basePath) {
435187
436222
  if (!partialPath) {
435188
436223
  const directory2 = basePath || getCwd();
@@ -435193,7 +436228,7 @@ function parsePartialPath(partialPath, basePath) {
435193
436228
  return { directory: resolved, prefix: "" };
435194
436229
  }
435195
436230
  const directory = dirname60(resolved);
435196
- const prefix = basename36(partialPath);
436231
+ const prefix = basename37(partialPath);
435197
436232
  return { directory, prefix };
435198
436233
  }
435199
436234
  async function scanDirectory(dirPath) {
@@ -438730,7 +439765,7 @@ __export(copy_exports, {
438730
439765
  fileExtension: () => fileExtension2
438731
439766
  });
438732
439767
  import { mkdir as mkdir32, writeFile as writeFile33 } from "fs/promises";
438733
- import { tmpdir as tmpdir10 } from "os";
439768
+ import { tmpdir as tmpdir11 } from "os";
438734
439769
  import { join as join130 } from "path";
438735
439770
  function extractCodeBlocks(markdown) {
438736
439771
  const tokens = g2.lexer(stripPromptXMLTags(markdown));
@@ -439045,7 +440080,7 @@ var init_copy = __esm({
439045
440080
  init_messages4();
439046
440081
  init_stringUtils();
439047
440082
  import_jsx_runtime174 = __toESM(require_jsx_runtime(), 1);
439048
- COPY_DIR = join130(tmpdir10(), "claude");
440083
+ COPY_DIR = join130(tmpdir11(), "claude");
439049
440084
  RESPONSE_FILENAME = "response.md";
439050
440085
  MAX_LOOKBACK = 20;
439051
440086
  call11 = async (onDone, context3, args) => {
@@ -445030,11 +446065,11 @@ var init_ansiToPng = __esm({
445030
446065
 
445031
446066
  // build-src/src/utils/screenshotClipboard.ts
445032
446067
  import { mkdir as mkdir33, unlink as unlink19, writeFile as writeFile34 } from "fs/promises";
445033
- import { tmpdir as tmpdir11 } from "os";
446068
+ import { tmpdir as tmpdir12 } from "os";
445034
446069
  import { join as join133 } from "path";
445035
446070
  async function copyAnsiToClipboard(ansiText, options) {
445036
446071
  try {
445037
- const tempDir = join133(tmpdir11(), "claude-code-screenshots");
446072
+ const tempDir = join133(tmpdir12(), "claude-code-screenshots");
445038
446073
  await mkdir33(tempDir, { recursive: true });
445039
446074
  const pngPath = join133(tempDir, `screenshot-${Date.now()}.png`);
445040
446075
  const pngBuffer = ansiToPng(ansiText, options);
@@ -445122,7 +446157,7 @@ var init_screenshotClipboard = __esm({
445122
446157
 
445123
446158
  // build-src/src/utils/stats.ts
445124
446159
  import { open as open15 } from "fs/promises";
445125
- import { basename as basename37, join as join134, sep as sep29 } from "path";
446160
+ import { basename as basename38, join as join134, sep as sep29 } from "path";
445126
446161
  async function processSessionFiles(sessionFiles, options = {}) {
445127
446162
  const { fromDate, toDate } = options;
445128
446163
  const fs15 = getFsImplementation();
@@ -445184,7 +446219,7 @@ async function processSessionFiles(sessionFiles, options = {}) {
445184
446219
  );
445185
446220
  continue;
445186
446221
  }
445187
- const sessionId = basename37(sessionFile, ".jsonl");
446222
+ const sessionId = basename38(sessionFile, ".jsonl");
445188
446223
  const messages = [];
445189
446224
  for (const entry of entries) {
445190
446225
  if (isTranscriptMessage(entry)) {
@@ -445196,7 +446231,7 @@ async function processSessionFiles(sessionFiles, options = {}) {
445196
446231
  if (messages.length === 0) continue;
445197
446232
  const isSubagentFile = sessionFile.includes(`${sep29}subagents${sep29}`);
445198
446233
  if (false) {
445199
- const parentSessionId = isSubagentFile ? basename37(dirname63(dirname63(sessionFile))) : sessionId;
446234
+ const parentSessionId = isSubagentFile ? basename38(dirname63(dirname63(sessionFile))) : sessionId;
445200
446235
  if (!sessionsWithShotCount.has(parentSessionId)) {
445201
446236
  const shotCount = extractShotCountFromMessages(messages);
445202
446237
  if (shotCount !== null) {
@@ -446956,7 +447991,7 @@ function Settings({
446956
447991
  var import_react112, import_jsx_runtime190;
446957
447992
  var init_cmd_config = __esm({
446958
447993
  "build-src/src/sema/overrides/cmd-config.tsx"() {
446959
- import_react112 = __toESM(require_react());
447994
+ import_react112 = __toESM(require_react(), 1);
446960
447995
  init_useKeybinding();
446961
447996
  init_useExitOnCtrlCDWithKeybindings();
446962
447997
  init_useTerminalSize();
@@ -446967,7 +448002,7 @@ var init_cmd_config = __esm({
446967
448002
  init_Config();
446968
448003
  init_settings_usage();
446969
448004
  init_Stats();
446970
- import_jsx_runtime190 = __toESM(require_jsx_runtime());
448005
+ import_jsx_runtime190 = __toESM(require_jsx_runtime(), 1);
446971
448006
  }
446972
448007
  });
446973
448008
 
@@ -449926,14 +450961,14 @@ var init_versions4 = __esm({
449926
450961
  // build-src/src/utils/editor.ts
449927
450962
  import {
449928
450963
  spawn as spawn11,
449929
- spawnSync as spawnSync8
450964
+ spawnSync as spawnSync9
449930
450965
  } from "child_process";
449931
- import { basename as basename38 } from "path";
450966
+ import { basename as basename39 } from "path";
449932
450967
  function isCommandAvailable3(command8) {
449933
450968
  return !!whichSync(command8);
449934
450969
  }
449935
450970
  function classifyGuiEditor(editor) {
449936
- const base = basename38(editor.split(" ")[0] ?? "");
450971
+ const base = basename39(editor.split(" ")[0] ?? "");
449937
450972
  return GUI_EDITORS.find((g5) => base.includes(g5));
449938
450973
  }
449939
450974
  function guiGotoArgv(guiFamily, filePath, line) {
@@ -449968,14 +451003,14 @@ function openFileInExternalEditor(filePath, line) {
449968
451003
  }
449969
451004
  const inkInstance = instances_default.get(process.stdout);
449970
451005
  if (!inkInstance) return false;
449971
- const useGotoLine = line && PLUS_N_EDITORS.test(basename38(base));
451006
+ const useGotoLine = line && PLUS_N_EDITORS.test(basename39(base));
449972
451007
  inkInstance.enterAlternateScreen();
449973
451008
  try {
449974
451009
  const syncOpts = { stdio: "inherit" };
449975
451010
  let result;
449976
451011
  if (process.platform === "win32") {
449977
451012
  const lineArg = useGotoLine ? `+${line} ` : "";
449978
- result = spawnSync8(`${editor} ${lineArg}"${filePath}"`, {
451013
+ result = spawnSync9(`${editor} ${lineArg}"${filePath}"`, {
449979
451014
  ...syncOpts,
449980
451015
  shell: true
449981
451016
  });
@@ -449984,7 +451019,7 @@ function openFileInExternalEditor(filePath, line) {
449984
451019
  ...editorArgs,
449985
451020
  ...useGotoLine ? [`+${line}`, filePath] : [filePath]
449986
451021
  ];
449987
- result = spawnSync8(base, args, syncOpts);
451022
+ result = spawnSync9(base, args, syncOpts);
449988
451023
  }
449989
451024
  if (result.error) {
449990
451025
  logForDebugging(`editor spawn failed: ${result.error}`, {
@@ -456402,7 +457437,7 @@ var init_channelPermissions = __esm({
456402
457437
  });
456403
457438
 
456404
457439
  // build-src/src/services/mcp/useManageMCPConnections.ts
456405
- import { basename as basename39 } from "path";
457440
+ import { basename as basename40 } from "path";
456406
457441
  function getErrorKey(error52) {
456407
457442
  const plugin2 = "plugin" in error52 ? error52.plugin : "no-plugin";
456408
457443
  return `${error52.type}:${error52.source}:${plugin2}`;
@@ -457014,7 +458049,7 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = false) {
457014
458049
  else if (serverConfig.scope === "dynamic") counts.plugin++;
457015
458050
  else if (serverConfig.scope === "claudeai") counts.claudeai++;
457016
458051
  if (process.env.USER_TYPE === "ant" && !isMcpServerDisabled(name) && (serverConfig.type === void 0 || serverConfig.type === "stdio") && "command" in serverConfig) {
457017
- stdioCommands.push(basename39(serverConfig.command));
458052
+ stdioCommands.push(basename40(serverConfig.command));
457018
458053
  }
457019
458054
  }
457020
458055
  logEvent("tengu_mcp_servers", {
@@ -461233,7 +462268,7 @@ var init_tipHistory = __esm({
461233
462268
  });
461234
462269
 
461235
462270
  // build-src/src/commands/plugin/DiscoverPlugins.tsx
461236
- import { basename as basename40 } from "path";
462271
+ import { basename as basename41 } from "path";
461237
462272
  function formatSuggestionReason(hit) {
461238
462273
  switch (hit.signal) {
461239
462274
  case "cwd":
@@ -461249,7 +462284,7 @@ function formatSuggestionReason(hit) {
461249
462284
  }
461250
462285
  }
461251
462286
  function formatSuggestionFile(file2) {
461252
- return truncateToWidth(basename40(file2).replaceAll("\\", "/"), 32);
462287
+ return truncateToWidth(basename41(file2).replaceAll("\\", "/"), 32);
461253
462288
  }
461254
462289
  function DiscoverPlugins({
461255
462290
  error: error52,
@@ -475801,8 +476836,8 @@ var init_sema_brand = __esm({
475801
476836
  "Slash-command gating wired to the fleet capability handshake"
475802
476837
  ]
475803
476838
  },
475804
- productVersion: "1.0.1",
475805
- announcement: "sema 1.0.1 \u2014 rolling engine upgrades, session auto-titles, and the sci-fi welcome you are looking at"
476839
+ productVersion: "1.0.3",
476840
+ announcement: "sema 1.0.3 \u2014 honest --bg failures with a cause, daemon crash logs you can find, clean engine teardown on every exit path, and background agents you can wake again"
475806
476841
  };
475807
476842
  }
475808
476843
  });
@@ -482865,7 +483900,7 @@ var init_share = __esm({
482865
483900
 
482866
483901
  // build-src/src/components/skills/SkillsMenu.tsx
482867
483902
  import { existsSync as existsSync19, mkdirSync as mkdirSync17, renameSync as renameSync7 } from "node:fs";
482868
- import { basename as basename43, dirname as dirname68, join as join146 } from "node:path";
483903
+ import { basename as basename44, dirname as dirname68, join as join146 } from "node:path";
482869
483904
  function skillSourceDisplayName(source) {
482870
483905
  switch (source) {
482871
483906
  case "mcp":
@@ -483032,7 +484067,7 @@ function SkillsMenu({ onExit: onExit2, commands }) {
483032
484067
  `skills-removed-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`
483033
484068
  );
483034
484069
  mkdirSync17(removedDir, { recursive: true });
483035
- let target = join146(removedDir, basename43(skill.skillRoot));
484070
+ let target = join146(removedDir, basename44(skill.skillRoot));
483036
484071
  if (existsSync19(target)) target = `${target}-${Date.now()}`;
483037
484072
  renameSync7(skill.skillRoot, target);
483038
484073
  const nameStillPresent = skills2.some(
@@ -510343,14 +511378,14 @@ var exit_exports = {};
510343
511378
  __export(exit_exports, {
510344
511379
  call: () => call65
510345
511380
  });
510346
- import { spawnSync as spawnSync9 } from "child_process";
511381
+ import { spawnSync as spawnSync10 } from "child_process";
510347
511382
  function getRandomGoodbyeMessage2() {
510348
511383
  return sample_default(GOODBYE_MESSAGES2) ?? "Goodbye!";
510349
511384
  }
510350
511385
  async function call65(onDone) {
510351
511386
  if (isBgSession()) {
510352
511387
  onDone();
510353
- spawnSync9("tmux", ["detach-client"], {
511388
+ spawnSync10("tmux", ["detach-client"], {
510354
511389
  stdio: "ignore"
510355
511390
  });
510356
511391
  return null;
@@ -512902,7 +513937,7 @@ import {
512902
513937
  unlink as unlink23,
512903
513938
  writeFile as writeFile44
512904
513939
  } from "fs/promises";
512905
- import { tmpdir as tmpdir12 } from "os";
513940
+ import { tmpdir as tmpdir13 } from "os";
512906
513941
  import { extname as extname14, join as join158 } from "path";
512907
513942
  function getAnalysisModel() {
512908
513943
  return getDefaultOpusModel();
@@ -514630,7 +515665,7 @@ var init_insights = __esm({
514630
515665
  } : async () => 0;
514631
515666
  collectFromRemoteHost = process.env.USER_TYPE === "ant" ? async (homespace, destDir) => {
514632
515667
  const result = { copied: 0, skipped: 0 };
514633
- const tempDir = await mkdtemp(join158(tmpdir12(), "claude-hs-"));
515668
+ const tempDir = await mkdtemp(join158(tmpdir13(), "claude-hs-"));
514634
515669
  try {
514635
515670
  const scpResult = await execFileNoThrow(
514636
515671
  "scp",
@@ -515935,7 +516970,7 @@ import {
515935
516970
  unlink as unlink24,
515936
516971
  writeFile as writeFile45
515937
516972
  } from "fs/promises";
515938
- import { basename as basename44, dirname as dirname71, join as join159 } from "path";
516973
+ import { basename as basename45, dirname as dirname71, join as join159 } from "path";
515939
516974
  function isTranscriptMessage(entry) {
515940
516975
  return entry.type === "user" || entry.type === "assistant" || entry.type === "attachment" || entry.type === "system";
515941
516976
  }
@@ -517990,7 +519025,7 @@ async function getSessionFilesWithMtime(projectDir2) {
517990
519025
  const candidates = [];
517991
519026
  for (const dirent of dirents) {
517992
519027
  if (!dirent.isFile() || !dirent.name.endsWith(".jsonl")) continue;
517993
- const sessionId = validateUuid(basename44(dirent.name, ".jsonl"));
519028
+ const sessionId = validateUuid(basename45(dirent.name, ".jsonl"));
517994
519029
  if (!sessionId) continue;
517995
519030
  candidates.push({ sessionId, filePath: join159(projectDir2, dirent.name) });
517996
519031
  }
@@ -519430,7 +520465,7 @@ var init_agentMemory = __esm({
519430
520465
 
519431
520466
  // build-src/src/utils/permissions/filesystem.ts
519432
520467
  import { randomBytes as randomBytes20 } from "crypto";
519433
- import { homedir as homedir42, tmpdir as tmpdir13 } from "os";
520468
+ import { homedir as homedir42, tmpdir as tmpdir14 } from "os";
519434
520469
  import { join as join161, normalize as normalize16, posix as posix8, sep as sep34 } from "path";
519435
520470
  function normalizeCaseForComparison2(path27) {
519436
520471
  return path27.toLowerCase();
@@ -520414,7 +521449,7 @@ var init_filesystem = __esm({
520414
521449
  ];
520415
521450
  DIR_SEP = posix8.sep;
520416
521451
  getClaudeTempDir = memoize_default(function getClaudeTempDir2() {
520417
- const baseTmpDir = process.env.SEMA_CODE_TMPDIR || (getPlatform() === "windows" ? tmpdir13() : "/tmp");
521452
+ const baseTmpDir = process.env.SEMA_CODE_TMPDIR || (getPlatform() === "windows" ? tmpdir14() : "/tmp");
520418
521453
  const fs15 = getFsImplementation();
520419
521454
  let resolvedBaseTmpDir = baseTmpDir;
520420
521455
  try {
@@ -522024,7 +523059,7 @@ __export(hooks_exports2, {
522024
523059
  hasWorktreeCreateHook: () => hasWorktreeCreateHook,
522025
523060
  shouldSkipHookDueToTrust: () => shouldSkipHookDueToTrust
522026
523061
  });
522027
- import { basename as basename45 } from "path";
523062
+ import { basename as basename46 } from "path";
522028
523063
  import { spawn as spawn12 } from "child_process";
522029
523064
  import { randomUUID as randomUUID32 } from "crypto";
522030
523065
  function getSessionEndHookTimeoutMs() {
@@ -522899,7 +523934,7 @@ async function getMatchingHooks(appState, sessionId, hookEvent, hookInput, tools
522899
523934
  matchQuery = hookInput.load_reason;
522900
523935
  break;
522901
523936
  case "FileChanged":
522902
- matchQuery = basename45(hookInput.file_path);
523937
+ matchQuery = basename46(hookInput.file_path);
522903
523938
  break;
522904
523939
  default:
522905
523940
  break;
@@ -525186,7 +526221,7 @@ import {
525186
526221
  symlink as symlink5,
525187
526222
  utimes as utimes2
525188
526223
  } from "fs/promises";
525189
- import { basename as basename46, dirname as dirname72, join as join163 } from "path";
526224
+ import { basename as basename47, dirname as dirname72, join as join163 } from "path";
525190
526225
  function validateWorktreeSlug(slug) {
525191
526226
  if (slug.length > MAX_WORKTREE_SLUG_LENGTH) {
525192
526227
  throw new Error(
@@ -525243,7 +526278,7 @@ function restoreWorktreeSession(session2) {
525243
526278
  currentWorktreeSession = session2;
525244
526279
  }
525245
526280
  function generateTmuxSessionName(repoPath, branch2) {
525246
- const repoName = basename46(repoPath);
526281
+ const repoName = basename47(repoPath);
525247
526282
  const combined = `${repoName}_${branch2}`;
525248
526283
  return combined.replace(/[/.]/g, "_");
525249
526284
  }
@@ -526494,7 +527529,7 @@ var init_prompts3 = __esm({
526494
527529
  });
526495
527530
 
526496
527531
  // build-src/src/utils/api.ts
526497
- import { createHash as createHash23 } from "crypto";
527532
+ import { createHash as createHash24 } from "crypto";
526498
527533
  function filterSwarmFieldsFromSchema(toolName2, schema) {
526499
527534
  const fieldsToRemove = SWARM_FIELDS_BY_TOOL[toolName2];
526500
527535
  if (!fieldsToRemove || fieldsToRemove.length === 0) {
@@ -526588,7 +527623,7 @@ function logAPIPrefix(systemPrompt) {
526588
527623
  20
526589
527624
  ),
526590
527625
  length: firstSystemPrompt?.length ?? 0,
526591
- hash: firstSystemPrompt ? createHash23("sha256").update(firstSystemPrompt).digest("hex") : ""
527626
+ hash: firstSystemPrompt ? createHash24("sha256").update(firstSystemPrompt).digest("hex") : ""
526592
527627
  });
526593
527628
  }
526594
527629
  function splitSysPromptPrefix(systemPrompt, options) {
@@ -532639,7 +533674,7 @@ var init_markdownConfigLoader = __esm({
532639
533674
  });
532640
533675
 
532641
533676
  // build-src/src/outputStyles/loadOutputStylesDir.ts
532642
- import { basename as basename47 } from "path";
533677
+ import { basename as basename48 } from "path";
532643
533678
  var getOutputStyleDirStyles;
532644
533679
  var init_loadOutputStylesDir = __esm({
532645
533680
  "build-src/src/outputStyles/loadOutputStylesDir.ts"() {
@@ -532658,7 +533693,7 @@ var init_loadOutputStylesDir = __esm({
532658
533693
  );
532659
533694
  const styles5 = markdownFiles.map(({ filePath, frontmatter: frontmatter2, content, source }) => {
532660
533695
  try {
532661
- const fileName = basename47(filePath);
533696
+ const fileName = basename48(filePath);
532662
533697
  const styleName = fileName.replace(/\.md$/, "");
532663
533698
  const name = frontmatter2["name"] || styleName;
532664
533699
  const description = coerceDescriptionToString(
@@ -566278,7 +567313,7 @@ var require_cross_spawn2 = __commonJS({
566278
567313
  enoent.hookChildProcess(spawned, parsed);
566279
567314
  return spawned;
566280
567315
  }
566281
- function spawnSync12(command8, args, options) {
567316
+ function spawnSync13(command8, args, options) {
566282
567317
  const parsed = parse14(command8, args, options);
566283
567318
  const result = cp2.spawnSync(parsed.command, parsed.args, parsed.options);
566284
567319
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
@@ -566286,7 +567321,7 @@ var require_cross_spawn2 = __commonJS({
566286
567321
  }
566287
567322
  module2.exports = spawn17;
566288
567323
  module2.exports.spawn = spawn17;
566289
- module2.exports.sync = spawnSync12;
567324
+ module2.exports.sync = spawnSync13;
566290
567325
  module2.exports._parse = parse14;
566291
567326
  module2.exports._enoent = enoent;
566292
567327
  }
@@ -566620,7 +567655,7 @@ var init_streamableHttp2 = __esm({
566620
567655
  });
566621
567656
 
566622
567657
  // ../ai-agent-core/dist/core/mcp.js
566623
- import { tmpdir as tmpdir14 } from "node:os";
567658
+ import { tmpdir as tmpdir15 } from "node:os";
566624
567659
  import { join as join165 } from "node:path";
566625
567660
  var MCP_IMAGE_MAX_BASE64, IMAGE_TARGET_RAW_SIZE3, MCP_BLOB_DIR;
566626
567661
  var init_mcp5 = __esm({
@@ -566633,7 +567668,7 @@ var init_mcp5 = __esm({
566633
567668
  init_untrusted_text();
566634
567669
  MCP_IMAGE_MAX_BASE64 = 5 * 1024 * 1024;
566635
567670
  IMAGE_TARGET_RAW_SIZE3 = MCP_IMAGE_MAX_BASE64 * 3 / 4;
566636
- MCP_BLOB_DIR = join165(tmpdir14(), "sema-mcp-blobs");
567671
+ MCP_BLOB_DIR = join165(tmpdir15(), "sema-mcp-blobs");
566637
567672
  }
566638
567673
  });
566639
567674
 
@@ -568796,7 +569831,7 @@ var init_lsp = __esm({
568796
569831
  });
568797
569832
 
568798
569833
  // ../ai-agent-core/dist/core/runner/prepare-task.js
568799
- import { createHash as createHash24, randomBytes as randomBytes24 } from "node:crypto";
569834
+ import { createHash as createHash25, randomBytes as randomBytes24 } from "node:crypto";
568800
569835
  var PROMPT_HASH_SALT, DEFAULT_RESOURCE_TTL_MS, DEFAULT_UNATTENDED_APPROVAL_TTL_MS;
568801
569836
  var init_prepare_task = __esm({
568802
569837
  "../ai-agent-core/dist/core/runner/prepare-task.js"() {
@@ -574586,7 +575621,7 @@ var init_managedEnv = __esm({
574586
575621
  });
574587
575622
 
574588
575623
  // build-src/src/upstreamproxy/relay.ts
574589
- import { createServer as createServer7 } from "node:net";
575624
+ import { createServer as createServer8 } from "node:net";
574590
575625
  function encodeChunk(data) {
574591
575626
  const len = data.length;
574592
575627
  const varint = [];
@@ -574688,7 +575723,7 @@ function startBunRelay(wsUrl, authHeader, wsAuthHeader) {
574688
575723
  async function startNodeRelay(wsUrl, authHeader, wsAuthHeader) {
574689
575724
  nodeWSCtor = (await Promise.resolve().then(() => (init_wrapper(), wrapper_exports))).default;
574690
575725
  const states = /* @__PURE__ */ new WeakMap();
574691
- const server = createServer7((sock) => {
575726
+ const server = createServer8((sock) => {
574692
575727
  const st2 = newConnState();
574693
575728
  states.set(sock, st2);
574694
575729
  const adapter2 = {
@@ -578875,61 +579910,6 @@ var init_fpsMetrics = __esm({
578875
579910
  }
578876
579911
  });
578877
579912
 
578878
- // build-src/src/utils/sessionState.ts
578879
- function setSessionStateChangedListener(cb) {
578880
- stateListener = cb;
578881
- }
578882
- function setSessionMetadataChangedListener(cb) {
578883
- metadataListener = cb;
578884
- }
578885
- function setPermissionModeChangedListener(cb) {
578886
- permissionModeListener = cb;
578887
- }
578888
- function getSessionState() {
578889
- return currentState;
578890
- }
578891
- function notifySessionStateChanged(state3, details) {
578892
- currentState = state3;
578893
- stateListener?.(state3, details);
578894
- if (state3 === "requires_action" && details) {
578895
- hasPendingAction = true;
578896
- metadataListener?.({
578897
- pending_action: details
578898
- });
578899
- } else if (hasPendingAction) {
578900
- hasPendingAction = false;
578901
- metadataListener?.({ pending_action: null });
578902
- }
578903
- if (state3 === "idle") {
578904
- metadataListener?.({ task_summary: null });
578905
- }
578906
- if (isEnvTruthy(process.env.SEMA_CODE_EMIT_SESSION_STATE_EVENTS)) {
578907
- enqueueSdkEvent({
578908
- type: "system",
578909
- subtype: "session_state_changed",
578910
- state: state3
578911
- });
578912
- }
578913
- }
578914
- function notifySessionMetadataChanged(metadata2) {
578915
- metadataListener?.(metadata2);
578916
- }
578917
- function notifyPermissionModeChanged(mode) {
578918
- permissionModeListener?.(mode);
578919
- }
578920
- var stateListener, metadataListener, permissionModeListener, hasPendingAction, currentState;
578921
- var init_sessionState = __esm({
578922
- "build-src/src/utils/sessionState.ts"() {
578923
- init_envUtils();
578924
- init_sdkEventQueue();
578925
- stateListener = null;
578926
- metadataListener = null;
578927
- permissionModeListener = null;
578928
- hasPendingAction = false;
578929
- currentState = "idle";
578930
- }
578931
- });
578932
-
578933
579913
  // build-src/src/state/onChangeAppState.ts
578934
579914
  function externalMetadataToAppState(metadata2) {
578935
579915
  return (prev) => ({
@@ -585889,7 +586869,7 @@ var init_FileEditToolDiff = __esm({
585889
586869
 
585890
586870
  // build-src/src/hooks/useDiffInIDE.ts
585891
586871
  import { randomUUID as randomUUID37 } from "crypto";
585892
- import { basename as basename49 } from "path";
586872
+ import { basename as basename50 } from "path";
585893
586873
  function useDiffInIDE({
585894
586874
  onChange,
585895
586875
  toolUseContext,
@@ -585901,7 +586881,7 @@ function useDiffInIDE({
585901
586881
  const [hasError, setHasError] = (0, import_react225.useState)(false);
585902
586882
  const sha = (0, import_react225.useMemo)(() => randomUUID37().slice(0, 6), []);
585903
586883
  const tabName = (0, import_react225.useMemo)(
585904
- () => `\u273B [Sema] ${basename49(filePath)} (${sha}) \u29C9`,
586884
+ () => `\u273B [Sema] ${basename50(filePath)} (${sha}) \u29C9`,
585905
586885
  [filePath, sha]
585906
586886
  );
585907
586887
  const shouldShowDiffInIDE = hasAccessToIDEExtensionDiffFeature(toolUseContext.options.mcpClients) && getGlobalConfig().diffTool === "auto" && // Diffs should only be for file edits.
@@ -586115,7 +587095,7 @@ var init_useDiffInIDE = __esm({
586115
587095
  });
586116
587096
 
586117
587097
  // build-src/src/components/ShowInIDEPrompt.tsx
586118
- import { basename as basename50, relative as relative28 } from "path";
587098
+ import { basename as basename51, relative as relative28 } from "path";
586119
587099
  function ShowInIDEPrompt(t0) {
586120
587100
  const $3 = (0, import_compiler_runtime273.c)(36);
586121
587101
  const {
@@ -586162,7 +587142,7 @@ function ShowInIDEPrompt(t0) {
586162
587142
  }
586163
587143
  let t4;
586164
587144
  if ($3[5] !== filePath) {
586165
- t4 = basename50(filePath);
587145
+ t4 = basename51(filePath);
586166
587146
  $3[5] = filePath;
586167
587147
  $3[6] = t4;
586168
587148
  } else {
@@ -586297,7 +587277,7 @@ var init_ShowInIDEPrompt = __esm({
586297
587277
 
586298
587278
  // build-src/src/components/permissions/FilePermissionDialog/permissionOptions.tsx
586299
587279
  import { homedir as homedir45 } from "os";
586300
- import { basename as basename51, join as join168, sep as sep36 } from "path";
587280
+ import { basename as basename52, join as join168, sep as sep36 } from "path";
586301
587281
  function isInClaudeFolder(filePath) {
586302
587282
  const absolutePath = expandPath(filePath);
586303
587283
  const claudeFolderPath = expandPath(`${getOriginalCwd()}/.claude`);
@@ -586375,7 +587355,7 @@ function getFilePermissionOptions({
586375
587355
  }
586376
587356
  } else {
586377
587357
  const dirPath = getDirectoryForPath(filePath);
586378
- const dirName = basename51(dirPath) || "this directory";
587358
+ const dirName = basename52(dirPath) || "this directory";
586379
587359
  if (operationType === "read") {
586380
587360
  sessionLabel = /* @__PURE__ */ (0, import_jsx_runtime396.jsxs)(ThemedText, { children: [
586381
587361
  "Yes, allow reading from ",
@@ -586849,7 +587829,7 @@ var init_FilePermissionDialog = __esm({
586849
587829
  });
586850
587830
 
586851
587831
  // build-src/src/components/permissions/SedEditPermissionRequest/SedEditPermissionRequest.tsx
586852
- import { basename as basename52, relative as relative30 } from "path";
587832
+ import { basename as basename53, relative as relative30 } from "path";
586853
587833
  function SedEditPermissionRequest(t0) {
586854
587834
  const $3 = (0, import_compiler_runtime274.c)(9);
586855
587835
  let props;
@@ -587016,7 +587996,7 @@ function SedEditPermissionRequestInner(t0) {
587016
587996
  }
587017
587997
  let t10;
587018
587998
  if ($3[16] !== filePath) {
587019
- t10 = basename52(filePath);
587999
+ t10 = basename53(filePath);
587020
588000
  $3[16] = filePath;
587021
588001
  $3[17] = t10;
587022
588002
  } else {
@@ -587217,7 +588197,7 @@ var init_useShellPermissionFeedback = __esm({
587217
588197
  });
587218
588198
 
587219
588199
  // build-src/src/components/permissions/shellPermissionHelpers.tsx
587220
- import { basename as basename53, sep as sep37 } from "path";
588200
+ import { basename as basename54, sep as sep37 } from "path";
587221
588201
  function commandListDisplay(commands) {
587222
588202
  switch (commands.length) {
587223
588203
  case 0:
@@ -587248,7 +588228,7 @@ function commandListDisplayTruncated(commands) {
587248
588228
  }
587249
588229
  function formatPathList(paths3) {
587250
588230
  if (paths3.length === 0) return "";
587251
- const names = paths3.map((p) => basename53(p) || p);
588231
+ const names = paths3.map((p) => basename54(p) || p);
587252
588232
  if (names.length === 1) {
587253
588233
  return /* @__PURE__ */ (0, import_jsx_runtime399.jsxs)(ThemedText, { children: [
587254
588234
  /* @__PURE__ */ (0, import_jsx_runtime399.jsx)(ThemedText, { bold: true, children: names[0] }),
@@ -587292,7 +588272,7 @@ function generateShellSuggestionsLabel(suggestions, shellToolName, commandTransf
587292
588272
  if (hasReadPaths && !hasDirectories && !hasCommands) {
587293
588273
  if (readPaths.length === 1) {
587294
588274
  const firstPath = readPaths[0];
587295
- const dirName = basename53(firstPath) || firstPath;
588275
+ const dirName = basename54(firstPath) || firstPath;
587296
588276
  return /* @__PURE__ */ (0, import_jsx_runtime399.jsxs)(ThemedText, { children: [
587297
588277
  "Yes, allow reading from ",
587298
588278
  /* @__PURE__ */ (0, import_jsx_runtime399.jsx)(ThemedText, { bold: true, children: dirName }),
@@ -587309,7 +588289,7 @@ function generateShellSuggestionsLabel(suggestions, shellToolName, commandTransf
587309
588289
  if (hasDirectories && !hasReadPaths && !hasCommands) {
587310
588290
  if (directories.length === 1) {
587311
588291
  const firstDir = directories[0];
587312
- const dirName = basename53(firstDir) || firstDir;
588292
+ const dirName = basename54(firstDir) || firstDir;
587313
588293
  return /* @__PURE__ */ (0, import_jsx_runtime399.jsxs)(ThemedText, { children: [
587314
588294
  "Yes, and always allow access to ",
587315
588295
  /* @__PURE__ */ (0, import_jsx_runtime399.jsx)(ThemedText, { bold: true, children: dirName }),
@@ -589350,7 +590330,7 @@ var init_ideDiffConfig = __esm({
589350
590330
  });
589351
590331
 
589352
590332
  // build-src/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx
589353
- import { basename as basename54, relative as relative31 } from "path";
590333
+ import { basename as basename55, relative as relative31 } from "path";
589354
590334
  function FileEditPermissionRequest(props) {
589355
590335
  const $3 = (0, import_compiler_runtime279.c)(51);
589356
590336
  const parseInput4 = _temp132;
@@ -589393,7 +590373,7 @@ function FileEditPermissionRequest(props) {
589393
590373
  t3 = " ";
589394
590374
  T0 = ThemedText;
589395
590375
  t0 = true;
589396
- t1 = basename54(file_path);
590376
+ t1 = basename55(file_path);
589397
590377
  $3[0] = props.onDone;
589398
590378
  $3[1] = props.onReject;
589399
590379
  $3[2] = props.toolUseConfirm;
@@ -589752,7 +590732,7 @@ var init_FileWriteToolDiff = __esm({
589752
590732
  });
589753
590733
 
589754
590734
  // build-src/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx
589755
- import { basename as basename55, relative as relative32 } from "path";
590735
+ import { basename as basename56, relative as relative32 } from "path";
589756
590736
  function FileWritePermissionRequest(props) {
589757
590737
  const $3 = (0, import_compiler_runtime282.c)(30);
589758
590738
  const parseInput4 = _temp135;
@@ -589820,7 +590800,7 @@ function FileWritePermissionRequest(props) {
589820
590800
  }
589821
590801
  let t9;
589822
590802
  if ($3[7] !== file_path) {
589823
- t9 = basename55(file_path);
590803
+ t9 = basename56(file_path);
589824
590804
  $3[7] = file_path;
589825
590805
  $3[8] = t9;
589826
590806
  } else {
@@ -590156,7 +591136,7 @@ var init_NotebookEditToolDiff = __esm({
590156
591136
  });
590157
591137
 
590158
591138
  // build-src/src/components/permissions/NotebookEditPermissionRequest/NotebookEditPermissionRequest.tsx
590159
- import { basename as basename56 } from "path";
591139
+ import { basename as basename57 } from "path";
590160
591140
  function NotebookEditPermissionRequest(props) {
590161
591141
  const $3 = (0, import_compiler_runtime284.c)(52);
590162
591142
  const parseInput4 = _temp137;
@@ -590200,7 +591180,7 @@ function NotebookEditPermissionRequest(props) {
590200
591180
  t4 = " ";
590201
591181
  T0 = ThemedText;
590202
591182
  t0 = true;
590203
- t1 = basename56(notebook_path);
591183
+ t1 = basename57(notebook_path);
590204
591184
  $3[0] = props.onDone;
590205
591185
  $3[1] = props.onReject;
590206
591186
  $3[2] = props.toolUseConfirm;
@@ -593659,7 +594639,7 @@ var init_useUpdateNotification = __esm({
593659
594639
 
593660
594640
  // build-src/src/sema/overrides/chrome-autoupdater-status.tsx
593661
594641
  import { statSync as statSync11 } from "node:fs";
593662
- import { basename as basename57 } from "path";
594642
+ import { basename as basename58 } from "path";
593663
594643
  function resolveRestoreFailedHint() {
593664
594644
  return null;
593665
594645
  }
@@ -593741,14 +594721,14 @@ function AutoUpdater({
593741
594721
  /* @__PURE__ */ (0, import_jsx_runtime419.jsxs)(ThemedText, { color: "error", wrap: "truncate", children: [
593742
594722
  /* @__PURE__ */ (0, import_jsx_runtime419.jsx)(StatusIcon2, { status: "error", withSpace: true }),
593743
594723
  "Update failed and ",
593744
- basename57(restoreHint.originalPath),
594724
+ basename58(restoreHint.originalPath),
593745
594725
  " could not be restored \u2014 it was preserved at:"
593746
594726
  ] }),
593747
594727
  /* @__PURE__ */ (0, import_jsx_runtime419.jsxs)(ThemedText, { color: "error", wrap: "truncate", children: [
593748
594728
  restoreHint.preservedPath,
593749
594729
  " \xB7 rename it back to",
593750
594730
  " ",
593751
- basename57(restoreHint.originalPath),
594731
+ basename58(restoreHint.originalPath),
593752
594732
  " or run",
593753
594733
  " ",
593754
594734
  /* @__PURE__ */ (0, import_jsx_runtime419.jsxs)(ThemedText, { bold: true, children: [
@@ -594143,7 +595123,7 @@ var init_AutoUpdaterWrapper = __esm({
594143
595123
  });
594144
595124
 
594145
595125
  // build-src/src/components/IdeStatusIndicator.tsx
594146
- import { basename as basename58 } from "path";
595126
+ import { basename as basename59 } from "path";
594147
595127
  function IdeStatusIndicator(t0) {
594148
595128
  const $3 = (0, import_compiler_runtime294.c)(7);
594149
595129
  const {
@@ -594179,7 +595159,7 @@ function IdeStatusIndicator(t0) {
594179
595159
  if (ideSelection.filePath) {
594180
595160
  let t1;
594181
595161
  if ($3[3] !== ideSelection.filePath) {
594182
- t1 = basename58(ideSelection.filePath);
595162
+ t1 = basename59(ideSelection.filePath);
594183
595163
  $3[3] = ideSelection.filePath;
594184
595164
  $3[4] = t1;
594185
595165
  } else {
@@ -597281,7 +598261,7 @@ var init_slackChannelSuggestions = __esm({
597281
598261
  });
597282
598262
 
597283
598263
  // build-src/src/hooks/unifiedSuggestions.ts
597284
- import { basename as basename59 } from "path";
598264
+ import { basename as basename60 } from "path";
597285
598265
  function createSuggestionFromSource(source) {
597286
598266
  switch (source.type) {
597287
598267
  case "file":
@@ -597347,7 +598327,7 @@ async function generateUnifiedSuggestions(query2, mcpResources, agents3, showOnE
597347
598327
  description: suggestion.description,
597348
598328
  path: suggestion.displayText,
597349
598329
  // Use displayText as path for files
597350
- filename: basename59(suggestion.displayText),
598330
+ filename: basename60(suggestion.displayText),
597351
598331
  score: suggestion.metadata?.score
597352
598332
  })
597353
598333
  );
@@ -598755,7 +599735,7 @@ var init_AutoModeOptInDialog = __esm({
598755
599735
  });
598756
599736
 
598757
599737
  // build-src/src/components/BridgeDialog.tsx
598758
- import { basename as basename60 } from "path";
599738
+ import { basename as basename61 } from "path";
598759
599739
  function BridgeDialog(t0) {
598760
599740
  const $3 = (0, import_compiler_runtime298.c)(87);
598761
599741
  const {
@@ -598778,7 +599758,7 @@ function BridgeDialog(t0) {
598778
599758
  const [branchName, setBranchName] = (0, import_react256.useState)("");
598779
599759
  let t1;
598780
599760
  if ($3[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
598781
- t1 = basename60(getOriginalCwd());
599761
+ t1 = basename61(getOriginalCwd());
598782
599762
  $3[0] = t1;
598783
599763
  } else {
598784
599764
  t1 = $3[0];
@@ -603749,6 +604729,14 @@ function PromptInputFooterWithFleet(props) {
603749
604729
  useEngineAgentPanelBridge(store.setState);
603750
604730
  const upgrade2 = React151.useSyncExternalStore(subscribeUpgradeState, getUpgradeState);
603751
604731
  const engineRt = React151.useSyncExternalStore(subscribeEngineRuntimeStatus, getEngineRuntimeStatus);
604732
+ const [nowTick, setNowTick] = React151.useState(() => Date.now());
604733
+ const wantCountdown = engineRt.phase === "failed" && typeof engineRt.nextRetryAt === "number";
604734
+ React151.useEffect(() => {
604735
+ if (!wantCountdown) return;
604736
+ const t2 = setInterval(() => setNowTick(Date.now()), 1e3);
604737
+ return () => clearInterval(t2);
604738
+ }, [wantCountdown]);
604739
+ const retryInS = wantCountdown ? Math.max(0, Math.ceil(((engineRt.nextRetryAt ?? 0) - nowTick) / 1e3)) : null;
603752
604740
  return /* @__PURE__ */ (0, import_jsx_runtime450.jsxs)(import_jsx_runtime450.Fragment, { children: [
603753
604741
  /* @__PURE__ */ (0, import_jsx_runtime450.jsx)(PromptInputFooter_default, { ...props }),
603754
604742
  engineRt.phase === "down" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsx)(ThemedText, { color: "warning", italic: true, children: " engine not responding \u2014 restarting\u2026" }) : engineRt.phase === "respawning" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsxs)(ThemedText, { color: "warning", italic: true, children: [
@@ -603759,7 +604747,11 @@ function PromptInputFooterWithFleet(props) {
603759
604747
  ")\u2026"
603760
604748
  ] }) : engineRt.phase === "recovered" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsx)(ThemedText, { dimColor: true, italic: true, children: " engine restarted \u2713 \u2014 press \u2191 then enter to resend the interrupted prompt" }) : engineRt.phase === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsxs)(ThemedText, { color: "error", italic: true, children: [
603761
604749
  " engine down \u2014 ",
603762
- engineRt.detail ?? "automatic restart failed; run sema doctor or restart sema"
604750
+ (() => {
604751
+ const detail = engineRt.detail ?? "automatic restart failed; run sema doctor or restart sema";
604752
+ return retryInS !== null ? detail.replace(/\s*[—;]?\s*retrying automatically in ~?\d+s\s*/, " ") : detail;
604753
+ })(),
604754
+ retryInS !== null ? ` \xB7 auto-retry in ${retryInS}s \xB7 send a message to retry now` : ""
603763
604755
  ] }) : null,
603764
604756
  upgrade2.phase === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsx)(ThemedText, { dimColor: true, italic: true, children: " engine update ready \xB7 applies between turns" }) : upgrade2.phase === "applying" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsx)(ThemedText, { dimColor: true, italic: true, children: " updating engine\u2026" }) : upgrade2.phase === "done" ? /* @__PURE__ */ (0, import_jsx_runtime450.jsxs)(ThemedText, { dimColor: true, italic: true, children: [
603765
604757
  " engine updated \u2713",
@@ -608901,10 +609893,12 @@ var init_autoDream = __esm({
608901
609893
  import * as fs14 from "fs/promises";
608902
609894
  import { homedir as homedir46 } from "os";
608903
609895
  import { join as join169 } from "path";
608904
- function getCutoffDate() {
609896
+ function getCleanupPeriodDays() {
608905
609897
  const settings2 = getSettings_DEPRECATED() || {};
608906
- const cleanupPeriodDays = settings2.cleanupPeriodDays ?? DEFAULT_CLEANUP_PERIOD_DAYS;
608907
- const cleanupPeriodMs = cleanupPeriodDays * 24 * 60 * 60 * 1e3;
609898
+ return settings2.cleanupPeriodDays ?? DEFAULT_CLEANUP_PERIOD_DAYS;
609899
+ }
609900
+ function getCutoffDate() {
609901
+ const cleanupPeriodMs = getCleanupPeriodDays() * 24 * 60 * 60 * 1e3;
608908
609902
  return new Date(Date.now() - cleanupPeriodMs);
608909
609903
  }
608910
609904
  function addCleanupResults(a, b3) {
@@ -608989,7 +609983,7 @@ async function tryRmdir(dirPath, fsImpl) {
608989
609983
  }
608990
609984
  async function cleanupOldSessionFiles() {
608991
609985
  const cutoffDate = getCutoffDate();
608992
- const result = { messages: 0, errors: 0 };
609986
+ let result = { messages: 0, errors: 0 };
608993
609987
  const projectsDir = getProjectsDir2();
608994
609988
  const fsImpl = getFsImplementation();
608995
609989
  let projectDirents;
@@ -609022,58 +610016,131 @@ async function cleanupOldSessionFiles() {
609022
610016
  }
609023
610017
  } else if (entry.isDirectory()) {
609024
610018
  const sessionDir = join169(projectDir2, entry.name);
609025
- const toolResultsDir = join169(sessionDir, TOOL_RESULTS_SUBDIR);
609026
- let toolDirs;
610019
+ result = addCleanupResults(
610020
+ result,
610021
+ await cleanupToolResultsUnderSession(sessionDir, cutoffDate, fsImpl)
610022
+ );
610023
+ result = addCleanupResults(
610024
+ result,
610025
+ await cleanupSubagentsUnderSession(sessionDir, cutoffDate, fsImpl)
610026
+ );
610027
+ await tryRmdir(sessionDir, fsImpl);
610028
+ }
610029
+ }
610030
+ await tryRmdir(projectDir2, fsImpl);
610031
+ }
610032
+ return result;
610033
+ }
610034
+ async function cleanupToolResultsUnderSession(sessionDir, cutoffDate, fsImpl) {
610035
+ const result = { messages: 0, errors: 0 };
610036
+ const toolResultsDir = join169(sessionDir, TOOL_RESULTS_SUBDIR);
610037
+ let toolDirs;
610038
+ try {
610039
+ toolDirs = await fsImpl.readdir(toolResultsDir);
610040
+ } catch {
610041
+ return result;
610042
+ }
610043
+ for (const toolEntry of toolDirs) {
610044
+ if (toolEntry.isFile()) {
610045
+ try {
610046
+ if (await unlinkIfOld(
610047
+ join169(toolResultsDir, toolEntry.name),
610048
+ cutoffDate,
610049
+ fsImpl
610050
+ )) {
610051
+ result.messages++;
610052
+ }
610053
+ } catch {
610054
+ result.errors++;
610055
+ }
610056
+ } else if (toolEntry.isDirectory()) {
610057
+ const toolDirPath = join169(toolResultsDir, toolEntry.name);
610058
+ let toolFiles;
610059
+ try {
610060
+ toolFiles = await fsImpl.readdir(toolDirPath);
610061
+ } catch {
610062
+ continue;
610063
+ }
610064
+ for (const tf of toolFiles) {
610065
+ if (!tf.isFile()) continue;
609027
610066
  try {
609028
- toolDirs = await fsImpl.readdir(toolResultsDir);
610067
+ if (await unlinkIfOld(join169(toolDirPath, tf.name), cutoffDate, fsImpl)) {
610068
+ result.messages++;
610069
+ }
609029
610070
  } catch {
609030
- await tryRmdir(sessionDir, fsImpl);
609031
- continue;
610071
+ result.errors++;
609032
610072
  }
609033
- for (const toolEntry of toolDirs) {
609034
- if (toolEntry.isFile()) {
610073
+ }
610074
+ await tryRmdir(toolDirPath, fsImpl);
610075
+ }
610076
+ }
610077
+ await tryRmdir(toolResultsDir, fsImpl);
610078
+ return result;
610079
+ }
610080
+ async function cleanupSubagentsUnderSession(sessionDir, cutoffDate, fsImpl) {
610081
+ const result = { messages: 0, errors: 0 };
610082
+ const subagentsDir = join169(sessionDir, "subagents");
610083
+ let entries;
610084
+ try {
610085
+ entries = await fsImpl.readdir(subagentsDir);
610086
+ } catch {
610087
+ return result;
610088
+ }
610089
+ for (const entry of entries) {
610090
+ if (entry.isFile()) {
610091
+ try {
610092
+ if (await unlinkIfOld(join169(subagentsDir, entry.name), cutoffDate, fsImpl)) {
610093
+ result.messages++;
610094
+ }
610095
+ } catch {
610096
+ result.errors++;
610097
+ }
610098
+ } else if (entry.isDirectory()) {
610099
+ const subDir = join169(subagentsDir, entry.name);
610100
+ let subEntries;
610101
+ try {
610102
+ subEntries = await fsImpl.readdir(subDir);
610103
+ } catch {
610104
+ continue;
610105
+ }
610106
+ for (const subEntry of subEntries) {
610107
+ if (subEntry.isFile()) {
610108
+ try {
610109
+ if (await unlinkIfOld(
610110
+ join169(subDir, subEntry.name),
610111
+ cutoffDate,
610112
+ fsImpl
610113
+ )) {
610114
+ result.messages++;
610115
+ }
610116
+ } catch {
610117
+ result.errors++;
610118
+ }
610119
+ } else if (subEntry.isDirectory()) {
610120
+ const runDir = join169(subDir, subEntry.name);
610121
+ let runFiles;
610122
+ try {
610123
+ runFiles = await fsImpl.readdir(runDir);
610124
+ } catch {
610125
+ continue;
610126
+ }
610127
+ for (const rf of runFiles) {
610128
+ if (!rf.isFile()) continue;
609035
610129
  try {
609036
- if (await unlinkIfOld(
609037
- join169(toolResultsDir, toolEntry.name),
609038
- cutoffDate,
609039
- fsImpl
609040
- )) {
610130
+ if (await unlinkIfOld(join169(runDir, rf.name), cutoffDate, fsImpl)) {
609041
610131
  result.messages++;
609042
610132
  }
609043
610133
  } catch {
609044
610134
  result.errors++;
609045
610135
  }
609046
- } else if (toolEntry.isDirectory()) {
609047
- const toolDirPath = join169(toolResultsDir, toolEntry.name);
609048
- let toolFiles;
609049
- try {
609050
- toolFiles = await fsImpl.readdir(toolDirPath);
609051
- } catch {
609052
- continue;
609053
- }
609054
- for (const tf of toolFiles) {
609055
- if (!tf.isFile()) continue;
609056
- try {
609057
- if (await unlinkIfOld(
609058
- join169(toolDirPath, tf.name),
609059
- cutoffDate,
609060
- fsImpl
609061
- )) {
609062
- result.messages++;
609063
- }
609064
- } catch {
609065
- result.errors++;
609066
- }
609067
- }
609068
- await tryRmdir(toolDirPath, fsImpl);
609069
610136
  }
610137
+ await tryRmdir(runDir, fsImpl);
609070
610138
  }
609071
- await tryRmdir(toolResultsDir, fsImpl);
609072
- await tryRmdir(sessionDir, fsImpl);
609073
610139
  }
610140
+ await tryRmdir(subDir, fsImpl);
609074
610141
  }
609075
- await tryRmdir(projectDir2, fsImpl);
609076
610142
  }
610143
+ await tryRmdir(subagentsDir, fsImpl);
609077
610144
  return result;
609078
610145
  }
609079
610146
  async function cleanupSingleDirectory(dirPath, extension2, removeEmptyDir = true) {
@@ -609172,6 +610239,36 @@ async function cleanupOldSessionEnvDirs() {
609172
610239
  }
609173
610240
  return result;
609174
610241
  }
610242
+ async function cleanupOldJobDirs() {
610243
+ const result = { messages: 0, errors: 0 };
610244
+ const fsImpl = getFsImplementation();
610245
+ const periodDays = JOB_GC_PERIOD_DAYS ?? getCleanupPeriodDays();
610246
+ const cutoffDate = new Date(Date.now() - periodDays * 24 * 60 * 60 * 1e3);
610247
+ let shorts;
610248
+ try {
610249
+ shorts = await listJobShorts();
610250
+ } catch {
610251
+ return result;
610252
+ }
610253
+ for (const short of shorts) {
610254
+ try {
610255
+ const state3 = await readJobState(short);
610256
+ if (!state3) continue;
610257
+ if (!isTerminalJobState(state3.state)) continue;
610258
+ if (isJobWorkerAlive(state3)) continue;
610259
+ const stats3 = await fsImpl.stat(getJobStatePath(short));
610260
+ if (stats3.mtime >= cutoffDate) continue;
610261
+ await fsImpl.rm(getJobDir(short), { recursive: true, force: true });
610262
+ logForDebugging(
610263
+ `job GC: removed terminal job dir ${short} (state=${state3.state}, mtime=${stats3.mtime.toISOString()} < ${cutoffDate.toISOString()})`
610264
+ );
610265
+ result.messages++;
610266
+ } catch {
610267
+ result.errors++;
610268
+ }
610269
+ }
610270
+ return result;
610271
+ }
609175
610272
  async function cleanupOldDebugLogs() {
609176
610273
  const cutoffDate = getCutoffDate();
609177
610274
  const result = { messages: 0, errors: 0 };
@@ -609313,6 +610410,7 @@ async function cleanupOldMessageFilesInBackground() {
609313
610410
  await cleanupOldPlanFiles();
609314
610411
  await cleanupOldFileHistoryBackups();
609315
610412
  await cleanupOldSessionEnvDirs();
610413
+ await cleanupOldJobDirs();
609316
610414
  await cleanupOldDebugLogs();
609317
610415
  await cleanupOldImageCaches();
609318
610416
  await cleanupOldPastes(getCutoffDate());
@@ -609324,10 +610422,11 @@ async function cleanupOldMessageFilesInBackground() {
609324
610422
  await cleanupNpmCacheForAnthropicPackages();
609325
610423
  }
609326
610424
  }
609327
- var DEFAULT_CLEANUP_PERIOD_DAYS, ONE_DAY_MS2;
610425
+ var DEFAULT_CLEANUP_PERIOD_DAYS, JOB_GC_PERIOD_DAYS, ONE_DAY_MS2;
609328
610426
  var init_cleanup = __esm({
609329
610427
  "build-src/src/utils/cleanup.ts"() {
609330
610428
  init_analytics_index();
610429
+ init_state2();
609331
610430
  init_cachePaths();
609332
610431
  init_debug();
609333
610432
  init_envUtils();
@@ -609343,6 +610442,7 @@ var init_cleanup = __esm({
609343
610442
  init_toolResultStorage();
609344
610443
  init_worktree();
609345
610444
  DEFAULT_CLEANUP_PERIOD_DAYS = 30;
610445
+ JOB_GC_PERIOD_DAYS = null;
609346
610446
  ONE_DAY_MS2 = 24 * 60 * 60 * 1e3;
609347
610447
  }
609348
610448
  });
@@ -613289,7 +614389,7 @@ __export(asciicast_exports, {
613289
614389
  renameRecordingForSession: () => renameRecordingForSession
613290
614390
  });
613291
614391
  import { appendFile as appendFile5, rename as rename14 } from "fs/promises";
613292
- import { basename as basename61, dirname as dirname74, join as join172 } from "path";
614392
+ import { basename as basename62, dirname as dirname74, join as join172 } from "path";
613293
614393
  function getRecordFilePath() {
613294
614394
  if (recordingState.filePath !== null) {
613295
614395
  return recordingState.filePath;
@@ -613341,8 +614441,8 @@ async function renameRecordingForSession() {
613341
614441
  return;
613342
614442
  }
613343
614443
  await recorder?.flush();
613344
- const oldName = basename61(oldPath);
613345
- const newName = basename61(newPath);
614444
+ const oldName = basename62(oldPath);
614445
+ const newName = basename62(newPath);
613346
614446
  try {
613347
614447
  await rename14(oldPath, newPath);
613348
614448
  recordingState.filePath = newPath;
@@ -613955,8 +615055,8 @@ async function processResumedConversation(result, opts, context3) {
613955
615055
  const { bindSessionPersistencePaths: bindSessionPersistencePaths2, reconcileResumeJournal: reconcileResumeJournal2 } = await Promise.resolve().then(() => (init_sessionPersistenceWire(), sessionPersistenceWire_exports));
613956
615056
  bindSessionPersistencePaths2();
613957
615057
  if (process.env.SEMA_RECONCILE_DIAG) {
613958
- const { appendFileSync: appendFileSync7 } = await import("fs");
613959
- appendFileSync7(
615058
+ const { appendFileSync: appendFileSync8 } = await import("fs");
615059
+ appendFileSync8(
613960
615060
  process.env.SEMA_RECONCILE_DIAG,
613961
615061
  `[entry] sid=${sid} baseUrl=${process.env.SEMA_LIVE_BASEURL ?? "UNSET"}
613962
615062
  `
@@ -613966,8 +615066,8 @@ async function processResumedConversation(result, opts, context3) {
613966
615066
  const { cancelEngineRun: cancelEngineRun2 } = await Promise.resolve().then(() => (init_seamQuery(), seamQuery_exports));
613967
615067
  const r = await reconcileResumeJournal2(void 0, (taskId) => cancelEngineRun2(taskId));
613968
615068
  if (process.env.SEMA_RECONCILE_DIAG) {
613969
- const { appendFileSync: appendFileSync7 } = await import("fs");
613970
- appendFileSync7(
615069
+ const { appendFileSync: appendFileSync8 } = await import("fs");
615070
+ appendFileSync8(
613971
615071
  process.env.SEMA_RECONCILE_DIAG,
613972
615072
  `[done] ${r.decision.lastState} -> ${r.recovery}
613973
615073
  `
@@ -613979,8 +615079,8 @@ async function processResumedConversation(result, opts, context3) {
613979
615079
  );
613980
615080
  }
613981
615081
  } else if (process.env.SEMA_RECONCILE_DIAG) {
613982
- const { appendFileSync: appendFileSync7 } = await import("fs");
613983
- appendFileSync7(process.env.SEMA_RECONCILE_DIAG, `[skip] baseUrl UNSET
615082
+ const { appendFileSync: appendFileSync8 } = await import("fs");
615083
+ appendFileSync8(process.env.SEMA_RECONCILE_DIAG, `[skip] baseUrl UNSET
613984
615084
  `);
613985
615085
  }
613986
615086
  } catch (ePw) {
@@ -623365,441 +624465,14 @@ var init_ScrollKeybindingHandler = __esm({
623365
624465
  }
623366
624466
  });
623367
624467
 
623368
- // build-src/src/utils/taskSummary.ts
623369
- var taskSummary_exports = {};
623370
- __export(taskSummary_exports, {
623371
- bgJobShort: () => bgJobShort,
623372
- blockedSummaryFor: () => blockedSummaryFor,
623373
- classifiedToPostTurnSummary: () => classifiedToPostTurnSummary,
623374
- classifierSummaryEnabled: () => classifierSummaryEnabled,
623375
- classifyTurnTail: () => classifyTurnTail,
623376
- emitTurnEndSummary: () => emitTurnEndSummary,
623377
- heuristicFallback: () => heuristicFallback,
623378
- notifySessionActivityForSummary: () => notifySessionActivityForSummary,
623379
- preClassifyTail: () => preClassifyTail,
623380
- runClassifierSummaryForBlocked: () => runClassifierSummaryForBlocked,
623381
- turnTail: () => turnTail
623382
- });
623383
- import { basename as basename62 } from "path";
623384
- function classifierSummaryEnabled() {
623385
- const v2 = process.env.SEMA_CODE_CLASSIFIER_SUMMARY ?? process.env[CLASSIFIER_SUMMARY_ENV];
623386
- if (v2 === void 0) return true;
623387
- return !/^(0|false|off|no|none)$/i.test(v2.trim());
623388
- }
623389
- function bgJobShort() {
623390
- const dir = process.env.SEMA_JOB_DIR;
623391
- if (!dir) return null;
623392
- const short = basename62(dir);
623393
- return short.length > 0 ? short : null;
623394
- }
623395
- function truncateDetail(s, max2 = DETAIL_MAX) {
623396
- if (s.length <= max2) return s;
623397
- let r = max2 - 1;
623398
- const c2 = s.charCodeAt(r - 1);
623399
- if (c2 >= 55296 && c2 <= 56319) r--;
623400
- return s.slice(0, r) + "\u2026";
623401
- }
623402
- function insideCodeFence(e, t2) {
623403
- let open20 = null;
623404
- let openLen = 0;
623405
- let o = 0;
623406
- while (o < t2) {
623407
- const i = e.indexOf("```", o);
623408
- const s = e.indexOf("~~~", o);
623409
- const a = i === -1 ? s : s === -1 ? i : Math.min(i, s);
623410
- if (a === -1 || a >= t2) break;
623411
- const ch2 = e[a];
623412
- let c2 = a - 1;
623413
- let u3 = 0;
623414
- while (c2 >= 0 && e[c2] === " " && u3 < 3) {
623415
- c2--;
623416
- u3++;
623417
- }
623418
- const atLineStart = c2 < 0 || e[c2] === "\n";
623419
- let len = 3;
623420
- o = a + 3;
623421
- while (e[o] === ch2) {
623422
- o++;
623423
- len++;
623424
- }
623425
- if (!atLineStart) continue;
623426
- if (open20 === null) {
623427
- open20 = ch2;
623428
- openLen = len;
623429
- } else if (open20 === ch2 && len >= openLen) {
623430
- open20 = null;
623431
- openLen = 0;
623432
- }
623433
- }
623434
- return open20 !== null;
623435
- }
623436
- function latestMarker(full, window2, windowStart) {
623437
- let best;
623438
- const table = [
623439
- ["failed", FAILED_MARKER],
623440
- ["blocked", NEEDS_INPUT_MARKER],
623441
- ["blocked", BLOCKED_MARKER],
623442
- ["blocked", IM_BLOCKED_MARKER]
623443
- ];
623444
- for (const [state3, re] of table) {
623445
- for (const m2 of window2.matchAll(re)) {
623446
- if (insideCodeFence(full, windowStart + m2.index)) continue;
623447
- if (!best || m2.index > best.index) {
623448
- best = {
623449
- state: state3,
623450
- capture: m2[1].trim(),
623451
- index: m2.index,
623452
- end: m2.index + m2[0].length
623453
- };
623454
- }
623455
- }
623456
- }
623457
- return best;
623458
- }
623459
- function preClassifyTail(text2) {
623460
- const t2 = text2.trim();
623461
- if (!t2) return null;
623462
- let window2 = t2.slice(-800);
623463
- let windowStart = t2.length - window2.length;
623464
- let resultMatch;
623465
- for (const m2 of window2.matchAll(/(?:^|\n)\s*result:\s*(.+?)\s*(?:\n|$)/gi)) {
623466
- if (!insideCodeFence(t2, windowStart + m2.index)) resultMatch = m2;
623467
- }
623468
- if (resultMatch) {
623469
- const after = resultMatch.index + resultMatch[0].length;
623470
- window2 = window2.slice(after);
623471
- windowStart += after;
623472
- }
623473
- const marker = latestMarker(t2, window2, windowStart);
623474
- if (resultMatch && !marker) {
623475
- const detail = truncateDetail(resultMatch[1]);
623476
- const hasNext = [...window2.matchAll(/(?:^|\n)\s*next:\s*\S/gi)].some(
623477
- (m2) => !insideCodeFence(t2, windowStart + m2.index)
623478
- );
623479
- if (hasNext) return { branch: "result-then-next", state: "working", tempo: "idle", detail };
623480
- return { branch: "result-marker", state: "done", tempo: "idle", detail };
623481
- }
623482
- if (marker?.state === "failed") {
623483
- return { branch: "failed-marker", state: "failed", tempo: "idle", detail: truncateDetail(marker.capture) };
623484
- }
623485
- if (marker?.state === "blocked") {
623486
- const after = window2.slice(marker.end);
623487
- const paras = after.split(/\n\s*\n/).filter((p) => p.trim().length > 0).length;
623488
- if (paras >= 3) return null;
623489
- if (!/\bnothing (?:needed|required) from you\b|\bno(?: user)? action (?:needed|required)\b/i.test(
623490
- window2
623491
- )) {
623492
- const m2 = truncateDetail(marker.capture);
623493
- return { branch: "blocked-marker", state: "blocked", tempo: "blocked", needs: m2, detail: m2 };
623494
- }
623495
- return null;
623496
- }
623497
- const tail800 = t2.slice(-800);
623498
- if (/[??]\s*$/.test(tail800) && tail800.replace(/[??\s]+$/, "").length >= 4) {
623499
- const f = Math.max(
623500
- tail800.lastIndexOf("\n"),
623501
- tail800.lastIndexOf(". "),
623502
- tail800.lastIndexOf("! "),
623503
- tail800.lastIndexOf("? ", tail800.length - 2)
623504
- );
623505
- if (!insideCodeFence(t2, t2.length - tail800.length + f)) {
623506
- const q2 = truncateDetail(tail800.slice(f + 1).trim());
623507
- if (!OPTIONAL_OFFER.test(q2)) {
623508
- return { branch: "trailing-q", state: "blocked", tempo: "blocked", needs: q2, detail: q2 };
623509
- }
623510
- return null;
623511
- }
623512
- }
623513
- const a = Math.max(
623514
- 0,
623515
- tail800.lastIndexOf(". "),
623516
- tail800.lastIndexOf("! "),
623517
- tail800.lastIndexOf("? "),
623518
- tail800.lastIndexOf("\n")
623519
- );
623520
- const l3 = tail800.slice(a).replace(/^[.!?\s]+/, "");
623521
- const fenced = insideCodeFence(t2, t2.length - tail800.length + a);
623522
- const waitExt = WAIT_EXTERNAL.exec(l3);
623523
- if (waitExt && !fenced) {
623524
- return { branch: "wait-external", state: "working", tempo: "idle", detail: truncateDetail(waitExt[0]) };
623525
- }
623526
- const awaiting = AWAITING_USER.exec(l3);
623527
- if (awaiting && !fenced) {
623528
- const f = truncateDetail(l3.slice(awaiting.index).trim());
623529
- return { branch: "awaiting-user", state: "blocked", tempo: "blocked", needs: f, detail: f };
623530
- }
623531
- const ask2 = ASK_VERB.exec(l3);
623532
- if (ask2 && !fenced) {
623533
- const f = truncateDetail(l3.slice(ask2.index).trim());
623534
- return { branch: "ask-verb", state: "blocked", tempo: "blocked", needs: f, detail: f };
623535
- }
623536
- if (!fenced && AUTH_PROSE.test(l3)) {
623537
- return {
623538
- branch: "auth-prose",
623539
- state: "blocked",
623540
- tempo: "blocked",
623541
- needs: truncateDetail(l3),
623542
- detail: "authentication required"
623543
- };
623544
- }
623545
- if (!fenced && WORKING_VERB.test(l3) && !NOT_FORWARD_INTENT.test(l3)) {
623546
- return { branch: "working-verb", state: "working", tempo: "active", detail: truncateDetail(l3) };
623547
- }
623548
- if (!fenced && AGENTS_STATUS.test(l3)) {
623549
- return { branch: "agents-status", state: "working", tempo: "idle", detail: truncateDetail(l3) };
623550
- }
623551
- if (!fenced && WILL_CHECK_BACK.test(l3)) {
623552
- return { branch: "will-check-back", state: "working", tempo: "idle", detail: truncateDetail(l3) };
623553
- }
623554
- if (!fenced && CANT_PROCEED.test(l3)) {
623555
- const f = truncateDetail(l3);
623556
- return { branch: "cant-proceed", state: "blocked", tempo: "blocked", detail: f, needs: f };
623557
- }
623558
- if (!fenced && GIVING_UP.test(l3)) {
623559
- return { branch: "giving-up", state: "failed", tempo: "idle", detail: truncateDetail(l3) };
623560
- }
623561
- if (!fenced && PUSHED_COMMITTED.test(l3)) {
623562
- return { branch: "pushed-committed", state: "done", tempo: "idle", detail: truncateDetail(l3) };
623563
- }
623564
- if (!fenced && READY_FOR.test(l3)) {
623565
- return { branch: "ready-for", state: "done", tempo: "idle", detail: truncateDetail(l3) };
623566
- }
623567
- if (!fenced && VERDICT_MARKER.test(l3)) {
623568
- return { branch: "verdict-marker", state: "done", tempo: "idle", detail: truncateDetail(l3) };
623569
- }
623570
- if (!fenced && PLEASE_DO_X.test(l3)) {
623571
- const f = truncateDetail(l3);
623572
- return { branch: "please-do-x", state: "blocked", tempo: "blocked", detail: f, needs: f };
623573
- }
623574
- if (!fenced && STOPPING_HERE.test(l3)) {
623575
- const f = truncateDetail(l3);
623576
- return { branch: "stopping-here", state: "blocked", tempo: "blocked", detail: f, needs: f };
623577
- }
623578
- return null;
623579
- }
623580
- function heuristicFallback(text2) {
623581
- const line = text2.split("\n").map((l3) => l3.trim()).findLast(Boolean);
623582
- return {
623583
- branch: "heuristic",
623584
- state: "working",
623585
- tempo: "idle",
623586
- detail: line ? truncateDetail(line) : "\u2014"
623587
- };
623588
- }
623589
- function classifyTurnTail(text2) {
623590
- const c2 = preClassifyTail(text2) ?? heuristicFallback(text2);
623591
- if (c2.tempo === "active" && c2.state === "working") return { ...c2, tempo: "idle" };
623592
- return c2;
623593
- }
623594
- function classifiedToPostTurnSummary(c2) {
623595
- return {
623596
- status_category: c2.state === "blocked" ? "blocked" : "review_ready",
623597
- status_detail: c2.detail,
623598
- needs_action: c2.state === "blocked" ? c2.needs ?? "" : ""
623599
- };
623600
- }
623601
- function assistantText(m2) {
623602
- const c2 = m2.message?.content;
623603
- if (typeof c2 === "string") return c2.trim();
623604
- if (!Array.isArray(c2)) return "";
623605
- return c2.map((b3) => b3?.type === "text" && typeof b3.text === "string" ? b3.text : "").filter(Boolean).join("\n").trim();
623606
- }
623607
- function turnTail(messages) {
623608
- const msgs = messages;
623609
- let start = 0;
623610
- for (let i = msgs.length - 1; i >= 0; i--) {
623611
- const m2 = msgs[i];
623612
- if (m2.type === "user" && !m2.isMeta && typeof m2.message?.content === "string") {
623613
- start = i + 1;
623614
- break;
623615
- }
623616
- }
623617
- const parts = [];
623618
- let lastAssistantUuid = "";
623619
- for (let i = start; i < msgs.length; i++) {
623620
- const m2 = msgs[i];
623621
- if (m2.type !== "assistant" || m2.isApiErrorMessage) continue;
623622
- const text2 = assistantText(m2);
623623
- if (text2) parts.push(text2);
623624
- if (typeof m2.uuid === "string") lastAssistantUuid = m2.uuid;
623625
- }
623626
- return { text: parts.join("\n\n"), lastAssistantUuid };
623627
- }
623628
- function chainBgWrite(fn2) {
623629
- bgWriteChain = bgWriteChain.then(fn2).catch(() => {
623630
- });
623631
- return bgWriteChain;
623632
- }
623633
- async function writeBgTurnEnd(short, c2) {
623634
- bgBlockedByActivity = false;
623635
- const cur = await readJobState(short);
623636
- if (!cur) return;
623637
- const curTerminal = isTerminalJobState(cur.state);
623638
- const nextTerminal = c2.state === "done" || c2.state === "failed";
623639
- const terminal = curTerminal || nextTerminal;
623640
- await patchJobState(short, {
623641
- state: curTerminal ? cur.state : c2.state,
623642
- detail: c2.detail,
623643
- tempo: terminal ? "idle" : c2.tempo,
623644
- needs: c2.tempo === "blocked" && !terminal ? c2.needs : void 0,
623645
- ...terminal && !cur.firstTerminalAt ? { firstTerminalAt: Date.now() } : {}
623646
- });
623647
- }
623648
- function emitForegroundSummary(c2, summarizesUuid) {
623649
- const y2 = classifiedToPostTurnSummary(c2);
623650
- notifySessionMetadataChanged({ post_turn_summary: y2 });
623651
- enqueueSdkEvent({
623652
- type: "system",
623653
- subtype: "post_turn_summary",
623654
- summarizes_uuid: summarizesUuid,
623655
- status_category: y2.status_category,
623656
- status_detail: y2.status_detail,
623657
- needs_action: y2.needs_action,
623658
- is_noteworthy: false,
623659
- title: "",
623660
- description: "",
623661
- recent_action: "",
623662
- artifact_urls: []
623663
- });
623664
- }
623665
- async function emitTurnEndSummary(messages) {
623666
- if (!classifierSummaryEnabled()) return;
623667
- const { text: text2, lastAssistantUuid } = turnTail(messages);
623668
- if (!/[\p{L}\p{N}]/u.test(text2)) return;
623669
- const classified = classifyTurnTail(text2);
623670
- const short = bgJobShort();
623671
- if (short) {
623672
- await chainBgWrite(() => writeBgTurnEnd(short, classified));
623673
- return;
623674
- }
623675
- emitForegroundSummary(classified, lastAssistantUuid);
623676
- }
623677
- function blockedSummaryFor(details) {
623678
- if (details.tool_name.startsWith("dialog:")) {
623679
- return {
623680
- status_category: "blocked",
623681
- status_detail: "Waiting on a user dialog",
623682
- needs_action: details.action_description ?? ""
623683
- };
623684
- }
623685
- return {
623686
- status_category: "blocked",
623687
- status_detail: `Waiting on permission: ${details.tool_name}`,
623688
- needs_action: `Approve or deny ${details.tool_name}`
623689
- };
623690
- }
623691
- function runClassifierSummaryForBlocked(details) {
623692
- if (!classifierSummaryEnabled()) return;
623693
- if (bgJobShort()) return;
623694
- notifySessionMetadataChanged({ post_turn_summary: blockedSummaryFor(details) });
623695
- }
623696
- async function writeBgBlocked(short, summary) {
623697
- const cur = await readJobState(short);
623698
- if (!cur || isTerminalJobState(cur.state)) return;
623699
- if (cur.tempo === "blocked" && cur.needs === summary.needs_action) return;
623700
- await patchJobState(short, {
623701
- state: "blocked",
623702
- tempo: "blocked",
623703
- detail: summary.status_detail,
623704
- needs: summary.needs_action || summary.status_detail
623705
- });
623706
- }
623707
- async function writeBgUnblocked(short, busy) {
623708
- const cur = await readJobState(short);
623709
- if (!cur) return;
623710
- if (busy) {
623711
- bgBlockedByActivity = false;
623712
- if (cur.tempo === "active" && !isTerminalJobState(cur.state) && cur.state !== "blocked") return;
623713
- const reviving = isTerminalJobState(cur.state);
623714
- await patchJobState(
623715
- short,
623716
- {
623717
- state: reviving || cur.state === "blocked" ? "working" : cur.state,
623718
- tempo: "active",
623719
- needs: void 0,
623720
- ...reviving ? { firstTerminalAt: void 0 } : {}
623721
- },
623722
- { allowRevive: true }
623723
- );
623724
- return;
623725
- }
623726
- if (!bgBlockedByActivity) return;
623727
- bgBlockedByActivity = false;
623728
- if (cur.tempo !== "blocked" || isSettledJobState(cur)) return;
623729
- await patchJobState(short, {
623730
- state: cur.state === "blocked" ? "working" : cur.state,
623731
- tempo: "idle",
623732
- needs: void 0
623733
- });
623734
- }
623735
- function notifySessionActivityForSummary(input) {
623736
- if (!classifierSummaryEnabled()) return;
623737
- const prev = prevActivityStatus;
623738
- prevActivityStatus = input.status;
623739
- const short = bgJobShort();
623740
- if (input.status === "waiting") {
623741
- const w2 = input.waitingFor ?? "";
623742
- const details = w2.startsWith("approve ") ? { tool_name: w2.slice("approve ".length), action_description: w2 } : { tool_name: "dialog:" + (w2 || "input"), action_description: w2 || "input needed" };
623743
- const summary = blockedSummaryFor(details);
623744
- if (short) {
623745
- bgBlockedByActivity = true;
623746
- void chainBgWrite(() => writeBgBlocked(short, summary));
623747
- } else {
623748
- notifySessionMetadataChanged({ post_turn_summary: summary });
623749
- }
623750
- return;
623751
- }
623752
- if (input.status === "idle" && prev === "busy" && input.getMessages) {
623753
- const messages = input.getMessages();
623754
- void emitTurnEndSummary(messages);
623755
- return;
623756
- }
623757
- if (short) {
623758
- void chainBgWrite(() => writeBgUnblocked(short, input.status === "busy"));
623759
- }
623760
- }
623761
- var CLASSIFIER_SUMMARY_ENV, DETAIL_MAX, FAILED_MARKER, NEEDS_INPUT_MARKER, BLOCKED_MARKER, IM_BLOCKED_MARKER, OPTIONAL_OFFER, WORKING_VERB, NOT_FORWARD_INTENT, AGENTS_STATUS, WILL_CHECK_BACK, CANT_PROCEED, GIVING_UP, PUSHED_COMMITTED, READY_FOR, VERDICT_MARKER, PLEASE_DO_X, STOPPING_HERE, WAIT_EXTERNAL, AWAITING_USER, ASK_VERB, AUTH_PROSE, bgWriteChain, bgBlockedByActivity, prevActivityStatus;
623762
- var init_taskSummary = __esm({
623763
- "build-src/src/utils/taskSummary.ts"() {
623764
- init_state2();
623765
- init_sdkEventQueue();
623766
- init_sessionState();
623767
- CLASSIFIER_SUMMARY_ENV = "CLAUDE_CODE_CLASSIFIER_SUMMARY";
623768
- DETAIL_MAX = 800;
623769
- FAILED_MARKER = /(?:^|\n)\s*failed\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
623770
- NEEDS_INPUT_MARKER = /(?:^|\n)\s*needs input\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
623771
- BLOCKED_MARKER = /(?:^|\n)\s*blocked\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
623772
- IM_BLOCKED_MARKER = /\bI'?m blocked\s*[:—–-]\s*(.{3,200}?)(?=\n|$)/gi;
623773
- OPTIONAL_OFFER = /\b(?:want|like) me to\b|\b(?:shall|should) I also\b/i;
623774
- WORKING_VERB = /^(?:(?:Now|Next|Then|Alright|OK|Okay|Right|Good|First|Also),?\s+)?(?:Let me (?!know\b)|(?:I(?:'?ll| will) |I'?m going to |Going to )(?!need\b|require\b|wait\b|leave\b|hold\b|skip\b|stop\b)|Proceeding |Moving (?:on|to)\b|Continuing |Starting |Trying |Checking |Looking |Searching |Reading |Investigating |Running |Re-?running |Building |Rebuilding |Installing |Fetching |Applying |Fixing |Patching |Updating |Adding |Removing |Deleting |Importing |Refactoring |Rewriting |Writing |Grepping |Scanning |Wrapping |Switching |Testing |Verifying |Regenerating |Pushing |Pulling |Reviewing |Examining |Loading |Compiling |Parsing |Analyzing |Tracing |Exploring )/i;
623775
- NOT_FORWARD_INTENT = /\b(?:once |when |after |until |as soon as )(?:you|it|the|that|this|they)\b|\bagain in\b|\bcheck back\b|\bin ~?\d+\s*(?:s(?:ec(?:ond)?s?)?|m(?:in(?:ute)?s?)?|h(?:ours?|rs?)?)\b|\bthen\.?\s*$|\bwhichever you\b|\bhold(?:ing)? for your\b|\b(?:to|and) wait for\b|\bgive it (?:more |some )?time\b|\bif (?:you(?:'d| want| prefer| need|'re)?|that(?:'s| helps| works)?|useful|needed|helpful|desired)\b|\b(?:isn'?t|not|won'?t) going to work\b/i;
623776
- AGENTS_STATUS = /^(?:(?:\*\*)?[1-9]\d* (?:agent|cron|task|fork|job|worker|PR|check)s? (?:in flight|remaining|active|still (?:running|working)|pending|running|launched)\b|(?:Continuous )?(?:[Ll]oop|[Cc]rons?|[Bb]abysit) (?:active|healthy|continuing|running|will keep|continues)\b|Waiting for (?:the )?(?:agent|cron|task|fork|worker|job|remaining|them)s?\b|Agents? will report back\b|Waiting\.?$)/;
623777
- WILL_CHECK_BACK = /^(?:I will|I'll|Will) (?:check back|re-?check|poll|look again|retry|re-?run|try again) (?:(?:when|once|after|until) (?!your?\b)|in\b|again\b)/i;
623778
- CANT_PROCEED = /^I (?:can(?:'?t|not)|am unable to) (?:proceed|continue|make (?:any )?progress|complete|fix this)\b/i;
623779
- GIVING_UP = /^(?:Giving up|I(?:'m| am) giving up|The task is not actionable)\b/i;
623780
- PUSHED_COMMITTED = /^(?:Pushed (?:to `|`[0-9a-f]{7,})|Committed as `?[0-9a-f]{7,}\b|Commit: `?[0-9a-f]{7,}\b|(?:Opened|Created) PR #?\d)/;
623781
- READY_FOR = /^Ready (?:for review|to (?:upload|merge|ship|land))\b/;
623782
- VERDICT_MARKER = /^VERDICT: (?:PASS|FAIL)\b/;
623783
- PLEASE_DO_X = /^Please (?:start|run|provide|grant|export|add|install|configure|give me|paste|point me|set (?:the |up |`?[A-Z][A-Z0-9_]+\b))/;
623784
- STOPPING_HERE = /^(?:Stopping here|I've stopped here|Parked (?:the|this) branch|Paused here)(?:\.|$| —| -| until| pending| since| because)/i;
623785
- WAIT_EXTERNAL = /\b(?:waiting (?:for|on)|pending)\s+(?:the\s+)?(?:CI|build|tests?|reviewer|deploy(?:ment)?|workflow|checks?|rollout|merge queue)\b/i;
623786
- AWAITING_USER = /\b(?:awaiting|waiting (?:for|on)|pending)\s+(?:your\s+(?:feedback|input|decision|response|approval|direction|guidance|go-ahead)|you\b|the user\b)/i;
623787
- ASK_VERB = /\b(please (?:run|provide|confirm|clarify|choose|let me know)|let me know (?:which|what|how|when)|which (?:option|approach|one)|should I (?:proceed|continue|use))\b/i;
623788
- AUTH_PROSE = /\b(not logged in|please run \/login|authentication failed|invalid api key|oauth token (?:expired|revoked)|credit balance (?:is )?too low|usage limit reached|mcp (?:server )?(?:authentication|auth|authorization|unauthorized)|mcp (?:server )?(?:credential|token) (?:missing|expired|invalid)|401 unauthorized|403 forbidden|token (?:has )?expired|bad credentials|gh auth login|gcloud auth login|aws (?:sso )?login)\b/i;
623789
- bgWriteChain = Promise.resolve();
623790
- bgBlockedByActivity = false;
623791
- prevActivityStatus = "idle";
623792
- }
623793
- });
623794
-
623795
624468
  // build-src/src/screens/REPL.tsx
623796
624469
  var REPL_exports = {};
623797
624470
  __export(REPL_exports, {
623798
624471
  REPL: () => REPL
623799
624472
  });
623800
- import { spawnSync as spawnSync10 } from "child_process";
624473
+ import { spawnSync as spawnSync11 } from "child_process";
623801
624474
  import { dirname as dirname76, join as join175 } from "path";
623802
- import { tmpdir as tmpdir15 } from "os";
624475
+ import { tmpdir as tmpdir16 } from "os";
623803
624476
  import { writeFile as writeFile48 } from "fs/promises";
623804
624477
  import { randomUUID as randomUUID50 } from "crypto";
623805
624478
  function TranscriptModeFooter(t0) {
@@ -626215,7 +626888,7 @@ Error: sandbox required but unavailable: ${reason}
626215
626888
  const handleExit = (0, import_react337.useCallback)(async () => {
626216
626889
  setIsExiting(true);
626217
626890
  if (isBgSession()) {
626218
- spawnSync10("tmux", ["detach-client"], {
626891
+ spawnSync11("tmux", ["detach-client"], {
626219
626892
  stdio: "ignore"
626220
626893
  });
626221
626894
  setIsExiting(false);
@@ -626747,7 +627420,7 @@ Note: ctrl + z now suspends Sema, ctrl + _ undoes input.
626747
627420
  const w2 = Math.max(80, (process.stdout.columns ?? 80) - 6);
626748
627421
  const raw2 = await renderMessagesToPlainText(deferredMessages, tools, w2);
626749
627422
  const text2 = raw2.replace(/[ \t]+$/gm, "");
626750
- const path27 = join175(tmpdir15(), `cc-transcript-${Date.now()}.txt`);
627423
+ const path27 = join175(tmpdir16(), `cc-transcript-${Date.now()}.txt`);
626751
627424
  await writeFile48(path27, text2);
626752
627425
  const opened = openFileInExternalEditor(path27);
626753
627426
  setStatus(opened ? `opening ${path27}` : `wrote ${path27} \xB7 no $VISUAL/$EDITOR set`);
@@ -632952,7 +633625,7 @@ async function collectEngineRows() {
632952
633625
  try {
632953
633626
  return configuredEnginePort();
632954
633627
  } catch {
632955
- return { port: DEFAULT_ENGINE_PORT, source: "default" };
633628
+ return { port: derivedDefaultEnginePort(), source: "default" };
632956
633629
  }
632957
633630
  })();
632958
633631
  const configuredPort2 = cp2.port;
@@ -633165,6 +633838,7 @@ var init_semaSections = __esm({
633165
633838
  init_ink2();
633166
633839
  init_envUtils();
633167
633840
  init_engineLifecycleManager();
633841
+ init_enginePortDerive();
633168
633842
  init_engineTarget();
633169
633843
  init_semaUpdater();
633170
633844
  init_axesRows();
@@ -639752,6 +640426,10 @@ function toLiveRequest(req, capturedSessionId) {
639752
640426
  ;
639753
640427
  out6.forwardSubagentEvents = true;
639754
640428
  }
640429
+ if (out6.retainSubagentSessions === void 0) {
640430
+ ;
640431
+ out6.retainSubagentSessions = true;
640432
+ }
639755
640433
  if (typeof out6.scenario === "string" && SEMA_MOCK_SCENARIO_KEYS.has(out6.scenario)) {
639756
640434
  delete out6.scenario;
639757
640435
  }
@@ -640281,6 +640959,7 @@ __export(seamQueryEngine_exports, {
640281
640959
  makeAdapterQuery: () => makeAdapterQuery,
640282
640960
  makeCanUseTool: () => makeCanUseTool,
640283
640961
  makeHitlCanUseTool: () => makeHitlCanUseTool,
640962
+ printTaskNotificationDedupKey: () => printTaskNotificationDedupKey,
640284
640963
  runStream: () => runStream,
640285
640964
  setQueryEngineClient: () => setQueryEngineClient
640286
640965
  });
@@ -640333,6 +641012,10 @@ function notifiedOnce(key) {
640333
641012
  printNotifiedKeys.add(key);
640334
641013
  return false;
640335
641014
  }
641015
+ function printTaskNotificationDedupKey(n2) {
641016
+ const lane = n2.task_type === "external" ? "external:" : "";
641017
+ return `${lane}${String(n2.task_id)}:${String(n2.status)}${n2.seq !== void 0 ? `:${String(n2.seq)}` : ""}`;
641018
+ }
640336
641019
  async function* ask(params) {
640337
641020
  const activeClient = await resolveClient();
640338
641021
  if (!clientExplicitlySet2 && !process.env.SEMA_LIVE_BASEURL && !process.env.SEMA_SCENARIO) {
@@ -640460,7 +641143,7 @@ async function* ask(params) {
640460
641143
  }
640461
641144
  if (t2 === "task_notification") {
640462
641145
  const n2 = msg.notification;
640463
- if (n2 && typeof n2.task_id === "string" && !notifiedOnce(`${n2.task_id}:${String(n2.status)}${n2.seq !== void 0 ? `:${String(n2.seq)}` : ""}`)) {
641146
+ if (n2 && typeof n2.task_id === "string" && !notifiedOnce(printTaskNotificationDedupKey(n2))) {
640464
641147
  const s = n2.status;
640465
641148
  yield {
640466
641149
  type: "system",
@@ -651961,8 +652644,8 @@ __export(cloudResources_exports, {
651961
652644
  cloudResourceRemove: () => cloudResourceRemove,
651962
652645
  cloudResourceSync: () => cloudResourceSync
651963
652646
  });
651964
- import { createHash as createHash25 } from "node:crypto";
651965
- import { existsSync as existsSync25, readdirSync as readdirSync8, readFileSync as readFileSync39, statSync as statSync12 } from "node:fs";
652647
+ import { createHash as createHash26 } from "node:crypto";
652648
+ import { existsSync as existsSync25, readdirSync as readdirSync9, readFileSync as readFileSync39, statSync as statSync12 } from "node:fs";
651966
652649
  import { basename as basename64, dirname as dirname81, isAbsolute as isAbsolute32, join as join186, resolve as resolve47 } from "node:path";
651967
652650
  function fail4(e) {
651968
652651
  err6(`Error: ${e instanceof Error ? e.message : String(e)}`);
@@ -652558,7 +653241,7 @@ async function readSkillEntry(file2, fallbackName) {
652558
653241
  if (!content) {
652559
653242
  return { name, display: display2, entry: null, notes: [], skipReason: `${file2} has no body after the frontmatter \u2014 nothing to upload.` };
652560
653243
  }
652561
- const contentHash = `sha256:${createHash25("sha256").update(content, "utf8").digest("hex")}`;
653244
+ const contentHash = `sha256:${createHash26("sha256").update(content, "utf8").digest("hex")}`;
652562
653245
  return {
652563
653246
  name,
652564
653247
  display: display2,
@@ -652572,7 +653255,7 @@ async function loadLocalSkillEntries() {
652572
653255
  for (const root2 of roots) {
652573
653256
  let dirs = [];
652574
653257
  try {
652575
- dirs = readdirSync8(root2).filter((d2) => {
653258
+ dirs = readdirSync9(root2).filter((d2) => {
652576
653259
  try {
652577
653260
  return statSync12(join186(root2, d2)).isDirectory() && existsSync25(join186(root2, d2, "SKILL.md"));
652578
653261
  } catch {
@@ -657389,7 +658072,7 @@ import {
657389
658072
  copyFileSync as copyFileSync5,
657390
658073
  existsSync as existsSync27,
657391
658074
  mkdirSync as mkdirSync21,
657392
- readdirSync as readdirSync9,
658075
+ readdirSync as readdirSync10,
657393
658076
  readFileSync as readFileSync40,
657394
658077
  statSync as statSync14
657395
658078
  } from "node:fs";
@@ -657536,7 +658219,7 @@ function syncTree(srcDir, destDir, labelBase, opts, report) {
657536
658219
  syncPlainFile(srcDir, destDir, labelBase, opts, report);
657537
658220
  return;
657538
658221
  }
657539
- for (const name of readdirSync9(srcDir)) {
658222
+ for (const name of readdirSync10(srcDir)) {
657540
658223
  const srcChild = join189(srcDir, name);
657541
658224
  const destChild = join189(destDir, name);
657542
658225
  let childStat;
@@ -658357,7 +659040,7 @@ var init_navStack = __esm({
658357
659040
  });
658358
659041
 
658359
659042
  // build-src/src/sema/config/skillsChannels.ts
658360
- import { existsSync as existsSync28, mkdirSync as mkdirSync22, readdirSync as readdirSync10, readFileSync as readFileSync43, realpathSync as realpathSync11, renameSync as renameSync8, statSync as statSync15 } from "node:fs";
659043
+ import { existsSync as existsSync28, mkdirSync as mkdirSync22, readdirSync as readdirSync11, readFileSync as readFileSync43, realpathSync as realpathSync11, renameSync as renameSync8, statSync as statSync15 } from "node:fs";
658361
659044
  import { basename as basename66, dirname as dirname85, join as join192 } from "node:path";
658362
659045
  function skillsDirFor(source) {
658363
659046
  return source === "user" ? join192(getClaudeConfigHomeDir(), "skills") : join192(getCwd(), ".sema", "skills");
@@ -658414,7 +659097,7 @@ function listInstalledSkills() {
658414
659097
  const dir = skillsDirFor(source);
658415
659098
  let entries;
658416
659099
  try {
658417
- entries = readdirSync10(dir).filter((n2) => !n2.startsWith("."));
659100
+ entries = readdirSync11(dir).filter((n2) => !n2.startsWith("."));
658418
659101
  } catch {
658419
659102
  continue;
658420
659103
  }
@@ -658535,7 +659218,7 @@ function settingsEnv3() {
658535
659218
  function configuredEnginePort2() {
658536
659219
  const raw2 = settingsEnv3().SEMA_ENGINE_PORT ?? process.env.SEMA_ENGINE_PORT;
658537
659220
  const p = raw2 ? Number.parseInt(raw2, 10) : NaN;
658538
- return Number.isInteger(p) && p > 0 && p < 65536 ? p : DEFAULT_ENGINE_PORT;
659221
+ return Number.isInteger(p) && p > 0 && p < 65536 ? p : derivedDefaultEnginePort();
658539
659222
  }
658540
659223
  function engineSummary() {
658541
659224
  const autostart = process.env.SEMA_TOC_ENGINE === "0" ? "autostart off" : "autostart on";
@@ -658559,7 +659242,7 @@ function portEditScreen() {
658559
659242
  title: "Engine \xB7 port",
658560
659243
  label: "Port:",
658561
659244
  initial: String(configuredEnginePort2()),
658562
- placeholder: String(DEFAULT_ENGINE_PORT),
659245
+ placeholder: String(derivedDefaultEnginePort()),
658563
659246
  onSubmit: (v2) => {
658564
659247
  const p = Number.parseInt(v2, 10);
658565
659248
  if (!Number.isInteger(p) || p <= 0 || p >= 65536) {
@@ -658640,7 +659323,7 @@ var init_EngineScreen = __esm({
658640
659323
  init_select();
658641
659324
  init_semaSections();
658642
659325
  init_envUtils();
658643
- init_engineLifecycleManager();
659326
+ init_enginePortDerive();
658644
659327
  init_applyOnboard();
658645
659328
  init_catalogScreens();
658646
659329
  import_jsx_runtime509 = __toESM(require_jsx_runtime(), 1);
@@ -664200,7 +664883,7 @@ Auth: unix socket -R \u2192 local proxy`, "info");
664200
664883
  pendingHookMessages
664201
664884
  }, renderAndRun);
664202
664885
  }
664203
- }).version("sema 1.0.1", "-v, --version", "Output the version number");
664886
+ }).version("sema 1.0.3", "-v, --version", "Output the version number");
664204
664887
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
664205
664888
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
664206
664889
  if (canUserConfigureAdvisor()) {
@@ -665187,8 +665870,8 @@ Auth: unix socket -R \u2192 local proxy`, "info");
665187
665870
  const completed = await onboardHandler2();
665188
665871
  if (completed && process.env.SEMA_ONBOARD_NO_LAUNCH !== "1") {
665189
665872
  try {
665190
- const { spawnSync: spawnSync12 } = await import("node:child_process");
665191
- spawnSync12(process.execPath, [process.argv[1]], { stdio: "inherit" });
665873
+ const { spawnSync: spawnSync13 } = await import("node:child_process");
665874
+ spawnSync13(process.execPath, [process.argv[1]], { stdio: "inherit" });
665192
665875
  } catch {
665193
665876
  }
665194
665877
  }
@@ -668505,12 +669188,12 @@ var init_skillsFill = __esm({
668505
669188
  });
668506
669189
 
668507
669190
  // build-src/mock/commands/teamOnboarding.ts
668508
- import { existsSync as existsSync31, readdirSync as readdirSync11 } from "fs";
669191
+ import { existsSync as existsSync31, readdirSync as readdirSync12 } from "fs";
668509
669192
  function hasWorkspaceData() {
668510
669193
  try {
668511
669194
  const dir = getProjectsDir2();
668512
669195
  if (!existsSync31(dir)) return false;
668513
- return readdirSync11(dir).length > 0;
669196
+ return readdirSync12(dir).length > 0;
668514
669197
  } catch {
668515
669198
  return false;
668516
669199
  }
@@ -669771,6 +670454,17 @@ async function runDaemonWorker(kind) {
669771
670454
  });
669772
670455
  const { installWorkerVirtualTerminal: installWorkerVirtualTerminal2 } = await Promise.resolve().then(() => (init_workerScreen(), workerScreen_exports));
669773
670456
  installWorkerVirtualTerminal2({ cols: config5.cols, rows: config5.rows, jobDir: config5.jobDir });
670457
+ try {
670458
+ const { subscribeEngineRuntimeStatus: subscribeEngineRuntimeStatus2, getEngineRuntimeStatus: getEngineRuntimeStatus2 } = await Promise.resolve().then(() => (init_engineRuntimeStatus(), engineRuntimeStatus_exports));
670459
+ const { reportBgEngineDown: reportBgEngineDown2 } = await Promise.resolve().then(() => (init_taskSummary(), taskSummary_exports));
670460
+ subscribeEngineRuntimeStatus2(() => {
670461
+ const st2 = getEngineRuntimeStatus2();
670462
+ if (st2.phase === "failed") {
670463
+ reportBgEngineDown2(st2.detail ?? "automatic engine restart failed");
670464
+ }
670465
+ });
670466
+ } catch {
670467
+ }
669774
670468
  process.argv = [process.argv[0], process.argv[1], ...config5.argv ?? []];
669775
670469
  const { launchReplProduction: launchReplProduction2 } = await Promise.resolve().then(() => (init_replEntry(), replEntry_exports));
669776
670470
  await launchReplProduction2();
@@ -669786,10 +670480,10 @@ __export(main_exports2, {
669786
670480
  daemonMain: () => daemonMain
669787
670481
  });
669788
670482
  import { spawn as spawn16 } from "child_process";
669789
- import { createWriteStream as createWriteStream5 } from "fs";
670483
+ import { appendFileSync as appendFileSync7, createWriteStream as createWriteStream5 } from "fs";
669790
670484
  import { chmod as chmod13, mkdir as mkdir50, readFile as readFile58, readdir as readdir33, rename as rename15, stat as stat54, unlink as unlink28 } from "fs/promises";
669791
- import { createConnection as createConnection4, createServer as createServer8 } from "net";
669792
- import { join as join201 } from "path";
670485
+ import { createConnection as createConnection4, createServer as createServer9 } from "net";
670486
+ import { dirname as dirname88, join as join201 } from "path";
669793
670487
  function probeSocketAlive(sockPath, timeoutMs = 1500) {
669794
670488
  return (async () => {
669795
670489
  const info = await readDaemonInfo();
@@ -669828,12 +670522,53 @@ function parseOrigin(args) {
669828
670522
  const v2 = i >= 0 ? args[i + 1] : void 0;
669829
670523
  return v2 === "service" ? "service" : "transient";
669830
670524
  }
670525
+ function appendDaemonCrashLine(kind, err8) {
670526
+ const detail = err8 instanceof Error ? err8.stack ?? err8.message : String(err8);
670527
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} [daemon] FATAL ${kind} (pid ${process.pid}): ${detail}
670528
+ `;
670529
+ try {
670530
+ appendFileSync7(getDaemonLogPath(), line, { mode: 384 });
670531
+ } catch {
670532
+ try {
670533
+ process.stderr.write(line);
670534
+ } catch {
670535
+ }
670536
+ }
670537
+ }
670538
+ function installDaemonCrashHandlers() {
670539
+ if (crashHandlersInstalled) return;
670540
+ crashHandlersInstalled = true;
670541
+ process.on("uncaughtException", (err8) => {
670542
+ appendDaemonCrashLine("uncaughtException", err8);
670543
+ process.exit(1);
670544
+ });
670545
+ process.on("unhandledRejection", (reason) => {
670546
+ appendDaemonCrashLine("unhandledRejection", reason);
670547
+ process.exit(1);
670548
+ });
670549
+ }
669831
670550
  async function daemonMain(args) {
670551
+ const cdIdx = args.indexOf("--config-dir");
670552
+ if (cdIdx >= 0 && args[cdIdx + 1]) {
670553
+ process.env.SEMA_CONFIG_DIR = args[cdIdx + 1];
670554
+ }
669832
670555
  const sub = args[0];
669833
670556
  switch (sub) {
669834
670557
  case "run": {
670558
+ installDaemonCrashHandlers();
669835
670559
  const supervisor = new Supervisor(parseOrigin(args.slice(1)));
669836
- const started = await supervisor.run();
670560
+ let started = false;
670561
+ try {
670562
+ started = await supervisor.run();
670563
+ } catch (e) {
670564
+ appendDaemonCrashLine("boot", e);
670565
+ process.stderr.write(
670566
+ `daemon failed to start \u2014 ${e instanceof Error ? e.message : String(e)} (details: ${getDaemonLogPath()})
670567
+ `
670568
+ );
670569
+ process.exitCode = 1;
670570
+ return;
670571
+ }
669837
670572
  if (!started) return;
669838
670573
  return;
669839
670574
  }
@@ -669893,6 +670628,8 @@ async function daemonMain(args) {
669893
670628
  const isHelp = sub === void 0 || sub === "--help" || sub === "-h";
669894
670629
  const usage = `Usage: sema daemon <run|status|stop>
669895
670630
  run [--origin transient|service] start the background supervisor
670631
+ [--config-dir <path>] explicit config home (win32 WMI spawn leg \u2014
670632
+ the WMI child doesn't inherit the caller's env)
669896
670633
  status show supervisor + workers
669897
670634
  stop stop the supervisor (workers keep running)
669898
670635
  `;
@@ -669901,7 +670638,7 @@ async function daemonMain(args) {
669901
670638
  }
669902
670639
  }
669903
670640
  }
669904
- var IDLE_EXIT_MS, DISPATCH_SCAN_MS, DAEMON_LOG_ROTATE_BYTES, ADOPTED_SWEEP_MS, CRASH_RESPAWN_MAX, CRASH_BACKOFF_BASE_MS, CRASH_BACKOFF_CAP_MS, CRASH_STABLE_UPTIME_MS, CRASH_WINDOW_MS, CRASH_WINDOW_MAX, Supervisor;
670641
+ var IDLE_EXIT_MS, DISPATCH_SCAN_MS, DAEMON_LOG_ROTATE_BYTES, ADOPTED_SWEEP_MS, CRASH_RESPAWN_MAX, CRASH_BACKOFF_BASE_MS, CRASH_BACKOFF_CAP_MS, CRASH_STABLE_UPTIME_MS, CRASH_WINDOW_MS, CRASH_WINDOW_MAX, Supervisor, crashHandlersInstalled;
669905
670642
  var init_main4 = __esm({
669906
670643
  "build-src/src/daemon/main.ts"() {
669907
670644
  init_envUtils();
@@ -669976,8 +670713,11 @@ var init_main4 = __esm({
669976
670713
  }
669977
670714
  this.log = createWriteStream5(logPath, { flags: "a", mode: 384 });
669978
670715
  const sockPath = getDaemonSocketPath();
670716
+ if (process.platform !== "win32") {
670717
+ await mkdir50(dirname88(sockPath), { recursive: true, mode: 448 });
670718
+ }
669979
670719
  const listen = () => new Promise((resolve53, reject2) => {
669980
- const s = createServer8((conn) => this.handleConnection(conn));
670720
+ const s = createServer9((conn) => this.handleConnection(conn));
669981
670721
  s.once("error", reject2);
669982
670722
  s.listen(sockPath, () => {
669983
670723
  this.server = s;
@@ -670009,17 +670749,25 @@ var init_main4 = __esm({
670009
670749
  }
670010
670750
  await chmod13(sockPath, 384).catch(() => {
670011
670751
  });
670012
- await writeDaemonInfo({
670013
- pid: process.pid,
670014
- procStart: this.procStart,
670015
- writtenAt: Date.now(),
670016
- socketPath: sockPath,
670017
- authToken: this.authToken,
670018
- origin: this.origin
670019
- });
670020
- this.logLine(`[daemon] supervisor up pid=${process.pid} origin=${this.origin}`);
670021
- await this.recoverJobs();
670022
- await mkdir50(join201(getDispatchDir(), "rejected"), { recursive: true, mode: 448 });
670752
+ try {
670753
+ await writeDaemonInfo({
670754
+ pid: process.pid,
670755
+ procStart: this.procStart,
670756
+ writtenAt: Date.now(),
670757
+ socketPath: sockPath,
670758
+ authToken: this.authToken,
670759
+ origin: this.origin
670760
+ });
670761
+ this.logLine(`[daemon] supervisor up pid=${process.pid} origin=${this.origin}`);
670762
+ await this.recoverJobs();
670763
+ await mkdir50(join201(getDispatchDir(), "rejected"), { recursive: true, mode: 448 });
670764
+ } catch (e) {
670765
+ this.server?.close();
670766
+ this.server = null;
670767
+ await unlink28(sockPath).catch(() => {
670768
+ });
670769
+ throw e;
670770
+ }
670023
670771
  const scanTimer = setInterval(() => void this.scanDispatchDir(), DISPATCH_SCAN_MS);
670024
670772
  const idleTimer2 = setInterval(() => this.maybeIdleExit(), 3e4);
670025
670773
  const nonceTimer = setInterval(() => this.seenNonces.clear(), 6e4);
@@ -670674,6 +671422,7 @@ var init_main4 = __esm({
670674
671422
  }
670675
671423
  }
670676
671424
  };
671425
+ crashHandlersInstalled = false;
670677
671426
  }
670678
671427
  });
670679
671428
 
@@ -670704,10 +671453,16 @@ function cleanName(s) {
670704
671453
  return t2 || void 0;
670705
671454
  }
670706
671455
  async function loadJobs(cwdFilter) {
671456
+ const daemonInfo = await readDaemonInfo();
671457
+ const daemonUp = daemonInfo !== null && isDaemonAlive(daemonInfo);
670707
671458
  const out6 = [];
670708
671459
  for (const short of await listJobShorts()) {
670709
- const state3 = await readJobState(short);
671460
+ let state3 = await readJobState(short);
670710
671461
  if (!state3) continue;
671462
+ if (!isTerminalJobState(state3.state) && Number.isFinite(state3.pid) && !isJobWorkerAlive(state3) && !(state3.state === "crashed" && daemonUp)) {
671463
+ const reaped = await markJobTerminal(short, "failed", "interrupted", { reaped: true });
671464
+ if (reaped) state3 = reaped;
671465
+ }
670711
671466
  if (!underCwd(cwdFilter, state3.cwd)) continue;
670712
671467
  out6.push({ short, state: state3 });
670713
671468
  }
@@ -670799,7 +671554,7 @@ __export(agentsView_exports, {
670799
671554
  agentsHandler: () => agentsHandler2
670800
671555
  });
670801
671556
  import { rm as rmrf2 } from "fs/promises";
670802
- import { spawnSync as spawnSync11 } from "child_process";
671557
+ import { spawnSync as spawnSync12 } from "child_process";
670803
671558
  async function stopJobFromView(short) {
670804
671559
  const { stopDaemonWorker: stopDaemonWorker2 } = await Promise.resolve().then(() => (init_respawn(), respawn_exports));
670805
671560
  const { confirmed, error: error52 } = await stopDaemonWorker2(short);
@@ -670822,14 +671577,14 @@ async function deleteJobFromView(short) {
670822
671577
  let keptWorktree;
670823
671578
  let keptReason;
670824
671579
  if (st2?.worktreePath) {
670825
- const dirty2 = spawnSync11("git", ["-C", st2.worktreePath, "status", "--porcelain"], {
671580
+ const dirty2 = spawnSync12("git", ["-C", st2.worktreePath, "status", "--porcelain"], {
670826
671581
  encoding: "utf8"
670827
671582
  });
670828
671583
  if (dirty2.status === 0 && (dirty2.stdout ?? "").trim().length > 0) {
670829
671584
  keptWorktree = st2.worktreePath;
670830
671585
  keptReason = "dirty";
670831
671586
  } else if (dirty2.status === 0) {
670832
- const removed = spawnSync11(
671587
+ const removed = spawnSync12(
670833
671588
  "git",
670834
671589
  ["-C", st2.cwd, "worktree", "remove", "--force", st2.worktreePath],
670835
671590
  { stdio: "ignore" }
@@ -671561,6 +672316,11 @@ function toWireSettings(eff, cfg) {
671561
672316
  async function launchReplProduction() {
671562
672317
  const { installSemaProcessBackstop: installSemaProcessBackstop2 } = await Promise.resolve().then(() => (init_processBackstop(), processBackstop_exports));
671563
672318
  installSemaProcessBackstop2();
672319
+ try {
672320
+ const { installEngineExitTeardown: installEngineExitTeardown2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
672321
+ installEngineExitTeardown2(() => null);
672322
+ } catch {
672323
+ }
671564
672324
  const { applyFullscreenDefault: applyFullscreenDefault2 } = await Promise.resolve().then(() => (init_fullscreenDefault(), fullscreenDefault_exports));
671565
672325
  const fullscreenAction = applyFullscreenDefault2();
671566
672326
  if (process.env.SEMA_DEBUG) {
@@ -671732,9 +672492,10 @@ async function launchReplProduction() {
671732
672492
  }
671733
672493
  if (!process.env.SEMA_LIVE_BASEURL && process.env.SEMA_TOC_ENGINE !== "0") {
671734
672494
  try {
671735
- const { initEngineLifecycle: initEngineLifecycle2, startHealthCheckLoop: startHealthCheckLoop2, getServiceAuthToken: getServiceAuthToken2, respawnOnConfigDrift: respawnOnConfigDrift2, runEngineDeadRespawn: runEngineDeadRespawn2, setOnOwnedEngineExit: setOnOwnedEngineExit2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
672495
+ const { initEngineLifecycle: initEngineLifecycle2, startHealthCheckLoop: startHealthCheckLoop2, getServiceAuthToken: getServiceAuthToken2, respawnOnConfigDrift: respawnOnConfigDrift2, runEngineDeadRespawn: runEngineDeadRespawn2, setOnOwnedEngineExit: setOnOwnedEngineExit2, installEngineExitTeardown: installEngineExitTeardown2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
671736
672496
  let engineHealthLoop = null;
671737
672497
  let currentEngineInstance = null;
672498
+ installEngineExitTeardown2(() => currentEngineInstance);
671738
672499
  const doEngineRespawn = async (label) => {
671739
672500
  console.error(`[sema] local engine ${label} \u2014 restarting (stop-then-start serialize), session preserved`);
671740
672501
  try {
@@ -671824,7 +672585,27 @@ async function launchReplProduction() {
671824
672585
  })();
671825
672586
  });
671826
672587
  };
671827
- const r = await initEngineLifecycle2();
672588
+ let r = await initEngineLifecycle2();
672589
+ if (!r.baseUrl && process.env.SEMA_CODE_SESSION_KIND === "bg" && process.env.SEMA_JOB_DIR) {
672590
+ const bgInitBackoffMs = [2e3, 5e3, 1e4, 2e4, 4e4];
672591
+ for (let i = 0; i < bgInitBackoffMs.length && !r.baseUrl; i++) {
672592
+ console.error(
672593
+ `[sema] bg worker: engine unavailable (${r.reason ?? "unknown"}) \u2014 retrying start ${i + 1}/${bgInitBackoffMs.length} in ${bgInitBackoffMs[i] / 1e3}s`
672594
+ );
672595
+ await new Promise((res) => setTimeout(res, bgInitBackoffMs[i]));
672596
+ r = await initEngineLifecycle2();
672597
+ }
672598
+ if (!r.baseUrl) {
672599
+ try {
672600
+ const { describeEngineInitFailure: describeEngineInitFailure2, getLastEngineInitFailure: getLastEngineInitFailure2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
672601
+ const { reportBgEngineDown: reportBgEngineDown2 } = await Promise.resolve().then(() => (init_taskSummary(), taskSummary_exports));
672602
+ reportBgEngineDown2(
672603
+ `engine unavailable \u2014 ${describeEngineInitFailure2(getLastEngineInitFailure2())}`
672604
+ );
672605
+ } catch {
672606
+ }
672607
+ }
672608
+ }
671828
672609
  if (r.baseUrl) {
671829
672610
  process.env.SEMA_LIVE_BASEURL = r.baseUrl;
671830
672611
  const tok = getServiceAuthToken2();