jonah-fleet 1.12.0 → 1.14.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 (33) hide show
  1. package/CHANGELOG.md +16 -5
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +356 -4
  5. package/dist/lib/installer.d.ts.map +1 -1
  6. package/dist/lib/labels.d.ts.map +1 -1
  7. package/dist/lib/loop-guard.d.ts +80 -0
  8. package/dist/lib/loop-guard.d.ts.map +1 -0
  9. package/dist/lib/presets.d.ts +5 -0
  10. package/dist/lib/presets.d.ts.map +1 -1
  11. package/dist/lib/runner.d.ts +10 -1
  12. package/dist/lib/runner.d.ts.map +1 -1
  13. package/package.json +1 -1
  14. package/schema.json +26 -0
  15. package/templates/docs/LESSONS.template.md +7 -0
  16. package/templates/prompts/ORCHESTRATION.md +26 -0
  17. package/templates/prompts/analytics-review.md +41 -0
  18. package/templates/prompts/autowork.md +26 -5
  19. package/templates/prompts/issues-housekeeping.md +11 -1
  20. package/templates/prompts/optimizer.md +3 -0
  21. package/templates/prompts/peer-review.md +1 -0
  22. package/templates/scripts/run-with-loop-guard.js +439 -0
  23. package/templates/skills/triage/SKILL.md +19 -14
  24. package/templates/workflows/analytics-review-cron.yml +313 -0
  25. package/templates/workflows/autowork-cron.yml +59 -4
  26. package/templates/workflows/dependency-check-cron.yml +64 -1
  27. package/templates/workflows/design-review-cron.yml +59 -4
  28. package/templates/workflows/issues-housekeeping-cron.yml +64 -1
  29. package/templates/workflows/prompt-optimizer-cron.yml +59 -4
  30. package/templates/workflows/trigger-autowork-manual.yml +59 -4
  31. package/templates/workflows/trigger-autowork-on-bug.yml +59 -4
  32. package/templates/workflows/trigger-autowork-on-merge.yml +59 -4
  33. package/templates/workflows/trigger-review-routine.yml +68 -4
