@suifei/dsh-pmo-button 0.7.3 → 0.8.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/README.md CHANGED
@@ -58,6 +58,22 @@ dsh plugin --profile <你的profile> add github:suifei/dsh-pmo-button
58
58
  | `greet` | `hi` | 每次启动发给子代理的问候文本 |
59
59
  | `rolePrompt` | (内置审查规程原文) | 身份提示词;每会话仅发一次,置空禁用 |
60
60
  | `maxRounds` | `20` | 自上次用户输入以来的审查轮数上限(0 = 不限),超出自动熄灭 |
61
+ | `childModelProvider` | (空 = 继承主会话) | 子代理提供方覆盖,如 `deepseek-official` |
62
+ | `childModel` | (空 = 继承主会话) | 子代理模型覆盖,如 `deepseek-v4.1-flash` |
63
+ | `childReasoningEffort` | (空 = 继承主会话) | 子代理思考等级覆盖,如 `max` |
64
+
65
+ ### 🔀 异构审查(审查方 ≠ 执行方)
66
+
67
+ 三个 `childModel*` 字段留空时,子代理**自动继承主会话**的提供方/模型/思考等级;全部留空即"同模型互审"。想要"盲区不同"的异构审查,把三项指向另一个模型即可:
68
+
69
+ ```yaml
70
+ config:
71
+ childModelProvider: deepseek-official
72
+ childModel: deepseek-v4.1-flash
73
+ childReasoningEffort: max
74
+ ```
75
+
76
+ > 前提:该提供方已在 Harness 中配置好凭据;id 以模型选择器目录为准。指定的模型/等级会写入子代理持久描述符——**冷恢复按描述符还原,不会漂回主会话模型**。
61
77
 
62
78
  ## 📜 日志格式
63
79
 
package/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * PMO button — Client half v0.7.3.
2
+ * PMO button — Client half v0.8.0.
3
3
  * Red start/stop control in `conversation.input.right` (idle: neutral circle
4
4
  * with red arrow; armed: red circle with pulse animation) plus a liveness
5
5
  * strip in `conversation.composer.dock`. State is owned by the Host half via
@@ -12,7 +12,7 @@ window.__ModuleLoader__.load({
12
12
  const React = require('react');
13
13
  const h = React.createElement;
14
14
  const BASE = '/pmo-button';
15
- const VER = 'v0.7.3';
15
+ const VER = 'v0.8.0';
16
16
  let loadError = null;
17
17
  let t = { start: 'Start PMO automation', stop: 'PMO running: click to stop', busy: 'PMO: pending…', offline: 'PMO: host unreachable' };
18
18
 
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * PMO button — Host half v0.7.3.
2
+ * PMO button — Host half v0.8.0.
3
3
  * Per-session armed set, turn buffers, child registry, and the once-per-session
4
4
  * identity-prompt flag are persisted (pmo-state.json), so restarts lose nothing.
5
5
  * The `session/event` feed drives two jobs for armed sessions:
@@ -67,6 +67,12 @@ export const Config = Schema.object({
67
67
  rolePrompt: Schema.string().default(ROLE_PROMPT_DEFAULT),
68
68
  /** Review-round cap per session since the last user input; 0 disables the cap. */
69
69
  maxRounds: Schema.number().default(20),
70
+ /** Child provider override; empty inherits the parent session's provider. */
71
+ childModelProvider: Schema.string().default(''),
72
+ /** Child model override; empty inherits the parent session's model. */
73
+ childModel: Schema.string().default(''),
74
+ /** Child reasoning-effort override; empty inherits the parent session's effort. */
75
+ childReasoningEffort: Schema.string().default(''),
70
76
  })
71
77
 
72
78
  const SEP = '\n' + '─'.repeat(68) + '\n'
@@ -180,6 +186,11 @@ export function apply(ctx, config) {
180
186
  if (t.length <= limit) return t
181
187
  return t.slice(0, limit) + `\n…(截断,原长 ${t.length} 字符)`
182
188
  }
189
+ /** Never let credential-looking strings (npm_ tokens etc.) reach the log,
190
+ * the review forward, or the child's durable session. */
191
+ function redact(s) {
192
+ return String(s ?? '').replace(/npm_[A-Za-z0-9]{20,}/g, 'npm_***已脱敏***')
193
+ }
183
194
  /** Auto-stop: dim the button and gate forwarding WITHOUT deafening the
184
195
  * session listener — turn logging keeps running, and user speech (or a
185
196
  * button re-light) releases the gate so the loop can auto-resume. */
@@ -315,7 +326,7 @@ export function apply(ctx, config) {
315
326
  otherTasks.forEach((t) => parts.push(`[注入:${t.src}] ${t.text}`))
316
327
  attachTasks.forEach((t) => parts.push(t.text))
317
328
  if (b.texts?.length > 0) parts.push(`[主代理] ${b.texts.join('\n\n---\n\n')}`)
318
- const forward = clip(`【PMO 轮次转发 · turn=${turn}】\n` + parts.join('\n'), config.maxChars * 2)
329
+ const forward = clip(redact(`【PMO 轮次转发 · turn=${turn}】\n` + parts.join('\n')), config.maxChars * 2)
319
330
  const agents = ctx.get('agents')
320
331
  const agent = agents && typeof agents.get === 'function' ? agents.get(sid) : undefined
321
332
  const subagentsSvc = ctx.get('subagents')
@@ -381,12 +392,21 @@ export function apply(ctx, config) {
381
392
  ...roleBlocks,
382
393
  { type: 'text', text: config.greet },
383
394
  ]
395
+ // agentOptions overrides (spawn capability): empty strings inherit the
396
+ // parent session's provider/model/reasoning effort (spawn README: the
397
+ // child inherits provider, model, reasoning effort unless agentOptions).
398
+ const overrides = {}
399
+ if (config.childModelProvider) overrides.provider = config.childModelProvider
400
+ if (config.childModel) overrides.model = config.childModel
401
+ if (config.childReasoningEffort) overrides.reasoningEffort = config.childReasoningEffort
402
+ const request = { parent: agent, prompt: promptBlocks, description: config.childLabel }
403
+ if (Object.keys(overrides).length > 0) request.agentOptions = overrides
384
404
  const act = await subagents.startActivation({
385
405
  provider: config.provider,
386
406
  label: config.childLabel,
387
407
  delivery: 'parent',
388
408
  signal: controller.signal,
389
- request: { parent: agent, prompt: promptBlocks, description: config.childLabel },
409
+ request,
390
410
  })
391
411
  children.set(sid, String(act.childId))
392
412
  if (needRole) {
@@ -424,7 +444,7 @@ export function apply(ctx, config) {
424
444
  const srcKind = text.trimStart().startsWith('<system-reminder>')
425
445
  ? 'system-reminder'
426
446
  : sourceKind(event.data)
427
- b.tasks.push({ src: srcKind, text })
447
+ b.tasks.push({ src: srcKind, text: redact(text) })
428
448
  for (const s of nonTextSummaries(event.data)) b.tasks.push({ src: '__attach__', text: s })
429
449
  // Recognize the PMO child's STATUS protocol from its settlement notice
430
450
  // or direct adjacent message, and record the review verdict.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suifei/dsh-pmo-button",
3
- "version": "0.7.3",
3
+ "version": "0.8.0",
4
4
  "description": "PMO 审查循环按钮 for DeepSeek Harness — 持久审查子代理 + 轮次转发 + STATUS 协议(CONTINUE/DONE/NEED_HUMAN)自动循环推进",
5
5
  "keywords": [
6
6
  "deepseek-harness", "dsh", "dsh-plugin", "pmo", "code-review",