barry-cache 0.3.0 → 0.4.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Barry Cache
2
2
 
3
3
  <p align="center">
4
- <img src="https://unpkg.com/barry-cache@latest/assets/barry-cache.png" alt="Barry Cache" width="420">
4
+ <img src="https://raw.githubusercontent.com/AlexanderIstomin/barry-cache/main/assets/barry-cache.png" alt="Barry Cache" width="420">
5
5
  </p>
6
6
 
7
7
  Barry Cache remembers your repo.
@@ -12,7 +12,7 @@ It creates source-backed context files for coding agents, validates them, and gi
12
12
 
13
13
  Barry Cache exists because coding agents need durable project context that is shared, reviewable, and smaller than the whole repository. Private assistant memory, ad hoc chat history, and vendor-specific instruction files drift apart; Barry keeps the source of truth in the repo and lets every agent load the same facts.
14
14
 
15
- The structure is intentionally layered: canonical context lives in `docs/context/`, operational continuity lives in `.context-state/`, and generated retrieval data lives in `.context-cache/`. Canonical facts stay source-backed and validated, while `route`, `search`, `load`, and `resume` project only the relevant feature pack into an agent session.
15
+ The structure is intentionally layered: canonical context lives in `docs/context/`, operational continuity lives in `.context-state/`, and generated retrieval data lives in `.context-cache/`. Canonical facts stay source-backed and validated, while `route`, `search`, `load`, and `resume` project only the relevant feature pack into an agent session. Repeated retrieval commands reuse `.context-cache/context-index.json` when the source context file manifest is unchanged.
16
16
 
17
17
  That gives Barry three core advantages: it is agent-agnostic, because adapters point to one canonical context; auditable, because facts carry stable IDs and source references; and context-efficient, because agents start from a small routed slice instead of rereading the whole codebase.
18
18
 
@@ -150,6 +150,8 @@ It appends a JSONL handoff record to `.context-state/handoffs/handoffs.jsonl`.
150
150
 
151
151
  Use this before ending a meaningful work session so the next agent can recover what happened.
152
152
 
153
+ `finalize` writes operational memory only. It does not update canonical project context in `docs/context/`. If a task introduced durable implementation behavior, add or update source-backed facts in `docs/context/features/*/FACTS.jsonl` and run `barry-cache validate`.
154
+
153
155
  Statuses:
154
156
  - `success`: the task was completed.
155
157
  - `partial`: some useful progress was made.
@@ -295,6 +297,8 @@ bun run barry -- load --route editor-media-runtime
295
297
 
296
298
  This keeps the agent from reading every context file in the repo.
297
299
 
300
+ Barry also keeps a disposable parsed context index in `.context-cache/context-index.json`. It is keyed by the source context files and directories, so repeated `resume`, `load`, `route`, `search`, and `review --json` commands reuse parsed context until a context source file changes.
301
+
298
302
  If an agent ignores the repo instructions, prompt it explicitly:
299
303
 
300
304
  ```text
@@ -345,6 +349,7 @@ Rules:
345
349
  3. Put uncertain notes, blockers, and next steps in operational memory, not canonical facts.
346
350
  4. Update IDMAP.md or KG.adj only when new source IDs or relationships are needed.
347
351
  5. Run barry-cache validate before finishing.
352
+ 6. Do not claim Barry canonical memory is updated unless docs/context/ changed.
348
353
  ```
349
354
 
350
355
  The minimum useful save is:
