jev-agent-tools 0.1.4 → 0.2.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +70 -1
  2. package/CONTRIBUTING.md +40 -0
  3. package/README.md +42 -9
  4. package/SECURITY.md +27 -0
  5. package/dist/adapters/analysis-context.js +75 -0
  6. package/dist/adapters/ask-files.js +189 -0
  7. package/dist/adapters/ask-proof.js +144 -0
  8. package/dist/adapters/ask-syntax.js +385 -0
  9. package/dist/adapters/canonical-path.js +17 -0
  10. package/dist/adapters/command.js +181 -0
  11. package/dist/adapters/docs.js +172 -0
  12. package/dist/adapters/exec.js +207 -0
  13. package/dist/adapters/files.js +293 -0
  14. package/dist/adapters/find.js +122 -0
  15. package/dist/adapters/git-base.js +26 -0
  16. package/dist/adapters/git-inventory.js +71 -0
  17. package/dist/adapters/git.js +439 -0
  18. package/dist/adapters/locate-file.js +159 -0
  19. package/dist/adapters/output-lines.js +46 -0
  20. package/dist/adapters/private-storage.js +98 -0
  21. package/dist/adapters/risk-callers.js +426 -0
  22. package/dist/adapters/runner-version.js +78 -0
  23. package/dist/adapters/shell.js +76 -0
  24. package/dist/adapters/syntax.js +187 -0
  25. package/dist/adapters/test-inventory.js +131 -0
  26. package/dist/adapters/usage.js +20 -0
  27. package/dist/adapters/utf8.js +47 -0
  28. package/dist/configuration.js +257 -0
  29. package/dist/constants.js +119 -0
  30. package/dist/core/ask-closure.js +282 -0
  31. package/dist/core/ask-proof.js +1 -0
  32. package/dist/core/ask-references.js +194 -0
  33. package/dist/core/asks.js +436 -0
  34. package/dist/core/batches.js +65 -0
  35. package/dist/core/command-output.js +224 -0
  36. package/dist/core/diff.js +178 -0
  37. package/dist/core/docs.js +302 -0
  38. package/dist/core/find.js +108 -0
  39. package/dist/core/git.js +1 -0
  40. package/dist/core/imports.js +550 -0
  41. package/dist/core/integrity.js +45 -0
  42. package/dist/core/lexical.js +132 -0
  43. package/dist/core/locate.js +169 -0
  44. package/dist/core/output.js +120 -0
  45. package/dist/core/pointer.js +29 -0
  46. package/dist/core/risk-callers.js +851 -0
  47. package/dist/core/runner-version.js +45 -0
  48. package/dist/core/sections.js +230 -0
  49. package/dist/core/state.js +44 -0
  50. package/dist/core/syntax.js +1 -0
  51. package/dist/core/test-commands.js +334 -0
  52. package/dist/core/test-coverage.js +74 -0
  53. package/dist/core/test-discovery.js +1382 -0
  54. package/dist/core/test-evidence.js +527 -0
  55. package/dist/core/test-state.js +81 -0
  56. package/dist/core/truncate.js +12 -0
  57. package/dist/core/units.js +349 -0
  58. package/dist/describe.js +23 -0
  59. package/dist/guide.js +33 -0
  60. package/dist/host.js +24 -0
  61. package/dist/jev/client.js +434 -0
  62. package/dist/jev/pool.js +54 -0
  63. package/dist/jev/types.js +1 -0
  64. package/dist/mcp/main.js +124 -0
  65. package/dist/mcp/protocol.js +187 -0
  66. package/dist/mcp/tools.js +116 -0
  67. package/dist/presets/docs.js +62 -0
  68. package/dist/presets/risk.js +179 -0
  69. package/dist/presets/spec.js +81 -0
  70. package/dist/presets/witnesses.js +249 -0
  71. package/dist/render.js +42 -0
  72. package/dist/result.js +3 -0
  73. package/dist/runtime.js +1 -0
  74. package/dist/session.js +147 -0
  75. package/dist/texts/ask-files.js +1 -0
  76. package/dist/texts/ask.js +2 -0
  77. package/dist/texts/check-diff.js +17 -0
  78. package/dist/texts/configuration.js +1 -0
  79. package/dist/texts/find.js +14 -0
  80. package/dist/texts/guide.js +16 -0
  81. package/dist/texts/locate.js +10 -0
  82. package/dist/texts/select-tests.js +2 -0
  83. package/dist/tools/ask-files.js +217 -0
  84. package/dist/tools/ask-schema.js +70 -0
  85. package/dist/tools/ask.js +686 -0
  86. package/dist/tools/check-diff.js +402 -0
  87. package/dist/tools/docs-check.js +299 -0
  88. package/dist/tools/find.js +389 -0
  89. package/dist/tools/locate.js +303 -0
  90. package/dist/tools/select-tests.js +567 -0
  91. package/dist/tools/spec-check.js +166 -0
  92. package/docs/adr/0001-strict-typescript-pure-core-offline-tests.md +31 -0
  93. package/docs/adr/0002-one-http-protocol-across-hosts.md +17 -0
  94. package/docs/adr/0003-explicit-scope-conservative-automation.md +19 -0
  95. package/docs/adr/0004-compiled-typed-intents.md +19 -0
  96. package/docs/adr/0005-evidence-construction-before-judgment.md +19 -0
  97. package/docs/adr/0006-visible-uncertainty-constrained-controls.md +21 -0
  98. package/docs/adr/0007-bounded-evidence-visible-limits.md +21 -0
  99. package/docs/adr/0008-static-test-discovery-conservative-plans.md +19 -0
  100. package/docs/adr/0009-session-cache-requested-model-identity.md +17 -0
  101. package/docs/adr/0010-mcp-server-thin-host.md +23 -0
  102. package/docs/agent-instructions.md +91 -0
  103. package/docs/design.md +3 -3
  104. package/docs/mcp.md +231 -0
  105. package/package.json +19 -4
  106. package/server.json +57 -0
  107. package/src/adapters/canonical-path.ts +18 -0
  108. package/src/adapters/command.ts +7 -4
  109. package/src/adapters/exec.ts +226 -0
  110. package/src/adapters/private-storage.ts +143 -0
  111. package/src/adapters/risk-callers.ts +4 -2
  112. package/src/adapters/shell.ts +97 -0
  113. package/src/configuration.ts +39 -12
  114. package/src/constants.ts +11 -0
  115. package/src/core/command-output.ts +17 -1
  116. package/src/host.ts +11 -0
  117. package/src/jev/client.ts +12 -0
  118. package/src/jev/types.ts +6 -0
  119. package/src/mcp/main.ts +135 -0
  120. package/src/mcp/protocol.ts +282 -0
  121. package/src/mcp/tools.ts +166 -0
  122. package/src/session.ts +59 -0
  123. package/src/setup.ts +13 -5
  124. package/src/tools/ask-files.ts +5 -7
  125. package/src/tools/ask.ts +26 -22
  126. package/src/tools/check-diff.ts +8 -5
  127. package/src/tools/docs-check.ts +1 -0
  128. package/src/tools/find.ts +5 -2
  129. package/src/tools/locate.ts +5 -8
  130. package/src/tools/select-tests.ts +7 -4
  131. package/src/tools/spec-check.ts +1 -0
