@ramarivera/coding-agent-langfuse 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,3 +34,50 @@ npx @ramarivera/coding-agent-langfuse@latest \
34
34
 
35
35
  The importer is fail-fast: the first failed OTLP POST stops the run, prints the
36
36
  real network cause, and preserves local state so reruns resume cleanly.
37
+
38
+ ## Follow as a host service
39
+
40
+ Install a live follower directly from npm. The generated service keeps inference
41
+ outside any gateway: agents keep calling their normal providers, while this tool
42
+ tails local histories and posts Langfuse OTLP traces.
43
+
44
+ Preview the service without touching the host:
45
+
46
+ ```sh
47
+ npx @ramarivera/coding-agent-langfuse@latest service print \
48
+ --platform linux \
49
+ --agents codex,pi \
50
+ --endpoint https://langfuse.ai.roxasroot.net/otel/v1/traces
51
+ ```
52
+
53
+ Install and start it on the current host:
54
+
55
+ ```sh
56
+ npx @ramarivera/coding-agent-langfuse@latest service install \
57
+ --agents codex,pi \
58
+ --endpoint https://langfuse.ai.roxasroot.net/otel/v1/traces
59
+ ```
60
+
61
+ The service installer supports:
62
+
63
+ - macOS: LaunchAgent under `~/Library/LaunchAgents`
64
+ - Linux: systemd user unit under `~/.config/systemd/user`
65
+ - Windows: scheduled task installer script under `%APPDATA%\\coding-agent-langfuse`
66
+
67
+ Use `--dry-run` to print the exact file and commands, `--no-start` to only write
68
+ the service file, and `service uninstall` to remove the service registration.
69
+
70
+ ## Backfill windows
71
+
72
+ Backfill only a timeframe when repairing a host or replaying a recent window:
73
+
74
+ ```sh
75
+ npx @ramarivera/coding-agent-langfuse@latest \
76
+ --agents claude,codex,grok,pi,opencode \
77
+ --since 2026-05-31T00:00:00Z \
78
+ --until 2026-06-01T00:00:00Z \
79
+ --endpoint https://langfuse.ai.roxasroot.net/otel/v1/traces
80
+ ```
81
+
82
+ Deduplication is state-file based and keyed by agent, session id, and source
83
+ record id. Reuse the same `--state` path for repeat repairs on a host.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const moduleUrl = new URL("../dist/backfill.js", import.meta.url);
2
+ const moduleUrl = new URL("../dist/cli.js", import.meta.url);
3
3
  const { main } = await import(moduleUrl.href);
4
4
 
5
5
  await main(process.argv.slice(2));
@@ -60,6 +60,8 @@ type FollowSummary = RunSummary & {
60
60
  iterations: number;
61
61
  follow: true;
62
62
  };
63
+ declare const allAgents: AgentName[];
64
+ declare const defaultEndpoint = "https://langfuse.ai.roxasroot.net/otel/v1/traces";
63
65
  declare function parseArgs(argv: string[]): BackfillOptions;
64
66
  declare function codexEvents(homeDir: string): BackfillEvent[];
65
67
  declare function claudeEvents(homeDir: string): BackfillEvent[];
@@ -78,4 +80,4 @@ declare function discoverEvents(options: BackfillOptions): BackfillEvent[];
78
80
  declare function run(options: BackfillOptions): Promise<RunSummary>;
79
81
  declare function follow(options: BackfillOptions): Promise<FollowSummary>;
80
82
  declare function main(argv?: string[]): Promise<RunSummary | FollowSummary>;
81
- export { type BackfillEvent, type BackfillOptions, claudeEvents, codexEvents, discoverEvents, fingerprint, follow, grokEvents, main, opencodeEvents, parseArgs, piEvents, run, toOtlp, };
83
+ export { type BackfillEvent, type BackfillOptions, type AgentName, allAgents, claudeEvents, codexEvents, defaultEndpoint, discoverEvents, fingerprint, follow, grokEvents, main, opencodeEvents, parseArgs, piEvents, run, toOtlp, };
package/dist/backfill.js CHANGED
@@ -1593,4 +1593,4 @@ if (import.meta.url === `file://${process.argv[1]}`) {
1593
1593
  process.exit(1);
1594
1594
  }
