@openclaw/lobster 2026.9.5 → 2026.9.7

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 (163) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/index.js +8 -294
  3. package/node_modules/@clawdbot/lobster/README.md +20 -133
  4. package/node_modules/@clawdbot/lobster/VISION.md +15 -238
  5. package/node_modules/@clawdbot/lobster/bin/clawd.invoke.js +2 -21
  6. package/node_modules/@clawdbot/lobster/bin/invoke.js +19 -0
  7. package/node_modules/@clawdbot/lobster/bin/lobster.js +2 -21
  8. package/node_modules/@clawdbot/lobster/bin/openclaw.invoke.js +2 -24
  9. package/node_modules/@clawdbot/lobster/dist/src/cli.js +32 -48
  10. package/node_modules/@clawdbot/lobster/dist/src/cli.js.map +1 -1
  11. package/node_modules/@clawdbot/lobster/dist/src/command_tokens.js +81 -0
  12. package/node_modules/@clawdbot/lobster/dist/src/command_tokens.js.map +1 -0
  13. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/dedupe.js +1 -12
  14. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/dedupe.js.map +1 -1
  15. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/group_by.js +2 -14
  16. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/group_by.js.map +1 -1
  17. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/llm_invoke.js +1 -337
  18. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/llm_invoke.js.map +1 -1
  19. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/map.js +2 -13
  20. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/map.js.map +1 -1
  21. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/sort.js +4 -21
  22. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/sort.js.map +1 -1
  23. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/state.js +1 -1
  24. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/state.js.map +1 -1
  25. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/template.js +2 -13
  26. package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/template.js.map +1 -1
  27. package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_run.js +0 -18
  28. package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_run.js.map +1 -1
  29. package/node_modules/@clawdbot/lobster/dist/src/core/llm_accounting.js +304 -0
  30. package/node_modules/@clawdbot/lobster/dist/src/core/llm_accounting.js.map +1 -0
  31. package/node_modules/@clawdbot/lobster/dist/src/core/value_path.js +11 -0
  32. package/node_modules/@clawdbot/lobster/dist/src/core/value_path.js.map +1 -0
  33. package/node_modules/@clawdbot/lobster/dist/src/parser.js +2 -67
  34. package/node_modules/@clawdbot/lobster/dist/src/parser.js.map +1 -1
  35. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/index.js +1 -1
  36. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/pr-monitor.js +5 -64
  37. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/pr-monitor.js.map +1 -1
  38. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/read_pr.js +45 -0
  39. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/read_pr.js.map +1 -0
  40. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/snapshot.js +45 -0
  41. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/snapshot.js.map +1 -0
  42. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/stages/pr-view.js +9 -47
  43. package/node_modules/@clawdbot/lobster/dist/src/recipes/github/stages/pr-view.js.map +1 -1
  44. package/node_modules/@clawdbot/lobster/dist/src/sdk/Lobster.js +18 -135
  45. package/node_modules/@clawdbot/lobster/dist/src/sdk/Lobster.js.map +1 -1
  46. package/node_modules/@clawdbot/lobster/dist/src/sdk/index.js +1 -1
  47. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/approve.js +1 -2
  48. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/approve.js.map +1 -1
  49. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/diff.js +2 -8
  50. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/diff.js.map +1 -1
  51. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/exec.js +15 -81
  52. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/exec.js.map +1 -1
  53. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/state.js +3 -9
  54. package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/state.js.map +1 -1
  55. package/node_modules/@clawdbot/lobster/dist/src/sdk/runtime.js +0 -12
  56. package/node_modules/@clawdbot/lobster/dist/src/sdk/runtime.js.map +1 -1
  57. package/node_modules/@clawdbot/lobster/dist/src/sdk/state_env.js +6 -0
  58. package/node_modules/@clawdbot/lobster/dist/src/sdk/state_env.js.map +1 -0
  59. package/node_modules/@clawdbot/lobster/dist/src/state/atomic_file.js +192 -0
  60. package/node_modules/@clawdbot/lobster/dist/src/state/atomic_file.js.map +1 -0
  61. package/node_modules/@clawdbot/lobster/dist/src/state/store.js +2 -188
  62. package/node_modules/@clawdbot/lobster/dist/src/state/store.js.map +1 -1
  63. package/node_modules/@clawdbot/lobster/dist/src/workflows/dry_run.js +262 -0
  64. package/node_modules/@clawdbot/lobster/dist/src/workflows/dry_run.js.map +1 -0
  65. package/node_modules/@clawdbot/lobster/dist/src/workflows/expressions.js +345 -0
  66. package/node_modules/@clawdbot/lobster/dist/src/workflows/expressions.js.map +1 -0
  67. package/node_modules/@clawdbot/lobster/dist/src/workflows/file.js +21 -1036
  68. package/node_modules/@clawdbot/lobster/dist/src/workflows/file.js.map +1 -1
  69. package/node_modules/@clawdbot/lobster/dist/src/workflows/github_pr_monitor.js +8 -77
  70. package/node_modules/@clawdbot/lobster/dist/src/workflows/github_pr_monitor.js.map +1 -1
  71. package/node_modules/@clawdbot/lobster/dist/src/workflows/graph.js +1 -7
  72. package/node_modules/@clawdbot/lobster/dist/src/workflows/graph.js.map +1 -1
  73. package/node_modules/@clawdbot/lobster/dist/src/workflows/load.js +347 -0
  74. package/node_modules/@clawdbot/lobster/dist/src/workflows/load.js.map +1 -0
  75. package/node_modules/@clawdbot/lobster/dist/src/workflows/types.js +2 -0
  76. package/node_modules/@clawdbot/lobster/dist/src/workflows/types.js.map +1 -0
  77. package/node_modules/@clawdbot/lobster/dist/src/workflows/values.js +93 -0
  78. package/node_modules/@clawdbot/lobster/dist/src/workflows/values.js.map +1 -0
  79. package/node_modules/@clawdbot/lobster/dist/test/cancellation.test.js +1 -0
  80. package/node_modules/@clawdbot/lobster/dist/test/cancellation.test.js.map +1 -1
  81. package/node_modules/@clawdbot/lobster/dist/test/cli_run_errors.test.js +53 -0
  82. package/node_modules/@clawdbot/lobster/dist/test/cli_run_errors.test.js.map +1 -0
  83. package/node_modules/@clawdbot/lobster/dist/test/command_arguments.test.js +82 -0
  84. package/node_modules/@clawdbot/lobster/dist/test/command_arguments.test.js.map +1 -0
  85. package/node_modules/@clawdbot/lobster/dist/test/cost_tracker.test.js +49 -19
  86. package/node_modules/@clawdbot/lobster/dist/test/cost_tracker.test.js.map +1 -1
  87. package/node_modules/@clawdbot/lobster/dist/test/helpers/node_shell_fixture.js +17 -0
  88. package/node_modules/@clawdbot/lobster/dist/test/helpers/node_shell_fixture.js.map +1 -0
  89. package/node_modules/@clawdbot/lobster/dist/test/llm_invoke.test.js +2 -0
  90. package/node_modules/@clawdbot/lobster/dist/test/llm_invoke.test.js.map +1 -1
  91. package/node_modules/@clawdbot/lobster/dist/test/pipeline_resume_state.test.js +65 -0
  92. package/node_modules/@clawdbot/lobster/dist/test/pipeline_resume_state.test.js.map +1 -0
  93. package/node_modules/@clawdbot/lobster/dist/test/process_output_limit.test.js +5 -3
  94. package/node_modules/@clawdbot/lobster/dist/test/process_output_limit.test.js.map +1 -1
  95. package/node_modules/@clawdbot/lobster/dist/test/sdk_exec.test.js +72 -25
  96. package/node_modules/@clawdbot/lobster/dist/test/sdk_exec.test.js.map +1 -1
  97. package/node_modules/@clawdbot/lobster/dist/test/workflow_graph.test.js +1 -1
  98. package/node_modules/@clawdbot/lobster/dist/test/workflow_graph.test.js.map +1 -1
  99. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/README.md +1 -0
  100. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/SECURITY.md +62 -13
  101. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/index.js +40 -9
  102. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/lib/schemes.js +76 -16
  103. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/lib/utils.js +54 -10
  104. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/package.json +1 -1
  105. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/fixtures/uri-js-parse.json +1 -0
  106. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/ipv6-validation.test.js +130 -0
  107. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/mailto-authority-security.test.js +125 -0
  108. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/mailto-field-name-security.test.js +151 -0
  109. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/test/security-normalization.test.js +38 -0
  110. package/node_modules/@clawdbot/lobster/node_modules/fast-uri/types/index.d.ts +16 -0
  111. package/node_modules/@clawdbot/lobster/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +19 -18
  112. package/node_modules/@clawdbot/lobster/node_modules/yaml/browser/dist/nodes/Alias.js +25 -23
  113. package/node_modules/@clawdbot/lobster/node_modules/yaml/dist/compose/resolve-flow-scalar.js +19 -18
  114. package/node_modules/@clawdbot/lobster/node_modules/yaml/dist/nodes/Alias.js +25 -23
  115. package/node_modules/@clawdbot/lobster/node_modules/yaml/package.json +1 -1
  116. package/node_modules/@clawdbot/lobster/package.json +6 -8
  117. package/node_modules/typebox/build/compile/code.mjs +1 -2
  118. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  119. package/node_modules/typebox/build/format/iri.mjs +16 -9
  120. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  121. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  122. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  123. package/node_modules/typebox/build/guard/index.mjs +6 -0
  124. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  125. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  126. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  127. package/node_modules/typebox/build/schema/build.mjs +2 -3
  128. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  129. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  130. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  131. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  132. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  133. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  134. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  135. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  136. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  137. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  138. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  139. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  140. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  141. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  142. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  143. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  144. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  145. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  146. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  147. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  148. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  149. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  150. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  151. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  152. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  153. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  154. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  155. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  156. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  157. package/node_modules/typebox/package.json +1 -1
  158. package/node_modules/typebox/readme.md +3 -1
  159. package/package.json +6 -6
  160. package/dist/runtime-api.js +0 -3
  161. package/node_modules/@clawdbot/lobster/dist/src/sdk/token.js +0 -9
  162. package/node_modules/@clawdbot/lobster/dist/src/sdk/token.js.map +0 -1
  163. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -0,0 +1,53 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { spawnSync } from "node:child_process";
