@versatly/workgraph 0.1.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
@@ -1,19 +1,33 @@
1
1
  import {
2
2
  bases_exports,
3
+ board_exports,
4
+ clawdapus_exports,
3
5
  command_center_exports,
6
+ integration_exports,
7
+ onboard_exports,
8
+ search_qmd_adapter_exports,
9
+ skill_exports,
10
+ trigger_exports,
11
+ workspace_exports
12
+ } from "./chunk-E3QU5Y53.js";
13
+ import {
14
+ dispatch_exports,
15
+ graph_exports,
4
16
  ledger_exports,
17
+ mcp_server_exports,
18
+ orientation_exports,
19
+ policy_exports,
20
+ query_exports,
5
21
  registry_exports,
6
- skill_exports,
7
22
  store_exports,
8
- thread_exports,
9
- workspace_exports
10
- } from "./chunk-CRQXDCPR.js";
23
+ thread_exports
24
+ } from "./chunk-65ZMX2WM.js";
11
25
 
12
26
  // src/cli.ts
13
27
  import fs from "fs";
14
28
  import path from "path";
15
29
  import { Command } from "commander";
16
- var DEFAULT_ACTOR = process.env.WORKGRAPH_AGENT || process.env.CLAWVAULT_AGENT || process.env.USER || "anonymous";
30
+ var DEFAULT_ACTOR = process.env.WORKGRAPH_AGENT || process.env.USER || "anonymous";
17
31
  var CLI_VERSION = (() => {
18
32
  try {
19
33
  const pkgUrl = new URL("../package.json", import.meta.url);
@@ -271,7 +285,7 @@ addWorkspaceOption(
271
285
  );
272
286
  var basesCmd = program.command("bases").description("Generate Obsidian .base files from primitive-registry.yaml");
273
287
  addWorkspaceOption(
274
- basesCmd.command("sync-registry").description("Sync .clawvault/primitive-registry.yaml from active registry").option("--json", "Emit structured JSON output")
288
+ basesCmd.command("sync-registry").description("Sync .workgraph/primitive-registry.yaml from active registry").option("--json", "Emit structured JSON output")
275
289
  ).action(
276
290
  (opts) => runCommand(
277
291
  opts,
@@ -280,7 +294,7 @@ addWorkspaceOption(
280
294
  const manifest = bases_exports.syncPrimitiveRegistryManifest(workspacePath);
281
295
  return {
282
296
  primitiveCount: manifest.primitives.length,
283
- manifestPath: ".clawvault/primitive-registry.yaml"
297
+ manifestPath: ".workgraph/primitive-registry.yaml"
284
298
  };
285
299
  },
286
300
  (result) => [
@@ -290,7 +304,7 @@ addWorkspaceOption(
290
304
  )
291
305
  );
292
306
  addWorkspaceOption(
293
- basesCmd.command("generate").description("Generate .base files by reading primitive-registry.yaml").option("--all", "Include non-canonical primitives").option("--refresh-registry", "Refresh primitive-registry.yaml before generation").option("--output-dir <path>", "Output directory for .base files (default: .clawvault/bases)").option("--json", "Emit structured JSON output")
307
+ basesCmd.command("generate").description("Generate .base files by reading primitive-registry.yaml").option("--all", "Include non-canonical primitives").option("--refresh-registry", "Refresh primitive-registry.yaml before generation").option("--output-dir <path>", "Output directory for .base files (default: .workgraph/bases)").option("--json", "Emit structured JSON output")
294
308
  ).action(
295
309
  (opts) => runCommand(
296
310
  opts,
@@ -330,17 +344,7 @@ addWorkspaceOption(
330
344
  opts,
331
345
  () => {
332
346
  const workspacePath = resolveWorkspacePath(opts);
333
- const fields = { title };
334
- for (const pair of opts.set ?? []) {
335
- const eqIdx = String(pair).indexOf("=");
336
- if (eqIdx === -1) continue;
337
- const key = String(pair).slice(0, eqIdx).trim();
338
- let value = String(pair).slice(eqIdx + 1).trim();
339
- if (typeof value === "string" && value.includes(",")) {
340
- value = value.split(",").map((v) => v.trim());
341
- }
342
- fields[key] = value;
343
- }
347
+ const fields = { title, ...parseSetPairs(opts.set ?? []) };
344
348
  return {
345
349
  instance: store_exports.create(workspacePath, type, fields, opts.body, opts.actor)
346
350
  };
@@ -348,9 +352,28 @@ addWorkspaceOption(
348
352
  (result) => [`Created ${result.instance.type}: ${result.instance.path}`]
349
353
  )
350
354
  );
355
+ addWorkspaceOption(
356
+ primitiveCmd.command("update <path>").description("Update an existing primitive instance").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--set <fields...>", 'Set fields as "key=value"').option("--body <text>", "Replace markdown body content").option("--body-file <path>", "Read markdown body content from file").option("--json", "Emit structured JSON output")
357
+ ).action(
358
+ (targetPath, opts) => runCommand(
359
+ opts,
360
+ () => {
361
+ const workspacePath = resolveWorkspacePath(opts);
362
+ const updates = parseSetPairs(opts.set ?? []);
363
+ let body = opts.body;
364
+ if (opts.bodyFile) {
365
+ body = fs.readFileSync(path.resolve(opts.bodyFile), "utf-8");
366
+ }
367
+ return {
368
+ instance: store_exports.update(workspacePath, targetPath, updates, body, opts.actor)
369
+ };
370
+ },
371
+ (result) => [`Updated ${result.instance.type}: ${result.instance.path}`]
372
+ )
373
+ );
351
374
  var skillCmd = program.command("skill").description("Manage native skill primitives in shared workgraph vaults");
352
375
  addWorkspaceOption(
353
- skillCmd.command("write <title>").description("Create or update a skill primitive").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--owner <name>", "Skill owner").option("--version <semver>", "Skill version").option("--status <status>", "draft | proposed | active | deprecated | archived").option("--distribution <mode>", "Distribution mode", "tailscale-shared-vault").option("--tailscale-path <path>", "Shared Tailscale workspace path").option("--reviewers <list>", "Comma-separated reviewer names").option("--tags <list>", "Comma-separated tags").option("--body <text>", "Skill markdown content").option("--body-file <path>", "Read markdown content from file").option("--json", "Emit structured JSON output")
376
+ skillCmd.command("write <title>").description("Create or update a skill primitive").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--owner <name>", "Skill owner").option("--skill-version <semver>", "Skill version").option("--status <status>", "draft | proposed | active | deprecated | archived").option("--distribution <mode>", "Distribution mode", "tailscale-shared-vault").option("--tailscale-path <path>", "Shared Tailscale workspace path").option("--reviewers <list>", "Comma-separated reviewer names").option("--depends-on <list>", "Comma-separated skill dependencies (slug/path)").option("--expected-updated-at <iso>", "Optimistic concurrency guard for updates").option("--tags <list>", "Comma-separated tags").option("--body <text>", "Skill markdown content").option("--body-file <path>", "Read markdown content from file").option("--json", "Emit structured JSON output")
354
377
  ).action(
355
378
  (title, opts) => runCommand(
356
379
  opts,
@@ -368,11 +391,13 @@ addWorkspaceOption(
368
391
  opts.actor,
369
392
  {
370
393
  owner: opts.owner,
371
- version: opts.version,
394
+ version: opts.skillVersion,
372
395
  status: opts.status,
373
396
  distribution: opts.distribution,
374
397
  tailscalePath: opts.tailscalePath,
375
398
  reviewers: csv(opts.reviewers),
399
+ dependsOn: csv(opts.dependsOn),
400
+ expectedUpdatedAt: opts.expectedUpdatedAt,
376
401
  tags: csv(opts.tags)
377
402
  }
378
403
  );
@@ -403,18 +428,54 @@ addWorkspaceOption(
403
428
  )
404
429
  );
405
430
  addWorkspaceOption(
406
- skillCmd.command("list").description("List skills").option("--status <status>", "Filter by status").option("--json", "Emit structured JSON output")
431
+ skillCmd.command("list").description("List skills").option("--status <status>", "Filter by status").option("--updated-since <iso>", "Filter by updated timestamp (ISO-8601)").option("--json", "Emit structured JSON output")
407
432
  ).action(
408
433
  (opts) => runCommand(
409
434
  opts,
410
435
  () => {
411
436
  const workspacePath = resolveWorkspacePath(opts);
412
- const skills = skill_exports.listSkills(workspacePath, { status: opts.status });
437
+ const skills = skill_exports.listSkills(workspacePath, {
438
+ status: opts.status,
439
+ updatedSince: opts.updatedSince
440
+ });
413
441
  return { skills, count: skills.length };
414
442
  },
415
443
  (result) => result.skills.map((skill) => `${String(skill.fields.title)} [${String(skill.fields.status)}] -> ${skill.path}`)
416
444
  )
417
445
  );
446
+ addWorkspaceOption(
447
+ skillCmd.command("history <skillRef>").description("Show ledger history entries for one skill").option("--limit <n>", "Limit number of returned entries").option("--json", "Emit structured JSON output")
448
+ ).action(
449
+ (skillRef, opts) => runCommand(
450
+ opts,
451
+ () => {
452
+ const workspacePath = resolveWorkspacePath(opts);
453
+ return {
454
+ entries: skill_exports.skillHistory(workspacePath, skillRef, {
455
+ limit: opts.limit ? Number.parseInt(String(opts.limit), 10) : void 0
456
+ })
457
+ };
458
+ },
459
+ (result) => result.entries.map((entry) => `${entry.ts} ${entry.op} ${entry.actor}`)
460
+ )
461
+ );
462
+ addWorkspaceOption(
463
+ skillCmd.command("diff <skillRef>").description("Show latest field-change summary for one skill").option("--json", "Emit structured JSON output")
464
+ ).action(
465
+ (skillRef, opts) => runCommand(
466
+ opts,
467
+ () => {
468
+ const workspacePath = resolveWorkspacePath(opts);
469
+ return skill_exports.skillDiff(workspacePath, skillRef);
470
+ },
471
+ (result) => [
472
+ `Skill: ${result.path}`,
473
+ `Latest: ${result.latestEntryTs ?? "none"}`,
474
+ `Previous: ${result.previousEntryTs ?? "none"}`,
475
+ `Changed fields: ${result.changedFields.join(", ") || "none"}`
476
+ ]
477
+ )
478
+ );
418
479
  addWorkspaceOption(
419
480
  skillCmd.command("propose <skillRef>").description("Move a skill into proposed state and open review thread").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--proposal-thread <path>", "Explicit proposal thread path").option("--no-create-thread", "Do not create a proposal thread automatically").option("--space <spaceRef>", "Space for created proposal thread").option("--reviewers <list>", "Comma-separated reviewers").option("--json", "Emit structured JSON output")
420
481
  ).action(
@@ -438,7 +499,7 @@ addWorkspaceOption(
438
499
  )
439
500
  );
440
501
  addWorkspaceOption(
441
- skillCmd.command("promote <skillRef>").description("Promote a proposed/draft skill to active").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--version <semver>", "Explicit promoted version").option("--json", "Emit structured JSON output")
502
+ skillCmd.command("promote <skillRef>").description("Promote a proposed/draft skill to active").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--skill-version <semver>", "Explicit promoted version").option("--json", "Emit structured JSON output")
442
503
  ).action(
443
504
  (skillRef, opts) => runCommand(
444
505
  opts,
@@ -446,7 +507,7 @@ addWorkspaceOption(
446
507
  const workspacePath = resolveWorkspacePath(opts);
447
508
  return {
448
509
  skill: skill_exports.promoteSkill(workspacePath, skillRef, opts.actor, {
449
- version: opts.version
510
+ version: opts.skillVersion
450
511
  })
451
512
  };
452
513
  },
@@ -456,6 +517,40 @@ addWorkspaceOption(
456
517
  ]
457
518
  )
458
519
  );
520
+ var integrationCmd = program.command("integration").description("Manage optional third-party integrations");
521
+ addWorkspaceOption(
522
+ integrationCmd.command("list").description("List supported optional integrations").option("--json", "Emit structured JSON output")
523
+ ).action(
524
+ (opts) => runCommand(
525
+ opts,
526
+ () => ({
527
+ integrations: integration_exports.listIntegrations()
528
+ }),
529
+ (result) => result.integrations.map((integration) => `${integration.id} (${integration.defaultTitle}) -> ${integration.defaultSourceUrl}`)
530
+ )
531
+ );
532
+ addWorkspaceOption(
533
+ integrationCmd.command("install <integrationName>").description("Install an optional integration into this workspace").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--owner <name>", "Skill owner override").option("--title <title>", "Skill title to store in workgraph").option("--source-url <url>", "Source URL override for integration content").option("--force", "Overwrite an existing imported integration skill").option("--json", "Emit structured JSON output")
534
+ ).action(
535
+ (integrationName, opts) => runCommand(
536
+ opts,
537
+ () => installNamedIntegration(resolveWorkspacePath(opts), integrationName, opts),
538
+ renderInstalledIntegrationResult
539
+ )
540
+ );
541
+ addWorkspaceOption(
542
+ integrationCmd.command("clawdapus").description("Import Clawdapus SKILL.md into this workspace").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--owner <name>", "Skill owner override").option("--title <title>", "Skill title to store in workgraph", "clawdapus").option(
543
+ "--source-url <url>",
544
+ "Source URL for Clawdapus SKILL.md",
545
+ clawdapus_exports.DEFAULT_CLAWDAPUS_SKILL_URL
546
+ ).option("--force", "Overwrite an existing imported Clawdapus skill").option("--json", "Emit structured JSON output")
547
+ ).action(
548
+ (opts) => runCommand(
549
+ opts,
550
+ () => installNamedIntegration(resolveWorkspacePath(opts), "clawdapus", opts),
551
+ renderInstalledIntegrationResult
552
+ )
553
+ );
459
554
  var ledgerCmd = program.command("ledger").description("Inspect the append-only workgraph ledger");
460
555
  addWorkspaceOption(
461
556
  ledgerCmd.command("show").description("Show recent ledger entries").option("-n, --count <n>", "Number of entries", "20").option("--actor <name>", "Filter by actor").option("--json", "Emit structured JSON output")
@@ -601,7 +696,527 @@ addWorkspaceOption(
601
696
  ]
602
697
  )
603
698
  );
604
- program.parse();
699
+ addWorkspaceOption(
700
+ program.command("status").description("Show workspace situational status snapshot").option("--json", "Emit structured JSON output")
701
+ ).action(
702
+ (opts) => runCommand(
703
+ opts,
704
+ () => {
705
+ const workspacePath = resolveWorkspacePath(opts);
706
+ return orientation_exports.statusSnapshot(workspacePath);
707
+ },
708
+ (result) => [
709
+ `Threads: total=${result.threads.total} open=${result.threads.open} active=${result.threads.active} blocked=${result.threads.blocked} done=${result.threads.done}`,
710
+ `Ready threads: ${result.threads.ready} Active claims: ${result.claims.active}`,
711
+ `Primitive types: ${Object.keys(result.primitives.byType).length}`
712
+ ]
713
+ )
714
+ );
715
+ addWorkspaceOption(
716
+ program.command("brief").description("Show actor-centric operational brief").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--recent <count>", "Recent activity count", "12").option("--next <count>", "Next ready threads to include", "5").option("--json", "Emit structured JSON output")
717
+ ).action(
718
+ (opts) => runCommand(
719
+ opts,
720
+ () => {
721
+ const workspacePath = resolveWorkspacePath(opts);
722
+ return orientation_exports.brief(workspacePath, opts.actor, {
723
+ recentCount: Number.parseInt(String(opts.recent), 10),
724
+ nextCount: Number.parseInt(String(opts.next), 10)
725
+ });
726
+ },
727
+ (result) => [
728
+ `Brief for ${result.actor}`,
729
+ `My claims: ${result.myClaims.length}`,
730
+ `Blocked threads: ${result.blockedThreads.length}`,
731
+ `Next ready: ${result.nextReadyThreads.map((item) => item.path).join(", ") || "none"}`
732
+ ]
733
+ )
734
+ );
735
+ addWorkspaceOption(
736
+ program.command("checkpoint <summary>").description("Create a checkpoint primitive for hand-off continuity").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--next <items>", "Comma-separated next actions").option("--blocked <items>", "Comma-separated blockers").option("--tags <items>", "Comma-separated tags").option("--json", "Emit structured JSON output")
737
+ ).action(
738
+ (summary, opts) => runCommand(
739
+ opts,
740
+ () => {
741
+ const workspacePath = resolveWorkspacePath(opts);
742
+ return {
743
+ checkpoint: orientation_exports.checkpoint(workspacePath, opts.actor, summary, {
744
+ next: csv(opts.next),
745
+ blocked: csv(opts.blocked),
746
+ tags: csv(opts.tags)
747
+ })
748
+ };
749
+ },
750
+ (result) => [`Created checkpoint: ${result.checkpoint.path}`]
751
+ )
752
+ );
753
+ addWorkspaceOption(
754
+ program.command("intake <observation>").description("Capture intake observation as lightweight checkpoint note").option("-a, --actor <name>", "Agent name", DEFAULT_ACTOR).option("--tags <items>", "Comma-separated tags").option("--json", "Emit structured JSON output")
755
+ ).action(
756
+ (observation, opts) => runCommand(
757
+ opts,
758
+ () => {
759
+ const workspacePath = resolveWorkspacePath(opts);
760
+ return {
761
+ intake: orientation_exports.intake(workspacePath, opts.actor, observation, {
762
+ tags: csv(opts.tags)
763
+ })
764
+ };
765
+ },
766
+ (result) => [`Captured intake: ${result.intake.path}`]
767
+ )
768
+ );
769
+ addWorkspaceOption(
770
+ program.command("query").description("Query primitive instances with multi-field filters").option("--type <type>", "Primitive type").option("--status <status>", "Status value").option("--owner <owner>", "Owner/actor value").option("--tag <tag>", "Tag filter").option("--text <text>", "Full-text contains filter").option("--path-includes <text>", "Path substring filter").option("--updated-after <iso>", "Updated at or after").option("--updated-before <iso>", "Updated at or before").option("--created-after <iso>", "Created at or after").option("--created-before <iso>", "Created at or before").option("--limit <n>", "Result limit").option("--offset <n>", "Result offset").option("--json", "Emit structured JSON output")
771
+ ).action(
772
+ (opts) => runCommand(
773
+ opts,
774
+ () => {
775
+ const workspacePath = resolveWorkspacePath(opts);
776
+ const results = query_exports.queryPrimitives(workspacePath, {
777
+ type: opts.type,
778
+ status: opts.status,
779
+ owner: opts.owner,
780
+ tag: opts.tag,
781
+ text: opts.text,
782
+ pathIncludes: opts.pathIncludes,
783
+ updatedAfter: opts.updatedAfter,
784
+ updatedBefore: opts.updatedBefore,
785
+ createdAfter: opts.createdAfter,
786
+ createdBefore: opts.createdBefore,
787
+ limit: opts.limit ? Number.parseInt(String(opts.limit), 10) : void 0,
788
+ offset: opts.offset ? Number.parseInt(String(opts.offset), 10) : void 0
789
+ });
790
+ return { results, count: results.length };
791
+ },
792
+ (result) => result.results.map((item) => `${item.type} ${item.path}`)
793
+ )
794
+ );
795
+ addWorkspaceOption(
796
+ program.command("search <text>").description("Keyword search across markdown body/frontmatter with optional QMD-compatible mode").option("--type <type>", "Limit to primitive type").option("--mode <mode>", "auto | core | qmd", "auto").option("--limit <n>", "Result limit").option("--json", "Emit structured JSON output")
797
+ ).action(
798
+ (text, opts) => runCommand(
799
+ opts,
800
+ () => {
801
+ const workspacePath = resolveWorkspacePath(opts);
802
+ const result = search_qmd_adapter_exports.search(workspacePath, text, {
803
+ mode: opts.mode,
804
+ type: opts.type,
805
+ limit: opts.limit ? Number.parseInt(String(opts.limit), 10) : void 0
806
+ });
807
+ return {
808
+ ...result,
809
+ count: result.results.length
810
+ };
811
+ },
812
+ (result) => [
813
+ `Mode: ${result.mode}`,
814
+ ...result.fallbackReason ? [`Note: ${result.fallbackReason}`] : [],
815
+ ...result.results.map((item) => `${item.type} ${item.path}`)
816
+ ]
817
+ )
818
+ );
819
+ var boardCmd = program.command("board").description("Generate and sync Obsidian Kanban board views");
820
+ addWorkspaceOption(
821
+ boardCmd.command("generate").description("Generate Obsidian Kanban board markdown from thread states").option("-o, --output <path>", "Output board path", "ops/Workgraph Board.md").option("--include-cancelled", "Include cancelled lane").option("--json", "Emit structured JSON output")
822
+ ).action(
823
+ (opts) => runCommand(
824
+ opts,
825
+ () => {
826
+ const workspacePath = resolveWorkspacePath(opts);
827
+ return board_exports.generateKanbanBoard(workspacePath, {
828
+ outputPath: opts.output,
829
+ includeCancelled: !!opts.includeCancelled
830
+ });
831
+ },
832
+ (result) => [
833
+ `Generated board: ${result.outputPath}`,
834
+ `Backlog=${result.counts.backlog} InProgress=${result.counts.inProgress} Blocked=${result.counts.blocked} Done=${result.counts.done}`
835
+ ]
836
+ )
837
+ );
838
+ addWorkspaceOption(
839
+ boardCmd.command("sync").description("Sync existing board markdown from current thread states").option("-o, --output <path>", "Output board path", "ops/Workgraph Board.md").option("--include-cancelled", "Include cancelled lane").option("--json", "Emit structured JSON output")
840
+ ).action(
841
+ (opts) => runCommand(
842
+ opts,
843
+ () => {
844
+ const workspacePath = resolveWorkspacePath(opts);
845
+ return board_exports.syncKanbanBoard(workspacePath, {
846
+ outputPath: opts.output,
847
+ includeCancelled: !!opts.includeCancelled
848
+ });
849
+ },
850
+ (result) => [
851
+ `Synced board: ${result.outputPath}`,
852
+ `Backlog=${result.counts.backlog} InProgress=${result.counts.inProgress} Blocked=${result.counts.blocked} Done=${result.counts.done}`
853
+ ]
854
+ )
855
+ );
856
+ var graphCmd = program.command("graph").description("Wiki-link graph indexing and hygiene");
857
+ addWorkspaceOption(
858
+ graphCmd.command("index").description("Build wiki-link graph index").option("--json", "Emit structured JSON output")
859
+ ).action(
860
+ (opts) => runCommand(
861
+ opts,
862
+ () => {
863
+ const workspacePath = resolveWorkspacePath(opts);
864
+ return graph_exports.refreshWikiLinkGraphIndex(workspacePath);
865
+ },
866
+ (result) => [
867
+ `Nodes: ${result.nodes.length}`,
868
+ `Edges: ${result.edges.length}`,
869
+ `Broken links: ${result.brokenLinks.length}`
870
+ ]
871
+ )
872
+ );
873
+ addWorkspaceOption(
874
+ graphCmd.command("hygiene").description("Generate graph hygiene report (orphans, broken links, hubs)").option("--json", "Emit structured JSON output")
875
+ ).action(
876
+ (opts) => runCommand(
877
+ opts,
878
+ () => {
879
+ const workspacePath = resolveWorkspacePath(opts);
880
+ return graph_exports.graphHygieneReport(workspacePath);
881
+ },
882
+ (result) => [
883
+ `Nodes=${result.nodeCount} Edges=${result.edgeCount}`,
884
+ `Orphans=${result.orphanCount} BrokenLinks=${result.brokenLinkCount}`,
885
+ `Top hub: ${result.hubs[0]?.node ?? "none"}`
886
+ ]
887
+ )
888
+ );
889
+ addWorkspaceOption(
890
+ graphCmd.command("neighbors <nodePath>").description("Query incoming/outgoing wiki-link neighbors for one node").option("--refresh", "Refresh graph index before querying").option("--json", "Emit structured JSON output")
891
+ ).action(
892
+ (nodePath, opts) => runCommand(
893
+ opts,
894
+ () => {
895
+ const workspacePath = resolveWorkspacePath(opts);
896
+ return graph_exports.graphNeighborhood(workspacePath, nodePath, {
897
+ refresh: !!opts.refresh
898
+ });
899
+ },
900
+ (result) => [
901
+ `Node: ${result.node} (${result.exists ? "exists" : "missing"})`,
902
+ `Outgoing: ${result.outgoing.length}`,
903
+ `Incoming: ${result.incoming.length}`
904
+ ]
905
+ )
906
+ );
907
+ var policyCmd = program.command("policy").description("Manage policy parties and capabilities");
908
+ var policyPartyCmd = policyCmd.command("party").description("Manage registered policy parties");
909
+ addWorkspaceOption(
910
+ policyPartyCmd.command("upsert <id>").description("Create or update a policy party").option("--roles <roles>", "Comma-separated roles").option("--capabilities <caps>", "Comma-separated capabilities").option("--json", "Emit structured JSON output")
911
+ ).action(
912
+ (id, opts) => runCommand(
913
+ opts,
914
+ () => {
915
+ const workspacePath = resolveWorkspacePath(opts);
916
+ return {
917
+ party: policy_exports.upsertParty(workspacePath, id, {
918
+ roles: csv(opts.roles),
919
+ capabilities: csv(opts.capabilities)
920
+ })
921
+ };
922
+ },
923
+ (result) => [`Upserted policy party: ${result.party.id}`]
924
+ )
925
+ );
926
+ addWorkspaceOption(
927
+ policyPartyCmd.command("get <id>").description("Get one policy party").option("--json", "Emit structured JSON output")
928
+ ).action(
929
+ (id, opts) => runCommand(
930
+ opts,
931
+ () => {
932
+ const workspacePath = resolveWorkspacePath(opts);
933
+ const party = policy_exports.getParty(workspacePath, id);
934
+ if (!party) throw new Error(`Policy party not found: ${id}`);
935
+ return { party };
936
+ },
937
+ (result) => [`${result.party.id} roles=${result.party.roles.join(",")}`]
938
+ )
939
+ );
940
+ addWorkspaceOption(
941
+ policyPartyCmd.command("list").description("List policy parties").option("--json", "Emit structured JSON output")
942
+ ).action(
943
+ (opts) => runCommand(
944
+ opts,
945
+ () => {
946
+ const workspacePath = resolveWorkspacePath(opts);
947
+ const registry = policy_exports.loadPolicyRegistry(workspacePath);
948
+ return {
949
+ parties: Object.values(registry.parties)
950
+ };
951
+ },
952
+ (result) => result.parties.map((party) => `${party.id} [${party.roles.join(", ")}]`)
953
+ )
954
+ );
955
+ var dispatchCmd = program.command("dispatch").description("Programmatic runtime dispatch contract");
956
+ addWorkspaceOption(
957
+ dispatchCmd.command("create <objective>").description("Create a new run dispatch request").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--adapter <name>", "Adapter name", "cursor-cloud").option("--idempotency-key <key>", "Idempotency key").option("--json", "Emit structured JSON output")
958
+ ).action(
959
+ (objective, opts) => runCommand(
960
+ opts,
961
+ () => {
962
+ const workspacePath = resolveWorkspacePath(opts);
963
+ return {
964
+ run: dispatch_exports.createRun(workspacePath, {
965
+ actor: opts.actor,
966
+ adapter: opts.adapter,
967
+ objective,
968
+ idempotencyKey: opts.idempotencyKey
969
+ })
970
+ };
971
+ },
972
+ (result) => [`Run created: ${result.run.id} [${result.run.status}]`]
973
+ )
974
+ );
975
+ addWorkspaceOption(
976
+ dispatchCmd.command("create-execute <objective>").description("Create and execute a run with autonomous multi-agent coordination").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--adapter <name>", "Adapter name", "cursor-cloud").option("--idempotency-key <key>", "Idempotency key").option("--agents <actors>", "Comma-separated agent identities for autonomous execution").option("--max-steps <n>", "Maximum scheduler steps", "200").option("--step-delay-ms <ms>", "Delay between scheduling steps", "25").option("--space <spaceRef>", "Restrict execution to one space").option("--no-checkpoint", "Skip automatic checkpoint generation after execution").option("--json", "Emit structured JSON output")
977
+ ).action(
978
+ (objective, opts) => runCommand(
979
+ opts,
980
+ async () => {
981
+ const workspacePath = resolveWorkspacePath(opts);
982
+ return {
983
+ run: await dispatch_exports.createAndExecuteRun(
984
+ workspacePath,
985
+ {
986
+ actor: opts.actor,
987
+ adapter: opts.adapter,
988
+ objective,
989
+ idempotencyKey: opts.idempotencyKey
990
+ },
991
+ {
992
+ agents: csv(opts.agents),
993
+ maxSteps: Number.parseInt(String(opts.maxSteps), 10),
994
+ stepDelayMs: Number.parseInt(String(opts.stepDelayMs), 10),
995
+ space: opts.space,
996
+ createCheckpoint: opts.checkpoint
997
+ }
998
+ )
999
+ };
1000
+ },
1001
+ (result) => [
1002
+ `Run executed: ${result.run.id} [${result.run.status}]`,
1003
+ ...result.run.output ? [`Output: ${result.run.output}`] : [],
1004
+ ...result.run.error ? [`Error: ${result.run.error}`] : []
1005
+ ]
1006
+ )
1007
+ );
1008
+ addWorkspaceOption(
1009
+ dispatchCmd.command("list").description("List runs").option("--status <status>", "queued|running|succeeded|failed|cancelled").option("--limit <n>", "Result limit").option("--json", "Emit structured JSON output")
1010
+ ).action(
1011
+ (opts) => runCommand(
1012
+ opts,
1013
+ () => {
1014
+ const workspacePath = resolveWorkspacePath(opts);
1015
+ return {
1016
+ runs: dispatch_exports.listRuns(workspacePath, {
1017
+ status: opts.status,
1018
+ limit: opts.limit ? Number.parseInt(String(opts.limit), 10) : void 0
1019
+ })
1020
+ };
1021
+ },
1022
+ (result) => result.runs.map((run) => `${run.id} [${run.status}] ${run.objective}`)
1023
+ )
1024
+ );
1025
+ addWorkspaceOption(
1026
+ dispatchCmd.command("status <runId>").description("Get run status by ID").option("--json", "Emit structured JSON output")
1027
+ ).action(
1028
+ (runId, opts) => runCommand(
1029
+ opts,
1030
+ () => {
1031
+ const workspacePath = resolveWorkspacePath(opts);
1032
+ return {
1033
+ run: dispatch_exports.status(workspacePath, runId)
1034
+ };
1035
+ },
1036
+ (result) => [`${result.run.id} [${result.run.status}]`]
1037
+ )
1038
+ );
1039
+ addWorkspaceOption(
1040
+ dispatchCmd.command("execute <runId>").description("Execute a queued/running run via adapter autonomous scheduling").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--agents <actors>", "Comma-separated agent identities").option("--max-steps <n>", "Maximum scheduler steps", "200").option("--step-delay-ms <ms>", "Delay between scheduling steps", "25").option("--space <spaceRef>", "Restrict execution to one space").option("--no-checkpoint", "Skip automatic checkpoint generation after execution").option("--json", "Emit structured JSON output")
1041
+ ).action(
1042
+ (runId, opts) => runCommand(
1043
+ opts,
1044
+ async () => {
1045
+ const workspacePath = resolveWorkspacePath(opts);
1046
+ return {
1047
+ run: await dispatch_exports.executeRun(workspacePath, runId, {
1048
+ actor: opts.actor,
1049
+ agents: csv(opts.agents),
1050
+ maxSteps: Number.parseInt(String(opts.maxSteps), 10),
1051
+ stepDelayMs: Number.parseInt(String(opts.stepDelayMs), 10),
1052
+ space: opts.space,
1053
+ createCheckpoint: opts.checkpoint
1054
+ })
1055
+ };
1056
+ },
1057
+ (result) => [
1058
+ `Run executed: ${result.run.id} [${result.run.status}]`,
1059
+ ...result.run.output ? [`Output: ${result.run.output}`] : [],
1060
+ ...result.run.error ? [`Error: ${result.run.error}`] : []
1061
+ ]
1062
+ )
1063
+ );
1064
+ addWorkspaceOption(
1065
+ dispatchCmd.command("followup <runId> <input>").description("Send follow-up input to a run").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--json", "Emit structured JSON output")
1066
+ ).action(
1067
+ (runId, input, opts) => runCommand(
1068
+ opts,
1069
+ () => {
1070
+ const workspacePath = resolveWorkspacePath(opts);
1071
+ return {
1072
+ run: dispatch_exports.followup(workspacePath, runId, opts.actor, input)
1073
+ };
1074
+ },
1075
+ (result) => [`Follow-up recorded: ${result.run.id} [${result.run.status}]`]
1076
+ )
1077
+ );
1078
+ addWorkspaceOption(
1079
+ dispatchCmd.command("stop <runId>").description("Cancel a run").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--json", "Emit structured JSON output")
1080
+ ).action(
1081
+ (runId, opts) => runCommand(
1082
+ opts,
1083
+ () => {
1084
+ const workspacePath = resolveWorkspacePath(opts);
1085
+ return {
1086
+ run: dispatch_exports.stop(workspacePath, runId, opts.actor)
1087
+ };
1088
+ },
1089
+ (result) => [`Stopped run: ${result.run.id} [${result.run.status}]`]
1090
+ )
1091
+ );
1092
+ addWorkspaceOption(
1093
+ dispatchCmd.command("mark <runId>").description("Set run status transition explicitly").requiredOption("--status <status>", "running|succeeded|failed|cancelled").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--output <text>", "Optional output payload").option("--error <text>", "Optional error payload").option("--json", "Emit structured JSON output")
1094
+ ).action(
1095
+ (runId, opts) => runCommand(
1096
+ opts,
1097
+ () => {
1098
+ const workspacePath = resolveWorkspacePath(opts);
1099
+ const status = normalizeRunStatus(opts.status);
1100
+ return {
1101
+ run: dispatch_exports.markRun(workspacePath, runId, opts.actor, status, {
1102
+ output: opts.output,
1103
+ error: opts.error
1104
+ })
1105
+ };
1106
+ },
1107
+ (result) => [`Marked run: ${result.run.id} [${result.run.status}]`]
1108
+ )
1109
+ );
1110
+ addWorkspaceOption(
1111
+ dispatchCmd.command("logs <runId>").description("Read logs from a run").option("--json", "Emit structured JSON output")
1112
+ ).action(
1113
+ (runId, opts) => runCommand(
1114
+ opts,
1115
+ () => {
1116
+ const workspacePath = resolveWorkspacePath(opts);
1117
+ return {
1118
+ runId,
1119
+ logs: dispatch_exports.logs(workspacePath, runId)
1120
+ };
1121
+ },
1122
+ (result) => result.logs.map((entry) => `${entry.ts} [${entry.level}] ${entry.message}`)
1123
+ )
1124
+ );
1125
+ var triggerCmd = program.command("trigger").description("Trigger primitives and run dispatch lifecycle");
1126
+ addWorkspaceOption(
1127
+ triggerCmd.command("fire <triggerPath>").description("Fire an approved/active trigger and dispatch a run").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--event-key <key>", "Deterministic event key for idempotency").option("--objective <text>", "Override run objective").option("--json", "Emit structured JSON output")
1128
+ ).action(
1129
+ (triggerPath, opts) => runCommand(
1130
+ opts,
1131
+ () => {
1132
+ const workspacePath = resolveWorkspacePath(opts);
1133
+ return trigger_exports.fireTrigger(workspacePath, triggerPath, {
1134
+ actor: opts.actor,
1135
+ eventKey: opts.eventKey,
1136
+ objective: opts.objective
1137
+ });
1138
+ },
1139
+ (result) => [
1140
+ `Fired trigger: ${result.triggerPath}`,
1141
+ `Run: ${result.run.id} [${result.run.status}]`
1142
+ ]
1143
+ )
1144
+ );
1145
+ addWorkspaceOption(
1146
+ program.command("onboard").description("Guided agent-first workspace setup and starter artifacts").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--spaces <list>", "Comma-separated space names").option("--no-demo-threads", "Skip starter onboarding threads").option("--json", "Emit structured JSON output")
1147
+ ).action(
1148
+ (opts) => runCommand(
1149
+ opts,
1150
+ () => {
1151
+ const workspacePath = resolveWorkspacePath(opts);
1152
+ return onboard_exports.onboardWorkspace(workspacePath, {
1153
+ actor: opts.actor,
1154
+ spaces: csv(opts.spaces),
1155
+ createDemoThreads: opts.demoThreads
1156
+ });
1157
+ },
1158
+ (result) => [
1159
+ `Onboarded actor: ${result.actor}`,
1160
+ `Spaces created: ${result.spacesCreated.length}`,
1161
+ `Threads created: ${result.threadsCreated.length}`,
1162
+ `Board: ${result.boardPath}`,
1163
+ `Command center: ${result.commandCenterPath}`,
1164
+ `Onboarding primitive: ${result.onboardingPath}`
1165
+ ]
1166
+ )
1167
+ );
1168
+ var onboardingCmd = program.command("onboarding").description("Manage onboarding primitive lifecycle");
1169
+ addWorkspaceOption(
1170
+ onboardingCmd.command("show <onboardingPath>").description("Show one onboarding primitive").option("--json", "Emit structured JSON output")
1171
+ ).action(
1172
+ (onboardingPath, opts) => runCommand(
1173
+ opts,
1174
+ () => {
1175
+ const workspacePath = resolveWorkspacePath(opts);
1176
+ const onboarding = store_exports.read(workspacePath, onboardingPath);
1177
+ if (!onboarding) throw new Error(`Onboarding primitive not found: ${onboardingPath}`);
1178
+ if (onboarding.type !== "onboarding") throw new Error(`Target is not onboarding primitive: ${onboardingPath}`);
1179
+ return { onboarding };
1180
+ },
1181
+ (result) => [
1182
+ `Onboarding: ${result.onboarding.path}`,
1183
+ `Status: ${String(result.onboarding.fields.status)}`,
1184
+ `Actor: ${String(result.onboarding.fields.actor)}`
1185
+ ]
1186
+ )
1187
+ );
1188
+ addWorkspaceOption(
1189
+ onboardingCmd.command("update <onboardingPath>").description("Update onboarding lifecycle status").requiredOption("--status <status>", "active|paused|completed").option("-a, --actor <name>", "Actor", DEFAULT_ACTOR).option("--json", "Emit structured JSON output")
1190
+ ).action(
1191
+ (onboardingPath, opts) => runCommand(
1192
+ opts,
1193
+ () => {
1194
+ const workspacePath = resolveWorkspacePath(opts);
1195
+ return {
1196
+ onboarding: onboard_exports.updateOnboardingStatus(
1197
+ workspacePath,
1198
+ onboardingPath,
1199
+ normalizeOnboardingStatus(opts.status),
1200
+ opts.actor
1201
+ )
1202
+ };
1203
+ },
1204
+ (result) => [`Updated onboarding: ${result.onboarding.path} [${String(result.onboarding.fields.status)}]`]
1205
+ )
1206
+ );
1207
+ var mcpCmd = program.command("mcp").description("Run Workgraph MCP server");
1208
+ addWorkspaceOption(
1209
+ mcpCmd.command("serve").description("Serve stdio MCP tools/resources for this workspace").option("-a, --actor <name>", "Default actor for MCP write tools", DEFAULT_ACTOR).option("--read-only", "Disable all MCP write tools")
1210
+ ).action(async (opts) => {
1211
+ const workspacePath = resolveWorkspacePath(opts);
1212
+ console.error(`Starting MCP server for workspace: ${workspacePath}`);
1213
+ await mcp_server_exports.startWorkgraphMcpServer({
1214
+ workspacePath,
1215
+ defaultActor: opts.actor,
1216
+ readOnly: !!opts.readOnly
1217
+ });
1218
+ });
1219
+ await program.parseAsync();
605
1220
  function addWorkspaceOption(command) {
606
1221
  return command.option("-w, --workspace <path>", "Workgraph workspace path").option("--vault <path>", "Alias for --workspace").option("--shared-vault <path>", "Shared vault path (e.g. mounted via Tailscale)");
607
1222
  }
@@ -610,21 +1225,82 @@ function resolveWorkspacePath(opts) {
610
1225
  if (explicit) return path.resolve(explicit);
611
1226
  if (process.env.WORKGRAPH_SHARED_VAULT) return path.resolve(process.env.WORKGRAPH_SHARED_VAULT);
612
1227
  if (process.env.WORKGRAPH_PATH) return path.resolve(process.env.WORKGRAPH_PATH);
613
- if (process.env.CLAWVAULT_PATH) return path.resolve(process.env.CLAWVAULT_PATH);
614
1228
  return process.cwd();
615
1229
  }
1230
+ function parseSetPairs(pairs) {
1231
+ const fields = {};
1232
+ for (const pair of pairs) {
1233
+ const eqIdx = String(pair).indexOf("=");
1234
+ if (eqIdx === -1) continue;
1235
+ const key = String(pair).slice(0, eqIdx).trim();
1236
+ const raw = String(pair).slice(eqIdx + 1).trim();
1237
+ if (!key) continue;
1238
+ fields[key] = parseScalar(raw);
1239
+ }
1240
+ return fields;
1241
+ }
616
1242
  function csv(value) {
617
1243
  if (!value) return void 0;
618
1244
  return String(value).split(",").map((s) => s.trim()).filter(Boolean);
619
1245
  }
1246
+ function installNamedIntegration(workspacePath, integrationName, opts) {
1247
+ return integration_exports.installIntegration(workspacePath, integrationName, {
1248
+ actor: opts.actor,
1249
+ owner: opts.owner,
1250
+ title: opts.title,
1251
+ sourceUrl: opts.sourceUrl,
1252
+ force: !!opts.force
1253
+ });
1254
+ }
1255
+ function renderInstalledIntegrationResult(result) {
1256
+ return [
1257
+ `${result.replacedExisting ? "Updated" : "Installed"} ${result.provider} integration skill: ${result.skill.path}`,
1258
+ `Source: ${result.sourceUrl}`,
1259
+ `Status: ${String(result.skill.fields.status)}`
1260
+ ];
1261
+ }
1262
+ function parseScalar(value) {
1263
+ if (value === "true") return true;
1264
+ if (value === "false") return false;
1265
+ if (value === "null") return null;
1266
+ if (value === "") return "";
1267
+ if (/^-?\d+(\.\d+)?$/.test(value)) return Number(value);
1268
+ if (value.startsWith("[") && value.endsWith("]")) {
1269
+ const inner = value.slice(1, -1).trim();
1270
+ if (!inner) return [];
1271
+ return inner.split(",").map((item) => parseScalar(item.trim()));
1272
+ }
1273
+ if (value.includes(",")) {
1274
+ return value.split(",").map((item) => parseScalar(item.trim()));
1275
+ }
1276
+ try {
1277
+ return JSON.parse(value);
1278
+ } catch {
1279
+ return value;
1280
+ }
1281
+ }
1282
+ function normalizeRunStatus(status) {
1283
+ const normalized = String(status).toLowerCase();
1284
+ if (normalized === "running" || normalized === "succeeded" || normalized === "failed" || normalized === "cancelled") {
1285
+ return normalized;
1286
+ }
1287
+ throw new Error(`Invalid run status "${status}". Expected running|succeeded|failed|cancelled.`);
1288
+ }
1289
+ function normalizeOnboardingStatus(status) {
1290
+ const normalized = String(status).toLowerCase();
1291
+ if (normalized === "active" || normalized === "paused" || normalized === "completed") {
1292
+ return normalized;
1293
+ }
1294
+ throw new Error(`Invalid onboarding status "${status}". Expected active|paused|completed.`);
1295
+ }
620
1296
  function wantsJson(opts) {
621
1297
  if (opts.json) return true;
622
1298
  if (process.env.WORKGRAPH_JSON === "1") return true;
623
1299
  return false;
624
1300
  }
625
- function runCommand(opts, action, renderText) {
1301
+ async function runCommand(opts, action, renderText) {
626
1302
  try {
627
- const result = action();
1303
+ const result = await action();
628
1304
  if (wantsJson(opts)) {
629
1305
  console.log(JSON.stringify({ ok: true, data: result }, null, 2));
630
1306
  return;