@hraness/wordcell 0.22.0 → 0.22.2

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 (46) hide show
  1. package/README.md +40 -17
  2. package/dist/authoring.js +5 -3
  3. package/dist/{authority-1pgftmwq.js → authority-06eqhqam.js} +2 -2
  4. package/dist/benchmark.js +3 -3
  5. package/dist/cli.js +15 -15
  6. package/dist/evaluation-builder.js +10 -10
  7. package/dist/evaluation-kb.js +10 -10
  8. package/dist/graph-authority.js +4 -4
  9. package/dist/graph-percolation.js +6 -6
  10. package/dist/graph.js +1 -1
  11. package/dist/{index-e6p9e926.js → index-1k595z6v.js} +2 -2
  12. package/dist/{index-1tm7bgx7.js → index-233z9wmn.js} +1 -1
  13. package/dist/{index-a6kbv718.js → index-76dbn6pe.js} +1 -1
  14. package/dist/{index-avbce90h.js → index-bqtqeak3.js} +4 -4
  15. package/dist/{index-4ag64rc1.js → index-bw2r37z9.js} +74 -19
  16. package/dist/{index-t2bs9xdr.js → index-djrcc1yf.js} +4 -4
  17. package/dist/{index-6sw24nvv.js → index-ecqpgr5y.js} +53 -2
  18. package/dist/{index-0dqfnrz9.js → index-hmw17zaa.js} +2 -2
  19. package/dist/{index-nd6nynv2.js → index-jk1sgx36.js} +1 -1
  20. package/dist/{index-qwgsmtsz.js → index-n386evxj.js} +1 -1
  21. package/dist/{index-2hf27mws.js → index-q7tbg07z.js} +7 -7
  22. package/dist/{index-ekpwvbra.js → index-qbssx940.js} +1 -2
  23. package/dist/{index-hcw140eb.js → index-rr9kzq4n.js} +2 -2
  24. package/dist/{index-11621h23.js → index-tf4wzjew.js} +1 -1
  25. package/dist/{index-gm9t95d9.js → index-vnybgywh.js} +1 -1
  26. package/dist/{index-famy7fhs.js → index-xv80vzfp.js} +4 -4
  27. package/dist/index.js +16 -14
  28. package/dist/percolate.js +2 -2
  29. package/dist/portfolio.js +10 -10
  30. package/dist/publish.js +3 -3
  31. package/dist/sdk.js +9 -9
  32. package/dist/search.js +2 -2
  33. package/dist/semantic.js +4 -4
  34. package/dist/{support-mywv1em0.js → support-p452p9c4.js} +15 -15
  35. package/dist/workflows/decision-context.js +10 -10
  36. package/dist/workflows/index.js +10 -10
  37. package/package.json +7 -6
  38. package/skills/wordcell/SKILL.md +2 -2
  39. package/skills/wordcell/references/publish.md +34 -0
  40. package/skills/wordcell/references/refresh.md +14 -0
  41. package/src/authoring-model.ts +29 -0
  42. package/src/authoring-program.ts +38 -3
  43. package/src/authoring.ts +17 -3
  44. package/src/cli-program.ts +95 -4
  45. package/src/graph.ts +1 -1
  46. package/src/support-profile.ts +1 -1
@@ -122,10 +122,14 @@ import {
122
122
  type QuerySort,
123
123
  } from "./query.js";
124
124
  import {
125
+ auditRepositoryMemoryScopes,
125
126
  buildRepositoryMemoryContext,
127
+ MAX_REPOSITORY_MEMORY_DETAIL_LIMIT,
126
128
  MAX_REPOSITORY_SCOPES,
127
129
  repositoryMemoryGroupKeys,
128
130
  type RepositoryMemoryContext,
131
+ type RepositoryMemoryScopeAudit,
132
+ type RepositoryMemoryScopeAuditError,
129
133
  } from "./repository-memory.js";
130
134
  import { validateSearchQuery } from "./search.js";
131
135
  import {
@@ -226,7 +230,7 @@ async function loadSearchRulesFile(path: string): Promise<SearchRulesV1> {
226
230
  return parseSearchRules(input);
227
231
  }
228
232
 
229
- export const usage = `wordcell — a local knowledge base for coding agents
233
+ export const usage = `wordcell — a local Markdown knowledge base with superpowers
230
234
 
231
235
  Start here (no account or model needed):
232
236
  wordcell init kb
@@ -248,7 +252,7 @@ Usage:
248
252
  wordcell inspect <url> [capture options]
249
253
  wordcell pdf <file-or-url> [PDF options]
250
254
  wordcell refresh [--root <directory>] [--index <path>] [--json]
251
- wordcell check [--root <directory>] [--index <path>] [--no-catalog] [--json]
255
+ wordcell check [--root <directory>] [--index <path>] [--no-catalog] [--repo <repository>] [--json]
252
256
  wordcell catalog [--root <directory>] [--index <path>] [--json]
253
257
  wordcell graph [--root <directory>] [--index <path>] [--json]
254
258
  wordcell graph rebuild [--fresh] [--root <directory>] [--index <path>] [--json]
@@ -443,6 +447,8 @@ type ParsedCommand =
443
447
  readonly depth?: number;
444
448
  readonly limit?: number;
445
449
  readonly noCatalog?: boolean;
450
+ /** `check --repo` only: repository working tree for the advisory scope lane. */
451
+ readonly repository?: string;
446
452
  }
