@twinsearth/dsh-master 3.3.5 → 3.3.6

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/client.js CHANGED
@@ -397,7 +397,7 @@ window.__ModuleLoader__.load({
397
397
  return h('div', { style: S.card, 'data-dsh-master': 'cost-block' },
398
398
  h('div', { style: S.row },
399
399
  h('span', { style: S.name }, '成本(只读)'),
400
- tag(block ? '3.3.5' : '未启用', block ? undefined : '#B45309')),
400
+ tag(block ? '3.3.6' : '未启用', block ? undefined : '#B45309')),
401
401
  failed ? h('div', { style: S.error }, '成本接口不可达') : null,
402
402
  !block && !failed ? h('div', { style: S.desc }, '成本系统未装配(cost-optimizer 未启用或角色不匹配)') : null,
403
403
  columns ? h('div', { style: S.desc },
@@ -12,6 +12,7 @@
12
12
  const DEFAULT_INTERVAL_MS = 1_000;
13
13
  const DEFAULT_TIMEOUT_MS = 30_000;
14
14
  const DEFAULT_MAX_ATTEMPTS = 30;
15
+ const DEFAULT_REQUEST_TIMEOUT_MS = 5_000;
15
16
  function positiveInt(value, fallback) {
16
17
  const n = Number(value);
17
18
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
@@ -43,6 +44,8 @@ export async function probeHealth(input = {}) {
43
44
  : (status) => status >= 200 && status < 300;
44
45
  const startedAt = now();
45
46
  const deadline = startedAt + timeoutMs;
47
+ // 单次请求超时必须与轮询间隔分开:拿 intervalMs 当请求超时会把「慢但有响应」误判成 probe-failed
48
+ const requestTimeoutMs = positiveInt(input.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS);
46
49
  let attempts = 0;
47
50
  let lastStatus = null;
48
51
  let lastError = null;
@@ -52,7 +55,7 @@ export async function probeHealth(input = {}) {
52
55
  attempts += 1;
53
56
  try {
54
57
  const controller = typeof AbortController === 'function' ? new AbortController() : null;
55
- const timer = controller ? setTimeout(() => controller.abort(), Math.max(1, Math.min(intervalMs, 5_000))) : null;
58
+ const timer = controller ? setTimeout(() => controller.abort(), Math.max(1, Math.min(requestTimeoutMs, 30_000))) : null;
56
59
  if (timer && typeof timer.unref === 'function')
57
60
  timer.unref();
58
61
  let response = null;
@@ -78,9 +81,10 @@ export async function probeHealth(input = {}) {
78
81
  await wait(intervalMs);
79
82
  }
80
83
  const elapsedMs = Math.max(0, now() - startedAt);
81
- if (lastError)
82
- return { ok: false, code: 'probe-failed', error: lastError, status: lastStatus, attempts, elapsedMs, url };
84
+ // 只要拿到过响应,就以状态码为准——不能因为某次连接失败把「服务返回 503」改写成 probe-failed
83
85
  if (lastStatus !== null)
84
86
  return { ok: false, code: 'unhealthy-status', status: lastStatus, attempts, elapsedMs, url };
87
+ if (lastError)
88
+ return { ok: false, code: 'probe-failed', error: lastError, status: lastStatus, attempts, elapsedMs, url };
85
89
  return { ok: false, code: 'probe-timeout', attempts, elapsedMs, url };
86
90
  }
@@ -7,7 +7,7 @@
7
7
  * 与瓮城 dsh-Fang 的协作只走 DSH 服务键,不 import fang 代码。
8
8
  */
9
9
  import crypto from 'node:crypto';
10
- export const MASTER_VERSION = '3.3.5';
10
+ export const MASTER_VERSION = '3.3.6';
11
11
  export const FANG_CONTRACT_MIN = '3.1.14';
12
12
  export const SERVICE = Object.freeze({
13
13
  master: 'dshMaster',
@@ -108,7 +108,7 @@ export function apply(ctx, config = {}) {
108
108
  };
109
109
  const service = {
110
110
  id: SERVICE.cost,
111
- version: '3.3.5',
111
+ version: '3.3.6',
112
112
  role,
113
113
  get mode() {
114
114
  return system.policy.describe().mode;
@@ -354,7 +354,7 @@ export function apply(ctx, config = {}) {
354
354
  return {
355
355
  ok: true,
356
356
  id: 'cost-optimizer',
357
- version: '3.3.5',
357
+ version: '3.3.6',
358
358
  role,
359
359
  mode: current.mode,
360
360
  requestedMode: current.requestedMode,
@@ -396,7 +396,7 @@ export function apply(ctx, config = {}) {
396
396
  doubleCountGuard: report.doubleCountGuard,
397
397
  };
398
398
  })(),
399
- note: '3.3.5:系统层记账/预算/灰度/审计 + A1 工具输出紧凑化(默认 shadow)+ 瓮城回流出口(contract 1.1.1 真实投递,回执计数修复);工具面 A2–A3 与决策复用 B1–B4 已接入(shadow 默认);3.3.3 起角色矩阵母体全开、分身挂双主管;3.3.4 起内置 PM/PJM 两个智能体 preset;3.3.5 起补齐引擎原语、可中断 LLM 流、WS 通道与流式管线。',
399
+ note: '3.3.6:系统层记账/预算/灰度/审计 + A1 工具输出紧凑化(默认 shadow)+ 瓮城回流出口(contract 1.1.1 真实投递,回执计数修复);工具面 A2–A3 与决策复用 B1–B4 已接入(shadow 默认);3.3.3 起角色矩阵母体全开、分身挂双主管;3.3.4 起内置 PM/PJM 两个智能体 preset;3.3.5 起补齐引擎原语、可中断 LLM 流、WS 通道与流式管线。',
400
400
  };
401
401
  },
402
402
  };
package/docs/CHANGELOG.md CHANGED
@@ -1,10 +1,15 @@
1
- ## 3.3.5(2026-11-14 已发布)
1
+ ## 3.3.6(2026-11-14 已发布)
2
2
 
3
- > 三方发布:annotated tag `v3.3.5` + GitHub Release + npm `@twinsearth/dsh-master@3.3.5`。
3
+ > 三方发布:annotated tag `v3.3.6` + GitHub Release + npm `@twinsearth/dsh-master@3.3.6`。
4
+ > **为什么有 3.3.6**:3.3.5 的 tag 与 GitHub Release 已建,但 npm 侧发布返回
5
+ > `E409 VERSION_EXISTS`(该版本号被 registry 占位,`npm view` 却 404),导致 3.3.5 无法从 npm 交付。
6
+ > 3.3.6 与 3.3.5 的代码内容一致,是**npm 可达的交付版本**;3.3.5 的 GitHub Release 已加注说明。
4
7
  > 接口包无变化(仍 `@twinsearth/dsh-fang-contract@1.1.1`)。
5
8
 
6
9
  **主题:宿主侧引擎原语 + PM/PJM 闭环 + 面板/通道/流式管线。**
7
10
 
11
+ ## 3.3.5(GitHub-only · npm 发布被 E409 阻塞)
12
+
8
13
  - **闭环第一步 · PM 交接**:`pm_handoff_to_pjm` 生成交接包;**验收标准为空、或仍有未决问题/冲突时不给 `ready`**(`needs-clarification` + 具名原因),PJM 不允许接单。
9
14
  - **闭环第二步 · PJM 接单与自反馈**:`pjm_take_handoff` / `pjm_create_plan({handoffId})` 接单(重复接单被拒);`pjm_report` 支持执行中随时汇报(`blocked` 必须写 blocker);全部步骤完成后 `pjm_submit_feedback` 提交交付/偏差/遗留/测试与实测用时。
10
15
  - **闭环第三步 · PM 复核/复盘/总结**:`pm_review_feedback` 逐条验收(`met` 必须是布尔 + 证据),写 `kept/improve/lessons` 复盘与总结;**结论必须与验收一致**(有未达标却判 accepted、或全达标却判 changes-requested,都直接拒收);`accepted` 把计划标记为 `pmReview.accepted`,`changes-requested` 保持闭环打开。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/dsh-master",
3
- "version": "3.3.5",
3
+ "version": "3.3.6",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -14,6 +14,7 @@
14
14
  const DEFAULT_INTERVAL_MS = 1_000
15
15
  const DEFAULT_TIMEOUT_MS = 30_000
16
16
  const DEFAULT_MAX_ATTEMPTS = 30
17
+ const DEFAULT_REQUEST_TIMEOUT_MS = 5_000
17
18
 
18
19
  function positiveInt(value, fallback) {
19
20
  const n = Number(value)
@@ -48,6 +49,8 @@ export async function probeHealth(input = {}) {
48
49
 
49
50
  const startedAt = now()
50
51
  const deadline = startedAt + timeoutMs
52
+ // 单次请求超时必须与轮询间隔分开:拿 intervalMs 当请求超时会把「慢但有响应」误判成 probe-failed
53
+ const requestTimeoutMs = positiveInt(input.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS)
51
54
  let attempts = 0
52
55
  let lastStatus = null
53
56
  let lastError = null
@@ -57,7 +60,7 @@ export async function probeHealth(input = {}) {
57
60
  attempts += 1
58
61
  try {
59
62
  const controller = typeof AbortController === 'function' ? new AbortController() : null
60
- const timer = controller ? setTimeout(() => controller.abort(), Math.max(1, Math.min(intervalMs, 5_000))) : null
63
+ const timer = controller ? setTimeout(() => controller.abort(), Math.max(1, Math.min(requestTimeoutMs, 30_000))) : null
61
64
  if (timer && typeof timer.unref === 'function') timer.unref()
62
65
  let response = null
63
66
  try {
@@ -78,7 +81,8 @@ export async function probeHealth(input = {}) {
78
81
  }
79
82
 
80
83
  const elapsedMs = Math.max(0, now() - startedAt)
81
- if (lastError) return { ok: false, code: 'probe-failed', error: lastError, status: lastStatus, attempts, elapsedMs, url }
84
+ // 只要拿到过响应,就以状态码为准——不能因为某次连接失败把「服务返回 503」改写成 probe-failed
82
85
  if (lastStatus !== null) return { ok: false, code: 'unhealthy-status', status: lastStatus, attempts, elapsedMs, url }
86
+ if (lastError) return { ok: false, code: 'probe-failed', error: lastError, status: lastStatus, attempts, elapsedMs, url }
83
87
  return { ok: false, code: 'probe-timeout', attempts, elapsedMs, url }
84
88
  }
package/src/kernel.ts CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  import crypto from 'node:crypto'
12
12
 
13
- export const MASTER_VERSION = '3.3.5'
13
+ export const MASTER_VERSION = '3.3.6'
14
14
  export const FANG_CONTRACT_MIN = '3.1.14'
15
15
 
16
16
  export const SERVICE = Object.freeze({
@@ -117,7 +117,7 @@ export function apply(ctx, config = {}) {
117
117
 
118
118
  const service = {
119
119
  id: SERVICE.cost,
120
- version: '3.3.5',
120
+ version: '3.3.6',
121
121
  role,
122
122
  get mode() {
123
123
  return system.policy.describe().mode
@@ -354,7 +354,7 @@ export function apply(ctx, config = {}) {
354
354
  return {
355
355
  ok: true,
356
356
  id: 'cost-optimizer',
357
- version: '3.3.5',
357
+ version: '3.3.6',
358
358
  role,
359
359
  mode: current.mode,
360
360
  requestedMode: current.requestedMode,
@@ -396,7 +396,7 @@ export function apply(ctx, config = {}) {
396
396
  doubleCountGuard: report.doubleCountGuard,
397
397
  }
398
398
  })(),
399
- note: '3.3.5:系统层记账/预算/灰度/审计 + A1 工具输出紧凑化(默认 shadow)+ 瓮城回流出口(contract 1.1.1 真实投递,回执计数修复);工具面 A2–A3 与决策复用 B1–B4 已接入(shadow 默认);3.3.3 起角色矩阵母体全开、分身挂双主管;3.3.4 起内置 PM/PJM 两个智能体 preset;3.3.5 起补齐引擎原语、可中断 LLM 流、WS 通道与流式管线。',
399
+ note: '3.3.6:系统层记账/预算/灰度/审计 + A1 工具输出紧凑化(默认 shadow)+ 瓮城回流出口(contract 1.1.1 真实投递,回执计数修复);工具面 A2–A3 与决策复用 B1–B4 已接入(shadow 默认);3.3.3 起角色矩阵母体全开、分身挂双主管;3.3.4 起内置 PM/PJM 两个智能体 preset;3.3.5 起补齐引擎原语、可中断 LLM 流、WS 通道与流式管线。',
400
400
  }
401
401
  },
402
402
  }