asljs-rq-cli 0.1.1 → 0.1.3
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 +44 -13
- package/README.md +21 -27
- package/dist/cli.d.ts +5 -9
- package/dist/cli.js +19 -62
- package/dist/config.d.ts +2 -2
- package/dist/config.js +15 -16
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/docs/Changing the graph.md +3 -3
- package/docs/Querying the graph.md +2 -2
- package/docs/rq agents.md +2 -2
- package/docs/rq check.md +3 -3
- package/docs/rq config.md +5 -5
- package/docs/rq coverage.md +2 -2
- package/docs/rq test.md +4 -4
- package/package.json +14 -14
- package/skills/requirements-authoring.md +2 -2
- package/skills/requirements-change.md +2 -2
- package/skills/requirements-coverage.md +2 -2
- package/bin/rq-mcp.js +0 -22
- package/dist/mcp.d.ts +0 -28
- package/dist/mcp.js +0 -70
- package/dist/view-script.d.ts +0 -41
- package/dist/view-script.js +0 -39
- package/dist/view.d.ts +0 -39
- package/dist/view.js +0 -321
- package/docs/rq view.md +0 -101
- package/docs/rq-mcp.md +0 -79
package/LICENSE.md
CHANGED
|
@@ -1,20 +1,51 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Permissive No-Derivatives License 1.0
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026 Alexandrite Software Ltd
|
|
3
|
+
Copyright (c) 2026 Alexandrite Software Ltd.
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
-
this software
|
|
7
|
-
the Software without restriction, including without limitation the rights to
|
|
8
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
-
subject to the following conditions:
|
|
6
|
+
this software (the "Software") to:
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
1. Use the Software for any purpose, including commercial purposes.
|
|
9
|
+
2. Copy and redistribute the Software, including as part of another application,
|
|
10
|
+
library, or package.
|
|
11
|
+
3. Modify the Software for private or internal use.
|
|
12
|
+
|
|
13
|
+
Subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
## 1. No Distribution of Modified Versions
|
|
16
|
+
|
|
17
|
+
Modified versions of the Software, or substantial portions thereof, must not be
|
|
18
|
+
distributed without prior written permission from the copyright holder.
|
|
19
|
+
|
|
20
|
+
Routine build transformations, including minification, transpilation, and
|
|
21
|
+
bundling, are permitted for distribution, provided they do not intentionally
|
|
22
|
+
alter the Software's functionality.
|
|
23
|
+
|
|
24
|
+
## 2. Licence and Copyright Preservation
|
|
25
|
+
|
|
26
|
+
All distributed copies of the Software must retain this copyright notice and
|
|
27
|
+
licence.
|
|
28
|
+
|
|
29
|
+
The Software itself, including copies incorporated into other applications,
|
|
30
|
+
libraries, or packages, remains subject to this licence.
|
|
31
|
+
|
|
32
|
+
The Software must not be sublicensed or redistributed under a different licence.
|
|
33
|
+
|
|
34
|
+
## 3. Use in Other Software
|
|
35
|
+
|
|
36
|
+
Applications and libraries that merely use, import, link to, or bundle the
|
|
37
|
+
Software are not considered modified versions of the Software and may be
|
|
38
|
+
distributed under any licence.
|
|
39
|
+
|
|
40
|
+
Such use, incorporation, or bundling does not grant permission to relicense the
|
|
41
|
+
Software or distribute modified versions of it.
|
|
42
|
+
|
|
43
|
+
### 4. No Warranty
|
|
14
44
|
|
|
15
45
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
46
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
18
|
-
|
|
19
|
-
IN
|
|
20
|
-
|
|
47
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
48
|
+
|
|
49
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR
|
|
50
|
+
OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS
|
|
51
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -35,10 +35,6 @@ covered by them.
|
|
|
35
35
|
`## Status` section; a failed test fails every requirement above it.
|
|
36
36
|
- `rq coverage <target>...` asks an AI agent whether each requirement's
|
|
37
37
|
sub-requirements and tests fully cover it, and records the verdict.
|
|
38
|
-
- `rq view [path]` serves the graph as a clickable diagram, each border coloured
|
|
39
|
-
by the result and drawn solid, dashed or dotted by the coverage, and each
|
|
40
|
-
document of the documents folder rendered as HTML, including documents outside
|
|
41
|
-
the requirements folder that the requirements link to.
|
|
42
38
|
- `rq agents` prints the formats and the rules every change keeps, for an AI
|
|
43
39
|
agent that edits the files without `rq`.
|
|
44
40
|
- `rq config` prints the folders, `rq.json`, the agent and the log settings, and
|
|
@@ -49,9 +45,11 @@ covered by them.
|
|
|
49
45
|
writes the text, and changes the structure with the commands.
|
|
50
46
|
|
|
51
47
|
The model and the commands themselves are functions of the [rq library][RQL].
|
|
52
|
-
This package is the `rq` command
|
|
53
|
-
|
|
54
|
-
`asljs-rq
|
|
48
|
+
This package is the `rq` command. The [rq-mcp][MCP] server, `asljs-rq-mcp`,
|
|
49
|
+
serves the same commands as MCP tools, and the [rq-srv][SRV] web server,
|
|
50
|
+
`asljs-rq-srv`, serves the graph as a clickable diagram and the documents
|
|
51
|
+
rendered and editable. An application that wants the functions without a command
|
|
52
|
+
line imports `asljs-rq` instead.
|
|
55
53
|
|
|
56
54
|
## Scope
|
|
57
55
|
|
|
@@ -67,8 +65,6 @@ an application that wants the functions without a command line imports
|
|
|
67
65
|
- Steps run in order, in the test's folder, until the first that fails. An
|
|
68
66
|
instruction step needs an AI agent, `claude` or `copilot`; the first one
|
|
69
67
|
installed is used unless `--ai` names one.
|
|
70
|
-
- The view loads Mermaid from a CDN to draw the diagram; the documents and their
|
|
71
|
-
links work without it.
|
|
72
68
|
|
|
73
69
|
## Installation
|
|
74
70
|
|
|
@@ -79,8 +75,9 @@ npm install asljs-rq-cli
|
|
|
79
75
|
## Usage
|
|
80
76
|
|
|
81
77
|
Every command takes `--loglevel <level>`, `--logfile <target>` and `--logformat
|
|
82
|
-
<format>`, or `RQ_LOG_LEVEL`, `RQ_LOG_FILE` and `RQ_LOG_FORMAT`,
|
|
83
|
-
|
|
78
|
+
<format>`, or `RQ_LOG_LEVEL`, `RQ_LOG_FILE` and `RQ_LOG_FORMAT`, or `logLevel`,
|
|
79
|
+
`logFile` and `logFormat` of `rq.json`, to log what it does, e.g. `--loglevel
|
|
80
|
+
debug --logfile stderr`; nothing is logged without them.
|
|
84
81
|
|
|
85
82
|
Build the graph with the commands, and write the statements, descriptions and
|
|
86
83
|
steps as text:
|
|
@@ -155,14 +152,8 @@ Run a single requirement and everything below it by id, from any folder:
|
|
|
155
152
|
npx rq test R1 --recurse --working-dir path/to/project
|
|
156
153
|
```
|
|
157
154
|
|
|
158
|
-
Browse the graph and the documents:
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
npx rq view requirements --port 8080
|
|
162
|
-
```
|
|
163
|
-
|
|
164
155
|
With `rq.json` at the project root, the commands default to the requirements
|
|
165
|
-
folder, and the
|
|
156
|
+
folder, and the documents folder is the whole project:
|
|
166
157
|
|
|
167
158
|
```json
|
|
168
159
|
{
|
|
@@ -172,7 +163,7 @@ folder, and the view serves the whole project:
|
|
|
172
163
|
```
|
|
173
164
|
|
|
174
165
|
```bash
|
|
175
|
-
npx rq
|
|
166
|
+
npx rq check
|
|
176
167
|
npx rq config
|
|
177
168
|
```
|
|
178
169
|
|
|
@@ -184,9 +175,8 @@ npx rq config
|
|
|
184
175
|
built.
|
|
185
176
|
- [Querying the graph][QG] and [Changing the graph][CG] - the structural
|
|
186
177
|
commands.
|
|
187
|
-
- [rq check][CK], [rq test][TS], [rq coverage][CV]
|
|
188
|
-
|
|
189
|
-
configuration.
|
|
178
|
+
- [rq check][CK], [rq test][TS], [rq coverage][CV] and [rq config][CF] -
|
|
179
|
+
checking, testing, checking coverage and the configuration.
|
|
190
180
|
- [rq agents][AG] - the instructions for an AI agent that edits the files
|
|
191
181
|
without `rq`.
|
|
192
182
|
- [rq-mcp][MC] - the MCP server with a tool per command.
|
|
@@ -197,6 +187,8 @@ Questions and bugs: [asljs/issues][IS].
|
|
|
197
187
|
## Related packages
|
|
198
188
|
|
|
199
189
|
- [rq library][RQL] - the requirements model and the commands as functions.
|
|
190
|
+
- [asljs-rq-mcp][MCP] - the `rq-mcp` MCP server.
|
|
191
|
+
- [asljs-rq-srv][SRV] - the `rq-srv` web server; see [rq-srv][VW].
|
|
200
192
|
- `asljs-part` defines project artefacts in markdown and checks them with rules.
|
|
201
193
|
|
|
202
194
|
## License
|
|
@@ -210,11 +202,13 @@ MIT
|
|
|
210
202
|
[CK]: <docs/rq check.md>
|
|
211
203
|
[CV]: <docs/rq coverage.md>
|
|
212
204
|
[IS]: https://github.com/AlexandriteSoftware/asljs/issues
|
|
213
|
-
[MC]: docs/rq-mcp.md
|
|
205
|
+
[MC]: ../rq-mcp/docs/rq-mcp.md
|
|
206
|
+
[MCP]: ../rq-mcp/README.md
|
|
214
207
|
[QG]: <docs/Querying the graph.md>
|
|
215
|
-
[RF]:
|
|
216
|
-
[RM]:
|
|
217
|
-
[RQL]:
|
|
208
|
+
[RF]: <../rq/docs/Requirement files.md>
|
|
209
|
+
[RM]: ../rq/docs/Requirements.md
|
|
210
|
+
[RQL]: ../rq/README.md
|
|
218
211
|
[SK]: skills
|
|
212
|
+
[SRV]: ../rq-srv/README.md
|
|
219
213
|
[TS]: <docs/rq test.md>
|
|
220
|
-
[VW]:
|
|
214
|
+
[VW]: ../rq-srv/docs/rq-srv.md
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type Folders, Io } from 'asljs-rq';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { Server } from 'node:http';
|
|
4
3
|
/**
|
|
5
4
|
* What a run of the command line leaves: its exit code, and the Io of the
|
|
6
5
|
* command, with `--working-dir`, `--requirements-dir` and
|
|
@@ -19,20 +18,17 @@ export interface CliState {
|
|
|
19
18
|
* The `rq` command line, not yet run: the program, and the state its
|
|
20
19
|
* actions set.
|
|
21
20
|
*/
|
|
22
|
-
export declare function createCli(args: string[], io: Io
|
|
21
|
+
export declare function createCli(args: string[], io: Io): {
|
|
23
22
|
cli: Command;
|
|
24
23
|
state: CliState;
|
|
25
24
|
};
|
|
26
25
|
/**
|
|
27
|
-
* Runs the `rq` command line and returns the exit code.
|
|
28
|
-
* returns once the server listens, and adds it to `servers`; it serves until
|
|
29
|
-
* whoever passed `servers` closes it.
|
|
26
|
+
* Runs the `rq` command line and returns the exit code.
|
|
30
27
|
*/
|
|
31
|
-
export declare function runCli(args: string[], io: Io
|
|
28
|
+
export declare function runCli(args: string[], io: Io): Promise<number>;
|
|
32
29
|
/**
|
|
33
30
|
* The `rq` executable: runs the command line with a logger provider made
|
|
34
|
-
* from `--loglevel`, `--logfile`, `--logformat
|
|
35
|
-
*
|
|
36
|
-
* `view` started serves until SIGINT or SIGTERM first.
|
|
31
|
+
* from `--loglevel`, `--logfile`, `--logformat`, the `RQ_LOG_` variables and
|
|
32
|
+
* `rq.json` (`runMain`), and disposes it before it returns the exit code.
|
|
37
33
|
*/
|
|
38
34
|
export declare function main(args: string[], io: Io): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { AI_AGENTS, parseAgentSpec } from 'asljs-agents';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { execAdd, execAgents, execBacklinks, execCheck, execCoverage, execLink, execLinks, execList, execLog, execMove, execRemove, execTest, execToJson, execUnlink, getLogger, resolveFolders } from 'asljs-rq';
|
|
2
|
+
import { commandLine, messageOf, postProcess, runMain, takeWritten } from 'asljs-appbase';
|
|
3
|
+
import { CONFIG_FILE, execAdd, execAgents, execBacklinks, execCheck, execCoverage, execLink, execLinks, execList, execLog, execMove, execRemove, execTest, execToJson, execUnlink, getLogger, resolveFolders } from 'asljs-rq';
|
|
5
4
|
import { Command, CommanderError } from 'commander';
|
|
6
5
|
import path from 'node:path';
|
|
7
6
|
import { execConfig } from './config.js';
|
|
8
|
-
import { execView } from './view.js';
|
|
9
7
|
const WORKING_DIR = 'The folder to work in: paths resolve against it, rq.json is looked for from it up, and its .rq folder holds the results; the current directory by default';
|
|
10
8
|
const REQUIREMENTS_DIR = 'The folder of the requirements: the default path, and where ids and .md names are searched for; requirementsDir of rq.json, else the working folder';
|
|
11
|
-
const DOCUMENTS_DIR = 'The folder of every document, containing the requirements folder: what
|
|
9
|
+
const DOCUMENTS_DIR = 'The folder of every document, containing the requirements folder: what rq-srv serves, and where backlinks and links to rewrite are searched for; documentsDir of rq.json, else the requirements folder';
|
|
12
10
|
/**
|
|
13
11
|
* The `rq` command line, not yet run: the program, and the state its
|
|
14
12
|
* actions set.
|
|
15
13
|
*/
|
|
16
|
-
export function createCli(args, io
|
|
14
|
+
export function createCli(args, io) {
|
|
17
15
|
const state = { exitCode: 0,
|
|
18
16
|
io,
|
|
19
17
|
folders: null };
|
|
@@ -23,15 +21,9 @@ export function createCli(args, io, servers = []) {
|
|
|
23
21
|
: JSON.stringify(arg))]
|
|
24
22
|
.join(' ');
|
|
25
23
|
const cli = new Command();
|
|
26
|
-
cli.name('rq')
|
|
27
|
-
.description('AI-assisted requirements management: test and
|
|
28
|
-
.helpCommand(false)
|
|
29
|
-
.configureOutput({ writeOut: value => io.stdout.write(value),
|
|
30
|
-
writeErr: value => io.stderr.write(value) })
|
|
31
|
-
.exitOverride()
|
|
32
|
-
.option('--loglevel <level>', 'Log level: trace, debug, information, warning, error')
|
|
33
|
-
.option('--logfile <target>', 'Where logs go: a file path, stdout or stderr')
|
|
34
|
-
.option('--logformat <format>', 'Log format: auto, json, text or pretty')
|
|
24
|
+
commandLine(cli.name('rq')
|
|
25
|
+
.description('AI-assisted requirements management: test and check requirements and tests written in markdown.')
|
|
26
|
+
.helpCommand(false), io)
|
|
35
27
|
.hook('preAction', async (_cli, action) => {
|
|
36
28
|
const options = action.opts();
|
|
37
29
|
const cwd = options.workingDir === undefined
|
|
@@ -40,8 +32,7 @@ export function createCli(args, io, servers = []) {
|
|
|
40
32
|
state.folders =
|
|
41
33
|
await resolveFolders(cwd, options);
|
|
42
34
|
// A folder left to its default stays unset, so that a command can
|
|
43
|
-
// tell it from one that was given
|
|
44
|
-
// path then.
|
|
35
|
+
// tell it from one that was given.
|
|
45
36
|
const given = (setting) => setting.source === 'default'
|
|
46
37
|
? undefined
|
|
47
38
|
: setting.value;
|
|
@@ -80,23 +71,6 @@ export function createCli(args, io, servers = []) {
|
|
|
80
71
|
? undefined
|
|
81
72
|
: parseAgentSpec(options.ai) });
|
|
82
73
|
});
|
|
83
|
-
cli.command('view')
|
|
84
|
-
.description('Serve the requirements graph and the rendered documents over HTTP')
|
|
85
|
-
.argument('[path]', 'A requirement file, or a folder of requirements; the requirements folder by default')
|
|
86
|
-
.option('--port <port>', 'Port to listen on, exactly; 0 picks a free one. By default the first free port from 3000 on')
|
|
87
|
-
.action(async (target, options) => {
|
|
88
|
-
const port = options.port === undefined
|
|
89
|
-
? undefined
|
|
90
|
-
: Number(options.port);
|
|
91
|
-
if (port !== undefined
|
|
92
|
-
&& (!Number.isInteger(port)
|
|
93
|
-
|| port < 0
|
|
94
|
-
|| port > 65535)) {
|
|
95
|
-
throw new Error(`Invalid port: ${options.port}`);
|
|
96
|
-
}
|
|
97
|
-
servers.push(await execView(state.io, { target,
|
|
98
|
-
port }));
|
|
99
|
-
});
|
|
100
74
|
cli.command('check')
|
|
101
75
|
.description('Check the structure of the graph and its documents without running anything')
|
|
102
76
|
.argument('[path]', 'A requirement file, or a folder of requirements; the requirements folder by default')
|
|
@@ -247,12 +221,10 @@ export function createCli(args, io, servers = []) {
|
|
|
247
221
|
state };
|
|
248
222
|
}
|
|
249
223
|
/**
|
|
250
|
-
* Runs the `rq` command line and returns the exit code.
|
|
251
|
-
* returns once the server listens, and adds it to `servers`; it serves until
|
|
252
|
-
* whoever passed `servers` closes it.
|
|
224
|
+
* Runs the `rq` command line and returns the exit code.
|
|
253
225
|
*/
|
|
254
|
-
export async function runCli(args, io
|
|
255
|
-
const { cli, state } = createCli(args, io
|
|
226
|
+
export async function runCli(args, io) {
|
|
227
|
+
const { cli, state } = createCli(args, io);
|
|
256
228
|
if (args.length === 0) {
|
|
257
229
|
cli.outputHelp();
|
|
258
230
|
return 0;
|
|
@@ -267,14 +239,12 @@ export async function runCli(args, io, servers = []) {
|
|
|
267
239
|
if (error instanceof CommanderError) {
|
|
268
240
|
return error.exitCode;
|
|
269
241
|
}
|
|
270
|
-
io.stderr.write(`${error
|
|
271
|
-
? error.message
|
|
272
|
-
: String(error)}\n`);
|
|
242
|
+
io.stderr.write(`${messageOf(error)}\n`);
|
|
273
243
|
state.exitCode = 1;
|
|
274
244
|
}
|
|
275
245
|
try {
|
|
276
246
|
const processed = await postProcess({ ...state.io,
|
|
277
|
-
logger: getLogger(state.io, 'rq.post-process') }, takeWritten(),
|
|
247
|
+
logger: getLogger(state.io, 'rq.post-process') }, takeWritten(), CONFIG_FILE);
|
|
278
248
|
logger.debug({ exitCode: state.exitCode,
|
|
279
249
|
postProcessing: processed }, 'command finished');
|
|
280
250
|
return state.exitCode === 0
|
|
@@ -282,9 +252,7 @@ export async function runCli(args, io, servers = []) {
|
|
|
282
252
|
: state.exitCode;
|
|
283
253
|
}
|
|
284
254
|
catch (error) {
|
|
285
|
-
io.stderr.write(`${error
|
|
286
|
-
? error.message
|
|
287
|
-
: String(error)}\n`);
|
|
255
|
+
io.stderr.write(`${messageOf(error)}\n`);
|
|
288
256
|
return 1;
|
|
289
257
|
}
|
|
290
258
|
}
|
|
@@ -294,22 +262,11 @@ function collect(value, previous) {
|
|
|
294
262
|
}
|
|
295
263
|
/**
|
|
296
264
|
* The `rq` executable: runs the command line with a logger provider made
|
|
297
|
-
* from `--loglevel`, `--logfile`, `--logformat
|
|
298
|
-
*
|
|
299
|
-
* `view` started serves until SIGINT or SIGTERM first.
|
|
265
|
+
* from `--loglevel`, `--logfile`, `--logformat`, the `RQ_LOG_` variables and
|
|
266
|
+
* `rq.json` (`runMain`), and disposes it before it returns the exit code.
|
|
300
267
|
*/
|
|
301
268
|
export async function main(args, io) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const exitCode = await runCli(args, { ...io,
|
|
306
|
-
loggerProvider }, servers);
|
|
307
|
-
for (const server of servers) {
|
|
308
|
-
await untilStopped(server);
|
|
309
|
-
}
|
|
310
|
-
return exitCode;
|
|
311
|
-
}
|
|
312
|
-
finally {
|
|
313
|
-
await loggerProvider.dispose();
|
|
314
|
-
}
|
|
269
|
+
return await runMain(args, io, { prefix: 'RQ_LOG_',
|
|
270
|
+
configFile: CONFIG_FILE }, async (loggerProvider) => await runCli(args, { ...io,
|
|
271
|
+
loggerProvider }));
|
|
315
272
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -41,11 +41,11 @@ export interface Configuration {
|
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* A log setting and where it comes from: its option, its `RQ_LOG_`
|
|
44
|
-
* variable, or the default.
|
|
44
|
+
* variable, `rq.json`, or the default.
|
|
45
45
|
*/
|
|
46
46
|
export interface LogSetting {
|
|
47
47
|
value: string;
|
|
48
|
-
source: 'option' | 'environment' | 'default';
|
|
48
|
+
source: 'option' | 'environment' | 'rq.json' | 'default';
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* Prints the configuration: the folders and where they come from, the
|
package/dist/config.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { AI_AGENTS } from 'asljs-agents';
|
|
2
2
|
import { readLoggerOptions } from 'asljs-logging';
|
|
3
|
-
import {
|
|
4
|
-
import { CONFIG_FILE } from 'asljs-rq';
|
|
5
|
-
import { createRequire } from 'node:module';
|
|
3
|
+
import { configLogging, configString, packageVersion } from 'asljs-appbase';
|
|
6
4
|
/**
|
|
7
5
|
* The environment variables `rq` reads.
|
|
8
6
|
*/
|
|
@@ -26,33 +24,37 @@ export async function execConfig(io, options) {
|
|
|
26
24
|
* The configuration `rq` runs with in the working folder of `io`.
|
|
27
25
|
*/
|
|
28
26
|
export async function readConfiguration(io, folders, args) {
|
|
29
|
-
const found = await findConfig(io.cwd, CONFIG_FILE);
|
|
30
27
|
const environment = Object.fromEntries(ENVIRONMENT_VARIABLES.map(name => [name,
|
|
31
28
|
io.env[name] || null]));
|
|
32
29
|
const overrides = readLoggerOptions(args);
|
|
33
|
-
const
|
|
30
|
+
const configured = configLogging(folders.config);
|
|
31
|
+
const pick = (option, variable, fromFile, fallback) => option !== undefined
|
|
34
32
|
? { value: option,
|
|
35
33
|
source: 'option' }
|
|
36
34
|
: environment[variable] !== null
|
|
37
35
|
? { value: environment[variable],
|
|
38
36
|
source: 'environment' }
|
|
39
|
-
:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
: fromFile !== undefined
|
|
38
|
+
? { value: fromFile,
|
|
39
|
+
source: 'rq.json' }
|
|
40
|
+
: { value: fallback,
|
|
41
|
+
source: 'default' };
|
|
42
|
+
const file = pick(overrides.file, 'RQ_LOG_FILE', configured.file, 'stdout');
|
|
43
|
+
return { version: packageVersion(import.meta.url),
|
|
43
44
|
workingDir: io.cwd,
|
|
44
|
-
configFile: folders.
|
|
45
|
+
configFile: folders.config.file,
|
|
45
46
|
requirementsDir: folders.requirementsDir,
|
|
46
47
|
documentsDir: folders.documentsDir,
|
|
47
|
-
markdownPostProcessing:
|
|
48
|
+
markdownPostProcessing: configString(folders.config, 'markdownPostProcessing')
|
|
49
|
+
?.trim()
|
|
48
50
|
|| null,
|
|
49
51
|
agent: { command: environment.RQ_AI_COMMAND,
|
|
50
52
|
agents: [...AI_AGENTS] },
|
|
51
|
-
log: { level: pick(overrides.level, 'RQ_LOG_LEVEL', file.source === 'default'
|
|
53
|
+
log: { level: pick(overrides.level, 'RQ_LOG_LEVEL', configured.level, file.source === 'default'
|
|
52
54
|
? 'silent'
|
|
53
55
|
: 'information'),
|
|
54
56
|
file,
|
|
55
|
-
format: pick(overrides.format, 'RQ_LOG_FORMAT', 'auto') },
|
|
57
|
+
format: pick(overrides.format, 'RQ_LOG_FORMAT', configured.format, 'auto') },
|
|
56
58
|
environment };
|
|
57
59
|
}
|
|
58
60
|
function describe(configuration) {
|
|
@@ -73,6 +75,3 @@ function describe(configuration) {
|
|
|
73
75
|
...Object.entries(configuration.environment).map(([name, value]) => ` ${name}=${value ?? ''}`)];
|
|
74
76
|
return `${lines.join('\n')}\n`;
|
|
75
77
|
}
|
|
76
|
-
function packageVersion() {
|
|
77
|
-
return createRequire(import.meta.url)('../package.json').version;
|
|
78
|
-
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -103,6 +103,6 @@ as [`rq test`][TS] does, with `--time` as the `Updated` of the test and of every
|
|
|
103
103
|
requirement recalculated above it.
|
|
104
104
|
|
|
105
105
|
[TS]: <rq test.md>
|
|
106
|
-
[RM]:
|
|
107
|
-
[FD]:
|
|
108
|
-
[WF]:
|
|
106
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
107
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
108
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
|
@@ -67,5 +67,5 @@ as JSON:
|
|
|
67
67
|
`body` (the text between the heading and the first section), `links` (the
|
|
68
68
|
paths its `## Implementation` links to), `steps`, `result` and `coverage`.
|
|
69
69
|
|
|
70
|
-
[RM]:
|
|
71
|
-
[FD]:
|
|
70
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
71
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
package/docs/rq agents.md
CHANGED
|
@@ -25,5 +25,5 @@ Use it where `rq` is neither installed for the agent nor served to it by
|
|
|
25
25
|
npx rq agents > .github/instructions/requirements.instructions.md
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
[MC]: rq-mcp.md
|
|
29
|
-
[RF]:
|
|
28
|
+
[MC]: ../../rq-mcp/docs/rq-mcp.md
|
|
29
|
+
[RF]: <../../rq/docs/Requirement files.md>
|
package/docs/rq check.md
CHANGED
|
@@ -27,6 +27,6 @@ OK 2 requirements, 2 tests
|
|
|
27
27
|
Run it after editing documents by hand, and before `rq test`, which runs the
|
|
28
28
|
steps.
|
|
29
29
|
|
|
30
|
-
[RM]:
|
|
31
|
-
[FD]:
|
|
32
|
-
[WF]:
|
|
30
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
31
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
32
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
package/docs/rq config.md
CHANGED
|
@@ -41,8 +41,8 @@ environment:
|
|
|
41
41
|
needs one.
|
|
42
42
|
- `logLevel`, `logFile`, `logFormat` - the log settings, and where each comes
|
|
43
43
|
from: `option` (`--loglevel`, `--logfile`, `--logformat`), `environment`
|
|
44
|
-
(`RQ_LOG_LEVEL`, `RQ_LOG_FILE`, `RQ_LOG_FORMAT`)
|
|
45
|
-
repository's logging rules.
|
|
44
|
+
(`RQ_LOG_LEVEL`, `RQ_LOG_FILE`, `RQ_LOG_FORMAT`), `rq.json` (`logLevel`,
|
|
45
|
+
`logFile`, `logFormat`) or `default`. See the repository's logging rules.
|
|
46
46
|
- `environment` - each variable `rq` reads, and its value, empty when it is not
|
|
47
47
|
set.
|
|
48
48
|
|
|
@@ -55,6 +55,6 @@ environment:
|
|
|
55
55
|
requirements folder outside the documents folder is an error, here as in every
|
|
56
56
|
command.
|
|
57
57
|
|
|
58
|
-
[CF]:
|
|
59
|
-
[FD]:
|
|
60
|
-
[WF]:
|
|
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
|
package/docs/rq coverage.md
CHANGED
|
@@ -75,6 +75,6 @@ only.
|
|
|
75
75
|
default. No agent is an error. `RQ_AI_COMMAND` replaces the agent, as for
|
|
76
76
|
[`rq test`][TS].
|
|
77
77
|
|
|
78
|
-
[FD]:
|
|
78
|
+
[FD]: ../../rq/docs/Requirements.md#requirements-and-documents-folders
|
|
79
79
|
[TS]: <rq test.md>
|
|
80
|
-
[WF]:
|
|
80
|
+
[WF]: ../../rq/docs/Requirements.md#working-folder
|
package/docs/rq test.md
CHANGED
|
@@ -118,7 +118,7 @@ checked by [`rq coverage`][CV], not by `rq test`.
|
|
|
118
118
|
`{"result":"OK"}` or `{"result":"Fail","message":"..."}`.
|
|
119
119
|
|
|
120
120
|
[CV]: <rq coverage.md>
|
|
121
|
-
[RM]:
|
|
122
|
-
[RT]:
|
|
123
|
-
[FD]:
|
|
124
|
-
[WF]:
|
|
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
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asljs-rq-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "The rq command line over asljs-rq: query, change, check and test requirements.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"asljs": {
|
|
7
|
+
"type": "app"
|
|
8
|
+
},
|
|
6
9
|
"main": "dist/index.js",
|
|
7
10
|
"types": "dist/index.d.ts",
|
|
8
11
|
"exports": {
|
|
@@ -14,28 +17,27 @@
|
|
|
14
17
|
"files": [
|
|
15
18
|
"dist/**",
|
|
16
19
|
"bin/**",
|
|
17
|
-
"docs
|
|
20
|
+
"docs/**",
|
|
18
21
|
"skills/*.md",
|
|
19
22
|
"README.md",
|
|
20
23
|
"LICENSE.md"
|
|
21
24
|
],
|
|
22
25
|
"bin": {
|
|
23
|
-
"rq": "bin/rq.js"
|
|
24
|
-
"rq-mcp": "bin/rq-mcp.js"
|
|
26
|
+
"rq": "bin/rq.js"
|
|
25
27
|
},
|
|
26
28
|
"scripts": {
|
|
27
29
|
"flint": "toolkit flint",
|
|
28
30
|
"clean": "toolkit clean",
|
|
29
|
-
"build": "tsc -p tsconfig.build.json",
|
|
30
|
-
"build:dist": "tsc -p tsconfig.dist.json",
|
|
31
|
-
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
31
|
+
"build": "npm run codegen --if-present && tsc -p tsconfig.build.json",
|
|
32
|
+
"build:dist": "npm run codegen --if-present && tsc -p tsconfig.dist.json",
|
|
33
|
+
"typecheck": "npm run codegen --if-present && tsc -p tsconfig.build.json --noEmit",
|
|
32
34
|
"guard:clean-git": "toolkit ensure-clean-working-directory",
|
|
33
35
|
"prepack": "npm run clean && npm run build:dist && npm run build && npm run test && npm run guard:clean-git",
|
|
34
36
|
"postpublish": "toolkit tag-release-revision",
|
|
35
37
|
"test": "node --test --enable-source-maps \"build/**/*.test.js\"",
|
|
36
38
|
"test:watch": "node --watch --test \"build/**/*.test.js\"",
|
|
37
39
|
"release:patch": "toolkit release-patch",
|
|
38
|
-
"all": "npm run clean && npm run
|
|
40
|
+
"all": "npm run clean && npm run build:dist && npm run flint && npm run typecheck && npm run build && npm run test"
|
|
39
41
|
},
|
|
40
42
|
"keywords": [
|
|
41
43
|
"requirements",
|
|
@@ -43,7 +45,6 @@
|
|
|
43
45
|
"test",
|
|
44
46
|
"markdown",
|
|
45
47
|
"ai",
|
|
46
|
-
"mcp",
|
|
47
48
|
"cli"
|
|
48
49
|
],
|
|
49
50
|
"homepage": "https://github.com/AlexandriteSoftware/asljs#readme",
|
|
@@ -55,13 +56,12 @@
|
|
|
55
56
|
"url": "git+https://github.com/AlexandriteSoftware/asljs.git"
|
|
56
57
|
},
|
|
57
58
|
"author": "\"Alex Netkachov\" <alex.netkachov@gmail.com>",
|
|
58
|
-
"license": "
|
|
59
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
59
60
|
"dependencies": {
|
|
60
61
|
"asljs-agents": "^0.1.0",
|
|
61
62
|
"asljs-logging": "^0.1.2",
|
|
62
|
-
"asljs-
|
|
63
|
-
"asljs-
|
|
64
|
-
"asljs-rq": "^0.1.4",
|
|
63
|
+
"asljs-appbase": "^0.1.3",
|
|
64
|
+
"asljs-rq": "^0.1.6",
|
|
65
65
|
"commander": "^15.0.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
@@ -78,5 +78,5 @@ analysis of an incomplete requirement.
|
|
|
78
78
|
[RC]: requirements-coverage.md
|
|
79
79
|
|
|
80
80
|
[CG]: <../docs/Changing the graph.md>
|
|
81
|
-
[RF]:
|
|
82
|
-
[RM]:
|
|
81
|
+
[RF]: <../../rq/docs/Requirement files.md>
|
|
82
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
@@ -47,5 +47,5 @@ analysis in the requirement's `## Coverage` section.
|
|
|
47
47
|
[RC]: requirements-coverage.md
|
|
48
48
|
|
|
49
49
|
[RA]: requirements-authoring.md
|
|
50
|
-
[RF]:
|
|
51
|
-
[RM]:
|
|
50
|
+
[RF]: <../../rq/docs/Requirement files.md>
|
|
51
|
+
[RM]: ../../rq/docs/Requirements.md
|
|
@@ -44,5 +44,5 @@ Use it to review the decomposition: a link that covers no statement can be
|
|
|
44
44
|
unlinked, and a statement covered only by a vague test deserves a sharper one.
|
|
45
45
|
|
|
46
46
|
[RA]: requirements-authoring.md
|
|
47
|
-
[RF]:
|
|
48
|
-
[RM]:
|
|
47
|
+
[RF]: <../../rq/docs/Requirement files.md>
|
|
48
|
+
[RM]: ../../rq/docs/Requirements.md
|