@swarmvaultai/cli 0.5.0 → 0.6.1

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 (4) hide show
  1. package/README.md +14 -7
  2. package/dist/index.js +120 -19
  3. package/package.json +8 -8
  4. package/LICENSE +0 -21
package/README.md CHANGED
@@ -23,9 +23,11 @@ Installed commands:
23
23
  mkdir my-vault
24
24
  cd my-vault
25
25
  swarmvault init --obsidian --profile personal-research
26
+ swarmvault init --obsidian --profile reader,timeline
26
27
  swarmvault source add https://github.com/karpathy/micrograd
27
28
  swarmvault source add https://example.com/docs/getting-started
28
29
  swarmvault source add ./exports/customer-call.srt --guide
30
+ swarmvault source session file-customer-call-srt-12345678
29
31
  swarmvault source list
30
32
  swarmvault source reload --all
31
33
  sed -n '1,120p' swarmvault.schema.md
@@ -51,7 +53,7 @@ swarmvault graph push neo4j --dry-run
51
53
 
52
54
  ## Commands
53
55
 
54
- ### `swarmvault init [--obsidian] [--profile personal-research]`
56
+ ### `swarmvault init [--obsidian] [--profile <alias-or-presets>]`
55
57
 
56
58
  Create a workspace with:
57
59
 
@@ -68,29 +70,33 @@ Create a workspace with:
68
70
 
69
71
  The schema file is the vault-specific instruction layer. Edit it to define naming rules, categories, grounding expectations, and exclusions before a serious compile.
70
72
 
71
- ### `swarmvault source add|list|reload|review|guide|delete`
73
+ `--profile` accepts `default`, `personal-research`, or a comma-separated preset list such as `reader,timeline`. For fully custom vault behavior, edit the `profile` block in `swarmvault.config.json`; that deterministic profile layer works alongside the human-written `swarmvault.schema.md`.
74
+
75
+ ### `swarmvault source add|list|reload|review|guide|session|delete`
72
76
 
73
77
  Manage recurring source roots through a registry-backed workflow.
74
78
 
75
- - `source add <input>` supports local directories, public GitHub repo root URLs such as `https://github.com/karpathy/micrograd`, and docs/wiki/help/reference/tutorial hubs
79
+ - `source add <input>` supports local files, local directories, public GitHub repo root URLs such as `https://github.com/karpathy/micrograd`, and docs/wiki/help/reference/tutorial hubs
76
80
  - by default `source add` registers the source, syncs it into the vault, runs one compile, and writes a source brief to `wiki/outputs/source-briefs/<source-id>.md`
77
- - add `--guide` when you want a source brief, source review, source guide, and approval bundle for one-source-at-a-time integration
81
+ - add `--guide` when you want a resumable source session, source brief, source review, source guide, and approval-bundled canonical page edits when `profile.guidedSessionMode` is `canonical_review`, with `wiki/insights/` fallback for `insights_only`
78
82
  - `source list` shows every managed source with its kind, status, and current brief path
79
83
  - `source reload [id]` re-syncs one source, or use `--all` to refresh everything in the registry and compile once
80
84
  - `source review <id>` stages a lighter source-scoped review artifact
81
- - `source guide <id>` stages the stronger guided-ingest bundle for that source scope
85
+ - `source guide <id>` remains a compatibility alias for the guided session flow
86
+ - `source session <id>` resumes the latest guided session for a managed source id, raw source id, source scope id, or session id
82
87
  - `source delete <id>` unregisters the source and removes transient sync state under `state/sources/<id>/`, but leaves canonical `raw/`, `wiki/`, and saved output artifacts intact
83
88
 
84
89
  Useful flags:
85
90
 
86
91
  - `--all`
87
92
  - `--guide`
93
+ - `--answers-file <path>`
88
94
  - `--no-compile`
89
95
  - `--no-brief`
90
96
  - `--max-pages <n>`
91
97
  - `--max-depth <n>`
92
98
 
93
- Managed sources write registry state to `state/sources.json`. Local directory entries remain compatible with `watch --repo`; remote GitHub and docs-crawl sources are manual `source reload` sources in this release.
99
+ Managed sources write registry state to `state/sources.json`. Guided sessions write durable anchors to `wiki/outputs/source-sessions/` and session state to `state/source-sessions/`. In an interactive TTY, `--guide` can ask the session questions immediately; otherwise use `source session <id>` or `--answers-file <path>` to resume and stage the approval bundle later. Local directory entries remain compatible with `watch --repo`; remote GitHub and docs-crawl sources are manual `source reload` sources in this release.
94
100
 
