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.
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/commands/ricord-flush.md +29 -0
- package/commands/ricord-init.md +129 -0
- package/commands/ricord-lint.md +64 -0
- package/commands/ricord-query.md +71 -0
- package/dist/cli/auth.d.ts +16 -0
- package/dist/cli/auth.js +42 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/bundle.d.ts +25 -0
- package/dist/cli/bundle.js +179 -0
- package/dist/cli/bundle.js.map +1 -0
- package/dist/cli/cache.d.ts +18 -0
- package/dist/cli/cache.js +39 -0
- package/dist/cli/cache.js.map +1 -0
- package/dist/cli/cli.d.ts +21 -0
- package/dist/cli/cli.js +355 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/client.d.ts +12 -0
- package/dist/cli/client.js +35 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/commands/build.d.ts +44 -0
- package/dist/cli/commands/build.js +437 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/curate.d.ts +32 -0
- package/dist/cli/commands/curate.js +154 -0
- package/dist/cli/commands/curate.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +16 -0
- package/dist/cli/commands/doctor.js +92 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/ingest.d.ts +25 -0
- package/dist/cli/commands/ingest.js +121 -0
- package/dist/cli/commands/ingest.js.map +1 -0
- package/dist/cli/commands/install.d.ts +16 -0
- package/dist/cli/commands/install.js +82 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/pull.d.ts +24 -0
- package/dist/cli/commands/pull.js +104 -0
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/commands/push.d.ts +28 -0
- package/dist/cli/commands/push.js +164 -0
- package/dist/cli/commands/push.js.map +1 -0
- package/dist/cli/commands/rollup.d.ts +21 -0
- package/dist/cli/commands/rollup.js +118 -0
- package/dist/cli/commands/rollup.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +7 -0
- package/dist/cli/commands/setup.js +43 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +15 -0
- package/dist/cli/commands/sync.js +63 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/watch.d.ts +17 -0
- package/dist/cli/commands/watch.js +87 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/config.d.ts +29 -0
- package/dist/cli/config.js +52 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/extract.d.ts +101 -0
- package/dist/cli/extract.js +216 -0
- package/dist/cli/extract.js.map +1 -0
- package/dist/cli/ingest.d.ts +48 -0
- package/dist/cli/ingest.js +74 -0
- package/dist/cli/ingest.js.map +1 -0
- package/dist/cli/ledger.d.ts +44 -0
- package/dist/cli/ledger.js +67 -0
- package/dist/cli/ledger.js.map +1 -0
- package/dist/cli/llm.d.ts +21 -0
- package/dist/cli/llm.js +138 -0
- package/dist/cli/llm.js.map +1 -0
- package/dist/cli/parse.d.ts +13 -0
- package/dist/cli/parse.js +188 -0
- package/dist/cli/parse.js.map +1 -0
- package/dist/cli/run-explore.d.ts +56 -0
- package/dist/cli/run-explore.js +229 -0
- package/dist/cli/run-explore.js.map +1 -0
- package/dist/cli/summarize.d.ts +15 -0
- package/dist/cli/summarize.js +49 -0
- package/dist/cli/summarize.js.map +1 -0
- package/dist/cli/uninstall.d.ts +6 -0
- package/dist/cli/uninstall.js +277 -0
- package/dist/cli/uninstall.js.map +1 -0
- package/dist/cli/walk.d.ts +13 -0
- package/dist/cli/walk.js +62 -0
- package/dist/cli/walk.js.map +1 -0
- package/dist/cli/walker.d.ts +14 -0
- package/dist/cli/walker.js +120 -0
- package/dist/cli/walker.js.map +1 -0
- package/dist/hooks/pre-compact.d.ts +15 -0
- package/dist/hooks/pre-compact.js +127 -0
- package/dist/hooks/pre-compact.js.map +1 -0
- package/dist/hooks/pre-tool-use.d.ts +15 -0
- package/dist/hooks/pre-tool-use.js +25 -0
- package/dist/hooks/pre-tool-use.js.map +1 -0
- package/dist/hooks/session-end.d.ts +21 -0
- package/dist/hooks/session-end.js +186 -0
- package/dist/hooks/session-end.js.map +1 -0
- package/dist/hooks/session-start.d.ts +15 -0
- package/dist/hooks/session-start.js +233 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/hooks/turn-end-post.d.ts +17 -0
- package/dist/hooks/turn-end-post.js +66 -0
- package/dist/hooks/turn-end-post.js.map +1 -0
- package/dist/hooks/turn-end.d.ts +29 -0
- package/dist/hooks/turn-end.js +295 -0
- package/dist/hooks/turn-end.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1547 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +45 -0
- package/dist/init.js +839 -0
- package/dist/init.js.map +1 -0
- package/dist/lib/active-project.d.ts +14 -0
- package/dist/lib/active-project.js +65 -0
- package/dist/lib/active-project.js.map +1 -0
- package/dist/lib/buffer.d.ts +34 -0
- package/dist/lib/buffer.js +79 -0
- package/dist/lib/buffer.js.map +1 -0
- package/dist/scripts/compile.d.ts +25 -0
- package/dist/scripts/compile.js +185 -0
- package/dist/scripts/compile.js.map +1 -0
- package/dist/scripts/config.d.ts +30 -0
- package/dist/scripts/config.js +68 -0
- package/dist/scripts/config.js.map +1 -0
- package/dist/scripts/flush.d.ts +23 -0
- package/dist/scripts/flush.js +230 -0
- package/dist/scripts/flush.js.map +1 -0
- package/dist/scripts/lint.d.ts +21 -0
- package/dist/scripts/lint.js +242 -0
- package/dist/scripts/lint.js.map +1 -0
- package/dist/scripts/utils.d.ts +43 -0
- package/dist/scripts/utils.js +165 -0
- package/dist/scripts/utils.js.map +1 -0
- package/package.json +74 -0
- package/scripts/postinstall.mjs +56 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord curate [--apply]` — wiki curation pass (F3 / S8).
|
|
3
|
+
*
|
|
4
|
+
* Default behavior (no flag) is a dry-run preview: fetches the server's
|
|
5
|
+
* curation suggestions and prints them. `--apply` posts the approved
|
|
6
|
+
* operations back to the server. Operations are server-defined:
|
|
7
|
+
*
|
|
8
|
+
* - move: retag / re-anchor a page
|
|
9
|
+
* - merge: fold two pages into one (keeps the better title)
|
|
10
|
+
* - archive: mark a page archived (kb_pages.archived_at)
|
|
11
|
+
* - supersede: B replaces A (kb_pages.superseded_by)
|
|
12
|
+
*
|
|
13
|
+
* The CLI does not run an LLM. The server invokes the CURATION_PROMPT
|
|
14
|
+
* inside /v1/kb/curate/preview; the CLI only orchestrates approval.
|
|
15
|
+
*/
|
|
16
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
17
|
+
import { join, resolve } from "node:path";
|
|
18
|
+
import kleur from "kleur";
|
|
19
|
+
import { resolveAuth } from "../config.js";
|
|
20
|
+
import { request } from "../client.js";
|
|
21
|
+
import { readLedger, ledgerDir } from "../ledger.js";
|
|
22
|
+
export async function curateCommand(opts) {
|
|
23
|
+
if (opts.local)
|
|
24
|
+
return curateLocal(opts);
|
|
25
|
+
const auth = await resolveAuth();
|
|
26
|
+
const ledger = await readLedger(opts.repoRoot);
|
|
27
|
+
const projectId = opts.projectId ?? ledger.project_id;
|
|
28
|
+
const qs = projectId ? `?project_id=${encodeURIComponent(projectId)}` : "";
|
|
29
|
+
if (opts.prepare) {
|
|
30
|
+
if (!projectId) {
|
|
31
|
+
console.error(kleur.red("--prepare needs --project <id> or a recorded ledger project."));
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
const p = await request(auth, `/v1/kb/curate/prompt${qs}`);
|
|
35
|
+
console.log(p.prompt);
|
|
36
|
+
console.log();
|
|
37
|
+
console.log(kleur.dim("--- Batch ---"));
|
|
38
|
+
console.log(JSON.stringify({ existing_topics: p.batch.existing_topics, pages: p.batch.pages }, null, 2));
|
|
39
|
+
console.log();
|
|
40
|
+
console.log(kleur.dim(`POST result back to: ${p.submit_url}`));
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
const preview = await request(auth, `/v1/kb/curate/preview${qs}`);
|
|
44
|
+
if (preview.operations.length === 0) {
|
|
45
|
+
console.log(kleur.green("✓"), `${preview.pages_examined} pages examined — nothing to curate.`);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
console.log(kleur.bold(`${preview.operations.length} suggested operation${preview.operations.length === 1 ? "" : "s"} across ${preview.pages_examined} pages`));
|
|
49
|
+
for (const o of preview.operations.slice(0, 50)) {
|
|
50
|
+
const tag = o.op === "merge" ? kleur.magenta("merge") :
|
|
51
|
+
o.op === "move" ? kleur.cyan("move") :
|
|
52
|
+
o.op === "archive" ? kleur.yellow("archive") :
|
|
53
|
+
kleur.blue("supersede");
|
|
54
|
+
console.log(` ${tag} ${o.page_id}${o.target_page_id ? ` → ${o.target_page_id}` : ""} ${kleur.dim(o.reason)}`);
|
|
55
|
+
}
|
|
56
|
+
if (preview.operations.length > 50) {
|
|
57
|
+
console.log(kleur.dim(` …${preview.operations.length - 50} more`));
|
|
58
|
+
}
|
|
59
|
+
if (!opts.apply) {
|
|
60
|
+
console.log();
|
|
61
|
+
console.log(kleur.dim("re-run with --apply to commit the operations."));
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
const out = await request(auth, `/v1/kb/curate/apply${qs}`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
body: JSON.stringify({ operations: preview.operations }),
|
|
67
|
+
});
|
|
68
|
+
console.log(kleur.green("✓"), `${out.applied} applied, ${out.skipped} skipped.`);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
/** G11 tick 27 — local-first curation report. Scans .ricord/pages/, flags
|
|
72
|
+
* empty bodies (stubs that never got rolled up), duplicate titles
|
|
73
|
+
* (case-insensitive), missing frontmatter ids (manually-created files
|
|
74
|
+
* that haven't been pushed yet), and stale files. No mutations. */
|
|
75
|
+
async function curateLocal(opts) {
|
|
76
|
+
const dir = resolve(opts.repoRoot, join(ledgerDir(opts.repoRoot), "pages"));
|
|
77
|
+
const entries = await readdir(dir).catch(() => []);
|
|
78
|
+
const mds = entries.filter((e) => e.endsWith(".md"));
|
|
79
|
+
if (mds.length === 0) {
|
|
80
|
+
console.log(kleur.yellow(`no markdown files under .ricord/pages/ — run \`ricord init --pull\` first.`));
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
const scans = [];
|
|
84
|
+
for (const f of mds) {
|
|
85
|
+
const full = join(dir, f);
|
|
86
|
+
const text = await readFile(full, "utf8").catch(() => "");
|
|
87
|
+
const st = await stat(full).catch(() => null);
|
|
88
|
+
const fmEnd = text.startsWith("---") ? text.indexOf("\n---", 3) : -1;
|
|
89
|
+
const fm = fmEnd > 0 ? text.slice(3, fmEnd) : "";
|
|
90
|
+
const body = fmEnd > 0 ? text.slice(fmEnd + 4).replace(/^\s*\n/, "").trim() : text.trim();
|
|
91
|
+
const idMatch = fm.match(/^id:\s*(\S+)/m);
|
|
92
|
+
const titleMatch = fm.match(/^title:\s*(.+)$/m);
|
|
93
|
+
scans.push({
|
|
94
|
+
file: f,
|
|
95
|
+
title: titleMatch?.[1]?.trim().replace(/^"|"$/g, "") ?? f.replace(/\.md$/, ""),
|
|
96
|
+
hasId: Boolean(idMatch?.[1]),
|
|
97
|
+
hasBody: body.length > 0 && body !== "(no body)",
|
|
98
|
+
mtimeMs: st?.mtimeMs ?? 0,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
const staleCutoff = now - opts.staleDays * 24 * 60 * 60 * 1000;
|
|
103
|
+
const empties = scans.filter((s) => !s.hasBody);
|
|
104
|
+
const noIds = scans.filter((s) => !s.hasId);
|
|
105
|
+
const stales = scans.filter((s) => s.hasBody && s.mtimeMs > 0 && s.mtimeMs < staleCutoff);
|
|
106
|
+
const titleGroups = new Map();
|
|
107
|
+
for (const s of scans) {
|
|
108
|
+
const k = s.title.toLowerCase();
|
|
109
|
+
const arr = titleGroups.get(k) ?? [];
|
|
110
|
+
arr.push(s);
|
|
111
|
+
titleGroups.set(k, arr);
|
|
112
|
+
}
|
|
113
|
+
const dupes = [...titleGroups.values()].filter((g) => g.length > 1);
|
|
114
|
+
console.log(kleur.bold(`ricord curate --local`), kleur.dim(`(${scans.length} pages in .ricord/pages/)`));
|
|
115
|
+
if (empties.length === 0 && noIds.length === 0 && stales.length === 0 && dupes.length === 0) {
|
|
116
|
+
console.log(kleur.green("✓ nothing to curate."));
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
if (empties.length > 0) {
|
|
120
|
+
console.log("");
|
|
121
|
+
console.log(kleur.yellow(`empty bodies (${empties.length})`), kleur.dim("— run `ricord rollup` or fill manually"));
|
|
122
|
+
for (const s of empties.slice(0, 15))
|
|
123
|
+
console.log(kleur.dim(` ${s.file} — ${s.title}`));
|
|
124
|
+
if (empties.length > 15)
|
|
125
|
+
console.log(kleur.dim(` …${empties.length - 15} more`));
|
|
126
|
+
}
|
|
127
|
+
if (noIds.length > 0) {
|
|
128
|
+
console.log("");
|
|
129
|
+
console.log(kleur.cyan(`missing frontmatter id (${noIds.length})`), kleur.dim("— manually-created files, push will skip them"));
|
|
130
|
+
for (const s of noIds.slice(0, 15))
|
|
131
|
+
console.log(kleur.dim(` ${s.file}`));
|
|
132
|
+
if (noIds.length > 15)
|
|
133
|
+
console.log(kleur.dim(` …${noIds.length - 15} more`));
|
|
134
|
+
}
|
|
135
|
+
if (dupes.length > 0) {
|
|
136
|
+
console.log("");
|
|
137
|
+
console.log(kleur.magenta(`duplicate titles (${dupes.length})`), kleur.dim("— consider merging"));
|
|
138
|
+
for (const g of dupes.slice(0, 10)) {
|
|
139
|
+
console.log(kleur.dim(` "${g[0].title}":`));
|
|
140
|
+
for (const s of g)
|
|
141
|
+
console.log(kleur.dim(` ${s.file}`));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (stales.length > 0) {
|
|
145
|
+
console.log("");
|
|
146
|
+
console.log(kleur.gray(`stale (>${opts.staleDays}d old) (${stales.length})`));
|
|
147
|
+
for (const s of stales.slice(0, 10)) {
|
|
148
|
+
const days = Math.floor((now - s.mtimeMs) / (1000 * 60 * 60 * 24));
|
|
149
|
+
console.log(kleur.dim(` ${s.file} — ${days}d`));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=curate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curate.js","sourceRoot":"","sources":["../../../src/cli/commands/curate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord doctor` — readiness check for the local-first setup (G11).
|
|
3
|
+
*
|
|
4
|
+
* Verifies (and reports clearly) the four things that block real use:
|
|
5
|
+
* 1. API key present (~/.ricord/config.json)
|
|
6
|
+
* 2. Project bound (.ricord/ledger.json has project_id)
|
|
7
|
+
* 3. Local `claude` CLI installed (Claude Code) for rollup + build
|
|
8
|
+
* 4. Cloud reachable (auth-gated /v1/health-like ping)
|
|
9
|
+
*
|
|
10
|
+
* Exit 0 if everything green; exit 1 if anything fails.
|
|
11
|
+
*/
|
|
12
|
+
interface DoctorOpts {
|
|
13
|
+
repoRoot: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function doctorCommand(opts: DoctorOpts): Promise<number>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord doctor` — readiness check for the local-first setup (G11).
|
|
3
|
+
*
|
|
4
|
+
* Verifies (and reports clearly) the four things that block real use:
|
|
5
|
+
* 1. API key present (~/.ricord/config.json)
|
|
6
|
+
* 2. Project bound (.ricord/ledger.json has project_id)
|
|
7
|
+
* 3. Local `claude` CLI installed (Claude Code) for rollup + build
|
|
8
|
+
* 4. Cloud reachable (auth-gated /v1/health-like ping)
|
|
9
|
+
*
|
|
10
|
+
* Exit 0 if everything green; exit 1 if anything fails.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import kleur from "kleur";
|
|
16
|
+
import { readLedger, ledgerDir } from "../ledger.js";
|
|
17
|
+
async function checkApiKey() {
|
|
18
|
+
const cfg = join(homedir(), ".ricord", "config.json");
|
|
19
|
+
if (!existsSync(cfg)) {
|
|
20
|
+
return { name: "api key", ok: false, detail: `missing — run \`ricord setup\` (~/.ricord/config.json)` };
|
|
21
|
+
}
|
|
22
|
+
return { name: "api key", ok: true, detail: `~/.ricord/config.json` };
|
|
23
|
+
}
|
|
24
|
+
async function checkProject(repoRoot) {
|
|
25
|
+
const ledger = await readLedger(repoRoot);
|
|
26
|
+
if (!ledger.project_id) {
|
|
27
|
+
return { name: "project", ok: false, detail: `no project_id — run \`ricord init --project <id>\`` };
|
|
28
|
+
}
|
|
29
|
+
return { name: "project", ok: true, detail: `bound to ${ledger.project_id}` };
|
|
30
|
+
}
|
|
31
|
+
async function checkLlm() {
|
|
32
|
+
// ONLY path is the local `claude` CLI. No paid-API fallback by
|
|
33
|
+
// design (see _pinned_top_never_paid_api_for_heavy_work memory).
|
|
34
|
+
const { spawn } = await import("node:child_process");
|
|
35
|
+
const haveClaude = await new Promise((res) => {
|
|
36
|
+
const c = spawn("claude", ["--version"], { stdio: "ignore" });
|
|
37
|
+
c.on("error", () => res(false));
|
|
38
|
+
c.on("close", (code) => res(code === 0));
|
|
39
|
+
});
|
|
40
|
+
if (haveClaude) {
|
|
41
|
+
return { name: "llm", ok: true, detail: `claude cli (Max subscription, no per-call billing)` };
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
name: "llm",
|
|
45
|
+
ok: false,
|
|
46
|
+
detail: `install Claude Code CLI: https://claude.com/claude-code`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function checkCloud() {
|
|
50
|
+
try {
|
|
51
|
+
const base = process.env.RICORD_API_BASE ?? "https://api.ricord.ai";
|
|
52
|
+
const r = await fetch(`${base}/health`);
|
|
53
|
+
if (!r.ok)
|
|
54
|
+
return { name: "cloud", ok: false, detail: `GET ${base}/health → ${r.status}` };
|
|
55
|
+
return { name: "cloud", ok: true, detail: `api reachable` };
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
return { name: "cloud", ok: false, detail: e.message };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function checkLayout(repoRoot) {
|
|
62
|
+
const dir = ledgerDir(repoRoot);
|
|
63
|
+
const pages = join(dir, "pages");
|
|
64
|
+
if (!existsSync(pages)) {
|
|
65
|
+
return { name: "layout", ok: false, detail: `.ricord/pages/ missing — \`ricord init\` to create it` };
|
|
66
|
+
}
|
|
67
|
+
return { name: "layout", ok: true, detail: `.ricord/{pages,ledger.json} present` };
|
|
68
|
+
}
|
|
69
|
+
export async function doctorCommand(opts) {
|
|
70
|
+
const checks = [
|
|
71
|
+
await checkApiKey(),
|
|
72
|
+
await checkProject(opts.repoRoot),
|
|
73
|
+
checkLayout(opts.repoRoot),
|
|
74
|
+
await checkLlm(),
|
|
75
|
+
await checkCloud(),
|
|
76
|
+
];
|
|
77
|
+
console.log(kleur.bold("ricord doctor"));
|
|
78
|
+
let allOk = true;
|
|
79
|
+
for (const c of checks) {
|
|
80
|
+
const tick = c.ok ? kleur.green("✓") : kleur.red("✗");
|
|
81
|
+
console.log(` ${tick} ${c.name.padEnd(10)} ${kleur.dim(c.detail)}`);
|
|
82
|
+
if (!c.ok)
|
|
83
|
+
allOk = false;
|
|
84
|
+
}
|
|
85
|
+
if (allOk) {
|
|
86
|
+
console.log(kleur.green("\nall green."));
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
console.log(kleur.yellow("\nfix the ✗ rows above before running ricord rollup / push."));
|
|
90
|
+
return 1;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord ingest [--mode initial|sync] [--project <id>] [--paths a,b,c]`
|
|
3
|
+
*
|
|
4
|
+
* Walks the repo, packages the working set into per-cluster batches, and
|
|
5
|
+
* POSTs them to /v1/ingest/repo. The server does no LLM work; the client
|
|
6
|
+
* is responsible for running its host LLM against the CODE_ANCHOR_PROMPT
|
|
7
|
+
* fetched from /v1/extraction/prompt?mode=code (server-injects existing
|
|
8
|
+
* topics when ?project_id= is supplied).
|
|
9
|
+
*
|
|
10
|
+
* This S5 slice ships the *transport* — file discovery, batching, server
|
|
11
|
+
* upload, ledger update. The host-LLM extraction step is exposed via a
|
|
12
|
+
* `--prepare` flag that prints the prompt + a JSON envelope template so
|
|
13
|
+
* the user can pipe it into their LLM of choice. Future slices wire a
|
|
14
|
+
* built-in extractor for opinionated default flows.
|
|
15
|
+
*/
|
|
16
|
+
interface IngestOpts {
|
|
17
|
+
mode: "initial" | "sync";
|
|
18
|
+
projectId?: string;
|
|
19
|
+
paths?: string[];
|
|
20
|
+
prepare: boolean;
|
|
21
|
+
dryRun: boolean;
|
|
22
|
+
repoRoot: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function ingestCommand(opts: IngestOpts): Promise<number>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord ingest [--mode initial|sync] [--project <id>] [--paths a,b,c]`
|
|
3
|
+
*
|
|
4
|
+
* Walks the repo, packages the working set into per-cluster batches, and
|
|
5
|
+
* POSTs them to /v1/ingest/repo. The server does no LLM work; the client
|
|
6
|
+
* is responsible for running its host LLM against the CODE_ANCHOR_PROMPT
|
|
7
|
+
* fetched from /v1/extraction/prompt?mode=code (server-injects existing
|
|
8
|
+
* topics when ?project_id= is supplied).
|
|
9
|
+
*
|
|
10
|
+
* This S5 slice ships the *transport* — file discovery, batching, server
|
|
11
|
+
* upload, ledger update. The host-LLM extraction step is exposed via a
|
|
12
|
+
* `--prepare` flag that prints the prompt + a JSON envelope template so
|
|
13
|
+
* the user can pipe it into their LLM of choice. Future slices wire a
|
|
14
|
+
* built-in extractor for opinionated default flows.
|
|
15
|
+
*/
|
|
16
|
+
import { readFile, stat } from "node:fs/promises";
|
|
17
|
+
import { resolve, relative } from "node:path";
|
|
18
|
+
import kleur from "kleur";
|
|
19
|
+
import { resolveAuth } from "../config.js";
|
|
20
|
+
import { request } from "../client.js";
|
|
21
|
+
import { readLedger, writeLedger } from "../ledger.js";
|
|
22
|
+
import { walkRepo } from "../walk.js";
|
|
23
|
+
export async function ingestCommand(opts) {
|
|
24
|
+
const auth = await resolveAuth();
|
|
25
|
+
const ledger = await readLedger(opts.repoRoot);
|
|
26
|
+
const projectId = opts.projectId ?? ledger.project_id;
|
|
27
|
+
if (!projectId) {
|
|
28
|
+
console.error(kleur.red("project_id is required — pass --project <id> or run `ricord ingest --project <id>` once to record it."));
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
const files = await walkRepo(opts.repoRoot, opts.paths);
|
|
32
|
+
if (files.length === 0) {
|
|
33
|
+
console.log(kleur.yellow("Nothing to ingest — repo walk produced 0 files."));
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
if (opts.prepare) {
|
|
37
|
+
const prompt = await request(auth, `/v1/extraction/prompt?mode=code&project_id=${encodeURIComponent(projectId)}`);
|
|
38
|
+
console.log(prompt.prompt);
|
|
39
|
+
console.log();
|
|
40
|
+
console.log(kleur.dim(`--- Files (${files.length}) ---`));
|
|
41
|
+
for (const f of files.slice(0, 50)) {
|
|
42
|
+
console.log(kleur.dim(` ${relative(opts.repoRoot, f.absPath)}`));
|
|
43
|
+
}
|
|
44
|
+
if (files.length > 50)
|
|
45
|
+
console.log(kleur.dim(` …${files.length - 50} more`));
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
if (opts.dryRun) {
|
|
49
|
+
console.log(kleur.bold(`Would ingest ${files.length} files into project ${projectId}.`));
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
// Single batch for now; clustering by directory is a follow-up. The
|
|
53
|
+
// server caps batches at 40 and files-per-batch at 500.
|
|
54
|
+
const batchFiles = [];
|
|
55
|
+
for (const f of files.slice(0, 500)) {
|
|
56
|
+
try {
|
|
57
|
+
const s = await stat(f.absPath);
|
|
58
|
+
if (s.size > 200_000)
|
|
59
|
+
continue; // skip very large files
|
|
60
|
+
const content = await readFile(f.absPath, "utf8");
|
|
61
|
+
batchFiles.push({ path: relative(opts.repoRoot, f.absPath), content });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// unreadable — skip
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const repoMeta = await detectRepoMeta(opts.repoRoot);
|
|
68
|
+
const body = {
|
|
69
|
+
project_id: projectId,
|
|
70
|
+
repo: repoMeta,
|
|
71
|
+
batches: [
|
|
72
|
+
{
|
|
73
|
+
cluster_name: "default",
|
|
74
|
+
files: batchFiles,
|
|
75
|
+
extracted: {
|
|
76
|
+
// Pre-LLM ingest mode lands the *files* without anchors. The user
|
|
77
|
+
// can then run a separate extraction step pointing at this repo.
|
|
78
|
+
// Anchor-emitting flows piping a host-LLM output go through
|
|
79
|
+
// /v1/ingest/extracted directly.
|
|
80
|
+
anchors: [],
|
|
81
|
+
},
|
|
82
|
+
extraction_meta: { client: "ricord-cli", mode: "code" },
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
const out = await request(auth, "/v1/ingest/repo", {
|
|
87
|
+
method: "POST",
|
|
88
|
+
body: JSON.stringify(body),
|
|
89
|
+
});
|
|
90
|
+
// Update ledger
|
|
91
|
+
await writeLedger(opts.repoRoot, {
|
|
92
|
+
...ledger,
|
|
93
|
+
project_id: projectId,
|
|
94
|
+
repo: repoMeta,
|
|
95
|
+
last_synced_at: Date.now(),
|
|
96
|
+
});
|
|
97
|
+
console.log(kleur.green("✓"), `repo ${out.repo_id} — ${out.pages_written} pages, ${out.links_written} links, ${out.files_indexed} file refs.`);
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
async function detectRepoMeta(repoRoot) {
|
|
101
|
+
// Best-effort git introspection without shelling out — read .git/config
|
|
102
|
+
// and .git/HEAD. If anything fails, fall back to root path as remote_url.
|
|
103
|
+
try {
|
|
104
|
+
const cfg = await readFile(resolve(repoRoot, ".git/config"), "utf8");
|
|
105
|
+
const m = cfg.match(/url\s*=\s*([^\s]+)/);
|
|
106
|
+
const head = await readFile(resolve(repoRoot, ".git/HEAD"), "utf8");
|
|
107
|
+
const branch = head.startsWith("ref:") ? head.slice(5).trim().split("/").pop() : undefined;
|
|
108
|
+
return {
|
|
109
|
+
remote_url: m?.[1] ?? `file://${resolve(repoRoot)}`,
|
|
110
|
+
branch,
|
|
111
|
+
root_name: resolve(repoRoot).split("/").pop(),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return {
|
|
116
|
+
remote_url: `file://${resolve(repoRoot)}`,
|
|
117
|
+
root_name: resolve(repoRoot).split("/").pop(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../../src/cli/commands/ingest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord install [--uninstall]` — manage the optional macOS launchd
|
|
3
|
+
* transcript daemon (F1 / S6).
|
|
4
|
+
*
|
|
5
|
+
* Writes a LaunchAgent plist at
|
|
6
|
+
* ~/Library/LaunchAgents/ai.ricord.sync.plist
|
|
7
|
+
* that fires `ricord sync` every 5 minutes against the user's recorded
|
|
8
|
+
* workspaces. Idempotent.
|
|
9
|
+
*
|
|
10
|
+
* Linux is not yet supported; emit a friendly message.
|
|
11
|
+
*/
|
|
12
|
+
interface InstallOpts {
|
|
13
|
+
uninstall: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function installCommand(opts: InstallOpts): Promise<number>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord install [--uninstall]` — manage the optional macOS launchd
|
|
3
|
+
* transcript daemon (F1 / S6).
|
|
4
|
+
*
|
|
5
|
+
* Writes a LaunchAgent plist at
|
|
6
|
+
* ~/Library/LaunchAgents/ai.ricord.sync.plist
|
|
7
|
+
* that fires `ricord sync` every 5 minutes against the user's recorded
|
|
8
|
+
* workspaces. Idempotent.
|
|
9
|
+
*
|
|
10
|
+
* Linux is not yet supported; emit a friendly message.
|
|
11
|
+
*/
|
|
12
|
+
import { writeFile, mkdir, unlink } from "node:fs/promises";
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { homedir, platform } from "node:os";
|
|
15
|
+
import { join, dirname, resolve } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import kleur from "kleur";
|
|
18
|
+
const PLIST_LABEL = "ai.ricord.sync";
|
|
19
|
+
function plistPath() {
|
|
20
|
+
return join(homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
21
|
+
}
|
|
22
|
+
function plistBody(nodePath, scriptPath) {
|
|
23
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
24
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
25
|
+
<plist version="1.0">
|
|
26
|
+
<dict>
|
|
27
|
+
<key>Label</key><string>${PLIST_LABEL}</string>
|
|
28
|
+
<key>ProgramArguments</key>
|
|
29
|
+
<array>
|
|
30
|
+
<string>${nodePath}</string>
|
|
31
|
+
<string>${scriptPath}</string>
|
|
32
|
+
<string>sync</string>
|
|
33
|
+
</array>
|
|
34
|
+
<key>StartInterval</key><integer>300</integer>
|
|
35
|
+
<key>RunAtLoad</key><true/>
|
|
36
|
+
<key>StandardOutPath</key><string>${join(homedir(), ".ricord", "logs", "sync.out.log")}</string>
|
|
37
|
+
<key>StandardErrorPath</key><string>${join(homedir(), ".ricord", "logs", "sync.err.log")}</string>
|
|
38
|
+
</dict>
|
|
39
|
+
</plist>
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
/** Resolve the absolute path to the `bin/ricord.js` shim shipped in this
|
|
43
|
+
* package. Works both when installed globally (`bun install -g`) and when
|
|
44
|
+
* consumed via `bun link` from a checkout. */
|
|
45
|
+
function resolveRicordScript() {
|
|
46
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
// dist/commands/install.js → ../../bin/ricord.js
|
|
48
|
+
return resolve(here, "..", "..", "bin", "ricord.js");
|
|
49
|
+
}
|
|
50
|
+
export async function installCommand(opts) {
|
|
51
|
+
if (platform() !== "darwin") {
|
|
52
|
+
console.error(kleur.red("daemon install only supports macOS in this release. Use `ricord sync` from cron on Linux."));
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
const target = plistPath();
|
|
56
|
+
if (opts.uninstall) {
|
|
57
|
+
if (existsSync(target)) {
|
|
58
|
+
await unlink(target);
|
|
59
|
+
console.log(kleur.green("✓"), `removed ${target}`);
|
|
60
|
+
console.log(kleur.dim("then run: launchctl unload ~/Library/LaunchAgents/ai.ricord.sync.plist"));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.log(kleur.yellow("nothing to uninstall."));
|
|
64
|
+
}
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
await mkdir(join(homedir(), "Library", "LaunchAgents"), { recursive: true });
|
|
68
|
+
await mkdir(join(homedir(), ".ricord", "logs"), { recursive: true });
|
|
69
|
+
const nodePath = process.execPath;
|
|
70
|
+
const scriptPath = resolveRicordScript();
|
|
71
|
+
if (!existsSync(scriptPath)) {
|
|
72
|
+
console.error(kleur.red(`could not find ricord shim at ${scriptPath}`));
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
await writeFile(target, plistBody(nodePath, scriptPath), "utf8");
|
|
76
|
+
console.log(kleur.green("✓"), `wrote ${target}`);
|
|
77
|
+
console.log(kleur.dim(` node: ${nodePath}`));
|
|
78
|
+
console.log(kleur.dim(` script: ${scriptPath}`));
|
|
79
|
+
console.log(kleur.dim("then run: launchctl load ~/Library/LaunchAgents/ai.ricord.sync.plist"));
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ricord pull [--out .ricord/pages/] [--merge] [--force]` — pull cloud
|
|
3
|
+
* pages onto local disk (F6 / S7 / G11 tick 28).
|
|
4
|
+
*
|
|
5
|
+
* Three modes:
|
|
6
|
+
* default — write a fresh page if absent; SKIP if already on disk
|
|
7
|
+
* --force — overwrite local files unconditionally
|
|
8
|
+
* --merge — for any file that exists locally AND has been edited since
|
|
9
|
+
* ledger.last_pulled_at, write the server copy as
|
|
10
|
+
* `<slug>.cloud.md` next to the local file so the user can
|
|
11
|
+
* diff + reconcile manually. Otherwise overwrite (cloud wins
|
|
12
|
+
* when there's no local change since the last pull).
|
|
13
|
+
*
|
|
14
|
+
* On success, advances ledger.last_pulled_at.
|
|
15
|
+
*/
|
|
16
|
+
interface PullOpts {
|
|
17
|
+
repoRoot: string;
|
|
18
|
+
out: string;
|
|
19
|
+
projectId?: string;
|
|
20
|
+
force?: boolean;
|
|
21
|
+
merge?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function pullCommand(opts: PullOpts): Promise<number>;
|
|
24
|
+
export {};
|