4
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+ for (const kind of ["missing", "directory", "extension"]) {
8
+ test(`tool run reports ${kind} workflow target errors as JSON`, async () => {
9
+ const dir = await mkdtemp(join(tmpdir(), "lobster-target-error-"));
10
+ try {
11
+ const target = kind === "directory"
12
+ ? dir
13
+ : join(dir, kind === "extension" ? "workflow.txt" : "missing.lobster");
14
+ if (kind === "extension")
15
+ await writeFile(target, JSON.stringify({ steps: [{ id: "ok", run: "echo ok" }] }));
16
+ const result = spawnSync(process.execPath, ["bin/lobster.js", "run", "--mode", "tool", "--file", target], { encoding: "utf8" });
17
+ assert.equal(result.status, 2);
18
+ const envelope = JSON.parse(result.stdout);
19
+ assert.equal(envelope.protocolVersion, 1);
20
+ assert.equal(envelope.ok, false);
21
+ assert.equal(envelope.error.type, "parse_error");
22
+ assert.match(envelope.error.message, kind === "missing" ? /ENOENT/ : kind === "directory" ? /not a file/ : /must end in/);
23
+ assert.equal(result.stderr, "");
24
+ }
25
+ finally {
26
+ await rm(dir, { recursive: true, force: true });
27
+ }
28
+ });
29
+ }
30
+ test("human run reports missing workflow without an uncaught stack", async () => {
31
+ const dir = await mkdtemp(join(tmpdir(), "lobster-human-error-"));
32
+ try {
33
+ const result = spawnSync(process.execPath, ["bin/lobster.js", "run", "--file", join(dir, "missing.json")], { encoding: "utf8" });
34
+ assert.equal(result.status, 2);
35
+ assert.equal(result.stdout, "");
36
+ assert.match(result.stderr, /^Parse error: .*ENOENT/);
37
+ assert.doesNotMatch(result.stderr, /at async|node:internal/);
38
+ }
39
+ finally {
40
+ await rm(dir, { recursive: true, force: true });
41
+ }
42
+ });
43
+ for (const flag of ["--help", "-h"]) {
44
+ test(`graph ${flag} shows graph-specific options`, () => {
45
+ const result = spawnSync(process.execPath, ["bin/lobster.js", "graph", flag], {
46
+ encoding: "utf8",
47
+ });
48
+ assert.equal(result.status, 0);
49
+ assert.match(result.stdout, /--format\s+Output format: mermaid \(default\), dot, ascii/);
50
+ assert.equal(result.stderr, "");
51
+ });
52
+ }
53
+ //# sourceMappingURL=cli_run_errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli_run_errors.test.js","sourceRoot":"","sources":["../../test/cli_run_errors.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { execFile } from "node:child_process";
4
+ import { createServer } from "node:http";
5
+ import { promisify } from "node:util";
6
+ import { parsePipeline } from "../src/parser.js";
7
+ import { Lobster, exec } from "../src/sdk/index.js";
8
+ const runFile = promisify(execFile);
9
+ const argvScript = "console.log(JSON.stringify(process.argv.slice(1)))";
10
+ const argvCommand = `${JSON.stringify(process.execPath)} -e '${argvScript}' "" tail`;
11
+ test("pipeline parsing preserves empty positional arguments", () => {
12
+ assert.deepEqual(parsePipeline(`exec node "" ' ' '' tail`)[0].args._, [
13
+ "node",
14
+ "",
15
+ " ",
16
+ "",
17
+ "tail",
18
+ ]);
19
+ });
20
+ test("pipeline parsing preserves an empty quoted option value", () => {
21
+ const args = parsePipeline(`custom --value "" tail`)[0].args;
22
+ assert.equal(args["value"], "");
23
+ assert.deepEqual(args._, ["tail"]);
24
+ });
25
+ test("built CLI passes explicit empty arguments to a child process", async () => {
26
+ const { stdout } = await runFile(process.execPath, [
27
+ "bin/lobster.js",
28
+ "run",
29
+ "--mode",
30
+ "tool",
31
+ `exec --json ${argvCommand}`,
32
+ ]);
33
+ assert.deepEqual(JSON.parse(stdout).output, ["", "tail"]);
34
+ });
35
+ test("SDK exec passes explicit empty arguments to a child process", async () => {
36
+ const result = await new Lobster().pipe(exec(argvCommand)).run();
37
+ assert.equal(result.ok, true, JSON.stringify(result));
38
+ assert.deepEqual(result.output, ["", "tail"]);
39
+ });
40
+ for (const alias of ["openclaw.invoke", "clawd.invoke"]) {
41
+ test(`${alias} shim preserves punctuation and literal pipeline characters`, async () => {
42
+ const expected = {
43
+ text: 'O\'Malley says "hello"\nnext line',
44
+ path: "C:\\folder\\",
45
+ literal: "$HOME `id` | head",
46
+ empty: "",
47
+ };
48
+ const requests = [];
49
+ const server = createServer(async (req, res) => {
50
+ let body = "";
51
+ for await (const chunk of req)
52
+ body += chunk;
53
+ const payload = JSON.parse(body);
54
+ requests.push(payload.args);
55
+ res.setHeader("content-type", "application/json");
56
+ res.end(JSON.stringify({ ok: true, result: [payload.args] }));
57
+ });
58
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
59
+ try {
60
+ const address = server.address();
61
+ assert.ok(address && typeof address === "object");
62
+ const { stdout } = await runFile(process.execPath, [
63
+ `bin/${alias}.js`,
64
+ "--url",
65
+ `http://127.0.0.1:${address.port}`,
66
+ "--tool",
67
+ "proof",
68
+ "--action",
69
+ "read",
70
+ "--args-json",
71
+ JSON.stringify(expected),
72
+ ], { env: { ...process.env, OPENCLAW_TOKEN: "", CLAWD_TOKEN: "" } });
73
+ assert.deepEqual(JSON.parse(stdout), [expected]);
74
+ assert.deepEqual(requests, [expected]);
75
+ }
76
+ finally {
77
+ server.closeAllConnections();
78
+ await new Promise((resolve) => server.close(() => resolve()));
79
+ }
80
+ });
81
+ }
82
+ //# sourceMappingURL=command_arguments.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command_arguments.test.js","sourceRoot":"","sources":["../../test/command_arguments.test.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ import path from "node:path";
7
7
  import { PassThrough } from "node:stream";