95
101
  ### `swarmvault ingest <path-or-url>`
96
102
 
@@ -102,12 +108,13 @@ Ingest a local file path, directory path, or URL into immutable source storage a
102
108
  - use `source add` instead when the same local directory, public GitHub repo root, or docs hub should stay registered and reloadable
103
109
  - URL ingest still localizes remote image references by default
104
110
  - local file ingest supports markdown, text, reStructuredText, HTML, PDF, DOCX, images, and code
105
- - add `--guide` when you want a source brief, source review, source guide, and approval bundle after ingest
111
+ - add `--guide` when you want a resumable source session, source brief, source review, source guide, and approval-bundled canonical page edits when `profile.guidedSessionMode` is `canonical_review`, with `wiki/insights/` fallback for `insights_only`
106
112
  - code-aware directory ingest currently covers JavaScript, JSX, TypeScript, TSX, Python, Go, Rust, Java, Kotlin, Scala, Lua, Zig, C#, C, C++, PHP, Ruby, and PowerShell
107
113
 
108
114
  Useful flags:
109
115
 
110
116
  - `--repo-root <path>`
117
+ - `--answers-file <path>`
111
118
  - `--include <glob...>`
112
119
  - `--exclude <glob...>`
113
120
  - `--max-files <n>`
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // src/index.ts
4
4
  import { readFileSync } from "fs";
5
5
  import process2 from "process";
