@cortexkit/opencode-magic-context 0.49.23 → 0.49.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +0 -26
  2. package/dist/agents/permissions.d.ts +8 -3
  3. package/dist/agents/permissions.d.ts.map +1 -1
  4. package/dist/auto-search-worker.js +4 -4
  5. package/dist/chunk-embedding-write-worker.js +5 -5
  6. package/dist/{compartment-chunk-embedding-he60aaa2.js → compartment-chunk-embedding-eypvn607.js} +3 -3
  7. package/dist/{conflict-warning-hook-2r32hyx6.js → conflict-warning-hook-a27bhggg.js} +4 -4
  8. package/dist/{context-j7hp43a0.js → context-keb00be8.js} +30 -24
  9. package/dist/{embedding-backfill-dtke6tck.js → embedding-backfill-vddgmem3.js} +5 -5
  10. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -1
  11. package/dist/features/magic-context/tool-definition-tokens.d.ts +113 -57
  12. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  13. package/dist/hooks/magic-context/ask-answer-notice.d.ts +25 -0
  14. package/dist/hooks/magic-context/ask-answer-notice.d.ts.map +1 -0
  15. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +1 -1
  16. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  17. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +12 -4
  18. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
  21. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  22. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +8 -0
  24. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  26. package/dist/hooks/magic-context/read-session-raw.d.ts +10 -0
  27. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  28. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts +42 -0
  30. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts.map +1 -0
  31. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  32. package/dist/{index-y76rhsnr.js → index-0s8454t2.js} +50 -31
  33. package/dist/{index-1gtfne2c.js → index-2haxh8h3.js} +1 -1
  34. package/dist/{index-m32esgmj.js → index-3d5wnkq7.js} +1 -1
  35. package/dist/{index-jfem3dgz.js → index-7tdtpqrg.js} +5 -1
  36. package/dist/{index-mnnkgq0q.js → index-awcftgmx.js} +7 -49
  37. package/dist/{index-1kbznkft.js → index-axjgxeww.js} +10 -8
  38. package/dist/{index-j32jj2t8.js → index-bhyksfyy.js} +3 -3
  39. package/dist/{index-ksq50rg0.js → index-c9zrgcnt.js} +1 -1
  40. package/dist/index-cfaet9cg.js +405 -0
  41. package/dist/{index-jmq8kfe7.js → index-ebsvmc5s.js} +4 -4
  42. package/dist/{index-66eby7hx.js → index-jcr6pe7z.js} +1 -1
  43. package/dist/{index-syaazvy2.js → index-n18sch77.js} +5 -5
  44. package/dist/{index-a9zvn5fe.js → index-q7ywt6xt.js} +3 -3
  45. package/dist/{index-x6cbrv9h.js → index-szf8r0ba.js} +1 -1
  46. package/dist/{index-rxqr723x.js → index-t6j3qxnd.js} +1 -1
  47. package/dist/{index-11gzxvf4.js → index-y6xpzjzr.js} +98 -48
  48. package/dist/{index-mnhcdfxg.js → index-yrrsp47d.js} +91 -17
  49. package/dist/{index-zy67whjr.js → index-z05n7702.js} +1 -1
  50. package/dist/{index-3svaejkh.js → index-z928hmnp.js} +1 -1
  51. package/dist/{index-ffzhwfzy.js → index-zzrzjnx5.js} +3 -3
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +43 -38
  54. package/dist/{message-fts-rowid-map-e79b7b6x.js → message-fts-rowid-map-9e1getgs.js} +2 -2
  55. package/dist/{message-index-4q8ek2fc.js → message-index-3g966xn7.js} +7 -7
  56. package/dist/{message-index-bounded-rydsg9r5.js → message-index-bounded-vaeqhp9w.js} +7 -7
  57. package/dist/migration-worker.js +4 -4
  58. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  59. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  60. package/dist/{project-embedding-registry-hn529988.js → project-embedding-registry-rstzmb60.js} +4 -4
  61. package/dist/raw-ordinal-warmup-worker.js +6 -6
  62. package/dist/{read-session-chunk-t039f0m5.js → read-session-chunk-z5gnc0zb.js} +4 -4
  63. package/dist/{read-session-raw-aw6jgvwg.js → read-session-raw-s4amywnh.js} +3 -1
  64. package/dist/{recomp-orchestrator-hbm53jj5.js → recomp-orchestrator-qwqeskhq.js} +14 -14
  65. package/dist/{search-hea079d7.js → search-84zfqeky.js} +11 -11
  66. package/dist/{search-archive-weh164mh.js → search-archive-mfabzyn2.js} +5 -5
  67. package/dist/{send-session-notification-gqzkz7da.js → send-session-notification-ygj4mja0.js} +3 -3
  68. package/dist/shared/slow-test.d.ts +7 -0
  69. package/dist/shared/slow-test.d.ts.map +1 -0
  70. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  71. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  72. package/dist/tools/parameter-descriptions.d.ts +6 -6
  73. package/dist/tools/parameter-descriptions.d.ts.map +1 -1
  74. package/dist/{transform-postprocess-phase-0b04tm1p.js → transform-postprocess-phase-hr1ntmjj.js} +14 -14
  75. package/dist/v2/auto-search-worker.js +4 -4
  76. package/dist/v2/chunk-embedding-write-worker.js +5 -5
  77. package/dist/v2/{compartment-chunk-embedding-8jjmcgeg.js → compartment-chunk-embedding-tk6g4q80.js} +3 -3
  78. package/dist/v2/{context-ea3x7smm.js → context-y7wfvdve.js} +106 -50
  79. package/dist/v2/{embedding-backfill-5e74ae0m.js → embedding-backfill-w5qp7t28.js} +5 -5
  80. package/dist/v2/hooks/context.d.ts +4 -0
  81. package/dist/v2/hooks/context.d.ts.map +1 -1
  82. package/dist/v2/{message-fts-rowid-map-n8fdg2ja.js → message-fts-rowid-map-pqk3a55v.js} +2 -2
  83. package/dist/v2/{message-index-bounded-8rcd7qq9.js → message-index-bounded-te303atj.js} +6 -6
  84. package/dist/v2/{message-index-qz9wdp82.js → message-index-fz6b4jeh.js} +6 -6
  85. package/dist/v2/migration-worker.js +4 -4
  86. package/dist/v2/{project-embedding-registry-v38q4xd5.js → project-embedding-registry-e7zftfvj.js} +4 -4
  87. package/dist/v2/raw-ordinal-warmup-worker.js +6 -6
  88. package/dist/v2/{read-session-chunk-wazfyxcg.js → read-session-chunk-knvkq1hf.js} +3 -3
  89. package/dist/v2/{read-session-raw-b70cpwzj.js → read-session-raw-ppjxnqk4.js} +3 -1
  90. package/dist/v2/{recomp-orchestrator-b12zaptj.js → recomp-orchestrator-e8a4jpvr.js} +11 -11
  91. package/dist/v2/{search-archive-x64rtz1z.js → search-archive-vrwgxv6z.js} +4 -4
  92. package/dist/v2/{search-hza9x72a.js → search-hav4dggf.js} +10 -10
  93. package/dist/v2/{send-session-notification-8eqe259v.js → send-session-notification-f8scq6ae.js} +1 -1
  94. package/dist/v2/{server-m4bfaevz.js → server-5brp2rfn.js} +90 -16
  95. package/dist/v2/{server-ppcd1qxh.js → server-6a8pxpxg.js} +7 -49
  96. package/dist/v2/server-7d6m1p2b.js +361 -0
  97. package/dist/v2/{server-zg5y109h.js → server-7weh65vd.js} +45 -27
  98. package/dist/v2/{server-qteg2kt9.js → server-8j2e7t31.js} +1 -1
  99. package/dist/v2/{server-d48x3m4x.js → server-9xbbaekh.js} +1 -1
  100. package/dist/v2/{server-j8h7bsca.js → server-e75vag9d.js} +3 -3
  101. package/dist/v2/{server-132h8twc.js → server-m6yyn961.js} +2 -2
  102. package/dist/v2/{server-62g58aaz.js → server-pw21ypwb.js} +1 -1
  103. package/dist/v2/{server-ad18djzs.js → server-q5z0gag0.js} +1 -1
  104. package/dist/v2/{server-4kjmrjn4.js → server-swvhxhxz.js} +5 -1
  105. package/dist/v2/{server-33nqbqkw.js → server-tfawsj08.js} +5 -5
  106. package/dist/v2/{server-dtp8hcjh.js → server-wxrdher8.js} +1 -1
  107. package/dist/v2/server.js +5 -5
  108. package/dist/v2/{wrapup-orchestrator-3ssd5yy1.js → wrapup-orchestrator-ycs8y6n4.js} +11 -11
  109. package/dist/{wrapup-orchestrator-5vpcd1zx.js → wrapup-orchestrator-f642w8n3.js} +15 -15
  110. package/package.json +4 -4
  111. package/src/agents/permissions.ts +22 -6
  112. package/src/agents/smart-notes-dreamer-gate.golden.json +241 -241
  113. package/src/agents/smart-notes-on.golden.json +4 -4
  114. package/src/config/compaction-accessor-guard.test.ts +0 -5
  115. package/src/config/removed-config-keys.test.ts +12 -26
  116. package/src/shared/announcement.test.ts +55 -59
  117. package/src/shared/prompt-surface-a1-golden.md +6 -7
  118. package/src/shared/slow-test.ts +24 -0
  119. package/src/shared/stable-json-linear.test.ts +18 -10
  120. package/dist/index-j76ah6d7.js +0 -120
  121. package/dist/v2/server-d1dzgvwd.js +0 -120
  122. package/src/config/latch-permanence-guard.test.ts +0 -258
