@eyeauras/insight-cli 0.0.0-stage → 0.2.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.
Files changed (174) hide show
  1. package/.cli-package-build.json +1 -0
  2. package/LICENSE +21 -0
  3. package/README.md +60 -2
  4. package/SKILL.md +58 -0
  5. package/dist/src/administration-results.d.ts +1 -0
  6. package/dist/src/administration-results.js +84 -0
  7. package/dist/src/administration.d.ts +14 -0
  8. package/dist/src/administration.js +134 -0
  9. package/dist/src/archive-contract.d.ts +6 -0
  10. package/dist/src/archive-contract.js +108 -0
  11. package/dist/src/archive.d.ts +12 -0
  12. package/dist/src/archive.js +116 -0
  13. package/dist/src/arguments.d.ts +14 -0
  14. package/dist/src/arguments.js +62 -0
  15. package/dist/src/artifacts.d.ts +17 -0
  16. package/dist/src/artifacts.js +115 -0
  17. package/dist/src/bin.d.ts +2 -0
  18. package/dist/src/bin.js +4 -0
  19. package/dist/src/cli.d.ts +10 -0
  20. package/dist/src/cli.js +419 -0
  21. package/dist/src/comment-effects.d.ts +3 -0
  22. package/dist/src/comment-effects.js +55 -0
  23. package/dist/src/contexts.d.ts +115 -0
  24. package/dist/src/contexts.js +1078 -0
  25. package/dist/src/coordinator.d.ts +41 -0
  26. package/dist/src/coordinator.js +160 -0
  27. package/dist/src/cross-results.d.ts +14 -0
  28. package/dist/src/cross-results.js +71 -0
  29. package/dist/src/cross.d.ts +3 -0
  30. package/dist/src/cross.js +43 -0
  31. package/dist/src/data-effects.d.ts +3 -0
  32. package/dist/src/data-effects.js +103 -0
  33. package/dist/src/debugger-results.d.ts +4 -0
  34. package/dist/src/debugger-results.js +151 -0
  35. package/dist/src/debugger-supervisor.d.ts +1 -0
  36. package/dist/src/debugger-supervisor.js +136 -0
  37. package/dist/src/debugger.d.ts +21 -0
  38. package/dist/src/debugger.js +267 -0
  39. package/dist/src/documentation-effects.d.ts +5 -0
  40. package/dist/src/documentation-effects.js +56 -0
  41. package/dist/src/extensions.d.ts +64 -0
  42. package/dist/src/extensions.js +289 -0
  43. package/dist/src/function-effects.d.ts +4 -0
  44. package/dist/src/function-effects.js +112 -0
  45. package/dist/src/ghidra.d.ts +50 -0
  46. package/dist/src/ghidra.js +468 -0
  47. package/dist/src/index.d.ts +2 -0
  48. package/dist/src/index.js +1 -0
  49. package/dist/src/initial-model.d.ts +6 -0
  50. package/dist/src/initial-model.js +85 -0
  51. package/dist/src/json.d.ts +2 -0
  52. package/dist/src/json.js +8 -0
  53. package/dist/src/lifecycle.d.ts +49 -0
  54. package/dist/src/lifecycle.js +154 -0
  55. package/dist/src/memory-inputs.d.ts +8 -0
  56. package/dist/src/memory-inputs.js +56 -0
  57. package/dist/src/merge.d.ts +29 -0
  58. package/dist/src/merge.js +66 -0
  59. package/dist/src/model.d.ts +74 -0
  60. package/dist/src/model.js +67 -0
  61. package/dist/src/mutation-effects.d.ts +4 -0
  62. package/dist/src/mutation-effects.js +321 -0
  63. package/dist/src/mutation-inputs.d.ts +2 -0
  64. package/dist/src/mutation-inputs.js +71 -0
  65. package/dist/src/mutations.d.ts +4 -0
  66. package/dist/src/mutations.js +53 -0
  67. package/dist/src/native-inputs.d.ts +28 -0
  68. package/dist/src/native-inputs.js +182 -0
  69. package/dist/src/native-queries.d.ts +2 -0
  70. package/dist/src/native-queries.js +29 -0
  71. package/dist/src/projects.d.ts +31 -0
  72. package/dist/src/projects.js +301 -0
  73. package/dist/src/prototype-cli.d.ts +8 -0
  74. package/dist/src/prototype-cli.js +155 -0
  75. package/dist/src/queries.d.ts +5 -0
  76. package/dist/src/queries.js +84 -0
  77. package/dist/src/query-policy.d.ts +6 -0
  78. package/dist/src/query-policy.js +72 -0
  79. package/dist/src/query-results.d.ts +2 -0
  80. package/dist/src/query-results.js +224 -0
  81. package/dist/src/research.d.ts +184 -0
  82. package/dist/src/research.js +808 -0
  83. package/dist/src/runtime-archives.d.ts +5 -0
  84. package/dist/src/runtime-archives.js +127 -0
  85. package/dist/src/runtime-catalog.d.ts +18 -0
  86. package/dist/src/runtime-catalog.js +27 -0
  87. package/dist/src/runtime-manager.d.ts +101 -0
  88. package/dist/src/runtime-manager.js +444 -0
  89. package/dist/src/runtime-selection.d.ts +13 -0
  90. package/dist/src/runtime-selection.js +25 -0
  91. package/dist/src/saved-materials.d.ts +12 -0
  92. package/dist/src/saved-materials.js +196 -0
  93. package/dist/src/scripts.d.ts +19 -0
  94. package/dist/src/scripts.js +79 -0
  95. package/dist/src/sdk-contracts.d.ts +13 -0
  96. package/dist/src/sdk-contracts.js +37 -0
  97. package/dist/src/sdk-files.d.ts +29 -0
  98. package/dist/src/sdk-files.js +249 -0
  99. package/dist/src/sdk.d.ts +4 -0
  100. package/dist/src/sdk.js +125 -0
  101. package/dist/src/server.d.ts +46 -0
  102. package/dist/src/server.js +460 -0
  103. package/dist/src/store.d.ts +33 -0
  104. package/dist/src/store.js +178 -0
  105. package/dist/src/sync-policy.d.ts +22 -0
  106. package/dist/src/sync-policy.js +123 -0
  107. package/dist/src/transport.d.ts +23 -0
  108. package/dist/src/transport.js +135 -0
  109. package/dist/src/ui-results.d.ts +2 -0
  110. package/dist/src/ui-results.js +80 -0
  111. package/dist/src/ui.d.ts +17 -0
  112. package/dist/src/ui.js +88 -0
  113. package/dist/src/utility.d.ts +14 -0
  114. package/dist/src/utility.js +43 -0
  115. package/dist/src/version-tracking.d.ts +57 -0
  116. package/dist/src/version-tracking.js +200 -0
  117. package/dist/src/workspace.d.ts +199 -0
  118. package/dist/src/workspace.js +564 -0
  119. package/package.json +47 -4
  120. package/references/InsightRepositoryProbe.java +55 -0
  121. package/references/administration.md +34 -0
  122. package/references/archive.md +32 -0
  123. package/references/artifacts.md +47 -0
  124. package/references/debugger.md +40 -0
  125. package/references/extensions-and-sync.md +124 -0
  126. package/references/managed-runtime.md +116 -0
  127. package/references/mutations.json +1424 -0
  128. package/references/native/InsightApplyDocumentation.java +48 -0
  129. package/references/native/InsightArchivePayloads.java +36 -0
  130. package/references/native/InsightBlockTransfer.java +57 -0
  131. package/references/native/InsightEmulation.java +93 -0
  132. package/references/native/InsightExtensions.java +36 -0
  133. package/references/native/InsightFunctionDatabases.java +98 -0
  134. package/references/native/InsightGuiMain.java +32 -0
  135. package/references/native/InsightHeadlessMain.java +10 -0
  136. package/references/native/InsightInitialImport.java +42 -0
  137. package/references/native/InsightInitialJournal.java +48 -0
  138. package/references/native/InsightInitialPublication.java +142 -0
  139. package/references/native/InsightKeytool.java +16 -0
  140. package/references/native/InsightNativeReceipt.java +31 -0
  141. package/references/native/InsightPlugins.java +34 -0
  142. package/references/native/InsightProjectFiles.java +92 -0
  143. package/references/native/InsightPublicationRecovery.java +63 -0
  144. package/references/native/InsightPythonWheels.java +31 -0
  145. package/references/native/InsightResearchQueries.java +188 -0
  146. package/references/native/InsightRuntimeDoctor.java +33 -0
  147. package/references/native/InsightSdkFiles.java +142 -0
  148. package/references/native/InsightSdkScript.java +31 -0
  149. package/references/native/InsightSdkTools.java +338 -0
  150. package/references/native/InsightSdkTypes.java +132 -0
  151. package/references/native/InsightServerAdministration.java +82 -0
  152. package/references/native/InsightServerInit.java +62 -0
  153. package/references/native/InsightServerMain.java +43 -0
  154. package/references/native/InsightServerProbe.java +29 -0
  155. package/references/native/InsightSnapshotFields.java +68 -0
  156. package/references/native/InsightSnapshotInspect.java +189 -0
  157. package/references/native/InsightSnapshotPublisher.java +123 -0
  158. package/references/native/InsightStartDebugger.java +28 -0
  159. package/references/native/InsightStopDebugger.java +20 -0
  160. package/references/native/InsightTraceInspect.java +24 -0
  161. package/references/native/InsightTraceState.java +130 -0
  162. package/references/native/InsightTraceTools.java +114 -0
  163. package/references/native/InsightVersionTracking.java +91 -0
  164. package/references/native-workflows.md +112 -0
  165. package/references/queries.json +1761 -0
  166. package/references/query-semantics.md +96 -0
  167. package/references/recovery.md +53 -0
  168. package/references/research.md +101 -0
  169. package/references/setup.md +49 -0
  170. package/runtime/GhidraMCP-7.0.0.jar +0 -0
  171. package/runtime/GhidraMCP-LICENSE +202 -0
  172. package/runtime/GhidraMCP-NOTICE +10 -0
  173. package/runtime/provenance.json +11 -0
  174. package/skills/insight-re/SKILL.md +108 -0
