@mstar-harness/dsh 3.6.3 → 3.7.1
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.i18n.yaml +2 -2
- package/README.md +8 -8
- package/README.zh.md +7 -5
- package/dist/client/panel/PanelView.d.ts +8 -11
- package/dist/client/panel/TabNav.d.ts +2 -2
- package/dist/client/panel/graph/event-log.d.ts +5 -9
- package/dist/client/panel/graph/project-graph.d.ts +53 -72
- package/dist/client/panel/graph/schema.d.ts +31 -37
- package/dist/client/panel/locale.d.ts +19 -19
- package/dist/client/panel/pages/AgentCanvasPage.d.ts +40 -58
- package/dist/client/panel/pages/EventLogPage.d.ts +6 -6
- package/dist/client/panel/pages/IterationInfoSection.d.ts +9 -11
- package/dist/client/panel/pages/IterationTaskPage.d.ts +3 -3
- package/dist/client/panel/plan-sort.d.ts +3 -6
- package/dist/client/panel/state-section.d.ts +1 -1
- package/dist/client/panel/zones/Legend.d.ts +2 -2
- package/dist/client/panel/zones/ProjectRollup.d.ts +1 -2
- package/dist/client/panel/zones/TaskBoard.d.ts +1 -2
- package/dist/gates/_shared.d.ts +24 -16
- package/dist/gates/adapter.d.ts +6 -9
- package/dist/gates/agent-flow.d.ts +49 -59
- package/dist/gates/agent-personas.d.ts +1 -2
- package/dist/gates/catalog.d.ts +2 -5
- package/dist/gates/dispatch.d.ts +9 -11
- package/dist/gates/fallbacks-advisory.d.ts +55 -18
- package/dist/gates/fallbacks-probe.d.ts +2 -2
- package/dist/gates/fallbacks-seeds.d.ts +1 -1
- package/dist/gates/fallbacks-structural.d.ts +1 -1
- package/dist/gates/goal-bridge.d.ts +6 -9
- package/dist/gates/role-persona.d.ts +123 -7
- package/dist/gates/skill-lint.d.ts +19 -2
- package/dist/gates/system-prompt.d.ts +7 -11
- package/dist/gates/tools.d.ts +1 -1
- package/dist/gates/workflow-ledger.d.ts +21 -28
- package/dist/gates/workflow-policy.d.ts +15 -19
- package/dist/gates/workflow-selection.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +472 -183
- package/dist/types.d.ts +4 -7
- package/harness-commands/iteration-drive.md +6 -6
- package/harness-commands/iteration-loop.md +7 -7
- package/harness-commands/iteration-start.md +8 -8
- package/harness-skills/mstar-coding-behavior/SKILL.md +3 -20
- package/harness-skills/mstar-dispatch-gates/SKILL.md +7 -13
- package/harness-skills/mstar-dispatch-gates/references/leaf-executor-checklist.md +1 -1
- package/harness-skills/mstar-harness-core/SKILL.md +16 -53
- package/harness-skills/mstar-host/references/zcode.md +7 -0
- package/harness-skills/mstar-iteration/SKILL.md +32 -318
- package/harness-skills/mstar-iteration/references/command-shared-invariants.md +1 -1
- package/harness-skills/mstar-iteration/references/phase-1-prepare.md +155 -0
- package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +113 -3
- package/harness-skills/mstar-iteration/references/phase5-helper-discovery.md +1 -1
- package/harness-skills/mstar-roles/SKILL.md +14 -12
- package/harness-skills/mstar-roles/references/_shared/leaf-executor-core.md +5 -6
- package/harness-skills/mstar-roles/references/architect.md +1 -1
- package/harness-skills/mstar-roles/references/code-reviewer.md +11 -1
- package/harness-skills/mstar-roles/references/frontend-dev.md +1 -1
- package/harness-skills/mstar-roles/references/fullstack-dev-shared.md +1 -1
- package/harness-skills/mstar-roles/references/ops-engineer.md +1 -1
- package/harness-skills/mstar-roles/references/product-manager.md +1 -1
- package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +4 -0
- package/harness-skills/mstar-roles/references/project-manager.md +6 -4
- package/harness-skills/mstar-roles/references/prompt-engineer.md +1 -1
- package/harness-skills/mstar-roles/references/qa-engineer.md +1 -1
- package/harness-skills/mstar-roles/references/qc-specialist-shared.md +1 -1
- package/harness-skills/mstar-roles/references/writing-specialist.md +1 -1
- package/harness-skills/mstar-sdd/references/file-handoffs.md +40 -7
- package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +9 -0
- package/harness-skills/mstar-sdd/references/implementer-prompt.md +9 -0
- package/harness-skills/mstar-sdd/references/task-reviewer-prompt.md +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1122,8 +1122,8 @@ var require_lib2 = __commonJS(function(exports, module) {
|
|
|
1122
1122
|
});
|
|
1123
1123
|
|
|
1124
1124
|
// src/index.ts
|
|
1125
|
-
import { existsSync as
|
|
1126
|
-
import { join as
|
|
1125
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18, readdirSync as readdirSync14 } from "node:fs";
|
|
1126
|
+
import { join as join24 } from "node:path";
|
|
1127
1127
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1128
1128
|
import {
|
|
1129
1129
|
apply as applySkillLocal,
|
|
@@ -1147,15 +1147,15 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
1147
1147
|
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync3, realpathSync } from "node:fs";
|
|
1148
1148
|
import { dirname as dirname4, join as join7, resolve as resolve5, sep } from "node:path";
|
|
1149
1149
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
1150
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
1151
|
-
import { isAbsolute as isAbsolute5, resolve as resolve8 } from "node:path";
|
|
1152
|
-
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1153
|
-
import { mkdirSync as mkdirSync6, readdirSync as readdirSync6, readFileSync as readFileSync7, realpathSync as
|
|
1154
|
-
import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute6, join as
|
|
1155
|
-
import { existsSync as
|
|
1156
|
-
import { basename as
|
|
1157
|
-
import { existsSync as
|
|
1158
|
-
import { join as
|
|
1150
|
+
import { existsSync as existsSync7, realpathSync as realpathSync3 } from "node:fs";
|
|
1151
|
+
import { isAbsolute as isAbsolute5, join as join10, resolve as resolve8 } from "node:path";
|
|
1152
|
+
import { execFileSync as execFileSync3, spawn } from "node:child_process";
|
|
1153
|
+
import { mkdirSync as mkdirSync6, readdirSync as readdirSync6, readFileSync as readFileSync7, realpathSync as realpathSync4, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1154
|
+
import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute6, join as join11, relative as relative3, resolve as resolve9 } from "node:path";
|
|
1155
|
+
import { existsSync as existsSync10, readdirSync as readdirSync9, readFileSync as readFileSync10 } from "node:fs";
|
|
1156
|
+
import { basename as basename7, isAbsolute as isAbsolute8, join as join15, relative as relative6, resolve as resolve13, sep as sep4 } from "node:path";
|
|
1157
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
1158
|
+
import { join as join16 } from "node:path";
|
|
1159
1159
|
var SEVERITY_ORDER = ["critical", "high", "medium", "low", "nit"];
|
|
1160
1160
|
function applyEnforcement(gate, opts) {
|
|
1161
1161
|
return { ...gate, hardBlocked: opts.hard && gate.violations.length > 0 };
|
|
@@ -2467,6 +2467,25 @@ function assertSafePathComponent(value, what) {
|
|
|
2467
2467
|
throw new Error(`${what} must be a single safe path component ([A-Za-z0-9._-]+; not "", ".", "..", or containing "/" or "\\") — got ${JSON.stringify(value)}`);
|
|
2468
2468
|
}
|
|
2469
2469
|
}
|
|
2470
|
+
function canonicalizeNearestExisting(path) {
|
|
2471
|
+
const abs = resolve7(path);
|
|
2472
|
+
let dir = abs;
|
|
2473
|
+
const tail = [];
|
|
2474
|
+
for (;; ) {
|
|
2475
|
+
if (existsSync6(dir)) {
|
|
2476
|
+
try {
|
|
2477
|
+
return join9(realpathSync2(dir), ...tail);
|
|
2478
|
+
} catch {
|
|
2479
|
+
return abs;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
const parent = dirname5(dir);
|
|
2483
|
+
if (parent === dir)
|
|
2484
|
+
return abs;
|
|
2485
|
+
tail.unshift(basename3(dir));
|
|
2486
|
+
dir = parent;
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2470
2489
|
function resolveSddDir(harnessDir, planId) {
|
|
2471
2490
|
assertSafePathComponent(planId, "planId");
|
|
2472
2491
|
const base = resolve7(harnessDir);
|
|
@@ -2564,6 +2583,28 @@ function probeBranch(worktreePath, opts) {
|
|
|
2564
2583
|
return { error: detail };
|
|
2565
2584
|
}
|
|
2566
2585
|
}
|
|
2586
|
+
function probeCheckout(worktreePath, opts) {
|
|
2587
|
+
const timeout = opts.timeoutMs ?? probeTimeoutMs();
|
|
2588
|
+
try {
|
|
2589
|
+
const stdout = execFileSync2(opts.gitPath ?? "git", ["-C", worktreePath, "rev-parse", "--git-dir"], {
|
|
2590
|
+
encoding: "utf8",
|
|
2591
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2592
|
+
timeout
|
|
2593
|
+
});
|
|
2594
|
+
const raw = stdout.trim();
|
|
2595
|
+
if (raw === "")
|
|
2596
|
+
return { error: `no git dir reported at "${worktreePath}"` };
|
|
2597
|
+
const abs = isAbsolute5(raw) ? raw : join10(worktreePath, raw);
|
|
2598
|
+
return { gitDir: realpathSync3(abs) };
|
|
2599
|
+
} catch (err) {
|
|
2600
|
+
const e = err;
|
|
2601
|
+
if (e.killed === true || e.signal !== undefined) {
|
|
2602
|
+
return { error: `git probe timed out after ${timeout}ms (killed by ${e.signal ?? "SIGTERM"})` };
|
|
2603
|
+
}
|
|
2604
|
+
const detail = (e.stderr !== undefined ? e.stderr.toString().trim() : "") || e.message || "git probe failed";
|
|
2605
|
+
return { error: detail };
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2567
2608
|
function l1PreDispatchCheck(input, opts = {}) {
|
|
2568
2609
|
const violations = [];
|
|
2569
2610
|
const { controlWorktreePath, leaseWorktreePath, leaseWorkingBranch, planId } = input;
|
|
@@ -2576,8 +2617,20 @@ function l1PreDispatchCheck(input, opts = {}) {
|
|
|
2576
2617
|
if (leaseWorkingBranch.trim() === "") {
|
|
2577
2618
|
violations.push(violation7("high", "worktree.l1.lease-branch-missing", `execution_lease.working_branch is empty for plan "${planId}"`, "record the lease working_branch before dispatch"));
|
|
2578
2619
|
}
|
|
2579
|
-
if (controlWorktreePath !== "" && leaseWorktreePath !== ""
|
|
2580
|
-
|
|
2620
|
+
if (controlWorktreePath !== "" && leaseWorktreePath !== "") {
|
|
2621
|
+
if (resolve8(controlWorktreePath) === resolve8(leaseWorktreePath)) {
|
|
2622
|
+
violations.push(violation7("critical", "worktree.l1.lease-equals-control", `execution_lease.worktree_path "${leaseWorktreePath}" equals metadata.control_worktree_path — the feature worktree MUST differ from the control worktree (L1 isolation; product edits never land in the control checkout)`, "use a distinct feature worktree for the plan (git worktree add <path> <branch>) and update the lease"));
|
|
2623
|
+
} else if (existsSync7(leaseWorktreePath)) {
|
|
2624
|
+
const controlProbe = probeCheckout(controlWorktreePath, opts);
|
|
2625
|
+
const leaseProbe = probeCheckout(leaseWorktreePath, opts);
|
|
2626
|
+
if ("error" in controlProbe) {
|
|
2627
|
+
violations.push(violation7("high", "worktree.l1.checkout-probe-failed", `cannot establish the lease worktree "${leaseWorktreePath}" is a distinct Git checkout from the control worktree "${controlWorktreePath}" for plan "${planId}": ${controlProbe.error}`, "verify the control worktree path is a git checkout (integration-branch checkout)"));
|
|
2628
|
+
} else if ("error" in leaseProbe) {
|
|
2629
|
+
violations.push(violation7("high", "worktree.l1.checkout-probe-failed", `cannot establish the lease worktree "${leaseWorktreePath}" is a distinct Git checkout from the control worktree "${controlWorktreePath}" for plan "${planId}": ${leaseProbe.error}`, "verify the lease worktree path is a git checkout (git worktree add <path> <branch>)"));
|
|
2630
|
+
} else if (controlProbe.gitDir === leaseProbe.gitDir) {
|
|
2631
|
+
violations.push(violation7("critical", "worktree.l1.lease-equals-control", `execution_lease.worktree_path "${leaseWorktreePath}" is the same Git checkout as metadata.control_worktree_path "${controlWorktreePath}" — a plain subdirectory or symlink alias of the control checkout is not isolation; the feature worktree MUST be a distinct checkout`, "use a distinct feature worktree for the plan (git worktree add <path> <branch>) and update the lease"));
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2581
2634
|
}
|
|
2582
2635
|
if (leaseWorktreePath !== "" && !existsSync7(leaseWorktreePath)) {
|
|
2583
2636
|
violations.push(violation7("high", "worktree.l1.feature-missing", `feature worktree directory "${leaseWorktreePath}" does not exist for plan "${planId}"`, `create it before dispatch: git worktree add ${leaseWorktreePath} <working-branch>`));
|
|
@@ -2626,6 +2679,16 @@ function l2PreDispatchCheck(input, opts = {}) {
|
|
|
2626
2679
|
});
|
|
2627
2680
|
return gate(violations);
|
|
2628
2681
|
}
|
|
2682
|
+
function assertBranchAlignment(worktreePath, expectedBranch, opts = {}) {
|
|
2683
|
+
const violations = [];
|
|
2684
|
+
const probe = probeBranch(worktreePath, opts);
|
|
2685
|
+
if ("error" in probe) {
|
|
2686
|
+
violations.push(violation7("high", "worktree.branch-probe-failed", `cannot probe branch at "${worktreePath}": ${probe.error}`, "verify the path is a git worktree checkout on the expected branch (not detached)"));
|
|
2687
|
+
} else if (probe.branch !== expectedBranch) {
|
|
2688
|
+
violations.push(violation7("high", "worktree.branch-mismatch", `worktree "${worktreePath}" is on branch "${probe.branch}", expected "${expectedBranch}" (Assignment Working branch)`, `checkout ${expectedBranch} in that worktree`));
|
|
2689
|
+
}
|
|
2690
|
+
return gate(violations);
|
|
2691
|
+
}
|
|
2629
2692
|
class SddScriptError extends Error {
|
|
2630
2693
|
exitCode;
|
|
2631
2694
|
constructor(message, exitCode) {
|
|
@@ -2662,14 +2725,14 @@ function gitOut(cwd, args) {
|
|
|
2662
2725
|
}
|
|
2663
2726
|
}
|
|
2664
2727
|
function probeHarnessWithStatus(root) {
|
|
2665
|
-
if (isFile2(
|
|
2666
|
-
return
|
|
2667
|
-
if (isFile2(
|
|
2668
|
-
return
|
|
2669
|
-
if (hasWorkflowSnapshot(
|
|
2670
|
-
return
|
|
2671
|
-
if (hasWorkflowSnapshot(
|
|
2672
|
-
return
|
|
2728
|
+
if (isFile2(join11(root, ".mstar", "status.json")))
|
|
2729
|
+
return join11(root, ".mstar");
|
|
2730
|
+
if (isFile2(join11(root, ".agents", "status.json")))
|
|
2731
|
+
return join11(root, ".agents");
|
|
2732
|
+
if (hasWorkflowSnapshot(join11(root, ".mstar")))
|
|
2733
|
+
return join11(root, ".mstar");
|
|
2734
|
+
if (hasWorkflowSnapshot(join11(root, ".agents")))
|
|
2735
|
+
return join11(root, ".agents");
|
|
2673
2736
|
return null;
|
|
2674
2737
|
}
|
|
2675
2738
|
function hasWorkflowSnapshot(harnessDir) {
|
|
@@ -2677,13 +2740,13 @@ function hasWorkflowSnapshot(harnessDir) {
|
|
|
2677
2740
|
try {
|
|
2678
2741
|
workflowsDir = resolveWorkflowDir(harnessDir, { harnessDir });
|
|
2679
2742
|
} catch {
|
|
2680
|
-
workflowsDir =
|
|
2743
|
+
workflowsDir = join11(harnessDir, "workflows");
|
|
2681
2744
|
}
|
|
2682
2745
|
if (!isDirectory2(workflowsDir))
|
|
2683
2746
|
return false;
|
|
2684
2747
|
try {
|
|
2685
2748
|
for (const entry of readdirSync6(workflowsDir, { withFileTypes: true })) {
|
|
2686
|
-
if (entry.isDirectory() && isFile2(
|
|
2749
|
+
if (entry.isDirectory() && isFile2(join11(workflowsDir, entry.name, "snapshot.json")))
|
|
2687
2750
|
return true;
|
|
2688
2751
|
}
|
|
2689
2752
|
} catch {
|
|
@@ -2696,14 +2759,14 @@ function isLinkedWorktree(root) {
|
|
|
2696
2759
|
const commonRaw = gitOut(root, ["rev-parse", "--git-common-dir"]);
|
|
2697
2760
|
if (gitDirRaw === null || commonRaw === null)
|
|
2698
2761
|
return false;
|
|
2699
|
-
const gitDir = isAbsolute6(gitDirRaw) ? gitDirRaw :
|
|
2700
|
-
const common = isAbsolute6(commonRaw) ? commonRaw :
|
|
2762
|
+
const gitDir = isAbsolute6(gitDirRaw) ? gitDirRaw : join11(root, gitDirRaw);
|
|
2763
|
+
const common = isAbsolute6(commonRaw) ? commonRaw : join11(root, commonRaw);
|
|
2701
2764
|
if (gitDir.includes("/.git/worktrees/") || gitDir.includes("/worktrees/"))
|
|
2702
2765
|
return true;
|
|
2703
2766
|
try {
|
|
2704
|
-
const gdParent =
|
|
2705
|
-
const cmAbs =
|
|
2706
|
-
return
|
|
2767
|
+
const gdParent = realpathSync4(dirname6(gitDir));
|
|
2768
|
+
const cmAbs = realpathSync4(common);
|
|
2769
|
+
return join11(gdParent, basename4(gitDir)) !== cmAbs && gitDir !== cmAbs;
|
|
2707
2770
|
} catch {
|
|
2708
2771
|
return false;
|
|
2709
2772
|
}
|
|
@@ -2720,10 +2783,10 @@ function sddWorkspace(planId, opts = {}) {
|
|
|
2720
2783
|
if (!isDirectory2(controlRoot)) {
|
|
2721
2784
|
throw new SddScriptError(`mstar sdd workspace: CONTROL_ROOT / MSTAR_CONTROL_ROOT is not a directory: ${controlRoot}`, 1);
|
|
2722
2785
|
}
|
|
2723
|
-
root =
|
|
2786
|
+
root = realpathSync4(controlRoot);
|
|
2724
2787
|
} else {
|
|
2725
2788
|
const topLevel = gitOut(cwd, ["rev-parse", "--show-toplevel"]);
|
|
2726
|
-
root =
|
|
2789
|
+
root = realpathSync4(topLevel ?? cwd);
|
|
2727
2790
|
}
|
|
2728
2791
|
if (!controlRoot && isLinkedWorktree(root)) {
|
|
2729
2792
|
throw new SddScriptError(`mstar sdd workspace: linked worktree at ${root} has no {HARNESS_DIR}/status.json (default gitignore).
|
|
@@ -2744,25 +2807,35 @@ function sddWorkspace(planId, opts = {}) {
|
|
|
2744
2807
|
const probed = probeHarnessWithStatus(root);
|
|
2745
2808
|
if (probed) {
|
|
2746
2809
|
harnessDir = probed;
|
|
2747
|
-
} else if (isDirectory2(
|
|
2748
|
-
harnessDir =
|
|
2749
|
-
} else if (isDirectory2(
|
|
2750
|
-
harnessDir =
|
|
2810
|
+
} else if (isDirectory2(join11(root, ".mstar"))) {
|
|
2811
|
+
harnessDir = join11(root, ".mstar");
|
|
2812
|
+
} else if (isDirectory2(join11(root, ".agents"))) {
|
|
2813
|
+
harnessDir = join11(root, ".agents");
|
|
2751
2814
|
} else {
|
|
2752
|
-
harnessDir =
|
|
2815
|
+
harnessDir = join11(root, ".mstar");
|
|
2753
2816
|
}
|
|
2754
2817
|
}
|
|
2755
2818
|
}
|
|
2756
2819
|
const sddDir = resolveSddDir(harnessDir, planId);
|
|
2757
2820
|
mkdirSync6(sddDir, { recursive: true });
|
|
2758
|
-
writeFileSync4(
|
|
2821
|
+
writeFileSync4(join11(sddDir, ".gitignore"), `*
|
|
2759
2822
|
`);
|
|
2760
|
-
return
|
|
2823
|
+
return realpathSync4(sddDir);
|
|
2761
2824
|
}
|
|
2762
2825
|
function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
2763
2826
|
if (!planFile || !Number.isInteger(taskN) || taskN < 1) {
|
|
2764
2827
|
throw new SddScriptError("usage: mstar sdd task-brief PLAN_FILE TASK_NUMBER [OUTFILE]", 2);
|
|
2765
2828
|
}
|
|
2829
|
+
const bound = opts.context;
|
|
2830
|
+
const observedCwd = opts.cwd ?? process.cwd();
|
|
2831
|
+
if (bound) {
|
|
2832
|
+
const inputPlan = canonicalizeNearestExisting(resolve9(observedCwd, planFile));
|
|
2833
|
+
if (inputPlan !== canonicalizeNearestExisting(bound.planFile)) {
|
|
2834
|
+
throwGateFail([
|
|
2835
|
+
contextViolation("high", "sdd.context.plan-file-mismatch", `plan file "${planFile}" does not match the bound context plan file "${bound.planFile}" — ` + "bound mode extracts only the resolved context's plan; refused before any read or write")
|
|
2836
|
+
]);
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2766
2839
|
let content;
|
|
2767
2840
|
try {
|
|
2768
2841
|
content = readFileSync7(planFile, "utf8");
|
|
@@ -2770,15 +2843,26 @@ function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
|
2770
2843
|
throw new SddScriptError(`no such plan file: ${planFile}`, 2);
|
|
2771
2844
|
}
|
|
2772
2845
|
let out;
|
|
2846
|
+
let mkdirAfterGate = null;
|
|
2773
2847
|
if (outFile) {
|
|
2774
|
-
out = outFile;
|
|
2848
|
+
out = bound ? resolve9(observedCwd, outFile) : outFile;
|
|
2849
|
+
} else if (bound) {
|
|
2850
|
+
out = join11(bound.sddDir, `task-${taskN}-brief.md`);
|
|
2851
|
+
mkdirAfterGate = bound.sddDir;
|
|
2775
2852
|
} else {
|
|
2776
2853
|
const sddDir = opts.sddDir ?? process.env.SDD_DIR;
|
|
2777
2854
|
if (!sddDir) {
|
|
2778
2855
|
throw new SddScriptError("mstar sdd task-brief: set SDD_DIR or pass OUTFILE (run mstar sdd workspace PLAN_ID first)", 2);
|
|
2779
2856
|
}
|
|
2780
2857
|
mkdirSync6(sddDir, { recursive: true });
|
|
2781
|
-
out =
|
|
2858
|
+
out = join11(sddDir, `task-${taskN}-brief.md`);
|
|
2859
|
+
}
|
|
2860
|
+
if (bound) {
|
|
2861
|
+
const gate2 = checkSddAction(bound, { kind: "artifact", cwd: observedCwd, target: out });
|
|
2862
|
+
if (!gate2.ok)
|
|
2863
|
+
throwGateFail(gate2.violations);
|
|
2864
|
+
if (mkdirAfterGate !== null)
|
|
2865
|
+
mkdirSync6(mkdirAfterGate, { recursive: true });
|
|
2782
2866
|
}
|
|
2783
2867
|
const records = content.endsWith(`
|
|
2784
2868
|
`) ? content.split(`
|
|
@@ -2804,7 +2888,98 @@ function taskBrief(planFile, taskN, outFile, opts = {}) {
|
|
|
2804
2888
|
if (printed.length === 0) {
|
|
2805
2889
|
throw new SddScriptError(`task ${taskN} not found in ${planFile} (no heading matching Task ${taskN})`, 3);
|
|
2806
2890
|
}
|
|
2807
|
-
return out;
|
|
2891
|
+
return bound ? resolve9(observedCwd, out) : out;
|
|
2892
|
+
}
|
|
2893
|
+
function isInside(child, ancestor) {
|
|
2894
|
+
const rel = relative3(ancestor, child);
|
|
2895
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute6(rel);
|
|
2896
|
+
}
|
|
2897
|
+
function canonicalDir(path) {
|
|
2898
|
+
try {
|
|
2899
|
+
return statSync4(path).isDirectory() ? realpathSync4(path) : null;
|
|
2900
|
+
} catch {
|
|
2901
|
+
return null;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
function contextViolation(severity, code, message, fix) {
|
|
2905
|
+
return { ok: false, severity, code, message, fix };
|
|
2906
|
+
}
|
|
2907
|
+
function throwGateFail(violations) {
|
|
2908
|
+
const detail = violations.map((v) => `${v.code}: ${v.message}${v.fix ? ` (fix: ${v.fix})` : ""}`).join(`
|
|
2909
|
+
`);
|
|
2910
|
+
throw new SddScriptError(`SDD execution context rejected:
|
|
2911
|
+
${detail}`, 1);
|
|
2912
|
+
}
|
|
2913
|
+
function checkSddAction(context, action) {
|
|
2914
|
+
const violations = [];
|
|
2915
|
+
const add = (code, message, fix) => {
|
|
2916
|
+
violations.push(contextViolation("high", code, message, fix));
|
|
2917
|
+
};
|
|
2918
|
+
if (action.kind !== "source" && action.kind !== "artifact" && action.kind !== "launch") {
|
|
2919
|
+
add("sdd.context.kind-unknown", `unknown action kind ${JSON.stringify(action.kind)} — expected "source" | "artifact" | "launch"`);
|
|
2920
|
+
return { ok: false, violations };
|
|
2921
|
+
}
|
|
2922
|
+
if (typeof action.cwd !== "string" || action.cwd.trim() === "") {
|
|
2923
|
+
add("sdd.context.cwd-missing", "action.cwd (the observed invocation cwd) is required — never an Assignment echo");
|
|
2924
|
+
return { ok: false, violations };
|
|
2925
|
+
}
|
|
2926
|
+
const featureReal = canonicalDir(context.featureCwd);
|
|
2927
|
+
const canonicalSddDir = canonicalizeNearestExisting(context.sddDir);
|
|
2928
|
+
const canonicalPlanFile = canonicalizeNearestExisting(context.planFile);
|
|
2929
|
+
const cwdResolved = resolve9(action.cwd);
|
|
2930
|
+
const checkTarget = (baseDir, target, kind) => {
|
|
2931
|
+
if (featureReal === null)
|
|
2932
|
+
return;
|
|
2933
|
+
const targetAbs = resolve9(baseDir, target);
|
|
2934
|
+
const canonical = canonicalizeNearestExisting(targetAbs);
|
|
2935
|
+
if (!isInside(canonical, featureReal)) {
|
|
2936
|
+
const declaredPrefix = targetAbs === featureReal || targetAbs.startsWith(`${featureReal}/`);
|
|
2937
|
+
if (declaredPrefix) {
|
|
2938
|
+
add("sdd.context.target-symlink-escape", `${kind} target "${target}" canonicalizes to "${canonical}", outside the feature worktree — symlink escape refused before mutation`);
|
|
2939
|
+
} else {
|
|
2940
|
+
add(`sdd.context.${kind}-target-outside-feature`, `${kind} target "${target}" resolves to "${targetAbs}", outside the feature worktree "${featureReal}" — refused before mutation`);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
};
|
|
2944
|
+
if (action.kind === "source") {
|
|
2945
|
+
const cwdReal = canonicalDir(cwdResolved);
|
|
2946
|
+
if (cwdReal === null) {
|
|
2947
|
+
add("sdd.context.cwd-missing", `observed source cwd "${action.cwd}" does not exist or is not a directory`);
|
|
2948
|
+
return { ok: false, violations };
|
|
2949
|
+
}
|
|
2950
|
+
if (featureReal === null || !isInside(cwdReal, featureReal)) {
|
|
2951
|
+
add("sdd.context.source-cwd-outside-feature", `observed source cwd "${cwdReal}" is outside the feature worktree "${context.featureCwd}" — a declared-correct context does not make a wrong-checkout write safe (A3)`, `run the source action from inside ${context.featureCwd}`);
|
|
2952
|
+
return { ok: false, violations };
|
|
2953
|
+
}
|
|
2954
|
+
if (action.target !== undefined)
|
|
2955
|
+
checkTarget(cwdReal, action.target, "source");
|
|
2956
|
+
} else if (action.kind === "artifact") {
|
|
2957
|
+
if (typeof action.target !== "string" || action.target.trim() === "") {
|
|
2958
|
+
add("sdd.context.target-missing", "artifact checks require the destination target");
|
|
2959
|
+
return { ok: false, violations };
|
|
2960
|
+
}
|
|
2961
|
+
const targetAbs = resolve9(cwdResolved, action.target);
|
|
2962
|
+
const canonical = canonicalizeNearestExisting(targetAbs);
|
|
2963
|
+
if (!isInside(canonical, canonicalSddDir) && canonical !== canonicalPlanFile) {
|
|
2964
|
+
const rawSddDir = resolve9(context.sddDir);
|
|
2965
|
+
const declaredPrefix = targetAbs === rawSddDir || targetAbs.startsWith(`${rawSddDir}/`) || targetAbs === canonicalSddDir || targetAbs.startsWith(`${canonicalSddDir}/`) || targetAbs === canonicalPlanFile;
|
|
2966
|
+
if (declaredPrefix) {
|
|
2967
|
+
add("sdd.context.artifact-symlink-escape", `artifact target "${targetAbs}" canonicalizes to "${canonical}", outside the plan's control sddDir — symlink escape refused before write`);
|
|
2968
|
+
} else {
|
|
2969
|
+
add("sdd.context.artifact-outside-plan", `artifact target "${targetAbs}" is outside the plan's control sddDir "${context.sddDir}" and is not the declared planFile "${context.planFile}" — legitimate control artifact edits stay inside the plan's artifacts; arbitrary control source edits are not allowed (A3)`);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
} else {
|
|
2973
|
+
if (featureReal === null) {
|
|
2974
|
+
add("sdd.context.launch-cwd-missing", `feature worktree "${context.featureCwd}" does not exist or is not a directory — cannot bind the child's starting cwd`);
|
|
2975
|
+
} else {
|
|
2976
|
+
violations.push(...assertBranchAlignment(featureReal, context.workingBranch).violations);
|
|
2977
|
+
}
|
|
2978
|
+
if (action.target !== undefined && action.target.trim() !== "" && featureReal !== null) {
|
|
2979
|
+
checkTarget(featureReal, action.target, "launch");
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
return { ok: violations.length === 0, violations };
|
|
2808
2983
|
}
|
|
2809
2984
|
function violation8(severity, code, message, fix) {
|
|
2810
2985
|
return { ok: false, severity, code, message, fix };
|
|
@@ -3547,7 +3722,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
3547
3722
|
break;
|
|
3548
3723
|
if (entry.isDirectory()) {
|
|
3549
3724
|
if (!WALK_SKIP_DIRS.has(entry.name))
|
|
3550
|
-
stack.push(
|
|
3725
|
+
stack.push(join15(dir, entry.name));
|
|
3551
3726
|
} else if (!entry.isSymbolicLink()) {
|
|
3552
3727
|
const base = entry.name.replace(/\.(?:ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
3553
3728
|
if (moduleNames.has(base))
|
|
@@ -3559,7 +3734,7 @@ function referenceExists(repoRoot, docText) {
|
|
|
3559
3734
|
for (const { ref, isSymbol, module } of refs) {
|
|
3560
3735
|
if (!isSymbol || module === undefined) {
|
|
3561
3736
|
const candidate = ref.replace(LINE_SUFFIX_RE, "").replace(ANCHOR_RE, "");
|
|
3562
|
-
if (
|
|
3737
|
+
if (existsSync10(resolve13(repoRoot, candidate))) {
|
|
3563
3738
|
checked++;
|
|
3564
3739
|
} else {
|
|
3565
3740
|
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"));
|
|
@@ -3586,11 +3761,11 @@ function collectKnowledgeDocs(dir) {
|
|
|
3586
3761
|
for (const entry of entries) {
|
|
3587
3762
|
if (entry.isSymbolicLink())
|
|
3588
3763
|
continue;
|
|
3589
|
-
const full =
|
|
3764
|
+
const full = join15(current, entry.name);
|
|
3590
3765
|
if (entry.isDirectory()) {
|
|
3591
3766
|
stack.push(full);
|
|
3592
3767
|
} else if (entry.name.endsWith(".md") && entry.name !== "README.md" && entry.name !== "index.md") {
|
|
3593
|
-
docs.push(
|
|
3768
|
+
docs.push(relative6(dir, full).split(sep4).join("/"));
|
|
3594
3769
|
}
|
|
3595
3770
|
}
|
|
3596
3771
|
}
|
|
@@ -3606,8 +3781,8 @@ function normalizeIndexRef(cell) {
|
|
|
3606
3781
|
}
|
|
3607
3782
|
function assertIndexRows(knowledgeDir) {
|
|
3608
3783
|
const violations = [];
|
|
3609
|
-
const readmePath =
|
|
3610
|
-
if (!
|
|
3784
|
+
const readmePath = join15(knowledgeDir, "README.md");
|
|
3785
|
+
if (!existsSync10(readmePath)) {
|
|
3611
3786
|
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"));
|
|
3612
3787
|
return { ok: false, violations };
|
|
3613
3788
|
}
|
|
@@ -3631,12 +3806,12 @@ function assertIndexRows(knowledgeDir) {
|
|
|
3631
3806
|
return { ok: violations.length === 0, violations };
|
|
3632
3807
|
}
|
|
3633
3808
|
function isFileLikeRoot(root) {
|
|
3634
|
-
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(
|
|
3809
|
+
return /^[^.]*\.[A-Za-z0-9]{1,10}$/.test(basename7(root));
|
|
3635
3810
|
}
|
|
3636
3811
|
function scopeGuard(path, allowedRoots) {
|
|
3637
|
-
const resolved =
|
|
3812
|
+
const resolved = resolve13(path);
|
|
3638
3813
|
for (const root of allowedRoots) {
|
|
3639
|
-
const r =
|
|
3814
|
+
const r = resolve13(root);
|
|
3640
3815
|
if (isFileLikeRoot(r)) {
|
|
3641
3816
|
if (resolved === r)
|
|
3642
3817
|
return { ok: true, violations: [] };
|
|
@@ -3794,8 +3969,8 @@ function validateRoleMapping(rolesDir, options = {}) {
|
|
|
3794
3969
|
const violations = [];
|
|
3795
3970
|
const referenceById = new Map(mapping.map((m) => [m.agentId, m.reference]));
|
|
3796
3971
|
for (const { agentId, reference } of mapping) {
|
|
3797
|
-
if (!
|
|
3798
|
-
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 ${
|
|
3972
|
+
if (!existsSync11(join16(rolesDir, reference))) {
|
|
3973
|
+
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 ${join16(rolesDir, reference)} or fix the mapping row`));
|
|
3799
3974
|
}
|
|
3800
3975
|
}
|
|
3801
3976
|
for (const { family, memberIds } of families) {
|
|
@@ -3847,6 +4022,14 @@ function validateRoleMapping(rolesDir, options = {}) {
|
|
|
3847
4022
|
return { ok: violations.length === 0, violations };
|
|
3848
4023
|
}
|
|
3849
4024
|
var LOAD_ORDER_HEADING_RE = /^#{1,6}\s+[^\r\n]*\b(?:load[\s-]*order|first\s+action)\b[^\r\n]*$/i;
|
|
4025
|
+
var HUB_BOOTSTRAP_ASSERTIONS = [
|
|
4026
|
+
{ marker: "identity-first", why: "identity boundary before any skill list" },
|
|
4027
|
+
{ marker: "skill presets", why: "Assignment Skill presets decision field" },
|
|
4028
|
+
{ marker: "none", why: "explicit none => identity only, no optional topic preset" },
|
|
4029
|
+
{ marker: "standard", why: "omitted on a substantive round => standard preset" },
|
|
4030
|
+
{ marker: "role-owned", why: "role-owned methods / evidence obligations load regardless of preset" },
|
|
4031
|
+
{ marker: "unknown preset", why: "unknown preset / missing identity => Needs Context / Blocked, never infer PM" }
|
|
4032
|
+
];
|
|
3850
4033
|
function extractLoadOrderSection(text) {
|
|
3851
4034
|
const lines = text.split(/\r?\n/);
|
|
3852
4035
|
let start = -1;
|
|
@@ -3880,11 +4063,22 @@ function lintLoadOrder(skillTexts) {
|
|
|
3880
4063
|
continue;
|
|
3881
4064
|
const section = extractLoadOrderSection(text);
|
|
3882
4065
|
if (section === null) {
|
|
3883
|
-
violations.push(violation12("medium", "roles.loadorder.section.missing", `skill "${name}" has no Load Order / First action section — every mstar-* topic skill must declare its first read (mstar-harness-core §
|
|
4066
|
+
violations.push(violation12("medium", "roles.loadorder.section.missing", `skill "${name}" has no Load Order / First action section — every mstar-* topic skill must declare its first read (mstar-harness-core § 加载契约; mstar-roles § Load Order = single load-selection authority)`, `add a "## Load Order" section: topics name mstar-harness-core first; mstar-roles declares the Skill presets decision matrix`));
|
|
4067
|
+
continue;
|
|
4068
|
+
}
|
|
4069
|
+
if (name === "mstar-roles") {
|
|
4070
|
+
const lower = section.toLowerCase();
|
|
4071
|
+
const missing = HUB_BOOTSTRAP_ASSERTIONS.filter((a) => !lower.includes(a.marker.toLowerCase()));
|
|
4072
|
+
if (missing.length > 0) {
|
|
4073
|
+
violations.push(violation12("medium", "roles.loadorder.hub.bootstrap.missing", `skill "${name}" Load Order section is missing the hub bootstrap decision matrix: ${missing.map((m) => `"${m.marker}" (${m.why})`).join("; ")} (mstar-roles § Load Order = single load-selection authority)`, "declare identity-first, the Skill presets none/standard decision, role-owned methods, and the unknown-preset / missing-identity refusal in the Load Order section"));
|
|
4074
|
+
}
|
|
4075
|
+
if (!section.includes("mstar-harness-core")) {
|
|
4076
|
+
violations.push(violation12("medium", "roles.loadorder.core.missing", `skill "${name}" Load Order section does not point at mstar-harness-core — the hub bootstrap is exempt from core-first, but core remains the lifecycle/authorization conflict authority and global entry whenever loaded`, "keep the conditional mstar-harness-core pointer (global entry / conflict authority) in the Load Order section"));
|
|
4077
|
+
}
|
|
3884
4078
|
continue;
|
|
3885
4079
|
}
|
|
3886
4080
|
if (!section.includes("mstar-harness-core")) {
|
|
3887
|
-
violations.push(violation12("medium", "roles.loadorder.core.missing", `skill "${name}" Load Order section does not declare mstar-harness-core as its first dependency (mstar-harness-core §
|
|
4081
|
+
violations.push(violation12("medium", "roles.loadorder.core.missing", `skill "${name}" Load Order section does not declare mstar-harness-core as its first dependency (mstar-harness-core § 加载契约: directly-invoked topics keep core as first dependency; the mstar-roles hub bootstrap is the only exception)`, "name mstar-harness-core first in the Load Order section"));
|
|
3888
4082
|
}
|
|
3889
4083
|
}
|
|
3890
4084
|
return { ok: violations.length === 0, violations };
|
|
@@ -3920,6 +4114,17 @@ var FIVE_QUESTION_SECTIONS = [
|
|
|
3920
4114
|
{ key: "evidence", label: "Evidence", question: "what a correct result looks like (success criteria / evidence)" },
|
|
3921
4115
|
{ key: "references", label: "References", question: "additional resources to open when the main path is not enough" }
|
|
3922
4116
|
];
|
|
4117
|
+
function stripFrontmatter(text) {
|
|
4118
|
+
const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
|
|
4119
|
+
if (lines.length === 0 || lines[0].trim() !== "---")
|
|
4120
|
+
return text;
|
|
4121
|
+
for (let i = 1;i < lines.length; i++) {
|
|
4122
|
+
if (lines[i].trim() === "---")
|
|
4123
|
+
return lines.slice(i + 1).join(`
|
|
4124
|
+
`);
|
|
4125
|
+
}
|
|
4126
|
+
return text;
|
|
4127
|
+
}
|
|
3923
4128
|
var HEADING_RE = /^#{1,6}\s+[^\r\n]+$/;
|
|
3924
4129
|
function collectHeadings(bodyText) {
|
|
3925
4130
|
const headings = [];
|
|
@@ -3935,6 +4140,16 @@ function collectHeadings(bodyText) {
|
|
|
3935
4140
|
}
|
|
3936
4141
|
return headings;
|
|
3937
4142
|
}
|
|
4143
|
+
function classifySkillLint(skillId) {
|
|
4144
|
+
const id = skillId ?? "";
|
|
4145
|
+
if (id === "mstar-harness-core")
|
|
4146
|
+
return { kind: "core", mode: null };
|
|
4147
|
+
if (id === "mstar-skill-authoring")
|
|
4148
|
+
return { kind: "authoring", mode: "authoring" };
|
|
4149
|
+
if (id.startsWith("mstar-"))
|
|
4150
|
+
return { kind: "runtime", mode: "runtime" };
|
|
4151
|
+
return { kind: "authoring", mode: "authoring" };
|
|
4152
|
+
}
|
|
3938
4153
|
var RUNTIME_HEADING_ALIASES = {
|
|
3939
4154
|
workflow: ["process", "playbook"],
|
|
3940
4155
|
"decision-rules": [
|
|
@@ -4162,12 +4377,12 @@ function skillLocalConfig(config) {
|
|
|
4162
4377
|
}
|
|
4163
4378
|
|
|
4164
4379
|
// src/gates/catalog.ts
|
|
4165
|
-
import { existsSync as
|
|
4380
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8, readdirSync as readdirSync4 } from "node:fs";
|
|
4166
4381
|
import { join as join8 } from "node:path";
|
|
4167
4382
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
4168
4383
|
|
|
4169
4384
|
// src/gates/agent-flow.ts
|
|
4170
|
-
import { appendFileSync, closeSync, existsSync as
|
|
4385
|
+
import { appendFileSync, closeSync, existsSync as existsSync12, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync5, readSync, renameSync as renameSync2, rmdirSync, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4171
4386
|
import { join as join6 } from "node:path";
|
|
4172
4387
|
|
|
4173
4388
|
// src/gates/dispatch.ts
|
|
@@ -4176,7 +4391,7 @@ import { basename as basename2, join as join5, resolve as resolve6 } from "node:
|
|
|
4176
4391
|
|
|
4177
4392
|
// src/gates/workflow-selection.ts
|
|
4178
4393
|
import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
|
|
4179
|
-
import { dirname as dirname7, join as join3, relative as
|
|
4394
|
+
import { dirname as dirname7, join as join3, relative as relative4 } from "node:path";
|
|
4180
4395
|
var TERMINAL_STATUS_CACHE_MAX = 64;
|
|
4181
4396
|
var terminalStatusCache = new Map;
|
|
4182
4397
|
function terminalStatusOf(snapshotPath) {
|
|
@@ -4298,7 +4513,7 @@ function resolveReadWorkflow(harnessDir) {
|
|
|
4298
4513
|
if (verdict === undefined || !verdict.terminal)
|
|
4299
4514
|
continue;
|
|
4300
4515
|
if (best === undefined || verdict.mtimeMs > best.mtimeMs) {
|
|
4301
|
-
best = { workflowId: entry.name, dir: join3(
|
|
4516
|
+
best = { workflowId: entry.name, dir: join3(relative4(harnessDir, workflowsDir), entry.name), mtimeMs: verdict.mtimeMs };
|
|
4302
4517
|
}
|
|
4303
4518
|
}
|
|
4304
4519
|
for (const cachedPath of terminalStatusCache.keys()) {
|
|
@@ -5315,7 +5530,7 @@ function ledgerContent(file, n) {
|
|
|
5315
5530
|
}
|
|
5316
5531
|
function readAgentFlow(workflowDir, limit) {
|
|
5317
5532
|
const file = join6(workflowDir, AGENT_FLOW_FILE);
|
|
5318
|
-
if (!
|
|
5533
|
+
if (!existsSync12(file)) {
|
|
5319
5534
|
return { events: [], summary: [] };
|
|
5320
5535
|
}
|
|
5321
5536
|
const n = limit === undefined ? AGENT_FLOW_DEFAULT_LIMIT : Math.max(0, Math.floor(limit));
|
|
@@ -5570,7 +5785,7 @@ function harnessStateSource(harnessDir) {
|
|
|
5570
5785
|
if (harnessDir === null)
|
|
5571
5786
|
return null;
|
|
5572
5787
|
const statusPath = join8(harnessDir, STATUS_FILE);
|
|
5573
|
-
if (!
|
|
5788
|
+
if (!existsSync14(statusPath))
|
|
5574
5789
|
return null;
|
|
5575
5790
|
try {
|
|
5576
5791
|
const selection = resolveReadWorkflow(harnessDir);
|
|
@@ -5591,7 +5806,7 @@ function harnessStateSource(harnessDir) {
|
|
|
5591
5806
|
}
|
|
5592
5807
|
const snapshotPath = join8(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
5593
5808
|
let snapshot;
|
|
5594
|
-
if (!
|
|
5809
|
+
if (!existsSync14(snapshotPath)) {
|
|
5595
5810
|
return selectionErrorState({
|
|
5596
5811
|
kind: "error",
|
|
5597
5812
|
code: "workflow.selection.snapshot-unreadable",
|
|
@@ -5683,7 +5898,7 @@ function selectionErrorState(selection, rollup, harnessDir, compass) {
|
|
|
5683
5898
|
function projectRollupSource(harnessDir, residuals) {
|
|
5684
5899
|
const milestones = [];
|
|
5685
5900
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5686
|
-
if (
|
|
5901
|
+
if (existsSync14(projectsDir)) {
|
|
5687
5902
|
let entries;
|
|
5688
5903
|
try {
|
|
5689
5904
|
entries = readdirSync4(projectsDir, { withFileTypes: true });
|
|
@@ -5694,7 +5909,7 @@ function projectRollupSource(harnessDir, residuals) {
|
|
|
5694
5909
|
if (!entry.isDirectory())
|
|
5695
5910
|
continue;
|
|
5696
5911
|
const roadmapPath = join8(projectsDir, entry.name, PROJECT_ROADMAP_FILE);
|
|
5697
|
-
if (!
|
|
5912
|
+
if (!existsSync14(roadmapPath))
|
|
5698
5913
|
continue;
|
|
5699
5914
|
try {
|
|
5700
5915
|
const doc = parseCompassFrontmatterText(readFileSync8(roadmapPath, "utf8"), roadmapPath);
|
|
@@ -5759,7 +5974,7 @@ function residualRollup(harnessDir) {
|
|
|
5759
5974
|
}
|
|
5760
5975
|
function projectRegisters(harnessDir) {
|
|
5761
5976
|
const projectsDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5762
|
-
if (!
|
|
5977
|
+
if (!existsSync14(projectsDir))
|
|
5763
5978
|
return [];
|
|
5764
5979
|
let entries;
|
|
5765
5980
|
try {
|
|
@@ -5772,7 +5987,7 @@ function projectRegisters(harnessDir) {
|
|
|
5772
5987
|
if (!entry.isDirectory())
|
|
5773
5988
|
continue;
|
|
5774
5989
|
const registerPath = join8(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
5775
|
-
if (!
|
|
5990
|
+
if (!existsSync14(registerPath))
|
|
5776
5991
|
continue;
|
|
5777
5992
|
try {
|
|
5778
5993
|
registers.push({ projectId: entry.name, doc: readJson(registerPath) });
|
|
@@ -5784,7 +5999,7 @@ function projectRegisters(harnessDir) {
|
|
|
5784
5999
|
}
|
|
5785
6000
|
function knowledgeDigest(harnessDir) {
|
|
5786
6001
|
const indexPath = join8(harnessDir, "knowledge", "README.md");
|
|
5787
|
-
if (!
|
|
6002
|
+
if (!existsSync14(indexPath))
|
|
5788
6003
|
return null;
|
|
5789
6004
|
try {
|
|
5790
6005
|
const categories = new Set;
|
|
@@ -5829,7 +6044,7 @@ function compassDirection(compassPath) {
|
|
|
5829
6044
|
}
|
|
5830
6045
|
function steeringCompassPath(harnessDir) {
|
|
5831
6046
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
5832
|
-
if (!
|
|
6047
|
+
if (!existsSync14(iterationsDir))
|
|
5833
6048
|
return;
|
|
5834
6049
|
let entries;
|
|
5835
6050
|
try {
|
|
@@ -5841,7 +6056,7 @@ function steeringCompassPath(harnessDir) {
|
|
|
5841
6056
|
if (!entry.isDirectory())
|
|
5842
6057
|
continue;
|
|
5843
6058
|
const compassPath = join8(iterationsDir, entry.name, "delivery-compass.md");
|
|
5844
|
-
if (!
|
|
6059
|
+
if (!existsSync14(compassPath))
|
|
5845
6060
|
continue;
|
|
5846
6061
|
let content;
|
|
5847
6062
|
try {
|
|
@@ -5860,7 +6075,7 @@ function iterationGateSource(harnessDir) {
|
|
|
5860
6075
|
if (harnessDir === null)
|
|
5861
6076
|
return;
|
|
5862
6077
|
const statusPath = join8(harnessDir, STATUS_FILE);
|
|
5863
|
-
if (!
|
|
6078
|
+
if (!existsSync14(statusPath))
|
|
5864
6079
|
return;
|
|
5865
6080
|
const compass = steeringCompassPath(harnessDir);
|
|
5866
6081
|
if (compass === undefined)
|
|
@@ -5922,15 +6137,15 @@ function agentDigestKey(agent, cwd) {
|
|
|
5922
6137
|
}
|
|
5923
6138
|
|
|
5924
6139
|
// src/gates/status.ts
|
|
5925
|
-
import { existsSync as
|
|
5926
|
-
import { basename as basename5, join as
|
|
6140
|
+
import { existsSync as existsSync15, readdirSync as readdirSync7 } from "node:fs";
|
|
6141
|
+
import { basename as basename5, join as join12, relative as relative7, resolve as resolve10 } from "node:path";
|
|
5927
6142
|
var LOGGER_NAME = "mstar/status-gate";
|
|
5928
6143
|
function harnessDocKindOfTarget(harnessDir, targetPath) {
|
|
5929
6144
|
const resolved = resolve10(targetPath);
|
|
5930
6145
|
const name = basename5(resolved);
|
|
5931
6146
|
if (name !== STATUS_FILE && name !== WORKFLOW_SNAPSHOT_FILE && name !== PROJECT_REGISTER_FILE)
|
|
5932
6147
|
return null;
|
|
5933
|
-
const rel =
|
|
6148
|
+
const rel = relative7(harnessDir, resolved);
|
|
5934
6149
|
if (name === STATUS_FILE && rel === STATUS_FILE)
|
|
5935
6150
|
return "status";
|
|
5936
6151
|
let workflowDir;
|
|
@@ -5939,12 +6154,12 @@ function harnessDocKindOfTarget(harnessDir, targetPath) {
|
|
|
5939
6154
|
workflowDir = resolveWorkflowDir(harnessDir, { harnessDir });
|
|
5940
6155
|
projectDir = resolveProjectDir(harnessDir, { harnessDir });
|
|
5941
6156
|
} catch {
|
|
5942
|
-
workflowDir =
|
|
5943
|
-
projectDir =
|
|
6157
|
+
workflowDir = join12(harnessDir, "workflows");
|
|
6158
|
+
projectDir = join12(harnessDir, "projects");
|
|
5944
6159
|
}
|
|
5945
|
-
if (name === WORKFLOW_SNAPSHOT_FILE && /^[^/]+\/snapshot\.json$/.test(
|
|
6160
|
+
if (name === WORKFLOW_SNAPSHOT_FILE && /^[^/]+\/snapshot\.json$/.test(relative7(workflowDir, resolved)))
|
|
5946
6161
|
return "snapshot";
|
|
5947
|
-
if (name === PROJECT_REGISTER_FILE && /^[^/]+\/residuals\.json$/.test(
|
|
6162
|
+
if (name === PROJECT_REGISTER_FILE && /^[^/]+\/residuals\.json$/.test(relative7(projectDir, resolved)))
|
|
5948
6163
|
return "register";
|
|
5949
6164
|
return null;
|
|
5950
6165
|
}
|
|
@@ -6004,8 +6219,8 @@ function projectRegisterDocs(harnessDir) {
|
|
|
6004
6219
|
for (const entry of entries) {
|
|
6005
6220
|
if (!entry.isDirectory())
|
|
6006
6221
|
continue;
|
|
6007
|
-
const registerPath =
|
|
6008
|
-
if (!
|
|
6222
|
+
const registerPath = join12(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
6223
|
+
if (!existsSync15(registerPath))
|
|
6009
6224
|
continue;
|
|
6010
6225
|
try {
|
|
6011
6226
|
registers.push({ projectId: entry.name, doc: readJson(registerPath) });
|
|
@@ -6078,8 +6293,8 @@ async function editIntentListener(ctx, resolver, config, adapter, target, actor,
|
|
|
6078
6293
|
}
|
|
6079
6294
|
|
|
6080
6295
|
// src/gates/skill-lint.ts
|
|
6081
|
-
import { existsSync as
|
|
6082
|
-
import { basename as
|
|
6296
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
|
|
6297
|
+
import { basename as basename8, dirname as dirname9, resolve as resolve12, sep as sep2 } from "node:path";
|
|
6083
6298
|
var SKILL_LINT_LOGGER = "mstar/skill-lint";
|
|
6084
6299
|
|
|
6085
6300
|
class SkillLintVetoError extends Error {
|
|
@@ -6093,17 +6308,6 @@ ${violations.map(formatViolation).join(`
|
|
|
6093
6308
|
this.violations = violations;
|
|
6094
6309
|
}
|
|
6095
6310
|
}
|
|
6096
|
-
function stripFrontmatter(text) {
|
|
6097
|
-
const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
|
|
6098
|
-
if (lines.length === 0 || lines[0].trim() !== "---")
|
|
6099
|
-
return text;
|
|
6100
|
-
for (let i = 1;i < lines.length; i++) {
|
|
6101
|
-
if (lines[i].trim() === "---")
|
|
6102
|
-
return lines.slice(i + 1).join(`
|
|
6103
|
-
`);
|
|
6104
|
-
}
|
|
6105
|
-
return text;
|
|
6106
|
-
}
|
|
6107
6311
|
var EPHEMERAL_CODES = {
|
|
6108
6312
|
"task-artifact": "skill.ephemeral.task-artifact",
|
|
6109
6313
|
"sdd-deeplink": "skill.ephemeral.sdd-deeplink"
|
|
@@ -6116,19 +6320,23 @@ function ephemeralViolation(citation) {
|
|
|
6116
6320
|
message: `ephemeral citation \`${citation.match}\` on line ${citation.line} — durable skill text must reference in-repo artifacts only (knowledge conventions/skill-content-porting-discipline.md §3)`
|
|
6117
6321
|
};
|
|
6118
6322
|
}
|
|
6119
|
-
function lintSkillDoc(doc) {
|
|
6323
|
+
function lintSkillDoc(doc, options = {}) {
|
|
6120
6324
|
const violations = [];
|
|
6121
6325
|
const frontmatter = lintSkillFrontmatter(doc);
|
|
6122
6326
|
if (!frontmatter.ok)
|
|
6123
6327
|
violations.push(...frontmatter.violations);
|
|
6124
|
-
const
|
|
6125
|
-
if (
|
|
6126
|
-
|
|
6328
|
+
const profile = classifySkillLint(options.skillId);
|
|
6329
|
+
if (profile.mode !== null) {
|
|
6330
|
+
const body = lintFiveQuestion(stripFrontmatter(doc), profile.mode);
|
|
6331
|
+
if (!body.ok)
|
|
6332
|
+
violations.push(...body.violations);
|
|
6333
|
+
}
|
|
6127
6334
|
violations.push(...findEphemeralCitations(doc).map(ephemeralViolation));
|
|
6128
6335
|
return violations.length === 0 ? { ok: true, violations } : { ok: false, violations };
|
|
6129
6336
|
}
|
|
6130
6337
|
function lintSkillWrite(doc, options) {
|
|
6131
|
-
const
|
|
6338
|
+
const skillId = basename8(dirname9(resolve12(options.target)));
|
|
6339
|
+
const result = lintSkillDoc(doc, { skillId });
|
|
6132
6340
|
if (options.hard && !result.ok) {
|
|
6133
6341
|
throw new SkillLintVetoError(options.target, result.violations);
|
|
6134
6342
|
}
|
|
@@ -6140,13 +6348,13 @@ function skillRootsOf(config) {
|
|
|
6140
6348
|
return roots.map((root) => root.trim()).filter((root) => root !== "");
|
|
6141
6349
|
}
|
|
6142
6350
|
function isSkillTarget(roots, target) {
|
|
6143
|
-
if (
|
|
6351
|
+
if (basename8(target.displayPath) !== "SKILL.md")
|
|
6144
6352
|
return false;
|
|
6145
|
-
const resolvedPath =
|
|
6146
|
-
return roots.some((root) => resolvedPath.startsWith(
|
|
6353
|
+
const resolvedPath = resolve12(target.displayPath);
|
|
6354
|
+
return roots.some((root) => resolvedPath.startsWith(resolve12(root) + sep2));
|
|
6147
6355
|
}
|
|
6148
6356
|
function skillNameOf(target) {
|
|
6149
|
-
return
|
|
6357
|
+
return basename8(dirname9(target.displayPath));
|
|
6150
6358
|
}
|
|
6151
6359
|
function skillCanonicalForm(target) {
|
|
6152
6360
|
return resolveSkillRoot("dsh", { skill: skillNameOf(target), rel: "SKILL.md" });
|
|
@@ -6158,8 +6366,8 @@ function gateSkillIntent(ctx, harnessDir, config, target) {
|
|
|
6158
6366
|
return;
|
|
6159
6367
|
if (!isSkillTarget(roots, target))
|
|
6160
6368
|
return;
|
|
6161
|
-
const skillPath =
|
|
6162
|
-
if (!
|
|
6369
|
+
const skillPath = resolve12(target.displayPath);
|
|
6370
|
+
if (!existsSync16(skillPath))
|
|
6163
6371
|
return;
|
|
6164
6372
|
let doc;
|
|
6165
6373
|
try {
|
|
@@ -6176,7 +6384,7 @@ function gateSkillIntent(ctx, harnessDir, config, target) {
|
|
|
6176
6384
|
});
|
|
6177
6385
|
return;
|
|
6178
6386
|
}
|
|
6179
|
-
const result = lintSkillDoc(doc);
|
|
6387
|
+
const result = lintSkillDoc(doc, { skillId: basename8(dirname9(skillPath)) });
|
|
6180
6388
|
if (result.ok)
|
|
6181
6389
|
return;
|
|
6182
6390
|
const hard = resolveSeamHard(harnessDir, config);
|
|
@@ -6210,8 +6418,8 @@ async function skillWriteIntentListener(ctx, resolver, config, target, actor, ne
|
|
|
6210
6418
|
}
|
|
6211
6419
|
|
|
6212
6420
|
// src/gates/seams.ts
|
|
6213
|
-
import { existsSync as
|
|
6214
|
-
import { basename as
|
|
6421
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13, readdirSync as readdirSync10 } from "node:fs";
|
|
6422
|
+
import { basename as basename10, dirname as dirname10, join as join14, resolve as resolve14, sep as sep3 } from "node:path";
|
|
6215
6423
|
|
|
6216
6424
|
// ../engine/dist/audit.js
|
|
6217
6425
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
@@ -6410,7 +6618,7 @@ var SEAM_LOGGERS = {
|
|
|
6410
6618
|
roles: "mstar/roles-lint"
|
|
6411
6619
|
};
|
|
6412
6620
|
function isIndexFile(path) {
|
|
6413
|
-
const base =
|
|
6621
|
+
const base = basename10(path);
|
|
6414
6622
|
return base === "README.md" || base === "index.md";
|
|
6415
6623
|
}
|
|
6416
6624
|
function isMarkdownDoc(path) {
|
|
@@ -6419,7 +6627,7 @@ function isMarkdownDoc(path) {
|
|
|
6419
6627
|
function isAuditPlanTarget(path) {
|
|
6420
6628
|
if (!isMarkdownDoc(path))
|
|
6421
6629
|
return false;
|
|
6422
|
-
const segments =
|
|
6630
|
+
const segments = resolve14(path).split(sep3);
|
|
6423
6631
|
for (let i = 0;i < segments.length; i++) {
|
|
6424
6632
|
if (segments[i] !== "plans")
|
|
6425
6633
|
continue;
|
|
@@ -6430,7 +6638,7 @@ function isAuditPlanTarget(path) {
|
|
|
6430
6638
|
return false;
|
|
6431
6639
|
}
|
|
6432
6640
|
function isRolesTarget(path) {
|
|
6433
|
-
const segments =
|
|
6641
|
+
const segments = resolve14(path).split(sep3);
|
|
6434
6642
|
const idx = segments.indexOf("mstar-roles");
|
|
6435
6643
|
if (idx === -1)
|
|
6436
6644
|
return false;
|
|
@@ -6440,17 +6648,17 @@ function isRolesTarget(path) {
|
|
|
6440
6648
|
return rest[0] === "SKILL.md" || rest[0] === "references" && rest[rest.length - 1].endsWith(".md");
|
|
6441
6649
|
}
|
|
6442
6650
|
function rolesDirOf(path) {
|
|
6443
|
-
const segments =
|
|
6651
|
+
const segments = resolve14(path).split(sep3);
|
|
6444
6652
|
const idx = segments.indexOf("mstar-roles");
|
|
6445
6653
|
if (idx === -1)
|
|
6446
6654
|
return dirname10(path);
|
|
6447
|
-
return idx === 0 ? sep3 :
|
|
6655
|
+
return idx === 0 ? sep3 : join14(sep3, ...segments.slice(1, idx + 1));
|
|
6448
6656
|
}
|
|
6449
6657
|
function isSeamTarget(seam, harnessDir, target) {
|
|
6450
|
-
const path =
|
|
6658
|
+
const path = resolve14(target.displayPath);
|
|
6451
6659
|
switch (seam) {
|
|
6452
6660
|
case "design-md": {
|
|
6453
|
-
const base =
|
|
6661
|
+
const base = basename10(path);
|
|
6454
6662
|
return base === "DESIGN.md" || base === "DESIGN.dark.md";
|
|
6455
6663
|
}
|
|
6456
6664
|
case "audit":
|
|
@@ -6458,7 +6666,7 @@ function isSeamTarget(seam, harnessDir, target) {
|
|
|
6458
6666
|
case "compound": {
|
|
6459
6667
|
if (harnessDir === null)
|
|
6460
6668
|
return false;
|
|
6461
|
-
return path.startsWith(
|
|
6669
|
+
return path.startsWith(resolve14(join14(harnessDir, "knowledge")) + sep3) && isMarkdownDoc(path);
|
|
6462
6670
|
}
|
|
6463
6671
|
case "roles":
|
|
6464
6672
|
return isRolesTarget(path);
|
|
@@ -6475,9 +6683,9 @@ function auditSecretsViolations(findings, file) {
|
|
|
6475
6683
|
}
|
|
6476
6684
|
function validateDesignDoc(doc, path) {
|
|
6477
6685
|
const violations = [...validateDesignTokenFrontmatter(doc).violations];
|
|
6478
|
-
const isDark =
|
|
6479
|
-
const sibling =
|
|
6480
|
-
if (
|
|
6686
|
+
const isDark = basename10(path) === "DESIGN.dark.md";
|
|
6687
|
+
const sibling = join14(dirname10(path), isDark ? "DESIGN.md" : "DESIGN.dark.md");
|
|
6688
|
+
if (existsSync17(sibling)) {
|
|
6481
6689
|
const light = isDark ? readFileSync13(sibling, "utf8") : doc;
|
|
6482
6690
|
const dark = isDark ? doc : readFileSync13(sibling, "utf8");
|
|
6483
6691
|
violations.push(...assertLightDarkParity(light, dark).violations);
|
|
@@ -6503,8 +6711,8 @@ function validateRolesState(rolesDir, skillsRoot = dirname10(rolesDir)) {
|
|
|
6503
6711
|
for (const entry of readdirSync10(skillsRoot, { withFileTypes: true })) {
|
|
6504
6712
|
if (!entry.isDirectory() || !entry.name.startsWith("mstar-"))
|
|
6505
6713
|
continue;
|
|
6506
|
-
const skillFile =
|
|
6507
|
-
if (!
|
|
6714
|
+
const skillFile = join14(skillsRoot, entry.name, "SKILL.md");
|
|
6715
|
+
if (!existsSync17(skillFile))
|
|
6508
6716
|
continue;
|
|
6509
6717
|
try {
|
|
6510
6718
|
skillTexts[entry.name] = readFileSync13(skillFile, "utf8");
|
|
@@ -6537,8 +6745,8 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
6537
6745
|
try {
|
|
6538
6746
|
if (!isSeamTarget(seam, harnessDir, target))
|
|
6539
6747
|
return;
|
|
6540
|
-
const path =
|
|
6541
|
-
if (!
|
|
6748
|
+
const path = resolve14(target.displayPath);
|
|
6749
|
+
if (!existsSync17(path))
|
|
6542
6750
|
return;
|
|
6543
6751
|
let doc;
|
|
6544
6752
|
try {
|
|
@@ -6554,12 +6762,12 @@ function gateSeamIntent(ctx, harnessDir, config, seam, target) {
|
|
|
6554
6762
|
const hard = resolveSeamHard(harnessDir, config);
|
|
6555
6763
|
const verdict = applyEnforcement(result, { hard });
|
|
6556
6764
|
if (verdict.hardBlocked) {
|
|
6557
|
-
logger.error(`${
|
|
6765
|
+
logger.error(`${basename10(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):
|
|
6558
6766
|
${verdict.violations.map(formatViolation).join(`
|
|
6559
6767
|
`)}`);
|
|
6560
6768
|
emitSeamAdvisory(ctx, seam, target.displayPath, verdict, hard, { repair: true });
|
|
6561
6769
|
} else {
|
|
6562
|
-
logger.warn(`${
|
|
6770
|
+
logger.warn(`${basename10(path)} write to ${target.displayPath} (advisory):
|
|
6563
6771
|
${verdict.violations.map(formatViolation).join(`
|
|
6564
6772
|
`)}`);
|
|
6565
6773
|
emitSeamAdvisory(ctx, seam, target.displayPath, verdict, hard);
|
|
@@ -6608,7 +6816,7 @@ function lintRolesWrite(doc, options) {
|
|
|
6608
6816
|
}
|
|
6609
6817
|
|
|
6610
6818
|
// src/gates/tools.ts
|
|
6611
|
-
import { existsSync as
|
|
6819
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "node:fs";
|
|
6612
6820
|
import { join as join17, resolve as resolve16 } from "node:path";
|
|
6613
6821
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
6614
6822
|
var ITERATION_VIOLATION_SCHEMA = {
|
|
@@ -6774,9 +6982,9 @@ function registerSddIterationTools(ctx, resolver) {
|
|
|
6774
6982
|
presentResult: (_args, _result) => ({ card: "generic", title: "Iteration gate evaluation" }),
|
|
6775
6983
|
isConcurrencySafe: () => false,
|
|
6776
6984
|
async execute(args) {
|
|
6777
|
-
if (!
|
|
6985
|
+
if (!existsSync18(args.snapshot_path))
|
|
6778
6986
|
throw new Error(`workflow snapshot not found: ${args.snapshot_path}`);
|
|
6779
|
-
if (!
|
|
6987
|
+
if (!existsSync18(args.compass_path))
|
|
6780
6988
|
throw new Error(`compass file not found: ${args.compass_path}`);
|
|
6781
6989
|
const snapshotDoc = readJson(args.snapshot_path);
|
|
6782
6990
|
const compassDoc = parseCompassFrontmatter(args.compass_path);
|
|
@@ -6831,7 +7039,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6831
7039
|
async execute(args) {
|
|
6832
7040
|
const abs = resolve16(args.dir);
|
|
6833
7041
|
const lightPath = join17(abs, "DESIGN.md");
|
|
6834
|
-
if (!
|
|
7042
|
+
if (!existsSync18(lightPath))
|
|
6835
7043
|
throw new Error(`design file not found: ${lightPath}`);
|
|
6836
7044
|
const light = readFileSync14(lightPath, "utf8");
|
|
6837
7045
|
const result = validateDesignDoc(light, lightPath);
|
|
@@ -6884,7 +7092,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6884
7092
|
isConcurrencySafe: () => false,
|
|
6885
7093
|
async execute(args) {
|
|
6886
7094
|
const abs = resolve16(args.plan_path);
|
|
6887
|
-
if (!
|
|
7095
|
+
if (!existsSync18(abs))
|
|
6888
7096
|
throw new Error(`plan file not found: ${abs}`);
|
|
6889
7097
|
const text = readFileSync14(abs, "utf8");
|
|
6890
7098
|
const result = validateAuditDoc(text, abs);
|
|
@@ -6924,7 +7132,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6924
7132
|
isConcurrencySafe: () => false,
|
|
6925
7133
|
async execute(args, exec) {
|
|
6926
7134
|
const abs = resolve16(args.doc_path);
|
|
6927
|
-
if (!
|
|
7135
|
+
if (!existsSync18(abs))
|
|
6928
7136
|
throw new Error(`knowledge doc not found: ${abs}`);
|
|
6929
7137
|
const text = readFileSync14(abs, "utf8");
|
|
6930
7138
|
const base = validateCompoundDoc(text, abs, args.repo_root !== undefined ? null : resolver.forAgent(exec.agent));
|
|
@@ -6969,7 +7177,7 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6969
7177
|
isConcurrencySafe: () => false,
|
|
6970
7178
|
async execute(args) {
|
|
6971
7179
|
const rolesDir = resolve16(args.roles_dir);
|
|
6972
|
-
if (!
|
|
7180
|
+
if (!existsSync18(join17(rolesDir, "SKILL.md")))
|
|
6973
7181
|
throw new Error(`roles dir not found: ${rolesDir}`);
|
|
6974
7182
|
const result = validateRolesState(rolesDir, args.skills_root !== undefined ? resolve16(args.skills_root) : undefined);
|
|
6975
7183
|
return { ok: result.ok, violations: result.violations.map(iterationViolationView) };
|
|
@@ -6979,8 +7187,8 @@ function registerSeamTools(ctx, resolver) {
|
|
|
6979
7187
|
}
|
|
6980
7188
|
|
|
6981
7189
|
// src/gates/adapter.ts
|
|
6982
|
-
import { existsSync as
|
|
6983
|
-
import { join as
|
|
7190
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
7191
|
+
import { join as join19 } from "node:path";
|
|
6984
7192
|
import { Service as Service2 } from "@deepseek-ai/cordis";
|
|
6985
7193
|
var HOST_LOGGER = "mstar/host-adapter";
|
|
6986
7194
|
function mergeLeasesMatch(left, right) {
|
|
@@ -7016,7 +7224,7 @@ class DshHostAdapter extends Service2 {
|
|
|
7016
7224
|
this.logSink(level, msg);
|
|
7017
7225
|
}
|
|
7018
7226
|
statusGate(path, kind, harnessDir) {
|
|
7019
|
-
if (!
|
|
7227
|
+
if (!existsSync19(path))
|
|
7020
7228
|
return { ok: true, violations: [] };
|
|
7021
7229
|
return validateStatusDoc(path, kind, harnessDir);
|
|
7022
7230
|
}
|
|
@@ -7071,7 +7279,7 @@ class DshHostAdapter extends Service2 {
|
|
|
7071
7279
|
if (harnessDir !== null) {
|
|
7072
7280
|
const selection = resolveActiveWorkflow(harnessDir);
|
|
7073
7281
|
if (selection.kind === "active") {
|
|
7074
|
-
const snapshotPath =
|
|
7282
|
+
const snapshotPath = join19(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
7075
7283
|
try {
|
|
7076
7284
|
const snapshot = readJson(snapshotPath);
|
|
7077
7285
|
const stored = snapshot?.integration_merge_lease;
|
|
@@ -7098,7 +7306,7 @@ class DshHostAdapter extends Service2 {
|
|
|
7098
7306
|
|
|
7099
7307
|
// src/gates/agent-personas.ts
|
|
7100
7308
|
import { readFileSync as readFileSync15, readdirSync as readdirSync12, statSync as statSync7 } from "node:fs";
|
|
7101
|
-
import { join as
|
|
7309
|
+
import { join as join20, resolve as resolve17, sep as sep5 } from "node:path";
|
|
7102
7310
|
var ROLE_ID_PATTERN = /^[a-z0-9-]{1,32}$/;
|
|
7103
7311
|
var defaultCache = new Map;
|
|
7104
7312
|
function personaFor(roleId, lookup, warn) {
|
|
@@ -7126,7 +7334,7 @@ function subagentRoleIds(agentsDir) {
|
|
|
7126
7334
|
const roleId = name.slice(0, -3);
|
|
7127
7335
|
let content;
|
|
7128
7336
|
try {
|
|
7129
|
-
content = readFileSync15(
|
|
7337
|
+
content = readFileSync15(join20(agentsDir, name), "utf8");
|
|
7130
7338
|
} catch {
|
|
7131
7339
|
continue;
|
|
7132
7340
|
}
|
|
@@ -7237,6 +7445,8 @@ function unquote(value) {
|
|
|
7237
7445
|
// src/gates/role-persona.ts
|
|
7238
7446
|
var ROLE_PERSONA_LOGGER = "mstar/role-persona";
|
|
7239
7447
|
var SUBAGENTS_SERVICE = "subagents";
|
|
7448
|
+
var PERSONA_SEAM_EVENT = "internal/get";
|
|
7449
|
+
var ROLE_PERSONA_WRAPPER_BRAND = Symbol("mstar.role-persona.wrapper");
|
|
7240
7450
|
var rolePersonaLogSink = () => {};
|
|
7241
7451
|
function setRolePersonaLogger(sink) {
|
|
7242
7452
|
const prior = rolePersonaLogSink;
|
|
@@ -7254,7 +7464,7 @@ function setRolePersonaAgentsDir(dir) {
|
|
|
7254
7464
|
var wrapperCache = new WeakMap;
|
|
7255
7465
|
function registerRolePersonaChannel(ctx, config) {
|
|
7256
7466
|
const rolePersonas = config.rolePersonas;
|
|
7257
|
-
ctx.on(
|
|
7467
|
+
ctx.on(PERSONA_SEAM_EVENT, (_readCtx, name, _error, next) => {
|
|
7258
7468
|
const value = next();
|
|
7259
7469
|
if (name !== SUBAGENTS_SERVICE)
|
|
7260
7470
|
return value;
|
|
@@ -7266,6 +7476,47 @@ function registerRolePersonaChannel(ctx, config) {
|
|
|
7266
7476
|
}
|
|
7267
7477
|
});
|
|
7268
7478
|
}
|
|
7479
|
+
var SEAM_WARN = `role persona channel not installed — cordis '${PERSONA_SEAM_EVENT}' seam missing or unrecognized (rolePersonas will not be merged into subagent starts)`;
|
|
7480
|
+
function evaluateSeamProbe({ dispatched, readError, value }) {
|
|
7481
|
+
if (!dispatched)
|
|
7482
|
+
return { ok: false, reason: "seam-absent" };
|
|
7483
|
+
if (readError !== undefined)
|
|
7484
|
+
return { ok: true, reason: "service-absent" };
|
|
7485
|
+
if (typeof value === "object" && value !== null && value[ROLE_PERSONA_WRAPPER_BRAND] === true) {
|
|
7486
|
+
return { ok: true };
|
|
7487
|
+
}
|
|
7488
|
+
return { ok: false, reason: "wrap-skipped" };
|
|
7489
|
+
}
|
|
7490
|
+
function probeRolePersonaSeam(ctx) {
|
|
7491
|
+
try {
|
|
7492
|
+
let dispatched = false;
|
|
7493
|
+
let readError;
|
|
7494
|
+
let value;
|
|
7495
|
+
const disposeCanary = ctx.on(PERSONA_SEAM_EVENT, (_readCtx, _name, _error, next) => {
|
|
7496
|
+
dispatched = true;
|
|
7497
|
+
return next();
|
|
7498
|
+
});
|
|
7499
|
+
try {
|
|
7500
|
+
value = ctx.subagents;
|
|
7501
|
+
} catch (error) {
|
|
7502
|
+
readError = error;
|
|
7503
|
+
} finally {
|
|
7504
|
+
disposeCanary();
|
|
7505
|
+
}
|
|
7506
|
+
const result = evaluateSeamProbe({ dispatched, readError, value });
|
|
7507
|
+
if (!result.ok) {
|
|
7508
|
+
log2("warn", `${SEAM_WARN} (reason: ${result.reason})`);
|
|
7509
|
+
} else if (result.reason === "service-absent") {
|
|
7510
|
+
log2("debug", `role persona seam probe: 'subagents' unresolved at apply (the apply ctx does not resolve it — cordis resolves the service in dispatch scopes, where reads are intercepted per read)`);
|
|
7511
|
+
}
|
|
7512
|
+
return result;
|
|
7513
|
+
} catch (error) {
|
|
7514
|
+
try {
|
|
7515
|
+
log2("debug", `role persona seam probe failed internally — fail-open (observation only): ${errorMessage2(error)}`);
|
|
7516
|
+
} catch {}
|
|
7517
|
+
return { ok: true };
|
|
7518
|
+
}
|
|
7519
|
+
}
|
|
7269
7520
|
function wrapSubagentsService(value, rolePersonas) {
|
|
7270
7521
|
if (typeof value !== "object" || value === null)
|
|
7271
7522
|
return value;
|
|
@@ -7276,6 +7527,7 @@ function wrapSubagentsService(value, rolePersonas) {
|
|
|
7276
7527
|
if (cached !== undefined && cached.rolePersonas === rolePersonas)
|
|
7277
7528
|
return cached.wrapper;
|
|
7278
7529
|
const wrapper = Object.create(value);
|
|
7530
|
+
Object.defineProperty(wrapper, ROLE_PERSONA_WRAPPER_BRAND, { value: true, enumerable: false });
|
|
7279
7531
|
wrapper.start = (name, request) => {
|
|
7280
7532
|
let merged = request;
|
|
7281
7533
|
try {
|
|
@@ -7344,7 +7596,7 @@ function log2(level, message) {
|
|
|
7344
7596
|
|
|
7345
7597
|
// src/gates/workflow-ledger.ts
|
|
7346
7598
|
import { readFileSync as readFileSync16, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
7347
|
-
import { join as
|
|
7599
|
+
import { join as join21 } from "node:path";
|
|
7348
7600
|
var WORKFLOW_LEDGER_LOGGER = "mstar/workflow-ledger";
|
|
7349
7601
|
var TOOL_WORKFLOW_RUN_START = "tool-workflow/run-start";
|
|
7350
7602
|
var TOOL_WORKFLOW_AGENT_START = "tool-workflow/agent-start";
|
|
@@ -7388,7 +7640,7 @@ function loadWatermark(workflowDir, fresh = false) {
|
|
|
7388
7640
|
return cached;
|
|
7389
7641
|
const watermark = new Map;
|
|
7390
7642
|
try {
|
|
7391
|
-
const raw = readFileSync16(
|
|
7643
|
+
const raw = readFileSync16(join21(workflowDir, WORKFLOW_LEDGER_WATERMARK_FILE), "utf8");
|
|
7392
7644
|
const record = asRecord(JSON.parse(raw));
|
|
7393
7645
|
const cursors = asRecord(record?.cursors);
|
|
7394
7646
|
if (cursors !== undefined) {
|
|
@@ -7411,7 +7663,7 @@ function loadWatermark(workflowDir, fresh = false) {
|
|
|
7411
7663
|
}
|
|
7412
7664
|
function saveWatermark(workflowDir, watermark) {
|
|
7413
7665
|
try {
|
|
7414
|
-
const file =
|
|
7666
|
+
const file = join21(workflowDir, WORKFLOW_LEDGER_WATERMARK_FILE);
|
|
7415
7667
|
const tmp = `${file}.tmp`;
|
|
7416
7668
|
writeFileSync5(tmp, JSON.stringify({ v: 1, cursors: Object.fromEntries(watermark) }));
|
|
7417
7669
|
renameSync3(tmp, file);
|
|
@@ -7627,8 +7879,8 @@ function registerWorkflowLedger(ctx, resolver, workflowAskCache) {
|
|
|
7627
7879
|
}
|
|
7628
7880
|
|
|
7629
7881
|
// src/gates/goal-bridge.ts
|
|
7630
|
-
import { existsSync as
|
|
7631
|
-
import { join as
|
|
7882
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, readdirSync as readdirSync13 } from "node:fs";
|
|
7883
|
+
import { join as join22 } from "node:path";
|
|
7632
7884
|
var GOAL_BRIDGE_LOGGER = "mstar/goal-bridge";
|
|
7633
7885
|
var DEFAULT_MAX_GOAL_ROUNDS = 256;
|
|
7634
7886
|
var FLOW_SEQUENCE = "iteration-start → per-plan cycles → iteration-close → PR delivery → merge-ready";
|
|
@@ -7655,12 +7907,12 @@ function projectRegisterPointer(harnessDir) {
|
|
|
7655
7907
|
for (const entry of readdirSync13(projectsDir, { withFileTypes: true })) {
|
|
7656
7908
|
if (!entry.isDirectory())
|
|
7657
7909
|
continue;
|
|
7658
|
-
const registerPath =
|
|
7659
|
-
if (
|
|
7910
|
+
const registerPath = join22(projectsDir, entry.name, PROJECT_REGISTER_FILE);
|
|
7911
|
+
if (existsSync20(registerPath))
|
|
7660
7912
|
return registerPath;
|
|
7661
7913
|
}
|
|
7662
7914
|
} catch {}
|
|
7663
|
-
return
|
|
7915
|
+
return join22(projectsDir, _DEFAULT_PROJECT, PROJECT_REGISTER_FILE);
|
|
7664
7916
|
}
|
|
7665
7917
|
function isRootLikeAgent(agent) {
|
|
7666
7918
|
const header = agent?.session?.header;
|
|
@@ -7671,7 +7923,7 @@ function iterationGoalObjective(iterationId) {
|
|
|
7671
7923
|
}
|
|
7672
7924
|
function steeringCompass(harnessDir) {
|
|
7673
7925
|
const iterationsDir = resolveIterationDir(harnessDir);
|
|
7674
|
-
if (!
|
|
7926
|
+
if (!existsSync20(iterationsDir))
|
|
7675
7927
|
return;
|
|
7676
7928
|
let entries;
|
|
7677
7929
|
try {
|
|
@@ -7682,8 +7934,8 @@ function steeringCompass(harnessDir) {
|
|
|
7682
7934
|
for (const entry of entries) {
|
|
7683
7935
|
if (!entry.isDirectory())
|
|
7684
7936
|
continue;
|
|
7685
|
-
const compassPath =
|
|
7686
|
-
if (!
|
|
7937
|
+
const compassPath = join22(iterationsDir, entry.name, "delivery-compass.md");
|
|
7938
|
+
if (!existsSync20(compassPath))
|
|
7687
7939
|
continue;
|
|
7688
7940
|
let content;
|
|
7689
7941
|
try {
|
|
@@ -7863,8 +8115,8 @@ function registerGoalBridge(ctx, resolver, config) {
|
|
|
7863
8115
|
}
|
|
7864
8116
|
|
|
7865
8117
|
// src/gates/plan-mode-bridge.ts
|
|
7866
|
-
import { existsSync as
|
|
7867
|
-
import { join as
|
|
8118
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
8119
|
+
import { join as join23 } from "node:path";
|
|
7868
8120
|
var PLAN_MODE_BRIDGE_LOGGER = "mstar/plan-mode-bridge";
|
|
7869
8121
|
var PLAN_STATUS_TODO = "Todo";
|
|
7870
8122
|
var planModeBridgeLogSink = () => {};
|
|
@@ -7880,13 +8132,13 @@ function errorMessage5(error) {
|
|
|
7880
8132
|
return error instanceof Error ? error.message : String(error);
|
|
7881
8133
|
}
|
|
7882
8134
|
function hasPrepareWindow(harnessDir) {
|
|
7883
|
-
const statusPath =
|
|
7884
|
-
if (!
|
|
8135
|
+
const statusPath = join23(harnessDir, STATUS_FILE);
|
|
8136
|
+
if (!existsSync21(statusPath))
|
|
7885
8137
|
return false;
|
|
7886
8138
|
const selection = resolveReadWorkflow(harnessDir);
|
|
7887
8139
|
if (selection.kind === "error")
|
|
7888
8140
|
return false;
|
|
7889
|
-
const snapshotPath =
|
|
8141
|
+
const snapshotPath = join23(harnessDir, selection.dir, WORKFLOW_SNAPSHOT_FILE);
|
|
7890
8142
|
let doc;
|
|
7891
8143
|
try {
|
|
7892
8144
|
doc = readJson(snapshotPath);
|
|
@@ -8057,6 +8309,10 @@ function setAdvisoryLogger(sink) {
|
|
|
8057
8309
|
return prior;
|
|
8058
8310
|
}
|
|
8059
8311
|
var ADVISORY_ID_LIST_CAP = 20;
|
|
8312
|
+
var advisoryAbortWarned = false;
|
|
8313
|
+
function resetAdvisoryAbortWarn() {
|
|
8314
|
+
advisoryAbortWarned = false;
|
|
8315
|
+
}
|
|
8060
8316
|
function capIdList(items) {
|
|
8061
8317
|
if (items.length <= ADVISORY_ID_LIST_CAP)
|
|
8062
8318
|
return items.join(", ");
|
|
@@ -8065,11 +8321,11 @@ function capIdList(items) {
|
|
|
8065
8321
|
async function runFallbacksAdvisory(ctx, agentsDir) {
|
|
8066
8322
|
try {
|
|
8067
8323
|
if (!fallbacksMounted(ctx))
|
|
8068
|
-
return false;
|
|
8324
|
+
return { ran: false, converged: false };
|
|
8069
8325
|
const config = readRowConfig(ctx);
|
|
8070
8326
|
if (config === undefined) {
|
|
8071
8327
|
log6("debug", "fallbacks row config unreadable (absent or non-object) — adoption advisory skipped");
|
|
8072
|
-
return true;
|
|
8328
|
+
return { ran: true, converged: true };
|
|
8073
8329
|
}
|
|
8074
8330
|
const service = fallbacksService(ctx);
|
|
8075
8331
|
if (service !== undefined) {
|
|
@@ -8077,8 +8333,11 @@ async function runFallbacksAdvisory(ctx, agentsDir) {
|
|
|
8077
8333
|
}
|
|
8078
8334
|
return runStructuralAdvisory(config, agentsDir);
|
|
8079
8335
|
} catch (error) {
|
|
8080
|
-
|
|
8081
|
-
|
|
8336
|
+
if (!advisoryAbortWarned) {
|
|
8337
|
+
advisoryAbortWarned = true;
|
|
8338
|
+
log6("warn", `fallbacks adoption advisory aborted (degraded — warn-only, deployment config untouched): ${errorMessage7(error)}`);
|
|
8339
|
+
}
|
|
8340
|
+
return { ran: true, converged: false };
|
|
8082
8341
|
}
|
|
8083
8342
|
}
|
|
8084
8343
|
async function runSeedsAdvisory(service, config, agentsDir) {
|
|
@@ -8088,12 +8347,12 @@ async function runSeedsAdvisory(service, config, agentsDir) {
|
|
|
8088
8347
|
}
|
|
8089
8348
|
if (agentsDir === undefined) {
|
|
8090
8349
|
log6("debug", "harness-agents mirror absent — fallbacks adoption taxonomy check skipped (config-only advisory)");
|
|
8091
|
-
return true;
|
|
8350
|
+
return { ran: true, converged: true };
|
|
8092
8351
|
}
|
|
8093
8352
|
const mstarIds = subagentRoleIds(agentsDir);
|
|
8094
8353
|
if (mstarIds.length === 0) {
|
|
8095
8354
|
log6("debug", "harness-agents mirror has no subagent-mode shells — fallbacks adoption taxonomy check skipped");
|
|
8096
|
-
return true;
|
|
8355
|
+
return { ran: true, converged: true };
|
|
8097
8356
|
}
|
|
8098
8357
|
const seedsLog = (_level, message) => log6("debug", message);
|
|
8099
8358
|
const view = await declareMstarSeeds(service, { agentsDir, log: seedsLog });
|
|
@@ -8102,26 +8361,26 @@ async function runSeedsAdvisory(service, config, agentsDir) {
|
|
|
8102
8361
|
readback = service.getEffectiveRoles();
|
|
8103
8362
|
} catch (error) {
|
|
8104
8363
|
log6("warn", `fallbacks effective-state readback failed — adoption state unavailable: ${errorMessage7(error)}`);
|
|
8105
|
-
return true;
|
|
8364
|
+
return { ran: true, converged: true };
|
|
8106
8365
|
}
|
|
8107
8366
|
reportEffectiveState(mstarIds, readback);
|
|
8108
8367
|
reportDeclareOutcome(view);
|
|
8109
|
-
return true;
|
|
8368
|
+
return { ran: true, converged: true };
|
|
8110
8369
|
}
|
|
8111
8370
|
function runStructuralAdvisory(config, agentsDir) {
|
|
8112
8371
|
if (agentsDir === undefined) {
|
|
8113
8372
|
log6("debug", "harness-agents mirror absent — fallbacks adoption taxonomy check skipped (config-only advisory)");
|
|
8114
|
-
return true;
|
|
8373
|
+
return { ran: true, converged: true };
|
|
8115
8374
|
}
|
|
8116
8375
|
const mstarIds = subagentRoleIds(agentsDir);
|
|
8117
8376
|
if (mstarIds.length === 0) {
|
|
8118
8377
|
log6("debug", "harness-agents mirror has no subagent-mode shells — fallbacks adoption taxonomy check skipped");
|
|
8119
|
-
return true;
|
|
8378
|
+
return { ran: true, converged: true };
|
|
8120
8379
|
}
|
|
8121
8380
|
const list = readRolesList(config);
|
|
8122
8381
|
if (list === undefined) {
|
|
8123
8382
|
log6("debug", "fallbacks roles block not structurally readable (roles.list absent or non-array) — adoption advisory skipped");
|
|
8124
|
-
return true;
|
|
8383
|
+
return { ran: true, converged: true };
|
|
8125
8384
|
}
|
|
8126
8385
|
const declared = new Map;
|
|
8127
8386
|
for (let index = 0;index < list.length; index++) {
|
|
@@ -8146,7 +8405,7 @@ function runStructuralAdvisory(config, agentsDir) {
|
|
|
8146
8405
|
if (emptyPersona.length > 0) {
|
|
8147
8406
|
log6("warn", `fallbacks roles.list declares roles with an empty persona: ${capIdList(emptyPersona)} — declare a persona (or remove the role)`);
|
|
8148
8407
|
}
|
|
8149
|
-
return true;
|
|
8408
|
+
return { ran: true, converged: true };
|
|
8150
8409
|
}
|
|
8151
8410
|
function reportEffectiveState(mstarIds, readback) {
|
|
8152
8411
|
const byId = new Map;
|
|
@@ -8363,14 +8622,22 @@ var inject = ["loader"];
|
|
|
8363
8622
|
function packagedCommandsDir() {
|
|
8364
8623
|
try {
|
|
8365
8624
|
const dir = fileURLToPath3(new URL("../harness-commands", import.meta.url));
|
|
8366
|
-
return
|
|
8625
|
+
return existsSync22(dir) ? dir : undefined;
|
|
8367
8626
|
} catch {
|
|
8368
8627
|
return;
|
|
8369
8628
|
}
|
|
8370
8629
|
}
|
|
8630
|
+
var FRONTMATTER_FIELD_RE = /^[ \t]*:[ \t]*(.+)$/;
|
|
8371
8631
|
function commandFrontmatterField(frontmatter, label) {
|
|
8372
|
-
|
|
8373
|
-
|
|
8632
|
+
for (const line of frontmatter.split(`
|
|
8633
|
+
`)) {
|
|
8634
|
+
if (!line.startsWith(label))
|
|
8635
|
+
continue;
|
|
8636
|
+
const match = FRONTMATTER_FIELD_RE.exec(line.slice(label.length));
|
|
8637
|
+
if (match)
|
|
8638
|
+
return match[1].trim();
|
|
8639
|
+
}
|
|
8640
|
+
return;
|
|
8374
8641
|
}
|
|
8375
8642
|
function unquote2(value) {
|
|
8376
8643
|
return value.length >= 2 && value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
@@ -8411,7 +8678,7 @@ function registerMstarCommands(ctx) {
|
|
|
8411
8678
|
for (const file of readdirSync14(dir).sort()) {
|
|
8412
8679
|
if (!file.endsWith(".md"))
|
|
8413
8680
|
continue;
|
|
8414
|
-
const parsed = parseCommandMarkdown(readFileSync18(
|
|
8681
|
+
const parsed = parseCommandMarkdown(readFileSync18(join24(dir, file), "utf8"));
|
|
8415
8682
|
if (parsed === undefined)
|
|
8416
8683
|
continue;
|
|
8417
8684
|
commandsCtx.commands.register({
|
|
@@ -8477,6 +8744,7 @@ function apply(ctx, config) {
|
|
|
8477
8744
|
else
|
|
8478
8745
|
logger.warn(message);
|
|
8479
8746
|
});
|
|
8747
|
+
resetAdvisoryAbortWarn();
|
|
8480
8748
|
let advisoryPassed = false;
|
|
8481
8749
|
let advisoryPassInFlight = false;
|
|
8482
8750
|
let advisoryGeneration = 0;
|
|
@@ -8485,8 +8753,8 @@ function apply(ctx, config) {
|
|
|
8485
8753
|
return;
|
|
8486
8754
|
advisoryPassInFlight = true;
|
|
8487
8755
|
const generation = advisoryGeneration;
|
|
8488
|
-
runFallbacksAdvisory(ctx, packagedAgentsDir()).then((
|
|
8489
|
-
if (ran && generation === advisoryGeneration)
|
|
8756
|
+
runFallbacksAdvisory(ctx, packagedAgentsDir()).then((report) => {
|
|
8757
|
+
if (report.ran && report.converged && generation === advisoryGeneration)
|
|
8490
8758
|
advisoryPassed = true;
|
|
8491
8759
|
}).finally(() => {
|
|
8492
8760
|
advisoryPassInFlight = false;
|
|
@@ -8500,23 +8768,43 @@ function apply(ctx, config) {
|
|
|
8500
8768
|
const service = fallbacksService(serviceCtx);
|
|
8501
8769
|
if (service === undefined)
|
|
8502
8770
|
return;
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8771
|
+
let disposed = false;
|
|
8772
|
+
const retryTimers = [];
|
|
8773
|
+
const declareAttempt = (attempt) => {
|
|
8774
|
+
declareMstarSeeds(service, {
|
|
8775
|
+
agentsDir: packagedAgentsDir(),
|
|
8776
|
+
log: (level, message) => {
|
|
8777
|
+
const logger = ctx.logger(SEEDS_LOGGER);
|
|
8778
|
+
if (level === "warn")
|
|
8779
|
+
logger.warn(message);
|
|
8780
|
+
else if (level === "error")
|
|
8781
|
+
logger.error(message);
|
|
8782
|
+
else
|
|
8783
|
+
logger.debug(message);
|
|
8784
|
+
}
|
|
8785
|
+
}).catch((error) => {
|
|
8786
|
+
if (disposed)
|
|
8787
|
+
return;
|
|
8788
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8789
|
+
if (attempt >= 3) {
|
|
8790
|
+
ctx.logger(SEEDS_LOGGER).error(`mstar seeds declaration failed (contained — fallbacks taxonomy unchanged): ${message}`);
|
|
8791
|
+
return;
|
|
8792
|
+
}
|
|
8793
|
+
ctx.logger(SEEDS_LOGGER).debug(`seeds declare attempt ${attempt}/3 failed: ${message}`);
|
|
8794
|
+
retryTimers.push(setTimeout(() => {
|
|
8795
|
+
if (!disposed)
|
|
8796
|
+
declareAttempt(attempt + 1);
|
|
8797
|
+
}, attempt === 1 ? 50 : 250));
|
|
8798
|
+
});
|
|
8799
|
+
};
|
|
8800
|
+
declareAttempt(1);
|
|
8517
8801
|
return () => {
|
|
8802
|
+
disposed = true;
|
|
8803
|
+
for (const timer of retryTimers)
|
|
8804
|
+
clearTimeout(timer);
|
|
8518
8805
|
advisoryPassed = false;
|
|
8519
8806
|
advisoryGeneration += 1;
|
|
8807
|
+
resetAdvisoryAbortWarn();
|
|
8520
8808
|
};
|
|
8521
8809
|
});
|
|
8522
8810
|
registerSettleListener(ctx, config, pairing);
|
|
@@ -8575,6 +8863,7 @@ function apply(ctx, config) {
|
|
|
8575
8863
|
}
|
|
8576
8864
|
ctx.on("tools/pre-execute", (exec, next) => preExecuteListener(ctx, resolver, config, adapter, exec, next), { prepend: true });
|
|
8577
8865
|
registerRolePersonaChannel(ctx, config);
|
|
8866
|
+
probeRolePersonaSeam(ctx);
|
|
8578
8867
|
ctx.events.on("subagent/start", () => {
|
|
8579
8868
|
runAdvisoryPass();
|
|
8580
8869
|
});
|