@rsaglobaltech/specgate 0.8.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/README.md +17 -25
  3. package/bin/specgate.ts +23 -5
  4. package/dist/bin/specgate.js +19 -4
  5. package/dist/bin/specgate.js.map +1 -1
  6. package/dist/packages/core/src/application/GenerateAgentPromptUseCase.js +56 -0
  7. package/dist/packages/core/src/application/GenerateAgentPromptUseCase.js.map +1 -1
  8. package/dist/packages/core/src/application/ValidateProjectUseCase.js +54 -0
  9. package/dist/packages/core/src/application/ValidateProjectUseCase.js.map +1 -1
  10. package/dist/packages/core/src/domain/AdversarialProbe.js +75 -0
  11. package/dist/packages/core/src/domain/AdversarialProbe.js.map +1 -0
  12. package/dist/packages/core/src/domain/AgentPrompt.js +52 -3
  13. package/dist/packages/core/src/domain/AgentPrompt.js.map +1 -1
  14. package/dist/packages/core/src/domain/DeclaredArtifacts.js +25 -0
  15. package/dist/packages/core/src/domain/DeclaredArtifacts.js.map +1 -1
  16. package/dist/packages/core/src/domain/DoneVerification.js +89 -0
  17. package/dist/packages/core/src/domain/DoneVerification.js.map +1 -0
  18. package/dist/packages/core/src/domain/GateCommandIntegrity.js +139 -0
  19. package/dist/packages/core/src/domain/GateCommandIntegrity.js.map +1 -0
  20. package/dist/packages/core/src/domain/GherkinQuality.js +19 -3
  21. package/dist/packages/core/src/domain/GherkinQuality.js.map +1 -1
  22. package/dist/packages/core/src/domain/HarnessConfig.js +6 -0
  23. package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
  24. package/dist/packages/core/src/domain/MultiStack.js +96 -0
  25. package/dist/packages/core/src/domain/MultiStack.js.map +1 -0
  26. package/dist/packages/core/src/domain/NewRequirement.js +46 -0
  27. package/dist/packages/core/src/domain/NewRequirement.js.map +1 -0
  28. package/dist/packages/core/src/domain/Precedents.js +96 -0
  29. package/dist/packages/core/src/domain/Precedents.js.map +1 -0
  30. package/dist/packages/core/src/domain/RequirementPlan.js +1 -0
  31. package/dist/packages/core/src/domain/RequirementPlan.js.map +1 -1
  32. package/dist/packages/core/src/domain/RequirementRemoval.js +161 -0
  33. package/dist/packages/core/src/domain/RequirementRemoval.js.map +1 -0
  34. package/dist/packages/core/src/domain/ScenarioCoverage.js +178 -0
  35. package/dist/packages/core/src/domain/ScenarioCoverage.js.map +1 -0
  36. package/dist/packages/core/src/domain/SpecSections.js +206 -0
  37. package/dist/packages/core/src/domain/SpecSections.js.map +1 -0
  38. package/dist/packages/core/src/domain/TestCommand.js +82 -0
  39. package/dist/packages/core/src/domain/TestCommand.js.map +1 -0
  40. package/dist/packages/core/src/domain/TraceabilityFormat.js +45 -2
  41. package/dist/packages/core/src/domain/TraceabilityFormat.js.map +1 -1
  42. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +31 -0
  43. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
  44. package/dist/packages/core/test/unit/adversarial-probe.test.js +81 -0
  45. package/dist/packages/core/test/unit/adversarial-probe.test.js.map +1 -0
  46. package/dist/packages/core/test/unit/done-verification.test.js +84 -0
  47. package/dist/packages/core/test/unit/done-verification.test.js.map +1 -0
  48. package/dist/packages/core/test/unit/gate-command-integrity.test.js +114 -0
  49. package/dist/packages/core/test/unit/gate-command-integrity.test.js.map +1 -0
  50. package/dist/packages/core/test/unit/gherkin-quality.test.js +28 -0
  51. package/dist/packages/core/test/unit/gherkin-quality.test.js.map +1 -1
  52. package/dist/packages/core/test/unit/multi-stack.test.js +86 -0
  53. package/dist/packages/core/test/unit/multi-stack.test.js.map +1 -0
  54. package/dist/packages/core/test/unit/new-requirement.test.js +67 -0
  55. package/dist/packages/core/test/unit/new-requirement.test.js.map +1 -0
  56. package/dist/packages/core/test/unit/precedents.test.js +99 -0
  57. package/dist/packages/core/test/unit/precedents.test.js.map +1 -0
  58. package/dist/packages/core/test/unit/requirement-removal.test.js +124 -0
  59. package/dist/packages/core/test/unit/requirement-removal.test.js.map +1 -0
  60. package/dist/packages/core/test/unit/scenario-coverage.test.js +146 -0
  61. package/dist/packages/core/test/unit/scenario-coverage.test.js.map +1 -0
  62. package/dist/packages/core/test/unit/spec-sections.test.js +146 -0
  63. package/dist/packages/core/test/unit/spec-sections.test.js.map +1 -0
  64. package/dist/packages/core/test/unit/test-command.test.js +81 -0
  65. package/dist/packages/core/test/unit/test-command.test.js.map +1 -0
  66. package/dist/packages/core/test/unit/validate-project.test.js +21 -0
  67. package/dist/packages/core/test/unit/validate-project.test.js.map +1 -1
  68. package/dist/scripts/agents/commands.js +1 -1
  69. package/dist/scripts/agents/commands.js.map +1 -1
  70. package/dist/scripts/agents/init.js +59 -15
  71. package/dist/scripts/agents/init.js.map +1 -1
  72. package/dist/scripts/change/instructions.js +2 -2
  73. package/dist/scripts/change/instructions.js.map +1 -1
  74. package/dist/scripts/check.js +10 -0
  75. package/dist/scripts/check.js.map +1 -0
  76. package/dist/scripts/cli/commands/change/ChangeCommand.js +2 -2
  77. package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
  78. package/dist/scripts/cli/commands/config/CiInitCommand.js +1 -1
  79. package/dist/scripts/cli/commands/config/CiInitCommand.js.map +1 -1
  80. package/dist/scripts/cli/commands/harness/RunCommand.js +214 -9
  81. package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
  82. package/dist/scripts/cli/commands/pack/InferPackCommand.js +331 -31
  83. package/dist/scripts/cli/commands/pack/InferPackCommand.js.map +1 -1
  84. package/dist/scripts/cli/commands/project/AdoptCommand.js +86 -9
  85. package/dist/scripts/cli/commands/project/AdoptCommand.js.map +1 -1
  86. package/dist/scripts/cli/commands/project/InitProjectCommand.js +286 -45
  87. package/dist/scripts/cli/commands/project/InitProjectCommand.js.map +1 -1
  88. package/dist/scripts/cli/commands/project/UpdateCommand.js +118 -8
  89. package/dist/scripts/cli/commands/project/UpdateCommand.js.map +1 -1
  90. package/dist/scripts/cli/commands/quality/CheckCommand.js +184 -0
  91. package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -0
  92. package/dist/scripts/cli/commands/quality/DoctorCommand.js +20 -2
  93. package/dist/scripts/cli/commands/quality/DoctorCommand.js.map +1 -1
  94. package/dist/scripts/cli/commands/quality/FixCommand.js +1 -1
  95. package/dist/scripts/cli/commands/quality/FixCommand.js.map +1 -1
  96. package/dist/scripts/cli/commands/quality/ReportCommand.js +1 -1
  97. package/dist/scripts/cli/commands/quality/ReportCommand.js.map +1 -1
  98. package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js +406 -24
  99. package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js.map +1 -1
  100. package/dist/scripts/cli/commands/spec/DoneCommand.js +108 -0
  101. package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
  102. package/dist/scripts/cli/commands/spec/NewCommand.js +178 -0
  103. package/dist/scripts/cli/commands/spec/NewCommand.js.map +1 -0
  104. package/dist/scripts/cli/commands/spec/PlanCommand.js +8 -2
  105. package/dist/scripts/cli/commands/spec/PlanCommand.js.map +1 -1
  106. package/dist/scripts/cli/commands/spec/ReqCommand.js +124 -4
  107. package/dist/scripts/cli/commands/spec/ReqCommand.js.map +1 -1
  108. package/dist/scripts/cli/commands/spec/StatusCommand.js +84 -32
  109. package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
  110. package/dist/scripts/docs/build-site.js +145 -35
  111. package/dist/scripts/docs/build-site.js.map +1 -1
  112. package/dist/scripts/docs/components.js +208 -0
  113. package/dist/scripts/docs/components.js.map +1 -0
  114. package/dist/scripts/docs/highlight.js +180 -0
  115. package/dist/scripts/docs/highlight.js.map +1 -0
  116. package/dist/scripts/docs/icons.js +63 -0
  117. package/dist/scripts/docs/icons.js.map +1 -0
  118. package/dist/scripts/docs/nav.js +9 -3
  119. package/dist/scripts/docs/nav.js.map +1 -1
  120. package/dist/scripts/gen_mcp_tools.js +22 -2
  121. package/dist/scripts/gen_mcp_tools.js.map +1 -1
  122. package/dist/scripts/harness/init.js +101 -40
  123. package/dist/scripts/harness/init.js.map +1 -1
  124. package/dist/scripts/harness/worktree-lock.js +161 -0
  125. package/dist/scripts/harness/worktree-lock.js.map +1 -0
  126. package/dist/scripts/infer_pack.js +4 -1
  127. package/dist/scripts/infer_pack.js.map +1 -1
  128. package/dist/scripts/lib/surface.js +88 -38
  129. package/dist/scripts/lib/surface.js.map +1 -1
  130. package/dist/scripts/new.js +10 -0
  131. package/dist/scripts/new.js.map +1 -0
  132. package/dist/scripts/plugin/gate-hook.js +2 -2
  133. package/dist/scripts/plugin/gate-hook.js.map +1 -1
  134. package/package.json +5 -2
  135. package/templates/adopt/AI_RULES.md.tpl +1 -1
  136. package/templates/adopt/spec.md.tpl +4 -4
  137. package/templates/base/spec.md.tpl +12 -0
  138. package/templates/ci/azure.yml.tpl +2 -2
  139. package/templates/ci/github.yml.tpl +2 -2
  140. package/templates/ci/gitlab.yml.tpl +1 -1
  141. package/templates/ci/jenkins.tpl +1 -1
  142. package/templates/contracts/test-strategy.md.tpl +2 -2
  143. package/templates/harness/harness.config.yaml.tpl +3 -3
  144. package/templates/harness/prompt-prefix.md.tpl +2 -5
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ /**
3
+ * Build-time syntax highlighting.
4
+ *
5
+ * ## Why not a library
6
+ *
7
+ * Prism and Shiki both do this better than 150 lines can. They would also be a
8
+ * new dependency in a repository that ships an SBOM, runs a licence allow-list
9
+ * over it (`npm run licences`) and puts "0 runtime dependencies" on its own
10
+ * landing page. The cost of a highlighter is not the download — it is that
11
+ * every future audit has to account for it.
12
+ *
13
+ * So: a deliberately conservative tokeniser. It knows strings, comments,
14
+ * numbers and a keyword list per language, and nothing else. It will not
15
+ * colour a nested template literal correctly and does not try.
16
+ *
17
+ * ## Why it cannot break a page
18
+ *
19
+ * The scanner only ever *wraps* text it has already escaped, and any input it
20
+ * does not recognise falls through as escaped literal. A language with no rules
21
+ * returns the same escaped source the old renderer produced, so an unknown
22
+ * fence is a plain block rather than a broken one.
23
+ *
24
+ * ## Why build time
25
+ *
26
+ * Highlighting in the browser means shipping a parser to every reader and
27
+ * repainting after first paint. These are static documents; the colours can be
28
+ * baked in and cost nothing at runtime.
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.HIGHLIGHTED = void 0;
32
+ exports.escapeHtml = escapeHtml;
33
+ exports.highlight = highlight;
34
+ function escapeHtml(value) {
35
+ return value
36
+ .replace(/&/g, "&")
37
+ .replace(/</g, "&lt;")
38
+ .replace(/>/g, "&gt;")
39
+ .replace(/"/g, "&quot;");
40
+ }
41
+ /** Shared shapes. Order matters: whatever matches first at a position wins. */
42
+ const STRING = String.raw `"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|\`(?:[^\`\\]|\\.)*\``;
43
+ const NUMBER = String.raw `\b\d+(?:\.\d+)?\b`;
44
+ function keywords(...words) {
45
+ return String.raw `\b(?:${words.join("|")})\b`;
46
+ }
47
+ const LANGS = {
48
+ bash: [
49
+ { cls: "c", re: String.raw `#[^\n]*` },
50
+ { cls: "s", re: STRING },
51
+ { cls: "v", re: String.raw `\$\{?[A-Za-z_][\w]*\}?` },
52
+ {
53
+ cls: "k",
54
+ re: keywords("if", "then", "else", "fi", "for", "in", "do", "done", "while", "case", "esac", "function", "return", "export", "local", "set", "cd", "echo", "exit"),
55
+ },
56
+ { cls: "f", re: String.raw `(?<=^|\||&&|;|\n)\s*[a-z][\w-]*` },
57
+ // Anchored to whitespace: without it `your-existing-repo` reads as the
58
+ // flag `-existing-repo` and half the word turns blue.
59
+ { cls: "o", re: String.raw `(?<=^|\s)--?[A-Za-z][\w-]*` },
60
+ { cls: "n", re: NUMBER },
61
+ ],
62
+ json: [
63
+ { cls: "a", re: String.raw `"(?:[^"\\]|\\.)*"(?=\s*:)` },
64
+ { cls: "s", re: String.raw `"(?:[^"\\]|\\.)*"` },
65
+ { cls: "k", re: keywords("true", "false", "null") },
66
+ { cls: "n", re: NUMBER },
67
+ ],
68
+ yaml: [
69
+ { cls: "c", re: String.raw `#[^\n]*` },
70
+ { cls: "a", re: String.raw `(?<=^|\n)\s*[-\w.]+(?=\s*:)` },
71
+ { cls: "s", re: STRING },
72
+ { cls: "k", re: keywords("true", "false", "null", "yes", "no", "on", "off") },
73
+ { cls: "n", re: NUMBER },
74
+ ],
75
+ ts: [
76
+ { cls: "c", re: String.raw `//[^\n]*|/\*[\s\S]*?\*/` },
77
+ { cls: "s", re: STRING },
78
+ {
79
+ cls: "k",
80
+ re: keywords("import", "export", "from", "const", "let", "var", "function", "return", "if", "else", "for", "of", "while", "class", "extends", "implements", "interface", "type", "new", "await", "async", "try", "catch", "finally", "throw", "typeof", "instanceof", "readonly", "public", "private", "static", "true", "false", "null", "undefined", "this"),
81
+ },
82
+ { cls: "n", re: NUMBER },
83
+ ],
84
+ java: [
85
+ { cls: "c", re: String.raw `//[^\n]*|/\*[\s\S]*?\*/` },
86
+ { cls: "s", re: STRING },
87
+ { cls: "an", re: String.raw `@[A-Za-z]\w*` },
88
+ {
89
+ cls: "k",
90
+ re: keywords("package", "import", "public", "private", "protected", "class", "interface", "extends", "implements", "static", "final", "void", "new", "return", "if", "else", "for", "while", "try", "catch", "throws", "record", "var", "true", "false", "null"),
91
+ },
92
+ { cls: "n", re: NUMBER },
93
+ ],
94
+ xml: [
95
+ { cls: "c", re: String.raw `<!--[\s\S]*?-->` },
96
+ { cls: "s", re: String.raw `"(?:[^"\\]|\\.)*"` },
97
+ { cls: "t", re: String.raw `</?[A-Za-z][\w:.-]*|/?>` },
98
+ ],
99
+ gherkin: [
100
+ { cls: "c", re: String.raw `#[^\n]*` },
101
+ {
102
+ cls: "k",
103
+ re: String.raw `(?<=^|\n)\s*(?:Feature|Background|Scenario Outline|Scenario|Examples|Rule)(?=:)`,
104
+ },
105
+ { cls: "g", re: String.raw `(?<=^|\n)\s*(?:Given|When|Then|And|But)\b` },
106
+ { cls: "an", re: String.raw `@[\w-]+` },
107
+ { cls: "s", re: String.raw `<[^>\n]+>` },
108
+ ],
109
+ groovy: [
110
+ { cls: "c", re: String.raw `//[^\n]*|/\*[\s\S]*?\*/` },
111
+ { cls: "s", re: STRING },
112
+ {
113
+ cls: "k",
114
+ re: keywords("pipeline", "agent", "stages", "stage", "steps", "sh", "def", "if", "else", "return", "docker", "image", "any", "true", "false", "null"),
115
+ },
116
+ { cls: "n", re: NUMBER },
117
+ ],
118
+ };
119
+ /** Fences whose language is really another one. */
120
+ const ALIASES = {
121
+ sh: "bash",
122
+ shell: "bash",
123
+ console: "bash",
124
+ javascript: "ts",
125
+ js: "ts",
126
+ typescript: "ts",
127
+ jsonc: "json",
128
+ yml: "yaml",
129
+ html: "xml",
130
+ svg: "xml",
131
+ feature: "gherkin",
132
+ kotlin: "java",
133
+ kts: "java",
134
+ groovy: "groovy",
135
+ jenkinsfile: "groovy",
136
+ };
137
+ const compiled = new Map();
138
+ function scanner(lang) {
139
+ if (compiled.has(lang))
140
+ return compiled.get(lang);
141
+ const rules = LANGS[lang];
142
+ if (!rules)
143
+ return null;
144
+ // One alternation, groups in rule order, so priority is positional.
145
+ const re = new RegExp(rules.map((r) => `(${r.re})`).join("|"), "gm");
146
+ compiled.set(lang, re);
147
+ return re;
148
+ }
149
+ /**
150
+ * Escaped HTML for one code block, with `<span class="tok tok--X">` wrappers.
151
+ *
152
+ * Returns plain escaped text when the language is unknown, which is the same
153
+ * output the site produced before highlighting existed.
154
+ */
155
+ function highlight(code, language) {
156
+ const lang = ALIASES[language.toLowerCase()] || language.toLowerCase();
157
+ const rules = LANGS[lang];
158
+ const re = scanner(lang);
159
+ if (!rules || !re)
160
+ return escapeHtml(code);
161
+ let out = "";
162
+ let last = 0;
163
+ re.lastIndex = 0;
164
+ for (let m = re.exec(code); m !== null; m = re.exec(code)) {
165
+ // A zero-width match would spin forever; step past it.
166
+ if (m[0] === "") {
167
+ re.lastIndex += 1;
168
+ continue;
169
+ }
170
+ out += escapeHtml(code.slice(last, m.index));
171
+ const which = m.slice(1).findIndex((g) => g !== undefined);
172
+ const cls = which === -1 ? "" : rules[which].cls;
173
+ out += cls ? `<span class="tok tok--${cls}">${escapeHtml(m[0])}</span>` : escapeHtml(m[0]);
174
+ last = m.index + m[0].length;
175
+ }
176
+ return out + escapeHtml(code.slice(last));
177
+ }
178
+ /** Languages that actually get colour, for the tests and for documentation. */
179
+ exports.HIGHLIGHTED = Object.keys(LANGS);
180
+ //# sourceMappingURL=highlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlight.js","sourceRoot":"","sources":["../../../scripts/docs/highlight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * The icon set the site draws from.
4
+ *
5
+ * Inline SVG rather than an icon font or sprite sheet, for two reasons that
6
+ * both come from how this site is built: there is no bundler to subset a font
7
+ * with, and every colour on the page is a `var(--…)` token so the theme toggle
8
+ * works — `stroke="currentColor"` inherits that for free, a font glyph or a
9
+ * remote `<img>` would not.
10
+ *
11
+ * Twenty-four by twenty-four, 1.5 stroke, no fills. Keep them geometric: these
12
+ * sit at 16-20px in a sidebar and anything fussier turns to mud.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ICON_NAMES = void 0;
16
+ exports.icon = icon;
17
+ exports.hasIcon = hasIcon;
18
+ const ICONS = {
19
+ // Start here — a flag planted at the beginning.
20
+ rocket: '<path d="M12 3c3 2 5 5.5 5 9l-5 4-5-4c0-3.5 2-7 5-9Z"/><circle cx="12" cy="10" r="1.6"/><path d="M9 17l-2 4 4-2M15 17l2 4-4-2"/>',
21
+ // Writing specs — a document with lines.
22
+ file: '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8Z"/><path d="M14 3v5h5M9 13h6M9 17h4"/>',
23
+ // Agents — a small machine with an eye.
24
+ robot: '<rect x="4" y="8" width="16" height="12" rx="2"/><path d="M12 8V4M8 4h8"/><circle cx="9" cy="13" r="1"/><circle cx="15" cy="13" r="1"/><path d="M9 17h6"/>',
25
+ // Running it for real — a stack of servers.
26
+ server: '<rect x="3" y="4" width="18" height="6" rx="1.5"/><rect x="3" y="14" width="18" height="6" rx="1.5"/><path d="M7 7h.01M7 17h.01"/>',
27
+ // Reference — a book.
28
+ book: '<path d="M4 5.5A2.5 2.5 0 0 1 6.5 3H20v15H6.5A2.5 2.5 0 0 0 4 20.5Z"/><path d="M4 5.5v15"/>',
29
+ // Background — a compass, for reading around the subject.
30
+ compass: '<circle cx="12" cy="12" r="9"/><path d="m15.5 8.5-2 5-5 2 2-5Z"/>',
31
+ // The gate itself.
32
+ shield: '<path d="M12 3l7 3v6c0 4-3 7.5-7 9-4-1.5-7-5-7-9V6Z"/><path d="m9 12 2 2 4-4"/>',
33
+ terminal: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="m7 9 3 3-3 3M13 15h4"/>',
34
+ play: '<circle cx="12" cy="12" r="9"/><path d="m10 8.5 6 3.5-6 3.5Z"/>',
35
+ package: '<path d="M21 8v8l-9 5-9-5V8l9-5Z"/><path d="m3 8 9 5 9-5M12 13v8"/>',
36
+ code: '<path d="m8 6-5 6 5 6M16 6l5 6-5 6"/>',
37
+ link: '<path d="M10 13a5 5 0 0 0 7 0l2-2a5 5 0 0 0-7-7l-1 1"/><path d="M14 11a5 5 0 0 0-7 0l-2 2a5 5 0 0 0 7 7l1-1"/>',
38
+ search: '<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',
39
+ spark: '<path d="M12 3v4M12 17v4M3 12h4M17 12h4M6 6l2.5 2.5M15.5 15.5 18 18M18 6l-2.5 2.5M8.5 15.5 6 18"/>',
40
+ check: '<circle cx="12" cy="12" r="9"/><path d="m8 12 3 3 5-6"/>',
41
+ arrow: '<path d="M5 12h14M13 6l6 6-6 6"/>',
42
+ };
43
+ /**
44
+ * One icon as inline SVG, or the empty string when the name is unknown.
45
+ *
46
+ * Unknown names return empty rather than throwing: an icon is decoration, and
47
+ * a missing one should not take the build down the way a missing diagram does.
48
+ * `aria-hidden` because every icon here sits beside its own text label.
49
+ */
50
+ function icon(name, cls = "icon") {
51
+ if (!name)
52
+ return "";
53
+ const body = ICONS[name];
54
+ if (!body)
55
+ return "";
56
+ return (`<svg class="${cls}" viewBox="0 0 24 24" fill="none" stroke="currentColor" ` +
57
+ `stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${body}</svg>`);
58
+ }
59
+ function hasIcon(name) {
60
+ return Boolean(name && ICONS[name]);
61
+ }
62
+ exports.ICON_NAMES = Object.keys(ICONS);
63
+ //# sourceMappingURL=icons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.js","sourceRoot":"","sources":["../../../scripts/docs/icons.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAuCH,oBAQC;AAED,0BAEC;AAjDD,MAAM,KAAK,GAA2B;IACpC,gDAAgD;IAChD,MAAM,EACJ,kIAAkI;IACpI,yCAAyC;IACzC,IAAI,EAAE,2GAA2G;IACjH,wCAAwC;IACxC,KAAK,EACH,4JAA4J;IAC9J,4CAA4C;IAC5C,MAAM,EACJ,oIAAoI;IACtI,sBAAsB;IACtB,IAAI,EAAE,6FAA6F;IACnG,0DAA0D;IAC1D,OAAO,EAAE,mEAAmE;IAC5E,mBAAmB;IACnB,MAAM,EAAE,iFAAiF;IACzF,QAAQ,EAAE,mFAAmF;IAC7F,IAAI,EAAE,iEAAiE;IACvE,OAAO,EAAE,qEAAqE;IAC9E,IAAI,EAAE,uCAAuC;IAC7C,IAAI,EAAE,gHAAgH;IACtH,MAAM,EAAE,2DAA2D;IACnE,KAAK,EACH,oGAAoG;IACtG,KAAK,EAAE,0DAA0D;IACjE,KAAK,EAAE,mCAAmC;CAC3C,CAAC;AAEF;;;;;;GAMG;AACH,SAAgB,IAAI,CAAC,IAAwB,EAAE,GAAG,GAAG,MAAM;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,CACL,eAAe,GAAG,0DAA0D;QAC5E,wFAAwF,IAAI,QAAQ,CACrG,CAAC;AACJ,CAAC;AAED,SAAgB,OAAO,CAAC,IAAwB;IAC9C,OAAO,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAEY,QAAA,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC"}
@@ -3,8 +3,8 @@
3
3
  * The shape of the documentation site, decided once.
