dsh-plugin-rollout-scout 1.4.0 → 1.4.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/README.en.md CHANGED
@@ -3,8 +3,9 @@
3
3
  English | [简体中文](README.md)
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/dsh-plugin-rollout-scout?color=cb3837&logo=npm)](https://www.npmjs.com/package/dsh-plugin-rollout-scout)
6
+ [![CI](https://github.com/SpookySandwich/dsh-plugin-rollout-scout/actions/workflows/ci.yml/badge.svg)](https://github.com/SpookySandwich/dsh-plugin-rollout-scout/actions/workflows/ci.yml)
6
7
  [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
- [![dsh](https://img.shields.io/badge/dsh-0.1.1--rc.2-4b8dff)](https://github.com/deepseek-ai/deepseek-harness)
8
+ [![dsh](https://img.shields.io/badge/dsh-0.1.2--rc.1-4b8dff)](https://github.com/deepseek-ai/deepseek-harness)
8
9
  [![stars](https://img.shields.io/github/stars/SpookySandwich/dsh-plugin-rollout-scout?style=flat&label=stars)](https://github.com/SpookySandwich/dsh-plugin-rollout-scout/stargazers)
9
10
 
10
11
  Providers sometimes roll a new conversation model out gradually, so which one you get is luck of the draw. Rollout Scout opens throwaway conversations on your own account, reads each one's chain-of-thought **as it streams**, and scores how the reasoning is written — cancelling the ones that read like the model you already have, and keeping the ones that don't.
@@ -134,6 +135,9 @@ Implementation notes live in [`docs/`](docs/) — [architecture](docs/architectu
134
135
 
135
136
  ## Compatibility
136
137
 
138
+ This release targets DSH `0.1.2-rc.1`. Run `npm ci`, `npm test`, and `npm run check:package` to verify the build and package. Restart DSH after updating.
139
+
140
+
137
141
  The launcher takes a `sidebar.footer.action` seat (a list slot, so it sits beside any other footer action rather than displacing one) and the console renders on the frame-wide `shell.overlay` layer. Neither is per-session, so it conflicts with no session plugin. Requires a DSH whose sidebar declares that seat; without it the console has no way in. Part of the same family as [dsh-plugin-smooth-stream](https://github.com/SpookySandwich/dsh-plugin-smooth-stream), [dsh-plugin-no-workspace](https://github.com/SpookySandwich/dsh-plugin-no-workspace) and [dsh-plugin-message-edit](https://github.com/SpookySandwich/dsh-plugin-message-edit).
138
142
 
139
143
  ## A note on cost
package/README.md CHANGED
@@ -3,8 +3,9 @@
3
3
  [English](README.en.md) | 简体中文
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/dsh-plugin-rollout-scout?color=cb3837&logo=npm)](https://www.npmjs.com/package/dsh-plugin-rollout-scout)
6
+ [![CI](https://github.com/SpookySandwich/dsh-plugin-rollout-scout/actions/workflows/ci.yml/badge.svg)](https://github.com/SpookySandwich/dsh-plugin-rollout-scout/actions/workflows/ci.yml)
6
7
  [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
- [![dsh](https://img.shields.io/badge/dsh-0.1.1--rc.2-4b8dff)](https://github.com/deepseek-ai/deepseek-harness)
8
+ [![dsh](https://img.shields.io/badge/dsh-0.1.2--rc.1-4b8dff)](https://github.com/deepseek-ai/deepseek-harness)
8
9
  [![stars](https://img.shields.io/github/stars/SpookySandwich/dsh-plugin-rollout-scout?style=flat&label=stars)](https://github.com/SpookySandwich/dsh-plugin-rollout-scout/stargazers)
9
10
 
10
11
  服务商有时会灰度发布新的对话模型,你分到哪一个全看运气。灰度侦察会用你自己的账号开启一批临时会话,**在思维链流式输出的同时**读取它,并按「推理是怎么写的」打分——读起来像你手上这个旧模型的立刻中止,不像的留下来。
@@ -132,6 +133,9 @@ dsh plugin --profile web add github:SpookySandwich/dsh-plugin-rollout-scout
132
133
 
133
134
  ## 兼容性
134
135
 
136
+ 本次兼容目标为 DSH `0.1.2-rc.1`。运行 `npm ci`、`npm test` 和 `npm run check:package` 可验证构建及发布包。更新后请重启 DSH。
137
+
138
+
135
139
  入口占用 `sidebar.footer.action` 座位(list 类型,会与其它底部操作并排,而不是把谁挤掉),控制台本体渲染在全局 `shell.overlay` 层。两者都不属于会话作用域,因此不与任何会话内插件冲突。需要侧边栏声明了该座位的 DSH 版本;否则控制台将没有入口。与 [dsh-plugin-smooth-stream](https://github.com/SpookySandwich/dsh-plugin-smooth-stream)、[dsh-plugin-no-workspace](https://github.com/SpookySandwich/dsh-plugin-no-workspace)、[dsh-plugin-message-edit](https://github.com/SpookySandwich/dsh-plugin-message-edit) 同族。
136
140
 
137
141
  ## 关于额度
package/_wrap-client.mjs CHANGED
@@ -29,4 +29,4 @@ const out = [
29
29
  "",
30
30
  ].join('\n');
31
31
  fs.writeFileSync(new URL('./lib/client.js', import.meta.url), out);
32
- console.log('wrote lib/client.js', out.length);
32
+ console.error('wrote lib/client.js', out.length);
package/lib/client.js CHANGED
@@ -489,13 +489,14 @@ const CSS = [
489
489
  ].join('');
490
490
 
491
491
  return {
492
+ inject: ['slots', 'sessions', 'locale'],
492
493
  apply(ctx) {
493
494
  const slots = ctx.get('slots');
494
- if (slots === undefined) return;
495
+ if (slots === undefined) throw new Error('[dsh-plugin-rollout-scout] Missing DSH slots service; check client dependencies.');
495
496
  ctx.effect(function () { return styles.insert(CSS); });
496
497
 
497
- let sessions = null;
498
- try { sessions = ctx.get('sessions'); } catch (e) {}
498
+ const sessions = ctx.get('sessions');
499
+ if (!sessions || typeof sessions.open !== 'function') throw new Error('[dsh-plugin-rollout-scout] Missing DSH session navigation service.');
499
500
 
500
501
  const I18N_NS = 'dsh-plugin-rollout-scout';
501
502
  const I18N = {
package/lib/index.js CHANGED
@@ -1192,20 +1192,7 @@ function pump(ctx) {
1192
1192
  state.attempts.unshift(attempt);
1193
1193
  trimHistory();
1194
1194
  const task = launch(ctx, attempt).catch((error) => {
1195
- const message = error instanceof Error ? error.message : String(error);
1196
- if (attempt.stopReason === null) attempt.error = message;
1197
- // Only a launch that never reached 'streaming' counts towards the
1198
- // breaker: a failure after the turn started is the probe's problem,
1199
- // not a sign that launching itself is broken.
1200
- if (!attempt.streamed && attempt.stopReason === null) {
1201
- state.launchFailures += 1;
1202
- if (state.launchFailures >= LAUNCH_FAILURE_LIMIT) {
1203
- state.running = false;
1204
- state.paused = true;
1205
- state.note = 'launch-failed';
1206
- state.lastError = message;
1207
- }
1208
- }
1195
+ if (attempt.stopReason === null) recordProbeFailure(attempt, error);
1209
1196
  finish(ctx, attempt);
1210
1197
  }).finally(() => {
1211
1198
  attempt.launching = false;
@@ -1314,7 +1301,7 @@ async function launch(ctx, attempt) {
1314
1301
  const handle = await ctx.agents.create({
1315
1302
  sessionId,
1316
1303
  meta: { cwd: workspace.path },
1317
- agentOptions: { provider: selection.provider, model: selection.model },
1304
+ agentOptions: selection,
1318
1305
  signal: attempt.launchController.signal,
1319
1306
  setup: (agentCtx) => {
1320
1307
  if (installModelSelection) {
@@ -1340,9 +1327,6 @@ async function launch(ctx, attempt) {
1340
1327
  }
1341
1328
 
1342
1329
  attempt.execution = 'running';
1343
- attempt.streamed = true;
1344
- // One probe that got as far as its first turn clears the breaker.
1345
- state.launchFailures = 0;
1346
1330
  titleAttempt(ctx, attempt, 'probe');
1347
1331
  attempt.promptSentAt = Date.now();
1348
1332
  armWatchdog(ctx, attempt);
@@ -1381,10 +1365,39 @@ function onSessionEvent(ctx, attempt, event) {
1381
1365
  return;
1382
1366
  }
1383
1367
  if (event.type === 'turn/end') {
1368
+ // Current DSH reports request/model failures as terminal session events,
1369
+ // after create() and followup() have succeeded. Treating those as normal
1370
+ // empty replies misclassifies them and can launch replacements forever.
1371
+ if (attempt.stopReason === null) {
1372
+ if (event.data?.reason?.kind === 'error') {
1373
+ recordProbeFailure(attempt, event.data.reason.error);
1374
+ } else if (!attempt.error) {
1375
+ state.launchFailures = 0;
1376
+ }
1377
+ }
1384
1378
  finish(ctx, attempt);
1385
1379
  }
1386
1380
  }
1387
1381
 
1382
+ function recordProbeFailure(attempt, error) {
1383
+ attempt.error = error?.message ?? String(error);
1384
+ if (!retained(attempt)) {
1385
+ attempt.verdict = 'unknown';
1386
+ attempt.reason = 'error';
1387
+ attempt.discard = 'none';
1388
+ resetFadeGrace(attempt);
1389
+ }
1390
+ if (attempt.failureCounted) return;
1391
+ attempt.failureCounted = true;
1392
+ state.launchFailures += 1;
1393
+ if (state.launchFailures >= LAUNCH_FAILURE_LIMIT) {
1394
+ state.running = false;
1395
+ state.paused = true;
1396
+ state.note = 'launch-failed';
1397
+ state.lastError = attempt.error;
1398
+ }
1399
+ }
1400
+
1388
1401
  /**
1389
1402
  * The fade grace has one owner and three derived phases:
1390
1403
  * idle — no timer, deadline or saved remainder
@@ -2115,7 +2128,7 @@ function finish(ctx, attempt) {
2115
2128
  attempt.endedAt = Date.now();
2116
2129
  clearWatchdog(attempt);
2117
2130
  clearCancelTimer(attempt);
2118
- if (attempt.stopReason === null) {
2131
+ if (attempt.stopReason === null && !attempt.error) {
2119
2132
  evaluate(ctx, attempt, true);
2120
2133
  }
2121
2134
  if (attempt.verdict === null) {
package/package.json CHANGED
@@ -1,54 +1,67 @@
1
- {
2
- "name": "dsh-plugin-rollout-scout",
3
- "version": "1.4.0",
4
- "description": "Detect which conversation model your DeepSeek Harness account is served: score probe conversations' live chain-of-thought, cancel old-model probes in seconds, keep confident catches.",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "exports": {
8
- ".": {
9
- "default": "./lib/index.js"
10
- },
11
- "./client": {
12
- "default": "./lib/client.js"
13
- },
14
- "./cordis.patch.yml": "./cordis.patch.yml",
15
- "./package.json": "./package.json"
16
- },
17
- "files": [
18
- "lib",
19
- "cordis.patch.yml",
20
- "plugin.client.js",
21
- "_wrap-client.mjs"
22
- ],
23
- "license": "MIT",
24
- "repository": {
25
- "type": "git",
26
- "url": "git+https://github.com/SpookySandwich/dsh-plugin-rollout-scout.git"
27
- },
28
- "keywords": [
29
- "dsh",
30
- "dsh-plugin",
31
- "deepseek-harness",
32
- "cordis-plugin",
33
- "rollout",
34
- "ab-test",
35
- "model-detection"
36
- ],
37
- "dsh": {
38
- "bundle": {
39
- "patch": "./cordis.patch.yml"
40
- },
41
- "client": {
42
- "platform": "web",
43
- "inject": []
44
- }
45
- },
46
- "scripts": {
47
- "build": "node _wrap-client.mjs",
48
- "prepare": "node _wrap-client.mjs",
49
- "prepack": "node _wrap-client.mjs",
50
- "pretest": "node _wrap-client.mjs",
51
- "test": "node test/classifier.test.mjs && node test/route.test.mjs && node test/pump.test.mjs && node test/delete.test.mjs && node test/lifecycle.test.mjs && node test/ownership.test.mjs && node test/manifest.test.mjs && node test/manifest-concurrency.test.mjs && node test/manifest-process.test.mjs && node test/history.test.mjs && node test/state-machine.test.mjs && node test/client-review.test.mjs && node test/client-anchor.test.mjs && node test/client-css.test.mjs",
52
- "check:client": "node _wrap-client.mjs && git diff --exit-code -- lib/client.js"
53
- }
54
- }
1
+ {
2
+ "name": "dsh-plugin-rollout-scout",
3
+ "version": "1.4.1",
4
+ "description": "Detect which conversation model your DeepSeek Harness account is served: score probe conversations' live chain-of-thought, cancel old-model probes in seconds, keep confident catches.",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "default": "./lib/index.js"
10
+ },
11
+ "./client": {
12
+ "default": "./lib/client.js"
13
+ },
14
+ "./cordis.patch.yml": "./cordis.patch.yml",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "lib",
19
+ "cordis.patch.yml",
20
+ "plugin.client.js",
21
+ "_wrap-client.mjs"
22
+ ],
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/SpookySandwich/dsh-plugin-rollout-scout.git"
27
+ },
28
+ "keywords": [
29
+ "dsh",
30
+ "dsh-plugin",
31
+ "deepseek-harness",
32
+ "cordis-plugin",
33
+ "rollout",
34
+ "ab-test",
35
+ "model-detection"
36
+ ],
37
+ "dsh": {
38
+ "bundle": {
39
+ "patch": "./cordis.patch.yml"
40
+ },
41
+ "client": {
42
+ "platform": "web",
43
+ "inject": [
44
+ "@deepseek-ai/dsh-api-session-controller",
45
+ "@deepseek-ai/dsh-client-locale",
46
+ "@deepseek-ai/dsh-client-ui-slots",
47
+ "@deepseek-ai/dsh-client-ui-layout",
48
+ "@deepseek-ai/dsh-client-modules"
49
+ ]
50
+ }
51
+ },
52
+ "scripts": {
53
+ "build": "node _wrap-client.mjs",
54
+ "prepare": "node _wrap-client.mjs",
55
+ "prepack": "node _wrap-client.mjs",
56
+ "pretest": "node _wrap-client.mjs",
57
+ "test": "node test/classifier.test.mjs && node test/route.test.mjs && node test/pump.test.mjs && node test/delete.test.mjs && node test/lifecycle.test.mjs && node test/ownership.test.mjs && node test/manifest.test.mjs && node test/manifest-concurrency.test.mjs && node test/manifest-process.test.mjs && node test/history.test.mjs && node test/state-machine.test.mjs && node test/client-review.test.mjs && node test/client-anchor.test.mjs && node test/client-css.test.mjs && node --test test/client-loading.test.mjs && node --test test/probe-errors.test.mjs",
58
+ "check:client": "node _wrap-client.mjs && git diff --exit-code -- lib/client.js",
59
+ "check:package": "node scripts/check-package.mjs"
60
+ },
61
+ "devDependencies": {
62
+ "@deepseek-ai/cordis": "^4.0.2",
63
+ "jsdom": "^29.1.1",
64
+ "react": "^18.3.1",
65
+ "react-dom": "^18.3.1"
66
+ }
67
+ }
package/plugin.client.js CHANGED
@@ -469,13 +469,14 @@ const CSS = [
469
469
  ].join('');
470
470
 
471
471
  return {
472
+ inject: ['slots', 'sessions', 'locale'],
472
473
  apply(ctx) {
473
474
  const slots = ctx.get('slots');
474
- if (slots === undefined) return;
475
+ if (slots === undefined) throw new Error('[dsh-plugin-rollout-scout] Missing DSH slots service; check client dependencies.');
475
476
  ctx.effect(function () { return styles.insert(CSS); });
476
477
 
477
- let sessions = null;
478
- try { sessions = ctx.get('sessions'); } catch (e) {}
478
+ const sessions = ctx.get('sessions');
479
+ if (!sessions || typeof sessions.open !== 'function') throw new Error('[dsh-plugin-rollout-scout] Missing DSH session navigation service.');
479
480
 
480
481
  const I18N_NS = 'dsh-plugin-rollout-scout';
481
482
  const I18N = {