@@ -0,0 +1,419 @@
1
+ import { command, createCli, Permission, CliError, ProfileStore } from '@eyeauras/cli-factory';
2
+ import { join, resolve } from 'node:path';
3
+ import { readFile, readdir } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Workspace } from './workspace.js';
7
+ import { GhidraContexts } from './contexts.js';
8
+ import { nativeInputs } from './native-inputs.js';
9
+ import { Research, scope, address, commentKind, scalarText, number } from './research.js';
10
+ import { fail, id, text, digest, object } from './model.js';
11
+ import { queryCommands, extendQueries } from './queries.js';
12
+ import { mutationCommands } from './mutations.js';
13
+ import { crossCommands } from './cross.js';
14
+ import { Administration, administrationCommands } from './administration.js';
15
+ import { Lifecycle, lifecycleCommands } from './lifecycle.js';
16
+ import { utilityCommands } from './utility.js';
17
+ import { Projects, projectCommands } from './projects.js';
18
+ import { UserInterface, uiCommands, pluginCommands } from './ui.js';
19
+ import { Debugger, debuggerCommands } from './debugger.js';
20
+ import { Archive, archiveCommands } from './archive.js';
21
+ import { blockContent } from './memory-inputs.js';
22
+ import { verifyMutation } from './mutation-effects.js';
23
+ import { sdkCommands } from './sdk.js';
24
+ import { SdkFiles, sdkFileCommands } from './sdk-files.js';
25
+ import { parseDomainJson } from './json.js';
26
+ import { VersionTracking, trackingCommands } from './version-tracking.js';
27
+ import { Extensions, extensionCommands, extensionState, extensionInventoryCommands, managedExtensions } from './extensions.js';
28
+ import { Synchronization, synchronizationCommands } from './sync-policy.js';
29
+ import { artifactsCommands } from './saved-materials.js';
30
+ import { RuntimeManager, runtimeCommands, runtimeProcesses } from './runtime-manager.js';
31
+ import { runtimeSelection } from './runtime-selection.js';
32
+ const bindingFields = ['java', 'ghidraHome', 'mcpJar', 'mcpJarSha256', 'server', 'repository', 'readerUser', 'publisherUser', 'maxContexts', 'debuggerPython', 'windbgDir', 'archiveUrl'];
33
+ class Owner {
34
+ options;
35
+ profiles = new Map();
36
+ runtimeChanging = new Set();
37
+ async runtime(c, action, quiescent = true) {
38
+ const directory = c.appArguments.AppDataDirectory;
39
+ if (this.runtimeChanging.has(directory))
40
+ fail('busy', 'Another runtime operation is in progress.');
41
+ const current = this.profiles.get(directory);
42
+ if (quiescent && current?.tasks.size)
43
+ fail('busy', 'Research operations are in progress; finish them before managing the runtime.');
44
+ this.runtimeChanging.add(directory);
45
+ try {
46
+ if (!quiescent)
47
+ return await action();
48
+ const processes = await runtimeProcesses(directory);
49
+ if (processes.length)
50
+ fail('busy', 'Close Ghidra contexts and stop the owned server before changing or checking the runtime.', { processes });
51
+ if (current) {
52
+ await (await current.backend)?.dispose();
53
+ current.workspace.close();
54
+ this.profiles.delete(directory);
55
+ }
56
+ return await action();
57
+ }
58
+ finally {
59
+ this.runtimeChanging.delete(directory);
60
+ }
61
+ }
62
+ constructor(options) {
63
+ this.options = options;
64
+ }
65
+ selected(c) {
66
+ const directory = c.appArguments.AppDataDirectory;
67
+ if (this.runtimeChanging.has(directory))
68
+ fail('busy', 'Runtime preparation is in progress.');
69
+ const configuration = digest({ runtime: runtimeSelection(directory), profile: Object.fromEntries(bindingFields.map(key => [key, c.profile.values[key]])), extensions: extensionState(join(directory, 'workspace')).modules.filter(m => m.enabled).map(m => [m.name, m.sha256]) });
70
+ let profile = this.profiles.get(directory);
71
+ if (!profile) {
72
+ profile = { workspace: new Workspace(join(directory, 'workspace'), c.profile.name), tasks: new Map(), configuration };
73
+ this.profiles.set(directory, profile);
74
+ }
75
+ if (profile.configuration !== configuration)
76
+ fail('binding', 'Runtime profile changed; stop the IPC owner before reopening its saved workspace.');
77
+ const selected = profile;
78
+ const backend = async () => {
79
+ if (!selected.backend)
80
+ selected.backend = Promise.resolve(this.options.backend ?
81
+ this.options.backend(selected.workspace, c) : nativeInputs(c.profile.values, selected.workspace.directory).then(inputs => new GhidraContexts(selected.workspace, inputs, c)))
82
+ .catch(error => { selected.backend = undefined; throw error; });
83
+ const result = await selected.backend;
84
+ if (result instanceof GhidraContexts)
85
+ await managedExtensions(selected.workspace.directory);
86
+ return result instanceof GhidraContexts ? result.fork(c) : result;
87
+ };
88
+ const research = new Research(profile.workspace, backend, profile.tasks);
89
+ return { workspace: profile.workspace, research, synchronization: new Synchronization(profile.workspace, research, async () => {
90
+ const store = this.options.runtime?.profileStore ?? new ProfileStore({ applicationId: c.appArguments.AppName, appArguments: c.appArguments });
91
+ if (!(await store.getPermissions(c.profile.name))?.includes(Permission.Update))
92
+ throw new CliError('Automatic synchronization requires the current Factory Update permission.', { code: 'permission.denied', next: [['permissions', 'grant', 'Update']] });
93
+ }), administration: new Administration(profile.workspace, backend, profile.tasks), lifecycle: new Lifecycle(profile.workspace, research, backend), projects: new Projects(profile.workspace, backend, research, profile.tasks), sdkFiles: new SdkFiles(profile.workspace, research, backend), tracking: new VersionTracking(profile.workspace, research, backend, profile.tasks), ui: new UserInterface(profile.workspace, research, backend), debugger: new Debugger(profile.workspace, research, backend), archive: new Archive(profile.workspace, research, backend, c), backend };
94
+ }
95
+ async invalidateProfile(app) {
96
+ const directory = app.AppDataDirectory, profile = this.profiles.get(directory);
97
+ if (this.runtimeChanging.has(directory))
98
+ fail('busy', 'Runtime preparation is in progress; finish it before changing or deleting the profile.');
99
+ const materials = await readdir(join(directory, 'materials')).catch(error => { if (error.code === 'ENOENT')
100
+ return []; throw error; });
101
+ if (existsSync(join(directory, 'workspace', 'workspace.sqlite')) || materials.length)
102
+ fail('blocked', 'Profile has retained research data; preserve its workspace and materials before deleting or reconfiguring it.');
103
+ if (profile) {
104
+ await (await profile.backend)?.dispose();
105
+ profile.workspace.close();
106
+ this.profiles.delete(directory);
107
+ }
108
+ }
109
+ async dispose() {
110
+ for (const profile of this.profiles.values()) {
111
+ await Promise.allSettled([...profile.tasks.values()]);
112
+ try {
113
+ await (await profile.backend)?.dispose();
114
+ }
115
+ finally {
116
+ profile.workspace.close();
117
+ }
118
+ }
119
+ this.profiles.clear();
120
+ }
121
+ }
122
+ const scoped = [
123
+ { flags: '--session <id>', description: 'Select the durable research session', required: true },
124
+ { flags: '--target <id>', description: 'Select the immutable input target', required: true },
125
+ ];
126
+ const at = { flags: '--address <address>', description: 'Explicit hexadecimal address or space:address', required: true };
127
+ const request = { flags: '--request-id <id>', description: 'Retrieve the same changing intent after a lost response' };
128
+ const resolveOptions = [{ flags: '--resolve-conflict', description: 'Resolve the existing field against an explicitly observed shared value' },
129
+ { flags: '--expect-shared <value>', description: 'Shared value used for this resolution' },
130
+ { flags: '--expect-shared-null', description: 'Expect the shared comment to be absent' }];
131
+ function resolution(options) {
132
+ const expected = options.expectShared !== undefined, absent = Boolean(options.expectSharedNull);
133
+ if (!options.resolveConflict) {
134
+ if (expected || absent)
135
+ fail('invalid', 'Shared expectation requires --resolve-conflict.');
136
+ return;
137
+ }
138
+ if (expected === absent)
139
+ fail('invalid', 'Resolution needs exactly one --expect-shared or --expect-shared-null.');
140
+ return { expectedShared: absent ? null : scalarText(options.expectShared) };
141
+ }
142
+ function structureFields(value) {
143
+ const source = text(value, 65536);
144
+ let parsed;
145
+ try {
146
+ parsed = JSON.parse(source);
147
+ }
148
+ catch {
149
+ fail('invalid', 'Fields must be a JSON array of name/type objects.');
150
+ }
151
+ if (!Array.isArray(parsed) || !parsed.length || parsed.length > 256)
152
+ fail('invalid', 'Structure requires 1–256 field objects.');
153
+ return parsed.map(value => {
154
+ const field = object(value);
155
+ if (Object.keys(field).some(key => !['name', 'type', 'offset'].includes(key)))
156
+ fail('invalid', 'Unknown structure field property.');
157
+ return { name: text(field.name, 512), type: text(field.type, 512), ...(field.offset === undefined ? {} : { offset: number(field.offset, 2147483647) }) };
158
+ });
159
+ }
160
+ const paged = [
161
+ { flags: '--limit <count>', description: 'Maximum items in this page (1–100)', defaultValue: 50, parse: (value) => number(value, 100, 1) },
162
+ { flags: '--offset <count>', description: 'Skip items before this page', defaultValue: 0, parse: (value) => number(value, 2147483647) },
163
+ ];
164
+ const fields = [
165
+ ['java', '--java <path>', 'Java 21 JDK executable'],
166
+ ['ghidraHome', '--ghidra-home <path>', 'Ghidra 12.1.2 installation'],
167
+ ['mcpJar', '--mcp-jar <path>', 'Optional override of the packaged verified GhidraMCP runtime'],
168
+ ['mcpJarSha256', '--mcp-jar-sha256 <sha>', 'Expected runtime artifact digest'],
169
+ ['server', '--server <origin>', 'External Ghidra Server origin (omit for local startup)'],
170
+ ['repository', '--repository <name>', 'Repository on the external server'],
171
+ ['readerUser', '--reader-user <name>', 'Read-only external account'],
172
+ ['publisherUser', '--publisher-user <name>', 'External publication account'],
173
+ ['maxContexts', '--max-contexts <count>', 'Concurrent contexts (default 4, maximum 16)'],
174
+ ['debuggerPython', '--debugger-python <path>', 'Optional Python executable for a configured debugger offer'],
175
+ ['windbgDir', '--windbg-dir <path>', 'Optional Windows debugger runtime directory'],
176
+ ['archiveUrl', '--archive-url <url>', 'Explicit archive service base URL (disabled by default)'],
177
+ ];
178
+ const mode = (value) => {
179
+ if (value === undefined)
180
+ return;
181
+ if (value !== 'headless' && value !== 'gui')
182
+ fail('invalid', 'Mode must be headless or gui.');
183
+ return value;
184
+ };
185
+ const targetView = (target) => ({ target: target.id, name: target.name, binarySha256: target.binarySha256, size: target.size, createdAt: target.createdAt });
186
+ function scopedFailures(entry, owner, parents = []) {
187
+ const path = [...parents, entry.name.split(' ')[0]], name = path.join(' ');
188
+ const run = entry.run;
189
+ return { ...entry, ...(entry.children ? { children: entry.children.map(child => scopedFailures(child, owner, path)) } : {}), ...(run ? { run: async (input, c) => {
190
+ try {
191
+ let selected;
192
+ try {
193
+ selected = scope(input.options);
194
+ if (selected.session === 'new')
195
+ selected = undefined;
196
+ }
197
+ catch { }
198
+ if (!selected)
199
+ return await run(input, c);
200
+ const services = owner.selected(c);
201
+ return await services.research.boundary(selected, async () => {
202
+ const excluded = ['open', 'merge', 'refresh', 'sync-policy', 'close', 'changes', 'debugger', 'ui', 'version-tracking', 'archive', 'projects', 'repository', 'server', 'formats', 'libraries', 'plugins'];
203
+ const eligible = entry.permission !== Permission.ReadOnly && entry.permission !== undefined && !excluded.includes(path[1]) && !['ghidra types archive-export', 'ghidra documentation transfer'].includes(name);
204
+ return eligible ? services.synchronization.execute(selected, name, { ...input.options, commandArguments: input.args }, async (requestId) => run({ ...input, options: { ...input.options, ...(requestId ? { requestId } : {}) } }, c)) : run(input, c);
205
+ });
206
+ }
207
+ catch (error) {
208
+ let selected;
209
+ try {
210
+ selected = scope(input.options);
211
+ }
212
+ catch {
213
+ throw error;
214
+ }
215
+ if (!(error instanceof CliError))
216
+ throw error;
217
+ const result = error.result && typeof error.result === 'object' && !Array.isArray(error.result) ? error.result : {};
218
+ throw new CliError(error.message, { code: error.code, exitCode: error.exitCode, next: error.next, result: { ...result, ...selected } });
219
+ }
220
+ } } : {}) };
221
+ }
222
+ export function createDefinition(options = {}) {
223
+ const owner = new Owner(options);
224
+ const definition = {
225
+ name: 'insight-cli', applicationId: 'insight-cli', version: '0.2.0', description: 'Isolated research contexts and coordinated Ghidra analysis',
226
+ resources: [owner], permissions: { categories: [{ name: 'Destructive', description: 'Explicit deletion or replacement of retained research data', enabledByDefault: false }] }, ...(options.runtime ? { runtime: options.runtime } : {}),
227
+ profile: { fields: fields.map(([name, flags, description]) => ({ name: name, flags: flags, description: description,
228
+ ...(name === 'maxContexts' ? { normalize: (value) => number(value, 16, 1) } : {}) })) },
229
+ auth: {
230
+ loginOptions: [{ flags: '--role <role>', description: 'External reader, publisher or archive role', defaultValue: 'reader' },
231
+ { flags: '--password-stdin', description: 'Read the password from stdin' }],
232
+ async login(c, o) {
233
+ const role = text(o.role);
234
+ if (!['reader', 'publisher', 'archive'].includes(role))
235
+ fail('invalid', 'Role must be reader, publisher or archive.');
236
+ if (role !== 'archive' && !c.profile.values.server)
237
+ fail('configuration', 'Local server credentials are managed automatically.');
238
+ if (role === 'archive' && !c.profile.values.archiveUrl)
239
+ fail('configuration', 'Configure an archive URL before storing its token.');
240
+ if (!o.passwordStdin || !c.stdinAvailable)
241
+ fail('credentials', 'Supply --password-stdin for this role.');
242
+ let candidate = '';
243
+ for await (const chunk of c.io.input) {
244
+ candidate += chunk.toString();
245
+ if (candidate.length > 4096)
246
+ fail('limit', 'Password input exceeds 4096 characters.');
247
+ }
248
+ candidate = candidate.replace(/\r?\n$/, '');
249
+ if (!candidate || /[\r\n\0]/.test(candidate))
250
+ fail('credentials', 'Password must be one nonempty line.');
251
+ await c.secrets.set(role === 'archive' ? 'archiveToken' : role + 'Password', candidate);
252
+ return { authenticated: true, identity: { role, ...(role === 'archive' ? {} : { user: c.profile.values[role + 'User'] }), validation: 'stored; authority verified at connection' } };
253
+ },
254
+ async status(c) {
255
+ let reader = 'readerPassword', publisher = 'publisherPassword';
256
+ const external = Boolean(c.profile.values.server);
257
+ if (!external) {
258
+ try {
259
+ const local = JSON.parse(await readFile(join(c.appArguments.AppDataDirectory, 'workspace/server/local.json'), 'utf8'));
260
+ reader = local.readerSecret;
261
+ publisher = local.publisherSecret;
262
+ }
263
+ catch (error) {
264
+ if (error.code !== 'ENOENT')
265
+ throw error;
266
+ return { authenticated: false, identity: { mode: 'local', validation: 'managed on first open' } };
267
+ }
268
+ }
269
+ const readerStored = Boolean(await c.secrets.get(reader)), publisherStored = Boolean(await c.secrets.get(publisher));
270
+ return { authenticated: readerStored && publisherStored, identity: { mode: external ? 'external' : 'local', readerStored, publisherStored } };
271
+ },
272
+ async logout(c) {
273
+ await c.secrets.delete('archiveToken');
274
+ if (!c.profile.values.server)
275
+ return;
276
+ await c.secrets.delete('readerPassword');
277
+ await c.secrets.delete('publisherPassword');
278
+ },
279
+ },
280
+ builtins: [command('skill [name]', 'Locate the installed insight-cli or insight-re skill', ({ args }) => {
281
+ const name = args.name === undefined ? 'insight-cli' : text(args.name);
282
+ if (!['insight-cli', 'insight-re'].includes(name))
283
+ fail('notFound', 'Unknown skill; choose insight-cli or insight-re.');
284
+ return { version: '0.2.0', name, path: fileURLToPath(new URL(name === 'insight-re' ? '../../skills/insight-re/SKILL.md' : '../../SKILL.md', import.meta.url)),
285
+ skills: ['insight-cli', 'insight-re'] };
286
+ })],
287
+ commands: [
288
+ ...artifactsCommands(),
289
+ command('targets', 'Inspect immutable inputs', [
290
+ command('add <input>', 'Consume input without starting a tool', async ({ args }, c) => targetView(await owner.selected(c).workspace.importTarget(resolve(c.cwd, text(args.input, 4096)))), { permission: Permission.Update }),
291
+ command('list', 'List known inputs', ({ options: o }, c) => {
292
+ const items = owner.selected(c).workspace.targets(number(o.limit, 100, 1), number(o.offset, 2147483647));
293
+ return { items: items.map(targetView), offset: o.offset, limit: o.limit, truncated: items.length === o.limit };
294
+ }, { permission: Permission.ReadOnly, options: paged }),
295
+ command('show <target>', 'Show an input identity', ({ args }, c) => targetView(owner.selected(c).workspace.target(id(args.target))), { permission: Permission.ReadOnly }),
296
+ ]),
297
+ command('sessions', 'Inspect durable sessions', [
298
+ command('list', 'List independent sessions', ({ options: o }, c) => { const items = owner.selected(c).workspace.sessions(number(o.limit, 100, 1), number(o.offset, 2147483647)); return { items, offset: o.offset, limit: o.limit, truncated: items.length === Number(o.limit) }; }, { permission: Permission.ReadOnly, options: paged }),
299
+ command('status <session>', 'Inspect saved work and unresolved outcomes', ({ args, options: o }, c) => {
300
+ const selected = owner.selected(c), session = id(args.session);
301
+ selected.workspace.session(session);
302
+ if (o.target)
303
+ return selected.research.status({ session, target: id(o.target) });
304
+ const limit = number(o.limit, 100, 1), offset = number(o.offset, 2147483647), contexts = selected.workspace.contexts(session, limit, offset);
305
+ return { session, contexts: contexts.map(context => selected.research.status(context)), limit, offset, truncated: contexts.length === limit };
306
+ }, { permission: Permission.ReadOnly, options: [{ flags: '--target <id>', description: 'Inspect one target context' }, ...paged] }),
307
+ ]),
308
+ command('ghidra', 'Research through an isolated saved context', [
309
+ command('refresh', 'Receive safe shared changes while retaining local conflicts', ({ options: o }, c) => owner.selected(c).research.refresh(scope(o), o.requestId === undefined ? undefined : id(o.requestId)), { permission: Permission.Update, options: [...scoped, request] }),
310
+ command('merge', 'Publish the complete selected context or retain every conflict', ({ options: o }, c) => owner.selected(c).research.merge(scope(o), o.requestId === undefined ? undefined : id(o.requestId)), { permission: Permission.Update, options: [...scoped, request] }),
311
+ command('open [input]', 'Start independent work or continue a context', async ({ args, options: o }, c) => {
312
+ if (Boolean(args.input) === Boolean(o.target))
313
+ fail('invalid', 'Supply exactly one input path or --target.');
314
+ const selected = owner.selected(c), target = args.input ? (await selected.workspace.importTarget(resolve(c.cwd, text(args.input, 4096)))).id : id(o.target);
315
+ let previous;
316
+ try {
317
+ previous = selected.workspace.model(target).settings;
318
+ }
319
+ catch (error) {
320
+ if (!String(error.code).endsWith('.notFound'))
321
+ throw error;
322
+ }
323
+ const settings = { ...previous, autoAnalyze: o.analysis === false ? false : previous?.autoAnalyze ?? true,
324
+ ...(o.language ? { language: text(o.language) } : {}), ...(o.compilerSpec ? { compilerSpec: text(o.compilerSpec) } : {}),
325
+ ...(o.imageBase ? { imageBase: text(o.imageBase) } : {}), ...(o.loader ? { loader: text(o.loader, 512) } : {}),
326
+ ...(o.loaderOptions !== undefined ? { loaderOptions: object(parseDomainJson(text(o.loaderOptions, 16000))) } : {}) };
327
+ return selected.research.open(target, text(o.session), settings, o.requestId === undefined ? undefined : id(o.requestId), mode(o.mode));
328
+ }, { permission: Permission.Update, options: [{ flags: '--session <id>', description: 'Use new for independent work, or an existing session', required: true },
329
+ { flags: '--target <id>', description: 'Continue existing input instead of supplying a file' }, request,
330
+ { flags: '--mode <mode>', description: 'Request headless or gui; continuation preserves current mode' },
331
+ { flags: '--no-analysis', description: 'Skip initial automatic analysis' },
332
+ { flags: '--language <id>', description: 'Explicit initial loader language' },
333
+ { flags: '--compiler-spec <id>', description: 'Explicit initial compiler specification' },
334
+ { flags: '--image-base <address>', description: 'Initial image base' },
335
+ { flags: '--loader <name>', description: 'Explicit installed loader name/ID from formats loaders' },
336
+ { flags: '--loader-options <json>', description: 'Named primitive SDK loader options, requiring --loader' }] }),
337
+ command('strings', 'Read defined strings', [
338
+ command('search', 'Find literal text and usable addresses', ({ options: o }, c) => owner.selected(c).research.strings(scope(o), text(o.contains, 4096), number(o.limit, 100, 1), number(o.offset, 2147483647)), { permission: Permission.ReadOnly, options: [...scoped, { flags: '--contains <text>', description: 'Literal case-insensitive substring', required: true }, ...paged] }),
339
+ ]),
340
+ command('xrefs', 'Follow cross references', [
341
+ command('to', 'Find incoming references and their functions', ({ options: o }, c) => owner.selected(c).research.xrefs(scope(o), address(o.address), number(o.limit, 100, 1), number(o.offset, 2147483647)), { permission: Permission.ReadOnly, options: [...scoped, at, ...paged] }),
342
+ ]),
343
+ command('types', 'Read and edit data types', [
344
+ command('struct-layout', 'Read a structure layout', ({ options: o }, c) => owner.selected(c).research.read(scope(o), '/get_struct_layout', { struct_name: text(o.name, 512) })
345
+ .then(value => ({ ...scope(o), value })), { permission: Permission.ReadOnly, options: [...scoped, { flags: '--name <name>', description: 'Structure name', required: true }] }),
346
+ command('create-struct', 'Create and save a private structure', ({ options: o }, c) => {
347
+ const selected = owner.selected(c), who = scope(o), name = text(o.name, 512), fields = structureFields(o.fields);
348
+ if (o.replacePlaceholder) {
349
+ const parameters = { path: name.startsWith('/') ? name : '/' + name, fields, packing: -1, alignment: 0, replace_placeholder: true };
350
+ return selected.research.mutate(who, '/sdk/type-structure', parameters, async () => ({}), o.requestId === undefined ? undefined : id(o.requestId), (backend, snapshot, response) => verifyMutation(backend, snapshot, '/sdk/type-structure', parameters, response));
351
+ }
352
+ return selected.research.mutate(who, '/create_struct', { name, fields }, async (backend) => {
353
+ const result = object(await backend.call(who, '/get_struct_layout', { struct_name: name }));
354
+ if (result.name !== name || !Array.isArray(result.fields) || result.fields.length !== fields.length)
355
+ fail('partial', 'Structure readback omitted fields or changed its name.');
356
+ for (let i = 0; i < fields.length; i++)
357
+ if (object(result.fields[i]).name !== fields[i].name)
358
+ fail('partial', 'Structure readback changed a field name.');
359
+ return result;
360
+ }, o.requestId === undefined ? undefined : id(o.requestId));
361
+ }, { permission: Permission.Update, options: [...scoped, { flags: '--name <name>', description: 'New structure name', required: true },
362
+ { flags: '--fields <json>', description: 'Array of {name,type,offset?}', required: true }, { flags: '--replace-placeholder', description: 'Replace only an existing empty structure, with independently verified saved layout' }, request] }),
363
+ ]),
364
+ command('memory', 'Read or edit memory blocks', [
365
+ command('list', 'Read bounded memory blocks', ({ options: o }, c) => owner.selected(c).research.read(scope(o), '/list_program_items', { kind: 'segments', limit: number(o.limit, 100, 1), offset: number(o.offset, 2147483647) })
366
+ .then(value => ({ ...scope(o), value })), { permission: Permission.ReadOnly, options: [...scoped, ...paged] }),
367
+ command('create-block', 'Create a saved initialized/uninitialized or overlay block with verified content', ({ options: o }, c) => {
368
+ const selected = owner.selected(c), who = scope(o), parameters = { name: text(o.name, 512), address: address(o.address),
369
+ ...(o.size === undefined ? {} : { size: number(o.size, 16777216, 1) }), read: o.read !== false, write: o.write !== false, execute: Boolean(o.execute),
370
+ initialized: o.initialized !== false, overlay: Boolean(o.overlay), volatile: Boolean(o.volatile), comment: o.comment === undefined ? '' : text(o.comment, 16000),
371
+ fill_byte: o.fillByte === undefined ? 0 : number(o.fillByte, 255), ...(o.bytesHex === undefined ? {} : { bytes_hex: o.bytesHex }), ...(o.bytesBase64 === undefined ? {} : { bytes_base64: o.bytesBase64 }) };
372
+ const expected = blockContent(parameters);
373
+ parameters.size = expected.size;
374
+ return selected.research.mutate(who, '/create_memory_block', parameters, async () => ({}), o.requestId === undefined ? undefined : id(o.requestId), (backend, snapshot, response) => verifyMutation(backend, snapshot, '/create_memory_block', parameters, response));
375
+ }, { permission: Permission.Update, options: [...scoped, at, { flags: '--name <name>', description: 'Memory block name', required: true },
376
+ { flags: '--size <bytes>', description: 'Positive size up to 16 MiB; defaults to content length' },
377
+ { flags: '--bytes-hex <hex>', description: 'Initial bytes in hexadecimal; remainder uses fill-byte' },
378
+ { flags: '--bytes-base64 <base64>', description: 'Initial bytes as canonical padded base64' },
379
+ { flags: '--fill-byte <byte>', description: 'Fill byte from 0 to 255', defaultValue: 0 },
380
+ { flags: '--initialized <boolean>', description: 'false creates uninitialized memory', defaultValue: true, parse: (v) => { if (v !== 'true' && v !== 'false')
381
+ fail('invalid', 'initialized must be true or false.'); return v === 'true'; } },
382
+ { flags: '--overlay', description: 'Create a distinct overlay address space' },
383
+ { flags: '--volatile', description: 'Mark memory volatile' }, { flags: '--comment <text>', description: 'Block comment' },
384
+ { flags: '--no-read', description: 'Disable read permission' }, { flags: '--no-write', description: 'Disable write permission' },
385
+ { flags: '--execute', description: 'Enable execution permission' }, request] }),
386
+ ]),
387
+ command('functions', 'Read or name functions', [
388
+ command('set-function-prototype', 'Set a C prototype and optional explicit compiler-supported calling convention', ({ options: o }, c) => {
389
+ const selected = owner.selected(c), who = scope(o), parameters = { function_address: address(o.address), prototype: text(o.prototype, 16000),
390
+ ...(o.callingConvention === undefined ? {} : { calling_convention: text(o.callingConvention, 512) }) };
391
+ return selected.research.mutate(who, '/set_function_prototype', parameters, async () => ({}), o.requestId === undefined ? undefined : id(o.requestId), (backend, snapshot, response) => verifyMutation(backend, snapshot, '/set_function_prototype', parameters, response));
392
+ }, { permission: Permission.Update, options: [...scoped, at, { flags: '--prototype <signature>', description: 'Complete C prototype', required: true },
393
+ { flags: '--calling-convention <name>', description: 'Explicit convention supported by the selected compiler specification' }, request] }),
394
+ command('get', 'Read a function and entry comments', ({ options: o }, c) => owner.selected(c).research.function(scope(o), address(o.address)), { permission: Permission.ReadOnly, options: [...scoped, at] }),
395
+ command('decompile', 'Read decompiled function text', ({ options: o }, c) => owner.selected(c).research.function(scope(o), address(o.address), true), { permission: Permission.ReadOnly, options: [...scoped, at] }),
396
+ command('rename', 'Record a saved private name', ({ options: o }, c) => {
397
+ const name = text(o.name, 512);
398
+ if (name !== name.trim())
399
+ fail('invalid', 'Function name may not have leading or trailing whitespace.');
400
+ return owner.selected(c).research.edit(scope(o), address(o.address), 'function.name', name, o.requestId === undefined ? undefined : id(o.requestId), resolution(o));
401
+ }, { permission: Permission.Update, options: [...scoped, at, { flags: '--name <name>', description: 'Desired function name', required: true }, request, ...resolveOptions] }),
402
+ ]),
403
+ command('comments', 'Read or edit listing comments', [
404
+ command('get', 'Read one kind or all five fields', ({ options: o }, c) => owner.selected(c).research.comment(scope(o), address(o.address), o.kind === undefined ? undefined : commentKind(o.kind)), { permission: Permission.ReadOnly, options: [...scoped, at, { flags: '--kind <kind>', description: 'eol, pre, post, plate or repeatable' }] }),
405
+ command('set', 'Record a saved private comment or clear it', ({ options: o }, c) => {
406
+ if (Boolean(o.clear) === (o.text !== undefined))
407
+ fail('invalid', 'Supply exactly one --text or --clear.');
408
+ return owner.selected(c).research.edit(scope(o), address(o.address), 'comment.' + commentKind(o.kind), o.clear ? null : scalarText(o.text), o.requestId === undefined ? undefined : id(o.requestId), resolution(o));
409
+ }, { permission: Permission.Update, options: [...scoped, at, { flags: '--kind <kind>', description: 'eol, pre, post, plate or repeatable', required: true },
410
+ { flags: '--text <text>', description: 'Desired text; empty text clears to null' }, { flags: '--clear', description: 'Clear this comment to null' }, request, ...resolveOptions] }),
411
+ ]),
412
+ ]),
413
+ ],
414
+ };
415
+ return { ...definition, commands: definition.commands?.map(entry => entry.name === 'ghidra' ?
416
+ scopedFailures({ ...entry, children: extendQueries(extendQueries(extendQueries(entry.children ?? [], queryCommands(c => owner.selected(c).research)), mutationCommands(c => owner.selected(c).research)), [...sdkCommands(c => owner.selected(c).research), ...sdkFileCommands(c => owner.selected(c).sdkFiles), ...trackingCommands(c => owner.selected(c).tracking), ...crossCommands(c => owner.selected(c).research), ...administrationCommands(c => owner.selected(c).administration, options.backend ? undefined : async (c) => { const status = await new RuntimeManager(c).status(); return status.state === 'not_ready' ? { ...status.server, connected: false, state: 'runtime_not_ready', missing: status.missing } : undefined; }),
417
+ ...extensionCommands(c => new Extensions(join(c.appArguments.AppDataDirectory, 'workspace'))), ...extensionInventoryCommands(c => owner.selected(c).backend), ...pluginCommands(c => owner.selected(c).ui), ...synchronizationCommands(c => owner.selected(c).synchronization), ...utilityCommands(), ...runtimeCommands((c, action, quiescent) => owner.runtime(c, action, quiescent)), ...lifecycleCommands(c => owner.selected(c).lifecycle, c => new RuntimeManager(c).status()), ...projectCommands(c => owner.selected(c).projects), ...uiCommands(c => owner.selected(c).ui), ...debuggerCommands(c => owner.selected(c).debugger), ...archiveCommands(c => owner.selected(c).archive)]) }, owner) : entry) };
418
+ }
419
+ export const createInsightCli = (options = {}) => createCli(createDefinition(options));
@@ -0,0 +1,3 @@
1
+ import type { ResearchBackend } from './research.js';
2
+ import type { Artifact } from './artifacts.js';
3
+ export declare function verifyComments(backend: ResearchBackend, snapshot: Artifact, path: string, p: Record<string, unknown>): Promise<Record<string, unknown>>;
@@ -0,0 +1,55 @@
1
+ import { address } from './research.js';
2
+ import { object, fail } from './model.js';
3
+ const normalize = (value) => value === '' ? null : value;
4
+ export async function verifyComments(backend, snapshot, path, p) {
5
+ if (!backend.inspect)
6
+ fail('configuration', 'Batch comments require saved-state inspection.');
7
+ const inspect = (kind, parameters) => backend.inspect(snapshot, { kind, ...parameters });
8
+ if (path === '/clear_function_comments') {
9
+ const ref = String(p.function);
10
+ let selector;
11
+ try {
12
+ selector = { address: address(ref) };
13
+ }
14
+ catch {
15
+ selector = { name: ref };
16
+ }
17
+ const value = await inspect('function_comments', selector);
18
+ if (p.clear_plate !== false && value.plate !== null)
19
+ fail('partial', 'Saved function plate comment was not cleared.');
20
+ if (!Array.isArray(value.comments))
21
+ fail('partial', 'Saved function comment inventory is absent.');
22
+ for (const item of value.comments) {
23
+ const comment = object(item);
24
+ if (comment.kind === 'eol' && p.clear_eol !== false || comment.kind === 'pre' && p.clear_pre !== false)
25
+ fail('partial', 'Requested function comments remain in saved state.');
26
+ }
27
+ return value;
28
+ }
29
+ const verified = [];
30
+ for (const [parameter, kind] of [['decompiler_comments', 'pre'], ['disassembly_comments', 'eol']]) {
31
+ const requested = p[parameter] ?? [];
32
+ if (!Array.isArray(requested))
33
+ fail('invalid', 'Batch comments require arrays of {address,comment}.');
34
+ const expected = new Map();
35
+ for (const raw of requested) {
36
+ const item = object(raw);
37
+ if (typeof item.comment !== 'string')
38
+ fail('invalid', 'Each batch comment requires text or empty text to clear.');
39
+ expected.set(address(item.address), normalize(item.comment));
40
+ }
41
+ for (const [at, text] of expected) {
42
+ const value = await inspect('comments', { address: at });
43
+ if (value[kind] !== text)
44
+ fail('partial', 'Saved batch comment differs from the requested text.');
45
+ verified.push({ address: at, kind, text });
46
+ }
47
+ }
48
+ if (p.plate_comment !== undefined && p.plate_comment !== null && !(path === '/batch_apply_documentation' && p.plate_comment === '')) {
49
+ const value = await inspect('comments', { address: p.address });
50
+ if (value.plate !== normalize(p.plate_comment))
51
+ fail('partial', 'Saved batch plate comment differs from the requested text.');
52
+ verified.push({ address: p.address, kind: 'plate', text: value.plate });
53
+ }
54
+ return { comments: verified };
55
+ }
@@ -0,0 +1,115 @@
1
+ import type { CommandContext } from '@eyeauras/cli-factory';
2
+ import { type ChildProcess } from 'node:child_process';
3
+ import { type NativeInputs } from './native-inputs.js';
4
+ import { GhidraServer } from './server.js';
5
+ import { Workspace, type Scope, type GhidraContext, type ScalarChange, type Publication, type DebuggerState } from './workspace.js';
6
+ import { type Artifact } from './artifacts.js';
7
+ import { HttpBridge } from './transport.js';
8
+ export type ToolMode = 'headless' | 'gui';
9
+ interface ProcessBinding {
10
+ pid: number;
11
+ endpoint: string;
12
+ root: string;
13
+ target: string;
14
+ context?: string;
15
+ mode: ToolMode;
16
+ program: string;
17
+ tokenSecret: string;
18
+ runtimeFingerprint: string;
19
+ kind: 'context' | 'shared' | 'bootstrap' | 'candidate';
20
+ baseRevision?: number;
21
+ viewEpoch?: number;
22
+ }
23
+ interface Running {
24
+ binding: ProcessBinding;
25
+ http: HttpBridge;
26
+ child?: ChildProcess;
27
+ }
28
+ /** Isolated native contexts. This layer has no agent-facing instance/worker selector. */
29
+ export declare class GhidraContexts {
30
+ private readonly workspace;
31
+ private readonly inputs;
32
+ private readonly c;
33
+ private readonly running;
34
+ private readonly modelTasks;
35
+ private readonly ownedServer;
36
+ private readonly capacity;
37
+ constructor(workspace: Workspace, inputs: NativeInputs, c: CommandContext, running?: Map<string, Running>, modelTasks?: Map<string, Promise<void>>, ownedServer?: GhidraServer, capacity?: {
38
+ slots: Set<string>;
39
+ inventory?: Promise<void>;
40
+ });
41
+ fork(c: CommandContext): GhidraContexts;
42
+ private directory;
43
+ private server;
44
+ administration(operation: string, parameters: Record<string, unknown>): Promise<Record<string, unknown>>;
45
+ sdkFile(operation: string, parameters: Record<string, unknown>): Promise<Record<string, unknown>>;
46
+ private prepareRoot;
47
+ private launch;
48
+ private verified;
49
+ private source;
50
+ private stopRecord;
51
+ private debuggerReleased;
52
+ private capture;
53
+ private shared;
54
+ private retireLegacyBootstrap;
55
+ private initialModel;
56
+ private model;
57
+ private privateCopy;
58
+ open(scope: Scope, request?: string): Promise<GhidraContext>;
59
+ private selected;
60
+ call(scope: Scope, operation: string, parameters?: Record<string, unknown>): Promise<unknown>;
61
+ saved(scope: Scope): Promise<Artifact>;
62
+ scripts(scope: Scope, filter: string, limit: number, offset: number): Promise<import("./scripts.js").ScriptPage>;
63
+ inspect(snapshot: Artifact, parameters: Record<string, unknown>): Promise<Record<string, unknown>>;
64
+ private removePeer;
65
+ private reconcilePeers;
66
+ private withPeer;
67
+ pair(selected: Scope, other: Scope, snapshot: Artifact, operation: string, parameters: Record<string, unknown>): Promise<unknown>;
68
+ transfer(selected: Scope, source: Artifact, dryRun: boolean): Promise<unknown>;
69
+ transferCheck(selected: Scope, source: Artifact, candidate: Artifact): Promise<unknown>;
70
+ mode(scope: Scope, mode: ToolMode): Promise<void>;
71
+ project(operation: string, parameters: Record<string, unknown>): Promise<Record<string, unknown>>;
72
+ ui(scope: Scope, operation: string, p: Record<string, unknown>): Promise<Record<string, unknown>>;
73
+ archivePayloads(scope: Scope, p: Record<string, unknown>): Promise<Record<string, unknown>>;
74
+ debuggerStart(scope: Scope): Promise<void>;
75
+ debuggerStop(scope: Scope): Promise<void>;
76
+ private debuggerHelper;
77
+ private debuggerHelperRecord;
78
+ debuggerCall(scope: Scope, operation: string, p?: Record<string, unknown>): Promise<unknown>;
79
+ private traceHelper;
80
+ debuggerSaved(scope: Scope): Promise<DebuggerState>;
81
+ debuggerSelect(scope: Scope, trace: string): Promise<void>;
82
+ debuggerLaunch(scope: Scope, p: Record<string, unknown>, request: string): Promise<unknown>;
83
+ projectOutcome(requestId: string, expected: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
84
+ private debuggerMetadataChanges;
85
+ close(scope: Scope): Promise<void>;
86
+ closed(scope: Scope): Promise<boolean>;
87
+ latest(targetId: string): Promise<{
88
+ revision: number;
89
+ snapshot: Artifact;
90
+ }>;
91
+ fields(snapshot: Artifact, changes: Pick<ScalarChange, 'address' | 'field'>[]): Promise<Record<string, {
92
+ value: string | null;
93
+ dependency: string;
94
+ exists: boolean;
95
+ }>>;
96
+ private applyField;
97
+ candidate(targetId: string, snapshot: Artifact, changes: ScalarChange[]): Promise<Artifact>;
98
+ publish(publication: Publication): Promise<{
99
+ state: 'published';
100
+ revision: number;
101
+ } | {
102
+ state: 'conflict';
103
+ applied: 0;
104
+ }>;
105
+ recover(publication: Publication): Promise<{
106
+ state: 'verified';
107
+ revision: number;
108
+ } | {
109
+ state: 'unknown';
110
+ }>;
111
+ recoverModel(targetId: string): Promise<boolean>;
112
+ dispose(): Promise<void>;
113
+ private inventory;
114
+ }
115
+ export {};