oasis_test 0.1.45 → 0.1.47

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 +920 -629
  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
  }
@@ -34338,15 +34362,30 @@ function priceForModel(model) {
34338
34362
  function estimateRowCost(row) {
34339
34363
  return estimateUsageCost(row.effectiveModel, row);
34340
34364
  }
34341
- function estimateUsageCost(model, usage) {
34365
+ function estimateUsageCostBreakdown(model, usage) {
34342
34366
  const price = priceForModel(model);
34343
34367
  if (!price) return null;
34344
34368
  const inputTokens = Math.max(usage.inputTokens ?? 0, 0);
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;
34349
- return { currency: price.currency, micros: Math.round(cost * 1e6) };
34372
+ const cacheReadPrice = price.cachedInputPerMillion ?? price.inputPerMillion * 0.1;
34373
+ return {
34374
+ currency: price.currency,
34375
+ inputMicros: Math.round(inputTokens * price.inputPerMillion / 1e6 * 1e6),
34376
+ cacheMicros: Math.round(
34377
+ (cacheCreationTokens * price.inputPerMillion + cacheReadTokens * cacheReadPrice) / 1e6 * 1e6
34378
+ ),
34379
+ outputMicros: Math.round(outputTokens * price.outputPerMillion / 1e6 * 1e6)
34380
+ };
34381
+ }
34382
+ function estimateUsageCost(model, usage) {
34383
+ const breakdown = estimateUsageCostBreakdown(model, usage);
34384
+ if (!breakdown) return null;
34385
+ return {
34386
+ currency: breakdown.currency,
34387
+ micros: breakdown.inputMicros + breakdown.cacheMicros + breakdown.outputMicros
34388
+ };
34350
34389
  }
34351
34390
  var FOREIGN_MODEL_MARKUP, usd, cny, MODEL_PRICES, PREFIX_PRICES;
34352
34391
  var init_model_pricing = __esm({
@@ -34461,6 +34500,30 @@ var init_model_pricing = __esm({
34461
34500
  });
34462
34501
 
34463
34502
  // ../server/src/domains/actors/stats.ts
34503
+ function emptyCostBreakdown() {
34504
+ return {
34505
+ inputUsdMicros: 0,
34506
+ cacheUsdMicros: 0,
34507
+ outputUsdMicros: 0,
34508
+ inputCnyMicros: 0,
34509
+ cacheCnyMicros: 0,
34510
+ outputCnyMicros: 0
34511
+ };
34512
+ }
34513
+ function addEstimatedBreakdown(target, model, usage) {
34514
+ const estimated = estimateUsageCostBreakdown(model, usage);
34515
+ if (!estimated) return false;
34516
+ if (estimated.currency === "USD") {
34517
+ target.inputUsdMicros += estimated.inputMicros;
34518
+ target.cacheUsdMicros += estimated.cacheMicros;
34519
+ target.outputUsdMicros += estimated.outputMicros;
34520
+ } else {
34521
+ target.inputCnyMicros += estimated.inputMicros;
34522
+ target.cacheCnyMicros += estimated.cacheMicros;
34523
+ target.outputCnyMicros += estimated.outputMicros;
34524
+ }
34525
+ return true;
34526
+ }
34464
34527
  async function actorStats(oplog, actorId, opts = {}) {
34465
34528
  const myRevisions = /* @__PURE__ */ new Set();
34466
34529
  const mergedTargets = /* @__PURE__ */ new Set();
@@ -34504,8 +34567,10 @@ async function actorStats(oplog, actorId, opts = {}) {
34504
34567
  approveRateGiven: reviewsGiven === 0 ? null : approvalsGiven / reviewsGiven,
34505
34568
  reworkReceived,
34506
34569
  tokenWeek: weeklyUsage.tokenWeek,
34570
+ tokenWeekBreakdown: weeklyUsage.tokenWeekBreakdown,
34507
34571
  costWeekUsdMicros: weeklyUsage.costWeekUsdMicros,
34508
34572
  costWeekCnyMicros: weeklyUsage.costWeekCnyMicros,
34573
+ costWeekBreakdown: weeklyUsage.costWeekBreakdown,
34509
34574
  usageWindow: { from, to },
34510
34575
  unpricedModels: weeklyUsage.unpricedModels
34511
34576
  };
@@ -34521,61 +34586,86 @@ async function listWeeklyRuns(trace, actorId, from, to) {
34521
34586
  return out;
34522
34587
  }
34523
34588
  function summarizeWeeklyRuns(runs) {
34524
- let tokenWeek = 0;
34589
+ let input = 0;
34590
+ let cache = 0;
34591
+ let output = 0;
34525
34592
  let costWeekUsdMicros = 0;
34526
34593
  let costWeekCnyMicros = 0;
34594
+ const costWeekBreakdown = emptyCostBreakdown();
34527
34595
  const unpriced = /* @__PURE__ */ new Set();
34528
34596
  for (const run of runs) {
34529
34597
  const usage = run.usage;
34530
34598
  if (!usage) continue;
34531
- const input = Math.max(usage.inputTokens ?? 0, 0);
34532
- const output = Math.max(usage.outputTokens ?? 0, 0);
34533
- tokenWeek += input + output;
34599
+ const inputTokens = Math.max(usage.inputTokens ?? 0, 0);
34600
+ const outputTokens = Math.max(usage.outputTokens ?? 0, 0);
34601
+ const cacheCreation = Math.max(usage.cacheCreationTokens ?? 0, 0);
34602
+ const cacheRead = Math.max(usage.cacheReadTokens ?? 0, 0);
34603
+ input += inputTokens;
34604
+ cache += cacheCreation + cacheRead;
34605
+ output += outputTokens;
34606
+ const priced = addEstimatedBreakdown(costWeekBreakdown, run.effectiveModel ?? null, usage);
34607
+ const storedCost = Math.max(usage.costUsdMicros ?? 0, 0);
34608
+ if (storedCost > 0) {
34609
+ costWeekUsdMicros += storedCost;
34610
+ continue;
34611
+ }
34534
34612
  const estimated = estimateUsageCost(run.effectiveModel, usage);
34535
34613
  if (estimated) {
34536
34614
  if (estimated.currency === "USD") costWeekUsdMicros += estimated.micros;
34537
34615
  else costWeekCnyMicros += estimated.micros;
34538
34616
  continue;
34539
34617
  }
34540
- const storedCost = Math.max(usage.costUsdMicros ?? 0, 0);
34541
- if (storedCost > 0) {
34542
- costWeekUsdMicros += storedCost;
34543
- } else if (input + output > 0) {
34618
+ if (!priced && inputTokens + outputTokens + cacheCreation + cacheRead > 0) {
34544
34619
  unpriced.add(run.effectiveModel ?? "unknown");
34545
34620
  }
34546
34621
  }
34547
34622
  return {
34548
- tokenWeek,
34623
+ tokenWeek: input + cache + output,
34624
+ tokenWeekBreakdown: { input, cache, output },
34549
34625
  costWeekUsdMicros,
34550
34626
  costWeekCnyMicros,
34627
+ costWeekBreakdown,
34551
34628
  unpricedModels: [...unpriced].sort()
34552
34629
  };
34553
34630
  }
34554
34631
  function summarizeWeeklyUsage(rows) {
34555
- let tokenWeek = 0;
34632
+ let input = 0;
34633
+ let cache = 0;
34634
+ let output = 0;
34556
34635
  let costWeekUsdMicros = 0;
34557
34636
  let costWeekCnyMicros = 0;
34637
+ const costWeekBreakdown = emptyCostBreakdown();
34558
34638
  const unpriced = /* @__PURE__ */ new Set();
34559
34639
  for (const row of rows) {
34560
- const input = Math.max(row.inputTokens, 0);
34561
- const output = Math.max(row.outputTokens, 0);
34562
- tokenWeek += input + output;
34640
+ const inputTokens = Math.max(row.inputTokens, 0);
34641
+ const outputTokens = Math.max(row.outputTokens, 0);
34642
+ const cacheCreation = Math.max(row.cacheCreationTokens, 0);
34643
+ const cacheRead = Math.max(row.cacheReadTokens, 0);
34644
+ input += inputTokens;
34645
+ cache += cacheCreation + cacheRead;
34646
+ output += outputTokens;
34647
+ const priced = addEstimatedBreakdown(costWeekBreakdown, row.effectiveModel, row);
34648
+ const storedCost = Math.max(row.costUsdMicros, 0);
34649
+ if (storedCost > 0) {
34650
+ costWeekUsdMicros += storedCost;
34651
+ continue;
34652
+ }
34563
34653
  const estimated = estimateRowCost(row);
34564
34654
  if (estimated) {
34565
34655
  if (estimated.currency === "USD") costWeekUsdMicros += estimated.micros;
34566
34656
  else costWeekCnyMicros += estimated.micros;
34567
34657
  continue;
34568
34658
  }
34569
- if (row.costUsdMicros > 0) {
34570
- costWeekUsdMicros += row.costUsdMicros;
34571
- } else if (input + output > 0) {
34659
+ if (!priced && inputTokens + outputTokens + cacheCreation + cacheRead > 0) {
34572
34660
  unpriced.add(row.effectiveModel ?? "unknown");
34573
34661
  }
34574
34662
  }
34575
34663
  return {
34576
- tokenWeek,
34664
+ tokenWeek: input + cache + output,
34665
+ tokenWeekBreakdown: { input, cache, output },
34577
34666
  costWeekUsdMicros,
34578
34667
  costWeekCnyMicros,
34668
+ costWeekBreakdown,
34579
34669
  unpricedModels: [...unpriced].sort()
34580
34670
  };
34581
34671
  }
@@ -36770,27 +36860,188 @@ var init_sender = __esm({
36770
36860
  }
36771
36861
  });
36772
36862
 
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
- }
36863
+ // ../adapters/src/open-design/driver.ts
36779
36864
  function deriveBoardKey(artifactId) {
36780
36865
  const tail = artifactId.split(":").pop() ?? artifactId;
36781
36866
  const ascii = tail.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 24);
36782
36867
  const sha8 = (0, import_node_crypto10.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
36783
36868
  return ascii ? `od-${ascii}-${sha8}` : `od-${sha8}`;
36784
36869
  }
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"() {
36870
+ async function odApi(base, fetchImpl, method, p2, body) {
36871
+ const res = await fetchImpl(`${base}${p2}`, {
36872
+ method,
36873
+ ...body !== void 0 ? { body: JSON.stringify(body), headers: { "content-type": "application/json" } } : {}
36874
+ });
36875
+ if (!res.ok) throw new Error(`od ${method} ${p2} \u2192 ${res.status}: ${(await res.text()).slice(0, 200)}`);
36876
+ return await res.json();
36877
+ }
36878
+ async function ensureProject(base, fetchImpl, boardKey, title) {
36879
+ let conversationId = null;
36880
+ try {
36881
+ const created = await odApi(base, fetchImpl, "POST", "/api/projects", { id: boardKey, name: title });
36882
+ conversationId = created.conversationId ?? null;
36883
+ } catch {
36884
+ }
36885
+ if (!conversationId) {
36886
+ const c = await odApi(base, fetchImpl, "GET", `/api/projects/${encodeURIComponent(boardKey)}/conversations`);
36887
+ conversationId = c.conversations?.[0]?.id ?? null;
36888
+ }
36889
+ if (!conversationId) throw new Error(`od \u9879\u76EE ${boardKey} \u65E0\u53EF\u7528\u4F1A\u8BDD`);
36890
+ let resolvedDir = null;
36891
+ try {
36892
+ const d = await odApi(base, fetchImpl, "GET", `/api/projects/${encodeURIComponent(boardKey)}`);
36893
+ resolvedDir = d.resolvedDir ?? null;
36894
+ } catch {
36895
+ }
36896
+ return { conversationId, resolvedDir };
36897
+ }
36898
+ function materializeContext(resolvedDir, files) {
36899
+ if (!resolvedDir) return;
36900
+ fs6.mkdirSync(resolvedDir, { recursive: true });
36901
+ const root = path5.join(resolvedDir, "task-context");
36902
+ fs6.rmSync(root, { recursive: true, force: true });
36903
+ for (const [rel, content] of Object.entries(files)) {
36904
+ const f2 = path5.join(root, rel);
36905
+ fs6.mkdirSync(path5.dirname(f2), { recursive: true });
36906
+ fs6.writeFileSync(f2, content);
36907
+ }
36908
+ }
36909
+ async function startDesignRun(base, fetchImpl, args) {
36910
+ const created = await odApi(base, fetchImpl, "POST", "/api/runs", {
36911
+ agentId: args.agentId,
36912
+ projectId: args.boardKey,
36913
+ conversationId: args.conversationId,
36914
+ assistantMessageId: (0, import_node_crypto10.randomUUID)(),
36915
+ clientRequestId: (0, import_node_crypto10.randomUUID)(),
36916
+ message: args.message,
36917
+ systemPrompt: args.systemPrompt
36918
+ });
36919
+ return created.runId;
36920
+ }
36921
+ async function pumpDesignEvents(base, fetchImpl, runId, onLine) {
36922
+ const res = await fetchImpl(`${base}/api/runs/${runId}/events`);
36923
+ if (!res.ok || !res.body) return;
36924
+ const reader = res.body.getReader();
36925
+ const dec2 = new TextDecoder();
36926
+ let buf = "";
36927
+ for (; ; ) {
36928
+ const { done, value } = await reader.read();
36929
+ if (done) break;
36930
+ buf += dec2.decode(value, { stream: true });
36931
+ let nl;
36932
+ while ((nl = buf.indexOf("\n")) >= 0) {
36933
+ const line = buf.slice(0, nl).trim();
36934
+ buf = buf.slice(nl + 1);
36935
+ if (line.startsWith("data:")) {
36936
+ const payload = line.slice(5).trim();
36937
+ if (payload) onLine(payload);
36938
+ }
36939
+ }
36940
+ }
36941
+ }
36942
+ async function pollDesignRun(base, fetchImpl, runId, opts = {}) {
36943
+ const interval = opts.intervalMs ?? 5e3;
36944
+ const maxMs = opts.maxMs ?? 30 * 6e4;
36945
+ const started = Date.now();
36946
+ for (; ; ) {
36947
+ await new Promise((r) => setTimeout(r, interval));
36948
+ const s2 = await odApi(base, fetchImpl, "GET", `/api/runs/${runId}`).catch(() => null);
36949
+ if (!s2) {
36950
+ 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`);
36951
+ continue;
36952
+ }
36953
+ opts.onPoll?.(s2.status);
36954
+ if (s2.status === "succeeded" || s2.status === "failed" || s2.status === "canceled") return s2.status;
36955
+ 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`);
36956
+ }
36957
+ }
36958
+ async function harvestBoard(base, fetchImpl, publicBase, workRoot, boardKey, runId) {
36959
+ const listing = await odApi(
36960
+ base,
36961
+ fetchImpl,
36962
+ "GET",
36963
+ `/api/projects/${encodeURIComponent(boardKey)}/files`
36964
+ );
36965
+ 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));
36966
+ const entry = htmls[0]?.path;
36967
+ 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");
36968
+ const dir = fs6.mkdtempSync(path5.join(workRoot, "od-deliverable-"));
36969
+ const fetchInline = async (rel) => {
36970
+ const res = await fetchImpl(`${base}/api/projects/${encodeURIComponent(boardKey)}/export/${encodeURIComponent(rel)}?inline=1`);
36971
+ if (!res.ok) throw new Error(`od export ${rel} \u2192 ${res.status}`);
36972
+ return await res.text();
36973
+ };
36974
+ fs6.writeFileSync(path5.join(dir, "index.html"), await fetchInline(entry));
36975
+ for (const f2 of listing.files ?? []) {
36976
+ if (f2.path.endsWith(".md") && !f2.path.includes("/")) {
36977
+ try {
36978
+ fs6.writeFileSync(path5.join(dir, f2.path), await fetchInline(f2.path));
36979
+ } catch {
36980
+ }
36981
+ }
36982
+ }
36983
+ fs6.writeFileSync(
36984
+ path5.join(dir, "board.link"),
36985
+ `${publicBase}/projects/${boardKey}
36986
+ \u5165\u53E3\u7A3F\uFF1A${entry}
36987
+ \u5FEB\u7167\u6765\u6E90 run\uFF1A${runId}
36988
+ \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
36989
+ `
36990
+ );
36991
+ return { dir, entry };
36992
+ }
36993
+ async function runOpenDesignSession(opts) {
36994
+ const fetchImpl = opts.fetchImpl ?? fetch;
36995
+ const workRoot = opts.workRoot ?? os.tmpdir();
36996
+ const boardKey = deriveBoardKey(opts.artifactId);
36997
+ const { conversationId, resolvedDir } = await ensureProject(opts.base, fetchImpl, boardKey, opts.title);
36998
+ if (opts.contextFiles) materializeContext(resolvedDir, opts.contextFiles);
36999
+ const runId = await startDesignRun(opts.base, fetchImpl, {
37000
+ agentId: opts.agentId,
37001
+ boardKey,
37002
+ conversationId,
37003
+ message: opts.message,
37004
+ systemPrompt: opts.systemPrompt
37005
+ });
37006
+ if (opts.onLine) void pumpDesignEvents(opts.base, fetchImpl, runId, opts.onLine).catch(() => {
37007
+ });
37008
+ const status = await pollDesignRun(opts.base, fetchImpl, runId, {
37009
+ ...opts.pollIntervalMs !== void 0 ? { intervalMs: opts.pollIntervalMs } : {},
37010
+ ...opts.pollMaxMs !== void 0 ? { maxMs: opts.pollMaxMs } : {}
37011
+ });
37012
+ if (status === "canceled") throw new Error(`od run ${runId} \u88AB\u53D6\u6D88`);
37013
+ if (status === "failed") throw new Error(`od run ${runId} \u5931\u8D25`);
37014
+ const { dir, entry } = await harvestBoard(opts.base, fetchImpl, opts.publicBase, workRoot, boardKey, runId);
37015
+ return { dir, entry, boardKey, runId };
37016
+ }
37017
+ var import_node_crypto10, fs6, os, path5;
37018
+ var init_driver = __esm({
37019
+ "../adapters/src/open-design/driver.ts"() {
36788
37020
  "use strict";
36789
37021
  import_node_crypto10 = require("node:crypto");
36790
- import_node_child_process2 = require("node:child_process");
36791
37022
  fs6 = __toESM(require("node:fs"), 1);
36792
37023
  os = __toESM(require("node:os"), 1);
36793
37024
  path5 = __toESM(require("node:path"), 1);
37025
+ }
37026
+ });
37027
+
37028
+ // ../adapters/src/open-design/index.ts
37029
+ function numEnv(name, fallback) {
37030
+ const v2 = process.env[name];
37031
+ const n = Number(v2);
37032
+ return v2 !== void 0 && v2 !== "" && Number.isFinite(n) && n > 0 ? n : fallback;
37033
+ }
37034
+ var import_node_crypto11, import_node_child_process2, fs7, os2, path6, TOOL_RESULT_SNIPPET, DELTA_FLUSH_MS, TELEMETRY_HEARTBEAT_MS, OdEventTranslator, OpenDesignAdapter;
37035
+ var init_open_design = __esm({
37036
+ "../adapters/src/open-design/index.ts"() {
37037
+ "use strict";
37038
+ import_node_crypto11 = require("node:crypto");
37039
+ import_node_child_process2 = require("node:child_process");
37040
+ fs7 = __toESM(require("node:fs"), 1);
37041
+ os2 = __toESM(require("node:os"), 1);
37042
+ path6 = __toESM(require("node:path"), 1);
37043
+ init_driver();
37044
+ init_driver();
36794
37045
  TOOL_RESULT_SNIPPET = 2e3;
36795
37046
  DELTA_FLUSH_MS = 2e4;
36796
37047
  TELEMETRY_HEARTBEAT_MS = 12e4;
@@ -36876,7 +37127,7 @@ var init_open_design = __esm({
36876
37127
  this.publicBase = (opts.publicBaseUrl ?? "https://design.open-friday.com").replace(/\/$/, "");
36877
37128
  this.agentId = opts.agentId ?? "claude";
36878
37129
  this.oasisBin = opts.oasisBin ?? "oasis";
36879
- this.workRoot = opts.workRoot ?? os.tmpdir();
37130
+ this.workRoot = opts.workRoot ?? os2.tmpdir();
36880
37131
  this.fetchImpl = opts.fetchImpl ?? fetch;
36881
37132
  this.maxConcurrent = opts.maxConcurrent ?? numEnv("OASIS_OPEN_DESIGN_MAX_CONCURRENT", 2);
36882
37133
  this.runPropose = opts.runPropose ?? (async ({ artifactId, dir, reason, serverUrl, token }) => {
@@ -36909,91 +37160,16 @@ var init_open_design = __esm({
36909
37160
  this.active--;
36910
37161
  this.waiters.shift()?.();
36911
37162
  }
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
37163
  async spawn(job) {
36988
37164
  const boardKey = deriveBoardKey(job.artifactId);
36989
- const id = `od-${boardKey}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
37165
+ const id = `od-${boardKey}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
36990
37166
  const exitCbs = [];
36991
37167
  const outputCbs = [];
36992
37168
  const telemetryCbs = [];
36993
37169
  let exited = null;
36994
37170
  let killed = false;
36995
37171
  let runId = null;
36996
- const transcriptRef = path5.join(this.workRoot, `od-transcript-${id}.ndjson`);
37172
+ const transcriptRef = path6.join(this.workRoot, `od-transcript-${id}.ndjson`);
36997
37173
  const translator = new OdEventTranslator();
36998
37174
  let eventSeq = 0;
36999
37175
  let lastTelemetryAt = Date.now();
@@ -37018,15 +37194,15 @@ var init_open_design = __esm({
37018
37194
  finish({ code: null, reason: "timeout" });
37019
37195
  return;
37020
37196
  }
37021
- const { conversationId, resolvedDir } = await this.ensureProject(boardKey, job.artifactId);
37022
- this.materializeContext(resolvedDir, job.bundle.files);
37197
+ const { conversationId, resolvedDir } = await ensureProject(this.base, this.fetchImpl, boardKey, job.artifactId);
37198
+ materializeContext(resolvedDir, job.bundle.files);
37023
37199
  const task = job.bundle.files["TASK.md"] ?? "";
37024
- const created = await this.api("POST", "/api/runs", {
37200
+ const created = await odApi(this.base, this.fetchImpl, "POST", "/api/runs", {
37025
37201
  agentId: this.agentId,
37026
37202
  projectId: boardKey,
37027
37203
  conversationId,
37028
- assistantMessageId: (0, import_node_crypto10.randomUUID)(),
37029
- clientRequestId: (0, import_node_crypto10.randomUUID)(),
37204
+ assistantMessageId: (0, import_node_crypto11.randomUUID)(),
37205
+ clientRequestId: (0, import_node_crypto11.randomUUID)(),
37030
37206
  message: task,
37031
37207
  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
37208
  });
@@ -37039,7 +37215,7 @@ var init_open_design = __esm({
37039
37215
  let status = "running";
37040
37216
  for (; ; ) {
37041
37217
  await new Promise((r) => setTimeout(r, 5e3));
37042
- const s2 = await this.api("GET", `/api/runs/${runId}`).catch(() => null);
37218
+ const s2 = await odApi(this.base, this.fetchImpl, "GET", `/api/runs/${runId}`).catch(() => null);
37043
37219
  if (!s2) continue;
37044
37220
  status = s2.status;
37045
37221
  if (status === "succeeded" || status === "failed" || status === "canceled") break;
@@ -37055,7 +37231,7 @@ var init_open_design = __esm({
37055
37231
  finish({ code: 1, reason: "error" });
37056
37232
  return;
37057
37233
  }
37058
- const { dir, entry } = await this.harvest(boardKey, runId);
37234
+ const { dir, entry } = await harvestBoard(this.base, this.fetchImpl, this.publicBase, this.workRoot, boardKey, runId);
37059
37235
  await this.runPropose({
37060
37236
  artifactId: job.artifactId,
37061
37237
  dir,
@@ -37066,7 +37242,7 @@ var init_open_design = __esm({
37066
37242
  finish({ code: 0, reason: "clean" });
37067
37243
  } catch (err) {
37068
37244
  try {
37069
- fs6.appendFileSync(transcriptRef, JSON.stringify({ kind: "adapter-error", message: String(err) }) + "\n");
37245
+ fs7.appendFileSync(transcriptRef, JSON.stringify({ kind: "adapter-error", message: String(err) }) + "\n");
37070
37246
  } catch {
37071
37247
  }
37072
37248
  finish({ code: 1, reason: "error" });
@@ -37076,7 +37252,7 @@ var init_open_design = __esm({
37076
37252
  })();
37077
37253
  const cancel = async () => {
37078
37254
  killed = true;
37079
- if (runId) await this.api("POST", `/api/runs/${runId}/cancel`).catch(() => {
37255
+ if (runId) await odApi(this.base, this.fetchImpl, "POST", `/api/runs/${runId}/cancel`).catch(() => {
37080
37256
  });
37081
37257
  };
37082
37258
  return {
@@ -37112,7 +37288,7 @@ var init_open_design = __esm({
37112
37288
  const payload = line.slice(5).trim();
37113
37289
  if (payload) {
37114
37290
  try {
37115
- fs6.appendFileSync(transcriptRef, payload + "\n");
37291
+ fs7.appendFileSync(transcriptRef, payload + "\n");
37116
37292
  } catch {
37117
37293
  }
37118
37294
  onLine(payload);
@@ -37216,26 +37392,26 @@ function classifyExit(result) {
37216
37392
  return void 0;
37217
37393
  }
37218
37394
  function conversationExists(sessionId) {
37219
- const configDir = process.env["CLAUDE_CONFIG_DIR"] || path6.join(os2.homedir(), ".claude");
37220
- const projectsDir = path6.join(configDir, "projects");
37395
+ const configDir = process.env["CLAUDE_CONFIG_DIR"] || path7.join(os3.homedir(), ".claude");
37396
+ const projectsDir = path7.join(configDir, "projects");
37221
37397
  const target = `${sessionId}.jsonl`;
37222
37398
  try {
37223
- for (const proj of fs7.readdirSync(projectsDir)) {
37224
- if (fs7.existsSync(path6.join(projectsDir, proj, target))) return true;
37399
+ for (const proj of fs8.readdirSync(projectsDir)) {
37400
+ if (fs8.existsSync(path7.join(projectsDir, proj, target))) return true;
37225
37401
  }
37226
37402
  } catch {
37227
37403
  }
37228
37404
  return false;
37229
37405
  }
37230
- var import_node_child_process3, import_node_crypto11, fs7, os2, path6, readline, ClaudeCodeAdapter;
37406
+ var import_node_child_process3, import_node_crypto12, fs8, os3, path7, readline, ClaudeCodeAdapter;
37231
37407
  var init_claude_code = __esm({
37232
37408
  "../adapters/src/claude-code/index.ts"() {
37233
37409
  "use strict";
37234
37410
  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);
37411
+ import_node_crypto12 = require("node:crypto");
37412
+ fs8 = __toESM(require("node:fs"), 1);
37413
+ os3 = __toESM(require("node:os"), 1);
37414
+ path7 = __toESM(require("node:path"), 1);
37239
37415
  readline = __toESM(require("node:readline"), 1);
37240
37416
  ClaudeCodeAdapter = class {
37241
37417
  constructor(opts = {}) {
@@ -37264,9 +37440,9 @@ var init_claude_code = __esm({
37264
37440
  }
37265
37441
  async spawn(job) {
37266
37442
  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 });
37443
+ const id = `claude-${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
37444
+ 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-"));
37445
+ fs8.mkdirSync(dir, { recursive: true });
37270
37446
  if (this.opts.syncSkills) {
37271
37447
  try {
37272
37448
  await this.opts.syncSkills({
@@ -37281,14 +37457,14 @@ var init_claude_code = __esm({
37281
37457
  }
37282
37458
  }
37283
37459
  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);
37460
+ const file = path7.join(dir, rel);
37461
+ fs8.mkdirSync(path7.dirname(file), { recursive: true });
37462
+ fs8.writeFileSync(file, content);
37287
37463
  }
37288
37464
  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"));
37465
+ const file = path7.join(dir, rel);
37466
+ fs8.mkdirSync(path7.dirname(file), { recursive: true });
37467
+ fs8.writeFileSync(file, Buffer.from(b64, "base64"));
37292
37468
  }
37293
37469
  const prompt = job.bundle.files["TASK.md"];
37294
37470
  if (!prompt) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -37320,7 +37496,7 @@ var init_claude_code = __esm({
37320
37496
  ...job.env,
37321
37497
  // BUG-4 缓冲:抬高单响应输出 token 上限(临时缓冲,根治靠分解)
37322
37498
  ...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"] ?? ""}` } : {},
37499
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path7.dirname(p2)).join(path7.delimiter)}${path7.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
37324
37500
  OASIS_SERVER: job.server.url,
37325
37501
  OASIS_TOKEN: job.actorToken,
37326
37502
  // OTel 遥测(默认关;resolveOtelEnv 决定开不开,runId 进 resource 属性自然归位到本次 run)。
@@ -37332,8 +37508,8 @@ var init_claude_code = __esm({
37332
37508
  });
37333
37509
  if (promptViaStdin) child.stdin.write(prompt);
37334
37510
  child.stdin.end();
37335
- let transcriptRef = path6.join(dir, "transcript.txt");
37336
- const out = fs7.createWriteStream(transcriptRef);
37511
+ let transcriptRef = path7.join(dir, "transcript.txt");
37512
+ const out = fs8.createWriteStream(transcriptRef);
37337
37513
  const telemetryCbs = [];
37338
37514
  let eventSeq = 0;
37339
37515
  let lastResult;
@@ -37403,14 +37579,14 @@ var init_claude_code = __esm({
37403
37579
  const reason = killedByUs ? "timeout" : classifyExit(lastResult);
37404
37580
  if (this.opts.cleanupWorkdir && !job.runtimeSessionId) {
37405
37581
  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`);
37582
+ const keepDir = path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-transcripts");
37583
+ fs8.mkdirSync(keepDir, { recursive: true });
37584
+ const kept = path7.join(keepDir, `${id}.txt`);
37409
37585
  const src = transcriptRef;
37410
37586
  out.end(() => {
37411
37587
  try {
37412
- fs7.renameSync(src, kept);
37413
- fs7.rmSync(dir, { recursive: true, force: true });
37588
+ fs8.renameSync(src, kept);
37589
+ fs8.rmSync(dir, { recursive: true, force: true });
37414
37590
  } catch {
37415
37591
  }
37416
37592
  });
@@ -37589,7 +37765,7 @@ var init_resilient = __esm({
37589
37765
 
37590
37766
  // ../adapters/src/_core/skill-cache.ts
37591
37767
  function defaultCacheRoot() {
37592
- return path7.join(os3.homedir(), ".oasis", "skill-cache");
37768
+ return path8.join(os4.homedir(), ".oasis", "skill-cache");
37593
37769
  }
37594
37770
  function sessionSkillsSubdir(runtimeKind) {
37595
37771
  return runtimeKind === "claude" || runtimeKind === "claude-code" ? ".claude/skills" : ".agent_context/skills";
@@ -37600,7 +37776,7 @@ async function syncActorSkills(opts) {
37600
37776
  });
37601
37777
  const now = opts.now ?? (() => /* @__PURE__ */ new Date());
37602
37778
  const actorDir = pathForActor(cacheRoot, opts.actorId);
37603
- const manifestPath = path7.join(actorDir, "manifest.json");
37779
+ const manifestPath = path8.join(actorDir, "manifest.json");
37604
37780
  await fsp.mkdir(actorDir, { recursive: true, mode: 493 });
37605
37781
  const release = await acquireLock(cacheRoot, opts.actorId, now, log3);
37606
37782
  try {
@@ -37618,7 +37794,7 @@ async function syncActorSkills(opts) {
37618
37794
  const cloudIds = new Set(cloudMetadata.map((s2) => s2.id));
37619
37795
  for (const cloud of cloudMetadata) {
37620
37796
  const cached2 = manifest.skills[cloud.id];
37621
- const skillDir = path7.join(actorDir, cloud.dir);
37797
+ const skillDir = path8.join(actorDir, cloud.dir);
37622
37798
  const inSync = cached2 && cached2.dir === cloud.dir && cached2.contentHash === cloud.contentHash && cached2.cloudUpdatedAt === cloud.updatedAt && await dirLooksValid(skillDir, cached2.fileList);
37623
37799
  if (inSync) {
37624
37800
  skipped += 1;
@@ -37646,7 +37822,7 @@ async function syncActorSkills(opts) {
37646
37822
  for (const [id, entry] of Object.entries(manifest.skills)) {
37647
37823
  if (cloudIds.has(id)) continue;
37648
37824
  try {
37649
- await fsp.rm(path7.join(actorDir, entry.dir), { recursive: true, force: true });
37825
+ await fsp.rm(path8.join(actorDir, entry.dir), { recursive: true, force: true });
37650
37826
  } catch (err) {
37651
37827
  log3("warn", `\u5220\u9664\u5B64\u513F\u6280\u80FD\u76EE\u5F55\u5931\u8D25 ${entry.dir}`, err);
37652
37828
  }
@@ -37663,14 +37839,14 @@ async function syncActorSkills(opts) {
37663
37839
  }
37664
37840
  }
37665
37841
  function pathForActor(cacheRoot, actorId) {
37666
- return path7.join(cacheRoot, "actors", encodeURIComponent(actorId));
37842
+ return path8.join(cacheRoot, "actors", encodeURIComponent(actorId));
37667
37843
  }
37668
37844
  function lockPathFor(cacheRoot, actorId) {
37669
- return path7.join(cacheRoot, "locks", `${encodeURIComponent(actorId)}.lock`);
37845
+ return path8.join(cacheRoot, "locks", `${encodeURIComponent(actorId)}.lock`);
37670
37846
  }
37671
37847
  async function acquireLock(cacheRoot, actorId, now, log3) {
37672
37848
  const lockPath = lockPathFor(cacheRoot, actorId);
37673
- await fsp.mkdir(path7.dirname(lockPath), { recursive: true, mode: 493 });
37849
+ await fsp.mkdir(path8.dirname(lockPath), { recursive: true, mode: 493 });
37674
37850
  const started = now().getTime();
37675
37851
  while (true) {
37676
37852
  try {
@@ -37736,26 +37912,26 @@ async function readManifest2(manifestPath, actorId, log3) {
37736
37912
  };
37737
37913
  }
37738
37914
  async function writeManifest(manifestPath, manifest) {
37739
- const dir = path7.dirname(manifestPath);
37915
+ const dir = path8.dirname(manifestPath);
37740
37916
  await fsp.mkdir(dir, { recursive: true });
37741
37917
  const tmp = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;
37742
37918
  await fsp.writeFile(tmp, JSON.stringify(manifest, null, 2), { mode: 420 });
37743
37919
  await fsp.rename(tmp, manifestPath);
37744
37920
  }
37745
37921
  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()}`);
37922
+ const targetPath = path8.join(actorDir, targetDir);
37923
+ const tmpPath = path8.join(actorDir, `${targetDir}.new.${process.pid}.${Date.now()}`);
37924
+ const oldBackup = path8.join(actorDir, `${targetDir}.old.${process.pid}.${Date.now()}`);
37749
37925
  await fsp.rm(tmpPath, { recursive: true, force: true });
37750
37926
  await fsp.mkdir(tmpPath, { recursive: true, mode: 493 });
37751
37927
  for (const f2 of files) {
37752
37928
  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)) {
37929
+ const dest = path8.join(tmpPath, f2.path);
37930
+ const rel = path8.relative(tmpPath, dest);
37931
+ if (rel.startsWith("..") || path8.isAbsolute(rel)) {
37756
37932
  throw new Error(`SkillFile.path \u4E0D\u5408\u6CD5: ${f2.path}`);
37757
37933
  }
37758
- await fsp.mkdir(path7.dirname(dest), { recursive: true });
37934
+ await fsp.mkdir(path8.dirname(dest), { recursive: true });
37759
37935
  await fsp.writeFile(dest, f2.content, { mode: 420 });
37760
37936
  }
37761
37937
  let hadOld = false;
@@ -37769,14 +37945,14 @@ async function materializeSkillDir(actorDir, targetDir, files, previousDir) {
37769
37945
  await fsp.rename(tmpPath, targetPath);
37770
37946
  if (hadOld) await fsp.rm(oldBackup, { recursive: true, force: true });
37771
37947
  if (previousDir && previousDir !== targetDir) {
37772
- await fsp.rm(path7.join(actorDir, previousDir), { recursive: true, force: true });
37948
+ await fsp.rm(path8.join(actorDir, previousDir), { recursive: true, force: true });
37773
37949
  }
37774
37950
  }
37775
37951
  async function dirLooksValid(dir, expectFileList) {
37776
37952
  if (expectFileList.length === 0) return false;
37777
37953
  try {
37778
37954
  for (const rel of expectFileList) {
37779
- await fsp.stat(path7.join(dir, rel));
37955
+ await fsp.stat(path8.join(dir, rel));
37780
37956
  }
37781
37957
  return true;
37782
37958
  } catch {
@@ -37785,18 +37961,18 @@ async function dirLooksValid(dir, expectFileList) {
37785
37961
  }
37786
37962
  async function syncSessionSymlinks(sessionDir, runtimeKind, actorDir, manifest, log3) {
37787
37963
  const subdir = sessionSkillsSubdir(runtimeKind);
37788
- const skillsDir = path7.join(sessionDir, subdir);
37964
+ const skillsDir = path8.join(sessionDir, subdir);
37789
37965
  await fsp.mkdir(skillsDir, { recursive: true, mode: 493 });
37790
37966
  const desired = /* @__PURE__ */ new Map();
37791
37967
  for (const entry of Object.values(manifest.skills)) {
37792
- desired.set(entry.dir, path7.join(actorDir, entry.dir));
37968
+ desired.set(entry.dir, path8.join(actorDir, entry.dir));
37793
37969
  }
37794
37970
  for (const [name, target] of desired) {
37795
- const link = path7.join(skillsDir, name);
37971
+ const link = path8.join(skillsDir, name);
37796
37972
  let ok = false;
37797
37973
  try {
37798
37974
  const current = await fsp.readlink(link);
37799
- ok = path7.resolve(skillsDir, current) === target;
37975
+ ok = path8.resolve(skillsDir, current) === target;
37800
37976
  } catch {
37801
37977
  }
37802
37978
  if (!ok) {
@@ -37816,19 +37992,19 @@ async function syncSessionSymlinks(sessionDir, runtimeKind, actorDir, manifest,
37816
37992
  for (const name of entries) {
37817
37993
  if (desired.has(name)) continue;
37818
37994
  try {
37819
- await fsp.rm(path7.join(skillsDir, name), { recursive: true, force: true });
37995
+ await fsp.rm(path8.join(skillsDir, name), { recursive: true, force: true });
37820
37996
  } catch (err) {
37821
37997
  log3("warn", `\u6E05\u5B64\u513F\u5931\u8D25 ${name}`, err);
37822
37998
  }
37823
37999
  }
37824
38000
  }
37825
- var fsp, os3, path7, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
38001
+ var fsp, os4, path8, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
37826
38002
  var init_skill_cache = __esm({
37827
38003
  "../adapters/src/_core/skill-cache.ts"() {
37828
38004
  "use strict";
37829
38005
  fsp = __toESM(require("node:fs/promises"), 1);
37830
- os3 = __toESM(require("node:os"), 1);
37831
- path7 = __toESM(require("node:path"), 1);
38006
+ os4 = __toESM(require("node:os"), 1);
38007
+ path8 = __toESM(require("node:path"), 1);
37832
38008
  MANIFEST_SCHEMA_VERSION = 1;
37833
38009
  STALE_LOCK_MS = 6e4;
37834
38010
  LOCK_ACQUIRE_TIMEOUT_MS = 3e4;
@@ -38197,12 +38373,12 @@ function parseCodexModel(lines) {
38197
38373
  function codexSessionsRoot() {
38198
38374
  const candidates = [];
38199
38375
  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"));
38376
+ if (ch) candidates.push(path9.join(ch, "sessions"));
38377
+ const home = process.env["HOME"] || os5.homedir();
38378
+ if (home) candidates.push(path9.join(home, ".codex", "sessions"));
38203
38379
  for (const c of candidates) {
38204
38380
  try {
38205
- if (fs8.statSync(c).isDirectory()) return c;
38381
+ if (fs9.statSync(c).isDirectory()) return c;
38206
38382
  } catch {
38207
38383
  }
38208
38384
  }
@@ -38216,13 +38392,13 @@ function codexRolloutExists(sessionId, root = codexSessionsRoot()) {
38216
38392
  if (hit) return;
38217
38393
  let ents;
38218
38394
  try {
38219
- ents = fs8.readdirSync(d, { withFileTypes: true });
38395
+ ents = fs9.readdirSync(d, { withFileTypes: true });
38220
38396
  } catch {
38221
38397
  return;
38222
38398
  }
38223
38399
  for (const ent of ents) {
38224
38400
  if (hit) return;
38225
- const p2 = path8.join(d, ent.name);
38401
+ const p2 = path9.join(d, ent.name);
38226
38402
  if (ent.isDirectory()) walk(p2);
38227
38403
  else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) {
38228
38404
  hit = true;
@@ -38239,17 +38415,17 @@ function listRecentRollouts(root, sinceMs) {
38239
38415
  const walk = (d) => {
38240
38416
  let ents;
38241
38417
  try {
38242
- ents = fs8.readdirSync(d, { withFileTypes: true });
38418
+ ents = fs9.readdirSync(d, { withFileTypes: true });
38243
38419
  } catch {
38244
38420
  return;
38245
38421
  }
38246
38422
  for (const ent of ents) {
38247
- const p2 = path8.join(d, ent.name);
38423
+ const p2 = path9.join(d, ent.name);
38248
38424
  if (ent.isDirectory()) walk(p2);
38249
38425
  else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(".jsonl")) {
38250
38426
  let m2 = 0;
38251
38427
  try {
38252
- m2 = fs8.statSync(p2).mtimeMs;
38428
+ m2 = fs9.statSync(p2).mtimeMs;
38253
38429
  } catch {
38254
38430
  }
38255
38431
  if (m2 >= margin) found.push({ f: p2, m: m2 });
@@ -38264,7 +38440,7 @@ function scanCodexTelemetry(workdir, sinceMs, sessionsRoot = codexSessionsRoot()
38264
38440
  for (const f2 of listRecentRollouts(sessionsRoot, sinceMs)) {
38265
38441
  let lines;
38266
38442
  try {
38267
- lines = fs8.readFileSync(f2, "utf8").split("\n");
38443
+ lines = fs9.readFileSync(f2, "utf8").split("\n");
38268
38444
  } catch {
38269
38445
  continue;
38270
38446
  }
@@ -38455,15 +38631,15 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
38455
38631
  tool.output.push(line);
38456
38632
  return [];
38457
38633
  }
38458
- var import_node_child_process5, import_node_crypto12, fs8, os4, path8, readline2, CodexAdapter;
38634
+ var import_node_child_process5, import_node_crypto13, fs9, os5, path9, readline2, CodexAdapter;
38459
38635
  var init_codex = __esm({
38460
38636
  "../adapters/src/codex/index.ts"() {
38461
38637
  "use strict";
38462
38638
  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);
38639
+ import_node_crypto13 = require("node:crypto");
38640
+ fs9 = __toESM(require("node:fs"), 1);
38641
+ os5 = __toESM(require("node:os"), 1);
38642
+ path9 = __toESM(require("node:path"), 1);
38467
38643
  readline2 = __toESM(require("node:readline"), 1);
38468
38644
  init_claude_code();
38469
38645
  CodexAdapter = class {
@@ -38472,13 +38648,13 @@ var init_codex = __esm({
38472
38648
  }
38473
38649
  async spawn(job) {
38474
38650
  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)}`;
38651
+ const id = `codex-${slug6}-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
38476
38652
  const startedAtMs = Date.now();
38477
- const dir = fs8.mkdtempSync(path8.join(this.opts.workRoot ?? os4.tmpdir(), "oasis-session-"));
38653
+ const dir = fs9.mkdtempSync(path9.join(this.opts.workRoot ?? os5.tmpdir(), "oasis-session-"));
38478
38654
  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);
38655
+ const file = path9.join(dir, rel);
38656
+ fs9.mkdirSync(path9.dirname(file), { recursive: true });
38657
+ fs9.writeFileSync(file, content);
38482
38658
  }
38483
38659
  const task = job.bundle.files["TASK.md"];
38484
38660
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -38507,14 +38683,14 @@ var init_codex = __esm({
38507
38683
  ...scrubLeakyEnv(process.env),
38508
38684
  ...this.opts.env,
38509
38685
  ...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"] ?? ""}` } : {},
38686
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path9.dirname(p2)).join(path9.delimiter)}${path9.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
38511
38687
  OASIS_SERVER: job.server.url,
38512
38688
  OASIS_TOKEN: job.actorToken
38513
38689
  },
38514
38690
  stdio: ["ignore", "pipe", "pipe"]
38515
38691
  });
38516
- let transcriptRef = path8.join(dir, "transcript.txt");
38517
- const out = fs8.createWriteStream(transcriptRef);
38692
+ let transcriptRef = path9.join(dir, "transcript.txt");
38693
+ const out = fs9.createWriteStream(transcriptRef);
38518
38694
  const outputCbs = [];
38519
38695
  const telemetryCbs = [];
38520
38696
  const normalizeState = createCodexNormalizeState();
@@ -38527,14 +38703,34 @@ var init_codex = __esm({
38527
38703
  for (const cb of telemetryCbs) cb(full);
38528
38704
  }
38529
38705
  };
38706
+ const stderrTail = [];
38707
+ const STDERR_MAX_LINES = 40;
38708
+ const STDERR_MAX_BYTES = 4e3;
38709
+ const pushStderrTail = (line) => {
38710
+ stderrTail.push(line);
38711
+ while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
38712
+ let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
38713
+ while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
38714
+ total -= stderrTail.shift().length + 1;
38715
+ }
38716
+ };
38717
+ const stdoutErrorLines = [];
38718
+ const pushStdoutErrorLine = (line) => {
38719
+ if (/^\s*(Error|error):/i.test(line) || /"error"\s*:/.test(line)) {
38720
+ stdoutErrorLines.push(line);
38721
+ if (stdoutErrorLines.length > 10) stdoutErrorLines.shift();
38722
+ }
38723
+ };
38530
38724
  const rl = readline2.createInterface({ input: child.stdout });
38531
38725
  rl.on("line", (line) => {
38532
38726
  out.write(line + "\n");
38727
+ pushStdoutErrorLine(line);
38533
38728
  emitNormalized(normalizeCodexStreamLine(line, normalizeState));
38534
38729
  });
38535
38730
  const errRl = readline2.createInterface({ input: child.stderr });
38536
38731
  errRl.on("line", (line) => {
38537
38732
  out.write(line + "\n");
38733
+ pushStderrTail(line);
38538
38734
  emitNormalized(normalizeCodexConsoleLine(line, consoleNormalizeState));
38539
38735
  });
38540
38736
  const callbacks = [];
@@ -38544,14 +38740,14 @@ var init_codex = __esm({
38544
38740
  if (exited) return;
38545
38741
  if (this.opts.cleanupWorkdir) {
38546
38742
  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`);
38743
+ const keepDir = path9.join(this.opts.workRoot ?? os5.tmpdir(), "oasis-transcripts");
38744
+ fs9.mkdirSync(keepDir, { recursive: true });
38745
+ const kept = path9.join(keepDir, `${id}.txt`);
38550
38746
  const src = transcriptRef;
38551
38747
  out.end(() => {
38552
38748
  try {
38553
- fs8.renameSync(src, kept);
38554
- fs8.rmSync(dir, { recursive: true, force: true });
38749
+ fs9.renameSync(src, kept);
38750
+ fs9.rmSync(dir, { recursive: true, force: true });
38555
38751
  } catch {
38556
38752
  }
38557
38753
  });
@@ -38576,13 +38772,16 @@ var init_codex = __esm({
38576
38772
  const telemetry = scanCodexTelemetry(dir, startedAtMs);
38577
38773
  const model = telemetry.model ?? job.model ?? this.opts.model;
38578
38774
  const runtimeSessionId = telemetry.sessionId ?? (job.resumeRuntimeSession ? job.runtimeSessionId : void 0);
38775
+ const isError = !killedByUs && typeof code === "number" && code !== 0;
38776
+ const errorMessage = isError ? [...stdoutErrorLines, ...stderrTail].join("\n").trim().slice(-4e3) || void 0 : void 0;
38579
38777
  finish({
38580
38778
  code: killedByUs ? null : code,
38581
38779
  reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error",
38582
38780
  transcriptRef,
38583
38781
  ...telemetry.usage ? { usage: telemetry.usage } : {},
38584
38782
  ...model ? { model } : {},
38585
- ...runtimeSessionId ? { runtimeSessionId } : {}
38783
+ ...runtimeSessionId ? { runtimeSessionId } : {},
38784
+ ...errorMessage ? { errorMessage } : {}
38586
38785
  });
38587
38786
  });
38588
38787
  return {
@@ -39096,6 +39295,13 @@ function parseArgsJSON(argsText) {
39096
39295
  return { text: t };
39097
39296
  }
39098
39297
  }
39298
+ function composeAcpErrorMessage(rpcError, stderrTail) {
39299
+ const parts = [];
39300
+ if (rpcError && rpcError.trim()) parts.push(rpcError.trim());
39301
+ if (stderrTail.length) parts.push(stderrTail.join("\n").trim());
39302
+ const combined = parts.filter(Boolean).join("\n---\n").slice(-4e3).trim();
39303
+ return combined || void 0;
39304
+ }
39099
39305
  function extractSessionID(result) {
39100
39306
  return result?.sessionId ?? "";
39101
39307
  }
@@ -39117,13 +39323,13 @@ function extractStopReason(result) {
39117
39323
  }
39118
39324
  async function runACPSession(job, cfg) {
39119
39325
  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-"));
39326
+ const binTag = path10.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
39327
+ const id = `${binTag}-${slug6}-${(0, import_node_crypto14.randomUUID)().slice(0, 8)}`;
39328
+ const dir = fs10.mkdtempSync(path10.join(cfg.workRoot ?? os6.tmpdir(), "oasis-session-"));
39123
39329
  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);
39330
+ const file = path10.join(dir, rel);
39331
+ fs10.mkdirSync(path10.dirname(file), { recursive: true });
39332
+ fs10.writeFileSync(file, content);
39127
39333
  }
39128
39334
  const task = job.bundle.files["TASK.md"];
39129
39335
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -39134,14 +39340,14 @@ async function runACPSession(job, cfg) {
39134
39340
  ...cfg.env,
39135
39341
  ...job.env,
39136
39342
  ...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"] ?? ""}` } : {},
39343
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path10.dirname(p2)).join(path10.delimiter)}${path10.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
39138
39344
  OASIS_SERVER: job.server.url,
39139
39345
  OASIS_TOKEN: job.actorToken
39140
39346
  },
39141
39347
  stdio: ["pipe", "pipe", "pipe"]
39142
39348
  });
39143
- let transcriptRef = path9.join(dir, "transcript.txt");
39144
- const transcriptOut = fs9.createWriteStream(transcriptRef);
39349
+ let transcriptRef = path10.join(dir, "transcript.txt");
39350
+ const transcriptOut = fs10.createWriteStream(transcriptRef);
39145
39351
  const outputCbs = [];
39146
39352
  const telemetryCbs = [];
39147
39353
  const exitCbs = [];
@@ -39158,14 +39364,14 @@ async function runACPSession(job, cfg) {
39158
39364
  if (capturedSessionId && !info.runtimeSessionId) info = { ...info, runtimeSessionId: capturedSessionId };
39159
39365
  if (cfg.cleanupWorkdir) {
39160
39366
  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`);
39367
+ const keepDir = path10.join(cfg.workRoot ?? os6.tmpdir(), "oasis-transcripts");
39368
+ fs10.mkdirSync(keepDir, { recursive: true });
39369
+ const kept = path10.join(keepDir, `${id}.txt`);
39164
39370
  const src = transcriptRef;
39165
39371
  transcriptOut.end(() => {
39166
39372
  try {
39167
- fs9.renameSync(src, kept);
39168
- fs9.rmSync(dir, { recursive: true, force: true });
39373
+ fs10.renameSync(src, kept);
39374
+ fs10.rmSync(dir, { recursive: true, force: true });
39169
39375
  } catch {
39170
39376
  }
39171
39377
  });
@@ -39181,7 +39387,23 @@ async function runACPSession(job, cfg) {
39181
39387
  killedByUs = true;
39182
39388
  child.kill("SIGKILL");
39183
39389
  }, job.limits.wallClockMs);
39184
- child.stderr.pipe(transcriptOut);
39390
+ const stderrTail = [];
39391
+ const STDERR_MAX_LINES = 40;
39392
+ const STDERR_MAX_BYTES = 4e3;
39393
+ const stderrRl = readline3.createInterface({ input: child.stderr });
39394
+ stderrRl.on("line", (line) => {
39395
+ try {
39396
+ transcriptOut.write(line + "\n");
39397
+ } catch {
39398
+ }
39399
+ stderrTail.push(line);
39400
+ while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
39401
+ let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
39402
+ while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
39403
+ total -= stderrTail.shift().length + 1;
39404
+ }
39405
+ });
39406
+ let lastRpcError;
39185
39407
  let streamingCurrentTurn = false;
39186
39408
  const client = new ACPClient(
39187
39409
  (line) => {
@@ -39213,14 +39435,20 @@ async function runACPSession(job, cfg) {
39213
39435
  resolve4();
39214
39436
  });
39215
39437
  });
39216
- child.on("error", () => {
39438
+ child.on("error", (err) => {
39217
39439
  clearTimeout(timer);
39218
- finish({ code: null, reason: "error", transcriptRef });
39440
+ finish({ code: null, reason: "error", transcriptRef, errorMessage: composeAcpErrorMessage(err instanceof Error ? err.message : String(err), stderrTail) });
39219
39441
  });
39220
39442
  child.on("exit", (code) => {
39221
39443
  clearTimeout(timer);
39222
39444
  void readerDone.then(() => {
39223
- finish({ code: killedByUs ? null : code, reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error", transcriptRef });
39445
+ const isError = !killedByUs && typeof code === "number" && code !== 0;
39446
+ finish({
39447
+ code: killedByUs ? null : code,
39448
+ reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error",
39449
+ transcriptRef,
39450
+ ...isError ? { errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail) } : {}
39451
+ });
39224
39452
  });
39225
39453
  });
39226
39454
  void (async () => {
@@ -39311,10 +39539,11 @@ ${task}` : task;
39311
39539
  if (!exited) finish({ code: 0, reason: "clean", transcriptRef, usage, model: actualModel });
39312
39540
  child.kill("SIGTERM");
39313
39541
  } catch (err) {
39542
+ lastRpcError = err instanceof Error ? err.message : String(err);
39314
39543
  if (!exited) {
39315
39544
  const reason = killedByUs ? "timeout" : "error";
39316
39545
  const usage = buildUsage(client.usage, estimateCost(client.usage, actualModel));
39317
- finish({ code: null, reason, transcriptRef, usage, model: actualModel });
39546
+ finish({ code: null, reason, transcriptRef, usage, model: actualModel, errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail) });
39318
39547
  }
39319
39548
  } finally {
39320
39549
  await readerDone;
@@ -39342,15 +39571,15 @@ ${task}` : task;
39342
39571
  }
39343
39572
  };
39344
39573
  }
39345
- var import_node_child_process6, import_node_crypto13, fs9, os5, path9, readline3, ACPClient;
39574
+ var import_node_child_process6, import_node_crypto14, fs10, os6, path10, readline3, ACPClient;
39346
39575
  var init_acp = __esm({
39347
39576
  "../adapters/src/_core/acp.ts"() {
39348
39577
  "use strict";
39349
39578
  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);
39579
+ import_node_crypto14 = require("node:crypto");
39580
+ fs10 = __toESM(require("node:fs"), 1);
39581
+ os6 = __toESM(require("node:os"), 1);
39582
+ path10 = __toESM(require("node:path"), 1);
39354
39583
  readline3 = __toESM(require("node:readline"), 1);
39355
39584
  init_claude_code();
39356
39585
  init_usage();
@@ -39668,12 +39897,12 @@ var init_kiro = __esm({
39668
39897
  // ../adapters/src/_core/subprocess.ts
39669
39898
  function materialize(job, workRoot) {
39670
39899
  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-"));
39900
+ const id = `${slug6}-${(0, import_node_crypto15.randomUUID)().slice(0, 8)}`;
39901
+ const dir = fs11.mkdtempSync(path11.join(workRoot ?? os7.tmpdir(), "oasis-session-"));
39673
39902
  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);
39903
+ const file = path11.join(dir, rel);
39904
+ fs11.mkdirSync(path11.dirname(file), { recursive: true });
39905
+ fs11.writeFileSync(file, content);
39677
39906
  }
39678
39907
  const task = job.bundle.files["TASK.md"];
39679
39908
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -39684,7 +39913,7 @@ function buildEnv(job, extra) {
39684
39913
  ...scrubLeakyEnv(process.env),
39685
39914
  ...extra,
39686
39915
  ...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"] ?? ""}` } : {},
39916
+ ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p2) => path11.dirname(p2)).join(path11.delimiter)}${path11.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
39688
39917
  OASIS_SERVER: job.server.url,
39689
39918
  OASIS_TOKEN: job.actorToken
39690
39919
  };
@@ -39696,14 +39925,14 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs) {
39696
39925
  if (cfg.model && !info.model) info = { ...info, model: cfg.model };
39697
39926
  if (cfg.cleanupWorkdir) {
39698
39927
  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`);
39928
+ const keepDir = path11.join(cfg.workRoot ?? os7.tmpdir(), "oasis-transcripts");
39929
+ fs11.mkdirSync(keepDir, { recursive: true });
39930
+ const kept = path11.join(keepDir, `${id}.txt`);
39702
39931
  const src = transcriptRefPtr.value;
39703
39932
  transcriptOut.end(() => {
39704
39933
  try {
39705
- fs10.renameSync(src, kept);
39706
- fs10.rmSync(dir, { recursive: true, force: true });
39934
+ fs11.renameSync(src, kept);
39935
+ fs11.rmSync(dir, { recursive: true, force: true });
39707
39936
  } catch {
39708
39937
  }
39709
39938
  });
@@ -39725,8 +39954,8 @@ function runStreamJson(job, cfg) {
39725
39954
  env: buildEnv(job, cfg.env),
39726
39955
  stdio: ["ignore", "pipe", "pipe"]
39727
39956
  });
39728
- const transcriptRefPtr = { value: path10.join(dir, "transcript.txt") };
39729
- const transcriptOut = fs10.createWriteStream(transcriptRefPtr.value);
39957
+ const transcriptRefPtr = { value: path11.join(dir, "transcript.txt") };
39958
+ const transcriptOut = fs11.createWriteStream(transcriptRefPtr.value);
39730
39959
  const outputCbs = [];
39731
39960
  const telemetryCbs = [];
39732
39961
  const exitCbs = [];
@@ -39783,8 +40012,8 @@ function runOneShotText(job, cfg) {
39783
40012
  env: buildEnv(job, cfg.env),
39784
40013
  stdio: ["ignore", "pipe", "pipe"]
39785
40014
  });
39786
- const transcriptRefPtr = { value: path10.join(dir, "transcript.txt") };
39787
- const transcriptOut = fs10.createWriteStream(transcriptRefPtr.value);
40015
+ const transcriptRefPtr = { value: path11.join(dir, "transcript.txt") };
40016
+ const transcriptOut = fs11.createWriteStream(transcriptRefPtr.value);
39788
40017
  const outputCbs = [];
39789
40018
  const exitCbs = [];
39790
40019
  const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
@@ -39823,15 +40052,15 @@ function runOneShotText(job, cfg) {
39823
40052
  }
39824
40053
  });
39825
40054
  }
39826
- var import_node_child_process7, import_node_crypto14, fs10, os6, path10, readline4;
40055
+ var import_node_child_process7, import_node_crypto15, fs11, os7, path11, readline4;
39827
40056
  var init_subprocess = __esm({
39828
40057
  "../adapters/src/_core/subprocess.ts"() {
39829
40058
  "use strict";
39830
40059
  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);
40060
+ import_node_crypto15 = require("node:crypto");
40061
+ fs11 = __toESM(require("node:fs"), 1);
40062
+ os7 = __toESM(require("node:os"), 1);
40063
+ path11 = __toESM(require("node:path"), 1);
39835
40064
  readline4 = __toESM(require("node:readline"), 1);
39836
40065
  init_claude_code();
39837
40066
  }
@@ -40235,11 +40464,11 @@ function normalizeOpenClaw(line) {
40235
40464
  }
40236
40465
  return [];
40237
40466
  }
40238
- var import_node_crypto15, OpenClawAdapter;
40467
+ var import_node_crypto16, OpenClawAdapter;
40239
40468
  var init_openclaw = __esm({
40240
40469
  "../adapters/src/openclaw/index.ts"() {
40241
40470
  "use strict";
40242
- import_node_crypto15 = require("node:crypto");
40471
+ import_node_crypto16 = require("node:crypto");
40243
40472
  init_subprocess();
40244
40473
  OpenClawAdapter = class {
40245
40474
  constructor(opts = {}) {
@@ -40257,7 +40486,7 @@ var init_openclaw = __esm({
40257
40486
  ---
40258
40487
 
40259
40488
  ${task}` : task;
40260
- const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto15.randomUUID)().slice(0, 8)}`;
40489
+ const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`;
40261
40490
  return [
40262
40491
  "agent",
40263
40492
  ...opts.mode !== "gateway" ? ["--local"] : [],
@@ -40561,7 +40790,7 @@ Write-Host " Remove : Unregister-ScheduledTask -TaskName 'OasisNode' -Confirm:$
40561
40790
  }
40562
40791
  function buildNpxCmd(p2) {
40563
40792
  const namePart = p2.nodeName ? ` --name ${p2.nodeName}` : "";
40564
- return `npx -y oasis_test@latest start --server-ws ${p2.gatewayUrl}${namePart} --enroll-token ${p2.token}`;
40793
+ return `npm install -g --prefer-online --prefix ~/.oasis/npm-global oasis_test@latest && ~/.oasis/npm-global/bin/oasis start --server-ws ${p2.gatewayUrl}${namePart} --enroll-token ${p2.token}`;
40565
40794
  }
40566
40795
  var init_connect_script = __esm({
40567
40796
  "../server/src/domains/nodes/connect-script.ts"() {
@@ -40728,7 +40957,7 @@ function nodesDomain(deps) {
40728
40957
  nodeId = incomingNodeId;
40729
40958
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
40730
40959
  } else {
40731
- nodeId = `node-${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`;
40960
+ nodeId = `node-${(0, import_node_crypto17.randomUUID)().slice(0, 8)}`;
40732
40961
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
40733
40962
  }
40734
40963
  const existingNode = await deps.nodeStore.getNode(nodeId);
@@ -40768,6 +40997,23 @@ function nodesDomain(deps) {
40768
40997
  await deps.nodeStore.deleteNode(nodeId);
40769
40998
  return { status: 200, body: { ok: true } };
40770
40999
  });
41000
+ router.get("/api/nodes/expected-daemon-version", async () => {
41001
+ const envVer = (process.env["OASIS_LATEST_NODE_DAEMON_VERSION"] ?? "").trim();
41002
+ if (envVer) return { status: 200, body: { version: envVer, source: "env" } };
41003
+ try {
41004
+ const here = (0, import_node_path2.dirname)((0, import_node_url.fileURLToPath)(__esm_import_meta_url));
41005
+ for (const rel of ["../../../../node-daemon/package.json", "../../../../../node-daemon/package.json"]) {
41006
+ try {
41007
+ const raw = (0, import_node_fs3.readFileSync)((0, import_node_path2.resolve)(here, rel), "utf8");
41008
+ const pkg = JSON.parse(raw);
41009
+ if (pkg.version) return { status: 200, body: { version: pkg.version, source: "monorepo" } };
41010
+ } catch {
41011
+ }
41012
+ }
41013
+ } catch {
41014
+ }
41015
+ return { status: 200, body: { version: null, source: null } };
41016
+ });
40771
41017
  router.post("/api/nodes/:nodeId/update", async (req) => {
40772
41018
  const nodeId = req.params["nodeId"];
40773
41019
  if (!nodeId) return { status: 400, body: { error: "missing nodeId" } };
@@ -40851,11 +41097,14 @@ function nodesDomain(deps) {
40851
41097
  });
40852
41098
  };
40853
41099
  }
40854
- var import_node_crypto16;
41100
+ var import_node_crypto17, import_node_fs3, import_node_url, import_node_path2;
40855
41101
  var init_routes4 = __esm({
40856
41102
  "../server/src/domains/nodes/routes.ts"() {
40857
41103
  "use strict";
40858
- import_node_crypto16 = require("node:crypto");
41104
+ import_node_crypto17 = require("node:crypto");
41105
+ import_node_fs3 = require("node:fs");
41106
+ import_node_url = require("node:url");
41107
+ import_node_path2 = require("node:path");
40859
41108
  init_src4();
40860
41109
  init_connect_script();
40861
41110
  }
@@ -40914,11 +41163,11 @@ var init_types3 = __esm({
40914
41163
  });
40915
41164
 
40916
41165
  // ../server/src/node-store.ts
40917
- var fs11, MemoryNodeStore, FileNodeStore;
41166
+ var fs12, MemoryNodeStore, FileNodeStore;
40918
41167
  var init_node_store = __esm({
40919
41168
  "../server/src/node-store.ts"() {
40920
41169
  "use strict";
40921
- fs11 = __toESM(require("node:fs"), 1);
41170
+ fs12 = __toESM(require("node:fs"), 1);
40922
41171
  MemoryNodeStore = class {
40923
41172
  nodes = /* @__PURE__ */ new Map();
40924
41173
  runtimes = /* @__PURE__ */ new Map();
@@ -41003,16 +41252,16 @@ var init_node_store = __esm({
41003
41252
  static async open(file) {
41004
41253
  const s2 = new _FileNodeStore(file);
41005
41254
  try {
41006
- const snap = JSON.parse(fs11.readFileSync(file, "utf8"));
41255
+ const snap = JSON.parse(fs12.readFileSync(file, "utf8"));
41007
41256
  for (const n of snap.nodes ?? []) s2.nodes.set(n.id, n);
41008
41257
  for (const r of snap.runtimes ?? []) s2.runtimes.set(r.id, r);
41009
41258
  } catch {
41010
- fs11.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
41259
+ fs12.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
41011
41260
  }
41012
41261
  return s2;
41013
41262
  }
41014
41263
  flush() {
41015
- fs11.writeFileSync(this.file, JSON.stringify({
41264
+ fs12.writeFileSync(this.file, JSON.stringify({
41016
41265
  nodes: [...this.nodes.values()],
41017
41266
  runtimes: [...this.runtimes.values()]
41018
41267
  }, null, 2));
@@ -41556,7 +41805,7 @@ var init_collab = __esm({
41556
41805
 
41557
41806
  // ../server/src/domains/collab/create-seeded-workorder.ts
41558
41807
  function makeSeededWorkorderCreator(deps) {
41559
- const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto17.randomUUID)().slice(0, 8)}`);
41808
+ const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto18.randomUUID)().slice(0, 8)}`);
41560
41809
  return async (input) => {
41561
41810
  const workspace = genWorkspace();
41562
41811
  if (input.projectId && deps.artifactState) {
@@ -41593,11 +41842,11 @@ function makeSeededWorkorderCreator(deps) {
41593
41842
  return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
41594
41843
  };
41595
41844
  }
41596
- var import_node_crypto17, enc2;
41845
+ var import_node_crypto18, enc2;
41597
41846
  var init_create_seeded_workorder = __esm({
41598
41847
  "../server/src/domains/collab/create-seeded-workorder.ts"() {
41599
41848
  "use strict";
41600
- import_node_crypto17 = require("node:crypto");
41849
+ import_node_crypto18 = require("node:crypto");
41601
41850
  init_planner();
41602
41851
  enc2 = (s2) => new TextEncoder().encode(s2);
41603
41852
  }
@@ -42623,7 +42872,7 @@ function createChatSessionsDomain(opts) {
42623
42872
  const runtimeId = await currentRuntimeId(body.aiActorId) ?? "unknown";
42624
42873
  const now = (/* @__PURE__ */ new Date()).toISOString();
42625
42874
  const session = {
42626
- id: (0, import_node_crypto18.randomUUID)(),
42875
+ id: (0, import_node_crypto19.randomUUID)(),
42627
42876
  humanActorId: req.auth.actor,
42628
42877
  aiActorId: body.aiActorId,
42629
42878
  runtimeId,
@@ -42674,7 +42923,7 @@ function createChatSessionsDomain(opts) {
42674
42923
  if (!body?.role || !body?.content) throw new ApiError(400, "BAD_REQUEST", "role and content required");
42675
42924
  if (body.role !== "user" && body.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
42676
42925
  const msg = await store.appendMessage({
42677
- id: (0, import_node_crypto18.randomUUID)(),
42926
+ id: (0, import_node_crypto19.randomUUID)(),
42678
42927
  sessionId: req.params.id,
42679
42928
  role: body.role,
42680
42929
  content: body.content,
@@ -42711,11 +42960,11 @@ function createChatSessionsDomain(opts) {
42711
42960
  });
42712
42961
  };
42713
42962
  }
42714
- var import_node_crypto18;
42963
+ var import_node_crypto19;
42715
42964
  var init_chat_sessions = __esm({
42716
42965
  "../server/src/domains/chat-sessions/index.ts"() {
42717
42966
  "use strict";
42718
- import_node_crypto18 = require("node:crypto");
42967
+ import_node_crypto19 = require("node:crypto");
42719
42968
  init_router();
42720
42969
  init_workorders();
42721
42970
  init_chat_parts();
@@ -44081,11 +44330,11 @@ function ackMsFromEnv(fallback) {
44081
44330
  const n = Number(v2);
44082
44331
  return Number.isFinite(n) && n >= 0 ? n : fallback;
44083
44332
  }
44084
- var import_node_crypto19, DaemonHubAdapter, BindingRouterAdapter;
44333
+ var import_node_crypto20, DaemonHubAdapter, BindingRouterAdapter;
44085
44334
  var init_daemon_adapter = __esm({
44086
44335
  "../server/src/daemon-adapter.ts"() {
44087
44336
  "use strict";
44088
- import_node_crypto19 = require("node:crypto");
44337
+ import_node_crypto20 = require("node:crypto");
44089
44338
  DaemonHubAdapter = class {
44090
44339
  constructor(hub, opts = {}) {
44091
44340
  this.hub = hub;
@@ -44172,7 +44421,7 @@ var init_daemon_adapter = __esm({
44172
44421
  async spawn(job) {
44173
44422
  const nodeId = job.binding?.nodeId;
44174
44423
  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)()}`;
44424
+ const dispatchId = `dispatch:${(0, import_node_crypto20.randomUUID)()}`;
44176
44425
  const entry = {
44177
44426
  nodeId,
44178
44427
  exitCbs: [],
@@ -44270,17 +44519,17 @@ var init_daemon_adapter = __esm({
44270
44519
  });
44271
44520
 
44272
44521
  // ../server/src/side-map.ts
44273
- var import_node_fs3, import_node_path2, FileSideMap;
44522
+ var import_node_fs4, import_node_path3, FileSideMap;
44274
44523
  var init_side_map = __esm({
44275
44524
  "../server/src/side-map.ts"() {
44276
44525
  "use strict";
44277
- import_node_fs3 = __toESM(require("node:fs"), 1);
44278
- import_node_path2 = __toESM(require("node:path"), 1);
44526
+ import_node_fs4 = __toESM(require("node:fs"), 1);
44527
+ import_node_path3 = __toESM(require("node:path"), 1);
44279
44528
  FileSideMap = class {
44280
44529
  constructor(file) {
44281
44530
  this.file = file;
44282
44531
  try {
44283
- const raw = JSON.parse(import_node_fs3.default.readFileSync(file, "utf8"));
44532
+ const raw = JSON.parse(import_node_fs4.default.readFileSync(file, "utf8"));
44284
44533
  for (const [k2, v2] of Object.entries(raw)) if (typeof v2 === "string") this.map.set(k2, v2);
44285
44534
  } catch {
44286
44535
  }
@@ -44298,10 +44547,10 @@ var init_side_map = __esm({
44298
44547
  }
44299
44548
  persist() {
44300
44549
  try {
44301
- import_node_fs3.default.mkdirSync(import_node_path2.default.dirname(this.file), { recursive: true });
44550
+ import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(this.file), { recursive: true });
44302
44551
  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);
44552
+ import_node_fs4.default.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.map), null, 2));
44553
+ import_node_fs4.default.renameSync(tmp, this.file);
44305
44554
  } catch {
44306
44555
  }
44307
44556
  }
@@ -44316,13 +44565,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
44316
44565
  if (sha(body) === lastPushedHash) return { kind: "echo" };
44317
44566
  return { kind: "human-edit", content: body, updatedBy: page.updatedBy };
44318
44567
  }
44319
- var import_node_crypto20, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
44568
+ var import_node_crypto21, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
44320
44569
  var init_engine = __esm({
44321
44570
  "../server/src/mirror/engine.ts"() {
44322
44571
  "use strict";
44323
- import_node_crypto20 = require("node:crypto");
44572
+ import_node_crypto21 = require("node:crypto");
44324
44573
  init_src();
44325
- sha = (s2) => (0, import_node_crypto20.createHash)("sha256").update(s2, "utf8").digest("hex");
44574
+ sha = (s2) => (0, import_node_crypto21.createHash)("sha256").update(s2, "utf8").digest("hex");
44326
44575
  enc3 = (s2) => new TextEncoder().encode(s2);
44327
44576
  dec = (b2) => new TextDecoder().decode(b2);
44328
44577
  MirrorEngine = class {
@@ -44435,22 +44684,22 @@ var init_engine = __esm({
44435
44684
  });
44436
44685
 
44437
44686
  // ../server/src/mirror/fs-state.ts
44438
- var fs13, FsMirrorStateStore;
44687
+ var fs14, FsMirrorStateStore;
44439
44688
  var init_fs_state = __esm({
44440
44689
  "../server/src/mirror/fs-state.ts"() {
44441
44690
  "use strict";
44442
- fs13 = __toESM(require("node:fs"), 1);
44691
+ fs14 = __toESM(require("node:fs"), 1);
44443
44692
  FsMirrorStateStore = class {
44444
44693
  constructor(file) {
44445
44694
  this.file = file;
44446
- if (fs13.existsSync(file)) {
44447
- const obj = JSON.parse(fs13.readFileSync(file, "utf8"));
44695
+ if (fs14.existsSync(file)) {
44696
+ const obj = JSON.parse(fs14.readFileSync(file, "utf8"));
44448
44697
  for (const [k2, v2] of Object.entries(obj)) this.map.set(k2, v2);
44449
44698
  }
44450
44699
  }
44451
44700
  map = /* @__PURE__ */ new Map();
44452
44701
  flush() {
44453
- fs13.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
44702
+ fs14.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
44454
44703
  }
44455
44704
  async get(artifactId) {
44456
44705
  return this.map.get(artifactId) ?? null;
@@ -44467,13 +44716,13 @@ var init_fs_state = __esm({
44467
44716
  });
44468
44717
 
44469
44718
  // ../server/src/git/integrate.ts
44470
- var import_node_child_process8, fs14, path12, GitRemoteIntegrator;
44719
+ var import_node_child_process8, fs15, path13, GitRemoteIntegrator;
44471
44720
  var init_integrate = __esm({
44472
44721
  "../server/src/git/integrate.ts"() {
44473
44722
  "use strict";
44474
44723
  import_node_child_process8 = require("node:child_process");
44475
- fs14 = __toESM(require("node:fs"), 1);
44476
- path12 = __toESM(require("node:path"), 1);
44724
+ fs15 = __toESM(require("node:fs"), 1);
44725
+ path13 = __toESM(require("node:path"), 1);
44477
44726
  GitRemoteIntegrator = class {
44478
44727
  constructor(remote, cloneDir, develop = "develop") {
44479
44728
  this.remote = remote;
@@ -44490,8 +44739,8 @@ var init_integrate = __esm({
44490
44739
  }
44491
44740
  /** 确保本地工作克隆存在并拉到最新远程态。幂等。 */
44492
44741
  sync() {
44493
- if (!fs14.existsSync(path12.join(this.cloneDir, ".git"))) {
44494
- fs14.mkdirSync(path12.dirname(this.cloneDir), { recursive: true });
44742
+ if (!fs15.existsSync(path13.join(this.cloneDir, ".git"))) {
44743
+ fs15.mkdirSync(path13.dirname(this.cloneDir), { recursive: true });
44495
44744
  (0, import_node_child_process8.execFileSync)("git", ["clone", "--quiet", this.remote, this.cloneDir], { env: this.env, maxBuffer: 256 * 1024 * 1024 });
44496
44745
  this.git(["config", "user.email", "oasis@local"]);
44497
44746
  this.git(["config", "user.name", "oasis"]);
@@ -44542,12 +44791,12 @@ var init_integrate = __esm({
44542
44791
  });
44543
44792
 
44544
44793
  // ../server/src/git/sync.ts
44545
- var os7, path13, slug3, GitSyncWorker;
44794
+ var os8, path14, slug3, GitSyncWorker;
44546
44795
  var init_sync = __esm({
44547
44796
  "../server/src/git/sync.ts"() {
44548
44797
  "use strict";
44549
- os7 = __toESM(require("node:os"), 1);
44550
- path13 = __toESM(require("node:path"), 1);
44798
+ os8 = __toESM(require("node:os"), 1);
44799
+ path14 = __toESM(require("node:path"), 1);
44551
44800
  init_src2();
44552
44801
  init_integrate();
44553
44802
  init_collect();
@@ -44563,8 +44812,8 @@ var init_sync = __esm({
44563
44812
  const key = repo.remote;
44564
44813
  let g2 = this.integrators.get(key);
44565
44814
  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));
44815
+ const root = this.deps.mirrorRoot ?? path14.join(os8.tmpdir(), "oasis-git-mirrors");
44816
+ const cloneDir = repo.repoDir ?? path14.join(root, slug3(repo.id));
44568
44817
  g2 = new GitRemoteIntegrator(repo.remote, cloneDir, repo.develop);
44569
44818
  this.integrators.set(key, g2);
44570
44819
  }
@@ -44605,13 +44854,13 @@ var init_sync = __esm({
44605
44854
  });
44606
44855
 
44607
44856
  // ../server/src/git/ci-provider.ts
44608
- var import_node_child_process9, fs15, path14, import_node_util, execFile, slug4, GhCiProvider;
44857
+ var import_node_child_process9, fs16, path15, import_node_util, execFile, slug4, GhCiProvider;
44609
44858
  var init_ci_provider = __esm({
44610
44859
  "../server/src/git/ci-provider.ts"() {
44611
44860
  "use strict";
44612
44861
  import_node_child_process9 = require("node:child_process");
44613
- fs15 = __toESM(require("node:fs"), 1);
44614
- path14 = __toESM(require("node:path"), 1);
44862
+ fs16 = __toESM(require("node:fs"), 1);
44863
+ path15 = __toESM(require("node:path"), 1);
44615
44864
  import_node_util = require("node:util");
44616
44865
  execFile = (0, import_node_util.promisify)(import_node_child_process9.execFile);
44617
44866
  slug4 = (id) => id.replace(/[^a-zA-Z0-9_-]+/g, "_");
@@ -44625,9 +44874,9 @@ var init_ci_provider = __esm({
44625
44874
  /** 缺则 clone(首次使用/进程重启后本地镜像不存在)——否则 git fetch 会"not a git repo"报错。同 GitRemoteIntegrator。 */
44626
44875
  ensureClone(repo) {
44627
44876
  const dir = this.repoDir(repo);
44628
- if (fs15.existsSync(path14.join(dir, ".git"))) return;
44877
+ if (fs16.existsSync(path15.join(dir, ".git"))) return;
44629
44878
  if (!repo.remote) throw new Error(`repo ${repo.id} \u65E0 remote\uFF0C\u65E0\u6CD5 clone`);
44630
- fs15.mkdirSync(path14.dirname(dir), { recursive: true });
44879
+ fs16.mkdirSync(path15.dirname(dir), { recursive: true });
44631
44880
  (0, import_node_child_process9.execFileSync)("git", ["clone", "--quiet", repo.remote, dir], { env: process.env });
44632
44881
  this.opts.log?.(`[ci] cloned ${repo.id} \u2192 ${dir}`);
44633
44882
  }
@@ -44890,11 +45139,11 @@ var init_resolve = __esm({
44890
45139
  });
44891
45140
 
44892
45141
  // ../server/src/coordinator/worker.ts
44893
- var import_node_crypto21, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_MANAGER_BODY, CoordinatorWorker;
45142
+ var import_node_crypto22, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_MANAGER_BODY, CoordinatorWorker;
44894
45143
  var init_worker = __esm({
44895
45144
  "../server/src/coordinator/worker.ts"() {
44896
45145
  "use strict";
44897
- import_node_crypto21 = require("node:crypto");
45146
+ import_node_crypto22 = require("node:crypto");
44898
45147
  init_src2();
44899
45148
  init_identity();
44900
45149
  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 +45319,7 @@ ${SHARED_GRAPH_BODY}`;
45070
45319
  return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
45071
45320
  }
45072
45321
  evaluationKey(kind, artifactId, evidence) {
45073
- const fingerprint = (0, import_node_crypto21.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
45322
+ const fingerprint = (0, import_node_crypto22.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
45074
45323
  return `${kind}:${artifactId}:${fingerprint}`;
45075
45324
  }
45076
45325
  artifactEvidence(id) {
@@ -45310,7 +45559,7 @@ ${SHARED_GRAPH_BODY}`;
45310
45559
  const token = this.deps.tokenFor(actorId, ctx);
45311
45560
  const serverUrl = this.deps.serverUrlFor ? await this.deps.serverUrlFor(ctx) : this.deps.serverUrl;
45312
45561
  const workspace = this.deps.kernel.model.artifacts.get(artifactId)?.workspace;
45313
- const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto21.randomUUID)();
45562
+ const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto22.randomUUID)();
45314
45563
  const job = {
45315
45564
  actor: actorId,
45316
45565
  actorToken: token,
@@ -45382,7 +45631,7 @@ ${SHARED_GRAPH_BODY}`;
45382
45631
  async function collectDir(root, dir, out) {
45383
45632
  const entries = await (0, import_promises.readdir)(dir, { withFileTypes: true });
45384
45633
  for (const e of entries) {
45385
- const abs = (0, import_node_path3.join)(dir, e.name);
45634
+ const abs = (0, import_node_path4.join)(dir, e.name);
45386
45635
  if (e.isDirectory()) {
45387
45636
  await collectDir(root, abs, out);
45388
45637
  } else if (e.isFile()) {
@@ -45391,7 +45640,7 @@ async function collectDir(root, dir, out) {
45391
45640
  console.warn(`[builtin-skills] skip oversized file (${info.size}B): ${abs}`);
45392
45641
  continue;
45393
45642
  }
45394
- const rel = (0, import_node_path3.relative)(root, abs).split(/[\\/]/).join("/");
45643
+ const rel = (0, import_node_path4.relative)(root, abs).split(/[\\/]/).join("/");
45395
45644
  out[rel] = await (0, import_promises.readFile)(abs, "utf8");
45396
45645
  }
45397
45646
  }
@@ -45407,7 +45656,7 @@ async function loadBuiltinSkills(skillsDir) {
45407
45656
  for (const d of dirents) {
45408
45657
  if (!d.isDirectory()) continue;
45409
45658
  const slug6 = d.name;
45410
- const skillDir = (0, import_node_path3.join)(skillsDir, slug6);
45659
+ const skillDir = (0, import_node_path4.join)(skillsDir, slug6);
45411
45660
  const files = {};
45412
45661
  try {
45413
45662
  await collectDir(skillDir, skillDir, files);
@@ -45439,12 +45688,12 @@ function sanitize(name) {
45439
45688
  const s2 = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
45440
45689
  return s2 || "skill";
45441
45690
  }
45442
- var import_promises, import_node_path3, MAX_FILE_BYTES2;
45691
+ var import_promises, import_node_path4, MAX_FILE_BYTES2;
45443
45692
  var init_builtin_skills = __esm({
45444
45693
  "../server/src/governance/builtin-skills.ts"() {
45445
45694
  "use strict";
45446
45695
  import_promises = require("node:fs/promises");
45447
- import_node_path3 = require("node:path");
45696
+ import_node_path4 = require("node:path");
45448
45697
  init_skill_fetcher();
45449
45698
  MAX_FILE_BYTES2 = 1 << 20;
45450
45699
  }
@@ -47099,15 +47348,15 @@ var require_pg_connection_string = __commonJS({
47099
47348
  if (config2.sslcert || config2.sslkey || config2.sslrootcert || config2.sslmode) {
47100
47349
  config2.ssl = {};
47101
47350
  }
47102
- const fs20 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
47351
+ const fs21 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
47103
47352
  if (config2.sslcert) {
47104
- config2.ssl.cert = fs20.readFileSync(config2.sslcert).toString();
47353
+ config2.ssl.cert = fs21.readFileSync(config2.sslcert).toString();
47105
47354
  }
47106
47355
  if (config2.sslkey) {
47107
- config2.ssl.key = fs20.readFileSync(config2.sslkey).toString();
47356
+ config2.ssl.key = fs21.readFileSync(config2.sslkey).toString();
47108
47357
  }
47109
47358
  if (config2.sslrootcert) {
47110
- config2.ssl.ca = fs20.readFileSync(config2.sslrootcert).toString();
47359
+ config2.ssl.ca = fs21.readFileSync(config2.sslrootcert).toString();
47111
47360
  }
47112
47361
  if (options.useLibpqCompat && config2.uselibpqcompat) {
47113
47362
  throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
@@ -48872,7 +49121,7 @@ var require_split2 = __commonJS({
48872
49121
  var require_helper = __commonJS({
48873
49122
  "../../node_modules/.pnpm/pgpass@1.0.5/node_modules/pgpass/lib/helper.js"(exports2, module2) {
48874
49123
  "use strict";
48875
- var path19 = require("path");
49124
+ var path20 = require("path");
48876
49125
  var Stream = require("stream").Stream;
48877
49126
  var split = require_split2();
48878
49127
  var util2 = require("util");
@@ -48911,7 +49160,7 @@ var require_helper = __commonJS({
48911
49160
  };
48912
49161
  module2.exports.getFileName = function(rawEnv) {
48913
49162
  var env = rawEnv || process.env;
48914
- var file = env.PGPASSFILE || (isWin ? path19.join(env.APPDATA || "./", "postgresql", "pgpass.conf") : path19.join(env.HOME || "./", ".pgpass"));
49163
+ var file = env.PGPASSFILE || (isWin ? path20.join(env.APPDATA || "./", "postgresql", "pgpass.conf") : path20.join(env.HOME || "./", ".pgpass"));
48915
49164
  return file;
48916
49165
  };
48917
49166
  module2.exports.usePgPass = function(stats, fname) {
@@ -49043,16 +49292,16 @@ var require_helper = __commonJS({
49043
49292
  var require_lib = __commonJS({
49044
49293
  "../../node_modules/.pnpm/pgpass@1.0.5/node_modules/pgpass/lib/index.js"(exports2, module2) {
49045
49294
  "use strict";
49046
- var path19 = require("path");
49047
- var fs20 = require("fs");
49295
+ var path20 = require("path");
49296
+ var fs21 = require("fs");
49048
49297
  var helper = require_helper();
49049
49298
  module2.exports = function(connInfo, cb) {
49050
49299
  var file = helper.getFileName();
49051
- fs20.stat(file, function(err, stat3) {
49300
+ fs21.stat(file, function(err, stat3) {
49052
49301
  if (err || !helper.usePgPass(stat3, file)) {
49053
49302
  return cb(void 0);
49054
49303
  }
49055
- var st = fs20.createReadStream(file);
49304
+ var st = fs21.createReadStream(file);
49056
49305
  helper.getPassword(connInfo, st, cb);
49057
49306
  });
49058
49307
  };
@@ -50605,38 +50854,38 @@ __export(trajectory_exports, {
50605
50854
  exportTrajectories: () => exportTrajectories
50606
50855
  });
50607
50856
  async function exportTrajectories(dataDir) {
50608
- const root = path15.join(dataDir, "trajectories");
50609
- if (!fs16.existsSync(root)) return [];
50857
+ const root = path16.join(dataDir, "trajectories");
50858
+ if (!fs17.existsSync(root)) return [];
50610
50859
  const model = emptyReadModel();
50611
- const oplogFile = path15.join(dataDir, "oplog.ndjson");
50612
- if (fs16.existsSync(oplogFile)) {
50860
+ const oplogFile = path16.join(dataDir, "oplog.ndjson");
50861
+ if (fs17.existsSync(oplogFile)) {
50613
50862
  const oplog = await NdjsonOplogStore.open(oplogFile);
50614
50863
  for await (const entry of oplog.readAll()) fold(model, entry.op);
50615
50864
  }
50616
50865
  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"));
50866
+ for (const sessionId of fs17.readdirSync(root).sort()) {
50867
+ const dir = path16.join(root, sessionId);
50868
+ const sessionFile = path16.join(dir, "session.json");
50869
+ if (!fs17.existsSync(sessionFile)) continue;
50870
+ const session = JSON.parse(fs17.readFileSync(sessionFile, "utf8"));
50622
50871
  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")) {
50872
+ const eventsFile = path16.join(dir, "events.ndjson");
50873
+ if (fs17.existsSync(eventsFile)) {
50874
+ for (const line of fs17.readFileSync(eventsFile, "utf8").split("\n")) {
50626
50875
  if (line.trim()) events.push(JSON.parse(line));
50627
50876
  }
50628
50877
  }
50629
50878
  const bundle = {};
50630
- const bundleDir = path15.join(dir, "bundle");
50879
+ const bundleDir = path16.join(dir, "bundle");
50631
50880
  const walk = (sub) => {
50632
- for (const name of fs16.readdirSync(path15.join(bundleDir, sub))) {
50881
+ for (const name of fs17.readdirSync(path16.join(bundleDir, sub))) {
50633
50882
  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");
50883
+ const full = path16.join(bundleDir, rel);
50884
+ if (fs17.statSync(full).isDirectory()) walk(rel);
50885
+ else bundle[rel] = fs17.readFileSync(full, "utf8");
50637
50886
  }
50638
50887
  };
50639
- if (fs16.existsSync(bundleDir)) walk("");
50888
+ if (fs17.existsSync(bundleDir)) walk("");
50640
50889
  const proposed = (session.opRefs ?? []).filter((r) => r.kind === "propose_revision").map((r) => r.target);
50641
50890
  const verdicts = proposed.flatMap(
50642
50891
  (rev) => (model.reviews.get(rev) ?? []).map((v2) => ({ author: v2.author, verdict: v2.verdict, ...v2.note !== void 0 ? { note: v2.note } : {} }))
@@ -50648,51 +50897,51 @@ async function exportTrajectories(dataDir) {
50648
50897
  }
50649
50898
  return samples;
50650
50899
  }
50651
- var fs16, path15, FsTrajectorySink;
50900
+ var fs17, path16, FsTrajectorySink;
50652
50901
  var init_trajectory = __esm({
50653
50902
  "../cli/src/trajectory.ts"() {
50654
50903
  "use strict";
50655
- fs16 = __toESM(require("node:fs"), 1);
50656
- path15 = __toESM(require("node:path"), 1);
50904
+ fs17 = __toESM(require("node:fs"), 1);
50905
+ path16 = __toESM(require("node:path"), 1);
50657
50906
  init_src2();
50658
50907
  init_src5();
50659
50908
  FsTrajectorySink = class {
50660
50909
  constructor(dataDir, broadcast) {
50661
50910
  this.broadcast = broadcast;
50662
- this.root = path15.join(dataDir, "trajectories");
50911
+ this.root = path16.join(dataDir, "trajectories");
50663
50912
  }
50664
50913
  root;
50665
50914
  dir(sessionId) {
50666
- return path15.join(this.root, sessionId);
50915
+ return path16.join(this.root, sessionId);
50667
50916
  }
50668
50917
  begin(session, bundleFiles) {
50669
50918
  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));
50919
+ fs17.mkdirSync(path16.join(dir, "bundle"), { recursive: true });
50920
+ fs17.writeFileSync(path16.join(dir, "session.json"), JSON.stringify(session, null, 2));
50672
50921
  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);
50922
+ const file = path16.join(dir, "bundle", rel);
50923
+ fs17.mkdirSync(path16.dirname(file), { recursive: true });
50924
+ fs17.writeFileSync(file, content);
50676
50925
  }
50677
50926
  this.broadcast?.({ type: "begin", sessionId: session.sessionId, data: session });
50678
50927
  }
50679
50928
  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));
50929
+ fs17.mkdirSync(this.dir(session.sessionId), { recursive: true });
50930
+ const file = path16.join(this.dir(session.sessionId), "session.json");
50931
+ if (!fs17.existsSync(file)) fs17.writeFileSync(file, JSON.stringify(session, null, 2));
50683
50932
  this.broadcast?.({ type: "begin", sessionId: session.sessionId, data: { ...session, recovered: true } });
50684
50933
  }
50685
50934
  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");
50935
+ fs17.mkdirSync(this.dir(sessionId), { recursive: true });
50936
+ fs17.appendFileSync(path16.join(this.dir(sessionId), "events.ndjson"), JSON.stringify(event) + "\n");
50688
50937
  this.broadcast?.({ type: "event", sessionId, data: event });
50689
50938
  }
50690
50939
  end(sessionId, update) {
50691
- const file = path15.join(this.dir(sessionId), "session.json");
50692
- const session = JSON.parse(fs16.readFileSync(file, "utf8"));
50940
+ const file = path16.join(this.dir(sessionId), "session.json");
50941
+ const session = JSON.parse(fs17.readFileSync(file, "utf8"));
50693
50942
  session.exit = update.exit;
50694
50943
  session.opRefs = update.opRefs;
50695
- fs16.writeFileSync(file, JSON.stringify(session, null, 2));
50944
+ fs17.writeFileSync(file, JSON.stringify(session, null, 2));
50696
50945
  this.broadcast?.({ type: "end", sessionId, data: session });
50697
50946
  }
50698
50947
  };
@@ -50700,30 +50949,30 @@ var init_trajectory = __esm({
50700
50949
  });
50701
50950
 
50702
50951
  // src/index.ts
50703
- var fs19 = __toESM(require("node:fs"));
50704
- var os10 = __toESM(require("node:os"));
50705
- var path18 = __toESM(require("node:path"));
50952
+ var fs20 = __toESM(require("node:fs"));
50953
+ var os11 = __toESM(require("node:os"));
50954
+ var path19 = __toESM(require("node:path"));
50706
50955
  var import_node_child_process15 = require("node:child_process");
50707
50956
 
50708
50957
  // ../cli/src/cli.ts
50958
+ var fs19 = __toESM(require("node:fs"), 1);
50959
+ var os10 = __toESM(require("node:os"), 1);
50960
+ var path18 = __toESM(require("node:path"), 1);
50961
+ var import_node_crypto27 = require("node:crypto");
50962
+
50963
+ // ../cli/src/serve.ts
50709
50964
  var fs18 = __toESM(require("node:fs"), 1);
50710
50965
  var os9 = __toESM(require("node:os"), 1);
50711
50966
  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");
50967
+ var import_node_crypto25 = require("node:crypto");
50968
+ var import_node_url4 = require("node:url");
50720
50969
  init_src2();
50721
50970
  init_src5();
50722
50971
 
50723
50972
  // ../connectors/src/_base/stage.ts
50724
- var import_node_fs4 = require("node:fs");
50973
+ var import_node_fs5 = require("node:fs");
50725
50974
  var import_node_os2 = require("node:os");
50726
- var import_node_path4 = require("node:path");
50975
+ var import_node_path5 = require("node:path");
50727
50976
  var stagedBinDirs = /* @__PURE__ */ new Map();
50728
50977
  function stageConnectorWrapper(connector) {
50729
50978
  const scriptPath = connector.wrapperScriptPath();
@@ -50734,10 +50983,10 @@ function stageConnectorWrapper(connector) {
50734
50983
  }
50735
50984
  const cacheKey = `${commandName}\0${scriptPath}`;
50736
50985
  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);
50986
+ if (cached2 && (0, import_node_fs5.existsSync)((0, import_node_path5.join)(cached2, commandName))) return (0, import_node_path5.join)(cached2, commandName);
50987
+ const binDir = (0, import_node_fs5.mkdtempSync)((0, import_node_path5.join)((0, import_node_os2.tmpdir)(), `oasis-conn-${connector.config.slug}-`));
50988
+ const link = (0, import_node_path5.join)(binDir, commandName);
50989
+ (0, import_node_fs5.symlinkSync)(scriptPath, link);
50741
50990
  stagedBinDirs.set(cacheKey, binDir);
50742
50991
  return link;
50743
50992
  }
@@ -50831,7 +51080,7 @@ async function ensureConnectorTools(tools, deps = {}) {
50831
51080
  // ../connectors/src/_base/cli-connector.ts
50832
51081
  var import_node_child_process11 = require("node:child_process");
50833
51082
  var import_node_util3 = require("node:util");
50834
- var import_node_path5 = require("node:path");
51083
+ var import_node_path6 = require("node:path");
50835
51084
  var execFile3 = (0, import_node_util3.promisify)(import_node_child_process11.execFile);
50836
51085
  var CliConnector = class {
50837
51086
  constructor(wrapperDir) {
@@ -50843,7 +51092,7 @@ var CliConnector = class {
50843
51092
  * The wrapper is a bash script that shadows the real CLI on PATH.
50844
51093
  */
50845
51094
  wrapperScriptPath() {
50846
- return (0, import_node_path5.join)(this.wrapperDir, "wrapper.sh");
51095
+ return (0, import_node_path6.join)(this.wrapperDir, "wrapper.sh");
50847
51096
  }
50848
51097
  /**
50849
51098
  * Resolve the absolute path to a CLI binary using `which`.
@@ -50878,15 +51127,15 @@ var CliConnector = class {
50878
51127
  // ../connectors/src/feishu/index.ts
50879
51128
  var import_node_child_process12 = require("node:child_process");
50880
51129
  var import_node_util4 = require("node:util");
50881
- var import_node_path6 = require("node:path");
50882
- var import_node_url = require("node:url");
51130
+ var import_node_path7 = require("node:path");
51131
+ var import_node_url2 = require("node:url");
50883
51132
  var import_promises2 = require("node:fs/promises");
50884
51133
  var import_node_os3 = require("node:os");
50885
51134
  function shSingleQuote(v2) {
50886
51135
  return `'${v2.replace(/'/g, `'\\''`)}'`;
50887
51136
  }
50888
51137
  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));
51138
+ var __dirname = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(__esm_import_meta_url));
50890
51139
  var FeishuConnector = class extends CliConnector {
50891
51140
  config = {
50892
51141
  slug: "feishu",
@@ -50926,8 +51175,8 @@ var FeishuConnector = class extends CliConnector {
50926
51175
  if (!appId) throw new Error("feishu inject: missing app_id");
50927
51176
  if (!appSecret) throw new Error("feishu inject: missing app_secret");
50928
51177
  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");
51178
+ const dir = await (0, import_promises2.mkdtemp)((0, import_node_path7.join)((0, import_node_os3.tmpdir)(), "oasis-feishu-"));
51179
+ const credsFile = (0, import_node_path7.join)(dir, "creds.env");
50931
51180
  const lines = [
50932
51181
  `export LARKSUITE_CLI_APP_ID=${shSingleQuote(appId)}`,
50933
51182
  `export LARKSUITE_CLI_APP_SECRET=${shSingleQuote(appSecret)}`
@@ -50982,11 +51231,11 @@ var FeishuConnector = class extends CliConnector {
50982
51231
  };
50983
51232
 
50984
51233
  // ../connectors/src/github/index.ts
50985
- var import_node_path7 = require("node:path");
50986
- var import_node_url2 = require("node:url");
51234
+ var import_node_path8 = require("node:path");
51235
+ var import_node_url3 = require("node:url");
50987
51236
  var import_promises3 = require("node:fs/promises");
50988
51237
  var import_node_os4 = require("node:os");
50989
- var __dirname2 = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(__esm_import_meta_url));
51238
+ var __dirname2 = (0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(__esm_import_meta_url));
50990
51239
  function shSingleQuote2(v2) {
50991
51240
  return `'${v2.replace(/'/g, `'\\''`)}'`;
50992
51241
  }
@@ -51024,8 +51273,8 @@ var GithubConnector = class extends CliConnector {
51024
51273
  const token = credentials["access_token"];
51025
51274
  if (!token) throw new Error("github inject: missing access_token");
51026
51275
  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");
51276
+ const dir = await (0, import_promises3.mkdtemp)((0, import_node_path8.join)((0, import_node_os4.tmpdir)(), "oasis-github-"));
51277
+ const credsFile = (0, import_node_path8.join)(dir, "creds.env");
51029
51278
  await (0, import_promises3.writeFile)(
51030
51279
  credsFile,
51031
51280
  `export GH_TOKEN=${shSingleQuote2(token)}
@@ -51065,7 +51314,7 @@ export GITHUB_TOKEN=${shSingleQuote2(token)}
51065
51314
  // ../connectors/src/connector-adapter.ts
51066
51315
  var import_promises4 = require("node:fs/promises");
51067
51316
  var import_node_os5 = require("node:os");
51068
- var import_node_path8 = require("node:path");
51317
+ var import_node_path9 = require("node:path");
51069
51318
  init_src4();
51070
51319
 
51071
51320
  // ../connectors/src/logger.ts
@@ -51095,11 +51344,11 @@ var ConnectorAwareAdapter = class {
51095
51344
  );
51096
51345
  let extraEnv = { ...strippedEnv };
51097
51346
  if (wrapperPaths.length > 0) {
51098
- const wrapperBinDir = await (0, import_promises4.mkdtemp)((0, import_node_path8.join)((0, import_node_os5.tmpdir)(), "oasis-wrappers-"));
51347
+ const wrapperBinDir = await (0, import_promises4.mkdtemp)((0, import_node_path9.join)((0, import_node_os5.tmpdir)(), "oasis-wrappers-"));
51099
51348
  await (0, import_promises4.mkdir)(wrapperBinDir, { recursive: true });
51100
51349
  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));
51350
+ const linkName = (0, import_node_path9.basename)(wp).replace(/\.sh$/, "");
51351
+ await (0, import_promises4.symlink)(wp, (0, import_node_path9.join)(wrapperBinDir, linkName));
51103
51352
  }
51104
51353
  extraEnv = { ...extraEnv, PATH: `${wrapperBinDir}:${process.env["PATH"] ?? ""}` };
51105
51354
  log("[adapter]", ` connectors injected +${Date.now() - t0}ms wrappers=${wrapperPaths.length} env_keys=${Object.keys(job.env ?? {}).join(",")}`);
@@ -51632,7 +51881,7 @@ function defaultDocumentPath2(input) {
51632
51881
  init_src4();
51633
51882
 
51634
51883
  // ../storage/src/postgres.ts
51635
- var import_node_crypto22 = require("node:crypto");
51884
+ var import_node_crypto23 = require("node:crypto");
51636
51885
 
51637
51886
  // ../../node_modules/.pnpm/pg@8.21.0/node_modules/pg/esm/index.mjs
51638
51887
  var import_lib = __toESM(require_lib2(), 1);
@@ -51767,7 +52016,7 @@ var PostgresBlobStore = class _PostgresBlobStore {
51767
52016
  return new _PostgresBlobStore(pool, schema);
51768
52017
  }
51769
52018
  async put(bytes) {
51770
- const hash = (0, import_node_crypto22.createHash)("sha256").update(bytes).digest("hex");
52019
+ const hash = (0, import_node_crypto23.createHash)("sha256").update(bytes).digest("hex");
51771
52020
  await this.pool.query(
51772
52021
  `INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
51773
52022
  [hash, Buffer.from(bytes), bytes.byteLength, sniffContentType(bytes) ?? null]
@@ -54760,7 +55009,7 @@ var rowToMessage = (row) => ({
54760
55009
  });
54761
55010
 
54762
55011
  // ../storage/src/postgres-nodes.ts
54763
- var import_node_crypto23 = require("node:crypto");
55012
+ var import_node_crypto24 = require("node:crypto");
54764
55013
  var ident8 = (s2) => {
54765
55014
  if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
54766
55015
  return s2;
@@ -54898,7 +55147,7 @@ var PostgresNodeTokenStore = class _PostgresNodeTokenStore {
54898
55147
  return store;
54899
55148
  }
54900
55149
  issue(nodeId) {
54901
- const token = `ont_${(0, import_node_crypto23.randomBytes)(24).toString("base64url")}`;
55150
+ const token = `ont_${(0, import_node_crypto24.randomBytes)(24).toString("base64url")}`;
54902
55151
  this.cache.set(token, nodeId);
54903
55152
  void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
54904
55153
  return token;
@@ -54940,8 +55189,8 @@ init_trajectory();
54940
55189
  function builtinSkillsDir() {
54941
55190
  const override = process.env["OASIS_BUILTIN_SKILLS_DIR"]?.trim();
54942
55191
  if (override) return override;
54943
- const repoRoot = (0, import_node_url3.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
54944
- return path16.join(repoRoot, "skills");
55192
+ const repoRoot = (0, import_node_url4.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
55193
+ return path17.join(repoRoot, "skills");
54945
55194
  }
54946
55195
  function materializeBuiltins(builtins, runtimeKind) {
54947
55196
  if (builtins.length === 0) return {};
@@ -54973,16 +55222,16 @@ function apiUrlFromGatewayUrl(raw) {
54973
55222
  }
54974
55223
  var oasisWrapperCache;
54975
55224
  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
55225
+ if (oasisWrapperCache && fs18.existsSync(oasisWrapperCache)) return oasisWrapperCache;
55226
+ const repoRoot = (0, import_node_url4.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
55227
+ const tsx = path17.join(repoRoot, "node_modules/.bin/tsx");
55228
+ const main = path17.join(repoRoot, "packages/cli/src/main.ts");
55229
+ const dir = fs18.mkdtempSync(path17.join(os9.tmpdir(), "oasis-cli-"));
55230
+ const wrapper = path17.join(dir, "oasis");
55231
+ fs18.writeFileSync(wrapper, `#!/usr/bin/env bash
54983
55232
  exec ${JSON.stringify(tsx)} ${JSON.stringify(main)} "$@"
54984
55233
  `);
54985
- fs17.chmodSync(wrapper, 493);
55234
+ fs18.chmodSync(wrapper, 493);
54986
55235
  oasisWrapperCache = wrapper;
54987
55236
  return wrapper;
54988
55237
  }
@@ -55069,26 +55318,26 @@ function traceRuntimeKind(runtimeKind) {
55069
55318
  }
55070
55319
  async function startServe(opts) {
55071
55320
  const serverStartedAt = (/* @__PURE__ */ new Date()).toISOString();
55072
- fs17.mkdirSync(opts.dir, { recursive: true });
55073
- const serverHeartbeatFile = path16.join(opts.dir, "serve-heartbeat.json");
55321
+ fs18.mkdirSync(opts.dir, { recursive: true });
55322
+ const serverHeartbeatFile = path17.join(opts.dir, "serve-heartbeat.json");
55074
55323
  let previousServerHeartbeatAt;
55075
- if (fs17.existsSync(serverHeartbeatFile)) {
55324
+ if (fs18.existsSync(serverHeartbeatFile)) {
55076
55325
  try {
55077
- const raw = JSON.parse(fs17.readFileSync(serverHeartbeatFile, "utf8"));
55326
+ const raw = JSON.parse(fs18.readFileSync(serverHeartbeatFile, "utf8"));
55078
55327
  if (raw.at && Number.isFinite(Date.parse(raw.at))) previousServerHeartbeatAt = raw.at;
55079
55328
  } catch {
55080
55329
  }
55081
55330
  }
55082
55331
  const writeServerHeartbeat = () => {
55083
- fs17.writeFile(serverHeartbeatFile, JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), pid: process.pid }) + "\n", () => {
55332
+ fs18.writeFile(serverHeartbeatFile, JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), pid: process.pid }) + "\n", () => {
55084
55333
  });
55085
55334
  };
55086
55335
  writeServerHeartbeat();
55087
55336
  const serverHeartbeatTimer = setInterval(writeServerHeartbeat, 5e3);
55088
55337
  serverHeartbeatTimer.unref?.();
55089
- const lock = path16.join(opts.dir, "serve.lock");
55090
- if (fs17.existsSync(lock)) {
55091
- const pid = Number(fs17.readFileSync(lock, "utf8"));
55338
+ const lock = path17.join(opts.dir, "serve.lock");
55339
+ if (fs18.existsSync(lock)) {
55340
+ const pid = Number(fs18.readFileSync(lock, "utf8"));
55092
55341
  let alive = false;
55093
55342
  try {
55094
55343
  process.kill(pid, 0);
@@ -55096,19 +55345,19 @@ async function startServe(opts) {
55096
55345
  } catch {
55097
55346
  }
55098
55347
  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);
55348
+ fs18.unlinkSync(lock);
55100
55349
  }
55101
- fs17.writeFileSync(lock, String(process.pid));
55350
+ fs18.writeFileSync(lock, String(process.pid));
55102
55351
  const loadJson = (name) => {
55103
- const file = path16.join(opts.dir, name);
55104
- return fs17.existsSync(file) ? JSON.parse(fs17.readFileSync(file, "utf8")) : void 0;
55352
+ const file = path17.join(opts.dir, name);
55353
+ return fs18.existsSync(file) ? JSON.parse(fs18.readFileSync(file, "utf8")) : void 0;
55105
55354
  };
55106
55355
  const pgDsn = process.env["OASIS_PG_DSN"] ?? process.env["DATABASE_URL"];
55107
55356
  const pgSchema = process.env["OASIS_PG_SCHEMA"] ?? "public";
55108
55357
  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"));
55358
+ const oplog = pgDsn && pgPool ? await PostgresOplogStore.open(pgPool, pgSchema) : await NdjsonOplogStore.open(path17.join(opts.dir, "oplog.ndjson"));
55359
+ const blobs = pgDsn && pgPool ? await PostgresBlobStore.open(pgPool, pgSchema) : new DirBlobStore(path17.join(opts.dir, "blobs"));
55360
+ const assets = new DirBlobStore(path17.join(opts.dir, "assets"));
55112
55361
  const defaultRootSchema = [
55113
55362
  { 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
55363
  {
@@ -55126,7 +55375,7 @@ async function startServe(opts) {
55126
55375
  if (!schema.some((d) => d.name === "document")) {
55127
55376
  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
55377
  }
55129
- const typeStore = await FileTypeRegistryStore.open(path16.join(opts.dir, "type-registry.json"));
55378
+ const typeStore = await FileTypeRegistryStore.open(path17.join(opts.dir, "type-registry.json"));
55130
55379
  if ((await typeStore.list()).length === 0) for (const d of schema) await typeStore.put(d);
55131
55380
  {
55132
55381
  const live = await typeStore.list();
@@ -55134,7 +55383,7 @@ async function startServe(opts) {
55134
55383
  schema.length = 0;
55135
55384
  schema.push(...live);
55136
55385
  }
55137
- const registryStore = pgDsn && pgPool ? await PostgresRegistryStore.open(pgPool, pgSchema) : await FileRegistryStore.open(path16.join(opts.dir, "registry-store.json"));
55386
+ const registryStore = pgDsn && pgPool ? await PostgresRegistryStore.open(pgPool, pgSchema) : await FileRegistryStore.open(path17.join(opts.dir, "registry-store.json"));
55138
55387
  try {
55139
55388
  await backfillSkillContentFromAssets(registryStore, assets);
55140
55389
  } catch (err) {
@@ -55158,17 +55407,17 @@ async function startServe(opts) {
55158
55407
  // per-contentType merge facet(§5.6):text=expensive→group-commit、code/structured=cheap→顺序 rebase
55159
55408
  handlers: defaultHandlersByContentType()
55160
55409
  });
55161
- const issuer = createTokenIssuer({ secretFile: path16.join(opts.dir, "session-token-secret") });
55162
- const operatorActor = `actor:human:${os8.userInfo().username}`;
55410
+ const issuer = createTokenIssuer({ secretFile: path17.join(opts.dir, "session-token-secret") });
55411
+ const operatorActor = `actor:human:${os9.userInfo().username}`;
55163
55412
  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");
55413
+ fs18.writeFileSync(path17.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
55414
+ let nodeTokens = createNodeTokenStore(path17.join(opts.dir, "node-tokens.json"));
55415
+ const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path17.join(opts.dir, "enroll-tokens.json"));
55416
+ let nodeStore = await FileNodeStore.open(path17.join(opts.dir, "nodes.json"));
55417
+ const registryAuditFile = path17.join(opts.dir, "registry-audit.ndjson");
55169
55418
  const registryListeners = /* @__PURE__ */ new Set();
55170
55419
  const registryAudit = (record5) => {
55171
- fs17.appendFile(registryAuditFile, JSON.stringify(record5) + "\n", () => {
55420
+ fs18.appendFile(registryAuditFile, JSON.stringify(record5) + "\n", () => {
55172
55421
  });
55173
55422
  for (const l of registryListeners) l({ kind: record5.kind, actor: record5.actor, target: record5.target, timestamp: record5.timestamp });
55174
55423
  };
@@ -55205,9 +55454,9 @@ async function startServe(opts) {
55205
55454
  nodeTokens = await PostgresNodeTokenStore.open(pgPool, pgSchema);
55206
55455
  console.log(`[serve] \u4E8B\u5B9E/\u72B6\u6001\u4F53\u7CFB\uFF1APostgres schema=${pgSchema}\uFF08oplog / registry / blobs / artifacts / chat\uFF09`);
55207
55456
  } 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"));
55457
+ projectStateStore = await FileProjectStateStore.open(path17.join(opts.dir, "artifact-document-projects.json"));
55458
+ artifactStateStore = await FileArtifactStateStore.open(path17.join(opts.dir, "artifact-document-state.json"));
55459
+ chatSessionStore = await FileChatSessionStore.open(path17.join(opts.dir, "chat-sessions.json"));
55211
55460
  console.log("[serve] \u4EA4\u4ED8\u7269\u72B6\u6001\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
55212
55461
  console.log("[serve] \u8282\u70B9/\u8FD0\u884C\u65F6\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
55213
55462
  }
@@ -55226,7 +55475,7 @@ async function startServe(opts) {
55226
55475
  });
55227
55476
  console.log(`[serve] \u9879\u76EE\u6587\u6863\u4F53\u7CFB\uFF1AOutline ${outlineUrl}\uFF08\u6302\u5728 Team Workspace\u300C\u9879\u76EE\u300D\u4E0B\uFF09`);
55228
55477
  } else {
55229
- projectDocumentStore = await FileProjectDocumentStore.open(path16.join(opts.dir, "project-document-spaces.json"));
55478
+ projectDocumentStore = await FileProjectDocumentStore.open(path17.join(opts.dir, "project-document-spaces.json"));
55230
55479
  console.log("[serve] \u9879\u76EE\u6587\u6863\u4F53\u7CFB\uFF1A\u672C\u5730\u5185\u5B58/\u6587\u4EF6 dev store");
55231
55480
  }
55232
55481
  const registryActorNames = /* @__PURE__ */ new Map();
@@ -55260,7 +55509,7 @@ async function startServe(opts) {
55260
55509
  traceStore = await PostgresTraceStore.open(tracePool, pgSchema);
55261
55510
  console.log(`[serve] \u8FD0\u884C\u8F68\u8FF9\u4F53\u7CFB\uFF1APostgres schema=${pgSchema}${traceDsn === pgDsn ? "" : "\uFF08\u72EC\u7ACB trace \u5E93\uFF09"}`);
55262
55511
  } else {
55263
- traceStore = await FileTraceStore.open(path16.join(opts.dir, "trace"));
55512
+ traceStore = await FileTraceStore.open(path17.join(opts.dir, "trace"));
55264
55513
  console.log("[serve] \u8FD0\u884C\u8F68\u8FF9\u4F53\u7CFB\uFF1A\u672C\u5730 ndjson dev store");
55265
55514
  }
55266
55515
  traceStoreForActors = traceStore;
@@ -55280,7 +55529,7 @@ async function startServe(opts) {
55280
55529
  create: createSeededWorkorder,
55281
55530
  projectExists: async (id) => Boolean(await projectStateStore.getProject(id))
55282
55531
  });
55283
- const controlPlaneStore = pgDsn && pgPool ? await PostgresControlPlaneStore.open(pgPool, pgSchema) : await FileControlPlaneStore.open(path16.join(opts.dir, "control-plane.json"));
55532
+ const controlPlaneStore = pgDsn && pgPool ? await PostgresControlPlaneStore.open(pgPool, pgSchema) : await FileControlPlaneStore.open(path17.join(opts.dir, "control-plane.json"));
55284
55533
  const resendKey = process.env["RESEND_API_KEY"];
55285
55534
  const mailFrom = process.env["RESEND_FROM_EMAIL"] ?? process.env["OASIS_MAIL_FROM"] ?? "noreply@open-friday.com";
55286
55535
  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 +55599,12 @@ async function startServe(opts) {
55350
55599
  }
55351
55600
  return auth.sessionAccountId(headers);
55352
55601
  };
55353
- const workorderDrafts = new WorkorderDraftStore(path16.join(opts.dir, "workorder-drafts.json"));
55354
- const journalFile = path16.join(opts.dir, "dispatch-journal.ndjson");
55602
+ const workorderDrafts = new WorkorderDraftStore(path17.join(opts.dir, "workorder-drafts.json"));
55603
+ const journalFile = path17.join(opts.dir, "dispatch-journal.ndjson");
55355
55604
  const journalRing = [];
55356
- if (fs17.existsSync(journalFile)) {
55605
+ if (fs18.existsSync(journalFile)) {
55357
55606
  try {
55358
- const lines = fs17.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean);
55607
+ const lines = fs18.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean);
55359
55608
  for (const line of lines.slice(-500)) {
55360
55609
  try {
55361
55610
  journalRing.push(JSON.parse(line));
@@ -55368,7 +55617,7 @@ async function startServe(opts) {
55368
55617
  const journal = (entry) => {
55369
55618
  journalRing.push(entry);
55370
55619
  if (journalRing.length > 500) journalRing.shift();
55371
- fs17.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
55620
+ fs18.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
55372
55621
  });
55373
55622
  };
55374
55623
  const closeOrphanedDispatches = () => {
@@ -55395,7 +55644,7 @@ async function startServe(opts) {
55395
55644
  defaultEngine: { kernel, oplog, blobs, registry: registryStore, assets },
55396
55645
  defaultCompanyId,
55397
55646
  buildEngine: async (companyId) => {
55398
- const engine2 = await openFileEngine(path16.join(opts.dir, "companies", companyEngineDirName(companyId)), { schema });
55647
+ const engine2 = await openFileEngine(path17.join(opts.dir, "companies", companyEngineDirName(companyId)), { schema });
55399
55648
  await ensureCompanyActors(controlPlaneStore, companyId, engine2.registry);
55400
55649
  await syncRegistryRolesToKernel(engine2.registry, engine2.kernel);
55401
55650
  return engine2;
@@ -55512,7 +55761,7 @@ async function startServe(opts) {
55512
55761
  return {};
55513
55762
  }));
55514
55763
  const limits = { wallClockMs: SESSION_WALL_CLOCK_MS.planner };
55515
- const artifactId = `artifact:planner:${(0, import_node_crypto24.randomUUID)()}`;
55764
+ const artifactId = `artifact:planner:${(0, import_node_crypto25.randomUUID)()}`;
55516
55765
  const handle = await chatRemoteAdapter.spawn({
55517
55766
  actor: planner.id,
55518
55767
  actorToken: issueSessionToken(planner.id, { artifactId, action: "plan-workorder", limits, binding }),
@@ -55620,7 +55869,7 @@ async function startServe(opts) {
55620
55869
  },
55621
55870
  retainedSession: (key) => key.annotationId && key.artifactId ? allDispatchers().map((d) => d.retainedProduceSessionFor(key.artifactId)).find(Boolean) : coordinatorRef?.retainedSessionFor(key),
55622
55871
  // 0030 D3/D7 落盘:discuss 按项表写文件,serve 重启后同一卡点续同一段、不再新开。
55623
- discussSessions: new FileSideMap(path16.join(opts.dir, "discuss-sessions.json")),
55872
+ discussSessions: new FileSideMap(path17.join(opts.dir, "discuss-sessions.json")),
55624
55873
  dispatchChat: async ({ actorId, message, sessionId, chatSessionId, attachments, workspace, companyId }) => {
55625
55874
  const runCompanyId = companyId ?? defaultCompanyId;
55626
55875
  const actorCtxForCompany = await actors.resolveCtx(runCompanyId);
@@ -55642,10 +55891,10 @@ async function startServe(opts) {
55642
55891
  if (!localUrl) {
55643
55892
  throw new ApiError(503, "SERVER_URL_NOT_READY", "server URL \u5C1A\u672A\u5C31\u7EEA");
55644
55893
  }
55645
- const runtimeSessionId = sessionId ?? (0, import_node_crypto24.randomUUID)();
55894
+ const runtimeSessionId = sessionId ?? (0, import_node_crypto25.randomUUID)();
55646
55895
  const resumeRuntimeSession = Boolean(sessionId);
55647
- const traceRunId = `chat-run:${(0, import_node_crypto24.randomUUID)()}`;
55648
- const artifactId = `artifact:chat:${(0, import_node_crypto24.randomUUID)()}`;
55896
+ const traceRunId = `chat-run:${(0, import_node_crypto25.randomUUID)()}`;
55897
+ const artifactId = `artifact:chat:${(0, import_node_crypto25.randomUUID)()}`;
55649
55898
  const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
55650
55899
  let traceSeq = 0;
55651
55900
  let traceEnabled = true;
@@ -55846,7 +56095,13 @@ async function startServe(opts) {
55846
56095
  }
55847
56096
  });
55848
56097
  if (info.code === 0) resolve4();
55849
- else reject(new Error(`runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`));
56098
+ else {
56099
+ const detail = info.errorMessage?.trim();
56100
+ const generic = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
56101
+ reject(new Error(detail ? `${generic}
56102
+
56103
+ ${detail}` : generic));
56104
+ }
55850
56105
  });
55851
56106
  });
55852
56107
  return {
@@ -55890,7 +56145,7 @@ async function startServe(opts) {
55890
56145
  console.log(`[serve] \u8FDC\u7A0B agent API URL\uFF1A${remoteApiUrl ?? "\u672A\u914D\u7F6E\uFF08\u4EC5\u652F\u6301\u672C\u673A runtime\uFF09"}`);
55891
56146
  const projectsCfg = loadJson("projects.json");
55892
56147
  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
56148
+ (p2) => p2.repos?.length ? { ...p2, repos: p2.repos.map((r) => r.repoDir ? { ...r, repoDir: path17.resolve(opts.dir, r.repoDir) } : r) } : p2
55894
56149
  );
55895
56150
  for (const sp of seedProjects) {
55896
56151
  const existing = await projectStateStore.getProject(sp.id);
@@ -56021,8 +56276,8 @@ async function startServe(opts) {
56021
56276
  // 每 agent 并发产出上限默认 5(工单数 / 全局总量默认不限);--max-produce-per-agent N 覆盖。
56022
56277
  maxConcurrentProducePerActor: opts.maxConcurrentProducePerActor ?? 5,
56023
56278
  // 提案 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`))
56279
+ annotationRescue: new FileSideMap(path17.join(opts.dir, `annotation-rescue.${companyId}.json`)),
56280
+ produceSessions: new FileSideMap(path17.join(opts.dir, `produce-sessions.${companyId}.json`))
56026
56281
  });
56027
56282
  const slot = { dispatcher: d, logged: 0, ticking: false };
56028
56283
  dispatchers.set(companyId, slot);
@@ -56208,7 +56463,7 @@ async function startServe(opts) {
56208
56463
  schema: schemaMap,
56209
56464
  mirrors: new Map(opts.mirror.connectors.map((c) => [c.platform, c])),
56210
56465
  identities: opts.mirror.identities ?? new MapMirrorIdentities(),
56211
- state: new FsMirrorStateStore(path16.join(opts.dir, "mirror-state.json")),
56466
+ state: new FsMirrorStateStore(path17.join(opts.dir, "mirror-state.json")),
56212
56467
  ...opts.mirror.debounceMs !== void 0 ? { debounceMs: opts.mirror.debounceMs } : {},
56213
56468
  log: (m2) => console.log(m2)
56214
56469
  });
@@ -56220,7 +56475,7 @@ async function startServe(opts) {
56220
56475
  if (opts.dispatch) {
56221
56476
  if (ciGateEnabled) {
56222
56477
  const ci = new GhCiProvider({
56223
- mirrorRoot: path16.join(opts.dir, "git-mirrors"),
56478
+ mirrorRoot: path17.join(opts.dir, "git-mirrors"),
56224
56479
  failClosedWhenNoChecks: process.env["OASIS_CI_FAIL_CLOSED"] === "1",
56225
56480
  log: (m2) => console.log(m2)
56226
56481
  });
@@ -56232,7 +56487,7 @@ async function startServe(opts) {
56232
56487
  const gitSync = new GitSyncWorker({
56233
56488
  kernel,
56234
56489
  resolveProject,
56235
- mirrorRoot: path16.join(opts.dir, "git-mirrors"),
56490
+ mirrorRoot: path17.join(opts.dir, "git-mirrors"),
56236
56491
  log: (m2) => console.log(m2)
56237
56492
  });
56238
56493
  gitTimer = setInterval(() => {
@@ -56295,7 +56550,7 @@ async function startServe(opts) {
56295
56550
  // 病历里展示节点的"在跑会话情况"(runId + 跑了多久):从派发器在途会话按 artifactId 过滤。
56296
56551
  sessionsOf: (id) => allDispatchers().flatMap((d) => d.inFlightSessions()).filter((s2) => s2.artifactId === id).map((s2) => ({ runId: s2.sessionId, action: s2.action, startedAt: s2.startedAt })),
56297
56552
  log: (m2) => console.log(m2),
56298
- retention: new FileSideMap(path16.join(opts.dir, "retained-sessions.json"))
56553
+ retention: new FileSideMap(path17.join(opts.dir, "retained-sessions.json"))
56299
56554
  // 0030 D7 落盘
56300
56555
  });
56301
56556
  coordinatorRef = coordinator;
@@ -56406,7 +56661,7 @@ async function startServe(opts) {
56406
56661
  await server.close();
56407
56662
  if (pgPool) await pgPool.end().catch(() => {
56408
56663
  });
56409
- fs17.rmSync(lock, { force: true });
56664
+ fs18.rmSync(lock, { force: true });
56410
56665
  }
56411
56666
  };
56412
56667
  }
@@ -56842,13 +57097,13 @@ async function startNode(opts) {
56842
57097
 
56843
57098
  // ../cli/src/daemon/machine-id.ts
56844
57099
  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");
57100
+ var import_node_fs6 = require("node:fs");
57101
+ var import_node_crypto26 = require("node:crypto");
56847
57102
  var import_node_os7 = require("node:os");
56848
57103
  function linuxMachineId() {
56849
57104
  for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
56850
57105
  try {
56851
- const v2 = (0, import_node_fs5.readFileSync)(p2, "utf8").trim();
57106
+ const v2 = (0, import_node_fs6.readFileSync)(p2, "utf8").trim();
56852
57107
  if (v2) return v2;
56853
57108
  } catch {
56854
57109
  }
@@ -56909,13 +57164,14 @@ var defaultSources = {
56909
57164
  function resolveNodeId(sources = {}) {
56910
57165
  const s2 = { ...defaultSources, ...sources };
56911
57166
  const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
56912
- const digest = (0, import_node_crypto25.createHash)("sha256").update(material).digest("hex").slice(0, 12);
57167
+ const digest = (0, import_node_crypto26.createHash)("sha256").update(material).digest("hex").slice(0, 12);
56913
57168
  return `node-${digest}`;
56914
57169
  }
56915
57170
 
56916
57171
  // ../cli/src/cli.ts
56917
57172
  init_src5();
56918
57173
  init_src();
57174
+ init_src4();
56919
57175
  var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uFF08\u670D\u52A1\u7AEF\u7626\u5BA2\u6237\u7AEF\uFF09
56920
57176
 
56921
57177
  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 +57208,9 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
56952
57208
  reject <artifactId> <revisionId> --reason <text>
56953
57209
  conclude <artifactId> [--note <text>] # \u673A\u68B0 grounding \u786C\u62E6\uFF1B\u6709 gate \u5219\u8FDB\u5165\u5F85\u5BA1
56954
57210
  review <artifactId> --verdict approve|request_changes [--note <t>]
57211
+ design run <artifactId> [--brief <t>] [--reason <t>] [--od-url <url>] [--title <t>] [--agent <id>]
57212
+ # 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
57213
+ # --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
57214
 
56956
57215
  \u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09
56957
57216
  annotate <artifactId> --body <text> [--from <\u4E0B\u6E38> --blocks true]
@@ -57075,8 +57334,8 @@ function makeClient(base, token) {
57075
57334
  if (!res.ok) await fail(res);
57076
57335
  return (await res.json()).data;
57077
57336
  },
57078
- async request(method, path19, body) {
57079
- const res = await fetch(`${base}${path19}`, {
57337
+ async request(method, path20, body) {
57338
+ const res = await fetch(`${base}${path20}`, {
57080
57339
  method,
57081
57340
  headers,
57082
57341
  ...body !== void 0 ? { body: JSON.stringify(body) } : {}
@@ -57084,8 +57343,8 @@ function makeClient(base, token) {
57084
57343
  if (!res.ok) await fail(res);
57085
57344
  return await res.json();
57086
57345
  },
57087
- async post(path19, body) {
57088
- const res = await fetch(`${base}${path19}`, { method: "POST", headers, body: JSON.stringify(body) });
57346
+ async post(path20, body) {
57347
+ const res = await fetch(`${base}${path20}`, { method: "POST", headers, body: JSON.stringify(body) });
57089
57348
  if (!res.ok) await fail(res);
57090
57349
  return await res.json();
57091
57350
  }
@@ -57098,62 +57357,62 @@ async function runCli(argv, println = console.log) {
57098
57357
  return;
57099
57358
  }
57100
57359
  const { positional, flags } = parseArgs(rest);
57101
- const dir = flags.get("dir") ?? process.env["OASIS_DIR"] ?? path17.resolve(".oasis");
57360
+ const dir = flags.get("dir") ?? process.env["OASIS_DIR"] ?? path18.resolve(".oasis");
57102
57361
  if (command === "node" && positional[0] !== "output") {
57103
57362
  const serverUrl = flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? "ws://127.0.0.1:7320/node-gateway";
57104
57363
  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;
57364
+ const nodeIdFile = path18.join(dir, "node-id");
57365
+ const nodeTokenFile = path18.join(dir, "node-token");
57366
+ const enrollTokenFile = path18.join(dir, "enroll-token");
57367
+ const reportMarkerFile = path18.join(dir, "report-runtimes");
57368
+ const persistedNodeId = fs19.existsSync(nodeIdFile) ? fs19.readFileSync(nodeIdFile, "utf8").trim() : null;
57110
57369
  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);
57370
+ let token2 = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? (fs19.existsSync(nodeTokenFile) ? fs19.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
57371
+ const enrollToken = flags.get("enroll-token") ?? process.env["OASIS_ENROLL_TOKEN"] ?? (fs19.existsSync(enrollTokenFile) ? fs19.readFileSync(enrollTokenFile, "utf8").trim() : void 0);
57113
57372
  let freshEnrollment = false;
57114
57373
  if (!token2 && enrollToken) {
57115
57374
  const httpBase2 = serverUrl.replace(/^ws(s?):\/\//, "http$1://").replace(/\/node-gateway.*$/, "");
57116
57375
  const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
57117
57376
  method: "POST",
57118
57377
  headers: { "content-type": "application/json" },
57119
- body: JSON.stringify({ enrollToken, nodeId, hostname: os9.hostname() })
57378
+ body: JSON.stringify({ enrollToken, nodeId, hostname: os10.hostname() })
57120
57379
  });
57121
57380
  if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
57122
57381
  const body = await res.json();
57123
57382
  nodeId = body.nodeId;
57124
57383
  token2 = body.token;
57125
- fs18.mkdirSync(dir, { recursive: true });
57126
- fs18.writeFileSync(nodeIdFile, nodeId);
57127
- fs18.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57384
+ fs19.mkdirSync(dir, { recursive: true });
57385
+ fs19.writeFileSync(nodeIdFile, nodeId);
57386
+ fs19.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57128
57387
  try {
57129
- fs18.unlinkSync(enrollTokenFile);
57388
+ fs19.unlinkSync(enrollTokenFile);
57130
57389
  } catch {
57131
57390
  }
57132
57391
  freshEnrollment = true;
57133
57392
  }
57134
57393
  if (!nodeId) throw new Error("no nodeId \u2014 provide --enroll-token <ent_...> on first run");
57135
- const scriptRun = freshEnrollment || fs18.existsSync(reportMarkerFile);
57394
+ const scriptRun = freshEnrollment || fs19.existsSync(reportMarkerFile);
57136
57395
  if (flags.has("service")) {
57137
57396
  const { spawnSync, execSync: execSync2 } = await import("node:child_process");
57138
57397
  if (token2) {
57139
- fs18.mkdirSync(dir, { recursive: true });
57140
- fs18.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57398
+ fs19.mkdirSync(dir, { recursive: true });
57399
+ fs19.writeFileSync(nodeTokenFile, token2, { mode: 384 });
57141
57400
  }
57142
57401
  if (scriptRun) {
57143
- fs18.mkdirSync(dir, { recursive: true });
57144
- fs18.writeFileSync(reportMarkerFile, "");
57402
+ fs19.mkdirSync(dir, { recursive: true });
57403
+ fs19.writeFileSync(reportMarkerFile, "");
57145
57404
  }
57146
57405
  println("\u2192 Installing oasis_test globally...");
57147
57406
  spawnSync("npm", ["install", "-g", "oasis_test@latest"], { stdio: "inherit" });
57148
57407
  const prefix = execSync2("npm prefix -g").toString().trim();
57149
- const binPath = path17.join(prefix, "bin", "oasis_test");
57408
+ const binPath = path18.join(prefix, "bin", "oasis_test");
57150
57409
  const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
57151
57410
  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 });
57411
+ const svcFile = path18.join(os10.homedir(), ".config/systemd/user/oasis-node.service");
57412
+ fs19.mkdirSync(path18.dirname(svcFile), { recursive: true });
57154
57413
  if (spawnSync("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
57155
57414
  spawnSync("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
57156
- fs18.writeFileSync(svcFile, [
57415
+ fs19.writeFileSync(svcFile, [
57157
57416
  "[Unit]",
57158
57417
  "Description=Oasis Node Daemon",
57159
57418
  "After=network.target",
@@ -57162,7 +57421,7 @@ async function runCli(argv, println = console.log) {
57162
57421
  `ExecStart=${binPath} ${svcArgs}`,
57163
57422
  // Carry the install-time PATH so the detached daemon detects CLIs in user dirs
57164
57423
  // (~/.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`,
57424
+ `Environment=PATH=${process.env["PATH"] ?? ""}:${path18.join(os10.homedir(), ".npm-global/bin")}:${path18.join(os10.homedir(), ".local/bin")}:/usr/local/bin`,
57166
57425
  "Restart=on-failure",
57167
57426
  "RestartSec=5",
57168
57427
  "StandardOutput=journal",
@@ -57174,31 +57433,31 @@ async function runCli(argv, println = console.log) {
57174
57433
  ].join("\n"));
57175
57434
  spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
57176
57435
  spawnSync("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
57177
- spawnSync("loginctl", ["enable-linger", os9.userInfo().username], { stdio: "ignore" });
57436
+ spawnSync("loginctl", ["enable-linger", os10.userInfo().username], { stdio: "ignore" });
57178
57437
  println("\u2713 Oasis node service started (systemd --user oasis-node)");
57179
57438
  println(" Status : systemctl --user status oasis-node");
57180
57439
  println(" Logs : journalctl --user -u oasis-node -f");
57181
57440
  println(" Stop : systemctl --user stop oasis-node");
57182
57441
  } 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 });
57442
+ const plist = path18.join(os10.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
57443
+ fs19.mkdirSync(path18.dirname(plist), { recursive: true });
57185
57444
  spawnSync("launchctl", ["unload", plist], { stdio: "ignore" });
57186
57445
  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>`);
57446
+ 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
57447
  spawnSync("launchctl", ["load", plist], { stdio: "inherit" });
57189
57448
  println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
57190
- println(` Logs : tail -f ${os9.homedir()}/.oasis-node.log`);
57449
+ println(` Logs : tail -f ${os10.homedir()}/.oasis-node.log`);
57191
57450
  println(` Stop : launchctl unload ${plist}`);
57192
57451
  } else {
57193
- spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path17.join(os9.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
57452
+ spawnSync("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path18.join(os10.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
57194
57453
  println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
57195
57454
  println(" Note: no automatic restart on reboot in this environment.");
57196
57455
  }
57197
57456
  return;
57198
57457
  }
57199
- if (fs18.existsSync(reportMarkerFile)) {
57458
+ if (fs19.existsSync(reportMarkerFile)) {
57200
57459
  try {
57201
- fs18.unlinkSync(reportMarkerFile);
57460
+ fs19.unlinkSync(reportMarkerFile);
57202
57461
  } catch {
57203
57462
  }
57204
57463
  }
@@ -57206,14 +57465,14 @@ async function runCli(argv, println = console.log) {
57206
57465
  return;
57207
57466
  }
57208
57467
  if (command === "node-token") {
57209
- const store = createNodeTokenStore(path17.join(dir, "node-tokens.json"));
57468
+ const store = createNodeTokenStore(path18.join(dir, "node-tokens.json"));
57210
57469
  const sub = positional[0];
57211
57470
  if (sub === "issue") {
57212
- const id = flags.get("id") ?? `node-${(0, import_node_crypto26.randomUUID)()}`;
57471
+ const id = flags.get("id") ?? `node-${(0, import_node_crypto27.randomUUID)()}`;
57213
57472
  const token2 = store.issue(id);
57214
57473
  println(token2);
57215
57474
  process.stderr.write(
57216
- `\u5DF2\u4E3A ${id} \u7B7E\u53D1 node-token\uFF08\u5199\u5165 ${path17.join(dir, "node-tokens.json")}\uFF09\u3002
57475
+ `\u5DF2\u4E3A ${id} \u7B7E\u53D1 node-token\uFF08\u5199\u5165 ${path18.join(dir, "node-tokens.json")}\uFF09\u3002
57217
57476
  \u628A\u4E0A\u9762\u8FD9\u4E32\u653E\u5230\u8282\u70B9\u673A\uFF1A--token <t> / $OASIS_NODE_TOKEN / <\u8282\u70B9dir>/node-token
57218
57477
  `
57219
57478
  );
@@ -57234,7 +57493,7 @@ async function runCli(argv, println = console.log) {
57234
57493
  }
57235
57494
  if (command === "admin" && positional[0] === "grant-owner") {
57236
57495
  const email2 = need(flags, "email");
57237
- const store = await FileControlPlaneStore.open(path17.join(dir, "control-plane.json"));
57496
+ const store = await FileControlPlaneStore.open(path18.join(dir, "control-plane.json"));
57238
57497
  const activeCompanies = (await store.listCompanies()).filter((c) => c.status === "active");
57239
57498
  const companyId = flags.get("company") ?? activeCompanies[0]?.id ?? resolveDefaultCompanyConfig().id;
57240
57499
  const name = flags.get("name");
@@ -57247,11 +57506,11 @@ async function runCli(argv, println = console.log) {
57247
57506
  }
57248
57507
  if (command === "export-trajectories") {
57249
57508
  const { exportTrajectories: exportTrajectories2 } = await Promise.resolve().then(() => (init_trajectory(), trajectory_exports));
57250
- const samples = await exportTrajectories2(path17.resolve(dir));
57509
+ const samples = await exportTrajectories2(path18.resolve(dir));
57251
57510
  const outFile = flags.get("out");
57252
57511
  const lines = samples.map((sample) => JSON.stringify(sample)).join("\n");
57253
57512
  if (outFile !== void 0) {
57254
- fs18.writeFileSync(outFile, lines + (lines ? "\n" : ""));
57513
+ fs19.writeFileSync(outFile, lines + (lines ? "\n" : ""));
57255
57514
  println(`\u5DF2\u5BFC\u51FA ${samples.length} \u6761\u8F68\u8FF9\u6837\u672C \u2192 ${outFile}\uFF08approved/rejected \u6210\u5BF9\u5373\u504F\u597D\u5BF9\uFF09`);
57256
57515
  } else {
57257
57516
  println(lines);
@@ -57259,10 +57518,10 @@ async function runCli(argv, println = console.log) {
57259
57518
  return;
57260
57519
  }
57261
57520
  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");
57521
+ const absDir = path18.resolve(dir);
57522
+ const name = `oasis-serve-${path18.basename(absDir)}`;
57523
+ const unitDir = flags.get("unit-dir") ?? path18.join(os10.homedir(), ".config", "systemd", "user");
57524
+ const bin = flags.get("bin") ?? path18.join(os10.homedir(), ".local", "bin", "oasis");
57266
57525
  const port = flags.get("port") ?? "7320";
57267
57526
  const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
57268
57527
  const unit = [
@@ -57279,9 +57538,9 @@ async function runCli(argv, println = console.log) {
57279
57538
  `WantedBy=default.target`,
57280
57539
  ``
57281
57540
  ].join("\n");
57282
- fs18.mkdirSync(unitDir, { recursive: true });
57283
- const unitPath = path17.join(unitDir, `${name}.service`);
57284
- fs18.writeFileSync(unitPath, unit);
57541
+ fs19.mkdirSync(unitDir, { recursive: true });
57542
+ const unitPath = path18.join(unitDir, `${name}.service`);
57543
+ fs19.writeFileSync(unitPath, unit);
57285
57544
  println(`\u5DF2\u5199\u5165 ${unitPath}`);
57286
57545
  println(`\u542F\u7528\uFF1Asystemctl --user daemon-reload && systemctl --user enable --now ${name}`);
57287
57546
  println(`\u5F00\u673A\u81EA\u542F\uFF08\u542B\u672A\u767B\u5F55\uFF09\uFF1Aloginctl enable-linger $USER`);
@@ -57303,20 +57562,20 @@ async function runCli(argv, println = console.log) {
57303
57562
  });
57304
57563
  const port2 = new URL(handle.baseUrl).port;
57305
57564
  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`);
57565
+ println(`operator token \u5DF2\u5199\u5165 ${path18.join(dir, "operator-token")}\uFF08\u672C\u673A CLI \u81EA\u52A8\u8BFB\u53D6\uFF09`);
57307
57566
  if (flags.get("dispatch") === "true") println(`\u8C03\u5EA6\u5FAA\u73AF\u5DF2\u542F\u52A8\uFF08claude-code adapter\uFF09`);
57308
57567
  await new Promise(() => {
57309
57568
  });
57310
57569
  return;
57311
57570
  }
57312
57571
  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);
57572
+ const tokenFile = path18.join(dir, "operator-token");
57573
+ const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs19.existsSync(tokenFile) ? fs19.readFileSync(tokenFile, "utf8").trim() : void 0);
57315
57574
  if (!token) {
57316
57575
  throw new Error(`\u65E0 token\uFF1A\u5148 oasis serve\uFF08\u4F1A\u751F\u6210 ${tokenFile}\uFF09\uFF0C\u6216\u663E\u5F0F --token / $OASIS_TOKEN`);
57317
57576
  }
57318
57577
  const api = makeClient(base, token);
57319
- const readFileArg = (file) => fs18.readFileSync(file, "utf8");
57578
+ const readFileArg = (file) => fs19.readFileSync(file, "utf8");
57320
57579
  const parseJsonFlag = (value, name) => {
57321
57580
  const parsed = JSON.parse(value);
57322
57581
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -57334,11 +57593,11 @@ async function runCli(argv, println = console.log) {
57334
57593
  const readDirFiles = (root) => {
57335
57594
  const out = [];
57336
57595
  const walk = (abs, rel) => {
57337
- for (const name of fs18.readdirSync(abs)) {
57338
- const childAbs = path17.join(abs, name);
57596
+ for (const name of fs19.readdirSync(abs)) {
57597
+ const childAbs = path18.join(abs, name);
57339
57598
  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") });
57599
+ if (fs19.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
57600
+ else out.push({ path: childRel, contentBase64: fs19.readFileSync(childAbs).toString("base64") });
57342
57601
  }
57343
57602
  };
57344
57603
  walk(root, "");
@@ -57464,7 +57723,7 @@ async function runCli(argv, println = console.log) {
57464
57723
  }
57465
57724
  switch (command) {
57466
57725
  case "create-workorder": {
57467
- const planRaw = flags.get("plan-file") !== void 0 ? fs18.readFileSync(flags.get("plan-file"), "utf8") : flags.get("plan");
57726
+ const planRaw = flags.get("plan-file") !== void 0 ? fs19.readFileSync(flags.get("plan-file"), "utf8") : flags.get("plan");
57468
57727
  const acceptanceFlag = flags.get("acceptance");
57469
57728
  const args = {
57470
57729
  createdVia: "seed",
@@ -57685,9 +57944,9 @@ async function runCli(argv, println = console.log) {
57685
57944
  if (verb === "add") {
57686
57945
  const file = flags.get("file");
57687
57946
  if (file !== void 0) {
57688
- const bytes = fs18.readFileSync(file);
57947
+ const bytes = fs19.readFileSync(file);
57689
57948
  const res = await api.request("POST", `/api/projects/${encodeURIComponent(projectId)}/files`, {
57690
- name: flags.get("name") ?? path17.basename(file),
57949
+ name: flags.get("name") ?? path18.basename(file),
57691
57950
  ...flags.has("path") ? { path: flags.get("path") } : {},
57692
57951
  content_base64: bytes.toString("base64"),
57693
57952
  ...flags.has("content-type") ? { content_type: flags.get("content-type") } : {}
@@ -57844,6 +58103,38 @@ ${res.warning}`);
57844
58103
  println(message);
57845
58104
  break;
57846
58105
  }
58106
+ case "design": {
58107
+ const sub = positional[0];
58108
+ if (sub !== "run") throw new Error("\u7528\u6CD5\uFF1Aoasis design run <artifactId> [--brief <t>] [--reason <t>] [--od-url <url>] [--title <t>] [--agent <id>]");
58109
+ const artifactId = needPos(positional, 1, "oasis design run <artifactId>");
58110
+ const odBase = (flags.get("od-url") ?? process.env["OASIS_OPEN_DESIGN_URL"] ?? "http://127.0.0.1:7457").replace(/\/$/, "");
58111
+ const odPublic = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
58112
+ const brief = flags.get("brief") ?? (fs19.existsSync("TASK.md") ? fs19.readFileSync("TASK.md", "utf8") : "");
58113
+ if (!brief.trim()) throw new Error("\u65E0\u8BBE\u8BA1\u4EFB\u52A1\uFF1A\u7ED9 --brief <text> \u6216\u5728\u5F53\u524D\u76EE\u5F55\u653E TASK.md");
58114
+ const contextFiles = { "TASK.md": brief };
58115
+ if (fs19.existsSync("inputs") && fs19.statSync("inputs").isDirectory()) {
58116
+ for (const f2 of readDirFiles("inputs")) {
58117
+ contextFiles[`inputs/${f2.path}`] = Buffer.from(f2.contentBase64, "base64").toString("utf8");
58118
+ }
58119
+ }
58120
+ println(`[design] \u753B\u677F ${deriveBoardKey(artifactId)} \u2190 ${artifactId}\uFF1B\u9A71\u52A8 od \u5F15\u64CE ${odBase} \u2026`);
58121
+ const { dir: dir2, entry, boardKey, runId } = await runOpenDesignSession({
58122
+ base: odBase,
58123
+ publicBase: odPublic,
58124
+ agentId: flags.get("agent") ?? "claude",
58125
+ artifactId,
58126
+ title: flags.get("title") ?? artifactId,
58127
+ message: brief,
58128
+ 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",
58129
+ contextFiles,
58130
+ onLine: (line) => println(`[od] ${line.length > 500 ? line.slice(0, 500) + "\u2026" : line}`)
58131
+ });
58132
+ println(`[design] \u753B\u677F\u4EA7\u51FA ${entry}\uFF08board ${boardKey}, run ${runId.slice(0, 8)}\uFF09\u2192 \u4EA4\u7A3F\u4E2D \u2026`);
58133
+ const reason = flags.get("reason") ?? `\u753B\u677F\u5FEB\u7167\u4EA4\u4ED8\uFF1A${entry}\uFF08board ${boardKey}, run ${runId.slice(0, 8)}\uFF09`;
58134
+ const { message } = await api.cmd("propose", { artifactId, files: readDirFiles(dir2), reason });
58135
+ println(message);
58136
+ break;
58137
+ }
57847
58138
  case "merge": {
57848
58139
  const artifactId = needPos(positional, 0, "oasis merge <artifactId> [revisionId]");
57849
58140
  const { message } = await api.cmd("merge", { artifactId, revisionId: positional[1] });
@@ -58236,8 +58527,8 @@ ${res.warning}`);
58236
58527
  }
58237
58528
  case "content": {
58238
58529
  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);
58530
+ const path20 = positional[1];
58531
+ const c = await api.view("content", id, path20 ? { path: path20 } : void 0);
58241
58532
  if (c.kind === "empty") println("\uFF08\u672C\u4EA7\u7269\u5C1A\u65E0\u5185\u5BB9\uFF09");
58242
58533
  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
58534
  else if (c.kind === "text") println(c.text);
@@ -58410,14 +58701,14 @@ ${res.warning}`);
58410
58701
  }
58411
58702
 
58412
58703
  // src/index.ts
58413
- var PKG_VERSION = true ? "0.1.45" : "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");
58704
+ var PKG_VERSION = true ? "0.1.47" : "dev";
58705
+ var OASIS_DIR = path19.join(os11.homedir(), ".oasis");
58706
+ var CONFIG_FILE = path19.join(OASIS_DIR, "node-config.json");
58707
+ var PID_FILE = path19.join(OASIS_DIR, "node.pid");
58708
+ var BIN_FILE = path19.join(OASIS_DIR, "bin", "oasis.js");
58709
+ var LOCAL_BIN = path19.join(os11.homedir(), ".local", "bin", "oasis");
58710
+ var LOG_FILE = path19.join(OASIS_DIR, "node.log");
58711
+ var NPM_PREFIX = path19.join(OASIS_DIR, "npm-global");
58421
58712
  var PKG_NAME = "oasis_test";
58422
58713
  var parseFlags = (argv) => {
58423
58714
  const flags = /* @__PURE__ */ new Map();
@@ -58429,18 +58720,18 @@ var parseFlags = (argv) => {
58429
58720
  };
58430
58721
  var readConfig = () => {
58431
58722
  try {
58432
- return JSON.parse(fs19.readFileSync(CONFIG_FILE, "utf8"));
58723
+ return JSON.parse(fs20.readFileSync(CONFIG_FILE, "utf8"));
58433
58724
  } catch {
58434
58725
  return null;
58435
58726
  }
58436
58727
  };
58437
58728
  var saveConfig = (c) => {
58438
- fs19.mkdirSync(OASIS_DIR, { recursive: true });
58439
- fs19.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
58729
+ fs20.mkdirSync(OASIS_DIR, { recursive: true });
58730
+ fs20.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
58440
58731
  };
58441
58732
  var readPid = () => {
58442
58733
  try {
58443
- const p2 = parseInt(fs19.readFileSync(PID_FILE, "utf8").trim(), 10);
58734
+ const p2 = parseInt(fs20.readFileSync(PID_FILE, "utf8").trim(), 10);
58444
58735
  return isNaN(p2) ? null : p2;
58445
58736
  } catch {
58446
58737
  return null;
@@ -58456,26 +58747,26 @@ var isRunning = (pid) => {
58456
58747
  };
58457
58748
  var httpBase = (wsUrl) => wsUrl.replace(/^ws(s?):\/\//, "http$1://").replace(/\/node-gateway.*$/, "");
58458
58749
  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
58750
+ fs20.mkdirSync(path19.dirname(BIN_FILE), { recursive: true });
58751
+ fs20.copyFileSync(process.argv[1], BIN_FILE);
58752
+ fs20.mkdirSync(path19.dirname(LOCAL_BIN), { recursive: true });
58753
+ fs20.writeFileSync(LOCAL_BIN, `#!/bin/sh
58463
58754
  exec node "${BIN_FILE}" "$@"
58464
58755
  `, { mode: 493 });
58465
58756
  }
58466
58757
  function setupAutostart() {
58467
58758
  const cmd = `${process.execPath} "${BIN_FILE}" --_daemon`;
58468
- const home = os10.homedir();
58759
+ const home = os11.homedir();
58469
58760
  const extraBins = [
58470
- path18.join(home, ".npm-global", "bin"),
58471
- path18.join(home, ".local", "bin"),
58761
+ path19.join(home, ".npm-global", "bin"),
58762
+ path19.join(home, ".local", "bin"),
58472
58763
  "/usr/local/bin"
58473
58764
  ];
58474
58765
  const daemonPath = [process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":");
58475
58766
  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"), [
58767
+ const unitDir = path19.join(os11.homedir(), ".config", "systemd", "user");
58768
+ fs20.mkdirSync(unitDir, { recursive: true });
58769
+ fs20.writeFileSync(path19.join(unitDir, "oasis-node.service"), [
58479
58770
  "[Unit]",
58480
58771
  "Description=Oasis Node Daemon",
58481
58772
  "After=network.target",
@@ -58497,9 +58788,9 @@ function setupAutostart() {
58497
58788
  } catch {
58498
58789
  }
58499
58790
  } 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"?>
58791
+ const plist = path19.join(os11.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
58792
+ fs20.mkdirSync(path19.dirname(plist), { recursive: true });
58793
+ fs20.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
58503
58794
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
58504
58795
  <plist version="1.0"><dict>
58505
58796
  <key>Label</key><string>com.oasis.node</string>
@@ -58516,14 +58807,14 @@ function setupAutostart() {
58516
58807
  }
58517
58808
  }
58518
58809
  function spawnDaemon() {
58519
- const log3 = fs19.openSync(LOG_FILE, "a");
58810
+ const log3 = fs20.openSync(LOG_FILE, "a");
58520
58811
  const child = (0, import_node_child_process15.spawn)(process.execPath, [BIN_FILE, "--_daemon"], {
58521
58812
  detached: true,
58522
58813
  stdio: ["ignore", log3, log3]
58523
58814
  });
58524
58815
  child.unref();
58525
58816
  const pid = child.pid ?? 0;
58526
- fs19.writeFileSync(PID_FILE, String(pid));
58817
+ fs20.writeFileSync(PID_FILE, String(pid));
58527
58818
  return pid;
58528
58819
  }
58529
58820
  function stopDaemon() {
@@ -58535,7 +58826,7 @@ function stopDaemon() {
58535
58826
  }
58536
58827
  }
58537
58828
  try {
58538
- fs19.unlinkSync(PID_FILE);
58829
+ fs20.unlinkSync(PID_FILE);
58539
58830
  } catch {
58540
58831
  }
58541
58832
  try {
@@ -58551,7 +58842,7 @@ function selfUpdate() {
58551
58842
  const cfg = readConfig();
58552
58843
  if (!cfg?.serverUrl) throw new Error("no config \u2014 run `oasis start` first");
58553
58844
  const nameArg = cfg.name ? ` --name '${cfg.name.replace(/'/g, "'\\''")}'` : "";
58554
- const oasisBin = path18.join(NPM_PREFIX, "bin", "oasis");
58845
+ const oasisBin = path19.join(NPM_PREFIX, "bin", "oasis");
58555
58846
  const startCmd = `"${oasisBin}" start --server-ws '${cfg.serverUrl}'${nameArg}`;
58556
58847
  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
58848
  const hasSystemd = process.platform === "linux" && (() => {
@@ -58562,7 +58853,7 @@ function selfUpdate() {
58562
58853
  return false;
58563
58854
  }
58564
58855
  })();
58565
- const log3 = fs19.openSync(LOG_FILE, "a");
58856
+ const log3 = fs20.openSync(LOG_FILE, "a");
58566
58857
  if (hasSystemd) {
58567
58858
  const child = (0, import_node_child_process15.spawn)("systemd-run", ["--user", "--scope", "--quiet", "sh", "-c", inner], {
58568
58859
  detached: true,
@@ -58588,10 +58879,10 @@ void (async () => {
58588
58879
  console.error(`[oasis] daemon already running (PID ${alivePid}) \u2014 exiting duplicate`);
58589
58880
  process.exit(0);
58590
58881
  }
58591
- fs19.writeFileSync(PID_FILE, String(process.pid));
58882
+ fs20.writeFileSync(PID_FILE, String(process.pid));
58592
58883
  const cleanup = () => {
58593
58884
  try {
58594
- fs19.unlinkSync(PID_FILE);
58885
+ fs20.unlinkSync(PID_FILE);
58595
58886
  } catch {
58596
58887
  }
58597
58888
  };
@@ -58651,7 +58942,7 @@ void (async () => {
58651
58942
  const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
58652
58943
  method: "POST",
58653
58944
  headers: { "content-type": "application/json" },
58654
- body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os10.hostname() })
58945
+ body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os11.hostname() })
58655
58946
  });
58656
58947
  if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
58657
58948
  const body = await res.json();
@@ -58674,7 +58965,7 @@ void (async () => {
58674
58965
  const pid = spawnDaemon();
58675
58966
  console.log(`\u2713 daemon started (PID ${pid})${nameChanged ? ` [name updated: ${prev.name} \u2192 ${name}]` : ""}`);
58676
58967
  console.log(` logs: tail -f ${LOG_FILE}`);
58677
- if (!process.env["PATH"]?.includes(path18.dirname(LOCAL_BIN)))
58968
+ if (!process.env["PATH"]?.includes(path19.dirname(LOCAL_BIN)))
58678
58969
  console.log(` add to PATH: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc`);
58679
58970
  return;
58680
58971
  }