@sema-agent/cli 1.0.87 → 1.0.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/sema-main.js CHANGED
@@ -55614,6 +55614,12 @@ function isLimitsExceededCode(code2) {
55614
55614
  function isDelegationCapCode(code2) {
55615
55615
  return typeof code2 == "string" && code2.startsWith("delegation.");
55616
55616
  }
55617
+ function delegationCapDispositionOf(code2) {
55618
+ if (code2 === DELEGATION_CONCURRENCY_CAP)
55619
+ return "wait-for-slot";
55620
+ if (code2 === DELEGATION_SESSION_CAP)
55621
+ return "reuse-existing-or-await-reap";
55622
+ }
55617
55623
  function isConfigRefusalCode(code2) {
55618
55624
  return typeof code2 == "string" && code2.startsWith("config.");
55619
55625
  }
@@ -55626,7 +55632,7 @@ function isRewindFamilyCode(code2) {
55626
55632
  function asModelFallbackReason(v2) {
55627
55633
  return v2 === MODEL_FALLBACK_INHERIT_NO_TIER_BINDING ? MODEL_FALLBACK_INHERIT_NO_TIER_BINDING : void 0;
55628
55634
  }
55629
- var LIMITS_MAX_TOKENS_EXCEEDED, LIMITS_MAX_COST_EXCEEDED, LIMITS_MAX_TURNS_EXCEEDED, LIMITS_MAX_WALLTIME_EXCEEDED, LIMITS_ERROR_CODE_PREFIX, USAGE_WINDOW_EXHAUSTED, ENV_LIFETIME_EXPIRED, CONFIG_LIMIT_INVALID, CONFIG_STRATEGY_FIND_LIMIT_INVALID, CONFIG_STRATEGY_MAX_SIZE_INVALID, CONFIG_LIMIT_UNKNOWN_KEY, CONFIG_DELEGATION_ENTRY_CAPS, CONFIG_REFUSAL_CODES, DELEGATION_CONCURRENCY_CAP, DELEGATION_SESSION_CAP, DELEGATION_CAP_CODES, TOOL_END_INTERRUPTED_NEVER_STARTED, TOOL_END_INTERRUPTED_OUTCOME_UNKNOWN, TOOL_END_INTERRUPTED_CODES, ACTIVE_RUN_BUSY_ERROR_CODE, STOP_PARK_ARBITER_UNREACHABLE, STOP_PARK_RESUME_WON, STOP_NOT_LANDED, STOP_NOT_LOCAL, STOP_PARKED, STOP_CONFLICT_CODES, OUTPUT_INVALID, RESUME_AT_ERROR_CODE_PREFIX, REWIND_ERROR_CODE_PREFIXES, DRAINING_ERROR_CODE, SCENARIO_NOT_ALLOWED_ERROR_CODE, STREAM_MAX_DURATION, MODEL_FALLBACK_INHERIT_NO_TIER_BINDING, init_engineErrorCodes = __esm({
55635
+ var LIMITS_MAX_TOKENS_EXCEEDED, LIMITS_MAX_COST_EXCEEDED, LIMITS_MAX_TURNS_EXCEEDED, LIMITS_MAX_WALLTIME_EXCEEDED, LIMITS_ERROR_CODE_PREFIX, USAGE_WINDOW_EXHAUSTED, ENV_LIFETIME_EXPIRED, CONFIG_LIMIT_INVALID, CONFIG_STRATEGY_FIND_LIMIT_INVALID, CONFIG_STRATEGY_MAX_SIZE_INVALID, CONFIG_LIMIT_UNKNOWN_KEY, CONFIG_DELEGATION_ENTRY_CAPS, CONFIG_REFUSAL_CODES, DELEGATION_CONCURRENCY_CAP, DELEGATION_SESSION_CAP, DELEGATION_CAP_CODES, MCP_SERVER_REVOKED, TOOL_END_INTERRUPTED_NEVER_STARTED, TOOL_END_INTERRUPTED_OUTCOME_UNKNOWN, TOOL_END_INTERRUPTED_CODES, ACTIVE_RUN_BUSY_ERROR_CODE, STOP_PARK_ARBITER_UNREACHABLE, STOP_PARK_RESUME_WON, STOP_NOT_LANDED, STOP_NOT_LOCAL, STOP_PARKED, STOP_CONFLICT_CODES, OUTPUT_INVALID, RESUME_AT_ERROR_CODE_PREFIX, REWIND_ERROR_CODE_PREFIXES, DRAINING_ERROR_CODE, SCENARIO_NOT_ALLOWED_ERROR_CODE, STREAM_MAX_DURATION, MODEL_FALLBACK_INHERIT_NO_TIER_BINDING, init_engineErrorCodes = __esm({
55630
55636
  "node_modules/@sema-agent/client-core/dist/engineErrorCodes.js"() {
55631
55637
  LIMITS_MAX_TOKENS_EXCEEDED = "limits.max_tokens_exceeded", LIMITS_MAX_COST_EXCEEDED = "limits.max_cost_exceeded", LIMITS_MAX_TURNS_EXCEEDED = "limits.max_turns_exceeded", LIMITS_MAX_WALLTIME_EXCEEDED = "limits.max_walltime_exceeded", LIMITS_ERROR_CODE_PREFIX = "limits.";
55632
55638
  USAGE_WINDOW_EXHAUSTED = "usage.window_exhausted", ENV_LIFETIME_EXPIRED = "env.lifetime_expired", CONFIG_LIMIT_INVALID = "config.limit_invalid", CONFIG_STRATEGY_FIND_LIMIT_INVALID = "config.strategy_find_limit_invalid", CONFIG_STRATEGY_MAX_SIZE_INVALID = "config.strategy_max_size_invalid", CONFIG_LIMIT_UNKNOWN_KEY = "config.limit_unknown_key", CONFIG_DELEGATION_ENTRY_CAPS = "config.delegation_entry_caps", CONFIG_REFUSAL_CODES = /* @__PURE__ */ new Set([
@@ -55639,6 +55645,7 @@ var LIMITS_MAX_TOKENS_EXCEEDED, LIMITS_MAX_COST_EXCEEDED, LIMITS_MAX_TURNS_EXCEE
55639
55645
  DELEGATION_CONCURRENCY_CAP,
55640
55646
  DELEGATION_SESSION_CAP
55641
55647
  ]);
55648
+ MCP_SERVER_REVOKED = "mcp.server_revoked";
55642
55649
  TOOL_END_INTERRUPTED_NEVER_STARTED = "interrupted_never_started", TOOL_END_INTERRUPTED_OUTCOME_UNKNOWN = "interrupted_outcome_unknown", TOOL_END_INTERRUPTED_CODES = /* @__PURE__ */ new Set([
55643
55650
  TOOL_END_INTERRUPTED_NEVER_STARTED,
55644
55651
  TOOL_END_INTERRUPTED_OUTCOME_UNKNOWN
@@ -63077,8 +63084,8 @@ function ensureWorkflowActivityLedger(cfg) {
63077
63084
  let evicted = activityLedgers.get(victim);
63078
63085
  evicted && (evicted.closed = !0, evicted.closedReason = "stopped", evicted.abort.abort(), emitActivityTick(evicted)), activityLedgers.delete(victim);
63079
63086
  }
63080
- let ledger = newActivityLedger(cfg.workflowId, scope);
63081
- activityLedgers.set(cfg.workflowId, ledger), consumeWorkflowActivity(ledger, cfg);
63087
+ let ledger2 = newActivityLedger(cfg.workflowId, scope);
63088
+ activityLedgers.set(cfg.workflowId, ledger2), consumeWorkflowActivity(ledger2, cfg);
63082
63089
  }
63083
63090
  function stopWorkflowActivityLedger(workflowId) {
63084
63091
  let l3 = activityLedgers.get(workflowId);
@@ -63160,21 +63167,21 @@ function createLiveWorkflowSource(config4) {
63160
63167
  ...config4.fetchImpl ? { fetchImpl: config4.fetchImpl } : {}
63161
63168
  });
63162
63169
  }
63163
- let ledger = activityDisabled ? void 0 : activityLedgers.get(id);
63164
- if (ledger) {
63165
- ledger.consumers += 1;
63170
+ let ledger2 = activityDisabled ? void 0 : activityLedgers.get(id);
63171
+ if (ledger2) {
63172
+ ledger2.consumers += 1;
63166
63173
  try {
63167
63174
  for (; ; ) {
63168
- let beat = await waitActivityTick(ledger, abort.signal);
63175
+ let beat = await waitActivityTick(ledger2, abort.signal);
63169
63176
  if (beat === "abort" || disposed4)
63170
63177
  return;
63171
63178
  if (beat === "tick" && (connected = !0), Date.now() - lastGetAt >= REFRESH_THROTTLE_MS && await refresh(id, abort.signal), degraded || beat === "closed")
63172
63179
  break;
63173
63180
  }
63174
63181
  } finally {
63175
- ledger.consumers -= 1;
63182
+ ledger2.consumers -= 1;
63176
63183
  }
63177
- ledger.displaced && (activityDisabled = !0, engineWireDebugEnabled() && hostLog("debug", `[sema][workflow] activity ledger for ${id} was taken over by another engine target/principal \u2014 this source stops re-opening it (GET polling only)`));
63184
+ ledger2.displaced && (activityDisabled = !0, engineWireDebugEnabled() && hostLog("debug", `[sema][workflow] activity ledger for ${id} was taken over by another engine target/principal \u2014 this source stops re-opening it (GET polling only)`));
63178
63185
  }
63179
63186
  !disposed4 && !abort.signal.aborted && await abortableSleep(STREAM_DROP_BACKOFF_MS, abort.signal);
63180
63187
  } catch (err8) {
@@ -65444,6 +65451,9 @@ function pathFromGateMessage(message) {
65444
65451
  if (typeof message == "string")
65445
65452
  return FS_WRITE_GATE_ASK_PATTERN.exec(message)?.[1];
65446
65453
  }
65454
+ function isNonNegativeFinite(v2) {
65455
+ return typeof v2 == "number" && Number.isFinite(v2) && v2 >= 0;
65456
+ }
65447
65457
  function isWireRecordCarrier(v2) {
65448
65458
  return typeof v2 == "object" && v2 !== null && !Array.isArray(v2);
65449
65459
  }
@@ -65487,6 +65497,22 @@ async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, si
65487
65497
  ...isFromSubagent(frame) ? { workerBadge: subagentBadgeFor(frame) } : {},
65488
65498
  ...wireNote !== void 0 ? { wireNote } : {},
65489
65499
  ...frame.governanceForced === !0 ? { governanceForced: !0 } : {},
65500
+ // [4851]:窗三键透传,三闸合取(异源对抗复审 P1/P2 收编):
65501
+ // ① `lane.windowIsCurrent === true` —— durable 账本重放的历史帧带的是铸帧时刻的旧余量,
65502
+ // 给它续窗 = 过期 ask 渲出精确假倒计时(壳孪生族同名闸的本包席位,见 LaneOpts 注);
65503
+ // ② **非负有限数**才 stamp —— `Number.isFinite` 单独放行负数,而三键定义域按 SDK 契约
65504
+ // 本就非负(`expiresInMs = max(0, …)`;0 合法 = 窗恰好到点)。负数/NaN/Infinity =
65505
+ // 坏形降缺席,绝不折 0 或猜(同文件 delegation.depth 曾同款教训);
65506
+ // ③ 三键各自独立 stamp:server 承诺同门在场,但包边界不替上游把「半套在场」湮灭成全缺席
65507
+ // —— 读器自己按「expiresAtMs 优先、expiresInMs 兜底」消化半套。
65508
+ // 任一键 stamp 时同步盖 `receivedAtMs`(本地收帧锚):卡口串行阻塞下,排队靠后的卡若按
65509
+ // 「呈现那一刻」起算余量,窗被整段还回去 —— 壳读器明文优先这枚锚。
65510
+ ...lane?.windowIsCurrent === !0 ? {
65511
+ ...isNonNegativeFinite(frame.expiresInMs) ? { expiresInMs: frame.expiresInMs } : {},
65512
+ ...isNonNegativeFinite(frame.expiresAtMs) ? { expiresAtMs: frame.expiresAtMs } : {},
65513
+ ...isNonNegativeFinite(frame.serverNowMs) ? { serverNowMs: frame.serverNowMs } : {},
65514
+ ...isNonNegativeFinite(frame.expiresInMs) || isNonNegativeFinite(frame.expiresAtMs) ? { receivedAtMs: Date.now() } : {}
65515
+ } : {},
65490
65516
  // 🔴 跨字段不变量(对抗复审命中):`delegation` 只在**子代 ask** 的门上在场(SDK 头注:
65491
65517
  // "Present on the same door as fromSubagent (child asks only)")。只校对象形不校这一条 ⇒
65492
65518
  // 一个**宿主自己**的破坏性工具审批也能带着 delegation 到卡口,被呈成「某层子代发起的」——
@@ -65581,6 +65607,14 @@ var cardPortByKey, cardPortMissesByKey, TOOL_APPROVAL_FRAME_KEYS_MIRROR, RESPOND
65581
65607
  // sdk 7.1.0 的运行期锚**尚无**本键(node 直读实证:锚 17 项)⇒ 这是一次**领先**,进对账门的
65582
65608
  // AHEAD_OF_ANCHOR 带退出条件登记(SDK 追平当天那条登记自红逼删,回到逐元素相等)。
65583
65609
  "requiresRealApproval",
65610
+ // [4851] 头号请托(client-core 0.38.2):server 7.34.0 起真发窗三键(#288/[4429]② cli 自己请托,
65611
+ // server src/tool-approval.ts 三键声明+条件 stamp)。⚠️ 与 requiresRealApproval 同形=**领先** SDK
65612
+ // 运行期锚(sdk 7.2.0 锚 17 项,node 直读实证无三键)⇒ 进对账门 AHEAD_OF_ANCHOR 带退出条件登记
65613
+ // (SDK 追平当天登记自红逼删)。0.38.1 把三键丢在包边界外 = [4845]「卡到期屏幕零反应」的直接成因
65614
+ // (壳读器 readAskDeadlineMs 早已预埋,缺的一直是包边界这一格——#283 逐字同形第四例)。
65615
+ "expiresInMs",
65616
+ "expiresAtMs",
65617
+ "serverNowMs",
65584
65618
  "delegation",
65585
65619
  "outcome"
65586
65620
  ];
@@ -68747,6 +68781,7 @@ __export(dist_exports, {
68747
68781
  MAX_TURNS_MAX: () => MAX_TURNS_MAX,
68748
68782
  MAX_TURNS_MIN: () => MAX_TURNS_MIN,
68749
68783
  MCP_CAPS: () => MCP_CAPS,
68784
+ MCP_SERVER_REVOKED: () => MCP_SERVER_REVOKED,
68750
68785
  MIGRATED_COMPENSATIONS: () => MIGRATED_COMPENSATIONS,
68751
68786
  MODEL_FALLBACK_INHERIT_NO_TIER_BINDING: () => MODEL_FALLBACK_INHERIT_NO_TIER_BINDING,
68752
68787
  MODEL_FAMILIES: () => MODEL_FAMILIES,
@@ -68968,6 +69003,7 @@ __export(dist_exports, {
68968
69003
  deferToolsForRequest: () => deferToolsForRequest,
68969
69004
  degradedToolResultBody: () => degradedToolResultBody,
68970
69005
  delegatedPromptText: () => delegatedPromptText,
69006
+ delegationCapDispositionOf: () => delegationCapDispositionOf,
68971
69007
  denyReasonForWire: () => denyReasonForWire,
68972
69008
  deriveAgentLabel: () => deriveAgentLabel,
68973
69009
  deriveNotificationResidualLines: () => deriveNotificationResidualLines,
@@ -78844,7 +78880,7 @@ function extraBodyUnsafe(v2) {
78844
78880
  function workerRouteKey(w2) {
78845
78881
  return w2.routePrefix ?? w2.name;
78846
78882
  }
78847
- var SECRET_LITERAL_RE, ENV_NAME, hasNul, NON_SECRET_URL, K8S_QUANTITY, TCP_PORT, ModelCost, SEALED_BOX_ALG, BASE64_SHAPE, SealedApiKey, ModelEntry, ModelRole, RoleTarget, TierBindings, TierGroup, ModelsConfig, RosterEntry, RostersConfig, ScenarioEntry, ScenarioConfig, DELIVER_DENYLIST, SystemEntry, SystemsConfig, SystemStatusEntry, RuntimeConfig, GovernanceConfig, EntitlementBudget, TokenQuota, BudgetGroupMember, BudgetGroup, ScenarioAssignments, EntitlementRuntimeCaps, EntitlementTier, EntitlementOverride, EntitlementSubject, EntitlementGroupBinding, EntitlementConfig, PrincipalOrgMemoryWire, PrincipalCapsWire, ActorAssertionWire, SESSION_MIRROR_ENGINE_URL, SessionMirrorPolicy, ExecutionPublicKey, ExecutionPolicy, PROJECT_ID_REGEX, ProjectRegistration, ProjectsConfig, CollabTopology, CollabFinalizerType, CollabEarlyStop, CollabPersistence, CollabMember, CollabSlot, CollabTemplate, CollabConfig, DURATION, WorkerLifecycle, WorkerSecretRefs, RESERVED_WORKER_ENV, RESERVED_ENV_FIELD, WorkerSpec, WorkersConfig, WorkerCondition, WorkerStatus, HOST_NAME_MAX, HOSTS_ARRAY_MAX, HostEntry, HostsConfig, PROBE_CPU_CORES_MAX, PROBE_MEM_BYTES_MAX, HostProbes, HostStatus, SkillSpec, SkillsConfig, SkillsManifestSchema, McpEnvRefs, HTTP_HEADER_NAME, McpHeaderRefs, McpTransport, McpServerSpec, McpConfig, PLUGIN_ORIGIN, GIT_COMMIT_SHA, PluginSource, PluginSpec, PluginsConfig, PromptTextDeclaration, PromptBinding, PROMPT_ARTIFACT_LIMITS, PromptArtifactSection, PromptCatalogSnapshot, PromptEpochArtifactPayload, PublishedPromptArtifactEnvelope, PromptsConfig, EffectivePrompts, EffectivePromptsWire, DOMAIN_SCHEMAS, SettingSource, EffectiveKey, DOMAINS, init_types6 = __esm({
78883
+ var SECRET_LITERAL_RE, ENV_NAME, hasNul, NON_SECRET_URL, K8S_QUANTITY, TCP_PORT, ModelCost, SEALED_BOX_ALG, BASE64_SHAPE, SealedApiKey, ModelEntry, ModelRole, RoleTarget, TierBindings, TierGroup, ModelsConfig, RosterEntry, RostersConfig, ScenarioEntry, ScenarioConfig, DELIVER_DENYLIST, SystemEntry, SystemsConfig, SystemStatusEntry, RuntimeConfig, InfraCostRates, LimitsConfig, GovernanceConfig, EntitlementBudget, TokenQuota, BudgetGroupMember, BudgetGroup, ScenarioAssignments, EntitlementRuntimeCaps, EntitlementTier, EntitlementOverride, EntitlementSubject, EntitlementGroupBinding, EntitlementConfig, PrincipalOrgMemoryWire, PrincipalCapsWire, ActorAssertionWire, SESSION_MIRROR_ENGINE_URL, SessionMirrorPolicy, ExecutionPublicKey, ExecutionPolicy, PROJECT_ID_REGEX, ProjectRegistration, ProjectsConfig, CollabTopology, CollabFinalizerType, CollabEarlyStop, CollabPersistence, CollabMember, CollabSlot, CollabTemplate, CollabConfig, DURATION, WorkerLifecycle, WorkerSecretRefs, RESERVED_WORKER_ENV, RESERVED_ENV_FIELD, WorkerSpec, WorkersConfig, WorkerCondition, WorkerStatus, HOST_NAME_MAX, HOSTS_ARRAY_MAX, HostEntry, HostsConfig, PROBE_CPU_CORES_MAX, PROBE_MEM_BYTES_MAX, HostProbes, HostStatus, SkillSpec, SkillsConfig, SkillsManifestSchema, McpEnvRefs, HTTP_HEADER_NAME, McpHeaderRefs, McpTransport, McpServerSpec, McpConfig, PLUGIN_ORIGIN, GIT_COMMIT_SHA, PluginSource, PluginSpec, PluginsConfig, PromptTextDeclaration, PromptBinding, PROMPT_ARTIFACT_LIMITS, PromptArtifactSection, PromptCatalogSnapshot, PromptEpochArtifactPayload, PublishedPromptArtifactEnvelope, PromptsConfig, EffectivePrompts, EffectivePromptsWire, DOMAIN_SCHEMAS, SettingSource, EffectiveKey, DOMAINS, init_types6 = __esm({
78848
78884
  "node_modules/@sema-agent/registry-core/dist/types.js"() {
78849
78885
  init_zod();
78850
78886
  init_hash2();
@@ -79114,7 +79150,43 @@ var SECRET_LITERAL_RE, ENV_NAME, hasNul, NON_SECRET_URL, K8S_QUANTITY, TCP_PORT,
79114
79150
  maxTaskTokens: external_exports2.number().int().nonnegative().optional(),
79115
79151
  maxPrincipalCostUsd: external_exports2.number().finite().nonnegative().optional(),
79116
79152
  costQuotaWindowSec: external_exports2.number().int().positive().optional()
79117
- }), GovernanceConfig = external_exports2.object({
79153
+ }), InfraCostRates = external_exports2.object({
79154
+ toolCallMicroUsd: external_exports2.number().finite().optional(),
79155
+ sandboxSecMicroUsd: external_exports2.number().finite().optional(),
79156
+ egressGbMicroUsd: external_exports2.number().finite().optional()
79157
+ }).passthrough(), LimitsConfig = external_exports2.object({
79158
+ // `.optional()` 无默认,与 RuntimeConfig 同纪律:ABSENT = 「center 不管这一键」⇒ 消费方回自己的 env 底;
79159
+ // 显式值(**包括 0**)= 发布了一个真值(0 多半是「关断哨兵」,语义归消费方)。给默认值 = 静默覆盖部署。
79160
+ /** 每 principal 每分钟请求上限。 */
79161
+ rateLimitPerMin: external_exports2.number().finite().optional(),
79162
+ /** 每 principal 滚动窗累计花费上限(USD)。 */
79163
+ maxPrincipalCostUsd: external_exports2.number().finite().optional(),
79164
+ /** 上面那条配额的窗长(秒)。 */
79165
+ costQuotaWindowSec: external_exports2.number().finite().optional(),
79166
+ /** 单任务成本天花板(USD)。 */
79167
+ maxTaskCostUsd: external_exports2.number().finite().optional(),
79168
+ /** 单任务 token 天花板。 */
79169
+ maxTaskTokens: external_exports2.number().finite().optional(),
79170
+ /** 基建计价(micro-USD/单位)。见 {@link InfraCostRates}。 */
79171
+ infraCostRates: InfraCostRates.optional(),
79172
+ /** 附件孤儿对象 GC 宽限(ms)。 */
79173
+ attachmentOrphanGraceMs: external_exports2.number().finite().optional(),
79174
+ /** workspace 单文件读上限(字节)。 */
79175
+ workspaceFileMaxBytes: external_exports2.number().finite().optional(),
79176
+ /** 附件单文件上限(字节)。 */
79177
+ attachmentMaxBytes: external_exports2.number().finite().optional(),
79178
+ /** 附件 mime 白名单。**空数组 = 显式「一个都不许」**,与缺席(本键不管)不是一回事——元素只判
79179
+ * 「是字符串」,空串/大小写/别名归消费方(它会响亮拒,见域头注的判据分工)。 */
79180
+ attachmentMimeAllowlist: external_exports2.array(external_exports2.string()).optional(),
79181
+ /** 未绑定附件 TTL(ms)。 */
79182
+ attachmentUnboundTtlMs: external_exports2.number().finite().optional(),
79183
+ /** SIGTERM drain 窗(ms)。 */
79184
+ drainGraceMs: external_exports2.number().finite().optional(),
79185
+ /** run 心跳陈旧窗(秒)。 */
79186
+ runStaleSec: external_exports2.number().finite().optional(),
79187
+ /** 卸载工具结果的 TTL(秒)。 */
79188
+ toolResultTtlSec: external_exports2.number().finite().optional()
79189
+ }).passthrough(), GovernanceConfig = external_exports2.object({
79118
79190
  // autonomy:一个跨 knob 的安全总开关 / 放权梯度(普通用户敢用 + 专业用户放权)。
79119
79191
  // read-only(只读规划,不落改)| ask(每个放权动作问)| plan(plan-review 门)| auto(放开)。
79120
79192
  // ⚠️ 消费侧(service)把它**展开**到 core 已有三原语(handsReadOnly / shellGate+onAsk / plan_review),
@@ -79959,8 +80031,10 @@ var SECRET_LITERAL_RE, ENV_NAME, hasNul, NON_SECRET_URL, K8S_QUANTITY, TCP_PORT,
79959
80031
  // 0.8.0: S3 execution-lane policy (scope 级; client-advisory until service gate)
79960
80032
  projects: ProjectsConfig,
79961
80033
  // 0.10.0: 142-S3 project identity ledger + 无仓铸造权威 (scope=tenant 轴; NOT portable — 租户身份数据)
79962
- prompts: PromptsConfig
80034
+ prompts: PromptsConfig,
79963
80035
  // 0.10.18: center prompts 战役 v1(board [1050]/[1051]/[1057];写门/store 携带解锁=[1064]②)
80036
+ limits: LimitsConfig
80037
+ // 0.19.0: cost/限流族热更新发布位(sema-server #322 批1;本地腿闭集缺口的源头修复)
79964
80038
  // integrations + access: DELETED in 0.6.0 (EXPERT-REDESIGN §9) — parseDomain/effective/路由随之 404。
79965
80039
  }, SettingSource = external_exports2.discriminatedUnion("axis", [
79966
80040
  external_exports2.object({ axis: external_exports2.literal("layer"), layer: external_exports2.enum(["MANAGED", "PROJECT", "LOCAL"]), applied: external_exports2.boolean().optional(), reason: external_exports2.string().optional() }),
@@ -80095,10 +80169,13 @@ function parseDomain(domain2, raw2) {
80095
80169
  return r.data;
80096
80170
  throw sanitizeZodError(r.error);
80097
80171
  }
80098
- var USER_ROLES, init_config_fns = __esm({
80172
+ var USER_ROLES, OPEN_WORLD_KNOWN_KEYS, init_config_fns = __esm({
80099
80173
  "node_modules/@sema-agent/registry-core/dist/config-fns.js"() {
80100
80174
  init_types6();
80101
80175
  USER_ROLES = ["viewer", "editor", "publisher", "admin"];
80176
+ OPEN_WORLD_KNOWN_KEYS = {
80177
+ limits: { "": Object.keys(LimitsConfig.shape), infraCostRates: Object.keys(InfraCostRates.shape) }
80178
+ };
80102
80179
  }
80103
80180
  });
80104
80181
 
@@ -116685,6 +116762,24 @@ var init_types8 = __esm({
116685
116762
  }
116686
116763
  });
116687
116764
 
116765
+ // build-src/src/sema/untrustedDisplayText.ts
116766
+ function cleanUntrustedForDisplay(v2, max2) {
116767
+ return String(v2 ?? "").replace(CONTROL_CHARS, ".").replace(BIDI_AND_SEPARATORS, ".").replace(LONE_SURROGATE, ".").slice(0, max2).replace(LONE_SURROGATE, ".");
116768
+ }
116769
+ function cleanUntrustedKeepLayout(v2) {
116770
+ return String(v2 ?? "").replace(CONTROL_CHARS_KEEP_LAYOUT, ".").replace(BIDI_AND_SEPARATORS, ".").replace(LONE_SURROGATE, ".");
116771
+ }
116772
+ function cleanUntrustedScalar(v2) {
116773
+ return String(v2 ?? "").replace(SCALAR_UNSAFE, (ch2) => "\\u" + (ch2.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0"));
116774
+ }
116775
+ var CONTROL_CHARS, BIDI_AND_SEPARATORS, LONE_SURROGATE, CONTROL_CHARS_KEEP_LAYOUT, SCALAR_UNSAFE, init_untrustedDisplayText = __esm({
116776
+ "build-src/src/sema/untrustedDisplayText.ts"() {
116777
+ CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f]/g, BIDI_AND_SEPARATORS = /[\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g, LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
116778
+ CONTROL_CHARS_KEEP_LAYOUT = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
116779
+ SCALAR_UNSAFE = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
116780
+ }
116781
+ });
116782
+
116688
116783
  // build-src/src/sema/sessionIdMapping.ts
116689
116784
  var sessionIdMapping_exports = {};
116690
116785
  __export(sessionIdMapping_exports, {
@@ -117102,10 +117197,7 @@ function hostSink(e, billTurnCosts = !0) {
117102
117197
  return;
117103
117198
  }
117104
117199
  if (e.kind === "human_input") {
117105
- let clean8 = (v2) => (
117106
- // eslint-disable-next-line no-control-regex
117107
- String(v2 ?? "").replace(/[\x00-\x1f\x7f]/g, ".").slice(0, 120)
117108
- ), who = e.actor?.id ? `${clean8(e.actor.id)}${e.actor.hostAsserted === !0 ? "" : " (unverified)"}` : "unattributed";
117200
+ let clean8 = (v2) => cleanUntrustedForDisplay(v2, 120), who = e.actor?.id ? `${clean8(e.actor.id)}${e.actor.hostAsserted === !0 ? "" : " (unverified)"}` : "unattributed";
117109
117201
  Promise.resolve().then(() => (init_debug(), debug_exports)).then(
117110
117202
  (m2) => m2.logForDebugging(
117111
117203
  `[sema][wire] human_input ledger: carrier=${clean8(e.carrier)} source=${clean8(e.source)} delivery=${clean8(e.delivery)} actor=${who}${e.eventId ? ` eventId=${clean8(e.eventId)}` : ""}`
@@ -117153,6 +117245,7 @@ function runStream2(events3, ctx, handle2 = {}, o = {}) {
117153
117245
  var reportedDroppedTypes2, DROPPED_TYPE_MEMO_CAP2, init_runStream2 = __esm({
117154
117246
  "build-src/src/seam/adapter/runStream.ts"() {
117155
117247
  init_dist();
117248
+ init_untrustedDisplayText();
117156
117249
  init_activeRunSelfHeal2();
117157
117250
  init_dist();
117158
117251
  reportedDroppedTypes2 = /* @__PURE__ */ new Set(), DROPPED_TYPE_MEMO_CAP2 = 64;
@@ -254620,24 +254713,6 @@ var MCP_TOKEN_COUNT_THRESHOLD_FACTOR, IMAGE_TOKEN_ESTIMATE, DEFAULT_MAX_MCP_OUTP
254620
254713
  }
254621
254714
  });
254622
254715
 
254623
- // build-src/src/sema/untrustedDisplayText.ts
254624
- function cleanUntrustedForDisplay(v2, max2) {
254625
- return String(v2 ?? "").replace(CONTROL_CHARS, ".").replace(BIDI_AND_SEPARATORS, ".").replace(LONE_SURROGATE, ".").slice(0, max2).replace(LONE_SURROGATE, ".");
254626
- }
254627
- function cleanUntrustedKeepLayout(v2) {
254628
- return String(v2 ?? "").replace(CONTROL_CHARS_KEEP_LAYOUT, ".").replace(BIDI_AND_SEPARATORS, ".").replace(LONE_SURROGATE, ".");
254629
- }
254630
- function cleanUntrustedScalar(v2) {
254631
- return String(v2 ?? "").replace(SCALAR_UNSAFE, (ch2) => "\\u" + (ch2.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0"));
254632
- }
254633
- var CONTROL_CHARS, BIDI_AND_SEPARATORS, LONE_SURROGATE, CONTROL_CHARS_KEEP_LAYOUT, SCALAR_UNSAFE, init_untrustedDisplayText = __esm({
254634
- "build-src/src/sema/untrustedDisplayText.ts"() {
254635
- CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f]/g, BIDI_AND_SEPARATORS = /[\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g, LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
254636
- CONTROL_CHARS_KEEP_LAYOUT = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
254637
- SCALAR_UNSAFE = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
254638
- }
254639
- });
254640
-
254641
254716
  // build-src/src/tools/MCPTool/UI.tsx
254642
254717
  function renderToolUseMessage2(input, {
254643
254718
  verbose
@@ -280942,7 +281017,7 @@ function FileEditToolUseRejectedMessage(t0) {
280942
281017
  }
280943
281018
  var import_compiler_runtime43, import_jsx_runtime52, MAX_LINES_TO_RENDER, init_FileEditToolUseRejectedMessage = __esm({
280944
281019
  "build-src/src/components/FileEditToolUseRejectedMessage.tsx"() {
280945
- import_compiler_runtime43 = __toESM(require_compiler_runtime(), 1);
281020
+ import_compiler_runtime43 = __toESM(require_compiler_runtime());
280946
281021
  init_useTerminalSize();
280947
281022
  init_cwd();
280948
281023
  init_ink2();
@@ -280950,7 +281025,7 @@ var import_compiler_runtime43, import_jsx_runtime52, MAX_LINES_TO_RENDER, init_F
280950
281025
  init_MessageResponse();
280951
281026
  init_StructuredDiffList();
280952
281027
  init_stringUtils();
280953
- import_jsx_runtime52 = __toESM(require_jsx_runtime(), 1), MAX_LINES_TO_RENDER = 10;
281028
+ import_jsx_runtime52 = __toESM(require_jsx_runtime()), MAX_LINES_TO_RENDER = 10;
280954
281029
  }
280955
281030
  });
280956
281031
 
@@ -292672,21 +292747,21 @@ function createMissLedger() {
292672
292747
  }
292673
292748
  };
292674
292749
  }
292675
- function interpolate(template, key, params, ledger) {
292750
+ function interpolate(template, key, params, ledger2) {
292676
292751
  return template.includes("{") ? template.replace(PLACEHOLDER, (token, name) => {
292677
292752
  let v2 = params?.[name];
292678
- return v2 === void 0 ? (ledger.record(`${key}#${name}`), token) : String(v2);
292753
+ return v2 === void 0 ? (ledger2.record(`${key}#${name}`), token) : String(v2);
292679
292754
  }) : template;
292680
292755
  }
292681
- function translate(lang, key, params, ledger = uiMissLedger) {
292756
+ function translate(lang, key, params, ledger2 = uiMissLedger) {
292682
292757
  let hit = CATALOGS[lang][key];
292683
- if (hit !== void 0) return interpolate(hit, key, params, ledger);
292684
- ledger.record(key);
292758
+ if (hit !== void 0) return interpolate(hit, key, params, ledger2);
292759
+ ledger2.record(key);
292685
292760
  let fallback = CATALOGS.en[key];
292686
- return fallback === void 0 ? "" : interpolate(fallback, key, params, ledger);
292761
+ return fallback === void 0 ? "" : interpolate(fallback, key, params, ledger2);
292687
292762
  }
292688
- function createTranslator(lang, ledger = uiMissLedger) {
292689
- return (key, params) => translate(lang, key, params, ledger);
292763
+ function createTranslator(lang, ledger2 = uiMissLedger) {
292764
+ return (key, params) => translate(lang, key, params, ledger2);
292690
292765
  }
292691
292766
  var uiMissLedger, CATALOGS, PLACEHOLDER, init_translate = __esm({
292692
292767
  "build-src/src/sema/i18n/core/translate.ts"() {
@@ -356411,25 +356486,25 @@ function getSessionMcpConfigLedger(slot) {
356411
356486
  let created = createMcpConfigLedger();
356412
356487
  return sessionConfigLedgers.set(slot, created), created;
356413
356488
  }
356414
- function pinSessionMcpConfigs(fresh, ledger) {
356489
+ function pinSessionMcpConfigs(fresh, ledger2) {
356415
356490
  let configs = {}, changed = [], deferred = [];
356416
356491
  for (let [name, config4] of Object.entries(fresh)) {
356417
- let pinned = ledger.entries.get(name);
356492
+ let pinned = ledger2.entries.get(name);
356418
356493
  if (pinned === void 0) {
356419
- if (ledger.sealed) {
356494
+ if (ledger2.sealed) {
356420
356495
  deferred.push(name);
356421
356496
  continue;
356422
356497
  }
356423
- ledger.entries.set(name, config4), configs[name] = config4;
356498
+ ledger2.entries.set(name, config4), configs[name] = config4;
356424
356499
  continue;
356425
356500
  }
356426
356501
  configs[name] = pinned, hashMcpConfig(pinned) !== hashMcpConfig(config4) && changed.push(name);
356427
356502
  }
356428
- return ledger.sealed = !0, { configs, changed, deferred };
356503
+ return ledger2.sealed = !0, { configs, changed, deferred };
356429
356504
  }
356430
- function syncSessionMcpRevocations(ledger, active2, isDisabled = () => !1) {
356505
+ function syncSessionMcpRevocations(ledger2, active2, isDisabled = () => !1) {
356431
356506
  let revoked = [];
356432
- for (let [name, pinned] of ledger.entries) {
356507
+ for (let [name, pinned] of ledger2.entries) {
356433
356508
  let reason;
356434
356509
  if (active2[name] === void 0 ? reason = "removed-from-config" : isDisabled(name) && (reason = "disabled"), reason === void 0) {
356435
356510
  sessionRevokedServers.delete(name);
@@ -356480,10 +356555,10 @@ function noteEngineSwapWindowStart() {
356480
356555
  function noteEngineSwapWindowEnd() {
356481
356556
  swapInFlightCount = Math.max(0, swapInFlightCount - 1);
356482
356557
  }
356483
- function summarizeEngineRestartInflight(inflight4) {
356484
- let live = (inflight4.bg?.tasks ?? []).filter((t2) => t2.retiredByNotification !== !0), wf = Math.max(0, inflight4.workflows ?? 0), others = Math.max(0, inflight4.otherSessionsMidTurn ?? 0), parts = [];
356485
- if (live.length > 0 && parts.push(`${live.length} background task${live.length === 1 ? "" : "s"} / subagent${live.length === 1 ? "" : "s"}`), wf > 0 && parts.push(`${wf} workflow run${wf === 1 ? "" : "s"}`), inflight4.leaderStreaming === !0 && parts.push("this turn (still streaming)"), others > 0 && parts.push(`${others} other session${others === 1 ? "" : "s"} mid-turn`), parts.length === 0) return null;
356486
- let stale = inflight4.bg && inflight4.bg.fresh === !1 && live.length > 0 ? " (stale fleet view)" : "";
356558
+ function summarizeEngineRestartInflight(inflight3) {
356559
+ let live = (inflight3.bg?.tasks ?? []).filter((t2) => t2.retiredByNotification !== !0), wf = Math.max(0, inflight3.workflows ?? 0), others = Math.max(0, inflight3.otherSessionsMidTurn ?? 0), parts = [];
356560
+ if (live.length > 0 && parts.push(`${live.length} background task${live.length === 1 ? "" : "s"} / subagent${live.length === 1 ? "" : "s"}`), wf > 0 && parts.push(`${wf} workflow run${wf === 1 ? "" : "s"}`), inflight3.leaderStreaming === !0 && parts.push("this turn (still streaming)"), others > 0 && parts.push(`${others} other session${others === 1 ? "" : "s"} mid-turn`), parts.length === 0) return null;
356561
+ let stale = inflight3.bg && inflight3.bg.fresh === !1 && live.length > 0 ? " (stale fleet view)" : "";
356487
356562
  return `\u26A0 ${parts.join(" + ")} in flight will be interrupted${stale}`;
356488
356563
  }
356489
356564
  var swapInFlightCount, init_engineSwapGate = __esm({
@@ -358590,7 +358665,7 @@ function scopeSessionId() {
358590
358665
  return engineSessionParam();
358591
358666
  }
358592
358667
  function createLiveFleetSource(config4, now2 = Date.now()) {
358593
- let t0 = now2, mainName = config4.mainName ?? "main", ledger = createFleetLedger({
358668
+ let t0 = now2, mainName = config4.mainName ?? "main", ledger2 = createFleetLedger({
358594
358669
  onHookNotice: (frame, sessionScoped) => maybeIngestFleetFrame(frame, sessionScoped),
358595
358670
  // #242 批 3:终态兜底腿的 bg 事实源改接包的 accepted 钩子(归属判别通过之后才回调)。
358596
358671
  // 此前壳在 consume 环里自设一道「meta 两位(sessionScoped+bgNotifyFailClosed)都真才记账」的
@@ -358617,7 +358692,7 @@ function createLiveFleetSource(config4, now2 = Date.now()) {
358617
358692
  viewed: !0
358618
358693
  };
358619
358694
  function project2(nowMs = Date.now()) {
358620
- let viewingTaskId = getAppStateStoreRef()?.getState().viewingAgentTaskId, { tasks: tasks3, workflows } = ledger.project(nowMs, {
358695
+ let viewingTaskId = getAppStateStoreRef()?.getState().viewingAgentTaskId, { tasks: tasks3, workflows } = ledger2.project(nowMs, {
358621
358696
  rowFilter: ROW_FILTER,
358622
358697
  ...viewingTaskId !== void 0 ? { viewingTaskId } : {}
358623
358698
  });
@@ -358644,7 +358719,7 @@ function createLiveFleetSource(config4, now2 = Date.now()) {
358644
358719
  let stream5 = client3.fleet.stream({ ...fleetStreamOptions(), signal: conn.signal });
358645
358720
  for await (let frame of stream5) {
358646
358721
  if (disposed4) return;
358647
- if (ledger.setConnected(!0), lastError = null, process.env.SEMA_DEBUG) {
358722
+ if (ledger2.setConnected(!0), lastError = null, process.env.SEMA_DEBUG) {
358648
358723
  if (process.env.SEMA_DEBUG_FILE && frame.type === "task" && frame.row) {
358649
358724
  let r = frame.row;
358650
358725
  try {
@@ -358677,12 +358752,12 @@ function createLiveFleetSource(config4, now2 = Date.now()) {
358677
358752
  }
358678
358753
  if (observeWorkflowFrame(frame), frame.type === "task" && frame.row && observeFleetTaskFrame(frame.row), frame.type === "snapshot" && Array.isArray(frame.tasks))
358679
358754
  for (let snapRow of frame.tasks) observeFleetTaskFrame(snapRow);
358680
- ledger.applyFrame(frame);
358755
+ ledger2.applyFrame(frame);
358681
358756
  }
358682
- ledger.setConnected(!1), lastError = "stream ended (EOF)";
358757
+ ledger2.setConnected(!1), lastError = "stream ended (EOF)";
358683
358758
  } catch (err8) {
358684
358759
  if (disposed4 || abort.signal.aborted) return;
358685
- scopeSessionId() === sessionAtOpen && (ledger.setConnected(!1), lastError = err8 instanceof Error ? err8.message : String(err8), process.env.SEMA_DEBUG && console.error("[sema][fleet] stream error (will reconnect):", lastError));
358760
+ scopeSessionId() === sessionAtOpen && (ledger2.setConnected(!1), lastError = err8 instanceof Error ? err8.message : String(err8), process.env.SEMA_DEBUG && console.error("[sema][fleet] stream error (will reconnect):", lastError));
358686
358761
  } finally {
358687
358762
  clearInterval(watch4), abort.signal.removeEventListener("abort", onGlobalAbort);
358688
358763
  }
@@ -358704,10 +358779,10 @@ function createLiveFleetSource(config4, now2 = Date.now()) {
358704
358779
  return Math.max(0, nowMs - t0);
358705
358780
  },
358706
358781
  dispose() {
358707
- disposed4 = !0, ledger.dispose(), abort.abort();
358782
+ disposed4 = !0, ledger2.dispose(), abort.abort();
358708
358783
  },
358709
358784
  status() {
358710
- let s = ledger.status();
358785
+ let s = ledger2.status();
358711
358786
  return {
358712
358787
  connected: s.connected,
358713
358788
  version: s.version,
@@ -358806,7 +358881,9 @@ __export(engineUpgradeCoordinator_exports, {
358806
358881
  notePendingEngineRestart: () => notePendingEngineRestart,
358807
358882
  pendingEngineRestartKind: () => pendingEngineRestartKind,
358808
358883
  pendingRestartBannerCopy: () => pendingRestartBannerCopy,
358884
+ pendingRestartLaneAvailable: () => pendingRestartLaneAvailable,
358809
358885
  resetUserConfirmedRestartWindowForTests: () => resetUserConfirmedRestartWindowForTests,
358886
+ retractHeartbeatConfigPending: () => retractHeartbeatConfigPending,
358810
358887
  subscribeUpgradeState: () => subscribeUpgradeState
358811
358888
  });
358812
358889
  import { readFileSync as readFileSync28, statSync as statSync9 } from "fs";
@@ -358828,8 +358905,13 @@ function engineSpawnSettingsFingerprint() {
358828
358905
  return "";
358829
358906
  }
358830
358907
  }
358908
+ function mergedPendingKind() {
358909
+ if (pendingCauses.size === 0) return null;
358910
+ for (let k2 of pendingCauses.values()) if (k2 === "config") return "config";
358911
+ return "update";
358912
+ }
358831
358913
  function setPhase(phase, opts) {
358832
- state2 = {
358914
+ phase !== "ready" && pendingCauses.clear(), state2 = {
358833
358915
  phase,
358834
358916
  ...phase === "ready" && opts?.kind ? { kind: opts.kind } : {},
358835
358917
  ...phase === "done" ? { appliedAt: Date.now(), ...opts?.version ? { version: opts.version } : {} } : {}
@@ -358891,8 +358973,36 @@ function noteEngineTurnBoundary() {
358891
358973
  }
358892
358974
  detectPendingFromDisk();
358893
358975
  }
358894
- function notePendingEngineRestart(kind) {
358895
- applying || state2.phase === "ready" && state2.kind === "config" && kind === "update" || state2.phase === "ready" && state2.kind === kind || setPhase("ready", { kind });
358976
+ function notePendingEngineRestart(kind, cause = "disk") {
358977
+ if (restartLedgerTxn) {
358978
+ let q2 = applyQueuedNotes.get(cause);
358979
+ applyQueuedNotes.set(cause, q2 === "config" && kind === "update" ? "config" : kind), applyQueuedRetractions.delete(cause);
358980
+ return;
358981
+ }
358982
+ let prev = pendingCauses.get(cause), effective = prev === "config" && kind === "update" ? "config" : kind, hadSameEntry = prev === effective;
358983
+ pendingCauses.set(cause, effective);
358984
+ let merged = mergedPendingKind() ?? effective;
358985
+ state2.phase === "ready" && state2.kind === merged && hadSameEntry || setPhase("ready", { kind: merged });
358986
+ }
358987
+ function pendingRestartLaneAvailable() {
358988
+ return deps !== null;
358989
+ }
358990
+ function retractHeartbeatConfigPending() {
358991
+ if (restartLedgerTxn) {
358992
+ applyQueuedRetractions.add("heartbeat-config"), applyQueuedNotes.delete("heartbeat-config");
358993
+ return;
358994
+ }
358995
+ if (!pendingCauses.delete("heartbeat-config")) return;
358996
+ let remaining = mergedPendingKind();
358997
+ if (remaining !== null) {
358998
+ logForDebugging(
358999
+ `[engine-upgrade] heartbeat config drift resolved, but other pending causes remain (${[...pendingCauses.keys()].join(", ")}) \u2014 keeping the banner`
359000
+ ), state2.phase === "ready" && state2.kind !== remaining && setPhase("ready", { kind: remaining });
359001
+ return;
359002
+ }
359003
+ state2.phase === "ready" && (logForDebugging(
359004
+ "[engine-upgrade] the engine finished hot-applying the config change that raised this banner \u2014 retracting the pending restart (nothing left to apply)"
359005
+ ), setPhase("idle"));
358896
359006
  }
358897
359007
  function pendingEngineRestartKind() {
358898
359008
  return state2.phase === "ready" ? state2.kind ?? "update" : null;
@@ -358901,6 +359011,8 @@ async function applyPendingEngineRestart() {
358901
359011
  if (!deps || applying) return "unchanged";
358902
359012
  let d4 = deps, kindBefore = pendingEngineRestartKind();
358903
359013
  if (kindBefore === null) return "unchanged";
359014
+ let causesBefore = new Map(pendingCauses);
359015
+ applyQueuedNotes.clear(), applyQueuedRetractions.clear(), restartLedgerTxn = !0;
358904
359016
  let killedSnapshot = [];
358905
359017
  try {
358906
359018
  killedSnapshot = (d4.readBgTasks ?? (await Promise.resolve().then(() => (init_fleetClient(), fleetClient_exports))).readEngineActiveBgTasks)().tasks.filter((t2) => t2.retiredByNotification !== !0);
@@ -358924,7 +359036,12 @@ async function applyPendingEngineRestart() {
358924
359036
  `[engine-upgrade] user-confirmed restart moved the engine endpoint (${baseUrlBefore} -> ${baseUrlAfter}) \u2014 fixed-port expectation broken; other attached shells still point at the old one`
358925
359037
  ), !ok2) {
358926
359038
  let stillAlive = await engineStillAlive(instanceBefore);
358927
- if (setPhase("ready", { kind: kindBefore }), stillAlive) return "unchanged";
359039
+ for (let [cause, kind] of causesBefore) pendingCauses.has(cause) || pendingCauses.set(cause, kind);
359040
+ for (let [cause, kind] of applyQueuedNotes) pendingCauses.set(cause, kind);
359041
+ for (let cause of applyQueuedRetractions) pendingCauses.delete(cause);
359042
+ if (applyQueuedNotes.clear(), applyQueuedRetractions.clear(), restartLedgerTxn = !1, mergedPendingKind() === null ? (logForDebugging(
359043
+ "[engine-upgrade] the confirmed restart did not go through, but every pending cause resolved while it ran \u2014 no banner to restore"
359044
+ ), setPhase("idle")) : setPhase("ready", { kind: mergedPendingKind() ?? kindBefore }), stillAlive) return "unchanged";
358928
359045
  if (killedSnapshot.length > 0) {
358929
359046
  let notify5 = d4.notifyKilled ?? synthesizeKilledNotifications;
358930
359047
  try {
@@ -358956,6 +359073,10 @@ async function applyPendingEngineRestart() {
358956
359073
  } catch {
358957
359074
  }
358958
359075
  }
359076
+ let carryCatalog = applyQueuedNotes.get("catalog");
359077
+ restartLedgerTxn = !1, applyQueuedNotes.clear(), applyQueuedRetractions.clear(), carryCatalog !== void 0 && (logForDebugging(
359078
+ "[engine-upgrade] a model-catalog change landed while the confirmed restart was running \u2014 re-arming the banner (models.json is outside the fingerprint, so we cannot prove the new engine picked it up)"
359079
+ ), notePendingEngineRestart(carryCatalog, "catalog"));
358959
359080
  let nowFingerprint = fingerprint(d4.entryPath);
358960
359081
  return nowFingerprint !== null && appliedFingerprint !== null && nowFingerprint !== appliedFingerprint && (logForDebugging(
358961
359082
  "[engine-upgrade] configuration changed again while the confirmed restart was running \u2014 re-arming the pending banner (the new engine does not have it)"
@@ -359028,7 +359149,7 @@ async function classifyStreamTear() {
359028
359149
  let r = await sdkProbeHealth3(base, 2e3);
359029
359150
  return r.alive ? typeof r.health.instanceId == "string" && r.health.instanceId !== before ? "restarted" : "not-restart" : "engine-down";
359030
359151
  }
359031
- var deps, baseline, turnRefs, state2, applying, listeners7, doneFadeTimer, swapOpSeq, activeSwapOp, USER_RESTART_GRACE_MS, userRestartDepth, userRestartUntil, USER_RESTART_TRANSCRIPT_LINE, init_engineUpgradeCoordinator = __esm({
359152
+ var deps, baseline, turnRefs, state2, applying, listeners7, pendingCauses, applyQueuedNotes, applyQueuedRetractions, restartLedgerTxn, doneFadeTimer, swapOpSeq, activeSwapOp, USER_RESTART_GRACE_MS, userRestartDepth, userRestartUntil, USER_RESTART_TRANSCRIPT_LINE, init_engineUpgradeCoordinator = __esm({
359032
359153
  "build-src/src/sema/engineUpgradeCoordinator.ts"() {
359033
359154
  init_envUtils();
359034
359155
  init_engineReadFace();
@@ -359037,6 +359158,7 @@ var deps, baseline, turnRefs, state2, applying, listeners7, doneFadeTimer, swapO
359037
359158
  init_dist();
359038
359159
  init_engineSwapGate();
359039
359160
  deps = null, baseline = null, turnRefs = 0, state2 = { phase: "idle" }, applying = !1, listeners7 = /* @__PURE__ */ new Set();
359161
+ pendingCauses = /* @__PURE__ */ new Map(), applyQueuedNotes = /* @__PURE__ */ new Map(), applyQueuedRetractions = /* @__PURE__ */ new Set(), restartLedgerTxn = !1;
359040
359162
  doneFadeTimer = null, swapOpSeq = 0, activeSwapOp = null;
359041
359163
  USER_RESTART_GRACE_MS = 2e4, userRestartDepth = 0, userRestartUntil = 0;
359042
359164
  USER_RESTART_TRANSCRIPT_LINE = "Engine restarted (user-confirmed) \u2014 press \u2191 to resend an interrupted prompt.";
@@ -359530,6 +359652,128 @@ var nextTurnId, activeTurnId, heldTurnIds, lostTurnIds, MAX_HELD_TURNS, init_inj
359530
359652
  }
359531
359653
  });
359532
359654
 
359655
+ // build-src/src/sema/terminationIntentLedger.ts
359656
+ function ttlMs() {
359657
+ return ttlOverrideMs ?? DEFAULT_TTL_MS;
359658
+ }
359659
+ function purgeExpired(now2) {
359660
+ let window2 = ttlMs();
359661
+ for (let [taskId, row2] of ledger)
359662
+ now2 - row2.at >= window2 && ledger.delete(taskId);
359663
+ }
359664
+ function recordTerminationIntent(taskId, source) {
359665
+ if (typeof taskId != "string" || taskId.length === 0) return;
359666
+ let now2 = Date.now();
359667
+ purgeExpired(now2), ledger.set(taskId, { at: now2, source });
359668
+ }
359669
+ function wasRecentlyTerminatedByUs(taskId) {
359670
+ if (typeof taskId != "string" || taskId.length === 0) return !1;
359671
+ let now2 = Date.now();
359672
+ return purgeExpired(now2), ledger.has(taskId);
359673
+ }
359674
+ function terminationIntentSource(taskId) {
359675
+ return typeof taskId != "string" || taskId.length === 0 ? null : (purgeExpired(Date.now()), ledger.get(taskId)?.source ?? null);
359676
+ }
359677
+ function armTerminationIntentOnAbort(signal, taskId) {
359678
+ if (signal === void 0 || typeof taskId != "string" || taskId.length === 0) return;
359679
+ let record2 = () => {
359680
+ signal.reason !== "background" && recordTerminationIntent(taskId, "esc-abort");
359681
+ };
359682
+ if (signal.aborted) {
359683
+ record2();
359684
+ return;
359685
+ }
359686
+ signal.addEventListener("abort", record2, { once: !0 });
359687
+ }
359688
+ function forgetTerminationIntent(taskId) {
359689
+ typeof taskId != "string" || taskId.length === 0 || ledger.delete(taskId);
359690
+ }
359691
+ function readStatus2(row2) {
359692
+ let s = row2?.status;
359693
+ return typeof s == "string" && s.length > 0 ? s : null;
359694
+ }
359695
+ function defaultSleep(ms, signal) {
359696
+ return new Promise((resolve57) => {
359697
+ if (signal?.aborted === !0) {
359698
+ resolve57();
359699
+ return;
359700
+ }
359701
+ let timer3 = setTimeout(() => {
359702
+ signal?.removeEventListener("abort", onAbort), resolve57();
359703
+ }, ms);
359704
+ function onAbort() {
359705
+ clearTimeout(timer3), resolve57();
359706
+ }
359707
+ signal?.addEventListener("abort", onAbort, { once: !0 });
359708
+ });
359709
+ }
359710
+ function anySignal(a, b3) {
359711
+ if (a === void 0) return b3;
359712
+ if (typeof AbortSignal.any == "function") return AbortSignal.any([a, b3]);
359713
+ let ac = new AbortController(), forward = (s) => ac.abort(s.reason);
359714
+ return a.aborted ? forward(a) : a.addEventListener("abort", () => forward(a), { once: !0 }), b3.aborted ? forward(b3) : b3.addEventListener("abort", () => forward(b3), { once: !0 }), ac.signal;
359715
+ }
359716
+ async function awaitInterruptedRunSettle(taskId, deps2) {
359717
+ let getRun = deps2.getRun;
359718
+ if (typeof getRun != "function") return { kind: "unknown" };
359719
+ if (typeof taskId != "string" || taskId.length === 0) return { kind: "unknown" };
359720
+ let budgetMs = deps2.budgetMs ?? settleBudgetOverrideMs ?? SETTLE_BUDGET_MS, intervalMs = deps2.intervalMs ?? settlePollOverrideMs ?? SETTLE_POLL_INTERVAL_MS, started2 = Date.now(), sawRunning = !1, isAborted3 = () => deps2.signal?.aborted === !0, budgetAc = new AbortController(), budgetSpent = !1, markStopped = () => {
359721
+ }, stopped = new Promise((resolve57) => {
359722
+ markStopped = () => resolve57(PROBE_STOPPED);
359723
+ }), onCallerAbort = () => markStopped(), budgetTimer = setTimeout(() => {
359724
+ budgetSpent = !0, budgetAc.abort(), markStopped();
359725
+ }, budgetMs);
359726
+ deps2.signal?.addEventListener("abort", onCallerAbort, { once: !0 }), isAborted3() && markStopped();
359727
+ let probeSignal = anySignal(deps2.signal, budgetAc.signal);
359728
+ try {
359729
+ for (; ; ) {
359730
+ if (isAborted3()) return { kind: "unknown" };
359731
+ if (budgetSpent) break;
359732
+ let probe3 = getRun(taskId, {
359733
+ signal: probeSignal
359734
+ }).then(
359735
+ (row2) => row2,
359736
+ () => PROBE_FAILED
359737
+ ), outcome = await Promise.race([probe3, stopped]);
359738
+ if (isAborted3()) return { kind: "unknown" };
359739
+ let status3 = outcome === PROBE_STOPPED || outcome === PROBE_FAILED ? null : readStatus2(outcome);
359740
+ if (status3 !== null) {
359741
+ if (CLAIM_RELEASED_STATES.includes(status3)) return { kind: "settled", status: status3 };
359742
+ if (PARK_STATES.includes(status3)) return { kind: "parked", status: status3 };
359743
+ status3 === "running" && (sawRunning = !0);
359744
+ }
359745
+ if (budgetSpent) break;
359746
+ let left = started2 + budgetMs - Date.now();
359747
+ if (left <= 0) break;
359748
+ if (await defaultSleep(Math.min(intervalMs, left), probeSignal), isAborted3()) return { kind: "unknown" };
359749
+ }
359750
+ return isAborted3() ? { kind: "unknown" } : sawRunning ? { kind: "still-running", waitedMs: Math.max(0, Date.now() - started2) } : { kind: "unknown" };
359751
+ } finally {
359752
+ clearTimeout(budgetTimer);
359753
+ try {
359754
+ deps2.signal?.removeEventListener("abort", onCallerAbort);
359755
+ } catch {
359756
+ }
359757
+ }
359758
+ }
359759
+ function interruptedRunSettleRow(taskId, verdict) {
359760
+ if (verdict.kind === "settled")
359761
+ return `The turn you interrupted has finished stopping on the engine (run ${taskId}), so sema is sending your message now as a new turn.`;
359762
+ if (verdict.kind === "still-running") {
359763
+ let secs = Math.max(1, Math.round(verdict.waitedMs / 1e3));
359764
+ return `The turn you interrupted is still finishing up on the engine (run ${taskId}), so your message was NOT sent \u2014 a session runs one turn at a time. sema waited ${String(secs)}s for that run to stop and does not send your message automatically after that: send it again in a moment.`;
359765
+ }
359766
+ return null;
359767
+ }
359768
+ var DEFAULT_TTL_MS, ledger, ttlOverrideMs, SETTLE_BUDGET_MS, SETTLE_POLL_INTERVAL_MS, settleBudgetOverrideMs, settlePollOverrideMs, PARK_STATES, PROBE_STOPPED, PROBE_FAILED, init_terminationIntentLedger = __esm({
359769
+ "build-src/src/sema/terminationIntentLedger.ts"() {
359770
+ init_dist();
359771
+ DEFAULT_TTL_MS = 6e4, ledger = /* @__PURE__ */ new Map(), ttlOverrideMs = null;
359772
+ SETTLE_BUDGET_MS = 1e4, SETTLE_POLL_INTERVAL_MS = 1e3, settleBudgetOverrideMs = null, settlePollOverrideMs = null, PARK_STATES = ["suspended", "needs_review"];
359773
+ PROBE_STOPPED = /* @__PURE__ */ Symbol("sema.interruptedSettleProbeStopped"), PROBE_FAILED = /* @__PURE__ */ Symbol("sema.interruptedSettleProbeFailed");
359774
+ }
359775
+ });
359776
+
359533
359777
  // build-src/src/sema/engineAttachCapabilityGate.ts
359534
359778
  var engineAttachCapabilityGate_exports = {};
359535
359779
  __export(engineAttachCapabilityGate_exports, {
@@ -359627,6 +359871,25 @@ var lastRecord, init_engineAttachCapabilityGate = __esm({
359627
359871
  }
359628
359872
  });
359629
359873
 
359874
+ // build-src/src/sema/engineConfigDriftGate.ts
359875
+ function readOrdinal(v2) {
359876
+ return typeof v2 == "number" && Number.isFinite(v2) && v2 >= 0 ? v2 : void 0;
359877
+ }
359878
+ function decideConfigDriftVerdict(input) {
359879
+ let { baselineConfigHash, baselineInstanceId, health } = input, nowHash = typeof health?.configHash == "string" ? health.configHash : void 0;
359880
+ if (!baselineConfigHash || !nowHash) return "skip";
359881
+ if (nowHash === baselineConfigHash) return "in-sync";
359882
+ if (health?.restartRequired === !0) return "ask";
359883
+ let nowInstance = typeof health?.instanceId == "string" ? health.instanceId : void 0;
359884
+ if (!baselineInstanceId || !nowInstance || nowInstance !== baselineInstanceId) return "ask";
359885
+ let target = readOrdinal(health?.configTargetOrdinal), applied = readOrdinal(health?.configAppliedOrdinal);
359886
+ return target === void 0 || applied === void 0 ? "ask" : target === applied ? "advance-baseline" : "ask";
359887
+ }
359888
+ var init_engineConfigDriftGate = __esm({
359889
+ "build-src/src/sema/engineConfigDriftGate.ts"() {
359890
+ }
359891
+ });
359892
+
359630
359893
  // build-src/src/sema/engineLogSweep.ts
359631
359894
  import { readdirSync as readdirSync8, rmSync as rmSync5, statSync as statSync10 } from "node:fs";
359632
359895
  import { basename as basename36, join as join119 } from "node:path";
@@ -361000,8 +361263,8 @@ async function reapStaleEngine(portFile, opts) {
361000
361263
  async function reapAnchoredEngineForUpdate() {
361001
361264
  let existing = readPortFile(getEnginePortFilePath());
361002
361265
  if (!existing || !isProcessAlive(existing.pid)) return { status: "none", midTurn: 0 };
361003
- let midTurn = otherSessionsMidTurn(), inflight4 = activeTurnInflight();
361004
- return midTurn > 0 || inflight4 !== null ? { status: "busy", midTurn: midTurn > 0 ? midTurn : 1 } : (await reapStaleEngine(existing, { killPid: !0 }), { status: "reaped", midTurn: 0 });
361266
+ let midTurn = otherSessionsMidTurn(), inflight3 = activeTurnInflight();
361267
+ return midTurn > 0 || inflight3 !== null ? { status: "busy", midTurn: midTurn > 0 ? midTurn : 1 } : (await reapStaleEngine(existing, { killPid: !0 }), { status: "reaped", midTurn: 0 });
361005
361268
  }
361006
361269
  function pinnedEnginePort() {
361007
361270
  let override = process.env.SEMA_ENGINE_PORT;
@@ -361094,16 +361357,16 @@ async function initEngineLifecycleInner(opts) {
361094
361357
  );
361095
361358
  let sourceStale = (existing.configSource ?? "local") !== engineConfigSource, desiredPort = pinnedEnginePort(), portStale = desiredPort !== null && existing.port !== desiredPort, pidStale = health2 !== null && typeof health2.pid == "number" && health2.pid !== existing.pid, identityOk = health2 !== null && !pidStale && healthIdentityMatches(health2, expectedDataRoot), upgradeDeferred = !1;
361096
361359
  if (identityOk && (versionStale || sourceStale)) {
361097
- let midTurn = otherSessionsMidTurn(), inflight4 = activeTurnInflight();
361098
- (midTurn > 0 || inflight4 !== null) && (upgradeDeferred = !0, logForDebugging(
361099
- `[engine-lifecycle] engine is ${versionStale ? "version-stale" : "config-source-stale"} but ${midTurn} local session(s) are mid-turn${inflight4 ? ` (turn-inflight marker pid=${inflight4.pid})` : ""} \u2014 deferring the reap, reusing the running engine (the upgrade applies on a later launch when no turn is in flight)`
361360
+ let midTurn = otherSessionsMidTurn(), inflight3 = activeTurnInflight();
361361
+ (midTurn > 0 || inflight3 !== null) && (upgradeDeferred = !0, logForDebugging(
361362
+ `[engine-lifecycle] engine is ${versionStale ? "version-stale" : "config-source-stale"} but ${midTurn} local session(s) are mid-turn${inflight3 ? ` (turn-inflight marker pid=${inflight3.pid})` : ""} \u2014 deferring the reap, reusing the running engine (the upgrade applies on a later launch when no turn is in flight)`
361100
361363
  ));
361101
361364
  }
361102
361365
  let forceFresh = opts?.forceFreshEngine === !0, engineCompatible = !forceFresh && identityOk && (!versionStale && !sourceStale || upgradeDeferred), portMoveDeferred = !1;
361103
361366
  if (engineCompatible && portStale) {
361104
- let midTurn = otherSessionsMidTurn(), inflight4 = midTurn > 0 ? null : activeTurnInflight();
361105
- (midTurn > 0 || inflight4 !== null) && (portMoveDeferred = !0, logForDebugging(
361106
- `[engine-lifecycle] port-config mismatch (anchor port=${existing.port} != configured ${desiredPort}) but ${midTurn} local session(s) are mid-turn${inflight4 ? ` (turn-inflight marker pid=${inflight4.pid})` : ""} \u2014 deferring the restart, reusing the engine on port ${existing.port} (the port moves on a later launch when no turn is in flight)`
361367
+ let midTurn = otherSessionsMidTurn(), inflight3 = midTurn > 0 ? null : activeTurnInflight();
361368
+ (midTurn > 0 || inflight3 !== null) && (portMoveDeferred = !0, logForDebugging(
361369
+ `[engine-lifecycle] port-config mismatch (anchor port=${existing.port} != configured ${desiredPort}) but ${midTurn} local session(s) are mid-turn${inflight3 ? ` (turn-inflight marker pid=${inflight3.pid})` : ""} \u2014 deferring the restart, reusing the engine on port ${existing.port} (the port moves on a later launch when no turn is in flight)`
361107
361370
  ));
361108
361371
  }
361109
361372
  if (engineCompatible && (!portStale || portMoveDeferred)) {
@@ -361343,7 +361606,7 @@ function sleep7(ms) {
361343
361606
  return new Promise((resolve57) => setTimeout(resolve57, ms));
361344
361607
  }
361345
361608
  function startHealthCheckLoop(instance2, onSignal) {
361346
- let misses = 0, fired2 = !1, versionDriftBeats = 0, newerEngineLogged = !1, configDriftReported = !1, versionDriftReported = !1, baselineConfigHash = instance2.configHash, timer3 = setInterval(() => {
361609
+ let misses = 0, fired2 = !1, versionDriftBeats = 0, newerEngineLogged = !1, configDriftReported = !1, versionDriftReported = !1, baselineConfigHash = instance2.configHash, baselineInstanceId = instance2.instanceId, timer3 = setInterval(() => {
361347
361610
  (async () => {
361348
361611
  if (fired2) return;
361349
361612
  let health = await probeHealth(instance2.port);
@@ -361353,12 +361616,13 @@ function startHealthCheckLoop(instance2, onSignal) {
361353
361616
  ), onSignal("engineDead"));
361354
361617
  return;
361355
361618
  }
361356
- if (misses = 0, baselineConfigHash && health.configHash) {
361357
- let drifted = health.configHash !== baselineConfigHash;
361358
- drifted && !configDriftReported ? (configDriftReported = !0, logForDebugging(
361359
- `[engine-lifecycle] heartbeat: configHash drift (${baselineConfigHash} \u2192 ${health.configHash}) \u2192 configDrift (pending user confirmation; heartbeat keeps running)`
361360
- ), onSignal("configDrift")) : !drifted && configDriftReported && (configDriftReported = !1);
361361
- }
361619
+ misses = 0;
361620
+ let verdict = decideConfigDriftVerdict({ baselineConfigHash, baselineInstanceId, health });
361621
+ verdict === "ask" && !configDriftReported ? (configDriftReported = !0, logForDebugging(
361622
+ `[engine-lifecycle] heartbeat: configHash drift (${String(baselineConfigHash)} \u2192 ${String(health.configHash)}) with an UNAPPLIED change (config apply ordinals not converged, or the endpoint is answered by a different instance) \u2192 configDrift (pending user confirmation; heartbeat keeps running)`
361623
+ ), onSignal("configDrift")) : verdict === "advance-baseline" ? (logForDebugging(
361624
+ `[engine-lifecycle] heartbeat: configHash drift (${String(baselineConfigHash)} \u2192 ${String(health.configHash)}) is already HOT-APPLIED (same instance, config apply ordinals converged) \u2014 advancing the baseline, no restart prompt`
361625
+ ), baselineConfigHash = health.configHash, configDriftReported && (configDriftReported = !1, onSignal("configDriftResolved"))) : verdict === "in-sync" && configDriftReported && (configDriftReported = !1, onSignal("configDriftResolved"));
361362
361626
  let want = localEngineVersion();
361363
361627
  if (want !== void 0 && health.version && health.version === want && versionDriftReported && (versionDriftReported = !1), want !== void 0 && health.version && health.version !== want && !fired2) {
361364
361628
  if (!localDistNewerThanEngine(want, health.version)) {
@@ -361692,6 +361956,7 @@ var PORT_FILE_VERSION, HEALTH_POLL_INTERVAL_MS, HEALTH_POLL_MAX_ATTEMPTS, HEALTH
361692
361956
  init_engineRuntimeStatus();
361693
361957
  init_engineAttachCapabilityGate();
361694
361958
  init_engineReadFace();
361959
+ init_engineConfigDriftGate();
361695
361960
  init_engineLogSweep();
361696
361961
  init_lockfile();
361697
361962
  init_debug();
@@ -362347,27 +362612,6 @@ var init_defaultModelWriter = __esm({
362347
362612
  }
362348
362613
  });
362349
362614
 
362350
- // build-src/src/sema/engineEndpointSwap.ts
362351
- var engineEndpointSwap_exports = {};
362352
- __export(engineEndpointSwap_exports, {
362353
- registerEngineConfigRespawn: () => registerEngineConfigRespawn,
362354
- requestEngineConfigRespawn: () => requestEngineConfigRespawn
362355
- });
362356
- function registerEngineConfigRespawn(fn2) {
362357
- respawnFn = fn2;
362358
- }
362359
- async function requestEngineConfigRespawn() {
362360
- return respawnFn ? (inflight2 || (inflight2 = respawnFn().finally(() => {
362361
- inflight2 = null;
362362
- })), inflight2) : !1;
362363
- }
362364
- var respawnFn, inflight2, init_engineEndpointSwap = __esm({
362365
- "build-src/src/sema/engineEndpointSwap.ts"() {
362366
- respawnFn = null;
362367
- inflight2 = null;
362368
- }
362369
- });
362370
-
362371
362615
  // build-src/src/sema/modelEndpointSwitch.ts
362372
362616
  var modelEndpointSwitch_exports = {};
362373
362617
  __export(modelEndpointSwitch_exports, {
@@ -362375,6 +362619,15 @@ __export(modelEndpointSwitch_exports, {
362375
362619
  ensureEngineServesModel: () => ensureEngineServesModel,
362376
362620
  poolEntryForModelRef: () => poolEntryForModelRef
362377
362621
  });
362622
+ function warnCrossEndpointResidual(entry, instanceId, extra) {
362623
+ if (instanceId !== void 0) {
362624
+ let key = JSON.stringify([instanceId, entry.id, servedEndpointFor(entry)]);
362625
+ if (warnedCrossEndpointEntries.has(key)) return;
362626
+ warnedCrossEndpointEntries.add(key);
362627
+ }
362628
+ let line = `Model "${entry.id}" lives on a different upstream endpoint (${entry.baseUrl}) and this engine cannot route it per-model. ${extra ?? "It is saved as the default, but the running engine still serves the previous endpoint"} \u2014 ${pendingRestartLaneAvailable() ? "press ctrl+u to restart the engine and apply it" : "it takes effect the next time a local engine is spawned"}. Until then this session's turns keep going to the previously configured provider.`;
362629
+ surfaceTranscriptSystemNotice(line) || console.error(`[sema] ${line}`);
362630
+ }
362378
362631
  function engineBootEnv() {
362379
362632
  let out6 = {};
362380
362633
  for (let k2 of Object.keys(process.env)) {
@@ -362386,10 +362639,13 @@ function engineBootEnv() {
362386
362639
  function poolEntryForModelRef(ref, pool = readModelPool()) {
362387
362640
  return pool.find((e) => e.id === ref) ?? pool.find((e) => e.modelId === ref);
362388
362641
  }
362642
+ function servedEndpointFor(entry, env6 = engineBootEnv()) {
362643
+ return entry.api === "anthropic-messages" ? norm(env6.ANTHROPIC_BASE_URL ?? env6.ANTHROPIC_BASEURL) : norm(env6.MODEL_GATEWAY_BASEURL);
362644
+ }
362389
362645
  function endpointSwitchNeeded(entry, env6 = engineBootEnv()) {
362390
362646
  if (entry.baseUrl.replace(/\/+$/, "") === "") return !1;
362391
362647
  let want = buildModelEnv({ defaultModel: toCatalogEntry(entry) });
362392
- return entry.api === "anthropic-messages" ? norm(want.ANTHROPIC_BASE_URL) !== norm(env6.ANTHROPIC_BASE_URL ?? env6.ANTHROPIC_BASEURL) : norm(want.MODEL_GATEWAY_BASEURL) !== norm(env6.MODEL_GATEWAY_BASEURL);
362648
+ return (entry.api === "anthropic-messages" ? norm(want.ANTHROPIC_BASE_URL) : norm(want.MODEL_GATEWAY_BASEURL)) !== servedEndpointFor(entry, env6);
362393
362649
  }
362394
362650
  function versionGte(v2, min) {
362395
362651
  let m2 = v2 ? /^(\d+)\.(\d+)\.(\d+)/.exec(v2) : null;
@@ -362400,16 +362656,20 @@ function versionGte(v2, min) {
362400
362656
  async function engineRoutesEntryItself(entry) {
362401
362657
  try {
362402
362658
  let u = new URL(entry.baseUrl);
362403
- if (u.protocol !== "http:" && u.protocol !== "https:") return !1;
362659
+ if (u.protocol !== "http:" && u.protocol !== "https:") return { instant: !1 };
362404
362660
  } catch {
362405
- return !1;
362661
+ return { instant: !1 };
362406
362662
  }
362407
- let { probeLocalEngineHealth: probeLocalEngineHealth2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports)), health = await probeLocalEngineHealth2();
362408
- if (!versionGte(health?.version, PER_MODEL_BASEURL_MIN)) return !1;
362663
+ let { probeLocalEngineHealth: probeLocalEngineHealth2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports)), health = await probeLocalEngineHealth2(), instanceId = typeof health?.instanceId == "string" ? health.instanceId : void 0;
362664
+ if (!versionGte(health?.version, PER_MODEL_BASEURL_MIN)) return { instant: !1, instanceId };
362409
362665
  let models = getLiveModelCatalog()?.models;
362410
- return models ? models.some((m2) => m2.name === entry.id || entry.modelId !== "" && m2.id === entry.modelId) : !1;
362666
+ return models ? {
362667
+ instant: models.some((m2) => m2.name === entry.id || entry.modelId !== "" && m2.id === entry.modelId),
362668
+ instanceId
362669
+ } : { instant: !1, instanceId };
362411
362670
  }
362412
362671
  async function ensureEngineServesModel(ref) {
362672
+ let crossEndpointRisk = null, engineInstanceId;
362413
362673
  try {
362414
362674
  let { hasManageableLocalEngine: hasManageableLocalEngine2 } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports));
362415
362675
  if (!hasManageableLocalEngine2()) return { switched: !1 };
@@ -362424,7 +362684,8 @@ async function ensureEngineServesModel(ref) {
362424
362684
  `[sema][model-endpoint] boot-readback echo of catalog default ${entry.id} \u2014 no persist, no respawn (S3 discipline)`
362425
362685
  ), { switched: !1 };
362426
362686
  }
362427
- let instant = await engineRoutesEntryItself(entry);
362687
+ let routed = await engineRoutesEntryItself(entry), instant = routed.instant;
362688
+ engineInstanceId = routed.instanceId, needsEndpoint && !instant && (crossEndpointRisk = entry);
362428
362689
  {
362429
362690
  let session2 = getSessionModelLatch();
362430
362691
  if (typeof session2 == "string" && session2.length > 0 && (session2 === ref || entry.id === session2 || entry.modelId !== "" && entry.modelId === session2) && (instant || !needsEndpoint))
@@ -362433,28 +362694,31 @@ async function ensureEngineServesModel(ref) {
362433
362694
  ), { switched: !1 };
362434
362695
  }
362435
362696
  let w2 = persistDefaultModelSelection(entry.id);
362436
- if (w2.error) return { switched: !1, error: w2.error };
362437
- if (instant || !needsEndpoint)
362438
- return process.env.SEMA_DEBUG && console.error(
362439
- `[sema][model-endpoint] ${instant ? "engine routes it per-model" : "same endpoint"}: ${entry.id} (${entry.api} @ ${entry.baseUrl}) \u2014 default persisted (env + top-level model), respawn skipped`
362440
- ), { switched: !1 };
362441
- let ok2 = await requestEngineConfigRespawn();
362442
- return process.env.SEMA_DEBUG && console.error(
362443
- `[sema][model-endpoint] switched main \u2192 ${entry.id} (${entry.api} @ ${entry.baseUrl}) \xB7 engine respawn ${ok2 ? "ok" : "unavailable"}`
362444
- ), { switched: ok2 };
362697
+ return w2.error ? (needsEndpoint && !instant && warnCrossEndpointResidual(
362698
+ entry,
362699
+ engineInstanceId,
362700
+ "Saving it as the default FAILED, and the running engine serves the previous endpoint"
362701
+ ), { switched: !1, error: w2.error }) : instant || !needsEndpoint ? (process.env.SEMA_DEBUG && console.error(
362702
+ `[sema][model-endpoint] ${instant ? "engine routes it per-model" : "same endpoint"}: ${entry.id} (${entry.api} @ ${entry.baseUrl}) \u2014 default persisted (env + top-level model), respawn skipped`
362703
+ ), { switched: !1 }) : (pendingRestartLaneAvailable() && notePendingEngineRestart("config", "catalog"), warnCrossEndpointResidual(entry, engineInstanceId), { switched: !1 });
362445
362704
  } catch (e) {
362705
+ try {
362706
+ crossEndpointRisk !== null && warnCrossEndpointResidual(crossEndpointRisk, engineInstanceId, "Switching the default FAILED");
362707
+ } catch {
362708
+ }
362446
362709
  return { switched: !1, error: e };
362447
362710
  }
362448
362711
  }
362449
- var norm, PER_MODEL_BASEURL_MIN, init_modelEndpointSwitch = __esm({
362712
+ var norm, warnedCrossEndpointEntries, PER_MODEL_BASEURL_MIN, init_modelEndpointSwitch = __esm({
362450
362713
  "build-src/src/sema/modelEndpointSwitch.ts"() {
362451
362714
  init_modelChannels();
362452
362715
  init_rosterStore();
362453
362716
  init_defaultModelWriter();
362454
362717
  init_dist();
362455
- init_engineEndpointSwap();
362718
+ init_engineUpgradeCoordinator();
362719
+ init_transcriptSystemNotice();
362456
362720
  init_applyOnboard();
362457
- norm = (u) => (u ?? "").replace(/\/+$/, "");
362721
+ norm = (u) => (u ?? "").replace(/\/+$/, ""), warnedCrossEndpointEntries = /* @__PURE__ */ new Set();
362458
362722
  PER_MODEL_BASEURL_MIN = [1, 128, 0];
362459
362723
  }
362460
362724
  });
@@ -362966,18 +363230,21 @@ Fix: run \`sema doctor\` to diagnose, or restart sema to retry.`
362966
363230
  }
362967
363231
  }
362968
363232
  }
362969
- }, bgTearResends = 0, drainingRetries = 0, resumeAtRetried = !1, busySignal = null, readBusySignal = () => busySignal, runningChoiceOffered = !1, runningChoiceSilentWaitTaskId = null, engineFrameSeen = !1, retryStream = !0;
363233
+ }, bgTearResends = 0, drainingRetries = 0, resumeAtRetried = !1, busySignal = null, readBusySignal = () => busySignal, runningChoiceOffered = !1, runningChoiceSilentWaitTaskId = null, engineFrameSeen = !1, boundRunId, retryStream = !0, interruptedResendDone = !1, pendingInterruptedSettledRow = null;
362970
363234
  for (; retryStream; ) {
362971
- retryStream = !1, engineFrameSeen = !1, busySignal = null;
363235
+ retryStream = !1, engineFrameSeen = !1, busySignal = null, boundRunId = void 0;
362972
363236
  try {
362973
- let reattachArmed = typeof client.runs.get == "function" && !isBgHeadlessWorker(), boundRunId, rawLive = client.tasks.stream(req, {
363237
+ let reattachArmed = typeof client.runs.get == "function" && !isBgHeadlessWorker(), rawLive = client.tasks.stream(req, {
362974
363238
  signal,
362975
- ...reattachArmed ? {
362976
- onRunBound: (id) => {
362977
- boundRunId = id;
362978
- }
362979
- } : {}
362980
- }), liveEvents = reattachArmed ? withInteractiveReattach(rawLive, {
363239
+ onRunBound: (id) => {
363240
+ boundRunId = id, armTerminationIntentOnAbort(signal, id);
363241
+ }
363242
+ });
363243
+ if (pendingInterruptedSettledRow !== null) {
363244
+ let settledRowNow = pendingInterruptedSettledRow;
363245
+ pendingInterruptedSettledRow = null, yield apiErrorRow(settledRowNow);
363246
+ }
363247
+ let liveEvents = reattachArmed ? withInteractiveReattach(rawLive, {
362981
363248
  getTaskId: () => boundRunId,
362982
363249
  ...signal ? { signal } : {},
362983
363250
  // 状态行只归**前台主车道**:后台 session(startBackgroundSession 的 ALS 链)与非主车道
@@ -363016,8 +363283,26 @@ Fix: run \`sema doctor\` to diagnose, or restart sema to retry.`
363016
363283
  for await (let ccEvent of sdkMessagesToCcEvents(sdk, { sessionId, uuid: uuid5, signal }))
363017
363284
  yield* flushChromeRows(), trackToolLifecycle(ccEvent), yield ccEvent;
363018
363285
  yield* flushChromeRows();
363019
- let detectedBusy = readBusySignal();
363020
- if (detectedBusy && !signal?.aborted) {
363286
+ let detectedBusy = readBusySignal(), interruptedTaskId = detectedBusy?.activeTaskId ?? null, interruptedShortCircuitSettled = !1;
363287
+ if (detectedBusy && !signal?.aborted && interruptedTaskId !== null && !interruptedResendDone && wasRecentlyTerminatedByUs(interruptedTaskId)) {
363288
+ let verdict = await awaitInterruptedRunSettle(interruptedTaskId, {
363289
+ getRun: durableRunVerbs(client).get,
363290
+ ...signal ? { signal } : {}
363291
+ });
363292
+ if (process.env.SEMA_DEBUG && console.error(
363293
+ `[sema][seamQuery] 409 running on ${interruptedTaskId} \u2014 we terminated it (${String(
363294
+ terminationIntentSource(interruptedTaskId)
363295
+ )}); settle verdict=${verdict.kind}`
363296
+ ), verdict.kind === "settled" && !signal?.aborted) {
363297
+ forgetTerminationIntent(interruptedTaskId), interruptedResendDone = !0, retryStream = !0, pendingInterruptedSettledRow = interruptedRunSettleRow(interruptedTaskId, verdict);
363298
+ continue;
363299
+ }
363300
+ if (verdict.kind === "still-running" && !signal?.aborted) {
363301
+ let row2 = interruptedRunSettleRow(interruptedTaskId, verdict);
363302
+ row2 !== null && (yield apiErrorRow(row2)), interruptedShortCircuitSettled = !0, isMainLaneQuerySource(params.querySource) && trailingStandaloneMetaUserMessages(params.messages).length > 0 && noteInjectionLostWhileHeld();
363303
+ }
363304
+ }
363305
+ if (detectedBusy && !signal?.aborted && !interruptedShortCircuitSettled) {
363021
363306
  let outcome = await attemptActiveRunSelfHeal2(detectedBusy, durableRunVerbs(client), {
363022
363307
  // `hasPendingDecision`(车L 12,原「故意不接」记账销案):真读面 = REPL
363023
363308
  // toolUseConfirmQueue 的模块级长度镜像(leaderPermissionBridge,队列变更 effect
@@ -363187,8 +363472,15 @@ function makeControlRouter(sessionId) {
363187
363472
  async function bestEffortDurableCancel() {
363188
363473
  try {
363189
363474
  let router = getControlRouter();
363190
- if (!router || router.activeTaskId() === null) return;
363191
- await router.cancel();
363475
+ if (!router) return;
363476
+ let taskId = router.activeTaskId();
363477
+ if (taskId === null) return;
363478
+ recordTerminationIntent(taskId, "durable-cancel");
363479
+ try {
363480
+ await router.cancel();
363481
+ } catch (e) {
363482
+ throw forgetTerminationIntent(taskId), e;
363483
+ }
363192
363484
  } catch {
363193
363485
  }
363194
363486
  }
@@ -363221,7 +363513,7 @@ async function cancelEngineRun(taskId) {
363221
363513
  try {
363222
363514
  if (typeof taskId != "string" || taskId.length === 0) return "failed";
363223
363515
  let o = client;
363224
- return typeof o.runs?.cancel != "function" ? "failed" : (await o.runs.cancel(taskId), "cancelled");
363516
+ return typeof o.runs?.cancel != "function" ? "failed" : (await o.runs.cancel(taskId), recordTerminationIntent(taskId, "command-cancel"), "cancelled");
363225
363517
  } catch (e) {
363226
363518
  return e?.errorCode === "conflict.approval_settled" ? "approval_settled" : "failed";
363227
363519
  }
@@ -363370,6 +363662,7 @@ var BG_TEAR_MAX_RESENDS, BG_RECOVERY_WAIT_MS, DRAINING_MAX_RETRIES, drainingBack
363370
363662
  init_engineRuntimeStatus();
363371
363663
  init_activeRunSelfHeal2();
363372
363664
  init_injectionRequeueLatch();
363665
+ init_terminationIntentLedger();
363373
363666
  BG_TEAR_MAX_RESENDS = 2, BG_RECOVERY_WAIT_MS = 12e4, DRAINING_MAX_RETRIES = 3;
363374
363667
  client = makeMockClient(), clientExplicitlySet = !1;
363375
363668
  seamRewindCapture = !0;
@@ -381928,15 +382221,15 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = !1) {
381928
382221
  [addNotification]
381929
382222
  );
381930
382223
  (0, import_react129.useEffect)(() => {
381931
- let ledger = getSessionMcpConfigLedger("session"), cancelled = !1;
382224
+ let ledger2 = getSessionMcpConfigLedger("session"), cancelled = !1;
381932
382225
  async function initializeServersAsPending() {
381933
382226
  let { servers: existingConfigs, errors: mcpErrors } = isStrictMcpConfig ? { servers: {}, errors: [] } : await getClaudeCodeMcpConfigs(dynamicMcpConfig);
381934
382227
  if (cancelled) return;
381935
382228
  let pinned = pinSessionMcpConfigs(
381936
382229
  { ...existingConfigs, ...dynamicMcpConfig },
381937
- ledger
382230
+ ledger2
381938
382231
  ), configs = pinned.configs;
381939
- noticeConfigPinned(pinned), syncSessionMcpRevocations(ledger, configs, isMcpServerDisabled), addErrorsToAppState(setAppState, mcpErrors), setAppState((prevState) => {
382232
+ noticeConfigPinned(pinned), syncSessionMcpRevocations(ledger2, configs, isMcpServerDisabled), addErrorsToAppState(setAppState, mcpErrors), setAppState((prevState) => {
381940
382233
  let { stale, ...mcpWithoutStale } = excludeStalePluginClients(
381941
382234
  prevState.mcp,
381942
382235
  configs,
@@ -381983,7 +382276,7 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = !1) {
381983
382276
  noticeConfigPinned,
381984
382277
  bumpAttemptEpoch
381985
382278
  ]), (0, import_react129.useEffect)(() => {
381986
- let cancelled = !1, ledger = getSessionMcpConfigLedger("session"), claudeaiLedger = getSessionMcpConfigLedger("claudeai");
382279
+ let cancelled = !1, ledger2 = getSessionMcpConfigLedger("session"), claudeaiLedger = getSessionMcpConfigLedger("claudeai");
381987
382280
  async function loadAndConnectMcpConfigs() {
381988
382281
  let claudeaiPromise;
381989
382282
  isStrictMcpConfig || doesEnterpriseMcpConfigExist() ? claudeaiPromise = Promise.resolve({}) : (clearClaudeAIMcpConfigsCache(), claudeaiPromise = fetchClaudeAIMcpConfigsIfEligible());
@@ -381992,9 +382285,9 @@ function useManageMCPConnections(dynamicMcpConfig, isStrictMcpConfig = !1) {
381992
382285
  addErrorsToAppState(setAppState, mcpErrors);
381993
382286
  let pinned = pinSessionMcpConfigs(
381994
382287
  { ...claudeCodeConfigs, ...dynamicMcpConfig },
381995
- ledger
382288
+ ledger2
381996
382289
  ), configs = pinned.configs;
381997
- noticeConfigPinned(pinned), syncSessionMcpRevocations(ledger, configs, isMcpServerDisabled);
382290
+ noticeConfigPinned(pinned), syncSessionMcpRevocations(ledger2, configs, isMcpServerDisabled);
381998
382291
  let enabledConfigs = Object.fromEntries(
381999
382292
  Object.entries(configs).filter(([name]) => !isMcpServerDisabled(name))
382000
382293
  );
@@ -392664,19 +392957,18 @@ var sema_brand_default, init_sema_brand = __esm({
392664
392957
  _doc: "displayName/email \u7559 null = \u8FD0\u884C\u65F6\u56DE\u9000(\u540D\u5B57\u53D6\u672C\u673A OS \u7528\u6237\u540D,\u90AE\u7BB1\u4E0D\u663E\u793A)\u3002\u522B\u70E7\u4E2A\u4EBA\u4FE1\u606F\u8FDB\u54C1\u724C\u6587\u4EF6(F-S1-1:\u65B0\u7528\u6237\u66FE\u770B\u5230 Welcome back Clay!)\u3002"
392665
392958
  },
392666
392959
  whatsNew: {
392667
- version: "1.0.87",
392960
+ version: "1.0.88",
392668
392961
  notes: [
392669
- "Engine restarts now ask first: pressing ctrl+u (or any flow that needs an engine restart) shows a confirmation card before anything stops \u2014 and the card appears in every screen, including transcript, fleet and plugin panels",
392670
- 'Restart messages tell the truth: a crash, a user-requested restart and a config-driven restart each get their own wording instead of one vague "may have crashed" line',
392671
- 'Reasoning effort "xhigh" now persists: it survives restarts and resume instead of silently dropping to a lower level, and JSON-defined agents accept all five effort levels',
392672
- "Model Hub: models you added yourself can now be deleted from the UI, a vision toggle lets self-configured models accept images, and the effort row shows both the requested and the effective value when they differ",
392673
- "MCP panel no longer re-greets servers it already knows after reopening \u2014 approved servers stay approved, removed ones stay gone",
392674
- "Background shell completions show up as they happen instead of waiting for your next message",
392675
- "Saving engine port/bind/read-face settings while attached to an external engine no longer shows a restart banner that could never apply \u2014 the notice now says the setting takes effect on the next local engine start"
392962
+ "Approval cards now show a live countdown to their decision window, with the card turning urgent in the last 60 seconds and withdrawing itself when the window closes \u2014 so a pending approval never silently looks alive after it expired.",
392963
+ "Countdowns only appear on live approvals: when a session re-attaches or resumes, replayed history never fakes a timer (those cards simply show without a countdown, exactly as before).",
392964
+ "When a delegation is refused because all concurrent seats are busy, the transcript now says so and tells you a seat frees up as soon as a sibling agent finishes \u2014 nothing to reconfigure.",
392965
+ "When the retained-window delegation quota is reached, the transcript now points to the actual way forward: continue an existing agent with SendMessage, or wait for old rows to be reaped \u2014 no need to switch sessions.",
392966
+ "Calls to an MCP server that an operator revoked mid-session now explain that the request was never sent and stays refused until the server is approved again.",
392967
+ "Engine updated to server 7.39.0 (core 5.53, including the prompt-cache fix that stops MCP tool refreshes from silently breaking cache reuse every turn)."
392676
392968
  ]
392677
392969
  },
392678
- productVersion: "1.0.87",
392679
- announcement: "sema 1.0.87 \u2014 engine restarts now ask first (ctrl+u confirmation card in every screen), restart messages tell the truth per cause, reasoning effort xhigh persists across restart/resume, and Model Hub gains model delete + vision toggle"
392970
+ productVersion: "1.0.88",
392971
+ announcement: "sema 1.0.88 \u2014 approval cards now show a live countdown to their decision window (live streams only; replayed history never fakes a timer), and delegation/MCP refusals explain the actual next step (wait for a seat, reuse via SendMessage, or re-approve a revoked server)"
392680
392972
  };
392681
392973
  }
392682
392974
  });
@@ -397020,19 +397312,18 @@ var require_sema_brand = __commonJS({
397020
397312
  _doc: "displayName/email \u7559 null = \u8FD0\u884C\u65F6\u56DE\u9000(\u540D\u5B57\u53D6\u672C\u673A OS \u7528\u6237\u540D,\u90AE\u7BB1\u4E0D\u663E\u793A)\u3002\u522B\u70E7\u4E2A\u4EBA\u4FE1\u606F\u8FDB\u54C1\u724C\u6587\u4EF6(F-S1-1:\u65B0\u7528\u6237\u66FE\u770B\u5230 Welcome back Clay!)\u3002"
397021
397313
  },
397022
397314
  whatsNew: {
397023
- version: "1.0.87",
397315
+ version: "1.0.88",
397024
397316
  notes: [
397025
- "Engine restarts now ask first: pressing ctrl+u (or any flow that needs an engine restart) shows a confirmation card before anything stops \u2014 and the card appears in every screen, including transcript, fleet and plugin panels",
397026
- 'Restart messages tell the truth: a crash, a user-requested restart and a config-driven restart each get their own wording instead of one vague "may have crashed" line',
397027
- 'Reasoning effort "xhigh" now persists: it survives restarts and resume instead of silently dropping to a lower level, and JSON-defined agents accept all five effort levels',
397028
- "Model Hub: models you added yourself can now be deleted from the UI, a vision toggle lets self-configured models accept images, and the effort row shows both the requested and the effective value when they differ",
397029
- "MCP panel no longer re-greets servers it already knows after reopening \u2014 approved servers stay approved, removed ones stay gone",
397030
- "Background shell completions show up as they happen instead of waiting for your next message",
397031
- "Saving engine port/bind/read-face settings while attached to an external engine no longer shows a restart banner that could never apply \u2014 the notice now says the setting takes effect on the next local engine start"
397317
+ "Approval cards now show a live countdown to their decision window, with the card turning urgent in the last 60 seconds and withdrawing itself when the window closes \u2014 so a pending approval never silently looks alive after it expired.",
397318
+ "Countdowns only appear on live approvals: when a session re-attaches or resumes, replayed history never fakes a timer (those cards simply show without a countdown, exactly as before).",
397319
+ "When a delegation is refused because all concurrent seats are busy, the transcript now says so and tells you a seat frees up as soon as a sibling agent finishes \u2014 nothing to reconfigure.",
397320
+ "When the retained-window delegation quota is reached, the transcript now points to the actual way forward: continue an existing agent with SendMessage, or wait for old rows to be reaped \u2014 no need to switch sessions.",
397321
+ "Calls to an MCP server that an operator revoked mid-session now explain that the request was never sent and stays refused until the server is approved again.",
397322
+ "Engine updated to server 7.39.0 (core 5.53, including the prompt-cache fix that stops MCP tool refreshes from silently breaking cache reuse every turn)."
397032
397323
  ]
397033
397324
  },
397034
- productVersion: "1.0.87",
397035
- announcement: "sema 1.0.87 \u2014 engine restarts now ask first (ctrl+u confirmation card in every screen), restart messages tell the truth per cause, reasoning effort xhigh persists across restart/resume, and Model Hub gains model delete + vision toggle"
397325
+ productVersion: "1.0.88",
397326
+ announcement: "sema 1.0.88 \u2014 approval cards now show a live countdown to their decision window (live streams only; replayed history never fakes a timer), and delegation/MCP refusals explain the actual next step (wait for a seat, reuse via SendMessage, or re-approve a revoked server)"
397036
397327
  };
397037
397328
  }
397038
397329
  });
@@ -434044,18 +434335,18 @@ function maybeQueueAutoSyncPushAfterTurn() {
434044
434335
  backoffTurnsRemaining--;
434045
434336
  return;
434046
434337
  }
434047
- if (inflight3) {
434338
+ if (inflight2) {
434048
434339
  dirty = !0;
434049
434340
  return;
434050
434341
  }
434051
- inflight3 = runOnce().catch((err8) => {
434342
+ inflight2 = runOnce().catch((err8) => {
434052
434343
  logForDebugging(`sessionAutoSync: unexpected failure: ${err8}`);
434053
434344
  }).finally(() => {
434054
- inflight3 = null, dirty && (dirty = !1, maybeQueueAutoSyncPushAfterTurn());
434345
+ inflight2 = null, dirty && (dirty = !1, maybeQueueAutoSyncPushAfterTurn());
434055
434346
  });
434056
434347
  }
434057
434348
  async function flushAutoSyncQueue() {
434058
- for (; inflight3; ) await inflight3;
434349
+ for (; inflight2; ) await inflight2;
434059
434350
  }
434060
434351
  async function projectAutoSyncEnabled() {
434061
434352
  try {
@@ -434155,16 +434446,16 @@ async function runOnce() {
434155
434446
  }
434156
434447
  }
434157
434448
  function _resetAutoSyncForTests() {
434158
- inflight3 = null, dirty = !1, capsCache.clear(), degradedTargets.clear(), orgMirrorNotified.clear(), consecutiveFailures = 0, latchCount = 0, backoffTurnsRemaining = 0, listener3 = null, pendingEvents2 = [], transportOverride = null;
434449
+ inflight2 = null, dirty = !1, capsCache.clear(), degradedTargets.clear(), orgMirrorNotified.clear(), consecutiveFailures = 0, latchCount = 0, backoffTurnsRemaining = 0, listener3 = null, pendingEvents2 = [], transportOverride = null;
434159
434450
  }
434160
- var AUTO_SYNC_SETTINGS_KEY, TRANSIENT_FAILURE_LATCH, MAX_BACKOFF_TURNS, listener3, pendingEvents2, inflight3, dirty, capsCache, degradedTargets, orgMirrorNotified, consecutiveFailures, latchCount, backoffTurnsRemaining, transportOverride, init_sessionAutoSync = __esm({
434451
+ var AUTO_SYNC_SETTINGS_KEY, TRANSIENT_FAILURE_LATCH, MAX_BACKOFF_TURNS, listener3, pendingEvents2, inflight2, dirty, capsCache, degradedTargets, orgMirrorNotified, consecutiveFailures, latchCount, backoffTurnsRemaining, transportOverride, init_sessionAutoSync = __esm({
434161
434452
  "build-src/src/sema/sessionAutoSync.ts"() {
434162
434453
  init_livePrincipal();
434163
434454
  init_debug();
434164
434455
  init_liveSessionStore();
434165
434456
  init_sessionIdMapping();
434166
434457
  AUTO_SYNC_SETTINGS_KEY = "cloudSessionAutoSync", TRANSIENT_FAILURE_LATCH = 5, MAX_BACKOFF_TURNS = 64, listener3 = null, pendingEvents2 = [];
434167
- inflight3 = null, dirty = !1, capsCache = /* @__PURE__ */ new Map(), degradedTargets = /* @__PURE__ */ new Set(), orgMirrorNotified = /* @__PURE__ */ new Set(), consecutiveFailures = 0, latchCount = 0, backoffTurnsRemaining = 0;
434458
+ inflight2 = null, dirty = !1, capsCache = /* @__PURE__ */ new Map(), degradedTargets = /* @__PURE__ */ new Set(), orgMirrorNotified = /* @__PURE__ */ new Set(), consecutiveFailures = 0, latchCount = 0, backoffTurnsRemaining = 0;
434168
434459
  transportOverride = null;
434169
434460
  }
434170
434461
  });
@@ -434958,6 +435249,57 @@ var ENGINE_BG_SHELL_WATCH_INTERVAL_MS, watchIntervalMs, WATCH_TTL_MS2, outstandi
434958
435249
  }
434959
435250
  });
434960
435251
 
435252
+ // build-src/src/sema/engineToolEndGuidance.ts
435253
+ function toolEndGuidanceRow(errorCode) {
435254
+ if (!(typeof errorCode != "string" || errorCode === "")) {
435255
+ if (errorCode === MCP_SERVER_REVOKED)
435256
+ return "this MCP server was revoked by an operator \u2014 the request was NOT sent, and calls to it keep being refused until it is approved again";
435257
+ switch (delegationCapDispositionOf(errorCode)) {
435258
+ case "wait-for-slot":
435259
+ return "delegation concurrency cap reached \u2014 a seat frees up as soon as a sibling agent finishes; re-sending the same call later will go through (nothing to reconfigure)";
435260
+ case "reuse-existing-or-await-reap":
435261
+ return "delegation seat cap reached for the retained window \u2014 continue an existing agent with SendMessage, or wait for its row to be reaped and the quota comes back (no need to switch sessions or change any setting)";
435262
+ default:
435263
+ break;
435264
+ }
435265
+ if (isDelegationCapCode(errorCode))
435266
+ return `the engine refused this delegation with code "${cleanUntrustedForDisplay(errorCode, MAX_CODE_CHARS)}" \u2014 this build has no guidance for that code yet`;
435267
+ }
435268
+ }
435269
+ function createToolEndGuidanceLane() {
435270
+ let byFrame = /* @__PURE__ */ new Map(), total = 0;
435271
+ return {
435272
+ note(frameNo, frame) {
435273
+ let f = frame;
435274
+ if (f === null || typeof f != "object" || f.type !== "tool_end_result" || typeof f.parentToolCallId == "string" || typeof f.toolCallId != "string" || f.toolCallId === "") return;
435275
+ let row2 = toolEndGuidanceRow(f.errorCode);
435276
+ if (row2 === void 0 || total >= MAX_PENDING_ROWS) return;
435277
+ total++;
435278
+ let bucket = byFrame.get(frameNo);
435279
+ bucket === void 0 ? byFrame.set(frameNo, [row2]) : bucket.push(row2);
435280
+ },
435281
+ flushFrame(frameNo) {
435282
+ let rows2 = byFrame.get(frameNo);
435283
+ if (rows2 !== void 0) {
435284
+ byFrame.delete(frameNo), total -= rows2.length;
435285
+ for (let row2 of rows2) surfaceTranscriptSystemNotice(row2);
435286
+ }
435287
+ },
435288
+ discard() {
435289
+ byFrame.clear(), total = 0;
435290
+ }
435291
+ };
435292
+ }
435293
+ var MAX_CODE_CHARS, MAX_PENDING_ROWS, init_engineToolEndGuidance = __esm({
435294
+ "build-src/src/sema/engineToolEndGuidance.ts"() {
435295
+ init_dist();
435296
+ init_transcriptSystemNotice();
435297
+ init_untrustedDisplayText();
435298
+ MAX_CODE_CHARS = 80;
435299
+ MAX_PENDING_ROWS = 32;
435300
+ }
435301
+ });
435302
+
434961
435303
  // build-src/src/sema/enginePromptSuggestionsStore.ts
434962
435304
  function getEnginePromptSuggestions() {
434963
435305
  return current3;
@@ -435217,10 +435559,7 @@ async function* sdkMessagesToCcEvents(sdk, meta3) {
435217
435559
  // 绝不铸 transcript 行(帧不带正文,替引擎编话=谎),落 debug 审计留痕(「这条 run 被谁插过话」
435218
435560
  // 可查);wire 值 UNTRUSTED,白名单键+控制字符消毒。
435219
435561
  case "human_input": {
435220
- let clean8 = (v2) => (
435221
- // eslint-disable-next-line no-control-regex
435222
- String(v2 ?? "").replace(/[\x00-\x1f\x7f]/g, ".").slice(0, 120)
435223
- ), who = e.actor?.id ? `${clean8(e.actor.id)}${e.actor.hostAsserted === !0 ? "" : " (unverified)"}` : "unattributed";
435562
+ let clean8 = (v2) => cleanUntrustedForDisplay(v2, 120), who = e.actor?.id ? `${clean8(e.actor.id)}${e.actor.hostAsserted === !0 ? "" : " (unverified)"}` : "unattributed";
435224
435563
  return logForDebugging(
435225
435564
  `[sema][bridge] human_input ledger frame (audit): carrier=${clean8(e.carrier)} eventId=${clean8(e.eventId)} by=${who}`
435226
435565
  ), [];
@@ -435255,17 +435594,17 @@ async function* sdkMessagesToCcEvents(sdk, meta3) {
435255
435594
  rowYielded: !1
435256
435595
  });
435257
435596
  }
435258
- let macrotask = () => new Promise((resolve57) => setTimeout(resolve57, 0)), curFrame = null, curFrameType = null, curFrameNo = 0, teed = (async function* () {
435597
+ let macrotask = () => new Promise((resolve57) => setTimeout(resolve57, 0)), curFrame = null, curFrameType = null, curFrameNo = 0, guidanceLane = createToolEndGuidanceLane(), teed = (async function* () {
435259
435598
  for await (let raw2 of sdk) {
435260
435599
  let m2 = raw2;
435261
- curFrame = m2, curFrameType = typeof m2.type == "string" ? m2.type : null, curFrameNo++, observeFrame(m2), recordAgentToolStatsFromFrame(m2), yield raw2;
435600
+ curFrame = m2, curFrameType = typeof m2.type == "string" ? m2.type : null, curFrameNo++, observeFrame(m2), recordAgentToolStatsFromFrame(m2), guidanceLane.note(curFrameNo, m2), yield raw2;
435262
435601
  }
435263
435602
  curFrame = null, curFrameType = null, curFrameNo++;
435264
435603
  })(), seenFrameNo = -1, prevFrameWasStreamEvent = !1, lastOutWasDelta = !1, macrotaskPending = !1;
435265
435604
  noteBridgeDriveStart(), abortInFlightBgShellReads();
435266
435605
  try {
435267
435606
  for await (let out6 of bridgeAdapter().adapt(teed, ctx)) {
435268
- curFrameNo !== seenFrameNo && (seenFrameNo >= 0 && notifEpilogue(seenFrameNo), prevFrameWasStreamEvent && lastOutWasDelta && await macrotask(), seenFrameNo = curFrameNo, prevFrameWasStreamEvent = curFrameType === "stream_event", macrotaskPending = curFrame !== null && curFrameType !== "stream_event", lastOutWasDelta = !1);
435607
+ curFrameNo !== seenFrameNo && (seenFrameNo >= 0 && guidanceLane.flushFrame(seenFrameNo), seenFrameNo >= 0 && notifEpilogue(seenFrameNo), prevFrameWasStreamEvent && lastOutWasDelta && await macrotask(), seenFrameNo = curFrameNo, prevFrameWasStreamEvent = curFrameType === "stream_event", macrotaskPending = curFrame !== null && curFrameType !== "stream_event", lastOutWasDelta = !1);
435269
435608
  let isDelta = out6.plane === "chrome" && out6.event.kind === "stream_delta";
435270
435609
  if (!isDelta && macrotaskPending && (await macrotask(), macrotaskPending = !1), out6.plane === "transcript") {
435271
435610
  let msg = reduceApiErrorEnvelope(out6.message);
@@ -435276,9 +435615,9 @@ async function* sdkMessagesToCcEvents(sdk, meta3) {
435276
435615
  for (let ev of consumeChrome(out6.event)) yield ev;
435277
435616
  lastOutWasDelta = isDelta;
435278
435617
  }
435279
- notifEpilogue(Number.MAX_SAFE_INTEGER);
435618
+ seenFrameNo >= 0 && guidanceLane.flushFrame(seenFrameNo), notifEpilogue(Number.MAX_SAFE_INTEGER);
435280
435619
  } finally {
435281
- noteBridgeDriveEnd();
435620
+ guidanceLane.discard(), noteBridgeDriveEnd();
435282
435621
  }
435283
435622
  }
435284
435623
  var BRIDGE_PROBE_ENV, init_upstreamBridge = __esm({
@@ -435292,6 +435631,7 @@ var BRIDGE_PROBE_ENV, init_upstreamBridge = __esm({
435292
435631
  init_modelVerificationStore();
435293
435632
  init_retryStatusStore();
435294
435633
  init_debug();
435634
+ init_untrustedDisplayText();
435295
435635
  init_thinkingActivityStore();
435296
435636
  init_dist();
435297
435637
  init_engineBgShellPanelStore();
@@ -435306,6 +435646,7 @@ var BRIDGE_PROBE_ENV, init_upstreamBridge = __esm({
435306
435646
  init_xml();
435307
435647
  init_engineTaskListSync();
435308
435648
  init_engineAgentToolStatsStore();
435649
+ init_engineToolEndGuidance();
435309
435650
  init_enginePromptSuggestionsStore();
435310
435651
  init_dist();
435311
435652
  BRIDGE_PROBE_ENV = {
@@ -448415,6 +448756,7 @@ __export(background_agent_store_exports, {
448415
448756
  InMemoryBackgroundAgentStore: () => InMemoryBackgroundAgentStore,
448416
448757
  REVIVED_ROW_CLEARED_FIELDS: () => REVIVED_ROW_CLEARED_FIELDS,
448417
448758
  STALE_RUNNING_REAP_ATTRIBUTION: () => STALE_RUNNING_REAP_ATTRIBUTION,
448759
+ announceTranscriptIntegrityGapOnce: () => announceTranscriptIntegrityGapOnce,
448418
448760
  assertBackgroundAgentReapOptions: () => assertBackgroundAgentReapOptions,
448419
448761
  canAccessAgentRecord: () => canAccessAgentRecord,
448420
448762
  clearRevivedRowTerminalPayload: () => clearRevivedRowTerminalPayload,
@@ -448425,6 +448767,18 @@ function clearRevivedRowTerminalPayload(record2) {
448425
448767
  for (let field of REVIVED_ROW_CLEARED_FIELDS)
448426
448768
  delete record2[field];
448427
448769
  }
448770
+ function announceTranscriptIntegrityGapOnce(handle2, scope, sink2) {
448771
+ if (sink2 === void 0)
448772
+ return;
448773
+ let key = `${scope ?? ""}\0${handle2}`;
448774
+ if (!transcriptIntegrityAnnounced.has(key)) {
448775
+ transcriptIntegrityAnnounced.add(key);
448776
+ try {
448777
+ sink2(handle2, scope);
448778
+ } catch {
448779
+ }
448780
+ }
448781
+ }
448428
448782
  function canAccessAgentRecord(record2, access7) {
448429
448783
  if (access7.scope === void 0 || record2.scope !== access7.scope)
448430
448784
  return !1;
@@ -448516,7 +448870,7 @@ function queryBackgroundAgents(rows2, query2) {
448516
448870
  r.scope === query2.scope && (query2.sessionId !== void 0 && (r.sessionScoped ? r.owner : r.parentSessionId) !== query2.sessionId && r.rootSessionId !== query2.sessionId || query2.status !== void 0 && r.status !== query2.status || out6.push(toSummary(r)));
448517
448871
  return out6.sort((a, b3) => b3.spawnedAt - a.spawnedAt), query2.limit !== void 0 ? out6.slice(0, Math.max(0, query2.limit)) : out6;
448518
448872
  }
448519
- var REVIVED_ROW_CLEARED_FIELDS, BackgroundAgentStoreError, STALE_RUNNING_REAP_ATTRIBUTION, InMemoryBackgroundAgentStore, init_background_agent_store = __esm({
448873
+ var REVIVED_ROW_CLEARED_FIELDS, transcriptIntegrityAnnounced, BackgroundAgentStoreError, STALE_RUNNING_REAP_ATTRIBUTION, InMemoryBackgroundAgentStore, init_background_agent_store = __esm({
448520
448874
  "node_modules/@sema-agent/core/dist/core/background-agent-store.js"() {
448521
448875
  init_harness();
448522
448876
  init_retention_policy();
@@ -448537,6 +448891,7 @@ var REVIVED_ROW_CLEARED_FIELDS, BackgroundAgentStoreError, STALE_RUNNING_REAP_AT
448537
448891
  "editedFiles",
448538
448892
  "usage"
448539
448893
  ];
448894
+ transcriptIntegrityAnnounced = /* @__PURE__ */ new Set();
448540
448895
  BackgroundAgentStoreError = class extends Error {
448541
448896
  code;
448542
448897
  constructor(code2, message) {
@@ -449272,6 +449627,16 @@ var TASK_STOP_PARAMS, init_task_tool_shape = __esm({
449272
449627
 
449273
449628
  // node_modules/@sema-agent/core/dist/core/task-registry-agent.js
449274
449629
  import { randomBytes as randomBytes23 } from "node:crypto";
449630
+ function activeDelegationHandlesLane(core, scope, rootSessionId) {
449631
+ let out6 = [];
449632
+ for (let h of core.handles.values()) {
449633
+ if (h.type !== "background_agent" || h.status !== "running" && h.status !== "pending" || h.scope !== scope)
449634
+ continue;
449635
+ let bh = h;
449636
+ (bh.rootSessionId ?? bh.parentSessionId ?? (bh.sessionScoped ? bh.owner : void 0)) === rootSessionId && out6.push(h.id);
449637
+ }
449638
+ return out6;
449639
+ }
449275
449640
  function ensureDurableHeartbeatLane(core) {
449276
449641
  if (core.durableHeartbeatTimer !== void 0)
449277
449642
  return;
@@ -449386,7 +449751,7 @@ async function reapDurableAgentsLane(core, scope, deps2, policy2) {
449386
449751
  assertRetentionPolicy("reapDurableAgents", policy2);
449387
449752
  let now2 = policy2.now ?? Date.now();
449388
449753
  if (policy2.staleRunningMaxAgeMs !== void 0 && await deps2.store.reap(scope, now2, { staleRunningMaxAgeMs: policy2.staleRunningMaxAgeMs }), policy2.maxAgeMs === void 0 && policy2.keep === void 0)
449389
- return { rowsReaped: 0, sessionsReleased: 0, skippedNoSessions: 0 };
449754
+ return { rowsReaped: 0, sessionsReleased: 0, skippedNoSessions: 0, orphanPlacedReleased: 0 };
449390
449755
  let terminal = (await deps2.store.listByScope(scope)).filter((r) => r.status !== "running" && r.status !== "parked");
449391
449756
  terminal.sort((a, b3) => b3.spawnedAt - a.spawnedAt);
449392
449757
  let doomed = /* @__PURE__ */ new Map();
@@ -449422,7 +449787,12 @@ async function reapDurableAgentsLane(core, scope, deps2, policy2) {
449422
449787
  } catch {
449423
449788
  continue;
449424
449789
  }
449425
- if (rowsReaped++, core.reapedHandles.add(r.handle), deps2.mailbox !== void 0)
449790
+ rowsReaped++;
449791
+ {
449792
+ let staleInProc = core.handles.get(r.handle);
449793
+ staleInProc !== void 0 && staleInProc.status !== "running" && staleInProc.status !== "pending" && staleInProc.status !== "parked" && core.handles.delete(r.handle);
449794
+ }
449795
+ if (core.reapedHandles.add(r.handle), deps2.mailbox !== void 0)
449426
449796
  try {
449427
449797
  await deps2.mailbox.drop(scope, r.handle);
449428
449798
  } catch {
@@ -449436,7 +449806,40 @@ async function reapDurableAgentsLane(core, scope, deps2, policy2) {
449436
449806
  core.reapingHandles.delete(r.handle), core.reapedHandles.delete(r.handle);
449437
449807
  }
449438
449808
  }
449439
- return { rowsReaped, sessionsReleased, skippedNoSessions };
449809
+ let orphanPlacedReleased = 0;
449810
+ if (policy2.maxAgeMs !== void 0 && deps2.sessions !== void 0 && typeof deps2.sessions.listPlaced == "function") {
449811
+ let placed = [];
449812
+ try {
449813
+ placed = await deps2.sessions.listPlaced("subagent", { olderThanMs: policy2.maxAgeMs, scope });
449814
+ } catch {
449815
+ placed = [];
449816
+ }
449817
+ for (let p of placed) {
449818
+ if ("tupleIncomplete" in p || p.scope !== scope || core.claimingHandles.has(p.handle) || core.reapingHandles.has(p.handle))
449819
+ continue;
449820
+ let row2;
449821
+ try {
449822
+ row2 = await deps2.store.get(p.handle, scope);
449823
+ } catch {
449824
+ continue;
449825
+ }
449826
+ if (row2 !== null)
449827
+ continue;
449828
+ let inProc = core.handles.get(p.handle);
449829
+ if (!(inProc !== void 0 && (inProc.status === "running" || inProc.status === "pending" || inProc.status === "parked"))) {
449830
+ try {
449831
+ await deps2.sessions.unpin?.(p.sessionId), await deps2.sessions.release(p.sessionId), orphanPlacedReleased++;
449832
+ } catch {
449833
+ }
449834
+ if (deps2.mailbox !== void 0)
449835
+ try {
449836
+ await deps2.mailbox.drop(scope, p.handle);
449837
+ } catch {
449838
+ }
449839
+ }
449840
+ }
449841
+ }
449842
+ return { rowsReaped, sessionsReleased, skippedNoSessions, orphanPlacedReleased };
449440
449843
  }
449441
449844
  function releaseDurableTranscriptAnchorLane(core, id) {
449442
449845
  let handle2 = core.handles.get(id);
@@ -450019,10 +450422,10 @@ async function deliverToRunningAgentLane(core, id, access7, notification, opts)
450019
450422
  }
450020
450423
  let detachOnTimeout;
450021
450424
  return await bounded(new Promise((resolve57) => {
450022
- let inflight4 = handle2.inFlightDirect ??= /* @__PURE__ */ new Set(), settleOnce = (r) => {
450023
- inflight4.has(settleOnce) && (inflight4.delete(settleOnce), resolve57(r));
450425
+ let inflight3 = handle2.inFlightDirect ??= /* @__PURE__ */ new Set(), settleOnce = (r) => {
450426
+ inflight3.has(settleOnce) && (inflight3.delete(settleOnce), resolve57(r));
450024
450427
  };
450025
- inflight4.add(settleOnce), detachOnTimeout = () => inflight4.delete(settleOnce), (async () => {
450428
+ inflight3.add(settleOnce), detachOnTimeout = () => inflight3.delete(settleOnce), (async () => {
450026
450429
  let result;
450027
450430
  try {
450028
450431
  await handle2.notify?.(notification, opts) === "parked" ? result = handle2.retainedContinuation === !0 ? { ok: !0, disposition: "parked" } : { ok: !1, reason: "not_running" } : result = { ok: !0, disposition: "queued" };
@@ -450190,7 +450593,7 @@ async function stopBackgroundAgentLane(core, handle2) {
450190
450593
  if (arbiter === void 0)
450191
450594
  return {
450192
450595
  content: `${handle2.id} is parked on a pending approval \u2014 stop it by deciding (deny/expire) the pending approval in the durable approval inbox.`,
450193
- details: { task_id: handle2.id, type: "background_agent", status: "parked", retrieval_status: "not_ready", error: "parked_pending_approval" }
450596
+ details: { task_id: handle2.id, type: "background_agent", status: "parked", retrieval_status: "not_ready", error: "parked_pending_approval", code: "parked_pending_approval" }
450194
450597
  };
450195
450598
  let stopWon = !1, arbiterUnreachable = !1;
450196
450599
  try {
@@ -450232,11 +450635,11 @@ async function stopBackgroundAgentLane(core, handle2) {
450232
450635
  }
450233
450636
  return arbiterUnreachable ? {
450234
450637
  content: `${handle2.id} was not stopped: the approval arbitration store was unreachable \u2014 the row stays parked; retry the stop.`,
450235
- details: { task_id: handle2.id, type: "background_agent", status: handle2.status, retrieval_status: "not_ready", error: "park_arbiter_unreachable" },
450638
+ details: { task_id: handle2.id, type: "background_agent", status: handle2.status, retrieval_status: "not_ready", error: "park_arbiter_unreachable", code: "park_arbiter_unreachable" },
450236
450639
  isError: !0
450237
450640
  } : {
450238
450641
  content: `${handle2.id} was not stopped: its pending approval was already consumed (a resume won the arbitration).`,
450239
- details: { task_id: handle2.id, type: "background_agent", status: handle2.status, retrieval_status: "not_ready", error: "park_resume_won" },
450642
+ details: { task_id: handle2.id, type: "background_agent", status: handle2.status, retrieval_status: "not_ready", error: "park_resume_won", code: "park_resume_won" },
450240
450643
  isError: !0
450241
450644
  };
450242
450645
  }
@@ -450474,6 +450877,9 @@ var BLOCK_DEFAULT_TIMEOUT_MS, BLOCK_MAX_TIMEOUT_MS, TASK_PREFIX, TaskRegistry, d
450474
450877
  backgroundAgentCycleSeq(id) {
450475
450878
  return backgroundAgentCycleSeqLane(this.core, id);
450476
450879
  }
450880
+ activeDelegationHandles(scope, rootSessionId) {
450881
+ return activeDelegationHandlesLane(this.core, scope, rootSessionId);
450882
+ }
450477
450883
  reviveBackgroundAgent(id, access7, abort) {
450478
450884
  return reviveBackgroundAgentLane(this.core, id, access7, abort);
450479
450885
  }
@@ -450916,7 +451322,8 @@ The durable record is still marked running (last update ${new Date(row2.updatedA
450916
451322
  type: "background_agent",
450917
451323
  status: "running",
450918
451324
  retrieval_status: "not_ready",
450919
- error: "not_local"
451325
+ error: "not_local",
451326
+ code: "not_local"
450920
451327
  }
450921
451328
  };
450922
451329
  }
@@ -450944,7 +451351,8 @@ The durable record is still marked running (last update ${new Date(row2.updatedA
450944
451351
  type: "workflow",
450945
451352
  status: run2.status,
450946
451353
  retrieval_status: "success",
450947
- error: "not_local"
451354
+ error: "not_local",
451355
+ code: "not_local"
450948
451356
  }
450949
451357
  };
450950
451358
  }
@@ -450963,8 +451371,8 @@ The durable record is still marked running (last update ${new Date(row2.updatedA
450963
451371
  type: "background_agent",
450964
451372
  status: row2.status,
450965
451373
  retrieval_status: row2.status === "parked" ? "not_ready" : "success",
450966
- ...row2.status === "running" ? { error: "not_local" } : {},
450967
- ...row2.status === "parked" ? { error: "parked_pending_approval" } : {}
451374
+ ...row2.status === "running" ? { error: "not_local", code: "not_local" } : {},
451375
+ ...row2.status === "parked" ? { error: "parked_pending_approval", code: "parked_pending_approval" } : {}
450968
451376
  }
450969
451377
  };
450970
451378
  }
@@ -451264,6 +451672,14 @@ var init_image_downsample = __esm({
451264
451672
  }
451265
451673
  });
451266
451674
 
451675
+ // node_modules/@sema-agent/core/dist/core/reminder-disclosure.js
451676
+ var init_reminder_disclosure = __esm({
451677
+ "node_modules/@sema-agent/core/dist/core/reminder-disclosure.js"() {
451678
+ init_reminder_mint();
451679
+ init_untrusted_text();
451680
+ }
451681
+ });
451682
+
451267
451683
  // node_modules/@sema-agent/core/dist/core/memory-engine/content-origin.js
451268
451684
  var init_content_origin = __esm({
451269
451685
  "node_modules/@sema-agent/core/dist/core/memory-engine/content-origin.js"() {
@@ -451291,6 +451707,7 @@ var MCP_PREFIX, MCP_IDLE_TIMEOUT_STDIO_DEFAULT_MS, MCP_IDLE_TIMEOUT_HTTP_DEFAULT
451291
451707
  init_surrogate_safe_slice();
451292
451708
  init_tool_errors();
451293
451709
  init_untrusted_text();
451710
+ init_reminder_disclosure();
451294
451711
  init_content_origin();
451295
451712
  init_strict_output_schema();
451296
451713
  init_protocol_naming();
@@ -451331,6 +451748,7 @@ var init_fs_pdf = __esm({
451331
451748
  init_mcp4();
451332
451749
  init_pdf2();
451333
451750
  init_fs_shared();
451751
+ init_reminder_disclosure();
451334
451752
  init_pdf2();
451335
451753
  }
451336
451754
  });
@@ -451348,6 +451766,7 @@ var init_fs_read = __esm({
451348
451766
  init_fs_shared();
451349
451767
  init_fs_pdf();
451350
451768
  init_reminder_mint();
451769
+ init_reminder_disclosure();
451351
451770
  }
451352
451771
  });
451353
451772
 
@@ -451637,8 +452056,13 @@ function combinePolicies(...policies) {
451637
452056
  let asked, current5 = req, rewrite, settled, ruleAskText;
451638
452057
  for (let p of policies) {
451639
452058
  let d4 = refuseOutOfContractDecision(await p.check(current5, signal));
451640
- if (d4.action === "deny")
451641
- return rewrite?.updatedInput !== void 0 ? { ...d4, updatedInput: rewrite.updatedInput } : d4;
452059
+ if (d4.action === "deny") {
452060
+ if (rewrite?.updatedInput !== void 0) {
452061
+ let out6 = { ...d4, updatedInput: rewrite.updatedInput }, attested = coreMintedResolutions.get(d4);
452062
+ return attested !== void 0 && coreMintedResolutions.set(out6, attested), out6;
452063
+ }
452064
+ return d4;
452065
+ }
451642
452066
  if (d4.updatedInput !== void 0 && (current5 = { ...current5, args: d4.updatedInput }, rewrite = d4), d4.action === "allow") {
451643
452067
  let supplied = d4.settledBy;
451644
452068
  supplied !== void 0 && (settled = supplied);
@@ -451654,7 +452078,7 @@ function combinePolicies(...policies) {
451654
452078
  }
451655
452079
  };
451656
452080
  }
451657
- var DECISION_REASONS, DECISION_REASON_SET, ALLOW, RETIRED_TEXT_FIELD, RETIRED_TEXT_FIELD_DENY_MESSAGE, COARSE_SHELL_TOOLS, CASE_INSENSITIVE_FS, init_tool_policy = __esm({
452081
+ var DECISION_REASONS, DECISION_REASON_SET, ALLOW, RETIRED_TEXT_FIELD, RETIRED_TEXT_FIELD_DENY_MESSAGE, COARSE_SHELL_TOOLS, CASE_INSENSITIVE_FS, ASK_DENY_RESOLUTION_VALUES, ASK_DENY_RESOLUTION_SET, coreMintedResolutions, init_tool_policy = __esm({
451658
452082
  "node_modules/@sema-agent/core/dist/core/tool-policy.js"() {
451659
452083
  init_ask_class();
451660
452084
  init_fs();
@@ -451663,7 +452087,17 @@ var DECISION_REASONS, DECISION_REASON_SET, ALLOW, RETIRED_TEXT_FIELD, RETIRED_TE
451663
452087
  init_permission_rules();
451664
452088
  init_safety();
451665
452089
  DECISION_REASONS = ["rule", "mode", "hook", "safety", "classifier", "persisted_rule", "sandbox", "org_rule", "org_unavailable"], DECISION_REASON_SET = new Set(DECISION_REASONS), ALLOW = { action: "allow" }, RETIRED_TEXT_FIELD = "reason", RETIRED_TEXT_FIELD_DENY_MESSAGE = `a permission decision carries the retired "${RETIRED_TEXT_FIELD}" field \u2014 rename it to "message" (the one text field a decision carries); denied fail-closed rather than executing a decision whose text this layer cannot read`;
451666
- COARSE_SHELL_TOOLS = ["Bash", "Monitor"], CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
452090
+ COARSE_SHELL_TOOLS = ["Bash", "Monitor"], CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32", ASK_DENY_RESOLUTION_VALUES = [
452091
+ "human_refused",
452092
+ "window_expired",
452093
+ "no_approver",
452094
+ "blanket_allow_refused",
452095
+ "approver_unavailable",
452096
+ "task_aborted",
452097
+ "presentation_failed",
452098
+ "approver_error",
452099
+ "approver_contract"
452100
+ ], ASK_DENY_RESOLUTION_SET = new Set(ASK_DENY_RESOLUTION_VALUES), coreMintedResolutions = /* @__PURE__ */ new WeakMap();
451667
452101
  }
451668
452102
  });
451669
452103
 
@@ -451699,6 +452133,28 @@ var init_delegation_provenance = __esm({
451699
452133
  }
451700
452134
  });
451701
452135
 
452136
+ // node_modules/@sema-agent/core/dist/core/memory-engine/types.js
452137
+ var init_types27 = __esm({
452138
+ "node_modules/@sema-agent/core/dist/core/memory-engine/types.js"() {
452139
+ }
452140
+ });
452141
+
452142
+ // node_modules/@sema-agent/core/dist/core/memory-engine/layout.js
452143
+ import { closeSync as closeSync13, constants as fsConstants7, copyFileSync as copyFileSync6, existsSync as existsSync28, fstatSync as fstatSync3, fsyncSync as fsyncSync10, lstatSync as lstatSync4, mkdirSync as mkdirSync22, openSync as openSync14, readFileSync as readFileSync39, readdirSync as readdirSync12, realpathSync as realpathSync11, renameSync as renameSync13, rmSync as rmSync7, rmdirSync as rmdirSync3, statSync as statSync14, unlinkSync as unlinkSync11, writeFileSync as writeFileSync21, writeSync as writeSync7 } from "node:fs";
452144
+ var O_WRONLY, O_CREAT, O_TRUNC, O_NOFOLLOW3, O_EXCL, init_layout = __esm({
452145
+ "node_modules/@sema-agent/core/dist/core/memory-engine/layout.js"() {
452146
+ init_types27();
452147
+ ({ O_WRONLY, O_CREAT, O_TRUNC, O_NOFOLLOW: O_NOFOLLOW3, O_EXCL } = fsConstants7);
452148
+ }
452149
+ });
452150
+
452151
+ // node_modules/@sema-agent/core/dist/core/memory-engine/delegation-settlement.js
452152
+ var init_delegation_settlement = __esm({
452153
+ "node_modules/@sema-agent/core/dist/core/memory-engine/delegation-settlement.js"() {
452154
+ init_layout();
452155
+ }
452156
+ });
452157
+
451702
452158
  // node_modules/@sema-agent/core/dist/core/runner/synthetic-tools.js
451703
452159
  var OUTPUT_TOOL_NAME, REPORT_FINDING_SCHEMA, SKILL_CONTENT_MAX_CHARS, init_synthetic_tools = __esm({
451704
452160
  "node_modules/@sema-agent/core/dist/core/runner/synthetic-tools.js"() {
@@ -451753,21 +452209,6 @@ var WORKTREE_PARENT, init_git_worktree_env = __esm({
451753
452209
  }
451754
452210
  });
451755
452211
 
451756
- // node_modules/@sema-agent/core/dist/core/memory-engine/types.js
451757
- var init_types27 = __esm({
451758
- "node_modules/@sema-agent/core/dist/core/memory-engine/types.js"() {
451759
- }
451760
- });
451761
-
451762
- // node_modules/@sema-agent/core/dist/core/memory-engine/layout.js
451763
- import { closeSync as closeSync13, constants as fsConstants7, copyFileSync as copyFileSync6, existsSync as existsSync28, fstatSync as fstatSync3, fsyncSync as fsyncSync10, lstatSync as lstatSync4, mkdirSync as mkdirSync22, openSync as openSync14, readFileSync as readFileSync39, readdirSync as readdirSync12, realpathSync as realpathSync11, renameSync as renameSync13, rmSync as rmSync7, rmdirSync as rmdirSync3, statSync as statSync14, unlinkSync as unlinkSync11, writeFileSync as writeFileSync21, writeSync as writeSync7 } from "node:fs";
451764
- var O_WRONLY, O_CREAT, O_TRUNC, O_NOFOLLOW3, O_EXCL, init_layout = __esm({
451765
- "node_modules/@sema-agent/core/dist/core/memory-engine/layout.js"() {
451766
- init_types27();
451767
- ({ O_WRONLY, O_CREAT, O_TRUNC, O_NOFOLLOW: O_NOFOLLOW3, O_EXCL } = fsConstants7);
451768
- }
451769
- });
451770
-
451771
452212
  // node_modules/@sema-agent/core/dist/core/memory-engine/scope-contract.js
451772
452213
  var CASE_INSENSITIVE_FS2, FATAL_UTF8, init_scope_contract = __esm({
451773
452214
  "node_modules/@sema-agent/core/dist/core/memory-engine/scope-contract.js"() {
@@ -452044,8 +452485,11 @@ var EXTRA_TOOLS_MAX_FACTORY_CALLS_PER_TREE, EXTRA_TOOLS_BUDGET_NOTE, FAILED_SESS
452044
452485
  "node_modules/@sema-agent/core/dist/agents/subagent.js"() {
452045
452486
  init_build3();
452046
452487
  init_tool_policy();
452488
+ init_tools3();
452047
452489
  init_surrogate_safe_slice();
452048
452490
  init_delegation_provenance();
452491
+ init_delegation_settlement();
452492
+ init_layout();
452049
452493
  init_roles();
452050
452494
  init_synthetic_tools();
452051
452495
  init_tool_disclosure();
@@ -453343,9 +453787,9 @@ var init_reasoning = __esm({
453343
453787
 
453344
453788
  // node_modules/@sema-agent/core/dist/brain/status-sink.js
453345
453789
  import { AsyncLocalStorage as AsyncLocalStorage8 } from "node:async_hooks";
453346
- var statusSinkStore, telemetrySinkStore, init_status_sink = __esm({
453790
+ var statusSinkStore, telemetrySinkStore, reasoningFactsSinkStore, init_status_sink = __esm({
453347
453791
  "node_modules/@sema-agent/core/dist/brain/status-sink.js"() {
453348
- statusSinkStore = new AsyncLocalStorage8(), telemetrySinkStore = new AsyncLocalStorage8();
453792
+ statusSinkStore = new AsyncLocalStorage8(), telemetrySinkStore = new AsyncLocalStorage8(), reasoningFactsSinkStore = new AsyncLocalStorage8();
453349
453793
  }
453350
453794
  });
453351
453795
 
@@ -453538,6 +453982,7 @@ var init_agent_transcript_tool = __esm({
453538
453982
  init_build3();
453539
453983
  init_tools3();
453540
453984
  init_background_agent_store();
453985
+ init_task_registry();
453541
453986
  init_untrusted_text();
453542
453987
  init_subagent_steps();
453543
453988
  init_subagent();
@@ -453559,6 +454004,7 @@ var uplinkSeqGlobal, REVIVE_LEASE_TTL_MS, init_send_message_tool = __esm({
453559
454004
  init_tools3();
453560
454005
  init_task_registry();
453561
454006
  init_background_agent_store();
454007
+ init_harness();
453562
454008
  init_mailbox_store();
453563
454009
  init_observer();
453564
454010
  init_retain_ledger();
@@ -453814,6 +454260,20 @@ var ONE_DAY_MS, ONE_WEEK_MS, ONE_MONTH_MS, init_memory_recall = __esm({
453814
454260
  }
453815
454261
  });
453816
454262
 
454263
+ // node_modules/@sema-agent/core/dist/core/memory-engine/frontmatter.js
454264
+ var init_frontmatter = __esm({
454265
+ "node_modules/@sema-agent/core/dist/core/memory-engine/frontmatter.js"() {
454266
+ init_types27();
454267
+ }
454268
+ });
454269
+
454270
+ // node_modules/@sema-agent/core/dist/core/memory-engine/provenance-wording.js
454271
+ var MEMORY_EXPOSURE_HANDLE_TAG, MEMORY_SEARCH_BAND_ORDER_HEADER, init_provenance_wording = __esm({
454272
+ "node_modules/@sema-agent/core/dist/core/memory-engine/provenance-wording.js"() {
454273
+ MEMORY_EXPOSURE_HANDLE_TAG = "[external-origin]", MEMORY_SEARCH_BAND_ORDER_HEADER = `entries without the ${MEMORY_EXPOSURE_HANDLE_TAG} tag first, best match first within each group`;
454274
+ }
454275
+ });
454276
+
453817
454277
  // node_modules/@sema-agent/core/dist/core/memory-engine/tools.js
453818
454278
  var MEMORY_SEARCH_TOOL_NAME2, MEMORY_GET_TOOL_NAME2, MEMORY_GET_PAGE_CAP_BYTES, SEARCH_HINT, SEARCH_DESCRIPTION, GET_HINT, GET_DESCRIPTION, init_tools5 = __esm({
453819
454279
  "node_modules/@sema-agent/core/dist/core/memory-engine/tools.js"() {
@@ -453821,6 +454281,8 @@ var MEMORY_SEARCH_TOOL_NAME2, MEMORY_GET_TOOL_NAME2, MEMORY_GET_PAGE_CAP_BYTES,
453821
454281
  init_tools3();
453822
454282
  init_untrusted_text();
453823
454283
  init_memory_recall();
454284
+ init_frontmatter();
454285
+ init_provenance_wording();
453824
454286
  MEMORY_SEARCH_TOOL_NAME2 = "memory_search", MEMORY_GET_TOOL_NAME2 = "memory_get", MEMORY_GET_PAGE_CAP_BYTES = 24 * 1024, SEARCH_HINT = "Search this session's long-term memory entries by keyword \u2014 check memory before saying you do not have or do not know something.", SEARCH_DESCRIPTION = [
453825
454287
  SEARCH_HINT,
453826
454288
  "",
@@ -453858,19 +454320,20 @@ var MAX_MEMORY_BYTES, init_memory4 = __esm({
453858
454320
  }
453859
454321
  });
453860
454322
 
453861
- // node_modules/@sema-agent/core/dist/core/memory-engine/frontmatter.js
453862
- var init_frontmatter = __esm({
453863
- "node_modules/@sema-agent/core/dist/core/memory-engine/frontmatter.js"() {
453864
- init_types27();
453865
- }
453866
- });
453867
-
453868
454323
  // node_modules/@sema-agent/core/dist/core/memory-engine/header-hints.js
453869
454324
  var init_header_hints = __esm({
453870
454325
  "node_modules/@sema-agent/core/dist/core/memory-engine/header-hints.js"() {
453871
454326
  }
453872
454327
  });
453873
454328
 
454329
+ // node_modules/@sema-agent/core/dist/core/memory-engine/origin-clearance.js
454330
+ var init_origin_clearance = __esm({
454331
+ "node_modules/@sema-agent/core/dist/core/memory-engine/origin-clearance.js"() {
454332
+ init_layout();
454333
+ init_types27();
454334
+ }
454335
+ });
454336
+
453874
454337
  // node_modules/@sema-agent/core/dist/core/memory-engine/scan.js
453875
454338
  var init_scan = __esm({
453876
454339
  "node_modules/@sema-agent/core/dist/core/memory-engine/scan.js"() {
@@ -453916,7 +454379,7 @@ var init_export_bundle = __esm({
453916
454379
  });
453917
454380
 
453918
454381
  // node_modules/@sema-agent/core/dist/core/memory-engine/engine.js
453919
- var MEMORY_INDEX_MAX_BYTES, init_engine4 = __esm({
454382
+ var MEMORY_INDEX_MAX_BYTES, DEFAULT_HOLD_SETTLE_TIMEOUT_MS, init_engine4 = __esm({
453920
454383
  "node_modules/@sema-agent/core/dist/core/memory-engine/engine.js"() {
453921
454384
  init_harness();
453922
454385
  init_memory4();
@@ -453924,12 +454387,16 @@ var MEMORY_INDEX_MAX_BYTES, init_engine4 = __esm({
453924
454387
  init_reminder_mint();
453925
454388
  init_memory_recall();
453926
454389
  init_frontmatter();
454390
+ init_provenance_wording();
453927
454391
  init_header_hints();
454392
+ init_delegation_settlement();
454393
+ init_delegation_settlement();
454394
+ init_origin_clearance();
453928
454395
  init_file_backend();
453929
454396
  init_export_bundle();
453930
454397
  init_layout();
453931
454398
  init_scan();
453932
- MEMORY_INDEX_MAX_BYTES = 25 * 1024;
454399
+ MEMORY_INDEX_MAX_BYTES = 25 * 1024, DEFAULT_HOLD_SETTLE_TIMEOUT_MS = 4320 * 60 * 1e3;
453933
454400
  }
453934
454401
  });
453935
454402
 
@@ -454323,6 +454790,7 @@ var PROMPT_HASH_SALT, DEFAULT_RESOURCE_TTL_MS, USAGE_WINDOW_REAP_MARGIN_MS, DEFA
454323
454790
  init_engine4();
454324
454791
  init_content_origin();
454325
454792
  init_delegation_provenance();
454793
+ init_delegation_settlement();
454326
454794
  init_memory4();
454327
454795
  init_compliance();
454328
454796
  init_memory_admission();
@@ -454513,6 +454981,7 @@ var DEFAULT_MAX_BYTES, GROUNDING_RATIO_MAX_TEXT_CHARS, GROUNDING_ECHO_MAX_CHARS,
454513
454981
  init_build3();
454514
454982
  init_tools3();
454515
454983
  init_untrusted_text();
454984
+ init_reminder_disclosure();
454516
454985
  init_untrusted_egress();
454517
454986
  init_image();
454518
454987
  init_safety();
@@ -454595,8 +455064,10 @@ var init_repetition = __esm({
454595
455064
  });
454596
455065
 
454597
455066
  // node_modules/@sema-agent/core/dist/core/strategy-store.js
454598
- var init_strategy_store = __esm({
455067
+ var MAX_STRATEGY_TS_FUTURE_MS, init_strategy_store = __esm({
454599
455068
  "node_modules/@sema-agent/core/dist/core/strategy-store.js"() {
455069
+ init_memory_vector();
455070
+ MAX_STRATEGY_TS_FUTURE_MS = 1440 * 60 * 1e3;
454600
455071
  }
454601
455072
  });
454602
455073
 
@@ -454616,6 +455087,8 @@ var init_cumulative_stats = __esm({
454616
455087
  // node_modules/@sema-agent/core/dist/agents/teacher.js
454617
455088
  var init_teacher = __esm({
454618
455089
  "node_modules/@sema-agent/core/dist/agents/teacher.js"() {
455090
+ init_strategy_store();
455091
+ init_safe_notify();
454619
455092
  init_suspend_guard();
454620
455093
  init_tools3();
454621
455094
  init_untrusted_text();
@@ -455104,6 +455577,162 @@ var RESUME_CLAIM_TTL_MS, RESUME_CLAIM_REAP_GRACE_MS, init_workflow_journal_store
455104
455577
  }
455105
455578
  });
455106
455579
 
455580
+ // node_modules/@sema-agent/core/dist/stores/file/background-agent-store.js
455581
+ import { join as join173 } from "node:path";
455582
+ var agentLedgers, FileBackgroundAgentStore, init_background_agent_store2 = __esm({
455583
+ "node_modules/@sema-agent/core/dist/stores/file/background-agent-store.js"() {
455584
+ init_background_agent_store();
455585
+ init_shared_ledger();
455586
+ init_marker();
455587
+ agentLedgers = new SharedLedgerTable({
455588
+ keyOf: (r) => FileBackgroundAgentStore.key(r.handle, r.scope),
455589
+ apply: (rows2, ev) => {
455590
+ if (ev.t === "delete") {
455591
+ rows2.delete(ev.k);
455592
+ return;
455593
+ }
455594
+ rows2.set(ev.k, ev.r);
455595
+ }
455596
+ }), FileBackgroundAgentStore = class _FileBackgroundAgentStore {
455597
+ fsyncEnabled;
455598
+ compactEvery;
455599
+ ledger;
455600
+ closed = !1;
455601
+ get rows() {
455602
+ return this.ledger.rows;
455603
+ }
455604
+ constructor(root2, opts = {}) {
455605
+ assertAdoptionBootGate(root2, "FileBackgroundAgentStore"), this.fsyncEnabled = opts.fsync !== !1, this.compactEvery = opts.compactEvery ?? 1e3;
455606
+ let dir = join173(root2, "background-agents");
455607
+ this.ledger = agentLedgers.acquire({
455608
+ dir,
455609
+ tmpDir: join173(root2, "tmp"),
455610
+ ledgerPath: join173(dir, "agents.jsonl"),
455611
+ snapshotPath: join173(dir, "agents.snapshot.jsonl")
455612
+ });
455613
+ }
455614
+ static key(handle2, scope) {
455615
+ return `${scope}\0${handle2}`;
455616
+ }
455617
+ withLock(key, fn2) {
455618
+ return this.ledger.withLock(key, fn2);
455619
+ }
455620
+ commit(ev) {
455621
+ this.ledger.commit(ev, this.fsyncEnabled, this.compactEvery);
455622
+ }
455623
+ async put(record2) {
455624
+ if (record2.scope === void 0 || record2.scope === "")
455625
+ throw new Error("BackgroundAgentStore.put: refusing a row without a scope (world-readable through the fallback)");
455626
+ let k2 = _FileBackgroundAgentStore.key(record2.handle, record2.scope);
455627
+ return this.withLock(k2, () => {
455628
+ if (this.rows.has(k2))
455629
+ throw new BackgroundAgentStoreError("agent_record.already_exists", "agent record already exists");
455630
+ let stored = structuredClone(record2);
455631
+ stored.rev = record2.rev ?? 0, this.commit({ t: "put", k: k2, r: stored });
455632
+ });
455633
+ }
455634
+ async get(handle2, scope) {
455635
+ let row2 = this.rows.get(_FileBackgroundAgentStore.key(handle2, scope));
455636
+ return row2 ? structuredClone(row2) : null;
455637
+ }
455638
+ async update(handle2, scope, record2, expect) {
455639
+ let k2 = _FileBackgroundAgentStore.key(handle2, scope);
455640
+ return this.withLock(k2, () => {
455641
+ let live = this.rows.get(k2);
455642
+ if (!live || live.scope !== scope || live.rev !== expect.rev)
455643
+ return !1;
455644
+ let stored = structuredClone(record2);
455645
+ return stored.handle = handle2, stored.scope = scope, stored.rev = live.rev + 1, this.commit({ t: "update", k: k2, r: stored }), !0;
455646
+ });
455647
+ }
455648
+ async updateIf(handle2, scope, record2, expect) {
455649
+ let k2 = _FileBackgroundAgentStore.key(handle2, scope);
455650
+ return this.withLock(k2, async () => {
455651
+ let live = this.rows.get(k2);
455652
+ if (!live || live.scope !== scope || live.rev !== expect.rev || expect.status !== void 0 && live.status !== expect.status || expect.parkedCheckpointToken !== void 0 && (expect.parkedCheckpointToken === null ? live.parkedCheckpointToken !== void 0 : live.parkedCheckpointToken !== expect.parkedCheckpointToken) || expect.parkClaimId !== void 0 && (expect.parkClaimId === null ? live.parkClaimId !== void 0 : live.parkClaimId !== expect.parkClaimId))
455653
+ return !1;
455654
+ let stored = structuredClone(record2);
455655
+ return stored.handle = handle2, stored.scope = scope, stored.rev = live.rev + 1, this.commit({ t: "update", k: k2, r: stored }), !0;
455656
+ });
455657
+ }
455658
+ async listBySession(scope, sessionId, opts) {
455659
+ return queryBackgroundAgents(this.rows.values(), { scope, sessionId, status: opts?.status, limit: opts?.limit });
455660
+ }
455661
+ async listByScope(scope, opts) {
455662
+ return queryBackgroundAgents(this.rows.values(), { scope, status: opts?.status, limit: opts?.limit });
455663
+ }
455664
+ async listScopes() {
455665
+ return [...new Set([...this.rows.values()].map((r) => r.scope))].sort();
455666
+ }
455667
+ async delete(handle2, scope, expect) {
455668
+ let k2 = _FileBackgroundAgentStore.key(handle2, scope);
455669
+ return this.withLock(k2, () => {
455670
+ let live = this.rows.get(k2);
455671
+ return !live || expect !== void 0 && live.rev !== expect.rev ? !1 : (this.commit({ t: "delete", k: k2 }), !0);
455672
+ });
455673
+ }
455674
+ async reap(scope, now2, opts) {
455675
+ if (assertBackgroundAgentReapOptions(opts), !opts || opts.maxAgeMs === void 0 && opts.keep === void 0 && opts.staleRunningMaxAgeMs === void 0)
455676
+ return 0;
455677
+ let changed = /* @__PURE__ */ new Set();
455678
+ if (opts.staleRunningMaxAgeMs !== void 0) {
455679
+ let staleCandidates = [...this.rows.entries()].filter(([, r]) => r.scope === scope && r.status === "running" && now2 - r.updatedAt > opts.staleRunningMaxAgeMs).map(([k2]) => k2);
455680
+ for (let k2 of staleCandidates)
455681
+ await this.withLock(k2, () => {
455682
+ let live = this.rows.get(k2);
455683
+ if (!live || live.status !== "running" || now2 - live.updatedAt <= opts.staleRunningMaxAgeMs)
455684
+ return !1;
455685
+ let next = structuredClone(live);
455686
+ return next.status = "failed", next.stoppedBy = "system", next.summary = next.summary ?? STALE_RUNNING_REAP_ATTRIBUTION, next.error = next.error ?? STALE_RUNNING_REAP_ATTRIBUTION, next.settledAt = now2, next.updatedAt = now2, next.rev = live.rev + 1, this.commit({ t: "update", k: k2, r: next }), !0;
455687
+ }) && changed.add(k2);
455688
+ }
455689
+ let terminal = [...this.rows.entries()].filter(([, r]) => r.scope === scope && r.status !== "running" && r.status !== "parked").sort(([, a], [, b3]) => b3.spawnedAt - a.spawnedAt), doomed = /* @__PURE__ */ new Map();
455690
+ if (opts.maxAgeMs !== void 0)
455691
+ for (let [k2, r] of terminal)
455692
+ (r.settledAt ?? r.spawnedAt) < now2 - opts.maxAgeMs && doomed.set(k2, { byAge: !0 });
455693
+ if (opts.keep !== void 0)
455694
+ for (let [k2] of terminal.slice(Math.max(0, opts.keep)))
455695
+ doomed.has(k2) || doomed.set(k2, { byAge: !1 });
455696
+ for (let [k2, why] of doomed)
455697
+ await this.withLock(k2, () => {
455698
+ let live = this.rows.get(k2);
455699
+ return !live || live.scope !== scope || live.status === "running" || live.status === "parked" || why.byAge && opts.maxAgeMs !== void 0 && (live.settledAt ?? live.spawnedAt) >= now2 - opts.maxAgeMs ? !1 : (this.commit({ t: "delete", k: k2 }), !0);
455700
+ }) && changed.add(k2);
455701
+ return changed.size;
455702
+ }
455703
+ compactNow() {
455704
+ this.ledger.compact();
455705
+ }
455706
+ get size() {
455707
+ return this.rows.size;
455708
+ }
455709
+ close() {
455710
+ this.closed || (this.closed = !0, this.ledger.release());
455711
+ }
455712
+ };
455713
+ }
455714
+ });
455715
+
455716
+ // node_modules/@sema-agent/core/dist/stores/file/mailbox-store.js
455717
+ var init_mailbox_store2 = __esm({
455718
+ "node_modules/@sema-agent/core/dist/stores/file/mailbox-store.js"() {
455719
+ init_retention_policy();
455720
+ init_mailbox_store();
455721
+ init_fs_atomic();
455722
+ init_marker();
455723
+ }
455724
+ });
455725
+
455726
+ // node_modules/@sema-agent/core/dist/stores/file/strategy-store.js
455727
+ var STALE_TEMP_MS, init_strategy_store2 = __esm({
455728
+ "node_modules/@sema-agent/core/dist/stores/file/strategy-store.js"() {
455729
+ init_fs_atomic();
455730
+ init_safe_notify();
455731
+ init_strategy_store();
455732
+ STALE_TEMP_MS = 3600 * 1e3;
455733
+ }
455734
+ });
455735
+
455107
455736
  // node_modules/@sema-agent/core/dist/core/permission-rule-sync.js
455108
455737
  var init_permission_rule_sync = __esm({
455109
455738
  "node_modules/@sema-agent/core/dist/core/permission-rule-sync.js"() {
@@ -455115,10 +455744,10 @@ var init_permission_rule_sync = __esm({
455115
455744
 
455116
455745
  // node_modules/@sema-agent/core/dist/stores/file/permission-rule-store.js
455117
455746
  import { closeSync as closeSync15, constants as FS2, existsSync as existsSync30, fsyncSync as fsyncSync12, lstatSync as lstatSync5, mkdirSync as mkdirSync24, openSync as openSync16, readFileSync as readFileSync42, renameSync as renameSync15, unlinkSync as unlinkSync13, writeFileSync as writeFileSync23 } from "node:fs";
455118
- import { join as join173 } from "node:path";
455747
+ import { join as join174 } from "node:path";
455119
455748
  import { createHash as createHash27, randomBytes as randomBytes28 } from "node:crypto";
455120
455749
  function atomicPublish(dir, file2, payload2) {
455121
- let tmp = join173(dir, `.${randomBytes28(8).toString("hex")}.tmp`), fd2;
455750
+ let tmp = join174(dir, `.${randomBytes28(8).toString("hex")}.tmp`), fd2;
455122
455751
  try {
455123
455752
  fd2 = openSync16(tmp, FS2.O_WRONLY | FS2.O_CREAT | FS2.O_EXCL | (FS2.O_NOFOLLOW ?? 0), 384), writeFileSync23(fd2, payload2), fsyncSync12(fd2), closeSync15(fd2), fd2 = void 0, renameSync15(tmp, file2);
455124
455753
  let dfd;
@@ -455365,6 +455994,10 @@ var init_file2 = __esm({
455365
455994
  init_file_snapshot_store2();
455366
455995
  init_workflow_journal_store2();
455367
455996
  init_usage_window_store2();
455997
+ init_background_agent_store2();
455998
+ init_mailbox_store2();
455999
+ init_roster_store();
456000
+ init_strategy_store2();
455368
456001
  init_checkpoint_store2();
455369
456002
  init_memory_store();
455370
456003
  init_session_store2();
@@ -455373,6 +456006,7 @@ var init_file2 = __esm({
455373
456006
  init_file_snapshot_store2();
455374
456007
  init_workflow_journal_store2();
455375
456008
  init_usage_window_store2();
456009
+ init_strategy_store2();
455376
456010
  init_fs_atomic();
455377
456011
  init_fs_atomic();
455378
456012
  init_marker();
@@ -455397,16 +456031,6 @@ var init_fs_write_gate_policy = __esm({
455397
456031
  }
455398
456032
  });
455399
456033
 
455400
- // node_modules/@sema-agent/core/dist/stores/file/mailbox-store.js
455401
- var init_mailbox_store2 = __esm({
455402
- "node_modules/@sema-agent/core/dist/stores/file/mailbox-store.js"() {
455403
- init_retention_policy();
455404
- init_mailbox_store();
455405
- init_fs_atomic();
455406
- init_marker();
455407
- }
455408
- });
455409
-
455410
456034
  // node_modules/@sema-agent/core/dist/stores/file/task-list-store.js
455411
456035
  var init_task_list_store = __esm({
455412
456036
  "node_modules/@sema-agent/core/dist/stores/file/task-list-store.js"() {
@@ -455583,6 +456207,7 @@ var init_memory_engine = __esm({
455583
456207
  "node_modules/@sema-agent/core/dist/core/memory-engine/index.js"() {
455584
456208
  init_engine4();
455585
456209
  init_tools5();
456210
+ init_provenance_wording();
455586
456211
  init_scan();
455587
456212
  init_file_backend();
455588
456213
  init_export_bundle();
@@ -455852,142 +456477,6 @@ var init_background_agent_store_contract = __esm({
455852
456477
  }
455853
456478
  });
455854
456479
 
455855
- // node_modules/@sema-agent/core/dist/stores/file/background-agent-store.js
455856
- import { join as join174 } from "node:path";
455857
- var agentLedgers, FileBackgroundAgentStore, init_background_agent_store2 = __esm({
455858
- "node_modules/@sema-agent/core/dist/stores/file/background-agent-store.js"() {
455859
- init_background_agent_store();
455860
- init_shared_ledger();
455861
- init_marker();
455862
- agentLedgers = new SharedLedgerTable({
455863
- keyOf: (r) => FileBackgroundAgentStore.key(r.handle, r.scope),
455864
- apply: (rows2, ev) => {
455865
- if (ev.t === "delete") {
455866
- rows2.delete(ev.k);
455867
- return;
455868
- }
455869
- rows2.set(ev.k, ev.r);
455870
- }
455871
- }), FileBackgroundAgentStore = class _FileBackgroundAgentStore {
455872
- fsyncEnabled;
455873
- compactEvery;
455874
- ledger;
455875
- closed = !1;
455876
- get rows() {
455877
- return this.ledger.rows;
455878
- }
455879
- constructor(root2, opts = {}) {
455880
- assertAdoptionBootGate(root2, "FileBackgroundAgentStore"), this.fsyncEnabled = opts.fsync !== !1, this.compactEvery = opts.compactEvery ?? 1e3;
455881
- let dir = join174(root2, "background-agents");
455882
- this.ledger = agentLedgers.acquire({
455883
- dir,
455884
- tmpDir: join174(root2, "tmp"),
455885
- ledgerPath: join174(dir, "agents.jsonl"),
455886
- snapshotPath: join174(dir, "agents.snapshot.jsonl")
455887
- });
455888
- }
455889
- static key(handle2, scope) {
455890
- return `${scope}\0${handle2}`;
455891
- }
455892
- withLock(key, fn2) {
455893
- return this.ledger.withLock(key, fn2);
455894
- }
455895
- commit(ev) {
455896
- this.ledger.commit(ev, this.fsyncEnabled, this.compactEvery);
455897
- }
455898
- async put(record2) {
455899
- if (record2.scope === void 0 || record2.scope === "")
455900
- throw new Error("BackgroundAgentStore.put: refusing a row without a scope (world-readable through the fallback)");
455901
- let k2 = _FileBackgroundAgentStore.key(record2.handle, record2.scope);
455902
- return this.withLock(k2, () => {
455903
- if (this.rows.has(k2))
455904
- throw new BackgroundAgentStoreError("agent_record.already_exists", "agent record already exists");
455905
- let stored = structuredClone(record2);
455906
- stored.rev = record2.rev ?? 0, this.commit({ t: "put", k: k2, r: stored });
455907
- });
455908
- }
455909
- async get(handle2, scope) {
455910
- let row2 = this.rows.get(_FileBackgroundAgentStore.key(handle2, scope));
455911
- return row2 ? structuredClone(row2) : null;
455912
- }
455913
- async update(handle2, scope, record2, expect) {
455914
- let k2 = _FileBackgroundAgentStore.key(handle2, scope);
455915
- return this.withLock(k2, () => {
455916
- let live = this.rows.get(k2);
455917
- if (!live || live.scope !== scope || live.rev !== expect.rev)
455918
- return !1;
455919
- let stored = structuredClone(record2);
455920
- return stored.handle = handle2, stored.scope = scope, stored.rev = live.rev + 1, this.commit({ t: "update", k: k2, r: stored }), !0;
455921
- });
455922
- }
455923
- async updateIf(handle2, scope, record2, expect) {
455924
- let k2 = _FileBackgroundAgentStore.key(handle2, scope);
455925
- return this.withLock(k2, async () => {
455926
- let live = this.rows.get(k2);
455927
- if (!live || live.scope !== scope || live.rev !== expect.rev || expect.status !== void 0 && live.status !== expect.status || expect.parkedCheckpointToken !== void 0 && (expect.parkedCheckpointToken === null ? live.parkedCheckpointToken !== void 0 : live.parkedCheckpointToken !== expect.parkedCheckpointToken) || expect.parkClaimId !== void 0 && (expect.parkClaimId === null ? live.parkClaimId !== void 0 : live.parkClaimId !== expect.parkClaimId))
455928
- return !1;
455929
- let stored = structuredClone(record2);
455930
- return stored.handle = handle2, stored.scope = scope, stored.rev = live.rev + 1, this.commit({ t: "update", k: k2, r: stored }), !0;
455931
- });
455932
- }
455933
- async listBySession(scope, sessionId, opts) {
455934
- return queryBackgroundAgents(this.rows.values(), { scope, sessionId, status: opts?.status, limit: opts?.limit });
455935
- }
455936
- async listByScope(scope, opts) {
455937
- return queryBackgroundAgents(this.rows.values(), { scope, status: opts?.status, limit: opts?.limit });
455938
- }
455939
- async listScopes() {
455940
- return [...new Set([...this.rows.values()].map((r) => r.scope))].sort();
455941
- }
455942
- async delete(handle2, scope, expect) {
455943
- let k2 = _FileBackgroundAgentStore.key(handle2, scope);
455944
- return this.withLock(k2, () => {
455945
- let live = this.rows.get(k2);
455946
- return !live || expect !== void 0 && live.rev !== expect.rev ? !1 : (this.commit({ t: "delete", k: k2 }), !0);
455947
- });
455948
- }
455949
- async reap(scope, now2, opts) {
455950
- if (assertBackgroundAgentReapOptions(opts), !opts || opts.maxAgeMs === void 0 && opts.keep === void 0 && opts.staleRunningMaxAgeMs === void 0)
455951
- return 0;
455952
- let changed = /* @__PURE__ */ new Set();
455953
- if (opts.staleRunningMaxAgeMs !== void 0) {
455954
- let staleCandidates = [...this.rows.entries()].filter(([, r]) => r.scope === scope && r.status === "running" && now2 - r.updatedAt > opts.staleRunningMaxAgeMs).map(([k2]) => k2);
455955
- for (let k2 of staleCandidates)
455956
- await this.withLock(k2, () => {
455957
- let live = this.rows.get(k2);
455958
- if (!live || live.status !== "running" || now2 - live.updatedAt <= opts.staleRunningMaxAgeMs)
455959
- return !1;
455960
- let next = structuredClone(live);
455961
- return next.status = "failed", next.stoppedBy = "system", next.summary = next.summary ?? STALE_RUNNING_REAP_ATTRIBUTION, next.error = next.error ?? STALE_RUNNING_REAP_ATTRIBUTION, next.settledAt = now2, next.updatedAt = now2, next.rev = live.rev + 1, this.commit({ t: "update", k: k2, r: next }), !0;
455962
- }) && changed.add(k2);
455963
- }
455964
- let terminal = [...this.rows.entries()].filter(([, r]) => r.scope === scope && r.status !== "running" && r.status !== "parked").sort(([, a], [, b3]) => b3.spawnedAt - a.spawnedAt), doomed = /* @__PURE__ */ new Map();
455965
- if (opts.maxAgeMs !== void 0)
455966
- for (let [k2, r] of terminal)
455967
- (r.settledAt ?? r.spawnedAt) < now2 - opts.maxAgeMs && doomed.set(k2, { byAge: !0 });
455968
- if (opts.keep !== void 0)
455969
- for (let [k2] of terminal.slice(Math.max(0, opts.keep)))
455970
- doomed.has(k2) || doomed.set(k2, { byAge: !1 });
455971
- for (let [k2, why] of doomed)
455972
- await this.withLock(k2, () => {
455973
- let live = this.rows.get(k2);
455974
- return !live || live.scope !== scope || live.status === "running" || live.status === "parked" || why.byAge && opts.maxAgeMs !== void 0 && (live.settledAt ?? live.spawnedAt) >= now2 - opts.maxAgeMs ? !1 : (this.commit({ t: "delete", k: k2 }), !0);
455975
- }) && changed.add(k2);
455976
- return changed.size;
455977
- }
455978
- compactNow() {
455979
- this.ledger.compact();
455980
- }
455981
- get size() {
455982
- return this.rows.size;
455983
- }
455984
- close() {
455985
- this.closed || (this.closed = !0, this.ledger.release());
455986
- }
455987
- };
455988
- }
455989
- });
455990
-
455991
456480
  // node_modules/@sema-agent/core/dist/agents/agent-definition.js
455992
456481
  var init_agent_definition = __esm({
455993
456482
  "node_modules/@sema-agent/core/dist/agents/agent-definition.js"() {
@@ -456187,6 +456676,7 @@ var init_dist10 = __esm({
456187
456676
  init_memory_admission();
456188
456677
  init_retention();
456189
456678
  init_governance_codes();
456679
+ init_governance_codes();
456190
456680
  init_session_store();
456191
456681
  init_session_reconcile();
456192
456682
  init_session4();
@@ -456330,6 +456820,7 @@ var init_dist10 = __esm({
456330
456820
  init_roster_store();
456331
456821
  init_catalog2();
456332
456822
  init_task_registry();
456823
+ init_defaults2();
456333
456824
  init_coordinator();
456334
456825
  init_subagent();
456335
456826
  init_retain_ledger();
@@ -471022,7 +471513,7 @@ function readRestartInflightLine() {
471022
471513
  ${caveat}`, key };
471023
471514
  }
471024
471515
  function EngineRestartConfirm({ onDone }) {
471025
- let upgrade2 = React131.useSyncExternalStore(subscribeUpgradeState, getUpgradeState), kind = upgrade2.phase === "ready" ? upgrade2.kind ?? "update" : "update", [inflight4, setInflight] = React131.useState(() => readRestartInflightLine());
471516
+ let upgrade2 = React131.useSyncExternalStore(subscribeUpgradeState, getUpgradeState), kind = upgrade2.phase === "ready" ? upgrade2.kind ?? "update" : "update", [inflight3, setInflight] = React131.useState(() => readRestartInflightLine());
471026
471517
  React131.useEffect(() => {
471027
471518
  let t2 = setInterval(() => setInflight(readRestartInflightLine()), 1e3);
471028
471519
  return () => clearInterval(t2);
@@ -471036,7 +471527,7 @@ function EngineRestartConfirm({ onDone }) {
471036
471527
  return;
471037
471528
  }
471038
471529
  let atConfirm = readRestartInflightLine();
471039
- if (atConfirm.key !== inflight4.key) {
471530
+ if (atConfirm.key !== inflight3.key) {
471040
471531
  setInflight(atConfirm), setNeedsReconfirm(!0);
471041
471532
  return;
471042
471533
  }
@@ -471053,7 +471544,7 @@ function EngineRestartConfirm({ onDone }) {
471053
471544
  }
471054
471545
  );
471055
471546
  },
471056
- [inflight4.key]
471547
+ [inflight3.key]
471057
471548
  ), options = [
471058
471549
  {
471059
471550
  label: needsReconfirm ? "Yes, restart anyway" : "Yes, restart the engine now",
@@ -471069,9 +471560,9 @@ function EngineRestartConfirm({ onDone }) {
471069
471560
  return /* @__PURE__ */ (0, import_jsx_runtime372.jsx)(PermissionDialog, { title: "Restart engine to apply?", children: /* @__PURE__ */ (0, import_jsx_runtime372.jsxs)(ThemedBox_default, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
471070
471561
  /* @__PURE__ */ (0, import_jsx_runtime372.jsxs)(ThemedBox_default, { marginBottom: 1, flexDirection: "column", children: [
471071
471562
  /* @__PURE__ */ (0, import_jsx_runtime372.jsx)(ThemedText, { children: restartConfirmSubtitle(kind) }),
471072
- inflight4.line !== null ? /* @__PURE__ */ (0, import_jsx_runtime372.jsxs)(import_jsx_runtime372.Fragment, { children: [
471563
+ inflight3.line !== null ? /* @__PURE__ */ (0, import_jsx_runtime372.jsxs)(import_jsx_runtime372.Fragment, { children: [
471073
471564
  /* @__PURE__ */ (0, import_jsx_runtime372.jsx)(ThemedText, { children: " " }),
471074
- /* @__PURE__ */ (0, import_jsx_runtime372.jsx)(ThemedText, { color: "warning", children: inflight4.line })
471565
+ /* @__PURE__ */ (0, import_jsx_runtime372.jsx)(ThemedText, { color: "warning", children: inflight3.line })
471075
471566
  ] }) : null,
471076
471567
  needsReconfirm ? /* @__PURE__ */ (0, import_jsx_runtime372.jsxs)(import_jsx_runtime372.Fragment, { children: [
471077
471568
  /* @__PURE__ */ (0, import_jsx_runtime372.jsx)(ThemedText, { children: " " }),
@@ -478006,6 +478497,9 @@ function askCountdownRow(remainingMs) {
478006
478497
  let total = Math.ceil(remainingMs / 1e3), m2 = Math.floor(total / 60), s = total % 60;
478007
478498
  return `This approval window closes in ${m2 > 0 ? `${String(m2)}m ${String(s).padStart(2, "0")}s` : `${String(s)}s`} \u2014 after that the engine's own policy takes over`;
478008
478499
  }
478500
+ function askCountdownIsUrgent(remainingMs) {
478501
+ return !Number.isFinite(remainingMs) || remainingMs <= 0 ? !1 : remainingMs <= ASK_COUNTDOWN_URGENT_MS;
478502
+ }
478009
478503
  function askRetractionRow(cause, toolName2) {
478010
478504
  let what = `the approval request for "${toolName2}"`;
478011
478505
  switch (cause) {
@@ -478019,9 +478513,10 @@ function askRetractionRow(cause, toolName2) {
478019
478513
  return `sema: ${what} was taken down (${cause}). Nothing was decided on your behalf here.`;
478020
478514
  }
478021
478515
  }
478022
- var ABSOLUTE_KEYS, RECEIVED_AT_KEYS, SERVER_NOW_KEYS, RELATIVE_MS_KEYS, RELATIVE_SEC_KEYS, init_askWindowCountdown = __esm({
478516
+ var ABSOLUTE_KEYS, RECEIVED_AT_KEYS, SERVER_NOW_KEYS, RELATIVE_MS_KEYS, RELATIVE_SEC_KEYS, ASK_COUNTDOWN_URGENT_MS, init_askWindowCountdown = __esm({
478023
478517
  "build-src/src/sema/askWindowCountdown.ts"() {
478024
478518
  ABSOLUTE_KEYS = ["expiresAtMs", "expiresAt", "askExpiresAt", "deadlineAt", "windowEndsAt"], RECEIVED_AT_KEYS = ["receivedAtMs"], SERVER_NOW_KEYS = ["serverNowMs", "serverTimeMs"], RELATIVE_MS_KEYS = ["expiresInMs", "askWindowMs", "windowMs", "ttlMs"], RELATIVE_SEC_KEYS = ["expiresInSec", "askWindowSec", "windowSec", "ttlSec", "ttlSeconds"];
478519
+ ASK_COUNTDOWN_URGENT_MS = 6e4;
478025
478520
  }
478026
478521
  });
478027
478522
 
@@ -478039,8 +478534,10 @@ function AskWindowCountdownRow({
478039
478534
  alive = !1, t2 !== void 0 && clearTimeout(t2);
478040
478535
  };
478041
478536
  }, [expiresAtMs]), expiresAtMs === void 0) return null;
478042
- let row2 = askCountdownRow(expiresAtMs - now2);
478043
- return row2 === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(ThemedBox_default, { paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(ThemedText, { dimColor: !0, children: row2 }) });
478537
+ let remainingMs = expiresAtMs - now2, row2 = askCountdownRow(remainingMs);
478538
+ if (row2 === void 0) return null;
478539
+ let urgent = askCountdownIsUrgent(remainingMs);
478540
+ return /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(ThemedBox_default, { paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(ThemedText, { dimColor: !urgent, color: urgent ? "warning" : void 0, children: row2 }) });
478044
478541
  }
478045
478542
  var React143, import_jsx_runtime404, init_AskWindowCountdownRow = __esm({
478046
478543
  "build-src/src/components/permissions/AskWindowCountdownRow.tsx"() {
@@ -498361,7 +498858,7 @@ function _temp158() {
498361
498858
  }
498362
498859
  var import_compiler_runtime308, import_react313, SETTINGS_ERRORS_NOTIFICATION_KEY, init_useSettingsErrors = __esm({
498363
498860
  "build-src/src/hooks/notifs/useSettingsErrors.tsx"() {
498364
- import_compiler_runtime308 = __toESM(require_compiler_runtime(), 1), import_react313 = __toESM(require_react(), 1);
498861
+ import_compiler_runtime308 = __toESM(require_compiler_runtime()), import_react313 = __toESM(require_react());
498365
498862
  init_notifications2();
498366
498863
  init_state();
498367
498864
  init_allErrors();
@@ -512086,11 +512583,15 @@ function shellApprovalCardPort(req) {
512086
512583
  // ⇒ 整键缺席 ⇒ 卡形与修前逐字节相同。绝不拿 #175 那个 300s 硬编码上去 —— 那是 server
512087
512584
  // 侧随部署可改的旋钮,壳抄一份等于渲一个看起来精确、实际与引擎无关的数字(见
512088
512585
  // askWindowCountdown.ts 的缺席纪律段)。
512089
- // ✅ 供给按车道分:design/172 v1 呈卡帧的 **live `tasks/stream` 腿**窗三键端到端在场 ⇒
512090
- // 这条腿上 `askDeadlineMs` 真解出来、倒计时行与到点撤卡 timer 真起来(见下方 `askDeadlineMs
512091
- // !== undefined` 分支);durable 重放腿 / 旧族 `tool_approval` 帧腿 / durable park 腿三处
512092
- // 仍无窗位供给 ⇒ 那三条腿上这一位仍恒缺席、卡形逐字节不变(逐腿点名见
512093
- // askWindowCountdown.ts 头注「车道覆盖」段)。
512586
+ // ✅ 供给按车道分(1.0.88 更新:旧族帧腿由「整腿无窗」改为「按装配点分」):
512587
+ // · design/172 v1 呈卡帧的 **live `tasks/stream` 腿**窗三键端到端在场 ⇒ 这条腿上
512588
+ // `askDeadlineMs` 真解出来、倒计时行与到点撤卡 timer 真起来(见下方
512589
+ // `askDeadlineMs !== undefined` 分支);
512590
+ // · **旧族 `tool_approval` 帧腿**自 client-core 0.39.0 + 壳 `liveClient.makeHitlDeps` 接线起
512591
+ // **同样按腿有窗**:live 装配点声明 `windowIsCurrent: true` ⇒ 有窗;durable 装配点与
512592
+ // park→decide 续流 ⇒ 闸落 ⇒ 无窗;
512593
+ // · durable 重放腿 / durable park 腿仍无窗位供给 ⇒ 那两条腿上这一位仍恒缺席、卡形逐字节不变。
512594
+ // 逐腿点名与证据见 askWindowCountdown.ts 头注「车道覆盖」段(唯一台账,别在这里抄第二份)。
512094
512595
  ...askDeadlineMs !== void 0 ? { askExpiresAtMs: askDeadlineMs } : {},
512095
512596
  permissionPromptStartTimeMs: Date.now(),
512096
512597
  onUserInteraction() {
@@ -512302,9 +512803,30 @@ function frameSaysExpired(frame) {
512302
512803
  let at = frame.expiresAtMs, srvNow = frame.serverNowMs;
512303
512804
  return typeof at == "number" && Number.isFinite(at) && typeof srvNow == "number" && Number.isFinite(srvNow) ? at <= srvNow : !1;
512304
512805
  }
512806
+ function readCoherentEnvelopeWindow(env6) {
512807
+ let inMs = env6.expiresInMs, at = env6.expiresAtMs, srvNow = env6.serverNowMs;
512808
+ if (typeof inMs != "number" || !Number.isFinite(inMs) || typeof at != "number" || !Number.isFinite(at) || typeof srvNow != "number" || !Number.isFinite(srvNow) || at <= 0 || srvNow <= 0) return;
512809
+ let expected = Math.max(0, at - srvNow);
512810
+ if (!(Math.abs(inMs - expected) > ENVELOPE_WINDOW_COHERENCE_TOLERANCE_MS))
512811
+ return { expiresInMs: inMs, expiresAtMs: at, serverNowMs: srvNow };
512812
+ }
512813
+ function envelopeWindowSaysExpired(w2) {
512814
+ return w2.expiresInMs <= 0 && w2.expiresAtMs <= w2.serverNowMs;
512815
+ }
512305
512816
  function askCallKey(askId) {
512306
512817
  return askGateQuestionId(askId);
512307
512818
  }
512819
+ function windowKeysFrom(frame, opts) {
512820
+ return opts.windowIsCurrent !== !0 ? {} : {
512821
+ // 🔴 帧**到手**的本地时刻(调用点在任何 await 之前盖的)。读口拿它当本地锚点,
512822
+ // 否则能力位探测(≤1.5s)与 legacy 收尾宽限(750ms)会被**还回**服务端的窗里,
512823
+ // 卡在真实 deadline 之后仍可点(复审)。
512824
+ ...typeof opts.receivedAtMs == "number" && Number.isFinite(opts.receivedAtMs) ? { receivedAtMs: opts.receivedAtMs } : {},
512825
+ ...typeof frame.expiresInMs == "number" && Number.isFinite(frame.expiresInMs) ? { expiresInMs: frame.expiresInMs } : {},
512826
+ ...typeof frame.expiresAtMs == "number" && Number.isFinite(frame.expiresAtMs) ? { expiresAtMs: frame.expiresAtMs } : {},
512827
+ ...typeof frame.serverNowMs == "number" && Number.isFinite(frame.serverNowMs) ? { serverNowMs: frame.serverNowMs } : {}
512828
+ };
512829
+ }
512308
512830
  function approvalCardRequestFrom(frame, opts) {
512309
512831
  let card = frame.card, notes = [riskNoteFor(card.risk)];
512310
512832
  card.argsOmitted === !0 && notes.push("arguments omitted by the engine (over the 16 KiB cap) \u2014 this does NOT mean the call has no arguments");
@@ -512328,23 +512850,9 @@ function approvalCardRequestFrom(frame, opts) {
512328
512850
  ...card.delegation !== void 0 ? { delegation: card.delegation } : {},
512329
512851
  ...card.ruleSuggestions !== void 0 && card.ruleSuggestions.length > 0 ? { ruleSuggestions: card.ruleSuggestions } : {},
512330
512852
  ...card.fromSubagent === !0 && typeof card.sourceAgentName == "string" && card.sourceAgentName !== "" ? { workerBadge: { name: cleanForDisplay(card.sourceAgentName, 60), color: "suggestion" } } : {},
512331
- // 窗三键原样转出([4297] Q2,见函数头注)。
512332
- // 🔴 逐键**在场才 stamp**:类型面写的是必填,但 wire 是开集、老 worker 可能不发,而
512333
- // 「缺席 ⇒ 不渲倒计时」正是这一批的成文降级路径 —— 照必填读法合成一个 0 出来会让每张卡
512334
- // 当场自撤。
512335
- // 🔴 `windowIsCurrent !== true` ⇒ 三键**整族不转**(复审实撞):账本重放的历史帧
512336
- // 带的是铸帧时刻的旧余量,拿它算「本地 now + 余量」等于给一只早就过期的 ask 续一个新窗
512337
- // (卡复活、倒计时从头走、到点撤卡被推迟)。新旧在帧里读不出来 —— 只有装配点知道自己接的
512338
- // 是哪条腿,所以判据在那里,而这里的缺省选「不渲」那一边。
512339
- ...opts.windowIsCurrent === !0 ? {
512340
- // 🔴 帧**到手**的本地时刻(调用点在任何 await 之前盖的)。读口拿它当本地锚点,
512341
- // 否则能力位探测(≤1.5s)与 legacy 收尾宽限(750ms)会被**还回**服务端的窗里,
512342
- // 卡在真实 deadline 之后仍可点(复审)。
512343
- ...typeof opts.receivedAtMs == "number" && Number.isFinite(opts.receivedAtMs) ? { receivedAtMs: opts.receivedAtMs } : {},
512344
- ...typeof frame.expiresInMs == "number" && Number.isFinite(frame.expiresInMs) ? { expiresInMs: frame.expiresInMs } : {},
512345
- ...typeof frame.expiresAtMs == "number" && Number.isFinite(frame.expiresAtMs) ? { expiresAtMs: frame.expiresAtMs } : {},
512346
- ...typeof frame.serverNowMs == "number" && Number.isFinite(frame.serverNowMs) ? { serverNowMs: frame.serverNowMs } : {}
512347
- } : {}
512853
+ // 窗三键原样转出([4297] Q2,见函数头注)——投影判据单源在 `windowKeysFrom`(通用卡腿共用
512854
+ // 同一口;两腿各抄一份就是同形存量)。
512855
+ ...windowKeysFrom(frame, opts)
512348
512856
  };
512349
512857
  }
512350
512858
  function genericCardRequestFrom(env6, askId, opts) {
@@ -512356,7 +512864,14 @@ function genericCardRequestFrom(env6, askId, opts) {
512356
512864
  args: typeof card.args == "object" && card.args !== null ? card.args : {},
512357
512865
  callKey: askCallKey(askId),
512358
512866
  ...opts.signal !== void 0 ? { signal: opts.signal } : {},
512359
- wireNote: notes.join(" \xB7 ")
512867
+ wireNote: notes.join(" \xB7 "),
512868
+ // 窗三键(见函数头注)——**先验自洽再投影**;验不过 ⇒ 整族不转(连本地锚点 `receivedAtMs` 都不盖:
512869
+ // 一个没有窗的卡上留个孤零零的锚点只会让下一棒以为这里有窗)⇒ 卡形与修前逐字节相同。
512870
+ // 投影口本身与 v1 腿同源(`windowKeysFrom`:新鲜度门 / 逐键在场 / 本地锚点三条纪律不重写一遍)。
512871
+ ...(() => {
512872
+ let w2 = readCoherentEnvelopeWindow(env6);
512873
+ return w2 === void 0 ? {} : windowKeysFrom(w2, opts);
512874
+ })()
512360
512875
  };
512361
512876
  }
512362
512877
  function defaultNotify(text2) {
@@ -512396,10 +512911,10 @@ async function* consumeStreamApprovalFrames(events3, deps2, opts = {}) {
512396
512911
  "a stream-approval frame arrived while this worker reports streamApproval=false (stale read / failed probe / genuine disagreement \u2014 indistinguishable here). Servicing it anyway: forwarding it downstream would DROP it, and this frame may be the only carrier of a pending card."
512397
512912
  ), !0;
512398
512913
  }
512399
- let card = deps2.surfaceCard ?? surfaceApprovalCard, notify5 = deps2.notify ?? defaultNotify, surfaceNote = deps2.surfaceDecisionNote ?? defaultSurfaceDecisionNote, legacyClaimed = /* @__PURE__ */ new Set(), legacySettled = /* @__PURE__ */ new Set(), handled = /* @__PURE__ */ new Set(), live = /* @__PURE__ */ new Map(), inflight4 = /* @__PURE__ */ new Set(), torn = !1, track2 = (p) => {
512914
+ let card = deps2.surfaceCard ?? surfaceApprovalCard, notify5 = deps2.notify ?? defaultNotify, surfaceNote = deps2.surfaceDecisionNote ?? defaultSurfaceDecisionNote, legacyClaimed = /* @__PURE__ */ new Set(), legacySettled = /* @__PURE__ */ new Set(), handled = /* @__PURE__ */ new Set(), live = /* @__PURE__ */ new Map(), inflight3 = /* @__PURE__ */ new Set(), torn = !1, track2 = (p) => {
512400
512915
  let guarded = p.catch(() => {
512401
512916
  });
512402
- inflight4.add(guarded), guarded.finally(() => inflight4.delete(guarded));
512917
+ inflight3.add(guarded), guarded.finally(() => inflight3.delete(guarded));
512403
512918
  };
512404
512919
  try {
512405
512920
  for await (let ev of events3) {
@@ -512430,8 +512945,8 @@ async function* consumeStreamApprovalFrames(events3, deps2, opts = {}) {
512430
512945
  } finally {
512431
512946
  torn = !0;
512432
512947
  for (let c2 of live.values()) c2.abort.abort();
512433
- live.clear(), inflight4.size > 0 && await Promise.race([
512434
- Promise.allSettled([...inflight4]),
512948
+ live.clear(), inflight3.size > 0 && await Promise.race([
512949
+ Promise.allSettled([...inflight3]),
512435
512950
  new Promise((r) => setTimeout(r, TEARDOWN_BUDGET_MS))
512436
512951
  ]);
512437
512952
  }
@@ -512463,7 +512978,8 @@ async function* consumeStreamApprovalFrames(events3, deps2, opts = {}) {
512463
512978
  `approval_request ask=${cleanForDisplay(askId, 64)}: the legacy leg saw approvalId=${cleanForDisplay(approvalId, 64)} but never settled it (wrong replica / dropped connection is exactly this path) \u2014 running the durable CAS route`
512464
512979
  );
512465
512980
  }
512466
- if (v1 !== void 0 && frameSaysExpired(v1)) {
512981
+ let envWindow = v1 === void 0 ? readCoherentEnvelopeWindow(raw2) : void 0;
512982
+ if (v1 !== void 0 ? frameSaysExpired(v1) : envWindow !== void 0 && envelopeWindowSaysExpired(envWindow)) {
512467
512983
  release2(), logging(
512468
512984
  `approval_request ask=${cleanForDisplay(askId, 64)} arrived already expired per its own window (expiresInMs=0 / expiresAtMs<=serverNowMs) \u2014 no card is raised (a card that can only ever return 404 is worse than no card)`
512469
512985
  );
@@ -512484,7 +513000,14 @@ async function* consumeStreamApprovalFrames(events3, deps2, opts = {}) {
512484
513000
  // 复审:本地锚点取**帧到手**那一刻(下面 await 掉的时间不还给窗)。
512485
513001
  receivedAtMs
512486
513002
  })
512487
- ) : await card(genericCardRequestFrom(raw2, askId, { signal: abort.signal }));
513003
+ ) : await card(
513004
+ genericCardRequestFrom(raw2, askId, {
513005
+ signal: abort.signal,
513006
+ // #324 件①:窗三键是信封级的 ⇒ 未知 card 形照样有窗。判据与 v1 腿逐字同源。
513007
+ windowIsCurrent: opts.windowIsCurrent === !0,
513008
+ receivedAtMs
513009
+ })
513010
+ );
512488
513011
  } catch (e) {
512489
513012
  logForDebugging(`[sema][wire] stream-approval card raise failed (fail-soft, engine window still governs): ${String(e)}`);
512490
513013
  return;
@@ -512642,7 +513165,7 @@ async function* consumeStreamApprovalFrames(events3, deps2, opts = {}) {
512642
513165
  logForDebugging(`[sema][wire] ${line}`);
512643
513166
  }
512644
513167
  }
512645
- var STREAM_APPROVAL_CAP, ASK_DECISION_DISABLED_CODE, IDEMPOTENCY_KEY_MAX, PARKING_POLL_MAX, PARKING_POLL_DELAY_MS, CAPS_SETTLE_BUDGET_MS, LEGACY_SETTLE_GRACE_MS, MAX_DECISION_NOTE_CHARS, TEARDOWN_BUDGET_MS, TYPED_NAME_TO_KIND, NOTICE_KEY2, init_approvalStreamWire = __esm({
513168
+ var STREAM_APPROVAL_CAP, ASK_DECISION_DISABLED_CODE, IDEMPOTENCY_KEY_MAX, PARKING_POLL_MAX, PARKING_POLL_DELAY_MS, CAPS_SETTLE_BUDGET_MS, LEGACY_SETTLE_GRACE_MS, MAX_DECISION_NOTE_CHARS, TEARDOWN_BUDGET_MS, TYPED_NAME_TO_KIND, ENVELOPE_WINDOW_COHERENCE_TOLERANCE_MS, NOTICE_KEY2, init_approvalStreamWire = __esm({
512646
513169
  "build-src/src/sema/approvalStreamWire.ts"() {
512647
513170
  init_dist();
512648
513171
  init_debug();
@@ -512660,6 +513183,7 @@ var STREAM_APPROVAL_CAP, ASK_DECISION_DISABLED_CODE, IDEMPOTENCY_KEY_MAX, PARKIN
512660
513183
  ["AskParkingError", "parking"],
512661
513184
  ["FeatureDisabledError", "ask-lane-disabled"]
512662
513185
  ]);
513186
+ ENVELOPE_WINDOW_COHERENCE_TOLERANCE_MS = 1e3;
512663
513187
  NOTICE_KEY2 = "stream-approval";
512664
513188
  }
512665
513189
  });
@@ -513298,33 +513822,40 @@ function createLiveConversationClient(config4) {
513298
513822
  }
513299
513823
  );
513300
513824
  return body.persistRule !== void 0 && surfaceRulePersistOutcome(ack), ack;
513301
- }, baseUrlTrimmed = config4.baseUrl.replace(/\/+$/, ""), hitlDeps = {
513302
- client: client3,
513303
- // 🔴 续流也要经登记级(对抗复审轮4 H3 实撞)**与流内审批级**(1.0.74 终扫 P2-2/P2-3):
513304
- // HITL 桥在 park→decide 之后把内部流**换成**这条 `runsEvents` 的返回值 —— 只包住最初的
513305
- // source 等于漏掉整条续流。台账级漏 = 子代若在批准之后才起、或首个 tick 落在续流里,
513306
- // 详情面的「继续」入口被永久藏起来;审批级漏 = park 之后续流上到达的 approval_request /
513307
- // approval_revoke 帧无人消费(投影器只有 dropped 一条路)。两层组合收在
513308
- // composeHitlContinuationEvents(与主管道同序同参数形,台账取舍见其头注)。
513309
- // 这里的 run id 是**本次 attach 的 taskId**,天然流局部。
513310
- runsEvents: (taskId, opts) => (
513311
- // session 与**这次 attach 实际发出去的那个值**同源(下面 spread 的同一次求值),不是逐帧现读。
513312
- ((sessionSpread) => composeHitlContinuationEvents(client3.runs.events(taskId, { ...opts, ...sessionSpread }), {
513825
+ }, baseUrlTrimmed = config4.baseUrl.replace(/\/+$/, ""), makeHitlDeps = (lane) => {
513826
+ let windowIsCurrent = lane.windowIsCurrent;
513827
+ return {
513828
+ client: client3,
513829
+ // 🔴 续流也要经登记级(对抗复审轮4 H3 实撞)**与流内审批级**(1.0.74 终扫 P2-2/P2-3):
513830
+ // HITL 桥在 park→decide 之后把内部流**换成**这条 `runsEvents` 的返回值 —— 只包住最初的
513831
+ // source 等于漏掉整条续流。台账级漏 = 子代若在批准之后才起、或首个 tick 落在续流里,
513832
+ // 详情面的「继续」入口被永久藏起来;审批级漏 = park 之后续流上到达的 approval_request /
513833
+ // approval_revoke 帧无人消费(投影器只有 dropped 一条路)。两层组合收在
513834
+ // composeHitlContinuationEvents(与主管道同序同参数形,台账取舍见其头注)。
513835
+ // 这里的 run id 是**本次 attach 的 taskId**,天然流局部。
513836
+ runsEvents: (taskId, opts) => (windowIsCurrent = !1, ((sessionSpread) => composeHitlContinuationEvents(client3.runs.events(taskId, { ...opts, ...sessionSpread }), {
513313
513837
  taskId,
513314
513838
  ownerSessionId: sessionSpread.session,
513315
513839
  approvalDeps: approvalStreamDeps,
513316
513840
  ...opts?.signal ? { signal: opts.signal } : {}
513317
- }))(engineSessionParamSpread())
513318
- ),
513319
- respondToolApproval,
513320
- // #229 respond-note 供给链(A-029.12 件3):帧腿车道参数 —— 包编排层的 note 门读
513321
- // `approvalDecisionNoteCapable`,缺席 = fail-closed 到「不发」侧,note 在 cli 恒死件。
513322
- // 供给 = caps 缓存的 `approvalDecisionNote` 位(server ≥7.15.0 硬编码 true 的版本探测位;
513323
- // per-call 真值归 ack.noteRecorded,A-029.9 消费面另批)。getter 按**读取时刻**取值:
513324
- // caps 探测是 boot 期 fire-and-forget 的,构造时 stamp 布尔会把「探测在飞」冻成永久 false。
513325
- get approvalLane() {
513326
- return { approvalDecisionNoteCapable: engineCapTrue(config4.baseUrl, "approvalDecisionNote") };
513327
- }
513841
+ }))(engineSessionParamSpread())),
513842
+ respondToolApproval,
513843
+ // #229 respond-note 供给链(A-029.12 件3):帧腿车道参数 —— 包编排层的 note 门读
513844
+ // `approvalDecisionNoteCapable`,缺席 = fail-closed 到「不发」侧,note 在 cli 恒死件。
513845
+ // 供给 = caps 缓存的 `approvalDecisionNote` 位(server ≥7.15.0 硬编码 true 的版本探测位;
513846
+ // per-call 真值归 ack.noteRecorded,A-029.9 消费面另批)。getter 按**读取时刻**取值:
513847
+ // caps 探测是 boot 期 fire-and-forget 的,构造时 stamp 布尔会把「探测在飞」冻成永久 false。
513848
+ // 🔴 `windowIsCurrent` 同理必须走 getter:闩是在 `runsEvents` 里落的,构造时 stamp 布尔
513849
+ // 等于把开流那一刻的值冻死,续流之后照旧过境三键(= 没修)。
513850
+ get approvalLane() {
513851
+ return {
513852
+ approvalDecisionNoteCapable: engineCapTrue(config4.baseUrl, "approvalDecisionNote"),
513853
+ // 🔴 只在真为 live 时**显式**声明;false 也如实写出去(包侧 `!== true` 读法两者等价,
513854
+ // 但显式 false 让「这条腿判过了」在 diff 与 census 上可见,不与「忘了传」同形)。
513855
+ windowIsCurrent
513856
+ };
513857
+ }
513858
+ };
513328
513859
  }, approvalStreamDeps = {
513329
513860
  decide: {
513330
513861
  // C4([3777] 第 5 层):传输层失败退避重试。**幂等键复用是这条腿的全部前提** —— `body`
@@ -513437,7 +513968,10 @@ function createLiveConversationClient(config4) {
513437
513968
  }
513438
513969
  )
513439
513970
  ),
513440
- hitlDeps,
513971
+ // legacy `tool_approval` 帧腿的车道:**live 装配点** ⇒ 窗三键过境(归属判据与上面
513972
+ // 孪生族那一位同源,逐条见 makeHitlDeps 头注)。park→decide 续流上的重放帧由工厂
513973
+ // 内那枚每流闩自动降位,不靠这里第二次判断。
513974
+ makeHitlDeps({ windowIsCurrent: !0 }),
513441
513975
  {
513442
513976
  ...opts?.signal ? { signal: opts.signal } : {}
513443
513977
  }
@@ -513486,7 +514020,10 @@ function createLiveConversationClient(config4) {
513486
514020
  { ...opts?.signal ? { signal: opts.signal } : {} }
513487
514021
  )
513488
514022
  ),
513489
- hitlDeps,
514023
+ // legacy `tool_approval` 帧腿的车道:**durable 重放装配点** ⇒ 窗三键**不**过境。
514024
+ // 与上面 `consumeStreamApprovalFrames` 在本腿刻意不传同名 opt 是同一条判据的两半
514025
+ // (孪生族与包腿同口径);这里写显式 `false` 而不是省略,好让「判过了」可见。
514026
+ makeHitlDeps({ windowIsCurrent: !1 }),
513490
514027
  {
513491
514028
  taskId,
513492
514029
  ...opts?.signal ? { signal: opts.signal } : {}
@@ -514284,6 +514821,7 @@ async function* ask(params) {
514284
514821
  }), finalResultText, lastAssistantUuid = "", markedInflight = !!process.env.SEMA_LIVE_BASEURL;
514285
514822
  markedInflight && markTurnInflight();
514286
514823
  try {
514824
+ let emittedNoticeKeys = /* @__PURE__ */ new Set();
514287
514825
  for await (let msg of sdk) {
514288
514826
  if (signal?.aborted) break;
514289
514827
  let t2 = msg.type;
@@ -514294,16 +514832,32 @@ async function* ask(params) {
514294
514832
  }
514295
514833
  if (!(t2 === "retry_status" || t2 === "turn_usage" || t2 === "task_progress" || t2 === "steering_injected")) {
514296
514834
  if (t2 === "human_input") {
514297
- let hi = msg, clean8 = (v2) => (
514298
- // eslint-disable-next-line no-control-regex
514299
- String(v2 ?? "").replace(/[\x00-\x1f\x7f]/g, ".").slice(0, 120)
514300
- ), who = hi.actor?.id ? `${clean8(hi.actor.id)}${hi.actor.hostAsserted === !0 ? "" : " (unverified)"}` : "unattributed";
514835
+ let hi = msg, clean8 = (v2) => cleanUntrustedForDisplay(v2, 120), who = hi.actor?.id ? `${clean8(hi.actor.id)}${hi.actor.hostAsserted === !0 ? "" : " (unverified)"}` : "unattributed";
514301
514836
  logForDebugging(
514302
514837
  `[sema][print] human_input ledger frame (audit): carrier=${clean8(hi.carrier)} eventId=${clean8(hi.eventId)} by=${who}`
514303
514838
  );
514304
514839
  continue;
514305
514840
  }
514306
514841
  if (!(t2 === "diagnostics" || t2 === "workspace_changed")) {
514842
+ if (t2 === "engine_notice") {
514843
+ let en2 = msg, clean8 = (v2) => cleanUntrustedForDisplay(v2, 160), detailText = "";
514844
+ try {
514845
+ detailText = en2.detail === void 0 ? "" : cleanUntrustedForDisplay(JSON.stringify(en2.detail), 400);
514846
+ } catch {
514847
+ detailText = "(unserializable)";
514848
+ }
514849
+ logForDebugging(
514850
+ `[sema][print] engine_notice swallowed (audit; no stdout parity frame \u2014 see [4429]/#302): code=${clean8(en2.code)} eventId=${clean8(en2.eventId)} eventSeq=${clean8(en2.eventSeq)} ts=${clean8(en2.ts)} sessionId=${clean8(en2.sessionId)} message=${clean8(en2.message)} detail=${detailText}`
514851
+ );
514852
+ let noticeKey = `${clean8(en2.eventId)}|${clean8(en2.eventSeq)}|${clean8(en2.code)}`;
514853
+ if (!emittedNoticeKeys.has(noticeKey)) {
514854
+ emittedNoticeKeys.add(noticeKey);
514855
+ let msgPart = en2.message === void 0 ? "" : ` \u2014 ${clean8(en2.message)}`;
514856
+ process.stderr.write(`[sema] engine notice: ${clean8(en2.code)}${msgPart}
514857
+ `);
514858
+ }
514859
+ continue;
514860
+ }
514307
514861
  if (t2 === "prompt_suggestions") {
514308
514862
  let list = msg.suggestions;
514309
514863
  if (Array.isArray(list)) {
@@ -514490,6 +515044,7 @@ var client2, clientExplicitlySet2, printNotifiedKeys, init_seamQueryEngine = __e
514490
515044
  init_dist();
514491
515045
  init_deferSessionExemption();
514492
515046
  init_debug();
515047
+ init_untrustedDisplayText();
514493
515048
  init_dist();
514494
515049
  init_dist();
514495
515050
  init_dist();
@@ -528176,8 +528731,7 @@ function ModelHubBody({
528176
528731
  }
528177
528732
  rr.renamedTo && (renamed = rr.renamedTo);
528178
528733
  }
528179
- renamed && requestEngineConfigRespawn().catch(() => {
528180
- }), nav2.pop();
528734
+ renamed && pendingRestartLaneAvailable() && notePendingEngineRestart("config", "catalog"), nav2.pop();
528181
528735
  }
528182
528736
  }),
528183
528737
  () => readEdit?.() ?? null,
@@ -528320,7 +528874,7 @@ var React192, import_jsx_runtime504, clampShown, hostOf5, SUPPORTED_CHANNELS, AD
528320
528874
  init_modelCtxOverride();
528321
528875
  init_modelChannels();
528322
528876
  init_rosterStore();
528323
- init_engineEndpointSwap();
528877
+ init_engineUpgradeCoordinator();
528324
528878
  init_tierStore();
528325
528879
  init_KeybindingContext();
528326
528880
  init_catalogScreens();
@@ -531749,7 +532303,7 @@ Usage: sema --remote "your task description"`, () => gracefulShutdown(1));
531749
532303
  pendingHookMessages
531750
532304
  }, renderAndRun);
531751
532305
  }
531752
- }).version("sema 1.0.87", "-v, --version", "Output the version number"), program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)"), program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux."), canUserConfigureAdvisor() && program2.addOption(new Option("--advisor <model>", "Enable the server-side advisor tool with the specified model (alias or full ID).").hideHelp()), program2.addOption(new Option("--bg, --background", "Start the session as a background agent and return immediately (manage with `sema agents`)")), program2.command("ps").description("List background sessions").action(async () => {
532306
+ }).version("sema 1.0.88", "-v, --version", "Output the version number"), program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)"), program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux."), canUserConfigureAdvisor() && program2.addOption(new Option("--advisor <model>", "Enable the server-side advisor tool with the specified model (alias or full ID).").hideHelp()), program2.addOption(new Option("--bg, --background", "Start the session as a background agent and return immediately (manage with `sema agents`)")), program2.command("ps").description("List background sessions").action(async () => {
531753
532307
  await (await Promise.resolve().then(() => (init_bg2(), bg_exports))).psHandler([]), process.exit(process.exitCode ?? 0);
531754
532308
  }), program2.command("logs [id]").description("Print a background session's recent terminal output").action(async (id) => {
531755
532309
  await (await Promise.resolve().then(() => (init_bg2(), bg_exports))).logsHandler(id, []), process.exit(process.exitCode ?? 0);
@@ -532825,9 +533379,6 @@ var React202, import_jsx_runtime517, ALL_INTERFACES_BIND_HOST, init_BindHostFiel
532825
533379
  // build-src/src/sema/config/EngineScreen.tsx
532826
533380
  import { readFileSync as readFileSync61 } from "node:fs";
532827
533381
  import { join as join211 } from "node:path";
532828
- function localEngineLane() {
532829
- return !process.env.SEMA_LIVE_BASEURL && process.env.SEMA_TOC_ENGINE !== "0";
532830
- }
532831
533382
  function settingsEnv2() {
532832
533383
  try {
532833
533384
  let sj = JSON.parse(
@@ -532873,7 +533424,7 @@ function portEditScreen() {
532873
533424
  return;
532874
533425
  }
532875
533426
  let err8 = applyEnginePort(p);
532876
- !err8 && localEngineLane() && notePendingEngineRestart("config"), saveNotice = err8 ? `failed to save port: ${err8.message}` : localEngineLane() ? `port ${p} saved to settings.json \u2014 the open session shows an engine-restart banner \u2014 press ctrl+u there to apply` : `port ${p} saved to settings.json \u2014 takes effect the next time a local engine is spawned (this session is attached to an external engine or engine autostart is off)`;
533427
+ !err8 && pendingRestartLaneAvailable() && notePendingEngineRestart("config"), saveNotice = err8 ? `failed to save port: ${err8.message}` : pendingRestartLaneAvailable() ? `port ${p} saved to settings.json \u2014 the open session shows an engine-restart banner \u2014 press ctrl+u there to apply` : `port ${p} saved to settings.json \u2014 takes effect the next time a local engine is spawned (this session is not managing a local engine \u2014 attached to an external one, autostart off, or run as a standalone config command)`;
532877
533428
  }
532878
533429
  });
532879
533430
  }
@@ -532888,7 +533439,7 @@ function bindHostEditScreen() {
532888
533439
  current: configuredBindHost().host,
532889
533440
  onSubmit: (host) => {
532890
533441
  let err8 = applyEngineBindHost(host);
532891
- !err8 && localEngineLane() && notePendingEngineRestart("config"), saveNotice = err8 ? `failed to save bind address: ${err8.message}` : host === null ? localEngineLane() ? `bind address back to default ${DEFAULT_BIND_HOST} (key removed from settings.json) \u2014 the open session shows an engine-restart banner \u2014 press ctrl+u there to apply` : `bind address back to default ${DEFAULT_BIND_HOST} (key removed from settings.json) \u2014 takes effect the next time a local engine is spawned (this session is attached to an external engine or engine autostart is off)` : localEngineLane() ? `bind address ${host} saved to settings.json \u2014 the open session shows an engine-restart banner \u2014 press ctrl+u there to apply` : `bind address ${host} saved to settings.json \u2014 takes effect the next time a local engine is spawned (this session is attached to an external engine or engine autostart is off)`, nav.pop();
533442
+ !err8 && pendingRestartLaneAvailable() && notePendingEngineRestart("config"), saveNotice = err8 ? `failed to save bind address: ${err8.message}` : host === null ? pendingRestartLaneAvailable() ? `bind address back to default ${DEFAULT_BIND_HOST} (key removed from settings.json) \u2014 the open session shows an engine-restart banner \u2014 press ctrl+u there to apply` : `bind address back to default ${DEFAULT_BIND_HOST} (key removed from settings.json) \u2014 takes effect the next time a local engine is spawned (this session is not managing a local engine \u2014 attached to an external one, autostart off, or run as a standalone config command)` : pendingRestartLaneAvailable() ? `bind address ${host} saved to settings.json \u2014 the open session shows an engine-restart banner \u2014 press ctrl+u there to apply` : `bind address ${host} saved to settings.json \u2014 takes effect the next time a local engine is spawned (this session is not managing a local engine \u2014 attached to an external one, autostart off, or run as a standalone config command)`, nav.pop();
532892
533443
  }
532893
533444
  }
532894
533445
  )
@@ -532933,7 +533484,7 @@ function readFaceEditScreen() {
532933
533484
  return;
532934
533485
  }
532935
533486
  let effective = configuredEngineReadFace(getClaudeConfigHomeDir());
532936
- effective.face === face && localEngineLane() && notePendingEngineRestart("config"), saveNotice = effective.face !== face ? `read face ${face} saved to settings.json \u2014 but the READ_FACE environment variable (${effective.face}) overrides it, so the engine stays "${effective.face}". Unset READ_FACE and relaunch sema to let this setting take effect.` : face === "open" ? localEngineLane() ? "read face back to default open \u2014 the whole filesystem is readable (key removed from settings.json); the open session shows an engine-restart banner \u2014 press ctrl+u there to apply" : "read face back to default open (key removed from settings.json) \u2014 takes effect the next time a local engine is spawned (this session is attached to an external engine or engine autostart is off)" : localEngineLane() ? "read face roots saved to settings.json \u2014 the engine reads only the workspace root plus declared read-only roots; the open session shows an engine-restart banner \u2014 press ctrl+u there to apply" : "read face roots saved to settings.json \u2014 takes effect the next time a local engine is spawned (this session is attached to an external engine or engine autostart is off)", nav.pop();
533487
+ effective.face === face && pendingRestartLaneAvailable() && notePendingEngineRestart("config"), saveNotice = effective.face !== face ? `read face ${face} saved to settings.json \u2014 but the READ_FACE environment variable (${effective.face}) overrides it, so the engine stays "${effective.face}". Unset READ_FACE and relaunch sema to let this setting take effect.` : face === "open" ? pendingRestartLaneAvailable() ? "read face back to default open \u2014 the whole filesystem is readable (key removed from settings.json); the open session shows an engine-restart banner \u2014 press ctrl+u there to apply" : "read face back to default open (key removed from settings.json) \u2014 takes effect the next time a local engine is spawned (this session is not managing a local engine \u2014 attached to an external one, autostart off, or run as a standalone config command)" : pendingRestartLaneAvailable() ? "read face roots saved to settings.json \u2014 the engine reads only the workspace root plus declared read-only roots; the open session shows an engine-restart banner \u2014 press ctrl+u there to apply" : "read face roots saved to settings.json \u2014 takes effect the next time a local engine is spawned (this session is not managing a local engine \u2014 attached to an external one, autostart off, or run as a standalone config command)", nav.pop();
532937
533488
  }
532938
533489
  }
532939
533490
  )
@@ -534054,11 +534605,11 @@ function wrapWorkflowDetailWithLiveActivity(base, opts) {
534054
534605
  ensureWorkflowActivityLedger(opts);
534055
534606
  let baseSubscribe = base.subscribe?.bind(base);
534056
534607
  function mergeSnapshot(snap) {
534057
- let ledger = readWorkflowActivityLedger(opts.workflowId);
534058
- if (!snap || !ledger || ledger.byCallKey.size === 0 && ledger.byLabel.size === 0) return snap;
534608
+ let ledger2 = readWorkflowActivityLedger(opts.workflowId);
534609
+ if (!snap || !ledger2 || ledger2.byCallKey.size === 0 && ledger2.byLabel.size === 0) return snap;
534059
534610
  let touched = !1, phases = snap.phases.map((ph) => {
534060
534611
  let agents3 = ph.agents.map((a) => {
534061
- let acc = a.callKey !== void 0 ? ledger.byCallKey.get(a.callKey) : a.label ? ledger.byLabel.get(a.label) : void 0;
534612
+ let acc = a.callKey !== void 0 ? ledger2.byCallKey.get(a.callKey) : a.label ? ledger2.byLabel.get(a.label) : void 0;
534062
534613
  if (!acc) return a;
534063
534614
  let patch2 = {};
534064
534615
  return a.toolCalls == null && acc.toolCalls > 0 && (patch2.toolCalls = acc.toolCalls), (a.activity == null || a.activity.length === 0) && acc.activity.length > 0 && (patch2.activity = acc.activity, acc.lastToolName !== void 0 && a.lastToolName == null && (patch2.lastToolName = acc.lastToolName, acc.lastToolSummary !== void 0 && (patch2.lastToolSummary = acc.lastToolSummary))), a.model == null && acc.requestedModel !== void 0 && (patch2.model = acc.requestedModel), a.fallbackModel == null && acc.resolvedModel !== void 0 && (patch2.fallbackModel = acc.resolvedModel), acc.lastProgressAt !== void 0 && (a.lastProgressAt == null || acc.lastProgressAt > a.lastProgressAt) && (patch2.lastProgressAt = acc.lastProgressAt), Object.keys(patch2).length === 0 ? a : (touched = !0, { ...a, ...patch2 });
@@ -536664,9 +537215,9 @@ var IDLE_EXIT_MS, DISPATCH_SCAN_MS, DAEMON_LOG_ROTATE_BYTES, ADOPTED_SWEEP_MS, C
536664
537215
  let seen2 = this.seenNonces.get(nonce);
536665
537216
  if (seen2) return seen2;
536666
537217
  }
536667
- let keys2 = [`short:${job.short}`, ...nonce ? [`nonce:${nonce}`] : []], inflight4 = keys2.map((k2) => this.inflightDispatches.get(k2)).find(Boolean);
536668
- if (inflight4) {
536669
- let outcome = await inflight4;
537218
+ let keys2 = [`short:${job.short}`, ...nonce ? [`nonce:${nonce}`] : []], inflight3 = keys2.map((k2) => this.inflightDispatches.get(k2)).find(Boolean);
537219
+ if (inflight3) {
537220
+ let outcome = await inflight3;
536670
537221
  return nonce && this.seenNonces.set(nonce, outcome), outcome;
536671
537222
  }
536672
537223
  let flight = (async () => {
@@ -537800,6 +538351,16 @@ async function launchReplProduction() {
537800
538351
  } catch {
537801
538352
  }
537802
538353
  })(), engineHealthLoop = startHealthCheckLoop2(instance2, (reason) => {
538354
+ if (reason === "configDriftResolved") {
538355
+ (async () => {
538356
+ try {
538357
+ let { retractHeartbeatConfigPending: retractHeartbeatConfigPending2 } = await Promise.resolve().then(() => (init_engineUpgradeCoordinator(), engineUpgradeCoordinator_exports));
538358
+ retractHeartbeatConfigPending2();
538359
+ } catch {
538360
+ }
538361
+ })();
538362
+ return;
538363
+ }
537803
538364
  if (reason !== "configDrift" && reason !== "versionDrift") {
537804
538365
  console.error(`[sema] local engine ${reason} \u2014 auto-restarting (limited retries), session preserved`), (async () => {
537805
538366
  try {
@@ -537814,7 +538375,10 @@ async function launchReplProduction() {
537814
538375
  (async () => {
537815
538376
  try {
537816
538377
  let { notePendingEngineRestart: notePendingEngineRestart2 } = await Promise.resolve().then(() => (init_engineUpgradeCoordinator(), engineUpgradeCoordinator_exports));
537817
- notePendingEngineRestart2(reason === "configDrift" ? "config" : "update");
538378
+ notePendingEngineRestart2(
538379
+ reason === "configDrift" ? "config" : "update",
538380
+ reason === "configDrift" ? "heartbeat-config" : "heartbeat-version"
538381
+ );
537818
538382
  } catch {
537819
538383
  }
537820
538384
  })();
@@ -537855,31 +538419,6 @@ async function launchReplProduction() {
537855
538419
  });
537856
538420
  } catch {
537857
538421
  }
537858
- try {
537859
- let { registerEngineConfigRespawn: registerEngineConfigRespawn2 } = await Promise.resolve().then(() => (init_engineEndpointSwap(), engineEndpointSwap_exports));
537860
- registerEngineConfigRespawn2(async () => {
537861
- engineHealthLoop?.stop();
537862
- let rr = await respawnOnConfigDrift2(currentEngineInstance);
537863
- if (!(rr.baseUrl && rr.instance))
537864
- return console.error(`[sema] /model endpoint respawn failed (${rr.reason ?? "unknown"}) \u2014 REPL stays up`), !1;
537865
- let { createLiveConversationClient: createLiveConversationClient2 } = await Promise.resolve().then(() => (init_liveClient(), liveClient_exports)), { setSeamClient: setSeamClient2 } = await Promise.resolve().then(() => (init_seamQuery(), seamQuery_exports)), { setQueryEngineClient: setQueryEngineClient2 } = await Promise.resolve().then(() => (init_seamQueryEngine(), seamQueryEngine_exports)), { resolveLiveAuthToken: resolveLiveAuthToken2 } = await Promise.resolve().then(() => (init_engineTarget(), engineTarget_exports)), swapClient = createLiveConversationClient2({
537866
- baseUrl: rr.baseUrl,
537867
- authToken: resolveLiveAuthToken2(rr.baseUrl),
537868
- // #118:同上,零 'anon' 占位符
537869
- principal: resolveLivePrincipal(),
537870
- afterEngineRespawn: !0
537871
- // 同上:换端点的温切也是换进程,caps 必须对新引擎重探
537872
- });
537873
- setSeamClient2(swapClient), setQueryEngineClient2(swapClient), installEngineHealthLoop(rr.instance);
537874
- try {
537875
- let { noteEngineReplacedExternally: noteEngineReplacedExternally2 } = await Promise.resolve().then(() => (init_engineUpgradeCoordinator(), engineUpgradeCoordinator_exports));
537876
- noteEngineReplacedExternally2();
537877
- } catch {
537878
- }
537879
- return console.error(`[sema] engine respawned onto the picked model's endpoint at ${rr.baseUrl} \u2014 session intact`), !0;
537880
- });
537881
- } catch {
537882
- }
537883
538422
  try {
537884
538423
  let { initEngineUpgradeCoordinator: initEngineUpgradeCoordinator2 } = await Promise.resolve().then(() => (init_engineUpgradeCoordinator(), engineUpgradeCoordinator_exports)), { resolveEngineEntry: resolveEngineEntry2, respawnOnConfigDrift: warmRespawn, getServiceAuthToken: tokenAfterRespawn } = await Promise.resolve().then(() => (init_engineLifecycleManager(), engineLifecycleManager_exports)), entry = resolveEngineEntry2(), entryFile = entry?.args[entry.args.length - 1];
537885
538424
  entryFile && initEngineUpgradeCoordinator2({