@mstar-harness/engine 3.6.3 → 3.7.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/dist/audit.d.ts +11 -12
- package/dist/compound.d.ts +10 -10
- package/dist/core.d.ts +2 -3
- package/dist/dispatch.d.ts +57 -64
- package/dist/engine.js +467 -30
- package/dist/index.d.ts +6 -6
- package/dist/iteration.d.ts +3 -3
- package/dist/lint.d.ts +49 -49
- package/dist/migrate.d.ts +22 -22
- package/dist/path.d.ts +35 -25
- package/dist/project.d.ts +24 -26
- package/dist/prreview.d.ts +98 -99
- package/dist/roles.d.ts +22 -12
- package/dist/sdd.d.ts +198 -8
- package/dist/skill-authoring.d.ts +36 -9
- package/dist/status.d.ts +10 -11
- package/dist/store.d.ts +9 -12
- package/dist/workflow.d.ts +11 -11
- package/dist/worktree.d.ts +1 -2
- package/package.json +1 -1
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
* Source skills (semantic SSOT — this module implements their deterministic
|
|
7
7
|
* rules, it never redefines them; roadmap §8.5 C2):
|
|
8
8
|
* - `mstar-skill-authoring` SKILL.md § Frontmatter Contract — `name` stable
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* lowercase-hyphen; `description` is the trigger contract (not a workflow
|
|
10
|
+
* summary), third person.
|
|
11
11
|
* - `mstar-skill-authoring` SKILL.md § Body 必须回答的 5 问 + § 默认 Body
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* 结构 — a SKILL.md body answers five questions via key sections (Load
|
|
13
|
+
* Order, Workflow, Decision Rules, Evidence, References).
|
|
14
14
|
* - `mstar-skill-authoring` SKILL.md § Skill-relative script and asset
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* paths ("skill `my-skill` → scripts/do-thing") + `mstar-host` SKILL.md
|
|
16
|
+
* § Resolve loaded skill root (per-host resolution).
|
|
17
17
|
*
|
|
18
18
|
* The SkillsBench six principles and trigger-contract reasoning stay prompt.
|
|
19
19
|
*/
|
|
@@ -46,10 +46,37 @@ export declare function stripFrontmatter(text: string): string;
|
|
|
46
46
|
* or `runtime` (canonical plus the locked `RUNTIME_HEADING_ALIASES` table
|
|
47
47
|
* — shipped `mstar-*` topic skills). */
|
|
48
48
|
export type FiveQuestionMode = "authoring" | "runtime";
|
|
49
|
+
/** Skill-lint profile kind (spec A4): `core` = the `mstar-harness-core` hub
|
|
50
|
+
* (five-question exempt), `runtime` = shipped `mstar-*` topic skills, and
|
|
51
|
+
* `authoring` = the standard plus every non-`mstar-*`/unknown input. */
|
|
52
|
+
export type SkillLintKind = "core" | "runtime" | "authoring";
|
|
53
|
+
/** Classification result: the profile kind plus the five-question mode to
|
|
54
|
+
* apply — `null` mode means the five-question check is skipped entirely
|
|
55
|
+
* (core exemption only; every other check stays active). */
|
|
56
|
+
export type SkillLintProfile = {
|
|
57
|
+
kind: SkillLintKind;
|
|
58
|
+
mode: FiveQuestionMode | null;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* One lint-classification policy (spec A4
|
|
62
|
+
* the single profile SSOT the CLI, dsh and drift Guard 5 consume.
|
|
63
|
+
* Semantics preserve the CLI `skill lint` selection verbatim:
|
|
64
|
+
* - exact `mstar-harness-core` → `core` / `null` (five-question exempt by
|
|
65
|
+
* design — hub headings; frontmatter + ephemeral checks still run);
|
|
66
|
+
* - exact `mstar-skill-authoring` → `authoring` (the standard's own
|
|
67
|
+
* definition stays strict despite the `mstar-` prefix);
|
|
68
|
+
* - any other `mstar-*` → `runtime` (locked alias table applies);
|
|
69
|
+
* - unknown / non-`mstar-*` / missing identity → `authoring` (strict
|
|
70
|
+
* default — greenfield inputs are never loosened).
|
|
71
|
+
* The `skillId` is the resolved target directory basename at the CLI and
|
|
72
|
+
* dsh configured skill-root boundaries — never an arbitrary YAML `name`
|
|
73
|
+
* alone (a misleading frontmatter name must not select a looser profile).
|
|
74
|
+
* These are lint profiles only: not authorization, not trusted origin.
|
|
75
|
+
*/
|
|
76
|
+
export declare function classifySkillLint(skillId: string | undefined): SkillLintProfile;
|
|
49
77
|
/**
|
|
50
|
-
* Locked runtime alias table
|
|
51
|
-
*
|
|
52
|
-
* shipped topic skills, verified against the corpus at `81480e7`. Tokens are
|
|
78
|
+
* Locked runtime alias table: heading synonyms that answer the same question
|
|
79
|
+
* for shipped topic skills, verified against the shipped-skill corpus. Tokens are
|
|
53
80
|
* case-insensitive heading substrings (any heading level); the `decision-rules`
|
|
54
81
|
* breadth is bounded by the corpus regression test pinning current state.
|
|
55
82
|
* `load-order` has no aliases — the canonical label covers 15/16 skills and
|
package/dist/status.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type StatusDoc = {
|
|
|
14
14
|
[key: string]: unknown;
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
|
-
* v2 root status document (`{HARNESS_DIR}/status.json
|
|
17
|
+
* v2 root status document (`{HARNESS_DIR}/status.json`( — hard
|
|
18
18
|
* cutover): `version`, `updated_at`, `workflows[]` only. The list holds
|
|
19
19
|
* ACTIVE (non-terminal) lifecycles; terminal writers unregister AFTER the
|
|
20
20
|
* snapshot write (removal-at-terminal).
|
|
@@ -96,7 +96,7 @@ export declare function validatePlanRow(row: unknown): GateResult;
|
|
|
96
96
|
*/
|
|
97
97
|
export declare function validateResidual(entry: unknown): GateResult;
|
|
98
98
|
/**
|
|
99
|
-
* Validate one v2 root `workflows[]` entry (
|
|
99
|
+
* Validate one v2 root `workflows[]` entry (): required `id`,
|
|
100
100
|
* `type` (plan | iteration), `started_at`, `dir` — harness-relative, never
|
|
101
101
|
* absolute and never containing `..`. The removal-at-terminal invariant
|
|
102
102
|
* (snapshot exists and is non-terminal) is checked at document level by
|
|
@@ -104,7 +104,7 @@ export declare function validateResidual(entry: unknown): GateResult;
|
|
|
104
104
|
*/
|
|
105
105
|
export declare function validateWorkflowEntry(entry: unknown): GateResult;
|
|
106
106
|
/**
|
|
107
|
-
* Validate a v2 status.json document (
|
|
107
|
+
* Validate a v2 status.json document ( — hard cutover). Accepts a
|
|
108
108
|
* parsed document or a file path (malformed JSON yields a
|
|
109
109
|
* `status.invalid-json` violation, never a throw). v1 or unknown-version
|
|
110
110
|
* inputs — including v1-shaped documents carrying a root `plans[]` — fail
|
|
@@ -122,14 +122,14 @@ export declare function validateWorkflowEntry(entry: unknown): GateResult;
|
|
|
122
122
|
* root holds active lifecycles only, and terminal writers unregister AFTER
|
|
123
123
|
* the snapshot write. The snapshot must also PHYSICALLY live under the
|
|
124
124
|
* harness: a symlinked `workflows/<id>/` (or snapshot file) resolving
|
|
125
|
-
* outside the harness dir is rejected fail-closed
|
|
125
|
+
* outside the harness dir is rejected fail-closed . Doc
|
|
126
126
|
* input without a harness dir is structure-only.
|
|
127
127
|
*/
|
|
128
128
|
export declare function validateStatusV2(docOrPath: StatusV2Doc | string, opts?: {
|
|
129
129
|
harnessDir?: string;
|
|
130
130
|
}): GateResult;
|
|
131
131
|
/**
|
|
132
|
-
* Relocated v2 root validator (
|
|
132
|
+
* Relocated v2 root validator ( — hard cutover, no dual path):
|
|
133
133
|
* the v1 `validateStatus` implementation was deleted in the same task that
|
|
134
134
|
* introduced the v2 surface; the public export name survives so external
|
|
135
135
|
* consumers (CLI, host hooks — cut over in P2) keep compiling and now fail
|
|
@@ -158,14 +158,14 @@ export declare const validateStatus: typeof validateStatusV2;
|
|
|
158
158
|
* Async-only (architect-locked 2026-08-27): the durable write goes through
|
|
159
159
|
* `getArtifactStore().put({ kind: "status", key: "root", ... })` inside the
|
|
160
160
|
* caller's lock — the store is the persist backend, never a second lock.
|
|
161
|
-
* Fails loud
|
|
161
|
+
* Fails loud when the active FsStore would resolve its
|
|
162
162
|
* `status.json` to a path other than `statusPath` — callers whose root
|
|
163
163
|
* differs from the active store's root MUST
|
|
164
164
|
* `setArtifactStore(createFsStore(root))` first.
|
|
165
165
|
*/
|
|
166
166
|
export declare function registerWorkflowEntryLocked(statusPath: string, entry: WorkflowEntry): Promise<StatusV2Doc>;
|
|
167
167
|
/**
|
|
168
|
-
* Register one active workflow entry in the v2 root file (
|
|
168
|
+
* Register one active workflow entry in the v2 root file ().
|
|
169
169
|
* Idempotent upsert by entry `id` under the root-file `withStatusWriteLock`,
|
|
170
170
|
* bumping root `updated_at`. A missing/empty root file is initialized from
|
|
171
171
|
* the v2 template (never a v1 tree); a v1 root is refused with the
|
|
@@ -178,7 +178,7 @@ export declare function registerWorkflowEntryLocked(statusPath: string, entry: W
|
|
|
178
178
|
*/
|
|
179
179
|
export declare function registerWorkflow(root: string, entry: WorkflowEntry): Promise<StatusV2Doc>;
|
|
180
180
|
/**
|
|
181
|
-
* Remove one workflow entry from the v2 root file (
|
|
181
|
+
* Remove one workflow entry from the v2 root file (). Idempotent:
|
|
182
182
|
* removing an absent id is a no-op with no write; a missing/empty root file
|
|
183
183
|
* is a no-op that never creates the file. Runs under the root-file
|
|
184
184
|
* `withStatusWriteLock`, bumping root `updated_at` only when an entry was
|
|
@@ -186,7 +186,7 @@ export declare function registerWorkflow(root: string, entry: WorkflowEntry): Pr
|
|
|
186
186
|
* invariant included) before the write — a v1 root is refused with the
|
|
187
187
|
* `mstar migrate` hint.
|
|
188
188
|
*
|
|
189
|
-
* Fails loud
|
|
189
|
+
* Fails loud when the active FsStore would resolve its
|
|
190
190
|
* `status.json` to a path other than the caller's root — the no-op branches
|
|
191
191
|
* below never mask a store/path mismatch.
|
|
192
192
|
*/
|
|
@@ -199,8 +199,7 @@ export declare function unregisterWorkflow(root: string, id: string): Promise<St
|
|
|
199
199
|
* frontmatter declares `enforcement: hard` hardens the gate in this repo.
|
|
200
200
|
* A COMPLETED (or status-less/archived) iteration's compass NEVER hardens:
|
|
201
201
|
* D2 rollback = unset the flag in the ACTIVE compass, and that must work
|
|
202
|
-
* while older completed compasses still declare hard
|
|
203
|
-
* A counting compass declaring a non-hard value, or no compass at all,
|
|
202
|
+
* while older completed compasses still declare hard. * A counting compass declaring a non-hard value, or no compass at all,
|
|
204
203
|
* leaves the flag unset (`source: none`) — hard gates are never the default
|
|
205
204
|
* and the flag is inert when the engine is absent. Frontmatter is
|
|
206
205
|
* `---`-fenced; hard declarations in the compass BODY do not count (the
|
package/dist/store.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
/** JSON coordination-doc kinds the store persists
|
|
2
|
-
export type ArtifactKind = "status" | "snapshot" | "residuals" | "review" | "json";
|
|
1
|
+
/** JSON coordination-doc kinds the store persists */ export type ArtifactKind = "status" | "snapshot" | "residuals" | "review" | "json";
|
|
3
2
|
/** Stable key inside the kind. Workflow id, project id, or review id;
|
|
4
3
|
* `kind: "status"` always uses key `"root"`. */
|
|
5
4
|
export type ArtifactRef = {
|
|
@@ -23,14 +22,13 @@ export interface ArtifactStore {
|
|
|
23
22
|
get<T = unknown>(ref: ArtifactRef): Promise<T | undefined>;
|
|
24
23
|
delete?(ref: ArtifactRef): Promise<void>;
|
|
25
24
|
/** Enumerate refs of `kind`, sorted by key ascending (spec D4). Uniform
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
* rule: report what exists — missing backing dir/file → `[]`; every
|
|
26
|
+
* listed key round-trips through `get`. `json` is not enumerable. */
|
|
28
27
|
list?(kind: ArtifactKind): Promise<ArtifactRef[]>;
|
|
29
28
|
}
|
|
30
|
-
/** Map an artifact ref to its file path under `harnessRoot` (
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* imports the contract instead of re-deriving it textually. */
|
|
29
|
+
/** Map an artifact ref to its file path under `harnessRoot` (the store contract — the single kind→path
|
|
30
|
+
* mapping). Exported so host adapters import the contract instead of
|
|
31
|
+
* re-deriving it textually. */
|
|
34
32
|
export declare function resolveArtifactPath(harnessRoot: string, ref: ArtifactRef): string;
|
|
35
33
|
/** Default local adapter: maps kinds to the existing `.mstar/` paths.
|
|
36
34
|
* `put` uses the sync `writeJson` (atomic temp+rename unchanged) and
|
|
@@ -39,7 +37,7 @@ export declare function resolveArtifactPath(harnessRoot: string, ref: ArtifactRe
|
|
|
39
37
|
* malformed JSON → throw with the path in the message. The returned store
|
|
40
38
|
* also exposes its resolved `root` so the routed writers can fail loud
|
|
41
39
|
* when a caller's explicit target path diverges from the store-resolved
|
|
42
|
-
* path
|
|
40
|
+
* path ; `root` is not part of the `ArtifactStore` contract.
|
|
43
41
|
* `list` enumerates per the D4 table: report what exists — missing
|
|
44
42
|
* backing dir/file → `[]`, `json` throws, keys sorted ascending. */
|
|
45
43
|
export declare function createFsStore(harnessRoot: string): ArtifactStore & {
|
|
@@ -52,7 +50,7 @@ export declare function setArtifactStore(store: ArtifactStore | undefined): void
|
|
|
52
50
|
* `resolveHarnessSubdir` — never a silent cwd fallback. */
|
|
53
51
|
export declare function getArtifactStore(): ArtifactStore;
|
|
54
52
|
/**
|
|
55
|
-
* Fail-loud path-agreement guard for the routed writers
|
|
53
|
+
* Fail-loud path-agreement guard for the routed writers : when
|
|
56
54
|
* `store` is an FsStore, resolve the path the store would compute for
|
|
57
55
|
* `ref` and require it to equal `expectedPath` (the caller's explicit
|
|
58
56
|
* target). A divergence means the caller's path lives outside the active
|
|
@@ -62,8 +60,7 @@ export declare function getArtifactStore(): ArtifactStore;
|
|
|
62
60
|
* Cheap: pure path resolution, no I/O.
|
|
63
61
|
*/
|
|
64
62
|
export declare function assertFsStorePath(store: ArtifactStore, ref: ArtifactRef, expectedPath: string): void;
|
|
65
|
-
/** Load a store module from a filesystem path (
|
|
66
|
-
* SP2-AC6 / SP2-AC7). Resolves against cwd; rejects empty values and any
|
|
63
|
+
/** Load a store module from a filesystem path (the store module-loading trust boundary). Resolves against cwd; rejects empty values and any
|
|
67
64
|
* URI scheme before `import()`; throws when the file is missing. Accepts a
|
|
68
65
|
* `createArtifactStore` named export, a default-exported factory, or a
|
|
69
66
|
* default-exported object; the result is structurally verified (`put` +
|
package/dist/workflow.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { GateResult } from "./core.js";
|
|
2
2
|
import { type IntegrationMergeLease } from "./lease.js";
|
|
3
3
|
import { type PlanRow } from "./status.js";
|
|
4
|
-
/** Snapshot file name inside `workflows/<id>/` (
|
|
4
|
+
/** Snapshot file name inside `workflows/<id>/` ( — writer contract). */
|
|
5
5
|
export declare const WORKFLOW_SNAPSHOT_FILE = "snapshot.json";
|
|
6
|
-
/** Lifecycle status enum (
|
|
6
|
+
/** Lifecycle status enum ( — terminal set = completed|failed|stopped). */
|
|
7
7
|
export declare const WORKFLOW_LIFECYCLE_STATUSES: readonly ["running", "paused", "completed", "failed", "stopped"];
|
|
8
8
|
/** Terminal statuses: snapshot must carry `ended_at` and no dangling leases. */
|
|
9
9
|
export declare const WORKFLOW_TERMINAL_STATUSES: readonly ["completed", "failed", "stopped"];
|
|
10
|
-
/** Lifecycle type enum (
|
|
10
|
+
/** Lifecycle type enum ( — id reuses the orchestration id). */
|
|
11
11
|
export declare const WORKFLOW_LIFECYCLE_TYPES: readonly ["plan", "iteration"];
|
|
12
12
|
export type WorkflowLifecycleStatus = (typeof WORKFLOW_LIFECYCLE_STATUSES)[number];
|
|
13
13
|
export type WorkflowLifecycleType = (typeof WORKFLOW_LIFECYCLE_TYPES)[number];
|
|
14
14
|
/**
|
|
15
|
-
* First-class lifecycle execution policy (
|
|
15
|
+
* First-class lifecycle execution policy ( — keys copied from root
|
|
16
16
|
* `metadata` at migrate; values accepted-but-opaque this iteration, no
|
|
17
17
|
* semantic gate).
|
|
18
18
|
*/
|
|
@@ -21,7 +21,7 @@ export type WorkflowExecutionPolicy = {
|
|
|
21
21
|
worktree_mode?: unknown;
|
|
22
22
|
push_policy?: unknown;
|
|
23
23
|
};
|
|
24
|
-
/** Iteration branch anchors (
|
|
24
|
+
/** Iteration branch anchors ( — from root metadata anchors). */
|
|
25
25
|
export type WorkflowBranchAnchors = {
|
|
26
26
|
base?: string;
|
|
27
27
|
integration?: string;
|
|
@@ -29,11 +29,11 @@ export type WorkflowBranchAnchors = {
|
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
31
|
* v3 workflow snapshot (`workflows/<id>/snapshot.json`) — final schema
|
|
32
|
-
* (
|
|
32
|
+
* (). `plans[]` rows are the legacy PlanRow shape verbatim;
|
|
33
33
|
* per-row `execution_lease` stays on the row, `integration_merge_lease` is
|
|
34
34
|
* top-level.
|
|
35
35
|
*
|
|
36
|
-
* Notes dual-home SSOT
|
|
36
|
+
* Notes dual-home SSOT: a plan row's `notes` array is the
|
|
37
37
|
* LEGACY VERBATIM copy preserved at migrate time — the RUNTIME ledger is
|
|
38
38
|
* `notes.jsonl` in the workflow dir (`migrate.ts` NOTES_LEDGER_FILE). New
|
|
39
39
|
* notes append to the ledger only; row `notes` is read-only legacy and is
|
|
@@ -57,7 +57,7 @@ export type WorkflowSnapshot = {
|
|
|
57
57
|
compass_ref?: string;
|
|
58
58
|
};
|
|
59
59
|
/**
|
|
60
|
-
* Validate a v3 workflow snapshot document (
|
|
60
|
+
* Validate a v3 workflow snapshot document ( — final schema):
|
|
61
61
|
* enum/type/id checks, `schema_version: 1`, required timestamps, `plans[]`
|
|
62
62
|
* rows validated by the legacy `validatePlanRow` with row-level
|
|
63
63
|
* `execution_lease` shape delegated to `validateExecutionLease`,
|
|
@@ -70,16 +70,16 @@ export type WorkflowSnapshot = {
|
|
|
70
70
|
export declare function validateWorkflowSnapshot(doc: unknown): GateResult;
|
|
71
71
|
/**
|
|
72
72
|
* Write a workflow snapshot as a whole-rewrite of `dir/snapshot.json` under
|
|
73
|
-
* `withStatusWriteLock(snapshotPath)` (
|
|
73
|
+
* `withStatusWriteLock(snapshotPath)` ( — the `.status-write.lockdir`
|
|
74
74
|
* lands inside `workflows/<id>/`, dirname of the snapshot; no harness-root
|
|
75
75
|
* pollution). The snapshot is validated first — an invalid snapshot throws
|
|
76
76
|
* and nothing is written. `dir` is created recursively. The durable write
|
|
77
|
-
* routes through the active `ArtifactStore` (
|
|
77
|
+
* routes through the active `ArtifactStore` (the store contract: snapshot →
|
|
78
78
|
* `{ kind: "snapshot", key: <workflow id> }`) inside the existing lock — the
|
|
79
79
|
* default FsStore resolves `{WORKFLOW_DIR}/<key>/snapshot.json`, identical
|
|
80
80
|
* to `join(dir, WORKFLOW_SNAPSHOT_FILE)` for canonical callers. The write
|
|
81
81
|
* fails loud when the active FsStore would resolve a different path than
|
|
82
|
-
* the caller's `join(dir, WORKFLOW_SNAPSHOT_FILE)`
|
|
82
|
+
* the caller's `join(dir, WORKFLOW_SNAPSHOT_FILE)` — callers
|
|
83
83
|
* whose target root differs from the active store's root MUST
|
|
84
84
|
* `setArtifactStore(createFsStore(root))` first.
|
|
85
85
|
*/
|
package/dist/worktree.d.ts
CHANGED
|
@@ -38,8 +38,7 @@ export type BranchProbeOptions = {
|
|
|
38
38
|
/**
|
|
39
39
|
* Git probe timeout in ms (default 10s; `MSTAR_GIT_PROBE_TIMEOUT_MS` env
|
|
40
40
|
* overrides; per-call value wins). On timeout the probe fails closed into
|
|
41
|
-
* `branch-probe-failed` — never hangs, never guesses a branch
|
|
42
|
-
*/
|
|
41
|
+
* `branch-probe-failed` — never hangs, never guesses a branch. */
|
|
43
42
|
timeoutMs?: number;
|
|
44
43
|
};
|
|
45
44
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mstar-harness/engine",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "Morning Star Harness Workflow Engine — deterministic workflow enforcement library (path, status, lease, dispatch, sdd, iteration, lint gates).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|