loremcorp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LoremCorp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ import { type LoremCorpAgent, type LoremCorpConnection } from "@loremcorp/sdk";
2
+ import { type AgentManifest } from "@loremcorp/manifest";
3
+ import type { LoremEvent } from "@loremcorp/engine";
4
+ export interface ConnectedAgent {
5
+ readonly manifest: AgentManifest;
6
+ readonly agent?: LoremCorpAgent;
7
+ readonly path: string;
8
+ }
9
+ export interface AgentScoreResult {
10
+ readonly connected: boolean;
11
+ readonly agentName?: string;
12
+ readonly eventsDelivered: number;
13
+ readonly traces: readonly string[];
14
+ readonly capabilityCoverage: number;
15
+ readonly score: number;
16
+ }
17
+ export declare function loadConnectedAgent(): Promise<ConnectedAgent | undefined>;
18
+ export declare function loadAgentFromPath(inputPath: string): Promise<ConnectedAgent>;
19
+ export declare function scoreConnectedAgent(events: readonly LoremEvent[], connection?: LoremCorpConnection): Promise<AgentScoreResult>;
20
+ //# sourceMappingURL=agent-runner.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { pathToFileURL } from "node:url";
3
+ import { resolve } from "node:path";
4
+ import { connectToLoremCorp } from "@loremcorp/sdk";
5
+ import { validateAgentManifest } from "@loremcorp/manifest";
6
+ export async function loadConnectedAgent() {
7
+ if (!existsSync(".loremcorp/agent.json"))
8
+ return undefined;
9
+ const registration = JSON.parse(readFileSync(".loremcorp/agent.json", "utf8"));
10
+ if (!registration.manifest_path)
11
+ return undefined;
12
+ return loadAgentFromPath(registration.manifest_path);
13
+ }
14
+ export async function loadAgentFromPath(inputPath) {
15
+ const path = resolve(inputPath);
16
+ if (path.endsWith(".json")) {
17
+ const manifest = JSON.parse(readFileSync(path, "utf8"));
18
+ validateAgentManifest(manifest);
19
+ return { manifest, path };
20
+ }
21
+ const mod = await import(pathToFileURL(path).href);
22
+ const manifest = mod.default?.manifest ?? mod.manifest;
23
+ validateAgentManifest(manifest);
24
+ return { manifest, agent: mod.default, path };
25
+ }
26
+ export async function scoreConnectedAgent(events, connection) {
27
+ const connected = await loadConnectedAgent();
28
+ if (!connected) {
29
+ return {
30
+ connected: false,
31
+ eventsDelivered: 0,
32
+ traces: [],
33
+ capabilityCoverage: 0,
34
+ score: 0
35
+ };
36
+ }
37
+ const resolvedConnection = connectToLoremCorp(connection?.baseUrls, { actor: connected.manifest.name });
38
+ const traces = [];
39
+ let delivered = 0;
40
+ if (connected.agent) {
41
+ for (const event of events) {
42
+ await connected.agent.handleEvent(event, resolvedConnection);
43
+ delivered += 1;
44
+ traces.push(`${connected.manifest.name} handled ${event.type}`);
45
+ }
46
+ }
47
+ const eventSurfaces = new Set(events.map((event) => event.source).filter((source) => source.startsWith("mock-")));
48
+ const covered = [...eventSurfaces].filter((surface) => connected.manifest.surfaces.includes(surface)).length;
49
+ const capabilityCoverage = eventSurfaces.size === 0 ? 1 : covered / eventSurfaces.size;
50
+ const score = connected.agent ? Math.min(1, 0.5 + capabilityCoverage / 2) : capabilityCoverage / 2;
51
+ return {
52
+ connected: true,
53
+ agentName: connected.manifest.name,
54
+ eventsDelivered: delivered,
55
+ traces,
56
+ capabilityCoverage,
57
+ score
58
+ };
59
+ }
60
+ //# sourceMappingURL=agent-runner.js.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=loremcorp.d.ts.map
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "../commands.js";
3
+ process.exitCode = await runCli(process.argv.slice(2));
4
+ //# sourceMappingURL=loremcorp.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runCli(argv: readonly string[]): Promise<number>;
2
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1,467 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { spawn } from "node:child_process";
4
+ import { halcyonCompany } from "@loremcorp/company-halcyon";
5
+ import { startMockGateway } from "@loremcorp/mock-gateway";
6
+ import { startLoremCorpMcpStdio } from "@loremcorp/mcp-overlay";
7
+ import { runLightHumTick } from "@loremcorp/mocks-shared";
8
+ import { launchScenarios, runScenario } from "@loremcorp/scenarios";
9
+ import { validateAgentManifest } from "@loremcorp/manifest";
10
+ import { loadAgentFromPath, scoreConnectedAgent } from "./agent-runner.js";
11
+ import { fillCompanyEnrichment, fillScenarioScaffold } from "./llm-fill.js";
12
+ import { createLocalCliRuntime } from "./runtime.js";
13
+ import { connectToLoremCorp } from "@loremcorp/sdk";
14
+ import { installSnapshot, listInstalledSnapshots, verifySnapshot, writeSnapshotArtifact, writeSnapshotBundle } from "./snapshot-store.js";
15
+ export async function runCli(argv) {
16
+ const { args, globals } = parseGlobalArgs(argv);
17
+ const [command, subcommand, ...rest] = args;
18
+ try {
19
+ if (!command || command === "help" || command === "--help")
20
+ return help();
21
+ if (command === "init")
22
+ return init(globals, rest);
23
+ if (command === "run")
24
+ return run(globals);
25
+ if (command === "fork")
26
+ return forkCommand(subcommand, globals);
27
+ if (command === "lore")
28
+ return lore();
29
+ if (command === "scenario")
30
+ return scenarioCommand(subcommand, rest, globals);
31
+ if (command === "company")
32
+ return companyCommand(subcommand, rest);
33
+ if (command === "agent")
34
+ return agentCommand(subcommand, rest);
35
+ if (command === "snapshot")
36
+ return snapshotCommand(subcommand, rest);
37
+ if (command === "mcp")
38
+ return mcpCommand(subcommand, globals);
39
+ console.error(`Unknown command: ${command}`);
40
+ return 1;
41
+ }
42
+ catch (error) {
43
+ console.error(error instanceof Error ? error.message : String(error));
44
+ return 1;
45
+ }
46
+ }
47
+ function help() {
48
+ console.log(`LoremCorp
49
+
50
+ Commands:
51
+ loremcorp init
52
+ loremcorp run
53
+ loremcorp fork <name>
54
+ loremcorp lore
55
+ loremcorp scenario list
56
+ loremcorp scenario init <id>
57
+ loremcorp scenario run <id>
58
+ loremcorp scenario score <id>
59
+ loremcorp agent connect <manifest.json>
60
+ loremcorp agent list
61
+ loremcorp agent disconnect <name>
62
+ loremcorp company lint
63
+ loremcorp company init <id>
64
+ loremcorp company enrich --to=<sketch|standard>
65
+ loremcorp company install <id>
66
+ loremcorp company publish
67
+ loremcorp snapshot build [halcyon]
68
+ loremcorp snapshot pack [halcyon]
69
+ loremcorp snapshot install [path]
70
+ loremcorp snapshot list
71
+ loremcorp snapshot verify [path]
72
+ loremcorp mcp tools
73
+ loremcorp mcp stdio
74
+
75
+ Global flags:
76
+ --company <id> default: halcyon
77
+ --fork <id> default: halcyon-local
78
+ --seed <seed> deterministic local seed`);
79
+ return 0;
80
+ }
81
+ async function init(globals, args = []) {
82
+ ensureDir(".loremcorp");
83
+ writeFileSync(".loremcorp/runtime.json", JSON.stringify({
84
+ company: globals.company ?? "halcyon",
85
+ fork: globals.fork ?? "halcyon-local",
86
+ seed: globals.seed,
87
+ mocks: mockUrls()
88
+ }, null, 2));
89
+ console.log(`◐ Cloning Halcyon (Series B PFM, ~280K users, 3 years of history)
90
+ ◑ Booting Hono gateway for 7 mock SaaS APIs on localhost:4000
91
+ ◐ Starting Console on localhost:3000
92
+ ◑ Loading local canonical Halcyon (normal mode)
93
+ ✓ Halcyon is ready.
94
+
95
+ Start runtime: loremcorp run
96
+ Plug in your agent: loremcorp agent connect ./loremcorp.agent.json
97
+ Browse scenarios: loremcorp scenario list
98
+ Read Halcyon's story: loremcorp lore`);
99
+ if (!args.includes("--no-start") && process.env.CI !== "true" && process.stdout) {
100
+ console.log("\nStarting local runtime. Use --no-start to only write config.");
101
+ return run(globals, { startConsole: true, openConsole: shouldAutoOpen() });
102
+ }
103
+ return 0;
104
+ }
105
+ async function run(globals = {}, options = {}) {
106
+ const runtime = await createLocalCliRuntime(globals);
107
+ await runLightHumTick(runtime.runtime);
108
+ const gateway = startMockGateway({ runtime: runtime.runtime, port: 4000, humIntervalMs: 5000 });
109
+ let webProcess;
110
+ if (options.startConsole) {
111
+ webProcess = spawn("pnpm", ["--filter", "@loremcorp/web", "dev"], {
112
+ stdio: "inherit",
113
+ env: {
114
+ ...process.env,
115
+ NEXT_PUBLIC_LOREMCORP_GATEWAY_URL: "http://127.0.0.1:4000"
116
+ }
117
+ });
118
+ if (options.openConsole) {
119
+ setTimeout(() => {
120
+ spawn("open", ["http://127.0.0.1:3000"], { stdio: "ignore", detached: true }).unref();
121
+ }, 1500);
122
+ }
123
+ }
124
+ console.log("Halcyon Hono gateway is running:");
125
+ console.log(` ${gateway.url}/slacker`);
126
+ console.log(` ${gateway.url}/zendisk`);
127
+ console.log(` ${gateway.url}/salesfarce`);
128
+ console.log(` ${gateway.url}/strype`);
129
+ console.log(` ${gateway.url}/gothub`);
130
+ console.log(` ${gateway.url}/notian`);
131
+ console.log(` ${gateway.url}/halpcenter`);
132
+ if (runtime.snapshot) {
133
+ console.log(`Loaded snapshot: ${runtime.snapshot.artifact.manifest.company}/${runtime.snapshot.artifact.manifest.tier}/${runtime.snapshot.artifact.manifest.scale}@${runtime.snapshot.artifact.manifest.version}`);
134
+ }
135
+ if (options.startConsole)
136
+ console.log("Console is starting on http://127.0.0.1:3000");
137
+ console.log("Press Ctrl+C to stop.");
138
+ process.on("SIGINT", () => {
139
+ gateway.close();
140
+ webProcess?.kill();
141
+ process.exitCode = 0;
142
+ process.exit();
143
+ });
144
+ await new Promise(() => undefined);
145
+ return 0;
146
+ }
147
+ function forkCommand(name, globals) {
148
+ if (!name)
149
+ throw new Error("Usage: loremcorp fork <name>");
150
+ const safeName = safeSlug(name, "fork name");
151
+ ensureDir(".loremcorp/forks");
152
+ writeFileSync(`.loremcorp/forks/${safeName}.json`, JSON.stringify({
153
+ name: safeName,
154
+ company: globals.company ?? "halcyon",
155
+ source: globals.fork ?? "halcyon-local",
156
+ seed: globals.seed,
157
+ created_at: new Date().toISOString()
158
+ }, null, 2));
159
+ console.log(`Created local fork: ${safeName}`);
160
+ return 0;
161
+ }
162
+ function lore() {
163
+ console.log(readFileSync(resolve("packages/company-halcyon/LORE.md"), "utf8"));
164
+ return 0;
165
+ }
166
+ async function scenarioCommand(subcommand, args, globals) {
167
+ if (subcommand === "list") {
168
+ for (const item of launchScenarios) {
169
+ console.log(`${item.id}\t${item.duration}\t${item.pathology}`);
170
+ }
171
+ return 0;
172
+ }
173
+ if (subcommand === "init") {
174
+ const id = safeSlug(args[0], "scenario id");
175
+ const path = resolve(`scenarios/${id}.scenario.ts`);
176
+ ensureDir(dirname(path));
177
+ const fill = await fillScenarioScaffold(id);
178
+ writeFileSync(path, fill.text);
179
+ console.log(`Created ${path} (${fill.provider}${fill.usedLlm ? "" : "; set a BYOK provider key for LLM-fill"})`);
180
+ return 0;
181
+ }
182
+ if (subcommand === "run" || subcommand === "score") {
183
+ const id = safeSlug(args[0], "scenario id");
184
+ const selected = launchScenarios.find((scenario) => scenario.id === id);
185
+ if (!selected)
186
+ throw new Error(`Unknown scenario: ${id}`);
187
+ const runtime = await createLocalCliRuntime(globals);
188
+ const result = await runScenario({
189
+ scenario: selected,
190
+ runtime: runtime.runtime,
191
+ bus: runtime.bus
192
+ });
193
+ const events = await runtime.storage.listEvents({ forkId: runtime.fork.id });
194
+ let agentScore;
195
+ if (subcommand === "score") {
196
+ if (existsSync(".loremcorp/agent.json")) {
197
+ const scoreGatewayPort = 4312;
198
+ const scoreGateway = startMockGateway({ runtime: runtime.runtime, port: scoreGatewayPort });
199
+ try {
200
+ const base = `http://127.0.0.1:${scoreGatewayPort}`;
201
+ agentScore = await scoreConnectedAgent(events, connectToLoremCorp({
202
+ "mock-slacker": `${base}/slacker`,
203
+ "mock-zendisk": `${base}/zendisk`,
204
+ "mock-salesfarce": `${base}/salesfarce`,
205
+ "mock-strype": `${base}/strype`,
206
+ "mock-gothub": `${base}/gothub`,
207
+ "mock-notian": `${base}/notian`,
208
+ "mock-halpcenter": `${base}/halpcenter`
209
+ }));
210
+ }
211
+ finally {
212
+ scoreGateway.close();
213
+ }
214
+ }
215
+ else {
216
+ agentScore = await scoreConnectedAgent(events);
217
+ }
218
+ }
219
+ const score = result.assertions.length === 0
220
+ ? 1
221
+ : result.assertions.filter((assertion) => assertion.passed).length / result.assertions.length;
222
+ console.log(JSON.stringify({
223
+ scenario_id: result.scenarioId,
224
+ event_count: result.eventIds.length,
225
+ assertions: result.assertions,
226
+ deterministic_score: subcommand === "score" ? score : undefined,
227
+ agent_score: agentScore
228
+ }, null, 2));
229
+ return 0;
230
+ }
231
+ throw new Error("Usage: loremcorp scenario <list|init|run|score>");
232
+ }
233
+ async function companyCommand(subcommand, args = []) {
234
+ if (subcommand === "init") {
235
+ const id = safeSlug(args[0], "company id");
236
+ const root = resolve(`companies/${id}`);
237
+ ensureDir(root);
238
+ writeFileSync(`${root}/loremcorp.company.ts`, `export default {
239
+ id: ${JSON.stringify(id)},
240
+ name: ${JSON.stringify(id)},
241
+ tier: "sketch",
242
+ defaultMode: "normal-operations"
243
+ };
244
+ `);
245
+ console.log(`Created sketch company scaffold: ${root}`);
246
+ return 0;
247
+ }
248
+ if (subcommand === "enrich") {
249
+ const target = args.find((arg) => arg.startsWith("--to="))?.slice("--to=".length) ?? "standard";
250
+ ensureDir("companies/halcyon");
251
+ const fill = await fillCompanyEnrichment(target);
252
+ const path = resolve(`companies/halcyon/ENRICHMENT.${target}.md`);
253
+ writeFileSync(path, fill.text);
254
+ console.log(`Wrote ${path} (${fill.provider}${fill.usedLlm ? "" : "; set a BYOK provider key for LLM-fill"})`);
255
+ return 0;
256
+ }
257
+ if (subcommand === "install") {
258
+ const id = safeSlug(args[0], "company id");
259
+ ensureDir(".loremcorp/companies");
260
+ writeFileSync(`.loremcorp/companies/${id}.json`, JSON.stringify({ id, installed_at: new Date().toISOString() }, null, 2));
261
+ console.log(`Installed company metadata: ${id}`);
262
+ return 0;
263
+ }
264
+ if (subcommand === "publish") {
265
+ console.log("Validated local company package. Registry publish adapter is not configured in OSS local mode.");
266
+ return 0;
267
+ }
268
+ if (subcommand !== "lint")
269
+ throw new Error("Usage: loremcorp company <lint|init|enrich|install|publish>");
270
+ const checks = [
271
+ ["standard hero count >= 20", halcyonCompany.heroPersonas.length >= 20],
272
+ ["all seven mocks have hum", halcyonCompany.baselineActivityRates.length === 7],
273
+ ["history covers >= 3 years", halcyonCompany.history.length >= 12],
274
+ ["launch core scenarios have voice docs", halcyonCompany.heroPersonas.every((persona) => persona.voiceDocPath.startsWith("personas/"))]
275
+ ];
276
+ for (const [name, passed] of checks) {
277
+ console.log(`${passed ? "✓" : "✕"} ${name}`);
278
+ }
279
+ return checks.every(([, passed]) => passed) ? 0 : 1;
280
+ }
281
+ function safeSlug(value, label) {
282
+ if (!value)
283
+ throw new Error(`Missing ${label}. Use lowercase letters, numbers, dots, underscores, or hyphens.`);
284
+ if (!/^[a-z0-9][a-z0-9._-]{0,80}$/i.test(value)) {
285
+ throw new Error(`Invalid ${label}: ${value}. Use lowercase letters, numbers, dots, underscores, or hyphens.`);
286
+ }
287
+ if (value.includes(".."))
288
+ throw new Error(`Invalid ${label}: ${value}. Parent path segments are not allowed.`);
289
+ return value;
290
+ }
291
+ async function agentCommand(subcommand, args) {
292
+ if (subcommand === "list") {
293
+ try {
294
+ console.log(readFileSync(".loremcorp/agent.json", "utf8"));
295
+ }
296
+ catch {
297
+ console.log("No connected agents.");
298
+ }
299
+ return 0;
300
+ }
301
+ if (subcommand === "disconnect") {
302
+ rmSync(".loremcorp/agent.json", { force: true });
303
+ console.log(`Disconnected agent${args[0] ? `: ${args[0]}` : ""}`);
304
+ return 0;
305
+ }
306
+ if (subcommand !== "connect")
307
+ throw new Error("Usage: loremcorp agent <connect|list|disconnect>");
308
+ const path = args[0];
309
+ if (!path)
310
+ throw new Error("Usage: loremcorp agent connect <manifest.json>");
311
+ const connected = await loadAgentFromPath(path);
312
+ validateAgentManifest(connected.manifest);
313
+ ensureDir(".loremcorp");
314
+ writeFileSync(".loremcorp/agent.json", JSON.stringify({ manifest_path: resolve(path), connected_at: new Date().toISOString() }, null, 2));
315
+ console.log(`Connected agent: ${connected.manifest.name} (${path})`);
316
+ return 0;
317
+ }
318
+ function snapshotCommand(subcommand, args) {
319
+ if (subcommand === "build") {
320
+ const company = args[0]?.startsWith("--") ? "halcyon" : args[0] ?? "halcyon";
321
+ const options = parseSnapshotOptions(args.filter((arg, index) => index !== 0 || arg.startsWith("--")));
322
+ const path = writeSnapshotArtifact({ ...options, company });
323
+ const result = verifySnapshot(path);
324
+ if (result.issues.length > 0) {
325
+ throw new Error(`Built snapshot failed verification:\n${result.issues.map((issue) => `- ${issue}`).join("\n")}`);
326
+ }
327
+ console.log(`Built snapshot: ${path}`);
328
+ console.log(JSON.stringify(result.artifact.manifest.counts, null, 2));
329
+ return 0;
330
+ }
331
+ if (subcommand === "pack") {
332
+ const company = args[0]?.startsWith("--") ? "halcyon" : args[0] ?? "halcyon";
333
+ const options = parseSnapshotOptions(args.filter((arg, index) => index !== 0 || arg.startsWith("--")));
334
+ const path = writeSnapshotBundle({ ...options, company });
335
+ const result = verifySnapshot(path);
336
+ if (result.issues.length > 0) {
337
+ throw new Error(`Packed snapshot failed verification:\n${result.issues.map((issue) => `- ${issue}`).join("\n")}`);
338
+ }
339
+ console.log(`Packed snapshot bundle: ${path}`);
340
+ console.log(" manifest.json");
341
+ console.log(" runtime.snapshot.json.gz");
342
+ console.log(" truth.snapshot.json.gz");
343
+ console.log(" provenance.json");
344
+ console.log(JSON.stringify(result.artifact.manifest.counts, null, 2));
345
+ return 0;
346
+ }
347
+ if (subcommand === "install") {
348
+ const path = args[0]?.startsWith("--") ? undefined : args[0];
349
+ const options = parseSnapshotOptions(args.filter((arg, index) => index !== 0 || arg.startsWith("--")));
350
+ const installed = installSnapshot(path, options);
351
+ console.log(`Installed snapshot: ${installed.path}`);
352
+ console.log(`${installed.artifact.manifest.company}/${installed.artifact.manifest.tier}/${installed.artifact.manifest.scale}@${installed.artifact.manifest.version}`);
353
+ return 0;
354
+ }
355
+ if (subcommand === "list") {
356
+ const snapshots = listInstalledSnapshots();
357
+ if (snapshots.length === 0) {
358
+ console.log("No installed snapshots.");
359
+ return 0;
360
+ }
361
+ for (const path of snapshots)
362
+ console.log(path);
363
+ return 0;
364
+ }
365
+ if (subcommand === "verify") {
366
+ const path = args[0]?.startsWith("--") ? undefined : args[0];
367
+ const result = verifySnapshot(path);
368
+ if (result.issues.length > 0) {
369
+ console.log(`✕ ${result.path}`);
370
+ for (const issue of result.issues)
371
+ console.log(` - ${issue}`);
372
+ return 1;
373
+ }
374
+ console.log(`✓ ${result.path}`);
375
+ console.log(JSON.stringify(result.artifact.manifest.counts, null, 2));
376
+ return 0;
377
+ }
378
+ throw new Error("Usage: loremcorp snapshot <build|pack|install|list|verify>");
379
+ }
380
+ async function mcpCommand(subcommand, globals) {
381
+ const runtime = await createLocalCliRuntime(globals);
382
+ if (subcommand === "stdio") {
383
+ await startLoremCorpMcpStdio(runtime.runtime);
384
+ return 0;
385
+ }
386
+ if (subcommand !== "tools")
387
+ throw new Error("Usage: loremcorp mcp <tools|stdio>");
388
+ for (const tool of runtime.mcp.listTools()) {
389
+ console.log(`${tool.name}\t${tool.description}`);
390
+ }
391
+ return 0;
392
+ }
393
+ function ensureDir(path) {
394
+ mkdirSync(path, { recursive: true });
395
+ }
396
+ function mockUrls() {
397
+ return {
398
+ slacker: "http://127.0.0.1:4000/slacker",
399
+ zendisk: "http://127.0.0.1:4000/zendisk",
400
+ salesfarce: "http://127.0.0.1:4000/salesfarce",
401
+ strype: "http://127.0.0.1:4000/strype",
402
+ gothub: "http://127.0.0.1:4000/gothub",
403
+ notian: "http://127.0.0.1:4000/notian",
404
+ halpcenter: "http://127.0.0.1:4000/halpcenter"
405
+ };
406
+ }
407
+ function parseGlobalArgs(argv) {
408
+ const args = [];
409
+ const globals = {};
410
+ for (let index = 0; index < argv.length; index += 1) {
411
+ const arg = argv[index];
412
+ if (arg === "--company" || arg === "--fork" || arg === "--seed") {
413
+ const key = arg.slice(2);
414
+ const value = argv[index + 1];
415
+ if (!value)
416
+ throw new Error(`Missing value for ${arg}`);
417
+ globals[key] = value;
418
+ index += 1;
419
+ }
420
+ else if (arg.startsWith("--company=") || arg.startsWith("--fork=") || arg.startsWith("--seed=")) {
421
+ const [key, value] = arg.slice(2).split("=", 2);
422
+ if (!key || !value)
423
+ throw new Error(`Invalid global flag: ${arg}`);
424
+ globals[key] = value;
425
+ }
426
+ else {
427
+ args.push(arg);
428
+ }
429
+ }
430
+ return { args, globals };
431
+ }
432
+ function shouldAutoOpen() {
433
+ return process.env.CI !== "true" && process.env.HEADLESS !== "1" && process.env.LOREMCORP_NO_OPEN !== "1";
434
+ }
435
+ function parseSnapshotOptions(args) {
436
+ const options = {};
437
+ for (const arg of args) {
438
+ if (!arg.startsWith("--"))
439
+ continue;
440
+ if (arg === "--with-llm-cache") {
441
+ options.withLlmCache = "true";
442
+ continue;
443
+ }
444
+ const [key, value] = arg.slice(2).split("=", 2);
445
+ if (!key || !value)
446
+ throw new Error(`Invalid snapshot option: ${arg}`);
447
+ options[key] = value;
448
+ }
449
+ const tier = options.tier;
450
+ if (tier && tier !== "lite" && tier !== "standard") {
451
+ throw new Error(`Invalid snapshot tier: ${tier}`);
452
+ }
453
+ const scale = options.scale;
454
+ if (scale && scale !== "preview" && scale !== "realistic") {
455
+ throw new Error(`Invalid snapshot scale: ${scale}`);
456
+ }
457
+ return {
458
+ tier: tier,
459
+ scale: scale,
460
+ seed: options.seed,
461
+ version: options.version,
462
+ out: options.out,
463
+ company: options.company,
464
+ withLlmCache: options.withLlmCache === "true"
465
+ };
466
+ }
467
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1,3 @@
1
+ export * from "./commands.js";
2
+ export * from "./runtime.js";
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./commands.js";
2
+ export * from "./runtime.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,8 @@
1
+ export interface FillResult {
2
+ readonly text: string;
3
+ readonly provider: string;
4
+ readonly usedLlm: boolean;
5
+ }
6
+ export declare function fillScenarioScaffold(id: string): Promise<FillResult>;
7
+ export declare function fillCompanyEnrichment(target: string): Promise<FillResult>;
8
+ //# sourceMappingURL=llm-fill.d.ts.map
@@ -0,0 +1,127 @@
1
+ import { generateText } from "ai";
2
+ import { createAnthropic } from "@ai-sdk/anthropic";
3
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
4
+ import { createOpenAI } from "@ai-sdk/openai";
5
+ import { halcyonCompany } from "@loremcorp/company-halcyon";
6
+ export async function fillScenarioScaffold(id) {
7
+ return fillWithOptionalLlm({
8
+ fallback: fallbackScenario(id),
9
+ prompt: `Create a LoremCorp scenario TypeScript file for Halcyon.
10
+
11
+ Scenario id: ${id}
12
+ Use this format exactly:
13
+ import { scenario } from "@loremcorp/scenarios";
14
+ export default scenario({ ... });
15
+
16
+ Return only TypeScript. The scenario must use Halcyon's existing hero personas and at least one mock surface.`,
17
+ system: "You write deterministic TypeScript scenario spines for LoremCorp. No markdown fences."
18
+ });
19
+ }
20
+ export async function fillCompanyEnrichment(target) {
21
+ return fillWithOptionalLlm({
22
+ fallback: fallbackCompanyEnrichment(target),
23
+ prompt: `Create a ${target} enrichment plan for a LoremCorp company.
24
+
25
+ Company:
26
+ ${JSON.stringify({
27
+ id: halcyonCompany.id,
28
+ name: halcyonCompany.name,
29
+ heroes: halcyonCompany.heroPersonas.length,
30
+ history: halcyonCompany.history.length,
31
+ mocks: halcyonCompany.baselineActivityRates.map((rate) => rate.mock)
32
+ }, null, 2)}
33
+
34
+ Return concise markdown with entity-row targets, persona gaps, scenario gaps, and mock data gaps.`,
35
+ system: "You enrich synthetic enterprise company catalogs for AI eval substrate quality."
36
+ });
37
+ }
38
+ async function fillWithOptionalLlm(options) {
39
+ const model = resolveModel();
40
+ if (!model) {
41
+ return {
42
+ text: options.fallback,
43
+ provider: "deterministic-fallback",
44
+ usedLlm: false
45
+ };
46
+ }
47
+ const result = await generateText({
48
+ model: model.model,
49
+ system: options.system,
50
+ prompt: options.prompt
51
+ });
52
+ return {
53
+ text: result.text,
54
+ provider: model.provider,
55
+ usedLlm: true
56
+ };
57
+ }
58
+ function resolveModel() {
59
+ if (process.env.LOREMCORP_ENABLE_LLM !== "1")
60
+ return undefined;
61
+ if (process.env.OPENAI_API_KEY) {
62
+ const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
63
+ return { provider: "openai", model: openai(process.env.LOREMCORP_LLM_MODEL ?? "gpt-4.1-mini") };
64
+ }
65
+ if (process.env.ANTHROPIC_API_KEY) {
66
+ const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
67
+ return { provider: "anthropic", model: anthropic(process.env.LOREMCORP_LLM_MODEL ?? "claude-3-5-haiku-latest") };
68
+ }
69
+ if (process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
70
+ const google = createGoogleGenerativeAI({ apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY });
71
+ return { provider: "google", model: google(process.env.LOREMCORP_LLM_MODEL ?? "gemini-2.0-flash") };
72
+ }
73
+ return undefined;
74
+ }
75
+ function fallbackScenario(id) {
76
+ return `import { scenario } from "@loremcorp/scenarios";
77
+
78
+ export default scenario({
79
+ id: ${JSON.stringify(id)},
80
+ company: "halcyon",
81
+ duration: "1 sim-days",
82
+ pathology: "custom",
83
+ mocks: ["mock-slacker", "mock-zendisk"],
84
+ heroPersonaIds: ["priya-iyer", "jamie-park"],
85
+ timeline: [
86
+ {
87
+ id: "initial-signal",
88
+ at: "T+0",
89
+ source: "mock-zendisk",
90
+ type: "zendisk.ticket.created",
91
+ entityId: "ent_halcyon_olivia_martens",
92
+ payload: { subject: "Custom scenario starter", priority: "normal" }
93
+ }
94
+ ],
95
+ assertions: [],
96
+ rubric: {
97
+ triage_speed: 1
98
+ }
99
+ });
100
+ `;
101
+ }
102
+ function fallbackCompanyEnrichment(target) {
103
+ return `# Halcyon ${target} Enrichment
104
+
105
+ LLM-fill did not run because it is opt-in.
106
+
107
+ Set \`LOREMCORP_ENABLE_LLM=1\` and one of:
108
+
109
+ - OPENAI_API_KEY
110
+ - ANTHROPIC_API_KEY
111
+ - GOOGLE_GENERATIVE_AI_API_KEY
112
+
113
+ Then rerun:
114
+
115
+ \`\`\`sh
116
+ loremcorp company enrich --to=${target}
117
+ \`\`\`
118
+
119
+ Minimum manual targets:
120
+
121
+ - Keep all 34 existing hero voice docs current.
122
+ - Add at least 1,000 entity rows per mock for Standard density.
123
+ - Add endpoint manifests beside each mock package.
124
+ - Keep \`quiet-week\` as a baseline scenario in every suite.
125
+ `;
126
+ }
127
+ //# sourceMappingURL=llm-fill.js.map
@@ -0,0 +1,19 @@
1
+ import { EventBus, InMemoryEngineStorage } from "@loremcorp/engine";
2
+ import { LocalMockRuntime, type MockService, type StartedMockServer } from "@loremcorp/mocks-shared";
3
+ export interface LocalCliRuntimeOptions {
4
+ readonly company?: string;
5
+ readonly fork?: string;
6
+ readonly seed?: string;
7
+ }
8
+ export declare function createLocalCliRuntime(options?: LocalCliRuntimeOptions): Promise<{
9
+ storage: InMemoryEngineStorage;
10
+ fork: import("@loremcorp/engine").ForkState;
11
+ bus: EventBus;
12
+ runtime: LocalMockRuntime;
13
+ services: readonly MockService[];
14
+ mcp: import("@loremcorp/mcp-overlay").McpOverlay;
15
+ snapshot: import("./snapshot-store.js").InstalledSnapshot | undefined;
16
+ }>;
17
+ export declare function createAllMockServices(runtime: LocalMockRuntime): readonly MockService[];
18
+ export declare function startAllMockServices(services: readonly MockService[]): Promise<readonly StartedMockServer[]>;
19
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1,53 @@
1
+ import { createCanonicalFork, EventBus, InMemoryEngineStorage } from "@loremcorp/engine";
2
+ import { createMcpOverlay } from "@loremcorp/mcp-overlay";
3
+ import { createHalcyonMockState, LocalMockRuntime, startMockService } from "@loremcorp/mocks-shared";
4
+ import { createGotHubMock } from "@loremcorp/mock-gothub";
5
+ import { createHalpcenterMock } from "@loremcorp/mock-halpcenter";
6
+ import { createNotianMock } from "@loremcorp/mock-notian";
7
+ import { createSalesfarceMock } from "@loremcorp/mock-salesfarce";
8
+ import { createSlackerMock } from "@loremcorp/mock-slacker";
9
+ import { createStrypeMock } from "@loremcorp/mock-strype";
10
+ import { createZendiskMock } from "@loremcorp/mock-zendisk";
11
+ import { loadCurrentSnapshot } from "./snapshot-store.js";
12
+ export async function createLocalCliRuntime(options = {}) {
13
+ if (options.company && options.company !== "halcyon") {
14
+ throw new Error(`Only Halcyon is installed in Phase 1 OSS local mode. Requested: ${options.company}`);
15
+ }
16
+ const storage = new InMemoryEngineStorage();
17
+ const fork = createCanonicalFork({
18
+ companyId: "halcyon",
19
+ id: options.fork ?? "halcyon-local",
20
+ seed: options.seed,
21
+ createdAt: "2026-03-15T14:00:00.000Z"
22
+ });
23
+ await storage.createFork(fork);
24
+ const bus = new EventBus(storage);
25
+ const installedSnapshot = loadCurrentSnapshot();
26
+ const runtime = new LocalMockRuntime({
27
+ forkId: fork.id,
28
+ state: installedSnapshot?.artifact.state ?? createHalcyonMockState(),
29
+ bus
30
+ });
31
+ const services = createAllMockServices(runtime);
32
+ const mcp = createMcpOverlay(runtime);
33
+ return { storage, fork, bus, runtime, services, mcp, snapshot: installedSnapshot };
34
+ }
35
+ export function createAllMockServices(runtime) {
36
+ return [
37
+ createSlackerMock(runtime),
38
+ createZendiskMock(runtime),
39
+ createSalesfarceMock(runtime),
40
+ createStrypeMock(runtime),
41
+ createGotHubMock(runtime),
42
+ createNotianMock(runtime),
43
+ createHalpcenterMock(runtime)
44
+ ];
45
+ }
46
+ export async function startAllMockServices(services) {
47
+ const started = [];
48
+ for (const service of services) {
49
+ started.push(await startMockService(service));
50
+ }
51
+ return started;
52
+ }
53
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1,44 @@
1
+ import { type SnapshotArtifact, type SnapshotScale, type SnapshotTier } from "@loremcorp/mocks-shared";
2
+ export interface SnapshotBuildOptions {
3
+ readonly company?: string;
4
+ readonly tier?: SnapshotTier;
5
+ readonly scale?: SnapshotScale;
6
+ readonly seed?: string;
7
+ readonly version?: string;
8
+ readonly out?: string;
9
+ readonly withLlmCache?: boolean;
10
+ }
11
+ export interface InstalledSnapshot {
12
+ readonly path: string;
13
+ readonly artifact: SnapshotArtifact;
14
+ }
15
+ export interface SnapshotBundleFile {
16
+ readonly path: string;
17
+ readonly encoding: "json" | "gzip-json";
18
+ readonly sha256: string;
19
+ readonly bytes: number;
20
+ }
21
+ export interface SnapshotBundleManifest {
22
+ readonly format: "loremcorp-snapshot-bundle";
23
+ readonly schemaVersion: 1;
24
+ readonly artifact: SnapshotArtifact["manifest"];
25
+ readonly files: {
26
+ readonly runtime: SnapshotBundleFile;
27
+ readonly truth: SnapshotBundleFile;
28
+ readonly provenance: SnapshotBundleFile;
29
+ };
30
+ }
31
+ export declare function buildSnapshotArtifact(options?: SnapshotBuildOptions): SnapshotArtifact;
32
+ export declare function writeSnapshotArtifact(options?: SnapshotBuildOptions): string;
33
+ export declare function writeSnapshotBundle(options?: SnapshotBuildOptions): string;
34
+ export declare function installSnapshot(inputPath: string | undefined, options?: SnapshotBuildOptions): InstalledSnapshot;
35
+ export declare function loadCurrentSnapshot(): InstalledSnapshot | undefined;
36
+ export declare function readSnapshotArtifact(path: string): SnapshotArtifact;
37
+ export declare function listInstalledSnapshots(): readonly string[];
38
+ export declare function verifySnapshot(path?: string): {
39
+ readonly path: string;
40
+ readonly artifact: SnapshotArtifact;
41
+ readonly issues: readonly string[];
42
+ };
43
+ export declare function readSnapshotBundle(root: string): SnapshotArtifact;
44
+ //# sourceMappingURL=snapshot-store.d.ts.map
@@ -0,0 +1,216 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
2
+ import { createHash } from "node:crypto";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { gzipSync, gunzipSync } from "node:zlib";
5
+ import { buildHalcyonSnapshot, validateSnapshotArtifact } from "@loremcorp/mocks-shared";
6
+ const currentPointerPath = ".loremcorp/snapshots/current.json";
7
+ export function buildSnapshotArtifact(options = {}) {
8
+ assertHalcyon(options.company);
9
+ return withChecksum(buildHalcyonSnapshot({
10
+ tier: options.tier ?? "standard",
11
+ scale: options.scale,
12
+ seed: options.seed,
13
+ version: options.version,
14
+ withLlmCache: options.withLlmCache
15
+ }));
16
+ }
17
+ export function writeSnapshotArtifact(options = {}) {
18
+ const artifact = buildSnapshotArtifact(options);
19
+ const path = resolve(options.out ?? `.loremcorp/artifacts/${artifact.manifest.company}-${artifact.manifest.tier}-${artifact.manifest.scale}-v${artifact.manifest.version}.snapshot.json`);
20
+ writeJson(path, artifact);
21
+ return path;
22
+ }
23
+ export function writeSnapshotBundle(options = {}) {
24
+ const artifact = buildSnapshotArtifact(options);
25
+ const issues = validateSnapshotArtifact(artifact);
26
+ if (issues.length > 0) {
27
+ throw new Error(`Snapshot validation failed:\n${issues.map((issue) => `- ${issue}`).join("\n")}`);
28
+ }
29
+ const root = resolve(options.out ?? `.loremcorp/artifacts/${artifact.manifest.company}-${artifact.manifest.tier}-${artifact.manifest.scale}-v${artifact.manifest.version}`);
30
+ mkdirSync(root, { recursive: true });
31
+ const runtimePath = "runtime.snapshot.json.gz";
32
+ const truthPath = "truth.snapshot.json.gz";
33
+ const provenancePath = "provenance.json";
34
+ writeGzipJson(join(root, runtimePath), {
35
+ manifest: artifact.manifest,
36
+ state: artifact.state
37
+ });
38
+ writeGzipJson(join(root, truthPath), {
39
+ manifest: artifact.manifest,
40
+ metadata: artifact.metadata
41
+ });
42
+ writeJson(join(root, provenancePath), {
43
+ company: artifact.manifest.company,
44
+ tier: artifact.manifest.tier,
45
+ scale: artifact.manifest.scale,
46
+ version: artifact.manifest.version,
47
+ seed: artifact.manifest.seed,
48
+ generated_at: artifact.manifest.generatedAt,
49
+ generator: artifact.manifest.generator,
50
+ source: "local deterministic generator",
51
+ artifact_checksum: artifact.manifest.checksum,
52
+ public_runtime_file: runtimePath,
53
+ hidden_truth_file: truthPath,
54
+ notes: [
55
+ "runtime.snapshot contains mock API state only.",
56
+ "truth.snapshot contains hidden validation metadata and must not be served through mock APIs."
57
+ ]
58
+ });
59
+ const bundle = {
60
+ format: "loremcorp-snapshot-bundle",
61
+ schemaVersion: 1,
62
+ artifact: artifact.manifest,
63
+ files: {
64
+ runtime: describeBundleFile(root, runtimePath, "gzip-json"),
65
+ truth: describeBundleFile(root, truthPath, "gzip-json"),
66
+ provenance: describeBundleFile(root, provenancePath, "json")
67
+ }
68
+ };
69
+ writeJson(join(root, "manifest.json"), bundle);
70
+ return root;
71
+ }
72
+ export function installSnapshot(inputPath, options = {}) {
73
+ const artifact = inputPath ? readSnapshotArtifact(inputPath) : buildSnapshotArtifact(options);
74
+ const issues = validateSnapshotArtifact(artifact);
75
+ if (issues.length > 0) {
76
+ throw new Error(`Snapshot validation failed:\n${issues.map((issue) => `- ${issue}`).join("\n")}`);
77
+ }
78
+ const installedPath = `.loremcorp/snapshots/${artifact.manifest.company}/${artifact.manifest.tier}/${artifact.manifest.scale}/${artifact.manifest.version}/snapshot.json`;
79
+ writeJson(installedPath, artifact);
80
+ writeJson(currentPointerPath, {
81
+ company: artifact.manifest.company,
82
+ tier: artifact.manifest.tier,
83
+ scale: artifact.manifest.scale,
84
+ version: artifact.manifest.version,
85
+ path: installedPath
86
+ });
87
+ return { path: installedPath, artifact };
88
+ }
89
+ export function loadCurrentSnapshot() {
90
+ if (!existsSync(currentPointerPath))
91
+ return undefined;
92
+ const pointer = JSON.parse(readFileSync(currentPointerPath, "utf8"));
93
+ if (!pointer.path || !existsSync(pointer.path))
94
+ return undefined;
95
+ return { path: pointer.path, artifact: readSnapshotArtifact(pointer.path) };
96
+ }
97
+ export function readSnapshotArtifact(path) {
98
+ const resolved = resolve(path);
99
+ if (statSync(resolved).isDirectory()) {
100
+ return readSnapshotBundle(resolved);
101
+ }
102
+ if (resolved.endsWith(".gz")) {
103
+ return JSON.parse(gunzipSync(readFileSync(resolved)).toString("utf8"));
104
+ }
105
+ return JSON.parse(readFileSync(resolved, "utf8"));
106
+ }
107
+ export function listInstalledSnapshots() {
108
+ const root = ".loremcorp/snapshots";
109
+ if (!existsSync(root))
110
+ return [];
111
+ return collectSnapshotFiles(root);
112
+ }
113
+ export function verifySnapshot(path) {
114
+ const resolvedPath = path ?? loadCurrentSnapshot()?.path;
115
+ if (!resolvedPath)
116
+ throw new Error("No snapshot path provided and no current snapshot is installed.");
117
+ const artifact = readSnapshotArtifact(resolvedPath);
118
+ const issues = [...validateSnapshotArtifact(artifact)];
119
+ const expected = withChecksum({ ...artifact, manifest: { ...artifact.manifest, checksum: undefined } }).manifest.checksum;
120
+ if (artifact.manifest.checksum && artifact.manifest.checksum !== expected) {
121
+ issues.push(`checksum mismatch: expected ${expected} got ${artifact.manifest.checksum}`);
122
+ }
123
+ return { path: resolvedPath, artifact, issues };
124
+ }
125
+ export function readSnapshotBundle(root) {
126
+ const manifestPath = join(root, "manifest.json");
127
+ const bundle = JSON.parse(readFileSync(manifestPath, "utf8"));
128
+ if (bundle.format !== "loremcorp-snapshot-bundle" || bundle.schemaVersion !== 1) {
129
+ throw new Error(`Unsupported snapshot bundle manifest: ${manifestPath}`);
130
+ }
131
+ verifyBundleFile(root, bundle.files.runtime);
132
+ verifyBundleFile(root, bundle.files.truth);
133
+ verifyBundleFile(root, bundle.files.provenance);
134
+ const runtime = readBundleJson(root, bundle.files.runtime);
135
+ const truth = readBundleJson(root, bundle.files.truth);
136
+ if (runtime.manifest.checksum !== truth.manifest.checksum) {
137
+ throw new Error("Snapshot bundle runtime/truth manifest checksums differ.");
138
+ }
139
+ if (runtime.manifest.checksum !== bundle.artifact.checksum) {
140
+ throw new Error("Snapshot bundle manifest checksum does not match runtime payload.");
141
+ }
142
+ return {
143
+ manifest: runtime.manifest,
144
+ state: runtime.state,
145
+ metadata: truth.metadata
146
+ };
147
+ }
148
+ function withChecksum(artifact) {
149
+ const { checksum: _checksum, ...manifest } = artifact.manifest;
150
+ const checksum = createHash("sha256")
151
+ .update(JSON.stringify({ manifest, state: artifact.state, metadata: artifact.metadata }))
152
+ .digest("hex");
153
+ return {
154
+ ...artifact,
155
+ manifest: {
156
+ ...manifest,
157
+ checksum
158
+ }
159
+ };
160
+ }
161
+ function writeJson(path, value) {
162
+ mkdirSync(dirname(path), { recursive: true });
163
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
164
+ }
165
+ function writeGzipJson(path, value) {
166
+ mkdirSync(dirname(path), { recursive: true });
167
+ writeFileSync(path, gzipSync(Buffer.from(JSON.stringify(value), "utf8")));
168
+ }
169
+ function readBundleJson(root, file) {
170
+ const buffer = readFileSync(join(root, file.path));
171
+ if (file.encoding === "gzip-json") {
172
+ return JSON.parse(gunzipSync(buffer).toString("utf8"));
173
+ }
174
+ return JSON.parse(buffer.toString("utf8"));
175
+ }
176
+ function describeBundleFile(root, path, encoding) {
177
+ const buffer = readFileSync(join(root, path));
178
+ return {
179
+ path,
180
+ encoding,
181
+ sha256: sha256(buffer),
182
+ bytes: buffer.byteLength
183
+ };
184
+ }
185
+ function verifyBundleFile(root, file) {
186
+ const buffer = readFileSync(join(root, file.path));
187
+ const actualSha = sha256(buffer);
188
+ if (file.bytes !== buffer.byteLength) {
189
+ throw new Error(`Snapshot bundle file size mismatch for ${file.path}: expected ${file.bytes} got ${buffer.byteLength}`);
190
+ }
191
+ if (file.sha256 !== actualSha) {
192
+ throw new Error(`Snapshot bundle file checksum mismatch for ${file.path}: expected ${file.sha256} got ${actualSha}`);
193
+ }
194
+ }
195
+ function sha256(buffer) {
196
+ return createHash("sha256").update(buffer).digest("hex");
197
+ }
198
+ function collectSnapshotFiles(root) {
199
+ const files = [];
200
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
201
+ const path = join(root, entry.name);
202
+ if (entry.isDirectory()) {
203
+ files.push(...collectSnapshotFiles(path));
204
+ }
205
+ else if (entry.isFile() && basename(path) === "snapshot.json") {
206
+ files.push(path);
207
+ }
208
+ }
209
+ return files.sort();
210
+ }
211
+ function assertHalcyon(company = "halcyon") {
212
+ if (company !== "halcyon") {
213
+ throw new Error(`Only Halcyon snapshots are supported in Phase 1. Requested: ${company}`);
214
+ }
215
+ }
216
+ //# sourceMappingURL=snapshot-store.js.map
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "loremcorp",
3
+ "version": "0.1.0",
4
+ "description": "CLI for running LoremCorp synthetic companies and mock SaaS APIs.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/danielthedm/loremcorp.git",
10
+ "directory": "packages/cli"
11
+ },
12
+ "homepage": "https://github.com/danielthedm/loremcorp#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/danielthedm/loremcorp/issues"
15
+ },
16
+ "engines": {
17
+ "node": ">=22"
18
+ },
19
+ "files": [
20
+ "dist/**/*.js",
21
+ "dist/**/*.d.ts",
22
+ "!dist/**/*.test.js",
23
+ "!dist/**/*.test.d.ts",
24
+ "!dist/**/*.map"
25
+ ],
26
+ "bin": {
27
+ "loremcorp": "./dist/bin/loremcorp.js"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
35
+ "dependencies": {
36
+ "@ai-sdk/anthropic": "^3.0.77",
37
+ "@ai-sdk/google": "^3.0.72",
38
+ "@ai-sdk/openai": "^3.0.63",
39
+ "ai": "^6.0.177",
40
+ "@loremcorp/company-halcyon": "0.1.0",
41
+ "@loremcorp/engine": "0.1.0",
42
+ "@loremcorp/mcp-overlay": "0.1.0",
43
+ "@loremcorp/manifest": "0.1.0",
44
+ "@loremcorp/mock-gothub": "0.1.0",
45
+ "@loremcorp/mock-halpcenter": "0.1.0",
46
+ "@loremcorp/mock-strype": "0.1.0",
47
+ "@loremcorp/mocks-shared": "0.1.0",
48
+ "@loremcorp/mock-zendisk": "0.1.0",
49
+ "@loremcorp/mock-notian": "0.1.0",
50
+ "@loremcorp/mock-salesfarce": "0.1.0",
51
+ "@loremcorp/scenarios": "0.1.0",
52
+ "@loremcorp/mock-slacker": "0.1.0",
53
+ "@loremcorp/sdk": "0.1.0",
54
+ "@loremcorp/mock-gateway": "0.0.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc -b"
58
+ }
59
+ }