@blogic-cz/agent-tools 0.14.43 → 0.14.44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blogic-cz/agent-tools",
3
- "version": "0.14.43",
3
+ "version": "0.14.44",
4
4
  "description": "CLI tools for AI coding agent workflows — GitHub, database, Kubernetes, Azure DevOps, logs, sessions, and audit",
5
5
  "keywords": [
6
6
  "agent",
@@ -137,13 +137,13 @@
137
137
  "test": "vitest run"
138
138
  },
139
139
  "dependencies": {
140
- "@effect/platform-bun": "4.0.0-beta.74",
140
+ "@effect/platform-bun": "4.0.0-beta.90",
141
141
  "@toon-format/toon": "2.1.0",
142
- "effect": "4.0.0-beta.74"
142
+ "effect": "4.0.0-beta.90"
143
143
  },
144
144
  "devDependencies": {
145
145
  "@effect/language-service": "0.86.2",
146
- "@effect/vitest": "4.0.0-beta.74",
146
+ "@effect/vitest": "4.0.0-beta.90",
147
147
  "@types/bun": "1.3.12",
148
148
  "oxfmt": "0.44.0",
149
149
  "oxlint": "1.59.0",
@@ -151,7 +151,7 @@
151
151
  "vitest": "^4.1.4"
152
152
  },
153
153
  "overrides": {
154
- "@effect/platform-node-shared": "4.0.0-beta.74"
154
+ "@effect/platform-node-shared": "4.0.0-beta.90"
155
155
  },
