odai-dsh-agent 0.2.51 → 0.2.52

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.
package/README.md CHANGED
@@ -15,7 +15,7 @@ odai-dsh-agent/
15
15
 
16
16
  The preset id stays `odai`, so sessions saved with it keep resolving after an upgrade. In DSH's Plugins page the whole bundle and its Control Center row can be switched on and off; the preset declaration and the rows inside the preset are read-only there, because DSH does not let its plugin manager edit a preset's composition.
17
17
 
18
- Odai owns its composition and capability set, with a scoped runtime in default `auto` mode. The `0.2.51` candidate admits DSH `>=0.1.7-rc.1`, including later prereleases; its npm peer is `*` to avoid a package-manager prerelease allow-list. The release matrix covers `0.1.7-rc.1` and `0.2.0-rc.1`; the latter requires the goal/todo adaptation added in `0.2.50`. Published `0.2.38` has the same range, but DSH `0.1.7` rejects its Odai notices, memory packets and compaction instructions and fails the turn; use `0.2.39`. A newer version alone is not a refusal, but the host still must provide the bundle registry, workflow engine and runtime services. It follows three Standard changes in that release: the workflow engine is `@deepseek-ai/dsh-workflow-ptc` (the worker-thread engine was removed), `ralph` is disabled by default, and the plugin-manager tool row is present but disabled. Standard is an upstream reference, not a required composition: release checks load Odai against the real host and verify scoped tool/prompt behavior rather than requiring text equality with Standard.
18
+ Odai owns its composition and capability set, with a scoped runtime in default `auto` mode. The `0.2.52` candidate admits DSH `>=0.1.7-rc.1`, including later prereleases; its npm peer is `*` to avoid a package-manager prerelease allow-list. The release matrix covers `0.1.7-rc.1` and `0.2.0-rc.1`; the latter requires the goal/todo adaptation added in `0.2.50`. Published `0.2.38` has the same range, but DSH `0.1.7` rejects its Odai notices, memory packets and compaction instructions and fails the turn; use `0.2.39`. A newer version alone is not a refusal, but the host still must provide the bundle registry, workflow engine and runtime services. It follows three Standard changes in that release: the workflow engine is `@deepseek-ai/dsh-workflow-ptc` (the worker-thread engine was removed), `ralph` is disabled by default, and the plugin-manager tool row is present but disabled. Standard is an upstream reference, not a required composition: release checks load Odai against the real host and verify scoped tool/prompt behavior rather than requiring text equality with Standard.
19
19
 
20
20
  Host-owned persistence, sandbox, approval, registries, and base controller selection remain in the selected DSH profile. Ordinary requests stay on that controller. Responsibility words are optional signals rather than commands: evidence-grounded task-state gaps route at any step, the gap tool records rather than claims a route start, terminal decisions consume the proposal, an incomplete reviewer proposal waits for changed native evidence, and an identical planner/controller model remains inline without another model call. After planner handback, the controller resumes implementation only when the current user task authorizes it; plan-only, new-task, expanded-scope, and unknown authorization remain non-implementing. Reviewer children require a current hash-addressed schema 3 evidence packet whose diff is newer than the last write and whose latest successful test or read-only check follows the last write; viewing a diff does not itself invalidate an earlier successful check. The packet binds to the authenticated direct-user task when available, excludes all prior-task session events, records its boundary in route evidence, and fails closed if an explicit task binding cannot be resolved uniquely. An incomplete packet keeps the current controller route, reports why native evidence was excluded, suppresses unchanged repeat notices, and reassesses the pending proposal after decisive evidence changes without claiming independent acceptance or terminating the authorized task. Every API route is resolved before provider I/O; deterministic invalid persisted mappings are backed up and exact-match removed, while recoverable provider failures preserve them. Frontend route failure becomes an explicit local controller fallback without a routed receipt. `execute` remains an explicit comparison mode and `observe` changes no model or child while retaining fail-closed high-impact protection. Configured compaction streams are buffered so partial failed output cannot contaminate the inherited-route retry or replace original history.
21
21
 
@@ -37,7 +37,7 @@ With DSH `0.1.7-rc.1` installed, run:
37
37
  npx odai-dsh-agent install [--profile web] [--dsh-home /path/to/dsh-home]
