@mstar-harness/dsh 3.1.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/client/panel/graph/schema.d.ts +1 -1
- package/dist/gates/_shared.d.ts +1 -1
- package/dist/gates/status.d.ts +7 -1
- package/dist/gates/workflow-selection.d.ts +7 -0
- package/dist/index.js +220 -154
- package/harness-commands/codebase-audit.md +3 -3
- package/harness-commands/iteration-drive.md +9 -90
- package/harness-commands/iteration-loop.md +22 -62
- package/harness-commands/iteration-start.md +20 -77
- package/harness-commands/pr-deep-review.md +37 -0
- package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/SKILL.md +3 -3
- package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/references/knowledge-and-designs.md +8 -8
- package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/references/plan-files-and-reports.md +6 -6
- package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/references/status-and-residuals.md +3 -3
- package/harness-skills/mstar-artifacts/templates/README.md +7 -0
- package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/templates/plan.main.md +1 -1
- package/harness-skills/mstar-audit/SKILL.md +36 -89
- package/harness-skills/mstar-audit/references/audit-playbook.md +1 -1
- package/harness-skills/mstar-audit/references/codebase-audit.md +85 -0
- package/harness-skills/mstar-audit/references/pr-review.md +139 -0
- package/harness-skills/mstar-branch-worktree/SKILL.md +5 -5
- package/harness-skills/mstar-compound/SKILL.md +4 -4
- package/harness-skills/mstar-compound/references/compound-workflow.md +1 -1
- package/harness-skills/mstar-compound-refresh/SKILL.md +4 -4
- package/harness-skills/mstar-compound-refresh/references/project-knowledge-bootstrap.md +3 -3
- package/harness-skills/{mstar-plan-conventions → mstar-conventions}/SKILL.md +9 -9
- package/harness-skills/{mstar-plan-conventions → mstar-conventions}/references/artifact-storage-paths.md +13 -13
- package/harness-skills/{mstar-plan-conventions → mstar-conventions}/references/harness-bootstrap-and-agents-layering.md +5 -5
- package/harness-skills/mstar-design-md/SKILL.md +3 -3
- package/harness-skills/mstar-dispatch-gates/SKILL.md +3 -3
- package/harness-skills/mstar-engine-legacy/SKILL.md +1 -1
- package/harness-skills/mstar-engine-legacy/references/lease-protocol.md +1 -1
- package/harness-skills/mstar-engine-legacy/references/status-field-history.md +1 -1
- package/harness-skills/mstar-harness-core/SKILL.md +21 -20
- package/harness-skills/mstar-host/references/_shared/plan-mode-bridge-core.md +5 -5
- package/harness-skills/mstar-host/references/cursor-plan-mode-bridge.md +7 -7
- package/harness-skills/mstar-host/references/cursor.md +1 -1
- package/harness-skills/mstar-host/references/kimi-plan-mode-bridge.md +1 -1
- package/harness-skills/mstar-host/references/omp-plan-mode-bridge.md +1 -1
- package/harness-skills/mstar-host/references/parallel-dispatch.md +1 -1
- package/harness-skills/mstar-host/references/zcode-plan-mode-bridge.md +1 -1
- package/harness-skills/mstar-iteration/SKILL.md +21 -15
- package/harness-skills/mstar-iteration/references/command-shared-invariants.md +62 -0
- package/harness-skills/mstar-iteration/references/iteration-artifact-boundaries.md +1 -1
- package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +5 -5
- package/harness-skills/mstar-iteration/references/phase-3-iteration-close.md +1 -1
- package/harness-skills/mstar-iteration/references/phase-4-5-pr-delivery.md +1 -1
- package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +1 -1
- package/harness-skills/mstar-phase-gates/SKILL.md +5 -5
- package/harness-skills/mstar-project-governance/SKILL.md +9 -9
- package/harness-skills/mstar-review-qc/SKILL.md +4 -4
- package/harness-skills/mstar-roles/SKILL.md +7 -7
- package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +20 -2
- package/harness-skills/mstar-roles/references/architect.md +7 -10
- package/harness-skills/mstar-roles/references/code-reviewer.md +7 -10
- package/harness-skills/mstar-roles/references/frontend-dev.md +6 -5
- package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +6 -5
- package/harness-skills/mstar-roles/references/ops-engineer.md +3 -7
- package/harness-skills/mstar-roles/references/product-manager.md +8 -11
- package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +1 -1
- package/harness-skills/mstar-roles/references/project-manager/plan-management.md +3 -3
- package/harness-skills/mstar-roles/references/project-manager/qa-trigger-matrix.md +2 -2
- package/harness-skills/mstar-roles/references/project-manager/qc-and-residuals.md +3 -3
- package/harness-skills/mstar-roles/references/project-manager.md +5 -5
- package/harness-skills/mstar-roles/references/prompt-engineer.md +4 -7
- package/harness-skills/mstar-roles/references/qa-engineer/acceptance-gate.md +2 -2
- package/harness-skills/mstar-roles/references/qa-engineer.md +4 -8
- package/harness-skills/mstar-roles/references/qc-specialist/report-template.md +1 -1
- package/harness-skills/mstar-roles/references/qc-specialist/reviewer-workflow.md +1 -1
- package/harness-skills/mstar-roles/references/qc-specialist-shared.md +5 -8
- package/harness-skills/mstar-roles/references/writing-specialist.md +3 -6
- package/harness-skills/mstar-sdd/SKILL.md +2 -2
- package/harness-skills/mstar-sdd/references/file-handoffs.md +1 -1
- package/harness-skills/mstar-strategy/SKILL.md +8 -38
- package/package.json +14 -14
- package/harness-skills/mstar-plan-artifacts/templates/README.md +0 -7
- /package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/references/plan-quality-bar.md +0 -0
- /package/harness-skills/{mstar-plan-artifacts → mstar-artifacts}/templates/status.empty.json +0 -0
- /package/harness-skills/{mstar-plan-conventions → mstar-conventions}/references/effort-estimation.md +0 -0
package/dist/index.js
CHANGED
|
@@ -1106,7 +1106,7 @@ var require_lib2 = __commonJS((exports, module) => {
|
|
|
1106
1106
|
});
|
|
1107
1107
|
|
|
1108
1108
|
// src/index.ts
|
|
1109
|
-
import { existsSync as
|
|
1109
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18, readdirSync as readdirSync14 } from "node:fs";
|
|
1110
1110
|
import { join as join23 } from "node:path";
|
|
1111
1111
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1112
1112
|
import {
|
|
@@ -1136,9 +1136,9 @@ import { execFileSync as execFileSync3 } from "node:child_process";
|
|
|
1136
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
1138
|
import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "node:fs";
|
|
1139
|
-
import { existsSync as
|
|
1140
|
-
import { basename as
|
|
1141
|
-
import { existsSync as
|
|
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) {
|
|
@@ -2080,7 +2080,7 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
2080
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`));
|
|
2081
2081
|
}
|
|
2082
2082
|
if (typeof entry.started_at === "string" && typeof snapshot.started_at === "string" && entry.started_at !== snapshot.started_at) {
|
|
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)} — the root entry mirrors the snapshot
|
|
2083
|
+
violations.push(violation4("medium", "status.workflow.mismatched-started-at", `workflows[] entry ${JSON.stringify(label)} started_at ${JSON.stringify(entry.started_at)} does not match its snapshot started_at ${JSON.stringify(snapshot.started_at)} — workflow ${JSON.stringify(label)} collided with another writer (e.g. a concurrent/re-run \`audit promote\` with the same workflow id rewrote the snapshot); the root entry mirrors the snapshot — align them or remove the colliding workflow`));
|
|
2084
2084
|
}
|
|
2085
2085
|
}
|
|
2086
2086
|
}
|
|
@@ -3217,14 +3217,14 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3217
3217
|
const violations = [];
|
|
3218
3218
|
const blocks = parseStatusBlocks(planText);
|
|
3219
3219
|
if (blocks.length === 0) {
|
|
3220
|
-
violations.push(violation9("medium", "audit.status.missing-block", "no `## Status` block found — audit plan files carry the Status block fields (mstar-audit SKILL § Plan
|
|
3220
|
+
violations.push(violation9("medium", "audit.status.missing-block", "no `## Status` block found — audit plan files carry the Status block fields (mstar-audit SKILL.md § Plan output)", "add a `## Status` block with Priority, Effort, Risk, Depends on, Category, Planned at"));
|
|
3221
3221
|
return { ok: false, violations };
|
|
3222
3222
|
}
|
|
3223
3223
|
blocks.forEach((block, index) => {
|
|
3224
3224
|
const label = blocks.length > 1 ? ` #${index + 1}` : "";
|
|
3225
3225
|
for (const field of AUDIT_STATUS_FIELDS) {
|
|
3226
3226
|
if (!block.fields.has(field)) {
|
|
3227
|
-
violations.push(violation9("medium", "audit.status.missing-field", `Status block${label} missing required field "${field}" (mstar-audit SKILL § Plan
|
|
3227
|
+
violations.push(violation9("medium", "audit.status.missing-field", `Status block${label} missing required field "${field}" (mstar-audit SKILL.md § Plan output)`, `add \`- **${field}**: <value>\` to the Status block`));
|
|
3228
3228
|
}
|
|
3229
3229
|
}
|
|
3230
3230
|
const check = (field, pattern, code, expected) => {
|
|
@@ -3232,7 +3232,7 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3232
3232
|
if (value === undefined)
|
|
3233
3233
|
return;
|
|
3234
3234
|
if (!pattern.test(value)) {
|
|
3235
|
-
violations.push(violation9("medium", code, `Status block${label} "${field}" = "${value}" — expected ${expected} (mstar-audit SKILL § Plan
|
|
3235
|
+
violations.push(violation9("medium", code, `Status block${label} "${field}" = "${value}" — expected ${expected} (mstar-audit SKILL.md § Plan output)`, `fix \`- **${field}**:\` to one of: ${expected}`));
|
|
3236
3236
|
}
|
|
3237
3237
|
};
|
|
3238
3238
|
check("Priority", /^P[123]$/, "audit.status.invalid-priority", "P1 | P2 | P3");
|
|
@@ -3244,74 +3244,6 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3244
3244
|
});
|
|
3245
3245
|
return { ok: violations.length === 0, violations };
|
|
3246
3246
|
}
|
|
3247
|
-
var WHOLE_MATCH_PATTERNS = [
|
|
3248
|
-
{ type: "private-key", re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/g },
|
|
3249
|
-
{ type: "aws-access-key", re: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
3250
|
-
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
3251
|
-
{ type: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
3252
|
-
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\b/g },
|
|
3253
|
-
{ type: "api-secret-key", re: /\bsk-[A-Za-z0-9-]{20,}\b/g }
|
|
3254
|
-
];
|
|
3255
|
-
var VALUE_PATTERNS = [
|
|
3256
|
-
{
|
|
3257
|
-
typeOf: (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_-]+/g, "-"),
|
|
3258
|
-
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
|
|
3259
|
-
}
|
|
3260
|
-
];
|
|
3261
|
-
function buildLineStarts(text) {
|
|
3262
|
-
const starts = [0];
|
|
3263
|
-
for (let i = 0;i < text.length; i++) {
|
|
3264
|
-
if (text[i] === `
|
|
3265
|
-
`)
|
|
3266
|
-
starts.push(i + 1);
|
|
3267
|
-
}
|
|
3268
|
-
return starts;
|
|
3269
|
-
}
|
|
3270
|
-
function lineAt(starts, index) {
|
|
3271
|
-
let lo = 0;
|
|
3272
|
-
let hi = starts.length - 1;
|
|
3273
|
-
while (lo < hi) {
|
|
3274
|
-
const mid = lo + hi + 1 >> 1;
|
|
3275
|
-
if (starts[mid] <= index)
|
|
3276
|
-
lo = mid;
|
|
3277
|
-
else
|
|
3278
|
-
hi = mid - 1;
|
|
3279
|
-
}
|
|
3280
|
-
return lo + 1;
|
|
3281
|
-
}
|
|
3282
|
-
function redactSecrets(text, filePath) {
|
|
3283
|
-
const starts = buildLineStarts(text);
|
|
3284
|
-
const marker = (type, index) => `[REDACTED ${type}@${lineAt(starts, index)}${filePath === undefined ? "" : ` in ${filePath}`}]`;
|
|
3285
|
-
const replacements = [];
|
|
3286
|
-
const findings = [];
|
|
3287
|
-
for (const pattern of WHOLE_MATCH_PATTERNS) {
|
|
3288
|
-
for (const match of text.matchAll(pattern.re)) {
|
|
3289
|
-
if (match.index === undefined)
|
|
3290
|
-
continue;
|
|
3291
|
-
replacements.push({ index: match.index, length: match[0].length, text: marker(pattern.type, match.index) });
|
|
3292
|
-
findings.push({ line: lineAt(starts, match.index), type: pattern.type });
|
|
3293
|
-
}
|
|
3294
|
-
}
|
|
3295
|
-
for (const pattern of VALUE_PATTERNS) {
|
|
3296
|
-
for (const match of text.matchAll(pattern.re)) {
|
|
3297
|
-
if (match.index === undefined)
|
|
3298
|
-
continue;
|
|
3299
|
-
const type = pattern.typeOf(match[2]);
|
|
3300
|
-
const replacement = `${match[1]}${match[2]}${match[3]}${match[4]}${marker(type, match.index)}`;
|
|
3301
|
-
replacements.push({ index: match.index, length: match[0].length, text: replacement });
|
|
3302
|
-
findings.push({ line: lineAt(starts, match.index), type });
|
|
3303
|
-
}
|
|
3304
|
-
}
|
|
3305
|
-
replacements.sort((a, b) => b.index - a.index);
|
|
3306
|
-
let out = text;
|
|
3307
|
-
for (const r of replacements)
|
|
3308
|
-
out = out.slice(0, r.index) + r.text + out.slice(r.index + r.length);
|
|
3309
|
-
const deduped = new Map;
|
|
3310
|
-
for (const f of findings)
|
|
3311
|
-
deduped.set(`${f.line}:${f.type}`, f);
|
|
3312
|
-
const sorted = [...deduped.values()].sort((a, b) => a.line - b.line || a.type.localeCompare(b.type));
|
|
3313
|
-
return { text: out, findings: sorted };
|
|
3314
|
-
}
|
|
3315
3247
|
function violation10(severity, code, message, fix) {
|
|
3316
3248
|
return { ok: false, severity, code, message, fix };
|
|
3317
3249
|
}
|
|
@@ -3606,7 +3538,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
3606
3538
|
for (const { ref, isSymbol, module } of refs) {
|
|
3607
3539
|
if (!isSymbol || module === undefined) {
|
|
3608
3540
|
const candidate = ref.replace(LINE_SUFFIX_RE, "").replace(ANCHOR_RE, "");
|
|
3609
|
-
if (
|
|
3541
|
+
if (existsSync8(resolve10(repoRoot, candidate))) {
|
|
3610
3542
|
checked++;
|
|
3611
3543
|
} else {
|
|
3612
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"));
|
|
@@ -3637,7 +3569,7 @@ function collectKnowledgeDocs(dir) {
|
|
|
3637
3569
|
if (entry.isDirectory()) {
|
|
3638
3570
|
stack.push(full);
|
|
3639
3571
|
} else if (entry.name.endsWith(".md") && entry.name !== "README.md" && entry.name !== "index.md") {
|
|
3640
|
-
docs.push(relative4(dir, full).split(
|
|
3572
|
+
docs.push(relative4(dir, full).split(sep4).join("/"));
|
|
3641
3573
|
}
|
|
3642
3574
|
}
|
|
3643
3575
|
}
|
|
@@ -3654,7 +3586,7 @@ function normalizeIndexRef(cell) {
|
|
|
3654
3586
|
function assertIndexRows(knowledgeDir) {
|
|
3655
3587
|
const violations = [];
|
|
3656
3588
|
const readmePath = join12(knowledgeDir, "README.md");
|
|
3657
|
-
if (!
|
|
3589
|
+
if (!existsSync8(readmePath)) {
|
|
3658
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"));
|
|
3659
3591
|
return { ok: false, violations };
|
|
3660
3592
|
}
|
|
@@ -3678,7 +3610,7 @@ function assertIndexRows(knowledgeDir) {
|
|
|
3678
3610
|
return { ok: violations.length === 0, violations };
|
|
3679
3611
|
}
|
|
3680
3612
|
function isFileLikeRoot(root) {
|
|
3681
|
-
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(
|
|
3613
|
+
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(basename5(root));
|
|
3682
3614
|
}
|
|
3683
3615
|
function scopeGuard(path, allowedRoots) {
|
|
3684
3616
|
const resolved = resolve10(path);
|
|
@@ -3687,7 +3619,7 @@ function scopeGuard(path, allowedRoots) {
|
|
|
3687
3619
|
if (isFileLikeRoot(r)) {
|
|
3688
3620
|
if (resolved === r)
|
|
3689
3621
|
return { ok: true, violations: [] };
|
|
3690
|
-
} else if (resolved === r || resolved.startsWith(r +
|
|
3622
|
+
} else if (resolved === r || resolved.startsWith(r + sep4)) {
|
|
3691
3623
|
return { ok: true, violations: [] };
|
|
3692
3624
|
}
|
|
3693
3625
|
}
|
|
@@ -3841,7 +3773,7 @@ function validateRoleMapping(rolesDir, options = {}) {
|
|
|
3841
3773
|
const violations = [];
|
|
3842
3774
|
const referenceById = new Map(mapping.map((m) => [m.agentId, m.reference]));
|
|
3843
3775
|
for (const { agentId, reference } of mapping) {
|
|
3844
|
-
if (!
|
|
3776
|
+
if (!existsSync9(join13(rolesDir, reference))) {
|
|
3845
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`));
|
|
3846
3778
|
}
|
|
3847
3779
|
}
|
|
@@ -4194,21 +4126,21 @@ function skillLocalConfig(config) {
|
|
|
4194
4126
|
}
|
|
4195
4127
|
|
|
4196
4128
|
// src/gates/catalog.ts
|
|
4197
|
-
import { existsSync as
|
|
4129
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9, readdirSync as readdirSync7 } from "node:fs";
|
|
4198
4130
|
import { join as join11 } from "node:path";
|
|
4199
4131
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
4200
4132
|
|
|
4201
4133
|
// src/gates/agent-flow.ts
|
|
4202
|
-
import { appendFileSync, closeSync, existsSync as
|
|
4134
|
+
import { appendFileSync, closeSync, existsSync as existsSync13, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync7, readSync, renameSync as renameSync2, rmdirSync, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4203
4135
|
import { join as join10 } from "node:path";
|
|
4204
4136
|
|
|
4205
4137
|
// src/gates/dispatch.ts
|
|
4206
|
-
import { existsSync as
|
|
4207
|
-
import { basename as
|
|
4138
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
4139
|
+
import { basename as basename4, join as join8, resolve as resolve11 } from "node:path";
|
|
4208
4140
|
|
|
4209
4141
|
// src/gates/workflow-selection.ts
|
|
4210
|
-
import { existsSync as
|
|
4211
|
-
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";
|
|
4212
4144
|
var TERMINAL_STATUS_CACHE_MAX = 64;
|
|
4213
4145
|
var terminalStatusCache = new Map;
|
|
4214
4146
|
function terminalStatusOf(snapshotPath) {
|
|
@@ -4216,6 +4148,7 @@ function terminalStatusOf(snapshotPath) {
|
|
|
4216
4148
|
try {
|
|
4217
4149
|
mtimeMs = statSync3(snapshotPath).mtimeMs;
|
|
4218
4150
|
} catch {
|
|
4151
|
+
terminalStatusCache.delete(snapshotPath);
|
|
4219
4152
|
return;
|
|
4220
4153
|
}
|
|
4221
4154
|
const cached = terminalStatusCache.get(snapshotPath);
|
|
@@ -4241,7 +4174,7 @@ function terminalStatusOf(snapshotPath) {
|
|
|
4241
4174
|
}
|
|
4242
4175
|
function resolveActiveWorkflow(harnessDir) {
|
|
4243
4176
|
const statusPath = join5(harnessDir, STATUS_FILE);
|
|
4244
|
-
if (!
|
|
4177
|
+
if (!existsSync10(statusPath)) {
|
|
4245
4178
|
return {
|
|
4246
4179
|
kind: "error",
|
|
4247
4180
|
code: "status.missing",
|
|
@@ -4299,7 +4232,7 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4299
4232
|
if (active.kind === "error" && active.code !== "workflow.selection.no-active")
|
|
4300
4233
|
return active;
|
|
4301
4234
|
const workflowsDir = resolveWorkflowDir(harnessDir, { harnessDir });
|
|
4302
|
-
if (!
|
|
4235
|
+
if (!existsSync10(workflowsDir)) {
|
|
4303
4236
|
return {
|
|
4304
4237
|
kind: "error",
|
|
4305
4238
|
code: "workflow.selection.no-snapshot",
|
|
@@ -4321,8 +4254,10 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4321
4254
|
if (!entry.isDirectory())
|
|
4322
4255
|
continue;
|
|
4323
4256
|
const snapshotPath = join5(workflowsDir, entry.name, WORKFLOW_SNAPSHOT_FILE);
|
|
4324
|
-
if (!
|
|
4257
|
+
if (!existsSync10(snapshotPath)) {
|
|
4258
|
+
terminalStatusCache.delete(snapshotPath);
|
|
4325
4259
|
continue;
|
|
4260
|
+
}
|
|
4326
4261
|
const verdict = terminalStatusOf(snapshotPath);
|
|
4327
4262
|
if (verdict === undefined || !verdict.terminal)
|
|
4328
4263
|
continue;
|
|
@@ -4330,6 +4265,11 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4330
4265
|
best = { workflowId: entry.name, dir: join5(relative3(harnessDir, workflowsDir), entry.name), mtimeMs: verdict.mtimeMs };
|
|
4331
4266
|
}
|
|
4332
4267
|
}
|
|
4268
|
+
for (const cachedPath of terminalStatusCache.keys()) {
|
|
4269
|
+
if (!existsSync10(join5(dirname7(cachedPath), WORKFLOW_SNAPSHOT_FILE))) {
|
|
4270
|
+
terminalStatusCache.delete(cachedPath);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4333
4273
|
if (best === undefined) {
|
|
4334
4274
|
return {
|
|
4335
4275
|
kind: "error",
|
|
@@ -4489,12 +4429,12 @@ function isNaValue(value) {
|
|
|
4489
4429
|
function planIdOf(headerRegion) {
|
|
4490
4430
|
const planPath = assignmentHeaderValue(headerRegion, "Plan Path");
|
|
4491
4431
|
if (!isNaValue(planPath)) {
|
|
4492
|
-
const id =
|
|
4432
|
+
const id = basename4(firstToken(planPath) ?? "");
|
|
4493
4433
|
return id.endsWith(".md") ? id.slice(0, -3) : id;
|
|
4494
4434
|
}
|
|
4495
4435
|
const sddDir = assignmentHeaderValue(headerRegion, "SDD dir");
|
|
4496
4436
|
if (!isNaValue(sddDir)) {
|
|
4497
|
-
const id =
|
|
4437
|
+
const id = basename4(firstToken(sddDir) ?? "");
|
|
4498
4438
|
return id === "" ? undefined : id;
|
|
4499
4439
|
}
|
|
4500
4440
|
const planId = assignmentHeaderValue(headerRegion, "plan_id");
|
|
@@ -4524,7 +4464,7 @@ function leaseGateViolations(harnessDir, exec, writable, prompt) {
|
|
|
4524
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)")];
|
|
4525
4465
|
}
|
|
4526
4466
|
const snapshotPath = join8(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
4527
|
-
if (!
|
|
4467
|
+
if (!existsSync12(snapshotPath)) {
|
|
4528
4468
|
if (!sdd)
|
|
4529
4469
|
return [];
|
|
4530
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)")];
|
|
@@ -4598,7 +4538,7 @@ function worktreeL2Violations(header) {
|
|
|
4598
4538
|
return violations;
|
|
4599
4539
|
}
|
|
4600
4540
|
function activeSnapshotRows(harnessDir) {
|
|
4601
|
-
if (!
|
|
4541
|
+
if (!existsSync12(join8(harnessDir, STATUS_FILE)))
|
|
4602
4542
|
return { rows: null, controlWorktreePath: undefined, unreadable: false };
|
|
4603
4543
|
const selection = resolveActiveWorkflow(harnessDir);
|
|
4604
4544
|
if (selection.kind !== "active") {
|
|
@@ -4609,7 +4549,7 @@ function activeSnapshotRows(harnessDir) {
|
|
|
4609
4549
|
};
|
|
4610
4550
|
}
|
|
4611
4551
|
const snapshotPath = join8(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
4612
|
-
if (!
|
|
4552
|
+
if (!existsSync12(snapshotPath))
|
|
4613
4553
|
return { rows: null, controlWorktreePath: undefined, unreadable: true };
|
|
4614
4554
|
let doc;
|
|
4615
4555
|
try {
|
|
@@ -5339,7 +5279,7 @@ function ledgerContent(file, n) {
|
|
|
5339
5279
|
}
|
|
5340
5280
|
function readAgentFlow(workflowDir, limit) {
|
|
5341
5281
|
const file = join10(workflowDir, AGENT_FLOW_FILE);
|
|
5342
|
-
if (!
|
|
5282
|
+
if (!existsSync13(file)) {
|
|
5343
5283
|
return { events: [], summary: [] };
|
|
5344
5284
|
}
|
|
5345
5285
|
const n = limit === undefined ? AGENT_FLOW_DEFAULT_LIMIT : Math.max(0, Math.floor(limit));
|
|
@@ -5594,7 +5534,7 @@ function harnessStateSource(harnessDir) {
|
|
|
5594
5534
|
if (harnessDir === null)
|
|
5595
5535
|
return null;
|
|
5596
5536
|
const statusPath = join11(harnessDir, STATUS_FILE);
|
|
5597
|
-
if (!
|
|
5537
|
+
if (!existsSync14(statusPath))
|
|
5598
5538
|
return null;
|
|
5599
5539
|
try {
|
|
5600
5540
|
const selection = resolveReadWorkflow(harnessDir);
|
|
@@ -5615,7 +5555,7 @@ function harnessStateSource(harnessDir) {
|
|
|
5615
5555
|
}
|
|
5616
5556
|
const snapshotPath = join11(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
5617
5557
|
let snapshot;
|
|
5618
|
-
if (!
|
|
5558
|
+
if (!existsSync14(snapshotPath)) {
|
|
5619
5559
|
return selectionErrorState({
|
|
5620
5560
|
kind: "error",
|
|
5621
5561
|
code: "workflow.selection.snapshot-unreadable",
|
|
@@ -5707,7 +5647,7 @@ function selectionErrorState(selection, rollup, harnessDir, compass) {
|
|
|
5707
5647
|
function projectRollupSource(harnessDir, residuals) {
|
|
5708
5648
|
const milestones = [];
|
|
5709
5649
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5710
|
-
if (
|
|
5650
|
+
if (existsSync14(projectsDir)) {
|
|
5711
5651
|
let entries;
|
|
5712
5652
|
try {
|
|
5713
5653
|
entries = readdirSync7(projectsDir, { withFileTypes: true });
|
|
@@ -5718,7 +5658,7 @@ function projectRollupSource(harnessDir, residuals) {
|
|
|
5718
5658
|
if (!entry.isDirectory())
|
|
5719
5659
|
continue;
|
|
5720
5660
|
const roadmapPath = join11(projectsDir, entry.name, PROJECT_ROADMAP_FILE);
|
|
5721
|
-
if (!
|
|
5661
|
+
if (!existsSync14(roadmapPath))
|
|
5722
5662
|
continue;
|
|
5723
5663
|
try {
|
|
5724
5664
|
const doc = parseCompassFrontmatterText(readFileSync9(roadmapPath, "utf8"), roadmapPath);
|
|
@@ -5783,7 +5723,7 @@ function residualRollup(harnessDir) {
|
|
|
5783
5723
|
}
|
|
5784
5724
|
function projectRegisters(harnessDir) {
|
|
5785
5725
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5786
|
-
if (!
|
|
5726
|
+
if (!existsSync14(projectsDir))
|
|
5787
5727
|
return [];
|
|
5788
5728
|
let entries;
|
|
5789
5729
|
try {
|
|
@@ -5796,7 +5736,7 @@ function projectRegisters(harnessDir) {
|
|
|
5796
5736
|
if (!entry.isDirectory())
|
|
5797
5737
|
continue;
|
|
5798
5738
|
const registerPath = join11(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
5799
|
-
if (!
|
|
5739
|
+
if (!existsSync14(registerPath))
|
|
5800
5740
|
continue;
|
|
5801
5741
|
try {
|
|
5802
5742
|
registers.push({ projectId: entry.name, doc: readJson(registerPath) });
|
|
@@ -5808,7 +5748,7 @@ function projectRegisters(harnessDir) {
|
|
|
5808
5748
|
}
|
|
5809
5749
|
function knowledgeDigest(harnessDir) {
|
|
5810
5750
|
const indexPath = join11(harnessDir, "knowledge", "README.md");
|
|
5811
|
-
if (!
|
|
5751
|
+
if (!existsSync14(indexPath))
|
|
5812
5752
|
return null;
|
|
5813
5753
|
try {
|
|
5814
5754
|
const categories = new Set;
|
|
@@ -5853,7 +5793,7 @@ function compassDirection(compassPath) {
|
|
|
5853
5793
|
}
|
|
5854
5794
|
function steeringCompassPath(harnessDir) {
|
|
5855
5795
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
5856
|
-
if (!
|
|
5796
|
+
if (!existsSync14(iterationsDir))
|
|
5857
5797
|
return;
|
|
5858
5798
|
let entries;
|
|
5859
5799
|
try {
|
|
@@ -5865,7 +5805,7 @@ function steeringCompassPath(harnessDir) {
|
|
|
5865
5805
|
if (!entry.isDirectory())
|
|
5866
5806
|
continue;
|
|
5867
5807
|
const compassPath = join11(iterationsDir, entry.name, "delivery-compass.md");
|
|
5868
|
-
if (!
|
|
5808
|
+
if (!existsSync14(compassPath))
|
|
5869
5809
|
continue;
|
|
5870
5810
|
let content;
|
|
5871
5811
|
try {
|
|
@@ -5884,7 +5824,7 @@ function iterationGateSource(harnessDir) {
|
|
|
5884
5824
|
if (harnessDir === null)
|
|
5885
5825
|
return;
|
|
5886
5826
|
const statusPath = join11(harnessDir, STATUS_FILE);
|
|
5887
|
-
if (!
|
|
5827
|
+
if (!existsSync14(statusPath))
|
|
5888
5828
|
return;
|
|
5889
5829
|
const compass = steeringCompassPath(harnessDir);
|
|
5890
5830
|
if (compass === undefined)
|
|
@@ -5946,12 +5886,12 @@ function agentDigestKey(agent, cwd) {
|
|
|
5946
5886
|
}
|
|
5947
5887
|
|
|
5948
5888
|
// src/gates/status.ts
|
|
5949
|
-
import { existsSync as
|
|
5950
|
-
import { basename as
|
|
5889
|
+
import { existsSync as existsSync15, readdirSync as readdirSync9 } from "node:fs";
|
|
5890
|
+
import { basename as basename6, join as join14, relative as relative5, resolve as resolve13 } from "node:path";
|
|
5951
5891
|
var LOGGER_NAME = "mstar/status-gate";
|
|
5952
5892
|
function harnessDocKindOfTarget(harnessDir, targetPath) {
|
|
5953
5893
|
const resolved = resolve13(targetPath);
|
|
5954
|
-
const name =
|
|
5894
|
+
const name = basename6(resolved);
|
|
5955
5895
|
if (name !== STATUS_FILE && name !== WORKFLOW_SNAPSHOT_FILE && name !== PROJECT_REGISTER_FILE)
|
|
5956
5896
|
return null;
|
|
5957
5897
|
const rel = relative5(harnessDir, resolved);
|
|
@@ -6029,7 +5969,7 @@ function projectRegisterDocs(harnessDir) {
|
|
|
6029
5969
|
if (!entry.isDirectory())
|
|
6030
5970
|
continue;
|
|
6031
5971
|
const registerPath = join14(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
6032
|
-
if (!
|
|
5972
|
+
if (!existsSync15(registerPath))
|
|
6033
5973
|
continue;
|
|
6034
5974
|
try {
|
|
6035
5975
|
registers.push({ projectId: entry.name, doc: readJson(registerPath) });
|
|
@@ -6082,7 +6022,11 @@ ${verdict.violations.map(formatViolation).join(`
|
|
|
6082
6022
|
} catch (error) {
|
|
6083
6023
|
ctx.logger(LOGGER_NAME).error(`status gate degraded to allow: ${error.message}`);
|
|
6084
6024
|
try {
|
|
6085
|
-
|
|
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 });
|
|
6086
6030
|
} catch (emitError) {
|
|
6087
6031
|
ctx.logger(LOGGER_NAME).error(`status gate degraded advisory emit failed: ${emitError.message}`);
|
|
6088
6032
|
}
|
|
@@ -6098,8 +6042,8 @@ async function editIntentListener(ctx, resolver, config, adapter, target, actor,
|
|
|
6098
6042
|
}
|
|
6099
6043
|
|
|
6100
6044
|
// src/gates/skill-lint.ts
|
|
6101
|
-
import { existsSync as
|
|
6102
|
-
import { basename as
|
|
6045
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
|
|
6046
|
+
import { basename as basename7, dirname as dirname9, resolve as resolve14, sep as sep2 } from "node:path";
|
|
6103
6047
|
var SKILL_LINT_LOGGER = "mstar/skill-lint";
|
|
6104
6048
|
|
|
6105
6049
|
class SkillLintVetoError extends Error {
|
|
@@ -6160,13 +6104,13 @@ function skillRootsOf(config) {
|
|
|
6160
6104
|
return roots.map((root) => root.trim()).filter((root) => root !== "");
|
|
6161
6105
|
}
|
|
6162
6106
|
function isSkillTarget(roots, target) {
|
|
6163
|
-
if (
|
|
6107
|
+
if (basename7(target.displayPath) !== "SKILL.md")
|
|
6164
6108
|
return false;
|
|
6165
6109
|
const resolvedPath = resolve14(target.displayPath);
|
|
6166
6110
|
return roots.some((root) => resolvedPath.startsWith(resolve14(root) + sep2));
|
|
6167
6111
|
}
|
|
6168
6112
|
function skillNameOf(target) {
|
|
6169
|
-
return
|
|
6113
|
+
return basename7(dirname9(target.displayPath));
|
|
6170
6114
|
}
|
|
6171
6115
|
function skillCanonicalForm(target) {
|
|
6172
6116
|
return resolveSkillRoot("dsh", { skill: skillNameOf(target), rel: "SKILL.md" });
|
|
@@ -6179,7 +6123,7 @@ function gateSkillIntent(ctx, harnessDir, config, target) {
|
|
|
6179
6123
|
if (!isSkillTarget(roots, target))
|
|
6180
6124
|
return;
|
|
6181
6125
|
const skillPath = resolve14(target.displayPath);
|
|
6182
|
-
if (!
|
|
6126
|
+
if (!existsSync16(skillPath))
|
|
6183
6127
|
return;
|
|
6184
6128
|
let doc;
|
|
6185
6129
|
try {
|
|
@@ -6230,8 +6174,130 @@ async function skillWriteIntentListener(ctx, resolver, config, target, actor, ne
|
|
|
6230
6174
|
}
|
|
6231
6175
|
|
|
6232
6176
|
// src/gates/seams.ts
|
|
6233
|
-
import { existsSync as
|
|
6234
|
-
import { basename as
|
|
6177
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13, readdirSync as readdirSync11 } from "node:fs";
|
|
6178
|
+
import { basename as basename8, dirname as dirname10, join as join16, resolve as resolve15, sep as sep3 } from "node:path";
|
|
6179
|
+
|
|
6180
|
+
// ../engine/dist/audit.js
|
|
6181
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
6182
|
+
var DATE_PART2 = String.raw`\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])`;
|
|
6183
|
+
var RFC3339_Z_RE2 = new RegExp(String.raw`^${DATE_PART2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$`);
|
|
6184
|
+
var DATE_ONLY_RE2 = new RegExp(String.raw`^${DATE_PART2}$`);
|
|
6185
|
+
var heldLockDirs2 = new AsyncLocalStorage2;
|
|
6186
|
+
var MSTARC_HARNESS_DIR_KEY2 = "harness_dir";
|
|
6187
|
+
var MSTARC_PLAN_DIR_KEY2 = "plan_dir";
|
|
6188
|
+
var MSTARC_SDD_DIR_KEY2 = "sdd_dir";
|
|
6189
|
+
var MSTARC_ITERATION_DIR_KEY2 = "iteration_dir";
|
|
6190
|
+
var MSTARC_KNOWLEDGE_DIR_KEY2 = "knowledge_dir";
|
|
6191
|
+
var MSTARC_SPECS_DIR_KEY2 = "specs_dir";
|
|
6192
|
+
var MSTARC_WORKFLOW_DIR_KEY2 = "workflow_dir";
|
|
6193
|
+
var MSTARC_PROJECT_DIR_KEY2 = "project_dir";
|
|
6194
|
+
var MSTARC_ENFORCEMENT_KEY2 = "enforcement";
|
|
6195
|
+
var CONFIG_KEYS2 = {
|
|
6196
|
+
[MSTARC_HARNESS_DIR_KEY2]: "harnessDir",
|
|
6197
|
+
[MSTARC_PLAN_DIR_KEY2]: "planDir",
|
|
6198
|
+
[MSTARC_SDD_DIR_KEY2]: "sddDir",
|
|
6199
|
+
[MSTARC_ITERATION_DIR_KEY2]: "iterationDir",
|
|
6200
|
+
[MSTARC_KNOWLEDGE_DIR_KEY2]: "knowledgeDir",
|
|
6201
|
+
[MSTARC_SPECS_DIR_KEY2]: "specsDir",
|
|
6202
|
+
[MSTARC_WORKFLOW_DIR_KEY2]: "workflowDir",
|
|
6203
|
+
[MSTARC_PROJECT_DIR_KEY2]: "projectDir",
|
|
6204
|
+
[MSTARC_ENFORCEMENT_KEY2]: "enforcement"
|
|
6205
|
+
};
|
|
6206
|
+
var GITIGNORE_SNIPPET2 = `# Morning Star harness (.mstar/)
|
|
6207
|
+
# Principle: process stays local; results are shared with the team.
|
|
6208
|
+
# Default-ignore everything under .mstar/, then re-include the tracked results.
|
|
6209
|
+
.mstar/**
|
|
6210
|
+
!.mstar/AGENTS.md
|
|
6211
|
+
!.mstar/knowledge/
|
|
6212
|
+
!.mstar/knowledge/**
|
|
6213
|
+
!.mstar/specs/
|
|
6214
|
+
!.mstar/specs/**
|
|
6215
|
+
# .mstarc — repo-local harness config (may declare [config] harness_dir=<name>)
|
|
6216
|
+
.mstarc
|
|
6217
|
+
`;
|
|
6218
|
+
var GITIGNORE_SNIPPET_AGENTS2 = `# Morning Star harness (.agents/) — legacy
|
|
6219
|
+
# Default-ignore everything under .agents/, then re-include the tracked results.
|
|
6220
|
+
.agents/**
|
|
6221
|
+
!.agents/AGENTS.md
|
|
6222
|
+
!.agents/knowledge/
|
|
6223
|
+
!.agents/knowledge/**
|
|
6224
|
+
!.agents/specs/
|
|
6225
|
+
!.agents/specs/**
|
|
6226
|
+
`;
|
|
6227
|
+
var GITIGNORE_PROCESS_ENTRIES2 = GITIGNORE_SNIPPET2.split(`
|
|
6228
|
+
`).filter((line) => line.startsWith(".mstar/") || line.startsWith("!.mstar/")).map((line) => line.trim());
|
|
6229
|
+
var GITIGNORE_PROCESS_ENTRIES_AGENTS2 = GITIGNORE_SNIPPET_AGENTS2.split(`
|
|
6230
|
+
`).filter((line) => line.startsWith(".agents/") || line.startsWith("!.agents/")).map((line) => line.trim());
|
|
6231
|
+
var WHOLE_MATCH_PATTERNS = [
|
|
6232
|
+
{ type: "private-key", re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/g },
|
|
6233
|
+
{ type: "aws-access-key", re: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
6234
|
+
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
6235
|
+
{ type: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
6236
|
+
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\b/g },
|
|
6237
|
+
{ type: "api-secret-key", re: /\bsk-[A-Za-z0-9-]{20,}\b/g }
|
|
6238
|
+
];
|
|
6239
|
+
var VALUE_PATTERNS = [
|
|
6240
|
+
{
|
|
6241
|
+
typeOf: (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_-]+/g, "-"),
|
|
6242
|
+
re: /(["']?)\b(password|passwd|api[_-]?key|access[_-]?token|auth[_-]?token|secret|token)\b(["']?)(\s*[:=]\s*)("[^"\n]{8,}"|'[^'\n]{8,}'|[A-Za-z0-9_./+\-=]{16,})/gi
|
|
6243
|
+
}
|
|
6244
|
+
];
|
|
6245
|
+
function buildLineStarts(text) {
|
|
6246
|
+
const starts = [0];
|
|
6247
|
+
for (let i = 0;i < text.length; i++) {
|
|
6248
|
+
if (text[i] === `
|
|
6249
|
+
`)
|
|
6250
|
+
starts.push(i + 1);
|
|
6251
|
+
}
|
|
6252
|
+
return starts;
|
|
6253
|
+
}
|
|
6254
|
+
function lineAt(starts, index) {
|
|
6255
|
+
let lo = 0;
|
|
6256
|
+
let hi = starts.length - 1;
|
|
6257
|
+
while (lo < hi) {
|
|
6258
|
+
const mid = lo + hi + 1 >> 1;
|
|
6259
|
+
if (starts[mid] <= index)
|
|
6260
|
+
lo = mid;
|
|
6261
|
+
else
|
|
6262
|
+
hi = mid - 1;
|
|
6263
|
+
}
|
|
6264
|
+
return lo + 1;
|
|
6265
|
+
}
|
|
6266
|
+
function redactSecrets(text, filePath) {
|
|
6267
|
+
const starts = buildLineStarts(text);
|
|
6268
|
+
const marker = (type, index) => `[REDACTED ${type}@${lineAt(starts, index)}${filePath === undefined ? "" : ` in ${filePath}`}]`;
|
|
6269
|
+
const replacements = [];
|
|
6270
|
+
const findings = [];
|
|
6271
|
+
for (const pattern of WHOLE_MATCH_PATTERNS) {
|
|
6272
|
+
for (const match of text.matchAll(pattern.re)) {
|
|
6273
|
+
if (match.index === undefined)
|
|
6274
|
+
continue;
|
|
6275
|
+
replacements.push({ index: match.index, length: match[0].length, text: marker(pattern.type, match.index) });
|
|
6276
|
+
findings.push({ line: lineAt(starts, match.index), type: pattern.type });
|
|
6277
|
+
}
|
|
6278
|
+
}
|
|
6279
|
+
for (const pattern of VALUE_PATTERNS) {
|
|
6280
|
+
for (const match of text.matchAll(pattern.re)) {
|
|
6281
|
+
if (match.index === undefined)
|
|
6282
|
+
continue;
|
|
6283
|
+
const type = pattern.typeOf(match[2]);
|
|
6284
|
+
const replacement = `${match[1]}${match[2]}${match[3]}${match[4]}${marker(type, match.index)}`;
|
|
6285
|
+
replacements.push({ index: match.index, length: match[0].length, text: replacement });
|
|
6286
|
+
findings.push({ line: lineAt(starts, match.index), type });
|
|
6287
|
+
}
|
|
6288
|
+
}
|
|
6289
|
+
replacements.sort((a, b) => b.index - a.index);
|
|
6290
|
+
let out = text;
|
|
6291
|
+
for (const r of replacements)
|
|
6292
|
+
out = out.slice(0, r.index) + r.text + out.slice(r.index + r.length);
|
|
6293
|
+
const deduped = new Map;
|
|
6294
|
+
for (const f of findings)
|
|
6295
|
+
deduped.set(`${f.line}:${f.type}`, f);
|
|
6296
|
+
const sorted = [...deduped.values()].sort((a, b) => a.line - b.line || a.type.localeCompare(b.type));
|
|
6297
|
+
return { text: out, findings: sorted };
|
|
6298
|
+
}
|
|
6299
|
+
|
|
6300
|
+
// src/gates/seams.ts
|
|
6235
6301
|
var SEAM_LOGGERS = {
|
|
6236
6302
|
"design-md": "mstar/design-md-lint",
|
|
6237
6303
|
audit: "mstar/audit-lint",
|
|
@@ -6239,7 +6305,7 @@ var SEAM_LOGGERS = {
|
|
|
6239
6305
|
roles: "mstar/roles-lint"
|
|
6240
6306
|
};
|
|
6241
6307
|
function isIndexFile(path) {
|
|
6242
|
-
const base =
|
|
6308
|
+
const base = basename8(path);
|
|
6243
6309
|
return base === "README.md" || base === "index.md";
|
|
6244
6310
|
}
|
|
6245
6311
|
function isMarkdownDoc(path) {
|
|
@@ -6248,7 +6314,7 @@ function isMarkdownDoc(path) {
|
|
|
6248
6314
|
function isAuditPlanTarget(path) {
|
|
6249
6315
|
if (!isMarkdownDoc(path))
|
|
6250
6316
|
return false;
|
|
6251
|
-
const segments = resolve15(path).split(
|
|
6317
|
+
const segments = resolve15(path).split(sep3);
|
|
6252
6318
|
for (let i = 0;i < segments.length; i++) {
|
|
6253
6319
|
if (segments[i] !== "plans")
|
|
6254
6320
|
continue;
|
|
@@ -6259,7 +6325,7 @@ function isAuditPlanTarget(path) {
|
|
|
6259
6325
|
return false;
|
|
6260
6326
|
}
|
|
6261
6327
|
function isRolesTarget(path) {
|
|
6262
|
-
const segments = resolve15(path).split(
|
|
6328
|
+
const segments = resolve15(path).split(sep3);
|
|
6263
6329
|
const idx = segments.indexOf("mstar-roles");
|
|
6264
6330
|
if (idx === -1)
|
|
6265
6331
|
return false;
|
|
@@ -6269,17 +6335,17 @@ function isRolesTarget(path) {
|
|
|
6269
6335
|
return rest[0] === "SKILL.md" || rest[0] === "references" && rest[rest.length - 1].endsWith(".md");
|
|
6270
6336
|
}
|
|
6271
6337
|
function rolesDirOf(path) {
|
|
6272
|
-
const segments = resolve15(path).split(
|
|
6338
|
+
const segments = resolve15(path).split(sep3);
|
|
6273
6339
|
const idx = segments.indexOf("mstar-roles");
|
|
6274
6340
|
if (idx === -1)
|
|
6275
|
-
return
|
|
6276
|
-
return idx === 0 ?
|
|
6341
|
+
return dirname10(path);
|
|
6342
|
+
return idx === 0 ? sep3 : join16(sep3, ...segments.slice(1, idx + 1));
|
|
6277
6343
|
}
|
|
6278
6344
|
function isSeamTarget(seam, harnessDir, target) {
|
|
6279
6345
|
const path = resolve15(target.displayPath);
|
|
6280
6346
|
switch (seam) {
|
|
6281
6347
|
case "design-md": {
|
|
6282
|
-
const base =
|
|
6348
|
+
const base = basename8(path);
|
|
6283
6349
|
return base === "DESIGN.md" || base === "DESIGN.dark.md";
|
|
6284
6350
|
}
|
|
6285
6351
|
case "audit":
|
|
@@ -6287,7 +6353,7 @@ function isSeamTarget(seam, harnessDir, target) {
|
|
|
6287
6353
|
case "compound": {
|
|
6288
6354
|
if (harnessDir === null)
|
|
6289
6355
|
return false;
|
|
6290
|
-
return path.startsWith(resolve15(join16(harnessDir, "knowledge")) +
|
|
6356
|
+
return path.startsWith(resolve15(join16(harnessDir, "knowledge")) + sep3) && isMarkdownDoc(path);
|
|
6291
6357
|
}
|
|
6292
6358
|
case "roles":
|
|
6293
6359
|
return isRolesTarget(path);
|
|
@@ -6304,9 +6370,9 @@ function auditSecretsViolations(findings, file) {
|
|
|
6304
6370
|
}
|
|
6305
6371
|
function validateDesignDoc(doc, path) {
|
|
6306
6372
|
const violations = [...validateDesignTokenFrontmatter(doc).violations];
|
|
6307
|
-
const isDark =
|
|
6308
|
-
const sibling = join16(
|
|
6309
|
-
if (
|
|
6373
|
+
const isDark = basename8(path) === "DESIGN.dark.md";
|
|
6374
|
+
const sibling = join16(dirname10(path), isDark ? "DESIGN.md" : "DESIGN.dark.md");
|
|
6375
|
+
if (existsSync17(sibling)) {
|
|
6310
6376
|
const light = isDark ? readFileSync13(sibling, "utf8") : doc;
|
|
6311
6377
|
const dark = isDark ? doc : readFileSync13(sibling, "utf8");
|
|
6312
6378
|
violations.push(...assertLightDarkParity(light, dark).violations);
|
|
@@ -6322,18 +6388,18 @@ function validateAuditDoc(doc, path) {
|
|
|
6322
6388
|
function validateCompoundDoc(doc, _path, harnessDir) {
|
|
6323
6389
|
const violations = [...validateSchemaYaml(doc).violations];
|
|
6324
6390
|
if (harnessDir !== null) {
|
|
6325
|
-
violations.push(...referenceExists(
|
|
6391
|
+
violations.push(...referenceExists(dirname10(harnessDir), doc).violations);
|
|
6326
6392
|
}
|
|
6327
6393
|
return violations.length === 0 ? { ok: true, violations } : { ok: false, violations };
|
|
6328
6394
|
}
|
|
6329
|
-
function validateRolesState(rolesDir, skillsRoot =
|
|
6395
|
+
function validateRolesState(rolesDir, skillsRoot = dirname10(rolesDir)) {
|
|
6330
6396
|
const violations = [...validateRoleMapping(rolesDir).violations];
|
|
6331
6397
|
const skillTexts = {};
|
|
6332
6398
|
for (const entry of readdirSync11(skillsRoot, { withFileTypes: true })) {
|
|
6333
6399
|
if (!entry.isDirectory() || !entry.name.startsWith("mstar-"))
|
|
6334
6400
|
continue;
|
|
6335
6401
|
const skillFile = join16(skillsRoot, entry.name, "SKILL.md");
|
|
6336
|
-
if (!
|
|
6402
|
+
if (!existsSync17(skillFile))
|
|
6337
6403
|
continue;
|
|
6338
6404
|
try {
|
|
6339
6405
|
skillTexts[entry.name] = readFileSync13(skillFile, "utf8");
|
|
@@ -6367,7 +6433,7 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
6367
6433
|
if (!isSeamTarget(seam, harnessDir, target))
|
|
6368
6434
|
return;
|
|
6369
6435
|
const path = resolve15(target.displayPath);
|
|
6370
|
-
if (!
|
|
6436
|
+
if (!existsSync17(path))
|
|
6371
6437
|
return;
|
|
6372
6438
|
let doc;
|
|
6373
6439
|
try {
|
|
@@ -6383,12 +6449,12 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
6383
6449
|
const hard = resolveSeamHard(harnessDir, config);
|
|
6384
6450
|
const verdict = applyEnforcement(result, { hard });
|
|
6385
6451
|
if (verdict.hardBlocked) {
|
|
6386
|
-
logger.error(`${
|
|
6452
|
+
logger.error(`${basename8(path)} write to ${target.displayPath} ALLOWED as repair (Enforcement: hard; the current on-disk document is already invalid — the intent carries no incoming content, so the vetoable signal is only the pre-write state):
|
|
6387
6453
|
${verdict.violations.map(formatViolation).join(`
|
|
6388
6454
|
`)}`);
|
|
6389
6455
|
emitSeamAdvisory(ctx, seam, target.displayPath, verdict, hard, { repair: true });
|
|
6390
6456
|
} else {
|
|
6391
|
-
logger.warn(`${
|
|
6457
|
+
logger.warn(`${basename8(path)} write to ${target.displayPath} (advisory):
|
|
6392
6458
|
${verdict.violations.map(formatViolation).join(`
|
|
6393
6459
|
`)}`);
|
|
6394
6460
|
emitSeamAdvisory(ctx, seam, target.displayPath, verdict, hard);
|
|
@@ -6437,7 +6503,7 @@ function lintRolesWrite(doc, options) {
|
|
|
6437
6503
|
}
|
|
6438
6504
|
|
|
6439
6505
|
// src/gates/tools.ts
|
|
6440
|
-
import { existsSync as
|
|
6506
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "node:fs";
|
|
6441
6507
|
import { join as join17, resolve as resolve16 } from "node:path";
|
|
6442
6508
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
6443
6509
|
var ITERATION_VIOLATION_SCHEMA = {
|
|
@@ -6603,9 +6669,9 @@ function registerSddIterationTools(ctx, resolver) {
|
|
|
6603
6669
|
presentResult: (_args, _result) => ({ card: "generic", title: "Iteration gate evaluation" }),
|
|
6604
6670
|
isConcurrencySafe: () => false,
|
|
6605
6671
|
async execute(args) {
|
|
6606
|
-
if (!
|
|
6672
|
+
if (!existsSync18(args.snapshot_path))
|
|
6607
6673
|
throw new Error(`workflow snapshot not found: ${args.snapshot_path}`);
|
|
6608
|
-
if (!
|
|
6674
|
+
if (!existsSync18(args.compass_path))
|
|
6609
6675
|
throw new Error(`compass file not found: ${args.compass_path}`);
|
|
6610
6676
|
const snapshotDoc = readJson(args.snapshot_path);
|
|
6611
6677
|
const compassDoc = parseCompassFrontmatter(args.compass_path);
|
|
@@ -6660,7 +6726,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6660
6726
|
async execute(args) {
|
|
6661
6727
|
const abs = resolve16(args.dir);
|
|
6662
6728
|
const lightPath = join17(abs, "DESIGN.md");
|
|
6663
|
-
if (!
|
|
6729
|
+
if (!existsSync18(lightPath))
|
|
6664
6730
|
throw new Error(`design file not found: ${lightPath}`);
|
|
6665
6731
|
const light = readFileSync14(lightPath, "utf8");
|
|
6666
6732
|
const result = validateDesignDoc(light, lightPath);
|
|
@@ -6713,7 +6779,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6713
6779
|
isConcurrencySafe: () => false,
|
|
6714
6780
|
async execute(args) {
|
|
6715
6781
|
const abs = resolve16(args.plan_path);
|
|
6716
|
-
if (!
|
|
6782
|
+
if (!existsSync18(abs))
|
|
6717
6783
|
throw new Error(`plan file not found: ${abs}`);
|
|
6718
6784
|
const text = readFileSync14(abs, "utf8");
|
|
6719
6785
|
const result = validateAuditDoc(text, abs);
|
|
@@ -6753,7 +6819,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6753
6819
|
isConcurrencySafe: () => false,
|
|
6754
6820
|
async execute(args, exec) {
|
|
6755
6821
|
const abs = resolve16(args.doc_path);
|
|
6756
|
-
if (!
|
|
6822
|
+
if (!existsSync18(abs))
|
|
6757
6823
|
throw new Error(`knowledge doc not found: ${abs}`);
|
|
6758
6824
|
const text = readFileSync14(abs, "utf8");
|
|
6759
6825
|
const base = validateCompoundDoc(text, abs, args.repo_root !== undefined ? null : resolver.forAgent(exec.agent));
|
|
@@ -6798,7 +6864,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6798
6864
|
isConcurrencySafe: () => false,
|
|
6799
6865
|
async execute(args) {
|
|
6800
6866
|
const rolesDir = resolve16(args.roles_dir);
|
|
6801
|
-
if (!
|
|
6867
|
+
if (!existsSync18(join17(rolesDir, "SKILL.md")))
|
|
6802
6868
|
throw new Error(`roles dir not found: ${rolesDir}`);
|
|
6803
6869
|
const result = validateRolesState(rolesDir, args.skills_root !== undefined ? resolve16(args.skills_root) : undefined);
|
|
6804
6870
|
return { ok: result.ok, violations: result.violations.map(iterationViolationView) };
|
|
@@ -6808,7 +6874,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6808
6874
|
}
|
|
6809
6875
|
|
|
6810
6876
|
// src/gates/adapter.ts
|
|
6811
|
-
import { existsSync as
|
|
6877
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
6812
6878
|
import { join as join18 } from "node:path";
|
|
6813
6879
|
import { Service as Service2 } from "@deepseek-ai/cordis";
|
|
6814
6880
|
var HOST_LOGGER = "mstar/host-adapter";
|
|
@@ -6845,7 +6911,7 @@ class DshHostAdapter extends Service2 {
|
|
|
6845
6911
|
this.logSink(level, msg);
|
|
6846
6912
|
}
|
|
6847
6913
|
statusGate(path, kind, harnessDir) {
|
|
6848
|
-
if (!
|
|
6914
|
+
if (!existsSync19(path))
|
|
6849
6915
|
return { ok: true, violations: [] };
|
|
6850
6916
|
return validateStatusDoc(path, kind, harnessDir);
|
|
6851
6917
|
}
|
|
@@ -6927,7 +6993,7 @@ class DshHostAdapter extends Service2 {
|
|
|
6927
6993
|
|
|
6928
6994
|
// src/gates/agent-personas.ts
|
|
6929
6995
|
import { readFileSync as readFileSync15, readdirSync as readdirSync12, statSync as statSync6 } from "node:fs";
|
|
6930
|
-
import { join as join19, resolve as resolve17, sep as
|
|
6996
|
+
import { join as join19, resolve as resolve17, sep as sep5 } from "node:path";
|
|
6931
6997
|
var ROLE_ID_PATTERN = /^[a-z0-9-]{1,32}$/;
|
|
6932
6998
|
var defaultCache = new Map;
|
|
6933
6999
|
function personaFor(roleId, lookup, warn) {
|
|
@@ -6970,7 +7036,7 @@ function defaultFromMirror(agentsDir, roleId, warn) {
|
|
|
6970
7036
|
return;
|
|
6971
7037
|
const root = resolve17(agentsDir);
|
|
6972
7038
|
const file = resolve17(agentsDir, `${roleId}.md`);
|
|
6973
|
-
if (!file.startsWith(root +
|
|
7039
|
+
if (!file.startsWith(root + sep5))
|
|
6974
7040
|
return;
|
|
6975
7041
|
let stat;
|
|
6976
7042
|
try {
|
|
@@ -7457,7 +7523,7 @@ function registerWorkflowLedger(ctx, resolver, workflowAskCache) {
|
|
|
7457
7523
|
}
|
|
7458
7524
|
|
|
7459
7525
|
// src/gates/goal-bridge.ts
|
|
7460
|
-
import { existsSync as
|
|
7526
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, readdirSync as readdirSync13 } from "node:fs";
|
|
7461
7527
|
import { join as join21 } from "node:path";
|
|
7462
7528
|
var GOAL_BRIDGE_LOGGER = "mstar/goal-bridge";
|
|
7463
7529
|
var DEFAULT_MAX_GOAL_ROUNDS = 256;
|
|
@@ -7486,7 +7552,7 @@ function projectRegisterPointer(harnessDir) {
|
|
|
7486
7552
|
if (!entry.isDirectory())
|
|
7487
7553
|
continue;
|
|
7488
7554
|
const registerPath = join21(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
7489
|
-
if (
|
|
7555
|
+
if (existsSync20(registerPath))
|
|
7490
7556
|
return registerPath;
|
|
7491
7557
|
}
|
|
7492
7558
|
} catch {}
|
|
@@ -7501,7 +7567,7 @@ function iterationGoalObjective(iterationId) {
|
|
|
7501
7567
|
}
|
|
7502
7568
|
function steeringCompass(harnessDir) {
|
|
7503
7569
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
7504
|
-
if (!
|
|
7570
|
+
if (!existsSync20(iterationsDir))
|
|
7505
7571
|
return;
|
|
7506
7572
|
let entries;
|
|
7507
7573
|
try {
|
|
@@ -7513,7 +7579,7 @@ function steeringCompass(harnessDir) {
|
|
|
7513
7579
|
if (!entry.isDirectory())
|
|
7514
7580
|
continue;
|
|
7515
7581
|
const compassPath = join21(iterationsDir, entry.name, "delivery-compass.md");
|
|
7516
|
-
if (!
|
|
7582
|
+
if (!existsSync20(compassPath))
|
|
7517
7583
|
continue;
|
|
7518
7584
|
let content;
|
|
7519
7585
|
try {
|
|
@@ -7693,7 +7759,7 @@ function registerGoalBridge(ctx, resolver, config) {
|
|
|
7693
7759
|
}
|
|
7694
7760
|
|
|
7695
7761
|
// src/gates/plan-mode-bridge.ts
|
|
7696
|
-
import { existsSync as
|
|
7762
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
7697
7763
|
import { join as join22 } from "node:path";
|
|
7698
7764
|
var PLAN_MODE_BRIDGE_LOGGER = "mstar/plan-mode-bridge";
|
|
7699
7765
|
var PLAN_STATUS_TODO = "Todo";
|
|
@@ -7711,7 +7777,7 @@ function errorMessage5(error) {
|
|
|
7711
7777
|
}
|
|
7712
7778
|
function hasPrepareWindow(harnessDir) {
|
|
7713
7779
|
const statusPath = join22(harnessDir, STATUS_FILE);
|
|
7714
|
-
if (!
|
|
7780
|
+
if (!existsSync21(statusPath))
|
|
7715
7781
|
return false;
|
|
7716
7782
|
const selection = resolveReadWorkflow(harnessDir);
|
|
7717
7783
|
if (selection.kind === "error")
|
|
@@ -8170,7 +8236,7 @@ var inject = ["loader"];
|
|
|
8170
8236
|
function packagedCommandsDir() {
|
|
8171
8237
|
try {
|
|
8172
8238
|
const dir = fileURLToPath3(new URL("../harness-commands", import.meta.url));
|
|
8173
|
-
return
|
|
8239
|
+
return existsSync22(dir) ? dir : undefined;
|
|
8174
8240
|
} catch {
|
|
8175
8241
|
return;
|
|
8176
8242
|
}
|