@mstar-harness/dsh 3.1.1 → 3.1.3
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 +2 -2
- package/README.zh.md +2 -2
- package/dist/gates/_shared.d.ts +4 -2
- package/dist/gates/status.d.ts +7 -1
- package/dist/gates/workflow-selection.d.ts +7 -0
- package/dist/index.js +248 -176
- package/harness-commands/iteration-drive.md +9 -90
- package/harness-commands/iteration-loop.md +22 -62
- package/harness-commands/iteration-start.md +20 -77
- package/harness-skills/mstar-audit/SKILL.md +2 -2
- package/harness-skills/mstar-compound-refresh/SKILL.md +1 -1
- package/harness-skills/mstar-dispatch-gates/SKILL.md +1 -1
- package/harness-skills/mstar-harness-core/SKILL.md +4 -3
- package/harness-skills/mstar-iteration/SKILL.md +16 -10
- package/harness-skills/mstar-iteration/references/command-shared-invariants.md +62 -0
- package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +3 -3
- package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +1 -1
- package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +1 -1
- package/harness-skills/mstar-phase-gates/SKILL.md +1 -1
- package/harness-skills/mstar-plan-artifacts/references/knowledge-and-designs.md +2 -2
- package/harness-skills/mstar-plan-artifacts/references/status-and-residuals.md +1 -1
- package/harness-skills/mstar-plan-conventions/SKILL.md +1 -1
- package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +11 -1
- package/harness-skills/mstar-roles/references/architect.md +4 -7
- package/harness-skills/mstar-roles/references/code-reviewer.md +1 -4
- package/harness-skills/mstar-roles/references/frontend-dev.md +2 -4
- package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +2 -4
- package/harness-skills/mstar-roles/references/ops-engineer.md +2 -6
- package/harness-skills/mstar-roles/references/product-manager.md +4 -7
- package/harness-skills/mstar-roles/references/prompt-engineer.md +2 -5
- package/harness-skills/mstar-roles/references/qa-engineer.md +2 -6
- package/harness-skills/mstar-roles/references/qc-specialist-shared.md +1 -4
- package/harness-skills/mstar-roles/references/writing-specialist.md +2 -5
- package/harness-skills/mstar-strategy/SKILL.md +5 -35
- package/package.json +15 -15
package/dist/index.js
CHANGED
|
@@ -1106,7 +1106,7 @@ var require_lib2 = __commonJS((exports, module) => {
|
|
|
1106
1106
|
});
|
|
1107
1107
|
|
|
1108
1108
|
// src/index.ts
|
|
1109
|
-
import { existsSync as
|
|
1109
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18, readdirSync as readdirSync14 } from "node:fs";
|
|
1110
1110
|
import { join as join23 } from "node:path";
|
|
1111
1111
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1112
1112
|
import {
|
|
@@ -1122,23 +1122,23 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
1122
1122
|
import { fileURLToPath } from "node:url";
|
|
1123
1123
|
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
1124
1124
|
import { dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "node:path";
|
|
1125
|
-
import { mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
|
|
1125
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, realpathSync, statSync as statSync2 } from "node:fs";
|
|
1126
1126
|
import { execFileSync } from "node:child_process";
|
|
1127
1127
|
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve as resolve3 } from "node:path";
|
|
1128
|
-
import { existsSync as
|
|
1128
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, readdirSync as readdirSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
1129
1129
|
import { dirname as dirname5, join as join6, resolve as resolve5, sep } from "node:path";
|
|
1130
1130
|
import { dirname as dirname4, isAbsolute as isAbsolute3, join as join4, resolve as resolve4 } from "node:path";
|
|
1131
1131
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1132
1132
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
1133
|
-
import { existsSync as
|
|
1133
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
1134
1134
|
import { isAbsolute as isAbsolute4, resolve as resolve6 } from "node:path";
|
|
1135
1135
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1136
|
-
import { mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync5, realpathSync as
|
|
1136
|
+
import { mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync5, realpathSync as realpathSync3, statSync as statSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1137
1137
|
import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute5, join as join7, resolve as resolve7 } from "node:path";
|
|
1138
|
-
import { existsSync as
|
|
1139
|
-
import { existsSync as
|
|
1140
|
-
import { basename as
|
|
1141
|
-
import { existsSync as
|
|
1138
|
+
import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "node:fs";
|
|
1139
|
+
import { existsSync as existsSync8, readdirSync as readdirSync8, readFileSync as readFileSync10 } from "node:fs";
|
|
1140
|
+
import { basename as basename5, isAbsolute as isAbsolute7, join as join12, relative as relative4, resolve as resolve10, sep as sep4 } from "node:path";
|
|
1141
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
1142
1142
|
import { join as join13 } from "node:path";
|
|
1143
1143
|
var SEVERITY_ORDER = ["critical", "high", "medium", "low", "nit"];
|
|
1144
1144
|
function applyEnforcement(gate, opts) {
|
|
@@ -1681,10 +1681,8 @@ function composeDispatchGate(text, opts = {}) {
|
|
|
1681
1681
|
const violations = [];
|
|
1682
1682
|
const writable = opts.writable !== false;
|
|
1683
1683
|
violations.push(...validateAssignmentFields(text, { writable }).violations);
|
|
1684
|
-
const agent =
|
|
1685
|
-
|
|
1686
|
-
violations.push(...antiRecursionPrecheck(agent, parseAssignmentFields(text).executeAs ?? "").violations);
|
|
1687
|
-
}
|
|
1684
|
+
const agent = opts.agent ?? "";
|
|
1685
|
+
violations.push(...antiRecursionPrecheck(agent, parseAssignmentFields(text).executeAs ?? "").violations);
|
|
1688
1686
|
if (writable) {
|
|
1689
1687
|
const forms = parseAssignmentBranchForms(text);
|
|
1690
1688
|
const branch = forms.createForm?.name ?? forms.workingBranch ?? forms.directOn?.branch ?? process.env.MSTAR_WORKING_BRANCH;
|
|
@@ -1703,7 +1701,15 @@ function composeDispatchGate(text, opts = {}) {
|
|
|
1703
1701
|
function antiRecursionPrecheck(subagentType, executeAs) {
|
|
1704
1702
|
const binding = subagentType.trim().toLowerCase();
|
|
1705
1703
|
const role = executeAs.trim().toLowerCase();
|
|
1706
|
-
if (binding
|
|
1704
|
+
if (binding === "") {
|
|
1705
|
+
return {
|
|
1706
|
+
ok: false,
|
|
1707
|
+
violations: [
|
|
1708
|
+
violation2("critical", "dispatch.anti-recursion.empty-binding", `empty host role binding — the host cannot report which agent is calling, so anti-recursion cannot be proven (a dispatch could silently recurse)`, "set the host role-binding field (omp task entry `agent` / opencode `subagent` / cursor `subagent_type` / dsh `dispatchBinding`) before dispatching")
|
|
1709
|
+
]
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
if (binding === role) {
|
|
1707
1713
|
return {
|
|
1708
1714
|
ok: false,
|
|
1709
1715
|
violations: [
|
|
@@ -2041,7 +2047,7 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
2041
2047
|
if (harnessDir !== undefined && Array.isArray(doc.workflows)) {
|
|
2042
2048
|
let realHarnessDir = null;
|
|
2043
2049
|
try {
|
|
2044
|
-
realHarnessDir =
|
|
2050
|
+
realHarnessDir = realpathSync2(harnessDir);
|
|
2045
2051
|
} catch {}
|
|
2046
2052
|
for (const entry of doc.workflows) {
|
|
2047
2053
|
if (!isPlainObject3(entry) || typeof entry.dir !== "string")
|
|
@@ -2051,7 +2057,7 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
2051
2057
|
const label = typeof entry.id === "string" ? entry.id : relSnapshot;
|
|
2052
2058
|
let physical;
|
|
2053
2059
|
try {
|
|
2054
|
-
physical =
|
|
2060
|
+
physical = realpathSync2(snapshotPath);
|
|
2055
2061
|
} catch {
|
|
2056
2062
|
violations.push(violation4("high", "status.workflow.snapshot-missing", `workflows[] lists ${JSON.stringify(label)} but its snapshot does not exist at ${JSON.stringify(relSnapshot)} — the root holds active lifecycles only; unregister the id when its snapshot is removed`));
|
|
2057
2063
|
continue;
|
|
@@ -2074,7 +2080,7 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
2074
2080
|
violations.push(violation4("medium", "status.workflow.mismatched-type", `workflows[] entry ${JSON.stringify(label)} type ${JSON.stringify(entry.type)} does not match its snapshot type ${JSON.stringify(snapshot.type)} — the root entry mirrors the snapshot; align them`));
|
|
2075
2081
|
}
|
|
2076
2082
|
if (typeof entry.started_at === "string" && typeof snapshot.started_at === "string" && entry.started_at !== snapshot.started_at) {
|
|
2077
|
-
violations.push(violation4("medium", "status.workflow.mismatched-started-at", `workflows[] entry ${JSON.stringify(label)} started_at ${JSON.stringify(entry.started_at)} does not match its snapshot started_at ${JSON.stringify(snapshot.started_at)} — the root entry mirrors the snapshot
|
|
2083
|
+
violations.push(violation4("medium", "status.workflow.mismatched-started-at", `workflows[] entry ${JSON.stringify(label)} started_at ${JSON.stringify(entry.started_at)} does not match its snapshot started_at ${JSON.stringify(snapshot.started_at)} — workflow ${JSON.stringify(label)} collided with another writer (e.g. a concurrent/re-run \`audit promote\` with the same workflow id rewrote the snapshot); the root entry mirrors the snapshot — align them or remove the colliding workflow`));
|
|
2078
2084
|
}
|
|
2079
2085
|
}
|
|
2080
2086
|
}
|
|
@@ -2083,7 +2089,7 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
2083
2089
|
var validateStatus = validateStatusV2;
|
|
2084
2090
|
function resolveCompassEnforcement(harnessDir) {
|
|
2085
2091
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
2086
|
-
if (!
|
|
2092
|
+
if (!existsSync3(iterationsDir))
|
|
2087
2093
|
return { hard: false, source: "none" };
|
|
2088
2094
|
let entries;
|
|
2089
2095
|
try {
|
|
@@ -2095,7 +2101,7 @@ function resolveCompassEnforcement(harnessDir) {
|
|
|
2095
2101
|
if (!entry.isDirectory())
|
|
2096
2102
|
continue;
|
|
2097
2103
|
const compassPath = join6(iterationsDir, entry.name, "delivery-compass.md");
|
|
2098
|
-
if (!
|
|
2104
|
+
if (!existsSync3(compassPath))
|
|
2099
2105
|
continue;
|
|
2100
2106
|
let content;
|
|
2101
2107
|
try {
|
|
@@ -2182,7 +2188,7 @@ function l1PreDispatchCheck(input, opts = {}) {
|
|
|
2182
2188
|
if (controlWorktreePath !== "" && leaseWorktreePath !== "" && resolve6(controlWorktreePath) === resolve6(leaseWorktreePath)) {
|
|
2183
2189
|
violations.push(violation5("critical", "worktree.l1.lease-equals-control", `execution_lease.worktree_path "${leaseWorktreePath}" equals metadata.control_worktree_path — the feature worktree MUST differ from the control worktree (L1 isolation; product edits never land in the control checkout)`, "use a distinct feature worktree for the plan (git worktree add <path> <branch>) and update the lease"));
|
|
2184
2190
|
}
|
|
2185
|
-
if (leaseWorktreePath !== "" && !
|
|
2191
|
+
if (leaseWorktreePath !== "" && !existsSync4(leaseWorktreePath)) {
|
|
2186
2192
|
violations.push(violation5("high", "worktree.l1.feature-missing", `feature worktree directory "${leaseWorktreePath}" does not exist for plan "${planId}"`, `create it before dispatch: git worktree add ${leaseWorktreePath} <working-branch>`));
|
|
2187
2193
|
} else if (leaseWorktreePath !== "" && leaseWorkingBranch !== "") {
|
|
2188
2194
|
const probe = probeBranch(leaseWorktreePath, opts);
|
|
@@ -2216,7 +2222,7 @@ function l2PreDispatchCheck(input, opts = {}) {
|
|
|
2216
2222
|
return;
|
|
2217
2223
|
}
|
|
2218
2224
|
seenPaths.add(normalized);
|
|
2219
|
-
if (!
|
|
2225
|
+
if (!existsSync4(track.worktreePath)) {
|
|
2220
2226
|
violations.push(violation5("high", "worktree.l2.track-missing", `track worktree directory "${track.worktreePath}" does not exist`, `create it before dispatch: git worktree add ${track.worktreePath} ${track.workingBranch}`));
|
|
2221
2227
|
return;
|
|
2222
2228
|
}
|
|
@@ -2304,8 +2310,8 @@ function isLinkedWorktree(root) {
|
|
|
2304
2310
|
if (gitDir.includes("/.git/worktrees/") || gitDir.includes("/worktrees/"))
|
|
2305
2311
|
return true;
|
|
2306
2312
|
try {
|
|
2307
|
-
const gdParent =
|
|
2308
|
-
const cmAbs =
|
|
2313
|
+
const gdParent = realpathSync3(dirname6(gitDir));
|
|
2314
|
+
const cmAbs = realpathSync3(common);
|
|
2309
2315
|
return join7(gdParent, basename3(gitDir)) !== cmAbs && gitDir !== cmAbs;
|
|
2310
2316
|
} catch {
|
|
2311
2317
|
return false;
|
|
@@ -2323,10 +2329,10 @@ function sddWorkspace(planId, opts = {}) {
|
|
|
2323
2329
|
if (!isDirectory2(controlRoot)) {
|
|
2324
2330
|
throw new SddScriptError(`mstar sdd workspace: CONTROL_ROOT / MSTAR_CONTROL_ROOT is not a directory: ${controlRoot}`, 1);
|
|
2325
2331
|
}
|
|
2326
|
-
root =
|
|
2332
|
+
root = realpathSync3(controlRoot);
|
|
2327
2333
|
} else {
|
|
2328
2334
|
const topLevel = gitOut(cwd, ["rev-parse", "--show-toplevel"]);
|
|
2329
|
-
root =
|
|
2335
|
+
root = realpathSync3(topLevel ?? cwd);
|
|
2330
2336
|
}
|
|
2331
2337
|
if (!controlRoot && isLinkedWorktree(root)) {
|
|
2332
2338
|
throw new SddScriptError(`mstar sdd workspace: linked worktree at ${root} has no {HARNESS_DIR}/status.json (default gitignore).
|
|
@@ -2360,7 +2366,7 @@ function sddWorkspace(planId, opts = {}) {
|
|
|
2360
2366
|
mkdirSync5(sddDir, { recursive: true });
|
|
2361
2367
|
writeFileSync3(join7(sddDir, ".gitignore"), `*
|
|
2362
2368
|
`);
|
|
2363
|
-
return
|
|
2369
|
+
return realpathSync3(sddDir);
|
|
2364
2370
|
}
|
|
2365
2371
|
function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
2366
2372
|
if (!planFile || !Number.isInteger(taskN) || taskN < 1) {
|
|
@@ -3238,74 +3244,6 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3238
3244
|
});
|
|
3239
3245
|
return { ok: violations.length === 0, violations };
|
|
3240
3246
|
}
|
|
3241
|
-
var WHOLE_MATCH_PATTERNS = [
|
|
3242
|
-
{ type: "private-key", re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/g },
|
|
3243
|
-
{ type: "aws-access-key", re: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
3244
|
-
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
3245
|
-
{ type: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
3246
|
-
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\b/g },
|
|
3247
|
-
{ type: "api-secret-key", re: /\bsk-[A-Za-z0-9-]{20,}\b/g }
|
|
3248
|
-
];
|
|
3249
|
-
var VALUE_PATTERNS = [
|
|
3250
|
-
{
|
|
3251
|
-
typeOf: (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_-]+/g, "-"),
|
|
3252
|
-
re: /(["']?)\b(password|passwd|api[_-]?key|access[_-]?token|auth[_-]?token|secret|token)\b(["']?)(\s*[:=]\s*)("[^"\n]{8,}"|'[^'\n]{8,}'|[A-Za-z0-9_./+\-=]{16,})/gi
|
|
3253
|
-
}
|
|
3254
|
-
];
|
|
3255
|
-
function buildLineStarts(text) {
|
|
3256
|
-
const starts = [0];
|
|
3257
|
-
for (let i = 0;i < text.length; i++) {
|
|
3258
|
-
if (text[i] === `
|
|
3259
|
-
`)
|
|
3260
|
-
starts.push(i + 1);
|
|
3261
|
-
}
|
|
3262
|
-
return starts;
|
|
3263
|
-
}
|
|
3264
|
-
function lineAt(starts, index) {
|
|
3265
|
-
let lo = 0;
|
|
3266
|
-
let hi = starts.length - 1;
|
|
3267
|
-
while (lo < hi) {
|
|
3268
|
-
const mid = lo + hi + 1 >> 1;
|
|
3269
|
-
if (starts[mid] <= index)
|
|
3270
|
-
lo = mid;
|
|
3271
|
-
else
|
|
3272
|
-
hi = mid - 1;
|
|
3273
|
-
}
|
|
3274
|
-
return lo + 1;
|
|
3275
|
-
}
|
|
3276
|
-
function redactSecrets(text, filePath) {
|
|
3277
|
-
const starts = buildLineStarts(text);
|
|
3278
|
-
const marker = (type, index) => `[REDACTED ${type}@${lineAt(starts, index)}${filePath === undefined ? "" : ` in ${filePath}`}]`;
|
|
3279
|
-
const replacements = [];
|
|
3280
|
-
const findings = [];
|
|
3281
|
-
for (const pattern of WHOLE_MATCH_PATTERNS) {
|
|
3282
|
-
for (const match of text.matchAll(pattern.re)) {
|
|
3283
|
-
if (match.index === undefined)
|
|
3284
|
-
continue;
|
|
3285
|
-
replacements.push({ index: match.index, length: match[0].length, text: marker(pattern.type, match.index) });
|
|
3286
|
-
findings.push({ line: lineAt(starts, match.index), type: pattern.type });
|
|
3287
|
-
}
|
|
3288
|
-
}
|
|
3289
|
-
for (const pattern of VALUE_PATTERNS) {
|
|
3290
|
-
for (const match of text.matchAll(pattern.re)) {
|
|
3291
|
-
if (match.index === undefined)
|
|
3292
|
-
continue;
|
|
3293
|
-
const type = pattern.typeOf(match[2]);
|
|
3294
|
-
const replacement = `${match[1]}${match[2]}${match[3]}${match[4]}${marker(type, match.index)}`;
|
|
3295
|
-
replacements.push({ index: match.index, length: match[0].length, text: replacement });
|
|
3296
|
-
findings.push({ line: lineAt(starts, match.index), type });
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
replacements.sort((a, b) => b.index - a.index);
|
|
3300
|
-
let out = text;
|
|
3301
|
-
for (const r of replacements)
|
|
3302
|
-
out = out.slice(0, r.index) + r.text + out.slice(r.index + r.length);
|
|
3303
|
-
const deduped = new Map;
|
|
3304
|
-
for (const f of findings)
|
|
3305
|
-
deduped.set(`${f.line}:${f.type}`, f);
|
|
3306
|
-
const sorted = [...deduped.values()].sort((a, b) => a.line - b.line || a.type.localeCompare(b.type));
|
|
3307
|
-
return { text: out, findings: sorted };
|
|
3308
|
-
}
|
|
3309
3247
|
function violation10(severity, code, message, fix) {
|
|
3310
3248
|
return { ok: false, severity, code, message, fix };
|
|
3311
3249
|
}
|
|
@@ -3600,7 +3538,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
3600
3538
|
for (const { ref, isSymbol, module } of refs) {
|
|
3601
3539
|
if (!isSymbol || module === undefined) {
|
|
3602
3540
|
const candidate = ref.replace(LINE_SUFFIX_RE, "").replace(ANCHOR_RE, "");
|
|
3603
|
-
if (
|
|
3541
|
+
if (existsSync8(resolve10(repoRoot, candidate))) {
|
|
3604
3542
|
checked++;
|
|
3605
3543
|
} else {
|
|
3606
3544
|
violations.push(violation10("medium", "compound.reference.missing-file", `referenced path \`${ref}\` does not exist under ${repoRoot} (compound-refresh Phase 2: referenced code still exists?)`, "update the doc to reference an existing path, or delete the stale reference"));
|
|
@@ -3631,7 +3569,7 @@ function collectKnowledgeDocs(dir) {
|
|
|
3631
3569
|
if (entry.isDirectory()) {
|
|
3632
3570
|
stack.push(full);
|
|
3633
3571
|
} else if (entry.name.endsWith(".md") && entry.name !== "README.md" && entry.name !== "index.md") {
|
|
3634
|
-
docs.push(relative4(dir, full).split(
|
|
3572
|
+
docs.push(relative4(dir, full).split(sep4).join("/"));
|
|
3635
3573
|
}
|
|
3636
3574
|
}
|
|
3637
3575
|
}
|
|
@@ -3648,7 +3586,7 @@ function normalizeIndexRef(cell) {
|
|
|
3648
3586
|
function assertIndexRows(knowledgeDir) {
|
|
3649
3587
|
const violations = [];
|
|
3650
3588
|
const readmePath = join12(knowledgeDir, "README.md");
|
|
3651
|
-
if (!
|
|
3589
|
+
if (!existsSync8(readmePath)) {
|
|
3652
3590
|
violations.push(violation10("medium", "compound.index.missing-readme", `missing ${readmePath} — the knowledge index is required (mstar-compound Phase 6: every doc gets a README.md row)`, "create knowledge/README.md with a Document / Source Plan / Description / Status table"));
|
|
3653
3591
|
return { ok: false, violations };
|
|
3654
3592
|
}
|
|
@@ -3672,7 +3610,7 @@ function assertIndexRows(knowledgeDir) {
|
|
|
3672
3610
|
return { ok: violations.length === 0, violations };
|
|
3673
3611
|
}
|
|
3674
3612
|
function isFileLikeRoot(root) {
|
|
3675
|
-
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(
|
|
3613
|
+
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(basename5(root));
|
|
3676
3614
|
}
|
|
3677
3615
|
function scopeGuard(path, allowedRoots) {
|
|
3678
3616
|
const resolved = resolve10(path);
|
|
@@ -3681,7 +3619,7 @@ function scopeGuard(path, allowedRoots) {
|
|
|
3681
3619
|
if (isFileLikeRoot(r)) {
|
|
3682
3620
|
if (resolved === r)
|
|
3683
3621
|
return { ok: true, violations: [] };
|
|
3684
|
-
} else if (resolved === r || resolved.startsWith(r +
|
|
3622
|
+
} else if (resolved === r || resolved.startsWith(r + sep4)) {
|
|
3685
3623
|
return { ok: true, violations: [] };
|
|
3686
3624
|
}
|
|
3687
3625
|
}
|
|
@@ -3835,7 +3773,7 @@ function validateRoleMapping(rolesDir, options = {}) {
|
|
|
3835
3773
|
const violations = [];
|
|
3836
3774
|
const referenceById = new Map(mapping.map((m) => [m.agentId, m.reference]));
|
|
3837
3775
|
for (const { agentId, reference } of mapping) {
|
|
3838
|
-
if (!
|
|
3776
|
+
if (!existsSync9(join13(rolesDir, reference))) {
|
|
3839
3777
|
violations.push(violation12("medium", "roles.mapping.reference.missing", `role "${agentId}" maps to ${reference} which does not exist under ${rolesDir} (mstar-roles § Role Reference Mapping)`, `create ${join13(rolesDir, reference)} or fix the mapping row`));
|
|
3840
3778
|
}
|
|
3841
3779
|
}
|
|
@@ -4046,7 +3984,7 @@ class DshMstar extends Service {
|
|
|
4046
3984
|
|
|
4047
3985
|
// src/gates/_shared.ts
|
|
4048
3986
|
var import_schemastery = __toESM(require_lib2(), 1);
|
|
4049
|
-
import { existsSync as
|
|
3987
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
4050
3988
|
import { resolve as resolve8 } from "node:path";
|
|
4051
3989
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4052
3990
|
var STATUS_FILE = "status.json";
|
|
@@ -4101,7 +4039,7 @@ function resolvePackagedSkillsDir(fileUrl) {
|
|
|
4101
4039
|
for (const rel of ["../harness-skills", "../../harness-skills"]) {
|
|
4102
4040
|
try {
|
|
4103
4041
|
const dir = fileURLToPath2(new URL(rel, fileUrl));
|
|
4104
|
-
if (
|
|
4042
|
+
if (existsSync6(dir))
|
|
4105
4043
|
return dir;
|
|
4106
4044
|
} catch {}
|
|
4107
4045
|
}
|
|
@@ -4120,7 +4058,7 @@ function resolvePackagedAgentsDir(fileUrl) {
|
|
|
4120
4058
|
for (const rel of ["../harness-agents", "../../harness-agents"]) {
|
|
4121
4059
|
try {
|
|
4122
4060
|
const dir = fileURLToPath2(new URL(rel, fileUrl));
|
|
4123
|
-
if (
|
|
4061
|
+
if (existsSync6(dir))
|
|
4124
4062
|
return dir;
|
|
4125
4063
|
} catch {}
|
|
4126
4064
|
}
|
|
@@ -4188,21 +4126,21 @@ function skillLocalConfig(config) {
|
|
|
4188
4126
|
}
|
|
4189
4127
|
|
|
4190
4128
|
// src/gates/catalog.ts
|
|
4191
|
-
import { existsSync as
|
|
4129
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9, readdirSync as readdirSync7 } from "node:fs";
|
|
4192
4130
|
import { join as join11 } from "node:path";
|
|
4193
4131
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
4194
4132
|
|
|
4195
4133
|
// src/gates/agent-flow.ts
|
|
4196
|
-
import { appendFileSync, closeSync, existsSync as
|
|
4134
|
+
import { appendFileSync, closeSync, existsSync as existsSync13, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync7, readSync, renameSync as renameSync2, rmdirSync, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4197
4135
|
import { join as join10 } from "node:path";
|
|
4198
4136
|
|
|
4199
4137
|
// src/gates/dispatch.ts
|
|
4200
|
-
import { existsSync as
|
|
4201
|
-
import { basename as
|
|
4138
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
4139
|
+
import { basename as basename4, join as join8, resolve as resolve11 } from "node:path";
|
|
4202
4140
|
|
|
4203
4141
|
// src/gates/workflow-selection.ts
|
|
4204
|
-
import { existsSync as
|
|
4205
|
-
import { join as join5, relative as relative3 } from "node:path";
|
|
4142
|
+
import { existsSync as existsSync10, readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
|
|
4143
|
+
import { dirname as dirname7, join as join5, relative as relative3 } from "node:path";
|
|
4206
4144
|
var TERMINAL_STATUS_CACHE_MAX = 64;
|
|
4207
4145
|
var terminalStatusCache = new Map;
|
|
4208
4146
|
function terminalStatusOf(snapshotPath) {
|
|
@@ -4210,6 +4148,7 @@ function terminalStatusOf(snapshotPath) {
|
|
|
4210
4148
|
try {
|
|
4211
4149
|
mtimeMs = statSync3(snapshotPath).mtimeMs;
|
|
4212
4150
|
} catch {
|
|
4151
|
+
terminalStatusCache.delete(snapshotPath);
|
|
4213
4152
|
return;
|
|
4214
4153
|
}
|
|
4215
4154
|
const cached = terminalStatusCache.get(snapshotPath);
|
|
@@ -4235,7 +4174,7 @@ function terminalStatusOf(snapshotPath) {
|
|
|
4235
4174
|
}
|
|
4236
4175
|
function resolveActiveWorkflow(harnessDir) {
|
|
4237
4176
|
const statusPath = join5(harnessDir, STATUS_FILE);
|
|
4238
|
-
if (!
|
|
4177
|
+
if (!existsSync10(statusPath)) {
|
|
4239
4178
|
return {
|
|
4240
4179
|
kind: "error",
|
|
4241
4180
|
code: "status.missing",
|
|
@@ -4293,7 +4232,7 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4293
4232
|
if (active.kind === "error" && active.code !== "workflow.selection.no-active")
|
|
4294
4233
|
return active;
|
|
4295
4234
|
const workflowsDir = resolveWorkflowDir(harnessDir, { harnessDir });
|
|
4296
|
-
if (!
|
|
4235
|
+
if (!existsSync10(workflowsDir)) {
|
|
4297
4236
|
return {
|
|
4298
4237
|
kind: "error",
|
|
4299
4238
|
code: "workflow.selection.no-snapshot",
|
|
@@ -4315,8 +4254,10 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4315
4254
|
if (!entry.isDirectory())
|
|
4316
4255
|
continue;
|
|
4317
4256
|
const snapshotPath = join5(workflowsDir, entry.name, WORKFLOW_SNAPSHOT_FILE);
|
|
4318
|
-
if (!
|
|
4257
|
+
if (!existsSync10(snapshotPath)) {
|
|
4258
|
+
terminalStatusCache.delete(snapshotPath);
|
|
4319
4259
|
continue;
|
|
4260
|
+
}
|
|
4320
4261
|
const verdict = terminalStatusOf(snapshotPath);
|
|
4321
4262
|
if (verdict === undefined || !verdict.terminal)
|
|
4322
4263
|
continue;
|
|
@@ -4324,6 +4265,11 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4324
4265
|
best = { workflowId: entry.name, dir: join5(relative3(harnessDir, workflowsDir), entry.name), mtimeMs: verdict.mtimeMs };
|
|
4325
4266
|
}
|
|
4326
4267
|
}
|
|
4268
|
+
for (const cachedPath of terminalStatusCache.keys()) {
|
|
4269
|
+
if (!existsSync10(join5(dirname7(cachedPath), WORKFLOW_SNAPSHOT_FILE))) {
|
|
4270
|
+
terminalStatusCache.delete(cachedPath);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4327
4273
|
if (best === undefined) {
|
|
4328
4274
|
return {
|
|
4329
4275
|
kind: "error",
|
|
@@ -4483,12 +4429,12 @@ function isNaValue(value) {
|
|
|
4483
4429
|
function planIdOf(headerRegion) {
|
|
4484
4430
|
const planPath = assignmentHeaderValue(headerRegion, "Plan Path");
|
|
4485
4431
|
if (!isNaValue(planPath)) {
|
|
4486
|
-
const id =
|
|
4432
|
+
const id = basename4(firstToken(planPath) ?? "");
|
|
4487
4433
|
return id.endsWith(".md") ? id.slice(0, -3) : id;
|
|
4488
4434
|
}
|
|
4489
4435
|
const sddDir = assignmentHeaderValue(headerRegion, "SDD dir");
|
|
4490
4436
|
if (!isNaValue(sddDir)) {
|
|
4491
|
-
const id =
|
|
4437
|
+
const id = basename4(firstToken(sddDir) ?? "");
|
|
4492
4438
|
return id === "" ? undefined : id;
|
|
4493
4439
|
}
|
|
4494
4440
|
const planId = assignmentHeaderValue(headerRegion, "plan_id");
|
|
@@ -4518,7 +4464,7 @@ function leaseGateViolations(harnessDir, exec, writable, prompt) {
|
|
|
4518
4464
|
return [leaseViolation("lease.dispatch.unverifiable", `${join8(harnessDir, STATUS_FILE)}: ${selection.kind === "error" ? selection.message : "no active workflow"} — the plan's execution_lease state is unverifiable; STOP before writable dispatch`, "create a valid v2 status.json registering an active workflow (first implement dispatch requires a plan row + lease)")];
|
|
4519
4465
|
}
|
|
4520
4466
|
const snapshotPath = join8(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
4521
|
-
if (!
|
|
4467
|
+
if (!existsSync12(snapshotPath)) {
|
|
4522
4468
|
if (!sdd)
|
|
4523
4469
|
return [];
|
|
4524
4470
|
return [leaseViolation("lease.dispatch.unverifiable", `${snapshotPath} is missing — the plan's execution_lease state is unverifiable; STOP before writable dispatch`, "create a valid workflow snapshot registering the plan row (first implement dispatch requires a plan row)")];
|
|
@@ -4592,7 +4538,7 @@ function worktreeL2Violations(header) {
|
|
|
4592
4538
|
return violations;
|
|
4593
4539
|
}
|
|
4594
4540
|
function activeSnapshotRows(harnessDir) {
|
|
4595
|
-
if (!
|
|
4541
|
+
if (!existsSync12(join8(harnessDir, STATUS_FILE)))
|
|
4596
4542
|
return { rows: null, controlWorktreePath: undefined, unreadable: false };
|
|
4597
4543
|
const selection = resolveActiveWorkflow(harnessDir);
|
|
4598
4544
|
if (selection.kind !== "active") {
|
|
@@ -4603,7 +4549,7 @@ function activeSnapshotRows(harnessDir) {
|
|
|
4603
4549
|
};
|
|
4604
4550
|
}
|
|
4605
4551
|
const snapshotPath = join8(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
4606
|
-
if (!
|
|
4552
|
+
if (!existsSync12(snapshotPath))
|
|
4607
4553
|
return { rows: null, controlWorktreePath: undefined, unreadable: true };
|
|
4608
4554
|
let doc;
|
|
4609
4555
|
try {
|
|
@@ -5333,7 +5279,7 @@ function ledgerContent(file, n) {
|
|
|
5333
5279
|
}
|
|
5334
5280
|
function readAgentFlow(workflowDir, limit) {
|
|
5335
5281
|
const file = join10(workflowDir, AGENT_FLOW_FILE);
|
|
5336
|
-
if (!
|
|
5282
|
+
if (!existsSync13(file)) {
|
|
5337
5283
|
return { events: [], summary: [] };
|
|
5338
5284
|
}
|
|
5339
5285
|
const n = limit === undefined ? AGENT_FLOW_DEFAULT_LIMIT : Math.max(0, Math.floor(limit));
|
|
@@ -5588,7 +5534,7 @@ function harnessStateSource(harnessDir) {
|
|
|
5588
5534
|
if (harnessDir === null)
|
|
5589
5535
|
return null;
|
|
5590
5536
|
const statusPath = join11(harnessDir, STATUS_FILE);
|
|
5591
|
-
if (!
|
|
5537
|
+
if (!existsSync14(statusPath))
|
|
5592
5538
|
return null;
|
|
5593
5539
|
try {
|
|
5594
5540
|
const selection = resolveReadWorkflow(harnessDir);
|
|
@@ -5609,7 +5555,7 @@ function harnessStateSource(harnessDir) {
|
|
|
5609
5555
|
}
|
|
5610
5556
|
const snapshotPath = join11(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
5611
5557
|
let snapshot;
|
|
5612
|
-
if (!
|
|
5558
|
+
if (!existsSync14(snapshotPath)) {
|
|
5613
5559
|
return selectionErrorState({
|
|
5614
5560
|
kind: "error",
|
|
5615
5561
|
code: "workflow.selection.snapshot-unreadable",
|
|
@@ -5701,7 +5647,7 @@ function selectionErrorState(selection, rollup, harnessDir, compass) {
|
|
|
5701
5647
|
function projectRollupSource(harnessDir, residuals) {
|
|
5702
5648
|
const milestones = [];
|
|
5703
5649
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5704
|
-
if (
|
|
5650
|
+
if (existsSync14(projectsDir)) {
|
|
5705
5651
|
let entries;
|
|
5706
5652
|
try {
|
|
5707
5653
|
entries = readdirSync7(projectsDir, { withFileTypes: true });
|
|
@@ -5712,7 +5658,7 @@ function projectRollupSource(harnessDir, residuals) {
|
|
|
5712
5658
|
if (!entry.isDirectory())
|
|
5713
5659
|
continue;
|
|
5714
5660
|
const roadmapPath = join11(projectsDir, entry.name, PROJECT_ROADMAP_FILE);
|
|
5715
|
-
if (!
|
|
5661
|
+
if (!existsSync14(roadmapPath))
|
|
5716
5662
|
continue;
|
|
5717
5663
|
try {
|
|
5718
5664
|
const doc = parseCompassFrontmatterText(readFileSync9(roadmapPath, "utf8"), roadmapPath);
|
|
@@ -5777,7 +5723,7 @@ function residualRollup(harnessDir) {
|
|
|
5777
5723
|
}
|
|
5778
5724
|
function projectRegisters(harnessDir) {
|
|
5779
5725
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5780
|
-
if (!
|
|
5726
|
+
if (!existsSync14(projectsDir))
|
|
5781
5727
|
return [];
|
|
5782
5728
|
let entries;
|
|
5783
5729
|
try {
|
|
@@ -5790,7 +5736,7 @@ function projectRegisters(harnessDir) {
|
|
|
5790
5736
|
if (!entry.isDirectory())
|
|
5791
5737
|
continue;
|
|
5792
5738
|
const registerPath = join11(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
5793
|
-
if (!
|
|
5739
|
+
if (!existsSync14(registerPath))
|
|
5794
5740
|
continue;
|
|
5795
5741
|
try {
|
|
5796
5742
|
registers.push({ projectId: entry.name, doc: readJson(registerPath) });
|
|
@@ -5802,7 +5748,7 @@ function projectRegisters(harnessDir) {
|
|
|
5802
5748
|
}
|
|
5803
5749
|
function knowledgeDigest(harnessDir) {
|
|
5804
5750
|
const indexPath = join11(harnessDir, "knowledge", "README.md");
|
|
5805
|
-
if (!
|
|
5751
|
+
if (!existsSync14(indexPath))
|
|
5806
5752
|
return null;
|
|
5807
5753
|
try {
|
|
5808
5754
|
const categories = new Set;
|
|
@@ -5847,7 +5793,7 @@ function compassDirection(compassPath) {
|
|
|
5847
5793
|
}
|
|
5848
5794
|
function steeringCompassPath(harnessDir) {
|
|
5849
5795
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
5850
|
-
if (!
|
|
5796
|
+
if (!existsSync14(iterationsDir))
|
|
5851
5797
|
return;
|
|
5852
5798
|
let entries;
|
|
5853
5799
|
try {
|
|
@@ -5859,7 +5805,7 @@ function steeringCompassPath(harnessDir) {
|
|
|
5859
5805
|
if (!entry.isDirectory())
|
|
5860
5806
|
continue;
|
|
5861
5807
|
const compassPath = join11(iterationsDir, entry.name, "delivery-compass.md");
|
|
5862
|
-
if (!
|
|
5808
|
+
if (!existsSync14(compassPath))
|
|
5863
5809
|
continue;
|
|
5864
5810
|
let content;
|
|
5865
5811
|
try {
|
|
@@ -5878,7 +5824,7 @@ function iterationGateSource(harnessDir) {
|
|
|
5878
5824
|
if (harnessDir === null)
|
|
5879
5825
|
return;
|
|
5880
5826
|
const statusPath = join11(harnessDir, STATUS_FILE);
|
|
5881
|
-
if (!
|
|
5827
|
+
if (!existsSync14(statusPath))
|
|
5882
5828
|
return;
|
|
5883
5829
|
const compass = steeringCompassPath(harnessDir);
|
|
5884
5830
|
if (compass === undefined)
|
|
@@ -5940,12 +5886,12 @@ function agentDigestKey(agent, cwd) {
|
|
|
5940
5886
|
}
|
|
5941
5887
|
|
|
5942
5888
|
// src/gates/status.ts
|
|
5943
|
-
import { existsSync as
|
|
5944
|
-
import { basename as
|
|
5889
|
+
import { existsSync as existsSync15, readdirSync as readdirSync9 } from "node:fs";
|
|
5890
|
+
import { basename as basename6, join as join14, relative as relative5, resolve as resolve13 } from "node:path";
|
|
5945
5891
|
var LOGGER_NAME = "mstar/status-gate";
|
|
5946
5892
|
function harnessDocKindOfTarget(harnessDir, targetPath) {
|
|
5947
5893
|
const resolved = resolve13(targetPath);
|
|
5948
|
-
const name =
|
|
5894
|
+
const name = basename6(resolved);
|
|
5949
5895
|
if (name !== STATUS_FILE && name !== WORKFLOW_SNAPSHOT_FILE && name !== PROJECT_REGISTER_FILE)
|
|
5950
5896
|
return null;
|
|
5951
5897
|
const rel = relative5(harnessDir, resolved);
|
|
@@ -6023,7 +5969,7 @@ function projectRegisterDocs(harnessDir) {
|
|
|
6023
5969
|
if (!entry.isDirectory())
|
|
6024
5970
|
continue;
|
|
6025
5971
|
const registerPath = join14(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
6026
|
-
if (!
|
|
5972
|
+
if (!existsSync15(registerPath))
|
|
6027
5973
|
continue;
|
|
6028
5974
|
try {
|
|
6029
5975
|
registers.push({ projectId: entry.name, doc: readJson(registerPath) });
|
|
@@ -6076,7 +6022,11 @@ ${verdict.violations.map(formatViolation).join(`
|
|
|
6076
6022
|
} catch (error) {
|
|
6077
6023
|
ctx.logger(LOGGER_NAME).error(`status gate degraded to allow: ${error.message}`);
|
|
6078
6024
|
try {
|
|
6079
|
-
|
|
6025
|
+
let hard = false;
|
|
6026
|
+
try {
|
|
6027
|
+
hard = harnessDir !== null && resolveHard(harnessDir, config);
|
|
6028
|
+
} catch {}
|
|
6029
|
+
ctx.emit("mstar/status-gate", { operation, target: target.displayPath, result: { ok: true, violations: [] }, hard, degraded: true });
|
|
6080
6030
|
} catch (emitError) {
|
|
6081
6031
|
ctx.logger(LOGGER_NAME).error(`status gate degraded advisory emit failed: ${emitError.message}`);
|
|
6082
6032
|
}
|
|
@@ -6092,8 +6042,8 @@ async function editIntentListener(ctx, resolver, config, adapter, target, actor,
|
|
|
6092
6042
|
}
|
|
6093
6043
|
|
|
6094
6044
|
// src/gates/skill-lint.ts
|
|
6095
|
-
import { existsSync as
|
|
6096
|
-
import { basename as
|
|
6045
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
|
|
6046
|
+
import { basename as basename7, dirname as dirname9, resolve as resolve14, sep as sep2 } from "node:path";
|
|
6097
6047
|
var SKILL_LINT_LOGGER = "mstar/skill-lint";
|
|
6098
6048
|
|
|
6099
6049
|
class SkillLintVetoError extends Error {
|
|
@@ -6154,13 +6104,13 @@ function skillRootsOf(config) {
|
|
|
6154
6104
|
return roots.map((root) => root.trim()).filter((root) => root !== "");
|
|
6155
6105
|
}
|
|
6156
6106
|
function isSkillTarget(roots, target) {
|
|
6157
|
-
if (
|
|
6107
|
+
if (basename7(target.displayPath) !== "SKILL.md")
|
|
6158
6108
|
return false;
|
|
6159
6109
|
const resolvedPath = resolve14(target.displayPath);
|
|
6160
6110
|
return roots.some((root) => resolvedPath.startsWith(resolve14(root) + sep2));
|
|
6161
6111
|
}
|
|
6162
6112
|
function skillNameOf(target) {
|
|
6163
|
-
return
|
|
6113
|
+
return basename7(dirname9(target.displayPath));
|
|
6164
6114
|
}
|
|
6165
6115
|
function skillCanonicalForm(target) {
|
|
6166
6116
|
return resolveSkillRoot("dsh", { skill: skillNameOf(target), rel: "SKILL.md" });
|
|
@@ -6173,7 +6123,7 @@ function gateSkillIntent(ctx, harnessDir, config, target) {
|
|
|
6173
6123
|
if (!isSkillTarget(roots, target))
|
|
6174
6124
|
return;
|
|
6175
6125
|
const skillPath = resolve14(target.displayPath);
|
|
6176
|
-
if (!
|
|
6126
|
+
if (!existsSync16(skillPath))
|
|
6177
6127
|
return;
|
|
6178
6128
|
let doc;
|
|
6179
6129
|
try {
|
|
@@ -6224,8 +6174,130 @@ async function skillWriteIntentListener(ctx, resolver, config, target, actor, ne
|
|
|
6224
6174
|
}
|
|
6225
6175
|
|
|
6226
6176
|
// src/gates/seams.ts
|
|
6227
|
-
import { existsSync as
|
|
6228
|
-
import { basename as
|
|
6177
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13, readdirSync as readdirSync11 } from "node:fs";
|
|
6178
|
+
import { basename as basename8, dirname as dirname10, join as join16, resolve as resolve15, sep as sep3 } from "node:path";
|
|
6179
|
+
|
|
6180
|
+
// ../engine/dist/audit.js
|
|
6181
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
6182
|
+
var DATE_PART2 = String.raw`\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])`;
|
|
6183
|
+
var RFC3339_Z_RE2 = new RegExp(String.raw`^${DATE_PART2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$`);
|
|
6184
|
+
var DATE_ONLY_RE2 = new RegExp(String.raw`^${DATE_PART2}$`);
|
|
6185
|
+
var heldLockDirs2 = new AsyncLocalStorage2;
|
|
6186
|
+
var MSTARC_HARNESS_DIR_KEY2 = "harness_dir";
|
|
6187
|
+
var MSTARC_PLAN_DIR_KEY2 = "plan_dir";
|
|
6188
|
+
var MSTARC_SDD_DIR_KEY2 = "sdd_dir";
|
|
6189
|
+
var MSTARC_ITERATION_DIR_KEY2 = "iteration_dir";
|
|
6190
|
+
var MSTARC_KNOWLEDGE_DIR_KEY2 = "knowledge_dir";
|
|
6191
|
+
var MSTARC_SPECS_DIR_KEY2 = "specs_dir";
|
|
6192
|
+
var MSTARC_WORKFLOW_DIR_KEY2 = "workflow_dir";
|
|
6193
|
+
var MSTARC_PROJECT_DIR_KEY2 = "project_dir";
|
|
6194
|
+
var MSTARC_ENFORCEMENT_KEY2 = "enforcement";
|
|
6195
|
+
var CONFIG_KEYS2 = {
|
|
6196
|
+
[MSTARC_HARNESS_DIR_KEY2]: "harnessDir",
|
|
6197
|
+
[MSTARC_PLAN_DIR_KEY2]: "planDir",
|
|
6198
|
+
[MSTARC_SDD_DIR_KEY2]: "sddDir",
|
|
6199
|
+
[MSTARC_ITERATION_DIR_KEY2]: "iterationDir",
|
|
6200
|
+
[MSTARC_KNOWLEDGE_DIR_KEY2]: "knowledgeDir",
|
|
6201
|
+
[MSTARC_SPECS_DIR_KEY2]: "specsDir",
|
|
6202
|
+
[MSTARC_WORKFLOW_DIR_KEY2]: "workflowDir",
|
|
6203
|
+
[MSTARC_PROJECT_DIR_KEY2]: "projectDir",
|
|
6204
|
+
[MSTARC_ENFORCEMENT_KEY2]: "enforcement"
|
|
6205
|
+
};
|
|
6206
|
+
var GITIGNORE_SNIPPET2 = `# Morning Star harness (.mstar/)
|
|
6207
|
+
# Principle: process stays local; results are shared with the team.
|
|
6208
|
+
# Default-ignore everything under .mstar/, then re-include the tracked results.
|
|
6209
|
+
.mstar/**
|
|
6210
|
+
!.mstar/AGENTS.md
|
|
6211
|
+
!.mstar/knowledge/
|
|
6212
|
+
!.mstar/knowledge/**
|
|
6213
|
+
!.mstar/specs/
|
|
6214
|
+
!.mstar/specs/**
|
|
6215
|
+
# .mstarc — repo-local harness config (may declare [config] harness_dir=<name>)
|
|
6216
|
+
.mstarc
|
|
6217
|
+
`;
|
|
6218
|
+
var GITIGNORE_SNIPPET_AGENTS2 = `# Morning Star harness (.agents/) — legacy
|
|
6219
|
+
# Default-ignore everything under .agents/, then re-include the tracked results.
|
|
6220
|
+
.agents/**
|
|
6221
|
+
!.agents/AGENTS.md
|
|
6222
|
+
!.agents/knowledge/
|
|
6223
|
+
!.agents/knowledge/**
|
|
6224
|
+
!.agents/specs/
|
|
6225
|
+
!.agents/specs/**
|
|
6226
|
+
`;
|
|
6227
|
+
var GITIGNORE_PROCESS_ENTRIES2 = GITIGNORE_SNIPPET2.split(`
|
|
6228
|
+
`).filter((line) => line.startsWith(".mstar/") || line.startsWith("!.mstar/")).map((line) => line.trim());
|
|
6229
|
+
var GITIGNORE_PROCESS_ENTRIES_AGENTS2 = GITIGNORE_SNIPPET_AGENTS2.split(`
|
|
6230
|
+
`).filter((line) => line.startsWith(".agents/") || line.startsWith("!.agents/")).map((line) => line.trim());
|
|
6231
|
+
var WHOLE_MATCH_PATTERNS = [
|
|
6232
|
+
{ type: "private-key", re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/g },
|
|
6233
|
+
{ type: "aws-access-key", re: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
6234
|
+
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
6235
|
+
{ type: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
6236
|
+
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\b/g },
|
|
6237
|
+
{ type: "api-secret-key", re: /\bsk-[A-Za-z0-9-]{20,}\b/g }
|
|
6238
|
+
];
|
|
6239
|
+
var VALUE_PATTERNS = [
|
|
6240
|
+
{
|
|
6241
|
+
typeOf: (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_-]+/g, "-"),
|
|
6242
|
+
re: /(["']?)\b(password|passwd|api[_-]?key|access[_-]?token|auth[_-]?token|secret|token)\b(["']?)(\s*[:=]\s*)("[^"\n]{8,}"|'[^'\n]{8,}'|[A-Za-z0-9_./+\-=]{16,})/gi
|
|
6243
|
+
}
|
|
6244
|
+
];
|
|
6245
|
+
function buildLineStarts(text) {
|
|
6246
|
+
const starts = [0];
|
|
6247
|
+
for (let i = 0;i < text.length; i++) {
|
|
6248
|
+
if (text[i] === `
|
|
6249
|
+
`)
|
|
6250
|
+
starts.push(i + 1);
|
|
6251
|
+
}
|
|
6252
|
+
return starts;
|
|
6253
|
+
}
|
|
6254
|
+
function lineAt(starts, index) {
|
|
6255
|
+
let lo = 0;
|
|
6256
|
+
let hi = starts.length - 1;
|
|
6257
|
+
while (lo < hi) {
|
|
6258
|
+
const mid = lo + hi + 1 >> 1;
|
|
6259
|
+
if (starts[mid] <= index)
|
|
6260
|
+
lo = mid;
|
|
6261
|
+
else
|
|
6262
|
+
hi = mid - 1;
|
|
6263
|
+
}
|
|
6264
|
+
return lo + 1;
|
|
6265
|
+
}
|
|
6266
|
+
function redactSecrets(text, filePath) {
|
|
6267
|
+
const starts = buildLineStarts(text);
|
|
6268
|
+
const marker = (type, index) => `[REDACTED ${type}@${lineAt(starts, index)}${filePath === undefined ? "" : ` in ${filePath}`}]`;
|
|
6269
|
+
const replacements = [];
|
|
6270
|
+
const findings = [];
|
|
6271
|
+
for (const pattern of WHOLE_MATCH_PATTERNS) {
|
|
6272
|
+
for (const match of text.matchAll(pattern.re)) {
|
|
6273
|
+
if (match.index === undefined)
|
|
6274
|
+
continue;
|
|
6275
|
+
replacements.push({ index: match.index, length: match[0].length, text: marker(pattern.type, match.index) });
|
|
6276
|
+
findings.push({ line: lineAt(starts, match.index), type: pattern.type });
|
|
6277
|
+
}
|
|
6278
|
+
}
|
|
6279
|
+
for (const pattern of VALUE_PATTERNS) {
|
|
6280
|
+
for (const match of text.matchAll(pattern.re)) {
|
|
6281
|
+
if (match.index === undefined)
|
|
6282
|
+
continue;
|
|
6283
|
+
const type = pattern.typeOf(match[2]);
|
|
6284
|
+
const replacement = `${match[1]}${match[2]}${match[3]}${match[4]}${marker(type, match.index)}`;
|
|
6285
|
+
replacements.push({ index: match.index, length: match[0].length, text: replacement });
|
|
6286
|
+
findings.push({ line: lineAt(starts, match.index), type });
|
|
6287
|
+
}
|
|
6288
|
+
}
|
|
6289
|
+
replacements.sort((a, b) => b.index - a.index);
|
|
6290
|
+
let out = text;
|
|
6291
|
+
for (const r of replacements)
|
|
6292
|
+
out = out.slice(0, r.index) + r.text + out.slice(r.index + r.length);
|
|
6293
|
+
const deduped = new Map;
|
|
6294
|
+
for (const f of findings)
|
|
6295
|
+
deduped.set(`${f.line}:${f.type}`, f);
|
|
6296
|
+
const sorted = [...deduped.values()].sort((a, b) => a.line - b.line || a.type.localeCompare(b.type));
|
|
6297
|
+
return { text: out, findings: sorted };
|
|
6298
|
+
}
|
|
6299
|
+
|
|
6300
|
+
// src/gates/seams.ts
|
|
6229
6301
|
var SEAM_LOGGERS = {
|
|
6230
6302
|
"design-md": "mstar/design-md-lint",
|
|
6231
6303
|
audit: "mstar/audit-lint",
|
|
@@ -6233,7 +6305,7 @@ var SEAM_LOGGERS = {
|
|
|
6233
6305
|
roles: "mstar/roles-lint"
|
|
6234
6306
|
};
|
|
6235
6307
|
function isIndexFile(path) {
|
|
6236
|
-
const base =
|
|
6308
|
+
const base = basename8(path);
|
|
6237
6309
|
return base === "README.md" || base === "index.md";
|
|
6238
6310
|
}
|
|
6239
6311
|
function isMarkdownDoc(path) {
|
|
@@ -6242,7 +6314,7 @@ function isMarkdownDoc(path) {
|
|
|
6242
6314
|
function isAuditPlanTarget(path) {
|
|
6243
6315
|
if (!isMarkdownDoc(path))
|
|
6244
6316
|
return false;
|
|
6245
|
-
const segments = resolve15(path).split(
|
|
6317
|
+
const segments = resolve15(path).split(sep3);
|
|
6246
6318
|
for (let i = 0;i < segments.length; i++) {
|
|
6247
6319
|
if (segments[i] !== "plans")
|
|
6248
6320
|
continue;
|
|
@@ -6253,7 +6325,7 @@ function isAuditPlanTarget(path) {
|
|
|
6253
6325
|
return false;
|
|
6254
6326
|
}
|
|
6255
6327
|
function isRolesTarget(path) {
|
|
6256
|
-
const segments = resolve15(path).split(
|
|
6328
|
+
const segments = resolve15(path).split(sep3);
|
|
6257
6329
|
const idx = segments.indexOf("mstar-roles");
|
|
6258
6330
|
if (idx === -1)
|
|
6259
6331
|
return false;
|
|
@@ -6263,17 +6335,17 @@ function isRolesTarget(path) {
|
|
|
6263
6335
|
return rest[0] === "SKILL.md" || rest[0] === "references" && rest[rest.length - 1].endsWith(".md");
|
|
6264
6336
|
}
|
|
6265
6337
|
function rolesDirOf(path) {
|
|
6266
|
-
const segments = resolve15(path).split(
|
|
6338
|
+
const segments = resolve15(path).split(sep3);
|
|
6267
6339
|
const idx = segments.indexOf("mstar-roles");
|
|
6268
6340
|
if (idx === -1)
|
|
6269
|
-
return
|
|
6270
|
-
return idx === 0 ?
|
|
6341
|
+
return dirname10(path);
|
|
6342
|
+
return idx === 0 ? sep3 : join16(sep3, ...segments.slice(1, idx + 1));
|
|
6271
6343
|
}
|
|
6272
6344
|
function isSeamTarget(seam, harnessDir, target) {
|
|
6273
6345
|
const path = resolve15(target.displayPath);
|
|
6274
6346
|
switch (seam) {
|
|
6275
6347
|
case "design-md": {
|
|
6276
|
-
const base =
|
|
6348
|
+
const base = basename8(path);
|
|
6277
6349
|
return base === "DESIGN.md" || base === "DESIGN.dark.md";
|
|
6278
6350
|
}
|
|
6279
6351
|
case "audit":
|
|
@@ -6281,7 +6353,7 @@ function isSeamTarget(seam, harnessDir, target) {
|
|
|
6281
6353
|
case "compound": {
|
|
6282
6354
|
if (harnessDir === null)
|
|
6283
6355
|
return false;
|
|
6284
|
-
return path.startsWith(resolve15(join16(harnessDir, "knowledge")) +
|
|
6356
|
+
return path.startsWith(resolve15(join16(harnessDir, "knowledge")) + sep3) && isMarkdownDoc(path);
|
|
6285
6357
|
}
|
|
6286
6358
|
case "roles":
|
|
6287
6359
|
return isRolesTarget(path);
|
|
@@ -6298,9 +6370,9 @@ function auditSecretsViolations(findings, file) {
|
|
|
6298
6370
|
}
|
|
6299
6371
|
function validateDesignDoc(doc, path) {
|
|
6300
6372
|
const violations = [...validateDesignTokenFrontmatter(doc).violations];
|
|
6301
|
-
const isDark =
|
|
6302
|
-
const sibling = join16(
|
|
6303
|
-
if (
|
|
6373
|
+
const isDark = basename8(path) === "DESIGN.dark.md";
|
|
6374
|
+
const sibling = join16(dirname10(path), isDark ? "DESIGN.md" : "DESIGN.dark.md");
|
|
6375
|
+
if (existsSync17(sibling)) {
|
|
6304
6376
|
const light = isDark ? readFileSync13(sibling, "utf8") : doc;
|
|
6305
6377
|
const dark = isDark ? doc : readFileSync13(sibling, "utf8");
|
|
6306
6378
|
violations.push(...assertLightDarkParity(light, dark).violations);
|
|
@@ -6316,18 +6388,18 @@ function validateAuditDoc(doc, path) {
|
|
|
6316
6388
|
function validateCompoundDoc(doc, _path, harnessDir) {
|
|
6317
6389
|
const violations = [...validateSchemaYaml(doc).violations];
|
|
6318
6390
|
if (harnessDir !== null) {
|
|
6319
|
-
violations.push(...referenceExists(
|
|
6391
|
+
violations.push(...referenceExists(dirname10(harnessDir), doc).violations);
|
|
6320
6392
|
}
|
|
6321
6393
|
return violations.length === 0 ? { ok: true, violations } : { ok: false, violations };
|
|
6322
6394
|
}
|
|
6323
|
-
function validateRolesState(rolesDir, skillsRoot =
|
|
6395
|
+
function validateRolesState(rolesDir, skillsRoot = dirname10(rolesDir)) {
|
|
6324
6396
|
const violations = [...validateRoleMapping(rolesDir).violations];
|
|
6325
6397
|
const skillTexts = {};
|
|
6326
6398
|
for (const entry of readdirSync11(skillsRoot, { withFileTypes: true })) {
|
|
6327
6399
|
if (!entry.isDirectory() || !entry.name.startsWith("mstar-"))
|
|
6328
6400
|
continue;
|
|
6329
6401
|
const skillFile = join16(skillsRoot, entry.name, "SKILL.md");
|
|
6330
|
-
if (!
|
|
6402
|
+
if (!existsSync17(skillFile))
|
|
6331
6403
|
continue;
|
|
6332
6404
|
try {
|
|
6333
6405
|
skillTexts[entry.name] = readFileSync13(skillFile, "utf8");
|
|
@@ -6361,7 +6433,7 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
6361
6433
|
if (!isSeamTarget(seam, harnessDir, target))
|
|
6362
6434
|
return;
|
|
6363
6435
|
const path = resolve15(target.displayPath);
|
|
6364
|
-
if (!
|
|
6436
|
+
if (!existsSync17(path))
|
|
6365
6437
|
return;
|
|
6366
6438
|
let doc;
|
|
6367
6439
|
try {
|
|
@@ -6377,12 +6449,12 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
6377
6449
|
const hard = resolveSeamHard(harnessDir, config);
|
|
6378
6450
|
const verdict = applyEnforcement(result, { hard });
|
|
6379
6451
|
if (verdict.hardBlocked) {
|
|
6380
|
-
logger.error(`${
|
|
6452
|
+
logger.error(`${basename8(path)} write to ${target.displayPath} ALLOWED as repair (Enforcement: hard; the current on-disk document is already invalid — the intent carries no incoming content, so the vetoable signal is only the pre-write state):
|
|
6381
6453
|
${verdict.violations.map(formatViolation).join(`
|
|
6382
6454
|
`)}`);
|
|
6383
6455
|
emitSeamAdvisory(ctx, seam, target.displayPath, verdict, hard, { repair: true });
|
|
6384
6456
|
} else {
|
|
6385
|
-
logger.warn(`${
|
|
6457
|
+
logger.warn(`${basename8(path)} write to ${target.displayPath} (advisory):
|
|
6386
6458
|
${verdict.violations.map(formatViolation).join(`
|
|
6387
6459
|
`)}`);
|
|
6388
6460
|
emitSeamAdvisory(ctx, seam, target.displayPath, verdict, hard);
|
|
@@ -6431,7 +6503,7 @@ function lintRolesWrite(doc, options) {
|
|
|
6431
6503
|
}
|
|
6432
6504
|
|
|
6433
6505
|
// src/gates/tools.ts
|
|
6434
|
-
import { existsSync as
|
|
6506
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "node:fs";
|
|
6435
6507
|
import { join as join17, resolve as resolve16 } from "node:path";
|
|
6436
6508
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
6437
6509
|
var ITERATION_VIOLATION_SCHEMA = {
|
|
@@ -6597,9 +6669,9 @@ function registerSddIterationTools(ctx, resolver) {
|
|
|
6597
6669
|
presentResult: (_args, _result) => ({ card: "generic", title: "Iteration gate evaluation" }),
|
|
6598
6670
|
isConcurrencySafe: () => false,
|
|
6599
6671
|
async execute(args) {
|
|
6600
|
-
if (!
|
|
6672
|
+
if (!existsSync18(args.snapshot_path))
|
|
6601
6673
|
throw new Error(`workflow snapshot not found: ${args.snapshot_path}`);
|
|
6602
|
-
if (!
|
|
6674
|
+
if (!existsSync18(args.compass_path))
|
|
6603
6675
|
throw new Error(`compass file not found: ${args.compass_path}`);
|
|
6604
6676
|
const snapshotDoc = readJson(args.snapshot_path);
|
|
6605
6677
|
const compassDoc = parseCompassFrontmatter(args.compass_path);
|
|
@@ -6654,7 +6726,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6654
6726
|
async execute(args) {
|
|
6655
6727
|
const abs = resolve16(args.dir);
|
|
6656
6728
|
const lightPath = join17(abs, "DESIGN.md");
|
|
6657
|
-
if (!
|
|
6729
|
+
if (!existsSync18(lightPath))
|
|
6658
6730
|
throw new Error(`design file not found: ${lightPath}`);
|
|
6659
6731
|
const light = readFileSync14(lightPath, "utf8");
|
|
6660
6732
|
const result = validateDesignDoc(light, lightPath);
|
|
@@ -6707,7 +6779,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6707
6779
|
isConcurrencySafe: () => false,
|
|
6708
6780
|
async execute(args) {
|
|
6709
6781
|
const abs = resolve16(args.plan_path);
|
|
6710
|
-
if (!
|
|
6782
|
+
if (!existsSync18(abs))
|
|
6711
6783
|
throw new Error(`plan file not found: ${abs}`);
|
|
6712
6784
|
const text = readFileSync14(abs, "utf8");
|
|
6713
6785
|
const result = validateAuditDoc(text, abs);
|
|
@@ -6747,7 +6819,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6747
6819
|
isConcurrencySafe: () => false,
|
|
6748
6820
|
async execute(args, exec) {
|
|
6749
6821
|
const abs = resolve16(args.doc_path);
|
|
6750
|
-
if (!
|
|
6822
|
+
if (!existsSync18(abs))
|
|
6751
6823
|
throw new Error(`knowledge doc not found: ${abs}`);
|
|
6752
6824
|
const text = readFileSync14(abs, "utf8");
|
|
6753
6825
|
const base = validateCompoundDoc(text, abs, args.repo_root !== undefined ? null : resolver.forAgent(exec.agent));
|
|
@@ -6792,7 +6864,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6792
6864
|
isConcurrencySafe: () => false,
|
|
6793
6865
|
async execute(args) {
|
|
6794
6866
|
const rolesDir = resolve16(args.roles_dir);
|
|
6795
|
-
if (!
|
|
6867
|
+
if (!existsSync18(join17(rolesDir, "SKILL.md")))
|
|
6796
6868
|
throw new Error(`roles dir not found: ${rolesDir}`);
|
|
6797
6869
|
const result = validateRolesState(rolesDir, args.skills_root !== undefined ? resolve16(args.skills_root) : undefined);
|
|
6798
6870
|
return { ok: result.ok, violations: result.violations.map(iterationViolationView) };
|
|
@@ -6802,7 +6874,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6802
6874
|
}
|
|
6803
6875
|
|
|
6804
6876
|
// src/gates/adapter.ts
|
|
6805
|
-
import { existsSync as
|
|
6877
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
6806
6878
|
import { join as join18 } from "node:path";
|
|
6807
6879
|
import { Service as Service2 } from "@deepseek-ai/cordis";
|
|
6808
6880
|
var HOST_LOGGER = "mstar/host-adapter";
|
|
@@ -6839,7 +6911,7 @@ class DshHostAdapter extends Service2 {
|
|
|
6839
6911
|
this.logSink(level, msg);
|
|
6840
6912
|
}
|
|
6841
6913
|
statusGate(path, kind, harnessDir) {
|
|
6842
|
-
if (!
|
|
6914
|
+
if (!existsSync19(path))
|
|
6843
6915
|
return { ok: true, violations: [] };
|
|
6844
6916
|
return validateStatusDoc(path, kind, harnessDir);
|
|
6845
6917
|
}
|
|
@@ -6921,7 +6993,7 @@ class DshHostAdapter extends Service2 {
|
|
|
6921
6993
|
|
|
6922
6994
|
// src/gates/agent-personas.ts
|
|
6923
6995
|
import { readFileSync as readFileSync15, readdirSync as readdirSync12, statSync as statSync6 } from "node:fs";
|
|
6924
|
-
import { join as join19, resolve as resolve17, sep as
|
|
6996
|
+
import { join as join19, resolve as resolve17, sep as sep5 } from "node:path";
|
|
6925
6997
|
var ROLE_ID_PATTERN = /^[a-z0-9-]{1,32}$/;
|
|
6926
6998
|
var defaultCache = new Map;
|
|
6927
6999
|
function personaFor(roleId, lookup, warn) {
|
|
@@ -6964,7 +7036,7 @@ function defaultFromMirror(agentsDir, roleId, warn) {
|
|
|
6964
7036
|
return;
|
|
6965
7037
|
const root = resolve17(agentsDir);
|
|
6966
7038
|
const file = resolve17(agentsDir, `${roleId}.md`);
|
|
6967
|
-
if (!file.startsWith(root +
|
|
7039
|
+
if (!file.startsWith(root + sep5))
|
|
6968
7040
|
return;
|
|
6969
7041
|
let stat;
|
|
6970
7042
|
try {
|
|
@@ -7451,7 +7523,7 @@ function registerWorkflowLedger(ctx, resolver, workflowAskCache) {
|
|
|
7451
7523
|
}
|
|
7452
7524
|
|
|
7453
7525
|
// src/gates/goal-bridge.ts
|
|
7454
|
-
import { existsSync as
|
|
7526
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, readdirSync as readdirSync13 } from "node:fs";
|
|
7455
7527
|
import { join as join21 } from "node:path";
|
|
7456
7528
|
var GOAL_BRIDGE_LOGGER = "mstar/goal-bridge";
|
|
7457
7529
|
var DEFAULT_MAX_GOAL_ROUNDS = 256;
|
|
@@ -7480,7 +7552,7 @@ function projectRegisterPointer(harnessDir) {
|
|
|
7480
7552
|
if (!entry.isDirectory())
|
|
7481
7553
|
continue;
|
|
7482
7554
|
const registerPath = join21(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
7483
|
-
if (
|
|
7555
|
+
if (existsSync20(registerPath))
|
|
7484
7556
|
return registerPath;
|
|
7485
7557
|
}
|
|
7486
7558
|
} catch {}
|
|
@@ -7495,7 +7567,7 @@ function iterationGoalObjective(iterationId) {
|
|
|
7495
7567
|
}
|
|
7496
7568
|
function steeringCompass(harnessDir) {
|
|
7497
7569
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
7498
|
-
if (!
|
|
7570
|
+
if (!existsSync20(iterationsDir))
|
|
7499
7571
|
return;
|
|
7500
7572
|
let entries;
|
|
7501
7573
|
try {
|
|
@@ -7507,7 +7579,7 @@ function steeringCompass(harnessDir) {
|
|
|
7507
7579
|
if (!entry.isDirectory())
|
|
7508
7580
|
continue;
|
|
7509
7581
|
const compassPath = join21(iterationsDir, entry.name, "delivery-compass.md");
|
|
7510
|
-
if (!
|
|
7582
|
+
if (!existsSync20(compassPath))
|
|
7511
7583
|
continue;
|
|
7512
7584
|
let content;
|
|
7513
7585
|
try {
|
|
@@ -7687,7 +7759,7 @@ function registerGoalBridge(ctx, resolver, config) {
|
|
|
7687
7759
|
}
|
|
7688
7760
|
|
|
7689
7761
|
// src/gates/plan-mode-bridge.ts
|
|
7690
|
-
import { existsSync as
|
|
7762
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
7691
7763
|
import { join as join22 } from "node:path";
|
|
7692
7764
|
var PLAN_MODE_BRIDGE_LOGGER = "mstar/plan-mode-bridge";
|
|
7693
7765
|
var PLAN_STATUS_TODO = "Todo";
|
|
@@ -7705,7 +7777,7 @@ function errorMessage5(error) {
|
|
|
7705
7777
|
}
|
|
7706
7778
|
function hasPrepareWindow(harnessDir) {
|
|
7707
7779
|
const statusPath = join22(harnessDir, STATUS_FILE);
|
|
7708
|
-
if (!
|
|
7780
|
+
if (!existsSync21(statusPath))
|
|
7709
7781
|
return false;
|
|
7710
7782
|
const selection = resolveReadWorkflow(harnessDir);
|
|
7711
7783
|
if (selection.kind === "error")
|
|
@@ -8164,7 +8236,7 @@ var inject = ["loader"];
|
|
|
8164
8236
|
function packagedCommandsDir() {
|
|
8165
8237
|
try {
|
|
8166
8238
|
const dir = fileURLToPath3(new URL("../harness-commands", import.meta.url));
|
|
8167
|
-
return
|
|
8239
|
+
return existsSync22(dir) ? dir : undefined;
|
|
8168
8240
|
} catch {
|
|
8169
8241
|
return;
|
|
8170
8242
|
}
|
|
@@ -8364,7 +8436,7 @@ function apply(ctx, config) {
|
|
|
8364
8436
|
}
|
|
8365
8437
|
const effectiveHard = config.enforcement === "hard" || bootHarnessDir !== null && resolveRepoEnforcement(bootHarnessDir).hard;
|
|
8366
8438
|
if (effectiveHard && (config.dispatchBinding ?? "").trim() === "") {
|
|
8367
|
-
ctx.logger(DISPATCH_LOGGER).warn("Enforcement: hard is active but dispatchBinding is unset — the
|
|
8439
|
+
ctx.logger(DISPATCH_LOGGER).warn("Enforcement: hard is active but dispatchBinding is unset — the empty host binding fails closed: every Assignment-shaped dispatch emits dispatch.anti-recursion.empty-binding (critical) until dispatchBinding is set");
|
|
8368
8440
|
}
|
|
8369
8441
|
if (effectiveHard && config.dispatchTools === undefined) {
|
|
8370
8442
|
ctx.logger(DISPATCH_LOGGER).warn('Enforcement: hard is active but dispatchTools is unset — the dispatch gate matches the default tool names "subagent" and "subagent_fork"; a deployment renaming either dsh subagent tool (toolName) without declaring dispatchTools silently disables the gate');
|