38
38
  ```
39
39
 
40
- The installer checks `dsh -V` (the `0.2.51` candidate accepts `>=0.1.7-rc.1`, including later prereleases, without an upper version cap; published `0.2.37` targets `0.1.5-rc.2` and keeps its copied-preset installer), then runs `dsh plugin --profile <profile> add odai-dsh-agent@<version> --save-exact`. DSH's plugin manager checks the package's DSH peer before downloading anything. The package already contains the canonical skills and runtime; it does not require the Plugin. Restart the DSH Web process after a profile change, open a new session, and select `odai 治理模式` in the preset picker. Existing sessions keep the composition they started with.
40
+ The installer checks `dsh -V` (the `0.2.52` candidate accepts `>=0.1.7-rc.1`, including later prereleases, without an upper version cap; published `0.2.37` targets `0.1.5-rc.2` and keeps its copied-preset installer), then runs `dsh plugin --profile <profile> add odai-dsh-agent@<version> --save-exact`. DSH's plugin manager checks the package's DSH peer before downloading anything. The package already contains the canonical skills and runtime; it does not require the Plugin. Restart the DSH Web process after a profile change, open a new session, and select `odai 治理模式` in the preset picker. Existing sessions keep the composition they started with.
41
41
 
42
42
  DSH `0.1.7` does not carry the earlier `agent-presets.default` setting forward. To make odai the default preset again, choose it as the default in DSH; the choice is saved in the profile's own `cordis.patch.yml`.
43
43
 
@@ -108,11 +108,11 @@ The Agent keeps the bundle's complete skill copy as its `bundled` default, so ex
108
108
 
109
109
  An independent install must be a complete directory bundle containing `SKILL.md`, `manifest.json`, and every manifest-declared file. The runtime checks SemVer 2.0.0 `skillVersion`, an exact supported `runtimeContract`, complete-file SHA-256 integrity, and same-version content conflicts. Prompt governance and routing role contracts are selected atomically for one agent turn; project sources are scoped by that session's cwd, and changes are reconsidered on the next user turn. Explicit deployment `skillPath` or `ODAI_SKILL_PATH` remains highest priority and requires a DSH restart.
110
110
 
111
- The `0.2.51` source candidate bundles governance `0.7.1` (schema `5`, runtime contract `9`) and `odai-orchestration` `0.2.1` (schema `1`). Published `0.2.38` bundles orchestration `0.2.0`. Published `0.2.37` bundles governance `0.7.0` with the same schemas and runtime contract, and orchestration `0.2.0`. Governance has no role or orchestration dependency. The bundle carries both skills and its own trusted compiler, combining separate source digests into one immutable turn snapshot; it never executes external scripts or discovers neighboring orchestration. Incompatible older sources fall back visibly without rewriting their files; an incompatible explicit `skillPath` fails fast.
111
+ The `0.2.52` source candidate bundles governance `0.7.1` (schema `5`, runtime contract `9`) and `odai-orchestration` `0.2.1` (schema `1`). Published `0.2.38` bundles orchestration `0.2.0`. Published `0.2.37` bundles governance `0.7.0` with the same schemas and runtime contract, and orchestration `0.2.0`. Governance has no role or orchestration dependency. The bundle carries both skills and its own trusted compiler, combining separate source digests into one immutable turn snapshot; it never executes external scripts or discovers neighboring orchestration. Incompatible older sources fall back visibly without rewriting their files; an incompatible explicit `skillPath` fails fast.
112
112
 
113
113
  ## Retired skill evolution
114
114
 
115
- Releases before `0.2.37` could refine both governance and orchestration Markdown in `$DSH_HOME/odai/skill-evolution`. Published `0.2.37` retired that overlay together with `odai_skill_evolution`, `ODAI_DISABLE_EVOLUTION`, and `governance.evolutionRoot`; later releases, including the `0.2.51` candidate, preserve that retirement. Previously active refinements stop taking effect after upgrading and restarting DSH. The runtime no longer reads the store, no package install, update, repair, or removal deletes it, and a leftover `evolutionRoot` is ignored.
115
+ Releases before `0.2.37` could refine both governance and orchestration Markdown in `$DSH_HOME/odai/skill-evolution`. Published `0.2.37` retired that overlay together with `odai_skill_evolution`, `ODAI_DISABLE_EVOLUTION`, and `governance.evolutionRoot`; later releases, including the `0.2.52` candidate, preserve that retirement. Previously active refinements stop taking effect after upgrading and restarting DSH. The runtime no longer reads the store, no package install, update, repair, or removal deletes it, and a leftover `evolutionRoot` is ignored.
116
116
 
117
117
  To retain governance customizations, start with a complete schema `5` / contract `9` user-level bundle, review and apply the desired rules, assign a distinct valid SemVer `skillVersion`, then ask Odai to set the source to `user`. Modified content retaining this candidate's bundled version `0.7.1` falls back with `same-version-content-conflict`; changing only build metadata is insufficient. On the next turn verify the actual canonical source, version and governance digest, not just the saved setting. Explicit deployment paths take precedence.
118
118
 
package/client/client.js CHANGED
@@ -46,6 +46,44 @@ window.__ModuleLoader__.load({
46
46
  const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
47
47
  return typeof parsed === "number" && Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
48
48
  }
49
+ const LOCAL_CLI_OPTIONS = Object.freeze([
50
+ { id: "claude", label: "Claude Code", efforts: "low / medium / high / xhigh / max" },
51
+ { id: "codex", label: "Codex", efforts: "由 Codex 判定,如 low / medium / high" },
52
+ { id: "antigravity", label: "Antigravity(agy)", efforts: "low / medium / high" },
53
+ { id: "grok", label: "Grok(按文档实现,未实测)", efforts: "none / minimal / low / medium / high / xhigh / max" },
54
+ ]);
55
+ // Researcher and reviewer depend on DSH evidence tools, so only these responsibilities accept a local CLI.
56
+ function localCliAllowed(role) {
57
+ return role === "planner" || role === "frontend" || role === "creative";
58
+ }
59
+ // Returns the set payload, or undefined while the form cannot be saved.
60
+ function routeEditorPayload(role, form) {
61
+ const model = form.model.trim();
62
+ const effort = form.effort.trim();
63
+ if (!model)
64
+ return undefined;
65
+ if (form.backend === "local-cli") {
66
+ if (!localCliAllowed(role) || !LOCAL_CLI_OPTIONS.some((option) => option.id === form.cli))
67
+ return undefined;
68
+ const timeout = form.timeoutSeconds.trim();
69
+ if (timeout && (!positiveInteger(timeout) || Number(timeout) > 7200))
70
+ return undefined;
71
+ return {
72
+ action: "set", responsibility: role, backend: "local-cli", cli: form.cli, model,
73
+ ...(effort ? { reasoningEffort: effort } : {}),
74
+ ...(timeout ? { timeoutSeconds: Number(timeout) } : {}),
75
+ };
76
+ }
77
+ const provider = form.provider.trim();
78
+ const maxTokens = form.maxTokens.trim();
79
+ if (!provider || (maxTokens && !positiveInteger(maxTokens)))
80
+ return undefined;
81
+ return {
82
+ action: "set", responsibility: role, provider, model,
83
+ ...(effort ? { reasoningEffort: effort } : {}),
84
+ ...(maxTokens ? { maxTokens: Number(maxTokens) } : {}),
85
+ };
86
+ }
49
87
  function roleOf(data) {
50
88
  const value = data?.responsibility ?? data?.targetRole ?? data?.role ?? data?.from;
51
89
  return typeof value === "string" && [...ROLES, "controller"].includes(value) ? value : "controller";
@@ -393,25 +431,24 @@ window.__ModuleLoader__.load({
393
431
  const [effort, setEffort] = useState(route?.reasoningEffort ?? "");
394
432
  const [maxTokens, setMaxTokens] = useState(route?.maxTokens ? String(route.maxTokens) : "");
395
433
  const [timeoutSeconds, setTimeoutSeconds] = useState(route?.timeoutSeconds ? String(route.timeoutSeconds) : "");
434
+ const cliAllowed = localCliAllowed(role);
435
+ const [backend, setBackend] = useState(localCli ? "local-cli" : "provider");
436
+ const [cli, setCli] = useState(route?.cli ?? "claude");
396
437
  useEffect(() => {
397
438
  if (editing)
398
439
  return;
440
+ setBackend(route?.backend === "local-cli" ? "local-cli" : "provider");
441
+ setCli(route?.cli ?? "claude");
399
442
  setProvider(route?.provider ?? "");
400
443
  setModel(route?.model ?? "");
401
444
  setEffort(route?.reasoningEffort ?? "");
402
445
  setMaxTokens(route?.maxTokens ? String(route.maxTokens) : "");
403
446
  setTimeoutSeconds(route?.timeoutSeconds ? String(route.timeoutSeconds) : "");
404
447
  }, [route, editing]);
405
- const save = () => onApply({
406
- action: "set",
407
- responsibility: role,
408
- ...(localCli ? { backend: "local-cli", cli: route?.cli } : { provider }),
409
- model,
410
- ...(effort.trim() ? { reasoningEffort: effort.trim() } : {}),
411
- ...(localCli
412
- ? timeoutSeconds.trim() ? { timeoutSeconds: Number(timeoutSeconds) } : {}
413
- : maxTokens.trim() ? { maxTokens: Number(maxTokens) } : {}),
414
- }).then(() => setEditing(false));
448
+ const formCli = backend === "local-cli";
449
+ const efforts = LOCAL_CLI_OPTIONS.find((option) => option.id === cli)?.efforts;
450
+ const payload = routeEditorPayload(role, { backend, cli, provider, model, effort, maxTokens, timeoutSeconds });
451
+ const save = () => payload ? onApply(payload).then(() => setEditing(false)) : undefined;
415
452
  const remove = () => {
416
453
  if (!window.confirm(`确认移除“${ROLE_LABELS[role]}”的本地模型映射?`))
417
454
  return;
@@ -429,11 +466,17 @@ window.__ModuleLoader__.load({
429
466
  className: (dispatch ?? "default") === value ? "is-active" : "",
430
467
  onClick: () => setDispatch(value),
431
468
  disabled: busy || (childOnly && value === "same-turn"),
432
- }, dispatchLabel(value)))), h("small", null, sourceLabel(dispatchSource, childOnly ? "默认子代理" : "兼容默认"))), editing ? h("div", { className: "odaiCC__routeForm" }, localCli
433
- ? h("label", null, h("span", null, "本机 CLI"), h("input", { value: route?.cli, disabled: true }))
434
- : h("label", null, h("span", null, "Provider"), h("input", { value: provider, onChange: (event) => setProvider(event.target.value), placeholder: "Provider ID", disabled: busy })), h("label", null, h("span", null, "模型"), h("input", { value: model, onChange: (event) => setModel(event.target.value), placeholder: "模型 ID", disabled: busy })), h("label", null, h("span", null, "推理档位"), h("input", { value: effort, onChange: (event) => setEffort(event.target.value), placeholder: "可选", disabled: busy })), localCli
435
- ? h("label", null, h("span", null, "超时(秒)"), h("input", { value: timeoutSeconds, onChange: (event) => setTimeoutSeconds(event.target.value), inputMode: "numeric", placeholder: "1200", disabled: busy }))
436
- : h("label", null, h("span", null, "最大 tokens"), h("input", { value: maxTokens, onChange: (event) => setMaxTokens(event.target.value), inputMode: "numeric", placeholder: "可选", disabled: busy })), h("div", { className: "odaiCC__formActions" }, route ? h("button", { type: "button", className: "odaiCC__dangerButton", onClick: remove, disabled: busy }, "移除映射") : null, h("button", { type: "button", className: "odaiCC__primaryButton", onClick: save, disabled: busy || (!localCli && !provider.trim()) || !model.trim() || (localCli ? timeoutSeconds.trim() && (!positiveInteger(timeoutSeconds) || Number(timeoutSeconds) > 7200) : maxTokens.trim() && !positiveInteger(maxTokens)) }, busy ? "正在验证…" : "验证并保存"))) : null);
469
+ }, dispatchLabel(value)))), h("small", null, sourceLabel(dispatchSource, childOnly ? "默认子代理" : "兼容默认"))), editing ? h("div", { className: "odaiCC__routeForm" }, cliAllowed ? h("div", { className: "odaiCC__routeBackend" }, h("span", null, "接入方式"), h("div", { className: "odaiCC__segments", role: "group", "aria-label": `${ROLE_LABELS[role]}接入方式` }, [["provider", "渠道(API)"], ["local-cli", "本机 CLI"]].map(([value, label]) => h("button", {
470
+ key: value,
471
+ type: "button",
472
+ className: backend === value ? "is-active" : "",
473
+ onClick: () => setBackend(value),
474
+ disabled: busy,
475
+ }, label))), formCli ? h("small", null, "本机 CLI 只读运行,固定子代理调度,需已安装并登录对应 CLI") : null) : null, formCli
476
+ ? h("label", null, h("span", null, "本机 CLI"), h("select", { value: cli, onChange: (event) => setCli(event.target.value), disabled: busy }, LOCAL_CLI_OPTIONS.map((option) => h("option", { key: option.id, value: option.id }, option.label))))
477
+ : h("label", null, h("span", null, "Provider"), h("input", { value: provider, onChange: (event) => setProvider(event.target.value), placeholder: "Provider ID", disabled: busy })), h("label", null, h("span", null, "模型"), h("input", { value: model, onChange: (event) => setModel(event.target.value), placeholder: formCli ? "模型 ID 或别名" : "模型 ID", disabled: busy })), h("label", null, h("span", null, "推理档位"), h("input", { value: effort, onChange: (event) => setEffort(event.target.value), placeholder: formCli && efforts ? `可选:${efforts}` : "可选", disabled: busy })), formCli
478
+ ? h("label", null, h("span", null, "超时(秒)"), h("input", { value: timeoutSeconds, onChange: (event) => setTimeoutSeconds(event.target.value), inputMode: "numeric", placeholder: "可选,默认 1200", disabled: busy }))
479
+ : h("label", null, h("span", null, "最大 tokens"), h("input", { value: maxTokens, onChange: (event) => setMaxTokens(event.target.value), inputMode: "numeric", placeholder: "可选", disabled: busy })), h("div", { className: "odaiCC__formActions" }, route ? h("button", { type: "button", className: "odaiCC__dangerButton", onClick: remove, disabled: busy }, "移除映射") : null, h("button", { type: "button", className: "odaiCC__primaryButton", onClick: save, disabled: busy || !payload }, busy ? "正在验证…" : (formCli ? "保存" : "验证并保存")))) : null);
437
480
  }
438
481
  function RoutingView({ connection, config, setConfig, loading, error, reload }) {
439
482
  const [busyRole, setBusyRole] = useState(undefined);
@@ -582,7 +625,7 @@ window.__ModuleLoader__.load({
582
625
  .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)}
583
626
  .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:16px;line-height:22px;margin:0}.odaiCC__brand span{display:block;color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.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:30px;min-width:72px;border:0;border-radius:4px;background:transparent;color:var(--odai-cc-text-3);cursor:pointer;font:600 12px/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}
584
627
  .odaiCC__nativeCalls{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:8px;min-width:0}.odaiCC__flowRole.odaiCC__nativeCall{grid-template-columns:minmax(0,1fr);width:100%;min-width:0}.odaiCC__nativeCall .odaiCC__roleNode{min-width:0;height:100%}.odaiCC__nativeNote{margin:6px 0 0;color:var(--odai-cc-text-3);font-size:12px;line-height:1.5}
585
- .odaiCC__routing{max-width:1000px;margin:0 auto;padding:16px 18px}.odaiCC__routingHead{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.odaiCC__routingHead h3{font-size:16px;line-height:22px;margin:0}.odaiCC__quietButton,.odaiCC__primaryButton,.odaiCC__dangerButton{height:30px;border-radius:6px;padding:0 11px;font:600 12px/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:12px;line-height:18px;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:9px 0}.odaiCC__controllerLock{display:grid;grid-template-columns:110px minmax(0,1fr) auto;gap:12px;align-items:center}.odaiCC__controllerLock strong{display:block;font-size:13px;line-height:18px}.odaiCC__controllerLock span:not(.odaiCC__role):not(.odaiCC__lock){display:block;color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__lock{border:1px solid var(--odai-cc-border);border-radius:999px;color:var(--odai-cc-text-3);font-size:10px;padding:3px 7px}.odaiCC__routeRow{display:grid;grid-template-columns:minmax(300px,1fr) minmax(410px,1.15fr);gap:8px 20px;align-items:center}.odaiCC__routeSummary{display:grid;grid-template-columns:96px minmax(0,1fr) auto;gap:10px;align-items:center}.odaiCC__routeValue strong{display:block;font-size:13px;line-height:18px;overflow-wrap:anywhere}.odaiCC__routeValue span{display:block;color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__dispatch{display:grid;grid-template-columns:70px auto minmax(0,1fr);gap:10px;align-items:center}.odaiCC__dispatch>span,.odaiCC__dispatch small{color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__segments{display:flex;border:1px solid var(--odai-cc-border);border-radius:6px;overflow:hidden}.odaiCC__segments button{height:28px;border:0;border-right:1px solid var(--odai-cc-border);background:transparent;color:var(--odai-cc-text-3);padding:0 9px;font:500 11px/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{grid-column:1/-1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:0;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:11px;line-height:16px;margin-bottom:4px}.odaiCC__routeForm input{width:100%;min-width:0;height:32px;border:1px solid var(--odai-cc-border);border-radius:5px;background:var(--odai-cc-panel);color:var(--odai-cc-text);padding:0 8px;font:12px/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}
628
+ .odaiCC__routing{max-width:1000px;margin:0 auto;padding:16px 18px}.odaiCC__routingHead{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.odaiCC__routingHead h3{font-size:16px;line-height:22px;margin:0}.odaiCC__quietButton,.odaiCC__primaryButton,.odaiCC__dangerButton{height:30px;border-radius:6px;padding:0 11px;font:600 12px/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:12px;line-height:18px;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:9px 0}.odaiCC__controllerLock{display:grid;grid-template-columns:110px minmax(0,1fr) auto;gap:12px;align-items:center}.odaiCC__controllerLock strong{display:block;font-size:13px;line-height:18px}.odaiCC__controllerLock span:not(.odaiCC__role):not(.odaiCC__lock){display:block;color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__lock{border:1px solid var(--odai-cc-border);border-radius:999px;color:var(--odai-cc-text-3);font-size:10px;padding:3px 7px}.odaiCC__routeRow{display:grid;grid-template-columns:minmax(300px,1fr) minmax(410px,1.15fr);gap:8px 20px;align-items:center}.odaiCC__routeSummary{display:grid;grid-template-columns:96px minmax(0,1fr) auto;gap:10px;align-items:center}.odaiCC__routeValue strong{display:block;font-size:13px;line-height:18px;overflow-wrap:anywhere}.odaiCC__routeValue span{display:block;color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__dispatch{display:grid;grid-template-columns:70px auto minmax(0,1fr);gap:10px;align-items:center}.odaiCC__dispatch>span,.odaiCC__dispatch small{color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__segments{display:flex;border:1px solid var(--odai-cc-border);border-radius:6px;overflow:hidden}.odaiCC__segments button{height:28px;border:0;border-right:1px solid var(--odai-cc-border);background:transparent;color:var(--odai-cc-text-3);padding:0 9px;font:500 11px/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{grid-column:1/-1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:0;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:11px;line-height:16px;margin-bottom:4px}.odaiCC__routeForm input,.odaiCC__routeForm select{width:100%;min-width:0;height:32px;border:1px solid var(--odai-cc-border);border-radius:5px;background:var(--odai-cc-panel);color:var(--odai-cc-text);padding:0 8px;font:12px/1 inherit;outline:none}.odaiCC__routeForm input:focus,.odaiCC__routeForm select:focus{border-color:var(--odai-cc-accent)}.odaiCC__routeBackend{grid-column:1/-1;display:flex;flex-wrap:wrap;align-items:center;gap:10px}.odaiCC__routeBackend>span,.odaiCC__routeBackend small{color:var(--odai-cc-text-3);font-size:11px;line-height:16px}.odaiCC__formActions{grid-column:1/-1;display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
586
629
  .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:11px}.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}
587
630
  @media(max-width:900px){.odaiCC__routeRow{display:block}.odaiCC__dispatch{margin-top:7px}}
588
631
  @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}}
@@ -721,7 +764,7 @@ window.__ModuleLoader__.load({
721
764
  }
722
765
  exports.apply = apply;
723
766
  exports.inject = ["slots", "sessions", "connection"];
724
- exports.__testing = { controlCenterError, conversationTraceSource, defaultTraceItem, projectTrace, stateOf, roleOf, shouldOwnSurface, traceFingerprint, windowTurnItems };
767
+ exports.__testing = { controlCenterError, conversationTraceSource, defaultTraceItem, localCliAllowed, projectTrace, routeEditorPayload, stateOf, roleOf, shouldOwnSurface, traceFingerprint, windowTurnItems };
725
768
  return module.exports;
726
769
  },
727
770
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odai-dsh-agent",
3
- "version": "0.2.51",
3
+ "version": "0.2.52",
4
4
  "description": "独立维护的 odai 治理模式预设(DSH bundle),按任务需要提供治理与协作。",
5
5
  "license": "MIT",
6
6
  "repository": {