@cortexkit/opencode-magic-context 0.6.2 → 0.7.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
@@ -45,6 +45,8 @@ Your agent should never stop working to manage its own context. Magic Context is
45
45
 
46
46
  **User Memories** — historian extracts behavioral observations about you alongside its normal compartment output (communication style, expertise level, review focus, working patterns). Recurring observations are promoted by the dreamer to stable user memories that appear in all sessions via `<user-profile>`. Enable with `experimental.user_memories.enabled: true` (requires dreamer).
47
47
 
48
+ **Key File Pinning** — dreamer analyzes which files your agent reads most frequently across the session. Core orientation files (architecture, config, types) that get re-read after every context drop are pinned into the system prompt as `<key-files>`, so the agent always has them without needing to re-read from disk. Files are read fresh on each cache-busting pass. Enable with `experimental.pin_key_files.enabled: true` (requires dreamer).
49
+
48
50
  ---
49
51
 
50
52
  ## Get Started
@@ -195,6 +195,13 @@ export interface MagicContextConfig {
195
195
  enabled: boolean;
196
196
  promotion_threshold: number;
197
197
  };
198
+ pin_key_files: {
199
+ enabled: boolean;
200
+ /** Total token budget for all pinned key files (default: 10000) */
201
+ token_budget: number;
202
+ /** Minimum full-read count before a file is considered for pinning (default: 4) */
203
+ min_reads: number;
204
+ };
198
205
  };
199
206
  embedding: EmbeddingConfig;
200
207
  memory: {
@@ -370,6 +377,11 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
370
377
  enabled: z.ZodDefault<z.ZodBoolean>;
371
378
  promotion_threshold: z.ZodDefault<z.ZodNumber>;
372
379
  }, z.core.$strip>>;
380
+ pin_key_files: z.ZodDefault<z.ZodObject<{
381
+ enabled: z.ZodDefault<z.ZodBoolean>;
382
+ token_budget: z.ZodDefault<z.ZodNumber>;
383
+ min_reads: z.ZodDefault<z.ZodNumber>;
384
+ }, z.core.$strip>>;
373
385
  }, z.core.$strip>>;
374
386
  memory: z.ZodDefault<z.ZodObject<{
375
387
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -470,6 +482,11 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
470
482
  enabled: boolean;
471
483
  promotion_threshold: number;
472
484
  };
485
+ pin_key_files: {
486
+ enabled: boolean;
487
+ token_budget: number;
488
+ min_reads: number;
489
+ };
473
490
  };
474
491
  memory: {
475
492
  enabled: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"magic-context.d.ts","sourceRoot":"","sources":["../../../src/config/schema/magic-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"magic-context.d.ts","sourceRoot":"","sources":["../../../src/config/schema/magic-context.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,11 @@
1
- import type { Database } from "bun:sqlite";
1
+ import { Database } from "bun:sqlite";
2
2
  import type { DreamingTask } from "../../../config/schema/magic-context";
3
3
  import type { PluginContext } from "../../../plugin/types";
4
+ interface ExperimentalPinKeyFilesConfig {
5
+ enabled: boolean;
6
+ token_budget: number;
7
+ min_reads: number;
8
+ }
4
9
  export declare function registerDreamProjectDirectory(projectIdentity: string, directory: string): void;
5
10
  export interface DreamRunResult {
6
11
  startedAt: number;
@@ -29,6 +34,7 @@ export declare function runDream(args: {
29
34
  enabled: boolean;
30
35
  promotionThreshold: number;
31
36
  };
37
+ experimentalPinKeyFiles?: ExperimentalPinKeyFilesConfig;
32
38
  }): Promise<DreamRunResult>;
33
39
  export declare function processDreamQueue(args: {
34
40
  db: Database;
@@ -40,5 +46,7 @@ export declare function processDreamQueue(args: {
40
46
  enabled: boolean;
41
47
  promotionThreshold: number;
42
48
  };
49
+ experimentalPinKeyFiles?: ExperimentalPinKeyFilesConfig;
43
50
  }): Promise<DreamRunResult | null>;
51
+ export {};
44
52
  //# sourceMappingURL=runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/dreamer/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAyB3D,wBAAgB,6BAA6B,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9F;AAMD,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE;QACH,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;CACP;AAaD,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACjC,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,6FAA6F;IAC7F,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E,GAAG,OAAO,CAAC,cAAc,CAAC,CA8R1B;AA0LD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC1C,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAwDjC"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/dreamer/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AA0C3D,UAAU,6BAA6B;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,6BAA6B,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9F;AAMD,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE;QACH,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;CACP;AA6RD,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACjC,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,6FAA6F;IAC7F,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uBAAuB,CAAC,EAAE,6BAA6B,CAAC;CAC3D,GAAG,OAAO,CAAC,cAAc,CAAC,CA8S1B;AA0LD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC1C,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uBAAuB,CAAC,EAAE,6BAA6B,CAAC;CAC3D,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAyDjC"}
@@ -0,0 +1,39 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import { type FileReadStat } from "./read-stats";
3
+ export declare const KEY_FILES_SYSTEM_PROMPT = "You are a file importance evaluator. Given read statistics about files in a coding session, identify which are core orientation files worth pinning in context. Return a JSON array.";
4
+ /**
5
+ * Build the LLM prompt for key file identification.
6
+ * Called from the dreamer runner which handles session creation.
7
+ */
8
+ export declare function buildKeyFilesPrompt(candidates: FileReadStat[], tokenBudget: number, minReads: number): string;
9
+ /**
10
+ * Parse the LLM's response into a ranked file list.
11
+ */
12
+ export declare function parseKeyFilesOutput(text: string): Array<{
13
+ filePath: string;
14
+ tokens: number;
15
+ }>;
16
+ /**
17
+ * Get candidate files for key-file analysis from OpenCode's DB.
18
+ * Returns files with full reads >= minReads and size under half the budget.
19
+ */
20
+ export declare function getKeyFileCandidates(openCodeDb: Database, sessionId: string, minReads: number, tokenBudget: number): FileReadStat[];
21
+ /**
22
+ * Apply LLM-ranked results through the knapsack solver and persist.
23
+ */
24
+ export declare function applyKeyFileResults(db: Database, sessionId: string, llmRanked: Array<{
25
+ filePath: string;
26
+ tokens: number;
27
+ }>, tokenBudget: number, candidatePaths?: Set<string>): {
28
+ filesIdentified: number;
29
+ totalTokens: number;
30
+ };
31
+ /**
32
+ * Pure heuristic fallback when LLM is unavailable.
33
+ * Ranks by: high read count, low edit count, reasonable size.
34
+ */
35
+ export declare function heuristicKeyFileSelection(db: Database, sessionId: string, candidates: FileReadStat[], tokenBudget: number): {
36
+ filesIdentified: number;
37
+ totalTokens: number;
38
+ };
39
+ //# sourceMappingURL=identify-key-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identify-key-files.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/key-files/identify-key-files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAE,KAAK,YAAY,EAAuB,MAAM,cAAc,CAAC;AAGtE,eAAO,MAAM,uBAAuB,yLACsJ,CAAC;AAE3L;;;GAGG;AACH,wBAAgB,mBAAmB,CAC/B,UAAU,EAAE,YAAY,EAAE,EAC1B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACjB,MAAM,CAqCR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB7F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAChC,UAAU,EAAE,QAAQ,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GACpB,YAAY,EAAE,CAIhB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EACtD,WAAW,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAC7B;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAelD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACrC,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,YAAY,EAAE,EAC1B,WAAW,EAAE,MAAM,GACpB;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAmBlD"}
@@ -0,0 +1,20 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export interface FileReadStat {
3
+ filePath: string;
4
+ fullReadCount: number;
5
+ /** Number of distinct compartment ranges the reads span across */
6
+ spreadAcrossCompartments: number;
7
+ /** Number of times the file was edited (write/edit tool) in this session */
8
+ editCount: number;
9
+ /** Byte size of the most recent full read output */
10
+ latestReadBytes: number;
11
+ /** Approximate token count of the most recent full read (~3.5 chars per token) */
12
+ latestReadTokens: number;
13
+ }
14
+ /**
15
+ * Query file read patterns from OpenCode's DB for a specific session.
16
+ * Returns files that were fully read (no line range) at least `minReads` times,
17
+ * sorted by read frequency descending.
18
+ */
19
+ export declare function getSessionReadStats(openCodeDb: Database, sessionId: string, minReads: number): FileReadStat[];
20
+ //# sourceMappingURL=read-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-stats.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/key-files/read-stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,wBAAwB,EAAE,MAAM,CAAC;IACjC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,eAAe,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAC/B,UAAU,EAAE,QAAQ,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACjB,YAAY,EAAE,CAgFhB"}
@@ -0,0 +1,25 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export interface KeyFileEntry {
3
+ filePath: string;
4
+ /** Approximate token count when last pinned */
5
+ tokens: number;
6
+ }
7
+ /**
8
+ * Get the pinned key files for a session from session_meta.
9
+ * Returns empty array if not set or parse fails.
10
+ */
11
+ export declare function getKeyFiles(db: Database, sessionId: string): KeyFileEntry[];
12
+ /**
13
+ * Set the pinned key files for a session.
14
+ */
15
+ export declare function setKeyFiles(db: Database, sessionId: string, files: KeyFileEntry[]): void;
16
+ /**
17
+ * Greedy-fit files into a token budget.
18
+ * Takes files sorted by priority (dreamer's ranking) and greedily adds
19
+ * them until the budget is exhausted. Returns the selected files.
20
+ */
21
+ export declare function greedyFitFiles(rankedFiles: Array<{
22
+ filePath: string;
23
+ tokens: number;
24
+ }>, tokenBudget: number): KeyFileEntry[];
25
+ //# sourceMappingURL=storage-key-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-key-files.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/key-files/storage-key-files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAqB3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAYxF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC1B,WAAW,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EACxD,WAAW,EAAE,MAAM,GACpB,YAAY,EAAE,CAehB"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-db.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/storage-db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAkBtC,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAiRrD;AAiCD,wBAAgB,YAAY,IAAI,QAAQ,CAsCvC;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAEzD;AAED,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAEvE;AAED,wBAAgB,aAAa,IAAI,IAAI,CAUpC;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"storage-db.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/storage-db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAkBtC,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAkRrD;AAiCD,wBAAgB,YAAY,IAAI,QAAQ,CAsCvC;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAEzD;AAED,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAEvE;AAED,wBAAgB,aAAa,IAAI,IAAI,CAUpC;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -47,6 +47,11 @@ export declare function createMagicContextCommandHandler(deps: {
47
47
  enabled: boolean;
48
48
  promotionThreshold: number;
49
49
  };
50
+ experimentalPinKeyFiles?: {
51
+ enabled: boolean;
52
+ token_budget: number;
53
+ min_reads: number;
54
+ };
50
55
  };
51
56
  }): {
52
57
  "command.execute.before": (input: CommandExecuteInput, _output: CommandExecuteOutput, _params: NotificationParams) => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/command-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EACH,KAAK,cAAc,EAGtB,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAOtE,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AA8JD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACnD,EAAE,EAAE,QAAQ,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0BAA0B,CAAC,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACtF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,oBAAoB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC5D,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,gBAAgB,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,kBAAkB,KACzB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE;QACP,MAAM,EAAE,cAAc,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;KACnC,CAAC;IACF,OAAO,CAAC,EAAE;QACN,MAAM,EAAE,aAAa,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QACrE,wBAAwB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,kBAAkB,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/E,CAAC;CACL;sCASkB,mBAAmB,WACjB,oBAAoB,WACpB,kBAAkB,KAC5B,OAAO,CAAC,IAAI,CAAC;EAoGvB"}
1
+ {"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/command-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EACH,KAAK,cAAc,EAGtB,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAOtE,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAoKD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACnD,EAAE,EAAE,QAAQ,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0BAA0B,CAAC,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACtF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,oBAAoB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC5D,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,gBAAgB,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,kBAAkB,KACzB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE;QACP,MAAM,EAAE,cAAc,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;KACnC,CAAC;IACF,OAAO,CAAC,EAAE;QACN,MAAM,EAAE,aAAa,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QACrE,wBAAwB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,kBAAkB,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5E,uBAAuB,CAAC,EAAE;YACtB,OAAO,EAAE,OAAO,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,SAAS,EAAE,MAAM,CAAC;SACrB,CAAC;KACL,CAAC;CACL;sCASkB,mBAAmB,WACjB,oBAAoB,WACpB,kBAAkB,KAC5B,OAAO,CAAC,IAAI,CAAC;EAoGvB"}
@@ -43,6 +43,11 @@ export interface MagicContextDeps {
43
43
  enabled: boolean;
44
44
  promotion_threshold: number;
45
45
  };
46
+ pin_key_files?: {
47
+ enabled: boolean;
48
+ token_budget: number;
49
+ min_reads: number;
50
+ };
46
51
  };