1595
1595
  }
1596
- export { claudeEvents, codexEvents, discoverEvents, fingerprint, follow, grokEvents, main, opencodeEvents, parseArgs, piEvents, run, toOtlp, };
1596
+ export { allAgents, claudeEvents, codexEvents, defaultEndpoint, discoverEvents, fingerprint, follow, grokEvents, main, opencodeEvents, parseArgs, piEvents, run, toOtlp, };
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ declare function main(argv?: string[]): Promise<void>;
3
+ export { main };
package/dist/cli.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { main as backfillMain } from "./backfill.js";
3
+ import { serviceMain } from "./service.js";
4
+ async function main(argv = process.argv.slice(2)) {
5
+ if (argv[0] === "service") {
6
+ await serviceMain(argv.slice(1));
7
+ return;
8
+ }
9
+ await backfillMain(argv);
10
+ }
11
+ await main();
12
+ export { main };
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { codexEvents, discoverEvents, fingerprint, parseArgs, piEvents, run, toOtlp, } from "./backfill.js";
2
+ export { buildServicePlan, parseServiceArgs, serviceMain, } from "./service.js";
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export { codexEvents, discoverEvents, fingerprint, parseArgs, piEvents, run, toOtlp, } from "./backfill.js";
2
+ export { buildServicePlan, parseServiceArgs, serviceMain, } from "./service.js";
@@ -0,0 +1,35 @@
1
+ type AgentName = "claude" | "codex" | "grok" | "opencode" | "pi";
2
+ type ServicePlatform = "darwin" | "linux" | "win32";
3
+ type ServiceAction = "install" | "uninstall" | "print";
4
+ type ServiceOptions = {
5
+ action: ServiceAction;
6
+ platform: ServicePlatform;
7
+ agents: AgentName[];
8
+ endpoint: string;
9
+ statePath: string;
10
+ homeDir: string;
11
+ name: string;
12
+ packageSpec: string;
13
+ batchSize: number;
14
+ pollIntervalMs: number;
15
+ postDelayMs: number;
16
+ since?: string;
17
+ dryRun: boolean;
18
+ start: boolean;
19
+ workingDirectory: string;
20
+ pathEnv: string;
21
+ };
22
+ type ServicePlan = {
23
+ platform: ServicePlatform;
24
+ action: ServiceAction;
25
+ name: string;
26
+ path: string;
27
+ content?: string;
28
+ command: string[];
29
+ postInstallCommands: string[][];
30
+ uninstallCommands: string[][];
31
+ };
32
+ declare function parseServiceArgs(argv: string[]): ServiceOptions;
33
+ declare function buildServicePlan(options: ServiceOptions): ServicePlan;
34
+ declare function serviceMain(argv?: string[]): Promise<ServicePlan>;
35
+ export { type ServiceOptions, type ServicePlan, buildServicePlan, parseServiceArgs, serviceMain, };
@@ -0,0 +1,422 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, rmSync, writeFileSync, } from "node:fs";
3
+ import { homedir, platform as osPlatform } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ const defaultPackageSpec = "@ramarivera/coding-agent-langfuse@latest";
6
+ const defaultEndpoint = "https://langfuse.ai.roxasroot.net/otel/v1/traces";
7
+ const allAgents = ["claude", "codex", "grok", "opencode", "pi"];
8
+ function serviceUsage() {
9
+ return `Usage:
10
+ coding-agent-langfuse service install [options]
11
+ coding-agent-langfuse service print [options]
12
+ coding-agent-langfuse service uninstall [options]
13
+
14
+ Service options:
15
+ --platform NAME Target platform: darwin, linux, win32 (default: current)
16
+ --name NAME Service name/label/unit name
17
+ --agents LIST Comma-separated agents: claude,codex,grok,opencode,pi
18
+ --endpoint URL OTLP HTTP traces endpoint (default: ${defaultEndpoint})
19
+ --state PATH Dedupe state file
20
+ --home PATH Home directory to scan (default: current user home)
21
+ --package-spec SPEC npx package spec (default: ${defaultPackageSpec})
22
+ --batch-size N OTLP spans per POST (default: 10)
23
+ --poll-interval-ms N Delay between --follow scans (default: 5000)
24
+ --post-delay-ms N Delay after each successful OTLP POST (default: 0)
25
+ --since ISO_OR_MS Optional lower bound for events the follower may send
26
+ --working-directory DIR Directory the service starts in (default: --home)
27
+ --path VALUE PATH value injected into the service environment
28
+ --dry-run Print the service plan without writing or running commands
29
+ --no-start Write the service but do not enable/start it
30
+ --help Show this help
31
+ `;
32
+ }
33
+ function parseServiceArgs(argv) {
34
+ const action = parseServiceAction(argv[0]);
35
+ if (argv.includes("--help") || argv.includes("-h")) {
36
+ console.log(serviceUsage());
37
+ process.exit(0);
38
+ }
39
+ let platform = currentServicePlatform();
40
+ let agents = [...allAgents];
41
+ let endpoint = process.env.LANGFUSE_BACKFILL_ENDPOINT ?? defaultEndpoint;
42
+ let homeDir = process.env.HOME ?? homedir();
43
+ let statePath = "";
44
+ let name = "";
45
+ let packageSpec = defaultPackageSpec;
46
+ let batchSize = 10;
47
+ let pollIntervalMs = 5_000;
48
+ let postDelayMs = 0;
49
+ let since;
50
+ let dryRun = false;
51
+ let start = true;
52
+ let workingDirectory = "";
53
+ let pathEnv = "";
54
+ for (let i = 1; i < argv.length; i++) {
55
+ const arg = argv[i];
56
+ const next = () => {
57
+ const value = argv[++i];
58
+ if (!value)
59
+ throw new Error(`Missing value for ${arg}`);
60
+ return value;
61
+ };
62
+ if (arg === "--platform") {
63
+ platform = parsePlatform(next());
64
+ }
65
+ else if (arg === "--name") {
66
+ name = next();
67
+ }
68
+ else if (arg === "--agents") {
69
+ agents = parseAgents(next());
70
+ }
71
+ else if (arg === "--endpoint") {
72
+ endpoint = next();
73
+ }
74
+ else if (arg === "--state") {
75
+ statePath = next();
76
+ }
77
+ else if (arg === "--home") {
78
+ homeDir = next();
79
+ }
80
+ else if (arg === "--package-spec") {
81
+ packageSpec = next();
82
+ }
83
+ else if (arg === "--batch-size") {
84
+ batchSize = parsePositiveInt(arg, next());
85
+ }
86
+ else if (arg === "--poll-interval-ms") {
87
+ pollIntervalMs = parsePositiveInt(arg, next());
88
+ }
89
+ else if (arg === "--post-delay-ms") {
90
+ postDelayMs = parseNonNegativeInt(arg, next());
91
+ }
92
+ else if (arg === "--since") {
93
+ since = next();
94
+ }
95
+ else if (arg === "--working-directory") {
96
+ workingDirectory = next();
97
+ }
98
+ else if (arg === "--path") {
99
+ pathEnv = next();
100
+ }
101
+ else if (arg === "--dry-run") {
102
+ dryRun = true;
103
+ }
104
+ else if (arg === "--no-start") {
105
+ start = false;
106
+ }
107
+ else {
108
+ throw new Error(`Unknown service argument '${arg}'`);
109
+ }
110
+ }
111
+ if (agents.length === 0)
112
+ throw new Error("--agents must include at least one agent");
113
+ name ||= defaultServiceName(agents, platform);
114
+ workingDirectory ||= homeDir;
115
+ pathEnv ||= defaultPathEnv(homeDir, platform);
116
+ statePath ||= join(homeDir, ".local/state/coding-agent-langfuse", `${name}.json`);
117
+ return {
118
+ action,
119
+ platform,
120
+ agents,
121
+ endpoint,
122
+ statePath,
123
+ homeDir,
124
+ name,
125
+ packageSpec,
126
+ batchSize,
127
+ pollIntervalMs,
128
+ postDelayMs,
129
+ since,
130
+ dryRun,
131
+ start,
132
+ workingDirectory,
133
+ pathEnv,
134
+ };
135
+ }
136
+ function buildServicePlan(options) {
137
+ const command = buildFollowCommand(options);
138
+ if (options.platform === "darwin") {
139
+ const path = join(options.homeDir, "Library/LaunchAgents", `${options.name}.plist`);
140
+ return {
141
+ platform: options.platform,
142
+ action: options.action,
143
+ name: options.name,
144
+ path,
145
+ content: renderLaunchdPlist(options, command),
146
+ command,
147
+ postInstallCommands: options.start
148
+ ? [
149
+ ["launchctl", "bootstrap", `gui/${process.getuid?.() ?? 501}`, path],
150
+ ["launchctl", "kickstart", "-k", `gui/${process.getuid?.() ?? 501}/${options.name}`],
151
+ ]
152
+ : [],
153
+ uninstallCommands: [
154
+ ["launchctl", "bootout", `gui/${process.getuid?.() ?? 501}`, path],
155
+ ],
156
+ };
157
+ }
158
+ if (options.platform === "linux") {
159
+ const path = join(options.homeDir, ".config/systemd/user", `${options.name}.service`);
160
+ return {
161
+ platform: options.platform,
162
+ action: options.action,
163
+ name: options.name,
164
+ path,
165
+ content: renderSystemdUnit(options, command),
166
+ command,
167
+ postInstallCommands: options.start
168
+ ? [
169
+ ["systemctl", "--user", "daemon-reload"],
170
+ ["systemctl", "--user", "enable", "--now", `${options.name}.service`],
171
+ ]
172
+ : [["systemctl", "--user", "daemon-reload"]],
173
+ uninstallCommands: [
174
+ ["systemctl", "--user", "disable", "--now", `${options.name}.service`],
175
+ ["systemctl", "--user", "daemon-reload"],
176
+ ],
177
+ };
178
+ }
179
+ const path = join(process.env.APPDATA ?? join(options.homeDir, "AppData/Roaming"), "coding-agent-langfuse", `${options.name}.ps1`);
180
+ const taskName = `CodingAgentLangfuse-${options.name}`;
181
+ return {
182
+ platform: options.platform,
183
+ action: options.action,
184
+ name: options.name,
185
+ path,
186
+ content: renderWindowsScript(command),
187
+ command,
188
+ postInstallCommands: options.start
189
+ ? [
190
+ [
191
+ "powershell.exe",
192
+ "-NoProfile",
193
+ "-ExecutionPolicy",
194
+ "Bypass",
195
+ "-File",
196
+ path,
197
+ "-Install",
198
+ "-TaskName",
199
+ taskName,
200
+ ],
201
+ ]
202
+ : [],
203
+ uninstallCommands: [
204
+ [
205
+ "powershell.exe",
206
+ "-NoProfile",
207
+ "-Command",
208
+ `Unregister-ScheduledTask -TaskName ${powershellString(taskName)} -Confirm:$false -ErrorAction SilentlyContinue`,
209
+ ],
210
+ ],
211
+ };
212
+ }
213
+ async function serviceMain(argv = process.argv.slice(2)) {
214
+ const options = parseServiceArgs(argv);
215
+ const plan = buildServicePlan(options);
216
+ if (options.action === "print" || options.dryRun) {
217
+ console.log(JSON.stringify(plan, null, 2));
218
+ return plan;
219
+ }
220
+ if (options.action === "install") {
221
+ if (!plan.content)
222
+ throw new Error("Service plan is missing content");
223
+ mkdirSync(dirname(plan.path), { recursive: true });
224
+ writeFileSync(plan.path, plan.content);
225
+ runCommands(plan.postInstallCommands);
226
+ console.log(JSON.stringify(plan, null, 2));
227
+ return plan;
228
+ }
229
+ runCommands(plan.uninstallCommands, { ignoreFailure: true });
230
+ if (existsSync(plan.path))
231
+ rmSync(plan.path);
232
+ console.log(JSON.stringify(plan, null, 2));
233
+ return plan;
234
+ }
235
+ function buildFollowCommand(options) {
236
+ const command = [
237
+ options.platform === "win32" ? "npx.cmd" : "npx",
238
+ "--yes",
239
+ options.packageSpec,
240
+ "--agents",
241
+ options.agents.join(","),
242
+ "--endpoint",
243
+ options.endpoint,
244
+ "--state",
245
+ options.statePath,
246
+ "--home",
247
+ options.homeDir,
248
+ "--batch-size",
249
+ String(options.batchSize),
250
+ "--poll-interval-ms",
251
+ String(options.pollIntervalMs),
252
+ "--post-delay-ms",
253
+ String(options.postDelayMs),
254
+ "--follow",
255
+ ];
256
+ if (options.since)
257
+ command.push("--since", options.since);
258
+ return command;
259
+ }
260
+ function renderSystemdUnit(options, command) {
261
+ return `[Unit]
262
+ Description=Coding Agent Langfuse follower (${options.agents.join(",")})
263
+ After=network-online.target
264
+ Wants=network-online.target
265
+
266
+ [Service]
267
+ Type=simple
268
+ ExecStart=${systemdCommand(command)}
269
+ Restart=always
270
+ RestartSec=15
271
+ StartLimitIntervalSec=60
272
+ StartLimitBurst=10
273
+ WorkingDirectory=${systemdQuote(options.workingDirectory)}
274
+ Environment=${systemdQuote(`PATH=${options.pathEnv}`)}
275
+ Environment=LANGFUSE_BACKFILL_ENDPOINT=${options.endpoint}
276
+
277
+ [Install]
278
+ WantedBy=default.target
279
+ `;
280
+ }
281
+ function renderLaunchdPlist(options, command) {
282
+ return `<?xml version="1.0" encoding="UTF-8"?>
283
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
284
+ <plist version="1.0">
285
+ <dict>
286
+ <key>Label</key>
287
+ <string>${escapeXml(options.name)}</string>
288
+ <key>ProgramArguments</key>
289
+ <array>
290
+ ${command.map((part) => ` <string>${escapeXml(part)}</string>`).join("\n")}
291
+ </array>
292
+ <key>EnvironmentVariables</key>
293
+ <dict>
294
+ <key>PATH</key>
295
+ <string>${escapeXml(options.pathEnv)}</string>
296
+ <key>LANGFUSE_BACKFILL_ENDPOINT</key>
297
+ <string>${escapeXml(options.endpoint)}</string>
298
+ </dict>
299
+ <key>WorkingDirectory</key>
300
+ <string>${escapeXml(options.workingDirectory)}</string>
301
+ <key>RunAtLoad</key>
302
+ <true/>
303
+ <key>KeepAlive</key>
304
+ <true/>
305
+ <key>StandardOutPath</key>
306
+ <string>${escapeXml(join(options.homeDir, "Library/Logs", `${options.name}.out.log`))}</string>
307
+ <key>StandardErrorPath</key>
308
+ <string>${escapeXml(join(options.homeDir, "Library/Logs", `${options.name}.err.log`))}</string>
309
+ </dict>
310
+ </plist>
311
+ `;
312
+ }
313
+ function renderWindowsScript(command) {
314
+ const commandArray = command.map(powershellString).join(", ");
315
+ return `param(
316
+ [switch]$Install,
317
+ [string]$TaskName = "CodingAgentLangfuse"
318
+ )
319
+
320
+ $Command = @(${commandArray})
321
+ $Action = New-ScheduledTaskAction -Execute $Command[0] -Argument (($Command | Select-Object -Skip 1) -join " ")
322
+ $Trigger = New-ScheduledTaskTrigger -AtLogOn
323
+ $Settings = New-ScheduledTaskSettingsSet -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1)
324
+
325
+ if ($Install) {
326
+ Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Settings $Settings -Force | Out-Null
327
+ Start-ScheduledTask -TaskName $TaskName
328
+ }
329
+ `;
330
+ }
331
+ function parseServiceAction(value) {
332
+ if (value === "install" || value === "uninstall" || value === "print")
333
+ return value;
334
+ throw new Error(`Expected service action install, uninstall, or print; got '${value ?? ""}'`);
335
+ }
336
+ function parsePlatform(value) {
337
+ if (value === "darwin" || value === "linux" || value === "win32")
338
+ return value;
339
+ throw new Error(`Unsupported platform '${value}'`);
340
+ }
341
+ function currentServicePlatform() {
342
+ return parsePlatform(osPlatform());
343
+ }
344
+ function parseAgents(value) {
345
+ return value.split(",").map((item) => {
346
+ const agent = item.trim();
347
+ if (!allAgents.includes(agent))
348
+ throw new Error(`Unknown agent '${item}'`);
349
+ return agent;
350
+ });
351
+ }
352
+ function defaultServiceName(agents, platform) {
353
+ const suffix = agents.join("-");
354
+ return platform === "darwin"
355
+ ? `net.roxasroot.coding-agent-langfuse.${suffix}`
356
+ : `coding-agent-langfuse-${suffix}`;
357
+ }
358
+ function defaultPathEnv(homeDir, platform) {
359
+ if (platform === "win32") {
360
+ return [
361
+ "%APPDATA%\\npm",
362
+ "%ProgramFiles%\\nodejs",
363
+ "%SystemRoot%\\System32",
364
+ "%SystemRoot%",
365
+ ].join(";");
366
+ }
367
+ return [
368
+ join(homeDir, ".local/share/mise/shims"),
369
+ join(homeDir, ".local/bin"),
370
+ "/opt/homebrew/bin",
371
+ "/usr/local/bin",
372
+ "/usr/bin",
373
+ "/bin",
374
+ "/usr/sbin",
375
+ "/sbin",
376
+ ].join(":");
377
+ }
378
+ function parsePositiveInt(flag, value) {
379
+ const parsed = Number.parseInt(value, 10);
380
+ if (!Number.isFinite(parsed) || parsed < 1) {
381
+ throw new Error(`${flag} must be a positive integer`);
382
+ }
383
+ return parsed;
384
+ }
385
+ function parseNonNegativeInt(flag, value) {
386
+ const parsed = Number.parseInt(value, 10);
387
+ if (!Number.isFinite(parsed) || parsed < 0) {
388
+ throw new Error(`${flag} must be a non-negative integer`);
389
+ }
390
+ return parsed;
391
+ }
392
+ function runCommands(commands, options = {}) {
393
+ for (const command of commands) {
394
+ try {
395
+ execFileSync(command[0], command.slice(1), { stdio: "inherit" });
396
+ }
397
+ catch (error) {
398
+ if (!options.ignoreFailure)
399
+ throw error;
400
+ }
401
+ }
402
+ }
403
+ function systemdCommand(command) {
404
+ return ["/usr/bin/env", ...command].map(systemdQuote).join(" ");
405
+ }
406
+ function systemdQuote(value) {
407
+ if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(value))
408
+ return value;
409
+ return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
410
+ }
411
+ function powershellString(value) {
412
+ return `'${value.replaceAll("'", "''")}'`;
413
+ }
414
+ function escapeXml(value) {
415
+ return value
416
+ .replaceAll("&", "&amp;")
417
+ .replaceAll("<", "&lt;")
418
+ .replaceAll(">", "&gt;")
419
+ .replaceAll('"', "&quot;")
420
+ .replaceAll("'", "&apos;");
421
+ }
422
+ export { buildServicePlan, parseServiceArgs, serviceMain, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramarivera/coding-agent-langfuse",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "Universal coding-agent Langfuse backfiller and live OTLP helpers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,7 +11,8 @@
11
11
  },
12
12
  "exports": {
13
13
  ".": "./dist/index.js",
14
- "./backfill": "./dist/backfill.js"
14
+ "./backfill": "./dist/backfill.js",
15
+ "./service": "./dist/service.js"
15
16
  },
16
17
  "files": [
17
18
  "bin",
@@ -23,7 +24,7 @@
23
24
  "build": "tsc -p tsconfig.build.json",
24
25
  "check": "tsc --noEmit",
25
26
  "test": "node --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types --test test/**/*.test.ts",
26
- "test:e2e": "node --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types --test e2e/test/**/*.test.ts",
27
+ "test:e2e": "npm run build && node --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types --test e2e/test/**/*.test.ts",
27
28
  "pack:dry-run": "npm pack --dry-run",
28
29
  "prepack": "npm run build"
29
30
  },