156
156
  "engines": {
157
157
  "bun": ">=1.0.0"
@@ -452,7 +452,11 @@ export const prChecksCommand = Command.make(
452
452
  repo: repoOption,
453
453
  timeout: Flag.integer("timeout").pipe(
454
454
  Flag.withDefault(CI_CHECK_WATCH_TIMEOUT_MS / 1000),
455
- Flag.withDescription("Timeout in seconds for watch mode (default: 600)"),
455
+ Flag.withDescription("Timeout in seconds for watch mode (default: 600, minimum 1)"),
456
+ Flag.filter(
457
+ (n) => n >= 1,
458
+ () => "--timeout must be at least 1 second",
459
+ ),
456
460
  ),
457
461
  watch: Flag.boolean("watch").pipe(
458
462
  Flag.withDefault(false),
@@ -20,9 +20,6 @@ import { runLocalCommand } from "./helpers";
20
20
 
21
21
  const CHECK_JSON_FIELDS = "name,state,bucket,link";
22
22
  const GITHUB_ACTIONS_RUN_ID_RE = /github\.com\/[^/]+\/[^/]+\/actions\/runs\/(\d+)/;
23
- // A single blocking `--watch` is capped here so an agent never loses a whole turn to a 30-min
24
- // foreground wait. On hitting the cap we return the partial snapshot, not a failure (H1).
25
- const MAX_WATCH_SECONDS = 120;
26
23
 
27
24
  const validatePRTitle = Effect.fn("pr.validatePRTitle")(function* (title: string) {
28
25
  const gh = yield* GitHubService;
@@ -874,11 +871,12 @@ export const fetchChecks = Effect.fn("pr.fetchChecks")(function* (
874
871
  watchArgs.push("--fail-fast");
875
872
  }
876
873
 
877
- // Cap the blocking wait; on timeout fall through to a snapshot instead of failing with no state.
878
- const cappedSeconds = Math.min(timeoutSeconds, MAX_WATCH_SECONDS);
874
+ // Block for the caller's requested --timeout (no artificial cap blocking isn't the problem;
875
+ // --timeout is validated >= 1s at the CLI boundary). On timeout return a snapshot, never
876
+ // nothing — that was the actual token-wasting bug.
879
877
  const watchOutcome = yield* gh.runGh(watchArgs).pipe(
880
878
  Effect.timeoutOrElse({
881
- duration: cappedSeconds * 1000,
879
+ duration: timeoutSeconds * 1000,
882
880
  orElse: () => Effect.succeed(null),
883
881
  }),
884
882
  );
@@ -887,7 +885,7 @@ export const fetchChecks = Effect.fn("pr.fetchChecks")(function* (
887
885
  if (watchOutcome === null && results.some((c) => c.bucket === "pending")) {
888
886
  const pending = results.filter((c) => c.bucket === "pending").length;
889
887
  yield* Console.warn(
890
- `ℹ️ Watch capped at ${cappedSeconds}s; ${pending} check(s) still pending (snapshot returned). ` +
888
+ `ℹ️ Watch timed out after ${timeoutSeconds}s; ${pending} check(s) still pending (snapshot returned). ` +
891
889
  `Re-run to keep watching:\n ${buildChecksCommand(pr, true)}`,
892
890
  );
893
891
  }
@@ -2,6 +2,7 @@ import { Command, Flag } from "effect/unstable/cli";
2
2
  import { Console, Effect, Option } from "effect";
3
3
 
4
4
  import { formatOption, logFormatted } from "#shared";
5
+ import { CI_CHECK_WATCH_TIMEOUT_MS } from "#gh/config";
5
6
  import { GitHubCommandError, GitHubNotFoundError } from "./errors";
6
7
  import { GitHubService } from "./service";
7
8
  import type { CheckRunAnnotation, JobAnnotations } from "./types";
@@ -212,11 +213,15 @@ const cancelRun = Effect.fn("workflow.cancelRun")(function* (runId: number, repo
212
213
  };
213
214
  });
214
215
 
215
- // `gh run watch` has no native timeout and was observed hanging a turn for 36 min. Cap it and
216
- // fall back to a one-shot snapshot, mirroring the `pr checks --watch` cap (M1).
217
- const WATCH_RUN_TIMEOUT_SECONDS = 120;
216
+ // `gh run watch` has no native timeout (observed hanging 36 min). Block for the caller's --timeout,
217
+ // then fall back to a one-shot snapshot so a timeout never returns nothing.
218
+ const DEFAULT_WATCH_RUN_TIMEOUT_SECONDS = CI_CHECK_WATCH_TIMEOUT_MS / 1000;
218
219
 
219
- const watchRun = Effect.fn("workflow.watchRun")(function* (runId: number, repo: string | null) {
220
+ const watchRun = Effect.fn("workflow.watchRun")(function* (
221
+ runId: number,
222
+ repo: string | null,
223
+ timeoutSeconds: number,
224
+ ) {
220
225
  const gh = yield* GitHubService;
221
226
 
222
227
  const watchArgs = ["run", "watch", String(runId), "--exit-status"];
@@ -237,7 +242,7 @@ const watchRun = Effect.fn("workflow.watchRun")(function* (runId: number, repo:
237
242
  return Effect.fail(error);
238
243
  }),
239
244
  Effect.timeoutOrElse({
240
- duration: WATCH_RUN_TIMEOUT_SECONDS * 1000,
245
+ duration: timeoutSeconds * 1000,
241
246
  orElse: () => Effect.succeed(null),
242
247
  }),
243
248
  );
@@ -255,7 +260,7 @@ const watchRun = Effect.fn("workflow.watchRun")(function* (runId: number, repo:
255
260
  })),
256
261
  watchOutput:
257
262
  result === null
258
- ? `(watch capped at ${WATCH_RUN_TIMEOUT_SECONDS}s; status taken from snapshot — re-run to keep watching)`
263
+ ? `(watch timed out after ${timeoutSeconds}s; status taken from snapshot — re-run to keep watching)`
259
264
  : result.stdout,
260
265
  };
261
266
  });
@@ -650,11 +655,21 @@ export const workflowWatchCommand = Command.make(
650
655
  format: formatOption,
651
656
  repo: repoOption,
652
657
  run: Flag.integer("run").pipe(Flag.withDescription("Workflow run ID to watch")),
658
+ timeout: Flag.integer("timeout").pipe(
659
+ Flag.withDescription(
660
+ `Max seconds to block before returning a snapshot (default: ${DEFAULT_WATCH_RUN_TIMEOUT_SECONDS}, minimum 1)`,
661
+ ),
662
+ Flag.withDefault(DEFAULT_WATCH_RUN_TIMEOUT_SECONDS),
663
+ Flag.filter(
664
+ (n) => n >= 1,
665
+ () => "--timeout must be at least 1 second",
666
+ ),
667
+ ),
653
668
  },
654
- ({ format, repo, run }) =>
669
+ ({ format, repo, run, timeout }) =>
655
670
  Effect.gen(function* () {
656
671
  const resolvedRepo = yield* resolveRepoArg(repo);
657
- const result = yield* watchRun(run, resolvedRepo);
672
+ const result = yield* watchRun(run, resolvedRepo, timeout);
658
673
  yield* logFormatted(result, format);
659
674
  }),
660
675
  ).pipe(Command.withDescription("Watch a workflow run until it completes, then show final status"));