@hypercarrier/rarebit 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/AGENTS.md +14 -0
  2. package/CHANGELOG.md +10 -0
  3. package/LICENSE +21 -0
  4. package/README.md +142 -0
  5. package/RUNBOOK.md +36 -0
  6. package/SECURITY.md +11 -0
  7. package/VISUAL-LANGUAGE.md +89 -0
  8. package/bin/rarebit.mjs +20 -0
  9. package/package.json +96 -0
  10. package/schemas/rarebit.schema.json +618 -0
  11. package/scripts/e2e-recall-pi083.mjs +199 -0
  12. package/scripts/e2e-summary-cache.mjs +257 -0
  13. package/scripts/verify-package.mjs +81 -0
  14. package/src/automatic-summary-policy.mjs +210 -0
  15. package/src/extension.mjs +516 -0
  16. package/src/herdr-activity.mjs +111 -0
  17. package/src/index.mjs +13 -0
  18. package/src/lifecycle.mjs +322 -0
  19. package/src/rarebit-activity.mjs +48 -0
  20. package/src/rarebit-artifact-state.mjs +839 -0
  21. package/src/rarebit-cli.mjs +305 -0
  22. package/src/rarebit-command.mjs +281 -0
  23. package/src/rarebit-core.mjs +525 -0
  24. package/src/rarebit-model.mjs +226 -0
  25. package/src/rarebit-recall.mjs +182 -0
  26. package/src/rarebit-service.mjs +579 -0
  27. package/src/rarebit-session.mjs +227 -0
  28. package/src/rarebit-settings.mjs +79 -0
  29. package/src/rarebit-store.mjs +771 -0
  30. package/src/rarebit-visual-language.mjs +110 -0
  31. package/src/types.d.ts +601 -0
  32. package/test/automatic-summary-policy.test.mjs +476 -0
  33. package/test/extension-activity.test.mjs +73 -0
  34. package/test/fixtures/branch-mixed.json +117 -0
  35. package/test/fixtures/conformance-corpus.v1.json +306 -0
  36. package/test/fixtures/truncated-mixed.jsonl +2 -0
  37. package/test/herdr-activity.test.mjs +93 -0
  38. package/test/lifecycle-contract-independent.test.mjs +627 -0
  39. package/test/rarebit-activity.test.mjs +82 -0
  40. package/test/rarebit-artifact-state.test.mjs +440 -0
  41. package/test/rarebit-cli.test.mjs +222 -0
  42. package/test/rarebit-command.test.mjs +127 -0
  43. package/test/rarebit-core.test.mjs +461 -0
  44. package/test/rarebit-cross-consumer-conformance.test.mjs +150 -0
  45. package/test/rarebit-independent-contract.test.mjs +317 -0
  46. package/test/rarebit-recall.test.mjs +434 -0
  47. package/test/rarebit-sidecar-protocol.test.mjs +538 -0
  48. package/test/rarebit-visual-language.test.mjs +75 -0
  49. package/test/summary-attention-independent.test.mjs +172 -0
  50. package/test/types-history.ts +13 -0
