@eyeauras/insight-cli 0.2.3 → 0.3.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/.cli-package-build.json +1 -1
- package/SKILL.md +4 -1
- package/dist/src/analysis-storage.d.ts +165 -0
- package/dist/src/analysis-storage.js +562 -0
- package/dist/src/cli.js +31 -6
- package/dist/src/contexts.d.ts +1 -0
- package/dist/src/contexts.js +9 -8
- package/dist/src/decode-results.d.ts +1 -0
- package/dist/src/decode-results.js +21 -0
- package/dist/src/function-inspection.d.ts +31 -0
- package/dist/src/function-inspection.js +78 -0
- package/dist/src/function-results.d.ts +2 -0
- package/dist/src/function-results.js +21 -0
- package/dist/src/ghidra-processes.js +5 -4
- package/dist/src/initial-model.js +2 -1
- package/dist/src/native-inputs.js +2 -2
- package/dist/src/queries.js +10 -2
- package/dist/src/query-policy.js +1 -1
- package/dist/src/research.d.ts +21 -0
- package/dist/src/research.js +14 -8
- package/dist/src/runtime-manager.js +6 -5
- package/dist/src/runtime-selection.d.ts +2 -2
- package/dist/src/runtime-selection.js +13 -6
- package/dist/src/saved-materials.js +2 -1
- package/dist/src/tool-runtime/installer.js +7 -6
- package/dist/src/tool-runtime/launch-worker.js +3 -1
- package/package.json +2 -2
- package/references/artifacts.md +1 -1
- package/references/managed-runtime.md +1 -1
- package/references/native/InsightResearchQueries.java +33 -2
- package/references/research.md +40 -0
- package/references/setup.md +4 -0
- package/references/storage.md +99 -0
- package/runtime/toolbox.json +10 -4
- package/skill-bundle/insight-artifacts/SKILL.md +1 -1
- package/skill-bundle/insight-artifacts/references/artifacts.md +1 -1
- package/skill-bundle/insight-artifacts/references/recovery.md +79 -0
- package/skill-bundle/insight-artifacts/references/storage.md +99 -0
- package/skill-bundle/insight-binary/SKILL.md +1 -1
- package/skill-bundle/insight-capture/SKILL.md +1 -1
- package/skill-bundle/insight-cli/SKILL.md +4 -1
- package/skill-bundle/insight-cli/references/recovery.md +79 -0
- package/skill-bundle/insight-cli/references/storage.md +99 -0
- package/skill-bundle/insight-die/SKILL.md +1 -1
- package/skill-bundle/insight-dnspy/SKILL.md +1 -1
- package/skill-bundle/insight-dotnet-dump/SKILL.md +1 -1
- package/skill-bundle/insight-dotnet-stack/SKILL.md +1 -1
- package/skill-bundle/insight-dotnet-trace/SKILL.md +1 -1
- package/skill-bundle/insight-frida/SKILL.md +1 -1
- package/skill-bundle/insight-ghidra/SKILL.md +1 -1
- package/skill-bundle/insight-ghidra/references/artifacts.md +1 -1
- package/skill-bundle/insight-ghidra/references/managed-runtime.md +1 -1
- package/skill-bundle/insight-ghidra/references/research.md +40 -0
- package/skill-bundle/insight-ghidra/references/setup.md +4 -0
- package/skill-bundle/insight-ghidra/references/storage.md +99 -0
- package/skill-bundle/insight-ilspy/SKILL.md +1 -1
- package/skill-bundle/insight-interop/SKILL.md +1 -1
- package/skill-bundle/insight-lldb/SKILL.md +1 -1
- package/skill-bundle/insight-llvm/SKILL.md +1 -1
- package/skill-bundle/insight-managed-heap/SKILL.md +1 -1
- package/skill-bundle/insight-managed-metadata/SKILL.md +1 -1
- package/skill-bundle/insight-mitmproxy/SKILL.md +1 -1
- package/skill-bundle/insight-overview/SKILL.md +1 -1
- package/skill-bundle/insight-procmon/SKILL.md +1 -1
- package/skill-bundle/insight-re/SKILL.md +1 -1
- package/skill-bundle/insight-re/references/artifacts.md +1 -1
- package/skill-bundle/insight-re/references/storage.md +99 -0
- package/skill-bundle/insight-sevenzip/SKILL.md +1 -1
- package/skill-bundle/insight-strace/SKILL.md +1 -1
- package/skill-bundle/insight-tshark/SKILL.md +1 -1
- package/skill-bundle/insight-windbg/SKILL.md +1 -1
- package/skill-bundle/manifest.json +1 -1
- package/skills/insight-artifacts/SKILL.md +1 -1
- package/skills/insight-artifacts/references/artifacts.md +1 -1
- package/skills/insight-artifacts/references/recovery.md +79 -0
- package/skills/insight-artifacts/references/storage.md +99 -0
- package/skills/insight-binary/SKILL.md +1 -1
- package/skills/insight-capture/SKILL.md +1 -1
- package/skills/insight-die/SKILL.md +1 -1
- package/skills/insight-dnspy/SKILL.md +1 -1
- package/skills/insight-dotnet-dump/SKILL.md +1 -1
- package/skills/insight-dotnet-stack/SKILL.md +1 -1
- package/skills/insight-dotnet-trace/SKILL.md +1 -1
- package/skills/insight-frida/SKILL.md +1 -1
- package/skills/insight-ghidra/SKILL.md +1 -1
- package/skills/insight-ghidra/references/artifacts.md +1 -1
- package/skills/insight-ghidra/references/managed-runtime.md +1 -1
- package/skills/insight-ghidra/references/research.md +40 -0
- package/skills/insight-ghidra/references/setup.md +4 -0
- package/skills/insight-ghidra/references/storage.md +99 -0
- package/skills/insight-ilspy/SKILL.md +1 -1
- package/skills/insight-interop/SKILL.md +1 -1
- package/skills/insight-lldb/SKILL.md +1 -1
- package/skills/insight-llvm/SKILL.md +1 -1
- package/skills/insight-managed-heap/SKILL.md +1 -1
- package/skills/insight-managed-metadata/SKILL.md +1 -1
- package/skills/insight-mitmproxy/SKILL.md +1 -1
- package/skills/insight-overview/SKILL.md +1 -1
- package/skills/insight-procmon/SKILL.md +1 -1
- package/skills/insight-re/SKILL.md +1 -1
- package/skills/insight-re/references/artifacts.md +1 -1
- package/skills/insight-re/references/storage.md +99 -0
- package/skills/insight-sevenzip/SKILL.md +1 -1
- package/skills/insight-strace/SKILL.md +1 -1
- package/skills/insight-tshark/SKILL.md +1 -1
- package/skills/insight-windbg/SKILL.md +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
|
2
2
|
import { join, isAbsolute, resolve } from 'node:path';
|
|
3
|
-
import { fail, object } from './model.js';
|
|
3
|
+
import { fail, object, digest } from './model.js';
|
|
4
4
|
export const runtimeRoot = (directory) => join(directory, 'runtime');
|
|
5
|
-
export function runtimeSelection(directory) {
|
|
5
|
+
export function runtimeSelection(directory, analysis = directory) {
|
|
6
6
|
const path = join(runtimeRoot(directory), 'selection.json');
|
|
7
7
|
if (!existsSync(path))
|
|
8
8
|
return;
|
|
@@ -15,23 +15,30 @@ export function runtimeSelection(directory) {
|
|
|
15
15
|
fail('binding', 'Managed runtime moved outside its owned installation.');
|
|
16
16
|
// Workspace resolves AppData physically; older install receipts can retain a profile
|
|
17
17
|
// alias such as /tmp -> /private/tmp. Accept that same profile, never an inner escape.
|
|
18
|
-
let profile, recorded, home;
|
|
18
|
+
let profile, recorded, owned, home, retained = false;
|
|
19
19
|
try {
|
|
20
20
|
profile = realpathSync.native(directory);
|
|
21
21
|
recorded = realpathSync.native(recordedProfile);
|
|
22
|
+
owned = realpathSync.native(analysis);
|
|
23
|
+
if (recorded !== profile && recorded !== owned) {
|
|
24
|
+
const marker = object(JSON.parse(readFileSync(join(recorded, '.insight-analysis.json'), 'utf8')));
|
|
25
|
+
retained = marker.schema === 1 && marker.binding === digest(profile);
|
|
26
|
+
}
|
|
27
|
+
if (realpathSync.native(runtimeRoot(directory)) !== join(owned, 'runtime') || realpathSync.native(runtimeRoot(recordedProfile)) !== join(owned, 'runtime'))
|
|
28
|
+
fail('binding', 'Managed runtime root differs from its configured analysis owner.');
|
|
22
29
|
if (existsSync(value.ghidraHome))
|
|
23
30
|
home = realpathSync.native(value.ghidraHome);
|
|
24
31
|
}
|
|
25
32
|
catch {
|
|
26
33
|
fail('binding', 'Managed runtime profile ownership could not be verified.');
|
|
27
34
|
}
|
|
28
|
-
if (recorded !== profile || home !== undefined && home !== join(runtimeRoot(
|
|
35
|
+
if (recorded !== profile && recorded !== owned && !retained || home !== undefined && home !== join(runtimeRoot(owned), 'installations', id, 'ghidra'))
|
|
29
36
|
fail('binding', 'Managed runtime moved outside its owned installation.');
|
|
30
37
|
}
|
|
31
38
|
return value;
|
|
32
39
|
}
|
|
33
|
-
export function runtimeValues(directory, values) {
|
|
34
|
-
const selected = runtimeSelection(directory);
|
|
40
|
+
export function runtimeValues(directory, values, analysis) {
|
|
41
|
+
const selected = runtimeSelection(directory, analysis);
|
|
35
42
|
if (!selected)
|
|
36
43
|
return values;
|
|
37
44
|
if (selected.uninstalledAt)
|
|
@@ -3,6 +3,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { constants } from 'node:fs';
|
|
4
4
|
import { lstat, mkdir, open, opendir, realpath, rename, rm } from 'node:fs/promises';
|
|
5
5
|
import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
6
|
+
import { analysisDirectory } from './analysis-storage.js';
|
|
6
7
|
const maximumEntries = 100_000, maximumDepth = 128;
|
|
7
8
|
function fail(code, message) { throw new CliError(message, { code: 'artifacts.' + code }); }
|
|
8
9
|
function check(signal) { if (signal?.aborted)
|
|
@@ -190,7 +191,7 @@ export function artifactsCommands() {
|
|
|
190
191
|
command('save <path>', 'Save a complete independent copy of a file or directory in this profile', ({ args }, context) => {
|
|
191
192
|
if (typeof args.path !== 'string' || !args.path || args.path.includes('\0'))
|
|
192
193
|
fail('invalid', 'Provide one file or directory path.');
|
|
193
|
-
return saveMaterials(context
|
|
194
|
+
return saveMaterials(analysisDirectory(context), resolve(context.cwd, args.path), context.signal);
|
|
194
195
|
}, { permission: Permission.Update }),
|
|
195
196
|
])];
|
|
196
197
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { analysisDirectory } from '../analysis-storage.js';
|
|
2
|
+
import { mkdir, stat, rm, readdir, writeFile, readFile, realpath } from 'node:fs/promises';
|
|
2
3
|
import { join, resolve, sep, dirname } from 'node:path';
|
|
3
4
|
import { cacheArtifact, consumeArchive, extractArchive, fileSha256, archiveName } from './archives.js';
|
|
4
5
|
import { atomicWrite, readJson, toolRoot, withToolLock, installationStage, removeInstallation, treeFingerprint, assertUnused, withToolUse } from './store.js';
|
|
@@ -7,7 +8,7 @@ import { digest, fail, text } from '../model.js';
|
|
|
7
8
|
/** Read-only verification used by an owned child after the command owner has staged a runtime. */
|
|
8
9
|
export async function verifyManagedInstallation(directory, tool, selected) {
|
|
9
10
|
const root = join(toolRoot(directory, tool), 'installations', selected.id);
|
|
10
|
-
if (selected.schema !== 1 || selected.tool !== tool || selected.mode !== 'managed' || selected.uninstalledAt || !/^[a-f0-9]{64}$/.test(selected.id) || selected.root !== root || !
|
|
11
|
+
if (selected.schema !== 1 || selected.tool !== tool || selected.mode !== 'managed' || selected.uninstalledAt || !/^[a-f0-9]{64}$/.test(selected.id) || await realpath(selected.root) !== await realpath(root) || !(await realpath(selected.executable)).startsWith(await realpath(root) + sep))
|
|
11
12
|
fail('binding', 'Invalid managed tool installation receipt.');
|
|
12
13
|
const ready = await readJson(join(root, 'ready.json'));
|
|
13
14
|
const binding = (v) => { const { selectedAt, uninstalledAt, ...rest } = v; return rest; };
|
|
@@ -27,8 +28,8 @@ export class ToolInstaller {
|
|
|
27
28
|
this.c = c;
|
|
28
29
|
this.descriptor = descriptor;
|
|
29
30
|
this.directory = c.appArguments.AppDataDirectory;
|
|
30
|
-
this.root = toolRoot(
|
|
31
|
-
this.cache = join(
|
|
31
|
+
this.root = toolRoot(analysisDirectory(c), descriptor.id);
|
|
32
|
+
this.cache = join(analysisDirectory(c), 'runtime/cache');
|
|
32
33
|
}
|
|
33
34
|
async receipt() { return readJson(join(this.root, 'selection.json')); }
|
|
34
35
|
async status() {
|
|
@@ -105,7 +106,7 @@ export class ToolInstaller {
|
|
|
105
106
|
if (selected.schema !== 1 || selected.tool !== this.descriptor.id || !/^[a-f0-9]{64}$/.test(selected.id))
|
|
106
107
|
fail('binding', 'Invalid tool installation receipt.');
|
|
107
108
|
const root = join(this.root, 'installations', selected.id);
|
|
108
|
-
if (selected.root !== root || selected.mode === 'managed' && !
|
|
109
|
+
if (await realpath(selected.root) !== await realpath(root) || selected.mode === 'managed' && !(await realpath(selected.executable)).startsWith(await realpath(root) + sep))
|
|
109
110
|
fail('binding', 'Selected tool points outside its owned installation.');
|
|
110
111
|
const ready = await readJson(join(root, 'ready.json'));
|
|
111
112
|
const binding = (v) => { const { selectedAt, uninstalledAt, ...rest } = v; return rest; };
|
|
@@ -131,7 +132,7 @@ export class ToolInstaller {
|
|
|
131
132
|
await verifyManagedInstallation(this.directory, this.descriptor.id, selected);
|
|
132
133
|
else if (await fileSha256(selected.executable, this.c.signal) !== selected.fingerprint)
|
|
133
134
|
fail('binding', 'Selected tool code differs from its verified installation.');
|
|
134
|
-
if (selected.execution && (!
|
|
135
|
+
if (selected.execution && (!(await realpath(selected.execution.executable)).startsWith(await realpath(root) + sep) || await treeFingerprint(root) !== selected.executionFingerprint))
|
|
135
136
|
fail('binding', 'Owned external-tool execution copy differs from its verified installation.');
|
|
136
137
|
if (selected.mode === 'external' && this.descriptor.externalInputs && (!selected.externalInputs || digest(await this.descriptor.externalInputs(selected.executable, this.c)) !== digest(selected.externalInputs)))
|
|
137
138
|
fail('binding', 'External tool family differs from its verified installation.');
|
|
@@ -19,7 +19,9 @@ async function main() {
|
|
|
19
19
|
if (input.length > 4 * 1024 ** 2)
|
|
20
20
|
throw Error('Launch input exceeds its bound');
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
// Factory's stable profile remains local while the complete runtime tree can be
|
|
23
|
+
// an authorized analysis-storage alias. Child paths must still stay inside it.
|
|
24
|
+
if (await realpath(String(record.root)) !== join(await realpath(join(root, 'runtime')), 'runs', id))
|
|
23
25
|
throw Error('Launch storage changed');
|
|
24
26
|
const plan = JSON.parse(input);
|
|
25
27
|
if (plan.executable !== record.executable)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eyeauras/insight-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-facing durable sessions and isolated Ghidra research contexts",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"prepack": "npm run build"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@eyeauras/cli-factory": "https://raw.githubusercontent.com/iXab3r/insight-cli/
|
|
27
|
+
"@eyeauras/cli-factory": "https://raw.githubusercontent.com/iXab3r/insight-cli/b0d2805ef97face11ab131e8aa39b34216eefaf0/vendor/factory-core-0413409.tgz",
|
|
28
28
|
"@eyeauras/cli-factory-ipc": "https://raw.githubusercontent.com/iXab3r/insight-cli/f47f6d14e8aadc6b6778a6e3627bbb08909521d2/vendor/factory-ipc-7c403d8.tgz",
|
|
29
29
|
"@modelcontextprotocol/sdk": "1.32.1",
|
|
30
30
|
"tar": "7.5.22",
|
package/references/artifacts.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Save ordinary research materials
|
|
2
2
|
|
|
3
3
|
`insight-cli artifacts save <path> --json` saves a file or a settled directory tree in
|
|
4
|
-
the selected profile's AppData. It needs Factory Update permission and does not require
|
|
4
|
+
the selected profile's [analysis storage](storage.md), which defaults to AppData. It needs Factory Update permission and does not require
|
|
5
5
|
Ghidra, Java, authentication, target/session selectors or evidence metadata. Relative input
|
|
6
6
|
paths resolve against the caller's working directory. Use `--help` for generated syntax.
|
|
7
7
|
|
|
@@ -79,7 +79,7 @@ operations until `connect`/`start`. `server connect/disconnect` retain their con
|
|
|
79
79
|
An external server remains configured through profile server/repository/account fields and Factory
|
|
80
80
|
secrets; `server stop` cannot stop that external service.
|
|
81
81
|
|
|
82
|
-
Code/cache/installation receipts live under
|
|
82
|
+
Code/cache/installation receipts live under configured [analysis storage](storage.md) `runtime/`; research remains under
|
|
83
83
|
`workspace/`, and saved files under `materials/`. One selected immutable installation serves many
|
|
84
84
|
isolated JVM contexts; each has its own projects, home, settings, cache/temp and authenticated
|
|
85
85
|
endpoint. No per-agent copy of the Ghidra code distribution is required. This is process and data
|
|
@@ -172,14 +172,45 @@ public class InsightResearchQueries extends GhidraScript {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
byte[] patternMasks;
|
|
175
|
-
Object
|
|
175
|
+
Object decodeInstructions()throws Exception{
|
|
176
|
+
Address start=address(str("address",""));int maximum=number("max_bytes",64,1,4096),maxInstructions=number("max_instructions",16,1,256);
|
|
177
|
+
String language=currentProgram.getLanguageID().toString();
|
|
178
|
+
// Other processors may require mode propagation or delay-slot handling. Fail explicitly
|
|
179
|
+
// until those semantics have their own native acceptance; never fall back to an Update API.
|
|
180
|
+
if(!currentProgram.getLanguage().getProcessor().toString().equalsIgnoreCase("x86"))throw new UnsupportedOperationException("Read-only decode currently supports x86 languages only; language/context unavailable: "+language);
|
|
181
|
+
MemoryBlock block=currentProgram.getMemory().getBlock(start);
|
|
182
|
+
if(block==null||!block.isInitialized()||!block.isExecute())throw new IllegalArgumentException("Decode requires initialized executable memory");
|
|
183
|
+
int available=(int)Math.min(maximum,block.getEnd().subtract(start)+1);byte[] input=new byte[available];
|
|
184
|
+
if(currentProgram.getMemory().getBytes(start,input)!=available)throw new IllegalStateException("Incomplete executable memory read");
|
|
185
|
+
var decoder=new ghidra.app.util.PseudoDisassembler(currentProgram);List<Object> rows=new ArrayList<>();int consumed=0;String reason="byte_limit";
|
|
186
|
+
while(consumed<input.length&&rows.size()<maxInstructions){
|
|
187
|
+
boundedMonitor.checkCancelled();Address at=start.addNoWrap(consumed);ghidra.app.util.PseudoInstruction instruction;
|
|
188
|
+
try{instruction=decoder.disassemble(at,Arrays.copyOfRange(input,consumed,input.length));}
|
|
189
|
+
catch(ghidra.program.model.lang.InsufficientBytesException error){reason="truncated_instruction";break;}
|
|
190
|
+
catch(ghidra.program.model.lang.UnknownInstructionException error){reason="undecodable";break;}
|
|
191
|
+
catch(ghidra.program.model.lang.UnknownContextException error){reason="context_unavailable";break;}
|
|
192
|
+
if(instruction==null){reason="undecodable";break;}
|
|
193
|
+
int length=instruction.getLength();if(length<1||length>input.length-consumed){reason="truncated_instruction";break;}
|
|
194
|
+
List<String> operands=new ArrayList<>();for(int i=0;i<instruction.getNumOperands();i++)operands.add(instruction.getDefaultOperandRepresentation(i));
|
|
195
|
+
var flow=instruction.getFlowType();List<String> targets=new ArrayList<>();
|
|
196
|
+
if(!flow.isComputed())for(Address target:instruction.getFlows())if(target!=null&&!target.equals(Address.NO_ADDRESS))targets.add(target.toString());
|
|
197
|
+
rows.add(map("address",at.toString(),"bytes",HexFormat.of().formatHex(Arrays.copyOfRange(input,consumed,consumed+length)),"length",length,"mnemonic",instruction.getMnemonicString(),"operands",operands,"direct_targets",targets,"flow",flow.toString(),"computed_flow",flow.isComputed()));
|
|
198
|
+
consumed+=length;
|
|
199
|
+
if(flow.isTerminal()){reason="terminal_flow";break;}
|
|
200
|
+
if(flow.isJump()&&!flow.isConditional()){reason="control_flow";break;}
|
|
201
|
+
}
|
|
202
|
+
if(consumed<input.length&&rows.size()==maxInstructions&&reason.equals("byte_limit"))reason="instruction_limit";
|
|
203
|
+
if(consumed==input.length&&available<maximum&&reason.equals("byte_limit"))reason="executable_block_end";
|
|
204
|
+
return map("address",start.toString(),"language",language,"compiler",currentProgram.getCompilerSpec().getCompilerSpecID().toString(),"input_bytes",HexFormat.of().formatHex(input),"input_sha256",HexFormat.of().formatHex(java.security.MessageDigest.getInstance("SHA-256").digest(input)),"maximum_bytes",maximum,"maximum_instructions",maxInstructions,"instructions",rows,"consumed_bytes",consumed,"stop_reason",reason,"truncated",List.of("byte_limit","instruction_limit","truncated_instruction","executable_block_end").contains(reason),"semantics","Linear pseudo instructions in the selected program context; direct targets are computed from bytes, not function membership or stored xrefs.");
|
|
205
|
+
}
|
|
206
|
+
Object execute(String operation)throws Exception{return switch(operation){case "/research_view"->map("modification",Long.toString(currentProgram.getModificationNumber()),"language",currentProgram.getLanguageID().toString(),"compiler",currentProgram.getCompilerSpec().getCompilerSpecID().toString());case "/decode_instructions"->decodeInstructions();case "/find_dead_code"->dead();case "/detect_crypto_constants"->bytes(true);case "/search_byte_patterns"->bytes(false);case "/get_valid_data_types"->types(true);case "/find_data_types"->types(false);case "/validate_data_type"->validateType();case "/validate_function_prototype"->validatePrototype();case "/get_entry_points"->entries();case "/list_globals"->globals();case "/list_strings"->strings(false);case "/search_strings"->strings(true);case "/search_instructions"->instructions();default->throw new IllegalArgumentException("Unknown native query");};}
|
|
176
207
|
public void run()throws Exception{
|
|
177
208
|
var request=JsonParser.parseString(new String(Base64.getDecoder().decode(getScriptArgs()[0]),StandardCharsets.UTF_8)).getAsJsonObject();p=request.getAsJsonObject("parameters");maxScan=number("max_scan",100000,1,200000);limit=number("limit",100,1,1000);offset=number("offset",0,0,2000000);deadline=System.nanoTime()+number("timeout_seconds",5,1,30)*1000000000L;
|
|
178
209
|
boundedMonitor=TimeoutTaskMonitor.timeoutIn(number("timeout_seconds",5,1,30),TimeUnit.SECONDS,monitor);
|
|
179
210
|
Map<String,Object> result;long modification=currentProgram.getModificationNumber();try{
|
|
180
211
|
Object value=execute(request.get("operation").getAsString());
|
|
181
212
|
if(currentProgram.getModificationNumber()!=modification)throw new IllegalStateException("Read-only query changed the program modification counter");
|
|
182
|
-
if(value instanceof Map<?,?>)((Map<String,Object>)value).put("read_only",map("modification_unchanged",true));result=map("value",value);
|
|
213
|
+
if(value instanceof Map<?,?>)((Map<String,Object>)value).put("read_only",map("modification_unchanged",true,"modification",Long.toString(modification)));result=map("value",value);
|
|
183
214
|
}catch(Exception error){result=map("error",map("code",error instanceof UnsupportedOperationException?"unsupported":error instanceof IllegalArgumentException?"invalid":"partial","message",Objects.toString(error.getMessage(),"Native query failed")));}
|
|
184
215
|
finally{boundedMonitor.finished();if(temporaryTypes!=null){temporaryTypes.endTransaction(temporaryTransaction,false);temporaryTypes.close();}}
|
|
185
216
|
|
package/references/research.md
CHANGED
|
@@ -99,3 +99,43 @@ publish program work. Switching modes retains private edits and other sessions k
|
|
|
99
99
|
|
|
100
100
|
Selected native SDK commands and their effect/budget contracts are described in
|
|
101
101
|
[native workflows](native-workflows.md).
|
|
102
|
+
|
|
103
|
+
`functions get/decompile` failures include `selector`, stable `reason` and, when supplied by
|
|
104
|
+
native, a sanitized diagnostic of at most 500 Unicode characters. Reasons distinguish
|
|
105
|
+
`function_not_found`, `native_function_failure`, `selector_mismatch`, `invalid_native_shape`,
|
|
106
|
+
`missing_signature` and `missing_decompiler_text`. Missing definitions remain failures; reads
|
|
107
|
+
never create functions or run analysis. JSON-RPC `cli.execute` preserves the same error data.
|
|
108
|
+
|
|
109
|
+
The existing `functions inspect` accepts 1–20 distinct names/addresses. Existing `--fields`
|
|
110
|
+
remain valid; unknown fields fail before dispatch. Decompiled text uses per-item
|
|
111
|
+
`--offset-chars` (default 0), `--limit-chars` (default 16000, maximum 32768), and a shared
|
|
112
|
+
`--total-chars` budget (default 64000, maximum 128000), allocated in selector order.
|
|
113
|
+
Each item retains success/not-found/failure and `text` metadata: full returned-native-text
|
|
114
|
+
SHA-256, Unicode code-point length, window, next offset and native truncation. A zero-length
|
|
115
|
+
window can mean the total budget was exhausted. A last CLI page does not establish native
|
|
116
|
+
completeness. Use fewer selectors to advance a starved item. The one MiB response cap still
|
|
117
|
+
applies to all fields. These are text/result bounds, not a native decompiler CPU budget.
|
|
118
|
+
|
|
119
|
+
Keep `value.view.identity` and supply `--expect-view <identity>` on continuation. An observed
|
|
120
|
+
context generation, snapshot or revision change rejects continuation with `changed_view`.
|
|
121
|
+
Hashes bind each observed native text; compare them across pages as well. A view identity is
|
|
122
|
+
conservative across lifecycle changes and does not assert determinism of the decompiler.
|
|
123
|
+
|
|
124
|
+
For compact evidence, use `--save-owner-directory <absolute-new-path>`. The elected CLI owner
|
|
125
|
+
writes full returned native text (at most four MiB per function, at most 20 functions) to numbered
|
|
126
|
+
hash-named `.c` files and writes `manifest.json` last. The response omits inline code and gives
|
|
127
|
+
absolute paths, coverage, hashes, lengths and native truncation. This directory is on the owner
|
|
128
|
+
host, including through JSON-RPC; it is never silently a client-host path. An existing directory
|
|
129
|
+
is rejected. A filesystem failure can leave a partial new directory without a completed manifest;
|
|
130
|
+
retain it for inspection and choose a fresh directory for another explicit save.
|
|
131
|
+
|
|
132
|
+
`functions decode --address <address> --max-bytes 64 --max-instructions 16` uses Ghidra pseudo
|
|
133
|
+
instructions without defining listing instructions, functions or xrefs, running analyzers or
|
|
134
|
+
saving state. It requires initialized executable memory and currently supports x86 language
|
|
135
|
+
variants; other languages return an explicit unsupported capability error. Bounds are 1–4096
|
|
136
|
+
bytes in one executable block and 1–256 instructions. Results bind input bytes/hash, language,
|
|
137
|
+
compiler and context view to instructions, consumed bytes and stop reason. Direct targets are
|
|
138
|
+
computed from instruction bytes, not proof of function membership or stored xrefs. Indirect
|
|
139
|
+
flow has no invented target. Decoding stops at terminal/unconditional flow, input/instruction
|
|
140
|
+
bounds, undecodable/truncated bytes or unavailable context. Existing `disassemble-bytes` remains
|
|
141
|
+
an Update operation with its original guards.
|
package/references/setup.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Setup
|
|
2
2
|
|
|
3
|
+
Inspect `storage show --json` and read [analysis storage](storage.md) before moving databases.
|
|
4
|
+
Use `storage configure` for an empty profile or `storage migrate` for existing work. Factory
|
|
5
|
+
control metadata and keyring identity stay in their original locations.
|
|
6
|
+
|
|
3
7
|
Use Node 24+ and `ghidra install` to deliver Ghidra 12.1.2, JDK 21, native components and
|
|
4
8
|
server support. See [managed runtime](managed-runtime.md) for download/install/offline archives,
|
|
5
9
|
external executable paths, status/doctor and safe removal. Existing Factory profile `java` and
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Analysis storage and migration
|
|
2
|
+
|
|
3
|
+
`storage show --json` reports effective profile storage, availability, active file/byte usage,
|
|
4
|
+
exact included trees and retained migration. The default is Factory profile AppData. No
|
|
5
|
+
checkout, environment or automatic disk fallback changes it. The non-secret setting is
|
|
6
|
+
`analysisDirectory` in Factory's profile (`profile show` also displays it). Use storage commands
|
|
7
|
+
to change it safely.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
insight-cli permissions grant Update
|
|
11
|
+
insight-cli storage show --json
|
|
12
|
+
insight-cli storage configure --directory "/mnt/analysis volume" --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`configure` requires no existing analysis entries. With existing data use `migrate`.
|
|
16
|
+
The directory is a **base**: the effective root appends `insight-cli/<profile>`, preserving
|
|
17
|
+
profile isolation. Choose an ordinary empty destination profile directory on a mounted local
|
|
18
|
+
filesystem. Spaces and Unicode are supported. Factory restricts the dedicated destination root to the
|
|
19
|
+
current user, including a Windows ACL; a filesystem that cannot apply this protection fails
|
|
20
|
+
before copying.
|
|
21
|
+
|
|
22
|
+
The complete `workspace`, `materials`, `temp` and `runtime` trees move: immutable inputs,
|
|
23
|
+
artifact/candidate snapshots, workspace SQLite DB/WAL, native private project/context DBs,
|
|
24
|
+
local Ghidra Server repositories, operation/publication/import journals, debugger traces,
|
|
25
|
+
process captures, exports, native helper compilation and verification working data.
|
|
26
|
+
**Runtime installations, acquisition caches, selections and process receipts move too**;
|
|
27
|
+
installation staging and activation must share a filesystem. External tool installations and
|
|
28
|
+
user-selected outputs outside these trees keep their locations.
|
|
29
|
+
|
|
30
|
+
Factory keeps profiles, permissions, IPC election/socket, migration-control metadata and
|
|
31
|
+
application logs in current-user AppData. Secrets stay in the OS keyring. Credential/profile
|
|
32
|
+
identities do not change. Updating/installing npm never migrates a profile automatically.
|
|
33
|
+
|
|
34
|
+
## Move an existing profile
|
|
35
|
+
|
|
36
|
+
Finish changing commands, close native contexts, and stop this profile's owned server/tool
|
|
37
|
+
processes through ordinary CLI commands. Inspect `tools processes --json`. Unverified lifetimes
|
|
38
|
+
also block migration. Do not kill guessed PIDs or stop other profiles to make preflight pass.
|
|
39
|
+
Factory retains IPC ownership and command admission; other profiles can keep working.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
insight-cli storage migrate --directory "/mnt/analysis volume" --dry-run --json
|
|
43
|
+
insight-cli storage migrate --directory "/mnt/analysis volume" --json
|
|
44
|
+
insight-cli storage show --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Dry-run checks separation, destination contents, access, conservative capacity and quiescence
|
|
48
|
+
without reserving/copying a migration. Source/destination/configuration roots cannot be equal
|
|
49
|
+
or nested. Destination symlink roots, escaping source links, special files, unresolved links
|
|
50
|
+
and inventories above one million entries or 128 directory levels are rejected. Internal
|
|
51
|
+
links retain their exact target strings. Preflight does not reserve space; concurrent disk use
|
|
52
|
+
can still cause a copy failure.
|
|
53
|
+
|
|
54
|
+
Migration durably reserves its journal, hashes stable source bytes, streams/syncs the copy,
|
|
55
|
+
independently hashes destination bytes and rechecks the source. Only then does it replace source
|
|
56
|
+
trees with permanent compatibility links and commit the Factory setting. Original trees are
|
|
57
|
+
renamed into `.storage-retained/<migration>` on their original volume. Copy/activation never
|
|
58
|
+
deletes them, including on failures. Existing IDs, requests, journals, candidate snapshots and
|
|
59
|
+
receipts retain exact bytes. Compatibility paths preserve old absolute references: do not remove
|
|
60
|
+
those links or their profile/source ancestors manually after migrating.
|
|
61
|
+
|
|
62
|
+
## Interruptions, uncertainty and retention
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
insight-cli storage resume --json
|
|
66
|
+
insight-cli storage rollback --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Ordinary research freezes during incomplete copy/activation/rollback/cleanup. `show` and Factory
|
|
70
|
+
profile inspection remain available. Resume verifies completed files, recopies an incomplete
|
|
71
|
+
file, rechecks capacity and finishes the retained transaction. Source and destination filesystem
|
|
72
|
+
anchor identities are bound durably. Missing/replaced volumes fail without creating a system-disk
|
|
73
|
+
fallback; mount the original volume before resuming.
|
|
74
|
+
|
|
75
|
+
Rollback restores retained source and the prior Factory setting. After activation it requires
|
|
76
|
+
an unchanged destination and a verified retained source. Native reopening or later findings can
|
|
77
|
+
make rollback unsafe, in which case it refuses and preserves both copies. Use forward migration
|
|
78
|
+
to another empty base after using the new location. A rolled-back destination remains for manual
|
|
79
|
+
inspection/removal and is never automatically adopted. Cleanup permanently disables rollback.
|
|
80
|
+
|
|
81
|
+
Unknown script/publication effects do **not** need abandonment before migrating a stopped
|
|
82
|
+
profile. Migration starts no worker, replays no script/check-in and marks no unknown outcome
|
|
83
|
+
applied. Inspect the original request after migrating; existing [recovery](recovery.md)
|
|
84
|
+
restrictions and independent readback requirements still apply.
|
|
85
|
+
|
|
86
|
+
After independent native reopen and saved-file readback, free retained source explicitly:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
insight-cli permissions grant Destructive
|
|
90
|
+
insight-cli storage cleanup --json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Cleanup verifies retained bytes, records irreversible intent, then deletes only that owned
|
|
94
|
+
backup. Interrupted cleanup continues through `storage resume`; rollback is already disabled.
|
|
95
|
+
Compatibility links, receipts and manifests remain. Clean or roll back the current migration
|
|
96
|
+
before starting another. This release provides no nonempty-destination adoption, reverse
|
|
97
|
+
synchronization, live-DB snapshotting or network-filesystem guarantees. POSIX directory fsync
|
|
98
|
+
is used. Windows has file fsync and rename/junction semantics; Node cannot fsync directories
|
|
99
|
+
there, and internal symlinks can require OS privileges.
|
package/runtime/toolbox.json
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
"title": "insight-cli",
|
|
7
7
|
"path": "SKILL.md",
|
|
8
8
|
"resources": {
|
|
9
|
-
"references/agent-execution.md": "references/agent-execution.md"
|
|
9
|
+
"references/agent-execution.md": "references/agent-execution.md",
|
|
10
|
+
"references/storage.md": "references/storage.md",
|
|
11
|
+
"references/recovery.md": "references/recovery.md"
|
|
10
12
|
}
|
|
11
13
|
},
|
|
12
14
|
{
|
|
@@ -16,7 +18,8 @@
|
|
|
16
18
|
"resources": {
|
|
17
19
|
"references/recovery.md": "references/recovery.md",
|
|
18
20
|
"references/artifacts.md": "references/artifacts.md",
|
|
19
|
-
"references/agent-execution.md": "references/agent-execution.md"
|
|
21
|
+
"references/agent-execution.md": "references/agent-execution.md",
|
|
22
|
+
"references/storage.md": "references/storage.md"
|
|
20
23
|
}
|
|
21
24
|
},
|
|
22
25
|
{
|
|
@@ -35,7 +38,8 @@
|
|
|
35
38
|
"references/archive.md": "references/archive.md",
|
|
36
39
|
"references/extensions-and-sync.md": "references/extensions-and-sync.md",
|
|
37
40
|
"references/artifacts.md": "references/artifacts.md",
|
|
38
|
-
"references/agent-execution.md": "references/agent-execution.md"
|
|
41
|
+
"references/agent-execution.md": "references/agent-execution.md",
|
|
42
|
+
"references/storage.md": "references/storage.md"
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
{
|
|
@@ -53,7 +57,9 @@
|
|
|
53
57
|
"path": "skills/insight-artifacts/SKILL.md",
|
|
54
58
|
"resources": {
|
|
55
59
|
"references/artifacts.md": "references/artifacts.md",
|
|
56
|
-
"references/agent-execution.md": "references/agent-execution.md"
|
|
60
|
+
"references/agent-execution.md": "references/agent-execution.md",
|
|
61
|
+
"references/storage.md": "references/storage.md",
|
|
62
|
+
"references/recovery.md": "references/recovery.md"
|
|
57
63
|
}
|
|
58
64
|
},
|
|
59
65
|
{
|
|
@@ -3,7 +3,7 @@ name: insight-artifacts
|
|
|
3
3
|
description: Retain a completed reverse-engineering evidence file or directory as an ordinary checkpoint using insight-cli artifacts save. Use after Ghidra or any external tool; preserve existing project formats and source of truth.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Insight Artifacts 0.
|
|
6
|
+
# Insight Artifacts 0.3.0
|
|
7
7
|
|
|
8
8
|
If local help/status reports AppData or IPC access denied, retry that **read-only probe**
|
|
9
9
|
with the agent host's normal permission escalation, then use that route for later authorized
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Save ordinary research materials
|
|
2
2
|
|
|
3
3
|
`insight-cli artifacts save <path> --json` saves a file or a settled directory tree in
|
|
4
|
-
the selected profile's AppData. It needs Factory Update permission and does not require
|
|
4
|
+
the selected profile's [analysis storage](storage.md), which defaults to AppData. It needs Factory Update permission and does not require
|
|
5
5
|
Ghidra, Java, authentication, target/session selectors or evidence metadata. Relative input
|
|
6
6
|
paths resolve against the caller's working directory. Use `--help` for generated syntax.
|
|
7
7
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Continue saved work
|
|
2
|
+
|
|
3
|
+
Retain the session/target returned by initial open. Continue the tuple through
|
|
4
|
+
`insight-cli ghidra open --session <id> --target <id> --json`. Saved private snapshots and
|
|
5
|
+
pending scalar comparisons persist independently of a backend process. Reopening preserves
|
|
6
|
+
private work; it does not silently receive a newer shared version.
|
|
7
|
+
|
|
8
|
+
First-import recovery uses the same scoped `ghidra open` or the original request ID/input.
|
|
9
|
+
Import/analysis writes a private snapshot and completion receipt before any initial publication.
|
|
10
|
+
If its worker is still running, continuation reports busy; wait and continue the same scope.
|
|
11
|
+
If that worker stopped before completing its receipt, continuation can repeat private analysis
|
|
12
|
+
from the immutable input while retaining previous attempts. A completed snapshot is reused.
|
|
13
|
+
Initial publication first creates a uniquely named staging object. A separate read-only process
|
|
14
|
+
verifies its complete saved DB buffers before a conditional server move to the absent canonical
|
|
15
|
+
path. It never checks in a new version of an existing canonical item. Lost promotion replies
|
|
16
|
+
are reconciled against the retained identity, one-version history and complete saved buffers.
|
|
17
|
+
Interrupted staging objects remain retained and can be replaced by another private stage;
|
|
18
|
+
they are not adopted as the canonical model. Foreign or mismatched canonical state stays blocked.
|
|
19
|
+
An older direct create that is provably owned and left only an incomplete `<Recovered>` entry
|
|
20
|
+
can be moved aside without deletion; its bytes and original receipt remain preserved.
|
|
21
|
+
|
|
22
|
+
Legacy first-import failures are also recoverable in the original profile. Continuation first
|
|
23
|
+
establishes that the old owned bootstrap worker has ended, then uses an authoritative repository
|
|
24
|
+
probe. An absent canonical item permits private preparation; an existing first version requires
|
|
25
|
+
independent readback. The old project, intent and original session/target remain preserved.
|
|
26
|
+
|
|
27
|
+
If a response was lost, inspect `sessions status <session> --target <target>`. Never infer
|
|
28
|
+
`applied` from a connection failure. A changing command's optional request ID binds one effective
|
|
29
|
+
intent inside the profile. Repeating the same ID/input retrieves its recorded outcome or
|
|
30
|
+
unresolved state; changing input under that ID fails. Without an ID, calls are new intentions.
|
|
31
|
+
|
|
32
|
+
An unknown or partial effect retains its request intent, snapshots and native stage. Open the
|
|
33
|
+
same tuple to reconcile supported outcomes. A committed merge is verified against its recorded
|
|
34
|
+
server version and complete saved buffers through independent read authority; it is never
|
|
35
|
+
checked in again merely because its response was lost. Until verification succeeds, publication
|
|
36
|
+
for this shared target is blocked across sessions. Saved private work remains retained.
|
|
37
|
+
|
|
38
|
+
Scalar reconciliation observes and saves an already present effect; it does not execute the
|
|
39
|
+
setter again. Supported structural/function edits retain a candidate snapshot after an incomplete
|
|
40
|
+
response; continuation can verify every requested effect in that immutable snapshot and adopt it
|
|
41
|
+
without replay. If the complete result cannot be established, the candidate and previous saved
|
|
42
|
+
private view remain retained. An unproved program/script/external outcome remains unresolved. Preserve the profile
|
|
43
|
+
storage and credential store. Do not delete another session's project, stop a process by guessed
|
|
44
|
+
PID/port, or blindly repeat a script/external action to turn uncertainty into success.
|
|
45
|
+
|
|
46
|
+
The older prototype's `workers`, `findings`, `integrate` and batch `recover` commands are not the
|
|
47
|
+
public facade API. Its coordinator journals remain separate and are never silently migrated.
|
|
48
|
+
|
|
49
|
+
A lost UI navigation response can be verified from the live authenticated cursor without another
|
|
50
|
+
goto. If its original owned GUI process has exited, continuation reports the uncertain UI action
|
|
51
|
+
as disconnected and retains saved program work. It does not recreate the old cursor or re-enable
|
|
52
|
+
a previous prompt policy. Other unproved live UI effects remain retained until their outcome is
|
|
53
|
+
established or the original process is known to have ended.
|
|
54
|
+
|
|
55
|
+
## Abandon an uncertain private program attempt
|
|
56
|
+
|
|
57
|
+
A post-mutation save timeout does not repeat the script or issue another save in the
|
|
58
|
+
error handler. Status exposes the original request identity and retained phase/budget.
|
|
59
|
+
Arbitrary script effects are never inferred from metadata or from an unverified DB.
|
|
60
|
+
After inspecting the retained attempt, explicitly stop only its verified owned worker
|
|
61
|
+
(`tools processes`, then `tools processes kill <process>` if required). Resume the
|
|
62
|
+
last acknowledged private snapshot with:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
insight-cli permissions grant Destructive
|
|
66
|
+
insight-cli ghidra abandon --session <session> --target <target> \
|
|
67
|
+
--request-id <original-request> --acknowledge-unknown-effects --json
|
|
68
|
+
insight-cli ghidra open --session <session> --target <target> --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Abandon requires exactly one unresolved private program operation, an unchanged verified
|
|
72
|
+
previous snapshot/generation, a stopped original worker and no active publication or live
|
|
73
|
+
debugger. It retains the native project, candidate artifacts, original intent/execution and
|
|
74
|
+
previous diagnostic result. Its terminal request is `failed` / `state: abandoned` with
|
|
75
|
+
`outcome: unknown`; no effect is marked applied. Repeating abandonment retrieves the same
|
|
76
|
+
result. Earlier saved private edits remain pending. The original changing request ID cannot
|
|
77
|
+
execute again. Abandoning never undoes external effects or establishes what an arbitrary
|
|
78
|
+
script did; the acknowledgement explicitly accepts that uncertainty. Publication recovery,
|
|
79
|
+
initial import, UI and debugger attempts use their own protocols and cannot use this command.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Analysis storage and migration
|
|
2
|
+
|
|
3
|
+
`storage show --json` reports effective profile storage, availability, active file/byte usage,
|
|
4
|
+
exact included trees and retained migration. The default is Factory profile AppData. No
|
|
5
|
+
checkout, environment or automatic disk fallback changes it. The non-secret setting is
|
|
6
|
+
`analysisDirectory` in Factory's profile (`profile show` also displays it). Use storage commands
|
|
7
|
+
to change it safely.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
insight-cli permissions grant Update
|
|
11
|
+
insight-cli storage show --json
|
|
12
|
+
insight-cli storage configure --directory "/mnt/analysis volume" --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`configure` requires no existing analysis entries. With existing data use `migrate`.
|
|
16
|
+
The directory is a **base**: the effective root appends `insight-cli/<profile>`, preserving
|
|
17
|
+
profile isolation. Choose an ordinary empty destination profile directory on a mounted local
|
|
18
|
+
filesystem. Spaces and Unicode are supported. Factory restricts the dedicated destination root to the
|
|
19
|
+
current user, including a Windows ACL; a filesystem that cannot apply this protection fails
|
|
20
|
+
before copying.
|
|
21
|
+
|
|
22
|
+
The complete `workspace`, `materials`, `temp` and `runtime` trees move: immutable inputs,
|
|
23
|
+
artifact/candidate snapshots, workspace SQLite DB/WAL, native private project/context DBs,
|
|
24
|
+
local Ghidra Server repositories, operation/publication/import journals, debugger traces,
|
|
25
|
+
process captures, exports, native helper compilation and verification working data.
|
|
26
|
+
**Runtime installations, acquisition caches, selections and process receipts move too**;
|
|
27
|
+
installation staging and activation must share a filesystem. External tool installations and
|
|
28
|
+
user-selected outputs outside these trees keep their locations.
|
|
29
|
+
|
|
30
|
+
Factory keeps profiles, permissions, IPC election/socket, migration-control metadata and
|
|
31
|
+
application logs in current-user AppData. Secrets stay in the OS keyring. Credential/profile
|
|
32
|
+
identities do not change. Updating/installing npm never migrates a profile automatically.
|
|
33
|
+
|
|
34
|
+
## Move an existing profile
|
|
35
|
+
|
|
36
|
+
Finish changing commands, close native contexts, and stop this profile's owned server/tool
|
|
37
|
+
processes through ordinary CLI commands. Inspect `tools processes --json`. Unverified lifetimes
|
|
38
|
+
also block migration. Do not kill guessed PIDs or stop other profiles to make preflight pass.
|
|
39
|
+
Factory retains IPC ownership and command admission; other profiles can keep working.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
insight-cli storage migrate --directory "/mnt/analysis volume" --dry-run --json
|
|
43
|
+
insight-cli storage migrate --directory "/mnt/analysis volume" --json
|
|
44
|
+
insight-cli storage show --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Dry-run checks separation, destination contents, access, conservative capacity and quiescence
|
|
48
|
+
without reserving/copying a migration. Source/destination/configuration roots cannot be equal
|
|
49
|
+
or nested. Destination symlink roots, escaping source links, special files, unresolved links
|
|
50
|
+
and inventories above one million entries or 128 directory levels are rejected. Internal
|
|
51
|
+
links retain their exact target strings. Preflight does not reserve space; concurrent disk use
|
|
52
|
+
can still cause a copy failure.
|
|
53
|
+
|
|
54
|
+
Migration durably reserves its journal, hashes stable source bytes, streams/syncs the copy,
|
|
55
|
+
independently hashes destination bytes and rechecks the source. Only then does it replace source
|
|
56
|
+
trees with permanent compatibility links and commit the Factory setting. Original trees are
|
|
57
|
+
renamed into `.storage-retained/<migration>` on their original volume. Copy/activation never
|
|
58
|
+
deletes them, including on failures. Existing IDs, requests, journals, candidate snapshots and
|
|
59
|
+
receipts retain exact bytes. Compatibility paths preserve old absolute references: do not remove
|
|
60
|
+
those links or their profile/source ancestors manually after migrating.
|
|
61
|
+
|
|
62
|
+
## Interruptions, uncertainty and retention
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
insight-cli storage resume --json
|
|
66
|
+
insight-cli storage rollback --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Ordinary research freezes during incomplete copy/activation/rollback/cleanup. `show` and Factory
|
|
70
|
+
profile inspection remain available. Resume verifies completed files, recopies an incomplete
|
|
71
|
+
file, rechecks capacity and finishes the retained transaction. Source and destination filesystem
|
|
72
|
+
anchor identities are bound durably. Missing/replaced volumes fail without creating a system-disk
|
|
73
|
+
fallback; mount the original volume before resuming.
|
|
74
|
+
|
|
75
|
+
Rollback restores retained source and the prior Factory setting. After activation it requires
|
|
76
|
+
an unchanged destination and a verified retained source. Native reopening or later findings can
|
|
77
|
+
make rollback unsafe, in which case it refuses and preserves both copies. Use forward migration
|
|
78
|
+
to another empty base after using the new location. A rolled-back destination remains for manual
|
|
79
|
+
inspection/removal and is never automatically adopted. Cleanup permanently disables rollback.
|
|
80
|
+
|
|
81
|
+
Unknown script/publication effects do **not** need abandonment before migrating a stopped
|
|
82
|
+
profile. Migration starts no worker, replays no script/check-in and marks no unknown outcome
|
|
83
|
+
applied. Inspect the original request after migrating; existing [recovery](recovery.md)
|
|
84
|
+
restrictions and independent readback requirements still apply.
|
|
85
|
+
|
|
86
|
+
After independent native reopen and saved-file readback, free retained source explicitly:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
insight-cli permissions grant Destructive
|
|
90
|
+
insight-cli storage cleanup --json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Cleanup verifies retained bytes, records irreversible intent, then deletes only that owned
|
|
94
|
+
backup. Interrupted cleanup continues through `storage resume`; rollback is already disabled.
|
|
95
|
+
Compatibility links, receipts and manifests remain. Clean or roll back the current migration
|
|
96
|
+
before starting another. This release provides no nonempty-destination adoption, reverse
|
|
97
|
+
synchronization, live-DB snapshotting or network-filesystem guarantees. POSIX directory fsync
|
|
98
|
+
is used. Windows has file fsync and rename/junction semantics; Node cannot fsync directories
|
|
99
|
+
there, and internal symlinks can require OS privileges.
|
|
@@ -3,7 +3,7 @@ name: insight-binary
|
|
|
3
3
|
description: Query structured PE, ELF and thin Mach-O headers, sections, imports and exports, or make an explicitly guarded new PE subsystem copy through insight-cli binary. Use for scoped binary structure, linkage and copy-only header edits without target execution.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Insight Binary 0.
|
|
6
|
+
# Insight Binary 0.3.0
|
|
7
7
|
|
|
8
8
|
If local help/status reports AppData or IPC access denied, retry that **read-only probe**
|
|
9
9
|
with the agent host's normal permission escalation, then use that route for later authorized
|