@sdods/cli 0.2.0 → 0.2.1
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/README.md +19 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/commands/analyze.js +0 -30
- package/dist/commands/browsers.js +1 -1
- package/dist/commands/coverage.js +1 -1
- package/dist/commands/tokens.js +17 -10
- package/dist/commands/users.js +2 -2
- package/dist/context.js +7 -0
- package/package.json +8 -8
package/dist/commands/analyze.js
CHANGED
|
@@ -169,41 +169,11 @@ function printReport(r) {
|
|
|
169
169
|
out(`${icon} ${pc.bold(c.title)} — ${c.detail}${c.fix ? pc.dim(`\n → ${c.fix}`) : ''}`);
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
-
/**
|
|
173
|
-
* Why each module exists. Modules are inferred by fusing several signals - the file that defines
|
|
174
|
-
* a route, the monorepo workspace, a domain directory, an OpenAPI tag - so the winning signal and
|
|
175
|
-
* its confidence are the part a reviewer actually needs to judge the proposal.
|
|
176
|
-
*/
|
|
177
|
-
function printModules(p) {
|
|
178
|
-
const mods = p.detectedModules ?? [];
|
|
179
|
-
if (!mods.length)
|
|
180
|
-
return;
|
|
181
|
-
out(pc.dim('--- modules ---'));
|
|
182
|
-
const w = Math.max(6, ...mods.map((m) => m.name.length));
|
|
183
|
-
for (const m of mods) {
|
|
184
|
-
const targets = [
|
|
185
|
-
m.routes ? `${m.routes} route${m.routes === 1 ? '' : 's'}` : '',
|
|
186
|
-
m.endpoints ? `${m.endpoints} endpoint${m.endpoints === 1 ? '' : 's'}` : '',
|
|
187
|
-
]
|
|
188
|
-
.filter(Boolean)
|
|
189
|
-
.join(', ');
|
|
190
|
-
const from = m.evidence[0]?.file;
|
|
191
|
-
out(` ${m.name.padEnd(w)} ${pc.dim(m.confidence.toFixed(2))} ${targets.padEnd(22)}` +
|
|
192
|
-
`${pc.dim(m.signals.join('+'))}${from ? pc.dim(` ← ${from}`) : ''}`);
|
|
193
|
-
}
|
|
194
|
-
const ignored = p.ignoredTargets ?? [];
|
|
195
|
-
if (ignored.length) {
|
|
196
|
-
out(pc.dim(`--- skipped (${ignored.length}) ---`));
|
|
197
|
-
for (const i of ignored)
|
|
198
|
-
out(pc.dim(` ${i.target.padEnd(20)} ${i.reason}`));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
172
|
function printProposal(p) {
|
|
202
173
|
heading(`Proposed project: ${p.slug}`);
|
|
203
174
|
out(pc.dim(`envs: ${Object.keys(p.envYamls).join(', ')} · starter features: ${Object.keys(p.starterFeatures).length} · coverage targets: ${p.coverageMap.length}`));
|
|
204
175
|
for (const n of p.notes)
|
|
205
176
|
warn(n);
|
|
206
|
-
printModules(p);
|
|
207
177
|
out(pc.dim('--- sdods.project.yaml ---'));
|
|
208
178
|
const lines = p.projectYaml.split('\n');
|
|
209
179
|
out(lines.slice(0, 60).join('\n'));
|
|
@@ -76,7 +76,7 @@ export function register(program) {
|
|
|
76
76
|
});
|
|
77
77
|
browsers
|
|
78
78
|
.command('list')
|
|
79
|
-
.description('Show which browsers are installed and where')
|
|
79
|
+
.description('Show which browsers are installed and where; exits 1 if any is missing')
|
|
80
80
|
.option('-p, --project <slug>', 'limit to the browsers declared by a project')
|
|
81
81
|
.action(async (opts, cmd) => {
|
|
82
82
|
const ctx = createContext(cmd);
|
|
@@ -4,7 +4,7 @@ import { heading, json, out, table } from '../ui.js';
|
|
|
4
4
|
export function register(program) {
|
|
5
5
|
program
|
|
6
6
|
.command('coverage')
|
|
7
|
-
.description('Route, endpoint and role coverage by scenarios, split by suite tag')
|
|
7
|
+
.description('Route, endpoint and role coverage by scenarios, split by suite tag; exits 1 if any module has no scenarios')
|
|
8
8
|
.requiredOption('-p, --project <slug>', 'project slug')
|
|
9
9
|
.option('-e, --env <name>', 'environment (for the OpenAPI spec and API base URL)')
|
|
10
10
|
.option('--openapi [file]', 'include endpoints from the OpenAPI spec (env api.openapi or a file)')
|
package/dist/commands/tokens.js
CHANGED
|
@@ -86,21 +86,28 @@ export function register(program) {
|
|
|
86
86
|
tokens
|
|
87
87
|
.command('revoke <id>')
|
|
88
88
|
.description('Revoke a token by id')
|
|
89
|
-
.action(async (id, cmd) => {
|
|
89
|
+
.action(async (id, _opts, cmd) => {
|
|
90
90
|
const ctx = createContext(cmd);
|
|
91
91
|
const db = await import('@sdods/db');
|
|
92
92
|
const adb = await db.openDb();
|
|
93
93
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
// Reporting success for an id that does not exist reads as "the token is gone" when
|
|
95
|
+
// nothing was checked at all — an operator revoking a leaked token needs the difference.
|
|
96
|
+
const revoked = await db.revokeApiToken(adb.db, id);
|
|
97
|
+
if (revoked) {
|
|
98
|
+
await db.audit(adb.db, {
|
|
99
|
+
actorType: 'cli',
|
|
100
|
+
action: 'token.revoke',
|
|
101
|
+
targetType: 'api_token',
|
|
102
|
+
targetId: id,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
101
105
|
if (ctx.opts.json)
|
|
102
|
-
return json({ id, revoked
|
|
103
|
-
|
|
106
|
+
return json({ id, revoked });
|
|
107
|
+
if (revoked)
|
|
108
|
+
ok(`Revoked ${id}`);
|
|
109
|
+
else
|
|
110
|
+
warn(`No live token with id ${id}; nothing to revoke.`);
|
|
104
111
|
}
|
|
105
112
|
finally {
|
|
106
113
|
await adb.close();
|
package/dist/commands/users.js
CHANGED
|
@@ -88,7 +88,7 @@ export function register(program) {
|
|
|
88
88
|
users
|
|
89
89
|
.command('set-role <username> <role>')
|
|
90
90
|
.description('Change a platform role (viewer | editor | admin)')
|
|
91
|
-
.action(async (username, role, cmd) => {
|
|
91
|
+
.action(async (username, role, _opts, cmd) => {
|
|
92
92
|
const ctx = createContext(cmd);
|
|
93
93
|
const adb = await openDb();
|
|
94
94
|
try {
|
|
@@ -112,7 +112,7 @@ export function register(program) {
|
|
|
112
112
|
users
|
|
113
113
|
.command('deactivate <username>')
|
|
114
114
|
.description('Deactivate a user (sessions and tokens stop working)')
|
|
115
|
-
.action(async (username, cmd) => {
|
|
115
|
+
.action(async (username, _opts, cmd) => {
|
|
116
116
|
const ctx = createContext(cmd);
|
|
117
117
|
const adb = await openDb();
|
|
118
118
|
try {
|
package/dist/context.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { ProjectRegistry, setLogJson, setLogLevel } from '@sdods/core';
|
|
2
2
|
export function globalOptions(cmd) {
|
|
3
|
+
// Commander calls an action with (...positionalArgs, options, command). A callback that forgets
|
|
4
|
+
// the options parameter receives the options object here instead of the Command, and the failure
|
|
5
|
+
// surfaced as an unhelpful "root.opts is not a function".
|
|
6
|
+
if (typeof cmd?.opts !== 'function' || !('parent' in cmd)) {
|
|
7
|
+
throw new Error('createContext expected the Commander Command. An action callback takes ' +
|
|
8
|
+
'(...args, options, command) — the options parameter is probably missing.');
|
|
9
|
+
}
|
|
3
10
|
let root = cmd;
|
|
4
11
|
while (root.parent)
|
|
5
12
|
root = root.parent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdods/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "SDODS command line: run, record, analyze, agents, MCP server, scheduler and the web server.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "SDODS <admin@sdods.com>",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"node": ">=22"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@sdods/contracts": "0.2.
|
|
27
|
-
"@sdods/core": "0.2.
|
|
26
|
+
"@sdods/contracts": "0.2.1",
|
|
27
|
+
"@sdods/core": "0.2.1",
|
|
28
28
|
"commander": "^15.0.0",
|
|
29
29
|
"execa": "^10.0.1",
|
|
30
30
|
"picocolors": "^1.1.1",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"zod": "^4.5.4",
|
|
34
34
|
"@playwright/test": "^1.62.1",
|
|
35
35
|
"playwright-core": "^1.62.1",
|
|
36
|
-
"@sdods/integrations": "0.2.
|
|
37
|
-
"@sdods/mcp": "0.2.
|
|
38
|
-
"@sdods/agents": "0.2.
|
|
39
|
-
"@sdods/db": "0.2.
|
|
36
|
+
"@sdods/integrations": "0.2.1",
|
|
37
|
+
"@sdods/mcp": "0.2.1",
|
|
38
|
+
"@sdods/agents": "0.2.1",
|
|
39
|
+
"@sdods/db": "0.2.1",
|
|
40
40
|
"csv-parse": "^7.0.2",
|
|
41
|
-
"@sdods/server": "0.2.
|
|
41
|
+
"@sdods/server": "0.2.1"
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://sdods.com",
|
|
44
44
|
"bugs": {
|