package/CHANGELOG.md CHANGED
@@ -5,19 +5,30 @@ 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.12.0](https://github.com/juliendurandeu/jonah-fleet/compare/v1.11.0...v1.12.0) (2026-09-18)
8
+ ## [1.14.0](https://github.com/juliendurandeu/jonah-fleet/compare/v1.13.0...v1.14.0) (2026-09-19)
9
9
 
10
10
 
11
11
  ### Features
12
12
 
13
- * **radar:** add zqiren/Orbital to ecosystem radar and evaluation matrix ([#212](https://github.com/juliendurandeu/jonah-fleet/issues/212)) ([910febb](https://github.com/juliendurandeu/jonah-fleet/commit/910febbbc8196d53c20f05730770aae231a6b8ea)), closes [#206](https://github.com/juliendurandeu/jonah-fleet/issues/206)
13
+ * **workflows:** handle LLM quota limits with graceful pause (status:quota-paused) ([#240](https://github.com/juliendurandeu/jonah-fleet/issues/240)) ([98bb176](https://github.com/juliendurandeu/jonah-fleet/commit/98bb176f0b29462ab9de6baf5d0f102fee78b0ba))
14
14
 
15
+ ## [Unreleased] - 2026-09-19
15
16
 
16
- ### Bug Fixes
17
+ ### Features
18
+
19
+ * **workflows:** intercept LLM quota limit errors (`Individual quota reached`), record reset timeline, label tracking issue `status:quota-paused`, and pause routine execution gracefully with exit code 0 to prevent broken Action builds and wasted runner minutes.
20
+ * **labels:** introduce `status:quota-paused` to core fleet label definitions.
21
+
22
+ ## [1.13.0](https://github.com/juliendurandeu/jonah-fleet/compare/v1.12.0...v1.13.0) (2026-09-19)
17
23
 
18
- * **runner:** prevent premature routine termination on async background tasks in headless mode ([6641b2b](https://github.com/juliendurandeu/jonah-fleet/commit/6641b2b2e46ab363b73d490aac1144a33a1c69f9))
19
24
 
20
- ## [Unreleased] - 2026-09-18
25
+ ### Features
26
+
27
+ * **guard:** implement CLI runner loop-guard and circuit-breaker wrapper ([#222](https://github.com/juliendurandeu/jonah-fleet/issues/222)) ([bedacc0](https://github.com/juliendurandeu/jonah-fleet/commit/bedacc0d9bc2a36276f58901ffa2f2b06e797016))
28
+ * **memory:** introduce opt-in LESSONS.md operational memory tier ([#207](https://github.com/juliendurandeu/jonah-fleet/issues/207)) ([#219](https://github.com/juliendurandeu/jonah-fleet/issues/219)) ([13f74fa](https://github.com/juliendurandeu/jonah-fleet/commit/13f74fa2acc78554bba486b2bf77521106265f03))
29
+ * **orchestration:** standardize 'Why I believe this' structured human escalation card ([#229](https://github.com/juliendurandeu/jonah-fleet/issues/229)) ([997e1d2](https://github.com/juliendurandeu/jonah-fleet/commit/997e1d20d7d0a3970ecca9f209841db745f99979))
30
+
31
+ ## [1.12.0](https://github.com/juliendurandeu/jonah-fleet/compare/v1.11.0...v1.12.0) (2026-09-18)
21
32
 
22
33
  ### Bug Fixes
23
34
 
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export {};
1
+ export * from './lib/loop-guard.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6IA,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -122,7 +122,7 @@ var ROUTINE_TO_WORKFLOW_MAP = {
122
122
  "issues-housekeeping": ["issues-housekeeping-cron.yml"],
123
123
  "dependency-update-security-check": ["dependency-check-cron.yml"],
124
124
  "product-planning": [],
125
- "analytics-review": [],
125
+ "analytics-review": ["analytics-review-cron.yml"],
126
126
  "design-review": ["design-review-cron.yml"]
127
127
  };
128
128
  var FLEET_VERSION = "1.8.0";
@@ -608,6 +608,22 @@ function installFleet(targetDir, manifest, options = {}) {
608
608
  }
609
609
  }
610
610
  }
611
+ const targetScriptsDir = path3.join(targetDir, ".github/scripts");
612
+ fs3.mkdirSync(targetScriptsDir, { recursive: true });
613
+ const baseScripts = ["run-with-loop-guard.js"];
614
+ for (const file of baseScripts) {
615
+ const src = path3.join(templatesDir, "scripts", file);
616
+ const dest = path3.join(targetScriptsDir, file);
617
+ if (fs3.existsSync(src)) {
618
+ if (!fs3.existsSync(dest) || options.force) {
619
+ fs3.copyFileSync(src, dest);
620
+ try {
621
+ fs3.chmodSync(dest, 493);
622
+ } catch {
623
+ }
624
+ }
625
+ }
626
+ }
611
627
  for (const [routineName, isEnabled] of Object.entries(manifest.routines)) {
612
628
  if (!isEnabled) continue;
613
629
  const promptFile = `${routineName}.md`;
@@ -672,6 +688,17 @@ function installFleet(targetDir, manifest, options = {}) {
672
688
  result.docsInstalled.push("AGENTS.md");
673
689
  }
674
690
  }
691
+ const lessonsEnabled = manifest.lessons === true || typeof manifest.lessons === "object" && manifest.lessons?.enabled;
692
+ if (lessonsEnabled) {
693
+ const lessonsPath = path3.join(targetDir, "LESSONS.md");
694
+ if (!fs3.existsSync(lessonsPath) || options.force) {
695
+ const lessonsSrc = path3.join(templatesDir, "docs/LESSONS.template.md");
696
+ if (fs3.existsSync(lessonsSrc)) {
697
+ fs3.copyFileSync(lessonsSrc, lessonsPath);
698
+ result.docsInstalled.push("LESSONS.md");
699
+ }
700
+ }
701
+ }
675
702
  return result;
676
703
  }
677
704
 
@@ -1321,6 +1348,7 @@ var FLEET_CORE_LABELS = [
1321
1348
  { name: "status:running", color: "fbca04", description: "Routine execution in progress" },
1322
1349
  { name: "status:success", color: "0e8a16", description: "Routine execution succeeded" },
1323
1350
  { name: "status:failure", color: "d93f0b", description: "Routine execution failed" },
1351
+ { name: "status:quota-paused", color: "e4e669", description: "Routine execution paused due to API quota limits" },
1324
1352
  { name: "needs-attention", color: "e11d48", description: "Requires maintainer triage" },
1325
1353
  { name: "runner:github-actions", color: "1f883d", description: "Executed via GitHub Actions" },
1326
1354
  { name: "runner:local", color: "bfd4f2", description: "Executed via local machine daemon" },
@@ -3495,6 +3523,223 @@ var TerminalSpinner = class {
3495
3523
  }
3496
3524
  };
3497
3525
 
3526
+ // src/lib/loop-guard.ts
3527
+ import crypto from "crypto";
3528
+ function canonicalStringify(value) {
3529
+ if (value === null || value === void 0) {
3530
+ return "";
3531
+ }
3532
+ if (typeof value !== "object") {
3533
+ return JSON.stringify(value);
3534
+ }
3535
+ if (Array.isArray(value)) {
3536
+ return "[" + value.map(canonicalStringify).join(",") + "]";
3537
+ }
3538
+ const keys = Object.keys(value).sort();
3539
+ const entries = keys.map((k) => `${JSON.stringify(k)}:${canonicalStringify(value[k])}`);
3540
+ return "{" + entries.join(",") + "}";
3541
+ }
3542
+ function computeActionHash(toolName, args) {
3543
+ const canonicalArgs = canonicalStringify(args);
3544
+ return crypto.createHash("sha256").update(`${toolName}:${canonicalArgs}`).digest("hex");
3545
+ }
3546
+ var LoopGuard = class {
3547
+ repetitionThreshold;
3548
+ pingPongThreshold;
3549
+ consecutiveErrorThreshold;
3550
+ slidingWindowSize;
3551
+ onTrip;
3552
+ history = [];
3553
+ lastErrorHash = null;
3554
+ consecutiveErrorCount = 0;
3555
+ trippedResult = null;
3556
+ constructor(options = {}) {
3557
+ this.repetitionThreshold = options.repetitionThreshold ?? 5;
3558
+ this.pingPongThreshold = options.pingPongThreshold ?? 3;
3559
+ this.consecutiveErrorThreshold = options.consecutiveErrorThreshold ?? 2;
3560
+ this.slidingWindowSize = options.slidingWindowSize ?? 20;
3561
+ this.onTrip = options.onTrip;
3562
+ }
3563
+ setOnTrip(callback) {
3564
+ this.onTrip = callback;
3565
+ }
3566
+ isTripped() {
3567
+ return this.trippedResult !== null;
3568
+ }
3569
+ getTrip() {
3570
+ return this.trippedResult;
3571
+ }
3572
+ getHistory() {
3573
+ return [...this.history];
3574
+ }
3575
+ reset() {
3576
+ this.history = [];
3577
+ this.lastErrorHash = null;
3578
+ this.consecutiveErrorCount = 0;
3579
+ this.trippedResult = null;
3580
+ }
3581
+ /**
3582
+ * Records an action occurrence and evaluates repetition, ping-pong, and error guards.
3583
+ */
3584
+ recordAction(toolName, args, isError = false) {
3585
+ if (this.trippedResult) {
3586
+ return this.trippedResult;
3587
+ }
3588
+ const hash = computeActionHash(toolName, args);
3589
+ const record = {
3590
+ toolName,
3591
+ args,
3592
+ hash,
3593
+ isError,
3594
+ timestamp: Date.now()
3595
+ };
3596
+ if (isError) {
3597
+ if (this.lastErrorHash === hash) {
3598
+ this.consecutiveErrorCount++;
3599
+ } else {
3600
+ this.lastErrorHash = hash;
3601
+ this.consecutiveErrorCount = 1;
3602
+ }
3603
+ if (this.consecutiveErrorCount >= this.consecutiveErrorThreshold) {
3604
+ return this.triggerTrip({
3605
+ reason: "consecutive_errors",
3606
+ message: `Tool circuit breaker tripped: ${this.consecutiveErrorCount} consecutive identical tool errors for '${toolName}' with unchanged arguments.`,
3607
+ toolName,
3608
+ actionHash: hash,
3609
+ count: this.consecutiveErrorCount
3610
+ });
3611
+ }
3612
+ } else {
3613
+ this.lastErrorHash = null;
3614
+ this.consecutiveErrorCount = 0;
3615
+ }
3616
+ this.history.push(record);
3617
+ const windowStart = Math.max(0, this.history.length - this.slidingWindowSize);
3618
+ const currentWindow = this.history.slice(windowStart);
3619
+ let repetitionCount = 0;
3620
+ for (const item of currentWindow) {
3621
+ if (item.hash === hash) {
3622
+ repetitionCount++;
3623
+ }
3624
+ }
3625
+ if (repetitionCount >= this.repetitionThreshold) {
3626
+ return this.triggerTrip({
3627
+ reason: "repetition",
3628
+ message: `Action repetition loop detected: tool '${toolName}' called ${repetitionCount} times with identical parameters within sliding window of ${this.slidingWindowSize}.`,
3629
+ toolName,
3630
+ actionHash: hash,
3631
+ count: repetitionCount
3632
+ });
3633
+ }
3634
+ const requiredPingPongLength = this.pingPongThreshold * 2;
3635
+ if (this.history.length >= requiredPingPongLength) {
3636
+ const pingPongSlice = this.history.slice(-requiredPingPongLength);
3637
+ const hashA = pingPongSlice[0].hash;
3638
+ const hashB = pingPongSlice[1].hash;
3639
+ if (hashA !== hashB) {
3640
+ let isPingPong = true;
3641
+ for (let i = 0; i < requiredPingPongLength; i++) {
3642
+ const expectedHash = i % 2 === 0 ? hashA : hashB;
3643
+ if (pingPongSlice[i].hash !== expectedHash) {
3644
+ isPingPong = false;
3645
+ break;
3646
+ }
3647
+ }
3648
+ if (isPingPong) {
3649
+ return this.triggerTrip({
3650
+ reason: "ping_pong",
3651
+ message: `Alternating ping-pong action loop detected: ${this.pingPongThreshold} consecutive alternating cycles between tools (A-B-A-B-A-B).`,
3652
+ toolName,
3653
+ actionHash: hash,
3654
+ count: this.pingPongThreshold
3655
+ });
3656
+ }
3657
+ }
3658
+ }
3659
+ return null;
3660
+ }
3661
+ /**
3662
+ * Feeds a single line of output (stream-json or raw text) into the guard.
3663
+ */
3664
+ feedLine(line) {
3665
+ if (!line || !line.trim()) return null;
3666
+ try {
3667
+ const parsed = JSON.parse(line.trim());
3668
+ if (parsed && typeof parsed === "object" && parsed.event === "step_update") {
3669
+ const su = parsed.step_update;
3670
+ if (su && su.step_type === "tool") {
3671
+ const toolName = su.tool_name || su.tool_info?.name || "unknown";
3672
+ const params = su.tool_info?.parameters;
3673
+ if (su.state === "ACTIVE") {
3674
+ return this.recordAction(toolName, params, false);
3675
+ }
3676
+ if (su.state === "ERROR") {
3677
+ return this.recordAction(toolName, params, true);
3678
+ }
3679
+ }
3680
+ }
3681
+ } catch {
3682
+ }
3683
+ return null;
3684
+ }
3685
+ triggerTrip(trip) {
3686
+ this.trippedResult = trip;
3687
+ if (this.onTrip) {
3688
+ try {
3689
+ this.onTrip(trip);
3690
+ } catch {
3691
+ }
3692
+ }
3693
+ return trip;
3694
+ }
3695
+ };
3696
+ function formatLoopGuardFailureCard(options) {
3697
+ const serverUrl = options.serverUrl || process.env.GITHUB_SERVER_URL || "https://github.com";
3698
+ const repository = options.repository || process.env.GITHUB_REPOSITORY || "";
3699
+ const runId = options.runId || process.env.GITHUB_RUN_ID || "";
3700
+ const logUrl = runId && repository ? `${serverUrl}/${repository}/actions/runs/${runId}` : "";
3701
+ const lines = [
3702
+ `### \u274C Milestone: Run Interrupted / Failed`,
3703
+ `- **Routine**: \`${options.routine}\``,
3704
+ `- **Status**: Loop guard circuit breaker tripped (\`loop_circuit_breaker\`)`,
3705
+ `- **Root Cause Category**: \`loop_circuit_breaker\``,
3706
+ `- **Trigger**: \`${options.trip.reason}\``,
3707
+ `- **Reason**: ${options.trip.message}`,
3708
+ `- **Action**: Process terminated to prevent runaway token burn`
3709
+ ];
3710
+ if (logUrl) {
3711
+ lines.push(`- **Action Log**: [View Run Logs](${logUrl})`);
3712
+ }
3713
+ return lines.join("\n");
3714
+ }
3715
+ function formatLoopGuardReport(options) {
3716
+ return [
3717
+ `# Run Report`,
3718
+ ``,
3719
+ `## Result`,
3720
+ `FAILURE`,
3721
+ ``,
3722
+ `## Summary`,
3723
+ `| Metric | Value |`,
3724
+ `|---|---|`,
3725
+ `| Routine | \`${options.routine}\` |`,
3726
+ `| Timestamp | \`${options.timestamp}\` |`,
3727
+ `| Result | \`FAILURE\` |`,
3728
+ `| Category | \`loop_circuit_breaker\` |`,
3729
+ `| Trigger | \`${options.trip.reason}\` |`,
3730
+ `| Tool | \`${options.trip.toolName}\` |`,
3731
+ `| Action Hash | \`${options.trip.actionHash}\` |`,
3732
+ ``,
3733
+ `### Failure Details`,
3734
+ `The autonomous execution was halted by the deterministic loop-guard wrapper.`,
3735
+ `- **Category**: \`loop_circuit_breaker\``,
3736
+ `- **Trigger**: \`${options.trip.reason}\``,
3737
+ `- **Tool**: \`${options.trip.toolName}\``,
3738
+ `- **Action Hash**: \`${options.trip.actionHash}\``,
3739
+ `- **Message**: ${options.trip.message}`
3740
+ ].join("\n");
3741
+ }
3742
+
3498
3743
  // src/lib/runner.ts
3499
3744
  import pc10 from "picocolors";
3500
3745
  var execFileAsync4 = promisify4(execFile4);
@@ -3699,8 +3944,56 @@ async function tryPostLocalRunMilestoneAsync(cwd, issueNumber, cardContent) {
3699
3944
  }
3700
3945
  }
3701
3946
  }
3702
- function tryReconcileLocalRunIssue(cwd, issueNumber, reportContent, exitCode, hostname, routine) {
3947
+ function detectQuotaExceeded(output, stderr) {
3948
+ const combined = `${output}
3949
+ ${stderr}`;
3950
+ if (/individual quota reached|quota reached/i.test(combined)) {
3951
+ const match = combined.match(/Resets in ([^.\n]+)/i);
3952
+ return {
3953
+ isQuota: true,
3954
+ resetInfo: match ? `Resets in ${match[1].trim()}` : void 0
3955
+ };
3956
+ }
3957
+ return { isQuota: false };
3958
+ }
3959
+ function tryReconcileLocalRunIssue(cwd, issueNumber, reportContent, exitCode, hostname, routine, quotaInfo) {
3703
3960
  try {
3961
+ if (quotaInfo?.isQuota) {
3962
+ const resetStr = quotaInfo.resetInfo || "Resets in future window";
3963
+ const quotaCard = [
3964
+ `### \u23F8\uFE0F Milestone: Routine Execution Quota-Paused`,
3965
+ `- **Routine**: \`${routine || "local-routine"}\``,
3966
+ `- **Status**: LLM quota reached (\`${resetStr}\`)`,
3967
+ `- **Runner**: \`local (${hostname})\``,
3968
+ `- **Next Action**: Routine execution paused cleanly. Work will resume on next sweep after quota resets.`
3969
+ ].join("\n");
3970
+ tryPostLocalRunMilestone(cwd, issueNumber, quotaCard);
3971
+ const finalBody2 = `${reportContent}
3972
+
3973
+ ---
3974
+ _Generated by Jonah Fleet local runner on ${hostname}._`;
3975
+ const tmpFile2 = path12.join(os2.tmpdir(), `jonah-fleet-run-${issueNumber}-${Date.now()}.md`);
3976
+ fs12.writeFileSync(tmpFile2, finalBody2, "utf8");
3977
+ try {
3978
+ execSync2(`gh issue edit ${issueNumber} --body-file ${JSON.stringify(tmpFile2)}`, {
3979
+ cwd,
3980
+ stdio: ["ignore", "ignore", "ignore"]
3981
+ });
3982
+ execSync2(`gh issue edit ${issueNumber} --add-label "status:quota-paused" --remove-label "status:running"`, {
3983
+ cwd,
3984
+ stdio: ["ignore", "ignore", "ignore"]
3985
+ });
3986
+ execSync2(`gh issue close ${issueNumber} --reason completed`, {
3987
+ cwd,
3988
+ stdio: ["ignore", "ignore", "ignore"]
3989
+ });
3990
+ } finally {
3991
+ if (fs12.existsSync(tmpFile2)) {
3992
+ fs12.unlinkSync(tmpFile2);
3993
+ }
3994
+ }
3995
+ return;
3996
+ }
3704
3997
  if (exitCode !== 0) {
3705
3998
  const interruptionCard = formatInterruptionCard({
3706
3999
  routine: routine || "local-routine",
@@ -4044,6 +4337,33 @@ Timeout: ${printTimeout}`,
4044
4337
  });
4045
4338
  }
4046
4339
  };
4340
+ let loopGuardTrip = null;
4341
+ let activeChild = null;
4342
+ const loopGuard = new LoopGuard({
4343
+ repetitionThreshold: 5,
4344
+ pingPongThreshold: 3,
4345
+ consecutiveErrorThreshold: 2,
4346
+ slidingWindowSize: 20,
4347
+ onTrip: (trip) => {
4348
+ loopGuardTrip = trip;
4349
+ spinner?.stop();
4350
+ if (activeChild && !activeChild.killed) {
4351
+ try {
4352
+ activeChild.kill("SIGTERM");
4353
+ } catch {
4354
+ }
4355
+ const killTimer = setTimeout(() => {
4356
+ try {
4357
+ if (activeChild && !activeChild.killed) {
4358
+ activeChild.kill("SIGKILL");
4359
+ }
4360
+ } catch {
4361
+ }
4362
+ }, 3e3);
4363
+ killTimer.unref();
4364
+ }
4365
+ }
4366
+ });
4047
4367
  const stdoutParser = new LineBufferedStreamParser((line) => {
4048
4368
  const event = parseStreamJsonEvent(line);
4049
4369
  if (event) {
@@ -4053,6 +4373,7 @@ Timeout: ${printTimeout}`,
4053
4373
  const toolName = su.tool_name || su.tool_info?.name || "unknown";
4054
4374
  const toolParams = su.tool_info?.parameters;
4055
4375
  if (su.state === "ACTIVE") {
4376
+ loopGuard.recordAction(toolName, toolParams, false);
4056
4377
  const actionDesc = formatActionDescription(toolName, toolParams);
4057
4378
  lastActionDesc = actionDesc;
4058
4379
  if (spinner) {
@@ -4065,6 +4386,9 @@ Timeout: ${printTimeout}`,
4065
4386
  const formatted = formatVerboseEvent(event);
4066
4387
  if (formatted) console.log(formatted);
4067
4388
  }
4389
+ } else if (su.state === "ERROR") {
4390
+ loopGuard.recordAction(toolName, toolParams, true);
4391
+ lastActionDesc = null;
4068
4392
  } else if (su.state === "DONE") {
4069
4393
  lastActionDesc = null;
4070
4394
  if (su.tool_info?.output) {
@@ -4168,6 +4492,7 @@ Timeout: ${printTimeout}`,
4168
4492
  env: childEnv,
4169
4493
  stdio: ["inherit", "pipe", "pipe"]
4170
4494
  });
4495
+ activeChild = child;
4171
4496
  child.stdout?.on("data", (data) => {
4172
4497
  processChunk(data.toString(), false);
4173
4498
  });
@@ -4204,7 +4529,26 @@ Timeout: ${printTimeout}`,
4204
4529
  exitCode = 1;
4205
4530
  }
4206
4531
  }
4207
- if (!reportContent) {
4532
+ if (loopGuardTrip) {
4533
+ exitCode = 1;
4534
+ reportContent = formatLoopGuardReport({
4535
+ routine,
4536
+ timestamp,
4537
+ trip: loopGuardTrip
4538
+ });
4539
+ try {
4540
+ fs12.writeFileSync(executionReportPath, reportContent, "utf8");
4541
+ fs12.writeFileSync(targetReportPath, reportContent, "utf8");
4542
+ } catch {
4543
+ }
4544
+ if (routineIssueNumber) {
4545
+ const failureCard = formatLoopGuardFailureCard({
4546
+ routine,
4547
+ trip: loopGuardTrip
4548
+ });
4549
+ tryPostLocalRunMilestone(targetDir, routineIssueNumber, failureCard);
4550
+ }
4551
+ } else if (!reportContent) {
4208
4552
  reportContent = formatFallbackRunReport({
4209
4553
  routine,
4210
4554
  timestamp,
@@ -4243,8 +4587,9 @@ Timeout: ${printTimeout}`,
4243
4587
  );
4244
4588
  } catch {
4245
4589
  }
4590
+ const quotaInfo = detectQuotaExceeded(output, accumulatedStderr);
4246
4591
  if (routineIssueNumber) {
4247
- tryReconcileLocalRunIssue(targetDir, routineIssueNumber, reportContent, exitCode, hostname, routine);
4592
+ tryReconcileLocalRunIssue(targetDir, routineIssueNumber, reportContent, exitCode, hostname, routine, quotaInfo);
4248
4593
  }
4249
4594
  if (options.showCard !== false && !options.verbose) {
4250
4595
  const prMatch = targetLabel.match(/PR\s*#?(\d+)/i);
@@ -5919,3 +6264,10 @@ program.command("telemetry [repos...]").description("Aggregate and report fleet-
5919
6264
  await runTelemetry({ ...options, repos, action });
5920
6265
  });
5921
6266
  program.parse(process.argv);
6267
+ export {
6268
+ LoopGuard,
6269
+ canonicalStringify,
6270
+ computeActionHash,
6271
+ formatLoopGuardFailureCard,
6272
+ formatLoopGuardReport
6273
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/lib/installer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAA2B,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,aAAa,EAAyC,MAAM,eAAe,CAAC;AAKrF,wBAAgB,eAAe,IAAI,MAAM,CAOxC;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAMlF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,aAAa,EACvB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAqBpB;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CA2GpH"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/lib/installer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAA2B,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,aAAa,EAAyC,MAAM,eAAe,CAAC;AAKrF,wBAAgB,eAAe,IAAI,MAAM,CAOxC;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAMlF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,aAAa,EACvB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAqBpB;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CAyIpH"}
@@ -1 +1 @@
1
- {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/lib/labels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/lib/labels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ export type LoopGuardTripReason = 'repetition' | 'ping_pong' | 'consecutive_errors';
2
+ export interface LoopGuardTrip {
3
+ reason: LoopGuardTripReason;
4
+ message: string;
5
+ toolName: string;
6
+ actionHash: string;
7
+ count: number;
8
+ }
9
+ export interface ActionRecord {
10
+ toolName: string;
11
+ args: any;
12
+ hash: string;
13
+ isError: boolean;
14
+ timestamp: number;
15
+ }
16
+ export interface LoopGuardOptions {
17
+ repetitionThreshold?: number;
18
+ pingPongThreshold?: number;
19
+ consecutiveErrorThreshold?: number;
20
+ slidingWindowSize?: number;
21
+ onTrip?: (trip: LoopGuardTrip) => void;
22
+ }
23
+ /**
24
+ * Deterministically stringifies an object by recursively sorting its keys.
25
+ */
26
+ export declare function canonicalStringify(value: any): string;
27
+ /**
28
+ * Computes a deterministic SHA-256 action hash: SHA-256(tool_name + canonicalString(args))
29
+ */
30
+ export declare function computeActionHash(toolName: string, args: any): string;
31
+ /**
32
+ * Deterministic Loop Guard & Circuit Breaker monitoring tool calls and execution events.
33
+ */
34
+ export declare class LoopGuard {
35
+ private repetitionThreshold;
36
+ private pingPongThreshold;
37
+ private consecutiveErrorThreshold;
38
+ private slidingWindowSize;
39
+ private onTrip?;
40
+ private history;
41
+ private lastErrorHash;
42
+ private consecutiveErrorCount;
43
+ private trippedResult;
44
+ constructor(options?: LoopGuardOptions);
45
+ setOnTrip(callback: (trip: LoopGuardTrip) => void): void;
46
+ isTripped(): boolean;
47
+ getTrip(): LoopGuardTrip | null;
48
+ getHistory(): ActionRecord[];
49
+ reset(): void;
50
+ /**
51
+ * Records an action occurrence and evaluates repetition, ping-pong, and error guards.
52
+ */
53
+ recordAction(toolName: string, args: any, isError?: boolean): LoopGuardTrip | null;
54
+ /**
55
+ * Feeds a single line of output (stream-json or raw text) into the guard.
56
+ */
57
+ feedLine(line: string): LoopGuardTrip | null;
58
+ private triggerTrip;
59
+ }
60
+ export interface LoopGuardFailureCardOptions {
61
+ routine: string;
62
+ trip: LoopGuardTrip;
63
+ runId?: string;
64
+ serverUrl?: string;
65
+ repository?: string;
66
+ }
67
+ /**
68
+ * Formats a structured 5-point milestone interruption card on circuit breaker trip.
69
+ */
70
+ export declare function formatLoopGuardFailureCard(options: LoopGuardFailureCardOptions): string;
71
+ export interface LoopGuardReportOptions {
72
+ routine: string;
73
+ timestamp: string;
74
+ trip: LoopGuardTrip;
75
+ }
76
+ /**
77
+ * Formats a markdown run report for .jonah-fleet/run-report.md when loop guard terminates a run.
78
+ */
79
+ export declare function formatLoopGuardReport(options: LoopGuardReportOptions): string;
80
+ //# sourceMappingURL=loop-guard.d.ts.map
@@ -0,0 +1 @@
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;CACf;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,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,qBAAa,SAAS;IACpB,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,EAMzC;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,CA6F/F;IAED;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAwBlD;IAED,OAAO,CAAC,WAAW;CAWpB;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,CAqBvF;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,CA0B7E"}
@@ -80,6 +80,11 @@ export interface FleetManifest {
80
80
  labels?: {
81
81
  protected?: string[];
82
82
  };
83
+ lessons?: boolean | LessonsConfig;
84
+ }
85
+ export interface LessonsConfig {
86
+ enabled?: boolean;
87
+ maxEntries?: number;
83
88
  }
84
89
  export declare const DEFAULT_ROUTINE_MODELS: Record<string, string>;
85
90
  export declare const DEFAULT_ROUTINE_TIMEOUTS: Record<string, number>;
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/lib/presets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/lib/presets.ts"],"names":[],"mappings":"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"}
@@ -145,12 +145,21 @@ export declare function tryPostLocalRunMilestone(cwd: string, issueNumber: numbe
145
145
  * Fails gracefully if offline or unauthenticated.
146
146
  */
147
147
  export declare function tryPostLocalRunMilestoneAsync(cwd: string, issueNumber: number, cardContent: string): Promise<boolean>;
148
+ export interface QuotaDetectionResult {
149
+ isQuota: boolean;
150
+ resetInfo?: string;
151
+ }
152
+ /**
153
+ * Detects whether routine runner stdout/stderr failed due to LLM quota exhaustion.
154
+ */
155
+ export declare function detectQuotaExceeded(output: string, stderr: string): QuotaDetectionResult;
148
156
  /**
149
157
  * Reconciles a GitHub issue for local routine execution.
150
158
  * Closes the issue if success, leaves it open with needs-attention if failure.
159
+ * Handles quota-paused routines gracefully without marking as failure.
151
160
  * Fails gracefully if offline or unauthenticated.
152
161
  */
153
- export declare function tryReconcileLocalRunIssue(cwd: string, issueNumber: number, reportContent: string, exitCode: number, hostname: string, routine?: string): void;
162
+ export declare function tryReconcileLocalRunIssue(cwd: string, issueNumber: number, reportContent: string, exitCode: number, hostname: string, routine?: string, quotaInfo?: QuotaDetectionResult): void;
154
163
  /**
155
164
  * Asynchronously marks an interrupted local routine run as failed and posts an interruption card.
156
165
  * Leaves the issue open with status:failure,needs-attention for maintainer triage.