@crustdev/armordesk 1.0.1 → 1.0.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/README.md +19 -10
- package/dist/{chunk-TVWUJ3XJ.mjs → chunk-IKQRJ7XB.mjs} +137 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +297 -20
- package/dist/cli.mjs +171 -16
- package/dist/client.d.ts +32 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +142 -6
- package/dist/index.mjs +11 -1
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ArmorDeskClient,
|
|
3
|
+
clearStoredConfig,
|
|
3
4
|
generateClaudeDesktopConfig,
|
|
4
|
-
generateCursorConfig
|
|
5
|
-
|
|
5
|
+
generateCursorConfig,
|
|
6
|
+
getConfigPath,
|
|
7
|
+
loadStoredConfig,
|
|
8
|
+
saveStoredConfig
|
|
9
|
+
} from "./chunk-IKQRJ7XB.mjs";
|
|
6
10
|
|
|
7
11
|
// src/cli.ts
|
|
12
|
+
import { exec } from "child_process";
|
|
13
|
+
function tryOpenBrowser(url) {
|
|
14
|
+
try {
|
|
15
|
+
const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}" 2>/dev/null`;
|
|
16
|
+
exec(cmd, () => {
|
|
17
|
+
});
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
8
21
|
var HELP_TEXT = `
|
|
9
22
|
\u{1F6E1}\uFE0F ArmorDesk CLI: Enterprise AI Agent Control Plane & MCP Gateway
|
|
10
23
|
|
|
11
24
|
Usage:
|
|
12
25
|
armordesk <command> [options]
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
Account & Authentication:
|
|
28
|
+
login [--email <email>] Authenticate with armordesk.crusts.dev
|
|
29
|
+
whoami Display active authenticated account & role
|
|
30
|
+
logout Clear local session credentials
|
|
31
|
+
|
|
32
|
+
MCP Gateway & Diagnostics:
|
|
33
|
+
mcp [check|status] Verify if MCP Gateway is connected & reachable
|
|
34
|
+
mcp claude Output Claude Desktop MCP configuration JSON
|
|
35
|
+
mcp cursor Output Cursor IDE MCP configuration JSON
|
|
36
|
+
|
|
37
|
+
Security & Governance:
|
|
15
38
|
status Check operational status of ArmorDesk Control Plane
|
|
16
39
|
tenants List active corporate tenants & spend policies
|
|
17
40
|
traces Inspect recent audited security & policy traces
|
|
@@ -20,12 +43,13 @@ var HELP_TEXT = `
|
|
|
20
43
|
reject <delegation_id> Reject an action held in escrow
|
|
21
44
|
receipts List digital execution receipts with proofs
|
|
22
45
|
verify <receipt_id> Cryptographically verify a receipt (Plan Hash & Merkle Root)
|
|
23
|
-
mcp [claude|cursor] Show MCP Gateway config for Claude Desktop or Cursor
|
|
24
46
|
scenario <1-5> Run an adversarial FinOps crew simulation
|
|
25
47
|
ctf "<prompt>" Test prompt injection attack against CTF Gauntlet
|
|
26
48
|
voice [executive|security] Generate voice briefing telemetry via ElevenLabs
|
|
27
49
|
|
|
28
50
|
Options:
|
|
51
|
+
--email <email> Account email for login (default: rustaman@crusts.dev)
|
|
52
|
+
--password <pass> Account password for login
|
|
29
53
|
--url <url> ArmorDesk Control Plane URL (default: https://armordesk.crusts.dev)
|
|
30
54
|
--tenant <id> Tenant ID (default: acme-corp)
|
|
31
55
|
--key <key> ArmorIQ API Key
|
|
@@ -66,6 +90,125 @@ async function runCLI(args = process.argv.slice(2)) {
|
|
|
66
90
|
});
|
|
67
91
|
try {
|
|
68
92
|
switch (command) {
|
|
93
|
+
case "login": {
|
|
94
|
+
const explicitEmail = flags["email"] || (positional[1] && positional[1].includes("@") ? positional[1] : null);
|
|
95
|
+
if (explicitEmail) {
|
|
96
|
+
const password = flags["password"] || "admin";
|
|
97
|
+
const tenant = flags["tenant"] || "acme-corp";
|
|
98
|
+
console.log(`
|
|
99
|
+
\u{1F510} Authenticating directly with ArmorDesk at ${client.baseUrl}...`);
|
|
100
|
+
const loginRes = await client.login(explicitEmail, password, tenant);
|
|
101
|
+
console.log("------------------------------------------------------------");
|
|
102
|
+
console.log(`\u2705 Logged in successfully as ${loginRes.user.name}!`);
|
|
103
|
+
console.log(` Email: ${loginRes.user.email}`);
|
|
104
|
+
console.log(` Role: ${loginRes.user.role.toUpperCase()}`);
|
|
105
|
+
console.log(` Title: ${loginRes.user.title}`);
|
|
106
|
+
console.log(` Tenant: ${loginRes.tenant.name} (${loginRes.tenant.id})`);
|
|
107
|
+
console.log(` Bank Balance: $${loginRes.tenant.balance.toLocaleString()} ${loginRes.tenant.currency}`);
|
|
108
|
+
console.log(` Scope: ${loginRes.user.scopeSummary}`);
|
|
109
|
+
console.log(`
|
|
110
|
+
\u{1F4C1} Session saved to: ${getConfigPath()}`);
|
|
111
|
+
console.log("All armordesk commands will now execute under this identity.\n");
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
console.log(`
|
|
115
|
+
\u{1F510} Initiating ArmorDesk Browser Authorization...`);
|
|
116
|
+
const codeRes = await client.requestDeviceCode();
|
|
117
|
+
console.log("------------------------------------------------------------");
|
|
118
|
+
console.log(` 1. Please visit the authorization URL in your browser:`);
|
|
119
|
+
console.log(` \u{1F449} \x1B[36m\x1B[1m${codeRes.verification_uri_complete}\x1B[0m`);
|
|
120
|
+
console.log(`
|
|
121
|
+
2. Confirm your one-time device code:`);
|
|
122
|
+
console.log(` \u{1F511} \x1B[32m\x1B[1m${codeRes.user_code}\x1B[0m`);
|
|
123
|
+
console.log("------------------------------------------------------------");
|
|
124
|
+
console.log(`Waiting for browser authorization... (Press Ctrl+C to abort)`);
|
|
125
|
+
tryOpenBrowser(codeRes.verification_uri_complete);
|
|
126
|
+
let approved = false;
|
|
127
|
+
const intervalMs = (codeRes.interval || 2) * 1e3;
|
|
128
|
+
const maxPolls = 450;
|
|
129
|
+
let polls = 0;
|
|
130
|
+
while (!approved && polls < maxPolls) {
|
|
131
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
132
|
+
polls++;
|
|
133
|
+
try {
|
|
134
|
+
const pollRes = await client.pollDeviceCode(codeRes.device_code);
|
|
135
|
+
if (pollRes.status === "APPROVED" && pollRes.token && pollRes.user) {
|
|
136
|
+
approved = true;
|
|
137
|
+
saveStoredConfig({
|
|
138
|
+
baseUrl: client.baseUrl,
|
|
139
|
+
token: pollRes.token,
|
|
140
|
+
user: {
|
|
141
|
+
id: pollRes.user.id,
|
|
142
|
+
name: pollRes.user.name,
|
|
143
|
+
email: pollRes.user.email,
|
|
144
|
+
role: pollRes.user.role,
|
|
145
|
+
title: pollRes.user.role === "manager" ? "Corporate Officer" : "FinOps Member",
|
|
146
|
+
avatar: pollRes.user.name.split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase() || "CU",
|
|
147
|
+
tenant_id: pollRes.user.tenant_id,
|
|
148
|
+
scopeSummary: pollRes.user.role === "manager" ? "Full Treasury & Wire Transfer Approval Authority" : "Restricted View-Only Scope"
|
|
149
|
+
},
|
|
150
|
+
tenant: pollRes.tenant,
|
|
151
|
+
apiKey: client.apiKey,
|
|
152
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
153
|
+
});
|
|
154
|
+
console.log("\n------------------------------------------------------------");
|
|
155
|
+
console.log(`\u2705 Authorization Approved by Browser!`);
|
|
156
|
+
console.log(` User: ${pollRes.user.name} (${pollRes.user.email})`);
|
|
157
|
+
console.log(` Role: ${pollRes.user.role.toUpperCase()}`);
|
|
158
|
+
console.log(` Tenant: ${pollRes.tenant?.name || pollRes.user.tenant_id}`);
|
|
159
|
+
console.log(`
|
|
160
|
+
\u{1F4C1} Session saved to: ${getConfigPath()}`);
|
|
161
|
+
console.log("All armordesk commands will now execute under this identity.\n");
|
|
162
|
+
break;
|
|
163
|
+
} else if (pollRes.status === "DENIED") {
|
|
164
|
+
console.error("\n\u274C Authorization request was declined in browser.");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
} else if (pollRes.status === "EXPIRED") {
|
|
167
|
+
console.error("\n\u231B Device code has expired. Please run 'armordesk login' again.");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
} else {
|
|
170
|
+
process.stdout.write(".");
|
|
171
|
+
}
|
|
172
|
+
} catch (err) {
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!approved) {
|
|
176
|
+
console.error("\n\u231B Authorization timed out. Please try logging in again.");
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
case "whoami": {
|
|
182
|
+
const cfg = loadStoredConfig();
|
|
183
|
+
if (!cfg.user) {
|
|
184
|
+
console.log("\n\u26A0\uFE0F Not currently logged in.");
|
|
185
|
+
console.log("Run 'armordesk login --email <your_email>' to authenticate.\n");
|
|
186
|
+
} else {
|
|
187
|
+
console.log("\n\u{1F464} ArmorDesk Active Identity");
|
|
188
|
+
console.log("------------------------------------------------------------");
|
|
189
|
+
console.log(`User: ${cfg.user.name} (${cfg.user.email})`);
|
|
190
|
+
console.log(`Role: ${cfg.user.role.toUpperCase()} \xB7 ${cfg.user.title}`);
|
|
191
|
+
console.log(`Tenant: ${cfg.tenant?.name || "Corporate"} (${cfg.user.tenant_id})`);
|
|
192
|
+
if (cfg.tenant) {
|
|
193
|
+
console.log(`Treasury: $${cfg.tenant.balance.toLocaleString()} ${cfg.tenant.currency}`);
|
|
194
|
+
console.log(`Spend Limit: $${cfg.tenant.spend_limit.toLocaleString()} USD`);
|
|
195
|
+
}
|
|
196
|
+
console.log(`Scope: ${cfg.user.scopeSummary}`);
|
|
197
|
+
console.log(`Endpoint: ${cfg.baseUrl || client.baseUrl}`);
|
|
198
|
+
console.log(`Config file: ${getConfigPath()}
|
|
199
|
+
`);
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
case "logout": {
|
|
204
|
+
const cleared = clearStoredConfig();
|
|
205
|
+
if (cleared) {
|
|
206
|
+
console.log("\n\u{1F44B} Logged out successfully. Local session cleared.\n");
|
|
207
|
+
} else {
|
|
208
|
+
console.log("\nNo active session found to logout.\n");
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
69
212
|
case "status":
|
|
70
213
|
case "info": {
|
|
71
214
|
const st = await client.status();
|
|
@@ -208,26 +351,38 @@ async function runCLI(args = process.argv.slice(2)) {
|
|
|
208
351
|
break;
|
|
209
352
|
}
|
|
210
353
|
case "mcp": {
|
|
211
|
-
const sub = positional[1] || "
|
|
354
|
+
const sub = positional[1] || "check";
|
|
212
355
|
if (sub === "claude") {
|
|
213
356
|
console.log(JSON.stringify(generateClaudeDesktopConfig({ gatewayUrl: `${client.baseUrl}/api/mcp/gateway` }), null, 2));
|
|
214
357
|
} else if (sub === "cursor") {
|
|
215
358
|
console.log(JSON.stringify(generateCursorConfig({ gatewayUrl: `${client.baseUrl}/api/mcp/gateway` }), null, 2));
|
|
216
359
|
} else {
|
|
217
|
-
|
|
360
|
+
console.log(`
|
|
361
|
+
\u{1F50D} Probing ArmorDesk Governed MCP Gateway at ${client.baseUrl}...`);
|
|
362
|
+
const diag = await client.checkMCP();
|
|
218
363
|
if (flags["json"]) {
|
|
219
|
-
console.log(JSON.stringify(
|
|
364
|
+
console.log(JSON.stringify(diag, null, 2));
|
|
220
365
|
} else {
|
|
221
|
-
console.log("
|
|
222
|
-
console.log("
|
|
223
|
-
console.log(`Gateway
|
|
224
|
-
console.log(`
|
|
225
|
-
console.log(`
|
|
226
|
-
console.log(`
|
|
227
|
-
|
|
228
|
-
|
|
366
|
+
console.log("------------------------------------------------------------");
|
|
367
|
+
console.log(`Connection: ${diag.connected ? "\u{1F7E2} ONLINE & CONNECTED" : "\u{1F534} DISCONNECTED"}`);
|
|
368
|
+
console.log(`Gateway Ping: ${diag.ping.status} (${diag.latencyMs}ms roundtrip)`);
|
|
369
|
+
console.log(`Gateway URL: ${diag.config.gateway_url}`);
|
|
370
|
+
console.log(`SSE URL: ${diag.config.sse_url}`);
|
|
371
|
+
console.log(`Protocol Version: ${diag.ping.protocol}`);
|
|
372
|
+
console.log(`Governance: ${diag.ping.governance}`);
|
|
373
|
+
console.log(`Sandboxes Active: ${diag.ping.active_sandboxes.join(", ")}`);
|
|
374
|
+
console.log(`Connected Agents: ${diag.config.connected_agents.length} fleet agents`);
|
|
375
|
+
diag.config.connected_agents.forEach((ag) => {
|
|
376
|
+
console.log(` \u2022 ${ag.name.padEnd(28)} [${ag.status}] (Sandbox: ${ag.assigned_sandbox})`);
|
|
377
|
+
});
|
|
378
|
+
console.log(`
|
|
379
|
+
Governed Tools: ${diag.config.governed_tools.length} policed tools`);
|
|
380
|
+
diag.config.governed_tools.forEach((t) => {
|
|
381
|
+
const desc = (t.description || "").slice(0, 55);
|
|
382
|
+
console.log(` \u2022 ${t.name.padEnd(24)} ${desc}...`);
|
|
229
383
|
});
|
|
230
|
-
console.log("\
|
|
384
|
+
console.log("\nVerdict: \u2705 MCP GATEWAY IS FULLY CONNECTED & GOVERNED");
|
|
385
|
+
console.log("Tip: Run 'armordesk mcp claude' or 'armordesk mcp cursor' to get MCP client configs.\n");
|
|
231
386
|
}
|
|
232
387
|
}
|
|
233
388
|
break;
|
package/dist/client.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type { ArmorDeskClientOptions, ArmorDeskStatus, TenantInfo, TraceItem, ApprovalItem, ReceiptItem, VerifyProofRequest, VerifyProofResponse, MCPGatewayConfig, MCPCallResponse, ScenarioRunResponse, CTFSubmitResponse, VoiceBriefingResponse } from "./types.js";
|
|
1
|
+
import type { ArmorDeskClientOptions, ArmorDeskStatus, TenantInfo, TraceItem, ApprovalItem, ReceiptItem, VerifyProofRequest, VerifyProofResponse, MCPGatewayConfig, MCPCallResponse, ScenarioRunResponse, CTFSubmitResponse, VoiceBriefingResponse, LoginResponse, MCPStatusResponse, DeviceCodeResponse, DevicePollResponse } from "./types.js";
|
|
2
2
|
import { canonicalJson, generatePlanHash, buildMerkleTree, verifyMerkleRoot, verifyProof } from "./crypto.js";
|
|
3
3
|
export declare class ArmorDeskClient {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
tenantId: string;
|
|
7
|
+
userName: string;
|
|
8
|
+
userRole: string;
|
|
9
|
+
token?: string;
|
|
9
10
|
private readonly _fetch;
|
|
10
11
|
readonly crypto: {
|
|
11
12
|
canonicalJson: typeof canonicalJson;
|
|
@@ -16,6 +17,31 @@ export declare class ArmorDeskClient {
|
|
|
16
17
|
};
|
|
17
18
|
constructor(options?: ArmorDeskClientOptions);
|
|
18
19
|
private request;
|
|
20
|
+
/**
|
|
21
|
+
* Authenticate with an ArmorDesk account and persist credentials
|
|
22
|
+
*/
|
|
23
|
+
login(email: string, password?: string, tenantId?: string): Promise<LoginResponse>;
|
|
24
|
+
/**
|
|
25
|
+
* Request OAuth 2.0 Device Code for terminal/browser authentication (RFC 8628)
|
|
26
|
+
*/
|
|
27
|
+
requestDeviceCode(): Promise<DeviceCodeResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* Poll OAuth 2.0 Device Code until authorized by user in browser
|
|
30
|
+
*/
|
|
31
|
+
pollDeviceCode(deviceCode: string): Promise<DevicePollResponse>;
|
|
32
|
+
/**
|
|
33
|
+
* Check live status and ping telemetry of Governed MCP Gateway
|
|
34
|
+
*/
|
|
35
|
+
getMCPStatus(): Promise<MCPStatusResponse>;
|
|
36
|
+
/**
|
|
37
|
+
* Comprehensive MCP diagnostic: measures latency, pings gateway, and tests tool readiness
|
|
38
|
+
*/
|
|
39
|
+
checkMCP(tenantId?: string): Promise<{
|
|
40
|
+
connected: boolean;
|
|
41
|
+
latencyMs: number;
|
|
42
|
+
ping: MCPStatusResponse;
|
|
43
|
+
config: MCPGatewayConfig;
|
|
44
|
+
}>;
|
|
19
45
|
/**
|
|
20
46
|
* Health and runtime operational telemetry
|
|
21
47
|
*/
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,eAAe,EACf,UAAU,EACV,SAAS,EACT,YAAY,EAEZ,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAEhB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { StoredConfig } from "./types.js";
|
|
2
|
+
export declare function getConfigDir(): string;
|
|
3
|
+
export declare function getConfigPath(): string;
|
|
4
|
+
export declare function loadStoredConfig(): StoredConfig;
|
|
5
|
+
export declare function saveStoredConfig(config: StoredConfig): void;
|
|
6
|
+
export declare function clearStoredConfig(): boolean;
|
|
7
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,gBAAgB,IAAI,YAAY,CAW/C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAc3D;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAW3C"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -23,10 +23,15 @@ __export(index_exports, {
|
|
|
23
23
|
ArmorDeskClient: () => ArmorDeskClient,
|
|
24
24
|
buildMerkleTree: () => buildMerkleTree,
|
|
25
25
|
canonicalJson: () => canonicalJson,
|
|
26
|
+
clearStoredConfig: () => clearStoredConfig,
|
|
26
27
|
generateClaudeDesktopConfig: () => generateClaudeDesktopConfig,
|
|
27
28
|
generateCursorConfig: () => generateCursorConfig,
|
|
28
29
|
generatePlanHash: () => generatePlanHash,
|
|
30
|
+
getConfigDir: () => getConfigDir,
|
|
31
|
+
getConfigPath: () => getConfigPath,
|
|
29
32
|
hashSha256: () => hashSha256,
|
|
33
|
+
loadStoredConfig: () => loadStoredConfig,
|
|
34
|
+
saveStoredConfig: () => saveStoredConfig,
|
|
30
35
|
verifyMerkleRoot: () => verifyMerkleRoot,
|
|
31
36
|
verifyProof: () => verifyProof
|
|
32
37
|
});
|
|
@@ -101,6 +106,54 @@ function verifyProof(request) {
|
|
|
101
106
|
};
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
// src/config.ts
|
|
110
|
+
var import_node_fs = require("fs");
|
|
111
|
+
var import_node_os = require("os");
|
|
112
|
+
var import_node_path = require("path");
|
|
113
|
+
function getConfigDir() {
|
|
114
|
+
return (0, import_node_path.join)((0, import_node_os.homedir)(), ".armordesk");
|
|
115
|
+
}
|
|
116
|
+
function getConfigPath() {
|
|
117
|
+
return (0, import_node_path.join)(getConfigDir(), "config.json");
|
|
118
|
+
}
|
|
119
|
+
function loadStoredConfig() {
|
|
120
|
+
try {
|
|
121
|
+
const configPath = getConfigPath();
|
|
122
|
+
if ((0, import_node_fs.existsSync)(configPath)) {
|
|
123
|
+
const raw = (0, import_node_fs.readFileSync)(configPath, "utf8");
|
|
124
|
+
return JSON.parse(raw);
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
return {};
|
|
129
|
+
}
|
|
130
|
+
function saveStoredConfig(config) {
|
|
131
|
+
try {
|
|
132
|
+
const dir = getConfigDir();
|
|
133
|
+
if (!(0, import_node_fs.existsSync)(dir)) {
|
|
134
|
+
(0, import_node_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
135
|
+
}
|
|
136
|
+
const configPath = getConfigPath();
|
|
137
|
+
(0, import_node_fs.writeFileSync)(configPath, JSON.stringify(config, null, 2), {
|
|
138
|
+
encoding: "utf8",
|
|
139
|
+
mode: 384
|
|
140
|
+
});
|
|
141
|
+
} catch (err) {
|
|
142
|
+
console.warn(`[ArmorDesk] Could not write config to ${getConfigPath()}: ${err.message}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function clearStoredConfig() {
|
|
146
|
+
try {
|
|
147
|
+
const configPath = getConfigPath();
|
|
148
|
+
if ((0, import_node_fs.existsSync)(configPath)) {
|
|
149
|
+
(0, import_node_fs.unlinkSync)(configPath);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
104
157
|
// src/client.ts
|
|
105
158
|
var ArmorDeskClient = class {
|
|
106
159
|
baseUrl;
|
|
@@ -108,6 +161,7 @@ var ArmorDeskClient = class {
|
|
|
108
161
|
tenantId;
|
|
109
162
|
userName;
|
|
110
163
|
userRole;
|
|
164
|
+
token;
|
|
111
165
|
_fetch;
|
|
112
166
|
crypto = {
|
|
113
167
|
canonicalJson,
|
|
@@ -117,11 +171,13 @@ var ArmorDeskClient = class {
|
|
|
117
171
|
verifyProof
|
|
118
172
|
};
|
|
119
173
|
constructor(options = {}) {
|
|
120
|
-
|
|
121
|
-
this.
|
|
122
|
-
this.
|
|
123
|
-
this.
|
|
124
|
-
this.
|
|
174
|
+
const stored = typeof process !== "undefined" ? loadStoredConfig() : {};
|
|
175
|
+
this.baseUrl = (options.baseUrl || typeof process !== "undefined" && process.env?.ARMORDESK_URL || stored.baseUrl || "https://armordesk.crusts.dev").replace(/\/$/, "");
|
|
176
|
+
this.apiKey = options.apiKey || (typeof process !== "undefined" ? process.env?.ARMORIQ_API_KEY || process.env?.ARMORIQ_PRO_API_KEY : void 0) || stored.apiKey;
|
|
177
|
+
this.token = stored.token;
|
|
178
|
+
this.tenantId = options.tenantId || stored.tenant?.id || "acme-corp";
|
|
179
|
+
this.userName = options.userName || stored.user?.name || "Sarah Chen";
|
|
180
|
+
this.userRole = options.userRole || stored.user?.role || "manager";
|
|
125
181
|
this._fetch = options.fetch || globalThis.fetch.bind(globalThis);
|
|
126
182
|
}
|
|
127
183
|
async request(endpoint, options = {}) {
|
|
@@ -131,7 +187,9 @@ var ArmorDeskClient = class {
|
|
|
131
187
|
"X-ArmorIQ-Tenant": this.tenantId,
|
|
132
188
|
...options.headers
|
|
133
189
|
};
|
|
134
|
-
if (this.
|
|
190
|
+
if (this.token) {
|
|
191
|
+
headers["Authorization"] = `Bearer ${this.token}`;
|
|
192
|
+
} else if (this.apiKey) {
|
|
135
193
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
136
194
|
headers["X-ArmorIQ-API-Key"] = this.apiKey;
|
|
137
195
|
}
|
|
@@ -151,6 +209,79 @@ var ArmorDeskClient = class {
|
|
|
151
209
|
}
|
|
152
210
|
return res.json();
|
|
153
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Authenticate with an ArmorDesk account and persist credentials
|
|
214
|
+
*/
|
|
215
|
+
async login(email, password = "admin", tenantId) {
|
|
216
|
+
const res = await this.request("/api/auth/login", {
|
|
217
|
+
method: "POST",
|
|
218
|
+
body: JSON.stringify({
|
|
219
|
+
email,
|
|
220
|
+
password,
|
|
221
|
+
tenant_id: tenantId || this.tenantId
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
if (res.user && res.token) {
|
|
225
|
+
this.token = res.token;
|
|
226
|
+
this.userName = res.user.name;
|
|
227
|
+
this.userRole = res.user.role;
|
|
228
|
+
if (res.tenant?.id) {
|
|
229
|
+
this.tenantId = res.tenant.id;
|
|
230
|
+
}
|
|
231
|
+
if (typeof process !== "undefined") {
|
|
232
|
+
saveStoredConfig({
|
|
233
|
+
baseUrl: this.baseUrl,
|
|
234
|
+
token: res.token,
|
|
235
|
+
user: res.user,
|
|
236
|
+
tenant: res.tenant,
|
|
237
|
+
apiKey: this.apiKey,
|
|
238
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return res;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Request OAuth 2.0 Device Code for terminal/browser authentication (RFC 8628)
|
|
246
|
+
*/
|
|
247
|
+
async requestDeviceCode() {
|
|
248
|
+
return this.request("/api/auth/device/code", {
|
|
249
|
+
method: "POST"
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Poll OAuth 2.0 Device Code until authorized by user in browser
|
|
254
|
+
*/
|
|
255
|
+
async pollDeviceCode(deviceCode) {
|
|
256
|
+
return this.request("/api/auth/device/poll", {
|
|
257
|
+
method: "POST",
|
|
258
|
+
body: JSON.stringify({ device_code: deviceCode })
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Check live status and ping telemetry of Governed MCP Gateway
|
|
263
|
+
*/
|
|
264
|
+
async getMCPStatus() {
|
|
265
|
+
return this.request("/api/mcp/ping", {
|
|
266
|
+
method: "POST"
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Comprehensive MCP diagnostic: measures latency, pings gateway, and tests tool readiness
|
|
271
|
+
*/
|
|
272
|
+
async checkMCP(tenantId) {
|
|
273
|
+
const start = Date.now();
|
|
274
|
+
const ping = await this.getMCPStatus();
|
|
275
|
+
const latencyMs = Date.now() - start;
|
|
276
|
+
const config = await this.getMCPConfig(tenantId || this.tenantId);
|
|
277
|
+
const connected = ping.status === "CONNECTED" && config.governed_tools.length > 0;
|
|
278
|
+
return {
|
|
279
|
+
connected,
|
|
280
|
+
latencyMs,
|
|
281
|
+
ping,
|
|
282
|
+
config
|
|
283
|
+
};
|
|
284
|
+
}
|
|
154
285
|
/**
|
|
155
286
|
* Health and runtime operational telemetry
|
|
156
287
|
*/
|
|
@@ -322,10 +453,15 @@ function generateCursorConfig(options = {}) {
|
|
|
322
453
|
ArmorDeskClient,
|
|
323
454
|
buildMerkleTree,
|
|
324
455
|
canonicalJson,
|
|
456
|
+
clearStoredConfig,
|
|
325
457
|
generateClaudeDesktopConfig,
|
|
326
458
|
generateCursorConfig,
|
|
327
459
|
generatePlanHash,
|
|
460
|
+
getConfigDir,
|
|
461
|
+
getConfigPath,
|
|
328
462
|
hashSha256,
|
|
463
|
+
loadStoredConfig,
|
|
464
|
+
saveStoredConfig,
|
|
329
465
|
verifyMerkleRoot,
|
|
330
466
|
verifyProof
|
|
331
467
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -2,21 +2,31 @@ import {
|
|
|
2
2
|
ArmorDeskClient,
|
|
3
3
|
buildMerkleTree,
|
|
4
4
|
canonicalJson,
|
|
5
|
+
clearStoredConfig,
|
|
5
6
|
generateClaudeDesktopConfig,
|
|
6
7
|
generateCursorConfig,
|
|
7
8
|
generatePlanHash,
|
|
9
|
+
getConfigDir,
|
|
10
|
+
getConfigPath,
|
|
8
11
|
hashSha256,
|
|
12
|
+
loadStoredConfig,
|
|
13
|
+
saveStoredConfig,
|
|
9
14
|
verifyMerkleRoot,
|
|
10
15
|
verifyProof
|
|
11
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-IKQRJ7XB.mjs";
|
|
12
17
|
export {
|
|
13
18
|
ArmorDeskClient,
|
|
14
19
|
buildMerkleTree,
|
|
15
20
|
canonicalJson,
|
|
21
|
+
clearStoredConfig,
|
|
16
22
|
generateClaudeDesktopConfig,
|
|
17
23
|
generateCursorConfig,
|
|
18
24
|
generatePlanHash,
|
|
25
|
+
getConfigDir,
|
|
26
|
+
getConfigPath,
|
|
19
27
|
hashSha256,
|
|
28
|
+
loadStoredConfig,
|
|
29
|
+
saveStoredConfig,
|
|
20
30
|
verifyMerkleRoot,
|
|
21
31
|
verifyProof
|
|
22
32
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,86 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TypeScript Type Definitions for ArmorDesk SDK
|
|
3
3
|
*/
|
|
4
|
+
export interface StoredConfig {
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
token?: string;
|
|
7
|
+
user?: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
email: string;
|
|
11
|
+
role: string;
|
|
12
|
+
title: string;
|
|
13
|
+
avatar: string;
|
|
14
|
+
tenant_id: string;
|
|
15
|
+
scopeSummary: string;
|
|
16
|
+
};
|
|
17
|
+
tenant?: {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
spend_limit: number;
|
|
21
|
+
balance: number;
|
|
22
|
+
currency: string;
|
|
23
|
+
};
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
updatedAt?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface LoginResponse {
|
|
28
|
+
status: string;
|
|
29
|
+
token: string;
|
|
30
|
+
user: {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
email: string;
|
|
34
|
+
role: string;
|
|
35
|
+
title: string;
|
|
36
|
+
avatar: string;
|
|
37
|
+
tenant_id: string;
|
|
38
|
+
scopeSummary: string;
|
|
39
|
+
};
|
|
40
|
+
tenant: {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
spend_limit: number;
|
|
44
|
+
balance: number;
|
|
45
|
+
currency: string;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export interface DeviceCodeResponse {
|
|
49
|
+
device_code: string;
|
|
50
|
+
user_code: string;
|
|
51
|
+
verification_uri: string;
|
|
52
|
+
verification_uri_complete: string;
|
|
53
|
+
expires_in: number;
|
|
54
|
+
interval: number;
|
|
55
|
+
}
|
|
56
|
+
export interface DevicePollResponse {
|
|
57
|
+
status: "PENDING" | "APPROVED" | "DENIED" | "EXPIRED" | string;
|
|
58
|
+
token?: string;
|
|
59
|
+
user?: {
|
|
60
|
+
id: string;
|
|
61
|
+
name: string;
|
|
62
|
+
email: string;
|
|
63
|
+
role: string;
|
|
64
|
+
tenant_id: string;
|
|
65
|
+
};
|
|
66
|
+
tenant?: {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
spend_limit: number;
|
|
70
|
+
balance: number;
|
|
71
|
+
currency: string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface MCPStatusResponse {
|
|
75
|
+
status: string;
|
|
76
|
+
gateway: string;
|
|
77
|
+
version: string;
|
|
78
|
+
protocol: string;
|
|
79
|
+
governance: string;
|
|
80
|
+
latency_ms: number;
|
|
81
|
+
active_sandboxes: string[];
|
|
82
|
+
timestamp: string;
|
|
83
|
+
}
|
|
4
84
|
export interface ArmorDeskClientOptions {
|
|
5
85
|
/**
|
|
6
86
|
* Base URL of ArmorDesk Control Plane instance
|