@agent-inspect/studio 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Database from 'better-sqlite3';
2
- import { Server } from 'node:http';
2
+ import { Server, IncomingMessage, ServerResponse } from 'node:http';
3
3
 
4
4
  type StudioAuthMode = "none" | "basic";
5
5
 
@@ -13,6 +13,12 @@ interface StudioProjectRow {
13
13
  traceCount: number;
14
14
  importedAt: string;
15
15
  }
16
+ type IngestFileKind = "ci" | "bundle";
17
+ declare function resolveStudioDbPath(options: {
18
+ dbPath?: string;
19
+ cwd?: string;
20
+ }): string;
21
+ declare function openStudioDb(dbPath: string): Database.Database;
16
22
 
17
23
  declare const STUDIO_REGISTRY_SCHEMA_VERSION: "1.0";
18
24
  interface StudioRegistryProject {
@@ -24,18 +30,42 @@ interface StudioRegistryProject {
24
30
  interface StudioRegistryImport {
25
31
  ciArtifactsDir?: string;
26
32
  bundlesDir?: string;
33
+ fileDropDir?: string;
34
+ enabled?: boolean;
35
+ }
36
+ interface StudioRegistryGitHubIngest {
37
+ enabled?: boolean;
38
+ tokenEnv?: string;
39
+ }
40
+ interface StudioRegistryHttpIngest {
41
+ enabled?: boolean;
42
+ path?: string;
43
+ tokenEnv?: string;
44
+ maxBytes?: number;
45
+ }
46
+ interface StudioRegistryBundleUploadIngest {
47
+ enabled?: boolean;
48
+ maxBytes?: number;
49
+ }
50
+ interface StudioRegistryIngest {
51
+ github?: StudioRegistryGitHubIngest;
52
+ http?: StudioRegistryHttpIngest;
53
+ bundleUpload?: StudioRegistryBundleUploadIngest;
27
54
  }
28
55
  interface StudioRegistry {
29
56
  schemaVersion: typeof STUDIO_REGISTRY_SCHEMA_VERSION;
30
57
  name: string;
31
58
  projects: StudioRegistryProject[];
32
59
  import?: StudioRegistryImport;
60
+ ingest?: StudioRegistryIngest;
33
61
  }
34
62
  interface StudioRegistryParseResult {
35
63
  ok: boolean;
36
64
  registry?: StudioRegistry;
37
65
  errors: string[];
66
+ warnings: string[];
38
67
  }
68
+
39
69
  declare function parseStudioRegistry(input: unknown): StudioRegistryParseResult;
40
70
  declare function readStudioRegistryFile(filePath: string): Promise<StudioRegistryParseResult & {
41
71
  path: string;
@@ -50,12 +80,59 @@ interface StudioImportResult {
50
80
  warnings: string[];
51
81
  }
52
82
 
83
+ interface FileDropImportOptions {
84
+ db: Database.Database;
85
+ registryPath: string;
86
+ registry: StudioRegistry;
87
+ /** Explicit opt-in required — ingest is disabled by default. */
88
+ enabled: boolean;
89
+ /** Override drop directory (CLI `--dir`). */
90
+ dropDir?: string;
91
+ /** Move successfully imported files into `dropDir/.imported/` instead of leaving copies. */
92
+ archiveAfterImport?: boolean;
93
+ }
94
+ interface FileDropImportedFile {
95
+ sourceKey: string;
96
+ sourceName: string;
97
+ destPath: string;
98
+ kind: IngestFileKind;
99
+ contentHash: string;
100
+ archived: boolean;
101
+ }
102
+ interface FileDropImportResult {
103
+ skipped: boolean;
104
+ reason?: string;
105
+ scanned: number;
106
+ imported: number;
107
+ skippedFiles: number;
108
+ errors: string[];
109
+ warnings: string[];
110
+ files: FileDropImportedFile[];
111
+ }
112
+ declare function importFileDrop(options: FileDropImportOptions): Promise<FileDropImportResult>;
113
+ declare function importFileDropFromRegistry(options: {
114
+ db: Database.Database;
115
+ registryPath: string;
116
+ registry: StudioRegistry;
117
+ enabled: boolean;
118
+ dropDir?: string;
119
+ archiveAfterImport?: boolean;
120
+ }): Promise<FileDropImportResult>;
121
+ declare function runStudioFileDropImport(options: {
122
+ workspacePath?: string;
123
+ dbPath?: string;
124
+ cwd?: string;
125
+ dropDir?: string;
126
+ archiveAfterImport?: boolean;
127
+ }): Promise<FileDropImportResult>;
128
+
53
129
  interface StudioContext {
54
130
  db: Database.Database;
55
131
  dbPath: string;
56
132
  registryPath: string;
57
133
  registry: StudioRegistry;
58
134
  importResult: StudioImportResult;
135
+ fileDropResult?: FileDropImportResult;
59
136
  projects: ImportedStudioProject[];
60
137
  }
61
138
  declare function createStudioContext(options?: StudioServerOptions): Promise<StudioContext>;
@@ -79,6 +156,14 @@ interface StudioServerOptions {
79
156
  passwordEnv?: string;
80
157
  /** Test hook: inject a preloaded context instead of importing on startup. */
81
158
  context?: StudioContext;
159
+ /** Run file-drop ingest once on startup (requires explicit opt-in). */
160
+ ingestFileDrop?: boolean;
161
+ /** Move imported drop files into `.imported/` after successful copy. */
162
+ archiveFileDrop?: boolean;
163
+ /** Enable HTTP ingest routes (requires explicit opt-in + ingest token env). */
164
+ ingestHttp?: boolean;
165
+ /** Env var name for HTTP ingest token (default STUDIO_INGEST_TOKEN). */
166
+ ingestTokenEnv?: string;
82
167
  }
83
168
  interface StudioServerInfo {
84
169
  host: string;
@@ -96,4 +181,100 @@ declare function startStudioServer(options?: StudioServerOptions): Promise<Studi
96
181
 
97
182
  declare const studioIndexHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>AgentInspect Studio</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }\n h1 { font-size: 1.25rem; }\n .muted { color: #666; }\n </style>\n</head>\n<body>\n <h1>AgentInspect Studio</h1>\n <p class=\"muted\">Self-hosted, read-only. JSONL and workspace manifests remain canonical.</p>\n <p id=\"status\">Loading health\u2026</p>\n <script>\n fetch(\"/api/health\")\n .then((res) => res.json())\n .then((data) => {\n document.getElementById(\"status\").textContent =\n data.ok ? \"Studio is running (read-only).\" : \"Studio health check failed.\";\n })\n .catch(() => {\n document.getElementById(\"status\").textContent = \"Studio health check failed.\";\n });\n </script>\n</body>\n</html>";
98
183
 
99
- export { type StudioRegistry, type StudioRegistryProject, type StudioServerInfo, type StudioServerOptions, createStudioContext, createStudioServer, parseStudioRegistry, readStudioRegistryFile, startStudioServer, studioIndexHtml, summarizeProjects };
184
+ type StudioFetch = typeof fetch;
185
+ interface GitHubArtifactImportOptions {
186
+ db: Database.Database;
187
+ registryPath: string;
188
+ registry: StudioRegistry;
189
+ repo: string;
190
+ runId: string;
191
+ artifactName: string;
192
+ /** Explicit opt-in required — disabled by default. */
193
+ enabled: boolean;
194
+ tokenEnv?: string;
195
+ fetchImpl?: StudioFetch;
196
+ }
197
+ interface GitHubArtifactImportResult {
198
+ skipped: boolean;
199
+ reason?: string;
200
+ imported: boolean;
201
+ destPath?: string;
202
+ sourceKey?: string;
203
+ contentHash?: string;
204
+ registryImportWarnings: string[];
205
+ errors: string[];
206
+ }
207
+ declare function downloadGitHubArtifactArchive(options: {
208
+ repo: string;
209
+ runId: string;
210
+ artifactName: string;
211
+ token: string;
212
+ fetchImpl?: StudioFetch;
213
+ }): Promise<Buffer>;
214
+ declare function importGitHubArtifact(options: GitHubArtifactImportOptions): Promise<GitHubArtifactImportResult>;
215
+ declare function runStudioGitHubArtifactImport(options: {
216
+ workspacePath?: string;
217
+ dbPath?: string;
218
+ cwd?: string;
219
+ repo: string;
220
+ runId: string;
221
+ artifact: string;
222
+ tokenEnv?: string;
223
+ fetchImpl?: StudioFetch;
224
+ }): Promise<GitHubArtifactImportResult>;
225
+
226
+ interface BundleUploadImportOptions {
227
+ db: Database.Database;
228
+ registryPath: string;
229
+ registry: StudioRegistry;
230
+ bundlePath: string;
231
+ enabled: boolean;
232
+ }
233
+ interface BundleUploadImportResult {
234
+ skipped: boolean;
235
+ reason?: string;
236
+ imported: boolean;
237
+ destPath?: string;
238
+ sourceKey?: string;
239
+ errors: string[];
240
+ registryImportWarnings: string[];
241
+ }
242
+ declare function validateBundleDirectory(bundleDir: string): Promise<string[]>;
243
+ declare function importBundleUpload(options: BundleUploadImportOptions): Promise<BundleUploadImportResult>;
244
+ declare function runStudioBundleUploadImport(options: {
245
+ workspacePath?: string;
246
+ dbPath?: string;
247
+ cwd?: string;
248
+ bundlePath: string;
249
+ }): Promise<BundleUploadImportResult>;
250
+
251
+ declare const HTTP_INGEST_BUNDLE_PATH = "/api/ingest/bundle";
252
+ declare const HTTP_INGEST_ARTIFACT_PATH = "/api/ingest/artifact";
253
+ interface HttpIngestConfig {
254
+ enabled: boolean;
255
+ basePath: string;
256
+ tokenEnv: string;
257
+ maxBytes: number;
258
+ }
259
+ declare function resolveHttpIngestConfig(options: StudioServerOptions, registryEnabled?: boolean): HttpIngestConfig;
260
+ declare function isHttpIngestRoute(pathname: string, config: HttpIngestConfig): boolean;
261
+ declare function handleHttpIngestRequest(req: IncomingMessage, res: ServerResponse, ctx: StudioContext, options: StudioServerOptions, pathname: string): Promise<boolean>;
262
+
263
+ declare function resolveIngestTokenEnv(options: {
264
+ tokenEnv?: string;
265
+ registryTokenEnv?: string;
266
+ }): string;
267
+ declare function resolveIngestToken(envName: string): string | undefined;
268
+ declare function extractIngestTokenFromRequest(headers: {
269
+ authorization?: string | string[] | undefined;
270
+ "x-agentinspect-token"?: string | string[] | undefined;
271
+ "x-agent-inspect-token"?: string | string[] | undefined;
272
+ }): string | undefined;
273
+ declare function isIngestTokenValid(provided: string | undefined, expected: string | undefined): boolean;
274
+
275
+ declare function resolveStudioRegistryPath(options: {
276
+ workspacePath?: string;
277
+ cwd?: string;
278
+ }): Promise<string>;
279
+
280
+ export { type BundleUploadImportResult, type FileDropImportOptions, type FileDropImportResult, type GitHubArtifactImportOptions, type GitHubArtifactImportResult, HTTP_INGEST_ARTIFACT_PATH, HTTP_INGEST_BUNDLE_PATH, type StudioFetch, type StudioRegistry, type StudioRegistryProject, type StudioServerInfo, type StudioServerOptions, createStudioContext, createStudioServer, downloadGitHubArtifactArchive, extractIngestTokenFromRequest, handleHttpIngestRequest, importBundleUpload, importFileDrop, importFileDropFromRegistry, importGitHubArtifact, isHttpIngestRoute, isIngestTokenValid, openStudioDb, parseStudioRegistry, readStudioRegistryFile, resolveHttpIngestConfig, resolveIngestToken, resolveIngestTokenEnv, resolveStudioDbPath, resolveStudioRegistryPath, runStudioBundleUploadImport, runStudioFileDropImport, runStudioGitHubArtifactImport, startStudioServer, studioIndexHtml, summarizeProjects, validateBundleDirectory };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Database from 'better-sqlite3';
2
- import { Server } from 'node:http';
2
+ import { Server, IncomingMessage, ServerResponse } from 'node:http';
3
3
 
4
4
  type StudioAuthMode = "none" | "basic";
5
5
 
@@ -13,6 +13,12 @@ interface StudioProjectRow {
13
13
  traceCount: number;
14
14
  importedAt: string;
15
15
  }
16
+ type IngestFileKind = "ci" | "bundle";
17
+ declare function resolveStudioDbPath(options: {
18
+ dbPath?: string;
19
+ cwd?: string;
20
+ }): string;
21
+ declare function openStudioDb(dbPath: string): Database.Database;
16
22
 
17
23
  declare const STUDIO_REGISTRY_SCHEMA_VERSION: "1.0";
18
24
  interface StudioRegistryProject {
@@ -24,18 +30,42 @@ interface StudioRegistryProject {
24
30
  interface StudioRegistryImport {
25
31
  ciArtifactsDir?: string;
26
32
  bundlesDir?: string;
33
+ fileDropDir?: string;
34
+ enabled?: boolean;
35
+ }
36
+ interface StudioRegistryGitHubIngest {
37
+ enabled?: boolean;
38
+ tokenEnv?: string;
39
+ }
40
+ interface StudioRegistryHttpIngest {
41
+ enabled?: boolean;
42
+ path?: string;
43
+ tokenEnv?: string;
44
+ maxBytes?: number;
45
+ }
46
+ interface StudioRegistryBundleUploadIngest {
47
+ enabled?: boolean;
48
+ maxBytes?: number;
49
+ }
50
+ interface StudioRegistryIngest {
51
+ github?: StudioRegistryGitHubIngest;
52
+ http?: StudioRegistryHttpIngest;
53
+ bundleUpload?: StudioRegistryBundleUploadIngest;
27
54
  }
28
55
  interface StudioRegistry {
29
56
  schemaVersion: typeof STUDIO_REGISTRY_SCHEMA_VERSION;
30
57
  name: string;
31
58
  projects: StudioRegistryProject[];
32
59
  import?: StudioRegistryImport;
60
+ ingest?: StudioRegistryIngest;
33
61
  }
34
62
  interface StudioRegistryParseResult {
35
63
  ok: boolean;
36
64
  registry?: StudioRegistry;
37
65
  errors: string[];
66
+ warnings: string[];
38
67
  }
68
+
39
69
  declare function parseStudioRegistry(input: unknown): StudioRegistryParseResult;
40
70
  declare function readStudioRegistryFile(filePath: string): Promise<StudioRegistryParseResult & {
41
71
  path: string;
@@ -50,12 +80,59 @@ interface StudioImportResult {
50
80
  warnings: string[];
51
81
  }
52
82
 
83
+ interface FileDropImportOptions {
84
+ db: Database.Database;
85
+ registryPath: string;
86
+ registry: StudioRegistry;
87
+ /** Explicit opt-in required — ingest is disabled by default. */
88
+ enabled: boolean;
89
+ /** Override drop directory (CLI `--dir`). */
90
+ dropDir?: string;
91
+ /** Move successfully imported files into `dropDir/.imported/` instead of leaving copies. */
92
+ archiveAfterImport?: boolean;
93
+ }
94
+ interface FileDropImportedFile {
95
+ sourceKey: string;
96
+ sourceName: string;
97
+ destPath: string;
98
+ kind: IngestFileKind;
99
+ contentHash: string;
100
+ archived: boolean;
101
+ }
102
+ interface FileDropImportResult {
103
+ skipped: boolean;
104
+ reason?: string;
105
+ scanned: number;
106
+ imported: number;
107
+ skippedFiles: number;
108
+ errors: string[];
109
+ warnings: string[];
110
+ files: FileDropImportedFile[];
111
+ }
112
+ declare function importFileDrop(options: FileDropImportOptions): Promise<FileDropImportResult>;
113
+ declare function importFileDropFromRegistry(options: {
114
+ db: Database.Database;
115
+ registryPath: string;
116
+ registry: StudioRegistry;
117
+ enabled: boolean;
118
+ dropDir?: string;
119
+ archiveAfterImport?: boolean;
120
+ }): Promise<FileDropImportResult>;
121
+ declare function runStudioFileDropImport(options: {
122
+ workspacePath?: string;
123
+ dbPath?: string;
124
+ cwd?: string;
125
+ dropDir?: string;
126
+ archiveAfterImport?: boolean;
127
+ }): Promise<FileDropImportResult>;
128
+
53
129
  interface StudioContext {
54
130
  db: Database.Database;
55
131
  dbPath: string;
56
132
  registryPath: string;
57
133
  registry: StudioRegistry;
58
134
  importResult: StudioImportResult;
135
+ fileDropResult?: FileDropImportResult;
59
136
  projects: ImportedStudioProject[];
60
137
  }
61
138
  declare function createStudioContext(options?: StudioServerOptions): Promise<StudioContext>;
@@ -79,6 +156,14 @@ interface StudioServerOptions {
79
156
  passwordEnv?: string;
80
157
  /** Test hook: inject a preloaded context instead of importing on startup. */
81
158
  context?: StudioContext;
159
+ /** Run file-drop ingest once on startup (requires explicit opt-in). */
160
+ ingestFileDrop?: boolean;
161
+ /** Move imported drop files into `.imported/` after successful copy. */
162
+ archiveFileDrop?: boolean;
163
+ /** Enable HTTP ingest routes (requires explicit opt-in + ingest token env). */
164
+ ingestHttp?: boolean;
165
+ /** Env var name for HTTP ingest token (default STUDIO_INGEST_TOKEN). */
166
+ ingestTokenEnv?: string;
82
167
  }
83
168
  interface StudioServerInfo {
84
169
  host: string;
@@ -96,4 +181,100 @@ declare function startStudioServer(options?: StudioServerOptions): Promise<Studi
96
181
 
97
182
  declare const studioIndexHtml = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <title>AgentInspect Studio</title>\n <style>\n body { font-family: system-ui, sans-serif; margin: 1.5rem; line-height: 1.4; }\n h1 { font-size: 1.25rem; }\n .muted { color: #666; }\n </style>\n</head>\n<body>\n <h1>AgentInspect Studio</h1>\n <p class=\"muted\">Self-hosted, read-only. JSONL and workspace manifests remain canonical.</p>\n <p id=\"status\">Loading health\u2026</p>\n <script>\n fetch(\"/api/health\")\n .then((res) => res.json())\n .then((data) => {\n document.getElementById(\"status\").textContent =\n data.ok ? \"Studio is running (read-only).\" : \"Studio health check failed.\";\n })\n .catch(() => {\n document.getElementById(\"status\").textContent = \"Studio health check failed.\";\n });\n </script>\n</body>\n</html>";
98
183
 
99
- export { type StudioRegistry, type StudioRegistryProject, type StudioServerInfo, type StudioServerOptions, createStudioContext, createStudioServer, parseStudioRegistry, readStudioRegistryFile, startStudioServer, studioIndexHtml, summarizeProjects };
184
+ type StudioFetch = typeof fetch;
185
+ interface GitHubArtifactImportOptions {
186
+ db: Database.Database;
187
+ registryPath: string;
188
+ registry: StudioRegistry;
189
+ repo: string;
190
+ runId: string;
191
+ artifactName: string;
192
+ /** Explicit opt-in required — disabled by default. */
193
+ enabled: boolean;
194
+ tokenEnv?: string;
195
+ fetchImpl?: StudioFetch;
196
+ }
197
+ interface GitHubArtifactImportResult {
198
+ skipped: boolean;
199
+ reason?: string;
200
+ imported: boolean;
201
+ destPath?: string;
202
+ sourceKey?: string;
203
+ contentHash?: string;
204
+ registryImportWarnings: string[];
205
+ errors: string[];
206
+ }
207
+ declare function downloadGitHubArtifactArchive(options: {
208
+ repo: string;
209
+ runId: string;
210
+ artifactName: string;
211
+ token: string;
212
+ fetchImpl?: StudioFetch;
213
+ }): Promise<Buffer>;
214
+ declare function importGitHubArtifact(options: GitHubArtifactImportOptions): Promise<GitHubArtifactImportResult>;
215
+ declare function runStudioGitHubArtifactImport(options: {
216
+ workspacePath?: string;
217
+ dbPath?: string;
218
+ cwd?: string;
219
+ repo: string;
220
+ runId: string;
221
+ artifact: string;
222
+ tokenEnv?: string;
223
+ fetchImpl?: StudioFetch;
224
+ }): Promise<GitHubArtifactImportResult>;
225
+
226
+ interface BundleUploadImportOptions {
227
+ db: Database.Database;
228
+ registryPath: string;
229
+ registry: StudioRegistry;
230
+ bundlePath: string;
231
+ enabled: boolean;
232
+ }
233
+ interface BundleUploadImportResult {
234
+ skipped: boolean;
235
+ reason?: string;
236
+ imported: boolean;
237
+ destPath?: string;
238
+ sourceKey?: string;
239
+ errors: string[];
240
+ registryImportWarnings: string[];
241
+ }
242
+ declare function validateBundleDirectory(bundleDir: string): Promise<string[]>;
243
+ declare function importBundleUpload(options: BundleUploadImportOptions): Promise<BundleUploadImportResult>;
244
+ declare function runStudioBundleUploadImport(options: {
245
+ workspacePath?: string;
246
+ dbPath?: string;
247
+ cwd?: string;
248
+ bundlePath: string;
249
+ }): Promise<BundleUploadImportResult>;
250
+
251
+ declare const HTTP_INGEST_BUNDLE_PATH = "/api/ingest/bundle";
252
+ declare const HTTP_INGEST_ARTIFACT_PATH = "/api/ingest/artifact";
253
+ interface HttpIngestConfig {
254
+ enabled: boolean;
255
+ basePath: string;
256
+ tokenEnv: string;
257
+ maxBytes: number;
258
+ }
259
+ declare function resolveHttpIngestConfig(options: StudioServerOptions, registryEnabled?: boolean): HttpIngestConfig;
260
+ declare function isHttpIngestRoute(pathname: string, config: HttpIngestConfig): boolean;
261
+ declare function handleHttpIngestRequest(req: IncomingMessage, res: ServerResponse, ctx: StudioContext, options: StudioServerOptions, pathname: string): Promise<boolean>;
262
+
263
+ declare function resolveIngestTokenEnv(options: {
264
+ tokenEnv?: string;
265
+ registryTokenEnv?: string;
266
+ }): string;
267
+ declare function resolveIngestToken(envName: string): string | undefined;
268
+ declare function extractIngestTokenFromRequest(headers: {
269
+ authorization?: string | string[] | undefined;
270
+ "x-agentinspect-token"?: string | string[] | undefined;
271
+ "x-agent-inspect-token"?: string | string[] | undefined;
272
+ }): string | undefined;
273
+ declare function isIngestTokenValid(provided: string | undefined, expected: string | undefined): boolean;
274
+
275
+ declare function resolveStudioRegistryPath(options: {
276
+ workspacePath?: string;
277
+ cwd?: string;
278
+ }): Promise<string>;
279
+
280
+ export { type BundleUploadImportResult, type FileDropImportOptions, type FileDropImportResult, type GitHubArtifactImportOptions, type GitHubArtifactImportResult, HTTP_INGEST_ARTIFACT_PATH, HTTP_INGEST_BUNDLE_PATH, type StudioFetch, type StudioRegistry, type StudioRegistryProject, type StudioServerInfo, type StudioServerOptions, createStudioContext, createStudioServer, downloadGitHubArtifactArchive, extractIngestTokenFromRequest, handleHttpIngestRequest, importBundleUpload, importFileDrop, importFileDropFromRegistry, importGitHubArtifact, isHttpIngestRoute, isIngestTokenValid, openStudioDb, parseStudioRegistry, readStudioRegistryFile, resolveHttpIngestConfig, resolveIngestToken, resolveIngestTokenEnv, resolveStudioDbPath, resolveStudioRegistryPath, runStudioBundleUploadImport, runStudioFileDropImport, runStudioGitHubArtifactImport, startStudioServer, studioIndexHtml, summarizeProjects, validateBundleDirectory };