fluffy-context 0.7.7 → 1.0.0-beta.1

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +110 -553
  3. package/ROADMAP-1.0.md +70 -0
  4. package/dist/src/agent/api.d.ts +41 -0
  5. package/dist/src/agent/api.js +37 -0
  6. package/dist/src/agent/index.d.ts +9 -1
  7. package/dist/src/agent/index.js +3 -0
  8. package/dist/src/capture/context-filter.js +2 -0
  9. package/dist/src/cli/main.js +293 -15
  10. package/dist/src/cognition/admission.d.ts +8 -0
  11. package/dist/src/cognition/admission.js +24 -0
  12. package/dist/src/cognition/evidence-graph.d.ts +4 -0
  13. package/dist/src/cognition/evidence-graph.js +187 -0
  14. package/dist/src/cognition/evolution.d.ts +36 -0
  15. package/dist/src/cognition/evolution.js +221 -0
  16. package/dist/src/cognition/import-memory.d.ts +18 -0
  17. package/dist/src/cognition/import-memory.js +124 -0
  18. package/dist/src/cognition/journal-segments.d.ts +11 -0
  19. package/dist/src/cognition/journal-segments.js +129 -0
  20. package/dist/src/cognition/journal.d.ts +13 -0
  21. package/dist/src/cognition/journal.js +186 -20
  22. package/dist/src/cognition/migration-v1.js +39 -3
  23. package/dist/src/cognition/projections.js +124 -2
  24. package/dist/src/cognition/recipes.d.ts +25 -0
  25. package/dist/src/cognition/recipes.js +149 -0
  26. package/dist/src/cognition/runtime.js +4 -0
  27. package/dist/src/cognition/skills.d.ts +45 -0
  28. package/dist/src/cognition/skills.js +184 -0
  29. package/dist/src/cognition/types.d.ts +181 -1
  30. package/dist/src/cognition/usage-report.js +30 -15
  31. package/dist/src/compiler/compile.js +101 -31
  32. package/dist/src/compiler/graph.d.ts +7 -0
  33. package/dist/src/compiler/graph.js +117 -0
  34. package/dist/src/compiler/identity.d.ts +1 -1
  35. package/dist/src/compiler/identity.js +2 -0
  36. package/dist/src/compiler/inject.d.ts +23 -0
  37. package/dist/src/compiler/inject.js +27 -0
  38. package/dist/src/compiler/sources.d.ts +3 -1
  39. package/dist/src/compiler/sources.js +10 -1
  40. package/dist/src/compiler/types.d.ts +22 -1
  41. package/dist/src/hooks/claude-code.js +17 -56
  42. package/dist/src/integrations/claude-code.js +30 -8
  43. package/dist/src/mcp/server.js +228 -1
  44. package/dist/src/runtime/knowledge.js +57 -8
  45. package/dist/src/runtime/setup.d.ts +27 -0
  46. package/dist/src/runtime/setup.js +85 -0
  47. package/dist/src/storage/layout.d.ts +5 -0
  48. package/dist/src/storage/layout.js +15 -0
  49. package/dist/src/storage/lock.js +19 -2
  50. package/dist/src/version.d.ts +1 -1
  51. package/dist/src/version.js +1 -1
  52. package/package.json +4 -1
  53. package/skills/fluffy-context/SKILL.md +46 -8
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { checkpoint } from '../runtime/runtime.js';
3
- import { contextCompile, contextExpand, contextOrient, contextUsageReport, loadContext } from '../agent/api.js';
3
+ import { contextCompile, contextExpand, contextOrient, contextUsageReport, inspectRecipe, inspectSkill, listRecipes, listSkills, loadContext, materializeContextRecipe, materializeContextSkill, recordContextSkillInvocation, recordContextSkillOutcome, transitionContextRecipe, transitionContextSkill, acceptContextEvolutionCandidate, inspectContextEvolutionProposal, listContextEvolutionProposals, proposeContextEvolution, transitionContextEvolutionProposal } from '../agent/api.js';
4
4
  import { formatUsageReport } from '../cognition/usage-report.js';
5
5
  import { importV1, verifyV1Import } from '../cognition/migration-v1.js';
6
6
  import { recordUse } from '../cognition/feedback.js';
7
- import { verifyJournal } from '../cognition/journal.js';
7
+ import { compactJournal, verifyJournal } from '../cognition/journal.js';
8
8
  import { projectEvents } from '../cognition/projections.js';