package/dist/cli.js CHANGED
@@ -263,7 +263,11 @@ function unquote(input) {
263
263
 
264
264
  // src/core/context.ts
265
265
  import { appendFile, mkdir as mkdir2 } from "node:fs/promises";
266
- import { basename as basename2, join as join4 } from "node:path";
266
+ import { basename as basename2, join as join5 } from "node:path";
267
+
268
+ // src/core/context-cache.ts
269
+ import { stat as stat2 } from "node:fs/promises";
270
+ import { join as join4 } from "node:path";
267
271
 
268
272
  // src/core/validate.ts
269
273
  import { join as join3 } from "node:path";
@@ -338,17 +342,155 @@ function validateFact(value) {
338
342
  return null;
339
343
  }
340
344
 
345
+ // src/core/context-cache.ts
346
+ var cacheVersion = 1;
347
+ var contextCachePath = ".context-cache/context-index.json";
348
+ async function readContextSnapshot(repo) {
349
+ const cached = await readFreshContextCache(repo);
350
+ if (cached)
351
+ return hydrateSnapshot(repo, cached);
352
+ const snapshot = await readContextSnapshotFromDisk(repo);
353
+ await writeContextCache(repo, snapshot);
354
+ return snapshot;
355
+ }
356
+ async function readFreshContextCache(repo) {
357
+ try {
358
+ const parsed = JSON.parse(await readTextIfExists(repoPath(repo, contextCachePath)));
359
+ if (!isContextCacheFile(parsed))
360
+ return null;
361
+ return await manifestIsFresh(repo, parsed.manifest) ? parsed : null;
362
+ } catch {
363
+ return null;
364
+ }
365
+ }
366
+ async function writeContextCache(repo, snapshot) {
367
+ const cache = {
368
+ version: cacheVersion,
369
+ generated_at: new Date().toISOString(),
370
+ manifest: await buildManifest(repo, snapshot),
371
+ features: snapshot.features.map((feature) => ({
372
+ ...feature,
373
+ dir: rel(repo, feature.dir)
374
+ })),
375
+ adrs: snapshot.adrs
376
+ };
377
+ try {
378
+ await writeText(repoPath(repo, contextCachePath), `${JSON.stringify(cache, null, 2)}
379
+ `);
380
+ } catch {}
381
+ }
382
+ async function readContextSnapshotFromDisk(repo) {
383
+ return {
384
+ features: await readFeaturePacksFromDisk(repo),
385
+ adrs: (await readAdrCatalog(repo)).adrs
386
+ };
387
+ }
388
+ async function readFeaturePacksFromDisk(repo) {
389
+ const root = repoPath(repo, "docs/context/features");
390
+ const slugs = await listDirs(root);
391
+ const features = [];
392
+ for (const slug2 of slugs) {
393
+ const dir = join4(root, slug2);
394
+ features.push({
395
+ slug: slug2,
396
+ dir,
397
+ readme: await readTextIfExists(join4(dir, "README.md")),
398
+ idmap: await readTextIfExists(join4(dir, "IDMAP.md")),
399
+ graph: await readTextIfExists(join4(dir, "KG.adj")),
400
+ facts: await readFacts(join4(dir, "FACTS.jsonl"))
401
+ });
402
+ }
403
+ return features;
404
+ }
405
+ async function readFacts(path) {
406
+ const rows = (await readTextIfExists(path)).split(/\r?\n/);
407
+ const facts = [];
408
+ for (const row of rows) {
409
+ if (row.trim().length === 0)
410
+ continue;
411
+ const parsed = JSON.parse(row);
412
+ if (validateFact(parsed) === null)
413
+ facts.push(parsed);
414
+ }
415
+ return facts;
416
+ }
417
+ async function buildManifest(repo, snapshot) {
418
+ const paths = new Map;
419
+ paths.set("docs/context/features", "dir");
420
+ paths.set("docs/context/adrs", "dir");
421
+ for (const feature of snapshot.features) {
422
+ const dir = rel(repo, feature.dir);
423
+ paths.set(dir, "dir");
424
+ paths.set(`${dir}/README.md`, "file");
425
+ paths.set(`${dir}/IDMAP.md`, "file");
426
+ paths.set(`${dir}/KG.adj`, "file");
427
+ paths.set(`${dir}/FACTS.jsonl`, "file");
428
+ }
429
+ for (const adr of snapshot.adrs) {
430
+ paths.set(adr.path, "file");
431
+ }
432
+ const entries = [...paths.entries()].sort((a, b) => a[0].localeCompare(b[0]));
433
+ return await Promise.all(entries.map(([path, kind]) => statManifestEntry(repo, path, kind)));
434
+ }
435
+ async function manifestIsFresh(repo, manifest) {
436
+ for (const entry of manifest) {
437
+ const current = await statManifestEntry(repo, entry.path, entry.kind);
438
+ if (!sameManifestEntry(entry, current))
439
+ return false;
440
+ }
441
+ return true;
442
+ }
443
+ async function statManifestEntry(repo, path, kind) {
444
+ try {
445
+ const value = await stat2(repoPath(repo, path));
446
+ const matchesKind = kind === "dir" ? value.isDirectory() : value.isFile();
447
+ if (!matchesKind)
448
+ return { path, kind, exists: false };
449
+ return {
450
+ path,
451
+ kind,
452
+ exists: true,
453
+ mtimeMs: value.mtimeMs,
454
+ size: value.size
455
+ };
456
+ } catch (error) {
457
+ if (error.code === "ENOENT")
458
+ return { path, kind, exists: false };
459
+ throw error;
460
+ }
461
+ }
462
+ function sameManifestEntry(left, right) {
463
+ if (left.path !== right.path || left.kind !== right.kind || left.exists !== right.exists)
464
+ return false;
465
+ if (!left.exists || !right.exists)
466
+ return true;
467
+ return left.mtimeMs === right.mtimeMs && left.size === right.size;
468
+ }
469
+ function hydrateSnapshot(repo, cache) {
470
+ return {
471
+ features: cache.features.map((feature) => ({
472
+ ...feature,
473
+ dir: repoPath(repo, feature.dir)
474
+ })),
475
+ adrs: cache.adrs
476
+ };
477
+ }
478
+ function isContextCacheFile(value) {
479
+ if (typeof value !== "object" || value === null)
480
+ return false;
481
+ const candidate = value;
482
+ return candidate.version === cacheVersion && Array.isArray(candidate.manifest) && Array.isArray(candidate.features) && Array.isArray(candidate.adrs);
483
+ }
484
+
341
485
  // src/core/context.ts
342
486
  async function routeTask({ repo, task }) {
343
- const features = await readFeaturePacks(repo);
344
- const adrs = await listAdrs({ repo });
487
+ const { features, adrs } = await readContextSnapshot(repo);
345
488
  const taskTokens = tokens(task);
346
489
  const routes = features.map((feature) => scoreFeature(feature, taskTokens, adrs)).filter((route) => route.score > 0).sort((a, b) => b.score - a.score || a.slug.localeCompare(b.slug));
347
490
  return { task, routes };
348
491
  }
349
492
  async function searchContext({ repo, query }) {
350
- const features = await readFeaturePacks(repo);
351
- const adrs = await listAdrs({ repo });
493
+ const { features, adrs } = await readContextSnapshot(repo);
352
494
  const queryTokens = tokens(query);
353
495
  const results = [];
354
496
  for (const feature of features) {
@@ -374,7 +516,7 @@ async function searchContext({ repo, query }) {
374
516
  route: feature.slug,
375
517
  score,
376
518
  text: factText,
377
- source: `${rel(repo, join4(feature.dir, "FACTS.jsonl"))}#${fact.id}`
519
+ source: `${rel(repo, join5(feature.dir, "FACTS.jsonl"))}#${fact.id}`
378
520
  });
379
521
  }
380
522
  }
