weir-harness 2.0.0 → 2.1.0

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 (46) hide show
  1. package/lib/client.capability-badge.js +2 -0
  2. package/lib/client.capability-manager.js +46 -179
  3. package/lib/client.capability-model.js +428 -3
  4. package/lib/client.file-lease-tool-model.js +189 -0
  5. package/lib/client.file-lease-tool-view.js +434 -0
  6. package/lib/client.js +105 -7
  7. package/lib/client.mcp-manager.js +563 -0
  8. package/package.json +1 -1
  9. package/skills/mcp-server-setup/SKILL.md +124 -0
  10. package/src/capabilities/apply-engine.js +18 -4
  11. package/src/capabilities/capability-remote.js +296 -45
  12. package/src/capabilities/initial-selection.js +3 -2
  13. package/src/capabilities/lifecycle-preload.js +69 -11
  14. package/src/capabilities/lifecycle-snapshot.js +127 -39
  15. package/src/capabilities/mcp-admission.js +2 -2
  16. package/src/capabilities/mcp-config.js +344 -0
  17. package/src/capabilities/mcp-credentials.js +180 -0
  18. package/src/capabilities/mcp-diagnostics.js +169 -0
  19. package/src/capabilities/mcp-drain.js +18 -4
  20. package/src/capabilities/mcp-facade.js +3 -3
  21. package/src/capabilities/mcp-gate.js +51 -52
  22. package/src/capabilities/mcp-install-tool.js +276 -0
  23. package/src/capabilities/mcp-manager.js +368 -142
  24. package/src/capabilities/mcp-mount.js +219 -79
  25. package/src/capabilities/mcp-operations.js +359 -0
  26. package/src/capabilities/mcp-process.js +43 -0
  27. package/src/capabilities/mcp-registry.js +74 -60
  28. package/src/capabilities/mcp-runtime.js +103 -0
  29. package/src/capabilities/read-payloads.js +8 -3
  30. package/src/capabilities/skill-applicability.js +185 -0
  31. package/src/capabilities/skill-builtin-migration.js +2 -1
  32. package/src/capabilities/skill-selection-plugin.js +161 -56
  33. package/src/file-lease/client.js +268 -35
  34. package/src/file-lease/index.js +4 -0
  35. package/src/file-lease/plugin.js +239 -15
  36. package/src/file-lease/tools.js +426 -38
  37. package/src/file-lease/watch.js +473 -0
  38. package/src/intent-gate/index.js +29 -12
  39. package/src/intent-gate/matcher.js +36 -2
  40. package/src/lease-broker/protocol.js +3 -2
  41. package/src/lease-broker/server.js +6 -3
  42. package/src/lease-broker/state.js +68 -11
  43. package/src/process/index.js +4 -2
  44. package/src/shared/audit.js +3 -0
  45. package/src/shared/child-scope.js +2 -0
  46. package/src/worktree/rules.js +1 -1