6
+ import { createInterface } from "readline/promises";
6
7
  import {
7
8
  acceptApproval,
8
9
  addInput,
@@ -41,6 +42,7 @@ import {
41
42
  readApproval,
42
43
  rejectApproval,
43
44
  reloadManagedSources,
45
+ resumeSourceSession,
44
46
  reviewManagedSource,
45
47
  reviewSourceScope,
46
48
  runSchedule,
@@ -226,9 +228,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
226
228
  function readCliVersion() {
227
229
  try {
228
230
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
229
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.5.0";
231
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.6.1";
230
232
  } catch {
231
- return "0.5.0";
233
+ return "0.6.1";
232
234
  }
233
235
  }
234
236
  function parsePositiveInt(value, fallback) {
@@ -271,6 +273,57 @@ function emitNotice(message) {
271
273
  process2.stderr.write(`[swarmvault] ${message}
272
274
  `);
273
275
  }
276
+ function canPromptGuide() {
277
+ return Boolean(process2.stdin.isTTY && process2.stdout.isTTY && !isJson());
278
+ }
279
+ function readGuideAnswersFile(filePath) {
280
+ if (!filePath) {
281
+ return void 0;
282
+ }
283
+ const raw = JSON.parse(readFileSync(filePath, "utf8"));
284
+ if (Array.isArray(raw)) {
285
+ return raw.filter((value) => typeof value === "string");
286
+ }
287
+ if (raw && typeof raw === "object") {
288
+ return Object.fromEntries(
289
+ Object.entries(raw).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string")
290
+ );
291
+ }
292
+ throw new Error("Guide answers files must contain either a JSON object keyed by question id or a JSON array of answers.");
293
+ }
294
+ async function promptGuideAnswers(questions) {
295
+ const rl = createInterface({
296
+ input: process2.stdin,
297
+ output: process2.stdout
298
+ });
299
+ try {
300
+ const answers = {};
301
+ for (const question of questions) {
302
+ const promptLines = [question.prompt];
303
+ if (question.answer) {
304
+ promptLines.push(`Current: ${question.answer}`);
305
+ promptLines.push("Press Enter to keep the current answer.");
306
+ }
307
+ const answer = (await rl.question(`${promptLines.join("\n")}
308
+ > `)).trim();
309
+ if (answer) {
310
+ answers[question.id] = answer;
311
+ } else if (question.answer) {
312
+ answers[question.id] = question.answer;
313
+ }
314
+ }
315
+ return answers;
316
+ } finally {
317
+ rl.close();
318
+ }
319
+ }
320
+ async function completeGuideInteractively(guide, fallbackTarget) {
321
+ if (!guide.awaitingInput || !canPromptGuide()) {
322
+ return guide;
323
+ }
324
+ const answers = await promptGuideAnswers(guide.questions);
325
+ return await resumeSourceSession(process2.cwd(), guide.sessionId || fallbackTarget, { answers });
326
+ }
274
327
  function getCommandPath(command) {
275
328
  const names = [];
276
329
  let current = command;
@@ -293,7 +346,10 @@ program.hook("postAction", async (_thisCommand, actionCommand) => {
293
346
  emitNotice(notice);
294
347
  }
295
348
  });
296
- program.command("init").description("Initialize a SwarmVault workspace in the current directory.").option("--obsidian", "Generate a minimal .obsidian workspace alongside the vault", false).addOption(new Option("--profile <profile>", "Starter workspace profile").choices(["default", "personal-research"])).action(async (options) => {
349
+ program.command("init").description("Initialize a SwarmVault workspace in the current directory.").option("--obsidian", "Generate a minimal .obsidian workspace alongside the vault", false).option(
350
+ "--profile <profile>",
351
+ "Starter workspace profile or comma-separated preset list (for example: personal-research or reader,timeline)"
352
+ ).action(async (options) => {
297
353
  await initVault(process2.cwd(), { obsidian: options.obsidian ?? false, profile: options.profile });
298
354
  if (isJson()) {
299
355
  emitJson({
@@ -306,8 +362,9 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
306
362
  log("Initialized SwarmVault workspace.");
307
363
  }
308
364
  });
309
- program.command("ingest").description("Ingest a local file path, directory path, or URL into the raw SwarmVault workspace.").argument("<input>", "Local file path, directory path, or URL").option("--review", "Stage a source review artifact after ingest and compile", false).option("--guide", "Stage a guided source integration bundle after ingest and compile", false).option("--include-assets", "Download remote image assets when ingesting URLs", true).option("--no-include-assets", "Skip downloading remote image assets when ingesting URLs").option("--max-asset-size <bytes>", "Maximum number of bytes to fetch for a single remote image asset").option("--repo-root <path>", "Override the detected repo root when ingesting a directory").option("--include <glob...>", "Only ingest files matching one or more glob patterns").option("--exclude <glob...>", "Skip files matching one or more glob patterns").option("--max-files <n>", "Maximum number of files to ingest from a directory").option("--include-third-party", "Also ingest repo files classified as third-party", false).option("--include-resources", "Also ingest repo files classified as resources", false).option("--include-generated", "Also ingest repo files classified as generated output", false).option("--no-gitignore", "Ignore .gitignore rules when ingesting a directory").action(
365
+ program.command("ingest").description("Ingest a local file path, directory path, or URL into the raw SwarmVault workspace.").argument("<input>", "Local file path, directory path, or URL").option("--review", "Stage a source review artifact after ingest and compile", false).option("--guide", "Stage a guided source integration bundle after ingest and compile", false).option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").option("--include-assets", "Download remote image assets when ingesting URLs", true).option("--no-include-assets", "Skip downloading remote image assets when ingesting URLs").option("--max-asset-size <bytes>", "Maximum number of bytes to fetch for a single remote image asset").option("--repo-root <path>", "Override the detected repo root when ingesting a directory").option("--include <glob...>", "Only ingest files matching one or more glob patterns").option("--exclude <glob...>", "Skip files matching one or more glob patterns").option("--max-files <n>", "Maximum number of files to ingest from a directory").option("--include-third-party", "Also ingest repo files classified as third-party", false).option("--include-resources", "Also ingest repo files classified as resources", false).option("--include-generated", "Also ingest repo files classified as generated output", false).option("--no-gitignore", "Ignore .gitignore rules when ingesting a directory").action(
310
366
  async (input, options) => {
367
+ const guideAnswers = readGuideAnswersFile(options.answersFile);
311
368
  const maxAssetSize = typeof options.maxAssetSize === "string" && options.maxAssetSize.trim() ? parsePositiveInt(options.maxAssetSize, 0) || void 0 : void 0;
312
369
  const maxFiles = typeof options.maxFiles === "string" && options.maxFiles.trim() ? parsePositiveInt(options.maxFiles, 0) || void 0 : void 0;
313
370
  const extractClasses = [
@@ -354,10 +411,13 @@ program.command("ingest").description("Ingest a local file path, directory path,
354
411
  })() : void 0;
355
412
  const guide2 = shouldStage && options.guide ? await (async () => {
356
413
  await compileVault(process2.cwd(), {});
357
- return await guideSourceScope(process2.cwd(), scope2);
414
+ return await guideSourceScope(process2.cwd(), scope2, { answers: guideAnswers });
358
415
  })() : void 0;
416
+ const completedGuide2 = guide2 && !options.answersFile ? await completeGuideInteractively(guide2, scope2?.id ?? input) : guide2;
359
417
  if (isJson()) {
360
- emitJson(guide2 ? { ingest: directoryResult, guide: guide2 } : review3 ? { ingest: directoryResult, review: review3 } : directoryResult);
418
+ emitJson(
419
+ completedGuide2 ? { ingest: directoryResult, guide: completedGuide2 } : review3 ? { ingest: directoryResult, review: review3 } : directoryResult
420
+ );
361
421
  } else {
362
422
  log(
363
423
  `Imported ${directoryResult.imported.length} file(s), updated ${directoryResult.updated.length}, skipped ${directoryResult.skipped.length}.`
@@ -365,8 +425,12 @@ program.command("ingest").description("Ingest a local file path, directory path,
365
425
  if (review3) {
366
426
  log(`Staged source review at ${review3.reviewPath}.`);
367
427
  }
368
- if (guide2) {
369
- log(`Staged source guide at ${guide2.guidePath}.`);
428
+ if (completedGuide2?.awaitingInput) {
429
+ log(
430
+ `Created guided session at ${completedGuide2.sessionPath}. Resume with \`swarmvault source session ${completedGuide2.sessionId}\`.`
431
+ );
432
+ } else if (completedGuide2?.guidePath) {
433
+ log(`Staged guided session at ${completedGuide2.guidePath}.`);
370
434
  }
371
435
  }
372
436
  return;
@@ -379,10 +443,11 @@ program.command("ingest").description("Ingest a local file path, directory path,
379
443
  })() : void 0;
380
444
  const guide = options.guide && scope && (ingest.created.length || ingest.updated.length || ingest.unchanged.length) ? await (async () => {
381
445
  await compileVault(process2.cwd(), {});
382
- return await guideSourceScope(process2.cwd(), scope);
446
+ return await guideSourceScope(process2.cwd(), scope, { answers: guideAnswers });
383
447
  })() : void 0;
448
+ const completedGuide = guide && !options.answersFile ? await completeGuideInteractively(guide, scope?.id ?? input) : guide;
384
449
  if (isJson()) {
385
- emitJson(guide ? { ingest, guide } : review2 ? { ingest, review: review2 } : ingest);
450
+ emitJson(completedGuide ? { ingest, guide: completedGuide } : review2 ? { ingest, review: review2 } : ingest);
386
451
  } else {
387
452
  const primary = [...ingest.created, ...ingest.updated, ...ingest.unchanged][0];
388
453
  if (ingest.created.length + ingest.updated.length + ingest.removed.length <= 1 && primary) {
@@ -395,8 +460,12 @@ program.command("ingest").description("Ingest a local file path, directory path,
395
460
  if (review2) {
396
461
  log(`Staged source review at ${review2.reviewPath}.`);
397
462
  }
398
- if (guide) {
399
- log(`Staged source guide at ${guide.guidePath}.`);
463
+ if (completedGuide?.awaitingInput) {
464
+ log(
465
+ `Created guided session at ${completedGuide.sessionPath}. Resume with \`swarmvault source session ${completedGuide.sessionId}\`.`
466
+ );
467
+ } else if (completedGuide?.guidePath) {
468
+ log(`Staged guided session at ${completedGuide.guidePath}.`);
400
469
  }
401
470
  }
402
471
  }
@@ -413,21 +482,26 @@ program.command("add").description("Capture supported URLs into normalized markd
413
482
  }
414
483
  });
415
484
  var source = program.command("source").description("Manage recurring local files, directories, public repos, and docs sources.");
416
- source.command("add").description("Register and sync a managed source from a local file, directory, public GitHub repo root URL, or docs hub URL.").argument("<input>", "Local file path, directory path, public GitHub repo root URL, or docs hub URL").option("--no-compile", "Register and sync without compiling the vault").option("--no-brief", "Skip source brief generation after sync").option("--review", "Stage a source review artifact after sync and compile", false).option("--guide", "Stage a guided source integration bundle after sync and compile", false).option("--max-pages <n>", "Maximum number of pages to crawl for docs sources").option("--max-depth <n>", "Maximum crawl depth for docs sources").action(
485
+ source.command("add").description("Register and sync a managed source from a local file, directory, public GitHub repo root URL, or docs hub URL.").argument("<input>", "Local file path, directory path, public GitHub repo root URL, or docs hub URL").option("--no-compile", "Register and sync without compiling the vault").option("--no-brief", "Skip source brief generation after sync").option("--review", "Stage a source review artifact after sync and compile", false).option("--guide", "Stage a guided source integration bundle after sync and compile", false).option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").option("--max-pages <n>", "Maximum number of pages to crawl for docs sources").option("--max-depth <n>", "Maximum crawl depth for docs sources").action(
417
486
  async (input, options) => {
487
+ const guideAnswers = readGuideAnswersFile(options.answersFile);
418
488
  const result = await addManagedSource(process2.cwd(), input, {
419
489
  compile: options.compile,
420
490
  brief: options.brief,
421
491
  review: options.review,
422
492
  guide: options.guide,
493
+ guideAnswers,
423
494
  maxPages: options.maxPages ? parsePositiveInt(options.maxPages, 0) || void 0 : void 0,
424
495
  maxDepth: options.maxDepth ? parsePositiveInt(options.maxDepth, 0) || void 0 : void 0
425
496
  });
497
+ if (result.guide && !options.answersFile) {
498
+ result.guide = await completeGuideInteractively(result.guide, result.source.id);
499
+ }
426
500
  if (isJson()) {
427
501
  emitJson(result);
428
502
  } else {
429
503
  log(
430
- `Registered ${result.source.kind} source ${result.source.id}. Status: ${result.source.status}.${result.compile ? ` Compiled ${result.compile.sourceCount} source(s).` : ""}${result.briefGenerated ? ` Brief: ${result.source.briefPath}` : ""}${result.review ? ` Review: ${result.review.reviewPath}` : ""}${result.guide ? ` Guide: ${result.guide.guidePath}` : ""}`
504
+ `Registered ${result.source.kind} source ${result.source.id}. Status: ${result.source.status}.${result.compile ? ` Compiled ${result.compile.sourceCount} source(s).` : ""}${result.briefGenerated ? ` Brief: ${result.source.briefPath}` : ""}${result.review ? ` Review: ${result.review.reviewPath}` : ""}${result.guide?.awaitingInput ? ` Session: ${result.guide.sessionPath}. Resume with \`swarmvault source session ${result.guide.sessionId}\`.` : result.guide?.guidePath ? ` Guide: ${result.guide.guidePath}` : ""}`
431
505
  );
432
506
  }
433
507
  }
@@ -444,8 +518,9 @@ source.command("list").description("List managed sources registered in this vaul
444
518
  }
445
519
  }
446
520
  });
447
- source.command("reload").description("Re-sync one managed source or all managed sources, then optionally compile and refresh briefs.").argument("[id]", "Managed source id").option("--all", "Reload all managed sources", false).option("--no-compile", "Re-sync without compiling the vault").option("--no-brief", "Skip source brief generation after sync").option("--review", "Stage a source review artifact after sync and compile", false).option("--guide", "Stage a guided source integration bundle after sync and compile", false).option("--max-pages <n>", "Maximum number of pages to crawl for docs sources").option("--max-depth <n>", "Maximum crawl depth for docs sources").action(
521
+ source.command("reload").description("Re-sync one managed source or all managed sources, then optionally compile and refresh briefs.").argument("[id]", "Managed source id").option("--all", "Reload all managed sources", false).option("--no-compile", "Re-sync without compiling the vault").option("--no-brief", "Skip source brief generation after sync").option("--review", "Stage a source review artifact after sync and compile", false).option("--guide", "Stage a guided source integration bundle after sync and compile", false).option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").option("--max-pages <n>", "Maximum number of pages to crawl for docs sources").option("--max-depth <n>", "Maximum crawl depth for docs sources").action(
448
522
  async (id, options) => {
523
+ const guideAnswers = readGuideAnswersFile(options.answersFile);
449
524
  const result = await reloadManagedSources(process2.cwd(), {
450
525
  id,
451
526
  all: options.all ?? false,
@@ -453,14 +528,18 @@ source.command("reload").description("Re-sync one managed source or all managed
453
528
  brief: options.brief,
454
529
  review: options.review,
455
530
  guide: options.guide,
531
+ guideAnswers,
456
532
  maxPages: options.maxPages ? parsePositiveInt(options.maxPages, 0) || void 0 : void 0,
457
533
  maxDepth: options.maxDepth ? parsePositiveInt(options.maxDepth, 0) || void 0 : void 0
458
534
  });
535
+ if (!options.answersFile && result.guides.length === 1) {
536
+ result.guides = [await completeGuideInteractively(result.guides[0], result.sources[0]?.id ?? id ?? "source")];
537
+ }
459
538
  if (isJson()) {
460
539
  emitJson(result);
461
540
  } else {
462
541
  log(
463
- `Reloaded ${result.sources.length} source(s).${result.compile ? ` Compiled ${result.compile.sourceCount} source(s).` : ""}${result.briefPaths.length ? ` Briefs: ${result.briefPaths.length}.` : ""}${result.reviews.length ? ` Reviews: ${result.reviews.length}.` : ""}${result.guides.length ? ` Guides: ${result.guides.length}.` : ""}`
542
+ `Reloaded ${result.sources.length} source(s).${result.compile ? ` Compiled ${result.compile.sourceCount} source(s).` : ""}${result.briefPaths.length ? ` Briefs: ${result.briefPaths.length}.` : ""}${result.reviews.length ? ` Reviews: ${result.reviews.length}.` : ""}${result.guides.length ? ` Guides/Sessions: ${result.guides.length}.` : ""}`
464
543
  );
465
544
  }
466
545
  }
@@ -481,12 +560,34 @@ source.command("review").description("Stage a source review artifact for a manag
481
560
  log(`Staged source review at ${result.reviewPath}.`);
482
561
  }
483
562
  });
484
- source.command("guide").description("Stage a guided source integration bundle for a managed source id or raw source id.").argument("<id>", "Managed source id or raw source id").action(async (id) => {
485
- const result = await guideManagedSource(process2.cwd(), id);
563
+ source.command("guide").description("Create or resume a guided source session for a managed source id or raw source id.").argument("<id>", "Managed source id or raw source id").option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").action(async (id, options) => {
564
+ const guideAnswers = readGuideAnswersFile(options.answersFile);
565
+ let result = await guideManagedSource(process2.cwd(), id, { answers: guideAnswers });
566
+ if (!options.answersFile) {
567
+ result = await completeGuideInteractively(result, id);
568
+ }
569
+ if (isJson()) {
570
+ emitJson(result);
571
+ } else {
572
+ if (result.awaitingInput) {
573
+ log(`Created guided session at ${result.sessionPath}. Resume with \`swarmvault source session ${result.sessionId}\`.`);
574
+ } else {
575
+ log(`Staged guided session at ${result.guidePath}.`);
576
+ }
577
+ }
578
+ });
579
+ source.command("session").description("Resume the latest guided source session for a managed source id, raw source id, source scope id, or session id.").argument("<id>", "Managed source id, raw source id, source scope id, or guided session id").option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").action(async (id, options) => {
580
+ const guideAnswers = readGuideAnswersFile(options.answersFile);
581
+ let result = await resumeSourceSession(process2.cwd(), id, { answers: guideAnswers });
582
+ if (!options.answersFile) {
583
+ result = await completeGuideInteractively(result, id);
584
+ }
486
585
  if (isJson()) {
487
586
  emitJson(result);
587
+ } else if (result.awaitingInput) {
588
+ log(`Updated guided session at ${result.sessionPath}. Resume with \`swarmvault source session ${result.sessionId}\` when ready.`);
488
589
  } else {
489
- log(`Staged source guide at ${result.guidePath}.`);
590
+ log(`Staged guided session at ${result.guidePath}.`);
490
591
  }
491
592
  });
492
593
  var inbox = program.command("inbox").description("Inbox and capture workflows.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Global CLI for SwarmVault.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,18 +37,18 @@
37
37
  "engines": {
38
38
  "node": ">=24.0.0"
39
39
  },
40
+ "scripts": {
41
+ "build": "tsup src/index.ts --format esm --dts",
42
+ "test": "vitest run",
43
+ "typecheck": "tsc --noEmit"
44
+ },
40
45
  "dependencies": {
41
- "@swarmvaultai/engine": "0.5.0",
46
+ "@swarmvaultai/engine": "0.6.1",
42
47
  "commander": "^14.0.1"
43
48
  },
44
49
  "devDependencies": {
45
50
  "@types/node": "^24.6.0",
46
51
  "tsup": "^8.5.0",
47
52
  "vitest": "^3.2.4"
48
- },
49
- "scripts": {
50
- "build": "tsup src/index.ts --format esm --dts",
51
- "test": "vitest run",
52
- "typecheck": "tsc --noEmit"
53
53
  }
54
- }
54
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 SwarmVault
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.