47
52
  };
48
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,aAAa,EAClB,KAAK,cAAc,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAOvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAMxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWxD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAiBnF,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,MAAM,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,4BAA4B,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACxF,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,uBAAuB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9C,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,CAAC,EAAE;YACL,OAAO,EAAE,OAAO,CAAC;YACjB,uBAAuB,EAAE,MAAM,CAAC;SACnC,CAAC;QACF,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,sBAAsB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;QACpE,YAAY,CAAC,EAAE;YACX,kBAAkB,CAAC,EAAE,OAAO,CAAC;YAC7B,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,mBAAmB,EAAE,MAAM,CAAA;aAAE,CAAC;SACrE,CAAC;KACL,CAAC;CACL;AAqCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB;;;;;iBAtDtC,CAAC;;;;;;;;;;;;iBAbpB,CAAA;eACA,CAAF;;mBA2S2B;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE;;;SAa7E"}
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,aAAa,EAClB,KAAK,cAAc,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAOvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAMxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWxD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAiBnF,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,MAAM,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,4BAA4B,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACxF,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,uBAAuB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9C,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,CAAC,EAAE;YACL,OAAO,EAAE,OAAO,CAAC;YACjB,uBAAuB,EAAE,MAAM,CAAC;SACnC,CAAC;QACF,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,sBAAsB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;QACpE,YAAY,CAAC,EAAE;YACX,kBAAkB,CAAC,EAAE,OAAO,CAAC;YAC7B,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,mBAAmB,EAAE,MAAM,CAAA;aAAE,CAAC;YAClE,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,YAAY,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAA;aAAE,CAAC;SACjF,CAAC;KACL,CAAC;CACL;AAqCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB;;;;;iBAxCF,CAAC;;;;;;;;;;;;iBA5BxD,CAAA;eACA,CAAF;;mBA4T2B;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE;;;SAa7E"}
@@ -25,6 +25,10 @@ export declare function createSystemPromptHashHandler(deps: {
25
25
  lastHeuristicsTurnId: Map<string, string>;
26
26
  /** When true, inject stable user memories as <user-profile> into system prompt */
27
27
  experimentalUserMemories?: boolean;
28
+ /** When true, inject pinned key files as <key-files> into system prompt */
29
+ experimentalPinKeyFiles?: boolean;
30
+ /** Token budget for key files injection (default 10000) */
31
+ experimentalPinKeyFilesTokenBudget?: number;
28
32
  }): (input: {
29
33
  sessionID?: string;
30
34
  }, output: {
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt-hash.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/system-prompt-hash.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,KAAK,eAAe,EAGvB,MAAM,sCAAsC,CAAC;AAqC9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAChD,EAAE,EAAE,eAAe,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,6FAA6F;IAC7F,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,kFAAkF;IAClF,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACtC,GAAG,CAAC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAgKjF"}
1
+ {"version":3,"file":"system-prompt-hash.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/system-prompt-hash.ts"],"names":[],"mappings":"AAQA,OAAO,EACH,KAAK,eAAe,EAGvB,MAAM,sCAAsC,CAAC;AAwC9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAChD,EAAE,EAAE,eAAe,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,6FAA6F;IAC7F,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,kFAAkF;IAClF,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2EAA2E;IAC3E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2DAA2D;IAC3D,kCAAkC,CAAC,EAAE,MAAM,CAAC;CAC/C,GAAG,CAAC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CA2PjF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAuBlD,QAAA,MAAM,MAAM,EAAE,MA2Lb,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAuBlD,QAAA,MAAM,MAAM,EAAE,MAkMb,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js CHANGED
@@ -22202,10 +22202,16 @@ var MagicContextConfigSchema = exports_external.object({
22202
22202
  user_memories: exports_external.object({
22203
22203
  enabled: exports_external.boolean().default(false),
22204
22204
  promotion_threshold: exports_external.number().min(2).max(20).default(3)
22205
- }).default({ enabled: false, promotion_threshold: 3 })
22205
+ }).default({ enabled: false, promotion_threshold: 3 }),
22206
+ pin_key_files: exports_external.object({
22207
+ enabled: exports_external.boolean().default(false),
22208
+ token_budget: exports_external.number().min(2000).max(30000).default(1e4),
22209
+ min_reads: exports_external.number().min(2).max(20).default(4)
22210
+ }).default({ enabled: false, token_budget: 1e4, min_reads: 4 })
22206
22211
  }).default({
22207
22212
  compaction_markers: false,
22208
- user_memories: { enabled: false, promotion_threshold: 3 }
22213
+ user_memories: { enabled: false, promotion_threshold: 3 },
22214
+ pin_key_files: { enabled: false, token_budget: 1e4, min_reads: 4 }
22209
22215
  }),
