weir-harness 1.2.0 → 1.2.1

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 (92) hide show
  1. package/lib/client.blackboard-model.js +172 -56
  2. package/lib/client.capability-manager.js +0 -1
  3. package/lib/client.capability-model.js +378 -31
  4. package/lib/client.chain-model.js +80 -0
  5. package/lib/client.disabled-categories-editor.js +22 -0
  6. package/lib/client.edit-lock-maintenance.js +239 -246
  7. package/lib/client.edit-lock-panel.js +110 -0
  8. package/lib/client.hash-edit-model.js +48 -0
  9. package/lib/client.js +267 -1549
  10. package/lib/client.lsp-model.js +92 -0
  11. package/lib/client.lsp-panel.js +11 -16
  12. package/lib/client.lsp-toggle.js +18 -0
  13. package/lib/client.notify-permissions.js +112 -20
  14. package/lib/client.notify-web.js +14 -11
  15. package/lib/client.robash-model.js +26 -0
  16. package/lib/client.settings-page.js +287 -17
  17. package/lib/client.worktree-model.js +225 -0
  18. package/package.json +1 -1
  19. package/src/blackboard/durable.js +12 -0
  20. package/src/blackboard/index.js +2 -2
  21. package/src/blackboard/kernel.js +23 -6
  22. package/src/blackboard/notify.js +10 -3
  23. package/src/blackboard/remote.js +31 -13
  24. package/src/blackboard/storage.js +13 -5
  25. package/src/capabilities/apply-engine.js +189 -101
  26. package/src/capabilities/defaults-transaction.js +136 -1
  27. package/src/capabilities/lifecycle-snapshot.js +83 -204
  28. package/src/capabilities/mcp-admission.js +1 -23
  29. package/src/capabilities/mcp-drain.js +30 -19
  30. package/src/capabilities/mcp-facade.js +23 -3
  31. package/src/capabilities/preset-library.js +247 -0
  32. package/src/capabilities/preset-package.js +212 -1
  33. package/src/capabilities/same-name-policy.js +3 -41
  34. package/src/capabilities/selection-notify.js +324 -21
  35. package/src/capabilities/skill-selection-plugin.js +315 -729
  36. package/src/capabilities/store/checked-contract.d.ts +5 -0
  37. package/src/capabilities/store/fs-adapter.js +52 -0
  38. package/src/capabilities/store/lock.js +86 -0
  39. package/src/capabilities/store/paths.js +5 -0
  40. package/src/capabilities/store/store.js +105 -5
  41. package/src/delegate/group-coordinator.js +1 -17
  42. package/src/delegate/index.js +4 -2
  43. package/src/delegate/rehydrate.js +2 -1
  44. package/src/delegate/robash-guard-core.js +2 -2
  45. package/src/delegate/supervision-mount.js +5 -4
  46. package/src/delegate/tool.js +26 -3
  47. package/src/{shared → delegate}/whitelist-defaults.js +2 -2
  48. package/src/edit-lock/admin-ledger.js +8 -11
  49. package/src/edit-lock/admin-recovery.js +2 -1
  50. package/src/edit-lock/admission.js +12 -2
  51. package/src/edit-lock/binding-guidance.js +28 -10
  52. package/src/edit-lock/binding-machine.js +312 -0
  53. package/src/edit-lock/derived-facts.js +67 -0
  54. package/src/edit-lock/index.js +44 -244
  55. package/src/edit-lock/inspect.js +113 -1
  56. package/src/edit-lock/lifecycle.js +8 -5
  57. package/src/edit-lock/limits.js +61 -0
  58. package/src/edit-lock/maintenance.js +5 -2
  59. package/src/edit-lock/manager.js +6 -2
  60. package/src/edit-lock/operation-history.js +1 -1
  61. package/src/edit-lock/peer-client.js +9 -2
  62. package/src/edit-lock/peer-transport.js +7 -1
  63. package/src/edit-lock/remote.js +11 -4
  64. package/src/edit-lock/state.js +2 -4
  65. package/src/edit-lock/view.js +10 -11
  66. package/src/lsp/admin.js +2 -24
  67. package/src/lsp/index.js +1 -1
  68. package/src/lsp/manager.js +1 -1
  69. package/src/notify/permissions-admin.js +1 -1
  70. package/src/{lsp/child-process.js → process/index.js} +12 -4
  71. package/src/settings/env-admin.js +1 -1
  72. package/src/settings/index.js +1 -1
  73. package/src/settings/sections.js +0 -54
  74. package/src/shared/audit.js +5 -0
  75. package/src/shared/http-json.js +28 -0
  76. package/src/{delegate/audit-readers.js → shared/terminal-evidence.js} +34 -4
  77. package/src/worktree/errors.js +3 -0
  78. package/src/worktree/index.js +1 -2
  79. package/src/worktree/lane-core.js +641 -0
  80. package/src/worktree/lane-views.js +147 -0
  81. package/src/worktree/lane-workflows.js +853 -0
  82. package/src/worktree/lanes.js +24 -1513
  83. package/src/worktree/runner.js +5 -4
  84. package/src/capabilities/content-pin.js +0 -88
  85. package/src/capabilities/content-refresh.js +0 -331
  86. package/src/capabilities/distribution-manifest.js +0 -78
  87. package/src/capabilities/isolated-exec.js +0 -106
  88. package/src/capabilities/publisher.js +0 -129
  89. package/src/capabilities/skill-admission.js +0 -181
  90. package/src/capabilities/update-lifecycle.js +0 -106
  91. package/src/edit-lock/remote-service.js +0 -28
  92. package/src/worktree/contract-guidance.test.js +0 -100
