oasis_test_v2 2.2.23 → 2.2.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1138 -909
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -4370,19 +4370,19 @@ var init_state = __esm({
4370
4370
  reviewMap = /* @__PURE__ */ new Map();
4371
4371
  mutationList = [];
4372
4372
  emittedList = [];
4373
- constructor(snapshot) {
4374
- this.workorder = { ...snapshot.workorder };
4375
- for (const n of snapshot.nodes) this.nodeMap.set(n.id, { ...n });
4376
- this.edgeList = snapshot.edges.map((e) => ({ ...e }));
4377
- this.requirementList = snapshot.requirements.map((r) => ({ ...r }));
4378
- for (const w2 of snapshot.works) this.workMap.set(w2.id, { ...w2 });
4379
- this.artifactList = snapshot.artifacts.map((a) => ({ ...a }));
4380
- this.workInputList = snapshot.workInputs.map((i) => ({ ...i }));
4381
- for (const i of snapshot.issues) this.issueMap.set(i.id, { ...i });
4382
- this.recipientList = snapshot.issueRecipients.map((r) => ({ ...r }));
4383
- this.replyList = snapshot.issueReplies.map((r) => ({ ...r }));
4384
- this.attachmentList = snapshot.issueAttachments.map((a) => ({ ...a }));
4385
- for (const r of snapshot.reviews) this.reviewMap.set(r.id, { ...r });
4373
+ constructor(snapshot2) {
4374
+ this.workorder = { ...snapshot2.workorder };
4375
+ for (const n of snapshot2.nodes) this.nodeMap.set(n.id, { ...n });
4376
+ this.edgeList = snapshot2.edges.map((e) => ({ ...e }));
4377
+ this.requirementList = snapshot2.requirements.map((r) => ({ ...r }));
4378
+ for (const w2 of snapshot2.works) this.workMap.set(w2.id, { ...w2 });
4379
+ this.artifactList = snapshot2.artifacts.map((a) => ({ ...a }));
4380
+ this.workInputList = snapshot2.workInputs.map((i) => ({ ...i }));
4381
+ for (const i of snapshot2.issues) this.issueMap.set(i.id, { ...i });
4382
+ this.recipientList = snapshot2.issueRecipients.map((r) => ({ ...r }));
4383
+ this.replyList = snapshot2.issueReplies.map((r) => ({ ...r }));
4384
+ this.attachmentList = snapshot2.issueAttachments.map((a) => ({ ...a }));
4385
+ for (const r of snapshot2.reviews) this.reviewMap.set(r.id, { ...r });
4386
4386
  }
4387
4387
  /* ── 读 ── */
4388
4388
  node(id) {
@@ -7761,15 +7761,15 @@ var require_pg_connection_string = __commonJS({
7761
7761
  if (config2.sslcert || config2.sslkey || config2.sslrootcert || config2.sslmode) {
7762
7762
  config2.ssl = {};
7763
7763
  }
7764
- const fs47 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
7764
+ const fs48 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
7765
7765
  if (config2.sslcert) {
7766
- config2.ssl.cert = fs47.readFileSync(config2.sslcert).toString();
7766
+ config2.ssl.cert = fs48.readFileSync(config2.sslcert).toString();
7767
7767
  }
7768
7768
  if (config2.sslkey) {
7769
- config2.ssl.key = fs47.readFileSync(config2.sslkey).toString();
7769
+ config2.ssl.key = fs48.readFileSync(config2.sslkey).toString();
7770
7770
  }
7771
7771
  if (config2.sslrootcert) {
7772
- config2.ssl.ca = fs47.readFileSync(config2.sslrootcert).toString();
7772
+ config2.ssl.ca = fs48.readFileSync(config2.sslrootcert).toString();
7773
7773
  }
7774
7774
  if (options.useLibpqCompat && config2.uselibpqcompat) {
7775
7775
  throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
@@ -9706,15 +9706,15 @@ var require_lib = __commonJS({
9706
9706
  "../../node_modules/.pnpm/pgpass@1.0.5/node_modules/pgpass/lib/index.js"(exports2, module2) {
9707
9707
  "use strict";
9708
9708
  var path43 = require("path");
9709
- var fs47 = require("fs");
9709
+ var fs48 = require("fs");
9710
9710
  var helper = require_helper();
9711
9711
  module2.exports = function(connInfo, cb) {
9712
9712
  var file = helper.getFileName();
9713
- fs47.stat(file, function(err, stat3) {
9713
+ fs48.stat(file, function(err, stat3) {
9714
9714
  if (err || !helper.usePgPass(stat3, file)) {
9715
9715
  return cb(void 0);
9716
9716
  }
9717
- var st = fs47.createReadStream(file);
9717
+ var st = fs48.createReadStream(file);
9718
9718
  helper.getPassword(connInfo, st, cb);
9719
9719
  });
9720
9720
  };
@@ -14048,8 +14048,8 @@ var init_bus = __esm({
14048
14048
  */
14049
14049
  async applyRecord(record8) {
14050
14050
  await this.store.transaction(async (tx) => {
14051
- const snapshot = await tx.loadWorkorder(record8.workorderId);
14052
- const state = new WorkorderState(snapshot ?? emptySnapshotPlaceholder(record8));
14051
+ const snapshot2 = await tx.loadWorkorder(record8.workorderId);
14052
+ const state = new WorkorderState(snapshot2 ?? emptySnapshotPlaceholder(record8));
14053
14053
  const ctx = {
14054
14054
  seq: record8.seq,
14055
14055
  at: record8.createdAt,
@@ -14223,10 +14223,10 @@ var init_bus = __esm({
14223
14223
  await tx.lockWorkorder(workorderId);
14224
14224
  if (await tx.hasPendingEvents(workorderId)) return { emitted: 0, terminated: false };
14225
14225
  settledAt = this.processedSeq.get(workorderId) ?? 0;
14226
- const snapshot = await tx.loadWorkorder(workorderId);
14227
- if (!snapshot) return { emitted: 0, terminated: false };
14228
- if (snapshot.workorder.lifecycle !== "active") return { emitted: 0, terminated: false };
14229
- const state = new WorkorderState(snapshot);
14226
+ const snapshot2 = await tx.loadWorkorder(workorderId);
14227
+ if (!snapshot2) return { emitted: 0, terminated: false };
14228
+ if (snapshot2.workorder.lifecycle !== "active") return { emitted: 0, terminated: false };
14229
+ const state = new WorkorderState(snapshot2);
14230
14230
  const continuationPolicies = /* @__PURE__ */ new Map();
14231
14231
  if (this.io.continuationPolicy) {
14232
14232
  for (const node2 of state.liveNodes()) {
@@ -14277,14 +14277,14 @@ var init_bus = __esm({
14277
14277
  return this.store.transaction(async (tx) => {
14278
14278
  const record8 = await tx.claimNextEvent(this.clock.now(), this.recoverAppliedBefore());
14279
14279
  if (!record8) return null;
14280
- const snapshot = await tx.loadWorkorder(record8.workorderId);
14281
- if (snapshot?.workorder.doneAt && record8.event.kind !== "work.content_edited") {
14280
+ const snapshot2 = await tx.loadWorkorder(record8.workorderId);
14281
+ if (snapshot2?.workorder.doneAt && record8.event.kind !== "work.content_edited") {
14282
14282
  await tx.applyMutations(record8.workorderId, [{
14283
14283
  t: "workorder.update",
14284
14284
  patch: { doneAt: null }
14285
14285
  }]);
14286
14286
  }
14287
- const state = new WorkorderState(snapshot ?? emptySnapshotPlaceholder(record8));
14287
+ const state = new WorkorderState(snapshot2 ?? emptySnapshotPlaceholder(record8));
14288
14288
  const ctx = {
14289
14289
  seq: record8.seq,
14290
14290
  at: record8.createdAt,
@@ -14332,9 +14332,9 @@ var init_bus = __esm({
14332
14332
  /* ═══════════════════════ 收敛断言(测试用) ═══════════════════════ */
14333
14333
  async assertConvergence(workorderId) {
14334
14334
  return this.store.transaction(async (tx) => {
14335
- const snapshot = await tx.loadWorkorder(workorderId);
14336
- if (!snapshot) return { stuck: false, codes: [] };
14337
- return assessConvergence(new WorkorderState(snapshot), {
14335
+ const snapshot2 = await tx.loadWorkorder(workorderId);
14336
+ if (!snapshot2) return { stuck: false, codes: [] };
14337
+ return assessConvergence(new WorkorderState(snapshot2), {
14338
14338
  seq: 0,
14339
14339
  at: this.clock.now(),
14340
14340
  actorId: SYSTEM_ACTOR,
@@ -16198,6 +16198,7 @@ function makeProduceResumeFallback(first, spawnFallback) {
16198
16198
  let active = first;
16199
16199
  let fellBack = false;
16200
16200
  let terminal;
16201
+ let cancelled = false;
16201
16202
  const fanOut = (chunk) => {
16202
16203
  if (outCbs.length) for (const cb of outCbs) cb(chunk);
16203
16204
  else outBuf.push(chunk);
@@ -16242,7 +16243,7 @@ function makeProduceResumeFallback(first, spawnFallback) {
16242
16243
  };
16243
16244
  wire(first);
16244
16245
  first.onExit((info) => {
16245
- if (fellBack || sawOutput || !isSessionNotFound(info)) {
16246
+ if (cancelled || fellBack || sawOutput || !isSessionNotFound(info)) {
16246
16247
  fireTerminal(info);
16247
16248
  return;
16248
16249
  }
@@ -16252,6 +16253,8 @@ function makeProduceResumeFallback(first, spawnFallback) {
16252
16253
  active = second;
16253
16254
  wire(second);
16254
16255
  second.onExit((info2) => fireTerminal(info2));
16256
+ if (cancelled) void second.kill().catch(() => {
16257
+ });
16255
16258
  },
16256
16259
  // 回落连 spawn 都起不来(节点掉线等)→ 把原始 session-not-found 如实上报,交常规重试兜底。
16257
16260
  () => fireTerminal(info)
@@ -16264,7 +16267,10 @@ function makeProduceResumeFallback(first, spawnFallback) {
16264
16267
  // 稳定关联 id:回落后底层会话换了,trace 仍以同一个 id 归一。
16265
16268
  id: stableId2,
16266
16269
  // 绑到**当下**的 active(回落后会换人),不能在构造时快照。
16267
- kill: () => active.kill(),
16270
+ kill: () => {
16271
+ cancelled = true;
16272
+ return active.kill();
16273
+ },
16268
16274
  // 四条流 + 退出走本代理的缓冲扇出:订阅者可能晚到、底层还会换人,都不能直接透传。
16269
16275
  onExit: (cb) => {
16270
16276
  if (terminal) {
@@ -17824,7 +17830,7 @@ ${supplemental.taskAppend.trim()}
17824
17830
  dispatchId: attempt
17825
17831
  };
17826
17832
  const first = await this.opts.adapter.spawn(job);
17827
- const session = resumeSession ? makeProduceResumeFallback(first, () => this.opts.adapter.spawn({ ...job, resumeRuntimeSession: false })) : first;
17833
+ const session = resumeSession && !job.execution ? makeProduceResumeFallback(first, () => this.opts.adapter.spawn({ ...job, resumeRuntimeSession: false })) : first;
17828
17834
  if (!this.isSpawnAttemptCurrent(jobKey, attempt)) {
17829
17835
  try {
17830
17836
  await session.kill();
@@ -17948,7 +17954,8 @@ ${supplemental.taskAppend.trim()}
17948
17954
  const reason = classifyExitReason(args.info);
17949
17955
  return reason === args.info.reason ? args.info : { ...args.info, reason };
17950
17956
  })();
17951
- if (this.inFlight.get(jobKey) === session) {
17957
+ const ownsSlot = this.inFlight.get(jobKey) === session;
17958
+ if (ownsSlot) {
17952
17959
  this.inFlight.delete(jobKey);
17953
17960
  this.inFlightActor.delete(jobKey);
17954
17961
  this.inFlightStartedAt.delete(jobKey);
@@ -17963,7 +17970,7 @@ ${supplemental.taskAppend.trim()}
17963
17970
  }
17964
17971
  const seqAtExit = kernel.model.lastSeq.get(spec.artifactId) ?? 0;
17965
17972
  const exitSessionKey = this.produceSessionKeyFor(spec);
17966
- if (exitSessionKey) {
17973
+ if (exitSessionKey && ownsSlot) {
17967
17974
  const prev = decodeProduceSession(this.produceSessions.get(exitSessionKey));
17968
17975
  if (prev) {
17969
17976
  const isWholeProduce = spec.action === "produce" && spec.part === void 0;
@@ -20943,9 +20950,9 @@ var init_kernel_bridge = __esm({
20943
20950
  if (!args.actor.startsWith("actor:human:")) throw new Error("\u6062\u590D\u51B3\u5B9A\u9700\u8981\u4EBA\u660E\u786E\u786E\u8BA4");
20944
20951
  if (!args.reason.trim()) throw new Error("\u6062\u590D\u51B3\u5B9A\u5FC5\u987B\u8BF4\u660E\u91C7\u7528\u7684\u65B9\u6848");
20945
20952
  const wid = this.wo(args.artifactId);
20946
- const snapshot = await this.store.transaction((tx) => tx.loadWorkorder(wid));
20947
- const gap = snapshot?.issues.find((i) => i.id === args.gapId && i.kind === "gap" && i.aboutNodeId === args.artifactId);
20948
- const escalation = snapshot?.issues.find((i) => i.id === args.escalationId && i.kind === "escalation" && i.aboutNodeId === args.artifactId);
20953
+ const snapshot2 = await this.store.transaction((tx) => tx.loadWorkorder(wid));
20954
+ const gap = snapshot2?.issues.find((i) => i.id === args.gapId && i.kind === "gap" && i.aboutNodeId === args.artifactId);
20955
+ const escalation = snapshot2?.issues.find((i) => i.id === args.escalationId && i.kind === "escalation" && i.aboutNodeId === args.artifactId);
20949
20956
  if (!gap || !escalation || escalation.gapId !== gap.id) throw new Error("\u6062\u590D\u5361\u7684\u7F3A\u53E3\u4E0E\u4E0A\u62A5\u5173\u8054\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u786E\u8BA4");
20950
20957
  const events = [];
20951
20958
  for (const issue2 of [gap, escalation]) if (!issue2.resolvedAt) events.push({
@@ -21437,22 +21444,22 @@ var init_kernel_bridge = __esm({
21437
21444
  async decideContinuation(draftId, actor, approve, reason) {
21438
21445
  const review = this.model.pendingReviews.get(draftId);
21439
21446
  if (!review?.continuation || !review.workspace) throw new Error("\u7EED\u8DD1\u5BA1\u6279\u4E0D\u5B58\u5728\u6216\u5DF2\u5904\u7406");
21440
- const snapshot = await this.store.transaction((tx) => tx.loadWorkorder(review.workspace));
21441
- const node2 = snapshot?.nodes.find((n) => n.id === review.continuation.nodeId);
21447
+ const snapshot2 = await this.store.transaction((tx) => tx.loadWorkorder(review.workspace));
21448
+ const node2 = snapshot2?.nodes.find((n) => n.id === review.continuation.nodeId);
21442
21449
  const request2 = node2?.continuationBudget?.request;
21443
- if (!actor.startsWith("actor:human:") || !snapshot || continuationApprover(new WorkorderState(snapshot)) !== actor) throw new Error("\u4EC5\u5DE5\u5355\u4EBA\u7C7B\u8D1F\u8D23\u4EBA\u53EF\u4EE5\u5BA1\u6279\u7EED\u8DD1\u989D\u5EA6");
21450
+ if (!actor.startsWith("actor:human:") || !snapshot2 || continuationApprover(new WorkorderState(snapshot2)) !== actor) throw new Error("\u4EC5\u5DE5\u5355\u4EBA\u7C7B\u8D1F\u8D23\u4EBA\u53EF\u4EE5\u5BA1\u6279\u7EED\u8DD1\u989D\u5EA6");
21444
21451
  if (!request2 || request2.id !== draftId || request2.decision !== "pending" || node2?.cancelledAt) throw new Error("\u7EED\u8DD1\u5BA1\u6279\u5DF2\u5904\u7406\u6216\u5931\u6548");
21445
21452
  const expectedAuthorized = Math.max(
21446
21453
  node2.continuationBudget.authorizedRounds,
21447
- continuationUsedRounds(new WorkorderState(snapshot), node2.id)
21454
+ continuationUsedRounds(new WorkorderState(snapshot2), node2.id)
21448
21455
  ) + request2.rounds;
21449
21456
  await this.commit({
21450
- companyId: snapshot.workorder.companyId,
21451
- workorderId: snapshot.workorder.id,
21457
+ companyId: snapshot2.workorder.companyId,
21458
+ workorderId: snapshot2.workorder.id,
21452
21459
  actorId: actor,
21453
- event: { kind: "continuation.decided", workorderId: snapshot.workorder.id, nodeId: node2.id, requestId: draftId, approve, reason }
21460
+ event: { kind: "continuation.decided", workorderId: snapshot2.workorder.id, nodeId: node2.id, requestId: draftId, approve, reason }
21454
21461
  });
21455
- const after = await this.store.transaction((tx) => tx.loadWorkorder(snapshot.workorder.id));
21462
+ const after = await this.store.transaction((tx) => tx.loadWorkorder(snapshot2.workorder.id));
21456
21463
  const afterBudget = after?.nodes.find((n) => n.id === node2.id)?.continuationBudget;
21457
21464
  const decided = afterBudget?.request;
21458
21465
  const applied = approve ? (afterBudget?.authorizedRounds ?? 0) >= expectedAuthorized : decided?.id === draftId && (decided.decision === "denied" || decided.decision === "completed");
@@ -23427,17 +23434,17 @@ function parseResultUsage(value2) {
23427
23434
  const oneHour = usageNum(cache["ephemeral_1h_input_tokens"]);
23428
23435
  return fiveMinute == null && oneHour == null ? void 0 : (fiveMinute ?? 0) + (oneHour ?? 0);
23429
23436
  })();
23430
- const snapshot = {
23437
+ const snapshot2 = {
23431
23438
  input: usageNum(usage["input_tokens"]),
23432
23439
  output: usageNum(usage["output_tokens"]),
23433
23440
  cacheRead: usageNum(usage["cache_read_input_tokens"]),
23434
23441
  cacheCreation
23435
23442
  };
23436
- return Object.values(snapshot).some((v2) => v2 != null) ? snapshot : null;
23443
+ return Object.values(snapshot2).some((v2) => v2 != null) ? snapshot2 : null;
23437
23444
  }
23438
23445
  function parseModelUsage(value2) {
23439
23446
  if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
23440
- const snapshot = {};
23447
+ const snapshot2 = {};
23441
23448
  const fields = [
23442
23449
  ["input", "inputTokens"],
23443
23450
  ["output", "outputTokens"],
@@ -23449,10 +23456,10 @@ function parseModelUsage(value2) {
23449
23456
  const usage = model;
23450
23457
  for (const [target, source] of fields) {
23451
23458
  const amount = usageNum(usage[source]);
23452
- if (amount != null) snapshot[target] = (snapshot[target] ?? 0) + amount;
23459
+ if (amount != null) snapshot2[target] = (snapshot2[target] ?? 0) + amount;
23453
23460
  }
23454
23461
  }
23455
- return Object.values(snapshot).some((v2) => v2 != null) ? snapshot : null;
23462
+ return Object.values(snapshot2).some((v2) => v2 != null) ? snapshot2 : null;
23456
23463
  }
23457
23464
  function mergeFinalUsage(primary, fallback) {
23458
23465
  if (!primary) return fallback;
@@ -25836,9 +25843,9 @@ function toolUseOnce(state, id, name, input) {
25836
25843
  state.toolUseIds.add(id);
25837
25844
  return [{ kind: "tool_use", payload: { id, name, input } }];
25838
25845
  }
25839
- function remainderAfterStream(streamed, snapshot) {
25840
- if (!streamed) return snapshot;
25841
- return snapshot.startsWith(streamed) ? snapshot.slice(streamed.length) : "";
25846
+ function remainderAfterStream(streamed, snapshot2) {
25847
+ if (!streamed) return snapshot2;
25848
+ return snapshot2.startsWith(streamed) ? snapshot2.slice(streamed.length) : "";
25842
25849
  }
25843
25850
  function noteCodexAgentDelta(state, delta) {
25844
25851
  if (!delta) return [];
@@ -31378,9 +31385,9 @@ var init_service = __esm({
31378
31385
  if (this.sending || this.finalized || !this.dirty) return;
31379
31386
  this.sending = true;
31380
31387
  this.dirty = false;
31381
- const snapshot = this.buf;
31388
+ const snapshot2 = this.buf;
31382
31389
  try {
31383
- const card2 = buildTextCard(snapshot, { footer: "\u25CF \u751F\u6210\u4E2D\u2026" });
31390
+ const card2 = buildTextCard(snapshot2, { footer: "\u25CF \u751F\u6210\u4E2D\u2026" });
31384
31391
  if (!this.messageId) {
31385
31392
  this.messageId = (await this.client.sendCard(this.chatId, card2)).messageId;
31386
31393
  } else {
@@ -41387,7 +41394,7 @@ var require_form_data = __commonJS({
41387
41394
  var http2 = require("http");
41388
41395
  var https = require("https");
41389
41396
  var parseUrl = require("url").parse;
41390
- var fs47 = require("fs");
41397
+ var fs48 = require("fs");
41391
41398
  var Stream = require("stream").Stream;
41392
41399
  var crypto4 = require("crypto");
41393
41400
  var mime = require_mime_types();
@@ -41457,7 +41464,7 @@ var require_form_data = __commonJS({
41457
41464
  if (value2.end != void 0 && value2.end != Infinity && value2.start != void 0) {
41458
41465
  callback(null, value2.end + 1 - (value2.start ? value2.start : 0));
41459
41466
  } else {
41460
- fs47.stat(value2.path, function(err, stat3) {
41467
+ fs48.stat(value2.path, function(err, stat3) {
41461
41468
  if (err) {
41462
41469
  callback(err);
41463
41470
  return;
@@ -52184,7 +52191,7 @@ var require_websocket = __commonJS({
52184
52191
  var http2 = require("http");
52185
52192
  var net = require("net");
52186
52193
  var tls = require("tls");
52187
- var { randomBytes: randomBytes13, createHash: createHash41 } = require("crypto");
52194
+ var { randomBytes: randomBytes13, createHash: createHash42 } = require("crypto");
52188
52195
  var { Duplex, Readable } = require("stream");
52189
52196
  var { URL: URL2 } = require("url");
52190
52197
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -52852,7 +52859,7 @@ var require_websocket = __commonJS({
52852
52859
  abortHandshake(websocket, socket, "Invalid Upgrade header");
52853
52860
  return;
52854
52861
  }
52855
- const digest = createHash41("sha1").update(key + GUID).digest("base64");
52862
+ const digest = createHash42("sha1").update(key + GUID).digest("base64");
52856
52863
  if (res.headers["sec-websocket-accept"] !== digest) {
52857
52864
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
52858
52865
  return;
@@ -53221,7 +53228,7 @@ var require_websocket_server = __commonJS({
53221
53228
  var EventEmitter = require("events");
53222
53229
  var http2 = require("http");
53223
53230
  var { Duplex } = require("stream");
53224
- var { createHash: createHash41 } = require("crypto");
53231
+ var { createHash: createHash42 } = require("crypto");
53225
53232
  var extension3 = require_extension();
53226
53233
  var PerMessageDeflate2 = require_permessage_deflate();
53227
53234
  var subprotocol2 = require_subprotocol();
@@ -53528,7 +53535,7 @@ var require_websocket_server = __commonJS({
53528
53535
  );
53529
53536
  }
53530
53537
  if (this._state > RUNNING) return abortHandshake(socket, 503);
53531
- const digest = createHash41("sha1").update(key + GUID).digest("base64");
53538
+ const digest = createHash42("sha1").update(key + GUID).digest("base64");
53532
53539
  const headers = [
53533
53540
  "HTTP/1.1 101 Switching Protocols",
53534
53541
  "Upgrade: websocket",
@@ -56032,7 +56039,7 @@ var require_lib4 = __commonJS({
56032
56039
  "use strict";
56033
56040
  Object.defineProperty(exports2, "__esModule", { value: true });
56034
56041
  var axios = require_axios();
56035
- var fs47 = require("fs");
56042
+ var fs48 = require("fs");
56036
56043
  var path43 = require("path");
56037
56044
  var crypto4 = require("crypto");
56038
56045
  var qs = require_lib3();
@@ -56050,7 +56057,7 @@ var require_lib4 = __commonJS({
56050
56057
  return e && typeof e === "object" && "default" in e ? e : { "default": e };
56051
56058
  }
56052
56059
  var axios__default = /* @__PURE__ */ _interopDefaultLegacy(axios);
56053
- var fs__default = /* @__PURE__ */ _interopDefaultLegacy(fs47);
56060
+ var fs__default = /* @__PURE__ */ _interopDefaultLegacy(fs48);
56054
56061
  var path__default = /* @__PURE__ */ _interopDefaultLegacy(path43);
56055
56062
  var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(crypto4);
56056
56063
  var identity__default = /* @__PURE__ */ _interopDefaultLegacy(identity);
@@ -140031,8 +140038,8 @@ var require_lib4 = __commonJS({
140031
140038
  while (this.content.length > this.maxChars) {
140032
140039
  yield this.rollover();
140033
140040
  }
140034
- const snapshot = this.content || "...";
140035
- yield this.sender.updateCardElementContent(this.cardId, ELEMENT_ID, snapshot, ++this.sequence);
140041
+ const snapshot2 = this.content || "...";
140042
+ yield this.sender.updateCardElementContent(this.cardId, ELEMENT_ID, snapshot2, ++this.sequence);
140036
140043
  });
140037
140044
  }
140038
140045
  /**
@@ -140175,9 +140182,9 @@ var require_lib4 = __commonJS({
140175
140182
  return __awaiter(this, void 0, void 0, function* () {
140176
140183
  if (!this._messageId)
140177
140184
  return;
140178
- const snapshot = this._current;
140185
+ const snapshot2 = this._current;
140179
140186
  yield this.queue.enqueue(() => __awaiter(this, void 0, void 0, function* () {
140180
- yield this.sender.patchCard(this._messageId, snapshot);
140187
+ yield this.sender.patchCard(this._messageId, snapshot2);
140181
140188
  }));
140182
140189
  });
140183
140190
  }
@@ -160426,12 +160433,12 @@ var require_dist2 = __commonJS({
160426
160433
  throw new Error(`Unknown format "${name}"`);
160427
160434
  return f2;
160428
160435
  };
160429
- function addFormats(ajv, list2, fs47, exportName) {
160436
+ function addFormats(ajv, list2, fs48, exportName) {
160430
160437
  var _a;
160431
160438
  var _b;
160432
160439
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
160433
160440
  for (const f2 of list2)
160434
- ajv.addFormat(f2, fs47[f2]);
160441
+ ajv.addFormat(f2, fs48[f2]);
160435
160442
  }
160436
160443
  module2.exports = exports2 = formatsPlugin;
160437
160444
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -167590,8 +167597,8 @@ var init_service2 = __esm({
167590
167597
  output += chunk;
167591
167598
  if (answerAttempt && (output.length - checkpointedChars >= 1024 || FINAL_ANSWER_MARKER.test(output))) {
167592
167599
  checkpointedChars = output.length;
167593
- const snapshot = output;
167594
- checkpointChain = checkpointChain.then(() => this.checkpointAnswerDraft(record8, answerAttempt.id, snapshot));
167600
+ const snapshot2 = output;
167601
+ checkpointChain = checkpointChain.then(() => this.checkpointAnswerDraft(record8, answerAttempt.id, snapshot2));
167595
167602
  }
167596
167603
  });
167597
167604
  dispatched.onTelemetry?.((event) => {
@@ -184561,14 +184568,14 @@ var require_parser2 = __commonJS({
184561
184568
  case "scalar":
184562
184569
  case "single-quoted-scalar":
184563
184570
  case "double-quoted-scalar": {
184564
- const fs47 = this.flowScalar(this.type);
184571
+ const fs48 = this.flowScalar(this.type);
184565
184572
  if (atNextItem || it.value) {
184566
- map.items.push({ start, key: fs47, sep: [] });
184573
+ map.items.push({ start, key: fs48, sep: [] });
184567
184574
  this.onKeyLine = true;
184568
184575
  } else if (it.sep) {
184569
- this.stack.push(fs47);
184576
+ this.stack.push(fs48);
184570
184577
  } else {
184571
- Object.assign(it, { key: fs47, sep: [] });
184578
+ Object.assign(it, { key: fs48, sep: [] });
184572
184579
  this.onKeyLine = true;
184573
184580
  }
184574
184581
  return;
@@ -184696,13 +184703,13 @@ var require_parser2 = __commonJS({
184696
184703
  case "scalar":
184697
184704
  case "single-quoted-scalar":
184698
184705
  case "double-quoted-scalar": {
184699
- const fs47 = this.flowScalar(this.type);
184706
+ const fs48 = this.flowScalar(this.type);
184700
184707
  if (!it || it.value)
184701
- fc.items.push({ start: [], key: fs47, sep: [] });
184708
+ fc.items.push({ start: [], key: fs48, sep: [] });
184702
184709
  else if (it.sep)
184703
- this.stack.push(fs47);
184710
+ this.stack.push(fs48);
184704
184711
  else
184705
- Object.assign(it, { key: fs47, sep: [] });
184712
+ Object.assign(it, { key: fs48, sep: [] });
184706
184713
  return;
184707
184714
  }
184708
184715
  case "flow-map-end":
@@ -185291,10 +185298,10 @@ function durationMs2(startedAt, completedAt) {
185291
185298
  if (!startedAt || !completedAt) return void 0;
185292
185299
  return Math.max(0, Date.parse(completedAt) - Date.parse(startedAt));
185293
185300
  }
185294
- function snapshotJson(snapshot, expectedHash) {
185295
- if (!snapshot || !expectedHash || snapshot.contentHash !== expectedHash || snapshot.contentHash !== sha256(snapshot.content)) return void 0;
185301
+ function snapshotJson(snapshot2, expectedHash) {
185302
+ if (!snapshot2 || !expectedHash || snapshot2.contentHash !== expectedHash || snapshot2.contentHash !== sha256(snapshot2.content)) return void 0;
185296
185303
  try {
185297
- return JSON.parse(snapshot.content);
185304
+ return JSON.parse(snapshot2.content);
185298
185305
  } catch {
185299
185306
  return void 0;
185300
185307
  }
@@ -185603,7 +185610,7 @@ var init_network_maintenance = __esm({
185603
185610
  store.list(scope, "snapshot")
185604
185611
  ]);
185605
185612
  const runTasks = tasks.filter((entry) => entry.maintenanceRunId === run.id).sort((left, right) => left.ordinal - right.ordinal);
185606
- const snapshotByRef = new Map(snapshots2.map((snapshot) => [snapshot.ref, snapshot]));
185613
+ const snapshotByRef = new Map(snapshots2.map((snapshot2) => [snapshot2.ref, snapshot2]));
185607
185614
  return {
185608
185615
  run,
185609
185616
  tasks: runTasks,
@@ -185649,7 +185656,7 @@ var init_network_maintenance = __esm({
185649
185656
  const itemById = new Map(allItems.map((item) => [item.id, item]));
185650
185657
  const items = allItems.filter((item) => item.status === "active" && item.currentApprovedVersionId);
185651
185658
  const versions = new Map((await store.list(scope, "item_version")).map((version2) => [version2.id, version2]));
185652
- const snapshots2 = new Map((await store.list(scope, "snapshot")).map((snapshot) => [snapshot.ref, snapshot]));
185659
+ const snapshots2 = new Map((await store.list(scope, "snapshot")).map((snapshot2) => [snapshot2.ref, snapshot2]));
185653
185660
  const relations = await store.list(scope, "version_relation");
185654
185661
  const currentVersions = new Map(items.map((item) => [item.currentApprovedVersionId, { item, version: versions.get(item.currentApprovedVersionId) }]));
185655
185662
  const aiVisibleVersions = [...currentVersions.values()].filter((entry) => Boolean(entry.version) && entry.version.accessMode === "agent_and_human");
@@ -185679,11 +185686,11 @@ var init_network_maintenance = __esm({
185679
185686
  if (mode === "full") for (const entry of currentDerived) affectedVersionIds.add(entry.version.id);
185680
185687
  const settings = await store.get(scope, "maintenance_settings", `knmaintsettings_${sha256(`${ctx.organizationId}:${projectId2 ?? "org"}:${spaceId}`).slice(0, 24)}`) ?? this.defaultSettings(ctx, projectId2, spaceId);
185681
185688
  const approvedContent = (entry) => {
185682
- const snapshot = snapshots2.get(entry.version.contentSnapshotRef);
185683
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content)) {
185689
+ const snapshot2 = snapshots2.get(entry.version.contentSnapshotRef);
185690
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content)) {
185684
185691
  return this.options.fail(409, "KNOWLEDGE_MAINTENANCE_SNAPSHOT_UNREADABLE", `\u6279\u51C6\u7248\u672C ${entry.version.id} \u7684\u4E0D\u53EF\u53D8\u5FEB\u7167\u4E0D\u53EF\u8BFB`);
185685
185692
  }
185686
- return snapshot.content;
185693
+ return snapshot2.content;
185687
185694
  };
185688
185695
  const relevanceEntry = (entry) => ({
185689
185696
  itemId: entry.item.id,
@@ -185898,7 +185905,7 @@ var init_network_maintenance = __esm({
185898
185905
  const maintenanceInput = maintenanceInputFromSnapshot(inputSnapshot.content, run.mode, projectId2 ? "project" : "organization");
185899
185906
  let existingTasks = (await store.list(scope, "maintenance_task")).filter((task) => task.maintenanceRunId === run.id);
185900
185907
  const requestActor = await this.options.actor(ctx.actorId);
185901
- const taskSnapshots = new Map((await store.list(scope, "snapshot")).map((snapshot) => [snapshot.ref, snapshot]));
185908
+ const taskSnapshots = new Map((await store.list(scope, "snapshot")).map((snapshot2) => [snapshot2.ref, snapshot2]));
185902
185909
  const completedTasks = [];
185903
185910
  for (const task of existingTasks.filter((entry) => entry.status === "succeeded")) {
185904
185911
  const resultSnapshot = task.resultSnapshotRef ? taskSnapshots.get(task.resultSnapshotRef) : void 0;
@@ -186036,9 +186043,9 @@ var init_network_maintenance = __esm({
186036
186043
  }
186037
186044
  if (puts.length > 0) await store.transact(scope, { puts });
186038
186045
  },
186039
- onTaskStarted: async (taskKey, sessionId) => {
186040
- const current = (await store.list(scope, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey);
186041
- if (!current) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u5C1A\u672A\u6301\u4E45\u5316`, false);
186046
+ onTaskStarted: async (taskKey2, sessionId) => {
186047
+ const current = (await store.list(scope, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey2);
186048
+ if (!current) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u5C1A\u672A\u6301\u4E45\u5316`, false);
186042
186049
  if (current.status === "succeeded") return;
186043
186050
  const now = this.iso();
186044
186051
  const running = {
@@ -186064,21 +186071,21 @@ var init_network_maintenance = __esm({
186064
186071
  ],
186065
186072
  puts: [put("maintenance_task", running)]
186066
186073
  });
186067
- if (!result2.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u5DF2\u88AB\u5176\u4ED6 Worker \u9886\u53D6`, true);
186074
+ if (!result2.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u5DF2\u88AB\u5176\u4ED6 Worker \u9886\u53D6`, true);
186068
186075
  },
186069
- onTaskSucceeded: async (taskKey, rawOutput, result2) => {
186070
- const current = (await store.list(scope, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey);
186071
- if (!current || current.status !== "running") throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u4E0D\u5728\u8FD0\u884C\u6001`, false);
186072
- const currentInputSnapshot = (await store.list(scope, "snapshot")).find((snapshot) => snapshot.ref === current.inputSnapshotRef);
186076
+ onTaskSucceeded: async (taskKey2, rawOutput, result2) => {
186077
+ const current = (await store.list(scope, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey2);
186078
+ if (!current || current.status !== "running") throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u4E0D\u5728\u8FD0\u884C\u6001`, false);
186079
+ const currentInputSnapshot = (await store.list(scope, "snapshot")).find((snapshot2) => snapshot2.ref === current.inputSnapshotRef);
186073
186080
  if (!currentInputSnapshot || currentInputSnapshot.contentHash !== current.inputHash || currentInputSnapshot.contentHash !== sha256(currentInputSnapshot.content)) {
186074
- throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u7684\u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB`, false);
186081
+ throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u7684\u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB`, false);
186075
186082
  }
186076
186083
  const taskInput = JSON.parse(currentInputSnapshot.content);
186077
186084
  try {
186078
186085
  validateMaintenanceTaskOperations(result2.operations, taskInput);
186079
186086
  } catch (error2) {
186080
186087
  const validationError = error2 instanceof Error ? error2.message : String(error2);
186081
- const output2 = this.snapshot(ctx, "maintenance_task_output", stableJson(rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey}:${current.retryCount}`);
186088
+ const output2 = this.snapshot(ctx, "maintenance_task_output", stableJson(rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey2}:${current.retryCount}`);
186082
186089
  const now2 = this.iso();
186083
186090
  const failed = {
186084
186091
  ...current,
@@ -186101,11 +186108,11 @@ var init_network_maintenance = __esm({
186101
186108
  ],
186102
186109
  puts: [put("snapshot", output2, "error"), put("maintenance_task", failed)]
186103
186110
  });
186104
- if (!rejected.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u65E0\u6548\u7ED3\u679C\u72B6\u6001\u63D0\u4EA4\u51B2\u7A81`, true);
186111
+ if (!rejected.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u65E0\u6548\u7ED3\u679C\u72B6\u6001\u63D0\u4EA4\u51B2\u7A81`, true);
186105
186112
  throw new KnowledgeMaintenanceProcessingError(validationError, false);
186106
186113
  }
186107
- const output = this.snapshot(ctx, "maintenance_task_output", stableJson(rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey}:${current.retryCount}`);
186108
- const normalized4 = this.snapshot(ctx, "maintenance_task_result", stableJson(result2), projectId2, run.spaceId, `snapshot:maintenance-task-result:${run.id}:${taskKey}:${current.retryCount}`);
186114
+ const output = this.snapshot(ctx, "maintenance_task_output", stableJson(rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey2}:${current.retryCount}`);
186115
+ const normalized4 = this.snapshot(ctx, "maintenance_task_result", stableJson(result2), projectId2, run.spaceId, `snapshot:maintenance-task-result:${run.id}:${taskKey2}:${current.retryCount}`);
186109
186116
  const now = this.iso();
186110
186117
  const succeeded = {
186111
186118
  ...current,
@@ -186128,14 +186135,14 @@ var init_network_maintenance = __esm({
186128
186135
  ],
186129
186136
  puts: [put("snapshot", output, "error"), put("snapshot", normalized4, "error"), put("maintenance_task", succeeded)]
186130
186137
  });
186131
- if (!saved.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u7ED3\u679C\u68C0\u67E5\u70B9\u63D0\u4EA4\u51B2\u7A81`, true);
186138
+ if (!saved.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u7ED3\u679C\u68C0\u67E5\u70B9\u63D0\u4EA4\u51B2\u7A81`, true);
186132
186139
  },
186133
- onTaskFailed: async (taskKey, failure) => {
186134
- const current = (await store.list(scope, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey);
186140
+ onTaskFailed: async (taskKey2, failure) => {
186141
+ const current = (await store.list(scope, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey2);
186135
186142
  if (!current || current.status === "succeeded") return;
186136
186143
  const retryable = failure.kind === "runtime" && isRetryableKnowledgeMaintenanceError(failure.cause ?? new Error(failure.message));
186137
186144
  const now = this.iso();
186138
- const output = failure.rawOutput ? this.snapshot(ctx, "maintenance_task_output", stableJson(failure.rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey}:${current.retryCount}`) : void 0;
186145
+ const output = failure.rawOutput ? this.snapshot(ctx, "maintenance_task_output", stableJson(failure.rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey2}:${current.retryCount}`) : void 0;
186139
186146
  const failed = {
186140
186147
  ...current,
186141
186148
  ...failure.sessionId ? { sessionId: failure.sessionId } : {},
@@ -186152,7 +186159,7 @@ var init_network_maintenance = __esm({
186152
186159
  checks: [{ kind: "maintenance_task", id: current.id, field: "status", equals: current.status }],
186153
186160
  puts: [...output ? [put("snapshot", output, "error")] : [], put("maintenance_task", failed)]
186154
186161
  });
186155
- if (!saved.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u5931\u8D25\u72B6\u6001\u63D0\u4EA4\u51B2\u7A81`, true);
186162
+ if (!saved.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey2} \u5931\u8D25\u72B6\u6001\u63D0\u4EA4\u51B2\u7A81`, true);
186156
186163
  }
186157
186164
  });
186158
186165
  const analyzer = await this.options.actor(analysis.analyzerActorId);
@@ -186252,7 +186259,7 @@ var init_network_maintenance = __esm({
186252
186259
  targetItems: previewTargets,
186253
186260
  sensitivityFindings: [...candidate.sensitivityFindings]
186254
186261
  };
186255
- const snapshot = this.snapshot(
186262
+ const snapshot2 = this.snapshot(
186256
186263
  ctx,
186257
186264
  "approved_preview",
186258
186265
  stableJson(preview2),
@@ -186260,15 +186267,15 @@ var init_network_maintenance = __esm({
186260
186267
  run.spaceId,
186261
186268
  `snapshot:maintenance-preview:${candidate.id}:${candidate.candidateRevision}`
186262
186269
  );
186263
- approvedPreviewSnapshots.push(snapshot);
186270
+ approvedPreviewSnapshots.push(snapshot2);
186264
186271
  approvedCandidates.push({
186265
186272
  ...candidate,
186266
186273
  decisionStatus: "approved",
186267
186274
  decisionAction: candidate.recommendedAction,
186268
186275
  decidedBy: ctx.actorId,
186269
186276
  decisionReason: "\u7CFB\u7EDF\u6700\u5C0F\u5B89\u5168\u6821\u9A8C\u901A\u8FC7\uFF0C\u81EA\u52A8\u8FDB\u5165\u53D1\u5E03",
186270
- approvedPreviewSnapshotRef: snapshot.ref,
186271
- approvedPreviewHash: snapshot.contentHash,
186277
+ approvedPreviewSnapshotRef: snapshot2.ref,
186278
+ approvedPreviewHash: snapshot2.contentHash,
186272
186279
  decidedAt: approvedAt,
186273
186280
  updatedAt: approvedAt
186274
186281
  });
@@ -186314,7 +186321,7 @@ var init_network_maintenance = __esm({
186314
186321
  { kind: "maintenance_run", id: run.id, field: "analysisAttemptId", equals: validating.analysisAttemptId }
186315
186322
  ],
186316
186323
  puts: [
186317
- ...approvedPreviewSnapshots.map((snapshot) => put("snapshot", snapshot, "error")),
186324
+ ...approvedPreviewSnapshots.map((snapshot2) => put("snapshot", snapshot2, "error")),
186318
186325
  ...approvedCandidates.map((candidate) => put("candidate", candidate, "error")),
186319
186326
  ...created.targets.map((target) => put("candidate_target", target, "error")),
186320
186327
  ...approvedOperations.map((operation) => put("maintenance_operation", operation, "error")),
@@ -186671,11 +186678,11 @@ var init_network_maintenance = __esm({
186671
186678
  if (relevantTasks.length !== taskKeys.length || relevantTasks.some((task) => task.status !== "failed_deterministic" || task.retryCount < 1)) {
186672
186679
  return this.options.fail(409, "KNOWLEDGE_MAINTENANCE_GAP_RETRY_REQUIRED", "\u81F3\u5C11\u8BA9\u77E5\u8BC6\u7BA1\u7406\u5458\u6309\u6821\u9A8C\u610F\u89C1\u8FD4\u4FEE\u4E00\u6B21\uFF1B\u8FDE\u7EED\u5931\u8D25\u540E\u624D\u80FD\u8DF3\u8FC7\u76F8\u5173\u4E3B\u9898");
186673
186680
  }
186674
- const inputSnapshot = snapshots2.find((snapshot) => snapshot.ref === run.inputSnapshotRef);
186681
+ const inputSnapshot = snapshots2.find((snapshot2) => snapshot2.ref === run.inputSnapshotRef);
186675
186682
  if (!inputSnapshot || inputSnapshot.contentHash !== run.inputHash || inputSnapshot.contentHash !== sha256(inputSnapshot.content)) {
186676
186683
  return this.options.fail(409, "KNOWLEDGE_MAINTENANCE_INPUT_CORRUPT", "\u7EF4\u62A4\u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB");
186677
186684
  }
186678
- const outputSnapshot = run.outputSnapshotRef ? snapshots2.find((snapshot) => snapshot.ref === run.outputSnapshotRef) : void 0;
186685
+ const outputSnapshot = run.outputSnapshotRef ? snapshots2.find((snapshot2) => snapshot2.ref === run.outputSnapshotRef) : void 0;
186679
186686
  if (!outputSnapshot || outputSnapshot.contentHash !== sha256(outputSnapshot.content)) {
186680
186687
  return this.options.fail(409, "KNOWLEDGE_MAINTENANCE_OUTPUT_CORRUPT", "\u7EF4\u62A4\u8F93\u51FA\u5FEB\u7167\u4E0D\u53EF\u8BFB");
186681
186688
  }
@@ -186826,16 +186833,16 @@ var init_network_maintenance = __esm({
186826
186833
  targetItems: previewTargets,
186827
186834
  sensitivityFindings: [...candidate.sensitivityFindings]
186828
186835
  };
186829
- const snapshot = this.snapshot(ctx, "approved_preview", stableJson(preview2), projectId2, run.spaceId, `snapshot:maintenance-preview:${candidate.id}:${candidate.candidateRevision}`);
186830
- snapshots2.push(snapshot);
186836
+ const snapshot2 = this.snapshot(ctx, "approved_preview", stableJson(preview2), projectId2, run.spaceId, `snapshot:maintenance-preview:${candidate.id}:${candidate.candidateRevision}`);
186837
+ snapshots2.push(snapshot2);
186831
186838
  decidedCandidates.push({
186832
186839
  ...candidate,
186833
186840
  decisionStatus: "approved",
186834
186841
  decisionAction: candidate.recommendedAction,
186835
186842
  decidedBy: ctx.actorId,
186836
186843
  decisionReason: request2.reason.trim(),
186837
- approvedPreviewSnapshotRef: snapshot.ref,
186838
- approvedPreviewHash: snapshot.contentHash,
186844
+ approvedPreviewSnapshotRef: snapshot2.ref,
186845
+ approvedPreviewHash: snapshot2.contentHash,
186839
186846
  decidedAt: now,
186840
186847
  updatedAt: now
186841
186848
  });
@@ -186889,7 +186896,7 @@ var init_network_maintenance = __esm({
186889
186896
  const result = await store.transact(scope, {
186890
186897
  checks: [{ kind: "maintenance_run", id: run.id, field: "status", equals: "awaiting_review" }],
186891
186898
  puts: [
186892
- ...snapshots2.map((snapshot) => put("snapshot", snapshot, "error")),
186899
+ ...snapshots2.map((snapshot2) => put("snapshot", snapshot2, "error")),
186893
186900
  ...decidedCandidates.map((candidate) => put("candidate", candidate)),
186894
186901
  ...nextOperations.map((operation) => put("maintenance_operation", operation)),
186895
186902
  put("maintenance_run", reviewed),
@@ -187279,7 +187286,7 @@ var init_network_maintenance = __esm({
187279
187286
  createdAt: now,
187280
187287
  updatedAt: now
187281
187288
  };
187282
- const snapshot = this.snapshot(ctx, "approved_content", normalizeKnowledgeContent(preview2.title, revision.content), run.projectId, run.spaceId, `snapshot:approved:${versionId}`);
187289
+ const snapshot2 = this.snapshot(ctx, "approved_content", normalizeKnowledgeContent(preview2.title, revision.content), run.projectId, run.spaceId, `snapshot:approved:${versionId}`);
187283
187290
  const metadata = preview2.metadata;
187284
187291
  const version2 = {
187285
187292
  id: versionId,
@@ -187311,7 +187318,7 @@ var init_network_maintenance = __esm({
187311
187318
  semanticContentHash: semanticKnowledgeHash(preview2.title, revision.content),
187312
187319
  providerContentHash: revision.providerContentHash || providerKnowledgeHash(revision.content),
187313
187320
  contentNormalizerVersion: KNOWLEDGE_NORMALIZER_VERSION,
187314
- contentSnapshotRef: snapshot.ref,
187321
+ contentSnapshotRef: snapshot2.ref,
187315
187322
  changeType: operation.action === "add" ? "initial" : operation.action,
187316
187323
  changeSummary: candidate.recommendedReason,
187317
187324
  approvedBy: candidate.decidedBy,
@@ -187320,7 +187327,7 @@ var init_network_maintenance = __esm({
187320
187327
  };
187321
187328
  finalItems.set(item.id, item);
187322
187329
  puts.push(
187323
- put("snapshot", snapshot, "error"),
187330
+ put("snapshot", snapshot2, "error"),
187324
187331
  put("item", item, updatesExisting ? "replace" : "error"),
187325
187332
  put("item_version", version2, "error"),
187326
187333
  put("provider_mapping", this.providerMapping(ctx, version2, connection, space, revision), "error"),
@@ -187401,7 +187408,7 @@ var init_network_maintenance = __esm({
187401
187408
  title: version2.title,
187402
187409
  abstract: version2.abstract,
187403
187410
  logicalPath: item.logicalPath,
187404
- content: snapshot.content
187411
+ content: snapshot2.content
187405
187412
  }).map((entry) => ({
187406
187413
  id: `${version2.id}:${entry.chunkId}:routing`,
187407
187414
  organizationId: ctx.organizationId,
@@ -187506,9 +187513,9 @@ var init_network_maintenance = __esm({
187506
187513
  const scope = recordScope(ctx.organizationId, projectId2, current.spaceId);
187507
187514
  const previous3 = await store.get(scope, "generation", current.previousGenerationId);
187508
187515
  if (!previous3?.manifestSnapshotRef || previous3.status !== "superseded") return this.options.fail(409, "KNOWLEDGE_GENERATION_PREVIOUS_UNAVAILABLE", "\u4E0A\u4E00 Generation \u4E0D\u53EF\u6062\u590D");
187509
- const snapshot = (await store.list(scope, "snapshot")).find((entry) => entry.ref === previous3.manifestSnapshotRef);
187510
- if (!snapshot || snapshot.contentHash !== previous3.manifestHash || snapshot.contentHash !== sha256(snapshot.content)) return this.options.fail(409, "KNOWLEDGE_GENERATION_MANIFEST_CORRUPT", "\u4E0A\u4E00 Generation Manifest \u4E0D\u53EF\u8BFB");
187511
- const manifest = JSON.parse(snapshot.content);
187516
+ const snapshot2 = (await store.list(scope, "snapshot")).find((entry) => entry.ref === previous3.manifestSnapshotRef);
187517
+ if (!snapshot2 || snapshot2.contentHash !== previous3.manifestHash || snapshot2.contentHash !== sha256(snapshot2.content)) return this.options.fail(409, "KNOWLEDGE_GENERATION_MANIFEST_CORRUPT", "\u4E0A\u4E00 Generation Manifest \u4E0D\u53EF\u8BFB");
187518
+ const manifest = JSON.parse(snapshot2.content);
187512
187519
  const items = await store.list(scope, "item");
187513
187520
  const versions = new Map((await store.list(scope, "item_version")).map((entry) => [entry.id, entry]));
187514
187521
  const itemById = new Map(items.map((entry) => [entry.id, entry]));
@@ -188390,8 +188397,8 @@ var init_governance_service = __esm({
188390
188397
  for (const item of (await store.list(itemScope, "item")).filter((entry) => entry.currentApprovedVersionId)) {
188391
188398
  const version2 = versions.find((entry) => entry.id === item.currentApprovedVersionId);
188392
188399
  if (!version2) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_CONFIGURATION_VERSION_MISSING", `\u6B63\u5F0F\u77E5\u8BC6\u5F53\u524D\u7248\u672C\u4E0D\u5B58\u5728\uFF1A${item.id}`);
188393
- const snapshot = snapshots2.find((entry) => entry.ref === version2.contentSnapshotRef);
188394
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content)) {
188400
+ const snapshot2 = snapshots2.find((entry) => entry.ref === version2.contentSnapshotRef);
188401
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content)) {
188395
188402
  throw new KnowledgeGovernanceError(409, "KNOWLEDGE_CONFIGURATION_SNAPSHOT_INVALID", `\u6B63\u5F0F\u77E5\u8BC6\u7F3A\u5C11\u53EF\u9A8C\u8BC1\u5FEB\u7167\uFF0C\u4E0D\u80FD\u5B89\u5168\u5207\u6362\u4F4D\u7F6E\uFF1A${item.id}`);
188396
188403
  }
188397
188404
  const targetSpace = {
@@ -188416,7 +188423,7 @@ var init_governance_service = __esm({
188416
188423
  libraryRef: binding.libraryRef,
188417
188424
  rootRef: binding.rootRef
188418
188425
  });
188419
- const approvedBody = approvedSnapshotBody(version2.title, snapshot.content);
188426
+ const approvedBody = approvedSnapshotBody(version2.title, snapshot2.content);
188420
188427
  const written = await this.options.provider.writeApprovedDocument(connection, {
188421
188428
  jobId: `knowledge-cutover:${relocationKey}`,
188422
188429
  itemId: item.id,
@@ -189209,9 +189216,9 @@ var init_governance_service = __esm({
189209
189216
  const run = await store.get(scope, "discovery_run", runId);
189210
189217
  if (!run) continue;
189211
189218
  if (run.status !== "failed") throw new KnowledgeGovernanceError(409, "KNOWLEDGE_DISCOVERY_NOT_RETRYABLE", "\u53EA\u6709 failed Discovery Run \u53EF\u91CD\u8BD5");
189212
- const snapshot = (await store.list(scope, "snapshot")).find((entry) => entry.ref === run.analysisInputSnapshotRef);
189213
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content)) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_DISCOVERY_INPUT_UNREADABLE", "Discovery \u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB");
189214
- const input = JSON.parse(snapshot.content);
189219
+ const snapshot2 = (await store.list(scope, "snapshot")).find((entry) => entry.ref === run.analysisInputSnapshotRef);
189220
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content)) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_DISCOVERY_INPUT_UNREADABLE", "Discovery \u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB");
189221
+ const input = JSON.parse(snapshot2.content);
189215
189222
  const currentRuntime = await this.options.discoveryRuntime?.();
189216
189223
  if (!currentRuntime) throw new KnowledgeGovernanceError(503, "KNOWLEDGE_DISCOVERY_RUNTIME_UNAVAILABLE", "\u77E5\u8BC6\u53D1\u73B0\u6A21\u578B\u914D\u7F6E\u4E0D\u53EF\u7528");
189217
189224
  return this.enqueueDiscoveryEvent(ctx, {
@@ -189747,8 +189754,8 @@ var init_governance_service = __esm({
189747
189754
  const limit = sampleSize === void 0 ? snapshots2.length : Math.max(1, Math.min(Math.floor(sampleSize), snapshots2.length));
189748
189755
  const offset = snapshots2.length > 0 ? Math.floor(this.now().getTime() / 864e5) % snapshots2.length : 0;
189749
189756
  const selected = [...snapshots2.slice(offset), ...snapshots2.slice(0, offset)].slice(0, limit);
189750
- const corruptRefs = selected.filter((snapshot) => snapshot.contentHash !== sha256(snapshot.content)).map((snapshot) => snapshot.ref);
189751
- const existingRefs = new Set(snapshots2.map((snapshot) => snapshot.ref));
189757
+ const corruptRefs = selected.filter((snapshot2) => snapshot2.contentHash !== sha256(snapshot2.content)).map((snapshot2) => snapshot2.ref);
189758
+ const existingRefs = new Set(snapshots2.map((snapshot2) => snapshot2.ref));
189752
189759
  const referencedRefs = await this.snapshotReferences(store, scope);
189753
189760
  const missingRefs = [...referencedRefs].filter((ref2) => !existingRefs.has(ref2)).sort();
189754
189761
  const report = {
@@ -189780,19 +189787,19 @@ var init_governance_service = __esm({
189780
189787
  const snapshots2 = await store.list(scope, "snapshot");
189781
189788
  const referencedRefs = await this.snapshotReferences(store, scope);
189782
189789
  const now = this.now().getTime();
189783
- const expired = snapshots2.filter((snapshot) => snapshot.retentionUntil && Date.parse(snapshot.retentionUntil) <= now && !referencedRefs.has(snapshot.ref)).sort((left, right) => left.retentionUntil.localeCompare(right.retentionUntil) || left.ref.localeCompare(right.ref));
189790
+ const expired = snapshots2.filter((snapshot2) => snapshot2.retentionUntil && Date.parse(snapshot2.retentionUntil) <= now && !referencedRefs.has(snapshot2.ref)).sort((left, right) => left.retentionUntil.localeCompare(right.retentionUntil) || left.ref.localeCompare(right.ref));
189784
189791
  if (expired.length > 0) {
189785
189792
  const result = await store.transact(scope, {
189786
- checks: expired.map((snapshot) => ({ kind: "snapshot", id: snapshot.id, field: "retentionUntil", equals: snapshot.retentionUntil })),
189787
- deletes: expired.map((snapshot) => ({ kind: "snapshot", id: snapshot.id })),
189793
+ checks: expired.map((snapshot2) => ({ kind: "snapshot", id: snapshot2.id, field: "retentionUntil", equals: snapshot2.retentionUntil })),
189794
+ deletes: expired.map((snapshot2) => ({ kind: "snapshot", id: snapshot2.id })),
189788
189795
  puts: [put2("audit_event", this.audit(ctx, "snapshot.retention_deleted", "snapshot", "expired", void 0, {
189789
- deletedRefs: expired.map((snapshot) => snapshot.ref),
189790
- deletedContentHashes: expired.map((snapshot) => snapshot.contentHash)
189796
+ deletedRefs: expired.map((snapshot2) => snapshot2.ref),
189797
+ deletedContentHashes: expired.map((snapshot2) => snapshot2.contentHash)
189791
189798
  }, projectId2), "error")]
189792
189799
  });
189793
189800
  if (!result.committed) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_SNAPSHOT_RETENTION_CONFLICT", "Snapshot \u4FDD\u7559\u6E05\u7406\u9047\u5230\u5E76\u53D1\u53D8\u66F4");
189794
189801
  }
189795
- return { inspected: snapshots2.length, deletedRefs: expired.map((snapshot) => snapshot.ref) };
189802
+ return { inspected: snapshots2.length, deletedRefs: expired.map((snapshot2) => snapshot2.ref) };
189796
189803
  }
189797
189804
  async cancelPublishJob(ctx, jobId, projectId2) {
189798
189805
  if (projectId2) await this.authorizeProjectResource(ctx, projectId2, "review");
@@ -189845,7 +189852,7 @@ var init_governance_service = __esm({
189845
189852
  if (!candidate || candidate.decisionStatus !== "approved" || candidate.candidateRevision !== job.candidateRevision) {
189846
189853
  return this.failPublish(store, scope, job, "APPROVED_CANDIDATE_MISSING", true);
189847
189854
  }
189848
- const previewSnapshot = candidate.approvedPreviewSnapshotRef ? (await store.list(scope, "snapshot")).find((snapshot) => snapshot.ref === candidate.approvedPreviewSnapshotRef) : void 0;
189855
+ const previewSnapshot = candidate.approvedPreviewSnapshotRef ? (await store.list(scope, "snapshot")).find((snapshot2) => snapshot2.ref === candidate.approvedPreviewSnapshotRef) : void 0;
189849
189856
  if (!previewSnapshot || previewSnapshot.contentHash !== job.previewHash || candidate.approvedPreviewHash !== job.previewHash) {
189850
189857
  return this.failPublish(store, scope, job, "APPROVED_PREVIEW_MISSING", true);
189851
189858
  }
@@ -189934,8 +189941,8 @@ var init_governance_service = __esm({
189934
189941
  if (!version2) throw new KnowledgeGovernanceError(404, "KNOWLEDGE_VERSION_NOT_FOUND", "\u77E5\u8BC6\u7248\u672C\u4E0D\u5B58\u5728");
189935
189942
  const item = await store.get(scope, "item", version2.knowledgeItemId);
189936
189943
  if (!item || item.currentApprovedVersionId !== version2.id) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_VERSION_NOT_CURRENT", "\u77E5\u8BC6\u7248\u672C\u4E0D\u662F\u5F53\u524D\u6279\u51C6\u7248\u672C");
189937
- const snapshot = (await store.list(scope, "snapshot")).find((entry) => entry.ref === version2.contentSnapshotRef);
189938
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content)) {
189944
+ const snapshot2 = (await store.list(scope, "snapshot")).find((entry) => entry.ref === version2.contentSnapshotRef);
189945
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content)) {
189939
189946
  await this.setRuntimeState(store, scope, version2, "snapshot", "corrupt", "SNAPSHOT_HASH_MISMATCH");
189940
189947
  throw new KnowledgeGovernanceError(409, "KNOWLEDGE_SNAPSHOT_CORRUPT", "\u77E5\u8BC6\u5FEB\u7167\u635F\u574F");
189941
189948
  }
@@ -189946,7 +189953,7 @@ var init_governance_service = __esm({
189946
189953
  title: version2.title,
189947
189954
  abstract: version2.abstract,
189948
189955
  logicalPath: item.logicalPath,
189949
- content: snapshot.content
189956
+ content: snapshot2.content
189950
189957
  }).map((entry) => ({
189951
189958
  id: `${version2.id}:${entry.chunkId}:${indexKind}`,
189952
189959
  organizationId: ctx.organizationId,
@@ -190050,7 +190057,7 @@ var init_governance_service = __esm({
190050
190057
  const activeGeneration = (await store.list(entry.scope, "generation")).find((generation) => generation.status === "active");
190051
190058
  const activeDerivedVersionIds = /* @__PURE__ */ new Set();
190052
190059
  if (activeGeneration?.manifestSnapshotRef) {
190053
- const manifest = (await store.list(entry.scope, "snapshot")).find((snapshot) => snapshot.ref === activeGeneration.manifestSnapshotRef);
190060
+ const manifest = (await store.list(entry.scope, "snapshot")).find((snapshot2) => snapshot2.ref === activeGeneration.manifestSnapshotRef);
190054
190061
  if (!manifest || manifest.contentHash !== activeGeneration.manifestHash || manifest.contentHash !== sha256(manifest.content)) {
190055
190062
  warnings.push(`${entry.space.id}: active Generation Manifest \u4E0D\u53EF\u8BFB`);
190056
190063
  } else {
@@ -191279,7 +191286,7 @@ var init_governance_service = __esm({
191279
191286
  });
191280
191287
  const result = await store.transact(scope, {
191281
191288
  puts: [
191282
- ...snapshots2.map((snapshot) => put2("snapshot", snapshot, "error")),
191289
+ ...snapshots2.map((snapshot2) => put2("snapshot", snapshot2, "error")),
191283
191290
  put2("context_pack", pack, "error"),
191284
191291
  ...entries.map((entry) => put2("context_pack_entry", entry, "error")),
191285
191292
  ...usageEvents.map((event) => put2("usage_event", event, "error")),
@@ -191304,7 +191311,7 @@ var init_governance_service = __esm({
191304
191311
  throw new KnowledgeGovernanceError(403, "KNOWLEDGE_PACK_FORBIDDEN", "\u65E0\u6743\u67E5\u770B\u8BE5 Context Pack");
191305
191312
  }
191306
191313
  const entries = (await store.list(scope, "context_pack_entry")).filter((entry) => entry.contextPackId === pack.id).sort((left, right) => left.ordinal - right.ordinal);
191307
- const rendered = pack.renderedSnapshotRef ? (await store.list(scope, "snapshot")).find((snapshot) => snapshot.ref === pack.renderedSnapshotRef) : void 0;
191314
+ const rendered = pack.renderedSnapshotRef ? (await store.list(scope, "snapshot")).find((snapshot2) => snapshot2.ref === pack.renderedSnapshotRef) : void 0;
191308
191315
  if (rendered && rendered.contentHash !== sha256(rendered.content)) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_PACK_CORRUPT", "Context Pack \u6E32\u67D3\u5FEB\u7167 Hash \u4E0D\u4E00\u81F4");
191309
191316
  return { pack, entries, ...rendered ? { renderedContent: rendered.content } : {} };
191310
191317
  }
@@ -191537,9 +191544,9 @@ var init_governance_service = __esm({
191537
191544
  const current = await store.get(scope, "discovery_run", runId);
191538
191545
  if (!current) continue;
191539
191546
  if (current.status === "ready") return current;
191540
- const snapshot = (await store.list(scope, "snapshot")).find((entry) => entry.ref === current.analysisInputSnapshotRef);
191541
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content)) throw new Error("Discovery \u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB");
191542
- const input = JSON.parse(snapshot.content);
191547
+ const snapshot2 = (await store.list(scope, "snapshot")).find((entry) => entry.ref === current.analysisInputSnapshotRef);
191548
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content)) throw new Error("Discovery \u8F93\u5165\u5FEB\u7167\u4E0D\u53EF\u8BFB");
191549
+ const input = JSON.parse(snapshot2.content);
191543
191550
  const rule = input.rule;
191544
191551
  if (!rule || rule.id !== current.ruleId || rule.ruleVersion !== current.ruleVersion) throw new Error("Discovery \u6765\u6E90\u89C4\u5219\u5FEB\u7167\u4E0D\u53EF\u8BFB");
191545
191552
  if (space.status !== "active") throw new Error("Discovery Knowledge Space \u4E0D\u53EF\u7528");
@@ -192353,7 +192360,7 @@ var init_governance_service = __esm({
192353
192360
  const existing = await store.get(scope, "migration_batch", batchId);
192354
192361
  if (existing) {
192355
192362
  const entries2 = (await store.list(scope, "migration_entry")).filter((entry) => entry.batchId === existing.id);
192356
- const reportSnapshot2 = (await store.list(scope, "snapshot")).find((snapshot) => snapshot.ref === existing.reportSnapshotRef);
192363
+ const reportSnapshot2 = (await store.list(scope, "snapshot")).find((snapshot2) => snapshot2.ref === existing.reportSnapshotRef);
192357
192364
  return { batch: existing, entries: entries2, report: reportSnapshot2 ? JSON.parse(reportSnapshot2.content) : { manifestHash } };
192358
192365
  }
192359
192366
  const report = {
@@ -192471,7 +192478,7 @@ var init_governance_service = __esm({
192471
192478
  const result = await store.transact(scope, {
192472
192479
  puts: [
192473
192480
  put2("migration_batch", batch, "error"),
192474
- ...snapshots2.map((snapshot) => put2("snapshot", snapshot, "error")),
192481
+ ...snapshots2.map((snapshot2) => put2("snapshot", snapshot2, "error")),
192475
192482
  ...candidates.map((candidate) => put2("candidate", candidate, "error")),
192476
192483
  ...entries.map((entry) => put2("migration_entry", entry, "error")),
192477
192484
  put2("audit_event", this.audit(ctx, "migration.dry_run", "migration_batch", batch.id, void 0, { ...batch, manifestHash }, input.projectId), "error")
@@ -192539,7 +192546,7 @@ var init_governance_service = __esm({
192539
192546
  const connection = space ? await store.get(this.orgScope(ctx), "connector_connection", space.connectorConnectionId) : null;
192540
192547
  if (!space || !connection) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_MIGRATION_BINDING_MISSING", "\u8FC1\u79FB Space \u6216 Connection \u4E0D\u5B58\u5728");
192541
192548
  if (!batch.signatureSnapshotRef) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_MIGRATION_SIGNATURE_REQUIRED", "\u6CA1\u6709\u53EF\u5BA1\u8BA1\u7684 Hash \u6E05\u5355\u7B7E\u7F72");
192542
- const signature = (await store.list(scope, "snapshot")).find((snapshot) => snapshot.ref === batch.signatureSnapshotRef);
192549
+ const signature = (await store.list(scope, "snapshot")).find((snapshot2) => snapshot2.ref === batch.signatureSnapshotRef);
192543
192550
  if (!signature || signature.contentHash !== sha256(signature.content)) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_MIGRATION_SIGNATURE_CORRUPT", "\u8FC1\u79FB\u7B7E\u7F72\u5FEB\u7167\u4E0D\u53EF\u8BFB");
192544
192551
  const signedManifest = JSON.parse(signature.content);
192545
192552
  if (signedManifest.batchId !== batch.id) throw new KnowledgeGovernanceError(409, "KNOWLEDGE_MIGRATION_SIGNATURE_MISMATCH", "\u8FC1\u79FB\u7B7E\u7F72\u6279\u6B21\u4E0D\u5339\u914D");
@@ -192826,11 +192833,11 @@ var init_governance_service = __esm({
192826
192833
  if (!run || run.inputHash !== candidate.maintenanceInputHash) {
192827
192834
  throw new KnowledgeGovernanceError(409, "KNOWLEDGE_MAINTENANCE_INPUT_STALE", "\u7EF4\u62A4 Candidate \u5DF2\u8131\u79BB\u51BB\u7ED3\u8F93\u5165");
192828
192835
  }
192829
- const snapshot = (await store.list(scope, "snapshot")).find((entry) => entry.ref === run.inputSnapshotRef);
192830
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content) || snapshot.contentHash !== run.inputHash) {
192836
+ const snapshot2 = (await store.list(scope, "snapshot")).find((entry) => entry.ref === run.inputSnapshotRef);
192837
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content) || snapshot2.contentHash !== run.inputHash) {
192831
192838
  throw new KnowledgeGovernanceError(409, "KNOWLEDGE_MAINTENANCE_INPUT_UNREADABLE", "\u7EF4\u62A4 Candidate \u7684\u51BB\u7ED3\u8F93\u5165\u4E0D\u53EF\u8BFB");
192832
192839
  }
192833
- const input = JSON.parse(snapshot.content);
192840
+ const input = JSON.parse(snapshot2.content);
192834
192841
  const sourceById = new Map(input.currentApprovedSources.filter((source) => source.knowledgeRole === "source").map((source) => [source.versionId, source]));
192835
192842
  const derivedFromVersionIds = this.canonicalTargetIds(candidate.derivedFromVersionIds ?? []);
192836
192843
  const sources = derivedFromVersionIds.map((versionId) => sourceById.get(versionId));
@@ -193137,7 +193144,7 @@ var init_governance_service = __esm({
193137
193144
  const now = this.iso();
193138
193145
  const projectId2 = candidate.projectId;
193139
193146
  const normalizedContent = normalizeKnowledgeContent(preview2.title, approvedRevision.content);
193140
- const snapshot = this.snapshot(ctx, "approved_content", normalizedContent, projectId2, candidate.spaceId, `snapshot:approved:${job.allocatedVersionId}`);
193147
+ const snapshot2 = this.snapshot(ctx, "approved_content", normalizedContent, projectId2, candidate.spaceId, `snapshot:approved:${job.allocatedVersionId}`);
193141
193148
  const primary = targets[0];
193142
193149
  const updatesExistingItem = Boolean(primary && job.action === "revise");
193143
193150
  const priorVersions = updatesExistingItem && primary ? (await store.list(scope, "item_version")).filter((version3) => version3.knowledgeItemId === primary.id) : [];
@@ -193195,7 +193202,7 @@ var init_governance_service = __esm({
193195
193202
  semanticContentHash: semanticKnowledgeHash(preview2.title, approvedRevision.content),
193196
193203
  providerContentHash: approvedRevision.providerContentHash || providerKnowledgeHash(approvedRevision.content),
193197
193204
  contentNormalizerVersion: KNOWLEDGE_NORMALIZER_VERSION,
193198
- contentSnapshotRef: snapshot.ref,
193205
+ contentSnapshotRef: snapshot2.ref,
193199
193206
  changeType: job.action === "add" ? "initial" : job.action,
193200
193207
  changeSummary: candidate.recommendedReason,
193201
193208
  approvedBy: candidate.decidedBy,
@@ -193299,7 +193306,7 @@ var init_governance_service = __esm({
193299
193306
  const result = await store.transact(scope, {
193300
193307
  checks,
193301
193308
  puts: [
193302
- put2("snapshot", snapshot, "error"),
193309
+ put2("snapshot", snapshot2, "error"),
193303
193310
  put2("item", item, updatesExistingItem ? "replace" : "error"),
193304
193311
  ...superseded.map((target) => put2("item", target)),
193305
193312
  put2("item_version", version2, "error"),
@@ -193397,12 +193404,12 @@ var init_governance_service = __esm({
193397
193404
  await this.setRuntimeState(store, scope, version2, "provider", "missing", "APPROVED_REVISION_UNREADABLE");
193398
193405
  }
193399
193406
  }
193400
- const snapshot = (await store.list(scope, "snapshot")).find((entry) => entry.ref === version2.contentSnapshotRef);
193401
- if (!snapshot || snapshot.contentHash !== sha256(snapshot.content)) {
193402
- await this.setRuntimeState(store, scope, version2, "snapshot", snapshot ? "corrupt" : "missing", snapshot ? "SNAPSHOT_HASH_MISMATCH" : "SNAPSHOT_MISSING");
193407
+ const snapshot2 = (await store.list(scope, "snapshot")).find((entry) => entry.ref === version2.contentSnapshotRef);
193408
+ if (!snapshot2 || snapshot2.contentHash !== sha256(snapshot2.content)) {
193409
+ await this.setRuntimeState(store, scope, version2, "snapshot", snapshot2 ? "corrupt" : "missing", snapshot2 ? "SNAPSHOT_HASH_MISMATCH" : "SNAPSHOT_MISSING");
193403
193410
  throw new KnowledgeGovernanceError(409, "KNOWLEDGE_APPROVED_CONTENT_UNREADABLE", "\u6279\u51C6 Revision \u4E0E Snapshot \u5747\u4E0D\u53EF\u8BFB");
193404
193411
  }
193405
- return { content: snapshot.content, source: "snapshot" };
193412
+ return { content: snapshot2.content, source: "snapshot" };
193406
193413
  }
193407
193414
  async findItemAndVersion(ctx, store, projectId2, itemId) {
193408
193415
  const scopes = [this.orgScope(ctx), ...projectId2 ? [this.projectScope(ctx, projectId2)] : []];
@@ -195489,36 +195496,36 @@ function keyBytes(key) {
195489
195496
  if (value2.length !== 32) throw new Error("knowledge snapshot key must be 32 bytes");
195490
195497
  return value2;
195491
195498
  }
195492
- function aad(snapshot) {
195499
+ function aad(snapshot2) {
195493
195500
  return Buffer.from([
195494
- snapshot.organizationId,
195495
- snapshot.projectId ?? "organization",
195496
- snapshot.spaceId ?? "none",
195497
- snapshot.ref,
195498
- snapshot.contentHash
195501
+ snapshot2.organizationId,
195502
+ snapshot2.projectId ?? "organization",
195503
+ snapshot2.spaceId ?? "none",
195504
+ snapshot2.ref,
195505
+ snapshot2.contentHash
195499
195506
  ].join("\0"), "utf8");
195500
195507
  }
195501
- function sealKnowledgeSnapshot(snapshot, key) {
195502
- if (snapshot.content.startsWith(PREFIX)) return structuredClone(snapshot);
195508
+ function sealKnowledgeSnapshot(snapshot2, key) {
195509
+ if (snapshot2.content.startsWith(PREFIX)) return structuredClone(snapshot2);
195503
195510
  const iv = (0, import_node_crypto29.randomBytes)(12);
195504
195511
  const cipher = (0, import_node_crypto29.createCipheriv)("aes-256-gcm", keyBytes(key), iv);
195505
- cipher.setAAD(aad(snapshot));
195506
- const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
195512
+ cipher.setAAD(aad(snapshot2));
195513
+ const encrypted = Buffer.concat([cipher.update(snapshot2.content, "utf8"), cipher.final()]);
195507
195514
  return {
195508
- ...structuredClone(snapshot),
195515
+ ...structuredClone(snapshot2),
195509
195516
  content: `${PREFIX}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}`
195510
195517
  };
195511
195518
  }
195512
- function openKnowledgeSnapshot(snapshot, key) {
195513
- if (!snapshot.content.startsWith(PREFIX)) return structuredClone(snapshot);
195514
- const packed = snapshot.content.slice(PREFIX.length).split(".");
195515
- if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
195519
+ function openKnowledgeSnapshot(snapshot2, key) {
195520
+ if (!snapshot2.content.startsWith(PREFIX)) return structuredClone(snapshot2);
195521
+ const packed = snapshot2.content.slice(PREFIX.length).split(".");
195522
+ if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot2.ref} ciphertext is malformed`);
195516
195523
  const [iv, tag, data] = packed;
195517
195524
  const decipher = (0, import_node_crypto29.createDecipheriv)("aes-256-gcm", keyBytes(key), Buffer.from(iv, "base64url"));
195518
- decipher.setAAD(aad(snapshot));
195525
+ decipher.setAAD(aad(snapshot2));
195519
195526
  decipher.setAuthTag(Buffer.from(tag, "base64url"));
195520
195527
  const content3 = Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8");
195521
- return { ...structuredClone(snapshot), content: content3 };
195528
+ return { ...structuredClone(snapshot2), content: content3 };
195522
195529
  }
195523
195530
  var import_node_crypto29, PREFIX;
195524
195531
  var init_snapshot_crypto = __esm({
@@ -196265,9 +196272,9 @@ function parentConversationTaskLines() {
196265
196272
  `- ${PARENT_CONVERSATION_PATH}`
196266
196273
  ];
196267
196274
  }
196268
- function delegationBundleAdditions(snapshot) {
196269
- if (!snapshot) return { files: {}, taskLines: [] };
196270
- return { files: { [PARENT_CONVERSATION_PATH]: snapshot }, taskLines: parentConversationTaskLines() };
196275
+ function delegationBundleAdditions(snapshot2) {
196276
+ if (!snapshot2) return { files: {}, taskLines: [] };
196277
+ return { files: { [PARENT_CONVERSATION_PATH]: snapshot2 }, taskLines: parentConversationTaskLines() };
196271
196278
  }
196272
196279
  var PARENT_CONVERSATION_RECENT_TURNS, FIRST_LINE_MAX, ROLE_LABEL;
196273
196280
  var init_parent_conversation = __esm({
@@ -196985,13 +196992,13 @@ var init_service3 = __esm({
196985
196992
  consumedAt: now,
196986
196993
  at: now
196987
196994
  });
196988
- const snapshot = buildParentConversationSnapshot(
196995
+ const snapshot2 = buildParentConversationSnapshot(
196989
196996
  parentMessages,
196990
196997
  this.options.recentTurns === void 0 ? void 0 : { recentTurns: this.options.recentTurns }
196991
196998
  );
196992
196999
  const turns = await this.resolveTurns(companyId);
196993
197000
  const claimed = await this.claim(store, record8.id, now, Boolean(turns));
196994
- if (claimed) this.track(this.dispatchExpert(claimed, input.task, companyId, snapshot, turns, { inbound }));
197001
+ if (claimed) this.track(this.dispatchExpert(claimed, input.task, companyId, snapshot2, turns, { inbound }));
196995
197002
  if (inserted) this.options.metrics?.recordCreated();
196996
197003
  return { record: record8, created: inserted };
196997
197004
  }
@@ -197025,10 +197032,10 @@ var init_service3 = __esm({
197025
197032
  const expert = { actorId: record8.expertActorId, name: named?.name ?? actorSlug(record8.expertActorId) };
197026
197033
  const now = this.now();
197027
197034
  await this.materializeChild({ record: record8, chatStore, parent, expert, task: input.task, companyId, now });
197028
- const snapshot = await this.parentSnapshot(chatStore, parent.id);
197035
+ const snapshot2 = await this.parentSnapshot(chatStore, parent.id);
197029
197036
  const turns = await this.resolveTurns(companyId);
197030
197037
  const claimed = await this.claim(store, record8.id, now, Boolean(turns));
197031
- if (claimed) this.track(this.dispatchExpert(claimed, input.task, companyId, snapshot, turns, { inbound }));
197038
+ if (claimed) this.track(this.dispatchExpert(claimed, input.task, companyId, snapshot2, turns, { inbound }));
197032
197039
  return { record: record8, created: false };
197033
197040
  }
197034
197041
  async materializeChild(args) {
@@ -197103,7 +197110,7 @@ var init_service3 = __esm({
197103
197110
  * 覆盖事实——而且是**不可逆的**:`failed` 之后租约回收再也不成立,那条既有 run 接不回来。
197104
197111
  * 那一类只释放派发所有权、其余原样留着,等账本恢复后由同一把稳定 dispatchId 接回去。
197105
197112
  */
197106
- async dispatchExpert(record8, task, companyId, snapshot, turns, opts) {
197113
+ async dispatchExpert(record8, task, companyId, snapshot2, turns, opts) {
197107
197114
  const inbound = opts?.inbound;
197108
197115
  let outcomeSettled = false;
197109
197116
  const notDispatched = async (reason) => {
@@ -197160,7 +197167,7 @@ var init_service3 = __esm({
197160
197167
  chatSessionId: record8.childSessionId,
197161
197168
  dispatchId,
197162
197169
  ...companyId ? { companyId } : {},
197163
- ...snapshot ? { parentConversationSnapshot: snapshot } : {},
197170
+ ...snapshot2 ? { parentConversationSnapshot: snapshot2 } : {},
197164
197171
  extraSystemPrompt: EXPERT_DELEGATION_SYSTEM_PROMPT,
197165
197172
  ..._DelegationService.inboundBundle(inbound) ? { workspaceBundle: _DelegationService.inboundBundle(inbound) } : {},
197166
197173
  /* 派发这一侧要拿它们建 `chat_items` 账本(见本文件 `DelegationDispatchRequest` 的注释)。
@@ -197445,7 +197452,7 @@ var init_service3 = __esm({
197445
197452
  },
197446
197453
  wantedFiles
197447
197454
  ) : void 0;
197448
- const snapshot = await this.parentSnapshot(chatStore, record8.parentSessionId).catch(() => null);
197455
+ const snapshot2 = await this.parentSnapshot(chatStore, record8.parentSessionId).catch(() => null);
197449
197456
  const released = await store.patch(record8.id, {
197450
197457
  state: "running",
197451
197458
  failureKind: null,
@@ -197478,7 +197485,7 @@ var init_service3 = __esm({
197478
197485
  await restore();
197479
197486
  return false;
197480
197487
  }
197481
- this.track(this.dispatchExpert(claimed, body2, companyId, snapshot, turns, {
197488
+ this.track(this.dispatchExpert(claimed, body2, companyId, snapshot2, turns, {
197482
197489
  ...inbound ? { inbound } : {},
197483
197490
  /**
197484
197491
  * **送到专家手上那一刻才算消费**(见 `dispatchExpert` 的 `onDispatched`)。
@@ -197586,7 +197593,7 @@ var init_service3 = __esm({
197586
197593
  const now = this.now();
197587
197594
  const messages = await this.parentMessages(chatStore, parent.id);
197588
197595
  const messageId = this.touchAnchor(_DelegationService.birthMessageId(messages) || record8.id);
197589
- const snapshot = buildParentConversationSnapshot(
197596
+ const snapshot2 = buildParentConversationSnapshot(
197590
197597
  messages,
197591
197598
  this.options.recentTurns === void 0 ? void 0 : { recentTurns: this.options.recentTurns }
197592
197599
  );
@@ -197606,7 +197613,7 @@ var init_service3 = __esm({
197606
197613
  \u3010\u968F\u8FD9\u6761\u8F6C\u8FBE\u9644\u5E26\u7684\u6587\u4EF6\u3011\u5DF2\u653E\u8FDB\u4F60\u7684\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u53EF\u76F4\u63A5\u8BFB\u53D6\uFF1A
197607
197614
  ${inboundBundle.paths.map((path43) => `- ${path43}`).join("\n")}` : text5,
197608
197615
  files: {
197609
- ...snapshot ? { [PARENT_CONVERSATION_PATH]: snapshot } : {},
197616
+ ...snapshot2 ? { [PARENT_CONVERSATION_PATH]: snapshot2 } : {},
197610
197617
  ...inboundBundle.files
197611
197618
  },
197612
197619
  ...Object.keys(inboundBundle.binaryFiles).length ? { binaryFiles: inboundBundle.binaryFiles } : {}
@@ -197691,9 +197698,9 @@ ${inboundBundle.paths.map((path43) => `- ${path43}`).join("\n")}` : text5,
197691
197698
  const record8 = await store.get(delegationId);
197692
197699
  if (!record8) return null;
197693
197700
  const chatStore = await this.options.resolveChatSessions(companyId);
197694
- const snapshot = await this.parentSnapshot(chatStore, record8.parentSessionId);
197701
+ const snapshot2 = await this.parentSnapshot(chatStore, record8.parentSessionId);
197695
197702
  return {
197696
- ...snapshot ? { parentConversationSnapshot: snapshot } : {},
197703
+ ...snapshot2 ? { parentConversationSnapshot: snapshot2 } : {},
197697
197704
  extraSystemPrompt: EXPERT_DELEGATION_SYSTEM_PROMPT
197698
197705
  };
197699
197706
  }
@@ -198080,11 +198087,11 @@ var init_store2 = __esm({
198080
198087
  return store;
198081
198088
  }
198082
198089
  save() {
198083
- const snapshot = {
198090
+ const snapshot2 = {
198084
198091
  delegations: [...this.rows.values()],
198085
198092
  touches: [...this.touches.values()]
198086
198093
  };
198087
- fs17.writeFileSync(this.file, JSON.stringify(snapshot, null, 2));
198094
+ fs17.writeFileSync(this.file, JSON.stringify(snapshot2, null, 2));
198088
198095
  }
198089
198096
  async create(record8) {
198090
198097
  const r = await super.create(record8);
@@ -201415,8 +201422,8 @@ async function loadSnapshot(api, credentials, scope, force = false) {
201415
201422
  const now = Date.now();
201416
201423
  const entry = snapshots.get(key);
201417
201424
  if (force) {
201418
- const snapshot2 = await startSnapshotRefresh(api, credentials, scope);
201419
- return { snapshot: snapshot2, status: "refreshed", ageMs: Math.max(0, Date.now() - snapshot2.loadedAt) };
201425
+ const snapshot3 = await startSnapshotRefresh(api, credentials, scope);
201426
+ return { snapshot: snapshot3, status: "refreshed", ageMs: Math.max(0, Date.now() - snapshot3.loadedAt) };
201420
201427
  }
201421
201428
  if (entry?.value && entry.freshUntil > now) {
201422
201429
  return { snapshot: entry.value, status: "fresh", ageMs: Math.max(0, now - entry.value.loadedAt) };
@@ -201425,8 +201432,8 @@ async function loadSnapshot(api, credentials, scope, force = false) {
201425
201432
  void startSnapshotRefresh(api, credentials, scope).catch(() => void 0);
201426
201433
  return { snapshot: entry.value, status: "stale", ageMs: Math.max(0, now - entry.value.loadedAt) };
201427
201434
  }
201428
- const snapshot = await startSnapshotRefresh(api, credentials, scope);
201429
- return { snapshot, status: "miss", ageMs: Math.max(0, Date.now() - snapshot.loadedAt) };
201435
+ const snapshot2 = await startSnapshotRefresh(api, credentials, scope);
201436
+ return { snapshot: snapshot2, status: "miss", ageMs: Math.max(0, Date.now() - snapshot2.loadedAt) };
201430
201437
  }
201431
201438
  function invalidateOutlineKnowledgeCache(credentials, scope) {
201432
201439
  snapshots.delete(snapshotKey(credentials, scope));
@@ -201439,9 +201446,9 @@ function evidenceLevel2(path43) {
201439
201446
  if (["wiki/index", "wiki/overview", "wiki/sources"].includes(path43)) return "index";
201440
201447
  return "other";
201441
201448
  }
201442
- function snapshotMatches(snapshot, plannedQueries) {
201449
+ function snapshotMatches(snapshot2, plannedQueries) {
201443
201450
  return plannedQueries.map((query) => {
201444
- const nodes = [...snapshot.byId.values()].filter((node2) => node2.path && node2.path !== "raw" && !node2.path.startsWith("raw/"));
201451
+ const nodes = [...snapshot2.byId.values()].filter((node2) => node2.path && node2.path !== "raw" && !node2.path.startsWith("raw/"));
201445
201452
  const queryTerms = lexicalTerms(query.text);
201446
201453
  const titleScores = bm25Scores(queryTerms, nodes.map((node2) => node2.title));
201447
201454
  const pathScores = bm25Scores(queryTerms, nodes.map((node2) => node2.path));
@@ -201484,16 +201491,16 @@ function mergeSearchCandidates(apiResults, localResults) {
201484
201491
  return { status: "fulfilled", value: [...merged.values()] };
201485
201492
  });
201486
201493
  }
201487
- function rankCandidates(results, snapshot, plannedQueries) {
201494
+ function rankCandidates(results, snapshot2, plannedQueries) {
201488
201495
  const merged = /* @__PURE__ */ new Map();
201489
201496
  results.forEach((result, queryIndex) => {
201490
201497
  if (result.status !== "fulfilled") return;
201491
201498
  result.value.forEach((document4, sourceIndex) => {
201492
201499
  const ref2 = string6(document4["id"]);
201493
- const node2 = ref2 ? snapshot.byId.get(ref2) : void 0;
201500
+ const node2 = ref2 ? snapshot2.byId.get(ref2) : void 0;
201494
201501
  const title = string6(document4["title"]);
201495
201502
  const url = string6(document4["url"]) ?? "";
201496
- if (!ref2 || !node2 || !title || !snapshot.scopedIds.has(ref2) || node2.path === "raw" || node2.path.startsWith("raw/")) return;
201503
+ if (!ref2 || !node2 || !title || !snapshot2.scopedIds.has(ref2) || node2.path === "raw" || node2.path.startsWith("raw/")) return;
201497
201504
  const sourceRank = sourceIndex + 1;
201498
201505
  const candidateSource = document4["candidateSource"] === "snapshot" ? "snapshot" : "api";
201499
201506
  const sources = document4["candidateSource"] === "hybrid" ? /* @__PURE__ */ new Set(["api", "snapshot"]) : /* @__PURE__ */ new Set([candidateSource]);
@@ -201558,7 +201565,7 @@ async function mapConcurrent(values, limit, mapper) {
201558
201565
  await Promise.all(workers);
201559
201566
  return results;
201560
201567
  }
201561
- async function readCandidates(api, credentials, scope, snapshot, candidates, limit = MAX_READ_CANDIDATES) {
201568
+ async function readCandidates(api, credentials, scope, snapshot2, candidates, limit = MAX_READ_CANDIDATES) {
201562
201569
  let refreshed;
201563
201570
  const values = await mapConcurrent(candidates.slice(0, limit), READ_CONCURRENCY, async (candidate) => {
201564
201571
  try {
@@ -201570,7 +201577,7 @@ async function readCandidates(api, credentials, scope, snapshot, candidates, lim
201570
201577
  const parentDocumentId = string6(document4["parentDocumentId"]);
201571
201578
  if (collectionId !== scope.libraryRef || !url || !text5 || !updatedAt) return null;
201572
201579
  if (new URL(url).origin !== new URL(api.baseUrl).origin) return null;
201573
- let activeSnapshot = snapshot;
201580
+ let activeSnapshot = snapshot2;
201574
201581
  const listed = activeSnapshot.byId.get(candidate.ref);
201575
201582
  if (!listed || listed.updatedAt !== updatedAt || listed.parentId !== parentDocumentId) {
201576
201583
  refreshed ??= loadSnapshot(api, credentials, scope, true).then((loaded) => loaded.snapshot);
@@ -201612,12 +201619,12 @@ function snapshotRankedCandidate(node2, queryIndexes, score) {
201612
201619
  evidenceLevel: evidenceLevel2(node2.path)
201613
201620
  };
201614
201621
  }
201615
- function routingPageCandidates(snapshot, queryCount) {
201622
+ function routingPageCandidates(snapshot2, queryCount) {
201616
201623
  const paths = /* @__PURE__ */ new Set(["wiki/overview", "wiki/index"]);
201617
- return [...snapshot.byId.values()].filter((node2) => paths.has(node2.path.toLocaleLowerCase())).map((node2) => snapshotRankedCandidate(node2, new Set(Array.from({ length: queryCount }, (_2, index2) => index2)), 0.05));
201624
+ return [...snapshot2.byId.values()].filter((node2) => paths.has(node2.path.toLocaleLowerCase())).map((node2) => snapshotRankedCandidate(node2, new Set(Array.from({ length: queryCount }, (_2, index2) => index2)), 0.05));
201618
201625
  }
201619
- function linkedCandidates(documents, snapshot, queries, excludedRefs) {
201620
- const byPath = new Map([...snapshot.byId.values()].map((node2) => [node2.path.toLocaleLowerCase(), node2]));
201626
+ function linkedCandidates(documents, snapshot2, queries, excludedRefs) {
201627
+ const byPath = new Map([...snapshot2.byId.values()].map((node2) => [node2.path.toLocaleLowerCase(), node2]));
201621
201628
  const ranked = /* @__PURE__ */ new Map();
201622
201629
  for (const document4 of documents) {
201623
201630
  for (const match of document4.text.matchAll(/\[([^\]]+)\]\(kb:\/\/([^\s)#]+)(?:#[^)]*)?\)/gu)) {
@@ -201834,35 +201841,35 @@ async function retrieveOutlineKnowledge(credentials, scope, request2) {
201834
201841
  const snapshotStartedAt = performance.now();
201835
201842
  let loadedSnapshot = await loadSnapshot(api, credentials, scope);
201836
201843
  request2.signal?.throwIfAborted();
201837
- let snapshot = loadedSnapshot.snapshot;
201844
+ let snapshot2 = loadedSnapshot.snapshot;
201838
201845
  let snapshotMs = performance.now() - snapshotStartedAt;
201839
201846
  const searchStartedAt = performance.now();
201840
201847
  const searchResults = await Promise.allSettled(effectiveQueries.map((query) => api.searchDocuments(scope.libraryRef, query.text)));
201841
201848
  request2.signal?.throwIfAborted();
201842
201849
  const apiCandidateRefs = new Set(searchResults.flatMap((result) => result.status === "fulfilled" ? result.value.map((document4) => string6(document4["id"])).filter((ref2) => Boolean(ref2)) : []));
201843
201850
  const emptySearchCount = searchResults.filter((result) => result.status === "fulfilled" && result.value.length === 0).length;
201844
- let localResults = snapshotMatches(snapshot, effectiveQueries);
201851
+ let localResults = snapshotMatches(snapshot2, effectiveQueries);
201845
201852
  let snapshotCandidateRefs = new Set(localResults.flatMap((documents2) => documents2.map((document4) => string6(document4["id"])).filter((ref2) => Boolean(ref2))));
201846
- let ranked = rankCandidates(mergeSearchCandidates(searchResults, localResults), snapshot, effectiveQueries);
201853
+ let ranked = rankCandidates(mergeSearchCandidates(searchResults, localResults), snapshot2, effectiveQueries);
201847
201854
  let retrievalRounds = 1;
201848
201855
  let recoveryReason;
201849
201856
  if (ranked.length === 0) {
201850
201857
  const refreshStartedAt = performance.now();
201851
201858
  loadedSnapshot = await loadSnapshot(api, credentials, scope, true);
201852
- snapshot = loadedSnapshot.snapshot;
201859
+ snapshot2 = loadedSnapshot.snapshot;
201853
201860
  snapshotMs += performance.now() - refreshStartedAt;
201854
- localResults = snapshotMatches(snapshot, effectiveQueries);
201861
+ localResults = snapshotMatches(snapshot2, effectiveQueries);
201855
201862
  snapshotCandidateRefs = new Set(localResults.flatMap((documents2) => documents2.map((document4) => string6(document4["id"])).filter((ref2) => Boolean(ref2))));
201856
- ranked = rankCandidates(mergeSearchCandidates(searchResults, localResults), snapshot, effectiveQueries);
201863
+ ranked = rankCandidates(mergeSearchCandidates(searchResults, localResults), snapshot2, effectiveQueries);
201857
201864
  retrievalRounds = 2;
201858
201865
  recoveryReason = "empty_candidates";
201859
201866
  }
201860
201867
  const searchMs = performance.now() - searchStartedAt;
201861
201868
  const readStartedAt = performance.now();
201862
201869
  request2.signal?.throwIfAborted();
201863
- let documents = await readCandidates(api, credentials, scope, snapshot, ranked, INITIAL_READ_CANDIDATES);
201870
+ let documents = await readCandidates(api, credentials, scope, snapshot2, ranked, INITIAL_READ_CANDIDATES);
201864
201871
  if (documents.length === 0) {
201865
- const routingPages = await readCandidates(api, credentials, scope, snapshot, routingPageCandidates(snapshot, effectiveQueries.length), 2);
201872
+ const routingPages = await readCandidates(api, credentials, scope, snapshot2, routingPageCandidates(snapshot2, effectiveQueries.length), 2);
201866
201873
  documents = routingPages;
201867
201874
  retrievalRounds = 2;
201868
201875
  recoveryReason ??= "insufficient_coverage";
@@ -201879,9 +201886,9 @@ async function retrieveOutlineKnowledge(credentials, scope, request2) {
201879
201886
  const needsRouting = initialSelection.items.length === 0 || initialSelection.items.every((item) => item.evidenceLevel === "index") || initialMissing.length > 0;
201880
201887
  if (needsRouting && documents.length < MAX_READ_CANDIDATES) {
201881
201888
  const existingRefs = new Set(documents.map((document4) => document4.ref));
201882
- const linked = linkedCandidates(documents, snapshot, effectiveQueries, existingRefs);
201889
+ const linked = linkedCandidates(documents, snapshot2, effectiveQueries, existingRefs);
201883
201890
  const remaining = MAX_READ_CANDIDATES - documents.length;
201884
- const linkedDocuments = await readCandidates(api, credentials, scope, snapshot, linked, remaining);
201891
+ const linkedDocuments = await readCandidates(api, credentials, scope, snapshot2, linked, remaining);
201885
201892
  if (linkedDocuments.length > 0) documents = [...documents, ...linkedDocuments];
201886
201893
  retrievalRounds = 2;
201887
201894
  recoveryReason ??= "insufficient_coverage";
@@ -201936,7 +201943,7 @@ async function retrieveOutlineKnowledge(credentials, scope, request2) {
201936
201943
  async function validateOutlineKnowledgeCitationsFast(credentials, scope, candidates) {
201937
201944
  if (candidates.length === 0) return [];
201938
201945
  const api = new OutlineKnowledgeApi(credentials);
201939
- let snapshot = (await loadSnapshot(api, credentials, scope)).snapshot;
201946
+ let snapshot2 = (await loadSnapshot(api, credentials, scope)).snapshot;
201940
201947
  let refreshed;
201941
201948
  const seen = /* @__PURE__ */ new Set();
201942
201949
  const unique4 = candidates.filter((candidate) => {
@@ -201945,7 +201952,7 @@ async function validateOutlineKnowledgeCitationsFast(credentials, scope, candida
201945
201952
  return true;
201946
201953
  }).slice(0, 20);
201947
201954
  const validated = await mapConcurrent(unique4, READ_CONCURRENCY, async (candidate) => {
201948
- if (!snapshot.scopedIds.has(candidate.ref)) return null;
201955
+ if (!snapshot2.scopedIds.has(candidate.ref)) return null;
201949
201956
  try {
201950
201957
  const document4 = await api.documentInfo(candidate.ref);
201951
201958
  const ref2 = string6(document4["id"]);
@@ -201956,12 +201963,12 @@ async function validateOutlineKnowledgeCitationsFast(credentials, scope, candida
201956
201963
  const parentDocumentId = string6(document4["parentDocumentId"]);
201957
201964
  if (!ref2 || !title || !url || collectionId !== scope.libraryRef) return null;
201958
201965
  if (new URL(url).origin !== new URL(api.baseUrl).origin) return null;
201959
- const listed = snapshot.byId.get(ref2);
201966
+ const listed = snapshot2.byId.get(ref2);
201960
201967
  if (!listed || updatedAt && listed.updatedAt !== updatedAt || listed.parentId !== parentDocumentId) {
201961
201968
  refreshed ??= loadSnapshot(api, credentials, scope, true).then((loaded) => loaded.snapshot);
201962
- snapshot = await refreshed;
201969
+ snapshot2 = await refreshed;
201963
201970
  }
201964
- if (!snapshot.scopedIds.has(ref2)) return null;
201971
+ if (!snapshot2.scopedIds.has(ref2)) return null;
201965
201972
  return { ref: ref2, title, url, ...updatedAt ? { updatedAt } : {} };
201966
201973
  } catch {
201967
201974
  return null;
@@ -205576,6 +205583,26 @@ async function startOasisServer(opts) {
205576
205583
  );
205577
205584
  return;
205578
205585
  }
205586
+ if (opts.isDispatchFenced && (req.method !== "GET" && req.method !== "HEAD" || url.pathname === "/api/whoami")) {
205587
+ const token = (req.headers.authorization ?? "").replace(/^Bearer /, "");
205588
+ const claims = opts.resolveTokenClaims?.(token);
205589
+ let fenced = false;
205590
+ if (claims?.dispatchId) {
205591
+ try {
205592
+ fenced = await opts.isDispatchFenced(claims.dispatchId);
205593
+ } catch {
205594
+ res.writeHead(503, { "content-type": "application/json" }).end(JSON.stringify({ error: {
205595
+ code: "EXECUTION_STATE_UNAVAILABLE",
205596
+ message: "\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u6267\u884C\u8F6E\u6B21\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
205597
+ } }));
205598
+ return;
205599
+ }
205600
+ }
205601
+ if (fenced) {
205602
+ res.writeHead(409, { "content-type": "application/json" }).end(JSON.stringify({ error: { code: "DISPATCH_FENCED", message: "\u672C\u8F6E\u6267\u884C\u5DF2\u5931\u6548\uFF0C\u8BF7\u505C\u6B62\u8FD0\u884C\uFF1B\u540C\u4E00\u4EFB\u52A1\u53EA\u6709\u6700\u65B0\u4E00\u8F6E\u53EF\u4EE5\u542F\u52A8\u548C\u63D0\u4EA4\u7ED3\u679C\u3002" } }));
205603
+ return;
205604
+ }
205605
+ }
205579
205606
  if (url.pathname === "/api/whoami" && req.method === "GET") {
205580
205607
  res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ actor }));
205581
205608
  return;
@@ -205688,7 +205715,7 @@ async function startOasisServer(opts) {
205688
205715
  const bearerToken = (req.headers.authorization ?? "").startsWith("Bearer ") ? req.headers.authorization.slice("Bearer ".length) : "";
205689
205716
  const tokenClaims = bearerToken && opts.resolveTokenClaims ? opts.resolveTokenClaims(bearerToken) : null;
205690
205717
  if (opts.isDispatchFenced && tokenClaims?.dispatchId) {
205691
- const fenced = await opts.isDispatchFenced(tokenClaims.dispatchId).catch(() => false);
205718
+ const fenced = await opts.isDispatchFenced(tokenClaims.dispatchId);
205692
205719
  if (fenced) {
205693
205720
  throw new ApiError(
205694
205721
  409,
@@ -207756,13 +207783,13 @@ ${composed}`;
207756
207783
  const actorCtx = await opts.resolveActorContext(body2.actorId).catch(() => null);
207757
207784
  if (actorCtx) {
207758
207785
  const { mkdtempSync: mkdtempSync6, mkdirSync: mkdirSync27, writeFileSync: writeFileSync20 } = await import("node:fs");
207759
- const { join: join42, dirname: dirname38 } = await import("node:path");
207786
+ const { join: join42, dirname: dirname37 } = await import("node:path");
207760
207787
  const { tmpdir: tmpdir13 } = await import("node:os");
207761
207788
  const dir = mkdtempSync6(join42(tmpdir13(), "oasis-chat-"));
207762
207789
  if (actorCtx.config?.prompt) {
207763
207790
  for (const [rel, content3] of Object.entries(splitIdentityFiles2(actorCtx.config.prompt))) {
207764
207791
  const file = join42(dir, rel);
207765
- mkdirSync27(dirname38(file), { recursive: true });
207792
+ mkdirSync27(dirname37(file), { recursive: true });
207766
207793
  writeFileSync20(file, content3);
207767
207794
  }
207768
207795
  }
@@ -207779,7 +207806,7 @@ ${composed}`;
207779
207806
  const skillFiles = await opts.materializeSkills(body2.actorId, "claude").catch(() => ({}));
207780
207807
  for (const [rel, content3] of Object.entries(skillFiles)) {
207781
207808
  const file = join42(dir, rel);
207782
- mkdirSync27(dirname38(file), { recursive: true });
207809
+ mkdirSync27(dirname37(file), { recursive: true });
207783
207810
  writeFileSync20(file, content3);
207784
207811
  }
207785
207812
  }
@@ -210215,8 +210242,8 @@ var init_memory_trace_store = __esm({
210215
210242
  handoffs: [...this.handoffs.values()].map((x2) => structuredClone(x2))
210216
210243
  };
210217
210244
  }
210218
- restoreContinuity(snapshot) {
210219
- for (const checkpoint of snapshot.checkpoints ?? []) {
210245
+ restoreContinuity(snapshot2) {
210246
+ for (const checkpoint of snapshot2.checkpoints ?? []) {
210220
210247
  const run = this.runs.get(checkpoint.attemptId);
210221
210248
  const list2 = this.checkpoints.get(checkpoint.attemptId) ?? [];
210222
210249
  list2.push(structuredClone({
@@ -210231,7 +210258,7 @@ var init_memory_trace_store = __esm({
210231
210258
  const n = Number(checkpoint.checkpointId.replace(/^checkpoint_/, ""));
210232
210259
  if (Number.isFinite(n)) this.checkpointIdCounter = Math.max(this.checkpointIdCounter, n);
210233
210260
  }
210234
- for (const effect of snapshot.externalEffects ?? []) {
210261
+ for (const effect of snapshot2.externalEffects ?? []) {
210235
210262
  this.externalEffects.set(`${effect.nodeId}\0${effect.idempotencyKey}`, structuredClone({
210236
210263
  ...effect,
210237
210264
  status: effect.status ?? "succeeded",
@@ -210239,7 +210266,7 @@ var init_memory_trace_store = __esm({
210239
210266
  occurredAt: effect.occurredAt ?? null
210240
210267
  }));
210241
210268
  }
210242
- for (const handoff of snapshot.handoffs ?? []) {
210269
+ for (const handoff of snapshot2.handoffs ?? []) {
210243
210270
  const run = this.runs.get(handoff.attemptId);
210244
210271
  this.handoffs.set(handoff.attemptId, structuredClone({
210245
210272
  ...handoff,
@@ -219218,6 +219245,7 @@ var init_daemon_hub = __esm({
219218
219245
  /** 外部可订阅的事件回调 */
219219
219246
  onDaemonConnected;
219220
219247
  onDaemonDisconnected;
219248
+ executionIsCurrent;
219221
219249
  onMessage;
219222
219250
  messageListeners = /* @__PURE__ */ new Set();
219223
219251
  requireExecutionStopPersistence;
@@ -219247,6 +219275,13 @@ var init_daemon_hub = __esm({
219247
219275
  });
219248
219276
  });
219249
219277
  }
219278
+ async acceptExecutionFrame(nodeId, msg) {
219279
+ if (msg.type !== "session_started" && msg.type !== "dispatch_received" || !this.executionIsCurrent) return true;
219280
+ if (await this.executionIsCurrent(msg.dispatchId)) return true;
219281
+ const kill = { type: "kill", dispatchId: msg.dispatchId };
219282
+ if (!this.sendToSession(msg.dispatchId, kill)) this.dispatch(nodeId, kill);
219283
+ return false;
219284
+ }
219250
219285
  async persistExecutionStop(nodeId, msg) {
219251
219286
  if (msg.type !== "session_exited" || msg.executionStopped !== true) return;
219252
219287
  if (this.requireExecutionStopPersistence && this.executionStopListeners.size === 0) throw new Error("\u505C\u6B62\u8BC1\u660E\u5B58\u50A8\u5668\u5C1A\u672A\u5C31\u7EEA");
@@ -219431,6 +219466,9 @@ var init_daemon_hub = __esm({
219431
219466
  ws.close(1008, "session identity mismatch");
219432
219467
  return;
219433
219468
  }
219469
+ if (this.executionIsCurrent && !await this.executionIsCurrent(dispatchId)) {
219470
+ ws.send(JSON.stringify({ type: "kill", dispatchId }));
219471
+ }
219434
219472
  if (!registered) {
219435
219473
  registered = true;
219436
219474
  this.sessionSockets.set(dispatchId, ws);
@@ -219458,6 +219496,7 @@ var init_daemon_hub = __esm({
219458
219496
  ws.close(1008, "session identity mismatch");
219459
219497
  return;
219460
219498
  }
219499
+ if (!await this.acceptExecutionFrame(nodeId, msg)) return;
219461
219500
  await this.persistExecutionStop(nodeId, msg);
219462
219501
  if (this.frameSeqSupported.has(dispatchId)) {
219463
219502
  const seq = typeof msg.seq === "number" ? msg.seq : void 0;
@@ -219732,6 +219771,7 @@ var init_daemon_hub = __esm({
219732
219771
  for (const listener of this.connectListeners) listener(daemon);
219733
219772
  }
219734
219773
  }
219774
+ if (!await this.acceptExecutionFrame(daemonId, msg)) return;
219735
219775
  await this.persistExecutionStop(daemonId, msg);
219736
219776
  this.onMessage?.(daemonId, msg);
219737
219777
  for (const listener of this.messageListeners) listener(daemonId, msg);
@@ -221033,8 +221073,8 @@ ${input.description}
221033
221073
  * 密文原样搬运,不经解密再加密——少一次明文落到内存里,也不受密钥轮换影响。
221034
221074
  * 返回改了几行,调用方好把「回滚做了什么」如实说出来(回滚静默是上一版的毛病)。
221035
221075
  */
221036
- async restoreActorConnectorVars(actorId, connectorId, snapshot) {
221037
- const keep = new Map(snapshot.map((r) => [r.key, r]));
221076
+ async restoreActorConnectorVars(actorId, connectorId, snapshot2) {
221077
+ const keep = new Map(snapshot2.map((r) => [r.key, r]));
221038
221078
  const now = await this.snapshotActorConnectorVars(actorId, connectorId);
221039
221079
  let removed = 0;
221040
221080
  for (const row of now) {
@@ -225117,53 +225157,6 @@ var init_routes5 = __esm({
225117
225157
  }
225118
225158
  });
225119
225159
 
225120
- // ../server/src/domains/collab/execution-stop-routes.ts
225121
- function registerExecutionStopRoutes(router, options, context2) {
225122
- const fail = (status, message) => ({ status, body: { error: { code: "execution_stop_recovery", message } } });
225123
- router.get("/api/workorders/:id/execution-stops", async (req) => {
225124
- if (!(await context2(req)).exists) return fail(404, "\u5DE5\u5355\u4E0D\u5B58\u5728");
225125
- if (!options) return fail(503, "\u505C\u6B62\u8865\u8BC1\u670D\u52A1\u672A\u5C31\u7EEA");
225126
- const ledger = await options.ledgerFor(req.auth.companyId);
225127
- const rows = await ledger.listByWorkorder(req.params.id);
225128
- const body2 = { items: rows.filter((r) => r.cancelRequestedAt).map((r) => ({
225129
- dispatchId: r.id,
225130
- daemonId: r.daemonId,
225131
- createdAt: r.createdAt,
225132
- requestedAt: r.cancelRequestedAt,
225133
- stoppedAt: r.executionStoppedAt ?? null,
225134
- check: r.executionRecovery ?? null
225135
- })) };
225136
- return { status: 200, body: body2 };
225137
- });
225138
- router.post("/api/workorders/:id/execution-stops/:dispatchId/verify", async (req) => {
225139
- if (!isHumanActor(req.auth.actor)) return fail(403, "\u505C\u6B62\u8865\u8BC1\u662F\u6CBB\u7406\u64CD\u4F5C\uFF0C\u4EC5\u4EBA\u7C7B\u53EF\u6267\u884C");
225140
- const ctx = await context2(req);
225141
- if (!ctx.exists) return fail(404, "\u5DE5\u5355\u4E0D\u5B58\u5728");
225142
- if (!options) return fail(503, "\u505C\u6B62\u8865\u8BC1\u670D\u52A1\u672A\u5C31\u7EEA");
225143
- const ledger = await options.ledgerFor(req.auth.companyId);
225144
- const row = await ledger.getById(req.params.dispatchId);
225145
- if (!row || row.workorderId !== req.params.id) return fail(404, "\u8BE5\u5DE5\u5355\u6CA1\u6709\u6B64\u6D3E\u53D1\u8BB0\u5F55");
225146
- if (!row.cancelRequestedAt) return fail(409, "\u8BE5\u6267\u884C\u5C1A\u672A\u8BF7\u6C42\u53D6\u6D88\uFF0C\u8BF7\u5148\u6682\u505C\u5DE5\u5355");
225147
- const body2 = req.body;
225148
- let verification;
225149
- if (body2?.evidence !== void 0 || body2?.confirmed !== void 0) {
225150
- if (!ctx.paused) return fail(409, "\u4EBA\u5DE5\u8865\u8BC1\u524D\u8BF7\u5148\u6682\u505C\u5DE5\u5355\uFF1B\u6838\u9A8C\u5B8C\u6210\u540E\u624B\u52A8\u6062\u590D\u6D3E\u53D1");
225151
- if (body2.confirmed !== true || typeof body2.evidence !== "string" || body2.evidence.trim().length < 20 || body2.evidence.length > 4e3) {
225152
- return fail(400, "\u9700\u660E\u786E\u786E\u8BA4\u5DF2\u6838\u9A8C\u539F\u5B9E\u4F8B\u3001\u5B50\u8FDB\u7A0B\u3001\u5BB9\u5668\u548C\u5F85\u542F\u52A8\u5165\u53E3\uFF0C\u5E76\u586B\u5199 20\u20134000 \u5B57\u6838\u9A8C\u4F9D\u636E");
225153
- }
225154
- verification = { actor: req.auth.actor, evidence: body2.evidence.trim() };
225155
- }
225156
- const result = await options.verify(ledger, row.id, verification);
225157
- return { status: 200, body: result };
225158
- });
225159
- }
225160
- var init_execution_stop_routes = __esm({
225161
- "../server/src/domains/collab/execution-stop-routes.ts"() {
225162
- "use strict";
225163
- init_src5();
225164
- }
225165
- });
225166
-
225167
225160
  // ../server/src/domains/collab/activity-notice.ts
225168
225161
  var NOTICE_TITLE;
225169
225162
  var init_activity_notice = __esm({
@@ -226477,6 +226470,8 @@ function buildSingleTrace(input) {
226477
226470
  const actorId = d.actorId ?? executorId;
226478
226471
  return {
226479
226472
  runId: d.id,
226473
+ ...d.outcome === "failed" && d.reason ? { dispatchError: d.reason } : {},
226474
+ ...(input.dispatches ?? []).some((newer) => newer.jobKey && newer.jobKey === d.jobKey && (newer.executionGeneration ?? 0) > (d.executionGeneration ?? 0)) ? { superseded: true } : {},
226480
226475
  ...d.cancelRequestedAt ? { cancelRequestedAt: d.cancelRequestedAt } : {},
226481
226476
  ...d.executionStoppedAt ? { executionStoppedAt: d.executionStoppedAt } : {},
226482
226477
  at: d.createdAt,
@@ -228556,13 +228551,6 @@ function collabDomain(opts) {
228556
228551
  }
228557
228552
  const resolverFor = async (companyId, registry2) => buildResolver(registry2, await memberNameResolver(opts.listMembers, companyId));
228558
228553
  return (router) => {
228559
- registerExecutionStopRoutes(router, opts.executionStopRecovery, async (req) => {
228560
- const { kernel } = await resolveCtx(req.auth.companyId);
228561
- return {
228562
- exists: [...kernel.model.artifacts.values()].some((a) => a.workspace === req.params.id),
228563
- paused: kernel.model.pausedWorkorders.has(req.params.id)
228564
- };
228565
- });
228566
228554
  router.get("/api/organization/usage-summary", async (req) => {
228567
228555
  if (!opts.trace) {
228568
228556
  return { status: 503, body: { error: { code: "no_trace_store", message: "\u8FD0\u884C\u7528\u91CF\u6570\u636E\u6E90\u672A\u63A5\u5165" } } };
@@ -229326,7 +229314,6 @@ var init_collab = __esm({
229326
229314
  init_workorders();
229327
229315
  init_workorder_detail();
229328
229316
  init_workorders();
229329
- init_execution_stop_routes();
229330
229317
  init_activity2();
229331
229318
  init_review_activity();
229332
229319
  init_activity_trace();
@@ -234244,8 +234231,8 @@ function renderResumePack(pack) {
234244
234231
  const action = effect.status === "succeeded" ? "do not repeat" : effect.status === "pending" ? "execution uncertain; reconcile before retry" : "failed; retry allowed";
234245
234232
  lines.push(`- [${effect.status}/${effect.source}] ${effect.kind} \u2192 ${effect.target} (${action}; key ${effect.idempotencyKey})`);
234246
234233
  }
234247
- const snapshot = Buffer.from(JSON.stringify(pack), "utf8").toString("base64url");
234248
- lines.push("", `${RESUME_SNAPSHOT_PREFIX}${snapshot}${RESUME_SNAPSHOT_SUFFIX}`);
234234
+ const snapshot2 = Buffer.from(JSON.stringify(pack), "utf8").toString("base64url");
234235
+ lines.push("", `${RESUME_SNAPSHOT_PREFIX}${snapshot2}${RESUME_SNAPSHOT_SUFFIX}`);
234249
234236
  return `${lines.join("\n")}
234250
234237
  `;
234251
234238
  }
@@ -235034,12 +235021,12 @@ function createReworkHandoffInputResolver(opts) {
235034
235021
  const warn = opts.warn ?? ((message) => console.warn(`[rework-handoff] ${message}`));
235035
235022
  return async (input) => {
235036
235023
  try {
235037
- const snapshot = await opts.loadWorkorder(input.workOrderId);
235038
- if (!snapshot) {
235024
+ const snapshot2 = await opts.loadWorkorder(input.workOrderId);
235025
+ if (!snapshot2) {
235039
235026
  warn(`\u5DE5\u5355\u5FEB\u7167\u8BFB\u4E0D\u5230\uFF0C\u8DF3\u8FC7\u8FD4\u5DE5\u4EA4\u63A5\u6CE8\u5165\uFF1A${input.workOrderId}`);
235040
235027
  return null;
235041
235028
  }
235042
- const work = snapshot.works.find(
235029
+ const work = snapshot2.works.find(
235043
235030
  (candidate) => candidate.id === input.workId && candidate.nodeId === input.nodeId
235044
235031
  );
235045
235032
  if (!work) {
@@ -235051,7 +235038,7 @@ function createReworkHandoffInputResolver(opts) {
235051
235038
  if (!handoff && work.agentHandoffAttemptId) {
235052
235039
  handoff = await opts.getHandoff(work.agentHandoffAttemptId).catch(() => null);
235053
235040
  }
235054
- const node2 = snapshot.nodes.find((candidate) => candidate.id === input.nodeId);
235041
+ const node2 = snapshot2.nodes.find((candidate) => candidate.id === input.nodeId);
235055
235042
  return renderReworkNodeHandoff({
235056
235043
  nodeId: input.nodeId,
235057
235044
  nodeTitle: node2?.title,
@@ -235071,12 +235058,12 @@ function createUpstreamHandoffInputResolver(opts) {
235071
235058
  const warn = opts.warn ?? ((message) => console.warn(`[upstream-handoff] ${message}`));
235072
235059
  return async (input) => {
235073
235060
  try {
235074
- const snapshot = await opts.loadWorkorder(input.workOrderId);
235075
- if (!snapshot) {
235061
+ const snapshot2 = await opts.loadWorkorder(input.workOrderId);
235062
+ if (!snapshot2) {
235076
235063
  warn(`\u5DE5\u5355\u5FEB\u7167\u8BFB\u4E0D\u5230\uFF0C\u8DF3\u8FC7\u4E0A\u6E38\u4EA4\u63A5\u6CE8\u5165\uFF1A${input.workOrderId}`);
235077
235064
  return null;
235078
235065
  }
235079
- const edge = snapshot.edges.find(
235066
+ const edge = snapshot2.edges.find(
235080
235067
  (candidate) => candidate.fromNodeId === input.upstreamNodeId && candidate.toNodeId === input.downstreamNodeId
235081
235068
  );
235082
235069
  const businessEdge = edge?.kind === "data" && edge.required;
@@ -235087,7 +235074,7 @@ function createUpstreamHandoffInputResolver(opts) {
235087
235074
  );
235088
235075
  return null;
235089
235076
  }
235090
- const work = snapshot.works.find(
235077
+ const work = snapshot2.works.find(
235091
235078
  (candidate) => candidate.id === input.pinnedWorkId && candidate.nodeId === input.upstreamNodeId
235092
235079
  );
235093
235080
  if (!work) {
@@ -235097,7 +235084,7 @@ function createUpstreamHandoffInputResolver(opts) {
235097
235084
  if (typeof work.assigneeActorId === "string" && work.assigneeActorId.startsWith("actor:human:")) {
235098
235085
  return null;
235099
235086
  }
235100
- const upstreamNode = snapshot.nodes.find((node2) => node2.id === input.upstreamNodeId);
235087
+ const upstreamNode = snapshot2.nodes.find((node2) => node2.id === input.upstreamNodeId);
235101
235088
  const conclusion = typeof work.conclusion === "string" ? work.conclusion : null;
235102
235089
  const changedOutputs = [{
235103
235090
  kind: "artifact",
@@ -235151,14 +235138,14 @@ var init_upstream_handoff_input = __esm({
235151
235138
  });
235152
235139
 
235153
235140
  // ../server/src/domains/execution-continuity/node-conclusions.ts
235154
- function nodeCoordinatorFactsFromSnapshot(snapshot) {
235155
- const workById = new Map(snapshot.works.map((work) => [work.id, work]));
235141
+ function nodeCoordinatorFactsFromSnapshot(snapshot2) {
235142
+ const workById = new Map(snapshot2.works.map((work) => [work.id, work]));
235156
235143
  const artifactCountByWork = /* @__PURE__ */ new Map();
235157
- for (const artifact of snapshot.artifacts) {
235144
+ for (const artifact of snapshot2.artifacts) {
235158
235145
  artifactCountByWork.set(artifact.workId, (artifactCountByWork.get(artifact.workId) ?? 0) + 1);
235159
235146
  }
235160
235147
  const out = {};
235161
- for (const node2 of snapshot.nodes) {
235148
+ for (const node2 of snapshot2.nodes) {
235162
235149
  const currentWorkId = node2.latestWorkId ?? null;
235163
235150
  const currentWork = currentWorkId ? workById.get(currentWorkId) : void 0;
235164
235151
  const work = {
@@ -235167,7 +235154,7 @@ function nodeCoordinatorFactsFromSnapshot(snapshot) {
235167
235154
  state: currentWorkId === null ? "not_started" : currentWork ? workState(currentWork, hasOutput(currentWork, artifactCountByWork.get(currentWork.id) ?? 0)) : "unavailable"
235168
235155
  };
235169
235156
  const accepted = node2.latestAcceptId ? workById.get(node2.latestAcceptId) : void 0;
235170
- const conclusion = accepted?.conclusion?.trim() || snapshot.works.filter((work2) => work2.nodeId === node2.id && work2.status === "success" && work2.conclusion?.trim()).sort((a, b2) => a.createdAt.localeCompare(b2.createdAt)).at(-1)?.conclusion?.trim();
235157
+ const conclusion = accepted?.conclusion?.trim() || snapshot2.works.filter((work2) => work2.nodeId === node2.id && work2.status === "success" && work2.conclusion?.trim()).sort((a, b2) => a.createdAt.localeCompare(b2.createdAt)).at(-1)?.conclusion?.trim();
235171
235158
  const sealed = node2.cancelledAt ? { reason: node2.sealReason ?? "cancelled", at: node2.cancelledAt } : null;
235172
235159
  out[node2.id] = {
235173
235160
  work,
@@ -239719,8 +239706,8 @@ function makeAutomationWorkorderSnapshotResolver(kernel) {
239719
239706
  };
239720
239707
  }
239721
239708
  function makeAutomationWorkorderStateResolver(kernel) {
239722
- const snapshot = makeAutomationWorkorderSnapshotResolver(kernel);
239723
- return async (workspace) => (await snapshot(workspace)).state;
239709
+ const snapshot2 = makeAutomationWorkorderSnapshotResolver(kernel);
239710
+ return async (workspace) => (await snapshot2(workspace)).state;
239724
239711
  }
239725
239712
  function makeAutomationReplyResolver(kernel, blobs) {
239726
239713
  return async (workspace) => {
@@ -240124,8 +240111,8 @@ var init_project_event_poller = __esm({
240124
240111
  // 完成判据必须来自 D3 resolver(snapshot.state),不在这里复制 deriveStage。
240125
240112
  // active / unknown 是「还没完成」,cancelled 永不产生 completed——四态里只有 done 触发。
240126
240113
  "workorder.completed": {
240127
- matches: (snapshot) => snapshot.state === "done",
240128
- fingerprint: (workspace, snapshot) => completionFingerprint(workspace, snapshot.members)
240114
+ matches: (snapshot2) => snapshot2.state === "done",
240115
+ fingerprint: (workspace, snapshot2) => completionFingerprint(workspace, snapshot2.members)
240129
240116
  }
240130
240117
  };
240131
240118
  ProjectEventPoller = class {
@@ -240214,17 +240201,17 @@ var init_project_event_poller = __esm({
240214
240201
  for (const event of config2.events) {
240215
240202
  const handler = AUTOMATION_EVENT_HANDLERS[event];
240216
240203
  if (!handler) continue;
240217
- for (const { workspace, snapshot } of candidates) {
240218
- if (!handler.matches(snapshot)) continue;
240204
+ for (const { workspace, snapshot: snapshot2 } of candidates) {
240205
+ if (!handler.matches(snapshot2)) continue;
240219
240206
  if (used >= budget) return used;
240220
- const fingerprint2 = handler.fingerprint(workspace, snapshot);
240207
+ const fingerprint2 = handler.fingerprint(workspace, snapshot2);
240221
240208
  const key = eventConsumptionKey({ triggerId: trigger.id, event, workspace, fingerprint: fingerprint2 });
240222
240209
  const envelope = {
240223
240210
  event,
240224
240211
  companyId: automation.companyId,
240225
240212
  projectId: config2.projectId,
240226
240213
  workspace,
240227
- rootArtifactId: snapshot.rootArtifactId,
240214
+ rootArtifactId: snapshot2.rootArtifactId,
240228
240215
  completionFingerprint: fingerprint2,
240229
240216
  observedAt: this.now().toISOString(),
240230
240217
  ...await this.originAutomationOf(workspace)
@@ -240694,7 +240681,7 @@ var init_daemon_adapter = __esm({
240694
240681
  return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
240695
240682
  }
240696
240683
  if (this.beforeDispatch) {
240697
- await this.beforeDispatch(dispatchId, nodeId);
240684
+ await this.beforeDispatch(dispatchId, nodeId, job);
240698
240685
  if (job.dispatchId && this.pending.has(dispatchId)) return this.recover(dispatchId, nodeId, job.binding?.runtimeKind, job.actor);
240699
240686
  }
240700
240687
  const supportsLiveProtocol = this.daemonSupportsLiveProtocol(nodeId, job.binding?.runtimeKind);
@@ -240945,18 +240932,6 @@ function isExplicitlyDispatchFenced(run) {
240945
240932
  const fence = metadataObject(run.metadata).dispatchFence;
240946
240933
  return fence !== null && typeof fence === "object" && !Array.isArray(fence);
240947
240934
  }
240948
- async function fenceDispatch(trace, dispatchId, reason, at = (/* @__PURE__ */ new Date()).toISOString()) {
240949
- const run = await trace.getRun(dispatchId);
240950
- if (!run) return false;
240951
- if (isExplicitlyDispatchFenced(run)) return true;
240952
- await trace.updateRun(dispatchId, {
240953
- metadata: {
240954
- ...metadataObject(run.metadata),
240955
- dispatchFence: { at, reason }
240956
- }
240957
- });
240958
- return true;
240959
- }
240960
240935
  var metadataObject;
240961
240936
  var init_dispatch_fence = __esm({
240962
240937
  "../server/src/dispatch-fence.ts"() {
@@ -240966,14 +240941,14 @@ var init_dispatch_fence = __esm({
240966
240941
  });
240967
240942
 
240968
240943
  // ../server/src/execution-stop.ts
240969
- function predecessorExecutions(rows, jobKey) {
240970
- return rows.filter((r) => r.jobKey === jobKey && !r.executionStoppedAt);
240944
+ async function acceptsExecutionOutcome(ledger, id) {
240945
+ const row = await ledger.getById(id);
240946
+ return !row || !row.cancelRequestedAt && await ledger.isExecutionLatest(id);
240971
240947
  }
240972
- var STOP_CONFIRMATION_WAIT_MS, ExecutionStopBarrier;
240948
+ var ExecutionStopBarrier;
240973
240949
  var init_execution_stop = __esm({
240974
240950
  "../server/src/execution-stop.ts"() {
240975
240951
  "use strict";
240976
- STOP_CONFIRMATION_WAIT_MS = 15e3;
240977
240952
  ExecutionStopBarrier = class {
240978
240953
  constructor(o) {
240979
240954
  this.o = o;
@@ -240981,15 +240956,9 @@ var init_execution_stop = __esm({
240981
240956
  o.hub.addExecutionStopListener((nodeId, dispatchId) => this.confirm(dispatchId, nodeId)),
240982
240957
  o.hub.addSessionConnectListener(({ dispatchId }) => {
240983
240958
  void this.replay(dispatchId).catch((e) => o.log?.(`\u6062\u590D\u53D6\u6D88\u5931\u8D25 ${dispatchId}: ${String(e)}`));
240984
- }),
240985
- o.hub.addConnectListener(({ daemonId }) => {
240986
- for (const dispatchId of this.waiting.keys()) {
240987
- void this.replay(dispatchId, daemonId).catch((e) => o.log?.(`\u91CD\u9001\u53D6\u6D88\u5931\u8D25 ${dispatchId}: ${String(e)}`));
240988
- }
240989
240959
  })
240990
240960
  ];
240991
240961
  }
240992
- waiting = /* @__PURE__ */ new Map();
240993
240962
  unsubscribe;
240994
240963
  async confirm(dispatchId, nodeId) {
240995
240964
  const ledger = await this.o.ledgerFor(dispatchId);
@@ -240997,7 +240966,6 @@ var init_execution_stop = __esm({
240997
240966
  if (!row) return;
240998
240967
  if (row.daemonId && row.daemonId !== nodeId) throw new Error("\u505C\u6B62\u8BC1\u660E\u7684\u8282\u70B9\u8EAB\u4EFD\u4E0D\u5339\u914D");
240999
240968
  if (!await ledger.recordExecutionStop(dispatchId, "confirmed")) throw new Error("dispatch \u4E0D\u5B58\u5728");
241000
- this.waiting.get(dispatchId)?.resolve();
241001
240969
  }
241002
240970
  send(dispatchId, nodeId) {
241003
240971
  const msg = { type: "kill", dispatchId };
@@ -241014,113 +240982,10 @@ var init_execution_stop = __esm({
241014
240982
  throw new Error(`\u627E\u4E0D\u5230\u6D3E\u53D1\u884C ${dispatchId}\uFF0C\u505C\u6B62\u672A\u786E\u8BA4\uFF0C\u7981\u6B62\u66FF\u4EE3\u6267\u884C`);
241015
240983
  }
241016
240984
  const row = await ledger.getById(dispatchId);
241017
- if (row?.executionStoppedAt) return;
241018
- const existing = this.waiting.get(dispatchId);
241019
- if (existing) return existing.promise;
241020
- if (row?.executionRecovery?.retryAt && Date.parse(row.executionRecovery.retryAt) > Date.now()) {
241021
- throw new Error(`\u6267\u884C ${dispatchId} \u505C\u6B62\u672A\u786E\u8BA4\uFF1A${row.executionRecovery.detail}\uFF1B\u8BF7\u5728\u6267\u884C\u8F68\u8FF9\u5904\u7406\uFF0C\u81EA\u52A8\u6838\u9A8C\u65F6\u95F4 ${row.executionRecovery.retryAt}`);
241022
- }
241023
- let resolve10, reject;
241024
- const promise = new Promise((yes, no) => {
241025
- resolve10 = yes;
241026
- reject = no;
241027
- });
241028
- const timer = setTimeout(
241029
- () => reject(new Error(`\u6267\u884C ${dispatchId} \u505C\u6B62\u672A\u786E\u8BA4\uFF0C\u7981\u6B62\u66FF\u4EE3\u6267\u884C\uFF1B\u7B49\u5F85\u8282\u70B9\u91CD\u8FDE\u6216\u6838\u9A8C\u8FD0\u884C\u65F6\u9000\u51FA`)),
241030
- this.o.timeoutMs ?? STOP_CONFIRMATION_WAIT_MS
241031
- );
241032
- const entry = { promise, resolve: resolve10, reject };
241033
- this.waiting.set(dispatchId, entry);
241034
- try {
241035
- void promise.catch(() => {
241036
- });
241037
- if ((await ledger.getById(dispatchId))?.executionStoppedAt) resolve10();
241038
- else {
241039
- this.send(dispatchId, nodeId ?? row?.daemonId);
241040
- if (this.o.recover) {
241041
- const result = await this.o.recover(dispatchId);
241042
- if (result.state === "stopped" || (await ledger.getById(dispatchId))?.executionStoppedAt) resolve10();
241043
- else if (result.state === "needs_verification") throw new Error(`\u6267\u884C ${dispatchId} \u505C\u6B62\u672A\u786E\u8BA4\uFF1A${result.detail}\uFF1B\u8BF7\u5728\u6267\u884C\u8F68\u8FF9\u5904\u7406`);
241044
- }
241045
- }
241046
- await promise;
241047
- } finally {
241048
- clearTimeout(timer);
241049
- if (this.waiting.get(dispatchId) === entry) this.waiting.delete(dispatchId);
241050
- }
241051
- }
241052
- async releaseIfStopped(dispatchId) {
241053
- if ((await (await this.o.ledgerFor(dispatchId)).getById(dispatchId))?.executionStoppedAt) this.waiting.get(dispatchId)?.resolve();
240985
+ if (!row?.executionStoppedAt) this.send(dispatchId, nodeId ?? row?.daemonId);
241054
240986
  }
241055
240987
  close() {
241056
240988
  for (const off of this.unsubscribe) off();
241057
- for (const entry of this.waiting.values()) entry.reject(new Error("\u670D\u52A1\u7AEF\u5173\u95ED\uFF0C\u505C\u6B62\u786E\u8BA4\u5C1A\u672A\u5B8C\u6210"));
241058
- this.waiting.clear();
241059
- }
241060
- };
241061
- }
241062
- });
241063
-
241064
- // ../server/src/execution-stop-recovery.ts
241065
- var import_node_crypto66, VERIFY_WAIT_MS, VERIFY_RETRY_MS, ExecutionStopRecovery;
241066
- var init_execution_stop_recovery = __esm({
241067
- "../server/src/execution-stop-recovery.ts"() {
241068
- "use strict";
241069
- import_node_crypto66 = require("node:crypto");
241070
- VERIFY_WAIT_MS = 5e3;
241071
- VERIFY_RETRY_MS = 5 * 6e4;
241072
- ExecutionStopRecovery = class {
241073
- constructor(hub, timeoutMs = VERIFY_WAIT_MS) {
241074
- this.hub = hub;
241075
- this.timeoutMs = timeoutMs;
241076
- }
241077
- async verify(ledger, id, verification) {
241078
- const row = await ledger.getById(id);
241079
- if (!row) throw new Error("\u6D3E\u53D1\u884C\u4E0D\u5B58\u5728");
241080
- if (row.executionStoppedAt) return { state: "stopped", at: row.executionStoppedAt, detail: "\u6267\u884C\u505C\u6B62\u5DF2\u786E\u8BA4" };
241081
- if (!await ledger.recordExecutionStop(id, "requested")) throw new Error("\u53D6\u6D88\u610F\u56FE\u672A\u4FDD\u5B58");
241082
- const confirmed2 = await ledger.getById(id);
241083
- if (confirmed2?.executionStoppedAt) return { state: "stopped", at: confirmed2.executionStoppedAt, detail: "\u5DF2\u786E\u8BA4\u6267\u884C\u4ECE\u672A\u53D6\u5F97\u542F\u52A8\u8BB8\u53EF" };
241084
- const now = () => (/* @__PURE__ */ new Date()).toISOString();
241085
- const daemon = this.hub.connectedDaemons().find((d) => d.daemonId === row.daemonId);
241086
- let result;
241087
- if (!daemon?.meta.supportsExecutionStopRecovery) {
241088
- result = { state: "unavailable", at: now(), detail: daemon ? "\u8282\u70B9\u4E0D\u652F\u6301\u505C\u6B62\u8865\u8BC1\uFF0C\u8BF7\u5347\u7EA7\u8282\u70B9\u5305" : "\u539F\u8282\u70B9\u672A\u8FDE\u63A5\uFF1B\u8BF7\u6062\u590D\u539F\u8282\u70B9\u8FDE\u63A5\u540E\u6838\u9A8C" };
241089
- } else if (verification && this.hub.hasSession(id)) {
241090
- result = { state: "running", at: now(), detail: "\u539F\u4F1A\u8BDD\u4ECD\u4FDD\u6301\u8FDE\u63A5\uFF0C\u62D2\u7EDD\u4EBA\u5DE5\u786E\u8BA4\uFF1B\u8BF7\u5148\u505C\u6B62\u539F\u4F1A\u8BDD" };
241091
- } else {
241092
- const requestId = (0, import_node_crypto66.randomUUID)();
241093
- result = await new Promise((resolve10) => {
241094
- const finish = (check2) => {
241095
- clearTimeout(timer);
241096
- off();
241097
- resolve10(check2);
241098
- };
241099
- const off = this.hub.addMessageListener((node2, msg) => {
241100
- if (node2 !== row.daemonId || msg.type !== "execution_stop_result" || msg.requestId !== requestId || msg.dispatchId !== id) return;
241101
- const check2 = msg.result;
241102
- const proof = check2?.proof;
241103
- if (!check2 || !["stopped", "running", "needs_verification", "unavailable"].includes(check2.state) || typeof check2.detail !== "string" || check2.state === "stopped" && (!proof || !Number.isFinite(Date.parse(proof.at)) || proof.kind !== "runtime_exit" && proof.kind !== "operator_verified" || proof.kind === "operator_verified" && (!proof.actor?.startsWith("actor:human:") || !proof.evidence?.trim()))) {
241104
- finish({ state: "unavailable", at: now(), detail: "\u8282\u70B9\u8865\u8BC1\u683C\u5F0F\u65E0\u6548\uFF0C\u4FDD\u6301\u505C\u6B62\u672A\u786E\u8BA4" });
241105
- } else finish(check2);
241106
- });
241107
- const timer = setTimeout(() => finish({ state: "unavailable", at: now(), detail: "\u8282\u70B9\u6838\u9A8C\u8D85\u65F6\uFF1B\u53EF\u5728\u6267\u884C\u8F68\u8FF9\u4E2D\u91CD\u65B0\u6838\u9A8C" }), this.timeoutMs);
241108
- if (!this.hub.dispatch(daemon.daemonId, { type: "verify_execution_stop", requestId, dispatchId: id, ...verification ? { verification } : {} })) {
241109
- finish({ state: "unavailable", at: now(), detail: "\u6838\u9A8C\u671F\u95F4\u8282\u70B9\u65AD\u5F00\uFF0C\u8BF7\u6062\u590D\u8FDE\u63A5\u540E\u91CD\u65B0\u6838\u9A8C" });
241110
- }
241111
- });
241112
- }
241113
- if (!verification && result.state === "needs_verification" && this.hub.hasSession(id)) {
241114
- result = { state: "running", at: now(), detail: "\u539F\u4F1A\u8BDD\u4ECD\u8FDE\u63A5\uFF0C\u7B49\u5F85\u5176\u771F\u5B9E\u505C\u6B62\u56DE\u62A5" };
241115
- }
241116
- result = {
241117
- ...result,
241118
- at: now(),
241119
- ...row.daemonId ? { nodeId: row.daemonId } : {},
241120
- ...result.state !== "stopped" ? { retryAt: new Date(Date.now() + VERIFY_RETRY_MS).toISOString() } : {}
241121
- };
241122
- if (!await ledger.recordExecutionRecovery(id, row.daemonId, result)) throw new Error("\u505C\u6B62\u8865\u8BC1\u672A\u843D\u5E93\uFF0C\u4FDD\u6301\u963B\u585E");
241123
- return result;
241124
240989
  }
241125
240990
  };
241126
240991
  }
@@ -241177,13 +241042,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
241177
241042
  if (sha(body2) === lastPushedHash) return { kind: "echo" };
241178
241043
  return { kind: "human-edit", content: body2, updatedBy: page.updatedBy };
241179
241044
  }
241180
- var import_node_crypto67, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
241045
+ var import_node_crypto66, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
241181
241046
  var init_engine = __esm({
241182
241047
  "../server/src/mirror/engine.ts"() {
241183
241048
  "use strict";
241184
- import_node_crypto67 = require("node:crypto");
241049
+ import_node_crypto66 = require("node:crypto");
241185
241050
  init_src();
241186
- sha = (s2) => (0, import_node_crypto67.createHash)("sha256").update(s2, "utf8").digest("hex");
241051
+ sha = (s2) => (0, import_node_crypto66.createHash)("sha256").update(s2, "utf8").digest("hex");
241187
241052
  enc3 = (s2) => new TextEncoder().encode(s2);
241188
241053
  dec = (b2) => new TextDecoder().decode(b2);
241189
241054
  MirrorEngine = class {
@@ -241430,11 +241295,11 @@ function humanExitCause(exit3) {
241430
241295
  const base = (exit3.reason ? label[exit3.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit3.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
241431
241296
  return exit3.errorMessage ? `${base}\uFF1A${exit3.errorMessage.slice(0, 200)}` : base;
241432
241297
  }
241433
- var import_node_crypto68, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
241298
+ var import_node_crypto67, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
241434
241299
  var init_worker = __esm({
241435
241300
  "../server/src/coordinator/worker.ts"() {
241436
241301
  "use strict";
241437
- import_node_crypto68 = require("node:crypto");
241302
+ import_node_crypto67 = require("node:crypto");
241438
241303
  init_src5();
241439
241304
  init_identity();
241440
241305
  AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
@@ -241703,7 +241568,7 @@ ${HIGH_RISK_COMMANDS}`;
241703
241568
  return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
241704
241569
  }
241705
241570
  evaluationKey(kind, artifactId, evidence) {
241706
- const fingerprint2 = (0, import_node_crypto68.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
241571
+ const fingerprint2 = (0, import_node_crypto67.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
241707
241572
  return `${kind}:${artifactId}:${fingerprint2}`;
241708
241573
  }
241709
241574
  artifactEvidence(id) {
@@ -242082,8 +241947,8 @@ ${ctx.nodeFault}
242082
241947
  this.deps.log?.(`[coordinator] ${workspace} \u5168\u5C40\u4E0A\u4E0B\u6587\u8BFB\u53D6\u5931\u8D25\uFF0C\u7EE7\u7EED\u6CBF\u7528\u539F\u534F\u8C03\u8005\u4EFB\u52A1\uFF1A${String(error2)}`);
242083
241948
  }
242084
241949
  }
242085
- const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto68.randomUUID)();
242086
- const coordinatorRunId = `coordinate:${(0, import_node_crypto68.randomUUID)()}`;
241950
+ const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto67.randomUUID)();
241951
+ const coordinatorRunId = `coordinate:${(0, import_node_crypto67.randomUUID)()}`;
242087
241952
  const taskWithContext = coordinatorContext ? [
242088
241953
  task,
242089
241954
  ``,
@@ -242127,7 +241992,7 @@ ${ctx.nodeFault}
242127
241992
  const startedAtMs = Date.now();
242128
241993
  let trajectoryStarted = false;
242129
241994
  if (this.deps.trajectory) {
242130
- const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto68.createHash)("sha256").update(content3).digest("hex")]));
241995
+ const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content3]) => [name, (0, import_node_crypto67.createHash)("sha256").update(content3).digest("hex")]));
242131
241996
  const session = {
242132
241997
  runId: coordinatorRunId,
242133
241998
  runtimeSessionId,
@@ -242332,11 +242197,11 @@ var init_pg_ident = __esm({
242332
242197
  });
242333
242198
 
242334
242199
  // ../storage/src/postgres.ts
242335
- var import_node_crypto69, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
242200
+ var import_node_crypto68, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
242336
242201
  var init_postgres = __esm({
242337
242202
  "../storage/src/postgres.ts"() {
242338
242203
  "use strict";
242339
- import_node_crypto69 = require("node:crypto");
242204
+ import_node_crypto68 = require("node:crypto");
242340
242205
  init_pg_ident();
242341
242206
  init_esm();
242342
242207
  init_src();
@@ -242516,7 +242381,7 @@ var init_postgres = __esm({
242516
242381
  return new _PostgresBlobStore(pool, schema);
242517
242382
  }
242518
242383
  async put(bytes2) {
242519
- const hash2 = (0, import_node_crypto69.createHash)("sha256").update(bytes2).digest("hex");
242384
+ const hash2 = (0, import_node_crypto68.createHash)("sha256").update(bytes2).digest("hex");
242520
242385
  await this.pool.query(
242521
242386
  `INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
242522
242387
  [hash2, Buffer.from(bytes2), bytes2.byteLength, sniffContentType(bytes2) ?? null]
@@ -250996,11 +250861,11 @@ var init_postgres_delegations = __esm({
250996
250861
  });
250997
250862
 
250998
250863
  // ../storage/src/postgres-nodes.ts
250999
- var import_node_crypto70, ident12, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
250864
+ var import_node_crypto69, ident12, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
251000
250865
  var init_postgres_nodes = __esm({
251001
250866
  "../storage/src/postgres-nodes.ts"() {
251002
250867
  "use strict";
251003
- import_node_crypto70 = require("node:crypto");
250868
+ import_node_crypto69 = require("node:crypto");
251004
250869
  init_pg_ident();
251005
250870
  init_esm();
251006
250871
  ident12 = (s2) => {
@@ -251210,7 +251075,7 @@ var init_postgres_nodes = __esm({
251210
251075
  return store;
251211
251076
  }
251212
251077
  issue(nodeId) {
251213
- const token = `ont_${(0, import_node_crypto70.randomBytes)(24).toString("base64url")}`;
251078
+ const token = `ont_${(0, import_node_crypto69.randomBytes)(24).toString("base64url")}`;
251214
251079
  this.cache.set(token, nodeId);
251215
251080
  void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
251216
251081
  return token;
@@ -251476,11 +251341,11 @@ var init_postgres_type_registry = __esm({
251476
251341
  });
251477
251342
 
251478
251343
  // ../storage/src/postgres-actor-memory.ts
251479
- var import_node_crypto71, matchClause, ident14, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
251344
+ var import_node_crypto70, matchClause, ident14, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
251480
251345
  var init_postgres_actor_memory = __esm({
251481
251346
  "../storage/src/postgres-actor-memory.ts"() {
251482
251347
  "use strict";
251483
- import_node_crypto71 = require("node:crypto");
251348
+ import_node_crypto70 = require("node:crypto");
251484
251349
  init_pg_ident();
251485
251350
  init_src();
251486
251351
  matchClause = (q2) => q2.requireMatch && q2.keywords.length > 0 ? " WHERE m > 0" : "";
@@ -251690,7 +251555,7 @@ var init_postgres_actor_memory = __esm({
251690
251555
  }
251691
251556
  async write(input, now) {
251692
251557
  if (input.memId === void 0) {
251693
- const memId = `mem:${(0, import_node_crypto71.randomUUID)()}`;
251558
+ const memId = `mem:${(0, import_node_crypto70.randomUUID)()}`;
251694
251559
  const r2 = await this.pool.query(
251695
251560
  `INSERT INTO ${this.s}.actor_memories
251696
251561
  (mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
@@ -251946,7 +251811,8 @@ function rowToRecord2(r) {
251946
251811
  outcome: r.outcome,
251947
251812
  exitCode: r.exit_code,
251948
251813
  reason: r.reason,
251949
- executionRecovery: r.execution_recovery ?? null,
251814
+ executionGeneration: r.execution_generation == null ? null : Number(r.execution_generation),
251815
+ executionPreparation: r.execution_preparation ?? null,
251950
251816
  executionReservedAt: r.execution_reserved_at ? new Date(r.execution_reserved_at).toISOString() : null,
251951
251817
  cancelRequestedAt: r.cancel_requested_at ? new Date(r.cancel_requested_at).toISOString() : null,
251952
251818
  executionStoppedAt: r.execution_stopped_at ? new Date(r.execution_stopped_at).toISOString() : null
@@ -251994,7 +251860,9 @@ var init_postgres_dispatches = __esm({
251994
251860
  )`);
251995
251861
  await pool.query(`CREATE INDEX IF NOT EXISTS dispatches_target_idx ON "${s2}".dispatches (target_kind, target_id, created_at DESC)`);
251996
251862
  await pool.query(`CREATE INDEX IF NOT EXISTS dispatches_workorder_idx ON "${s2}".dispatches (workorder_id, created_at DESC)`);
251997
- await pool.query(`ALTER TABLE "${s2}".dispatches ADD COLUMN IF NOT EXISTS execution_reserved_at timestamptz, ADD COLUMN IF NOT EXISTS cancel_requested_at timestamptz, ADD COLUMN IF NOT EXISTS execution_stopped_at timestamptz, ADD COLUMN IF NOT EXISTS execution_recovery jsonb`);
251863
+ await pool.query(`ALTER TABLE "${s2}".dispatches ADD COLUMN IF NOT EXISTS execution_reserved_at timestamptz, ADD COLUMN IF NOT EXISTS cancel_requested_at timestamptz, ADD COLUMN IF NOT EXISTS execution_stopped_at timestamptz`);
251864
+ await pool.query(`ALTER TABLE "${s2}".dispatches ADD COLUMN IF NOT EXISTS execution_generation bigint, ADD COLUMN IF NOT EXISTS execution_preparation jsonb`);
251865
+ await pool.query(`CREATE INDEX IF NOT EXISTS dispatches_execution_task_idx ON "${s2}".dispatches (workorder_id, job_key, execution_generation DESC) WHERE execution_generation IS NOT NULL`);
251998
251866
  return new _PostgresDispatchStore(pool, s2);
251999
251867
  }
252000
251868
  /** write-ahead:派发意图产生的那一刻落 open 行(提案 I-D1)。同 id 重放安全(ON CONFLICT DO NOTHING)。 */
@@ -252014,21 +251882,46 @@ var init_postgres_dispatches = __esm({
252014
251882
  ]
252015
251883
  );
252016
251884
  }
252017
- /** 数据库内原子占位,跨异步入口/服务进程也只能有一个未确认执行。 */
251885
+ /** 每个任务只有最新一轮有效。首次升级汇总历史身份一次,后续只继承任务清场状态。 */
252018
251886
  async reserveExecution(rec) {
252019
251887
  if (!rec.jobKey || !rec.workorderId) throw new Error("\u6267\u884C\u5360\u4F4D\u7F3A\u5C11\u7A33\u5B9A\u4EFB\u52A1\u8EAB\u4EFD");
252020
251888
  const client = await this.pool.connect();
252021
251889
  try {
252022
251890
  await client.query("BEGIN");
252023
251891
  await client.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [JSON.stringify([this.s, rec.workorderId, rec.jobKey])]);
252024
- const prior = await client.query(`SELECT id FROM "${this.s}".dispatches
252025
- WHERE workorder_id = $1 AND job_key = $2 AND execution_stopped_at IS NULL LIMIT 1`, [rec.workorderId, rec.jobKey]);
252026
- if (prior.rows.length) throw new Error(`\u505C\u6B62\u672A\u786E\u8BA4\uFF0C\u7981\u6B62\u5E76\u53D1\u6D3E\u53D1\uFF1A${prior.rows[0].id}`);
251892
+ const latest = await client.query(`SELECT * FROM "${this.s}".dispatches WHERE workorder_id=$1 AND job_key=$2
251893
+ AND execution_generation IS NOT NULL ORDER BY execution_generation DESC LIMIT 1 FOR UPDATE`, [rec.workorderId, rec.jobKey]);
251894
+ const prior = latest.rows[0];
251895
+ const generation = Number(prior?.execution_generation ?? 0) + 1;
251896
+ let nodes, legacyDispatchIds, unassignedDispatchIds;
251897
+ if (prior) {
251898
+ nodes = prior.daemon_id && prior.execution_stopped_at ? [] : [.../* @__PURE__ */ new Set([...prior.execution_preparation?.nodes ?? [], ...prior.daemon_id ? [prior.daemon_id] : [], ...prior.execution_preparation?.targetNode ? [prior.execution_preparation.targetNode] : []])];
251899
+ legacyDispatchIds = prior.execution_preparation?.legacyDispatchIds ?? [];
251900
+ unassignedDispatchIds = prior.execution_preparation?.unassignedDispatchIds ?? [];
251901
+ } else {
251902
+ const legacy = await client.query(`SELECT id, daemon_id, execution_stopped_at, execution_reserved_at FROM "${this.s}".dispatches WHERE workorder_id=$1 AND job_key=$2`, [rec.workorderId, rec.jobKey]);
251903
+ nodes = [...new Set(legacy.rows.flatMap((r) => r.daemon_id && !r.execution_stopped_at ? [r.daemon_id] : []))];
251904
+ legacyDispatchIds = legacy.rows.map((r) => r.id);
251905
+ unassignedDispatchIds = legacy.rows.filter((r) => !r.daemon_id && !r.execution_stopped_at && !r.execution_reserved_at).map((r) => r.id);
251906
+ }
251907
+ await client.query(`UPDATE "${this.s}".dispatches SET cancel_requested_at=COALESCE(cancel_requested_at,now()),
251908
+ ended_at=now(), outcome='superseded', reason='newer-execution' WHERE workorder_id=$1 AND job_key=$2 AND ended_at IS NULL`, [rec.workorderId, rec.jobKey]);
252027
251909
  await client.query(
252028
251910
  `INSERT INTO "${this.s}".dispatches
252029
- (id, target_kind, target_id, workorder_id, node_id, actor_id, job_key, created_at, execution_reserved_at)
252030
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,now())`,
252031
- [rec.id, rec.targetKind, rec.targetId, rec.workorderId, rec.nodeId ?? null, rec.actorId, rec.jobKey, rec.at ?? (/* @__PURE__ */ new Date()).toISOString()]
251911
+ (id,target_kind,target_id,workorder_id,node_id,actor_id,job_key,created_at,execution_reserved_at,execution_generation,execution_preparation)
251912
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,now(),$9,$10::jsonb)`,
251913
+ [
251914
+ rec.id,
251915
+ rec.targetKind,
251916
+ rec.targetId,
251917
+ rec.workorderId,
251918
+ rec.nodeId ?? null,
251919
+ rec.actorId,
251920
+ rec.jobKey,
251921
+ rec.at ?? (/* @__PURE__ */ new Date()).toISOString(),
251922
+ generation,
251923
+ JSON.stringify({ generation, nodes, legacyDispatchIds, unassignedDispatchIds })
251924
+ ]
252032
251925
  );
252033
251926
  await client.query("COMMIT");
252034
251927
  } catch (error2) {
@@ -252038,12 +251931,74 @@ var init_postgres_dispatches = __esm({
252038
251931
  client.release();
252039
251932
  }
252040
251933
  }
252041
- /** 真正发帧前抢占启动许可;取消、关闭和重复使用终结 dispatch 都不能越过。 */
251934
+ async withCurrentExecution(id, fn) {
251935
+ const client = await this.pool.connect();
251936
+ try {
251937
+ await client.query("BEGIN");
251938
+ const found = await client.query(`SELECT workorder_id,job_key FROM "${this.s}".dispatches WHERE id=$1`, [id]);
251939
+ const identity = found.rows[0];
251940
+ if (!identity) throw new Error(`\u6267\u884C ${id} \u6CA1\u6709\u542F\u52A8\u8BB8\u53EF`);
251941
+ await client.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [JSON.stringify([this.s, identity.workorder_id, identity.job_key])]);
251942
+ const latest = await client.query(`SELECT * FROM "${this.s}".dispatches WHERE workorder_id=$1 AND job_key=$2
251943
+ AND execution_generation IS NOT NULL ORDER BY execution_generation DESC LIMIT 1 FOR UPDATE`, [identity.workorder_id, identity.job_key]);
251944
+ const row = latest.rows[0];
251945
+ if (row?.id !== id || row.ended_at || row.cancel_requested_at || row.execution_stopped_at) throw new Error(`\u6267\u884C ${id} \u6CA1\u6709\u542F\u52A8\u8BB8\u53EF\uFF1A\u5DF2\u88AB\u65B0\u8F6E\u66FF\u4EE3\u3001\u53D6\u6D88\u6216\u7ED3\u675F`);
251946
+ const result = await fn(client, row);
251947
+ await client.query("COMMIT");
251948
+ return result;
251949
+ } catch (error2) {
251950
+ await client.query("ROLLBACK");
251951
+ throw error2;
251952
+ } finally {
251953
+ client.release();
251954
+ }
251955
+ }
251956
+ /** 先将目标机器纳入清场集合,再允许异步 RPC;并发换轮也不会漏掉正在准备的旧目标。 */
251957
+ async prepareExecution(id, daemonId, locatedNodes) {
251958
+ return this.withCurrentExecution(id, async (client, row) => {
251959
+ if (row.daemon_id) throw new Error(`\u6267\u884C ${id} \u5DF2\u9886\u53D6\u542F\u52A8\u8BB8\u53EF`);
251960
+ const plan = row.execution_preparation;
251961
+ plan.nodes = [.../* @__PURE__ */ new Set([...plan.nodes, daemonId, ...locatedNodes ?? []])];
251962
+ if (locatedNodes) plan.unassignedDispatchIds = [];
251963
+ plan.targetNode = daemonId;
251964
+ await client.query(`UPDATE "${this.s}".dispatches SET execution_preparation=$2::jsonb WHERE id=$1`, [id, JSON.stringify(plan)]);
251965
+ return plan;
251966
+ });
251967
+ }
251968
+ async confirmExecutionPrepared(id, daemonId, generation) {
251969
+ await this.withCurrentExecution(id, async (client, row) => {
251970
+ const plan = row.execution_preparation;
251971
+ if (plan.generation !== generation) throw new Error("\u4EFB\u52A1\u6E05\u573A\u786E\u8BA4\u7684\u8F6E\u6B21\u4E0D\u5339\u914D");
251972
+ plan.nodes = plan.nodes.filter((n) => n !== daemonId);
251973
+ await client.query(`UPDATE "${this.s}".dispatches SET execution_preparation=$2::jsonb WHERE id=$1`, [id, JSON.stringify(plan)]);
251974
+ });
251975
+ }
251976
+ /** 清场完成后原子领取许可;先来的清场回执不能放行已过期轮次。 */
252042
251977
  async claimExecution(id, daemonId) {
252043
- const result = await this.pool.query(`UPDATE "${this.s}".dispatches SET daemon_id = $2
252044
- WHERE id = $1 AND execution_reserved_at IS NOT NULL AND daemon_id IS NULL
252045
- AND cancel_requested_at IS NULL AND execution_stopped_at IS NULL AND ended_at IS NULL`, [id, daemonId]);
252046
- if (!result.rowCount) throw new Error(`\u6267\u884C ${id} \u6CA1\u6709\u542F\u52A8\u8BB8\u53EF\uFF1B\u53EF\u80FD\u5DF2\u53D6\u6D88\u3001\u5DF2\u6D3E\u53D1\u6216\u5DF2\u7ED3\u675F`);
251978
+ await this.withCurrentExecution(id, async (client, row) => {
251979
+ const plan = row.execution_preparation;
251980
+ if (row.daemon_id || plan.nodes.length || plan.unassignedDispatchIds?.length || plan.targetNode !== daemonId) throw new Error(`\u6267\u884C ${id} \u6CA1\u6709\u542F\u52A8\u8BB8\u53EF\uFF1A\u4EFB\u52A1\u6E05\u573A\u5C1A\u672A\u5B8C\u6210\u6216\u5DF2\u6D3E\u53D1`);
251981
+ await client.query(
251982
+ `UPDATE "${this.s}".dispatches SET daemon_id=$2,execution_preparation=$3::jsonb WHERE id=$1`,
251983
+ [id, daemonId, JSON.stringify({ generation: plan.generation, nodes: [daemonId], legacyDispatchIds: [] })]
251984
+ );
251985
+ });
251986
+ }
251987
+ /** 退出帧仍需归属当前轮次,但不能因为刚记录实际退出就拒绝其正常收尾。 */
251988
+ async isExecutionLatest(id) {
251989
+ return this.executionMatches(id, false);
251990
+ }
251991
+ /** 平台启动和写入只查询最新轮次;不依赖 trace 是否存在或旧 outcome 是否可信。 */
251992
+ async isExecutionCurrent(id) {
251993
+ return this.executionMatches(id, true);
251994
+ }
251995
+ async executionMatches(id, requireActive) {
251996
+ const result = await this.pool.query(`SELECT d.* FROM "${this.s}".dispatches d WHERE id=$1
251997
+ AND (NOT $2::boolean OR (ended_at IS NULL AND cancel_requested_at IS NULL AND execution_stopped_at IS NULL))
251998
+ AND NOT EXISTS (SELECT 1 FROM "${this.s}".dispatches n WHERE n.workorder_id=d.workorder_id AND n.job_key=d.job_key
251999
+ AND ((n.execution_generation IS NOT NULL AND (d.execution_generation IS NULL OR n.execution_generation>d.execution_generation))
252000
+ OR (n.execution_generation IS NULL AND d.execution_generation IS NULL AND (n.created_at,n.id)>(d.created_at,d.id))))`, [id, requireActive]);
252001
+ return result.rows.length > 0;
252047
252002
  }
252048
252003
  /** 取消意图与停止证据独立、幂等持久化;返回 false 表示根本没有该派发行。 */
252049
252004
  async recordExecutionStop(id, phase, at = (/* @__PURE__ */ new Date()).toISOString()) {
@@ -252055,18 +252010,6 @@ var init_postgres_dispatches = __esm({
252055
252010
  );
252056
252011
  return (result.rowCount ?? 0) > 0;
252057
252012
  }
252058
- /** 核验状态与补证审计同一次写;取消意图和节点归属必须仍匹配。 */
252059
- async recordExecutionRecovery(id, nodeId, check2) {
252060
- if (check2.state === "stopped" && !check2.proof) throw new Error("\u8865\u8BC1\u7F3A\u5C11\u6765\u6E90");
252061
- const result = await this.pool.query(
252062
- `UPDATE "${this.s}".dispatches
252063
- SET execution_recovery = CASE WHEN execution_stopped_at IS NULL THEN $3::jsonb ELSE execution_recovery END,
252064
- execution_stopped_at = COALESCE(execution_stopped_at, CASE WHEN $4 THEN now() ELSE NULL END)
252065
- WHERE id = $1 AND daemon_id IS NOT DISTINCT FROM $2 AND cancel_requested_at IS NOT NULL`,
252066
- [id, nodeId, JSON.stringify(check2), check2.state === "stopped"]
252067
- );
252068
- return (result.rowCount ?? 0) > 0;
252069
- }
252070
252013
  /** session_started 帧:回填 started_at / session_ref / daemon_id(幂等:只填第一次)。 */
252071
252014
  async markStarted(id, opts) {
252072
252015
  await this.pool.query(
@@ -253197,14 +253140,14 @@ function companySchemaName(companyId) {
253197
253140
  if (typeof companyId !== "string" || !companyId.trim()) {
253198
253141
  throw new Error("company schema mapping \u9700\u8981\u975E\u7A7A companyId\uFF08fail-closed\uFF1A\u4E0D\u56DE\u9000\u9ED8\u8BA4\u516C\u53F8\uFF09");
253199
253142
  }
253200
- const hex = (0, import_node_crypto72.createHash)("sha256").update(companyId, "utf8").digest("hex");
253143
+ const hex = (0, import_node_crypto71.createHash)("sha256").update(companyId, "utf8").digest("hex");
253201
253144
  return `${COMPANY_SCHEMA_PREFIX}${hex.slice(0, DIGEST_HEX_LEN)}`;
253202
253145
  }
253203
- var import_node_crypto72, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
253146
+ var import_node_crypto71, COMPANY_SCHEMA_PREFIX, DIGEST_HEX_LEN, SchemaMappingConflictError, TenantStorageLocationStore;
253204
253147
  var init_tenant_schema_mapping = __esm({
253205
253148
  "../storage/src/tenant-schema-mapping.ts"() {
253206
253149
  "use strict";
253207
- import_node_crypto72 = require("node:crypto");
253150
+ import_node_crypto71 = require("node:crypto");
253208
253151
  init_esm();
253209
253152
  init_pg_ident();
253210
253153
  COMPANY_SCHEMA_PREFIX = "c_";
@@ -253278,7 +253221,7 @@ var init_tenant_schema_mapping = __esm({
253278
253221
 
253279
253222
  // ../storage/src/company-data-plane-schema.ts
253280
253223
  function canonicalTypeDefHash(def) {
253281
- return `sha256:${(0, import_node_crypto73.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
253224
+ return `sha256:${(0, import_node_crypto72.createHash)("sha256").update(JSON.stringify(def), "utf8").digest("hex")}`;
253282
253225
  }
253283
253226
  function defaultArtifactTypeTemplate() {
253284
253227
  return [
@@ -253460,11 +253403,11 @@ async function seedDefaultArtifactTypes(pool, schema, templates = defaultArtifac
253460
253403
  }
253461
253404
  return { inserted };
253462
253405
  }
253463
- var import_node_crypto73, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
253406
+ var import_node_crypto72, DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION;
253464
253407
  var init_company_data_plane_schema = __esm({
253465
253408
  "../storage/src/company-data-plane-schema.ts"() {
253466
253409
  "use strict";
253467
- import_node_crypto73 = require("node:crypto");
253410
+ import_node_crypto72 = require("node:crypto");
253468
253411
  init_esm();
253469
253412
  init_pg_ident();
253470
253413
  DEFAULT_ARTIFACT_TYPE_TEMPLATE_VERSION = "4c368e5c-types-v1";
@@ -253544,11 +253487,11 @@ function rowToFile2(row) {
253544
253487
  updatedAt: new Date(row.updated_at).toISOString()
253545
253488
  };
253546
253489
  }
253547
- var import_node_crypto74, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
253490
+ var import_node_crypto73, COMPANY_CONFLICT_MSG, CompanyIdentifierConflictError, CompanyOwnedRegistryStore;
253548
253491
  var init_company_owned_registry_store = __esm({
253549
253492
  "../storage/src/company-owned-registry-store.ts"() {
253550
253493
  "use strict";
253551
- import_node_crypto74 = require("node:crypto");
253494
+ import_node_crypto73 = require("node:crypto");
253552
253495
  init_esm();
253553
253496
  init_src();
253554
253497
  init_pg_ident();
@@ -253934,7 +253877,7 @@ var init_company_owned_registry_store = __esm({
253934
253877
  enabled: skill.enabled,
253935
253878
  files: files.map((f2) => ({ path: f2.path, blobHash: f2.blobHash }))
253936
253879
  });
253937
- return (0, import_node_crypto74.createHash)("sha256").update(body2).digest("hex");
253880
+ return (0, import_node_crypto73.createHash)("sha256").update(body2).digest("hex");
253938
253881
  }
253939
253882
  };
253940
253883
  }
@@ -254674,15 +254617,24 @@ var init_cutover_aware_dispatches = __esm({
254674
254617
  async reserveExecution(rec) {
254675
254618
  return (await this.pickWritable()).reserveExecution(rec);
254676
254619
  }
254620
+ async prepareExecution(id, nodeId, locatedNodes) {
254621
+ return (await this.pickWritable()).prepareExecution(id, nodeId, locatedNodes);
254622
+ }
254623
+ async confirmExecutionPrepared(id, nodeId, generation) {
254624
+ return (await this.pickWritable()).confirmExecutionPrepared(id, nodeId, generation);
254625
+ }
254626
+ async isExecutionCurrent(id) {
254627
+ return (await this.pick()).isExecutionCurrent(id);
254628
+ }
254629
+ async isExecutionLatest(id) {
254630
+ return (await this.pick()).isExecutionLatest(id);
254631
+ }
254677
254632
  async claimExecution(id, daemonId) {
254678
254633
  return (await this.pickWritable()).claimExecution(id, daemonId);
254679
254634
  }
254680
254635
  async recordExecutionStop(id, phase, at) {
254681
254636
  return (await this.pickWritable()).recordExecutionStop(id, phase, at);
254682
254637
  }
254683
- async recordExecutionRecovery(...args) {
254684
- return (await this.pickWritable()).recordExecutionRecovery(...args);
254685
- }
254686
254638
  async close(id, opts) {
254687
254639
  return (await this.pickWritable()).close(id, opts);
254688
254640
  }
@@ -254775,24 +254727,36 @@ var init_cutover_aware_dispatches = __esm({
254775
254727
  async reserveExecution(_rec) {
254776
254728
  throw new Error("\u6267\u884C\u5360\u4F4D\u5FC5\u987B\u6307\u5B9A\u516C\u53F8");
254777
254729
  }
254778
- async claimExecution(id, daemonId) {
254730
+ async ownerOf(id) {
254779
254731
  for (const cid of await this.o.listCompanies()) {
254780
254732
  const ledger = await this.o.ledgerFor(cid);
254781
- if (await ledger.getById(id)) return ledger.claimExecution(id, daemonId);
254733
+ if (await ledger.getById(id)) return ledger;
254782
254734
  }
254783
254735
  throw new Error(`\u627E\u4E0D\u5230\u6267\u884C ${id}`);
254784
254736
  }
254785
- async recordExecutionStop(id, phase, at) {
254737
+ async prepareExecution(id, nodeId, locatedNodes) {
254738
+ return (await this.ownerOf(id)).prepareExecution(id, nodeId, locatedNodes);
254739
+ }
254740
+ async confirmExecutionPrepared(id, nodeId, generation) {
254741
+ return (await this.ownerOf(id)).confirmExecutionPrepared(id, nodeId, generation);
254742
+ }
254743
+ async isExecutionCurrent(id) {
254744
+ return (await this.ownerOf(id)).isExecutionCurrent(id);
254745
+ }
254746
+ async isExecutionLatest(id) {
254747
+ return (await this.ownerOf(id)).isExecutionLatest(id);
254748
+ }
254749
+ async claimExecution(id, daemonId) {
254786
254750
  for (const cid of await this.o.listCompanies()) {
254787
254751
  const ledger = await this.o.ledgerFor(cid);
254788
- if (await ledger.getById(id)) return ledger.recordExecutionStop(id, phase, at);
254752
+ if (await ledger.getById(id)) return ledger.claimExecution(id, daemonId);
254789
254753
  }
254790
- return false;
254754
+ throw new Error(`\u627E\u4E0D\u5230\u6267\u884C ${id}`);
254791
254755
  }
254792
- async recordExecutionRecovery(...args) {
254756
+ async recordExecutionStop(id, phase, at) {
254793
254757
  for (const cid of await this.o.listCompanies()) {
254794
254758
  const ledger = await this.o.ledgerFor(cid);
254795
- if (await ledger.getById(args[0])) return ledger.recordExecutionRecovery(...args);
254759
+ if (await ledger.getById(id)) return ledger.recordExecutionStop(id, phase, at);
254796
254760
  }
254797
254761
  return false;
254798
254762
  }
@@ -256558,7 +256522,7 @@ function sourceSetConservation(input) {
256558
256522
  return input.sourceFinal === input.copied + input.approvedRuntimeConversion + input.approvedArchive + input.approvedDiscard;
256559
256523
  }
256560
256524
  function payloadChecksum(value2) {
256561
- return (0, import_node_crypto75.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
256525
+ return (0, import_node_crypto74.createHash)("sha256").update(JSON.stringify(value2)).digest("hex");
256562
256526
  }
256563
256527
  async function copyWorkorderDraftsIdempotent(pool, companyId, companySchema, manifestId, opts) {
256564
256528
  const cs = quoteIdent2(companySchema);
@@ -256946,11 +256910,11 @@ async function copyTraceFamilyIdempotent(pool, companyId, companySchema, manifes
256946
256910
  sequences
256947
256911
  };
256948
256912
  }
256949
- var import_node_crypto75, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
256913
+ var import_node_crypto74, MissingInstallerActorsError, TypeCatalogNotCoveredError, ORG_REGISTRY_TABLES, TRACE_FAMILY;
256950
256914
  var init_tenant_migration_operator = __esm({
256951
256915
  "../storage/src/tenant-migration-operator.ts"() {
256952
256916
  "use strict";
256953
- import_node_crypto75 = require("node:crypto");
256917
+ import_node_crypto74 = require("node:crypto");
256954
256918
  init_esm();
256955
256919
  init_pg_ident();
256956
256920
  init_tenancy_attribution();
@@ -257180,44 +257144,44 @@ var init_tenant_new_company_provision = __esm({
257180
257144
  });
257181
257145
 
257182
257146
  // ../storage/src/knowledge-snapshot-crypto.ts
257183
- function sealSnapshot(snapshot, key) {
257184
- if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
257185
- const iv = (0, import_node_crypto76.randomBytes)(12);
257186
- const cipher = (0, import_node_crypto76.createCipheriv)("aes-256-gcm", bytes(key), iv);
257187
- cipher.setAAD(aad2(snapshot));
257188
- const encrypted = Buffer.concat([cipher.update(snapshot.content, "utf8"), cipher.final()]);
257189
- return { ...structuredClone(snapshot), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
257190
- }
257191
- function openSnapshot(snapshot, key) {
257192
- if (!snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
257193
- const packed = snapshot.content.slice(PREFIX3.length).split(".");
257194
- if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot.ref} ciphertext is malformed`);
257147
+ function sealSnapshot(snapshot2, key) {
257148
+ if (snapshot2.content.startsWith(PREFIX3)) return structuredClone(snapshot2);
257149
+ const iv = (0, import_node_crypto75.randomBytes)(12);
257150
+ const cipher = (0, import_node_crypto75.createCipheriv)("aes-256-gcm", bytes(key), iv);
257151
+ cipher.setAAD(aad2(snapshot2));
257152
+ const encrypted = Buffer.concat([cipher.update(snapshot2.content, "utf8"), cipher.final()]);
257153
+ return { ...structuredClone(snapshot2), content: `${PREFIX3}${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${encrypted.toString("base64url")}` };
257154
+ }
257155
+ function openSnapshot(snapshot2, key) {
257156
+ if (!snapshot2.content.startsWith(PREFIX3)) return structuredClone(snapshot2);
257157
+ const packed = snapshot2.content.slice(PREFIX3.length).split(".");
257158
+ if (packed.length !== 3 || packed.some((part) => !part)) throw new Error(`knowledge snapshot ${snapshot2.ref} ciphertext is malformed`);
257195
257159
  const [iv, tag, data] = packed;
257196
- const decipher = (0, import_node_crypto76.createDecipheriv)("aes-256-gcm", bytes(key), Buffer.from(iv, "base64url"));
257197
- decipher.setAAD(aad2(snapshot));
257160
+ const decipher = (0, import_node_crypto75.createDecipheriv)("aes-256-gcm", bytes(key), Buffer.from(iv, "base64url"));
257161
+ decipher.setAAD(aad2(snapshot2));
257198
257162
  decipher.setAuthTag(Buffer.from(tag, "base64url"));
257199
257163
  return {
257200
- ...structuredClone(snapshot),
257164
+ ...structuredClone(snapshot2),
257201
257165
  content: Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8")
257202
257166
  };
257203
257167
  }
257204
- var import_node_crypto76, PREFIX3, bytes, aad2;
257168
+ var import_node_crypto75, PREFIX3, bytes, aad2;
257205
257169
  var init_knowledge_snapshot_crypto = __esm({
257206
257170
  "../storage/src/knowledge-snapshot-crypto.ts"() {
257207
257171
  "use strict";
257208
- import_node_crypto76 = require("node:crypto");
257172
+ import_node_crypto75 = require("node:crypto");
257209
257173
  PREFIX3 = "oasis-knowledge:v1:";
257210
257174
  bytes = (key) => {
257211
257175
  const value2 = Buffer.from(key);
257212
257176
  if (value2.length !== 32) throw new Error("knowledge snapshot key must be 32 bytes");
257213
257177
  return value2;
257214
257178
  };
257215
- aad2 = (snapshot) => Buffer.from([
257216
- snapshot.organizationId,
257217
- snapshot.projectId ?? "organization",
257218
- snapshot.spaceId ?? "none",
257219
- snapshot.ref,
257220
- snapshot.contentHash
257179
+ aad2 = (snapshot2) => Buffer.from([
257180
+ snapshot2.organizationId,
257181
+ snapshot2.projectId ?? "organization",
257182
+ snapshot2.spaceId ?? "none",
257183
+ snapshot2.ref,
257184
+ snapshot2.contentHash
257221
257185
  ].join("\0"), "utf8");
257222
257186
  }
257223
257187
  });
@@ -258611,7 +258575,7 @@ var init_board_watch = __esm({
258611
258575
  freshTerminalRunId: newestTerminalRun !== null && !letteredRuns.has(newestTerminalRun.runId) ? newestTerminalRun.runId : null
258612
258576
  };
258613
258577
  if (!decideBoardLetter(candidate, now, quietMs)) continue;
258614
- const fmt = (fs47) => fs47.slice(0, 5).map((f2) => `- ${f2.path}\uFF08${f2.kind ?? "?"}\uFF09\xB7 ${f2.mtime ? new Date(f2.mtime).toISOString() : "?"}`).join("\n");
258578
+ const fmt = (fs48) => fs48.slice(0, 5).map((f2) => `- ${f2.path}\uFF08${f2.kind ?? "?"}\uFF09\xB7 ${f2.mtime ? new Date(f2.mtime).toISOString() : "?"}`).join("\n");
258615
258579
  let body2;
258616
258580
  let logLine;
258617
258581
  if (candidate.freshTerminalRunId !== null) {
@@ -259192,6 +259156,58 @@ var init_read_model_clock = __esm({
259192
259156
  }
259193
259157
  });
259194
259158
 
259159
+ // ../server/src/task-replacement.ts
259160
+ var import_node_crypto76, TaskReplacementBarrier;
259161
+ var init_task_replacement = __esm({
259162
+ "../server/src/task-replacement.ts"() {
259163
+ "use strict";
259164
+ import_node_crypto76 = require("node:crypto");
259165
+ TaskReplacementBarrier = class {
259166
+ constructor(hub, timeoutMs = 3e4, locateLegacy) {
259167
+ this.hub = hub;
259168
+ this.timeoutMs = timeoutMs;
259169
+ this.locateLegacy = locateLegacy;
259170
+ }
259171
+ async prepare(ledger, dispatchId, nodeId, job, companyId = "") {
259172
+ let plan = await ledger.prepareExecution(dispatchId, nodeId);
259173
+ if (plan.unassignedDispatchIds?.length) {
259174
+ if (!this.locateLegacy) throw new Error(`\u4EFB\u52A1 ${dispatchId} \u7684\u5386\u53F2\u6267\u884C\u7F3A\u5C11\u673A\u5668\u5F52\u5C5E\uFF0C\u4E0D\u80FD\u786E\u8BA4\u6E05\u573A`);
259175
+ const nodes = await this.locateLegacy(plan.unassignedDispatchIds);
259176
+ if (!nodes.length) throw new Error(`\u4EFB\u52A1 ${dispatchId} \u7684\u5386\u53F2\u6267\u884C\u673A\u5668\u672A\u5B9A\u4F4D\uFF0C\u4E0D\u80FD\u786E\u8BA4\u6E05\u573A`);
259177
+ plan = await ledger.prepareExecution(dispatchId, nodeId, nodes);
259178
+ }
259179
+ const key = (0, import_node_crypto76.createHash)("sha256").update(JSON.stringify([job.server.url.replace(/\/+$/, ""), companyId, job.jobKey])).digest("hex");
259180
+ job.execution = { key, generation: plan.generation };
259181
+ const results = await Promise.allSettled(plan.nodes.map(async (node2) => {
259182
+ await this.replace(node2, { requestId: (0, import_node_crypto76.randomUUID)(), dispatchId, key, generation: plan.generation, legacyDispatchIds: plan.legacyDispatchIds, usesContainers: Boolean(job.executionEnv), ...job.workdirKey ? { workdirKey: job.workdirKey } : {} });
259183
+ await ledger.confirmExecutionPrepared(dispatchId, node2, plan.generation);
259184
+ }));
259185
+ const failures = results.flatMap((r, i) => r.status === "rejected" ? [`${plan.nodes[i]}\uFF1A${String(r.reason)}`] : []);
259186
+ if (failures.length) throw new Error(`\u4EFB\u52A1\u5207\u6362\u5C1A\u672A\u5B8C\u6210\uFF08\u5F53\u524D\u6267\u884C ${dispatchId}\uFF09\uFF1A${failures.join("\uFF1B")}`);
259187
+ await ledger.claimExecution(dispatchId, nodeId);
259188
+ }
259189
+ async replace(nodeId, request2) {
259190
+ const node2 = this.hub.connectedDaemons().find((n) => n.daemonId === nodeId);
259191
+ if (!node2) throw new Error("\u6267\u884C\u673A\u5668\u79BB\u7EBF\uFF0C\u8FDE\u63A5\u6062\u590D\u540E\u53EF\u7EE7\u7EED\u4EFB\u52A1\u5207\u6362");
259192
+ if (!node2.meta.supportsTaskReplacement) throw new Error("\u6267\u884C\u673A\u5668\u9700\u5347\u7EA7\u5230\u652F\u6301\u4EFB\u52A1\u6362\u8F6E\u7684\u7248\u672C");
259193
+ await new Promise((resolve10, reject) => {
259194
+ const finish = (error2) => {
259195
+ clearTimeout(timer);
259196
+ off();
259197
+ error2 ? reject(error2) : resolve10();
259198
+ };
259199
+ const off = this.hub.addMessageListener((sender, msg) => {
259200
+ if (sender !== nodeId || msg.type !== "task_replaced" || msg.requestId !== request2.requestId || msg.dispatchId !== request2.dispatchId || msg.key !== request2.key || msg.generation !== request2.generation) return;
259201
+ finish(msg.stopped ? void 0 : new Error(msg.detail ?? "\u65E7\u8FDB\u7A0B\u6E05\u7406\u5931\u8D25"));
259202
+ });
259203
+ const timer = setTimeout(() => finish(new Error("\u8282\u70B9\u5C1A\u672A\u5B8C\u6210\u65E7\u8FDB\u7A0B\u6E05\u7406\uFF0C\u8BF7\u68C0\u67E5\u8BE5\u8282\u70B9\u8FDE\u63A5\u4E0E\u8FDB\u7A0B\u6743\u9650")), this.timeoutMs);
259204
+ if (!this.hub.dispatch(nodeId, { type: "replace_task", ...request2 })) finish(new Error("\u6E05\u573A\u547D\u4EE4\u672A\u9001\u8FBE\u8282\u70B9"));
259205
+ });
259206
+ }
259207
+ };
259208
+ }
259209
+ });
259210
+
259195
259211
  // ../server/src/index.ts
259196
259212
  var init_src11 = __esm({
259197
259213
  "../server/src/index.ts"() {
@@ -259284,7 +259300,6 @@ var init_src11 = __esm({
259284
259300
  init_daemon_adapter();
259285
259301
  init_dispatch_fence();
259286
259302
  init_execution_stop();
259287
- init_execution_stop_recovery();
259288
259303
  init_node_health();
259289
259304
  init_side_map();
259290
259305
  init_engine();
@@ -259312,6 +259327,7 @@ var init_src11 = __esm({
259312
259327
  init_run_settlement_wiring();
259313
259328
  init_deadline_clock();
259314
259329
  init_read_model_clock();
259330
+ init_task_replacement();
259315
259331
  }
259316
259332
  });
259317
259333
 
@@ -259443,15 +259459,15 @@ var init_trajectory = __esm({
259443
259459
  });
259444
259460
 
259445
259461
  // src/index.ts
259446
- var fs46 = __toESM(require("node:fs"));
259447
- var os15 = __toESM(require("node:os"));
259462
+ var fs47 = __toESM(require("node:fs"));
259463
+ var os16 = __toESM(require("node:os"));
259448
259464
  var path42 = __toESM(require("node:path"));
259449
259465
  var import_node_child_process20 = require("node:child_process");
259450
259466
  var import_node_crypto85 = require("node:crypto");
259451
259467
 
259452
259468
  // ../cli/src/cli.ts
259453
- var fs41 = __toESM(require("node:fs"), 1);
259454
- var os13 = __toESM(require("node:os"), 1);
259469
+ var fs42 = __toESM(require("node:fs"), 1);
259470
+ var os14 = __toESM(require("node:os"), 1);
259455
259471
  var path37 = __toESM(require("node:path"), 1);
259456
259472
  var import_node_crypto83 = require("node:crypto");
259457
259473
 
@@ -262663,14 +262679,6 @@ async function startServe(opts) {
262663
262679
  // 派发台账:动态卡的 runId 与「执行轨迹」抽屉靠它把 work/review 硬关联到 agent_runs.id。
262664
262680
  // 与上面 createServer 的 `dispatchesOfWorkorder`(timeline 用)是同一个闭包,别分叉。
262665
262681
  dispatchesOfWorkorder: (wid) => fanOutLedger.listByWorkorder(wid),
262666
- executionStopRecovery: {
262667
- ledgerFor: (cid) => dispatchLedgerFor(cid),
262668
- verify: async (ledger, id, verification) => {
262669
- const result = await executionStopRecovery.verify(ledger, id, verification);
262670
- if (result.state === "stopped") await executionStops.releaseIfStopped(id);
262671
- return result;
262672
- }
262673
- },
262674
262682
  // 组织汇总用——从 nodes 取 name(用户友好名),优先于 hostname 作为展示标签
262675
262683
  listNodes: () => nodeStore.listNodes(),
262676
262684
  // 诊断 92ac8f18-83e5fde6 §④ D-2:按**请求公司**取其 dispatcher 的 queued/backoff 信号。
@@ -263190,23 +263198,23 @@ async function startServe(opts) {
263190
263198
  }
263191
263199
  } catch (error2) {
263192
263200
  const rollbackErrors = [];
263193
- for (const snapshot of [...snapshots2].reverse()) {
263201
+ for (const snapshot2 of [...snapshots2].reverse()) {
263194
263202
  try {
263195
- if (!snapshot.row || snapshot.previousValue === null) {
263196
- await actors.service.deleteVariable(snapshot.write.key, request2.actorId);
263203
+ if (!snapshot2.row || snapshot2.previousValue === null) {
263204
+ await actors.service.deleteVariable(snapshot2.write.key, request2.actorId);
263197
263205
  } else {
263198
263206
  await actors.service.putVariable({
263199
- key: snapshot.row.key,
263200
- value: snapshot.previousValue,
263201
- scope: snapshot.row.scope,
263202
- ...snapshot.row.actorId ? { actorId: snapshot.row.actorId } : {},
263203
- ...snapshot.row.connectorId ? { connectorId: snapshot.row.connectorId } : {},
263204
- ...snapshot.row.overrides ? { overrides: snapshot.row.overrides } : {},
263205
- encrypted: snapshot.row.encrypted
263207
+ key: snapshot2.row.key,
263208
+ value: snapshot2.previousValue,
263209
+ scope: snapshot2.row.scope,
263210
+ ...snapshot2.row.actorId ? { actorId: snapshot2.row.actorId } : {},
263211
+ ...snapshot2.row.connectorId ? { connectorId: snapshot2.row.connectorId } : {},
263212
+ ...snapshot2.row.overrides ? { overrides: snapshot2.row.overrides } : {},
263213
+ encrypted: snapshot2.row.encrypted
263206
263214
  });
263207
263215
  }
263208
263216
  } catch (rollbackError) {
263209
- rollbackErrors.push(`${snapshot.write.key}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
263217
+ rollbackErrors.push(`${snapshot2.write.key}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
263210
263218
  }
263211
263219
  }
263212
263220
  const detail = error2 instanceof Error ? error2.message : String(error2);
@@ -263412,7 +263420,9 @@ async function startServe(opts) {
263412
263420
  * 这正是 ADR 点名要求的「收割记录须持久化,否则重启后 fencing 静默失效」。
263413
263421
  */
263414
263422
  isDispatchFenced: async (dispatchId) => {
263415
- const r = await fanOutTrace.getRun(dispatchId).catch(() => null);
263423
+ const ledger = await ledgerForDispatch(dispatchId);
263424
+ if (await ledger.getById(dispatchId)) return !await ledger.isExecutionCurrent(dispatchId);
263425
+ const r = await fanOutTrace.getRun(dispatchId);
263416
263426
  if (!r) return false;
263417
263427
  if (isExplicitlyDispatchFenced(r)) return true;
263418
263428
  if (r.status === "running") return false;
@@ -264174,9 +264184,10 @@ async function startServe(opts) {
264174
264184
  log: (m2) => console.log(m2)
264175
264185
  });
264176
264186
  if (!chatHandled) {
264187
+ const acceptsOutcome = await acceptsExecutionOutcome(await ledgerForDispatch(msg.dispatchId), msg.dispatchId);
264177
264188
  const mapping = dispatchToWork.get(msg.dispatchId);
264178
264189
  const exitBus = mapping ? busForCompany(mapping.companyId) ?? busForWorkorder(mapping.workorderId) : null;
264179
- if (mapping && exitBus) {
264190
+ if (acceptsOutcome && mapping && exitBus) {
264180
264191
  exitBus.submit({
264181
264192
  companyId: "",
264182
264193
  workorderId: mapping.workorderId,
@@ -264190,13 +264201,13 @@ async function startServe(opts) {
264190
264201
  }
264191
264202
  }).catch((err) => console.error(`[new-engine] work.response submit \u5931\u8D25:`, err));
264192
264203
  dispatchToWork.delete(msg.dispatchId);
264193
- if (mapping) workToSession.delete(mapping.workId);
264194
- } else if (!mapping) {
264204
+ if (workToSession.get(mapping.workId)?.dispatchId === msg.dispatchId) workToSession.delete(mapping.workId);
264205
+ } else if (acceptsOutcome && !mapping) {
264195
264206
  await fallbackDispatchExitToWork(msg);
264196
264207
  }
264197
264208
  const revMapping = dispatchToReview.get(msg.dispatchId);
264198
264209
  const revExitBus = revMapping ? busForCompany(revMapping.companyId) ?? busForWorkorder(revMapping.workorderId) : null;
264199
- if (revMapping && revExitBus) {
264210
+ if (acceptsOutcome && revMapping && revExitBus) {
264200
264211
  revExitBus.submit({
264201
264212
  companyId: "",
264202
264213
  workorderId: revMapping.workorderId,
@@ -264208,7 +264219,13 @@ async function startServe(opts) {
264208
264219
  }
264209
264220
  }).catch((err) => console.error(`[new-engine] review.expired submit \u5931\u8D25:`, err));
264210
264221
  dispatchToReview.delete(msg.dispatchId);
264211
- reviewToSession.delete(revMapping.reviewId);
264222
+ if (reviewToSession.get(revMapping.reviewId)?.dispatchId === msg.dispatchId) reviewToSession.delete(revMapping.reviewId);
264223
+ }
264224
+ if (!acceptsOutcome) {
264225
+ dispatchToWork.delete(msg.dispatchId);
264226
+ dispatchToReview.delete(msg.dispatchId);
264227
+ if (mapping && workToSession.get(mapping.workId)?.dispatchId === msg.dispatchId) workToSession.delete(mapping.workId);
264228
+ if (revMapping && reviewToSession.get(revMapping.reviewId)?.dispatchId === msg.dispatchId) reviewToSession.delete(revMapping.reviewId);
264212
264229
  }
264213
264230
  await reconcileDispatchExitFrame({
264214
264231
  dispatchId: msg.dispatchId,
@@ -264312,11 +264329,27 @@ async function startServe(opts) {
264312
264329
  gatewayUrl: opts.gatewayUrl ?? `ws://127.0.0.1:${opts.port ?? 7320}/node-gateway`
264313
264330
  }
264314
264331
  };
264332
+ const taskReplacements = new TaskReplacementBarrier(hub, void 0, async (ids2) => {
264333
+ const nodes = /* @__PURE__ */ new Set();
264334
+ for (const id of ids2) {
264335
+ const run = await fanOutTrace.getRun(id);
264336
+ const instance = run?.runtimeInstanceId;
264337
+ if (!instance?.startsWith("runtime:") || instance.lastIndexOf(":") <= 8) {
264338
+ throw new Error("\u5386\u53F2\u4EFB\u52A1\u7684\u6267\u884C\u673A\u5668\u5F52\u5C5E\u7F3A\u5931\uFF0C\u65E0\u6CD5\u81EA\u52A8\u6E05\u573A\uFF1B\u8BF7\u6062\u590D\u8BE5\u4EFB\u52A1\u7684\u8282\u70B9\u767B\u8BB0\u548C\u8FD0\u884C\u8F68\u8FF9\u540E\u91CD\u8BD5");
264339
+ }
264340
+ nodes.add(instance.slice(8, instance.lastIndexOf(":")));
264341
+ }
264342
+ return [...nodes];
264343
+ });
264344
+ hub.executionIsCurrent = async (id) => {
264345
+ const ledger = await ledgerForDispatch(id);
264346
+ return !await ledger.getById(id) || ledger.isExecutionCurrent(id);
264347
+ };
264315
264348
  chatRemoteAdapter = new DaemonHubAdapter(hub, { ...hubAdapterOpts, stashUnknownFrames: true });
264316
264349
  dispatchRemoteAdapter = new DaemonHubAdapter(hub, {
264317
- beforeDispatch: async (id, nodeId) => {
264350
+ beforeDispatch: async (id, nodeId, job) => {
264318
264351
  const ledger = await ledgerForDispatch(id);
264319
- if (await ledger.getById(id)) await ledger.claimExecution(id, nodeId);
264352
+ if (await ledger.getById(id)) await taskReplacements.prepare(ledger, id, nodeId, job, issuer.resolveClaims(job.actorToken)?.companyId);
264320
264353
  },
264321
264354
  onDispatchNotSent: async (id) => {
264322
264355
  const ledger = await ledgerForDispatch(id);
@@ -264364,13 +264397,7 @@ async function startServe(opts) {
264364
264397
  const cid = companyOfDispatch(dispatchId);
264365
264398
  return cid ? await dispatchLedgerFor(cid) : fanOutLedger;
264366
264399
  };
264367
- const executionStopRecovery = new ExecutionStopRecovery(hub);
264368
- const executionStops = new ExecutionStopBarrier({
264369
- hub,
264370
- ledgerFor: ledgerForDispatch,
264371
- log: console.warn,
264372
- recover: async (id) => executionStopRecovery.verify(await ledgerForDispatch(id), id)
264373
- });
264400
+ const executionStops = new ExecutionStopBarrier({ hub, ledgerFor: ledgerForDispatch, log: console.warn });
264374
264401
  const traceStoreForDispatch = async (dispatchId) => {
264375
264402
  const cid = companyOfDispatch(dispatchId) ?? await fanOutTrace.companyOfRun(dispatchId).catch(() => null);
264376
264403
  return cid ? await traceStoreFor(cid) : void 0;
@@ -264580,12 +264607,7 @@ async function startServe(opts) {
264580
264607
  }
264581
264608
  const bridge = engineDispatchBridges.forArtifact(rev.artifactId, companyId);
264582
264609
  if (!bridge) return;
264583
- const jobKey = replyIssueId ? `reply::${replyIssueId}::${rev.author}` : `produce::${rev.artifactId}`;
264584
264610
  const ledger = await dispatchLedgerFor(companyId);
264585
- for (const old of predecessorExecutions(await ledger.listByWorkorder(wid), jobKey)) {
264586
- await fenceDispatch(await traceStoreFor(companyId), old.id, "successor-stop-barrier");
264587
- await executionStops.cancel(ledger, old.id, old.daemonId);
264588
- }
264589
264611
  const ledgerId = `dispatch:${(0, import_node_crypto77.randomUUID)()}`;
264590
264612
  try {
264591
264613
  await (await dispatchLedgerFor(companyId)).reserveExecution({
@@ -264606,6 +264628,7 @@ async function startServe(opts) {
264606
264628
  result = replyIssueId ? await bridge.replyWork(rev.artifactId, rev.author, replyIssueId, ledgerId) : await bridge.produce(rev.artifactId, rev.author, workId, ledgerId, opts2?.resumeEligible);
264607
264629
  } catch (err) {
264608
264630
  void dispatchLedgerFor(companyId).then((l) => l.close(ledgerId, { outcome: "failed", reason: `dispatch error: ${err instanceof Error ? err.message : String(err)}` })).catch(ledgerWarn("close(error)"));
264631
+ if (!await ledger.isExecutionLatest(ledgerId)) return;
264609
264632
  console.log(`[new-engine] dispatchWork ${workId} \u6D3E\u53D1\u5F02\u5E38\uFF1A${String(err)} \u2192 \u7F6E work failed`);
264610
264633
  const failBus = busForCompany(companyId);
264611
264634
  if (failBus) {
@@ -264624,6 +264647,7 @@ async function startServe(opts) {
264624
264647
  }
264625
264648
  return;
264626
264649
  }
264650
+ if (!await ledger.isExecutionLatest(ledgerId)) return;
264627
264651
  if (result?.dispatchId) {
264628
264652
  const delivery = dispatchRemoteAdapter?.deliveryStatus(result.dispatchId);
264629
264653
  dispatchToWork.set(result.dispatchId, {
@@ -264637,7 +264661,8 @@ async function startServe(opts) {
264637
264661
  if (delivery) workToSession.set(workId, { dispatchId: result.dispatchId, daemonId: delivery.nodeId });
264638
264662
  dispatchedWorks.add(workId);
264639
264663
  } else if (result?.kind === "spawn-failed" || result?.kind === "predispatch-timeout") {
264640
- void dispatchLedgerFor(companyId).then((l) => l.close(ledgerId, { outcome: "failed", reason: `dispatch ${result.kind}` })).catch(ledgerWarn("close(spawn-failed)"));
264664
+ const failureReason = result.reason ?? `dispatch ${result.kind}`;
264665
+ void ledger.close(ledgerId, { outcome: "failed", reason: failureReason }).catch(ledgerWarn("close(spawn-failed)"));
264641
264666
  console.log(`[new-engine] dispatchWork ${workId} \u6D3E\u53D1\u5931\u8D25\uFF08${result.kind}${result.reason ? `\uFF1A${result.reason}` : ""}\uFF09\u2192 \u7F6E work failed`);
264642
264667
  const failBus = busForCompany(companyId);
264643
264668
  if (failBus) {
@@ -264650,7 +264675,7 @@ async function startServe(opts) {
264650
264675
  workorderId: wid,
264651
264676
  workId,
264652
264677
  outcome: "failed",
264653
- detail: { reason: `dispatch ${result.kind}` }
264678
+ detail: { reason: failureReason }
264654
264679
  }
264655
264680
  });
264656
264681
  }
@@ -264670,11 +264695,6 @@ async function startServe(opts) {
264670
264695
  const art = kernelModel.artifacts.get(nodeId);
264671
264696
  const revWid = art?.workspace ?? "";
264672
264697
  const reviewLedger = await dispatchLedgerFor(companyId);
264673
- const reviewJobKey = `review::${nodeId}::${reviewerActorId}`;
264674
- for (const old of predecessorExecutions(await reviewLedger.listByWorkorder(revWid), reviewJobKey)) {
264675
- await fenceDispatch(await traceStoreFor(companyId), old.id, "review-successor-stop-barrier");
264676
- await executionStops.cancel(reviewLedger, old.id, old.daemonId);
264677
- }
264678
264698
  const ledgerId = `dispatch:${(0, import_node_crypto77.randomUUID)()}`;
264679
264699
  try {
264680
264700
  await (await dispatchLedgerFor(companyId)).reserveExecution({
@@ -264695,14 +264715,16 @@ async function startServe(opts) {
264695
264715
  result = await bridge.review(nodeId, reviewerActorId, ledgerId, reviewId);
264696
264716
  } catch (err) {
264697
264717
  void dispatchLedgerFor(companyId).then((l) => l.close(ledgerId, { outcome: "failed", reason: `dispatch error: ${err instanceof Error ? err.message : String(err)}` })).catch(ledgerWarn("close(review-error)"));
264718
+ if (!await reviewLedger.isExecutionLatest(ledgerId)) return;
264698
264719
  throw err;
264699
264720
  }
264721
+ if (!await reviewLedger.isExecutionLatest(ledgerId)) return;
264700
264722
  if (result?.dispatchId) {
264701
264723
  dispatchedReviews.add(reviewId);
264702
264724
  dispatchToReview.set(result.dispatchId, { reviewId, workorderId: revWid, nodeId, companyId });
264703
264725
  if (revWid) workorderCompany.set(revWid, companyId);
264704
264726
  } else if (result?.kind === "spawn-failed" || result?.kind === "predispatch-timeout") {
264705
- void dispatchLedgerFor(companyId).then((l) => l.close(ledgerId, { outcome: "failed", reason: `dispatch ${result.kind}` })).catch(ledgerWarn("close(review-spawn-failed)"));
264727
+ void reviewLedger.close(ledgerId, { outcome: "failed", reason: result.reason ?? `dispatch ${result.kind}` }).catch(ledgerWarn("close(review-spawn-failed)"));
264706
264728
  } else if (result?.kind) {
264707
264729
  void dispatchLedgerFor(companyId).then((l) => l.close(ledgerId, { outcome: "superseded", reason: result.kind })).catch(ledgerWarn("close(review-skipped)"));
264708
264730
  }
@@ -264715,9 +264737,8 @@ async function startServe(opts) {
264715
264737
  const ids2 = new Map(rows.map((r) => [r.id, r.daemonId]));
264716
264738
  if (mapped) ids2.set(mapped.dispatchId, mapped.daemonId);
264717
264739
  for (const [dispatchId, daemonId] of ids2) {
264718
- await fenceDispatch(await traceStoreFor(companyId), dispatchId, "engine-cancel-before-successor");
264719
264740
  await executionStops.cancel(ledger, dispatchId, daemonId);
264720
- await ledger.close(dispatchId, { outcome: "cancelled", reason: "session-stop-confirmed" });
264741
+ await ledger.close(dispatchId, { outcome: "cancelled", reason: "session-stop-requested" });
264721
264742
  }
264722
264743
  workToSession.delete(ref2);
264723
264744
  reviewToSession.delete(ref2);
@@ -266473,7 +266494,7 @@ var SessionManager = class {
266473
266494
  };
266474
266495
 
266475
266496
  // ../cli/src/daemon/session-process.ts
266476
- var fs37 = __toESM(require("node:fs"), 1);
266497
+ var fs38 = __toESM(require("node:fs"), 1);
266477
266498
  var path33 = __toESM(require("node:path"), 1);
266478
266499
  init_wrapper();
266479
266500
  init_src();
@@ -266560,10 +266581,15 @@ function isSessionLocked(lockPath) {
266560
266581
  }
266561
266582
  }
266562
266583
 
266563
- // ../cli/src/daemon/execution-recovery.ts
266564
- var fs36 = __toESM(require("node:fs"), 1);
266584
+ // ../cli/src/daemon/session-runner.ts
266585
+ init_src();
266586
+ init_src6();
266587
+ init_src8();
266588
+
266589
+ // ../cli/src/daemon/task-execution.ts
266590
+ var fs37 = __toESM(require("node:fs"), 1);
266565
266591
  var path32 = __toESM(require("node:path"), 1);
266566
- var import_node_child_process16 = require("node:child_process");
266592
+ var os10 = __toESM(require("node:os"), 1);
266567
266593
  var import_node_crypto79 = require("node:crypto");
266568
266594
 
266569
266595
  // ../cli/src/daemon/execution-lock.ts
@@ -266577,38 +266603,6 @@ var ExecutionLockConflictError = class extends Error {
266577
266603
  this.conflictingDispatchId = conflictingDispatchId;
266578
266604
  }
266579
266605
  };
266580
- function mutateLock(file, fn) {
266581
- const guard = `${file}.guard`;
266582
- fs35.mkdirSync(guard, { mode: 448 });
266583
- try {
266584
- return fn();
266585
- } finally {
266586
- fs35.rmdirSync(guard);
266587
- }
266588
- }
266589
- function releaseExecutionLocksForDispatch(dispatchId, root = path31.join(os9.tmpdir(), `oasis-execution-locks-${process.getuid?.() ?? "user"}`)) {
266590
- let names;
266591
- try {
266592
- names = fs35.readdirSync(root);
266593
- } catch (e) {
266594
- if (e.code === "ENOENT") return;
266595
- throw e;
266596
- }
266597
- for (const name of names) {
266598
- if (!/^[a-f0-9]{64}$/.test(name)) continue;
266599
- const file = path31.join(root, name);
266600
- try {
266601
- const before = JSON.parse(fs35.readFileSync(file, "utf8"));
266602
- if (before.dispatchId !== dispatchId) continue;
266603
- mutateLock(file, () => {
266604
- const held = JSON.parse(fs35.readFileSync(file, "utf8"));
266605
- if (held.dispatchId === dispatchId && held.owner) fs35.unlinkSync(file);
266606
- });
266607
- } catch (e) {
266608
- if (e.code !== "ENOENT") throw e;
266609
- }
266610
- }
266611
- }
266612
266606
  function executionLockKey(job) {
266613
266607
  const key = job.workdirKey ?? job.jobKey;
266614
266608
  if (!key) return null;
@@ -266621,7 +266615,7 @@ function acquireExecutionLock(job, dispatchId, root = path31.join(os9.tmpdir(),
266621
266615
  const file = path31.join(root, key);
266622
266616
  const owner = (0, import_node_crypto78.randomUUID)();
266623
266617
  try {
266624
- mutateLock(file, () => fs35.writeFileSync(file, JSON.stringify({ owner, pid: process.pid, dispatchId }), { flag: "wx", mode: 384 }));
266618
+ fs35.writeFileSync(file, JSON.stringify({ owner, pid: process.pid, dispatchId }), { flag: "wx", mode: 384 });
266625
266619
  } catch (e) {
266626
266620
  if (e.code === "EEXIST") {
266627
266621
  let conflictingDispatchId = null;
@@ -266636,121 +266630,343 @@ function acquireExecutionLock(job, dispatchId, root = path31.join(os9.tmpdir(),
266636
266630
  }
266637
266631
  return { path: file, release() {
266638
266632
  try {
266639
- mutateLock(file, () => {
266640
- if (JSON.parse(fs35.readFileSync(file, "utf8")).owner === owner) fs35.unlinkSync(file);
266641
- });
266633
+ if (JSON.parse(fs35.readFileSync(file, "utf8")).owner === owner) fs35.unlinkSync(file);
266642
266634
  } catch {
266643
266635
  }
266644
266636
  } };
266645
266637
  }
266638
+ function clearStoppedExecutionLocks(dispatchIds, root = path31.join(os9.tmpdir(), `oasis-execution-locks-${process.getuid?.() ?? "user"}`)) {
266639
+ const stopped2 = new Set(dispatchIds);
266640
+ let files;
266641
+ try {
266642
+ files = fs35.readdirSync(root);
266643
+ } catch (e) {
266644
+ if (e.code === "ENOENT") return;
266645
+ throw e;
266646
+ }
266647
+ for (const file of files) {
266648
+ if (!/^[a-f0-9]{64}$/.test(file)) continue;
266649
+ const target = path31.join(root, file);
266650
+ let owner;
266651
+ try {
266652
+ owner = JSON.parse(fs35.readFileSync(target, "utf8"));
266653
+ } catch {
266654
+ continue;
266655
+ }
266656
+ if (!owner?.dispatchId || !stopped2.has(owner.dispatchId)) continue;
266657
+ try {
266658
+ fs35.unlinkSync(target);
266659
+ } catch (e) {
266660
+ if (e.code !== "ENOENT") throw new Error("\u65E0\u6CD5\u56DE\u6536\u65E7\u4EFB\u52A1\u76EE\u5F55\u9501");
266661
+ }
266662
+ }
266663
+ }
266646
266664
 
266647
- // ../cli/src/daemon/execution-recovery.ts
266665
+ // ../cli/src/daemon/task-execution.ts
266666
+ init_src6();
266667
+
266668
+ // ../cli/src/daemon/task-processes.ts
266669
+ var fs36 = __toESM(require("node:fs"), 1);
266670
+ var import_node_child_process16 = require("node:child_process");
266671
+ var psEnv = { ...process.env, LC_ALL: "C" };
266648
266672
  function processBirth(pid) {
266649
- const ps = (0, import_node_child_process16.spawnSync)("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8", timeout: 3e3, env: { ...process.env, LC_ALL: "C" } });
266650
- return ps.status === 0 && ps.stdout.trim() ? ps.stdout.trim() : null;
266673
+ const p2 = (0, import_node_child_process16.spawnSync)("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8", env: psEnv, timeout: 3e3 });
266674
+ if (p2.error) throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u8FDB\u7A0B\u8EAB\u4EFD");
266675
+ return p2.stdout.trim();
266676
+ }
266677
+ function snapshot() {
266678
+ const p2 = (0, import_node_child_process16.spawnSync)("ps", ["-A", "-o", "pid=,ppid=,pgid=,stat=,lstart=,command="], { encoding: "utf8", env: psEnv, timeout: 3e3, maxBuffer: 16 * 1024 * 1024 });
266679
+ if (p2.status !== 0) throw new Error("\u65E0\u6CD5\u6838\u9A8C\u8282\u70B9\u8FDB\u7A0B\u8868");
266680
+ return p2.stdout.split("\n").flatMap((line) => {
266681
+ const parts = line.trim().split(/\s+/);
266682
+ return parts.length < 9 ? [] : [{ pid: Number(parts[0]), ppid: Number(parts[1]), pgid: Number(parts[2]), state: parts[3], birth: parts.slice(4, 9).join(" "), command: parts.slice(9).join(" ") }];
266683
+ });
266651
266684
  }
266652
- function durableWrite(file, value2, exclusive = false) {
266653
- const temp = exclusive ? file : `${file}.${(0, import_node_crypto79.randomUUID)()}.tmp`;
266654
- const fd = fs36.openSync(temp, "wx", 384);
266655
- try {
266656
- fs36.writeFileSync(fd, JSON.stringify(value2));
266657
- fs36.fsyncSync(fd);
266658
- } finally {
266659
- fs36.closeSync(fd);
266660
- }
266661
- if (!exclusive) fs36.renameSync(temp, file);
266662
- const dir = fs36.openSync(path32.dirname(file), "r");
266663
- try {
266664
- fs36.fsyncSync(dir);
266665
- } finally {
266666
- fs36.closeSync(dir);
266685
+ function executionIdentity(environment) {
266686
+ const value2 = (name) => new RegExp(`(?:^|[\\s\\0])${name}=([^\\s\\0]+)`).exec(environment)?.[1];
266687
+ let dispatchId = value2("OASIS_EXECUTION_DISPATCH_ID");
266688
+ if (!dispatchId) {
266689
+ const token = value2("OASIS_TOKEN");
266690
+ if (token?.startsWith("ost_")) {
266691
+ try {
266692
+ const claims = JSON.parse(Buffer.from(token.slice(4).split(".")[0], "base64url").toString("utf8"));
266693
+ if (typeof claims.dispatchId === "string") dispatchId = claims.dispatchId;
266694
+ } catch {
266695
+ }
266696
+ }
266667
266697
  }
266698
+ return { key: value2("OASIS_EXECUTION_KEY"), generation: Number(value2("OASIS_EXECUTION_GENERATION")), dispatchId };
266668
266699
  }
266669
- var ExecutionRecovery = class {
266670
- constructor(sessionsRoot, lockRoot) {
266671
- this.sessionsRoot = sessionsRoot;
266672
- this.lockRoot = lockRoot;
266700
+ function environments(rows) {
266701
+ if (process.platform === "linux") {
266702
+ const out = /* @__PURE__ */ new Map();
266703
+ for (const row of rows) {
266704
+ try {
266705
+ if (fs36.statSync(`/proc/${row.pid}`).uid !== process.getuid?.()) continue;
266706
+ out.set(row.pid, fs36.readFileSync(`/proc/${row.pid}/environ`, "utf8"));
266707
+ } catch (e) {
266708
+ if (!["ENOENT", "ESRCH"].includes(e.code ?? "") && !row.state.startsWith("Z")) throw new Error(`\u65E0\u6CD5\u6838\u9A8C\u8FDB\u7A0B ${row.pid} \u7684\u4EFB\u52A1\u5F52\u5C5E`);
266709
+ }
266710
+ }
266711
+ return out;
266673
266712
  }
266674
- dir(id) {
266675
- const dir = path32.join(`${this.sessionsRoot}.execution-stops`, (0, import_node_crypto79.createHash)("sha256").update(id).digest("hex"));
266676
- const created = fs36.mkdirSync(dir, { recursive: true, mode: 448 });
266677
- if (created) {
266678
- for (let current = dir; ; current = path32.dirname(current)) {
266679
- const fd = fs36.openSync(current, "r");
266680
- try {
266681
- fs36.fsyncSync(fd);
266682
- } finally {
266683
- fs36.closeSync(fd);
266713
+ if (process.platform === "darwin") {
266714
+ const p2 = (0, import_node_child_process16.spawnSync)("ps", ["eww", "-U", String(process.getuid?.()), "-o", "pid=,command="], { encoding: "utf8", env: psEnv, timeout: 3e3, maxBuffer: 32 * 1024 * 1024 });
266715
+ if (p2.status !== 0) throw new Error("\u65E0\u6CD5\u6838\u9A8C\u8282\u70B9\u6267\u884C\u73AF\u5883");
266716
+ return new Map(p2.stdout.split("\n").flatMap((line) => {
266717
+ const m2 = /^\s*(\d+)\s+(.*)$/.exec(line);
266718
+ return m2 ? [[Number(m2[1]), m2[2]]] : [];
266719
+ }));
266720
+ }
266721
+ throw new Error("\u5F53\u524D\u8282\u70B9\u4E0D\u652F\u6301\u53EF\u9A8C\u8BC1\u7684\u4EFB\u52A1\u8FDB\u7A0B\u6811\u6E05\u573A");
266722
+ }
266723
+ async function stopTaskProcesses(scope) {
266724
+ const ids2 = new Set(scope.legacyDispatchIds), safeIds = scope.legacyDispatchIds.map((id) => id.replace(/[^A-Za-z0-9._-]/g, "_"));
266725
+ const captured = /* @__PURE__ */ new Map();
266726
+ const deadline = Date.now() + 2e4;
266727
+ const isOld = (identity) => identity.key === scope.key && identity.generation < scope.generation || Boolean(identity.dispatchId && ids2.has(identity.dispatchId));
266728
+ const signal = (row, sig) => {
266729
+ scope.assertCurrent();
266730
+ if (row.pid === process.pid || row.pid <= 1 || row.birth !== processBirth(row.pid).replace(/\s+/g, " ")) return;
266731
+ try {
266732
+ process.kill(row.pid, sig);
266733
+ } catch (e) {
266734
+ if (e.code !== "ESRCH") throw new Error(`\u65E0\u6CD5\u505C\u6B62\u4EFB\u52A1\u8FDB\u7A0B ${row.pid}`);
266735
+ }
266736
+ };
266737
+ const containers = new Set(scope.checkContainers === false ? [] : scope.containers);
266738
+ const containerAbsent = (name) => {
266739
+ const result = (0, import_node_child_process16.spawnSync)("podman", ["container", "exists", name], { timeout: 3e3 });
266740
+ if (result.status === 1) return true;
266741
+ if (result.status !== 0) throw new Error("\u5BB9\u5668\u505C\u6B62\u72B6\u6001\u65E0\u6CD5\u786E\u8BA4");
266742
+ return false;
266743
+ };
266744
+ const discoverContainers = () => {
266745
+ if (scope.checkContainers === false) return;
266746
+ const podman = (0, import_node_child_process16.spawnSync)("podman", ["ps", "-a", "--format", "{{.Names}}"], { encoding: "utf8", timeout: 3e3 });
266747
+ if (podman.error && podman.error.code !== "ENOENT") throw new Error("\u65E0\u6CD5\u6838\u9A8C\u4EFB\u52A1\u5BB9\u5668");
266748
+ if (!podman.error && podman.status !== 0) throw new Error("\u5BB9\u5668\u5F15\u64CE\u4E0D\u53EF\u7528\uFF0C\u4EFB\u52A1\u5207\u6362\u7B49\u5F85\u8282\u70B9\u4FEE\u590D");
266749
+ if (podman.error?.code === "ENOENT") containers.clear();
266750
+ for (const name of (podman.stdout ?? "").split("\n").filter((n) => /^oasis-(job|wd)-[A-Za-z0-9_-]+$/.test(n))) {
266751
+ const result = (0, import_node_child_process16.spawnSync)("podman", ["inspect", name], { encoding: "utf8", timeout: 3e3, maxBuffer: 8 * 1024 * 1024 });
266752
+ if (result.status !== 0) {
266753
+ if (containerAbsent(name)) {
266754
+ containers.delete(name);
266755
+ continue;
266684
266756
  }
266685
- if (current === path32.dirname(created)) break;
266757
+ throw new Error("\u65E0\u6CD5\u6838\u9A8C\u4EFB\u52A1\u5BB9\u5668\u8EAB\u4EFD");
266758
+ }
266759
+ const config2 = JSON.parse(result.stdout)[0];
266760
+ if (isOld(executionIdentity((config2?.Config?.Env ?? []).join("\0")))) containers.add(name);
266761
+ }
266762
+ };
266763
+ do {
266764
+ scope.assertCurrent();
266765
+ discoverContainers();
266766
+ const rows = snapshot().filter((r) => !r.state.startsWith("Z")), env = environments(rows);
266767
+ const selected = new Set(rows.filter((r) => r.pid !== process.pid && (captured.get(r.pid) === r.birth || scope.owners.some((o) => o.pid === r.pid && o.birth.replace(/\s+/g, " ") === r.birth) || isOld(executionIdentity(env.get(r.pid) ?? r.command)) || r.command.includes("--_session ") && safeIds.some((id) => r.command.includes(`/sessions/${id}/spec.json`)))).map((r) => r.pid));
266768
+ let grew;
266769
+ do {
266770
+ grew = false;
266771
+ for (const row of rows) if (row.pid !== process.pid && selected.has(row.ppid) && !selected.has(row.pid)) {
266772
+ selected.add(row.pid);
266773
+ grew = true;
266774
+ }
266775
+ } while (grew);
266776
+ for (const row of rows.filter((r) => selected.has(r.pid))) {
266777
+ captured.set(row.pid, row.birth);
266778
+ signal(row, "SIGSTOP");
266779
+ }
266780
+ if (selected.size) {
266781
+ const frozen = snapshot().filter((r) => !r.state.startsWith("Z"));
266782
+ do {
266783
+ grew = false;
266784
+ for (const row of frozen) if (row.pid !== process.pid && selected.has(row.ppid) && !selected.has(row.pid)) {
266785
+ selected.add(row.pid);
266786
+ captured.set(row.pid, row.birth);
266787
+ signal(row, "SIGSTOP");
266788
+ grew = true;
266789
+ }
266790
+ } while (grew);
266791
+ for (const row of frozen.filter((r) => selected.has(r.pid))) signal(row, "SIGKILL");
266792
+ }
266793
+ for (const name of [...containers]) {
266794
+ if (containerAbsent(name)) {
266795
+ containers.delete(name);
266796
+ continue;
266797
+ }
266798
+ const state = (0, import_node_child_process16.spawnSync)("podman", ["inspect", "--format", "{{.State.Running}}", name], { encoding: "utf8", timeout: 3e3 });
266799
+ if (state.status !== 0) {
266800
+ if (containerAbsent(name)) {
266801
+ containers.delete(name);
266802
+ continue;
266803
+ }
266804
+ throw new Error("\u5BB9\u5668\u505C\u6B62\u72B6\u6001\u65E0\u6CD5\u786E\u8BA4");
266805
+ }
266806
+ if (state.status === 0 && state.stdout.trim() === "false") {
266807
+ containers.delete(name);
266808
+ continue;
266809
+ }
266810
+ scope.assertCurrent();
266811
+ const killed = (0, import_node_child_process16.spawnSync)("podman", ["kill", name], { timeout: 3e3 });
266812
+ if (killed.status !== 0) {
266813
+ if (containerAbsent(name)) {
266814
+ containers.delete(name);
266815
+ continue;
266816
+ }
266817
+ throw new Error("\u65E0\u6CD5\u7EC8\u6B62\u65E7\u4EFB\u52A1\u5BB9\u5668");
266818
+ }
266819
+ }
266820
+ if (!selected.size && !containers.size && !scope.busy()) return;
266821
+ await new Promise((resolve10) => setTimeout(resolve10, 50));
266822
+ } while (Date.now() < deadline);
266823
+ throw new Error("\u65E7\u4EFB\u52A1\u8FDB\u7A0B\u5C1A\u672A\u5168\u90E8\u505C\u6B62\uFF0C\u8BF7\u68C0\u67E5\u8282\u70B9\u8FDB\u7A0B\u6743\u9650\u6216\u4ECD\u5728\u8FDB\u884C\u7684\u542F\u52A8\u64CD\u4F5C");
266824
+ }
266825
+
266826
+ // ../cli/src/daemon/task-execution.ts
266827
+ function taskKey(job) {
266828
+ let companyId = "";
266829
+ if (job.actorToken.startsWith("ost_")) {
266830
+ try {
266831
+ companyId = JSON.parse(Buffer.from(job.actorToken.slice(4).split(".")[0], "base64url").toString("utf8")).companyId ?? "";
266832
+ } catch {
266833
+ }
266834
+ }
266835
+ return (0, import_node_crypto79.createHash)("sha256").update(JSON.stringify([job.server.url.replace(/\/+$/, ""), companyId, job.jobKey])).digest("hex");
266836
+ }
266837
+ var TaskExecutions = class {
266838
+ constructor(root = process.env["OASIS_TASK_EXECUTIONS_ROOT"] ?? path32.join(os10.homedir(), ".oasis", "task-executions")) {
266839
+ this.root = root;
266840
+ }
266841
+ dir(key) {
266842
+ if (!/^[a-f0-9]{64}$/.test(key)) throw new Error("\u4EFB\u52A1\u6267\u884C\u8EAB\u4EFD\u65E0\u6548");
266843
+ return path32.join(this.root, key);
266844
+ }
266845
+ write(file, data) {
266846
+ fs37.mkdirSync(path32.dirname(file), { recursive: true, mode: 448 });
266847
+ const temporary = `${file}.${(0, import_node_crypto79.randomUUID)()}.tmp`;
266848
+ const fd = fs37.openSync(temporary, "wx", 384);
266849
+ try {
266850
+ try {
266851
+ fs37.writeFileSync(fd, JSON.stringify(data));
266852
+ fs37.fsyncSync(fd);
266853
+ } finally {
266854
+ fs37.closeSync(fd);
266686
266855
  }
266856
+ fs37.linkSync(temporary, file);
266857
+ } finally {
266858
+ fs37.unlinkSync(temporary);
266859
+ }
266860
+ const dir = fs37.openSync(path32.dirname(file), "r");
266861
+ try {
266862
+ fs37.fsyncSync(dir);
266863
+ } finally {
266864
+ fs37.closeSync(dir);
266687
266865
  }
266688
- return dir;
266689
266866
  }
266690
- read(id, file) {
266867
+ generations(key) {
266691
266868
  try {
266692
- return JSON.parse(fs36.readFileSync(path32.join(this.dir(id), file), "utf8"));
266869
+ return fs37.readdirSync(this.dir(key)).filter((n) => /^\d+\.json$/.test(n)).map((n) => Number(n.slice(0, -5)));
266693
266870
  } catch (e) {
266694
- if (e.code === "ENOENT") return null;
266871
+ if (e.code === "ENOENT") return [];
266695
266872
  throw e;
266696
266873
  }
266697
266874
  }
266698
- fenced(id) {
266699
- return fs36.existsSync(path32.join(this.dir(id), "fence.json"));
266875
+ current(key, generation) {
266876
+ return this.generations(key).reduce((max, value2) => Math.max(max, value2), 0) === generation;
266700
266877
  }
266701
- fence(id) {
266702
- durableWrite(path32.join(this.dir(id), "fence.json"), { dispatchId: id });
266703
- }
266704
- begin(id) {
266705
- if (this.fenced(id)) throw new Error("\u65E7\u6D3E\u53D1\u5DF2\u5C01\u7981\uFF0C\u62D2\u7EDD\u8FDF\u5230\u542F\u52A8");
266706
- durableWrite(path32.join(this.dir(id), "owner.json"), { dispatchId: id, pid: process.pid, birth: processBirth(process.pid) }, true);
266707
- if (this.fenced(id)) throw new Error("\u65E7\u6D3E\u53D1\u5DF2\u5C01\u7981\uFF0C\u62D2\u7EDD\u8FDF\u5230\u542F\u52A8");
266878
+ assertAllowed(dispatchId, job) {
266879
+ if (!job.jobKey) return;
266880
+ const key = taskKey(job), execution = job.execution;
266881
+ if (!execution) {
266882
+ if (this.generations(key).length) throw new Error("\u65E7\u8F6E\u6B21\u5DF2\u5931\u6548\uFF0C\u62D2\u7EDD\u65E0\u8F6E\u6B21\u8BB8\u53EF\u7684\u6267\u884C");
266883
+ return;
266884
+ }
266885
+ if (execution.key !== key || !this.current(key, execution.generation)) throw new Error("\u65E7\u8F6E\u6B21\u5DF2\u5931\u6548\uFF0C\u62D2\u7EDD\u91CD\u65B0\u542F\u52A8");
266886
+ const state = JSON.parse(fs37.readFileSync(path32.join(this.dir(key), `${execution.generation}.json`), "utf8"));
266887
+ if (state.dispatchId !== dispatchId || !fs37.existsSync(path32.join(this.dir(key), `${execution.generation}.ready`))) throw new Error("\u4EFB\u52A1\u5C1A\u672A\u5B8C\u6210\u65E7\u8FDB\u7A0B\u6E05\u573A");
266708
266888
  }
266709
- stopped(id, proof = { kind: "runtime_exit", at: (/* @__PURE__ */ new Date()).toISOString() }) {
266710
- this.fence(id);
266711
- if (!this.read(id, "stopped.json")) durableWrite(path32.join(this.dir(id), "stopped.json"), proof);
266889
+ begin(dispatchId, job, isolated = false) {
266890
+ this.assertAllowed(dispatchId, job);
266891
+ if (!job.execution) return;
266892
+ this.write(
266893
+ path32.join(this.dir(job.execution.key), `${job.execution.generation}.started`),
266894
+ { dispatchId, pid: process.pid, birth: processBirth(process.pid), isolated }
266895
+ );
266896
+ try {
266897
+ this.assertAllowed(dispatchId, job);
266898
+ } catch (error2) {
266899
+ this.finish(job);
266900
+ throw error2;
266901
+ }
266712
266902
  }
266713
- verify(id, busy, verification) {
266714
- const result = (state, detail, proof2) => ({ state, detail, at: (/* @__PURE__ */ new Date()).toISOString(), ...proof2 ? { proof: proof2 } : {} });
266715
- this.fence(id);
266716
- const proof = this.read(id, "stopped.json");
266717
- if (proof) {
266718
- if (!Number.isFinite(Date.parse(proof.at)) || !["runtime_exit", "operator_verified"].includes(proof.kind) || proof.kind === "operator_verified" && (!proof.actor?.startsWith("actor:human:") || !proof.evidence?.trim())) {
266719
- throw new Error("\u505C\u6B62\u6536\u636E\u635F\u574F\uFF0C\u4FDD\u6301\u4EFB\u52A1\u9501\uFF1B\u8BF7\u4FDD\u7559\u73B0\u573A\u5E76\u6838\u9A8C\u8BE5\u8BB0\u5F55");
266720
- }
266721
- releaseExecutionLocksForDispatch(id, this.lockRoot);
266722
- return result("stopped", "\u8282\u70B9\u5DF2\u6062\u590D\u6301\u4E45\u505C\u6B62\u6536\u636E", proof);
266903
+ finish(job) {
266904
+ if (!job.execution) return;
266905
+ try {
266906
+ this.write(path32.join(this.dir(job.execution.key), `${job.execution.generation}.finished`), {});
266907
+ } catch (e) {
266908
+ if (e.code !== "EEXIST") throw e;
266723
266909
  }
266724
- if (busy) return result("running", "\u8282\u70B9\u4ECD\u6709\u8FD0\u884C\u53E5\u67C4\u6216\u5F85\u542F\u52A8\u8BB0\u5F55\uFF0C\u7B49\u5F85\u771F\u5B9E\u9000\u51FA");
266725
- const owner = this.read(id, "owner.json");
266726
- if (owner) {
266910
+ }
266911
+ async replace(request2, local) {
266912
+ if (!Number.isSafeInteger(request2.generation) || request2.generation < 1) throw new Error("\u4EFB\u52A1\u8F6E\u6B21\u65E0\u6548");
266913
+ const dir = this.dir(request2.key), file = path32.join(dir, `${request2.generation}.json`);
266914
+ try {
266915
+ this.write(file, request2);
266916
+ } catch (e) {
266917
+ if (e.code !== "EEXIST") throw e;
266918
+ const existing = JSON.parse(fs37.readFileSync(file, "utf8"));
266919
+ if (existing.dispatchId !== request2.dispatchId) throw new Error("\u540C\u4E00\u4EFB\u52A1\u8F6E\u6B21\u8EAB\u4EFD\u51B2\u7A81");
266920
+ }
266921
+ const assertCurrent = () => {
266922
+ if (!this.current(request2.key, request2.generation)) throw new Error("\u6E05\u573A\u8BF7\u6C42\u5DF2\u88AB\u66F4\u65B0\u8F6E\u6B21\u66FF\u4EE3");
266923
+ };
266924
+ assertCurrent();
266925
+ if (fs37.existsSync(path32.join(dir, `${request2.generation}.started`))) throw new Error("\u672C\u8F6E\u5DF2\u7ECF\u542F\u52A8\uFF0C\u62D2\u7EDD\u91CD\u590D\u6E05\u573A\u6216\u542F\u52A8");
266926
+ const ids2 = new Set(request2.legacyDispatchIds);
266927
+ let checkContainers = ids2.size > 0;
266928
+ const owners = [];
266929
+ const pendingOwners = [];
266930
+ for (const generation of this.generations(request2.key).filter((g2) => g2 < request2.generation).sort((a, b2) => b2 - a)) {
266931
+ const older = JSON.parse(fs37.readFileSync(path32.join(dir, `${generation}.json`), "utf8"));
266932
+ const prepared = fs37.existsSync(path32.join(dir, `${generation}.ready`));
266933
+ checkContainers ||= older.usesContainers !== false || !prepared && older.legacyDispatchIds.length > 0;
266934
+ ids2.add(older.dispatchId);
266935
+ if (!prepared) for (const id of older.legacyDispatchIds) ids2.add(id);
266727
266936
  try {
266728
- if (!Number.isSafeInteger(owner.pid) || owner.pid <= 0) throw new Error("\u4F1A\u8BDD\u8FDB\u7A0B\u8EAB\u4EFD\u635F\u574F");
266729
- process.kill(owner.pid, 0);
266730
- const birth = processBirth(owner.pid);
266731
- if (!owner.birth || !birth || birth === owner.birth) return result("running", "\u4F1A\u8BDD\u5BBF\u4E3B\u8FDB\u7A0B\u4ECD\u5B58\u5728\u6216\u8EAB\u4EFD\u65E0\u6CD5\u6392\u9664\uFF0C\u4E0D\u80FD\u4EBA\u5DE5\u786E\u8BA4\u505C\u6B62");
266937
+ const owner = JSON.parse(fs37.readFileSync(path32.join(dir, `${generation}.started`), "utf8"));
266938
+ if (owner.isolated) owners.push(owner);
266939
+ else pendingOwners.push({ ...owner, generation });
266732
266940
  } catch (e) {
266733
- if (e.code !== "ESRCH") return result("unavailable", "\u65E0\u6CD5\u6838\u9A8C\u4F1A\u8BDD\u5BBF\u4E3B\u8FDB\u7A0B");
266941
+ if (e.code !== "ENOENT") throw e;
266734
266942
  }
266943
+ if (prepared) break;
266735
266944
  }
266736
- const legacyDir = path32.join(this.sessionsRoot, id.replace(/[^A-Za-z0-9._-]/g, "_"));
266737
- if (fs36.existsSync(path32.join(legacyDir, "spec.json"))) return result("needs_verification", "\u4ECD\u6709\u5F85\u542F\u52A8 spec\uFF1B\u8BF7\u5728\u8282\u70B9\u6838\u9A8C\u5E76\u79FB\u9664\u8BE5\u65E7\u6D3E\u53D1\u7684\u5F85\u542F\u52A8\u6587\u4EF6");
266738
- const legacyLock = path32.join(legacyDir, "lock");
266739
- if (fs36.existsSync(legacyLock) && (!hasFlock() || isSessionLocked(legacyLock))) {
266740
- return result("running", "\u4F1A\u8BDD\u9501\u4ECD\u88AB\u5360\u7528\u6216\u65E0\u6CD5\u53EF\u9760\u6838\u9A8C");
266945
+ const containers = request2.workdirKey ? [`oasis-wd-${workdirSlug(request2.workdirKey)}`] : [];
266946
+ void local.cancel().catch(() => {
266947
+ });
266948
+ await stopTaskProcesses({
266949
+ key: request2.key,
266950
+ generation: request2.generation,
266951
+ legacyDispatchIds: [...ids2],
266952
+ owners,
266953
+ containers,
266954
+ checkContainers,
266955
+ busy: () => local.busy() || pendingOwners.some((o) => !fs37.existsSync(path32.join(dir, `${o.generation}.finished`)) && processBirth(o.pid) === o.birth),
266956
+ assertCurrent
266957
+ });
266958
+ assertCurrent();
266959
+ clearStoppedExecutionLocks([...ids2]);
266960
+ try {
266961
+ this.write(path32.join(dir, `${request2.generation}.ready`), { at: (/* @__PURE__ */ new Date()).toISOString() });
266962
+ } catch (e) {
266963
+ if (e.code !== "EEXIST") throw e;
266741
266964
  }
266742
- if (!verification) return result("needs_verification", "\u7F3A\u5C11\u505C\u6B62\u6536\u636E\uFF1B\u9700\u9010\u6761\u6838\u9A8C\u65E7\u5B9E\u4F8B\u3001\u5B50\u8FDB\u7A0B\u3001\u5BB9\u5668\u548C\u5F85\u542F\u52A8\u5165\u53E3\uFF0C\u63D0\u4EA4\u4EBA\u5DE5\u6838\u9A8C\u4F9D\u636E");
266743
- const manual = { kind: "operator_verified", at: (/* @__PURE__ */ new Date()).toISOString(), ...verification };
266744
- this.stopped(id, manual);
266745
- releaseExecutionLocksForDispatch(id, this.lockRoot);
266746
- return result("stopped", "\u4EBA\u5DE5\u6838\u9A8C\u5DF2\u8BB0\u5F55\uFF0C\u8282\u70B9\u5DF2\u6301\u4E45\u5C01\u7981\u65E7\u6D3E\u53D1", manual);
266747
266965
  }
266748
266966
  };
266749
266967
 
266750
266968
  // ../cli/src/daemon/session-runner.ts
266751
- init_src();
266752
- init_src6();
266753
- init_src8();
266969
+ init_src5();
266754
266970
  async function preflightOasisAccess(job) {
266755
266971
  const base = job.server.url.replace(/\/+$/, "");
266756
266972
  try {
@@ -266758,6 +266974,7 @@ async function preflightOasisAccess(job) {
266758
266974
  headers: { authorization: `Bearer ${job.actorToken}` },
266759
266975
  signal: AbortSignal.timeout(5e3)
266760
266976
  });
266977
+ if (res.status === 409) return { code: null, reason: "cancelled" };
266761
266978
  if (res.status === 401 || res.status === 403) return { code: null, reason: "auth-error" };
266762
266979
  if (!res.ok) return { code: null, reason: "server-unreachable" };
266763
266980
  return null;
@@ -266767,49 +266984,50 @@ async function preflightOasisAccess(job) {
266767
266984
  }
266768
266985
  async function runSession(dispatchId, job, deps) {
266769
266986
  const t0 = Date.now();
266770
- const originalSink = deps.sink;
266771
- if (deps.recovery) {
266772
- const recovery = deps.recovery;
266773
- deps = { ...deps, sink: { ...originalSink, keyFrame: (msg) => {
266774
- if (msg.type !== "session_exited" || !msg.executionStopped) {
266775
- originalSink.keyFrame(msg);
266776
- return;
266777
- }
266778
- const persist = () => {
266779
- try {
266780
- recovery.stopped(dispatchId);
266781
- } catch (error2) {
266782
- log2("[node-cli]", `\u505C\u6B62\u6536\u636E\u5199\u76D8\u5931\u8D25 ${dispatchId}\uFF0C\u4FDD\u6301\u672A\u786E\u8BA4\uFF1A${String(error2)}`);
266783
- setTimeout(persist, 1e3);
266784
- return;
266785
- }
266786
- originalSink.keyFrame(msg);
266787
- };
266788
- persist();
266789
- } } };
266790
- }
266987
+ const executions = new TaskExecutions();
266988
+ const wasCancelled = () => {
266989
+ if (deps.wasCancelled?.()) return true;
266990
+ try {
266991
+ executions.assertAllowed(dispatchId, job);
266992
+ return false;
266993
+ } catch {
266994
+ return true;
266995
+ }
266996
+ };
266791
266997
  let handle;
266792
266998
  let lock = null;
266793
266999
  let cleanup;
266794
267000
  let exited = false;
266795
267001
  let admitted = false;
267002
+ let began = false;
266796
267003
  const cancelledWithoutRuntime = () => {
267004
+ executions.finish(job);
266797
267005
  lock?.release();
266798
267006
  deps.sink.keyFrame({ type: "session_exited", dispatchId, sessionId: "cancelled-before-spawn", executionStopped: true, info: { code: null, reason: "cancelled" } });
266799
267007
  deps.onFailure?.();
266800
267008
  };
266801
267009
  try {
266802
- deps.recovery?.begin(dispatchId);
267010
+ executions.begin(dispatchId, job, deps.isolatedProcess);
267011
+ began = true;
267012
+ if (job.execution) {
267013
+ job = { ...job, env: {
267014
+ ...job.env,
267015
+ OASIS_EXECUTION_KEY: job.execution.key,
267016
+ OASIS_EXECUTION_GENERATION: String(job.execution.generation),
267017
+ OASIS_EXECUTION_DISPATCH_ID: dispatchId
267018
+ } };
267019
+ }
266803
267020
  lock = acquireExecutionLock(job, dispatchId);
266804
267021
  admitted = true;
266805
- if (deps.wasCancelled?.() || deps.recovery?.fenced(dispatchId)) {
267022
+ if (wasCancelled()) {
266806
267023
  cancelledWithoutRuntime();
266807
267024
  return;
266808
267025
  }
266809
- if (deps.preflight) {
267026
+ if (deps.preflight || job.execution) {
266810
267027
  const preflightFailure = await preflightOasisAccess(job);
266811
267028
  if (preflightFailure) {
266812
267029
  log2("[node-cli]", ` preflight failed: ${preflightFailure.reason}`);
267030
+ executions.finish(job);
266813
267031
  lock?.release();
266814
267032
  deps.sink.keyFrame({ type: "session_exited", dispatchId, sessionId: "preflight-failed", executionStopped: true, info: preflightFailure });
266815
267033
  deps.onFailure?.();
@@ -266822,19 +267040,25 @@ async function runSession(dispatchId, job, deps) {
266822
267040
  }
266823
267041
  const prepared = await prepareConnectorsForJob(job);
266824
267042
  cleanup = prepared.cleanup;
266825
- if (deps.wasCancelled?.() || deps.recovery?.fenced(dispatchId)) {
267043
+ if (wasCancelled()) {
266826
267044
  await cleanup();
266827
267045
  cancelledWithoutRuntime();
266828
267046
  return;
266829
267047
  }
266830
267048
  handle = await deps.adapter.spawn(prepared.job);
267049
+ if (job.execution && job.action === "produce" && job.resumeRuntimeSession) {
267050
+ handle = makeProduceResumeFallback(handle, async () => {
267051
+ if (wasCancelled()) throw new Error("\u65E7\u8F6E\u6B21\u5DF2\u5931\u6548\uFF0C\u62D2\u7EDD\u6062\u590D\u4F1A\u8BDD\u56DE\u843D");
267052
+ return deps.adapter.spawn({ ...prepared.job, resumeRuntimeSession: false });
267053
+ });
267054
+ }
266831
267055
  const startedHandle = handle;
266832
267056
  startedHandle.onExit(() => {
266833
267057
  void prepared.cleanup().catch(() => {
266834
267058
  });
266835
267059
  });
266836
267060
  deps.onHandle?.(handle);
266837
- const cancelledBeforeStart = (deps.wasCancelled?.() || deps.recovery?.fenced(dispatchId)) ?? false;
267061
+ const cancelledBeforeStart = wasCancelled();
266838
267062
  const normalizer = new ProviderStreamNormalizer({
266839
267063
  providerName: job.binding?.runtimeKind ?? "runtime",
266840
267064
  hasLiveProtocol: startedHandle.supportsLiveProtocol === true,
@@ -266856,6 +267080,7 @@ async function runSession(dispatchId, job, deps) {
266856
267080
  startedHandle.onExit((info) => {
266857
267081
  if (exited) return;
266858
267082
  exited = true;
267083
+ executions.finish(job);
266859
267084
  lock?.release();
266860
267085
  normalizer.turnFinished(isHealthySessionExit(info) ? "completed" : "failed");
266861
267086
  log2("[node-cli]", ` \u25A0 session_exited id=${startedHandle.id} code=${info.code ?? "killed"} total=${Date.now() - t0}ms`);
@@ -266873,6 +267098,7 @@ async function runSession(dispatchId, job, deps) {
266873
267098
  }
266874
267099
  } catch (err) {
266875
267100
  if (!admitted && !(err instanceof ExecutionLockConflictError && err.conflictingDispatchId && err.conflictingDispatchId !== dispatchId)) {
267101
+ if (began) executions.finish(job);
266876
267102
  log2("[node-cli]", `\u6267\u884C ${dispatchId} \u505C\u6B62\u672A\u786E\u8BA4\uFF1A${String(err)}`);
266877
267103
  deps.onFailure?.(false);
266878
267104
  return;
@@ -266881,6 +267107,7 @@ async function runSession(dispatchId, job, deps) {
266881
267107
  log2("[node-cli]", `\u6267\u884C ${dispatchId} \u505C\u6B62\u672A\u786E\u8BA4\uFF1A${String(err)}`);
266882
267108
  return;
266883
267109
  }
267110
+ executions.finish(job);
266884
267111
  lock?.release();
266885
267112
  await cleanup?.().catch(() => {
266886
267113
  });
@@ -266913,9 +267140,9 @@ async function runSessionProcess(specFile, adapter) {
266913
267140
  await state.run();
266914
267141
  }
266915
267142
  function readSpec(specFile) {
266916
- const spec = JSON.parse(fs37.readFileSync(specFile, "utf8"));
267143
+ const spec = JSON.parse(fs38.readFileSync(specFile, "utf8"));
266917
267144
  try {
266918
- fs37.unlinkSync(specFile);
267145
+ fs38.unlinkSync(specFile);
266919
267146
  } catch {
266920
267147
  }
266921
267148
  return spec;
@@ -266967,8 +267194,8 @@ var SessionProcessState = class {
266967
267194
  this.finish = resolve10;
266968
267195
  });
266969
267196
  await runSession(this.spec.dispatchId, this.spec.job, {
266970
- recovery: new ExecutionRecovery(path33.dirname(this.spec.sessionDir)),
266971
267197
  adapter: this.adapter,
267198
+ isolatedProcess: true,
266972
267199
  preflight: this.spec.preflight,
266973
267200
  sink: {
266974
267201
  keyFrame: (m2) => this.sendKeyFrame(m2),
@@ -267521,7 +267748,6 @@ var DaemonWsClient = class {
267521
267748
  this.preflight = preflight;
267522
267749
  this.onUpdate = onUpdate;
267523
267750
  this.daemonVersion = daemonVersion;
267524
- this.recovery = opts.sessionsRoot ? new ExecutionRecovery(opts.sessionsRoot) : void 0;
267525
267751
  this.daemonPkg = opts.daemonPkg;
267526
267752
  this.spawnSessionProcess = opts.spawnSessionProcess;
267527
267753
  this.countDetachedSessions = opts.countDetachedSessions;
@@ -267559,9 +267785,10 @@ var DaemonWsClient = class {
267559
267785
  draining = false;
267560
267786
  /** 已回 dispatch_received、尚未完成 runtime spawn 的派发;也随 hello 上报供重连对账。 */
267561
267787
  pendingDispatchIds = /* @__PURE__ */ new Set();
267788
+ dispatchJobs = /* @__PURE__ */ new Map();
267789
+ taskExecutions = new TaskExecutions();
267562
267790
  /** setup 期间收到 kill 的派发。spawn 返回后先杀句柄,不得再宣告 session_started。 */
267563
267791
  cancelledPendingDispatchIds = /* @__PURE__ */ new Set();
267564
- recovery;
267565
267792
  spawnSessionProcess;
267566
267793
  countDetachedSessions;
267567
267794
  /**
@@ -267744,18 +267971,36 @@ var DaemonWsClient = class {
267744
267971
  }
267745
267972
  async handleMessage(msg) {
267746
267973
  switch (msg.type) {
267974
+ case "replace_task": {
267975
+ const matches = () => [...this.dispatchJobs].filter(([id, job]) => id !== msg.dispatchId && (taskKey(job) === msg.key || msg.legacyDispatchIds.includes(id)));
267976
+ try {
267977
+ await this.taskExecutions.replace(msg, {
267978
+ cancel: async () => {
267979
+ for (const [id] of matches()) this.cancelledPendingDispatchIds.add(id);
267980
+ await Promise.all(matches().map(([id]) => this.sessions.kill(id)));
267981
+ },
267982
+ busy: () => matches().some(([id]) => this.pendingDispatchIds.has(id) || Boolean(this.sessions.get(id)))
267983
+ });
267984
+ for (const [id] of matches()) {
267985
+ this.dispatchJobs.delete(id);
267986
+ this.cancelledPendingDispatchIds.delete(id);
267987
+ }
267988
+ this.send({ type: "task_replaced", requestId: msg.requestId, dispatchId: msg.dispatchId, key: msg.key, generation: msg.generation, stopped: true });
267989
+ } catch (e) {
267990
+ this.send({ type: "task_replaced", requestId: msg.requestId, dispatchId: msg.dispatchId, key: msg.key, generation: msg.generation, stopped: false, detail: String(e) });
267991
+ }
267992
+ break;
267993
+ }
267747
267994
  case "dispatch": {
267748
267995
  const { dispatchId, job } = msg;
267996
+ const t0 = Date.now();
267749
267997
  try {
267750
- if (this.recovery?.fenced(dispatchId)) {
267751
- log2("[node-cli]", `\u62D2\u7EDD\u5DF2\u5C01\u7981\u6D3E\u53D1 ${dispatchId}`);
267752
- break;
267753
- }
267754
- } catch (error2) {
267755
- log2("[node-cli]", `\u65E0\u6CD5\u8BFB\u53D6\u6267\u884C\u5C01\u7981\uFF0C\u62D2\u7EDD\u542F\u52A8 ${dispatchId}\uFF1A${String(error2)}`);
267998
+ this.taskExecutions.assertAllowed(dispatchId, job);
267999
+ } catch {
268000
+ log2("[node-cli]", `\u62D2\u7EDD\u5931\u6548\u8F6E\u6B21 ${dispatchId}`);
267756
268001
  break;
267757
268002
  }
267758
- const t0 = Date.now();
268003
+ this.dispatchJobs.set(dispatchId, job);
267759
268004
  log2("[node-cli]", `\u2190 dispatch ${dispatchId} artifact=${job.artifactId}`);
267760
268005
  if (this.pendingDispatchIds.has(dispatchId) || this.sessions.get(dispatchId)) {
267761
268006
  this.send({ type: "dispatch_received", dispatchId });
@@ -267764,7 +268009,6 @@ var DaemonWsClient = class {
267764
268009
  if (this.draining) {
267765
268010
  log2("[node-cli]", ` \u62D2\u6536\uFF1A\u8282\u70B9\u6B63\u5728\u505C\u673A\u6392\u7A7A \u2192 \u56DE\u9000\u51FA\u5E27\uFF0C\u670D\u52A1\u7AEF\u53EF\u7ACB\u5373\u6539\u6D3E`);
267766
268011
  await runSession(dispatchId, job, {
267767
- recovery: this.recovery,
267768
268012
  adapter: this.sessions.getAdapter(),
267769
268013
  preflight: false,
267770
268014
  wasCancelled: () => true,
@@ -267785,7 +268029,6 @@ var DaemonWsClient = class {
267785
268029
  log2("[node-cli]", ` \u72EC\u7ACB\u4F1A\u8BDD\u8FDB\u7A0B\u672A\u63A5\u7BA1\uFF0C\u56DE\u843D\u672C\u8FDB\u7A0B\u8DD1 dispatch=${dispatchId}`);
267786
268030
  }
267787
268031
  await runSession(dispatchId, job, {
267788
- recovery: this.recovery,
267789
268032
  adapter: this.sessions.getAdapter(),
267790
268033
  preflight: this.preflight,
267791
268034
  sink: {
@@ -267804,37 +268047,20 @@ var DaemonWsClient = class {
267804
268047
  },
267805
268048
  wasCancelled: () => this.cancelledPendingDispatchIds.has(dispatchId),
267806
268049
  onExited: () => {
268050
+ this.dispatchJobs.delete(dispatchId);
267807
268051
  this.cancelledPendingDispatchIds.delete(dispatchId);
267808
268052
  this.maybeRunPendingUpdate();
267809
268053
  },
267810
268054
  onFailure: () => {
268055
+ this.dispatchJobs.delete(dispatchId);
267811
268056
  this.pendingDispatchIds.delete(dispatchId);
267812
268057
  this.cancelledPendingDispatchIds.delete(dispatchId);
267813
268058
  }
267814
268059
  });
267815
268060
  break;
267816
268061
  }
267817
- case "verify_execution_stop": {
267818
- let result;
267819
- try {
267820
- result = this.recovery ? this.recovery.verify(msg.dispatchId, this.pendingDispatchIds.has(msg.dispatchId) || !!this.sessions.get(msg.dispatchId), msg.verification) : { state: "unavailable", at: (/* @__PURE__ */ new Date()).toISOString(), detail: "\u8282\u70B9\u672A\u914D\u7F6E\u6301\u4E45\u4F1A\u8BDD\u76EE\u5F55\uFF0C\u8BF7\u5347\u7EA7\u8282\u70B9" };
267821
- if (result.state === "running") {
267822
- if (this.pendingDispatchIds.has(msg.dispatchId)) this.cancelledPendingDispatchIds.add(msg.dispatchId);
267823
- await this.sessions.kill(msg.dispatchId);
267824
- }
267825
- } catch (e) {
267826
- result = { state: "unavailable", at: (/* @__PURE__ */ new Date()).toISOString(), detail: `\u8282\u70B9\u6838\u9A8C\u5931\u8D25\uFF1A${String(e)}` };
267827
- }
267828
- this.send({ type: "execution_stop_result", requestId: msg.requestId, dispatchId: msg.dispatchId, result });
267829
- break;
267830
- }
267831
268062
  case "kill": {
267832
268063
  log2("[node-cli]", `\u2190 kill dispatch=${msg.dispatchId}`);
267833
- try {
267834
- this.recovery?.fence(msg.dispatchId);
267835
- } catch (error2) {
267836
- log2("[node-cli]", `\u5C01\u7981\u5199\u76D8\u5931\u8D25 ${msg.dispatchId}\uFF0C\u4ECD\u8BF7\u6C42\u505C\u6B62\uFF1A${String(error2)}`);
267837
- }
267838
268064
  const killed = await this.sessions.kill(msg.dispatchId);
267839
268065
  if (!killed && this.pendingDispatchIds.has(msg.dispatchId)) {
267840
268066
  this.cancelledPendingDispatchIds.add(msg.dispatchId);
@@ -268060,7 +268286,6 @@ var DaemonWsClient = class {
268060
268286
  // probe honest. See DaemonMeta.runtimeCapabilities for the split rationale.
268061
268287
  runtimeCapabilities: this.runtimes,
268062
268288
  nodeVersion: process.version,
268063
- ...this.recovery ? { supportsExecutionStopRecovery: true } : {},
268064
268289
  ...this.daemonVersion ? { daemonVersion: this.daemonVersion } : {},
268065
268290
  ...this.daemonPkg ? { daemonPkg: this.daemonPkg } : {},
268066
268291
  connectorReadiness: inspectConnectorRuntimeReadiness(),
@@ -268071,6 +268296,7 @@ var DaemonWsClient = class {
268071
268296
  // **恒 true**——归一层在 `_core` 里、与具体 adapter 无关,装了这版 daemon 就一定发。
268072
268297
  // 服务端据此决定是用节点归一还是自己就地归一;判据取能力位而不是「见过帧没有」,
268073
268298
  // 否则首个 chunk 之前那段窗口两边都不归一,正文会静默丢一截。
268299
+ supportsTaskReplacement: true,
268074
268300
  supportsNormalizedEvents: true,
268075
268301
  ...activeSessions.length > 0 ? { activeSessions } : {},
268076
268302
  // 始终带字段(空数组也带)作为新协议能力标志;服务端仅对支持该字段的节点做缺席确认。
@@ -268219,7 +268445,6 @@ async function startNode(opts) {
268219
268445
  ...opts.daemonPkg ? { daemonPkg: opts.daemonPkg } : {},
268220
268446
  // chat 文件浏览 handler 用它定位会话目录;production 不传 = 与 adapter 同款默认根(~/.oasis/work)。
268221
268447
  ...opts.workRoot !== void 0 ? { workRoot: opts.workRoot } : {},
268222
- ...opts.sessionsRoot ? { sessionsRoot: opts.sessionsRoot } : {},
268223
268448
  ...opts.spawnSessionProcess ? { spawnSessionProcess: opts.spawnSessionProcess } : {},
268224
268449
  ...opts.countDetachedSessions ? { countDetachedSessions: opts.countDetachedSessions } : {}
268225
268450
  });
@@ -268270,7 +268495,7 @@ async function startNode(opts) {
268270
268495
  }
268271
268496
 
268272
268497
  // ../cli/src/exec.ts
268273
- var os12 = __toESM(require("node:os"), 1);
268498
+ var os13 = __toESM(require("node:os"), 1);
268274
268499
  var UnsafeExecArgvError = class extends Error {
268275
268500
  code = "ERR_UNSAFE_EXEC_ARGV";
268276
268501
  constructor(message) {
@@ -268307,7 +268532,7 @@ function planExec(opts) {
268307
268532
  function computeExitCode(code2, signal) {
268308
268533
  if (code2 !== null) return code2;
268309
268534
  if (signal) {
268310
- const num3 = os12.constants.signals[signal];
268535
+ const num3 = os13.constants.signals[signal];
268311
268536
  return 128 + (typeof num3 === "number" ? num3 : 1);
268312
268537
  }
268313
268538
  return 1;
@@ -268410,7 +268635,7 @@ init_src5();
268410
268635
  init_src6();
268411
268636
 
268412
268637
  // ../cli/src/workorder-attachments.ts
268413
- var fs40 = __toESM(require("node:fs"), 1);
268638
+ var fs41 = __toESM(require("node:fs"), 1);
268414
268639
  var path36 = __toESM(require("node:path"), 1);
268415
268640
  init_src();
268416
268641
  var MIME_BY_EXTENSION = {
@@ -268459,7 +268684,7 @@ function parseLocalWorkorderAttachments(argv) {
268459
268684
  return out;
268460
268685
  }
268461
268686
  function readLocalWorkorderAttachment(input) {
268462
- const stat3 = fs40.statSync(input.path);
268687
+ const stat3 = fs41.statSync(input.path);
268463
268688
  if (!stat3.isFile()) throw new Error(`\u9644\u4EF6\u4E0D\u662F\u6587\u4EF6\uFF1A${input.path}`);
268464
268689
  if (stat3.size > WORKORDER_ATTACHMENT_MAX_BYTES) {
268465
268690
  throw new Error(`\u9644\u4EF6\u300C${path36.basename(input.path)}\u300D\u8D85\u8FC7 10MB`);
@@ -268467,7 +268692,7 @@ function readLocalWorkorderAttachment(input) {
268467
268692
  return {
268468
268693
  name: path36.basename(input.path),
268469
268694
  contentType: input.contentType ?? inferAttachmentContentType(input.path),
268470
- contentBase64: fs40.readFileSync(input.path).toString("base64")
268695
+ contentBase64: fs41.readFileSync(input.path).toString("base64")
268471
268696
  };
268472
268697
  }
268473
268698
 
@@ -270569,7 +270794,7 @@ function fieldsFromFlags(flags, ownFlags) {
270569
270794
  }
270570
270795
  return Object.keys(fields).length > 0 ? fields : void 0;
270571
270796
  }
270572
- function buildStageOp(cmd, flags, positional, readFile9 = (file) => fs41.readFileSync(file, "utf8")) {
270797
+ function buildStageOp(cmd, flags, positional, readFile9 = (file) => fs42.readFileSync(file, "utf8")) {
270573
270798
  switch (cmd) {
270574
270799
  case "link":
270575
270800
  return {
@@ -270703,43 +270928,43 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270703
270928
  const nodeTokenFile = path37.join(dir, "node-token");
270704
270929
  const enrollTokenFile = path37.join(dir, "enroll-token");
270705
270930
  const reportMarkerFile = path37.join(dir, "report-runtimes");
270706
- const persistedNodeId = fs41.existsSync(nodeIdFile) ? fs41.readFileSync(nodeIdFile, "utf8").trim() : null;
270931
+ const persistedNodeId = fs42.existsSync(nodeIdFile) ? fs42.readFileSync(nodeIdFile, "utf8").trim() : null;
270707
270932
  let nodeId = persistedNodeId || resolveNodeId();
270708
270933
  const explicitToken = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"];
270709
- let token2 = explicitToken ?? (fs41.existsSync(nodeTokenFile) ? fs41.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
270710
- const enrollToken = flags.get("enroll-token") ?? process.env["OASIS_ENROLL_TOKEN"] ?? (fs41.existsSync(enrollTokenFile) ? fs41.readFileSync(enrollTokenFile, "utf8").trim() : void 0);
270934
+ let token2 = explicitToken ?? (fs42.existsSync(nodeTokenFile) ? fs42.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
270935
+ const enrollToken = flags.get("enroll-token") ?? process.env["OASIS_ENROLL_TOKEN"] ?? (fs42.existsSync(enrollTokenFile) ? fs42.readFileSync(enrollTokenFile, "utf8").trim() : void 0);
270711
270936
  let freshEnrollment = false;
270712
270937
  if (enrollToken && !explicitToken) {
270713
270938
  const httpBase2 = serverUrl.replace(/^ws(s?):\/\//, "http$1://").replace(/\/node-gateway.*$/, "");
270714
270939
  const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
270715
270940
  method: "POST",
270716
270941
  headers: { "content-type": "application/json" },
270717
- body: JSON.stringify({ enrollToken, nodeId, hostname: os13.hostname(), serverUrl, ...companyId ? { companyId } : {} })
270942
+ body: JSON.stringify({ enrollToken, nodeId, hostname: os14.hostname(), serverUrl, ...companyId ? { companyId } : {} })
270718
270943
  });
270719
270944
  if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
270720
270945
  const body2 = await res.json();
270721
270946
  nodeId = body2.nodeId;
270722
270947
  token2 = body2.token;
270723
- fs41.mkdirSync(dir, { recursive: true });
270724
- fs41.writeFileSync(nodeIdFile, nodeId);
270725
- fs41.writeFileSync(nodeTokenFile, token2, { mode: 384 });
270948
+ fs42.mkdirSync(dir, { recursive: true });
270949
+ fs42.writeFileSync(nodeIdFile, nodeId);
270950
+ fs42.writeFileSync(nodeTokenFile, token2, { mode: 384 });
270726
270951
  try {
270727
- fs41.unlinkSync(enrollTokenFile);
270952
+ fs42.unlinkSync(enrollTokenFile);
270728
270953
  } catch {
270729
270954
  }
270730
270955
  freshEnrollment = true;
270731
270956
  }
270732
270957
  if (!nodeId) throw new Error("no nodeId \u2014 provide --enroll-token <ent_...> on first run");
270733
- const scriptRun = freshEnrollment || fs41.existsSync(reportMarkerFile);
270958
+ const scriptRun = freshEnrollment || fs42.existsSync(reportMarkerFile);
270734
270959
  if (flags.has("service")) {
270735
270960
  const { spawnSync: spawnSync5, execSync: execSync2 } = await import("node:child_process");
270736
270961
  if (token2) {
270737
- fs41.mkdirSync(dir, { recursive: true });
270738
- fs41.writeFileSync(nodeTokenFile, token2, { mode: 384 });
270962
+ fs42.mkdirSync(dir, { recursive: true });
270963
+ fs42.writeFileSync(nodeTokenFile, token2, { mode: 384 });
270739
270964
  }
270740
270965
  if (scriptRun) {
270741
- fs41.mkdirSync(dir, { recursive: true });
270742
- fs41.writeFileSync(reportMarkerFile, "");
270966
+ fs42.mkdirSync(dir, { recursive: true });
270967
+ fs42.writeFileSync(reportMarkerFile, "");
270743
270968
  }
270744
270969
  println("\u2192 Installing oasis_test globally...");
270745
270970
  spawnSync5("npm", ["install", "-g", "oasis_test@latest"], { stdio: "inherit" });
@@ -270747,11 +270972,11 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270747
270972
  const binPath = path37.join(prefix, "bin", "oasis_test");
270748
270973
  const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
270749
270974
  if (process.platform === "linux") {
270750
- const svcFile = path37.join(os13.homedir(), ".config/systemd/user/oasis-node.service");
270751
- fs41.mkdirSync(path37.dirname(svcFile), { recursive: true });
270975
+ const svcFile = path37.join(os14.homedir(), ".config/systemd/user/oasis-node.service");
270976
+ fs42.mkdirSync(path37.dirname(svcFile), { recursive: true });
270752
270977
  if (spawnSync5("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
270753
270978
  spawnSync5("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
270754
- fs41.writeFileSync(svcFile, [
270979
+ fs42.writeFileSync(svcFile, [
270755
270980
  "[Unit]",
270756
270981
  "Description=Oasis Node Daemon",
270757
270982
  "After=network.target",
@@ -270760,7 +270985,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270760
270985
  `ExecStart=${binPath} ${svcArgs}`,
270761
270986
  // Carry the install-time PATH so the detached daemon detects CLIs in user dirs
270762
270987
  // (~/.npm-global/bin, ~/.local/bin) — systemd --user otherwise gives a minimal PATH.
270763
- `Environment=PATH=${process.env["PATH"] ?? ""}:${path37.join(os13.homedir(), ".npm-global/bin")}:${path37.join(os13.homedir(), ".local/bin")}:/usr/local/bin`,
270988
+ `Environment=PATH=${process.env["PATH"] ?? ""}:${path37.join(os14.homedir(), ".npm-global/bin")}:${path37.join(os14.homedir(), ".local/bin")}:/usr/local/bin`,
270764
270989
  "Restart=on-failure",
270765
270990
  "RestartSec=5",
270766
270991
  "StandardOutput=journal",
@@ -270772,31 +270997,31 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270772
270997
  ].join("\n"));
270773
270998
  spawnSync5("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
270774
270999
  spawnSync5("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
270775
- spawnSync5("loginctl", ["enable-linger", os13.userInfo().username], { stdio: "ignore" });
271000
+ spawnSync5("loginctl", ["enable-linger", os14.userInfo().username], { stdio: "ignore" });
270776
271001
  println("\u2713 Oasis node service started (systemd --user oasis-node)");
270777
271002
  println(" Status : systemctl --user status oasis-node");
270778
271003
  println(" Logs : journalctl --user -u oasis-node -f");
270779
271004
  println(" Stop : systemctl --user stop oasis-node");
270780
271005
  } else if (process.platform === "darwin") {
270781
- const plist = path37.join(os13.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
270782
- fs41.mkdirSync(path37.dirname(plist), { recursive: true });
271006
+ const plist = path37.join(os14.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
271007
+ fs42.mkdirSync(path37.dirname(plist), { recursive: true });
270783
271008
  spawnSync5("launchctl", ["unload", plist], { stdio: "ignore" });
270784
271009
  const argXml = [binPath, "node", "--server-ws", serverUrl, "--dir", dir, ...nodeName ? ["--name", nodeName] : []].map((a) => `<string>${a}</string>`).join("");
270785
- fs41.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${os13.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os13.homedir()}/.oasis-node.err</string></dict></plist>`);
271010
+ fs42.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${os14.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os14.homedir()}/.oasis-node.err</string></dict></plist>`);
270786
271011
  spawnSync5("launchctl", ["load", plist], { stdio: "inherit" });
270787
271012
  println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
270788
- println(` Logs : tail -f ${os13.homedir()}/.oasis-node.log`);
271013
+ println(` Logs : tail -f ${os14.homedir()}/.oasis-node.log`);
270789
271014
  println(` Stop : launchctl unload ${plist}`);
270790
271015
  } else {
270791
- spawnSync5("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path37.join(os13.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
271016
+ spawnSync5("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path37.join(os14.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
270792
271017
  println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
270793
271018
  println(" Note: no automatic restart on reboot in this environment.");
270794
271019
  }
270795
271020
  return;
270796
271021
  }
270797
- if (fs41.existsSync(reportMarkerFile)) {
271022
+ if (fs42.existsSync(reportMarkerFile)) {
270798
271023
  try {
270799
- fs41.unlinkSync(reportMarkerFile);
271024
+ fs42.unlinkSync(reportMarkerFile);
270800
271025
  } catch {
270801
271026
  }
270802
271027
  }
@@ -270877,7 +271102,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270877
271102
  const outFile = flags.get("out");
270878
271103
  const lines = samples.map((sample) => JSON.stringify(sample)).join("\n");
270879
271104
  if (outFile !== void 0) {
270880
- fs41.writeFileSync(outFile, lines + (lines ? "\n" : ""));
271105
+ fs42.writeFileSync(outFile, lines + (lines ? "\n" : ""));
270881
271106
  println(`\u5DF2\u5BFC\u51FA ${samples.length} \u6761\u8F68\u8FF9\u6837\u672C \u2192 ${outFile}\uFF08approved/rejected \u6210\u5BF9\u5373\u504F\u597D\u5BF9\uFF09`);
270882
271107
  } else {
270883
271108
  println(lines);
@@ -270887,8 +271112,8 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270887
271112
  if (command === "serve" && positional[0] === "install") {
270888
271113
  const absDir = path37.resolve(dir);
270889
271114
  const name = `oasis-serve-${path37.basename(absDir)}`;
270890
- const unitDir = flags.get("unit-dir") ?? path37.join(os13.homedir(), ".config", "systemd", "user");
270891
- const bin = flags.get("bin") ?? path37.join(os13.homedir(), ".local", "bin", "oasis");
271115
+ const unitDir = flags.get("unit-dir") ?? path37.join(os14.homedir(), ".config", "systemd", "user");
271116
+ const bin = flags.get("bin") ?? path37.join(os14.homedir(), ".local", "bin", "oasis");
270892
271117
  const port = flags.get("port") ?? "7320";
270893
271118
  const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
270894
271119
  const unit = [
@@ -270905,9 +271130,9 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270905
271130
  `WantedBy=default.target`,
270906
271131
  ``
270907
271132
  ].join("\n");
270908
- fs41.mkdirSync(unitDir, { recursive: true });
271133
+ fs42.mkdirSync(unitDir, { recursive: true });
270909
271134
  const unitPath = path37.join(unitDir, `${name}.service`);
270910
- fs41.writeFileSync(unitPath, unit);
271135
+ fs42.writeFileSync(unitPath, unit);
270911
271136
  println(`\u5DF2\u5199\u5165 ${unitPath}`);
270912
271137
  println(`\u542F\u7528\uFF1Asystemctl --user daemon-reload && systemctl --user enable --now ${name}`);
270913
271138
  println(`\u5F00\u673A\u81EA\u542F\uFF08\u542B\u672A\u767B\u5F55\uFF09\uFF1Aloginctl enable-linger $USER`);
@@ -270953,7 +271178,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270953
271178
  }
270954
271179
  const base = flags.get("server") ?? process.env["OASIS_SERVER"] ?? "http://127.0.0.1:7320";
270955
271180
  const tokenFile = path37.join(dir, "operator-token");
270956
- const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs41.existsSync(tokenFile) ? fs41.readFileSync(tokenFile, "utf8").trim() : void 0);
271181
+ const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs42.existsSync(tokenFile) ? fs42.readFileSync(tokenFile, "utf8").trim() : void 0);
270957
271182
  if (!token) {
270958
271183
  throw new Error(`\u65E0 token\uFF1A\u5148 oasis serve\uFF08\u4F1A\u751F\u6210 ${tokenFile}\uFF09\uFF0C\u6216\u663E\u5F0F --token / $OASIS_TOKEN`);
270959
271184
  }
@@ -270964,7 +271189,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270964
271189
  println(JSON.stringify({ mode: flags.get("execute") === "true" ? "execute" : "dry-run", count: rows.length, records: rows }, null, 2));
270965
271190
  return;
270966
271191
  }
270967
- const readFileArg = (file) => fs41.readFileSync(file, "utf8");
271192
+ const readFileArg = (file) => fs42.readFileSync(file, "utf8");
270968
271193
  const parseJsonFlag = (value2, name) => {
270969
271194
  const parsed = JSON.parse(value2);
270970
271195
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -270980,11 +271205,11 @@ async function runCli(argv, println = console.log, progressln = console.error) {
270980
271205
  const readDirFiles = (root) => {
270981
271206
  const out = [];
270982
271207
  const walk = (abs, rel) => {
270983
- for (const name of fs41.readdirSync(abs)) {
271208
+ for (const name of fs42.readdirSync(abs)) {
270984
271209
  const childAbs = path37.join(abs, name);
270985
271210
  const childRel = rel ? `${rel}/${name}` : name;
270986
- if (fs41.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
270987
- else out.push({ path: childRel, contentBase64: fs41.readFileSync(childAbs).toString("base64") });
271211
+ if (fs42.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
271212
+ else out.push({ path: childRel, contentBase64: fs42.readFileSync(childAbs).toString("base64") });
270988
271213
  }
270989
271214
  };
270990
271215
  walk(root, "");
@@ -271041,7 +271266,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
271041
271266
  if (items.length > ATTACHMENT_MAX_COUNT) throw new Error(`\u9644\u4EF6\u6700\u591A ${ATTACHMENT_MAX_COUNT} \u4E2A`);
271042
271267
  const uploaded = [];
271043
271268
  for (const item of items) {
271044
- const st = fs41.statSync(item.file);
271269
+ const st = fs42.statSync(item.file);
271045
271270
  if (!st.isFile()) throw new Error(`\u9644\u4EF6\u4E0D\u662F\u6587\u4EF6\uFF1A${item.file}`);
271046
271271
  if (st.size > ATTACHMENT_MAX_BYTES) throw new Error(`\u9644\u4EF6\u8D85\u8FC7 10MB\uFF1A${item.file}`);
271047
271272
  const contentType = item.contentType ?? mimeOf(item.file);
@@ -271049,7 +271274,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
271049
271274
  const res = await api.post("/api/chat/attachments", {
271050
271275
  name,
271051
271276
  contentType,
271052
- contentBase64: fs41.readFileSync(item.file).toString("base64")
271277
+ contentBase64: fs42.readFileSync(item.file).toString("base64")
271053
271278
  });
271054
271279
  if (!res.blobRef) throw new Error(`\u9644\u4EF6\u4E0A\u4F20\u672A\u8FD4\u56DE blobRef\uFF1A${item.file}`);
271055
271280
  uploaded.push({ name, contentType, url: blobUrlOf(res.blobRef) });
@@ -271300,16 +271525,16 @@ Trace: ${run.traceRunId}`);
271300
271525
  const url = flags.get("url");
271301
271526
  if (Boolean(file) === Boolean(url)) throw new Error("oasis kb ingest \u5FC5\u987B\u4E14\u53EA\u80FD\u4F20 --file \u6216 --url");
271302
271527
  if (file) {
271303
- if (!fs41.existsSync(file) || !fs41.statSync(file).isFile()) throw new Error(`\u5165\u5E93\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${file}`);
271528
+ if (!fs42.existsSync(file) || !fs42.statSync(file).isFile()) throw new Error(`\u5165\u5E93\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${file}`);
271304
271529
  const extension3 = path37.extname(file).toLowerCase();
271305
271530
  if (![".md", ".txt", ".pdf"].includes(extension3)) throw new Error("V1 \u53EA\u652F\u6301 Markdown\u3001TXT \u548C PDF \u6587\u4EF6");
271306
- if (fs41.statSync(file).size > ATTACHMENT_MAX_BYTES) throw new Error(`\u5165\u5E93\u6587\u4EF6\u8D85\u8FC7 10MB\uFF1A${file}`);
271531
+ if (fs42.statSync(file).size > ATTACHMENT_MAX_BYTES) throw new Error(`\u5165\u5E93\u6587\u4EF6\u8D85\u8FC7 10MB\uFF1A${file}`);
271307
271532
  const name = path37.basename(file);
271308
271533
  const contentType = mimeOf(file);
271309
271534
  const uploaded = await api.post("/api/chat/attachments", {
271310
271535
  name,
271311
271536
  contentType,
271312
- contentBase64: fs41.readFileSync(file).toString("base64")
271537
+ contentBase64: fs42.readFileSync(file).toString("base64")
271313
271538
  });
271314
271539
  if (!uploaded.blobRef) throw new Error("\u9644\u4EF6\u4E0A\u4F20\u672A\u8FD4\u56DE blobRef");
271315
271540
  request2 = { action: "ingest", attachmentRef: uploaded.blobRef, attachmentName: name, attachmentContentType: contentType };
@@ -271363,7 +271588,7 @@ Trace: ${run.traceRunId}`);
271363
271588
  const cleanup = async () => {
271364
271589
  if (tmpDir) {
271365
271590
  try {
271366
- await fs41.promises.rm(tmpDir, { recursive: true, force: true });
271591
+ await fs42.promises.rm(tmpDir, { recursive: true, force: true });
271367
271592
  } catch {
271368
271593
  }
271369
271594
  }
@@ -271371,9 +271596,9 @@ Trace: ${run.traceRunId}`);
271371
271596
  if (plan.inject.mode === "env") {
271372
271597
  childEnv[plan.inject.envName] = value2;
271373
271598
  } else {
271374
- tmpDir = await fs41.promises.mkdtemp(path37.join(os13.tmpdir(), "oasis-var-exec-"));
271599
+ tmpDir = await fs42.promises.mkdtemp(path37.join(os14.tmpdir(), "oasis-var-exec-"));
271375
271600
  const keyfile = path37.join(tmpDir, "value");
271376
- await fs41.promises.writeFile(keyfile, value2, { mode: 384 });
271601
+ await fs42.promises.writeFile(keyfile, value2, { mode: 384 });
271377
271602
  childEnv[plan.inject.fileEnv] = keyfile;
271378
271603
  }
271379
271604
  const { spawn: spawn5 } = await import("node:child_process");
@@ -271689,7 +271914,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
271689
271914
  break;
271690
271915
  }
271691
271916
  case "create-workorder": {
271692
- const planRaw = flags.get("plan-file") !== void 0 ? fs41.readFileSync(flags.get("plan-file"), "utf8") : flags.get("plan");
271917
+ const planRaw = flags.get("plan-file") !== void 0 ? fs42.readFileSync(flags.get("plan-file"), "utf8") : flags.get("plan");
271693
271918
  const acceptanceFlag = flags.get("acceptance");
271694
271919
  const type = need(flags, "type");
271695
271920
  const title = need(flags, "title");
@@ -271908,7 +272133,7 @@ ${t.ref} ${t.name} [\u5267\u672C=${t.playbookRef}]`);
271908
272133
  if (verb === "add") {
271909
272134
  const file = flags.get("file");
271910
272135
  if (file !== void 0) {
271911
- const bytes2 = fs41.readFileSync(file);
272136
+ const bytes2 = fs42.readFileSync(file);
271912
272137
  const res = await api.request("POST", `/api/projects/${encodeURIComponent(projectId2)}/files`, {
271913
272138
  name: flags.get("name") ?? path37.basename(file),
271914
272139
  ...flags.has("path") ? { path: flags.get("path") } : {},
@@ -272082,14 +272307,14 @@ ${res.warning}`);
272082
272307
  const LEGACY_DESIGN_SYSTEM_PROMPT = "\u4F60\u662F\u8BBE\u8BA1\u5F15\u64CE\u4E2D\u7684\u754C\u9762\u8BBE\u8BA1\u5E08\u3002\u4EFB\u52A1\u4E66\u89C1\u672C\u6761\u6D88\u606F\uFF1B\u4E0A\u6E38\u8F93\u5165\u7B49\u4E0A\u4E0B\u6587\u6587\u4EF6\u5728\u9879\u76EE task-context/ \u76EE\u5F55\u3002\u6309\u4EFB\u52A1\u4E66\u7684\u300C\u600E\u4E48\u63D0\u4EA4\u300D\u534F\u8BAE\u5DE5\u4F5C\uFF1A\u4EA7\u51FA\u81EA\u5305\u542B HTML \u5165\u53E3\u7A3F\u4E0E acceptance.md\uFF0C\u5B8C\u6210\u5373\u7ED3\u675F\u56DE\u590D\uFF0C\u4EA4\u7A3F\u7531\u7CFB\u7EDF\u4EE3\u529E\u3002";
272083
272308
  if (sub === "chat") {
272084
272309
  const artifactId2 = needPos(positional, 1, "oasis design chat <artifactId> --message <t>");
272085
- const message2 = flags.get("message") ?? (["DESIGN_BRIEF.md", "TASK.md"].map((f2) => fs41.existsSync(f2) ? fs41.readFileSync(f2, "utf8") : "").find((s2) => s2.trim()) ?? "");
272310
+ const message2 = flags.get("message") ?? (["DESIGN_BRIEF.md", "TASK.md"].map((f2) => fs42.existsSync(f2) ? fs42.readFileSync(f2, "utf8") : "").find((s2) => s2.trim()) ?? "");
272086
272311
  if (!message2.trim()) throw new Error("\u65E0\u5BF9\u8BDD\u5185\u5BB9\uFF1A\u7ED9 --message <text>\uFF0C\u6216\u5728\u5F53\u524D\u76EE\u5F55\u653E DESIGN_BRIEF.md / TASK.md");
272087
272312
  const odBase2 = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
272088
272313
  const isContinue = flags.get("turn") === "continue";
272089
272314
  const contextFiles2 = {};
272090
272315
  if (!isContinue) {
272091
272316
  contextFiles2["DESIGN_BRIEF.md"] = message2;
272092
- if (fs41.existsSync("inputs") && fs41.statSync("inputs").isDirectory()) {
272317
+ if (fs42.existsSync("inputs") && fs42.statSync("inputs").isDirectory()) {
272093
272318
  for (const f2 of readDirFiles("inputs")) {
272094
272319
  contextFiles2[`inputs/${f2.path}`] = Buffer.from(f2.contentBase64, "base64").toString("utf8");
272095
272320
  }
@@ -272145,7 +272370,7 @@ ${res.warning}`);
272145
272370
  for (const a of st.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.mtime ? ` \xB7 ${new Date(a.mtime).toISOString()}` : ""}`);
272146
272371
  if (flags.get("pull") === "true") {
272147
272372
  const odPublic2 = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
272148
- const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2, os13.tmpdir(), st.boardKey, st.runs[0]?.runId ?? "status-pull");
272373
+ const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2, os14.tmpdir(), st.boardKey, st.runs[0]?.runId ?? "status-pull");
272149
272374
  println(`[design] \u5DF2\u62C9\u5230\u672C\u5730\uFF1A${dir3}\uFF08\u5165\u53E3 ${entry2}\uFF09`);
272150
272375
  println(`[design] \u8BFB\u5B8C\u6EE1\u610F\u5373\u4EA4\u7A3F\uFF1Aoasis propose ${artifactId2} --from-dir ${dir3} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"`);
272151
272376
  } else {
@@ -272157,11 +272382,11 @@ ${res.warning}`);
272157
272382
  const artifactId = needPos(positional, 1, "oasis design run <artifactId>");
272158
272383
  const odBase = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
272159
272384
  const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
272160
- const briefFile = ["DESIGN_BRIEF.md", "TASK.md"].find((f2) => fs41.existsSync(f2));
272161
- const brief = flags.get("brief") ?? (briefFile ? fs41.readFileSync(briefFile, "utf8") : "");
272385
+ const briefFile = ["DESIGN_BRIEF.md", "TASK.md"].find((f2) => fs42.existsSync(f2));
272386
+ const brief = flags.get("brief") ?? (briefFile ? fs42.readFileSync(briefFile, "utf8") : "");
272162
272387
  if (!brief.trim()) throw new Error("\u65E0\u8BBE\u8BA1\u4EFB\u52A1\uFF1A\u7ED9 --brief <text>\uFF0C\u6216\u5728\u5F53\u524D\u76EE\u5F55\u653E DESIGN_BRIEF.md / TASK.md");
272163
272388
  const contextFiles = { "DESIGN_BRIEF.md": brief };
272164
- if (fs41.existsSync("inputs") && fs41.statSync("inputs").isDirectory()) {
272389
+ if (fs42.existsSync("inputs") && fs42.statSync("inputs").isDirectory()) {
272165
272390
  for (const f2 of readDirFiles("inputs")) {
272166
272391
  contextFiles[`inputs/${f2.path}`] = Buffer.from(f2.contentBase64, "base64").toString("utf8");
272167
272392
  }
@@ -272675,22 +272900,22 @@ ${res.warning}`);
272675
272900
  }
272676
272901
  if (sub === "push") {
272677
272902
  const dir2 = needPos(positional, 1, "oasis skill push <\u76EE\u5F55> [--scope self|all|actors]");
272678
- if (!fs41.existsSync(dir2) || !fs41.statSync(dir2).isDirectory()) throw new Error(`\u6280\u80FD\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dir2}`);
272903
+ if (!fs42.existsSync(dir2) || !fs42.statSync(dir2).isDirectory()) throw new Error(`\u6280\u80FD\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dir2}`);
272679
272904
  const SKIP2 = /* @__PURE__ */ new Set([".git", "node_modules", ".DS_Store"]);
272680
272905
  const MAX_FILE_BYTES5 = 1 << 20;
272681
272906
  const MAX_FILE_COUNT2 = 128;
272682
272907
  const local = {};
272683
272908
  const binary = [];
272684
272909
  const walk = (abs, rel) => {
272685
- for (const name2 of fs41.readdirSync(abs).sort()) {
272910
+ for (const name2 of fs42.readdirSync(abs).sort()) {
272686
272911
  if (SKIP2.has(name2)) continue;
272687
272912
  const childAbs = path37.join(abs, name2);
272688
272913
  const childRel = rel ? `${rel}/${name2}` : name2;
272689
- if (fs41.statSync(childAbs).isDirectory()) {
272914
+ if (fs42.statSync(childAbs).isDirectory()) {
272690
272915
  walk(childAbs, childRel);
272691
272916
  continue;
272692
272917
  }
272693
- const buf = fs41.readFileSync(childAbs);
272918
+ const buf = fs42.readFileSync(childAbs);
272694
272919
  if (buf.length > MAX_FILE_BYTES5) throw new Error(`\u6280\u80FD\u6587\u4EF6\u8D85\u8FC7 1MiB\uFF1A${childRel}\uFF08${buf.length} \u5B57\u8282\uFF09`);
272695
272920
  if (buf.includes(0)) {
272696
272921
  binary.push(childRel);
@@ -273639,14 +273864,14 @@ ${res.warning}`);
273639
273864
  init_src8();
273640
273865
 
273641
273866
  // src/session-sweep.ts
273642
- var fs42 = __toESM(require("node:fs"));
273867
+ var fs43 = __toESM(require("node:fs"));
273643
273868
  var path38 = __toESM(require("node:path"));
273644
273869
  function liveSessionPinnedLabels(sessionRoots2, deps) {
273645
273870
  const labels = /* @__PURE__ */ new Set();
273646
273871
  for (const root of sessionRoots2) {
273647
273872
  let dirs;
273648
273873
  try {
273649
- dirs = fs42.readdirSync(root);
273874
+ dirs = fs43.readdirSync(root);
273650
273875
  } catch {
273651
273876
  continue;
273652
273877
  }
@@ -273655,7 +273880,7 @@ function liveSessionPinnedLabels(sessionRoots2, deps) {
273655
273880
  const live = deps.flockAvailable ? deps.isLocked(path38.join(sessionDir, "lock")) : true;
273656
273881
  if (!live) continue;
273657
273882
  try {
273658
- const label = fs42.readFileSync(path38.join(sessionDir, "pinned-version"), "utf8").trim();
273883
+ const label = fs43.readFileSync(path38.join(sessionDir, "pinned-version"), "utf8").trim();
273659
273884
  if (label) labels.add(label);
273660
273885
  } catch {
273661
273886
  }
@@ -273671,7 +273896,7 @@ function sweepOrphanSessions(sessionRoots2, deps) {
273671
273896
  for (const root of sessionRoots2) {
273672
273897
  let dirs;
273673
273898
  try {
273674
- dirs = fs42.readdirSync(root);
273899
+ dirs = fs43.readdirSync(root);
273675
273900
  } catch {
273676
273901
  continue;
273677
273902
  }
@@ -273679,12 +273904,12 @@ function sweepOrphanSessions(sessionRoots2, deps) {
273679
273904
  const sessionDir = path38.join(root, d);
273680
273905
  if (deps.isLocked(path38.join(sessionDir, "lock"))) continue;
273681
273906
  try {
273682
- if (now() - fs42.statSync(sessionDir).mtimeMs < minAgeMs) continue;
273907
+ if (now() - fs43.statSync(sessionDir).mtimeMs < minAgeMs) continue;
273683
273908
  } catch {
273684
273909
  continue;
273685
273910
  }
273686
273911
  try {
273687
- fs42.rmSync(sessionDir, { recursive: true, force: true });
273912
+ fs43.rmSync(sessionDir, { recursive: true, force: true });
273688
273913
  removed.push(sessionDir);
273689
273914
  } catch {
273690
273915
  }
@@ -273698,7 +273923,7 @@ function countLiveSessions(sessionRoots2, deps) {
273698
273923
  for (const root of sessionRoots2) {
273699
273924
  let dirs;
273700
273925
  try {
273701
- dirs = fs42.readdirSync(root);
273926
+ dirs = fs43.readdirSync(root);
273702
273927
  } catch {
273703
273928
  continue;
273704
273929
  }
@@ -273711,7 +273936,7 @@ function countLiveSessions(sessionRoots2, deps) {
273711
273936
  init_src8();
273712
273937
 
273713
273938
  // src/runtime-assets.ts
273714
- var fs43 = __toESM(require("node:fs"));
273939
+ var fs44 = __toESM(require("node:fs"));
273715
273940
  var path39 = __toESM(require("node:path"));
273716
273941
  var ASSET_EXTS = [".sh", ".mjs"];
273717
273942
  var SESSION_SCOPED_PREFIXES = ["oasis-conn-", "oasis-wrappers-", "oasis-cli-"];
@@ -273727,7 +273952,7 @@ function installRuntimeAssets(srcRoot, binDir) {
273727
273952
  let copied = 0;
273728
273953
  let entries;
273729
273954
  try {
273730
- entries = fs43.readdirSync(srcRoot, { withFileTypes: true });
273955
+ entries = fs44.readdirSync(srcRoot, { withFileTypes: true });
273731
273956
  } catch {
273732
273957
  return 0;
273733
273958
  }
@@ -273736,24 +273961,24 @@ function installRuntimeAssets(srcRoot, binDir) {
273736
273961
  const srcDir = path39.join(srcRoot, entry.name);
273737
273962
  let files;
273738
273963
  try {
273739
- files = fs43.readdirSync(srcDir).filter((f2) => ASSET_EXTS.some((ext) => f2.endsWith(ext)));
273964
+ files = fs44.readdirSync(srcDir).filter((f2) => ASSET_EXTS.some((ext) => f2.endsWith(ext)));
273740
273965
  } catch {
273741
273966
  continue;
273742
273967
  }
273743
273968
  if (files.length === 0) continue;
273744
273969
  const destDir = path39.join(binDir, entry.name);
273745
- fs43.mkdirSync(destDir, { recursive: true });
273970
+ fs44.mkdirSync(destDir, { recursive: true });
273746
273971
  for (const f2 of files) {
273747
273972
  const dest = path39.join(destDir, f2);
273748
- fs43.copyFileSync(path39.join(srcDir, f2), dest);
273749
- fs43.chmodSync(dest, 493);
273973
+ fs44.copyFileSync(path39.join(srcDir, f2), dest);
273974
+ fs44.chmodSync(dest, 493);
273750
273975
  copied++;
273751
273976
  }
273752
273977
  }
273753
273978
  return copied;
273754
273979
  }
273755
273980
  function syncRuntimeAssets(candidateRoots, binDir) {
273756
- fs43.mkdirSync(binDir, { recursive: true });
273981
+ fs44.mkdirSync(binDir, { recursive: true });
273757
273982
  for (const root of candidateRoots) {
273758
273983
  const copied = installRuntimeAssets(root, binDir);
273759
273984
  if (copied > 0) return { from: root, copied };
@@ -273764,7 +273989,7 @@ function runtimeAssetSourceRoots(input) {
273764
273989
  const roots = [];
273765
273990
  if (input.executingBundle) roots.push(path39.dirname(input.executingBundle));
273766
273991
  try {
273767
- roots.push(fs43.realpathSync(input.currentLink));
273992
+ roots.push(fs44.realpathSync(input.currentLink));
273768
273993
  } catch {
273769
273994
  }
273770
273995
  roots.push(input.packageDist);
@@ -273772,11 +273997,11 @@ function runtimeAssetSourceRoots(input) {
273772
273997
  }
273773
273998
 
273774
273999
  // src/paths.ts
273775
- var fs44 = __toESM(require("node:fs"));
273776
- var os14 = __toESM(require("node:os"));
274000
+ var fs45 = __toESM(require("node:fs"));
274001
+ var os15 = __toESM(require("node:os"));
273777
274002
  var path40 = __toESM(require("node:path"));
273778
274003
  var DEFAULT_INSTANCE = "default";
273779
- var home = () => os14.homedir();
274004
+ var home = () => os15.homedir();
273780
274005
  var oasisDir = () => path40.join(home(), ".oasis");
273781
274006
  var versionsDir = () => path40.join(oasisDir(), "versions");
273782
274007
  var versionDir = (label) => path40.join(versionsDir(), label);
@@ -273806,17 +274031,17 @@ function instancePaths(name) {
273806
274031
  }
273807
274032
  function listInstances() {
273808
274033
  const found = [];
273809
- if (fs44.existsSync(instancePaths(DEFAULT_INSTANCE).configFile)) found.push(DEFAULT_INSTANCE);
274034
+ if (fs45.existsSync(instancePaths(DEFAULT_INSTANCE).configFile)) found.push(DEFAULT_INSTANCE);
273810
274035
  let entries = [];
273811
274036
  try {
273812
- entries = fs44.readdirSync(instancesRoot());
274037
+ entries = fs45.readdirSync(instancesRoot());
273813
274038
  } catch {
273814
274039
  return found;
273815
274040
  }
273816
274041
  for (const name of entries.sort()) {
273817
274042
  if (name === DEFAULT_INSTANCE) continue;
273818
274043
  if (!isValidInstanceName(name)) continue;
273819
- if (fs44.existsSync(instancePaths(name).configFile)) found.push(name);
274044
+ if (fs45.existsSync(instancePaths(name).configFile)) found.push(name);
273820
274045
  }
273821
274046
  return found;
273822
274047
  }
@@ -273824,7 +274049,7 @@ function referencedVersionLabels() {
273824
274049
  const labels = /* @__PURE__ */ new Set();
273825
274050
  for (const name of listInstances()) {
273826
274051
  try {
273827
- labels.add(path40.basename(fs44.realpathSync(instancePaths(name).currentLink)));
274052
+ labels.add(path40.basename(fs45.realpathSync(instancePaths(name).currentLink)));
273828
274053
  } catch {
273829
274054
  }
273830
274055
  }
@@ -273849,12 +274074,12 @@ var LEGACY_LAUNCHD_LABEL = "com.oasis.node";
273849
274074
 
273850
274075
  // src/install.ts
273851
274076
  var import_node_crypto84 = require("node:crypto");
273852
- var fs45 = __toESM(require("node:fs"));
274077
+ var fs46 = __toESM(require("node:fs"));
273853
274078
  var path41 = __toESM(require("node:path"));
273854
274079
  function versionLabel(sourceFile, pkgVersion, npmPrefixDir, pkgName = LEGACY_PKG_NAME) {
273855
274080
  const tag = pkgName === LEGACY_PKG_NAME ? "" : `+pkg.${pkgName.replace(/[^A-Za-z0-9-]/g, "-")}`;
273856
274081
  if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return `${pkgVersion}${tag}`;
273857
- const digest = (0, import_node_crypto84.createHash)("sha256").update(fs45.readFileSync(sourceFile)).digest("hex").slice(0, 8);
274082
+ const digest = (0, import_node_crypto84.createHash)("sha256").update(fs46.readFileSync(sourceFile)).digest("hex").slice(0, 8);
273858
274083
  return tag ? `${pkgVersion}${tag}.local.${digest}` : `${pkgVersion}+local.${digest}`;
273859
274084
  }
273860
274085
  function isFromNpmPrefix(sourceFile, npmPrefixDir) {
@@ -273865,14 +274090,14 @@ function isFromNpmPrefix(sourceFile, npmPrefixDir) {
273865
274090
  var isLocalLabel = (label) => /(?:^|[+.])local\.[0-9a-f]{8}$/.test(label);
273866
274091
  function installBinaryAtomic(sourceFile, targetPath) {
273867
274092
  if (realpathOrSelf(sourceFile) === realpathOrSelf(targetPath)) return;
273868
- fs45.mkdirSync(path41.dirname(targetPath), { recursive: true });
274093
+ fs46.mkdirSync(path41.dirname(targetPath), { recursive: true });
273869
274094
  const tmp = `${targetPath}.tmp.${process.pid}`;
273870
274095
  try {
273871
- fs45.copyFileSync(sourceFile, tmp);
273872
- fs45.renameSync(tmp, targetPath);
274096
+ fs46.copyFileSync(sourceFile, tmp);
274097
+ fs46.renameSync(tmp, targetPath);
273873
274098
  } catch (e) {
273874
274099
  try {
273875
- fs45.unlinkSync(tmp);
274100
+ fs46.unlinkSync(tmp);
273876
274101
  } catch {
273877
274102
  }
273878
274103
  throw e;
@@ -273880,24 +274105,24 @@ function installBinaryAtomic(sourceFile, targetPath) {
273880
274105
  }
273881
274106
  var realpathOrSelf = (p2) => {
273882
274107
  try {
273883
- return fs45.realpathSync(p2);
274108
+ return fs46.realpathSync(p2);
273884
274109
  } catch {
273885
274110
  return path41.resolve(p2);
273886
274111
  }
273887
274112
  };
273888
274113
  function pointCurrentAt(linkPath, targetDir) {
273889
- fs45.mkdirSync(path41.dirname(linkPath), { recursive: true });
274114
+ fs46.mkdirSync(path41.dirname(linkPath), { recursive: true });
273890
274115
  const tmp = `${linkPath}.tmp.${process.pid}`;
273891
274116
  try {
273892
- fs45.unlinkSync(tmp);
274117
+ fs46.unlinkSync(tmp);
273893
274118
  } catch {
273894
274119
  }
273895
- fs45.symlinkSync(targetDir, tmp, "dir");
274120
+ fs46.symlinkSync(targetDir, tmp, "dir");
273896
274121
  try {
273897
- fs45.renameSync(tmp, linkPath);
274122
+ fs46.renameSync(tmp, linkPath);
273898
274123
  } catch (e) {
273899
274124
  try {
273900
- fs45.unlinkSync(tmp);
274125
+ fs46.unlinkSync(tmp);
273901
274126
  } catch {
273902
274127
  }
273903
274128
  throw new Error(`\u65E0\u6CD5\u628A ${linkPath} \u6307\u5411 ${targetDir}\uFF1A${String(e)}\uFF08\u82E5\u5B83\u662F\u771F\u76EE\u5F55\uFF0C\u5220\u6389\u540E\u91CD\u8DD1\uFF09`);
@@ -273910,14 +274135,14 @@ function gcVersions(versionsDirPath, opts) {
273910
274135
  const now = opts.now ?? Date.now();
273911
274136
  let entries;
273912
274137
  try {
273913
- entries = fs45.readdirSync(versionsDirPath);
274138
+ entries = fs46.readdirSync(versionsDirPath);
273914
274139
  } catch {
273915
274140
  return [];
273916
274141
  }
273917
274142
  const candidates = entries.filter((name) => !keep.has(name) && !name.includes(".tmp.")).map((name) => {
273918
274143
  const full = path41.join(versionsDirPath, name);
273919
274144
  try {
273920
- const st = fs45.statSync(full);
274145
+ const st = fs46.statSync(full);
273921
274146
  return st.isDirectory() ? { name, full, mtime: st.mtimeMs } : null;
273922
274147
  } catch {
273923
274148
  return null;
@@ -273927,7 +274152,7 @@ function gcVersions(versionsDirPath, opts) {
273927
274152
  for (const c of candidates.slice(keepSpare)) {
273928
274153
  if (now - c.mtime < minAgeMs) continue;
273929
274154
  try {
273930
- fs45.rmSync(c.full, { recursive: true, force: true });
274155
+ fs46.rmSync(c.full, { recursive: true, force: true });
273931
274156
  deleted.push(c.name);
273932
274157
  } catch {
273933
274158
  }
@@ -273977,7 +274202,7 @@ function shimScript() {
273977
274202
  }
273978
274203
 
273979
274204
  // src/index.ts
273980
- var PKG_VERSION = true ? "2.2.23" : "dev";
274205
+ var PKG_VERSION = true ? "2.2.24" : "dev";
273981
274206
  var LOCAL_BIN = localBin();
273982
274207
  var NPM_PREFIX = npmPrefix();
273983
274208
  var INSTANCE = DEFAULT_INSTANCE;
@@ -274018,18 +274243,18 @@ var parseFlags = (argv) => {
274018
274243
  };
274019
274244
  var readConfig = () => {
274020
274245
  try {
274021
- return JSON.parse(fs46.readFileSync(CONFIG_FILE, "utf8"));
274246
+ return JSON.parse(fs47.readFileSync(CONFIG_FILE, "utf8"));
274022
274247
  } catch {
274023
274248
  return null;
274024
274249
  }
274025
274250
  };
274026
274251
  var saveConfig = (c) => {
274027
- fs46.mkdirSync(INST.dir, { recursive: true });
274028
- fs46.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
274252
+ fs47.mkdirSync(INST.dir, { recursive: true });
274253
+ fs47.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
274029
274254
  };
274030
274255
  var readPidAt = (file) => {
274031
274256
  try {
274032
- const p2 = parseInt(fs46.readFileSync(file, "utf8").trim(), 10);
274257
+ const p2 = parseInt(fs47.readFileSync(file, "utf8").trim(), 10);
274033
274258
  return isNaN(p2) ? null : p2;
274034
274259
  } catch {
274035
274260
  return null;
@@ -274038,7 +274263,7 @@ var readPidAt = (file) => {
274038
274263
  var readPid = () => readPidAt(PID_FILE);
274039
274264
  var readConfigAt = (file) => {
274040
274265
  try {
274041
- return JSON.parse(fs46.readFileSync(file, "utf8"));
274266
+ return JSON.parse(fs47.readFileSync(file, "utf8"));
274042
274267
  } catch {
274043
274268
  return null;
274044
274269
  }
@@ -274073,8 +274298,8 @@ function installSoftware(label) {
274073
274298
  installBinaryAtomic(src, BIN_FILE);
274074
274299
  ensureRuntimeAssets(BIN_DIR);
274075
274300
  pointCurrentAt(INST.currentLink, vDir);
274076
- fs46.mkdirSync(path42.dirname(LOCAL_BIN), { recursive: true });
274077
- fs46.writeFileSync(LOCAL_BIN, shimScript(), { mode: 493 });
274301
+ fs47.mkdirSync(path42.dirname(LOCAL_BIN), { recursive: true });
274302
+ fs47.writeFileSync(LOCAL_BIN, shimScript(), { mode: 493 });
274078
274303
  const keep = [.../* @__PURE__ */ new Set([label, ...referencedVersionLabels(), ...liveSessionPinnedLabels(sessionRoots(), { isLocked: isSessionLocked, flockAvailable: hasFlock() })])];
274079
274304
  const removed = gcVersions(versionsDir(), { keep });
274080
274305
  if (removed.length) console.error(`[oasis] \u7248\u672C GC\uFF1A\u5220\u9664 ${removed.join(", ")}\uFF08\u5728\u7528\uFF1A${keep.join(", ")}\uFF09`);
@@ -274083,7 +274308,7 @@ function installSoftware(label) {
274083
274308
  function setupAutostart(name) {
274084
274309
  const inst = instancePaths(name);
274085
274310
  const cmd = `${process.execPath} "${inst.binFile}" --_daemon --instance ${name}`;
274086
- const home2 = os15.homedir();
274311
+ const home2 = os16.homedir();
274087
274312
  const pnpmHome = process.env["PNPM_HOME"] || path42.join(home2, ".local", "share", "pnpm");
274088
274313
  const extraBins = [
274089
274314
  path42.join(home2, ".npm-global", "bin"),
@@ -274093,11 +274318,11 @@ function setupAutostart(name) {
274093
274318
  ];
274094
274319
  const daemonPath = sanitizeDaemonPath([process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":"));
274095
274320
  if (process.platform === "linux") {
274096
- const unitDir = path42.join(os15.homedir(), ".config", "systemd", "user");
274097
- fs46.mkdirSync(unitDir, { recursive: true });
274321
+ const unitDir = path42.join(os16.homedir(), ".config", "systemd", "user");
274322
+ fs47.mkdirSync(unitDir, { recursive: true });
274098
274323
  const unit = systemdUnitName(name);
274099
- fs46.mkdirSync(path42.dirname(inst.logFile), { recursive: true });
274100
- fs46.writeFileSync(path42.join(unitDir, unit), systemdUnitText({
274324
+ fs47.mkdirSync(path42.dirname(inst.logFile), { recursive: true });
274325
+ fs47.writeFileSync(path42.join(unitDir, unit), systemdUnitText({
274101
274326
  name,
274102
274327
  cmd,
274103
274328
  daemonPath,
@@ -274118,9 +274343,9 @@ function setupAutostart(name) {
274118
274343
  return false;
274119
274344
  } else if (process.platform === "darwin") {
274120
274345
  const label = launchdLabel(name);
274121
- const plist = path42.join(os15.homedir(), "Library", "LaunchAgents", `${label}.plist`);
274122
- fs46.mkdirSync(path42.dirname(plist), { recursive: true });
274123
- fs46.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
274346
+ const plist = path42.join(os16.homedir(), "Library", "LaunchAgents", `${label}.plist`);
274347
+ fs47.mkdirSync(path42.dirname(plist), { recursive: true });
274348
+ fs47.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
274124
274349
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
274125
274350
  <plist version="1.0"><dict>
274126
274351
  <key>Label</key><string>${label}</string>
@@ -274140,8 +274365,8 @@ function setupAutostart(name) {
274140
274365
  return false;
274141
274366
  }
274142
274367
  function spawnDaemon() {
274143
- fs46.mkdirSync(path42.dirname(LOG_FILE), { recursive: true });
274144
- const log3 = fs46.openSync(LOG_FILE, "a");
274368
+ fs47.mkdirSync(path42.dirname(LOG_FILE), { recursive: true });
274369
+ const log3 = fs47.openSync(LOG_FILE, "a");
274145
274370
  const child = (0, import_node_child_process20.spawn)(process.execPath, [INST.binFile, "--_daemon", "--instance", INSTANCE], {
274146
274371
  detached: true,
274147
274372
  stdio: ["ignore", log3, log3],
@@ -274162,7 +274387,7 @@ function stopDaemon(name) {
274162
274387
  }
274163
274388
  }
274164
274389
  try {
274165
- fs46.unlinkSync(inst.pidFile);
274390
+ fs47.unlinkSync(inst.pidFile);
274166
274391
  } catch {
274167
274392
  }
274168
274393
  if (process.platform === "linux") {
@@ -274228,7 +274453,7 @@ function selfUpdate(targetPkg) {
274228
274453
  return false;
274229
274454
  }
274230
274455
  })();
274231
- const log3 = fs46.openSync(LOG_FILE, "a");
274456
+ const log3 = fs47.openSync(LOG_FILE, "a");
274232
274457
  if (hasSystemd) {
274233
274458
  const child = (0, import_node_child_process20.spawn)("systemd-run", ["--user", "--scope", "--quiet", "sh", "-c", inner], {
274234
274459
  detached: true,
@@ -274250,13 +274475,13 @@ function resolveInstance(explicit) {
274250
274475
  }
274251
274476
  function currentLabelOf(inst) {
274252
274477
  try {
274253
- return path42.basename(fs46.realpathSync(inst.currentLink));
274478
+ return path42.basename(fs47.realpathSync(inst.currentLink));
274254
274479
  } catch {
274255
274480
  return null;
274256
274481
  }
274257
274482
  }
274258
274483
  function instanceHasSoftware(inst) {
274259
- return fs46.existsSync(inst.binFile) && currentLabelOf(inst) !== null;
274484
+ return fs47.existsSync(inst.binFile) && currentLabelOf(inst) !== null;
274260
274485
  }
274261
274486
  function newInstanceName() {
274262
274487
  const existing = new Set(listInstances());
@@ -274269,7 +274494,7 @@ function newInstanceName() {
274269
274494
  function planStart(explicit, serverUrl, companyId) {
274270
274495
  if (explicit) {
274271
274496
  const name = resolveInstance(explicit);
274272
- return { mode: fs46.existsSync(instancePaths(name).configFile) ? "resume" : "new", names: [name] };
274497
+ return { mode: fs47.existsSync(instancePaths(name).configFile) ? "resume" : "new", names: [name] };
274273
274498
  }
274274
274499
  const all2 = listInstances();
274275
274500
  if (all2.length === 0) return { mode: "new", names: [DEFAULT_INSTANCE] };
@@ -274300,7 +274525,7 @@ async function startOneInstance(o) {
274300
274525
  const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
274301
274526
  method: "POST",
274302
274527
  headers: { "content-type": "application/json" },
274303
- body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os15.hostname(), serverUrl, ...companyId ? { companyId } : {} })
274528
+ body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os16.hostname(), serverUrl, ...companyId ? { companyId } : {} })
274304
274529
  });
274305
274530
  if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
274306
274531
  const body2 = await res.json();
@@ -274340,8 +274565,8 @@ async function startOneInstance(o) {
274340
274565
  const cfgNow = readConfig();
274341
274566
  if (cfgNow && !cfgNow.pkgName) saveConfig({ ...cfgNow, pkgName: BUILT_PKG_NAME });
274342
274567
  } else {
274343
- fs46.mkdirSync(path42.dirname(LOCAL_BIN), { recursive: true });
274344
- fs46.writeFileSync(LOCAL_BIN, shimScript(), { mode: 493 });
274568
+ fs47.mkdirSync(path42.dirname(LOCAL_BIN), { recursive: true });
274569
+ fs47.writeFileSync(LOCAL_BIN, shimScript(), { mode: 493 });
274345
274570
  }
274346
274571
  const pidNow = readPid();
274347
274572
  const alive2 = !!pidNow && isRunning2(pidNow);
@@ -274365,7 +274590,7 @@ function derivedNodeIdFor(name) {
274365
274590
  if (name === DEFAULT_INSTANCE) return resolveNodeId();
274366
274591
  const user = (() => {
274367
274592
  try {
274368
- return os15.userInfo().username;
274593
+ return os16.userInfo().username;
274369
274594
  } catch {
274370
274595
  return process.env["USER"] ?? process.env["USERNAME"] ?? "unknown";
274371
274596
  }
@@ -274385,10 +274610,10 @@ function spawnSessionProcess(spec) {
274385
274610
  try {
274386
274611
  const safe = spec.dispatchId.replace(/[^A-Za-z0-9._-]/g, "_");
274387
274612
  const dir = path42.join(INST.sessionsDir, safe);
274388
- fs46.mkdirSync(dir, { recursive: true, mode: 448 });
274613
+ fs47.mkdirSync(dir, { recursive: true, mode: 448 });
274389
274614
  const specFile = path42.join(dir, "spec.json");
274390
274615
  const cfg = readConfig();
274391
- fs46.writeFileSync(specFile, JSON.stringify({
274616
+ fs47.writeFileSync(specFile, JSON.stringify({
274392
274617
  ...spec,
274393
274618
  sessionDir: dir,
274394
274619
  nodeId: cfg?.nodeId ?? INSTANCE,
@@ -274397,19 +274622,24 @@ function spawnSessionProcess(spec) {
274397
274622
  }), { mode: 384 });
274398
274623
  let pinnedDir = INST.currentLink;
274399
274624
  try {
274400
- pinnedDir = fs46.realpathSync(INST.currentLink);
274625
+ pinnedDir = fs47.realpathSync(INST.currentLink);
274401
274626
  } catch {
274402
274627
  }
274403
274628
  try {
274404
- fs46.writeFileSync(path42.join(dir, "pinned-version"), path42.basename(pinnedDir));
274629
+ fs47.writeFileSync(path42.join(dir, "pinned-version"), path42.basename(pinnedDir));
274405
274630
  } catch {
274406
274631
  }
274407
- const logFd = fs46.openSync(path42.join(dir, "session.log"), "a");
274632
+ const logFd = fs47.openSync(path42.join(dir, "session.log"), "a");
274408
274633
  const argv = [INST.binFile, "--_session", specFile];
274409
- const env = { ...process.env, OASIS_CLI_HOME: pinnedDir };
274634
+ const executionEnv = spec.job.execution ? {
274635
+ OASIS_EXECUTION_KEY: spec.job.execution.key,
274636
+ OASIS_EXECUTION_GENERATION: String(spec.job.execution.generation),
274637
+ OASIS_EXECUTION_DISPATCH_ID: spec.dispatchId
274638
+ } : {};
274639
+ const env = { ...process.env, ...executionEnv, OASIS_CLI_HOME: pinnedDir };
274410
274640
  const child = userScopeAvailable() ? (0, import_node_child_process20.spawn)(
274411
274641
  "systemd-run",
274412
- ["--user", "--scope", "--quiet", `--setenv=OASIS_CLI_HOME=${pinnedDir}`, process.execPath, ...argv],
274642
+ ["--user", "--scope", "--quiet", `--setenv=OASIS_CLI_HOME=${pinnedDir}`, ...Object.entries(executionEnv).map(([key, value2]) => `--setenv=${key}=${value2}`), process.execPath, ...argv],
274413
274643
  { detached: true, stdio: ["ignore", logFd, logFd], env }
274414
274644
  ) : (0, import_node_child_process20.spawn)(process.execPath, argv, { detached: true, stdio: ["ignore", logFd, logFd], env });
274415
274645
  child.unref();
@@ -274452,9 +274682,9 @@ void (async () => {
274452
274682
  process.exit(1);
274453
274683
  }
274454
274684
  try {
274455
- const fd = fs46.openSync(PID_FILE, "wx");
274456
- fs46.writeSync(fd, String(process.pid));
274457
- fs46.closeSync(fd);
274685
+ const fd = fs47.openSync(PID_FILE, "wx");
274686
+ fs47.writeSync(fd, String(process.pid));
274687
+ fs47.closeSync(fd);
274458
274688
  } catch {
274459
274689
  const alivePid = readPid();
274460
274690
  if (alivePid && alivePid !== process.pid && isRunning2(alivePid)) {
@@ -274462,13 +274692,13 @@ void (async () => {
274462
274692
  process.exit(0);
274463
274693
  }
274464
274694
  try {
274465
- fs46.writeFileSync(PID_FILE, String(process.pid));
274695
+ fs47.writeFileSync(PID_FILE, String(process.pid));
274466
274696
  } catch {
274467
274697
  }
274468
274698
  }
274469
274699
  const cleanup = () => {
274470
274700
  try {
274471
- if (fs46.readFileSync(PID_FILE, "utf8").trim() === String(process.pid)) fs46.unlinkSync(PID_FILE);
274701
+ if (fs47.readFileSync(PID_FILE, "utf8").trim() === String(process.pid)) fs47.unlinkSync(PID_FILE);
274472
274702
  } catch {
274473
274703
  }
274474
274704
  };
@@ -274542,7 +274772,6 @@ void (async () => {
274542
274772
  drainNode = ctl.drain;
274543
274773
  },
274544
274774
  // 服务端下发了数据面通行证时,把会话交给独立进程跑(daemon 重启不再连坐它)。
274545
- sessionsRoot: INST.sessionsDir,
274546
274775
  spawnSessionProcess,
274547
274776
  countDetachedSessions: () => countLiveSessions(sessionRoots(), { isLocked: isSessionLocked, flockAvailable: hasFlock() })
274548
274777
  });