22210
22216
  memory: exports_external.object({
22211
22217
  enabled: exports_external.boolean().default(true),
@@ -23502,8 +23508,19 @@ function clearStaleEntries(db, maxAgeMs) {
23502
23508
  return result.changes;
23503
23509
  }
23504
23510
  // src/features/magic-context/dreamer/runner.ts
23511
+ import { Database } from "bun:sqlite";
23505
23512
  import { existsSync as existsSync4 } from "fs";
23506
- import { join as join6 } from "path";
23513
+ import { join as join7 } from "path";
23514
+
23515
+ // src/shared/data-path.ts
23516
+ import * as os2 from "os";
23517
+ import * as path2 from "path";
23518
+ function getDataDir() {
23519
+ return process.env.XDG_DATA_HOME ?? path2.join(os2.homedir(), ".local", "share");
23520
+ }
23521
+ function getOpenCodeStorageDir() {
23522
+ return path2.join(getDataDir(), "opencode", "storage");
23523
+ }
23507
23524
 
23508
23525
  // src/shared/error-message.ts
23509
23526
  function getErrorMessage(error48) {
@@ -23513,6 +23530,189 @@ function getErrorMessage(error48) {
23513
23530
  // src/features/magic-context/dreamer/runner.ts
23514
23531
  init_logger();
23515
23532
 
23533
+ // src/features/magic-context/key-files/identify-key-files.ts
23534
+ init_logger();
23535
+
23536
+ // src/features/magic-context/key-files/read-stats.ts
23537
+ function getSessionReadStats(openCodeDb, sessionId, minReads) {
23538
+ const fullReads = openCodeDb.prepare(`
23539
+ WITH full_reads AS (
23540
+ SELECT
23541
+ json_extract(json_extract(data, '$.state'), '$.input.filePath') as file_path,
23542
+ LENGTH(json_extract(json_extract(data, '$.state'), '$.output')) as output_bytes,
23543
+ p.time_created,
23544
+ ROW_NUMBER() OVER (
23545
+ PARTITION BY json_extract(json_extract(data, '$.state'), '$.input.filePath')
23546
+ ORDER BY p.time_created DESC
23547
+ ) as rn
23548
+ FROM part p
23549
+ WHERE p.session_id = ?
23550
+ AND json_extract(data, '$.type') = 'tool'
23551
+ AND json_extract(data, '$.tool') = 'read'
23552
+ AND json_extract(json_extract(data, '$.state'), '$.input.filePath') IS NOT NULL
23553
+ AND json_extract(json_extract(data, '$.state'), '$.input.startLine') IS NULL
23554
+ AND json_extract(json_extract(data, '$.state'), '$.input.start_line') IS NULL
23555
+ AND json_extract(json_extract(data, '$.state'), '$.input.endLine') IS NULL
23556
+ AND json_extract(json_extract(data, '$.state'), '$.input.end_line') IS NULL
23557
+ AND json_extract(json_extract(data, '$.state'), '$.input.offset') IS NULL
23558
+ AND json_extract(json_extract(data, '$.state'), '$.input.limit') IS NULL
23559
+ ),
23560
+ file_counts AS (
23561
+ SELECT file_path, COUNT(*) as full_read_count
23562
+ FROM full_reads
23563
+ GROUP BY file_path
23564
+ HAVING full_read_count >= ?
23565
+ )
23566
+ SELECT
23567
+ r.file_path,
23568
+ fc.full_read_count,
23569
+ r.output_bytes as latest_read_bytes
23570
+ FROM full_reads r
23571
+ JOIN file_counts fc ON r.file_path = fc.file_path
23572
+ WHERE r.rn = 1
23573
+ ORDER BY fc.full_read_count DESC
23574
+ `).all(sessionId, minReads);
23575
+ if (fullReads.length === 0)
23576
+ return [];
23577
+ const editCounts = new Map;
23578
+ const editRows = openCodeDb.prepare(`
23579
+ SELECT
23580
+ json_extract(json_extract(data, '$.state'), '$.input.filePath') as file_path,
23581
+ COUNT(*) as edit_count
23582
+ FROM part p
23583
+ WHERE p.session_id = ?
23584
+ AND json_extract(data, '$.type') = 'tool'
23585
+ AND json_extract(data, '$.tool') IN ('edit', 'write', 'mcp_edit', 'mcp_write')
23586
+ AND json_extract(json_extract(data, '$.state'), '$.input.filePath') IS NOT NULL
23587
+ GROUP BY file_path
23588
+ `).all(sessionId);
23589
+ for (const row of editRows) {
23590
+ editCounts.set(row.file_path, row.edit_count);
23591
+ }
23592
+ return fullReads.map((row) => ({
23593
+ filePath: row.file_path,
23594
+ fullReadCount: row.full_read_count,
23595
+ spreadAcrossCompartments: 0,
23596
+ editCount: editCounts.get(row.file_path) ?? 0,
23597
+ latestReadBytes: row.latest_read_bytes ?? 0,
23598
+ latestReadTokens: Math.ceil((row.latest_read_bytes ?? 0) / 3.5)
23599
+ }));
23600
+ }
23601
+
23602
+ // src/features/magic-context/key-files/storage-key-files.ts
23603
+ init_logger();
23604
+ function getKeyFiles(db, sessionId) {
23605
+ try {
23606
+ const row = db.prepare("SELECT key_files FROM session_meta WHERE session_id = ?").get(sessionId);
23607
+ if (!row?.key_files)
23608
+ return [];
23609
+ const parsed = JSON.parse(row.key_files);
23610
+ if (!Array.isArray(parsed))
23611
+ return [];
23612
+ return parsed.filter((e) => typeof e === "object" && e !== null && typeof e.filePath === "string" && typeof e.tokens === "number");
23613
+ } catch {
23614
+ return [];
23615
+ }
23616
+ }
23617
+ function setKeyFiles(db, sessionId, files) {
23618
+ try {
23619
+ db.prepare("INSERT OR IGNORE INTO session_meta (session_id) VALUES (?)").run(sessionId);
23620
+ db.prepare("UPDATE session_meta SET key_files = ? WHERE session_id = ?").run(JSON.stringify(files), sessionId);
23621
+ } catch (error48) {
23622
+ sessionLog(sessionId, "failed to persist key files:", error48);
23623
+ }
23624
+ }
23625
+ function greedyFitFiles(rankedFiles, tokenBudget) {
23626
+ const selected = [];
23627
+ let remainingBudget = tokenBudget;
23628
+ for (const file2 of rankedFiles) {
23629
+ if (file2.tokens <= 0)
23630
+ continue;
23631
+ if (file2.tokens > remainingBudget)
23632
+ continue;
23633
+ selected.push({ filePath: file2.filePath, tokens: file2.tokens });
23634
+ remainingBudget -= file2.tokens;
23635
+ if (remainingBudget <= 0)
23636
+ break;
23637
+ }
23638
+ return selected;
23639
+ }
23640
+
23641
+ // src/features/magic-context/key-files/identify-key-files.ts
23642
+ var KEY_FILES_SYSTEM_PROMPT = "You are a file importance evaluator. Given read statistics about files in a coding session, identify which are core orientation files worth pinning in context. Return a JSON array.";
23643
+ function buildKeyFilesPrompt(candidates, tokenBudget, minReads) {
23644
+ const statsText = candidates.map((s) => `- **${s.filePath}** \u2014 ${s.fullReadCount} full reads, ${s.editCount} edits, ~${s.latestReadTokens} tokens`).join(`
23645
+ `);
23646
+ return `## Identify Key Files for Pinning
23647
+
23648
+ The following files were fully read ${minReads}+ times during a coding session.
23649
+ Identify which ones are **core orientation files** worth keeping permanently in context.
23650
+
23651
+ ### Signals of a core orientation file:
23652
+ - Read many times across different phases of work (not clustered in one task)
23653
+ - Read without editing \u2014 consulted for understanding, not modification
23654
+ - Contains architecture, configuration, types, or key abstractions
23655
+
23656
+ ### Signals of a NON-core file (exclude):
23657
+ - Read many times but always edited \u2014 actively working on it
23658
+ - Very large (>5000 tokens) \u2014 too expensive to pin
23659
+ - Test files, scripts, or generated files
23660
+
23661
+ ### Token budget: ${tokenBudget} tokens total
23662
+
23663
+ ### Files:
23664
+ ${statsText}
23665
+
23666
+ ### Output Format
23667
+ Return a JSON array ranked by importance (most important first):
23668
+ \`\`\`json
23669
+ [
23670
+ {"filePath": "src/path/to/file.ts", "tokens": 2500, "reason": "brief reason"}
23671
+ ]
23672
+ \`\`\`
23673
+
23674
+ Only include files you're confident are true orientation files. Return empty array if none qualify.`;
23675
+ }
23676
+ function parseKeyFilesOutput(text) {
23677
+ const jsonMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/) ?? text.match(/\[[\s\S]*\]/);
23678
+ if (!jsonMatch)
23679
+ return [];
23680
+ try {
23681
+ const raw = jsonMatch[1] ?? jsonMatch[0];
23682
+ const parsed = JSON.parse(raw);
23683
+ if (!Array.isArray(parsed))
23684
+ return [];
23685
+ return parsed.filter((item) => typeof item === "object" && item !== null && typeof item.filePath === "string" && typeof item.tokens === "number").map((item) => ({ filePath: item.filePath, tokens: item.tokens }));
23686
+ } catch {
23687
+ return [];
23688
+ }
23689
+ }
23690
+ function getKeyFileCandidates(openCodeDb, sessionId, minReads, tokenBudget) {
23691
+ const stats = getSessionReadStats(openCodeDb, sessionId, minReads);
23692
+ const maxPerFileTokens = Math.min(tokenBudget / 2, 5000);
23693
+ return stats.filter((s) => s.latestReadTokens > 0 && s.latestReadTokens <= maxPerFileTokens);
23694
+ }
23695
+ function applyKeyFileResults(db, sessionId, llmRanked, tokenBudget, candidatePaths) {
23696
+ const filtered = candidatePaths ? llmRanked.filter((f) => candidatePaths.has(f.filePath)) : llmRanked;
23697
+ const selected = greedyFitFiles(filtered, tokenBudget);
23698
+ setKeyFiles(db, sessionId, selected);
23699
+ const totalTokens = selected.reduce((sum, f) => sum + f.tokens, 0);
23700
+ log(`[key-files][${sessionId}] pinned ${selected.length} files (${totalTokens} tokens): ${selected.map((f) => f.filePath).join(", ")}`);
23701
+ return { filesIdentified: selected.length, totalTokens };
23702
+ }
23703
+ function heuristicKeyFileSelection(db, sessionId, candidates, tokenBudget) {
23704
+ const scored = candidates.map((c) => ({
23705
+ filePath: c.filePath,
23706
+ tokens: c.latestReadTokens,
23707
+ score: c.fullReadCount * 2 - c.editCount * 3
23708
+ })).filter((c) => c.score > 0).sort((a, b) => b.score - a.score);
23709
+ const selected = greedyFitFiles(scored, tokenBudget);
23710
+ setKeyFiles(db, sessionId, selected);
23711
+ const totalTokens = selected.reduce((sum, f) => sum + f.tokens, 0);
23712
+ log(`[key-files][${sessionId}] heuristic pinned ${selected.length} files (${totalTokens} tokens)`);
23713
+ return { filesIdentified: selected.length, totalTokens };
23714
+ }
23715
+
23516
23716
  // src/features/magic-context/memory/storage-memory-embeddings.ts
23517
23717
  var saveEmbeddingStatements = new WeakMap;
23518
23718
  var loadAllEmbeddingsStatements = new WeakMap;
@@ -24408,6 +24608,176 @@ function countNewIds(beforeIds, afterIds) {
24408
24608
  }
24409
24609
  return count;
24410
24610
  }
24611
+ function getOpenCodeDbPath() {
24612
+ return join7(getDataDir(), "opencode", "opencode.db");
24613
+ }
24614
+ function openOpenCodeDb() {
24615
+ const dbPath = getOpenCodeDbPath();
24616
+ if (!existsSync4(dbPath)) {
24617
+ log(`[key-files] OpenCode DB not found at ${dbPath} \u2014 skipping`);
24618
+ return null;
24619
+ }
24620
+ try {
24621
+ const db = new Database(dbPath, { readonly: true });
24622
+ db.exec("PRAGMA busy_timeout = 5000");
24623
+ return db;
24624
+ } catch (error48) {
24625
+ log(`[key-files] failed to open OpenCode DB at ${dbPath}: ${getErrorMessage(error48)}`);
24626
+ return null;
24627
+ }
24628
+ }
24629
+ function isSessionIdRow(row) {
24630
+ if (row === null || typeof row !== "object") {
24631
+ return false;
24632
+ }
24633
+ return typeof row.sessionId === "string";
24634
+ }
24635
+ function hasExplicitEmptyKeyFilesOutput(text) {
24636
+ return /```(?:json)?\s*\[\s*\]\s*```/s.test(text) || /^\s*\[\s*\]\s*$/s.test(text);
24637
+ }
24638
+ async function getActiveProjectSessionIds(args) {
24639
+ const listResponse = await args.client.session.list({
24640
+ query: { directory: args.sessionDirectory ?? args.projectIdentity }
24641
+ });
24642
+ const sessions = normalizeSDKResponse(listResponse, [], {
24643
+ preferResponseOnMissingData: true
24644
+ });
24645
+ const projectSessionIds = new Set(sessions.map((session) => typeof session?.id === "string" ? session.id : null).filter((sessionId) => Boolean(sessionId)));
24646
+ if (projectSessionIds.size === 0) {
24647
+ return [];
24648
+ }
24649
+ return args.db.prepare("SELECT session_id AS sessionId FROM session_meta WHERE is_subagent = 0 ORDER BY session_id ASC").all().filter(isSessionIdRow).map((row) => row.sessionId).filter((sessionId) => projectSessionIds.has(sessionId));
24650
+ }
24651
+ async function identifyKeyFilesForSession(args) {
24652
+ let openCodeDb = null;
24653
+ try {
24654
+ openCodeDb = openOpenCodeDb();
24655
+ if (!openCodeDb) {
24656
+ return;
24657
+ }
24658
+ const candidates = getKeyFileCandidates(openCodeDb, args.sessionId, args.config.min_reads, args.config.token_budget);
24659
+ if (candidates.length === 0) {
24660
+ log(`[key-files][${args.sessionId}] no candidates found \u2014 skipping`);
24661
+ return;
24662
+ }
24663
+ const prompt = buildKeyFilesPrompt(candidates, args.config.token_budget, args.config.min_reads);
24664
+ const applyHeuristicFallback = () => {
24665
+ heuristicKeyFileSelection(args.db, args.sessionId, candidates, args.config.token_budget);
24666
+ };
24667
+ let agentSessionId = null;
24668
+ const abortController = new AbortController;
24669
+ const leaseInterval = setInterval(() => {
24670
+ try {
24671
+ if (!renewLease(args.db, args.holderId)) {
24672
+ log(`[key-files][${args.sessionId}] lease renewal failed \u2014 aborting`);
24673
+ abortController.abort();
24674
+ }
24675
+ } catch {
24676
+ abortController.abort();
24677
+ }
24678
+ }, 60000);
24679
+ try {
24680
+ const createResponse = await args.client.session.create({
24681
+ body: {
24682
+ ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
24683
+ title: `magic-context-dream-key-files-${args.sessionId.slice(0, 12)}`
24684
+ },
24685
+ query: { directory: args.sessionDirectory }
24686
+ });
24687
+ const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
24688
+ agentSessionId = typeof created?.id === "string" ? created.id : null;
24689
+ if (!agentSessionId) {
24690
+ throw new Error("Could not create key-file identification session.");
24691
+ }
24692
+ log(`[key-files][${args.sessionId}] child session created ${agentSessionId}`);
24693
+ const remainingMs = Math.max(0, args.deadline - Date.now());
24694
+ await promptSyncWithModelSuggestionRetry(args.client, {
24695
+ path: { id: agentSessionId },
24696
+ query: { directory: args.sessionDirectory },
24697
+ body: {
24698
+ agent: DREAMER_AGENT,
24699
+ system: KEY_FILES_SYSTEM_PROMPT,
24700
+ parts: [{ type: "text", text: prompt }]
24701
+ }
24702
+ }, { timeoutMs: Math.min(remainingMs, 5 * 60 * 1000), signal: abortController.signal });
24703
+ const messagesResponse = await args.client.session.messages({
24704
+ path: { id: agentSessionId },
24705
+ query: { directory: args.sessionDirectory }
24706
+ });
24707
+ const messages = normalizeSDKResponse(messagesResponse, [], {
24708
+ preferResponseOnMissingData: true
24709
+ });
24710
+ const responseText = extractLatestAssistantText(messages);
24711
+ if (!responseText) {
24712
+ log(`[key-files][${args.sessionId}] no response from agent \u2014 using heuristic fallback`);
24713
+ applyHeuristicFallback();
24714
+ return;
24715
+ }
24716
+ const parsed = parseKeyFilesOutput(responseText);
24717
+ if (parsed.length > 0 || hasExplicitEmptyKeyFilesOutput(responseText)) {
24718
+ const candidatePaths = new Set(candidates.map((c) => c.filePath));
24719
+ applyKeyFileResults(args.db, args.sessionId, parsed, args.config.token_budget, candidatePaths);
24720
+ return;
24721
+ }
24722
+ log(`[key-files][${args.sessionId}] could not parse agent output \u2014 using heuristic fallback`);
24723
+ applyHeuristicFallback();
24724
+ } catch (error48) {
24725
+ log(`[key-files][${args.sessionId}] identification failed: ${getErrorMessage(error48)} \u2014 using heuristic fallback`);
24726
+ try {
24727
+ applyHeuristicFallback();
24728
+ } catch (fallbackError) {
24729
+ log(`[key-files][${args.sessionId}] heuristic fallback failed: ${getErrorMessage(fallbackError)}`);
24730
+ }
24731
+ } finally {
24732
+ clearInterval(leaseInterval);
24733
+ if (agentSessionId) {
24734
+ await args.client.session.delete({
24735
+ path: { id: agentSessionId },
24736
+ query: { directory: args.sessionDirectory }
24737
+ }).catch((error48) => {
24738
+ log(`[key-files][${args.sessionId}] session cleanup failed: ${getErrorMessage(error48)}`);
24739
+ });
24740
+ }
24741
+ }
24742
+ } finally {
24743
+ if (openCodeDb) {
24744
+ try {
24745
+ openCodeDb.close(false);
24746
+ } catch (error48) {
24747
+ log(`[key-files][${args.sessionId}] failed to close OpenCode DB: ${getErrorMessage(error48)}`);
24748
+ }
24749
+ }
24750
+ }
24751
+ }
24752
+ async function identifyKeyFiles(args) {
24753
+ const sessionIds = await getActiveProjectSessionIds({
24754
+ db: args.db,
24755
+ client: args.client,
24756
+ projectIdentity: args.projectIdentity,
24757
+ sessionDirectory: args.sessionDirectory
24758
+ });
24759
+ if (sessionIds.length === 0) {
24760
+ log(`[key-files] no active sessions found for ${args.projectIdentity}`);
24761
+ return;
24762
+ }
24763
+ log(`[key-files] evaluating ${sessionIds.length} active session(s) for ${args.projectIdentity}`);
24764
+ for (const sessionId of sessionIds) {
24765
+ if (Date.now() > args.deadline) {
24766
+ log("[key-files] deadline reached \u2014 stopping key-file identification");
24767
+ break;
24768
+ }
24769
+ await identifyKeyFilesForSession({
24770
+ db: args.db,
24771
+ client: args.client,
24772
+ parentSessionId: args.parentSessionId,
24773
+ sessionDirectory: args.sessionDirectory,
24774
+ holderId: args.holderId,
24775
+ deadline: args.deadline,
24776
+ sessionId,
24777
+ config: args.config
24778
+ });
24779
+ }
24780
+ }
24411
24781
  async function runDream(args) {
24412
24782
  const holderId = crypto.randomUUID();
24413
24783
  const startedAt = Date.now();
@@ -24479,8 +24849,8 @@ async function runDream(args) {
24479
24849
  try {
24480
24850
  const docsDir = args.sessionDirectory ?? args.projectIdentity;
24481
24851
  const existingDocs = taskName === "maintain-docs" ? {
24482
- architecture: existsSync4(join6(docsDir, "ARCHITECTURE.md")),
24483
- structure: existsSync4(join6(docsDir, "STRUCTURE.md"))
24852
+ architecture: existsSync4(join7(docsDir, "ARCHITECTURE.md")),
24853
+ structure: existsSync4(join7(docsDir, "STRUCTURE.md"))
24484
24854
  } : undefined;
24485
24855
  const taskPrompt = buildDreamTaskPrompt(taskName, {
24486
24856
  projectPath: args.projectIdentity,
@@ -24586,6 +24956,22 @@ async function runDream(args) {
24586
24956
  log(`[dreamer] smart note evaluation failed: ${getErrorMessage(error48)}`);
24587
24957
  }
24588
24958
  }
24959
+ if (args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
24960
+ try {
24961
+ await identifyKeyFiles({
24962
+ db: args.db,
24963
+ client: args.client,
24964
+ projectIdentity: args.projectIdentity,
24965
+ parentSessionId,
24966
+ sessionDirectory: args.sessionDirectory ?? args.projectIdentity,
24967
+ holderId,
24968
+ deadline,
24969
+ config: args.experimentalPinKeyFiles
24970
+ });
24971
+ } catch (error48) {
24972
+ log(`[key-files] identification phase failed: ${getErrorMessage(error48)}`);
24973
+ }
24974
+ }
24589
24975
  } finally {
24590
24976
  releaseLease(args.db, holderId);
24591
24977
  log(`[dreamer] lease released: ${holderId}`);
@@ -24794,7 +25180,8 @@ async function processDreamQueue(args) {
24794
25180
  taskTimeoutMinutes: args.taskTimeoutMinutes,
24795
25181
  maxRuntimeMinutes: args.maxRuntimeMinutes,
24796
25182
  sessionDirectory: projectDirectory,
24797
- experimentalUserMemories: args.experimentalUserMemories
25183
+ experimentalUserMemories: args.experimentalUserMemories,
25184
+ experimentalPinKeyFiles: args.experimentalPinKeyFiles
24798
25185
  });
24799
25186
  } catch (error48) {
24800
25187
  log(`[dreamer] runDream threw for ${entry.projectIdentity}: ${getErrorMessage(error48)}`);
@@ -25291,7 +25678,7 @@ function getEmbeddingModelId() {
25291
25678
 
25292
25679
  // src/features/magic-context/memory/project-identity.ts
25293
25680
  import { execSync } from "child_process";
25294
- import path2 from "path";
25681
+ import path3 from "path";
25295
25682
  var GIT_TIMEOUT_MS = 5000;
25296
25683
  var resolvedCache = new Map;
25297
25684
  function getRootCommitHash(directory) {
@@ -25310,12 +25697,12 @@ function getRootCommitHash(directory) {
25310
25697
  }
25311
25698
  }
25312
25699
  function directoryFallback(directory) {
25313
- const canonical = path2.resolve(directory);
25700
+ const canonical = path3.resolve(directory);
25314
25701
  const hash2 = Bun.hash(canonical).toString(16).slice(0, 12);
25315
25702
  return `dir:${hash2}`;
25316
25703
  }
25317
25704
  function resolveProjectIdentity(directory) {
25318
- const resolved = path2.resolve(directory);
25705
+ const resolved = path3.resolve(directory);
25319
25706
  const cached2 = resolvedCache.get(resolved);
25320
25707
  if (cached2 !== undefined) {
25321
25708
  return cached2;
@@ -25402,22 +25789,10 @@ function removeSystemReminders(text) {
25402
25789
  }
25403
25790
 
25404
25791
  // src/hooks/magic-context/read-session-db.ts
25405
- import { Database } from "bun:sqlite";
25792
+ import { Database as Database2 } from "bun:sqlite";
25406
25793
  import { join as join8 } from "path";
25407
-
25408
- // src/shared/data-path.ts
25409
- import * as os2 from "os";
25410
- import * as path3 from "path";
25411
- function getDataDir() {
25412
- return process.env.XDG_DATA_HOME ?? path3.join(os2.homedir(), ".local", "share");
25413
- }
25414
- function getOpenCodeStorageDir() {
25415
- return path3.join(getDataDir(), "opencode", "storage");
25416
- }
25417
-
25418
- // src/hooks/magic-context/read-session-db.ts
25419
25794
  init_logger();
25420
- function getOpenCodeDbPath() {
25795
+ function getOpenCodeDbPath2() {
25421
25796
  return join8(getDataDir(), "opencode", "opencode.db");
25422
25797
  }
25423
25798
  var cachedReadOnlyDb = null;
@@ -25434,12 +25809,12 @@ function closeCachedReadOnlyDb() {
25434
25809
  }
25435
25810
  }
25436
25811
  function getReadOnlySessionDb() {
25437
- const dbPath = getOpenCodeDbPath();
25812
+ const dbPath = getOpenCodeDbPath2();
25438
25813
  if (cachedReadOnlyDb?.path === dbPath) {
25439
25814
  return cachedReadOnlyDb.db;
25440
25815
  }
25441
25816
  closeCachedReadOnlyDb();
25442
- const db = new Database(dbPath, { readonly: true });
25817
+ const db = new Database2(dbPath, { readonly: true });
25443
25818
  cachedReadOnlyDb = { path: dbPath, db };
25444
25819
  return db;
25445
25820
  }
@@ -25992,7 +26367,7 @@ function ensureMessagesIndexed(db, sessionId, readMessages) {
25992
26367
  })();
25993
26368
  }
25994
26369
  // src/features/magic-context/storage-db.ts
25995
- import { Database as Database2 } from "bun:sqlite";
26370
+ import { Database as Database3 } from "bun:sqlite";
25996
26371
  import { mkdirSync } from "fs";
25997
26372
  import { join as join9 } from "path";
25998
26373
  init_logger();
@@ -26428,6 +26803,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
26428
26803
  ensureColumn(db, "tags", "reasoning_byte_size", "INTEGER DEFAULT 0");
26429
26804
  ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
26430
26805
  ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
26806
+ ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
26431
26807
  }
26432
26808
  function ensureColumn(db, table, column, definition) {
26433
26809
  if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'(),\s]+$/i.test(definition)) {
@@ -26441,7 +26817,7 @@ function ensureColumn(db, table, column, definition) {
26441
26817
  }
26442
26818
  function createFallbackDatabase() {
26443
26819
  try {
26444
- const fallback = new Database2(":memory:");
26820
+ const fallback = new Database3(":memory:");
26445
26821
  initializeDatabase(fallback);
26446
26822
  runMigrations(fallback);
26447
26823
  return fallback;
@@ -26460,7 +26836,7 @@ function openDatabase() {
26460
26836
  return existing;
26461
26837
  }
26462
26838
  mkdirSync(dbDir, { recursive: true });
26463
- const db = new Database2(dbPath);
26839
+ const db = new Database3(dbPath);
26464
26840
  initializeDatabase(db);
26465
26841
  runMigrations(db);
26466
26842
  databases.set(dbPath, db);
@@ -27012,7 +27388,8 @@ function startDreamScheduleTimer(args) {
27012
27388
  dreamerConfig,
27013
27389
  embeddingConfig: embeddingConfig2,
27014
27390
  memoryEnabled,
27015
- experimentalUserMemories
27391
+ experimentalUserMemories,
27392
+ experimentalPinKeyFiles
27016
27393
  } = args;
27017
27394
  const dreamingEnabled = Boolean(dreamerConfig?.enabled && dreamerConfig.schedule?.trim());
27018
27395
  const embeddingSweepEnabled = memoryEnabled && embeddingConfig2.provider !== "off";
@@ -27042,7 +27419,8 @@ function startDreamScheduleTimer(args) {
27042
27419
  tasks: dreamerConfig.tasks,
27043
27420
  taskTimeoutMinutes: dreamerConfig.task_timeout_minutes,
27044
27421
  maxRuntimeMinutes: dreamerConfig.max_runtime_minutes,
27045
- experimentalUserMemories
27422
+ experimentalUserMemories,
27423
+ experimentalPinKeyFiles
27046
27424
  }).catch((error48) => {
27047
27425
  log("[dreamer] timer-triggered queue processing failed:", error48);
27048
27426
  });
@@ -27841,7 +28219,8 @@ Dreaming is not configured for this project.`, {});
27841
28219
  tasks: deps.dreamer.config.tasks,
27842
28220
  taskTimeoutMinutes: deps.dreamer.config.task_timeout_minutes,
27843
28221
  maxRuntimeMinutes: deps.dreamer.config.max_runtime_minutes,
27844
- experimentalUserMemories: deps.dreamer.experimentalUserMemories
28222
+ experimentalUserMemories: deps.dreamer.experimentalUserMemories,
28223
+ experimentalPinKeyFiles: deps.dreamer.experimentalPinKeyFiles
27845
28224
  });
27846
28225
  await deps.sendNotification(sessionId, result ? summarizeDreamResult(result) : "Dream queued, but another worker is already processing the queue.", {});
27847
28226
  throw new Error(`${SENTINEL_PREFIX}CTX-DREAM_HANDLED__`);
@@ -27930,7 +28309,7 @@ Historian recomp started. Rebuilding compartments and facts from raw session his
27930
28309
  init_logger();
27931
28310
 
27932
28311
  // src/features/magic-context/compaction-marker.ts
27933
- import { Database as Database3 } from "bun:sqlite";
28312
+ import { Database as Database4 } from "bun:sqlite";
27934
28313
  import { join as join10 } from "path";
27935
28314
  init_logger();
27936
28315
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -27952,12 +28331,12 @@ function generateMessageId(timestampMs, counter = 0n) {
27952
28331
  function generatePartId(timestampMs, counter = 0n) {
27953
28332
  return generateId("prt", timestampMs, counter);
27954
28333
  }
27955
- function getOpenCodeDbPath2() {
28334
+ function getOpenCodeDbPath3() {
27956
28335
  return join10(getDataDir(), "opencode", "opencode.db");
27957
28336
  }
27958
28337
  var cachedWriteDb = null;
27959
28338
  function getWritableOpenCodeDb() {
27960
- const dbPath = getOpenCodeDbPath2();
28339
+ const dbPath = getOpenCodeDbPath3();
27961
28340
  if (cachedWriteDb?.path === dbPath) {
27962
28341
  return cachedWriteDb.db;
27963
28342
  }
@@ -27966,7 +28345,7 @@ function getWritableOpenCodeDb() {
27966
28345
  cachedWriteDb.db.close(false);
27967
28346
  } catch {}
27968
28347
  }
27969
- const db = new Database3(dbPath);
28348
+ const db = new Database4(dbPath);
27970
28349
  db.exec("PRAGMA journal_mode=WAL");
27971
28350
  db.exec("PRAGMA busy_timeout=5000");
27972
28351
  cachedWriteDb = { path: dbPath, db };
@@ -31965,8 +32344,8 @@ function createToolExecuteAfterHook(args) {
31965
32344
  }
31966
32345
 
31967
32346
  // src/hooks/magic-context/system-prompt-hash.ts
31968
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
31969
- import { join as join12 } from "path";
32347
+ import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync } from "fs";
32348
+ import { join as join12, resolve as resolve2, sep } from "path";
31970
32349
 
31971
32350
  // src/agents/magic-context-prompt.ts
31972
32351
  var BASE_INTRO = (protectedTags) => `Messages and tool outputs are tagged with \xA7N\xA7 identifiers (e.g., \xA71\xA7, \xA742\xA7).
@@ -32168,7 +32547,9 @@ init_logger();
32168
32547
  var MAGIC_CONTEXT_MARKER = "## Magic Context";
32169
32548
  var PROJECT_DOCS_MARKER = "<project-docs>";
32170
32549
  var USER_PROFILE_MARKER = "<user-profile>";
32550
+ var KEY_FILES_MARKER = "<key-files>";
32171
32551
  var cachedUserProfileBySession = new Map;
32552
+ var cachedKeyFilesBySession = new Map;
32172
32553
  var DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
32173
32554
  function readProjectDocs(directory) {
32174
32555
  const sections = [];
@@ -32250,6 +32631,72 @@ ${items}
32250
32631
  output.system.push(profileBlock);
32251
32632
  }
32252
32633
  }
32634
+ if (deps.experimentalPinKeyFiles) {
32635
+ const hasCachedKeyFiles = cachedKeyFilesBySession.has(sessionId);
32636
+ if (!hasCachedKeyFiles || isCacheBusting) {
32637
+ const keyFileEntries = getKeyFiles(deps.db, sessionId);
32638
+ if (keyFileEntries.length > 0) {
32639
+ const sections = [];
32640
+ const projectRoot = resolve2(deps.directory);
32641
+ let remainingBudgetTokens = deps.experimentalPinKeyFilesTokenBudget ?? 1e4;
32642
+ for (const entry of keyFileEntries) {
32643
+ try {
32644
+ const absPath = resolve2(deps.directory, entry.filePath);
32645
+ if (!absPath.startsWith(projectRoot + sep) && absPath !== projectRoot) {
32646
+ log(`[magic-context] key file path escapes project root, skipping: ${entry.filePath}`);
32647
+ continue;
32648
+ }
32649
+ if (!existsSync5(absPath))
32650
+ continue;
32651
+ let realPath;
32652
+ try {
32653
+ realPath = realpathSync(absPath);
32654
+ } catch {
32655
+ continue;
32656
+ }
32657
+ if (!realPath.startsWith(projectRoot + sep) && realPath !== projectRoot) {
32658
+ log(`[magic-context] key file symlink escapes project root, skipping: ${entry.filePath} \u2192 ${realPath}`);
32659
+ continue;
32660
+ }
32661
+ const content = readFileSync4(realPath, "utf-8").trim();
32662
+ if (content.length === 0)
32663
+ continue;
32664
+ const fileTokens = estimateTokens(content);
32665
+ if (fileTokens > remainingBudgetTokens) {
32666
+ log(`[magic-context] key file ${entry.filePath} exceeds remaining budget (${fileTokens} > ${remainingBudgetTokens}), skipping`);
32667
+ continue;
32668
+ }
32669
+ remainingBudgetTokens -= fileTokens;
32670
+ sections.push(`<file path="${escapeXmlAttr(entry.filePath)}">
32671
+ ${escapeXmlContent(content)}
32672
+ </file>`);
32673
+ } catch (error48) {
32674
+ log(`[magic-context] failed to read key file ${entry.filePath}:`, error48);
32675
+ }
32676
+ }
32677
+ if (sections.length > 0) {
32678
+ cachedKeyFilesBySession.set(sessionId, `${KEY_FILES_MARKER}
32679
+ ${sections.join(`
32680
+
32681
+ `)}
32682
+ </key-files>`);
32683
+ if (!hasCachedKeyFiles) {
32684
+ sessionLog(sessionId, `loaded ${sections.length} key file(s) into system prompt`);
32685
+ } else {
32686
+ sessionLog(sessionId, "refreshed key files (cache-busting pass)");
32687
+ }
32688
+ } else {
32689
+ cachedKeyFilesBySession.set(sessionId, null);
32690
+ }
32691
+ } else {
32692
+ cachedKeyFilesBySession.set(sessionId, null);
32693
+ }
32694
+ }
32695
+ const keyFilesBlock = cachedKeyFilesBySession.get(sessionId);
32696
+ if (keyFilesBlock && !fullPrompt.includes(KEY_FILES_MARKER)) {
32697
+ output.system.push(keyFilesBlock);
32698
+ }
32699
+ }
32253
32700
  const DATE_PATTERN = /Today's date: .+/;
32254
32701
  for (let i = 0;i < output.system.length; i++) {
32255
32702
  const match = output.system[i].match(DATE_PATTERN);
@@ -32290,7 +32737,7 @@ ${items}
32290
32737
  } else if (previousHash === "" || previousHash === "0") {
32291
32738
  sessionLog(sessionId, `system prompt hash initialized: ${currentHash} (len=${systemContent.length})`);
32292
32739
  }
32293
- const systemPromptTokens = Math.ceil(systemContent.length / 4);
32740
+ const systemPromptTokens = estimateTokens(systemContent);
32294
32741
  if (currentHash !== previousHash) {
32295
32742
  updateSessionMeta(deps.db, sessionId, {
32296
32743
  systemPromptHash: currentHash,
@@ -32424,6 +32871,11 @@ function createMagicContextHook(deps) {
32424
32871
  experimentalUserMemories: deps.config.experimental?.user_memories?.enabled ? {
32425
32872
  enabled: true,
32426
32873
  promotionThreshold: deps.config.experimental.user_memories?.promotion_threshold
32874
+ } : undefined,
32875
+ experimentalPinKeyFiles: deps.config.experimental?.pin_key_files?.enabled ? {
32876
+ enabled: true,
32877
+ token_budget: deps.config.experimental.pin_key_files?.token_budget,
32878
+ min_reads: deps.config.experimental.pin_key_files?.min_reads
32427
32879
  } : undefined
32428
32880
  }).catch((error48) => {
32429
32881
  log("[dreamer] scheduled queue processing failed:", error48);
@@ -32470,6 +32922,11 @@ function createMagicContextHook(deps) {
32470
32922
  experimentalUserMemories: deps.config.experimental?.user_memories?.enabled ? {
32471
32923
  enabled: true,
32472
32924
  promotionThreshold: deps.config.experimental.user_memories?.promotion_threshold
32925
+ } : undefined,
32926
+ experimentalPinKeyFiles: deps.config.experimental?.pin_key_files?.enabled ? {
32927
+ enabled: true,
32928
+ token_budget: deps.config.experimental.pin_key_files?.token_budget,
32929
+ min_reads: deps.config.experimental.pin_key_files?.min_reads
32473
32930
  } : undefined
32474
32931
  } : undefined
32475
32932
  });
@@ -32483,7 +32940,9 @@ function createMagicContextHook(deps) {
32483
32940
  directory: deps.directory,
32484
32941
  flushedSessions,
32485
32942
  lastHeuristicsTurnId,
32486
- experimentalUserMemories: deps.config.experimental?.user_memories?.enabled
32943
+ experimentalUserMemories: deps.config.experimental?.user_memories?.enabled,
32944
+ experimentalPinKeyFiles: deps.config.experimental?.pin_key_files?.enabled ?? false,
32945
+ experimentalPinKeyFilesTokenBudget: deps.config.experimental?.pin_key_files?.token_budget
32487
32946
  });
32488
32947
  const eventHook = createEventHook({
32489
32948
  eventHandler,
@@ -32962,15 +33421,17 @@ Historian reads these notes, deduplicates them, and rewrites the remaining usefu
32962
33421
  import { tool as tool3 } from "@opencode-ai/plugin";
32963
33422
  function formatNoteLine(note) {
32964
33423
  const statusSuffix = note.status === "active" ? "" : ` (${note.status})`;
32965
- const dismissHint = note.status === "dismissed" ? "" : ` _(dismiss with \`ctx_note(action="dismiss", note_id=${note.id})\`)_`;
32966
33424
  if (note.type === "session") {
32967
- return `- **#${note.id}**${statusSuffix}: ${note.content}${dismissHint}`;
33425
+ return `- **#${note.id}**${statusSuffix}: ${note.content}`;
32968
33426
  }
32969
33427
  const conditionText = note.status === "ready" ? note.readyReason ?? note.surfaceCondition ?? "Condition satisfied" : note.surfaceCondition ?? "No condition recorded";
32970
33428
  const conditionLabel = note.status === "ready" ? "Condition met" : "Condition";
32971
33429
  return `- **#${note.id}**${statusSuffix}: ${note.content}
32972
- ${conditionLabel}: ${conditionText}${dismissHint}`;
33430
+ ${conditionLabel}: ${conditionText}`;
32973
33431
  }
33432
+ var DISMISS_FOOTER = `
33433
+
33434
+ To dismiss a stale note: ctx_note(action="dismiss", note_id=N)`;
32974
33435
  function buildReadSections(args) {
32975
33436
  if (args.filter === undefined) {
32976
33437
  const sessionNotes2 = getSessionNotes(args.db, args.sessionId);
@@ -33109,7 +33570,7 @@ No session notes or smart notes.`;
33109
33570
  }
33110
33571
  return sections.join(`
33111
33572
 
33112
- `);
33573
+ `) + DISMISS_FOOTER;
33113
33574
  }
33114
33575
  });
33115
33576
  }
@@ -33880,6 +34341,11 @@ var plugin = async (ctx) => {
33880
34341
  experimentalUserMemories: pluginConfig.experimental?.user_memories?.enabled ? {
33881
34342
  enabled: true,
33882
34343
  promotionThreshold: pluginConfig.experimental.user_memories?.promotion_threshold
34344
+ } : undefined,
34345
+ experimentalPinKeyFiles: pluginConfig.experimental?.pin_key_files?.enabled ? {
34346
+ enabled: true,
34347
+ token_budget: pluginConfig.experimental.pin_key_files?.token_budget,
34348
+ min_reads: pluginConfig.experimental.pin_key_files?.min_reads
33883
34349
  } : undefined
33884
34350
  });
33885
34351
  startTuiActionConsumer({
@@ -17,5 +17,10 @@ export declare function startDreamScheduleTimer(args: {
17
17
  enabled: boolean;
18
18
  promotionThreshold: number;
19
19
  };
20
+ experimentalPinKeyFiles?: {
21
+ enabled: boolean;
22
+ token_budget: number;
23
+ min_reads: number;
24
+ };
20
25
  }): (() => void) | undefined;
21
26
  //# sourceMappingURL=dream-timer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dream-timer.d.ts","sourceRoot":"","sources":["../../src/plugin/dream-timer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAMrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAqE3B"}
1
+ {"version":3,"file":"dream-timer.d.ts","sourceRoot":"","sources":["../../src/plugin/dream-timer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAMrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uBAAuB,CAAC,EAAE;QACtB,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;CACL,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAuE3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C;;;;;;qBA4C+R,CAAC;;;;;;;;;;;;qBATjR,CAAN;mBAAiB,CAAC;;;;;0BASwtW,CAAC;;;;;;EADpvW"}
1
+ {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C;;;;;;qBA4Cq4B,CAAC;;;;;;;;;;;;qBATv3B,CAAN;mBAAiB,CAAC;;;;;0BASwvY,CAAC;;;;;;EADpxY"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAchE,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAkND,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAIxF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAchE,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAgND,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAIxF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",
@@ -272,7 +272,7 @@ export function loadSidebarSnapshot(sessionId: string, directory: string): Sideb
272
272
  for (const c of compRows) {
273
273
  compartmentTokens += Math.ceil(
274
274
  `<compartment start="${c.start_message}" end="${c.end_message}" title="${c.title}">\n${c.content}\n</compartment>\n`
275
- .length / 4,
275
+ .length / 3.5,
276
276
  );
277
277
  }
278
278
  } catch {
@@ -285,7 +285,7 @@ export function loadSidebarSnapshot(sessionId: string, directory: string): Sideb
285
285
  )
286
286
  .all(sessionId);
287
287
  for (const f of factRows) {
288
- factTokens += Math.ceil(`* ${f.content}\n`.length / 4);
288
+ factTokens += Math.ceil(`* ${f.content}\n`.length / 3.5);
289
289
  }
290
290
  } catch {
291
291
  /* session_facts table may not exist */
@@ -294,7 +294,7 @@ export function loadSidebarSnapshot(sessionId: string, directory: string): Sideb
294
294
  if (meta) {
295
295
  const cached = (meta as Record<string, unknown>).memory_block_cache;
296
296
  if (typeof cached === "string" && cached.length > 0) {
297
- memoryTokens = Math.ceil(cached.length / 4);
297
+ memoryTokens = Math.ceil(cached.length / 3.5);
298
298
  }
299
299
  }
300
300
 
@@ -514,14 +514,14 @@ export function loadStatusDetail(
514
514
 
515
515
  let histTokens = 0;
516
516
  for (const c of compartments) {
517
- // ~4 chars per token estimate (same as plugin's estimateTokens)
517
+ // ~3.5 chars per token estimate (matches plugin's estimateTokens)
518
518
  histTokens += Math.ceil(
519
519
  `<compartment start="${c.start_message}" end="${c.end_message}" title="${c.title}">\n${c.content}\n</compartment>\n`
520
- .length / 4,
520
+ .length / 3.5,
521
521
  );
522
522
  }
523
523
  for (const f of facts) {
524
- histTokens += Math.ceil(`* ${f.content}\n`.length / 4);
524
+ histTokens += Math.ceil(`* ${f.content}\n`.length / 3.5);
525
525
  }
526
526
  detail.historyBlockTokens = histTokens;
527
527