dsh-decision-layer 0.5.4 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  `dsh-decision-layer` adds structured, explicitly scoped decisions to the DeepSeek Harness (DSH) agent loop, backed by a pluggable adjudication backend. Dangerous-call gating, output self-check, tool narrowing, and loop prevention hook into the agent loop as automatic interventions.
6
6
 
7
- > **0.5.4 is a preview release.** The plugin works, but how much real value the adjudication interventions add is still being explored — every threshold is an unvalidated heuristic default. Treat it as something to observe, not a proven guarantee of impact. See [ROADMAP.md](<ROADMAP.md>) for scope and progress.
7
+ > **0.5.5 is a preview release.** The plugin works, but how much real value the adjudication interventions add is still being explored — every threshold is an unvalidated heuristic default. Treat it as something to observe, not a proven guarantee of impact. See [ROADMAP.md](<ROADMAP.md>) for scope and progress.
8
8
 
9
9
  ## Installation
10
10
 
@@ -49,4 +49,4 @@ Restart `dsh web` and refresh after installing or updating: the host and client
49
49
 
50
50
  ## Safety boundary and development
51
51
 
52
- Automatic intervention only subtracts: the gate only denies, narrowing only removes tools, and neither grants new permissions. The gate defers to native DSH approval on backend failure rather than allowing; self-check, narrowing, and loop-guard errors skip intervention. The redacted summary sent to the backend carries only tool name and command/path with secret redaction — never file content. Node.js `>=20.11`; `npm test` and `npm run build:client` run local checks. Rebuild and commit `lib/client.js` with any client change. 0.5.4 is a preview: the interventions work, but their real value and thresholds are still being explored — feedback on misjudgments and feel observed in the decision log is welcome.
52
+ Automatic intervention only subtracts: the gate only denies, narrowing only removes tools, and neither grants new permissions. The gate defers to native DSH approval on backend failure rather than allowing; self-check, narrowing, and loop-guard errors skip intervention. The redacted summary sent to the backend carries only tool name and command/path with secret redaction — never file content. Node.js `>=20.11`; `npm test` and `npm run build:client` run local checks. Rebuild and commit `lib/client.js` with any client change. 0.5.5 is a preview: the interventions work, but their real value and thresholds are still being explored — feedback on misjudgments and feel observed in the decision log is welcome.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  DeepSeek Harness(DSH)的结构化裁决插件。它把有明确判断标准的问题交给同协议的裁决后端,供 agent 在需要时使用,并在 agent loop 上接入危险门控、产出自检、工具收窄和防循环等自动介入。
6
6
 
7
- > **0.5.4 是体验版。** 插件功能已可用,但裁决介入能带来多少实际价值仍在探索中——各决策点的阈值都是未经验证的启发式默认值,建议先以观察心态体验,别当成经过验证的效果保证。功能与后续进度以 [ROADMAP.md](<ROADMAP.md>) 为准。
7
+ > **0.5.5 是体验版。** 插件功能已可用,但裁决介入能带来多少实际价值仍在探索中——各决策点的阈值都是未经验证的启发式默认值,建议先以观察心态体验,别当成经过验证的效果保证。功能与后续进度以 [ROADMAP.md](<ROADMAP.md>) 为准。
8
8
 
9
9
  ## 安装
10
10
 
@@ -53,4 +53,4 @@ dsh plugin --profile web add file:/绝对路径/dsh-decision-layer
53
53
 
54
54
  ## 开发
55
55
 
56
- 服务端使用 Node.js `>=20.11`(`.mjs`,无需构建);客户端用 TypeScript + esbuild 构建。`npm test` 跑本地测试,`npm run build:client` 生成 `lib/client.js`。改动客户端后需重建并连同 `lib/client.js` 一起提交,否则 GitHub 安装拿到的是旧 bundle。0.5.4 为体验版:介入能力已可用,但实际价值与阈值仍在探索,欢迎反馈决策日志观察到的误判与体感。
56
+ 服务端使用 Node.js `>=20.11`(`.mjs`,无需构建);客户端用 TypeScript + esbuild 构建。`npm test` 跑本地测试,`npm run build:client` 生成 `lib/client.js`。改动客户端后需重建并连同 `lib/client.js` 一起提交,否则 GitHub 安装拿到的是旧 bundle。0.5.5 为体验版:介入能力已可用,但实际价值与阈值仍在探索,欢迎反馈决策日志观察到的误判与体感。
package/lib/client.js CHANGED
@@ -1113,14 +1113,20 @@ function ConfigForm({ t, fetchFn = fetch }) {
1113
1113
  setNarrowOn(features?.narrow !== false);
1114
1114
  setCompleteOn(features?.complete !== false);
1115
1115
  };