package/src/tools/ask.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { createHash } from "node:crypto";
2
- import { resolve } from "node:path";
2
+ import { isAbsolute, relative, resolve } from "node:path";
3
3
  import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
4
4
  import { type Static, Type } from "@sinclair/typebox";
5
5
  import { createAnalysisContext } from "../adapters/analysis-context.ts";
6
6
  import { collectAskRepository, repositoryPath } from "../adapters/ask-proof.ts";
7
7
  import { collectProofSyntax } from "../adapters/ask-syntax.ts";
8
+ import { canonicalPath } from "../adapters/canonical-path.ts";
8
9
  import { captureCommand } from "../adapters/command.ts";
9
10
  import { collectFiles } from "../adapters/files.ts";
10
11
  import { shareGitInventory } from "../adapters/git-inventory.ts";
@@ -117,6 +118,7 @@ export function createAskTool(dependencies: ToolDependencies) {
117
118
  };
118
119
  }> {
119
120
  const client = dependencies.client;
121
+ const cwd = await canonicalPath(ctx.cwd);
120
122
  const started = performance.now();
121
123
  const exec = shareGitInventory(execute);
122
124
  const finish = (
@@ -159,7 +161,7 @@ export function createAskTool(dependencies: ToolDependencies) {
159
161
  return textResult("Provide state, command or at least one path.");
160
162
  const asks = compileAsks(args.asks, { surface: "ask" });
161
163
  if (!asks.ok) return textResult(asks.error);
162
- const files = await collectFiles(ctx.cwd, args.paths ?? [], signal, {
164
+ const files = await collectFiles(cwd, args.paths ?? [], signal, {
163
165
  exec,
164
166
  allowEmpty: true,
165
167
  skipInvalidUtf8: true,
@@ -178,12 +180,7 @@ export function createAskTool(dependencies: ToolDependencies) {
178
180
  fact,
179
181
  next: "Provide this file as UTF-8 text if the judgment needs it.",
180
182
  }));
181
- let repository = await collectAskRepository(
182
- exec,
183
- ctx.cwd,
184
- args.base,
185
- signal,
186
- );
183
+ let repository = await collectAskRepository(exec, cwd, args.base, signal);
187
184
  if (!repository.ok && args.base) return textResult(repository.error);
188
185
  if (!repository.ok)
189
186
  proofLimitations.push({
@@ -193,7 +190,7 @@ export function createAskTool(dependencies: ToolDependencies) {
193
190
  const command = args.command
194
191
  ? await captureCommand(
195
192
  exec,
196
- repository.ok ? repository.root : ctx.cwd,
193
+ repository.ok ? repository.root : cwd,
197
194
  args.command,
198
195
  args.timeout_s,
199
196
  signal,
@@ -201,12 +198,7 @@ export function createAskTool(dependencies: ToolDependencies) {
201
198
  : undefined;
202
199
  if (command && !command.ok) return textResult(command.error);
203
200
  if (command?.ok) {
204
- repository = await collectAskRepository(
205
- exec,
206
- ctx.cwd,
207
- args.base,
208
- signal,
209
- );
201
+ repository = await collectAskRepository(exec, cwd, args.base, signal);
210
202
  if (!repository.ok && args.base) return textResult(repository.error);
211
203
  }
212
204
  const initialState = assembleState(args.state, files.files);
@@ -220,6 +212,17 @@ export function createAskTool(dependencies: ToolDependencies) {
220
212
  for (const target of command.targets) {
221
213
  if (target.path.startsWith(`${repository.root}/`))
222
214
  target.path = target.path.slice(repository.root.length + 1);
215
+ else if (isAbsolute(target.path)) {
216
+ // Windows reports C:/... or short 8.3 forms; compare canonically.
217
+ const local = relative(
218
+ repository.root,
219
+ await canonicalPath(target.path),
220
+ )
221
+ .split("\\")
222
+ .join("/");
223
+ if (local && !local.startsWith("../") && !isAbsolute(local))
224
+ target.path = local;
225
+ }
223
226
  let matches = [...repository.known].filter(
224
227
  (path) => path === target.path || path.endsWith(`/${target.path}`),
225
228
  );
@@ -252,7 +255,7 @@ export function createAskTool(dependencies: ToolDependencies) {
252
255
  }
253
256
  const path = matches[0];
254
257
  if (!path) continue;
255
- const local = repositoryPath(ctx.cwd, repository.root, path);
258
+ const local = repositoryPath(cwd, repository.root, path);
256
259
  if (!Object.hasOwn(files.files, local)) {
257
260
  const added = await collectFiles(repository.root, [path], signal, {
258
261
  exec,
@@ -348,7 +351,7 @@ export function createAskTool(dependencies: ToolDependencies) {
348
351
  if (repository?.ok) {
349
352
  const canonical = Object.fromEntries(
350
353
  Object.entries(files.files).map(([path, text]) => [
351
- repositoryPath(repository.root, ctx.cwd, path),
354
+ repositoryPath(repository.root, cwd, path),
352
355
  text,
353
356
  ]),
354
357
  );
@@ -370,7 +373,7 @@ export function createAskTool(dependencies: ToolDependencies) {
370
373
  const canonicalPath =
371
374
  references.additions.find(
372
375
  (addition) => addition.reference === path,
373
- )?.path ?? repositoryPath(repository.root, ctx.cwd, path);
376
+ )?.path ?? repositoryPath(repository.root, cwd, path);
374
377
  return [path, before[canonicalPath] ?? null];
375
378
  }),
376
379
  );
@@ -512,11 +515,11 @@ export function createAskTool(dependencies: ToolDependencies) {
512
515
  const identities = files.identities.map((file) => {
513
516
  const content = inserted[file.requestedPath];
514
517
  const insertedPath = Object.keys(inserted).find(
515
- (path) => resolve(ctx.cwd, path) === file.resolvedPath,
518
+ (path) => resolve(cwd, path) === file.resolvedPath,
516
519
  );
517
520
  return {
518
521
  ...file,
519
- insertedPath: insertedPath ? resolve(ctx.cwd, insertedPath) : "",
522
+ insertedPath: insertedPath ? resolve(cwd, insertedPath) : "",
520
523
  content: typeof content === "string" ? content : "",
521
524
  insertedSha256: createHash("sha256")
522
525
  .update(typeof content === "string" ? content : "")
@@ -544,6 +547,7 @@ export function createAskTool(dependencies: ToolDependencies) {
544
547
  const options = {
545
548
  signal,
546
549
  cache: !args.command,
550
+ ...runtime.session.requestGate(),
547
551
  beforeRequest: (questionCount: number) => {
548
552
  if (args.max_calls !== undefined && sent >= args.max_calls) {
549
553
  refusal = {
@@ -787,14 +791,14 @@ export function createAskTool(dependencies: ToolDependencies) {
787
791
  const selectedPath = repository?.ok
788
792
  ? (references.additions.find(
789
793
  (addition) => addition.reference === selected,
790
- )?.path ?? repositoryPath(repository.root, ctx.cwd, selected))
794
+ )?.path ?? repositoryPath(repository.root, cwd, selected))
791
795
  : selected;
792
796
  const retained = (path: string) => {
793
797
  if (!repository?.ok) return path !== selected;
794
798
  return (
795
799
  (references.additions.find(
796
800
  (addition) => addition.reference === path,
797
- )?.path ?? repositoryPath(repository.root, ctx.cwd, path)) !==
801
+ )?.path ?? repositoryPath(repository.root, cwd, path)) !==
798
802
  selectedPath
799
803
  );
800
804
  };
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { type Static, Type } from "@sinclair/typebox";
3
3
  import { createAnalysisContext } from "../adapters/analysis-context.ts";
4
+ import { canonicalPath } from "../adapters/canonical-path.ts";
4
5
  import { collectUnits } from "../adapters/git.ts";
5
6
  import { resolveBase } from "../adapters/git-base.ts";
6
7
  import { shareGitInventory } from "../adapters/git-inventory.ts";
@@ -107,19 +108,20 @@ export function createCheckDiffTool(dependencies: ToolDependencies) {
107
108
  ctx: { cwd: string } & GuideContext,
108
109
  ) {
109
110
  const client = dependencies.client;
111
+ const cwd = await canonicalPath(ctx.cwd);
110
112
  const exec = shareGitInventory(execute);
111
113
  if (args.check === "docs" || args.check === "spec") {
112
114
  const deps = { client, host, runtime, exec };
113
115
  const result =
114
116
  args.check === "docs"
115
117
  ? await runDocsCheck(deps, {
116
- cwd: ctx.cwd,
118
+ cwd: cwd,
117
119
  base: args.base,
118
120
  signal,
119
121
  maxCalls: args.max_calls,
120
122
  })
121
123
  : await runSpecCheck(deps, {
122
- cwd: ctx.cwd,
124
+ cwd: cwd,
123
125
  base: args.base,
124
126
  specPath: args.spec_path,
125
127
  signal,
@@ -223,14 +225,14 @@ export function createCheckDiffTool(dependencies: ToolDependencies) {
223
225
  };
224
226
  };
225
227
  if (!client) return finish(NOT_CONFIGURED);
226
- const comparison = await resolveBase(exec, ctx.cwd, args.base, signal);
228
+ const comparison = await resolveBase(exec, cwd, args.base, signal);
227
229
  if (!comparison.ok) return finish(comparison.error);
228
230
  const base = comparison.base;
229
231
  const analysis = await createAnalysisContext();
230
232
  const collected = await collectUnits(
231
233
  exec,
232
234
  {
233
- cwd: ctx.cwd,
235
+ cwd: cwd,
234
236
  base,
235
237
  signal,
236
238
  },
@@ -271,6 +273,7 @@ export function createCheckDiffTool(dependencies: ToolDependencies) {
271
273
  let reservedMatrixCalls = batches.batches.length;
272
274
  const optionsFor = (matrixRequest = false): JudgmentOptions => ({
273
275
  signal,
276
+ ...runtime.session.requestGate(),
274
277
  beforeRequest(questionCount) {
275
278
  if (matrixRequest && reservedMatrixCalls > 0) reservedMatrixCalls--;
276
279
  const limit =
@@ -312,7 +315,7 @@ export function createCheckDiffTool(dependencies: ToolDependencies) {
312
315
  )
313
316
  ? await collectRiskCallers(
314
317
  exec,
315
- { cwd: ctx.cwd, base, signal },
318
+ { cwd: cwd, base, signal },
316
319
  collected.units,
317
320
  collected.files,
318
321
  analysis.parser,
@@ -319,6 +319,7 @@ export async function runDocsCheck(
319
319
  prepared.questions,
320
320
  {
321
321
  signal,
322
+ ...deps.runtime.session.requestGate(),
322
323
  beforeRequest(questionCount) {
323
324
  if (budget?.kind === "session")
324
325
  return { ok: false, error: budget.message };
package/src/tools/find.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type Static, Type } from "@sinclair/typebox";
2
+ import { canonicalPath } from "../adapters/canonical-path.ts";
2
3
  import { collectSearchExcerpts } from "../adapters/files.ts";
3
4
  import { prefilter } from "../adapters/find.ts";
4
5
  import { shareGitInventory } from "../adapters/git-inventory.ts";
@@ -74,6 +75,7 @@ export function createFindFilesTool(dependencies: ToolDependencies) {
74
75
  ctx: { cwd: string } & GuideContext,
75
76
  ) {
76
77
  const client = dependencies.client;
78
+ const cwd = await canonicalPath(ctx.cwd);
77
79
  const started = performance.now();
78
80
  const exec = shareGitInventory(execute);
79
81
  const totals = {
@@ -130,7 +132,7 @@ export function createFindFilesTool(dependencies: ToolDependencies) {
130
132
  : C.FIND_FILES_READ;
131
133
  const candidates = await prefilter(
132
134
  exec,
133
- ctx.cwd,
135
+ cwd,
134
136
  keywords,
135
137
  candidateLimit,
136
138
  args.scope,
@@ -190,6 +192,7 @@ export function createFindFilesTool(dependencies: ToolDependencies) {
190
192
  ): Promise<Judgment> => {
191
193
  const result = await client.judge(state, questions, {
192
194
  signal,
195
+ ...runtime.session.requestGate(),
193
196
  beforeRequest: (count) => {
194
197
  if (args.max_calls !== undefined && sent >= args.max_calls) {
195
198
  budget = {
@@ -308,7 +311,7 @@ export function createFindFilesTool(dependencies: ToolDependencies) {
308
311
  const contentResults = await Promise.all(
309
312
  contentBatches.map(async (paths) => {
310
313
  const read = await collectSearchExcerpts(
311
- ctx.cwd,
314
+ cwd,
312
315
  paths,
313
316
  keywords,
314
317
  signal,
@@ -1,5 +1,6 @@
1
1
  import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
2
2
  import { type Static, Type } from "@sinclair/typebox";
3
+ import { canonicalPath } from "../adapters/canonical-path.ts";
3
4
  import { shareGitInventory } from "../adapters/git-inventory.ts";
4
5
  import { readLocateFile, scanRange } from "../adapters/locate-file.ts";
5
6
  import { loadSyntaxParser } from "../adapters/syntax.ts";
@@ -74,6 +75,7 @@ export function createLocateTool(
74
75
  ctx: { cwd: string } & GuideContext,
75
76
  ) {
76
77
  const client = dependencies.client;
78
+ const cwd = await canonicalPath(ctx.cwd);
77
79
  const started = performance.now();
78
80
  const exec = shareGitInventory(execute);
79
81
  const results: Judgment[] = [];
@@ -118,7 +120,7 @@ export function createLocateTool(
118
120
  ),
119
121
  };
120
122
  };
121
- const file = await readLocateFile(ctx.cwd, args.path, signal, exec);
123
+ const file = await readLocateFile(cwd, args.path, signal, exec);
122
124
  if (!file.ok) return finish({ refusal: file.error });
123
125
  if (file.bytes < LOCATE_MIN_KB * 1000)
124
126
  return finish({
@@ -182,6 +184,7 @@ export function createLocateTool(
182
184
  },
183
185
  {
184
186
  signal,
187
+ ...runtime.session.requestGate(),
185
188
  beforeRequest: (n) => runtime.session.admit(n),
186
189
  onUsage: (usage) => runtime.session.recordUsage(usage),
187
190
  },
@@ -270,13 +273,7 @@ export function createLocateTool(
270
273
  });
271
274
  }
272
275
  if (file.kind === "outline") {
273
- const selected = await scanRange(
274
- ctx.cwd,
275
- args.path,
276
- block,
277
- signal,
278
- exec,
279
- );
276
+ const selected = await scanRange(cwd, args.path, block, signal, exec);
280
277
  if (!selected.ok) return finish({ refusal: selected.error });
281
278
  const lines = selected.text.split("\n");
282
279
  sections = sections
@@ -2,6 +2,7 @@ import { matchesGlob, relative, resolve } from "node:path";
2
2
  import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
3
3
  import { type Static, Type } from "@sinclair/typebox";
4
4
  import { createAnalysisContext } from "../adapters/analysis-context.ts";
5
+ import { canonicalPath } from "../adapters/canonical-path.ts";
5
6
  import { collectUnits } from "../adapters/git.ts";
6
7
  import { resolveBase } from "../adapters/git-base.ts";
7
8
  import { shareGitInventory } from "../adapters/git-inventory.ts";
@@ -125,6 +126,7 @@ export function createSelectTestsTool(dependencies: ToolDependencies) {
125
126
  ctx: { cwd: string } & GuideContext,
126
127
  ) {
127
128
  const client = dependencies.client;
129
+ const cwd = await canonicalPath(ctx.cwd);
128
130
  const started = performance.now();
129
131
  const exec = shareGitInventory(execute);
130
132
  const totals = {
@@ -168,14 +170,14 @@ export function createSelectTestsTool(dependencies: ToolDependencies) {
168
170
  ...hostUsage(host.isOmp, costKnown ? totals.usage : undefined),
169
171
  };
170
172
  };
171
- const comparison = await resolveBase(exec, ctx.cwd, args.base, signal);
173
+ const comparison = await resolveBase(exec, cwd, args.base, signal);
172
174
  if (!comparison.ok) return finish({ refusal: comparison.error });
173
175
  const analysis = await createAnalysisContext();
174
176
  const [inventory, diff] = await Promise.all([
175
- collectTestInventory(exec, ctx.cwd, signal),
177
+ collectTestInventory(exec, cwd, signal),
176
178
  collectUnits(
177
179
  exec,
178
- { cwd: ctx.cwd, base: comparison.base, signal },
180
+ { cwd: cwd, base: comparison.base, signal },
179
181
  analysis.parser,
180
182
  ),
181
183
  ]);
@@ -387,6 +389,7 @@ export function createSelectTestsTool(dependencies: ToolDependencies) {
387
389
  const result = await client.judge(state, questions, {
388
390
  signal,
389
391
  witnesses: witnessIds,
392
+ ...runtime.session.requestGate(),
390
393
  beforeRequest: (questionCount) => {
391
394
  if (args.max_calls !== undefined && sent >= args.max_calls) {
392
395
  budget = {
@@ -735,7 +738,7 @@ export function createSelectTestsTool(dependencies: ToolDependencies) {
735
738
  lines: commands.commands.map((command) => ({
736
739
  type: "command" as const,
737
740
  ...command,
738
- cwd: relative(ctx.cwd, resolve(inventory.cwd, command.cwd)) || ".",
741
+ cwd: relative(cwd, resolve(inventory.cwd, command.cwd)) || ".",
739
742
  })),
740
743
  });
741
744
  },
@@ -175,6 +175,7 @@ export async function runSpecCheck(
175
175
  if (!units.length) return finish();
176
176
  const judgment = await deps.client.judge(prepared.state, prepared.questions, {
177
177
  signal: input.signal,
178
+ ...deps.runtime.session.requestGate(),
178
179
  beforeRequest(questionCount) {
179
180
  if (input.maxCalls !== undefined && sent >= input.maxCalls) {
180
181
  budget = {