@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
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow/ralph gate policy — the P-a name allowlist + P-b lease
|
|
3
|
+
* attribution + P-c first-seen ask (plan `20260815-dsh-workflow-gate`
|
|
4
|
+
* Tasks 2–3, W-B3). The policy is the SINGLE
|
|
5
|
+
* decision point for the four-tier `workflowGate` mode semantics
|
|
6
|
+
* (`off | warn | ask | hard`, default `warn`): it turns one composed
|
|
7
|
+
* {@link WorkflowGateInput} (Task 1) into `allow | warn | ask | deny` + a
|
|
8
|
+
* reason. The dispatch-gate listener maps the verdict to the
|
|
9
|
+
* `tools/pre-execute` refusal vocabulary (`PreToolDecision`) — this module
|
|
10
|
+
* NEVER throws and NEVER builds an approval path: an `ask` verdict flows
|
|
11
|
+
* through dsh's own approval waterfall (fail-closed upstream, this gate
|
|
12
|
+
* invents no answerer).
|
|
13
|
+
*
|
|
14
|
+
* Policy matrix (mode × P-a/P-b/P-c):
|
|
15
|
+
*
|
|
16
|
+
* | input | mode | verdict |
|
|
17
|
+
* |---|---|---|
|
|
18
|
+
* | uncovered InProgress plan (P-b) | `off` | allow — the gate short-circuits `off` before the policy; kept here for a total policy |
|
|
19
|
+
* | uncovered InProgress plan (P-b) | `hard` | deny — reason cites the uncovered plan id, veto before any child starts |
|
|
20
|
+
* | uncovered InProgress plan (P-b) | `warn`/`ask` | warn — allowed + advisory verdict + one warn (the ask channel is for first-seen NAMES, never the workspace red line) |
|
|
21
|
+
* | ralph (no `meta.name`), covered/read-only | any | allow — P-a/P-c NEVER apply to ralph (no allowlist identity); P-b applies |
|
|
22
|
+
* | workflow, name ∈ `workflowNames` (non-empty list), covered | any | allow — the allowlist passes under every mode |
|
|
23
|
+
* | workflow, unknown (empty/absent list ⇒ EVERY name unknown), covered | `off` | allow — the gate short-circuits `off` before the policy; kept here for a total policy |
|
|
24
|
+
* | workflow, unknown, covered | `warn` | warn — advisory + one warn (Task 1 behavior, now centralized) |
|
|
25
|
+
* | workflow, unknown, covered | `hard` | deny — reason names the workflow name, veto before any child starts |
|
|
26
|
+
* | workflow, unknown, covered, first-seen (no cached decision) | `ask` | ask — `{kind:'ask'}` through the approval waterfall + the name is marked asked (W-1 — the run-start observation promotes only asked names to allow) |
|
|
27
|
+
* | workflow, unknown, covered, cached allow | `ask` | allow — cached decision, NO re-ask |
|
|
28
|
+
* | workflow, unknown, covered, cached deny | `ask` | deny — cached decision, NO re-ask |
|
|
29
|
+
*
|
|
30
|
+
* P-c cache lifecycle: the {@link WorkflowAskCache} is apply-scoped — created
|
|
31
|
+
* per plugin `apply` (owned by the host adapter, constructed with it) and
|
|
32
|
+
* closed over by the listener; there is NO module-level Map, so disposal
|
|
33
|
+
* (fiber teardown / HMR reload) makes the cache unreachable with the apply
|
|
34
|
+
* and a fresh apply starts with an empty cache. The cache records only
|
|
35
|
+
* RESOLVED decisions (`allow` | `deny`) keyed by workflow name.
|
|
36
|
+
*
|
|
37
|
+
* Cache-key normalization (Task 5 fold-in — the Task-4 Important congruence
|
|
38
|
+
* fix): every key — the gate's `metaName` (composed through
|
|
39
|
+
* {@link normalizeWorkflowName} in dispatch.ts `workflowGateInputOf`), the
|
|
40
|
+
* run-start observation's `runName` (workflow-ledger.ts), and the explicit
|
|
41
|
+
* `record()` / `markAsked()` APIs (which normalize internally, F-302) — is
|
|
42
|
+
* the ASCII-control-char-stripped, UNCAPPED name. One shared function, both
|
|
43
|
+
* seams; a control-char name (`au\u0000dit`) gates and observes under the
|
|
44
|
+
* same normalized key (`audit`), and the length is never capped on the
|
|
45
|
+
* identity axis (the ledger ROW display field is capped separately — the
|
|
46
|
+
* cache key stays the full name, matching the gate).
|
|
47
|
+
*
|
|
48
|
+
* Answer-recording seam (`WorkflowAskCache.record` + W-1 `markAsked`): the
|
|
49
|
+
* gate CANNOT observe the ask outcome directly — the tool registry's
|
|
50
|
+
* `serviceAsk` consumes the approval result internally (`deepseek-harness
|
|
51
|
+
* packages/core/tools/src/index.ts`, `prepareExecution`/`serviceAsk`) — so
|
|
52
|
+
* the ANSWER reaches the cache through the workflow-ledger consumer's
|
|
53
|
+
* run-start observation (plan `20260815-dsh-workflow-gate` Task 4 fold-in —
|
|
54
|
+
* the Task-2 Important handoff): an ALLOWED ask executes the call, the
|
|
55
|
+
* durable `tool-workflow/run-start` session event carries the run name, and
|
|
56
|
+
* the consumer records `allow` for it (`workflow-ledger.ts`). The policy
|
|
57
|
+
* marks every name that received an `ask` verdict in this apply
|
|
58
|
+
* (`markAsked`, at the single ask point), and the observation promotes ONLY
|
|
59
|
+
* marked names to `allow` — a run observed WITHOUT a prior ask (a P-b
|
|
60
|
+
* advisory under `ask` mode, a `warn`/`off`-mode run) is NOT an approval
|
|
61
|
+
* resolution and never pre-authorizes the name (qc2 W-1). A DENIED answer
|
|
62
|
+
* produces no run → no observation → the next same-name call re-asks
|
|
63
|
+
* (fail-closed — no grant evidence, never an invented allow). The explicit
|
|
64
|
+
* `record()` API stays the general seam — an answerer integration or the
|
|
65
|
+
* tests may drive it directly, and an unresolved first-seen re-asks per
|
|
66
|
+
* call until the observation (or an explicit record) lands.
|
|
67
|
+
*
|
|
68
|
+
* Module boundary: no barrel. This module imports dispatch.ts TYPE-ONLY
|
|
69
|
+
* (`WorkflowGateInput` — erased at runtime, no cycle); dispatch.ts imports
|
|
70
|
+
* the policy/cache values from here. The P-a vocabulary
|
|
71
|
+
* (`workflowNameUnknown`, `WORKFLOW_NAME_UNKNOWN_CODE`) centralized HERE from
|
|
72
|
+
* Task 1's dispatch.ts.
|
|
73
|
+
*/
|
|
74
|
+
import type { Config } from './_shared.ts';
|
|
75
|
+
import type { WorkflowGateInput } from './dispatch.ts';
|
|
76
|
+
/**
|
|
77
|
+
* The workflow-gate advisory/deny violation code for a name outside the P-a
|
|
78
|
+
* allowlist (warn-mode advisory / hard-mode veto reason — Task 2/3 policies
|
|
79
|
+
* share this vocabulary).
|
|
80
|
+
*/
|
|
81
|
+
export declare const WORKFLOW_NAME_UNKNOWN_CODE = "workflow.name.unknown";
|
|
82
|
+
/**
|
|
83
|
+
* The workflow-gate advisory/deny violation code for P-b lease attribution
|
|
84
|
+
* (Task 3): the calling workspace has an `InProgress` plan without
|
|
85
|
+
* `execution_lease` coverage (warn-mode advisory / hard-mode veto reason —
|
|
86
|
+
* the reason cites the uncovered plan id).
|
|
87
|
+
*/
|
|
88
|
+
export declare const WORKFLOW_LEASE_UNCOVERED_CODE = "workflow.lease.uncovered";
|
|
89
|
+
/**
|
|
90
|
+
* Strip ASCII control characters (newlines / tabs / CR — the log-forging
|
|
91
|
+
* surface, qc2 S-1) from one workflow name. THE shared P-c cache-key
|
|
92
|
+
* normalization (plan `20260815-dsh-workflow-gate` Task 5 fold-in — the
|
|
93
|
+
* Task-4 Important congruence fix): the gate's `metaName` (composed in
|
|
94
|
+
* dispatch.ts `workflowGateInputOf`) and the run-start observation's
|
|
95
|
+
* `runName` (workflow-ledger.ts) MUST key the ask cache through the SAME
|
|
96
|
+
* function — a raw-vs-stripped mismatch (e.g. `au\u0000dit` gating under
|
|
97
|
+
* one key while the observation records another) would re-ask a resolved
|
|
98
|
+
* name forever. Pure — NEVER throws. The ledger's other display fields
|
|
99
|
+
* (`label` / `phase`) use the same strip; ID-sized fields (`runId` /
|
|
100
|
+
* `childId`) are NOT routed here — they keep their skip-if-oversized
|
|
101
|
+
* semantics.
|
|
102
|
+
*/
|
|
103
|
+
export declare function normalizeWorkflowName(value: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* P-a allowlist membership: a workflow name is UNKNOWN when `workflowNames`
|
|
106
|
+
* is absent or empty (⇒ every name unknown — documented, the gate is NOT
|
|
107
|
+
* "allow all" by omission) or the name is not listed. Ralph calls carry no
|
|
108
|
+
* `meta.name` — P-a never applies to them (callers guard on
|
|
109
|
+
* `input.metaName !== undefined` first).
|
|
110
|
+
*
|
|
111
|
+
* Comparison boundary (qc1-S2): entries are normalized through
|
|
112
|
+
* {@link normalizeWorkflowName} BEFORE the comparison — the gate's
|
|
113
|
+
* `metaName` is already stripped, so an operator-pasted control-char
|
|
114
|
+
* variant (trailing newline, copied config value) matches the same
|
|
115
|
+
* identity instead of silently degrading to unknown. The operator's config
|
|
116
|
+
* array is NEVER mutated — the normalization happens at the boundary only.
|
|
117
|
+
*/
|
|
118
|
+
export declare function workflowNameUnknown(config: Config, metaName: string): boolean;
|
|
119
|
+
/** One workflow name's resolved P-c decision (the cache value). */
|
|
120
|
+
export type WorkflowAskCacheDecision = 'allow' | 'deny';
|
|
121
|
+
/**
|
|
122
|
+
* The P-c per-session first-seen cache: workflow name → resolved decision.
|
|
123
|
+
* Apply-scoped (one instance per plugin `apply`, owned by the host adapter —
|
|
124
|
+
* see the module doc for the lifecycle). Records ONLY resolved decisions; a
|
|
125
|
+
* miss means first-seen (or an unanswered ask) → the policy asks again.
|
|
126
|
+
*
|
|
127
|
+
* W-1 (qc2 fix-wave): the cache ALSO tracks which names received an `ask`
|
|
128
|
+
* verdict in this apply ({@link markAsked} — the gate marks EVERY ask
|
|
129
|
+
* decision at the policy's single ask point). The run-start observation
|
|
130
|
+
* (workflow-ledger.ts) records `allow` ONLY for names marked-asked — a run
|
|
131
|
+
* that happened without an ask (P-b advisory under `ask` mode, a
|
|
132
|
+
* `warn`/`off`-mode run) is NOT an approval resolution and must not
|
|
133
|
+
* pre-authorize the name.
|
|
134
|
+
*
|
|
135
|
+
* F-302 (qc3 fix-wave): the WRITE seams ({@link record} / {@link markAsked})
|
|
136
|
+
* normalize their keys internally — the "ONE shared normalization" contract
|
|
137
|
+
* holds even for a caller that passes a raw spelling (today's production
|
|
138
|
+
* callers already normalize before calling; this is defense-in-depth for the
|
|
139
|
+
* documented answerer-integration seam). {@link get} stays a verbatim read —
|
|
140
|
+
* the gate always passes the normalized `metaName`, and the raw spelling is
|
|
141
|
+
* never stored (test 13 pins that).
|
|
142
|
+
*/
|
|
143
|
+
export declare class WorkflowAskCache {
|
|
144
|
+
private readonly decisions;
|
|
145
|
+
/** Names that received an `ask` verdict in this apply (W-1 — the observation promotes ONLY asked names to allow). */
|
|
146
|
+
private readonly asked;
|
|
147
|
+
/** The resolved decision for `name`, or undefined when never resolved. */
|
|
148
|
+
get(name: string): WorkflowAskCacheDecision | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* Record the approval-flow outcome for `name` (the ask's ANSWER — the
|
|
151
|
+
* answerer integration's seam; see the module doc). Subsequent same-name
|
|
152
|
+
* calls under `ask` reuse the cached decision without re-asking. The key
|
|
153
|
+
* is normalized internally (F-302).
|
|
154
|
+
*/
|
|
155
|
+
record(name: string, decision: WorkflowAskCacheDecision): void;
|
|
156
|
+
/**
|
|
157
|
+
* Mark `name` as having received an `ask` verdict in this apply (W-1).
|
|
158
|
+
* Called by the policy on EVERY ask decision, BEFORE the verdict is
|
|
159
|
+
* returned — the run-start observation promotes only marked names to
|
|
160
|
+
* `allow`. The key is normalized internally.
|
|
161
|
+
*/
|
|
162
|
+
markAsked(name: string): void;
|
|
163
|
+
/** Whether `name` received an `ask` verdict in this apply (the observation's promote gate). Normalizes internally. */
|
|
164
|
+
wasAsked(name: string): boolean;
|
|
165
|
+
}
|
|
166
|
+
/** The four-tier policy decision vocabulary (plan W-B3, Task 2). */
|
|
167
|
+
export type WorkflowPolicyDecision = 'allow' | 'warn' | 'ask' | 'deny';
|
|
168
|
+
/**
|
|
169
|
+
* One policy verdict: the decision + a human-readable reason + the violation
|
|
170
|
+
* code for the warn/ask/deny vocabulary (the caller emits `code` in the
|
|
171
|
+
* advisory row — the gate never guesses which policy fired).
|
|
172
|
+
*/
|
|
173
|
+
export type WorkflowPolicyVerdict = {
|
|
174
|
+
decision: 'allow';
|
|
175
|
+
reason?: undefined;
|
|
176
|
+
code?: undefined;
|
|
177
|
+
} | {
|
|
178
|
+
decision: 'warn' | 'ask' | 'deny';
|
|
179
|
+
reason: string;
|
|
180
|
+
code: string;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* The workflow/ralph gate policy — P-a name allowlist + P-c first-seen ask
|
|
184
|
+
* (plan `20260815-dsh-workflow-gate` Task 2). `config` + cache + composed
|
|
185
|
+
* input → verdict; the caller (dispatch gate) maps the verdict to the
|
|
186
|
+
* `PreToolDecision` refusal vocabulary and owns the advisory emit/log
|
|
187
|
+
* infrastructure. The ONE cache write is contained: an `ask` verdict marks
|
|
188
|
+
* the name via `WorkflowAskCache.markAsked` (W-1 — see the cache doc)
|
|
189
|
+
* before returning; `markAsked` never throws. NEVER throws.
|
|
190
|
+
*
|
|
191
|
+
* P-b: `input.uncoveredPlanId` (the dispatch gate computes it from the
|
|
192
|
+
* calling workspace's status.json — see dispatch.ts `writableFanOutUncovered`)
|
|
193
|
+
* → hard denies (reason cites the plan id), warn/ask emit the advisory
|
|
194
|
+
* verdict; `off` always allows. Preempts P-a/P-c: an orphan InProgress plan
|
|
195
|
+
* is a workspace red line independent of the workflow name.
|
|
196
|
+
* P-a: `metaName ∈ workflowNames` (empty/absent list ⇒ every name unknown);
|
|
197
|
+
* allowlisted → allow under ANY mode. Unknown → per-mode: `warn` → advisory
|
|
198
|
+
* verdict; `hard` → deny (reason names the workflow name); `ask` → first-seen
|
|
199
|
+
* `{kind:'ask'}` verdict, afterwards the cached decision (allow/deny), never
|
|
200
|
+
* a re-ask for a resolved name. Ralph carries no `meta.name` — P-a/P-c never
|
|
201
|
+
* apply to it (P-b applies).
|
|
202
|
+
*/
|
|
203
|
+
export declare function workflowPolicy(config: Config, cache: WorkflowAskCache, input: WorkflowGateInput): WorkflowPolicyVerdict;
|
package/dist/index.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ import type { DispatchGateAdvisory } from './gates/dispatch.ts';
|
|
|
17
17
|
export { DshMstar } from './service.ts';
|
|
18
18
|
export type { DshMstarOptions } from './service.ts';
|
|
19
19
|
export type { MstarEngineStatusSource, MstarHarnessState, MstarIterationGateView, AgentFlowEventView, AgentFlowSummaryRow, AgentFlowView, } from './types.ts';
|
|
20
|
-
export { AGENT_FLOW_FILE, AGENT_FLOW_MAX_EVENTS, SETTLE_SEAM, readAgentFlow, recordDispatch, recordSettle, } from './gates/agent-flow.ts';
|
|
21
|
-
export type { AgentFlowEvent, DispatchVerdict, SettleOutcome } from './gates/agent-flow.ts';
|
|
20
|
+
export { AGENT_FLOW_FILE, AGENT_FLOW_MAX_EVENTS, SETTLE_SEAM, readAgentFlow, recordDispatch, recordSettle, recordWorkflowVerdict, } from './gates/agent-flow.ts';
|
|
21
|
+
export type { AgentFlowEvent, DispatchVerdict, SettleOutcome, WorkflowGateMode, WorkflowVerdict, WorkflowVerdictInput, } from './gates/agent-flow.ts';
|
|
22
22
|
export { Config, HarnessResolver, skillLocalConfig } from './gates/_shared.ts';
|
|
23
23
|
export type { StatusGateAdvisory } from './gates/status.ts';
|
|
24
24
|
export { SkillLintVetoError, lintSkillDoc, lintSkillWrite } from './gates/skill-lint.ts';
|
|
@@ -26,14 +26,20 @@ export type { SkillLintAdvisory } from './gates/skill-lint.ts';
|
|
|
26
26
|
export { SeamVetoError, lintSeamWrite, lintDesignMdWrite, lintAuditWrite, lintCompoundWrite, lintRolesWrite } from './gates/seams.ts';
|
|
27
27
|
export type { SeamId, SeamLintAdvisory } from './gates/seams.ts';
|
|
28
28
|
export type { DispatchGateAdvisory } from './gates/dispatch.ts';
|
|
29
|
+
export { DECORATION_LOGGER, PERSONA_SECTION_NAME, PERSONA_SECTION_ORDER, decorateSubagentStart, setDecorationAgentsDir, setDecorationLogger, } from './gates/fallbacks-decoration.ts';
|
|
30
|
+
export type { DecorationLogLevel, DecorationLogSink, SubagentRunInfoView } from './gates/fallbacks-decoration.ts';
|
|
31
|
+
export { ADVISORY_LOGGER, runFallbacksAdvisory, setAdvisoryLogger } from './gates/fallbacks-advisory.ts';
|
|
32
|
+
export type { AdvisoryLogLevel, AdvisoryLogSink } from './gates/fallbacks-advisory.ts';
|
|
29
33
|
export { DshHostAdapter } from './gates/adapter.ts';
|
|
30
34
|
export type { DshHostAdapterOptions } from './gates/adapter.ts';
|
|
31
35
|
/** Cordis function-plugin name registered by the Loader. */
|
|
32
36
|
export declare const name = "dsh";
|
|
33
37
|
/**
|
|
34
38
|
* Services required before this plugin's `apply` fiber starts.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
39
|
+
* `loader` — the dsh profile loader's entry tree — is guaranteed before
|
|
40
|
+
* apply (the plugin row is composed BY the loader), so the Task 1 probe can
|
|
41
|
+
* read `ctx.loader.entries()` at decision points (plugin-inventory
|
|
42
|
+
* precedent; no runtime dependency on `@deepseek-ai/cordis-plugin-loader`).
|
|
37
43
|
*/
|
|
38
44
|
export declare const inject: string[];
|
|
39
45
|
declare module '@deepseek-ai/cordis' {
|