oasis_test 0.1.44 → 0.1.46

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 +854 -619
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1958,9 +1958,9 @@ var init_kernel = __esm({
1958
1958
  throw new KernelError(`revision not in queue: ${args.revisionId}\uFF08state=${target?.state ?? "missing"}\uFF09`);
1959
1959
  }
1960
1960
  if (isStale(this.model, head)) {
1961
- const path19 = this.pathForStaleHead(artifact, queue);
1961
+ const path20 = this.pathForStaleHead(artifact, queue);
1962
1962
  throw new KernelError(
1963
- `stale base: ${head.id} based on ${head.base ?? "\u2205"}, head is ${artifact.currentRev ?? "\u2205"} \u2014 ` + (path19 === "rebase" ? `\u9700\u8981 rebase\uFF1A\u4F5C\u8005\u5728\u65B0 head \u4E0A\u91CD\u5199\u540E propose --rebase-of ${head.id}\uFF08\xA75.5\uFF09` : `\u591A\u6761\u7ADE\u4E89\u4E14\u68C0\u67E5\u8D35 \u2192 group-commit\uFF1Aowner \u4E00\u6B21\u96C6\u6210\u6574\u6279\uFF08\xA75.5\uFF09`)
1963
+ `stale base: ${head.id} based on ${head.base ?? "\u2205"}, head is ${artifact.currentRev ?? "\u2205"} \u2014 ` + (path20 === "rebase" ? `\u9700\u8981 rebase\uFF1A\u4F5C\u8005\u5728\u65B0 head \u4E0A\u91CD\u5199\u540E propose --rebase-of ${head.id}\uFF08\xA75.5\uFF09` : `\u591A\u6761\u7ADE\u4E89\u4E14\u68C0\u67E5\u8D35 \u2192 group-commit\uFF1Aowner \u4E00\u6B21\u96C6\u6210\u6574\u6279\uFF08\xA75.5\uFF09`)
1964
1964
  );
1965
1965
  }
1966
1966
  await this.landHead(args.artifactId, args.actor, head, args.hand);
@@ -1977,13 +1977,13 @@ var init_kernel = __esm({
1977
1977
  const head = queue[0];
1978
1978
  if (!head) return { landed };
1979
1979
  if (isStale(this.model, head)) {
1980
- const path19 = this.pathForStaleHead(artifact, queue);
1980
+ const path20 = this.pathForStaleHead(artifact, queue);
1981
1981
  return {
1982
1982
  landed,
1983
1983
  blockedHead: {
1984
1984
  revision: head,
1985
- path: path19,
1986
- hint: path19 === "rebase" ? `\u4F5C\u8005\u91CD\u5199\u540E propose --rebase-of ${head.id}` : `owner \u96C6\u6210\u6574\u6279\uFF08integrate\uFF09\uFF0CR*.parents = [head, \u2026batch]`
1985
+ path: path20,
1986
+ hint: path20 === "rebase" ? `\u4F5C\u8005\u91CD\u5199\u540E propose --rebase-of ${head.id}` : `owner \u96C6\u6210\u6574\u6279\uFF08integrate\uFF09\uFF0CR*.parents = [head, \u2026batch]`
1987
1987
  }
1988
1988
  };
1989
1989
  }
@@ -3852,7 +3852,7 @@ function computeReviewJobs(model) {
3852
3852
  }
3853
3853
  return out;
3854
3854
  }
3855
- var import_node_crypto2, DEFAULT_PREDISPATCH_TIMEOUT_MS, SpawnAttemptStale, SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT, Dispatcher;
3855
+ var import_node_crypto2, DEFAULT_PREDISPATCH_TIMEOUT_MS, SpawnAttemptStale, SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT, CANVAS_RUNTIME_KIND, NON_PRODUCE_FALLBACK_RUNTIME_KIND, Dispatcher;
3856
3856
  var init_dispatcher = __esm({
3857
3857
  "../core/src/dispatcher.ts"() {
3858
3858
  "use strict";
@@ -3869,6 +3869,8 @@ var init_dispatcher = __esm({
3869
3869
  }
3870
3870
  };
3871
3871
  SEED_ROOT_SUCCESSFUL_PRODUCE_LIMIT = 5;
3872
+ CANVAS_RUNTIME_KIND = "open-design";
3873
+ NON_PRODUCE_FALLBACK_RUNTIME_KIND = "claude-code";
3872
3874
  Dispatcher = class {
3873
3875
  constructor(opts) {
3874
3876
  this.opts = opts;
@@ -4177,6 +4179,28 @@ var init_dispatcher = __esm({
4177
4179
  });
4178
4180
  }
4179
4181
  }
4182
+ /**
4183
+ * 员工 → 运行时绑定,按动作校正。
4184
+ *
4185
+ * 背景:design 产物走「画板化」(提案 design-node-canvas-driven)——designer 的 produce 会话跑在
4186
+ * open-design 画板引擎里,产出**真实可打开的界面稿**(HTML + acceptance.md)而非文档。为此
4187
+ * designer 被绑到 `runtimeKind: "open-design"`。但 open-design 是**只会 produce 的专用引擎**:
4188
+ * 它的适配器无视 action,永远驱动画板引擎产界面再 propose。designer 一旦以 reviewer / 被 @ 回复 /
4189
+ * 收口身份被派活(action ≠ produce),仍按绑定路由到 open-design 就必崩(harvest 无 HTML 入口稿、
4190
+ * 或 propose 非己产物 → 会话 code=1 reason=error),评审票永远投不出,评审门只能靠他人凑 quorum 或
4191
+ * 人工 force-conclude。
4192
+ *
4193
+ * 修正:非 produce 的动作忽略画板绑定,回退到节点上的通用编码运行时(claude-code)——保持同一 nodeId,
4194
+ * 只换 runtimeKind。与 assembler 的 `canvasMode`(同样 `action !== "review"` 才进画板模式)语义一致:
4195
+ * 画板只服务于「产界面」,评审/回复/收口回到能真正读写、能投票的通用运行时。
4196
+ */
4197
+ async resolveBindingFor(spec) {
4198
+ const binding = await this.opts.resolveBinding?.(spec.actor) ?? void 0;
4199
+ if (binding && spec.action !== "produce" && binding.runtimeKind === CANVAS_RUNTIME_KIND) {
4200
+ return { ...binding, runtimeKind: NON_PRODUCE_FALLBACK_RUNTIME_KIND };
4201
+ }
4202
+ return binding;
4203
+ }
4180
4204
  async spawnJobInner(jobKey, spec, attempt) {
4181
4205
  if (this.inFlight.has(jobKey)) return 0;
4182
4206
  const { kernel } = this.opts;
@@ -4217,7 +4241,7 @@ var init_dispatcher = __esm({
4217
4241
  const ws = kernel.model.artifacts.get(spec.artifactId)?.workspace;
4218
4242
  const codeRepo = ws ? await this.opts.resolveCodeRepo?.(ws) ?? null : null;
4219
4243
  this.assertSpawnAttemptCurrent(jobKey, attempt);
4220
- const binding = await this.opts.resolveBinding?.(spec.actor) ?? void 0;
4244
+ const binding = await this.resolveBindingFor(spec);
4221
4245
  this.assertSpawnAttemptCurrent(jobKey, attempt);
4222
4246
  const materializeSkills = this.opts.materializeSkills ? () => this.opts.materializeSkills(spec.actor, binding?.runtimeKind ?? "claude") : void 0;
4223
4247
  const bundle = await assembleContext({
@@ -5181,8 +5205,8 @@ var init_parseUtil = __esm({
5181
5205
  init_errors2();
5182
5206
  init_en();
5183
5207
  makeIssue = (params) => {
5184
- const { data, path: path19, errorMaps, issueData } = params;
5185
- const fullPath = [...path19, ...issueData.path || []];
5208
+ const { data, path: path20, errorMaps, issueData } = params;
5209
+ const fullPath = [...path20, ...issueData.path || []];
5186
5210
  const fullIssue = {
5187
5211
  ...issueData,
5188
5212
  path: fullPath
@@ -5490,11 +5514,11 @@ var init_types = __esm({
5490
5514
  init_parseUtil();
5491
5515
  init_util();
5492
5516
  ParseInputLazyPath = class {
5493
- constructor(parent, value, path19, key) {
5517
+ constructor(parent, value, path20, key) {
5494
5518
  this._cachedPath = [];
5495
5519
  this.parent = parent;
5496
5520
  this.data = value;
5497
- this._path = path19;
5521
+ this._path = path20;
5498
5522
  this._key = key;
5499
5523
  }
5500
5524
  get path() {
@@ -9068,10 +9092,10 @@ function assignProp(target, prop, value) {
9068
9092
  configurable: true
9069
9093
  });
9070
9094
  }
9071
- function getElementAtPath(obj, path19) {
9072
- if (!path19)
9095
+ function getElementAtPath(obj, path20) {
9096
+ if (!path20)
9073
9097
  return obj;
9074
- return path19.reduce((acc, key) => acc?.[key], obj);
9098
+ return path20.reduce((acc, key) => acc?.[key], obj);
9075
9099
  }
9076
9100
  function promiseAllObject(promisesObj) {
9077
9101
  const keys = Object.keys(promisesObj);
@@ -9320,11 +9344,11 @@ function aborted(x2, startIndex = 0) {
9320
9344
  }
9321
9345
  return false;
9322
9346
  }
9323
- function prefixIssues(path19, issues) {
9347
+ function prefixIssues(path20, issues) {
9324
9348
  return issues.map((iss) => {
9325
9349
  var _a;
9326
9350
  (_a = iss).path ?? (_a.path = []);
9327
- iss.path.unshift(path19);
9351
+ iss.path.unshift(path20);
9328
9352
  return iss;
9329
9353
  });
9330
9354
  }
@@ -17864,8 +17888,8 @@ var require_utils = __commonJS({
17864
17888
  }
17865
17889
  return ind;
17866
17890
  }
17867
- function removeDotSegments(path19) {
17868
- let input = path19;
17891
+ function removeDotSegments(path20) {
17892
+ let input = path20;
17869
17893
  const output = [];
17870
17894
  let nextSlash = -1;
17871
17895
  let len = 0;
@@ -18117,8 +18141,8 @@ var require_schemes = __commonJS({
18117
18141
  wsComponent.secure = void 0;
18118
18142
  }
18119
18143
  if (wsComponent.resourceName) {
18120
- const [path19, query] = wsComponent.resourceName.split("?");
18121
- wsComponent.path = path19 && path19 !== "/" ? path19 : void 0;
18144
+ const [path20, query] = wsComponent.resourceName.split("?");
18145
+ wsComponent.path = path20 && path20 !== "/" ? path20 : void 0;
18122
18146
  wsComponent.query = query;
18123
18147
  wsComponent.resourceName = void 0;
18124
18148
  }
@@ -21511,12 +21535,12 @@ var require_dist = __commonJS({
21511
21535
  throw new Error(`Unknown format "${name}"`);
21512
21536
  return f2;
21513
21537
  };
21514
- function addFormats(ajv, list, fs20, exportName) {
21538
+ function addFormats(ajv, list, fs21, exportName) {
21515
21539
  var _a;
21516
21540
  var _b;
21517
21541
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
21518
21542
  for (const f2 of list)
21519
- ajv.addFormat(f2, fs20[f2]);
21543
+ ajv.addFormat(f2, fs21[f2]);
21520
21544
  }
21521
21545
  module2.exports = exports2 = formatsPlugin;
21522
21546
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -21631,23 +21655,23 @@ var init_router = __esm({
21631
21655
  };
21632
21656
  Router = class {
21633
21657
  routes = [];
21634
- on(method, path19, handler) {
21635
- this.routes.push({ method, segments: path19.split("/").filter(Boolean), handler });
21658
+ on(method, path20, handler) {
21659
+ this.routes.push({ method, segments: path20.split("/").filter(Boolean), handler });
21636
21660
  }
21637
- get(path19, h) {
21638
- this.on("GET", path19, h);
21661
+ get(path20, h) {
21662
+ this.on("GET", path20, h);
21639
21663
  }
21640
- post(path19, h) {
21641
- this.on("POST", path19, h);
21664
+ post(path20, h) {
21665
+ this.on("POST", path20, h);
21642
21666
  }
21643
- patch(path19, h) {
21644
- this.on("PATCH", path19, h);
21667
+ patch(path20, h) {
21668
+ this.on("PATCH", path20, h);
21645
21669
  }
21646
- put(path19, h) {
21647
- this.on("PUT", path19, h);
21670
+ put(path20, h) {
21671
+ this.on("PUT", path20, h);
21648
21672
  }
21649
- delete(path19, h) {
21650
- this.on("DELETE", path19, h);
21673
+ delete(path20, h) {
21674
+ this.on("DELETE", path20, h);
21651
21675
  }
21652
21676
  match(method, pathname) {
21653
21677
  const parts = pathname.split("/").filter(Boolean);
@@ -24384,7 +24408,7 @@ async function runView(kernel, oplog, blobs, name, artifactId, params) {
24384
24408
  }
24385
24409
  case "content": {
24386
24410
  const id = need2();
24387
- const path19 = params?.get("path") ?? null;
24411
+ const path20 = params?.get("path") ?? null;
24388
24412
  const artifact = model.artifacts.get(id);
24389
24413
  if (!artifact) throw new Error(`artifact \u4E0D\u5B58\u5728: ${id}`);
24390
24414
  const head = artifact.currentRev;
@@ -24396,11 +24420,11 @@ async function runView(kernel, oplog, blobs, name, artifactId, params) {
24396
24420
  const dec2 = new TextDecoder();
24397
24421
  if (headRev.contentKind === "manifest") {
24398
24422
  const entries = await readManifest(blobs, headRev.contentRef);
24399
- if (path19 !== null) {
24400
- const e = entries.find((x2) => x2.path === path19);
24401
- if (!e) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${path19}\uFF08\u672C\u4EA7\u7269\u6709\uFF1A${entries.map((x2) => x2.path).join("\u3001")}\uFF09`);
24423
+ if (path20 !== null) {
24424
+ const e = entries.find((x2) => x2.path === path20);
24425
+ if (!e) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${path20}\uFF08\u672C\u4EA7\u7269\u6709\uFF1A${entries.map((x2) => x2.path).join("\u3001")}\uFF09`);
24402
24426
  const isText = !e.bytes.includes(0);
24403
- return { kind: "file", path: path19, bytes: e.bytes.length, text: isText ? dec2.decode(e.bytes) : null };
24427
+ return { kind: "file", path: path20, bytes: e.bytes.length, text: isText ? dec2.decode(e.bytes) : null };
24404
24428
  }
24405
24429
  return {
24406
24430
  kind: "manifest",
@@ -24695,9 +24719,9 @@ async function startOasisServer(opts) {
24695
24719
  }
24696
24720
  }
24697
24721
  if (!target) return;
24698
- const { randomUUID: randomUUID18 } = await import("node:crypto");
24722
+ const { randomUUID: randomUUID19 } = await import("node:crypto");
24699
24723
  if (chatStore) {
24700
- await chatStore.appendMessage({ id: randomUUID18(), sessionId: target, role: "user", content: message, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
24724
+ await chatStore.appendMessage({ id: randomUUID19(), sessionId: target, role: "user", content: message, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
24701
24725
  }
24702
24726
  const rt = record5?.runtimeSessionId ?? opts.retainedSession?.({ draftId: review.draftId });
24703
24727
  const session = await opts.dispatchChat({
@@ -24715,7 +24739,7 @@ async function startOasisServer(opts) {
24715
24739
  });
24716
24740
  void session.done.then(async () => {
24717
24741
  if (reply || session.runId) {
24718
- await chatStore.appendMessage({ id: randomUUID18(), sessionId: sid, role: "assistant", content: reply, createdAt: (/* @__PURE__ */ new Date()).toISOString(), ...session.runId ? { runId: session.runId } : {} }).catch(() => void 0);
24742
+ await chatStore.appendMessage({ id: randomUUID19(), sessionId: sid, role: "assistant", content: reply, createdAt: (/* @__PURE__ */ new Date()).toISOString(), ...session.runId ? { runId: session.runId } : {} }).catch(() => void 0);
24719
24743
  }
24720
24744
  }).catch(() => void 0);
24721
24745
  }
@@ -24785,11 +24809,11 @@ async function startOasisServer(opts) {
24785
24809
  let chatSessionId;
24786
24810
  let createdThisCall = false;
24787
24811
  if (chatStore) {
24788
- const { randomUUID: randomUUID18 } = await import("node:crypto");
24812
+ const { randomUUID: randomUUID19 } = await import("node:crypto");
24789
24813
  const known = discussSessions.get(itemKey);
24790
24814
  if (known && await chatStore.getSession(known).catch(() => null)) chatSessionId = known;
24791
24815
  if (!chatSessionId) {
24792
- chatSessionId = randomUUID18();
24816
+ chatSessionId = randomUUID19();
24793
24817
  createdThisCall = true;
24794
24818
  const now = (/* @__PURE__ */ new Date()).toISOString();
24795
24819
  const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
@@ -24797,7 +24821,7 @@ async function startOasisServer(opts) {
24797
24821
  await chatStore.linkWorkOrder(chatSessionId, ctx.workspace).catch(() => void 0);
24798
24822
  }
24799
24823
  discussSessions.set(itemKey, chatSessionId);
24800
- await chatStore.appendMessage({ id: randomUUID18(), sessionId: chatSessionId, role: "user", content: ctx.seed, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
24824
+ await chatStore.appendMessage({ id: randomUUID19(), sessionId: chatSessionId, role: "user", content: ctx.seed, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
24801
24825
  }
24802
24826
  let session;
24803
24827
  try {
@@ -24816,9 +24840,9 @@ async function startOasisServer(opts) {
24816
24840
  reply += chunk;
24817
24841
  });
24818
24842
  void session.done.then(async () => {
24819
- const { randomUUID: randomUUID18 } = await import("node:crypto");
24843
+ const { randomUUID: randomUUID19 } = await import("node:crypto");
24820
24844
  if (reply || session.runId) {
24821
- await chatStore.appendMessage({ id: randomUUID18(), sessionId: sid, role: "assistant", content: reply, createdAt: (/* @__PURE__ */ new Date()).toISOString(), ...session.runId ? { runId: session.runId } : {} }).catch(() => void 0);
24845
+ await chatStore.appendMessage({ id: randomUUID19(), sessionId: sid, role: "assistant", content: reply, createdAt: (/* @__PURE__ */ new Date()).toISOString(), ...session.runId ? { runId: session.runId } : {} }).catch(() => void 0);
24822
24846
  }
24823
24847
  }).catch(() => void 0);
24824
24848
  }
@@ -25151,14 +25175,14 @@ async function startOasisServer(opts) {
25151
25175
  const persistSession = chatStore && body.chatSessionId ? await chatStore.getSession(body.chatSessionId).catch(() => null) : null;
25152
25176
  const persistTarget = persistSession && persistSession.humanActorId === actor ? persistSession : null;
25153
25177
  if (chatStore && persistTarget) {
25154
- const { randomUUID: randomUUID19 } = await import("node:crypto");
25178
+ const { randomUUID: randomUUID20 } = await import("node:crypto");
25155
25179
  const persistAttachments = attachments.map((a) => ({
25156
25180
  name: a.name,
25157
25181
  ...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
25158
25182
  ...a.contentType !== void 0 ? { contentType: a.contentType } : {}
25159
25183
  }));
25160
25184
  await chatStore.appendMessage({
25161
- id: randomUUID19(),
25185
+ id: randomUUID20(),
25162
25186
  sessionId: persistTarget.id,
25163
25187
  role: "user",
25164
25188
  content: body.message,
@@ -25168,8 +25192,8 @@ async function startOasisServer(opts) {
25168
25192
  }
25169
25193
  let assistantMsgId;
25170
25194
  if (chatStore && persistTarget) {
25171
- const { randomUUID: randomUUID19 } = await import("node:crypto");
25172
- const id = randomUUID19();
25195
+ const { randomUUID: randomUUID20 } = await import("node:crypto");
25196
+ const id = randomUUID20();
25173
25197
  await chatStore.appendMessage({
25174
25198
  id,
25175
25199
  sessionId: persistTarget.id,
@@ -25200,9 +25224,9 @@ async function startOasisServer(opts) {
25200
25224
  }).catch(() => void 0);
25201
25225
  } else {
25202
25226
  if (!assistantText && !session.runId && parts.length === 0) return;
25203
- const { randomUUID: randomUUID19 } = await import("node:crypto");
25227
+ const { randomUUID: randomUUID20 } = await import("node:crypto");
25204
25228
  await chatStore.appendMessage({
25205
- id: randomUUID19(),
25229
+ id: randomUUID20(),
25206
25230
  sessionId: persistTarget.id,
25207
25231
  role: "assistant",
25208
25232
  content: assistantText,
@@ -25330,13 +25354,13 @@ async function startOasisServer(opts) {
25330
25354
  const actorCtx = await opts.resolveActorContext(body.actorId).catch(() => null);
25331
25355
  if (actorCtx) {
25332
25356
  const { mkdtempSync: mkdtempSync9, mkdirSync: mkdirSync16, writeFileSync: writeFileSync15 } = await import("node:fs");
25333
- const { join: join23, dirname: dirname17 } = await import("node:path");
25334
- const { tmpdir: tmpdir13 } = await import("node:os");
25335
- const dir = mkdtempSync9(join23(tmpdir13(), "oasis-chat-"));
25357
+ const { join: join24, dirname: dirname18 } = await import("node:path");
25358
+ const { tmpdir: tmpdir14 } = await import("node:os");
25359
+ const dir = mkdtempSync9(join24(tmpdir14(), "oasis-chat-"));
25336
25360
  if (actorCtx.config?.prompt) {
25337
25361
  for (const [rel, content] of Object.entries(splitIdentityFiles2(actorCtx.config.prompt))) {
25338
- const file = join23(dir, rel);
25339
- mkdirSync16(dirname17(file), { recursive: true });
25362
+ const file = join24(dir, rel);
25363
+ mkdirSync16(dirname18(file), { recursive: true });
25340
25364
  writeFileSync15(file, content);
25341
25365
  }
25342
25366
  }
@@ -25347,13 +25371,13 @@ async function startOasisServer(opts) {
25347
25371
  const s2 = byId.get(id);
25348
25372
  return s2 ? `- **${s2.name}** (\`${s2.id}\`): ${s2.description}` : `- \`${id}\`\uFF08\u672A\u5728\u6280\u80FD\u5E93\u4E2D\uFF0C\u53EF\u80FD\u5DF2\u5378\u8F7D\uFF09`;
25349
25373
  });
25350
- writeFileSync15(join23(dir, "SKILLS.md"), ["# \u53EF\u7528\u6280\u80FD", "", "\u4EE5\u4E0B\u6280\u80FD\u5DF2\u4E3A\u4F60\u542F\u7528\uFF0C\u53EF\u5728\u672C\u6B21\u4F1A\u8BDD\u4E2D\u76F4\u63A5\u4F7F\u7528\uFF1A", "", ...lines].join("\n"));
25374
+ writeFileSync15(join24(dir, "SKILLS.md"), ["# \u53EF\u7528\u6280\u80FD", "", "\u4EE5\u4E0B\u6280\u80FD\u5DF2\u4E3A\u4F60\u542F\u7528\uFF0C\u53EF\u5728\u672C\u6B21\u4F1A\u8BDD\u4E2D\u76F4\u63A5\u4F7F\u7528\uFF1A", "", ...lines].join("\n"));
25351
25375
  }
25352
25376
  if (opts.materializeSkills) {
25353
25377
  const skillFiles = await opts.materializeSkills(body.actorId, "claude").catch(() => ({}));
25354
25378
  for (const [rel, content] of Object.entries(skillFiles)) {
25355
- const file = join23(dir, rel);
25356
- mkdirSync16(dirname17(file), { recursive: true });
25379
+ const file = join24(dir, rel);
25380
+ mkdirSync16(dirname18(file), { recursive: true });
25357
25381
  writeFileSync15(file, content);
25358
25382
  }
25359
25383
  }
@@ -25366,14 +25390,14 @@ async function startOasisServer(opts) {
25366
25390
  const modeNote = c.mode === "oauth" ? "OAuth \xB7 \u51ED\u8BC1\u7531\u5E73\u53F0\u7BA1\u7406\uFF0C\u901A\u8FC7\u5BF9\u5E94 CLI wrapper \u8C03\u7528" : "\u76F4\u63A5\u5199\u5165 \xB7 \u51ED\u8BC1\u5DF2\u6CE8\u5165\u73AF\u5883\u53D8\u91CF";
25367
25391
  return `- **${c.name}** (\`${c.id}\`): ${statusNote} \xB7 ${modeNote}`;
25368
25392
  });
25369
- writeFileSync15(join23(dir, "CONNECTORS.md"), ["# \u53EF\u7528\u8FDE\u63A5\u5668", "", "\u4EE5\u4E0B\u8FDE\u63A5\u5668\u5DF2\u4E3A\u672C\u6B21\u4F1A\u8BDD\u914D\u7F6E\uFF0C\u51ED\u8BC1\u5DF2\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u6216 CLI wrapper \u6CE8\u5165\uFF0C\u65E0\u9700\u624B\u52A8\u914D\u7F6E\uFF1A", "", ...lines].join("\n"));
25393
+ writeFileSync15(join24(dir, "CONNECTORS.md"), ["# \u53EF\u7528\u8FDE\u63A5\u5668", "", "\u4EE5\u4E0B\u8FDE\u63A5\u5668\u5DF2\u4E3A\u672C\u6B21\u4F1A\u8BDD\u914D\u7F6E\uFF0C\u51ED\u8BC1\u5DF2\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u6216 CLI wrapper \u6CE8\u5165\uFF0C\u65E0\u9700\u624B\u52A8\u914D\u7F6E\uFF1A", "", ...lines].join("\n"));
25370
25394
  }
25371
25395
  spawnCwd = dir;
25372
25396
  }
25373
25397
  }
25374
25398
  const { spawn: spawn7 } = await import("node:child_process");
25375
- const { randomUUID: randomUUID18 } = await import("node:crypto");
25376
- const sessionId = body.sessionId ?? randomUUID18();
25399
+ const { randomUUID: randomUUID19 } = await import("node:crypto");
25400
+ const sessionId = body.sessionId ?? randomUUID19();
25377
25401
  const args = [
25378
25402
  "-p",
25379
25403
  body.message,
@@ -27690,13 +27714,13 @@ var init_service = __esm({
27690
27714
  async readDocument(contentRef) {
27691
27715
  for (const [projectId, space] of this.spaces) {
27692
27716
  if (!contentRef.startsWith(`${space.rootRef}/`)) continue;
27693
- const path19 = contentRef.slice(space.rootRef.length + 1);
27694
- const content = space.files.get(path19);
27717
+ const path20 = contentRef.slice(space.rootRef.length + 1);
27718
+ const content = space.files.get(path20);
27695
27719
  if (content === void 0) return null;
27696
27720
  return {
27697
27721
  contentRef,
27698
27722
  content,
27699
- url: `https://outline.local/${encodeURIComponent(projectId)}/${path19.split("/").map(encodeURIComponent).join("/")}`
27723
+ url: `https://outline.local/${encodeURIComponent(projectId)}/${path20.split("/").map(encodeURIComponent).join("/")}`
27700
27724
  };
27701
27725
  }
27702
27726
  return null;
@@ -27780,8 +27804,8 @@ var init_service = __esm({
27780
27804
  const space = this.requireSpace(state.projectId);
27781
27805
  const stored = { ...state, payload: { ...state.payload }, updatedAt: state.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString() };
27782
27806
  space.runStates.set(runStateKey(state.workOrderId, state.nodeId), stored);
27783
- const path19 = `run_state/${state.workOrderId ?? "project"}/${state.nodeId ?? "default"}.json`;
27784
- space.files.set(path19, JSON.stringify(stored, null, 2));
27807
+ const path20 = `run_state/${state.workOrderId ?? "project"}/${state.nodeId ?? "default"}.json`;
27808
+ space.files.set(path20, JSON.stringify(stored, null, 2));
27785
27809
  return { ...stored, payload: { ...stored.payload } };
27786
27810
  }
27787
27811
  requireSpace(projectId) {
@@ -33266,12 +33290,12 @@ var init_daemon_hub = __esm({
33266
33290
  this.disconnectListeners.add(cb);
33267
33291
  return () => this.disconnectListeners.delete(cb);
33268
33292
  }
33269
- constructor(server, path19 = "/daemon/ws", resolveNode, opts = {}) {
33293
+ constructor(server, path20 = "/daemon/ws", resolveNode, opts = {}) {
33270
33294
  this.pingIntervalMs = opts.pingIntervalMs ?? 2e4;
33271
33295
  this.silenceTimeoutMs = opts.silenceTimeoutMs ?? 6e4;
33272
33296
  this.wss = new import_websocket_server.default({
33273
33297
  server,
33274
- path: path19,
33298
+ path: path20,
33275
33299
  ...resolveNode ? {
33276
33300
  verifyClient: (info, cb) => {
33277
33301
  const authHeader = info.req.headers.authorization ?? "";
@@ -33626,13 +33650,13 @@ var init_skill_fetcher = __esm({
33626
33650
  files = {};
33627
33651
  totalBytes = 0;
33628
33652
  fileCount = 0;
33629
- add(path19, content) {
33653
+ add(path20, content) {
33630
33654
  const bytes = new TextEncoder().encode(content).length;
33631
33655
  if (this.fileCount >= MAX_FILE_COUNT)
33632
33656
  throw new Error(`Import bundle exceeds ${MAX_FILE_COUNT} file limit`);
33633
33657
  if (this.totalBytes + bytes > MAX_TOTAL_BYTES)
33634
33658
  throw new Error(`Import bundle exceeds ${MAX_TOTAL_BYTES} byte limit`);
33635
- this.files[path19] = content;
33659
+ this.files[path20] = content;
33636
33660
  this.totalBytes += bytes;
33637
33661
  this.fileCount++;
33638
33662
  }
@@ -33901,7 +33925,7 @@ ${input.description}
33901
33925
  };
33902
33926
  await this.opts.store.putInstalledSkill(installed);
33903
33927
  const skillFiles = Object.entries(fetched.files).map(
33904
- ([path19, content]) => this.buildSkillFile(id, path19, content, now)
33928
+ ([path20, content]) => this.buildSkillFile(id, path20, content, now)
33905
33929
  );
33906
33930
  await this.opts.store.putSkillFiles(id, skillFiles);
33907
33931
  await this.audit({ kind: "skill_install", actorId: by, by, at: now, detail: { skillId: id, source: input.sourceKind, sourceUrl } });
@@ -33936,7 +33960,7 @@ ${input.description}
33936
33960
  connectorId
33937
33961
  });
33938
33962
  const skillFiles = Object.entries(entry.files).map(
33939
- ([path19, content]) => this.buildSkillFile(id, path19, content, now)
33963
+ ([path20, content]) => this.buildSkillFile(id, path20, content, now)
33940
33964
  );
33941
33965
  await this.opts.store.putSkillFiles(id, skillFiles);
33942
33966
  }
@@ -33954,25 +33978,25 @@ ${input.description}
33954
33978
  * 构造 SkillFile:正文内联进 content(决策 0036);blobHash/size 计算为 content 的 sha256
33955
33979
  * 与字节数,仅作元数据/审计(不再有读取方,正文直接从 content 出)。
33956
33980
  */
33957
- buildSkillFile(skillId, path19, content, now) {
33981
+ buildSkillFile(skillId, path20, content, now) {
33958
33982
  const bytes = new TextEncoder().encode(content);
33959
33983
  const blobHash = (0, import_node_crypto6.createHash)("sha256").update(bytes).digest("hex");
33960
- return { skillId, path: path19, content, blobHash, size: bytes.length, updatedAt: now };
33984
+ return { skillId, path: path20, content, blobHash, size: bytes.length, updatedAt: now };
33961
33985
  }
33962
33986
  /**
33963
33987
  * 更新或新建技能的单个文件。
33964
33988
  * 正文内联进 skill_files(决策 0036),更新文件索引,但**不**改写技能的 name/description——
33965
33989
  * 如果修改的是 SKILL.md,调用方应另外调用 updateInstalledSkill 同步 frontmatter。
33966
33990
  */
33967
- async putSkillFile(skillId, path19, content) {
33991
+ async putSkillFile(skillId, path20, content) {
33968
33992
  const cur = (await this.opts.store.listInstalledSkills()).find((x2) => x2.id === skillId);
33969
33993
  if (!cur) throw new Error(`\u672A\u5B89\u88C5\u8BE5\u6280\u80FD\uFF1A${skillId}`);
33970
33994
  const now = this.now();
33971
- const file = this.buildSkillFile(skillId, path19, content, now);
33995
+ const file = this.buildSkillFile(skillId, path20, content, now);
33972
33996
  const existing = await this.opts.store.listSkillFiles(skillId);
33973
- const next = [...existing.filter((f2) => f2.path !== path19), file];
33997
+ const next = [...existing.filter((f2) => f2.path !== path20), file];
33974
33998
  await this.opts.store.putSkillFiles(skillId, next);
33975
- if (path19 === "SKILL.md") {
33999
+ if (path20 === "SKILL.md") {
33976
34000
  const { name, description } = parseSkillFrontmatter(content);
33977
34001
  if (name || description) {
33978
34002
  await this.opts.store.putInstalledSkill({
@@ -33988,11 +34012,11 @@ ${input.description}
33988
34012
  * 删除技能的单个支撑文件(SKILL.md 主文档受保护,调用方应先拦截)。
33989
34013
  * 单文件删除=读现有清单→剔除该 path→整体回写(putSkillFiles 是 replace-all 语义);blob 残留由 GC 回收。
33990
34014
  */
33991
- async deleteSkillFile(skillId, path19) {
34015
+ async deleteSkillFile(skillId, path20) {
33992
34016
  const cur = (await this.opts.store.listInstalledSkills()).find((x2) => x2.id === skillId);
33993
34017
  if (!cur) throw new Error(`\u672A\u5B89\u88C5\u8BE5\u6280\u80FD\uFF1A${skillId}`);
33994
34018
  const existing = await this.opts.store.listSkillFiles(skillId);
33995
- const next = existing.filter((f2) => f2.path !== path19);
34019
+ const next = existing.filter((f2) => f2.path !== path20);
33996
34020
  if (next.length === existing.length) return;
33997
34021
  await this.opts.store.putSkillFiles(skillId, next);
33998
34022
  }
@@ -34345,7 +34369,8 @@ function estimateUsageCost(model, usage) {
34345
34369
  const outputTokens = Math.max(usage.outputTokens ?? 0, 0);
34346
34370
  const cacheReadTokens = Math.max(usage.cacheReadTokens ?? 0, 0);
34347
34371
  const cacheCreationTokens = Math.max(usage.cacheCreationTokens ?? 0, 0);
34348
- const cost = (inputTokens + cacheCreationTokens) * price.inputPerMillion / 1e6 + outputTokens * price.outputPerMillion / 1e6 + cacheReadTokens * (price.cachedInputPerMillion ?? price.inputPerMillion) / 1e6;
34372
+ const cacheReadPrice = price.cachedInputPerMillion ?? price.inputPerMillion * 0.1;
34373
+ const cost = (inputTokens + cacheCreationTokens) * price.inputPerMillion / 1e6 + outputTokens * price.outputPerMillion / 1e6 + cacheReadTokens * cacheReadPrice / 1e6;
34349
34374
  return { currency: price.currency, micros: Math.round(cost * 1e6) };
34350
34375
  }
34351
34376
  var FOREIGN_MODEL_MARKUP, usd, cny, MODEL_PRICES, PREFIX_PRICES;
@@ -34530,17 +34555,21 @@ function summarizeWeeklyRuns(runs) {
34530
34555
  if (!usage) continue;
34531
34556
  const input = Math.max(usage.inputTokens ?? 0, 0);
34532
34557
  const output = Math.max(usage.outputTokens ?? 0, 0);
34533
- tokenWeek += input + output;
34558
+ const cacheCreation = Math.max(usage.cacheCreationTokens ?? 0, 0);
34559
+ const cacheRead = Math.max(usage.cacheReadTokens ?? 0, 0);
34560
+ tokenWeek += input + output + cacheCreation + cacheRead;
34561
+ const storedCost = Math.max(usage.costUsdMicros ?? 0, 0);
34562
+ if (storedCost > 0) {
34563
+ costWeekUsdMicros += storedCost;
34564
+ continue;
34565
+ }
34534
34566
  const estimated = estimateUsageCost(run.effectiveModel, usage);
34535
34567
  if (estimated) {
34536
34568
  if (estimated.currency === "USD") costWeekUsdMicros += estimated.micros;
34537
34569
  else costWeekCnyMicros += estimated.micros;
34538
34570
  continue;
34539
34571
  }
34540
- const storedCost = Math.max(usage.costUsdMicros ?? 0, 0);
34541
- if (storedCost > 0) {
34542
- costWeekUsdMicros += storedCost;
34543
- } else if (input + output > 0) {
34572
+ if (input + output + cacheCreation + cacheRead > 0) {
34544
34573
  unpriced.add(run.effectiveModel ?? "unknown");
34545
34574
  }
34546
34575
  }
@@ -34559,16 +34588,21 @@ function summarizeWeeklyUsage(rows) {
34559
34588
  for (const row of rows) {
34560
34589
  const input = Math.max(row.inputTokens, 0);
34561
34590
  const output = Math.max(row.outputTokens, 0);
34562
- tokenWeek += input + output;
34591
+ const cacheCreation = Math.max(row.cacheCreationTokens, 0);
34592
+ const cacheRead = Math.max(row.cacheReadTokens, 0);
34593
+ tokenWeek += input + output + cacheCreation + cacheRead;
34594
+ const storedCost = Math.max(row.costUsdMicros, 0);
34595
+ if (storedCost > 0) {
34596
+ costWeekUsdMicros += storedCost;
34597
+ continue;
34598
+ }
34563
34599
  const estimated = estimateRowCost(row);
34564
34600
  if (estimated) {
34565
34601
  if (estimated.currency === "USD") costWeekUsdMicros += estimated.micros;
34566
34602
  else costWeekCnyMicros += estimated.micros;
34567
34603
  continue;
34568
34604
  }
34569
- if (row.costUsdMicros > 0) {
34570
- costWeekUsdMicros += row.costUsdMicros;
34571
- } else if (input + output > 0) {
34605
+ if (input + output + cacheCreation + cacheRead > 0) {
34572
34606
  unpriced.add(row.effectiveModel ?? "unknown");
34573
34607
  }
34574
34608
  }
@@ -36770,27 +36804,188 @@ var init_sender = __esm({
36770
36804
  }
36771
36805
  });
36772
36806
 
36773
- // ../adapters/src/open-design/index.ts
36774
- function numEnv(name, fallback) {
36775
- const v2 = process.env[name];
36776
- const n = Number(v2);
36777
- return v2 !== void 0 && v2 !== "" && Number.isFinite(n) && n > 0 ? n : fallback;
36778
- }
36807
+ // ../adapters/src/open-design/driver.ts
36779
36808
  function deriveBoardKey(artifactId) {
36780
36809
  const tail = artifactId.split(":").pop() ?? artifactId;
36781
36810
  const ascii = tail.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 24);
36782
36811
  const sha8 = (0, import_node_crypto10.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
36783
36812
  return ascii ? `od-${ascii}-${sha8}` : `od-${sha8}`;
36784
36813
  }
36785
- var import_node_crypto10, import_node_child_process2, fs6, os, path5, TOOL_RESULT_SNIPPET, DELTA_FLUSH_MS, TELEMETRY_HEARTBEAT_MS, OdEventTranslator, OpenDesignAdapter;
36786
- var init_open_design = __esm({
36787
- "../adapters/src/open-design/index.ts"() {
36814
+ async function odApi(base, fetchImpl, method, p2, body) {
36815
+ const res = await fetchImpl(`${base}${p2}`, {
36816
+ method,
36817
+ ...body !== void 0 ? { body: JSON.stringify(body), headers: { "content-type": "application/json" } } : {}
36818
+ });
36819
+ if (!res.ok) throw new Error(`od ${method} ${p2} \u2192 ${res.status}: ${(await res.text()).slice(0, 200)}`);
36820
+ return await res.json();
36821
+ }
36822
+ async function ensureProject(base, fetchImpl, boardKey, title) {
36823
+ let conversationId = null;
36824
+ try {
36825
+ const created = await odApi(base, fetchImpl, "POST", "/api/projects", { id: boardKey, name: title });
36826
+ conversationId = created.conversationId ?? null;
36827
+ } catch {
36828
+ }
36829
+ if (!conversationId) {
36830
+ const c = await odApi(base, fetchImpl, "GET", `/api/projects/${encodeURIComponent(boardKey)}/conversations`);
36831
+ conversationId = c.conversations?.[0]?.id ?? null;
36832
+ }
36833
+ if (!conversationId) throw new Error(`od \u9879\u76EE ${boardKey} \u65E0\u53EF\u7528\u4F1A\u8BDD`);
36834
+ let resolvedDir = null;
36835
+ try {
36836
+ const d = await odApi(base, fetchImpl, "GET", `/api/projects/${encodeURIComponent(boardKey)}`);
36837
+ resolvedDir = d.resolvedDir ?? null;
36838
+ } catch {
36839
+ }
36840
+ return { conversationId, resolvedDir };
36841
+ }
36842
+ function materializeContext(resolvedDir, files) {
36843
+ if (!resolvedDir) return;
36844
+ fs6.mkdirSync(resolvedDir, { recursive: true });
36845
+ const root = path5.join(resolvedDir, "task-context");
36846
+ fs6.rmSync(root, { recursive: true, force: true });
36847
+ for (const [rel, content] of Object.entries(files)) {
36848
+ const f2 = path5.join(root, rel);
36849
+ fs6.mkdirSync(path5.dirname(f2), { recursive: true });
36850
+ fs6.writeFileSync(f2, content);
36851
+ }
36852
+ }
36853
+ async function startDesignRun(base, fetchImpl, args) {
36854
+ const created = await odApi(base, fetchImpl, "POST", "/api/runs", {
36855
+ agentId: args.agentId,
36856
+ projectId: args.boardKey,
36857
+ conversationId: args.conversationId,
36858
+ assistantMessageId: (0, import_node_crypto10.randomUUID)(),
36859
+ clientRequestId: (0, import_node_crypto10.randomUUID)(),
36860
+ message: args.message,
36861
+ systemPrompt: args.systemPrompt
36862
+ });
36863
+ return created.runId;
36864
+ }
36865
+ async function pumpDesignEvents(base, fetchImpl, runId, onLine) {
36866
+ const res = await fetchImpl(`${base}/api/runs/${runId}/events`);
36867
+ if (!res.ok || !res.body) return;
36868
+ const reader = res.body.getReader();
36869
+ const dec2 = new TextDecoder();
36870
+ let buf = "";
36871
+ for (; ; ) {
36872
+ const { done, value } = await reader.read();
36873
+ if (done) break;
36874
+ buf += dec2.decode(value, { stream: true });
36875
+ let nl;
36876
+ while ((nl = buf.indexOf("\n")) >= 0) {
36877
+ const line = buf.slice(0, nl).trim();
36878
+ buf = buf.slice(nl + 1);
36879
+ if (line.startsWith("data:")) {
36880
+ const payload = line.slice(5).trim();
36881
+ if (payload) onLine(payload);
36882
+ }
36883
+ }
36884
+ }
36885
+ }
36886
+ async function pollDesignRun(base, fetchImpl, runId, opts = {}) {
36887
+ const interval = opts.intervalMs ?? 5e3;
36888
+ const maxMs = opts.maxMs ?? 30 * 6e4;
36889
+ const started = Date.now();
36890
+ for (; ; ) {
36891
+ await new Promise((r) => setTimeout(r, interval));
36892
+ const s2 = await odApi(base, fetchImpl, "GET", `/api/runs/${runId}`).catch(() => null);
36893
+ if (!s2) {
36894
+ if (Date.now() - started > maxMs) throw new Error(`od run ${runId} \u8F6E\u8BE2\u8D85\u65F6\uFF08${Math.round(maxMs / 6e4)}min \u65E0\u7EC8\u6001\uFF09`);
36895
+ continue;
36896
+ }
36897
+ opts.onPoll?.(s2.status);
36898
+ if (s2.status === "succeeded" || s2.status === "failed" || s2.status === "canceled") return s2.status;
36899
+ if (Date.now() - started > maxMs) throw new Error(`od run ${runId} \u8F6E\u8BE2\u8D85\u65F6\uFF08${Math.round(maxMs / 6e4)}min \u672A\u6536\u5C3E\uFF0C\u672B\u72B6\u6001 ${s2.status}\uFF09`);
36900
+ }
36901
+ }
36902
+ async function harvestBoard(base, fetchImpl, publicBase, workRoot, boardKey, runId) {
36903
+ const listing = await odApi(
36904
+ base,
36905
+ fetchImpl,
36906
+ "GET",
36907
+ `/api/projects/${encodeURIComponent(boardKey)}/files`
36908
+ );
36909
+ const htmls = (listing.files ?? []).filter((f2) => f2.kind === "html" && !f2.path.startsWith("task-context/")).filter((f2) => (f2.artifactManifest?.status ?? "complete") === "complete").sort((a, b2) => (b2.mtime ?? 0) - (a.mtime ?? 0));
36910
+ const entry = htmls[0]?.path;
36911
+ if (!entry) throw new Error("\u753B\u677F\u9879\u76EE\u65E0\u5DF2\u5B8C\u6210\u7684 HTML \u5165\u53E3\u7A3F\u2014\u2014\u8BBE\u8BA1\u4F1A\u8BDD\u672A\u4EA7\u51FA\u53EF\u4EA4\u4ED8\u754C\u9762");
36912
+ const dir = fs6.mkdtempSync(path5.join(workRoot, "od-deliverable-"));
36913
+ const fetchInline = async (rel) => {
36914
+ const res = await fetchImpl(`${base}/api/projects/${encodeURIComponent(boardKey)}/export/${encodeURIComponent(rel)}?inline=1`);
36915
+ if (!res.ok) throw new Error(`od export ${rel} \u2192 ${res.status}`);
36916
+ return await res.text();
36917
+ };
36918
+ fs6.writeFileSync(path5.join(dir, "index.html"), await fetchInline(entry));
36919
+ for (const f2 of listing.files ?? []) {
36920
+ if (f2.path.endsWith(".md") && !f2.path.includes("/")) {
36921
+ try {
36922
+ fs6.writeFileSync(path5.join(dir, f2.path), await fetchInline(f2.path));
36923
+ } catch {
36924
+ }
36925
+ }
36926
+ }
36927
+ fs6.writeFileSync(
36928
+ path5.join(dir, "board.link"),
36929
+ `${publicBase}/projects/${boardKey}
36930
+ \u5165\u53E3\u7A3F\uFF1A${entry}
36931
+ \u5FEB\u7167\u6765\u6E90 run\uFF1A${runId}
36932
+ \uFF08\u6D3B\u753B\u677F\u2014\u2014\u7EE7\u7EED\u8FED\u4EE3\u8BF7\u56DE\u5230\u8BE5\u9879\u76EE\uFF1B\u672C\u88C5\u7BB1\u5355\u4E3A\u8BE5\u6B21\u4EA4\u4ED8\u7684\u51BB\u7ED3\u5FEB\u7167\uFF09
36933
+ `
36934
+ );
36935
+ return { dir, entry };
36936
+ }
36937
+ async function runOpenDesignSession(opts) {
36938
+ const fetchImpl = opts.fetchImpl ?? fetch;
36939
+ const workRoot = opts.workRoot ?? os.tmpdir();
36940
+ const boardKey = deriveBoardKey(opts.artifactId);
36941
+ const { conversationId, resolvedDir } = await ensureProject(opts.base, fetchImpl, boardKey, opts.title);
36942
+ if (opts.contextFiles) materializeContext(resolvedDir, opts.contextFiles);
36943
+ const runId = await startDesignRun(opts.base, fetchImpl, {
36944
+ agentId: opts.agentId,
36945
+ boardKey,
36946
+ conversationId,
36947
+ message: opts.message,
36948
+ systemPrompt: opts.systemPrompt
36949
+ });
36950
+ if (opts.onLine) void pumpDesignEvents(opts.base, fetchImpl, runId, opts.onLine).catch(() => {
36951
+ });
36952
+ const status = await pollDesignRun(opts.base, fetchImpl, runId, {
36953
+ ...opts.pollIntervalMs !== void 0 ? { intervalMs: opts.pollIntervalMs } : {},
36954
+ ...opts.pollMaxMs !== void 0 ? { maxMs: opts.pollMaxMs } : {}
36955
+ });
36956
+ if (status === "canceled") throw new Error(`od run ${runId} \u88AB\u53D6\u6D88`);
36957
+ if (status === "failed") throw new Error(`od run ${runId} \u5931\u8D25`);
36958
+ const { dir, entry } = await harvestBoard(opts.base, fetchImpl, opts.publicBase, workRoot, boardKey, runId);
36959
+ return { dir, entry, boardKey, runId };
36960
+ }
36961
+ var import_node_crypto10, fs6, os, path5;
36962
+ var init_driver = __esm({
36963
+ "../adapters/src/open-design/driver.ts"() {
36788
36964
  "use strict";
36789
36965
  import_node_crypto10 = require("node:crypto");
36790
- import_node_child_process2 = require("node:child_process");
36791
36966
  fs6 = __toESM(require("node:fs"), 1);
36792
36967
  os = __toESM(require("node:os"), 1);
36793
36968
  path5 = __toESM(require("node:path"), 1);
36969
+ }
36970
+ });
36971
+
36972
+ // ../adapters/src/open-design/index.ts
36973
+ function numEnv(name, fallback) {
36974
+ const v2 = process.env[name];
36975
+ const n = Number(v2);
36976
+ return v2 !== void 0 && v2 !== "" && Number.isFinite(n) && n > 0 ? n : fallback;
36977
+ }
36978
+ var import_node_crypto11, import_node_child_process2, fs7, os2, path6, TOOL_RESULT_SNIPPET, DELTA_FLUSH_MS, TELEMETRY_HEARTBEAT_MS, OdEventTranslator, OpenDesignAdapter;
36979
+ var init_open_design = __esm({
36980
+ "../adapters/src/open-design/index.ts"() {
36981
+ "use strict";
36982
+ import_node_crypto11 = require("node:crypto");
36983
+ import_node_child_process2 = require("node:child_process");
36984
+ fs7 = __toESM(require("node:fs"), 1);
36985
+ os2 = __toESM(require("node:os"), 1);
36986
+ path6 = __toESM(require("node:path"), 1);
36987
+ init_driver();
36988
+ init_driver();
36794
36989
  TOOL_RESULT_SNIPPET = 2e3;
36795
36990
  DELTA_FLUSH_MS = 2e4;
36796
36991
  TELEMETRY_HEARTBEAT_MS = 12e4;
@@ -36876,7 +37071,7 @@ var init_open_design = __esm({
36876
37071
  this.publicBase = (opts.publicBaseUrl ?? "https://design.open-friday.com").replace(/\/$/, "");
36877
37072
  this.agentId = opts.agentId ?? "claude";
36878
37073
  this.oasisBin = opts.oasisBin ?? "oasis";
36879
- this.workRoot = opts.workRoot ?? os.tmpdir();
37074
+ this.workRoot = opts.workRoot ?? os2.tmpdir();
36880
37075
  this.fetchImpl = opts.fetchImpl ?? fetch;
36881
37076
  this.maxConcurrent = opts.maxConcurrent ?? numEnv("OASIS_OPEN_DESIGN_MAX_CONCURRENT", 2);
36882
37077
  this.runPropose = opts.runPropose ?? (async ({ artifactId, dir, reason, serverUrl, token }) => {
@@ -36909,91 +37104,16 @@ var init_open_design = __esm({
36909
37104
  this.active--;
36910
37105
  this.waiters.shift()?.();
36911
37106
  }
36912
- async api(method, p2, body) {
36913
- const res = await this.fetchImpl(`${this.base}${p2}`, {
36914
- method,
36915
- ...body !== void 0 ? { body: JSON.stringify(body), headers: { "content-type": "application/json" } } : {}
36916
- });
36917
- if (!res.ok) throw new Error(`od ${method} ${p2} \u2192 ${res.status}: ${(await res.text()).slice(0, 200)}`);
36918
- return await res.json();
36919
- }
36920
- /** 项目就绪(幂等):不存在则建(显式 id=派生 key);已存在则取既有会话。返回 conversationId + 项目目录。 */
36921
- async ensureProject(boardKey, title) {
36922
- let conversationId = null;
36923
- try {
36924
- const created = await this.api("POST", "/api/projects", { id: boardKey, name: title });
36925
- conversationId = created.conversationId ?? null;
36926
- } catch {
36927
- }
36928
- if (!conversationId) {
36929
- const c = await this.api("GET", `/api/projects/${encodeURIComponent(boardKey)}/conversations`);
36930
- conversationId = c.conversations?.[0]?.id ?? null;
36931
- }
36932
- if (!conversationId) throw new Error(`od \u9879\u76EE ${boardKey} \u65E0\u53EF\u7528\u4F1A\u8BDD`);
36933
- let resolvedDir = null;
36934
- try {
36935
- const d = await this.api("GET", `/api/projects/${encodeURIComponent(boardKey)}`);
36936
- resolvedDir = d.resolvedDir ?? null;
36937
- } catch {
36938
- }
36939
- return { conversationId, resolvedDir };
36940
- }
36941
- /** 把派发 bundle 铺进画板项目的 task-context/(同机直写;TASK.md 里引用的 inputs/ 等由此可读)。 */
36942
- materializeContext(resolvedDir, files) {
36943
- if (!resolvedDir) return;
36944
- fs6.mkdirSync(resolvedDir, { recursive: true });
36945
- const root = path5.join(resolvedDir, "task-context");
36946
- fs6.rmSync(root, { recursive: true, force: true });
36947
- for (const [rel, content] of Object.entries(files)) {
36948
- const f2 = path5.join(root, rel);
36949
- fs6.mkdirSync(path5.dirname(f2), { recursive: true });
36950
- fs6.writeFileSync(f2, content);
36951
- }
36952
- }
36953
- /** 收割:挑最新完成态的 HTML 为入口导出(引用树收拢),连同项目内 .md 文档组装装箱单目录。 */
36954
- async harvest(boardKey, runId) {
36955
- const listing = await this.api(
36956
- "GET",
36957
- `/api/projects/${encodeURIComponent(boardKey)}/files`
36958
- );
36959
- const htmls = (listing.files ?? []).filter((f2) => f2.kind === "html" && !f2.path.startsWith("task-context/")).filter((f2) => (f2.artifactManifest?.status ?? "complete") === "complete").sort((a, b2) => (b2.mtime ?? 0) - (a.mtime ?? 0));
36960
- const entry = htmls[0]?.path;
36961
- if (!entry) throw new Error("\u753B\u677F\u9879\u76EE\u65E0\u5DF2\u5B8C\u6210\u7684 HTML \u5165\u53E3\u7A3F\u2014\u2014\u8BBE\u8BA1\u4F1A\u8BDD\u672A\u4EA7\u51FA\u53EF\u4EA4\u4ED8\u754C\u9762");
36962
- const dir = fs6.mkdtempSync(path5.join(this.workRoot, "od-deliverable-"));
36963
- const fetchInline = async (rel) => {
36964
- const res = await this.fetchImpl(`${this.base}/api/projects/${encodeURIComponent(boardKey)}/export/${encodeURIComponent(rel)}?inline=1`);
36965
- if (!res.ok) throw new Error(`od export ${rel} \u2192 ${res.status}`);
36966
- return await res.text();
36967
- };
36968
- fs6.writeFileSync(path5.join(dir, "index.html"), await fetchInline(entry));
36969
- for (const f2 of listing.files ?? []) {
36970
- if (f2.path.endsWith(".md") && !f2.path.includes("/")) {
36971
- try {
36972
- fs6.writeFileSync(path5.join(dir, f2.path), await fetchInline(f2.path));
36973
- } catch {
36974
- }
36975
- }
36976
- }
36977
- fs6.writeFileSync(
36978
- path5.join(dir, "board.link"),
36979
- `${this.publicBase}/projects/${boardKey}
36980
- \u5165\u53E3\u7A3F\uFF1A${entry}
36981
- \u5FEB\u7167\u6765\u6E90 run\uFF1A${runId}
36982
- \uFF08\u6D3B\u753B\u677F\u2014\u2014\u7EE7\u7EED\u8FED\u4EE3\u8BF7\u56DE\u5230\u8BE5\u9879\u76EE\uFF1B\u672C\u88C5\u7BB1\u5355\u4E3A\u8BE5\u6B21\u4EA4\u4ED8\u7684\u51BB\u7ED3\u5FEB\u7167\uFF09
36983
- `
36984
- );
36985
- return { dir, entry };
36986
- }
36987
37107
  async spawn(job) {
36988
37108
  const boardKey = deriveBoardKey(job.artifactId);
36989
- const id = `od-${boardKey}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
37109
+ const id = `od-${boardKey}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
36990
37110
  const exitCbs = [];
36991
37111
  const outputCbs = [];
36992
37112
  const telemetryCbs = [];
36993
37113
  let exited = null;
36994
37114
  let killed = false;
36995
37115
  let runId = null;
36996
- const transcriptRef = path5.join(this.workRoot, `od-transcript-${id}.ndjson`);
37116
+ const transcriptRef = path6.join(this.workRoot, `od-transcript-${id}.ndjson`);
36997
37117
  const translator = new OdEventTranslator();
36998
37118
  let eventSeq = 0;
36999
37119
  let lastTelemetryAt = Date.now();
@@ -37018,15 +37138,15 @@ var init_open_design = __esm({
37018
37138
  finish({ code: null, reason: "timeout" });
37019
37139
  return;
37020
37140
  }
37021
- const { conversationId, resolvedDir } = await this.ensureProject(boardKey, job.artifactId);
37022
- this.materializeContext(resolvedDir, job.bundle.files);
37141
+ const { conversationId, resolvedDir } = await ensureProject(this.base, this.fetchImpl, boardKey, job.artifactId);
37142
+ materializeContext(resolvedDir, job.bundle.files);
37023
37143
  const task = job.bundle.files["TASK.md"] ?? "";
37024
- const created = await this.api("POST", "/api/runs", {
37144
+ const created = await odApi(this.base, this.fetchImpl, "POST", "/api/runs", {
37025
37145
  agentId: this.agentId,
37026
37146
  projectId: boardKey,
37027
37147
  conversationId,
37028
- assistantMessageId: (0, import_node_crypto10.randomUUID)(),
37029
- clientRequestId: (0, import_node_crypto10.randomUUID)(),
37148
+ assistantMessageId: (0, import_node_crypto11.randomUUID)(),
37149
+ clientRequestId: (0, import_node_crypto11.randomUUID)(),
37030
37150
  message: task,
37031
37151
  systemPrompt: "\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"
37032
37152
  });
@@ -37039,7 +37159,7 @@ var init_open_design = __esm({
37039
37159
  let status = "running";
37040
37160
  for (; ; ) {
37041
37161
  await new Promise((r) => setTimeout(r, 5e3));
37042
- const s2 = await this.api("GET", `/api/runs/${runId}`).catch(() => null);
37162
+ const s2 = await odApi(this.base, this.fetchImpl, "GET", `/api/runs/${runId}`).catch(() => null);
37043
37163
  if (!s2) continue;
37044
37164
  status = s2.status;
37045
37165
  if (status === "succeeded" || status === "failed" || status === "canceled") break;
@@ -37055,7 +37175,7 @@ var init_open_design = __esm({
37055
37175
  finish({ code: 1, reason: "error" });
37056
37176
  return;
37057
37177
  }
37058
- const { dir, entry } = await this.harvest(boardKey, runId);
37178
+ const { dir, entry } = await harvestBoard(this.base, this.fetchImpl, this.publicBase, this.workRoot, boardKey, runId);
37059
37179
  await this.runPropose({
37060
37180
  artifactId: job.artifactId,
37061
37181
  dir,
@@ -37066,7 +37186,7 @@ var init_open_design = __esm({
37066
37186
  finish({ code: 0, reason: "clean" });
37067
37187
  } catch (err) {
37068
37188
  try {
37069
- fs6.appendFileSync(transcriptRef, JSON.stringify({ kind: "adapter-error", message: String(err) }) + "\n");
37189
+ fs7.appendFileSync(transcriptRef, JSON.stringify({ kind: "adapter-error", message: String(err) }) + "\n");
37070
37190
  } catch {
37071
37191
  }
37072
37192
  finish({ code: 1, reason: "error" });
@@ -37076,7 +37196,7 @@ var init_open_design = __esm({
37076
37196
  })();
37077
37197
  const cancel = async () => {
37078
37198
  killed = true;
37079
- if (runId) await this.api("POST", `/api/runs/${runId}/cancel`).catch(() => {
37199
+ if (runId) await odApi(this.base, this.fetchImpl, "POST", `/api/runs/${runId}/cancel`).catch(() => {
37080
37200
  });
37081
37201
  };
37082
37202
  return {
@@ -37112,7 +37232,7 @@ var init_open_design = __esm({
37112
37232
  const payload = line.slice(5).trim();
37113
37233
  if (payload) {
37114
37234
  try {
37115
- fs6.appendFileSync(transcriptRef, payload + "\n");
37235
+ fs7.appendFileSync(transcriptRef, payload + "\n");
37116
37236
  } catch {
37117
37237
  }
37118
37238
  onLine(payload);
@@ -37216,26 +37336,26 @@ function classifyExit(result) {
37216
37336
  return void 0;
37217
37337
  }
37218
37338
  function conversationExists(sessionId) {
37219
- const configDir = process.env["CLAUDE_CONFIG_DIR"] || path6.join(os2.homedir(), ".claude");
37220
- const projectsDir = path6.join(configDir, "projects");
37339
+ const configDir = process.env["CLAUDE_CONFIG_DIR"] || path7.join(os3.homedir(), ".claude");
37340
+ const projectsDir = path7.join(configDir, "projects");
37221
37341
  const target = `${sessionId}.jsonl`;
37222
37342
  try {
37223
- for (const proj of fs7.readdirSync(projectsDir)) {
37224
- if (fs7.existsSync(path6.join(projectsDir, proj, target))) return true;
37343
+ for (const proj of fs8.readdirSync(projectsDir)) {
37344
+ if (fs8.existsSync(path7.join(projectsDir, proj, target))) return true;
37225
37345
  }
37226
37346
  } catch {
37227
37347
  }
37228
37348
  return false;
37229
37349
  }
37230
- var import_node_child_process3, import_node_crypto11, fs7, os2, path6, readline, ClaudeCodeAdapter;
37350
+ var import_node_child_process3, import_node_crypto12, fs8, os3, path7, readline, ClaudeCodeAdapter;
37231
37351
  var init_claude_code = __esm({
37232
37352
  "../adapters/src/claude-code/index.ts"() {
37233
37353
  "use strict";
37234
37354
  import_node_child_process3 = require("node:child_process");
37235
- import_node_crypto11 = require("node:crypto");
37236
- fs7 = __toESM(require("node:fs"), 1);
37237
- os2 = __toESM(require("node:os"), 1);
37238
- path6 = __toESM(require("node:path"), 1);
37355
+ import_node_crypto12 = require("node:crypto");
37356
+ fs8 = __toESM(require("node:fs"), 1);
37357
+ os3 = __toESM(require("node:os"), 1);
37358
+ path7 = __toESM(require("node:path"), 1);
37239
37359
  readline = __toESM(require("node:readline"), 1);
37240
37360
  ClaudeCodeAdapter = class {
37241
37361
  constructor(opts = {}) {
@@ -37264,9 +37384,9 @@ var init_claude_code = __esm({
37264
37384
  }
37265
37385
  async spawn(job) {
37266
37386
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
37267
- const id = `claude-${slug6}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
37268
- const dir = job.runtimeSessionId ? path6.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-chat-sessions", job.runtimeSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_")) : fs7.mkdtempSync(path6.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-session-"));
37269
- fs7.mkdirSync(dir, { recursive: true });
37387
+ const id = `claude-${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
37388
+ const dir = job.runtimeSessionId ? path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-chat-sessions", job.runtimeSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_")) : fs8.mkdtempSync(path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-session-"));
37389
+ fs8.mkdirSync(dir, { recursive: true });
37270
37390
  if (this.opts.syncSkills) {
37271
37391
  try {
37272
37392
  await this.opts.syncSkills({
@@ -37281,14 +37401,14 @@ var init_claude_code = __esm({
37281
37401
  }
37282
37402
  }
37283
37403
  for (const [rel, content] of Object.entries(job.bundle.files)) {
37284
- const file = path6.join(dir, rel);
37285
- fs7.mkdirSync(path6.dirname(file), { recursive: true });
37286
- fs7.writeFileSync(file, content);
37404
+ const file = path7.join(dir, rel);
37405
+ fs8.mkdirSync(path7.dirname(file), { recursive: true });
37406
+ fs8.writeFileSync(file, content);
37287
37407
  }
37288
37408
  for (const [rel, b64] of Object.entries(job.bundle.binaryFiles ?? {})) {
37289
- const file = path6.join(dir, rel);
37290
- fs7.mkdirSync(path6.dirname(file), { recursive: true });
37291
- fs7.writeFileSync(file, Buffer.from(b64, "base64"));
37409
+ const file = path7.join(dir, rel);
37410
+ fs8.mkdirSync(path7.dirname(file), { recursive: true });
37411
+ fs8.writeFileSync(file, Buffer.from(b64, "base64"));
37292
37412
  }
37293
37413
  const prompt = job.bundle.files["TASK.md"];
37294
37414
  if (!prompt) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -37320,7 +37440,7 @@ var init_claude_code = __esm({
37320
37440
  ...job.env,
37321
37441
  // BUG-4 缓冲:抬高单响应输出 token 上限(临时缓冲,根治靠分解)
37322
37442
  ...this.opts.maxOutputTokens ? { CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(this.opts.maxOutputTokens) } : {},
37323
- ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path6.dirname(p2)).join(path6.delimiter)}${path6.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
37443
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path7.dirname(p2)).join(path7.delimiter)}${path7.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
37324
37444
  OASIS_SERVER: job.server.url,
37325
37445
  OASIS_TOKEN: job.actorToken,
37326
37446
  // OTel 遥测(默认关;resolveOtelEnv 决定开不开,runId 进 resource 属性自然归位到本次 run)。
@@ -37332,8 +37452,8 @@ var init_claude_code = __esm({
37332
37452
  });
37333
37453
  if (promptViaStdin) child.stdin.write(prompt);
37334
37454
  child.stdin.end();
37335
- let transcriptRef = path6.join(dir, "transcript.txt");
37336
- const out = fs7.createWriteStream(transcriptRef);
37455
+ let transcriptRef = path7.join(dir, "transcript.txt");
37456
+ const out = fs8.createWriteStream(transcriptRef);
37337
37457
  const telemetryCbs = [];
37338
37458
  let eventSeq = 0;
37339
37459
  let lastResult;
@@ -37403,14 +37523,14 @@ var init_claude_code = __esm({
37403
37523
  const reason = killedByUs ? "timeout" : classifyExit(lastResult);
37404
37524
  if (this.opts.cleanupWorkdir && !job.runtimeSessionId) {
37405
37525
  try {
37406
- const keepDir = path6.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-transcripts");
37407
- fs7.mkdirSync(keepDir, { recursive: true });
37408
- const kept = path6.join(keepDir, `${id}.txt`);
37526
+ const keepDir = path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-transcripts");
37527
+ fs8.mkdirSync(keepDir, { recursive: true });
37528
+ const kept = path7.join(keepDir, `${id}.txt`);
37409
37529
  const src = transcriptRef;
37410
37530
  out.end(() => {
37411
37531
  try {
37412
- fs7.renameSync(src, kept);
37413
- fs7.rmSync(dir, { recursive: true, force: true });
37532
+ fs8.renameSync(src, kept);
37533
+ fs8.rmSync(dir, { recursive: true, force: true });
37414
37534
  } catch {
37415
37535
  }
37416
37536
  });
@@ -37589,7 +37709,7 @@ var init_resilient = __esm({
37589
37709
 
37590
37710
  // ../adapters/src/_core/skill-cache.ts
37591
37711
  function defaultCacheRoot() {
37592
- return path7.join(os3.homedir(), ".oasis", "skill-cache");
37712
+ return path8.join(os4.homedir(), ".oasis", "skill-cache");
37593
37713
  }
37594
37714
  function sessionSkillsSubdir(runtimeKind) {
37595
37715
  return runtimeKind === "claude" || runtimeKind === "claude-code" ? ".claude/skills" : ".agent_context/skills";
@@ -37600,7 +37720,7 @@ async function syncActorSkills(opts) {
37600
37720
  });
37601
37721
  const now = opts.now ?? (() => /* @__PURE__ */ new Date());
37602
37722
  const actorDir = pathForActor(cacheRoot, opts.actorId);
37603
- const manifestPath = path7.join(actorDir, "manifest.json");
37723
+ const manifestPath = path8.join(actorDir, "manifest.json");
37604
37724
  await fsp.mkdir(actorDir, { recursive: true, mode: 493 });
37605
37725
  const release = await acquireLock(cacheRoot, opts.actorId, now, log3);
37606
37726
  try {
@@ -37618,7 +37738,7 @@ async function syncActorSkills(opts) {
37618
37738
  const cloudIds = new Set(cloudMetadata.map((s2) => s2.id));
37619
37739
  for (const cloud of cloudMetadata) {
37620
37740
  const cached2 = manifest.skills[cloud.id];
37621
- const skillDir = path7.join(actorDir, cloud.dir);
37741
+ const skillDir = path8.join(actorDir, cloud.dir);
37622
37742
  const inSync = cached2 && cached2.dir === cloud.dir && cached2.contentHash === cloud.contentHash && cached2.cloudUpdatedAt === cloud.updatedAt && await dirLooksValid(skillDir, cached2.fileList);
37623
37743
  if (inSync) {
37624
37744
  skipped += 1;
@@ -37646,7 +37766,7 @@ async function syncActorSkills(opts) {
37646
37766
  for (const [id, entry] of Object.entries(manifest.skills)) {
37647
37767
  if (cloudIds.has(id)) continue;
37648
37768
  try {
37649
- await fsp.rm(path7.join(actorDir, entry.dir), { recursive: true, force: true });
37769
+ await fsp.rm(path8.join(actorDir, entry.dir), { recursive: true, force: true });
37650
37770
  } catch (err) {
37651
37771
  log3("warn", `\u5220\u9664\u5B64\u513F\u6280\u80FD\u76EE\u5F55\u5931\u8D25 ${entry.dir}`, err);
37652
37772
  }
@@ -37663,14 +37783,14 @@ async function syncActorSkills(opts) {
37663
37783
  }
37664
37784
  }
37665
37785
  function pathForActor(cacheRoot, actorId) {
37666
- return path7.join(cacheRoot, "actors", encodeURIComponent(actorId));
37786
+ return path8.join(cacheRoot, "actors", encodeURIComponent(actorId));
37667
37787
  }
37668
37788
  function lockPathFor(cacheRoot, actorId) {
37669
- return path7.join(cacheRoot, "locks", `${encodeURIComponent(actorId)}.lock`);
37789
+ return path8.join(cacheRoot, "locks", `${encodeURIComponent(actorId)}.lock`);
37670
37790
  }
37671
37791
  async function acquireLock(cacheRoot, actorId, now, log3) {
37672
37792
  const lockPath = lockPathFor(cacheRoot, actorId);
37673
- await fsp.mkdir(path7.dirname(lockPath), { recursive: true, mode: 493 });
37793
+ await fsp.mkdir(path8.dirname(lockPath), { recursive: true, mode: 493 });
37674
37794
  const started = now().getTime();
37675
37795
  while (true) {
37676
37796
  try {
@@ -37736,26 +37856,26 @@ async function readManifest2(manifestPath, actorId, log3) {
37736
37856
  };
37737
37857
  }
37738
37858
  async function writeManifest(manifestPath, manifest) {
37739
- const dir = path7.dirname(manifestPath);
37859
+ const dir = path8.dirname(manifestPath);
37740
37860
  await fsp.mkdir(dir, { recursive: true });
37741
37861
  const tmp = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;
37742
37862
  await fsp.writeFile(tmp, JSON.stringify(manifest, null, 2), { mode: 420 });
37743
37863
  await fsp.rename(tmp, manifestPath);
37744
37864
  }
37745
37865
  async function materializeSkillDir(actorDir, targetDir, files, previousDir) {
37746
- const targetPath = path7.join(actorDir, targetDir);
37747
- const tmpPath = path7.join(actorDir, `${targetDir}.new.${process.pid}.${Date.now()}`);
37748
- const oldBackup = path7.join(actorDir, `${targetDir}.old.${process.pid}.${Date.now()}`);
37866
+ const targetPath = path8.join(actorDir, targetDir);
37867
+ const tmpPath = path8.join(actorDir, `${targetDir}.new.${process.pid}.${Date.now()}`);
37868
+ const oldBackup = path8.join(actorDir, `${targetDir}.old.${process.pid}.${Date.now()}`);
37749
37869
  await fsp.rm(tmpPath, { recursive: true, force: true });
37750
37870
  await fsp.mkdir(tmpPath, { recursive: true, mode: 493 });
37751
37871
  for (const f2 of files) {
37752
37872
  if (!f2.content) continue;
37753
- const dest = path7.join(tmpPath, f2.path);
37754
- const rel = path7.relative(tmpPath, dest);
37755
- if (rel.startsWith("..") || path7.isAbsolute(rel)) {
37873
+ const dest = path8.join(tmpPath, f2.path);
37874
+ const rel = path8.relative(tmpPath, dest);
37875
+ if (rel.startsWith("..") || path8.isAbsolute(rel)) {
37756
37876
  throw new Error(`SkillFile.path \u4E0D\u5408\u6CD5: ${f2.path}`);
37757
37877
  }
37758
- await fsp.mkdir(path7.dirname(dest), { recursive: true });
37878
+ await fsp.mkdir(path8.dirname(dest), { recursive: true });
37759
37879
  await fsp.writeFile(dest, f2.content, { mode: 420 });
37760
37880
  }
37761
37881
  let hadOld = false;
@@ -37769,14 +37889,14 @@ async function materializeSkillDir(actorDir, targetDir, files, previousDir) {
37769
37889
  await fsp.rename(tmpPath, targetPath);
37770
37890
  if (hadOld) await fsp.rm(oldBackup, { recursive: true, force: true });
37771
37891
  if (previousDir && previousDir !== targetDir) {
37772
- await fsp.rm(path7.join(actorDir, previousDir), { recursive: true, force: true });
37892
+ await fsp.rm(path8.join(actorDir, previousDir), { recursive: true, force: true });
37773
37893
  }
37774
37894
  }
37775
37895
  async function dirLooksValid(dir, expectFileList) {
37776
37896
  if (expectFileList.length === 0) return false;
37777
37897
  try {
37778
37898
  for (const rel of expectFileList) {
37779
- await fsp.stat(path7.join(dir, rel));
37899
+ await fsp.stat(path8.join(dir, rel));
37780
37900
  }
37781
37901
  return true;
37782
37902
  } catch {
@@ -37785,18 +37905,18 @@ async function dirLooksValid(dir, expectFileList) {
37785
37905
  }
37786
37906
  async function syncSessionSymlinks(sessionDir, runtimeKind, actorDir, manifest, log3) {
37787
37907
  const subdir = sessionSkillsSubdir(runtimeKind);
37788
- const skillsDir = path7.join(sessionDir, subdir);
37908
+ const skillsDir = path8.join(sessionDir, subdir);
37789
37909
  await fsp.mkdir(skillsDir, { recursive: true, mode: 493 });
37790
37910
  const desired = /* @__PURE__ */ new Map();
37791
37911
  for (const entry of Object.values(manifest.skills)) {
37792
- desired.set(entry.dir, path7.join(actorDir, entry.dir));
37912
+ desired.set(entry.dir, path8.join(actorDir, entry.dir));
37793
37913
  }
37794
37914
  for (const [name, target] of desired) {
37795
- const link = path7.join(skillsDir, name);
37915
+ const link = path8.join(skillsDir, name);
37796
37916
  let ok = false;
37797
37917
  try {
37798
37918
  const current = await fsp.readlink(link);
37799
- ok = path7.resolve(skillsDir, current) === target;
37919
+ ok = path8.resolve(skillsDir, current) === target;
37800
37920
  } catch {
37801
37921
  }
37802
37922
  if (!ok) {
@@ -37816,19 +37936,19 @@ async function syncSessionSymlinks(sessionDir, runtimeKind, actorDir, manifest,
37816
37936
  for (const name of entries) {
37817
37937
  if (desired.has(name)) continue;
37818
37938
  try {
37819
- await fsp.rm(path7.join(skillsDir, name), { recursive: true, force: true });
37939
+ await fsp.rm(path8.join(skillsDir, name), { recursive: true, force: true });
37820
37940
  } catch (err) {
37821
37941
  log3("warn", `\u6E05\u5B64\u513F\u5931\u8D25 ${name}`, err);
37822
37942
  }
37823
37943
  }
37824
37944
  }
37825
- var fsp, os3, path7, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
37945
+ var fsp, os4, path8, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
37826
37946
  var init_skill_cache = __esm({
37827
37947
  "../adapters/src/_core/skill-cache.ts"() {
37828
37948
  "use strict";
37829
37949
  fsp = __toESM(require("node:fs/promises"), 1);
37830
- os3 = __toESM(require("node:os"), 1);
37831
- path7 = __toESM(require("node:path"), 1);
37950
+ os4 = __toESM(require("node:os"), 1);
37951
+ path8 = __toESM(require("node:path"), 1);
37832
37952
  MANIFEST_SCHEMA_VERSION = 1;
37833
37953
  STALE_LOCK_MS = 6e4;
37834
37954
  LOCK_ACQUIRE_TIMEOUT_MS = 3e4;
@@ -38197,12 +38317,12 @@ function parseCodexModel(lines) {
38197
38317
  function codexSessionsRoot() {
38198
38318
  const candidates = [];
38199
38319
  const ch = process.env["CODEX_HOME"];
38200
- if (ch) candidates.push(path8.join(ch, "sessions"));
38201
- const home = process.env["HOME"] || os4.homedir();
38202
- if (home) candidates.push(path8.join(home, ".codex", "sessions"));
38320
+ if (ch) candidates.push(path9.join(ch, "sessions"));
38321
+ const home = process.env["HOME"] || os5.homedir();
38322
+ if (home) candidates.push(path9.join(home, ".codex", "sessions"));
38203
38323
  for (const c of candidates) {
38204
38324
  try {
38205
- if (fs8.statSync(c).isDirectory()) return c;
38325
+ if (fs9.statSync(c).isDirectory()) return c;
38206
38326
  } catch {
38207
38327
  }
38208
38328
  }
@@ -38216,13 +38336,13 @@ function codexRolloutExists(sessionId, root = codexSessionsRoot()) {
38216
38336
  if (hit) return;
38217
38337
  let ents;
38218
38338
  try {
38219
- ents = fs8.readdirSync(d, { withFileTypes: true });
38339
+ ents = fs9.readdirSync(d, { withFileTypes: true });
38220
38340
  } catch {
38221
38341
  return;
38222
38342
  }
38223
38343
  for (const ent of ents) {
38224
38344
  if (hit) return;
38225
- const p2 = path8.join(d, ent.name);
38345
+ const p2 = path9.join(d, ent.name);
38226
38346
  if (ent.isDirectory()) walk(p2);
38227
38347
  else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) {
38228
38348
  hit = true;
@@ -38239,17 +38359,17 @@ function listRecentRollouts(root, sinceMs) {
38239
38359
  const walk = (d) => {
38240
38360
  let ents;
38241
38361
  try {
38242
- ents = fs8.readdirSync(d, { withFileTypes: true });
38362
+ ents = fs9.readdirSync(d, { withFileTypes: true });
38243
38363
  } catch {
38244
38364
  return;
38245
38365
  }
38246
38366
  for (const ent of ents) {
38247
- const p2 = path8.join(d, ent.name);
38367
+ const p2 = path9.join(d, ent.name);
38248
38368
  if (ent.isDirectory()) walk(p2);
38249
38369
  else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(".jsonl")) {
38250
38370
  let m2 = 0;
38251
38371
  try {
38252
- m2 = fs8.statSync(p2).mtimeMs;
38372
+ m2 = fs9.statSync(p2).mtimeMs;
38253
38373
  } catch {
38254
38374
  }
38255
38375
  if (m2 >= margin) found.push({ f: p2, m: m2 });
@@ -38264,7 +38384,7 @@ function scanCodexTelemetry(workdir, sinceMs, sessionsRoot = codexSessionsRoot()
38264
38384
  for (const f2 of listRecentRollouts(sessionsRoot, sinceMs)) {
38265
38385
  let lines;
38266
38386
  try {
38267
- lines = fs8.readFileSync(f2, "utf8").split("\n");
38387
+ lines = fs9.readFileSync(f2, "utf8").split("\n");
38268
38388
  } catch {
38269
38389
  continue;
38270
38390
  }
@@ -38455,15 +38575,15 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
38455
38575
  tool.output.push(line);
38456
38576
  return [];
38457
38577
  }
38458
- var import_node_child_process5, import_node_crypto12, fs8, os4, path8, readline2, CodexAdapter;
38578
+ var import_node_child_process5, import_node_crypto13, fs9, os5, path9, readline2, CodexAdapter;
38459
38579
  var init_codex = __esm({
38460
38580
  "../adapters/src/codex/index.ts"() {
38461
38581
  "use strict";
38462
38582
  import_node_child_process5 = require("node:child_process");
38463
- import_node_crypto12 = require("node:crypto");
38464
- fs8 = __toESM(require("node:fs"), 1);
38465
- os4 = __toESM(require("node:os"), 1);
38466
- path8 = __toESM(require("node:path"), 1);
38583
+ import_node_crypto13 = require("node:crypto");
38584
+ fs9 = __toESM(require("node:fs"), 1);
38585
+ os5 = __toESM(require("node:os"), 1);
38586
+ path9 = __toESM(require("node:path"), 1);
38467
38587
  readline2 = __toESM(require("node:readline"), 1);
38468
38588
  init_claude_code();
38469
38589
  CodexAdapter = class {
@@ -38472,13 +38592,13 @@ var init_codex = __esm({
38472
38592
  }
38473
38593
  async spawn(job) {
38474
38594
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
38475
- const id = `codex-${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
38595
+ const id = `codex-${slug6}-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
38476
38596
  const startedAtMs = Date.now();
38477
- const dir = fs8.mkdtempSync(path8.join(this.opts.workRoot ?? os4.tmpdir(), "oasis-session-"));
38597
+ const dir = fs9.mkdtempSync(path9.join(this.opts.workRoot ?? os5.tmpdir(), "oasis-session-"));
38478
38598
  for (const [rel, content] of Object.entries(job.bundle.files)) {
38479
- const file = path8.join(dir, rel);
38480
- fs8.mkdirSync(path8.dirname(file), { recursive: true });
38481
- fs8.writeFileSync(file, content);
38599
+ const file = path9.join(dir, rel);
38600
+ fs9.mkdirSync(path9.dirname(file), { recursive: true });
38601
+ fs9.writeFileSync(file, content);
38482
38602
  }
38483
38603
  const task = job.bundle.files["TASK.md"];
38484
38604
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -38507,14 +38627,14 @@ var init_codex = __esm({
38507
38627
  ...scrubLeakyEnv(process.env),
38508
38628
  ...this.opts.env,
38509
38629
  ...job.env,
38510
- ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path8.dirname(p2)).join(path8.delimiter)}${path8.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
38630
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path9.dirname(p2)).join(path9.delimiter)}${path9.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
38511
38631
  OASIS_SERVER: job.server.url,
38512
38632
  OASIS_TOKEN: job.actorToken
38513
38633
  },
38514
38634
  stdio: ["ignore", "pipe", "pipe"]
38515
38635
  });
38516
- let transcriptRef = path8.join(dir, "transcript.txt");
38517
- const out = fs8.createWriteStream(transcriptRef);
38636
+ let transcriptRef = path9.join(dir, "transcript.txt");
38637
+ const out = fs9.createWriteStream(transcriptRef);
38518
38638
  const outputCbs = [];
38519
38639
  const telemetryCbs = [];
38520
38640
  const normalizeState = createCodexNormalizeState();
@@ -38527,14 +38647,34 @@ var init_codex = __esm({
38527
38647
  for (const cb of telemetryCbs) cb(full);
38528
38648
  }
38529
38649
  };
38650
+ const stderrTail = [];
38651
+ const STDERR_MAX_LINES = 40;
38652
+ const STDERR_MAX_BYTES = 4e3;
38653
+ const pushStderrTail = (line) => {
38654
+ stderrTail.push(line);
38655
+ while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
38656
+ let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
38657
+ while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
38658
+ total -= stderrTail.shift().length + 1;
38659
+ }
38660
+ };
38661
+ const stdoutErrorLines = [];
38662
+ const pushStdoutErrorLine = (line) => {
38663
+ if (/^\s*(Error|error):/i.test(line) || /"error"\s*:/.test(line)) {
38664
+ stdoutErrorLines.push(line);
38665
+ if (stdoutErrorLines.length > 10) stdoutErrorLines.shift();
38666
+ }
38667
+ };
38530
38668
  const rl = readline2.createInterface({ input: child.stdout });
38531
38669
  rl.on("line", (line) => {
38532
38670
  out.write(line + "\n");
38671
+ pushStdoutErrorLine(line);
38533
38672
  emitNormalized(normalizeCodexStreamLine(line, normalizeState));
38534
38673
  });
38535
38674
  const errRl = readline2.createInterface({ input: child.stderr });
38536
38675
  errRl.on("line", (line) => {
38537
38676
  out.write(line + "\n");
38677
+ pushStderrTail(line);
38538
38678
  emitNormalized(normalizeCodexConsoleLine(line, consoleNormalizeState));
38539
38679
  });
38540
38680
  const callbacks = [];
@@ -38544,14 +38684,14 @@ var init_codex = __esm({
38544
38684
  if (exited) return;
38545
38685
  if (this.opts.cleanupWorkdir) {
38546
38686
  try {
38547
- const keepDir = path8.join(this.opts.workRoot ?? os4.tmpdir(), "oasis-transcripts");
38548
- fs8.mkdirSync(keepDir, { recursive: true });
38549
- const kept = path8.join(keepDir, `${id}.txt`);
38687
+ const keepDir = path9.join(this.opts.workRoot ?? os5.tmpdir(), "oasis-transcripts");
38688
+ fs9.mkdirSync(keepDir, { recursive: true });
38689
+ const kept = path9.join(keepDir, `${id}.txt`);
38550
38690
  const src = transcriptRef;
38551
38691
  out.end(() => {
38552
38692
  try {
38553
- fs8.renameSync(src, kept);
38554
- fs8.rmSync(dir, { recursive: true, force: true });
38693
+ fs9.renameSync(src, kept);
38694
+ fs9.rmSync(dir, { recursive: true, force: true });
38555
38695
  } catch {
38556
38696
  }
38557
38697
  });
@@ -38576,13 +38716,16 @@ var init_codex = __esm({
38576
38716
  const telemetry = scanCodexTelemetry(dir, startedAtMs);
38577
38717
  const model = telemetry.model ?? job.model ?? this.opts.model;
38578
38718
  const runtimeSessionId = telemetry.sessionId ?? (job.resumeRuntimeSession ? job.runtimeSessionId : void 0);
38719
+ const isError = !killedByUs && typeof code === "number" && code !== 0;
38720
+ const errorMessage = isError ? [...stdoutErrorLines, ...stderrTail].join("\n").trim().slice(-4e3) || void 0 : void 0;
38579
38721
  finish({
38580
38722
  code: killedByUs ? null : code,
38581
38723
  reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error",
38582
38724
  transcriptRef,
38583
38725
  ...telemetry.usage ? { usage: telemetry.usage } : {},
38584
38726
  ...model ? { model } : {},
38585
- ...runtimeSessionId ? { runtimeSessionId } : {}
38727
+ ...runtimeSessionId ? { runtimeSessionId } : {},
38728
+ ...errorMessage ? { errorMessage } : {}
38586
38729
  });
38587
38730
  });
38588
38731
  return {
@@ -39096,6 +39239,13 @@ function parseArgsJSON(argsText) {
39096
39239
  return { text: t };
39097
39240
  }
39098
39241
  }
39242
+ function composeAcpErrorMessage(rpcError, stderrTail) {
39243
+ const parts = [];
39244
+ if (rpcError && rpcError.trim()) parts.push(rpcError.trim());
39245
+ if (stderrTail.length) parts.push(stderrTail.join("\n").trim());
39246
+ const combined = parts.filter(Boolean).join("\n---\n").slice(-4e3).trim();
39247
+ return combined || void 0;
39248
+ }
39099
39249
  function extractSessionID(result) {
39100
39250
  return result?.sessionId ?? "";
39101
39251
  }
@@ -39117,13 +39267,13 @@ function extractStopReason(result) {
39117
39267
  }
39118
39268
  async function runACPSession(job, cfg) {
39119
39269
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
39120
- const binTag = path9.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
39121
- const id = `${binTag}-${slug6}-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
39122
- const dir = fs9.mkdtempSync(path9.join(cfg.workRoot ?? os5.tmpdir(), "oasis-session-"));
39270
+ const binTag = path10.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
39271
+ const id = `${binTag}-${slug6}-${(0, import_node_crypto14.randomUUID)().slice(0, 8)}`;
39272
+ const dir = fs10.mkdtempSync(path10.join(cfg.workRoot ?? os6.tmpdir(), "oasis-session-"));
39123
39273
  for (const [rel, content] of Object.entries(job.bundle.files)) {
39124
- const file = path9.join(dir, rel);
39125
- fs9.mkdirSync(path9.dirname(file), { recursive: true });
39126
- fs9.writeFileSync(file, content);
39274
+ const file = path10.join(dir, rel);
39275
+ fs10.mkdirSync(path10.dirname(file), { recursive: true });
39276
+ fs10.writeFileSync(file, content);
39127
39277
  }
39128
39278
  const task = job.bundle.files["TASK.md"];
39129
39279
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -39134,14 +39284,14 @@ async function runACPSession(job, cfg) {
39134
39284
  ...cfg.env,
39135
39285
  ...job.env,
39136
39286
  ...cfg.yoloEnv ?? {},
39137
- ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path9.dirname(p2)).join(path9.delimiter)}${path9.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
39287
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path10.dirname(p2)).join(path10.delimiter)}${path10.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
39138
39288
  OASIS_SERVER: job.server.url,
39139
39289
  OASIS_TOKEN: job.actorToken
39140
39290
  },
39141
39291
  stdio: ["pipe", "pipe", "pipe"]
39142
39292
  });
39143
- let transcriptRef = path9.join(dir, "transcript.txt");
39144
- const transcriptOut = fs9.createWriteStream(transcriptRef);
39293
+ let transcriptRef = path10.join(dir, "transcript.txt");
39294
+ const transcriptOut = fs10.createWriteStream(transcriptRef);
39145
39295
  const outputCbs = [];
39146
39296
  const telemetryCbs = [];
39147
39297
  const exitCbs = [];
@@ -39158,14 +39308,14 @@ async function runACPSession(job, cfg) {
39158
39308
  if (capturedSessionId && !info.runtimeSessionId) info = { ...info, runtimeSessionId: capturedSessionId };
39159
39309
  if (cfg.cleanupWorkdir) {
39160
39310
  try {
39161
- const keepDir = path9.join(cfg.workRoot ?? os5.tmpdir(), "oasis-transcripts");
39162
- fs9.mkdirSync(keepDir, { recursive: true });
39163
- const kept = path9.join(keepDir, `${id}.txt`);
39311
+ const keepDir = path10.join(cfg.workRoot ?? os6.tmpdir(), "oasis-transcripts");
39312
+ fs10.mkdirSync(keepDir, { recursive: true });
39313
+ const kept = path10.join(keepDir, `${id}.txt`);
39164
39314
  const src = transcriptRef;
39165
39315
  transcriptOut.end(() => {
39166
39316
  try {
39167
- fs9.renameSync(src, kept);
39168
- fs9.rmSync(dir, { recursive: true, force: true });
39317
+ fs10.renameSync(src, kept);
39318
+ fs10.rmSync(dir, { recursive: true, force: true });
39169
39319
  } catch {
39170
39320
  }
39171
39321
  });
@@ -39181,7 +39331,23 @@ async function runACPSession(job, cfg) {
39181
39331
  killedByUs = true;
39182
39332
  child.kill("SIGKILL");
39183
39333
  }, job.limits.wallClockMs);
39184
- child.stderr.pipe(transcriptOut);
39334
+ const stderrTail = [];
39335
+ const STDERR_MAX_LINES = 40;
39336
+ const STDERR_MAX_BYTES = 4e3;
39337
+ const stderrRl = readline3.createInterface({ input: child.stderr });
39338
+ stderrRl.on("line", (line) => {
39339
+ try {
39340
+ transcriptOut.write(line + "\n");
39341
+ } catch {
39342
+ }
39343
+ stderrTail.push(line);
39344
+ while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
39345
+ let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
39346
+ while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
39347
+ total -= stderrTail.shift().length + 1;
39348
+ }
39349
+ });
39350
+ let lastRpcError;
39185
39351
  let streamingCurrentTurn = false;
39186
39352
  const client = new ACPClient(
39187
39353
  (line) => {
@@ -39213,14 +39379,20 @@ async function runACPSession(job, cfg) {
39213
39379
  resolve4();
39214
39380
  });
39215
39381
  });
39216
- child.on("error", () => {
39382
+ child.on("error", (err) => {
39217
39383
  clearTimeout(timer);
39218
- finish({ code: null, reason: "error", transcriptRef });
39384
+ finish({ code: null, reason: "error", transcriptRef, errorMessage: composeAcpErrorMessage(err instanceof Error ? err.message : String(err), stderrTail) });
39219
39385
  });
39220
39386
  child.on("exit", (code) => {
39221
39387
  clearTimeout(timer);
39222
39388
  void readerDone.then(() => {
39223
- finish({ code: killedByUs ? null : code, reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error", transcriptRef });
39389
+ const isError = !killedByUs && typeof code === "number" && code !== 0;
39390
+ finish({
39391
+ code: killedByUs ? null : code,
39392
+ reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error",
39393
+ transcriptRef,
39394
+ ...isError ? { errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail) } : {}
39395
+ });
39224
39396
  });
39225
39397
  });
39226
39398
  void (async () => {
@@ -39311,10 +39483,11 @@ ${task}` : task;
39311
39483
  if (!exited) finish({ code: 0, reason: "clean", transcriptRef, usage, model: actualModel });
39312
39484
  child.kill("SIGTERM");
39313
39485
  } catch (err) {
39486
+ lastRpcError = err instanceof Error ? err.message : String(err);
39314
39487
  if (!exited) {
39315
39488
  const reason = killedByUs ? "timeout" : "error";
39316
39489
  const usage = buildUsage(client.usage, estimateCost(client.usage, actualModel));
39317
- finish({ code: null, reason, transcriptRef, usage, model: actualModel });
39490
+ finish({ code: null, reason, transcriptRef, usage, model: actualModel, errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail) });
39318
39491
  }
39319
39492
  } finally {
39320
39493
  await readerDone;
@@ -39342,15 +39515,15 @@ ${task}` : task;
39342
39515
  }
39343
39516
  };
39344
39517
  }
39345
- var import_node_child_process6, import_node_crypto13, fs9, os5, path9, readline3, ACPClient;
39518
+ var import_node_child_process6, import_node_crypto14, fs10, os6, path10, readline3, ACPClient;
39346
39519
  var init_acp = __esm({
39347
39520
  "../adapters/src/_core/acp.ts"() {
39348
39521
  "use strict";
39349
39522
  import_node_child_process6 = require("node:child_process");
39350
- import_node_crypto13 = require("node:crypto");
39351
- fs9 = __toESM(require("node:fs"), 1);
39352
- os5 = __toESM(require("node:os"), 1);
39353
- path9 = __toESM(require("node:path"), 1);
39523
+ import_node_crypto14 = require("node:crypto");
39524
+ fs10 = __toESM(require("node:fs"), 1);
39525
+ os6 = __toESM(require("node:os"), 1);
39526
+ path10 = __toESM(require("node:path"), 1);
39354
39527
  readline3 = __toESM(require("node:readline"), 1);
39355
39528
  init_claude_code();
39356
39529
  init_usage();
@@ -39489,9 +39662,9 @@ var init_acp = __esm({
39489
39662
  this.onTelemetry({ kind, payload, seq: ++this.seq, ts: (/* @__PURE__ */ new Date()).toISOString() });
39490
39663
  }
39491
39664
  appendText(kind, text) {
39492
- if (kind === "message") this.onOutput(text);
39493
39665
  const other = kind === "message" ? "thought" : "message";
39494
39666
  this.flushTextBuffer(other);
39667
+ if (kind === "message") this.onOutput(text);
39495
39668
  const existing = this.textBuffers.get(kind);
39496
39669
  if (existing) existing.text += text;
39497
39670
  else this.textBuffers.set(kind, { text, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
@@ -39668,12 +39841,12 @@ var init_kiro = __esm({
39668
39841
  // ../adapters/src/_core/subprocess.ts
39669
39842
  function materialize(job, workRoot) {
39670
39843
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
39671
- const id = `${slug6}-${(0, import_node_crypto14.randomUUID)().slice(0, 8)}`;
39672
- const dir = fs10.mkdtempSync(path10.join(workRoot ?? os6.tmpdir(), "oasis-session-"));
39844
+ const id = `${slug6}-${(0, import_node_crypto15.randomUUID)().slice(0, 8)}`;
39845
+ const dir = fs11.mkdtempSync(path11.join(workRoot ?? os7.tmpdir(), "oasis-session-"));
39673
39846
  for (const [rel, content] of Object.entries(job.bundle.files)) {
39674
- const file = path10.join(dir, rel);
39675
- fs10.mkdirSync(path10.dirname(file), { recursive: true });
39676
- fs10.writeFileSync(file, content);
39847
+ const file = path11.join(dir, rel);
39848
+ fs11.mkdirSync(path11.dirname(file), { recursive: true });
39849
+ fs11.writeFileSync(file, content);
39677
39850
  }
39678
39851
  const task = job.bundle.files["TASK.md"];
39679
39852
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -39684,7 +39857,7 @@ function buildEnv(job, extra) {
39684
39857
  ...scrubLeakyEnv(process.env),
39685
39858
  ...extra,
39686
39859
  ...job.env,
39687
- ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path10.dirname(p2)).join(path10.delimiter)}${path10.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
39860
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path11.dirname(p2)).join(path11.delimiter)}${path11.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
39688
39861
  OASIS_SERVER: job.server.url,
39689
39862
  OASIS_TOKEN: job.actorToken
39690
39863
  };
@@ -39696,14 +39869,14 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs) {
39696
39869
  if (cfg.model && !info.model) info = { ...info, model: cfg.model };
39697
39870
  if (cfg.cleanupWorkdir) {
39698
39871
  try {
39699
- const keepDir = path10.join(cfg.workRoot ?? os6.tmpdir(), "oasis-transcripts");
39700
- fs10.mkdirSync(keepDir, { recursive: true });
39701
- const kept = path10.join(keepDir, `${id}.txt`);
39872
+ const keepDir = path11.join(cfg.workRoot ?? os7.tmpdir(), "oasis-transcripts");
39873
+ fs11.mkdirSync(keepDir, { recursive: true });
39874
+ const kept = path11.join(keepDir, `${id}.txt`);
39702
39875
  const src = transcriptRefPtr.value;
39703
39876
  transcriptOut.end(() => {
39704
39877
  try {
39705
- fs10.renameSync(src, kept);
39706
- fs10.rmSync(dir, { recursive: true, force: true });
39878
+ fs11.renameSync(src, kept);
39879
+ fs11.rmSync(dir, { recursive: true, force: true });
39707
39880
  } catch {
39708
39881
  }
39709
39882
  });
@@ -39725,8 +39898,8 @@ function runStreamJson(job, cfg) {
39725
39898
  env: buildEnv(job, cfg.env),
39726
39899
  stdio: ["ignore", "pipe", "pipe"]
39727
39900
  });
39728
- const transcriptRefPtr = { value: path10.join(dir, "transcript.txt") };
39729
- const transcriptOut = fs10.createWriteStream(transcriptRefPtr.value);
39901
+ const transcriptRefPtr = { value: path11.join(dir, "transcript.txt") };
39902
+ const transcriptOut = fs11.createWriteStream(transcriptRefPtr.value);
39730
39903
  const outputCbs = [];
39731
39904
  const telemetryCbs = [];
39732
39905
  const exitCbs = [];
@@ -39783,8 +39956,8 @@ function runOneShotText(job, cfg) {
39783
39956
  env: buildEnv(job, cfg.env),
39784
39957
  stdio: ["ignore", "pipe", "pipe"]
39785
39958
  });
39786
- const transcriptRefPtr = { value: path10.join(dir, "transcript.txt") };
39787
- const transcriptOut = fs10.createWriteStream(transcriptRefPtr.value);
39959
+ const transcriptRefPtr = { value: path11.join(dir, "transcript.txt") };
39960
+ const transcriptOut = fs11.createWriteStream(transcriptRefPtr.value);
39788
39961
  const outputCbs = [];
39789
39962
  const exitCbs = [];
39790
39963
  const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
@@ -39823,15 +39996,15 @@ function runOneShotText(job, cfg) {
39823
39996
  }
39824
39997
  });
39825
39998
  }
39826
- var import_node_child_process7, import_node_crypto14, fs10, os6, path10, readline4;
39999
+ var import_node_child_process7, import_node_crypto15, fs11, os7, path11, readline4;
39827
40000
  var init_subprocess = __esm({
39828
40001
  "../adapters/src/_core/subprocess.ts"() {
39829
40002
  "use strict";
39830
40003
  import_node_child_process7 = require("node:child_process");
39831
- import_node_crypto14 = require("node:crypto");
39832
- fs10 = __toESM(require("node:fs"), 1);
39833
- os6 = __toESM(require("node:os"), 1);
39834
- path10 = __toESM(require("node:path"), 1);
40004
+ import_node_crypto15 = require("node:crypto");
40005
+ fs11 = __toESM(require("node:fs"), 1);
40006
+ os7 = __toESM(require("node:os"), 1);
40007
+ path11 = __toESM(require("node:path"), 1);
39835
40008
  readline4 = __toESM(require("node:readline"), 1);
39836
40009
  init_claude_code();
39837
40010
  }
@@ -40235,11 +40408,11 @@ function normalizeOpenClaw(line) {
40235
40408
  }
40236
40409
  return [];
40237
40410
  }
40238
- var import_node_crypto15, OpenClawAdapter;
40411
+ var import_node_crypto16, OpenClawAdapter;
40239
40412
  var init_openclaw = __esm({
40240
40413
  "../adapters/src/openclaw/index.ts"() {
40241
40414
  "use strict";
40242
- import_node_crypto15 = require("node:crypto");
40415
+ import_node_crypto16 = require("node:crypto");
40243
40416
  init_subprocess();
40244
40417
  OpenClawAdapter = class {
40245
40418
  constructor(opts = {}) {
@@ -40257,7 +40430,7 @@ var init_openclaw = __esm({
40257
40430
  ---
40258
40431
 
40259
40432
  ${task}` : task;
40260
- const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto15.randomUUID)().slice(0, 8)}`;
40433
+ const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`;
40261
40434
  return [
40262
40435
  "agent",
40263
40436
  ...opts.mode !== "gateway" ? ["--local"] : [],
@@ -40728,7 +40901,7 @@ function nodesDomain(deps) {
40728
40901
  nodeId = incomingNodeId;
40729
40902
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
40730
40903
  } else {
40731
- nodeId = `node-${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`;
40904
+ nodeId = `node-${(0, import_node_crypto17.randomUUID)().slice(0, 8)}`;
40732
40905
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
40733
40906
  }
40734
40907
  const existingNode = await deps.nodeStore.getNode(nodeId);
@@ -40768,6 +40941,23 @@ function nodesDomain(deps) {
40768
40941
  await deps.nodeStore.deleteNode(nodeId);
40769
40942
  return { status: 200, body: { ok: true } };
40770
40943
  });
40944
+ router.get("/api/nodes/expected-daemon-version", async () => {
40945
+ const envVer = (process.env["OASIS_LATEST_NODE_DAEMON_VERSION"] ?? "").trim();
40946
+ if (envVer) return { status: 200, body: { version: envVer, source: "env" } };
40947
+ try {
40948
+ const here = (0, import_node_path2.dirname)((0, import_node_url.fileURLToPath)(__esm_import_meta_url));
40949
+ for (const rel of ["../../../../node-daemon/package.json", "../../../../../node-daemon/package.json"]) {
40950
+ try {
40951
+ const raw = (0, import_node_fs3.readFileSync)((0, import_node_path2.resolve)(here, rel), "utf8");
40952
+ const pkg = JSON.parse(raw);
40953
+ if (pkg.version) return { status: 200, body: { version: pkg.version, source: "monorepo" } };
40954
+ } catch {
40955
+ }
40956
+ }
40957
+ } catch {
40958
+ }
40959
+ return { status: 200, body: { version: null, source: null } };
40960
+ });
40771
40961
  router.post("/api/nodes/:nodeId/update", async (req) => {
40772
40962
  const nodeId = req.params["nodeId"];
40773
40963
  if (!nodeId) return { status: 400, body: { error: "missing nodeId" } };
@@ -40851,11 +41041,14 @@ function nodesDomain(deps) {
40851
41041
  });
40852
41042
  };
40853
41043
  }
40854
- var import_node_crypto16;
41044
+ var import_node_crypto17, import_node_fs3, import_node_url, import_node_path2;
40855
41045
  var init_routes4 = __esm({
40856
41046
  "../server/src/domains/nodes/routes.ts"() {
40857
41047
  "use strict";
40858
- import_node_crypto16 = require("node:crypto");
41048
+ import_node_crypto17 = require("node:crypto");
41049
+ import_node_fs3 = require("node:fs");
41050
+ import_node_url = require("node:url");
41051
+ import_node_path2 = require("node:path");
40859
41052
  init_src4();
40860
41053
  init_connect_script();
40861
41054
  }
@@ -40914,11 +41107,11 @@ var init_types3 = __esm({
40914
41107
  });
40915
41108
 
40916
41109
  // ../server/src/node-store.ts
40917
- var fs11, MemoryNodeStore, FileNodeStore;
41110
+ var fs12, MemoryNodeStore, FileNodeStore;
40918
41111
  var init_node_store = __esm({
40919
41112
  "../server/src/node-store.ts"() {
40920
41113
  "use strict";
40921
- fs11 = __toESM(require("node:fs"), 1);
41114
+ fs12 = __toESM(require("node:fs"), 1);
40922
41115
  MemoryNodeStore = class {
40923
41116
  nodes = /* @__PURE__ */ new Map();
40924
41117
  runtimes = /* @__PURE__ */ new Map();
@@ -41003,16 +41196,16 @@ var init_node_store = __esm({
41003
41196
  static async open(file) {
41004
41197
  const s2 = new _FileNodeStore(file);
41005
41198
  try {
41006
- const snap = JSON.parse(fs11.readFileSync(file, "utf8"));
41199
+ const snap = JSON.parse(fs12.readFileSync(file, "utf8"));
41007
41200
  for (const n of snap.nodes ?? []) s2.nodes.set(n.id, n);
41008
41201
  for (const r of snap.runtimes ?? []) s2.runtimes.set(r.id, r);
41009
41202
  } catch {
41010
- fs11.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
41203
+ fs12.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
41011
41204
  }
41012
41205
  return s2;
41013
41206
  }
41014
41207
  flush() {
41015
- fs11.writeFileSync(this.file, JSON.stringify({
41208
+ fs12.writeFileSync(this.file, JSON.stringify({
41016
41209
  nodes: [...this.nodes.values()],
41017
41210
  runtimes: [...this.runtimes.values()]
41018
41211
  }, null, 2));
@@ -41556,7 +41749,7 @@ var init_collab = __esm({
41556
41749
 
41557
41750
  // ../server/src/domains/collab/create-seeded-workorder.ts
41558
41751
  function makeSeededWorkorderCreator(deps) {
41559
- const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto17.randomUUID)().slice(0, 8)}`);
41752
+ const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto18.randomUUID)().slice(0, 8)}`);
41560
41753
  return async (input) => {
41561
41754
  const workspace = genWorkspace();
41562
41755
  if (input.projectId && deps.artifactState) {
@@ -41593,11 +41786,11 @@ function makeSeededWorkorderCreator(deps) {
41593
41786
  return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
41594
41787
  };
41595
41788
  }
41596
- var import_node_crypto17, enc2;
41789
+ var import_node_crypto18, enc2;
41597
41790
  var init_create_seeded_workorder = __esm({
41598
41791
  "../server/src/domains/collab/create-seeded-workorder.ts"() {
41599
41792
  "use strict";
41600
- import_node_crypto17 = require("node:crypto");
41793
+ import_node_crypto18 = require("node:crypto");
41601
41794
  init_planner();
41602
41795
  enc2 = (s2) => new TextEncoder().encode(s2);
41603
41796
  }
@@ -42623,7 +42816,7 @@ function createChatSessionsDomain(opts) {
42623
42816
  const runtimeId = await currentRuntimeId(body.aiActorId) ?? "unknown";
42624
42817
  const now = (/* @__PURE__ */ new Date()).toISOString();
42625
42818
  const session = {
42626
- id: (0, import_node_crypto18.randomUUID)(),
42819
+ id: (0, import_node_crypto19.randomUUID)(),
42627
42820
  humanActorId: req.auth.actor,
42628
42821
  aiActorId: body.aiActorId,
42629
42822
  runtimeId,
@@ -42674,7 +42867,7 @@ function createChatSessionsDomain(opts) {
42674
42867
  if (!body?.role || !body?.content) throw new ApiError(400, "BAD_REQUEST", "role and content required");
42675
42868
  if (body.role !== "user" && body.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
42676
42869
  const msg = await store.appendMessage({
42677
- id: (0, import_node_crypto18.randomUUID)(),
42870
+ id: (0, import_node_crypto19.randomUUID)(),
42678
42871
  sessionId: req.params.id,
42679
42872
  role: body.role,
42680
42873
  content: body.content,
@@ -42711,11 +42904,11 @@ function createChatSessionsDomain(opts) {
42711
42904
  });
42712
42905
  };
42713
42906
  }
42714
- var import_node_crypto18;
42907
+ var import_node_crypto19;
42715
42908
  var init_chat_sessions = __esm({
42716
42909
  "../server/src/domains/chat-sessions/index.ts"() {
42717
42910
  "use strict";
42718
- import_node_crypto18 = require("node:crypto");
42911
+ import_node_crypto19 = require("node:crypto");
42719
42912
  init_router();
42720
42913
  init_workorders();
42721
42914
  init_chat_parts();
@@ -44081,11 +44274,11 @@ function ackMsFromEnv(fallback) {
44081
44274
  const n = Number(v2);
44082
44275
  return Number.isFinite(n) && n >= 0 ? n : fallback;
44083
44276
  }
44084
- var import_node_crypto19, DaemonHubAdapter, BindingRouterAdapter;
44277
+ var import_node_crypto20, DaemonHubAdapter, BindingRouterAdapter;
44085
44278
  var init_daemon_adapter = __esm({
44086
44279
  "../server/src/daemon-adapter.ts"() {
44087
44280
  "use strict";
44088
- import_node_crypto19 = require("node:crypto");
44281
+ import_node_crypto20 = require("node:crypto");
44089
44282
  DaemonHubAdapter = class {
44090
44283
  constructor(hub, opts = {}) {
44091
44284
  this.hub = hub;
@@ -44172,7 +44365,7 @@ var init_daemon_adapter = __esm({
44172
44365
  async spawn(job) {
44173
44366
  const nodeId = job.binding?.nodeId;
44174
44367
  if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
44175
- const dispatchId = `dispatch:${(0, import_node_crypto19.randomUUID)()}`;
44368
+ const dispatchId = `dispatch:${(0, import_node_crypto20.randomUUID)()}`;
44176
44369
  const entry = {
44177
44370
  nodeId,
44178
44371
  exitCbs: [],
@@ -44270,17 +44463,17 @@ var init_daemon_adapter = __esm({
44270
44463
  });
44271
44464
 
44272
44465
  // ../server/src/side-map.ts
44273
- var import_node_fs3, import_node_path2, FileSideMap;
44466
+ var import_node_fs4, import_node_path3, FileSideMap;
44274
44467
  var init_side_map = __esm({
44275
44468
  "../server/src/side-map.ts"() {
44276
44469
  "use strict";
44277
- import_node_fs3 = __toESM(require("node:fs"), 1);
44278
- import_node_path2 = __toESM(require("node:path"), 1);
44470
+ import_node_fs4 = __toESM(require("node:fs"), 1);
44471
+ import_node_path3 = __toESM(require("node:path"), 1);
44279
44472
  FileSideMap = class {
44280
44473
  constructor(file) {
44281
44474
  this.file = file;
44282
44475
  try {
44283
- const raw = JSON.parse(import_node_fs3.default.readFileSync(file, "utf8"));
44476
+ const raw = JSON.parse(import_node_fs4.default.readFileSync(file, "utf8"));
44284
44477
  for (const [k2, v2] of Object.entries(raw)) if (typeof v2 === "string") this.map.set(k2, v2);
44285
44478
  } catch {
44286
44479
  }
@@ -44298,10 +44491,10 @@ var init_side_map = __esm({
44298
44491
  }
44299
44492
  persist() {
44300
44493
  try {
44301
- import_node_fs3.default.mkdirSync(import_node_path2.default.dirname(this.file), { recursive: true });
44494
+ import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(this.file), { recursive: true });
44302
44495
  const tmp = `${this.file}.tmp`;
44303
- import_node_fs3.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
44304
- import_node_fs3.default.renameSync(tmp, this.file);
44496
+ import_node_fs4.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
44497
+ import_node_fs4.default.renameSync(tmp, this.file);
44305
44498
  } catch {
44306
44499
  }
44307
44500
  }
@@ -44316,13 +44509,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
44316
44509
  if (sha(body) === lastPushedHash) return { kind: "echo" };
44317
44510
  return { kind: "human-edit", content: body, updatedBy: page.updatedBy };
44318
44511
  }
44319
- var import_node_crypto20, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
44512
+ var import_node_crypto21, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
44320
44513
  var init_engine = __esm({
44321
44514
  "../server/src/mirror/engine.ts"() {
44322
44515
  "use strict";
44323
- import_node_crypto20 = require("node:crypto");
44516
+ import_node_crypto21 = require("node:crypto");
44324
44517
  init_src();
44325
- sha = (s2) => (0, import_node_crypto20.createHash)("sha256").update(s2, "utf8").digest("hex");
44518
+ sha = (s2) => (0, import_node_crypto21.createHash)("sha256").update(s2, "utf8").digest("hex");
44326
44519
  enc3 = (s2) => new TextEncoder().encode(s2);
44327
44520
  dec = (b2) => new TextDecoder().decode(b2);
44328
44521
  MirrorEngine = class {
@@ -44435,22 +44628,22 @@ var init_engine = __esm({
44435
44628
  });
44436
44629
 
44437
44630
  // ../server/src/mirror/fs-state.ts
44438
- var fs13, FsMirrorStateStore;
44631
+ var fs14, FsMirrorStateStore;
44439
44632
  var init_fs_state = __esm({
44440
44633
  "../server/src/mirror/fs-state.ts"() {
44441
44634
  "use strict";
44442
- fs13 = __toESM(require("node:fs"), 1);
44635
+ fs14 = __toESM(require("node:fs"), 1);
44443
44636
  FsMirrorStateStore = class {
44444
44637
  constructor(file) {
44445
44638
  this.file = file;
44446
- if (fs13.existsSync(file)) {
44447
- const obj = JSON.parse(fs13.readFileSync(file, "utf8"));
44639
+ if (fs14.existsSync(file)) {
44640
+ const obj = JSON.parse(fs14.readFileSync(file, "utf8"));
44448
44641
  for (const [k2, v2] of Object.entries(obj)) this.map.set(k2, v2);
44449
44642
  }
44450
44643
  }
44451
44644
  map = /* @__PURE__ */ new Map();
44452
44645
  flush() {
44453
- fs13.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
44646
+ fs14.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
44454
44647
  }
44455
44648
  async get(artifactId) {
44456
44649
  return this.map.get(artifactId) ?? null;
@@ -44467,13 +44660,13 @@ var init_fs_state = __esm({
44467
44660
  });
44468
44661
 
44469
44662
  // ../server/src/git/integrate.ts
44470
- var import_node_child_process8, fs14, path12, GitRemoteIntegrator;
44663
+ var import_node_child_process8, fs15, path13, GitRemoteIntegrator;
44471
44664
  var init_integrate = __esm({
44472
44665
  "../server/src/git/integrate.ts"() {
44473
44666
  "use strict";
44474
44667
  import_node_child_process8 = require("node:child_process");
44475
- fs14 = __toESM(require("node:fs"), 1);
44476
- path12 = __toESM(require("node:path"), 1);
44668
+ fs15 = __toESM(require("node:fs"), 1);
44669
+ path13 = __toESM(require("node:path"), 1);
44477
44670
  GitRemoteIntegrator = class {
44478
44671
  constructor(remote, cloneDir, develop = "develop") {
44479
44672
  this.remote = remote;
@@ -44490,8 +44683,8 @@ var init_integrate = __esm({
44490
44683
  }
44491
44684
  /** 确保本地工作克隆存在并拉到最新远程态。幂等。 */
44492
44685
  sync() {
44493
- if (!fs14.existsSync(path12.join(this.cloneDir, ".git"))) {
44494
- fs14.mkdirSync(path12.dirname(this.cloneDir), { recursive: true });
44686
+ if (!fs15.existsSync(path13.join(this.cloneDir, ".git"))) {
44687
+ fs15.mkdirSync(path13.dirname(this.cloneDir), { recursive: true });
44495
44688
  (0, import_node_child_process8.execFileSync)("git", ["clone", "--quiet", this.remote, this.cloneDir], { env: this.env, maxBuffer: 256 * 1024 * 1024 });
44496
44689
  this.git(["config", "user.email", "oasis@local"]);
44497
44690
  this.git(["config", "user.name", "oasis"]);
@@ -44542,12 +44735,12 @@ var init_integrate = __esm({
44542
44735
  });
44543
44736
 
44544
44737
  // ../server/src/git/sync.ts
44545
- var os7, path13, slug3, GitSyncWorker;
44738
+ var os8, path14, slug3, GitSyncWorker;
44546
44739
  var init_sync = __esm({
44547
44740
  "../server/src/git/sync.ts"() {
44548
44741
  "use strict";
44549
- os7 = __toESM(require("node:os"), 1);
44550
- path13 = __toESM(require("node:path"), 1);
44742
+ os8 = __toESM(require("node:os"), 1);
44743
+ path14 = __toESM(require("node:path"), 1);
44551
44744
  init_src2();
44552
44745
  init_integrate();
44553
44746
  init_collect();
@@ -44563,8 +44756,8 @@ var init_sync = __esm({
44563
44756
  const key = repo.remote;
44564
44757
  let g2 = this.integrators.get(key);
44565
44758
  if (!g2) {
44566
- const root = this.deps.mirrorRoot ?? path13.join(os7.tmpdir(), "oasis-git-mirrors");
44567
- const cloneDir = repo.repoDir ?? path13.join(root, slug3(repo.id));
44759
+ const root = this.deps.mirrorRoot ?? path14.join(os8.tmpdir(), "oasis-git-mirrors");
44760
+ const cloneDir = repo.repoDir ?? path14.join(root, slug3(repo.id));
44568
44761
  g2 = new GitRemoteIntegrator(repo.remote, cloneDir, repo.develop);
44569
44762
  this.integrators.set(key, g2);
44570
44763
  }
@@ -44605,13 +44798,13 @@ var init_sync = __esm({
44605
44798
  });
44606
44799
 
44607
44800
  // ../server/src/git/ci-provider.ts
44608
- var import_node_child_process9, fs15, path14, import_node_util, execFile, slug4, GhCiProvider;
44801
+ var import_node_child_process9, fs16, path15, import_node_util, execFile, slug4, GhCiProvider;
44609
44802
  var init_ci_provider = __esm({
44610
44803
  "../server/src/git/ci-provider.ts"() {
44611
44804
  "use strict";
44612
44805
  import_node_child_process9 = require("node:child_process");
44613
- fs15 = __toESM(require("node:fs"), 1);
44614
- path14 = __toESM(require("node:path"), 1);
44806
+ fs16 = __toESM(require("node:fs"), 1);
44807
+ path15 = __toESM(require("node:path"), 1);
44615
44808
  import_node_util = require("node:util");
44616
44809
  execFile = (0, import_node_util.promisify)(import_node_child_process9.execFile);
44617
44810
  slug4 = (id) => id.replace(/[^a-zA-Z0-9_-]+/g, "_");
@@ -44625,9 +44818,9 @@ var init_ci_provider = __esm({
44625
44818
  /** 缺则 clone(首次使用/进程重启后本地镜像不存在)——否则 git fetch 会"not a git repo"报错。同 GitRemoteIntegrator。 */
44626
44819
  ensureClone(repo) {
44627
44820
  const dir = this.repoDir(repo);
44628
- if (fs15.existsSync(path14.join(dir, ".git"))) return;
44821
+ if (fs16.existsSync(path15.join(dir, ".git"))) return;
44629
44822
  if (!repo.remote) throw new Error(`repo ${repo.id} \u65E0 remote\uFF0C\u65E0\u6CD5 clone`);
44630
- fs15.mkdirSync(path14.dirname(dir), { recursive: true });
44823
+ fs16.mkdirSync(path15.dirname(dir), { recursive: true });
44631
44824
  (0, import_node_child_process9.execFileSync)("git", ["clone", "--quiet", repo.remote, dir], { env: process.env });
44632
44825
  this.opts.log?.(`[ci] cloned ${repo.id} \u2192 ${dir}`);
44633
44826
  }
@@ -44890,11 +45083,11 @@ var init_resolve = __esm({
44890
45083
  });
44891
45084
 
44892
45085
  // ../server/src/coordinator/worker.ts
44893
- var import_node_crypto21, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_MANAGER_BODY, CoordinatorWorker;
45086
+ var import_node_crypto22, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_MANAGER_BODY, CoordinatorWorker;
44894
45087
  var init_worker = __esm({
44895
45088
  "../server/src/coordinator/worker.ts"() {
44896
45089
  "use strict";
44897
- import_node_crypto21 = require("node:crypto");
45090
+ import_node_crypto22 = require("node:crypto");
44898
45091
  init_src2();
44899
45092
  init_identity();
44900
45093
  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
@@ -45070,7 +45263,7 @@ ${SHARED_GRAPH_BODY}`;
45070
45263
  return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
45071
45264
  }
45072
45265
  evaluationKey(kind, artifactId, evidence) {
45073
- const fingerprint = (0, import_node_crypto21.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
45266
+ const fingerprint = (0, import_node_crypto22.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
45074
45267
  return `${kind}:${artifactId}:${fingerprint}`;
45075
45268
  }
45076
45269
  artifactEvidence(id) {
@@ -45310,7 +45503,7 @@ ${SHARED_GRAPH_BODY}`;
45310
45503
  const token = this.deps.tokenFor(actorId, ctx);
45311
45504
  const serverUrl = this.deps.serverUrlFor ? await this.deps.serverUrlFor(ctx) : this.deps.serverUrl;
45312
45505
  const workspace = this.deps.kernel.model.artifacts.get(artifactId)?.workspace;
45313
- const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto21.randomUUID)();
45506
+ const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto22.randomUUID)();
45314
45507
  const job = {
45315
45508
  actor: actorId,
45316
45509
  actorToken: token,
@@ -45382,7 +45575,7 @@ ${SHARED_GRAPH_BODY}`;
45382
45575
  async function collectDir(root, dir, out) {
45383
45576
  const entries = await (0, import_promises.readdir)(dir, { withFileTypes: true });
45384
45577
  for (const e of entries) {
45385
- const abs = (0, import_node_path3.join)(dir, e.name);
45578
+ const abs = (0, import_node_path4.join)(dir, e.name);
45386
45579
  if (e.isDirectory()) {
45387
45580
  await collectDir(root, abs, out);
45388
45581
  } else if (e.isFile()) {
@@ -45391,7 +45584,7 @@ async function collectDir(root, dir, out) {
45391
45584
  console.warn(`[builtin-skills] skip oversized file (${info.size}B): ${abs}`);
45392
45585
  continue;
45393
45586
  }
45394
- const rel = (0, import_node_path3.relative)(root, abs).split(/[\\/]/).join("/");
45587
+ const rel = (0, import_node_path4.relative)(root, abs).split(/[\\/]/).join("/");
45395
45588
  out[rel] = await (0, import_promises.readFile)(abs, "utf8");
45396
45589
  }
45397
45590
  }
@@ -45407,7 +45600,7 @@ async function loadBuiltinSkills(skillsDir) {
45407
45600
  for (const d of dirents) {
45408
45601
  if (!d.isDirectory()) continue;
45409
45602
  const slug6 = d.name;
45410
- const skillDir = (0, import_node_path3.join)(skillsDir, slug6);
45603
+ const skillDir = (0, import_node_path4.join)(skillsDir, slug6);
45411
45604
  const files = {};
45412
45605
  try {
45413
45606
  await collectDir(skillDir, skillDir, files);
@@ -45439,12 +45632,12 @@ function sanitize(name) {
45439
45632
  const s2 = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
45440
45633
  return s2 || "skill";
45441
45634
  }
45442
- var import_promises, import_node_path3, MAX_FILE_BYTES2;
45635
+ var import_promises, import_node_path4, MAX_FILE_BYTES2;
45443
45636
  var init_builtin_skills = __esm({
45444
45637
  "../server/src/governance/builtin-skills.ts"() {
45445
45638
  "use strict";
45446
45639
  import_promises = require("node:fs/promises");
45447
- import_node_path3 = require("node:path");
45640
+ import_node_path4 = require("node:path");
45448
45641
  init_skill_fetcher();
45449
45642
  MAX_FILE_BYTES2 = 1 << 20;
45450
45643
  }
@@ -47099,15 +47292,15 @@ var require_pg_connection_string = __commonJS({
47099
47292
  if (config2.sslcert || config2.sslkey || config2.sslrootcert || config2.sslmode) {
47100
47293
  config2.ssl = {};
47101
47294
  }
47102
- const fs20 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
47295
+ const fs21 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
47103
47296
  if (config2.sslcert) {
47104
- config2.ssl.cert = fs20.readFileSync(config2.sslcert).toString();
47297
+ config2.ssl.cert = fs21.readFileSync(config2.sslcert).toString();
47105
47298
  }
47106
47299
  if (config2.sslkey) {
47107
- config2.ssl.key = fs20.readFileSync(config2.sslkey).toString();
47300
+ config2.ssl.key = fs21.readFileSync(config2.sslkey).toString();
47108
47301
  }
47109
47302
  if (config2.sslrootcert) {
47110
- config2.ssl.ca = fs20.readFileSync(config2.sslrootcert).toString();
47303
+ config2.ssl.ca = fs21.readFileSync(config2.sslrootcert).toString();
47111
47304
  }
47112
47305
  if (options.useLibpqCompat && config2.uselibpqcompat) {
47113
47306
  throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
@@ -48872,7 +49065,7 @@ var require_split2 = __commonJS({
48872
49065
  var require_helper = __commonJS({
48873
49066
  "../../node_modules/.pnpm/pgpass@1.0.5/node_modules/pgpass/lib/helper.js"(exports2, module2) {
48874
49067
  "use strict";
48875
- var path19 = require("path");
49068
+ var path20 = require("path");
48876
49069
  var Stream = require("stream").Stream;
48877
49070
  var split = require_split2();
48878
49071
  var util2 = require("util");
@@ -48911,7 +49104,7 @@ var require_helper = __commonJS({
48911
49104
  };
48912
49105
  module2.exports.getFileName = function(rawEnv) {
48913
49106
  var env = rawEnv || process.env;
48914
- var file = env.PGPASSFILE || (isWin ? path19.join(env.APPDATA || "./", "postgresql", "pgpass.conf") : path19.join(env.HOME || "./", ".pgpass"));
49107
+ var file = env.PGPASSFILE || (isWin ? path20.join(env.APPDATA || "./", "postgresql", "pgpass.conf") : path20.join(env.HOME || "./", ".pgpass"));
48915
49108
  return file;
48916
49109
  };
48917
49110
  module2.exports.usePgPass = function(stats, fname) {
@@ -49043,16 +49236,16 @@ var require_helper = __commonJS({
49043
49236
  var require_lib = __commonJS({
49044
49237
  "../../node_modules/.pnpm/pgpass@1.0.5/node_modules/pgpass/lib/index.js"(exports2, module2) {
49045
49238
  "use strict";
49046
- var path19 = require("path");
49047
- var fs20 = require("fs");
49239
+ var path20 = require("path");
49240
+ var fs21 = require("fs");
49048
49241
  var helper = require_helper();
49049
49242
  module2.exports = function(connInfo, cb) {
49050
49243
  var file = helper.getFileName();
49051
- fs20.stat(file, function(err, stat3) {
49244
+ fs21.stat(file, function(err, stat3) {
49052
49245
  if (err || !helper.usePgPass(stat3, file)) {
49053
49246
  return cb(void 0);
49054
49247
  }
49055
- var st = fs20.createReadStream(file);
49248
+ var st = fs21.createReadStream(file);
49056
49249
  helper.getPassword(connInfo, st, cb);
49057
49250
  });
49058
49251
  };
@@ -50605,38 +50798,38 @@ __export(trajectory_exports, {
50605
50798
  exportTrajectories: () => exportTrajectories
50606
50799
  });
50607
50800
  async function exportTrajectories(dataDir) {
50608
- const root = path15.join(dataDir, "trajectories");
50609
- if (!fs16.existsSync(root)) return [];
50801
+ const root = path16.join(dataDir, "trajectories");
50802
+ if (!fs17.existsSync(root)) return [];
50610
50803
  const model = emptyReadModel();
50611
- const oplogFile = path15.join(dataDir, "oplog.ndjson");
50612
- if (fs16.existsSync(oplogFile)) {
50804
+ const oplogFile = path16.join(dataDir, "oplog.ndjson");
50805
+ if (fs17.existsSync(oplogFile)) {
50613
50806
  const oplog = await NdjsonOplogStore.open(oplogFile);
50614
50807
  for await (const entry of oplog.readAll()) fold(model, entry.op);
50615
50808
  }
50616
50809
  const samples = [];
50617
- for (const sessionId of fs16.readdirSync(root).sort()) {
50618
- const dir = path15.join(root, sessionId);
50619
- const sessionFile = path15.join(dir, "session.json");
50620
- if (!fs16.existsSync(sessionFile)) continue;
50621
- const session = JSON.parse(fs16.readFileSync(sessionFile, "utf8"));
50810
+ for (const sessionId of fs17.readdirSync(root).sort()) {
50811
+ const dir = path16.join(root, sessionId);
50812
+ const sessionFile = path16.join(dir, "session.json");
50813
+ if (!fs17.existsSync(sessionFile)) continue;
50814
+ const session = JSON.parse(fs17.readFileSync(sessionFile, "utf8"));
50622
50815
  const events = [];
50623
- const eventsFile = path15.join(dir, "events.ndjson");
50624
- if (fs16.existsSync(eventsFile)) {
50625
- for (const line of fs16.readFileSync(eventsFile, "utf8").split("\n")) {
50816
+ const eventsFile = path16.join(dir, "events.ndjson");
50817
+ if (fs17.existsSync(eventsFile)) {
50818
+ for (const line of fs17.readFileSync(eventsFile, "utf8").split("\n")) {
50626
50819
  if (line.trim()) events.push(JSON.parse(line));
50627
50820
  }
50628
50821
  }
50629
50822
  const bundle = {};
50630
- const bundleDir = path15.join(dir, "bundle");
50823
+ const bundleDir = path16.join(dir, "bundle");
50631
50824
  const walk = (sub) => {
50632
- for (const name of fs16.readdirSync(path15.join(bundleDir, sub))) {
50825
+ for (const name of fs17.readdirSync(path16.join(bundleDir, sub))) {
50633
50826
  const rel = sub ? `${sub}/${name}` : name;
50634
- const full = path15.join(bundleDir, rel);
50635
- if (fs16.statSync(full).isDirectory()) walk(rel);
50636
- else bundle[rel] = fs16.readFileSync(full, "utf8");
50827
+ const full = path16.join(bundleDir, rel);
50828
+ if (fs17.statSync(full).isDirectory()) walk(rel);
50829
+ else bundle[rel] = fs17.readFileSync(full, "utf8");
50637
50830
  }
50638
50831
  };
50639
- if (fs16.existsSync(bundleDir)) walk("");
50832
+ if (fs17.existsSync(bundleDir)) walk("");
50640
50833
  const proposed = (session.opRefs ?? []).filter((r) => r.kind === "propose_revision").map((r) => r.target);
50641
50834
  const verdicts = proposed.flatMap(
50642
50835
  (rev) => (model.reviews.get(rev) ?? []).map((v2) => ({ author: v2.author, verdict: v2.verdict, ...v2.note !== void 0 ? { note: v2.note } : {} }))
@@ -50648,51 +50841,51 @@ async function exportTrajectories(dataDir) {
50648
50841
  }
50649
50842
  return samples;
50650
50843
  }
50651
- var fs16, path15, FsTrajectorySink;
50844
+ var fs17, path16, FsTrajectorySink;
50652
50845
  var init_trajectory = __esm({
50653
50846
  "../cli/src/trajectory.ts"() {
50654
50847
  "use strict";
50655
- fs16 = __toESM(require("node:fs"), 1);
50656
- path15 = __toESM(require("node:path"), 1);
50848
+ fs17 = __toESM(require("node:fs"), 1);
50849
+ path16 = __toESM(require("node:path"), 1);
50657
50850
  init_src2();
50658
50851
  init_src5();
50659
50852
  FsTrajectorySink = class {
50660
50853
  constructor(dataDir, broadcast) {
50661
50854
  this.broadcast = broadcast;
50662
- this.root = path15.join(dataDir, "trajectories");
50855
+ this.root = path16.join(dataDir, "trajectories");
50663
50856
  }
50664
50857
  root;
50665
50858
  dir(sessionId) {
50666
- return path15.join(this.root, sessionId);
50859
+ return path16.join(this.root, sessionId);
50667
50860
  }
50668
50861
  begin(session, bundleFiles) {
50669
50862
  const dir = this.dir(session.sessionId);
50670
- fs16.mkdirSync(path15.join(dir, "bundle"), { recursive: true });
50671
- fs16.writeFileSync(path15.join(dir, "session.json"), JSON.stringify(session, null, 2));
50863
+ fs17.mkdirSync(path16.join(dir, "bundle"), { recursive: true });
50864
+ fs17.writeFileSync(path16.join(dir, "session.json"), JSON.stringify(session, null, 2));
50672
50865
  for (const [rel, content] of Object.entries(bundleFiles)) {
50673
- const file = path15.join(dir, "bundle", rel);
50674
- fs16.mkdirSync(path15.dirname(file), { recursive: true });
50675
- fs16.writeFileSync(file, content);
50866
+ const file = path16.join(dir, "bundle", rel);
50867
+ fs17.mkdirSync(path16.dirname(file), { recursive: true });
50868
+ fs17.writeFileSync(file, content);
50676
50869
  }
50677
50870
  this.broadcast?.({ type: "begin", sessionId: session.sessionId, data: session });
50678
50871
  }
50679
50872
  recover(session) {
50680
- fs16.mkdirSync(this.dir(session.sessionId), { recursive: true });
50681
- const file = path15.join(this.dir(session.sessionId), "session.json");
50682
- if (!fs16.existsSync(file)) fs16.writeFileSync(file, JSON.stringify(session, null, 2));
50873
+ fs17.mkdirSync(this.dir(session.sessionId), { recursive: true });
50874
+ const file = path16.join(this.dir(session.sessionId), "session.json");
50875
+ if (!fs17.existsSync(file)) fs17.writeFileSync(file, JSON.stringify(session, null, 2));
50683
50876
  this.broadcast?.({ type: "begin", sessionId: session.sessionId, data: { ...session, recovered: true } });
50684
50877
  }
50685
50878
  event(sessionId, event) {
50686
- fs16.mkdirSync(this.dir(sessionId), { recursive: true });
50687
- fs16.appendFileSync(path15.join(this.dir(sessionId), "events.ndjson"), JSON.stringify(event) + "\n");
50879
+ fs17.mkdirSync(this.dir(sessionId), { recursive: true });
50880
+ fs17.appendFileSync(path16.join(this.dir(sessionId), "events.ndjson"), JSON.stringify(event) + "\n");
50688
50881
  this.broadcast?.({ type: "event", sessionId, data: event });
50689
50882
  }
50690
50883
  end(sessionId, update) {
50691
- const file = path15.join(this.dir(sessionId), "session.json");
50692
- const session = JSON.parse(fs16.readFileSync(file, "utf8"));
50884
+ const file = path16.join(this.dir(sessionId), "session.json");
50885
+ const session = JSON.parse(fs17.readFileSync(file, "utf8"));
50693
50886
  session.exit = update.exit;
50694
50887
  session.opRefs = update.opRefs;
50695
- fs16.writeFileSync(file, JSON.stringify(session, null, 2));
50888
+ fs17.writeFileSync(file, JSON.stringify(session, null, 2));
50696
50889
  this.broadcast?.({ type: "end", sessionId, data: session });
50697
50890
  }
50698
50891
  };
@@ -50700,30 +50893,30 @@ var init_trajectory = __esm({
50700
50893
  });
50701
50894
 
50702
50895
  // src/index.ts
50703
- var fs19 = __toESM(require("node:fs"));
50704
- var os10 = __toESM(require("node:os"));
50705
- var path18 = __toESM(require("node:path"));
50896
+ var fs20 = __toESM(require("node:fs"));
50897
+ var os11 = __toESM(require("node:os"));
50898
+ var path19 = __toESM(require("node:path"));
50706
50899
  var import_node_child_process15 = require("node:child_process");
50707
50900
 
50708
50901
  // ../cli/src/cli.ts
50902
+ var fs19 = __toESM(require("node:fs"), 1);
50903
+ var os10 = __toESM(require("node:os"), 1);
50904
+ var path18 = __toESM(require("node:path"), 1);
50905
+ var import_node_crypto27 = require("node:crypto");
50906
+
50907
+ // ../cli/src/serve.ts
50709
50908
  var fs18 = __toESM(require("node:fs"), 1);
50710
50909
  var os9 = __toESM(require("node:os"), 1);
50711
50910
  var path17 = __toESM(require("node:path"), 1);
50712
- var import_node_crypto26 = require("node:crypto");
50713
-
50714
- // ../cli/src/serve.ts
50715
- var fs17 = __toESM(require("node:fs"), 1);
50716
- var os8 = __toESM(require("node:os"), 1);
50717
- var path16 = __toESM(require("node:path"), 1);
50718
- var import_node_crypto24 = require("node:crypto");
50719
- var import_node_url3 = require("node:url");
50911
+ var import_node_crypto25 = require("node:crypto");
50912
+ var import_node_url4 = require("node:url");
50720
50913
  init_src2();
50721
50914
  init_src5();
50722
50915
 
50723
50916
  // ../connectors/src/_base/stage.ts
50724
- var import_node_fs4 = require("node:fs");
50917
+ var import_node_fs5 = require("node:fs");
50725
50918
  var import_node_os2 = require("node:os");
50726
- var import_node_path4 = require("node:path");
50919
+ var import_node_path5 = require("node:path");
50727
50920
  var stagedBinDirs = /* @__PURE__ */ new Map();
50728
50921
  function stageConnectorWrapper(connector) {
50729
50922
  const scriptPath = connector.wrapperScriptPath();
@@ -50734,10 +50927,10 @@ function stageConnectorWrapper(connector) {
50734
50927
  }
50735
50928
  const cacheKey = `${commandName}\0${scriptPath}`;
50736
50929
  const cached2 = stagedBinDirs.get(cacheKey);
50737
- if (cached2 && (0, import_node_fs4.existsSync)((0, import_node_path4.join)(cached2, commandName))) return (0, import_node_path4.join)(cached2, commandName);
50738
- const binDir = (0, import_node_fs4.mkdtempSync)((0, import_node_path4.join)((0, import_node_os2.tmpdir)(), `oasis-conn-${connector.config.slug}-`));
50739
- const link = (0, import_node_path4.join)(binDir, commandName);
50740
- (0, import_node_fs4.symlinkSync)(scriptPath, link);
50930
+ if (cached2 && (0, import_node_fs5.existsSync)((0, import_node_path5.join)(cached2, commandName))) return (0, import_node_path5.join)(cached2, commandName);
50931
+ const binDir = (0, import_node_fs5.mkdtempSync)((0, import_node_path5.join)((0, import_node_os2.tmpdir)(), `oasis-conn-${connector.config.slug}-`));
50932
+ const link = (0, import_node_path5.join)(binDir, commandName);
50933
+ (0, import_node_fs5.symlinkSync)(scriptPath, link);
50741
50934
  stagedBinDirs.set(cacheKey, binDir);
50742
50935
  return link;
50743
50936
  }
@@ -50831,7 +51024,7 @@ async function ensureConnectorTools(tools, deps = {}) {
50831
51024
  // ../connectors/src/_base/cli-connector.ts
50832
51025
  var import_node_child_process11 = require("node:child_process");
50833
51026
  var import_node_util3 = require("node:util");
50834
- var import_node_path5 = require("node:path");
51027
+ var import_node_path6 = require("node:path");
50835
51028
  var execFile3 = (0, import_node_util3.promisify)(import_node_child_process11.execFile);
50836
51029
  var CliConnector = class {
50837
51030
  constructor(wrapperDir) {
@@ -50843,7 +51036,7 @@ var CliConnector = class {
50843
51036
  * The wrapper is a bash script that shadows the real CLI on PATH.
50844
51037
  */
50845
51038
  wrapperScriptPath() {
50846
- return (0, import_node_path5.join)(this.wrapperDir, "wrapper.sh");
51039
+ return (0, import_node_path6.join)(this.wrapperDir, "wrapper.sh");
50847
51040
  }
50848
51041
  /**
50849
51042
  * Resolve the absolute path to a CLI binary using `which`.
@@ -50878,15 +51071,15 @@ var CliConnector = class {
50878
51071
  // ../connectors/src/feishu/index.ts
50879
51072
  var import_node_child_process12 = require("node:child_process");
50880
51073
  var import_node_util4 = require("node:util");
50881
- var import_node_path6 = require("node:path");
50882
- var import_node_url = require("node:url");
51074
+ var import_node_path7 = require("node:path");
51075
+ var import_node_url2 = require("node:url");
50883
51076
  var import_promises2 = require("node:fs/promises");
50884
51077
  var import_node_os3 = require("node:os");
50885
51078
  function shSingleQuote(v2) {
50886
51079
  return `'${v2.replace(/'/g, `'\\''`)}'`;
50887
51080
  }
50888
51081
  var execFileAsync2 = (0, import_node_util4.promisify)(import_node_child_process12.execFile);
50889
- var __dirname = (0, import_node_path6.dirname)((0, import_node_url.fileURLToPath)(__esm_import_meta_url));
51082
+ var __dirname = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(__esm_import_meta_url));
50890
51083
  var FeishuConnector = class extends CliConnector {
50891
51084
  config = {
50892
51085
  slug: "feishu",
@@ -50926,8 +51119,8 @@ var FeishuConnector = class extends CliConnector {
50926
51119
  if (!appId) throw new Error("feishu inject: missing app_id");
50927
51120
  if (!appSecret) throw new Error("feishu inject: missing app_secret");
50928
51121
  const userAccessToken = credentials["user_access_token"] ?? credentials["FEISHU_USER_ACCESS_TOKEN"];
50929
- const dir = await (0, import_promises2.mkdtemp)((0, import_node_path6.join)((0, import_node_os3.tmpdir)(), "oasis-feishu-"));
50930
- const credsFile = (0, import_node_path6.join)(dir, "creds.env");
51122
+ const dir = await (0, import_promises2.mkdtemp)((0, import_node_path7.join)((0, import_node_os3.tmpdir)(), "oasis-feishu-"));
51123
+ const credsFile = (0, import_node_path7.join)(dir, "creds.env");
50931
51124
  const lines = [
50932
51125
  `export LARKSUITE_CLI_APP_ID=${shSingleQuote(appId)}`,
50933
51126
  `export LARKSUITE_CLI_APP_SECRET=${shSingleQuote(appSecret)}`
@@ -50982,11 +51175,11 @@ var FeishuConnector = class extends CliConnector {
50982
51175
  };
50983
51176
 
50984
51177
  // ../connectors/src/github/index.ts
50985
- var import_node_path7 = require("node:path");
50986
- var import_node_url2 = require("node:url");
51178
+ var import_node_path8 = require("node:path");
51179
+ var import_node_url3 = require("node:url");
50987
51180
  var import_promises3 = require("node:fs/promises");
50988
51181
  var import_node_os4 = require("node:os");
50989
- var __dirname2 = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(__esm_import_meta_url));
51182
+ var __dirname2 = (0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(__esm_import_meta_url));
50990
51183
  function shSingleQuote2(v2) {
50991
51184
  return `'${v2.replace(/'/g, `'\\''`)}'`;
50992
51185
  }
@@ -51024,8 +51217,8 @@ var GithubConnector = class extends CliConnector {
51024
51217
  const token = credentials["access_token"];
51025
51218
  if (!token) throw new Error("github inject: missing access_token");
51026
51219
  const name = credentials["actor_name"] ?? "oasis-agent";
51027
- const dir = await (0, import_promises3.mkdtemp)((0, import_node_path7.join)((0, import_node_os4.tmpdir)(), "oasis-github-"));
51028
- const credsFile = (0, import_node_path7.join)(dir, "creds.env");
51220
+ const dir = await (0, import_promises3.mkdtemp)((0, import_node_path8.join)((0, import_node_os4.tmpdir)(), "oasis-github-"));
51221
+ const credsFile = (0, import_node_path8.join)(dir, "creds.env");
51029
51222
  await (0, import_promises3.writeFile)(
51030
51223
  credsFile,
51031
51224
  `export GH_TOKEN=${shSingleQuote2(token)}
@@ -51065,7 +51258,7 @@ export GITHUB_TOKEN=${shSingleQuote2(token)}
51065
51258
  // ../connectors/src/connector-adapter.ts
51066
51259
  var import_promises4 = require("node:fs/promises");
51067
51260
  var import_node_os5 = require("node:os");
51068
- var import_node_path8 = require("node:path");
51261
+ var import_node_path9 = require("node:path");
51069
51262
  init_src4();
51070
51263
 
51071
51264
  // ../connectors/src/logger.ts
@@ -51095,11 +51288,11 @@ var ConnectorAwareAdapter = class {
51095
51288
  );
51096
51289
  let extraEnv = { ...strippedEnv };
51097
51290
  if (wrapperPaths.length > 0) {
51098
- const wrapperBinDir = await (0, import_promises4.mkdtemp)((0, import_node_path8.join)((0, import_node_os5.tmpdir)(), "oasis-wrappers-"));
51291
+ const wrapperBinDir = await (0, import_promises4.mkdtemp)((0, import_node_path9.join)((0, import_node_os5.tmpdir)(), "oasis-wrappers-"));
51099
51292
  await (0, import_promises4.mkdir)(wrapperBinDir, { recursive: true });
51100
51293
  for (const wp of wrapperPaths) {
51101
- const linkName = (0, import_node_path8.basename)(wp).replace(/\.sh$/, "");
51102
- await (0, import_promises4.symlink)(wp, (0, import_node_path8.join)(wrapperBinDir, linkName));
51294
+ const linkName = (0, import_node_path9.basename)(wp).replace(/\.sh$/, "");
51295
+ await (0, import_promises4.symlink)(wp, (0, import_node_path9.join)(wrapperBinDir, linkName));
51103
51296
  }
51104
51297
  extraEnv = { ...extraEnv, PATH: `${wrapperBinDir}:${process.env["PATH"] ?? ""}` };
51105
51298
  log("[adapter]", ` connectors injected +${Date.now() - t0}ms wrappers=${wrapperPaths.length} env_keys=${Object.keys(job.env ?? {}).join(",")}`);
@@ -51632,7 +51825,7 @@ function defaultDocumentPath2(input) {
51632
51825
  init_src4();
51633
51826
 
51634
51827
  // ../storage/src/postgres.ts
51635
- var import_node_crypto22 = require("node:crypto");
51828
+ var import_node_crypto23 = require("node:crypto");
51636
51829
 
51637
51830
  // ../../node_modules/.pnpm/pg@8.21.0/node_modules/pg/esm/index.mjs
51638
51831
  var import_lib = __toESM(require_lib2(), 1);
@@ -51767,7 +51960,7 @@ var PostgresBlobStore = class _PostgresBlobStore {
51767
51960
  return new _PostgresBlobStore(pool, schema);
51768
51961
  }
51769
51962
  async put(bytes) {
51770
- const hash = (0, import_node_crypto22.createHash)("sha256").update(bytes).digest("hex");
51963
+ const hash = (0, import_node_crypto23.createHash)("sha256").update(bytes).digest("hex");
51771
51964
  await this.pool.query(
51772
51965
  `INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
51773
51966
  [hash, Buffer.from(bytes), bytes.byteLength, sniffContentType(bytes) ?? null]
@@ -54760,7 +54953,7 @@ var rowToMessage = (row) => ({
54760
54953
  });
54761
54954
 
54762
54955
  // ../storage/src/postgres-nodes.ts
54763
- var import_node_crypto23 = require("node:crypto");
54956
+ var import_node_crypto24 = require("node:crypto");
54764
54957
  var ident8 = (s2) => {
54765
54958
  if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
54766
54959
  return s2;
@@ -54898,7 +55091,7 @@ var PostgresNodeTokenStore = class _PostgresNodeTokenStore {
54898
55091
  return store;
54899
55092
  }
54900
55093
  issue(nodeId) {
54901
- const token = `ont_${(0, import_node_crypto23.randomBytes)(24).toString("base64url")}`;
55094
+ const token = `ont_${(0, import_node_crypto24.randomBytes)(24).toString("base64url")}`;
54902
55095
  this.cache.set(token, nodeId);
54903
55096
  void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
54904
55097
  return token;
@@ -54940,8 +55133,8 @@ init_trajectory();
54940
55133
  function builtinSkillsDir() {
54941
55134
  const override = process.env["OASIS_BUILTIN_SKILLS_DIR"]?.trim();
54942
55135
  if (override) return override;
54943
- const repoRoot = (0, import_node_url3.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
54944
- return path16.join(repoRoot, "skills");
55136
+ const repoRoot = (0, import_node_url4.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
55137
+ return path17.join(repoRoot, "skills");
54945
55138
  }
54946
55139
  function materializeBuiltins(builtins, runtimeKind) {
54947
55140
  if (builtins.length === 0) return {};
@@ -54973,16 +55166,16 @@ function apiUrlFromGatewayUrl(raw) {
54973
55166
  }
54974
55167
  var oasisWrapperCache;
54975
55168
  function oasisWrapperScript() {
54976
- if (oasisWrapperCache && fs17.existsSync(oasisWrapperCache)) return oasisWrapperCache;
54977
- const repoRoot = (0, import_node_url3.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
54978
- const tsx = path16.join(repoRoot, "node_modules/.bin/tsx");
54979
- const main = path16.join(repoRoot, "packages/cli/src/main.ts");
54980
- const dir = fs17.mkdtempSync(path16.join(os8.tmpdir(), "oasis-cli-"));
54981
- const wrapper = path16.join(dir, "oasis");
54982
- fs17.writeFileSync(wrapper, `#!/usr/bin/env bash
55169
+ if (oasisWrapperCache && fs18.existsSync(oasisWrapperCache)) return oasisWrapperCache;
55170
+ const repoRoot = (0, import_node_url4.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
55171
+ const tsx = path17.join(repoRoot, "node_modules/.bin/tsx");
55172
+ const main = path17.join(repoRoot, "packages/cli/src/main.ts");
55173
+ const dir = fs18.mkdtempSync(path17.join(os9.tmpdir(), "oasis-cli-"));
55174
+ const wrapper = path17.join(dir, "oasis");
55175
+ fs18.writeFileSync(wrapper, `#!/usr/bin/env bash
54983
55176
  exec ${JSON.stringify(tsx)} ${JSON.stringify(main)} "$@"
54984
55177
  `);
54985
- fs17.chmodSync(wrapper, 493);
55178
+ fs18.chmodSync(wrapper, 493);
54986
55179
  oasisWrapperCache = wrapper;
54987
55180
  return wrapper;
54988
55181
  }
@@ -55069,26 +55262,26 @@ function traceRuntimeKind(runtimeKind) {
55069
55262
  }
55070
55263
  async function startServe(opts) {
55071
55264
  const serverStartedAt = (/* @__PURE__ */ new Date()).toISOString();
55072
- fs17.mkdirSync(opts.dir, { recursive: true });
55073
- const serverHeartbeatFile = path16.join(opts.dir, "serve-heartbeat.json");
55265
+ fs18.mkdirSync(opts.dir, { recursive: true });
55266
+ const serverHeartbeatFile = path17.join(opts.dir, "serve-heartbeat.json");
55074
55267
  let previousServerHeartbeatAt;
55075
- if (fs17.existsSync(serverHeartbeatFile)) {
55268
+ if (fs18.existsSync(serverHeartbeatFile)) {
55076
55269
  try {
55077
- const raw = JSON.parse(fs17.readFileSync(serverHeartbeatFile, "utf8"));
55270
+ const raw = JSON.parse(fs18.readFileSync(serverHeartbeatFile, "utf8"));
55078
55271
  if (raw.at && Number.isFinite(Date.parse(raw.at))) previousServerHeartbeatAt = raw.at;
55079
55272
  } catch {
55080
55273
  }
55081
55274
  }
55082
55275
  const writeServerHeartbeat = () => {
55083
- fs17.writeFile(serverHeartbeatFile, JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), pid: process.pid }) + "\n", () => {
55276
+ fs18.writeFile(serverHeartbeatFile, JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), pid: process.pid }) + "\n", () => {
55084
55277
  });
55085
55278
  };
55086
55279
  writeServerHeartbeat();
55087
55280
  const serverHeartbeatTimer = setInterval(writeServerHeartbeat, 5e3);
55088
55281
  serverHeartbeatTimer.unref?.();
55089
- const lock = path16.join(opts.dir, "serve.lock");
55090
- if (fs17.existsSync(lock)) {
55091
- const pid = Number(fs17.readFileSync(lock, "utf8"));
55282
+ const lock = path17.join(opts.dir, "serve.lock");
55283
+ if (fs18.existsSync(lock)) {
55284
+ const pid = Number(fs18.readFileSync(lock, "utf8"));
55092
55285
  let alive = false;
55093
55286
  try {
55094
55287
  process.kill(pid, 0);
@@ -55096,19 +55289,19 @@ async function startServe(opts) {
55096
55289
  } catch {
55097
55290
  }
55098
55291
  if (alive) throw new Error(`\u8BE5\u6570\u636E\u76EE\u5F55\u5DF2\u6709 serve \u5728\u8DD1\uFF08pid=${pid}\uFF09\u2014\u2014\u5355\u5199\u8005\u8FDB\u7A0B\uFF0C\u4E0D\u80FD\u53CC\u5F00`);
55099
- fs17.unlinkSync(lock);
55292
+ fs18.unlinkSync(lock);
55100
55293
  }
55101
- fs17.writeFileSync(lock, String(process.pid));
55294
+ fs18.writeFileSync(lock, String(process.pid));
55102
55295
  const loadJson = (name) => {
55103
- const file = path16.join(opts.dir, name);
55104
- return fs17.existsSync(file) ? JSON.parse(fs17.readFileSync(file, "utf8")) : void 0;
55296
+ const file = path17.join(opts.dir, name);
55297
+ return fs18.existsSync(file) ? JSON.parse(fs18.readFileSync(file, "utf8")) : void 0;
55105
55298
  };
55106
55299
  const pgDsn = process.env["OASIS_PG_DSN"] ?? process.env["DATABASE_URL"];
55107
55300
  const pgSchema = process.env["OASIS_PG_SCHEMA"] ?? "public";
55108
55301
  const pgPool = pgDsn ? createPgPool(pgDsn) : void 0;
55109
- const oplog = pgDsn && pgPool ? await PostgresOplogStore.open(pgPool, pgSchema) : await NdjsonOplogStore.open(path16.join(opts.dir, "oplog.ndjson"));
55110
- const blobs = pgDsn && pgPool ? await PostgresBlobStore.open(pgPool, pgSchema) : new DirBlobStore(path16.join(opts.dir, "blobs"));
55111
- const assets = new DirBlobStore(path16.join(opts.dir, "assets"));
55302
+ const oplog = pgDsn && pgPool ? await PostgresOplogStore.open(pgPool, pgSchema) : await NdjsonOplogStore.open(path17.join(opts.dir, "oplog.ndjson"));
55303
+ const blobs = pgDsn && pgPool ? await PostgresBlobStore.open(pgPool, pgSchema) : new DirBlobStore(path17.join(opts.dir, "blobs"));
55304
+ const assets = new DirBlobStore(path17.join(opts.dir, "assets"));
55112
55305
  const defaultRootSchema = [
55113
55306
  { name: "brief", description: "\u5DE5\u5355\u603B\u7EB2\uFF1A\u53D1\u8D77\u65B9\u5BF9\u9F50\u7684\u603B\u76EE\u6807\u4E0E\u8303\u56F4\uFF0C\u6574\u5F20\u534F\u4F5C\u56FE\u7684\u6839\u3002", contentType: "text", ownerRole: "founder" },
55114
55307
  {
@@ -55126,7 +55319,7 @@ async function startServe(opts) {
55126
55319
  if (!schema.some((d) => d.name === "document")) {
55127
55320
  schema.push({ name: "document", description: "\u901A\u7528\u6587\u6863\uFF1A\u672A\u7EC6\u5206\u7684\u6587\u5B57\u4EA7\u7269\uFF08\u5177\u4F53\u7C7B\u578B\u89C1 docType\uFF09\u3002", contentType: "text", ownerRole: "writer" });
55128
55321
  }
55129
- const typeStore = await FileTypeRegistryStore.open(path16.join(opts.dir, "type-registry.json"));
55322
+ const typeStore = await FileTypeRegistryStore.open(path17.join(opts.dir, "type-registry.json"));
55130
55323
  if ((await typeStore.list()).length === 0) for (const d of schema) await typeStore.put(d);
55131
55324
  {
55132
55325
  const live = await typeStore.list();
@@ -55134,7 +55327,7 @@ async function startServe(opts) {
55134
55327
  schema.length = 0;
55135
55328
  schema.push(...live);
55136
55329
  }
55137
- const registryStore = pgDsn && pgPool ? await PostgresRegistryStore.open(pgPool, pgSchema) : await FileRegistryStore.open(path16.join(opts.dir, "registry-store.json"));
55330
+ const registryStore = pgDsn && pgPool ? await PostgresRegistryStore.open(pgPool, pgSchema) : await FileRegistryStore.open(path17.join(opts.dir, "registry-store.json"));
55138
55331
  try {
55139
55332
  await backfillSkillContentFromAssets(registryStore, assets);
55140
55333
  } catch (err) {
@@ -55158,17 +55351,17 @@ async function startServe(opts) {
55158
55351
  // per-contentType merge facet(§5.6):text=expensive→group-commit、code/structured=cheap→顺序 rebase
55159
55352
  handlers: defaultHandlersByContentType()
55160
55353
  });
55161
- const issuer = createTokenIssuer({ secretFile: path16.join(opts.dir, "session-token-secret") });
55162
- const operatorActor = `actor:human:${os8.userInfo().username}`;
55354
+ const issuer = createTokenIssuer({ secretFile: path17.join(opts.dir, "session-token-secret") });
55355
+ const operatorActor = `actor:human:${os9.userInfo().username}`;
55163
55356
  const operatorToken = issuer.issue(operatorActor);
55164
- fs17.writeFileSync(path16.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
55165
- let nodeTokens = createNodeTokenStore(path16.join(opts.dir, "node-tokens.json"));
55166
- const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path16.join(opts.dir, "enroll-tokens.json"));
55167
- let nodeStore = await FileNodeStore.open(path16.join(opts.dir, "nodes.json"));
55168
- const registryAuditFile = path16.join(opts.dir, "registry-audit.ndjson");
55357
+ fs18.writeFileSync(path17.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
55358
+ let nodeTokens = createNodeTokenStore(path17.join(opts.dir, "node-tokens.json"));
55359
+ const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path17.join(opts.dir, "enroll-tokens.json"));
55360
+ let nodeStore = await FileNodeStore.open(path17.join(opts.dir, "nodes.json"));
55361
+ const registryAuditFile = path17.join(opts.dir, "registry-audit.ndjson");
55169
55362
  const registryListeners = /* @__PURE__ */ new Set();
55170
55363
  const registryAudit = (record5) => {
55171
- fs17.appendFile(registryAuditFile, JSON.stringify(record5) + "\n", () => {
55364
+ fs18.appendFile(registryAuditFile, JSON.stringify(record5) + "\n", () => {
55172
55365
  });
55173
55366
  for (const l of registryListeners) l({ kind: record5.kind, actor: record5.actor, target: record5.target, timestamp: record5.timestamp });
55174
55367
  };
@@ -55205,9 +55398,9 @@ async function startServe(opts) {
55205
55398
  nodeTokens = await PostgresNodeTokenStore.open(pgPool, pgSchema);
55206
55399
  console.log(`[serve] \u4E8B\u5B9E/\u72B6\u6001\u4F53\u7CFB\uFF1APostgres schema=${pgSchema}\uFF08oplog / registry / blobs / artifacts / chat\uFF09`);
55207
55400
  } else {
55208
- projectStateStore = await FileProjectStateStore.open(path16.join(opts.dir, "artifact-document-projects.json"));
55209
- artifactStateStore = await FileArtifactStateStore.open(path16.join(opts.dir, "artifact-document-state.json"));
55210
- chatSessionStore = await FileChatSessionStore.open(path16.join(opts.dir, "chat-sessions.json"));
55401
+ projectStateStore = await FileProjectStateStore.open(path17.join(opts.dir, "artifact-document-projects.json"));
55402
+ artifactStateStore = await FileArtifactStateStore.open(path17.join(opts.dir, "artifact-document-state.json"));
55403
+ chatSessionStore = await FileChatSessionStore.open(path17.join(opts.dir, "chat-sessions.json"));
55211
55404
  console.log("[serve] \u4EA4\u4ED8\u7269\u72B6\u6001\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
55212
55405
  console.log("[serve] \u8282\u70B9/\u8FD0\u884C\u65F6\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
55213
55406
  }
@@ -55226,7 +55419,7 @@ async function startServe(opts) {
55226
55419
  });
55227
55420
  console.log(`[serve] \u9879\u76EE\u6587\u6863\u4F53\u7CFB\uFF1AOutline ${outlineUrl}\uFF08\u6302\u5728 Team Workspace\u300C\u9879\u76EE\u300D\u4E0B\uFF09`);
55228
55421
  } else {
55229
- projectDocumentStore = await FileProjectDocumentStore.open(path16.join(opts.dir, "project-document-spaces.json"));
55422
+ projectDocumentStore = await FileProjectDocumentStore.open(path17.join(opts.dir, "project-document-spaces.json"));
55230
55423
  console.log("[serve] \u9879\u76EE\u6587\u6863\u4F53\u7CFB\uFF1A\u672C\u5730\u5185\u5B58/\u6587\u4EF6 dev store");
55231
55424
  }
55232
55425
  const registryActorNames = /* @__PURE__ */ new Map();
@@ -55260,7 +55453,7 @@ async function startServe(opts) {
55260
55453
  traceStore = await PostgresTraceStore.open(tracePool, pgSchema);
55261
55454
  console.log(`[serve] \u8FD0\u884C\u8F68\u8FF9\u4F53\u7CFB\uFF1APostgres schema=${pgSchema}${traceDsn === pgDsn ? "" : "\uFF08\u72EC\u7ACB trace \u5E93\uFF09"}`);
55262
55455
  } else {
55263
- traceStore = await FileTraceStore.open(path16.join(opts.dir, "trace"));
55456
+ traceStore = await FileTraceStore.open(path17.join(opts.dir, "trace"));
55264
55457
  console.log("[serve] \u8FD0\u884C\u8F68\u8FF9\u4F53\u7CFB\uFF1A\u672C\u5730 ndjson dev store");
55265
55458
  }
55266
55459
  traceStoreForActors = traceStore;
@@ -55280,7 +55473,7 @@ async function startServe(opts) {
55280
55473
  create: createSeededWorkorder,
55281
55474
  projectExists: async (id) => Boolean(await projectStateStore.getProject(id))
55282
55475
  });
55283
- const controlPlaneStore = pgDsn && pgPool ? await PostgresControlPlaneStore.open(pgPool, pgSchema) : await FileControlPlaneStore.open(path16.join(opts.dir, "control-plane.json"));
55476
+ const controlPlaneStore = pgDsn && pgPool ? await PostgresControlPlaneStore.open(pgPool, pgSchema) : await FileControlPlaneStore.open(path17.join(opts.dir, "control-plane.json"));
55284
55477
  const resendKey = process.env["RESEND_API_KEY"];
55285
55478
  const mailFrom = process.env["RESEND_FROM_EMAIL"] ?? process.env["OASIS_MAIL_FROM"] ?? "noreply@open-friday.com";
55286
55479
  if (!resendKey) console.warn("[serve] RESEND_API_KEY \u672A\u8BBE\u2014\u2014\u9A8C\u8BC1\u7801/\u9080\u8BF7\u6253\u5370\u5230\u65E5\u5FD7\uFF08dev\uFF09\uFF1B\u751F\u4EA7\u8BF7\u914D RESEND_API_KEY + RESEND_FROM_EMAIL\uFF08Resend \u5DF2\u9A8C\u8BC1\u57DF\u540D\uFF09");
@@ -55350,12 +55543,12 @@ async function startServe(opts) {
55350
55543
  }
55351
55544
  return auth.sessionAccountId(headers);
55352
55545
  };
55353
- const workorderDrafts = new WorkorderDraftStore(path16.join(opts.dir, "workorder-drafts.json"));
55354
- const journalFile = path16.join(opts.dir, "dispatch-journal.ndjson");
55546
+ const workorderDrafts = new WorkorderDraftStore(path17.join(opts.dir, "workorder-drafts.json"));
55547
+ const journalFile = path17.join(opts.dir, "dispatch-journal.ndjson");
55355
55548
  const journalRing = [];
55356
- if (fs17.existsSync(journalFile)) {
55549
+ if (fs18.existsSync(journalFile)) {
55357
55550
  try {
55358
- const lines = fs17.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean);
55551
+ const lines = fs18.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean);
55359
55552
  for (const line of lines.slice(-500)) {
55360
55553
  try {
55361
55554
  journalRing.push(JSON.parse(line));
@@ -55368,7 +55561,7 @@ async function startServe(opts) {
55368
55561
  const journal = (entry) => {
55369
55562
  journalRing.push(entry);
55370
55563
  if (journalRing.length > 500) journalRing.shift();
55371
- fs17.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
55564
+ fs18.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
55372
55565
  });
55373
55566
  };
55374
55567
  const closeOrphanedDispatches = () => {
@@ -55395,7 +55588,7 @@ async function startServe(opts) {
55395
55588
  defaultEngine: { kernel, oplog, blobs, registry: registryStore, assets },
55396
55589
  defaultCompanyId,
55397
55590
  buildEngine: async (companyId) => {
55398
- const engine2 = await openFileEngine(path16.join(opts.dir, "companies", companyEngineDirName(companyId)), { schema });
55591
+ const engine2 = await openFileEngine(path17.join(opts.dir, "companies", companyEngineDirName(companyId)), { schema });
55399
55592
  await ensureCompanyActors(controlPlaneStore, companyId, engine2.registry);
55400
55593
  await syncRegistryRolesToKernel(engine2.registry, engine2.kernel);
55401
55594
  return engine2;
@@ -55512,7 +55705,7 @@ async function startServe(opts) {
55512
55705
  return {};
55513
55706
  }));
55514
55707
  const limits = { wallClockMs: SESSION_WALL_CLOCK_MS.planner };
55515
- const artifactId = `artifact:planner:${(0, import_node_crypto24.randomUUID)()}`;
55708
+ const artifactId = `artifact:planner:${(0, import_node_crypto25.randomUUID)()}`;
55516
55709
  const handle = await chatRemoteAdapter.spawn({
55517
55710
  actor: planner.id,
55518
55711
  actorToken: issueSessionToken(planner.id, { artifactId, action: "plan-workorder", limits, binding }),
@@ -55620,7 +55813,7 @@ async function startServe(opts) {
55620
55813
  },
55621
55814
  retainedSession: (key) => key.annotationId && key.artifactId ? allDispatchers().map((d) => d.retainedProduceSessionFor(key.artifactId)).find(Boolean) : coordinatorRef?.retainedSessionFor(key),
55622
55815
  // 0030 D3/D7 落盘:discuss 按项表写文件,serve 重启后同一卡点续同一段、不再新开。
55623
- discussSessions: new FileSideMap(path16.join(opts.dir, "discuss-sessions.json")),
55816
+ discussSessions: new FileSideMap(path17.join(opts.dir, "discuss-sessions.json")),
55624
55817
  dispatchChat: async ({ actorId, message, sessionId, chatSessionId, attachments, workspace, companyId }) => {
55625
55818
  const runCompanyId = companyId ?? defaultCompanyId;
55626
55819
  const actorCtxForCompany = await actors.resolveCtx(runCompanyId);
@@ -55642,10 +55835,10 @@ async function startServe(opts) {
55642
55835
  if (!localUrl) {
55643
55836
  throw new ApiError(503, "SERVER_URL_NOT_READY", "server URL \u5C1A\u672A\u5C31\u7EEA");
55644
55837
  }
55645
- const runtimeSessionId = sessionId ?? (0, import_node_crypto24.randomUUID)();
55838
+ const runtimeSessionId = sessionId ?? (0, import_node_crypto25.randomUUID)();
55646
55839
  const resumeRuntimeSession = Boolean(sessionId);
55647
- const traceRunId = `chat-run:${(0, import_node_crypto24.randomUUID)()}`;
55648
- const artifactId = `artifact:chat:${(0, import_node_crypto24.randomUUID)()}`;
55840
+ const traceRunId = `chat-run:${(0, import_node_crypto25.randomUUID)()}`;
55841
+ const artifactId = `artifact:chat:${(0, import_node_crypto25.randomUUID)()}`;
55649
55842
  const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
55650
55843
  let traceSeq = 0;
55651
55844
  let traceEnabled = true;
@@ -55846,7 +56039,13 @@ async function startServe(opts) {
55846
56039
  }
55847
56040
  });
55848
56041
  if (info.code === 0) resolve4();
55849
- else reject(new Error(`runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`));
56042
+ else {
56043
+ const detail = info.errorMessage?.trim();
56044
+ const generic = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
56045
+ reject(new Error(detail ? `${generic}
56046
+
56047
+ ${detail}` : generic));
56048
+ }
55850
56049
  });
55851
56050
  });
55852
56051
  return {
@@ -55890,7 +56089,7 @@ async function startServe(opts) {
55890
56089
  console.log(`[serve] \u8FDC\u7A0B agent API URL\uFF1A${remoteApiUrl ?? "\u672A\u914D\u7F6E\uFF08\u4EC5\u652F\u6301\u672C\u673A runtime\uFF09"}`);
55891
56090
  const projectsCfg = loadJson("projects.json");
55892
56091
  const seedProjects = (projectsCfg?.projects ?? []).map(
55893
- (p2) => p2.repos?.length ? { ...p2, repos: p2.repos.map((r) => r.repoDir ? { ...r, repoDir: path16.resolve(opts.dir, r.repoDir) } : r) } : p2
56092
+ (p2) => p2.repos?.length ? { ...p2, repos: p2.repos.map((r) => r.repoDir ? { ...r, repoDir: path17.resolve(opts.dir, r.repoDir) } : r) } : p2
55894
56093
  );
55895
56094
  for (const sp of seedProjects) {
55896
56095
  const existing = await projectStateStore.getProject(sp.id);
@@ -56021,8 +56220,8 @@ async function startServe(opts) {
56021
56220
  // 每 agent 并发产出上限默认 5(工单数 / 全局总量默认不限);--max-produce-per-agent N 覆盖。
56022
56221
  maxConcurrentProducePerActor: opts.maxConcurrentProducePerActor ?? 5,
56023
56222
  // 提案 uniform-annotation-resolve ③/④ 落盘:容错计数 + produce 会话号(重启不丢;丢了也只是降级/多容错一轮)
56024
- annotationRescue: new FileSideMap(path16.join(opts.dir, `annotation-rescue.${companyId}.json`)),
56025
- produceSessions: new FileSideMap(path16.join(opts.dir, `produce-sessions.${companyId}.json`))
56223
+ annotationRescue: new FileSideMap(path17.join(opts.dir, `annotation-rescue.${companyId}.json`)),
56224
+ produceSessions: new FileSideMap(path17.join(opts.dir, `produce-sessions.${companyId}.json`))
56026
56225
  });
56027
56226
  const slot = { dispatcher: d, logged: 0, ticking: false };
56028
56227
  dispatchers.set(companyId, slot);
@@ -56208,7 +56407,7 @@ async function startServe(opts) {
56208
56407
  schema: schemaMap,
56209
56408
  mirrors: new Map(opts.mirror.connectors.map((c) => [c.platform, c])),
56210
56409
  identities: opts.mirror.identities ?? new MapMirrorIdentities(),
56211
- state: new FsMirrorStateStore(path16.join(opts.dir, "mirror-state.json")),
56410
+ state: new FsMirrorStateStore(path17.join(opts.dir, "mirror-state.json")),
56212
56411
  ...opts.mirror.debounceMs !== void 0 ? { debounceMs: opts.mirror.debounceMs } : {},
56213
56412
  log: (m2) => console.log(m2)
56214
56413
  });
@@ -56220,7 +56419,7 @@ async function startServe(opts) {
56220
56419
  if (opts.dispatch) {
56221
56420
  if (ciGateEnabled) {
56222
56421
  const ci = new GhCiProvider({
56223
- mirrorRoot: path16.join(opts.dir, "git-mirrors"),
56422
+ mirrorRoot: path17.join(opts.dir, "git-mirrors"),
56224
56423
  failClosedWhenNoChecks: process.env["OASIS_CI_FAIL_CLOSED"] === "1",
56225
56424
  log: (m2) => console.log(m2)
56226
56425
  });
@@ -56232,7 +56431,7 @@ async function startServe(opts) {
56232
56431
  const gitSync = new GitSyncWorker({
56233
56432
  kernel,
56234
56433
  resolveProject,
56235
- mirrorRoot: path16.join(opts.dir, "git-mirrors"),
56434
+ mirrorRoot: path17.join(opts.dir, "git-mirrors"),
56236
56435
  log: (m2) => console.log(m2)
56237
56436
  });
56238
56437
  gitTimer = setInterval(() => {
@@ -56295,7 +56494,7 @@ async function startServe(opts) {
56295
56494
  // 病历里展示节点的"在跑会话情况"(runId + 跑了多久):从派发器在途会话按 artifactId 过滤。
56296
56495
  sessionsOf: (id) => allDispatchers().flatMap((d) => d.inFlightSessions()).filter((s2) => s2.artifactId === id).map((s2) => ({ runId: s2.sessionId, action: s2.action, startedAt: s2.startedAt })),
56297
56496
  log: (m2) => console.log(m2),
56298
- retention: new FileSideMap(path16.join(opts.dir, "retained-sessions.json"))
56497
+ retention: new FileSideMap(path17.join(opts.dir, "retained-sessions.json"))
56299
56498
  // 0030 D7 落盘
56300
56499
  });
56301
56500
  coordinatorRef = coordinator;
@@ -56406,7 +56605,7 @@ async function startServe(opts) {
56406
56605
  await server.close();
56407
56606
  if (pgPool) await pgPool.end().catch(() => {
56408
56607
  });
56409
- fs17.rmSync(lock, { force: true });
56608
+ fs18.rmSync(lock, { force: true });
56410
56609
  }
56411
56610
  };
56412
56611
  }
@@ -56842,13 +57041,13 @@ async function startNode(opts) {
56842
57041
 
56843
57042
  // ../cli/src/daemon/machine-id.ts
56844
57043
  var import_node_child_process14 = require("node:child_process");
56845
- var import_node_fs5 = require("node:fs");
56846
- var import_node_crypto25 = require("node:crypto");
57044
+ var import_node_fs6 = require("node:fs");
57045
+ var import_node_crypto26 = require("node:crypto");
56847
57046
  var import_node_os7 = require("node:os");
56848
57047
  function linuxMachineId() {
56849
57048
  for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
56850
57049
  try {
56851
- const v2 = (0, import_node_fs5.readFileSync)(p2, "utf8").trim();
57050
+ const v2 = (0, import_node_fs6.readFileSync)(p2, "utf8").trim();
56852
57051
  if (v2) return v2;
56853
57052
  } catch {
56854
57053
  }
@@ -56909,13 +57108,14 @@ var defaultSources = {
56909
57108
  function resolveNodeId(sources = {}) {
56910
57109
  const s2 = { ...defaultSources, ...sources };
56911
57110
  const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
56912
- const digest = (0, import_node_crypto25.createHash)("sha256").update(material).digest("hex").slice(0, 12);
57111
+ const digest = (0, import_node_crypto26.createHash)("sha256").update(material).digest("hex").slice(0, 12);
56913
57112
  return `node-${digest}`;
56914
57113
  }
56915
57114
 
56916
57115
  // ../cli/src/cli.ts
56917
57116
  init_src5();
56918
57117
  init_src();
57118
+ init_src4();
56919
57119
  var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uFF08\u670D\u52A1\u7AEF\u7626\u5BA2\u6237\u7AEF\uFF09
56920
57120
 
56921
57121
  oasis serve [--dir .oasis] [--port 7320] [--dispatch true [--model haiku] [--max-produce-per-agent 5] [--max-concurrent-produce N]] [--allow-simple-tokens true] [--public-url https://host/oasis-api] [--gateway-url wss://host/oasis-api/node-gateway]
@@ -56952,6 +57152,9 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
56952
57152
  reject <artifactId> <revisionId> --reason <text>
56953
57153
  conclude <artifactId> [--note <text>] # \u673A\u68B0 grounding \u786C\u62E6\uFF1B\u6709 gate \u5219\u8FDB\u5165\u5F85\u5BA1
56954
57154
  review <artifactId> --verdict approve|request_changes [--note <t>]
57155
+ design run <artifactId> [--brief <t>] [--reason <t>] [--od-url <url>] [--title <t>] [--agent <id>]
57156
+ # design \u4EA7\u7269\uFF1A\u5728\u901A\u7528 runtime \u4E0A\u9A71\u52A8 open-design \u753B\u677F\u5F15\u64CE\u4EA7\u754C\u9762\u7A3F\u5E76\u4EA4\u7A3F\uFF08\u63D0\u6848 design-node-runtime-to-cli-tool\uFF09\u3002
57157
+ # --brief \u7F3A\u7701\u8BFB\u5F53\u524D\u76EE\u5F55 TASK.md\uFF1B\u4E0A\u4E0B\u6587\u53D6\u5F53\u524D\u76EE\u5F55 inputs/\uFF1Bod \u5730\u5740\u7F3A\u7701 $OASIS_OPEN_DESIGN_URL \u6216\u672C\u673A 7457\u3002
56955
57158
 
56956
57159
  \u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09
56957
57160
  annotate <artifactId> --body <text> [--from <\u4E0B\u6E38> --blocks true]
@@ -57075,8 +57278,8 @@ function makeClient(base, token) {
57075
57278
  if (!res.ok) await fail(res);
57076
57279
  return (await res.json()).data;
57077
57280
  },
57078
- async request(method, path19, body) {
57079
- const res = await fetch(`${base}${path19}`, {
57281
+ async request(method, path20, body) {
57282
+ const res = await fetch(`${base}${path20}`, {
57080
57283
  method,
57081
57284
  headers,
57082
57285
  ...body !== void 0 ? { body: JSON.stringify(body) } : {}
@@ -57084,8 +57287,8 @@ function makeClient(base, token) {
57084
57287
  if (!res.ok) await fail(res);
57085
57288
  return await res.json();
57086
57289
  },
57087
- async post(path19, body) {
57088
- const res = await fetch(`${base}${path19}`, { method: "POST", headers, body: JSON.stringify(body) });
57290
+ async post(path20, body) {
57291
+ const res = await fetch(`${base}${path20}`, { method: "POST", headers, body: JSON.stringify(body) });
57089
57292
  if (!res.ok) await fail(res);
57090
57293
  return await res.json();
57091
57294
  }
@@ -57098,62 +57301,62 @@ async function runCli(argv, println = console.log) {
57098
57301
  return;
57099
57302
  }
57100
57303
  const { positional, flags } = parseArgs(rest);
57101
- const dir = flags.get("dir") ?? process.env["OASIS_DIR"] ?? path17.resolve(".oasis");
57304
+ const dir = flags.get("dir") ?? process.env["OASIS_DIR"] ?? path18.resolve(".oasis");
57102
57305
  if (command === "node" && positional[0] !== "output") {
57103
57306
  const serverUrl = flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? "ws://127.0.0.1:7320/node-gateway";
57104
57307
  const nodeName = flags.get("name") ?? process.env["OASIS_NODE_NAME"];
57105
- const nodeIdFile = path17.join(dir, "node-id");
57106
- const nodeTokenFile = path17.join(dir, "node-token");
57107
- const enrollTokenFile = path17.join(dir, "enroll-token");
57108
- const reportMarkerFile = path17.join(dir, "report-runtimes");
57109
- const persistedNodeId = fs18.existsSync(nodeIdFile) ? fs18.readFileSync(nodeIdFile, "utf8").trim() : null;
57308
+ const nodeIdFile = path18.join(dir, "node-id");
57309
+ const nodeTokenFile = path18.join(dir, "node-token");
57310
+ const enrollTokenFile = path18.join(dir, "enroll-token");
57311
+ const reportMarkerFile = path18.join(dir, "report-runtimes");
57312
+ const persistedNodeId = fs19.existsSync(nodeIdFile) ? fs19.readFileSync(nodeIdFile, "utf8").trim() : null;
57110
57313
  let nodeId = persistedNodeId || resolveNodeId();
57111
- let token2 = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? (fs18.existsSync(nodeTokenFile) ? fs18.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
57112
- const enrollToken = flags.get("enroll-token") ?? process.env["OASIS_ENROLL_TOKEN"] ?? (fs18.existsSync(enrollTokenFile) ? fs18.readFileSync(enrollTokenFile, "utf8").trim() : void 0);
57314
+ let token2 = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? (fs19.existsSync(nodeTokenFile) ? fs19.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
57315
+ const enrollToken = flags.get("enroll-token") ?? process.env["OASIS_ENROLL_TOKEN"] ?? (fs19.existsSync(enrollTokenFile) ? fs19.readFileSync(enrollTokenFile, "utf8").trim() : void 0);
57113
57316
  let freshEnrollment = false;
57114
57317
  if (!token2 && enrollToken) {
57115
57318
  const httpBase2 = serverUrl.replace(/^ws(s?):\/\//, "http$1://").replace(/\/node-gateway.*$/, "");
57116
57319
  const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
57117
57320
  method: "POST",
57118
57321
  headers: { "content-type": "application/json" },
57119
- body: JSON.stringify({ enrollToken, nodeId, hostname: os9.hostname() })
57322
+ body: JSON.stringify({ enrollToken, nodeId, hostname: os10.hostname() })
57120
57323
  });
57121
57324
  if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
57122
57325
  const body = await res.json();
57123
57326
  nodeId = body.nodeId;
57124
57327
  token2 = body.token;
57125
- fs18.mkdirSync(dir, { recursive: true });
57126
- fs18.writeFileSync(nodeIdFile, nodeId);
57127
- fs18.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57328
+ fs19.mkdirSync(dir, { recursive: true });
57329
+ fs19.writeFileSync(nodeIdFile, nodeId);
57330
+ fs19.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57128
57331
  try {
57129
- fs18.unlinkSync(enrollTokenFile);
57332
+ fs19.unlinkSync(enrollTokenFile);
57130
57333
  } catch {
57131
57334
  }
57132
57335
  freshEnrollment = true;
57133
57336
  }
57134
57337
  if (!nodeId) throw new Error("no nodeId \u2014 provide --enroll-token <ent_...> on first run");
57135
- const scriptRun = freshEnrollment || fs18.existsSync(reportMarkerFile);
57338
+ const scriptRun = freshEnrollment || fs19.existsSync(reportMarkerFile);
57136
57339
  if (flags.has("service")) {
57137
57340
  const { spawnSync, execSync: execSync2 } = await import("node:child_process");
57138
57341
  if (token2) {
57139
- fs18.mkdirSync(dir, { recursive: true });
57140
- fs18.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57342
+ fs19.mkdirSync(dir, { recursive: true });
57343
+ fs19.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57141
57344
  }
57142
57345
  if (scriptRun) {
57143
- fs18.mkdirSync(dir, { recursive: true });
57144
- fs18.writeFileSync(reportMarkerFile, "");
57346
+ fs19.mkdirSync(dir, { recursive: true });
57347
+ fs19.writeFileSync(reportMarkerFile, "");
57145
57348
  }
57146
57349
  println("\u2192 Installing oasis_test globally...");
57147
57350
  spawnSync("npm", ["install", "-g", "oasis_test@latest"], { stdio: "inherit" });
57148
57351
  const prefix = execSync2("npm prefix -g").toString().trim();
57149
- const binPath = path17.join(prefix, "bin", "oasis_test");
57352
+ const binPath = path18.join(prefix, "bin", "oasis_test");
57150
57353
  const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
57151
57354
  if (process.platform === "linux") {
57152
- const svcFile = path17.join(os9.homedir(), ".config/systemd/user/oasis-node.service");
57153
- fs18.mkdirSync(path17.dirname(svcFile), { recursive: true });
57355
+ const svcFile = path18.join(os10.homedir(), ".config/systemd/user/oasis-node.service");
57356
+ fs19.mkdirSync(path18.dirname(svcFile), { recursive: true });
57154
57357
  if (spawnSync("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
57155
57358
  spawnSync("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
57156
- fs18.writeFileSync(svcFile, [
57359
+ fs19.writeFileSync(svcFile, [
57157
57360
  "[Unit]",
57158
57361
  "Description=Oasis Node Daemon",
57159
57362
  "After=network.target",
@@ -57162,7 +57365,7 @@ async function runCli(argv, println = console.log) {
57162
57365
  `ExecStart=${binPath} ${svcArgs}`,
57163
57366
  // Carry the install-time PATH so the detached daemon detects CLIs in user dirs
57164
57367
  // (~/.npm-global/bin, ~/.local/bin) — systemd --user otherwise gives a minimal PATH.
57165
- `Environment=PATH=${process.env["PATH"] ?? ""}:${path17.join(os9.homedir(), ".npm-global/bin")}:${path17.join(os9.homedir(), ".local/bin")}:/usr/local/bin`,
57368
+ `Environment=PATH=${process.env["PATH"] ?? ""}:${path18.join(os10.homedir(), ".npm-global/bin")}:${path18.join(os10.homedir(), ".local/bin")}:/usr/local/bin`,
57166
57369
  "Restart=on-failure",
57167
57370
  "RestartSec=5",
57168
57371
  "StandardOutput=journal",
@@ -57174,31 +57377,31 @@ async function runCli(argv, println = console.log) {
57174
57377
  ].join("\n"));
57175
57378
  spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
57176
57379
  spawnSync("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
57177
- spawnSync("loginctl", ["enable-linger", os9.userInfo().username], { stdio: "ignore" });
57380
+ spawnSync("loginctl", ["enable-linger", os10.userInfo().username], { stdio: "ignore" });
57178
57381
  println("\u2713 Oasis node service started (systemd --user oasis-node)");
57179
57382
  println(" Status : systemctl --user status oasis-node");
57180
57383
  println(" Logs : journalctl --user -u oasis-node -f");
57181
57384
  println(" Stop : systemctl --user stop oasis-node");
57182
57385
  } else if (process.platform === "darwin") {
57183
- const plist = path17.join(os9.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
57184
- fs18.mkdirSync(path17.dirname(plist), { recursive: true });
57386
+ const plist = path18.join(os10.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
57387
+ fs19.mkdirSync(path18.dirname(plist), { recursive: true });
57185
57388
  spawnSync("launchctl", ["unload", plist], { stdio: "ignore" });
57186
57389
  const argXml = [binPath, "node", "--server-ws", serverUrl, "--dir", dir, ...nodeName ? ["--name", nodeName] : []].map((a) => `<string>${a}</string>`).join("");
57187
- fs18.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>${os9.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os9.homedir()}/.oasis-node.err</string></dict></plist>`);
57390
+ fs19.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>${os10.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os10.homedir()}/.oasis-node.err</string></dict></plist>`);
57188
57391
  spawnSync("launchctl", ["load", plist], { stdio: "inherit" });
57189
57392
  println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
57190
- println(` Logs : tail -f ${os9.homedir()}/.oasis-node.log`);
57393
+ println(` Logs : tail -f ${os10.homedir()}/.oasis-node.log`);
57191
57394
  println(` Stop : launchctl unload ${plist}`);
57192
57395
  } else {
57193
- spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path17.join(os9.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
57396
+ spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path18.join(os10.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
57194
57397
  println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
57195
57398
  println(" Note: no automatic restart on reboot in this environment.");
57196
57399
  }
57197
57400
  return;
57198
57401
  }
57199
- if (fs18.existsSync(reportMarkerFile)) {
57402
+ if (fs19.existsSync(reportMarkerFile)) {
57200
57403
  try {
57201
- fs18.unlinkSync(reportMarkerFile);
57404
+ fs19.unlinkSync(reportMarkerFile);
57202
57405
  } catch {
57203
57406
  }
57204
57407
  }
@@ -57206,14 +57409,14 @@ async function runCli(argv, println = console.log) {
57206
57409
  return;
57207
57410
  }
57208
57411
  if (command === "node-token") {
57209
- const store = createNodeTokenStore(path17.join(dir, "node-tokens.json"));
57412
+ const store = createNodeTokenStore(path18.join(dir, "node-tokens.json"));
57210
57413
  const sub = positional[0];
57211
57414
  if (sub === "issue") {
57212
- const id = flags.get("id") ?? `node-${(0, import_node_crypto26.randomUUID)()}`;
57415
+ const id = flags.get("id") ?? `node-${(0, import_node_crypto27.randomUUID)()}`;
57213
57416
  const token2 = store.issue(id);
57214
57417
  println(token2);
57215
57418
  process.stderr.write(
57216
- `\u5DF2\u4E3A ${id} \u7B7E\u53D1 node-token\uFF08\u5199\u5165 ${path17.join(dir, "node-tokens.json")}\uFF09\u3002
57419
+ `\u5DF2\u4E3A ${id} \u7B7E\u53D1 node-token\uFF08\u5199\u5165 ${path18.join(dir, "node-tokens.json")}\uFF09\u3002
57217
57420
  \u628A\u4E0A\u9762\u8FD9\u4E32\u653E\u5230\u8282\u70B9\u673A\uFF1A--token <t> / $OASIS_NODE_TOKEN / <\u8282\u70B9dir>/node-token
57218
57421
  `
57219
57422
  );
@@ -57234,7 +57437,7 @@ async function runCli(argv, println = console.log) {
57234
57437
  }
57235
57438
  if (command === "admin" && positional[0] === "grant-owner") {
57236
57439
  const email2 = need(flags, "email");
57237
- const store = await FileControlPlaneStore.open(path17.join(dir, "control-plane.json"));
57440
+ const store = await FileControlPlaneStore.open(path18.join(dir, "control-plane.json"));
57238
57441
  const activeCompanies = (await store.listCompanies()).filter((c) => c.status === "active");
57239
57442
  const companyId = flags.get("company") ?? activeCompanies[0]?.id ?? resolveDefaultCompanyConfig().id;
57240
57443
  const name = flags.get("name");
@@ -57247,11 +57450,11 @@ async function runCli(argv, println = console.log) {
57247
57450
  }
57248
57451
  if (command === "export-trajectories") {
57249
57452
  const { exportTrajectories: exportTrajectories2 } = await Promise.resolve().then(() => (init_trajectory(), trajectory_exports));
57250
- const samples = await exportTrajectories2(path17.resolve(dir));
57453
+ const samples = await exportTrajectories2(path18.resolve(dir));
57251
57454
  const outFile = flags.get("out");
57252
57455
  const lines = samples.map((sample) => JSON.stringify(sample)).join("\n");
57253
57456
  if (outFile !== void 0) {
57254
- fs18.writeFileSync(outFile, lines + (lines ? "\n" : ""));
57457
+ fs19.writeFileSync(outFile, lines + (lines ? "\n" : ""));
57255
57458
  println(`\u5DF2\u5BFC\u51FA ${samples.length} \u6761\u8F68\u8FF9\u6837\u672C \u2192 ${outFile}\uFF08approved/rejected \u6210\u5BF9\u5373\u504F\u597D\u5BF9\uFF09`);
57256
57459
  } else {
57257
57460
  println(lines);
@@ -57259,10 +57462,10 @@ async function runCli(argv, println = console.log) {
57259
57462
  return;
57260
57463
  }
57261
57464
  if (command === "serve" && positional[0] === "install") {
57262
- const absDir = path17.resolve(dir);
57263
- const name = `oasis-serve-${path17.basename(absDir)}`;
57264
- const unitDir = flags.get("unit-dir") ?? path17.join(os9.homedir(), ".config", "systemd", "user");
57265
- const bin = flags.get("bin") ?? path17.join(os9.homedir(), ".local", "bin", "oasis");
57465
+ const absDir = path18.resolve(dir);
57466
+ const name = `oasis-serve-${path18.basename(absDir)}`;
57467
+ const unitDir = flags.get("unit-dir") ?? path18.join(os10.homedir(), ".config", "systemd", "user");
57468
+ const bin = flags.get("bin") ?? path18.join(os10.homedir(), ".local", "bin", "oasis");
57266
57469
  const port = flags.get("port") ?? "7320";
57267
57470
  const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
57268
57471
  const unit = [
@@ -57279,9 +57482,9 @@ async function runCli(argv, println = console.log) {
57279
57482
  `WantedBy=default.target`,
57280
57483
  ``
57281
57484
  ].join("\n");
57282
- fs18.mkdirSync(unitDir, { recursive: true });
57283
- const unitPath = path17.join(unitDir, `${name}.service`);
57284
- fs18.writeFileSync(unitPath, unit);
57485
+ fs19.mkdirSync(unitDir, { recursive: true });
57486
+ const unitPath = path18.join(unitDir, `${name}.service`);
57487
+ fs19.writeFileSync(unitPath, unit);
57285
57488
  println(`\u5DF2\u5199\u5165 ${unitPath}`);
57286
57489
  println(`\u542F\u7528\uFF1Asystemctl --user daemon-reload && systemctl --user enable --now ${name}`);
57287
57490
  println(`\u5F00\u673A\u81EA\u542F\uFF08\u542B\u672A\u767B\u5F55\uFF09\uFF1Aloginctl enable-linger $USER`);
@@ -57303,20 +57506,20 @@ async function runCli(argv, println = console.log) {
57303
57506
  });
57304
57507
  const port2 = new URL(handle.baseUrl).port;
57305
57508
  println(`oasis serve \u5C31\u7EEA\uFF1Ahttp://0.0.0.0:${port2}\uFF08\u672C\u673A\u8BBF\u95EE\u7528 http://127.0.0.1:${port2}\uFF09`);
57306
- println(`operator token \u5DF2\u5199\u5165 ${path17.join(dir, "operator-token")}\uFF08\u672C\u673A CLI \u81EA\u52A8\u8BFB\u53D6\uFF09`);
57509
+ println(`operator token \u5DF2\u5199\u5165 ${path18.join(dir, "operator-token")}\uFF08\u672C\u673A CLI \u81EA\u52A8\u8BFB\u53D6\uFF09`);
57307
57510
  if (flags.get("dispatch") === "true") println(`\u8C03\u5EA6\u5FAA\u73AF\u5DF2\u542F\u52A8\uFF08claude-code adapter\uFF09`);
57308
57511
  await new Promise(() => {
57309
57512
  });
57310
57513
  return;
57311
57514
  }
57312
57515
  const base = flags.get("server") ?? process.env["OASIS_SERVER"] ?? "http://127.0.0.1:7320";
57313
- const tokenFile = path17.join(dir, "operator-token");
57314
- const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs18.existsSync(tokenFile) ? fs18.readFileSync(tokenFile, "utf8").trim() : void 0);
57516
+ const tokenFile = path18.join(dir, "operator-token");
57517
+ const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs19.existsSync(tokenFile) ? fs19.readFileSync(tokenFile, "utf8").trim() : void 0);
57315
57518
  if (!token) {
57316
57519
  throw new Error(`\u65E0 token\uFF1A\u5148 oasis serve\uFF08\u4F1A\u751F\u6210 ${tokenFile}\uFF09\uFF0C\u6216\u663E\u5F0F --token / $OASIS_TOKEN`);
57317
57520
  }
57318
57521
  const api = makeClient(base, token);
57319
- const readFileArg = (file) => fs18.readFileSync(file, "utf8");
57522
+ const readFileArg = (file) => fs19.readFileSync(file, "utf8");
57320
57523
  const parseJsonFlag = (value, name) => {
57321
57524
  const parsed = JSON.parse(value);
57322
57525
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -57334,11 +57537,11 @@ async function runCli(argv, println = console.log) {
57334
57537
  const readDirFiles = (root) => {
57335
57538
  const out = [];
57336
57539
  const walk = (abs, rel) => {
57337
- for (const name of fs18.readdirSync(abs)) {
57338
- const childAbs = path17.join(abs, name);
57540
+ for (const name of fs19.readdirSync(abs)) {
57541
+ const childAbs = path18.join(abs, name);
57339
57542
  const childRel = rel ? `${rel}/${name}` : name;
57340
- if (fs18.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
57341
- else out.push({ path: childRel, contentBase64: fs18.readFileSync(childAbs).toString("base64") });
57543
+ if (fs19.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
57544
+ else out.push({ path: childRel, contentBase64: fs19.readFileSync(childAbs).toString("base64") });
57342
57545
  }
57343
57546
  };
57344
57547
  walk(root, "");
@@ -57464,7 +57667,7 @@ async function runCli(argv, println = console.log) {
57464
57667
  }
57465
57668
  switch (command) {
57466
57669
  case "create-workorder": {
57467
- const planRaw = flags.get("plan-file") !== void 0 ? fs18.readFileSync(flags.get("plan-file"), "utf8") : flags.get("plan");
57670
+ const planRaw = flags.get("plan-file") !== void 0 ? fs19.readFileSync(flags.get("plan-file"), "utf8") : flags.get("plan");
57468
57671
  const acceptanceFlag = flags.get("acceptance");
57469
57672
  const args = {
57470
57673
  createdVia: "seed",
@@ -57685,9 +57888,9 @@ async function runCli(argv, println = console.log) {
57685
57888
  if (verb === "add") {
57686
57889
  const file = flags.get("file");
57687
57890
  if (file !== void 0) {
57688
- const bytes = fs18.readFileSync(file);
57891
+ const bytes = fs19.readFileSync(file);
57689
57892
  const res = await api.request("POST", `/api/projects/${encodeURIComponent(projectId)}/files`, {
57690
- name: flags.get("name") ?? path17.basename(file),
57893
+ name: flags.get("name") ?? path18.basename(file),
57691
57894
  ...flags.has("path") ? { path: flags.get("path") } : {},
57692
57895
  content_base64: bytes.toString("base64"),
57693
57896
  ...flags.has("content-type") ? { content_type: flags.get("content-type") } : {}
@@ -57844,6 +58047,38 @@ ${res.warning}`);
57844
58047
  println(message);
57845
58048
  break;
57846
58049
  }
58050
+ case "design": {
58051
+ const sub = positional[0];
58052
+ if (sub !== "run") throw new Error("\u7528\u6CD5\uFF1Aoasis design run <artifactId> [--brief <t>] [--reason <t>] [--od-url <url>] [--title <t>] [--agent <id>]");
58053
+ const artifactId = needPos(positional, 1, "oasis design run <artifactId>");
58054
+ const odBase = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
58055
+ const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
58056
+ const brief = flags.get("brief") ?? (fs19.existsSync("TASK.md") ? fs19.readFileSync("TASK.md", "utf8") : "");
58057
+ if (!brief.trim()) throw new Error("\u65E0\u8BBE\u8BA1\u4EFB\u52A1\uFF1A\u7ED9 --brief <text> \u6216\u5728\u5F53\u524D\u76EE\u5F55\u653E TASK.md");
58058
+ const contextFiles = { "TASK.md": brief };
58059
+ if (fs19.existsSync("inputs") && fs19.statSync("inputs").isDirectory()) {
58060
+ for (const f2 of readDirFiles("inputs")) {
58061
+ contextFiles[`inputs/${f2.path}`] = Buffer.from(f2.contentBase64, "base64").toString("utf8");
58062
+ }
58063
+ }
58064
+ println(`[design] \u753B\u677F ${deriveBoardKey(artifactId)} \u2190 ${artifactId}\uFF1B\u9A71\u52A8 od \u5F15\u64CE ${odBase} \u2026`);
58065
+ const { dir: dir2, entry, boardKey, runId } = await runOpenDesignSession({
58066
+ base: odBase,
58067
+ publicBase: odPublic,
58068
+ agentId: flags.get("agent") ?? "claude",
58069
+ artifactId,
58070
+ title: flags.get("title") ?? artifactId,
58071
+ message: brief,
58072
+ systemPrompt: "\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",
58073
+ contextFiles,
58074
+ onLine: (line) => println(`[od] ${line.length > 500 ? line.slice(0, 500) + "\u2026" : line}`)
58075
+ });
58076
+ println(`[design] \u753B\u677F\u4EA7\u51FA ${entry}\uFF08board ${boardKey}, run ${runId.slice(0, 8)}\uFF09\u2192 \u4EA4\u7A3F\u4E2D \u2026`);
58077
+ const reason = flags.get("reason") ?? `\u753B\u677F\u5FEB\u7167\u4EA4\u4ED8\uFF1A${entry}\uFF08board ${boardKey}, run ${runId.slice(0, 8)}\uFF09`;
58078
+ const { message } = await api.cmd("propose", { artifactId, files: readDirFiles(dir2), reason });
58079
+ println(message);
58080
+ break;
58081
+ }
57847
58082
  case "merge": {
57848
58083
  const artifactId = needPos(positional, 0, "oasis merge <artifactId> [revisionId]");
57849
58084
  const { message } = await api.cmd("merge", { artifactId, revisionId: positional[1] });
@@ -58236,8 +58471,8 @@ ${res.warning}`);
58236
58471
  }
58237
58472
  case "content": {
58238
58473
  const id = needPos(positional, 0, "oasis content <artifactId> [path]");
58239
- const path19 = positional[1];
58240
- const c = await api.view("content", id, path19 ? { path: path19 } : void 0);
58474
+ const path20 = positional[1];
58475
+ const c = await api.view("content", id, path20 ? { path: path20 } : void 0);
58241
58476
  if (c.kind === "empty") println("\uFF08\u672C\u4EA7\u7269\u5C1A\u65E0\u5185\u5BB9\uFF09");
58242
58477
  else if (c.kind === "external-pin") println(`\u4EE3\u7801/\u5916\u90E8\u4EA4\u4ED8\u7269\uFF1A\u5185\u5BB9\u5728 git/\u5916\u90E8 \u2192 ${c.ref}\uFF08\u6309\u300C\u600E\u4E48\u63D0\u4EA4\u300D\u91CC\u7684\u4ED3\u5E93\u6E05\u5355 clone \u53D6\uFF09`);
58243
58478
  else if (c.kind === "text") println(c.text);
@@ -58410,14 +58645,14 @@ ${res.warning}`);
58410
58645
  }
58411
58646
 
58412
58647
  // src/index.ts
58413
- var PKG_VERSION = true ? "0.1.44" : "dev";
58414
- var OASIS_DIR = path18.join(os10.homedir(), ".oasis");
58415
- var CONFIG_FILE = path18.join(OASIS_DIR, "node-config.json");
58416
- var PID_FILE = path18.join(OASIS_DIR, "node.pid");
58417
- var BIN_FILE = path18.join(OASIS_DIR, "bin", "oasis.js");
58418
- var LOCAL_BIN = path18.join(os10.homedir(), ".local", "bin", "oasis");
58419
- var LOG_FILE = path18.join(OASIS_DIR, "node.log");
58420
- var NPM_PREFIX = path18.join(OASIS_DIR, "npm-global");
58648
+ var PKG_VERSION = true ? "0.1.46" : "dev";
58649
+ var OASIS_DIR = path19.join(os11.homedir(), ".oasis");
58650
+ var CONFIG_FILE = path19.join(OASIS_DIR, "node-config.json");
58651
+ var PID_FILE = path19.join(OASIS_DIR, "node.pid");
58652
+ var BIN_FILE = path19.join(OASIS_DIR, "bin", "oasis.js");
58653
+ var LOCAL_BIN = path19.join(os11.homedir(), ".local", "bin", "oasis");
58654
+ var LOG_FILE = path19.join(OASIS_DIR, "node.log");
58655
+ var NPM_PREFIX = path19.join(OASIS_DIR, "npm-global");
58421
58656
  var PKG_NAME = "oasis_test";
58422
58657
  var parseFlags = (argv) => {
58423
58658
  const flags = /* @__PURE__ */ new Map();
@@ -58429,18 +58664,18 @@ var parseFlags = (argv) => {
58429
58664
  };
58430
58665
  var readConfig = () => {
58431
58666
  try {
58432
- return JSON.parse(fs19.readFileSync(CONFIG_FILE, "utf8"));
58667
+ return JSON.parse(fs20.readFileSync(CONFIG_FILE, "utf8"));
58433
58668
  } catch {
58434
58669
  return null;
58435
58670
  }
58436
58671
  };
58437
58672
  var saveConfig = (c) => {
58438
- fs19.mkdirSync(OASIS_DIR, { recursive: true });
58439
- fs19.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
58673
+ fs20.mkdirSync(OASIS_DIR, { recursive: true });
58674
+ fs20.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
58440
58675
  };
58441
58676
  var readPid = () => {
58442
58677
  try {
58443
- const p2 = parseInt(fs19.readFileSync(PID_FILE, "utf8").trim(), 10);
58678
+ const p2 = parseInt(fs20.readFileSync(PID_FILE, "utf8").trim(), 10);
58444
58679
  return isNaN(p2) ? null : p2;
58445
58680
  } catch {
58446
58681
  return null;
@@ -58456,26 +58691,26 @@ var isRunning = (pid) => {
58456
58691
  };
58457
58692
  var httpBase = (wsUrl) => wsUrl.replace(/^ws(s?):\/\//, "http$1://").replace(/\/node-gateway.*$/, "");
58458
58693
  function installBinary() {
58459
- fs19.mkdirSync(path18.dirname(BIN_FILE), { recursive: true });
58460
- fs19.copyFileSync(process.argv[1], BIN_FILE);
58461
- fs19.mkdirSync(path18.dirname(LOCAL_BIN), { recursive: true });
58462
- fs19.writeFileSync(LOCAL_BIN, `#!/bin/sh
58694
+ fs20.mkdirSync(path19.dirname(BIN_FILE), { recursive: true });
58695
+ fs20.copyFileSync(process.argv[1], BIN_FILE);
58696
+ fs20.mkdirSync(path19.dirname(LOCAL_BIN), { recursive: true });
58697
+ fs20.writeFileSync(LOCAL_BIN, `#!/bin/sh
58463
58698
  exec node "${BIN_FILE}" "$@"
58464
58699
  `, { mode: 493 });
58465
58700
  }
58466
58701
  function setupAutostart() {
58467
58702
  const cmd = `${process.execPath} "${BIN_FILE}" --_daemon`;
58468
- const home = os10.homedir();
58703
+ const home = os11.homedir();
58469
58704
  const extraBins = [
58470
- path18.join(home, ".npm-global", "bin"),
58471
- path18.join(home, ".local", "bin"),
58705
+ path19.join(home, ".npm-global", "bin"),
58706
+ path19.join(home, ".local", "bin"),
58472
58707
  "/usr/local/bin"
58473
58708
  ];
58474
58709
  const daemonPath = [process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":");
58475
58710
  if (process.platform === "linux") {
58476
- const unitDir = path18.join(os10.homedir(), ".config", "systemd", "user");
58477
- fs19.mkdirSync(unitDir, { recursive: true });
58478
- fs19.writeFileSync(path18.join(unitDir, "oasis-node.service"), [
58711
+ const unitDir = path19.join(os11.homedir(), ".config", "systemd", "user");
58712
+ fs20.mkdirSync(unitDir, { recursive: true });
58713
+ fs20.writeFileSync(path19.join(unitDir, "oasis-node.service"), [
58479
58714
  "[Unit]",
58480
58715
  "Description=Oasis Node Daemon",
58481
58716
  "After=network.target",
@@ -58497,9 +58732,9 @@ function setupAutostart() {
58497
58732
  } catch {
58498
58733
  }
58499
58734
  } else if (process.platform === "darwin") {
58500
- const plist = path18.join(os10.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
58501
- fs19.mkdirSync(path18.dirname(plist), { recursive: true });
58502
- fs19.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
58735
+ const plist = path19.join(os11.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
58736
+ fs20.mkdirSync(path19.dirname(plist), { recursive: true });
58737
+ fs20.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
58503
58738
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
58504
58739
  <plist version="1.0"><dict>
58505
58740
  <key>Label</key><string>com.oasis.node</string>
@@ -58516,14 +58751,14 @@ function setupAutostart() {
58516
58751
  }
58517
58752
  }
58518
58753
  function spawnDaemon() {
58519
- const log3 = fs19.openSync(LOG_FILE, "a");
58754
+ const log3 = fs20.openSync(LOG_FILE, "a");
58520
58755
  const child = (0, import_node_child_process15.spawn)(process.execPath, [BIN_FILE, "--_daemon"], {
58521
58756
  detached: true,
58522
58757
  stdio: ["ignore", log3, log3]
58523
58758
  });
58524
58759
  child.unref();
58525
58760
  const pid = child.pid ?? 0;
58526
- fs19.writeFileSync(PID_FILE, String(pid));
58761
+ fs20.writeFileSync(PID_FILE, String(pid));
58527
58762
  return pid;
58528
58763
  }
58529
58764
  function stopDaemon() {
@@ -58535,7 +58770,7 @@ function stopDaemon() {
58535
58770
  }
58536
58771
  }
58537
58772
  try {
58538
- fs19.unlinkSync(PID_FILE);
58773
+ fs20.unlinkSync(PID_FILE);
58539
58774
  } catch {
58540
58775
  }
58541
58776
  try {
@@ -58551,7 +58786,7 @@ function selfUpdate() {
58551
58786
  const cfg = readConfig();
58552
58787
  if (!cfg?.serverUrl) throw new Error("no config \u2014 run `oasis start` first");
58553
58788
  const nameArg = cfg.name ? ` --name '${cfg.name.replace(/'/g, "'\\''")}'` : "";
58554
- const oasisBin = path18.join(NPM_PREFIX, "bin", "oasis");
58789
+ const oasisBin = path19.join(NPM_PREFIX, "bin", "oasis");
58555
58790
  const startCmd = `"${oasisBin}" start --server-ws '${cfg.serverUrl}'${nameArg}`;
58556
58791
  const inner = `{ echo "[oasis] self-update \u2192 npm install --prefix ${NPM_PREFIX} ${PKG_NAME}@latest"; sleep 2; npm install -g --prefer-online --prefix '${NPM_PREFIX}' '${PKG_NAME}@latest' && ${startCmd}; } >> '${LOG_FILE}' 2>&1`;
58557
58792
  const hasSystemd = process.platform === "linux" && (() => {
@@ -58562,7 +58797,7 @@ function selfUpdate() {
58562
58797
  return false;
58563
58798
  }
58564
58799
  })();
58565
- const log3 = fs19.openSync(LOG_FILE, "a");
58800
+ const log3 = fs20.openSync(LOG_FILE, "a");
58566
58801
  if (hasSystemd) {
58567
58802
  const child = (0, import_node_child_process15.spawn)("systemd-run", ["--user", "--scope", "--quiet", "sh", "-c", inner], {
58568
58803
  detached: true,
@@ -58588,10 +58823,10 @@ void (async () => {
58588
58823
  console.error(`[oasis] daemon already running (PID ${alivePid}) \u2014 exiting duplicate`);
58589
58824
  process.exit(0);
58590
58825
  }
58591
- fs19.writeFileSync(PID_FILE, String(process.pid));
58826
+ fs20.writeFileSync(PID_FILE, String(process.pid));
58592
58827
  const cleanup = () => {
58593
58828
  try {
58594
- fs19.unlinkSync(PID_FILE);
58829
+ fs20.unlinkSync(PID_FILE);
58595
58830
  } catch {
58596
58831
  }
58597
58832
  };
@@ -58651,7 +58886,7 @@ void (async () => {
58651
58886
  const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
58652
58887
  method: "POST",
58653
58888
  headers: { "content-type": "application/json" },
58654
- body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os10.hostname() })
58889
+ body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os11.hostname() })
58655
58890
  });
58656
58891
  if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
58657
58892
  const body = await res.json();
@@ -58674,7 +58909,7 @@ void (async () => {
58674
58909
  const pid = spawnDaemon();
58675
58910
  console.log(`\u2713 daemon started (PID ${pid})${nameChanged ? ` [name updated: ${prev.name} \u2192 ${name}]` : ""}`);
58676
58911
  console.log(` logs: tail -f ${LOG_FILE}`);
58677
- if (!process.env["PATH"]?.includes(path18.dirname(LOCAL_BIN)))
58912
+ if (!process.env["PATH"]?.includes(path19.dirname(LOCAL_BIN)))
58678
58913
  console.log(` add to PATH: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc`);
58679
58914
  return;
58680
58915
  }