@mstar-harness/engine 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/engine.js +57 -27
- package/dist/host.d.ts +24 -14
- package/dist/path.d.ts +28 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ const version = readHarnessVersion(); // "1.8.8" — monorepo root package.json
|
|
|
19
19
|
## Scope
|
|
20
20
|
|
|
21
21
|
- Importable library only — **no `bin`**; the CLI (`@mstar-harness/cli`) wraps engine functions as thin `mstar …` subcommands.
|
|
22
|
-
- Dependencies: `node:*` only (zero external runtime deps — all validators hand-rolled; ajv pruned as phantom
|
|
22
|
+
- Dependencies: `node:*` only (zero external runtime deps — all validators hand-rolled; ajv and zod were pruned as phantom dependencies).
|
|
23
23
|
- Skill prose stays authoritative; engine exports are the machine-checkable mirror of the rules the `mstar-*` skills state.
|
|
24
24
|
|
|
25
25
|
## License
|
package/dist/engine.js
CHANGED
|
@@ -83,24 +83,52 @@ function readHarnessVersion() {
|
|
|
83
83
|
}
|
|
84
84
|
// src/path.ts
|
|
85
85
|
import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
86
|
+
import { execFileSync } from "node:child_process";
|
|
86
87
|
import { basename as basename2, dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "node:path";
|
|
87
88
|
function resolveHarnessDir(startDir = process.cwd(), opts = {}) {
|
|
88
89
|
const start = resolve2(startDir);
|
|
89
90
|
const explicit = opts.harnessDir ?? process.env.MSTAR_HARNESS_DIR;
|
|
90
91
|
if (explicit)
|
|
91
92
|
return resolve2(start, explicit);
|
|
93
|
+
const boundary = resolve2(start, opts.workspaceRoot ?? defaultWorkspaceRoot(start));
|
|
92
94
|
let dir = start;
|
|
93
95
|
for (;; ) {
|
|
96
|
+
if (!isAtOrBelow(dir, boundary))
|
|
97
|
+
return null;
|
|
94
98
|
for (const candidate of [join2(dir, ".mstar"), join2(dir, ".agents"), join2(dir, ".plans"), join2(dir, "plans")]) {
|
|
95
99
|
if (isDirectory(candidate))
|
|
96
100
|
return candidate;
|
|
97
101
|
}
|
|
102
|
+
if (dir === boundary)
|
|
103
|
+
return null;
|
|
98
104
|
const parent = dirname2(dir);
|
|
99
105
|
if (parent === dir)
|
|
100
106
|
return null;
|
|
101
107
|
dir = parent;
|
|
102
108
|
}
|
|
103
109
|
}
|
|
110
|
+
function defaultWorkspaceRoot(startDir) {
|
|
111
|
+
try {
|
|
112
|
+
const cdup = execFileSync("git", ["rev-parse", "--show-cdup"], {
|
|
113
|
+
cwd: startDir,
|
|
114
|
+
encoding: "utf8",
|
|
115
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
116
|
+
}).trim();
|
|
117
|
+
if (!cdup)
|
|
118
|
+
return startDir;
|
|
119
|
+
let boundary = startDir;
|
|
120
|
+
for (const segment of cdup.split(/[\\/]/)) {
|
|
121
|
+
if (segment && segment !== ".")
|
|
122
|
+
boundary = dirname2(boundary);
|
|
123
|
+
}
|
|
124
|
+
return resolve2(boundary);
|
|
125
|
+
} catch {}
|
|
126
|
+
return startDir;
|
|
127
|
+
}
|
|
128
|
+
function isAtOrBelow(dir, root) {
|
|
129
|
+
const rel = relative(root, dir);
|
|
130
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
131
|
+
}
|
|
104
132
|
function resolveSpecsDir(harnessDir, opts = {}) {
|
|
105
133
|
const harness = resolve2(harnessDir);
|
|
106
134
|
const repoRoot = dirname2(harness);
|
|
@@ -158,28 +186,27 @@ function scaffoldHarness(root) {
|
|
|
158
186
|
}
|
|
159
187
|
var GITIGNORE_SNIPPET = `# Morning Star harness (.mstar/)
|
|
160
188
|
# Principle: process stays local; results are shared with the team.
|
|
161
|
-
#
|
|
162
|
-
.mstar
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
# Tracked (results): .mstar/AGENTS.md, .mstar/knowledge/, .mstar/specs/
|
|
189
|
+
# Default-ignore everything under .mstar/, then re-include the tracked results.
|
|
190
|
+
.mstar/**
|
|
191
|
+
!.mstar/AGENTS.md
|
|
192
|
+
!.mstar/knowledge/
|
|
193
|
+
!.mstar/knowledge/**
|
|
194
|
+
!.mstar/specs/
|
|
195
|
+
!.mstar/specs/**
|
|
169
196
|
`;
|
|
170
197
|
var GITIGNORE_SNIPPET_AGENTS = `# Morning Star harness (.agents/) — legacy
|
|
171
|
-
.agents
|
|
172
|
-
.agents
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
198
|
+
# Default-ignore everything under .agents/, then re-include the tracked results.
|
|
199
|
+
.agents/**
|
|
200
|
+
!.agents/AGENTS.md
|
|
201
|
+
!.agents/knowledge/
|
|
202
|
+
!.agents/knowledge/**
|
|
203
|
+
!.agents/specs/
|
|
204
|
+
!.agents/specs/**
|
|
178
205
|
`;
|
|
179
206
|
var GITIGNORE_PROCESS_ENTRIES = GITIGNORE_SNIPPET.split(`
|
|
180
|
-
`).filter((line) => line.startsWith(".mstar/")).map((line) => line.trim());
|
|
207
|
+
`).filter((line) => line.startsWith(".mstar/") || line.startsWith("!.mstar/")).map((line) => line.trim());
|
|
181
208
|
var GITIGNORE_PROCESS_ENTRIES_AGENTS = GITIGNORE_SNIPPET_AGENTS.split(`
|
|
182
|
-
`).filter((line) => line.startsWith(".agents/")).map((line) => line.trim());
|
|
209
|
+
`).filter((line) => line.startsWith(".agents/") || line.startsWith("!.agents/")).map((line) => line.trim());
|
|
183
210
|
function emitGitignoreSnippet(kind) {
|
|
184
211
|
if (kind === "agents")
|
|
185
212
|
return GITIGNORE_SNIPPET_AGENTS;
|
|
@@ -230,7 +257,7 @@ function validateGitignore(root) {
|
|
|
230
257
|
ok: true,
|
|
231
258
|
severity: "low",
|
|
232
259
|
code: "gitignore.ok",
|
|
233
|
-
message: `.gitignore at ${gitignorePath} contains a complete canonical harness
|
|
260
|
+
message: `.gitignore at ${gitignorePath} contains a complete canonical harness ignore set — default-ignore + tracked re-includes (${label})`
|
|
234
261
|
};
|
|
235
262
|
}
|
|
236
263
|
function detectHarnessKind(harnessDir) {
|
|
@@ -1151,7 +1178,7 @@ function techDebtRollup(docOrPath) {
|
|
|
1151
1178
|
return { computed, stored, checks, overall };
|
|
1152
1179
|
}
|
|
1153
1180
|
// src/worktree.ts
|
|
1154
|
-
import { execFileSync } from "node:child_process";
|
|
1181
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
1155
1182
|
import { existsSync as existsSync3 } from "node:fs";
|
|
1156
1183
|
import { isAbsolute as isAbsolute3, resolve as resolve5 } from "node:path";
|
|
1157
1184
|
var DEFAULT_PROBE_TIMEOUT_MS = 1e4;
|
|
@@ -1174,7 +1201,7 @@ function probeBranch(worktreePath, opts) {
|
|
|
1174
1201
|
return { branch: precomputed };
|
|
1175
1202
|
const timeout = opts.timeoutMs ?? probeTimeoutMs();
|
|
1176
1203
|
try {
|
|
1177
|
-
const stdout =
|
|
1204
|
+
const stdout = execFileSync2(opts.gitPath ?? "git", ["-C", worktreePath, "branch", "--show-current"], {
|
|
1178
1205
|
encoding: "utf8",
|
|
1179
1206
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1180
1207
|
timeout
|
|
@@ -1303,7 +1330,7 @@ function singleReviewSnapshot(assignments) {
|
|
|
1303
1330
|
return gate(violations);
|
|
1304
1331
|
}
|
|
1305
1332
|
// src/sdd.ts
|
|
1306
|
-
import { execFileSync as
|
|
1333
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1307
1334
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, realpathSync, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1308
1335
|
import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute4, join as join5, resolve as resolve6 } from "node:path";
|
|
1309
1336
|
class SddScriptError extends Error {
|
|
@@ -1331,7 +1358,7 @@ function isFile(file) {
|
|
|
1331
1358
|
var GIT_CAPTURE_MAX_BYTES = 64 * 1024 * 1024;
|
|
1332
1359
|
function gitOut(cwd, args) {
|
|
1333
1360
|
try {
|
|
1334
|
-
return
|
|
1361
|
+
return execFileSync3("git", args, {
|
|
1335
1362
|
cwd,
|
|
1336
1363
|
encoding: "utf8",
|
|
1337
1364
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -1464,7 +1491,7 @@ function reviewPackage(base, head, outFile, opts = {}) {
|
|
|
1464
1491
|
const cwd = opts.cwd ?? process.cwd();
|
|
1465
1492
|
const verifyRef = (ref, what) => {
|
|
1466
1493
|
try {
|
|
1467
|
-
|
|
1494
|
+
execFileSync3("git", ["rev-parse", "--verify", "--quiet", ref], { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
1468
1495
|
} catch {
|
|
1469
1496
|
throw new SddScriptError(`bad ${what}: ${ref}`, 2);
|
|
1470
1497
|
}
|
|
@@ -1484,7 +1511,7 @@ function reviewPackage(base, head, outFile, opts = {}) {
|
|
|
1484
1511
|
const shortHead = gitOut(cwd, ["rev-parse", "--short", head]) ?? head;
|
|
1485
1512
|
out = join5(sddDir, `review-${shortBase}..${shortHead}.diff`);
|
|
1486
1513
|
}
|
|
1487
|
-
const run = (args) =>
|
|
1514
|
+
const run = (args) => execFileSync3("git", args, { cwd, maxBuffer: GIT_CAPTURE_MAX_BYTES });
|
|
1488
1515
|
const parts = [
|
|
1489
1516
|
Buffer.from(`# Review package: ${base}..${head}
|
|
1490
1517
|
|
|
@@ -1508,7 +1535,7 @@ function assertBaseSha(ref, opts = {}) {
|
|
|
1508
1535
|
throw new SddScriptError(`assertBaseSha: BASE must be a commit SHA (full or prefix); got ${JSON.stringify(ref)}. ` + "Never use HEAD~1 as review BASE (multi-commit tasks truncate).", 2);
|
|
1509
1536
|
}
|
|
1510
1537
|
try {
|
|
1511
|
-
|
|
1538
|
+
execFileSync3("git", ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], {
|
|
1512
1539
|
cwd: opts.cwd,
|
|
1513
1540
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1514
1541
|
});
|
|
@@ -3378,6 +3405,8 @@ function detectHost(signals) {
|
|
|
3378
3405
|
return "opencode";
|
|
3379
3406
|
if (s.has("task_agent_batch") || s.has("ask") || s.has("hub"))
|
|
3380
3407
|
return "omp";
|
|
3408
|
+
if (s.has("subagent"))
|
|
3409
|
+
return "dsh";
|
|
3381
3410
|
if (s.has("AgentSwarm"))
|
|
3382
3411
|
return "kimi";
|
|
3383
3412
|
if (s.has("Agent") || s.has("AskUserQuestion") || s.has("EnterPlanMode") || s.has("TodoWrite"))
|
|
@@ -3401,9 +3430,10 @@ function resolveSkillRoot(host, paths) {
|
|
|
3401
3430
|
case "kimi":
|
|
3402
3431
|
case "zcode":
|
|
3403
3432
|
return `./skills/${skill}${suffix}`;
|
|
3404
|
-
case "pi":
|
|
3405
3433
|
case "dsh":
|
|
3406
|
-
return
|
|
3434
|
+
return `$DSH_BUNDLED_SKILL_DIR/${skill}${suffix}`;
|
|
3435
|
+
case "pi":
|
|
3436
|
+
return `deferred: pi has no plugin API in v1 — skill-root resolution lands with its adapter (roadmap §8.4)`;
|
|
3407
3437
|
}
|
|
3408
3438
|
}
|
|
3409
3439
|
// src/skill-authoring.ts
|
package/dist/host.d.ts
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
* resolution.
|
|
12
12
|
* - `.harness/references/skill-programmatic-roadmap.md` §8.4 — the
|
|
13
13
|
* `HostAdapter` shared contract (all hooks optional; no concrete adapters
|
|
14
|
-
* in the engine; pi
|
|
14
|
+
* in the engine; pi deferred).
|
|
15
|
+
* - `.harness/references/dsh-adapter-roadmap.md` §4 D5 (this iteration) —
|
|
16
|
+
* the dsh detection row + skill-root form; mirror text lands in the
|
|
17
|
+
* mstar-host skill when this module is upstreamed.
|
|
15
18
|
*
|
|
16
19
|
* UX judgment (ambiguous-host fallback reasoning, plan-mode bridges) stays
|
|
17
20
|
* prompt — this module only turns tool shapes into a host id.
|
|
@@ -19,18 +22,19 @@
|
|
|
19
22
|
import type { GateResult, ValidationResult } from "./core.js";
|
|
20
23
|
import type { AssignmentFields } from "./dispatch.js";
|
|
21
24
|
import type { IntegrationMergeLease } from "./lease.js";
|
|
22
|
-
/** All hosts the engine knows about (roadmap §8.4 host union). `pi`
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
/** All hosts the engine knows about (roadmap §8.4 host union). `pi` has no
|
|
26
|
+
* plugin API in v1 — it appears in the union (and in `HostAdapter.host`) but
|
|
27
|
+
* is never detected and gets no adapter. `dsh` is detected and resolved
|
|
28
|
+
* (roadmap §4 D5, this iteration); its adapter ships in the dsh plugin. */
|
|
25
29
|
export type HostId = "opencode" | "omp" | "pi" | "dsh" | "cursor" | "codex" | "kimi" | "zcode";
|
|
26
|
-
/** Result of `detectHost`: one of the
|
|
30
|
+
/** Result of `detectHost`: one of the seven known hosts or `ambiguous`
|
|
27
31
|
* (prompt judgment then applies per mstar-host). */
|
|
28
|
-
export type DetectResult = "opencode" | "omp" | "cursor" | "codex" | "kimi" | "zcode" | "ambiguous";
|
|
32
|
+
export type DetectResult = "opencode" | "omp" | "dsh" | "cursor" | "codex" | "kimi" | "zcode" | "ambiguous";
|
|
29
33
|
/** Tool-shape signal tokens accepted by `detectHost`, derived from the
|
|
30
34
|
* mstar-host detection table. Plan-mode extras (CreatePlan/SwitchMode) and
|
|
31
35
|
* Browser-plugin tools are documented in the table but are not part of the
|
|
32
36
|
* v1 signal enum. */
|
|
33
|
-
export type ToolSignal = "subagent_type" | "question" | "task_subagent" | "task_agent_batch" | "ask" | "hub" | "Agent" | "AgentSwarm" | "AskUserQuestion" | "EnterPlanMode" | "TodoWrite" | "plan_slash" | "goal" | "functions.*" | "tool_search";
|
|
37
|
+
export type ToolSignal = "subagent_type" | "question" | "task_subagent" | "task_agent_batch" | "ask" | "hub" | "subagent" | "Agent" | "AgentSwarm" | "AskUserQuestion" | "EnterPlanMode" | "TodoWrite" | "plan_slash" | "goal" | "functions.*" | "tool_search";
|
|
34
38
|
/**
|
|
35
39
|
* Detect the active host from session tool shapes, per the ordered
|
|
36
40
|
* mstar-host table (ported verbatim):
|
|
@@ -40,14 +44,19 @@ export type ToolSignal = "subagent_type" | "question" | "task_subagent" | "task_
|
|
|
40
44
|
* | `subagent_type` (Task param; plan mode + CreatePlan/SwitchMode) | cursor |
|
|
41
45
|
* | `question`, or `task_subagent` (task tool, singular subagent, no batch) | opencode |
|
|
42
46
|
* | `task_agent_batch` (task tool, agent/tasks[] batch), `ask`, `hub` | omp |
|
|
47
|
+
* | `subagent` (dsh's model-facing delegation tool) | dsh |
|
|
43
48
|
* | `Agent`/`AskUserQuestion`/`EnterPlanMode` + `AgentSwarm` (Kimi-only) | kimi |
|
|
44
49
|
* | `Agent`/`AskUserQuestion`/`EnterPlanMode`/`TodoWrite`, no `AgentSwarm` | zcode |
|
|
45
50
|
* | `/plan`, `/goal`; Goal tools; `functions.*` namespaces; `tool_search` | codex |
|
|
46
51
|
*
|
|
47
|
-
* Order matters: cursor → opencode → omp → kimi → zcode → codex — the
|
|
48
|
-
* sharpest Task-based split is `subagent_type` (Cursor) vs `
|
|
49
|
-
* (OpenCode) vs `agent`/`tasks[]` (omp)
|
|
50
|
-
*
|
|
52
|
+
* Order matters: cursor → opencode → omp → dsh → kimi → zcode → codex — the
|
|
53
|
+
* sharpest Task-based split is `subagent_type` (Cursor) vs `task_subagent`
|
|
54
|
+
* (OpenCode) vs `agent`/`tasks[]` (omp); dsh's `subagent` tool (roadmap §4
|
|
55
|
+
* D5) collides with no other row, so it sits with the agent-tool hosts.
|
|
56
|
+
* (`mstar-host` skill prose still says colloquial `subagent` for OpenCode —
|
|
57
|
+
* disambiguate it to `task_subagent` in the same upstream PR that carries
|
|
58
|
+
* this row, together with the CLI `HOST_SIGNALS` list.)
|
|
59
|
+
* Still ambiguous → `"ambiguous"` (prompt judgment stays in the skill).
|
|
51
60
|
*/
|
|
52
61
|
export declare function detectHost(signals: readonly ToolSignal[]): DetectResult;
|
|
53
62
|
/** Skill name + optional skill-relative path for skill-root resolution. */
|
|
@@ -69,7 +78,8 @@ export type SkillRootPaths = {
|
|
|
69
78
|
* | codex | `skills/<name>[/<rel>]` (plugin-mounted; project command skills under `.agents/skills/<name>/`) |
|
|
70
79
|
* | opencode | `harness-skills/<name>[/<rel>]` (package-internal via `@mstar-harness/opencode` — never `process.cwd()/skills/`) |
|
|
71
80
|
* | kimi / zcode | `./skills/<name>[/<rel>]` (plugin mount from the installed plugin root) |
|
|
72
|
-
* |
|
|
81
|
+
* | dsh | `$DSH_BUNDLED_SKILL_DIR/<name>[/<rel>]` (skill-local bundled root — dsh-skill-local `bundledSkillDir` default; the single canonical mount per roadmap D6. Frozen this iteration; local dev mounts the mirror `skills/` via `customSkillDirs` instead, but the canonical published form stays the bundled root) |
|
|
82
|
+
* | pi | deferred — no plugin API in v1 (roadmap §8.4) |
|
|
73
83
|
*/
|
|
74
84
|
export declare function resolveSkillRoot(host: HostId, paths: SkillRootPaths): string;
|
|
75
85
|
/**
|
|
@@ -79,8 +89,8 @@ export declare function resolveSkillRoot(host: HostId, paths: SkillRootPaths): s
|
|
|
79
89
|
* rule: skill text remains authoritative; the engine only returns results
|
|
80
90
|
* the caller chooses to honor). `log` is required — adapters must be able to
|
|
81
91
|
* report. No concrete adapters ship in the engine: opencode binds via its
|
|
82
|
-
* own plugin code, omp via the command layer
|
|
83
|
-
* until
|
|
92
|
+
* own plugin code, omp via the command layer, dsh via the dsh plugin (this
|
|
93
|
+
* iteration); pi stays deferred until its plugin API lands.
|
|
84
94
|
*/
|
|
85
95
|
export interface HostAdapter {
|
|
86
96
|
host: "opencode" | "omp" | "pi" | "dsh" | "cursor" | "codex" | "kimi" | "zcode";
|
package/dist/path.d.ts
CHANGED
|
@@ -10,15 +10,32 @@ export type ResolveHarnessDirOptions = {
|
|
|
10
10
|
* (the caller may scaffold it).
|
|
11
11
|
*/
|
|
12
12
|
harnessDir?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Workspace-root stop boundary (roadmap §7c / plan
|
|
15
|
+
* 20260810-harness-root-boundary). The upward probe keeps walking only
|
|
16
|
+
* while `dir` is at or below this root — a harness dir above it is never
|
|
17
|
+
* returned (the `~/.mstar` global-collision defect is the special case).
|
|
18
|
+
* Resolved against `startDir` when relative. When omitted, the default
|
|
19
|
+
* boundary is the git top-level of `startDir` (sync `git rev-parse
|
|
20
|
+
* --show-cdup`; on failure / non-git start it falls back to
|
|
21
|
+
* `startDir` itself — a non-git start probes only itself, never upward;
|
|
22
|
+
* deliberate tightening). The boundary is an explicit caller value: the
|
|
23
|
+
* engine git-probes only for this default resolution, never during the
|
|
24
|
+
* walk.
|
|
25
|
+
*/
|
|
26
|
+
workspaceRoot?: string;
|
|
13
27
|
};
|
|
14
28
|
/**
|
|
15
29
|
* Resolve `{HARNESS_DIR}` per plan-conventions § {HARNESS_DIR} 解析顺序
|
|
16
30
|
* (find-first-stop): `.mstar/` → `.agents/` → `.plans/`/`plans/`, walking up
|
|
17
|
-
* from `startDir
|
|
18
|
-
*
|
|
19
|
-
*
|
|
31
|
+
* from `startDir` but NEVER above the workspace root (`opts.workspaceRoot`,
|
|
32
|
+
* default = git top-level of `startDir`). Harness candidates are
|
|
33
|
+
* dir-existence (the empty-dir rule applies to `{SPECS_DIR}` only). An
|
|
34
|
+
* explicit override via `opts.harnessDir` or `MSTAR_HARNESS_DIR` wins over
|
|
35
|
+
* probing and short-circuits before any boundary logic.
|
|
20
36
|
*
|
|
21
|
-
* Returns the absolute harness dir, or `null` when no candidate exists
|
|
37
|
+
* Returns the absolute harness dir, or `null` when no candidate exists
|
|
38
|
+
* within the workspace boundary.
|
|
22
39
|
*/
|
|
23
40
|
export declare function resolveHarnessDir(startDir?: string, opts?: ResolveHarnessDirOptions): string | null;
|
|
24
41
|
/**
|
|
@@ -86,15 +103,17 @@ export declare function scaffoldHarness(root: string): string;
|
|
|
86
103
|
export type HarnessKind = "mstar" | "agents";
|
|
87
104
|
/**
|
|
88
105
|
* Emit the canonical `.gitignore` snippet for `kind` (plan-conventions
|
|
89
|
-
* § Git 跟踪策略): the
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
106
|
+
* § Git 跟踪策略): default-ignore the whole harness dir (`<dir>/**`) and
|
|
107
|
+
* re-include only the tracked results (AGENTS.md, knowledge/, specs/).
|
|
108
|
+
* When the kind is unknown (omitted), both snippets are emitted so either
|
|
109
|
+
* fence can be applied.
|
|
93
110
|
*/
|
|
94
111
|
export declare function emitGitignoreSnippet(kind?: HarnessKind): string;
|
|
95
112
|
/**
|
|
96
113
|
* Validate that `<root>/.gitignore` contains a complete canonical
|
|
97
|
-
*
|
|
114
|
+
* harness ignore set — default-ignore `<dir>/**` plus the tracked
|
|
115
|
+
* re-includes (AGENTS.md, knowledge/, specs/) per plan-conventions
|
|
116
|
+
* § Git 跟踪策略. Rule
|
|
98
117
|
* (chosen alignment): the gate passes when the repo's .gitignore holds ONE
|
|
99
118
|
* complete set for the DETECTED harness kind — `.mstar/` for a `.mstar`
|
|
100
119
|
* harness, `.agents/` for a legacy `.agents` harness; layouts without a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mstar-harness/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.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": {
|