447
453
  | {
448
454
  readonly kind: "note-create";
@@ -528,6 +534,7 @@ type CliDependencies = GraphCliDependencies & {
528
534
  readonly percolateWithGraph?: typeof percolateWithGraph;
529
535
  readonly inspectAgentContextRepository?: typeof inspectAgentContextRepository;
530
536
  readonly buildRepositoryMemoryContext?: typeof buildRepositoryMemoryContext;
537
+ readonly auditRepositoryMemoryScopes?: typeof auditRepositoryMemoryScopes;
531
538
  readonly auditAgentGuideRepository?: typeof auditAgentGuideRepository;
532
539
  readonly validateMarkdownAttachments?: typeof validateMarkdownAttachments;
533
540
  readonly publishVault?: typeof publishVault;
@@ -623,6 +630,7 @@ function parseVaultCommand(command: VaultCommand, arguments_: readonly string[])
623
630
  let depth = 1;
624
631
  let limit: number | undefined;
625
632
  let noCatalog = false;
633
+ let repository: string | undefined;
626
634
  const positional: string[] = [];
627
635
 
628
636
  for (let cursor = 0; cursor < arguments_.length; cursor += 1) {
@@ -636,6 +644,13 @@ function parseVaultCommand(command: VaultCommand, arguments_: readonly string[])
636
644
  noCatalog = true;
637
645
  continue;
638
646
  }
647
+ if (argument === "--repo" && command === "check") {
648
+ const value = readValue(arguments_, cursor);
649
+ if (value === null) return { ok: false, message: "--repo requires a value" };
650
+ repository = value;
651
+ cursor += 1;
652
+ continue;
653
+ }
639
654
  if (argument === "--root" || argument === "--index") {
640
655
  const value = readValue(arguments_, cursor);
641
656
  if (value === null) return { ok: false, message: `${argument} requires a value` };
@@ -700,6 +715,7 @@ function parseVaultCommand(command: VaultCommand, arguments_: readonly string[])
700
715
  options: index === undefined ? {} : { index },
701
716
  json,
702
717
  ...(command === "check" && noCatalog ? { noCatalog: true } : {}),
718
+ ...(command === "check" && repository !== undefined ? { repository } : {}),
703
719
  },
704
720
  };
705
721
  }
@@ -2637,6 +2653,7 @@ function summary(
2637
2653
  options: {
2638
2654
  readonly noCatalog?: boolean;
2639
2655
  readonly attachments?: AttachmentValidationReport;
2656
+ readonly repositoryScopes?: RepositoryMemoryScopeAudit;
2640
2657
  } = {},
2641
2658
  ): Record<string, unknown> {
2642
2659
  return {
@@ -2662,6 +2679,9 @@ function summary(
2662
2679
  issues: options.attachments.issues,
2663
2680
  },
2664
2681
  }),
2682
+ ...(options.repositoryScopes === undefined
2683
+ ? {}
2684
+ : { repositoryScopes: options.repositoryScopes }),
2665
2685
  };
2666
2686
  }
2667
2687
 
@@ -2697,6 +2717,60 @@ function renderAdvisories(analysis: VaultAnalysis): string[] {
2697
2717
  return lines;
2698
2718
  }
2699
2719
 