4
4
  *
5
5
  * Ordered by the question a reader is asking, not alphabetically and not by
6
- * the order the files happened to be written. Someone who has just run `npx
7
- * create-spec-driven-app` needs a different page from someone deciding whether
6
+ * the order the files happened to be written. Someone who has just run
7
+ * `npx @rsaglobaltech/specgate` needs a different page from someone deciding whether
8
8
  * to adopt the tool at all, and the sidebar should make that obvious without
9
9
  * being read end to end.
10
10
  *
@@ -21,6 +21,7 @@ exports.neighbours = neighbours;
21
21
  exports.NAV = [
22
22
  {
23
23
  title: "Start here",
24
+ icon: "rocket",
24
25
  summary: "Fifteen minutes from nothing to a project whose specs are checked by CI.",
25
26
  entries: [
26
27
  {
@@ -47,6 +48,7 @@ exports.NAV = [
47
48
  },
48
49
  {
49
50
  title: "Working with specs",
51
+ icon: "file",
50
52
  summary: "What a specification is here, and what the tool does with it.",
51
53
  entries: [
52
54
  {
@@ -73,6 +75,7 @@ exports.NAV = [
73
75
  },
74
76
  {
75
77
  title: "Agents and the harness",
78
+ icon: "robot",
76
79
  summary: "The part that spends money. Read the harness page before pointing an agent at anything.",
77
80
  entries: [
78
81
  {
@@ -99,6 +102,7 @@ exports.NAV = [
99
102
  },
100
103
  {
101
104
  title: "Running it for real",
105
+ icon: "server",
102
106
  summary: "CI, boards, and the things an enterprise asks before it says yes.",
103
107
  entries: [
104
108
  {
@@ -114,7 +118,7 @@ exports.NAV = [
114
118
  {
115
119
  slug: "deployment",
116
120
  label: "Deployment",
117
- blurb: "Where the generated project expects to be deployed from.",
121
+ blurb: "How specgate's own docs site, npm package and container image are published.",
118
122
  },
119
123
  {
120
124
  slug: "supply-chain",
@@ -125,6 +129,7 @@ exports.NAV = [
125
129
  },
126
130
  {
127
131
  title: "Reference",
132
+ icon: "book",
128
133
  summary: "Look things up.",
129
134
  entries: [
130
135
  {
@@ -159,6 +164,7 @@ exports.NAV = [
159
164
  // documents that explain *why* the tool is shaped this way, which makes
160
165
  // them the wrong ones to leave unreachable.
161
166
  title: "Background",
167
+ icon: "compass",
162
168
  summary: "Why it works this way.",
163
169
  entries: [
164
170
  {
@@ -1 +1 @@
1
- {"version":3,"file":"nav.js","sourceRoot":"","sources":["../../../scripts/docs/nav.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nav.js","sourceRoot":"","sources":["../../../scripts/docs/nav.ts"],"names":[],"mappings":"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"}
@@ -72,6 +72,7 @@ import {
72
72
  ReadSpecTool,
73
73
  ListRequirementsTool,
74
74
  UpdateTraceabilityTool,
75
+ assertContractEditable,
75
76
  } from "./native-tools";
76
77
 
77
78
  export interface ITool {
@@ -147,11 +148,26 @@ export class GenericCliTool implements ITool {
147
148
  * "Unknown flag(s)" and an empty payload over MCP. The surface already
148
149
  * records which is which in \`json.args\`; this reads it instead of assuming.
149
150
  */
150
- public readonly dirStyle: "flag" | "positional" = "flag"
151
+ public readonly dirStyle: "flag" | "positional" = "flag",
152
+ /**
153
+ * True when this command may write a path the write-scope rules protect.
154
+ * Computed at generation time from scripts/lib/surface.ts and
155
+ * WriteScope.DEFAULT_PROTECTED_PATHS, so the rule has one definition.
156
+ */
157
+ public readonly editsContract = false
151
158
  ) {}
152
159
 
153
160
  public handler(args: Record<string, unknown>) {
154
161
  const dir = ProjectHelper.ensureProjectDir(args.projectDir);
162
+
163
+ // C10-04. The prompt has always told the agent not to rewrite the
164
+ // specification it is being measured against; nothing enforced it over MCP.
165
+ // An agent that cannot make a scenario pass can otherwise relax the
166
+ // scenario, and the gate approves — the exact failure this product exists
167
+ // to prevent. The change cycle is the way to edit a spec on purpose, and it
168
+ // leaves a reviewable trail.
169
+ if (this.editsContract) assertContractEditable(this.name, dir);
170
+
155
171
  const argv = this.csda.split(" ");
156
172
 
157
173
  if (this.dirStyle === "positional") argv.push(dir);
@@ -200,6 +216,9 @@ for (const command of surface_1.SURFACE) {
200
216
  // directory positionally rather than behind `--project-dir`.
201
217
  const jsonDef = subDef ? subDef.json : cmdDef.json;
202
218
  const dirStyle = jsonDef && jsonDef.args === "<dir>" ? "positional" : "flag";
219
+ // `change *` is how a specification is edited on purpose; refusing it would
220
+ // leave no way to open the change the guard asks for.
221
+ const editsContract = Boolean((subDef ? subDef.editsContract : cmdDef.editsContract) && cmdDef.name !== "change");
203
222
  out += `TOOLS["${toolName}"] = new GenericCliTool(
204
223
  "${toolName}",
205
224
  ${JSON.stringify(summary)},
@@ -212,7 +231,8 @@ for (const command of surface_1.SURFACE) {
212
231
  },
213
232
  required: ["projectDir"]
214
233
  },
215
- "${dirStyle}"
234
+ "${dirStyle}",
235
+ ${editsContract}
216
236
  );\n`;
217
237
  };
218
238
  if (command.subcommands) {
@@ -1 +1 @@
1
- {"version":3,"file":"gen_mcp_tools.js","sourceRoot":"","sources":["../../scripts/gen_mcp_tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gen_mcp_tools.js","sourceRoot":"","sources":["../../scripts/gen_mcp_tools.ts"],"names":[],"mappings":"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"}
@@ -59,6 +59,7 @@ const project_root_1 = require("../lib/project-root");
59
59
  const agent_1 = require("../lib/agent");
60
60
  const diagnostics_1 = require("../lib/diagnostics");
61
61
  const command_1 = require("../lib/command");
62
+ const TestCommand_1 = require("../../packages/core/src/domain/TestCommand");
62
63
  const ROOT_DIR = path.resolve(__dirname, "..", "..", "..");
63
64
  const TEMPLATES = path.join(ROOT_DIR, "templates", "harness");
64
65
  const CONFIG_FILE = "harness.config.yaml";
@@ -69,7 +70,7 @@ const NULL_SHAPE = { projectDir: null, files: [] };
69
70
  * or `null` when nothing gives it away.
70
71
  *
71
72
  * `null` matters more than the guesses. `test_cmd` is an *additional* gate —
72
- * `harness run` always runs `validate --strict-tdd` first — so leaving it
73
+ * `harness run` always runs `validate --strict` first — so leaving it
73
74
  * unset is safe, while filling it with a placeholder is not. A placeholder
74
75
  * like `echo "set this"` exits 0, which is a gate that passes unconditionally:
75
76
  * the harness would mark requirements done without ever running a test. A
@@ -77,36 +78,21 @@ const NULL_SHAPE = { projectDir: null, files: [] };
77
78
  * exists, so this is the common case, not the edge one.
78
79
  */
79
80
  function detectTestCommand(projectDir) {
80
- const has = (file) => fs.existsSync(path.join(projectDir, file));
81
- if (has("package.json")) {
82
- try {
83
- const pkg = JSON.parse(fs.readFileSync(path.join(projectDir, "package.json"), "utf8"));
84
- const scripts = pkg.scripts || {};
85
- // `verify` is this project's own convention for "the fast gate";
86
- // prefer it, because `test` in a spec-driven repo often includes the
87
- // end-to-end suite that stays red until the last requirement lands.
88
- if (scripts.verify)
89
- return "npm run verify";
90
- if (scripts.test)
91
- return "npm test";
92
- }
93
- catch {
94
- // A malformed package.json is the user's problem, not a reason to fail
95
- // scaffolding. Fall through to the generic guess.
96
- }
97
- return "npm test";
98
- }
99
- if (has("pom.xml"))
100
- return "mvn -B test";
101
- if (has("build.gradle") || has("build.gradle.kts"))
102
- return "./gradlew test";
103
- if (has("Cargo.toml"))
104
- return "cargo test";
105
- if (has("go.mod"))
106
- return "go test ./...";
107
- if (has("pyproject.toml") || has("setup.py"))
108
- return "pytest";
109
- return null;
81
+ // One detector, shared with `adopt`/`onboard`. They used to disagree on the
82
+ // same pom.xml — `./mvnw -B test` there, `mvn -B test` here — which a cold
83
+ // evaluator found by running both. `preferVerify` is the one intentional
84
+ // difference, and it is an argument so that it stays intentional.
85
+ return (0, TestCommand_1.detectTestCommand)({
86
+ exists: (rel) => fs.existsSync(path.join(projectDir, rel)),
87
+ read: (rel) => {
88
+ try {
89
+ return fs.readFileSync(path.join(projectDir, rel), "utf8");
90
+ }
91
+ catch {
92
+ return null;
93
+ }
94
+ },
95
+ }, { preferVerify: true });
110
96
  }
111
97
  function projectName(projectDir) {
112
98
  const specPath = path.join(projectDir, "spec.md");
@@ -192,14 +178,40 @@ class InitCommand extends command_1.BaseCommand {
192
178
  // Rendered into the config as a live key when known, and as a commented-out
193
179
  // one when not — see detectTestCommand for why a placeholder would be worse
194
180
  // than an absent key.
181
+ // Shared with `doctor`, which used to call a Gherkin quality check
182
+ // "every scenario runnable" in projects where nothing runs one.
183
+ const hasGherkinRunner = (0, TestCommand_1.hasGherkinRunner)({
184
+ exists: (rel) => fs.existsSync(path.join(projectDir, rel)),
185
+ read: (rel) => {
186
+ try {
187
+ return fs.readFileSync(path.join(projectDir, rel), "utf8");
188
+ }
189
+ catch {
190
+ return null;
191
+ }
192
+ },
193
+ });
195
194
  const vars = {
196
195
  PROJECT_NAME: projectName(projectDir),
196
+ STEP_DEFS_LINE: hasGherkinRunner
197
+ ? "- `features/step_definitions/**` and `features/support/**` — step definitions\n" +
198
+ " are code, not specification. This is the one place inside `features/` you\n" +
199
+ " own."
200
+ : "\nThis project has no Gherkin runner, so nothing executes a `.feature` here.\n" +
201
+ "The scenarios are the specification and your tests are the proof: make the\n" +
202
+ "test named in the matrix assert what the scenario says, in the project's own\n" +
203
+ "test framework. Do not add a BDD runner to satisfy this prompt.",
204
+ SCENARIO_STEP: hasGherkinRunner
205
+ ? "2. Write or extend the step definitions so the scenario fails **for the right\n" +
206
+ " reason** — a missing implementation, not a typo in a step."
207
+ : "2. Write the test named in the traceability matrix so it fails **for the right\n" +
208
+ " reason** — a missing implementation, not a typo in the test.",
197
209
  TEST_CMD_LINE: testCmd
198
210
  ? `test_cmd: "${testCmd}"`
199
211
  : '# test_cmd: "npm test" # ← set this once the project has a test command',
200
212
  GATE_COMMAND: testCmd
201
- ? `${testCmd}\nspecgate validate . --strict-tdd`
202
- : "specgate validate . --strict-tdd",
213
+ ? `${testCmd}\nspecgate validate . --strict`
214
+ : "specgate validate . --strict",
203
215
  };
204
216
  const outputs = [
205
217
  {
@@ -258,7 +270,7 @@ class InitCommand extends command_1.BaseCommand {
258
270
  if (!testCmd) {
259
271
  status.push((0, diagnostics_1.warning)("harness_test_cmd_unset", "No test command detected, so `test_cmd` is commented out.", {
260
272
  target: CONFIG_FILE,
261
- fix: "Set it once the project has one. Until then the gate is `validate --strict-tdd` alone, which is a real gate — a placeholder that exits 0 would not be.",
273
+ fix: "Set it once the project has one. Until then the gate is `validate . --strict` alone, which is a real gate — a placeholder that exits 0 would not be.",
262
274
  }));
263
275
  }
264
276
  io.emit({
@@ -269,8 +281,18 @@ class InitCommand extends command_1.BaseCommand {
269
281
  }, () => {
270
282
  for (const file of written)
271
283
  process.stdout.write(`ℹ️ [INFO] write ${file}\n`);
284
+ // Warnings only reached `--json` before, so a text-mode user learned
285
+ // that a tracked file had changed from `git status` instead of from the
286
+ // command that changed it.
287
+ for (const d of status) {
288
+ if (d.severity !== "warning")
289
+ continue;
290
+ process.stderr.write(`⚠️ [WARN] ${d.message}\n`);
291
+ if (d.fix)
292
+ process.stderr.write(`💡 [FIX] ${d.fix}\n`);
293
+ }
272
294
  process.stdout.write("ℹ️ [INFO] ✅ Harness configured.\n" +
273
- `ℹ️ [INFO] gate: validate --strict-tdd${testCmd ? ` + ${testCmd}` : " (no test command detected)"}\n` +
295
+ `ℹ️ [INFO] gate: validate . --strict${testCmd ? ` + ${testCmd}` : " (no test command detected)"}\n` +
274
296
  "ℹ️ [INFO] agent: not set — that is your choice and your credentials.\n" +
275
297
  "ℹ️ [INFO] Next:\n" +
276
298
  "ℹ️ [INFO] 1. Read .harness/prompt-prefix.md and make it sound like your team.\n" +
@@ -311,16 +333,36 @@ exports.GITATTRIBUTES_LINE = `docs/specs/traceability.md merge=${exports.MERGE_D
311
333
  function installMergeDriver(projectDir) {
312
334
  const attributesPath = path.join(projectDir, ".gitattributes");
313
335
  const existing = fs.existsSync(attributesPath) ? fs.readFileSync(attributesPath, "utf8") : "";
336
+ let appendedToTracked = false;
314
337
  if (!existing.includes(exports.GITATTRIBUTES_LINE)) {
338
+ // `.gitattributes` is committed, so appending to it changes a file the
339
+ // whole team shares. A cold evaluator found this the way you always find a
340
+ // silent write — in `git status`, after the fact — so the command says it.
341
+ appendedToTracked = existing !== "";
315
342
  const separator = existing === "" || existing.endsWith("\n") ? "" : "\n";
316
343
  fs.appendFileSync(attributesPath, `${separator}# Merge the traceability matrix row by row, so parallel harness\n` +
317
344
  `# branches do not collide on adjacent rows. Needs the driver registered:\n` +
318
345
  `# specgate harness init --project-dir .\n` +
319
346
  `${exports.GITATTRIBUTES_LINE}\n`, "utf8");
320
347
  }
321
- // The driver runs from the installed CLI, so the path is resolved here rather
322
- // than assumed: a project does not have specgate in its own tree.
323
- const driverScript = path.join(__dirname, "..", "merge-traceability.js");
348
+ // How the driver is addressed decides whether it works on anybody else's
349
+ // clone.
350
+ //
351
+ // It used to be `node "/Users/someone/.../merge-traceability.js"` — the path
352
+ // of whichever checkout ran `harness init` — while `.gitattributes` said
353
+ // `merge=csda-matrix` and was committed. A cold evaluator found the pair: a
354
+ // shared rule pointing at a directory that exists on one laptop.
355
+ //
356
+ // A project that has specgate in its own `node_modules` can be addressed
357
+ // relatively, which every clone reproduces when it installs. Otherwise the
358
+ // running CLI's own path is the only thing that works here and now — and
359
+ // then the command says out loud that it is local, rather than leaving the
360
+ // next person to find out during a merge.
361
+ const localBin = path.join(projectDir, "node_modules", "@rsaglobaltech", "specgate", "bin", "specgate.js");
362
+ const driverIsPortable = fs.existsSync(localBin);
363
+ const driverCommand = driverIsPortable
364
+ ? `node node_modules/@rsaglobaltech/specgate/bin/specgate.js merge-traceability`
365
+ : `node ${JSON.stringify(path.join(__dirname, "..", "merge-traceability.js"))}`;
324
366
  const gitConfig = (key, value) => (0, node_child_process_1.spawnSync)("git", ["-C", projectDir, "config", key, value], { encoding: "utf8" });
325
367
  // Order matters, and getting it wrong is worse than not doing it at all.
326
368
  //
@@ -337,7 +379,7 @@ function installMergeDriver(projectDir) {
337
379
  //
338
380
  // So `driver` goes in first and `name` only follows if it landed; and if it
339
381
  // did not, any stale `name` is removed rather than left pointing at nothing.
340
- const configured = gitConfig(`merge.${exports.MERGE_DRIVER_NAME}.driver`, `node ${JSON.stringify(driverScript)} %O %A %B`);
382
+ const configured = gitConfig(`merge.${exports.MERGE_DRIVER_NAME}.driver`, `${driverCommand} %O %A %B`);
341
383
  if (configured.status !== 0) {
342
384
  (0, node_child_process_1.spawnSync)("git", ["-C", projectDir, "config", "--unset", `merge.${exports.MERGE_DRIVER_NAME}.name`], {
343
385
  encoding: "utf8",
@@ -345,12 +387,31 @@ function installMergeDriver(projectDir) {
345
387
  return (0, diagnostics_1.warning)("merge_driver_not_registered", "Could not register the traceability merge driver in git config.", {
346
388
  target: ".gitattributes",
347
389
  fix: `Run it by hand inside the project:\n` +
348
- ` git config merge.${exports.MERGE_DRIVER_NAME}.driver 'node ${driverScript} %O %A %B'\n` +
390
+ ` git config merge.${exports.MERGE_DRIVER_NAME}.driver '${driverCommand} %O %A %B'\n` +
349
391
  "Until then git uses its built-in merge, which conflicts when two " +
350
392
  "harness branches touch adjacent rows.",
351
393
  });
352
394
  }
353
395
  gitConfig(`merge.${exports.MERGE_DRIVER_NAME}.name`, "csda traceability matrix merge");
396
+ if (!driverIsPortable) {
397
+ return (0, diagnostics_1.warning)("merge_driver_is_machine_local", "The merge driver points at this machine's copy of specgate.", {
398
+ target: ".gitattributes",
399
+ fix: "`.gitattributes` is committed and names the driver; the driver itself is " +
400
+ "local git config, so every other clone and CI runner must run `specgate " +
401
+ "harness init` once or git falls back to its built-in merge (safe, just " +
402
+ "noisier on parallel branches).\n" +
403
+ "To make it reproducible instead, add specgate to the project: " +
404
+ "`npm i -D @rsaglobaltech/specgate` and re-run this — the driver is then " +
405
+ "a path inside node_modules that every clone rebuilds." +
406
+ (appendedToTracked ? "\nThis also appended to your existing .gitattributes." : ""),
407
+ });
408
+ }
409
+ if (appendedToTracked) {
410
+ return (0, diagnostics_1.warning)("gitattributes_modified", "Appended a merge rule to your existing .gitattributes — a tracked file.", {
411
+ target: ".gitattributes",
412
+ fix: "Review and commit it. The rule is shared; the driver behind it is per-clone.",
413
+ });
414
+ }
354
415
  return null;
355
416
  }
356
417
  if (require.main === module)