@siftd/connect-agent 0.2.29 → 0.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.js +35 -7
- package/dist/core/asset-api.d.ts +94 -0
- package/dist/core/asset-api.js +182 -0
- package/dist/core/assets.d.ts +176 -0
- package/dist/core/assets.js +192 -0
- package/dist/core/preview-worker.d.ts +98 -0
- package/dist/core/preview-worker.js +395 -0
- package/dist/genesis/tool-patterns.json +9 -4
- package/dist/orchestrator.js +24 -5
- package/dist/prompts/worker-system.d.ts +1 -1
- package/dist/prompts/worker-system.js +34 -7
- package/dist/websocket.d.ts +19 -2
- package/dist/websocket.js +40 -2
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -5,18 +5,19 @@ import { MasterOrchestrator } from './orchestrator.js';
|
|
|
5
5
|
import { AgentWebSocket } from './websocket.js';
|
|
6
6
|
import { startHeartbeat, stopHeartbeat, getHeartbeatState } from './heartbeat.js';
|
|
7
7
|
import { loadHubContext, readScratchpad } from './core/hub.js';
|
|
8
|
+
import { startPreviewWorker, stopPreviewWorker } from './core/preview-worker.js';
|
|
8
9
|
// Strip ANSI escape codes for clean output
|
|
9
10
|
function stripAnsi(str) {
|
|
10
11
|
return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '');
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
|
-
* Self-update: npm install latest and restart
|
|
14
|
+
* Self-update: npm install latest and auto-restart
|
|
14
15
|
* Called from webapp banner or update command
|
|
15
16
|
*/
|
|
16
17
|
async function performSelfUpdate() {
|
|
17
18
|
console.log('[AGENT] === SELF-UPDATE STARTING ===');
|
|
18
19
|
try {
|
|
19
|
-
//
|
|
20
|
+
// Install the latest version
|
|
20
21
|
console.log('[AGENT] Running: npm install -g @siftd/connect-agent@latest');
|
|
21
22
|
execSync('npm install -g @siftd/connect-agent@latest', {
|
|
22
23
|
encoding: 'utf8',
|
|
@@ -24,13 +25,24 @@ async function performSelfUpdate() {
|
|
|
24
25
|
stdio: 'inherit', // Show output in real-time
|
|
25
26
|
timeout: 180000
|
|
26
27
|
});
|
|
27
|
-
console.log('[AGENT] Update installed.
|
|
28
|
-
//
|
|
28
|
+
console.log('[AGENT] Update installed. Auto-restarting...');
|
|
29
|
+
// Spawn a new agent process that will outlive this one
|
|
30
|
+
// Use a small delay script so the old process can exit cleanly
|
|
31
|
+
const restartScript = `sleep 2 && npx @siftd/connect-agent start`;
|
|
32
|
+
const child = spawn('/bin/bash', ['-c', restartScript], {
|
|
33
|
+
detached: true,
|
|
34
|
+
stdio: 'ignore',
|
|
35
|
+
env: process.env
|
|
36
|
+
});
|
|
37
|
+
// Unref so this process can exit while child continues
|
|
38
|
+
child.unref();
|
|
39
|
+
console.log('[AGENT] === AUTO-RESTART SCHEDULED ===');
|
|
40
|
+
// Give the response time to send, then exit
|
|
29
41
|
setTimeout(() => {
|
|
30
|
-
console.log('[AGENT]
|
|
42
|
+
console.log('[AGENT] Exiting for restart...');
|
|
31
43
|
process.exit(0);
|
|
32
|
-
},
|
|
33
|
-
return '✅ Update installed.
|
|
44
|
+
}, 1000);
|
|
45
|
+
return '✅ Update installed. Auto-restarting in 2 seconds...';
|
|
34
46
|
}
|
|
35
47
|
catch (error) {
|
|
36
48
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -235,6 +247,21 @@ export async function runAgent(pollInterval = 2000) {
|
|
|
235
247
|
console.log(`[AGENT] Scratchpad: ${scratchpad.length} chars of pending notes`);
|
|
236
248
|
}
|
|
237
249
|
}
|
|
250
|
+
// Start preview worker for fast-path asset previews (no LLM)
|
|
251
|
+
const previewWorker = startPreviewWorker({
|
|
252
|
+
verbose: true,
|
|
253
|
+
onAsset: (manifest) => {
|
|
254
|
+
console.log(`[PREVIEW] New asset: ${manifest.name} (${manifest.id})`);
|
|
255
|
+
// Send gallery state update via WebSocket
|
|
256
|
+
if (wsClient?.connected()) {
|
|
257
|
+
wsClient.sendGalleryState();
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
onPreview: (preview) => {
|
|
261
|
+
console.log(`[PREVIEW] Preview ready: ${preview.assetId}`);
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
console.log('[AGENT] Preview worker started (fast-path asset system)');
|
|
238
265
|
// Start heartbeat to maintain presence in runner registry
|
|
239
266
|
const runnerType = isCloudMode() ? 'vm' : 'local';
|
|
240
267
|
startHeartbeat({
|
|
@@ -251,6 +278,7 @@ export async function runAgent(pollInterval = 2000) {
|
|
|
251
278
|
process.on('SIGINT', async () => {
|
|
252
279
|
console.log('\n[AGENT] Shutting down...');
|
|
253
280
|
stopHeartbeat();
|
|
281
|
+
stopPreviewWorker();
|
|
254
282
|
if (wsClient) {
|
|
255
283
|
wsClient.close();
|
|
256
284
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset API - WebSocket-based asset serving
|
|
3
|
+
*
|
|
4
|
+
* Handles asset requests from the Connect web UI:
|
|
5
|
+
* - asset.list - List all assets
|
|
6
|
+
* - asset.get - Get asset bytes (streamed)
|
|
7
|
+
* - asset.preview - Get preview metadata + thumbnail
|
|
8
|
+
* - asset.group - Get assets by group
|
|
9
|
+
* - view.get - Get ViewSpec
|
|
10
|
+
*/
|
|
11
|
+
import { AssetManifest, AssetPreview, ViewSpec } from './assets.js';
|
|
12
|
+
export interface AssetRequest {
|
|
13
|
+
type: 'asset.list' | 'asset.get' | 'asset.preview' | 'asset.group' | 'view.get' | 'view.list';
|
|
14
|
+
requestId: string;
|
|
15
|
+
assetId?: string;
|
|
16
|
+
groupId?: string;
|
|
17
|
+
viewId?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AssetListResponse {
|
|
20
|
+
type: 'asset.list';
|
|
21
|
+
requestId: string;
|
|
22
|
+
assets: AssetManifest[];
|
|
23
|
+
}
|
|
24
|
+
export interface AssetGetResponse {
|
|
25
|
+
type: 'asset.get';
|
|
26
|
+
requestId: string;
|
|
27
|
+
assetId: string;
|
|
28
|
+
data: string;
|
|
29
|
+
mime: string;
|
|
30
|
+
size: number;
|
|
31
|
+
}
|
|
32
|
+
export interface AssetPreviewResponse {
|
|
33
|
+
type: 'asset.preview';
|
|
34
|
+
requestId: string;
|
|
35
|
+
assetId: string;
|
|
36
|
+
manifest: AssetManifest;
|
|
37
|
+
preview: AssetPreview | null;
|
|
38
|
+
}
|
|
39
|
+
export interface AssetGroupResponse {
|
|
40
|
+
type: 'asset.group';
|
|
41
|
+
requestId: string;
|
|
42
|
+
groupId: string;
|
|
43
|
+
assets: AssetManifest[];
|
|
44
|
+
previews: (AssetPreview | null)[];
|
|
45
|
+
}
|
|
46
|
+
export interface ViewGetResponse {
|
|
47
|
+
type: 'view.get';
|
|
48
|
+
requestId: string;
|
|
49
|
+
view: ViewSpec | null;
|
|
50
|
+
}
|
|
51
|
+
export interface ViewListResponse {
|
|
52
|
+
type: 'view.list';
|
|
53
|
+
requestId: string;
|
|
54
|
+
views: ViewSpec[];
|
|
55
|
+
}
|
|
56
|
+
export interface AssetErrorResponse {
|
|
57
|
+
type: 'asset.error';
|
|
58
|
+
requestId: string;
|
|
59
|
+
error: string;
|
|
60
|
+
}
|
|
61
|
+
export type AssetResponse = AssetListResponse | AssetGetResponse | AssetPreviewResponse | AssetGroupResponse | ViewGetResponse | ViewListResponse | AssetErrorResponse;
|
|
62
|
+
export declare function registerView(view: ViewSpec): void;
|
|
63
|
+
export declare function getView(viewId: string): ViewSpec | undefined;
|
|
64
|
+
export declare function getAllViews(): ViewSpec[];
|
|
65
|
+
/**
|
|
66
|
+
* Handle asset request from WebSocket
|
|
67
|
+
*/
|
|
68
|
+
export declare function handleAssetRequest(request: AssetRequest): Promise<AssetResponse>;
|
|
69
|
+
/**
|
|
70
|
+
* Build gallery state for WebSocket broadcast
|
|
71
|
+
* This replaces the old extractFilesFromOutput approach
|
|
72
|
+
*/
|
|
73
|
+
export interface GalleryState {
|
|
74
|
+
assets: AssetManifest[];
|
|
75
|
+
previews: Map<string, AssetPreview>;
|
|
76
|
+
groups: Map<string, AssetManifest[]>;
|
|
77
|
+
views: ViewSpec[];
|
|
78
|
+
}
|
|
79
|
+
export declare function buildGalleryState(): GalleryState;
|
|
80
|
+
/**
|
|
81
|
+
* Convert gallery state to WebSocket message format
|
|
82
|
+
* Compatible with existing gallery_workers message
|
|
83
|
+
*/
|
|
84
|
+
export declare function galleryStateToMessage(state: GalleryState): {
|
|
85
|
+
type: 'gallery_state';
|
|
86
|
+
assets: AssetManifest[];
|
|
87
|
+
previews: {
|
|
88
|
+
[key: string]: AssetPreview;
|
|
89
|
+
};
|
|
90
|
+
groups: {
|
|
91
|
+
[key: string]: string[];
|
|
92
|
+
};
|
|
93
|
+
views: ViewSpec[];
|
|
94
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset API - WebSocket-based asset serving
|
|
3
|
+
*
|
|
4
|
+
* Handles asset requests from the Connect web UI:
|
|
5
|
+
* - asset.list - List all assets
|
|
6
|
+
* - asset.get - Get asset bytes (streamed)
|
|
7
|
+
* - asset.preview - Get preview metadata + thumbnail
|
|
8
|
+
* - asset.group - Get assets by group
|
|
9
|
+
* - view.get - Get ViewSpec
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync, existsSync, statSync } from 'fs';
|
|
12
|
+
import { getAsset, getPreview, getAllAssets, getAssetsByGroup, getAssetRegistry, } from './preview-worker.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// VIEW REGISTRY
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const viewRegistry = new Map();
|
|
17
|
+
export function registerView(view) {
|
|
18
|
+
viewRegistry.set(view.id, view);
|
|
19
|
+
}
|
|
20
|
+
export function getView(viewId) {
|
|
21
|
+
return viewRegistry.get(viewId);
|
|
22
|
+
}
|
|
23
|
+
export function getAllViews() {
|
|
24
|
+
return Array.from(viewRegistry.values());
|
|
25
|
+
}
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// REQUEST HANDLER
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Handle asset request from WebSocket
|
|
31
|
+
*/
|
|
32
|
+
export async function handleAssetRequest(request) {
|
|
33
|
+
try {
|
|
34
|
+
switch (request.type) {
|
|
35
|
+
case 'asset.list':
|
|
36
|
+
return handleAssetList(request);
|
|
37
|
+
case 'asset.get':
|
|
38
|
+
return handleAssetGet(request);
|
|
39
|
+
case 'asset.preview':
|
|
40
|
+
return handleAssetPreview(request);
|
|
41
|
+
case 'asset.group':
|
|
42
|
+
return handleAssetGroup(request);
|
|
43
|
+
case 'view.get':
|
|
44
|
+
return handleViewGet(request);
|
|
45
|
+
case 'view.list':
|
|
46
|
+
return handleViewList(request);
|
|
47
|
+
default:
|
|
48
|
+
return {
|
|
49
|
+
type: 'asset.error',
|
|
50
|
+
requestId: request.requestId,
|
|
51
|
+
error: `Unknown request type: ${request.type}`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
type: 'asset.error',
|
|
58
|
+
requestId: request.requestId,
|
|
59
|
+
error: error instanceof Error ? error.message : String(error),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function handleAssetList(request) {
|
|
64
|
+
return {
|
|
65
|
+
type: 'asset.list',
|
|
66
|
+
requestId: request.requestId,
|
|
67
|
+
assets: getAllAssets(),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function handleAssetGet(request) {
|
|
71
|
+
const { assetId, requestId } = request;
|
|
72
|
+
if (!assetId) {
|
|
73
|
+
return { type: 'asset.error', requestId, error: 'Missing assetId' };
|
|
74
|
+
}
|
|
75
|
+
const manifest = getAsset(assetId);
|
|
76
|
+
if (!manifest) {
|
|
77
|
+
return { type: 'asset.error', requestId, error: `Asset not found: ${assetId}` };
|
|
78
|
+
}
|
|
79
|
+
if (!existsSync(manifest.path)) {
|
|
80
|
+
return { type: 'asset.error', requestId, error: `File not found: ${manifest.path}` };
|
|
81
|
+
}
|
|
82
|
+
// Read file and encode as base64
|
|
83
|
+
const data = readFileSync(manifest.path);
|
|
84
|
+
const stats = statSync(manifest.path);
|
|
85
|
+
return {
|
|
86
|
+
type: 'asset.get',
|
|
87
|
+
requestId,
|
|
88
|
+
assetId,
|
|
89
|
+
data: data.toString('base64'),
|
|
90
|
+
mime: manifest.mime,
|
|
91
|
+
size: stats.size,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function handleAssetPreview(request) {
|
|
95
|
+
const { assetId, requestId } = request;
|
|
96
|
+
if (!assetId) {
|
|
97
|
+
return { type: 'asset.error', requestId, error: 'Missing assetId' };
|
|
98
|
+
}
|
|
99
|
+
const manifest = getAsset(assetId);
|
|
100
|
+
if (!manifest) {
|
|
101
|
+
return { type: 'asset.error', requestId, error: `Asset not found: ${assetId}` };
|
|
102
|
+
}
|
|
103
|
+
const preview = getPreview(assetId) || null;
|
|
104
|
+
return {
|
|
105
|
+
type: 'asset.preview',
|
|
106
|
+
requestId,
|
|
107
|
+
assetId,
|
|
108
|
+
manifest,
|
|
109
|
+
preview,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function handleAssetGroup(request) {
|
|
113
|
+
const { groupId, requestId } = request;
|
|
114
|
+
if (!groupId) {
|
|
115
|
+
return { type: 'asset.error', requestId, error: 'Missing groupId' };
|
|
116
|
+
}
|
|
117
|
+
const assets = getAssetsByGroup(groupId);
|
|
118
|
+
const previews = assets.map(a => getPreview(a.id) || null);
|
|
119
|
+
return {
|
|
120
|
+
type: 'asset.group',
|
|
121
|
+
requestId,
|
|
122
|
+
groupId,
|
|
123
|
+
assets,
|
|
124
|
+
previews,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function handleViewGet(request) {
|
|
128
|
+
const { viewId, requestId } = request;
|
|
129
|
+
if (!viewId) {
|
|
130
|
+
return { type: 'asset.error', requestId, error: 'Missing viewId' };
|
|
131
|
+
}
|
|
132
|
+
const view = getView(viewId) || null;
|
|
133
|
+
return {
|
|
134
|
+
type: 'view.get',
|
|
135
|
+
requestId,
|
|
136
|
+
view,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function handleViewList(request) {
|
|
140
|
+
return {
|
|
141
|
+
type: 'view.list',
|
|
142
|
+
requestId: request.requestId,
|
|
143
|
+
views: getAllViews(),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export function buildGalleryState() {
|
|
147
|
+
const registry = getAssetRegistry();
|
|
148
|
+
const groups = new Map();
|
|
149
|
+
for (const [groupId, assetIds] of registry.byGroup) {
|
|
150
|
+
const assets = Array.from(assetIds)
|
|
151
|
+
.map(id => registry.assets.get(id))
|
|
152
|
+
.filter(Boolean);
|
|
153
|
+
groups.set(groupId, assets);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
assets: getAllAssets(),
|
|
157
|
+
previews: registry.previews,
|
|
158
|
+
groups,
|
|
159
|
+
views: getAllViews(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Convert gallery state to WebSocket message format
|
|
164
|
+
* Compatible with existing gallery_workers message
|
|
165
|
+
*/
|
|
166
|
+
export function galleryStateToMessage(state) {
|
|
167
|
+
const previews = {};
|
|
168
|
+
for (const [id, preview] of state.previews) {
|
|
169
|
+
previews[id] = preview;
|
|
170
|
+
}
|
|
171
|
+
const groups = {};
|
|
172
|
+
for (const [groupId, assets] of state.groups) {
|
|
173
|
+
groups[groupId] = assets.map(a => a.id);
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
type: 'gallery_state',
|
|
177
|
+
assets: state.assets,
|
|
178
|
+
previews,
|
|
179
|
+
groups,
|
|
180
|
+
views: state.views,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset System - Fast-path preview architecture
|
|
3
|
+
*
|
|
4
|
+
* Assets are files produced by workers with metadata for instant preview.
|
|
5
|
+
* The preview-worker generates thumbnails/metadata WITHOUT using the LLM.
|
|
6
|
+
*/
|
|
7
|
+
export interface AssetManifest {
|
|
8
|
+
/** Unique asset ID */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Absolute path to the file */
|
|
11
|
+
path: string;
|
|
12
|
+
/** Filename */
|
|
13
|
+
name: string;
|
|
14
|
+
/** MIME type */
|
|
15
|
+
mime: string;
|
|
16
|
+
/** SHA256 content hash for caching */
|
|
17
|
+
sha256: string;
|
|
18
|
+
/** File size in bytes */
|
|
19
|
+
size: number;
|
|
20
|
+
/** Creation timestamp */
|
|
21
|
+
createdAt: number;
|
|
22
|
+
/** Worker/run group ID for grouping related assets */
|
|
23
|
+
groupId?: string;
|
|
24
|
+
/** Label for the asset (old, new, diff, etc.) */
|
|
25
|
+
label?: 'old' | 'new' | 'diff' | 'output' | 'source';
|
|
26
|
+
/** Asset kind */
|
|
27
|
+
kind: 'file' | 'view';
|
|
28
|
+
/** For kind=view, the ViewSpec */
|
|
29
|
+
viewSpec?: ViewSpec;
|
|
30
|
+
}
|
|
31
|
+
export interface AssetPreview {
|
|
32
|
+
/** Reference to the asset */
|
|
33
|
+
assetId: string;
|
|
34
|
+
/** Thumbnail path (for images/PDFs) */
|
|
35
|
+
thumbnailPath?: string;
|
|
36
|
+
/** Thumbnail as base64 data URL (for inline display) */
|
|
37
|
+
thumbnailData?: string;
|
|
38
|
+
/** Extracted text snippet (first ~500 chars) */
|
|
39
|
+
textSnippet?: string;
|
|
40
|
+
/** Image dimensions */
|
|
41
|
+
dimensions?: {
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
};
|
|
45
|
+
/** PDF page count */
|
|
46
|
+
pageCount?: number;
|
|
47
|
+
/** Additional metadata */
|
|
48
|
+
metadata?: Record<string, unknown>;
|
|
49
|
+
/** When preview was generated */
|
|
50
|
+
generatedAt: number;
|
|
51
|
+
/** Cache key: sha256 + transform params */
|
|
52
|
+
cacheKey: string;
|
|
53
|
+
}
|
|
54
|
+
export interface ViewSpec {
|
|
55
|
+
/** View ID */
|
|
56
|
+
id: string;
|
|
57
|
+
/** Display title */
|
|
58
|
+
title: string;
|
|
59
|
+
/** Layout type */
|
|
60
|
+
layout: 'single' | 'grid' | 'twoColumn' | 'compare' | 'stack' | 'tabs';
|
|
61
|
+
/** Items in the view */
|
|
62
|
+
items?: ViewItem[];
|
|
63
|
+
/** For twoColumn layout */
|
|
64
|
+
left?: ViewItem[];
|
|
65
|
+
right?: ViewItem[];
|
|
66
|
+
/** For compare layout */
|
|
67
|
+
before?: ViewItem;
|
|
68
|
+
after?: ViewItem;
|
|
69
|
+
/** Optional description */
|
|
70
|
+
description?: string;
|
|
71
|
+
/** Created timestamp */
|
|
72
|
+
createdAt: number;
|
|
73
|
+
}
|
|
74
|
+
export interface ViewItem {
|
|
75
|
+
/** Item type */
|
|
76
|
+
type: 'asset' | 'markdown' | 'text' | 'html';
|
|
77
|
+
/** For type=asset, the asset ID */
|
|
78
|
+
assetId?: string;
|
|
79
|
+
/** For type=markdown/text/html, the content */
|
|
80
|
+
content?: string;
|
|
81
|
+
/** Viewer to use */
|
|
82
|
+
viewer?: 'image' | 'pdf' | 'code' | 'markdown' | 'text' | 'video' | 'audio';
|
|
83
|
+
/** Viewer params (overlays, annotations, etc.) */
|
|
84
|
+
params?: ViewerParams;
|
|
85
|
+
/** Optional label */
|
|
86
|
+
label?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface ViewerParams {
|
|
89
|
+
/** Scale bar overlay for microscopy images */
|
|
90
|
+
overlay?: 'scaleBar' | 'grid' | 'ruler';
|
|
91
|
+
/** Brightness adjustment (-100 to 100) */
|
|
92
|
+
brightness?: number;
|
|
93
|
+
/** Contrast adjustment (-100 to 100) */
|
|
94
|
+
contrast?: number;
|
|
95
|
+
/** Crop region */
|
|
96
|
+
crop?: {
|
|
97
|
+
x: number;
|
|
98
|
+
y: number;
|
|
99
|
+
width: number;
|
|
100
|
+
height: number;
|
|
101
|
+
};
|
|
102
|
+
/** Zoom level */
|
|
103
|
+
zoom?: number;
|
|
104
|
+
/** Highlight lines (for code) */
|
|
105
|
+
highlightLines?: number[];
|
|
106
|
+
/** Annotations */
|
|
107
|
+
annotations?: Annotation[];
|
|
108
|
+
}
|
|
109
|
+
export interface Annotation {
|
|
110
|
+
type: 'box' | 'circle' | 'arrow' | 'text';
|
|
111
|
+
x: number;
|
|
112
|
+
y: number;
|
|
113
|
+
width?: number;
|
|
114
|
+
height?: number;
|
|
115
|
+
label?: string;
|
|
116
|
+
color?: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Generate SHA256 hash of file contents
|
|
120
|
+
*/
|
|
121
|
+
export declare function hashFile(filePath: string): string;
|
|
122
|
+
/**
|
|
123
|
+
* Get MIME type from file extension
|
|
124
|
+
*/
|
|
125
|
+
export declare function getMimeType(filePath: string): string;
|
|
126
|
+
/**
|
|
127
|
+
* Generate unique asset ID
|
|
128
|
+
*/
|
|
129
|
+
export declare function generateAssetId(): string;
|
|
130
|
+
/**
|
|
131
|
+
* Create asset manifest for a file
|
|
132
|
+
*/
|
|
133
|
+
export declare function createAssetManifest(filePath: string, options?: {
|
|
134
|
+
groupId?: string;
|
|
135
|
+
label?: AssetManifest['label'];
|
|
136
|
+
}): AssetManifest;
|
|
137
|
+
/**
|
|
138
|
+
* Write asset manifest alongside the file
|
|
139
|
+
*/
|
|
140
|
+
export declare function writeAssetManifest(manifest: AssetManifest): void;
|
|
141
|
+
/**
|
|
142
|
+
* Read asset manifest for a file
|
|
143
|
+
*/
|
|
144
|
+
export declare function readAssetManifest(filePath: string): AssetManifest | null;
|
|
145
|
+
/**
|
|
146
|
+
* Get preview cache directory
|
|
147
|
+
*/
|
|
148
|
+
export declare function getPreviewCacheDir(): string;
|
|
149
|
+
/**
|
|
150
|
+
* Generate cache key for preview
|
|
151
|
+
*/
|
|
152
|
+
export declare function getPreviewCacheKey(sha256: string, params?: ViewerParams): string;
|
|
153
|
+
/**
|
|
154
|
+
* Check if preview exists in cache
|
|
155
|
+
*/
|
|
156
|
+
export declare function getPreviewFromCache(cacheKey: string): AssetPreview | null;
|
|
157
|
+
/**
|
|
158
|
+
* Save preview to cache
|
|
159
|
+
*/
|
|
160
|
+
export declare function savePreviewToCache(preview: AssetPreview): void;
|
|
161
|
+
/**
|
|
162
|
+
* Create a ViewSpec for comparing two assets
|
|
163
|
+
*/
|
|
164
|
+
export declare function createCompareView(beforeAssetId: string, afterAssetId: string, title?: string): ViewSpec;
|
|
165
|
+
/**
|
|
166
|
+
* Create a ViewSpec for a grid of assets
|
|
167
|
+
*/
|
|
168
|
+
export declare function createGridView(assetIds: string[], title?: string): ViewSpec;
|
|
169
|
+
/**
|
|
170
|
+
* Create a ViewSpec for a report with markdown and assets
|
|
171
|
+
*/
|
|
172
|
+
export declare function createReportView(title: string, sections: Array<{
|
|
173
|
+
markdown?: string;
|
|
174
|
+
assetId?: string;
|
|
175
|
+
label?: string;
|
|
176
|
+
}>): ViewSpec;
|