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.
- package/lib/client.blackboard-model.js +172 -56
- package/lib/client.capability-manager.js +0 -1
- package/lib/client.capability-model.js +378 -31
- package/lib/client.chain-model.js +80 -0
- package/lib/client.disabled-categories-editor.js +22 -0
- package/lib/client.edit-lock-maintenance.js +239 -246
- package/lib/client.edit-lock-panel.js +110 -0
- package/lib/client.hash-edit-model.js +48 -0
- package/lib/client.js +267 -1549
- package/lib/client.lsp-model.js +92 -0
- package/lib/client.lsp-panel.js +11 -16
- package/lib/client.lsp-toggle.js +18 -0
- package/lib/client.notify-permissions.js +112 -20
- package/lib/client.notify-web.js +14 -11
- package/lib/client.robash-model.js +26 -0
- package/lib/client.settings-page.js +287 -17
- package/lib/client.worktree-model.js +225 -0
- package/package.json +1 -1
- package/src/blackboard/durable.js +12 -0
- package/src/blackboard/index.js +2 -2
- package/src/blackboard/kernel.js +23 -6
- package/src/blackboard/notify.js +10 -3
- package/src/blackboard/remote.js +31 -13
- package/src/blackboard/storage.js +13 -5
- package/src/capabilities/apply-engine.js +189 -101
- package/src/capabilities/defaults-transaction.js +136 -1
- package/src/capabilities/lifecycle-snapshot.js +83 -204
- package/src/capabilities/mcp-admission.js +1 -23
- package/src/capabilities/mcp-drain.js +30 -19
- package/src/capabilities/mcp-facade.js +23 -3
- package/src/capabilities/preset-library.js +247 -0
- package/src/capabilities/preset-package.js +212 -1
- package/src/capabilities/same-name-policy.js +3 -41
- package/src/capabilities/selection-notify.js +324 -21
- package/src/capabilities/skill-selection-plugin.js +315 -729
- package/src/capabilities/store/checked-contract.d.ts +5 -0
- package/src/capabilities/store/fs-adapter.js +52 -0
- package/src/capabilities/store/lock.js +86 -0
- package/src/capabilities/store/paths.js +5 -0
- package/src/capabilities/store/store.js +105 -5
- package/src/delegate/group-coordinator.js +1 -17
- package/src/delegate/index.js +4 -2
- package/src/delegate/rehydrate.js +2 -1
- package/src/delegate/robash-guard-core.js +2 -2
- package/src/delegate/supervision-mount.js +5 -4
- package/src/delegate/tool.js +26 -3
- package/src/{shared → delegate}/whitelist-defaults.js +2 -2
- package/src/edit-lock/admin-ledger.js +8 -11
- package/src/edit-lock/admin-recovery.js +2 -1
- package/src/edit-lock/admission.js +12 -2
- package/src/edit-lock/binding-guidance.js +28 -10
- package/src/edit-lock/binding-machine.js +312 -0
- package/src/edit-lock/derived-facts.js +67 -0
- package/src/edit-lock/index.js +44 -244
- package/src/edit-lock/inspect.js +113 -1
- package/src/edit-lock/lifecycle.js +8 -5
- package/src/edit-lock/limits.js +61 -0
- package/src/edit-lock/maintenance.js +5 -2
- package/src/edit-lock/manager.js +6 -2
- package/src/edit-lock/operation-history.js +1 -1
- package/src/edit-lock/peer-client.js +9 -2
- package/src/edit-lock/peer-transport.js +7 -1
- package/src/edit-lock/remote.js +11 -4
- package/src/edit-lock/state.js +2 -4
- package/src/edit-lock/view.js +10 -11
- package/src/lsp/admin.js +2 -24
- package/src/lsp/index.js +1 -1
- package/src/lsp/manager.js +1 -1
- package/src/notify/permissions-admin.js +1 -1
- package/src/{lsp/child-process.js → process/index.js} +12 -4
- package/src/settings/env-admin.js +1 -1
- package/src/settings/index.js +1 -1
- package/src/settings/sections.js +0 -54
- package/src/shared/audit.js +5 -0
- package/src/shared/http-json.js +28 -0
- package/src/{delegate/audit-readers.js → shared/terminal-evidence.js} +34 -4
- package/src/worktree/errors.js +3 -0
- package/src/worktree/index.js +1 -2
- package/src/worktree/lane-core.js +641 -0
- package/src/worktree/lane-views.js +147 -0
- package/src/worktree/lane-workflows.js +853 -0
- package/src/worktree/lanes.js +24 -1513
- package/src/worktree/runner.js +5 -4
- package/src/capabilities/content-pin.js +0 -88
- package/src/capabilities/content-refresh.js +0 -331
- package/src/capabilities/distribution-manifest.js +0 -78
- package/src/capabilities/isolated-exec.js +0 -106
- package/src/capabilities/publisher.js +0 -129
- package/src/capabilities/skill-admission.js +0 -181
- package/src/capabilities/update-lifecycle.js +0 -106
- package/src/edit-lock/remote-service.js +0 -28
- package/src/worktree/contract-guidance.test.js +0 -100
package/lib/client.lsp-model.js
CHANGED
|
@@ -39,6 +39,98 @@ window.__ModuleLoader__.load({
|
|
|
39
39
|
if (parts.length === 0) return undefined;
|
|
40
40
|
return { command: parts[0], args: parts.slice(1) };
|
|
41
41
|
}
|
|
42
|
+
// Locale data face (pure data, NO ctx calls — a chunk factory re-executes
|
|
43
|
+
// under HMR, so a chunk-local register would throw on the duplicate
|
|
44
|
+
// (namespace, locale) pair): the entry registers these under "settings.weir.page"
|
|
45
|
+
// inside a ctx.effect when this chunk arrives (lib/client.js
|
|
46
|
+
// registerChunkDictionaries). Pinned by test/client.test.js's dictionary
|
|
47
|
+
// union pin.
|
|
48
|
+
// (The entry merges every settings-batch slice into the single "settings.weir.page"
|
|
49
|
+
// registration — the whole settings card tree shares one t.)
|
|
50
|
+
const dictionaries = {
|
|
51
|
+
en: {
|
|
52
|
+
lspManager: "Manage LSP services",
|
|
53
|
+
lspManagerHint: "Check which language servers are installed and install the missing ones from the community catalog.",
|
|
54
|
+
lspManagerLoading: "Loading…",
|
|
55
|
+
lspManagerFailed: "The LSP manager failed; check the runtime log.",
|
|
56
|
+
lspManagerUnavailable: "LSP management endpoints unavailable in this deployment:",
|
|
57
|
+
lspManagerRetry: "Retry",
|
|
58
|
+
lspManagerInstall: "Install",
|
|
59
|
+
lspManagerCancel: "Cancel",
|
|
60
|
+
lspManagerConfirmInstall: "Run install",
|
|
61
|
+
lspManagerInstalling: "Installing…",
|
|
62
|
+
lspManagerInstalled: "Installed",
|
|
63
|
+
lspManagerMissing: "Not installed",
|
|
64
|
+
lspManagerExitCode: "Exit code",
|
|
65
|
+
lspManagerTimedOut: "(timed out)",
|
|
66
|
+
lspManagerCustom: "Custom servers",
|
|
67
|
+
lspManagerCustomHint: "Add your own language servers; saved with the settings and detected on the next status load.",
|
|
68
|
+
lspManagerAddServer: "Add server",
|
|
69
|
+
lspManagerRemove: "Remove",
|
|
70
|
+
lspManagerFamily: "family name",
|
|
71
|
+
lspManagerCommand: "command",
|
|
72
|
+
lspManagerArgs: "args (space separated)",
|
|
73
|
+
lspManagerInstallCmd: "install command (optional)",
|
|
74
|
+
lspManagerPendingStatus: "detected after save",
|
|
75
|
+
lspManagerInstallerMissing: "Installer unavailable: install it first, then retry.",
|
|
76
|
+
lspManagerInvalidJson: "The stored custom-servers JSON is malformed; the panel opened with an empty list — saving replaces the stored value.",
|
|
77
|
+
lspFamily_typescript: "TypeScript",
|
|
78
|
+
lspFamily_python: "Python",
|
|
79
|
+
lspFamily_go: "Go",
|
|
80
|
+
lspFamily_rust: "Rust",
|
|
81
|
+
lspFamily_json: "JSON",
|
|
82
|
+
lspFamily_html: "HTML",
|
|
83
|
+
lspFamily_css: "CSS",
|
|
84
|
+
lspFamily_markdown: "Markdown",
|
|
85
|
+
lspFamily_bash: "Bash",
|
|
86
|
+
lspFamily_dockerfile: "Dockerfile",
|
|
87
|
+
lspFamily_yaml: "YAML",
|
|
88
|
+
lspFamily_lua: "Lua",
|
|
89
|
+
lspFamily_cpp: "C/C++",
|
|
90
|
+
},
|
|
91
|
+
zh: {
|
|
92
|
+
lspManager: "管理 LSP 服务",
|
|
93
|
+
lspManagerHint: "查看各语言服务器安装状态,一键安装缺失的社区服务器。",
|
|
94
|
+
lspManagerLoading: "加载中…",
|
|
95
|
+
lspManagerFailed: "LSP 管理面板异常,请查看运行时日志。",
|
|
96
|
+
lspManagerUnavailable: "此部署不提供 LSP 管理端点:",
|
|
97
|
+
lspManagerRetry: "重试",
|
|
98
|
+
lspManagerInstall: "安装",
|
|
99
|
+
lspManagerCancel: "取消",
|
|
100
|
+
lspManagerConfirmInstall: "确认安装",
|
|
101
|
+
lspManagerInstalling: "安装中…",
|
|
102
|
+
lspManagerInstalled: "已安装",
|
|
103
|
+
lspManagerMissing: "未安装",
|
|
104
|
+
lspManagerExitCode: "退出码",
|
|
105
|
+
lspManagerTimedOut: "(超时)",
|
|
106
|
+
lspManagerCustom: "自定义服务器",
|
|
107
|
+
lspManagerCustomHint: "添加你自己的语言服务器;随设置保存,下次状态加载时检测。",
|
|
108
|
+
lspManagerAddServer: "添加服务器",
|
|
109
|
+
lspManagerRemove: "删除",
|
|
110
|
+
lspManagerFamily: "族名",
|
|
111
|
+
lspManagerCommand: "命令",
|
|
112
|
+
lspManagerArgs: "参数(空格分隔)",
|
|
113
|
+
lspManagerInstallCmd: "安装命令(可空)",
|
|
114
|
+
lspManagerPendingStatus: "保存后检测",
|
|
115
|
+
lspManagerInstallerMissing: "安装器不可用:请先安装安装器,再重试。",
|
|
116
|
+
lspManagerInvalidJson: "已保存的自定义服务器 JSON 格式有误;面板已以空列表打开——保存将覆盖该值。",
|
|
117
|
+
lspFamily_typescript: "TypeScript",
|
|
118
|
+
lspFamily_python: "Python",
|
|
119
|
+
lspFamily_go: "Go",
|
|
120
|
+
lspFamily_rust: "Rust",
|
|
121
|
+
lspFamily_json: "JSON",
|
|
122
|
+
lspFamily_html: "HTML",
|
|
123
|
+
lspFamily_css: "CSS",
|
|
124
|
+
lspFamily_markdown: "Markdown",
|
|
125
|
+
lspFamily_bash: "Bash",
|
|
126
|
+
lspFamily_dockerfile: "Dockerfile",
|
|
127
|
+
lspFamily_yaml: "YAML",
|
|
128
|
+
lspFamily_lua: "Lua",
|
|
129
|
+
lspFamily_cpp: "C/C++",
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
exports.dictionaries = dictionaries;
|
|
42
134
|
exports.jsonToLspServers = jsonToLspServers;
|
|
43
135
|
exports.lspServersJsonValid = lspServersJsonValid;
|
|
44
136
|
exports.lspServersToJson = lspServersToJson;
|
package/lib/client.lsp-panel.js
CHANGED
|
@@ -9,8 +9,10 @@ window.__ModuleLoader__.load({
|
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
10
|
let primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
11
11
|
// LSP service manager panel: status over the catalog + one-click
|
|
12
|
-
// install + custom servers, talking to the host over
|
|
13
|
-
//
|
|
12
|
+
// install + custom servers, talking to the host over the composition
|
|
13
|
+
// root's HTTP channel adapter (props.channel: (endpoint, payload?) =>
|
|
14
|
+
// Promise<{ ok: true, value } | { ok: false, error }>, never rejecting;
|
|
15
|
+
// "/api/weir-lsp/*"). The lsp model trio (client.lsp-model.js) and
|
|
14
16
|
// `t` arrive via props. Style constants are verbatim copies of the
|
|
15
17
|
// settings-page constants this panel uses (same-package sync require
|
|
16
18
|
// is impossible in the ModuleLoader).
|
|
@@ -63,10 +65,9 @@ window.__ModuleLoader__.load({
|
|
|
63
65
|
const serversInvalid = model.lspServersJsonValid(props.serversText) === false;
|
|
64
66
|
const load = () => {
|
|
65
67
|
setView({ status: "loading" });
|
|
66
|
-
|
|
67
|
-
.then((
|
|
68
|
-
|
|
69
|
-
setView(payload?.ok ? { status: "ready", servers: payload.value.servers } : { status: "error", message: payload?.error?.message ?? "unknown" });
|
|
68
|
+
props.channel("api/weir-lsp/status")
|
|
69
|
+
.then((result) => {
|
|
70
|
+
setView(result.ok === true ? { status: "ready", servers: result.value.servers } : { status: "error", message: result.error.message });
|
|
70
71
|
})
|
|
71
72
|
.catch((error) => setView({ status: "error", message: String(error?.message ?? error) }));
|
|
72
73
|
};
|
|
@@ -81,17 +82,11 @@ window.__ModuleLoader__.load({
|
|
|
81
82
|
setConfirming(null);
|
|
82
83
|
setBusy(family);
|
|
83
84
|
setResult(null);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
credentials: "include",
|
|
87
|
-
headers: { "content-type": "application/json" },
|
|
88
|
-
body: JSON.stringify({ family })
|
|
89
|
-
})
|
|
90
|
-
.then((response) => response.json())
|
|
91
|
-
.then((payload) => {
|
|
85
|
+
props.channel("api/weir-lsp/install", { family })
|
|
86
|
+
.then((result) => {
|
|
92
87
|
setBusy(null);
|
|
93
|
-
setResult(
|
|
94
|
-
if (
|
|
88
|
+
setResult(result.ok === true ? { family, output: result.value.output, exitCode: result.value.exitCode, timedOut: result.value.timedOut } : { family, error: result.error.message });
|
|
89
|
+
if (result.ok === true) load();
|
|
95
90
|
})
|
|
96
91
|
.catch((error) => {
|
|
97
92
|
setBusy(null);
|
package/lib/client.lsp-toggle.js
CHANGED
|
@@ -113,6 +113,24 @@ window.__ModuleLoader__.load({
|
|
|
113
113
|
]
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
|
+
// Locale data face (pure data, NO ctx calls — a chunk factory re-executes
|
|
117
|
+
// under HMR, so a chunk-local register would throw on the duplicate
|
|
118
|
+
// (namespace, locale) pair): the entry registers these under "settings.weir.lsp-toggle"
|
|
119
|
+
// inside a ctx.effect when this chunk arrives (lib/client.js
|
|
120
|
+
// registerChunkDictionaries). Pinned by test/client.test.js's dictionary
|
|
121
|
+
// union pin.
|
|
122
|
+
const dictionaries = {
|
|
123
|
+
en: {
|
|
124
|
+
lspToggleLabel: "LSP",
|
|
125
|
+
lspToggleTitle: "Toggle LSP semantic tools for this session",
|
|
126
|
+
},
|
|
127
|
+
zh: {
|
|
128
|
+
lspToggleLabel: "LSP",
|
|
129
|
+
lspToggleTitle: "为本会话启用/禁用 LSP 语义工具",
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
exports.dictionaries = dictionaries;
|
|
116
134
|
exports.LSP_PROJECTION_KEY = LSP_PROJECTION_KEY;
|
|
117
135
|
exports.LspToggle = LspToggle;
|
|
118
136
|
return module.exports;
|
|
@@ -11,8 +11,10 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
// macOS notification permission panel: an entry row plus a modal that
|
|
12
12
|
// detects the permission and walks the user through allowing it. The
|
|
13
13
|
// host decides everything (platform, state, actions) over
|
|
14
|
-
// "api/weir-notify/permissions/*"
|
|
15
|
-
//
|
|
14
|
+
// "api/weir-notify/permissions/*" via the composition root's HTTP
|
|
15
|
+
// channel adapter (props.channel: (endpoint, payload?) => Promise<
|
|
16
|
+
// { ok: true, value } | { ok: false, error }>, never rejecting); this
|
|
17
|
+
// chunk only renders the answer and calls the two whitelisted actions. The entry renders NOTHING until
|
|
16
18
|
// the host confirms it is macOS, so other platforms never see it. Style
|
|
17
19
|
// constants are verbatim copies of the settings-page ones (same-package
|
|
18
20
|
// sync require is impossible in the ModuleLoader).
|
|
@@ -56,14 +58,6 @@ window.__ModuleLoader__.load({
|
|
|
56
58
|
return "wait";
|
|
57
59
|
}
|
|
58
60
|
const INITIAL_FLOW = { testSent: false, settingsOpened: false, seen: null };
|
|
59
|
-
function post(path, body) {
|
|
60
|
-
return fetch(path, {
|
|
61
|
-
method: "POST",
|
|
62
|
-
credentials: "include",
|
|
63
|
-
headers: { "content-type": "application/json" },
|
|
64
|
-
body: JSON.stringify(body ?? {})
|
|
65
|
-
}).then((response) => response.json());
|
|
66
|
-
}
|
|
67
61
|
const messageOf = (error) => String(error?.message ?? error);
|
|
68
62
|
/**
|
|
69
63
|
* The page's own web-notification permission, read-only. Delivery itself
|
|
@@ -123,14 +117,14 @@ window.__ModuleLoader__.load({
|
|
|
123
117
|
// Resolves the fresh host status, or null when it could not be read.
|
|
124
118
|
const load = () => {
|
|
125
119
|
setChecking(true);
|
|
126
|
-
return
|
|
120
|
+
return props.channel(STATUS_PATH, {}).then((result) => {
|
|
127
121
|
setChecking(false);
|
|
128
|
-
if (
|
|
129
|
-
setHost(
|
|
122
|
+
if (result.ok === true && result.value?.supported) {
|
|
123
|
+
setHost(result.value);
|
|
130
124
|
setError(null);
|
|
131
|
-
return
|
|
125
|
+
return result.value;
|
|
132
126
|
}
|
|
133
|
-
setError(
|
|
127
|
+
setError(result.error?.message ?? "unknown");
|
|
134
128
|
return null;
|
|
135
129
|
}).catch((failure) => {
|
|
136
130
|
setChecking(false);
|
|
@@ -139,8 +133,8 @@ window.__ModuleLoader__.load({
|
|
|
139
133
|
});
|
|
140
134
|
};
|
|
141
135
|
react.useEffect(() => {
|
|
142
|
-
|
|
143
|
-
(
|
|
136
|
+
props.channel(STATUS_PATH, {}).then(
|
|
137
|
+
(result) => setHost(result.ok === true && result.value?.supported ? result.value : { supported: false }),
|
|
144
138
|
() => setHost({ supported: false })
|
|
145
139
|
);
|
|
146
140
|
return stopPolling;
|
|
@@ -183,10 +177,10 @@ window.__ModuleLoader__.load({
|
|
|
183
177
|
setError(null);
|
|
184
178
|
// Ask for the page permission inside this click (the only place a browser shows the prompt).
|
|
185
179
|
const ready = action === "test" ? requestWebPermission(globalThis).then(() => setPermTick((tick) => tick + 1)) : Promise.resolve();
|
|
186
|
-
ready.then(() =>
|
|
180
|
+
ready.then(() => props.channel(ACTION_PATH, { action })).then((result) => {
|
|
187
181
|
setBusy(null);
|
|
188
|
-
if (
|
|
189
|
-
setError(
|
|
182
|
+
if (result.ok !== true) {
|
|
183
|
+
setError(result.error?.message ?? "unknown");
|
|
190
184
|
return;
|
|
191
185
|
}
|
|
192
186
|
setFlow((current) => action === "test"
|
|
@@ -295,6 +289,104 @@ window.__ModuleLoader__.load({
|
|
|
295
289
|
function NotifyPermissionsField(props) {
|
|
296
290
|
return react_jsx_runtime.jsx(NotifyPermissionsBoundary, { t: props.t, children: react_jsx_runtime.jsx(NotifyPermissionsPanel, props) });
|
|
297
291
|
}
|
|
292
|
+
// Locale data face (pure data, NO ctx calls — a chunk factory re-executes
|
|
293
|
+
// under HMR, so a chunk-local register would throw on the duplicate
|
|
294
|
+
// (namespace, locale) pair): the entry registers these under "settings.weir.page"
|
|
295
|
+
// inside a ctx.effect when this chunk arrives (lib/client.js
|
|
296
|
+
// registerChunkDictionaries). Pinned by test/client.test.js's dictionary
|
|
297
|
+
// union pin.
|
|
298
|
+
// (The entry merges every settings-batch slice into the single "settings.weir.page"
|
|
299
|
+
// registration — the whole settings card tree shares one t.)
|
|
300
|
+
const dictionaries = {
|
|
301
|
+
en: {
|
|
302
|
+
notifyPermissions: "Notification permission",
|
|
303
|
+
notifyPermissionsHint: "Check whether macOS lets these notifications through, and walk through allowing them.",
|
|
304
|
+
notifyPermissionsOpen: "Manage",
|
|
305
|
+
notifyPermTitle: "Notification permission",
|
|
306
|
+
notifyPermDescription: "Notifications are shown by DeepSeek Harness itself, so macOS has to let DeepSeek Harness notify you.",
|
|
307
|
+
notifyPermClose: "Close",
|
|
308
|
+
notifyPermChecking: "Checking…",
|
|
309
|
+
notifyPermRecheck: "Check again",
|
|
310
|
+
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.",
|
|
311
|
+
notifyPermFocusNote: "Focus / Do Not Disturb can still hold notifications back, and it cannot be checked from here.",
|
|
312
|
+
notifyPermSendTest: "Send a test notification",
|
|
313
|
+
notifyPermSending: "Sending…",
|
|
314
|
+
notifyPermOpenSettings: "Open notification settings",
|
|
315
|
+
notifyPermOpening: "Opening…",
|
|
316
|
+
notifyPermOpenHint: "In the list, find “DeepSeek Harness”, turn on “Allow notifications”, and pick the Banners or Alerts style.",
|
|
317
|
+
notifyPermWaiting: "Waiting for you to allow notifications… checking every 2 seconds.",
|
|
318
|
+
notifyPermConfirm: "Did you see the test notification?",
|
|
319
|
+
notifyPermSeenYes: "Yes, I saw it",
|
|
320
|
+
notifyPermSeenNo: "No",
|
|
321
|
+
notifyPermSeen: "All set — notifications will reach you.",
|
|
322
|
+
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.",
|
|
323
|
+
notifyPermRetry: "Start over",
|
|
324
|
+
notifyPermSendAgain: "Send another test",
|
|
325
|
+
notifyPermError: "Something went wrong:",
|
|
326
|
+
notifyPermManualPath: "You can do this by hand: System Settings → Notifications → DeepSeek Harness.",
|
|
327
|
+
notifyPermDetails: "Technical details",
|
|
328
|
+
notifyPermFailed: "The permission panel failed; check the runtime log.",
|
|
329
|
+
"notifyPermState_granted": "Allowed",
|
|
330
|
+
"notifyPermState_denied": "Not allowed",
|
|
331
|
+
"notifyPermState_unknown": "Can't tell",
|
|
332
|
+
"notifyPermReason_alerts-allowed": "Alerts are allowed for DeepSeek Harness.",
|
|
333
|
+
"notifyPermReason_not-allowed": "Notifications are turned off for DeepSeek Harness.",
|
|
334
|
+
"notifyPermReason_no-record": "macOS has no record of DeepSeek Harness yet. Send a test notification so it shows up in the list.",
|
|
335
|
+
"notifyPermReason_default": "macOS has no explicit setting for DeepSeek Harness (it uses the system default), so this can't be told from here.",
|
|
336
|
+
"notifyPermReason_unreadable": "The notification settings could not be read.",
|
|
337
|
+
notifyWebUnsupported: "This page has no web Notification support, so DeepSeek Harness cannot notify directly.",
|
|
338
|
+
notifyWebPermission: "Web notification permission",
|
|
339
|
+
notifyWebDeniedHint: "This page was blocked from showing notifications and cannot ask again. Open System Settings → Notifications → DeepSeek Harness and turn notifications on.",
|
|
340
|
+
"notifyWebPerm_granted": "Allowed",
|
|
341
|
+
"notifyWebPerm_denied": "Blocked",
|
|
342
|
+
"notifyWebPerm_default": "Not asked yet",
|
|
343
|
+
},
|
|
344
|
+
zh: {
|
|
345
|
+
notifyPermissions: "通知权限",
|
|
346
|
+
notifyPermissionsHint: "检测 macOS 是否放行这些通知,并引导你完成授权。",
|
|
347
|
+
notifyPermissionsOpen: "管理",
|
|
348
|
+
notifyPermTitle: "通知权限",
|
|
349
|
+
notifyPermDescription: "通知由 DeepSeek Harness 自己弹出,所以需要在 macOS 里允许 DeepSeek Harness 发送通知。",
|
|
350
|
+
notifyPermClose: "关闭",
|
|
351
|
+
notifyPermChecking: "检测中…",
|
|
352
|
+
notifyPermRecheck: "重新检测",
|
|
353
|
+
notifyPermBestEffort: "该检测读取的是苹果未公开文档化的系统设置,仅供参考;亲眼看到测试通知才是最终证明。",
|
|
354
|
+
notifyPermFocusNote: "专注模式 / 勿扰仍可能拦截通知,且无法在这里检测。",
|
|
355
|
+
notifyPermSendTest: "发送测试通知",
|
|
356
|
+
notifyPermSending: "发送中…",
|
|
357
|
+
notifyPermOpenSettings: "打开系统通知设置",
|
|
358
|
+
notifyPermOpening: "打开中…",
|
|
359
|
+
notifyPermOpenHint: "在列表中找到「DeepSeek Harness」,打开「允许通知」,并选择「横幅」或「提醒」样式。",
|
|
360
|
+
notifyPermWaiting: "正在等你允许通知…每 2 秒自动检测一次。",
|
|
361
|
+
notifyPermConfirm: "你看到测试通知了吗?",
|
|
362
|
+
notifyPermSeenYes: "看到了",
|
|
363
|
+
notifyPermSeenNo: "没看到",
|
|
364
|
+
notifyPermSeen: "设置完成,通知会送达你。",
|
|
365
|
+
notifyPermNotSeen: "请确认专注模式 / 勿扰已关闭,「DeepSeek Harness」的样式是「横幅」或「提醒」,并且(若窗口在前台)「窗口在前台时」已设为「始终通知」,然后重试。",
|
|
366
|
+
notifyPermRetry: "重新开始",
|
|
367
|
+
notifyPermSendAgain: "再发一条测试",
|
|
368
|
+
notifyPermError: "出错了:",
|
|
369
|
+
notifyPermManualPath: "也可以手动操作:系统设置 → 通知 → DeepSeek Harness。",
|
|
370
|
+
notifyPermDetails: "技术细节",
|
|
371
|
+
notifyPermFailed: "权限面板出错,请查看运行日志。",
|
|
372
|
+
"notifyPermState_granted": "已允许",
|
|
373
|
+
"notifyPermState_denied": "未允许",
|
|
374
|
+
"notifyPermState_unknown": "无法判定",
|
|
375
|
+
"notifyPermReason_alerts-allowed": "已允许「DeepSeek Harness」弹出提醒。",
|
|
376
|
+
"notifyPermReason_not-allowed": "「DeepSeek Harness」的通知已被关闭。",
|
|
377
|
+
"notifyPermReason_no-record": "macOS 里还没有「DeepSeek Harness」的记录。先发一条测试通知,让它出现在列表里。",
|
|
378
|
+
"notifyPermReason_default": "macOS 里没有「DeepSeek Harness」的明确设置(沿用系统默认),无法在这里判定。",
|
|
379
|
+
"notifyPermReason_unreadable": "无法读取通知设置。",
|
|
380
|
+
notifyWebUnsupported: "当前页面没有网页通知能力,DeepSeek Harness 无法直接通知。",
|
|
381
|
+
notifyWebPermission: "网页通知权限",
|
|
382
|
+
notifyWebDeniedHint: "本页面被禁止显示通知,且无法再次询问。请打开「系统设置 → 通知 → DeepSeek Harness」并开启通知。",
|
|
383
|
+
"notifyWebPerm_granted": "已允许",
|
|
384
|
+
"notifyWebPerm_denied": "已禁止",
|
|
385
|
+
"notifyWebPerm_default": "尚未询问",
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
exports.dictionaries = dictionaries;
|
|
298
390
|
exports.LABEL_KEYS = LABEL_KEYS;
|
|
299
391
|
exports.webNotificationSupport = webNotificationSupport;
|
|
300
392
|
exports.requestWebPermission = requestWebPermission;
|
package/lib/client.notify-web.js
CHANGED
|
@@ -87,10 +87,13 @@ window.__ModuleLoader__.load({
|
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
89
|
* Start the long-poll loop. Returns { stop, stats }. `env` is injectable:
|
|
90
|
-
* {
|
|
90
|
+
* { channel, Notification, document, setTimeout, clearTimeout } — channel
|
|
91
|
+
* is the composition root's HTTP channel adapter ((endpoint, payload,
|
|
92
|
+
* { signal }) => Promise<{ ok, value | error }>, never rejecting; a
|
|
93
|
+
* carrier throw arrives folded as error.code "call-threw").
|
|
91
94
|
*/
|
|
92
95
|
function startWebDelivery(env) {
|
|
93
|
-
const
|
|
96
|
+
const channel = env.channel;
|
|
94
97
|
const wait = env.setTimeout ?? globalThis.setTimeout;
|
|
95
98
|
const unwait = env.clearTimeout ?? globalThis.clearTimeout;
|
|
96
99
|
const open = new Map();
|
|
@@ -99,13 +102,7 @@ window.__ModuleLoader__.load({
|
|
|
99
102
|
let failures = 0;
|
|
100
103
|
let controller = null;
|
|
101
104
|
let sleeper = null;
|
|
102
|
-
const post = (path, body, signal) =>
|
|
103
|
-
method: "POST",
|
|
104
|
-
credentials: "include",
|
|
105
|
-
headers: { "content-type": "application/json" },
|
|
106
|
-
body: JSON.stringify(body ?? {}),
|
|
107
|
-
signal
|
|
108
|
-
}).then((response) => response.json());
|
|
105
|
+
const post = (path, body, signal) => channel(path, body ?? {}, { signal });
|
|
109
106
|
const sleep = (ms) => new Promise((resolve) => {
|
|
110
107
|
sleeper = wait(resolve, ms);
|
|
111
108
|
});
|
|
@@ -114,6 +111,10 @@ window.__ModuleLoader__.load({
|
|
|
114
111
|
try {
|
|
115
112
|
controller = typeof AbortController === "function" ? new AbortController() : null;
|
|
116
113
|
const payload = await post(PULL_PATH, {}, controller?.signal);
|
|
114
|
+
// A folded carrier failure (call-threw) throws BEFORE stats.pulls++
|
|
115
|
+
// exactly like the old rejecting post did; an envelope failure
|
|
116
|
+
// counts as an answered pull, then throws.
|
|
117
|
+
if (payload?.error?.code === "call-threw") throw new Error(payload.error.message);
|
|
117
118
|
stats.pulls++;
|
|
118
119
|
if (!payload?.ok) throw new Error(payload?.error?.message ?? "pull failed");
|
|
119
120
|
failures = 0;
|
|
@@ -122,8 +123,10 @@ window.__ModuleLoader__.load({
|
|
|
122
123
|
const result = await showNote(env, pulled.note, open);
|
|
123
124
|
if (result === "shown") stats.shown++;
|
|
124
125
|
// The ACK must not be able to wedge the loop.
|
|
125
|
-
post(ACK_PATH, { id: pulled.id, result: RESULTS.includes(result) ? result : "error" }).
|
|
126
|
-
|
|
126
|
+
post(ACK_PATH, { id: pulled.id, result: RESULTS.includes(result) ? result : "error" }).then((ackResult) => {
|
|
127
|
+
// The folded call-threw stands in for the old rejection (the only
|
|
128
|
+
// shape the .catch counted); an envelope failure was ignored then.
|
|
129
|
+
if (ackResult?.error?.code === "call-threw") stats.failures++;
|
|
127
130
|
});
|
|
128
131
|
}
|
|
129
132
|
} catch {
|
|
@@ -31,6 +31,32 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
function stringListToJson(list) {
|
|
32
32
|
return JSON.stringify((list ?? []).map((entry) => entry.trim()).filter((entry) => entry.length > 0));
|
|
33
33
|
}
|
|
34
|
+
// Locale data face (pure data, NO ctx calls — a chunk factory re-executes
|
|
35
|
+
// under HMR, so a chunk-local register would throw on the duplicate
|
|
36
|
+
// (namespace, locale) pair): the entry registers these under "settings.weir.page"
|
|
37
|
+
// inside a ctx.effect when this chunk arrives (lib/client.js
|
|
38
|
+
// registerChunkDictionaries). Pinned by test/client.test.js's dictionary
|
|
39
|
+
// union pin.
|
|
40
|
+
// (The entry merges every settings-batch slice into the single "settings.weir.page"
|
|
41
|
+
// registration — the whole settings card tree shares one t.)
|
|
42
|
+
const dictionaries = {
|
|
43
|
+
en: {
|
|
44
|
+
robashListEntries: "entries",
|
|
45
|
+
robashListAdd: "Add entry",
|
|
46
|
+
robashListInvalid: "The stored value is not a valid command list; the editor opened empty — saving replaces it.",
|
|
47
|
+
robashListPanelHint: "One command name per row; entries are added to the built-in list, which always applies — an empty list adds nothing.",
|
|
48
|
+
robashListEntryPlaceholder: "command name",
|
|
49
|
+
},
|
|
50
|
+
zh: {
|
|
51
|
+
robashListEntries: "条目",
|
|
52
|
+
robashListAdd: "添加条目",
|
|
53
|
+
robashListInvalid: "已保存的值不是有效的命令清单;编辑器已以空列表打开,保存将覆盖该值。",
|
|
54
|
+
robashListPanelHint: "每行一个命令名;条目追加到内置清单,内置清单始终生效——空列表即不追加。",
|
|
55
|
+
robashListEntryPlaceholder: "命令名",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
exports.dictionaries = dictionaries;
|
|
34
60
|
exports.jsonToStringList = jsonToStringList;
|
|
35
61
|
exports.robashEditorOpenState = robashEditorOpenState;
|
|
36
62
|
exports.stringListToJson = stringListToJson;
|