1116
- const applyConfig = (value) => {
1116
+ const applyBackend = (value) => {
1117
1117
  setConfig(value);
1118
+ };
1119
+ const applyAdvanced = (value) => {
1118
1120
  setCheckMode(value.checkSettings?.mode ?? "observe");
1119
1121
  setNarrowMode(value.narrowSettings?.mode ?? "enforce");
1120
1122
  setCompleteMode(value.completeSettings?.mode ?? "observe");
1121
1123
  setKeepPrefixes(prefixesText(value.narrowSettings));
1122
1124
  setMaxCandidates(String(maxCandidatesOf(value.narrowSettings)));
1123
1125
  setThreshold(String(thresholdOf(value.narrowSettings)));
1126
+ };
1127
+ const applyConfig = (value) => {
1128
+ applyBackend(value);
1129
+ applyAdvanced(value);
1124
1130
  applyFeatures(value.features);
1125
1131
  };
1126
1132
  (0, import_react4.useEffect)(() => {
@@ -1141,6 +1147,23 @@ function ConfigForm({ t, fetchFn = fetch }) {
1141
1147
  live = false;
1142
1148
  };
1143
1149
  }, [t, fetchFn]);
1150
+ const toggleFeature = async (features, revert) => {
1151
+ setBusy(true);
1152
+ try {
1153
+ const value = await request2("config", fetchFn, {
1154
+ method: "PUT",
1155
+ headers: { "content-type": "application/json" },
1156
+ body: JSON.stringify({ features })
1157
+ });
1158
+ applyFeatures(value.features);
1159
+ } catch {
1160
+ revert();
1161
+ setMessage({ text: t("error"), ok: false });
1162
+ } finally {
1163
+ setBusy(false);
1164
+ }
1165
+ };
1166
+ const featureState = () => ({ gate: gateOn, check: checkOn, narrow: narrowOn, complete: completeOn });
1144
1167
  const saveAdvanced = async (event) => {
1145
1168
  event.preventDefault();
1146
1169
  const parsedCap = Number.parseInt(maxCandidates, 10);
@@ -1155,11 +1178,10 @@ function ConfigForm({ t, fetchFn = fetch }) {
1155
1178
  body: JSON.stringify({
1156
1179
  checkSettings: { mode: checkMode },
1157
1180
  narrowSettings: { mode: narrowMode, keepPrefixes: parsePrefixes(keepPrefixes), maxCandidates: cap, threshold: thresh },
1158
- completeSettings: { mode: completeMode },
1159
- features: { gate: gateOn, check: checkOn, narrow: narrowOn, complete: completeOn }
1181
+ completeSettings: { mode: completeMode }
1160
1182
  })
1161
1183
  });
1162
- applyConfig(value);
1184
+ applyAdvanced(value);
1163
1185
  setAdvancedDirty(false);
1164
1186
  setMessage({ text: t("saved"), ok: true });
1165
1187
  } catch {
@@ -1186,7 +1208,7 @@ ${url}`)) return;
1186
1208
  ...needsHttpConsent ? { confirmHttpUrl: url } : {}
1187
1209
  })
1188
1210
  });
1189
- applyConfig(value);
1211
+ applyBackend(value);
1190
1212
  setKey("");
1191
1213
  setBackendDirty(false);
1192
1214
  setMessage({ text: t("saved"), ok: true });
@@ -1241,10 +1263,10 @@ ${url}`)) return;
1241
1263
  {
1242
1264
  label: t("featureGate"),
1243
1265
  checked: gateOn,
1244
- disabled: !ready,
1266
+ disabled: !ready || busy,
1245
1267
  onChange: (next) => {
1246
1268
  setGateOn(next);
1247
- setAdvancedDirty(true);
1269
+ void toggleFeature({ ...featureState(), gate: next }, () => setGateOn(!next));
1248
1270
  }
1249
1271
  }
1250
1272
  ),
@@ -1254,10 +1276,10 @@ ${url}`)) return;
1254
1276
  {
1255
1277
  label: t("featureCheck"),
1256
1278
  checked: checkOn,
1257
- disabled: !ready,
1279
+ disabled: !ready || busy,
1258
1280
  onChange: (next) => {
1259
1281
  setCheckOn(next);
1260
- setAdvancedDirty(true);
1282
+ void toggleFeature({ ...featureState(), check: next }, () => setCheckOn(!next));
1261
1283
  }
1262
1284
  }
1263
1285
  ),
@@ -1267,10 +1289,10 @@ ${url}`)) return;
1267
1289
  {
1268
1290
  label: t("featureNarrow"),
1269
1291
  checked: narrowOn,
1270
- disabled: !ready,
1292
+ disabled: !ready || busy,
1271
1293
  onChange: (next) => {
1272
1294
  setNarrowOn(next);
1273
- setAdvancedDirty(true);
1295
+ void toggleFeature({ ...featureState(), narrow: next }, () => setNarrowOn(!next));
1274
1296
  }
1275
1297
  }
1276
1298
  ),
@@ -1280,10 +1302,10 @@ ${url}`)) return;
1280
1302
  {
1281
1303
  label: t("featureComplete"),
1282
1304
  checked: completeOn,
1283
- disabled: !ready,
1305
+ disabled: !ready || busy,
1284
1306
  onChange: (next) => {
1285
1307
  setCompleteOn(next);
1286
- setAdvancedDirty(true);
1308
+ void toggleFeature({ ...featureState(), complete: next }, () => setCompleteOn(!next));
1287
1309
  }
1288
1310
  }
1289
1311
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-decision-layer",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "A structured decision layer for the DeepSeek Harness agent loop: a danger-call gate, output self-check, tool narrowing, and loop guard backed by a pluggable adjudication model.",
5
5
  "keywords": [
6
6
  "dsh",