@mstar-harness/engine 2.3.0 → 2.4.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/dist/engine.js CHANGED
@@ -3468,13 +3468,56 @@ var FIVE_QUESTION_SECTIONS = [
3468
3468
  { key: "evidence", label: "Evidence", question: "what a correct result looks like (success criteria / evidence)" },
3469
3469
  { key: "references", label: "References", question: "additional resources to open when the main path is not enough" }
3470
3470
  ];
3471
+ function stripFrontmatter(text) {
3472
+ const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
3473
+ if (lines.length === 0 || lines[0].trim() !== "---")
3474
+ return text;
3475
+ for (let i = 1;i < lines.length; i++) {
3476
+ if (lines[i].trim() === "---")
3477
+ return lines.slice(i + 1).join(`
3478
+ `);
3479
+ }
3480
+ return text;
3481
+ }
3471
3482
  var HEADING_RE = /^#{1,6}\s+[^\r\n]+$/;
3472
- function lintFiveQuestion(bodyText) {
3473
- const headings = bodyText.split(/\r?\n/).filter((line) => HEADING_RE.test(line)).map((line) => line.replace(/^#{1,6}\s+/, "").trim().toLowerCase());
3483
+ function collectHeadings(bodyText) {
3484
+ const headings = [];
3485
+ let inFence = false;
3486
+ for (const line of bodyText.split(/\r?\n/)) {
3487
+ if (line.startsWith("```") || line.startsWith("~~~")) {
3488
+ inFence = !inFence;
3489
+ continue;
3490
+ }
3491
+ if (!inFence && HEADING_RE.test(line)) {
3492
+ headings.push(line.replace(/^#{1,6}\s+/, "").trim().toLowerCase());
3493
+ }
3494
+ }
3495
+ return headings;
3496
+ }
3497
+ var RUNTIME_HEADING_ALIASES = {
3498
+ workflow: ["process", "playbook"],
3499
+ "decision-rules": [
3500
+ "hard rules",
3501
+ "core rules",
3502
+ "rule",
3503
+ "gate",
3504
+ "not to do",
3505
+ "red flags",
3506
+ "反模式",
3507
+ "红线",
3508
+ "规则",
3509
+ "门禁"
3510
+ ],
3511
+ evidence: ["output format", "证据"],
3512
+ references: ["dependencies", "关系"]
3513
+ };
3514
+ function lintFiveQuestion(bodyText, mode = "authoring") {
3515
+ const headings = collectHeadings(bodyText);
3474
3516
  const violations = [];
3475
3517
  for (const section of FIVE_QUESTION_SECTIONS) {
3476
3518
  const label = section.label.toLowerCase();
3477
- const covered = headings.some((heading) => heading.includes(label));
3519
+ const aliases = mode === "runtime" ? RUNTIME_HEADING_ALIASES[section.key] ?? [] : [];
3520
+ const covered = headings.some((heading) => heading.includes(label) || aliases.some((alias) => heading.includes(alias)));
3478
3521
  if (!covered) {
3479
3522
  violations.push(violation11("low", `skill-authoring.five-question.${section.key}`, `body does not answer "${section.question}" — no "${section.label}" section (mstar-skill-authoring § Body 必须回答的 5 问 / § 默认 Body 结构)`, `add a "## ${section.label}" section covering ${section.question}`));
3480
3523
  }
@@ -3503,6 +3546,7 @@ export {
3503
3546
  techDebtRollup,
3504
3547
  taskReportExists,
3505
3548
  taskBrief,
3549
+ stripFrontmatter,
3506
3550
  singleReviewSnapshot,
3507
3551
  sddWorkspace,
3508
3552
  scopeGuard,
@@ -3575,6 +3619,7 @@ export {
3575
3619
  SddScriptError,
3576
3620
  SHARED_FAMILIES,
3577
3621
  SEVERITY_ORDER,
3622
+ RUNTIME_HEADING_ALIASES,
3578
3623
  ROLE_MAPPING,
3579
3624
  QC_REVIEWER_PARAMS,
3580
3625
  KNOWLEDGE_SEVERITIES,
package/dist/index.d.ts CHANGED
@@ -48,5 +48,5 @@ export type { DevTrackParam, QcReviewerParam, RoleFamily, RoleMappingEntry, Role
48
48
  export { DEV_TRACK_PARAMS, QC_REVIEWER_PARAMS, ROLE_MAPPING, SHARED_FAMILIES, lintLoadOrder, validateRoleMapping, } from "./roles.js";
49
49
  export type { DetectResult, HostAdapter, HostId, SkillRootPaths, ToolSignal } from "./host.js";
50
50
  export { detectHost, resolveSkillRoot } from "./host.js";
51
- export type { FiveQuestionSection } from "./skill-authoring.js";
52
- export { FIVE_QUESTION_SECTIONS, lintFiveQuestion, lintFrontmatter, resolveAssetPath, } from "./skill-authoring.js";
51
+ export type { FiveQuestionMode, FiveQuestionSection } from "./skill-authoring.js";
52
+ export { FIVE_QUESTION_SECTIONS, RUNTIME_HEADING_ALIASES, lintFiveQuestion, lintFrontmatter, resolveAssetPath, stripFrontmatter, } from "./skill-authoring.js";
@@ -36,19 +36,43 @@ export type FiveQuestionSection = {
36
36
  question: string;
37
37
  };
38
38
  export declare const FIVE_QUESTION_SECTIONS: readonly FiveQuestionSection[];
39
+ /** Strip a leading `---`-fenced YAML frontmatter block, returning the body
40
+ * (the five-question lint takes the body; the frontmatter lint takes the
41
+ * full doc). Returns the input unchanged when there is no closing fence —
42
+ * an unparseable block is treated as body rather than destroyed. Canonical
43
+ * helper shared by the CLI, drift-lint Guard 5 and the engine corpus test. */
44
+ export declare function stripFrontmatter(text: string): string;
45
+ /** Lint mode: `authoring` (canonical headings only — greenfield / strict)
46
+ * or `runtime` (canonical plus the locked `RUNTIME_HEADING_ALIASES` table
47
+ * — shipped `mstar-*` topic skills). */
48
+ export type FiveQuestionMode = "authoring" | "runtime";
49
+ /**
50
+ * Locked runtime alias table (plan 20260816-audit-001-five-question-runtime-
51
+ * alignment, Step 2): heading synonyms that answer the same question for
52
+ * shipped topic skills, verified against the corpus at `81480e7`. Tokens are
53
+ * case-insensitive heading substrings (any heading level); the `decision-rules`
54
+ * breadth is bounded by the corpus regression test pinning current state.
55
+ * `load-order` has no aliases — the canonical label covers 15/16 skills and
56
+ * `mstar-host` closes its gap with a corpus edit instead. Chinese tokens are
57
+ * `\uXXXX` escapes (ASCII-only src literals; runtime value is identical).
58
+ */
59
+ export declare const RUNTIME_HEADING_ALIASES: Readonly<Record<string, readonly string[]>>;
39
60
  /**
40
61
  * Lint a SKILL.md body for the 5-question contract (mstar-skill-authoring
41
62
  * § Body 必须回答的 5 问). Heuristic: each of the five questions must be
42
63
  * answered by the presence of its canonical section heading (case-
43
64
  * insensitive substring match on heading text, any heading level — so
44
65
  * "## Load Order (Required)" and "### Workflow — main path" both match).
45
- * Content judgment (whether the answer is actually narrow / procedural)
46
- * stays prompt. Advisory: violations are `low` severity (v1 non-blocking).
66
+ * `mode: "runtime"` additionally accepts the locked `RUNTIME_HEADING_ALIASES`
67
+ * synonyms for shipped topic skills; `authoring` (default) stays canonical-
68
+ * only — greenfield skills still must use the canonical headings. Content
69
+ * judgment (whether the answer is actually narrow / procedural) stays prompt.
70
+ * Advisory: violations are `low` severity (v1 non-blocking).
47
71
  *
48
72
  * Violations: `skill-authoring.five-question.<key>` for each uncovered
49
73
  * question.
50
74
  */
51
- export declare function lintFiveQuestion(bodyText: string): GateResult;
75
+ export declare function lintFiveQuestion(bodyText: string, mode?: FiveQuestionMode): GateResult;
52
76
  /**
53
77
  * Resolve a skill-relative asset path (mstar-skill-authoring § Skill-
54
78
  * relative script and asset paths: name assets as skill `<name>` →
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/engine",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "Morning Star Harness Workflow Engine — deterministic workflow enforcement library (path, status, lease, dispatch, sdd, iteration, lint gates).",
5
5
  "license": "MIT",
6
6
  "repository": {