8
8
  import { createDefaultRegistry } from "../src/commands/registry.js";
9
9
  import { CostTracker } from "../src/core/cost_tracker.js";
10
- import { createLlmSpendLedger, llmProvenanceOf, restoreLlmProvenance, } from "../src/commands/stdlib/llm_invoke.js";
10
+ import { createLlmSpendLedger, llmProvenanceOf, restoreLlmProvenance, } from "../src/core/llm_accounting.js";
11
11
  import { runWorkflowFile } from "../src/workflows/file.js";
12
12
  import { decodeToken } from "../src/token.js";
13
13
  test("CostTracker records usage and computes totals", () => {
@@ -121,19 +121,25 @@ async function runWorkflow(workflow, envOverride, llmAdapters) {
121
121
  stderr.on("data", (d) => {
122
122
  stderrOutput += String(d);
123
123
  });
124
- const result = await runWorkflowFile({
125
- filePath,
126
- ctx: {
127
- stdin: process.stdin,
128
- stdout: process.stdout,
129
- stderr,
130
- env: { ...process.env, LOBSTER_STATE_DIR: stateDir, ...envOverride },
131
- mode: "tool",
132
- registry: createDefaultRegistry(),
133
- llmAdapters,
134
- },
135
- });
136
- return { result, stderrOutput };
124
+ try {
125
+ const result = await runWorkflowFile({
126
+ filePath,
127
+ ctx: {
128
+ stdin: process.stdin,
129
+ stdout: process.stdout,
130
+ stderr,
131
+ env: { ...process.env, LOBSTER_STATE_DIR: stateDir, ...envOverride },
132
+ mode: "tool",
133
+ registry: createDefaultRegistry(),
134
+ llmAdapters,
135
+ },
136
+ });
137
+ return { result, stderrOutput };
138
+ }
139
+ finally {
140
+ stderr.destroy();
141
+ await fsp.rm(tmpDir, { recursive: true, force: true });
142
+ }
137
143
  }
138
144
  test("workflow result includes _meta.cost when usage is present", async () => {
139
145
  const { result } = await runWorkflow({
@@ -920,11 +926,6 @@ test("workflow cost tracking bills both live calls a retried step's replays stan
920
926
  await fsp.rm(cacheDir, { recursive: true, force: true });
921
927
  }
922
928
  });
923
- // A gate pauses a run rather than resetting what it spent. The resume is a different run — a
924
- // different process, even — so the call made before the gate is only in the paused run's
925
- // record; if a later step repeats the prompt, it replays and correctly bills nothing. Without
926
- // carrying that record forward, the provider call before the gate would appear in no total at
927
- // all, and a `cost_limit` could be walked past one gate at a time.
928
929
  // A gate pauses a run, it does not reset what the run has spent. The resume is a separate run
929
930
  // with its own accounting, so a call made before the gate lives only in the paused run's
930
931
  // record: if a later step repeats the prompt it replays, correctly bills nothing, and the
@@ -1960,4 +1961,33 @@ for (const loop of [false, true]) {
1960
1961
  assert.equal(calls, 1, "a downstream failure must not hide paid usage from the retry budget");
1961
1962
  });
1962
1963
  }
1964
+ for (const rendered of [false, true]) {
1965
+ for (const passthrough of ["head --n 1", "pick usage"]) {
1966
+ test(`uninterrupted workflow does not rebill ${rendered ? "rendered" : "live"} output through ${passthrough}`, async () => {
1967
+ const provider = await startFakeProvider();
1968
+ const cacheDir = await fsp.mkdtemp(path.join(os.tmpdir(), "lobster-cost-step-reference-"));
1969
+ try {
1970
+ const { result } = await runWorkflow({
1971
+ cost_limit: { max_usd: 0.01, action: "stop" },
1972
+ steps: [
1973
+ {
1974
+ id: "live",
1975
+ pipeline: `llm.invoke --model gpt-4o --prompt Summarize${rendered ? " | json" : ""}`,
1976
+ },
1977
+ { id: "copy", pipeline: passthrough, stdin: "$live.json" },
1978
+ { id: "again", pipeline: "head --n 1", stdin: "$copy.json" },
1979
+ ],
1980
+ }, { OPENCLAW_URL: provider.url, LOBSTER_CACHE_DIR: cacheDir });
1981
+ assert.equal(provider.requests(), 1);
1982
+ assert.equal(result._meta?.cost?.totalInputTokens, 1000);
1983
+ assert.equal(result._meta?.cost?.totalOutputTokens, 500);
1984
+ assert.deepEqual(result._meta?.cost?.byStep.map((entry) => entry.stepId), ["live"]);
1985
+ }
1986
+ finally {
1987
+ await provider.close();
1988
+ await fsp.rm(cacheDir, { recursive: true, force: true });
1989
+ }
1990
+ });
1991
+ }
1992
+ }
1963
1993
  //# sourceMappingURL=cost_tracker.test.js.map