@bodhi-ventures/aiocs 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,31 +2,51 @@
2
2
  import {
3
3
  AIOCS_ERROR_CODES,
4
4
  AiocsError,
5
+ answerWorkspace,
5
6
  backfillEmbeddings,
7
+ bindWorkspaceSources,
6
8
  clearEmbeddings,
9
+ compileWorkspaceArtifacts,
10
+ createWorkspace,
7
11
  diffSnapshotsForSource,
8
12
  exportCatalogBackup,
9
13
  fetchSources,
14
+ generateWorkspaceArtifactOutput,
10
15
  getDoctorReport,
11
16
  getEmbeddingStatus,
17
+ getWorkspaceStatus,
12
18
  importCatalogBackup,
19
+ ingestWorkspaceRawInput,
13
20
  initManagedSources,
14
21
  linkProjectSources,
22
+ lintWorkspaceArtifacts,
15
23
  listSnapshotsForSource,
16
24
  listSources,
25
+ listWorkspaceArtifacts,
26
+ listWorkspaceRawInputsRecord,
27
+ listWorkspaceRecords,
17
28
  packageDescription,
18
29
  packageName,
19
30
  packageVersion,
20
31
  refreshDueSources,
32
+ removeWorkspaceRawInput,
21
33
  runEmbeddingWorker,
34
+ runQueuedWorkspaceCompiles,
22
35
  runSourceCanaries,
23
36
  searchCatalog,
37
+ searchWorkspaceCatalog,
38
+ searchWorkspaceRawInputCatalog,
24
39
  showChunk,
40
+ showWorkspaceArtifact,
41
+ showWorkspaceRawInput,
42
+ syncWorkspaceToObsidianVault,
25
43
  toAiocsError,
44
+ unbindWorkspaceSources,
26
45
  unlinkProjectSources,
46
+ updateWorkspaceSettings,
27
47
  upsertSourceFromSpecFile,
28
48
  verifyCoverage
29
- } from "./chunk-CZ6C4YUX.js";
49
+ } from "./chunk-GX6CZOO7.js";
30
50
 
31
51
  // src/mcp-server.ts
32
52
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -50,6 +70,7 @@ var doctorReportSchema = z.object({
50
70
  });
