asljs-rq-cli 0.0.0-stage → 0.1.2
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.md +51 -0
- package/README.md +224 -2
- package/bin/rq.js +12 -0
- package/dist/cli.d.ts +38 -0
- package/dist/cli.js +315 -0
- package/dist/config.d.ts +63 -0
- package/dist/config.js +78 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/docs/Changing the graph.md +108 -0
- package/docs/Querying the graph.md +71 -0
- package/docs/rq agents.md +29 -0
- package/docs/rq check.md +32 -0
- package/docs/rq config.md +60 -0
- package/docs/rq coverage.md +80 -0
- package/docs/rq test.md +124 -0
- package/package.json +71 -4
- package/skills/requirements-authoring.md +82 -0
- package/skills/requirements-change.md +51 -0
- package/skills/requirements-coverage.md +48 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Folders, Io, type Setting } from 'asljs-rq';
|
|
2
|
+
/**
|
|
3
|
+
* The environment variables `rq` reads.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ENVIRONMENT_VARIABLES: readonly ["RQ_AI_COMMAND", "RQ_LOG_LEVEL", "RQ_LOG_FILE", "RQ_LOG_FORMAT"];
|
|
6
|
+
/**
|
|
7
|
+
* The configuration `rq` runs with, as `rq config` prints it.
|
|
8
|
+
*/
|
|
9
|
+
export interface Configuration {
|
|
10
|
+
version: string;
|
|
11
|
+
workingDir: string;
|
|
12
|
+
/**
|
|
13
|
+
* The `rq.json` in use; `null` when there is none.
|
|
14
|
+
*/
|
|
15
|
+
configFile: string | null;
|
|
16
|
+
requirementsDir: Setting;
|
|
17
|
+
documentsDir: Setting;
|
|
18
|
+
/**
|
|
19
|
+
* The command `rq.json` runs on the markdown files a command wrote; `null`
|
|
20
|
+
* when there is none.
|
|
21
|
+
*/
|
|
22
|
+
markdownPostProcessing: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* The agent of instruction steps and `rq coverage` when `--ai` names none:
|
|
25
|
+
* `RQ_AI_COMMAND`, or the first installed of `agents`, detected when a
|
|
26
|
+
* command needs it.
|
|
27
|
+
*/
|
|
28
|
+
agent: {
|
|
29
|
+
command: string | null;
|
|
30
|
+
agents: string[];
|
|
31
|
+
};
|
|
32
|
+
log: {
|
|
33
|
+
level: LogSetting;
|
|
34
|
+
file: LogSetting;
|
|
35
|
+
format: LogSetting;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Each variable `rq` reads, and its value; `null` when it is not set.
|
|
39
|
+
*/
|
|
40
|
+
environment: Record<string, string | null>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A log setting and where it comes from: its option, its `RQ_LOG_`
|
|
44
|
+
* variable, or the default.
|
|
45
|
+
*/
|
|
46
|
+
export interface LogSetting {
|
|
47
|
+
value: string;
|
|
48
|
+
source: 'option' | 'environment' | 'default';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Prints the configuration: the folders and where they come from, the
|
|
52
|
+
* `rq.json` in use, the agent, the log settings, and the environment
|
|
53
|
+
* variables `rq` reads. `args` is the command line, for the log options.
|
|
54
|
+
*/
|
|
55
|
+
export declare function execConfig(io: Io, options: {
|
|
56
|
+
folders: Folders;
|
|
57
|
+
args: readonly string[];
|
|
58
|
+
json?: boolean;
|
|
59
|
+
}): Promise<number>;
|
|
60
|
+
/**
|
|
61
|
+
* The configuration `rq` runs with in the working folder of `io`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function readConfiguration(io: Io, folders: Folders, args: readonly string[]): Promise<Configuration>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AI_AGENTS } from 'asljs-agents';
|
|
2
|
+
import { readLoggerOptions } from 'asljs-logging';
|
|
3
|
+
import { findConfig } from 'asljs-mdcli';
|
|
4
|
+
import { CONFIG_FILE } from 'asljs-rq';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
/**
|
|
7
|
+
* The environment variables `rq` reads.
|
|
8
|
+
*/
|
|
9
|
+
export const ENVIRONMENT_VARIABLES = ['RQ_AI_COMMAND',
|
|
10
|
+
'RQ_LOG_LEVEL',
|
|
11
|
+
'RQ_LOG_FILE',
|
|
12
|
+
'RQ_LOG_FORMAT'];
|
|
13
|
+
/**
|
|
14
|
+
* Prints the configuration: the folders and where they come from, the
|
|
15
|
+
* `rq.json` in use, the agent, the log settings, and the environment
|
|
16
|
+
* variables `rq` reads. `args` is the command line, for the log options.
|
|
17
|
+
*/
|
|
18
|
+
export async function execConfig(io, options) {
|
|
19
|
+
const configuration = await readConfiguration(io, options.folders, options.args);
|
|
20
|
+
io.stdout.write(options.json
|
|
21
|
+
? `${JSON.stringify(configuration, null, 2)}\n`
|
|
22
|
+
: describe(configuration));
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The configuration `rq` runs with in the working folder of `io`.
|
|
27
|
+
*/
|
|
28
|
+
export async function readConfiguration(io, folders, args) {
|
|
29
|
+
const found = await findConfig(io.cwd, CONFIG_FILE);
|
|
30
|
+
const environment = Object.fromEntries(ENVIRONMENT_VARIABLES.map(name => [name,
|
|
31
|
+
io.env[name] || null]));
|
|
32
|
+
const overrides = readLoggerOptions(args);
|
|
33
|
+
const pick = (option, variable, fallback) => option !== undefined
|
|
34
|
+
? { value: option,
|
|
35
|
+
source: 'option' }
|
|
36
|
+
: environment[variable] !== null
|
|
37
|
+
? { value: environment[variable],
|
|
38
|
+
source: 'environment' }
|
|
39
|
+
: { value: fallback,
|
|
40
|
+
source: 'default' };
|
|
41
|
+
const file = pick(overrides.file, 'RQ_LOG_FILE', 'stdout');
|
|
42
|
+
return { version: packageVersion(),
|
|
43
|
+
workingDir: io.cwd,
|
|
44
|
+
configFile: folders.configFile,
|
|
45
|
+
requirementsDir: folders.requirementsDir,
|
|
46
|
+
documentsDir: folders.documentsDir,
|
|
47
|
+
markdownPostProcessing: found?.config.markdownPostProcessing?.trim()
|
|
48
|
+
|| null,
|
|
49
|
+
agent: { command: environment.RQ_AI_COMMAND,
|
|
50
|
+
agents: [...AI_AGENTS] },
|
|
51
|
+
log: { level: pick(overrides.level, 'RQ_LOG_LEVEL', file.source === 'default'
|
|
52
|
+
? 'silent'
|
|
53
|
+
: 'information'),
|
|
54
|
+
file,
|
|
55
|
+
format: pick(overrides.format, 'RQ_LOG_FORMAT', 'auto') },
|
|
56
|
+
environment };
|
|
57
|
+
}
|
|
58
|
+
function describe(configuration) {
|
|
59
|
+
const setting = (value) => `${value.value} (${value.source})`;
|
|
60
|
+
const lines = [`version: ${configuration.version}`,
|
|
61
|
+
`workingDir: ${configuration.workingDir}`,
|
|
62
|
+
`configFile: ${configuration.configFile ?? '(none)'}`,
|
|
63
|
+
`requirementsDir: ${setting(configuration.requirementsDir)}`,
|
|
64
|
+
`documentsDir: ${setting(configuration.documentsDir)}`,
|
|
65
|
+
`markdownPostProcessing: ${configuration.markdownPostProcessing ?? '(none)'}`,
|
|
66
|
+
`agent: ${configuration.agent.command === null
|
|
67
|
+
? `the first installed of ${configuration.agent.agents.join(', ')}, detected when needed`
|
|
68
|
+
: `${configuration.agent.command} (RQ_AI_COMMAND)`}`,
|
|
69
|
+
`logLevel: ${setting(configuration.log.level)}`,
|
|
70
|
+
`logFile: ${setting(configuration.log.file)}`,
|
|
71
|
+
`logFormat: ${setting(configuration.log.format)}`,
|
|
72
|
+
'environment:',
|
|
73
|
+
...Object.entries(configuration.environment).map(([name, value]) => ` ${name}=${value ?? ''}`)];
|
|
74
|
+
return `${lines.join('\n')}\n`;
|
|
75
|
+
}
|
|
76
|
+
function packageVersion() {
|
|
77
|
+
return createRequire(import.meta.url)('../package.json').version;
|
|
78
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createCli, runCli, type CliState } from './cli.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createCli, runCli } from './cli.js';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Changing the graph
|
|
2
|
+
|
|
3
|
+
Commands that change the structure of the graph, so that no one edits links or
|
|
4
|
+
results by hand. Each prints the files it created, changed or removed.
|
|
5
|
+
|
|
6
|
+
Every command takes `--working-dir <folder>`, `--requirements-dir <folder>` and
|
|
7
|
+
`--documents-dir <folder>`; see [Working folder][WF] and
|
|
8
|
+
[Requirements and documents folders][FD] for how paths, ids and `.md` names are
|
|
9
|
+
resolved. The scope - every `.md` document of the documents folder - is where
|
|
10
|
+
the next free id, the links to rewrite or remove, and another parent of a
|
|
11
|
+
requirement being linked are looked for.
|
|
12
|
+
|
|
13
|
+
## rq add requirement
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
rq add requirement <parent> <name> [--statement <text>] [--path <file>]
|
|
17
|
+
[--working-dir <folder>]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Creates `R<n> <name>.md` in the parent's folder, with `<n>` the highest `R`
|
|
21
|
+
number in the scope plus one, a level 1 heading equal to the file name, and the
|
|
22
|
+
statement. Adds a link to it to the parent's `## Implementation` list.
|
|
23
|
+
|
|
24
|
+
- `<parent>` must be a requirement; `<name>` must not contain `/` or `\`.
|
|
25
|
+
- `--path` gives the new file's path instead; its name must still start with
|
|
26
|
+
`R<n>` (`T<n>` for a test), and its heading is its file name.
|
|
27
|
+
- An existing file is an error.
|
|
28
|
+
|
|
29
|
+
## rq add test
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
rq add test <parent> <name> [--description <text>] [--step <command>]...
|
|
33
|
+
[--path <file>] [--working-dir <folder>]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Like `add requirement`, but creates `tests/T<n> <name>.md` next to the parent,
|
|
37
|
+
with the description and a `## Steps` section holding one `shell` step, `###
|
|
38
|
+
Step <n>`, per `--step`. Write other kinds of steps by editing the text; see
|
|
39
|
+
[Requirements][RM].
|
|
40
|
+
|
|
41
|
+
## rq link
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
rq link <parent> <child> [--working-dir <folder>]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Adds a link to an existing requirement or test to the parent's `##
|
|
48
|
+
Implementation` list. Refused when the parent is a test, when it already links
|
|
49
|
+
to the child, when the child leads back to the parent, or when the child is a
|
|
50
|
+
requirement another requirement of the scope already links to: a requirement has
|
|
51
|
+
one parent, a test may have several.
|
|
52
|
+
|
|
53
|
+
## rq unlink
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
rq unlink <parent> <child> [--working-dir <folder>]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Removes every link from the parent to the child: an `## Implementation` item
|
|
60
|
+
holding one goes with it, a link definition goes with its line, and any other
|
|
61
|
+
link, or reference to a removed definition, is replaced by its text. An error
|
|
62
|
+
when the parent does not link to the child.
|
|
63
|
+
|
|
64
|
+
## rq remove
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
rq remove <file> [--recursive] [--working-dir <folder>]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Deletes a requirement or a test, and removes the links to it from every document
|
|
71
|
+
of the scope, as `unlink` does. A requirement that links to anything is refused
|
|
72
|
+
unless `--recursive` is given; then every document only removed documents link
|
|
73
|
+
to is removed too, down the graph.
|
|
74
|
+
|
|
75
|
+
## rq move
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
rq move <file> <destination> [--working-dir <folder>]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Moves or renames a requirement or a test. `<destination>` is the new path, or an
|
|
82
|
+
existing folder to move it into; an existing file is an error, and so is a name
|
|
83
|
+
of another kind, e.g. an `R` file renamed to `T` or `notes.md`.
|
|
84
|
+
|
|
85
|
+
- Links to it from every document of the scope point at the new path, keeping
|
|
86
|
+
their `#` fragments.
|
|
87
|
+
- Its own relative links, including images, are rewritten for its new folder.
|
|
88
|
+
- When its heading is its old file name, the heading becomes the new file name,
|
|
89
|
+
and so does the text of `## Implementation` links that was the old heading.
|
|
90
|
+
|
|
91
|
+
## rq log
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
rq log <test> --result PASS|FAIL [--note <text>] [--time <time>] [--working-dir <folder>]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Records a result established another way: writes an execution file, `.rq/E<n>
|
|
98
|
+
<test>.md` in the working folder, with the one test, its result and the note, in
|
|
99
|
+
the format [`rq test`][TS] writes. `<test>` is a test file or id, e.g. `T12`.
|
|
100
|
+
`--time` is ISO 8601, now by default; the note is written on one line. The test
|
|
101
|
+
itself is not changed, except that the results are then recalculated and written
|
|
102
|
+
as [`rq test`][TS] does, with `--time` as the `Updated` of the test and of every
|
|
103
|
+
requirement recalculated above it.
|
|
104
|
+
|
|
105
|
+
[TS]: <rq test.md>
|
|
106
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
107
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
108
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Querying the graph
|
|
2
|
+
|
|
3
|
+
Commands that print the structure of the graph without changing anything. Paths
|
|
4
|
+
are printed relative to the working folder, with `/` separators.
|
|
5
|
+
|
|
6
|
+
The text output has one line per document: its kind - `requirement`, `test`,
|
|
7
|
+
`other` for an `## Implementation` link to a document that is neither, or
|
|
8
|
+
`missing` for one to no file - its path, and for a requirement or test its
|
|
9
|
+
status, `PASS`, `FAIL` or `NOT RUN`, as its `## Status` records it, then for a
|
|
10
|
+
requirement its coverage, `COMPLETE` or `INCOMPLETE`, when it was checked; see
|
|
11
|
+
[Requirements][RM]. The commands take only requirement and test files.
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
requirement requirements/R1 Export.md FAIL
|
|
15
|
+
test requirements/tests/T1 PDF export.md PASS
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
With `--json` the same documents are printed as an array of `{ path, kind,
|
|
19
|
+
title, result, coverage }`; `result` is `null` for any other document, and
|
|
20
|
+
`coverage` for one that is not a requirement or was never checked.
|
|
21
|
+
|
|
22
|
+
Every command takes `--working-dir <folder>`, `--requirements-dir <folder>` and
|
|
23
|
+
`--documents-dir <folder>`, and a requirement or test as a path, `.md` name or
|
|
24
|
+
id; see [Requirements and documents folders][FD]. The results are read from the
|
|
25
|
+
working folder's `.rq` folder.
|
|
26
|
+
|
|
27
|
+
## rq list
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
rq list [path] [--working-dir <folder>] [--json]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Every document of the graph of a requirement file or folder, the requirements
|
|
34
|
+
folder by default, in breadth-first order from the roots. Structure errors are
|
|
35
|
+
written to standard error.
|
|
36
|
+
|
|
37
|
+
## rq links
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
rq links <requirement> [--working-dir <folder>] [--json]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
What a requirement's `## Implementation` list links to.
|
|
44
|
+
|
|
45
|
+
## rq backlinks
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
rq backlinks <file> [--working-dir <folder>] [--json]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The requirements that link to a requirement or a test, looked for in every `.md`
|
|
52
|
+
document of the documents folder. Links in a test are not edges, so a test is
|
|
53
|
+
never a backlink.
|
|
54
|
+
|
|
55
|
+
## rq tojson
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
rq tojson [path] [--working-dir <folder>]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The graph of a requirement file or folder, the requirements folder by default,
|
|
62
|
+
as JSON:
|
|
63
|
+
|
|
64
|
+
- `roots` - the paths of the roots, empty when a folder has none;
|
|
65
|
+
- `errors` - the structure errors;
|
|
66
|
+
- `nodes` - every document, from the roots down, with `path`, `kind`, `title`,
|
|
67
|
+
`body` (the text between the heading and the first section), `links` (the
|
|
68
|
+
paths its `## Implementation` links to), `steps`, `result` and `coverage`.
|
|
69
|
+
|
|
70
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
71
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# rq agents
|
|
2
|
+
|
|
3
|
+
Prints instructions for an AI agent that edits the files of a requirements
|
|
4
|
+
folder directly, without `rq`: the formats of requirements, tests, `## Status`
|
|
5
|
+
sections and execution files, and the rules every change keeps, so that the
|
|
6
|
+
requirements stay one valid graph.
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
rq agents [--working-dir <folder>] [--requirements-dir <folder>]
|
|
10
|
+
[--documents-dir <folder>]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
It takes the folder options of every command, and they are checked as for every
|
|
14
|
+
command, but the instructions do not depend on them.
|
|
15
|
+
|
|
16
|
+
The instructions are made, when the command runs, from [Requirement files][RF],
|
|
17
|
+
the page of the package that is the only description of the formats: its text,
|
|
18
|
+
with every link replaced by its text so that it stands alone. They do not
|
|
19
|
+
mention `rq`; they are about the files, not about the commands.
|
|
20
|
+
|
|
21
|
+
Use it where `rq` is neither installed for the agent nor served to it by
|
|
22
|
+
[rq-mcp][MC], e.g. to give Copilot or Claude the rules in an instructions file:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx rq agents > .github/instructions/requirements.instructions.md
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
[MC]: ../../rq-mcp/docs/rq-mcp.md
|
|
29
|
+
[RF]: <../../rq/docs/Requirement files.md>
|
package/docs/rq check.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# rq check
|
|
2
|
+
|
|
3
|
+
Checks the structure of the graph and of each document without running anything.
|
|
4
|
+
It exits with a non-zero code when it finds a problem.
|
|
5
|
+
|
|
6
|
+
```text
|
|
7
|
+
rq check [path] [--working-dir <folder>]
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`[path]` is a requirement file, a folder, a `.md` name or an id, the
|
|
11
|
+
requirements folder by default; see [Requirements][RM] for the problems it
|
|
12
|
+
reports. `--working-dir`, `--requirements-dir` and `--documents-dir` set the
|
|
13
|
+
folders that paths, names and ids resolve in; see [Working folder][WF] and
|
|
14
|
+
[Requirements and documents folders][FD].
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
Error R1 Export.md: the link to R3.md points at no file.
|
|
18
|
+
Error tests/T2 CSV export.md: has a Log section; results are kept in .rq/E<n> files.
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Without problems it prints a count:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
OK 2 requirements, 2 tests
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Run it after editing documents by hand, and before `rq test`, which runs the
|
|
28
|
+
steps.
|
|
29
|
+
|
|
30
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
31
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
32
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# rq config
|
|
2
|
+
|
|
3
|
+
Prints the configuration `rq` runs with in the working folder, with the current
|
|
4
|
+
values and where each comes from. It reads and writes nothing else.
|
|
5
|
+
|
|
6
|
+
```text
|
|
7
|
+
rq config [--json] [--working-dir <folder>] [--requirements-dir <folder>]
|
|
8
|
+
[--documents-dir <folder>]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
version: 0.1.1
|
|
13
|
+
workingDir: C:\projects\project1
|
|
14
|
+
configFile: C:\projects\project1\rq.json
|
|
15
|
+
requirementsDir: C:\projects\project1\requirements (rq.json)
|
|
16
|
+
documentsDir: C:\projects\project1 (option)
|
|
17
|
+
markdownPostProcessing: npx toolkit flint
|
|
18
|
+
agent: the first installed of claude, copilot, detected when needed
|
|
19
|
+
logLevel: silent (default)
|
|
20
|
+
logFile: stdout (default)
|
|
21
|
+
logFormat: auto (default)
|
|
22
|
+
environment:
|
|
23
|
+
RQ_AI_COMMAND=
|
|
24
|
+
RQ_LOG_LEVEL=
|
|
25
|
+
RQ_LOG_FILE=
|
|
26
|
+
RQ_LOG_FORMAT=
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `version` - the version of `rq`.
|
|
30
|
+
- `workingDir` - the [working folder][WF], whose `.rq` folder holds the results.
|
|
31
|
+
- `configFile` - the `rq.json` in use, the nearest one from the working folder
|
|
32
|
+
up; `(none)` when there is none. See [Configuration][CF].
|
|
33
|
+
- `requirementsDir`, `documentsDir` - the
|
|
34
|
+
[requirements and documents folders][FD], and where each comes from: `option`,
|
|
35
|
+
`rq.json` or `default`.
|
|
36
|
+
- `markdownPostProcessing` - the command of `rq.json`; `(none)` when there is
|
|
37
|
+
none.
|
|
38
|
+
- `agent` - the agent of instruction steps and `rq coverage` when `--ai` names
|
|
39
|
+
none: `RQ_AI_COMMAND`, or the first installed of `claude` and `copilot`. `rq
|
|
40
|
+
config` does not look for an installed agent; that happens when a command
|
|
41
|
+
needs one.
|
|
42
|
+
- `logLevel`, `logFile`, `logFormat` - the log settings, and where each comes
|
|
43
|
+
from: `option` (`--loglevel`, `--logfile`, `--logformat`), `environment`
|
|
44
|
+
(`RQ_LOG_LEVEL`, `RQ_LOG_FILE`, `RQ_LOG_FORMAT`) or `default`. See the
|
|
45
|
+
repository's logging rules.
|
|
46
|
+
- `environment` - each variable `rq` reads, and its value, empty when it is not
|
|
47
|
+
set.
|
|
48
|
+
|
|
49
|
+
## Options
|
|
50
|
+
|
|
51
|
+
- `--json` - print the same as a JSON object, with `null` for a missing value
|
|
52
|
+
and `{ value, source }` for each folder and log setting.
|
|
53
|
+
- `--working-dir <folder>`, `--requirements-dir <folder>`, `--documents-dir
|
|
54
|
+
<folder>` - as for every command; `rq config` shows what they resolve to. A
|
|
55
|
+
requirements folder outside the documents folder is an error, here as in every
|
|
56
|
+
command.
|
|
57
|
+
|
|
58
|
+
[CF]: ../../rq/docs/Requirements.md#configuration
|
|
59
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
60
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# rq coverage
|
|
2
|
+
|
|
3
|
+
Asks an AI agent, for each requirement the targets select, whether its
|
|
4
|
+
sub-requirements and its own tests together provide sufficient functional
|
|
5
|
+
coverage, writes the verdict to the `- Coverage:` item of its `## Status`
|
|
6
|
+
section, and the agent's analysis to its `## Coverage` section. It exits with a
|
|
7
|
+
non-zero code when a checked requirement is incomplete or the graph has a
|
|
8
|
+
structure error.
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
rq coverage <target>... [--recurse] [--working-dir <folder>]
|
|
12
|
+
[--ai[=<agent>][:<model>]]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The targets are as for [`rq test`][TS]: ids, `.md` names, requirement files or
|
|
16
|
+
folders. A requirement target checks itself, and with `--recurse` every
|
|
17
|
+
requirement below it; a folder checks all its requirements. Tests are skipped.
|
|
18
|
+
|
|
19
|
+
It is independent of `rq test`: it runs no steps and reads no results, and `rq
|
|
20
|
+
test` keeps the coverage it writes. The agent judges coverage only: whether what
|
|
21
|
+
the linked requirements state and what the linked tests check covers each
|
|
22
|
+
statement. It is told to ignore test results and the `## Status` sections, not
|
|
23
|
+
to report on them, and not to recommend running tests.
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
COMPLETE requirements/R1 Export.md
|
|
27
|
+
INCOMPLETE requirements/R2 CSV export.md - Nothing covers quoting of commas.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- The `## Coverage` section holds the analysis: when the requirement is
|
|
31
|
+
complete, which requirement or test covers each statement; when it is not,
|
|
32
|
+
each statement nothing covers and what to do - a test to add and what it
|
|
33
|
+
should check, a sub-requirement to add and its statement, or a change to make.
|
|
34
|
+
It explains only what is covered, what is not, and how to improve the
|
|
35
|
+
coverage. The agent is asked to name requirements and tests by their id; a
|
|
36
|
+
link it writes anyway is replaced by its text. Then each id of a requirement
|
|
37
|
+
or test below the requirement in the graph, outside code, becomes a reference
|
|
38
|
+
link to its document, e.g. `[T2][]`, with its definition at the end of the
|
|
39
|
+
section, or none when the document already defines that label for the same
|
|
40
|
+
file. Other ids, e.g. of the requirements a test builds as its fixture, stay
|
|
41
|
+
text. It is rewritten on every check, with its definitions, placed before `##
|
|
42
|
+
Status`; a heading the agent writes is escaped so the section stays one
|
|
43
|
+
section.
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
## Coverage
|
|
47
|
+
|
|
48
|
+
Nothing covers "quotes fields that contain commas": [T2][] checks plain values
|
|
49
|
+
only.
|
|
50
|
+
|
|
51
|
+
- Add a test that exports a value with a comma and checks it is quoted, or
|
|
52
|
+
- extend [T2][] with such a value.
|
|
53
|
+
|
|
54
|
+
## Status
|
|
55
|
+
|
|
56
|
+
- Coverage: INCOMPLETE - Nothing covers quoting of commas.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- A requirement that links to nothing is `INCOMPLETE` without asking, with an
|
|
60
|
+
analysis that says to decompose it or add tests.
|
|
61
|
+
- The agent reads the requirement and what it links to; it is allowed to read
|
|
62
|
+
and search files only, so it runs no command and changes no file. The reason
|
|
63
|
+
it gives for an incomplete verdict becomes the note.
|
|
64
|
+
- The verdict is not invalidated by later edits: run `rq coverage` again after
|
|
65
|
+
changing a requirement or what it links to.
|
|
66
|
+
|
|
67
|
+
## Options
|
|
68
|
+
|
|
69
|
+
- `--recurse` - also check every requirement below a requirement target.
|
|
70
|
+
- `--working-dir <folder>` - the working folder; see [Working folder][WF].
|
|
71
|
+
- `--requirements-dir <folder>`, `--documents-dir <folder>` - see
|
|
72
|
+
[Requirements and documents folders][FD].
|
|
73
|
+
- `--ai[=<agent>][:<model>]` - the agent, `claude` or `copilot`, and its model,
|
|
74
|
+
both optional; the first of `claude` and `copilot` that is installed by
|
|
75
|
+
default. No agent is an error. `RQ_AI_COMMAND` replaces the agent, as for
|
|
76
|
+
[`rq test`][TS].
|
|
77
|
+
|
|
78
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
79
|
+
[TS]: <rq test.md>
|
|
80
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
package/docs/rq test.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# rq test
|
|
2
|
+
|
|
3
|
+
Runs the tests of requirements and tests, records the results in an execution
|
|
4
|
+
file, writes the results that follow to the `## Status` sections as each test
|
|
5
|
+
finishes, and reports the result of each target. It exits with a non-zero code
|
|
6
|
+
when a reported node does not pass or the graph has a structure error.
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
rq test <target>... [--recurse] [--working-dir <folder>] [--name <slug>]
|
|
10
|
+
[--ai[=<agent>][:<model>]]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Targets
|
|
14
|
+
|
|
15
|
+
Each target is one of:
|
|
16
|
+
|
|
17
|
+
- an id, e.g. `R10` or `T12`, or a `.md` name: the requirement or test the
|
|
18
|
+
requirements folder and its subfolders hold;
|
|
19
|
+
- a requirement or test file, relative to the working folder;
|
|
20
|
+
- a folder, relative to the working folder; see [Requirements][RM] for how its
|
|
21
|
+
roots are found.
|
|
22
|
+
|
|
23
|
+
See [Requirements and documents folders][FD] for how ids and names are matched.
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
rq test R10 R56 R100 T12 --recurse
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
What runs:
|
|
30
|
+
|
|
31
|
+
- a test target runs itself;
|
|
32
|
+
- a requirement target runs the tests it links to directly, and with `--recurse`
|
|
33
|
+
every test below it;
|
|
34
|
+
- a folder target runs every test of its graph.
|
|
35
|
+
|
|
36
|
+
Each test runs once, however many targets reach it.
|
|
37
|
+
|
|
38
|
+
## Results
|
|
39
|
+
|
|
40
|
+
The run is written to `.rq/E<n> <slug>.md` in the working folder, with `<n>` the
|
|
41
|
+
next free number; see [Requirements][RM] for the format. As each test finishes,
|
|
42
|
+
it is added to that file, its result is written to its `## Status` section, and
|
|
43
|
+
every requirement above it is recalculated and written, all with the time the
|
|
44
|
+
test finished as `Updated`; a failed test fails every requirement above it, and
|
|
45
|
+
each of them names it, with its note and the execution file. After the last
|
|
46
|
+
test, the targets are recalculated too. A run that stops early leaves every test
|
|
47
|
+
that finished recorded. Nothing is written when no test runs.
|
|
48
|
+
|
|
49
|
+
## Output
|
|
50
|
+
|
|
51
|
+
One line per test, as it finishes, with its note, and for a failed one the
|
|
52
|
+
execution file. Then one line per other reported node: each requirement target,
|
|
53
|
+
and with `--recurse` or for a folder every requirement below it; without
|
|
54
|
+
`--recurse`, also each requirement a target links to, marked `(recorded)`, with
|
|
55
|
+
the result its document records. Then one `Error` line per structure error, the
|
|
56
|
+
path of the execution file, one `Updated` line per document whose `## Status`
|
|
57
|
+
changed, in the order they changed, and one `Removed` line per old execution
|
|
58
|
+
file the [retention][RT] removed.
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
PASS requirements/tests/T1 PDF export.md - 1 step
|
|
62
|
+
FAIL requirements/tests/T2 CSV export.md - step 1 exited with code 1: 1 test failed (.rq/E4 requirements.md)
|
|
63
|
+
FAIL requirements/R1 Export.md - 1 of 2 links failed: T2 CSV export: step 1 exited with code 1: 1 test failed (.rq/E4 requirements.md)
|
|
64
|
+
FAIL requirements/R2 CSV export.md - 1 of 1 links failed: T2 CSV export: step 1 exited with code 1: 1 test failed (.rq/E4 requirements.md)
|
|
65
|
+
Error R2 CSV export.md: the link to R3.md points at no file.
|
|
66
|
+
Results .rq/E4 requirements.md
|
|
67
|
+
Updated requirements/tests/T1 PDF export.md
|
|
68
|
+
Updated requirements/R1 Export.md
|
|
69
|
+
Updated requirements/R2 CSV export.md
|
|
70
|
+
Updated requirements/tests/T2 CSV export.md
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Without `--recurse`, `rq test R1` runs the tests R1 links to and merges their
|
|
74
|
+
results with the results its sub-requirements record, which it does not
|
|
75
|
+
recalculate; `--recurse` reruns the tests below them too. The results come from
|
|
76
|
+
the documents' `## Status` sections, never from `.rq`.
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
PASS requirements/tests/T1 PDF export.md - 1 step
|
|
80
|
+
NOT RUN requirements/R1 Export.md - 1 of 2 links not run
|
|
81
|
+
NOT RUN requirements/R2 CSV export.md (recorded) - 1 of 1 links not run
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A requirement is:
|
|
85
|
+
|
|
86
|
+
- `PASS` when every node it links to passes;
|
|
87
|
+
- `FAIL` when one fails, or when it links to nothing, naming each failed test
|
|
88
|
+
below it with its note and execution file;
|
|
89
|
+
- `NOT RUN` otherwise: something below it has no result yet.
|
|
90
|
+
|
|
91
|
+
## Options
|
|
92
|
+
|
|
93
|
+
- `--recurse` - also run the tests of every requirement below a requirement
|
|
94
|
+
target.
|
|
95
|
+
- `--working-dir <folder>` - the working folder; the current directory by
|
|
96
|
+
default.
|
|
97
|
+
- `--requirements-dir <folder>`, `--documents-dir <folder>` - the requirements
|
|
98
|
+
folder, where ids and names are searched for, and the documents folder; see
|
|
99
|
+
[Requirements and documents folders][FD].
|
|
100
|
+
- `--name <slug>` - the slug of the execution file. By default the targets, a
|
|
101
|
+
path by its file or folder name: `rq test R10 T12` writes `E<n> R10 T12.md`.
|
|
102
|
+
- `--ai[=<agent>][:<model>]` - the AI agent of instruction steps, `claude` or
|
|
103
|
+
`copilot`, and its model, both optional: `--ai`, `--ai=claude:fable`,
|
|
104
|
+
`--ai=copilot`.
|
|
105
|
+
|
|
106
|
+
Instruction steps always use an agent: the one `--ai` names, or the first of
|
|
107
|
+
`claude` and `copilot` that is installed. Such a step may read files and run
|
|
108
|
+
commands, and is told and configured not to edit files; see [Requirements][RM]
|
|
109
|
+
for what that does not prevent. An instruction step without an agent fails.
|
|
110
|
+
Write `--ai=<agent>` with `=` when a target follows it, e.g. `rq test
|
|
111
|
+
--ai=claude R1`, so that the target is not taken for the agent. Coverage is
|
|
112
|
+
checked by [`rq coverage`][CV], not by `rq test`.
|
|
113
|
+
|
|
114
|
+
## Environment
|
|
115
|
+
|
|
116
|
+
- `RQ_AI_COMMAND` - a command line that replaces the agent. It gets the prompt
|
|
117
|
+
on standard input, and its verdict is the last line of its output that is
|
|
118
|
+
`{"result":"OK"}` or `{"result":"Fail","message":"..."}`.
|
|
119
|
+
|
|
120
|
+
[CV]: <rq coverage.md>
|
|
121
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
122
|
+
[RT]: ../../rq/docs/Requirements.md#results
|
|
123
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
124
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|