@bodhi-ventures/aiocs 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -2,36 +2,56 @@
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
  getAiocsConfigDir,
11
16
  getAiocsDataDir,
12
17
  getDoctorReport,
13
18
  getEmbeddingStatus,
14
19
  getManagedSourceSpecDirectories,
20
+ getWorkspaceStatus,
15
21
  importCatalogBackup,
22
+ ingestWorkspaceRawInput,
16
23
  initManagedSources,
17
24
  linkProjectSources,
25
+ lintWorkspaceArtifacts,
18
26
  listSnapshotsForSource,
19
27
  listSources,
28
+ listWorkspaceArtifacts,
29
+ listWorkspaceRawInputsRecord,
30
+ listWorkspaceRecords,
20
31
  openCatalog,
21
32
  packageName,
22
33
  packageVersion,
23
34
  parseDaemonConfig,
24
35
  refreshDueSources,
36
+ removeWorkspaceRawInput,
25
37
  runEmbeddingWorker,
38
+ runQueuedWorkspaceCompiles,
26
39
  runSourceCanaries,
27
40
  searchCatalog,
41
+ searchWorkspaceCatalog,
42
+ searchWorkspaceRawInputCatalog,
28
43
  showChunk,
44
+ showWorkspaceArtifact,
45
+ showWorkspaceRawInput,
29
46
  startDaemon,
47
+ syncWorkspaceToObsidianVault,
30
48
  toAiocsError,
49
+ unbindWorkspaceSources,
31
50
  unlinkProjectSources,
51
+ updateWorkspaceSettings,
32
52
  upsertSourceFromSpecFile,
33
53
  verifyCoverage
34
- } from "./chunk-M7YEYMJL.js";
54
+ } from "./chunk-GX6CZOO7.js";
35
55
 
36
56
  // src/cli.ts
37
57
  import { Command, CommanderError as CommanderError2 } from "commander";
@@ -124,6 +144,21 @@ function renderSearchResult(result) {
124
144
  ""
125
145
  ].join("\n");
126
146
  }
147
+ function renderWorkspaceSearchResult(result) {
148
+ if (result.kind === "source") {
149
+ return renderSearchResult(result);
150
+ }
151
+ return [
152
+ `Artifact: ${result.artifactPath}`,
153
+ `Kind: ${result.artifactKind}`,
154
+ `Section: ${result.sectionTitle}`,
155
+ `Stale: ${String(result.stale)}`,
156
+ `Score: ${result.score.toFixed(4)}`,
157
+ "",
158
+ result.markdown,
159
+ ""
160
+ ].join("\n");
161
+ }
127
162
  function parsePositiveIntegerOption(value, field) {
128
163
  if (typeof value === "undefined") {
129
164
  return void 0;
@@ -440,6 +475,309 @@ project.command("unlink").argument("<project-path>").argument("[source-ids...]")
440
475
  };
441
476
  });
442
477
  });