51
71
  var sourceSchema = z.object({
52
72
  id: z.string(),
73
+ kind: z.enum(["web", "git"]),
53
74
  label: z.string(),
54
75
  specPath: z.string().nullable(),
55
76
  nextDueAt: z.string(),
@@ -77,6 +98,9 @@ var searchResultSchema = z.object({
77
98
  pageTitle: z.string(),
78
99
  sectionTitle: z.string(),
79
100
  markdown: z.string(),
101
+ pageKind: z.enum(["document", "file"]),
102
+ filePath: z.string().nullable(),
103
+ language: z.string().nullable(),
80
104
  score: z.number().optional(),
81
105
  signals: z.array(z.enum(["lexical", "vector"])).optional()
82
106
  });
@@ -123,7 +147,8 @@ var canaryResultSchema = z.object({
123
147
  failCount: z.number().int().nonnegative()
124
148
  }),
125
149
  checks: z.array(z.object({
126
- url: z.string(),
150
+ url: z.string().optional(),
151
+ path: z.string().optional(),
127
152
  status: z.enum(["pass", "fail"]),
128
153
  title: z.string().optional(),
129
154
  markdownLength: z.number().int().nonnegative().optional(),
@@ -142,16 +167,25 @@ var snapshotDiffSchema = z.object({
142
167
  }),
143
168
  addedPages: z.array(z.object({
144
169
  url: z.string(),
145
- title: z.string()
170
+ title: z.string(),
171
+ pageKind: z.enum(["document", "file"]),
172
+ filePath: z.string().nullable(),
173
+ language: z.string().nullable()
146
174
  })),
147
175
  removedPages: z.array(z.object({
148
176
  url: z.string(),
149
- title: z.string()
177
+ title: z.string(),
178
+ pageKind: z.enum(["document", "file"]),
179
+ filePath: z.string().nullable(),
180
+ language: z.string().nullable()
150
181
  })),
151
182
  changedPages: z.array(z.object({
152
183
  url: z.string(),
153
184
  beforeTitle: z.string(),
154
185
  afterTitle: z.string(),
186
+ pageKind: z.enum(["document", "file"]),
187
+ filePath: z.string().nullable(),
188
+ language: z.string().nullable(),
155
189
  lineSummary: z.object({
156
190
  addedLineCount: z.number().int().nonnegative(),
157
191
  removedLineCount: z.number().int().nonnegative()
@@ -185,6 +219,204 @@ var embeddingStatusSchema = z.object({
185
219
  coverageRatio: z.number()
186
220
  }))
187
221
  });
222
+ var workspaceSchema = z.object({
223
+ id: z.string(),
224
+ label: z.string(),
225
+ purpose: z.string().nullable(),
226
+ autoCompileEnabled: z.boolean(),
227
+ compilerProfile: z.object({
228
+ provider: z.literal("lmstudio"),
229
+ model: z.string(),
230
+ temperature: z.number(),
231
+ topP: z.number(),
232
+ maxInputChars: z.number().int().positive(),
233
+ maxOutputTokens: z.number().int().positive(),
234
+ concurrency: z.number().int().positive()
235
+ }),
236
+ defaultOutputFormats: z.array(z.enum(["report", "slides", "summary"])),
237
+ bindingCount: z.number().int().nonnegative(),
238
+ artifactCount: z.number().int().nonnegative(),
239
+ lastCompileRunId: z.string().nullable(),
240
+ lastCompileStatus: z.enum(["success", "failed"]).nullable(),
241
+ lastCompiledAt: z.string().nullable(),
242
+ createdAt: z.string(),
243
+ updatedAt: z.string()
244
+ });
245
+ var workspaceCompileJobSchema = z.object({
246
+ workspaceId: z.string(),
247
+ status: z.enum(["pending", "running", "succeeded", "failed"]),
248
+ requestedSourceIds: z.array(z.string()),
249
+ requestedRawInputIds: z.array(z.string()),
250
+ requestedFingerprint: z.string().nullable(),
251
+ attemptCount: z.number().int().nonnegative(),
252
+ createdAt: z.string(),
253
+ updatedAt: z.string(),
254
+ claimedAt: z.string().nullable(),
255
+ completedAt: z.string().nullable(),
256
+ errorMessage: z.string().nullable()
257
+ });
258
+ var workspaceRawInputSchema = z.object({
259
+ id: z.string(),
260
+ workspaceId: z.string(),
261
+ kind: z.enum(["markdown-dir", "pdf", "image", "csv", "json", "jsonl"]),
262
+ label: z.string(),
263
+ sourcePath: z.string(),
264
+ storagePath: z.string(),
265
+ extractedTextPath: z.string().nullable(),
266
+ contentHash: z.string(),
267
+ metadata: z.record(z.string(), z.unknown()),
268
+ chunkCount: z.number().int().nonnegative(),
269
+ createdAt: z.string(),
270
+ updatedAt: z.string()
271
+ });
272
+ var workspaceSyncTargetSchema = z.object({
273
+ workspaceId: z.string(),
274
+ kind: z.enum(["obsidian"]),
275
+ targetPath: z.string(),
276
+ exportSubdir: z.string(),
277
+ lastSyncedAt: z.string().nullable(),
278
+ lastSyncStatus: z.enum(["success", "failed"]).nullable(),
279
+ lastErrorMessage: z.string().nullable(),
280
+ createdAt: z.string(),
281
+ updatedAt: z.string()
282
+ });
283
+ var workspaceQuestionRunSchema = z.object({
284
+ id: z.string(),
285
+ workspaceId: z.string(),
286
+ question: z.string(),
287
+ format: z.enum(["report", "slides", "summary", "note"]),
288
+ artifactPath: z.string(),
289
+ status: z.enum(["success", "failed"]),
290
+ errorMessage: z.string().nullable(),
291
+ createdAt: z.string(),
292
+ completedAt: z.string()
293
+ });
294
+ var workspaceArtifactRawInputProvenanceSchema = z.object({
295
+ workspaceId: z.string(),
296
+ path: z.string(),
297
+ rawInputId: z.string(),
298
+ chunkIds: z.array(z.number().int().nonnegative())
299
+ });
300
+ var workspaceArtifactLinkSchema = z.object({
301
+ workspaceId: z.string(),
302
+ fromPath: z.string(),
303
+ toPath: z.string(),
304
+ relationKind: z.enum(["explicit_link", "derived_from", "mentions", "related_to", "expands", "index_entry", "summary_of", "concept_of", "output_depends_on"]),
305
+ anchorText: z.string().nullable(),
306
+ source: z.enum(["compiler", "deterministic"]),
307
+ broken: z.boolean(),
308
+ createdAt: z.string(),
309
+ updatedAt: z.string()
310
+ });
311
+ var workspaceHealthSchema = z.object({
312
+ status: z.enum(["healthy", "degraded"]),
313
+ staleArtifactCount: z.number().int().nonnegative(),
314
+ pendingCompileJobs: z.number().int().nonnegative(),
315
+ failedCompileJobs: z.number().int().nonnegative(),
316
+ brokenLinkCount: z.number().int().nonnegative(),
317
+ orphanArtifactCount: z.number().int().nonnegative(),
318
+ rawInputCount: z.number().int().nonnegative(),
319
+ lintFindingCount: z.number().int().nonnegative(),
320
+ duplicateConceptCandidateCount: z.number().int().nonnegative(),
321
+ missingArticleCandidateCount: z.number().int().nonnegative(),
322
+ followUpQuestionCount: z.number().int().nonnegative()
323
+ });
324
+ var workspaceBindingSchema = z.object({
325
+ workspaceId: z.string(),
326
+ sourceId: z.string(),
327
+ createdAt: z.string()
328
+ });
329
+ var workspaceArtifactSchema = z.object({
330
+ workspaceId: z.string(),
331
+ path: z.string(),
332
+ kind: z.enum(["concept", "summary", "report", "slides", "image", "index", "note"]),
333
+ contentHash: z.string(),
334
+ compilerMetadata: z.record(z.string(), z.unknown()),
335
+ stale: z.boolean(),
336
+ chunkCount: z.number().int().nonnegative(),
337
+ createdAt: z.string(),
338
+ updatedAt: z.string()
339
+ });
340
+ var workspaceArtifactProvenanceSchema = z.object({
341
+ workspaceId: z.string(),
342
+ path: z.string(),
343
+ sourceId: z.string(),
344
+ snapshotId: z.string(),
345
+ chunkIds: z.array(z.number().int().nonnegative())
346
+ });
347
+ var workspaceLintSchema = z.object({
348
+ workspaceId: z.string(),
349
+ summary: z.object({
350
+ status: z.enum(["pass", "warn"]),
351
+ findingCount: z.number().int().nonnegative(),
352
+ staleArtifactCount: z.number().int().nonnegative(),
353
+ missingProvenanceCount: z.number().int().nonnegative(),
354
+ missingArtifactCount: z.number().int().nonnegative(),
355
+ brokenLinkCount: z.number().int().nonnegative(),
356
+ orphanArtifactCount: z.number().int().nonnegative(),
357
+ suggestedConceptCount: z.number().int().nonnegative(),
358
+ duplicateConceptCandidateCount: z.number().int().nonnegative(),
359
+ missingArticleCandidateCount: z.number().int().nonnegative(),
360
+ followUpQuestionCount: z.number().int().nonnegative()
361
+ }),
362
+ findings: z.array(z.object({
363
+ kind: z.enum([
364
+ "stale-artifact",
365
+ "missing-provenance",
366
+ "missing-artifact",
367
+ "broken-artifact-link",
368
+ "orphan-artifact",
369
+ "suggested-concept",
370
+ "duplicate-concept-candidate",
371
+ "missing-article-candidate",
372
+ "follow-up-question-suggestion"
373
+ ]),
374
+ severity: z.literal("warn"),
375
+ summary: z.string(),
376
+ artifactPath: z.string().optional(),
377
+ sourceId: z.string().optional(),
378
+ rawInputId: z.string().optional(),
379
+ relatedArtifactPaths: z.array(z.string()).optional()
380
+ })),
381
+ suggestionsArtifactPath: z.string().nullable()
382
+ });
383
+ var workspaceRawInputSearchResultSchema = z.object({
384
+ rawInputId: z.string(),
385
+ kind: z.enum(["markdown-dir", "pdf", "image", "csv", "json", "jsonl"]),
386
+ label: z.string(),
387
+ sectionTitle: z.string(),
388
+ markdown: z.string(),
389
+ filePath: z.string().nullable(),
390
+ score: z.number()
391
+ });
392
+ var workspaceSearchResultSchema = z.union([
393
+ z.object({
394
+ kind: z.literal("source"),
395
+ scope: z.literal("source"),
396
+ chunkId: z.number().int().nonnegative(),
397
+ sourceId: z.string(),
398
+ snapshotId: z.string(),
399
+ pageUrl: z.string(),
400
+ pageTitle: z.string(),
401
+ sectionTitle: z.string(),
402
+ markdown: z.string(),
403
+ pageKind: z.enum(["document", "file"]),
404
+ filePath: z.string().nullable(),
405
+ language: z.string().nullable(),
406
+ score: z.number(),
407
+ signals: z.array(z.enum(["lexical", "vector"]))
408
+ }),
409
+ z.object({
410
+ kind: z.literal("derived"),
411
+ scope: z.literal("derived"),
412
+ artifactPath: z.string(),
413
+ artifactKind: z.string(),
414
+ sectionTitle: z.string(),
415
+ markdown: z.string(),
416
+ stale: z.boolean(),
417
+ score: z.number()
418
+ })
419
+ ]);
188
420
  var server = new McpServer({
189
421
  name: packageName,
190
422
  version: packageVersion,
@@ -251,11 +483,89 @@ var toolHandlers = {
251
483
  }),
252
484
  project_link: async (args = {}) => linkProjectSources(args.projectPath, args.sourceIds),
253
485
  project_unlink: async (args = {}) => unlinkProjectSources(args.projectPath, args.sourceIds ?? []),
486
+ workspace_create: async (args = {}) => createWorkspace({
487
+ workspaceId: args.workspaceId,
488
+ label: args.label,
489
+ ...typeof args.purpose === "string" ? { purpose: args.purpose } : {},
490
+ ...typeof args.autoCompileEnabled === "boolean" ? { autoCompileEnabled: args.autoCompileEnabled } : {},
491
+ ...Array.isArray(args.defaultOutputFormats) ? { defaultOutputFormats: args.defaultOutputFormats } : {}
492
+ }),
493
+ workspace_list: async () => listWorkspaceRecords(),
494
+ workspace_update: async (args = {}) => updateWorkspaceSettings({
495
+ workspaceId: args.workspaceId,
496
+ autoCompileEnabled: args.autoCompileEnabled
497
+ }),
498
+ workspace_bind: async (args = {}) => bindWorkspaceSources({
499
+ workspaceId: args.workspaceId,
500
+ sourceIds: args.sourceIds
501
+ }),
502
+ workspace_unbind: async (args = {}) => unbindWorkspaceSources({
503
+ workspaceId: args.workspaceId,
504
+ ...Array.isArray(args.sourceIds) ? { sourceIds: args.sourceIds } : {}
505
+ }),
506
+ workspace_compile: async (args = {}) => compileWorkspaceArtifacts(args.workspaceId),
507
+ workspace_queue_run: async (args = {}) => runQueuedWorkspaceCompiles({
508
+ ...typeof args.maxJobs === "number" ? { maxJobs: args.maxJobs } : {}
509
+ }),
510
+ workspace_status: async (args = {}) => getWorkspaceStatus(args.workspaceId),
511
+ workspace_search: async (args = {}) => searchWorkspaceCatalog(
512
+ args.workspaceId,
513
+ args.query,
514
+ {
515
+ ...typeof args.scope === "string" ? { scope: args.scope } : {},
516
+ ...Array.isArray(args.pathPatterns) ? { path: args.pathPatterns } : {},
517
+ ...Array.isArray(args.languages) ? { language: args.languages } : {},
518
+ ...typeof args.mode === "string" ? { mode: args.mode } : {},
519
+ ...typeof args.limit === "number" ? { limit: args.limit } : {},
520
+ ...typeof args.offset === "number" ? { offset: args.offset } : {}
521
+ }
522
+ ),
523
+ workspace_ingest_add: async (args = {}) => ingestWorkspaceRawInput({
524
+ workspaceId: args.workspaceId,
525
+ kind: args.kind,
526
+ sourcePath: args.path,
527
+ ...typeof args.label === "string" ? { label: args.label } : {}
528
+ }),
529
+ workspace_ingest_list: async (args = {}) => listWorkspaceRawInputsRecord(args.workspaceId),
530
+ workspace_ingest_show: async (args = {}) => showWorkspaceRawInput(args.workspaceId, args.rawInputId),
531
+ workspace_ingest_search: async (args = {}) => searchWorkspaceRawInputCatalog({
532
+ workspaceId: args.workspaceId,
533
+ query: args.query,
534
+ ...Array.isArray(args.kinds) ? { kinds: args.kinds } : {},
535
+ ...typeof args.limit === "number" ? { limit: args.limit } : {},
536
+ ...typeof args.offset === "number" ? { offset: args.offset } : {}
537
+ }),
538
+ workspace_ingest_remove: async (args = {}) => removeWorkspaceRawInput({
539
+ workspaceId: args.workspaceId,
540
+ rawInputId: args.rawInputId
541
+ }),
542
+ workspace_artifact_list: async (args = {}) => listWorkspaceArtifacts(args.workspaceId),
543
+ workspace_artifact_show: async (args = {}) => showWorkspaceArtifact(args.workspaceId, args.artifactPath),
544
+ workspace_lint: async (args = {}) => lintWorkspaceArtifacts(args.workspaceId),
545
+ workspace_output: async (args = {}) => generateWorkspaceArtifactOutput({
546
+ workspaceId: args.workspaceId,
547
+ format: args.format,
548
+ ...typeof args.name === "string" ? { name: args.name } : {},
549
+ ...typeof args.prompt === "string" ? { prompt: args.prompt } : {}
550
+ }),
551
+ workspace_answer: async (args = {}) => answerWorkspace({
552
+ workspaceId: args.workspaceId,
553
+ question: args.question,
554
+ format: args.format,
555
+ ...typeof args.name === "string" ? { name: args.name } : {}
556
+ }),
557
+ workspace_sync_obsidian: async (args = {}) => syncWorkspaceToObsidianVault({
558
+ workspaceId: args.workspaceId,
559
+ vaultPath: args.vaultPath,
560
+ ...typeof args.exportSubdir === "string" ? { exportSubdir: args.exportSubdir } : {}
561
+ }),
254
562
  search: async (args = {}) => searchCatalog(args.query, {
255
563
  source: args.sourceIds ?? [],
256
564
  ...typeof args.snapshotId === "string" ? { snapshot: args.snapshotId } : {},
257
565
  ...typeof args.all === "boolean" ? { all: args.all } : {},
258
566
  ...typeof args.project === "string" ? { project: args.project } : {},
567
+ ...Array.isArray(args.pathPatterns) ? { path: args.pathPatterns } : {},
568
+ ...Array.isArray(args.languages) ? { language: args.languages } : {},
259
569
  ...typeof args.mode === "string" ? { mode: args.mode } : {},
260
570
  ...typeof args.limit === "number" ? { limit: args.limit } : {},
261
571
  ...typeof args.offset === "number" ? { offset: args.offset } : {}
@@ -496,6 +806,397 @@ registerAiocsTool(
496
806
  })
497
807
  }
498
808
  );
809
+ registerAiocsTool(
810
+ "workspace_create",
811
+ {
812
+ title: "Workspace create",
813
+ description: "Create or update a research workspace with the default LM Studio compiler profile.",
814
+ inputSchema: z.object({
815
+ workspaceId: z.string(),
816
+ label: z.string(),
817
+ purpose: z.string().optional(),
818
+ autoCompileEnabled: z.boolean().optional(),
819
+ defaultOutputFormats: z.array(z.enum(["report", "slides", "summary"])).optional()
820
+ }),
821
+ outputSchema: z.object({
822
+ workspace: workspaceSchema
823
+ })
824
+ }
825
+ );
826
+ registerAiocsTool(
827
+ "workspace_update",
828
+ {
829
+ title: "Workspace update",
830
+ description: "Update workspace settings such as automatic recompilation.",
831
+ inputSchema: z.object({
832
+ workspaceId: z.string(),
833
+ autoCompileEnabled: z.boolean()
834
+ }),
835
+ outputSchema: z.object({
836
+ workspace: workspaceSchema
837
+ })
838
+ }
839
+ );
840
+ registerAiocsTool(
841
+ "workspace_list",
842
+ {
843
+ title: "Workspace list",
844
+ description: "List all research workspaces in the local aiocs catalog.",
845
+ outputSchema: z.object({
846
+ workspaces: z.array(workspaceSchema)
847
+ })
848
+ }
849
+ );
850
+ registerAiocsTool(
851
+ "workspace_bind",
852
+ {
853
+ title: "Workspace bind",
854
+ description: "Bind one or more existing aiocs sources to a research workspace.",
855
+ inputSchema: z.object({
856
+ workspaceId: z.string(),
857
+ sourceIds: z.array(z.string()).min(1)
858
+ }),
859
+ outputSchema: z.object({
860
+ workspaceId: z.string(),
861
+ sourceIds: z.array(z.string())
862
+ })
863
+ }
864
+ );
865
+ registerAiocsTool(
866
+ "workspace_unbind",
867
+ {
868
+ title: "Workspace unbind",
869
+ description: "Unbind one or more sources from a research workspace.",
870
+ inputSchema: z.object({
871
+ workspaceId: z.string(),
872
+ sourceIds: z.array(z.string()).optional()
873
+ }),
874
+ outputSchema: z.object({
875
+ workspaceId: z.string(),
876
+ sourceIds: z.array(z.string())
877
+ })
878
+ }
879
+ );
880
+ registerAiocsTool(
881
+ "workspace_compile",
882
+ {
883
+ title: "Workspace compile",
884
+ description: "Compile or refresh derived workspace wiki artifacts from bound canonical sources.",
885
+ inputSchema: z.object({
886
+ workspaceId: z.string()
887
+ }),
888
+ outputSchema: z.object({
889
+ workspaceId: z.string(),
890
+ skipped: z.boolean(),
891
+ sourceFingerprint: z.string(),
892
+ changedSourceIds: z.array(z.string()),
893
+ changedRawInputIds: z.array(z.string()),
894
+ updatedArtifactPaths: z.array(z.string()),
895
+ artifactCount: z.number().int().nonnegative(),
896
+ compileRunId: z.string().nullable()
897
+ })
898
+ }
899
+ );
900
+ registerAiocsTool(
901
+ "workspace_status",
902
+ {
903
+ title: "Workspace status",
904
+ description: "Show workspace metadata, bindings, artifacts, graph summary, and recent compile runs.",
905
+ inputSchema: z.object({
906
+ workspaceId: z.string()
907
+ }),
908
+ outputSchema: z.object({
909
+ workspace: workspaceSchema,
910
+ bindings: z.array(workspaceBindingSchema),
911
+ artifacts: z.array(workspaceArtifactSchema),
912
+ compileJob: workspaceCompileJobSchema.nullable(),
913
+ compileRuns: z.array(z.object({
914
+ runId: z.string(),
915
+ workspaceId: z.string(),
916
+ status: z.enum(["success", "failed"]),
917
+ sourceFingerprint: z.string(),
918
+ artifactCount: z.number().int().nonnegative(),
919
+ errorMessage: z.string().nullable(),
920
+ startedAt: z.string(),
921
+ finishedAt: z.string()
922
+ })),
923
+ rawInputs: z.array(workspaceRawInputSchema),
924
+ syncTargets: z.array(workspaceSyncTargetSchema),
925
+ questionRuns: z.array(workspaceQuestionRunSchema),
926
+ links: z.array(workspaceArtifactLinkSchema),
927
+ graph: z.object({
928
+ linkCount: z.number().int().nonnegative(),
929
+ brokenLinkCount: z.number().int().nonnegative(),
930
+ orphanArtifactCount: z.number().int().nonnegative(),
931
+ backlinkCount: z.number().int().nonnegative(),
932
+ relationCounts: z.object({
933
+ explicit_link: z.number().int().nonnegative(),
934
+ derived_from: z.number().int().nonnegative(),
935
+ mentions: z.number().int().nonnegative(),
936
+ related_to: z.number().int().nonnegative(),
937
+ expands: z.number().int().nonnegative(),
938
+ index_entry: z.number().int().nonnegative(),
939
+ summary_of: z.number().int().nonnegative(),
940
+ concept_of: z.number().int().nonnegative(),
941
+ output_depends_on: z.number().int().nonnegative()
942
+ }),
943
+ mostLinkedArtifacts: z.array(z.object({
944
+ artifactPath: z.string(),
945
+ incomingCount: z.number().int().nonnegative(),
946
+ outgoingCount: z.number().int().nonnegative()
947
+ }))
948
+ }),
949
+ lintSummary: workspaceLintSchema.shape.summary,
950
+ health: workspaceHealthSchema
951
+ })
952
+ }
953
+ );
954
+ registerAiocsTool(
955
+ "workspace_queue_run",
956
+ {
957
+ title: "Workspace queue run",
958
+ description: "Process queued workspace compile jobs.",
959
+ inputSchema: z.object({
960
+ maxJobs: z.number().int().positive().optional()
961
+ }),
962
+ outputSchema: z.object({
963
+ processedJobs: z.number().int().nonnegative(),
964
+ succeededJobs: z.array(z.object({
965
+ workspaceId: z.string(),
966
+ sourceFingerprint: z.string(),
967
+ changedSourceIds: z.array(z.string()),
968
+ changedRawInputIds: z.array(z.string())
969
+ })),
970
+ failedJobs: z.array(z.object({
971
+ workspaceId: z.string(),
972
+ errorMessage: z.string()
973
+ }))
974
+ })
975
+ }
976
+ );
977
+ registerAiocsTool(
978
+ "workspace_search",
979
+ {
980
+ title: "Workspace search",
981
+ description: "Search canonical source evidence, derived artifacts, or both within a research workspace.",
982
+ inputSchema: z.object({
983
+ workspaceId: z.string(),
984
+ query: z.string(),
985
+ scope: z.enum(["source", "derived", "mixed"]).optional(),
986
+ pathPatterns: z.array(z.string()).optional(),
987
+ languages: z.array(z.string()).optional(),
988
+ mode: z.enum(["auto", "lexical", "hybrid", "semantic"]).optional(),
989
+ limit: z.number().int().positive().optional(),
990
+ offset: z.number().int().nonnegative().optional()
991
+ }),
992
+ outputSchema: z.object({
993
+ workspaceId: z.string(),
994
+ query: z.string(),
995
+ scope: z.enum(["source", "derived", "mixed"]),
996
+ limit: z.number().int().positive(),
997
+ offset: z.number().int().nonnegative(),
998
+ hasMore: z.boolean(),
999
+ modeRequested: z.enum(["auto", "lexical", "hybrid", "semantic"]),
1000
+ modeUsed: z.union([z.enum(["auto", "lexical", "hybrid", "semantic"]), z.literal("derived")]),
1001
+ total: z.number().int().nonnegative(),
1002
+ results: z.array(workspaceSearchResultSchema)
1003
+ })
1004
+ }
1005
+ );
1006
+ registerAiocsTool(
1007
+ "workspace_ingest_add",
1008
+ {
1009
+ title: "Workspace ingest add",
1010
+ description: "Ingest a local markdown directory, PDF, image, CSV, JSON, or JSONL file into a research workspace as raw evidence.",
1011
+ inputSchema: z.object({
1012
+ workspaceId: z.string(),
1013
+ kind: z.enum(["markdown-dir", "pdf", "image", "csv", "json", "jsonl"]),
1014
+ path: z.string(),
1015
+ label: z.string().optional()
1016
+ }),
1017
+ outputSchema: z.object({
1018
+ workspaceId: z.string(),
1019
+ rawInput: workspaceRawInputSchema
1020
+ })
1021
+ }
1022
+ );
1023
+ registerAiocsTool(
1024
+ "workspace_ingest_list",
1025
+ {
1026
+ title: "Workspace ingest list",
1027
+ description: "List raw inputs ingested into a workspace.",
1028
+ inputSchema: z.object({
1029
+ workspaceId: z.string()
1030
+ }),
1031
+ outputSchema: z.object({
1032
+ workspaceId: z.string(),
1033
+ rawInputs: z.array(workspaceRawInputSchema)
1034
+ })
1035
+ }
1036
+ );
1037
+ registerAiocsTool(
1038
+ "workspace_ingest_show",
1039
+ {
1040
+ title: "Workspace ingest show",
1041
+ description: "Show one raw input together with its searchable chunks.",
1042
+ inputSchema: z.object({
1043
+ workspaceId: z.string(),
1044
+ rawInputId: z.string()
1045
+ }),
1046
+ outputSchema: z.object({
1047
+ workspaceId: z.string(),
1048
+ rawInput: workspaceRawInputSchema,
1049
+ chunks: z.array(z.object({
1050
+ id: z.number().int().nonnegative(),
1051
+ workspace_id: z.string(),
1052
+ raw_input_id: z.string(),
1053
+ section_title: z.string(),
1054
+ markdown: z.string(),
1055
+ file_path: z.string().nullable(),
1056
+ score: z.number()
1057
+ }))
1058
+ })
1059
+ }
1060
+ );
1061
+ registerAiocsTool(
1062
+ "workspace_ingest_search",
1063
+ {
1064
+ title: "Workspace ingest search",
1065
+ description: "Search workspace-scoped raw input chunks directly, including structured dataset inputs.",
1066
+ inputSchema: z.object({
1067
+ workspaceId: z.string(),
1068
+ query: z.string(),
1069
+ kinds: z.array(z.enum(["markdown-dir", "pdf", "image", "csv", "json", "jsonl"])).optional(),
1070
+ limit: z.number().int().positive().optional(),
1071
+ offset: z.number().int().nonnegative().optional()
1072
+ }),
1073
+ outputSchema: z.object({
1074
+ workspaceId: z.string(),
1075
+ query: z.string(),
1076
+ total: z.number().int().nonnegative(),
1077
+ limit: z.number().int().positive(),
1078
+ offset: z.number().int().nonnegative(),
1079
+ hasMore: z.boolean(),
1080
+ results: z.array(workspaceRawInputSearchResultSchema)
1081
+ })
1082
+ }
1083
+ );
1084
+ registerAiocsTool(
1085
+ "workspace_ingest_remove",
1086
+ {
1087
+ title: "Workspace ingest remove",
1088
+ description: "Remove one raw input and its derived artifacts from a workspace.",
1089
+ inputSchema: z.object({
1090
+ workspaceId: z.string(),
1091
+ rawInputId: z.string()
1092
+ }),
1093
+ outputSchema: z.object({
1094
+ workspaceId: z.string(),
1095
+ rawInputId: z.string(),
1096
+ deleted: z.boolean()
1097
+ })
1098
+ }
1099
+ );
1100
+ registerAiocsTool(
1101
+ "workspace_artifact_list",
1102
+ {
1103
+ title: "Workspace artifact list",
1104
+ description: "List derived artifacts recorded for a workspace.",
1105
+ inputSchema: z.object({
1106
+ workspaceId: z.string()
1107
+ }),
1108
+ outputSchema: z.object({
1109
+ workspaceId: z.string(),
1110
+ artifacts: z.array(workspaceArtifactSchema)
1111
+ })
1112
+ }
1113
+ );
1114
+ registerAiocsTool(
1115
+ "workspace_artifact_show",
1116
+ {
1117
+ title: "Workspace artifact show",
1118
+ description: "Read a workspace artifact file together with its provenance metadata.",
1119
+ inputSchema: z.object({
1120
+ workspaceId: z.string(),
1121
+ artifactPath: z.string()
1122
+ }),
1123
+ outputSchema: z.object({
1124
+ workspaceId: z.string(),
1125
+ artifact: workspaceArtifactSchema,
1126
+ content: z.string(),
1127
+ provenance: z.array(workspaceArtifactProvenanceSchema),
1128
+ rawInputProvenance: z.array(workspaceArtifactRawInputProvenanceSchema)
1129
+ })
1130
+ }
1131
+ );
1132
+ registerAiocsTool(
1133
+ "workspace_lint",
1134
+ {
1135
+ title: "Workspace lint",
1136
+ description: "Lint a workspace for stale artifacts, graph issues, and deterministic suggestion candidates.",
1137
+ inputSchema: z.object({
1138
+ workspaceId: z.string()
1139
+ }),
1140
+ outputSchema: workspaceLintSchema
1141
+ }
1142
+ );
1143
+ registerAiocsTool(
1144
+ "workspace_output",
1145
+ {
1146
+ title: "Workspace output",
1147
+ description: "Generate a report, slide deck, or summary artifact from a compiled workspace.",
1148
+ inputSchema: z.object({
1149
+ workspaceId: z.string(),
1150
+ format: z.enum(["report", "slides", "summary"]),
1151
+ name: z.string().optional(),
1152
+ prompt: z.string().optional()
1153
+ }),
1154
+ outputSchema: z.object({
1155
+ workspaceId: z.string(),
1156
+ format: z.enum(["report", "slides", "summary"]),
1157
+ path: z.string(),
1158
+ artifactCount: z.number().int().nonnegative()
1159
+ })
1160
+ }
1161
+ );
1162
+ registerAiocsTool(
1163
+ "workspace_answer",
1164
+ {
1165
+ title: "Workspace answer",
1166
+ description: "Answer a question against a compiled workspace and save the result as a derived artifact.",
1167
+ inputSchema: z.object({
1168
+ workspaceId: z.string(),
1169
+ question: z.string(),
1170
+ format: z.enum(["report", "slides", "summary", "note"]),
1171
+ name: z.string().optional()
1172
+ }),
1173
+ outputSchema: z.object({
1174
+ workspaceId: z.string(),
1175
+ format: z.enum(["report", "slides", "summary", "note"]),
1176
+ path: z.string(),
1177
+ artifactCount: z.number().int().nonnegative(),
1178
+ questionRun: workspaceQuestionRunSchema
1179
+ })
1180
+ }
1181
+ );
1182
+ registerAiocsTool(
1183
+ "workspace_sync_obsidian",
1184
+ {
1185
+ title: "Workspace sync Obsidian",
1186
+ description: "Sync a workspace tree into an Obsidian vault target.",
1187
+ inputSchema: z.object({
1188
+ workspaceId: z.string(),
1189
+ vaultPath: z.string(),
1190
+ exportSubdir: z.string().optional()
1191
+ }),
1192
+ outputSchema: z.object({
1193
+ workspaceId: z.string(),
1194
+ vaultPath: z.string(),
1195
+ targetPath: z.string(),
1196
+ exportSubdir: z.string()
1197
+ })
1198
+ }
1199
+ );
499
1200
  registerAiocsTool(
500
1201
  "search",
501
1202
  {
@@ -507,6 +1208,8 @@ registerAiocsTool(
507
1208
  snapshotId: z.string().optional(),
508
1209
  all: z.boolean().optional(),
509
1210
  project: z.string().optional(),
1211
+ pathPatterns: z.array(z.string()).optional(),
1212
+ languages: z.array(z.string()).optional(),
510
1213
  mode: z.enum(["auto", "lexical", "hybrid", "semantic"]).optional(),
511
1214
  limit: z.number().int().positive().optional(),
512
1215
  offset: z.number().int().nonnegative().optional()