jonah-fleet 1.31.2 → 1.31.3

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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to `jonah-fleet` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.31.3](https://github.com/Jonah-Projects/jonah-fleet/compare/v1.31.2...v1.31.3) (2026-10-02)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **loop-guard,prompts:** exempt read-only status polling from loop guard and streamline local autowork handoff ([#580](https://github.com/Jonah-Projects/jonah-fleet/issues/580)) ([ff38bdb](https://github.com/Jonah-Projects/jonah-fleet/commit/ff38bdb6bc3ffccde890df958a2feda0db1effd6))
14
+
8
15
  ## [1.31.2](https://github.com/Jonah-Projects/jonah-fleet/compare/v1.31.1...v1.31.2) (2026-10-02)
9
16
 
10
17
 
@@ -18,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
25
 
19
26
  * **runner:** introduce `detectTransientServiceError` and add startup retry loop (up to 2 retries with backoff) when `agy` encounters transient 503 UNAVAILABLE or handshake EOF during initialization
20
27
  * **daemon:** exempt transient service errors (503 UNAVAILABLE) from PR failure cooldowns to avoid penalizing PR review schedules on momentary upstream cloud blips
28
+ * **loop-guard:** exempt read-only CLI status polling commands (`gh run view`, `gh run watch`, `gh pr view`, `gh pr checks`, `git status`) from repetition and ping-pong loop circuit breakers
29
+ * **prompts:** clarify fast autonomous handoff in autowork Step 15 for local daemon runs so completed PRs hand off cleanly to peer-review without 12-minute polling wait
21
30
 
22
31
  ## [1.31.1](https://github.com/Jonah-Projects/jonah-fleet/compare/v1.31.0...v1.31.1) (2026-10-01)
23
32
 
package/dist/index.js CHANGED
@@ -3992,6 +3992,20 @@ function computeActionHash(toolName, args) {
3992
3992
  const canonicalArgs = canonicalStringify(args);
3993
3993
  return crypto.createHash("sha256").update(`${toolName}:${canonicalArgs}`).digest("hex");
3994
3994
  }
3995
+ function isStatusPollingAction(toolName, args) {
3996
+ if (toolName === "manage_task" && (args?.Action === "status" || args?.action === "status" || args?.Action === "list" || args?.action === "list")) {
3997
+ return true;
3998
+ }
3999
+ if (toolName === "manage_subagents" && (args?.Action === "list" || args?.action === "list")) {
4000
+ return true;
4001
+ }
4002
+ if (toolName === "run_command" && typeof (args?.CommandLine || args?.command) === "string" && /^\s*(?:gh\s+(?:run\s+(?:view|watch|list)|pr\s+(?:view|checks|status|list))|git\s+(?:status|log))\b/i.test(
4003
+ args?.CommandLine || args?.command || ""
4004
+ )) {
4005
+ return true;
4006
+ }
4007
+ return false;
4008
+ }
3995
4009
  var LoopGuard = class {
3996
4010
  routine;
3997
4011
  repetitionThreshold;
@@ -4036,7 +4050,7 @@ var LoopGuard = class {
4036
4050
  if (this.trippedResult) {
4037
4051
  return this.trippedResult;
4038
4052
  }
4039
- const isStatusPolling = toolName === "manage_task" && (args?.Action === "status" || args?.action === "status" || args?.Action === "list" || args?.action === "list") || toolName === "manage_subagents" && (args?.Action === "list" || args?.action === "list");
4053
+ const isStatusPolling = isStatusPollingAction(toolName, args);
4040
4054
  const isAnalyticsRoutine = this.routine === "analytics-review";
4041
4055
  const isExemptFromRepetition = isStatusPolling || isAnalyticsRoutine || toolName === "view_file" || toolName === "read_file" || toolName === "replace_file_content" || toolName === "write_to_file";
4042
4056
  const hash = computeActionHash(toolName, args);
@@ -4093,7 +4107,7 @@ var LoopGuard = class {
4093
4107
  if (this.history.length >= requiredPingPongLength) {
4094
4108
  const pingPongSlice = this.history.slice(-requiredPingPongLength);
4095
4109
  const hasExemptPingPongAction = isAnalyticsRoutine || pingPongSlice.some(
4096
- (item) => item.toolName === "manage_task" && (item.args?.Action === "status" || item.args?.action === "status" || item.args?.Action === "list" || item.args?.action === "list") || item.toolName === "manage_subagents" && (item.args?.Action === "list" || item.args?.action === "list") || item.toolName === "replace_file_content" || item.toolName === "write_to_file"
4110
+ (item) => isStatusPollingAction(item.toolName, item.args) || item.toolName === "replace_file_content" || item.toolName === "write_to_file"
4097
4111
  );
4098
4112
  if (!hasExemptPingPongAction) {
4099
4113
  const hashA = pingPongSlice[0].hash;
@@ -4345,7 +4359,7 @@ function buildRoutinePrompt(targetDir, routine, options = {}) {
4345
4359
  const promptFile = `.github/prompts/${routine}.md`;
4346
4360
  const repoContext = `Working repository is located at ${targetDir}. All git, gh, and workspace commands must execute strictly within this repository.`;
4347
4361
  const logPrompt = options.routineIssueNumber ? ` Tracking run log issue: #${options.routineIssueNumber}.` : "";
4348
- const headlessGuardrail = ` Execution Guardrail: You are executing in a headless autonomous session. You MUST NEVER call schedule or yield your turn with plain text to wait on background tasks or verification checks. If a verification command (tests, type-check, lint) runs in the background, inspect its completion with manage_task(Action='status') or manage_subagents(Action='list') (status polling with these tools is explicitly exempted from loop guard circuit breakers), or execute commands with sufficient WaitMsBeforeAsync (up to 10000 ms). DO NOT busy-wait by repeatedly calling read tools (such as view_file) on unchanged files to pass time while waiting, as calling non-polling tools with identical parameters will trip the loop circuit breaker. Never stop calling tools or yield your turn until the routine's terminal Definition of Done is fully reached.`;
4362
+ const headlessGuardrail = ` Execution Guardrail: You are executing in a headless autonomous session. You MUST NEVER call schedule or yield your turn with plain text to wait on background tasks or verification checks. If a verification command (tests, type-check, lint) runs in the background, inspect its completion with manage_task(Action='status') or manage_subagents(Action='list') (status polling with these tools is explicitly exempted from loop guard circuit breakers), or execute commands with sufficient WaitMsBeforeAsync (up to 10000 ms). DO NOT busy-wait by repeatedly calling read tools (such as view_file) on unchanged files to pass time while waiting, as calling non-polling tools with identical parameters will trip the loop circuit breaker. Read-only status commands (gh run view, gh pr view, gh pr checks, git status) are also exempted from loop guard repetition limits. Never stop calling tools or yield your turn until the routine's terminal Definition of Done is fully reached.`;
4349
4363
  if (routine === "autowork") {
4350
4364
  if (options.issue) {
4351
4365
  return `You are the Autowork routine for this repository. ${repoContext} Read and follow the instructions in ${promptFile} exactly. ${skillsPrompt}Your target is issue #${options.issue}. You are in Targeted mode: work issue #${options.issue} directly, ahead of Phase 1 convergence and priority scan.${logPrompt}${headlessGuardrail}`;
@@ -7310,5 +7324,6 @@ export {
7310
7324
  formatLoopGuardReport,
7311
7325
  getFleetFooter,
7312
7326
  getFleetRunBadge,
7327
+ isStatusPollingAction,
7313
7328
  renderFleetBanner
7314
7329
  };
@@ -30,6 +30,10 @@ export declare function canonicalStringify(value: any): string;
30
30
  * Computes a deterministic SHA-256 action hash: SHA-256(tool_name + canonicalString(args))
31
31
  */
32
32
  export declare function computeActionHash(toolName: string, args: any): string;
33
+ /**
34
+ * Checks whether an action is a read-only status or task polling action exempt from repetition / ping-pong loops.
35
+ */
36
+ export declare function isStatusPollingAction(toolName: string, args: any): boolean;
33
37
  /**
34
38
  * Deterministic Loop Guard & Circuit Breaker monitoring tool calls and execution events.
35
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"loop-guard.d.ts","sourceRoot":"","sources":["../../src/lib/loop-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop-guard.d.ts","sourceRoot":"","sources":["../../src/lib/loop-guard.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEpF,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAarD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,CAGrE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CA6B1E;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,MAAM,CAAC,CAAgC;IAE/C,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,qBAAqB,CAAa;IAC1C,OAAO,CAAC,aAAa,CAA8B;IAEnD,YAAY,OAAO,GAAE,gBAAqB,EAOzC;IAEM,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI,CAE9D;IAEM,SAAS,IAAI,OAAO,CAE1B;IAEM,OAAO,IAAI,aAAa,GAAG,IAAI,CAErC;IAEM,UAAU,IAAI,YAAY,EAAE,CAElC;IAEM,KAAK,IAAI,IAAI,CAKnB;IAED;;OAEG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,GAAE,OAAe,GAAG,aAAa,GAAG,IAAI,CAyH/F;IAED;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAwBlD;IAED,OAAO,CAAC,WAAW;CAWpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,CAWvE;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,MAAM,CA0BvF;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAmC7E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jonah-fleet",
3
- "version": "1.31.2",
3
+ "version": "1.31.3",
4
4
  "description": "Standalone autonomous agent fleet with Symphony orchestration, claim protocols, and continuous improvement loops",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -306,7 +306,8 @@ _Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/ru
306
306
  ```
307
307
  14. If run aborts before opening PR, release claim (unassign).
308
308
  15. **In-Session Peer Review Wait & Immediate Convergence (Warm Context):**
309
- - Poll PR status for up to 10–12 minutes.
309
+ - **Local Daemon Environment**: If running locally under `jonah-fleet daemon` or with local runner (`runner:local`): Do NOT busy-wait or poll PR status. Autonomous handoff is complete. Proceed immediately to Step 16 / Logging, unassign yourself from the PR (`gh pr edit <PR> --remove-assignee <login>`), record terminal SUCCESS, and exit cleanly so the daemon's Peer Review Watchdog can review the PR without delay.
310
+ - **Cloud CI Environment**: Poll PR status for up to 10–12 minutes using read-only status checks (`gh pr view`, `gh pr checks`, `gh run view`).
310
311
  - If merged: unassign yourself, resolve and close any open past failed routine run issues for `#<TARGET_ISSUE>`, record terminal SUCCESS and exit cleanly:
311
312
  ```bash
312
313
  PAST_FAILURES=$(gh issue list --label routine-log --search "Issue #<TARGET_ISSUE>" --state open --json number --jq '.[].number' || true)
@@ -38,6 +38,37 @@ export function computeActionHash(toolName, args) {
38
38
  return crypto.createHash('sha256').update(`${toolName}:${canonicalArgs}`).digest('hex');
39
39
  }
40
40
 
41
+ export function isStatusPollingAction(toolName, args) {
42
+ if (
43
+ toolName === 'manage_task' &&
44
+ (args?.Action === 'status' ||
45
+ args?.action === 'status' ||
46
+ args?.Action === 'list' ||
47
+ args?.action === 'list')
48
+ ) {
49
+ return true;
50
+ }
51
+
52
+ if (
53
+ toolName === 'manage_subagents' &&
54
+ (args?.Action === 'list' || args?.action === 'list')
55
+ ) {
56
+ return true;
57
+ }
58
+
59
+ if (
60
+ toolName === 'run_command' &&
61
+ typeof (args?.CommandLine || args?.command) === 'string' &&
62
+ /^\s*(?:gh\s+(?:run\s+(?:view|watch|list)|pr\s+(?:view|checks|status|list))|git\s+(?:status|log))\b/i.test(
63
+ args?.CommandLine || args?.command || ''
64
+ )
65
+ ) {
66
+ return true;
67
+ }
68
+
69
+ return false;
70
+ }
71
+
41
72
  export class LoopGuard {
42
73
  constructor(options = {}) {
43
74
  this.routine = options.routine;
@@ -64,15 +95,7 @@ export class LoopGuard {
64
95
  recordAction(toolName, args, isError = false) {
65
96
  if (this.trippedResult) return this.trippedResult;
66
97
 
67
- const isStatusPolling =
68
- (toolName === 'manage_task' &&
69
- (args?.Action === 'status' ||
70
- args?.action === 'status' ||
71
- args?.Action === 'list' ||
72
- args?.action === 'list')) ||
73
- (toolName === 'manage_subagents' &&
74
- (args?.Action === 'list' ||
75
- args?.action === 'list'));
98
+ const isStatusPolling = isStatusPollingAction(toolName, args);
76
99
 
77
100
  const isAnalyticsRoutine = this.routine === 'analytics-review';
78
101
 
@@ -151,14 +174,7 @@ export class LoopGuard {
151
174
  isAnalyticsRoutine ||
152
175
  pingPongSlice.some(
153
176
  (item) =>
154
- (item.toolName === 'manage_task' &&
155
- (item.args?.Action === 'status' ||
156
- item.args?.action === 'status' ||
157
- item.args?.Action === 'list' ||
158
- item.args?.action === 'list')) ||
159
- (item.toolName === 'manage_subagents' &&
160
- (item.args?.Action === 'list' ||
161
- item.args?.action === 'list')) ||
177
+ isStatusPollingAction(item.toolName, item.args) ||
162
178
  item.toolName === 'replace_file_content' ||
163
179
  item.toolName === 'write_to_file'
164
180
  );