@mstar-harness/dsh 2.2.0 → 2.3.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.i18n.yaml +2 -3
- package/README.md +118 -3
- package/README.zh.md +118 -3
- package/bundle/README.md +11 -1
- package/dist/client/panel/graph/event-log.d.ts +18 -3
- package/dist/client/panel/graph/project-graph.d.ts +40 -14
- package/dist/client/panel/locale.d.ts +1 -1
- package/dist/client.js +131 -17
- package/dist/gates/_shared.d.ts +104 -5
- package/dist/gates/adapter.d.ts +34 -1
- package/dist/gates/agent-flow.d.ts +186 -4
- package/dist/gates/agent-personas.d.ts +44 -0
- package/dist/gates/dispatch.d.ts +64 -2
- package/dist/gates/fallbacks-advisory.d.ts +77 -0
- package/dist/gates/fallbacks-decoration.d.ts +108 -0
- package/dist/gates/fallbacks-probe.d.ts +63 -0
- package/dist/gates/fallbacks-seeds.d.ts +98 -0
- package/dist/gates/goal-bridge.d.ts +151 -0
- package/dist/gates/plan-mode-bridge.d.ts +70 -0
- package/dist/gates/skill-lint.d.ts +4 -3
- package/dist/gates/system-prompt.d.ts +121 -0
- package/dist/gates/workflow-ledger.d.ts +149 -0
- package/dist/gates/workflow-policy.d.ts +203 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +1833 -60
- package/dist/types.d.ts +30 -5
- package/harness-agents/architect.md +35 -0
- package/harness-agents/code-reviewer.md +98 -0
- package/harness-agents/frontend-dev.md +33 -0
- package/harness-agents/fullstack-dev-2.md +33 -0
- package/harness-agents/fullstack-dev.md +33 -0
- package/harness-agents/ops-engineer.md +33 -0
- package/harness-agents/product-manager.md +35 -0
- package/harness-agents/project-manager.md +32 -0
- package/harness-agents/prompt-engineer.md +33 -0
- package/harness-agents/qa-engineer.md +35 -0
- package/harness-agents/qc-specialist-2.md +62 -0
- package/harness-agents/qc-specialist-3.md +62 -0
- package/harness-agents/qc-specialist.md +62 -0
- package/harness-agents/writing-specialist.md +35 -0
- package/harness-commands/codebase-audit.md +2 -2
- package/harness-skills/mstar-audit/SKILL.md +20 -0
- package/harness-skills/mstar-audit/references/audit-playbook.md +27 -0
- package/harness-skills/mstar-branch-worktree/SKILL.md +7 -0
- package/harness-skills/mstar-coding-behavior/SKILL.md +5 -0
- package/harness-skills/mstar-compound/references/compound-workflow.md +16 -0
- package/harness-skills/mstar-compound-refresh/SKILL.md +5 -0
- package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +1 -0
- package/harness-skills/mstar-plan-artifacts/SKILL.md +1 -0
- package/harness-skills/mstar-plan-artifacts/references/status-and-residuals.md +8 -0
- package/harness-skills/mstar-review-qc/SKILL.md +6 -0
- package/harness-skills/mstar-roles/references/project-manager/qc-and-residuals.md +2 -1
- package/harness-skills/mstar-roles/references/qc-specialist/deep-review-lenses.md +16 -7
- package/harness-skills/mstar-roles/references/qc-specialist/report-template.md +17 -1
- package/harness-skills/mstar-roles/references/qc-specialist-shared.md +3 -1
- package/harness-skills/mstar-roles/references/writing-specialist.md +33 -0
- package/harness-skills/mstar-sdd/SKILL.md +5 -1
- package/harness-skills/mstar-sdd/references/file-handoffs.md +2 -0
- package/harness-skills/mstar-skill-authoring/SKILL.md +4 -2
- package/harness-skills/mstar-skill-authoring/references/regression-fixation.md +46 -0
- package/harness-skills/mstar-skill-authoring/references/skillsbench-authoring.md +37 -0
- package/package.json +7 -4
|
@@ -89,28 +89,32 @@ export interface GraphViolation {
|
|
|
89
89
|
code: string;
|
|
90
90
|
message: string;
|
|
91
91
|
}
|
|
92
|
-
/** Event status coloring: dispatch → dispatched|advisory|denied; settle → ok|error|denied. */
|
|
93
|
-
export type FlowEventStatus = 'dispatched' | 'advisory' | 'denied' | 'ok' | 'error';
|
|
92
|
+
/** Event status coloring: dispatch → dispatched|advisory|denied; settle → ok|error|denied; workflow/unknown rows → unknown (no gate status — honest). */
|
|
93
|
+
export type FlowEventStatus = 'dispatched' | 'advisory' | 'denied' | 'ok' | 'error' | 'unknown';
|
|
94
94
|
/**
|
|
95
95
|
* One projected agent-flow event (spec agent-flow-catalog-graph §2.4 —
|
|
96
|
-
* unchanged by the zone refactor
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
96
|
+
* unchanged by the zone refactor; plan `20260815-dsh-workflow-ledger` Task 4
|
|
97
|
+
* adds the workflow kinds + the unknown-kind degradation path). Every field
|
|
98
|
+
* degrades individually via `guards.ts` — a missing/illegal value becomes
|
|
99
|
+
* `null`/''/`0`/a base status, never a throw and never a guessed value.
|
|
100
|
+
* Dispatch/settle rows keep their gate semantics; the three WORKFLOW kinds
|
|
101
|
+
* project with their run identity (no verdict/outcome → status `unknown`);
|
|
102
|
+
* any UNKNOWN kind string renders as a GENERIC row — never dropped, never
|
|
103
|
+
* guessed. Only a row WITHOUT a kind is unclassifiable and skipped.
|
|
101
104
|
*/
|
|
102
105
|
export interface FlowEventView {
|
|
103
106
|
/** `${ts}-${kind}-${index}` — stable id (index = position in the projected window). */
|
|
104
107
|
id: string;
|
|
105
108
|
ts: number;
|
|
106
|
-
kind:
|
|
107
|
-
|
|
109
|
+
/** The ledger kind verbatim: dispatch | settle | the three workflow kinds | any unknown kind string (generic row). */
|
|
110
|
+
kind: 'dispatch' | 'settle' | 'workflow-run' | 'workflow-agent' | 'workflow-run-end' | (string & {});
|
|
111
|
+
/** `Execute as`; '' for settle rows without a paired identity and for workflow/unknown rows. */
|
|
108
112
|
role: string;
|
|
109
113
|
planId: string | null;
|
|
110
114
|
taskId: string | null;
|
|
111
115
|
taskCategory: string | null;
|
|
112
116
|
agent: string | null;
|
|
113
|
-
/** dispatch → dispatched|advisory|denied; settle → ok|error|denied (spec §2.4). */
|
|
117
|
+
/** dispatch → dispatched|advisory|denied; settle → ok|error|denied; workflow/unknown → unknown (spec §2.4). */
|
|
114
118
|
status: FlowEventStatus;
|
|
115
119
|
/** `role` ∈ the EXPECTED_ROLE_FLOW role union (spec §2.3 exact-string match). */
|
|
116
120
|
expected: boolean;
|
|
@@ -124,6 +128,22 @@ export interface FlowEventView {
|
|
|
124
128
|
/** Settle rows only (plan `20260811-panel-f4-timeliness` Task 1): the settle carries the PAIRED dispatch's identity (exact pairing). */
|
|
125
129
|
paired?: boolean;
|
|
126
130
|
durationMs: number | null;
|
|
131
|
+
/** Workflow run identity (workflow-* + unknown rows, when carried; absent otherwise). */
|
|
132
|
+
readonly runId?: string;
|
|
133
|
+
/** Workflow run display name (workflow-run rows only). */
|
|
134
|
+
readonly name?: string;
|
|
135
|
+
/** The run's member count in the window (workflow-run rows only — the window's `workflow-agent` rows for the runId; absent when 0/truncated, never a 0 guess). */
|
|
136
|
+
readonly memberCount?: number;
|
|
137
|
+
/** Run-member 1-based sequence (workflow-agent rows only). */
|
|
138
|
+
readonly seq?: number;
|
|
139
|
+
/** Run-member display label (workflow-agent rows only). */
|
|
140
|
+
readonly label?: string;
|
|
141
|
+
/** Run-member phase (workflow-agent rows only, when carried). */
|
|
142
|
+
readonly phase?: string;
|
|
143
|
+
/** The published member's child session identity (workflow-agent rows only). */
|
|
144
|
+
readonly childId?: string;
|
|
145
|
+
/** Terminal workflow run reason (workflow-run-end rows only). */
|
|
146
|
+
readonly stopReason?: string;
|
|
127
147
|
}
|
|
128
148
|
/**
|
|
129
149
|
* One iteration step (spec §3 + plan 20260812-panel-f5-iteration-zone-fix
|
|
@@ -456,9 +476,11 @@ export declare function projectGraph(source: MstarEngineStatusSource | null): Zo
|
|
|
456
476
|
export declare function projectAgents(source: MstarEngineStatusSource | null, currentStep: number | null): AgentZoneView;
|
|
457
477
|
/** One row of the pairing walk — the identity a PAIRED settle carries (plan
|
|
458
478
|
* `20260811-panel-f4-timeliness` Task 1, spec R1: exact identity pairing,
|
|
459
|
-
* never owner+time guessing).
|
|
479
|
+
* never owner+time guessing). The kind is the FULL projected kind union:
|
|
480
|
+
* workflow/unknown rows are walk no-ops (they carry no paired marker) —
|
|
481
|
+
* widened so the classify output feeds the walk unchanged. */
|
|
460
482
|
interface PairingRow {
|
|
461
|
-
kind: '
|
|
483
|
+
kind: FlowEventView['kind'];
|
|
462
484
|
agent: string | null;
|
|
463
485
|
role?: string;
|
|
464
486
|
planId?: string | null;
|
|
@@ -479,11 +501,15 @@ export declare function pairSettleIndexes(rows: readonly PairingRow[]): Readonly
|
|
|
479
501
|
* `flow.stages` merged into the plan-3 agents projection). Total function:
|
|
480
502
|
* NEVER throws, NEVER fabricates values.
|
|
481
503
|
*
|
|
482
|
-
* - events: the actual events, latest first, ≤50
|
|
504
|
+
* - events: the actual events, latest first, ≤50 — dispatch, settle, the
|
|
505
|
+
* three workflow kinds (run identity: name / member count / stopReason,
|
|
506
|
+
* plan `20260815-dsh-workflow-ledger` Task 4) and ANY unknown kind string
|
|
507
|
+
* as a generic row (degradation — never dropped, never guessed);
|
|
483
508
|
* - unexpected: DISPATCH events whose role is not in the expected role union
|
|
484
509
|
* (e.g. `general` / `explore` / `scout`). Settle rows are completion
|
|
485
510
|
* records — they carry no role at all, so they never flag as unexpected
|
|
486
|
-
* even though their `expected` field is false ('' ∉ union)
|
|
511
|
+
* even though their `expected` field is false ('' ∉ union). Workflow /
|
|
512
|
+
* unknown rows are not dispatches → never unexpected either;
|
|
487
513
|
* - settled: EXACT identity pairing via `pairSettleIndexes` (the same walk the
|
|
488
514
|
* agent-entity status derivation uses; an unpaired settle stays unpaired —
|
|
489
515
|
* honest). The panel never depends on the pairing's correctness;
|
|
@@ -122,7 +122,7 @@ import type { LocaleDictOf } from '@deepseek-ai/dsh-client-ui-slots';
|
|
|
122
122
|
/** Locale namespace id for the workflow-viz panel. */
|
|
123
123
|
export declare const NS = "mstar-panel";
|
|
124
124
|
/** Panel dictionary keys (union of every translatable string the panel renders). */
|
|
125
|
-
export type PanelKey = 'view.mstar-workflow' | 'tab.tasks' | 'tab.agents' | 'tab.events' | 'page.iteration.not-started' | 'page.iteration.expand' | 'page.iteration.collapse' | 'event-log.section.events' | 'event-log.section.violations' | 'event-log.empty' | 'event-log.empty.events' | 'event-log.empty.violations' | 'event-log.field.role' | 'event-log.field.agent' | 'event-log.field.stage' | 'event-log.field.plan' | 'event-log.field.task' | 'event-log.field.category' | 'event-log.field.time' | 'event-log.field.kind' | 'event-log.field.status' | 'event-log.field.expected' | 'event-log.field.settled' | 'event-log.field.duration' | 'event-log.field.severity' | 'event-log.field.code' | 'event-log.field.message' | 'event-log.kind.dispatch' | 'event-log.kind.settle' | 'event-log.yes' | 'event-log.no' | 'empty.waiting' | 'empty.no-harness' | 'empty.no-harness-hint' | 'watermark.version' | 'watermark.harness' | 'watermark.none' | 'panel.unknown' | 'graph.pass' | 'graph.fail' | 'zone.legend.title' | 'zone.legend.agent-running' | 'zone.legend.agent-settled' | 'zone.legend.agent-idle' | 'zone.iteration.step-label' | 'zone.iteration.step-badge' | 'zone.iteration.step.current' | 'zone.iteration.step.next' | 'zone.iteration.step.done' | 'zone.iteration.step.idle' | 'zone.phase.iteration-start' | 'zone.phase.autonomous-execute' | 'zone.phase.iteration-close' | 'zone.phase.pr-delivery' | 'zone.phase.merge-ready' | 'zone.branches.title' | 'zone.branches.iteration-base' | 'zone.branches.target' | 'zone.branches.spec-integration' | 'zone.tasks.title' | 'zone.tasks.total' | 'zone.tasks.no-plans' | 'zone.tasks.more' | 'zone.tasks.collapse' | 'zone.state.Todo' | 'zone.state.InProgress' | 'zone.state.InReview' | 'zone.state.Done' | 'zone.state.blocked-unknown' | 'zone.agents.title' | 'zone.agents.summary' | 'zone.agents.on-demand' | 'zone.agents.unknown-sub' | 'zone.agents.bucket.implementor' | 'zone.agents.bucket.reviewer' | 'zone.agents.group.phase-1' | 'zone.agents.group.phase-2' | 'zone.agents.group.phase-n' | 'zone.agents.group.plan' | 'zone.agents.group.no-plan' | 'zone.agents.group.plan-more' | 'flow.empty' | 'flow.settle-only' | 'flow.degraded' | 'flow.unexpected' | 'flow.in-flight' | 'flow.settled-ok' | 'flow.error' | 'flow.advisory' | 'flow.denied' | 'state.title' | 'state.plans' | 'state.residuals' | 'state.policy' | 'state.leases' | 'state.knowledge' | 'state.direction' | 'state.none' | 'state.enforcement' | 'state.enforcement.hard' | 'state.enforcement.soft' | 'state.plans.more' | 'state.residual.more' | 'state.policy.push' | 'state.policy.worktree' | 'state.policy.control-worktree' | 'state.knowledge.docs' | 'freshness.last-updated' | 'freshness.refresh-note';
|
|
125
|
+
export type PanelKey = 'view.mstar-workflow' | 'tab.tasks' | 'tab.agents' | 'tab.events' | 'page.iteration.not-started' | 'page.iteration.expand' | 'page.iteration.collapse' | 'event-log.section.events' | 'event-log.section.violations' | 'event-log.empty' | 'event-log.empty.events' | 'event-log.empty.violations' | 'event-log.field.role' | 'event-log.field.agent' | 'event-log.field.stage' | 'event-log.field.plan' | 'event-log.field.task' | 'event-log.field.category' | 'event-log.field.time' | 'event-log.field.kind' | 'event-log.field.status' | 'event-log.field.expected' | 'event-log.field.settled' | 'event-log.field.duration' | 'event-log.field.run-id' | 'event-log.field.name' | 'event-log.field.members' | 'event-log.field.stop-reason' | 'event-log.field.severity' | 'event-log.field.code' | 'event-log.field.message' | 'event-log.kind.dispatch' | 'event-log.kind.settle' | 'event-log.yes' | 'event-log.no' | 'empty.waiting' | 'empty.no-harness' | 'empty.no-harness-hint' | 'watermark.version' | 'watermark.harness' | 'watermark.none' | 'panel.unknown' | 'graph.pass' | 'graph.fail' | 'zone.legend.title' | 'zone.legend.agent-running' | 'zone.legend.agent-settled' | 'zone.legend.agent-idle' | 'zone.iteration.step-label' | 'zone.iteration.step-badge' | 'zone.iteration.step.current' | 'zone.iteration.step.next' | 'zone.iteration.step.done' | 'zone.iteration.step.idle' | 'zone.phase.iteration-start' | 'zone.phase.autonomous-execute' | 'zone.phase.iteration-close' | 'zone.phase.pr-delivery' | 'zone.phase.merge-ready' | 'zone.branches.title' | 'zone.branches.iteration-base' | 'zone.branches.target' | 'zone.branches.spec-integration' | 'zone.tasks.title' | 'zone.tasks.total' | 'zone.tasks.no-plans' | 'zone.tasks.more' | 'zone.tasks.collapse' | 'zone.state.Todo' | 'zone.state.InProgress' | 'zone.state.InReview' | 'zone.state.Done' | 'zone.state.blocked-unknown' | 'zone.agents.title' | 'zone.agents.summary' | 'zone.agents.on-demand' | 'zone.agents.unknown-sub' | 'zone.agents.bucket.implementor' | 'zone.agents.bucket.reviewer' | 'zone.agents.group.phase-1' | 'zone.agents.group.phase-2' | 'zone.agents.group.phase-n' | 'zone.agents.group.plan' | 'zone.agents.group.no-plan' | 'zone.agents.group.plan-more' | 'flow.empty' | 'flow.settle-only' | 'flow.degraded' | 'flow.unexpected' | 'flow.in-flight' | 'flow.settled-ok' | 'flow.error' | 'flow.advisory' | 'flow.denied' | 'state.title' | 'state.plans' | 'state.residuals' | 'state.policy' | 'state.leases' | 'state.knowledge' | 'state.direction' | 'state.none' | 'state.enforcement' | 'state.enforcement.hard' | 'state.enforcement.soft' | 'state.plans.more' | 'state.residual.more' | 'state.policy.push' | 'state.policy.worktree' | 'state.policy.control-worktree' | 'state.knowledge.docs' | 'freshness.last-updated' | 'freshness.refresh-note';
|
|
126
126
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
127
127
|
interface LocaleNamespaceMap {
|
|
128
128
|
'mstar-panel': PanelKey;
|
package/dist/client.js
CHANGED
|
@@ -76,6 +76,10 @@ var zh = {
|
|
|
76
76
|
"event-log.field.expected": "预期角色",
|
|
77
77
|
"event-log.field.settled": "已结算",
|
|
78
78
|
"event-log.field.duration": "耗时",
|
|
79
|
+
"event-log.field.run-id": "运行 ID",
|
|
80
|
+
"event-log.field.name": "运行名称",
|
|
81
|
+
"event-log.field.members": "成员数",
|
|
82
|
+
"event-log.field.stop-reason": "停止原因",
|
|
79
83
|
"event-log.field.severity": "严重度",
|
|
80
84
|
"event-log.field.code": "代码",
|
|
81
85
|
"event-log.field.message": "信息",
|
|
@@ -187,6 +191,10 @@ var en = {
|
|
|
187
191
|
"event-log.field.expected": "Expected role",
|
|
188
192
|
"event-log.field.settled": "Settled",
|
|
189
193
|
"event-log.field.duration": "Duration",
|
|
194
|
+
"event-log.field.run-id": "Run ID",
|
|
195
|
+
"event-log.field.name": "Run name",
|
|
196
|
+
"event-log.field.members": "Members",
|
|
197
|
+
"event-log.field.stop-reason": "Stop reason",
|
|
190
198
|
"event-log.field.severity": "Severity",
|
|
191
199
|
"event-log.field.code": "Code",
|
|
192
200
|
"event-log.field.message": "Message",
|
|
@@ -1524,27 +1532,77 @@ function settleStatus(outcome) {
|
|
|
1524
1532
|
}
|
|
1525
1533
|
function flowEventOf(raw, index, stageIndex) {
|
|
1526
1534
|
const row = raw;
|
|
1527
|
-
const kind = row?.kind;
|
|
1528
|
-
if (kind
|
|
1535
|
+
const kind = str(row?.kind);
|
|
1536
|
+
if (kind === null)
|
|
1529
1537
|
return null;
|
|
1530
1538
|
const role = str(row?.role) ?? "";
|
|
1531
1539
|
const matched = stageIndex.get(role);
|
|
1532
1540
|
const ts = count(row?.ts) ?? 0;
|
|
1541
|
+
if (kind === "dispatch") {
|
|
1542
|
+
return {
|
|
1543
|
+
id: `${ts}-${kind}-${index}`,
|
|
1544
|
+
ts,
|
|
1545
|
+
kind,
|
|
1546
|
+
role,
|
|
1547
|
+
planId: str(row?.planId),
|
|
1548
|
+
taskId: str(row?.taskId),
|
|
1549
|
+
taskCategory: str(row?.taskCategory),
|
|
1550
|
+
agent: str(row?.agent),
|
|
1551
|
+
status: dispatchStatus(row?.verdict),
|
|
1552
|
+
expected: matched !== undefined,
|
|
1553
|
+
stage: matched ?? null,
|
|
1554
|
+
settled: false,
|
|
1555
|
+
durationMs: count(row?.durationMs)
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
if (kind === "settle") {
|
|
1559
|
+
return {
|
|
1560
|
+
id: `${ts}-${kind}-${index}`,
|
|
1561
|
+
ts,
|
|
1562
|
+
kind,
|
|
1563
|
+
role,
|
|
1564
|
+
planId: str(row?.planId),
|
|
1565
|
+
taskId: str(row?.taskId),
|
|
1566
|
+
taskCategory: str(row?.taskCategory),
|
|
1567
|
+
agent: str(row?.agent),
|
|
1568
|
+
status: settleStatus(row?.outcome),
|
|
1569
|
+
expected: matched !== undefined,
|
|
1570
|
+
stage: matched ?? null,
|
|
1571
|
+
settled: false,
|
|
1572
|
+
...row?.paired === true ? { paired: true } : {},
|
|
1573
|
+
durationMs: count(row?.durationMs)
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
const runId = str(row?.runId);
|
|
1577
|
+
const name = str(row?.name);
|
|
1578
|
+
const seq = count(row?.seq);
|
|
1579
|
+
const label = str(row?.label);
|
|
1580
|
+
const phase = str(row?.phase);
|
|
1581
|
+
const childId = str(row?.childId);
|
|
1582
|
+
const stopReason = str(row?.stopReason);
|
|
1533
1583
|
return {
|
|
1534
1584
|
id: `${ts}-${kind}-${index}`,
|
|
1535
1585
|
ts,
|
|
1536
1586
|
kind,
|
|
1537
|
-
role,
|
|
1538
|
-
planId:
|
|
1539
|
-
taskId:
|
|
1540
|
-
taskCategory:
|
|
1587
|
+
role: "",
|
|
1588
|
+
planId: null,
|
|
1589
|
+
taskId: null,
|
|
1590
|
+
taskCategory: null,
|
|
1541
1591
|
agent: str(row?.agent),
|
|
1542
|
-
status:
|
|
1543
|
-
expected:
|
|
1544
|
-
stage:
|
|
1592
|
+
status: "unknown",
|
|
1593
|
+
expected: false,
|
|
1594
|
+
stage: null,
|
|
1545
1595
|
settled: false,
|
|
1546
|
-
|
|
1547
|
-
|
|
1596
|
+
durationMs: null,
|
|
1597
|
+
...runId !== null ? { runId } : {},
|
|
1598
|
+
...kind === "workflow-run" && name !== null ? { name } : {},
|
|
1599
|
+
...kind === "workflow-agent" ? {
|
|
1600
|
+
...seq !== null ? { seq } : {},
|
|
1601
|
+
...label !== null ? { label } : {},
|
|
1602
|
+
...phase !== null ? { phase } : {},
|
|
1603
|
+
...childId !== null ? { childId } : {}
|
|
1604
|
+
} : {},
|
|
1605
|
+
...kind === "workflow-run-end" && stopReason !== null ? { stopReason } : {}
|
|
1548
1606
|
};
|
|
1549
1607
|
}
|
|
1550
1608
|
function pairingKeyOf(row) {
|
|
@@ -1572,6 +1630,15 @@ function pairSettleIndexes(rows) {
|
|
|
1572
1630
|
function classifyFlowRows(rawEvents) {
|
|
1573
1631
|
const stageIndex = roleStageIndex();
|
|
1574
1632
|
const windowed = rawEvents.slice(0, FLOW_EVENT_WINDOW);
|
|
1633
|
+
const memberCounts = new Map;
|
|
1634
|
+
for (const raw of windowed) {
|
|
1635
|
+
const row = raw;
|
|
1636
|
+
if (row?.kind !== "workflow-agent")
|
|
1637
|
+
continue;
|
|
1638
|
+
const runId = str(row.runId);
|
|
1639
|
+
if (runId !== null)
|
|
1640
|
+
memberCounts.set(runId, (memberCounts.get(runId) ?? 0) + 1);
|
|
1641
|
+
}
|
|
1575
1642
|
const entries = [];
|
|
1576
1643
|
windowed.forEach((raw, i) => {
|
|
1577
1644
|
const view = flowEventOf(raw, i, stageIndex);
|
|
@@ -1579,6 +1646,14 @@ function classifyFlowRows(rawEvents) {
|
|
|
1579
1646
|
return;
|
|
1580
1647
|
entries.push({ view });
|
|
1581
1648
|
});
|
|
1649
|
+
for (const entry of entries) {
|
|
1650
|
+
const v = entry.view;
|
|
1651
|
+
if (v.kind !== "workflow-run" || v.runId === undefined)
|
|
1652
|
+
continue;
|
|
1653
|
+
const n = memberCounts.get(v.runId);
|
|
1654
|
+
if (n !== undefined && n > 0)
|
|
1655
|
+
entry.view = { ...v, memberCount: n };
|
|
1656
|
+
}
|
|
1582
1657
|
return entries;
|
|
1583
1658
|
}
|
|
1584
1659
|
function projectFlowEvents(source) {
|
|
@@ -3464,6 +3539,9 @@ function AgentCanvasPage({ view, iteration, t, initialPan }) {
|
|
|
3464
3539
|
}
|
|
3465
3540
|
|
|
3466
3541
|
// src/client/panel/graph/event-log.ts
|
|
3542
|
+
function isWorkflowKind(kind) {
|
|
3543
|
+
return kind === "workflow-run" || kind === "workflow-agent" || kind === "workflow-run-end";
|
|
3544
|
+
}
|
|
3467
3545
|
function taskTag(event) {
|
|
3468
3546
|
if (event.planId !== null && event.taskId !== null)
|
|
3469
3547
|
return `${event.planId}#${event.taskId}`;
|
|
@@ -3473,7 +3551,7 @@ function taskTag(event) {
|
|
|
3473
3551
|
return `#${event.taskId}`;
|
|
3474
3552
|
return "";
|
|
3475
3553
|
}
|
|
3476
|
-
function eventEntryOf(event) {
|
|
3554
|
+
function eventEntryOf(event, runNames) {
|
|
3477
3555
|
return {
|
|
3478
3556
|
kind: "event",
|
|
3479
3557
|
id: event.id,
|
|
@@ -3486,11 +3564,19 @@ function eventEntryOf(event) {
|
|
|
3486
3564
|
status: event.status,
|
|
3487
3565
|
settled: event.settled,
|
|
3488
3566
|
durationMs: event.durationMs,
|
|
3489
|
-
expected: event.expected
|
|
3567
|
+
expected: event.expected,
|
|
3568
|
+
runId: event.runId ?? "",
|
|
3569
|
+
name: event.kind === "workflow-run" && event.name !== undefined ? event.name : event.runId !== undefined ? runNames.get(event.runId) ?? "" : ""
|
|
3490
3570
|
};
|
|
3491
3571
|
}
|
|
3492
3572
|
function eventLogEntries(view) {
|
|
3493
|
-
const
|
|
3573
|
+
const runNames = new Map;
|
|
3574
|
+
for (const event of view.events) {
|
|
3575
|
+
if (event.kind === "workflow-run" && event.name !== undefined && event.name !== "") {
|
|
3576
|
+
runNames.set(event.runId ?? "", event.name);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
const entries = view.events.map((event) => eventEntryOf(event, runNames));
|
|
3494
3580
|
view.violations.forEach((violation, i) => {
|
|
3495
3581
|
entries.push({
|
|
3496
3582
|
kind: "violation",
|
|
@@ -3892,7 +3978,7 @@ function EventDetailsBody({
|
|
|
3892
3978
|
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
3893
3979
|
field: "kind",
|
|
3894
3980
|
label: t("event-log.field.kind"),
|
|
3895
|
-
value: entry.eventKind === "dispatch" ? t("event-log.kind.dispatch") : t("event-log.kind.settle")
|
|
3981
|
+
value: entry.eventKind === "dispatch" ? t("event-log.kind.dispatch") : entry.eventKind === "settle" ? t("event-log.kind.settle") : entry.eventKind
|
|
3896
3982
|
}),
|
|
3897
3983
|
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
3898
3984
|
field: "status",
|
|
@@ -3902,17 +3988,41 @@ function EventDetailsBody({
|
|
|
3902
3988
|
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
3903
3989
|
field: "expected",
|
|
3904
3990
|
label: t("event-log.field.expected"),
|
|
3905
|
-
value: entry.eventKind === "settle" ? "" : entry.expected ? t("event-log.yes") : t("event-log.no")
|
|
3991
|
+
value: entry.eventKind === "settle" || isWorkflowKind(entry.eventKind) ? "" : entry.expected ? t("event-log.yes") : t("event-log.no")
|
|
3906
3992
|
}),
|
|
3907
3993
|
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
3908
3994
|
field: "settled",
|
|
3909
3995
|
label: t("event-log.field.settled"),
|
|
3910
|
-
value: entry.eventKind === "settle" ? "" : entry.settled ? t("event-log.yes") : t("event-log.no")
|
|
3996
|
+
value: entry.eventKind === "settle" || isWorkflowKind(entry.eventKind) ? "" : entry.settled ? t("event-log.yes") : t("event-log.no")
|
|
3911
3997
|
}),
|
|
3912
3998
|
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
3913
3999
|
field: "duration",
|
|
3914
4000
|
label: t("event-log.field.duration"),
|
|
3915
4001
|
value: entry.durationMs === null ? "" : `${entry.durationMs}ms`
|
|
4002
|
+
}),
|
|
4003
|
+
isWorkflowKind(entry.eventKind) && /* @__PURE__ */ jsx_runtime8.jsxs(jsx_runtime8.Fragment, {
|
|
4004
|
+
children: [
|
|
4005
|
+
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
4006
|
+
field: "run-id",
|
|
4007
|
+
label: t("event-log.field.run-id"),
|
|
4008
|
+
value: source?.runId ?? ""
|
|
4009
|
+
}),
|
|
4010
|
+
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
4011
|
+
field: "name",
|
|
4012
|
+
label: t("event-log.field.name"),
|
|
4013
|
+
value: entry.name
|
|
4014
|
+
}),
|
|
4015
|
+
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
4016
|
+
field: "members",
|
|
4017
|
+
label: t("event-log.field.members"),
|
|
4018
|
+
value: source?.memberCount !== undefined ? String(source.memberCount) : ""
|
|
4019
|
+
}),
|
|
4020
|
+
/* @__PURE__ */ jsx_runtime8.jsx(DetailField, {
|
|
4021
|
+
field: "stop-reason",
|
|
4022
|
+
label: t("event-log.field.stop-reason"),
|
|
4023
|
+
value: source?.stopReason ?? ""
|
|
4024
|
+
})
|
|
4025
|
+
]
|
|
3916
4026
|
})
|
|
3917
4027
|
]
|
|
3918
4028
|
});
|
|
@@ -3923,6 +4033,7 @@ function EventLogEventRow({
|
|
|
3923
4033
|
t
|
|
3924
4034
|
}) {
|
|
3925
4035
|
const time = formatEventTime(entry.ts);
|
|
4036
|
+
const workflowIdentity = isWorkflowKind(entry.eventKind) ? entry.name !== "" ? entry.name : entry.runId !== "" ? entry.runId : "" : "";
|
|
3926
4037
|
return /* @__PURE__ */ jsx_runtime8.jsx("li", {
|
|
3927
4038
|
className: event_log_module_default.eventRow,
|
|
3928
4039
|
"data-event-log-row-kind": "event",
|
|
@@ -3942,6 +4053,9 @@ function EventLogEventRow({
|
|
|
3942
4053
|
className: event_log_module_default.settleGlyph,
|
|
3943
4054
|
"aria-hidden": "true",
|
|
3944
4055
|
children: "✓"
|
|
4056
|
+
}) : workflowIdentity !== "" ? /* @__PURE__ */ jsx_runtime8.jsx("span", {
|
|
4057
|
+
"data-event-log-name": workflowIdentity,
|
|
4058
|
+
children: workflowIdentity
|
|
3945
4059
|
}) : entry.role !== "" ? entry.role : t("panel.unknown")
|
|
3946
4060
|
}),
|
|
3947
4061
|
entry.stage !== "" && /* @__PURE__ */ jsx_runtime8.jsx("span", {
|
package/dist/gates/_shared.d.ts
CHANGED
|
@@ -24,10 +24,11 @@ export interface Config {
|
|
|
24
24
|
enforcement?: 'hard' | 'soft';
|
|
25
25
|
/**
|
|
26
26
|
* Model-facing delegation tool name(s) the dispatch gate matches. The dsh
|
|
27
|
-
* subagent tool registers as `subagent` by default
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* subagent tool registers as `subagent` by default (its fork sibling
|
|
28
|
+
* `subagent_fork` carries the same Assignment-shaped args and is gated
|
|
29
|
+
* too), but the `toolName` config may rename instances (tool-subagent
|
|
30
|
+
* README: each instance needs a distinct name), so the match list is
|
|
31
|
+
* deployment-settable. Defaults to `['subagent', 'subagent_fork']`.
|
|
31
32
|
*/
|
|
32
33
|
dispatchTools?: string[];
|
|
33
34
|
/**
|
|
@@ -68,8 +69,93 @@ export interface Config {
|
|
|
68
69
|
* per interval). Absent → 60000.
|
|
69
70
|
*/
|
|
70
71
|
catalogTtlMs?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Taxonomy bridge: mstar role id → fallbacks role id (the
|
|
74
|
+
* `dsh-llm-fallbacks` role taxonomy). Logging + future rule-driven
|
|
75
|
+
* interop only — NOT required for persona injection (`rolePersonas` is
|
|
76
|
+
* the decoration's only payload source). Absent → no bridge mapping.
|
|
77
|
+
*/
|
|
78
|
+
roleMap?: Record<string, string>;
|
|
79
|
+
/**
|
|
80
|
+
* mstar role id → persona text — the subagent decoration's only payload
|
|
81
|
+
* source (plan `20260814-dsh-fallbacks-integration` Task 2). A
|
|
82
|
+
* role-matched `subagent/start` registers the persona as the child's
|
|
83
|
+
* `mstar:role-persona` system-prompt section (agent-scoped on
|
|
84
|
+
* `Agent.ctx`, unwinds on disposal). Lookup is DIRECT — never gated on
|
|
85
|
+
* `roleMap` or on the fallbacks mounted state (unmounted → same
|
|
86
|
+
* injection from Config + one debug log). Absent → no decoration.
|
|
87
|
+
*
|
|
88
|
+
* INTERPOLATION CONSTRAINT: dsh system-prompt renders section text with
|
|
89
|
+
* STRICT `{{variable}}` interpolation and throws on any `{{` paired with a
|
|
90
|
+
* later `}}` (unknown/malformed/undefined reference), so persona values
|
|
91
|
+
* MUST NOT contain that pattern — a violating persona would break child
|
|
92
|
+
* prompt assembly at the child's first render, for EVERY role-matched
|
|
93
|
+
* dispatch. The Config schema rejects such values at plugin mount with a
|
|
94
|
+
* clear error (see {@link PERSONA_INTERPOLATION_HAZARD}); a lone `{{` with
|
|
95
|
+
* no later `}}` is literal prose (safe), and the escape rule is single
|
|
96
|
+
* braces or rewording. Keep persona text concise; bound its length at
|
|
97
|
+
* deployment.
|
|
98
|
+
*/
|
|
99
|
+
rolePersonas?: Record<string, string>;
|
|
100
|
+
/**
|
|
101
|
+
* Workflow/ralph gate mode (plan `20260815-dsh-workflow-gate` W-B3, AC-7):
|
|
102
|
+
* `off` disables the gate entirely (workflow/ralph calls pass through
|
|
103
|
+
* untouched, NO verdict row); `warn` (default) logs an advisory for
|
|
104
|
+
* policy-unknown fan-out without ever blocking; `ask` routes first-seen
|
|
105
|
+
* workflow names through the dsh approval channel (`{kind:'ask'}` —
|
|
106
|
+
* fail-closed upstream, this gate invents no answerer); `hard` vetoes a
|
|
107
|
+
* policy-violating fan-out call before any child starts. Absent → 'warn'.
|
|
108
|
+
*/
|
|
109
|
+
workflowGate?: 'off' | 'warn' | 'ask' | 'hard';
|
|
110
|
+
/**
|
|
111
|
+
* Workflow name allowlist (P-a): `meta.name` values treated as KNOWN by
|
|
112
|
+
* the gate. Empty or absent ⇒ every name is unknown (documented — the
|
|
113
|
+
* gate is NOT "allow all" by omission). Ralph calls carry no `meta.name`,
|
|
114
|
+
* so P-a never applies to them.
|
|
115
|
+
*/
|
|
116
|
+
workflowNames?: string[];
|
|
117
|
+
/**
|
|
118
|
+
* Goal-bridge round cap (plan `20260816-dsh-nb2-goal-bridge` Task 2): the
|
|
119
|
+
* flat `maxGoalRounds` the goal bridge passes to the goals service when it
|
|
120
|
+
* mirrors the active iteration objective (bounds autonomous Phase 2
|
|
121
|
+
* loops — the service itself throws on resume past the cap). Absent →
|
|
122
|
+
* 256 (aligned with the GoalService default and ralph `maxRounds` —
|
|
123
|
+
* architect decision; see the plan).
|
|
124
|
+
*/
|
|
125
|
+
maxGoalRounds?: number;
|
|
71
126
|
}
|
|
72
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* dsh system-prompt strict `{{variable}}` interpolation hazard: the renderer
|
|
129
|
+
* (`renderPrompt` → `interpolate` in `@deepseek-ai/dsh-system-prompt`) scans
|
|
130
|
+
* section text for `{{` and THROWS on any `{{` paired with a later `}}` in
|
|
131
|
+
* the same text (unknown variable, malformed group, or undefined value).
|
|
132
|
+
* Persona text lands in the `mstar:role-persona` section verbatim, so a
|
|
133
|
+
* persona containing this pattern breaks child prompt assembly at the
|
|
134
|
+
* child's first render — every role-matched dispatch. The Config schema
|
|
135
|
+
* rejects such values at validation (plugin mount) with a clear error. The
|
|
136
|
+
* mirror-default extraction (agent-personas.ts) reuses this constant: a
|
|
137
|
+
* violating default is WARNED + skipped at extraction, never a boot throw. A
|
|
138
|
+
* lone `{{` with no later `}}` is literal prose (safe); the escape rule is
|
|
139
|
+
* single braces or rewording.
|
|
140
|
+
*/
|
|
141
|
+
export declare const PERSONA_INTERPOLATION_HAZARD: RegExp;
|
|
142
|
+
/**
|
|
143
|
+
* Screen ONE dynamic string before it is embedded into dsh system-prompt
|
|
144
|
+
* section/context text (plan QC fix wave W-1): break every COMPLETE
|
|
145
|
+
* `{{...}}` group (the renderer's STRICT `interpolate` throws on any `{{`
|
|
146
|
+
* paired with a later `}}` — unknown variable, malformed group, undefined
|
|
147
|
+
* value), while leaving a LONE `{{` without a later `}}` verbatim (upstream
|
|
148
|
+
* renders it as literal prose — already safe, do not mangle it).
|
|
149
|
+
*
|
|
150
|
+
* A complete group is rewritten to `{ {…} }` (a space inside each pair), so
|
|
151
|
+
* no adjacent `{{`/`}}` survives the renderer scan; the rewrite is re-scanned
|
|
152
|
+
* because a nested/adjacent brace at either boundary can expose a fresh pair.
|
|
153
|
+
* The output is plain text the renderer treats as literal — operator-chosen
|
|
154
|
+
* values (paths, plan/iteration ids, lease fields, compass direction prose)
|
|
155
|
+
* can never break prompt assembly.
|
|
156
|
+
*/
|
|
157
|
+
export declare function stripInterpolationHazard(text: string): string;
|
|
158
|
+
/** Schemastery configuration schema for the plugin consumer. Object keys are optional by default (`.optional()` is a vendored-fork addition not present in npm schemastery); omitted ARRAY keys would materialize as `[]` (schemastery empty-value default — the tool-subagent `toolFilter` pitfall) and omitted DICT keys would materialize as `{}`, so the dispatch keys and the decoration keys all preserve omission via `.default(undefined)`. */
|
|
73
159
|
export declare const Config: z<Config>;
|
|
74
160
|
/** One violation line for logs and the typed veto message. */
|
|
75
161
|
export declare function formatViolation(violation: ValidationResult): string;
|
|
@@ -117,6 +203,19 @@ export declare function resolveSeamHard(harnessDir: string | null, config: Confi
|
|
|
117
203
|
*/
|
|
118
204
|
export declare function resolvePackagedSkillsDir(fileUrl: string): string | undefined;
|
|
119
205
|
export declare function packagedSkillsDir(): string | undefined;
|
|
206
|
+
/**
|
|
207
|
+
* Resolve the plugin package's own `harness-agents/` mirror (synced from the
|
|
208
|
+
* repo root by `bundle-assets` at build/postinstall; gitignored) — the
|
|
209
|
+
* zero-config role-persona default source (plan
|
|
210
|
+
* `20260815-dsh-fallbacks-personas` Task 3). Same dual-depth probe semantics
|
|
211
|
+
* as {@link resolvePackagedSkillsDir}: `'../harness-agents'` (dist layout
|
|
212
|
+
* candidate) then `'../../harness-agents'` (source-layout candidate);
|
|
213
|
+
* `src/harness-agents` is non-canonical and skipped shallow-first.
|
|
214
|
+
* @param fileUrl - the module's `import.meta.url` string (or any file URL at
|
|
215
|
+
* the depth whose layout should be probed).
|
|
216
|
+
*/
|
|
217
|
+
export declare function resolvePackagedAgentsDir(fileUrl: string): string | undefined;
|
|
218
|
+
export declare function packagedAgentsDir(): string | undefined;
|
|
120
219
|
/**
|
|
121
220
|
* Per-workspace `{HARNESS_DIR}` resolution for the plugin.
|
|
122
221
|
*
|
package/dist/gates/adapter.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { Service, type Context } from '@deepseek-ai/cordis';
|
|
|
2
2
|
import type { AssignmentFields, GateResult, HostAdapter, IntegrationMergeLease, ValidationResult } from '@mstar-harness/engine';
|
|
3
3
|
import type { ToolExecution } from '@deepseek-ai/dsh-tools';
|
|
4
4
|
import type { HarnessResolver, Config } from './_shared.ts';
|
|
5
|
-
import type { AgentFlowPairing } from './agent-flow.ts';
|
|
5
|
+
import type { AgentFlowPairing, WorkflowVerdictInput } from './agent-flow.ts';
|
|
6
|
+
import { WorkflowAskCache } from './workflow-policy.ts';
|
|
6
7
|
/** Options for {@link DshHostAdapter}. */
|
|
7
8
|
export interface DshHostAdapterOptions {
|
|
8
9
|
/**
|
|
@@ -22,6 +23,16 @@ export interface DshHostAdapterOptions {
|
|
|
22
23
|
* construction) → no pairing registration (record-only).
|
|
23
24
|
*/
|
|
24
25
|
readonly pairing?: AgentFlowPairing;
|
|
26
|
+
/**
|
|
27
|
+
* The P-c first-seen ask cache (plan `20260815-dsh-workflow-gate`
|
|
28
|
+
* Task 2): workflow name → resolved decision, apply-scoped. Absent (the
|
|
29
|
+
* entry relies on this default — `index.ts` constructs the adapter
|
|
30
|
+
* without it) → the constructor builds ONE cache per adapter per apply,
|
|
31
|
+
* shared by the gate and any answerer integration via the readonly
|
|
32
|
+
* property. An explicit instance may be passed to share a specific cache
|
|
33
|
+
* (host-adapter tests / direct construction).
|
|
34
|
+
*/
|
|
35
|
+
readonly workflowAskCache?: WorkflowAskCache;
|
|
25
36
|
/**
|
|
26
37
|
* Log sink for `HostAdapter.log`. Defaults to the dsh ctx logger scoped
|
|
27
38
|
* `mstar/host-adapter` (dsh logger naming: `<scope>/<subject>`).
|
|
@@ -64,6 +75,14 @@ export declare class DshHostAdapter extends Service implements HostAdapter {
|
|
|
64
75
|
private readonly resolver;
|
|
65
76
|
private readonly config;
|
|
66
77
|
private readonly pairing;
|
|
78
|
+
/**
|
|
79
|
+
* The P-c first-seen ask cache (plan `20260815-dsh-workflow-gate`
|
|
80
|
+
* Task 2) — apply-scoped with the adapter: the dispatch gate reads it
|
|
81
|
+
* through `gateDispatch`, and tests/answerer integrations reach the same
|
|
82
|
+
* instance via `ctx.dshHostAdapter.workflowAskCache`. Dies with the
|
|
83
|
+
* fiber (no module-level reference — an HMR reload starts a fresh cache).
|
|
84
|
+
*/
|
|
85
|
+
readonly workflowAskCache: WorkflowAskCache;
|
|
67
86
|
private readonly logSink;
|
|
68
87
|
constructor(ctx: Context, options: DshHostAdapterOptions);
|
|
69
88
|
/**
|
|
@@ -98,6 +117,20 @@ export declare class DshHostAdapter extends Service implements HostAdapter {
|
|
|
98
117
|
* when omitted (external callers) the adapter resolves it itself.
|
|
99
118
|
*/
|
|
100
119
|
dispatchGate(prompt: string, exec?: ToolExecution, hard?: boolean): GateResult;
|
|
120
|
+
/**
|
|
121
|
+
* Record one workflow/ralph gate verdict row (plan
|
|
122
|
+
* `20260815-dsh-workflow-gate` Task 4 — the durable ledger row for every
|
|
123
|
+
* gated workflow/ralph call: verdict + metaName/objective + mode, via the
|
|
124
|
+
* ledger plan's record path). `gateWorkflow` routes the record through
|
|
125
|
+
* this adapter method so dispatch.ts stays free of a runtime agent-flow
|
|
126
|
+
* import (the ledger imports dispatch helpers — the adapter is the
|
|
127
|
+
* acyclic junction, the same role it plays for `dispatchGate`). The
|
|
128
|
+
* underlying record is fully try/catch-contained (a failing ledger write
|
|
129
|
+
* logs and never reaches the gate) — this method never throws.
|
|
130
|
+
* @param input - the gate's decision identity (harness dir + tool +
|
|
131
|
+
* workflow/objective + mode + verdict + code).
|
|
132
|
+
*/
|
|
133
|
+
recordWorkflowVerdict(input: WorkflowVerdictInput): void;
|
|
101
134
|
/**
|
|
102
135
|
* `HostAdapter.beforeStatusWrite` — see the class doc for the doc-first /
|
|
103
136
|
* on-disk-fallback semantics. Never throws; a failing gate maps to its
|