@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 +16 -0
- package/client.js +2 -2
- package/index.js +24 -4
- package/package.json +1 -1
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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",
|