focused-spec 0.1.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/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +205 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +114 -0
- package/dist/config.js.map +1 -0
- package/dist/executor.d.ts +4 -0
- package/dist/executor.js +45 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +94 -0
- package/dist/model.js +2 -0
- package/dist/model.js.map +1 -0
- package/dist/parser.d.ts +6 -0
- package/dist/parser.js +64 -0
- package/dist/parser.js.map +1 -0
- package/dist/planner.d.ts +9 -0
- package/dist/planner.js +100 -0
- package/dist/planner.js.map +1 -0
- package/dist/runner-api.d.ts +50 -0
- package/dist/runner-api.js +2 -0
- package/dist/runner-api.js.map +1 -0
- package/dist/runner-client.d.ts +4 -0
- package/dist/runner-client.js +193 -0
- package/dist/runner-client.js.map +1 -0
- package/dist/runner-host.d.ts +1 -0
- package/dist/runner-host.js +34 -0
- package/dist/runner-host.js.map +1 -0
- package/dist/sources.d.ts +5 -0
- package/dist/sources.js +64 -0
- package/dist/sources.js.map +1 -0
- package/dist/validate.d.ts +19 -0
- package/dist/validate.js +107 -0
- package/dist/validate.js.map +1 -0
- package/install.sh +27 -0
- package/package.json +46 -0
- package/skills/focused-spec/SKILL.md +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 focused-spec contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# focused-spec
|
|
2
|
+
|
|
3
|
+
`focused-spec` connects small behavioral scenarios to exact executable evidence. The core is language- and test-framework-agnostic; projects provide local runner plugins for their own test stacks.
|
|
4
|
+
|
|
5
|
+
## Start here
|
|
6
|
+
|
|
7
|
+
- [Documentation map](docs/README.md)
|
|
8
|
+
- [Concepts](docs/concepts/README.md)
|
|
9
|
+
- [Install the CLI and agent skill](docs/guides/install.md)
|
|
10
|
+
- [Configure scenarios](docs/guides/configuration.md)
|
|
11
|
+
- [Implement runners](docs/guides/runners.md)
|
|
12
|
+
- [CLI reference](docs/reference/cli.md)
|
|
13
|
+
- [Development workflow](docs/development/README.md)
|
|
14
|
+
- [Agent evals](docs/development/agent-evals.md)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm install --save-dev focused-spec
|
|
20
|
+
npx --yes skills add bamanoz/focused-spec --skill focused-spec
|
|
21
|
+
```
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
import { executePlan } from './executor.js';
|
|
6
|
+
import { parseEvidenceReference } from './parser.js';
|
|
7
|
+
import { planEvidence } from './planner.js';
|
|
8
|
+
import { validateFocusedSpecs } from './validate.js';
|
|
9
|
+
const USAGE = `Usage:
|
|
10
|
+
focused-spec validate [--root <path>] [--config <path>] [--change <name>] [--strict] [--syntax-only] [--json]
|
|
11
|
+
focused-spec run [--root <path>] [--config <path>] [--change <name>] [--scenario <id>] [--allow-skip] [--json]
|
|
12
|
+
`;
|
|
13
|
+
function parseArguments(argumentsList) {
|
|
14
|
+
const command = argumentsList[0];
|
|
15
|
+
if (command !== 'validate' && command !== 'run')
|
|
16
|
+
throw new Error(USAGE);
|
|
17
|
+
let root = process.cwd();
|
|
18
|
+
let configPath;
|
|
19
|
+
let changeName;
|
|
20
|
+
let strict = false;
|
|
21
|
+
let syntaxOnly = false;
|
|
22
|
+
let json = false;
|
|
23
|
+
let allowSkip = false;
|
|
24
|
+
let scenarioId;
|
|
25
|
+
for (let index = 1; index < argumentsList.length; index += 1) {
|
|
26
|
+
const argument = argumentsList[index];
|
|
27
|
+
if (argument === '--strict')
|
|
28
|
+
strict = true;
|
|
29
|
+
else if (argument === '--syntax-only')
|
|
30
|
+
syntaxOnly = true;
|
|
31
|
+
else if (argument === '--json')
|
|
32
|
+
json = true;
|
|
33
|
+
else if (argument === '--allow-skip')
|
|
34
|
+
allowSkip = true;
|
|
35
|
+
else if (argument === '--root' || argument === '--config' || argument === '--change' || argument === '--scenario') {
|
|
36
|
+
const value = argumentsList[index + 1];
|
|
37
|
+
if (value === undefined || value.startsWith('--'))
|
|
38
|
+
throw new Error(`missing value for ${argument}\n${USAGE}`);
|
|
39
|
+
index += 1;
|
|
40
|
+
if (argument === '--root')
|
|
41
|
+
root = resolve(value);
|
|
42
|
+
else if (argument === '--config')
|
|
43
|
+
configPath = value;
|
|
44
|
+
else if (argument === '--change')
|
|
45
|
+
changeName = value;
|
|
46
|
+
else
|
|
47
|
+
scenarioId = value;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw new Error(`unknown argument ${String(argument)}\n${USAGE}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (command === 'validate' && (allowSkip || scenarioId !== undefined)) {
|
|
54
|
+
throw new Error(`--allow-skip and --scenario are valid only for run\n${USAGE}`);
|
|
55
|
+
}
|
|
56
|
+
if (command === 'run' && (strict || syntaxOnly))
|
|
57
|
+
throw new Error(`run is always strict and cannot be syntax-only\n${USAGE}`);
|
|
58
|
+
return {
|
|
59
|
+
command,
|
|
60
|
+
root,
|
|
61
|
+
...(configPath === undefined ? {} : { configPath }),
|
|
62
|
+
...(changeName === undefined ? {} : { changeName }),
|
|
63
|
+
strict,
|
|
64
|
+
syntaxOnly,
|
|
65
|
+
json,
|
|
66
|
+
allowSkip,
|
|
67
|
+
...(scenarioId === undefined ? {} : { scenarioId }),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function runContext(options) {
|
|
71
|
+
return {
|
|
72
|
+
validationScope: {
|
|
73
|
+
current: true,
|
|
74
|
+
changes: options.changeName === undefined
|
|
75
|
+
? { mode: 'all-active' }
|
|
76
|
+
: { mode: 'selected', name: options.changeName },
|
|
77
|
+
},
|
|
78
|
+
executionSelection: {
|
|
79
|
+
source: options.changeName === undefined ? 'current' : 'change',
|
|
80
|
+
...(options.changeName === undefined ? {} : { change: options.changeName }),
|
|
81
|
+
...(options.scenarioId === undefined ? {} : { scenario: options.scenarioId }),
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function displayRunContext(context) {
|
|
86
|
+
const changes = context.validationScope.changes;
|
|
87
|
+
const validation = changes.mode === 'all-active'
|
|
88
|
+
? 'current specifications and all active changes'
|
|
89
|
+
: `current specifications and selected change ${changes.name}`;
|
|
90
|
+
const selection = context.executionSelection;
|
|
91
|
+
const execution = selection.source === 'current'
|
|
92
|
+
? 'current specifications'
|
|
93
|
+
: `change ${String(selection.change)}`;
|
|
94
|
+
const scenario = selection.scenario === undefined ? '' : `, scenario ${selection.scenario}`;
|
|
95
|
+
return `validation scope: ${validation}\nexecution selection: ${execution}${scenario}\n`;
|
|
96
|
+
}
|
|
97
|
+
function displayViolation(violation) {
|
|
98
|
+
const location = violation.line === undefined ? violation.path : `${violation.path}:${violation.line}`;
|
|
99
|
+
return `${location}: ${violation.message}`;
|
|
100
|
+
}
|
|
101
|
+
function printViolations(violations, json, context) {
|
|
102
|
+
if (json) {
|
|
103
|
+
const output = context === undefined
|
|
104
|
+
? { valid: false, violations }
|
|
105
|
+
: { valid: false, executionStarted: false, ...context, violations };
|
|
106
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (context !== undefined)
|
|
110
|
+
process.stderr.write(`${displayRunContext(context)}execution did not start\n`);
|
|
111
|
+
for (const violation of violations)
|
|
112
|
+
process.stderr.write(`${displayViolation(violation)}\n`);
|
|
113
|
+
}
|
|
114
|
+
function printExecution(result, json, context) {
|
|
115
|
+
if (json) {
|
|
116
|
+
process.stdout.write(`${JSON.stringify({ ...result, executionStarted: result.targetCount > 0, ...context }, null, 2)}\n`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
process.stdout.write(displayRunContext(context));
|
|
120
|
+
for (const scenario of result.scenarios) {
|
|
121
|
+
process.stdout.write(`${scenario.status} ${scenario.id}\n`);
|
|
122
|
+
for (const evidence of scenario.evidence) {
|
|
123
|
+
process.stdout.write(` ${evidence.status} ${evidence.reference}\n`);
|
|
124
|
+
if (evidence.diagnostic !== undefined)
|
|
125
|
+
process.stdout.write(` ${evidence.diagnostic.split('\n').join('\n ')}\n`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const counts = { PASS: 0, FAIL: 0, SKIP: 0, ERROR: 0 };
|
|
129
|
+
for (const scenario of result.scenarios)
|
|
130
|
+
counts[scenario.status] += 1;
|
|
131
|
+
process.stdout.write(`summary: ${counts.PASS} PASS, ${counts.FAIL} FAIL, ${counts.SKIP} SKIP, ${counts.ERROR} ERROR; ${result.targetCount} unique targets\n`);
|
|
132
|
+
}
|
|
133
|
+
function validationCounts(documents, plan) {
|
|
134
|
+
let scenarios = 0;
|
|
135
|
+
let plannedEvidence = 0;
|
|
136
|
+
for (const document of documents) {
|
|
137
|
+
scenarios += document.scenarios.length;
|
|
138
|
+
for (const scenario of document.scenarios) {
|
|
139
|
+
for (const raw of scenario.evidence) {
|
|
140
|
+
const reference = parseEvidenceReference(raw);
|
|
141
|
+
if (!('error' in reference) && reference.planned)
|
|
142
|
+
plannedEvidence += 1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { scenarios, plannedEvidence, targets: plan.targets.length };
|
|
147
|
+
}
|
|
148
|
+
async function main(argumentsList) {
|
|
149
|
+
const options = parseArguments(argumentsList);
|
|
150
|
+
const context = options.command === 'run' ? runContext(options) : undefined;
|
|
151
|
+
const projectRoot = isAbsolute(options.root) ? options.root : resolve(options.root);
|
|
152
|
+
const loaded = await loadConfig(projectRoot, options.configPath);
|
|
153
|
+
if (loaded.config === undefined) {
|
|
154
|
+
printViolations(loaded.violations, options.json, context);
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
const validation = await validateFocusedSpecs(projectRoot, loaded.config, {
|
|
158
|
+
...(options.changeName === undefined ? {} : { changeName: options.changeName }),
|
|
159
|
+
strict: options.command === 'run' || options.strict,
|
|
160
|
+
});
|
|
161
|
+
if (validation.violations.length > 0) {
|
|
162
|
+
printViolations(validation.violations, options.json, context);
|
|
163
|
+
return 1;
|
|
164
|
+
}
|
|
165
|
+
if (options.syntaxOnly) {
|
|
166
|
+
if (options.json)
|
|
167
|
+
process.stdout.write(`${JSON.stringify({ valid: true, mode: 'syntax-only' }, null, 2)}\n`);
|
|
168
|
+
else
|
|
169
|
+
process.stdout.write('focused specifications are structurally valid\n');
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
const resolution = await planEvidence(projectRoot, loaded.config, validation.resolutionDocuments);
|
|
173
|
+
if (resolution.violations.length > 0) {
|
|
174
|
+
printViolations(resolution.violations, options.json, context);
|
|
175
|
+
return 1;
|
|
176
|
+
}
|
|
177
|
+
if (options.command === 'validate') {
|
|
178
|
+
if (resolution.plan === undefined)
|
|
179
|
+
throw new Error('evidence validation did not produce a resolution plan');
|
|
180
|
+
const counts = validationCounts(validation.resolutionDocuments, resolution.plan);
|
|
181
|
+
if (options.json)
|
|
182
|
+
process.stdout.write(`${JSON.stringify({ valid: true, ...counts }, null, 2)}\n`);
|
|
183
|
+
else
|
|
184
|
+
process.stdout.write(`focused specifications are valid: ${counts.scenarios} scenarios, ${counts.plannedEvidence} planned evidence, ${counts.targets} unique targets\n`);
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
const planned = await planEvidence(projectRoot, loaded.config, validation.targetDocuments, {
|
|
188
|
+
...(options.scenarioId === undefined ? {} : { scenarioId: options.scenarioId }),
|
|
189
|
+
});
|
|
190
|
+
if (planned.violations.length > 0 || planned.plan === undefined) {
|
|
191
|
+
printViolations(planned.violations, options.json, context);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
const result = await executePlan(planned.plan, { allowSkip: options.allowSkip });
|
|
195
|
+
printExecution(result, options.json, context);
|
|
196
|
+
return result.success ? 0 : 1;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FocusedSpecConfig, Violation } from './model.js';
|
|
2
|
+
import type { JsonValue } from './runner-api.js';
|
|
3
|
+
export declare function isJsonValue(value: unknown): value is JsonValue;
|
|
4
|
+
export declare function loadConfig(projectRoot: string, explicitPath?: string): Promise<{
|
|
5
|
+
config?: FocusedSpecConfig;
|
|
6
|
+
path: string;
|
|
7
|
+
violations: readonly Violation[];
|
|
8
|
+
}>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
const RUNNER_ID = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/u;
|
|
5
|
+
const PARENT_SEGMENT = /(?:^|[\\/])\.\.(?:[\\/]|$)/u;
|
|
6
|
+
function object(value) {
|
|
7
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
8
|
+
? value
|
|
9
|
+
: undefined;
|
|
10
|
+
}
|
|
11
|
+
export function isJsonValue(value) {
|
|
12
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
13
|
+
return true;
|
|
14
|
+
if (typeof value === 'number')
|
|
15
|
+
return Number.isFinite(value);
|
|
16
|
+
if (Array.isArray(value))
|
|
17
|
+
return value.every(isJsonValue);
|
|
18
|
+
const record = object(value);
|
|
19
|
+
return record !== undefined && Object.values(record).every(isJsonValue);
|
|
20
|
+
}
|
|
21
|
+
function parseRunner(id, value, path, violations) {
|
|
22
|
+
const record = object(value);
|
|
23
|
+
if (!RUNNER_ID.test(id)) {
|
|
24
|
+
violations.push({ path, message: `invalid runner ID ${id}` });
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (record === undefined || typeof record.module !== 'string' || record.module.length === 0) {
|
|
28
|
+
violations.push({ path, message: `runner ${id} must define a non-empty module path` });
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
if (record.cwd !== undefined && (typeof record.cwd !== 'string' || record.cwd.length === 0)) {
|
|
32
|
+
violations.push({ path, message: `runner ${id} cwd must be a non-empty relative path` });
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
if (record.timeoutMs !== undefined && (!Number.isInteger(record.timeoutMs) || record.timeoutMs <= 0)) {
|
|
36
|
+
violations.push({ path, message: `runner ${id} timeoutMs must be a positive integer` });
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (record.options !== undefined && !isJsonValue(record.options)) {
|
|
40
|
+
violations.push({ path, message: `runner ${id} options must be JSON-compatible` });
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
module: record.module,
|
|
45
|
+
...(record.cwd === undefined ? {} : { cwd: record.cwd }),
|
|
46
|
+
...(record.timeoutMs === undefined ? {} : { timeoutMs: record.timeoutMs }),
|
|
47
|
+
...(record.options === undefined ? {} : { options: record.options }),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export async function loadConfig(projectRoot, explicitPath) {
|
|
51
|
+
const path = explicitPath === undefined
|
|
52
|
+
? resolve(projectRoot, '.focused-spec/config.yaml')
|
|
53
|
+
: isAbsolute(explicitPath) ? explicitPath : resolve(projectRoot, explicitPath);
|
|
54
|
+
let source;
|
|
55
|
+
try {
|
|
56
|
+
source = await readFile(path, 'utf8');
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
return { path, violations: [{ path, message: `cannot read configuration: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
60
|
+
}
|
|
61
|
+
let value;
|
|
62
|
+
try {
|
|
63
|
+
value = parse(source);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return { path, violations: [{ path, message: `invalid YAML: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
67
|
+
}
|
|
68
|
+
const violations = [];
|
|
69
|
+
const root = object(value);
|
|
70
|
+
if (root === undefined || root.version !== 1) {
|
|
71
|
+
return { path, violations: [{ path, message: 'configuration version must be 1' }] };
|
|
72
|
+
}
|
|
73
|
+
const specifications = object(root.specifications);
|
|
74
|
+
let specificationConfig;
|
|
75
|
+
if (specifications?.source === 'openspec') {
|
|
76
|
+
if (specifications.root !== undefined && (typeof specifications.root !== 'string' || specifications.root.length === 0 || isAbsolute(specifications.root) || PARENT_SEGMENT.test(specifications.root))) {
|
|
77
|
+
violations.push({ path, message: 'specifications.root must be a non-empty relative path' });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
specificationConfig = {
|
|
81
|
+
source: 'openspec',
|
|
82
|
+
...(specifications.root === undefined ? {} : { root: specifications.root }),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (specifications?.source === 'files') {
|
|
87
|
+
if (!Array.isArray(specifications.paths) || specifications.paths.length === 0 || !specifications.paths.every(item => typeof item === 'string' && item.length > 0 && !isAbsolute(item) && !PARENT_SEGMENT.test(item))) {
|
|
88
|
+
violations.push({ path, message: 'file specifications require a non-empty paths string array' });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
specificationConfig = { source: 'files', paths: specifications.paths };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
violations.push({ path, message: 'specifications.source must be openspec or files' });
|
|
96
|
+
}
|
|
97
|
+
const runnerValues = object(root.runners);
|
|
98
|
+
if (runnerValues === undefined)
|
|
99
|
+
violations.push({ path, message: 'runners must be an object' });
|
|
100
|
+
const runners = {};
|
|
101
|
+
for (const [id, runner] of Object.entries(runnerValues ?? {})) {
|
|
102
|
+
const parsed = parseRunner(id, runner, path, violations);
|
|
103
|
+
if (parsed !== undefined)
|
|
104
|
+
runners[id] = parsed;
|
|
105
|
+
}
|
|
106
|
+
if (specificationConfig === undefined || violations.length > 0)
|
|
107
|
+
return { path, violations };
|
|
108
|
+
return {
|
|
109
|
+
path,
|
|
110
|
+
violations,
|
|
111
|
+
config: { version: 1, specifications: specificationConfig, runners },
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/executor.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { runRunnerTargets } from './runner-client.js';
|
|
2
|
+
function aggregate(statuses) {
|
|
3
|
+
if (statuses.includes('ERROR'))
|
|
4
|
+
return 'ERROR';
|
|
5
|
+
if (statuses.includes('FAIL'))
|
|
6
|
+
return 'FAIL';
|
|
7
|
+
if (statuses.includes('SKIP'))
|
|
8
|
+
return 'SKIP';
|
|
9
|
+
return 'PASS';
|
|
10
|
+
}
|
|
11
|
+
export async function executePlan(plan, options = {}) {
|
|
12
|
+
const resultByKey = new Map();
|
|
13
|
+
for (const group of plan.groups) {
|
|
14
|
+
try {
|
|
15
|
+
const output = await runRunnerTargets(plan.projectRoot, group.runnerId, group.config, group.targets.map(target => target.target));
|
|
16
|
+
const outputById = new Map(output.results.map(result => [result.targetId, result]));
|
|
17
|
+
for (const target of group.targets) {
|
|
18
|
+
const result = outputById.get(target.target.targetId);
|
|
19
|
+
if (result === undefined) {
|
|
20
|
+
resultByKey.set(target.key, { status: 'ERROR', diagnostic: 'runner omitted the target result' });
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
resultByKey.set(target.key, {
|
|
24
|
+
status: result.status === 'pass' ? 'PASS' : result.status === 'fail' ? 'FAIL' : 'SKIP',
|
|
25
|
+
...(result.diagnostic === undefined ? {} : { diagnostic: result.diagnostic }),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
31
|
+
for (const target of group.targets)
|
|
32
|
+
resultByKey.set(target.key, { status: 'ERROR', diagnostic });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const scenarios = plan.scenarios.map(scenario => {
|
|
36
|
+
const evidence = scenario.evidence.map(item => {
|
|
37
|
+
const result = resultByKey.get(item.key) ?? { status: 'ERROR', diagnostic: 'execution plan lost the evidence result' };
|
|
38
|
+
return { reference: item.reference, ...result };
|
|
39
|
+
});
|
|
40
|
+
return { id: scenario.id, status: aggregate(evidence.map(item => item.status)), evidence };
|
|
41
|
+
});
|
|
42
|
+
const success = scenarios.every(scenario => scenario.status === 'PASS' || (options.allowSkip === true && scenario.status === 'SKIP'));
|
|
43
|
+
return { success, scenarios, targetCount: plan.targets.length };
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { loadConfig } from './config.js';
|
|
2
|
+
export { executePlan } from './executor.js';
|
|
3
|
+
export { parseEvidenceReference, parseFocusedSpecDocument } from './parser.js';
|
|
4
|
+
export { planEvidence } from './planner.js';
|
|
5
|
+
export type { ExecutionPlan, ExecutionResult, FocusedSpecConfig, Scenario, SpecDocument, Violation, } from './model.js';
|
|
6
|
+
export type { ResolveRequest, ResolveResponse, ResolvedTarget, RunnerPlugin, RunRequest, RunResponse, TargetResult, } from './runner-api.js';
|
|
7
|
+
export { validateDocuments, validateFocusedSpecs } from './validate.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { loadConfig } from './config.js';
|
|
2
|
+
export { executePlan } from './executor.js';
|
|
3
|
+
export { parseEvidenceReference, parseFocusedSpecDocument } from './parser.js';
|
|
4
|
+
export { planEvidence } from './planner.js';
|
|
5
|
+
export { validateDocuments, validateFocusedSpecs } from './validate.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAkB3C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { JsonValue, ResolvedTarget, TargetResult } from './runner-api.js';
|
|
2
|
+
export type SpecOperation = 'CURRENT' | 'ADDED' | 'MODIFIED' | 'REMOVED' | 'RENAMED';
|
|
3
|
+
export interface Scenario {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly line: number;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly requirement?: string;
|
|
8
|
+
readonly operation: SpecOperation;
|
|
9
|
+
readonly ids: readonly string[];
|
|
10
|
+
readonly evidence: readonly string[];
|
|
11
|
+
readonly whenCount: number;
|
|
12
|
+
readonly thenCount: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SpecDocument {
|
|
15
|
+
readonly path: string;
|
|
16
|
+
readonly scenarios: readonly Scenario[];
|
|
17
|
+
readonly malformedScenarioHeadings: readonly number[];
|
|
18
|
+
}
|
|
19
|
+
export interface Violation {
|
|
20
|
+
readonly path: string;
|
|
21
|
+
readonly line?: number;
|
|
22
|
+
readonly scenarioId?: string;
|
|
23
|
+
readonly message: string;
|
|
24
|
+
}
|
|
25
|
+
export interface RunnerConfig {
|
|
26
|
+
readonly module: string;
|
|
27
|
+
readonly cwd?: string;
|
|
28
|
+
readonly timeoutMs?: number;
|
|
29
|
+
readonly options?: JsonValue;
|
|
30
|
+
}
|
|
31
|
+
export interface OpenSpecSourceConfig {
|
|
32
|
+
readonly source: 'openspec';
|
|
33
|
+
readonly root?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface FileSourceConfig {
|
|
36
|
+
readonly source: 'files';
|
|
37
|
+
readonly paths: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
export interface FocusedSpecConfig {
|
|
40
|
+
readonly version: 1;
|
|
41
|
+
readonly specifications: OpenSpecSourceConfig | FileSourceConfig;
|
|
42
|
+
readonly runners: Readonly<Record<string, RunnerConfig>>;
|
|
43
|
+
}
|
|
44
|
+
export interface EvidenceReference {
|
|
45
|
+
readonly raw: string;
|
|
46
|
+
readonly planned: boolean;
|
|
47
|
+
readonly runnerId: string;
|
|
48
|
+
readonly selector: string;
|
|
49
|
+
}
|
|
50
|
+
export interface PlannedTarget {
|
|
51
|
+
readonly key: string;
|
|
52
|
+
readonly runnerId: string;
|
|
53
|
+
readonly config: RunnerConfig;
|
|
54
|
+
readonly target: ResolvedTarget;
|
|
55
|
+
readonly references: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
export interface PlannedEvidence {
|
|
58
|
+
readonly key: string;
|
|
59
|
+
readonly reference: string;
|
|
60
|
+
}
|
|
61
|
+
export interface PlannedScenario {
|
|
62
|
+
readonly id: string;
|
|
63
|
+
readonly evidence: readonly PlannedEvidence[];
|
|
64
|
+
}
|
|
65
|
+
export interface RunnerGroup {
|
|
66
|
+
readonly runnerId: string;
|
|
67
|
+
readonly config: RunnerConfig;
|
|
68
|
+
readonly targets: readonly PlannedTarget[];
|
|
69
|
+
}
|
|
70
|
+
export interface ExecutionPlan {
|
|
71
|
+
readonly projectRoot: string;
|
|
72
|
+
readonly scenarios: readonly PlannedScenario[];
|
|
73
|
+
readonly targets: readonly PlannedTarget[];
|
|
74
|
+
readonly groups: readonly RunnerGroup[];
|
|
75
|
+
}
|
|
76
|
+
export type EvidenceStatus = 'PASS' | 'FAIL' | 'SKIP' | 'ERROR';
|
|
77
|
+
export interface EvidenceResult {
|
|
78
|
+
readonly reference: string;
|
|
79
|
+
readonly status: EvidenceStatus;
|
|
80
|
+
readonly diagnostic?: string;
|
|
81
|
+
}
|
|
82
|
+
export interface ScenarioResult {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly status: EvidenceStatus;
|
|
85
|
+
readonly evidence: readonly EvidenceResult[];
|
|
86
|
+
}
|
|
87
|
+
export interface ExecutionResult {
|
|
88
|
+
readonly success: boolean;
|
|
89
|
+
readonly scenarios: readonly ScenarioResult[];
|
|
90
|
+
readonly targetCount: number;
|
|
91
|
+
}
|
|
92
|
+
export interface RunnerRunOutput {
|
|
93
|
+
readonly results: readonly TargetResult[];
|
|
94
|
+
}
|
package/dist/model.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":""}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EvidenceReference, SpecDocument } from './model.js';
|
|
2
|
+
export declare const STABLE_ID: RegExp;
|
|
3
|
+
export declare function parseFocusedSpecDocument(path: string, source: string): SpecDocument;
|
|
4
|
+
export declare function parseEvidenceReference(raw: string): EvidenceReference | {
|
|
5
|
+
readonly error: string;
|
|
6
|
+
};
|