atris 3.12.0 → 3.13.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/README.md +13 -12
- package/atris/skills/atris-feedback/SKILL.md +108 -0
- package/bin/atris.js +22 -11
- package/commands/business.js +124 -21
- package/commands/computer.js +145 -6
- package/commands/errors.js +155 -0
- package/commands/feedback.js +223 -71
- package/commands/proof.js +115 -0
- package/commands/pull.js +4 -2
- package/commands/push.js +6 -0
- package/commands/visualize.js +324 -8
- package/package.json +1 -1
package/commands/computer.js
CHANGED
|
@@ -52,8 +52,40 @@ const KNOWN_CHAT_COMMANDS = new Set([
|
|
|
52
52
|
'/start',
|
|
53
53
|
'/status',
|
|
54
54
|
'/worker',
|
|
55
|
+
'/workflow',
|
|
55
56
|
]);
|
|
56
57
|
|
|
58
|
+
const CODEOPS_WORKFLOW_PROMPT = `
|
|
59
|
+
## Atris CodeOps Workflow
|
|
60
|
+
|
|
61
|
+
You are running inside Atris CodeOps with full computer permissions (permission_mode=bypassPermissions).
|
|
62
|
+
Use those permissions to inspect, edit, test, commit, push, and open PRs when the task calls for it.
|
|
63
|
+
|
|
64
|
+
Do not behave like an open-ended chat.
|
|
65
|
+
Every coding or repo operation must follow the scientific workflow:
|
|
66
|
+
OBSERVE -> HYPOTHESIS -> PLAN -> ACTION -> VALIDATION -> EVIDENCE -> NEXT STATE.
|
|
67
|
+
|
|
68
|
+
For a new coding request, first show a concise PLAN with Files, Checks, Risk, and Merge policy.
|
|
69
|
+
If the user has not clearly approved execution, ask for approval before editing.
|
|
70
|
+
If the user explicitly says to execute, proceed after the concise plan.
|
|
71
|
+
|
|
72
|
+
After work, always report:
|
|
73
|
+
- edited_files
|
|
74
|
+
- commands_run
|
|
75
|
+
- validation_result
|
|
76
|
+
- evidence
|
|
77
|
+
- pr_url if any
|
|
78
|
+
- pr_state
|
|
79
|
+
- merge_state
|
|
80
|
+
- next_task
|
|
81
|
+
|
|
82
|
+
Use one of these next states:
|
|
83
|
+
planned, executing, validated, pr_opened, merge_ready, merge_blocked_checks, merge_blocked_policy, merged, failed, needs_human.
|
|
84
|
+
|
|
85
|
+
Never hide failures.
|
|
86
|
+
A blocked check or missing permission is evidence, not success.
|
|
87
|
+
`.trim();
|
|
88
|
+
|
|
57
89
|
function color(code, value) {
|
|
58
90
|
if (process.env.NO_COLOR || !process.stdout.isTTY) return String(value);
|
|
59
91
|
return `\x1b[${code}m${value}\x1b[0m`;
|
|
@@ -165,6 +197,7 @@ function printCloudHelp() {
|
|
|
165
197
|
console.log(' /start Show the beginner flow again');
|
|
166
198
|
console.log(' /help Show this menu');
|
|
167
199
|
console.log(' /status Show cloud computer status');
|
|
200
|
+
console.log(' /workflow Show the CodeOps workflow contract');
|
|
168
201
|
console.log(' /files [path] List files in the workspace');
|
|
169
202
|
console.log(' /run <cmd> Run shell without the model');
|
|
170
203
|
console.log(' /audit [n] Show recent runs, output, and charges');
|
|
@@ -201,6 +234,48 @@ function printCloudStartPanel(ctx, worker, model, billingLabel, authSummary = nu
|
|
|
201
234
|
console.log(ui.dim('Plain English goes to Atris. Slash commands control the computer.'));
|
|
202
235
|
}
|
|
203
236
|
|
|
237
|
+
function appendSystemPrompt(basePrompt, extraPrompt) {
|
|
238
|
+
if (!extraPrompt) return basePrompt || null;
|
|
239
|
+
if (basePrompt && basePrompt.includes('## Atris CodeOps Workflow')) return basePrompt;
|
|
240
|
+
if (!basePrompt) return extraPrompt;
|
|
241
|
+
return `${String(basePrompt).trim()}\n\n${extraPrompt}`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function codeOpsCloudOptions(options = {}) {
|
|
245
|
+
return {
|
|
246
|
+
...options,
|
|
247
|
+
worker: options.worker || 'claude',
|
|
248
|
+
mode: 'codeops',
|
|
249
|
+
systemPrompt: appendSystemPrompt(options.systemPrompt, CODEOPS_WORKFLOW_PROMPT),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function printCodeOpsStartPanel(ctx, worker, model, billingLabel, authSummary = null) {
|
|
254
|
+
console.log('');
|
|
255
|
+
console.log(ui.bold('Atris CodeOps Computer'));
|
|
256
|
+
console.log(`${ctx.businessName} ${ui.dim('/workspace persists, full permissions enabled')}`);
|
|
257
|
+
console.log(`Lane: ${ui.bold(formatWorkerName(worker))} ${ui.dim(formatCloudSelection({ worker, model }))}`);
|
|
258
|
+
console.log(`Billing: ${billingLabel}`);
|
|
259
|
+
if (authSummary) console.log(`${authSummary.label} ${ui.dim(authSummary.detail)}`);
|
|
260
|
+
console.log(`${ui.green('Workflow locked')} ${ui.dim('observe -> plan -> act -> validate -> evidence -> next')}`);
|
|
261
|
+
console.log('');
|
|
262
|
+
console.log(ui.bold('Start here'));
|
|
263
|
+
console.log(' Type a coding goal in plain English.');
|
|
264
|
+
console.log(' CodeOps will plan first, then execute after approval or explicit proceed language.');
|
|
265
|
+
console.log(' Use /workflow to see the contract, /run for shell, /audit for run history, /exit to leave.');
|
|
266
|
+
console.log('');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function printCodeOpsWorkflowContract() {
|
|
270
|
+
console.log('');
|
|
271
|
+
console.log(ui.bold('CodeOps workflow'));
|
|
272
|
+
console.log(' observe -> hypothesis -> plan -> action -> validation -> evidence -> next state');
|
|
273
|
+
console.log('');
|
|
274
|
+
console.log(' Required final evidence: edited_files, commands_run, validation_result, pr_url, pr_state, merge_state, next_task.');
|
|
275
|
+
console.log(' Allowed states: planned, executing, validated, pr_opened, merge_ready, merge_blocked_checks, merge_blocked_policy, merged, failed, needs_human.');
|
|
276
|
+
console.log(' Full permissions stay on; the workflow contract controls how the computer uses them.');
|
|
277
|
+
}
|
|
278
|
+
|
|
204
279
|
function buildLocalBridgeSystemPrompt(sessionId, localRoot, allowBash) {
|
|
205
280
|
const endpoint = `/api/cli/sessions/${sessionId}/file-op`;
|
|
206
281
|
const bashLine = allowBash
|
|
@@ -1386,6 +1461,8 @@ async function computerExec(token, prompt, ctx = null, options = {}) {
|
|
|
1386
1461
|
workspace_id: ctx.workspaceId,
|
|
1387
1462
|
...(options.worker ? { worker: options.worker } : {}),
|
|
1388
1463
|
...(options.model ? { model: options.model } : {}),
|
|
1464
|
+
...(options.systemPrompt ? { system_prompt: options.systemPrompt } : {}),
|
|
1465
|
+
...(options.allowedTools ? { allowed_tools: options.allowedTools } : {}),
|
|
1389
1466
|
},
|
|
1390
1467
|
timeoutMs: 40000,
|
|
1391
1468
|
});
|
|
@@ -1742,6 +1819,10 @@ async function computerChat(token, ctx, initialOptions = {}) {
|
|
|
1742
1819
|
return;
|
|
1743
1820
|
}
|
|
1744
1821
|
|
|
1822
|
+
const isCodeOps = initialOptions.mode === 'codeops' || ctx.slug === 'atris-codeops';
|
|
1823
|
+
const chatSystemPrompt = isCodeOps
|
|
1824
|
+
? appendSystemPrompt(initialOptions.systemPrompt, CODEOPS_WORKFLOW_PROMPT)
|
|
1825
|
+
: initialOptions.systemPrompt;
|
|
1745
1826
|
let sessionId = `biz-${ctx.businessId.slice(0, 8)}-${Date.now().toString(36)}`;
|
|
1746
1827
|
printCloudWordmark();
|
|
1747
1828
|
const selection = await chooseCloudLane(token, ctx, initialOptions);
|
|
@@ -1758,12 +1839,16 @@ async function computerChat(token, ctx, initialOptions = {}) {
|
|
|
1758
1839
|
return;
|
|
1759
1840
|
}
|
|
1760
1841
|
|
|
1761
|
-
|
|
1842
|
+
if (isCodeOps) {
|
|
1843
|
+
printCodeOpsStartPanel(ctx, worker, model, billingLabel, authSummary);
|
|
1844
|
+
} else {
|
|
1845
|
+
printCloudStartPanel(ctx, worker, model, billingLabel, authSummary);
|
|
1846
|
+
}
|
|
1762
1847
|
|
|
1763
1848
|
const rl = readline.createInterface({
|
|
1764
1849
|
input: process.stdin,
|
|
1765
1850
|
output: process.stdout,
|
|
1766
|
-
prompt: 'cloud> ',
|
|
1851
|
+
prompt: isCodeOps ? 'codeops> ' : 'cloud> ',
|
|
1767
1852
|
});
|
|
1768
1853
|
|
|
1769
1854
|
rl.prompt();
|
|
@@ -1782,7 +1867,11 @@ async function computerChat(token, ctx, initialOptions = {}) {
|
|
|
1782
1867
|
if (line === '/start') {
|
|
1783
1868
|
billingLabel = await describeBillingMode(token, ctx, worker);
|
|
1784
1869
|
authSummary = activeWorker(worker) === 'claude' ? await describeClaudeAuth(token, ctx) : null;
|
|
1785
|
-
|
|
1870
|
+
if (isCodeOps) {
|
|
1871
|
+
printCodeOpsStartPanel(ctx, worker, model, billingLabel, authSummary);
|
|
1872
|
+
} else {
|
|
1873
|
+
printCloudStartPanel(ctx, worker, model, billingLabel, authSummary);
|
|
1874
|
+
}
|
|
1786
1875
|
rl.prompt();
|
|
1787
1876
|
continue;
|
|
1788
1877
|
}
|
|
@@ -1796,6 +1885,11 @@ async function computerChat(token, ctx, initialOptions = {}) {
|
|
|
1796
1885
|
rl.prompt();
|
|
1797
1886
|
continue;
|
|
1798
1887
|
}
|
|
1888
|
+
if (line === '/workflow') {
|
|
1889
|
+
printCodeOpsWorkflowContract();
|
|
1890
|
+
rl.prompt();
|
|
1891
|
+
continue;
|
|
1892
|
+
}
|
|
1799
1893
|
if (line === '/pwd') {
|
|
1800
1894
|
await computerRun(token, 'pwd', ctx);
|
|
1801
1895
|
rl.prompt();
|
|
@@ -1889,7 +1983,12 @@ async function computerChat(token, ctx, initialOptions = {}) {
|
|
|
1889
1983
|
}
|
|
1890
1984
|
}
|
|
1891
1985
|
|
|
1892
|
-
sessionId = await sendBusinessChat(token, ctx, line, sessionId, false, rl, {
|
|
1986
|
+
sessionId = await sendBusinessChat(token, ctx, line, sessionId, false, rl, {
|
|
1987
|
+
worker,
|
|
1988
|
+
model,
|
|
1989
|
+
systemPrompt: chatSystemPrompt,
|
|
1990
|
+
allowedTools: initialOptions.allowedTools,
|
|
1991
|
+
});
|
|
1893
1992
|
rl.prompt();
|
|
1894
1993
|
}
|
|
1895
1994
|
} catch (error) {
|
|
@@ -2318,7 +2417,7 @@ async function runComputer() {
|
|
|
2318
2417
|
console.log(' local-byo Open LOCAL BYO Claude mode; Anthropic tokens, no cloud audit');
|
|
2319
2418
|
console.log(' --cloud Open CLOUD workspace mode in the bound business workspace');
|
|
2320
2419
|
console.log(' cloud Open CLOUD workspace mode in the bound business workspace');
|
|
2321
|
-
console.log(' codeops Open Atris CodeOps
|
|
2420
|
+
console.log(' codeops Open Atris CodeOps workflow computer if your account has access');
|
|
2322
2421
|
console.log(' --worker Cloud worker override: claude | openai');
|
|
2323
2422
|
console.log(' --model Cloud model override');
|
|
2324
2423
|
console.log(' claude|codex Legacy local console backends');
|
|
@@ -2351,6 +2450,9 @@ async function runComputer() {
|
|
|
2351
2450
|
console.log(' atris computer --cloud --worker openai --model gpt-5.4');
|
|
2352
2451
|
console.log(' atris computer cloud');
|
|
2353
2452
|
console.log(' atris computer codeops');
|
|
2453
|
+
console.log(' atris computer codeops status');
|
|
2454
|
+
console.log(' atris computer codeops run "pwd"');
|
|
2455
|
+
console.log(' atris computer codeops exec "Plan a safe repo fix"');
|
|
2354
2456
|
console.log(' atris computer status');
|
|
2355
2457
|
console.log(' atris computer wake');
|
|
2356
2458
|
console.log(' atris computer run "ls -la /workspace"');
|
|
@@ -2370,7 +2472,44 @@ async function runComputer() {
|
|
|
2370
2472
|
console.error('Ask an Atris CodeOps admin to add you to the atris-codeops business.');
|
|
2371
2473
|
return;
|
|
2372
2474
|
}
|
|
2373
|
-
|
|
2475
|
+
const codeopsOptions = codeOpsCloudOptions(cloudOptions);
|
|
2476
|
+
const codeopsSub = args[1];
|
|
2477
|
+
const codeopsRest = args.slice(2).join(' ');
|
|
2478
|
+
if (!codeopsSub || codeopsSub === 'chat') {
|
|
2479
|
+
await computerChat(token, codeopsCtx, codeopsOptions);
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
switch (codeopsSub) {
|
|
2483
|
+
case '--help':
|
|
2484
|
+
case 'help':
|
|
2485
|
+
console.log('Usage: atris computer codeops [chat|status|wake|sleep|run|grep|ls|cat|exec|audit|workflow]');
|
|
2486
|
+
console.log('');
|
|
2487
|
+
console.log('Examples:');
|
|
2488
|
+
console.log(' atris computer codeops');
|
|
2489
|
+
console.log(' atris computer codeops status');
|
|
2490
|
+
console.log(' atris computer codeops run "pwd && git status --short"');
|
|
2491
|
+
console.log(' atris computer codeops exec "Plan the smallest safe fix, then wait"');
|
|
2492
|
+
return;
|
|
2493
|
+
case 'status': return computerStatus(token, codeopsCtx);
|
|
2494
|
+
case 'wake': return computerWake(token, codeopsCtx);
|
|
2495
|
+
case 'sleep': return computerSleep(token, codeopsCtx);
|
|
2496
|
+
case 'run': return computerRun(token, codeopsRest, codeopsCtx);
|
|
2497
|
+
case 'grep': return computerGrep(token, codeopsRest, codeopsCtx);
|
|
2498
|
+
case 'ls': return computerLs(token, codeopsRest || undefined, codeopsCtx);
|
|
2499
|
+
case 'cat': return computerCat(token, codeopsRest, codeopsCtx);
|
|
2500
|
+
case 'exec': return computerExec(token, codeopsRest, codeopsCtx, codeopsOptions);
|
|
2501
|
+
case 'audit': {
|
|
2502
|
+
const limit = codeopsRest ? Number.parseInt(codeopsRest, 10) : 10;
|
|
2503
|
+
return computerAudit(token, codeopsCtx, Number.isFinite(limit) ? limit : 10);
|
|
2504
|
+
}
|
|
2505
|
+
case 'workflow':
|
|
2506
|
+
printCodeOpsWorkflowContract();
|
|
2507
|
+
return;
|
|
2508
|
+
default:
|
|
2509
|
+
console.error(`Unknown CodeOps subcommand: ${codeopsSub}`);
|
|
2510
|
+
console.log('Run: atris computer codeops help');
|
|
2511
|
+
return;
|
|
2512
|
+
}
|
|
2374
2513
|
return;
|
|
2375
2514
|
}
|
|
2376
2515
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors command for Atris CLI — admin dashboard over atris_error_events.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* atris errors List errors from last 24h, grouped by signature
|
|
6
|
+
* atris errors --hours 72 Widen the window (max 720h / 30d)
|
|
7
|
+
* atris errors --limit 1000 Raise the raw-event cap for grouping
|
|
8
|
+
* atris errors show <id> Full detail (stack trace, message) for one event
|
|
9
|
+
*
|
|
10
|
+
* Requires admin role on the user row.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { loadCredentials } = require('../utils/auth');
|
|
14
|
+
const { apiRequestJson } = require('../utils/api');
|
|
15
|
+
|
|
16
|
+
function getToken() {
|
|
17
|
+
const creds = loadCredentials();
|
|
18
|
+
if (!creds || !creds.token) {
|
|
19
|
+
console.error('Not logged in. Run: atris login');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
return creds.token;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function extractFlag(args, ...names) {
|
|
26
|
+
const remaining = [];
|
|
27
|
+
let value = null;
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
const a = args[i];
|
|
30
|
+
const eq = a.indexOf('=');
|
|
31
|
+
const key = eq >= 0 ? a.slice(0, eq) : a;
|
|
32
|
+
if (names.includes(key)) {
|
|
33
|
+
value = eq >= 0 ? a.slice(eq + 1) : args[++i];
|
|
34
|
+
} else {
|
|
35
|
+
remaining.push(a);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [value, remaining];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function listErrors(args) {
|
|
42
|
+
const [hoursArg, r1] = extractFlag(args, '--hours', '-H');
|
|
43
|
+
const [limitArg, r2] = extractFlag(r1, '--limit', '-L');
|
|
44
|
+
const hours = hoursArg ? parseInt(hoursArg, 10) : 24;
|
|
45
|
+
const limit = limitArg ? parseInt(limitArg, 10) : 500;
|
|
46
|
+
|
|
47
|
+
const token = getToken();
|
|
48
|
+
const result = await apiRequestJson(`/errors?hours=${hours}&limit=${limit}`, {
|
|
49
|
+
method: 'GET',
|
|
50
|
+
token,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (!result.ok) {
|
|
54
|
+
console.error(`Error: ${result.error || 'Failed to fetch errors'}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const data = result.data || {};
|
|
59
|
+
const groups = data.groups || [];
|
|
60
|
+
|
|
61
|
+
if (groups.length === 0) {
|
|
62
|
+
console.log(`No errors in the last ${hours}h. Clean.`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log(
|
|
67
|
+
`Errors — last ${data.window_hours}h — ` +
|
|
68
|
+
`${data.total_events} events across ${data.unique_signatures} signatures\n`,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
groups.forEach((g, idx) => {
|
|
72
|
+
const s = g.sample || {};
|
|
73
|
+
const shortId = (s.id || '').substring(0, 8);
|
|
74
|
+
const last = s.created_at ? s.created_at.substring(0, 16).replace('T', ' ') : '';
|
|
75
|
+
const status = s.status_code ? ` [${s.status_code}]` : '';
|
|
76
|
+
const msg = (s.message || '').replace(/\s+/g, ' ').substring(0, 140);
|
|
77
|
+
|
|
78
|
+
console.log(`${idx + 1}. x${g.count} ${g.signature}${status}`);
|
|
79
|
+
if (last) console.log(` last: ${last} UTC latest id: ${shortId}`);
|
|
80
|
+
if (msg) console.log(` "${msg}"`);
|
|
81
|
+
console.log('');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
console.log(
|
|
85
|
+
`Run \`atris errors show <id>\` for full stack trace of a specific event.`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function showError(errorId) {
|
|
90
|
+
if (!errorId) {
|
|
91
|
+
console.error('Usage: atris errors show <id>');
|
|
92
|
+
console.error('(id must be a full UUID — get one from `atris errors` output)');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const token = getToken();
|
|
97
|
+
const result = await apiRequestJson(`/errors/${encodeURIComponent(errorId)}`, {
|
|
98
|
+
method: 'GET',
|
|
99
|
+
token,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (!result.ok) {
|
|
103
|
+
console.error(`Error: ${result.error || 'Failed to fetch error'}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const e = result.data || {};
|
|
108
|
+
console.log(`Error ${e.id || errorId}`);
|
|
109
|
+
console.log(` type: ${e.error_type || '?'}`);
|
|
110
|
+
console.log(` method: ${e.request_method || '?'}`);
|
|
111
|
+
console.log(` path: ${e.request_path || '?'}`);
|
|
112
|
+
console.log(` status: ${e.status_code || '?'}`);
|
|
113
|
+
console.log(` when: ${e.created_at || '?'}`);
|
|
114
|
+
console.log(` source: ${e.source || '?'}`);
|
|
115
|
+
if (e.user_id) console.log(` user: ${e.user_id}`);
|
|
116
|
+
console.log('');
|
|
117
|
+
console.log('Message:');
|
|
118
|
+
console.log(' ' + (e.message || '(none)').split('\n').join('\n '));
|
|
119
|
+
console.log('');
|
|
120
|
+
if (e.stack_trace) {
|
|
121
|
+
console.log('Stack trace:');
|
|
122
|
+
console.log(' ' + e.stack_trace.split('\n').join('\n '));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function printHelp() {
|
|
127
|
+
console.log('');
|
|
128
|
+
console.log('Usage:');
|
|
129
|
+
console.log(' atris errors List errors from last 24h, grouped');
|
|
130
|
+
console.log(' atris errors --hours 72 Widen the window (max 720h / 30d)');
|
|
131
|
+
console.log(' atris errors --limit 1000 Raise the raw-event cap');
|
|
132
|
+
console.log(' atris errors show <full-uuid> Full detail for one event');
|
|
133
|
+
console.log('');
|
|
134
|
+
console.log('Admin role required.');
|
|
135
|
+
console.log('');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function errorsCommand() {
|
|
139
|
+
const args = process.argv.slice(3);
|
|
140
|
+
const sub = args[0];
|
|
141
|
+
|
|
142
|
+
if (sub === '--help' || sub === '-h' || sub === 'help') {
|
|
143
|
+
printHelp();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (sub === 'show') {
|
|
148
|
+
await showError(args[1]);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await listErrors(args);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = { errorsCommand };
|