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.
- package/CHANGELOG.md +35 -0
- package/README.md +110 -553
- package/ROADMAP-1.0.md +70 -0
- package/dist/src/agent/api.d.ts +41 -0
- package/dist/src/agent/api.js +37 -0
- package/dist/src/agent/index.d.ts +9 -1
- package/dist/src/agent/index.js +3 -0
- package/dist/src/capture/context-filter.js +2 -0
- package/dist/src/cli/main.js +293 -15
- package/dist/src/cognition/admission.d.ts +8 -0
- package/dist/src/cognition/admission.js +24 -0
- package/dist/src/cognition/evidence-graph.d.ts +4 -0
- package/dist/src/cognition/evidence-graph.js +187 -0
- package/dist/src/cognition/evolution.d.ts +36 -0
- package/dist/src/cognition/evolution.js +221 -0
- package/dist/src/cognition/import-memory.d.ts +18 -0
- package/dist/src/cognition/import-memory.js +124 -0
- package/dist/src/cognition/journal-segments.d.ts +11 -0
- package/dist/src/cognition/journal-segments.js +129 -0
- package/dist/src/cognition/journal.d.ts +13 -0
- package/dist/src/cognition/journal.js +186 -20
- package/dist/src/cognition/migration-v1.js +39 -3
- package/dist/src/cognition/projections.js +124 -2
- package/dist/src/cognition/recipes.d.ts +25 -0
- package/dist/src/cognition/recipes.js +149 -0
- package/dist/src/cognition/runtime.js +4 -0
- package/dist/src/cognition/skills.d.ts +45 -0
- package/dist/src/cognition/skills.js +184 -0
- package/dist/src/cognition/types.d.ts +181 -1
- package/dist/src/cognition/usage-report.js +30 -15
- package/dist/src/compiler/compile.js +101 -31
- package/dist/src/compiler/graph.d.ts +7 -0
- package/dist/src/compiler/graph.js +117 -0
- package/dist/src/compiler/identity.d.ts +1 -1
- package/dist/src/compiler/identity.js +2 -0
- package/dist/src/compiler/inject.d.ts +23 -0
- package/dist/src/compiler/inject.js +27 -0
- package/dist/src/compiler/sources.d.ts +3 -1
- package/dist/src/compiler/sources.js +10 -1
- package/dist/src/compiler/types.d.ts +22 -1
- package/dist/src/hooks/claude-code.js +17 -56
- package/dist/src/integrations/claude-code.js +30 -8
- package/dist/src/mcp/server.js +228 -1
- package/dist/src/runtime/knowledge.js +57 -8
- package/dist/src/runtime/setup.d.ts +27 -0
- package/dist/src/runtime/setup.js +85 -0
- package/dist/src/storage/layout.d.ts +5 -0
- package/dist/src/storage/layout.js +15 -0
- package/dist/src/storage/lock.js +19 -2
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +4 -1
- package/skills/fluffy-context/SKILL.md +46 -8
package/dist/src/cli/main.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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]
|
|
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
|
|
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;
|