@mstar-harness/opencode 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/CHANGELOG.md +27 -0
- package/dist/mstar.js +200 -113
- 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 +1 -1
- 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/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,33 @@ The monorepo root [CHANGELOG.md](../../CHANGELOG.md) summarizes cross-surface re
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [3.2.0] - 2026-08-23
|
|
10
|
+
|
|
11
|
+
### Harness
|
|
12
|
+
|
|
13
|
+
- Hoisted the shared plan-output contract out of `references/codebase-audit.md` into the `mstar-audit` SKILL.md core as **`## Plan output (all variants)`**: write-only-on-selection boundary, `{PLAN_DIR}/audit-<date>/` layout (README index + numbered plan files), `plan.main.md` + plan-quality-bar enrichment, Status-block fields + status values, `git rev-parse --short HEAD` commit stamp, and the four handoff steps (promote / state machine / fast-track Prepare / SDD or inline dispatch). Both variants (`codebase-audit`, `pr-review`) and both commands (`/codebase-audit`, `/pr-deep-review`) now cite the core section; `pr-review.md` § Plan output carries no `codebase-audit.md` cites. Engine audit Status-block and scaffold validators repoint their spec cites to `mstar-audit SKILL.md § Plan output`, and `pr-review.md` § Evidence rules now cites `finding-format.md` § What disqualifies a finding. Closes residual R1 (hoist when a third variant arrives — that condition is now met by the `pr` variant) early.
|
|
14
|
+
- Restructured `mstar-audit` into a **variant carrier**: SKILL.md now holds the common core (hard rules, recon, attack-and-vet discipline, variant dispatch table, output-format contract), with full codebase-audit detail moved verbatim to `references/codebase-audit.md` (Phase 2 category fan-out + subagent-prompt requirements, effort table, scope variants, Phase 4 plan writing, audit index / plan-file output templates, `mstar audit scaffold` callout, handoff to execution). `pr-deep-review` no longer loads full-audit-only content; pointer surfaces (`references/pr-review.md`, both commands, `code-reviewer` role, `mstar-harness-core` index) cite the common core + the correct variant reference.
|
|
15
|
+
- Added a **generic deep PR review** command (`pr-deep-review`) + `mstar-audit` `pr` scope variant: worktree-isolated, evidence-first, verdict-producing review with concern lenses, linked-issue hygiene, and batch sibling-PR support.
|
|
16
|
+
- Renamed `mstar-plan-conventions` → **`mstar-conventions`** and `mstar-plan-artifacts` → **`mstar-artifacts`**: the two skills are general harness conventions (paths, artifacts), not plan-specific, so the `plan-` prefix was dropped. All live surfaces swept (`skills/**` load orders, index rows and cross-cites, `commands/**`, `AGENTS.md`, `README.md` + `README_CN.md` skill tables, `docs/cli.md`, `.cursor/` routing-eval fixtures + local validation, `scripts/` guards, engine/dsh/cli source comments and path literals, dsh test expectations). Historical changelogs and engine test-fixture prose are untouched — old names there are correct as historical record.
|
|
17
|
+
|
|
18
|
+
- Version alignment with harness **3.2.0** (no OpenCode package API change).
|
|
19
|
+
|
|
20
|
+
See root [CHANGELOG.md](../../CHANGELOG.md) **3.2.0**.
|
|
21
|
+
|
|
22
|
+
## [3.1.3] - 2026-08-23
|
|
23
|
+
|
|
24
|
+
### Harness
|
|
25
|
+
|
|
26
|
+
- **`mstar audit promote` (CLI)**: selected audit plans can now enter the v2 workflow lifecycle as `type: plan` — `promoteAuditPlans` writes the workflow snapshot (`{HARNESS_DIR}/workflows/<id>/snapshot.json`, one Todo `PlanRow` per selected plan, `id` + `title` + `file`) **before** registering the workflow in root `status.json`, so the snapshot-before-register invariant holds. `--plans` accepts the README Plan column id, stem, or basename; `--workflow` defaults to the `audit-<date>` dir basename; `--harness` defaults to the resolved `{HARNESS_DIR}`. Promote stays an explicit post-selection action — the audit itself never registers (advisory contract preserved).
|
|
27
|
+
- **Engine**: `promoteAuditPlans` exported from `@mstar-harness/engine` (titles come from the audit README index, falling back to `readPlanFileSummary`).
|
|
28
|
+
- **Harness skills**: `mstar-audit` Handoff step 1 now names `mstar audit promote <audit-dir> --plans <ids>` as the first-class v2 path (manual `mstar-plan-artifacts` wording kept as fallback).
|
|
29
|
+
- **Thinned the iteration slash commands** (`/iteration-start`, `/iteration-drive`, `/iteration-loop`) into wrappers: shared PM invariants, session todos, the continuous-execution STOP list, and the assignment-preflight bash (warn-only + `enforcement: hard` fail-fast) now live once in `skills/mstar-iteration/references/command-shared-invariants.md`, and `mstar-iteration` points at it. Frontmatter (`name` / `description` / `agent` / `input`) and each command's unique bits (start grill-me, drive helper discovery, loop do-not-load-grill-me) are unchanged.
|
|
30
|
+
- **Trigger-strong `mstar-iteration` description**: the skill now loads for "start an iteration" / "drive the iteration" / "run an autonomous loop" even when no `/iteration-*` slash command fires; phase labels no longer treat command names as phase names.
|
|
31
|
+
|
|
32
|
+
- Version alignment with harness **3.1.3** (no OpenCode package API change).
|
|
33
|
+
|
|
34
|
+
See root [CHANGELOG.md](../../CHANGELOG.md) **3.1.3**.
|
|
35
|
+
|
|
9
36
|
## [3.1.2] - 2026-08-21
|
|
10
37
|
|
|
11
38
|
### Harness
|
package/dist/mstar.js
CHANGED
|
@@ -63,11 +63,11 @@ __export(exports_engine, {
|
|
|
63
63
|
releaseLease: () => releaseLease,
|
|
64
64
|
registerWorkflow: () => registerWorkflow,
|
|
65
65
|
referenceExists: () => referenceExists,
|
|
66
|
-
redactSecrets: () => redactSecrets,
|
|
67
66
|
readProgressLedger: () => readProgressLedger,
|
|
68
67
|
readJson: () => readJson,
|
|
69
68
|
readHarnessVersion: () => readHarnessVersion,
|
|
70
69
|
pushCadenceProbe: () => pushCadenceProbe,
|
|
70
|
+
promoteAuditPlans: () => promoteAuditPlans,
|
|
71
71
|
planQualityBar: () => planQualityBar,
|
|
72
72
|
planExecutionLeaseLocations: () => planExecutionLeaseLocations,
|
|
73
73
|
parseMstarc: () => parseMstarc,
|
|
@@ -185,11 +185,11 @@ import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync a
|
|
|
185
185
|
import { join as join9 } from "node:path";
|
|
186
186
|
import { copyFileSync, mkdirSync as mkdirSync6, readFileSync as readFileSync8, readdirSync as readdirSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
187
187
|
import { dirname as dirname7, isAbsolute as isAbsolute6, join as join10, relative as relative3, resolve as resolve8, sep as sep2 } from "node:path";
|
|
188
|
-
import { mkdirSync as mkdirSync7, readdirSync as readdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
189
|
-
import { join as join11, resolve as resolve9 } from "node:path";
|
|
190
|
-
import { existsSync as
|
|
191
|
-
import { basename as
|
|
192
|
-
import { existsSync as
|
|
188
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readdirSync as readdirSync7, readFileSync as readFileSync9, rmdirSync as rmdirSync2, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
189
|
+
import { basename as basename4, join as join11, resolve as resolve9, sep as sep3 } from "node:path";
|
|
190
|
+
import { existsSync as existsSync8, readdirSync as readdirSync8, readFileSync as readFileSync10 } from "node:fs";
|
|
191
|
+
import { basename as basename5, isAbsolute as isAbsolute7, join as join12, relative as relative4, resolve as resolve10, sep as sep4 } from "node:path";
|
|
192
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
193
193
|
import { join as join13 } from "node:path";
|
|
194
194
|
function applyEnforcement(gate, opts) {
|
|
195
195
|
return { ...gate, hardBlocked: opts.hard && gate.violations.length > 0 };
|
|
@@ -1434,40 +1434,41 @@ function validateStatusV2(docOrPath, opts = {}) {
|
|
|
1434
1434
|
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`));
|
|
1435
1435
|
}
|
|
1436
1436
|
if (typeof entry.started_at === "string" && typeof snapshot.started_at === "string" && entry.started_at !== snapshot.started_at) {
|
|
1437
|
-
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
|
|
1437
|
+
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`));
|
|
1438
1438
|
}
|
|
1439
1439
|
}
|
|
1440
1440
|
}
|
|
1441
1441
|
return { ok: violations.length === 0, violations };
|
|
1442
1442
|
}
|
|
1443
|
+
function registerWorkflowEntryLocked(statusPath, entry) {
|
|
1444
|
+
const harnessDir = dirname5(statusPath);
|
|
1445
|
+
const current = readJson(statusPath);
|
|
1446
|
+
const fresh = Object.keys(current).length === 0;
|
|
1447
|
+
const doc = fresh ? { version: 2, updated_at: todayString(), workflows: [] } : current;
|
|
1448
|
+
if (!fresh && !Array.isArray(doc.workflows)) {
|
|
1449
|
+
throw new Error("refusing to modify status.json: workflows must be an array — a v1 root must be migrated first (run `mstar migrate`)");
|
|
1450
|
+
}
|
|
1451
|
+
const existing = doc.workflows.findIndex((wf) => wf.id === entry.id);
|
|
1452
|
+
if (existing >= 0) {
|
|
1453
|
+
doc.workflows[existing] = entry;
|
|
1454
|
+
} else {
|
|
1455
|
+
doc.workflows.push(entry);
|
|
1456
|
+
}
|
|
1457
|
+
doc.updated_at = todayString();
|
|
1458
|
+
const gate = validateStatusV2(doc, { harnessDir });
|
|
1459
|
+
if (!gate.ok) {
|
|
1460
|
+
throw new Error(`refusing to write invalid status.json: ${gate.violations.map((v) => v.message).join("; ")}`);
|
|
1461
|
+
}
|
|
1462
|
+
writeJson(statusPath, doc);
|
|
1463
|
+
return doc;
|
|
1464
|
+
}
|
|
1443
1465
|
async function registerWorkflow(root, entry) {
|
|
1444
1466
|
const entryGate = validateWorkflowEntry(entry);
|
|
1445
1467
|
if (!entryGate.ok) {
|
|
1446
1468
|
throw new Error(`refusing to register invalid workflow entry: ${entryGate.violations.map((v) => v.message).join("; ")}`);
|
|
1447
1469
|
}
|
|
1448
1470
|
const statusPath = resolve5(root);
|
|
1449
|
-
|
|
1450
|
-
return withStatusWriteLock(statusPath, () => {
|
|
1451
|
-
const current = readJson(statusPath);
|
|
1452
|
-
const fresh = Object.keys(current).length === 0;
|
|
1453
|
-
const doc = fresh ? { version: 2, updated_at: todayString(), workflows: [] } : current;
|
|
1454
|
-
if (!fresh && !Array.isArray(doc.workflows)) {
|
|
1455
|
-
throw new Error("refusing to modify status.json: workflows must be an array — a v1 root must be migrated first (run `mstar migrate`)");
|
|
1456
|
-
}
|
|
1457
|
-
const existing = doc.workflows.findIndex((wf) => wf.id === entry.id);
|
|
1458
|
-
if (existing >= 0) {
|
|
1459
|
-
doc.workflows[existing] = entry;
|
|
1460
|
-
} else {
|
|
1461
|
-
doc.workflows.push(entry);
|
|
1462
|
-
}
|
|
1463
|
-
doc.updated_at = todayString();
|
|
1464
|
-
const gate = validateStatusV2(doc, { harnessDir });
|
|
1465
|
-
if (!gate.ok) {
|
|
1466
|
-
throw new Error(`refusing to write invalid status.json: ${gate.violations.map((v) => v.message).join("; ")}`);
|
|
1467
|
-
}
|
|
1468
|
-
writeJson(statusPath, doc);
|
|
1469
|
-
return doc;
|
|
1470
|
-
});
|
|
1471
|
+
return withStatusWriteLock(statusPath, () => registerWorkflowEntryLocked(statusPath, entry));
|
|
1471
1472
|
}
|
|
1472
1473
|
async function unregisterWorkflow(root, id) {
|
|
1473
1474
|
if (typeof id !== "string" || id.trim() === "") {
|
|
@@ -3012,9 +3013,11 @@ async function applyMigratePlan(plan) {
|
|
|
3012
3013
|
if (!gate2.ok) {
|
|
3013
3014
|
throw new Error(`refusing to apply migration: invalid project register: ${gate2.violations.map((v) => v.message).join("; ")}`);
|
|
3014
3015
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3016
|
+
if (Object.keys(plan.register.data.entries ?? {}).length > 0) {
|
|
3017
|
+
const filePath = projectTargetOf(plan.register.file);
|
|
3018
|
+
mkdirSync6(dirname7(filePath), { recursive: true });
|
|
3019
|
+
writeJson(filePath, plan.register.data);
|
|
3020
|
+
}
|
|
3018
3021
|
}
|
|
3019
3022
|
if (plan.roadmap !== null) {
|
|
3020
3023
|
const filePath = projectTargetOf(plan.roadmap.file);
|
|
@@ -3444,14 +3447,14 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3444
3447
|
const violations = [];
|
|
3445
3448
|
const blocks = parseStatusBlocks(planText);
|
|
3446
3449
|
if (blocks.length === 0) {
|
|
3447
|
-
violations.push(violation9("medium", "audit.status.missing-block", "no `## Status` block found — audit plan files carry the Status block fields (mstar-audit SKILL § Plan
|
|
3450
|
+
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"));
|
|
3448
3451
|
return { ok: false, violations };
|
|
3449
3452
|
}
|
|
3450
3453
|
blocks.forEach((block, index) => {
|
|
3451
3454
|
const label = blocks.length > 1 ? ` #${index + 1}` : "";
|
|
3452
3455
|
for (const field of AUDIT_STATUS_FIELDS) {
|
|
3453
3456
|
if (!block.fields.has(field)) {
|
|
3454
|
-
violations.push(violation9("medium", "audit.status.missing-field", `Status block${label} missing required field "${field}" (mstar-audit SKILL § Plan
|
|
3457
|
+
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`));
|
|
3455
3458
|
}
|
|
3456
3459
|
}
|
|
3457
3460
|
const check = (field, pattern, code, expected) => {
|
|
@@ -3459,7 +3462,7 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3459
3462
|
if (value === undefined)
|
|
3460
3463
|
return;
|
|
3461
3464
|
if (!pattern.test(value)) {
|
|
3462
|
-
violations.push(violation9("medium", code, `Status block${label} "${field}" = "${value}" — expected ${expected} (mstar-audit SKILL § Plan
|
|
3465
|
+
violations.push(violation9("medium", code, `Status block${label} "${field}" = "${value}" — expected ${expected} (mstar-audit SKILL.md § Plan output)`, `fix \`- **${field}**:\` to one of: ${expected}`));
|
|
3463
3466
|
}
|
|
3464
3467
|
};
|
|
3465
3468
|
check("Priority", /^P[123]$/, "audit.status.invalid-priority", "P1 | P2 | P3");
|
|
@@ -3471,60 +3474,6 @@ function validateAuditStatusBlocks(planText) {
|
|
|
3471
3474
|
});
|
|
3472
3475
|
return { ok: violations.length === 0, violations };
|
|
3473
3476
|
}
|
|
3474
|
-
function buildLineStarts(text) {
|
|
3475
|
-
const starts = [0];
|
|
3476
|
-
for (let i = 0;i < text.length; i++) {
|
|
3477
|
-
if (text[i] === `
|
|
3478
|
-
`)
|
|
3479
|
-
starts.push(i + 1);
|
|
3480
|
-
}
|
|
3481
|
-
return starts;
|
|
3482
|
-
}
|
|
3483
|
-
function lineAt(starts, index) {
|
|
3484
|
-
let lo = 0;
|
|
3485
|
-
let hi = starts.length - 1;
|
|
3486
|
-
while (lo < hi) {
|
|
3487
|
-
const mid = lo + hi + 1 >> 1;
|
|
3488
|
-
if (starts[mid] <= index)
|
|
3489
|
-
lo = mid;
|
|
3490
|
-
else
|
|
3491
|
-
hi = mid - 1;
|
|
3492
|
-
}
|
|
3493
|
-
return lo + 1;
|
|
3494
|
-
}
|
|
3495
|
-
function redactSecrets(text, filePath) {
|
|
3496
|
-
const starts = buildLineStarts(text);
|
|
3497
|
-
const marker = (type, index) => `[REDACTED ${type}@${lineAt(starts, index)}${filePath === undefined ? "" : ` in ${filePath}`}]`;
|
|
3498
|
-
const replacements = [];
|
|
3499
|
-
const findings = [];
|
|
3500
|
-
for (const pattern of WHOLE_MATCH_PATTERNS) {
|
|
3501
|
-
for (const match of text.matchAll(pattern.re)) {
|
|
3502
|
-
if (match.index === undefined)
|
|
3503
|
-
continue;
|
|
3504
|
-
replacements.push({ index: match.index, length: match[0].length, text: marker(pattern.type, match.index) });
|
|
3505
|
-
findings.push({ line: lineAt(starts, match.index), type: pattern.type });
|
|
3506
|
-
}
|
|
3507
|
-
}
|
|
3508
|
-
for (const pattern of VALUE_PATTERNS) {
|
|
3509
|
-
for (const match of text.matchAll(pattern.re)) {
|
|
3510
|
-
if (match.index === undefined)
|
|
3511
|
-
continue;
|
|
3512
|
-
const type = pattern.typeOf(match[2]);
|
|
3513
|
-
const replacement = `${match[1]}${match[2]}${match[3]}${match[4]}${marker(type, match.index)}`;
|
|
3514
|
-
replacements.push({ index: match.index, length: match[0].length, text: replacement });
|
|
3515
|
-
findings.push({ line: lineAt(starts, match.index), type });
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
replacements.sort((a, b) => b.index - a.index);
|
|
3519
|
-
let out = text;
|
|
3520
|
-
for (const r of replacements)
|
|
3521
|
-
out = out.slice(0, r.index) + r.text + out.slice(r.index + r.length);
|
|
3522
|
-
const deduped = new Map;
|
|
3523
|
-
for (const f of findings)
|
|
3524
|
-
deduped.set(`${f.line}:${f.type}`, f);
|
|
3525
|
-
const sorted = [...deduped.values()].sort((a, b) => a.line - b.line || a.type.localeCompare(b.type));
|
|
3526
|
-
return { text: out, findings: sorted };
|
|
3527
|
-
}
|
|
3528
3477
|
function slugify(title) {
|
|
3529
3478
|
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3530
3479
|
}
|
|
@@ -3659,6 +3608,137 @@ function scaffoldAuditPlan(outDir, findings, options = {}) {
|
|
|
3659
3608
|
}));
|
|
3660
3609
|
return { outDir: resolve9(outDir), date, files: written, nextNumber: next };
|
|
3661
3610
|
}
|
|
3611
|
+
async function promoteAuditPlans(outDir, selected, options) {
|
|
3612
|
+
if (selected.length === 0) {
|
|
3613
|
+
throw new Error("promoteAuditPlans: at least one plan id must be selected (--plans 001,002,…)");
|
|
3614
|
+
}
|
|
3615
|
+
if (typeof options.harnessDir !== "string" || options.harnessDir.trim() === "") {
|
|
3616
|
+
throw new Error("promoteAuditPlans: options.harnessDir is required (must contain status.json + workflows/)");
|
|
3617
|
+
}
|
|
3618
|
+
const workflowId = options.workflowId ?? basename4(resolve9(outDir));
|
|
3619
|
+
assertSafePathComponent(workflowId, "workflow id");
|
|
3620
|
+
const harnessDir = resolve9(options.harnessDir);
|
|
3621
|
+
const statusPath = join11(harnessDir, "status.json");
|
|
3622
|
+
const workflowDir = join11(harnessDir, "workflows", workflowId);
|
|
3623
|
+
const snapshotPath = join11(workflowDir, WORKFLOW_SNAPSHOT_FILE);
|
|
3624
|
+
const planFiles = resolveSelectedPlanFiles(outDir, selected);
|
|
3625
|
+
const indexRows = readExecutionOrderIndex(outDir);
|
|
3626
|
+
const plans = planFiles.map((planFile) => {
|
|
3627
|
+
const stem = planFile.replace(/\.md$/, "");
|
|
3628
|
+
const num = stem.slice(0, 3);
|
|
3629
|
+
const indexRow = indexRows.get(num);
|
|
3630
|
+
const title = indexRow?.title ?? readPlanFileSummary(join11(outDir, planFile)).title;
|
|
3631
|
+
return {
|
|
3632
|
+
id: stem,
|
|
3633
|
+
title,
|
|
3634
|
+
file: planFileRel(outDir, planFile),
|
|
3635
|
+
status: "Todo"
|
|
3636
|
+
};
|
|
3637
|
+
});
|
|
3638
|
+
const now = new Date;
|
|
3639
|
+
const snapshot = {
|
|
3640
|
+
schema_version: 1,
|
|
3641
|
+
id: workflowId,
|
|
3642
|
+
type: "plan",
|
|
3643
|
+
status: "running",
|
|
3644
|
+
started_at: now.toISOString(),
|
|
3645
|
+
updated_at: now.toISOString().slice(0, 10),
|
|
3646
|
+
plans
|
|
3647
|
+
};
|
|
3648
|
+
const entry = {
|
|
3649
|
+
id: workflowId,
|
|
3650
|
+
type: "plan",
|
|
3651
|
+
started_at: snapshot.started_at,
|
|
3652
|
+
dir: `workflows/${workflowId}`
|
|
3653
|
+
};
|
|
3654
|
+
const entryGate = validateWorkflowEntry(entry);
|
|
3655
|
+
if (!entryGate.ok) {
|
|
3656
|
+
throw new Error(`refusing to register invalid workflow entry: ${entryGate.violations.map((v) => v.message).join("; ")}`);
|
|
3657
|
+
}
|
|
3658
|
+
await withStatusWriteLock(statusPath, () => {
|
|
3659
|
+
if (existsSync7(snapshotPath)) {
|
|
3660
|
+
throw new Error(`refusing to promote audit plans: workflow ${JSON.stringify(workflowId)} already exists ` + `(snapshot at ${snapshotPath}) — re-promote would drop its registered plan rows; ` + `remove that workflow before promoting again`);
|
|
3661
|
+
}
|
|
3662
|
+
mkdirSync7(workflowDir, { recursive: true });
|
|
3663
|
+
try {
|
|
3664
|
+
writeJson(snapshotPath, snapshot);
|
|
3665
|
+
registerWorkflowEntryLocked(statusPath, entry);
|
|
3666
|
+
} catch (error) {
|
|
3667
|
+
rmSync(snapshotPath, { force: true });
|
|
3668
|
+
try {
|
|
3669
|
+
if (readdirSync7(workflowDir).length === 0) {
|
|
3670
|
+
rmdirSync2(workflowDir);
|
|
3671
|
+
}
|
|
3672
|
+
} catch {}
|
|
3673
|
+
throw error;
|
|
3674
|
+
}
|
|
3675
|
+
return { workflowId, snapshotPath };
|
|
3676
|
+
});
|
|
3677
|
+
return { workflowId, snapshotPath };
|
|
3678
|
+
}
|
|
3679
|
+
function resolveSelectedPlanFiles(outDir, selected) {
|
|
3680
|
+
const files = readdirSync7(outDir).filter((f) => /^\d{3}-.*\.md$/.test(f)).sort();
|
|
3681
|
+
const byNum = new Map;
|
|
3682
|
+
const byStem = new Map;
|
|
3683
|
+
for (const file of files) {
|
|
3684
|
+
const stem = file.replace(/\.md$/, "");
|
|
3685
|
+
if (!byNum.has(stem.slice(0, 3))) {
|
|
3686
|
+
byNum.set(stem.slice(0, 3), file);
|
|
3687
|
+
}
|
|
3688
|
+
byStem.set(stem, file);
|
|
3689
|
+
}
|
|
3690
|
+
const resolved = [];
|
|
3691
|
+
const seen = new Set;
|
|
3692
|
+
for (const id of selected) {
|
|
3693
|
+
const file = byNum.get(id) ?? byStem.get(id) ?? byStem.get(id.replace(/\.md$/, ""));
|
|
3694
|
+
if (file === undefined) {
|
|
3695
|
+
throw new Error(`promoteAuditPlans: selected plan ${JSON.stringify(id)} does not match any NNN-*.md file in ${resolve9(outDir)}`);
|
|
3696
|
+
}
|
|
3697
|
+
if (!seen.has(file)) {
|
|
3698
|
+
seen.add(file);
|
|
3699
|
+
resolved.push(file);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
return resolved;
|
|
3703
|
+
}
|
|
3704
|
+
function readExecutionOrderIndex(outDir) {
|
|
3705
|
+
const readmePath = join11(outDir, "README.md");
|
|
3706
|
+
let text;
|
|
3707
|
+
try {
|
|
3708
|
+
text = readFileSync9(readmePath, "utf8");
|
|
3709
|
+
} catch {
|
|
3710
|
+
return new Map;
|
|
3711
|
+
}
|
|
3712
|
+
const rows = new Map;
|
|
3713
|
+
const lines = text.split(`
|
|
3714
|
+
`);
|
|
3715
|
+
let inSection = false;
|
|
3716
|
+
for (const line of lines) {
|
|
3717
|
+
if (/^##\s+Execution order & status/.test(line)) {
|
|
3718
|
+
inSection = true;
|
|
3719
|
+
continue;
|
|
3720
|
+
}
|
|
3721
|
+
if (inSection && /^#/.test(line)) {
|
|
3722
|
+
break;
|
|
3723
|
+
}
|
|
3724
|
+
if (!inSection)
|
|
3725
|
+
continue;
|
|
3726
|
+
const cells = line.split(/(?<!\\)\|/).map((c) => c.trim());
|
|
3727
|
+
if (cells.length >= 3 && /^\d{3}$/.test(cells[1])) {
|
|
3728
|
+
rows.set(cells[1], { title: cells[2].replace(/\\\|/g, "|") });
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
return rows;
|
|
3732
|
+
}
|
|
3733
|
+
function planFileRel(outDir, planFile) {
|
|
3734
|
+
const resolved = resolve9(outDir);
|
|
3735
|
+
const parts = resolved.split(sep3);
|
|
3736
|
+
const plansIdx = parts.lastIndexOf("plans");
|
|
3737
|
+
if (plansIdx >= 0) {
|
|
3738
|
+
return `${parts.slice(plansIdx + 1).join(sep3)}${sep3}${planFile}`;
|
|
3739
|
+
}
|
|
3740
|
+
return planFile;
|
|
3741
|
+
}
|
|
3662
3742
|
function violation10(severity, code, message, fix) {
|
|
3663
3743
|
return { ok: false, severity, code, message, fix };
|
|
3664
3744
|
}
|
|
@@ -3875,7 +3955,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
3875
3955
|
for (const { ref, isSymbol, module } of refs) {
|
|
3876
3956
|
if (!isSymbol || module === undefined) {
|
|
3877
3957
|
const candidate = ref.replace(LINE_SUFFIX_RE, "").replace(ANCHOR_RE, "");
|
|
3878
|
-
if (
|
|
3958
|
+
if (existsSync8(resolve10(repoRoot, candidate))) {
|
|
3879
3959
|
checked++;
|
|
3880
3960
|
} else {
|
|
3881
3961
|
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"));
|
|
@@ -3906,7 +3986,7 @@ function collectKnowledgeDocs(dir) {
|
|
|
3906
3986
|
if (entry.isDirectory()) {
|
|
3907
3987
|
stack.push(full);
|
|
3908
3988
|
} else if (entry.name.endsWith(".md") && entry.name !== "README.md" && entry.name !== "index.md") {
|
|
3909
|
-
docs.push(relative4(dir, full).split(
|
|
3989
|
+
docs.push(relative4(dir, full).split(sep4).join("/"));
|
|
3910
3990
|
}
|
|
3911
3991
|
}
|
|
3912
3992
|
}
|
|
@@ -3923,7 +4003,7 @@ function normalizeIndexRef(cell) {
|
|
|
3923
4003
|
function assertIndexRows(knowledgeDir) {
|
|
3924
4004
|
const violations = [];
|
|
3925
4005
|
const readmePath = join12(knowledgeDir, "README.md");
|
|
3926
|
-
if (!
|
|
4006
|
+
if (!existsSync8(readmePath)) {
|
|
3927
4007
|
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"));
|
|
3928
4008
|
return { ok: false, violations };
|
|
3929
4009
|
}
|
|
@@ -3955,7 +4035,7 @@ function compoundRefreshScope(harnessDir, projectRoot) {
|
|
|
3955
4035
|
];
|
|
3956
4036
|
}
|
|
3957
4037
|
function isFileLikeRoot(root) {
|
|
3958
|
-
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(
|
|
4038
|
+
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(basename5(root));
|
|
3959
4039
|
}
|
|
3960
4040
|
function scopeGuard(path, allowedRoots) {
|
|
3961
4041
|
const resolved = resolve10(path);
|
|
@@ -3964,7 +4044,7 @@ function scopeGuard(path, allowedRoots) {
|
|
|
3964
4044
|
if (isFileLikeRoot(r)) {
|
|
3965
4045
|
if (resolved === r)
|
|
3966
4046
|
return { ok: true, violations: [] };
|
|
3967
|
-
} else if (resolved === r || resolved.startsWith(r +
|
|
4047
|
+
} else if (resolved === r || resolved.startsWith(r + sep4)) {
|
|
3968
4048
|
return { ok: true, violations: [] };
|
|
3969
4049
|
}
|
|
3970
4050
|
}
|
|
@@ -4092,7 +4172,7 @@ function planQualityBar(planText) {
|
|
|
4092
4172
|
if (token !== null) {
|
|
4093
4173
|
const text = trimmed.length > 80 ? `${trimmed.slice(0, 77)}...` : trimmed;
|
|
4094
4174
|
findings.push({ token, line: i + 1, text });
|
|
4095
|
-
violations.push(violation11("medium", "lint.plan-quality.placeholder", `placeholder token "${token}" at line ${i + 1}: "${text}"`, "replace the placeholder with concrete content before locking the plan (mstar-
|
|
4175
|
+
violations.push(violation11("medium", "lint.plan-quality.placeholder", `placeholder token "${token}" at line ${i + 1}: "${text}"`, "replace the placeholder with concrete content before locking the plan (mstar-artifacts/references/plan-quality-bar.md; templates/plan.main.md placeholder scan)"));
|
|
4096
4176
|
}
|
|
4097
4177
|
}
|
|
4098
4178
|
return { ok: violations.length === 0, violations, findings };
|
|
@@ -4186,7 +4266,7 @@ function validateRoleMapping(rolesDir, options = {}) {
|
|
|
4186
4266
|
const violations = [];
|
|
4187
4267
|
const referenceById = new Map(mapping.map((m) => [m.agentId, m.reference]));
|
|
4188
4268
|
for (const { agentId, reference } of mapping) {
|
|
4189
|
-
if (!
|
|
4269
|
+
if (!existsSync9(join13(rolesDir, reference))) {
|
|
4190
4270
|
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`));
|
|
4191
4271
|
}
|
|
4192
4272
|
}
|
|
@@ -4382,7 +4462,7 @@ var SEVERITY_ORDER, MSTARC_FILE = ".mstarc", MSTARC_SECTION = "config", MSTARC_H
|
|
|
4382
4462
|
!.agents/knowledge/**
|
|
4383
4463
|
!.agents/specs/
|
|
4384
4464
|
!.agents/specs/**
|
|
4385
|
-
`, GITIGNORE_PROCESS_ENTRIES, GITIGNORE_PROCESS_ENTRIES_AGENTS, DATE_PART, RFC3339_Z_RE, DATE_ONLY_RE, STATUS_WRITE_LOCKDIR = ".status-write.lockdir", LOCKDIR_HOLDER_PID = "holder.pid", heldLockDirs, BRANCH_FORMS_HINT = '"Working branch: <existing>" | "Working branch: create <new> from <base>" | "Branch policy: direct on <branch> — <reason>"', REQUIRED_FIELDS, ASSIGNMENT_ENFORCEMENT_BOLD_RE, ASSIGNMENT_ENFORCEMENT_PLAIN_RE, COMPASS_ENFORCEMENT_RE, ASSIGNMENT_BODY_START_RE, ASSIGNMENT_HEADING_RE, ASSIGNMENT_FIELD_RE, WORKFLOW_SNAPSHOT_FILE = "snapshot.json", WORKFLOW_LIFECYCLE_STATUSES, WORKFLOW_TERMINAL_STATUSES, WORKFLOW_LIFECYCLE_TYPES, DATE_RE, PLAN_STATUSES, RESIDUAL_DECISIONS, RESIDUAL_LIFECYCLES, validateStatus, DEFAULT_PROBE_TIMEOUT_MS = 1e4, QC_ALIGNMENT_FIELDS, SddScriptError, GIT_CAPTURE_MAX_BYTES, COMPASS_STATUSES, DATE_RE2, PLAN_STATUS_DONE = "Done", COMPASS_FILE = "delivery-compass.md", INDEX_README = "README.md", INDEX_HEADER = "| Iteration | Path | Description | Status |", PROJECT_ROADMAP_FILE = "roadmap.md", PROJECT_REFERENCES_DIR = "references", PROJECT_REGISTER_FILE = "residuals.json", _DEFAULT_PROJECT = "_default", ROADMAP_STATUSES, DATE_RE3, ROLLUP_FIELDS, MIGRATE_STATUS_FILE = "status.json", ARCHIVED_STATUS_V1_FILE = "archived/status.v1.json", NOTES_LEDGER_FILE = "notes.jsonl", DATE_RE4, ROOT_METADATA_LIFT_KEYS, RAW_GROUP = "__raw", isMap = (v) => typeof v === "object" && v !== null && !Array.isArray(v), HEX_RE, OKLCH_RE, PX_RE, PLACEHOLDER_RE, TYPOGRAPHY_PROPS, REF_RE, REF_GROUPS, isPlaceholder = (value) => PLACEHOLDER_RE.test(value), PARITY_GROUPS, GRAY_STEPS, ALPHA_STEPS, ACCENT_SCALES, L3_BODY_ITEM_IDS, LEVEL_RANK, AUDIT_PRIORITIES, AUDIT_EFFORTS, AUDIT_RISKS, AUDIT_CATEGORIES, AUDIT_STATUS_FIELDS,
|
|
4465
|
+
`, GITIGNORE_PROCESS_ENTRIES, GITIGNORE_PROCESS_ENTRIES_AGENTS, DATE_PART, RFC3339_Z_RE, DATE_ONLY_RE, STATUS_WRITE_LOCKDIR = ".status-write.lockdir", LOCKDIR_HOLDER_PID = "holder.pid", heldLockDirs, BRANCH_FORMS_HINT = '"Working branch: <existing>" | "Working branch: create <new> from <base>" | "Branch policy: direct on <branch> — <reason>"', REQUIRED_FIELDS, ASSIGNMENT_ENFORCEMENT_BOLD_RE, ASSIGNMENT_ENFORCEMENT_PLAIN_RE, COMPASS_ENFORCEMENT_RE, ASSIGNMENT_BODY_START_RE, ASSIGNMENT_HEADING_RE, ASSIGNMENT_FIELD_RE, WORKFLOW_SNAPSHOT_FILE = "snapshot.json", WORKFLOW_LIFECYCLE_STATUSES, WORKFLOW_TERMINAL_STATUSES, WORKFLOW_LIFECYCLE_TYPES, DATE_RE, PLAN_STATUSES, RESIDUAL_DECISIONS, RESIDUAL_LIFECYCLES, validateStatus, DEFAULT_PROBE_TIMEOUT_MS = 1e4, QC_ALIGNMENT_FIELDS, SddScriptError, GIT_CAPTURE_MAX_BYTES, COMPASS_STATUSES, DATE_RE2, PLAN_STATUS_DONE = "Done", COMPASS_FILE = "delivery-compass.md", INDEX_README = "README.md", INDEX_HEADER = "| Iteration | Path | Description | Status |", PROJECT_ROADMAP_FILE = "roadmap.md", PROJECT_REFERENCES_DIR = "references", PROJECT_REGISTER_FILE = "residuals.json", _DEFAULT_PROJECT = "_default", ROADMAP_STATUSES, DATE_RE3, ROLLUP_FIELDS, MIGRATE_STATUS_FILE = "status.json", ARCHIVED_STATUS_V1_FILE = "archived/status.v1.json", NOTES_LEDGER_FILE = "notes.jsonl", DATE_RE4, ROOT_METADATA_LIFT_KEYS, RAW_GROUP = "__raw", isMap = (v) => typeof v === "object" && v !== null && !Array.isArray(v), HEX_RE, OKLCH_RE, PX_RE, PLACEHOLDER_RE, TYPOGRAPHY_PROPS, REF_RE, REF_GROUPS, isPlaceholder = (value) => PLACEHOLDER_RE.test(value), PARITY_GROUPS, GRAY_STEPS, ALPHA_STEPS, ACCENT_SCALES, L3_BODY_ITEM_IDS, LEVEL_RANK, AUDIT_PRIORITIES, AUDIT_EFFORTS, AUDIT_RISKS, AUDIT_CATEGORIES, AUDIT_STATUS_FIELDS, escapeCell = (value) => value.replace(/\|/g, "\\|"), truncate = (value, max) => value.length > max ? `${value.slice(0, max)}…` : value, KNOWLEDGE_REQUIRED_FIELDS, KNOWLEDGE_PROBLEM_TYPES, KNOWLEDGE_BUG_PROBLEM_TYPES, KNOWLEDGE_KNOWLEDGE_PROBLEM_TYPES, KNOWLEDGE_SEVERITIES, KNOWLEDGE_RESOLUTION_TYPES, KNOWLEDGE_CATEGORY_MAP, DATE_RE5, isMap2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), REF_EXT_RE, SYMBOL_REF_RE, SCHEME_RE, LINE_SUFFIX_RE, ANCHOR_RE, WALK_SKIP_DIRS, MAX_WALK_FILES = 5000, COMMENT_INTRODUCER = "(?:\\/\\/|\\/\\*|#|;|--|\\s\\*)", REMOVAL_PATH_PATTERNS, TASK_ARTIFACT_RE, SDD_DEEPLINK_RE, TEST_FILE_PATH_RE, TEST_FILE_PHRASE_RE, COMMAND_PROMPT_RE, RUNNER_RE, OUTPUT_TOKEN_RE, PLACEHOLDER_TOKEN_RE, ELLIPSIS_RE, NEGATION_RE, WORKFLOW_VERB_START_RE, PRONOUN_RE, DESCRIPTION_MAX_WORDS = 120, REQUIRED_STRATEGY_SECTIONS, ROLE_MAPPING, SHARED_FAMILIES, DEV_TRACK_PARAMS, QC_REVIEWER_PARAMS, LOAD_ORDER_HEADING_RE, FIVE_QUESTION_SECTIONS, HEADING_RE, RUNTIME_HEADING_ALIASES;
|
|
4386
4466
|
var init_engine = __esm(() => {
|
|
4387
4467
|
SEVERITY_ORDER = ["critical", "high", "medium", "low", "nit"];
|
|
4388
4468
|
CONFIG_KEYS = {
|
|
@@ -4497,20 +4577,6 @@ var init_engine = __esm(() => {
|
|
|
4497
4577
|
"direction"
|
|
4498
4578
|
];
|
|
4499
4579
|
AUDIT_STATUS_FIELDS = ["Priority", "Effort", "Risk", "Depends on", "Category", "Planned at"];
|
|
4500
|
-
WHOLE_MATCH_PATTERNS = [
|
|
4501
|
-
{ type: "private-key", re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/g },
|
|
4502
|
-
{ type: "aws-access-key", re: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
4503
|
-
{ type: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
4504
|
-
{ type: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
4505
|
-
{ type: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\.[A-Za-z0-9_-]{10,1024}\b/g },
|
|
4506
|
-
{ type: "api-secret-key", re: /\bsk-[A-Za-z0-9-]{20,}\b/g }
|
|
4507
|
-
];
|
|
4508
|
-
VALUE_PATTERNS = [
|
|
4509
|
-
{
|
|
4510
|
-
typeOf: (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_-]+/g, "-"),
|
|
4511
|
-
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
|
|
4512
|
-
}
|
|
4513
|
-
];
|
|
4514
4580
|
KNOWLEDGE_REQUIRED_FIELDS = ["module", "date", "problem_type", "category", "severity"];
|
|
4515
4581
|
KNOWLEDGE_PROBLEM_TYPES = [
|
|
4516
4582
|
"build_error",
|
|
@@ -5033,7 +5099,7 @@ async function validateStatusWrite(targetPath, opts = {}) {
|
|
|
5033
5099
|
for (const violation14 of result.violations) {
|
|
5034
5100
|
const fix = violation14.fix ? ` (fix: ${violation14.fix})` : "";
|
|
5035
5101
|
if (enforcement.hard) {
|
|
5036
|
-
log("error", `${path.basename(resolved)} validation (hard gate): [${violation14.severity}] ${violation14.code}: ${violation14.message}${fix} — hardBlocked per Enforcement: hard; refusal requires a host refusal channel (skill: mstar-
|
|
5102
|
+
log("error", `${path.basename(resolved)} validation (hard gate): [${violation14.severity}] ${violation14.code}: ${violation14.message}${fix} — hardBlocked per Enforcement: hard; refusal requires a host refusal channel (skill: mstar-artifacts/references/status-and-residuals.md)`);
|
|
5037
5103
|
} else {
|
|
5038
5104
|
log("warn", `${path.basename(resolved)} validation: [${violation14.severity}] ${violation14.code}: ${violation14.message}${fix}`);
|
|
5039
5105
|
}
|
|
@@ -5143,7 +5209,28 @@ var MorningStarHarnessPlugin = async () => {
|
|
|
5143
5209
|
defaultStatusLogger("error", "hard-gate blocked (hardBlocked=true) — refusal requires a host refusal channel");
|
|
5144
5210
|
}
|
|
5145
5211
|
} else if (input.tool === "edit") {
|
|
5146
|
-
|
|
5212
|
+
classifyDirResolvers = await dirResolversLoader.load();
|
|
5213
|
+
if (harnessDocKindOfTarget(filePath) === null)
|
|
5214
|
+
return;
|
|
5215
|
+
const oldString = args.oldString;
|
|
5216
|
+
const newString = args.newString;
|
|
5217
|
+
const replaceAll = args.replaceAll;
|
|
5218
|
+
let patchedDoc;
|
|
5219
|
+
if (typeof oldString === "string" && oldString.length > 0 && typeof newString === "string" && (replaceAll === undefined || typeof replaceAll === "boolean")) {
|
|
5220
|
+
try {
|
|
5221
|
+
const text = fs.readFileSync(filePath, "utf8");
|
|
5222
|
+
const hits = text.split(oldString).length - 1;
|
|
5223
|
+
if (replaceAll === true || hits === 1) {
|
|
5224
|
+
const patched = text.split(oldString).join(newString);
|
|
5225
|
+
try {
|
|
5226
|
+
patchedDoc = JSON.parse(patched);
|
|
5227
|
+
} catch {
|
|
5228
|
+
patchedDoc = null;
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
} catch {}
|
|
5232
|
+
}
|
|
5233
|
+
const gate2 = patchedDoc !== undefined ? await validateStatusWrite(filePath, { doc: patchedDoc }) : await validateStatusWrite(filePath);
|
|
5147
5234
|
if (gate2?.hardBlocked) {
|
|
5148
5235
|
defaultStatusLogger("error", "hard-gate blocked (hardBlocked=true) — refusal requires a host refusal channel");
|
|
5149
5236
|
}
|
|
@@ -14,9 +14,9 @@ Run a read-only codebase audit that discovers what is worth doing and writes sel
|
|
|
14
14
|
## Boot
|
|
15
15
|
|
|
16
16
|
1. `mstar-harness-core`
|
|
17
|
-
2. `mstar-audit` → SKILL.md(
|
|
17
|
+
2. `mstar-audit` → SKILL.md(common core:hard rules、recon、vet、variant dispatch、`## Plan output (all variants)`)+ `references/codebase-audit.md`(full-audit 变体:Phase 2 类别 + effort、scope variants、Phase 4 变体细则、audit index 模板)
|
|
18
18
|
3. `mstar-roles` → `references/code-reviewer.md`(执行角色:audit 执行体)
|
|
19
|
-
4. `mstar-
|
|
19
|
+
4. `mstar-conventions` (path symbols — `{PLAN_DIR}`, `{HARNESS_DIR}`)
|
|
20
20
|
5. `mstar-host` → active host reference (invoke capability for parallel subagents)
|
|
21
21
|
|
|
22
22
|
## Routing(谁执行 audit)
|
|
@@ -33,7 +33,7 @@ The audit is **advisory** — it does not enter the per-plan state machine (`Tod
|
|
|
33
33
|
|
|
34
34
|
## Execute
|
|
35
35
|
|
|
36
|
-
Execute **`mstar-audit`** end to end(SKILL.md:Recon →
|
|
36
|
+
Execute **`mstar-audit`** end to end(SKILL.md common core:Recon → Vet & prioritize;full-audit detail:**`references/codebase-audit.md`** —— Phase 2 九类别 fan-out、effort `quick` / `standard` / `deep`、scope variants `bare` / `quick` / `deep` / category focus(`security` / `perf` / `tests`, ...)/ `branch` / `next` / `roadmap` / `simplify`、Phase 4 变体细则、audit index 输出模板;plan writing → SKILL.md **`## Plan output (all variants)`**)。Plans → `{PLAN_DIR}/audit-<YYYY-MM-DD>/NNN-<slug>.md` + `README.md` index,per **`mstar-artifacts/references/plan-quality-bar.md`**。
|
|
37
37
|
|
|
38
38
|
Executor: PM dispatches `@code-reviewer`;大型仓库 scout 扇出经 Assignment `Delegation: allowed (scout/explore only, read-only)`(Routing 表)。
|
|
39
39
|
|