oasis_test 0.1.5 → 0.1.7

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 +437 -208
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2782,7 +2782,11 @@ var init_dispatcher = __esm({
2782
2782
  this.opts = opts;
2783
2783
  }
2784
2784
  inFlight = /* @__PURE__ */ new Map();
2785
+ /** v1 调度准入:在途会话的 actor(jobKey → actorId),用于每 agent 并发计数。与 inFlight 同生同灭。 */
2786
+ inFlightActor = /* @__PURE__ */ new Map();
2785
2787
  strikes = /* @__PURE__ */ new Map();
2788
+ /** v1 调度准入:上一轮 tick 中"够格但被并发上限挡下"的 produce jobKey(隐式队列;下个 tick 重评)。 */
2789
+ queued = /* @__PURE__ */ new Set();
2786
2790
  dispatchLog = [];
2787
2791
  emitJournal(entry) {
2788
2792
  try {
@@ -2801,6 +2805,10 @@ var init_dispatcher = __esm({
2801
2805
  fusedAt: st.fusedAt
2802
2806
  }));
2803
2807
  }
2808
+ /** v1 调度准入:当前被并发上限挡下、等待重评的 produce 会话数(/api/view dispatches 表面化)。 */
2809
+ queuedCount() {
2810
+ return this.queued.size;
2811
+ }
2804
2812
  /** 在途会话视图(liveness 的 hasInFlightWork 来源)。含 part 维度的生产会话。 */
2805
2813
  hasInFlight(artifactId) {
2806
2814
  return [...this.inFlight.keys()].some(
@@ -2814,6 +2822,7 @@ var init_dispatcher = __esm({
2814
2822
  async tick() {
2815
2823
  const { kernel } = this.opts;
2816
2824
  let started = 0;
2825
+ this.queued.clear();
2817
2826
  await this.autoConcludeReadyMergedArtifacts();
2818
2827
  for (const job of computeProduceJobs(kernel.model)) {
2819
2828
  if (kernel.isFrozen(job.artifactId)) continue;
@@ -2877,6 +2886,26 @@ var init_dispatcher = __esm({
2877
2886
  return 0;
2878
2887
  }
2879
2888
  }
2889
+ if (spec.action === "produce") {
2890
+ const o = this.opts;
2891
+ if (o.maxConcurrentProduce !== void 0) {
2892
+ const producing = [...this.inFlight.keys()].filter((k) => k.startsWith("produce::")).length;
2893
+ if (producing >= o.maxConcurrentProduce) {
2894
+ this.queued.add(jobKey);
2895
+ return 0;
2896
+ }
2897
+ }
2898
+ if (o.maxConcurrentProducePerActor !== void 0) {
2899
+ let perActor = 0;
2900
+ for (const [k, a] of this.inFlightActor) {
2901
+ if (a === spec.actor && k.startsWith("produce::")) perActor++;
2902
+ }
2903
+ if (perActor >= o.maxConcurrentProducePerActor) {
2904
+ this.queued.add(jobKey);
2905
+ return 0;
2906
+ }
2907
+ }
2908
+ }
2880
2909
  const retry = this.strikes.get(jobKey);
2881
2910
  const lastFailure = retry && retry.count > 0 && retry.lastReason ? { reason: retry.lastReason } : void 0;
2882
2911
  const ws = kernel.model.artifacts.get(spec.artifactId)?.workspace;
@@ -2909,6 +2938,7 @@ var init_dispatcher = __esm({
2909
2938
  };
2910
2939
  const session = await this.opts.adapter.spawn(job);
2911
2940
  this.inFlight.set(jobKey, session);
2941
+ this.inFlightActor.set(jobKey, spec.actor);
2912
2942
  const dispatchedAtMs = Date.now();
2913
2943
  const seqAtDispatch = seqNow;
2914
2944
  const sink = this.opts.trajectory;
@@ -2974,6 +3004,7 @@ var init_dispatcher = __esm({
2974
3004
  await this.maybeAutoConclude(spec);
2975
3005
  }
2976
3006
  this.inFlight.delete(jobKey);
3007
+ this.inFlightActor.delete(jobKey);
2977
3008
  const seqAtExit = kernel.model.lastSeq.get(spec.artifactId) ?? 0;
2978
3009
  if (sink) {
2979
3010
  void (async () => {
@@ -15823,12 +15854,12 @@ var require_dist = __commonJS({
15823
15854
  throw new Error(`Unknown format "${name}"`);
15824
15855
  return f;
15825
15856
  };
15826
- function addFormats(ajv, list, fs15, exportName) {
15857
+ function addFormats(ajv, list, fs16, exportName) {
15827
15858
  var _a;
15828
15859
  var _b;
15829
15860
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
15830
15861
  for (const f of list)
15831
- ajv.addFormat(f, fs15[f]);
15862
+ ajv.addFormat(f, fs16[f]);
15832
15863
  }
15833
15864
  module2.exports = exports2 = formatsPlugin;
15834
15865
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -17615,7 +17646,7 @@ async function startOasisServer(opts) {
17615
17646
  if (body.actorId && opts.resolveActorContext) {
17616
17647
  const actorCtx = await opts.resolveActorContext(body.actorId).catch(() => null);
17617
17648
  if (actorCtx) {
17618
- const { mkdtempSync: mkdtempSync6, mkdirSync: mkdirSync13, writeFileSync: writeFileSync13 } = await import("node:fs");
17649
+ const { mkdtempSync: mkdtempSync6, mkdirSync: mkdirSync13, writeFileSync: writeFileSync14 } = await import("node:fs");
17619
17650
  const { join: join16, dirname: dirname13 } = await import("node:path");
17620
17651
  const { tmpdir: tmpdir8 } = await import("node:os");
17621
17652
  const dir = mkdtempSync6(join16(tmpdir8(), "oasis-chat-"));
@@ -17623,7 +17654,7 @@ async function startOasisServer(opts) {
17623
17654
  for (const [rel, content] of Object.entries(splitIdentityFiles2(actorCtx.config.prompt))) {
17624
17655
  const file = join16(dir, rel);
17625
17656
  mkdirSync13(dirname13(file), { recursive: true });
17626
- writeFileSync13(file, content);
17657
+ writeFileSync14(file, content);
17627
17658
  }
17628
17659
  }
17629
17660
  const enabledSkillIds = new Set(actorCtx.config?.skills ?? []);
@@ -17633,7 +17664,7 @@ async function startOasisServer(opts) {
17633
17664
  const s = byId.get(id);
17634
17665
  return s ? `- **${s.name}** (\`${s.id}\`): ${s.description}` : `- \`${id}\`\uFF08\u672A\u5728\u6280\u80FD\u5E93\u4E2D\uFF0C\u53EF\u80FD\u5DF2\u5378\u8F7D\uFF09`;
17635
17666
  });
17636
- writeFileSync13(join16(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"));
17667
+ writeFileSync14(join16(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"));
17637
17668
  }
17638
17669
  const activeConnectors = actorCtx.connectors.filter(
17639
17670
  (c) => c.status === "connected" || c.status === "verifying"
@@ -17644,7 +17675,7 @@ async function startOasisServer(opts) {
17644
17675
  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";
17645
17676
  return `- **${c.name}** (\`${c.id}\`): ${statusNote} \xB7 ${modeNote}`;
17646
17677
  });
17647
- writeFileSync13(join16(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"));
17678
+ writeFileSync14(join16(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"));
17648
17679
  }
17649
17680
  spawnCwd = dir;
17650
17681
  }
@@ -20237,7 +20268,7 @@ var init_service = __esm({
20237
20268
  });
20238
20269
 
20239
20270
  // ../server/src/dev-store.ts
20240
- var import_node_crypto4, fs2, path, NdjsonOplogStore, DirBlobStore, MUTATORS, FileRegistryStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore;
20271
+ var import_node_crypto4, fs2, path, NdjsonOplogStore, DirBlobStore, MUTATORS, FileRegistryStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore;
20241
20272
  var init_dev_store = __esm({
20242
20273
  "../server/src/dev-store.ts"() {
20243
20274
  "use strict";
@@ -20626,6 +20657,43 @@ var init_dev_store = __esm({
20626
20657
  this.appendLine(this.artifactsFile, artifact);
20627
20658
  }
20628
20659
  };
20660
+ MemoryChatSessionStore = class {
20661
+ sessions = /* @__PURE__ */ new Map();
20662
+ messages = /* @__PURE__ */ new Map();
20663
+ async createSession(s) {
20664
+ this.sessions.set(s.id, { ...s });
20665
+ this.messages.set(s.id, []);
20666
+ }
20667
+ async listSessions(humanActorId) {
20668
+ return [...this.sessions.values()].filter((s) => s.humanActorId === humanActorId).sort((a, b) => b.touchedAt.localeCompare(a.touchedAt));
20669
+ }
20670
+ async getSession(id) {
20671
+ return this.sessions.get(id) ?? null;
20672
+ }
20673
+ async updateSession(id, patch) {
20674
+ const s = this.sessions.get(id);
20675
+ if (!s) return;
20676
+ const updated = { ...s };
20677
+ if (patch.runtimeId !== void 0) updated.runtimeId = patch.runtimeId;
20678
+ if (Object.prototype.hasOwnProperty.call(patch, "runtimeSessionId")) updated.runtimeSessionId = patch.runtimeSessionId ?? null;
20679
+ if (patch.title !== void 0) updated.title = patch.title;
20680
+ if (patch.touchedAt !== void 0) updated.touchedAt = patch.touchedAt;
20681
+ this.sessions.set(id, updated);
20682
+ }
20683
+ async deleteSession(id) {
20684
+ this.sessions.delete(id);
20685
+ this.messages.delete(id);
20686
+ }
20687
+ async appendMessage(m) {
20688
+ const list = this.messages.get(m.sessionId) ?? [];
20689
+ list.push({ ...m });
20690
+ this.messages.set(m.sessionId, list);
20691
+ }
20692
+ async listMessages(sessionId, limit) {
20693
+ const list = this.messages.get(sessionId) ?? [];
20694
+ return limit !== void 0 ? list.slice(-limit) : [...list];
20695
+ }
20696
+ };
20629
20697
  }
20630
20698
  });
20631
20699
 
@@ -24488,7 +24556,8 @@ var init_daemon_hub = __esm({
24488
24556
  cb(false, 401, "invalid node token");
24489
24557
  return;
24490
24558
  }
24491
- info.req.oasisNodeId = nodeId;
24559
+ const claimed = info.req.headers["x-daemon-id"];
24560
+ info.req.oasisNodeId = claimed || nodeId;
24492
24561
  cb(true);
24493
24562
  }
24494
24563
  } : {}
@@ -27380,72 +27449,110 @@ var init_connect_script = __esm({
27380
27449
  // ../server/src/domains/nodes/routes.ts
27381
27450
  function nodesDomain(deps) {
27382
27451
  const nodeNames = /* @__PURE__ */ new Map();
27452
+ let hubWired = false;
27453
+ function wireHub(hub) {
27454
+ if (hubWired) return;
27455
+ hubWired = true;
27456
+ const { nodeStore } = deps;
27457
+ const now = () => (/* @__PURE__ */ new Date()).toISOString();
27458
+ hub.addMessageListener(async (daemonId, msg) => {
27459
+ if (msg.type !== "hello") return;
27460
+ const d = hub.connectedDaemons().find((c) => c.daemonId === daemonId);
27461
+ if (!d) return;
27462
+ const existing = await nodeStore.getNode(daemonId);
27463
+ await nodeStore.upsertNode({
27464
+ id: daemonId,
27465
+ hostname: d.meta.hostname,
27466
+ nodeVersion: d.meta.nodeVersion ?? "unknown",
27467
+ status: "online",
27468
+ lastSeenAt: now(),
27469
+ enrolledAt: existing?.enrolledAt ?? now(),
27470
+ ...d.meta.nodeName ? { name: d.meta.nodeName } : existing?.name ? { name: existing.name } : {}
27471
+ });
27472
+ const capabilities = d.meta.runtimes?.length ? d.meta.runtimes : d.meta.adapters.map((kind) => ({ kind, binary: void 0, version: void 0 }));
27473
+ for (const cap of capabilities) {
27474
+ await nodeStore.upsertRuntime({
27475
+ id: `runtime:${daemonId}:${cap.kind}`,
27476
+ nodeId: daemonId,
27477
+ kind: cap.kind,
27478
+ hostname: d.meta.hostname,
27479
+ ...cap.binary ? { binary: cap.binary } : {},
27480
+ ...cap.version ? { version: cap.version } : {},
27481
+ status: "online",
27482
+ lastSeenAt: now()
27483
+ });
27484
+ }
27485
+ });
27486
+ hub.onDaemonDisconnected = async (daemonId) => {
27487
+ await nodeStore.setNodeOnline(daemonId, false);
27488
+ await nodeStore.setNodeRuntimesOnline(daemonId, false);
27489
+ };
27490
+ }
27383
27491
  return (router) => {
27384
27492
  router.get("/api/nodes", async () => {
27385
27493
  const hub = deps.getHub();
27386
- const onlineIds = /* @__PURE__ */ new Set();
27387
- const online = (hub?.connectedDaemons() ?? []).map((d) => {
27388
- onlineIds.add(d.daemonId);
27389
- if (d.meta.nodeName) nodeNames.set(d.daemonId, d.meta.nodeName);
27494
+ if (hub) wireHub(hub);
27495
+ const nodes = await deps.nodeStore.listNodes();
27496
+ const items = await Promise.all(nodes.map(async (n) => {
27497
+ const rts = await deps.nodeStore.listRuntimes(n.id);
27390
27498
  return {
27391
- id: d.daemonId,
27392
- hostname: d.meta.hostname,
27393
- adapters: d.meta.adapters,
27394
- runtimes: runtimeInfos(d.daemonId, d.meta, "online"),
27395
- nodeVersion: d.meta.nodeVersion,
27396
- name: nodeNames.get(d.daemonId)
27499
+ id: n.id,
27500
+ hostname: n.hostname,
27501
+ adapters: rts.map((r) => r.kind),
27502
+ runtimes: rts.map((r) => ({
27503
+ id: r.id,
27504
+ nodeId: r.nodeId,
27505
+ hostname: r.hostname,
27506
+ kind: r.kind,
27507
+ ...r.binary ? { binary: r.binary } : {},
27508
+ ...r.version ? { version: r.version } : {},
27509
+ status: r.status,
27510
+ busy: false,
27511
+ lastReportAt: r.lastSeenAt
27512
+ })),
27513
+ nodeVersion: n.nodeVersion,
27514
+ ...n.name ? { name: n.name } : {}
27397
27515
  };
27398
- });
27399
- const offline = (hub?.recentlyDisconnected() ?? []).filter((g) => !onlineIds.has(g.daemonId)).map((g) => ({
27400
- id: g.daemonId,
27401
- hostname: g.meta.hostname,
27402
- adapters: g.meta.adapters,
27403
- runtimes: runtimeInfos(g.daemonId, g.meta, "offline"),
27404
- nodeVersion: g.meta.nodeVersion,
27405
- name: nodeNames.get(g.daemonId)
27406
27516
  }));
27407
- return { status: 200, body: { items: [...online, ...offline] } };
27517
+ return { status: 200, body: { items } };
27408
27518
  });
27409
- const suppressedRuntimes = /* @__PURE__ */ new Set();
27410
- let hubListenerAdded = false;
27411
27519
  router.get("/api/runtimes", async () => {
27412
27520
  const hub = deps.getHub();
27413
- if (hub && !hubListenerAdded) {
27414
- hubListenerAdded = true;
27415
- hub.addMessageListener((daemonId, msg) => {
27416
- if (msg.type === "hello") {
27417
- for (const id of suppressedRuntimes) {
27418
- if (id.startsWith(`runtime:${daemonId}:`)) suppressedRuntimes.delete(id);
27419
- }
27420
- }
27421
- });
27422
- }
27423
- const online = (hub?.connectedDaemons() ?? []).flatMap((d) => {
27424
- if (d.meta.nodeName) nodeNames.set(d.daemonId, d.meta.nodeName);
27425
- return runtimeInfos(d.daemonId, d.meta, "online");
27426
- });
27427
- const onlineIds = new Set(online.map((r) => r.id));
27428
- const offline = (hub?.recentlyDisconnected() ?? []).flatMap(
27429
- (g) => runtimeInfos(g.daemonId, g.meta, "offline").filter((r) => !onlineIds.has(r.id))
27430
- );
27431
- return { status: 200, body: { items: [...online, ...offline].filter((r) => !suppressedRuntimes.has(r.id)) } };
27432
- });
27433
- router.delete("/api/runtimes/:runtimeId", async (req) => {
27434
- const runtimeId = req.params["runtimeId"];
27435
- if (!runtimeId) return { status: 400, body: { error: "missing runtimeId" } };
27436
- suppressedRuntimes.add(runtimeId);
27437
- return { status: 200, body: { ok: true } };
27521
+ if (hub) wireHub(hub);
27522
+ const rts = await deps.nodeStore.listRuntimes();
27523
+ const items = rts.map((r) => ({
27524
+ id: r.id,
27525
+ nodeId: r.nodeId,
27526
+ hostname: r.hostname,
27527
+ kind: r.kind,
27528
+ ...r.binary ? { binary: r.binary } : {},
27529
+ ...r.version ? { version: r.version } : {},
27530
+ status: r.status,
27531
+ busy: false,
27532
+ lastReportAt: r.lastSeenAt
27533
+ }));
27534
+ return { status: 200, body: { items } };
27438
27535
  });
27439
27536
  router.post("/api/nodes/enroll", async (req) => {
27440
27537
  const body = req.body ?? {};
27441
27538
  const requested = body.nodeId?.trim();
27442
27539
  const nodeId = requested || `node-${(0, import_node_crypto9.randomUUID)().slice(0, 8)}`;
27443
- const nodeName = body.nodeName?.trim() || nodeId;
27444
- for (const { token: token2, nodeId: existing } of deps.nodeTokens.list()) {
27445
- if (existing === nodeId) deps.nodeTokens.revoke(token2);
27540
+ const nodeName = body.nodeName?.trim() || void 0;
27541
+ for (const { token: token2, nodeId: existing2 } of deps.nodeTokens.list()) {
27542
+ if (existing2 === nodeId) deps.nodeTokens.revoke(token2);
27446
27543
  }
27447
27544
  const token = deps.nodeTokens.issue(nodeId);
27448
- nodeNames.set(nodeId, nodeName);
27545
+ if (nodeName) nodeNames.set(nodeId, nodeName);
27546
+ const existing = await deps.nodeStore.getNode(nodeId);
27547
+ await deps.nodeStore.upsertNode({
27548
+ id: nodeId,
27549
+ name: nodeName,
27550
+ hostname: existing?.hostname ?? "unknown",
27551
+ nodeVersion: existing?.nodeVersion ?? "unknown",
27552
+ status: "offline",
27553
+ lastSeenAt: existing?.lastSeenAt ?? (/* @__PURE__ */ new Date()).toISOString(),
27554
+ enrolledAt: existing?.enrolledAt ?? (/* @__PURE__ */ new Date()).toISOString()
27555
+ });
27449
27556
  const params = { gatewayUrl: deps.gatewayUrl, nodeId, token, repoRemote: deps.repoRemote };
27450
27557
  const script = body.platform === "windows" ? buildWindowsConnectScript(params) : buildConnectScript(params);
27451
27558
  const npxCmd = buildNpxCmd({ gatewayUrl: deps.gatewayUrl, nodeId, token, nodeName });
@@ -27455,7 +27562,7 @@ function nodesDomain(deps) {
27455
27562
  const nodeId = req.params["nodeId"];
27456
27563
  if (!nodeId) return { status: 400, body: { error: "missing nodeId" } };
27457
27564
  const body = req.body ?? {};
27458
- if (body.name) nodeNames.set(nodeId, body.name);
27565
+ if (body.name) await deps.nodeStore.updateNodeName(nodeId, body.name);
27459
27566
  return { status: 200, body: { ok: true } };
27460
27567
  });
27461
27568
  router.delete("/api/nodes/:nodeId", async (req) => {
@@ -27466,27 +27573,17 @@ function nodesDomain(deps) {
27466
27573
  }
27467
27574
  const hub = deps.getHub();
27468
27575
  hub?.connectedDaemons().find((d) => d.daemonId === nodeId)?.close();
27469
- hub?.evictGhost(nodeId);
27470
- nodeNames.delete(nodeId);
27576
+ await deps.nodeStore.deleteNode(nodeId);
27577
+ return { status: 200, body: { ok: true } };
27578
+ });
27579
+ router.delete("/api/runtimes/:runtimeId", async (req) => {
27580
+ const runtimeId = req.params["runtimeId"];
27581
+ if (!runtimeId) return { status: 400, body: { error: "missing runtimeId" } };
27582
+ await deps.nodeStore.deleteRuntime(runtimeId);
27471
27583
  return { status: 200, body: { ok: true } };
27472
27584
  });
27473
27585
  };
27474
27586
  }
27475
- function runtimeInfos(nodeId, meta, status) {
27476
- const lastReportAt = (/* @__PURE__ */ new Date()).toISOString();
27477
- const capabilities = meta.runtimes?.length ? meta.runtimes : meta.adapters.map((kind) => ({ kind }));
27478
- return capabilities.map((r) => ({
27479
- id: `runtime:${nodeId}:${r.kind}`,
27480
- nodeId,
27481
- hostname: meta.hostname,
27482
- kind: r.kind,
27483
- ...r.binary ? { binary: r.binary } : {},
27484
- ...r.version ? { version: r.version } : {},
27485
- status,
27486
- busy: false,
27487
- lastReportAt
27488
- }));
27489
- }
27490
27587
  var import_node_crypto9;
27491
27588
  var init_routes4 = __esm({
27492
27589
  "../server/src/domains/nodes/routes.ts"() {
@@ -27496,6 +27593,124 @@ var init_routes4 = __esm({
27496
27593
  }
27497
27594
  });
27498
27595
 
27596
+ // ../server/src/node-store.ts
27597
+ var fs5, MemoryNodeStore, FileNodeStore;
27598
+ var init_node_store = __esm({
27599
+ "../server/src/node-store.ts"() {
27600
+ "use strict";
27601
+ fs5 = __toESM(require("node:fs"), 1);
27602
+ MemoryNodeStore = class {
27603
+ nodes = /* @__PURE__ */ new Map();
27604
+ runtimes = /* @__PURE__ */ new Map();
27605
+ async upsertNode(node) {
27606
+ this.nodes.set(node.id, { ...this.nodes.get(node.id), ...node });
27607
+ }
27608
+ async upsertRuntime(rt) {
27609
+ this.runtimes.set(rt.id, { ...this.runtimes.get(rt.id), ...rt });
27610
+ }
27611
+ async setNodeOnline(id, online) {
27612
+ const n = this.nodes.get(id);
27613
+ if (n) {
27614
+ n.status = online ? "online" : "offline";
27615
+ n.lastSeenAt = (/* @__PURE__ */ new Date()).toISOString();
27616
+ }
27617
+ }
27618
+ async setNodeRuntimesOnline(nodeId, online) {
27619
+ const now = (/* @__PURE__ */ new Date()).toISOString();
27620
+ for (const rt of this.runtimes.values()) {
27621
+ if (rt.nodeId === nodeId) {
27622
+ rt.status = online ? "online" : "offline";
27623
+ rt.lastSeenAt = now;
27624
+ }
27625
+ }
27626
+ }
27627
+ async updateNodeName(id, name) {
27628
+ const n = this.nodes.get(id);
27629
+ if (n) n.name = name;
27630
+ }
27631
+ async getNode(id) {
27632
+ return this.nodes.get(id) ?? null;
27633
+ }
27634
+ async listNodes() {
27635
+ return [...this.nodes.values()];
27636
+ }
27637
+ async listRuntimes(nodeId) {
27638
+ const all = [...this.runtimes.values()];
27639
+ return nodeId ? all.filter((r) => r.nodeId === nodeId) : all;
27640
+ }
27641
+ async deleteNode(id) {
27642
+ this.nodes.delete(id);
27643
+ for (const [k, rt] of this.runtimes) {
27644
+ if (rt.nodeId === id) this.runtimes.delete(k);
27645
+ }
27646
+ }
27647
+ async deleteRuntime(id) {
27648
+ const rt = this.runtimes.get(id);
27649
+ this.runtimes.delete(id);
27650
+ if (!rt) return { nodeDeleted: false };
27651
+ const remaining = [...this.runtimes.values()].filter((r) => r.nodeId === rt.nodeId);
27652
+ if (remaining.length === 0) {
27653
+ this.nodes.delete(rt.nodeId);
27654
+ return { nodeDeleted: true };
27655
+ }
27656
+ return { nodeDeleted: false };
27657
+ }
27658
+ };
27659
+ FileNodeStore = class _FileNodeStore extends MemoryNodeStore {
27660
+ constructor(file) {
27661
+ super();
27662
+ this.file = file;
27663
+ }
27664
+ static async open(file) {
27665
+ const s = new _FileNodeStore(file);
27666
+ try {
27667
+ const snap = JSON.parse(fs5.readFileSync(file, "utf8"));
27668
+ for (const n of snap.nodes ?? []) s.nodes.set(n.id, n);
27669
+ for (const r of snap.runtimes ?? []) s.runtimes.set(r.id, r);
27670
+ } catch {
27671
+ fs5.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
27672
+ }
27673
+ return s;
27674
+ }
27675
+ flush() {
27676
+ fs5.writeFileSync(this.file, JSON.stringify({
27677
+ nodes: [...this.nodes.values()],
27678
+ runtimes: [...this.runtimes.values()]
27679
+ }, null, 2));
27680
+ }
27681
+ async upsertNode(node) {
27682
+ await super.upsertNode(node);
27683
+ this.flush();
27684
+ }
27685
+ async upsertRuntime(rt) {
27686
+ await super.upsertRuntime(rt);
27687
+ this.flush();
27688
+ }
27689
+ async setNodeOnline(id, online) {
27690
+ await super.setNodeOnline(id, online);
27691
+ this.flush();
27692
+ }
27693
+ async setNodeRuntimesOnline(nodeId, online) {
27694
+ await super.setNodeRuntimesOnline(nodeId, online);
27695
+ this.flush();
27696
+ }
27697
+ async updateNodeName(id, name) {
27698
+ await super.updateNodeName(id, name);
27699
+ this.flush();
27700
+ }
27701
+ async deleteNode(id) {
27702
+ await super.deleteNode(id);
27703
+ this.flush();
27704
+ }
27705
+ async deleteRuntime(id) {
27706
+ const r = await super.deleteRuntime(id);
27707
+ this.flush();
27708
+ return r;
27709
+ }
27710
+ };
27711
+ }
27712
+ });
27713
+
27499
27714
  // ../server/src/domains/collab/workorder-detail.ts
27500
27715
  function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject, dispatchJournal = []) {
27501
27716
  const arts = [...model.artifacts.values()].filter((a) => a.workspace === workspaceId);
@@ -27515,6 +27730,7 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
27515
27730
  const nodes = arts.map((a) => {
27516
27731
  const info = nodeInfo(model, a);
27517
27732
  const runtime = runtimeByArtifact.get(a.id);
27733
+ const lifecycle = lifecycleOf(model, a.id);
27518
27734
  return {
27519
27735
  id: a.id,
27520
27736
  type: a.type,
@@ -27524,6 +27740,8 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
27524
27740
  queue: info.queueLen,
27525
27741
  blocked: blockedOf(model, a.id).blocked,
27526
27742
  owner: ref(a.owner),
27743
+ // 封存原因透出:stage 只到 "sealed" 粒度,原因(accepted/cancelled/frozen)另给,供前端区分展示。
27744
+ ...lifecycle !== "active" ? { sealedReason: lifecycle.slice("sealed:".length) } : {},
27527
27745
  ...runtime ? { runtime } : {}
27528
27746
  };
27529
27747
  });
@@ -29056,22 +29274,22 @@ var init_engine = __esm({
29056
29274
  });
29057
29275
 
29058
29276
  // ../server/src/mirror/fs-state.ts
29059
- var fs5, FsMirrorStateStore;
29277
+ var fs6, FsMirrorStateStore;
29060
29278
  var init_fs_state = __esm({
29061
29279
  "../server/src/mirror/fs-state.ts"() {
29062
29280
  "use strict";
29063
- fs5 = __toESM(require("node:fs"), 1);
29281
+ fs6 = __toESM(require("node:fs"), 1);
29064
29282
  FsMirrorStateStore = class {
29065
29283
  constructor(file) {
29066
29284
  this.file = file;
29067
- if (fs5.existsSync(file)) {
29068
- const obj = JSON.parse(fs5.readFileSync(file, "utf8"));
29285
+ if (fs6.existsSync(file)) {
29286
+ const obj = JSON.parse(fs6.readFileSync(file, "utf8"));
29069
29287
  for (const [k, v] of Object.entries(obj)) this.map.set(k, v);
29070
29288
  }
29071
29289
  }
29072
29290
  map = /* @__PURE__ */ new Map();
29073
29291
  flush() {
29074
- fs5.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
29292
+ fs6.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
29075
29293
  }
29076
29294
  async get(artifactId) {
29077
29295
  return this.map.get(artifactId) ?? null;
@@ -29088,12 +29306,12 @@ var init_fs_state = __esm({
29088
29306
  });
29089
29307
 
29090
29308
  // ../server/src/git/integrate.ts
29091
- var import_node_child_process2, fs6, path4, GitRemoteIntegrator;
29309
+ var import_node_child_process2, fs7, path4, GitRemoteIntegrator;
29092
29310
  var init_integrate = __esm({
29093
29311
  "../server/src/git/integrate.ts"() {
29094
29312
  "use strict";
29095
29313
  import_node_child_process2 = require("node:child_process");
29096
- fs6 = __toESM(require("node:fs"), 1);
29314
+ fs7 = __toESM(require("node:fs"), 1);
29097
29315
  path4 = __toESM(require("node:path"), 1);
29098
29316
  GitRemoteIntegrator = class {
29099
29317
  constructor(remote, cloneDir, develop = "develop") {
@@ -29111,8 +29329,8 @@ var init_integrate = __esm({
29111
29329
  }
29112
29330
  /** 确保本地工作克隆存在并拉到最新远程态。幂等。 */
29113
29331
  sync() {
29114
- if (!fs6.existsSync(path4.join(this.cloneDir, ".git"))) {
29115
- fs6.mkdirSync(path4.dirname(this.cloneDir), { recursive: true });
29332
+ if (!fs7.existsSync(path4.join(this.cloneDir, ".git"))) {
29333
+ fs7.mkdirSync(path4.dirname(this.cloneDir), { recursive: true });
29116
29334
  (0, import_node_child_process2.execFileSync)("git", ["clone", "--quiet", this.remote, this.cloneDir], { env: this.env, maxBuffer: 256 * 1024 * 1024 });
29117
29335
  this.git(["config", "user.email", "oasis@local"]);
29118
29336
  this.git(["config", "user.name", "oasis"]);
@@ -29518,9 +29736,11 @@ var init_src4 = __esm({
29518
29736
  init_auth();
29519
29737
  init_sender();
29520
29738
  init_routes4();
29739
+ init_node_store();
29521
29740
  init_collab();
29522
29741
  init_trace2();
29523
29742
  init_chat_sessions();
29743
+ init_dev_store();
29524
29744
  init_daemon_adapter();
29525
29745
  init_engine();
29526
29746
  init_fs_state();
@@ -31120,15 +31340,15 @@ var require_pg_connection_string = __commonJS({
31120
31340
  if (config2.sslcert || config2.sslkey || config2.sslrootcert || config2.sslmode) {
31121
31341
  config2.ssl = {};
31122
31342
  }
31123
- const fs15 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
31343
+ const fs16 = config2.sslcert || config2.sslkey || config2.sslrootcert ? require("fs") : null;
31124
31344
  if (config2.sslcert) {
31125
- config2.ssl.cert = fs15.readFileSync(config2.sslcert).toString();
31345
+ config2.ssl.cert = fs16.readFileSync(config2.sslcert).toString();
31126
31346
  }
31127
31347
  if (config2.sslkey) {
31128
- config2.ssl.key = fs15.readFileSync(config2.sslkey).toString();
31348
+ config2.ssl.key = fs16.readFileSync(config2.sslkey).toString();
31129
31349
  }
31130
31350
  if (config2.sslrootcert) {
31131
- config2.ssl.ca = fs15.readFileSync(config2.sslrootcert).toString();
31351
+ config2.ssl.ca = fs16.readFileSync(config2.sslrootcert).toString();
31132
31352
  }
31133
31353
  if (options.useLibpqCompat && config2.uselibpqcompat) {
31134
31354
  throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
@@ -33065,15 +33285,15 @@ var require_lib = __commonJS({
33065
33285
  "../../node_modules/.pnpm/pgpass@1.0.5/node_modules/pgpass/lib/index.js"(exports2, module2) {
33066
33286
  "use strict";
33067
33287
  var path14 = require("path");
33068
- var fs15 = require("fs");
33288
+ var fs16 = require("fs");
33069
33289
  var helper = require_helper();
33070
33290
  module2.exports = function(connInfo, cb) {
33071
33291
  var file = helper.getFileName();
33072
- fs15.stat(file, function(err, stat) {
33292
+ fs16.stat(file, function(err, stat) {
33073
33293
  if (err || !helper.usePgPass(stat, file)) {
33074
33294
  return cb(void 0);
33075
33295
  }
33076
- var st = fs15.createReadStream(file);
33296
+ var st = fs16.createReadStream(file);
33077
33297
  helper.getPassword(connInfo, st, cb);
33078
33298
  });
33079
33299
  };
@@ -34627,37 +34847,37 @@ __export(trajectory_exports, {
34627
34847
  });
34628
34848
  async function exportTrajectories(dataDir) {
34629
34849
  const root = path10.join(dataDir, "trajectories");
34630
- if (!fs11.existsSync(root)) return [];
34850
+ if (!fs12.existsSync(root)) return [];
34631
34851
  const model = emptyReadModel();
34632
34852
  const oplogFile = path10.join(dataDir, "oplog.ndjson");
34633
- if (fs11.existsSync(oplogFile)) {
34853
+ if (fs12.existsSync(oplogFile)) {
34634
34854
  const oplog = await NdjsonOplogStore.open(oplogFile);
34635
34855
  for await (const entry of oplog.readAll()) fold(model, entry.op);
34636
34856
  }
34637
34857
  const samples = [];
34638
- for (const sessionId of fs11.readdirSync(root).sort()) {
34858
+ for (const sessionId of fs12.readdirSync(root).sort()) {
34639
34859
  const dir = path10.join(root, sessionId);
34640
34860
  const sessionFile = path10.join(dir, "session.json");
34641
- if (!fs11.existsSync(sessionFile)) continue;
34642
- const session = JSON.parse(fs11.readFileSync(sessionFile, "utf8"));
34861
+ if (!fs12.existsSync(sessionFile)) continue;
34862
+ const session = JSON.parse(fs12.readFileSync(sessionFile, "utf8"));
34643
34863
  const events = [];
34644
34864
  const eventsFile = path10.join(dir, "events.ndjson");
34645
- if (fs11.existsSync(eventsFile)) {
34646
- for (const line of fs11.readFileSync(eventsFile, "utf8").split("\n")) {
34865
+ if (fs12.existsSync(eventsFile)) {
34866
+ for (const line of fs12.readFileSync(eventsFile, "utf8").split("\n")) {
34647
34867
  if (line.trim()) events.push(JSON.parse(line));
34648
34868
  }
34649
34869
  }
34650
34870
  const bundle = {};
34651
34871
  const bundleDir = path10.join(dir, "bundle");
34652
34872
  const walk = (sub) => {
34653
- for (const name of fs11.readdirSync(path10.join(bundleDir, sub))) {
34873
+ for (const name of fs12.readdirSync(path10.join(bundleDir, sub))) {
34654
34874
  const rel = sub ? `${sub}/${name}` : name;
34655
34875
  const full = path10.join(bundleDir, rel);
34656
- if (fs11.statSync(full).isDirectory()) walk(rel);
34657
- else bundle[rel] = fs11.readFileSync(full, "utf8");
34876
+ if (fs12.statSync(full).isDirectory()) walk(rel);
34877
+ else bundle[rel] = fs12.readFileSync(full, "utf8");
34658
34878
  }
34659
34879
  };
34660
- if (fs11.existsSync(bundleDir)) walk("");
34880
+ if (fs12.existsSync(bundleDir)) walk("");
34661
34881
  const proposed = (session.opRefs ?? []).filter((r) => r.kind === "propose_revision").map((r) => r.target);
34662
34882
  const verdicts = proposed.flatMap(
34663
34883
  (rev) => (model.reviews.get(rev) ?? []).map((v) => ({ author: v.author, verdict: v.verdict, ...v.note !== void 0 ? { note: v.note } : {} }))
@@ -34669,11 +34889,11 @@ async function exportTrajectories(dataDir) {
34669
34889
  }
34670
34890
  return samples;
34671
34891
  }
34672
- var fs11, path10, FsTrajectorySink;
34892
+ var fs12, path10, FsTrajectorySink;
34673
34893
  var init_trajectory = __esm({
34674
34894
  "../cli/src/trajectory.ts"() {
34675
34895
  "use strict";
34676
- fs11 = __toESM(require("node:fs"), 1);
34896
+ fs12 = __toESM(require("node:fs"), 1);
34677
34897
  path10 = __toESM(require("node:path"), 1);
34678
34898
  init_src2();
34679
34899
  init_src4();
@@ -34688,25 +34908,25 @@ var init_trajectory = __esm({
34688
34908
  }
34689
34909
  begin(session, bundleFiles) {
34690
34910
  const dir = this.dir(session.sessionId);
34691
- fs11.mkdirSync(path10.join(dir, "bundle"), { recursive: true });
34692
- fs11.writeFileSync(path10.join(dir, "session.json"), JSON.stringify(session, null, 2));
34911
+ fs12.mkdirSync(path10.join(dir, "bundle"), { recursive: true });
34912
+ fs12.writeFileSync(path10.join(dir, "session.json"), JSON.stringify(session, null, 2));
34693
34913
  for (const [rel, content] of Object.entries(bundleFiles)) {
34694
34914
  const file = path10.join(dir, "bundle", rel);
34695
- fs11.mkdirSync(path10.dirname(file), { recursive: true });
34696
- fs11.writeFileSync(file, content);
34915
+ fs12.mkdirSync(path10.dirname(file), { recursive: true });
34916
+ fs12.writeFileSync(file, content);
34697
34917
  }
34698
34918
  this.broadcast?.({ type: "begin", sessionId: session.sessionId, data: session });
34699
34919
  }
34700
34920
  event(sessionId, event) {
34701
- fs11.appendFileSync(path10.join(this.dir(sessionId), "events.ndjson"), JSON.stringify(event) + "\n");
34921
+ fs12.appendFileSync(path10.join(this.dir(sessionId), "events.ndjson"), JSON.stringify(event) + "\n");
34702
34922
  this.broadcast?.({ type: "event", sessionId, data: event });
34703
34923
  }
34704
34924
  end(sessionId, update) {
34705
34925
  const file = path10.join(this.dir(sessionId), "session.json");
34706
- const session = JSON.parse(fs11.readFileSync(file, "utf8"));
34926
+ const session = JSON.parse(fs12.readFileSync(file, "utf8"));
34707
34927
  session.exit = update.exit;
34708
34928
  session.opRefs = update.opRefs;
34709
- fs11.writeFileSync(file, JSON.stringify(session, null, 2));
34929
+ fs12.writeFileSync(file, JSON.stringify(session, null, 2));
34710
34930
  this.broadcast?.({ type: "end", sessionId, data: session });
34711
34931
  }
34712
34932
  };
@@ -34715,19 +34935,19 @@ var init_trajectory = __esm({
34715
34935
 
34716
34936
  // src/index.ts
34717
34937
  var import_node_crypto21 = require("node:crypto");
34718
- var fs14 = __toESM(require("node:fs"));
34938
+ var fs15 = __toESM(require("node:fs"));
34719
34939
  var os8 = __toESM(require("node:os"));
34720
34940
  var path13 = __toESM(require("node:path"));
34721
34941
  var import_node_child_process10 = require("node:child_process");
34722
34942
 
34723
34943
  // ../cli/src/cli.ts
34724
- var fs13 = __toESM(require("node:fs"), 1);
34944
+ var fs14 = __toESM(require("node:fs"), 1);
34725
34945
  var os7 = __toESM(require("node:os"), 1);
34726
34946
  var path12 = __toESM(require("node:path"), 1);
34727
34947
  var import_node_crypto20 = require("node:crypto");
34728
34948
 
34729
34949
  // ../cli/src/serve.ts
34730
- var fs12 = __toESM(require("node:fs"), 1);
34950
+ var fs13 = __toESM(require("node:fs"), 1);
34731
34951
  var os6 = __toESM(require("node:os"), 1);
34732
34952
  var path11 = __toESM(require("node:path"), 1);
34733
34953
  var import_node_crypto19 = require("node:crypto");
@@ -34936,7 +35156,7 @@ var import_node_path3 = require("node:path");
34936
35156
  // ../adapters/src/claude-code/index.ts
34937
35157
  var import_node_child_process5 = require("node:child_process");
34938
35158
  var import_node_crypto14 = require("node:crypto");
34939
- var fs7 = __toESM(require("node:fs"), 1);
35159
+ var fs8 = __toESM(require("node:fs"), 1);
34940
35160
  var os2 = __toESM(require("node:os"), 1);
34941
35161
  var path6 = __toESM(require("node:path"), 1);
34942
35162
  var readline = __toESM(require("node:readline"), 1);
@@ -35055,13 +35275,13 @@ var ClaudeCodeAdapter = class {
35055
35275
  async spawn(job) {
35056
35276
  const slug4 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
35057
35277
  const id = `claude-${slug4}-${(0, import_node_crypto14.randomUUID)().slice(0, 8)}`;
35058
- const dir = fs7.mkdtempSync(
35278
+ const dir = fs8.mkdtempSync(
35059
35279
  path6.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-session-")
35060
35280
  );
35061
35281
  for (const [rel, content] of Object.entries(job.bundle.files)) {
35062
35282
  const file = path6.join(dir, rel);
35063
- fs7.mkdirSync(path6.dirname(file), { recursive: true });
35064
- fs7.writeFileSync(file, content);
35283
+ fs8.mkdirSync(path6.dirname(file), { recursive: true });
35284
+ fs8.writeFileSync(file, content);
35065
35285
  }
35066
35286
  const prompt = job.bundle.files["TASK.md"];
35067
35287
  if (!prompt) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -35098,7 +35318,7 @@ var ClaudeCodeAdapter = class {
35098
35318
  stdio: ["ignore", "pipe", "pipe"]
35099
35319
  });
35100
35320
  let transcriptRef = path6.join(dir, "transcript.txt");
35101
- const out = fs7.createWriteStream(transcriptRef);
35321
+ const out = fs8.createWriteStream(transcriptRef);
35102
35322
  const telemetryCbs = [];
35103
35323
  let eventSeq = 0;
35104
35324
  let lastResult;
@@ -35161,13 +35381,13 @@ var ClaudeCodeAdapter = class {
35161
35381
  if (this.opts.cleanupWorkdir) {
35162
35382
  try {
35163
35383
  const keepDir = path6.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-transcripts");
35164
- fs7.mkdirSync(keepDir, { recursive: true });
35384
+ fs8.mkdirSync(keepDir, { recursive: true });
35165
35385
  const kept = path6.join(keepDir, `${id}.txt`);
35166
35386
  const src = transcriptRef;
35167
35387
  out.end(() => {
35168
35388
  try {
35169
- fs7.renameSync(src, kept);
35170
- fs7.rmSync(dir, { recursive: true, force: true });
35389
+ fs8.renameSync(src, kept);
35390
+ fs8.rmSync(dir, { recursive: true, force: true });
35171
35391
  } catch {
35172
35392
  }
35173
35393
  });
@@ -35202,7 +35422,7 @@ var ClaudeCodeAdapter = class {
35202
35422
  // ../adapters/src/codex/index.ts
35203
35423
  var import_node_child_process6 = require("node:child_process");
35204
35424
  var import_node_crypto15 = require("node:crypto");
35205
- var fs8 = __toESM(require("node:fs"), 1);
35425
+ var fs9 = __toESM(require("node:fs"), 1);
35206
35426
  var os3 = __toESM(require("node:os"), 1);
35207
35427
  var path7 = __toESM(require("node:path"), 1);
35208
35428
  var readline2 = __toESM(require("node:readline"), 1);
@@ -35247,7 +35467,7 @@ function codexSessionsRoot() {
35247
35467
  if (home) candidates.push(path7.join(home, ".codex", "sessions"));
35248
35468
  for (const c of candidates) {
35249
35469
  try {
35250
- if (fs8.statSync(c).isDirectory()) return c;
35470
+ if (fs9.statSync(c).isDirectory()) return c;
35251
35471
  } catch {
35252
35472
  }
35253
35473
  }
@@ -35259,7 +35479,7 @@ function listRecentRollouts(root, sinceMs) {
35259
35479
  const walk = (d) => {
35260
35480
  let ents;
35261
35481
  try {
35262
- ents = fs8.readdirSync(d, { withFileTypes: true });
35482
+ ents = fs9.readdirSync(d, { withFileTypes: true });
35263
35483
  } catch {
35264
35484
  return;
35265
35485
  }
@@ -35269,7 +35489,7 @@ function listRecentRollouts(root, sinceMs) {
35269
35489
  else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(".jsonl")) {
35270
35490
  let m = 0;
35271
35491
  try {
35272
- m = fs8.statSync(p).mtimeMs;
35492
+ m = fs9.statSync(p).mtimeMs;
35273
35493
  } catch {
35274
35494
  }
35275
35495
  if (m >= margin) found.push({ f: p, m });
@@ -35284,7 +35504,7 @@ function scanCodexUsage(workdir, sinceMs, sessionsRoot = codexSessionsRoot()) {
35284
35504
  for (const f of listRecentRollouts(sessionsRoot, sinceMs)) {
35285
35505
  let lines;
35286
35506
  try {
35287
- lines = fs8.readFileSync(f, "utf8").split("\n");
35507
+ lines = fs9.readFileSync(f, "utf8").split("\n");
35288
35508
  } catch {
35289
35509
  continue;
35290
35510
  }
@@ -35476,11 +35696,11 @@ var CodexAdapter = class {
35476
35696
  const slug4 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
35477
35697
  const id = `codex-${slug4}-${(0, import_node_crypto15.randomUUID)().slice(0, 8)}`;
35478
35698
  const startedAtMs = Date.now();
35479
- const dir = fs8.mkdtempSync(path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-session-"));
35699
+ const dir = fs9.mkdtempSync(path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-session-"));
35480
35700
  for (const [rel, content] of Object.entries(job.bundle.files)) {
35481
35701
  const file = path7.join(dir, rel);
35482
- fs8.mkdirSync(path7.dirname(file), { recursive: true });
35483
- fs8.writeFileSync(file, content);
35702
+ fs9.mkdirSync(path7.dirname(file), { recursive: true });
35703
+ fs9.writeFileSync(file, content);
35484
35704
  }
35485
35705
  const task = job.bundle.files["TASK.md"];
35486
35706
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -35509,7 +35729,7 @@ var CodexAdapter = class {
35509
35729
  stdio: ["ignore", "pipe", "pipe"]
35510
35730
  });
35511
35731
  let transcriptRef = path7.join(dir, "transcript.txt");
35512
- const out = fs8.createWriteStream(transcriptRef);
35732
+ const out = fs9.createWriteStream(transcriptRef);
35513
35733
  const outputCbs = [];
35514
35734
  const telemetryCbs = [];
35515
35735
  const normalizeState = createCodexNormalizeState();
@@ -35540,13 +35760,13 @@ var CodexAdapter = class {
35540
35760
  if (this.opts.cleanupWorkdir) {
35541
35761
  try {
35542
35762
  const keepDir = path7.join(this.opts.workRoot ?? os3.tmpdir(), "oasis-transcripts");
35543
- fs8.mkdirSync(keepDir, { recursive: true });
35763
+ fs9.mkdirSync(keepDir, { recursive: true });
35544
35764
  const kept = path7.join(keepDir, `${id}.txt`);
35545
35765
  const src = transcriptRef;
35546
35766
  out.end(() => {
35547
35767
  try {
35548
- fs8.renameSync(src, kept);
35549
- fs8.rmSync(dir, { recursive: true, force: true });
35768
+ fs9.renameSync(src, kept);
35769
+ fs9.rmSync(dir, { recursive: true, force: true });
35550
35770
  } catch {
35551
35771
  }
35552
35772
  });
@@ -35599,7 +35819,7 @@ var CodexAdapter = class {
35599
35819
  // ../adapters/src/_core/acp.ts
35600
35820
  var import_node_child_process7 = require("node:child_process");
35601
35821
  var import_node_crypto16 = require("node:crypto");
35602
- var fs9 = __toESM(require("node:fs"), 1);
35822
+ var fs10 = __toESM(require("node:fs"), 1);
35603
35823
  var os4 = __toESM(require("node:os"), 1);
35604
35824
  var path8 = __toESM(require("node:path"), 1);
35605
35825
  var readline3 = __toESM(require("node:readline"), 1);
@@ -35805,11 +36025,11 @@ async function runACPSession(job, cfg) {
35805
36025
  const slug4 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
35806
36026
  const binTag = path8.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
35807
36027
  const id = `${binTag}-${slug4}-${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`;
35808
- const dir = fs9.mkdtempSync(path8.join(cfg.workRoot ?? os4.tmpdir(), "oasis-session-"));
36028
+ const dir = fs10.mkdtempSync(path8.join(cfg.workRoot ?? os4.tmpdir(), "oasis-session-"));
35809
36029
  for (const [rel, content] of Object.entries(job.bundle.files)) {
35810
36030
  const file = path8.join(dir, rel);
35811
- fs9.mkdirSync(path8.dirname(file), { recursive: true });
35812
- fs9.writeFileSync(file, content);
36031
+ fs10.mkdirSync(path8.dirname(file), { recursive: true });
36032
+ fs10.writeFileSync(file, content);
35813
36033
  }
35814
36034
  const task = job.bundle.files["TASK.md"];
35815
36035
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -35827,7 +36047,7 @@ async function runACPSession(job, cfg) {
35827
36047
  stdio: ["pipe", "pipe", "pipe"]
35828
36048
  });
35829
36049
  let transcriptRef = path8.join(dir, "transcript.txt");
35830
- const transcriptOut = fs9.createWriteStream(transcriptRef);
36050
+ const transcriptOut = fs10.createWriteStream(transcriptRef);
35831
36051
  const outputCbs = [];
35832
36052
  const telemetryCbs = [];
35833
36053
  const exitCbs = [];
@@ -35838,13 +36058,13 @@ async function runACPSession(job, cfg) {
35838
36058
  if (cfg.cleanupWorkdir) {
35839
36059
  try {
35840
36060
  const keepDir = path8.join(cfg.workRoot ?? os4.tmpdir(), "oasis-transcripts");
35841
- fs9.mkdirSync(keepDir, { recursive: true });
36061
+ fs10.mkdirSync(keepDir, { recursive: true });
35842
36062
  const kept = path8.join(keepDir, `${id}.txt`);
35843
36063
  const src = transcriptRef;
35844
36064
  transcriptOut.end(() => {
35845
36065
  try {
35846
- fs9.renameSync(src, kept);
35847
- fs9.rmSync(dir, { recursive: true, force: true });
36066
+ fs10.renameSync(src, kept);
36067
+ fs10.rmSync(dir, { recursive: true, force: true });
35848
36068
  } catch {
35849
36069
  }
35850
36070
  });
@@ -36021,18 +36241,18 @@ var KiroAdapter = class {
36021
36241
  // ../adapters/src/_core/subprocess.ts
36022
36242
  var import_node_child_process8 = require("node:child_process");
36023
36243
  var import_node_crypto17 = require("node:crypto");
36024
- var fs10 = __toESM(require("node:fs"), 1);
36244
+ var fs11 = __toESM(require("node:fs"), 1);
36025
36245
  var os5 = __toESM(require("node:os"), 1);
36026
36246
  var path9 = __toESM(require("node:path"), 1);
36027
36247
  var readline4 = __toESM(require("node:readline"), 1);
36028
36248
  function materialize(job, workRoot) {
36029
36249
  const slug4 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
36030
36250
  const id = `${slug4}-${(0, import_node_crypto17.randomUUID)().slice(0, 8)}`;
36031
- const dir = fs10.mkdtempSync(path9.join(workRoot ?? os5.tmpdir(), "oasis-session-"));
36251
+ const dir = fs11.mkdtempSync(path9.join(workRoot ?? os5.tmpdir(), "oasis-session-"));
36032
36252
  for (const [rel, content] of Object.entries(job.bundle.files)) {
36033
36253
  const file = path9.join(dir, rel);
36034
- fs10.mkdirSync(path9.dirname(file), { recursive: true });
36035
- fs10.writeFileSync(file, content);
36254
+ fs11.mkdirSync(path9.dirname(file), { recursive: true });
36255
+ fs11.writeFileSync(file, content);
36036
36256
  }
36037
36257
  const task = job.bundle.files["TASK.md"];
36038
36258
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
@@ -36055,13 +36275,13 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs) {
36055
36275
  if (cfg.cleanupWorkdir) {
36056
36276
  try {
36057
36277
  const keepDir = path9.join(cfg.workRoot ?? os5.tmpdir(), "oasis-transcripts");
36058
- fs10.mkdirSync(keepDir, { recursive: true });
36278
+ fs11.mkdirSync(keepDir, { recursive: true });
36059
36279
  const kept = path9.join(keepDir, `${id}.txt`);
36060
36280
  const src = transcriptRefPtr.value;
36061
36281
  transcriptOut.end(() => {
36062
36282
  try {
36063
- fs10.renameSync(src, kept);
36064
- fs10.rmSync(dir, { recursive: true, force: true });
36283
+ fs11.renameSync(src, kept);
36284
+ fs11.rmSync(dir, { recursive: true, force: true });
36065
36285
  } catch {
36066
36286
  }
36067
36287
  });
@@ -36084,7 +36304,7 @@ function runStreamJson(job, cfg) {
36084
36304
  stdio: ["ignore", "pipe", "pipe"]
36085
36305
  });
36086
36306
  const transcriptRefPtr = { value: path9.join(dir, "transcript.txt") };
36087
- const transcriptOut = fs10.createWriteStream(transcriptRefPtr.value);
36307
+ const transcriptOut = fs11.createWriteStream(transcriptRefPtr.value);
36088
36308
  const outputCbs = [];
36089
36309
  const telemetryCbs = [];
36090
36310
  const exitCbs = [];
@@ -36142,7 +36362,7 @@ function runOneShotText(job, cfg) {
36142
36362
  stdio: ["ignore", "pipe", "pipe"]
36143
36363
  });
36144
36364
  const transcriptRefPtr = { value: path9.join(dir, "transcript.txt") };
36145
- const transcriptOut = fs10.createWriteStream(transcriptRefPtr.value);
36365
+ const transcriptOut = fs11.createWriteStream(transcriptRefPtr.value);
36146
36366
  const outputCbs = [];
36147
36367
  const exitCbs = [];
36148
36368
  const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
@@ -38647,16 +38867,16 @@ var rowToMessage = (row) => ({
38647
38867
  init_trajectory();
38648
38868
  var oasisWrapperCache;
38649
38869
  function oasisWrapperScript() {
38650
- if (oasisWrapperCache && fs12.existsSync(oasisWrapperCache)) return oasisWrapperCache;
38870
+ if (oasisWrapperCache && fs13.existsSync(oasisWrapperCache)) return oasisWrapperCache;
38651
38871
  const repoRoot = (0, import_node_url3.fileURLToPath)(new URL("../../../", __esm_import_meta_url));
38652
38872
  const tsx = path11.join(repoRoot, "node_modules/.bin/tsx");
38653
38873
  const main = path11.join(repoRoot, "packages/cli/src/main.ts");
38654
- const dir = fs12.mkdtempSync(path11.join(os6.tmpdir(), "oasis-cli-"));
38874
+ const dir = fs13.mkdtempSync(path11.join(os6.tmpdir(), "oasis-cli-"));
38655
38875
  const wrapper = path11.join(dir, "oasis");
38656
- fs12.writeFileSync(wrapper, `#!/usr/bin/env bash
38876
+ fs13.writeFileSync(wrapper, `#!/usr/bin/env bash
38657
38877
  exec ${JSON.stringify(tsx)} ${JSON.stringify(main)} "$@"
38658
38878
  `);
38659
- fs12.chmodSync(wrapper, 493);
38879
+ fs13.chmodSync(wrapper, 493);
38660
38880
  oasisWrapperCache = wrapper;
38661
38881
  return wrapper;
38662
38882
  }
@@ -38717,10 +38937,10 @@ function traceRuntimeKind(runtimeKind) {
38717
38937
  return "custom";
38718
38938
  }
38719
38939
  async function startServe(opts) {
38720
- fs12.mkdirSync(opts.dir, { recursive: true });
38940
+ fs13.mkdirSync(opts.dir, { recursive: true });
38721
38941
  const lock = path11.join(opts.dir, "serve.lock");
38722
- if (fs12.existsSync(lock)) {
38723
- const pid = Number(fs12.readFileSync(lock, "utf8"));
38942
+ if (fs13.existsSync(lock)) {
38943
+ const pid = Number(fs13.readFileSync(lock, "utf8"));
38724
38944
  let alive = false;
38725
38945
  try {
38726
38946
  process.kill(pid, 0);
@@ -38728,12 +38948,12 @@ async function startServe(opts) {
38728
38948
  } catch {
38729
38949
  }
38730
38950
  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`);
38731
- fs12.unlinkSync(lock);
38951
+ fs13.unlinkSync(lock);
38732
38952
  }
38733
- fs12.writeFileSync(lock, String(process.pid));
38953
+ fs13.writeFileSync(lock, String(process.pid));
38734
38954
  const loadJson = (name) => {
38735
38955
  const file = path11.join(opts.dir, name);
38736
- return fs12.existsSync(file) ? JSON.parse(fs12.readFileSync(file, "utf8")) : void 0;
38956
+ return fs13.existsSync(file) ? JSON.parse(fs13.readFileSync(file, "utf8")) : void 0;
38737
38957
  };
38738
38958
  const oplog = await NdjsonOplogStore.open(path11.join(opts.dir, "oplog.ndjson"));
38739
38959
  const blobs = new DirBlobStore(path11.join(opts.dir, "blobs"));
@@ -38770,12 +38990,13 @@ async function startServe(opts) {
38770
38990
  const issuer = createTokenIssuer();
38771
38991
  const operatorActor = `actor:human:${os6.userInfo().username}`;
38772
38992
  const operatorToken = issuer.issue(operatorActor);
38773
- fs12.writeFileSync(path11.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
38993
+ fs13.writeFileSync(path11.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
38774
38994
  const nodeTokens = createNodeTokenStore(path11.join(opts.dir, "node-tokens.json"));
38995
+ const nodeStore = await FileNodeStore.open(path11.join(opts.dir, "nodes.json"));
38775
38996
  const registryAuditFile = path11.join(opts.dir, "registry-audit.ndjson");
38776
38997
  const registryListeners = /* @__PURE__ */ new Set();
38777
38998
  const registryAudit = (record3) => {
38778
- fs12.appendFile(registryAuditFile, JSON.stringify(record3) + "\n", () => {
38999
+ fs13.appendFile(registryAuditFile, JSON.stringify(record3) + "\n", () => {
38779
39000
  });
38780
39001
  for (const l of registryListeners) l({ kind: record3.kind, actor: record3.actor, target: record3.target, timestamp: record3.timestamp });
38781
39002
  };
@@ -38807,6 +39028,7 @@ async function startServe(opts) {
38807
39028
  } else {
38808
39029
  projectStateStore = await FileProjectStateStore.open(path11.join(opts.dir, "artifact-document-projects.json"));
38809
39030
  artifactStateStore = await FileArtifactStateStore.open(path11.join(opts.dir, "artifact-document-state.json"));
39031
+ chatSessionStore = new MemoryChatSessionStore();
38810
39032
  console.log("[serve] \u4EA4\u4ED8\u7269\u72B6\u6001\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
38811
39033
  }
38812
39034
  const outlineUrl = process.env["OUTLINE_URL"];
@@ -38910,9 +39132,9 @@ async function startServe(opts) {
38910
39132
  const interventionDrafts = new InterventionDraftStore();
38911
39133
  const journalFile = path11.join(opts.dir, "dispatch-journal.ndjson");
38912
39134
  const journalRing = [];
38913
- if (fs12.existsSync(journalFile)) {
39135
+ if (fs13.existsSync(journalFile)) {
38914
39136
  try {
38915
- const lines = fs12.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean);
39137
+ const lines = fs13.readFileSync(journalFile, "utf8").split(/\r?\n/).filter(Boolean);
38916
39138
  for (const line of lines.slice(-500)) {
38917
39139
  try {
38918
39140
  journalRing.push(JSON.parse(line));
@@ -38925,7 +39147,7 @@ async function startServe(opts) {
38925
39147
  const journal = (entry) => {
38926
39148
  journalRing.push(entry);
38927
39149
  if (journalRing.length > 500) journalRing.shift();
38928
- fs12.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
39150
+ fs13.appendFile(journalFile, JSON.stringify(entry) + "\n", () => {
38929
39151
  });
38930
39152
  };
38931
39153
  let dispatcher;
@@ -39017,6 +39239,7 @@ async function startServe(opts) {
39017
39239
  nodesDomain({
39018
39240
  getHub: () => hub,
39019
39241
  nodeTokens,
39242
+ nodeStore,
39020
39243
  gatewayUrl: opts.gatewayUrl ?? `ws://127.0.0.1:${opts.port ?? 7320}/node-gateway`,
39021
39244
  repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git"
39022
39245
  }),
@@ -39030,7 +39253,7 @@ async function startServe(opts) {
39030
39253
  resolveEngine: (cid) => engineRouter.getEngine(cid ?? DEFAULT_COMPANY_ID)
39031
39254
  }),
39032
39255
  trace.register,
39033
- ...chatSessionStore ? [createChatSessionsDomain({ store: chatSessionStore, registry: registryStore })] : []
39256
+ createChatSessionsDomain({ store: chatSessionStore, registry: registryStore })
39034
39257
  ],
39035
39258
  drafts: interventionDrafts,
39036
39259
  // 暴露注册的 artifact 类型,给前端「发起工单」动态拉取根产物可选类型——schema.json 增改即自动扩展,
@@ -39039,7 +39262,8 @@ async function startServe(opts) {
39039
39262
  "artifact-types": () => schema.map((d) => ({ name: d.name, ownerRole: d.ownerRole, contentType: d.contentType })),
39040
39263
  dispatches: () => ({
39041
39264
  recent: journalRing.slice(-100),
39042
- fused: dispatcher?.fusedJobs() ?? []
39265
+ fused: dispatcher?.fusedJobs() ?? [],
39266
+ queued: dispatcher?.queuedCount() ?? 0
39043
39267
  })
39044
39268
  },
39045
39269
  resolveActorEnv: async (actorId) => (await buildActorProvision(actors.service, actorId)).env,
@@ -39282,7 +39506,10 @@ async function startServe(opts) {
39282
39506
  journal,
39283
39507
  // TrajectoryEvent 是唯一事件模型;trace 旁账与 M7 蒸馏库并行消费同一流(§16.D 收口)。
39284
39508
  trajectory: combineTrajectorySinks([trajectorySink, traceStoreSink]),
39285
- ...opts.backoff !== void 0 ? { backoff: opts.backoff } : {}
39509
+ ...opts.backoff !== void 0 ? { backoff: opts.backoff } : {},
39510
+ ...opts.maxConcurrentProduce !== void 0 ? { maxConcurrentProduce: opts.maxConcurrentProduce } : {},
39511
+ // 每 agent 并发产出上限默认 5(工单数 / 全局总量默认不限);--max-produce-per-agent N 覆盖。
39512
+ maxConcurrentProducePerActor: opts.maxConcurrentProducePerActor ?? 5
39286
39513
  });
39287
39514
  const d = dispatcher;
39288
39515
  let logged = 0;
@@ -39444,7 +39671,7 @@ async function startServe(opts) {
39444
39671
  await server.close();
39445
39672
  if (pgPool) await pgPool.end().catch(() => {
39446
39673
  });
39447
- fs12.rmSync(lock, { force: true });
39674
+ fs13.rmSync(lock, { force: true });
39448
39675
  }
39449
39676
  };
39450
39677
  }
@@ -39708,7 +39935,7 @@ async function startNode(opts) {
39708
39935
  init_src4();
39709
39936
  var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uFF08\u670D\u52A1\u7AEF\u7626\u5BA2\u6237\u7AEF\uFF09
39710
39937
 
39711
- oasis serve [--dir .oasis] [--port 7320] [--dispatch true [--model haiku]] [--allow-simple-tokens true] [--gateway-url wss://host/oasis-api/node-gateway]
39938
+ oasis serve [--dir .oasis] [--port 7320] [--dispatch true [--model haiku] [--max-produce-per-agent 5] [--max-concurrent-produce N]] [--allow-simple-tokens true] [--gateway-url wss://host/oasis-api/node-gateway]
39712
39939
  # --gateway-url\uFF08\u6216 $OASIS_GATEWAY_URL\uFF09\uFF1A\u8282\u70B9\u5165\u7F51\u811A\u672C\u91CC\u5B88\u62A4\u8FDB\u7A0B\u8981\u8FDE\u7684\u7F51\u5173 URL\uFF1B\u516C\u7F51\u7ECF nginx \u5FC5\u8BBE\uFF0C\u5426\u5219\u9ED8\u8BA4\u672C\u673A ws://127.0.0.1:<port>\u3002
39713
39940
  oasis export-trajectories [--dir d] [--out samples.jsonl] \u5BFC\u51FA\u84B8\u998F\u6837\u672C\uFF08\u8F93\u5165\u5305+\u4E8B\u4EF6\u6D41+\u7ED3\u679C\u5F15\u7528+gate \u6807\u7B7E\uFF09
39714
39941
  oasis serve install [--dir d] [--port p] [--dispatch true --model m] [--bin ~/.local/bin/oasis] [--unit-dir ~/.config/systemd/user] \u751F\u6210 systemd \u7528\u6237\u5355\u5143\uFF08D2 \u5B88\u62A4\u5316\uFF09
@@ -39867,19 +40094,19 @@ async function runCli(argv, println = console.log) {
39867
40094
  const serverUrl = flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? "ws://127.0.0.1:7320/node-gateway";
39868
40095
  const nodeName = flags.get("name") ?? process.env["OASIS_NODE_NAME"];
39869
40096
  const nodeIdFile = path12.join(dir, "node-id");
39870
- const storedNodeId = fs13.existsSync(nodeIdFile) ? fs13.readFileSync(nodeIdFile, "utf8").trim() : null;
40097
+ const storedNodeId = fs14.existsSync(nodeIdFile) ? fs14.readFileSync(nodeIdFile, "utf8").trim() : null;
39871
40098
  const nodeId = storedNodeId ?? flags.get("id") ?? process.env["OASIS_NODE_ID"] ?? `node-${(0, import_node_crypto20.randomUUID)()}`;
39872
40099
  if (!storedNodeId) {
39873
- fs13.mkdirSync(dir, { recursive: true });
39874
- fs13.writeFileSync(nodeIdFile, nodeId);
40100
+ fs14.mkdirSync(dir, { recursive: true });
40101
+ fs14.writeFileSync(nodeIdFile, nodeId);
39875
40102
  }
39876
40103
  const nodeTokenFile = path12.join(dir, "node-token");
39877
- const token2 = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? (fs13.existsSync(nodeTokenFile) ? fs13.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
40104
+ const token2 = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? (fs14.existsSync(nodeTokenFile) ? fs14.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
39878
40105
  if (flags.has("service")) {
39879
40106
  const { spawnSync, execSync: execSync2 } = await import("node:child_process");
39880
40107
  if (token2) {
39881
- fs13.mkdirSync(dir, { recursive: true });
39882
- fs13.writeFileSync(nodeTokenFile, token2, { mode: 384 });
40108
+ fs14.mkdirSync(dir, { recursive: true });
40109
+ fs14.writeFileSync(nodeTokenFile, token2, { mode: 384 });
39883
40110
  }
39884
40111
  println("\u2192 Installing oasis_test globally...");
39885
40112
  spawnSync("npm", ["install", "-g", "oasis_test@latest"], { stdio: "inherit" });
@@ -39888,10 +40115,10 @@ async function runCli(argv, println = console.log) {
39888
40115
  const svcArgs = `node --server-ws ${serverUrl} --id ${nodeId} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
39889
40116
  if (process.platform === "linux") {
39890
40117
  const svcFile = path12.join(os7.homedir(), ".config/systemd/user/oasis-node.service");
39891
- fs13.mkdirSync(path12.dirname(svcFile), { recursive: true });
40118
+ fs14.mkdirSync(path12.dirname(svcFile), { recursive: true });
39892
40119
  if (spawnSync("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
39893
40120
  spawnSync("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
39894
- fs13.writeFileSync(svcFile, [
40121
+ fs14.writeFileSync(svcFile, [
39895
40122
  "[Unit]",
39896
40123
  "Description=Oasis Node Daemon",
39897
40124
  "After=network.target",
@@ -39916,10 +40143,10 @@ async function runCli(argv, println = console.log) {
39916
40143
  println(" Stop : systemctl --user stop oasis-node");
39917
40144
  } else if (process.platform === "darwin") {
39918
40145
  const plist = path12.join(os7.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
39919
- fs13.mkdirSync(path12.dirname(plist), { recursive: true });
40146
+ fs14.mkdirSync(path12.dirname(plist), { recursive: true });
39920
40147
  spawnSync("launchctl", ["unload", plist], { stdio: "ignore" });
39921
40148
  const argXml = [binPath, "node", "--server-ws", serverUrl, "--id", nodeId, "--dir", dir, ...nodeName ? ["--name", nodeName] : []].map((a) => `<string>${a}</string>`).join("");
39922
- fs13.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>${os7.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os7.homedir()}/.oasis-node.err</string></dict></plist>`);
40149
+ fs14.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>${os7.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os7.homedir()}/.oasis-node.err</string></dict></plist>`);
39923
40150
  spawnSync("launchctl", ["load", plist], { stdio: "inherit" });
39924
40151
  println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
39925
40152
  println(` Logs : tail -f ${os7.homedir()}/.oasis-node.log`);
@@ -39979,7 +40206,7 @@ async function runCli(argv, println = console.log) {
39979
40206
  const outFile = flags.get("out");
39980
40207
  const lines = samples.map((sample) => JSON.stringify(sample)).join("\n");
39981
40208
  if (outFile !== void 0) {
39982
- fs13.writeFileSync(outFile, lines + (lines ? "\n" : ""));
40209
+ fs14.writeFileSync(outFile, lines + (lines ? "\n" : ""));
39983
40210
  println(`\u5DF2\u5BFC\u51FA ${samples.length} \u6761\u8F68\u8FF9\u6837\u672C \u2192 ${outFile}\uFF08approved/rejected \u6210\u5BF9\u5373\u504F\u597D\u5BF9\uFF09`);
39984
40211
  } else {
39985
40212
  println(lines);
@@ -40007,9 +40234,9 @@ async function runCli(argv, println = console.log) {
40007
40234
  `WantedBy=default.target`,
40008
40235
  ``
40009
40236
  ].join("\n");
40010
- fs13.mkdirSync(unitDir, { recursive: true });
40237
+ fs14.mkdirSync(unitDir, { recursive: true });
40011
40238
  const unitPath = path12.join(unitDir, `${name}.service`);
40012
- fs13.writeFileSync(unitPath, unit);
40239
+ fs14.writeFileSync(unitPath, unit);
40013
40240
  println(`\u5DF2\u5199\u5165 ${unitPath}`);
40014
40241
  println(`\u542F\u7528\uFF1Asystemctl --user daemon-reload && systemctl --user enable --now ${name}`);
40015
40242
  println(`\u5F00\u673A\u81EA\u542F\uFF08\u542B\u672A\u767B\u5F55\uFF09\uFF1Aloginctl enable-linger $USER`);
@@ -40022,6 +40249,8 @@ async function runCli(argv, println = console.log) {
40022
40249
  dir,
40023
40250
  ...port !== void 0 ? { port } : {},
40024
40251
  dispatch: flags.get("dispatch") === "true",
40252
+ ...flags.has("max-concurrent-produce") ? { maxConcurrentProduce: Number(flags.get("max-concurrent-produce")) } : {},
40253
+ ...flags.has("max-produce-per-agent") ? { maxConcurrentProducePerActor: Number(flags.get("max-produce-per-agent")) } : {},
40025
40254
  ...flags.has("model") ? { model: flags.get("model") } : {},
40026
40255
  allowSimpleTokens: flags.get("allow-simple-tokens") === "true",
40027
40256
  ...flags.get("gateway-url") ?? process.env["OASIS_GATEWAY_URL"] ? { gatewayUrl: flags.get("gateway-url") ?? process.env["OASIS_GATEWAY_URL"] } : {}
@@ -40036,12 +40265,12 @@ async function runCli(argv, println = console.log) {
40036
40265
  }
40037
40266
  const base = flags.get("server") ?? process.env["OASIS_SERVER"] ?? "http://127.0.0.1:7320";
40038
40267
  const tokenFile = path12.join(dir, "operator-token");
40039
- const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs13.existsSync(tokenFile) ? fs13.readFileSync(tokenFile, "utf8").trim() : void 0);
40268
+ const token = flags.get("token") ?? process.env["OASIS_TOKEN"] ?? (fs14.existsSync(tokenFile) ? fs14.readFileSync(tokenFile, "utf8").trim() : void 0);
40040
40269
  if (!token) {
40041
40270
  throw new Error(`\u65E0 token\uFF1A\u5148 oasis serve\uFF08\u4F1A\u751F\u6210 ${tokenFile}\uFF09\uFF0C\u6216\u663E\u5F0F --token / $OASIS_TOKEN`);
40042
40271
  }
40043
40272
  const api = makeClient(base, token);
40044
- const readFileArg = (file) => fs13.readFileSync(file, "utf8");
40273
+ const readFileArg = (file) => fs14.readFileSync(file, "utf8");
40045
40274
  const parseJsonFlag = (value, name) => {
40046
40275
  const parsed = JSON.parse(value);
40047
40276
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -40059,11 +40288,11 @@ async function runCli(argv, println = console.log) {
40059
40288
  const readDirFiles = (root) => {
40060
40289
  const out = [];
40061
40290
  const walk = (abs, rel) => {
40062
- for (const name of fs13.readdirSync(abs)) {
40291
+ for (const name of fs14.readdirSync(abs)) {
40063
40292
  const childAbs = path12.join(abs, name);
40064
40293
  const childRel = rel ? `${rel}/${name}` : name;
40065
- if (fs13.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
40066
- else out.push({ path: childRel, contentBase64: fs13.readFileSync(childAbs).toString("base64") });
40294
+ if (fs14.statSync(childAbs).isDirectory()) walk(childAbs, childRel);
40295
+ else out.push({ path: childRel, contentBase64: fs14.readFileSync(childAbs).toString("base64") });
40067
40296
  }
40068
40297
  };
40069
40298
  walk(root, "");
@@ -40747,18 +40976,18 @@ var parseFlags = (argv) => {
40747
40976
  };
40748
40977
  var readConfig = () => {
40749
40978
  try {
40750
- return JSON.parse(fs14.readFileSync(CONFIG_FILE, "utf8"));
40979
+ return JSON.parse(fs15.readFileSync(CONFIG_FILE, "utf8"));
40751
40980
  } catch {
40752
40981
  return null;
40753
40982
  }
40754
40983
  };
40755
40984
  var saveConfig = (c) => {
40756
- fs14.mkdirSync(OASIS_DIR, { recursive: true });
40757
- fs14.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
40985
+ fs15.mkdirSync(OASIS_DIR, { recursive: true });
40986
+ fs15.writeFileSync(CONFIG_FILE, JSON.stringify(c), { mode: 384 });
40758
40987
  };
40759
40988
  var readPid = () => {
40760
40989
  try {
40761
- const p = parseInt(fs14.readFileSync(PID_FILE, "utf8").trim(), 10);
40990
+ const p = parseInt(fs15.readFileSync(PID_FILE, "utf8").trim(), 10);
40762
40991
  return isNaN(p) ? null : p;
40763
40992
  } catch {
40764
40993
  return null;
@@ -40774,10 +41003,10 @@ var isRunning = (pid) => {
40774
41003
  };
40775
41004
  var httpBase = (wsUrl) => wsUrl.replace(/^wss?:\/\//, "http://").replace(/\/node-gateway.*$/, "");
40776
41005
  function installBinary() {
40777
- fs14.mkdirSync(path13.dirname(BIN_FILE), { recursive: true });
40778
- fs14.copyFileSync(process.argv[1], BIN_FILE);
40779
- fs14.mkdirSync(path13.dirname(LOCAL_BIN), { recursive: true });
40780
- fs14.writeFileSync(LOCAL_BIN, `#!/bin/sh
41006
+ fs15.mkdirSync(path13.dirname(BIN_FILE), { recursive: true });
41007
+ fs15.copyFileSync(process.argv[1], BIN_FILE);
41008
+ fs15.mkdirSync(path13.dirname(LOCAL_BIN), { recursive: true });
41009
+ fs15.writeFileSync(LOCAL_BIN, `#!/bin/sh
40781
41010
  exec node "${BIN_FILE}" "$@"
40782
41011
  `, { mode: 493 });
40783
41012
  }
@@ -40785,8 +41014,8 @@ function setupAutostart() {
40785
41014
  const cmd = `${process.execPath} "${BIN_FILE}" --_daemon`;
40786
41015
  if (process.platform === "linux") {
40787
41016
  const unitDir = path13.join(os8.homedir(), ".config", "systemd", "user");
40788
- fs14.mkdirSync(unitDir, { recursive: true });
40789
- fs14.writeFileSync(path13.join(unitDir, "oasis-node.service"), [
41017
+ fs15.mkdirSync(unitDir, { recursive: true });
41018
+ fs15.writeFileSync(path13.join(unitDir, "oasis-node.service"), [
40790
41019
  "[Unit]",
40791
41020
  "Description=Oasis Node Daemon",
40792
41021
  "After=network.target",
@@ -40808,8 +41037,8 @@ function setupAutostart() {
40808
41037
  }
40809
41038
  } else if (process.platform === "darwin") {
40810
41039
  const plist = path13.join(os8.homedir(), "Library", "LaunchAgents", "com.oasis.node.plist");
40811
- fs14.mkdirSync(path13.dirname(plist), { recursive: true });
40812
- fs14.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
41040
+ fs15.mkdirSync(path13.dirname(plist), { recursive: true });
41041
+ fs15.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
40813
41042
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
40814
41043
  <plist version="1.0"><dict>
40815
41044
  <key>Label</key><string>com.oasis.node</string>
@@ -40825,14 +41054,14 @@ function setupAutostart() {
40825
41054
  }
40826
41055
  }
40827
41056
  function spawnDaemon() {
40828
- const log3 = fs14.openSync(LOG_FILE, "a");
41057
+ const log3 = fs15.openSync(LOG_FILE, "a");
40829
41058
  const child = (0, import_node_child_process10.spawn)(process.execPath, [BIN_FILE, "--_daemon"], {
40830
41059
  detached: true,
40831
41060
  stdio: ["ignore", log3, log3]
40832
41061
  });
40833
41062
  child.unref();
40834
41063
  const pid = child.pid ?? 0;
40835
- fs14.writeFileSync(PID_FILE, String(pid));
41064
+ fs15.writeFileSync(PID_FILE, String(pid));
40836
41065
  return pid;
40837
41066
  }
40838
41067
  function stopDaemon() {
@@ -40844,7 +41073,7 @@ function stopDaemon() {
40844
41073
  }
40845
41074
  }
40846
41075
  try {
40847
- fs14.unlinkSync(PID_FILE);
41076
+ fs15.unlinkSync(PID_FILE);
40848
41077
  } catch {
40849
41078
  }
40850
41079
  try {
@@ -40865,10 +41094,10 @@ void (async () => {
40865
41094
  console.error("[oasis] no config \u2014 run `oasis start` first");
40866
41095
  process.exit(1);
40867
41096
  }
40868
- fs14.writeFileSync(PID_FILE, String(process.pid));
41097
+ fs15.writeFileSync(PID_FILE, String(process.pid));
40869
41098
  const cleanup = () => {
40870
41099
  try {
40871
- fs14.unlinkSync(PID_FILE);
41100
+ fs15.unlinkSync(PID_FILE);
40872
41101
  } catch {
40873
41102
  }
40874
41103
  };
@@ -40894,7 +41123,7 @@ void (async () => {
40894
41123
  serverUrl: cfg.serverUrl,
40895
41124
  token: cfg.token,
40896
41125
  nodeId: cfg.nodeId ?? `node-${(0, import_node_crypto21.randomUUID)()}`,
40897
- ...cfg.name ? { nodeName: cfg.name } : {}
41126
+ nodeName: cfg.name ?? cfg.nodeId ?? `node-${(0, import_node_crypto21.randomUUID)()}`
40898
41127
  });
40899
41128
  return;
40900
41129
  }