libretto 0.6.11 → 0.6.13

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 (130) hide show
  1. package/README.md +7 -8
  2. package/README.template.md +7 -8
  3. package/dist/cli/cli.js +0 -22
  4. package/dist/cli/commands/browser.js +18 -24
  5. package/dist/cli/commands/execution.js +254 -234
  6. package/dist/cli/commands/experiments.js +100 -0
  7. package/dist/cli/commands/setup.js +3 -310
  8. package/dist/cli/commands/shared.js +10 -0
  9. package/dist/cli/commands/snapshot.js +46 -64
  10. package/dist/cli/commands/status.js +1 -40
  11. package/dist/cli/core/browser.js +303 -124
  12. package/dist/cli/core/config.js +5 -6
  13. package/dist/cli/core/context.js +4 -0
  14. package/dist/cli/core/daemon/config.js +0 -6
  15. package/dist/cli/core/daemon/daemon.js +497 -90
  16. package/dist/cli/core/daemon/ipc.js +170 -129
  17. package/dist/cli/core/daemon/snapshot.js +48 -9
  18. package/dist/cli/core/experiments.js +39 -0
  19. package/dist/cli/core/session.js +5 -4
  20. package/dist/cli/core/skill-version.js +2 -1
  21. package/dist/cli/core/workflow-runner/runner.js +147 -0
  22. package/dist/cli/core/workflow-runtime.js +60 -0
  23. package/dist/cli/index.js +0 -2
  24. package/dist/cli/router.js +4 -3
  25. package/dist/shared/debug/pause-handler.d.ts +9 -0
  26. package/dist/shared/debug/pause-handler.js +15 -0
  27. package/dist/shared/debug/pause.d.ts +1 -2
  28. package/dist/shared/debug/pause.js +13 -36
  29. package/dist/shared/instrumentation/instrument.js +4 -4
  30. package/dist/shared/ipc/child-process-transport.d.ts +7 -0
  31. package/dist/shared/ipc/child-process-transport.js +60 -0
  32. package/dist/shared/ipc/child-process-transport.spec.d.ts +2 -0
  33. package/dist/shared/ipc/child-process-transport.spec.js +68 -0
  34. package/dist/shared/ipc/ipc.d.ts +46 -0
  35. package/dist/shared/ipc/ipc.js +165 -0
  36. package/dist/shared/ipc/ipc.spec.d.ts +2 -0
  37. package/dist/shared/ipc/ipc.spec.js +114 -0
  38. package/dist/shared/ipc/socket-transport.d.ts +9 -0
  39. package/dist/shared/ipc/socket-transport.js +143 -0
  40. package/dist/shared/ipc/socket-transport.spec.d.ts +2 -0
  41. package/dist/shared/ipc/socket-transport.spec.js +117 -0
  42. package/dist/shared/package-manager.d.ts +7 -0
  43. package/dist/shared/package-manager.js +60 -0
  44. package/dist/shared/paths/paths.d.ts +1 -8
  45. package/dist/shared/paths/paths.js +1 -49
  46. package/dist/shared/snapshot/capture-snapshot.d.ts +9 -0
  47. package/dist/shared/snapshot/capture-snapshot.js +463 -0
  48. package/dist/shared/snapshot/diff-snapshots.d.ts +72 -0
  49. package/dist/shared/snapshot/diff-snapshots.js +358 -0
  50. package/dist/shared/snapshot/render-snapshot.d.ts +39 -0
  51. package/dist/shared/snapshot/render-snapshot.js +651 -0
  52. package/dist/shared/snapshot/snapshot.spec.d.ts +2 -0
  53. package/dist/shared/snapshot/snapshot.spec.js +333 -0
  54. package/dist/shared/snapshot/types.d.ts +40 -0
  55. package/dist/shared/snapshot/types.js +0 -0
  56. package/dist/shared/snapshot/wait-for-page-stable.d.ts +17 -0
  57. package/dist/shared/snapshot/wait-for-page-stable.js +281 -0
  58. package/dist/shared/state/session-state.d.ts +1 -0
  59. package/dist/shared/state/session-state.js +1 -0
  60. package/docs/experiments.md +67 -0
  61. package/docs/releasing.md +8 -6
  62. package/package.json +5 -2
  63. package/skills/libretto/SKILL.md +19 -19
  64. package/skills/libretto/references/configuration-file-reference.md +6 -12
  65. package/skills/libretto/references/pages-and-page-targeting.md +1 -1
  66. package/skills/libretto-readonly/SKILL.md +2 -9
  67. package/src/cli/AGENTS.md +7 -0
  68. package/src/cli/cli.ts +0 -23
  69. package/src/cli/commands/browser.ts +14 -18
  70. package/src/cli/commands/execution.ts +303 -271
  71. package/src/cli/commands/experiments.ts +120 -0
  72. package/src/cli/commands/setup.ts +3 -400
  73. package/src/cli/commands/shared.ts +20 -0
  74. package/src/cli/commands/snapshot.ts +54 -94
  75. package/src/cli/commands/status.ts +1 -48
  76. package/src/cli/core/browser.ts +372 -150
  77. package/src/cli/core/config.ts +4 -5
  78. package/src/cli/core/context.ts +4 -0
  79. package/src/cli/core/daemon/config.ts +35 -19
  80. package/src/cli/core/daemon/daemon.ts +645 -107
  81. package/src/cli/core/daemon/ipc.ts +319 -214
  82. package/src/cli/core/daemon/snapshot.ts +71 -15
  83. package/src/cli/core/experiments.ts +56 -0
  84. package/src/cli/core/resolve-model.ts +5 -0
  85. package/src/cli/core/session.ts +5 -4
  86. package/src/cli/core/skill-version.ts +2 -1
  87. package/src/cli/core/workflow-runner/runner.ts +237 -0
  88. package/src/cli/core/workflow-runtime.ts +86 -0
  89. package/src/cli/index.ts +0 -1
  90. package/src/cli/router.ts +4 -3
  91. package/src/shared/debug/pause-handler.ts +20 -0
  92. package/src/shared/debug/pause.ts +14 -48
  93. package/src/shared/instrumentation/instrument.ts +4 -4
  94. package/src/shared/ipc/AGENTS.md +24 -0
  95. package/src/shared/ipc/child-process-transport.spec.ts +86 -0
  96. package/src/shared/ipc/child-process-transport.ts +96 -0
  97. package/src/shared/ipc/ipc.spec.ts +161 -0
  98. package/src/shared/ipc/ipc.ts +288 -0
  99. package/src/shared/ipc/socket-transport.spec.ts +141 -0
  100. package/src/shared/ipc/socket-transport.ts +189 -0
  101. package/src/shared/package-manager.ts +76 -0
  102. package/src/shared/paths/paths.ts +0 -72
  103. package/src/shared/snapshot/capture-snapshot.ts +615 -0
  104. package/src/shared/snapshot/diff-snapshots.ts +579 -0
  105. package/src/shared/snapshot/render-snapshot.ts +962 -0
  106. package/src/shared/snapshot/snapshot.spec.ts +388 -0
  107. package/src/shared/snapshot/types.ts +43 -0
  108. package/src/shared/snapshot/wait-for-page-stable.ts +425 -0
  109. package/src/shared/state/session-state.ts +1 -0
  110. package/dist/cli/commands/ai.js +0 -109
  111. package/dist/cli/core/ai-model.js +0 -192
  112. package/dist/cli/core/api-snapshot-analyzer.js +0 -86
  113. package/dist/cli/core/daemon/index.js +0 -16
  114. package/dist/cli/core/daemon/spawn.js +0 -90
  115. package/dist/cli/core/pause-signals.js +0 -29
  116. package/dist/cli/core/snapshot-analyzer.js +0 -666
  117. package/dist/cli/workers/run-integration-runtime.js +0 -235
  118. package/dist/cli/workers/run-integration-worker-protocol.js +0 -17
  119. package/dist/cli/workers/run-integration-worker.js +0 -64
  120. package/scripts/summarize-evals.mjs +0 -135
  121. package/src/cli/commands/ai.ts +0 -143
  122. package/src/cli/core/ai-model.ts +0 -298
  123. package/src/cli/core/api-snapshot-analyzer.ts +0 -110
  124. package/src/cli/core/daemon/index.ts +0 -24
  125. package/src/cli/core/daemon/spawn.ts +0 -171
  126. package/src/cli/core/pause-signals.ts +0 -35
  127. package/src/cli/core/snapshot-analyzer.ts +0 -855
  128. package/src/cli/workers/run-integration-runtime.ts +0 -326
  129. package/src/cli/workers/run-integration-worker-protocol.ts +0 -19
  130. package/src/cli/workers/run-integration-worker.ts +0 -72
