windows-exe-decompiler-mcp-server 0.1.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/CODEX_INSTALLATION.md +69 -0
- package/COPILOT_INSTALLATION.md +77 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/bin/windows-exe-decompiler-mcp-server.js +3 -0
- package/dist/analysis-provenance.d.ts +184 -0
- package/dist/analysis-provenance.js +74 -0
- package/dist/analysis-task-runner.d.ts +31 -0
- package/dist/analysis-task-runner.js +160 -0
- package/dist/artifact-inventory.d.ts +23 -0
- package/dist/artifact-inventory.js +175 -0
- package/dist/cache-manager.d.ts +128 -0
- package/dist/cache-manager.js +454 -0
- package/dist/confidence-semantics.d.ts +66 -0
- package/dist/confidence-semantics.js +122 -0
- package/dist/config.d.ts +335 -0
- package/dist/config.js +193 -0
- package/dist/database.d.ts +227 -0
- package/dist/database.js +601 -0
- package/dist/decompiler-worker.d.ts +441 -0
- package/dist/decompiler-worker.js +1962 -0
- package/dist/dynamic-trace.d.ts +95 -0
- package/dist/dynamic-trace.js +629 -0
- package/dist/env-validator.d.ts +15 -0
- package/dist/env-validator.js +249 -0
- package/dist/error-handler.d.ts +28 -0
- package/dist/error-handler.example.d.ts +22 -0
- package/dist/error-handler.example.js +141 -0
- package/dist/error-handler.js +139 -0
- package/dist/ghidra-analysis-status.d.ts +49 -0
- package/dist/ghidra-analysis-status.js +178 -0
- package/dist/ghidra-config.d.ts +134 -0
- package/dist/ghidra-config.js +464 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +200 -0
- package/dist/job-queue.d.ts +169 -0
- package/dist/job-queue.js +407 -0
- package/dist/logger.d.ts +106 -0
- package/dist/logger.js +176 -0
- package/dist/policy-guard.d.ts +115 -0
- package/dist/policy-guard.js +243 -0
- package/dist/process-output.d.ts +15 -0
- package/dist/process-output.js +90 -0
- package/dist/prompts/function-explanation-review.d.ts +5 -0
- package/dist/prompts/function-explanation-review.js +64 -0
- package/dist/prompts/semantic-name-review.d.ts +5 -0
- package/dist/prompts/semantic-name-review.js +63 -0
- package/dist/runtime-correlation.d.ts +34 -0
- package/dist/runtime-correlation.js +279 -0
- package/dist/runtime-paths.d.ts +3 -0
- package/dist/runtime-paths.js +11 -0
- package/dist/selection-diff.d.ts +667 -0
- package/dist/selection-diff.js +53 -0
- package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
- package/dist/semantic-name-suggestion-artifacts.js +314 -0
- package/dist/server.d.ts +129 -0
- package/dist/server.js +578 -0
- package/dist/tools/artifact-read.d.ts +235 -0
- package/dist/tools/artifact-read.js +317 -0
- package/dist/tools/artifacts-diff.d.ts +728 -0
- package/dist/tools/artifacts-diff.js +304 -0
- package/dist/tools/artifacts-list.d.ts +515 -0
- package/dist/tools/artifacts-list.js +389 -0
- package/dist/tools/attack-map.d.ts +290 -0
- package/dist/tools/attack-map.js +519 -0
- package/dist/tools/cache-observability.d.ts +4 -0
- package/dist/tools/cache-observability.js +36 -0
- package/dist/tools/code-function-cfg.d.ts +50 -0
- package/dist/tools/code-function-cfg.js +102 -0
- package/dist/tools/code-function-decompile.d.ts +55 -0
- package/dist/tools/code-function-decompile.js +103 -0
- package/dist/tools/code-function-disassemble.d.ts +43 -0
- package/dist/tools/code-function-disassemble.js +185 -0
- package/dist/tools/code-function-explain-apply.d.ts +255 -0
- package/dist/tools/code-function-explain-apply.js +225 -0
- package/dist/tools/code-function-explain-prepare.d.ts +535 -0
- package/dist/tools/code-function-explain-prepare.js +276 -0
- package/dist/tools/code-function-explain-review.d.ts +397 -0
- package/dist/tools/code-function-explain-review.js +589 -0
- package/dist/tools/code-function-rename-apply.d.ts +248 -0
- package/dist/tools/code-function-rename-apply.js +220 -0
- package/dist/tools/code-function-rename-prepare.d.ts +506 -0
- package/dist/tools/code-function-rename-prepare.js +279 -0
- package/dist/tools/code-function-rename-review.d.ts +574 -0
- package/dist/tools/code-function-rename-review.js +761 -0
- package/dist/tools/code-functions-list.d.ts +37 -0
- package/dist/tools/code-functions-list.js +91 -0
- package/dist/tools/code-functions-rank.d.ts +34 -0
- package/dist/tools/code-functions-rank.js +90 -0
- package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
- package/dist/tools/code-functions-reconstruct.js +2807 -0
- package/dist/tools/code-functions-search.d.ts +39 -0
- package/dist/tools/code-functions-search.js +90 -0
- package/dist/tools/code-reconstruct-export.d.ts +1212 -0
- package/dist/tools/code-reconstruct-export.js +4002 -0
- package/dist/tools/code-reconstruct-plan.d.ts +274 -0
- package/dist/tools/code-reconstruct-plan.js +342 -0
- package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
- package/dist/tools/dotnet-metadata-extract.js +355 -0
- package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
- package/dist/tools/dotnet-reconstruct-export.js +1151 -0
- package/dist/tools/dotnet-types-list.d.ts +325 -0
- package/dist/tools/dotnet-types-list.js +201 -0
- package/dist/tools/dynamic-dependencies.d.ts +115 -0
- package/dist/tools/dynamic-dependencies.js +213 -0
- package/dist/tools/dynamic-memory-import.d.ts +10 -0
- package/dist/tools/dynamic-memory-import.js +567 -0
- package/dist/tools/dynamic-trace-import.d.ts +10 -0
- package/dist/tools/dynamic-trace-import.js +235 -0
- package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
- package/dist/tools/entrypoint-fallback-disasm.js +89 -0
- package/dist/tools/ghidra-analyze.d.ts +88 -0
- package/dist/tools/ghidra-analyze.js +208 -0
- package/dist/tools/ghidra-health.d.ts +37 -0
- package/dist/tools/ghidra-health.js +212 -0
- package/dist/tools/ioc-export.d.ts +209 -0
- package/dist/tools/ioc-export.js +542 -0
- package/dist/tools/packer-detect.d.ts +165 -0
- package/dist/tools/packer-detect.js +284 -0
- package/dist/tools/pe-exports-extract.d.ts +175 -0
- package/dist/tools/pe-exports-extract.js +253 -0
- package/dist/tools/pe-fingerprint.d.ts +234 -0
- package/dist/tools/pe-fingerprint.js +269 -0
- package/dist/tools/pe-imports-extract.d.ts +105 -0
- package/dist/tools/pe-imports-extract.js +245 -0
- package/dist/tools/report-generate.d.ts +157 -0
- package/dist/tools/report-generate.js +457 -0
- package/dist/tools/report-summarize.d.ts +2131 -0
- package/dist/tools/report-summarize.js +596 -0
- package/dist/tools/runtime-detect.d.ts +135 -0
- package/dist/tools/runtime-detect.js +247 -0
- package/dist/tools/sample-ingest.d.ts +94 -0
- package/dist/tools/sample-ingest.js +327 -0
- package/dist/tools/sample-profile-get.d.ts +183 -0
- package/dist/tools/sample-profile-get.js +121 -0
- package/dist/tools/sandbox-execute.d.ts +441 -0
- package/dist/tools/sandbox-execute.js +392 -0
- package/dist/tools/strings-extract.d.ts +375 -0
- package/dist/tools/strings-extract.js +314 -0
- package/dist/tools/strings-floss-decode.d.ts +143 -0
- package/dist/tools/strings-floss-decode.js +259 -0
- package/dist/tools/system-health.d.ts +434 -0
- package/dist/tools/system-health.js +446 -0
- package/dist/tools/task-cancel.d.ts +21 -0
- package/dist/tools/task-cancel.js +70 -0
- package/dist/tools/task-status.d.ts +27 -0
- package/dist/tools/task-status.js +106 -0
- package/dist/tools/task-sweep.d.ts +22 -0
- package/dist/tools/task-sweep.js +77 -0
- package/dist/tools/tool-help.d.ts +340 -0
- package/dist/tools/tool-help.js +261 -0
- package/dist/tools/yara-scan.d.ts +554 -0
- package/dist/tools/yara-scan.js +313 -0
- package/dist/types.d.ts +266 -0
- package/dist/types.js +41 -0
- package/dist/worker-pool.d.ts +204 -0
- package/dist/worker-pool.js +650 -0
- package/dist/workflows/deep-static.d.ts +104 -0
- package/dist/workflows/deep-static.js +276 -0
- package/dist/workflows/function-explanation-review.d.ts +655 -0
- package/dist/workflows/function-explanation-review.js +440 -0
- package/dist/workflows/reconstruct.d.ts +2053 -0
- package/dist/workflows/reconstruct.js +666 -0
- package/dist/workflows/semantic-name-review.d.ts +2418 -0
- package/dist/workflows/semantic-name-review.js +521 -0
- package/dist/workflows/triage.d.ts +659 -0
- package/dist/workflows/triage.js +1374 -0
- package/dist/workspace-manager.d.ts +150 -0
- package/dist/workspace-manager.js +411 -0
- package/ghidra_scripts/DecompileFunction.java +487 -0
- package/ghidra_scripts/DecompileFunction.py +150 -0
- package/ghidra_scripts/ExtractCFG.java +256 -0
- package/ghidra_scripts/ExtractCFG.py +233 -0
- package/ghidra_scripts/ExtractFunctions.java +442 -0
- package/ghidra_scripts/ExtractFunctions.py +101 -0
- package/ghidra_scripts/README.md +125 -0
- package/ghidra_scripts/SearchFunctionReferences.java +380 -0
- package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
- package/helpers/DotNetMetadataProbe/Program.cs +566 -0
- package/install-to-codex.ps1 +178 -0
- package/install-to-copilot.ps1 +303 -0
- package/package.json +101 -0
- package/requirements.txt +9 -0
- package/workers/requirements-dynamic.txt +11 -0
- package/workers/requirements.txt +8 -0
- package/workers/speakeasy_compat.py +175 -0
- package/workers/static_worker.py +5183 -0
- package/workers/yara_rules/default.yar +33 -0
- package/workers/yara_rules/malware_families.yar +93 -0
- package/workers/yara_rules/packers.yar +80 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* strings.floss.decode tool implementation
|
|
3
|
+
* Uses FLOSS tool to decode obfuscated strings from PE files
|
|
4
|
+
* Requirements: 4.4, 4.5
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import type { ToolDefinition, ToolArgs, WorkerResult } from '../types.js';
|
|
8
|
+
import type { WorkspaceManager } from '../workspace-manager.js';
|
|
9
|
+
import type { DatabaseManager } from '../database.js';
|
|
10
|
+
import type { CacheManager } from '../cache-manager.js';
|
|
11
|
+
/**
|
|
12
|
+
* Input schema for strings.floss.decode tool
|
|
13
|
+
* Requirements: 4.4, 4.5
|
|
14
|
+
*/
|
|
15
|
+
export declare const StringsFlossDecodeInputSchema: z.ZodObject<{
|
|
16
|
+
sample_id: z.ZodString;
|
|
17
|
+
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
18
|
+
modes: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEnum<["static", "stack", "tight", "decoded"]>, "many">>>;
|
|
19
|
+
force_refresh: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
timeout: number;
|
|
22
|
+
sample_id: string;
|
|
23
|
+
force_refresh: boolean;
|
|
24
|
+
modes: ("static" | "stack" | "tight" | "decoded")[];
|
|
25
|
+
}, {
|
|
26
|
+
sample_id: string;
|
|
27
|
+
timeout?: number | undefined;
|
|
28
|
+
force_refresh?: boolean | undefined;
|
|
29
|
+
modes?: ("static" | "stack" | "tight" | "decoded")[] | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
export type StringsFlossDecodeInput = z.infer<typeof StringsFlossDecodeInputSchema>;
|
|
32
|
+
/**
|
|
33
|
+
* Output schema for strings.floss.decode tool
|
|
34
|
+
* Requirements: 4.4, 4.5
|
|
35
|
+
*/
|
|
36
|
+
export declare const StringsFlossDecodeOutputSchema: z.ZodObject<{
|
|
37
|
+
ok: z.ZodBoolean;
|
|
38
|
+
data: z.ZodOptional<z.ZodObject<{
|
|
39
|
+
decoded_strings: z.ZodArray<z.ZodObject<{
|
|
40
|
+
string: z.ZodString;
|
|
41
|
+
offset: z.ZodNumber;
|
|
42
|
+
type: z.ZodString;
|
|
43
|
+
decoding_method: z.ZodNullable<z.ZodString>;
|
|
44
|
+
}, "strip", z.ZodTypeAny, {
|
|
45
|
+
string: string;
|
|
46
|
+
type: string;
|
|
47
|
+
offset: number;
|
|
48
|
+
decoding_method: string | null;
|
|
49
|
+
}, {
|
|
50
|
+
string: string;
|
|
51
|
+
type: string;
|
|
52
|
+
offset: number;
|
|
53
|
+
decoding_method: string | null;
|
|
54
|
+
}>, "many">;
|
|
55
|
+
count: z.ZodNumber;
|
|
56
|
+
timeout_occurred: z.ZodBoolean;
|
|
57
|
+
partial_results: z.ZodBoolean;
|
|
58
|
+
}, "strip", z.ZodTypeAny, {
|
|
59
|
+
count: number;
|
|
60
|
+
decoded_strings: {
|
|
61
|
+
string: string;
|
|
62
|
+
type: string;
|
|
63
|
+
offset: number;
|
|
64
|
+
decoding_method: string | null;
|
|
65
|
+
}[];
|
|
66
|
+
timeout_occurred: boolean;
|
|
67
|
+
partial_results: boolean;
|
|
68
|
+
}, {
|
|
69
|
+
count: number;
|
|
70
|
+
decoded_strings: {
|
|
71
|
+
string: string;
|
|
72
|
+
type: string;
|
|
73
|
+
offset: number;
|
|
74
|
+
decoding_method: string | null;
|
|
75
|
+
}[];
|
|
76
|
+
timeout_occurred: boolean;
|
|
77
|
+
partial_results: boolean;
|
|
78
|
+
}>>;
|
|
79
|
+
warnings: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
80
|
+
errors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
81
|
+
artifacts: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
|
|
82
|
+
metrics: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
elapsed_ms: z.ZodNumber;
|
|
84
|
+
tool: z.ZodString;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
elapsed_ms: number;
|
|
87
|
+
tool: string;
|
|
88
|
+
}, {
|
|
89
|
+
elapsed_ms: number;
|
|
90
|
+
tool: string;
|
|
91
|
+
}>>;
|
|
92
|
+
}, "strip", z.ZodTypeAny, {
|
|
93
|
+
ok: boolean;
|
|
94
|
+
metrics?: {
|
|
95
|
+
elapsed_ms: number;
|
|
96
|
+
tool: string;
|
|
97
|
+
} | undefined;
|
|
98
|
+
data?: {
|
|
99
|
+
count: number;
|
|
100
|
+
decoded_strings: {
|
|
101
|
+
string: string;
|
|
102
|
+
type: string;
|
|
103
|
+
offset: number;
|
|
104
|
+
decoding_method: string | null;
|
|
105
|
+
}[];
|
|
106
|
+
timeout_occurred: boolean;
|
|
107
|
+
partial_results: boolean;
|
|
108
|
+
} | undefined;
|
|
109
|
+
warnings?: string[] | undefined;
|
|
110
|
+
errors?: string[] | undefined;
|
|
111
|
+
artifacts?: any[] | undefined;
|
|
112
|
+
}, {
|
|
113
|
+
ok: boolean;
|
|
114
|
+
metrics?: {
|
|
115
|
+
elapsed_ms: number;
|
|
116
|
+
tool: string;
|
|
117
|
+
} | undefined;
|
|
118
|
+
data?: {
|
|
119
|
+
count: number;
|
|
120
|
+
decoded_strings: {
|
|
121
|
+
string: string;
|
|
122
|
+
type: string;
|
|
123
|
+
offset: number;
|
|
124
|
+
decoding_method: string | null;
|
|
125
|
+
}[];
|
|
126
|
+
timeout_occurred: boolean;
|
|
127
|
+
partial_results: boolean;
|
|
128
|
+
} | undefined;
|
|
129
|
+
warnings?: string[] | undefined;
|
|
130
|
+
errors?: string[] | undefined;
|
|
131
|
+
artifacts?: any[] | undefined;
|
|
132
|
+
}>;
|
|
133
|
+
export type StringsFlossDecodeOutput = z.infer<typeof StringsFlossDecodeOutputSchema>;
|
|
134
|
+
/**
|
|
135
|
+
* Tool definition for strings.floss.decode
|
|
136
|
+
*/
|
|
137
|
+
export declare const stringsFlossDecodeToolDefinition: ToolDefinition;
|
|
138
|
+
/**
|
|
139
|
+
* Create strings.floss.decode tool handler
|
|
140
|
+
* Requirements: 4.4, 4.5
|
|
141
|
+
*/
|
|
142
|
+
export declare function createStringsFlossDecodeHandler(workspaceManager: WorkspaceManager, database: DatabaseManager, cacheManager: CacheManager): (args: ToolArgs) => Promise<WorkerResult>;
|
|
143
|
+
//# sourceMappingURL=strings-floss-decode.d.ts.map
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* strings.floss.decode tool implementation
|
|
3
|
+
* Uses FLOSS tool to decode obfuscated strings from PE files
|
|
4
|
+
* Requirements: 4.4, 4.5
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
import { generateCacheKey } from '../cache-manager.js';
|
|
11
|
+
import { resolvePackagePath } from '../runtime-paths.js';
|
|
12
|
+
import { lookupCachedResult, formatCacheWarning } from './cache-observability.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Constants
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const TOOL_NAME = 'strings.floss.decode';
|
|
17
|
+
const TOOL_VERSION = '1.0.0';
|
|
18
|
+
const CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
19
|
+
const DEFAULT_TIMEOUT = 60; // seconds
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Input/Output Schemas
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* Input schema for strings.floss.decode tool
|
|
25
|
+
* Requirements: 4.4, 4.5
|
|
26
|
+
*/
|
|
27
|
+
export const StringsFlossDecodeInputSchema = z.object({
|
|
28
|
+
sample_id: z.string().describe('Sample ID (format: sha256:<hex>)'),
|
|
29
|
+
timeout: z.number().int().min(1).optional().default(DEFAULT_TIMEOUT).describe('Timeout in seconds (default: 60)'),
|
|
30
|
+
modes: z.array(z.enum(['static', 'stack', 'tight', 'decoded'])).optional().default(['decoded']).describe('Decoding modes to use'),
|
|
31
|
+
force_refresh: z
|
|
32
|
+
.boolean()
|
|
33
|
+
.optional()
|
|
34
|
+
.default(false)
|
|
35
|
+
.describe('Bypass cache lookup and recompute from source sample'),
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Output schema for strings.floss.decode tool
|
|
39
|
+
* Requirements: 4.4, 4.5
|
|
40
|
+
*/
|
|
41
|
+
export const StringsFlossDecodeOutputSchema = z.object({
|
|
42
|
+
ok: z.boolean(),
|
|
43
|
+
data: z.object({
|
|
44
|
+
decoded_strings: z.array(z.object({
|
|
45
|
+
string: z.string(),
|
|
46
|
+
offset: z.number(),
|
|
47
|
+
type: z.string(),
|
|
48
|
+
decoding_method: z.string().nullable(),
|
|
49
|
+
})),
|
|
50
|
+
count: z.number(),
|
|
51
|
+
timeout_occurred: z.boolean(),
|
|
52
|
+
partial_results: z.boolean(),
|
|
53
|
+
}).optional(),
|
|
54
|
+
warnings: z.array(z.string()).optional(),
|
|
55
|
+
errors: z.array(z.string()).optional(),
|
|
56
|
+
artifacts: z.array(z.any()).optional(),
|
|
57
|
+
metrics: z.object({
|
|
58
|
+
elapsed_ms: z.number(),
|
|
59
|
+
tool: z.string(),
|
|
60
|
+
}).optional(),
|
|
61
|
+
});
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Tool Definition
|
|
64
|
+
// ============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Tool definition for strings.floss.decode
|
|
67
|
+
*/
|
|
68
|
+
export const stringsFlossDecodeToolDefinition = {
|
|
69
|
+
name: TOOL_NAME,
|
|
70
|
+
description: '使用 FLOSS 工具解码混淆字符串,支持多种解码模式(static、stack、tight、decoded)',
|
|
71
|
+
inputSchema: StringsFlossDecodeInputSchema,
|
|
72
|
+
outputSchema: StringsFlossDecodeOutputSchema,
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Spawn Python Static Worker and communicate via stdin/stdout JSON protocol
|
|
76
|
+
*
|
|
77
|
+
* Requirements: Worker communication
|
|
78
|
+
*
|
|
79
|
+
* @param request - Worker request object
|
|
80
|
+
* @returns Worker response object
|
|
81
|
+
*/
|
|
82
|
+
async function callStaticWorker(request) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
// Get Python worker path
|
|
85
|
+
const workerPath = resolvePackagePath('workers', 'static_worker.py');
|
|
86
|
+
// Spawn Python process
|
|
87
|
+
const pythonCommand = process.platform === 'win32' ? 'python' : 'python3';
|
|
88
|
+
const pythonProcess = spawn(pythonCommand, [workerPath], {
|
|
89
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
90
|
+
});
|
|
91
|
+
let stdout = '';
|
|
92
|
+
let stderr = '';
|
|
93
|
+
// Collect stdout
|
|
94
|
+
pythonProcess.stdout.on('data', (data) => {
|
|
95
|
+
stdout += data.toString();
|
|
96
|
+
});
|
|
97
|
+
// Collect stderr
|
|
98
|
+
pythonProcess.stderr.on('data', (data) => {
|
|
99
|
+
stderr += data.toString();
|
|
100
|
+
});
|
|
101
|
+
// Handle process exit
|
|
102
|
+
pythonProcess.on('close', (code) => {
|
|
103
|
+
if (code !== 0) {
|
|
104
|
+
reject(new Error(`Python worker exited with code ${code}. stderr: ${stderr}`));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Parse response from stdout
|
|
108
|
+
try {
|
|
109
|
+
const lines = stdout.trim().split('\n');
|
|
110
|
+
const lastLine = lines[lines.length - 1];
|
|
111
|
+
const response = JSON.parse(lastLine);
|
|
112
|
+
resolve(response);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
reject(new Error(`Failed to parse worker response: ${error.message}. stdout: ${stdout}`));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
// Handle process error
|
|
119
|
+
pythonProcess.on('error', (error) => {
|
|
120
|
+
reject(new Error(`Failed to spawn Python worker: ${error.message}`));
|
|
121
|
+
});
|
|
122
|
+
// Send request to worker via stdin
|
|
123
|
+
try {
|
|
124
|
+
pythonProcess.stdin.write(JSON.stringify(request) + '\n');
|
|
125
|
+
pythonProcess.stdin.end();
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
reject(new Error(`Failed to write to worker stdin: ${error.message}`));
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// ============================================================================
|
|
133
|
+
// Tool Handler
|
|
134
|
+
// ============================================================================
|
|
135
|
+
/**
|
|
136
|
+
* Create strings.floss.decode tool handler
|
|
137
|
+
* Requirements: 4.4, 4.5
|
|
138
|
+
*/
|
|
139
|
+
export function createStringsFlossDecodeHandler(workspaceManager, database, cacheManager) {
|
|
140
|
+
return async (args) => {
|
|
141
|
+
const input = args;
|
|
142
|
+
const startTime = Date.now();
|
|
143
|
+
try {
|
|
144
|
+
// 1. Generate cache key
|
|
145
|
+
const sample = database.findSample(input.sample_id);
|
|
146
|
+
if (!sample) {
|
|
147
|
+
return {
|
|
148
|
+
ok: false,
|
|
149
|
+
errors: [`Sample not found: ${input.sample_id}`],
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
const cacheKey = generateCacheKey({
|
|
153
|
+
sampleSha256: sample.sha256,
|
|
154
|
+
toolName: TOOL_NAME,
|
|
155
|
+
toolVersion: TOOL_VERSION,
|
|
156
|
+
args: {
|
|
157
|
+
timeout: input.timeout,
|
|
158
|
+
modes: input.modes,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
// 2. Check cache
|
|
162
|
+
if (!input.force_refresh) {
|
|
163
|
+
const cachedLookup = await lookupCachedResult(cacheManager, cacheKey);
|
|
164
|
+
if (cachedLookup) {
|
|
165
|
+
return {
|
|
166
|
+
ok: true,
|
|
167
|
+
data: cachedLookup.data,
|
|
168
|
+
warnings: ['Result from cache', formatCacheWarning(cachedLookup.metadata)],
|
|
169
|
+
metrics: {
|
|
170
|
+
elapsed_ms: Date.now() - startTime,
|
|
171
|
+
tool: TOOL_NAME,
|
|
172
|
+
cached: true,
|
|
173
|
+
cache_key: cachedLookup.metadata.key,
|
|
174
|
+
cache_tier: cachedLookup.metadata.tier,
|
|
175
|
+
cache_created_at: cachedLookup.metadata.createdAt,
|
|
176
|
+
cache_expires_at: cachedLookup.metadata.expiresAt,
|
|
177
|
+
cache_hit_at: cachedLookup.metadata.fetchedAt,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 3. Get sample path from workspace
|
|
183
|
+
const workspace = await workspaceManager.getWorkspace(input.sample_id);
|
|
184
|
+
// Find the sample file in the original directory
|
|
185
|
+
const fs = await import('fs/promises');
|
|
186
|
+
const files = await fs.readdir(workspace.original);
|
|
187
|
+
if (files.length === 0) {
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
errors: ['Sample file not found in workspace'],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const samplePath = path.join(workspace.original, files[0]);
|
|
194
|
+
// 4. Prepare worker request
|
|
195
|
+
const workerRequest = {
|
|
196
|
+
job_id: uuidv4(),
|
|
197
|
+
tool: TOOL_NAME,
|
|
198
|
+
sample: {
|
|
199
|
+
sample_id: input.sample_id,
|
|
200
|
+
path: samplePath,
|
|
201
|
+
},
|
|
202
|
+
args: {
|
|
203
|
+
timeout: input.timeout,
|
|
204
|
+
modes: input.modes,
|
|
205
|
+
},
|
|
206
|
+
context: {
|
|
207
|
+
request_time_utc: new Date().toISOString(),
|
|
208
|
+
policy: {
|
|
209
|
+
allow_dynamic: false,
|
|
210
|
+
allow_network: false,
|
|
211
|
+
},
|
|
212
|
+
versions: {
|
|
213
|
+
tool_version: TOOL_VERSION,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
// 5. Call Static Worker
|
|
218
|
+
// Requirements: 4.4, 4.5
|
|
219
|
+
const workerResponse = await callStaticWorker(workerRequest);
|
|
220
|
+
if (!workerResponse.ok) {
|
|
221
|
+
return {
|
|
222
|
+
ok: false,
|
|
223
|
+
errors: workerResponse.errors,
|
|
224
|
+
warnings: workerResponse.warnings,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// 6. Cache result (only if not timeout or partial)
|
|
228
|
+
const responseData = workerResponse.data;
|
|
229
|
+
if (!responseData.timeout_occurred && !responseData.partial_results) {
|
|
230
|
+
await cacheManager.setCachedResult(cacheKey, workerResponse.data, CACHE_TTL_MS);
|
|
231
|
+
}
|
|
232
|
+
// 7. Return result
|
|
233
|
+
return {
|
|
234
|
+
ok: true,
|
|
235
|
+
data: workerResponse.data,
|
|
236
|
+
warnings: input.force_refresh
|
|
237
|
+
? ['force_refresh=true; bypassed cache lookup', ...(workerResponse.warnings || [])]
|
|
238
|
+
: workerResponse.warnings,
|
|
239
|
+
errors: workerResponse.errors,
|
|
240
|
+
artifacts: workerResponse.artifacts,
|
|
241
|
+
metrics: {
|
|
242
|
+
...workerResponse.metrics,
|
|
243
|
+
elapsed_ms: Date.now() - startTime,
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
return {
|
|
249
|
+
ok: false,
|
|
250
|
+
errors: [error.message],
|
|
251
|
+
metrics: {
|
|
252
|
+
elapsed_ms: Date.now() - startTime,
|
|
253
|
+
tool: TOOL_NAME,
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=strings-floss-decode.js.map
|