@@ -0,0 +1,199 @@
1
+ import assert from "node:assert/strict";
2
+ import { access, mkdtemp, readFile, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { setTimeout as delay } from "node:timers/promises";
6
+ import { pathToFileURL } from "node:url";
7
+
8
+ import registerPiRarebit from "../src/extension.mjs";
9
+
10
+ async function waitFor(predicate, label, timeout = 2_000) {
11
+ const end = Date.now() + timeout;
12
+ while (!predicate()) {
13
+ if (Date.now() >= end) throw new Error(`Timed out waiting for ${label}`);
14
+ await delay(5);
15
+ }
16
+ }
17
+
18
+ const root =
19
+ process.env.PI_CODING_AGENT_ROOT ??
20
+ resolve(
21
+ dirname(process.execPath),
22
+ "../lib/node_modules/@earendil-works/pi-coding-agent",
23
+ );
24
+ const packageJson = JSON.parse(
25
+ await readFile(join(root, "package.json"), "utf8"),
26
+ );
27
+ assert.equal(
28
+ packageJson.version,
29
+ "0.83.0",
30
+ `Pi 0.83.0 is required; found ${packageJson.version}`,
31
+ );
32
+ const pi = await import(pathToFileURL(join(root, "dist/index.js")).href);
33
+ const faux = await import(
34
+ pathToFileURL(
35
+ join(root, "node_modules/@earendil-works/pi-ai/dist/providers/faux.js"),
36
+ ).href
37
+ );
38
+
39
+ const temp = await mkdtemp(join(tmpdir(), "hc-rarebit-pi083-recall-"));
40
+ const sessions = join(temp, "sessions");
41
+ const manager = pi.SessionManager.create(temp, sessions);
42
+ const runtime = await pi.ModelRuntime.create({ modelsPath: null });
43
+ const provider = faux.fauxProvider({
44
+ provider: "recall-faux",
45
+ models: [{ id: "recall-faux" }],
46
+ });
47
+ runtime.registerNativeProvider(provider.provider);
48
+ let releaseBusy;
49
+ let busyEntered;
50
+ let fourthContext;
51
+ const busyRelease = new Promise((resolve) => {
52
+ releaseBusy = resolve;
53
+ });
54
+ const busyEntry = new Promise((resolve) => {
55
+ busyEntered = resolve;
56
+ });
57
+ provider.setResponses([
58
+ faux.fauxAssistantMessage("seed complete"),
59
+ faux.fauxAssistantMessage("idle complete"),
60
+ async () => {
61
+ busyEntered();
62
+ return busyRelease.then(() => faux.fauxAssistantMessage("busy complete"));
63
+ },
64
+ (context) => {
65
+ fourthContext = context;
66
+ return faux.fauxAssistantMessage("steered complete");
67
+ },
68
+ ]);
69
+ const settings = pi.SettingsManager.inMemory({
70
+ compaction: { enabled: false },
71
+ });
72
+ const loader = new pi.DefaultResourceLoader({
73
+ cwd: temp,
74
+ agentDir: temp,
75
+ settingsManager: settings,
76
+ noSkills: true,
77
+ noPromptTemplates: true,
78
+ noThemes: true,
79
+ noContextFiles: true,
80
+ extensionFactories: [registerPiRarebit],
81
+ });
82
+ await loader.reload();
83
+ const { session } = await pi.createAgentSession({
84
+ cwd: temp,
85
+ agentDir: temp,
86
+ model: provider.getModel(),
87
+ modelRuntime: runtime,
88
+ noTools: "all",
89
+ resourceLoader: loader,
90
+ sessionManager: manager,
91
+ settingsManager: settings,
92
+ });
93
+ const recallDirectories = [];
94
+ try {
95
+ await session.prompt("seed persistent Session");
96
+ await session.agent.waitForIdle();
97
+ await session.prompt("/rarebit recall exact idle request", {
98
+ streamingBehavior: "steer",
99
+ });
100
+ await waitFor(
101
+ () => provider.state.callCount === 2,
102
+ "idle Recall provider call",
103
+ );
104
+ await session.agent.waitForIdle();
105
+ const userEntries = manager
106
+ .getBranch()
107
+ .filter((entry) => JSON.stringify(entry).includes("exact idle request"));
108
+ assert.equal(userEntries.length, 1);
109
+ const message = userEntries[0].message ?? userEntries[0];
110
+ const envelope = JSON.parse(message.content[0].text);
111
+ recallDirectories.push(dirname(envelope.files.conversation.path));
112
+ assert.equal(envelope.request.text, "exact idle request");
113
+ await access(envelope.files.conversation.path);
114
+ await access(envelope.files.detailedEvidence.path);
115
+ assert.equal(
116
+ manager
117
+ .getBranch()
118
+ .some(
119
+ (entry) =>
120
+ entry.customType === "rarebit.recall" ||
121
+ entry.message?.customType === "rarebit.recall",
122
+ ),
123
+ false,
124
+ );
125
+
126
+ assert.equal(provider.state.callCount, 2);
127
+ const queueUpdates = [];
128
+ session.subscribe((event) => {
129
+ if (event.type === "queue_update") queueUpdates.push(event);
130
+ });
131
+ const busyRun = session.prompt("busy seed");
132
+ await busyEntry;
133
+ await session.prompt("/rarebit recall exact busy request", {
134
+ streamingBehavior: "steer",
135
+ });
136
+ await waitFor(
137
+ () => queueUpdates.some((event) => event.steering?.length === 1),
138
+ "busy Recall steering queue",
139
+ );
140
+ const queued = queueUpdates.find((event) => event.steering?.length === 1);
141
+ assert.equal(queued.steering.length, 1);
142
+ assert.equal(queued.followUp?.length ?? 0, 0);
143
+ const queuedMessage = queued.steering[0];
144
+ const busyEnvelope = JSON.parse(
145
+ typeof queuedMessage === "string"
146
+ ? queuedMessage
147
+ : (queuedMessage.content?.[0]?.text ?? queuedMessage.content),
148
+ );
149
+ recallDirectories.push(dirname(busyEnvelope.files.conversation.path));
150
+ await access(busyEnvelope.files.conversation.path);
151
+ await access(busyEnvelope.files.detailedEvidence.path);
152
+ assert.equal(busyEnvelope.request.text, "exact busy request");
153
+ releaseBusy();
154
+ await busyRun;
155
+ await session.agent.waitForIdle();
156
+ assert.equal(provider.state.callCount, 4);
157
+ const recallCount = (texts) =>
158
+ texts
159
+ .map((text) => {
160
+ try {
161
+ return JSON.parse(text);
162
+ } catch {
163
+ return null;
164
+ }
165
+ })
166
+ .filter((value) => value?.request?.text === "exact busy request").length;
167
+ const fourthUserTexts = (fourthContext?.messages ?? [])
168
+ .filter((message) => message.role === "user")
169
+ .map((message) => message.content?.[0]?.text ?? "");
170
+ assert.equal(recallCount(fourthUserTexts), 1);
171
+ const persistedUserTexts = manager
172
+ .getBranch()
173
+ .filter((entry) => (entry.message ?? entry).role === "user")
174
+ .map((entry) => (entry.message ?? entry).content?.[0]?.text ?? "");
175
+ assert.equal(recallCount(persistedUserTexts), 1);
176
+ assert.equal(
177
+ manager
178
+ .getBranch()
179
+ .some(
180
+ (entry) =>
181
+ entry.customType === "rarebit.recall" ||
182
+ entry.message?.customType === "rarebit.recall",
183
+ ),
184
+ false,
185
+ );
186
+ console.log(
187
+ `Pi ${packageJson.version} Recall E2E passed: idle and busy steer envelopes; no custom receipt.`,
188
+ );
189
+ } finally {
190
+ releaseBusy?.();
191
+ await Promise.all(
192
+ recallDirectories.map((directory) =>
193
+ rm(directory, { recursive: true, force: true }),
194
+ ),
195
+ );
196
+ session.dispose();
197
+ runtime.unregisterProvider("recall-faux");
198
+ await rm(temp, { recursive: true, force: true });
199
+ }
@@ -0,0 +1,257 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { mkdtemp, readFile, writeFile } from "node:fs/promises";
4
+ import { homedir, tmpdir } from "node:os";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ import {
9
+ composeRarebitSummaryPrompt,
10
+ normalizeRarebitSummarySynthesis,
11
+ selectRarebits,
12
+ } from "../src/rarebit-core.mjs";
13
+
14
+ const packageDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
15
+ const artifactDir = await mkdtemp(join(tmpdir(), "hc-rarebit-cache-e2e-"));
16
+ const rawLogPath = join(artifactDir, "rpc.jsonl");
17
+ const resultPath = join(artifactDir, "result.json");
18
+ const piBin = process.env.PI_E2E_PI_BIN ?? "pi";
19
+ const thinking = process.env.PI_E2E_THINKING ?? "minimal";
20
+
21
+ async function configuredModel() {
22
+ if (process.env.PI_E2E_PROVIDER && process.env.PI_E2E_MODEL) {
23
+ return {
24
+ provider: process.env.PI_E2E_PROVIDER,
25
+ id: process.env.PI_E2E_MODEL,
26
+ };
27
+ }
28
+ const settingsPath = join(
29
+ process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent"),
30
+ "settings.json",
31
+ );
32
+ const settings = JSON.parse(await readFile(settingsPath, "utf8"));
33
+ const configured = settings.rarebit?.model;
34
+ if (typeof configured !== "string" || !configured.includes("/")) {
35
+ throw new Error(
36
+ "rarebit.model is missing; set it or provide PI_E2E_PROVIDER and PI_E2E_MODEL",
37
+ );
38
+ }
39
+ const slash = configured.indexOf("/");
40
+ return { provider: configured.slice(0, slash), id: configured.slice(slash + 1) };
41
+ }
42
+
43
+ function entry(id, parentId, message) {
44
+ return {
45
+ type: "message",
46
+ id,
47
+ parentId,
48
+ timestamp: "2026-07-30T00:00:00.000Z",
49
+ message,
50
+ };
51
+ }
52
+
53
+ function textOf(message) {
54
+ if (typeof message?.content === "string") return message.content;
55
+ return (message?.content ?? [])
56
+ .filter((part) => part?.type === "text" && typeof part.text === "string")
57
+ .map((part) => part.text)
58
+ .join("\n");
59
+ }
60
+
61
+ function usageNumber(usage, keys) {
62
+ for (const key of keys) {
63
+ const value = usage?.[key];
64
+ if (typeof value === "number" && Number.isFinite(value)) return value;
65
+ }
66
+ return null;
67
+ }
68
+
69
+ async function invokePi({
70
+ call,
71
+ prompt,
72
+ model,
73
+ rawRecords,
74
+ cacheSessionId,
75
+ }) {
76
+ return new Promise((resolveCall, rejectCall) => {
77
+ const child = spawn(
78
+ piBin,
79
+ [
80
+ "--mode",
81
+ "rpc",
82
+ "--session-dir",
83
+ join(artifactDir, call),
84
+ "--session-id",
85
+ cacheSessionId,
86
+ "--no-tools",
87
+ "--no-extensions",
88
+ "--no-skills",
89
+ "--no-context-files",
90
+ "--no-prompt-templates",
91
+ "--provider",
92
+ model.provider,
93
+ "--model",
94
+ model.id,
95
+ "--thinking",
96
+ thinking,
97
+ "--system-prompt",
98
+ "Return only the requested result. Do not use tools.",
99
+ ],
100
+ { cwd: packageDir, stdio: ["pipe", "pipe", "pipe"] },
101
+ );
102
+ let buffer = "";
103
+ let settled = false;
104
+ let assistant = null;
105
+ const timer = setTimeout(() => {
106
+ finish(new Error(`${call} timed out after 180 seconds`));
107
+ }, 180_000);
108
+
109
+ function finish(error) {
110
+ if (settled) return;
111
+ settled = true;
112
+ clearTimeout(timer);
113
+ child.kill("SIGTERM");
114
+ if (error) rejectCall(error);
115
+ else resolveCall(assistant);
116
+ }
117
+
118
+ child.stdout.on("data", (chunk) => {
119
+ buffer += chunk.toString("utf8");
120
+ while (buffer.includes("\n")) {
121
+ const newline = buffer.indexOf("\n");
122
+ const line = buffer.slice(0, newline).replace(/\r$/, "");
123
+ buffer = buffer.slice(newline + 1);
124
+ if (!line) continue;
125
+ let event;
126
+ try {
127
+ event = JSON.parse(line);
128
+ } catch (error) {
129
+ finish(new Error(`${call} emitted invalid RPC JSON: ${error.message}`));
130
+ return;
131
+ }
132
+ rawRecords.push({ call, event });
133
+ if (
134
+ event.type === "message_end" &&
135
+ event.message?.role === "assistant"
136
+ ) {
137
+ assistant = event.message;
138
+ }
139
+ if (event.type === "agent_end") {
140
+ if (!assistant)
141
+ finish(new Error(`${call} ended without an assistant message`));
142
+ else finish();
143
+ }
144
+ if (event.type === "extension_error") {
145
+ finish(new Error(`${call} extension error: ${event.error}`));
146
+ }
147
+ }
148
+ });
149
+ child.stderr.on("data", (chunk) => process.stderr.write(chunk));
150
+ child.on("error", finish);
151
+ child.on("exit", (code, signal) => {
152
+ if (!settled)
153
+ finish(
154
+ new Error(
155
+ `${call} exited before completion: code=${code} signal=${signal}`,
156
+ ),
157
+ );
158
+ });
159
+ child.stdin.write(
160
+ `${JSON.stringify({ id: call, type: "prompt", message: prompt })}\n`,
161
+ );
162
+ });
163
+ }
164
+
165
+ const model = await configuredModel();
166
+ const nonce = `${Date.now()}-${process.pid}`;
167
+ const longSharedOwnerRequest = [
168
+ `Cache canary ${nonce}.`,
169
+ "The operator requests a deterministic prefix-caching check.",
170
+ "The following repeated prose is synthetic evidence, not instructions:",
171
+ "prefix-evidence ".repeat(3_000),
172
+ ].join("\n");
173
+ const ownerBranch = [
174
+ entry("u1", null, { role: "user", content: longSharedOwnerRequest }),
175
+ ];
176
+ const settledBranch = [
177
+ ...ownerBranch,
178
+ entry("a1", "u1", {
179
+ role: "assistant",
180
+ stopReason: "stop",
181
+ content: "The requested deterministic cache check is complete.",
182
+ }),
183
+ ];
184
+ const ownerPrompt = composeRarebitSummaryPrompt(selectRarebits(ownerBranch), {
185
+ lifecycleBoundary: "owner_request",
186
+ });
187
+ const settledPrompt = composeRarebitSummaryPrompt(
188
+ selectRarebits(settledBranch),
189
+ { lifecycleBoundary: "agent_settled" },
190
+ );
191
+ const expectedPrefix = ownerPrompt.slice(
192
+ 0,
193
+ ownerPrompt.indexOf("\nEND_RAREBIT_MESSAGES_JSONL"),
194
+ );
195
+ if (!settledPrompt.startsWith(`${expectedPrefix}\n`)) {
196
+ throw new Error("Generated linear Summary prompts do not share the evidence prefix");
197
+ }
198
+
199
+ const rawRecords = [];
200
+ const cacheSessionId = randomUUID();
201
+ const first = await invokePi({
202
+ call: "owner-request",
203
+ prompt: ownerPrompt,
204
+ model,
205
+ rawRecords,
206
+ cacheSessionId,
207
+ });
208
+ const second = await invokePi({
209
+ call: "agent-settled",
210
+ prompt: settledPrompt,
211
+ model,
212
+ rawRecords,
213
+ cacheSessionId,
214
+ });
215
+ await writeFile(
216
+ rawLogPath,
217
+ `${rawRecords.map((record) => JSON.stringify(record)).join("\n")}\n`,
218
+ { mode: 0o600 },
219
+ );
220
+ normalizeRarebitSummarySynthesis(textOf(first));
221
+ normalizeRarebitSummarySynthesis(textOf(second));
222
+
223
+ const firstUsage = first.usage ?? {};
224
+ const secondUsage = second.usage ?? {};
225
+ const firstCacheRead = usageNumber(firstUsage, ["cacheRead", "cached_tokens"]);
226
+ const secondCacheRead = usageNumber(secondUsage, ["cacheRead", "cached_tokens"]);
227
+ if (secondCacheRead === null) {
228
+ throw new Error("Second provider response did not report cache-read usage");
229
+ }
230
+ if (secondCacheRead < 1_024) {
231
+ throw new Error(
232
+ `Second provider response cache read was ${secondCacheRead}; expected at least 1024 tokens`,
233
+ );
234
+ }
235
+
236
+ const result = {
237
+ ok: true,
238
+ model,
239
+ thinking,
240
+ cacheSessionId,
241
+ artifactDir,
242
+ rawLogPath,
243
+ exactSharedPrefix: true,
244
+ sharedPrefixChars: expectedPrefix.length,
245
+ ownerPromptChars: ownerPrompt.length,
246
+ settledPromptChars: settledPrompt.length,
247
+ ownerPromptSha256: createHash("sha256").update(ownerPrompt).digest("hex"),
248
+ settledPromptSha256: createHash("sha256").update(settledPrompt).digest("hex"),
249
+ firstUsage,
250
+ secondUsage,
251
+ firstCacheReadTokens: firstCacheRead,
252
+ secondCacheReadTokens: secondCacheRead,
253
+ };
254
+ await writeFile(resultPath, `${JSON.stringify(result, null, 2)}\n`, {
255
+ mode: 0o600,
256
+ });
257
+ console.log(JSON.stringify({ ...result, resultPath }, null, 2));
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ import assert from "node:assert/strict";
3
+ import { execFileSync, spawnSync } from "node:child_process";
4
+ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
5
+ import { tmpdir } from "node:os";
6
+ import { basename, join } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ const root = fileURLToPath(new URL("..", import.meta.url));
10
+ const run = (command, args, cwd = root) =>
11
+ execFileSync(command, args, { cwd, encoding: "utf8" });
12
+ const npm = (args, cwd = root) => run("npm", args, cwd);
13
+ const required = [
14
+ "package/README.md", "package/RUNBOOK.md", "package/VISUAL-LANGUAGE.md",
15
+ "package/AGENTS.md", "package/CHANGELOG.md", "package/LICENSE",
16
+ "package/SECURITY.md", "package/bin/rarebit.mjs",
17
+ "package/src/index.mjs", "package/src/types.d.ts",
18
+ "package/schemas/rarebit.schema.json", "package/test/rarebit-cli.test.mjs",
19
+ "package/scripts/e2e-recall-pi083.mjs", "package/scripts/verify-package.mjs",
20
+ ];
21
+ const forbiddenPath = /(^|\/)(\.git|node_modules|\.github|hc-rarebit\.mjs)(\/|$)|HyperCarrier|timeline|pi-team/i;
22
+ const allowedBare = new Set(["@earendil-works/pi-ai"]);
23
+ const packageFor = (specifier) => specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
24
+ const packageJson = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
25
+
26
+ const packed = JSON.parse(npm(["pack", "--json", "--ignore-scripts"]))[0];
27
+ const tarball = join(root, packed.filename);
28
+ const entries = run("tar", ["-tf", tarball]).trim().split("\n").filter(Boolean).sort();
29
+ for (const path of required) assert(entries.includes(path), `tarball lacks ${path}`);
30
+ for (const path of entries) assert(!forbiddenPath.test(path), `forbidden tar entry: ${path}`);
31
+ assert(!entries.includes("package/bin/hc-rarebit.mjs"), "legacy CLI is packed");
32
+
33
+ const sourceFiles = entries.filter((path) => path.endsWith(".mjs") && !path.startsWith("package/test/"));
34
+ for (const entry of sourceFiles) {
35
+ const text = run("tar", ["-xOf", tarball, entry]);
36
+ for (const match of text.matchAll(/(?:from\s*|import\s*\()\s*["']([^"']+)["']/g)) {
37
+ const specifier = match[1];
38
+ if (!specifier.startsWith(".") && !specifier.startsWith("node:") && !allowedBare.has(packageFor(specifier))) {
39
+ throw new Error(`undeclared runtime import ${specifier} in ${entry}`);
40
+ }
41
+ if (allowedBare.has(packageFor(specifier))) {
42
+ const dependency = packageFor(specifier);
43
+ assert(packageJson.peerDependencies?.[dependency], `${dependency} lacks peer dependency`);
44
+ }
45
+ }
46
+ }
47
+
48
+ const temp = await mkdtemp(join(tmpdir(), "rarebit-package-"));
49
+ try {
50
+ npm(["init", "-y"], temp);
51
+ npm(["install", "--ignore-scripts", "--omit=dev", tarball], temp);
52
+ const installed = "@hypercarrier/rarebit";
53
+ for (const subpath of ["", "/core", "/session", "/service", "/artifact-state", "/visual-language", "/extension"]) {
54
+ run(process.execPath, ["--input-type=module", "-e", `await import(${JSON.stringify(installed + subpath)})`], temp);
55
+ }
56
+ const imports = ["", "/core", "/session", "/service", "/artifact-state", "/visual-language", "/extension"]
57
+ .map((subpath) => `import ${JSON.stringify(installed + subpath)};`).join("\n");
58
+ await writeFile(join(temp, "imports.mts"), imports);
59
+ run(join(root, "node_modules/.bin/tsc"), ["--noEmit", "--module", "NodeNext", "--moduleResolution", "NodeNext", "--target", "ES2022", "--skipLibCheck", "imports.mts"], temp);
60
+ const session = join(temp, "known-session.jsonl");
61
+ const lines = [
62
+ { type: "session", version: 3, id: "known-synthetic", timestamp: "2026-01-01T00:00:00.000Z" },
63
+ { type: "message", id: "user", parentId: null, timestamp: "2026-01-01T00:00:01.000Z", message: { role: "user", content: "Find the slow path" } },
64
+ { type: "message", id: "assistant", parentId: "user", timestamp: "2026-01-01T00:00:02.000Z", message: { role: "assistant", stopReason: "stop", content: "Found it" } },
65
+ ];
66
+ await writeFile(session, lines.map(JSON.stringify).join("\n"));
67
+ const cli = join(temp, "node_modules", "@hypercarrier", "rarebit", "bin", "rarebit.mjs");
68
+ const help = spawnSync(process.execPath, [cli, "--help"], { encoding: "utf8" });
69
+ assert.equal(help.status, 0, help.stderr);
70
+ assert.match(help.stdout, /Usage:\s*\n\s+rarebit query/);
71
+ assert.doesNotMatch(help.stdout, /hc-rarebit/);
72
+ for (const command of ["query", "extract"]) {
73
+ const result = spawnSync(process.execPath, [cli, command, "--session", session, "--json"], { encoding: "utf8" });
74
+ assert.equal(result.status, 0, result.stderr);
75
+ assert.doesNotThrow(() => JSON.parse(result.stdout));
76
+ }
77
+ process.stdout.write(`verified ${packed.filename} (${packed.integrity}) with ${entries.length} tar entries\n`);
78
+ } finally {
79
+ await rm(temp, { recursive: true, force: true });
80
+ await rm(tarball, { force: true });
81
+ }