odai-dsh-agent 0.2.16 → 0.2.18

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 (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +155 -155
  3. package/build/bin/odai-dsh-agent.mjs +36 -29
  4. package/build/bin/odai-dsh-agent.mjs.map +1 -1
  5. package/build/src/control-center-installer.d.mts +7 -2
  6. package/build/src/control-center-installer.d.mts.map +1 -1
  7. package/build/src/control-center-installer.mjs +251 -31
  8. package/build/src/control-center-installer.mjs.map +1 -1
  9. package/build/src/control-center-prompt.d.mts +1 -1
  10. package/build/src/control-center-prompt.d.mts.map +1 -1
  11. package/build/src/control-center-prompt.mjs +14 -2
  12. package/build/src/control-center-prompt.mjs.map +1 -1
  13. package/client/client.js +125 -32
  14. package/control-center.cordis.patch.yml +3 -3
  15. package/package.json +89 -89
  16. package/preset/odai/agent.cordis.yml +266 -266
  17. package/preset/odai/preset.yml +3 -3
  18. package/preset/odai/runtime/control-center-runtime.d.mts +2 -0
  19. package/preset/odai/runtime/control-center-runtime.d.mts.map +1 -1
  20. package/preset/odai/runtime/control-center-runtime.mjs +18 -9
  21. package/preset/odai/runtime/control-center-runtime.mjs.map +1 -1
  22. package/preset/odai/runtime/role-overlays.mjs +8 -8
  23. package/preset/odai/runtime/session-evidence.d.mts +1 -0
  24. package/preset/odai/runtime/session-evidence.d.mts.map +1 -1
  25. package/preset/odai/runtime/session-evidence.mjs +14 -0
  26. package/preset/odai/runtime/session-evidence.mjs.map +1 -1
  27. package/preset/odai/skills/odai/SKILL.md +68 -68
  28. package/preset/odai/skills/odai/agents/openai.yaml +4 -4
  29. package/preset/odai/skills/odai/assets/claude-agents/agent.md +11 -11
  30. package/preset/odai/skills/odai/assets/codex-agents/config.toml +11 -11
  31. package/preset/odai/skills/odai/assets/codex-agents/role.toml +5 -5
  32. package/preset/odai/skills/odai/assets/copilot-agents/agent.md +13 -13
  33. package/preset/odai/skills/odai/assets/hooks-policy.example.json +24 -24
  34. package/preset/odai/skills/odai/assets/routing-roles/controller.md +15 -15
  35. package/preset/odai/skills/odai/assets/routing-roles/frontend.md +7 -7
  36. package/preset/odai/skills/odai/assets/routing-roles/planner.md +28 -28
  37. package/preset/odai/skills/odai/assets/routing-roles/researcher.md +6 -6
  38. package/preset/odai/skills/odai/assets/routing-roles/reviewer.md +11 -11
  39. package/preset/odai/skills/odai/assets/task-state.md +14 -14
  40. package/preset/odai/skills/odai/manifest.json +52 -52
  41. package/preset/odai/skills/odai/references/craft.md +54 -54
  42. package/preset/odai/skills/odai/references/dao.md +31 -31
  43. package/preset/odai/skills/odai/references/leverage.md +50 -50
  44. package/preset/odai/skills/odai/references/planning.md +83 -83
  45. package/preset/odai/skills/odai/references/support.md +30 -30
  46. package/preset/odai/skills/odai/references/verification.md +24 -24
  47. package/preset/odai/skills/odai/scripts/build-hooks.mjs +273 -273
  48. package/preset/odai/skills/odai/scripts/build-routing.mjs +315 -315
  49. package/preset/odai/skills/odai/scripts/install-routing.mjs +393 -393
  50. package/preset/odai/skills/odai/scripts/odai-hook.mjs +457 -457
  51. package/preset/odai/skills/odai/scripts/run-role.mjs +285 -285
  52. package/preset/odai/skills/odai/scripts/verify-routing.mjs +103 -103
package/client/client.js CHANGED
@@ -29,6 +29,7 @@ window.__ModuleLoader__.load({
29
29
  configured: "已配置",
30
30
  evidence: "证据",
31
31
  });
32
+ const EVENT_BATCH_SIZE = 100;
32
33
  function record(value) {
33
34
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
34
35
  }
@@ -125,6 +126,21 @@ window.__ModuleLoader__.load({
125
126
  }
126
127
  return output;
127
128
  }
129
+ // Evidence logs are append-only, so boundary identity avoids an O(n) digest on every poll.
130
+ function traceFingerprint(events = []) {
131
+ const first = record(events.at(0));
132
+ const last = record(events.at(-1));
133
+ return [events.length, first?.seq ?? "", first?.type ?? "", last?.seq ?? "", last?.type ?? "", last?.time ?? ""].join(":");
134
+ }
135
+ function windowTurnItems(items, limit, selectedKey) {
136
+ const size = Math.max(1, limit);
137
+ const tailStart = Math.max(0, items.length - size);
138
+ const selectedIndex = selectedKey ? items.findIndex((item) => item.key === selectedKey) : -1;
139
+ if (selectedIndex < 0 || selectedIndex >= tailStart)
140
+ return items.slice(tailStart);
141
+ const start = Math.max(0, Math.min(selectedIndex - Math.floor(size / 2), items.length - size));
142
+ return items.slice(start, start + size);
143
+ }
128
144
  function projectTrace(events = []) {
129
145
  const items = [];
130
146
  const turns = new Map();
@@ -147,7 +163,7 @@ window.__ModuleLoader__.load({
147
163
  title: titleOf(type, data),
148
164
  detail: detailOf(data),
149
165
  route: routeOf(data),
150
- raw: compact(data),
166
+ raw: data,
151
167
  });
152
168
  items.push(item);
153
169
  const key = turn === undefined ? "session" : `turn-${turn}`;
@@ -201,13 +217,29 @@ window.__ModuleLoader__.load({
201
217
  throw new Error(response.value?.error?.message || "Routing configuration failed");
202
218
  return response.value.config;
203
219
  }
204
- async function callEvidence(connection, sessionId, signal) {
205
- const response = await connection.rpc.call("/odai-control-center", "evidence", { sessionId }, signal);
206
- if (!response?.ok)
207
- throw new Error(response?.error?.message || "Control Center evidence RPC failed");
208
- if (!response.value?.ok)
209
- throw new Error(response.value?.error?.message || "Session evidence could not be read");
210
- return Array.isArray(response.value.events) ? response.value.events : [];
220
+ async function callEvidence(connection, sessionId, revision, signal) {
221
+ const request = async (payload) => {
222
+ const response = await connection.rpc.call("/odai-control-center", "evidence", payload, signal);
223
+ if (!response?.ok)
224
+ throw new Error(response?.error?.message || "Control Center evidence RPC failed");
225
+ if (!response.value?.ok)
226
+ throw new Error(response.value?.error?.message || "Session evidence could not be read");
227
+ return response.value;
228
+ };
229
+ let value;
230
+ try {
231
+ value = await request({ sessionId, ...(revision ? { revision } : {}) });
232
+ }
233
+ catch (cause) {
234
+ if (!revision || !/requires only a non-empty sessionId/iu.test(cause instanceof Error ? cause.message : String(cause)))
235
+ throw cause;
236
+ value = await request({ sessionId });
237
+ }
238
+ return {
239
+ events: Array.isArray(value.events) ? value.events : [],
240
+ revision: text(value.revision) || undefined,
241
+ unchanged: value.unchanged === true,
242
+ };
211
243
  }
212
244
  function controlCenterError(cause) {
213
245
  const message = cause instanceof Error ? cause.message : String(cause);
@@ -247,19 +279,56 @@ window.__ModuleLoader__.load({
247
279
  }))));
248
280
  }
249
281
  function Timeline({ trace, selectedKey, onSelect }) {
250
- return h("section", { className: "odaiCC__timeline" }, h("div", { className: "odaiCC__sectionHead" }, h("h3", null, "会话时间线"), h("span", { className: "odaiCC__eventCount" }, `${trace.items.length} 个事件`)), trace.turns.length ? h("div", { className: "odaiCC__turns" }, trace.turns.map((turn) => h("details", {
251
- key: turn.key,
252
- open: turn.key === trace.currentTurn?.key,
253
- className: "odaiCC__turn",
254
- }, h("summary", null, h("strong", null, turn.title), h("span", null, `${turn.items.length} 个事件`)), h("div", { className: "odaiCC__events" }, turn.items.map((item) => h(EventRow, {
255
- key: item.key,
256
- item,
257
- selected: selectedKey === item.key,
258
- onSelect,
259
- })))))) : h("div", { className: "odaiCC__empty" }, "当前会话窗口中还没有 Odai 职责证据。"));
282
+ const [expandedKey, setExpandedKey] = useState(() => trace.currentTurn?.key);
283
+ const [visibleCount, setVisibleCount] = useState(EVENT_BATCH_SIZE);
284
+ useEffect(() => {
285
+ if (!selectedKey)
286
+ return;
287
+ const item = trace.items.find((entry) => entry.key === selectedKey);
288
+ const groupKey = item?.turn === undefined ? "session" : `turn-${item.turn}`;
289
+ if (item && groupKey !== expandedKey) {
290
+ setExpandedKey(groupKey);
291
+ setVisibleCount(EVENT_BATCH_SIZE);
292
+ }
293
+ }, [selectedKey]);
294
+ useEffect(() => {
295
+ if (expandedKey && !trace.turns.some((turn) => turn.key === expandedKey)) {
296
+ setExpandedKey(trace.currentTurn?.key);
297
+ setVisibleCount(EVENT_BATCH_SIZE);
298
+ }
299
+ }, [trace.turns, trace.currentTurn?.key, expandedKey]);
300
+ return h("section", { className: "odaiCC__timeline" }, h("div", { className: "odaiCC__sectionHead" }, h("h3", null, "会话时间线"), h("span", { className: "odaiCC__eventCount" }, `${trace.items.length} 个事件`)), trace.turns.length ? h("div", { className: "odaiCC__turns" }, trace.turns.map((turn) => {
301
+ const expanded = turn.key === expandedKey;
302
+ const visibleItems = expanded ? windowTurnItems(turn.items, visibleCount, selectedKey) : [];
303
+ const hiddenCount = Math.max(0, turn.items.length - visibleItems.length);
304
+ return h("details", {
305
+ key: turn.key,
306
+ open: expanded,
307
+ className: "odaiCC__turn",
308
+ onToggle: (event) => {
309
+ if (event.currentTarget.open) {
310
+ setExpandedKey(turn.key);
311
+ setVisibleCount(EVENT_BATCH_SIZE);
312
+ }
313
+ else {
314
+ setExpandedKey((value) => value === turn.key ? undefined : value);
315
+ }
316
+ },
317
+ }, h("summary", null, h("strong", null, turn.title), h("span", null, `${turn.items.length} 个事件`)), expanded ? h("div", { className: "odaiCC__events" }, hiddenCount ? h("button", {
318
+ type: "button",
319
+ className: "odaiCC__loadEarlier",
320
+ onClick: () => setVisibleCount((count) => count + EVENT_BATCH_SIZE),
321
+ }, `加载更早的 ${Math.min(EVENT_BATCH_SIZE, hiddenCount)} 条`) : null, visibleItems.map((item) => h(EventRow, {
322
+ key: item.key,
323
+ item,
324
+ selected: selectedKey === item.key,
325
+ onSelect,
326
+ }))) : null);
327
+ })) : h("div", { className: "odaiCC__empty" }, "当前会话窗口中还没有 Odai 职责证据。"));
260
328
  }
261
329
  function Inspector({ item }) {
262
- return h("aside", { className: "odaiCC__inspector" }, h("div", { className: "odaiCC__sectionHead" }, h("h3", null, "事件检查器"), item ? h("code", null, `#${item.seq}`) : null), item ? h(React.Fragment, null, h("dl", { className: "odaiCC__facts" }, h("div", null, h("dt", null, "类型"), h("dd", null, h("code", null, item.type))), h("div", null, h("dt", null, "状态"), h("dd", null, h(StateBadge, { state: item.state }))), h("div", null, h("dt", null, "责任方"), h("dd", null, h(RoleBadge, { role: item.role }))), h("div", null, h("dt", null, "模型路由"), h("dd", null, formatRoute(item.route)))), h("pre", { className: "odaiCC__raw" }, JSON.stringify(item.raw, null, 2))) : h("div", { className: "odaiCC__empty" }, "选择一条事件查看结构化证据。"));
330
+ const raw = useMemo(() => item ? JSON.stringify(compact(item.raw), null, 2) : "", [item]);
331
+ return h("aside", { className: "odaiCC__inspector" }, h("div", { className: "odaiCC__sectionHead" }, h("h3", null, "事件检查器"), item ? h("code", null, `#${item.seq}`) : null), item ? h(React.Fragment, null, h("dl", { className: "odaiCC__facts" }, h("div", null, h("dt", null, "类型"), h("dd", null, h("code", null, item.type))), h("div", null, h("dt", null, "状态"), h("dd", null, h(StateBadge, { state: item.state }))), h("div", null, h("dt", null, "责任方"), h("dd", null, h(RoleBadge, { role: item.role }))), h("div", null, h("dt", null, "模型路由"), h("dd", null, formatRoute(item.route)))), h("pre", { className: "odaiCC__raw" }, raw)) : h("div", { className: "odaiCC__empty" }, "选择一条事件查看结构化证据。"));
263
332
  }
264
333
  function LiveView({ trace, evidenceError }) {
265
334
  const [selectedKey, setSelectedKey] = useState(() => trace.items.at(-1)?.key);
@@ -356,6 +425,8 @@ window.__ModuleLoader__.load({
356
425
  const [routingAttempted, setRoutingAttempted] = useState(false);
357
426
  const [error, setError] = useState("");
358
427
  const closeRef = useRef(null);
428
+ const evidenceFingerprintRef = useRef(traceFingerprint(traceEvents));
429
+ const evidenceRevisionRef = useRef(undefined);
359
430
  const reload = async () => {
360
431
  setRoutingAttempted(true);
361
432
  setLoading(true);
@@ -379,16 +450,32 @@ window.__ModuleLoader__.load({
379
450
  closeRef.current?.focus();
380
451
  return () => document.removeEventListener("keydown", onKey);
381
452
  }, [onClose]);
453
+ useEffect(() => {
454
+ setStoredEvidence([]);
455
+ evidenceFingerprintRef.current = traceFingerprint(traceView.events ?? []);
456
+ evidenceRevisionRef.current = undefined;
457
+ }, [sessionId]);
382
458
  useEffect(() => {
383
459
  if (!sessionId || tab !== "live")
384
460
  return undefined;
385
461
  const controller = new AbortController();
386
462
  let active = true;
463
+ let refreshing = false;
387
464
  const refreshEvidence = async () => {
465
+ if (refreshing || document.hidden)
466
+ return;
467
+ refreshing = true;
388
468
  try {
389
- const events = await callEvidence(connection, sessionId, controller.signal);
469
+ const snapshot = await callEvidence(connection, sessionId, evidenceRevisionRef.current, controller.signal);
390
470
  if (active) {
391
- setStoredEvidence(events);
471
+ evidenceRevisionRef.current = snapshot.revision;
472
+ if (!snapshot.unchanged) {
473
+ const fingerprint = traceFingerprint(snapshot.events);
474
+ if (fingerprint !== evidenceFingerprintRef.current) {
475
+ evidenceFingerprintRef.current = fingerprint;
476
+ setStoredEvidence(snapshot.events);
477
+ }
478
+ }
392
479
  setEvidenceError("");
393
480
  }
394
481
  }
@@ -396,12 +483,16 @@ window.__ModuleLoader__.load({
396
483
  if (active && !controller.signal.aborted)
397
484
  setEvidenceError(controlCenterError(cause));
398
485
  }
486
+ finally {
487
+ refreshing = false;
488
+ }
399
489
  };
400
- void refreshEvidence();
490
+ const initialTimer = window.setTimeout(refreshEvidence, 0);
401
491
  const timer = window.setInterval(refreshEvidence, 1_500);
402
492
  return () => {
403
493
  active = false;
404
494
  controller.abort();
495
+ window.clearTimeout(initialTimer);
405
496
  window.clearInterval(timer);
406
497
  };
407
498
  }, [connection, sessionId, tab]);
@@ -431,15 +522,17 @@ window.__ModuleLoader__.load({
431
522
  const tag = document.createElement("style");
432
523
  tag.dataset.plugin = PACKAGE_ID;
433
524
  tag.dataset.pluginCss = styleId;
434
- tag.textContent = `
435
- .odaiCC__launcher,.odaiCC{--odai-cc-bg:#f5f7fa;--odai-cc-panel:#fff;--odai-cc-surface:#f8fafc;--odai-cc-surface-2:#edf1f5;--odai-cc-text:#151922;--odai-cc-text-2:#4c5665;--odai-cc-text-3:#778190;--odai-cc-border:#d8dee7;--odai-cc-border-strong:#bdc6d2;--odai-cc-hover:#edf3ff;--odai-cc-accent:#2f6feb}
436
- .odaiCC__launcher{box-sizing:border-box;height:28px;border:1px solid var(--odai-cc-border);border-radius:6px;background:transparent;color:var(--odai-cc-text-2);display:inline-flex;align-items:center;gap:6px;padding:0 8px;cursor:pointer;font:600 11px/1 inherit;letter-spacing:0}.odaiCC__launcher:hover{background:var(--odai-cc-hover);color:var(--odai-cc-text)}
437
- .odaiCC__graphIcon{position:relative;width:17px;height:15px;display:inline-block;flex:none}.odaiCC__graphNode{position:absolute;width:5px;height:5px;border:1.5px solid currentColor;border-radius:50%;box-sizing:border-box}.odaiCC__graphNode--a{left:0;top:5px}.odaiCC__graphNode--b{right:0;top:0}.odaiCC__graphNode--c{right:0;bottom:0}.odaiCC__graphLine{position:absolute;left:5px;top:7px;width:7px;height:1px;background:currentColor}.odaiCC__graphLine:before,.odaiCC__graphLine:after{content:"";position:absolute;right:0;width:5px;height:1px;background:currentColor;transform-origin:right center}.odaiCC__graphLine:before{transform:rotate(-38deg)}.odaiCC__graphLine:after{transform:rotate(38deg)}
438
- .odaiCC{position:fixed;inset:0;z-index:120;color:var(--odai-cc-text);font-family:inherit;letter-spacing:0}.odaiCC *{box-sizing:border-box}.odaiCC__backdrop{position:absolute;inset:0;border:0;background:rgba(0,0,0,.28)}.odaiCC__drawer{position:absolute;inset:14px;max-width:1180px;margin-left:auto;border:1px solid var(--odai-cc-border-strong);border-radius:8px;background:var(--odai-cc-panel);box-shadow:0 24px 80px rgba(0,0,0,.42);display:flex;flex-direction:column;overflow:hidden}.odaiCC__header{min-height:62px;border-bottom:1px solid var(--odai-cc-border);display:grid;grid-template-columns:minmax(230px,1fr) auto minmax(44px,1fr);align-items:center;gap:16px;padding:10px 14px}.odaiCC__brand{display:flex;align-items:center;gap:10px;min-width:0}.odaiCC__brand>.odaiCC__graphIcon{width:22px;height:19px;color:var(--odai-cc-accent)}.odaiCC__brand h2{font-size:15px;line-height:20px;margin:0}.odaiCC__brand span{display:block;color:var(--odai-cc-text-3);font-size:10px;line-height:15px}.odaiCC__tabs{display:flex;border:1px solid var(--odai-cc-border);border-radius:6px;padding:2px;background:var(--odai-cc-surface)}.odaiCC__tabs button{height:28px;min-width:72px;border:0;border-radius:4px;background:transparent;color:var(--odai-cc-text-3);cursor:pointer;font:600 11px/1 inherit}.odaiCC__tabs button.is-active{background:var(--odai-cc-panel);color:var(--odai-cc-text);box-shadow:0 1px 4px rgba(0,0,0,.2)}.odaiCC__close{justify-self:end;width:32px;height:32px;border:0;border-radius:6px;background:transparent;color:var(--odai-cc-text-2);font-size:22px;line-height:1;cursor:pointer}.odaiCC__close:hover{background:var(--odai-cc-hover)}.odaiCC__body{min-height:0;flex:1;overflow:auto}.odaiCC__live{padding:14px}.odaiCC__kicker{display:block;color:var(--odai-cc-text-3);font:700 9px/14px inherit;letter-spacing:.08em}.odaiCC__sectionHead{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:10px}.odaiCC__sectionHead h3{font-size:12px;line-height:18px;margin:0}.odaiCC__eventCount{color:var(--odai-cc-text-3);font-size:10px}.odaiCC__flow{border:1px solid var(--odai-cc-border);border-radius:8px;background:var(--odai-cc-surface);padding:12px}.odaiCC__flowGrid{display:grid;grid-template-columns:minmax(160px,220px) minmax(360px,1fr);gap:22px;align-items:center;min-height:265px}.odaiCC__controllerNode{border:1px solid rgba(119,167,255,.45);border-radius:8px;background:rgba(119,167,255,.08);padding:18px}.odaiCC__controllerNode strong,.odaiCC__roleNode strong{display:block;font-size:12px;line-height:18px}.odaiCC__controllerNode small,.odaiCC__roleNode small{display:block;color:var(--odai-cc-text-3);font-size:10px;line-height:15px;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.odaiCC__nodeEyebrow{color:#2f6feb;font-size:9px;font-weight:700}.odaiCC__roleStack{display:flex;flex-direction:column;gap:8px}.odaiCC__flowRole{display:grid;grid-template-columns:92px minmax(0,1fr);align-items:center;border:0;background:transparent;color:inherit;padding:0;text-align:left}.odaiCC__flowRole:not(:disabled){cursor:pointer}.odaiCC__flowRole:disabled{opacity:1}.odaiCC__edge{position:relative;height:1px;background:var(--odai-cc-border-strong);margin-right:12px}.odaiCC__edge i{position:absolute;right:-1px;top:-3px;width:7px;height:7px;border-top:1px solid currentColor;border-right:1px solid currentColor;transform:rotate(45deg)}.odaiCC__edge em{position:absolute;left:5px;top:-17px;color:var(--odai-cc-text-3);font:500 9px/12px inherit;font-style:normal}.odaiCC__edge[data-state=proposal],.odaiCC__edge[data-state=decision]{background:repeating-linear-gradient(90deg,#65c6b8 0 5px,transparent 5px 9px);color:#65c6b8}.odaiCC__edge[data-state=same-turn]{background:#b99cff;color:#b99cff}.odaiCC__edge[data-state=child]{background:var(--odai-cc-accent);color:var(--odai-cc-accent)}.odaiCC__edge[data-state=handback]{background:#f1bb61;color:#f1bb61}.odaiCC__edge[data-state=blocked],.odaiCC__edge[data-state=interrupted]{background:#ef7e78;color:#ef7e78}.odaiCC__roleNode{border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-panel);padding:8px 10px;min-width:0}.odaiCC__flowRole:not(:disabled):hover .odaiCC__roleNode{border-color:var(--odai-cc-accent)}.odaiCC__role{display:inline-flex;align-items:center;gap:5px;color:var(--odai-cc-text-2);font-size:9px;line-height:14px}.odaiCC__role i{width:6px;height:6px;border-radius:50%;background:#8f969e}.odaiCC__role--controller i{background:var(--odai-cc-accent)}.odaiCC__role--researcher i{background:#65c6b8}.odaiCC__role--planner i{background:#b99cff}.odaiCC__role--reviewer i{background:#f1bb61}.odaiCC__role--frontend i{background:#ef8fbd}.odaiCC__evidenceGrid{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(300px,.8fr);gap:12px;margin-top:12px}.odaiCC__timeline,.odaiCC__inspector{min-width:0;border:1px solid var(--odai-cc-border);border-radius:8px;background:var(--odai-cc-surface);padding:10px}.odaiCC__turn{border-top:1px solid var(--odai-cc-border);padding:8px 0}.odaiCC__turn:first-child{border-top:0;padding-top:0}.odaiCC__turn summary{display:flex;justify-content:space-between;gap:10px;cursor:pointer;list-style:none;font-size:10px}.odaiCC__turn summary::-webkit-details-marker{display:none}.odaiCC__turn summary span{color:var(--odai-cc-text-3)}.odaiCC__events{display:flex;flex-direction:column;gap:6px;margin-top:8px}.odaiCC__event{width:100%;border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-panel);color:inherit;padding:8px;text-align:left;cursor:pointer}.odaiCC__event:hover,.odaiCC__event.is-selected{border-color:var(--odai-cc-accent);background:var(--odai-cc-hover)}.odaiCC__eventTop{display:flex;align-items:center;gap:6px;color:var(--odai-cc-text-3);font-size:9px}.odaiCC__eventTop time{margin-left:auto}.odaiCC__eventTop code{font-size:9px}.odaiCC__event>strong{display:block;margin-top:5px;font-size:11px;line-height:16px}.odaiCC__eventDetail{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:var(--odai-cc-text-2);font-size:10px;line-height:15px;margin-top:2px}.odaiCC__eventBottom{display:flex;gap:8px;align-items:center;color:var(--odai-cc-text-3);font-size:9px;margin-top:6px}.odaiCC__state{display:inline-flex;border-radius:999px;background:var(--odai-cc-surface-2);color:var(--odai-cc-text-2);padding:1px 6px;font-size:9px;line-height:13px}.odaiCC__state--proposal{background:rgba(101,198,184,.15);color:#18756b}.odaiCC__state--same-turn{background:rgba(185,156,255,.15);color:#6f42c1}.odaiCC__state--child{background:rgba(119,167,255,.15);color:#245ec7}.odaiCC__state--handback{background:rgba(241,187,97,.15);color:#946000}.odaiCC__state--blocked,.odaiCC__state--interrupted{background:rgba(239,126,120,.15);color:#b42318}.odaiCC__facts{margin:0;display:flex;flex-direction:column;gap:7px}.odaiCC__facts>div{display:grid;grid-template-columns:56px minmax(0,1fr);gap:8px;font-size:10px}.odaiCC__facts dt{color:var(--odai-cc-text-3)}.odaiCC__facts dd{margin:0;overflow-wrap:anywhere}.odaiCC__facts code{font-size:9px}.odaiCC__raw{max-height:360px;overflow:auto;border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-panel);color:var(--odai-cc-text-2);font:9px/14px ui-monospace,SFMono-Regular,Menlo,monospace;padding:8px;margin:10px 0 0}.odaiCC__empty{border:1px dashed var(--odai-cc-border-strong);border-radius:7px;color:var(--odai-cc-text-3);font-size:10px;line-height:16px;padding:18px;text-align:center}
439
- .odaiCC__routing{max-width:920px;margin:0 auto;padding:18px}.odaiCC__routingHead{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.odaiCC__routingHead h3{font-size:14px;margin:0}.odaiCC__quietButton,.odaiCC__primaryButton,.odaiCC__dangerButton{height:28px;border-radius:6px;padding:0 10px;font:600 10px/1 inherit;cursor:pointer}.odaiCC__quietButton{border:1px solid var(--odai-cc-border);background:transparent;color:var(--odai-cc-text-2)}.odaiCC__primaryButton{border:1px solid var(--odai-cc-accent);background:var(--odai-cc-accent);color:#fff}.odaiCC__dangerButton{border:1px solid rgba(239,126,120,.45);background:transparent;color:#b42318}.odaiCC button:disabled:not(.odaiCC__flowRole){opacity:.45;cursor:default}.odaiCC__flowRole:disabled{opacity:1;cursor:default}.odaiCC__alert{border:1px solid var(--odai-cc-border);border-radius:7px;padding:8px 10px;font-size:10px;line-height:15px;margin-bottom:10px}.odaiCC__alert.is-error{border-color:rgba(239,126,120,.4);background:rgba(239,126,120,.08);color:#b42318}.odaiCC__alert.is-success{border-color:rgba(101,198,184,.4);background:rgba(101,198,184,.08);color:#18756b}.odaiCC__controllerLock,.odaiCC__routeRow{border-top:1px solid var(--odai-cc-border);padding:12px 0}.odaiCC__controllerLock{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:12px;align-items:center}.odaiCC__controllerLock strong{display:block;font-size:11px}.odaiCC__controllerLock span:not(.odaiCC__role):not(.odaiCC__lock){display:block;color:var(--odai-cc-text-3);font-size:10px}.odaiCC__lock{border:1px solid var(--odai-cc-border);border-radius:999px;color:var(--odai-cc-text-3);font-size:9px;padding:3px 7px}.odaiCC__routeSummary{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:12px;align-items:center}.odaiCC__routeValue strong{display:block;font-size:11px;overflow-wrap:anywhere}.odaiCC__routeValue span{display:block;color:var(--odai-cc-text-3);font-size:9px;margin-top:2px}.odaiCC__dispatch{display:grid;grid-template-columns:120px auto 1fr;gap:12px;align-items:center;margin-top:9px}.odaiCC__dispatch>span{color:var(--odai-cc-text-3);font-size:9px}.odaiCC__dispatch small{color:var(--odai-cc-text-3);font-size:9px}.odaiCC__segments{display:flex;border:1px solid var(--odai-cc-border);border-radius:6px;overflow:hidden}.odaiCC__segments button{height:25px;border:0;border-right:1px solid var(--odai-cc-border);background:transparent;color:var(--odai-cc-text-3);padding:0 9px;font:500 9px/1 inherit;cursor:pointer}.odaiCC__segments button:last-child{border-right:0}.odaiCC__segments button.is-active{background:var(--odai-cc-hover);color:var(--odai-cc-text)}.odaiCC__routeForm{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:10px 0 0 132px;padding:10px;border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-surface)}.odaiCC__routeForm label span{display:block;color:var(--odai-cc-text-3);font-size:9px;margin-bottom:4px}.odaiCC__routeForm input{width:100%;height:30px;border:1px solid var(--odai-cc-border);border-radius:5px;background:var(--odai-cc-panel);color:var(--odai-cc-text);padding:0 7px;font:10px/1 inherit;outline:none}.odaiCC__routeForm input:focus{border-color:var(--odai-cc-accent)}.odaiCC__formActions{grid-column:1/-1;display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
440
- @media(max-width:760px){.odaiCC__launcher span:last-child{display:none}.odaiCC__drawer{inset:6px}.odaiCC__header{grid-template-columns:minmax(0,1fr) auto auto;gap:7px;padding:8px}.odaiCC__brand span{display:none}.odaiCC__tabs button{min-width:56px}.odaiCC__live{padding:8px}.odaiCC__flowGrid{grid-template-columns:1fr;gap:10px;min-height:0}.odaiCC__controllerNode{padding:10px}.odaiCC__flowRole{grid-template-columns:65px minmax(0,1fr)}.odaiCC__evidenceGrid{grid-template-columns:1fr}.odaiCC__inspector{max-height:none}.odaiCC__routing{padding:10px}.odaiCC__controllerLock,.odaiCC__routeSummary{grid-template-columns:92px minmax(0,1fr) auto}.odaiCC__dispatch{grid-template-columns:92px 1fr}.odaiCC__dispatch small{grid-column:2}.odaiCC__routeForm{grid-template-columns:1fr 1fr;margin-left:0}.odaiCC__raw{max-height:240px}}
441
- @media(prefers-color-scheme:dark){.odaiCC__launcher,.odaiCC{--odai-cc-bg:#14171b;--odai-cc-panel:#191d22;--odai-cc-surface:#1f242a;--odai-cc-surface-2:#282e35;--odai-cc-text:#f2f4f7;--odai-cc-text-2:#c5cbd3;--odai-cc-text-3:#929ba7;--odai-cc-border:#333a43;--odai-cc-border-strong:#46505c;--odai-cc-hover:#26354b;--odai-cc-accent:#77a7ff}.odaiCC__nodeEyebrow{color:#91b7ff}.odaiCC__state--proposal,.odaiCC__alert.is-success{color:#90d9cf}.odaiCC__state--same-turn{color:#cbb8ff}.odaiCC__state--child{color:#a6c3ff}.odaiCC__state--handback{color:#f4ca84}.odaiCC__state--blocked,.odaiCC__state--interrupted,.odaiCC__dangerButton,.odaiCC__alert.is-error{color:#f3a39e}}
442
- @media(prefers-reduced-motion:no-preference){.odaiCC__drawer{animation:odaiCCIn .15s ease-out}}@keyframes odaiCCIn{from{opacity:.72;transform:translateX(8px)}to{opacity:1;transform:none}}
525
+ tag.textContent = `
526
+ .odaiCC__launcher,.odaiCC{--odai-cc-bg:#f5f7fa;--odai-cc-panel:#fff;--odai-cc-surface:#f8fafc;--odai-cc-surface-2:#edf1f5;--odai-cc-text:#151922;--odai-cc-text-2:#4c5665;--odai-cc-text-3:#778190;--odai-cc-border:#d8dee7;--odai-cc-border-strong:#bdc6d2;--odai-cc-hover:#edf3ff;--odai-cc-accent:#2f6feb}
527
+ .odaiCC__launcher{box-sizing:border-box;height:28px;border:1px solid var(--odai-cc-border);border-radius:6px;background:transparent;color:var(--odai-cc-text-2);display:inline-flex;align-items:center;gap:6px;padding:0 8px;cursor:pointer;font:600 11px/1 inherit;letter-spacing:0}.odaiCC__launcher:hover{background:var(--odai-cc-hover);color:var(--odai-cc-text)}
528
+ .odaiCC__graphIcon{position:relative;width:17px;height:15px;display:inline-block;flex:none}.odaiCC__graphNode{position:absolute;width:5px;height:5px;border:1.5px solid currentColor;border-radius:50%;box-sizing:border-box}.odaiCC__graphNode--a{left:0;top:5px}.odaiCC__graphNode--b{right:0;top:0}.odaiCC__graphNode--c{right:0;bottom:0}.odaiCC__graphLine{position:absolute;left:5px;top:7px;width:7px;height:1px;background:currentColor}.odaiCC__graphLine:before,.odaiCC__graphLine:after{content:"";position:absolute;right:0;width:5px;height:1px;background:currentColor;transform-origin:right center}.odaiCC__graphLine:before{transform:rotate(-38deg)}.odaiCC__graphLine:after{transform:rotate(38deg)}
529
+ .odaiCC{position:fixed;inset:0;z-index:120;color:var(--odai-cc-text);font-family:inherit;letter-spacing:0}.odaiCC *{box-sizing:border-box}.odaiCC__backdrop{position:absolute;inset:0;border:0;background:rgba(0,0,0,.28)}.odaiCC__drawer{position:absolute;inset:14px;max-width:1180px;margin-left:auto;border:1px solid var(--odai-cc-border-strong);border-radius:8px;background:var(--odai-cc-panel);box-shadow:0 24px 80px rgba(0,0,0,.42);display:flex;flex-direction:column;overflow:hidden}.odaiCC__header{min-height:62px;border-bottom:1px solid var(--odai-cc-border);display:grid;grid-template-columns:minmax(230px,1fr) auto minmax(44px,1fr);align-items:center;gap:16px;padding:10px 14px}.odaiCC__brand{display:flex;align-items:center;gap:10px;min-width:0}.odaiCC__brand>.odaiCC__graphIcon{width:22px;height:19px;color:var(--odai-cc-accent)}.odaiCC__brand h2{font-size:15px;line-height:20px;margin:0}.odaiCC__brand span{display:block;color:var(--odai-cc-text-3);font-size:10px;line-height:15px}.odaiCC__tabs{display:flex;border:1px solid var(--odai-cc-border);border-radius:6px;padding:2px;background:var(--odai-cc-surface)}.odaiCC__tabs button{height:28px;min-width:72px;border:0;border-radius:4px;background:transparent;color:var(--odai-cc-text-3);cursor:pointer;font:600 11px/1 inherit}.odaiCC__tabs button.is-active{background:var(--odai-cc-panel);color:var(--odai-cc-text);box-shadow:0 1px 4px rgba(0,0,0,.2)}.odaiCC__close{justify-self:end;width:32px;height:32px;border:0;border-radius:6px;background:transparent;color:var(--odai-cc-text-2);font-size:22px;line-height:1;cursor:pointer}.odaiCC__close:hover{background:var(--odai-cc-hover)}.odaiCC__body{min-height:0;flex:1;overflow:auto}.odaiCC__live{padding:14px}.odaiCC__kicker{display:block;color:var(--odai-cc-text-3);font:700 9px/14px inherit;letter-spacing:.08em}.odaiCC__sectionHead{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:10px}.odaiCC__sectionHead h3{font-size:12px;line-height:18px;margin:0}.odaiCC__eventCount{color:var(--odai-cc-text-3);font-size:10px}.odaiCC__flow{border:1px solid var(--odai-cc-border);border-radius:8px;background:var(--odai-cc-surface);padding:12px}.odaiCC__flowGrid{display:grid;grid-template-columns:minmax(160px,220px) minmax(360px,1fr);gap:22px;align-items:center;min-height:265px}.odaiCC__controllerNode{border:1px solid rgba(119,167,255,.45);border-radius:8px;background:rgba(119,167,255,.08);padding:18px}.odaiCC__controllerNode strong,.odaiCC__roleNode strong{display:block;font-size:12px;line-height:18px}.odaiCC__controllerNode small,.odaiCC__roleNode small{display:block;color:var(--odai-cc-text-3);font-size:10px;line-height:15px;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.odaiCC__nodeEyebrow{color:#2f6feb;font-size:9px;font-weight:700}.odaiCC__roleStack{display:flex;flex-direction:column;gap:8px}.odaiCC__flowRole{display:grid;grid-template-columns:92px minmax(0,1fr);align-items:center;border:0;background:transparent;color:inherit;padding:0;text-align:left}.odaiCC__flowRole:not(:disabled){cursor:pointer}.odaiCC__flowRole:disabled{opacity:1}.odaiCC__edge{position:relative;height:1px;background:var(--odai-cc-border-strong);margin-right:12px}.odaiCC__edge i{position:absolute;right:-1px;top:-3px;width:7px;height:7px;border-top:1px solid currentColor;border-right:1px solid currentColor;transform:rotate(45deg)}.odaiCC__edge em{position:absolute;left:5px;top:-17px;color:var(--odai-cc-text-3);font:500 9px/12px inherit;font-style:normal}.odaiCC__edge[data-state=proposal],.odaiCC__edge[data-state=decision]{background:repeating-linear-gradient(90deg,#65c6b8 0 5px,transparent 5px 9px);color:#65c6b8}.odaiCC__edge[data-state=same-turn]{background:#b99cff;color:#b99cff}.odaiCC__edge[data-state=child]{background:var(--odai-cc-accent);color:var(--odai-cc-accent)}.odaiCC__edge[data-state=handback]{background:#f1bb61;color:#f1bb61}.odaiCC__edge[data-state=blocked],.odaiCC__edge[data-state=interrupted]{background:#ef7e78;color:#ef7e78}.odaiCC__roleNode{border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-panel);padding:8px 10px;min-width:0}.odaiCC__flowRole:not(:disabled):hover .odaiCC__roleNode{border-color:var(--odai-cc-accent)}.odaiCC__role{display:inline-flex;align-items:center;gap:5px;color:var(--odai-cc-text-2);font-size:9px;line-height:14px}.odaiCC__role i{width:6px;height:6px;border-radius:50%;background:#8f969e}.odaiCC__role--controller i{background:var(--odai-cc-accent)}.odaiCC__role--researcher i{background:#65c6b8}.odaiCC__role--planner i{background:#b99cff}.odaiCC__role--reviewer i{background:#f1bb61}.odaiCC__role--frontend i{background:#ef8fbd}.odaiCC__evidenceGrid{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(300px,.8fr);gap:12px;margin-top:12px}.odaiCC__timeline,.odaiCC__inspector{min-width:0;border:1px solid var(--odai-cc-border);border-radius:8px;background:var(--odai-cc-surface);padding:10px}.odaiCC__turn{border-top:1px solid var(--odai-cc-border);padding:8px 0}.odaiCC__turn:first-child{border-top:0;padding-top:0}.odaiCC__turn summary{display:flex;justify-content:space-between;gap:10px;cursor:pointer;list-style:none;font-size:10px}.odaiCC__turn summary::-webkit-details-marker{display:none}.odaiCC__turn summary span{color:var(--odai-cc-text-3)}.odaiCC__events{display:flex;flex-direction:column;gap:6px;margin-top:8px}.odaiCC__event{width:100%;border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-panel);color:inherit;padding:8px;text-align:left;cursor:pointer}.odaiCC__event:hover,.odaiCC__event.is-selected{border-color:var(--odai-cc-accent);background:var(--odai-cc-hover)}.odaiCC__eventTop{display:flex;align-items:center;gap:6px;color:var(--odai-cc-text-3);font-size:9px}.odaiCC__eventTop time{margin-left:auto}.odaiCC__eventTop code{font-size:9px}.odaiCC__event>strong{display:block;margin-top:5px;font-size:11px;line-height:16px}.odaiCC__eventDetail{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:var(--odai-cc-text-2);font-size:10px;line-height:15px;margin-top:2px}.odaiCC__eventBottom{display:flex;gap:8px;align-items:center;color:var(--odai-cc-text-3);font-size:9px;margin-top:6px}.odaiCC__state{display:inline-flex;border-radius:999px;background:var(--odai-cc-surface-2);color:var(--odai-cc-text-2);padding:1px 6px;font-size:9px;line-height:13px}.odaiCC__state--proposal{background:rgba(101,198,184,.15);color:#18756b}.odaiCC__state--same-turn{background:rgba(185,156,255,.15);color:#6f42c1}.odaiCC__state--child{background:rgba(119,167,255,.15);color:#245ec7}.odaiCC__state--handback{background:rgba(241,187,97,.15);color:#946000}.odaiCC__state--blocked,.odaiCC__state--interrupted{background:rgba(239,126,120,.15);color:#b42318}.odaiCC__facts{margin:0;display:flex;flex-direction:column;gap:7px}.odaiCC__facts>div{display:grid;grid-template-columns:56px minmax(0,1fr);gap:8px;font-size:10px}.odaiCC__facts dt{color:var(--odai-cc-text-3)}.odaiCC__facts dd{margin:0;overflow-wrap:anywhere}.odaiCC__facts code{font-size:9px}.odaiCC__raw{max-height:360px;overflow:auto;border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-panel);color:var(--odai-cc-text-2);font:9px/14px ui-monospace,SFMono-Regular,Menlo,monospace;padding:8px;margin:10px 0 0}.odaiCC__empty{border:1px dashed var(--odai-cc-border-strong);border-radius:7px;color:var(--odai-cc-text-3);font-size:10px;line-height:16px;padding:18px;text-align:center}
530
+ .odaiCC__routing{max-width:920px;margin:0 auto;padding:18px}.odaiCC__routingHead{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.odaiCC__routingHead h3{font-size:14px;margin:0}.odaiCC__quietButton,.odaiCC__primaryButton,.odaiCC__dangerButton{height:28px;border-radius:6px;padding:0 10px;font:600 10px/1 inherit;cursor:pointer}.odaiCC__quietButton{border:1px solid var(--odai-cc-border);background:transparent;color:var(--odai-cc-text-2)}.odaiCC__primaryButton{border:1px solid var(--odai-cc-accent);background:var(--odai-cc-accent);color:#fff}.odaiCC__dangerButton{border:1px solid rgba(239,126,120,.45);background:transparent;color:#b42318}.odaiCC button:disabled:not(.odaiCC__flowRole){opacity:.45;cursor:default}.odaiCC__flowRole:disabled{opacity:1;cursor:default}.odaiCC__alert{border:1px solid var(--odai-cc-border);border-radius:7px;padding:8px 10px;font-size:10px;line-height:15px;margin-bottom:10px}.odaiCC__alert.is-error{border-color:rgba(239,126,120,.4);background:rgba(239,126,120,.08);color:#b42318}.odaiCC__alert.is-success{border-color:rgba(101,198,184,.4);background:rgba(101,198,184,.08);color:#18756b}.odaiCC__controllerLock,.odaiCC__routeRow{border-top:1px solid var(--odai-cc-border);padding:12px 0}.odaiCC__controllerLock{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:12px;align-items:center}.odaiCC__controllerLock strong{display:block;font-size:11px}.odaiCC__controllerLock span:not(.odaiCC__role):not(.odaiCC__lock){display:block;color:var(--odai-cc-text-3);font-size:10px}.odaiCC__lock{border:1px solid var(--odai-cc-border);border-radius:999px;color:var(--odai-cc-text-3);font-size:9px;padding:3px 7px}.odaiCC__routeSummary{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:12px;align-items:center}.odaiCC__routeValue strong{display:block;font-size:11px;overflow-wrap:anywhere}.odaiCC__routeValue span{display:block;color:var(--odai-cc-text-3);font-size:9px;margin-top:2px}.odaiCC__dispatch{display:grid;grid-template-columns:120px auto 1fr;gap:12px;align-items:center;margin-top:9px}.odaiCC__dispatch>span{color:var(--odai-cc-text-3);font-size:9px}.odaiCC__dispatch small{color:var(--odai-cc-text-3);font-size:9px}.odaiCC__segments{display:flex;border:1px solid var(--odai-cc-border);border-radius:6px;overflow:hidden}.odaiCC__segments button{height:25px;border:0;border-right:1px solid var(--odai-cc-border);background:transparent;color:var(--odai-cc-text-3);padding:0 9px;font:500 9px/1 inherit;cursor:pointer}.odaiCC__segments button:last-child{border-right:0}.odaiCC__segments button.is-active{background:var(--odai-cc-hover);color:var(--odai-cc-text)}.odaiCC__routeForm{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:10px 0 0 132px;padding:10px;border:1px solid var(--odai-cc-border);border-radius:7px;background:var(--odai-cc-surface)}.odaiCC__routeForm label span{display:block;color:var(--odai-cc-text-3);font-size:9px;margin-bottom:4px}.odaiCC__routeForm input{width:100%;height:30px;border:1px solid var(--odai-cc-border);border-radius:5px;background:var(--odai-cc-panel);color:var(--odai-cc-text);padding:0 7px;font:10px/1 inherit;outline:none}.odaiCC__routeForm input:focus{border-color:var(--odai-cc-accent)}.odaiCC__formActions{grid-column:1/-1;display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
531
+ .odaiCC__body{overflow:hidden}.odaiCC__live{height:100%;min-height:0;display:flex;flex-direction:column;gap:14px;overflow:hidden;padding:14px}.odaiCC__live>.odaiCC__alert{flex:none;margin-bottom:0}.odaiCC__flow{flex:none;max-height:38vh;overflow:auto;scrollbar-gutter:stable}.odaiCC__evidenceGrid{flex:1;min-height:0;overflow:hidden;margin-top:0}.odaiCC__timeline{display:flex;flex-direction:column;min-height:0;overflow:hidden}.odaiCC__timeline>.odaiCC__sectionHead{flex:none}.odaiCC__turns{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}.odaiCC__inspector{min-height:0;max-height:none;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}.odaiCC__inspector>.odaiCC__sectionHead{position:sticky;top:0;z-index:1;background:var(--odai-cc-panel);padding-bottom:8px}.odaiCC__sectionHead h3{font-size:13px;line-height:20px}.odaiCC__kicker{font:700 11px/16px inherit;letter-spacing:0}.odaiCC__role,.odaiCC__state,.odaiCC__nodeEyebrow{font-size:10px}.odaiCC__controllerNode strong,.odaiCC__roleNode strong{font-size:13px;line-height:18px}.odaiCC__controllerNode small,.odaiCC__roleNode small,.odaiCC__edge em{font-size:11px;line-height:16px}.odaiCC__eventCount{font-size:11px;line-height:16px}.odaiCC__turn summary{font-size:12px;line-height:18px}.odaiCC__eventTop code,.odaiCC__eventTop time{font-size:11px;line-height:16px}.odaiCC__event>strong{font-size:13px;line-height:18px}.odaiCC__eventDetail,.odaiCC__eventBottom{font-size:11px;line-height:16px}.odaiCC__eventTop .odaiCC__state,.odaiCC__eventBottom .odaiCC__role,.odaiCC__facts .odaiCC__state,.odaiCC__facts .odaiCC__role{font-size:10px}.odaiCC__facts dt{font-size:11px;line-height:18px}.odaiCC__facts dd{font-size:12px;line-height:18px}.odaiCC__facts code{font-size:11px;line-height:18px}.odaiCC__raw{font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace}.odaiCC__loadEarlier{width:100%;height:30px;border:0;border-bottom:1px solid var(--odai-cc-border);background:var(--odai-cc-surface);color:var(--odai-cc-text-2);font:600 10px/1 inherit;cursor:pointer}.odaiCC__loadEarlier:hover{background:var(--odai-cc-hover);color:var(--odai-cc-text)}.odaiCC__routing{height:100%;overflow-y:auto}
532
+ @media(max-width:760px){.odaiCC__launcher span:last-child{display:none}.odaiCC__drawer{inset:6px}.odaiCC__header{grid-template-columns:minmax(0,1fr) auto auto;gap:7px;padding:8px}.odaiCC__brand span{display:none}.odaiCC__tabs button{min-width:56px}.odaiCC__live{padding:8px}.odaiCC__flowGrid{grid-template-columns:1fr;gap:10px;min-height:0}.odaiCC__controllerNode{padding:10px}.odaiCC__flowRole{grid-template-columns:65px minmax(0,1fr)}.odaiCC__evidenceGrid{grid-template-columns:1fr}.odaiCC__inspector{max-height:none}.odaiCC__routing{padding:10px}.odaiCC__controllerLock,.odaiCC__routeSummary{grid-template-columns:92px minmax(0,1fr) auto}.odaiCC__dispatch{grid-template-columns:92px 1fr}.odaiCC__dispatch small{grid-column:2}.odaiCC__routeForm{grid-template-columns:1fr 1fr;margin-left:0}.odaiCC__raw{max-height:240px}}
533
+ @media(max-width:760px){.odaiCC__body{overflow:hidden}.odaiCC__live{gap:8px}.odaiCC__flow{max-height:30vh}.odaiCC__evidenceGrid{grid-template-rows:minmax(180px,1fr) minmax(120px,35vh);overflow:hidden}.odaiCC__timeline,.odaiCC__inspector{min-height:0;max-height:none}}
534
+ @media(prefers-color-scheme:dark){.odaiCC__launcher,.odaiCC{--odai-cc-bg:#14171b;--odai-cc-panel:#191d22;--odai-cc-surface:#1f242a;--odai-cc-surface-2:#282e35;--odai-cc-text:#f2f4f7;--odai-cc-text-2:#c5cbd3;--odai-cc-text-3:#929ba7;--odai-cc-border:#333a43;--odai-cc-border-strong:#46505c;--odai-cc-hover:#26354b;--odai-cc-accent:#77a7ff}.odaiCC__nodeEyebrow{color:#91b7ff}.odaiCC__state--proposal,.odaiCC__alert.is-success{color:#90d9cf}.odaiCC__state--same-turn{color:#cbb8ff}.odaiCC__state--child{color:#a6c3ff}.odaiCC__state--handback{color:#f4ca84}.odaiCC__state--blocked,.odaiCC__state--interrupted,.odaiCC__dangerButton,.odaiCC__alert.is-error{color:#f3a39e}}
535
+ @media(prefers-reduced-motion:no-preference){.odaiCC__drawer{animation:odaiCCIn .15s ease-out}}@keyframes odaiCCIn{from{opacity:.72;transform:translateX(8px)}to{opacity:1;transform:none}}
443
536
  `;
444
537
  document.head.appendChild(tag);
445
538
  }
@@ -511,7 +604,7 @@ window.__ModuleLoader__.load({
511
604
  }
512
605
  exports.apply = apply;
513
606
  exports.inject = ["slots", "sessions", "conversationEvents", "conversationViews", "connection"];
514
- exports.__testing = { projectTrace, stateOf, roleOf, shouldOwnSurface };
607
+ exports.__testing = { projectTrace, stateOf, roleOf, shouldOwnSurface, traceFingerprint, windowTurnItems };
515
608
  return module.exports;
516
609
  },
517
610
  });
@@ -1,3 +1,3 @@
1
- - insert:
2
- - id: odai-control-center
3
- name: odai-dsh-agent
1
+ - insert:
2
+ - id: odai-control-center
3
+ name: odai-dsh-agent
package/package.json CHANGED
@@ -1,89 +1,89 @@
1
- {
2
- "name": "odai-dsh-agent",
3
- "version": "0.2.16",
4
- "description": "完整继承 DSH 标准模式 全部能力的 Odai Agent preset。主要用于治理、规划、测试、验证 等,可当成默认总控使用。",
5
- "license": "MIT",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/orziz/odai.git",
9
- "directory": "dsh/agent"
10
- },
11
- "homepage": "https://github.com/orziz/odai#readme",
12
- "bugs": {
13
- "url": "https://github.com/orziz/odai/issues"
14
- },
15
- "type": "module",
16
- "main": "./build/src/installer.mjs",
17
- "exports": {
18
- ".": "./build/src/installer.mjs",
19
- "./control-center": "./build/src/control-center-installer.mjs",
20
- "./control-center-host": "./preset/odai/runtime/control-center-host.mjs",
21
- "./client": "./client/client.js",
22
- "./package.json": "./package.json"
23
- },
24
- "bin": {
25
- "odai-dsh-agent": "./build/bin/odai-dsh-agent.mjs"
26
- },
27
- "publishConfig": {
28
- "registry": "https://registry.npmjs.org/",
29
- "access": "public"
30
- },
31
- "files": [
32
- "build/bin",
33
- "build/src",
34
- "client",
35
- "preset",
36
- "control-center.cordis.patch.yml",
37
- "README.md",
38
- "LICENSE"
39
- ],
40
- "dsh": {
41
- "bundle": {
42
- "patch": "./control-center.cordis.patch.yml"
43
- },
44
- "client": {
45
- "inject": [
46
- "@deepseek-ai/dsh-client-runtime",
47
- "@deepseek-ai/dsh-client-connection",
48
- "@deepseek-ai/dsh-client-ui-layout",
49
- "@deepseek-ai/dsh-client-ui-conversation"
50
- ],
51
- "platform": "web"
52
- }
53
- },
54
- "scripts": {
55
- "build:dsh": "npm --prefix ../.. run build:dsh",
56
- "typecheck:dsh": "npm --prefix ../.. run typecheck:dsh",
57
- "check": "npm run typecheck:dsh && npm run build:dsh && find ../runtime/build build/bin build/src -name '*.mjs' -print0 | xargs -0 -n1 node --check",
58
- "prepare:artifact": "npm run build:dsh && node ../../scripts/package-odai-artifact.mjs prepare --skill-root preset/odai/skills --runtime-root preset/odai/runtime --client-root client --client-package odai-dsh-agent",
59
- "clean:artifact": "node ../../scripts/package-odai-artifact.mjs clean --skill-root preset/odai/skills --runtime-root preset/odai/runtime --client-root client --client-package odai-dsh-agent",
60
- "prepare": "npm run prepare:artifact",
61
- "verify:version": "node ../../scripts/verify-dsh-package-versions.mjs",
62
- "prepack": "npm run verify:version && node ../../scripts/validate-odai-skill.mjs",
63
- "postpack": "npm run clean:artifact",
64
- "pack:dry-run": "node ../../scripts/run-package-pack.mjs --clean preset/odai/runtime --clean preset/odai/skills --clean client -- --dry-run",
65
- "test": "npm run verify:version && npm run build:dsh && npm --prefix ../.. exec -- tsx --test ./tests/*.test.mts",
66
- "verify:dsh": "npm run build:dsh && npm --prefix ../.. exec -- tsx ./tests/verify-agent-load.mts"
67
- },
68
- "dependencies": {
69
- "yaml": "^2.8.1"
70
- },
71
- "peerDependencies": {
72
- "@deepseek-ai/dsh": "0.1.1-rc.2 || 0.1.2-alpha.2"
73
- },
74
- "peerDependenciesMeta": {
75
- "@deepseek-ai/dsh": {
76
- "optional": true
77
- }
78
- },
79
- "engines": {
80
- "node": ">=22.15.0"
81
- },
82
- "keywords": [
83
- "agent",
84
- "deepseek-harness",
85
- "dsh",
86
- "odai",
87
- "preset"
88
- ]
89
- }
1
+ {
2
+ "name": "odai-dsh-agent",
3
+ "version": "0.2.18",
4
+ "description": "完整继承 DSH 标准模式 全部能力的 Odai Agent preset。主要用于治理、规划、测试、验证 等,可当成默认总控使用。",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/orziz/odai.git",
9
+ "directory": "dsh/agent"
10
+ },
11
+ "homepage": "https://github.com/orziz/odai#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/orziz/odai/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./build/src/installer.mjs",
17
+ "exports": {
18
+ ".": "./build/src/installer.mjs",
19
+ "./control-center": "./build/src/control-center-installer.mjs",
20
+ "./control-center-host": "./preset/odai/runtime/control-center-host.mjs",
21
+ "./client": "./client/client.js",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "bin": {
25
+ "odai-dsh-agent": "./build/bin/odai-dsh-agent.mjs"
26
+ },
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org/",
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "build/bin",
33
+ "build/src",
34
+ "client",
35
+ "preset",
36
+ "control-center.cordis.patch.yml",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "dsh": {
41
+ "bundle": {
42
+ "patch": "./control-center.cordis.patch.yml"
43
+ },
44
+ "client": {
45
+ "inject": [
46
+ "@deepseek-ai/dsh-client-runtime",
47
+ "@deepseek-ai/dsh-client-connection",
48
+ "@deepseek-ai/dsh-client-ui-layout",
49
+ "@deepseek-ai/dsh-client-ui-conversation"
50
+ ],
51
+ "platform": "web"
52
+ }
53
+ },
54
+ "scripts": {
55
+ "build:dsh": "npm --prefix ../.. run build:dsh",
56
+ "typecheck:dsh": "npm --prefix ../.. run typecheck:dsh",
57
+ "check": "npm run typecheck:dsh && npm run build:dsh && find ../runtime/build build/bin build/src -name '*.mjs' -print0 | xargs -0 -n1 node --check",
58
+ "prepare:artifact": "npm run build:dsh && node ../../scripts/package-odai-artifact.mjs prepare --skill-root preset/odai/skills --runtime-root preset/odai/runtime --client-root client --client-package odai-dsh-agent",
59
+ "clean:artifact": "node ../../scripts/package-odai-artifact.mjs clean --skill-root preset/odai/skills --runtime-root preset/odai/runtime --client-root client --client-package odai-dsh-agent",
60
+ "prepare": "npm run prepare:artifact",
61
+ "verify:version": "node ../../scripts/verify-dsh-package-versions.mjs",
62
+ "prepack": "npm run verify:version && node ../../scripts/validate-odai-skill.mjs",
63
+ "postpack": "npm run clean:artifact",
64
+ "pack:dry-run": "node ../../scripts/run-package-pack.mjs --clean preset/odai/runtime --clean preset/odai/skills --clean client -- --dry-run",
65
+ "test": "npm run verify:version && npm run build:dsh && npm --prefix ../.. exec -- tsx --test ./tests/*.test.mts",
66
+ "verify:dsh": "npm run build:dsh && npm --prefix ../.. exec -- tsx ./tests/verify-agent-load.mts"
67
+ },
68
+ "dependencies": {
69
+ "yaml": "^2.8.1"
70
+ },
71
+ "peerDependencies": {
72
+ "@deepseek-ai/dsh": "0.1.1-rc.2 || 0.1.2-alpha.2"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "@deepseek-ai/dsh": {
76
+ "optional": true
77
+ }
78
+ },
79
+ "engines": {
80
+ "node": ">=22.15.0"
81
+ },
82
+ "keywords": [
83
+ "agent",
84
+ "deepseek-harness",
85
+ "dsh",
86
+ "odai",
87
+ "preset"
88
+ ]
89
+ }