ricord 1.0.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.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/commands/ricord-flush.md +29 -0
  4. package/commands/ricord-init.md +129 -0
  5. package/commands/ricord-lint.md +64 -0
  6. package/commands/ricord-query.md +71 -0
  7. package/dist/cli/auth.d.ts +16 -0
  8. package/dist/cli/auth.js +42 -0
  9. package/dist/cli/auth.js.map +1 -0
  10. package/dist/cli/bundle.d.ts +25 -0
  11. package/dist/cli/bundle.js +179 -0
  12. package/dist/cli/bundle.js.map +1 -0
  13. package/dist/cli/cache.d.ts +18 -0
  14. package/dist/cli/cache.js +39 -0
  15. package/dist/cli/cache.js.map +1 -0
  16. package/dist/cli/cli.d.ts +21 -0
  17. package/dist/cli/cli.js +355 -0
  18. package/dist/cli/cli.js.map +1 -0
  19. package/dist/cli/client.d.ts +12 -0
  20. package/dist/cli/client.js +35 -0
  21. package/dist/cli/client.js.map +1 -0
  22. package/dist/cli/commands/build.d.ts +44 -0
  23. package/dist/cli/commands/build.js +437 -0
  24. package/dist/cli/commands/build.js.map +1 -0
  25. package/dist/cli/commands/curate.d.ts +32 -0
  26. package/dist/cli/commands/curate.js +154 -0
  27. package/dist/cli/commands/curate.js.map +1 -0
  28. package/dist/cli/commands/doctor.d.ts +16 -0
  29. package/dist/cli/commands/doctor.js +92 -0
  30. package/dist/cli/commands/doctor.js.map +1 -0
  31. package/dist/cli/commands/ingest.d.ts +25 -0
  32. package/dist/cli/commands/ingest.js +121 -0
  33. package/dist/cli/commands/ingest.js.map +1 -0
  34. package/dist/cli/commands/install.d.ts +16 -0
  35. package/dist/cli/commands/install.js +82 -0
  36. package/dist/cli/commands/install.js.map +1 -0
  37. package/dist/cli/commands/pull.d.ts +24 -0
  38. package/dist/cli/commands/pull.js +104 -0
  39. package/dist/cli/commands/pull.js.map +1 -0
  40. package/dist/cli/commands/push.d.ts +28 -0
  41. package/dist/cli/commands/push.js +164 -0
  42. package/dist/cli/commands/push.js.map +1 -0
  43. package/dist/cli/commands/rollup.d.ts +21 -0
  44. package/dist/cli/commands/rollup.js +118 -0
  45. package/dist/cli/commands/rollup.js.map +1 -0
  46. package/dist/cli/commands/setup.d.ts +7 -0
  47. package/dist/cli/commands/setup.js +43 -0
  48. package/dist/cli/commands/setup.js.map +1 -0
  49. package/dist/cli/commands/sync.d.ts +15 -0
  50. package/dist/cli/commands/sync.js +63 -0
  51. package/dist/cli/commands/sync.js.map +1 -0
  52. package/dist/cli/commands/watch.d.ts +17 -0
  53. package/dist/cli/commands/watch.js +87 -0
  54. package/dist/cli/commands/watch.js.map +1 -0
  55. package/dist/cli/config.d.ts +29 -0
  56. package/dist/cli/config.js +52 -0
  57. package/dist/cli/config.js.map +1 -0
  58. package/dist/cli/extract.d.ts +101 -0
  59. package/dist/cli/extract.js +216 -0
  60. package/dist/cli/extract.js.map +1 -0
  61. package/dist/cli/ingest.d.ts +48 -0
  62. package/dist/cli/ingest.js +74 -0
  63. package/dist/cli/ingest.js.map +1 -0
  64. package/dist/cli/ledger.d.ts +44 -0
  65. package/dist/cli/ledger.js +67 -0
  66. package/dist/cli/ledger.js.map +1 -0
  67. package/dist/cli/llm.d.ts +21 -0
  68. package/dist/cli/llm.js +138 -0
  69. package/dist/cli/llm.js.map +1 -0
  70. package/dist/cli/parse.d.ts +13 -0
  71. package/dist/cli/parse.js +188 -0
  72. package/dist/cli/parse.js.map +1 -0
  73. package/dist/cli/run-explore.d.ts +56 -0
  74. package/dist/cli/run-explore.js +229 -0
  75. package/dist/cli/run-explore.js.map +1 -0
  76. package/dist/cli/summarize.d.ts +15 -0
  77. package/dist/cli/summarize.js +49 -0
  78. package/dist/cli/summarize.js.map +1 -0
  79. package/dist/cli/uninstall.d.ts +6 -0
  80. package/dist/cli/uninstall.js +277 -0
  81. package/dist/cli/uninstall.js.map +1 -0
  82. package/dist/cli/walk.d.ts +13 -0
  83. package/dist/cli/walk.js +62 -0
  84. package/dist/cli/walk.js.map +1 -0
  85. package/dist/cli/walker.d.ts +14 -0
  86. package/dist/cli/walker.js +120 -0
  87. package/dist/cli/walker.js.map +1 -0
  88. package/dist/hooks/pre-compact.d.ts +15 -0
  89. package/dist/hooks/pre-compact.js +127 -0
  90. package/dist/hooks/pre-compact.js.map +1 -0
  91. package/dist/hooks/pre-tool-use.d.ts +15 -0
  92. package/dist/hooks/pre-tool-use.js +25 -0
  93. package/dist/hooks/pre-tool-use.js.map +1 -0
  94. package/dist/hooks/session-end.d.ts +21 -0
  95. package/dist/hooks/session-end.js +186 -0
  96. package/dist/hooks/session-end.js.map +1 -0
  97. package/dist/hooks/session-start.d.ts +15 -0
  98. package/dist/hooks/session-start.js +233 -0
  99. package/dist/hooks/session-start.js.map +1 -0
  100. package/dist/hooks/turn-end-post.d.ts +17 -0
  101. package/dist/hooks/turn-end-post.js +66 -0
  102. package/dist/hooks/turn-end-post.js.map +1 -0
  103. package/dist/hooks/turn-end.d.ts +29 -0
  104. package/dist/hooks/turn-end.js +295 -0
  105. package/dist/hooks/turn-end.js.map +1 -0
  106. package/dist/index.d.ts +24 -0
  107. package/dist/index.js +1547 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/init.d.ts +45 -0
  110. package/dist/init.js +839 -0
  111. package/dist/init.js.map +1 -0
  112. package/dist/lib/active-project.d.ts +14 -0
  113. package/dist/lib/active-project.js +65 -0
  114. package/dist/lib/active-project.js.map +1 -0
  115. package/dist/lib/buffer.d.ts +34 -0
  116. package/dist/lib/buffer.js +79 -0
  117. package/dist/lib/buffer.js.map +1 -0
  118. package/dist/scripts/compile.d.ts +25 -0
  119. package/dist/scripts/compile.js +185 -0
  120. package/dist/scripts/compile.js.map +1 -0
  121. package/dist/scripts/config.d.ts +30 -0
  122. package/dist/scripts/config.js +68 -0
  123. package/dist/scripts/config.js.map +1 -0
  124. package/dist/scripts/flush.d.ts +23 -0
  125. package/dist/scripts/flush.js +230 -0
  126. package/dist/scripts/flush.js.map +1 -0
  127. package/dist/scripts/lint.d.ts +21 -0
  128. package/dist/scripts/lint.js +242 -0
  129. package/dist/scripts/lint.js.map +1 -0
  130. package/dist/scripts/utils.d.ts +43 -0
  131. package/dist/scripts/utils.js +165 -0
  132. package/dist/scripts/utils.js.map +1 -0
  133. package/package.json +74 -0
  134. package/scripts/postinstall.mjs +56 -0
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `ricord watch [--from .ricord/pages/]` — file watcher that auto-pushes
3
+ * markdown edits to the cloud mirror (G11 tick 26).
4
+ *
5
+ * Uses node:fs.watch (no chokidar dep). Edits are coalesced with a 1.5s
6
+ * debounce so a save burst from an editor doesn't trigger N pushes.
7
+ * Each fire calls pushCommand which mtime-gates against the ledger.
8
+ *
9
+ * Ctrl-C exits cleanly.
10
+ */
11
+ import { watch } from "node:fs";
12
+ import { resolve } from "node:path";
13
+ import { existsSync } from "node:fs";
14
+ import kleur from "kleur";
15
+ import { pushCommand } from "./push.js";
16
+ const DEBOUNCE_MS = 1500;
17
+ export async function watchCommand(opts) {
18
+ const dir = resolve(opts.repoRoot, opts.from);
19
+ if (!existsSync(dir)) {
20
+ console.error(kleur.red(`watch dir not found: ${dir}`));
21
+ return 1;
22
+ }
23
+ console.log(kleur.green("ricord watch"), kleur.dim(`watching ${opts.from} (debounce ${DEBOUNCE_MS}ms)`));
24
+ console.log(kleur.dim("ctrl-c to stop"));
25
+ let pending = null;
26
+ let inflight = false;
27
+ let queued = false;
28
+ const fire = async () => {
29
+ if (inflight) {
30
+ queued = true;
31
+ return;
32
+ }
33
+ inflight = true;
34
+ try {
35
+ await pushCommand({
36
+ repoRoot: opts.repoRoot,
37
+ from: opts.from,
38
+ projectId: opts.projectId,
39
+ dryRun: false,
40
+ all: false,
41
+ });
42
+ }
43
+ catch (e) {
44
+ console.error(kleur.red(`push failed: ${e.message}`));
45
+ }
46
+ finally {
47
+ inflight = false;
48
+ if (queued) {
49
+ queued = false;
50
+ schedule();
51
+ }
52
+ }
53
+ };
54
+ function schedule() {
55
+ if (pending)
56
+ clearTimeout(pending);
57
+ pending = setTimeout(() => {
58
+ pending = null;
59
+ void fire();
60
+ }, DEBOUNCE_MS);
61
+ }
62
+ let watcher;
63
+ try {
64
+ watcher = watch(dir, { persistent: true }, (event, filename) => {
65
+ if (!filename || !filename.endsWith(".md"))
66
+ return;
67
+ console.log(kleur.dim(` ${event} ${filename} — scheduling push`));
68
+ schedule();
69
+ });
70
+ }
71
+ catch (e) {
72
+ console.error(kleur.red(`watch failed: ${e.message}`));
73
+ return 1;
74
+ }
75
+ return await new Promise((res) => {
76
+ const onSig = () => {
77
+ watcher.close();
78
+ if (pending)
79
+ clearTimeout(pending);
80
+ console.log(kleur.dim("\nwatch stopped."));
81
+ res(0);
82
+ };
83
+ process.once("SIGINT", onSig);
84
+ process.once("SIGTERM", onSig);
85
+ });
86
+ }
87
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/cli/commands/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Config + auth resolution for the ricord CLI.
3
+ *
4
+ * Lookup order for the API key:
5
+ * 1. RICORD_API_KEY env var
6
+ * 2. ~/.ricord/config.json {"api_key": "rc_live_..."}
7
+ *
8
+ * Lookup order for the API base URL:
9
+ * 1. RICORD_API_URL env var
10
+ * 2. ~/.ricord/config.json {"api_url": "..."}
11
+ * 3. https://api.ricord.ai
12
+ *
13
+ * Config dir is gitignored by convention (top-level .gitignore in
14
+ * ricord-ai already covers `.ricord/`).
15
+ */
16
+ export interface RicordConfig {
17
+ api_key?: string;
18
+ api_url?: string;
19
+ default_project_id?: string;
20
+ }
21
+ export declare function configDir(): string;
22
+ export declare function configPath(): string;
23
+ export declare function readConfig(): Promise<RicordConfig>;
24
+ export declare function writeConfig(next: RicordConfig): Promise<void>;
25
+ export interface ResolvedAuth {
26
+ apiKey: string;
27
+ apiUrl: string;
28
+ }
29
+ export declare function resolveAuth(): Promise<ResolvedAuth>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Config + auth resolution for the ricord CLI.
3
+ *
4
+ * Lookup order for the API key:
5
+ * 1. RICORD_API_KEY env var
6
+ * 2. ~/.ricord/config.json {"api_key": "rc_live_..."}
7
+ *
8
+ * Lookup order for the API base URL:
9
+ * 1. RICORD_API_URL env var
10
+ * 2. ~/.ricord/config.json {"api_url": "..."}
11
+ * 3. https://api.ricord.ai
12
+ *
13
+ * Config dir is gitignored by convention (top-level .gitignore in
14
+ * ricord-ai already covers `.ricord/`).
15
+ */
16
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
17
+ import { existsSync } from "node:fs";
18
+ import { homedir } from "node:os";
19
+ import { join } from "node:path";
20
+ const DEFAULT_API_URL = "https://api.ricord.ai";
21
+ export function configDir() {
22
+ return join(homedir(), ".ricord");
23
+ }
24
+ export function configPath() {
25
+ return join(configDir(), "config.json");
26
+ }
27
+ export async function readConfig() {
28
+ const p = configPath();
29
+ if (!existsSync(p))
30
+ return {};
31
+ try {
32
+ const raw = await readFile(p, "utf8");
33
+ return JSON.parse(raw);
34
+ }
35
+ catch {
36
+ return {};
37
+ }
38
+ }
39
+ export async function writeConfig(next) {
40
+ await mkdir(configDir(), { recursive: true });
41
+ await writeFile(configPath(), JSON.stringify(next, null, 2) + "\n", "utf8");
42
+ }
43
+ export async function resolveAuth() {
44
+ const cfg = await readConfig();
45
+ const apiKey = process.env.RICORD_API_KEY ?? cfg.api_key ?? "";
46
+ const apiUrl = process.env.RICORD_API_URL ?? cfg.api_url ?? DEFAULT_API_URL;
47
+ if (!apiKey) {
48
+ throw new Error("No API key found. Run `ricord setup` or set RICORD_API_KEY in your shell.");
49
+ }
50
+ return { apiKey, apiUrl };
51
+ }
52
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEhD,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IACvB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAkB;IAClD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AAC9E,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,OAAO,IAAI,eAAe,CAAC;IAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Client-side extraction for `ricord init`.
3
+ *
4
+ * Post-2026-05-12 the Ricord server runs zero generative LLM calls — clients
5
+ * own anchor/connection/task extraction. This module wires the CLI into that
6
+ * flow: fetch the canonical extraction prompt from /v1/extraction/prompt,
7
+ * run it through the caller's LLM, and POST the structured result to
8
+ * /v1/ingest/extracted.
9
+ *
10
+ * Provider auto-detect at startup: OPENAI_API_KEY (default, gpt-4o) or
11
+ * ANTHROPIC_API_KEY (claude-sonnet-4-6). One key is enough.
12
+ */
13
+ export interface Anchor {
14
+ type: "entity" | "topic" | "epoch";
15
+ subtype?: string;
16
+ value: string;
17
+ aliases?: string[];
18
+ confidence: number;
19
+ }
20
+ export interface Connection {
21
+ source: string;
22
+ target: string;
23
+ relation: "mentions" | "relates_to" | "supersedes" | "contradicts" | "caused_by" | "part_of" | "derived_from";
24
+ relationship?: string;
25
+ strength: number;
26
+ valid_at?: string | number | null;
27
+ invalid_at?: string | number | null;
28
+ }
29
+ export interface Task {
30
+ text: string;
31
+ priority?: "low" | "normal" | "high";
32
+ due_date?: string;
33
+ related_anchor?: string;
34
+ }
35
+ export interface Extracted {
36
+ anchors: Anchor[];
37
+ connections: Connection[];
38
+ tasks: Task[];
39
+ }
40
+ export interface ExtractionPromptResponse {
41
+ schema_version: number;
42
+ prompt: string;
43
+ output_schema: unknown;
44
+ submit_url: string;
45
+ caps: {
46
+ max_messages: number;
47
+ max_total_chars: number;
48
+ max_anchors: number;
49
+ max_connections: number;
50
+ max_tasks: number;
51
+ };
52
+ }
53
+ export type LlmProvider = "openai" | "anthropic";
54
+ export interface LlmConfig {
55
+ provider: LlmProvider;
56
+ model: string;
57
+ apiKey: string;
58
+ }
59
+ export type LlmFn = (prompt: string) => Promise<string>;
60
+ export interface ExtractIngestConfig {
61
+ apiBase: string;
62
+ token: string;
63
+ }
64
+ export interface ExtractedIngestResult {
65
+ ok: boolean;
66
+ status: number;
67
+ pagesWritten: number;
68
+ linksWritten: number;
69
+ tasksWritten: number;
70
+ body: unknown;
71
+ }
72
+ /**
73
+ * Resolve LLM provider + key from explicit flags or env. Throws with a clear
74
+ * message if no usable key is found — the CLI surfaces this at startup so the
75
+ * user fixes it before we walk the repo.
76
+ */
77
+ export declare function resolveLlmConfig(opts: {
78
+ modelFlag?: string;
79
+ keyFlag?: string;
80
+ }): LlmConfig;
81
+ export declare function makeLlmFn(cfg: LlmConfig): LlmFn;
82
+ export declare function fetchExtractionPrompt(cfg: ExtractIngestConfig): Promise<ExtractionPromptResponse>;
83
+ export declare function runExtraction(llm: LlmFn, promptTemplate: string, text: string): Promise<Extracted>;
84
+ /**
85
+ * POST extracted anchors/connections/tasks to /v1/ingest/extracted. The route
86
+ * embeds the raw bundle text on its end (Vertex, $0.025/1M) so the bundle is
87
+ * still searchable; we just don't pay for generative extraction on the server.
88
+ */
89
+ export declare function postExtracted(cfg: ExtractIngestConfig, payload: {
90
+ dirRel: string;
91
+ bundleText: string;
92
+ extracted: Extracted;
93
+ repo: string;
94
+ model: string;
95
+ schemaVersion: number;
96
+ }): Promise<ExtractedIngestResult>;
97
+ export declare function fetchUsage(cfg: ExtractIngestConfig): Promise<{
98
+ memories_used?: number;
99
+ memories_cap?: number;
100
+ tier?: string;
101
+ } | null>;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Client-side extraction for `ricord init`.
3
+ *
4
+ * Post-2026-05-12 the Ricord server runs zero generative LLM calls — clients
5
+ * own anchor/connection/task extraction. This module wires the CLI into that
6
+ * flow: fetch the canonical extraction prompt from /v1/extraction/prompt,
7
+ * run it through the caller's LLM, and POST the structured result to
8
+ * /v1/ingest/extracted.
9
+ *
10
+ * Provider auto-detect at startup: OPENAI_API_KEY (default, gpt-4o) or
11
+ * ANTHROPIC_API_KEY (claude-sonnet-4-6). One key is enough.
12
+ */
13
+ const DEFAULT_OPENAI_MODEL = "gpt-4o";
14
+ const DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-6";
15
+ /**
16
+ * Resolve LLM provider + key from explicit flags or env. Throws with a clear
17
+ * message if no usable key is found — the CLI surfaces this at startup so the
18
+ * user fixes it before we walk the repo.
19
+ */
20
+ export function resolveLlmConfig(opts) {
21
+ const explicitKey = opts.keyFlag?.trim();
22
+ const model = opts.modelFlag?.trim();
23
+ const looksAnthropic = model && /^(claude|anthropic)/i.test(model);
24
+ const looksOpenAI = model && /^(gpt|o\d|openai)/i.test(model);
25
+ // If model hints at provider, honor it.
26
+ if (looksAnthropic) {
27
+ const key = explicitKey ?? process.env.ANTHROPIC_API_KEY;
28
+ if (!key)
29
+ throw new Error("ANTHROPIC_API_KEY not set (or pass --llm-key)");
30
+ return { provider: "anthropic", model: model, apiKey: key };
31
+ }
32
+ if (looksOpenAI) {
33
+ const key = explicitKey ?? process.env.OPENAI_API_KEY;
34
+ if (!key)
35
+ throw new Error("OPENAI_API_KEY not set (or pass --llm-key)");
36
+ return { provider: "openai", model: model, apiKey: key };
37
+ }
38
+ // No model flag — pick whichever env key exists, OpenAI first.
39
+ if (explicitKey || process.env.OPENAI_API_KEY) {
40
+ return {
41
+ provider: "openai",
42
+ model: model ?? DEFAULT_OPENAI_MODEL,
43
+ apiKey: explicitKey ?? process.env.OPENAI_API_KEY,
44
+ };
45
+ }
46
+ if (process.env.ANTHROPIC_API_KEY) {
47
+ return {
48
+ provider: "anthropic",
49
+ model: model ?? DEFAULT_ANTHROPIC_MODEL,
50
+ apiKey: process.env.ANTHROPIC_API_KEY,
51
+ };
52
+ }
53
+ throw new Error("no LLM key found. Set OPENAI_API_KEY (or ANTHROPIC_API_KEY), " +
54
+ "or pass --llm-key <key> --llm-model <model>. " +
55
+ "Extraction runs client-side; Ricord no longer ships generative LLM calls.");
56
+ }
57
+ export function makeLlmFn(cfg) {
58
+ if (cfg.provider === "openai")
59
+ return makeOpenAiFn(cfg);
60
+ return makeAnthropicFn(cfg);
61
+ }
62
+ function makeOpenAiFn(cfg) {
63
+ return async (prompt) => {
64
+ const r = await fetch("https://api.openai.com/v1/chat/completions", {
65
+ method: "POST",
66
+ headers: {
67
+ Authorization: `Bearer ${cfg.apiKey}`,
68
+ "Content-Type": "application/json",
69
+ },
70
+ body: JSON.stringify({
71
+ model: cfg.model,
72
+ messages: [{ role: "user", content: prompt }],
73
+ temperature: 0,
74
+ response_format: { type: "json_object" },
75
+ }),
76
+ });
77
+ if (!r.ok)
78
+ throw new Error(`OpenAI ${r.status}: ${(await r.text()).slice(0, 300)}`);
79
+ const j = await r.json();
80
+ return j.choices?.[0]?.message?.content ?? "";
81
+ };
82
+ }
83
+ function makeAnthropicFn(cfg) {
84
+ return async (prompt) => {
85
+ const r = await fetch("https://api.anthropic.com/v1/messages", {
86
+ method: "POST",
87
+ headers: {
88
+ "x-api-key": cfg.apiKey,
89
+ "anthropic-version": "2023-06-01",
90
+ "Content-Type": "application/json",
91
+ },
92
+ body: JSON.stringify({
93
+ model: cfg.model,
94
+ max_tokens: 3000,
95
+ messages: [{ role: "user", content: prompt }],
96
+ }),
97
+ });
98
+ if (!r.ok)
99
+ throw new Error(`Anthropic ${r.status}: ${(await r.text()).slice(0, 300)}`);
100
+ const j = await r.json();
101
+ return (j.content ?? []).map(c => c.text ?? "").join("");
102
+ };
103
+ }
104
+ export async function fetchExtractionPrompt(cfg) {
105
+ const r = await fetch(`${cfg.apiBase}/v1/extraction/prompt`, {
106
+ headers: { Authorization: `Bearer ${cfg.token}` },
107
+ });
108
+ if (!r.ok)
109
+ throw new Error(`extraction prompt fetch failed: ${r.status} ${(await r.text()).slice(0, 200)}`);
110
+ return r.json();
111
+ }
112
+ function tryParseJson(raw) {
113
+ const fenced = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
114
+ const candidate = fenced ? fenced[1] : raw;
115
+ const start = candidate.indexOf("{");
116
+ const end = candidate.lastIndexOf("}");
117
+ if (start === -1 || end === -1 || end < start)
118
+ throw new Error("no JSON object in LLM output");
119
+ return JSON.parse(candidate.slice(start, end + 1));
120
+ }
121
+ /** Coarse types the server accepts; subtype values often leak into `type`. */
122
+ const COARSE_TYPES = new Set(["entity", "topic", "epoch"]);
123
+ const SUBTYPE_TO_COARSE = {
124
+ person: "entity", people: "entity", company: "entity", institution: "entity",
125
+ community: "entity", relationship: "entity", project: "entity",
126
+ product: "entity", codebase: "entity", repo: "entity", repository: "entity",
127
+ technology: "entity", tool: "entity", library: "entity", framework: "entity",
128
+ place: "entity", location: "entity",
129
+ decision: "topic", pattern: "topic", lesson: "topic", gotcha: "topic",
130
+ theme: "topic", concept: "topic", architecture: "topic", design: "topic",
131
+ bug: "topic", feature: "topic",
132
+ period: "epoch", era: "epoch", quarter: "epoch", week: "epoch", day: "epoch",
133
+ };
134
+ function coerceAnchorType(a) {
135
+ const raw = a.type?.toLowerCase?.() ?? "";
136
+ if (COARSE_TYPES.has(raw))
137
+ return { ...a, type: raw };
138
+ const coarse = SUBTYPE_TO_COARSE[raw] ?? "entity";
139
+ return {
140
+ ...a,
141
+ type: coarse,
142
+ subtype: a.subtype ?? raw ?? undefined,
143
+ };
144
+ }
145
+ export async function runExtraction(llm, promptTemplate, text) {
146
+ const filled = promptTemplate.replace("{TEXT}", text);
147
+ const raw = await llm(filled);
148
+ const parsed = tryParseJson(raw);
149
+ if (!Array.isArray(parsed.anchors))
150
+ throw new Error("LLM output missing anchors[]");
151
+ // Cap to 10 anchors (server limit) and coerce types into the allowed set.
152
+ const anchors = parsed.anchors.slice(0, 10).map(coerceAnchorType);
153
+ const connections = Array.isArray(parsed.connections) ? parsed.connections.slice(0, 30) : [];
154
+ const tasks = Array.isArray(parsed.tasks) ? parsed.tasks.slice(0, 5) : [];
155
+ return { anchors, connections, tasks };
156
+ }
157
+ /**
158
+ * POST extracted anchors/connections/tasks to /v1/ingest/extracted. The route
159
+ * embeds the raw bundle text on its end (Vertex, $0.025/1M) so the bundle is
160
+ * still searchable; we just don't pay for generative extraction on the server.
161
+ */
162
+ export async function postExtracted(cfg, payload) {
163
+ // Cap text to /v1/ingest/extracted's 200KB limit (server enforces too).
164
+ const safeText = payload.bundleText.length > 180_000
165
+ ? payload.bundleText.slice(0, 180_000)
166
+ : payload.bundleText;
167
+ const body = {
168
+ messages: [{ role: "user", content: safeText }],
169
+ extracted: payload.extracted,
170
+ extraction_meta: {
171
+ model: payload.model,
172
+ client: "ricord-cli",
173
+ schema_version: payload.schemaVersion,
174
+ },
175
+ tags: [`repo:${payload.repo}`, `dir:${payload.dirRel}`, "kind:dir-summary"],
176
+ };
177
+ const r = await fetch(`${cfg.apiBase}/v1/ingest/extracted`, {
178
+ method: "POST",
179
+ headers: {
180
+ Authorization: `Bearer ${cfg.token}`,
181
+ "Content-Type": "application/json",
182
+ },
183
+ body: JSON.stringify(body),
184
+ });
185
+ let parsed;
186
+ try {
187
+ parsed = await r.json();
188
+ }
189
+ catch {
190
+ parsed = await r.text();
191
+ }
192
+ const p = parsed;
193
+ return {
194
+ ok: r.ok,
195
+ status: r.status,
196
+ pagesWritten: p?.pages_written ?? 0,
197
+ linksWritten: p?.links_written ?? 0,
198
+ tasksWritten: p?.tasks_written ?? 0,
199
+ body: parsed,
200
+ };
201
+ }
202
+ export async function fetchUsage(cfg) {
203
+ try {
204
+ const r = await fetch(`${cfg.apiBase}/v1/usage`, {
205
+ headers: { Authorization: `Bearer ${cfg.token}` },
206
+ });
207
+ if (!r.ok)
208
+ return null;
209
+ const b = await r.json();
210
+ return b.quota ?? null;
211
+ }
212
+ catch {
213
+ return null;
214
+ }
215
+ }
216
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/cli/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ export interface IngestConfig {
2
+ apiBase: string;
3
+ token: string;
4
+ }
5
+ /**
6
+ * `/v1/ingest/source` returns `pipeline_status` immediately — no async job_id.
7
+ * The synchronous stages (`turns`, `recall`) run during the request; the rest
8
+ * (`facts`, `kb`, `graph`, `observe`) get queued and run in the background.
9
+ */
10
+ export interface PipelineStatus {
11
+ turns?: "success" | "queued" | "skipped" | "failed";
12
+ recall?: "success" | "queued" | "skipped" | "failed";
13
+ facts?: "success" | "queued" | "skipped" | "failed";
14
+ kb?: "success" | "queued" | "skipped" | "failed";
15
+ graph?: "success" | "queued" | "skipped" | "failed";
16
+ observe?: "success" | "queued" | "skipped" | "failed";
17
+ }
18
+ export interface IngestResult {
19
+ ok: boolean;
20
+ status: number;
21
+ sessionId?: string;
22
+ pipelineStatus?: PipelineStatus;
23
+ turnsSaved?: number;
24
+ factsExtracted?: number;
25
+ creditsCharged?: number;
26
+ body: unknown;
27
+ }
28
+ export declare function postSourceText(cfg: IngestConfig, payload: {
29
+ dirRel: string;
30
+ summary: string;
31
+ repo: string;
32
+ }): Promise<IngestResult>;
33
+ /**
34
+ * Compact one-line summary of which stages finished synchronously vs were
35
+ * queued for background extraction. e.g. "turns:✓ recall:✓ facts:⏳ kb:⏳"
36
+ */
37
+ export declare function formatPipelineStatus(s: PipelineStatus | undefined): string;
38
+ /**
39
+ * Quick post-run quota delta check. The ingest jobs queue surface (`/v1/ingest/jobs/stats`)
40
+ * is for a different code path than `/v1/ingest/source` — polling it during a CLI run
41
+ * surfaces unrelated counters and confuses the user. Use `/v1/usage` instead — it shows
42
+ * the user's actual memory/quota state, which moves as their ingest finishes.
43
+ */
44
+ export declare function fetchUsage(cfg: IngestConfig): Promise<{
45
+ memories_used?: number;
46
+ memories_cap?: number;
47
+ tier?: string;
48
+ } | null>;
@@ -0,0 +1,74 @@
1
+ export async function postSourceText(cfg, payload) {
2
+ const body = {
3
+ type: "text",
4
+ value: payload.summary,
5
+ title: payload.dirRel,
6
+ metadata: {
7
+ repo: payload.repo,
8
+ kind: "dir-summary",
9
+ path: payload.dirRel,
10
+ source: "ricord-cli",
11
+ },
12
+ };
13
+ const resp = await fetch(`${cfg.apiBase}/v1/ingest/source`, {
14
+ method: "POST",
15
+ headers: {
16
+ "Authorization": `Bearer ${cfg.token}`,
17
+ "Content-Type": "application/json",
18
+ },
19
+ body: JSON.stringify(body),
20
+ });
21
+ let parsed;
22
+ try {
23
+ parsed = await resp.json();
24
+ }
25
+ catch {
26
+ parsed = await resp.text();
27
+ }
28
+ const p = parsed;
29
+ return {
30
+ ok: resp.ok,
31
+ status: resp.status,
32
+ sessionId: p?.session_id,
33
+ pipelineStatus: p?.pipeline_status,
34
+ turnsSaved: p?.turns_saved,
35
+ factsExtracted: p?.facts_extracted,
36
+ creditsCharged: p?.credits_charged,
37
+ body: parsed,
38
+ };
39
+ }
40
+ /**
41
+ * Compact one-line summary of which stages finished synchronously vs were
42
+ * queued for background extraction. e.g. "turns:✓ recall:✓ facts:⏳ kb:⏳"
43
+ */
44
+ export function formatPipelineStatus(s) {
45
+ if (!s)
46
+ return "";
47
+ const glyph = (v) => v === "success" ? "✓" :
48
+ v === "queued" ? "⏳" :
49
+ v === "skipped" ? "·" :
50
+ v === "failed" ? "✗" : "?";
51
+ const order = ["turns", "recall", "facts", "kb", "graph", "observe"];
52
+ return order.filter(k => s[k] !== undefined).map(k => `${k}:${glyph(s[k])}`).join(" ");
53
+ }
54
+ /**
55
+ * Quick post-run quota delta check. The ingest jobs queue surface (`/v1/ingest/jobs/stats`)
56
+ * is for a different code path than `/v1/ingest/source` — polling it during a CLI run
57
+ * surfaces unrelated counters and confuses the user. Use `/v1/usage` instead — it shows
58
+ * the user's actual memory/quota state, which moves as their ingest finishes.
59
+ */
60
+ export async function fetchUsage(cfg) {
61
+ try {
62
+ const resp = await fetch(`${cfg.apiBase}/v1/usage`, {
63
+ headers: { "Authorization": `Bearer ${cfg.token}` },
64
+ });
65
+ if (!resp.ok)
66
+ return null;
67
+ const body = await resp.json();
68
+ return body.quota ?? null;
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/cli/ingest.ts"],"names":[],"mappings":"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"}