@@ -1,6 +1,6 @@
1
1
  {
2
- "opencode/full": "ee8313665a36e94be315b564c3959c21644c6b13a6e80de86aff8492a7948248",
3
- "pi/full": "06d5cdfa5922dc889f8924e40ed60a76055b6f008614f552c11249dbba7ccf32",
2
+ "opencode/full": "240b4eddfc4ec9a27bda24e44e2b94fd3df558212e2d49999ae2852fa96d206f",
3
+ "pi/full": "1b513f1dcd873c496f71d4df7f23d9ae5adeea55f69381e9c8ad86c7c1e76f9d",
4
4
  "guidance/full/false/false/false/false": "5fd6f9d5ceadc9afb6c2e5f6f1359ee0fb51d03afa17d002a503a9958941fa84",
5
5
  "pi-guidance/full/false/false/false/false": "5fd6f9d5ceadc9afb6c2e5f6f1359ee0fb51d03afa17d002a503a9958941fa84",
6
6
  "guidance/full/false/false/false/true": "c07904e2985b91a3bfec547cbd3e6aa3b6eee9e2d0fed49df2aa701bbc927998",
@@ -33,8 +33,8 @@
33
33
  "pi-guidance/full/true/true/true/false": "77aaa97847d1cf96b947664a48656cb32ae9c0354882746c2e9961785acc5ce3",
34
34
  "guidance/full/true/true/true/true": "224fe7ba3904c53b0fa22d079ec7cb7c4a132d8092dade80a86c44d56f588831",
35
35
  "pi-guidance/full/true/true/true/true": "224fe7ba3904c53b0fa22d079ec7cb7c4a132d8092dade80a86c44d56f588831",
36
- "opencode/light": "203313946dd10c99b0e8ae9ddd47bd3f5d7568d6571eb189babb7cb59ef6a2f0",
37
- "pi/light": "2ab9c355546c723f51df122a04d325ab7e0c700078c30e44452a5eee3d7e37ee",
36
+ "opencode/light": "c7af178d40ac2ddaf4b91d5aab75a216b5d76cb335dad924c05af75d0f4f76c5",
37
+ "pi/light": "d80cf09b6fa563f20f31e535dbb2b32253f6f978bcbffdacacba6a70865455f3",
38
38
  "guidance/light/false/false/false/false": "a8713eda6b4d8888f584a9740b69b72c57f1cdff04bc675844c1caa0c95557d7",
39
39
  "pi-guidance/light/false/false/false/false": "a8713eda6b4d8888f584a9740b69b72c57f1cdff04bc675844c1caa0c95557d7",
40
40
  "guidance/light/false/false/false/true": "7a99730b51c8dd094d052288bb54f9d1b2563ade3cbfafa190496b6fe18e461c",
@@ -74,11 +74,6 @@ describe("compaction.enabled accessor exclusivity (issue #266)", () => {
74
74
  expect(offenders).toEqual([]);
75
75
  });
76
76
 
77
- it("isCompactionEnabled is exported from the accessor module", async () => {
78
- const mod = await import("../config/agent-disable");
79
- expect(typeof mod.isCompactionEnabled).toBe("function");
80
- });
81
-
82
77
  it("isCompactionEnabled resolves default-on for absent block and explicit true, off for false", async () => {
83
78
  const { isCompactionEnabled } = await import("../config/agent-disable");
84
79
  expect(isCompactionEnabled({})).toBe(true);
@@ -37,12 +37,7 @@ const FORBIDDEN = [
37
37
  const ALLOWED_BASENAMES = new Set<string>([]);
38
38
 
39
39
  function walkSourceFiles(dir: string, out: string[] = []): string[] {
40
- let entries: string[];
41
- try {
42
- entries = readdirSync(dir);
43
- } catch {
44
- return out; // package not present in this checkout
45
- }
40
+ const entries = readdirSync(dir);
46
41
  for (const entry of entries) {
47
42
  if (entry === "node_modules" || entry === "dist") continue;
48
43
  const full = join(dir, entry);
@@ -65,12 +60,7 @@ function walkSourceFiles(dir: string, out: string[] = []): string[] {
65
60
  function scanForForbidden(files: string[]): string[] {
66
61
  const offenders: string[] = [];
67
62
  for (const file of files) {
68
- let text: string;
69
- try {
70
- text = readFileSync(file, "utf-8");
71
- } catch {
72
- continue; // file absent in this checkout
73
- }
63
+ const text = readFileSync(file, "utf-8");
74
64
  for (const key of FORBIDDEN) {
75
65
  if (text.includes(key)) offenders.push(`${file}: ${key}`);
76
66
  }
@@ -82,7 +72,11 @@ const REPO_ROOT = join(__dirname, "..", "..", "..", "..");
82
72
 
83
73
  describe("removed Phase 2 config keys", () => {
84
74
  it("no production source references auto_drop_tool_age / drop_tool_structure", () => {
85
- const files = [...walkSourceFiles(PLUGIN_SRC), ...walkSourceFiles(PI_SRC)];
75
+ const files = [PLUGIN_SRC, PI_SRC].flatMap((root) => {
76
+ const found = walkSourceFiles(root);
77
+ expect(found).toContain(join(root, "index.ts"));
78
+ return found;
79
+ });
86
80
  expect(scanForForbidden(files)).toEqual([]);
87
81
  });
88
82
 
@@ -96,21 +90,13 @@ describe("removed Phase 2 config keys", () => {
96
90
  join(REPO_ROOT, "README.md"),
97
91
  join(REPO_ROOT, "assets", "magic-context.schema.json"),
98
92
  ];
99
- const e2eFiles = walkSourceFiles(join(REPO_ROOT, "packages", "e2e-tests", "tests")).filter(
100
- // e2e tests are the consumer surface here, not unit tests of the
101
- // keys — scan them despite the .test.ts skip in walkSourceFiles.
102
- () => true,
103
- );
93
+ const e2eFiles = walkSourceFiles(join(REPO_ROOT, "packages", "e2e-tests", "tests"));
104
94
  // walkSourceFiles skips .test.ts, so collect e2e .test.ts explicitly.
105
95
  const e2eDir = join(REPO_ROOT, "packages", "e2e-tests", "tests");
106
- let e2eEntries: string[] = [];
107
- try {
108
- e2eEntries = readdirSync(e2eDir)
109
- .filter((f) => f.endsWith(".ts"))
110
- .map((f) => join(e2eDir, f));
111
- } catch {
112
- e2eEntries = [];
113
- }
96
+ const e2eEntries = readdirSync(e2eDir)
97
+ .filter((f) => f.endsWith(".ts"))
98
+ .map((f) => join(e2eDir, f));
99
+ expect(e2eEntries.length).toBeGreaterThan(0);
114
100
  expect(scanForForbidden([...docFiles, ...e2eFiles, ...e2eEntries])).toEqual([]);
115
101
  });
116
102
  });
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
2
  import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
+ import { pathToFileURL } from "node:url";
5
6
  import { createTestTempDirFromPath } from "./test-temp-dir";
6
7
 
7
8
  /**
@@ -22,6 +23,34 @@ import { createTestTempDirFromPath } from "./test-temp-dir";
22
23
 
23
24
  let tmpRoot = "";
24
25
  let originalXdg: string | undefined;
26
+ let fixtureCounter = 0;
27
+ let fixturePath = "";
28
+
29
+ async function loadAnnouncement(version = "1.2.3", features = ["Fixture announcement"]) {
30
+ // Load the real gate with pinned release content, without a process-global module mock.
31
+ const source = fs.readFileSync(path.join(import.meta.dir, "announcement.ts"), "utf8");
32
+ const pinned = source
33
+ .replace(
34
+ /export const ANNOUNCEMENT_VERSION = .*?;/s,
35
+ `export const ANNOUNCEMENT_VERSION = ${JSON.stringify(version)};`,
36
+ )
37
+ .replace(
38
+ /export const ANNOUNCEMENT_FEATURES: ReadonlyArray<string> = \[[\s\S]*?\];/,
39
+ `export const ANNOUNCEMENT_FEATURES: ReadonlyArray<string> = ${JSON.stringify(features)};`,
40
+ )
41
+ .replace(
42
+ /from "(\.[^"]+)"/g,
43
+ (_, specifier) => `from ${JSON.stringify(path.resolve(import.meta.dir, specifier))}`,
44
+ );
45
+ const scratch = path.resolve(import.meta.dir, "../../../../target/scratch");
46
+ fs.mkdirSync(scratch, { recursive: true });
47
+ fixturePath = path.join(scratch, `announcement-${process.pid}-${fixtureCounter++}.ts`);
48
+ fs.writeFileSync(fixturePath, pinned);
49
+ const mod = (await import(pathToFileURL(fixturePath).href)) as typeof import("./announcement");
50
+ expect(mod.ANNOUNCEMENT_VERSION).toBe(version);
51
+ expect(mod.ANNOUNCEMENT_FEATURES).toEqual(features);
52
+ return mod;
53
+ }
25
54
 
26
55
  beforeEach(() => {
27
56
  tmpRoot = createTestTempDirFromPath(path.join(os.tmpdir(), "mc-announcement-test-"));
@@ -30,6 +59,7 @@ beforeEach(() => {
30
59
  });
31
60
 
32
61
  afterEach(() => {
62
+ if (fixturePath) fs.rmSync(fixturePath, { force: true });
33
63
  if (originalXdg === undefined) {
34
64
  delete process.env.XDG_DATA_HOME;
35
65
  } else {
@@ -46,7 +76,7 @@ afterEach(() => {
46
76
  describe("announcement state persistence", () => {
47
77
  test("round-trips a dismissed version through the file", async () => {
48
78
  // Fresh import after XDG override so the module captures the temp path
49
- const mod = await import(`./announcement?t=${Date.now()}-rt`);
79
+ const mod = await loadAnnouncement();
50
80
  const { readLastAnnouncedVersion, markAnnouncementSeen } = mod;
51
81
 
52
82
  expect(readLastAnnouncedVersion()).toBe("");
@@ -59,7 +89,7 @@ describe("announcement state persistence", () => {
59
89
  });
60
90
 
61
91
  test("ignores empty / zero-length version marks", async () => {
62
- const mod = await import(`./announcement?t=${Date.now()}-empty`);
92
+ const mod = await loadAnnouncement();
63
93
  const { readLastAnnouncedVersion, markAnnouncementSeen } = mod;
64
94
 
65
95
  markAnnouncementSeen("");
@@ -67,7 +97,7 @@ describe("announcement state persistence", () => {
67
97
  });
68
98
 
69
99
  test("creates the storage directory if it does not exist", async () => {
70
- const mod = await import(`./announcement?t=${Date.now()}-mkdir`);
100
+ const mod = await loadAnnouncement();
71
101
  const { markAnnouncementSeen } = mod;
72
102
 
73
103
  // Storage dir lives under tmpRoot + cortexkit/magic-context — does not
@@ -84,7 +114,7 @@ describe("announcement state persistence", () => {
84
114
  });
85
115
 
86
116
  test("trims whitespace from stored version on read", async () => {
87
- const mod = await import(`./announcement?t=${Date.now()}-trim`);
117
+ const mod = await loadAnnouncement();
88
118
  const { readLastAnnouncedVersion } = mod;
89
119
 
90
120
  const dir = path.join(tmpRoot, "cortexkit", "magic-context");
@@ -96,39 +126,28 @@ describe("announcement state persistence", () => {
96
126
  });
97
127
 
98
128
  describe("shouldShowAnnouncement gating", () => {
99
- test("returns false when the live version is already marked", async () => {
100
- const mod = await import(`./announcement?t=${Date.now()}-match`);
101
- const {
102
- ANNOUNCEMENT_VERSION,
103
- ANNOUNCEMENT_FEATURES,
104
- markAnnouncementSeen,
105
- shouldShowAnnouncement,
106
- } = mod;
107
-
108
- // Skip the test if announcements are currently disabled (empty constants)
109
- // — the gate's empty-input behavior is covered separately below.
110
- if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
111
- return;
129
+ test("empty release content does not announce or seed state", async () => {
130
+ for (const [version, features] of [
131
+ ["", ["Fixture"]],
132
+ ["1.2.3", []],
133
+ ] as const) {
134
+ const mod = await loadAnnouncement(version, [...features]);
135
+ expect(mod.shouldShowAnnouncement()).toBe(false);
136
+ expect(mod.readLastAnnouncedVersion()).toBe("");
137
+ fs.rmSync(fixturePath);
112
138
  }
139
+ });
140
+ test("returns false when the live version is already marked", async () => {
141
+ const mod = await loadAnnouncement();
142
+ const { ANNOUNCEMENT_VERSION, markAnnouncementSeen, shouldShowAnnouncement } = mod;
113
143
 
114
144
  markAnnouncementSeen(ANNOUNCEMENT_VERSION);
115
145
  expect(shouldShowAnnouncement()).toBe(false);
116
146
  });
117
147
 
118
148
  test("seeds state and returns false on first run / wiped sandbox (issue #99)", async () => {
119
- const mod = await import(`./announcement?t=${Date.now()}-none`);
120
- const {
121
- ANNOUNCEMENT_VERSION,
122
- ANNOUNCEMENT_FEATURES,
123
- shouldShowAnnouncement,
124
- readLastAnnouncedVersion,
125
- } = mod;
126
-
127
- if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
128
- // When empty, the gate is always false regardless of state
129
- expect(shouldShowAnnouncement()).toBe(false);
130
- return;
131
- }
149
+ const mod = await loadAnnouncement();
150
+ const { ANNOUNCEMENT_VERSION, shouldShowAnnouncement, readLastAnnouncedVersion } = mod;
132
151
 
133
152
  // No mark exists yet (fresh install or ephemeral/wiped sandbox). The
134
153
  // gate must NOT announce — it seeds the state to the current version and
@@ -142,13 +161,8 @@ describe("shouldShowAnnouncement gating", () => {
142
161
  });
143
162
 
144
163
  test("does not seed or advance state when an existing state file is unreadable/corrupt", async () => {
145
- const mod = await import(`./announcement?t=${Date.now()}-corrupt`);
146
- const { ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, shouldShowAnnouncement } = mod;
147
-
148
- if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
149
- expect(shouldShowAnnouncement()).toBe(false);
150
- return;
151
- }
164
+ const mod = await loadAnnouncement();
165
+ const { shouldShowAnnouncement } = mod;
152
166
 
153
167
  const dir = path.join(tmpRoot, "cortexkit", "magic-context");
154
168
  const file = path.join(dir, "last_announced_version");
@@ -160,34 +174,16 @@ describe("shouldShowAnnouncement gating", () => {
160
174
  });
161
175
 
162
176
  test("returns true when a different (older) version is marked", async () => {
163
- const mod = await import(`./announcement?t=${Date.now()}-older`);
164
- const {
165
- ANNOUNCEMENT_VERSION,
166
- ANNOUNCEMENT_FEATURES,
167
- markAnnouncementSeen,
168
- shouldShowAnnouncement,
169
- } = mod;
170
-
171
- if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
172
- return;
173
- }
177
+ const mod = await loadAnnouncement();
178
+ const { markAnnouncementSeen, shouldShowAnnouncement } = mod;
174
179
 
175
180
  markAnnouncementSeen("0.0.0-pre-historic");
176
181
  expect(shouldShowAnnouncement()).toBe(true);
177
182
  });
178
183
 
179
184
  test("does NOT re-announce on a downgrade (stored version is newer)", async () => {
180
- const mod = await import(`./announcement?t=${Date.now()}-downgrade`);
181
- const {
182
- ANNOUNCEMENT_VERSION,
183
- ANNOUNCEMENT_FEATURES,
184
- markAnnouncementSeen,
185
- shouldShowAnnouncement,
186
- } = mod;
187
-
188
- if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
189
- return;
190
- }
185
+ const mod = await loadAnnouncement();
186
+ const { markAnnouncementSeen, shouldShowAnnouncement } = mod;
191
187
 
192
188
  // Stored version is far newer than the running binary (user downgraded).
193
189
  // A bare string-inequality gate would re-show the OLD announcement; the
@@ -1,6 +1,6 @@
1
1
  # Magic Context agent-facing surface (exported from source)
2
2
 
3
- Generated by `packages/plugin/scripts/export-agent-surface.ts` at 2026-09-30.
3
+ Generated by `packages/plugin/scripts/export-agent-surface.ts` at 2026-10-26.
4
4
  Token counts are Claude BPE estimates on the raw text.
5
5
 
6
6
  ## 1. System-prompt guidance section
@@ -201,7 +201,7 @@ Finer recovery:
201
201
  }
202
202
  ```
203
203
 
204
- ### ctx_note — description ~376 tokens, params ~303 tokens (total ~679)
204
+ ### ctx_note — description ~376 tokens, params ~296 tokens (total ~672)
205
205
 
206
206
  **Description:**
207
207
 
@@ -229,7 +229,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
229
229
  ```json
230
230
  {
231
231
  "action": {
232
- "description": "write | read | update | dismiss. Defaults to write when content is given, else read.",
232
+ "description": "write | read | update | dismiss.",
233
233
  "type": "string",
234
234
  "enum": [
235
235
  "write",
@@ -266,8 +266,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
266
266
  "type": "number"
267
267
  },
268
268
  "note_ids": {
269
- "description": "Note ids: one for update, 1–50 for dismiss or read (read returns full bodies). Ignored by write.",
270
- "minItems": 1,
269
+ "description": "Note ids: one for update, 1–50 for dismiss, or 1–50 to read those notes in full. Write and a plain read take an empty list.",
271
270
  "maxItems": 50,
272
271
  "type": "array",
273
272
  "items": {
@@ -279,7 +278,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
279
278
  }
280
279
  ```
281
280
 
282
- ### ctx_memory — description ~278 tokens, params ~172 tokens (total ~450)
281
+ ### ctx_memory — description ~278 tokens, params ~175 tokens (total ~453)
283
282
 
284
283
  **Description:**
285
284
 
@@ -317,7 +316,7 @@ Examples: category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/op
317
316
  "type": "string"
318
317
  },
319
318
  "category": {
320
- "description": "Kind of fact (required for write; on update/merge optional, omitted keeps the current category).",
319
+ "description": "Kind of fact (required for write; on update/merge, pass the memory's current category to keep it).",
321
320
  "type": "string",
322
321
  "enum": [
323
322
  "PROJECT_RULES",
@@ -0,0 +1,24 @@
1
+ import { test } from "bun:test";
2
+
3
+ export const slowLane = process.env.MC_SLOW_TESTS === "1";
4
+ export const slowPrefix = "[slow] ";
5
+
6
+ function register(name: string, run: () => void | Promise<void>, timeout: number) {
7
+ if (process.env.MC_SLOW_TEST_LIST === "1")
8
+ console.log(`SLOW_SELECTION ${JSON.stringify(name)}`);
9
+ test(name, run, timeout);
10
+ }
11
+
12
+ /** Run the same behavioral oracle at unit scale or at its full scheduled scale. */
13
+ export function scaleTest(
14
+ name: string,
15
+ run: (slow: boolean) => void | Promise<void>,
16
+ timeout = 30_000,
17
+ ) {
18
+ register(`${slowLane ? slowPrefix : ""}${name}`, () => run(slowLane), timeout);
19
+ }
20
+
21
+ /** Measurement calibration and production-duration sentinels have no fast substitute. */
22
+ export function slowOnlyTest(name: string, run: () => void | Promise<void>, timeout = 30_000) {
23
+ if (slowLane) register(`${slowPrefix}${name}`, run, timeout);
24
+ }
@@ -1,6 +1,7 @@
1
1
  /// <reference types="bun-types" />
2
2
 
3
3
  import { describe, expect, it } from "bun:test";
4
+ import { scaleTest } from "./slow-test";
4
5
  import { stableStringify } from "./stable-json";
5
6
 
6
7
  /** stableStringify as it was before it collected pieces: joins at every level. */
@@ -96,14 +97,21 @@ describe("stableStringify", () => {
96
97
  expect(holes).toBeGreaterThan(50);
97
98
  });
98
99
 
99
- it("copies a deeply nested value once, not once per level", () => {
100
- // 3,000 levels around a 2 MB string: joining at every level copied about
101
- // 6 GB of text (over a second); one copy takes a few milliseconds.
102
- let node: unknown = { body: "x".repeat(2_000_000) };
103
- for (let depth = 0; depth < 3_000; depth += 1) node = { child: node, depth };
104
- const started = performance.now();
105
- const text = stableStringify(node);
106
- expect(text.length).toBeGreaterThan(2_000_000);
107
- expect(performance.now() - started).toBeLessThan(300);
108
- }, 30_000);
100
+ scaleTest(
101
+ "copies a deeply nested value once, not once per level",
102
+ (slow) => {
103
+ // The slow fixture wraps 2 MB in 3,000 levels: joining at every level
104
+ // copied about 6 GB of text; the unit fixture retains nested-byte coverage.
105
+ const size = slow ? 2_000_000 : 4096;
106
+ let node: unknown = { body: "x".repeat(size) };
107
+ for (let depth = 0; depth < (slow ? 3_000 : 64); depth += 1)
108
+ node = { child: node, depth };
109
+ const started = performance.now();
110
+ const text = stableStringify(node);
111
+ expect(text.length).toBeGreaterThan(size);
112
+ expect(text).toContain("x".repeat(size));
113
+ if (slow) expect(performance.now() - started).toBeLessThan(300);
114
+ },
115
+ 30_000,
116
+ );
109
117
  });
@@ -1,120 +0,0 @@
1
- import {
2
- estimateTokens
3
- } from "./index-b88dwwrh.js";
4
- import {
5
- stableStringify
6
- } from "./index-x9k3mqrf.js";
7
-
8
- // src/features/magic-context/tool-definition-tokens.ts
9
- import { createHash } from "node:crypto";
10
- var measurements = new Map;
11
- var fingerprints = new Map;
12
- var persistenceDb = null;
13
- var cachedInsertStmt = null;
14
- function keyFor(providerID, modelID, agentName) {
15
- const agent = agentName && agentName.length > 0 ? agentName : "default";
16
- return `${providerID}/${modelID}/${agent}`;
17
- }
18
- function fingerprintFor(description, parameters) {
19
- return createHash("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
20
- }
21
- function getCurrentToolSetHash(providerID, modelID, agentName) {
22
- if (!providerID || !modelID)
23
- return "";
24
- const toolIds = measurements.get(keyFor(providerID, modelID, agentName));
25
- if (!toolIds || toolIds.size === 0)
26
- return "";
27
- return createHash("sha256").update(Array.from(toolIds.keys()).sort().join("\x00")).digest("hex");
28
- }
29
- function getToolDefinitionMeasurementSignature(providerID, modelID, agentName) {
30
- const key = keyFor(providerID, modelID, agentName);
31
- const measured = measurements.get(key);
32
- const observed = fingerprints.get(key);
33
- if (!measured || !observed || [...measured.keys()].some((id) => !observed.has(id)))
34
- return;
35
- return createHash("sha256").update(JSON.stringify([...measured.keys()].sort().map((id) => [id, observed.get(id)]))).digest("hex");
36
- }
37
- function setDatabase(db) {
38
- persistenceDb = db;
39
- cachedInsertStmt = null;
40
- }
41
- function loadToolDefinitionMeasurements(db) {
42
- let rows = [];
43
- try {
44
- rows = db.prepare("SELECT provider_id, model_id, agent_name, tool_id, token_count FROM tool_definition_measurements").all();
45
- } catch {
46
- return;
47
- }
48
- for (const row of rows) {
49
- const key = keyFor(row.provider_id, row.model_id, row.agent_name);
50
- let inner = measurements.get(key);
51
- if (!inner) {
52
- inner = new Map;
53
- measurements.set(key, inner);
54
- }
55
- inner.set(row.tool_id, row.token_count);
56
- }
57
- }
58
- function recordToolDefinition(providerID, modelID, agentName, toolID, description, parameters) {
59
- if (!providerID || !modelID || !toolID)
60
- return;
61
- const key = keyFor(providerID, modelID, agentName);
62
- const fp = fingerprintFor(description ?? "", parameters);
63
- let innerFp = fingerprints.get(key);
64
- if (innerFp && innerFp.get(toolID) === fp)
65
- return;
66
- let paramsText = "";
67
- try {
68
- paramsText = parameters === undefined ? "" : JSON.stringify(parameters);
69
- } catch {
70
- paramsText = "";
71
- }
72
- const tokens = estimateTokens(description ?? "") + estimateTokens(paramsText);
73
- let inner = measurements.get(key);
74
- if (!inner) {
75
- inner = new Map;
76
- measurements.set(key, inner);
77
- }
78
- inner.set(toolID, tokens);
79
- if (!innerFp) {
80
- innerFp = new Map;
81
- fingerprints.set(key, innerFp);
82
- }
83
- innerFp.set(toolID, fp);
84
- if (persistenceDb) {
85
- try {
86
- const agent = agentName && agentName.length > 0 ? agentName : "default";
87
- if (!cachedInsertStmt) {
88
- cachedInsertStmt = persistenceDb.prepare(`INSERT OR REPLACE INTO tool_definition_measurements
89
- (provider_id, model_id, agent_name, tool_id, token_count, recorded_at)
90
- VALUES (?, ?, ?, ?, ?, ?)`);
91
- }
92
- cachedInsertStmt.run(providerID, modelID, agent, toolID, tokens, Date.now());
93
- } catch {
94
- cachedInsertStmt = null;
95
- }
96
- }
97
- }
98
- function getLargestMeasuredToolDefinitionTokens() {
99
- let largest = 0;
100
- for (const tools of measurements.values()) {
101
- let total = 0;
102
- for (const tokens of tools.values())
103
- total += tokens;
104
- largest = Math.max(largest, total);
105
- }
106
- return largest > 0 ? largest : undefined;
107
- }
108
- function getMeasuredToolDefinitionTokens(providerID, modelID, agentName) {
109
- if (!providerID || !modelID)
110
- return;
111
- const inner = measurements.get(keyFor(providerID, modelID, agentName));
112
- if (!inner || inner.size === 0)
113
- return;
114
- let total = 0;
115
- for (const tokens of inner.values())
116
- total += tokens;
117
- return total;
118
- }
119
-
120
- export { getCurrentToolSetHash, getToolDefinitionMeasurementSignature, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getLargestMeasuredToolDefinitionTokens, getMeasuredToolDefinitionTokens };
@@ -1,120 +0,0 @@
1
- import {
2
- estimateTokens
3
- } from "./server-3mz2qh5a.js";
4
- import {
5
- stableStringify
6
- } from "./server-rqebawx1.js";
7
-
8
- // src/features/magic-context/tool-definition-tokens.ts
9
- import { createHash } from "node:crypto";
10
- var measurements = new Map;
11
- var fingerprints = new Map;
12
- var persistenceDb = null;
13
- var cachedInsertStmt = null;
14
- function keyFor(providerID, modelID, agentName) {
15
- const agent = agentName && agentName.length > 0 ? agentName : "default";
16
- return `${providerID}/${modelID}/${agent}`;
17
- }
18
- function fingerprintFor(description, parameters) {
19
- return createHash("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
20
- }
21
- function getCurrentToolSetHash(providerID, modelID, agentName) {
22
- if (!providerID || !modelID)
23
- return "";
24
- const toolIds = measurements.get(keyFor(providerID, modelID, agentName));
25
- if (!toolIds || toolIds.size === 0)
26
- return "";
27
- return createHash("sha256").update(Array.from(toolIds.keys()).sort().join("\x00")).digest("hex");
28
- }
29
- function getToolDefinitionMeasurementSignature(providerID, modelID, agentName) {
30
- const key = keyFor(providerID, modelID, agentName);
31
- const measured = measurements.get(key);
32
- const observed = fingerprints.get(key);
33
- if (!measured || !observed || [...measured.keys()].some((id) => !observed.has(id)))
34
- return;
35
- return createHash("sha256").update(JSON.stringify([...measured.keys()].sort().map((id) => [id, observed.get(id)]))).digest("hex");
36
- }
37
- function setDatabase(db) {
38
- persistenceDb = db;
39
- cachedInsertStmt = null;
40
- }
41
- function loadToolDefinitionMeasurements(db) {
42
- let rows = [];
43
- try {
44
- rows = db.prepare("SELECT provider_id, model_id, agent_name, tool_id, token_count FROM tool_definition_measurements").all();
45
- } catch {
46
- return;
47
- }
48
- for (const row of rows) {
49
- const key = keyFor(row.provider_id, row.model_id, row.agent_name);
50
- let inner = measurements.get(key);
51
- if (!inner) {
52
- inner = new Map;
53
- measurements.set(key, inner);
54
- }
55
- inner.set(row.tool_id, row.token_count);
56
- }
57
- }
58
- function recordToolDefinition(providerID, modelID, agentName, toolID, description, parameters) {
59
- if (!providerID || !modelID || !toolID)
60
- return;
61
- const key = keyFor(providerID, modelID, agentName);
62
- const fp = fingerprintFor(description ?? "", parameters);
63
- let innerFp = fingerprints.get(key);
64
- if (innerFp && innerFp.get(toolID) === fp)
65
- return;
66
- let paramsText = "";
67
- try {
68
- paramsText = parameters === undefined ? "" : JSON.stringify(parameters);
69
- } catch {
70
- paramsText = "";
71
- }
72
- const tokens = estimateTokens(description ?? "") + estimateTokens(paramsText);
73
- let inner = measurements.get(key);
74
- if (!inner) {
75
- inner = new Map;
76
- measurements.set(key, inner);
77
- }
78
- inner.set(toolID, tokens);
79
- if (!innerFp) {
80
- innerFp = new Map;
81
- fingerprints.set(key, innerFp);
82
- }
83
- innerFp.set(toolID, fp);
84
- if (persistenceDb) {
85
- try {
86
- const agent = agentName && agentName.length > 0 ? agentName : "default";
87
- if (!cachedInsertStmt) {
88
- cachedInsertStmt = persistenceDb.prepare(`INSERT OR REPLACE INTO tool_definition_measurements
89
- (provider_id, model_id, agent_name, tool_id, token_count, recorded_at)
90
- VALUES (?, ?, ?, ?, ?, ?)`);
91
- }
92
- cachedInsertStmt.run(providerID, modelID, agent, toolID, tokens, Date.now());
93
- } catch {
94
- cachedInsertStmt = null;
95
- }
96
- }
97
- }
98
- function getLargestMeasuredToolDefinitionTokens() {
99
- let largest = 0;
100
- for (const tools of measurements.values()) {
101
- let total = 0;
102
- for (const tokens of tools.values())
103
- total += tokens;
104
- largest = Math.max(largest, total);
105
- }
106
- return largest > 0 ? largest : undefined;
107
- }
108
- function getMeasuredToolDefinitionTokens(providerID, modelID, agentName) {
109
- if (!providerID || !modelID)
110
- return;
111
- const inner = measurements.get(keyFor(providerID, modelID, agentName));
112
- if (!inner || inner.size === 0)
113
- return;
114
- let total = 0;
115
- for (const tokens of inner.values())
116
- total += tokens;
117
- return total;
118
- }
119
-
120
- export { getCurrentToolSetHash, getToolDefinitionMeasurementSignature, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getLargestMeasuredToolDefinitionTokens, getMeasuredToolDefinitionTokens };