oasis_test 0.1.77 → 0.1.78

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 +238 -44
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4734,12 +4734,12 @@ var init_memory_prompt = __esm({
4734
4734
  });
4735
4735
 
4736
4736
  // ../core/src/assembler.ts
4737
- function renderLetterDetail(model, a, recipient) {
4737
+ function renderLetterDetail(model, a, recipient, actorLabel) {
4738
4738
  const rootSeq = model.annotationSeq.get(a.id) ?? 0;
4739
4739
  const lastSelf = recipient !== void 0 ? lastPostSeqOf(model, a, recipient) : Number.NEGATIVE_INFINITY;
4740
4740
  const lines = [];
4741
4741
  if (rootSeq > lastSelf) lines.push(`- \u300C${a.body}\u300D`);
4742
- for (const t of a.thread) if ((t.seq ?? rootSeq) > lastSelf) lines.push(` - \u21B3 ${t.author}\uFF1A${t.body}`);
4742
+ for (const t of a.thread) if ((t.seq ?? rootSeq) > lastSelf) lines.push(` - \u21B3 ${actorLabel(t.author)}\uFF1A${t.body}`);
4743
4743
  lines.push(`\uFF08\u672C\u4FE1\u5168\u6587\uFF1A\`oasis content ${a.id}\`\uFF09`);
4744
4744
  return lines;
4745
4745
  }
@@ -4864,12 +4864,14 @@ async function assembleContext(args) {
4864
4864
  if (!artifact) throw new Error(`assembleContext: artifact not found: ${artifactId}`);
4865
4865
  const typeDef = args.schema?.get(artifact.type);
4866
4866
  const canvasMode = typeDef?.name === "design" && args.action !== "review" && args.part === void 0;
4867
+ const actorLabels = args.resolveActorLabels ? await args.resolveActorLabels().catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
4868
+ const actorLabel = (id) => id === void 0 ? "" : actorLabels.get(id) ?? id;
4867
4869
  const files = {};
4868
4870
  if (canvasMode && artifact.description) files["DESIGN_BRIEF.md"] = artifact.description;
4869
4871
  if (args.action === "reply") {
4870
4872
  const a = args.annotationId !== void 0 ? model.annotations.get(args.annotationId) : void 0;
4871
4873
  if (!a) throw new Error(`assembleContext(reply): annotation not found: ${args.annotationId}`);
4872
- const newPostLines = renderLetterDetail(model, a, args.actorId);
4874
+ const newPostLines = renderLetterDetail(model, a, args.actorId, actorLabel);
4873
4875
  if (args.resolveActorContext && args.actorId) {
4874
4876
  const actorCtx = await args.resolveActorContext(args.actorId).catch(() => null);
4875
4877
  if (actorCtx?.config?.prompt) Object.assign(files, splitIdentityFiles(actorCtx.config.prompt));
@@ -4881,13 +4883,14 @@ async function assembleContext(args) {
4881
4883
  ``,
4882
4884
  `artifact_id: ${artifactId}`,
4883
4885
  `annotation_id: ${a.id}`,
4884
- `actor_id: ${args.actorId ?? ""}`,
4886
+ // 诊断 1be339c7:`your_actor_id` 而非 `actor_id`——消歧「这行是我还是对方」(与 chat 抬头同款同改)。
4887
+ `your_actor_id: ${args.actorId ?? ""}`,
4885
4888
  ``,
4886
4889
  `## \u672C\u6B21\u4E3A\u4EC0\u4E48\u5524\u8D77\u4F60`,
4887
4890
  `\u6709\u4EBA\u5728\u4EA7\u7269 ${artifactId} \u7684\u4E00\u5C01\u4FE1\u91CC @ \u4E86\u4F60\uFF0C\u7B49\u4F60\u56DE\u8BDD\u3002\u4F60**\u4E0D\u662F**\u8FD9\u4E2A\u4EA7\u7269\u7684 owner\u2014\u2014`,
4888
4891
  `\u672C\u8F6E\u4F60\u53EA\u6709\u53D1\u8A00\u6743\uFF1A\u8BFB\u4E0A\u4E0B\u6587\u3001\u56DE\u4E00\u5E16\uFF0C\u522B\u7684\u90FD\u4E0D\u7528\uFF08\u4E5F\u4E0D\u80FD\uFF09\u505A\u3002`,
4889
4892
  ``,
4890
- `## \u8981\u4F60\u56DE\u7684\u65B0\u8BDD\uFF08\u4F5C\u8005 ${a.author}${a.state === "open" ? "" : `\uFF0C\u72B6\u6001 ${a.state}`}\uFF09`,
4893
+ `## \u8981\u4F60\u56DE\u7684\u65B0\u8BDD\uFF08\u4F5C\u8005 ${actorLabel(a.author)}${a.state === "open" ? "" : `\uFF0C\u72B6\u6001 ${a.state}`}\uFF09`,
4891
4894
  ...newPostLines,
4892
4895
  ``,
4893
4896
  `## \u9700\u8981\u4F60\u505A\u4EC0\u4E48`,
@@ -5037,7 +5040,7 @@ async function assembleContext(args) {
5037
5040
  const detail = [];
5038
5041
  for (const r of queued) {
5039
5042
  const info = queuedParts.find((q) => q.revisionId === r.id);
5040
- const who = r.author === artifact.owner ? "\u4F60\u81EA\u5DF1\u4E0A\u4E00\u8F6E" : r.author;
5043
+ const who = r.author === artifact.owner ? "\u4F60\u81EA\u5DF1\u4E0A\u4E00\u8F6E" : actorLabel(r.author);
5041
5044
  const baseC = await contentMapOf(r.base ? model.revisions.get(r.base) ?? null : null);
5042
5045
  const newC = await contentMapOf(r);
5043
5046
  const dir = info?.dir ?? `competing/${slug2(r.id.slice(9, 17))}`;
@@ -5045,7 +5048,7 @@ async function assembleContext(args) {
5045
5048
  if (baseC !== null && newC !== null) {
5046
5049
  files[`${dir}/DIFF.md`] = `# \`${r.id.slice(9, 17)}\` \u76F8\u5BF9\u5B83\u81EA\u5DF1\u7684\u5E95\u7A3F\uFF08base \`${(r.base ?? "\u2205").slice(9, 17)}\`\uFF09\u6539\u4E86\u4EC0\u4E48
5047
5050
 
5048
- > \u4F5C\u8005\uFF1A${r.author}\u3000\u7406\u7531\uFF1A${r.reason}
5051
+ > \u4F5C\u8005\uFF1A${actorLabel(r.author)}\u3000\u7406\u7531\uFF1A${r.reason}
5049
5052
 
5050
5053
  ${manifestDiff(baseC, newC)}
5051
5054
  `;
@@ -5119,15 +5122,15 @@ ${manifestDiff(baseC, newC)}
5119
5122
  const onRev = v2.onRev;
5120
5123
  const stale = head !== null && onRev !== head;
5121
5124
  const at = stale ? `\uFF08\u57FA\u4E8E ${onRev}\uFF0C**\u5F53\u524D head \u5DF2\u662F ${head}**\u2014\u2014\u81EA\u884C\u5224\u65AD\u8FD9\u6761\u662F\u5426\u5DF2\u88AB\u540E\u7EED\u7248\u672C\u4FEE\u6389\uFF1B\u770B\u90A3\u4E00\u7248\u539F\u6587\uFF1A\`oasis content ${onRev}\`\uFF09` : "";
5122
- return `- ${v2.author}${at}\uFF1A${truncateReviewNote(v2.note ?? "\uFF08\u65E0\u8BC4\u8BED\uFF09")}`;
5125
+ return `- ${actorLabel(v2.author)}${at}\uFF1A${truncateReviewNote(v2.note ?? "\uFF08\u65E0\u8BC4\u8BED\uFF09")}`;
5123
5126
  }),
5124
5127
  closing: `**\u9010\u6761\u56DE\u5E94\u4E0A\u9762\u7684\u8BC4\u5BA1\u610F\u89C1**\uFF08\u6539\u52A8\u5E76\u5165\u672C\u8F6E propose\uFF09\u3002`
5125
5128
  });
5126
5129
  }
5127
5130
  for (const a of openAnnosHere) {
5128
- const from = `${a.raisedFrom ?? a.author}${a.anchor.target !== artifactId ? `\uFF08\u951A ${a.anchor.target}\uFF09` : ""}`;
5129
- const detail = renderLetterDetail(model, a, ownerId);
5130
- const detailFull = [`- \u300C${a.body}\u300D`, ...a.thread.map((t) => ` - \u21B3 ${t.author}\uFF1A${t.body}`)];
5131
+ const from = `${actorLabel(a.raisedFrom ?? a.author)}${a.anchor.target !== artifactId ? `\uFF08\u951A ${a.anchor.target}\uFF09` : ""}`;
5132
+ const detail = renderLetterDetail(model, a, ownerId, actorLabel);
5133
+ const detailFull = [`- \u300C${a.body}\u300D`, ...a.thread.map((t) => ` - \u21B3 ${actorLabel(t.author)}\uFF1A${t.body}`)];
5131
5134
  if (a.state !== "open") {
5132
5135
  tasks.push({
5133
5136
  label: `\u3010\u590D\u6D3B\u7684\u4FE1\xB7\u4F5C\u8005\u8FFD\u95EE\u3011${from}\uFF08id\uFF1A${a.id}\uFF09`,
@@ -5510,7 +5513,8 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
5510
5513
  (e) => `- ${e.to} @ ${e.pinned ?? "\u2205\uFF08\u672A\u5C31\u7EEA\uFF09"}${e.required ? " [required]" : ""}`
5511
5514
  ),
5512
5515
  `\u4E0B\u6E38\u6D88\u8D39\u8005\uFF1A${consumers.length === 0 ? "\uFF08\u6682\u65E0\uFF09" : ""}`,
5513
- ...consumers.map((c) => `- ${c.id}\uFF08type=${c.type}\uFF0Cowner=${c.owner}\uFF09`),
5516
+ // 诊断 1be339c7:邻域里下游消费者的 owner 也走 actorLabel——否则这里留一个裸 actor id
5517
+ ...consumers.map((c) => `- ${c.id}\uFF08type=${c.type}\uFF0Cowner=${actorLabel(c.owner)}\uFF09`),
5514
5518
  ...staleSet.length > 0 ? [
5515
5519
  ``,
5516
5520
  `## \u8FC7\u671F\u8F93\u5165\uFF08stale-set\uFF09`,
@@ -6884,6 +6888,7 @@ var init_dispatcher = __esm({
6884
6888
  ...this.opts.schema !== void 0 ? { schema: this.opts.schema } : {},
6885
6889
  ...codeRepo ? { codeRepo } : {},
6886
6890
  ...this.opts.resolveActorContext !== void 0 ? { resolveActorContext: this.opts.resolveActorContext } : {},
6891
+ ...this.opts.resolveActorLabels !== void 0 ? { resolveActorLabels: this.opts.resolveActorLabels } : {},
6887
6892
  ...this.opts.resolveRoleBriefs !== void 0 ? { resolveRoleBriefs: this.opts.resolveRoleBriefs } : {},
6888
6893
  ...materializeSkills ? { materializeSkills } : {},
6889
6894
  ...resolveActorMemoryIndex ? { resolveActorMemoryIndex } : {}
@@ -137607,19 +137612,27 @@ var init_live_chat = __esm({
137607
137612
  * 顺序不能倒:runtime 没接受就不该在流里留下痕迹,否则刷新后那条插入会凭空消失。
137608
137613
  */
137609
137614
  async append(chatSessionId, text2) {
137615
+ const t0 = Date.now();
137616
+ const say = (r, extra) => {
137617
+ const bits = { sid: chatSessionId, accepted: r.accepted, reason: r.reason ?? "-", ms: Date.now() - t0, ...extra ?? {} };
137618
+ console.log("[live-chat.append]", JSON.stringify(bits));
137619
+ return r;
137620
+ };
137610
137621
  const turn = this.turns.get(chatSessionId);
137611
- if (!turn || turn.status !== "running") return { accepted: false, reason: "no-live-turn" };
137622
+ if (!turn || turn.status !== "running") {
137623
+ return say({ accepted: false, reason: "no-live-turn" }, { turnStatus: turn?.status ?? "<no-turn>" });
137624
+ }
137612
137625
  const fn = turn.handle.appendInput;
137613
- if (typeof fn !== "function") return { accepted: false, reason: "unsupported" };
137626
+ if (typeof fn !== "function") return say({ accepted: false, reason: "unsupported" });
137614
137627
  let res;
137615
137628
  try {
137616
137629
  res = await fn.call(turn.handle, { text: text2 });
137617
- } catch {
137618
- return { accepted: false, reason: "rejected" };
137630
+ } catch (e) {
137631
+ return say({ accepted: false, reason: "rejected" }, { err: String(e) });
137619
137632
  }
137620
- if (!res.accepted) return res;
137633
+ if (!res.accepted) return say(res, { from: "runtime" });
137621
137634
  if (this.turns.get(chatSessionId) !== turn || turn.status !== "running") {
137622
- return { accepted: true, reason: "turn-finished" };
137635
+ return say({ accepted: true, reason: "turn-finished" }, { turnStatus: turn.status, replaced: this.turns.get(chatSessionId) !== turn });
137623
137636
  }
137624
137637
  const withSeq = { type: "user", text: text2, seq: ++turn.seq };
137625
137638
  turn.buffer.push(withSeq);
@@ -142082,22 +142095,70 @@ async function startOasisServer(opts) {
142082
142095
  const discussSessions = opts.discussSessions ?? /* @__PURE__ */ new Map();
142083
142096
  const reviewWaiters = /* @__PURE__ */ new Map();
142084
142097
  const terminalReviews = /* @__PURE__ */ new Map();
142085
- const notifyReviewResolved = (draftId, r) => {
142098
+ const notifyReviewResolved = (draftId, r, resume) => {
142099
+ if (terminalReviews.has(draftId)) return;
142086
142100
  terminalReviews.set(draftId, r);
142087
142101
  if (terminalReviews.size > 512) {
142088
142102
  const first = terminalReviews.keys().next().value;
142089
142103
  if (first !== void 0) terminalReviews.delete(first);
142090
142104
  }
142091
142105
  const waiters = reviewWaiters.get(draftId);
142106
+ const hadWaiters = !!waiters && waiters.size > 0;
142092
142107
  if (waiters) {
142093
142108
  reviewWaiters.delete(draftId);
142094
142109
  for (const w2 of waiters) w2(r);
142095
142110
  }
142111
+ if (!hadWaiters && resume && resume.kind === "command" && resume.origin) {
142112
+ void resumeChatAfterAuthorization(resume.origin, r, resume);
142113
+ }
142096
142114
  };
142097
142115
  const resolveEngine = opts.resolveEngine ?? (async () => ({ kernel: opts.kernel, oplog: opts.oplog, blobs: opts.blobs, ...opts.registry ? { registry: opts.registry } : {} }));
142098
142116
  const domainRouter = new Router();
142099
142117
  for (const register of opts.domains ?? []) register(domainRouter);
142100
142118
  const liveChat = opts.liveChat ?? new LiveChatRegistry();
142119
+ const resumeChatAfterAuthorization = async (origin, resolution, ctx) => {
142120
+ const store = opts.chatSession;
142121
+ const dispatch = opts.dispatchChat;
142122
+ if (!store || !dispatch) return;
142123
+ const session = await store.getSession(origin).catch(() => null);
142124
+ if (!session) return;
142125
+ const { randomUUID: randomUUID29 } = await import("node:crypto");
142126
+ const approved = resolution.status === "approved";
142127
+ const by = ctx.authorizedBy ?? "\u7BA1\u7406\u8005";
142128
+ const label = ctx.effectLabel || ctx.command || "";
142129
+ const statusText = approved ? `\u547D\u4EE4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C${label ? `\uFF1A${label}` : ""}\u3002` : `\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF1A${ctx.reason}` : ""}\u3002`;
142130
+ await store.appendMessage({ id: randomUUID29(), sessionId: origin, role: "system", content: statusText, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
142131
+ if (liveChat.isRunning(origin)) return;
142132
+ const prompt = approved ? `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C\uFF08\u547D\u4EE4\uFF1A${label}\uFF09\u3002\u8BF7\u7EE7\u7EED\u539F\u4EFB\u52A1\u3002` : `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF08\u7406\u7531\uFF1A${ctx.reason}\uFF09` : ""}\u3002\u522B\u91CD\u8BD5\u540C\u4E00\u6761\u2014\u2014\u8BF7\u6539\u65B9\u6848\u6216\u5148\u5411\u53D1\u8D77\u4EBA\u95EE\u6E05\u695A\u3002`;
142133
+ let dispatched;
142134
+ try {
142135
+ dispatched = await dispatch({
142136
+ actorId: session.aiActorId,
142137
+ message: prompt,
142138
+ chatSessionId: origin,
142139
+ ...session.runtimeSessionId ? { sessionId: session.runtimeSessionId } : {}
142140
+ });
142141
+ } catch {
142142
+ return;
142143
+ }
142144
+ let text2 = "";
142145
+ dispatched.onOutput((chunk) => {
142146
+ text2 += chunk;
142147
+ });
142148
+ void dispatched.done.then(async () => {
142149
+ if (text2 || dispatched.runId) {
142150
+ await store.appendMessage({
142151
+ id: randomUUID29(),
142152
+ sessionId: origin,
142153
+ role: "assistant",
142154
+ content: text2,
142155
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
142156
+ ...dispatched.runId ? { runId: dispatched.runId } : {}
142157
+ }).catch(() => void 0);
142158
+ }
142159
+ await store.updateSession(origin, { runtimeSessionId: dispatched.nativeSessionId ?? null, touchedAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
142160
+ }).catch(() => void 0);
142161
+ };
142101
142162
  const channelService = opts.channels?.enabled && opts.dispatchChat && opts.actors ? new ChannelService({
142102
142163
  store: opts.channels.store,
142103
142164
  dispatchChat: (req) => opts.dispatchChat(req),
@@ -142615,7 +142676,11 @@ async function startOasisServer(opts) {
142615
142676
  if (review.kind === "command" && review.command) {
142616
142677
  const { command, artifactId } = await engine.kernel.applyAuthorizedCommand({ draftId, actor });
142617
142678
  const receipt = authorizedCommandReceipt(command, review.command.args, actor);
142618
- notifyReviewResolved(draftId, { status: "approved", command, effectLabel: review.command.effectLabel, authorizedBy: actor, receipt });
142679
+ notifyReviewResolved(
142680
+ draftId,
142681
+ { status: "approved", command, effectLabel: review.command.effectLabel, authorizedBy: actor, receipt },
142682
+ { origin: review.origin, kind: "command", authorizedBy: actor, effectLabel: review.command.effectLabel, command }
142683
+ );
142619
142684
  res.writeHead(200, { "content-type": "application/json" }).end(
142620
142685
  JSON.stringify({ applied: 1, command, artifactId, draftId, draftedBy: review.proposedBy, authorizedBy: actor })
142621
142686
  );
@@ -142624,7 +142689,11 @@ async function startOasisServer(opts) {
142624
142689
  const plan = { ...review.plan, authorizedBy: actor, draftedBy: review.proposedBy, resolvesProposal: draftId };
142625
142690
  const fresh = await engine.kernel.previewIntervention(plan);
142626
142691
  const result = await engine.kernel.applyIntervention(plan, fresh.baseSeqs, actor);
142627
- notifyReviewResolved(draftId, { status: "approved", command: "", effectLabel: review.plan.reason, authorizedBy: actor });
142692
+ notifyReviewResolved(
142693
+ draftId,
142694
+ { status: "approved", command: "", effectLabel: review.plan.reason, authorizedBy: actor },
142695
+ { origin: review.origin, kind: review.kind ?? "graph-edit" }
142696
+ );
142628
142697
  res.writeHead(200, { "content-type": "application/json" }).end(
142629
142698
  JSON.stringify({ ...result, draftId, draftedBy: review.proposedBy, authorizedBy: actor })
142630
142699
  );
@@ -142653,7 +142722,18 @@ async function startOasisServer(opts) {
142653
142722
  }
142654
142723
  }
142655
142724
  await engine.kernel.rejectIntervention({ draftId, anchor: review.anchor, actor, ...reason !== void 0 ? { reason } : {} });
142656
- notifyReviewResolved(draftId, { status: "denied", ...reason !== void 0 ? { reason } : {} });
142725
+ notifyReviewResolved(
142726
+ draftId,
142727
+ { status: "denied", ...reason !== void 0 ? { reason } : {} },
142728
+ {
142729
+ origin: review.origin,
142730
+ kind: review.kind ?? "graph-edit",
142731
+ authorizedBy: actor,
142732
+ ...review.command?.effectLabel ? { effectLabel: review.command.effectLabel } : {},
142733
+ ...review.command?.command ? { command: review.command.command } : {},
142734
+ ...reason !== void 0 ? { reason } : {}
142735
+ }
142736
+ );
142657
142737
  res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ rejected: true, draftId, annotated: touched.length }));
142658
142738
  } catch (err) {
142659
142739
  res.writeHead(400, { "content-type": "application/json" }).end(
@@ -143140,7 +143220,7 @@ async function startOasisServer(opts) {
143140
143220
  { nodeId: currentRuntimeId, runtimeKind: currentRuntimeKind }
143141
143221
  );
143142
143222
  const persistedUserMessage = persistTarget ? stripInjectedChatContext(body.message) : body.message;
143143
- const history = runtimeChanged && chatStore && persistTarget ? (await chatStore.listMessages(persistTarget.id, 20)).filter((message) => !(message.role === "assistant" && message.status === "running")).map((message) => ({
143223
+ const history = runtimeChanged && chatStore && persistTarget ? (await chatStore.listMessages(persistTarget.id, 20)).filter((message) => message.role !== "system" && !(message.role === "assistant" && message.status === "running")).map((message) => ({
143144
143224
  role: message.role,
143145
143225
  content: message.role === "user" ? stripInjectedChatContext(message.content) : message.content
143146
143226
  })) : [];
@@ -143152,7 +143232,7 @@ async function startOasisServer(opts) {
143152
143232
  ...draftWorkspace ? { draftWorkspace } : {}
143153
143233
  });
143154
143234
  const effectiveSessionId = persistTarget ? runtimeChanged ? void 0 : persistTarget.runtimeSessionId ?? void 0 : body.sessionId || void 0;
143155
- const resumeFallbackHistory = effectiveSessionId && chatStore && persistTarget ? (await chatStore.listMessages(persistTarget.id, 20)).filter((m2) => !(m2.role === "assistant" && m2.status === "running")).map((m2) => ({ role: m2.role, content: m2.role === "user" ? stripInjectedChatContext(m2.content) : m2.content })) : [];
143235
+ const resumeFallbackHistory = effectiveSessionId && chatStore && persistTarget ? (await chatStore.listMessages(persistTarget.id, 20)).filter((m2) => m2.role !== "system" && !(m2.role === "assistant" && m2.status === "running")).map((m2) => ({ role: m2.role, content: m2.role === "user" ? stripInjectedChatContext(m2.content) : m2.content })) : [];
143156
143236
  const fallbackMessage = resumeFallbackHistory.length ? buildRuntimeChatPrompt({ userMessage: persistedUserMessage, history: resumeFallbackHistory, ...draftWorkspace ? { draftWorkspace } : {} }) : void 0;
143157
143237
  const session = await opts.dispatchChat({
143158
143238
  actorId: body.actorId,
@@ -153649,6 +153729,8 @@ var init_claude_code = __esm({
153649
153729
  let writes = 0;
153650
153730
  let results = 0;
153651
153731
  let inputClosing = false;
153732
+ let diag = () => {
153733
+ };
153652
153734
  let pendingClose = null;
153653
153735
  const cancelPendingClose = () => {
153654
153736
  if (pendingClose) {
@@ -153663,15 +153745,18 @@ var init_claude_code = __esm({
153663
153745
  );
153664
153746
  writes++;
153665
153747
  cancelPendingClose();
153748
+ diag("stdin_write", { writes, results, chars: text2.length });
153666
153749
  return true;
153667
- } catch {
153750
+ } catch (e) {
153751
+ diag("stdin_write_failed", { writes, results, err: String(e) });
153668
153752
  return false;
153669
153753
  }
153670
153754
  };
153671
- const closeInput = () => {
153755
+ const closeInput = (reason = "unspecified") => {
153672
153756
  cancelPendingClose();
153673
153757
  if (inputClosing) return;
153674
153758
  inputClosing = true;
153759
+ diag("stdin_closed", { reason, writes, results });
153675
153760
  try {
153676
153761
  child.stdin.end();
153677
153762
  } catch {
@@ -153680,13 +153765,13 @@ var init_claude_code = __esm({
153680
153765
  const maybeCloseInputOnResult = () => {
153681
153766
  if (!appendMode || inputClosing) return;
153682
153767
  if (appendGraceMs <= 0) {
153683
- closeInput();
153768
+ closeInput("result");
153684
153769
  return;
153685
153770
  }
153686
153771
  cancelPendingClose();
153687
153772
  pendingClose = setTimeout(() => {
153688
153773
  pendingClose = null;
153689
- closeInput();
153774
+ closeInput("grace-expired");
153690
153775
  }, appendGraceMs);
153691
153776
  pendingClose.unref?.();
153692
153777
  };
@@ -153705,6 +153790,13 @@ var init_claude_code = __esm({
153705
153790
  }
153706
153791
  let transcriptRef = path12.join(dir, "transcript.txt");
153707
153792
  const out = openTranscript(transcriptRef);
153793
+ diag = (event, extra) => {
153794
+ try {
153795
+ out.write(JSON.stringify({ type: "oasis_diag", at: (/* @__PURE__ */ new Date()).toISOString(), event, ...extra ?? {} }) + "\n");
153796
+ } catch {
153797
+ }
153798
+ };
153799
+ diag("session_started", { appendMode, appendGraceMs });
153708
153800
  const telemetryCbs = [];
153709
153801
  let eventSeq = 0;
153710
153802
  let lastResult;
@@ -153723,6 +153815,7 @@ var init_claude_code = __esm({
153723
153815
  if (p2["type"] === "result") {
153724
153816
  lastResult = p2;
153725
153817
  results++;
153818
+ diag("result", { writes, results, subtype: p2["subtype"], is_error: p2["is_error"] });
153726
153819
  maybeCloseInputOnResult();
153727
153820
  }
153728
153821
  accumulateClaudeUsage(usageAcc, p2);
@@ -153844,6 +153937,7 @@ var init_claude_code = __esm({
153844
153937
  return {
153845
153938
  id,
153846
153939
  async kill() {
153940
+ diag("kill", { writes, results, exited, inputClosing });
153847
153941
  cancelPendingClose();
153848
153942
  inputClosing = true;
153849
153943
  killReason ??= "cancelled";
@@ -153865,10 +153959,17 @@ var init_claude_code = __esm({
153865
153959
  return appendMode && !exited && !inputClosing;
153866
153960
  },
153867
153961
  appendInput(input) {
153868
- if (!appendMode) return Promise.resolve({ accepted: false, reason: "unsupported" });
153869
- if (exited || inputClosing) return Promise.resolve({ accepted: false, reason: "session-closing" });
153962
+ if (!appendMode) {
153963
+ diag("append_rejected", { reason: "unsupported", writes, results });
153964
+ return Promise.resolve({ accepted: false, reason: "unsupported" });
153965
+ }
153966
+ if (exited || inputClosing) {
153967
+ diag("append_rejected", { reason: "session-closing", exited, inputClosing, writes, results });
153968
+ return Promise.resolve({ accepted: false, reason: "session-closing" });
153969
+ }
153870
153970
  materializeFiles(dir, input.files);
153871
153971
  if (input.interrupt) writeInterrupt();
153972
+ diag("append_accepted", { writes, results, interrupt: !!input.interrupt, chars: input.text.length });
153872
153973
  const ok = writeUserMessage(input.text);
153873
153974
  return Promise.resolve(ok ? { accepted: true } : { accepted: false, reason: "rejected" });
153874
153975
  }
@@ -161345,9 +161446,30 @@ function changeConfirmSummary(r) {
161345
161446
  const what = r.nonMonotonicOps.map((a) => C_ACTION_LABEL[a] ?? a).join("\u3001");
161346
161447
  return `\u7BA1\u7406\u8005\u63D0\u4E86\u4E00\u4EFD\u9700\u8981\u4F60\u786E\u8BA4\u7684\u6539\u52A8\uFF08${what || "\u9500\u6BC1\u6027\u6539\u56FE"}\uFF09\uFF1A${why}`;
161347
161448
  }
161449
+ function latestOtherLetterActivity(an, me) {
161450
+ let best;
161451
+ const consider = (at, by, seq) => {
161452
+ if (!at || by === void 0 || by === me) return;
161453
+ const s2 = seq ?? -1;
161454
+ if (!best || s2 > best.seq) best = { at, by, seq: s2 };
161455
+ };
161456
+ for (const t of an.thread) consider(t.ts, t.author, t.seq);
161457
+ if (an.resolvedBy !== void 0) consider(an.resolvedAt, an.resolvedBy, an.resolvedAtSeq);
161458
+ return best;
161459
+ }
161460
+ function myLatestLetterPostSeq(an, me) {
161461
+ let s2;
161462
+ for (const t of an.thread) {
161463
+ if (t.author !== me) continue;
161464
+ const v2 = t.seq ?? -1;
161465
+ if (s2 === void 0 || v2 > s2) s2 = v2;
161466
+ }
161467
+ return s2;
161468
+ }
161348
161469
  function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso) {
161349
161470
  const out = [];
161350
161471
  const gapItems = [];
161472
+ const mentionedLettersEmittedForMe = /* @__PURE__ */ new Set();
161351
161473
  const readAt = new Map(markers.map((m2) => [m2.scope, m2]));
161352
161474
  const actorRef = (id) => {
161353
161475
  const extra = resolveActor?.(id);
@@ -161508,26 +161630,29 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
161508
161630
  ...lastPost ? { actor: actorRef(lastPost.author) } : {},
161509
161631
  ...overdueField(an.createdAt)
161510
161632
  });
161633
+ mentionedLettersEmittedForMe.add(an.id);
161511
161634
  }
161512
161635
  for (const an of anns) {
161513
- if (!an.mail && !model.convergenceUnified || an.author !== me || an.state === "open") continue;
161514
- if (an.resolvedBy === void 0 || !an.resolvedBy.startsWith("actor:agent:")) continue;
161515
- const repliedByMeAfterClose = an.thread.some((t) => an.resolvedAtSeq !== void 0 && (t.seq ?? -1) > an.resolvedAtSeq && t.author === me);
161516
- if (repliedByMeAfterClose) continue;
161517
- const answeredAt = an.resolvedAt ?? model.lastOpAt.get(a.id) ?? "";
161518
- if (!isUnread(answeredAt, readAt.get(letterScope(an.id)))) continue;
161636
+ if (!an.mail && !model.convergenceUnified || an.author !== me) continue;
161637
+ if (mentionedLettersEmittedForMe.has(an.id)) continue;
161638
+ const activity = latestOtherLetterActivity(an, me);
161639
+ if (!activity) continue;
161640
+ const myLatest = myLatestLetterPostSeq(an, me);
161641
+ if (myLatest !== void 0 && myLatest > activity.seq) continue;
161642
+ if (!isUnread(activity.at, readAt.get(letterScope(an.id)))) continue;
161519
161643
  const lastNote = an.thread.at(-1)?.body ?? "\uFF08\u65E0\u8BF4\u660E\uFF09";
161644
+ const phrase = an.state === "open" ? "\u6709\u65B0\u56DE\u590D" : an.state === "wontfix" ? "\u672A\u6539\u5185\u5BB9" : an.answeredVia ? `\u58F0\u79F0\u5DF2\u5728 ${an.answeredVia.slice(9, 17)} \u89E3\u51B3` : "\u5DF2\u5904\u7F6E";
161520
161645
  out.push({
161521
161646
  kind: "letter-answered",
161522
161647
  artifactId: a.id,
161523
161648
  workspace: ws,
161524
161649
  annotationId: an.id,
161525
- since: answeredAt,
161650
+ since: activity.at,
161526
161651
  actionRequired: false,
161527
- summary: `\u4F60\u7684\u4FE1\u5DF2\u88AB\u7B54\u590D\uFF08${an.state === "wontfix" ? "\u672A\u6539\u5185\u5BB9" : an.answeredVia ? `\u58F0\u79F0\u5DF2\u5728 ${an.answeredVia.slice(9, 17)} \u89E3\u51B3` : "\u5DF2\u5904\u7F6E"}\uFF09\u300C${nodeLabel(a)}\u300D\uFF1A${lastNote.slice(0, 100)}\u2014\u2014\u4E0D\u8BA4\u53EF\u53EF\u5728\u4FE1\u4E2D\u56DE\u5E16`,
161652
+ summary: `\u4F60\u7684\u4FE1\u6709\u65B0\u52A8\u9759\uFF08${phrase}\uFF09\u300C${nodeLabel(a)}\u300D\uFF1A${lastNote.slice(0, 100)}\u2014\u2014\u4E0D\u8BA4\u53EF\u53EF\u5728\u4FE1\u4E2D\u56DE\u5E16`,
161528
161653
  title: nodeLabel(a),
161529
- detail: `${actorName(an.resolvedBy) || "agent"} \u7B54\u590D\u4E86\u4F60\u7684\u4FE1\uFF1A${firstSentence(lastNote)}`,
161530
- actor: actorRef(an.resolvedBy)
161654
+ detail: `${actorName(activity.by) || "\u5BF9\u65B9"} \u56DE\u5E94\u4E86\u4F60\u7684\u4FE1\uFF1A${firstSentence(lastNote)}`,
161655
+ actor: actorRef(activity.by)
161531
161656
  // 通知型不判 overdue(诊断明说),不设 overdue 字段。
161532
161657
  });
161533
161658
  }
@@ -175407,6 +175532,7 @@ var init_worker = __esm({
175407
175532
 
175408
175533
  - \`oasis roles\` \u2014\u2014 **\u6709\u54EA\u4E9B\u5C97\u4F4D**\uFF1A\u6807\u8BC6 / \u663E\u793A\u540D / \u5728\u5C97\u4EBA\u6570 / \u804C\u8D23 / \u5B83\u8D1F\u8D23\xB7\u8BC4\u5BA1\u54EA\u4E9B\u4EA4\u4ED8\u7269\uFF08\u65E0\u53C2\u6570\uFF09\u3002**\u522B\u731C\u5C97\u4F4D\u540D**\u2014\u2014\u5EFA\u56FE\u586B\u4E0D\u5230\u5C97\u4F4D\u7684\u5730\u65B9\u3001\u60F3\u77E5\u9053\u67D0\u7C7B\u4EA4\u4ED8\u7269\u5F52\u8C01\u7BA1\uFF0C\u5148\u67E5\u8FD9\u4E2A\u3002\u6807"0 \u4EBA\u5728\u5C97"\u7684\u5C97\u4F4D\u6D3E\u4E0D\u51FA\u6D3B\uFF1B\u6807"\u4E0D\u53EF\u5206\u914D"\u7684\u662F\u7CFB\u7EDF\u5C97\u4F4D\uFF08\u5982 ci\uFF09\u3002
175409
175534
  - \`oasis actors [--role <\u5C97\u4F4D>] [--kind human|agent]\` \u2014\u2014 **\u6709\u8C01\u53EF\u6D3E**\uFF1Aid / \u540D\u5B57 / \u4EBA\u8FD8\u662F agent / \u5C97\u4F4D\u3002\u9ED8\u8BA4\u53EA\u5217**\u5728\u5C97**\uFF08\u79BB\u5C97\u7684\u6D3E\u4E0D\u4E86\u6D3B\uFF0C\u522B\u9009\uFF09\u3002\u8981\u7ED9\u8282\u70B9\u6307\u8D1F\u8D23\u4EBA\uFF08\`oasis assign\`\uFF09\u65F6\u7528 \`--role\` \u6309\u5C97\u4F4D\u627E\u4EBA\u3002
175535
+ - \`oasis actor <actorId>\` \u2014\u2014 **\u8FD9\u4E2A id \u5230\u5E95\u662F\u8C01**\uFF1A\u5355\u4EBA\u5B8C\u6574\u6863\u6848\uFF08\u59D3\u540D / \u5C97\u4F4D / \u56E2\u961F / \u6C47\u62A5\u5173\u7CFB / \u80FD\u529B\u4ECB\u7ECD / \u64C5\u957F / \u90AE\u7BB1 / \u72B6\u6001\uFF09\u3002\`oasis actors\` \u5217\u51FA\u5C97\u4F4D\u4E0B\u6709\u8C01\u4E4B\u540E\u3001\u8981**\u4ECE\u5C97\u4F4D\u843D\u5230\u5177\u4F53\u4EBA**\uFF08\u770B\u8FD9\u4E2A\u4EBA\u64C5\u957F\u4EC0\u4E48\u3001\u80FD\u4E0D\u80FD\u62C5\u8FD9\u6D3B\uFF09\u65F6\u7528\u5B83\u6DF1\u6316\u4E00\u5C42\u2014\u2014\u5206\u8BCA / \u6307\u6D3E / \u627E\u4EBA\u6B63\u662F\u4F60\u534F\u8C03\u8005\u6700\u9700\u8981\u7684\u90A3\u4E00\u8DF3\u3002
175410
175536
  - \`oasis assign <id> --owner <actorId>\` \u2014\u2014 \u7ED9\u8282\u70B9**\u6307\u5B9A\u8D1F\u8D23\u4EBA**\u3002\`<id>\` = \u8282\u70B9\uFF1B\`--owner\` = \u5177\u4F53\u7684\u4EBA\u6216 agent \u7684 id\uFF08\u7528\u4E0A\u9762 \`oasis actors\` \u67E5\uFF0C\u522B\u7F16\uFF09\u3002**\u6709\u7684\u4EA4\u4ED8\u7269\u7C7B\u578B\u4E0D\u7ED1\u5C97\u4F4D**\uFF08\u8C01\u90FD\u80FD\u5199\uFF09\uFF0C\u5B83\u4EEC\u5EFA\u51FA\u6765 owner \u662F\u5F85\u6D3E\u72B6\u6001\u3001\u5FC5\u987B assign \u624D\u52A8\u5F97\u4E86\u2014\u2014preview \u4F1A\u7528 \u26A0 \u63D0\u9192\u4F60\u3002**\u9500\u6BC1\u6027**\uFF08\u4F1A\u593A\u8D70\u5728\u4EA7\u65B9\u7684\u6D3B\uFF09\u2014\u2014apply \u65F6\u8F6C\u4EBA\u786E\u8BA4\u3002
175411
175537
  - \`oasis link <consumer> --to <up> [--required true]\` \u2014\u2014 \u7ED9 consumer \u52A0\u4E00\u6761\u6307\u5411\u4E0A\u6E38 up \u7684\u4F9D\u8D56\u8FB9\u3002\`<consumer>\` = \u8981\u52A0\u4F9D\u8D56\u7684\u4E0B\u6E38\u8282\u70B9\uFF08\u5F15\u7528,\u89C1\u4E0A\uFF09\uFF1B\`--to <up>\` = \u88AB\u4F9D\u8D56\u7684\u4E0A\u6E38\uFF1B\`--required true\` = \u8FD9\u6761\u662F**\u963B\u585E\u6027**\u4F9D\u8D56\uFF08up \u6CA1 conclude\uFF0Cconsumer \u5C31\u52A8\u4E0D\u4E86\uFF09\uFF0C**\u7701\u7565\u5219\u662F\u8F6F\u4F9D\u8D56**\uFF08\u53EA\u8BB0\u5173\u7CFB\u3001\u4E0D\u963B\u585E\uFF09\u3002\u53BB\u91CD\u65F6\u7528\u5B83\u628A"\u8BE5\u8FDE\u65E2\u6709"\u7684\u8FB9\u8865\u4E0A\u3002
175412
175538
  - \`oasis spawn --type <t> --title "<\u77ED\u540D>" [--brief "<\u89C4\u683C>"] [--input <ref>[,\u2026]]\` \u2014\u2014 \u65B0\u5EFA\u4E00\u4E2A\u8282\u70B9\u3002**id \u4E0D\u7528\u4F60\u7ED9,\u7CFB\u7EDF\u636E (type,title) \u81EA\u52A8\u6D3E\u751F**\u3002\`--type <t>\` = \u7C7B\u578B\u540D\uFF08**\u5FC5\u586B**\uFF0C\u5148 \`oasis artifact-types\` \u770B\u53EF\u9009\u7C7B\u578B\u4E0E\u7528\u9014\uFF09\uFF1B\`--title\` = \u77ED\u540D\uFF08**\u5FC5\u586B\u3001\u540C type \u4E0B\u552F\u4E00**,\u649E\u540D\u4F1A\u8BA9\u4F60\u6539\uFF09\uFF1B\`--brief\` = \u7ED9\u5B83\u7684\u4EA7\u51FA\u89C4\u683C\uFF08\u5199\u6E05\u8981\u505A\u6210\u4EC0\u4E48\uFF0C\u4F1A\u6210\u4E3A\u8BE5\u8282\u70B9 owner \u7684\u4EFB\u52A1\u4E66\uFF09\uFF1B\`--input\` = \u5B83\u4F9D\u8D56\u54EA\u4E9B\u4E0A\u6E38\uFF08**\u9017\u53F7\u5206\u9694**\u591A\u4E2A,\u6BCF\u4E2A\u6309\u4E0A\u9762\u5F15\u7528\u5199\u6CD5\uFF09\u3002**\u786E\u65E0\u65E2\u6709\u53EF\u8FDE\u3001\u662F\u771F\u65B0\u9700\u6C42\u624D\u7528**\u3002
@@ -186935,6 +187061,29 @@ async function buildActorContext(service, actorId) {
186935
187061
  ]);
186936
187062
  return { config: config2, connectors, installedSkills, ...record8?.roles?.length ? { roles: record8.roles } : {} };
186937
187063
  }
187064
+ async function buildChatWhoSection(service, rolesAdmin, humanActorId, selfActorId) {
187065
+ if (!humanActorId) return [];
187066
+ const [human, self2, roleDefs, teams] = await Promise.all([
187067
+ service.getActor(humanActorId).catch(() => null),
187068
+ service.getActor(selfActorId).catch(() => null),
187069
+ rolesAdmin.list().catch(() => []),
187070
+ service.listTeams().catch(() => [])
187071
+ ]);
187072
+ if (!human) return [];
187073
+ const roleLabel = new Map(roleDefs.map((r) => [r.name, r.label ?? r.name]));
187074
+ const headerParts = [`${human.name}\uFF08${human.id}\uFF09`];
187075
+ const pos = (human.roles ?? [])[0];
187076
+ if (pos) headerParts.push(roleLabel.get(pos) ?? pos);
187077
+ const teamName = human.teamId ? teams.find((t) => t.id === human.teamId)?.name : void 0;
187078
+ if (teamName) headerParts.push(teamName);
187079
+ const lines = ["## \u4F60\u5728\u8DDF\u8C01\u8BF4\u8BDD", "", headerParts.join(" \xB7 ")];
187080
+ if (human.description) lines.push(human.description);
187081
+ if (human.tags?.length) lines.push(`\u64C5\u957F\uFF1A${human.tags.join("\u3001")}`);
187082
+ if (human.email) lines.push(`\u90AE\u7BB1\uFF1A${human.email}`);
187083
+ lines.push("", `\u4F60\u662F ${self2?.name ?? selfActorId}\u3002TA \u8BF4\u300C\u6211\u300D\u65F6\u6307\u7684\u5C31\u662F\u4E0A\u9762\u8FD9\u4E2A\u4EBA\uFF1B\u63D0\u5230\u7684\u5176\u4ED6\u4EBA\u662F\u522B\u4EBA\uFF0C\u522B\u6DF7\u3002`);
187084
+ lines.push(`\u60F3\u8FDB\u4E00\u6B65\u4E86\u89E3 TA\u3001\u6216\u6838\u5B9E\u5BF9\u8BDD\u91CC\u63D0\u5230\u7684\u5176\u4ED6\u4EBA\u662F\u8C01\uFF1A\`oasis actor <actorId>\`\uFF08\u5355\u4EBA\u5B8C\u6574\u6863\u6848\uFF09\u3002`);
187085
+ return lines;
187086
+ }
186938
187087
  function traceRuntimeKind(runtimeKind) {
186939
187088
  if (runtimeKind === "claude" || runtimeKind === "claude-code") return "claude-code";
186940
187089
  if (runtimeKind === "codex") return "codex";
@@ -188018,11 +188167,13 @@ async function startServe(opts) {
188018
188167
  }
188019
188168
  }
188020
188169
  const sessionLine = chatSessionId ? `chat_session_id: ${chatSessionId}` : `runtime_session_id: ${runtimeSessionId}`;
188170
+ const whoLines = await buildChatWhoSection(actorService, rolesAdmin, priorChatSession?.humanActorId, actorId);
188021
188171
  const taskHeader = workspace ? [
188022
188172
  "# \u4E0E\u5DE5\u5355\u7BA1\u7406\u8005\u5BF9\u8BDD",
188023
188173
  "",
188024
188174
  sessionLine,
188025
- `actor_id: ${actorId}`,
188175
+ // 诊断 1be339c7:`your_actor_id` 而非 `actor_id`——这行是 **agent 自己**,改名把「这行是我还是对方」消歧到零。
188176
+ `your_actor_id: ${actorId}`,
188026
188177
  `workspace: ${workspace}`,
188027
188178
  "",
188028
188179
  CONVERSATIONAL_MANAGER_BODY
@@ -188030,7 +188181,7 @@ async function startServe(opts) {
188030
188181
  "# \u5373\u65F6\u8111\u66B4\u5BF9\u8BDD",
188031
188182
  "",
188032
188183
  sessionLine,
188033
- `actor_id: ${actorId}`,
188184
+ `your_actor_id: ${actorId}`,
188034
188185
  "",
188035
188186
  "\u8BF7\u76F4\u63A5\u56DE\u7B54\u7528\u6237\u95EE\u9898\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u5199\u5165\u7CFB\u7EDF\uFF0C\u5426\u5219\u4E0D\u8981\u521B\u5EFA\u6216\u4FEE\u6539 artifact\u3002"
188036
188187
  ];
@@ -188040,6 +188191,8 @@ async function startServe(opts) {
188040
188191
  ...taskHeader,
188041
188192
  ...attachmentPaths.length ? ["", "## \u7528\u6237\u9644\u4EF6", "", "\u7528\u6237\u968F\u6D88\u606F\u9644\u5E26\u4E86\u4EE5\u4E0B\u6587\u4EF6\uFF08\u5728\u4F60\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0B\uFF0C\u53EF\u76F4\u63A5\u8BFB\u53D6\uFF09\uFF1A", ...attachmentPaths.map((p2) => `- ${p2}`)] : [],
188042
188193
  ...projectContextLines.length ? ["", "## \u5F53\u524D\u9879\u76EE\u516C\u5F00\u8F93\u5165", "", "\u751F\u6210 Brief \u524D\u5FC5\u987B\u5148\u8BFB\u53D6 `PROJECT_CONTEXT.md` \u53CA\u5176\u4E2D\u5217\u51FA\u7684 `project/` \u6587\u4EF6\uFF1B\u4ED3\u5E93\u7B49\u5916\u90E8\u4F4D\u7F6E\u4E5F\u8BB0\u5F55\u5728\u8BE5\u6587\u4EF6\u4E2D\u3002"] : [],
188194
+ // 诊断 1be339c7:身份段紧贴在「## 用户消息」之前——让 agent 先知道「你在跟谁说话」,再读那条消息。
188195
+ ...whoLines.length ? ["", ...whoLines] : [],
188043
188196
  "",
188044
188197
  "## \u7528\u6237\u6D88\u606F",
188045
188198
  "",
@@ -188492,6 +188645,23 @@ async function startServe(opts) {
188492
188645
  const want = new Set(roles);
188493
188646
  return all.filter((r) => want.has(r.name)).map((r) => ({ name: r.name, ...r.label ? { label: r.label } : {}, ...r.description ? { description: r.description } : {} }));
188494
188647
  },
188648
+ // 诊断 1be339c7:actorId → 「姓名(岗位)」全量映射,供装配器把任务书里所有裸 id 换掉(信署名、评审票
188649
+ // 作者、集成竞争版作者、thread 每帖……)。一次性拉全员名册 ∪ 岗位目录(岗位取首个 position 的显示名);
188650
+ // 无岗位仅姓名;查不到某 id 由装配器回退裸 id。整表拉 = 一次 listActors,比逐 id 回调更省也更不会漏。
188651
+ resolveActorLabels: async () => {
188652
+ const [actorList, roleList] = await Promise.all([
188653
+ (await runActors()).service.listActors().catch(() => []),
188654
+ rolesAdmin.list().catch(() => [])
188655
+ ]);
188656
+ const roleLabel = new Map(roleList.map((r) => [r.name, r.label ?? r.name]));
188657
+ const map = /* @__PURE__ */ new Map();
188658
+ for (const a of actorList) {
188659
+ const pos = (a.roles ?? [])[0];
188660
+ const posLabel = pos ? roleLabel.get(pos) ?? pos : void 0;
188661
+ map.set(a.id, posLabel ? `${a.name}\uFF08${posLabel}\uFF09` : a.name);
188662
+ }
188663
+ return map;
188664
+ },
188495
188665
  materializeSkills: async (actorId, runtimeKind) => {
188496
188666
  if (SKILL_CACHE_RUNTIMES.has(runtimeKind)) return {};
188497
188667
  const ctx = await runActors();
@@ -190280,6 +190450,7 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
190280
190450
  freeze <artifactId> [--note "\u2026"] # \u51BB\u7ED3\u8282\u70B9\uFF1A\u4FDD\u7559\u8F93\u51FA\u3001\u505C\u6B62\u6539\u52A8
190281
190451
  accept <artifactId> [--note "\u2026"] # \u5B9A\u7A3F\uFF08\u5148 conclude \u518D accept\uFF09
190282
190452
  actors [--role <\u5C97\u4F4D>] [--kind human|agent] [--all true] # \u6709\u8C01\u53EF\u6D3E\uFF1Aid/\u540D\u5B57/\u4EBA\u8FD8\u662Fagent/\u5C97\u4F4D\u3002\u9ED8\u8BA4\u53EA\u5217\u5728\u5C97\uFF08\u79BB\u5C97\u7684\u6D3E\u4E0D\u4E86\u6D3B\uFF09\u3002assign \u524D\u7528\u5B83\u627E\u4EBA
190453
+ actor <actorId> # \u8FD9\u4E2A id \u5230\u5E95\u662F\u8C01\uFF1A\u5355\u4EBA\u5B8C\u6574\u6863\u6848\uFF08\u59D3\u540D/\u5C97\u4F4D/\u56E2\u961F/\u6C47\u62A5/\u80FD\u529B\u4ECB\u7ECD/\u64C5\u957F/\u90AE\u7BB1/\u72B6\u6001\uFF09\u3002\u4ECE\u5C97\u4F4D\u8DF3\u5230\u5177\u4F53\u4EBA\u3001\u6216\u6838\u5B9E\u7F72\u540D\u8EAB\u4EFD\u65F6\u7528
190283
190454
  roles # \u6709\u54EA\u4E9B\u5C97\u4F4D\uFF1A\u6807\u8BC6/\u663E\u793A\u540D/\u5728\u5C97\u4EBA\u6570/\u804C\u8D23/\u5B83\u8D1F\u8D23\xB7\u8BC4\u5BA1\u54EA\u4E9B\u4EA4\u4ED8\u7269\u3002\u586B --owner-role\u3001\u95F8\u7684 reviewers\u3001\u7ED9\u5458\u5DE5\u5B9A\u5C97\u524D\u7528\u5B83\u67E5\u5408\u6CD5\u5C97\u4F4D
190284
190455
  assign <artifactId> --owner <actorId>
190285
190456
  gc # \u5B64\u513F blob \u56DE\u6536\uFF08mark-and-sweep\uFF1B\u64CD\u4F5C\u8005\u547D\u4EE4\uFF0CF1\uFF09
@@ -190382,9 +190553,13 @@ var ASYNC_AUTH_MESSAGE = "\u5DF2\u63D0\u4EA4\u4EBA\u5DE5\u5BA1\u6838\uFF1B\u5148
190382
190553
  function asyncAuthorizationReturn(data) {
190383
190554
  return data !== void 0 ? { message: ASYNC_AUTH_MESSAGE, data } : { message: ASYNC_AUTH_MESSAGE };
190384
190555
  }
190556
+ var DEFAULT_AUTH_WAIT_MS = 2 * 60 * 1e3;
190557
+ function resolveAuthWaitMs() {
190558
+ return Number(process.env["OASIS_AUTH_WAIT_MS"] ?? DEFAULT_AUTH_WAIT_MS);
190559
+ }
190385
190560
  async function waitForCommandAuthorization(base, headers, draftId, fallback) {
190386
190561
  const asyncFallback = asyncAuthorizationReturn(fallback.data);
190387
- const timeoutMs = Number(process.env["OASIS_AUTH_WAIT_MS"] ?? 90 * 60 * 1e3);
190562
+ const timeoutMs = resolveAuthWaitMs();
190388
190563
  const controller = new AbortController();
190389
190564
  const timer = setTimeout(() => controller.abort(), timeoutMs);
190390
190565
  process.stderr.write(
@@ -191960,6 +192135,25 @@ ${res.warning}`);
191960
192135
  }
191961
192136
  break;
191962
192137
  }
192138
+ // 诊断 1be339c7 ③:单人详情——「这个 id 到底是谁」。协调者要从岗位跳到人时用它,chat agent 想核实
192139
+ // 发起人身份时也用它。复用现成 GET /api/actors/:id(服务端零改动);id 不存在时该路由已回 404「没有这个
192140
+ // 员工」而非 500。命令签名与 status <id> / content <id> 同形(位置参数,不用 --id);不加 --company(公司
192141
+ // 由 token 定死,加了服务端也会忽略 = 假承诺)。每字段一行、人话标签、id 完整不截断。
192142
+ case "actor": {
192143
+ const id = needPos(positional, 0, "oasis actor <actorId>");
192144
+ const a = await api.request("GET", `/api/actors/${encodeURIComponent(id)}`);
192145
+ println(`id\uFF1A${a.id}`);
192146
+ if (a.name) println(`\u59D3\u540D\uFF1A${a.name}`);
192147
+ println(`\u7C7B\u578B\uFF1A${a.kind === "human" ? "\u4EBA" : a.kind === "agent" ? "AI \u5458\u5DE5" : a.kind}`);
192148
+ println(`\u5C97\u4F4D\uFF1A${(a.positions ?? []).join("\u3001") || "(\u65E0\u5C97\u4F4D)"}`);
192149
+ if (a.teamId) println(`\u56E2\u961F\uFF1A${a.teamId}`);
192150
+ if (a.reportsTo) println(`\u6C47\u62A5\u7ED9\uFF1A${a.reportsTo}`);
192151
+ if (a.description) println(`\u80FD\u529B\u4ECB\u7ECD\uFF1A${a.description}`);
192152
+ if (a.tags?.length) println(`\u64C5\u957F\uFF1A${a.tags.join("\u3001")}`);
192153
+ if (a.email) println(`\u90AE\u7BB1\uFF1A${a.email}`);
192154
+ println(`\u72B6\u6001\uFF1A${a.status === "active" ? "\u5728\u5C97" : a.status === "disabled" ? "\u5DF2\u505C\u7528" : a.status}`);
192155
+ break;
192156
+ }
191963
192157
  case "roles": {
191964
192158
  const { items } = await api.request(
191965
192159
  "GET",
@@ -192406,7 +192600,7 @@ ${res.warning}`);
192406
192600
  init_src6();
192407
192601
 
192408
192602
  // src/index.ts
192409
- var PKG_VERSION = true ? "0.1.77" : "dev";
192603
+ var PKG_VERSION = true ? "0.1.78" : "dev";
192410
192604
  var OASIS_DIR = path28.join(os9.homedir(), ".oasis");
192411
192605
  var CONFIG_FILE = path28.join(OASIS_DIR, "node-config.json");
192412
192606
  var PID_FILE = path28.join(OASIS_DIR, "node.pid");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.77",
3
+ "version": "0.1.78",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"