package/lib/client.js CHANGED
@@ -1,4 +1,4 @@
1
- // Weir client chunks: {"client.blackboard-model.js":"2e5abdd44edb599d10d9d547fa07133e84250d6007161c2c8704b58151896f93","client.blackboard-panel.js":"c9d6a0f02623075fc884f3519f982574ad33ad871f7bcd7e8c36f12512f0de39","client.capability-badge.js":"6ffd703f498e0aa5cc8ac78f244402ec4ceee56d22d2a0e74c246799565776cc","client.capability-manager.js":"d22e8116922f98e61bbbdf36fc78bd81e8b47b0ee5e75ddb06bea4e204749b89","client.capability-model.js":"d2aef1aa2daaecad6c9a1b9d9a0ecf6fb37dd7ec80efff5d532cf3b8a6efa712","client.capability-presets.js":"12ac8da3568d013abd76b67cfe473a329f4af2feaac9cd55a82d8881e5bc1017","client.chain-editor.js":"1e9a33bc68cabc43bc27b91ef83eab5028a33256596c147e15722d684687765b","client.chain-model.js":"2e885922cf8c2972725c6eef8bf20c7d1202d961edfb8ad41574dac062d74371","client.disabled-categories-editor.js":"f9103fd2e2691eda9afd199e1a5462189097a9f3dee0518be5fa3587d896e033","client.file-lease-badge.js":"cd30546307c91c94fe05484557e46f58c53fe55657f62b0a0415a072dfb3b582","client.hash-edit-model.js":"71727d47a6ef32ebd2abfb063fa93499a5e607d6716e3ec8983ae056c4fb317f","client.hash-edit-view.js":"fc0f4dabddab9a48527553ad4232b3715e46e6863aab75e02ae2dcd6687265c2","client.lsp-model.js":"30943ed1ed11c1f2770a724da855ea2417c11566c2778c79e17cfc2de499cd80","client.lsp-panel.js":"61629a4d317dae9ed01c1cc0355632fb752788dc23f7606257188050734cd030","client.lsp-toggle.js":"d6af81be5e5b854e98563bbb9349a6db89834a9d7dee9cf0e97759ecb32090e8","client.model-picker.js":"57f96826e00b37ae6d6474a6750f31b4e128e5fdb37e302875a41cdb2e18f14a","client.notify-permissions.js":"2be9bdbeffef96baa3cbe4ce430ab30a1d1bf797782453d287d54602ea47db8e","client.notify-web.js":"0943f67d5526ff0fb7cb4f69580e0a9ea54ed06465c513afc51a5a7fb1c55ccf","client.robash-editor.js":"cd6a283b72cb02598e32ca4ce03a1b8de5f328ecdd1f5f920377524f3bdcbe1c","client.robash-model.js":"f4395338a773e8bb48e4f96aeb737cd634edcca0b90af992a7dbbe47be42e451","client.settings-page.js":"f3c04a5b33cdb963357bc653f7050e598f19efc4cc833694379a4ba055e949d3","client.worktree-model.js":"8bfbaaa080f20e90a0128afccb9b4e232514615a8f2fee3a32a42dde78b34a8f","client.worktree-view.js":"356c3f5f683b8509ae8679243a6460ca02957fd15e057a629b2ac4fdd12ed057"}
1
+ // Weir client chunks: {"client.blackboard-model.js":"2e5abdd44edb599d10d9d547fa07133e84250d6007161c2c8704b58151896f93","client.blackboard-panel.js":"c9d6a0f02623075fc884f3519f982574ad33ad871f7bcd7e8c36f12512f0de39","client.capability-badge.js":"f5c5d21293360d00815446beb8455794a1778ae033e270af37e436329ac09185","client.capability-manager.js":"f02e08174487f2f70e90a5c50a4a44cbeb4d462f115a2d2ab8a52ed8b4e70aee","client.capability-model.js":"57127dc5ea7ca6aa70c619480684f4de84fcbff4922f70df9886f55fad66abbf","client.capability-presets.js":"12ac8da3568d013abd76b67cfe473a329f4af2feaac9cd55a82d8881e5bc1017","client.chain-editor.js":"1e9a33bc68cabc43bc27b91ef83eab5028a33256596c147e15722d684687765b","client.chain-model.js":"2e885922cf8c2972725c6eef8bf20c7d1202d961edfb8ad41574dac062d74371","client.disabled-categories-editor.js":"f9103fd2e2691eda9afd199e1a5462189097a9f3dee0518be5fa3587d896e033","client.file-lease-badge.js":"cd30546307c91c94fe05484557e46f58c53fe55657f62b0a0415a072dfb3b582","client.file-lease-tool-model.js":"f72d87b049454ec489b4dffac1f32dabc273947b8a4c55fe07c91ddf320bd899","client.file-lease-tool-view.js":"7004caa06b36d8497a1d2e448b6ce5e4c8efd22ad903d8b39e26220de64bb1fe","client.hash-edit-model.js":"71727d47a6ef32ebd2abfb063fa93499a5e607d6716e3ec8983ae056c4fb317f","client.hash-edit-view.js":"fc0f4dabddab9a48527553ad4232b3715e46e6863aab75e02ae2dcd6687265c2","client.lsp-model.js":"30943ed1ed11c1f2770a724da855ea2417c11566c2778c79e17cfc2de499cd80","client.lsp-panel.js":"61629a4d317dae9ed01c1cc0355632fb752788dc23f7606257188050734cd030","client.lsp-toggle.js":"d6af81be5e5b854e98563bbb9349a6db89834a9d7dee9cf0e97759ecb32090e8","client.mcp-manager.js":"cfcd4792251fcca8bfa6a2c35b80881ab6f6480cf2ebce24a8ce304cddf940a7","client.model-picker.js":"57f96826e00b37ae6d6474a6750f31b4e128e5fdb37e302875a41cdb2e18f14a","client.notify-permissions.js":"2be9bdbeffef96baa3cbe4ce430ab30a1d1bf797782453d287d54602ea47db8e","client.notify-web.js":"0943f67d5526ff0fb7cb4f69580e0a9ea54ed06465c513afc51a5a7fb1c55ccf","client.robash-editor.js":"cd6a283b72cb02598e32ca4ce03a1b8de5f328ecdd1f5f920377524f3bdcbe1c","client.robash-model.js":"f4395338a773e8bb48e4f96aeb737cd634edcca0b90af992a7dbbe47be42e451","client.settings-page.js":"f3c04a5b33cdb963357bc653f7050e598f19efc4cc833694379a4ba055e949d3","client.worktree-model.js":"8bfbaaa080f20e90a0128afccb9b4e232514615a8f2fee3a32a42dde78b34a8f","client.worktree-view.js":"356c3f5f683b8509ae8679243a6460ca02957fd15e057a629b2ac4fdd12ed057"}
2
2
  window.__ModuleLoader__.load({
3
3
  id: "weir-harness",
4
4
  factory: (require) => {
@@ -49,6 +49,17 @@ window.__ModuleLoader__.load({
49
49
  worktreeLoading: "Loading lanes…",
50
50
  hashEditInput: "Input",
51
51
  hashEditOutput: "Output",
52
+ // Edit-lock conversation cards: the seven tool titles the pre-arrival
53
+ // placeholder reads synchronously. Byte-identical to the view chunk's
54
+ // data face ("settings.weir.file-lease-tools") — a documented
55
+ // cross-namespace duplicate pinned by test/client.test.js.
56
+ leaseToolTitle_edit_lock_acquire: "Claim edit lock",
57
+ leaseToolTitle_edit_lock_release: "Release edit lock",
58
+ leaseToolTitle_edit_lock_hold: "Keep edit lock",
59
+ leaseToolTitle_edit_lock_status: "Edit lock status",
60
+ leaseToolTitle_edit_lock_try_steal: "Request edit lock transfer",
61
+ leaseToolTitle_edit_lock_reply: "Answer transfer request",
62
+ leaseToolTitle_edit_lock_watch: "Watch for release",
52
63
  // Session capability Badge + manager (12.x, D3/D4): the chunks carry
53
64
  // the same strings as in-code fallbacks; these rows translate them.
54
65
  capabilityTabLabel: "Capabilities",
@@ -84,6 +95,13 @@ window.__ModuleLoader__.load({
84
95
  worktreeLoading: "正在加载车道…",
85
96
  hashEditInput: "输入",
86
97
  hashEditOutput: "输出",
98
+ leaseToolTitle_edit_lock_acquire: "申请编辑锁",
99
+ leaseToolTitle_edit_lock_release: "释放编辑锁",
100
+ leaseToolTitle_edit_lock_hold: "保留编辑锁",
101
+ leaseToolTitle_edit_lock_status: "编辑锁状态",
102
+ leaseToolTitle_edit_lock_try_steal: "请求转交编辑锁",
103
+ leaseToolTitle_edit_lock_reply: "答复转交请求",
104
+ leaseToolTitle_edit_lock_watch: "订阅释放",
87
105
  capabilityTabLabel: "能力",
88
106
  capabilityGuideTitle: "能力",
89
107
  capabilityGuideDescription: "此会话的技能、MCP server 与预设。",
@@ -123,6 +141,7 @@ window.__ModuleLoader__.load({
123
141
  lspToggle: null,
124
142
  hashEdit: null,
125
143
  fileLease: null,
144
+ fileLeaseTools: null,
126
145
  worktree: null,
127
146
  };
128
147
  // ---- Package-local chunk wiring (composition root) ----
@@ -228,6 +247,59 @@ window.__ModuleLoader__.load({
228
247
  if (!arrival?.chunks) return null;
229
248
  return react_jsx_runtime.jsx(arrival.chunks.FileLeaseBadge, { ...props, t: chunkDictionaries.fileLease ?? props.t });
230
249
  }
250
+ // ---- Edit-lock conversation cards (edit-lock-tool-cards D2) ----
251
+ // One view chunk plus one model chunk carry the seven keyed tool cards;
252
+ // the dictionaries ride the view chunk and register under their own
253
+ // namespace (the composer badge already owns "settings.weir.file-lease",
254
+ // and a namespace registers once per apply).
255
+ const FILE_LEASE_TOOL_NAMES = ["edit_lock_acquire", "edit_lock_release", "edit_lock_hold", "edit_lock_status", "edit_lock_try_steal", "edit_lock_reply", "edit_lock_watch"];
256
+ const loadFileLeaseToolChunks = lazyChunks(() => Promise.all([
257
+ require.async("./client.file-lease-tool-view.js"),
258
+ require.async("./client.file-lease-tool-model.js")
259
+ ]).then((chunks) => {
260
+ chunkDictionaries.register?.("settings.weir.file-lease-tools", chunks[0].dictionaries);
261
+ return chunks;
262
+ }));
263
+ // Pre-arrival (or failed-load) placeholder: the localized title and the
264
+ // requested paths from the call arguments, so a card is never blank. The
265
+ // argument read mirrors the model chunk's argsPaths (same-package sync
266
+ // require is impossible, so the tiny parse is mirrored here, not shared).
267
+ const fileLeasePlaceholderStyle = { display: "flex", alignItems: "baseline", gap: "8px", minWidth: 0, padding: "8px 10px", border: "1px solid var(--dsw-alias-border-l2)", borderRadius: "var(--dsw-radius-md, 8px)", background: "var(--dsw-alias-bg-layer-1)" };
268
+ const fileLeasePlaceholderTitleStyle = { fontSize: "13px", lineHeight: "18px", fontWeight: 600, color: "var(--dsw-alias-label-primary)", whiteSpace: "nowrap" };
269
+ const fileLeasePlaceholderPathStyle = { fontSize: "12px", lineHeight: "16px", color: "var(--dsw-alias-label-secondary)", fontFamily: "var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 };
270
+ const fileLeaseArgsPaths = (block) => {
271
+ const raw = typeof block?.argsRaw === "string" ? block.argsRaw : typeof block?.call?.argsRaw === "string" ? block.call.argsRaw : null;
272
+ if (raw === null) return [];
273
+ let args;
274
+ try {
275
+ args = JSON.parse(raw);
276
+ } catch {
277
+ return [];
278
+ }
279
+ if (Array.isArray(args?.paths)) return args.paths.filter((path) => typeof path === "string" && path !== "");
280
+ return typeof args?.file_path === "string" && args.file_path !== "" ? [args.file_path] : [];
281
+ };
282
+ function FileLeaseToolPlaceholder(props) {
283
+ const paths = fileLeaseArgsPaths(props.block);
284
+ const title = typeof props.t === "function" ? props.t(`leaseToolTitle_${props.toolName}`) : props.toolName;
285
+ return react_jsx_runtime.jsxs("div", { "data-tool": props.toolName, "data-weir-lease-placeholder": "", style: fileLeasePlaceholderStyle, children: [
286
+ react_jsx_runtime.jsx("span", { style: fileLeasePlaceholderTitleStyle, children: title }, "title"),
287
+ paths.length > 0 ? react_jsx_runtime.jsx("span", { style: fileLeasePlaceholderPathStyle, children: paths.length > 1 ? `${paths[0]} +${paths.length - 1}` : paths[0] }, "path") : null
288
+ ] });
289
+ }
290
+ /** Keyed toolview wrapper for one edit_lock_* tool: the placeholder until
291
+ * the view+model chunks arrive, then the read-only card. */
292
+ const fileLeaseToolView = (toolName) => {
293
+ function FileLeaseToolViewWrapper(props) {
294
+ const arrival = useChunkArrival(loadFileLeaseToolChunks);
295
+ if (arrival?.chunks) {
296
+ const [view, model] = arrival.chunks;
297
+ return react_jsx_runtime.jsx(view.FileLeaseToolRow, { ...props, toolName, t: chunkDictionaries.fileLeaseTools ?? props.t, model });
298
+ }
299
+ return react_jsx_runtime.jsx(FileLeaseToolPlaceholder, { ...props, toolName });
300
+ }
301
+ return FileLeaseToolViewWrapper;
302
+ };
231
303
  // ---- Tab glyphs (ui-entries-and-icons) ----
232
304
  // Three 16x16 stroke glyphs drawn in currentColor, matching the host
233
305
  // CompassGlyph/CubeGlyph style (no strokeWidth, rounded caps/joins).
@@ -428,6 +500,7 @@ window.__ModuleLoader__.load({
428
500
  chunkDictionaries.lspToggle = ctx.locale.bind("settings.weir.lsp-toggle");
429
501
  chunkDictionaries.hashEdit = ctx.locale.bind("settings.weir.hash-edit");
430
502
  chunkDictionaries.fileLease = ctx.locale.bind("settings.weir.file-lease");
503
+ chunkDictionaries.fileLeaseTools = ctx.locale.bind("settings.weir.file-lease-tools");
431
504
  chunkDictionaries.worktree = ctx.locale.bind("settings.weir.worktree");
432
505
  const pageT = ctx.locale.bind("settings.weir.page");
433
506
  const capabilityT = ctx.locale.bind("settings.weir.capability");
@@ -802,6 +875,11 @@ window.__ModuleLoader__.load({
802
875
  const result = await capabilityChannel(`weirCapabilities/${method}`, { args: { sessionId: sid } });
803
876
  return result.ok === true ? result.value : fallback;
804
877
  };
878
+ const capabilityMutation = async (method, sid, request) => {
879
+ const result = await capabilityChannel(`weirCapabilityMutations/${method}`, { args: { sessionId: sid, request } });
880
+ if (result.ok === true) return result.value;
881
+ return { status: result.error?.code ?? "call-failed", saved: false, error: result.error ?? { code: "call-failed", message: "MCP mutation failed" } };
882
+ };
805
883
  // The presets & workspace-default view is its own chunk, pulled only
806
884
  // when the Presets view is first selected (D3) — the composition root
807
885
  // owns every require.async specifier (no chunk-to-chunk waterfall).
@@ -829,6 +907,9 @@ window.__ModuleLoader__.load({
829
907
  // (explicit error surface) — a null payload maps to the error state.
830
908
  applySelection: (sid, draft) => capabilityPayload(sid, `/capabilities apply ${JSON.stringify(draft)}`, true),
831
909
  mcpAdd: (sid, spec) => capabilityPayload(sid, `/capabilities mcp-add ${JSON.stringify(spec)}`),
910
+ mcpPreview: (sid, request) => capabilityMutation("mutate", sid, request),
911
+ mcpMutate: (sid, request) => capabilityMutation("mutate", sid, request),
912
+ mcpBatch: (sid, request) => capabilityMutation("batch", sid, request),
832
913
  fetchListing: (sid) => capabilityRead("list", sid, { error: true }),
833
914
  fetchConditions: (sid) => capabilityRead("conditions", sid, { error: true }),
834
915
  // The manager forwards only its established props. Adapt the lazy view
@@ -859,14 +940,19 @@ window.__ModuleLoader__.load({
859
940
  const [impl, setImpl] = react.useState(null);
860
941
  react.useEffect(() => {
861
942
  let alive = true;
862
- Promise.all([require.async("./client.capability-badge.js"), require.async("./client.capability-model.js"), require.async("./client.capability-manager.js")]).then(([badge, model, panel]) => {
943
+ Promise.all([
944
+ require.async("./client.capability-badge.js"),
945
+ require.async("./client.capability-model.js"),
946
+ require.async("./client.capability-manager.js"),
947
+ require.async("./client.mcp-manager.js").catch(() => null),
948
+ ]).then(([badge, model, panel, mcp]) => {
863
949
  registerChunkDictionaries("settings.weir.capability", model.dictionaries);
864
- if (alive) setImpl(() => ({ Badge: badge.CapabilityBadge, model, Panel: panel.CapabilityManagerPanel }));
950
+ if (alive) setImpl(() => ({ Badge: badge.CapabilityBadge, model, Panel: panel.CapabilityManagerPanel, McpManagerView: mcp?.McpManagerView, McpManagerBoundary: mcp?.McpManagerBoundary }));
865
951
  });
866
952
  return () => { alive = false; };
867
953
  }, [props.sessionId]);
868
954
  if (!impl) return null;
869
- return react_jsx_runtime.jsx(impl.Badge, { ...props, t: capabilityT, model: impl.model, ManagerPanel: impl.Panel });
955
+ return react_jsx_runtime.jsx(impl.Badge, { ...props, t: capabilityT, model: impl.model, ManagerPanel: impl.Panel, McpManagerView: impl.McpManagerView, McpManagerBoundary: impl.McpManagerBoundary });
870
956
  };
871
957
  ctx.effect(() => ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
872
958
  name: "conversation.input.right",
@@ -895,7 +981,8 @@ window.__ModuleLoader__.load({
895
981
  // view tree.
896
982
  const loadCapabilityPanelChunks = lazyChunks(() => Promise.all([
897
983
  require.async("./client.capability-model.js"),
898
- require.async("./client.capability-manager.js")
984
+ require.async("./client.capability-manager.js"),
985
+ require.async("./client.mcp-manager.js").catch(() => null),
899
986
  ]).then((chunks) => {
900
987
  registerChunkDictionaries("settings.weir.capability", chunks[0].dictionaries);
901
988
  return chunks;
@@ -903,10 +990,10 @@ window.__ModuleLoader__.load({
903
990
  function CapabilityPanelWrapper(props) {
904
991
  const arrival = useChunkArrival(loadCapabilityPanelChunks, typeof props.sessionId === "string" && props.sessionId !== "");
905
992
  if (!arrival?.chunks) return react_jsx_runtime.jsx("div", { style: settingsLoadingStyle, children: typeof props.t === "function" ? props.t("capability.loading") : "" });
906
- const [model, panel] = arrival.chunks;
993
+ const [model, panel, mcp] = arrival.chunks;
907
994
  // The same view tree the composer popover renders — the sidebar is
908
995
  // just the outer frame (D1). No onClose: the pane chrome owns closing.
909
- return react_jsx_runtime.jsx(panel.CapabilityManagerPanel, { ...props, t: capabilityT, model, shell: "sidebar" });
996
+ return react_jsx_runtime.jsx(panel.CapabilityManagerPanel, { ...props, t: capabilityT, model, shell: "sidebar", McpManagerView: mcp?.McpManagerView, McpManagerBoundary: mcp?.McpManagerBoundary });
910
997
  }
911
998
  ctx.inject?.(["sidebarRightTabs"], (sidebarScope) => {
912
999
  capabilitySidebarTab = true;
@@ -1005,6 +1092,17 @@ window.__ModuleLoader__.load({
1005
1092
  }
1006
1093
  } : {})
1007
1094
  }, BlackboardPill)), "ui-weir-settings: blackboard header pill");
1095
+ // Edit-lock conversation cards (edit-lock-tool-cards D2): one keyed,
1096
+ // read-only tool view per edit_lock_* tool, each in its own effect so
1097
+ // one registration failure cannot take down the others. Registration
1098
+ // pulls no chunk; the wrapper renders a title+paths placeholder first.
1099
+ for (const toolName of FILE_LEASE_TOOL_NAMES) {
1100
+ ctx.effect(() => ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1101
+ name: "tool.call.toolview",
1102
+ key: toolName,
1103
+ locale: NS
1104
+ }, fileLeaseToolView(toolName))), `ui-weir-settings: ${toolName} toolview`);
1105
+ }
1008
1106
  // Top-level Settings section (same place as dsh-web-kimi and the
1009
1107
  // built-in General/Models sections), with a nested item slot
1010
1108
  // hosting the form — the single Weir settings entry.