@@ -396,8 +538,7 @@ async function searchContext({ repo, query }) {
396
538
  return { query, results };
397
539
  }
398
540
  async function loadContext({ repo, route }) {
399
- const features = await readFeaturePacks(repo);
400
- const adrs = await listAdrs({ repo });
541
+ const { features, adrs } = await readContextSnapshot(repo);
401
542
  const feature = features.find((item) => item.slug === route) ?? null;
402
543
  if (!feature)
403
544
  return { feature: null, facts: [], sources: [], adrs: [] };
@@ -405,10 +546,10 @@ async function loadContext({ repo, route }) {
405
546
  feature,
406
547
  facts: feature.facts,
407
548
  sources: [
408
- rel(repo, join4(feature.dir, "README.md")),
409
- rel(repo, join4(feature.dir, "IDMAP.md")),
410
- rel(repo, join4(feature.dir, "KG.adj")),
411
- rel(repo, join4(feature.dir, "FACTS.jsonl"))
549
+ rel(repo, join5(feature.dir, "README.md")),
550
+ rel(repo, join5(feature.dir, "IDMAP.md")),
551
+ rel(repo, join5(feature.dir, "KG.adj")),
552
+ rel(repo, join5(feature.dir, "FACTS.jsonl"))
412
553
  ],
413
554
  adrs: linkedAdrsForSources(feature.facts.flatMap((fact) => fact.src), adrs)
414
555
  };
@@ -432,7 +573,7 @@ async function resumeProject({ repo, task }) {
432
573
  async function finalizeProject(options) {
433
574
  const dir = repoPath(options.repo, ".context-state/handoffs");
434
575
  await mkdir2(dir, { recursive: true });
435
- const path = join4(dir, "handoffs.jsonl");
576
+ const path = join5(dir, "handoffs.jsonl");
436
577
  const record = {
437
578
  id: `handoff-${new Date().toISOString()}`,
438
579
  updated_at: new Date().toISOString(),
@@ -445,35 +586,6 @@ async function finalizeProject(options) {
445
586
  `);
446
587
  return { saved: true, path: rel(options.repo, path), summary: options.summary };
447
588
  }
448
- async function readFeaturePacks(repo) {
449
- const root = repoPath(repo, "docs/context/features");
450
- const slugs = await listDirs(root);
451
- const features = [];
452
- for (const slug2 of slugs) {
453
- const dir = join4(root, slug2);
454
- features.push({
455
- slug: slug2,
456
- dir,
457
- readme: await readTextIfExists(join4(dir, "README.md")),
458
- idmap: await readTextIfExists(join4(dir, "IDMAP.md")),
459
- graph: await readTextIfExists(join4(dir, "KG.adj")),
460
- facts: await readFacts(join4(dir, "FACTS.jsonl"))
461
- });
462
- }
463
- return features;
464
- }
465
- async function readFacts(path) {
466
- const rows = (await readTextIfExists(path)).split(/\r?\n/);
467
- const facts = [];
468
- for (const row of rows) {
469
- if (row.trim().length === 0)
470
- continue;
471
- const parsed = JSON.parse(row);
472
- if (validateFact(parsed) === null)
473
- facts.push(parsed);
474
- }
475
- return facts;
476
- }
477
589
  function scoreFeature(feature, taskTokens, adrs) {
478
590
  const linkedAdrs = linkedAdrsForSources(feature.facts.flatMap((fact) => fact.src), adrs);
479
591
  const text = [
@@ -516,7 +628,7 @@ function firstLine(value) {
516
628
  }
517
629
 
518
630
  // src/core/import-pulpcut.ts
519
- import { join as join5 } from "node:path";
631
+ import { join as join6 } from "node:path";
520
632
  async function importPulpcutKb(options) {
521
633
  const dryRun = options.dryRun ?? false;
522
634
  const result = {
@@ -531,19 +643,19 @@ async function importPulpcutKb(options) {
531
643
  warnings: []
532
644
  };
533
645
  const sourceDocs = repoPath(options.from, "docs");
534
- const kbIndex = await readTextIfExists(join5(sourceDocs, "KB_INDEX.md"));
646
+ const kbIndex = await readTextIfExists(join6(sourceDocs, "KB_INDEX.md"));
535
647
  if (kbIndex.trim().length === 0) {
536
- throw new Error(`PulpCut KB index not found at ${join5(sourceDocs, "KB_INDEX.md")}`);
648
+ throw new Error(`PulpCut KB index not found at ${join6(sourceDocs, "KB_INDEX.md")}`);
537
649
  }
538
650
  const routes = parseKbIndex(kbIndex);
539
651
  const slugs = await listDirs(sourceDocs);
540
652
  for (const slug2 of slugs) {
541
- const sourceDir = join5(sourceDocs, slug2);
542
- const rawFacts = await readTextIfExists(join5(sourceDir, "FACTS.jsonl"));
653
+ const sourceDir = join6(sourceDocs, slug2);
654
+ const rawFacts = await readTextIfExists(join6(sourceDir, "FACTS.jsonl"));
543
655
  if (rawFacts.trim().length === 0)
544
656
  continue;
545
- const idmap = await readTextIfExists(join5(sourceDir, "IDMAP.md"));
546
- const graph = await readTextIfExists(join5(sourceDir, "KG.adj"));
657
+ const idmap = await readTextIfExists(join6(sourceDir, "IDMAP.md"));
658
+ const graph = await readTextIfExists(join6(sourceDir, "KG.adj"));
547
659
  if (idmap.trim().length === 0)
548
660
  result.warnings.push(`${slug2}: missing IDMAP.md`);
549
661
  if (graph.trim().length === 0)
@@ -728,7 +840,7 @@ function stringOrStringArray(value) {
728
840
 
729
841
  // src/core/init.ts
730
842
  import { mkdir as mkdir3 } from "node:fs/promises";
731
- import { join as join6 } from "node:path";
843
+ import { join as join7 } from "node:path";
732
844
 
733
845
  // src/core/templates.ts
734
846
  var managedStart = "<!-- barry-cache:start -->";
@@ -761,6 +873,8 @@ Barry Cache remembers this repo through source-backed context files.
761
873
 
762
874
  ${commandNote}
763
875
 
876
+ Repeated retrieval commands use the disposable parsed index in \`.context-cache/context-index.json\` when source context files have not changed.
877
+
764
878
  Start task context with:
765
879
 
766
880
  \`\`\`bash
@@ -786,6 +900,12 @@ Before handing off substantial work, record factual evidence:
786
900
  \`\`\`bash
787
901
  ${commandPrefix} finalize --status success --summary "<summary>"
788
902
  \`\`\`
903
+
904
+ Memory policy:
905
+
906
+ - Finalize writes operational memory only.
907
+ - Do not claim Barry canonical memory is updated unless \`docs/context/\` changed.
908
+ - If a task adds durable implementation behavior, add or update source-backed facts in \`docs/context/features/*/FACTS.jsonl\` and run \`${commandPrefix} validate\`.
789
909
  `;
790
910
  }
791
911
  var indexMd = `# Context Index
@@ -849,7 +969,7 @@ Barry Cache keeps repo context source-backed, validated, and easy for agents to
849
969
 
850
970
  This directory is the canonical project memory for Barry Cache. It keeps durable implementation context in Git so humans and agents can review the same source-backed facts instead of relying on private assistant memory or stale chat history.
851
971
 
852
- Barry separates three concerns: \`docs/context/\` is reviewed truth, \`.context-state/\` is operational session continuity, and \`.context-cache/\` is disposable retrieval data. Use this structure to explain existing behavior, route tasks, validate facts, and resume agent work without loading the whole repo.
972
+ Barry separates three concerns: \`docs/context/\` is reviewed truth, \`.context-state/\` is operational session continuity, and \`.context-cache/\` is disposable retrieval data. Barry stores a parsed context index in \`.context-cache/context-index.json\` and reuses it while the source context manifest is unchanged. Use this structure to explain existing behavior, route tasks, validate facts, and resume agent work without loading the whole repo.
853
973
  `;
854
974
  var adrReadmeMd = `# Architecture Decision Records
855
975
 
@@ -870,7 +990,7 @@ Barry Cache separates canonical context, operational state, and generated caches
870
990
 
871
991
  - Canonical context lives in \`docs/context/\`.
872
992
  - Operational continuity lives in \`.context-state/\`.
873
- - Generated retrieval data lives in \`.context-cache/\`.
993
+ - Generated retrieval data lives in \`.context-cache/\`, including the disposable parsed context index.
874
994
  `;
875
995
  var factSchema = {
876
996
  $schema: "https://json-schema.org/draft/2020-12/schema",
@@ -969,11 +1089,11 @@ async function initProject(options) {
969
1089
  await patchAgentInstructions(repo, dryRun, result, options.agents, commandPrefix, packageManager);
970
1090
  await patchGitignore(repo, dryRun, result);
971
1091
  if (!dryRun) {
972
- await mkdir3(join6(repo, ".context-state/work/threads"), { recursive: true });
973
- await mkdir3(join6(repo, ".context-state/handoffs"), { recursive: true });
974
- await mkdir3(join6(repo, ".context-state/failures"), { recursive: true });
975
- await mkdir3(join6(repo, ".context-state/strategies"), { recursive: true });
976
- await mkdir3(join6(repo, ".context-cache"), { recursive: true });
1092
+ await mkdir3(join7(repo, ".context-state/work/threads"), { recursive: true });
1093
+ await mkdir3(join7(repo, ".context-state/handoffs"), { recursive: true });
1094
+ await mkdir3(join7(repo, ".context-state/failures"), { recursive: true });
1095
+ await mkdir3(join7(repo, ".context-state/strategies"), { recursive: true });
1096
+ await mkdir3(join7(repo, ".context-cache"), { recursive: true });
977
1097
  }
978
1098
  result.changed = result.written.length > 0 || result.updated.length > 0;
979
1099
  return result;
@@ -1070,6 +1190,18 @@ Validate context changes with:
1070
1190
  \`\`\`bash
1071
1191
  ${commandPrefix} validate
1072
1192
  \`\`\`
1193
+
1194
+ Before handing off substantial work, record factual evidence:
1195
+
1196
+ \`\`\`bash
1197
+ ${commandPrefix} finalize --status success --summary "<summary>"
1198
+ \`\`\`
1199
+
1200
+ Memory policy:
1201
+
1202
+ - Finalize writes operational memory only.
1203
+ - Do not claim Barry canonical memory is updated unless \`docs/context/\` changed.
1204
+ - If a task adds durable implementation behavior, add or update source-backed facts in \`docs/context/features/*/FACTS.jsonl\` and run \`${commandPrefix} validate\`.
1073
1205
  `;
1074
1206
  }
1075
1207
  function llmsTxt() {
@@ -1084,7 +1216,7 @@ function llmsTxt() {
1084
1216
  }
1085
1217
 
1086
1218
  // src/core/review-model.ts
1087
- import { join as join7 } from "node:path";
1219
+ import { join as join8 } from "node:path";
1088
1220
 
1089
1221
  // src/core/review-tree.ts
1090
1222
  function buildReviewTree(facts) {
@@ -1236,8 +1368,7 @@ async function buildReviewModel({ repo }) {
1236
1368
  const warnings = [];
1237
1369
  const facts = [];
1238
1370
  const timeline = [];
1239
- const features = await readFeaturePacks(repo);
1240
- const adrs = await listAdrs({ repo });
1371
+ const { features, adrs } = await readContextSnapshot(repo);
1241
1372
  for (const adr of adrs)
1242
1373
  addAdr(graph, adr);
1243
1374
  for (const feature of features) {
@@ -1247,7 +1378,7 @@ async function buildReviewModel({ repo }) {
1247
1378
  for (const fact of feature.facts) {
1248
1379
  facts.push({
1249
1380
  route: feature.slug,
1250
- source: `${rel(repo, join7(feature.dir, "FACTS.jsonl"))}#${fact.id}`,
1381
+ source: `${rel(repo, join8(feature.dir, "FACTS.jsonl"))}#${fact.id}`,
1251
1382
  fact
1252
1383
  });
1253
1384
  addFact(graph, repo, feature, fact, sourceMap, adrs);
@@ -1329,7 +1460,7 @@ function addFact(graph, repo, feature, fact, sourceMap, adrs) {
1329
1460
  kind: "fact",
1330
1461
  label: fact.id,
1331
1462
  subtitle: `${fact.subject} ${fact.predicate} ${fact.object}`,
1332
- source: `${rel(repo, join7(feature.dir, "FACTS.jsonl"))}#${fact.id}`,
1463
+ source: `${rel(repo, join8(feature.dir, "FACTS.jsonl"))}#${fact.id}`,
1333
1464
  meta: {
1334
1465
  route: feature.slug,
1335
1466
  status: fact.status,
@@ -3915,7 +4046,8 @@ async function main(argv = process.argv.slice(2)) {
3915
4046
  case "finalize": {
3916
4047
  const status = optionalChoice(parsed, "status", finalizeStatuses, "success", commandUsage("finalize"));
3917
4048
  const summary = requiredString(parsed, "summary", commandUsage("finalize"), { status: [...finalizeStatuses] });
3918
- print(await finalizeProject({ repo, status, summary }), json);
4049
+ const result = await finalizeProject({ repo, status, summary });
4050
+ print(result, json, formatFinalizeMessage(result));
3919
4051
  break;
3920
4052
  }
3921
4053
  case "adr": {
@@ -4124,6 +4256,14 @@ function formatAdrList(adrs) {
4124
4256
  return adrs.map((adr) => `${adr.id} ${adr.status} ${adr.title} (${adr.path})`).join(`
4125
4257
  `);
4126
4258
  }
4259
+ function formatFinalizeMessage(result) {
4260
+ return [
4261
+ `Saved operational handoff to ${result.path}.`,
4262
+ "Finalize writes operational memory only; it does not update canonical context in docs/context/.",
4263
+ "If this task introduced durable implementation behavior, add or update docs/context/features/*/FACTS.jsonl and run barry-cache validate."
4264
+ ].join(`
4265
+ `);
4266
+ }
4127
4267
  function formatInitMessage(result) {
4128
4268
  if (!result.dryRun) {
4129
4269
  const lines2 = [`Barry Cache init ${result.changed ? "changed files" : "already up to date"}.`];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "barry-cache",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Barry Cache remembers your repo.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,7 +15,6 @@
15
15
  },
16
16
  "files": [
17
17
  "dist",
18
- "assets/barry-cache.png",
19
18
  "README.md"
20
19
  ],
21
20
  "engines": {
@@ -26,4 +25,4 @@
26
25
  "@types/node": "^25.8.0",
27
26
  "typescript": "^6.0.3"
28
27
  }
29
- }
28
+ }
Binary file