@agentproto/corpus-cli 0.1.0-alpha.2 → 0.1.0-alpha.4
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.mjs +162 -14
- package/dist/cli.mjs.map +1 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -7,11 +7,12 @@ import { fileURLToPath, pathToFileURL } from 'url';
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { randomBytes, randomUUID } from 'crypto';
|
|
9
9
|
import { readFileSync, existsSync } from 'fs';
|
|
10
|
-
import { buildDistillPrompt, parseItems, isRefinedKind, SyncRunner, resolveKnowledge, DistillRunner, systemClock, WebImporter, ImporterRunner, CorpusEventEmitter, CorpusWorkspaceReader, CorpusLinter, CorpusValidator, normalizeLanguageTag } from '@agentproto/corpus';
|
|
10
|
+
import { buildDistillPrompt, parseItems, isRefinedKind, SyncRunner, resolveKnowledge, DistillRunner, systemClock, WebImporter, ImporterRunner, CorpusEventEmitter, CorpusWorkspaceReader, CorpusLinter, CorpusValidator, ReadOnlyFs, normalizeLanguageTag } from '@agentproto/corpus';
|
|
11
11
|
import matter2 from 'gray-matter';
|
|
12
12
|
import { execFile } from 'child_process';
|
|
13
13
|
import { promisify } from 'util';
|
|
14
14
|
import { parseClaudeJsonOutput, spawnWithStdin } from '@agentproto/cli-exec';
|
|
15
|
+
import { stitchReport, buildPacks, reportConfigSchema } from '@agentproto/corpus/report';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @agentproto/corpus-cli v0.1.0-alpha
|
|
@@ -103,9 +104,9 @@ function resolvePackageJson(packageName) {
|
|
|
103
104
|
}
|
|
104
105
|
return null;
|
|
105
106
|
}
|
|
106
|
-
async function readJsonIfExists(
|
|
107
|
+
async function readJsonIfExists(path5) {
|
|
107
108
|
try {
|
|
108
|
-
const raw = await readFile(
|
|
109
|
+
const raw = await readFile(path5, "utf8");
|
|
109
110
|
return JSON.parse(raw);
|
|
110
111
|
} catch (err) {
|
|
111
112
|
if (err.code === "ENOENT") return void 0;
|
|
@@ -114,9 +115,9 @@ async function readJsonIfExists(path4) {
|
|
|
114
115
|
}
|
|
115
116
|
async function readConfiguredPresetPackages() {
|
|
116
117
|
const base = process.env["AGENTPROTO_HOME"] ?? join(homedir(), ".agentproto");
|
|
117
|
-
const
|
|
118
|
+
const path5 = join(base, "config.json");
|
|
118
119
|
try {
|
|
119
|
-
const raw = await readFile(
|
|
120
|
+
const raw = await readFile(path5, "utf8");
|
|
120
121
|
const parsed = JSON.parse(raw);
|
|
121
122
|
const list = parsed.corpusPresetPackages;
|
|
122
123
|
if (Array.isArray(list) && list.length > 0) return list;
|
|
@@ -453,6 +454,10 @@ Run \`corpus init --list\` for available presets.`,
|
|
|
453
454
|
2
|
|
454
455
|
);
|
|
455
456
|
}
|
|
457
|
+
if (!presetSlug) {
|
|
458
|
+
const nameErr = invalidCorpusName(name);
|
|
459
|
+
if (nameErr) return fail(nameErr, 2);
|
|
460
|
+
}
|
|
456
461
|
const target = resolveWorkspacePath(pathArg);
|
|
457
462
|
const fs = new NodeFsAdapter({ root: target });
|
|
458
463
|
if (await fs.exists("KNOWLEDGE.md")) {
|
|
@@ -507,6 +512,19 @@ Try: corpus import-web ${pathArg ?? "."} --urls-file urls.txt
|
|
|
507
512
|
);
|
|
508
513
|
return 0;
|
|
509
514
|
}
|
|
515
|
+
var CORPUS_NAME_RE = /^[a-z][a-z0-9-]*[a-z0-9]$/;
|
|
516
|
+
function invalidCorpusName(name) {
|
|
517
|
+
if (name.length >= 2 && name.length <= 96 && CORPUS_NAME_RE.test(name)) {
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
const suggestion = slugifyName(name);
|
|
521
|
+
const hint = suggestion.length >= 2 && CORPUS_NAME_RE.test(suggestion) ? `
|
|
522
|
+
Did you mean: ${suggestion}` : "";
|
|
523
|
+
return `init: invalid corpus name "${name}". A corpus name is a kebab-case identifier \u2014 lowercase letters, digits and hyphens, 2\u201396 chars, starting with a letter and ending alphanumerically (^[a-z][a-z0-9-]*[a-z0-9]$).${hint}`;
|
|
524
|
+
}
|
|
525
|
+
function slugifyName(raw) {
|
|
526
|
+
return raw.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
527
|
+
}
|
|
510
528
|
function splitList(v) {
|
|
511
529
|
return (v ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
512
530
|
}
|
|
@@ -1126,18 +1144,18 @@ var AssemblyAiStt = class {
|
|
|
1126
1144
|
...job.language_code ? { language: job.language_code } : {}
|
|
1127
1145
|
};
|
|
1128
1146
|
}
|
|
1129
|
-
async post(
|
|
1130
|
-
const r = await fetch(`${this.baseUrl}${
|
|
1147
|
+
async post(path5, body) {
|
|
1148
|
+
const r = await fetch(`${this.baseUrl}${path5}`, {
|
|
1131
1149
|
method: "POST",
|
|
1132
1150
|
headers: { authorization: this.apiKey, "content-type": "application/json" },
|
|
1133
1151
|
body: JSON.stringify(body)
|
|
1134
1152
|
});
|
|
1135
|
-
if (!r.ok) throw new Error(`AssemblyAI POST ${
|
|
1153
|
+
if (!r.ok) throw new Error(`AssemblyAI POST ${path5} ${r.status}: ${(await r.text()).slice(0, 200)}`);
|
|
1136
1154
|
return AAI_TRANSCRIPT.parse(await r.json());
|
|
1137
1155
|
}
|
|
1138
|
-
async get(
|
|
1139
|
-
const r = await fetch(`${this.baseUrl}${
|
|
1140
|
-
if (!r.ok) throw new Error(`AssemblyAI GET ${
|
|
1156
|
+
async get(path5) {
|
|
1157
|
+
const r = await fetch(`${this.baseUrl}${path5}`, { headers: { authorization: this.apiKey } });
|
|
1158
|
+
if (!r.ok) throw new Error(`AssemblyAI GET ${path5} ${r.status}: ${(await r.text()).slice(0, 200)}`);
|
|
1141
1159
|
return AAI_TRANSCRIPT.parse(await r.json());
|
|
1142
1160
|
}
|
|
1143
1161
|
};
|
|
@@ -2003,13 +2021,13 @@ async function readSources(root) {
|
|
|
2003
2021
|
const out = [];
|
|
2004
2022
|
for (const e of entries) {
|
|
2005
2023
|
if (!e.isFile() || !e.name.endsWith(".md")) continue;
|
|
2006
|
-
const
|
|
2024
|
+
const path5 = join(e.parentPath, e.name);
|
|
2007
2025
|
try {
|
|
2008
|
-
const parsed = matter2(await readFile(
|
|
2026
|
+
const parsed = matter2(await readFile(path5, "utf-8"));
|
|
2009
2027
|
const fm = SOURCE_FRONTMATTER.parse(parsed.data);
|
|
2010
2028
|
if (!fm.id || !parsed.content.trim()) continue;
|
|
2011
2029
|
out.push({
|
|
2012
|
-
path:
|
|
2030
|
+
path: path5,
|
|
2013
2031
|
id: fm.id,
|
|
2014
2032
|
title: fm.title ?? fm.id,
|
|
2015
2033
|
body: parsed.content.trim(),
|
|
@@ -2168,6 +2186,126 @@ async function runKnowledge(args) {
|
|
|
2168
2186
|
}
|
|
2169
2187
|
return 0;
|
|
2170
2188
|
}
|
|
2189
|
+
async function runReport(args) {
|
|
2190
|
+
const [sub, ...rest] = args;
|
|
2191
|
+
switch (sub) {
|
|
2192
|
+
case "packs":
|
|
2193
|
+
return await runReportPacks(rest);
|
|
2194
|
+
case "stitch":
|
|
2195
|
+
return await runReportStitch(rest);
|
|
2196
|
+
case void 0:
|
|
2197
|
+
return fail("report needs a subcommand (packs | stitch). Try --help.", 2);
|
|
2198
|
+
default:
|
|
2199
|
+
return fail(`unknown report subcommand "${sub}". Try --help.`, 2);
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
function loadReportConfig(configPath) {
|
|
2203
|
+
const raw = readFileSync(path.resolve(process.cwd(), configPath), "utf8");
|
|
2204
|
+
return reportConfigSchema.parse(JSON.parse(raw));
|
|
2205
|
+
}
|
|
2206
|
+
async function runReportPacks(args) {
|
|
2207
|
+
let dataset;
|
|
2208
|
+
let configPath;
|
|
2209
|
+
let out;
|
|
2210
|
+
let viewsDir;
|
|
2211
|
+
for (let i = 0; i < args.length; i++) {
|
|
2212
|
+
const a = args[i];
|
|
2213
|
+
const next = () => args[++i];
|
|
2214
|
+
switch (a) {
|
|
2215
|
+
case "--config":
|
|
2216
|
+
configPath = next();
|
|
2217
|
+
break;
|
|
2218
|
+
case "--out":
|
|
2219
|
+
out = next();
|
|
2220
|
+
break;
|
|
2221
|
+
case "--views-dir":
|
|
2222
|
+
viewsDir = next();
|
|
2223
|
+
break;
|
|
2224
|
+
default:
|
|
2225
|
+
if (!a.startsWith("-") && dataset === void 0) dataset = a;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
const datasetPath = resolveWorkspacePath(dataset);
|
|
2229
|
+
if (!configPath) {
|
|
2230
|
+
return fail("report packs needs --config <report.config.json>.", 2);
|
|
2231
|
+
}
|
|
2232
|
+
let config;
|
|
2233
|
+
try {
|
|
2234
|
+
config = loadReportConfig(configPath);
|
|
2235
|
+
} catch (err) {
|
|
2236
|
+
return fail(
|
|
2237
|
+
`could not load/validate config "${configPath}": ${err instanceof Error ? err.message : String(err)}`,
|
|
2238
|
+
2
|
|
2239
|
+
);
|
|
2240
|
+
}
|
|
2241
|
+
const reportRoot = out ? path.resolve(process.cwd(), out) : datasetPath;
|
|
2242
|
+
const datasetFs = new ReadOnlyFs(new NodeFsAdapter({ root: datasetPath }));
|
|
2243
|
+
const reportFs = new NodeFsAdapter({ root: reportRoot });
|
|
2244
|
+
const result = await buildPacks({
|
|
2245
|
+
dataset: datasetFs,
|
|
2246
|
+
config,
|
|
2247
|
+
...viewsDir ? { viewsDir } : {}
|
|
2248
|
+
});
|
|
2249
|
+
for (const file of result.files) {
|
|
2250
|
+
await reportFs.writeFile(file.path, file.content);
|
|
2251
|
+
}
|
|
2252
|
+
process.stdout.write(
|
|
2253
|
+
`report packs \u2192 ${result.files.length} files \xB7 ${result.bibliography} sources
|
|
2254
|
+
` + result.chapters.map((c) => ` ${c.id}: ${c.entryCount}`).join("\n") + "\n"
|
|
2255
|
+
);
|
|
2256
|
+
return 0;
|
|
2257
|
+
}
|
|
2258
|
+
async function runReportStitch(args) {
|
|
2259
|
+
let reportRoot;
|
|
2260
|
+
let configPath;
|
|
2261
|
+
let out;
|
|
2262
|
+
let chaptersDir;
|
|
2263
|
+
let viewsDir;
|
|
2264
|
+
for (let i = 0; i < args.length; i++) {
|
|
2265
|
+
const a = args[i];
|
|
2266
|
+
const next = () => args[++i];
|
|
2267
|
+
switch (a) {
|
|
2268
|
+
case "--config":
|
|
2269
|
+
configPath = next();
|
|
2270
|
+
break;
|
|
2271
|
+
case "--out":
|
|
2272
|
+
out = next();
|
|
2273
|
+
break;
|
|
2274
|
+
case "--chapters-dir":
|
|
2275
|
+
chaptersDir = next();
|
|
2276
|
+
break;
|
|
2277
|
+
case "--views-dir":
|
|
2278
|
+
viewsDir = next();
|
|
2279
|
+
break;
|
|
2280
|
+
default:
|
|
2281
|
+
if (!a.startsWith("-") && reportRoot === void 0) reportRoot = a;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
const root = resolveWorkspacePath(reportRoot);
|
|
2285
|
+
if (!configPath) {
|
|
2286
|
+
return fail("report stitch needs --config <report.config.json>.", 2);
|
|
2287
|
+
}
|
|
2288
|
+
let config;
|
|
2289
|
+
try {
|
|
2290
|
+
config = loadReportConfig(configPath);
|
|
2291
|
+
} catch (err) {
|
|
2292
|
+
return fail(
|
|
2293
|
+
`could not load/validate config "${configPath}": ${err instanceof Error ? err.message : String(err)}`,
|
|
2294
|
+
2
|
|
2295
|
+
);
|
|
2296
|
+
}
|
|
2297
|
+
const reportFs = new NodeFsAdapter({ root });
|
|
2298
|
+
const { content, wordCount } = await stitchReport({
|
|
2299
|
+
config,
|
|
2300
|
+
report: reportFs,
|
|
2301
|
+
...chaptersDir ? { chaptersDir } : {},
|
|
2302
|
+
...viewsDir ? { viewsDir } : {}
|
|
2303
|
+
});
|
|
2304
|
+
await reportFs.writeFile(out ?? "REPORT.md", content);
|
|
2305
|
+
process.stdout.write(`report stitch \u2192 ${out ?? "REPORT.md"} \xB7 ${wordCount} words
|
|
2306
|
+
`);
|
|
2307
|
+
return 0;
|
|
2308
|
+
}
|
|
2171
2309
|
var RPC_RESPONSE2 = z.object({ result: z.unknown().optional(), error: z.unknown().optional() }).loose();
|
|
2172
2310
|
var RPC_MESSAGE = z.object({
|
|
2173
2311
|
id: z.number().optional(),
|
|
@@ -2566,6 +2704,14 @@ Commands:
|
|
|
2566
2704
|
knowledge [path] --tags a,b [--kind k --access scope --max n]
|
|
2567
2705
|
Preview what a skill's knowledge: binding resolves to
|
|
2568
2706
|
\u2014 refined entries + their provenance (filesystem).
|
|
2707
|
+
report packs [dataset] --config <f> [--out <dir>] [--views-dir <n>]
|
|
2708
|
+
Build per-chapter knowledge views + the global
|
|
2709
|
+
citation bibliography from a dataset. Dataset is
|
|
2710
|
+
mounted read-only; --out (default: dataset) is the
|
|
2711
|
+
only writer; --views-dir defaults to "views".
|
|
2712
|
+
report stitch [report] --config <f> [--out <REPORT.md>] [--chapters-dir <d> --views-dir <n>]
|
|
2713
|
+
Stitch front + parts + chapters + annexes + Sources
|
|
2714
|
+
into one REPORT.md (report-side reads only).
|
|
2569
2715
|
sync [path] --config <sink.json> [--tags a,b --kind k --throttle ms]
|
|
2570
2716
|
Push refined entries to an external store via a
|
|
2571
2717
|
config-driven MCP sink (host-agnostic).
|
|
@@ -2605,6 +2751,8 @@ async function main(argv2) {
|
|
|
2605
2751
|
return await runDistill(rest);
|
|
2606
2752
|
case "knowledge":
|
|
2607
2753
|
return await runKnowledge(rest);
|
|
2754
|
+
case "report":
|
|
2755
|
+
return await runReport(rest);
|
|
2608
2756
|
case "sync":
|
|
2609
2757
|
return await runSync(rest);
|
|
2610
2758
|
default:
|