@tityra/cli 1.0.0 → 1.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/CHANGELOG.md +15 -0
- package/README.md +49 -11
- package/dist/commands/audits.js +2 -1
- package/dist/commands/projects.js +20 -3
- package/dist/schema/writeSchema.js +56 -20
- package/dist/services/apiClient.js +4 -2
- package/dist/services/brandingService.js +1 -1
- package/dist/services/outputService.js +11 -3
- package/dist/services/workspaceService.js +14 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
- Clarify that audit requests use explicit authorisation and validated scope without a second manual staff authority confirmation, while retaining report quality and commercial checks.
|
|
6
|
+
- Add selected-project monitoring reads and confirmed enable, pause, resume and scope changes.
|
|
7
|
+
- Require a new explicit `monitoring:write` grant for changes, preserving revision checks and stable retry keys.
|
|
8
|
+
- Explain that confirmed website and scope authorisation enables monitoring without separate administrator approval.
|
|
9
|
+
- Expose monitoring settings in the interactive project menu without adding write permissions.
|
|
10
|
+
- Show server-provided pricing status, including genuine included weekly audits, in audit tables.
|
|
11
|
+
- Clarify the first-request schedule, automatic admission of overdue audits and organisation Billing Profile eligibility.
|
|
12
|
+
- Clarify Scale and Enterprise workspace plans, monthly and annual Enterprise pricing and
|
|
13
|
+
per-project weekly AX Audit monitoring in the package documentation.
|
|
14
|
+
- Specify that Expert Review always follows the separately paid request and checkout flow.
|
|
15
|
+
- Explain that AX Audit and Expert Review requests submitted with `audits create` are separately priced;
|
|
16
|
+
billing assignment and subscription changes stay in the Tityra application.
|
|
17
|
+
|
|
3
18
|
## 1.0.0
|
|
4
19
|
|
|
5
20
|
- Stable `@tityra/cli` release, version `1.0.0`, distributed through npm's `latest` tag.
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ The CLI is an API client for the Tityra service. It uses the same account permis
|
|
|
6
6
|
|
|
7
7
|
## Project status
|
|
8
8
|
|
|
9
|
-
Version `1.
|
|
9
|
+
Version `1.1.0` adds project monitoring commands and included-audit pricing status. Stable releases use npm's `latest` tag; check the [npm package page](https://www.npmjs.com/package/@tityra/cli) for the currently published version. CI targets Node.js 22 and 24 on Linux, macOS and Windows; local regression tests use isolated fixtures rather than live customer accounts.
|
|
10
10
|
|
|
11
11
|
## Basic functionality
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Version `1.0.0` is the stable release. Stable releases use npm's `latest` tag. C
|
|
|
18
18
|
|
|
19
19
|
## What it does not do
|
|
20
20
|
|
|
21
|
-
The CLI does not execute audits locally
|
|
21
|
+
The CLI does not execute audits locally or independently verify website ownership. Your explicit `authorisation: true` declaration and the validated website scope provide the required request authorisation; no second manual staff confirmation of website authority is required. Individually requested reports retain Tityra's staff quality review. The CLI does not verify a fix, change technical report evidence, expose private staff notes or grant access to another customer's data. Checkout creates a link; it does not make a payment or authorise automatic charges.
|
|
22
22
|
|
|
23
23
|
The interactive workspace offers read-only navigation. Account changes use the explicit commands described below and require reviewed JSON input plus `--yes`.
|
|
24
24
|
|
|
@@ -73,6 +73,43 @@ tityra audits payment AUDIT_ID
|
|
|
73
73
|
|
|
74
74
|
Audit options describe the existing eligibility and review rules. A submitted request does not start an instant scan or promise a delivery date. Payment status provides the canonical report reference when available.
|
|
75
75
|
|
|
76
|
+
### Workspace plans and weekly monitoring
|
|
77
|
+
|
|
78
|
+
Scale and Enterprise support unlimited organisations, projects and members. Enterprise offers monthly billing at £3,600 or annual billing at £36,000, excluding VAT, with one scheduled AX Audit per week for each enabled project and up to 500 pages per project. Check [current plans and prices](https://app.tityra.com/customer) in your account before subscribing.
|
|
79
|
+
|
|
80
|
+
Enable **Monitor this project** in the Tityra application, or use the monitoring commands below with an explicitly granted `monitoring:write` permission and current project management access. Confirm that you are authorised to scan the website and selected pages. Eligibility comes from the project's organisation and its explicitly assigned Billing Profile, with an active subscription or explicit complimentary assignment that includes weekly monitoring. Your personal plan or membership in another paying organisation does not supply it. Your confirmed project consent enables monitoring without a separate administrator approval. Reports are delivered automatically after the required checks. You can pause and resume each project separately; existing reports remain available.
|
|
81
|
+
|
|
82
|
+
The first included AX Audit is due seven days after the project's first production audit request for its current website, whether that request was Free Audit, AX Audit or Expert Review. If no request exists, confirmed monitoring consent starts that interval. Enabling or resuming an eligible project whose audit is already due automatically queues one included AX Audit. Later included audits remain at least seven days apart; missed slots do not accumulate. Read the server's `nextScheduledAt` and `history` rather than calculating a new start date locally.
|
|
83
|
+
|
|
84
|
+
Use `audits list` and `reports get` to read released weekly AX Audit reports within the projects and permissions you approved. An AX Audit submitted through `audits create` is an additional request, charged separately; it does not replace the included weekly AX Audit slot. Expert Review is never included in weekly monitoring and always follows the normal separately paid request and checkout process. Free Audit requests retain their normal eligibility limits. The CLI cannot choose a payer or change a subscription.
|
|
85
|
+
|
|
86
|
+
Audit lists show the server's pricing status when your connection has `billing:read`; genuine included monitoring requests use `included`. A missing pricing status does not mean a payment is due. Use `audits payment AUDIT_ID` for current payment requirements. Normal report publication and payment checks remain in force.
|
|
87
|
+
|
|
88
|
+
Monitoring commands require version `1.1.0` or later; version `1.0.0` does not include them. Read settings with `projects:read`. To change them, request `monitoring:write` through fresh consent; default scopes and existing connections stay unchanged. The `--scope` list replaces the defaults, so include any other access you still need.
|
|
89
|
+
|
|
90
|
+
The interactive project menu also offers **Weekly monitoring** to read the same settings. It does not change monitoring or request additional permissions.
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
tityra auth login --scope "projects:read monitoring:write"
|
|
94
|
+
tityra projects monitoring get PROJECT_ID --json
|
|
95
|
+
tityra projects monitoring update PROJECT_ID --input monitoring.json --yes --json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For `monitoring.json`, copy the current `revision` and `website` into `expectedRevision` and `expectedWebsite`, and generate a UUID once for the intended action:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"action": "enable",
|
|
103
|
+
"expectedRevision": 0,
|
|
104
|
+
"expectedWebsite": "https://example.com/",
|
|
105
|
+
"authorisation": true,
|
|
106
|
+
"auditScope": { "mode": "website" },
|
|
107
|
+
"idempotencyKey": "10000000-0000-4000-8000-000000000001"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`enable` also resumes monitoring or changes its scope. To pause, send only `action: "disable"`, the current `expectedRevision` and a new action's `idempotencyKey`. Revision zero is valid for a project without settings. On an uncertain write, retry only the same input and key. The server checks the selected project, current manager, explicit payer, subscription and website. Confirm your authorisation again when changing the website or scope.
|
|
112
|
+
|
|
76
113
|
### 3. Read reports, findings and discussions
|
|
77
114
|
|
|
78
115
|
```sh
|
|
@@ -114,18 +151,19 @@ tityra discussions create REPORT_ID FINDING_ID --input discussion.json --yes --j
|
|
|
114
151
|
|
|
115
152
|
Other write commands use the same confirmation pattern:
|
|
116
153
|
|
|
117
|
-
| Command | Input fields besides `idempotencyKey`
|
|
118
|
-
| -------------------------------------------------- |
|
|
119
|
-
| `audits create` | `projectId`, `plan` (`free`, `automated`, `human`), `authorisation: true`; optional `notes`, `auditScope`
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `discussions
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
154
|
+
| Command | Input fields besides `idempotencyKey` |
|
|
155
|
+
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
156
|
+
| `audits create` | `projectId`, `plan` (`free`, `automated`, `human`), `authorisation: true`; optional `notes`, `auditScope` |
|
|
157
|
+
| `projects monitoring update PROJECT_ID` | `action` (`enable`, `disable`), `expectedRevision`; enable requires `authorisation: true`, `expectedWebsite`, and accepts `auditScope` |
|
|
158
|
+
| `findings challenge REPORT_ID FINDING_ID` | `reason` (`irrelevant`, `false_positive`, `unclear_other`), `body`, `expectedReportRevision` |
|
|
159
|
+
| `discussions create REPORT_ID FINDING_ID` | `body`, `expectedReportRevision` |
|
|
160
|
+
| `discussions reply REPORT_ID FINDING_ID THREAD_ID` | `body`, `expectedReportRevision`, `expectedThreadRevision` |
|
|
161
|
+
| `findings remediate REPORT_ID FINDING_ID` | `status`, `reason`, `expectedReportRevision`, `expectedTrackingRevision` |
|
|
162
|
+
| `reports checkout REPORT_ID` | No additional fields |
|
|
125
163
|
|
|
126
164
|
Read current revision fields using `--json` before changing a record. Discussion and challenge messages contain 3–4,000 characters. Remediation statuses are `open`, `planned`, `in_progress`, `resolved`, `wont_fix` and `not_applicable`; `resolved` remains customer-reported rather than independently verified.
|
|
127
165
|
|
|
128
|
-
Audit scope is either `{"mode":"website"}` or `{"mode":"specific_urls","urls":["https://example.com/path"]}`. The project supplies the website
|
|
166
|
+
Audit scope is either `{"mode":"website"}` or `{"mode":"specific_urls","urls":["https://example.com/path"]}`. The project supplies the website. Normal audit requests record your explicit authorisation for that scope without a separate manual staff authority confirmation. Eligibility, scope and commercial checks still apply, and individually requested reports retain staff quality review. Monitoring reuses the confirmed project consent described above. Checkout creates a link for the customer to complete.
|
|
129
167
|
|
|
130
168
|
### 5. Use the CLI in scripts or with an agent
|
|
131
169
|
|
package/dist/commands/audits.js
CHANGED
|
@@ -36,7 +36,8 @@ export function registerAuditsCommands(program, context) {
|
|
|
36
36
|
});
|
|
37
37
|
writeOptions(audits
|
|
38
38
|
.command('create')
|
|
39
|
-
.description('Request an audit
|
|
39
|
+
.description('Request an additional audit with explicit authorisation for its website scope')
|
|
40
|
+
.addHelpText('after', '\nYour authorisation: true declaration and the validated website scope provide the required request authorisation. No second manual staff confirmation of website authority is required.\nEligibility, scope and commercial checks still apply. Individually requested reports retain staff quality review.\nWeekly monitoring includes AX Audit only. Additional AX Audits and Expert Review require a separate request and payment through the normal checkout.\nUse projects monitoring get/update for an explicitly authorised project, or manage monitoring in the Tityra application.\n')).action(async (_options, command) => {
|
|
40
41
|
await write(command, context, 'audit', '/api/agent/audits');
|
|
41
42
|
});
|
|
42
43
|
}
|
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { identifier } from '../schema/writeSchema.js';
|
|
2
|
+
import { read, write, writeOptions } from './shared.js';
|
|
2
3
|
export function registerProjectsCommands(program, context) {
|
|
3
|
-
program
|
|
4
|
+
const projects = program
|
|
4
5
|
.command('projects')
|
|
5
|
-
.description('Read
|
|
6
|
+
.description('Read selected projects and manage authorised weekly monitoring');
|
|
7
|
+
projects
|
|
6
8
|
.command('list')
|
|
7
9
|
.description('List accessible projects')
|
|
8
10
|
.action(async (_options, command) => {
|
|
9
11
|
await read(command, context, '/api/agent/projects', 'Loading projects');
|
|
10
12
|
});
|
|
13
|
+
const monitoring = projects
|
|
14
|
+
.command('monitoring')
|
|
15
|
+
.description('Read or change weekly AX Audit monitoring for a selected project');
|
|
16
|
+
monitoring
|
|
17
|
+
.command('get <project-id>')
|
|
18
|
+
.description('Read current monitoring settings, scope, revision and report history')
|
|
19
|
+
.action(async (id, _options, command) => {
|
|
20
|
+
await read(command, context, `/api/agent/projects/${identifier(id)}/monitoring`, 'Loading project monitoring');
|
|
21
|
+
});
|
|
22
|
+
writeOptions(monitoring
|
|
23
|
+
.command('update <project-id>')
|
|
24
|
+
.description('Enable, pause, resume or update the scope of weekly AX Audit monitoring')
|
|
25
|
+
.addHelpText('after', '\nRequires an explicitly granted monitoring:write permission and current project management access.\nRead settings first; include the current expectedRevision and keep the same input and idempotencyKey when retrying an uncertain write.\nUse action enable with authorisation: true and the returned website as expectedWebsite. Use action disable to pause.\nEnabling monitoring records your website and scope authorisation without a separate administrator approval. Confirm that authorisation again after changing the website or scope.\nThe first included audit is due seven days after the first audit request for this project website, or after consent if none exists. Enabling or resuming an overdue eligible project queues its due AX Audit automatically. Read nextScheduledAt and history for the current server state.\nThe CLI cannot select a payer or change a subscription.\n')).action(async (id, _options, command) => {
|
|
26
|
+
await write(command, context, 'monitoring', `/api/agent/projects/${identifier(id)}/monitoring`, 'PATCH');
|
|
27
|
+
});
|
|
11
28
|
}
|
|
@@ -38,6 +38,14 @@ export function validateWrite(kind, input) {
|
|
|
38
38
|
'idempotencyKey',
|
|
39
39
|
],
|
|
40
40
|
checkout: ['idempotencyKey'],
|
|
41
|
+
monitoring: [
|
|
42
|
+
'action',
|
|
43
|
+
'expectedRevision',
|
|
44
|
+
'idempotencyKey',
|
|
45
|
+
'authorisation',
|
|
46
|
+
'expectedWebsite',
|
|
47
|
+
'auditScope',
|
|
48
|
+
],
|
|
41
49
|
};
|
|
42
50
|
if (Object.keys(body).some((key) => !fields[kind].includes(key)))
|
|
43
51
|
usage('Input contains an unsupported field. Use the documented request body.');
|
|
@@ -51,7 +59,32 @@ export function validateWrite(kind, input) {
|
|
|
51
59
|
if (!Number.isSafeInteger(body[key]) || Number(body[key]) < 1)
|
|
52
60
|
usage(`${key} must be a positive integer from the current server response.`);
|
|
53
61
|
};
|
|
54
|
-
if (kind === '
|
|
62
|
+
if (kind === 'monitoring') {
|
|
63
|
+
if (!['enable', 'disable'].includes(String(body.action)))
|
|
64
|
+
usage('Monitoring action must be enable or disable.');
|
|
65
|
+
if (!Number.isSafeInteger(body.expectedRevision) || Number(body.expectedRevision) < 0)
|
|
66
|
+
usage('expectedRevision must be a non-negative integer from the current monitoring response.');
|
|
67
|
+
if (body.action === 'enable') {
|
|
68
|
+
if (body.authorisation !== true)
|
|
69
|
+
usage('Enabling monitoring requires explicit authorisation: true.');
|
|
70
|
+
text('expectedWebsite', 1, 2000);
|
|
71
|
+
let website;
|
|
72
|
+
try {
|
|
73
|
+
website = new URL(body.expectedWebsite);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
usage('expectedWebsite must be the website returned by the monitoring response.');
|
|
77
|
+
}
|
|
78
|
+
if (!['http:', 'https:'].includes(website.protocol) || website.username || website.password)
|
|
79
|
+
usage('expectedWebsite must be an HTTP(S) website without credentials.');
|
|
80
|
+
validateAuditScope(body.auditScope);
|
|
81
|
+
}
|
|
82
|
+
else if (body.authorisation !== undefined ||
|
|
83
|
+
body.expectedWebsite !== undefined ||
|
|
84
|
+
body.auditScope !== undefined)
|
|
85
|
+
usage('Pausing monitoring accepts only action, expectedRevision and idempotencyKey.');
|
|
86
|
+
}
|
|
87
|
+
else if (kind === 'audit') {
|
|
55
88
|
if (typeof body.projectId !== 'string')
|
|
56
89
|
usage('projectId is required.');
|
|
57
90
|
identifier(body.projectId);
|
|
@@ -61,25 +94,7 @@ export function validateWrite(kind, input) {
|
|
|
61
94
|
usage('Audit requests require a plan and explicit authorisation: true.');
|
|
62
95
|
if (body.notes !== undefined)
|
|
63
96
|
text('notes', 0, 20000);
|
|
64
|
-
|
|
65
|
-
if (!body.auditScope || typeof body.auditScope !== 'object' || Array.isArray(body.auditScope))
|
|
66
|
-
usage('auditScope must be an object.');
|
|
67
|
-
const scope = body.auditScope;
|
|
68
|
-
if (scope.mode === 'website') {
|
|
69
|
-
if (Object.keys(scope).length !== 1)
|
|
70
|
-
usage('Website auditScope accepts only mode.');
|
|
71
|
-
}
|
|
72
|
-
else if (scope.mode === 'specific_urls') {
|
|
73
|
-
if (Object.keys(scope).some((k) => !['mode', 'urls'].includes(k)) ||
|
|
74
|
-
!Array.isArray(scope.urls) ||
|
|
75
|
-
scope.urls.length < 1 ||
|
|
76
|
-
scope.urls.length > 500 ||
|
|
77
|
-
scope.urls.some((url) => typeof url !== 'string' || !url.length || url.length > 2000))
|
|
78
|
-
usage('specific_urls requires 1–500 URL strings.');
|
|
79
|
-
}
|
|
80
|
-
else
|
|
81
|
-
usage('auditScope.mode must be website or specific_urls.');
|
|
82
|
-
}
|
|
97
|
+
validateAuditScope(body.auditScope);
|
|
83
98
|
}
|
|
84
99
|
else if (kind !== 'checkout') {
|
|
85
100
|
revision('expectedReportRevision');
|
|
@@ -101,3 +116,24 @@ export function validateWrite(kind, input) {
|
|
|
101
116
|
}
|
|
102
117
|
return body;
|
|
103
118
|
}
|
|
119
|
+
function validateAuditScope(value) {
|
|
120
|
+
if (value === undefined)
|
|
121
|
+
return;
|
|
122
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
123
|
+
usage('auditScope must be an object.');
|
|
124
|
+
const scope = value;
|
|
125
|
+
if (scope.mode === 'website') {
|
|
126
|
+
if (Object.keys(scope).length !== 1)
|
|
127
|
+
usage('Website auditScope accepts only mode.');
|
|
128
|
+
}
|
|
129
|
+
else if (scope.mode === 'specific_urls') {
|
|
130
|
+
if (Object.keys(scope).some((key) => !['mode', 'urls'].includes(key)) ||
|
|
131
|
+
!Array.isArray(scope.urls) ||
|
|
132
|
+
scope.urls.length < 1 ||
|
|
133
|
+
scope.urls.length > 500 ||
|
|
134
|
+
scope.urls.some((url) => typeof url !== 'string' || !url.length || url.length > 2000))
|
|
135
|
+
usage('specific_urls requires 1–500 URL strings.');
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
usage('auditScope.mode must be website or specific_urls.');
|
|
139
|
+
}
|
|
@@ -91,9 +91,11 @@ export class ApiClient {
|
|
|
91
91
|
: response.status === 403
|
|
92
92
|
? 'Your connection does not have permission for this project or action. Review its scopes and project access.'
|
|
93
93
|
: response.status === 402
|
|
94
|
-
?
|
|
94
|
+
? pathname.endsWith('/monitoring')
|
|
95
|
+
? 'This project is not currently eligible for monitoring. Review its subscription in Tityra.'
|
|
96
|
+
: 'Payment is required before this report is available.'
|
|
95
97
|
: response.status === 409
|
|
96
|
-
? 'The
|
|
98
|
+
? 'The resource or its authorisation changed. Read the latest revision and review your input before retrying.'
|
|
97
99
|
: response.status === 429
|
|
98
100
|
? 'Tityra rate limited this request. Wait before retrying; preserve the idempotency key for writes.'
|
|
99
101
|
: response.status === 404
|
|
@@ -20,7 +20,7 @@ export function welcomeBanner(version, color = true) {
|
|
|
20
20
|
level: color && !('NO_COLOR' in process.env) && supportsColor ? supportsColor.level : 0,
|
|
21
21
|
});
|
|
22
22
|
if (process.env.TERM === 'dumb')
|
|
23
|
-
return `\nTityra
|
|
23
|
+
return `\nTityra v${version}\n`;
|
|
24
24
|
const captions = {
|
|
25
25
|
2: paint.hex('#ed4832').bold('Tityra'),
|
|
26
26
|
4: (process.stdout.columns || 80) >= 70 ? 'Your workspace, from the terminal.' : '',
|
|
@@ -39,7 +39,15 @@ export function createOutput(json = false, color = true) {
|
|
|
39
39
|
process.stdout.write(paint.dim('No results.\n'));
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
const keys = [
|
|
42
|
+
const keys = [
|
|
43
|
+
'id',
|
|
44
|
+
'threadId',
|
|
45
|
+
'title',
|
|
46
|
+
'name',
|
|
47
|
+
'status',
|
|
48
|
+
'severity',
|
|
49
|
+
'pricingStatus',
|
|
50
|
+
].filter((key) => rows.some((row) => row[key] !== undefined));
|
|
43
51
|
if (!keys.length) {
|
|
44
52
|
process.stdout.write(humanJson(data) + '\n');
|
|
45
53
|
return;
|
|
@@ -53,12 +61,12 @@ export function createOutput(json = false, color = true) {
|
|
|
53
61
|
})
|
|
54
62
|
.join(' ')
|
|
55
63
|
.trimEnd();
|
|
56
|
-
process.stdout.write(paint.bold(rowText(Object.fromEntries(keys.map((key) => [key, key.toUpperCase()])))) + '\n');
|
|
64
|
+
process.stdout.write(paint.bold(rowText(Object.fromEntries(keys.map((key) => [key, key === 'pricingStatus' ? 'PRICING' : key.toUpperCase()])))) + '\n');
|
|
57
65
|
for (const row of rows)
|
|
58
66
|
process.stdout.write(rowText(row) + '\n');
|
|
59
67
|
if (value?.pagination && typeof value.pagination === 'object') {
|
|
60
68
|
const pagination = value.pagination;
|
|
61
|
-
process.stdout.write(paint.dim(`\nPage ${terminalText(pagination.page)}
|
|
69
|
+
process.stdout.write(paint.dim(`\nPage ${terminalText(pagination.page)}: ${terminalText(pagination.total)} total${pagination.hasMore ? ', more available' : ''}\n`));
|
|
62
70
|
}
|
|
63
71
|
process.stdout.write(paint.dim('Use --json for complete records and revision fields.\n'));
|
|
64
72
|
},
|
|
@@ -56,7 +56,7 @@ async function requestMenu(context, initial, environment) {
|
|
|
56
56
|
if (reportId)
|
|
57
57
|
choices.push({ title: 'Read report', value: 'report' }, { title: 'View findings', value: 'findings' });
|
|
58
58
|
choices.push({ title: 'Payment status', value: 'payment' }, back);
|
|
59
|
-
const action = await environment.choose(`Audit ${terminalText(request.id)}
|
|
59
|
+
const action = await environment.choose(`Audit ${terminalText(request.id)}: ${terminalText(request.status)}`, choices);
|
|
60
60
|
if (!action || action === 'back')
|
|
61
61
|
return;
|
|
62
62
|
if (action === 'status') {
|
|
@@ -81,9 +81,16 @@ async function recentAudits(context, projectId, environment) {
|
|
|
81
81
|
const result = await load(context, `/api/agent/audits?${query}`);
|
|
82
82
|
const requests = items(result, 'requests');
|
|
83
83
|
const choices = requests.map((request, index) => ({
|
|
84
|
-
title: `${terminalText(request.packageName || request.id)}
|
|
84
|
+
title: `${terminalText(request.packageName || request.id)}: ${terminalText(request.status)}`,
|
|
85
85
|
value: `request:${index}`,
|
|
86
|
-
description:
|
|
86
|
+
description: [
|
|
87
|
+
terminalText(request.receivedAt || request.websiteUrl),
|
|
88
|
+
...(typeof request.pricingStatus === 'string'
|
|
89
|
+
? [`Pricing: ${terminalText(request.pricingStatus)}`]
|
|
90
|
+
: []),
|
|
91
|
+
]
|
|
92
|
+
.filter(Boolean)
|
|
93
|
+
.join(' | '),
|
|
87
94
|
}));
|
|
88
95
|
if (!requests.length)
|
|
89
96
|
environment.write('\nNo audit requests on this page.\n');
|
|
@@ -95,7 +102,7 @@ async function recentAudits(context, projectId, environment) {
|
|
|
95
102
|
if (page > 1)
|
|
96
103
|
choices.push({ title: 'Previous page', value: 'previous' });
|
|
97
104
|
choices.push(back);
|
|
98
|
-
const selected = await environment.choose(`Recent audits
|
|
105
|
+
const selected = await environment.choose(`Recent audits: page ${page}`, choices);
|
|
99
106
|
if (!selected || selected === 'back')
|
|
100
107
|
return;
|
|
101
108
|
if (selected === 'next') {
|
|
@@ -145,6 +152,7 @@ async function projectWorkspace(context, projects, environment) {
|
|
|
145
152
|
const action = await environment.choose('What would you like to do?', [
|
|
146
153
|
{ title: 'Recent audits', value: 'audits' },
|
|
147
154
|
{ title: 'Audit options', value: 'options' },
|
|
155
|
+
{ title: 'Weekly monitoring', value: 'monitoring' },
|
|
148
156
|
{ title: 'Switch project', value: 'switch' },
|
|
149
157
|
{ title: 'Connection status', value: 'status' },
|
|
150
158
|
exit,
|
|
@@ -157,6 +165,8 @@ async function projectWorkspace(context, projects, environment) {
|
|
|
157
165
|
context.output(await environment.status(context.auth));
|
|
158
166
|
else if (action === 'options')
|
|
159
167
|
context.output(await load(context, `/api/agent/audits/options?${new URLSearchParams({ projectId })}`));
|
|
168
|
+
else if (action === 'monitoring')
|
|
169
|
+
context.output(await load(context, `/api/agent/projects/${projectId}/monitoring`));
|
|
160
170
|
else if (action === 'audits')
|
|
161
171
|
await recentAudits(context, projectId, environment);
|
|
162
172
|
}
|
package/package.json
CHANGED