@@ -1,192 +0,0 @@
1
- import { readSnapshotModel } from "./config.js";
2
- import { LIBRETTO_CONFIG_PATH } from "./context.js";
3
- import {
4
- hasProviderCredentials,
5
- parseModel
6
- } from "./resolve-model.js";
7
- import { parseDotEnvAssignment } from "../../shared/env/load-env.js";
8
- const DEFAULT_SNAPSHOT_MODELS = {
9
- openai: "openai/gpt-5.4",
10
- anthropic: "anthropic/claude-sonnet-4-6",
11
- google: "google/gemini-3-flash-preview",
12
- vertex: "vertex/gemini-2.5-flash",
13
- openrouter: "openrouter/free"
14
- };
15
- function detectProviderEnvVar(provider, env = process.env) {
16
- switch (provider) {
17
- case "openai":
18
- return env.OPENAI_API_KEY?.trim() ? "OPENAI_API_KEY" : null;
19
- case "anthropic":
20
- return env.ANTHROPIC_API_KEY?.trim() ? "ANTHROPIC_API_KEY" : null;
21
- case "google":
22
- if (env.GEMINI_API_KEY?.trim()) return "GEMINI_API_KEY";
23
- if (env.GOOGLE_GENERATIVE_AI_API_KEY?.trim())
24
- return "GOOGLE_GENERATIVE_AI_API_KEY";
25
- return null;
26
- case "vertex":
27
- if (env.GOOGLE_CLOUD_PROJECT?.trim()) return "GOOGLE_CLOUD_PROJECT";
28
- if (env.GCLOUD_PROJECT?.trim()) return "GCLOUD_PROJECT";
29
- return null;
30
- case "openrouter":
31
- return env.OPENROUTER_API_KEY?.trim() ? "OPENROUTER_API_KEY" : null;
32
- }
33
- }
34
- class SnapshotApiUnavailableError extends Error {
35
- constructor(message) {
36
- super(message);
37
- this.name = "SnapshotApiUnavailableError";
38
- }
39
- }
40
- function providerSetupSentence(provider) {
41
- switch (provider) {
42
- case "openai":
43
- return "Add OPENAI_API_KEY to .env or as a shell environment variable.";
44
- case "anthropic":
45
- return "Add ANTHROPIC_API_KEY to .env or as a shell environment variable.";
46
- case "google":
47
- return "Add GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY to .env or as a shell environment variable.";
48
- case "vertex":
49
- return "Add GOOGLE_CLOUD_PROJECT or GCLOUD_PROJECT to .env or as a shell environment variable, and make sure application default credentials are configured.";
50
- case "openrouter":
51
- return "Add OPENROUTER_API_KEY to .env or as a shell environment variable.";
52
- }
53
- }
54
- function defaultModelCommandLine() {
55
- return "npx libretto ai configure openai | anthropic | gemini | vertex | openrouter";
56
- }
57
- function providerMissingCredentialSummary(provider) {
58
- switch (provider) {
59
- case "openai":
60
- return "OPENAI_API_KEY is missing";
61
- case "anthropic":
62
- return "ANTHROPIC_API_KEY is missing";
63
- case "google":
64
- return "GEMINI_API_KEY and GOOGLE_GENERATIVE_AI_API_KEY are missing";
65
- case "vertex":
66
- return "GOOGLE_CLOUD_PROJECT and GCLOUD_PROJECT are missing";
67
- case "openrouter":
68
- return "OPENROUTER_API_KEY is missing";
69
- }
70
- }
71
- function noSnapshotApiConfiguredMessage() {
72
- return [
73
- "Failed to analyze snapshot because no snapshot analyzer is configured.",
74
- `Add OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY, GOOGLE_CLOUD_PROJECT, or OPENROUTER_API_KEY to .env or as a shell environment variable, or choose a default model with \`${defaultModelCommandLine()}\`.`,
75
- "For more info, run `npx libretto setup`."
76
- ].join(" ");
77
- }
78
- function missingProviderSnapshotMessage(selection) {
79
- const configuredSource = selection.source === "config" ? ` in ${LIBRETTO_CONFIG_PATH}` : " from process env or .env";
80
- return [
81
- `Failed to analyze snapshot because ${selection.provider} is configured${configuredSource}, but ${providerMissingCredentialSummary(selection.provider)}.`,
82
- providerSetupSentence(selection.provider),
83
- "For more info, run `npx libretto setup`."
84
- ].join(" ");
85
- }
86
- function inferAutoSnapshotModel() {
87
- const providersInPriorityOrder = [
88
- "openai",
89
- "anthropic",
90
- "google",
91
- "vertex",
92
- "openrouter"
93
- ];
94
- for (const provider of providersInPriorityOrder) {
95
- const envVar = detectProviderEnvVar(provider);
96
- if (!envVar) continue;
97
- return {
98
- model: DEFAULT_SNAPSHOT_MODELS[provider],
99
- provider,
100
- source: `env:${envVar}`
101
- };
102
- }
103
- return null;
104
- }
105
- function resolveSnapshotApiModel(snapshotModel = readSnapshotModel()) {
106
- if (snapshotModel) {
107
- const { provider } = parseModel(snapshotModel);
108
- return {
109
- model: snapshotModel,
110
- provider,
111
- source: "config"
112
- };
113
- }
114
- return inferAutoSnapshotModel();
115
- }
116
- function resolveSnapshotApiModelOrThrow(snapshotModel = readSnapshotModel()) {
117
- const selection = resolveSnapshotApiModel(snapshotModel);
118
- if (!selection) {
119
- throw new SnapshotApiUnavailableError(noSnapshotApiConfiguredMessage());
120
- }
121
- if (!hasProviderCredentials(selection.provider)) {
122
- throw new SnapshotApiUnavailableError(
123
- missingProviderSnapshotMessage(selection)
124
- );
125
- }
126
- return selection;
127
- }
128
- function isSnapshotApiUnavailableError(error) {
129
- return error instanceof SnapshotApiUnavailableError;
130
- }
131
- function readSnapshotModelSafely(configPath) {
132
- try {
133
- return { ok: true, model: readSnapshotModel(configPath) };
134
- } catch (err) {
135
- return {
136
- ok: false,
137
- message: err instanceof Error ? err.message : String(err)
138
- };
139
- }
140
- }
141
- function resolveAiSetupStatus(configPath = LIBRETTO_CONFIG_PATH) {
142
- const result = readSnapshotModelSafely(configPath);
143
- if (!result.ok) {
144
- return { kind: "invalid-config", message: result.message };
145
- }
146
- if (result.model) {
147
- let selection;
148
- try {
149
- selection = resolveSnapshotApiModel(result.model);
150
- } catch (err) {
151
- return {
152
- kind: "invalid-config",
153
- message: err instanceof Error ? err.message : String(err)
154
- };
155
- }
156
- if (!selection) {
157
- return { kind: "unconfigured" };
158
- }
159
- if (hasProviderCredentials(selection.provider)) {
160
- return {
161
- kind: "ready",
162
- model: selection.model,
163
- provider: selection.provider,
164
- source: selection.source
165
- };
166
- }
167
- return {
168
- kind: "configured-missing-credentials",
169
- model: selection.model,
170
- provider: selection.provider
171
- };
172
- }
173
- const envSelection = resolveSnapshotApiModel(null);
174
- if (envSelection && hasProviderCredentials(envSelection.provider)) {
175
- return {
176
- kind: "ready",
177
- model: envSelection.model,
178
- provider: envSelection.provider,
179
- source: envSelection.source
180
- };
181
- }
182
- return { kind: "unconfigured" };
183
- }
184
- export {
185
- DEFAULT_SNAPSHOT_MODELS,
186
- SnapshotApiUnavailableError,
187
- isSnapshotApiUnavailableError,
188
- parseDotEnvAssignment,
189
- resolveAiSetupStatus,
190
- resolveSnapshotApiModel,
191
- resolveSnapshotApiModelOrThrow
192
- };
@@ -1,86 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { generateObject } from "ai";
3
- import { resolveModel } from "./resolve-model.js";
4
- import {
5
- InterpretResultSchema,
6
- buildInlinePromptSelection,
7
- getMimeType,
8
- readFileAsBase64
9
- } from "./snapshot-analyzer.js";
10
- import { readSnapshotModel } from "./config.js";
11
- import { resolveSnapshotApiModelOrThrow } from "./ai-model.js";
12
- async function runApiInterpret(args, logger, snapshotModel = readSnapshotModel()) {
13
- const selection = resolveSnapshotApiModelOrThrow(snapshotModel);
14
- logger.info("api-interpret-start", {
15
- objective: args.objective,
16
- pngPath: args.pngPath,
17
- htmlPath: args.htmlPath,
18
- condensedHtmlPath: args.condensedHtmlPath,
19
- model: selection.model,
20
- modelSource: selection.source
21
- });
22
- const fullHtmlContent = readFileSync(args.htmlPath, "utf-8");
23
- const condensedHtmlContent = readFileSync(args.condensedHtmlPath, "utf-8");
24
- const promptSelection = buildInlinePromptSelection(
25
- args,
26
- fullHtmlContent,
27
- condensedHtmlContent,
28
- selection.model
29
- );
30
- logger.info("api-interpret-dom-selection", {
31
- configuredModel: promptSelection.stats.configuredModel,
32
- fullDomEstimatedTokens: promptSelection.stats.fullDomEstimatedTokens,
33
- condensedDomEstimatedTokens: promptSelection.stats.condensedDomEstimatedTokens,
34
- contextWindowTokens: promptSelection.budget.contextWindowTokens,
35
- promptBudgetTokens: promptSelection.budget.promptBudgetTokens,
36
- selectedDom: promptSelection.domSource,
37
- selectedHtmlEstimatedTokens: promptSelection.htmlEstimatedTokens,
38
- selectedPromptEstimatedTokens: promptSelection.promptEstimatedTokens,
39
- selectionReason: promptSelection.selectionReason,
40
- truncated: promptSelection.truncated
41
- });
42
- const imageBase64 = readFileAsBase64(args.pngPath);
43
- const imageMimeType = getMimeType(args.pngPath);
44
- const imageBytes = Buffer.from(imageBase64, "base64");
45
- const model = await resolveModel(selection.model);
46
- const { object: result } = await generateObject({
47
- model,
48
- schema: InterpretResultSchema,
49
- messages: [
50
- {
51
- role: "user",
52
- content: [
53
- { type: "text", text: promptSelection.prompt },
54
- {
55
- type: "image",
56
- image: imageBytes,
57
- mediaType: imageMimeType
58
- }
59
- ]
60
- }
61
- ],
62
- temperature: 0.1
63
- });
64
- const parsed = InterpretResultSchema.parse(result);
65
- logger.info("api-interpret-success", {
66
- selectorCount: parsed.selectors.length,
67
- answer: parsed.answer.slice(0, 200)
68
- });
69
- console.log("");
70
- console.log("Analysis:");
71
- console.log(parsed.answer);
72
- if (parsed.selectors.length > 0) {
73
- console.log("");
74
- console.log("Selectors:");
75
- parsed.selectors.forEach((selector, index) => {
76
- console.log(` ${index + 1}. ${selector.label}: ${selector.selector}`);
77
- });
78
- }
79
- if (parsed.notes?.trim()) {
80
- console.log("");
81
- console.log(`Notes: ${parsed.notes.trim()}`);
82
- }
83
- }
84
- export {
85
- runApiInterpret
86
- };
@@ -1,16 +0,0 @@
1
- import {
2
- DaemonServer,
3
- DaemonClient,
4
- DaemonClientError,
5
- getDaemonSocketPath
6
- } from "./ipc.js";
7
- import {
8
- spawnSessionDaemon
9
- } from "./spawn.js";
10
- export {
11
- DaemonClient,
12
- DaemonClientError,
13
- DaemonServer,
14
- getDaemonSocketPath,
15
- spawnSessionDaemon
16
- };
@@ -1,90 +0,0 @@
1
- import { openSync, closeSync } from "node:fs";
2
- import { fileURLToPath, pathToFileURL } from "node:url";
3
- import { createRequire } from "node:module";
4
- import { spawn } from "node:child_process";
5
- import { getDaemonSocketPath } from "./ipc.js";
6
- import { DaemonClient } from "./ipc.js";
7
- const DEFAULT_IPC_TIMEOUT_MS = 1e4;
8
- const IPC_POLL_INTERVAL_MS = 250;
9
- async function spawnSessionDaemon(options) {
10
- const {
11
- config,
12
- session,
13
- logger,
14
- logPath,
15
- ipcTimeoutMs = DEFAULT_IPC_TIMEOUT_MS,
16
- onFailure
17
- } = options;
18
- const daemonEntryPath = fileURLToPath(
19
- new URL("./daemon.js", import.meta.url)
20
- );
21
- const require2 = createRequire(import.meta.url);
22
- const tsxImportPath = pathToFileURL(require2.resolve("tsx/esm")).href;
23
- const childStderrFd = openSync(logPath, "a");
24
- const child = spawn(
25
- process.execPath,
26
- ["--import", tsxImportPath, daemonEntryPath, JSON.stringify(config)],
27
- {
28
- detached: true,
29
- stdio: ["ignore", "ignore", childStderrFd]
30
- }
31
- );
32
- child.unref();
33
- closeSync(childStderrFd);
34
- const pid = child.pid;
35
- logger.info("daemon-spawned", { pid, session });
36
- let childSpawnError = null;
37
- let childEarlyExit = null;
38
- child.on("error", (err) => {
39
- childSpawnError = err;
40
- logger.error("daemon-spawn-error", { error: err, session });
41
- });
42
- child.on("exit", (code, signal) => {
43
- childEarlyExit = { code, signal };
44
- logger.warn("daemon-early-exit", { code, signal, session, pid });
45
- });
46
- const socketPath = getDaemonSocketPath(session);
47
- const client = new DaemonClient(socketPath);
48
- const maxAttempts = Math.ceil(ipcTimeoutMs / IPC_POLL_INTERVAL_MS);
49
- let ipcReady = false;
50
- for (let i = 0; i < maxAttempts; i++) {
51
- const spawnError = childSpawnError;
52
- if (spawnError !== null) {
53
- await onFailure?.();
54
- const errWithCode = spawnError;
55
- const hint = errWithCode.code === "ENOENT" ? " Ensure Node.js is available in PATH for child processes." : "";
56
- throw new Error(
57
- `Failed to spawn daemon: ${spawnError.message}.${hint} Check logs: ${logPath}`
58
- );
59
- }
60
- const earlyExit = childEarlyExit;
61
- if (earlyExit !== null) {
62
- await onFailure?.();
63
- const status = earlyExit.code ?? earlyExit.signal ?? "unknown";
64
- throw new Error(
65
- `Daemon exited before startup (status: ${status}). Check logs: ${logPath}`
66
- );
67
- }
68
- await new Promise((r) => setTimeout(r, IPC_POLL_INTERVAL_MS));
69
- ipcReady = await client.ping();
70
- if (ipcReady) break;
71
- if (i > 0 && i % 10 === 0) {
72
- logger.info("daemon-waiting-for-ipc", { attempt: i, session });
73
- }
74
- }
75
- if (!ipcReady) {
76
- try {
77
- process.kill(pid, "SIGTERM");
78
- } catch {
79
- }
80
- await onFailure?.();
81
- throw new Error(
82
- `Daemon failed to start within ${Math.ceil(ipcTimeoutMs / 1e3)}s. Check logs: ${logPath}`
83
- );
84
- }
85
- logger.info("daemon-ipc-ready", { session, socketPath });
86
- return { pid, socketPath, client };
87
- }
88
- export {
89
- spawnSessionDaemon
90
- };
@@ -1,29 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { unlink } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { getSessionDir } from "./context.js";
5
- function getPauseSignalPaths(session) {
6
- const sessionDir = getSessionDir(session);
7
- return {
8
- pausedSignalPath: join(sessionDir, `${session}.paused`),
9
- resumeSignalPath: join(sessionDir, `${session}.resume`),
10
- completedSignalPath: join(sessionDir, `${session}.completed`),
11
- failedSignalPath: join(sessionDir, `${session}.failed`),
12
- outputSignalPath: join(sessionDir, `${session}.output`)
13
- };
14
- }
15
- async function removeSignalIfExists(path) {
16
- if (!existsSync(path)) return;
17
- try {
18
- await unlink(path);
19
- } catch (error) {
20
- const code = error.code;
21
- if (code !== "ENOENT") {
22
- throw error;
23
- }
24
- }
25
- }
26
- export {
27
- getPauseSignalPaths,
28
- removeSignalIfExists
29
- };