@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/dist/cli.mjs CHANGED
@@ -1,17 +1,40 @@
1
1
  import {
2
2
  ArmorDeskClient,
3
+ clearStoredConfig,
3
4
  generateClaudeDesktopConfig,
4
- generateCursorConfig
5
- } from "./chunk-TVWUJ3XJ.mjs";
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
- Commands:
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] || "info";
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
- const cfg = await client.getMCPConfig();
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(cfg, null, 2));
364
+ console.log(JSON.stringify(diag, null, 2));
220
365
  } else {
221
- console.log("\n\u{1F50C} ArmorDesk Governed MCP Gateway");
222
- console.log("-----------------------------------------");
223
- console.log(`Gateway URL: ${cfg.gateway_url}`);
224
- console.log(`SSE URL: ${cfg.sse_url}`);
225
- console.log(`Protocol Version: ${cfg.protocol_version}`);
226
- console.log(`Governed Tools: ${cfg.governed_tools.length} sandboxed tools`);
227
- cfg.governed_tools.forEach((t) => {
228
- console.log(` \u2022 ${t.name.padEnd(24)} [${t.tier}] (${t.governing_agent})`);
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("\nTip: Run 'armordesk mcp claude' or 'armordesk mcp cursor' to get snippet configurations.\n");
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
- readonly baseUrl: string;
5
- readonly apiKey?: string;
6
- readonly tenantId: string;
7
- readonly userName: string;
8
- readonly userRole: string;
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
  */
@@ -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,EACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,WAAW,EACZ,MAAM,aAAa,CAAC;AAErB,qBAAa,eAAe;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,SAAgB,MAAM;;;;;;MAMpB;gBAEU,OAAO,GAAE,sBAA2B;YAmBlC,OAAO;IAoCrB;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC;IAIxC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAIzC;;OAEG;IACG,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAKxD;;OAEG;IACG,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAK9D;;OAEG;IACG,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,SAAS,GAAG,QAAQ,EAC5B,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAa3F;;OAEG;IACG,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAK5D;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzD;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAO1E;;OAEG;IACG,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAKhE;;OAEG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,GAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KAClB,GACL,OAAO,CAAC,eAAe,CAAC;IAsB3B;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAUtF;;OAEG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC;IAW7B;;OAEG;IACG,gBAAgB,CACpB,YAAY,GAAE,UAAU,GAAG,WAAyB,EACpD,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC;CASlC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -1,5 +1,6 @@
1
1
  export * from "./types.js";
2
2
  export * from "./crypto.js";
3
+ export * from "./config.js";
3
4
  export * from "./client.js";
4
5
  export * from "./mcp.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -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
- this.baseUrl = (options.baseUrl || typeof process !== "undefined" && process.env?.ARMORDESK_URL || "https://armordesk.crusts.dev").replace(/\/$/, "");
121
- this.apiKey = options.apiKey || (typeof process !== "undefined" ? process.env?.ARMORIQ_API_KEY || process.env?.ARMORIQ_PRO_API_KEY : void 0);
122
- this.tenantId = options.tenantId || "acme-corp";
123
- this.userName = options.userName || "Sarah Chen";
124
- this.userRole = options.userRole || "manager";
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.apiKey) {
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-TVWUJ3XJ.mjs";
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