nexarch 0.6.3 → 0.6.5
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/dist/commands/check-in.js +30 -101
- package/dist/commands/command-claim.js +91 -0
- package/dist/commands/init-agent.js +1 -1
- package/dist/commands/init-project.js +1 -26
- package/dist/commands/login.js +17 -0
- package/dist/commands/logout.js +7 -0
- package/dist/index.js +9 -4
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import process from "process";
|
|
2
|
-
import { existsSync, readFileSync
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { requireCredentials } from "../lib/credentials.js";
|
|
@@ -23,136 +23,65 @@ function parseToolText(result) {
|
|
|
23
23
|
function loadIdentity() {
|
|
24
24
|
const identityPath = join(homedir(), ".nexarch", "identity.json");
|
|
25
25
|
if (!existsSync(identityPath))
|
|
26
|
-
return { agentKey: null,
|
|
26
|
+
return { agentKey: null, companyId: null };
|
|
27
27
|
try {
|
|
28
28
|
const data = JSON.parse(readFileSync(identityPath, "utf8"));
|
|
29
|
-
return {
|
|
30
|
-
agentKey: data.agentKey ?? null,
|
|
31
|
-
projectKeys: Array.isArray(data.projectKeys) ? data.projectKeys : [],
|
|
32
|
-
};
|
|
29
|
+
return { agentKey: data.agentKey ?? null, companyId: data.companyId ?? null };
|
|
33
30
|
}
|
|
34
31
|
catch {
|
|
35
|
-
return { agentKey: null,
|
|
32
|
+
return { agentKey: null, companyId: null };
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
|
-
function safeReadText(path, maxChars = 6000) {
|
|
39
|
-
if (!existsSync(path))
|
|
40
|
-
return null;
|
|
41
|
-
try {
|
|
42
|
-
return readFileSync(path, "utf8").slice(0, maxChars);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function collectEvidenceFromRepo() {
|
|
49
|
-
const cwd = process.cwd();
|
|
50
|
-
const readme = safeReadText(join(cwd, "README.md"), 8000)
|
|
51
|
-
?? safeReadText(join(cwd, "readme.md"), 8000)
|
|
52
|
-
?? undefined;
|
|
53
|
-
const packageJson = safeReadText(join(cwd, "package.json"), 5000);
|
|
54
|
-
const notes = [];
|
|
55
|
-
if (packageJson)
|
|
56
|
-
notes.push("package.json detected");
|
|
57
|
-
const files = [];
|
|
58
|
-
if (packageJson)
|
|
59
|
-
files.push({ path: "package.json", content: packageJson });
|
|
60
|
-
const srcDir = join(cwd, "src");
|
|
61
|
-
if (existsSync(srcDir)) {
|
|
62
|
-
try {
|
|
63
|
-
const entries = readdirSync(srcDir)
|
|
64
|
-
.filter((name) => /\.(ts|tsx|js|jsx)$/i.test(name))
|
|
65
|
-
.slice(0, 8);
|
|
66
|
-
for (const name of entries) {
|
|
67
|
-
const full = join(srcDir, name);
|
|
68
|
-
try {
|
|
69
|
-
if (!statSync(full).isFile())
|
|
70
|
-
continue;
|
|
71
|
-
const content = safeReadText(full, 4000);
|
|
72
|
-
if (content)
|
|
73
|
-
files.push({ path: `src/${name}`, content });
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
// ignore per-file failures
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (entries.length > 0)
|
|
80
|
-
notes.push(`included ${entries.length} source file snippet(s)`);
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
// ignore directory read issues
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
const summary = [
|
|
87
|
-
`cwd=${cwd}`,
|
|
88
|
-
readme ? "README included" : "README missing",
|
|
89
|
-
files.length > 0 ? `evidence files=${files.length}` : "no evidence files collected",
|
|
90
|
-
].join("; ");
|
|
91
|
-
return {
|
|
92
|
-
summary,
|
|
93
|
-
...(readme ? { readme } : {}),
|
|
94
|
-
...(notes.length ? { notes: notes.join("; ") } : {}),
|
|
95
|
-
...(files.length ? { files } : {}),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
35
|
export async function checkIn(args) {
|
|
99
36
|
const asJson = parseFlag(args, "--json");
|
|
100
37
|
const agentKeyArg = parseOptionValue(args, "--agent-key");
|
|
101
|
-
const projectKey = parseOptionValue(args, "--project");
|
|
102
38
|
const creds = requireCredentials();
|
|
103
39
|
const identity = loadIdentity();
|
|
104
40
|
const agentKey = agentKeyArg ?? identity.agentKey;
|
|
105
|
-
// Use --project flag as a single override, otherwise send all stored keys
|
|
106
|
-
const resolvedProjectKeys = projectKey ? [projectKey] : identity.projectKeys;
|
|
107
41
|
if (!agentKey) {
|
|
108
42
|
if (asJson) {
|
|
109
|
-
process.stdout.write(JSON.stringify({
|
|
43
|
+
process.stdout.write(JSON.stringify({ commands: [], reason: "no-agent-key" }) + "\n");
|
|
110
44
|
}
|
|
111
45
|
else {
|
|
112
46
|
console.log("No agent key found. Pass --agent-key or run nexarch init-agent first.");
|
|
113
47
|
}
|
|
114
48
|
return;
|
|
115
49
|
}
|
|
116
|
-
const mcpOpts = { companyId: creds.companyId };
|
|
117
|
-
const evidence = collectEvidenceFromRepo();
|
|
118
50
|
const raw = await callMcpTool("nexarch_claim_command", {
|
|
119
51
|
agentKey,
|
|
120
|
-
...(resolvedProjectKeys.length > 0 ? { projectKeys: resolvedProjectKeys } : {}),
|
|
121
|
-
evidence,
|
|
122
52
|
companyId: creds.companyId,
|
|
123
|
-
},
|
|
53
|
+
}, { companyId: creds.companyId });
|
|
124
54
|
const result = parseToolText(raw);
|
|
125
55
|
if (asJson) {
|
|
126
56
|
process.stdout.write(JSON.stringify(result) + "\n");
|
|
127
57
|
return;
|
|
128
58
|
}
|
|
129
|
-
|
|
130
|
-
|
|
59
|
+
const commands = result.commands ?? [];
|
|
60
|
+
if (commands.length === 0) {
|
|
61
|
+
console.log("No pending application-target commands found.");
|
|
131
62
|
return;
|
|
132
63
|
}
|
|
133
|
-
|
|
134
|
-
console.log(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
console.log(`\nCommand ID : ${cmd.id}`);
|
|
138
|
-
console.log(`Type : ${cmd.command_type}`);
|
|
139
|
-
console.log(`Target : ${cmd.target_entity_key ?? "(any)"}`);
|
|
140
|
-
console.log(`Priority : ${cmd.priority}`);
|
|
141
|
-
if (cmd.resolved_runtime_handler)
|
|
142
|
-
console.log(`Runtime : ${cmd.resolved_runtime_handler}`);
|
|
143
|
-
if (cmd.command_type_version != null)
|
|
144
|
-
console.log(`Type ver : ${cmd.command_type_version}`);
|
|
145
|
-
if (Object.keys(cmd.command_params).length > 0) {
|
|
146
|
-
console.log(`Params : ${JSON.stringify(cmd.command_params)}`);
|
|
147
|
-
}
|
|
148
|
-
if (cmd.resolved_playbook_text?.trim()) {
|
|
149
|
-
console.log(`\nPlaybook:\n${cmd.resolved_playbook_text}`);
|
|
64
|
+
console.log("\nPending application-target commands (preview only; nothing claimed):");
|
|
65
|
+
console.log(`Company scope is resolved server-side from companyId=${creds.companyId}.`);
|
|
66
|
+
if (identity.companyId && identity.companyId !== creds.companyId) {
|
|
67
|
+
console.log(`Note: local identity companyId ${identity.companyId} differs from current credentials companyId ${creds.companyId}.`);
|
|
150
68
|
}
|
|
151
|
-
|
|
152
|
-
|
|
69
|
+
for (const cmd of commands) {
|
|
70
|
+
const claimable = cmd.claimable ? "yes" : "no";
|
|
71
|
+
const reason = cmd.claimReason ?? (cmd.claimable ? "application_access_confirmed" : "application_not_found_for_company");
|
|
72
|
+
console.log(`\n- ID : ${cmd.id}`);
|
|
73
|
+
console.log(` Type : ${cmd.command_type}`);
|
|
74
|
+
console.log(` Target : ${cmd.target_entity_key ?? "(none)"}`);
|
|
75
|
+
console.log(` Priority : ${cmd.priority}`);
|
|
76
|
+
console.log(` Claimable : ${claimable} (${reason})`);
|
|
77
|
+
if (cmd.command_type_version != null)
|
|
78
|
+
console.log(` Type ver : ${cmd.command_type_version}`);
|
|
79
|
+
if (cmd.resolved_runtime_handler)
|
|
80
|
+
console.log(` Runtime : ${cmd.resolved_runtime_handler}`);
|
|
81
|
+
if (cmd.claimable) {
|
|
82
|
+
console.log(` Claim cmd : npx nexarch command-claim --id "${cmd.id}"`);
|
|
83
|
+
}
|
|
153
84
|
}
|
|
154
|
-
console.log(
|
|
155
|
-
console.log(
|
|
156
|
-
console.log(`\nIf it fails, run:`);
|
|
157
|
-
console.log(` npx nexarch command-fail --id "${cmd.id}" --error "..."`);
|
|
85
|
+
console.log("\nTo validate an application target is accessible in Nexarch before claiming:");
|
|
86
|
+
console.log(" npx nexarch policy-controls --entity <application:key> --json");
|
|
158
87
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
6
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
7
|
+
function parseFlag(args, flag) {
|
|
8
|
+
return args.includes(flag);
|
|
9
|
+
}
|
|
10
|
+
function parseOptionValue(args, option) {
|
|
11
|
+
const idx = args.indexOf(option);
|
|
12
|
+
if (idx === -1)
|
|
13
|
+
return null;
|
|
14
|
+
const v = args[idx + 1];
|
|
15
|
+
if (!v || v.startsWith("--"))
|
|
16
|
+
return null;
|
|
17
|
+
return v;
|
|
18
|
+
}
|
|
19
|
+
function parseToolText(result) {
|
|
20
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
21
|
+
return JSON.parse(text);
|
|
22
|
+
}
|
|
23
|
+
function loadIdentity() {
|
|
24
|
+
const identityPath = join(homedir(), ".nexarch", "identity.json");
|
|
25
|
+
if (!existsSync(identityPath))
|
|
26
|
+
return { agentKey: null };
|
|
27
|
+
try {
|
|
28
|
+
const data = JSON.parse(readFileSync(identityPath, "utf8"));
|
|
29
|
+
return { agentKey: data.agentKey ?? null };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { agentKey: null };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function commandClaim(args) {
|
|
36
|
+
const asJson = parseFlag(args, "--json");
|
|
37
|
+
const id = parseOptionValue(args, "--id");
|
|
38
|
+
const agentKeyArg = parseOptionValue(args, "--agent-key");
|
|
39
|
+
if (!id) {
|
|
40
|
+
console.error("error: --id <commandId> is required");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const creds = requireCredentials();
|
|
44
|
+
const identity = loadIdentity();
|
|
45
|
+
const agentKey = agentKeyArg ?? identity.agentKey;
|
|
46
|
+
if (!agentKey) {
|
|
47
|
+
console.error("error: no agent key found. Pass --agent-key or run nexarch init-agent first.");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const raw = await callMcpTool("nexarch_claim_command_by_id", {
|
|
51
|
+
commandId: id,
|
|
52
|
+
agentKey,
|
|
53
|
+
companyId: creds.companyId,
|
|
54
|
+
}, { companyId: creds.companyId });
|
|
55
|
+
const result = parseToolText(raw);
|
|
56
|
+
if (asJson) {
|
|
57
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!result.command) {
|
|
61
|
+
console.log(`Command ${id} was not claimed.`);
|
|
62
|
+
if (result.reason)
|
|
63
|
+
console.log(`Reason: ${result.reason}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const cmd = result.command;
|
|
67
|
+
console.log(`\n╔══════════════════════════════════════════════════════════════════╗`);
|
|
68
|
+
console.log(`║ COMMAND CLAIMED — action required ║`);
|
|
69
|
+
console.log(`╚══════════════════════════════════════════════════════════════════╝`);
|
|
70
|
+
console.log(`\nCommand ID : ${cmd.id}`);
|
|
71
|
+
console.log(`Type : ${cmd.command_type}`);
|
|
72
|
+
console.log(`Target : ${cmd.target_entity_key ?? "(any)"}`);
|
|
73
|
+
console.log(`Priority : ${cmd.priority}`);
|
|
74
|
+
if (cmd.resolved_runtime_handler)
|
|
75
|
+
console.log(`Runtime : ${cmd.resolved_runtime_handler}`);
|
|
76
|
+
if (cmd.command_type_version != null)
|
|
77
|
+
console.log(`Type ver : ${cmd.command_type_version}`);
|
|
78
|
+
if (Object.keys(cmd.command_params).length > 0) {
|
|
79
|
+
console.log(`Params : ${JSON.stringify(cmd.command_params)}`);
|
|
80
|
+
}
|
|
81
|
+
if (cmd.resolved_playbook_text?.trim()) {
|
|
82
|
+
console.log(`\nPlaybook:\n${cmd.resolved_playbook_text}`);
|
|
83
|
+
}
|
|
84
|
+
if (cmd.instructions) {
|
|
85
|
+
console.log(`\nInstructions:\n${cmd.instructions}`);
|
|
86
|
+
}
|
|
87
|
+
console.log(`\nWhen done, run:`);
|
|
88
|
+
console.log(` npx nexarch command-done --id "${cmd.id}" --summary "..."`);
|
|
89
|
+
console.log(`\nIf it fails, run:`);
|
|
90
|
+
console.log(` npx nexarch command-fail --id "${cmd.id}" --error "..."`);
|
|
91
|
+
}
|
|
@@ -756,7 +756,7 @@ export async function initAgent(args) {
|
|
|
756
756
|
// Save identity so check-in can find the agent key
|
|
757
757
|
const identityDir = join(homedir(), ".nexarch");
|
|
758
758
|
mkdirSync(identityDir, { recursive: true });
|
|
759
|
-
writeFileSync(join(identityDir, "identity.json"), JSON.stringify({ agentKey: `agent:${agentId}
|
|
759
|
+
writeFileSync(join(identityDir, "identity.json"), JSON.stringify({ agentKey: `agent:${agentId}`, companyId: creds.companyId }, null, 2), { mode: 0o600 });
|
|
760
760
|
}
|
|
761
761
|
catch {
|
|
762
762
|
// non-fatal
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import process from "process";
|
|
2
2
|
import { execFileSync } from "node:child_process";
|
|
3
|
-
import { existsSync,
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
4
4
|
import { basename, join, relative, resolve as resolvePath } from "node:path";
|
|
5
|
-
import { homedir } from "node:os";
|
|
6
5
|
import { requireCredentials } from "../lib/credentials.js";
|
|
7
6
|
import { callMcpTool } from "../lib/mcp.js";
|
|
8
7
|
import { buildVersionAttributes } from "../lib/version-normalization.js";
|
|
@@ -1234,30 +1233,6 @@ ${subPkgSection}${gapCheckSection}`;
|
|
|
1234
1233
|
relationshipErrors: relsResult?.errors ?? [],
|
|
1235
1234
|
enrichmentTask,
|
|
1236
1235
|
};
|
|
1237
|
-
// Persist all application entity keys to ~/.nexarch/identity.json so nexarch check-in
|
|
1238
|
-
// can automatically claim commands targeted at any application in this project.
|
|
1239
|
-
if (output.ok) {
|
|
1240
|
-
try {
|
|
1241
|
-
const allAppKeys = [
|
|
1242
|
-
projectExternalKey,
|
|
1243
|
-
...subPackages
|
|
1244
|
-
.filter((sp) => sp.entityType === "application" && sp.externalKey)
|
|
1245
|
-
.map((sp) => sp.externalKey),
|
|
1246
|
-
];
|
|
1247
|
-
const identityDir = join(homedir(), ".nexarch");
|
|
1248
|
-
mkdirSync(identityDir, { recursive: true });
|
|
1249
|
-
const identityPath = join(identityDir, "identity.json");
|
|
1250
|
-
const existing = existsSync(identityPath)
|
|
1251
|
-
? JSON.parse(readFileSync(identityPath, "utf8"))
|
|
1252
|
-
: {};
|
|
1253
|
-
const stored = Array.isArray(existing.projectKeys) ? existing.projectKeys : [];
|
|
1254
|
-
const merged = Array.from(new Set([...allAppKeys, ...stored]));
|
|
1255
|
-
writeFileSync(identityPath, JSON.stringify({ ...existing, projectKeys: merged }, null, 2), { mode: 0o600 });
|
|
1256
|
-
}
|
|
1257
|
-
catch {
|
|
1258
|
-
// non-fatal
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
1236
|
if (asJson) {
|
|
1262
1237
|
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
|
|
1263
1238
|
if (!output.ok)
|
package/dist/commands/login.js
CHANGED
|
@@ -3,6 +3,9 @@ import { createServer as createNetServer } from "net";
|
|
|
3
3
|
import { randomBytes } from "crypto";
|
|
4
4
|
import { execFile } from "child_process";
|
|
5
5
|
import { saveCredentials } from "../lib/credentials.js";
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
7
|
+
import { homedir } from "os";
|
|
8
|
+
import { join } from "path";
|
|
6
9
|
const NEXARCH_URL = "https://nexarch.ai";
|
|
7
10
|
const LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
8
11
|
function printLoginBanner() {
|
|
@@ -152,6 +155,20 @@ export async function login(args) {
|
|
|
152
155
|
companyId,
|
|
153
156
|
expiresAt: expiresAt.toISOString(),
|
|
154
157
|
});
|
|
158
|
+
try {
|
|
159
|
+
const identityDir = join(homedir(), ".nexarch");
|
|
160
|
+
mkdirSync(identityDir, { recursive: true });
|
|
161
|
+
const identityPath = join(identityDir, "identity.json");
|
|
162
|
+
const existing = existsSync(identityPath)
|
|
163
|
+
? JSON.parse(readFileSync(identityPath, "utf8"))
|
|
164
|
+
: {};
|
|
165
|
+
const next = { ...existing, companyId };
|
|
166
|
+
delete next.projectKeys;
|
|
167
|
+
writeFileSync(identityPath, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// non-fatal
|
|
171
|
+
}
|
|
155
172
|
console.log("✓ Logged in successfully");
|
|
156
173
|
console.log("\nRun `nexarch status` to verify your connection.");
|
|
157
174
|
}
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { loadCredentials, removeCredentials } from "../lib/credentials.js";
|
|
2
|
+
import { existsSync, rmSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
2
5
|
export async function logout(_args) {
|
|
3
6
|
const creds = loadCredentials();
|
|
4
7
|
if (!creds) {
|
|
@@ -6,7 +9,11 @@ export async function logout(_args) {
|
|
|
6
9
|
return;
|
|
7
10
|
}
|
|
8
11
|
removeCredentials();
|
|
12
|
+
const identityPath = join(homedir(), ".nexarch", "identity.json");
|
|
13
|
+
if (existsSync(identityPath))
|
|
14
|
+
rmSync(identityPath);
|
|
9
15
|
console.log("✓ Logged out. Credentials removed from ~/.nexarch/credentials.json");
|
|
16
|
+
console.log("✓ Local identity removed from ~/.nexarch/identity.json");
|
|
10
17
|
console.log("\nNote: the token still exists in your Nexarch workspace until revoked.");
|
|
11
18
|
console.log("To revoke it, visit Workspace → Agents → Manage tokens.");
|
|
12
19
|
}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { resolveNames } from "./commands/resolve-names.js";
|
|
|
15
15
|
import { checkIn } from "./commands/check-in.js";
|
|
16
16
|
import { commandDone } from "./commands/command-done.js";
|
|
17
17
|
import { commandFail } from "./commands/command-fail.js";
|
|
18
|
+
import { commandClaim } from "./commands/command-claim.js";
|
|
18
19
|
import { policyControls } from "./commands/policy-controls.js";
|
|
19
20
|
import { policyAuditSubmit } from "./commands/policy-audit-submit.js";
|
|
20
21
|
const [, , command, ...args] = process.argv;
|
|
@@ -35,6 +36,7 @@ const commands = {
|
|
|
35
36
|
"check-in": checkIn,
|
|
36
37
|
"command-done": commandDone,
|
|
37
38
|
"command-fail": commandFail,
|
|
39
|
+
"command-claim": commandClaim,
|
|
38
40
|
"policy-controls": policyControls,
|
|
39
41
|
"policy-audit-submit": policyAuditSubmit,
|
|
40
42
|
};
|
|
@@ -117,11 +119,14 @@ Usage:
|
|
|
117
119
|
results before calling add-relationship.
|
|
118
120
|
Options: --names <csv> (required, e.g. "vercel,neon")
|
|
119
121
|
--json
|
|
120
|
-
nexarch check-in
|
|
121
|
-
|
|
122
|
-
(written by init-agent) or via --agent-key.
|
|
122
|
+
nexarch check-in Preview pending application-target commands (no auto-claim).
|
|
123
|
+
Scope is resolved server-side from active company context.
|
|
123
124
|
Options: --agent-key <key> override stored agent key
|
|
124
|
-
--
|
|
125
|
+
--json
|
|
126
|
+
nexarch command-claim
|
|
127
|
+
Explicitly claim a pending command by ID.
|
|
128
|
+
Options: --id <commandId> (required)
|
|
129
|
+
--agent-key <key> override stored agent key
|
|
125
130
|
--json
|
|
126
131
|
nexarch command-done
|
|
127
132
|
Mark a claimed command as completed.
|