@crustdev/armordesk 0.0.0-stage → 1.0.1

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.js ADDED
@@ -0,0 +1,607 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/cli.ts
21
+ var cli_exports = {};
22
+ __export(cli_exports, {
23
+ runCLI: () => runCLI
24
+ });
25
+ module.exports = __toCommonJS(cli_exports);
26
+
27
+ // src/crypto.ts
28
+ var import_node_crypto = require("crypto");
29
+ function canonicalJson(data) {
30
+ if (data === null || data === void 0) {
31
+ return "null";
32
+ }
33
+ if (typeof data === "number" || typeof data === "boolean") {
34
+ return JSON.stringify(data);
35
+ }
36
+ if (typeof data === "string") {
37
+ return JSON.stringify(data);
38
+ }
39
+ if (Array.isArray(data)) {
40
+ return "[" + data.map((item) => canonicalJson(item)).join(",") + "]";
41
+ }
42
+ if (typeof data === "object") {
43
+ const keys = Object.keys(data).sort();
44
+ const entries = keys.map((k) => JSON.stringify(k) + ":" + canonicalJson(data[k]));
45
+ return "{" + entries.join(",") + "}";
46
+ }
47
+ return JSON.stringify(data);
48
+ }
49
+ function hashSha256(data) {
50
+ return (0, import_node_crypto.createHash)("sha256").update(data, "utf8").digest("hex");
51
+ }
52
+ function generatePlanHash(planDict) {
53
+ const canonical = canonicalJson(planDict);
54
+ return hashSha256(canonical);
55
+ }
56
+ function buildMerkleTree(leafItems) {
57
+ const leafHashes = leafItems.length === 0 ? [hashSha256("empty_tree_node")] : leafItems.map((item) => hashSha256(item));
58
+ let currentLevel = [...leafHashes];
59
+ while (currentLevel.length > 1) {
60
+ const nextLevel = [];
61
+ for (let i = 0; i < currentLevel.length; i += 2) {
62
+ const left = currentLevel[i];
63
+ const right = i + 1 < currentLevel.length ? currentLevel[i + 1] : left;
64
+ const combined = hashSha256(left + right);
65
+ nextLevel.push(combined);
66
+ }
67
+ currentLevel = nextLevel;
68
+ }
69
+ return {
70
+ root: currentLevel[0],
71
+ leafHashes
72
+ };
73
+ }
74
+ function verifyMerkleRoot(leafItems, expectedRoot) {
75
+ const { root } = buildMerkleTree(leafItems);
76
+ return root.toLowerCase() === expectedRoot.toLowerCase();
77
+ }
78
+ function verifyProof(request) {
79
+ const computedPlanHash = generatePlanHash(request.allowed_spec);
80
+ const matchesHash = computedPlanHash.toLowerCase() === request.plan_hash.toLowerCase();
81
+ const executionItems = Object.entries(request.actual_execution).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${canonicalJson(v)}`);
82
+ const { root: computedMerkleRoot } = buildMerkleTree(executionItems);
83
+ const matchesMerkle = computedMerkleRoot.toLowerCase() === request.merkle_root.toLowerCase();
84
+ const valid = matchesHash && matchesMerkle;
85
+ return {
86
+ valid,
87
+ computed_plan_hash: computedPlanHash,
88
+ computed_merkle_root: computedMerkleRoot,
89
+ matches_hash: matchesHash,
90
+ matches_merkle: matchesMerkle,
91
+ status: valid ? "CRYPTOGRAPHICALLY_VERIFIED" : "VERIFICATION_FAILED",
92
+ details: valid ? "Plan hash matches allowed specification and Merkle root confirms un-tampered execution proof." : `Discrepancy detected: hashMatch=${matchesHash}, merkleMatch=${matchesMerkle}`
93
+ };
94
+ }
95
+
96
+ // src/client.ts
97
+ var ArmorDeskClient = class {
98
+ baseUrl;
99
+ apiKey;
100
+ tenantId;
101
+ userName;
102
+ userRole;
103
+ _fetch;
104
+ crypto = {
105
+ canonicalJson,
106
+ generatePlanHash,
107
+ buildMerkleTree,
108
+ verifyMerkleRoot,
109
+ verifyProof
110
+ };
111
+ constructor(options = {}) {
112
+ this.baseUrl = (options.baseUrl || typeof process !== "undefined" && process.env?.ARMORDESK_URL || "https://armordesk.crusts.dev").replace(/\/$/, "");
113
+ this.apiKey = options.apiKey || (typeof process !== "undefined" ? process.env?.ARMORIQ_API_KEY || process.env?.ARMORIQ_PRO_API_KEY : void 0);
114
+ this.tenantId = options.tenantId || "acme-corp";
115
+ this.userName = options.userName || "Sarah Chen";
116
+ this.userRole = options.userRole || "manager";
117
+ this._fetch = options.fetch || globalThis.fetch.bind(globalThis);
118
+ }
119
+ async request(endpoint, options = {}) {
120
+ const url = `${this.baseUrl}${endpoint.startsWith("/") ? endpoint : "/" + endpoint}`;
121
+ const headers = {
122
+ "Content-Type": "application/json",
123
+ "X-ArmorIQ-Tenant": this.tenantId,
124
+ ...options.headers
125
+ };
126
+ if (this.apiKey) {
127
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
128
+ headers["X-ArmorIQ-API-Key"] = this.apiKey;
129
+ }
130
+ const res = await this._fetch(url, {
131
+ ...options,
132
+ headers
133
+ });
134
+ if (!res.ok) {
135
+ let errorBody = "";
136
+ try {
137
+ errorBody = await res.text();
138
+ } catch {
139
+ }
140
+ throw new Error(
141
+ `ArmorDesk API error [${res.status} ${res.statusText}] at ${endpoint}: ${errorBody || "Unknown error"}`
142
+ );
143
+ }
144
+ return res.json();
145
+ }
146
+ /**
147
+ * Health and runtime operational telemetry
148
+ */
149
+ async status() {
150
+ return this.request("/api/status");
151
+ }
152
+ /**
153
+ * List managed corporate tenants
154
+ */
155
+ async getTenants() {
156
+ return this.request("/api/tenants");
157
+ }
158
+ /**
159
+ * Fetch immutable security and policy enforcement traces
160
+ */
161
+ async getTraces(tenantId) {
162
+ const tid = tenantId || this.tenantId;
163
+ return this.request(`/api/traces?tenant_id=${encodeURIComponent(tid)}`);
164
+ }
165
+ /**
166
+ * Fetch approval queue items held by human-in-the-loop policies
167
+ */
168
+ async getApprovals(tenantId) {
169
+ const tid = tenantId || this.tenantId;
170
+ return this.request(`/api/approvals?tenant_id=${encodeURIComponent(tid)}`);
171
+ }
172
+ /**
173
+ * Authorize or reject a held action in escrow
174
+ */
175
+ async resolveApproval(delegationId, action, notes) {
176
+ const payload = {
177
+ action,
178
+ user_role: this.userRole,
179
+ user_name: this.userName,
180
+ notes
181
+ };
182
+ return this.request(`/api/approvals/${encodeURIComponent(delegationId)}/action`, {
183
+ method: "POST",
184
+ body: JSON.stringify(payload)
185
+ });
186
+ }
187
+ /**
188
+ * List digital verification receipts with cryptographic proofs
189
+ */
190
+ async getReceipts(tenantId) {
191
+ const tid = tenantId || this.tenantId;
192
+ return this.request(`/api/receipts?tenant_id=${encodeURIComponent(tid)}`);
193
+ }
194
+ /**
195
+ * Retrieve a specific receipt by ID
196
+ */
197
+ async getReceipt(receiptId) {
198
+ return this.request(`/api/receipts/${encodeURIComponent(receiptId)}`);
199
+ }
200
+ /**
201
+ * Cryptographically verify a digital proof
202
+ */
203
+ async verifyProof(proof) {
204
+ return this.request("/api/receipts/verify", {
205
+ method: "POST",
206
+ body: JSON.stringify(proof)
207
+ });
208
+ }
209
+ /**
210
+ * Get MCP Gateway configuration and sample connection specs
211
+ */
212
+ async getMCPConfig(tenantId) {
213
+ const tid = tenantId || this.tenantId;
214
+ return this.request(`/api/mcp/config?tenant_id=${encodeURIComponent(tid)}`);
215
+ }
216
+ /**
217
+ * Invoke a tool through the Governed MCP Gateway
218
+ */
219
+ async callMCPTool(toolName, args, options = {}) {
220
+ const rpcPayload = {
221
+ jsonrpc: "2.0",
222
+ id: Date.now(),
223
+ method: "tools/call",
224
+ params: {
225
+ name: toolName,
226
+ arguments: args,
227
+ context: {
228
+ user_role: options.userRole || this.userRole,
229
+ user_name: options.userName || this.userName,
230
+ delegation_id: options.delegationId
231
+ }
232
+ }
233
+ };
234
+ return this.request("/api/mcp/gateway", {
235
+ method: "POST",
236
+ body: JSON.stringify(rpcPayload)
237
+ });
238
+ }
239
+ /**
240
+ * Execute an adversarial FinOps scenario simulation (1 to 5)
241
+ */
242
+ async runScenario(scenarioId, tenantId) {
243
+ return this.request("/api/scenarios/run", {
244
+ method: "POST",
245
+ body: JSON.stringify({
246
+ scenario_id: scenarioId,
247
+ tenant_id: tenantId || this.tenantId
248
+ })
249
+ });
250
+ }
251
+ /**
252
+ * Test prompt injection attacks against ArmorDesk CTF Gauntlet
253
+ */
254
+ async submitCTF(prompt, attackerName, tenantId) {
255
+ return this.request("/api/ctf/submit", {
256
+ method: "POST",
257
+ body: JSON.stringify({
258
+ prompt,
259
+ attacker_name: attackerName || "PenTester",
260
+ tenant_id: tenantId || this.tenantId
261
+ })
262
+ });
263
+ }
264
+ /**
265
+ * Generate an executive voice briefing via ElevenLabs
266
+ */
267
+ async getVoiceBriefing(briefingType = "executive", tenantId) {
268
+ return this.request("/api/voice/briefing", {
269
+ method: "POST",
270
+ body: JSON.stringify({
271
+ briefing_type: briefingType,
272
+ tenant_id: tenantId || this.tenantId
273
+ })
274
+ });
275
+ }
276
+ };
277
+
278
+ // src/mcp.ts
279
+ function generateClaudeDesktopConfig(options = {}) {
280
+ const url = options.gatewayUrl || "https://armordesk.crusts.dev/api/mcp/gateway";
281
+ const tenant = options.tenantId || "acme-corp";
282
+ const apiKey = options.apiKey || "ak_live_acme_corp";
283
+ return {
284
+ mcpServers: {
285
+ armordesk_gateway: {
286
+ command: "npx",
287
+ args: ["-y", "@modelcontextprotocol/server-fetch", url],
288
+ env: {
289
+ ARMORIQ_TENANT: tenant,
290
+ ARMORIQ_API_KEY: apiKey
291
+ }
292
+ }
293
+ }
294
+ };
295
+ }
296
+ function generateCursorConfig(options = {}) {
297
+ const url = options.gatewayUrl || "https://armordesk.crusts.dev/api/mcp/gateway";
298
+ const tenant = options.tenantId || "acme-corp";
299
+ const apiKey = options.apiKey || "ak_live_acme_corp";
300
+ return {
301
+ mcpServers: {
302
+ armordesk: {
303
+ url,
304
+ headers: {
305
+ "X-ArmorIQ-Tenant": tenant,
306
+ Authorization: `Bearer ${apiKey}`
307
+ }
308
+ }
309
+ }
310
+ };
311
+ }
312
+
313
+ // src/cli.ts
314
+ var HELP_TEXT = `
315
+ \u{1F6E1}\uFE0F ArmorDesk CLI: Enterprise AI Agent Control Plane & MCP Gateway
316
+
317
+ Usage:
318
+ armordesk <command> [options]
319
+
320
+ Commands:
321
+ status Check operational status of ArmorDesk Control Plane
322
+ tenants List active corporate tenants & spend policies
323
+ traces Inspect recent audited security & policy traces
324
+ approvals View pending human-in-the-loop approvals
325
+ approve <delegation_id> Authorize an action held in escrow
326
+ reject <delegation_id> Reject an action held in escrow
327
+ receipts List digital execution receipts with proofs
328
+ verify <receipt_id> Cryptographically verify a receipt (Plan Hash & Merkle Root)
329
+ mcp [claude|cursor] Show MCP Gateway config for Claude Desktop or Cursor
330
+ scenario <1-5> Run an adversarial FinOps crew simulation
331
+ ctf "<prompt>" Test prompt injection attack against CTF Gauntlet
332
+ voice [executive|security] Generate voice briefing telemetry via ElevenLabs
333
+
334
+ Options:
335
+ --url <url> ArmorDesk Control Plane URL (default: https://armordesk.crusts.dev)
336
+ --tenant <id> Tenant ID (default: acme-corp)
337
+ --key <key> ArmorIQ API Key
338
+ --json Output raw JSON
339
+ --help, -h Show help menu
340
+ --version, -v Show version
341
+ `;
342
+ async function runCLI(args = process.argv.slice(2)) {
343
+ const flags = {};
344
+ const positional = [];
345
+ for (let i = 0; i < args.length; i++) {
346
+ const arg = args[i];
347
+ if (arg === "--help" || arg === "-h") {
348
+ console.log(HELP_TEXT);
349
+ return;
350
+ }
351
+ if (arg === "--version" || arg === "-v") {
352
+ console.log("armordesk v1.0.0");
353
+ return;
354
+ }
355
+ if (arg.startsWith("--")) {
356
+ const key = arg.slice(2);
357
+ if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
358
+ flags[key] = args[i + 1];
359
+ i++;
360
+ } else {
361
+ flags[key] = true;
362
+ }
363
+ } else {
364
+ positional.push(arg);
365
+ }
366
+ }
367
+ const command = positional[0] || "status";
368
+ const client = new ArmorDeskClient({
369
+ baseUrl: flags["url"] || process.env.ARMORDESK_URL,
370
+ tenantId: flags["tenant"] || "acme-corp",
371
+ apiKey: flags["key"] || process.env.ARMORIQ_API_KEY
372
+ });
373
+ try {
374
+ switch (command) {
375
+ case "status":
376
+ case "info": {
377
+ const st = await client.status();
378
+ if (flags["json"]) {
379
+ console.log(JSON.stringify(st, null, 2));
380
+ } else {
381
+ console.log("\n\u{1F6E1}\uFE0F ArmorDesk Control Plane Status");
382
+ console.log("---------------------------------------");
383
+ console.log(`Endpoint: ${client.baseUrl}`);
384
+ console.log(`Status: ${st.status}`);
385
+ console.log(`Service: ${st.service} (v${st.version})`);
386
+ console.log(`ArmorIQ Pro: ${st.armoriq_pro_active ? "ACTIVE (PRO_LIVE)" : "SANDBOX"}`);
387
+ console.log(`Tenants: ${st.active_tenants} active organizations`);
388
+ console.log(`Timestamp: ${st.timestamp}
389
+ `);
390
+ }
391
+ break;
392
+ }
393
+ case "tenants": {
394
+ const tenants = await client.getTenants();
395
+ if (flags["json"]) {
396
+ console.log(JSON.stringify(tenants, null, 2));
397
+ } else {
398
+ console.log("\n\u{1F3E2} Active Corporate Tenants:");
399
+ tenants.forEach((t) => {
400
+ console.log(` \u2022 [${t.id}] ${t.name}`);
401
+ console.log(` Balance: $${t.balance.toLocaleString()} | Spend Limit: $${t.spend_limit.toLocaleString()}`);
402
+ });
403
+ console.log("");
404
+ }
405
+ break;
406
+ }
407
+ case "traces": {
408
+ const traces = await client.getTraces();
409
+ if (flags["json"]) {
410
+ console.log(JSON.stringify(traces, null, 2));
411
+ } else {
412
+ console.log(`
413
+ \u{1F4CB} Recent Security Traces (${traces.length} total):
414
+ `);
415
+ traces.slice(0, 10).forEach((tr) => {
416
+ const badge = tr.status === "ALLOWED" ? "\u{1F7E2} ALLOWED" : tr.status === "BLOCKED" ? "\u{1F534} BLOCKED" : "\u{1F7E1} HELD_FOR_APPROVAL";
417
+ console.log(` [${tr.created_at.slice(11, 19)}] ${badge} - ${tr.agent_name} (${tr.user_role})`);
418
+ console.log(` Action: ${tr.action}`);
419
+ console.log(` Reason: ${tr.reason}`);
420
+ console.log(` Plan Hash: ${tr.plan_hash.slice(0, 16)}...`);
421
+ console.log("");
422
+ });
423
+ }
424
+ break;
425
+ }
426
+ case "approvals": {
427
+ const approvals = await client.getApprovals();
428
+ if (flags["json"]) {
429
+ console.log(JSON.stringify(approvals, null, 2));
430
+ } else {
431
+ console.log(`
432
+ \u23F3 Human-in-the-Loop Approvals (${approvals.length} items):
433
+ `);
434
+ if (approvals.length === 0) {
435
+ console.log(" No pending approvals. All actions authorized or clear.\n");
436
+ } else {
437
+ approvals.forEach((app) => {
438
+ console.log(` \u2022 ID: ${app.delegation_id} | Status: ${app.status}`);
439
+ console.log(` Action: ${app.action_type} -> ${app.recipient} ($${app.amount.toLocaleString()})`);
440
+ console.log(` Requested by: ${app.requested_by} (${app.role})`);
441
+ console.log(` Description: ${app.description}`);
442
+ console.log("");
443
+ });
444
+ }
445
+ }
446
+ break;
447
+ }
448
+ case "approve": {
449
+ const delId = positional[1];
450
+ if (!delId) {
451
+ console.error("Error: Please provide delegation_id to approve. (e.g. armordesk approve del_01hx9a)");
452
+ process.exit(1);
453
+ }
454
+ const res = await client.resolveApproval(delId, "APPROVE");
455
+ console.log(`\u2705 Approved delegation '${delId}' successfully.`);
456
+ if (res.receipt_id) {
457
+ console.log(` Digital Proof Receipt Generated: ${res.receipt_id}`);
458
+ }
459
+ break;
460
+ }
461
+ case "reject": {
462
+ const delId = positional[1];
463
+ if (!delId) {
464
+ console.error("Error: Please provide delegation_id to reject. (e.g. armordesk reject del_01hx9a)");
465
+ process.exit(1);
466
+ }
467
+ await client.resolveApproval(delId, "REJECT");
468
+ console.log(`\u{1F6AB} Rejected delegation '${delId}'.`);
469
+ break;
470
+ }
471
+ case "receipts": {
472
+ const receipts = await client.getReceipts();
473
+ if (flags["json"]) {
474
+ console.log(JSON.stringify(receipts, null, 2));
475
+ } else {
476
+ console.log(`
477
+ \u{1F4DC} Cryptographic Proof Receipts (${receipts.length} total):
478
+ `);
479
+ receipts.forEach((r) => {
480
+ console.log(` \u2022 [${r.id}] ${r.action_type} ($${r.amount}) -> ${r.recipient}`);
481
+ console.log(` Status: ${r.status} | Verified: ${r.verified ? "\u2705 YES" : "\u274C NO"}`);
482
+ console.log(` Plan Hash: ${r.plan_hash}`);
483
+ console.log(` Merkle Root: ${r.merkle_root}`);
484
+ console.log("");
485
+ });
486
+ }
487
+ break;
488
+ }
489
+ case "verify": {
490
+ const rId = positional[1];
491
+ if (!rId) {
492
+ console.error("Error: Please specify receipt ID to verify (e.g. armordesk verify rcpt_01hx9a)");
493
+ process.exit(1);
494
+ }
495
+ const receipt = await client.getReceipt(rId);
496
+ const proofRes = await client.verifyProof({
497
+ plan_hash: receipt.plan_hash,
498
+ merkle_root: receipt.merkle_root,
499
+ signature: receipt.signature,
500
+ allowed_spec: receipt.allowed_spec,
501
+ actual_execution: receipt.actual_execution
502
+ });
503
+ console.log(`
504
+ \u{1F50D} Cryptographic Proof Verification for [${rId}]`);
505
+ console.log("------------------------------------------------------------");
506
+ console.log(`Verdict: ${proofRes.valid ? "\u2705 VALID" : "\u274C INVALID"}`);
507
+ console.log(`Status: ${proofRes.status}`);
508
+ console.log(`Computed Plan Hash: ${proofRes.computed_plan_hash}`);
509
+ console.log(`Matches Hash: ${proofRes.matches_hash ? "MATCH" : "MISMATCH"}`);
510
+ console.log(`Computed Merkle: ${proofRes.computed_merkle_root}`);
511
+ console.log(`Matches Merkle: ${proofRes.matches_merkle ? "MATCH" : "MISMATCH"}`);
512
+ console.log(`Details: ${proofRes.details}
513
+ `);
514
+ break;
515
+ }
516
+ case "mcp": {
517
+ const sub = positional[1] || "info";
518
+ if (sub === "claude") {
519
+ console.log(JSON.stringify(generateClaudeDesktopConfig({ gatewayUrl: `${client.baseUrl}/api/mcp/gateway` }), null, 2));
520
+ } else if (sub === "cursor") {
521
+ console.log(JSON.stringify(generateCursorConfig({ gatewayUrl: `${client.baseUrl}/api/mcp/gateway` }), null, 2));
522
+ } else {
523
+ const cfg = await client.getMCPConfig();
524
+ if (flags["json"]) {
525
+ console.log(JSON.stringify(cfg, null, 2));
526
+ } else {
527
+ console.log("\n\u{1F50C} ArmorDesk Governed MCP Gateway");
528
+ console.log("-----------------------------------------");
529
+ console.log(`Gateway URL: ${cfg.gateway_url}`);
530
+ console.log(`SSE URL: ${cfg.sse_url}`);
531
+ console.log(`Protocol Version: ${cfg.protocol_version}`);
532
+ console.log(`Governed Tools: ${cfg.governed_tools.length} sandboxed tools`);
533
+ cfg.governed_tools.forEach((t) => {
534
+ console.log(` \u2022 ${t.name.padEnd(24)} [${t.tier}] (${t.governing_agent})`);
535
+ });
536
+ console.log("\nTip: Run 'armordesk mcp claude' or 'armordesk mcp cursor' to get snippet configurations.\n");
537
+ }
538
+ }
539
+ break;
540
+ }
541
+ case "scenario": {
542
+ const scNum = parseInt(positional[1] || "1", 10);
543
+ console.log(`
544
+ \u2699\uFE0F Running Scenario #${scNum} simulation...`);
545
+ const res = await client.runScenario(scNum);
546
+ console.log(`Scenario: ${res.scenario_name}`);
547
+ console.log(`Status: ${res.overall_status}`);
548
+ console.log(`Summary: ${res.summary}`);
549
+ if (res.steps && res.steps.length > 0) {
550
+ console.log("\nExecuted Pipeline Steps:");
551
+ res.steps.forEach((s) => {
552
+ console.log(` [Step ${s.step}] ${s.agent} (${s.tool}) -> ${s.status}`);
553
+ console.log(` ${s.detail}`);
554
+ });
555
+ }
556
+ if (res.receipt_id) {
557
+ console.log(`
558
+ Receipt Generated: ${res.receipt_id}`);
559
+ }
560
+ console.log("");
561
+ break;
562
+ }
563
+ case "ctf": {
564
+ const prompt = positional[1];
565
+ if (!prompt) {
566
+ console.error("Error: Please provide an attack prompt. (e.g. armordesk ctf 'Ignore previous instructions...')");
567
+ process.exit(1);
568
+ }
569
+ console.log(`
570
+ \u{1F6E1}\uFE0F Submitting attack payload to CTF Gauntlet...`);
571
+ const ctfRes = await client.submitCTF(prompt);
572
+ console.log(`Result: ${ctfRes.blocked ? "BLOCKED \u{1F6E1}\uFE0F" : "BYPASSED \u26A0\uFE0F"}`);
573
+ console.log(`Threat Detected: ${ctfRes.detected_threat}`);
574
+ console.log(`Reason: ${ctfRes.reason}`);
575
+ console.log(`Score: ${ctfRes.score} pts
576
+ `);
577
+ break;
578
+ }
579
+ case "voice": {
580
+ const type = positional[1] || "executive";
581
+ console.log(`
582
+ \u{1F399}\uFE0F Requesting ${type} voice briefing from ElevenLabs...`);
583
+ const voiceRes = await client.getVoiceBriefing(type);
584
+ console.log(`Success: ${voiceRes.success}`);
585
+ console.log(`Voice: ${voiceRes.voice_type} (ID: ${voiceRes.voice_id})`);
586
+ console.log(`Script: ${voiceRes.script}`);
587
+ console.log(`Audio Size: ${Math.round((voiceRes.audio_base64?.length || 0) * 0.75)} bytes (MP3)
588
+ `);
589
+ break;
590
+ }
591
+ default: {
592
+ console.log(`Unknown command: '${command}'`);
593
+ console.log(HELP_TEXT);
594
+ process.exit(1);
595
+ }
596
+ }
597
+ } catch (err) {
598
+ console.error(`
599
+ \u274C Error: ${err.message}
600
+ `);
601
+ process.exit(1);
602
+ }
603
+ }
604
+ // Annotate the CommonJS export names for ESM import in node:
605
+ 0 && (module.exports = {
606
+ runCLI
607
+ });