9
9
  import { disableRuntime, enableRuntime, ensureRuntimeForSession, runtimeStatus, serveRuntime, setFilesystemEvents, startRuntime, stopRuntime } from '../cognition/runtime.js';
10
10
  import { loadRuntimePolicy } from '../cognition/policy.js';
@@ -13,7 +13,9 @@ import { runClaudeCodeHook } from '../hooks/claude-code.js';
13
13
  import { readGitWorktreeState } from '../git/git-adapter.js';
14
14
  import { inspectClaudeIntegration, installClaudeIntegration } from '../integrations/claude-code.js';
15
15
  import { doctor, status } from '../runtime/diagnostics.js';
16
- import { initProject } from '../runtime/init.js';
16
+ import { setupProject } from '../runtime/setup.js';
17
+ import { importMemory } from '../cognition/import-memory.js';
18
+ import { injectContext } from '../compiler/inject.js';
17
19
  import { discoverKnowledge, learnKnowledge, listKnowledge, verifyKnowledge, recordDeadend, listDeadends, verifyDeadend, transitionKnowledge, transitionDeadend } from '../runtime/knowledge.js';
18
20
  import { addNote, listActivity, listNotes } from '../runtime/notes.js';
19
21
  import { VERSION } from '../version.js';
@@ -74,13 +76,35 @@ function enumOption(args, name, values) {
74
76
  throw new Error(`${name} must be one of: ${values.join(', ')}`);
75
77
  return value;
76
78
  }
