@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.
- package/CHANGELOG.md +196 -0
- package/README.md +17 -25
- package/bin/specgate.ts +23 -5
- package/dist/bin/specgate.js +19 -4
- package/dist/bin/specgate.js.map +1 -1
- package/dist/packages/core/src/application/GenerateAgentPromptUseCase.js +56 -0
- package/dist/packages/core/src/application/GenerateAgentPromptUseCase.js.map +1 -1
- package/dist/packages/core/src/application/ValidateProjectUseCase.js +54 -0
- package/dist/packages/core/src/application/ValidateProjectUseCase.js.map +1 -1
- package/dist/packages/core/src/domain/AdversarialProbe.js +75 -0
- package/dist/packages/core/src/domain/AdversarialProbe.js.map +1 -0
- package/dist/packages/core/src/domain/AgentPrompt.js +52 -3
- package/dist/packages/core/src/domain/AgentPrompt.js.map +1 -1
- package/dist/packages/core/src/domain/DeclaredArtifacts.js +25 -0
- package/dist/packages/core/src/domain/DeclaredArtifacts.js.map +1 -1
- package/dist/packages/core/src/domain/DoneVerification.js +89 -0
- package/dist/packages/core/src/domain/DoneVerification.js.map +1 -0
- package/dist/packages/core/src/domain/GateCommandIntegrity.js +139 -0
- package/dist/packages/core/src/domain/GateCommandIntegrity.js.map +1 -0
- package/dist/packages/core/src/domain/GherkinQuality.js +19 -3
- package/dist/packages/core/src/domain/GherkinQuality.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessConfig.js +6 -0
- package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
- package/dist/packages/core/src/domain/MultiStack.js +96 -0
- package/dist/packages/core/src/domain/MultiStack.js.map +1 -0
- package/dist/packages/core/src/domain/NewRequirement.js +46 -0
- package/dist/packages/core/src/domain/NewRequirement.js.map +1 -0
- package/dist/packages/core/src/domain/Precedents.js +96 -0
- package/dist/packages/core/src/domain/Precedents.js.map +1 -0
- package/dist/packages/core/src/domain/RequirementPlan.js +1 -0
- package/dist/packages/core/src/domain/RequirementPlan.js.map +1 -1
- package/dist/packages/core/src/domain/RequirementRemoval.js +161 -0
- package/dist/packages/core/src/domain/RequirementRemoval.js.map +1 -0
- package/dist/packages/core/src/domain/ScenarioCoverage.js +178 -0
- package/dist/packages/core/src/domain/ScenarioCoverage.js.map +1 -0
- package/dist/packages/core/src/domain/SpecSections.js +206 -0
- package/dist/packages/core/src/domain/SpecSections.js.map +1 -0
- package/dist/packages/core/src/domain/TestCommand.js +82 -0
- package/dist/packages/core/src/domain/TestCommand.js.map +1 -0
- package/dist/packages/core/src/domain/TraceabilityFormat.js +45 -2
- package/dist/packages/core/src/domain/TraceabilityFormat.js.map +1 -1
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +31 -0
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
- package/dist/packages/core/test/unit/adversarial-probe.test.js +81 -0
- package/dist/packages/core/test/unit/adversarial-probe.test.js.map +1 -0
- package/dist/packages/core/test/unit/done-verification.test.js +84 -0
- package/dist/packages/core/test/unit/done-verification.test.js.map +1 -0
- package/dist/packages/core/test/unit/gate-command-integrity.test.js +114 -0
- package/dist/packages/core/test/unit/gate-command-integrity.test.js.map +1 -0
- package/dist/packages/core/test/unit/gherkin-quality.test.js +28 -0
- package/dist/packages/core/test/unit/gherkin-quality.test.js.map +1 -1
- package/dist/packages/core/test/unit/multi-stack.test.js +86 -0
- package/dist/packages/core/test/unit/multi-stack.test.js.map +1 -0
- package/dist/packages/core/test/unit/new-requirement.test.js +67 -0
- package/dist/packages/core/test/unit/new-requirement.test.js.map +1 -0
- package/dist/packages/core/test/unit/precedents.test.js +99 -0
- package/dist/packages/core/test/unit/precedents.test.js.map +1 -0
- package/dist/packages/core/test/unit/requirement-removal.test.js +124 -0
- package/dist/packages/core/test/unit/requirement-removal.test.js.map +1 -0
- package/dist/packages/core/test/unit/scenario-coverage.test.js +146 -0
- package/dist/packages/core/test/unit/scenario-coverage.test.js.map +1 -0
- package/dist/packages/core/test/unit/spec-sections.test.js +146 -0
- package/dist/packages/core/test/unit/spec-sections.test.js.map +1 -0
- package/dist/packages/core/test/unit/test-command.test.js +81 -0
- package/dist/packages/core/test/unit/test-command.test.js.map +1 -0
- package/dist/packages/core/test/unit/validate-project.test.js +21 -0
- package/dist/packages/core/test/unit/validate-project.test.js.map +1 -1
- package/dist/scripts/agents/commands.js +1 -1
- package/dist/scripts/agents/commands.js.map +1 -1
- package/dist/scripts/agents/init.js +59 -15
- package/dist/scripts/agents/init.js.map +1 -1
- package/dist/scripts/change/instructions.js +2 -2
- package/dist/scripts/change/instructions.js.map +1 -1
- package/dist/scripts/check.js +10 -0
- package/dist/scripts/check.js.map +1 -0
- package/dist/scripts/cli/commands/change/ChangeCommand.js +2 -2
- package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
- package/dist/scripts/cli/commands/config/CiInitCommand.js +1 -1
- package/dist/scripts/cli/commands/config/CiInitCommand.js.map +1 -1
- package/dist/scripts/cli/commands/harness/RunCommand.js +214 -9
- package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
- package/dist/scripts/cli/commands/pack/InferPackCommand.js +331 -31
- package/dist/scripts/cli/commands/pack/InferPackCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/AdoptCommand.js +86 -9
- package/dist/scripts/cli/commands/project/AdoptCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/InitProjectCommand.js +286 -45
- package/dist/scripts/cli/commands/project/InitProjectCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/UpdateCommand.js +118 -8
- package/dist/scripts/cli/commands/project/UpdateCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/CheckCommand.js +184 -0
- package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -0
- package/dist/scripts/cli/commands/quality/DoctorCommand.js +20 -2
- package/dist/scripts/cli/commands/quality/DoctorCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/FixCommand.js +1 -1
- package/dist/scripts/cli/commands/quality/FixCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/ReportCommand.js +1 -1
- package/dist/scripts/cli/commands/quality/ReportCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js +406 -24
- package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/DoneCommand.js +108 -0
- package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/NewCommand.js +178 -0
- package/dist/scripts/cli/commands/spec/NewCommand.js.map +1 -0
- package/dist/scripts/cli/commands/spec/PlanCommand.js +8 -2
- package/dist/scripts/cli/commands/spec/PlanCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/ReqCommand.js +124 -4
- package/dist/scripts/cli/commands/spec/ReqCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StatusCommand.js +84 -32
- package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
- package/dist/scripts/docs/build-site.js +145 -35
- package/dist/scripts/docs/build-site.js.map +1 -1
- package/dist/scripts/docs/components.js +208 -0
- package/dist/scripts/docs/components.js.map +1 -0
- package/dist/scripts/docs/highlight.js +180 -0
- package/dist/scripts/docs/highlight.js.map +1 -0
- package/dist/scripts/docs/icons.js +63 -0
- package/dist/scripts/docs/icons.js.map +1 -0
- package/dist/scripts/docs/nav.js +9 -3
- package/dist/scripts/docs/nav.js.map +1 -1
- package/dist/scripts/gen_mcp_tools.js +22 -2
- package/dist/scripts/gen_mcp_tools.js.map +1 -1
- package/dist/scripts/harness/init.js +101 -40
- package/dist/scripts/harness/init.js.map +1 -1
- package/dist/scripts/harness/worktree-lock.js +161 -0
- package/dist/scripts/harness/worktree-lock.js.map +1 -0
- package/dist/scripts/infer_pack.js +4 -1
- package/dist/scripts/infer_pack.js.map +1 -1
- package/dist/scripts/lib/surface.js +88 -38
- package/dist/scripts/lib/surface.js.map +1 -1
- package/dist/scripts/new.js +10 -0
- package/dist/scripts/new.js.map +1 -0
- package/dist/scripts/plugin/gate-hook.js +2 -2
- package/dist/scripts/plugin/gate-hook.js.map +1 -1
- package/package.json +5 -2
- package/templates/adopt/AI_RULES.md.tpl +1 -1
- package/templates/adopt/spec.md.tpl +4 -4
- package/templates/base/spec.md.tpl +12 -0
- package/templates/ci/azure.yml.tpl +2 -2
- package/templates/ci/github.yml.tpl +2 -2
- package/templates/ci/gitlab.yml.tpl +1 -1
- package/templates/ci/jenkins.tpl +1 -1
- package/templates/contracts/test-strategy.md.tpl +2 -2
- package/templates/harness/harness.config.yaml.tpl +3 -3
- 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, "<")
|
|
38
|
+
.replace(/>/g, ">")
|
|
39
|
+
.replace(/"/g, """);
|
|
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":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;;;AAEH,gCAMC;AAkOD,8BAwBC;AAhQD,SAAgB,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAOD,+EAA+E;AAC/E,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA,8DAA8D,CAAC;AACxF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA,mBAAmB,CAAC;AAE7C,SAAS,QAAQ,CAAC,GAAG,KAAe;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA,QAAQ,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AAChD,CAAC;AAED,MAAM,KAAK,GAAoC;IAC7C,IAAI,EAAE;QACJ,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,SAAS,EAAE;QACrC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;QACxB,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,wBAAwB,EAAE;QACpD;YACE,GAAG,EAAE,GAAG;YACR,EAAE,EAAE,QAAQ,CACV,IAAI,EACJ,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,OAAO,EACP,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,IAAI,EACJ,MAAM,EACN,MAAM,CACP;SACF;QACD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,iCAAiC,EAAE;QAC7D,uEAAuE;QACvE,sDAAsD;QACtD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,4BAA4B,EAAE;QACxD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;KACzB;IACD,IAAI,EAAE;QACJ,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,2BAA2B,EAAE;QACvD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,mBAAmB,EAAE;QAC/C,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE;QACnD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;KACzB;IACD,IAAI,EAAE;QACJ,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,SAAS,EAAE;QACrC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,6BAA6B,EAAE;QACzD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;QACxB,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE;QAC7E,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;KACzB;IACD,EAAE,EAAE;QACF,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,yBAAyB,EAAE;QACrD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;QACxB;YACE,GAAG,EAAE,GAAG;YACR,EAAE,EAAE,QAAQ,CACV,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,OAAO,EACP,KAAK,EACL,KAAK,EACL,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,KAAK,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,SAAS,EACT,YAAY,EACZ,WAAW,EACX,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,KAAK,EACL,OAAO,EACP,SAAS,EACT,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,MAAM,EACN,OAAO,EACP,MAAM,EACN,WAAW,EACX,MAAM,CACP;SACF;QACD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;KACzB;IACD,IAAI,EAAE;QACJ,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,yBAAyB,EAAE;QACrD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;QACxB,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,cAAc,EAAE;QAC3C;YACE,GAAG,EAAE,GAAG;YACR,EAAE,EAAE,QAAQ,CACV,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,WAAW,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,MAAM,EACN,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,KAAK,EACL,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,EACP,MAAM,CACP;SACF;QACD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;KACzB;IACD,GAAG,EAAE;QACH,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,iBAAiB,EAAE;QAC7C,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,mBAAmB,EAAE;QAC/C,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,yBAAyB,EAAE;KACtD;IACD,OAAO,EAAE;QACP,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,SAAS,EAAE;QACrC;YACE,GAAG,EAAE,GAAG;YACR,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,iFAAiF;SAChG;QACD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,2CAA2C,EAAE;QACvE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,SAAS,EAAE;QACtC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,WAAW,EAAE;KACxC;IACD,MAAM,EAAE;QACN,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAA,yBAAyB,EAAE;QACrD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;QACxB;YACE,GAAG,EAAE,GAAG;YACR,EAAE,EAAE,QAAQ,CACV,UAAU,EACV,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACP,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACP,MAAM,CACP;SACF;QACD,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;KACzB;CACF,CAAC;AAEF,mDAAmD;AACnD,MAAM,OAAO,GAA2B;IACtC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,MAAM;IACf,UAAU,EAAE,IAAI;IAChB,EAAE,EAAE,IAAI;IACR,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,MAAM;IACb,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,MAAM;IACd,GAAG,EAAE,MAAM;IACX,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,QAAQ;CACtB,CAAC;AAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE3C,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,oEAAoE;IACpE,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IACrE,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,IAAY,EAAE,QAAgB;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE;QAAE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,EAAE,CAAC,SAAS,GAAG,CAAC,CAAC;IAEjB,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1D,uDAAuD;QACvD,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YAChB,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAC3D,MAAM,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;QACjD,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,yBAAyB,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3F,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,OAAO,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,+EAA+E;AAClE,QAAA,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -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"}
|
package/dist/scripts/docs/nav.js
CHANGED
|
@@ -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
|
|
7
|
-
*
|
|
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: "
|
|
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":";AAAA;;;;;;;;;;;;;GAaG;;;
|
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAA8B;AAC9B,gDAAkC;AAClC,2CAAkD;AAElD;;;;;;;GAOG;AACH,SAAS,QAAQ;IACf,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,SAAS,CAAC;QACR,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,SAAS,CAAC,CAAC;QACjF,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,uCAAuC,CAAC,CAAC;AAChF,MAAM,QAAQ,GAAG,IAAA,kBAAQ,GAA4B,CAAC;AAEtD,mFAAmF;AACnF,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAC/C,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE;IACnB,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC,EACD,EAA4B,CAC7B,CAAC;AAEF,IAAI,GAAG,GAAG
|
|
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
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
202
|
-
: "specgate validate . --strict
|
|
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
|
|
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
|
|
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
|
-
//
|
|
322
|
-
//
|
|
323
|
-
|
|
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`,
|
|
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 '
|
|
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)
|