@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/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  export { systemClock } from './chunk-KYX2DTEH.mjs';
2
- import { REFINED_KIND_SCHEMA, resolveKnowledge } from './chunk-3P23OX5X.mjs';
3
- export { REFINED_KIND_SCHEMA, isRefinedKind, resolveKnowledge } from './chunk-3P23OX5X.mjs';
4
- import { CandidatesSidecar } from './chunk-UPX26MYH.mjs';
5
- export { CandidatesSidecar, SidecarDuplicateError, SidecarNotFoundError } from './chunk-UPX26MYH.mjs';
6
- import matter from 'gray-matter';
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 = matter(content);
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 matter.stringify(doc.body.startsWith("\n") ? doc.body : "\n" + doc.body, doc.frontmatter);
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 matter.stringify(
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 matter.stringify(body.startsWith("\n") ? body : "\n" + body, fm);
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
- return `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.
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 "principle" | "pattern" | "critique" | "summary" | "example",
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(matter(await fs.readFile(path)).data);
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/run.ts
1178
- async function runDistill(descriptor, scope) {
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: target.fs,
1194
- clock: target.clock,
1195
- distiller: descriptor.distiller(scope)
1221
+ fs: opts.fs,
1222
+ clock: opts.clock,
1223
+ distiller: opts.distiller,
1224
+ ...opts.layout ? { layout: opts.layout } : {}
1196
1225
  });
1197
- for await (const imported of binding.importer.enumerate({
1198
- importerId: descriptor.id,
1199
- config
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: binding.provenanceId(imported),
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-TTWQD5R3.mjs');
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 = matter.stringify(
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 = matter.stringify(
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