@agentproto/corpus 0.1.0-alpha.3 → 0.1.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/{chunk-3P23OX5X.mjs → chunk-JV6VRZ6U.mjs} +2 -2
- package/dist/chunk-JV6VRZ6U.mjs.map +1 -0
- package/dist/{chunk-UPX26MYH.mjs → chunk-WF5KGEL6.mjs} +7 -2
- package/dist/chunk-WF5KGEL6.mjs.map +1 -0
- package/dist/index.d.ts +373 -10
- package/dist/index.mjs +362 -38
- package/dist/index.mjs.map +1 -1
- package/dist/report/index.mjs +1 -1
- package/dist/sidecar-WZTZS2I6.mjs +3 -0
- package/dist/{sidecar-TTWQD5R3.mjs.map → sidecar-WZTZS2I6.mjs.map} +1 -1
- package/package.json +4 -4
- package/dist/chunk-3P23OX5X.mjs.map +0 -1
- package/dist/chunk-UPX26MYH.mjs.map +0 -1
- package/dist/sidecar-TTWQD5R3.mjs +0 -3
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { systemClock } from './chunk-KYX2DTEH.mjs';
|
|
2
|
-
import { REFINED_KIND_SCHEMA, resolveKnowledge } from './chunk-
|
|
3
|
-
export { REFINED_KIND_SCHEMA, isRefinedKind, resolveKnowledge } from './chunk-
|
|
4
|
-
import { CandidatesSidecar } from './chunk-
|
|
5
|
-
export { CandidatesSidecar, SidecarDuplicateError, SidecarNotFoundError } from './chunk-
|
|
6
|
-
import
|
|
2
|
+
import { REFINED_KIND_SCHEMA, resolveKnowledge } from './chunk-JV6VRZ6U.mjs';
|
|
3
|
+
export { REFINED_KIND_SCHEMA, isRefinedKind, resolveKnowledge } from './chunk-JV6VRZ6U.mjs';
|
|
4
|
+
import { CandidatesSidecar } from './chunk-WF5KGEL6.mjs';
|
|
5
|
+
export { CandidatesSidecar, SidecarDuplicateError, SidecarNotFoundError } from './chunk-WF5KGEL6.mjs';
|
|
6
|
+
import matter6 from 'gray-matter';
|
|
7
7
|
import { createHash } from 'crypto';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import { parse, stringify } from 'yaml';
|
|
@@ -320,6 +320,7 @@ var CorpusEventEmitter = class {
|
|
|
320
320
|
constructor(opts) {
|
|
321
321
|
this.opts = opts;
|
|
322
322
|
}
|
|
323
|
+
opts;
|
|
323
324
|
/**
|
|
324
325
|
* Emit one event. Returns the event as written (including the
|
|
325
326
|
* ISO timestamp and actor resolved at emit time). The .md log file
|
|
@@ -357,6 +358,7 @@ var CorpusWorkspaceReader = class {
|
|
|
357
358
|
constructor(opts) {
|
|
358
359
|
this.opts = opts;
|
|
359
360
|
}
|
|
361
|
+
opts;
|
|
360
362
|
/**
|
|
361
363
|
* Scan the workspace rooted at `root` and return a typed snapshot.
|
|
362
364
|
* `root` is workspace-relative (the host resolves to a backing
|
|
@@ -379,7 +381,7 @@ var CorpusWorkspaceReader = class {
|
|
|
379
381
|
};
|
|
380
382
|
for (const path of mdFiles) {
|
|
381
383
|
const content = await this.opts.fs.readFile(path);
|
|
382
|
-
const parsed =
|
|
384
|
+
const parsed = matter6(content);
|
|
383
385
|
const file = {
|
|
384
386
|
// Workspace-relative path. The walk returns paths anchored at
|
|
385
387
|
// the host's storage root (which already includes `root` for
|
|
@@ -466,11 +468,15 @@ var CorpusVersionConflictError = class extends Error {
|
|
|
466
468
|
this.actual = actual;
|
|
467
469
|
this.name = "CorpusVersionConflictError";
|
|
468
470
|
}
|
|
471
|
+
path;
|
|
472
|
+
expected;
|
|
473
|
+
actual;
|
|
469
474
|
};
|
|
470
475
|
var CorpusWorkspaceWriter = class _CorpusWorkspaceWriter {
|
|
471
476
|
constructor(opts) {
|
|
472
477
|
this.opts = opts;
|
|
473
478
|
}
|
|
479
|
+
opts;
|
|
474
480
|
/**
|
|
475
481
|
* Compute the versionToken for raw file content. Exposed so the
|
|
476
482
|
* caller can stage a write and pass the same hash function used
|
|
@@ -535,7 +541,7 @@ var CorpusWorkspaceWriter = class _CorpusWorkspaceWriter {
|
|
|
535
541
|
}
|
|
536
542
|
};
|
|
537
543
|
function serializeMarkdown(doc) {
|
|
538
|
-
return
|
|
544
|
+
return matter6.stringify(doc.body.startsWith("\n") ? doc.body : "\n" + doc.body, doc.frontmatter);
|
|
539
545
|
}
|
|
540
546
|
|
|
541
547
|
// src/importers/runner.ts
|
|
@@ -544,6 +550,7 @@ var ImporterRunner = class {
|
|
|
544
550
|
constructor(opts) {
|
|
545
551
|
this.opts = opts;
|
|
546
552
|
}
|
|
553
|
+
opts;
|
|
547
554
|
/**
|
|
548
555
|
* Run a single importer batch end-to-end.
|
|
549
556
|
*
|
|
@@ -673,7 +680,7 @@ function serializeSource(source, archiveDirSegment, clock) {
|
|
|
673
680
|
}
|
|
674
681
|
};
|
|
675
682
|
}
|
|
676
|
-
return
|
|
683
|
+
return matter6.stringify(
|
|
677
684
|
source.body.startsWith("\n") ? source.body : "\n" + source.body,
|
|
678
685
|
fm
|
|
679
686
|
);
|
|
@@ -686,6 +693,7 @@ var LocalFilesImporter = class {
|
|
|
686
693
|
constructor(opts) {
|
|
687
694
|
this.opts = opts;
|
|
688
695
|
}
|
|
696
|
+
opts;
|
|
689
697
|
id = "local-files";
|
|
690
698
|
label = "Local Files";
|
|
691
699
|
async *enumerate(target) {
|
|
@@ -820,6 +828,7 @@ var WebImporter = class {
|
|
|
820
828
|
constructor(opts) {
|
|
821
829
|
this.opts = opts;
|
|
822
830
|
}
|
|
831
|
+
opts;
|
|
823
832
|
id = "web";
|
|
824
833
|
label = "Web (URLs)";
|
|
825
834
|
async *enumerate(target) {
|
|
@@ -886,6 +895,7 @@ var ConversationImporter = class {
|
|
|
886
895
|
constructor(opts) {
|
|
887
896
|
this.opts = opts;
|
|
888
897
|
}
|
|
898
|
+
opts;
|
|
889
899
|
id = "conversation";
|
|
890
900
|
label = "Conversation";
|
|
891
901
|
async *enumerate(target) {
|
|
@@ -991,11 +1001,14 @@ var DistillRunner = class {
|
|
|
991
1001
|
constructor(opts) {
|
|
992
1002
|
this.opts = opts;
|
|
993
1003
|
}
|
|
1004
|
+
opts;
|
|
994
1005
|
async run(source) {
|
|
995
1006
|
const items = await this.opts.distiller.distill({
|
|
996
1007
|
title: source.title,
|
|
997
1008
|
body: source.body,
|
|
998
|
-
...source.tags ? { tags: source.tags } : {}
|
|
1009
|
+
...source.tags ? { tags: source.tags } : {},
|
|
1010
|
+
...source.kinds ? { kinds: source.kinds } : {},
|
|
1011
|
+
...source.instruction ? { instruction: source.instruction } : {}
|
|
999
1012
|
});
|
|
1000
1013
|
const year = this.opts.clock.now().getUTCFullYear();
|
|
1001
1014
|
const flat = this.opts.layout === "flat";
|
|
@@ -1028,7 +1041,7 @@ function serializeEntry(item, slug, source, clock) {
|
|
|
1028
1041
|
sources: [source.id],
|
|
1029
1042
|
// ← derivedFrom / provenance edge
|
|
1030
1043
|
confidence: typeof item.confidence === "number" ? item.confidence : 0.7,
|
|
1031
|
-
tags: dedupeTags(item.tags, source.tags),
|
|
1044
|
+
tags: withAspect(dedupeTags(item.tags, source.tags), source.aspect),
|
|
1032
1045
|
metadata: {
|
|
1033
1046
|
corpus: {
|
|
1034
1047
|
status: "active",
|
|
@@ -1042,7 +1055,14 @@ function serializeEntry(item, slug, source, clock) {
|
|
|
1042
1055
|
}
|
|
1043
1056
|
};
|
|
1044
1057
|
const body = item.body.trim();
|
|
1045
|
-
return
|
|
1058
|
+
return matter6.stringify(body.startsWith("\n") ? body : "\n" + body, fm);
|
|
1059
|
+
}
|
|
1060
|
+
function withAspect(tags, aspect) {
|
|
1061
|
+
if (!aspect) return [...tags];
|
|
1062
|
+
const value = sanitizeTag(aspect);
|
|
1063
|
+
if (!value) return [...tags];
|
|
1064
|
+
const facet = `aspect:${value}`;
|
|
1065
|
+
return tags.includes(facet) ? [...tags] : [facet, ...tags];
|
|
1046
1066
|
}
|
|
1047
1067
|
function dedupeTags(a, b) {
|
|
1048
1068
|
const out = /* @__PURE__ */ new Set();
|
|
@@ -1064,10 +1084,16 @@ var DISTILLED_ITEM = z.object({
|
|
|
1064
1084
|
tags: z.array(z.string()).optional()
|
|
1065
1085
|
}).loose();
|
|
1066
1086
|
function buildDistillPrompt(input, maxItems) {
|
|
1067
|
-
|
|
1087
|
+
const lensBlock = input.instruction?.trim() ? `LENS \u2014 read the source THROUGH this aspect, extract ONLY what serves it:
|
|
1088
|
+
${input.instruction.trim()}
|
|
1089
|
+
|
|
1090
|
+
` : "";
|
|
1091
|
+
const kinds = input.kinds?.length ? input.kinds : ["principle", "pattern", "critique", "summary", "example"];
|
|
1092
|
+
const kindUnion = kinds.map((k) => `"${k}"`).join(" | ");
|
|
1093
|
+
return `${lensBlock}You distill a raw source (a video transcript or article) into REFINED, reusable knowledge for an AI operator. Extract the durable insights \u2014 not a summary of the video, but the transferable lessons.
|
|
1068
1094
|
|
|
1069
1095
|
Return a JSON array (max ${maxItems} items). Each item:
|
|
1070
|
-
{ "kind": one of
|
|
1096
|
+
{ "kind": one of ${kindUnion},
|
|
1071
1097
|
"title": short imperative/declarative title,
|
|
1072
1098
|
"body": 2-5 sentences, SELF-CONTAINED (no "the speaker says"), the actual insight,
|
|
1073
1099
|
"confidence": 0-1, "tags": [short topic tags] }
|
|
@@ -1125,7 +1151,7 @@ async function scanDistilledSourceIds(fs) {
|
|
|
1125
1151
|
if (!rel.endsWith(".md")) continue;
|
|
1126
1152
|
const path = rel.startsWith("entries/") ? rel : `entries/${rel}`;
|
|
1127
1153
|
try {
|
|
1128
|
-
const fm = ENTRY_SOURCES.parse(
|
|
1154
|
+
const fm = ENTRY_SOURCES.parse(matter6(await fs.readFile(path)).data);
|
|
1129
1155
|
if (fm.sources) for (const s of fm.sources) ids.add(s);
|
|
1130
1156
|
} catch {
|
|
1131
1157
|
}
|
|
@@ -1174,47 +1200,309 @@ function createDistillRegistry() {
|
|
|
1174
1200
|
};
|
|
1175
1201
|
}
|
|
1176
1202
|
|
|
1177
|
-
// src/distill/
|
|
1178
|
-
|
|
1203
|
+
// src/distill/lens.ts
|
|
1204
|
+
function lensAspect(lens) {
|
|
1205
|
+
return lens.aspect ?? lens.id;
|
|
1206
|
+
}
|
|
1207
|
+
function lensAspectTag(lens) {
|
|
1208
|
+
return `aspect:${lensAspect(lens)}`;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// src/distill/generate.ts
|
|
1212
|
+
async function distillFromImporter(opts) {
|
|
1179
1213
|
const report = {
|
|
1180
|
-
descriptorId: descriptor.id,
|
|
1181
|
-
scopeId: scope.id,
|
|
1182
1214
|
unitsConsidered: 0,
|
|
1183
1215
|
unitsDistilled: 0,
|
|
1184
1216
|
entriesWritten: 0,
|
|
1185
|
-
skipped: 0
|
|
1217
|
+
skipped: 0,
|
|
1218
|
+
unchanged: 0
|
|
1186
1219
|
};
|
|
1187
|
-
const target = await descriptor.target(scope);
|
|
1188
|
-
const distilled = await scanDistilledSourceIds(target.fs);
|
|
1189
|
-
const binding = descriptor.bind(scope, target);
|
|
1190
|
-
const config = await binding.prepare(distilled);
|
|
1191
|
-
if (!config) return report;
|
|
1192
1220
|
const runner = new DistillRunner({
|
|
1193
|
-
fs:
|
|
1194
|
-
clock:
|
|
1195
|
-
distiller:
|
|
1221
|
+
fs: opts.fs,
|
|
1222
|
+
clock: opts.clock,
|
|
1223
|
+
distiller: opts.distiller,
|
|
1224
|
+
...opts.layout ? { layout: opts.layout } : {}
|
|
1196
1225
|
});
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1226
|
+
const provenanceId = opts.provenanceId ?? ((s) => s.slug);
|
|
1227
|
+
const lensId = opts.lens?.id;
|
|
1228
|
+
for await (const imported of opts.importer.enumerate({
|
|
1229
|
+
importerId: opts.importerId,
|
|
1230
|
+
config: opts.config
|
|
1200
1231
|
})) {
|
|
1201
1232
|
report.unitsConsidered++;
|
|
1233
|
+
const sourceId = provenanceId(imported);
|
|
1234
|
+
if (opts.index && await opts.index.isDistilled(sourceId, imported.contentHash, lensId)) {
|
|
1235
|
+
report.unchanged++;
|
|
1236
|
+
continue;
|
|
1237
|
+
}
|
|
1202
1238
|
const source = {
|
|
1203
|
-
id:
|
|
1239
|
+
id: sourceId,
|
|
1204
1240
|
title: imported.title,
|
|
1205
1241
|
body: imported.body,
|
|
1206
|
-
...imported.tags ? { tags: imported.tags } : {}
|
|
1242
|
+
...imported.tags ? { tags: imported.tags } : {},
|
|
1243
|
+
...opts.lens?.prompt ? { instruction: opts.lens.prompt } : {},
|
|
1244
|
+
...opts.lens?.kinds ? { kinds: opts.lens.kinds } : {},
|
|
1245
|
+
...opts.lens ? { aspect: lensAspect(opts.lens) } : {}
|
|
1207
1246
|
};
|
|
1208
1247
|
try {
|
|
1209
1248
|
const r = await runner.run(source);
|
|
1210
1249
|
if (r.entryPaths.length > 0) report.unitsDistilled++;
|
|
1211
1250
|
report.entriesWritten += r.entryPaths.length;
|
|
1212
1251
|
report.skipped += r.skipped.length;
|
|
1252
|
+
if (opts.index) {
|
|
1253
|
+
await opts.index.record({
|
|
1254
|
+
sourceId,
|
|
1255
|
+
...lensId ? { lensId } : {},
|
|
1256
|
+
title: imported.title,
|
|
1257
|
+
distilledAt: opts.clock.now().toISOString(),
|
|
1258
|
+
...opts.engine ? { engine: opts.engine } : {},
|
|
1259
|
+
...imported.contentHash ? { contentHash: imported.contentHash } : {},
|
|
1260
|
+
entryCount: r.entryPaths.length,
|
|
1261
|
+
...r.entryPaths.length ? { entryPaths: r.entryPaths } : {}
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1213
1264
|
} catch {
|
|
1214
1265
|
}
|
|
1215
1266
|
}
|
|
1216
1267
|
return report;
|
|
1217
1268
|
}
|
|
1269
|
+
|
|
1270
|
+
// src/distill/run.ts
|
|
1271
|
+
async function runDistill(descriptor, scope, opts = {}) {
|
|
1272
|
+
const empty = {
|
|
1273
|
+
unitsConsidered: 0,
|
|
1274
|
+
unitsDistilled: 0,
|
|
1275
|
+
entriesWritten: 0,
|
|
1276
|
+
skipped: 0,
|
|
1277
|
+
unchanged: 0
|
|
1278
|
+
};
|
|
1279
|
+
const target = await descriptor.target(scope);
|
|
1280
|
+
const distilled = await scanDistilledSourceIds(target.fs);
|
|
1281
|
+
const binding = descriptor.bind(scope, target);
|
|
1282
|
+
const config = await binding.prepare(distilled);
|
|
1283
|
+
if (!config) {
|
|
1284
|
+
return { descriptorId: descriptor.id, scopeId: scope.id, ...empty };
|
|
1285
|
+
}
|
|
1286
|
+
const core = await distillFromImporter({
|
|
1287
|
+
fs: target.fs,
|
|
1288
|
+
clock: target.clock,
|
|
1289
|
+
distiller: descriptor.distiller(scope),
|
|
1290
|
+
importer: binding.importer,
|
|
1291
|
+
importerId: descriptor.id,
|
|
1292
|
+
config,
|
|
1293
|
+
provenanceId: binding.provenanceId,
|
|
1294
|
+
...opts.index ? { index: opts.index } : {},
|
|
1295
|
+
...opts.engine ? { engine: opts.engine } : {},
|
|
1296
|
+
...opts.lens ? { lens: opts.lens } : {}
|
|
1297
|
+
});
|
|
1298
|
+
return { descriptorId: descriptor.id, scopeId: scope.id, ...core };
|
|
1299
|
+
}
|
|
1300
|
+
var DISTILL_INDEX_PATH = "_distill-index.yaml";
|
|
1301
|
+
var DistillIndex = class {
|
|
1302
|
+
fs;
|
|
1303
|
+
path;
|
|
1304
|
+
constructor(opts) {
|
|
1305
|
+
this.fs = opts.fs;
|
|
1306
|
+
this.path = opts.path ?? DISTILL_INDEX_PATH;
|
|
1307
|
+
}
|
|
1308
|
+
/** Every record on disk. Empty for a fresh corpus (no file yet). */
|
|
1309
|
+
async load() {
|
|
1310
|
+
if (!await this.fs.exists(this.path)) return [];
|
|
1311
|
+
const content = await this.fs.readFile(this.path);
|
|
1312
|
+
if (!content.trim()) return [];
|
|
1313
|
+
const parsed = parse(content);
|
|
1314
|
+
if (!parsed || !Array.isArray(parsed.runs)) return [];
|
|
1315
|
+
return parsed.runs;
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* The record for a `(sourceId, lensId)` pair, or null if never distilled.
|
|
1319
|
+
* `lensId` undefined matches the generic lens-less row (back-compat).
|
|
1320
|
+
*/
|
|
1321
|
+
async get(sourceId, lensId) {
|
|
1322
|
+
const rows = await this.load();
|
|
1323
|
+
return rows.find((r) => r.sourceId === sourceId && r.lensId === lensId) ?? null;
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* True if the `(source, lens)` pair was distilled with a matching content
|
|
1327
|
+
* hash (when given). Each lens has independent cadence over the same source.
|
|
1328
|
+
*/
|
|
1329
|
+
async isDistilled(sourceId, contentHash, lensId) {
|
|
1330
|
+
const row = await this.get(sourceId, lensId);
|
|
1331
|
+
if (!row) return false;
|
|
1332
|
+
if (contentHash === void 0) return true;
|
|
1333
|
+
return row.contentHash === contentHash;
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Upsert a record by `(sourceId, lensId)`. Re-distilling overwrites that
|
|
1337
|
+
* pair's row (cadence is "latest run wins") while leaving the same source's
|
|
1338
|
+
* other lens rows untouched; a new pair appends. Returns the full list.
|
|
1339
|
+
*/
|
|
1340
|
+
async record(row) {
|
|
1341
|
+
const existing = await this.load();
|
|
1342
|
+
const idx = existing.findIndex(
|
|
1343
|
+
(r) => r.sourceId === row.sourceId && r.lensId === row.lensId
|
|
1344
|
+
);
|
|
1345
|
+
const next = idx === -1 ? [...existing, row] : [...existing.slice(0, idx), row, ...existing.slice(idx + 1)];
|
|
1346
|
+
await this.write(next);
|
|
1347
|
+
return next;
|
|
1348
|
+
}
|
|
1349
|
+
/** Whole-file replace. Prefer {@link record} for normal flow. */
|
|
1350
|
+
async write(runs) {
|
|
1351
|
+
const shape = { runs };
|
|
1352
|
+
await this.fs.writeFile(this.path, stringify(shape));
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
var SYNTHESIS_ROLE_TAG = "role:synthesis";
|
|
1356
|
+
var ATOM_FRONTMATTER = z.object({
|
|
1357
|
+
schema: z.string().optional().catch(void 0),
|
|
1358
|
+
slug: z.string().optional().catch(void 0),
|
|
1359
|
+
title: z.string().optional().catch(void 0),
|
|
1360
|
+
sources: z.array(z.string()).optional().catch(void 0),
|
|
1361
|
+
confidence: z.number().optional().catch(void 0),
|
|
1362
|
+
tags: z.array(z.string()).optional().catch(void 0),
|
|
1363
|
+
supersedes: z.array(z.string()).optional().catch(void 0),
|
|
1364
|
+
metadata: z.object({
|
|
1365
|
+
corpus: z.object({ status: z.string().optional().catch(void 0) }).loose().optional().catch(void 0)
|
|
1366
|
+
}).loose().optional().catch(void 0)
|
|
1367
|
+
}).loose();
|
|
1368
|
+
async function readEntries(fs) {
|
|
1369
|
+
let rels;
|
|
1370
|
+
try {
|
|
1371
|
+
rels = await fs.walk("entries");
|
|
1372
|
+
} catch {
|
|
1373
|
+
return [];
|
|
1374
|
+
}
|
|
1375
|
+
const out = [];
|
|
1376
|
+
for (const rel of rels) {
|
|
1377
|
+
if (!rel.endsWith(".md")) continue;
|
|
1378
|
+
const path = `entries/${rel}`;
|
|
1379
|
+
let parsed;
|
|
1380
|
+
try {
|
|
1381
|
+
parsed = matter6(await fs.readFile(path));
|
|
1382
|
+
} catch {
|
|
1383
|
+
continue;
|
|
1384
|
+
}
|
|
1385
|
+
const fm = ATOM_FRONTMATTER.parse(parsed.data);
|
|
1386
|
+
if (fm.schema !== "knowledge.entry/v1") continue;
|
|
1387
|
+
const tags = fm.tags ?? [];
|
|
1388
|
+
out.push({
|
|
1389
|
+
slug: fm.slug ?? path,
|
|
1390
|
+
title: fm.title ?? "",
|
|
1391
|
+
body: parsed.content.trim(),
|
|
1392
|
+
confidence: fm.confidence ?? 0,
|
|
1393
|
+
tags,
|
|
1394
|
+
supersedes: fm.supersedes ?? [],
|
|
1395
|
+
path,
|
|
1396
|
+
archived: fm.metadata?.corpus?.status === "archived",
|
|
1397
|
+
isSynthesis: tags.includes(SYNTHESIS_ROLE_TAG)
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
return out;
|
|
1401
|
+
}
|
|
1402
|
+
async function currentLensAtoms(fs, lens) {
|
|
1403
|
+
const aspectTag = lensAspectTag(lens);
|
|
1404
|
+
const entries = await readEntries(fs);
|
|
1405
|
+
const superseded = /* @__PURE__ */ new Set();
|
|
1406
|
+
for (const e of entries) for (const s of e.supersedes) superseded.add(s);
|
|
1407
|
+
return entries.filter(
|
|
1408
|
+
(e) => !e.archived && !e.isSynthesis && e.tags.includes(aspectTag) && !superseded.has(e.slug)
|
|
1409
|
+
).sort((a, b) => b.confidence - a.confidence).map((e) => ({ slug: e.slug, title: e.title, body: e.body }));
|
|
1410
|
+
}
|
|
1411
|
+
function defaultSynthesisPath(lens) {
|
|
1412
|
+
return `entries/summaries/${lensAspect(lens)}-knowledge.md`;
|
|
1413
|
+
}
|
|
1414
|
+
async function lensSynthesisStale(fs, lens) {
|
|
1415
|
+
const atoms = await currentLensAtoms(fs, lens);
|
|
1416
|
+
const atomSlugs = new Set(atoms.map((a) => a.slug));
|
|
1417
|
+
const path = lens.synthesisPath ?? defaultSynthesisPath(lens);
|
|
1418
|
+
if (!await fs.exists(path)) {
|
|
1419
|
+
return { stale: atoms.length > 0, reason: atoms.length > 0 ? "missing" : "fresh", atomCount: atoms.length };
|
|
1420
|
+
}
|
|
1421
|
+
let recorded = [];
|
|
1422
|
+
try {
|
|
1423
|
+
const fm = ATOM_FRONTMATTER.parse(matter6(await fs.readFile(path)).data);
|
|
1424
|
+
recorded = fm.sources ?? [];
|
|
1425
|
+
} catch {
|
|
1426
|
+
return { stale: true, reason: "drifted", atomCount: atoms.length };
|
|
1427
|
+
}
|
|
1428
|
+
const recordedSet = new Set(recorded);
|
|
1429
|
+
const same = recordedSet.size === atomSlugs.size && [...atomSlugs].every((s) => recordedSet.has(s));
|
|
1430
|
+
return {
|
|
1431
|
+
stale: !same,
|
|
1432
|
+
reason: same ? "fresh" : "drifted",
|
|
1433
|
+
atomCount: atoms.length
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
async function synthesizeLens(opts) {
|
|
1437
|
+
const { fs, clock, synthesizer, lens } = opts;
|
|
1438
|
+
const aspect = lensAspect(lens);
|
|
1439
|
+
const entries = await readEntries(fs);
|
|
1440
|
+
const aspectTag = lensAspectTag(lens);
|
|
1441
|
+
const considered = entries.filter(
|
|
1442
|
+
(e) => !e.archived && !e.isSynthesis && e.tags.includes(aspectTag)
|
|
1443
|
+
).length;
|
|
1444
|
+
const atoms = await currentLensAtoms(fs, lens);
|
|
1445
|
+
if (atoms.length === 0) {
|
|
1446
|
+
return { lensId: lens.id, aspect, atomsConsidered: considered, atomsUsed: 0, wrote: false };
|
|
1447
|
+
}
|
|
1448
|
+
const body = await synthesizer.synthesize({ aspect, label: lens.label, atoms });
|
|
1449
|
+
const path = lens.synthesisPath ?? defaultSynthesisPath(lens);
|
|
1450
|
+
await fs.writeFile(path, serializeSynthesis(body, lens, atoms, clock));
|
|
1451
|
+
return {
|
|
1452
|
+
lensId: lens.id,
|
|
1453
|
+
aspect,
|
|
1454
|
+
atomsConsidered: considered,
|
|
1455
|
+
atomsUsed: atoms.length,
|
|
1456
|
+
wrote: true,
|
|
1457
|
+
path
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
function serializeSynthesis(body, lens, atoms, clock) {
|
|
1461
|
+
const now = clock.now().toISOString();
|
|
1462
|
+
const slug = `${lensAspect(lens)}-knowledge`;
|
|
1463
|
+
const fm = {
|
|
1464
|
+
schema: "knowledge.entry/v1",
|
|
1465
|
+
slug,
|
|
1466
|
+
kind: "summary",
|
|
1467
|
+
title: `${lens.label} \u2014 current view`,
|
|
1468
|
+
updated_at: now,
|
|
1469
|
+
// Provenance: the atoms this synthesis consolidates (derivedFrom edges).
|
|
1470
|
+
sources: atoms.map((a) => a.slug),
|
|
1471
|
+
confidence: 0.8,
|
|
1472
|
+
// Faceted aspect tag + the synthesis role marker (kept verbatim — both are
|
|
1473
|
+
// AIP-10 facet structure, not plain tags, so they bypass the topic sanitizer).
|
|
1474
|
+
tags: [lensAspectTag(lens), SYNTHESIS_ROLE_TAG],
|
|
1475
|
+
metadata: {
|
|
1476
|
+
corpus: {
|
|
1477
|
+
status: "active",
|
|
1478
|
+
promotionMode: "lens-synthesis",
|
|
1479
|
+
promotedAt: now,
|
|
1480
|
+
lens: lens.id
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
const trimmed = body.trim();
|
|
1485
|
+
return matter6.stringify("\n" + trimmed, fm);
|
|
1486
|
+
}
|
|
1487
|
+
function buildSynthesisPrompt(input) {
|
|
1488
|
+
const atomBlock = input.atoms.map((a, i) => `### Atom ${i + 1}: ${a.title}
|
|
1489
|
+
${a.body}`).join("\n\n");
|
|
1490
|
+
return `You consolidate the CURRENT knowledge of one aspect into a single living document for an AI operator. You are given the current (non-superseded) atoms \u2014 each a durable insight already extracted. Earlier reversed decisions have already been removed, so treat every atom as currently true.
|
|
1491
|
+
|
|
1492
|
+
ASPECT: ${input.aspect} (${input.label})
|
|
1493
|
+
|
|
1494
|
+
Write a coherent, well-structured markdown document that:
|
|
1495
|
+
- Synthesizes the atoms into a unified current view \u2014 not a list, a narrative the operator can act on.
|
|
1496
|
+
- Resolves overlaps; group related atoms under headings.
|
|
1497
|
+
- States the CURRENT position plainly. Do not hedge with "previously" / "it was decided" \u2014 this is the present truth.
|
|
1498
|
+
- Stays grounded ONLY in the atoms; invent nothing.
|
|
1499
|
+
- Writes in ENGLISH.
|
|
1500
|
+
|
|
1501
|
+
CURRENT ATOMS:
|
|
1502
|
+
${atomBlock}
|
|
1503
|
+
|
|
1504
|
+
Return ONLY the markdown document body (no frontmatter, no code fence).`;
|
|
1505
|
+
}
|
|
1218
1506
|
var ANTHROPIC_RESPONSE = z.object({
|
|
1219
1507
|
content: z.array(
|
|
1220
1508
|
z.object({ type: z.string(), text: z.string().optional() }).loose()
|
|
@@ -1430,6 +1718,7 @@ var ReadOnlyFs = class {
|
|
|
1430
1718
|
constructor(inner) {
|
|
1431
1719
|
this.inner = inner;
|
|
1432
1720
|
}
|
|
1721
|
+
inner;
|
|
1433
1722
|
exists(path) {
|
|
1434
1723
|
return this.inner.exists(path);
|
|
1435
1724
|
}
|
|
@@ -1514,6 +1803,7 @@ var StackResolver = class {
|
|
|
1514
1803
|
constructor(registry) {
|
|
1515
1804
|
this.registry = registry;
|
|
1516
1805
|
}
|
|
1806
|
+
registry;
|
|
1517
1807
|
async resolve(ctx) {
|
|
1518
1808
|
const providers = [...this.registry.list()].sort((a, b) => a.band - b.band);
|
|
1519
1809
|
const entries = [];
|
|
@@ -1604,6 +1894,7 @@ var SyncRunner = class {
|
|
|
1604
1894
|
constructor(opts) {
|
|
1605
1895
|
this.opts = opts;
|
|
1606
1896
|
}
|
|
1897
|
+
opts;
|
|
1607
1898
|
async run() {
|
|
1608
1899
|
const scheme = this.opts.uriScheme ?? "corpus";
|
|
1609
1900
|
const throttle = this.opts.throttleMs ?? 0;
|
|
@@ -1708,6 +1999,7 @@ var ReviewerTrackRecord = class {
|
|
|
1708
1999
|
this.opts = opts;
|
|
1709
2000
|
this.path = opts.path ?? DEFAULT_PATH;
|
|
1710
2001
|
}
|
|
2002
|
+
opts;
|
|
1711
2003
|
path;
|
|
1712
2004
|
/** Load the full record. Empty when the file doesn't exist yet. */
|
|
1713
2005
|
async load() {
|
|
@@ -1946,6 +2238,7 @@ var CorpusLinter = class {
|
|
|
1946
2238
|
constructor(opts) {
|
|
1947
2239
|
this.opts = opts;
|
|
1948
2240
|
}
|
|
2241
|
+
opts;
|
|
1949
2242
|
lint(snapshot) {
|
|
1950
2243
|
const decls = extractLintDeclarations(snapshot);
|
|
1951
2244
|
const issues = [];
|
|
@@ -2197,6 +2490,9 @@ var IllegalTransitionError = class extends Error {
|
|
|
2197
2490
|
this.reason = reason;
|
|
2198
2491
|
this.name = "IllegalTransitionError";
|
|
2199
2492
|
}
|
|
2493
|
+
from;
|
|
2494
|
+
to;
|
|
2495
|
+
reason;
|
|
2200
2496
|
};
|
|
2201
2497
|
function assertTransition(from, to, graph) {
|
|
2202
2498
|
const check = canTransition(from, to, graph);
|
|
@@ -2324,11 +2620,14 @@ var PromoteRejectedError = class extends Error {
|
|
|
2324
2620
|
this.failures = failures;
|
|
2325
2621
|
this.name = "PromoteRejectedError";
|
|
2326
2622
|
}
|
|
2623
|
+
entrySlug;
|
|
2624
|
+
failures;
|
|
2327
2625
|
};
|
|
2328
2626
|
var CorpusPromoter = class {
|
|
2329
2627
|
constructor(ctx) {
|
|
2330
2628
|
this.ctx = ctx;
|
|
2331
2629
|
}
|
|
2630
|
+
ctx;
|
|
2332
2631
|
async promote(opts) {
|
|
2333
2632
|
const reader = new CorpusWorkspaceReader({ fs: this.ctx.fs });
|
|
2334
2633
|
const writer = new CorpusWorkspaceWriter({ fs: this.ctx.fs });
|
|
@@ -2397,7 +2696,7 @@ var CorpusPromoter = class {
|
|
|
2397
2696
|
clock: this.ctx.clock
|
|
2398
2697
|
});
|
|
2399
2698
|
if (opts.candidateId && opts.candidateSidecarPath) {
|
|
2400
|
-
const { CandidatesSidecar: CandidatesSidecar2 } = await import('./sidecar-
|
|
2699
|
+
const { CandidatesSidecar: CandidatesSidecar2 } = await import('./sidecar-WZTZS2I6.mjs');
|
|
2401
2700
|
const sidecar = new CandidatesSidecar2({
|
|
2402
2701
|
fs: this.ctx.fs,
|
|
2403
2702
|
path: joinPath3(opts.workspacePath, opts.candidateSidecarPath)
|
|
@@ -2514,6 +2813,7 @@ var CorpusIndexer = class {
|
|
|
2514
2813
|
constructor(opts) {
|
|
2515
2814
|
this.opts = opts;
|
|
2516
2815
|
}
|
|
2816
|
+
opts;
|
|
2517
2817
|
/**
|
|
2518
2818
|
* Re-sync every active entry. Used at boot (cold-install) and by
|
|
2519
2819
|
* the admin `corpus reindex` command for drift recovery.
|
|
@@ -2523,6 +2823,20 @@ var CorpusIndexer = class {
|
|
|
2523
2823
|
let removed = 0;
|
|
2524
2824
|
let skipped = 0;
|
|
2525
2825
|
let chunkCount = 0;
|
|
2826
|
+
let sourcesPushed = 0;
|
|
2827
|
+
if (this.opts.writer.pushSource) {
|
|
2828
|
+
for (const source of snapshot.sources) {
|
|
2829
|
+
const sourceId = source.frontmatter.id;
|
|
2830
|
+
if (typeof sourceId !== "string") continue;
|
|
2831
|
+
await this.opts.writer.pushSource({
|
|
2832
|
+
sourceId,
|
|
2833
|
+
sourcePath: source.path,
|
|
2834
|
+
title: typeof source.frontmatter.title === "string" ? source.frontmatter.title : void 0,
|
|
2835
|
+
sourceFrontmatter: source.frontmatter
|
|
2836
|
+
});
|
|
2837
|
+
sourcesPushed++;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2526
2840
|
for (const entry of snapshot.entries) {
|
|
2527
2841
|
const status = readStatus(entry);
|
|
2528
2842
|
if (status === "active") {
|
|
@@ -2539,7 +2853,7 @@ var CorpusIndexer = class {
|
|
|
2539
2853
|
skipped++;
|
|
2540
2854
|
}
|
|
2541
2855
|
}
|
|
2542
|
-
return { pushed, removed, skipped, chunkCount };
|
|
2856
|
+
return { pushed, removed, skipped, chunkCount, sourcesPushed };
|
|
2543
2857
|
}
|
|
2544
2858
|
/**
|
|
2545
2859
|
* Re-sync a single entry by slug. The lifecycle's `promote`
|
|
@@ -2585,7 +2899,10 @@ var CorpusIndexer = class {
|
|
|
2585
2899
|
confidence: entry.frontmatter.confidence,
|
|
2586
2900
|
tags: entry.frontmatter.tags,
|
|
2587
2901
|
...corpus
|
|
2588
|
-
}
|
|
2902
|
+
},
|
|
2903
|
+
// Full frontmatter for a graph-projection writer (relation arrays the
|
|
2904
|
+
// flattened entryMetadata drops). Vector engines ignore it.
|
|
2905
|
+
entryFrontmatter: entry.frontmatter
|
|
2589
2906
|
});
|
|
2590
2907
|
return chunks.length;
|
|
2591
2908
|
}
|
|
@@ -2922,6 +3239,7 @@ var OperatorOverlayResolver = class {
|
|
|
2922
3239
|
constructor(registry) {
|
|
2923
3240
|
this.registry = registry;
|
|
2924
3241
|
}
|
|
3242
|
+
registry;
|
|
2925
3243
|
resolve(ctx) {
|
|
2926
3244
|
const slugs = ctx.roleSlug ? [ctx.operatorSlug, ctx.roleSlug] : [ctx.operatorSlug];
|
|
2927
3245
|
const candidates = this.registry.listBy({
|
|
@@ -2967,6 +3285,7 @@ var PlaybookNotFoundError = class extends Error {
|
|
|
2967
3285
|
this.slug = slug;
|
|
2968
3286
|
this.name = "PlaybookNotFoundError";
|
|
2969
3287
|
}
|
|
3288
|
+
slug;
|
|
2970
3289
|
};
|
|
2971
3290
|
var IllegalPlaybookTransitionError = class extends Error {
|
|
2972
3291
|
constructor(slug, from, to) {
|
|
@@ -2978,11 +3297,15 @@ var IllegalPlaybookTransitionError = class extends Error {
|
|
|
2978
3297
|
this.to = to;
|
|
2979
3298
|
this.name = "IllegalPlaybookTransitionError";
|
|
2980
3299
|
}
|
|
3300
|
+
slug;
|
|
3301
|
+
from;
|
|
3302
|
+
to;
|
|
2981
3303
|
};
|
|
2982
3304
|
var PlaybookLifecycle = class {
|
|
2983
3305
|
constructor(opts) {
|
|
2984
3306
|
this.opts = opts;
|
|
2985
3307
|
}
|
|
3308
|
+
opts;
|
|
2986
3309
|
/**
|
|
2987
3310
|
* Transition `slug` from shadow → active. Cascades through
|
|
2988
3311
|
* `supersedes[]`: any currently-active playbook listed there is
|
|
@@ -3102,7 +3425,7 @@ var PlaybookLifecycle = class {
|
|
|
3102
3425
|
async writeWith(playbook, patch) {
|
|
3103
3426
|
const writer = new CorpusWorkspaceWriter({ fs: this.opts.fs });
|
|
3104
3427
|
const nextFm = patch({ ...playbook.file.frontmatter });
|
|
3105
|
-
const nextContent =
|
|
3428
|
+
const nextContent = matter6.stringify(
|
|
3106
3429
|
playbook.body.startsWith("\n") ? playbook.body : "\n" + playbook.body,
|
|
3107
3430
|
nextFm
|
|
3108
3431
|
);
|
|
@@ -3163,6 +3486,7 @@ var PlaybookEvaluator = class {
|
|
|
3163
3486
|
constructor(opts) {
|
|
3164
3487
|
this.opts = opts;
|
|
3165
3488
|
}
|
|
3489
|
+
opts;
|
|
3166
3490
|
/**
|
|
3167
3491
|
* Run an eval batch against a single playbook. For each case:
|
|
3168
3492
|
* 1. Score shadow.response against rubric → shadowScore
|
|
@@ -3270,7 +3594,7 @@ var PlaybookEvaluator = class {
|
|
|
3270
3594
|
note: `n=${metrics.sampleSize} winRate=${metrics.winRateVsBaseline.toFixed(3)}`
|
|
3271
3595
|
})
|
|
3272
3596
|
);
|
|
3273
|
-
const content =
|
|
3597
|
+
const content = matter6.stringify(
|
|
3274
3598
|
playbook.body.startsWith("\n") ? playbook.body : "\n" + playbook.body,
|
|
3275
3599
|
fm
|
|
3276
3600
|
);
|
|
@@ -3309,6 +3633,6 @@ function joinPath5(a, b) {
|
|
|
3309
3633
|
var SPEC_NAME = "agentcorpus/v1";
|
|
3310
3634
|
var SPEC_VERSION = "0.1.0-alpha";
|
|
3311
3635
|
|
|
3312
|
-
export { ANY_REF, ClaudeDistiller, ConversationImporter, CorpusEventEmitter, CorpusIndexer, CorpusLinter, CorpusPromoter, CorpusValidator, CorpusVersionConflictError, CorpusWorkspaceReader, CorpusWorkspaceWriter, DEFAULT_TRANSITIONS, DistillRunner, EMPTY_SELECTOR, IllegalPlaybookTransitionError, IllegalTransitionError, ImporterRunner, KbMigrationImporter, LocalFilesImporter, MemFs, OperatorOverlayResolver, OverlayFs, PlaybookEvaluator, PlaybookLifecycle, PlaybookNotFoundError, PlaybookRegistry, PromoteRejectedError, ReadOnlyFs, ReviewerTrackRecord, SPEC_NAME, SPEC_VERSION, StackResolver, SyncRunner, WELL_KNOWN_AXES, WHITEOUT_SUFFIX, WebImporter, aggregateReviewerScores, appendAttestation, assertTransition, buildDistillPrompt, buildOverlayFromStack, canTransition, capabilityAxis, chunkText, compileLegacyPlaybookBinding, computeReviewerCalibration, createAxisRegistry, createDistillRegistry, enumerateWindowRefs, evaluateAccess, evaluateCapability, evaluateGate, extractAutoPromoteConfig, flattenPackRefs, identityAxis, isEmptySelector, isEntrySlug, isSourceSlug, makeAttestation, matchAttachmentRefs, matchAttachments, matchesLanguageFilter, matchesSelector, modelDistiller, normalizeLanguageTag, parseItems, parseSelectorFrontmatter, parseWindowRef, partitionStackRefs, pearsonCorrelation, positionAxis, prefixedRefNormalizer, readAccessModes, readAccessSpec, readAttestations, readEntryLanguage, readOperatorLocale, readWorkspaceDefaultLanguage, renderOverlays, resolveLanguageFilter, roleAxis, runDistill, scanDistilledSourceIds, slugify, transitionGraphFromCollection, uniqueSlug, windowRef, windowSlug };
|
|
3636
|
+
export { ANY_REF, ClaudeDistiller, ConversationImporter, CorpusEventEmitter, CorpusIndexer, CorpusLinter, CorpusPromoter, CorpusValidator, CorpusVersionConflictError, CorpusWorkspaceReader, CorpusWorkspaceWriter, DEFAULT_TRANSITIONS, DISTILL_INDEX_PATH, DistillIndex, DistillRunner, EMPTY_SELECTOR, IllegalPlaybookTransitionError, IllegalTransitionError, ImporterRunner, KbMigrationImporter, LocalFilesImporter, MemFs, OperatorOverlayResolver, OverlayFs, PlaybookEvaluator, PlaybookLifecycle, PlaybookNotFoundError, PlaybookRegistry, PromoteRejectedError, ReadOnlyFs, ReviewerTrackRecord, SPEC_NAME, SPEC_VERSION, SYNTHESIS_ROLE_TAG, StackResolver, SyncRunner, WELL_KNOWN_AXES, WHITEOUT_SUFFIX, WebImporter, aggregateReviewerScores, appendAttestation, assertTransition, buildDistillPrompt, buildOverlayFromStack, buildSynthesisPrompt, canTransition, capabilityAxis, chunkText, compileLegacyPlaybookBinding, computeReviewerCalibration, createAxisRegistry, createDistillRegistry, currentLensAtoms, defaultSynthesisPath, distillFromImporter, enumerateWindowRefs, evaluateAccess, evaluateCapability, evaluateGate, extractAutoPromoteConfig, flattenPackRefs, identityAxis, isEmptySelector, isEntrySlug, isSourceSlug, lensAspect, lensAspectTag, lensSynthesisStale, makeAttestation, matchAttachmentRefs, matchAttachments, matchesLanguageFilter, matchesSelector, modelDistiller, normalizeLanguageTag, parseItems, parseSelectorFrontmatter, parseWindowRef, partitionStackRefs, pearsonCorrelation, positionAxis, prefixedRefNormalizer, readAccessModes, readAccessSpec, readAttestations, readEntryLanguage, readOperatorLocale, readWorkspaceDefaultLanguage, renderOverlays, resolveLanguageFilter, roleAxis, runDistill, scanDistilledSourceIds, slugify, synthesizeLens, transitionGraphFromCollection, uniqueSlug, windowRef, windowSlug };
|
|
3313
3637
|
//# sourceMappingURL=index.mjs.map
|
|
3314
3638
|
//# sourceMappingURL=index.mjs.map
|