package/lib/client.js CHANGED
@@ -1,4 +1,4 @@
1
- // Weir client chunks: {"client.blackboard-model.js":"f635f6c1a03538b41c253a3236826220c38a5a1f45db73547fa82f4955e41cb3","client.blackboard-panel.js":"c9d6a0f02623075fc884f3519f982574ad33ad871f7bcd7e8c36f12512f0de39","client.capability-badge.js":"6ffd703f498e0aa5cc8ac78f244402ec4ceee56d22d2a0e74c246799565776cc","client.capability-manager.js":"d8d1076e1b624c1dfc0834ad393c05fd7d9ee35004cd2fb34e5e5ba83f44c902","client.capability-model.js":"d0ad248c4a6defbc90f79c8c0e7904639779d47927874b8663c15c6cecb9d54a","client.capability-presets.js":"12ac8da3568d013abd76b67cfe473a329f4af2feaac9cd55a82d8881e5bc1017","client.chain-editor.js":"1e9a33bc68cabc43bc27b91ef83eab5028a33256596c147e15722d684687765b","client.chain-model.js":"81cdd04626900a63c38ccb3d9c4d117686c6f8a5da2ce9131b7aaf2f089dea77","client.disabled-categories-editor.js":"d4606a3172b47b25caf76fd64c8420a0079cd5f008bc67a9c71b3f146724e393","client.edit-lock-maintenance.js":"f5dca1a7658e2f536b52d265c49ab37bb5d2df6bcd6cf21826b843c9554311a8","client.edit-lock-panel.js":"54f7a21b79adc2b91803c61d92b0dad72d95d5d320fdf35433719cefd0a6c46d","client.hash-edit-model.js":"99df87cc3cc261abd160b83124b5ce726d0708f3c87eba9d58ad9e5a1f41bae9","client.hash-edit-view.js":"fc0f4dabddab9a48527553ad4232b3715e46e6863aab75e02ae2dcd6687265c2","client.lsp-model.js":"6b5bead2900289427a1ad723b9c7bea85af4c5547029e486c620ff94ece24775","client.lsp-panel.js":"39211da7658e0810abc0984b8bcbbfb4ee6a6299fedfd21649ded1ab39d1f291","client.lsp-toggle.js":"4d960984ccf1045c617be6d282665513a9cf636779563a276973b55036a59fb6","client.model-picker.js":"57f96826e00b37ae6d6474a6750f31b4e128e5fdb37e302875a41cdb2e18f14a","client.notify-permissions.js":"c1c103ce5976a4032b62e12b3b3ecb907a574159bf89512539c68c4886ea37a7","client.notify-web.js":"b2ccf831524be4e94c532324cb5495793d4424e3b78d6014d2a3f3d20e9c5871","client.robash-editor.js":"cd6a283b72cb02598e32ca4ce03a1b8de5f328ecdd1f5f920377524f3bdcbe1c","client.robash-model.js":"356ee7a679223bcd351720b2bc9e7300e390d97a60d1c8d75998706b4644923b","client.settings-page.js":"ca31b2fbf5bbca0e1357bf6c78d5860898a5bdc9c878fe61c6b4645e0a7ecb79","client.worktree-model.js":"819f1b00650aa0bb01140690b29b4a1f09b9d26e6bb73adc7efbb3a08e215766","client.worktree-view.js":"356c3f5f683b8509ae8679243a6460ca02957fd15e057a629b2ac4fdd12ed057"}
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.edit-lock-maintenance.js":"5e6933f3ad222ea99e890a06b94a223de1e864de058fca2a53954d62eaad9ab8","client.edit-lock-panel.js":"fa78a0762d2787e6322308dfff103aab3cdbd078d1ec22000d6deefe258153b1","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":"b6524f04641793602e00bc42f1c86f7e8981b903e16a8493379126c359dbab96","client.worktree-model.js":"8bfbaaa080f20e90a0128afccb9b4e232514615a8f2fee3a32a42dde78b34a8f","client.worktree-view.js":"356c3f5f683b8509ae8679243a6460ca02957fd15e057a629b2ac4fdd12ed057"}
2
2
  window.__ModuleLoader__.load({
3
3
  id: "weir-harness",
4
4
  factory: (require) => {
@@ -31,680 +31,30 @@ window.__ModuleLoader__.load({
31
31
  })();
32
32
  const en = {
33
33
  title: "Weir",
34
- description: "One-stop configuration for the Weir preset: intent classification, auto-continuation, context pressure, file editing, worktree lanes, read-only shell, LSP, and notifications; model routing is a separate page.",
35
34
  routingTitle: "Weir Model Routing",
36
- routingDescription: "Which models delegated children run on: per task category or curated agent, with ordered fallbacks.",
37
35
  loading: "Loading Weir settings…",
38
36
  loadFailed: "Weir settings could not be loaded:",
39
- unavailable: "This plugin is not loaded, so it cannot be configured right now.",
40
- readOnly: "This deployment stores settings read-only.",
41
- saveFailed: "The deployment did not accept these values; they were left for you to correct.",
42
- save: "Save",
43
- saving: "Saving…",
44
- pendingChanges: "{n} unsaved change(s)",
45
- discardChanges: "Discard",
46
- overridden: "Overridden",
47
- reset: "Reset to default",
48
- restartRequired: "Restart required",
49
- invalidValue: "Enter a value this field accepts, or leave blank to use the default.",
50
- restartReminderTitle: "Restart to apply",
51
- restartReminderBody: "These settings changed and take effect after restarting DeepSeek Harness. Everything else you saved is already live.",
52
- restartReminderDismiss: "Dismiss",
53
- restartReminderAcknowledge: "Got it",
54
- catalogLoading: "Loading providers…",
55
- pickerModel: "Model",
56
- pickerEffort: "Reasoning",
57
- effortProviderDefault: "Provider default",
58
- catalogFailed: "Provider catalog unavailable; enter provider and model manually.",
59
- providerEmpty: "Select a provider",
60
- modelEmpty: "Select a model",
61
- pickerUnavailable: "Model picker unavailable — reload the settings page to retry.",
62
- groupIntent: "Intent",
63
- groupTodo: "Auto-continuation",
64
- groupGuard: "Context pressure",
65
- groupEditing: "File editing",
66
- groupWorktree: "Worktree lanes",
67
- groupRobash: "Read-only shell",
68
- groupLsp: "LSP",
69
- groupNotify: "Notifications",
70
- groupRoutingCategories: "Task categories",
71
- groupRoutingAgents: "Curated agents",
72
- groupRoutingSupervision: "Supervision and retries",
73
- intentGateClassifierOptionRegex: "regex",
74
- intentGateClassifierOptionLlm: "llm",
75
- intentGateClassifierOptionJev: "jev",
76
- intentGateClassifier: "Intent classifier",
77
- intentGateClassifierHint: "How each message's intent is detected: regex uses built-in rules at zero cost (default); llm uses a small dedicated model; jev is experimental.",
78
- intentGateProvider: "Classifier model (llm mode)",
79
- intentGateProviderHint: "A dedicated model for semantic classification; blank follows the session model.",
80
- intentGateModel: "Classifier model name (llm mode)",
81
- intentGateModelHint: "Blank follows the session route's model.",
82
- intentGateReasoningEffort: "Classifier reasoning effort (llm mode)",
83
- intentGateReasoningEffortHint: "Blank follows the model default.",
84
- intentGateTimeoutMs: "Classifier timeout (ms)",
85
- intentGateTimeoutMsHint: "On timeout the rule-based result is used; the message is never blocked (default 1500).",
86
- jevEndpoint: "Jev endpoint",
87
- jevEndpointHint: "Jev decisions service URL (experimental mode).",
88
- jevModel: "Jev model",
89
- jevModelHint: "Model name for Jev (default jev).",
90
- jevApiKeyEnv: "Jev API key env var",
91
- jevApiKeyEnvHint: "Environment variable name holding the Jev API key; the key itself never enters config.",
92
- delegateCategoryChains: "Category models",
93
- delegateCategoryChainsHint: "The model children of each task category run on; add fallbacks tried in order, or leave empty to follow the session model.",
94
- delegateAgentChains: "Curated agent models",
95
- delegateAgentChainsHint: "The model each curated agent (finder, scholar, advisor) runs on; empty inherits the caller's route.",
96
- delegateDisabledCategories: "Disabled categories",
97
- delegateDisabledCategoriesHint: "Disabled categories leave the delegation list and can no longer be delegated to.",
98
- disabledCategoriesCount: "disabled",
99
- disabledCategoriesPanelHint: "One switch per category; saving writes exactly the switched-on names — all off disables nothing.",
100
- disabledCategoriesInvalid: "The stored value is not a valid category list; the editor opened with every category off — saving replaces it.",
101
- chainAgent_finder: "Finder",
102
- chainAgent_finder_desc: "Contextual codebase search: answers \"where is X?\" and \"find the code that does Z\". Read-only, fast, parallel-first.",
103
- chainAgent_scholar: "Scholar",
104
- chainAgent_scholar_desc: "Documentation and OSS research: official docs, library APIs, best practices, real-world usage. Read-only.",
105
- chainAgent_advisor: "Advisor",
106
- chainAgent_advisor_desc: "Architecture and design advisor: module boundaries, decomposition, trade-offs. Read-only, high reasoning.",
107
- chainAgentPanelHint: "One row per curated agent; empty inherits the caller's route, fallbacks are tried in order.",
108
- chainEdit: "Edit",
109
- chainPanelHint: "One row per category: Edit picks the models, fallbacks are tried in order; an empty row follows the session model.",
110
- chainSave: "Save",
111
- chainCancel: "Cancel",
112
- chainAddRung: "Add fallback",
113
- chainRemove: "Remove",
114
- chainClear: "Clear (inherit)",
115
- chainCategory_quick: "Quick",
116
- chainCategory_quick_desc: "Trivial mechanical work: single-file changes, typo fixes, boilerplate.",
117
- chainCategory_deep: "Deep",
118
- chainCategory_deep_desc: "One goal, one deliverable: debugging, cross-module work, subtle logic.",
119
- "chainCategory_deep-plus": "Deep plus",
120
- "chainCategory_deep-plus_desc": "Escalation lane: trade-offs, contracts, invariants evidence cannot settle.",
121
- chainCategory_visual: "Visual",
122
- chainCategory_visual_desc: "Frontend, UI/UX, styling, animation, layout.",
123
- chainCategory_writing: "Writing",
124
- chainCategory_writing_desc: "Documentation, prose, technical writing, README and guides.",
125
- "chainCategory_general-low": "General (light)",
126
- "chainCategory_general-low_desc": "Small tasks that fit no other category.",
127
- "chainCategory_general-high": "General (standard)",
128
- "chainCategory_general-high_desc": "Standard features spanning a few files with known patterns.",
129
- chainCategory_artistry: "Artistry",
130
- chainCategory_artistry_desc: "Highly creative or artistic tasks, novel ideas, design exploration.",
131
- chainCategory_architect: "Architect",
132
- chainCategory_architect_desc: "Advisory architecture consult: boundaries, decomposition, trade-offs (read-only).",
133
- supervisionMaxRetries: "Child retry limit",
134
- supervisionMaxRetriesHint: "How many times a supervised child is continued when it ends without a report or keeps failing (default 5).",
135
- supervisionInitialBackoffMs: "Initial retry backoff (ms)",
136
- supervisionInitialBackoffMsHint: "Wait before the first retry; doubles each round (default 30000).",
137
- supervisionMaxBackoffMs: "Maximum retry backoff (ms)",
138
- supervisionMaxBackoffMsHint: "The retry wait never grows past this (default 300000).",
139
- todoEnabled: "Auto-continuation",
140
- todoEnabledHint: "With unfinished todos the assistant keeps going without waiting for your message (default on).",
141
- todoMaxConsecutive: "Continuation limit",
142
- todoMaxConsecutiveHint: "At most this many consecutive auto-continuations without your input (default 8).",
143
- todoErrorRetryMax: "Error retry limit",
144
- todoErrorRetryMaxHint: "How many times a provider error is retried automatically (default 5).",
145
- guardEnabled: "Context pressure guard",
146
- guardEnabledHint: "As the context fills up, asks the assistant to wrap up and requests compaction before it overflows; applies immediately.",
147
- guardSoftThreshold: "Advisory threshold",
148
- guardSoftThresholdHint: "Above this fill ratio the assistant is asked to wrap up (default 0.72; must stay below the compaction threshold).",
149
- guardHardThreshold: "Compaction threshold",
150
- guardHardThresholdHint: "Above this fill ratio compaction is requested (default 0.88; not a completion guarantee).",
151
- hashlineHideStockEdit: "Anchor editing only",
152
- hashlineHideStockEditHint: "Hides the built-in edit tool; file edits go through hash_edit anchors only.",
153
- editLockEnabled: "Edit Lock",
154
- editLockLabel: "Edit Lock",
155
- editLockTitle: "Files this session is editing",
156
- editLockPanelTitle: "Edit Lock",
157
- editLockLoading: "Loading…",
158
- editLockRefresh: "Refresh",
159
- editLockStop: "Revoke editing",
160
- editLockRevokeConfirm: "Revoke now — the assistant stops editing until you continue",
161
- editLockResume: "Continue editing",
162
- editLockRetry: "Retry connection",
163
- editLockRetryPending: "Retrying connection… Editing remains unavailable.",
164
- editLockBinding_serving: "This session is being edited in another attachment right now. Retry the connection when that turn finishes; retry does not continue editing.",
165
- editLockBinding_transferable: "This session's editing authority is held by an inactive attachment of this same session. It attaches here automatically when you send a message; Retry connection also takes it over now (retry does not continue editing).",
166
- editLockBinding_unknown: "The holder cannot be verified. Wait for its disconnect or confirmed process shutdown, then retry. Never remove a live publisher reservation.",
167
- "editLockBinding_cross-process": "The holder is in another process. Disconnect it or confirm that process has shut down before retrying.",
168
- "editLockBinding_revocation-failed": "Durable revocation was not acknowledged. Inspect Edit Lock maintenance; no replacement has been granted.",
169
- editLockConfirmAll: "Continue with these files",
170
- editLockReleaseAll: "Release all files now",
171
- editLockDetails: "Technical details",
172
- editLockOwnerOther: "Another session",
173
- editLockHoldUntil: "until {time}",
174
- editLockRecovery: "The last turn failed; cleaning up (attempt {n}).",
175
- editLockState_idle: "Not editing any file",
176
- editLockCleanupOnly: "Cleanup only: business edits and new ownership are blocked. Release files you no longer need; inspect the tool result before retrying edits.",
177
- editLockRecoveryUsage: "Recorded recovery: {attempts} attempts · {elapsed}s elapsed · {pause} min pause used.",
178
- editLockPauseUsageHint: "Pause usage is cumulative, not a live timer. Pause expiry re-checks recovery; it does not release locks or restore editing.",
179
- editLockPausedUntil: "Recovery paused until {time}.",
180
- editLockOwnershipHint: "Locks show ownership, not write outcomes. For failed edits, inspect the tool result; releasing locks does not undo changes.",
181
- editLockState_editing: "Editing",
182
- editLockState_holding: "Files kept for this session",
183
- editLockState_confirm: "Waiting for you to continue",
184
- editLockState_stopped: "Editing stopped",
185
- editLockState_attention: "Needs your attention",
186
- editLockState_revoked: "Editing revoked by an administrator",
187
- editLockRevokedHint: "An administrative recovery revoked this session's editing authority and released its locks. Continue editing here, or send any message — editing resumes automatically in a new execution epoch; the revocation record is preserved.",
188
- editLockColdRevokedAuto: "An administrative recovery revoked this session's editing authority and released its locks. Send any message in this session — the binding and editing resume automatically.",
189
- editLockColdRevokedManual: "An administrative recovery revoked this session's editing authority and released its locks. Send any message to activate the session, then continue editing from this panel.",
190
- editLockColdResumeAuto: "This session was restored after a restart and is stopped. Send any message — editing resumes automatically, with the files below confirmed again.",
191
- editLockColdResumeManual: "This session was restored after a restart and is stopped. Send any message to activate the session, then continue editing from this panel.",
192
- editLockState_unavailable: "Edit Lock is starting",
193
- editLockState_failed: "Edit Lock is unavailable; edits are refused",
194
- editLockStatus_active: "editing",
195
- "editLockStatus_user-interrupted": "stopped",
196
- "editLockStatus_pending-confirmation": "waiting",
197
- editLockStatus_abnormal: "needs attention",
198
- editLockRow_release: "Release",
199
- editLockRow_confirm: "Continue",
200
- editLockRow_unlock: "Unlock",
201
- editLockRow_unlockConfirm: "Unlock now — the other session loses this file",
202
- editLockEnabledHint: "Sessions take turns editing the same files instead of overwriting each other.",
203
- editLockOptOutWarning: "Edit Lock is set to off. After saving, restart DeepSeek Harness to apply the change. Once enforcement is off, ordinary editing is UNPROTECTED and can overwrite another session's work. Old fences and history are retained and may block files when you re-enable Edit Lock.",
204
- editLockAutoResume: "Message resumes editing",
205
- editLockAutoResumeHint: "After a session is stopped, sending any message restores its editing right and re-confirms its kept files (default on).",
206
- editLockStaleSweep: "Sweep stale locks",
207
- editLockStaleSweepHint: "Locks whose target file was deleted or moved are re-verified and released as you send messages (default on).",
208
- editLockMaint: "Edit Lock maintenance",
209
- editLockMaintHint: "Profile-wide enforcement status and read-only diagnostics.",
210
- editLockMaintFailed: "Edit Lock maintenance failed",
211
- editLockMaintLoading: "Loading…",
212
- editLockMaintUnavailable: "Maintenance data unavailable:",
213
- editLockMaintRetry: "Retry",
214
- editLockMaintRefresh: "Refresh",
215
- editLockMaintInspect: "Inspect",
216
- editLockMaintStateEnforced: "Enforced",
217
- editLockMaintStateEnforcedHint: "The switch is on and the Edit Lock manager is mounted in this process.",
218
- editLockMaintStateDisableRequested: "Disable requested — restart required",
219
- editLockMaintStateDisableRequestedHint: "You turned the switch off, but the manager is still mounted and enforcing. The change applies after restarting DeepSeek Harness.",
220
- editLockMaintStateEnableRequested: "Enable requested — restart required",
221
- editLockMaintStateEnableRequestedHint: "You turned the switch on, but no manager is mounted in this process. The change applies after restarting DeepSeek Harness.",
222
- editLockMaintStateDisabled: "Enforcement disabled",
223
- editLockMaintStateDisabledHint: "The switch is off and every recorded, fully installed row reports enforcement disabled.",
224
- editLockMaintStateUnknown: "Unknown",
225
- editLockMaintStateUnknownHint: "Mount evidence is absent, inconsistent, installing, disposing or failed. The saved value alone never proves enforcement or disablement.",
226
- editLockMaintRestart: "Applies after restarting DeepSeek Harness.",
227
- editLockMaintPinned: "This composition pins the Edit Lock row configuration; the settings switch does not govern it here.",
228
- editLockMaintScopeNote: "The switch is profile-wide: it covers every Weir session in this profile, not one workspace.",
229
- editLockMaintWarnKeepHistory: "Turning enforcement off does not clear unresolved operations, fences or history — turning it back on can block the same files again.",
230
- editLockMaintWarnUnlock: "An ordinary unlock frees one lock without validating content; it is not historical recovery and never settles an unknown publication.",
231
- editLockMaintOffRisk: "Edit Lock is not mounted. Ordinary edits are UNPROTECTED and can overwrite another session's work. Retained locks and fences do not block off-period edits; they may block files again after you re-enable and restart.",
232
- editLockMaintUnknownRisk: "Edit Lock mount status cannot be verified. If no manager is mounted, ordinary edits are UNPROTECTED and can overwrite another session's work. Do not treat retained fences as proof of current protection.",
233
- editLockMaintHistory: "Retained history — not current blocks",
234
- editLockMaintHistoryHint: "These old locks and publication fences remain on disk for inspection. Without a mounted manager they do not block ordinary edits; after re-enabling they may block files again. Online force release is unavailable here; separate offline administrator recovery remains available.",
235
- editLockMaintUnknownHistory: "Retained authority — current effect unverified",
236
- editLockMaintUnknownHistoryHint: "The saved value and old fences cannot establish whether a manager is mounted. Inspect this history read-only; online force release is unavailable until enforcement is verified. Separate offline administrator recovery remains available.",
237
- editLockMaintBlocked: "Initialization blocked",
238
- editLockMaintDomains: "Domains",
239
- editLockMaintNoDomains: "No live session reports an Edit Lock domain in this profile.",
240
- editLockMaintAuthorityYes: "authority present",
241
- editLockMaintAuthorityNo: "authority currently absent",
242
- editLockMaintReservation: "A publisher reservation is present: this or another Harness holds (or stranded) the publishing claim for this domain.",
243
- editLockMaintPresenceNone: "No authority directory is currently present. Prior initialization cannot be determined.",
244
- editLockMaintPresenceEmpty: "The authority directory is currently empty. Prior initialization cannot be determined.",
245
- editLockMaintPresenceJunk: "The authority directory has contents but no committed snapshot; the store would refuse to open it. Nothing was changed.",
246
- editLockMaintPresenceNotAFile: "snapshot.json is not a regular file; the store would refuse it. Nothing was changed.",
247
- editLockMaintPresenceCorrupt: "The authority image failed integrity validation and was left untouched — no automatic repair exists. Refusal:",
248
- editLockMaintPresenceUnreadable: "The authority could not be read:",
249
- editLockMaintCounts: "{sessions} session(s) · {locks} lock(s) · {operations} recorded operation(s)",
250
- editLockMaintUnresolved: "Unresolved operations",
251
- editLockMaintUnresolvedNone: "No unresolved operations.",
252
- editLockMaintRetained: "Retained locks (interrupted / abnormal / pending)",
253
- editLockMaintScopeFile: "one file",
254
- editLockMaintScopeSubtree: "a directory subtree",
255
- editLockMaintScopeDomain: "the whole work directory",
256
- editLockMaintScopeNone: "no recorded scope",
257
- editLockMaintRecoveries: "Online administrative recovery",
258
- editLockMaintRecoverHint: "Settle an interrupted owner's unknown publications in the running manager: one explicit click, no restart, no hash typing. The unknown outcome stays in history. If the scope changed since it was loaded, the manager refuses and the panel reloads it.",
259
- editLockMaintRecoverRoot: "Root",
260
- editLockMaintRecoverOwner: "Owner session",
261
- editLockMaintRecoverRevision: "Authority revision",
262
- editLockMaintRecoverOperations: "Unresolved operation IDs",
263
- editLockMaintRecoverRisk: "Risk you accept",
264
- editLockMaintRecoverDigest: "Confirmation digest",
265
- editLockMaintRecoverConfirm: "Settle this owner online",
266
- editLockMaintRecoverBusy: "Settling…",
267
- editLockMaintRecoverDone: "Settled at revision {revision}; admission is unblocked and the unknown outcome stays in history.",
268
- editLockMaintRecoverFailed: "Recovery not acknowledged:",
269
- worktreeEnabled: "Worktree lanes",
270
- worktreeEnabledHint: "Lets the assistant work in isolated git worktrees: lane tools, the /worktree command, and the lanes panel.",
271
- worktreeAutoSetup: "Auto-install in new lanes",
272
- worktreeAutoSetupHint: "Runs the repository's configured install command when a lane opens (default on).",
273
- worktreeMaxActive: "Active lane limit",
274
- worktreeMaxActiveHint: "At most this many active lanes per repository (default 4).",
275
- worktreeRoot: "Lane directory",
276
- worktreeRootHint: "Repository-relative directory holding lanes (default .weir/worktrees; locally git-ignored).",
277
- worktreeWatchTimeoutMinutes: "Lane watch timeout (minutes)",
278
- worktreeWatchTimeoutMinutesHint: "A lane-state watch expires with one notice after this long without a hit (default 360); existing watches keep their deadline.",
279
- worktreeAutoApprove: "Lane auto-approve",
280
- worktreeAutoApproveHint: "Default approval mode for new sessions: manual asks every time; auto-keep approves and keeps the branch; auto-clean also deletes it; /worktree approve overrides per session.",
281
- worktreeAutoApproveOptionManual: "manual",
282
- "worktreeAutoApproveOptionAuto-keep": "auto-keep",
283
- "worktreeAutoApproveOptionAuto-clean": "auto-clean",
284
- robashEnabled: "Read-only shell guard",
285
- robashEnabledHint: "Curated read-only agents (finder etc.) may only run allow-listed read-only commands (default on).",
286
- robashAllow: "Extra allowed commands",
287
- robashAllowHint: "Command names added on top of the built-in allow list; built-ins always apply, empty adds nothing.",
288
- robashGitAllow: "Extra allowed git subcommands",
289
- robashGitAllowHint: "Git subcommands added on top of the built-in list (shared with the pwsh gate); empty adds nothing.",
290
- robashDeny: "Extra denied commands",
291
- robashDenyHint: "Command names added on top of the built-in deny list; deny wins over allow.",
292
- robashPwshAllow: "Extra allowed pwsh commands",
293
- robashPwshAllowHint: "Additions to the Windows read-only pwsh allow list; built-ins always apply.",
294
- robashPwshDeny: "Extra denied pwsh commands",
295
- robashPwshDenyHint: "Additions to the Windows read-only pwsh deny list; deny wins over allow.",
296
- robashListEntries: "entries",
297
- robashListAdd: "Add entry",
298
- robashListInvalid: "The stored value is not a valid command list; the editor opened empty — saving replaces it.",
299
- robashListPanelHint: "One command name per row; entries are added to the built-in list, which always applies — an empty list adds nothing.",
300
- robashListEntryPlaceholder: "command name",
301
- lspEnabled: "LSP semantic tools",
302
- lspEnabledHint: "When on, each session can enable go-to-definition, find-references and friends from its composer switch (sessions start off).",
303
- lspServers: "Custom language servers",
304
- lspServersHint: "Add language servers beyond the built-in catalog, edited visually in the manager panel.",
305
- notifyEnabled: "System notifications",
306
- notifyEnabledHint: "Sends a system notification when a session needs you or a turn finishes (default on).",
307
- notifyOnComplete: "Notify on completion",
308
- notifyOnCompleteHint: "Notifies when a turn finishes and ran longer than the minimum below.",
309
- notifyOnAttention: "Notify when needed",
310
- notifyOnAttentionHint: "Notifies on approval requests, questions, plan reviews, and failed or stopped turns.",
311
- notifyMinTurnSeconds: "Minimum turn length (seconds)",
312
- notifyMinTurnSecondsHint: "A finished turn is only reported when it ran at least this long; 0 reports every turn (default 15).",
313
- notifySound: "Notification sound",
314
- notifySoundHint: "Plays the platform notification sound where supported.",
315
- notifyForeground: "When the window is in front",
316
- notifyForegroundHint: "Whether to notify while the window is in the foreground: don't notify (default) or always notify.",
317
- notifyForegroundOptionSkip: "Don't notify",
318
- notifyForegroundOptionAlways: "Always notify",
319
- notifyPermissions: "Notification permission",
320
- notifyPermissionsHint: "Check whether macOS lets these notifications through, and walk through allowing them.",
321
- notifyPermissionsOpen: "Manage",
322
- notifyPermTitle: "Notification permission",
323
- notifyPermDescription: "Notifications are shown by DeepSeek Harness itself, so macOS has to let DeepSeek Harness notify you.",
324
- notifyPermClose: "Close",
325
- notifyPermChecking: "Checking…",
326
- notifyPermRecheck: "Check again",
327
- notifyPermBestEffort: "This check reads macOS settings that Apple does not document, so treat it as a hint. Seeing the test notification is the real proof.",
328
- notifyPermFocusNote: "Focus / Do Not Disturb can still hold notifications back, and it cannot be checked from here.",
329
- notifyPermSendTest: "Send a test notification",
330
- notifyPermSending: "Sending…",
331
- notifyPermOpenSettings: "Open notification settings",
332
- notifyPermOpening: "Opening…",
333
- notifyPermOpenHint: "In the list, find “DeepSeek Harness”, turn on “Allow notifications”, and pick the Banners or Alerts style.",
334
- notifyPermWaiting: "Waiting for you to allow notifications… checking every 2 seconds.",
335
- notifyPermConfirm: "Did you see the test notification?",
336
- notifyPermSeenYes: "Yes, I saw it",
337
- notifyPermSeenNo: "No",
338
- notifyPermSeen: "All set — notifications will reach you.",
339
- notifyPermNotSeen: "Check that Focus / Do Not Disturb is off, that DeepSeek Harness's style is Banners or Alerts, and — if the window is in front — that \"When the window is in front\" is set to Always notify. Then try again.",
340
- notifyPermRetry: "Start over",
341
- notifyPermSendAgain: "Send another test",
342
- notifyPermError: "Something went wrong:",
343
- notifyPermManualPath: "You can do this by hand: System Settings → Notifications → DeepSeek Harness.",
344
- notifyPermDetails: "Technical details",
345
- notifyPermFailed: "The permission panel failed; check the runtime log.",
346
- "notifyPermState_granted": "Allowed",
347
- "notifyPermState_denied": "Not allowed",
348
- "notifyPermState_unknown": "Can't tell",
349
- "notifyPermReason_alerts-allowed": "Alerts are allowed for DeepSeek Harness.",
350
- "notifyPermReason_not-allowed": "Notifications are turned off for DeepSeek Harness.",
351
- "notifyPermReason_no-record": "macOS has no record of DeepSeek Harness yet. Send a test notification so it shows up in the list.",
352
- "notifyPermReason_default": "macOS has no explicit setting for DeepSeek Harness (it uses the system default), so this can't be told from here.",
353
- "notifyPermReason_unreadable": "The notification settings could not be read.",
354
- notifyWebUnsupported: "This page has no web Notification support, so DeepSeek Harness cannot notify directly.",
355
- notifyWebPermission: "Web notification permission",
356
- notifyWebDeniedHint: "This page was blocked from showing notifications and cannot ask again. Open System Settings → Notifications → DeepSeek Harness and turn notifications on.",
357
- "notifyWebPerm_granted": "Allowed",
358
- "notifyWebPerm_denied": "Blocked",
359
- "notifyWebPerm_default": "Not asked yet",
360
- lspManager: "Manage LSP services",
361
- lspManagerHint: "Check which language servers are installed and install the missing ones from the community catalog.",
362
- lspManagerLoading: "Loading…",
363
- lspManagerFailed: "The LSP manager failed; check the runtime log.",
364
- lspManagerUnavailable: "LSP management endpoints unavailable in this deployment:",
365
- lspManagerRetry: "Retry",
366
- lspManagerInstall: "Install",
367
- lspManagerCancel: "Cancel",
368
- lspManagerConfirmInstall: "Run install",
369
- lspManagerInstalling: "Installing…",
370
- lspManagerInstalled: "Installed",
371
- lspManagerMissing: "Not installed",
372
- lspManagerExitCode: "Exit code",
373
- lspManagerTimedOut: "(timed out)",
374
- lspManagerCustom: "Custom servers",
375
- lspManagerCustomHint: "Add your own language servers; saved with the settings and detected on the next status load.",
376
- lspManagerAddServer: "Add server",
377
- lspManagerRemove: "Remove",
378
- lspManagerFamily: "family name",
379
- lspManagerCommand: "command",
380
- lspManagerArgs: "args (space separated)",
381
- lspManagerInstallCmd: "install command (optional)",
382
- lspManagerPendingStatus: "detected after save",
383
- lspManagerInstallerMissing: "Installer unavailable: install it first, then retry.",
384
- lspManagerInvalidJson: "The stored custom-servers JSON is malformed; the panel opened with an empty list — saving replaces the stored value.",
385
- lspFamily_typescript: "TypeScript",
386
- lspFamily_python: "Python",
387
- lspFamily_go: "Go",
388
- lspFamily_rust: "Rust",
389
- lspFamily_json: "JSON",
390
- lspFamily_html: "HTML",
391
- lspFamily_css: "CSS",
392
- lspFamily_markdown: "Markdown",
393
- lspFamily_bash: "Bash",
394
- lspFamily_dockerfile: "Dockerfile",
395
- lspFamily_yaml: "YAML",
396
- lspFamily_lua: "Lua",
397
- lspFamily_cpp: "C/C++",
398
- lspToggleLabel: "LSP",
399
- lspToggleTitle: "Toggle LSP semantic tools for this session",
400
- worktreePillMode: "Worktree",
401
- worktreePillLanes: "Worktree",
402
- worktreePillCount: "{n} lane(s)",
403
- worktreePillAwaiting: "{n} awaiting approval",
404
- worktreePillTitle: "Worktree lanes — open the panel",
405
- worktreePillBaseMoved: "The main worktree left the lane base branch; check it out to land",
406
- worktreeModeLabel: "Worktree",
407
- worktreeModeTitle: "Optional discipline: lanes work without this mode. Turned on, the assistant stops editing files directly and every change goes through isolated lanes.",
408
- worktreeModeUnavailable: "Worktree mode unavailable:",
409
- worktreeApproveLabel: "Auto-approve",
410
- worktreeApproveTitle: "Lane auto-approve mode ({mode}): manual asks on every card; auto-keep merges/abandons without cards and removes the worktree but keeps the branch; auto-clean also deletes the branch. The new-session default lives in Settings › Worktree.",
411
- worktreeApproveOptionManual: "manual",
412
- worktreeApproveOptionAutoKeep: "keep",
413
- worktreeApproveOptionAutoClean: "clean",
414
- worktreeLoading: "Loading lanes…",
415
- worktreeLoadFailed: "The lane view could not be read.",
416
- worktreeUnavailable: "Worktree lanes are unavailable for this session.",
417
- worktreeDisabled: "Worktree lanes are switched off in Settings.",
418
- worktreeEmpty: "No active lanes. The assistant opens one with worktree_open.",
419
- worktreeEmptyTitle: "No active lanes",
420
- worktreeEmptyBody: "When the assistant needs an isolated workspace it opens one with worktree_open. Track checks, approve merges, and clean up here.",
421
- worktreeRefresh: "Refresh",
422
- worktreeConfigure: "Verification…",
423
- worktreeShowHistory: "History ({n})",
424
- worktreeHideHistory: "Hide history",
425
- worktreeVerificationOn: "verification: {n} command(s)",
426
- worktreeVerificationOff: "verification not enabled",
427
- worktreeExcludeOk: "locally ignored",
428
- worktreeExcludeMissing: "lane folder is not ignored yet",
429
- worktreeUnmanaged: "{n} worktree(s) under the lane folder are not managed by Weir",
430
- worktreeStaleData: "Showing the last data read; the refresh failed.",
431
- worktreeAheadBehind: "{ahead} ahead · {behind} behind",
432
- worktreeBaseMoved: "base moved",
433
- worktreeNextLabel: "next: {next}",
434
- worktreeViewDiff: "Changes",
435
- worktreeHideDiff: "Hide changes",
436
- worktreeDiffUnavailable: "changes unavailable",
437
- worktreeFiles: "{n} file(s)",
438
- worktreeExitCode: "exit {code}",
439
- worktreeNoChanges: "No changes against the base branch.",
440
- worktreeRecheck: "Re-check",
441
- worktreeRetrySetup: "Retry setup",
442
- worktreeSkipSetup: "Skip setup",
443
- worktreeLand: "Merge…",
444
- worktreeLandConfirm: "Confirm merge",
445
- worktreeAbandon: "Abandon…",
446
- worktreeAbandonConfirm: "Confirm abandon",
447
- worktreeCleanupWorktree: "Remove worktree",
448
- worktreeCleanupAll: "Remove worktree and branch",
449
- worktreeCleanupAllConfirm: "Confirm remove branch",
450
- worktreeCopyPath: "Copy path",
451
- worktreeActionUnavailable: "not available now",
452
- worktreeActionFailed: "This lane action is unavailable right now; try the /worktree command directly.",
453
- worktreeConflicts: "conflicts",
454
- worktreeMergeCommit: "merge commit",
455
- worktreeCleanup: "cleanup",
456
- worktreeConfigName: "name",
457
- worktreeConfigRun: "command",
458
- worktreeConfigChecks: "Verification commands",
459
- worktreeConfigSetup: "setup command (optional)",
460
- worktreeConfigAdd: "Add command",
461
- worktreeConfigRemove: "Remove",
462
- worktreeConfigSave: "Save",
463
- worktreeCancel: "Cancel",
464
- worktreeConfigHint: "Saved to this repository only (.weir/worktrees/.config.json, never committed). Commands run in a lane when it is checked.",
465
- worktreeInitParseFailed: "The repository configuration could not be read.",
466
- worktreeFlatInput: "Input",
467
- worktreeFlatOutput: "Output",
37
+ // Worktree lanes: only the strings the entry’s own synchronous surfaces
38
+ // read stay in this namespace — the sidebar tab type’s title/guide thunks
39
+ // and the lanes panel’s pre-arrival loading state. Every lazily rendered
40
+ // string (the header pill included: its wrapper renders nothing until the
41
+ // chunks arrive) lives in lib/client.worktree-model.js’s data face,
42
+ // registered under "settings.weir.worktree" on worktree-batch arrival.
43
+ // worktreeLoading is byte-identical in both homes — a documented
44
+ // cross-namespace duplicate (the panel’s pre-arrival state resolves it
45
+ // here, the chunk’s own loading row from its feature namespace).
468
46
  worktreeTabLabel: "Worktrees",
469
47
  worktreeGuideTitle: "Worktree lanes",
470
48
  worktreeGuideDescription: "Lanes for this session: state, checks, merge, cleanup.",
471
- worktreeState_preparing: "preparing",
472
- worktreeState_setup_failed: "setup failed",
473
- worktreeState_ready: "ready",
474
- worktreeState_working: "working",
475
- worktreeState_dirty: "uncommitted changes",
476
- worktreeState_no_commits: "no commits",
477
- worktreeState_branch_moved: "branch moved",
478
- worktreeState_checking: "checking",
479
- worktreeState_check_failed: "check failed",
480
- worktreeState_landable: "ready to merge",
481
- worktreeState_conflicted: "conflicts",
482
- worktreeState_awaiting_approval: "awaiting approval",
483
- worktreeState_declined: "merge declined",
484
- worktreeState_landed: "merged",
485
- worktreeState_kept: "kept",
486
- worktreeState_cleaned: "cleaned up",
487
- worktreeState_abandoned: "abandoned",
488
- worktreeTool_worktree_open: "Open worktree lane",
489
- worktreeTool_worktree_check: "Check worktree lane",
490
- worktreeTool_worktree_land: "Merge worktree lane",
491
- worktreeTool_worktree_cleanup: "Worktree cleanup",
492
- worktreeTool_worktree_abandon: "Abandon worktree lane",
493
- worktreeTool_worktree_watch: "Watch worktree lane",
494
- worktreeWatchStates: "Watching for",
495
- worktreeWatchExpires: "until {time}",
496
- worktreeWatchHit: "hit immediately",
497
- worktreeWatching: "{n} watching",
498
- worktreeNext_delegate: "assign a worker to this lane",
499
- worktreeNext_worktree_check: "check the lane",
500
- worktreeNext_worktree_land: "merge the lane (asks you to approve)",
501
- worktreeNext_worktree_cleanup: "choose the cleanup",
502
- worktreeWait_lane_ready: "waiting for dependency setup",
503
- worktreeWait_child_settle: "waiting for the lane worker",
504
- worktreeWait_check_complete: "waiting for verification",
505
- worktreeWait_user: "waiting for your decision",
506
- hashEditTitle: "Edit file",
507
- hashEditPreparing: "Preparing edit",
508
- hashEditPlanned: "Planned edit — the applied diff appears when the call settles.",
509
- hashEditRunning: "Editing…",
510
- hashEditFailed: "Edit failed",
511
- hashEditStopped: "Interrupted",
49
+ worktreeLoading: "Loading lanes…",
512
50
  hashEditInput: "Input",
513
51
  hashEditOutput: "Output",
514
- hashEditCodeLabel: "diff",
515
- hashEditCopy: "Copy",
516
- hashEditCopied: "Copied",
517
- hashEditWrap: "Wrap lines",
518
- hashEditUnwrap: "Disable line wrap",
519
- hashEditCollapse: "Collapse",
520
- hashEditCollapseAria: "Collapse diff",
521
- hashEditExpand: "Show {count} more",
522
- hashEditExpandAria: "Expand {count} more rows",
523
52
  // Session capability Badge + manager (12.x, D3/D4): the chunks carry
524
53
  // the same strings as in-code fallbacks; these rows translate them.
525
54
  capabilityTabLabel: "Capabilities",
526
55
  capabilityGuideTitle: "Capabilities",
527
56
  capabilityGuideDescription: "Skills, MCP servers, and presets for this session.",
528
- "capability.badge": "{skills} skills · {mcp} MCP",
529
- "capability.unavailable.short": "Capabilities n/a",
530
- "capability.effectiveUnknown": "Applied count unknown — refresh and check Skill sources",
531
- "capability.effectiveUnknownShort": "Skills ? · MCP ?",
532
- "capability.effectiveUnknownDetail": "Accepted revision; effective capabilities cannot be verified. Refresh and check Skill sources. Draft kept; only Apply changes the session.",
533
- "capability.unknownOverwriteRisk": "Previous selection is unknown. Applying this draft may replace other accepted Skills and MCP servers. Review the full selection before confirming.",
534
- "capability.confirmUnknownOverwrite": "Confirm replacing unknown selection",
535
57
  "capability.loading": "Loading capabilities…",
536
- "capability.error": "Capabilities unavailable for this session.",
537
- "capability.unavailable": "Capabilities are unavailable in this session.",
538
- "capability.unsupported": "Unsupported: consistency conditions are not met on this host.",
539
- "capability.tab.skills": "Skills",
540
- "capability.tab.mcp": "MCP",
541
- "capability.tab.presets": "Presets",
542
- "capability.search": "Search",
543
- "capability.close": "Close",
544
- "capability.conflict": "conflict",
545
- "capability.sourceUnknown": "unknown source",
546
- "capability.sourceNumber": " · source ",
547
- "capability.sameNameWarning": "{name}: only one source can be enabled in this session. Uncheck one: {sources}.",
548
- "capability.unresolvedNameWarning": "{name}: legacy name has no chosen source. Choose an exact source or remove the name: {sources}.",
549
- "capability.unknownLegacyName": "{name}: no matching Skill in the current listing. Refresh the listing or remove this legacy name.",
550
- "capability.inventoryUnavailableName": "The listing is unavailable; legacy names remain unresolved in the draft. Retry later; no source was selected.",
551
- "capability.unresolvedNameTitle": "Choose a source for legacy name {name}",
552
- "capability.replaceName": "Replace {name} with {source}",
553
- "capability.removeName": "Remove legacy name {name}",
554
- "capability.serverSameName": "Server rejected same-name Skill {names}. Uncheck one source, or refresh the listing; draft kept.",
555
- "capability.serverMissing": "Server could not resolve {names}. Refresh the listing and choose an exact source or remove the name; draft kept.",
556
- "capability.unknownName": "unknown name",
557
- "capability.missing": "missing",
558
- "capability.noSkills": "No skills match.",
559
- "capability.mcp.groupManaged": "Weir managed",
560
- "capability.mcp.groupUnmanaged": "Unmanaged",
561
- "capability.mcp.none": "No MCP servers configured.",
562
- "capability.mcp.unmanagedHint": "Configured outside Weir; the selection cannot govern it.",
563
- "capability.mcp.stateMounted": "mounted",
564
- "capability.mcp.stateRegistered": "registered",
565
- "capability.unmanaged": "unmanaged",
566
- "capability.mcp.add": "+ Add managed MCP server",
567
- "capability.mcp.identity": "identity (e.g. my-docs)",
568
- "capability.mcp.label": "label (display name, optional)",
569
- "capability.mcp.command": "command (e.g. npx)",
570
- "capability.mcp.args": "args, space-separated (optional)",
571
- "capability.mcp.adding": "Adding…",
572
- "capability.mcp.addConfirm": "Add",
573
- "capability.mcp.cancel": "Cancel",
574
- "capability.mcp.errorRequired": "Required.",
575
- "capability.mcp.errorIdentityInvalid": "Letters, digits, \"-\" and \"_\" only; start with a letter or digit.",
576
- "capability.diff.addSkills": "+{n} skills",
577
- "capability.diff.removeSkills": "−{n} skills",
578
- "capability.diff.addMcp": "+{n} MCP",
579
- "capability.diff.removeMcp": "−{n} MCP",
580
- "capability.apply": "Apply",
581
- "capability.applying": "Applying…",
582
- "capability.discard": "Discard",
583
- "capability.applied": "Applied",
584
- "capability.acceptedUnknown": "Accepted · effective count unknown",
585
- "capability.appliedSkipped": "skipped {n} (not applicable here)",
586
- "capability.failed": "Failed — draft kept",
587
- "capability.conflictState": "Changed elsewhere — review current state",
588
- "capability.missingAction": "Missing items need install/configure",
589
- "capability.pending": "Result pending — query the receipt",
590
- "capability.presets.unavailable": "Presets are unavailable on this host.",
591
- "capability.presets.errorName": "Enter a name.",
592
- "capability.presets.saved": "Preset saved.",
593
- "capability.presets.replaced": "Replaced the confirmed preset under ID {id}; no second preset was created.",
594
- "capability.presets.renameRow": "Rename preset…",
595
- "capability.presets.resaveRow": "Re-save…",
596
- "capability.presets.newName": "New preset name",
597
- "capability.presets.renameSubmit": "Save new name",
598
- "capability.presets.resaveSubmit": "Confirm re-save",
599
- "capability.presets.editTarget": "Target: {name} · {scope} · ID {id} · revision {revision}",
600
- "capability.presets.resaveConfirm": "Overwrite this preset from {source}: {skills} Skills · {mcp} MCP · {unresolved} unresolved. Current session stays unchanged.",
601
- "capability.presets.renamed": "Preset renamed; current draft and applied selection unchanged.",
602
- "capability.presets.resaved": "Preset re-saved; current draft and applied selection unchanged.",
603
- "capability.presets.renameCollision": "That name belongs to another preset. Choose another name.",
604
- "capability.presets.editConflict": "The preset changed. Review the refreshed row and confirm again.",
605
- "capability.presets.sourceChanged": "The applied selection changed. Refresh the session receipt and confirm again.",
606
- "capability.presets.sourceUnavailable": "Applied source unavailable{missing}. Restore the missing Skills, refresh the receipt, and confirm again.",
607
- "capability.presets.appliedUnavailable": "The applied source has unavailable entries. Restore them and refresh the session receipt before re-saving.",
608
- "capability.presets.appliedReceiptMissing": "The applied source cannot be verified from this receipt. Refresh the session receipt before re-saving; the current draft is still available.",
609
- "capability.presets.locked": "Preset storage is busy. Wait, then refresh and decide again.",
610
- "capability.presets.unreadable": "Preset storage cannot be read safely. Check the storage before retrying.",
611
- "capability.presets.unsupported": "This preset version is unsupported. Update the client or host before editing.",
612
- "capability.presets.gone": "This preset was deleted or is missing. Refresh the list; it was not recreated.",
613
- "capability.presets.confirmAgain": "The replacement target changed. Refresh and confirm its identity again.",
614
- "capability.presets.uncertain": "Result unknown. Refresh and inspect the preset before deciding whether to retry.",
615
- "capability.presets.missingSelection": "The draft selection is incomplete. Refresh before saving.",
616
- "capability.presets.replaceTarget": "Replace preset ID {id} at revision {revision} in {scope}?",
617
- "capability.presets.noneKnown": "none reported",
618
- "capability.presets.importPartial": "Installed Skills: {names}. Preset status is unconfirmed. Inspect the installed files and refresh the preset before deciding how to recover.",
619
- "capability.presets.currentRevision": " Current stored revision: {revision}.",
620
- "capability.presets.revisionConflict": "Changed elsewhere — the list was refreshed.",
621
- "capability.presets.noWorkspace": "This session has no workspace.",
622
- "capability.presets.saveFailed": "The preset could not be saved.",
623
- "capability.presets.loaded": "Staged into the draft — Apply to activate.",
624
- "capability.presets.loadedUnresolved": "Staged into the draft — {n} unresolved ref(s) reported.",
625
- "capability.presets.loadFailed": "Load failed — the preset may be gone.",
626
- "capability.presets.deleted": "Preset deleted.",
627
- "capability.presets.deleteFailed": "Delete failed.",
628
- "capability.presets.exportFailed": "Export failed.",
629
- "capability.presets.imported": "Imported: {bound} MCP binding(s), {unresolved} unresolved ref(s).",
630
- "capability.presets.counts": "{skills} skills · {mcp} MCP",
631
- "capability.presets.countsUnresolved": " · {n} unresolved",
632
- "capability.presets.loading": "Loading…",
633
- "capability.presets.load": "Load",
634
- "capability.presets.export": "Export",
635
- "capability.presets.delete": "Delete",
636
- "capability.presets.deleteConfirm": "Delete preset \"{name}\"? This cannot be undone.",
637
- "capability.presets.deleteConfirmButton": "Delete preset",
638
- "capability.presets.deleting": "Deleting…",
639
- "capability.presets.cancel": "Cancel",
640
- "capability.presets.exportLabel": "Preset JSON",
641
- "capability.presets.copy": "Copy to clipboard",
642
- "capability.presets.copied": "Copied",
643
- "capability.presets.close": "Close",
644
- "capability.presets.saveOpen": "Save as preset…",
645
- "capability.presets.importOpen": "Import…",
646
- "capability.presets.name": "Preset name",
647
- "capability.presets.namespace": "Namespace",
648
- "capability.presets.scopeWorkspace": "workspace",
649
- "capability.presets.scopeGlobal": "global",
650
- "capability.presets.source": "From",
651
- "capability.presets.fromDraft": "current draft",
652
- "capability.presets.fromApplied": "applied selection",
653
- "capability.presets.nameConflict": "A preset named \"{name}\" already exists in this namespace.",
654
- "capability.presets.rename": "Rename…",
655
- "capability.presets.renameHint": "Edit the name, then save again.",
656
- "capability.presets.replace": "Replace it",
657
- "capability.presets.saving": "Saving…",
658
- "capability.presets.save": "Save preset",
659
- "capability.presets.importPlaceholder": "Paste a portable preset document (JSON)…",
660
- "capability.presets.importing": "Importing…",
661
- "capability.presets.importSubmit": "Import",
662
- "capability.presets.importInvalidJson": "Not valid JSON — nothing was written.",
663
- "capability.presets.importRejected": "Rejected: {reason} — nothing was written.",
664
- "capability.presets.importNameConflict": "A preset with this name already exists here.",
665
- "capability.presets.importFailed": "Import failed — nothing was written.",
666
- "capability.presets.groupWorkspace": "Workspace presets",
667
- "capability.presets.groupWorkspaceNone": "Workspace presets (no workspace)",
668
- "capability.presets.groupGlobal": "Global presets",
669
- "capability.presets.emptyWorkspace": "No workspace presets yet.",
670
- "capability.presets.emptyGlobal": "No global presets yet.",
671
- "capability.presets.defaultTitle": "Workspace default for new sessions",
672
- "capability.presets.defaultUnavailable": "The workspace default is unavailable.",
673
- "capability.presets.defaultNone": "No default is set — new sessions use the builtin baseline.",
674
- "capability.presets.defaultEmpty": "An explicit empty default is set: new sessions start with 0 skills · 0 MCP.",
675
- "capability.presets.defaultEntries": "Default: {counts}",
676
- "capability.presets.defaultUnresolved": "…with {n} unresolved ref(s) reported on resolve.",
677
- "capability.presets.defaultSaveOpen": "Save as default…",
678
- "capability.presets.defaultClearOpen": "Clear default…",
679
- "capability.presets.defaultSaveConfirm": "Save {counts} as this workspace's default? New sessions in this workspace will start from it; the current session does not change.",
680
- "capability.presets.defaultSaveConfirmButton": "Save default",
681
- "capability.presets.defaultSaved": "Workspace default saved.",
682
- "capability.presets.defaultSaveFailed": "The default could not be saved.",
683
- "capability.presets.defaultClearConfirm": "Clear the workspace default? New sessions return to the builtin baseline; open sessions do not change.",
684
- "capability.presets.defaultClearConfirmButton": "Clear default",
685
- "capability.presets.defaultCleared": "Workspace default cleared — new sessions use the builtin baseline.",
686
- "capability.presets.defaultClearFailed": "The default could not be cleared.",
687
- "capability.presets.clearing": "Clearing…",
688
- "capability.presets.needsReceipt": "Unavailable until the session receipt loads.",
689
- "capability.presets.exportDownload": "Download .json",
690
- "capability.presets.downloaded": "Downloaded",
691
- "capability.presets.importedPackage": "Imported: {installed} Skill(s) installed, {bound} MCP binding(s), {unresolved} unresolved ref(s).",
692
- "capability.presets.importSummaryTitle": "Import summary — review before anything is written",
693
- "capability.presets.importFiles": "{n} file(s)",
694
- "capability.presets.importNoInstalls": "This package bundles no Skills to install.",
695
- "capability.presets.importUnresolvedTitle": "Unresolved refs — not installed:",
696
- "capability.presets.importCollision": "name collision",
697
- "capability.presets.importCollisionDecision": "When a bundled Skill name already exists:",
698
- "capability.presets.collisionCancel": "skip it (default)",
699
- "capability.presets.collisionReplace": "replace it",
700
- "capability.presets.collisionCoexist": "keep both, renamed",
701
- "capability.presets.importConfirm": "Confirm import",
702
- "capability.presets.importResultTitle": "Import result",
703
- "capability.presets.importInstalledNote": "Installed Skills stay unselected — pick them in the draft and Apply to activate.",
704
- "capability.presets.importInstallFailed": "Installation failed: {reason} — rolled back {n} file(s); no preset was created.",
705
- "capability.presets.importNoTargetRoot": "No {scope} Skill root is available on this host — nothing was installed.",
706
- "capability.presets.scopeProject": "project",
707
- "capability.presets.scopeUser": "user",
708
58
  // Session blackboard (slice 2): the right-sidebar panel's tab, list,
709
59
  // detail and editor strings. Type labels are short semantic names,
710
60
  // translated per locale.
@@ -712,811 +62,39 @@ window.__ModuleLoader__.load({
712
62
  blackboardGuideTitle: "Session blackboard",
713
63
  blackboardGuideDescription: "Findings shared across this session: entries, usage counts, arbitrated editing.",
714
64
  blackboardPillTitle: "Open the session blackboard",
715
- "blackboard.title": "Blackboard",
716
- "blackboard.entries": "{n} entries",
717
65
  "blackboard.loading": "Loading the board…",
718
- "blackboard.unavailable": "Blackboard unavailable for this session.",
719
- "blackboard.parentBoard": "Showing the parent conversation's board.",
720
- "blackboard.retry": "Retry",
721
- "blackboard.empty": "The board is empty.",
722
- "blackboard.emptyDesc": "Findings agents write to this session's board appear here.",
723
- "blackboard.noMatch": "No entries match.",
724
- "blackboard.search": "Search",
725
- "blackboard.new": "New entry",
726
- "blackboard.refresh": "Refresh",
727
- "blackboard.back": "Back",
728
- "blackboard.dismiss": "Dismiss",
729
- "blackboard.filterAll": "All",
730
- "blackboard.type.map": "map",
731
- "blackboard.type.contract": "contract",
732
- "blackboard.type.deadend": "dead end",
733
- "blackboard.type.wiring": "wiring",
734
- "blackboard.type.recipe": "recipe",
735
- "blackboard.type.why": "why",
736
- "blackboard.rowMeta": "{read} reads · {watching} watching",
737
- "blackboard.updated": "updated {time}",
738
- "blackboard.summary": "Summary",
739
- "blackboard.content": "Content",
740
- "blackboard.gone": "This entry is gone.",
741
- "blackboard.goneDesc": "It was deleted from the board (possibly by another writer).",
742
- "blackboard.error": "The entry could not be loaded.",
743
- "blackboard.edit": "Edit",
744
- "blackboard.delete": "Delete",
745
- "blackboard.deleting": "Deleting…",
746
- "blackboard.deleted": "Entry deleted.",
747
- "blackboard.deleteConfirm": "Delete this entry? The write authority is consumed.",
748
- "blackboard.contention": "Write authority is held by {holder}.",
749
- "blackboard.watch": "Notify me when free",
750
- "blackboard.watching": "watching {key}",
751
- "blackboard.watchingState": "watching…",
752
- "blackboard.released": "Key free — you hold the write authority.",
753
- "blackboard.editorNew": "New entry",
754
- "blackboard.formKey": "Key",
755
- "blackboard.formType": "Type",
756
- "blackboard.formRequired": "Required.",
757
- "blackboard.formKeyInvalid": "Letters, digits and . _ - / only; start with a letter or digit.",
758
- "blackboard.formSummaryPlaceholder": "One or two sentences: the finding, what it cost, how to verify it",
759
- "blackboard.save": "Save",
760
- "blackboard.saving": "Saving…",
761
- "blackboard.cancel": "Cancel",
762
- "blackboard.saved": "Saved (revision {n}).",
763
- "blackboard.created": "Entry created.",
764
- "blackboard.applying": "Acquiring write authority…",
765
- "blackboard.reacquire": "Re-acquire",
766
- "blackboard.tokenHeld": "write authority {time}",
767
- "blackboard.tokenExpired": "Write authority expired — re-acquire before saving.",
768
- "blackboard.tokenExpiredShort": "write authority expired",
769
- // Session blackboard (slice 3): the promotion-evaluation button and
770
- // the promoted read-only marker.
771
- "blackboard.promote": "Evaluate for promotion",
772
- "blackboard.promoteDisabled": "Every entry is already promoted — nothing to evaluate.",
773
- "blackboard.promotionRequested": "The main agent received the promotion-evaluation request.",
774
- "blackboard.promoted": "promoted",
775
- "blackboard.promotedTo": "promoted → {destination}",
776
- "blackboard.promotedReadonly": "This entry is promoted and read-only.",
777
- "blackboard.promotedReadonlyDetail": "Promoted entries are read-only: the durable copy lives in the target document, this board copy preserves the session references."
778
66
  };
779
67
  const zh = {
780
68
  title: "Weir",
781
- description: "Weir 预设的一站式配置:意图分类、自动续推、上下文压力、文件编辑、Worktree 车道、只读命令行、LSP 与系统通知;模型路由为独立页面。",
782
69
  routingTitle: "Weir 模型路由",
783
- routingDescription: "委派给子代理的模型:按任务类别或精选代理指定,可设备选按序回退。",
784
70
  loading: "正在加载 Weir 设置…",
785
71
  loadFailed: "Weir 设置加载失败:",
786
- unavailable: "此插件未加载,当前无法配置。",
787
- readOnly: "此部署的设置为只读。",
788
- saveFailed: "部署未接受这些值,已保留供你修正。",
789
- save: "保存",
790
- saving: "保存中…",
791
- pendingChanges: "{n} 项未保存的更改",
792
- discardChanges: "放弃更改",
793
- overridden: "已覆盖",
794
- reset: "恢复默认",
795
- restartRequired: "需重启",
796
- invalidValue: "请输入该字段接受的值,或留空以使用默认值。",
797
- restartReminderTitle: "重启后生效",
798
- restartReminderBody: "以下设置已更改,重启 DeepSeek Harness 后才会生效;本次保存的其它改动已即时生效。",
799
- restartReminderDismiss: "知道了",
800
- restartReminderAcknowledge: "知道了",
801
- catalogLoading: "正在加载 provider…",
802
- pickerModel: "模型",
803
- pickerEffort: "推理",
804
- effortProviderDefault: "跟随 provider 默认",
805
- catalogFailed: "Provider 目录不可用;可手动填写 provider 与模型。",
806
- providerEmpty: "选择 provider",
807
- modelEmpty: "选择模型",
808
- pickerUnavailable: "模型选择器不可用——请重新加载设置页后重试。",
809
- groupIntent: "意图分类",
810
- groupTodo: "自动续推",
811
- groupGuard: "上下文压力",
812
- groupEditing: "文件编辑",
813
- groupWorktree: "Worktree 车道",
814
- groupRobash: "只读命令行",
815
- groupLsp: "LSP 语义工具",
816
- groupNotify: "系统通知",
817
- groupRoutingCategories: "任务类别",
818
- groupRoutingAgents: "精选代理",
819
- groupRoutingSupervision: "监督与重试",
820
- intentGateClassifierOptionRegex: "regex(规则)",
821
- intentGateClassifierOptionLlm: "llm(语义)",
822
- intentGateClassifierOptionJev: "jev(实验)",
823
- intentGateClassifier: "意图分类器",
824
- intentGateClassifierHint: "如何识别每条消息的意图:regex 用内置规则,零成本(默认);llm 用独立小模型做语义分类;jev 为实验实现。",
825
- intentGateProvider: "分类器模型(llm 模式)",
826
- intentGateProviderHint: "为语义分类单独指定的模型;留空跟随会话当前模型。",
827
- intentGateModel: "分类器模型名(llm 模式)",
828
- intentGateModelHint: "留空跟随会话路由所用模型。",
829
- intentGateReasoningEffort: "分类器推理档位(llm 模式)",
830
- intentGateReasoningEffortHint: "留空跟随模型默认。",
831
- intentGateTimeoutMs: "分类超时(毫秒)",
832
- intentGateTimeoutMsHint: "超过该时长按规则分类结果继续,不阻塞消息(默认 1500)。",
833
- jevEndpoint: "Jev 端点",
834
- jevEndpointHint: "Jev 决策服务地址(实验模式)。",
835
- jevModel: "Jev 模型",
836
- jevModelHint: "Jev 使用的模型名(默认 jev)。",
837
- jevApiKeyEnv: "Jev 密钥环境变量名",
838
- jevApiKeyEnvHint: "存放 Jev API 密钥的环境变量名;密钥本身不写入配置。",
839
- delegateCategoryChains: "任务类别模型",
840
- delegateCategoryChainsHint: "每类任务委派给子代理时使用的模型;可添加备选按序回退,留空跟随会话模型。",
841
- delegateAgentChains: "精选代理模型",
842
- delegateAgentChainsHint: "finder、scholar、advisor 各自运行的模型;留空继承调用方路由。",
843
- delegateDisabledCategories: "停用任务类别",
844
- delegateDisabledCategoriesHint: "停用的类别从委派清单中移除,助手无法再委派这类任务。",
845
- disabledCategoriesCount: "个已停用",
846
- disabledCategoriesPanelHint: "每个类别一个开关;保存只写入打开的类别,全部关闭即不停用任何类别。",
847
- disabledCategoriesInvalid: "已保存的值不是有效的类别清单;编辑器已以全部关闭打开,保存将覆盖该值。",
848
- chainAgent_finder: "finder(检索)",
849
- chainAgent_finder_desc: "代码库上下文检索:回答「X 在哪里」「做 Z 的代码在哪」。只读、快速、并行优先。",
850
- chainAgent_scholar: "scholar(调研)",
851
- chainAgent_scholar_desc: "文档与 OSS 调研:官方文档、库 API、最佳实践、真实用法。只读。",
852
- chainAgent_advisor: "advisor(架构)",
853
- chainAgent_advisor_desc: "架构与设计顾问:模块边界、拆分、权衡。只读、高推理。",
854
- chainAgentPanelHint: "每个精选代理一行;留空继承调用方路由,备选按序回退。",
855
- chainEdit: "编辑",
856
- chainPanelHint: "每个类别一行:点「编辑」挑选模型,可添加备选按序回退;留空的类别跟随会话模型。",
857
- chainSave: "保存",
858
- chainCancel: "取消",
859
- chainAddRung: "添加备选",
860
- chainRemove: "删除",
861
- chainClear: "清空(跟随会话)",
862
- chainCategory_quick: "quick(快活)",
863
- chainCategory_quick_desc: "机械性小活:单文件修改、错别字、样板代码。",
864
- chainCategory_deep: "deep(攻坚)",
865
- chainCategory_deep_desc: "一个目标一个交付物:调试、跨模块、微妙逻辑。",
866
- "chainCategory_deep-plus": "deep-plus(升级)",
867
- "chainCategory_deep-plus_desc": "升级车道:证据无法定夺的权衡、契约、不变量。",
868
- chainCategory_visual: "visual(视觉)",
869
- chainCategory_visual_desc: "前端、UI/UX、样式、动画、布局。",
870
- chainCategory_writing: "writing(写作)",
871
- chainCategory_writing_desc: "文档、散文、技术写作、README 与指南。",
872
- "chainCategory_general-low": "general-low(通用·轻量)",
873
- "chainCategory_general-low_desc": "不属于任何专业类别的小任务。",
874
- "chainCategory_general-high": "general-high(通用·标准)",
875
- "chainCategory_general-high_desc": "跨几个文件、有既定模式的标准特性。",
876
- chainCategory_artistry: "artistry(艺术)",
877
- chainCategory_artistry_desc: "高度创意或艺术性任务、新颖想法、设计探索。",
878
- chainCategory_architect: "architect(架构)",
879
- chainCategory_architect_desc: "咨询式架构评估:模块边界、拆分、权衡(只读)。",
880
- supervisionMaxRetries: "子代理续推上限",
881
- supervisionMaxRetriesHint: "受监督子代理未交结果或连续出错时,最多自动续推几次(默认 5)。",
882
- supervisionInitialBackoffMs: "重试初始间隔(毫秒)",
883
- supervisionInitialBackoffMsHint: "首次重试前的等待时间,之后逐次加倍(默认 30000)。",
884
- supervisionMaxBackoffMs: "重试间隔上限(毫秒)",
885
- supervisionMaxBackoffMsHint: "重试间隔最多增长到该值(默认 300000)。",
886
- todoEnabled: "自动续推",
887
- todoEnabledHint: "有待办未完成时,助手自动继续推进,无需你发消息(默认开启)。",
888
- todoMaxConsecutive: "连续续推上限",
889
- todoMaxConsecutiveHint: "没有你输入时最多连续自动续推几轮(默认 8)。",
890
- todoErrorRetryMax: "出错重试上限",
891
- todoErrorRetryMaxHint: "模型供应商报错时最多自动重试几次(默认 5)。",
892
- guardEnabled: "上下文压力守卫",
893
- guardEnabledHint: "上下文将满时提醒助手收尾并请求压缩,避免超限报错;即时生效。",
894
- guardSoftThreshold: "提醒阈值",
895
- guardSoftThresholdHint: "上下文用量超过该比例时提醒助手收尾(默认 0.72,须小于压缩阈值)。",
896
- guardHardThreshold: "压缩阈值",
897
- guardHardThresholdHint: "上下文用量超过该比例时请求立即压缩(默认 0.88,不保证压缩完成)。",
898
- hashlineHideStockEdit: "仅用锚点编辑",
899
- hashlineHideStockEditHint: "隐藏内置 edit 工具,文件修改一律走 hash_edit 锚点编辑。",
900
- editLockEnabled: "编辑锁",
901
- editLockLabel: "编辑锁",
902
- editLockTitle: "本会话正在编辑的文件",
903
- editLockPanelTitle: "编辑锁",
904
- editLockLoading: "加载中…",
905
- editLockRefresh: "刷新",
906
- editLockStop: "收回编辑权",
907
- editLockRevokeConfirm: "确认收回——助手将停止编辑,直到你点继续",
908
- editLockResume: "继续编辑",
909
- editLockRetry: "重试连接",
910
- editLockRetryPending: "正在重试连接……编辑仍不可用。",
911
- editLockBinding_serving: "本会话正在另一个附着位置编辑中。请在该回合结束后重试连接;重试不等于继续编辑。",
912
- editLockBinding_transferable: "本会话的编辑权由同一会话的一个不活跃附着持有。你发送下一条消息时会自动接管;也可以立即点「重试连接」接管(重试不等于继续编辑)。",
913
- editLockBinding_unknown: "无法核实原持有者。请等待原连接断开或确认其进程已退出,再重试;勿删除存活 publisher 的预约。",
914
- "editLockBinding_cross-process": "原持有者位于另一进程。请先断开原连接或确认其进程已退出,再重试。",
915
- "editLockBinding_revocation-failed": "持久撤权尚未确认。请查看编辑锁维护;未授予替代绑定权限。",
916
- editLockConfirmAll: "继续编辑这些文件",
917
- editLockReleaseAll: "立即释放全部文件",
918
- editLockDetails: "技术细节",
919
- editLockOwnerOther: "其他会话",
920
- editLockHoldUntil: "保留至 {time}",
921
- editLockRecovery: "上一回合出错,正在清理(第 {n} 次)。",
922
- editLockState_idle: "未占用任何文件",
923
- editLockCleanupOnly: "仅允许清理:业务编辑和新占用都被拒绝。请释放不再需要的文件,重试前查看工具结果。",
924
- editLockRecoveryUsage: "已记录恢复:{attempts} 次 · 已用 {elapsed} 秒 · 已暂停 {pause} 分钟。",
925
- editLockPauseUsageHint: "暂停时长是累计用量,不是当前倒计时。暂停到期只会重新检查恢复,不释放锁,也不恢复编辑。",
926
- editLockPausedUntil: "恢复已暂停,至 {time} 后重新检查。",
927
- editLockOwnershipHint: "锁只表示归属,不表示写入结果。编辑失败请查看工具结果;释放锁不会撤销已发生的修改。",
928
- editLockState_editing: "正在编辑",
929
- editLockState_holding: "文件为本会话保留",
930
- editLockState_confirm: "等你确认继续",
931
- editLockState_stopped: "编辑已停止",
932
- editLockState_attention: "需要你处理",
933
- editLockState_revoked: "编辑权已被管理员吊销",
934
- editLockRevokedHint: "管理员恢复已吊销本会话的编辑权并释放其锁。点击「继续编辑」或发送任意消息,即在新执行纪元恢复编辑;吊销记录保留。",
935
- editLockColdRevokedAuto: "管理员恢复已吊销本会话的编辑权并释放其锁。在本会话发送任意消息——连接与编辑会自动恢复。",
936
- editLockColdRevokedManual: "管理员恢复已吊销本会话的编辑权并释放其锁。发送任意消息激活会话,然后回到此面板点「继续编辑」。",
937
- editLockColdResumeAuto: "重启后恢复的会话,编辑已停止。发送任意消息即自动恢复编辑(下列文件会一并确认)。",
938
- editLockColdResumeManual: "重启后恢复的会话,编辑已停止。发送任意消息激活会话,然后回到此面板点「继续编辑」。",
939
- editLockState_unavailable: "编辑锁启动中",
940
- editLockState_failed: "编辑锁不可用,编辑会被拒绝",
941
- editLockStatus_active: "编辑中",
942
- "editLockStatus_user-interrupted": "已停止",
943
- "editLockStatus_pending-confirmation": "待确认",
944
- editLockStatus_abnormal: "需处理",
945
- editLockRow_release: "释放",
946
- editLockRow_confirm: "继续",
947
- editLockRow_unlock: "解锁",
948
- editLockRow_unlockConfirm: "确认解锁——对方会失去这个文件",
949
- editLockEnabledHint: "多个会话轮流编辑同一批文件,而不是互相覆盖。",
950
- editLockOptOutWarning: "编辑锁已设为关闭。保存后须重启 DeepSeek Harness 才会生效。停用强制执行后,普通编辑不受保护,可能覆盖其他会话的工作。旧围栏与历史仍会保留,重新启用编辑锁时可能再次阻塞文件。",
951
- editLockAutoResume: "发消息即恢复编辑",
952
- editLockAutoResumeHint: "会话被停止后,发送任意消息即自动恢复其编辑权并确认保留的文件(默认开启)。",
953
- editLockStaleSweep: "自动清理失效锁",
954
- editLockStaleSweepHint: "目标文件已被删除或移动的锁,在你发消息时自动复核并释放(默认开启)。",
955
- editLockMaint: "编辑锁维护",
956
- editLockMaintHint: "查看全 profile 的强制执行状态与只读诊断。",
957
- editLockMaintFailed: "编辑锁维护面板加载失败",
958
- editLockMaintLoading: "加载中……",
959
- editLockMaintUnavailable: "维护数据不可用:",
960
- editLockMaintRetry: "重试",
961
- editLockMaintRefresh: "刷新",
962
- editLockMaintInspect: "检查",
963
- editLockMaintStateEnforced: "强制执行中",
964
- editLockMaintStateEnforcedHint: "开关已打开,且编辑锁管理器已在本进程中挂载。",
965
- editLockMaintStateDisableRequested: "已请求停用——需要重启",
966
- editLockMaintStateDisableRequestedHint: "你已关闭开关,但管理器仍处于挂载并强制执行状态。重启 DeepSeek Harness 后生效。",
967
- editLockMaintStateEnableRequested: "已请求启用——需要重启",
968
- editLockMaintStateEnableRequestedHint: "你已打开开关,但本进程尚未挂载管理器。重启 DeepSeek Harness 后生效。",
969
- editLockMaintStateDisabled: "强制执行已停用",
970
- editLockMaintStateDisabledHint: "开关关闭,所有已记录且完成安装的行均报告强制执行已停用。",
971
- editLockMaintStateUnknown: "未知",
972
- editLockMaintStateUnknownHint: "挂载证据缺失、不一致,或仍在安装、卸载、失败状态。仅凭已保存的值不能证明正在强制执行或已经停用。",
973
- editLockMaintRestart: "重启 DeepSeek Harness 后生效。",
974
- editLockMaintPinned: "当前组合在编辑锁行上钉死了配置;这里的设置开关对它不生效。",
975
- editLockMaintScopeNote: "该开关对整个 profile 生效:覆盖此 profile 下的所有 Weir 会话,而非某一个工作区。",
976
- editLockMaintWarnKeepHistory: "关闭强制执行不会清除未决操作、围栏或历史——重新打开后同一批文件可能再次被阻塞。",
977
- editLockMaintWarnUnlock: "普通解锁只释放一把锁且不校验内容;它不是历史恢复,永远不会结清未知的发布。",
978
- editLockMaintOffRisk: "编辑锁管理器未挂载。普通编辑不受保护,可能覆盖其他会话的工作。保留的锁和围栏不会阻止停用期间的编辑;重新启用并重启后可能再次阻塞文件。",
979
- editLockMaintUnknownRisk: "无法核实编辑锁的挂载状态。如果管理器未挂载,普通编辑不受保护,可能覆盖其他会话的工作。不能把保留的围栏当成当前仍受保护的证据。",
980
- editLockMaintHistory: "保留的历史——不是当前阻塞",
981
- editLockMaintHistoryHint: "这些旧锁与发布围栏保留在磁盘供检查。没有挂载管理器时,它们不会阻止普通编辑;重新启用后可能再次阻塞文件。此处不可在线强制释放;独立的离线管理员恢复端点仍可使用。",
982
- editLockMaintUnknownHistory: "保留的权威记录——当前作用未经核实",
983
- editLockMaintUnknownHistoryHint: "仅凭已保存的值与旧围栏无法确认管理器是否挂载。可只读检查这些历史;核实强制执行前不可在线强制释放。独立的离线管理员恢复端点仍可使用。",
984
- editLockMaintBlocked: "初始化受阻",
985
- editLockMaintDomains: "管理域",
986
- editLockMaintNoDomains: "此 profile 中没有活动会话报告编辑锁管理域。",
987
- editLockMaintAuthorityYes: "权威已存在",
988
- editLockMaintAuthorityNo: "当前无权威",
989
- editLockMaintReservation: "存在发布者预留:本进程或另一个 Harness 持有(或遗留)了该域的发布权。",
990
- editLockMaintPresenceNone: "当前没有权威目录。无法据此判断此前是否初始化过。",
991
- editLockMaintPresenceEmpty: "权威目录当前为空。无法据此判断此前是否初始化过。",
992
- editLockMaintPresenceJunk: "权威目录有内容但没有已提交的快照;存储层会拒绝打开它。未做任何改动。",
993
- editLockMaintPresenceNotAFile: "snapshot.json 不是常规文件;存储层会拒绝它。未做任何改动。",
994
- editLockMaintPresenceCorrupt: "权威镜像未通过完整性校验,已原样保留——不存在自动修复。拒绝原因:",
995
- editLockMaintPresenceUnreadable: "无法读取权威:",
996
- editLockMaintCounts: "{sessions} 个会话 · {locks} 把锁 · {operations} 条已记录操作",
997
- editLockMaintUnresolved: "未决操作",
998
- editLockMaintUnresolvedNone: "没有未决操作。",
999
- editLockMaintRetained: "保留的锁(中断 / 异常 / 待确认)",
1000
- editLockMaintScopeFile: "单个文件",
1001
- editLockMaintScopeSubtree: "一个目录子树",
1002
- editLockMaintScopeDomain: "整个工作目录",
1003
- editLockMaintScopeNone: "无记录范围",
1004
- editLockMaintRecoveries: "在线管理员恢复",
1005
- editLockMaintRecoverHint: "在运行中的管理器里结清已中断 owner 的未知发布:一次明确点击,无需重启、无需手打哈希;历史中的未知结论原样保留。若范围自加载后发生变化,管理器会拒绝,面板会重新加载。",
1006
- editLockMaintRecoverRoot: "管理根",
1007
- editLockMaintRecoverOwner: "属主会话",
1008
- editLockMaintRecoverRevision: "权威 revision",
1009
- editLockMaintRecoverOperations: "未决操作 ID",
1010
- editLockMaintRecoverRisk: "你接受的风险",
1011
- editLockMaintRecoverDigest: "确认摘要",
1012
- editLockMaintRecoverConfirm: "在线结清该 owner",
1013
- editLockMaintRecoverBusy: "结清中……",
1014
- editLockMaintRecoverDone: "已在 revision {revision} 结清;准入阻塞解除,历史仍保持未知。",
1015
- editLockMaintRecoverFailed: "恢复未确认:",
1016
- worktreeEnabled: "Worktree 车道",
1017
- worktreeEnabledHint: "让助手在隔离的 git worktree 中工作:车道工具、/worktree 命令与车道面板。",
1018
- worktreeAutoSetup: "新车道自动安装依赖",
1019
- worktreeAutoSetupHint: "开车道时自动执行仓库配置的安装命令(默认开启)。",
1020
- worktreeMaxActive: "活跃车道上限",
1021
- worktreeMaxActiveHint: "每个仓库最多同时活跃几条车道(默认 4)。",
1022
- worktreeRoot: "车道目录",
1023
- worktreeRootHint: "车道存放在仓库内的相对目录(默认 .weir/worktrees,已通过 .git/info/exclude 本地忽略)。",
1024
- worktreeWatchTimeoutMinutes: "车道订阅有效期(分钟)",
1025
- worktreeWatchTimeoutMinutesHint: "订阅车道状态后,超过该时长未命中即过期并通知一次(默认 360);已建立的订阅不变。",
1026
- worktreeAutoApprove: "车道自动授权",
1027
- worktreeAutoApproveHint: "新会话的默认审批方式:manual 每次都问;auto-keep 自动批准并保留分支;auto-clean 自动批准并删除分支;会话内 /worktree approve 可覆盖。",
1028
- worktreeAutoApproveOptionManual: "manual(手动)",
1029
- "worktreeAutoApproveOptionAuto-keep": "auto-keep(保留分支)",
1030
- "worktreeAutoApproveOptionAuto-clean": "auto-clean(清理分支)",
1031
- robashEnabled: "只读命令行守卫",
1032
- robashEnabledHint: "精选只读代理(finder 等)只能运行允许清单内的只读命令(默认开启)。",
1033
- robashAllow: "额外允许的命令",
1034
- robashAllowHint: "在内置允许清单之上追加的命令名;内置清单始终生效,留空即不追加。",
1035
- robashGitAllow: "额外允许的 git 子命令",
1036
- robashGitAllowHint: "追加的 git 只读子命令(与 pwsh 侧共用);留空即不追加。",
1037
- robashDeny: "额外禁止的命令",
1038
- robashDenyHint: "在内置禁止清单之上追加的命令名;禁止优先于允许。",
1039
- robashPwshAllow: "额外允许的 pwsh 命令",
1040
- robashPwshAllowHint: "Windows 只读 pwsh 的追加允许项;内置清单始终生效。",
1041
- robashPwshDeny: "额外禁止的 pwsh 命令",
1042
- robashPwshDenyHint: "Windows 只读 pwsh 的追加禁止项;禁止优先于允许。",
1043
- robashListEntries: "条目",
1044
- robashListAdd: "添加条目",
1045
- robashListInvalid: "已保存的值不是有效的命令清单;编辑器已以空列表打开,保存将覆盖该值。",
1046
- robashListPanelHint: "每行一个命令名;条目追加到内置清单,内置清单始终生效——空列表即不追加。",
1047
- robashListEntryPlaceholder: "命令名",
1048
- lspEnabled: "LSP 语义工具",
1049
- lspEnabledHint: "开启后,每个会话可在输入栏单独启用定义跳转、引用查找等语言服务(会话默认关)。",
1050
- lspServers: "自定义语言服务器",
1051
- lspServersHint: "添加内置清单之外的语言服务器,在管理面板中可视化配置。",
1052
- notifyEnabled: "系统通知",
1053
- notifyEnabledHint: "会话需要你处理或一轮任务结束时发送系统通知(默认开启)。",
1054
- notifyOnComplete: "完成时通知",
1055
- notifyOnCompleteHint: "一轮任务结束且耗时超过下方最短时长时通知。",
1056
- notifyOnAttention: "需要处理时通知",
1057
- notifyOnAttentionHint: "审批请求、提问、计划评审、任务失败或中止时通知。",
1058
- notifyMinTurnSeconds: "最短通知时长(秒)",
1059
- notifyMinTurnSecondsHint: "任务至少运行这么久才通知完成;0 表示每轮都通知(默认 15)。",
1060
- notifySound: "通知提示音",
1061
- notifySoundHint: "通知时播放系统提示音(平台支持时)。",
1062
- notifyForeground: "窗口在前台时",
1063
- notifyForegroundHint: "你正看着窗口时是否仍通知:不通知(默认)或始终通知。",
1064
- notifyForegroundOptionSkip: "不通知",
1065
- notifyForegroundOptionAlways: "始终通知",
1066
- notifyPermissions: "通知权限",
1067
- notifyPermissionsHint: "检测 macOS 是否放行这些通知,并引导你完成授权。",
1068
- notifyPermissionsOpen: "管理",
1069
- notifyPermTitle: "通知权限",
1070
- notifyPermDescription: "通知由 DeepSeek Harness 自己弹出,所以需要在 macOS 里允许 DeepSeek Harness 发送通知。",
1071
- notifyPermClose: "关闭",
1072
- notifyPermChecking: "检测中…",
1073
- notifyPermRecheck: "重新检测",
1074
- notifyPermBestEffort: "该检测读取的是苹果未公开文档化的系统设置,仅供参考;亲眼看到测试通知才是最终证明。",
1075
- notifyPermFocusNote: "专注模式 / 勿扰仍可能拦截通知,且无法在这里检测。",
1076
- notifyPermSendTest: "发送测试通知",
1077
- notifyPermSending: "发送中…",
1078
- notifyPermOpenSettings: "打开系统通知设置",
1079
- notifyPermOpening: "打开中…",
1080
- notifyPermOpenHint: "在列表中找到「DeepSeek Harness」,打开「允许通知」,并选择「横幅」或「提醒」样式。",
1081
- notifyPermWaiting: "正在等你允许通知…每 2 秒自动检测一次。",
1082
- notifyPermConfirm: "你看到测试通知了吗?",
1083
- notifyPermSeenYes: "看到了",
1084
- notifyPermSeenNo: "没看到",
1085
- notifyPermSeen: "设置完成,通知会送达你。",
1086
- notifyPermNotSeen: "请确认专注模式 / 勿扰已关闭,「DeepSeek Harness」的样式是「横幅」或「提醒」,并且(若窗口在前台)「窗口在前台时」已设为「始终通知」,然后重试。",
1087
- notifyPermRetry: "重新开始",
1088
- notifyPermSendAgain: "再发一条测试",
1089
- notifyPermError: "出错了:",
1090
- notifyPermManualPath: "也可以手动操作:系统设置 → 通知 → DeepSeek Harness。",
1091
- notifyPermDetails: "技术细节",
1092
- notifyPermFailed: "权限面板出错,请查看运行日志。",
1093
- "notifyPermState_granted": "已允许",
1094
- "notifyPermState_denied": "未允许",
1095
- "notifyPermState_unknown": "无法判定",
1096
- "notifyPermReason_alerts-allowed": "已允许「DeepSeek Harness」弹出提醒。",
1097
- "notifyPermReason_not-allowed": "「DeepSeek Harness」的通知已被关闭。",
1098
- "notifyPermReason_no-record": "macOS 里还没有「DeepSeek Harness」的记录。先发一条测试通知,让它出现在列表里。",
1099
- "notifyPermReason_default": "macOS 里没有「DeepSeek Harness」的明确设置(沿用系统默认),无法在这里判定。",
1100
- "notifyPermReason_unreadable": "无法读取通知设置。",
1101
- notifyWebUnsupported: "当前页面没有网页通知能力,DeepSeek Harness 无法直接通知。",
1102
- notifyWebPermission: "网页通知权限",
1103
- notifyWebDeniedHint: "本页面被禁止显示通知,且无法再次询问。请打开「系统设置 → 通知 → DeepSeek Harness」并开启通知。",
1104
- "notifyWebPerm_granted": "已允许",
1105
- "notifyWebPerm_denied": "已禁止",
1106
- "notifyWebPerm_default": "尚未询问",
1107
- lspManager: "管理 LSP 服务",
1108
- lspManagerHint: "查看各语言服务器安装状态,一键安装缺失的社区服务器。",
1109
- lspManagerLoading: "加载中…",
1110
- lspManagerFailed: "LSP 管理面板异常,请查看运行时日志。",
1111
- lspManagerUnavailable: "此部署不提供 LSP 管理端点:",
1112
- lspManagerRetry: "重试",
1113
- lspManagerInstall: "安装",
1114
- lspManagerCancel: "取消",
1115
- lspManagerConfirmInstall: "确认安装",
1116
- lspManagerInstalling: "安装中…",
1117
- lspManagerInstalled: "已安装",
1118
- lspManagerMissing: "未安装",
1119
- lspManagerExitCode: "退出码",
1120
- lspManagerTimedOut: "(超时)",
1121
- lspManagerCustom: "自定义服务器",
1122
- lspManagerCustomHint: "添加你自己的语言服务器;随设置保存,下次状态加载时检测。",
1123
- lspManagerAddServer: "添加服务器",
1124
- lspManagerRemove: "删除",
1125
- lspManagerFamily: "族名",
1126
- lspManagerCommand: "命令",
1127
- lspManagerArgs: "参数(空格分隔)",
1128
- lspManagerInstallCmd: "安装命令(可空)",
1129
- lspManagerPendingStatus: "保存后检测",
1130
- lspManagerInstallerMissing: "安装器不可用:请先安装安装器,再重试。",
1131
- lspManagerInvalidJson: "已保存的自定义服务器 JSON 格式有误;面板已以空列表打开——保存将覆盖该值。",
1132
- lspFamily_typescript: "TypeScript",
1133
- lspFamily_python: "Python",
1134
- lspFamily_go: "Go",
1135
- lspFamily_rust: "Rust",
1136
- lspFamily_json: "JSON",
1137
- lspFamily_html: "HTML",
1138
- lspFamily_css: "CSS",
1139
- lspFamily_markdown: "Markdown",
1140
- lspFamily_bash: "Bash",
1141
- lspFamily_dockerfile: "Dockerfile",
1142
- lspFamily_yaml: "YAML",
1143
- lspFamily_lua: "Lua",
1144
- lspFamily_cpp: "C/C++",
1145
- lspToggleLabel: "LSP",
1146
- lspToggleTitle: "为本会话启用/禁用 LSP 语义工具",
1147
- worktreePillMode: "Worktree",
1148
- worktreePillLanes: "Worktree",
1149
- worktreePillCount: "{n} 条车道",
1150
- worktreePillAwaiting: "{n} 待批准",
1151
- worktreePillTitle: "Worktree 车道——打开面板",
1152
- worktreePillBaseMoved: "主工作区已离开车道基线分支,切回后才能合并",
1153
- worktreeModeLabel: "Worktree",
1154
- worktreeModeTitle: "可选纪律:车道随时可用,无需开启。开启后助手不再直接改文件,所有改动走隔离车道。",
1155
- worktreeModeUnavailable: "Worktree 模式不可用:",
1156
- worktreeApproveLabel: "自动授权",
1157
- worktreeApproveTitle: "车道自动授权模式({mode}):manual 每张卡片都要批准;auto-keep 自动批准合并/放弃并清理 worktree 但保留分支;auto-clean 连分支一起删除。新会话默认在设置 › Worktree 车道。",
1158
- worktreeApproveOptionManual: "手动",
1159
- worktreeApproveOptionAutoKeep: "保留",
1160
- worktreeApproveOptionAutoClean: "清理",
1161
- worktreeLoading: "正在加载车道…",
1162
- worktreeLoadFailed: "车道视图读取失败。",
1163
- worktreeUnavailable: "本会话无法使用 Worktree 车道。",
1164
- worktreeDisabled: "Worktree 车道已在设置中关闭。",
1165
- worktreeEmpty: "没有活跃车道。助手会用 worktree_open 开一条。",
1166
- worktreeEmptyTitle: "没有活跃车道",
1167
- worktreeEmptyBody: "助手需要隔离工作区时会用 worktree_open 开一条车道。在这里跟踪检查、批准合并与收尾。",
1168
- worktreeRefresh: "刷新",
1169
- worktreeConfigure: "验证配置…",
1170
- worktreeShowHistory: "历史({n})",
1171
- worktreeHideHistory: "收起历史",
1172
- worktreeVerificationOn: "验证:{n} 条命令",
1173
- worktreeVerificationOff: "未启用验证",
1174
- worktreeExcludeOk: "已本地忽略",
1175
- worktreeExcludeMissing: "车道目录尚未忽略",
1176
- worktreeUnmanaged: "车道目录下有 {n} 个不由 Weir 管理的 worktree",
1177
- worktreeStaleData: "显示的是上次读取的数据;刷新失败。",
1178
- worktreeAheadBehind: "领先 {ahead} · 落后 {behind}",
1179
- worktreeBaseMoved: "基线已移动",
1180
- worktreeNextLabel: "下一步:{next}",
1181
- worktreeViewDiff: "改动",
1182
- worktreeHideDiff: "收起改动",
1183
- worktreeDiffUnavailable: "改动不可用",
1184
- worktreeFiles: "{n} 个文件",
1185
- worktreeExitCode: "退出码 {code}",
1186
- worktreeNoChanges: "相对基线分支没有改动。",
1187
- worktreeRecheck: "重新检查",
1188
- worktreeRetrySetup: "重试安装",
1189
- worktreeSkipSetup: "跳过安装",
1190
- worktreeLand: "合并…",
1191
- worktreeLandConfirm: "确认合并",
1192
- worktreeAbandon: "放弃…",
1193
- worktreeAbandonConfirm: "确认放弃",
1194
- worktreeCleanupWorktree: "清理 worktree",
1195
- worktreeCleanupAll: "清理 worktree 与分支",
1196
- worktreeCleanupAllConfirm: "确认删除分支",
1197
- worktreeCopyPath: "复制路径",
1198
- worktreeActionUnavailable: "当前不可用",
1199
- worktreeActionFailed: "此车道操作当前不可用,请改用 /worktree 命令直接执行。",
1200
- worktreeConflicts: "冲突",
1201
- worktreeMergeCommit: "合并提交",
1202
- worktreeCleanup: "收尾",
1203
- worktreeConfigName: "名称",
1204
- worktreeConfigRun: "命令",
1205
- worktreeConfigChecks: "验证命令",
1206
- worktreeConfigSetup: "setup 命令(可选)",
1207
- worktreeConfigAdd: "添加命令",
1208
- worktreeConfigRemove: "删除",
1209
- worktreeConfigSave: "保存",
1210
- worktreeCancel: "取消",
1211
- worktreeConfigHint: "只写入本仓库(.weir/worktrees/.config.json,不入库)。车道检查时在该车道内执行这些命令。",
1212
- worktreeInitParseFailed: "仓库配置读取失败。",
1213
- worktreeFlatInput: "输入",
1214
- worktreeFlatOutput: "输出",
72
+ // Worktree lanes: only the strings the entry’s own synchronous surfaces
73
+ // read stay in this namespace — the sidebar tab type’s title/guide thunks
74
+ // and the lanes panel’s pre-arrival loading state. Every lazily rendered
75
+ // string (the header pill included: its wrapper renders nothing until the
76
+ // chunks arrive) lives in lib/client.worktree-model.js’s data face,
77
+ // registered under "settings.weir.worktree" on worktree-batch arrival.
78
+ // worktreeLoading is byte-identical in both homes — a documented
79
+ // cross-namespace duplicate (the panel’s pre-arrival state resolves it
80
+ // here, the chunk’s own loading row from its feature namespace).
1215
81
  worktreeTabLabel: "Worktrees",
1216
82
  worktreeGuideTitle: "Worktree 车道",
1217
83
  worktreeGuideDescription: "本会话的车道:状态、检查、合并与收尾。",
1218
- worktreeState_preparing: "准备中",
1219
- worktreeState_setup_failed: "安装失败",
1220
- worktreeState_ready: "就绪",
1221
- worktreeState_working: "工作中",
1222
- worktreeState_dirty: "有未提交改动",
1223
- worktreeState_no_commits: "没有提交",
1224
- worktreeState_branch_moved: "分支被切换",
1225
- worktreeState_checking: "检查中",
1226
- worktreeState_check_failed: "检查失败",
1227
- worktreeState_landable: "可合并",
1228
- worktreeState_conflicted: "有冲突",
1229
- worktreeState_awaiting_approval: "等待批准",
1230
- worktreeState_declined: "已拒绝合并",
1231
- worktreeState_landed: "已合并",
1232
- worktreeState_kept: "已保留",
1233
- worktreeState_cleaned: "已清理",
1234
- worktreeState_abandoned: "已放弃",
1235
- worktreeTool_worktree_open: "开启 worktree 车道",
1236
- worktreeTool_worktree_check: "检查 worktree 车道",
1237
- worktreeTool_worktree_land: "合并 worktree 车道",
1238
- worktreeTool_worktree_cleanup: "worktree 收尾",
1239
- worktreeTool_worktree_abandon: "放弃 worktree 车道",
1240
- worktreeTool_worktree_watch: "订阅 worktree 车道",
1241
- worktreeWatchStates: "订阅状态",
1242
- worktreeWatchExpires: "有效期至 {time}",
1243
- worktreeWatchHit: "已立即命中",
1244
- worktreeWatching: "{n} 个订阅",
1245
- worktreeNext_delegate: "派子代理到该车道工作",
1246
- worktreeNext_worktree_check: "检查车道",
1247
- worktreeNext_worktree_land: "合并车道(需你批准)",
1248
- worktreeNext_worktree_cleanup: "选择收尾方式",
1249
- worktreeWait_lane_ready: "等待依赖安装完成",
1250
- worktreeWait_child_settle: "等待车道子代理完成",
1251
- worktreeWait_check_complete: "等待验证完成",
1252
- worktreeWait_user: "等待你的决定",
1253
- hashEditTitle: "编辑文件",
1254
- hashEditPreparing: "准备编辑",
1255
- hashEditPlanned: "计划编辑——调用完成后此处显示实际应用的 diff。",
1256
- hashEditRunning: "编辑中…",
1257
- hashEditFailed: "编辑失败",
1258
- hashEditStopped: "已中断",
84
+ worktreeLoading: "正在加载车道…",
1259
85
  hashEditInput: "输入",
1260
86
  hashEditOutput: "输出",
1261
- hashEditCodeLabel: "diff",
1262
- hashEditCopy: "复制",
1263
- hashEditCopied: "已复制",
1264
- hashEditWrap: "自动换行",
1265
- hashEditUnwrap: "取消换行",
1266
- hashEditCollapse: "收起",
1267
- hashEditCollapseAria: "收起 diff",
1268
- hashEditExpand: "展开剩余 {count} 行",
1269
- hashEditExpandAria: "展开剩余 {count} 行",
1270
87
  capabilityTabLabel: "能力",
1271
88
  capabilityGuideTitle: "能力",
1272
89
  capabilityGuideDescription: "此会话的技能、MCP server 与预设。",
1273
- "capability.badge": "{skills} 个技能 · {mcp} 个 MCP",
1274
- "capability.unavailable.short": "能力不可用",
1275
- "capability.effectiveUnknown": "已应用数量未知——请刷新并检查技能来源",
1276
- "capability.effectiveUnknownShort": "技能 ? · MCP ?",
1277
- "capability.effectiveUnknownDetail": "修订已接受,但有效能力暂无法核实。请刷新并检查技能来源。草稿已保留;只有手动应用才会更改会话。",
1278
- "capability.unknownOverwriteRisk": "原有选择未知。应用此草稿可能覆盖其他已接受的技能与 MCP server。确认前请核对完整选择。",
1279
- "capability.confirmUnknownOverwrite": "确认替换未知选择",
1280
90
  "capability.loading": "正在加载能力…",
1281
- "capability.error": "此会话的能力不可用。",
1282
- "capability.unavailable": "能力在此会话中不可用。",
1283
- "capability.unsupported": "不支持:此宿主未满足一致性条件。",
1284
- "capability.tab.skills": "技能",
1285
- "capability.tab.mcp": "MCP",
1286
- "capability.tab.presets": "预设",
1287
- "capability.search": "搜索",
1288
- "capability.close": "关闭",
1289
- "capability.conflict": "冲突",
1290
- "capability.sourceUnknown": "未知来源",
1291
- "capability.sourceNumber": " · 候选 ",
1292
- "capability.sameNameWarning": "{name}:本会话只能启用一个来源。请取消其中一项:{sources}。",
1293
- "capability.unresolvedNameWarning": "{name}:旧名称尚未选定来源。请选择精确来源或移除该名称:{sources}。",
1294
- "capability.unknownLegacyName": "{name}:当前清单中没有匹配的技能。请刷新清单或移除这个旧名称。",
1295
- "capability.inventoryUnavailableName": "清单暂不可读;旧名称在草稿中保持未解析。请稍后重试;未选择任何来源。",
1296
- "capability.unresolvedNameTitle": "为旧名称 {name} 选择来源",
1297
- "capability.replaceName": "将 {name} 替换为 {source}",
1298
- "capability.removeName": "移除旧名称 {name}",
1299
- "capability.serverSameName": "服务端拒绝同名技能 {names}。请取消一个来源或刷新清单;草稿已保留。",
1300
- "capability.serverMissing": "服务端无法解析 {names}。请刷新清单并选择精确来源或移除该名称;草稿已保留。",
1301
- "capability.unknownName": "未知名称",
1302
- "capability.missing": "缺失",
1303
- "capability.noSkills": "没有匹配的技能。",
1304
- "capability.mcp.groupManaged": "Weir 管理",
1305
- "capability.mcp.groupUnmanaged": "未纳入管理",
1306
- "capability.mcp.none": "未配置 MCP server。",
1307
- "capability.mcp.unmanagedHint": "在 Weir 之外配置,会话选择无法管理它。",
1308
- "capability.mcp.stateMounted": "已挂载",
1309
- "capability.mcp.stateRegistered": "已注册",
1310
- "capability.unmanaged": "未管理",
1311
- "capability.mcp.add": "+ 添加受管 MCP server",
1312
- "capability.mcp.identity": "identity(如 my-docs)",
1313
- "capability.mcp.label": "标签(显示名,可选)",
1314
- "capability.mcp.command": "命令(如 npx)",
1315
- "capability.mcp.args": "参数,空格分隔(可选)",
1316
- "capability.mcp.adding": "正在添加…",
1317
- "capability.mcp.addConfirm": "添加",
1318
- "capability.mcp.cancel": "取消",
1319
- "capability.mcp.errorRequired": "必填。",
1320
- "capability.mcp.errorIdentityInvalid": "仅限字母、数字、\"-\"、\"_\",且以字母或数字开头。",
1321
- "capability.diff.addSkills": "+{n} 个技能",
1322
- "capability.diff.removeSkills": "−{n} 个技能",
1323
- "capability.diff.addMcp": "+{n} 个 MCP",
1324
- "capability.diff.removeMcp": "−{n} 个 MCP",
1325
- "capability.apply": "应用",
1326
- "capability.applying": "正在应用…",
1327
- "capability.discard": "放弃",
1328
- "capability.applied": "已应用",
1329
- "capability.acceptedUnknown": "已接受 · 有效数量未知",
1330
- "capability.appliedSkipped": "已跳过 {n} 项(当前预设不适用)",
1331
- "capability.failed": "失败——草稿已保留",
1332
- "capability.conflictState": "已在别处变更——请核对当前状态",
1333
- "capability.missingAction": "缺失项需要安装/配置",
1334
- "capability.pending": "结果待确认——请查询回执",
1335
- "capability.presets.unavailable": "预设在此宿主上不可用。",
1336
- "capability.presets.errorName": "请输入名称。",
1337
- "capability.presets.saved": "预设已保存。",
1338
- "capability.presets.replaced": "已替换确认的预设 ID {id};未新建第二个预设。",
1339
- "capability.presets.renameRow": "重命名预设…",
1340
- "capability.presets.resaveRow": "重新保存…",
1341
- "capability.presets.newName": "新预设名称",
1342
- "capability.presets.renameSubmit": "保存新名称",
1343
- "capability.presets.resaveSubmit": "确认重新保存",
1344
- "capability.presets.editTarget": "目标:{name} · {scope} · ID {id} · 修订 {revision}",
1345
- "capability.presets.resaveConfirm": "从{source}覆盖此预设:{skills} 个技能 · {mcp} 个 MCP · {unresolved} 个未解析引用。当前会话不变。",
1346
- "capability.presets.renamed": "预设已改名;当前草稿和已应用选择不变。",
1347
- "capability.presets.resaved": "预设已重新保存;当前草稿和已应用选择不变。",
1348
- "capability.presets.renameCollision": "此名称已属于另一预设,请另选名称。",
1349
- "capability.presets.editConflict": "预设已更改;请检查刷新后的行并重新确认。",
1350
- "capability.presets.sourceChanged": "已应用选择已改变;请刷新会话回执后重新确认。",
1351
- "capability.presets.sourceUnavailable": "已应用来源不可用{missing}。请恢复缺失技能、刷新回执后重新确认。",
1352
- "capability.presets.appliedUnavailable": "已应用来源有不可用项目。请恢复项目并刷新会话回执后重新保存。",
1353
- "capability.presets.appliedReceiptMissing": "当前回执无法验证已应用来源。请刷新会话回执后重新保存;当前草稿仍可使用。",
1354
- "capability.presets.locked": "预设存储正忙;请稍后刷新并重新决定。",
1355
- "capability.presets.unreadable": "无法安全读取预设存储;重试前请检查存储。",
1356
- "capability.presets.unsupported": "不支持此预设版本;编辑前请更新客户端或宿主。",
1357
- "capability.presets.gone": "预设已删除或不存在;请刷新列表,它未被重建。",
1358
- "capability.presets.confirmAgain": "替换目标已改变;请刷新并重新确认身份。",
1359
- "capability.presets.uncertain": "结果未知;请刷新并检查预设,再决定是否重试。",
1360
- "capability.presets.missingSelection": "草稿选择不完整;请刷新后再保存。",
1361
- "capability.presets.replaceTarget": "确认替换 {scope} 范围内 ID {id}、修订 {revision} 的预设?",
1362
- "capability.presets.noneKnown": "无已报告项",
1363
- "capability.presets.importPartial": "已安装的技能:{names}。预设状态尚未确认。请检查已安装文件并刷新预设,再决定如何恢复。",
1364
- "capability.presets.currentRevision": " 当前存储修订:{revision}。",
1365
- "capability.presets.revisionConflict": "已在别处变更——列表已刷新。",
1366
- "capability.presets.noWorkspace": "此会话没有工作区。",
1367
- "capability.presets.saveFailed": "预设保存失败。",
1368
- "capability.presets.loaded": "已装入草稿——应用后生效。",
1369
- "capability.presets.loadedUnresolved": "已装入草稿——报告 {n} 个未解析引用。",
1370
- "capability.presets.loadFailed": "载入失败——预设可能已不存在。",
1371
- "capability.presets.deleted": "预设已删除。",
1372
- "capability.presets.deleteFailed": "删除失败。",
1373
- "capability.presets.exportFailed": "导出失败。",
1374
- "capability.presets.imported": "已导入:{bound} 个 MCP 绑定,{unresolved} 个未解析引用。",
1375
- "capability.presets.counts": "{skills} 个技能 · {mcp} 个 MCP",
1376
- "capability.presets.countsUnresolved": " · {n} 个未解析",
1377
- "capability.presets.loading": "正在载入…",
1378
- "capability.presets.load": "载入",
1379
- "capability.presets.export": "导出",
1380
- "capability.presets.delete": "删除",
1381
- "capability.presets.deleteConfirm": "删除预设“{name}”?此操作不可撤销。",
1382
- "capability.presets.deleteConfirmButton": "删除预设",
1383
- "capability.presets.deleting": "正在删除…",
1384
- "capability.presets.cancel": "取消",
1385
- "capability.presets.exportLabel": "预设 JSON",
1386
- "capability.presets.copy": "复制到剪贴板",
1387
- "capability.presets.copied": "已复制",
1388
- "capability.presets.close": "关闭",
1389
- "capability.presets.saveOpen": "存为预设…",
1390
- "capability.presets.importOpen": "导入…",
1391
- "capability.presets.name": "预设名称",
1392
- "capability.presets.namespace": "命名空间",
1393
- "capability.presets.scopeWorkspace": "工作区",
1394
- "capability.presets.scopeGlobal": "全局",
1395
- "capability.presets.source": "来源",
1396
- "capability.presets.fromDraft": "当前草稿",
1397
- "capability.presets.fromApplied": "已应用的选择",
1398
- "capability.presets.nameConflict": "此命名空间中已存在名为“{name}”的预设。",
1399
- "capability.presets.rename": "改名…",
1400
- "capability.presets.renameHint": "修改名称后重新保存。",
1401
- "capability.presets.replace": "替换它",
1402
- "capability.presets.saving": "正在保存…",
1403
- "capability.presets.save": "保存预设",
1404
- "capability.presets.importPlaceholder": "粘贴便携式预设文档(JSON)…",
1405
- "capability.presets.importing": "正在导入…",
1406
- "capability.presets.importSubmit": "导入",
1407
- "capability.presets.importInvalidJson": "不是有效的 JSON——未写入任何内容。",
1408
- "capability.presets.importRejected": "已拒绝:{reason}——未写入任何内容。",
1409
- "capability.presets.importNameConflict": "此处已存在同名预设。",
1410
- "capability.presets.importFailed": "导入失败——未写入任何内容。",
1411
- "capability.presets.groupWorkspace": "工作区预设",
1412
- "capability.presets.groupWorkspaceNone": "工作区预设(无工作区)",
1413
- "capability.presets.groupGlobal": "全局预设",
1414
- "capability.presets.emptyWorkspace": "暂无工作区预设。",
1415
- "capability.presets.emptyGlobal": "暂无全局预设。",
1416
- "capability.presets.defaultTitle": "新会话的工作区默认值",
1417
- "capability.presets.defaultUnavailable": "工作区默认值不可用。",
1418
- "capability.presets.defaultNone": "未设置默认值——新会话使用内置基线。",
1419
- "capability.presets.defaultEmpty": "已设置显式空默认:新会话以 0 个技能 · 0 个 MCP 开始。",
1420
- "capability.presets.defaultEntries": "默认值:{counts}",
1421
- "capability.presets.defaultUnresolved": "……解析时报告 {n} 个未解析引用。",
1422
- "capability.presets.defaultSaveOpen": "存为默认值…",
1423
- "capability.presets.defaultClearOpen": "清除默认值…",
1424
- "capability.presets.defaultSaveConfirm": "将 {counts} 存为此工作区的默认值?此工作区的新会话将从它开始;当前会话不变。",
1425
- "capability.presets.defaultSaveConfirmButton": "保存默认值",
1426
- "capability.presets.defaultSaved": "工作区默认值已保存。",
1427
- "capability.presets.defaultSaveFailed": "默认值保存失败。",
1428
- "capability.presets.defaultClearConfirm": "清除工作区默认值?新会话回到内置基线;已打开的会话不变。",
1429
- "capability.presets.defaultClearConfirmButton": "清除默认值",
1430
- "capability.presets.defaultCleared": "工作区默认值已清除——新会话使用内置基线。",
1431
- "capability.presets.defaultClearFailed": "默认值清除失败。",
1432
- "capability.presets.clearing": "正在清除…",
1433
- "capability.presets.needsReceipt": "会话回执载入前不可用。",
1434
- "capability.presets.exportDownload": "下载 .json",
1435
- "capability.presets.downloaded": "已下载",
1436
- "capability.presets.importedPackage": "已导入:安装 {installed} 个技能,{bound} 个 MCP 绑定,{unresolved} 个未解析引用。",
1437
- "capability.presets.importSummaryTitle": "导入摘要——写入前请核对",
1438
- "capability.presets.importFiles": "{n} 个文件",
1439
- "capability.presets.importNoInstalls": "此包不包含需要安装的技能。",
1440
- "capability.presets.importUnresolvedTitle": "未解析引用——不会安装:",
1441
- "capability.presets.importCollision": "名称冲突",
1442
- "capability.presets.importCollisionDecision": "当打包技能名称已存在时:",
1443
- "capability.presets.collisionCancel": "跳过它(默认)",
1444
- "capability.presets.collisionReplace": "替换它",
1445
- "capability.presets.collisionCoexist": "共存(自动改名)",
1446
- "capability.presets.importConfirm": "确认导入",
1447
- "capability.presets.importResultTitle": "导入结果",
1448
- "capability.presets.importInstalledNote": "已安装的技能保持未勾选——在草稿中勾选并应用后生效。",
1449
- "capability.presets.importInstallFailed": "安装失败:{reason}——已回滚 {n} 个文件;未创建预设。",
1450
- "capability.presets.importNoTargetRoot": "此宿主没有可用的 {scope} 技能根目录——未安装任何内容。",
1451
- "capability.presets.scopeProject": "工作区",
1452
- "capability.presets.scopeUser": "用户",
1453
91
  // 会话黑板(切片二):右侧边栏面板的页签、列表、详情与编辑字符串。
1454
92
  // 类型标签为短语义名,随语言翻译。
1455
93
  blackboardTabLabel: "黑板",
1456
94
  blackboardGuideTitle: "会话黑板",
1457
95
  blackboardGuideDescription: "本会话共享的发现:条目、用量计数与仲裁编辑。",
1458
96
  blackboardPillTitle: "打开会话黑板",
1459
- "blackboard.title": "黑板",
1460
- "blackboard.entries": "{n} 条",
1461
97
  "blackboard.loading": "正在加载黑板…",
1462
- "blackboard.unavailable": "此会话的黑板不可用。",
1463
- "blackboard.parentBoard": "正在显示父会话的黑板。",
1464
- "blackboard.retry": "重试",
1465
- "blackboard.empty": "黑板为空。",
1466
- "blackboard.emptyDesc": "Agent 写入本会话黑板的发现会出现在这里。",
1467
- "blackboard.noMatch": "没有匹配的条目。",
1468
- "blackboard.search": "搜索",
1469
- "blackboard.new": "新建条目",
1470
- "blackboard.refresh": "刷新",
1471
- "blackboard.back": "返回",
1472
- "blackboard.dismiss": "忽略",
1473
- "blackboard.filterAll": "全部",
1474
- "blackboard.type.map": "索引",
1475
- "blackboard.type.contract": "硬约束",
1476
- "blackboard.type.deadend": "已否决方案",
1477
- "blackboard.type.wiring": "隐藏耦合",
1478
- "blackboard.type.recipe": "操作流程",
1479
- "blackboard.type.why": "设计缘由",
1480
- "blackboard.rowMeta": "{read} 次读取 · {watching} 个等待者",
1481
- "blackboard.updated": "更新于 {time}",
1482
- "blackboard.summary": "摘要",
1483
- "blackboard.content": "正文",
1484
- "blackboard.gone": "此条目已不存在。",
1485
- "blackboard.goneDesc": "它已从黑板删除(可能是其他写入者所为)。",
1486
- "blackboard.error": "条目加载失败。",
1487
- "blackboard.edit": "编辑",
1488
- "blackboard.delete": "删除",
1489
- "blackboard.deleting": "删除中…",
1490
- "blackboard.deleted": "条目已删除。",
1491
- "blackboard.deleteConfirm": "删除此条目?写入权将被消耗。",
1492
- "blackboard.contention": "写入权正被 {holder} 持有。",
1493
- "blackboard.watch": "释放时通知我",
1494
- "blackboard.watching": "正在监视 {key}",
1495
- "blackboard.watchingState": "监视中…",
1496
- "blackboard.released": "键已释放——写入权现由你持有。",
1497
- "blackboard.editorNew": "新建条目",
1498
- "blackboard.formKey": "键",
1499
- "blackboard.formType": "类型",
1500
- "blackboard.formRequired": "必填。",
1501
- "blackboard.formKeyInvalid": "仅限字母、数字与 . _ - /;须以字母或数字开头。",
1502
- "blackboard.formSummaryPlaceholder": "一两句话:发现是什么、代价几何、如何复核",
1503
- "blackboard.save": "保存",
1504
- "blackboard.saving": "保存中…",
1505
- "blackboard.cancel": "取消",
1506
- "blackboard.saved": "已保存(修订 {n})。",
1507
- "blackboard.created": "条目已创建。",
1508
- "blackboard.applying": "正在申请写入权…",
1509
- "blackboard.reacquire": "重新申请",
1510
- "blackboard.tokenHeld": "写入权 {time}",
1511
- "blackboard.tokenExpired": "写入权已过期——保存前请重新申请。",
1512
- "blackboard.tokenExpiredShort": "写入权已过期",
1513
- "blackboard.promote": "评估晋升",
1514
- "blackboard.promoteDisabled": "所有条目均已晋升——没有可评估的条目。",
1515
- "blackboard.promotionRequested": "主 Agent 已收到晋升评估请求。",
1516
- "blackboard.promoted": "已晋升",
1517
- "blackboard.promotedTo": "已晋升 → {destination}",
1518
- "blackboard.promotedReadonly": "此条目已晋升,只读。",
1519
- "blackboard.promotedReadonlyDetail": "已晋升条目只读:持久副本位于目标文档,黑板副本保留会话内引用。"
1520
98
  };
1521
99
  const NS = "settings.weir";
1522
100
  const SECTION_ID = "weir-settings";
@@ -1527,6 +105,26 @@ window.__ModuleLoader__.load({
1527
105
  // settings-page chunk.
1528
106
  const ROUTING_SECTION_ID = "weir-model-routing";
1529
107
  const ROUTING_ITEM_SLOT = "settings.weir-routing.item";
108
+ // ---- Chunk-carried dictionaries ----
109
+ // Every lazily delivered feature chunk carries a pure { en, zh } data
110
+ // face (NO ctx calls inside a chunk: the factory re-executes under HMR,
111
+ // so a chunk-local register would throw on the duplicate (namespace,
112
+ // locale) pair). The entry registers one namespace per feature when the
113
+ // chunk arrives, inside a ctx.effect whose disposer owns the
114
+ // registration (released on fiber unload before any re-registration).
115
+ // NS keeps only the strings apply-time-registered synchronous face
116
+ // callbacks read: tab titles and guide copy, pill labels, and the
117
+ // pre-arrival loading states. This bridge is how the module-level
118
+ // loaders and wrappers receive apply-scope values (the registration
119
+ // hook and the feature t seats); apply() fills it before anything can
120
+ // load a chunk, and an HMR restart re-executes this factory and refills.
121
+ const chunkDictionaries = {
122
+ register: null,
123
+ lspToggle: null,
124
+ hashEdit: null,
125
+ editLock: null,
126
+ worktree: null,
127
+ };
1530
128
  // ---- Package-local chunk wiring (composition root) ----
1531
129
  // Same-package sync require is impossible in the ModuleLoader, so each
1532
130
  // lazily delivered surface fans out one Promise.all over
@@ -1550,7 +148,10 @@ window.__ModuleLoader__.load({
1550
148
  const loadHashEditChunks = lazyChunks(() => Promise.all([
1551
149
  require.async("./client.hash-edit-view.js"),
1552
150
  require.async("./client.hash-edit-model.js")
1553
- ]));
151
+ ]).then((chunks) => {
152
+ chunkDictionaries.register?.("settings.weir.hash-edit", chunks[1].dictionaries);
153
+ return chunks;
154
+ }));
1554
155
  /** Shared arrival state for one async chunk surface: null while in
1555
156
  * flight, { chunks } once arrived, { error } after a failed load. */
1556
157
  const useChunkArrival = (load, enabled = true) => {
@@ -1600,11 +201,14 @@ window.__ModuleLoader__.load({
1600
201
  const arrival = useChunkArrival(loadHashEditChunks);
1601
202
  if (arrival?.chunks) {
1602
203
  const [view, model] = arrival.chunks;
1603
- return react_jsx_runtime.jsx(view.HashEditRow, { ...props, model });
204
+ return react_jsx_runtime.jsx(view.HashEditRow, { ...props, t: chunkDictionaries.hashEdit ?? props.t, model });
1604
205
  }
1605
206
  return react_jsx_runtime.jsx(HashEditFallbackBody, props);
1606
207
  }
1607
- const loadLspToggleChunk = lazyChunks(() => require.async("./client.lsp-toggle.js"));
208
+ const loadLspToggleChunk = lazyChunks(() => require.async("./client.lsp-toggle.js").then((chunk) => {
209
+ chunkDictionaries.register?.("settings.weir.lsp-toggle", chunk.dictionaries);
210
+ return chunk;
211
+ }));
1608
212
  const loadNotifyWebChunk = lazyChunks(() => require.async("./client.notify-web.js"));
1609
213
  /** Composer-bar wrapper: renders nothing until the toggle chunk arrives
1610
214
  * (and nothing at all when the slot injected no session id — the
@@ -1612,14 +216,17 @@ window.__ModuleLoader__.load({
1612
216
  function LspToggleWrapper(props) {
1613
217
  const arrival = useChunkArrival(loadLspToggleChunk, typeof props.sessionId === "string" && props.sessionId !== "");
1614
218
  if (!arrival?.chunks) return null;
1615
- return react_jsx_runtime.jsx(arrival.chunks.LspToggle, { ...props, settingsBus });
219
+ return react_jsx_runtime.jsx(arrival.chunks.LspToggle, { ...props, settingsBus, t: chunkDictionaries.lspToggle ?? props.t });
1616
220
  }
1617
- const loadEditLockChunk = lazyChunks(() => require.async("./client.edit-lock-panel.js"));
221
+ const loadEditLockChunk = lazyChunks(() => require.async("./client.edit-lock-panel.js").then((chunk) => {
222
+ chunkDictionaries.register?.("settings.weir.edit-lock", chunk.dictionaries);
223
+ return chunk;
224
+ }));
1618
225
  /** Composer-bar Edit Lock entry: nothing until its chunk arrives. */
1619
226
  function EditLockWrapper(props) {
1620
227
  const arrival = useChunkArrival(loadEditLockChunk, typeof props.sessionId === "string" && props.sessionId !== "");
1621
228
  if (!arrival?.chunks) return null;
1622
- return react_jsx_runtime.jsx(arrival.chunks.EditLockPanel, props);
229
+ return react_jsx_runtime.jsx(arrival.chunks.EditLockPanel, { ...props, t: chunkDictionaries.editLock ?? props.t });
1623
230
  }
1624
231
  // ---- Tab glyphs (ui-entries-and-icons) ----
1625
232
  // Three 16x16 stroke glyphs drawn in currentColor, matching the host
@@ -1711,16 +318,21 @@ window.__ModuleLoader__.load({
1711
318
  const loadWorktreeChunks = lazyChunks(() => Promise.all([
1712
319
  require.async("./client.worktree-view.js"),
1713
320
  require.async("./client.worktree-model.js")
1714
- ]));
321
+ ]).then((chunks) => {
322
+ chunkDictionaries.register?.("settings.weir.worktree", chunks[1].dictionaries);
323
+ return chunks;
324
+ }));
1715
325
  /** The views name keys without the namespace prefix ("abandon",
1716
326
  * "state_landable"); the dictionaries hold them prefixed
1717
327
  * ("worktreeAbandon", "worktreeState_landable"). Hyphens in state names
1718
- * map to underscores. */
328
+ * map to underscores. The seat binds the feature namespace
329
+ * ("settings.weir.worktree", registered on batch arrival) once apply()
330
+ * has filled the bridge; props.t is the pre-apply/test fallback. */
1719
331
  const worktreeKey = (key) => `worktree${key.charAt(0).toUpperCase()}${key.slice(1)}`.replace(/-/g, "_");
1720
332
  const worktreeT = (t) => (typeof t === "function" ? (key, ...rest) => t(worktreeKey(String(key)), ...rest) : t);
1721
333
  const worktreeFace = (props, view, model) => ({
1722
334
  ...props,
1723
- t: worktreeT(props.t),
335
+ t: worktreeT(chunkDictionaries.worktree ?? props.t),
1724
336
  view,
1725
337
  model,
1726
338
  WORKTREE_PROJECTION_KEY: model.WORKTREE_PROJECTION_KEY,
@@ -1757,7 +369,7 @@ window.__ModuleLoader__.load({
1757
369
  const arrival = useChunkArrival(loadWorktreeChunks);
1758
370
  if (!arrival?.chunks) return null;
1759
371
  const [view, model] = arrival.chunks;
1760
- return react_jsx_runtime.jsx(view.WorktreeToolRow, { ...props, t: worktreeT(props.t), model });
372
+ return react_jsx_runtime.jsx(view.WorktreeToolRow, { ...props, t: worktreeT(chunkDictionaries.worktree ?? props.t), model });
1761
373
  }
1762
374
  /** Snapshot-store facade with a stable identity: the host caches slot
1763
375
  * inject faces on first render, so the settings card's hooks source must
@@ -1797,6 +409,154 @@ window.__ModuleLoader__.load({
1797
409
  const inject = ["slots", "locale", "configForms", "remote", "remote.session", "remote.commands", "connection"];
1798
410
  function apply(ctx) {
1799
411
  const t = ctx.locale.bind(NS);
412
+ // Chunk-carried dictionaries: one registration per feature namespace
413
+ // per apply (a duplicate (namespace, locale) pair throws
414
+ // synchronously), owned by an effect disposer so an HMR unload
415
+ // releases it before any re-registration. The per-apply Set makes a
416
+ // repeated arrival (a second surface of the same feature) a no-op.
417
+ const registeredDictNamespaces = new Set();
418
+ const registerChunkDictionaries = (ns, dictionaries) => {
419
+ const en = dictionaries?.en;
420
+ const zh = dictionaries?.zh;
421
+ // Sentinel chunks in unit tests carry no data face: nothing to register.
422
+ if ((!en || Object.keys(en).length === 0) && (!zh || Object.keys(zh).length === 0)) return;
423
+ if (registeredDictNamespaces.has(ns)) return;
424
+ registeredDictNamespaces.add(ns);
425
+ ctx.effect(() => ctx.locale.register(ns, { zh: zh ?? {}, en: en ?? {} }), `ui-weir-settings: ${ns} dictionaries`);
426
+ };
427
+ chunkDictionaries.register = registerChunkDictionaries;
428
+ chunkDictionaries.lspToggle = ctx.locale.bind("settings.weir.lsp-toggle");
429
+ chunkDictionaries.hashEdit = ctx.locale.bind("settings.weir.hash-edit");
430
+ chunkDictionaries.editLock = ctx.locale.bind("settings.weir.edit-lock");
431
+ chunkDictionaries.worktree = ctx.locale.bind("settings.weir.worktree");
432
+ const pageT = ctx.locale.bind("settings.weir.page");
433
+ const capabilityT = ctx.locale.bind("settings.weir.capability");
434
+ const blackboardT = ctx.locale.bind("settings.weir.blackboard");
435
+ // ---- Channel adapters (composition root) ----
436
+ // Every feature read channel below rides one of two carriers through
437
+ // these adapters instead of re-hand-building "POST → unfold the {ok,
438
+ // value} envelope → warn-once on degradation" per site. A channel call
439
+ // NEVER rejects: a carrier throw folds to { ok:false, error:{ code:
440
+ // "call-threw" } }, a failure envelope to call-failed, a missing gateway
441
+ // connection to channel-unavailable — the folded shape the blackboard
442
+ // model chunk's foldRemoteResult used to own chunk-side. Warn-once keeps
443
+ // degradation observable: once per failure shape per page generation (an
444
+ // apply() run), never per render (the silent-fallback lesson). The kind
445
+ // strings, the per-channel method labeling and the documented cold-open
446
+ // "unknown session" silence are byte-identical to the hand-written sites
447
+ // this replaces.
448
+ const createWarnOnce = (label) => {
449
+ const warned = new Set();
450
+ return (kind, method, detail) => {
451
+ if (warned.has(kind)) return;
452
+ warned.add(kind);
453
+ console.warn(`[weir] ${label} degraded (${kind}${method ? `, ${method}` : ""})`, detail ?? "");
454
+ };
455
+ };
456
+ // Raw-gateway carrier (connection.rpc.call("/api", …)) for the endpoints
457
+ // that cannot mount a typed namespace: ctx.remote.$mount's strict-codec
458
+ // gate rejects src-json codecs, and declaring the namespace in inject
459
+ // would park this fiber forever, so these channels ride the raw gateway
460
+ // (zero session-log events). requireValue marks channels whose callers
461
+ // treat an ok envelope with a null value as a failure (capability reads).
462
+ const createGatewayChannel = ({ label, unavailableMessage, warnOnFailure = false, silentFailure = null, requireValue = false, methodOf = (endpoint) => endpoint }) => {
463
+ const warn = createWarnOnce(label);
464
+ return async (endpoint, payload) => {
465
+ const method = methodOf(endpoint);
466
+ let connection = null;
467
+ try { connection = ctx.get?.("connection") ?? null; } catch { connection = null; }
468
+ if (typeof connection?.rpc?.call !== "function") {
469
+ warn("connection-missing", method, null);
470
+ return { ok: false, error: { code: "channel-unavailable", message: unavailableMessage } };
471
+ }
472
+ let result = null;
473
+ try {
474
+ result = await connection.rpc.call("/api", endpoint, payload);
475
+ } catch (callError) {
476
+ if (warnOnFailure) warn("call-threw", method, callError && (callError.stack || callError.message || String(callError)));
477
+ return { ok: false, error: { code: "call-threw", message: callError instanceof Error ? callError.message : String(callError) } };
478
+ }
479
+ if (result?.ok === true && (!requireValue || result.value != null)) return { ok: true, value: result.value };
480
+ const failure = result?.error ?? result ?? null;
481
+ if (warnOnFailure && !silentFailure?.test(String(failure?.message ?? failure ?? ""))) warn("call-failed", method, failure);
482
+ return {
483
+ ok: false,
484
+ error: {
485
+ code: typeof failure?.code === "string" ? failure.code : "call-failed",
486
+ message: typeof failure?.message === "string" ? failure.message : String(failure ?? "unknown"),
487
+ },
488
+ };
489
+ };
490
+ };
491
+ // Plain HTTP carrier (fetch): the weir-* admin endpoints are ordinary
492
+ // JSON POSTs that need no gateway connection and must work inside chunks
493
+ // (a chunk cannot reach ctx.get("connection")). payload === undefined
494
+ // sends NO body (the status endpoints' wire convention); an object
495
+ // payload crosses as a JSON body. The failure fold keeps every extra
496
+ // error field the server sent (e.g. detail) so consumers lose nothing,
497
+ // and defaults the message to the HTTP status exactly like the
498
+ // hand-written sites did. No warn-once here: every HTTP consumer already
499
+ // surfaces failures inline in its own UI (the settings env read keeps
500
+ // its chunk-side warn-once).
501
+ const createHttpChannel = () => {
502
+ return async (endpoint, payload, options) => {
503
+ let response;
504
+ try {
505
+ response = await fetch(endpoint, {
506
+ method: "POST",
507
+ credentials: "include",
508
+ ...(payload === undefined ? {} : { headers: { "content-type": "application/json" }, body: JSON.stringify(payload) }),
509
+ ...(options?.signal ? { signal: options.signal } : {}),
510
+ });
511
+ } catch (cause) {
512
+ return { ok: false, error: { code: "call-threw", message: cause instanceof Error ? cause.message : String(cause) } };
513
+ }
514
+ let parsed = null;
515
+ try {
516
+ parsed = await response.json();
517
+ } catch (cause) {
518
+ return { ok: false, error: { code: "call-threw", message: cause instanceof Error ? cause.message : String(cause) } };
519
+ }
520
+ if (parsed?.ok === true) return { ok: true, value: parsed.value };
521
+ const failure = parsed?.error;
522
+ return {
523
+ ok: false,
524
+ error: {
525
+ ...(failure !== null && typeof failure === "object" ? failure : {}),
526
+ code: typeof failure?.code === "string" ? failure.code : "call-failed",
527
+ message: typeof failure?.message === "string" ? failure.message : `HTTP ${response.status}`,
528
+ },
529
+ };
530
+ };
531
+ };
532
+ const httpChannel = createHttpChannel();
533
+ const capabilityChannel = createGatewayChannel({
534
+ label: "capability read",
535
+ // Never surfaces: capabilityRead maps every failure to its fallback.
536
+ unavailableMessage: "the capability channel has no gateway connection",
537
+ warnOnFailure: true,
538
+ // unknown-session at cold open is the DOCUMENTED convergence shape
539
+ // (先空后收敛): the Badge may read before the session's agent is
540
+ // registered; the agent-preset/selected frame refetches and
541
+ // converges. Never warn for it — warns are for failures that would
542
+ // otherwise stay invisible.
543
+ silentFailure: /unknown session/,
544
+ requireValue: true,
545
+ methodOf: (endpoint) => endpoint.split("/")[1] ?? endpoint,
546
+ });
547
+ const blackboardChannel = createGatewayChannel({
548
+ label: "blackboard call",
549
+ unavailableMessage: "the blackboard channel has no gateway connection",
550
+ });
551
+ // Host environment-facts endpoint (src/settings/env-admin.js): read
552
+ // once per settings-page arrival over the HTTP channel. A carrier
553
+ // failure rethrows with the carrier's message; an envelope-level or
554
+ // shape failure throws the malformed marker — the chunk-side
555
+ // warn-once reports either exactly as before.
556
+ const fetchEnvFacts = () => httpChannel("api/weir-settings/env", {}).then((result) => {
557
+ if (result.ok === true && typeof result.value?.platform === "string") return { platform: result.value.platform };
558
+ throw new Error(result.error?.code === "call-threw" ? result.error.message : "malformed environment facts response");
559
+ });
1800
560
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), "ui-weir-settings: dictionaries");
1801
561
  // Web notification delivery: the page half of "notify as DeepSeek Harness".
1802
562
  // It long-polls the host for notes the host decided to send and shows
@@ -1807,7 +567,9 @@ window.__ModuleLoader__.load({
1807
567
  let delivery = null;
1808
568
  let live = true;
1809
569
  loadNotifyWebChunk().then((chunk) => {
1810
- if (live) delivery = chunk.startWebDelivery(globalThis);
570
+ // The delivery env is the page's global scope plus the HTTP channel
571
+ // adapter (env injection face; the chunk never touches fetch itself).
572
+ if (live) delivery = chunk.startWebDelivery(Object.assign(Object.create(globalThis), { channel: httpChannel }));
1811
573
  }, () => {});
1812
574
  return () => {
1813
575
  live = false;
@@ -1881,15 +643,9 @@ window.__ModuleLoader__.load({
1881
643
  },
1882
644
  // Structured view: read-only, never written to the conversation.
1883
645
  fetchView: async () => {
1884
- const response = await fetch("api/weir-edit-lock/view", {
1885
- method: "POST",
1886
- credentials: "include",
1887
- headers: { "content-type": "application/json" },
1888
- body: JSON.stringify({ sessionId })
1889
- });
1890
- const payload = await response.json();
1891
- if (!payload?.ok) throw new Error(payload?.error?.message ?? `HTTP ${response.status}`);
1892
- return payload.value;
646
+ const result = await httpChannel("api/weir-edit-lock/view", { sessionId });
647
+ if (!result.ok) throw new Error(result.error.message);
648
+ return result.value;
1893
649
  }
1894
650
  };
1895
651
  }
@@ -1909,26 +665,14 @@ window.__ModuleLoader__.load({
1909
665
  }
1910
666
  };
1911
667
  const worktreeView = async (sessionId) => {
1912
- const response = await fetch("api/weir-worktree/view", {
1913
- method: "POST",
1914
- credentials: "include",
1915
- headers: { "content-type": "application/json" },
1916
- body: JSON.stringify({ sessionId, locale: activeLocale() })
1917
- });
1918
- const payload = await response.json();
1919
- if (!payload?.ok) throw new Error(payload?.error?.message ?? `HTTP ${response.status}`);
1920
- return payload.value;
668
+ const result = await httpChannel("api/weir-worktree/view", { sessionId, locale: activeLocale() });
669
+ if (!result.ok) throw new Error(result.error.message);
670
+ return result.value;
1921
671
  };
1922
672
  const worktreeDiff = async (sessionId, lane) => {
1923
- const response = await fetch("api/weir-worktree/diff", {
1924
- method: "POST",
1925
- credentials: "include",
1926
- headers: { "content-type": "application/json" },
1927
- body: JSON.stringify({ sessionId, lane })
1928
- });
1929
- const payload = await response.json();
1930
- if (!payload?.ok) throw new Error(payload?.error?.message ?? `HTTP ${response.status}`);
1931
- return payload.value?.diff ?? "";
673
+ const result = await httpChannel("api/weir-worktree/diff", { sessionId, lane });
674
+ if (!result.ok) throw new Error(result.error.message);
675
+ return result.value?.diff ?? "";
1932
676
  };
1933
677
  const worktreeRun = async (sessionId, line) => {
1934
678
  if (!ctx.remote.commands?.execute) return { kind: "error", text: "unknown command: /worktree" };
@@ -2059,43 +803,12 @@ window.__ModuleLoader__.load({
2059
803
  // failed call maps to the existing degraded semantics (receipt →
2060
804
  // null → "Capabilities n/a"; listing/conditions → { error: true }).
2061
805
  //
2062
- // Degradation must be observable: the silent-fallback design made a
2063
- // multi-link failure chain invisible for days. Warn once per
2064
- // distinct failure shape per page generation, never per render.
2065
- const capabilityReadWarns = new Set();
2066
- const capabilityReadWarn = (kind, method, detail) => {
2067
- if (capabilityReadWarns.has(kind)) return;
2068
- capabilityReadWarns.add(kind);
2069
- console.warn(`[weir] capability read degraded (${kind}${method ? `, ${method}` : ""})`, detail ?? "");
2070
- };
806
+ // The warn-once degradation (kind strings, unknown-session silence) now
807
+ // lives in the capability channel adapter (composition root, above);
808
+ // this read keeps only its endpoint and its fallback semantics.
2071
809
  const capabilityRead = async (method, sid, fallback) => {
2072
- let connection = null;
2073
- try { connection = ctx.get?.("connection") ?? null; } catch { connection = null; }
2074
- if (typeof connection?.rpc?.call !== "function") {
2075
- capabilityReadWarn("connection-missing", method, null);
2076
- return fallback;
2077
- }
2078
- let result = null;
2079
- try {
2080
- result = await connection.rpc.call("/api", `weirCapabilities/${method}`, { args: { sessionId: sid } });
2081
- } catch (callError) {
2082
- capabilityReadWarn("call-threw", method, callError && (callError.stack || callError.message || String(callError)));
2083
- return fallback;
2084
- }
2085
- // Remote calls resolve to the RemoteResult ENVELOPE — never the
2086
- // bare payload; a failing call resolves { ok: false, error }
2087
- // rather than rejecting (the gateway folds carrier failures).
2088
- if (result?.ok === true && result.value != null) return result.value;
2089
- // unknown-session at cold open is the DOCUMENTED convergence shape
2090
- // (先空后收敛): the Badge may read before the session's agent is
2091
- // registered; the agent-preset/selected frame refetches and
2092
- // converges. Never warn for it — warns are for failures that
2093
- // would otherwise stay invisible.
2094
- const failure = result?.error ?? result ?? null;
2095
- if (!/unknown session/.test(String(failure?.message ?? failure ?? ""))) {
2096
- capabilityReadWarn("call-failed", method, failure);
2097
- }
2098
- return fallback;
810
+ const result = await capabilityChannel(`weirCapabilities/${method}`, { args: { sessionId: sid } });
811
+ return result.ok === true ? result.value : fallback;
2099
812
  };
2100
813
  // The presets & workspace-default view is its own chunk, pulled only
2101
814
  // when the Presets view is first selected (D3) — the composition root
@@ -2155,12 +868,13 @@ window.__ModuleLoader__.load({
2155
868
  react.useEffect(() => {
2156
869
  let alive = true;
2157
870
  Promise.all([require.async("./client.capability-badge.js"), require.async("./client.capability-model.js"), require.async("./client.capability-manager.js")]).then(([badge, model, panel]) => {
871
+ registerChunkDictionaries("settings.weir.capability", model.dictionaries);
2158
872
  if (alive) setImpl(() => ({ Badge: badge.CapabilityBadge, model, Panel: panel.CapabilityManagerPanel }));
2159
873
  });
2160
874
  return () => { alive = false; };
2161
875
  }, [props.sessionId]);
2162
876
  if (!impl) return null;
2163
- return react_jsx_runtime.jsx(impl.Badge, { ...props, model: impl.model, ManagerPanel: impl.Panel });
877
+ return react_jsx_runtime.jsx(impl.Badge, { ...props, t: capabilityT, model: impl.model, ManagerPanel: impl.Panel });
2164
878
  };
2165
879
  ctx.effect(() => ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
2166
880
  name: "conversation.input.right",
@@ -2190,14 +904,17 @@ window.__ModuleLoader__.load({
2190
904
  const loadCapabilityPanelChunks = lazyChunks(() => Promise.all([
2191
905
  require.async("./client.capability-model.js"),
2192
906
  require.async("./client.capability-manager.js")
2193
- ]));
907
+ ]).then((chunks) => {
908
+ registerChunkDictionaries("settings.weir.capability", chunks[0].dictionaries);
909
+ return chunks;
910
+ }));
2194
911
  function CapabilityPanelWrapper(props) {
2195
912
  const arrival = useChunkArrival(loadCapabilityPanelChunks, typeof props.sessionId === "string" && props.sessionId !== "");
2196
913
  if (!arrival?.chunks) return react_jsx_runtime.jsx("div", { style: settingsLoadingStyle, children: typeof props.t === "function" ? props.t("capability.loading") : "" });
2197
914
  const [model, panel] = arrival.chunks;
2198
915
  // The same view tree the composer popover renders — the sidebar is
2199
916
  // just the outer frame (D1). No onClose: the pane chrome owns closing.
2200
- return react_jsx_runtime.jsx(panel.CapabilityManagerPanel, { ...props, model, shell: "sidebar" });
917
+ return react_jsx_runtime.jsx(panel.CapabilityManagerPanel, { ...props, t: capabilityT, model, shell: "sidebar" });
2201
918
  }
2202
919
  ctx.inject?.(["sidebarRightTabs"], (sidebarScope) => {
2203
920
  capabilitySidebarTab = true;
@@ -2234,34 +951,22 @@ window.__ModuleLoader__.load({
2234
951
  // src-json codecs), so the panel calls the RAW gateway exactly like
2235
952
  // the capability reads — POST /api/weirBlackboard/<method>,
2236
953
  // answered with the RemoteResult envelope, zero session log. The
2237
- // pinned wire shape ({ agentId, args }) and the envelope folding are
2238
- // owned by the model chunk's channel factory; this closure only binds
2239
- // the carrier. Degradation warns once per shape per page generation,
2240
- // never per render (the silent-fallback lesson).
2241
- const blackboardCallWarns = new Set();
2242
- const blackboardCallWarn = (kind, method, detail) => {
2243
- if (blackboardCallWarns.has(kind)) return;
2244
- blackboardCallWarns.add(kind);
2245
- console.warn(`[weir] blackboard call degraded (${kind}${method ? `, ${method}` : ""})`, detail ?? "");
2246
- };
2247
- const blackboardRawCall = (endpoint, payload) => {
2248
- let connection = null;
2249
- try { connection = ctx.get?.("connection") ?? null; } catch { connection = null; }
2250
- if (typeof connection?.rpc?.call !== "function") {
2251
- blackboardCallWarn("connection-missing", endpoint, null);
2252
- return Promise.resolve({ ok: false, error: { code: "channel-unavailable", message: "the blackboard channel has no gateway connection" } });
2253
- }
2254
- return connection.rpc.call("/api", endpoint, payload);
2255
- };
954
+ // pinned wire shape ({ agentId, args }) stays owned by the model
955
+ // chunk's channel factory; the carrier, the envelope folding and the
956
+ // warn-once degradation live in the blackboard channel adapter
957
+ // (composition root, above).
2256
958
  const loadBlackboardPanelChunks = lazyChunks(() => Promise.all([
2257
959
  require.async("./client.blackboard-model.js"),
2258
960
  require.async("./client.blackboard-panel.js")
2259
- ]));
961
+ ]).then((chunks) => {
962
+ registerChunkDictionaries("settings.weir.blackboard", chunks[0].dictionaries);
963
+ return chunks;
964
+ }));
2260
965
  function BlackboardPanelWrapper(props) {
2261
966
  const arrival = useChunkArrival(loadBlackboardPanelChunks, typeof props.sessionId === "string" && props.sessionId !== "");
2262
967
  if (!arrival?.chunks) return react_jsx_runtime.jsx("div", { style: settingsLoadingStyle, children: typeof props.t === "function" ? props.t("blackboard.loading") : "" });
2263
968
  const [model, panel] = arrival.chunks;
2264
- return react_jsx_runtime.jsx(panel.BlackboardPanel, { ...props, model });
969
+ return react_jsx_runtime.jsx(panel.BlackboardPanel, { ...props, t: blackboardT, model });
2265
970
  }
2266
971
  // The blackboard panel as a right-sidebar tab — the same optional-
2267
972
  // inject pattern as the worktree/capability panels: a shell without
@@ -2285,7 +990,7 @@ window.__ModuleLoader__.load({
2285
990
  name: "sidebar.right.pane.tab",
2286
991
  key: tabId,
2287
992
  locale: NS,
2288
- inject: (sessionId) => (sessionId ? { sessionId, callBoard: blackboardRawCall } : {})
993
+ inject: (sessionId) => (sessionId ? { sessionId, callBoard: blackboardChannel } : {})
2289
994
  }, BlackboardPanelWrapper), "ui-weir-settings: blackboard panel body");
2290
995
  sidebarScope.effect(() => sidebarScope.slots.register({
2291
996
  name: "sidebar.right.pane.tab.title",
@@ -2362,10 +1067,20 @@ window.__ModuleLoader__.load({
2362
1067
  require.async("./client.notify-permissions.js"),
2363
1068
  require.async("./client.edit-lock-maintenance.js")
2364
1069
  ]).then(([settingsPage, chainEditor, robashEditor, disabledCategoriesEditor, lspPanel, chainModel, robashModel, lspModel, notifyPermissions, editLockMaintenance]) => {
1070
+ // The whole settings card tree shares one t (the page
1071
+ // namespace): every batch chunk's data face merges into ONE
1072
+ // registration — a duplicate (namespace, locale) pair would
1073
+ // throw, so per-feature namespaces are not an option here.
1074
+ const pageDictionaries = { en: {}, zh: {} };
1075
+ for (const chunk of [settingsPage, chainModel, robashModel, lspModel, disabledCategoriesEditor, notifyPermissions, editLockMaintenance]) {
1076
+ Object.assign(pageDictionaries.en, chunk.dictionaries?.en);
1077
+ Object.assign(pageDictionaries.zh, chunk.dictionaries?.zh);
1078
+ }
1079
+ registerChunkDictionaries("settings.weir.page", pageDictionaries);
2365
1080
  if (serving) {
2366
- controller = new settingsPage.WeirCardController(scope, { settingsBus, getSession: () => ctx.remote.session }, "main");
1081
+ controller = new settingsPage.WeirCardController(scope, { settingsBus, getSession: () => ctx.remote.session, fetchEnv: fetchEnvFacts }, "main");
2367
1082
  deferredStore.attach(controller.store);
2368
- routingController = new settingsPage.WeirCardController(scope, { settingsBus, getSession: () => ctx.remote.session }, "routing");
1083
+ routingController = new settingsPage.WeirCardController(scope, { settingsBus, getSession: () => ctx.remote.session, fetchEnv: fetchEnvFacts }, "routing");
2369
1084
  routingDeferredStore.attach(routingController.store);
2370
1085
  }
2371
1086
  // Editor components pre-bound with their model chunks,
@@ -2375,9 +1090,12 @@ window.__ModuleLoader__.load({
2375
1090
  ChainEditorField: (editorProps) => react_jsx_runtime.jsx(chainEditor.ChainEditorField, { ...editorProps, model: chainModel }),
2376
1091
  RobashListEditorField: (editorProps) => react_jsx_runtime.jsx(robashEditor.RobashListEditorField, { ...editorProps, model: robashModel }),
2377
1092
  DisabledCategoriesEditorField: (editorProps) => react_jsx_runtime.jsx(disabledCategoriesEditor.DisabledCategoriesEditorField, editorProps),
2378
- LspManagerField: (editorProps) => react_jsx_runtime.jsx(lspPanel.LspManagerField, { ...editorProps, model: lspModel }),
2379
- NotifyPermissionsField: (editorProps) => react_jsx_runtime.jsx(notifyPermissions.NotifyPermissionsField, editorProps),
2380
- EditLockMaintenanceField: (editorProps) => react_jsx_runtime.jsx(editLockMaintenance.EditLockMaintenanceField, editorProps)
1093
+ LspManagerField: (editorProps) => react_jsx_runtime.jsx(lspPanel.LspManagerField, { ...editorProps, model: lspModel, channel: httpChannel }),
1094
+ // The HTTP channel adapter reaches every fetch-talking editor
1095
+ // through the same prop (composition-root injection: a chunk
1096
+ // never builds its own carrier).
1097
+ NotifyPermissionsField: (editorProps) => react_jsx_runtime.jsx(notifyPermissions.NotifyPermissionsField, { ...editorProps, channel: httpChannel }),
1098
+ EditLockMaintenanceField: (editorProps) => react_jsx_runtime.jsx(editLockMaintenance.EditLockMaintenanceField, { ...editorProps, channel: httpChannel })
2381
1099
  };
2382
1100
  return { settingsPage, editors };
2383
1101
  }, (error) => {
@@ -2412,7 +1130,7 @@ window.__ModuleLoader__.load({
2412
1130
  const cardArrival = useChunkArrival(ensureSettingsChunks);
2413
1131
  const pickerArrival = useChunkArrival(loadModelPickerChunk);
2414
1132
  if (cardArrival?.chunks) {
2415
- return react_jsx_runtime.jsx(cardArrival.chunks.settingsPage.WeirCard, { ...props, page: "routing", editors: cardArrival.chunks.editors, modelPicker: pickerArrival?.chunks });
1133
+ return react_jsx_runtime.jsx(cardArrival.chunks.settingsPage.WeirCard, { ...props, t: pageT, page: "routing", editors: cardArrival.chunks.editors, modelPicker: pickerArrival?.chunks });
2416
1134
  }
2417
1135
  if (cardArrival?.error) {
2418
1136
  return react_jsx_runtime.jsx("div", { style: settingsLoadFailedStyle, children: `${props.t("loadFailed")} ${describeChunkError(cardArrival.error)}` });
@@ -2423,7 +1141,7 @@ window.__ModuleLoader__.load({
2423
1141
  const cardArrival = useChunkArrival(ensureSettingsChunks);
2424
1142
  const pickerArrival = useChunkArrival(loadModelPickerChunk);
2425
1143
  if (cardArrival?.chunks) {
2426
- return react_jsx_runtime.jsx(cardArrival.chunks.settingsPage.WeirCard, { ...props, editors: cardArrival.chunks.editors, modelPicker: pickerArrival?.chunks });
1144
+ return react_jsx_runtime.jsx(cardArrival.chunks.settingsPage.WeirCard, { ...props, t: pageT, editors: cardArrival.chunks.editors, modelPicker: pickerArrival?.chunks });
2427
1145
  }
2428
1146
  if (cardArrival?.error) {
2429
1147
  return react_jsx_runtime.jsx("div", { style: settingsLoadFailedStyle, children: `${props.t("loadFailed")} ${describeChunkError(cardArrival.error)}` });