2720
+ function renderRepositoryScopeAuditError(error: RepositoryMemoryScopeAuditError): string {
2721
+ if (error.kind === "invalid-record") {
2722
+ return `${safe(error.path)}: ${error.issues.map(safe).join(" ")}`;
2723
+ }
2724
+ const declared = error.recordPaths.map(safe).join(", ")
2725
+ + (error.recordPathsTruncated ? ", …" : "");
2726
+ return `${safe(error.scope)}: ${safe(error.state.reason)} at ${safe(error.state.path)}`
2727
+ + ` (declared by ${declared})`;
2728
+ }
2729
+
2730
+ /**
2731
+ * Advisory repository-state lane for `check --repo`.
2732
+ *
2733
+ * Every line derives from authored `repository_scopes` declarations and the
2734
+ * working tree they name. Nothing here changes the exit code: a current note
2735
+ * that names a path the repository no longer has is reported for a reader to
2736
+ * judge, never treated as a vault correctness failure.
2737
+ */
2738
+ function renderRepositoryScopeAudit(audit: RepositoryMemoryScopeAudit): string[] {
2739
+ const { counts } = audit;
2740
+ const lines = [
2741
+ `Repository scopes: ${counts.authoredRecords} declaring note${counts.authoredRecords === 1 ? "" : "s"}; `
2742
+ + `${counts.distinctScopes} distinct scope${counts.distinctScopes === 1 ? "" : "s"} `
2743
+ + `(${counts.presentScopes} present, ${counts.absentScopes} absent, ${counts.invalidScopes} unusable).`,
2744
+ ];
2745
+ if (audit.advisories.total > 0) {
2746
+ lines.push(audit.advisories.total === 1
2747
+ ? "Advisory: 1 current note declares a repository path that no longer exists."
2748
+ : `Advisory: ${audit.advisories.total} current notes declare repository paths that no longer exist.`);
2749
+ for (const advisory of audit.advisories.details) {
2750
+ lines.push(` ${safe(advisory.path)} declares absent scope ${safe(advisory.scope)}`);
2751
+ }
2752
+ if (audit.advisories.truncated) {
2753
+ lines.push(
2754
+ ` … ${audit.advisories.total - audit.advisories.returned} more; rerun with --json for the complete audit.`,
2755
+ );
2756
+ }
2757
+ }
2758
+ if (audit.errors.total > 0) {
2759
+ lines.push(
2760
+ `Advisory: ${audit.errors.total} repository scope declaration problem${audit.errors.total === 1 ? "" : "s"}.`,
2761
+ );
2762
+ for (const error of audit.errors.details) {
2763
+ lines.push(` ${renderRepositoryScopeAuditError(error)}`);
2764
+ }
2765
+ if (audit.errors.truncated) {
2766
+ lines.push(
2767
+ ` … ${audit.errors.total - audit.errors.returned} more; rerun with --json for the complete audit.`,
2768
+ );
2769
+ }
2770
+ }
2771
+ return lines;
2772
+ }
2773
+
2700
2774
  function checkExitCode(
2701
2775
  snapshot: VaultSnapshot,
2702
2776
  noCatalog = false,
@@ -2723,6 +2797,7 @@ function renderSnapshot(
2723
2797
  snapshot: VaultSnapshot,
2724
2798
  noCatalog = false,
2725
2799
  attachments?: AttachmentValidationReport,
2800
+ repositoryScopes?: RepositoryMemoryScopeAudit,
2726
2801
  ): string {
2727
2802
  const lines = [
2728
2803
  `${command === "refresh" ? "Refreshed" : "Checked"} ${safe(snapshot.root)}`,
@@ -2742,6 +2817,7 @@ function renderSnapshot(
2742
2817
  lines.push("error: attachment validation was truncated by a resource limit");
2743
2818
  }
2744
2819
  lines.push(...renderAdvisories(snapshot.analysis));
2820
+ if (repositoryScopes !== undefined) lines.push(...renderRepositoryScopeAudit(repositoryScopes));
2745
2821
  return `${lines.join("\n")}\n`;
2746
2822
  }
2747
2823
 
@@ -3806,9 +3882,24 @@ async function runVault(
3806
3882
  documents: snapshot.notes.map(({ path, content }) => ({ path, content })),
3807
3883
  })
3808
3884
  : undefined;
3885
+ const repositoryScopes = command.kind === "check" && command.repository !== undefined
3886
+ ? await (dependencies.auditRepositoryMemoryScopes ?? auditRepositoryMemoryScopes)(
3887
+ snapshot.notes,
3888
+ {
3889
+ repositoryRoot: command.repository,
3890
+ detailLimit: MAX_REPOSITORY_MEMORY_DETAIL_LIMIT,
3891
+ },
3892
+ )
3893
+ : undefined;
3809
3894
  output.stdout(command.json
3810
- ? terminalSafeJson(summary(snapshot, { noCatalog, ...(attachments === undefined ? {} : { attachments }) }))
3811
- : sanitizeTerminalText(renderSnapshot(command.kind, snapshot, noCatalog, attachments)));
3895
+ ? terminalSafeJson(summary(snapshot, {
3896
+ noCatalog,
3897
+ ...(attachments === undefined ? {} : { attachments }),
3898
+ ...(repositoryScopes === undefined ? {} : { repositoryScopes }),
3899
+ }))
3900
+ : sanitizeTerminalText(
3901
+ renderSnapshot(command.kind, snapshot, noCatalog, attachments, repositoryScopes),
3902
+ ));
3812
3903
  return checkExitCode(snapshot, noCatalog, attachments);
3813
3904
  }
3814
3905
  if (command.kind === "graph") {
package/src/graph.ts CHANGED
@@ -608,7 +608,7 @@ function aliasesFromMetadata(metadata: MetadataObject): readonly string[] {
608
608
  }
609
609
 
610
610
  function frontmatterOf(content: string, path: string): Frontmatter {
611
- const lines = content.split("\n");
611
+ const lines = content.split(/\r?\n/u);
612
612
  if (lines[0]?.trim() !== "---") {
613
613
  return {
614
614
  values: new Map(),
@@ -2,6 +2,6 @@
2
2
  export const supportProfile = {
3
3
  id: "kb",
4
4
  name: "Wordcell",
5
- valueProposition: "Support ongoing development of inspectable Markdown memory for coding agents.",
5
+ valueProposition: "Support ongoing development of inspectable Markdown memory.",
6
6
  updates: false,
7
7
  } as const;