79
+ function graphHopsOption(args) {
80
+ const value = option(args, '--graph-hops');
81
+ if (value === undefined)
82
+ return undefined;
83
+ if (value !== '0' && value !== '1' && value !== '2')
84
+ throw new Error('--graph-hops must be one of: 0, 1, 2');
85
+ return Number(value);
86
+ }
87
+ const recipeBudgets = (value) => value === undefined ? undefined : Object.fromEntries(value.split(',').map((item) => { const [section, budget] = item.split('=', 2); const parsed = Number(budget); if (!section || !Number.isSafeInteger(parsed) || parsed < 0 || parsed > 100_000)
88
+ throw new Error('--budgets must be section=non-negative-integer up to 100000'); return [section, parsed]; }));
77
89
  const HELP = {
78
- init: `usage: ctx init [path] [--path <path>]
90
+ init: `usage: ctx init [path] [--path <path>] [--no-start] [--no-integrations]
79
91
 
80
- Initialize the local .context runtime layout. Re-running init is safe.
92
+ Initialize, migrate, verify, install project guidance and start the runtime. Re-running init preserves policy.
81
93
 
82
94
  Options:
83
- --path <path> Project path`,
95
+ --path <path> Project path
96
+ --no-start Configure without starting a background process
97
+ --no-integrations Skip project guidance and host configuration`,
98
+ import: `usage: ctx import [--path <path>] [--apply]
99
+
100
+ Preview project memory, .claude, .zcode, .cursor, .curcor, .codex and AGENTS.md.
101
+ --apply imports deduplicated, source-linked candidates; verification remains explicit.`,
102
+ inject: `usage: ctx inject [query] [--path <path>] [--max-chars <number>] [--paths <paths>] [--explain]
103
+
104
+ Select bounded task context; --explain includes detailed source provenance.`,
105
+ report: `usage: ctx report [options]
106
+
107
+ Alias of ctx usage report; supports its window, format and baseline options.`,
84
108
  usage: `usage: ctx usage report [options]
85
109
 
86
110
  Show read-only context asset, reuse, token investment, and operation metrics.
@@ -152,6 +176,8 @@ Compile bounded, provider-neutral context with source provenance and selection e
152
176
  Options:
153
177
  --path <path> Project path
154
178
  --context <id> Context ID
179
+ --recipe-id <id> Explicit verified or published Recipe
180
+ --graph-hops <0|1|2> Optional bounded evidence-graph traversal
155
181
  --scenario <scenario> resume|implementation|debugging|verification|handoff|exploration|unknown
156
182
  --scope <scope> Exact consensus scope
157
183
  --paths <paths> Comma-separated project-relative paths
@@ -173,6 +199,8 @@ Options:
173
199
  --max-chars <number> Maximum expanded characters
174
200
  --compile-max-chars <number> Original compile budget (default: 4000)
175
201
  --context <id> Context ID
202
+ --recipe-id <id> Explicit verified or published Recipe
203
+ --graph-hops <0|1|2> Optional bounded evidence-graph traversal
176
204
  --query <text> Original compile query
177
205
  --scenario <scenario> resume|implementation|debugging|verification|handoff|exploration|unknown
178
206
  --scope <scope> Exact consensus scope
@@ -286,12 +314,23 @@ Record explicit use of verified v2 retrieval material.`,
286
314
  'feedback use': `usage: ctx feedback use knowledge|deadend <id> --event-id <stable-id> [--path <path>]
287
315
 
288
316
  Record an idempotent use signal that affects deterministic rank only.`,
289
- journal: `usage: ctx journal verify [--path <path>]
317
+ skill: `usage: ctx skill list [--path <path>]
318
+ ctx skill inspect <skill-id> [--path <path>]
319
+ ctx skill materialize <proposal-id> --title <title> --procedure <steps> [--path <path>]
320
+ ctx skill verify|publish|deprecate <skill-id> --rationale <text> [--path <path>]
321
+ ctx skill supersede <skill-id> --rationale <text> --supersedes <entity:id> [--path <path>]
322
+ ctx skill invoke <skill-id> --invocation-id <id> --caller-event <id> --input-hash <hash> [--path <path>]
323
+ ctx skill outcome <skill-id> --invocation-id <id> --outcome-id <id> --caller-event <id> --outcome <value> --summary <text> [--path <path>]`,
324
+ journal: `usage: ctx journal verify|compact [--path <path>] [--apply]
290
325
 
291
326
  Validate the v2 journal hash chain and replay projections in memory.`,
292
327
  'journal verify': `usage: ctx journal verify [--path <path>]
293
328
 
294
329
  Validate journal integrity without writing derived state.`,
330
+ 'journal compact': `usage: ctx journal compact [--path <path>] [--apply]
331
+
332
+ Preview or apply lossless gzip archival. Replays the full hash chain before and after.
333
+ Archived projects require this development version or newer readers.`,
295
334
  deadends: `usage: ctx deadends [--all] [--path <path>]
296
335
 
297
336
  List recorded deadends.`,
@@ -352,9 +391,49 @@ Rebuild v2 projections and verify imported v1 parity.
352
391
 
353
392
  Options:
354
393
  --path <path> Project path`,
355
- runtime: `usage: ctx runtime enable|disable|start|stop|status [--path <path>]
394
+ recipe: `usage: ctx recipe list|inspect|materialize|verify|publish|deprecate|supersede [options]
395
+
396
+ List, inspect, materialize, or govern immutable compiler Recipes.
397
+
398
+ Options:
399
+ --path <path> Project path
400
+ --title <text> Recipe title for materialize
401
+ --sources <items> Comma-separated source preferences
402
+ --sections <items> Comma-separated section preferences
403
+ --budgets <items> Comma-separated section=characters budgets
404
+ --rationale <text> Governance rationale
405
+ --supersedes <ref> Superseding entity:id`,
406
+ 'recipe verify': `usage: ctx recipe verify <recipe-id> --rationale <text> [--path <path>]
407
+
408
+ Mark a candidate compiler Recipe as verified.`,
409
+ 'recipe publish': `usage: ctx recipe publish <recipe-id> --rationale <text> [--path <path>]
410
+
411
+ Publish a verified compiler Recipe.`,
412
+ 'recipe deprecate': `usage: ctx recipe deprecate <recipe-id> --rationale <text> [--path <path>]
413
+
414
+ Retire a compiler Recipe with an explicit governance reason.`,
415
+ 'recipe supersede': `usage: ctx recipe supersede <recipe-id> --rationale <text> --supersedes <entity:id> [--path <path>]
416
+
417
+ Supersede a compiler Recipe while retaining its history.`,
418
+ evolution: `usage: ctx evolution propose|list|inspect|accept|verify|reject|deprecate|supersede [options]
419
+
420
+ Create and govern bounded, metadata-only Evolution proposals.
356
421
 
357
- Control the local event-driven Knowledge Runtime after v1 migration verification.`,
422
+ Options:
423
+ --path <path> Project path
424
+ --events <items> Comma-separated source event IDs
425
+ --recent-limit <n> Number of recent source events
426
+ --target-kind <kind> skill|compiler-recipe
427
+ --rationale <text> Governance rationale
428
+ --supersedes <ref> Superseding entity:id`,
429
+ 'evolution propose': `usage: ctx evolution propose [--events <event-id,...>|--recent-limit <n>] [--target-kind skill|compiler-recipe] [--path <path>]`,
430
+ 'evolution list': `usage: ctx evolution list [--path <path>]`,
431
+ 'evolution inspect': `usage: ctx evolution inspect <proposal-id> [--path <path>]`,
432
+ 'evolution accept': `usage: ctx evolution accept <proposal-id> --rationale <text> [--path <path>]`,
433
+ 'evolution verify': `usage: ctx evolution verify <proposal-id> --rationale <text> [--path <path>]`,
434
+ 'evolution reject': `usage: ctx evolution reject <proposal-id> --rationale <text> [--path <path>]`,
435
+ 'evolution deprecate': `usage: ctx evolution deprecate <proposal-id> --rationale <text> [--path <path>]`,
436
+ 'evolution supersede': `usage: ctx evolution supersede <proposal-id> --rationale <text> --supersedes <entity:id> [--path <path>]`,
358
437
  filesystem: `usage: ctx filesystem enable|disable|status [--path <path>]
359
438
 
360
439
  Control whether the Runtime records filtered file metadata changes.`,
@@ -367,6 +446,9 @@ Disable filesystem change observation and restart a running Runtime.`,
367
446
  'filesystem status': `usage: ctx filesystem status [--path <path>]
368
447
 
369
448
  Show the filesystem observation policy and Runtime status.`,
449
+ runtime: `usage: ctx runtime enable|disable|start|stop|status [--path <path>]
450
+
451
+ Control the local Knowledge Runtime lifecycle.`,
370
452
  'runtime status': `usage: ctx runtime status [--path <path>]
371
453
 
372
454
  Show the read-only runtime policy, migration and authenticated lease status.
@@ -390,7 +472,7 @@ Stop the local runtime through authenticated loopback IPC.`,
390
472
  Internal runtime daemon entry point.`,
391
473
  };
