@mstar-harness/dsh 3.9.4 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gates/dispatch.d.ts +9 -3
- package/dist/index.js +175 -89
- package/harness-skills/mstar-artifacts/SKILL.md +4 -2
- package/harness-skills/mstar-artifacts/references/plan-files-and-reports.md +1 -1
- package/harness-skills/mstar-artifacts/references/plan-quality-bar.md +10 -0
- package/harness-skills/mstar-artifacts/references/plan-workflow-lifecycle-contract.md +115 -0
- package/harness-skills/mstar-artifacts/references/status-and-residuals.md +24 -3
- package/harness-skills/mstar-artifacts/templates/plan.main.md +6 -1
- package/harness-skills/mstar-compound/SKILL.md +4 -4
- package/harness-skills/mstar-conventions/SKILL.md +1 -0
- package/harness-skills/mstar-conventions/references/effort-estimation.md +2 -0
- package/harness-skills/mstar-dispatch-gates/SKILL.md +1 -1
- package/harness-skills/mstar-harness-core/SKILL.md +2 -2
- package/harness-skills/mstar-host/SKILL.md +8 -2
- package/harness-skills/mstar-host/references/_shared/plan-mode-bridge-core.md +2 -0
- package/harness-skills/mstar-host/references/dsh.md +8 -4
- package/harness-skills/mstar-host/references/omp.md +61 -1
- package/harness-skills/mstar-iteration/SKILL.md +1 -1
- package/harness-skills/mstar-iteration/references/command-shared-invariants.md +2 -0
- package/harness-skills/mstar-iteration/references/phase-1-prepare.md +2 -0
- package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +38 -3
- package/harness-skills/mstar-iteration/references/phase-3-iteration-close.md +3 -3
- package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +3 -2
- package/harness-skills/mstar-iteration/references/phase-6-post-merge-close.md +5 -2
- package/harness-skills/mstar-iteration/references/plan-scoped-pm.md +2 -0
- package/harness-skills/mstar-phase-gates/SKILL.md +7 -5
- package/harness-skills/mstar-project-governance/SKILL.md +3 -3
- package/harness-skills/mstar-review-qc/SKILL.md +4 -4
- package/harness-skills/mstar-review-qc/references/review-responsibility-boundaries.md +1 -1
- package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +1 -0
- package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +5 -2
- package/harness-skills/mstar-roles/references/project-manager/plan-management.md +15 -0
- package/harness-skills/mstar-roles/references/project-manager/qa-trigger-matrix.md +3 -3
- package/harness-skills/mstar-roles/references/project-manager/qc-and-residuals.md +7 -5
- package/harness-skills/mstar-roles/references/project-manager.md +2 -3
- package/harness-skills/mstar-sdd/SKILL.md +5 -2
- package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +4 -1
- package/harness-skills/mstar-sdd/references/implementer-prompt.md +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1122,7 +1122,7 @@ var require_lib2 = __commonJS(function(exports, module) {
|
|
|
1122
1122
|
});
|
|
1123
1123
|
|
|
1124
1124
|
// src/index.ts
|
|
1125
|
-
import { existsSync as existsSync24, readFileSync as readFileSync19, readdirSync as
|
|
1125
|
+
import { existsSync as existsSync24, readFileSync as readFileSync19, readdirSync as readdirSync15 } from "node:fs";
|
|
1126
1126
|
import { join as join29 } from "node:path";
|
|
1127
1127
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1128
1128
|
import {
|
|
@@ -1138,28 +1138,28 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
1138
1138
|
import { fileURLToPath } from "node:url";
|
|
1139
1139
|
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
1140
1140
|
import { dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "node:path";
|
|
1141
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as
|
|
1141
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1142
1142
|
import { execFileSync } from "node:child_process";
|
|
1143
|
-
import { basename as basename5, dirname as dirname6, isAbsolute as isAbsolute6, join as join10, relative as relative2, resolve as
|
|
1144
|
-
import { existsSync as existsSync6, readdirSync as
|
|
1145
|
-
import { existsSync as existsSync5, readFileSync as readFileSync5, readdirSync as
|
|
1146
|
-
import { dirname as dirname5, join as join7, resolve as
|
|
1143
|
+
import { basename as basename5, dirname as dirname6, isAbsolute as isAbsolute6, join as join10, relative as relative2, resolve as resolve9 } from "node:path";
|
|
1144
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "node:fs";
|
|
1145
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, readdirSync as readdirSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
1146
|
+
import { dirname as dirname5, join as join7, resolve as resolve7, sep as sep2 } from "node:path";
|
|
1147
1147
|
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve3 } from "node:path";
|
|
1148
1148
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1149
1149
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
1150
1150
|
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute3, join as join4, resolve as resolve4 } from "node:path";
|
|
1151
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
1152
|
-
import { isAbsolute as isAbsolute5, join as join6 } from "node:path";
|
|
1151
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync as readdirSync2, rmdirSync as rmdirSync2 } from "node:fs";
|
|
1152
|
+
import { isAbsolute as isAbsolute5, join as join6, resolve as resolve6 } from "node:path";
|
|
1153
1153
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
1154
1154
|
import { existsSync as existsSync9, realpathSync as realpathSync4 } from "node:fs";
|
|
1155
|
-
import { isAbsolute as isAbsolute7, join as join11, resolve as
|
|
1155
|
+
import { isAbsolute as isAbsolute7, join as join11, resolve as resolve10 } from "node:path";
|
|
1156
1156
|
import { existsSync as existsSync10 } from "node:fs";
|
|
1157
1157
|
import { join as join12, dirname as dirname8 } from "node:path";
|
|
1158
1158
|
import { execFileSync as execFileSync3, spawn } from "node:child_process";
|
|
1159
|
-
import { mkdirSync as mkdirSync6, readdirSync as
|
|
1160
|
-
import { basename as basename7, dirname as dirname9, isAbsolute as isAbsolute8, join as join13, relative as relative3, resolve as
|
|
1161
|
-
import { existsSync as existsSync13, readdirSync as
|
|
1162
|
-
import { basename as basename11, isAbsolute as isAbsolute10, join as join17, relative as relative6, resolve as
|
|
1159
|
+
import { mkdirSync as mkdirSync6, readdirSync as readdirSync7, readFileSync as readFileSync9, realpathSync as realpathSync5, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1160
|
+
import { basename as basename7, dirname as dirname9, isAbsolute as isAbsolute8, join as join13, relative as relative3, resolve as resolve11 } from "node:path";
|
|
1161
|
+
import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync12 } from "node:fs";
|
|
1162
|
+
import { basename as basename11, isAbsolute as isAbsolute10, join as join17, relative as relative6, resolve as resolve15, sep as sep5 } from "node:path";
|
|
1163
1163
|
import { existsSync as existsSync14 } from "node:fs";
|
|
1164
1164
|
import { join as join18 } from "node:path";
|
|
1165
1165
|
var SEVERITY_ORDER = ["critical", "high", "medium", "low", "nit"];
|
|
@@ -1702,6 +1702,7 @@ var REQUIRED_FIELDS = [
|
|
|
1702
1702
|
var REVIEW_SEAT_ROLES = ["qc-specialist", "qc-specialist-2", "qc-specialist-3", "code-reviewer", "qa-engineer"];
|
|
1703
1703
|
var BUDGET_LABELS = ["Budget (review / QC seats)", "Budget"];
|
|
1704
1704
|
var RETURN_SHAPE_LABELS = ["Return shape (review / QC seats)", "Return shape"];
|
|
1705
|
+
var TASK_BUDGET_LABELS = ["Task budget (implement / ops rounds)", "Task budget"];
|
|
1705
1706
|
function violation2(severity, code, message, fix) {
|
|
1706
1707
|
return { ok: false, severity, code, message, fix };
|
|
1707
1708
|
}
|
|
@@ -1729,6 +1730,8 @@ function parseAssignmentFields(assignmentText) {
|
|
|
1729
1730
|
fields.budget = value;
|
|
1730
1731
|
else if (RETURN_SHAPE_LABELS.includes(label))
|
|
1731
1732
|
fields.returnShape = value;
|
|
1733
|
+
else if (TASK_BUDGET_LABELS.includes(label))
|
|
1734
|
+
fields.taskBudget = value;
|
|
1732
1735
|
}
|
|
1733
1736
|
return fields;
|
|
1734
1737
|
}
|
|
@@ -1843,6 +1846,12 @@ function validateAssignmentFields(assignmentText, opts = {}) {
|
|
|
1843
1846
|
violations.push(violation2("high", field.code, `${subject} must declare a round ${field.label} — ${missing}`, field.fix));
|
|
1844
1847
|
}
|
|
1845
1848
|
}
|
|
1849
|
+
if (!reviewSeat && !auditRound) {
|
|
1850
|
+
const missing = describeAbsence(fields.taskBudget);
|
|
1851
|
+
if (missing !== undefined) {
|
|
1852
|
+
violations.push(violation2("high", "assignment.field.task-budget-missing", `implement/ops round "${role}" must declare a Task budget — ${missing}`, `add "**Task budget (implement / ops rounds)**: <one implementer round closing the task's declared Files list and verification gates> — capacity contract spec § A1/A2"`));
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1846
1855
|
if (writable) {
|
|
1847
1856
|
const workingPresent = fields.workingBranch !== undefined && fields.workingBranch !== "";
|
|
1848
1857
|
const policyPresent = fields.branchPolicy !== undefined && fields.branchPolicy !== "";
|
|
@@ -1963,6 +1972,8 @@ var WORKFLOW_SNAPSHOT_FILE = "snapshot.json";
|
|
|
1963
1972
|
var WORKFLOW_LIFECYCLE_STATUSES = ["running", "paused", "completed", "failed", "stopped"];
|
|
1964
1973
|
var WORKFLOW_TERMINAL_STATUSES = ["completed", "failed", "stopped"];
|
|
1965
1974
|
var WORKFLOW_LIFECYCLE_TYPES = ["plan", "iteration"];
|
|
1975
|
+
var WORKFLOW_DELIVERY_KINDS = ["development", "verification/report-only"];
|
|
1976
|
+
var WORKFLOW_COMPOUND_OUTCOMES = ["created", "updated", "skipped"];
|
|
1966
1977
|
function violation3(severity, code, message, fix) {
|
|
1967
1978
|
return { ok: false, severity, code, message, fix };
|
|
1968
1979
|
}
|
|
@@ -1978,6 +1989,61 @@ function validateWorktreePathValue(violations, value, field) {
|
|
|
1978
1989
|
violations.push(violation3("high", "workflow.snapshot.invalid-integration-worktree-path", `${field} must be a non-empty absolute path — got ${JSON.stringify(value)}`, "record the absolute integration checkout path (integration_worktree_path)"));
|
|
1979
1990
|
}
|
|
1980
1991
|
}
|
|
1992
|
+
function deliveryEvidenceViolations(value, what) {
|
|
1993
|
+
const violations = [];
|
|
1994
|
+
const invalid2 = (message) => {
|
|
1995
|
+
violations.push(violation3("medium", "workflow.snapshot.invalid-delivery-evidence", `${what}: ${message}`));
|
|
1996
|
+
};
|
|
1997
|
+
if (!isPlainObject2(value)) {
|
|
1998
|
+
invalid2("must be an object");
|
|
1999
|
+
return violations;
|
|
2000
|
+
}
|
|
2001
|
+
const members = ["compound", "pr", "merge", "completion"];
|
|
2002
|
+
const unknownMembers = Object.keys(value).filter((key) => !members.includes(key));
|
|
2003
|
+
if (unknownMembers.length > 0)
|
|
2004
|
+
invalid2(`unknown member(s) ${unknownMembers.join(", ")} — expected ${members.join(" | ")}`);
|
|
2005
|
+
const compound = value.compound;
|
|
2006
|
+
if (compound !== undefined) {
|
|
2007
|
+
if (!isPlainObject2(compound))
|
|
2008
|
+
invalid2("compound must be an object");
|
|
2009
|
+
else {
|
|
2010
|
+
const unknown = Object.keys(compound).filter((key) => key !== "outcome" && key !== "reason");
|
|
2011
|
+
if (unknown.length > 0)
|
|
2012
|
+
invalid2(`compound has unknown key(s) ${unknown.join(", ")}`);
|
|
2013
|
+
if (typeof compound.outcome !== "string" || !WORKFLOW_COMPOUND_OUTCOMES.includes(compound.outcome)) {
|
|
2014
|
+
invalid2(`compound.outcome must be one of ${WORKFLOW_COMPOUND_OUTCOMES.join(" | ")} — got ${JSON.stringify(compound.outcome)}`);
|
|
2015
|
+
} else if (compound.outcome === "skipped" && (typeof compound.reason !== "string" || compound.reason.trim() === "")) {
|
|
2016
|
+
invalid2("compound reason is required when the disposition outcome is 'skipped' (contract §4c)");
|
|
2017
|
+
} else if (compound.reason !== undefined && (typeof compound.reason !== "string" || compound.reason.trim() === "")) {
|
|
2018
|
+
invalid2("compound.reason must be a non-empty string when given");
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
const stringMembers = {
|
|
2023
|
+
pr: ["repo", "head", "target"],
|
|
2024
|
+
merge: ["provider", "evidence"],
|
|
2025
|
+
completion: ["policy", "evidence"]
|
|
2026
|
+
};
|
|
2027
|
+
for (const member of ["pr", "merge", "completion"]) {
|
|
2028
|
+
const block = value[member];
|
|
2029
|
+
if (block === undefined)
|
|
2030
|
+
continue;
|
|
2031
|
+
if (!isPlainObject2(block)) {
|
|
2032
|
+
invalid2(`${member} must be an object`);
|
|
2033
|
+
continue;
|
|
2034
|
+
}
|
|
2035
|
+
const fields = stringMembers[member];
|
|
2036
|
+
const unknown = Object.keys(block).filter((key) => !fields.includes(key));
|
|
2037
|
+
if (unknown.length > 0)
|
|
2038
|
+
invalid2(`${member} has unknown key(s) ${unknown.join(", ")}`);
|
|
2039
|
+
for (const field of fields) {
|
|
2040
|
+
if (typeof block[field] !== "string" || block[field].trim() === "") {
|
|
2041
|
+
invalid2(`${member}.${field} must be a non-empty string`);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
return violations;
|
|
2046
|
+
}
|
|
1981
2047
|
function validateWorkflowSnapshot(doc) {
|
|
1982
2048
|
const violations = [];
|
|
1983
2049
|
if (!isPlainObject2(doc)) {
|
|
@@ -2043,7 +2109,7 @@ function validateWorkflowSnapshot(doc) {
|
|
|
2043
2109
|
if (!isPlainObject2(doc.branch)) {
|
|
2044
2110
|
violations.push(violation3("medium", "workflow.snapshot.invalid-branch", "branch must be an object"));
|
|
2045
2111
|
} else {
|
|
2046
|
-
for (const key of ["base", "integration", "target"]) {
|
|
2112
|
+
for (const key of ["base", "source", "integration", "target"]) {
|
|
2047
2113
|
if (doc.branch[key] !== undefined && (typeof doc.branch[key] !== "string" || doc.branch[key].trim() === "")) {
|
|
2048
2114
|
violations.push(violation3("medium", "workflow.snapshot.invalid-branch", `branch.${key} must be a non-empty string`));
|
|
2049
2115
|
}
|
|
@@ -2069,6 +2135,20 @@ function validateWorkflowSnapshot(doc) {
|
|
|
2069
2135
|
if (doc.compass_ref !== undefined) {
|
|
2070
2136
|
validateNonEmptyString2(violations, doc.compass_ref, "compass_ref", "workflow.snapshot.missing-compass-ref", "workflow.snapshot.invalid-compass-ref");
|
|
2071
2137
|
}
|
|
2138
|
+
if (doc.delivery_kind !== undefined) {
|
|
2139
|
+
if (typeof doc.delivery_kind !== "string" || !WORKFLOW_DELIVERY_KINDS.includes(doc.delivery_kind)) {
|
|
2140
|
+
violations.push(violation3("medium", "workflow.snapshot.invalid-delivery-kind", `delivery_kind must be one of ${WORKFLOW_DELIVERY_KINDS.join(" | ")} — got ${JSON.stringify(doc.delivery_kind)}`));
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
if (doc.project !== undefined) {
|
|
2144
|
+
validateNonEmptyString2(violations, doc.project, "project", "workflow.snapshot.missing-project", "workflow.snapshot.invalid-project");
|
|
2145
|
+
}
|
|
2146
|
+
if (doc.completion_policy !== undefined) {
|
|
2147
|
+
validateNonEmptyString2(violations, doc.completion_policy, "completion_policy", "workflow.snapshot.missing-completion-policy", "workflow.snapshot.invalid-completion-policy");
|
|
2148
|
+
}
|
|
2149
|
+
if (doc.delivery !== undefined) {
|
|
2150
|
+
violations.push(...deliveryEvidenceViolations(doc.delivery, "delivery"));
|
|
2151
|
+
}
|
|
2072
2152
|
const terminal = typeof doc.status === "string" && WORKFLOW_TERMINAL_STATUSES.includes(doc.status);
|
|
2073
2153
|
if (terminal) {
|
|
2074
2154
|
if (doc.ended_at === undefined) {
|
|
@@ -2283,7 +2363,7 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
2283
2363
|
if (typeof docOrPath === "string") {
|
|
2284
2364
|
try {
|
|
2285
2365
|
doc = readJson(docOrPath);
|
|
2286
|
-
harnessDir = dirname5(
|
|
2366
|
+
harnessDir = dirname5(resolve7(docOrPath));
|
|
2287
2367
|
} catch (error) {
|
|
2288
2368
|
return {
|
|
2289
2369
|
ok: false,
|
|
@@ -2391,7 +2471,7 @@ function resolveCompassEnforcement(harnessDir) {
|
|
|
2391
2471
|
return { hard: false, source: "none" };
|
|
2392
2472
|
let entries;
|
|
2393
2473
|
try {
|
|
2394
|
-
entries =
|
|
2474
|
+
entries = readdirSync3(iterationsDir, { withFileTypes: true });
|
|
2395
2475
|
} catch {
|
|
2396
2476
|
return { hard: false, source: "none" };
|
|
2397
2477
|
}
|
|
@@ -2418,7 +2498,7 @@ function resolveCompassEnforcement(harnessDir) {
|
|
|
2418
2498
|
return { hard: false, source: "none" };
|
|
2419
2499
|
}
|
|
2420
2500
|
function resolveMstarcEnforcement(harnessDir) {
|
|
2421
|
-
const dir =
|
|
2501
|
+
const dir = resolve7(harnessDir);
|
|
2422
2502
|
const rc = loadMstarc(dir, dirname5(dir));
|
|
2423
2503
|
const value = rc?.config.enforcement;
|
|
2424
2504
|
if (value === "hard")
|
|
@@ -2806,14 +2886,14 @@ function findingsCleanupGate(register, planId, opts) {
|
|
|
2806
2886
|
return { ok: violations.length === 0, violations };
|
|
2807
2887
|
}
|
|
2808
2888
|
function resolveHarnessDir(startDir = process.cwd(), opts = {}) {
|
|
2809
|
-
const start =
|
|
2889
|
+
const start = resolve9(startDir);
|
|
2810
2890
|
const explicit = opts.harnessDir ?? process.env.MSTAR_HARNESS_DIR;
|
|
2811
2891
|
if (explicit)
|
|
2812
|
-
return
|
|
2813
|
-
const boundary =
|
|
2892
|
+
return resolve9(start, explicit);
|
|
2893
|
+
const boundary = resolve9(start, opts.workspaceRoot ?? defaultWorkspaceRoot(start));
|
|
2814
2894
|
const rc = loadMstarc(start, boundary);
|
|
2815
2895
|
if (rc !== null && rc.config.harnessDir)
|
|
2816
|
-
return
|
|
2896
|
+
return resolve9(rc.dir, rc.config.harnessDir);
|
|
2817
2897
|
let dir = start;
|
|
2818
2898
|
for (;; ) {
|
|
2819
2899
|
if (!isAtOrBelow2(dir, boundary))
|
|
@@ -2844,7 +2924,7 @@ function defaultWorkspaceRoot(startDir) {
|
|
|
2844
2924
|
if (segment && segment !== ".")
|
|
2845
2925
|
boundary = dirname6(boundary);
|
|
2846
2926
|
}
|
|
2847
|
-
return
|
|
2927
|
+
return resolve9(boundary);
|
|
2848
2928
|
} catch {}
|
|
2849
2929
|
return startDir;
|
|
2850
2930
|
}
|
|
@@ -2853,10 +2933,10 @@ function isAtOrBelow2(dir, root) {
|
|
|
2853
2933
|
return rel === "" || !rel.startsWith("..") && !isAbsolute6(rel);
|
|
2854
2934
|
}
|
|
2855
2935
|
function mstarcDirOverride(harnessDir, key) {
|
|
2856
|
-
const dir =
|
|
2936
|
+
const dir = resolve9(harnessDir);
|
|
2857
2937
|
const rc = loadMstarc(dir, dirname6(dir));
|
|
2858
2938
|
const declared = rc?.config[key];
|
|
2859
|
-
return declared ?
|
|
2939
|
+
return declared ? resolve9(rc.dir, declared) : null;
|
|
2860
2940
|
}
|
|
2861
2941
|
function assertSafePathComponent(value, what) {
|
|
2862
2942
|
if (value === "" || value === "." || value === ".." || !/^[A-Za-z0-9._-]+$/.test(value)) {
|
|
@@ -2864,7 +2944,7 @@ function assertSafePathComponent(value, what) {
|
|
|
2864
2944
|
}
|
|
2865
2945
|
}
|
|
2866
2946
|
function canonicalizeNearestExisting(path) {
|
|
2867
|
-
const abs =
|
|
2947
|
+
const abs = resolve9(path);
|
|
2868
2948
|
let dir = abs;
|
|
2869
2949
|
const tail = [];
|
|
2870
2950
|
for (;; ) {
|
|
@@ -2884,7 +2964,7 @@ function canonicalizeNearestExisting(path) {
|
|
|
2884
2964
|
}
|
|
2885
2965
|
function resolveSddDir(harnessDir, planId) {
|
|
2886
2966
|
assertSafePathComponent(planId, "planId");
|
|
2887
|
-
const base =
|
|
2967
|
+
const base = resolve9(harnessDir);
|
|
2888
2968
|
const declared = mstarcDirOverride(base, "sddDir");
|
|
2889
2969
|
const sddBase = declared !== null ? declared : join10(base, "sdd");
|
|
2890
2970
|
return join10(sddBase, planId);
|
|
@@ -2893,15 +2973,15 @@ function resolveIterationDir(harnessDir) {
|
|
|
2893
2973
|
const declared = mstarcDirOverride(harnessDir, "iterationDir");
|
|
2894
2974
|
if (declared !== null)
|
|
2895
2975
|
return declared;
|
|
2896
|
-
return join10(
|
|
2976
|
+
return join10(resolve9(harnessDir), "iterations");
|
|
2897
2977
|
}
|
|
2898
2978
|
function resolveHarnessSubdir(startDir, opts, key, fallback) {
|
|
2899
2979
|
const harness = resolveHarnessDir(startDir, opts);
|
|
2900
2980
|
if (harness === null) {
|
|
2901
|
-
throw new Error(`harness dir not found from ${
|
|
2981
|
+
throw new Error(`harness dir not found from ${resolve9(startDir)} — cannot resolve the ${fallback} dir (run \`mstar harness scaffold\`, pass opts.harnessDir, or set MSTAR_HARNESS_DIR)`);
|
|
2902
2982
|
}
|
|
2903
2983
|
const declared = mstarcDirOverride(harness, key);
|
|
2904
|
-
return declared !== null ? declared : join10(
|
|
2984
|
+
return declared !== null ? declared : join10(resolve9(harness), fallback);
|
|
2905
2985
|
}
|
|
2906
2986
|
function resolveWorkflowDir(startDir = process.cwd(), opts = {}) {
|
|
2907
2987
|
return resolveHarnessSubdir(startDir, opts, "workflowDir", "workflows");
|
|
@@ -3080,7 +3160,7 @@ function l1PreDispatchCheck(input, opts = {}) {
|
|
|
3080
3160
|
const violations = [];
|
|
3081
3161
|
const checkoutCache = new Map;
|
|
3082
3162
|
const checkout = (path) => {
|
|
3083
|
-
const key =
|
|
3163
|
+
const key = resolve10(path);
|
|
3084
3164
|
if (!checkoutCache.has(key))
|
|
3085
3165
|
checkoutCache.set(key, probeCheckout(path, opts));
|
|
3086
3166
|
return checkoutCache.get(key);
|
|
@@ -3131,7 +3211,7 @@ function l1PreDispatchCheck(input, opts = {}) {
|
|
|
3131
3211
|
}
|
|
3132
3212
|
}
|
|
3133
3213
|
const identityViolation = (aPath, bPath, code, describe, fix) => {
|
|
3134
|
-
if (
|
|
3214
|
+
if (resolve10(aPath) === resolve10(bPath)) {
|
|
3135
3215
|
return violation8("critical", code, `${describe} — the same checkout (normalized path equality) is not isolation`, fix);
|
|
3136
3216
|
}
|
|
3137
3217
|
if (!existsSync9(aPath) || !existsSync9(bPath))
|
|
@@ -3192,7 +3272,7 @@ function l2PreDispatchCheck(input, opts = {}) {
|
|
|
3192
3272
|
violations.push(violation8("high", "worktree.l2.track-path-relative", `track ${index + 1} worktreePath "${track.worktreePath}" is not an absolute path — L2 tracks MUST use absolute worktree checkout paths (consistent with the lease validator's absolute worktree_path enforcement)`, `use an absolute path for track ${index + 1} (e.g. /Users/<you>/worktrees/<branch>)`));
|
|
3193
3273
|
return;
|
|
3194
3274
|
}
|
|
3195
|
-
const normalized =
|
|
3275
|
+
const normalized = resolve10(track.worktreePath);
|
|
3196
3276
|
if (seenPaths.has(normalized)) {
|
|
3197
3277
|
violations.push(violation8("high", "worktree.l2.track-path-collision", `duplicate worktreePath "${track.worktreePath}" across parallel tracks — L2 parallel-writable isolation requires a distinct absolute Worktree path per track (N parallel invokes ≠ isolation)`, "give every parallel track its own git worktree checkout"));
|
|
3198
3278
|
return;
|
|
@@ -3374,7 +3454,7 @@ function hasWorkflowSnapshot(harnessDir) {
|
|
|
3374
3454
|
if (!isDirectory2(workflowsDir))
|
|
3375
3455
|
return false;
|
|
3376
3456
|
try {
|
|
3377
|
-
for (const entry of
|
|
3457
|
+
for (const entry of readdirSync7(workflowsDir, { withFileTypes: true })) {
|
|
3378
3458
|
if (entry.isDirectory() && isFile2(join13(workflowsDir, entry.name, "snapshot.json")))
|
|
3379
3459
|
return true;
|
|
3380
3460
|
}
|
|
@@ -3384,9 +3464,9 @@ function hasWorkflowSnapshot(harnessDir) {
|
|
|
3384
3464
|
return false;
|
|
3385
3465
|
}
|
|
3386
3466
|
function checkoutRootNearestExisting(dir, boundary) {
|
|
3387
|
-
const stop =
|
|
3388
|
-
const startInside = isInside(
|
|
3389
|
-
let current =
|
|
3467
|
+
const stop = resolve11(boundary);
|
|
3468
|
+
const startInside = isInside(resolve11(dir), stop);
|
|
3469
|
+
let current = resolve11(dir);
|
|
3390
3470
|
for (;; ) {
|
|
3391
3471
|
const probed = probeCheckoutRoot(current);
|
|
3392
3472
|
if (probed !== null)
|
|
@@ -3440,12 +3520,12 @@ function sddWorkspace(planId, opts = {}) {
|
|
|
3440
3520
|
const harnessOverride = opts.harnessDir ?? (process.env.MSTAR_HARNESS_DIR || undefined);
|
|
3441
3521
|
let harnessDir;
|
|
3442
3522
|
if (harnessOverride) {
|
|
3443
|
-
harnessDir =
|
|
3523
|
+
harnessDir = resolve11(root, harnessOverride);
|
|
3444
3524
|
} else {
|
|
3445
3525
|
const rc = findMstarc(root, root);
|
|
3446
3526
|
const rcHarnessDir = rc !== null ? parseMstarc(readFileSync9(rc, "utf8")).harnessDir : undefined;
|
|
3447
3527
|
if (rcHarnessDir) {
|
|
3448
|
-
harnessDir =
|
|
3528
|
+
harnessDir = resolve11(rc !== null ? dirname9(rc) : root, rcHarnessDir);
|
|
3449
3529
|
} else {
|
|
3450
3530
|
const probed = probeHarnessWithStatus(root);
|
|
3451
3531
|
if (probed) {
|
|
@@ -3477,7 +3557,7 @@ function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
|
3477
3557
|
const bound = opts.context;
|
|
3478
3558
|
const observedCwd = opts.cwd ?? process.cwd();
|
|
3479
3559
|
if (bound) {
|
|
3480
|
-
const inputPlan = canonicalizeNearestExisting(
|
|
3560
|
+
const inputPlan = canonicalizeNearestExisting(resolve11(observedCwd, planFile));
|
|
3481
3561
|
if (inputPlan !== canonicalizeNearestExisting(bound.planFile)) {
|
|
3482
3562
|
throwGateFail([
|
|
3483
3563
|
contextViolation("high", "sdd.context.plan-file-mismatch", `plan file "${planFile}" does not match the bound context plan file "${bound.planFile}" — ` + "bound mode extracts only the resolved context's plan; refused before any read or write")
|
|
@@ -3493,7 +3573,7 @@ function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
|
3493
3573
|
let out;
|
|
3494
3574
|
let mkdirAfterGate = null;
|
|
3495
3575
|
if (outFile) {
|
|
3496
|
-
out = bound ?
|
|
3576
|
+
out = bound ? resolve11(observedCwd, outFile) : outFile;
|
|
3497
3577
|
} else if (bound) {
|
|
3498
3578
|
out = join13(bound.sddDir, `task-${taskN}-brief.md`);
|
|
3499
3579
|
mkdirAfterGate = bound.sddDir;
|
|
@@ -3536,7 +3616,7 @@ function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
|
3536
3616
|
if (printed.length === 0) {
|
|
3537
3617
|
throw new SddScriptError(`task ${taskN} not found in ${planFile} (no heading matching Task ${taskN})`, 3);
|
|
3538
3618
|
}
|
|
3539
|
-
return bound ?
|
|
3619
|
+
return bound ? resolve11(observedCwd, out) : out;
|
|
3540
3620
|
}
|
|
3541
3621
|
function isInside(child, ancestor) {
|
|
3542
3622
|
const rel = relative3(ancestor, child);
|
|
@@ -3574,11 +3654,11 @@ function checkSddAction(context, action) {
|
|
|
3574
3654
|
const featureReal = canonicalDir(context.featureCwd);
|
|
3575
3655
|
const canonicalSddDir = canonicalizeNearestExisting(context.sddDir);
|
|
3576
3656
|
const canonicalPlanFile = canonicalizeNearestExisting(context.planFile);
|
|
3577
|
-
const cwdResolved =
|
|
3657
|
+
const cwdResolved = resolve11(action.cwd);
|
|
3578
3658
|
const checkTarget = (baseDir, target, kind) => {
|
|
3579
3659
|
if (featureReal === null)
|
|
3580
3660
|
return;
|
|
3581
|
-
const targetAbs =
|
|
3661
|
+
const targetAbs = resolve11(baseDir, target);
|
|
3582
3662
|
const canonical = canonicalizeNearestExisting(targetAbs);
|
|
3583
3663
|
if (!isInside(canonical, featureReal)) {
|
|
3584
3664
|
const declaredPrefix = targetAbs === featureReal || targetAbs.startsWith(`${featureReal}/`);
|
|
@@ -3606,10 +3686,10 @@ function checkSddAction(context, action) {
|
|
|
3606
3686
|
add("sdd.context.target-missing", "artifact checks require the destination target");
|
|
3607
3687
|
return { ok: false, violations };
|
|
3608
3688
|
}
|
|
3609
|
-
const targetAbs =
|
|
3689
|
+
const targetAbs = resolve11(cwdResolved, action.target);
|
|
3610
3690
|
const canonical = canonicalizeNearestExisting(targetAbs);
|
|
3611
3691
|
if (!isInside(canonical, canonicalSddDir) && canonical !== canonicalPlanFile) {
|
|
3612
|
-
const rawSddDir =
|
|
3692
|
+
const rawSddDir = resolve11(context.sddDir);
|
|
3613
3693
|
const declaredPrefix = targetAbs === rawSddDir || targetAbs.startsWith(`${rawSddDir}/`) || targetAbs === canonicalSddDir || targetAbs.startsWith(`${canonicalSddDir}/`) || targetAbs === canonicalPlanFile;
|
|
3614
3694
|
if (declaredPrefix) {
|
|
3615
3695
|
add("sdd.context.artifact-symlink-escape", `artifact target "${targetAbs}" canonicalizes to "${canonical}", outside the plan's control sddDir — symlink escape refused before write`);
|
|
@@ -4361,7 +4441,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
4361
4441
|
const dir = stack.pop();
|
|
4362
4442
|
let entries;
|
|
4363
4443
|
try {
|
|
4364
|
-
entries =
|
|
4444
|
+
entries = readdirSync10(dir, { withFileTypes: true });
|
|
4365
4445
|
} catch {
|
|
4366
4446
|
continue;
|
|
4367
4447
|
}
|
|
@@ -4382,7 +4462,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
4382
4462
|
for (const { ref, isSymbol, module } of refs) {
|
|
4383
4463
|
if (!isSymbol || module === undefined) {
|
|
4384
4464
|
const candidate = ref.replace(LINE_SUFFIX_RE, "").replace(ANCHOR_RE, "");
|
|
4385
|
-
if (existsSync13(
|
|
4465
|
+
if (existsSync13(resolve15(repoRoot, candidate))) {
|
|
4386
4466
|
checked++;
|
|
4387
4467
|
} else {
|
|
4388
4468
|
violations.push(violation11("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"));
|
|
@@ -4402,7 +4482,7 @@ function collectKnowledgeDocs(dir) {
|
|
|
4402
4482
|
const current = stack.pop();
|
|
4403
4483
|
let entries;
|
|
4404
4484
|
try {
|
|
4405
|
-
entries =
|
|
4485
|
+
entries = readdirSync10(current, { withFileTypes: true });
|
|
4406
4486
|
} catch {
|
|
4407
4487
|
continue;
|
|
4408
4488
|
}
|
|
@@ -4457,9 +4537,9 @@ function isFileLikeRoot(root) {
|
|
|
4457
4537
|
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(basename11(root));
|
|
4458
4538
|
}
|
|
4459
4539
|
function scopeGuard(path, allowedRoots) {
|
|
4460
|
-
const resolved =
|
|
4540
|
+
const resolved = resolve15(path);
|
|
4461
4541
|
for (const root of allowedRoots) {
|
|
4462
|
-
const r =
|
|
4542
|
+
const r = resolve15(root);
|
|
4463
4543
|
if (isFileLikeRoot(r)) {
|
|
4464
4544
|
if (resolved === r)
|
|
4465
4545
|
return { ok: true, violations: [] };
|
|
@@ -5056,7 +5136,7 @@ function skillLocalConfig(config) {
|
|
|
5056
5136
|
}
|
|
5057
5137
|
|
|
5058
5138
|
// src/gates/catalog.ts
|
|
5059
|
-
import { existsSync as existsSync15, readFileSync as readFileSync10, readdirSync as
|
|
5139
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10, readdirSync as readdirSync5, realpathSync as realpathSync6 } from "node:fs";
|
|
5060
5140
|
import { basename as basename6, isAbsolute as isAbsolute9, join as join19, relative as relative7, sep as sep3 } from "node:path";
|
|
5061
5141
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
5062
5142
|
|
|
@@ -5066,7 +5146,7 @@ import { join as join14 } from "node:path";
|
|
|
5066
5146
|
|
|
5067
5147
|
// src/gates/dispatch.ts
|
|
5068
5148
|
import { existsSync as existsSync7 } from "node:fs";
|
|
5069
|
-
import { basename as basename3, join as join8, resolve as
|
|
5149
|
+
import { basename as basename3, join as join8, resolve as resolve8 } from "node:path";
|
|
5070
5150
|
|
|
5071
5151
|
// src/gates/workflow-selection.ts
|
|
5072
5152
|
import { existsSync as existsSync3, readdirSync, realpathSync, statSync as statSync2 } from "node:fs";
|
|
@@ -5570,7 +5650,7 @@ function leaseGateViolations(harnessDir, exec, writable, prompt, hint) {
|
|
|
5570
5650
|
const wt = worktree === undefined ? undefined : firstToken(worktree);
|
|
5571
5651
|
if (isNaValue(wt)) {
|
|
5572
5652
|
violations.push(leaseViolation("lease.dispatch.worktree-mismatch", "Assignment declares no Worktree path — cannot confirm this dispatch matches execution_lease.worktree_path", "add the absolute Worktree path to the Assignment (must equal the lease worktree_path)"));
|
|
5573
|
-
} else if (
|
|
5653
|
+
} else if (resolve8(wt) !== resolve8(String(lease.worktree_path ?? ""))) {
|
|
5574
5654
|
violations.push(leaseViolation("lease.dispatch.worktree-mismatch", `Assignment Worktree path "${wt}" differs from execution_lease.worktree_path "${String(lease.worktree_path)}"`, "align the Assignment with the lease worktree path (or update the lease)"));
|
|
5575
5655
|
}
|
|
5576
5656
|
const forms = parseAssignmentBranchForms(header);
|
|
@@ -5839,10 +5919,16 @@ function assignmentTextFromFields(fields) {
|
|
|
5839
5919
|
lines.push(`**Delegation**: ${fields.delegation}`);
|
|
5840
5920
|
if (fields.taskCategory !== undefined)
|
|
5841
5921
|
lines.push(`**Task category**: ${fields.taskCategory}`);
|
|
5922
|
+
if (fields.taskBudget !== undefined)
|
|
5923
|
+
lines.push(`**Task budget (implement / ops rounds)**: ${fields.taskBudget}`);
|
|
5842
5924
|
if (fields.workingBranch !== undefined)
|
|
5843
5925
|
lines.push(`**Working branch**: ${fields.workingBranch}`);
|
|
5844
5926
|
if (fields.branchPolicy !== undefined)
|
|
5845
5927
|
lines.push(`**Branch policy**: ${fields.branchPolicy}`);
|
|
5928
|
+
if (fields.budget !== undefined)
|
|
5929
|
+
lines.push(`**Budget (review / QC seats)**: ${fields.budget}`);
|
|
5930
|
+
if (fields.returnShape !== undefined)
|
|
5931
|
+
lines.push(`**Return shape (review / QC seats)**: ${fields.returnShape}`);
|
|
5846
5932
|
return lines.join(`
|
|
5847
5933
|
`);
|
|
5848
5934
|
}
|
|
@@ -7428,7 +7514,7 @@ function projectRollupSource(harnessDir, residuals) {
|
|
|
7428
7514
|
if (existsSync15(projectsDir)) {
|
|
7429
7515
|
let entries;
|
|
7430
7516
|
try {
|
|
7431
|
-
entries =
|
|
7517
|
+
entries = readdirSync5(projectsDir, { withFileTypes: true });
|
|
7432
7518
|
} catch {
|
|
7433
7519
|
entries = [];
|
|
7434
7520
|
}
|
|
@@ -7505,7 +7591,7 @@ function projectRegisters(harnessDir) {
|
|
|
7505
7591
|
return [];
|
|
7506
7592
|
let entries;
|
|
7507
7593
|
try {
|
|
7508
|
-
entries =
|
|
7594
|
+
entries = readdirSync5(projectsDir, { withFileTypes: true });
|
|
7509
7595
|
} catch {
|
|
7510
7596
|
return [];
|
|
7511
7597
|
}
|
|
@@ -7994,11 +8080,11 @@ function installEngineStatusEndpoint(ctx, options) {
|
|
|
7994
8080
|
}
|
|
7995
8081
|
|
|
7996
8082
|
// src/gates/status.ts
|
|
7997
|
-
import { existsSync as existsSync17, readdirSync as
|
|
7998
|
-
import { basename as basename8, join as join21, relative as relative9, resolve as
|
|
8083
|
+
import { existsSync as existsSync17, readdirSync as readdirSync8 } from "node:fs";
|
|
8084
|
+
import { basename as basename8, join as join21, relative as relative9, resolve as resolve12 } from "node:path";
|
|
7999
8085
|
var LOGGER_NAME = "mstar/status-gate";
|
|
8000
8086
|
function harnessDocKindOfTarget(harnessDir, targetPath) {
|
|
8001
|
-
const resolved =
|
|
8087
|
+
const resolved = resolve12(targetPath);
|
|
8002
8088
|
const name = basename8(resolved);
|
|
8003
8089
|
if (name !== STATUS_FILE && name !== WORKFLOW_SNAPSHOT_FILE && name !== PROJECT_REGISTER_FILE)
|
|
8004
8090
|
return null;
|
|
@@ -8068,7 +8154,7 @@ function projectRegisterDocs(harnessDir) {
|
|
|
8068
8154
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
8069
8155
|
let entries;
|
|
8070
8156
|
try {
|
|
8071
|
-
entries =
|
|
8157
|
+
entries = readdirSync8(projectsDir, { withFileTypes: true });
|
|
8072
8158
|
} catch {
|
|
8073
8159
|
return [];
|
|
8074
8160
|
}
|
|
@@ -8151,7 +8237,7 @@ async function editIntentListener(ctx, resolver, config, adapter, target, actor,
|
|
|
8151
8237
|
|
|
8152
8238
|
// src/gates/skill-lint.ts
|
|
8153
8239
|
import { existsSync as existsSync18, readFileSync as readFileSync13 } from "node:fs";
|
|
8154
|
-
import { basename as basename9, dirname as dirname12, resolve as
|
|
8240
|
+
import { basename as basename9, dirname as dirname12, resolve as resolve14, sep as sep6 } from "node:path";
|
|
8155
8241
|
var SKILL_LINT_LOGGER = "mstar/skill-lint";
|
|
8156
8242
|
|
|
8157
8243
|
class SkillLintVetoError extends Error {
|
|
@@ -8192,7 +8278,7 @@ function lintSkillDoc(doc, options = {}) {
|
|
|
8192
8278
|
return violations.length === 0 ? { ok: true, violations } : { ok: false, violations };
|
|
8193
8279
|
}
|
|
8194
8280
|
function lintSkillWrite(doc, options) {
|
|
8195
|
-
const skillId = basename9(dirname12(
|
|
8281
|
+
const skillId = basename9(dirname12(resolve14(options.target)));
|
|
8196
8282
|
const result = lintSkillDoc(doc, { skillId });
|
|
8197
8283
|
if (options.hard && !result.ok) {
|
|
8198
8284
|
throw new SkillLintVetoError(options.target, result.violations);
|
|
@@ -8207,8 +8293,8 @@ function skillRootsOf(config) {
|
|
|
8207
8293
|
function isSkillTarget(roots, target) {
|
|
8208
8294
|
if (basename9(target.displayPath) !== "SKILL.md")
|
|
8209
8295
|
return false;
|
|
8210
|
-
const resolvedPath =
|
|
8211
|
-
return roots.some((root) => resolvedPath.startsWith(
|
|
8296
|
+
const resolvedPath = resolve14(target.displayPath);
|
|
8297
|
+
return roots.some((root) => resolvedPath.startsWith(resolve14(root) + sep6));
|
|
8212
8298
|
}
|
|
8213
8299
|
function skillNameOf(target) {
|
|
8214
8300
|
return basename9(dirname12(target.displayPath));
|
|
@@ -8223,7 +8309,7 @@ function gateSkillIntent(ctx, harnessDir, config, target) {
|
|
|
8223
8309
|
return;
|
|
8224
8310
|
if (!isSkillTarget(roots, target))
|
|
8225
8311
|
return;
|
|
8226
|
-
const skillPath =
|
|
8312
|
+
const skillPath = resolve14(target.displayPath);
|
|
8227
8313
|
if (!existsSync18(skillPath))
|
|
8228
8314
|
return;
|
|
8229
8315
|
let doc;
|
|
@@ -8275,8 +8361,8 @@ async function skillWriteIntentListener(ctx, resolver, config, target, actor, ne
|
|
|
8275
8361
|
}
|
|
8276
8362
|
|
|
8277
8363
|
// src/gates/seams.ts
|
|
8278
|
-
import { existsSync as existsSync19, readFileSync as readFileSync15, readdirSync as
|
|
8279
|
-
import { basename as basename10, dirname as dirname13, join as join22, resolve as
|
|
8364
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15, readdirSync as readdirSync11 } from "node:fs";
|
|
8365
|
+
import { basename as basename10, dirname as dirname13, join as join22, resolve as resolve16, sep as sep8 } from "node:path";
|
|
8280
8366
|
|
|
8281
8367
|
// ../engine/dist/audit.js
|
|
8282
8368
|
import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
|
|
@@ -8486,7 +8572,7 @@ function isMarkdownDoc(path) {
|
|
|
8486
8572
|
function isAuditPlanTarget(path) {
|
|
8487
8573
|
if (!isMarkdownDoc(path))
|
|
8488
8574
|
return false;
|
|
8489
|
-
const segments =
|
|
8575
|
+
const segments = resolve16(path).split(sep8);
|
|
8490
8576
|
for (let i = 0;i < segments.length; i++) {
|
|
8491
8577
|
if (segments[i] !== "plans")
|
|
8492
8578
|
continue;
|
|
@@ -8497,7 +8583,7 @@ function isAuditPlanTarget(path) {
|
|
|
8497
8583
|
return false;
|
|
8498
8584
|
}
|
|
8499
8585
|
function isRolesTarget(path) {
|
|
8500
|
-
const segments =
|
|
8586
|
+
const segments = resolve16(path).split(sep8);
|
|
8501
8587
|
const idx = segments.indexOf("mstar-roles");
|
|
8502
8588
|
if (idx === -1)
|
|
8503
8589
|
return false;
|
|
@@ -8507,14 +8593,14 @@ function isRolesTarget(path) {
|
|
|
8507
8593
|
return rest[0] === "SKILL.md" || rest[0] === "references" && rest[rest.length - 1].endsWith(".md");
|
|
8508
8594
|
}
|
|
8509
8595
|
function rolesDirOf(path) {
|
|
8510
|
-
const segments =
|
|
8596
|
+
const segments = resolve16(path).split(sep8);
|
|
8511
8597
|
const idx = segments.indexOf("mstar-roles");
|
|
8512
8598
|
if (idx === -1)
|
|
8513
8599
|
return dirname13(path);
|
|
8514
8600
|
return idx === 0 ? sep8 : join22(sep8, ...segments.slice(1, idx + 1));
|
|
8515
8601
|
}
|
|
8516
8602
|
function isSeamTarget(seam, harnessDir, target) {
|
|
8517
|
-
const path =
|
|
8603
|
+
const path = resolve16(target.displayPath);
|
|
8518
8604
|
switch (seam) {
|
|
8519
8605
|
case "design-md": {
|
|
8520
8606
|
const base = basename10(path);
|
|
@@ -8525,7 +8611,7 @@ function isSeamTarget(seam, harnessDir, target) {
|
|
|
8525
8611
|
case "compound": {
|
|
8526
8612
|
if (harnessDir === null)
|
|
8527
8613
|
return false;
|
|
8528
|
-
return path.startsWith(
|
|
8614
|
+
return path.startsWith(resolve16(join22(harnessDir, "knowledge")) + sep8) && isMarkdownDoc(path);
|
|
8529
8615
|
}
|
|
8530
8616
|
case "roles":
|
|
8531
8617
|
return isRolesTarget(path);
|
|
@@ -8567,7 +8653,7 @@ function validateCompoundDoc(doc, _path, harnessDir) {
|
|
|
8567
8653
|
function validateRolesState(rolesDir, skillsRoot = dirname13(rolesDir)) {
|
|
8568
8654
|
const violations = [...validateRoleMapping(rolesDir).violations];
|
|
8569
8655
|
const skillTexts = {};
|
|
8570
|
-
for (const entry of
|
|
8656
|
+
for (const entry of readdirSync11(skillsRoot, { withFileTypes: true })) {
|
|
8571
8657
|
if (!entry.isDirectory() || !entry.name.startsWith("mstar-"))
|
|
8572
8658
|
continue;
|
|
8573
8659
|
const skillFile = join22(skillsRoot, entry.name, "SKILL.md");
|
|
@@ -8604,7 +8690,7 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
8604
8690
|
try {
|
|
8605
8691
|
if (!isSeamTarget(seam, harnessDir, target))
|
|
8606
8692
|
return;
|
|
8607
|
-
const path =
|
|
8693
|
+
const path = resolve16(target.displayPath);
|
|
8608
8694
|
if (!existsSync19(path))
|
|
8609
8695
|
return;
|
|
8610
8696
|
let doc;
|
|
@@ -8676,7 +8762,7 @@ function lintRolesWrite(doc, options) {
|
|
|
8676
8762
|
|
|
8677
8763
|
// src/gates/tools.ts
|
|
8678
8764
|
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
|
|
8679
|
-
import { join as join23, resolve as
|
|
8765
|
+
import { join as join23, resolve as resolve18 } from "node:path";
|
|
8680
8766
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
8681
8767
|
var ITERATION_VIOLATION_SCHEMA = {
|
|
8682
8768
|
type: "object",
|
|
@@ -8896,7 +8982,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
8896
8982
|
presentCall: (args) => ({ card: "generic", title: "Validate DESIGN.md", kind: "other", rawInput: args.dir }),
|
|
8897
8983
|
isConcurrencySafe: () => false,
|
|
8898
8984
|
async execute(args) {
|
|
8899
|
-
const abs =
|
|
8985
|
+
const abs = resolve18(args.dir);
|
|
8900
8986
|
const lightPath = join23(abs, "DESIGN.md");
|
|
8901
8987
|
if (!existsSync20(lightPath))
|
|
8902
8988
|
throw new Error(`design file not found: ${lightPath}`);
|
|
@@ -8950,7 +9036,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
8950
9036
|
presentCall: (args) => ({ card: "generic", title: "Validate audit plan", kind: "other", rawInput: args.plan_path }),
|
|
8951
9037
|
isConcurrencySafe: () => false,
|
|
8952
9038
|
async execute(args) {
|
|
8953
|
-
const abs =
|
|
9039
|
+
const abs = resolve18(args.plan_path);
|
|
8954
9040
|
if (!existsSync20(abs))
|
|
8955
9041
|
throw new Error(`plan file not found: ${abs}`);
|
|
8956
9042
|
const text = readFileSync16(abs, "utf8");
|
|
@@ -8990,17 +9076,17 @@ function registerSeamTools(ctx, resolver) {
|
|
|
8990
9076
|
presentCall: (args) => ({ card: "generic", title: "Validate knowledge doc", kind: "other", rawInput: args.doc_path }),
|
|
8991
9077
|
isConcurrencySafe: () => false,
|
|
8992
9078
|
async execute(args, exec) {
|
|
8993
|
-
const abs =
|
|
9079
|
+
const abs = resolve18(args.doc_path);
|
|
8994
9080
|
if (!existsSync20(abs))
|
|
8995
9081
|
throw new Error(`knowledge doc not found: ${abs}`);
|
|
8996
9082
|
const text = readFileSync16(abs, "utf8");
|
|
8997
9083
|
const base = validateCompoundDoc(text, abs, args.repo_root !== undefined ? null : resolver.forAgent(exec.agent));
|
|
8998
9084
|
const violations = [...base.violations];
|
|
8999
9085
|
if (args.repo_root !== undefined) {
|
|
9000
|
-
violations.push(...referenceExists(
|
|
9086
|
+
violations.push(...referenceExists(resolve18(args.repo_root), text).violations);
|
|
9001
9087
|
}
|
|
9002
9088
|
if (args.knowledge_dir !== undefined) {
|
|
9003
|
-
const knowledgeDir =
|
|
9089
|
+
const knowledgeDir = resolve18(args.knowledge_dir);
|
|
9004
9090
|
violations.push(...assertIndexRows(knowledgeDir).violations);
|
|
9005
9091
|
violations.push(...scopeGuard(abs, [knowledgeDir]).violations);
|
|
9006
9092
|
}
|
|
@@ -9035,10 +9121,10 @@ function registerSeamTools(ctx, resolver) {
|
|
|
9035
9121
|
presentCall: (args) => ({ card: "generic", title: "Validate roles mapping", kind: "other", rawInput: args.roles_dir }),
|
|
9036
9122
|
isConcurrencySafe: () => false,
|
|
9037
9123
|
async execute(args) {
|
|
9038
|
-
const rolesDir =
|
|
9124
|
+
const rolesDir = resolve18(args.roles_dir);
|
|
9039
9125
|
if (!existsSync20(join23(rolesDir, "SKILL.md")))
|
|
9040
9126
|
throw new Error(`roles dir not found: ${rolesDir}`);
|
|
9041
|
-
const result = validateRolesState(rolesDir, args.skills_root !== undefined ?
|
|
9127
|
+
const result = validateRolesState(rolesDir, args.skills_root !== undefined ? resolve18(args.skills_root) : undefined);
|
|
9042
9128
|
return { ok: result.ok, violations: result.violations.map(iterationViolationView) };
|
|
9043
9129
|
}
|
|
9044
9130
|
}));
|
|
@@ -9188,8 +9274,8 @@ class DshHostAdapter extends Service3 {
|
|
|
9188
9274
|
}
|
|
9189
9275
|
|
|
9190
9276
|
// src/gates/agent-personas.ts
|
|
9191
|
-
import { readFileSync as readFileSync17, readdirSync as
|
|
9192
|
-
import { join as join25, resolve as
|
|
9277
|
+
import { readFileSync as readFileSync17, readdirSync as readdirSync13, statSync as statSync8 } from "node:fs";
|
|
9278
|
+
import { join as join25, resolve as resolve19, sep as sep9 } from "node:path";
|
|
9193
9279
|
var ROLE_ID_PATTERN = /^[a-z0-9-]{1,32}$/;
|
|
9194
9280
|
var defaultCache = new Map;
|
|
9195
9281
|
function personaFor(roleId, lookup, warn) {
|
|
@@ -9206,7 +9292,7 @@ function personaFor(roleId, lookup, warn) {
|
|
|
9206
9292
|
function subagentRoleIds(agentsDir) {
|
|
9207
9293
|
let names;
|
|
9208
9294
|
try {
|
|
9209
|
-
names =
|
|
9295
|
+
names = readdirSync13(agentsDir);
|
|
9210
9296
|
} catch {
|
|
9211
9297
|
return [];
|
|
9212
9298
|
}
|
|
@@ -9230,8 +9316,8 @@ function subagentRoleIds(agentsDir) {
|
|
|
9230
9316
|
function defaultFromMirror(agentsDir, roleId, warn) {
|
|
9231
9317
|
if (!ROLE_ID_PATTERN.test(roleId))
|
|
9232
9318
|
return;
|
|
9233
|
-
const root =
|
|
9234
|
-
const file =
|
|
9319
|
+
const root = resolve19(agentsDir);
|
|
9320
|
+
const file = resolve19(agentsDir, `${roleId}.md`);
|
|
9235
9321
|
if (!file.startsWith(root + sep9))
|
|
9236
9322
|
return;
|
|
9237
9323
|
let stat;
|
|
@@ -9881,7 +9967,7 @@ function registerWorkflowLedger(ctx, resolver, workflowAskCache) {
|
|
|
9881
9967
|
}
|
|
9882
9968
|
|
|
9883
9969
|
// src/gates/goal-bridge.ts
|
|
9884
|
-
import { existsSync as existsSync22, readdirSync as
|
|
9970
|
+
import { existsSync as existsSync22, readdirSync as readdirSync14 } from "node:fs";
|
|
9885
9971
|
import { join as join27 } from "node:path";
|
|
9886
9972
|
var GOAL_BRIDGE_LOGGER = "mstar/goal-bridge";
|
|
9887
9973
|
var GOAL_CHANGE_EVENT_TYPE = "goal/change";
|
|
@@ -9904,7 +9990,7 @@ function errorMessage4(error) {
|
|
|
9904
9990
|
function projectRegisterPointer(harnessDir) {
|
|
9905
9991
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
9906
9992
|
try {
|
|
9907
|
-
for (const entry of
|
|
9993
|
+
for (const entry of readdirSync14(projectsDir, { withFileTypes: true })) {
|
|
9908
9994
|
if (!entry.isDirectory())
|
|
9909
9995
|
continue;
|
|
9910
9996
|
const registerPath = join27(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
@@ -10598,7 +10684,7 @@ function registerMstarCommands(ctx) {
|
|
|
10598
10684
|
if (dir === undefined)
|
|
10599
10685
|
return;
|
|
10600
10686
|
ctx.inject(["commands"], (commandsCtx) => {
|
|
10601
|
-
for (const file of
|
|
10687
|
+
for (const file of readdirSync15(dir).sort()) {
|
|
10602
10688
|
if (!file.endsWith(".md"))
|
|
10603
10689
|
continue;
|
|
10604
10690
|
const parsed = parseCommandMarkdown(readFileSync19(join29(dir, file), "utf8"));
|