whale-code 6.4.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/swagmanager-mcp.js +7 -0
- package/dist/cli/app.js +30 -2
- package/dist/cli/chat/ChatApp.d.ts +4 -4
- package/dist/cli/chat/ChatApp.js +114 -44
- package/dist/cli/chat/ChatInput.d.ts +13 -6
- package/dist/cli/chat/ChatInput.js +433 -89
- package/dist/cli/chat/MemoryManager.d.ts +15 -0
- package/dist/cli/chat/MemoryManager.js +61 -0
- package/dist/cli/chat/MessageList.d.ts +8 -0
- package/dist/cli/chat/MessageList.js +1 -1
- package/dist/cli/chat/NodeManager.d.ts +30 -0
- package/dist/cli/chat/NodeManager.js +89 -0
- package/dist/cli/chat/NodeSelector.d.ts +19 -0
- package/dist/cli/chat/NodeSelector.js +37 -0
- package/dist/cli/chat/PlanApproval.d.ts +17 -0
- package/dist/cli/chat/PlanApproval.js +82 -0
- package/dist/cli/chat/SessionManager.d.ts +16 -0
- package/dist/cli/chat/SessionManager.js +43 -0
- package/dist/cli/chat/SlashMenu.d.ts +38 -0
- package/dist/cli/chat/SlashMenu.js +208 -0
- package/dist/cli/chat/StatusBar.d.ts +16 -0
- package/dist/cli/chat/StatusBar.js +22 -0
- package/dist/cli/chat/ThemeSelector.d.ts +14 -0
- package/dist/cli/chat/ThemeSelector.js +29 -0
- package/dist/cli/chat/ToolIndicator.d.ts +8 -0
- package/dist/cli/chat/ToolIndicator.js +33 -9
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +2 -1
- package/dist/cli/chat/hooks/useAgentLoop.js +22 -17
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +19 -0
- package/dist/cli/chat/hooks/useSlashCommands.js +254 -15
- package/dist/cli/commands/config-cmd.js +4 -25
- package/dist/cli/commands/db.d.ts +13 -0
- package/dist/cli/commands/db.js +243 -0
- package/dist/cli/commands/doctor.js +6 -9
- package/dist/cli/commands/mcp.js +1 -20
- package/dist/cli/services/agent-events.d.ts +22 -1
- package/dist/cli/services/agent-events.js +9 -0
- package/dist/cli/services/agent-loop.js +66 -2
- package/dist/cli/services/agent-worker-base.js +21 -6
- package/dist/cli/services/api-retry.d.ts +25 -0
- package/dist/cli/services/api-retry.js +91 -0
- package/dist/cli/services/auth-service.d.ts +1 -1
- package/dist/cli/services/auth-service.js +40 -19
- package/dist/cli/services/background-processes.js +26 -2
- package/dist/cli/services/config-store.d.ts +13 -1
- package/dist/cli/services/config-store.js +116 -13
- package/dist/cli/services/format-server-response.js +12 -6
- package/dist/cli/services/ink-resize-fix.d.ts +18 -0
- package/dist/cli/services/ink-resize-fix.js +66 -0
- package/dist/cli/services/interactive-tools.d.ts +14 -0
- package/dist/cli/services/interactive-tools.js +47 -2
- package/dist/cli/services/keybinding-manager.js +1 -1
- package/dist/cli/services/local-tools.js +35 -2
- package/dist/cli/services/server-tools.js +175 -3
- package/dist/cli/services/subagent.js +15 -3
- package/dist/cli/services/system-prompt.js +5 -3
- package/dist/cli/services/task-decomposer.d.ts +35 -0
- package/dist/cli/services/task-decomposer.js +199 -0
- package/dist/cli/services/team-lead.d.ts +18 -0
- package/dist/cli/services/team-lead.js +80 -0
- package/dist/cli/services/teammate.js +5 -5
- package/dist/cli/services/telemetry.d.ts +8 -2
- package/dist/cli/services/telemetry.js +116 -92
- package/dist/cli/services/tools/agent-tools.d.ts +1 -0
- package/dist/cli/services/tools/agent-tools.js +50 -4
- package/dist/cli/services/tools/file-ops.d.ts +2 -0
- package/dist/cli/services/tools/file-ops.js +71 -19
- package/dist/cli/services/tools/shell-exec.js +22 -12
- package/dist/cli/shared/Theme.d.ts +1 -2
- package/dist/cli/shared/Theme.js +1 -1
- package/dist/cli/shared/WhaleBanner.d.ts +4 -1
- package/dist/cli/shared/WhaleBanner.js +12 -8
- package/dist/cli/shared/markdown.d.ts +5 -4
- package/dist/cli/shared/markdown.js +376 -334
- package/dist/cli/shared/theme-manager.d.ts +27 -0
- package/dist/cli/shared/theme-manager.js +178 -0
- package/dist/cli/shared/theme-presets.d.ts +16 -0
- package/dist/cli/shared/theme-presets.js +265 -0
- package/dist/index.js +0 -51
- package/dist/node/adapters/imessage.d.ts +10 -0
- package/dist/node/adapters/imessage.js +45 -6
- package/dist/node/cli.js +459 -8
- package/dist/node/config.d.ts +17 -0
- package/dist/node/gateway-client.d.ts +55 -0
- package/dist/node/gateway-client.js +201 -0
- package/dist/node/portal/clipboard.d.ts +28 -0
- package/dist/node/portal/clipboard.js +183 -0
- package/dist/node/portal/discovery.d.ts +29 -0
- package/dist/node/portal/discovery.js +61 -0
- package/dist/node/portal/forward.d.ts +30 -0
- package/dist/node/portal/forward.js +90 -0
- package/dist/node/portal/index.d.ts +47 -0
- package/dist/node/portal/index.js +250 -0
- package/dist/node/portal/multiplexer.d.ts +48 -0
- package/dist/node/portal/multiplexer.js +207 -0
- package/dist/node/portal/permissions.d.ts +36 -0
- package/dist/node/portal/permissions.js +131 -0
- package/dist/node/portal/protocol.d.ts +140 -0
- package/dist/node/portal/protocol.js +193 -0
- package/dist/node/portal/screen.d.ts +18 -0
- package/dist/node/portal/screen.js +93 -0
- package/dist/node/portal/session.d.ts +68 -0
- package/dist/node/portal/session.js +127 -0
- package/dist/node/portal/shell.d.ts +26 -0
- package/dist/node/portal/shell.js +142 -0
- package/dist/node/portal/stream.d.ts +43 -0
- package/dist/node/portal/stream.js +90 -0
- package/dist/node/portal/transfer.d.ts +33 -0
- package/dist/node/portal/transfer.js +231 -0
- package/dist/node/portal/ui.d.ts +16 -0
- package/dist/node/portal/ui.js +148 -0
- package/dist/node/remote-desktop/compile-helper.d.ts +13 -0
- package/dist/node/remote-desktop/compile-helper.js +73 -0
- package/dist/node/remote-desktop/index.d.ts +67 -0
- package/dist/node/remote-desktop/index.js +220 -0
- package/dist/node/remote-desktop/protocol.d.ts +96 -0
- package/dist/node/remote-desktop/protocol.js +67 -0
- package/dist/node/runtime.d.ts +8 -1
- package/dist/node/runtime.js +117 -9
- package/dist/server/handlers/__test-utils__/test-db.d.ts +25 -0
- package/dist/server/handlers/__test-utils__/test-db.js +128 -0
- package/dist/server/handlers/api-keys.js +26 -2
- package/dist/server/handlers/browser.d.ts +0 -4
- package/dist/server/handlers/browser.js +0 -46
- package/dist/server/handlers/catalog.js +37 -14
- package/dist/server/handlers/clickhouse.d.ts +10 -0
- package/dist/server/handlers/clickhouse.js +215 -0
- package/dist/server/handlers/comms.d.ts +308 -4
- package/dist/server/handlers/comms.js +444 -11
- package/dist/server/handlers/creations.js +1 -1
- package/dist/server/handlers/crm.d.ts +54 -8
- package/dist/server/handlers/crm.js +353 -68
- package/dist/server/handlers/embeddings.js +3 -3
- package/dist/server/handlers/enrichment.js +39 -55
- package/dist/server/handlers/inventory.js +1 -1
- package/dist/server/handlers/kali.d.ts +9 -1
- package/dist/server/handlers/kali.js +50 -1
- package/dist/server/handlers/media.d.ts +8 -0
- package/dist/server/handlers/media.js +902 -0
- package/dist/server/handlers/meta-ads.js +6 -3
- package/dist/server/handlers/nodes.d.ts +2 -0
- package/dist/server/handlers/nodes.js +331 -40
- package/dist/server/handlers/operations.d.ts +4 -6
- package/dist/server/handlers/operations.js +99 -38
- package/dist/server/handlers/platform.js +224 -107
- package/dist/server/handlers/remove-bg.d.ts +6 -0
- package/dist/server/handlers/remove-bg.js +96 -0
- package/dist/server/handlers/storefront.d.ts +6 -0
- package/dist/server/handlers/storefront.js +477 -0
- package/dist/server/handlers/supply-chain.js +21 -3
- package/dist/server/handlers/workflow-steps.js +87 -31
- package/dist/server/handlers/workflows.js +4 -1
- package/dist/server/index.js +334 -88
- package/dist/server/lib/clickhouse-buffer.d.ts +48 -0
- package/dist/server/lib/clickhouse-buffer.js +175 -0
- package/dist/server/lib/clickhouse-client.d.ts +112 -0
- package/dist/server/lib/clickhouse-client.js +141 -0
- package/dist/server/lib/coa-renderer.d.ts +91 -0
- package/dist/server/lib/coa-renderer.js +411 -0
- package/dist/server/lib/compaction-service.js +45 -1
- package/dist/server/lib/pdf-renderer.d.ts +143 -0
- package/dist/server/lib/pdf-renderer.js +867 -0
- package/dist/server/lib/react-pdf-layout.d.ts +40 -0
- package/dist/server/lib/react-pdf-layout.js +437 -0
- package/dist/server/lib/server-agent-loop.d.ts +2 -0
- package/dist/server/lib/server-agent-loop.js +61 -15
- package/dist/server/lib/server-subagent.d.ts +3 -0
- package/dist/server/lib/server-subagent.js +7 -4
- package/dist/server/lib/supabase-client.js +51 -3
- package/dist/server/lib/template-resolver.js +14 -4
- package/dist/server/lib/utils.js +15 -0
- package/dist/server/local-agent-gateway.d.ts +44 -0
- package/dist/server/local-agent-gateway.js +389 -49
- package/dist/server/providers/anthropic.js +12 -2
- package/dist/server/providers/gemini.js +17 -2
- package/dist/server/proxy-handlers.js +151 -0
- package/dist/server/tool-router.d.ts +2 -2
- package/dist/server/tool-router.js +25 -35
- package/dist/shared/agent-core.d.ts +5 -2
- package/dist/shared/agent-core.js +30 -4
- package/dist/shared/api-client.js +54 -3
- package/dist/shared/sse-parser.d.ts +1 -1
- package/dist/shared/sse-parser.js +5 -2
- package/dist/shared/tool-dispatch.js +1 -1
- package/package.json +16 -10
- package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +0 -11
- package/dist/server/handlers/__test-utils__/mock-supabase.js +0 -393
|
@@ -66,7 +66,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
66
66
|
const profile = {
|
|
67
67
|
customer_id: customerId,
|
|
68
68
|
store_id: sid,
|
|
69
|
-
|
|
69
|
+
enrichment_source: "pdl",
|
|
70
70
|
enrichment_data: pdlData,
|
|
71
71
|
enriched_at: nowISO(),
|
|
72
72
|
updated_at: nowISO(),
|
|
@@ -157,7 +157,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
157
157
|
const profile = {
|
|
158
158
|
customer_id: customerId,
|
|
159
159
|
store_id: sid,
|
|
160
|
-
|
|
160
|
+
enrichment_source: "brightdata",
|
|
161
161
|
enrichment_data: profileData,
|
|
162
162
|
enriched_at: nowISO(),
|
|
163
163
|
updated_at: nowISO(),
|
|
@@ -179,7 +179,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
179
179
|
.select("id")
|
|
180
180
|
.eq("customer_id", customerId)
|
|
181
181
|
.eq("store_id", sid)
|
|
182
|
-
.eq("
|
|
182
|
+
.eq("enrichment_source", "brightdata")
|
|
183
183
|
.maybeSingle();
|
|
184
184
|
let result;
|
|
185
185
|
if (existing) {
|
|
@@ -245,17 +245,17 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
245
245
|
breach_domain: breach.domain || null,
|
|
246
246
|
breach_date: breach.xposed_date || breach.date || null,
|
|
247
247
|
data_classes: breach.xposed_data ? breach.xposed_data.split(",").map((s) => s.trim()) : null,
|
|
248
|
-
|
|
248
|
+
breach_source: "xonplus",
|
|
249
249
|
raw_data: breach,
|
|
250
250
|
discovered_at: nowISO(),
|
|
251
251
|
created_at: nowISO(),
|
|
252
252
|
};
|
|
253
|
-
// Deduplicate by customer_id + breach_name +
|
|
253
|
+
// Deduplicate by customer_id + breach_name + breach_source
|
|
254
254
|
const { data: existing } = await sb.from("customer_breach_records")
|
|
255
255
|
.select("id")
|
|
256
256
|
.eq("customer_id", customerId)
|
|
257
257
|
.eq("breach_name", record.breach_name)
|
|
258
|
-
.eq("
|
|
258
|
+
.eq("breach_source", "xonplus")
|
|
259
259
|
.maybeSingle();
|
|
260
260
|
if (!existing) {
|
|
261
261
|
const { data, error } = await sb.from("customer_breach_records")
|
|
@@ -326,8 +326,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
326
326
|
data_classes: breach.DataClasses,
|
|
327
327
|
description: breach.Description,
|
|
328
328
|
is_verified: breach.IsVerified,
|
|
329
|
-
|
|
330
|
-
source: "hibp",
|
|
329
|
+
breach_source: "hibp",
|
|
331
330
|
discovered_at: nowISO(),
|
|
332
331
|
created_at: nowISO(),
|
|
333
332
|
};
|
|
@@ -404,7 +403,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
404
403
|
breach_domain: entry.domain || null,
|
|
405
404
|
breach_date: entry.obtained_date || null,
|
|
406
405
|
data_classes: entry.type ? [entry.type] : null,
|
|
407
|
-
|
|
406
|
+
breach_source: "dehashed",
|
|
408
407
|
raw_data: entry,
|
|
409
408
|
discovered_at: nowISO(),
|
|
410
409
|
created_at: nowISO(),
|
|
@@ -442,7 +441,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
442
441
|
.eq("store_id", sid)
|
|
443
442
|
.order("enriched_at", { ascending: false });
|
|
444
443
|
if (args.source)
|
|
445
|
-
q = q.eq("
|
|
444
|
+
q = q.eq("enrichment_source", args.source);
|
|
446
445
|
const limit = args.limit || 10;
|
|
447
446
|
q = q.limit(limit);
|
|
448
447
|
const { data, error } = await q;
|
|
@@ -461,7 +460,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
461
460
|
.eq("store_id", sid)
|
|
462
461
|
.order("discovered_at", { ascending: false });
|
|
463
462
|
if (args.source)
|
|
464
|
-
q = q.eq("
|
|
463
|
+
q = q.eq("breach_source", args.source);
|
|
465
464
|
const limit = args.limit || 50;
|
|
466
465
|
q = q.limit(limit);
|
|
467
466
|
const { data, error } = await q;
|
|
@@ -478,11 +477,11 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
478
477
|
.select("*")
|
|
479
478
|
.eq("customer_id", customerId)
|
|
480
479
|
.eq("store_id", sid)
|
|
481
|
-
.order("
|
|
480
|
+
.order("first_seen_at", { ascending: false });
|
|
482
481
|
if (args.status)
|
|
483
482
|
q = q.eq("status", args.status);
|
|
484
|
-
if (args.broker)
|
|
485
|
-
q = q.eq("
|
|
483
|
+
if (args.source_name || args.broker)
|
|
484
|
+
q = q.eq("source_name", (args.source_name || args.broker));
|
|
486
485
|
const limit = args.limit || 50;
|
|
487
486
|
q = q.limit(limit);
|
|
488
487
|
const { data, error } = await q;
|
|
@@ -555,29 +554,27 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
555
554
|
// ---- STORE_EXPOSURE: Insert a broker exposure ----
|
|
556
555
|
case "store_exposure": {
|
|
557
556
|
const customerId = args.customer_id;
|
|
558
|
-
const
|
|
557
|
+
const sourceName = (args.source_name || args.broker);
|
|
559
558
|
if (!customerId)
|
|
560
559
|
return { success: false, error: "customer_id is required" };
|
|
561
|
-
if (!
|
|
562
|
-
return { success: false, error: "
|
|
560
|
+
if (!sourceName)
|
|
561
|
+
return { success: false, error: "source_name is required" };
|
|
563
562
|
// Check for existing exposure to avoid duplicates
|
|
564
563
|
const { data: existing } = await sb.from("customer_exposures")
|
|
565
564
|
.select("id")
|
|
566
565
|
.eq("customer_id", customerId)
|
|
567
566
|
.eq("store_id", sid)
|
|
568
|
-
.eq("
|
|
567
|
+
.eq("source_name", sourceName)
|
|
569
568
|
.maybeSingle();
|
|
570
569
|
if (existing) {
|
|
571
570
|
// Update existing record
|
|
572
|
-
const updates = {
|
|
573
|
-
if (args.
|
|
574
|
-
updates.
|
|
575
|
-
if (args.
|
|
576
|
-
updates.
|
|
571
|
+
const updates = {};
|
|
572
|
+
if (args.source_url)
|
|
573
|
+
updates.source_url = args.source_url;
|
|
574
|
+
if (args.data_types_exposed)
|
|
575
|
+
updates.data_types_exposed = args.data_types_exposed;
|
|
577
576
|
if (args.status)
|
|
578
577
|
updates.status = args.status;
|
|
579
|
-
if (args.exposure_data)
|
|
580
|
-
updates.exposure_data = args.exposure_data;
|
|
581
578
|
const { data, error } = await sb.from("customer_exposures")
|
|
582
579
|
.update(updates)
|
|
583
580
|
.eq("id", existing.id)
|
|
@@ -590,17 +587,16 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
590
587
|
const record = {
|
|
591
588
|
customer_id: customerId,
|
|
592
589
|
store_id: sid,
|
|
593
|
-
|
|
590
|
+
source_name: sourceName,
|
|
591
|
+
source_type: args.source_type || "data_broker",
|
|
594
592
|
status: args.status || "found",
|
|
595
|
-
|
|
593
|
+
first_seen_at: nowISO(),
|
|
596
594
|
created_at: nowISO(),
|
|
597
595
|
};
|
|
598
|
-
if (args.
|
|
599
|
-
record.
|
|
600
|
-
if (args.
|
|
601
|
-
record.
|
|
602
|
-
if (args.exposure_data)
|
|
603
|
-
record.exposure_data = args.exposure_data;
|
|
596
|
+
if (args.source_url)
|
|
597
|
+
record.source_url = args.source_url;
|
|
598
|
+
if (args.data_types_exposed)
|
|
599
|
+
record.data_types_exposed = args.data_types_exposed;
|
|
604
600
|
if (args.scan_id)
|
|
605
601
|
record.scan_id = args.scan_id;
|
|
606
602
|
const { data, error } = await sb.from("customer_exposures")
|
|
@@ -616,15 +612,9 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
616
612
|
const exposureId = args.exposure_id;
|
|
617
613
|
if (!exposureId)
|
|
618
614
|
return { success: false, error: "exposure_id is required" };
|
|
619
|
-
const updates = {
|
|
615
|
+
const updates = {};
|
|
620
616
|
if (args.status)
|
|
621
617
|
updates.status = args.status;
|
|
622
|
-
if (args.removal_method)
|
|
623
|
-
updates.removal_method = args.removal_method;
|
|
624
|
-
if (args.removal_confirmed_at)
|
|
625
|
-
updates.removal_confirmed_at = args.removal_confirmed_at;
|
|
626
|
-
if (args.notes)
|
|
627
|
-
updates.notes = args.notes;
|
|
628
618
|
if (args.status === "removed") {
|
|
629
619
|
updates.removed_at = nowISO();
|
|
630
620
|
}
|
|
@@ -641,16 +631,16 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
641
631
|
// ---- STORE_REMOVAL_REQUEST: Insert a removal request ----
|
|
642
632
|
case "store_removal_request": {
|
|
643
633
|
const customerId = args.customer_id;
|
|
644
|
-
const
|
|
634
|
+
const brokerName = (args.broker_name || args.source_name || args.broker);
|
|
645
635
|
if (!customerId)
|
|
646
636
|
return { success: false, error: "customer_id is required" };
|
|
647
|
-
if (!
|
|
648
|
-
return { success: false, error: "
|
|
637
|
+
if (!brokerName)
|
|
638
|
+
return { success: false, error: "source_name is required" };
|
|
649
639
|
const record = {
|
|
650
640
|
customer_id: customerId,
|
|
651
641
|
store_id: sid,
|
|
652
|
-
|
|
653
|
-
|
|
642
|
+
broker_name: brokerName,
|
|
643
|
+
removal_method: args.removal_method || args.method || "manual",
|
|
654
644
|
status: args.status || "pending",
|
|
655
645
|
created_at: nowISO(),
|
|
656
646
|
updated_at: nowISO(),
|
|
@@ -679,15 +669,15 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
679
669
|
// Gather data for risk calculation
|
|
680
670
|
const [exposuresResult, breachesResult, removalsResult] = await Promise.all([
|
|
681
671
|
sb.from("customer_exposures")
|
|
682
|
-
.select("id,
|
|
672
|
+
.select("id, source_name, status")
|
|
683
673
|
.eq("customer_id", customerId)
|
|
684
674
|
.eq("store_id", sid),
|
|
685
675
|
sb.from("customer_breach_records")
|
|
686
|
-
.select("id, breach_name, data_classes,
|
|
676
|
+
.select("id, breach_name, data_classes, is_verified")
|
|
687
677
|
.eq("customer_id", customerId)
|
|
688
678
|
.eq("store_id", sid),
|
|
689
679
|
sb.from("customer_removal_requests")
|
|
690
|
-
.select("id, status,
|
|
680
|
+
.select("id, status, broker_name")
|
|
691
681
|
.eq("customer_id", customerId)
|
|
692
682
|
.eq("store_id", sid),
|
|
693
683
|
]);
|
|
@@ -710,12 +700,7 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
710
700
|
score += removedExposures.length * 2;
|
|
711
701
|
// Breach scoring
|
|
712
702
|
for (const breach of breaches) {
|
|
713
|
-
|
|
714
|
-
score += 25;
|
|
715
|
-
}
|
|
716
|
-
else {
|
|
717
|
-
score += 15;
|
|
718
|
-
}
|
|
703
|
+
score += 15;
|
|
719
704
|
if (breach.is_verified) {
|
|
720
705
|
score += 5;
|
|
721
706
|
}
|
|
@@ -744,7 +729,6 @@ export async function handleEnrichment(sb, args, storeId) {
|
|
|
744
729
|
active_exposures: activeExposures.length,
|
|
745
730
|
removed_exposures: removedExposures.length,
|
|
746
731
|
total_breaches: breaches.length,
|
|
747
|
-
sensitive_breaches: breaches.filter((b) => b.is_sensitive).length,
|
|
748
732
|
completed_removals: completedRemovals.length,
|
|
749
733
|
pending_removals: removals.filter((r) => r.status === "pending").length,
|
|
750
734
|
},
|
|
@@ -415,7 +415,7 @@ export async function handleInventoryAudit(sb, args, storeId) {
|
|
|
415
415
|
switch (args.action) {
|
|
416
416
|
case "start": {
|
|
417
417
|
const { data, error } = await sb.from("inventory_audits")
|
|
418
|
-
.insert({ store_id: sid, location_id: args.location_id, status: "in_progress", started_at: new Date().toISOString() })
|
|
418
|
+
.insert({ store_id: sid, location_id: args.location_id, audit_type: args.audit_type || "full", status: "in_progress", started_at: new Date().toISOString() })
|
|
419
419
|
.select().single();
|
|
420
420
|
return error ? { success: false, error: error.message } : { success: true, data };
|
|
421
421
|
}
|
|
@@ -3,7 +3,15 @@ export interface KaliProgressEvent {
|
|
|
3
3
|
type: "stdout" | "stderr";
|
|
4
4
|
data: string;
|
|
5
5
|
}
|
|
6
|
-
export
|
|
6
|
+
export interface KaliStructuredProgress {
|
|
7
|
+
phase?: string;
|
|
8
|
+
elapsed_s: number;
|
|
9
|
+
stdout_lines: number;
|
|
10
|
+
stderr_lines: number;
|
|
11
|
+
stdout_bytes: number;
|
|
12
|
+
last_line?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function handleKali(_sb: SupabaseClient, args: Record<string, unknown>, _storeId?: string, onToolProgress?: (progress: KaliProgressEvent) => void, onStructuredProgress?: (progress: KaliStructuredProgress) => void): Promise<{
|
|
7
15
|
success: boolean;
|
|
8
16
|
data?: unknown;
|
|
9
17
|
error?: string;
|
|
@@ -5,6 +5,25 @@
|
|
|
5
5
|
const KALI_BOX_URL = process.env.KALI_BOX_URL || "http://kali-box.internal:8080";
|
|
6
6
|
const KALI_AUTH_TOKEN = process.env.KALI_AUTH_TOKEN || "";
|
|
7
7
|
const MAX_OUTPUT_CHARS = 500 * 1024; // 500KB safety cap — context_management handles limits
|
|
8
|
+
/** Detect the current phase of a command based on output patterns */
|
|
9
|
+
function detectPhase(stdout, stderr) {
|
|
10
|
+
const combined = (stderr + "\n" + stdout).toLowerCase();
|
|
11
|
+
if (combined.includes("compiling") || combined.includes("building"))
|
|
12
|
+
return "compiling";
|
|
13
|
+
if (combined.includes("scanning") || combined.includes("nmap"))
|
|
14
|
+
return "scanning";
|
|
15
|
+
if (combined.includes("downloading") || combined.includes("fetching"))
|
|
16
|
+
return "downloading";
|
|
17
|
+
if (combined.includes("installing") || combined.includes("apt"))
|
|
18
|
+
return "installing";
|
|
19
|
+
if (combined.includes("testing") || combined.includes("exploit"))
|
|
20
|
+
return "testing";
|
|
21
|
+
if (combined.includes("cracking") || combined.includes("hashcat") || combined.includes("john"))
|
|
22
|
+
return "cracking";
|
|
23
|
+
if (combined.includes("enumerating") || combined.includes("enum"))
|
|
24
|
+
return "enumerating";
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
8
27
|
const VALID_ACTIONS = new Set([
|
|
9
28
|
"exec", "exec_stream", "exec_bg", "bg_status", "bg_kill", "bg_list",
|
|
10
29
|
"upload", "download", "info", "sessions", "reset",
|
|
@@ -62,7 +81,7 @@ async function* readNDJSON(body) {
|
|
|
62
81
|
reader.releaseLock();
|
|
63
82
|
}
|
|
64
83
|
}
|
|
65
|
-
export async function handleKali(_sb, args, _storeId, onToolProgress) {
|
|
84
|
+
export async function handleKali(_sb, args, _storeId, onToolProgress, onStructuredProgress) {
|
|
66
85
|
const action = args.action;
|
|
67
86
|
if (!action) {
|
|
68
87
|
return { success: false, error: "action is required" };
|
|
@@ -112,11 +131,21 @@ export async function handleKali(_sb, args, _storeId, onToolProgress) {
|
|
|
112
131
|
// Read NDJSON stream — emit progress for each chunk, accumulate for final result
|
|
113
132
|
let stdout = "";
|
|
114
133
|
let stderr = "";
|
|
134
|
+
let stdoutLines = 0;
|
|
135
|
+
let stderrLines = 0;
|
|
136
|
+
let lastLine = "";
|
|
115
137
|
let doneEvent = null;
|
|
138
|
+
const streamStart = Date.now();
|
|
139
|
+
let lastStatusEmit = 0;
|
|
140
|
+
const STATUS_INTERVAL_MS = 3000;
|
|
116
141
|
for await (const line of readNDJSON(resp.body)) {
|
|
117
142
|
if (line.type === "stdout") {
|
|
118
143
|
const data = String(line.data || "");
|
|
119
144
|
stdout += data;
|
|
145
|
+
stdoutLines += data.split("\n").filter(l => l.trim()).length;
|
|
146
|
+
const trimmed = data.trim();
|
|
147
|
+
if (trimmed)
|
|
148
|
+
lastLine = trimmed.split("\n").pop() || lastLine;
|
|
120
149
|
// Filter out the CWD marker line from progress events
|
|
121
150
|
if (!data.includes("__KALI_END_")) {
|
|
122
151
|
onToolProgress({ type: "stdout", data });
|
|
@@ -125,11 +154,31 @@ export async function handleKali(_sb, args, _storeId, onToolProgress) {
|
|
|
125
154
|
else if (line.type === "stderr") {
|
|
126
155
|
const data = String(line.data || "");
|
|
127
156
|
stderr += data;
|
|
157
|
+
stderrLines += data.split("\n").filter(l => l.trim()).length;
|
|
128
158
|
onToolProgress({ type: "stderr", data });
|
|
129
159
|
}
|
|
130
160
|
else if (line.type === "done") {
|
|
131
161
|
doneEvent = line;
|
|
132
162
|
}
|
|
163
|
+
// Emit structured status every 3 seconds
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
if (now - lastStatusEmit >= STATUS_INTERVAL_MS) {
|
|
166
|
+
lastStatusEmit = now;
|
|
167
|
+
const structuredProgress = {
|
|
168
|
+
phase: detectPhase(stdout, stderr),
|
|
169
|
+
elapsed_s: Math.round((now - streamStart) / 1000),
|
|
170
|
+
stdout_lines: stdoutLines,
|
|
171
|
+
stderr_lines: stderrLines,
|
|
172
|
+
stdout_bytes: stdout.length,
|
|
173
|
+
last_line: lastLine.length > 120 ? lastLine.slice(0, 117) + "..." : lastLine || undefined,
|
|
174
|
+
};
|
|
175
|
+
if (onStructuredProgress) {
|
|
176
|
+
onStructuredProgress(structuredProgress);
|
|
177
|
+
}
|
|
178
|
+
// Also emit as a special "status" event through the standard progress callback
|
|
179
|
+
// so the NDJSON streaming path can relay it to the CLI
|
|
180
|
+
onToolProgress({ type: "status", progress: structuredProgress });
|
|
181
|
+
}
|
|
133
182
|
}
|
|
134
183
|
// Strip CWD marker from accumulated stdout (same as non-streaming path)
|
|
135
184
|
const markerIdx = stdout.lastIndexOf("__KALI_END_");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
type Result = {
|
|
3
|
+
success: boolean;
|
|
4
|
+
data?: unknown;
|
|
5
|
+
error?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function handleMedia(sb: SupabaseClient, args: Record<string, unknown>, storeId?: string): Promise<Result>;
|
|
8
|
+
export {};
|