478
+ var workspace = program.command("workspace");
479
+ workspace.command("create").argument("<workspace-id>").requiredOption("--label <label>", "workspace label").option("--purpose <purpose>", "workspace purpose/description").option("--auto-compile", "automatically recompile after bound-source or raw-input changes").option("--output <format>", "default output format", (value, current) => {
480
+ current.push(value);
481
+ return current;
482
+ }, []).action(async (workspaceId, options, command) => {
483
+ await executeCommand(command, "workspace.create", async () => {
484
+ const result = await createWorkspace({
485
+ workspaceId,
486
+ label: options.label,
487
+ ...options.purpose ? { purpose: options.purpose } : {},
488
+ ...options.autoCompile ? { autoCompileEnabled: true } : {},
489
+ ...options.output && options.output.length > 0 ? { defaultOutputFormats: options.output } : {}
490
+ });
491
+ return {
492
+ data: result,
493
+ human: `Created workspace ${result.workspace.id}`
494
+ };
495
+ });
496
+ });
497
+ workspace.command("configure").argument("<workspace-id>").requiredOption("--auto-compile <enabled>", "set workspace auto-compile to true or false").action(async (workspaceId, options, command) => {
498
+ await executeCommand(command, "workspace.configure", async () => {
499
+ const normalized = options.autoCompile.trim().toLowerCase();
500
+ if (normalized !== "true" && normalized !== "false") {
501
+ throw new AiocsError(
502
+ AIOCS_ERROR_CODES.invalidArgument,
503
+ "--auto-compile must be true or false"
504
+ );
505
+ }
506
+ const result = await updateWorkspaceSettings({
507
+ workspaceId,
508
+ autoCompileEnabled: normalized === "true"
509
+ });
510
+ return {
511
+ data: result,
512
+ human: `Updated ${workspaceId}: autoCompile=${result.workspace.autoCompileEnabled}`
513
+ };
514
+ });
515
+ });
516
+ workspace.command("list").action(async (_options, command) => {
517
+ await executeCommand(command, "workspace.list", async () => {
518
+ const result = await listWorkspaceRecords();
519
+ return {
520
+ data: result,
521
+ human: result.workspaces.length === 0 ? "No workspaces registered." : result.workspaces.map((item) => [
522
+ item.id,
523
+ item.label,
524
+ `bindings=${item.bindingCount}`,
525
+ `artifacts=${item.artifactCount}`,
526
+ item.lastCompileStatus ? `last=${item.lastCompileStatus}` : "never compiled"
527
+ ].join(" | "))
528
+ };
529
+ });
530
+ });
531
+ workspace.command("bind").argument("<workspace-id>").argument("<source-ids...>").action(async (workspaceId, sourceIds, _options, command) => {
532
+ await executeCommand(command, "workspace.bind", async () => {
533
+ const result = await bindWorkspaceSources({ workspaceId, sourceIds });
534
+ return {
535
+ data: result,
536
+ human: `Bound ${workspaceId} -> ${sourceIds.join(", ")}`
537
+ };
538
+ });
539
+ });
540
+ workspace.command("unbind").argument("<workspace-id>").argument("[source-ids...]").action(async (workspaceId, sourceIds, _options, command) => {
541
+ await executeCommand(command, "workspace.unbind", async () => {
542
+ const result = await unbindWorkspaceSources({
543
+ workspaceId,
544
+ ...sourceIds.length > 0 ? { sourceIds } : {}
545
+ });
546
+ return {
547
+ data: result,
548
+ human: sourceIds.length > 0 ? `Unbound ${workspaceId} -> ${sourceIds.join(", ")}` : `Unbound all sources from ${workspaceId}`
549
+ };
550
+ });
551
+ });
552
+ workspace.command("compile").argument("<workspace-id>").action(async (workspaceId, _options, command) => {
553
+ await executeCommand(command, "workspace.compile", async () => {
554
+ const result = await compileWorkspaceArtifacts(workspaceId);
555
+ return {
556
+ data: result,
557
+ human: result.skipped ? `Workspace ${workspaceId} is already up to date.` : [
558
+ `Compiled ${workspaceId}`,
559
+ `Changed sources: ${result.changedSourceIds.join(", ") || "(none)"}`,
560
+ `Changed raw inputs: ${result.changedRawInputIds.join(", ") || "(none)"}`,
561
+ ...result.updatedArtifactPaths.map((path) => `- ${path}`)
562
+ ]
563
+ };
564
+ });
565
+ });
566
+ workspace.command("status").argument("<workspace-id>").action(async (workspaceId, _options, command) => {
567
+ await executeCommand(command, "workspace.status", async () => {
568
+ const result = await getWorkspaceStatus(workspaceId);
569
+ return {
570
+ data: result,
571
+ human: [
572
+ `${result.workspace.id} | ${result.workspace.label}`,
573
+ `Bindings=${result.bindings.length} | RawInputs=${result.rawInputs.length} | Artifacts=${result.artifacts.length} | Runs=${result.compileRuns.length}`,
574
+ `AutoCompile=${result.workspace.autoCompileEnabled} | Health=${result.health.status} | PendingJobs=${result.health.pendingCompileJobs} | FailedJobs=${result.health.failedCompileJobs}`,
575
+ `Links=${result.graph.linkCount} | BrokenLinks=${result.graph.brokenLinkCount} | Orphans=${result.graph.orphanArtifactCount}`
576
+ ]
577
+ };
578
+ });
579
+ });
580
+ workspace.command("queue-run").option("--max-jobs <count>", "maximum queued workspace compile jobs to process").action(async (options, command) => {
581
+ await executeCommand(command, "workspace.queue-run", async () => {
582
+ const maxJobs = parsePositiveIntegerOption(options.maxJobs, "max-jobs");
583
+ const result = await runQueuedWorkspaceCompiles({
584
+ ...typeof maxJobs === "number" ? { maxJobs } : {}
585
+ });
586
+ return {
587
+ data: result,
588
+ human: [
589
+ `Processed ${result.processedJobs} workspace compile job(s)`,
590
+ ...result.succeededJobs.map((job) => `success | ${job.workspaceId} | sources=${job.changedSourceIds.length} | raw=${job.changedRawInputIds.length}`),
591
+ ...result.failedJobs.map((job) => `failed | ${job.workspaceId} | ${job.errorMessage}`)
592
+ ]
593
+ };
594
+ });
595
+ });
596
+ workspace.command("search").argument("<workspace-id>").argument("<query>").option("--scope <scope>", "source, derived, or mixed").option("--mode <mode>", "search mode: auto, lexical, hybrid, semantic").option("--path <glob>", "restrict source-side search to file paths matching a glob", (value, current) => {
597
+ current.push(value);
598
+ return current;
599
+ }, []).option("--language <name>", "restrict source-side search to a language", (value, current) => {
600
+ current.push(value);
601
+ return current;
602
+ }, []).option("--limit <count>", "maximum number of results to return").option("--offset <count>", "number of results to skip before returning matches").action(async (workspaceId, query, options, command) => {
603
+ await executeCommand(command, "workspace.search", async () => {
604
+ const limit = parsePositiveIntegerOption(options.limit, "limit");
605
+ const offset = parsePositiveIntegerOption(options.offset, "offset");
606
+ const mode = parseSearchModeOption(options.mode);
607
+ const result = await searchWorkspaceCatalog(workspaceId, query, {
608
+ ...options.scope ? { scope: options.scope } : {},
609
+ ...mode ? { mode } : {},
610
+ ...options.path && options.path.length > 0 ? { path: options.path } : {},
611
+ ...options.language && options.language.length > 0 ? { language: options.language } : {},
612
+ ...typeof limit === "number" ? { limit } : {},
613
+ ...typeof offset === "number" ? { offset } : {}
614
+ });
615
+ return {
616
+ data: result,
617
+ human: result.results.length === 0 ? `No workspace results for "${query}" (${result.scope})` : [
618
+ `Showing ${result.offset + 1}-${result.offset + result.results.length} of ${result.total} workspace result(s)`,
619
+ ...result.results.map((entry) => renderWorkspaceSearchResult(entry))
620
+ ]
621
+ };
622
+ });
623
+ });
624
+ var workspaceArtifact = workspace.command("artifact");
625
+ workspaceArtifact.command("list").argument("<workspace-id>").action(async (workspaceId, _options, command) => {
626
+ await executeCommand(command, "workspace.artifact.list", async () => {
627
+ const result = await listWorkspaceArtifacts(workspaceId);
628
+ return {
629
+ data: result,
630
+ human: result.artifacts.length === 0 ? `No artifacts for ${workspaceId}` : result.artifacts.map((artifact) => [
631
+ artifact.path,
632
+ artifact.kind,
633
+ artifact.stale ? "stale" : "fresh",
634
+ `chunks=${artifact.chunkCount}`
635
+ ].join(" | "))
636
+ };
637
+ });
638
+ });
639
+ workspaceArtifact.command("show").argument("<workspace-id>").argument("<artifact-path>").action(async (workspaceId, artifactPath, _options, command) => {
640
+ await executeCommand(command, "workspace.artifact.show", async () => {
641
+ const result = await showWorkspaceArtifact(workspaceId, artifactPath);
642
+ return {
643
+ data: result,
644
+ human: result.content
645
+ };
646
+ });
647
+ });
648
+ var workspaceIngest = workspace.command("ingest");
649
+ workspaceIngest.command("add").argument("<workspace-id>").argument("<kind>").argument("<path>").option("--label <label>", "display label for the raw input").action(async (workspaceId, kind, path, options, command) => {
650
+ await executeCommand(command, "workspace.ingest.add", async () => {
651
+ const result = await ingestWorkspaceRawInput({
652
+ workspaceId,
653
+ kind,
654
+ sourcePath: path,
655
+ ...options.label ? { label: options.label } : {}
656
+ });
657
+ return {
658
+ data: result,
659
+ human: `Ingested ${result.rawInput.kind} ${result.rawInput.id} into ${workspaceId}`
660
+ };
661
+ });
662
+ });
663
+ workspaceIngest.command("list").argument("<workspace-id>").action(async (workspaceId, _options, command) => {
664
+ await executeCommand(command, "workspace.ingest.list", async () => {
665
+ const result = await listWorkspaceRawInputsRecord(workspaceId);
666
+ return {
667
+ data: result,
668
+ human: result.rawInputs.length === 0 ? `No raw inputs for ${workspaceId}` : result.rawInputs.map((rawInput) => [
669
+ rawInput.id,
670
+ rawInput.kind,
671
+ rawInput.label,
672
+ `chunks=${rawInput.chunkCount}`
673
+ ].join(" | "))
674
+ };
675
+ });
676
+ });
677
+ workspaceIngest.command("show").argument("<workspace-id>").argument("<raw-input-id>").action(async (workspaceId, rawInputId, _options, command) => {
678
+ await executeCommand(command, "workspace.ingest.show", async () => {
679
+ const result = await showWorkspaceRawInput(workspaceId, rawInputId);
680
+ return {
681
+ data: result,
682
+ human: [
683
+ `${result.rawInput.id} | ${result.rawInput.kind} | ${result.rawInput.label}`,
684
+ ...result.chunks.map((chunk) => `${chunk.section_title} | ${chunk.file_path ?? "(root)"}`)
685
+ ]
686
+ };
687
+ });
688
+ });
689
+ workspaceIngest.command("search").argument("<workspace-id>").argument("<query>").option("--kind <kind>", "raw input kind filter", (value, current) => {
690
+ current.push(value);
691
+ return current;
692
+ }, []).option("--limit <count>", "maximum number of results to return").option("--offset <count>", "number of results to skip").action(async (workspaceId, query, options, command) => {
693
+ await executeCommand(command, "workspace.ingest.search", async () => {
694
+ const limit = parsePositiveIntegerOption(options.limit, "limit");
695
+ const offset = parsePositiveIntegerOption(options.offset, "offset");
696
+ const result = await searchWorkspaceRawInputCatalog({
697
+ workspaceId,
698
+ query,
699
+ ...options.kind && options.kind.length > 0 ? { kinds: options.kind } : {},
700
+ ...typeof limit === "number" ? { limit } : {},
701
+ ...typeof offset === "number" ? { offset } : {}
702
+ });
703
+ return {
704
+ data: result,
705
+ human: result.results.length === 0 ? `No raw-input matches for "${query}"` : [
706
+ `Showing ${result.offset + 1}-${result.offset + result.results.length} of ${result.total} raw-input result(s)`,
707
+ ...result.results.map((entry) => [
708
+ entry.rawInputId,
709
+ entry.kind,
710
+ entry.label,
711
+ entry.sectionTitle,
712
+ entry.filePath ?? "(root)"
713
+ ].join(" | "))
714
+ ]
715
+ };
716
+ });
717
+ });
718
+ workspaceIngest.command("remove").argument("<workspace-id>").argument("<raw-input-id>").action(async (workspaceId, rawInputId, _options, command) => {
719
+ await executeCommand(command, "workspace.ingest.remove", async () => {
720
+ const result = await removeWorkspaceRawInput({ workspaceId, rawInputId });
721
+ return {
722
+ data: result,
723
+ human: `Removed raw input ${rawInputId} from ${workspaceId}`
724
+ };
725
+ });
726
+ });
727
+ workspace.command("lint").argument("<workspace-id>").action(async (workspaceId, _options, command) => {
728
+ await executeCommand(command, "workspace.lint", async () => {
729
+ const result = await lintWorkspaceArtifacts(workspaceId);
730
+ return {
731
+ data: result,
732
+ human: [
733
+ `${workspaceId} lint status=${result.summary.status}`,
734
+ ...result.findings.map((finding) => `${finding.kind} | ${finding.artifactPath ?? finding.sourceId ?? "(workspace)"} | ${finding.summary}`)
735
+ ]
736
+ };
737
+ });
738
+ });
739
+ workspace.command("output").argument("<workspace-id>").argument("<format>").option("--name <name>", "output file slug").option("--prompt <prompt>", "extra output instructions").action(async (workspaceId, format, options, command) => {
740
+ await executeCommand(command, "workspace.output", async () => {
741
+ const result = await generateWorkspaceArtifactOutput({
742
+ workspaceId,
743
+ format,
744
+ ...options.name ? { name: options.name } : {},
745
+ ...options.prompt ? { prompt: options.prompt } : {}
746
+ });
747
+ return {
748
+ data: result,
749
+ human: `Generated ${result.format} at ${result.path}`
750
+ };
751
+ });
752
+ });
753
+ workspace.command("answer").argument("<workspace-id>").argument("<format>").argument("<question>").option("--name <name>", "output file slug").action(async (workspaceId, format, question, options, command) => {
754
+ await executeCommand(command, "workspace.answer", async () => {
755
+ const result = await answerWorkspace({
756
+ workspaceId,
757
+ format,
758
+ question,
759
+ ...options.name ? { name: options.name } : {}
760
+ });
761
+ return {
762
+ data: result,
763
+ human: `Answered into ${result.path} (${result.format})`
764
+ };
765
+ });
766
+ });
767
+ var workspaceSync = workspace.command("sync");
768
+ workspaceSync.command("obsidian").argument("<workspace-id>").argument("<vault-path>").option("--export-subdir <subdir>", "vault subdirectory to sync into").action(async (workspaceId, vaultPath, options, command) => {
769
+ await executeCommand(command, "workspace.sync.obsidian", async () => {
770
+ const result = await syncWorkspaceToObsidianVault({
771
+ workspaceId,
772
+ vaultPath,
773
+ ...options.exportSubdir ? { exportSubdir: options.exportSubdir } : {}
774
+ });
775
+ return {
776
+ data: result,
777
+ human: `Synced ${workspaceId} to ${result.targetPath}`
778
+ };
779
+ });
780
+ });
443
781
  var backup = program.command("backup");
444
782
  backup.command("export").argument("<output-dir>").option("--replace-existing", "replace an existing non-empty export directory").action(
445
783
  async (outputDir, options, command) => {