weir-harness 1.1.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.blackboard-model.js +35 -2
- package/lib/client.blackboard-panel.js +61 -9
- package/lib/client.js +254 -223
- package/lib/client.settings-page.js +132 -46
- package/package.json +1 -1
- package/src/blackboard/durable.js +13 -0
- package/src/blackboard/index.js +45 -1
- package/src/blackboard/remote.js +69 -16
- package/src/blackboard/storage.js +56 -0
- package/src/edit-lock/binding-guidance.js +15 -4
- package/src/edit-lock/domain.js +12 -0
- package/src/edit-lock/domains.js +67 -0
- package/src/edit-lock/index.js +209 -45
- package/src/edit-lock/lifecycle.js +70 -4
- package/src/edit-lock/remote.js +23 -4
- package/src/settings/sections.js +25 -16
package/src/settings/sections.js
CHANGED
|
@@ -15,13 +15,16 @@ import { guardOptions } from '../context-guard/pressure.js'
|
|
|
15
15
|
* restart: true marks keys whose consuming module snapshots them once at
|
|
16
16
|
* apply, so a volatile settings commit only takes effect after an app
|
|
17
17
|
* restart (see RESTART_KEYS below).
|
|
18
|
+
* page: false marks keys that never appear on the settings page(s): they
|
|
19
|
+
* stay configurable through the generic config face only (see
|
|
20
|
+
* CONFIG_FACE_ONLY_KEYS below).
|
|
18
21
|
*/
|
|
19
22
|
const FIELDS = [
|
|
20
|
-
{ key: 'intentGateClassifier', section: 'intentGate', field: 'classifier', type: { union: ['regex', 'llm', 'jev'] }, description: 'Intent
|
|
21
|
-
{ key: 'intentGateProvider', section: 'intentGate', field: 'classifierProvider', type: 'string', description: 'Sidecar route override
|
|
23
|
+
{ key: 'intentGateClassifier', section: 'intentGate', field: 'classifier', type: { union: ['regex', 'llm', 'jev'] }, description: 'Intent detection front-end: regex rules (default), llm semantic classification, or experimental jev', restart: true },
|
|
24
|
+
{ key: 'intentGateProvider', section: 'intentGate', field: 'classifierProvider', type: 'string', description: 'Sidecar route override for llm classifier mode; blank follows the session route', restart: true },
|
|
22
25
|
{ key: 'intentGateModel', section: 'intentGate', field: 'classifierModel', type: 'string', description: 'Sidecar model override (llm mode)', restart: true },
|
|
23
26
|
{ key: 'intentGateReasoningEffort', section: 'intentGate', field: 'classifierReasoningEffort', type: 'string', description: 'Sidecar reasoning-effort override (llm mode)', restart: true },
|
|
24
|
-
{ key: 'intentGateTimeoutMs', section: 'intentGate', field: 'classifierTimeoutMs', type: 'number', description: 'Classifier timeout (fail-open)', restart: true },
|
|
27
|
+
{ key: 'intentGateTimeoutMs', section: 'intentGate', field: 'classifierTimeoutMs', type: 'number', description: 'Classifier timeout in ms; on timeout the regex result is used (fail-open)', restart: true },
|
|
25
28
|
{ key: 'jevEndpoint', section: 'intentGate', field: 'jevEndpoint', type: 'string', description: 'Jev decisions endpoint (experimental)', restart: true },
|
|
26
29
|
{ key: 'jevModel', section: 'intentGate', field: 'jevModel', type: 'string', description: 'Jev model name (experimental)', restart: true },
|
|
27
30
|
{ key: 'jevApiKeyEnv', section: 'intentGate', field: 'jevApiKeyEnv', type: 'string', description: 'Env var name holding the Jev API key', restart: true },
|
|
@@ -34,8 +37,8 @@ const FIELDS = [
|
|
|
34
37
|
{ key: 'todoEnabled', section: 'todoDriver', field: 'enabled', type: 'boolean', description: 'Todo continuation driver switch', restart: true },
|
|
35
38
|
{ key: 'todoMaxConsecutive', section: 'todoDriver', field: 'maxConsecutive', type: 'number', description: 'Auto-continuation cap without user input', restart: true },
|
|
36
39
|
{ key: 'todoErrorRetryMax', section: 'todoDriver', field: 'errorRetryMax', type: 'number', description: 'Provider-error retry cap', restart: true },
|
|
37
|
-
{ key: 'todoErrorBackoffBaseMs', section: 'todoDriver', field: 'errorBackoffBaseMs', type: 'number', description: 'Provider-error retry initial backoff (ms)', restart: true },
|
|
38
|
-
{ key: 'todoErrorBackoffCapMs', section: 'todoDriver', field: 'errorBackoffCapMs', type: 'number', description: 'Provider-error retry backoff cap (ms)', restart: true },
|
|
40
|
+
{ key: 'todoErrorBackoffBaseMs', section: 'todoDriver', field: 'errorBackoffBaseMs', type: 'number', description: 'Provider-error retry initial backoff (ms)', restart: true, page: false },
|
|
41
|
+
{ key: 'todoErrorBackoffCapMs', section: 'todoDriver', field: 'errorBackoffCapMs', type: 'number', description: 'Provider-error retry backoff cap (ms)', restart: true, page: false },
|
|
39
42
|
{ key: 'guardEnabled', section: 'contextGuard', field: 'enabled', type: 'boolean', description: 'Context pressure guard switch (live)' },
|
|
40
43
|
{ key: 'guardSoftThreshold', section: 'contextGuard', field: 'softThreshold', type: 'number', description: 'Soft pressure threshold (live advisory; 0 < soft < hard < 1)' },
|
|
41
44
|
{ key: 'guardHardThreshold', section: 'contextGuard', field: 'hardThreshold', type: 'number', description: 'Hard pressure threshold (live maintenance request; not a completion guarantee)' },
|
|
@@ -44,11 +47,11 @@ const FIELDS = [
|
|
|
44
47
|
// Retention (design D1/D2): one lock batch shares one cumulative allowance, so a
|
|
45
48
|
// session reads one expiry instead of N countdowns. These keys are policy, not
|
|
46
49
|
// mechanism: the kernel never sees them, the lifecycle resolves them per call.
|
|
47
|
-
{ key: 'editLockHoldDefaultMinutes', section: 'editLock', field: 'holdDefaultMinutes', type: 'number', description: 'Edit Lock: retention minutes used when a session asks to keep its locks without giving a period (default 30)' },
|
|
48
|
-
{ key: 'editLockHoldSingleMaxMinutes', section: 'editLock', field: 'holdSingleMaxMinutes', type: 'number', description: 'Edit Lock: most minutes one retention request may ask for (default 30)' },
|
|
49
|
-
{ key: 'editLockHoldCumulativeMaxMinutes', section: 'editLock', field: 'holdCumulativeMaxMinutes', type: 'number', description: 'Edit Lock: cumulative retention minutes one batch of locks may use; asks beyond it are refused and only release remains (default 120)' },
|
|
50
|
-
{ key: 'editLockNudgeAttempts', section: 'editLock', field: 'nudgeAttempts', type: 'number', description: 'Edit Lock: how many times a finished turn is continued to ask for still-held locks to be released or retained (default 2)' },
|
|
51
|
-
{ key: 'editLockNudgeFallback', section: 'editLock', field: 'nudgeFallback', type: { union: ['release', 'abnormal'] }, description: 'Edit Lock: disposition of locks still held after those notices are used up; release frees the files for other sessions, abnormal keeps them for the user (default release)' },
|
|
50
|
+
{ key: 'editLockHoldDefaultMinutes', section: 'editLock', field: 'holdDefaultMinutes', type: 'number', description: 'Edit Lock: retention minutes used when a session asks to keep its locks without giving a period (default 30)', page: false },
|
|
51
|
+
{ key: 'editLockHoldSingleMaxMinutes', section: 'editLock', field: 'holdSingleMaxMinutes', type: 'number', description: 'Edit Lock: most minutes one retention request may ask for (default 30)', page: false },
|
|
52
|
+
{ key: 'editLockHoldCumulativeMaxMinutes', section: 'editLock', field: 'holdCumulativeMaxMinutes', type: 'number', description: 'Edit Lock: cumulative retention minutes one batch of locks may use; asks beyond it are refused and only release remains (default 120)', page: false },
|
|
53
|
+
{ key: 'editLockNudgeAttempts', section: 'editLock', field: 'nudgeAttempts', type: 'number', description: 'Edit Lock: how many times a finished turn is continued to ask for still-held locks to be released or retained (default 2)', page: false },
|
|
54
|
+
{ key: 'editLockNudgeFallback', section: 'editLock', field: 'nudgeFallback', type: { union: ['release', 'abnormal'] }, description: 'Edit Lock: disposition of locks still held after those notices are used up; release frees the files for other sessions, abnormal keeps them for the user (default release)', page: false },
|
|
52
55
|
{ key: 'editLockAutoResume', section: 'editLock', field: 'autoResume', type: 'boolean', description: 'Edit Lock: a genuine user message automatically resumes a stopped or administratively revoked session and retries a duplicate-binding failure (default on)' },
|
|
53
56
|
{ key: 'editLockStaleSweep', section: 'editLock', field: 'staleSweep', type: 'boolean', description: 'Edit Lock: a genuine user message silently releases locks whose target file no longer exists (default on; read per message, applies immediately)' },
|
|
54
57
|
{ key: 'robashEnabled', section: 'robash', field: 'enabled', type: 'boolean', description: 'Guarded read-only bash for curated agents (master switch)' },
|
|
@@ -57,12 +60,12 @@ const FIELDS = [
|
|
|
57
60
|
{ key: 'robashDeny', section: 'robash', field: 'deny', type: 'string', list: true, description: 'JSON array of command names to APPEND to the product-default bash deny list (empty adds nothing; the defaults are always in effect)' },
|
|
58
61
|
{ key: 'robashPwshAllow', section: 'robash', field: 'pwshAllow', type: 'string', list: true, description: 'JSON array of command names to APPEND to the product-default pwsh allow list (empty adds nothing; the defaults are always in effect)' },
|
|
59
62
|
{ key: 'robashPwshDeny', section: 'robash', field: 'pwshDeny', type: 'string', list: true, description: 'JSON array of command names to APPEND to the product-default pwsh deny list (empty adds nothing; the defaults are always in effect)' },
|
|
60
|
-
{ key: 'robashDefaultsPath', section: 'robash', field: 'defaultsPath', type: 'string', description: 'Path to a whitelist defaults file that TAKES OVER the shipped one (JSON object keyed by the five robash* table names); empty uses the shipped defaults' },
|
|
61
|
-
{ key: 'robashDefaultsReload', section: 'robash', field: 'defaultsReload', type: 'number', description: 'Bump this number to re-read the whitelist defaults file without restarting (advanced/debug entry)' },
|
|
63
|
+
{ key: 'robashDefaultsPath', section: 'robash', field: 'defaultsPath', type: 'string', description: 'Path to a whitelist defaults file that TAKES OVER the shipped one (JSON object keyed by the five robash* table names); empty uses the shipped defaults', page: false },
|
|
64
|
+
{ key: 'robashDefaultsReload', section: 'robash', field: 'defaultsReload', type: 'number', description: 'Bump this number to re-read the whitelist defaults file without restarting (advanced/debug entry)', page: false },
|
|
62
65
|
{ key: 'lspEnabled', section: 'lsp', field: 'enabled', type: 'boolean', description: 'LSP capability master switch (default off; when on, sessions start with LSP off and toggle it from the session header switch or the lsp tool)' },
|
|
63
|
-
{ key: 'lspIdleMs', section: 'lsp', field: 'idleMs', type: 'number', description: 'LSP server idle shutdown threshold (ms)' },
|
|
64
|
-
{ key: 'lspRequestTimeoutMs', section: 'lsp', field: 'requestTimeoutMs', type: 'number', description: 'LSP request timeout (ms)' },
|
|
65
|
-
{ key: 'lspDiagnosticsWaitMs', section: 'lsp', field: 'diagnosticsWaitMs', type: 'number', description: 'LSP diagnostics publish wait window (ms)' },
|
|
66
|
+
{ key: 'lspIdleMs', section: 'lsp', field: 'idleMs', type: 'number', description: 'LSP server idle shutdown threshold (ms)', page: false },
|
|
67
|
+
{ key: 'lspRequestTimeoutMs', section: 'lsp', field: 'requestTimeoutMs', type: 'number', description: 'LSP request timeout (ms)', page: false },
|
|
68
|
+
{ key: 'lspDiagnosticsWaitMs', section: 'lsp', field: 'diagnosticsWaitMs', type: 'number', description: 'LSP diagnostics publish wait window (ms)', page: false },
|
|
66
69
|
{ key: 'worktreeEnabled', section: 'worktree', field: 'enabled', type: 'boolean', description: 'Worktree lanes capability switch: lane tools, /worktree, Worktree mode, and the lanes panel' },
|
|
67
70
|
{ key: 'worktreeRoot', section: 'worktree', field: 'root', type: 'string', description: 'Repository-relative directory that holds lanes (locally ignored through .git/info/exclude)' },
|
|
68
71
|
{ key: 'worktreeMaxActive', section: 'worktree', field: 'maxActive', type: 'number', description: 'Maximum number of active lanes per repository' },
|
|
@@ -76,7 +79,7 @@ const FIELDS = [
|
|
|
76
79
|
{ key: 'notifyMinTurnSeconds', section: 'notify', field: 'minTurnSeconds', type: 'number', description: 'A finished turn is only reported when it ran at least this many seconds (0 reports every turn)' },
|
|
77
80
|
{ key: 'notifySound', section: 'notify', field: 'sound', type: 'boolean', description: 'Play the platform notification sound where supported' },
|
|
78
81
|
{ key: 'notifyForeground', section: 'notify', field: 'foreground', type: { union: ['skip', 'always'] }, description: 'DeepSeek Harness window in the foreground: skip stays quiet (default), always notifies anyway' },
|
|
79
|
-
{ key: 'blackboardWriteTokenTtlMinutes', section: 'blackboard', field: 'writeTokenTtlMinutes', type: 'number', description: 'Session blackboard write-token TTL (minutes): an acquired write authority expires after this long, the key is released, and its subscribers are notified (default 60)' },
|
|
82
|
+
{ key: 'blackboardWriteTokenTtlMinutes', section: 'blackboard', field: 'writeTokenTtlMinutes', type: 'number', description: 'Session blackboard write-token TTL (minutes): an acquired write authority expires after this long, the key is released, and its subscribers are notified (default 60)', page: false },
|
|
80
83
|
]
|
|
81
84
|
|
|
82
85
|
/** Flat settings keys that only take effect after an app restart: their
|
|
@@ -85,6 +88,12 @@ const FIELDS = [
|
|
|
85
88
|
* settings page keeps a client-side copy pinned to this list by test. */
|
|
86
89
|
export const RESTART_KEYS = Object.freeze(FIELDS.filter(({ restart }) => restart).map(({ key }) => key))
|
|
87
90
|
|
|
91
|
+
/** Flat settings keys that never appear on the settings page(s): advanced or
|
|
92
|
+
* debug-level knobs reachable only through the generic config face. Derived
|
|
93
|
+
* from FIELDS (declared once); the settings page drops exactly these keys
|
|
94
|
+
* from its GROUPS table, pinned by test. */
|
|
95
|
+
export const CONFIG_FACE_ONLY_KEYS = Object.freeze(FIELDS.filter((f) => f.page === false).map((f) => f.key))
|
|
96
|
+
|
|
88
97
|
export { FIELDS }
|
|
89
98
|
|
|
90
99
|
/** Product defaults of the flat settings keys, mirrored from the consuming
|