392
474
  function usage() {
393
- return `usage: ctx init|checkpoint|resume|orient|compile|expand|usage|agent|hook|integrate|status|doctor|learn|knowledge|deadend|deadends|note|activity|migrate|runtime|filesystem|feedback|journal [options]
475
+ return `usage: ctx init|inject|import|report|checkpoint|resume|orient|compile|expand|usage|agent|hook|integrate|status|doctor|learn|knowledge|deadend|deadends|note|activity|migrate|runtime|filesystem|feedback|skill|recipe|evolution|journal [options]
394
476
 
395
477
  Run \"ctx <command> --help\" for command details.`;
396
478
  }
@@ -415,9 +497,11 @@ function printHelp(args) {
415
497
  || (command === 'knowledge' && ['verify', 'discover', 'deprecate', 'reject'].includes(args[1]))
416
498
  || (command === 'deadend' && ['verify', 'obsolete', 'reject'].includes(args[1]))
417
499
  || (command === 'feedback' && args[1] === 'use')
418
- || (command === 'journal' && args[1] === 'verify')
500
+ || (command === 'journal' && ['verify', 'compact'].includes(args[1]))
419
501
  || (command === 'note' && ['add', 'list'].includes(args[1]))
420
502
  || (command === 'migrate' && ['v1', 'verify'].includes(args[1]))
503
+ || (command === 'recipe' && ['list', 'inspect', 'materialize', 'verify', 'publish', 'deprecate', 'supersede'].includes(args[1]))
504
+ || (command === 'evolution' && ['propose', 'list', 'inspect', 'accept', 'verify', 'reject', 'deprecate', 'supersede'].includes(args[1]))
421
505
  || (command === 'runtime' && ['enable', 'disable', 'start', 'stop', 'status', 'serve'].includes(args[1]))
422
506
  || (command === 'usage' && args[1] === 'report');
423
507
  const key = nested ? `${command} ${args[1]}` : command;
@@ -436,6 +520,8 @@ function validatePositionals(values, max, usageText) {
436
520
  throw new Error(usageText);
437
521
  }
438
522
  async function run(args) {
523
+ if (args[0] === 'report' && !args.includes('--help'))
524
+ args = ['usage', 'report', ...args.slice(1)];
439
525
  if (args.includes('--version')) {
440
526
  print(VERSION);
441
527
  return;
@@ -450,10 +536,24 @@ async function run(args) {
450
536
  const target = option(args, '--path');
451
537
  switch (command) {
452
538
  case 'init': {
453
- validateOptions(args.slice(1), ['--path'], ['--path']);
539
+ validateOptions(args.slice(1), ['--path', '--no-start', '--no-integrations'], ['--path']);
454
540
  const values = positionals(args.slice(1), ['--path']);
455
541
  validatePositionals(values, 1, HELP.init);
456
- print(await initProject(target ?? values[0]));
542
+ print(await setupProject(target ?? values[0], { start: !args.includes('--no-start'), integrations: !args.includes('--no-integrations') }));
543
+ return;
544
+ }
545
+ case 'import': {
546
+ validateOptions(args.slice(1), ['--path', '--apply'], ['--path']);
547
+ validatePositionals(positionals(args.slice(1), ['--path']), 0, HELP.import);
548
+ print(await importMemory(target, args.includes('--apply')));
549
+ return;
550
+ }
551
+ case 'inject': {
552
+ const valueOptions = ['--path', '--max-chars', '--paths'];
553
+ validateOptions(args.slice(1), [...valueOptions, '--explain'], valueOptions);
554
+ const values = positionals(args.slice(1), valueOptions);
555
+ validatePositionals(values, 1, HELP.inject);
556
+ print(await injectContext(target, { query: values[0], paths: listOption(args, '--paths'), maxChars: numericOption(args, '--max-chars', 2400), explain: args.includes('--explain') }, 'cli'));
457
557
  return;
458
558
  }
459
559
  case 'checkpoint': {
@@ -497,12 +597,14 @@ async function run(args) {
497
597
  return;
498
598
  }
499
599
  case 'compile': {
500
- const valueOptions = ['--path', '--context', '--scenario', '--scope', '--paths', '--max-chars', '--knowledge-limit', '--deadend-limit', '--note-limit', '--activity-limit'];
600
+ const valueOptions = ['--path', '--context', '--recipe-id', '--graph-hops', '--scenario', '--scope', '--paths', '--max-chars', '--knowledge-limit', '--deadend-limit', '--note-limit', '--activity-limit'];
501
601
  validateOptions(args.slice(1), valueOptions, valueOptions);
502
602
  const query = positionals(args.slice(1), valueOptions);
503
603
  validatePositionals(query, 1, HELP.compile);
504
604
  print(await contextCompile(target, {
505
605
  contextId: option(args, '--context'),
606
+ recipeId: option(args, '--recipe-id'),
607
+ graphHops: graphHopsOption(args),
506
608
  query: query[0],
507
609
  scenario: enumOption(args, '--scenario', ['resume', 'implementation', 'debugging', 'verification', 'handoff', 'exploration', 'unknown']),
508
610
  scope: option(args, '--scope'),
@@ -516,7 +618,7 @@ async function run(args) {
516
618
  return;
517
619
  }
518
620
  case 'expand': {
519
- const valueOptions = ['--path', '--manifest-hash', '--candidate-id', '--item-hash', '--level', '--max-chars', '--compile-max-chars', '--context', '--query', '--scenario', '--scope', '--paths', '--knowledge-limit', '--deadend-limit', '--note-limit', '--activity-limit'];
621
+ const valueOptions = ['--path', '--manifest-hash', '--candidate-id', '--item-hash', '--level', '--max-chars', '--compile-max-chars', '--context', '--recipe-id', '--graph-hops', '--query', '--scenario', '--scope', '--paths', '--knowledge-limit', '--deadend-limit', '--note-limit', '--activity-limit'];
520
622
  validateOptions(args.slice(1), valueOptions, valueOptions);
521
623
  validatePositionals(positionals(args.slice(1), valueOptions), 0, HELP.expand);
522
624
  const level = enumOption(args, '--level', ['structured', 'evidence']);
@@ -535,6 +637,8 @@ async function run(args) {
535
637
  maxChars: option(args, '--max-chars') === undefined ? undefined : numericOption(args, '--max-chars', 0),
536
638
  compile: {
537
639
  contextId: option(args, '--context'),
640
+ recipeId: option(args, '--recipe-id'),
641
+ graphHops: graphHopsOption(args),
538
642
  query: option(args, '--query'),
539
643
  scenario: enumOption(args, '--scenario', ['resume', 'implementation', 'debugging', 'verification', 'handoff', 'exploration', 'unknown']),
540
644
  scope: option(args, '--scope'),
@@ -678,7 +782,181 @@ async function run(args) {
678
782
  }
679
783
  return;
680
784
  }
785
+ case 'skill': {
786
+ const action = args[1];
787
+ if (action === 'list') {
788
+ validateOptions(args.slice(2), ['--path'], ['--path']);
789
+ validatePositionals(positionals(args.slice(2), ['--path']), 0, HELP.skill);
790
+ print(await listSkills(target));
791
+ return;
792
+ }
793
+ if (!action)
794
+ throw new Error(HELP.skill);
795
+ const skillId = positionals(args.slice(2), ['--path', '--title', '--procedure', '--rationale', '--supersedes', '--invocation-id', '--caller-event', '--input-hash', '--outcome-id', '--outcome', '--summary'])[0];
796
+ if (action === 'inspect') {
797
+ validateOptions(args.slice(2), ['--path'], ['--path']);
798
+ const values = positionals(args.slice(2), ['--path']);
799
+ if (values.length !== 1)
800
+ throw new Error(HELP.skill);
801
+ print(await inspectSkill(target, values[0]));
802
+ return;
803
+ }
804
+ if (action === 'materialize') {
805
+ const options = ['--path', '--title', '--procedure'];
806
+ validateOptions(args.slice(2), options, options);
807
+ const values = positionals(args.slice(2), options);
808
+ if (values.length !== 1)
809
+ throw new Error(HELP.skill);
810
+ print(await materializeContextSkill(target, { proposalId: values[0], title: option(args, '--title') ?? '', procedure: listOption(args, '--procedure') ?? [] }));
811
+ return;
812
+ }
813
+ if (['verify', 'publish', 'deprecate', 'supersede'].includes(action)) {
814
+ const options = ['--path', '--rationale', '--supersedes'];
815
+ validateOptions(args.slice(2), options, options);
816
+ const values = positionals(args.slice(2), options);
817
+ if (values.length !== 1)
818
+ throw new Error(HELP.skill);
819
+ const supersedes = option(args, '--supersedes');
820
+ const [entity, entityId] = supersedes?.split(':', 2) ?? [];
821
+ if (action === 'supersede' && (!entity || !entityId || !['knowledge', 'deadend', 'skill', 'compiler-recipe', 'experience', 'proposal'].includes(entity)))
822
+ throw new Error('--supersedes must be <entity:id>');
823
+ print(await transitionContextSkill(target, {
824
+ skillId: values[0],
825
+ to: action === 'supersede' ? 'superseded' : action,
826
+ rationale: option(args, '--rationale') ?? '',
827
+ ...(supersedes ? { supersedes: { entity: entity, entityId: entityId, relation: 'supersedes' } } : {}),
828
+ }));
829
+ return;
830
+ }
831
+ if (action === 'invoke') {
832
+ const options = ['--path', '--invocation-id', '--caller-event', '--input-hash'];
833
+ validateOptions(args.slice(2), options, options);
834
+ const values = positionals(args.slice(2), options);
835
+ if (values.length !== 1)
836
+ throw new Error(HELP.skill);
837
+ print(await recordContextSkillInvocation(target, { skillId: values[0], invocationId: option(args, '--invocation-id') ?? '', callerEventId: option(args, '--caller-event') ?? '', inputHash: option(args, '--input-hash') ?? '' }));
838
+ return;
839
+ }
840
+ if (action === 'outcome') {
841
+ const options = ['--path', '--invocation-id', '--outcome-id', '--caller-event', '--outcome', '--summary'];
842
+ validateOptions(args.slice(2), options, options);
843
+ const values = positionals(args.slice(2), options);
844
+ if (values.length !== 1)
845
+ throw new Error(HELP.skill);
846
+ print(await recordContextSkillOutcome(target, { skillId: values[0], invocationId: option(args, '--invocation-id') ?? '', outcomeId: option(args, '--outcome-id') ?? '', callerEventId: option(args, '--caller-event') ?? '', outcome: enumOption(args, '--outcome', ['success', 'failure', 'partial', 'irrelevant', 'unknown']) ?? 'unknown', summary: option(args, '--summary') ?? '' }));
847
+ return;
848
+ }
849
+ void skillId;
850
+ throw new Error(HELP.skill);
851
+ }
852
+ case 'evolution': {
853
+ const action = args[1];
854
+ const valueOptions = ['--path', '--events', '--recent-limit', '--target-kind', '--rationale', '--supersedes'];
855
+ if (action === 'propose') {
856
+ validateOptions(args.slice(2), valueOptions.slice(0, 4), valueOptions.slice(0, 4));
857
+ validatePositionals(positionals(args.slice(2), valueOptions.slice(0, 4)), 0, HELP['evolution propose']);
858
+ if (option(args, '--events') !== undefined && option(args, '--recent-limit') !== undefined)
859
+ throw new Error('use either --events or --recent-limit');
860
+ const eventIds = listOption(args, '--events');
861
+ if (eventIds && (eventIds.length === 0 || eventIds.length > 32))
862
+ throw new Error('--events must contain 1 to 32 event IDs');
863
+ print(await proposeContextEvolution(target, { eventIds, recentLimit: option(args, '--recent-limit') === undefined ? undefined : numericOption(args, '--recent-limit', 32), targetKind: enumOption(args, '--target-kind', ['skill', 'compiler-recipe']) }));
864
+ return;
865
+ }
866
+ if (action === 'list') {
867
+ validateOptions(args.slice(2), ['--path'], ['--path']);
868
+ validatePositionals(positionals(args.slice(2), ['--path']), 0, HELP['evolution list']);
869
+ print(await listContextEvolutionProposals(target));
870
+ return;
871
+ }
872
+ const values = positionals(args.slice(2), valueOptions);
873
+ if (action === 'inspect') {
874
+ validateOptions(args.slice(2), ['--path'], ['--path']);
875
+ if (values.length !== 1)
876
+ throw new Error(HELP['evolution inspect']);
877
+ print(await inspectContextEvolutionProposal(target, values[0]));
878
+ return;
879
+ }
880
+ if (['accept', 'verify', 'reject', 'deprecate', 'supersede'].includes(action ?? '')) {
881
+ validateOptions(args.slice(2), valueOptions, valueOptions);
882
+ if (values.length !== 1)
883
+ throw new Error(HELP[`evolution ${action}`]);
884
+ const rationale = option(args, '--rationale') ?? '';
885
+ if (!rationale.trim())
886
+ throw new Error('--rationale is required');
887
+ const supersedes = option(args, '--supersedes');
888
+ const [entity, entityId] = supersedes?.split(':', 2) ?? [];
889
+ if (action === 'supersede' && (!entity || !entityId || !['knowledge', 'deadend', 'skill', 'compiler-recipe', 'experience', 'proposal'].includes(entity)))
890
+ throw new Error('--supersedes must be <entity:id>');
891
+ if (action === 'accept')
892
+ print(await acceptContextEvolutionCandidate(target, { proposalId: values[0], rationale }));
893
+ else {
894
+ const to = action === 'verify' ? 'verified'
895
+ : action === 'supersede' ? 'superseded'
896
+ : action;
897
+ print(await transitionContextEvolutionProposal(target, { proposalId: values[0], to, rationale, ...(supersedes ? { supersedes: { entity: entity, entityId: entityId, relation: 'supersedes' } } : {}) }));
898
+ }
899
+ return;
900
+ }
901
+ throw new Error(HELP.evolution);
902
+ }
903
+ case 'recipe': {
904
+ const action = args[1];
905
+ const valueOptions = ['--path', '--title', '--sources', '--sections', '--budgets', '--rationale', '--supersedes'];
906
+ if (action === 'list') {
907
+ validateOptions(args.slice(2), ['--path'], ['--path']);
908
+ validatePositionals(positionals(args.slice(2), ['--path']), 0, HELP.recipe);
909
+ print(await listRecipes(target));
910
+ return;
911
+ }
912
+ if (action === 'inspect') {
913
+ validateOptions(args.slice(2), ['--path'], ['--path']);
914
+ const values = positionals(args.slice(2), ['--path']);
915
+ if (values.length !== 1)
916
+ throw new Error(HELP.recipe);
917
+ print(await inspectRecipe(target, values[0]));
918
+ return;
919
+ }
920
+ if (action === 'materialize') {
921
+ validateOptions(args.slice(2), valueOptions, valueOptions);
922
+ const values = positionals(args.slice(2), valueOptions);
923
+ if (values.length !== 1)
924
+ throw new Error(HELP.recipe);
925
+ print(await materializeContextRecipe(target, {
926
+ proposalId: values[0],
927
+ title: option(args, '--title') ?? '',
928
+ preferredSources: listOption(args, '--sources'),
929
+ preferredSections: listOption(args, '--sections'),
930
+ sectionBudgets: recipeBudgets(option(args, '--budgets')),
931
+ }));
932
+ return;
933
+ }
934
+ if (['verify', 'publish', 'deprecate', 'supersede'].includes(action ?? '')) {
935
+ validateOptions(args.slice(2), ['--path', '--rationale', '--supersedes'], ['--path', '--rationale', '--supersedes']);
936
+ const values = positionals(args.slice(2), ['--path', '--rationale', '--supersedes']);
937
+ if (values.length !== 1)
938
+ throw new Error(HELP.recipe);
939
+ const supersedes = option(args, '--supersedes');
940
+ const [entity, entityId] = supersedes?.split(':', 2) ?? [];
941
+ if (action === 'supersede' && (!entity || !entityId || !['knowledge', 'deadend', 'skill', 'compiler-recipe', 'experience', 'proposal'].includes(entity)))
942
+ throw new Error('--supersedes must be <entity:id>');
943
+ print(await transitionContextRecipe(target, {
944
+ recipeId: values[0],
945
+ to: action === 'supersede' ? 'superseded' : action,
946
+ rationale: option(args, '--rationale') ?? '',
947
+ ...(supersedes ? { supersedes: { entity: entity, entityId: entityId, relation: 'supersedes' } } : {}),
948
+ }));
949
+ return;
950
+ }
951
+ throw new Error(HELP.recipe);
952
+ }
681
953
  case 'journal': {
954
+ if (args[1] === 'compact') {
955
+ validateOptions(args.slice(2), ['--path', '--apply'], ['--path']);
956
+ validatePositionals(positionals(args.slice(2), ['--path']), 0, HELP['journal compact']);
957
+ print(await compactJournal(target, { apply: args.includes('--apply') }));
958
+ return;
959
+ }
682
960
  if (args[1] !== 'verify')
683
961
  throw new Error(HELP.journal);
684
962
  validateOptions(args.slice(2), ['--path'], ['--path']);
@@ -0,0 +1,8 @@
1
+ interface AdmissionStats {
2
+ schemaVersion: 1;
3
+ dropped: Record<string, number>;
4
+ updatedAt: string;
5
+ }
6
+ export declare function readAdmissionStats(root: string): Promise<AdmissionStats>;
7
+ export declare function recordAdmissionDrop(root: string, type: string): Promise<void>;
8
+ export {};
@@ -0,0 +1,24 @@
1
+ import path from 'node:path';
2
+ import { cognitionRuntimeDirectory } from '../storage/layout.js';
3
+ import { readJson, isRecord } from '../storage/json-store.js';
4
+ import { atomicWriteJson } from '../storage/atomic-write.js';
5
+ const statsPath = (root) => path.join(cognitionRuntimeDirectory(root), 'admission.json');
6
+ export async function readAdmissionStats(root) {
7
+ try {
8
+ return await readJson(statsPath(root), (value) => isRecord(value)
9
+ && value.schemaVersion === 1 && typeof value.updatedAt === 'string' && isRecord(value.dropped)
10
+ && Object.values(value.dropped).every((count) => typeof count === 'number' && Number.isSafeInteger(count) && count >= 0));
11
+ }
12
+ catch (error) {
13
+ if (error.code === 'ENOENT')
14
+ return { schemaVersion: 1, dropped: {}, updatedAt: '' };
15
+ throw error;
16
+ }
17
+ }
18
+ // The journal writer lock serializes these counters too. Never store content.
19
+ export async function recordAdmissionDrop(root, type) {
20
+ const stats = await readAdmissionStats(root);
21
+ stats.dropped[type] = Math.min(Number.MAX_SAFE_INTEGER, (stats.dropped[type] ?? 0) + 1);
22
+ stats.updatedAt = new Date().toISOString();
23
+ await atomicWriteJson(statsPath(root), stats);
24
+ }
@@ -0,0 +1,4 @@
1
+ import type { CognitionEvent, CognitionGitAnchor, EvidenceGraphProjection } from './types.js';
2
+ export declare const EVIDENCE_GRAPH_DERIVATION_VERSION: "evidence-graph-v1";
3
+ export declare function workspaceNodeId(anchor: Pick<CognitionGitAnchor, 'worktreeId' | 'branch' | 'ref'>): string;
4
+ export declare function buildEvidenceGraph(events: CognitionEvent[]): EvidenceGraphProjection;