@mstar-harness/dsh 2.1.1
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 +7 -0
- package/README.md +448 -0
- package/README.zh.md +221 -0
- package/bundle/README.md +312 -0
- package/bundle/cordis.patch.yml +17 -0
- package/dist/client/index.d.ts +14 -0
- package/dist/client/panel/PanelView.d.ts +67 -0
- package/dist/client/panel/TabNav.d.ts +28 -0
- package/dist/client/panel/graph/event-log.d.ts +76 -0
- package/dist/client/panel/graph/project-graph.d.ts +499 -0
- package/dist/client/panel/graph/schema.d.ts +224 -0
- package/dist/client/panel/guards.d.ts +12 -0
- package/dist/client/panel/locale.d.ts +134 -0
- package/dist/client/panel/pages/AgentCanvasPage.d.ts +363 -0
- package/dist/client/panel/pages/EventLogPage.d.ts +48 -0
- package/dist/client/panel/pages/IterationInfoSection.d.ts +80 -0
- package/dist/client/panel/pages/IterationTaskPage.d.ts +37 -0
- package/dist/client/panel/panel-meta.d.ts +18 -0
- package/dist/client/panel/plan-sort.d.ts +54 -0
- package/dist/client/panel/sidebar.d.ts +17 -0
- package/dist/client/panel/state-section.d.ts +23 -0
- package/dist/client/panel/use-mstar-engine-status.d.ts +42 -0
- package/dist/client/panel/zones/Legend.d.ts +18 -0
- package/dist/client/panel/zones/TaskBoard.d.ts +40 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +4486 -0
- package/dist/gates/_shared.d.ts +198 -0
- package/dist/gates/adapter.d.ts +131 -0
- package/dist/gates/agent-flow.d.ts +320 -0
- package/dist/gates/catalog.d.ts +118 -0
- package/dist/gates/dispatch.d.ts +152 -0
- package/dist/gates/seams.d.ts +152 -0
- package/dist/gates/skill-lint.d.ts +87 -0
- package/dist/gates/status.d.ts +81 -0
- package/dist/gates/tools.d.ts +37 -0
- package/dist/index.d.ts +107 -0
- package/dist/index.js +5748 -0
- package/dist/invariant.d.ts +15 -0
- package/dist/invariant.js +29 -0
- package/dist/service.d.ts +96 -0
- package/dist/types.d.ts +241 -0
- package/harness-commands/codebase-audit.md +40 -0
- package/harness-commands/iteration-drive.md +129 -0
- package/harness-commands/iteration-loop.md +139 -0
- package/harness-commands/iteration-start.md +179 -0
- package/harness-skills/grill-me/SKILL.md +10 -0
- package/harness-skills/mstar-audit/SKILL.md +183 -0
- package/harness-skills/mstar-audit/references/audit-playbook.md +130 -0
- package/harness-skills/mstar-audit/references/finding-format.md +65 -0
- package/harness-skills/mstar-branch-worktree/SKILL.md +219 -0
- package/harness-skills/mstar-branch-worktree/references/parallel-writable-pre-dispatch.md +68 -0
- package/harness-skills/mstar-coding-behavior/SKILL.md +147 -0
- package/harness-skills/mstar-compound/SKILL.md +105 -0
- package/harness-skills/mstar-compound/assets/resolution-template.md +94 -0
- package/harness-skills/mstar-compound/references/category-mapping.md +37 -0
- package/harness-skills/mstar-compound/references/compound-workflow.md +155 -0
- package/harness-skills/mstar-compound/references/concepts-vocabulary.md +44 -0
- package/harness-skills/mstar-compound/references/schema.yaml +122 -0
- package/harness-skills/mstar-compound-refresh/SKILL.md +140 -0
- package/harness-skills/mstar-compound-refresh/references/project-knowledge-bootstrap.md +164 -0
- package/harness-skills/mstar-design-md/SKILL.md +142 -0
- package/harness-skills/mstar-design-md/references/completeness-checklist.md +181 -0
- package/harness-skills/mstar-design-md/references/design-md-spec.md +508 -0
- package/harness-skills/mstar-design-md/references/vercel-example.md +200 -0
- package/harness-skills/mstar-design-md/templates/DESIGN.dark.md.template +354 -0
- package/harness-skills/mstar-design-md/templates/DESIGN.md.template +474 -0
- package/harness-skills/mstar-dispatch-gates/SKILL.md +128 -0
- package/harness-skills/mstar-dispatch-gates/references/leaf-executor-checklist.md +23 -0
- package/harness-skills/mstar-harness-core/SKILL.md +180 -0
- package/harness-skills/mstar-host/SKILL.md +78 -0
- package/harness-skills/mstar-host/references/_shared/host-role-binding-core.md +51 -0
- package/harness-skills/mstar-host/references/_shared/plan-mode-bridge-core.md +91 -0
- package/harness-skills/mstar-host/references/codex.md +61 -0
- package/harness-skills/mstar-host/references/cursor-plan-mode-bridge.md +159 -0
- package/harness-skills/mstar-host/references/cursor.md +183 -0
- package/harness-skills/mstar-host/references/dsh.md +502 -0
- package/harness-skills/mstar-host/references/kimi-plan-mode-bridge.md +36 -0
- package/harness-skills/mstar-host/references/kimi.md +136 -0
- package/harness-skills/mstar-host/references/omp-plan-mode-bridge.md +32 -0
- package/harness-skills/mstar-host/references/omp.md +244 -0
- package/harness-skills/mstar-host/references/opencode.md +76 -0
- package/harness-skills/mstar-host/references/parallel-dispatch.md +68 -0
- package/harness-skills/mstar-host/references/zcode-plan-mode-bridge.md +36 -0
- package/harness-skills/mstar-host/references/zcode.md +129 -0
- package/harness-skills/mstar-iteration/SKILL.md +393 -0
- package/harness-skills/mstar-iteration/references/autonomous-direction-lock.md +90 -0
- package/harness-skills/mstar-iteration/references/iteration-artifact-boundaries.md +103 -0
- package/harness-skills/mstar-iteration/references/iteration-compass-template.md +142 -0
- package/harness-skills/mstar-iteration/references/iteration-corpus-hygiene.md +45 -0
- package/harness-skills/mstar-iteration/references/iteration-workspace-readme-template.md +27 -0
- package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +193 -0
- package/harness-skills/mstar-iteration/references/phase-3-iteration-close.md +95 -0
- package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +84 -0
- package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +24 -0
- package/harness-skills/mstar-phase-gates/SKILL.md +112 -0
- package/harness-skills/mstar-plan-artifacts/SKILL.md +46 -0
- package/harness-skills/mstar-plan-artifacts/references/done-compaction.md +88 -0
- package/harness-skills/mstar-plan-artifacts/references/knowledge-and-designs.md +100 -0
- package/harness-skills/mstar-plan-artifacts/references/plan-files-and-reports.md +99 -0
- package/harness-skills/mstar-plan-artifacts/references/plan-quality-bar.md +99 -0
- package/harness-skills/mstar-plan-artifacts/references/status-and-residuals.md +570 -0
- package/harness-skills/mstar-plan-artifacts/templates/README.md +9 -0
- package/harness-skills/mstar-plan-artifacts/templates/notes.empty.json +5 -0
- package/harness-skills/mstar-plan-artifacts/templates/plan.main.md +54 -0
- package/harness-skills/mstar-plan-artifacts/templates/plans-done.empty.json +3 -0
- package/harness-skills/mstar-plan-artifacts/templates/status.empty.json +7 -0
- package/harness-skills/mstar-plan-conventions/SKILL.md +165 -0
- package/harness-skills/mstar-plan-conventions/references/artifact-storage-paths.md +50 -0
- package/harness-skills/mstar-plan-conventions/references/effort-estimation.md +38 -0
- package/harness-skills/mstar-plan-conventions/references/harness-bootstrap-and-agents-layering.md +93 -0
- package/harness-skills/mstar-review-qc/SKILL.md +60 -0
- package/harness-skills/mstar-review-qc/references/review-responsibility-boundaries.md +54 -0
- package/harness-skills/mstar-roles/SKILL.md +86 -0
- package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +46 -0
- package/harness-skills/mstar-roles/references/architect.md +114 -0
- package/harness-skills/mstar-roles/references/code-reviewer.md +109 -0
- package/harness-skills/mstar-roles/references/frontend-dev.md +70 -0
- package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +89 -0
- package/harness-skills/mstar-roles/references/ops-engineer.md +78 -0
- package/harness-skills/mstar-roles/references/product-manager.md +107 -0
- package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +198 -0
- package/harness-skills/mstar-roles/references/project-manager/plan-management.md +61 -0
- package/harness-skills/mstar-roles/references/project-manager/qa-trigger-matrix.md +56 -0
- package/harness-skills/mstar-roles/references/project-manager/qc-and-residuals.md +98 -0
- package/harness-skills/mstar-roles/references/project-manager/routing-and-dev-allocation.md +99 -0
- package/harness-skills/mstar-roles/references/project-manager.md +310 -0
- package/harness-skills/mstar-roles/references/prompt-engineer.md +71 -0
- package/harness-skills/mstar-roles/references/qa-engineer/acceptance-gate.md +62 -0
- package/harness-skills/mstar-roles/references/qa-engineer.md +79 -0
- package/harness-skills/mstar-roles/references/qc-specialist/deep-review-lenses.md +95 -0
- package/harness-skills/mstar-roles/references/qc-specialist/report-template.md +72 -0
- package/harness-skills/mstar-roles/references/qc-specialist/reviewer-checklist.md +44 -0
- package/harness-skills/mstar-roles/references/qc-specialist/reviewer-workflow.md +57 -0
- package/harness-skills/mstar-roles/references/qc-specialist-shared.md +128 -0
- package/harness-skills/mstar-roles/references/writing-specialist.md +59 -0
- package/harness-skills/mstar-sdd/SKILL.md +133 -0
- package/harness-skills/mstar-sdd/references/file-handoffs.md +83 -0
- package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +44 -0
- package/harness-skills/mstar-sdd/references/implementer-prompt.md +56 -0
- package/harness-skills/mstar-sdd/references/sticky-implementer-session.md +103 -0
- package/harness-skills/mstar-sdd/references/task-reviewer-prompt.md +53 -0
- package/harness-skills/mstar-skill-authoring/SKILL.md +162 -0
- package/harness-skills/mstar-skill-authoring/references/skillsbench-authoring.md +117 -0
- package/harness-skills/mstar-strategy/SKILL.md +130 -0
- package/harness-skills/pm/SKILL.md +40 -0
- package/package.json +92 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type UserMessage } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import type { PreStepDecision } from '@deepseek-ai/dsh-agent';
|
|
4
|
+
import type { MstarEngineStatusSource } from '../types.ts';
|
|
5
|
+
import { HarnessResolver } from './_shared.ts';
|
|
6
|
+
/** Default catalog cache refresh interval (ms) — see Config `catalogTtlMs`. */
|
|
7
|
+
export declare const DEFAULT_CATALOG_TTL_MS = 60000;
|
|
8
|
+
/** Catalog cache key for the explicit-`harnessDir` app-wide entry (one entry for every session). */
|
|
9
|
+
export declare const EXPLICIT_CACHE_KEY = "\0explicit";
|
|
10
|
+
/** One TTL cache entry: the unified source plus the build timestamp. */
|
|
11
|
+
export interface CatalogCacheEntry {
|
|
12
|
+
sources: MstarEngineStatusSource;
|
|
13
|
+
builtAt: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The apply-scoped `harnessDir → cache key` reverse map + invalidation
|
|
17
|
+
* closure (plan `20260811-panel-f4-timeliness` Task 2, decision D3): the
|
|
18
|
+
* catalog cache is keyed by {@link EXPLICIT_CACHE_KEY} or the session cwd,
|
|
19
|
+
* while ledger records (dispatch/settle) identify the affected workspace by
|
|
20
|
+
* `{HARNESS_DIR}` — the reverse map bridges the two so a ledger change
|
|
21
|
+
* deletes EXACTLY the affected workspace's entry (no global clear; a
|
|
22
|
+
* multi-workspace deployment does not rebuild every workspace). BOTH the map
|
|
23
|
+
* and the closure are created per-apply by the entry (same lifetime as the
|
|
24
|
+
* cache): module-level state would survive an HMR fiber restart and point at
|
|
25
|
+
* a destroyed cache.
|
|
26
|
+
*/
|
|
27
|
+
export interface CatalogInvalidation {
|
|
28
|
+
/**
|
|
29
|
+
* Register `key` as the cache key of `harnessDir` — called by
|
|
30
|
+
* `catalogSourcesFor` on cache hit AND build, and pre-registered by the
|
|
31
|
+
* entry at apply for the explicit-config boot entry (a ledger record
|
|
32
|
+
* between apply and the first pre-step must still invalidate the
|
|
33
|
+
* pre-seeded entry). A null harness dir (no `{HARNESS_DIR}` resolved) has
|
|
34
|
+
* no cache entry to invalidate → no-op.
|
|
35
|
+
*/
|
|
36
|
+
register(harnessDir: string | null, key: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Delete the cache entry of `harnessDir` (D3 — the ledger record path
|
|
39
|
+
* invokes this through the apply-bound hook). A missing mapping is a safe
|
|
40
|
+
* no-op, and a missing entry after a previous invalidation is a no-op too
|
|
41
|
+
* (the next pre-step rebuilds regardless). A throwing invalidation is
|
|
42
|
+
* contained by the record path (log-only — it never blocks the ledger
|
|
43
|
+
* record).
|
|
44
|
+
*/
|
|
45
|
+
invalidate(harnessDir: string): void;
|
|
46
|
+
}
|
|
47
|
+
/** Create the apply-scoped invalidation bound to ONE catalog cache (entry-internal wiring — see {@link CatalogInvalidation}). */
|
|
48
|
+
export declare function createCatalogInvalidation(cache: Map<string, CatalogCacheEntry>): CatalogInvalidation;
|
|
49
|
+
/**
|
|
50
|
+
* Build the unified catalog source for one harness dir (boot for the
|
|
51
|
+
* explicit config, first-use per workspace otherwise, then TTL-refreshed —
|
|
52
|
+
* see `catalogSourcesFor`). Logs the manifest fallback once per build — a
|
|
53
|
+
* '0.0.0' version would watermark every catalog row wrongly, so the
|
|
54
|
+
* fallback is never silent.
|
|
55
|
+
* @param ctx - registrant context (logger for the manifest fallback).
|
|
56
|
+
* @param harnessDir - the resolved `{HARNESS_DIR}` (null when none found).
|
|
57
|
+
*/
|
|
58
|
+
export declare function buildCatalogSources(ctx: Context, harnessDir: string | null): MstarEngineStatusSource;
|
|
59
|
+
/**
|
|
60
|
+
* Advisory `agent/pre-step` waterfall listener (agent
|
|
61
|
+
* catalog): delegates through `next()` (never `reject` — that would block the
|
|
62
|
+
* step — and never replaces the delegated messages) and appends the ONE
|
|
63
|
+
* unified `mstar-engine-status` catalog message to the composed step
|
|
64
|
+
* messages, so the durable session log carries it (model-visible ⟺ logged,
|
|
65
|
+
* MessageSource form): the `<mstar_engine_status>` block renders the
|
|
66
|
+
* watermark fields (version, harness dir, enforcement), plus the iteration
|
|
67
|
+
* phase-gate section when a steering compass + status.json resolve, plus
|
|
68
|
+
* the workspace-state digest section when the workspace has a status.json.
|
|
69
|
+
*
|
|
70
|
+
* Digest-gated re-emission (the documented P3 dedup, landed early): per
|
|
71
|
+
* agent+workspace, the row is injected ONCE per turn — later steps of the
|
|
72
|
+
* same turn append it again only when its rendered text CHANGED (a TTL
|
|
73
|
+
* refresh picked up new state). The durable session log therefore carries
|
|
74
|
+
* the row on the first step of every turn plus each change, not on every
|
|
75
|
+
* step; a 20-step turn shows the catalog once, not 20 times.
|
|
76
|
+
*
|
|
77
|
+
* An aborted step publishes nothing: the delegated decision
|
|
78
|
+
* is returned unchanged (tool-skill precedent; a narrowed abort race —
|
|
79
|
+
* an abort after delegation must not surface as a turn failure).
|
|
80
|
+
*
|
|
81
|
+
* Error containment: the append path is wrapped — a failure
|
|
82
|
+
* (e.g. a downstream decider returning a non-iterable `messages` set, or a
|
|
83
|
+
* throwing message factory) logs and returns the delegated decision
|
|
84
|
+
* unchanged; the advisory listener never aborts the very step it observes.
|
|
85
|
+
*
|
|
86
|
+
* simplify: dev-time stub — the digest is in-memory per app (the real
|
|
87
|
+
* dsh-session log is unavailable at dev time; digest state resets on
|
|
88
|
+
* fiber disposal, which is also HMR-correct).
|
|
89
|
+
* @param ctx - registrant context (logger for the containment path).
|
|
90
|
+
* @param resolver - the per-workspace `{HARNESS_DIR}` resolver (the probe
|
|
91
|
+
* never starts from the process cwd).
|
|
92
|
+
* @param explicitKey - the app-wide cache key when an explicit
|
|
93
|
+
* `harnessDir` config is set (undefined → per-session-cwd keys).
|
|
94
|
+
* @param cache - per-workspace TTL catalog sources cache (boot pre-seeded
|
|
95
|
+
* for the explicit-config case; otherwise built on first use of each
|
|
96
|
+
* workspace root and TTL-refreshed — Config `catalogTtlMs`).
|
|
97
|
+
* @param ttlMs - catalog refresh interval in milliseconds.
|
|
98
|
+
* @param register - the apply-scoped `harnessDir → cache key` reverse-map
|
|
99
|
+
* registration (plan `20260811-panel-f4-timeliness` Task 2 — keeps every
|
|
100
|
+
* workspace's entry invalidatable by a ledger change; see
|
|
101
|
+
* `createCatalogInvalidation`).
|
|
102
|
+
* @param digests - per agent+workspace turn digests (last rendered text)
|
|
103
|
+
* for the digest-gated re-emission.
|
|
104
|
+
* @param payload - the proposed step the loop is about to enter.
|
|
105
|
+
* @param next - the remaining pre-step chain; its value is the delegated decision.
|
|
106
|
+
*/
|
|
107
|
+
export declare function preStepCatalogListener(ctx: Context, resolver: HarnessResolver, explicitKey: string | undefined, cache: Map<string, CatalogCacheEntry>, ttlMs: number, register: (harnessDir: string | null, key: string) => void, digests: Map<string, TurnDigest>, payload: {
|
|
108
|
+
agent: unknown;
|
|
109
|
+
messages: UserMessage[];
|
|
110
|
+
turn: number;
|
|
111
|
+
step: number;
|
|
112
|
+
signal: AbortSignal;
|
|
113
|
+
}, next: () => Promise<PreStepDecision>): Promise<PreStepDecision>;
|
|
114
|
+
/** Per agent+workspace turn digest: the rendered catalog text as of the last injection. */
|
|
115
|
+
export interface TurnDigest {
|
|
116
|
+
turn: number;
|
|
117
|
+
text: string;
|
|
118
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { AssignmentFields, GateResult, ValidationResult } from '@mstar-harness/engine';
|
|
3
|
+
import type { PreToolDecision, ToolExecution } from '@deepseek-ai/dsh-tools';
|
|
4
|
+
import { HarnessResolver } from './_shared.ts';
|
|
5
|
+
import type { Config } from './_shared.ts';
|
|
6
|
+
import type { DshHostAdapter } from './adapter.ts';
|
|
7
|
+
/** Logger label for the dispatch gate (dsh logger naming: `<scope>/<subject>`). */
|
|
8
|
+
export declare const DISPATCH_LOGGER = "mstar/dispatch-gate";
|
|
9
|
+
/**
|
|
10
|
+
* Default delegation tool names the dispatch gate matches (tool-subagent
|
|
11
|
+
* default id). Exported SHARED with the agent-flow settle pairing
|
|
12
|
+
* (`registerSettleListener` matches the same tool set — plan
|
|
13
|
+
* `20260811-panel-f4-timeliness` Task 1) so the default cannot drift between
|
|
14
|
+
* the gate and the settle seam.
|
|
15
|
+
*/
|
|
16
|
+
export declare const DEFAULT_DISPATCH_TOOLS: readonly ["subagent"];
|
|
17
|
+
/**
|
|
18
|
+
* Advisory emitted on warn-mode dispatch-gate passes (the * `mstar/status-gate` decision reused for the dispatch gate — dsh's
|
|
19
|
+
* `agent/status` lifecycle event stays untouched). Consumers (later tasks,
|
|
20
|
+
* catalogs) observe this event for model-visible/session-log surfacing.
|
|
21
|
+
*/
|
|
22
|
+
export interface DispatchGateAdvisory {
|
|
23
|
+
/** The matched delegation tool name. */
|
|
24
|
+
tool: string;
|
|
25
|
+
/** The Assignment's declared `Execute as` ('' when missing). */
|
|
26
|
+
role: string;
|
|
27
|
+
/** The gate verdict (warn-mode: `hardBlocked` is false). */
|
|
28
|
+
result: GateResult;
|
|
29
|
+
/** Whether hard enforcement is on (advisory events are warn-mode by construction). */
|
|
30
|
+
hard: boolean;
|
|
31
|
+
/** True when the gate errored internally and degraded to allow (structured degraded advisory). */
|
|
32
|
+
degraded?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* True when the text looks like an Assignment (opencode parity: `## Assignment`
|
|
36
|
+
* heading or at least one core field line). Non-Assignment delegation prompts
|
|
37
|
+
* stay silent — no false-positive warnings. Callers MUST pass the engine
|
|
38
|
+
* `assignmentHeaderRegion` slice: a `## Assignment` heading or
|
|
39
|
+
* field line quoted in the task body must not shape a non-assignment prompt.
|
|
40
|
+
* Exported for the agent-flow ledger's shape guard (qc2 F-2 — the shared
|
|
41
|
+
* `DshHostAdapter.dispatchGate` core applies the SAME guard on both dispatch
|
|
42
|
+
* surfaces, so the exec-less host-hook path records nothing for
|
|
43
|
+
* non-Assignment text either).
|
|
44
|
+
*/
|
|
45
|
+
export declare function isAssignmentShaped(assignmentText: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the hard-enforcement flag for one dispatch: explicit Config override
|
|
48
|
+
* wins, else the Assignment's OWN `Enforcement: hard` header flag (opencode
|
|
49
|
+
* parity — header region only, a body-quoted example never hardens), else the
|
|
50
|
+
* iteration compass frontmatter, else warn-only.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveDispatchHard(harnessDir: string | null, config: Config, assignmentText: string): boolean;
|
|
53
|
+
/** A header value that means "no value" (placeholder conventions). Type guard so callers narrow to `string`. Shared with the agent-flow ledger (qc1 F-003 — one grammar, no copy-paste drift). */
|
|
54
|
+
export declare function isNaValue(value: string | undefined): value is undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the target plan id from the Assignment HEADER region: `Plan Path`
|
|
57
|
+
* basename (`.md` stripped), else `SDD dir` basename, else a `plan_id` field.
|
|
58
|
+
* Exported for the agent-flow ledger's dispatch derivation (the ledger
|
|
59
|
+
* records the same plan identity the gate resolved — one grammar).
|
|
60
|
+
* @param headerRegion - `assignmentHeaderRegion(assignmentText)` (
|
|
61
|
+
* only the header is read — a plan path quoted in the task body never
|
|
62
|
+
* resolves a plan id).
|
|
63
|
+
*/
|
|
64
|
+
export declare function planIdOf(headerRegion: string): string | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* The dispatching session's stable id, when the seam exposes it (dsh
|
|
67
|
+
* Agent.id). Exported for the agent-flow ledger's dispatch derivation (the
|
|
68
|
+
* ledger records the same agent identity the lease gate compares — one
|
|
69
|
+
* grammar).
|
|
70
|
+
*/
|
|
71
|
+
export declare function sessionIdOf(exec: ToolExecution): string | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Lease gate — ADDITIVE beyond the opencode parity field set:
|
|
74
|
+
* opencode's `validateDispatchAssignment` does NOT run lease checks at
|
|
75
|
+
* dispatch, so every violation emitted here is dsh-only and clearly scoped:
|
|
76
|
+
* the check fires ONLY for WRITABLE dispatches whose Assignment declares
|
|
77
|
+
* `Execution mode: sdd` (engine `executionModeToN` semantics — sdd maps to
|
|
78
|
+
* N=3; the function's violation path is intentionally unused so
|
|
79
|
+
* `dispatch.execution-mode.*` codes stay out of the parity field set) OR
|
|
80
|
+
* whose plan row is `InProgress`.
|
|
81
|
+
*
|
|
82
|
+
* Contract (status-and-residuals.md § Pre-dispatch re-verify): before any
|
|
83
|
+
* writable implement dispatch, reread `{HARNESS_DIR}/status.json` and confirm
|
|
84
|
+
* the session still passes verify-held-lease — `holder`, `worktree_path` and
|
|
85
|
+
* `working_branch` must match the Assignment; mismatch or absent lease →
|
|
86
|
+
* STOP. Engine `verifyPlanExecutionLease` + `validateExecutionLease` carry
|
|
87
|
+
* the presence/shape checks (missing / orphan / dual-write / non-ssot /
|
|
88
|
+
* invalid fields); the dispatch-context comparisons (holder vs the
|
|
89
|
+
* dispatching session, worktree and branch vs the Assignment) are dsh-side.
|
|
90
|
+
*
|
|
91
|
+
* Degrade-allow cases (no false positives): no harness dir, unresolvable plan
|
|
92
|
+
* id, and non-SDD assignments whose plan row is absent or not InProgress.
|
|
93
|
+
* Unverifiable lease states (malformed status.json, MISSING status.json, plan
|
|
94
|
+
* row not registered) are violations ONLY for sdd dispatches (the lease state
|
|
95
|
+
* cannot be confirmed — the status gate already guards the next write);
|
|
96
|
+
* unreadable docs never harden a soft workflow. Missing status.json is NOT a
|
|
97
|
+
* silent fail-open for sdd: the claim-before-InProgress red line
|
|
98
|
+
* needs the plan's execution_lease, and a missing status file cannot confirm
|
|
99
|
+
* it — `lease.dispatch.unverifiable` fires (advisory in warn, deny under hard).
|
|
100
|
+
*/
|
|
101
|
+
export declare function leaseGateViolations(harnessDir: string | null, exec: ToolExecution, writable: boolean | undefined, prompt: string): ValidationResult[];
|
|
102
|
+
/**
|
|
103
|
+
* The dispatch-gate validation core — the engine's SINGLE dispatch-gate
|
|
104
|
+
* composition (`dispatch.composeDispatchGate`, opencode/omp/CLI parity — the
|
|
105
|
+
* SAME composition, so violation codes are identical by construction): shape
|
|
106
|
+
* guard + field gate (read-only roles skip the branch gate) +
|
|
107
|
+
* anti-recursion precheck (Config binding) + default-branch gate +
|
|
108
|
+
* header-region enforcement. The dsh-side additions layer ON TOP: the
|
|
109
|
+
* worktree L1/L2 checks (additive beyond opencode parity; the
|
|
110
|
+
* lease gate is exec-bound and joins via {@link DshHostAdapter.dispatchGate}).
|
|
111
|
+
* Extracted from `gateDispatch` so the `tools/pre-execute` listener and the
|
|
112
|
+
* host adapter's `beforeDispatch` share ONE code path.
|
|
113
|
+
*
|
|
114
|
+
* Header-region scoping: the engine `assignmentHeaderRegion`
|
|
115
|
+
* slice is computed ONCE and feeds the composition AND the worktree parsers
|
|
116
|
+
* (fields, branch forms, direct-on exception, worktree tracks) — body-quoted
|
|
117
|
+
* field examples after a `# Task` / `# Target` / `---` marker never leak
|
|
118
|
+
* into the header fields the gate validates (the same discipline
|
|
119
|
+
* enforcement / plan-id / lease already honor). Well-formed assignments
|
|
120
|
+
* (fields in the header) slice to the full text, so their verdicts are
|
|
121
|
+
* unchanged. The composition never throws: unexpected failures degrade to
|
|
122
|
+
* the silent non-shaped result.
|
|
123
|
+
*
|
|
124
|
+
* @returns the violations plus the writable flag (false for read-only
|
|
125
|
+
* roles — the listener feeds it to the lease gate).
|
|
126
|
+
*/
|
|
127
|
+
export declare function dispatchGateCore(config: Config, harnessDir: string | null, prompt: string): {
|
|
128
|
+
violations: ValidationResult[];
|
|
129
|
+
writable: boolean | undefined;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* `tools/pre-execute` listener. The waterfall refusal channel is the returned
|
|
133
|
+
* decision: a deny is returned WITHOUT calling `next()` (short-circuits the
|
|
134
|
+
* chain — downstream listeners and the registry default never run); every
|
|
135
|
+
* other path calls `next()` to delegate (the registry's default is
|
|
136
|
+
* `{ kind: 'allow' }`). Engine failures degrade to allow in BOTH modes (hard
|
|
137
|
+
* gates are opt-in — an engine failure must not harden a workflow that was
|
|
138
|
+
* soft; opencode parity) but the degrade is NEVER silent: the
|
|
139
|
+
* catch path emits the plugin-owned `mstar/dispatch-gate` advisory with
|
|
140
|
+
* `degraded: true` + an error log, so a hard deployment can detect a dead
|
|
141
|
+
* control instead of only finding it in logs. `next()` itself is invoked
|
|
142
|
+
* outside the guard so a downstream rejection propagates untouched.
|
|
143
|
+
*/
|
|
144
|
+
export declare function preExecuteListener(ctx: Context, resolver: HarnessResolver, config: Config, adapter: DshHostAdapter, exec: ToolExecution, next: () => Promise<PreToolDecision>): Promise<PreToolDecision>;
|
|
145
|
+
/**
|
|
146
|
+
* Rebuild the canonical Assignment HEADER text from parsed fields (the
|
|
147
|
+
* engine's OWN header grammar — `parseAssignmentFields` reads exactly these
|
|
148
|
+
* labels — so the engine parsers round-trip losslessly). The host hook's
|
|
149
|
+
* engine-typed input is `AssignmentFields`; the shared gate core validates
|
|
150
|
+
* assignment TEXT, so the fields form is normalized to text before gating.
|
|
151
|
+
*/
|
|
152
|
+
export declare function assignmentTextFromFields(fields: AssignmentFields): string;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { GateResult, SecretFinding, ValidationResult } from '@mstar-harness/engine';
|
|
3
|
+
import type { FsTarget, FsWriteIntent } from '@deepseek-ai/dsh-fs';
|
|
4
|
+
import { HarnessResolver } from './_shared.ts';
|
|
5
|
+
import type { Config } from './_shared.ts';
|
|
6
|
+
/** The four artifact seams (design-md / audit / compound / roles). */
|
|
7
|
+
export type SeamId = 'design-md' | 'audit' | 'compound' | 'roles';
|
|
8
|
+
/**
|
|
9
|
+
* Advisory emitted on seam-gate decisions (the `mstar/status-gate` /
|
|
10
|
+
* `mstar/skill-lint` advisory pattern reused for the design-md / audit /
|
|
11
|
+
* compound / roles artifact gates — one event with a `seam` discriminator,
|
|
12
|
+
* consumers filter on it). Emitted when an in-scope artifact write-intent
|
|
13
|
+
* finds violations in the pre-write on-disk document (warn mode), when hard
|
|
14
|
+
* mode allows an ALREADY-invalid document as a repair escape, and when the
|
|
15
|
+
* gate degrades to allow after an unexpected internal error. Clean passes
|
|
16
|
+
* stay silent.
|
|
17
|
+
*
|
|
18
|
+
* The gate NEVER throws on the listener path (status-gate repair-escape
|
|
19
|
+
* semantics): the intent waterfall carries no incoming content, so the only
|
|
20
|
+
* lint signal is the pre-write on-disk state; the typed hard veto lives on
|
|
21
|
+
* the known-document branch (`lintSeamWrite` + friends, `SeamVetoError`).
|
|
22
|
+
*/
|
|
23
|
+
export interface SeamLintAdvisory {
|
|
24
|
+
/** The artifact seam that decided this intent. */
|
|
25
|
+
seam: SeamId;
|
|
26
|
+
/** Which intent slot passed the gate (write-intent only — no linted edit slot). */
|
|
27
|
+
operation: 'write';
|
|
28
|
+
/** `displayPath` of the guarded file. */
|
|
29
|
+
target: string;
|
|
30
|
+
/** The gate verdict (warn-mode: `hardBlocked` false; hard repair escape: `hardBlocked` true). */
|
|
31
|
+
result: GateResult;
|
|
32
|
+
/** Resolved enforcement flag: false for warn-mode advisories, true for hard-mode repair escapes. */
|
|
33
|
+
hard: boolean;
|
|
34
|
+
/** True when hard mode allowed a write to an ALREADY-invalid document (repair escape). */
|
|
35
|
+
repair?: boolean;
|
|
36
|
+
/** True when the gate errored internally and degraded to allow (error-containment envelope). */
|
|
37
|
+
degraded?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate a DESIGN.md / DESIGN.dark.md document: token frontmatter plus
|
|
41
|
+
* light/dark parity against the on-disk sibling when it exists (parity is
|
|
42
|
+
* inherently cross-file — the sibling is read at validation time; a dark
|
|
43
|
+
* write with no light sibling skips parity). Shared by the content-blind
|
|
44
|
+
* listener and the known-document branch.
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateDesignDoc(doc: string, path: string): GateResult;
|
|
47
|
+
/**
|
|
48
|
+
* Validate an audit plan document: Status-block contract + secret scan.
|
|
49
|
+
* The findings summary (line + type only — mstar-audit Hard Rule 4 never
|
|
50
|
+
* reproduces secret values) rides along for the validate tool's `secrets`
|
|
51
|
+
* output field; the gate path reads only `ok`/`violations`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function validateAuditDoc(doc: string, path: string): GateResult & {
|
|
54
|
+
findings: SecretFinding[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Validate a knowledge doc: schema.yaml frontmatter contract + referenced
|
|
58
|
+
* path/module existence. The repo root for `referenceExists` is derived as
|
|
59
|
+
* the parent of `{HARNESS_DIR}` — the plan-conventions discovery layout
|
|
60
|
+
* always places the harness dir directly under the repo root
|
|
61
|
+
* (`<repo>/.mstar`, `<repo>/.agents`, `<repo>/plans`).
|
|
62
|
+
* simplify: single-level harness layout — revisit if a nested harness root
|
|
63
|
+
* becomes an observed deployment.
|
|
64
|
+
*/
|
|
65
|
+
export declare function validateCompoundDoc(doc: string, _path: string, harnessDir: string | null): GateResult;
|
|
66
|
+
/**
|
|
67
|
+
* Validate the mstar-roles skill-dir state: role mapping / parameter tables
|
|
68
|
+
* against the on-disk references layout, plus load-order declarations
|
|
69
|
+
* across every sibling `mstar-*` skill (unreadable sibling SKILL.md files
|
|
70
|
+
* are skipped — best-effort reads for a lint that must never take the gate
|
|
71
|
+
* down). The `skillsRoot` override exists for the validate tool (its
|
|
72
|
+
* explicit `skills_root` parameter); the gate path keeps the default
|
|
73
|
+
* (the parent of the roles dir).
|
|
74
|
+
* @param rolesDir - the mstar-roles skill directory.
|
|
75
|
+
* @param skillsRoot - directory scanned for sibling `mstar-*` skills
|
|
76
|
+
* (default: `dirname(rolesDir)`).
|
|
77
|
+
*/
|
|
78
|
+
export declare function validateRolesState(rolesDir: string, skillsRoot?: string): GateResult;
|
|
79
|
+
/**
|
|
80
|
+
* `fs/write-intent` listener for one seam gate. Registered with `prepend`
|
|
81
|
+
* for the same reachability reason as the status gate: the slot is
|
|
82
|
+
* first-wins by registration order (dsh-fs-policy README), so without
|
|
83
|
+
* prepend a policy plugin mounted earlier would make this gate unreachable.
|
|
84
|
+
* Every gate decision (warn advisory, repair escape, degraded allow) calls
|
|
85
|
+
* `next()` — the seam gates never own the intent decision and must not
|
|
86
|
+
* terminate the chain (fs-policy's observed-state CAS stays live in
|
|
87
|
+
* composed deployments).
|
|
88
|
+
*/
|
|
89
|
+
export declare function seamWriteIntentListener(ctx: Context, resolver: HarnessResolver, config: Config, seam: SeamId, target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise<FsWriteIntent | undefined>): Promise<FsWriteIntent | undefined>;
|
|
90
|
+
/**
|
|
91
|
+
* Typed hard-mode veto for the seam gates (the dsh fs-policy veto channel:
|
|
92
|
+
* "veto = throw"; the write tool turns the throw into an isError tool
|
|
93
|
+
* result carrying `{ name, code }`). Thrown ONLY by {@link lintSeamWrite} —
|
|
94
|
+
* the entry that lints a KNOWN incoming document (the brief's "hard veto
|
|
95
|
+
* via throw where the slot semantics allow" branch). The content-blind
|
|
96
|
+
* `fs/write-intent` listeners never throw: they cannot distinguish a repair
|
|
97
|
+
* from a re-violation, so hard mode degrades to the repair escape there
|
|
98
|
+
* (see {@link gateSeamIntent}).
|
|
99
|
+
*/
|
|
100
|
+
export declare class SeamVetoError extends Error {
|
|
101
|
+
/** Stable code for tool-result serialization (the `{ name, code }` convention). */
|
|
102
|
+
readonly code: "seam.veto";
|
|
103
|
+
/** The seam whose gate vetoed the write. */
|
|
104
|
+
readonly seam: SeamId;
|
|
105
|
+
/** The violations that caused the veto. */
|
|
106
|
+
readonly violations: readonly ValidationResult[];
|
|
107
|
+
constructor(seam: SeamId, target: string, violations: readonly ValidationResult[]);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Enforce one seam's lints over a KNOWN document (the brief's "incoming
|
|
111
|
+
* doc when available" branch): `Enforcement: hard` + violations → throw the
|
|
112
|
+
* typed {@link SeamVetoError} (fs-policy veto channel); warn mode → return
|
|
113
|
+
* the gate for advisory logging. A repairing write carries a VALID incoming
|
|
114
|
+
* document and passes by construction — no repair escape is needed on this
|
|
115
|
+
* branch. The content-blind listener paths (where the incoming doc is never
|
|
116
|
+
* visible) route through {@link gateSeamIntent} instead, which applies the
|
|
117
|
+
* repair-escape decision.
|
|
118
|
+
* @param seam - the artifact seam whose validator runs.
|
|
119
|
+
* @param doc - the document about to be written (roles: ignored — the
|
|
120
|
+
* validator checks the whole mstar-roles dir state).
|
|
121
|
+
* @param options - target display path (veto message) + resolved hard flag
|
|
122
|
+
* + the plugin harness dir (compound reference checks; null-tolerant).
|
|
123
|
+
*/
|
|
124
|
+
export declare function lintSeamWrite(seam: SeamId, doc: string, options: {
|
|
125
|
+
target: string;
|
|
126
|
+
hard: boolean;
|
|
127
|
+
harnessDir?: string | null;
|
|
128
|
+
}): GateResult;
|
|
129
|
+
/** {@link lintSeamWrite} bound to the design-md seam. */
|
|
130
|
+
export declare function lintDesignMdWrite(doc: string, options: {
|
|
131
|
+
target: string;
|
|
132
|
+
hard: boolean;
|
|
133
|
+
harnessDir?: string | null;
|
|
134
|
+
}): GateResult;
|
|
135
|
+
/** {@link lintSeamWrite} bound to the audit seam. */
|
|
136
|
+
export declare function lintAuditWrite(doc: string, options: {
|
|
137
|
+
target: string;
|
|
138
|
+
hard: boolean;
|
|
139
|
+
harnessDir?: string | null;
|
|
140
|
+
}): GateResult;
|
|
141
|
+
/** {@link lintSeamWrite} bound to the compound seam. */
|
|
142
|
+
export declare function lintCompoundWrite(doc: string, options: {
|
|
143
|
+
target: string;
|
|
144
|
+
hard: boolean;
|
|
145
|
+
harnessDir?: string | null;
|
|
146
|
+
}): GateResult;
|
|
147
|
+
/** {@link lintSeamWrite} bound to the roles seam. */
|
|
148
|
+
export declare function lintRolesWrite(doc: string, options: {
|
|
149
|
+
target: string;
|
|
150
|
+
hard: boolean;
|
|
151
|
+
harnessDir?: string | null;
|
|
152
|
+
}): GateResult;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { GateResult, ValidationResult } from '@mstar-harness/engine';
|
|
3
|
+
import type { FsTarget, FsWriteIntent } from '@deepseek-ai/dsh-fs';
|
|
4
|
+
import { HarnessResolver } from './_shared.ts';
|
|
5
|
+
import type { Config } from './_shared.ts';
|
|
6
|
+
/**
|
|
7
|
+
* Advisory emitted on skill-lint gate decisions (the `mstar/status-gate`
|
|
8
|
+
* advisory pattern reused for the skill-authoring gate). Emitted
|
|
9
|
+
* when a `SKILL.md` write-intent under a configured skill root finds lint
|
|
10
|
+
* violations in the pre-write on-disk document (warn mode), when hard mode
|
|
11
|
+
* allows an ALREADY-invalid document as a repair escape, and when the gate
|
|
12
|
+
* degrades to allow after an unexpected internal error. Clean passes stay
|
|
13
|
+
* silent.
|
|
14
|
+
*
|
|
15
|
+
* The gate NEVER throws on the listener path (status-gate repair-escape
|
|
16
|
+
* semantics): the intent waterfall carries no incoming content, so the only
|
|
17
|
+
* lint signal is the pre-write on-disk state; the typed hard veto lives on
|
|
18
|
+
* the incoming-document branch (`lintSkillWrite`, `SkillLintVetoError`).
|
|
19
|
+
*/
|
|
20
|
+
export interface SkillLintAdvisory {
|
|
21
|
+
/** Which intent slot passed the gate (write-intent only — skills have no linted edit slot). */
|
|
22
|
+
operation: 'write';
|
|
23
|
+
/** `displayPath` of the guarded SKILL.md. */
|
|
24
|
+
target: string;
|
|
25
|
+
/** Canonical skill-root form of the target (`resolveSkillRoot('dsh', …)` form). */
|
|
26
|
+
canonical: string;
|
|
27
|
+
/** The lint verdict (warn-mode: `hardBlocked` false; hard repair escape: `hardBlocked` true). */
|
|
28
|
+
result: GateResult;
|
|
29
|
+
/** Resolved enforcement flag: false for warn-mode advisories, true for hard-mode repair escapes. */
|
|
30
|
+
hard: boolean;
|
|
31
|
+
/** True when hard mode allowed a write to an ALREADY-invalid document (repair escape). */
|
|
32
|
+
repair?: boolean;
|
|
33
|
+
/** True when the gate errored internally and degraded to allow (error-containment envelope). */
|
|
34
|
+
degraded?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Typed hard-mode veto for the skill lint gate (the dsh fs-policy veto
|
|
38
|
+
* channel: "veto = throw"; the write tool turns the throw into an isError
|
|
39
|
+
* tool result carrying `{ name, code }`). Thrown ONLY by
|
|
40
|
+
* {@link lintSkillWrite} — the entry that lints a KNOWN incoming document
|
|
41
|
+
* (the brief's "against the incoming doc when available" branch). The
|
|
42
|
+
* content-blind `fs/write-intent` listener never throws: it cannot
|
|
43
|
+
* distinguish a repair from a re-violation, so hard mode degrades to the
|
|
44
|
+
* status-gate repair escape there (see {@link gateSkillIntent}).
|
|
45
|
+
*/
|
|
46
|
+
export declare class SkillLintVetoError extends Error {
|
|
47
|
+
/** Stable code for tool-result serialization (the `{ name, code }` convention). */
|
|
48
|
+
readonly code: "skill-lint.veto";
|
|
49
|
+
/** The lint violations that caused the veto. */
|
|
50
|
+
readonly violations: readonly ValidationResult[];
|
|
51
|
+
constructor(target: string, violations: readonly ValidationResult[]);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Lint one SKILL.md document with the engine skill-authoring lints
|
|
55
|
+
* (`lintFrontmatter` + `lintFiveQuestion` — the CLI `mstar skill lint`
|
|
56
|
+
* combination; violation codes `lint.frontmatter.*` /
|
|
57
|
+
* `skill-authoring.five-question.*`). Pure: no enforcement, no I/O.
|
|
58
|
+
* @param doc - the full SKILL.md text.
|
|
59
|
+
*/
|
|
60
|
+
export declare function lintSkillDoc(doc: string): GateResult;
|
|
61
|
+
/**
|
|
62
|
+
* Enforce the skill-authoring lints over a KNOWN document (the brief's
|
|
63
|
+
* "incoming doc when available" branch): `Enforcement: hard` + violations →
|
|
64
|
+
* throw the typed {@link SkillLintVetoError} (fs-policy veto channel); warn
|
|
65
|
+
* mode → return the gate for advisory logging. A repairing write carries a
|
|
66
|
+
* VALID incoming document and passes by construction — no repair escape is
|
|
67
|
+
* needed on this branch. The content-blind listener path (where the
|
|
68
|
+
* incoming doc is never visible) routes through {@link gateSkillIntent}
|
|
69
|
+
* instead, which applies the status-gate repair-escape decision.
|
|
70
|
+
* @param doc - the document about to be written (the write's content).
|
|
71
|
+
* @param options - target display path (veto message) + resolved hard flag.
|
|
72
|
+
*/
|
|
73
|
+
export declare function lintSkillWrite(doc: string, options: {
|
|
74
|
+
target: string;
|
|
75
|
+
hard: boolean;
|
|
76
|
+
}): GateResult;
|
|
77
|
+
/**
|
|
78
|
+
* `fs/write-intent` listener for the skill lint gate. Registered with
|
|
79
|
+
* `prepend` for the same reachability reason as the status gate: the slot
|
|
80
|
+
* is first-wins by registration order (dsh-fs-policy README), so without
|
|
81
|
+
* prepend a policy plugin mounted earlier would make this gate unreachable.
|
|
82
|
+
* Every gate decision (warn advisory, repair escape, degraded allow) calls
|
|
83
|
+
* `next()` — the skill lint gate never owns the intent decision and must
|
|
84
|
+
* not terminate the chain (fs-policy's observed-state CAS on skill files
|
|
85
|
+
* stays live in composed deployments).
|
|
86
|
+
*/
|
|
87
|
+
export declare function skillWriteIntentListener(ctx: Context, resolver: HarnessResolver, config: Config, target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise<FsWriteIntent | undefined>): Promise<FsWriteIntent | undefined>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { GateResult } from '@mstar-harness/engine';
|
|
3
|
+
import type { FsTarget, FsVersion, FsWriteIntent } from '@deepseek-ai/dsh-fs';
|
|
4
|
+
import { HarnessResolver } from './_shared.ts';
|
|
5
|
+
import type { Config } from './_shared.ts';
|
|
6
|
+
import type { DshHostAdapter } from './adapter.ts';
|
|
7
|
+
/**
|
|
8
|
+
* Advisory emitted on status-gate decisions (the plan's "emit `agent/status`
|
|
9
|
+
* (advisory)" step). Named `mstar/status-gate` instead: the dsh `agent/status`
|
|
10
|
+
* event is a lifecycle-only channel (`{ agent, status }`, idle ⇄ running, with
|
|
11
|
+
* an invariant rejecting no-op transitions) — emitting gate warnings on it
|
|
12
|
+
* would violate the seam contract. Consumers (later tasks, catalogs) observe
|
|
13
|
+
* this event for model-visible/session-log surfacing.
|
|
14
|
+
*
|
|
15
|
+
* The status gate NEVER throws: the fs intent waterfall
|
|
16
|
+
* carries no incoming content, so the only hard-mode decision this seam can
|
|
17
|
+
* make about an ALREADY-invalid document is to allow the write as a repair
|
|
18
|
+
* escape. Every decision surfaces through this advisory; unexpected internal
|
|
19
|
+
* errors degrade to an allow with `degraded: true`.
|
|
20
|
+
*/
|
|
21
|
+
export interface StatusGateAdvisory {
|
|
22
|
+
/** Which intent slot passed the gate. */
|
|
23
|
+
operation: 'write' | 'edit';
|
|
24
|
+
/** `displayPath` of the guarded file. */
|
|
25
|
+
target: string;
|
|
26
|
+
/** The gate verdict (warn-mode: `hardBlocked` false; hard repair escape: `hardBlocked` true). */
|
|
27
|
+
result: GateResult;
|
|
28
|
+
/** Resolved enforcement flag: false for warn-mode advisories, true for hard-mode repair escapes. */
|
|
29
|
+
hard: boolean;
|
|
30
|
+
/** True when hard mode allowed a write/edit to an ALREADY-invalid document (repair escape). */
|
|
31
|
+
repair?: boolean;
|
|
32
|
+
/** True when the gate errored internally and degraded to allow (error-containment envelope). */
|
|
33
|
+
degraded?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Validate a PARSED status document through the status-gate pipeline
|
|
37
|
+
* (engine `validateStatus` + `findingsCleanupGate` per plan row that
|
|
38
|
+
* CONFIGURES a mode). Shared by {@link validateStatusDoc} (the on-disk
|
|
39
|
+
* single-read path) and the host adapter's `beforeStatusWrite` (the
|
|
40
|
+
* incoming document) — the fs-intent gate, the adapter hook and the repair
|
|
41
|
+
* escape all surface the SAME violation codes.
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateStatusValue(doc: unknown): GateResult;
|
|
44
|
+
/**
|
|
45
|
+
* Run the status gate over the CURRENT on-disk document. The fs intent
|
|
46
|
+
* waterfall carries only `(target, actor)` — never the incoming content — so
|
|
47
|
+
* the vetoable check is the pre-write state (the opencode hook's fallback for
|
|
48
|
+
* the same reason). `findingsCleanupGate` runs per plan row that CONFIGURES a
|
|
49
|
+
* mode (`plans[].metadata.findings_cleanup`); schema violations short-circuit
|
|
50
|
+
* it (the doc must parse for the cleanup gate to be meaningful).
|
|
51
|
+
*
|
|
52
|
+
* Single-read contract: the file is parsed exactly once and the
|
|
53
|
+
* parsed doc is passed to {@link validateStatusValue} — the previous
|
|
54
|
+
* path-first read then `readJson` re-read was a TOCTOU window (a concurrent
|
|
55
|
+
* writer between the two reads threw a raw error from inside the gate).
|
|
56
|
+
* Malformed JSON is contained here with the engine's `status.invalid-json`
|
|
57
|
+
* shape; never throws. Missing files are guarded by the callers
|
|
58
|
+
* (`gateStatusIntent`, {@link DshHostAdapter.statusGate}) — first create has
|
|
59
|
+
* no document to validate and passes before this function runs.
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateStatusDoc(statusPath: string): GateResult;
|
|
62
|
+
/**
|
|
63
|
+
* `fs/write-intent` listener. Registered with `prepend` so this decider runs
|
|
64
|
+
* BEFORE dsh-fs-policy regardless of mount order: the slot is first-wins by
|
|
65
|
+
* registration order (dsh-fs-policy README), so without prepend a policy
|
|
66
|
+
* plugin mounted earlier would make this gate unreachable. Every gate
|
|
67
|
+
* decision (warn advisory, repair escape, degraded allow) calls `next()` —
|
|
68
|
+
* delegating the observed-state intent decision to the remaining chain
|
|
69
|
+
* (fs-policy when mounted; the bare `undefined` default otherwise) rather
|
|
70
|
+
* than terminating the slot with `undefined` (which would silently disable
|
|
71
|
+
* fs-policy's CAS for status.json in composed deployments).
|
|
72
|
+
*/
|
|
73
|
+
export declare function writeIntentListener(ctx: Context, resolver: HarnessResolver, config: Config, adapter: DshHostAdapter, target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise<FsWriteIntent | undefined>): Promise<FsWriteIntent | undefined>;
|
|
74
|
+
/** `fs/edit-intent` listener — same gate and delegation contract as {@link writeIntentListener}. */
|
|
75
|
+
export declare function editIntentListener(ctx: Context, resolver: HarnessResolver, config: Config, adapter: DshHostAdapter, target: FsTarget, actor: object | undefined, next: () => {
|
|
76
|
+
version: FsVersion;
|
|
77
|
+
} | undefined | Promise<{
|
|
78
|
+
version: FsVersion;
|
|
79
|
+
} | undefined>): Promise<{
|
|
80
|
+
version: FsVersion;
|
|
81
|
+
} | undefined>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { HarnessResolver } from './_shared.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Register the v2 seam model-facing tools: `mstar sdd …` / `mstar iteration gate` equivalents operating
|
|
5
|
+
* in-app against control-path artifacts.
|
|
6
|
+
*
|
|
7
|
+
* The registrations are deferred with `ctx.inject(['tools'], …)` — the same
|
|
8
|
+
* optional-unit pattern as dsh-tool-todo — so the plugin boots without the
|
|
9
|
+
* tools service (gates stay active) and registers when the composed dsh app
|
|
10
|
+
* provides `ctx.tools`. The fs-mutating tools declare
|
|
11
|
+
* `isConcurrencySafe: () => false` (exclusive — never overlap with sibling
|
|
12
|
+
* calls, matching the real registry's exclusive default).
|
|
13
|
+
* @param ctx - registrant context carrying the tool registry.
|
|
14
|
+
* @param resolver - the per-workspace `{HARNESS_DIR}` resolver (the tools
|
|
15
|
+
* resolve per the calling session's workspace — never the process cwd;
|
|
16
|
+
* explicit config wins).
|
|
17
|
+
*/
|
|
18
|
+
export declare function registerSddIterationTools(ctx: Context, resolver: HarnessResolver): void;
|
|
19
|
+
/**
|
|
20
|
+
* Register the on-demand seam validation tools (
|
|
21
|
+
* 20260808-dsh-seams-bundle): `mstar design-md validate` / `mstar compound
|
|
22
|
+
* validate` CLI mirrors plus the audit / roles validators — thin wrappers
|
|
23
|
+
* running the engine in-app. The registrations are deferred with
|
|
24
|
+
* `ctx.inject(['tools'], …)` (same optional-unit pattern as the sdd tools),
|
|
25
|
+
* so the plugin boots without the tools service (gates stay active).
|
|
26
|
+
*
|
|
27
|
+
* `mstar_compound_validate` adds one `repo_root` param beyond the CLI
|
|
28
|
+
* (`mstar compound validate` has no reference-existence check) — the
|
|
29
|
+
* compound-refresh Phase 2 check the seam gate runs per write, offered
|
|
30
|
+
* on-demand. All tools are read-only evaluations — exclusive anyway
|
|
31
|
+
* (registry default; the engine results are pure functions of the docs).
|
|
32
|
+
* @param ctx - registrant context carrying the tool registry.
|
|
33
|
+
* @param resolver - the per-workspace `{HARNESS_DIR}` resolver (the
|
|
34
|
+
* compound default root resolves per the calling session's workspace —
|
|
35
|
+
* never the process cwd; explicit config wins).
|
|
36
|
+
*/
|
|
37
|
+
export declare function registerSeamTools(ctx: Context, resolver: HarnessResolver): void;
|