@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.
Files changed (35) hide show
  1. package/README.md +2 -2
  2. package/README.zh.md +2 -2
  3. package/dist/gates/_shared.d.ts +4 -2
  4. package/dist/gates/status.d.ts +7 -1
  5. package/dist/gates/workflow-selection.d.ts +7 -0
  6. package/dist/index.js +248 -176
  7. package/harness-commands/iteration-drive.md +9 -90
  8. package/harness-commands/iteration-loop.md +22 -62
  9. package/harness-commands/iteration-start.md +20 -77
  10. package/harness-skills/mstar-audit/SKILL.md +2 -2
  11. package/harness-skills/mstar-compound-refresh/SKILL.md +1 -1
  12. package/harness-skills/mstar-dispatch-gates/SKILL.md +1 -1
  13. package/harness-skills/mstar-harness-core/SKILL.md +4 -3
  14. package/harness-skills/mstar-iteration/SKILL.md +16 -10
  15. package/harness-skills/mstar-iteration/references/command-shared-invariants.md +62 -0
  16. package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +3 -3
  17. package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +1 -1
  18. package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +1 -1
  19. package/harness-skills/mstar-phase-gates/SKILL.md +1 -1
  20. package/harness-skills/mstar-plan-artifacts/references/knowledge-and-designs.md +2 -2
  21. package/harness-skills/mstar-plan-artifacts/references/status-and-residuals.md +1 -1
  22. package/harness-skills/mstar-plan-conventions/SKILL.md +1 -1
  23. package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +11 -1
  24. package/harness-skills/mstar-roles/references/architect.md +4 -7
  25. package/harness-skills/mstar-roles/references/code-reviewer.md +1 -4
  26. package/harness-skills/mstar-roles/references/frontend-dev.md +2 -4
  27. package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +2 -4
  28. package/harness-skills/mstar-roles/references/ops-engineer.md +2 -6
  29. package/harness-skills/mstar-roles/references/product-manager.md +4 -7
  30. package/harness-skills/mstar-roles/references/prompt-engineer.md +2 -5
  31. package/harness-skills/mstar-roles/references/qa-engineer.md +2 -6
  32. package/harness-skills/mstar-roles/references/qc-specialist-shared.md +1 -4
  33. package/harness-skills/mstar-roles/references/writing-specialist.md +2 -5
  34. package/harness-skills/mstar-strategy/SKILL.md +5 -35
  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 existsSync20, readFileSync as readFileSync18, readdirSync as readdirSync14 } from "node:fs";
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 existsSync2, readFileSync as readFileSync4, readdirSync as readdirSync2, realpathSync } from "node:fs";
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 existsSync3 } from "node:fs";
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 realpathSync2, statSync as statSync4, writeFileSync as writeFileSync3 } from "node:fs";
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 existsSync4, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "node:fs";
1139
- import { existsSync as existsSync6, readdirSync as readdirSync8, readFileSync as readFileSync10 } from "node:fs";
1140
- import { basename as basename4, isAbsolute as isAbsolute7, join as join12, relative as relative4, resolve as resolve10, sep as sep3 } from "node:path";
1141
- import { existsSync as existsSync7 } from "node:fs";
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 = (opts.agent ?? "").trim();
1685
- if (agent !== "") {
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 !== "" && binding === role) {
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 = realpathSync(harnessDir);
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 = realpathSync(snapshotPath);
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; align them`));
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 (!existsSync2(iterationsDir))
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 (!existsSync2(compassPath))
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 !== "" && !existsSync3(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 (!existsSync3(track.worktreePath)) {
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 = realpathSync2(dirname6(gitDir));
2308
- const cmAbs = realpathSync2(common);
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 = realpathSync2(controlRoot);
2332
+ root = realpathSync3(controlRoot);
2327
2333
  } else {
2328
2334
  const topLevel = gitOut(cwd, ["rev-parse", "--show-toplevel"]);
2329
- root = realpathSync2(topLevel ?? cwd);
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 realpathSync2(sddDir);
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 (existsSync6(resolve10(repoRoot, candidate))) {
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(sep3).join("/"));
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 (!existsSync6(readmePath)) {
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(basename4(root));
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 + sep3)) {
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 (!existsSync7(join13(rolesDir, reference))) {
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 existsSync5 } from "node:fs";
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 (existsSync5(dir))
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 (existsSync5(dir))
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 existsSync12, readFileSync as readFileSync9, readdirSync as readdirSync7 } from "node:fs";
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 existsSync11, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync7, readSync, renameSync as renameSync2, rmdirSync, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
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 existsSync10 } from "node:fs";
4201
- import { basename as basename5, join as join8, resolve as resolve11 } from "node:path";
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 existsSync8, readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
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 (!existsSync8(statusPath)) {
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 (!existsSync8(workflowsDir)) {
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 (!existsSync8(snapshotPath))
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 = basename5(firstToken(planPath) ?? "");
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 = basename5(firstToken(sddDir) ?? "");
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 (!existsSync10(snapshotPath)) {
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 (!existsSync10(join8(harnessDir, STATUS_FILE)))
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 (!existsSync10(snapshotPath))
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 (!existsSync11(file)) {
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 (!existsSync12(statusPath))
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 (!existsSync12(snapshotPath)) {
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 (existsSync12(projectsDir)) {
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 (!existsSync12(roadmapPath))
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 (!existsSync12(projectsDir))
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 (!existsSync12(registerPath))
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 (!existsSync12(indexPath))
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 (!existsSync12(iterationsDir))
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 (!existsSync12(compassPath))
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 (!existsSync12(statusPath))
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 existsSync13, readdirSync as readdirSync9 } from "node:fs";
5944
- import { basename as basename7, join as join14, relative as relative5, resolve as resolve13 } from "node:path";
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 = basename7(resolved);
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 (!existsSync13(registerPath))
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
- ctx.emit("mstar/status-gate", { operation, target: target.displayPath, result: { ok: true, violations: [] }, hard: false, degraded: true });
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 existsSync14, readFileSync as readFileSync11 } from "node:fs";
6096
- import { basename as basename8, dirname as dirname7, resolve as resolve14, sep as sep2 } from "node:path";
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 (basename8(target.displayPath) !== "SKILL.md")
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 basename8(dirname7(target.displayPath));
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 (!existsSync14(skillPath))
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 existsSync15, readFileSync as readFileSync13, readdirSync as readdirSync11 } from "node:fs";
6228
- import { basename as basename9, dirname as dirname9, join as join16, resolve as resolve15, sep as sep4 } from "node:path";
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 = basename9(path);
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(sep4);
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(sep4);
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(sep4);
6338
+ const segments = resolve15(path).split(sep3);
6267
6339
  const idx = segments.indexOf("mstar-roles");
6268
6340
  if (idx === -1)
6269
- return dirname9(path);
6270
- return idx === 0 ? sep4 : join16(sep4, ...segments.slice(1, idx + 1));
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 = basename9(path);
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")) + sep4) && isMarkdownDoc(path);
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 = basename9(path) === "DESIGN.dark.md";
6302
- const sibling = join16(dirname9(path), isDark ? "DESIGN.md" : "DESIGN.dark.md");
6303
- if (existsSync15(sibling)) {
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(dirname9(harnessDir), doc).violations);
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 = dirname9(rolesDir)) {
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 (!existsSync15(skillFile))
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 (!existsSync15(path))
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(`${basename9(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):
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(`${basename9(path)} write to ${target.displayPath} (advisory):
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 existsSync16, readFileSync as readFileSync14 } from "node:fs";
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 (!existsSync16(args.snapshot_path))
6672
+ if (!existsSync18(args.snapshot_path))
6601
6673
  throw new Error(`workflow snapshot not found: ${args.snapshot_path}`);
6602
- if (!existsSync16(args.compass_path))
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 (!existsSync16(lightPath))
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 (!existsSync16(abs))
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 (!existsSync16(abs))
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 (!existsSync16(join17(rolesDir, "SKILL.md")))
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 existsSync17 } from "node:fs";
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 (!existsSync17(path))
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 sep6 } from "node:path";
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 + sep6))
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 existsSync18, readFileSync as readFileSync17, readdirSync as readdirSync13 } from "node:fs";
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 (existsSync18(registerPath))
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 (!existsSync18(iterationsDir))
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 (!existsSync18(compassPath))
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 existsSync19 } from "node:fs";
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 (!existsSync19(statusPath))
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 existsSync20(dir) ? dir : undefined;
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 anti-recursion precheck is skipped (an Assignment whose Execute as equals the dispatching agent cannot be detected)");
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');