jonah-fleet 1.4.2 → 1.5.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.
- package/CHANGELOG.md +44 -0
- package/dist/commands/daemon.d.ts +1 -0
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/index.js +574 -95
- package/dist/lib/daemon.d.ts +2 -0
- package/dist/lib/daemon.d.ts.map +1 -1
- package/dist/lib/presets.d.ts +1 -1
- package/dist/lib/runner.d.ts +3 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/terminal-card.d.ts +85 -0
- package/dist/lib/terminal-card.d.ts.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,56 @@ 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.5.0](https://github.com/juliendurandeu/jonah-fleet/compare/jonah-fleet-v1.4.2...jonah-fleet-v1.5.0) (2026-09-03)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **autowork:** add selective server-side issue querying to prevent tool buffer truncation ([#54](https://github.com/juliendurandeu/jonah-fleet/issues/54)) ([e85958b](https://github.com/juliendurandeu/jonah-fleet/commit/e85958bc9129b16af170961a0ae85ff91211ec85))
|
|
14
|
+
* **cli:** add multi-repo fleet monitoring command (jonah-fleet monitor) ([#6](https://github.com/juliendurandeu/jonah-fleet/issues/6)) ([0093c0f](https://github.com/juliendurandeu/jonah-fleet/commit/0093c0f2bdeb0d48d952119b96e541be73c59a03))
|
|
15
|
+
* **cli:** add per-agent token breakdown to jonah-fleet status and monitor commands ([#16](https://github.com/juliendurandeu/jonah-fleet/issues/16)) ([7e51d0c](https://github.com/juliendurandeu/jonah-fleet/commit/7e51d0cb6bdf8fef127cac7f13f8320821cb4391))
|
|
16
|
+
* **cli:** enhance jonah-fleet init with smart tech-stack auto-detection ([#37](https://github.com/juliendurandeu/jonah-fleet/issues/37)) ([b1b028a](https://github.com/juliendurandeu/jonah-fleet/commit/b1b028a5cc145aeb6a0a9b0df2e4ab010c1fa104))
|
|
17
|
+
* **daemon:** dynamically track and display active issue or PR in terminal spinner and status ([#57](https://github.com/juliendurandeu/jonah-fleet/issues/57)) ([f9c3baa](https://github.com/juliendurandeu/jonah-fleet/commit/f9c3baaab1562e21a0db170f311873cdc9a3e287))
|
|
18
|
+
* **daemon:** multi-cadence daemon, terminal cards, and strict allowlist review filters ([5889a0c](https://github.com/juliendurandeu/jonah-fleet/commit/5889a0c2b11b74faece74f7a64db43cb98fd47a1))
|
|
19
|
+
* **dual-execution:** priority-driven dual execution (local agents + actions) ([#53](https://github.com/juliendurandeu/jonah-fleet/issues/53)) ([5711bf3](https://github.com/juliendurandeu/jonah-fleet/commit/5711bf3798bba799ba4638c8cb2584878ad25d25))
|
|
20
|
+
* **evals:** add automated test suite for bi-directional optimization bridge and downstream sync ([#23](https://github.com/juliendurandeu/jonah-fleet/issues/23)) ([2e55227](https://github.com/juliendurandeu/jonah-fleet/commit/2e552273600c22879d81b6ad607ad912809d3dbb))
|
|
21
|
+
* **fleet-query:** extend fleet query engine with per-routine token and iteration aggregation ([#15](https://github.com/juliendurandeu/jonah-fleet/issues/15)) ([cabbbbc](https://github.com/juliendurandeu/jonah-fleet/commit/cabbbbcc62d8fe39ea135f56acdba0343aa11e02))
|
|
22
|
+
* **fleet:** initial release of jonah-fleet standalone agent suite and CLI ([1b08b3e](https://github.com/juliendurandeu/jonah-fleet/commit/1b08b3e14626cda25e76464d92782f16cfaae936))
|
|
23
|
+
* **optimizer:** implement token anomaly heuristics and automated PR triggers ([#10](https://github.com/juliendurandeu/jonah-fleet/issues/10)) ([#17](https://github.com/juliendurandeu/jonah-fleet/issues/17)) ([3090785](https://github.com/juliendurandeu/jonah-fleet/commit/30907857f7e24edaee1d2c2dbca61568d95f7767))
|
|
24
|
+
* **optimizer:** update optimizer routine with per-agent token aggregation protocol and scorecard schema ([#14](https://github.com/juliendurandeu/jonah-fleet/issues/14)) ([2e435ef](https://github.com/juliendurandeu/jonah-fleet/commit/2e435ef7492bf75dbf3c081d64375f49ea542667))
|
|
25
|
+
* **orchestration:** add failure notification and periodic scan watchdog to prevent stuck PRs ([#32](https://github.com/juliendurandeu/jonah-fleet/issues/32)) ([a7c555f](https://github.com/juliendurandeu/jonah-fleet/commit/a7c555f2f38a868674931bd9b61511b4530f2784))
|
|
26
|
+
* **orchestration:** add symphony radar, attribution notice, and inward blocker dependency gating ([#34](https://github.com/juliendurandeu/jonah-fleet/issues/34)) ([f8995ef](https://github.com/juliendurandeu/jonah-fleet/commit/f8995efd63a1509414768b2f0bf726d1de15a214))
|
|
27
|
+
* **peer-review:** add autonomous issue synthesis for unlinked PRs ([54e9a54](https://github.com/juliendurandeu/jonah-fleet/commit/54e9a54685ee89bf124923fb6086760c3753d097))
|
|
28
|
+
* **peer-review:** allow self-contained PR descriptions without blocking on linked issues ([97b7034](https://github.com/juliendurandeu/jonah-fleet/commit/97b703403040fc9dbe4f6b6622000822d9925aae))
|
|
29
|
+
* **prompts:** add Design System & Telemetry Friction Guardrails to core routines (closes [#49](https://github.com/juliendurandeu/jonah-fleet/issues/49)) ([#50](https://github.com/juliendurandeu/jonah-fleet/issues/50)) ([16d1011](https://github.com/juliendurandeu/jonah-fleet/commit/16d1011ac5255b84f93a8ece7e3f516d7355dc09))
|
|
30
|
+
* **prompts:** add feedback loop stagnation heuristic and closed-loop verification audit ([#24](https://github.com/juliendurandeu/jonah-fleet/issues/24)) ([c3ea012](https://github.com/juliendurandeu/jonah-fleet/commit/c3ea01297017347f6b3c43e4bdd99ea2704fd60e))
|
|
31
|
+
* **routines:** bridge analytics measurement outcomes into product planning for feature pivots and deprecations ([#43](https://github.com/juliendurandeu/jonah-fleet/issues/43)) ([446641d](https://github.com/juliendurandeu/jonah-fleet/commit/446641da7a9f9fc0c00dcf1fa98c26c067145ddc)), closes [#28](https://github.com/juliendurandeu/jonah-fleet/issues/28)
|
|
32
|
+
* **telemetry:** design and implement centralized cross-repo telemetry and token tracking hub (closes [#5](https://github.com/juliendurandeu/jonah-fleet/issues/5)) ([#22](https://github.com/juliendurandeu/jonah-fleet/issues/22)) ([e910277](https://github.com/juliendurandeu/jonah-fleet/commit/e9102779293601e94a23401a10e669bb174cb972))
|
|
33
|
+
* **workflows:** support custom cron schedules in manifest and preserve across syncs ([#47](https://github.com/juliendurandeu/jonah-fleet/issues/47)) ([#48](https://github.com/juliendurandeu/jonah-fleet/issues/48)) ([029fadb](https://github.com/juliendurandeu/jonah-fleet/commit/029fadbcabe805fb46268fa369e8f0f7272c33f1))
|
|
34
|
+
* **workflows:** support manual and comment-based (re)triggering for peer review routine ([#30](https://github.com/juliendurandeu/jonah-fleet/issues/30)) ([e8be955](https://github.com/juliendurandeu/jonah-fleet/commit/e8be955f429450fdce2d79f52a27c3ee4bb41acd)), closes [#29](https://github.com/juliendurandeu/jonah-fleet/issues/29)
|
|
35
|
+
* **workflows:** support triggering autowork via workflow_dispatch badge link (closes [#18](https://github.com/juliendurandeu/jonah-fleet/issues/18)) ([#20](https://github.com/juliendurandeu/jonah-fleet/issues/20)) ([a44e54e](https://github.com/juliendurandeu/jonah-fleet/commit/a44e54e647db11587ab58eb0ec01201cb7e9376f))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Bug Fixes
|
|
39
|
+
|
|
40
|
+
* **ci:** grant issues:write to release-please and use googleapis action ([37a6782](https://github.com/juliendurandeu/jonah-fleet/commit/37a67824e4cbbced5e08dc48d79b70a4145646ff))
|
|
41
|
+
* **detector:** use literal replacers and pmPrefix for fastapi dev ([0b96e2a](https://github.com/juliendurandeu/jonah-fleet/commit/0b96e2a06230df86a1c5a9097aa98b380565bcc8))
|
|
42
|
+
* **security:** resolve Critical and High vulnerabilities in vitest and transitive dependencies ([#42](https://github.com/juliendurandeu/jonah-fleet/issues/42)) ([9c88fa9](https://github.com/juliendurandeu/jonah-fleet/commit/9c88fa97b1529ba20fc9223ddb6e7c08e1b345f6))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
### Performance Improvements
|
|
46
|
+
|
|
47
|
+
* **workflows:** optimize github actions quota consumption ([#51](https://github.com/juliendurandeu/jonah-fleet/issues/51)) ([af8a8fb](https://github.com/juliendurandeu/jonah-fleet/commit/af8a8fb08cc9b884192e1204548a53b571f1a4a6))
|
|
48
|
+
|
|
8
49
|
## [1.4.2] - 2026-09-03
|
|
9
50
|
|
|
10
51
|
### Changed
|
|
11
52
|
- Strict Allowlist for Cloud Review Triggers:
|
|
12
53
|
- Updated `trigger-review-routine.yml` to strictly require `priority/P0` or `priority/P1` labels to fire immediate cloud reviews on `pull_request` events.
|
|
13
54
|
- Untagged PRs and lower-priority PRs (P2/P3) skip immediate cloud review, routing review execution exclusively to local peer-review daemons (with 48h scheduled cloud catchup fallback).
|
|
55
|
+
- Dynamic Issue & PR Target Tracking:
|
|
56
|
+
- Added real-time target detection (`detectClaimedIssue` and `detectClaimedPR`) in `src/lib/terminal-card.ts` that dynamically switches the live spinner label from `autowork` / `peer-review` to `[Issue #<N>]` or `[PR #<N>]` the moment a candidate is claimed.
|
|
57
|
+
- Added `activeTarget` tracking in `DaemonState` (`.jonah-fleet/daemon.json`), displayed in `jonah-fleet daemon status` (e.g. `WORKING on autowork (Issue #42)`).
|
|
14
58
|
|
|
15
59
|
## [1.4.1] - 2026-09-03
|
|
16
60
|
|
|
@@ -5,6 +5,7 @@ export interface DaemonCommandOptions {
|
|
|
5
5
|
routines?: string;
|
|
6
6
|
model?: string;
|
|
7
7
|
foreground?: boolean;
|
|
8
|
+
verbose?: boolean;
|
|
8
9
|
}
|
|
9
10
|
export declare function runDaemonCommand(action?: string, options?: DaemonCommandOptions): Promise<void>;
|
|
10
11
|
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6FzG"}
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface RunCommandOptions {
|
|
|
6
6
|
worktree?: boolean;
|
|
7
7
|
keepWorktree?: boolean;
|
|
8
8
|
dryRun?: boolean;
|
|
9
|
+
verbose?: boolean;
|
|
9
10
|
}
|
|
10
11
|
export declare function runRoutineCommand(routine: string, options?: RunCommandOptions): Promise<void>;
|
|
11
12
|
//# sourceMappingURL=run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+DvG"}
|
package/dist/index.js
CHANGED
|
@@ -92,7 +92,7 @@ var ROUTINE_TO_WORKFLOW_MAP = {
|
|
|
92
92
|
"product-planning": [],
|
|
93
93
|
"analytics-review": []
|
|
94
94
|
};
|
|
95
|
-
var FLEET_VERSION = "1.
|
|
95
|
+
var FLEET_VERSION = "1.5.0";
|
|
96
96
|
var SCHEMA_URL = "https://raw.githubusercontent.com/juliendurandeu/jonah-fleet/main/schema.json";
|
|
97
97
|
|
|
98
98
|
// src/lib/manifest.ts
|
|
@@ -2157,11 +2157,11 @@ async function runTelemetry(options = {}) {
|
|
|
2157
2157
|
}
|
|
2158
2158
|
|
|
2159
2159
|
// src/commands/run.ts
|
|
2160
|
-
import
|
|
2160
|
+
import pc10 from "picocolors";
|
|
2161
2161
|
|
|
2162
2162
|
// src/lib/runner.ts
|
|
2163
|
-
import
|
|
2164
|
-
import
|
|
2163
|
+
import fs12 from "fs";
|
|
2164
|
+
import path12 from "path";
|
|
2165
2165
|
import os2 from "os";
|
|
2166
2166
|
import { spawn, execSync as execSync2 } from "child_process";
|
|
2167
2167
|
|
|
@@ -2286,18 +2286,369 @@ async function cleanupStaleWorktrees(repoRoot) {
|
|
|
2286
2286
|
return cleaned;
|
|
2287
2287
|
}
|
|
2288
2288
|
|
|
2289
|
+
// src/lib/terminal-card.ts
|
|
2290
|
+
import fs11 from "fs";
|
|
2291
|
+
import path11 from "path";
|
|
2292
|
+
import pc9 from "picocolors";
|
|
2293
|
+
function sanitizeWorktreePaths(text) {
|
|
2294
|
+
let cleaned = text.replace(/file:\/\/\/[^\s"'()]+?\/\.jonah-fleet\/worktrees\/[^/\s"'()]+\//g, "");
|
|
2295
|
+
cleaned = cleaned.replace(/(?:^|[\s"'(`[])(?:\/[^\s"'()]+?)?\.jonah-fleet\/worktrees\/[^/\s"'()]+\//g, (match) => {
|
|
2296
|
+
const prefix = match.charAt(0);
|
|
2297
|
+
return prefix === "/" ? "" : prefix;
|
|
2298
|
+
});
|
|
2299
|
+
cleaned = cleaned.replace(/\[`?([^`\]]+?)`?\]\(file:\/\/\/[^\s)]+\)/g, "`$1`");
|
|
2300
|
+
return cleaned;
|
|
2301
|
+
}
|
|
2302
|
+
function extractExecutionSummary(output) {
|
|
2303
|
+
const summaryHeaderRegex = /#\s+([A-Za-z0-9\s_-]+?Execution\s+Summary[\s\S]*)/i;
|
|
2304
|
+
const match = output.match(summaryHeaderRegex);
|
|
2305
|
+
if (!match) return null;
|
|
2306
|
+
let summary = match[1].trim();
|
|
2307
|
+
const trailingSeparators = [
|
|
2308
|
+
"\u2713 Local peer-review completed",
|
|
2309
|
+
"\u2713 Local autowork completed",
|
|
2310
|
+
"\u2713 Local agent session",
|
|
2311
|
+
"[6:",
|
|
2312
|
+
"Peer Review Watchdog:"
|
|
2313
|
+
];
|
|
2314
|
+
for (const sep of trailingSeparators) {
|
|
2315
|
+
const idx = summary.indexOf(sep);
|
|
2316
|
+
if (idx !== -1) {
|
|
2317
|
+
summary = summary.slice(0, idx).trim();
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
return sanitizeWorktreePaths(summary);
|
|
2321
|
+
}
|
|
2322
|
+
function findLatestRunLog(repoRoot, routine) {
|
|
2323
|
+
const logsDir = path11.join(repoRoot, ".github", "prompts", "logs", routine);
|
|
2324
|
+
if (!fs11.existsSync(logsDir)) return null;
|
|
2325
|
+
try {
|
|
2326
|
+
const files = fs11.readdirSync(logsDir).filter((f) => f.endsWith(".md") && !f.startsWith("_"));
|
|
2327
|
+
if (files.length === 0) return null;
|
|
2328
|
+
files.sort().reverse();
|
|
2329
|
+
return path11.join(logsDir, files[0]);
|
|
2330
|
+
} catch {
|
|
2331
|
+
return null;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
function parseRunLog(logContent) {
|
|
2335
|
+
const summary = {
|
|
2336
|
+
passes: [],
|
|
2337
|
+
actions: []
|
|
2338
|
+
};
|
|
2339
|
+
const lines = logContent.split("\n");
|
|
2340
|
+
for (const line of lines) {
|
|
2341
|
+
const trimmed = line.trim();
|
|
2342
|
+
if (trimmed.startsWith("|") && trimmed.includes("|")) {
|
|
2343
|
+
const parts = trimmed.split("|").map((p) => p.trim()).filter(Boolean);
|
|
2344
|
+
if (parts.length >= 2) {
|
|
2345
|
+
const key = parts[0].toLowerCase();
|
|
2346
|
+
const value = parts[1].replace(/`/g, "");
|
|
2347
|
+
if (key.includes("routine")) summary.routine = value;
|
|
2348
|
+
if (key.includes("target pr") || key.includes("target issue")) summary.target = value;
|
|
2349
|
+
if (key.includes("decision")) summary.decision = value;
|
|
2350
|
+
if (key.includes("result")) summary.result = value;
|
|
2351
|
+
if (key.includes("duration")) summary.duration = value;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
let inDoD = false;
|
|
2356
|
+
let inFindings = false;
|
|
2357
|
+
let inActions = false;
|
|
2358
|
+
for (const line of lines) {
|
|
2359
|
+
const trimmed = line.trim();
|
|
2360
|
+
if (trimmed.startsWith("## Definition of Done")) {
|
|
2361
|
+
inDoD = true;
|
|
2362
|
+
inFindings = false;
|
|
2363
|
+
inActions = false;
|
|
2364
|
+
continue;
|
|
2365
|
+
} else if (trimmed.startsWith("## Code Review Findings") || trimmed.startsWith("## Findings")) {
|
|
2366
|
+
inDoD = false;
|
|
2367
|
+
inFindings = true;
|
|
2368
|
+
inActions = false;
|
|
2369
|
+
continue;
|
|
2370
|
+
} else if (trimmed.startsWith("## Execution Trace") || trimmed.startsWith("### Actions Taken")) {
|
|
2371
|
+
inDoD = false;
|
|
2372
|
+
inFindings = false;
|
|
2373
|
+
inActions = true;
|
|
2374
|
+
continue;
|
|
2375
|
+
} else if (trimmed.startsWith("## ")) {
|
|
2376
|
+
inDoD = false;
|
|
2377
|
+
inFindings = false;
|
|
2378
|
+
inActions = false;
|
|
2379
|
+
}
|
|
2380
|
+
if (inDoD && trimmed.startsWith("|") && !trimmed.includes("Criterion") && !trimmed.includes("---")) {
|
|
2381
|
+
const parts = trimmed.split("|").map((p) => p.trim()).filter(Boolean);
|
|
2382
|
+
if (parts.length >= 2) {
|
|
2383
|
+
const criterion = parts[0];
|
|
2384
|
+
const met = parts[1].toUpperCase() === "YES" || parts[1].toUpperCase() === "PASS";
|
|
2385
|
+
const evidence = parts[2] ? ` (${parts[2].slice(0, 60)}...)` : "";
|
|
2386
|
+
summary.passes?.push({
|
|
2387
|
+
name: criterion,
|
|
2388
|
+
status: met ? "pass" : "fail",
|
|
2389
|
+
detail: evidence
|
|
2390
|
+
});
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
if (inActions && (trimmed.startsWith("- ") || trimmed.startsWith("* "))) {
|
|
2394
|
+
summary.actions?.push(sanitizeWorktreePaths(trimmed.slice(2)));
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
return summary;
|
|
2398
|
+
}
|
|
2399
|
+
function detectActivePhase(chunk, currentPhase = "Executing routine") {
|
|
2400
|
+
const lower = chunk.toLowerCase();
|
|
2401
|
+
if (lower.includes("\u{1F512} claimed") || lower.includes("claimed by local autowork") || lower.includes("claimed by autowork")) {
|
|
2402
|
+
return "Claimed target issue, starting implementation";
|
|
2403
|
+
}
|
|
2404
|
+
if (lower.includes("starting review (round")) {
|
|
2405
|
+
return "Claimed review window, starting review passes";
|
|
2406
|
+
}
|
|
2407
|
+
if (lower.includes("check-client-boundary")) return "Verifying React Server Component boundaries";
|
|
2408
|
+
if (lower.includes("type-check") || lower.includes("tsc --noemit")) return "Running TypeScript type checks";
|
|
2409
|
+
if (lower.includes("lint") || lower.includes("eslint")) return "Running codebase linter";
|
|
2410
|
+
if (lower.includes("test") || lower.includes("vitest") || lower.includes("jest")) return "Running automated test suite";
|
|
2411
|
+
if (lower.includes("build") || lower.includes("next build") || lower.includes("tsup")) return "Running production build verification";
|
|
2412
|
+
if (lower.includes("code-review") || lower.includes("subagent")) return "Running multi-angle code review passes";
|
|
2413
|
+
if (lower.includes("squash-merge") || lower.includes("pr merge")) return "Squash-merging target PR to main";
|
|
2414
|
+
if (lower.includes("gh issue create") || lower.includes("autonomous issue synthesis")) return "Synthesizing tracking issue";
|
|
2415
|
+
if (lower.includes("--undo") || lower.includes("draft")) return "Bouncing PR back to draft for author fixes";
|
|
2416
|
+
if (lower.includes("issue edit") || lower.includes("pr edit")) return "Linking PR & tracking issues";
|
|
2417
|
+
if (lower.includes("pr comment") || lower.includes("review summary")) return "Submitting review comment";
|
|
2418
|
+
if (lower.includes("worktree")) return "Preparing workspace worktree";
|
|
2419
|
+
return currentPhase;
|
|
2420
|
+
}
|
|
2421
|
+
function detectClaimedIssue(chunk) {
|
|
2422
|
+
const claimMatch = chunk.match(/🔒\s*Claimed[^\n#]*?#(\d+)/i);
|
|
2423
|
+
if (claimMatch) return `Issue #${claimMatch[1]}`;
|
|
2424
|
+
const ghMatch = chunk.match(/gh\s+issue\s+(?:view|edit|comment|develop)\s+(\d+)/i);
|
|
2425
|
+
if (ghMatch) return `Issue #${ghMatch[1]}`;
|
|
2426
|
+
const textMatch = chunk.match(/(?:selected|claimed|claiming|target(?:ing)?|working|candidate)\s+(?:candidate\s+)?issue\s+#?(\d+)/i);
|
|
2427
|
+
if (textMatch) return `Issue #${textMatch[1]}`;
|
|
2428
|
+
const passiveMatch = chunk.match(/issue\s+#(\d+)\s+(?:claimed|selected)/i);
|
|
2429
|
+
if (passiveMatch) return `Issue #${passiveMatch[1]}`;
|
|
2430
|
+
return null;
|
|
2431
|
+
}
|
|
2432
|
+
function detectClaimedPR(chunk) {
|
|
2433
|
+
const reviewMatch = chunk.match(/Starting\s+review[^\n#]*?#(\d+)/i);
|
|
2434
|
+
if (reviewMatch) return `PR #${reviewMatch[1]}`;
|
|
2435
|
+
const prMatch = chunk.match(/(?:selected|target|reviewing)\s+(?:target\s+)?PR:?\s*\[?PR\s*#?(\d+)/i);
|
|
2436
|
+
if (prMatch) return `PR #${prMatch[1]}`;
|
|
2437
|
+
const ghPrMatch = chunk.match(/gh\s+pr\s+(?:view|diff|checkout|review)\s+(\d+)/i);
|
|
2438
|
+
if (ghPrMatch) return `PR #${ghPrMatch[1]}`;
|
|
2439
|
+
return null;
|
|
2440
|
+
}
|
|
2441
|
+
function renderSummaryCard(options) {
|
|
2442
|
+
const width = Math.min(Math.max((process.stdout.columns || 80) - 4, 60), 86);
|
|
2443
|
+
const horizontal = "\u2500".repeat(width - 2);
|
|
2444
|
+
const rawSummary = options.output ? extractExecutionSummary(options.output) : null;
|
|
2445
|
+
let parsedFromLog = null;
|
|
2446
|
+
if (options.repoRoot) {
|
|
2447
|
+
const latestLog = findLatestRunLog(options.repoRoot, options.routine);
|
|
2448
|
+
if (latestLog) {
|
|
2449
|
+
try {
|
|
2450
|
+
const content = fs11.readFileSync(latestLog, "utf8");
|
|
2451
|
+
parsedFromLog = parseRunLog(content);
|
|
2452
|
+
parsedFromLog.logPath = path11.relative(options.repoRoot, latestLog);
|
|
2453
|
+
} catch {
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
let target = options.pr ? `PR #${options.pr}` : options.issue ? `Issue #${options.issue}` : "";
|
|
2458
|
+
if (!target && parsedFromLog?.target) target = parsedFromLog.target;
|
|
2459
|
+
let decision = parsedFromLog?.decision || "";
|
|
2460
|
+
if (!decision && rawSummary) {
|
|
2461
|
+
const decisionMatch = rawSummary.match(/\*\*Final Action\*\*:\s*([^\n]+)/i);
|
|
2462
|
+
if (decisionMatch) decision = decisionMatch[1].replace(/[`*]/g, "").trim();
|
|
2463
|
+
}
|
|
2464
|
+
const durationStr = options.durationMs ? `${Math.round(options.durationMs / 1e3)}s` : parsedFromLog?.duration || "";
|
|
2465
|
+
const lines = [];
|
|
2466
|
+
lines.push(pc9.cyan(`\u250C${horizontal}\u2510`));
|
|
2467
|
+
const title = ` Jonah Fleet Routine: ${pc9.bold(options.routine.toUpperCase())} `;
|
|
2468
|
+
lines.push(
|
|
2469
|
+
pc9.cyan("\u2502") + ` ${pc9.bold(pc9.white(options.routine.toUpperCase()))}` + (target ? ` \xB7 ${pc9.yellow(target)}` : "") + (durationStr ? pc9.dim(` (${durationStr})`) : "") + " ".repeat(
|
|
2470
|
+
Math.max(
|
|
2471
|
+
1,
|
|
2472
|
+
width - 4 - options.routine.length - target.length - (durationStr ? durationStr.length + 3 : 0)
|
|
2473
|
+
)
|
|
2474
|
+
) + pc9.cyan("\u2502")
|
|
2475
|
+
);
|
|
2476
|
+
if (decision) {
|
|
2477
|
+
let decisionBadge = pc9.green(`\u2714 ${decision}`);
|
|
2478
|
+
if (/bounce|draft|reject|fail/i.test(decision)) {
|
|
2479
|
+
decisionBadge = pc9.yellow(`\u26A0\uFE0F ${decision}`);
|
|
2480
|
+
} else if (/escalat/i.test(decision)) {
|
|
2481
|
+
decisionBadge = pc9.red(`\u{1F6A8} ${decision}`);
|
|
2482
|
+
}
|
|
2483
|
+
lines.push(
|
|
2484
|
+
pc9.cyan("\u2502") + ` Action: ${decisionBadge}` + " ".repeat(Math.max(1, width - 11 - decision.length)) + pc9.cyan("\u2502")
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
lines.push(pc9.cyan(`\u251C${horizontal}\u2524`));
|
|
2488
|
+
if (rawSummary) {
|
|
2489
|
+
const summaryLines = rawSummary.split("\n");
|
|
2490
|
+
for (const rawLine of summaryLines) {
|
|
2491
|
+
const line = rawLine.trim();
|
|
2492
|
+
if (!line) continue;
|
|
2493
|
+
if (line.startsWith("# ")) continue;
|
|
2494
|
+
if (line.startsWith("---")) continue;
|
|
2495
|
+
if (line.startsWith("**Selected Target") || line.startsWith("**Final Action") || line.startsWith("**Mode**:")) {
|
|
2496
|
+
continue;
|
|
2497
|
+
}
|
|
2498
|
+
if (line.startsWith("### ")) {
|
|
2499
|
+
const heading = line.replace("### ", "").trim();
|
|
2500
|
+
lines.push(
|
|
2501
|
+
pc9.cyan("\u2502") + ` ${pc9.bold(pc9.cyan(heading))}` + " ".repeat(Math.max(1, width - 3 - heading.length)) + pc9.cyan("\u2502")
|
|
2502
|
+
);
|
|
2503
|
+
} else if (line.startsWith("- ") || line.startsWith("* ")) {
|
|
2504
|
+
const item = sanitizeWorktreePaths(line.slice(2)).trim();
|
|
2505
|
+
const formatted = item.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, (_, text) => pc9.bold(text)).replace(/`([^`]+)`/g, (_, code) => pc9.yellow(code));
|
|
2506
|
+
const plainLen = item.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").length;
|
|
2507
|
+
if (plainLen <= width - 6) {
|
|
2508
|
+
lines.push(pc9.cyan("\u2502") + ` \u2022 ${formatted}` + " ".repeat(Math.max(1, width - 5 - plainLen)) + pc9.cyan("\u2502"));
|
|
2509
|
+
} else {
|
|
2510
|
+
const truncated = formatted.slice(0, width - 10) + "...";
|
|
2511
|
+
lines.push(pc9.cyan("\u2502") + ` \u2022 ${truncated}` + " ".repeat(Math.max(1, width - 5 - (width - 7))) + pc9.cyan("\u2502"));
|
|
2512
|
+
}
|
|
2513
|
+
} else if (/^[0-9]+\.\s+/.test(line)) {
|
|
2514
|
+
const item = sanitizeWorktreePaths(line.replace(/^[0-9]+\.\s+/, "")).trim();
|
|
2515
|
+
const formatted = item.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, (_, text) => pc9.bold(text)).replace(/`([^`]+)`/g, (_, code) => pc9.yellow(code));
|
|
2516
|
+
const plainLen = item.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").length;
|
|
2517
|
+
if (plainLen <= width - 6) {
|
|
2518
|
+
lines.push(pc9.cyan("\u2502") + ` \u2714 ${formatted}` + " ".repeat(Math.max(1, width - 5 - plainLen)) + pc9.cyan("\u2502"));
|
|
2519
|
+
} else {
|
|
2520
|
+
const truncated = formatted.slice(0, width - 10) + "...";
|
|
2521
|
+
lines.push(pc9.cyan("\u2502") + ` \u2714 ${truncated}` + " ".repeat(Math.max(1, width - 5 - (width - 7))) + pc9.cyan("\u2502"));
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
} else if (parsedFromLog && parsedFromLog.passes && parsedFromLog.passes.length > 0) {
|
|
2526
|
+
lines.push(pc9.cyan("\u2502") + ` ${pc9.bold("Verification Passes:")}` + " ".repeat(Math.max(1, width - 23)) + pc9.cyan("\u2502"));
|
|
2527
|
+
for (const pass of parsedFromLog.passes.slice(0, 6)) {
|
|
2528
|
+
const icon = pass.status === "pass" ? pc9.green("\u2714") : pc9.red("\u2716");
|
|
2529
|
+
const text = `${pass.name}${pass.detail || ""}`;
|
|
2530
|
+
const plainLen = text.length + 4;
|
|
2531
|
+
const truncated = plainLen > width - 6 ? text.slice(0, width - 10) + "..." : text;
|
|
2532
|
+
lines.push(pc9.cyan("\u2502") + ` ${icon} ${truncated}` + " ".repeat(Math.max(1, width - 5 - truncated.length)) + pc9.cyan("\u2502"));
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
if (parsedFromLog?.logPath) {
|
|
2536
|
+
lines.push(pc9.cyan(`\u251C${horizontal}\u2524`));
|
|
2537
|
+
const logInfo = ` Run log: ${pc9.dim(parsedFromLog.logPath)}`;
|
|
2538
|
+
const logPlain = ` Run log: ${parsedFromLog.logPath}`;
|
|
2539
|
+
lines.push(pc9.cyan("\u2502") + logInfo + " ".repeat(Math.max(1, width - 2 - logPlain.length)) + pc9.cyan("\u2502"));
|
|
2540
|
+
}
|
|
2541
|
+
lines.push(pc9.cyan(`\u2514${horizontal}\u2518`));
|
|
2542
|
+
return lines.join("\n");
|
|
2543
|
+
}
|
|
2544
|
+
function renderErrorCard(options) {
|
|
2545
|
+
const width = Math.min(Math.max((process.stdout.columns || 80) - 4, 60), 86);
|
|
2546
|
+
const horizontal = "\u2500".repeat(width - 2);
|
|
2547
|
+
const lines = [];
|
|
2548
|
+
lines.push(pc9.red(`\u250C${horizontal}\u2510`));
|
|
2549
|
+
const target = options.pr ? ` \xB7 PR #${options.pr}` : options.issue ? ` \xB7 Issue #${options.issue}` : "";
|
|
2550
|
+
const durationStr = options.durationMs ? ` (${Math.round(options.durationMs / 1e3)}s)` : "";
|
|
2551
|
+
const routineUpper = options.routine.toUpperCase();
|
|
2552
|
+
const header = ` \u2717 Routine '${routineUpper}' Failed (Exit Code ${options.exitCode})${target}${durationStr}`;
|
|
2553
|
+
const headerPlain = ` \u2717 Routine '${routineUpper}' Failed (Exit Code ${options.exitCode})${target}${durationStr}`;
|
|
2554
|
+
lines.push(
|
|
2555
|
+
pc9.red("\u2502") + pc9.bold(pc9.red(header.slice(0, width - 3))) + " ".repeat(Math.max(1, width - 2 - headerPlain.length)) + pc9.red("\u2502")
|
|
2556
|
+
);
|
|
2557
|
+
lines.push(pc9.red(`\u251C${horizontal}\u2524`));
|
|
2558
|
+
const logPath = path11.join(options.repoRoot, ".jonah-fleet", "daemon.log");
|
|
2559
|
+
lines.push(pc9.red("\u2502") + pc9.yellow(" Recent Log Output:") + " ".repeat(Math.max(1, width - 21)) + pc9.red("\u2502"));
|
|
2560
|
+
if (fs11.existsSync(logPath)) {
|
|
2561
|
+
try {
|
|
2562
|
+
const logContent = fs11.readFileSync(logPath, "utf8");
|
|
2563
|
+
const allLines = logContent.split("\n").filter((l) => l.trim().length > 0);
|
|
2564
|
+
const tailLines = allLines.slice(-10);
|
|
2565
|
+
for (const line of tailLines) {
|
|
2566
|
+
const cleaned = sanitizeWorktreePaths(line).trim();
|
|
2567
|
+
const truncated = cleaned.length > width - 6 ? cleaned.slice(0, width - 9) + "..." : cleaned;
|
|
2568
|
+
lines.push(pc9.red("\u2502") + pc9.dim(` ${truncated}`) + " ".repeat(Math.max(1, width - 4 - truncated.length)) + pc9.red("\u2502"));
|
|
2569
|
+
}
|
|
2570
|
+
} catch {
|
|
2571
|
+
lines.push(
|
|
2572
|
+
pc9.red("\u2502") + pc9.dim(" (Could not read .jonah-fleet/daemon.log)") + " ".repeat(Math.max(1, width - 45)) + pc9.red("\u2502")
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
} else {
|
|
2576
|
+
lines.push(pc9.red("\u2502") + pc9.dim(" (No daemon.log found)") + " ".repeat(Math.max(1, width - 26)) + pc9.red("\u2502"));
|
|
2577
|
+
}
|
|
2578
|
+
lines.push(pc9.red(`\u251C${horizontal}\u2524`));
|
|
2579
|
+
const relLogPath = path11.relative(options.repoRoot, logPath) || ".jonah-fleet/daemon.log";
|
|
2580
|
+
const footer = ` Full trace: ${relLogPath}`;
|
|
2581
|
+
const truncatedFooter = footer.slice(0, width - 4);
|
|
2582
|
+
lines.push(pc9.red("\u2502") + pc9.dim(truncatedFooter) + " ".repeat(Math.max(1, width - 2 - truncatedFooter.length)) + pc9.red("\u2502"));
|
|
2583
|
+
lines.push(pc9.red(`\u2514${horizontal}\u2518`));
|
|
2584
|
+
return lines.join("\n");
|
|
2585
|
+
}
|
|
2586
|
+
var TerminalSpinner = class {
|
|
2587
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
2588
|
+
currentFrame = 0;
|
|
2589
|
+
intervalId = null;
|
|
2590
|
+
startTime = 0;
|
|
2591
|
+
message = "";
|
|
2592
|
+
isRunning = false;
|
|
2593
|
+
isTTY;
|
|
2594
|
+
constructor() {
|
|
2595
|
+
this.isTTY = Boolean(process.stderr.isTTY);
|
|
2596
|
+
}
|
|
2597
|
+
start(initialMessage) {
|
|
2598
|
+
this.message = initialMessage;
|
|
2599
|
+
this.startTime = Date.now();
|
|
2600
|
+
this.isRunning = true;
|
|
2601
|
+
if (!this.isTTY) {
|
|
2602
|
+
process.stderr.write(`[jonah-fleet] ${initialMessage}
|
|
2603
|
+
`);
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2606
|
+
this.intervalId = setInterval(() => {
|
|
2607
|
+
this.render();
|
|
2608
|
+
}, 80);
|
|
2609
|
+
}
|
|
2610
|
+
update(newMessage) {
|
|
2611
|
+
this.message = newMessage;
|
|
2612
|
+
if (!this.isTTY) {
|
|
2613
|
+
process.stderr.write(`[jonah-fleet] ${newMessage}
|
|
2614
|
+
`);
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
render() {
|
|
2618
|
+
if (!this.isRunning || !this.isTTY) return;
|
|
2619
|
+
const frame = pc9.cyan(this.frames[this.currentFrame]);
|
|
2620
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
2621
|
+
const elapsedSeconds = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
2622
|
+
const mins = Math.floor(elapsedSeconds / 60);
|
|
2623
|
+
const secs = elapsedSeconds % 60;
|
|
2624
|
+
const timeStr = pc9.dim(`[${mins}m ${secs < 10 ? "0" : ""}${secs}s]`);
|
|
2625
|
+
process.stderr.write(`\r\x1B[K ${frame} ${this.message} ${timeStr}`);
|
|
2626
|
+
}
|
|
2627
|
+
stop() {
|
|
2628
|
+
if (!this.isRunning) return;
|
|
2629
|
+
this.isRunning = false;
|
|
2630
|
+
if (this.intervalId) {
|
|
2631
|
+
clearInterval(this.intervalId);
|
|
2632
|
+
this.intervalId = null;
|
|
2633
|
+
}
|
|
2634
|
+
if (this.isTTY) {
|
|
2635
|
+
process.stderr.write("\r\x1B[K");
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
};
|
|
2639
|
+
|
|
2289
2640
|
// src/lib/runner.ts
|
|
2290
2641
|
function discoverSkillsPrompt(targetDir) {
|
|
2291
|
-
const skillsDir =
|
|
2292
|
-
if (!
|
|
2642
|
+
const skillsDir = path12.join(targetDir, ".agents", "skills");
|
|
2643
|
+
if (!fs12.existsSync(skillsDir)) return "";
|
|
2293
2644
|
let skillsPrompt = "";
|
|
2294
2645
|
try {
|
|
2295
|
-
const entries =
|
|
2646
|
+
const entries = fs12.readdirSync(skillsDir, { withFileTypes: true });
|
|
2296
2647
|
for (const entry of entries) {
|
|
2297
2648
|
if (entry.isDirectory()) {
|
|
2298
|
-
const skillPath =
|
|
2299
|
-
const fullPath =
|
|
2300
|
-
if (
|
|
2649
|
+
const skillPath = path12.join(".agents", "skills", entry.name, "SKILL.md");
|
|
2650
|
+
const fullPath = path12.join(targetDir, skillPath);
|
|
2651
|
+
if (fs12.existsSync(fullPath)) {
|
|
2301
2652
|
skillsPrompt += `Read and follow ${skillPath}. `;
|
|
2302
2653
|
}
|
|
2303
2654
|
}
|
|
@@ -2324,14 +2675,14 @@ function buildRoutinePrompt(targetDir, routine, options = {}) {
|
|
|
2324
2675
|
return `You are the ${routine} routine for this repository. Read and follow the instructions in ${promptFile} exactly. ${skillsPrompt}`;
|
|
2325
2676
|
}
|
|
2326
2677
|
async function runLocalRoutine(options) {
|
|
2327
|
-
const targetDir =
|
|
2678
|
+
const targetDir = path12.resolve(options.targetDir);
|
|
2328
2679
|
const routine = options.routine;
|
|
2329
2680
|
const model = options.model || "gemini-3.7-flash-high";
|
|
2330
2681
|
const printTimeout = options.printTimeout || "30m";
|
|
2331
2682
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2332
2683
|
const hostname = os2.hostname();
|
|
2333
|
-
const promptFile =
|
|
2334
|
-
if (!
|
|
2684
|
+
const promptFile = path12.join(targetDir, ".github", "prompts", `${routine}.md`);
|
|
2685
|
+
if (!fs12.existsSync(promptFile)) {
|
|
2335
2686
|
throw new Error(`Routine prompt file not found: ${promptFile}`);
|
|
2336
2687
|
}
|
|
2337
2688
|
let branchName = `agent/${routine}-${timestamp}`;
|
|
@@ -2384,7 +2735,19 @@ Timeout: ${printTimeout}`,
|
|
|
2384
2735
|
];
|
|
2385
2736
|
let output = "";
|
|
2386
2737
|
let exitCode = 0;
|
|
2738
|
+
const startTime = Date.now();
|
|
2739
|
+
const logDir = path12.join(targetDir, ".jonah-fleet");
|
|
2740
|
+
fs12.mkdirSync(logDir, { recursive: true });
|
|
2741
|
+
const logFilePath = path12.join(logDir, "daemon.log");
|
|
2742
|
+
let targetLabel = options.pr ? `PR #${options.pr}` : options.issue ? `Issue #${options.issue}` : routine;
|
|
2743
|
+
let dynamicTargetDetected = Boolean(options.pr || options.issue);
|
|
2744
|
+
let activePhase = "Starting session...";
|
|
2745
|
+
const spinner = !options.verbose ? new TerminalSpinner() : null;
|
|
2746
|
+
if (spinner) {
|
|
2747
|
+
spinner.start(`${targetLabel}: ${activePhase}`);
|
|
2748
|
+
}
|
|
2387
2749
|
const cleanup = async () => {
|
|
2750
|
+
spinner?.stop();
|
|
2388
2751
|
if (worktreePath && !options.keepWorktree) {
|
|
2389
2752
|
await removeWorktree(targetDir, worktreePath, { deleteBranch: false }).catch(() => {
|
|
2390
2753
|
});
|
|
@@ -2396,6 +2759,40 @@ Timeout: ${printTimeout}`,
|
|
|
2396
2759
|
};
|
|
2397
2760
|
process.once("SIGINT", sigintHandler);
|
|
2398
2761
|
process.once("SIGTERM", sigintHandler);
|
|
2762
|
+
const processChunk = (chunk, isStderr = false) => {
|
|
2763
|
+
output += chunk;
|
|
2764
|
+
try {
|
|
2765
|
+
fs12.appendFileSync(logFilePath, chunk, "utf8");
|
|
2766
|
+
} catch {
|
|
2767
|
+
}
|
|
2768
|
+
if (!dynamicTargetDetected) {
|
|
2769
|
+
const detected = routine === "peer-review" ? detectClaimedPR(chunk) : detectClaimedIssue(chunk);
|
|
2770
|
+
if (detected) {
|
|
2771
|
+
dynamicTargetDetected = true;
|
|
2772
|
+
targetLabel = detected;
|
|
2773
|
+
options.onTargetDetected?.(detected);
|
|
2774
|
+
if (spinner) {
|
|
2775
|
+
spinner.update(`${targetLabel}: ${activePhase}`);
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
if (options.onLog) {
|
|
2780
|
+
options.onLog(chunk);
|
|
2781
|
+
}
|
|
2782
|
+
if (options.verbose) {
|
|
2783
|
+
if (isStderr) {
|
|
2784
|
+
process.stderr.write(chunk);
|
|
2785
|
+
} else {
|
|
2786
|
+
process.stdout.write(chunk);
|
|
2787
|
+
}
|
|
2788
|
+
} else if (spinner) {
|
|
2789
|
+
const newPhase = detectActivePhase(chunk, activePhase);
|
|
2790
|
+
if (newPhase !== activePhase) {
|
|
2791
|
+
activePhase = newPhase;
|
|
2792
|
+
spinner.update(`${targetLabel}: ${activePhase}`);
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
};
|
|
2399
2796
|
try {
|
|
2400
2797
|
exitCode = await new Promise((resolve, reject) => {
|
|
2401
2798
|
const child = spawn("agy", args, {
|
|
@@ -2404,37 +2801,56 @@ Timeout: ${printTimeout}`,
|
|
|
2404
2801
|
stdio: ["inherit", "pipe", "pipe"]
|
|
2405
2802
|
});
|
|
2406
2803
|
child.stdout?.on("data", (data) => {
|
|
2407
|
-
|
|
2408
|
-
output += chunk;
|
|
2409
|
-
if (options.onLog) {
|
|
2410
|
-
options.onLog(chunk);
|
|
2411
|
-
} else {
|
|
2412
|
-
process.stdout.write(chunk);
|
|
2413
|
-
}
|
|
2804
|
+
processChunk(data.toString(), false);
|
|
2414
2805
|
});
|
|
2415
2806
|
child.stderr?.on("data", (data) => {
|
|
2416
|
-
|
|
2417
|
-
output += chunk;
|
|
2418
|
-
if (options.onLog) {
|
|
2419
|
-
options.onLog(chunk);
|
|
2420
|
-
} else {
|
|
2421
|
-
process.stderr.write(chunk);
|
|
2422
|
-
}
|
|
2807
|
+
processChunk(data.toString(), true);
|
|
2423
2808
|
});
|
|
2424
2809
|
child.on("error", (err) => {
|
|
2810
|
+
spinner?.stop();
|
|
2425
2811
|
reject(err);
|
|
2426
2812
|
});
|
|
2427
2813
|
child.on("close", (code) => {
|
|
2814
|
+
spinner?.stop();
|
|
2428
2815
|
resolve(code ?? 0);
|
|
2429
2816
|
});
|
|
2430
2817
|
});
|
|
2431
2818
|
} finally {
|
|
2819
|
+
spinner?.stop();
|
|
2432
2820
|
process.removeListener("SIGINT", sigintHandler);
|
|
2433
2821
|
process.removeListener("SIGTERM", sigintHandler);
|
|
2434
2822
|
if (!options.keepWorktree) {
|
|
2435
2823
|
await cleanup();
|
|
2436
2824
|
}
|
|
2437
2825
|
}
|
|
2826
|
+
if (options.showCard !== false && !options.verbose) {
|
|
2827
|
+
const durationMs = Date.now() - startTime;
|
|
2828
|
+
const effectiveIssue = options.issue || (targetLabel.startsWith("Issue #") ? targetLabel.replace("Issue #", "") : void 0);
|
|
2829
|
+
const effectivePR = options.pr || (targetLabel.startsWith("PR #") ? targetLabel.replace("PR #", "") : void 0);
|
|
2830
|
+
if (exitCode === 0) {
|
|
2831
|
+
console.log(
|
|
2832
|
+
"\n" + renderSummaryCard({
|
|
2833
|
+
routine,
|
|
2834
|
+
output,
|
|
2835
|
+
repoRoot: targetDir,
|
|
2836
|
+
issue: effectiveIssue,
|
|
2837
|
+
pr: effectivePR,
|
|
2838
|
+
durationMs
|
|
2839
|
+
}) + "\n"
|
|
2840
|
+
);
|
|
2841
|
+
} else {
|
|
2842
|
+
console.log(
|
|
2843
|
+
"\n" + renderErrorCard({
|
|
2844
|
+
routine,
|
|
2845
|
+
exitCode,
|
|
2846
|
+
repoRoot: targetDir,
|
|
2847
|
+
issue: effectiveIssue,
|
|
2848
|
+
pr: effectivePR,
|
|
2849
|
+
durationMs
|
|
2850
|
+
}) + "\n"
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2438
2854
|
return {
|
|
2439
2855
|
success: exitCode === 0,
|
|
2440
2856
|
exitCode,
|
|
@@ -2450,28 +2866,31 @@ async function runRoutineCommand(routine, options = {}) {
|
|
|
2450
2866
|
const manifest = loadManifest(cwd);
|
|
2451
2867
|
if (!manifest) {
|
|
2452
2868
|
console.warn(
|
|
2453
|
-
|
|
2869
|
+
pc10.yellow(`\u26A0\uFE0F No agents-manifest.json found in ${cwd}. Running in unmanaged repository mode.`)
|
|
2454
2870
|
);
|
|
2455
2871
|
} else if (manifest.routines && manifest.routines[routine] === false) {
|
|
2456
2872
|
console.warn(
|
|
2457
|
-
|
|
2873
|
+
pc10.yellow(`\u26A0\uFE0F Routine '${routine}' is disabled in agents-manifest.json. Running anyway via explicit command.`)
|
|
2458
2874
|
);
|
|
2459
2875
|
}
|
|
2460
|
-
console.log(
|
|
2461
|
-
\u{1F680} Launching local agent session for routine: ${
|
|
2876
|
+
console.log(pc10.cyan(`
|
|
2877
|
+
\u{1F680} Launching local agent session for routine: ${pc10.bold(routine)}`));
|
|
2462
2878
|
if (options.issue) {
|
|
2463
|
-
console.log(
|
|
2879
|
+
console.log(pc10.dim(` Target issue: #${options.issue}`));
|
|
2464
2880
|
}
|
|
2465
2881
|
if (options.pr) {
|
|
2466
|
-
console.log(
|
|
2882
|
+
console.log(pc10.dim(` Target pull request: #${options.pr}`));
|
|
2467
2883
|
}
|
|
2468
2884
|
if (options.model) {
|
|
2469
|
-
console.log(
|
|
2885
|
+
console.log(pc10.dim(` Model override: ${options.model}`));
|
|
2886
|
+
}
|
|
2887
|
+
if (options.verbose) {
|
|
2888
|
+
console.log(pc10.dim(` Verbose output: Enabled (streaming raw tokens)`));
|
|
2470
2889
|
}
|
|
2471
2890
|
if (options.worktree !== false) {
|
|
2472
|
-
console.log(
|
|
2891
|
+
console.log(pc10.dim(` Workspace isolation: Git Worktree (.jonah-fleet/worktrees/)`));
|
|
2473
2892
|
} else {
|
|
2474
|
-
console.log(
|
|
2893
|
+
console.log(pc10.yellow(` Workspace isolation: Disabled (running in current directory)`));
|
|
2475
2894
|
}
|
|
2476
2895
|
console.log("");
|
|
2477
2896
|
try {
|
|
@@ -2484,59 +2903,60 @@ async function runRoutineCommand(routine, options = {}) {
|
|
|
2484
2903
|
printTimeout: options.timeout,
|
|
2485
2904
|
noWorktree: options.worktree === false,
|
|
2486
2905
|
keepWorktree: options.keepWorktree,
|
|
2487
|
-
dryRun: options.dryRun
|
|
2906
|
+
dryRun: options.dryRun,
|
|
2907
|
+
verbose: options.verbose
|
|
2488
2908
|
});
|
|
2489
2909
|
if (options.dryRun) {
|
|
2490
|
-
console.log(
|
|
2910
|
+
console.log(pc10.green(result.output));
|
|
2491
2911
|
return;
|
|
2492
2912
|
}
|
|
2493
2913
|
if (result.success) {
|
|
2494
|
-
console.log(
|
|
2914
|
+
console.log(pc10.green(`
|
|
2495
2915
|
\u2713 Local agent session for '${routine}' completed successfully.`));
|
|
2496
2916
|
} else {
|
|
2497
|
-
console.error(
|
|
2917
|
+
console.error(pc10.red(`
|
|
2498
2918
|
\u2717 Local agent session for '${routine}' failed with exit code ${result.exitCode}.`));
|
|
2499
2919
|
process.exit(result.exitCode);
|
|
2500
2920
|
}
|
|
2501
2921
|
} catch (error) {
|
|
2502
|
-
console.error(
|
|
2922
|
+
console.error(pc10.red(`
|
|
2503
2923
|
\u2717 Failed to execute routine '${routine}': ${error.message}`));
|
|
2504
2924
|
process.exit(1);
|
|
2505
2925
|
}
|
|
2506
2926
|
}
|
|
2507
2927
|
|
|
2508
2928
|
// src/commands/daemon.ts
|
|
2509
|
-
import
|
|
2929
|
+
import pc12 from "picocolors";
|
|
2510
2930
|
|
|
2511
2931
|
// src/lib/daemon.ts
|
|
2512
|
-
import
|
|
2513
|
-
import
|
|
2932
|
+
import fs13 from "fs";
|
|
2933
|
+
import path13 from "path";
|
|
2514
2934
|
import { spawn as spawn2, execFile as execFile3 } from "child_process";
|
|
2515
2935
|
import { promisify as promisify3 } from "util";
|
|
2516
|
-
import
|
|
2936
|
+
import pc11 from "picocolors";
|
|
2517
2937
|
var execFileAsync3 = promisify3(execFile3);
|
|
2518
2938
|
function getDaemonStatePath(repoRoot) {
|
|
2519
|
-
return
|
|
2939
|
+
return path13.join(repoRoot, ".jonah-fleet", "daemon.json");
|
|
2520
2940
|
}
|
|
2521
2941
|
function readDaemonState(repoRoot) {
|
|
2522
2942
|
const statePath = getDaemonStatePath(repoRoot);
|
|
2523
|
-
if (!
|
|
2943
|
+
if (!fs13.existsSync(statePath)) return null;
|
|
2524
2944
|
try {
|
|
2525
|
-
return JSON.parse(
|
|
2945
|
+
return JSON.parse(fs13.readFileSync(statePath, "utf8"));
|
|
2526
2946
|
} catch {
|
|
2527
2947
|
return null;
|
|
2528
2948
|
}
|
|
2529
2949
|
}
|
|
2530
2950
|
function writeDaemonState(repoRoot, state) {
|
|
2531
2951
|
const statePath = getDaemonStatePath(repoRoot);
|
|
2532
|
-
|
|
2533
|
-
|
|
2952
|
+
fs13.mkdirSync(path13.dirname(statePath), { recursive: true });
|
|
2953
|
+
fs13.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
2534
2954
|
}
|
|
2535
2955
|
function clearDaemonState(repoRoot) {
|
|
2536
2956
|
const statePath = getDaemonStatePath(repoRoot);
|
|
2537
|
-
if (
|
|
2957
|
+
if (fs13.existsSync(statePath)) {
|
|
2538
2958
|
try {
|
|
2539
|
-
|
|
2959
|
+
fs13.unlinkSync(statePath);
|
|
2540
2960
|
} catch {
|
|
2541
2961
|
}
|
|
2542
2962
|
}
|
|
@@ -2572,9 +2992,9 @@ async function startBackgroundDaemon(repoRoot, options = {}) {
|
|
|
2572
2992
|
const reviewInterval = options.reviewInterval || 3;
|
|
2573
2993
|
const autoworkInterval = options.autoworkInterval || options.interval || 30;
|
|
2574
2994
|
const routines = options.routines || ["peer-review", "autowork"];
|
|
2575
|
-
const logFilePath =
|
|
2576
|
-
|
|
2577
|
-
const logFd =
|
|
2995
|
+
const logFilePath = path13.join(repoRoot, ".jonah-fleet", "daemon.log");
|
|
2996
|
+
fs13.mkdirSync(path13.dirname(logFilePath), { recursive: true });
|
|
2997
|
+
const logFd = fs13.openSync(logFilePath, "a");
|
|
2578
2998
|
const cliPath = process.argv[1];
|
|
2579
2999
|
const args = [
|
|
2580
3000
|
"daemon",
|
|
@@ -2589,6 +3009,9 @@ async function startBackgroundDaemon(repoRoot, options = {}) {
|
|
|
2589
3009
|
if (options.model) {
|
|
2590
3010
|
args.push("--model", options.model);
|
|
2591
3011
|
}
|
|
3012
|
+
if (options.verbose) {
|
|
3013
|
+
args.push("--verbose");
|
|
3014
|
+
}
|
|
2592
3015
|
const child = spawn2(process.execPath, [cliPath, ...args], {
|
|
2593
3016
|
cwd: repoRoot,
|
|
2594
3017
|
detached: true,
|
|
@@ -2633,19 +3056,48 @@ async function runDaemonLoop(repoRoot, options = {}) {
|
|
|
2633
3056
|
status: "idle"
|
|
2634
3057
|
};
|
|
2635
3058
|
writeDaemonState(repoRoot, state);
|
|
2636
|
-
console.log(
|
|
3059
|
+
console.log(pc11.cyan(`
|
|
2637
3060
|
\u{1F916} Jonah Fleet Multi-Cadence Local Agent Daemon Started`));
|
|
2638
|
-
console.log(
|
|
2639
|
-
console.log(
|
|
2640
|
-
console.log(
|
|
2641
|
-
console.log(
|
|
3061
|
+
console.log(pc11.dim(` PID: ${process.pid}`));
|
|
3062
|
+
console.log(pc11.dim(` Peer Review Watchdog: Every ${reviewInterval} minutes (with zero-cost PR preflight)`));
|
|
3063
|
+
console.log(pc11.dim(` Autowork Backlog Scan: Every ${autoworkInterval} minutes`));
|
|
3064
|
+
console.log(pc11.dim(` Working Directory: ${repoRoot}
|
|
2642
3065
|
`));
|
|
2643
3066
|
let isStopping = false;
|
|
2644
3067
|
let isWorking = false;
|
|
3068
|
+
const reviewIntervalMs = reviewInterval * 60 * 1e3;
|
|
3069
|
+
const autoworkIntervalMs = autoworkInterval * 60 * 1e3;
|
|
3070
|
+
let nextReviewCheckTime = Date.now() + (routines.includes("peer-review") ? reviewIntervalMs : Infinity);
|
|
3071
|
+
let nextAutoworkCheckTime = Date.now() + (routines.includes("autowork") ? autoworkIntervalMs : Infinity);
|
|
3072
|
+
let lastOpenPRCount = void 0;
|
|
3073
|
+
const clearTicker = () => {
|
|
3074
|
+
if (process.stderr.isTTY && !options.verbose) {
|
|
3075
|
+
process.stderr.write("\r\x1B[K");
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
const updateTicker = () => {
|
|
3079
|
+
if (isStopping || isWorking || options.verbose || !process.stderr.isTTY) return;
|
|
3080
|
+
const now = Date.now();
|
|
3081
|
+
const nextCheck = Math.min(nextReviewCheckTime, nextAutoworkCheckTime);
|
|
3082
|
+
const diffMs = Math.max(0, nextCheck - now);
|
|
3083
|
+
const remainingSecs = Math.ceil(diffMs / 1e3);
|
|
3084
|
+
const mins = Math.floor(remainingSecs / 60);
|
|
3085
|
+
const secs = remainingSecs % 60;
|
|
3086
|
+
const timeStr = `${mins}m ${secs < 10 ? "0" : ""}${secs}s`;
|
|
3087
|
+
const prStr = lastOpenPRCount !== void 0 ? ` (${lastOpenPRCount} ready PRs)` : "";
|
|
3088
|
+
process.stderr.write(
|
|
3089
|
+
`\r\x1B[K${pc11.dim("[" + (/* @__PURE__ */ new Date()).toLocaleTimeString() + "]")} \u{1F4A4} ${pc11.dim("Watchdog Idle \xB7 Next check in " + timeStr + prStr)}`
|
|
3090
|
+
);
|
|
3091
|
+
};
|
|
3092
|
+
const tickerInterval = setInterval(updateTicker, 1e3);
|
|
2645
3093
|
const handleStop = async () => {
|
|
2646
3094
|
if (isStopping) return;
|
|
2647
3095
|
isStopping = true;
|
|
2648
|
-
|
|
3096
|
+
clearInterval(tickerInterval);
|
|
3097
|
+
clearInterval(reviewTimer);
|
|
3098
|
+
clearInterval(autoworkTimer);
|
|
3099
|
+
clearTicker();
|
|
3100
|
+
console.log(pc11.yellow(`
|
|
2649
3101
|
Stopping local agent daemon...`));
|
|
2650
3102
|
clearDaemonState(repoRoot);
|
|
2651
3103
|
await cleanupStaleWorktrees(repoRoot);
|
|
@@ -2658,36 +3110,52 @@ Stopping local agent daemon...`));
|
|
|
2658
3110
|
state.lastReviewCheckAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2659
3111
|
writeDaemonState(repoRoot, state);
|
|
2660
3112
|
const openPRCount = await countOpenReadyPRs(repoRoot);
|
|
3113
|
+
lastOpenPRCount = openPRCount;
|
|
2661
3114
|
if (openPRCount === 0) {
|
|
2662
|
-
|
|
3115
|
+
if (options.verbose) {
|
|
3116
|
+
console.log(pc11.dim(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Peer Review Watchdog: 0 ready PRs found (0 tokens used).`));
|
|
3117
|
+
}
|
|
3118
|
+
nextReviewCheckTime = Date.now() + reviewIntervalMs;
|
|
3119
|
+
updateTicker();
|
|
2663
3120
|
return;
|
|
2664
3121
|
}
|
|
2665
3122
|
try {
|
|
2666
3123
|
isWorking = true;
|
|
3124
|
+
clearTicker();
|
|
2667
3125
|
state.status = "working";
|
|
2668
3126
|
state.activeRoutine = "peer-review";
|
|
2669
3127
|
writeDaemonState(repoRoot, state);
|
|
2670
|
-
console.log(
|
|
3128
|
+
console.log(pc11.cyan(`
|
|
2671
3129
|
[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] \u{1F50D} Peer Review Watchdog: Found ${openPRCount} ready PR(s). Starting review session...`));
|
|
2672
3130
|
await cleanupStaleWorktrees(repoRoot);
|
|
2673
3131
|
const result = await runLocalRoutine({
|
|
2674
3132
|
targetDir: repoRoot,
|
|
2675
3133
|
routine: "peer-review",
|
|
2676
3134
|
model: options.model,
|
|
2677
|
-
|
|
3135
|
+
verbose: options.verbose,
|
|
3136
|
+
noWorktree: false,
|
|
3137
|
+
onTargetDetected: (target) => {
|
|
3138
|
+
state.activeTarget = target;
|
|
3139
|
+
writeDaemonState(repoRoot, state);
|
|
3140
|
+
}
|
|
2678
3141
|
});
|
|
2679
3142
|
if (result.success) {
|
|
2680
|
-
console.log(
|
|
3143
|
+
console.log(pc11.green(`\u2713 Local peer-review completed successfully.
|
|
3144
|
+
`));
|
|
2681
3145
|
} else {
|
|
2682
|
-
console.warn(
|
|
3146
|
+
console.warn(pc11.yellow(`\u26A0\uFE0F Local peer-review completed with code ${result.exitCode}.
|
|
3147
|
+
`));
|
|
2683
3148
|
}
|
|
2684
3149
|
} catch (err) {
|
|
2685
|
-
console.error(
|
|
3150
|
+
console.error(pc11.red(`\u2717 Error in peer-review: ${err.message}`));
|
|
2686
3151
|
} finally {
|
|
2687
3152
|
isWorking = false;
|
|
2688
3153
|
state.status = "idle";
|
|
2689
3154
|
state.activeRoutine = void 0;
|
|
3155
|
+
state.activeTarget = void 0;
|
|
2690
3156
|
writeDaemonState(repoRoot, state);
|
|
3157
|
+
nextReviewCheckTime = Date.now() + reviewIntervalMs;
|
|
3158
|
+
updateTicker();
|
|
2691
3159
|
}
|
|
2692
3160
|
};
|
|
2693
3161
|
const runAutoworkCheck = async () => {
|
|
@@ -2696,30 +3164,41 @@ Stopping local agent daemon...`));
|
|
|
2696
3164
|
writeDaemonState(repoRoot, state);
|
|
2697
3165
|
try {
|
|
2698
3166
|
isWorking = true;
|
|
3167
|
+
clearTicker();
|
|
2699
3168
|
state.status = "working";
|
|
2700
3169
|
state.activeRoutine = "autowork";
|
|
2701
3170
|
writeDaemonState(repoRoot, state);
|
|
2702
|
-
console.log(
|
|
3171
|
+
console.log(pc11.cyan(`
|
|
2703
3172
|
[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] \u{1F680} Autowork Backlog Scan: Starting session...`));
|
|
2704
3173
|
await cleanupStaleWorktrees(repoRoot);
|
|
2705
3174
|
const result = await runLocalRoutine({
|
|
2706
3175
|
targetDir: repoRoot,
|
|
2707
3176
|
routine: "autowork",
|
|
2708
3177
|
model: options.model,
|
|
2709
|
-
|
|
3178
|
+
verbose: options.verbose,
|
|
3179
|
+
noWorktree: false,
|
|
3180
|
+
onTargetDetected: (target) => {
|
|
3181
|
+
state.activeTarget = target;
|
|
3182
|
+
writeDaemonState(repoRoot, state);
|
|
3183
|
+
}
|
|
2710
3184
|
});
|
|
2711
3185
|
if (result.success) {
|
|
2712
|
-
console.log(
|
|
3186
|
+
console.log(pc11.green(`\u2713 Local autowork completed successfully.
|
|
3187
|
+
`));
|
|
2713
3188
|
} else {
|
|
2714
|
-
console.warn(
|
|
3189
|
+
console.warn(pc11.yellow(`\u26A0\uFE0F Local autowork completed with code ${result.exitCode}.
|
|
3190
|
+
`));
|
|
2715
3191
|
}
|
|
2716
3192
|
} catch (err) {
|
|
2717
|
-
console.error(
|
|
3193
|
+
console.error(pc11.red(`\u2717 Error in autowork: ${err.message}`));
|
|
2718
3194
|
} finally {
|
|
2719
3195
|
isWorking = false;
|
|
2720
3196
|
state.status = "idle";
|
|
2721
3197
|
state.activeRoutine = void 0;
|
|
3198
|
+
state.activeTarget = void 0;
|
|
2722
3199
|
writeDaemonState(repoRoot, state);
|
|
3200
|
+
nextAutoworkCheckTime = Date.now() + autoworkIntervalMs;
|
|
3201
|
+
updateTicker();
|
|
2723
3202
|
}
|
|
2724
3203
|
};
|
|
2725
3204
|
if (routines.includes("peer-review")) {
|
|
@@ -2728,8 +3207,6 @@ Stopping local agent daemon...`));
|
|
|
2728
3207
|
if (routines.includes("autowork")) {
|
|
2729
3208
|
await runAutoworkCheck();
|
|
2730
3209
|
}
|
|
2731
|
-
const reviewIntervalMs = reviewInterval * 60 * 1e3;
|
|
2732
|
-
const autoworkIntervalMs = autoworkInterval * 60 * 1e3;
|
|
2733
3210
|
const reviewTimer = setInterval(runReviewCheck, reviewIntervalMs);
|
|
2734
3211
|
const autoworkTimer = setInterval(runAutoworkCheck, autoworkIntervalMs);
|
|
2735
3212
|
await new Promise(() => {
|
|
@@ -2746,7 +3223,8 @@ async function runDaemonCommand(action, options = {}) {
|
|
|
2746
3223
|
autoworkInterval: options.autoworkInterval ? parseInt(options.autoworkInterval, 10) : options.interval ? parseInt(options.interval, 10) : void 0,
|
|
2747
3224
|
routines: options.routines ? options.routines.split(",").map((r) => r.trim()) : void 0,
|
|
2748
3225
|
model: options.model,
|
|
2749
|
-
foreground: options.foreground
|
|
3226
|
+
foreground: options.foreground,
|
|
3227
|
+
verbose: options.verbose
|
|
2750
3228
|
};
|
|
2751
3229
|
if (act === "start") {
|
|
2752
3230
|
if (options.foreground) {
|
|
@@ -2755,16 +3233,16 @@ async function runDaemonCommand(action, options = {}) {
|
|
|
2755
3233
|
}
|
|
2756
3234
|
try {
|
|
2757
3235
|
const state2 = await startBackgroundDaemon(cwd, daemonOpts);
|
|
2758
|
-
console.log(
|
|
3236
|
+
console.log(pc12.green(`
|
|
2759
3237
|
\u2713 Background agent daemon started successfully.`));
|
|
2760
|
-
console.log(
|
|
2761
|
-
console.log(
|
|
2762
|
-
console.log(
|
|
2763
|
-
console.log(
|
|
2764
|
-
console.log(
|
|
2765
|
-
console.log(
|
|
3238
|
+
console.log(pc12.dim(` PID: ${state2.pid}`));
|
|
3239
|
+
console.log(pc12.dim(` Peer Review Watchdog: Every ${state2.reviewIntervalMinutes} minutes (zero-cost PR preflight)`));
|
|
3240
|
+
console.log(pc12.dim(` Autowork Backlog Scan: Every ${state2.autoworkIntervalMinutes} minutes`));
|
|
3241
|
+
console.log(pc12.dim(` Routines: ${state2.routines.join(", ")}`));
|
|
3242
|
+
console.log(pc12.dim(` Log file: .jonah-fleet/daemon.log`));
|
|
3243
|
+
console.log(pc12.dim(` Run 'jonah-fleet daemon status' or 'jonah-fleet daemon stop' to manage.`));
|
|
2766
3244
|
} catch (err) {
|
|
2767
|
-
console.error(
|
|
3245
|
+
console.error(pc12.red(`
|
|
2768
3246
|
\u2717 Failed to start daemon: ${err.message}`));
|
|
2769
3247
|
process.exit(1);
|
|
2770
3248
|
}
|
|
@@ -2772,18 +3250,18 @@ async function runDaemonCommand(action, options = {}) {
|
|
|
2772
3250
|
}
|
|
2773
3251
|
if (act === "stop") {
|
|
2774
3252
|
if (!isDaemonRunning(cwd)) {
|
|
2775
|
-
console.log(
|
|
3253
|
+
console.log(pc12.yellow(`
|
|
2776
3254
|
\u26A0\uFE0F No local agent daemon is currently running in this repository.`));
|
|
2777
3255
|
return;
|
|
2778
3256
|
}
|
|
2779
3257
|
const state2 = readDaemonState(cwd);
|
|
2780
|
-
console.log(
|
|
3258
|
+
console.log(pc12.cyan(`
|
|
2781
3259
|
Stopping background agent daemon (PID ${state2?.pid})...`));
|
|
2782
3260
|
const stopped = await stopDaemon(cwd);
|
|
2783
3261
|
if (stopped) {
|
|
2784
|
-
console.log(
|
|
3262
|
+
console.log(pc12.green(`\u2713 Local agent daemon stopped successfully.`));
|
|
2785
3263
|
} else {
|
|
2786
|
-
console.error(
|
|
3264
|
+
console.error(pc12.red(`\u2717 Could not terminate daemon process.`));
|
|
2787
3265
|
process.exit(1);
|
|
2788
3266
|
}
|
|
2789
3267
|
return;
|
|
@@ -2795,17 +3273,18 @@ Stopping background agent daemon (PID ${state2?.pid})...`));
|
|
|
2795
3273
|
const running = isDaemonRunning(cwd);
|
|
2796
3274
|
const state = readDaemonState(cwd);
|
|
2797
3275
|
const activeWorktrees = await listActiveWorktrees(cwd);
|
|
2798
|
-
console.log(
|
|
3276
|
+
console.log(pc12.cyan(`
|
|
2799
3277
|
\u{1F916} Jonah Fleet Local Daemon Status
|
|
2800
3278
|
`));
|
|
2801
3279
|
if (running && state) {
|
|
2802
|
-
console.log(` Status: ${
|
|
3280
|
+
console.log(` Status: ${pc12.green(pc12.bold("RUNNING"))}`);
|
|
2803
3281
|
console.log(` PID: ${state.pid}`);
|
|
2804
3282
|
console.log(` Started: ${new Date(state.startedAt).toLocaleString()}`);
|
|
2805
3283
|
console.log(` Peer Review Cadence: Every ${state.reviewIntervalMinutes} minutes (0-token fast preflight)`);
|
|
2806
3284
|
console.log(` Autowork Cadence: Every ${state.autoworkIntervalMinutes} minutes`);
|
|
2807
3285
|
console.log(` Routines: ${state.routines.join(", ")}`);
|
|
2808
|
-
|
|
3286
|
+
const workingDesc = state.activeRoutine + (state.activeTarget ? ` (${pc12.bold(state.activeTarget)})` : "");
|
|
3287
|
+
console.log(` Current State: ${state.status === "working" ? pc12.yellow("WORKING on " + workingDesc) : pc12.green("IDLE")}`);
|
|
2809
3288
|
if (state.lastReviewCheckAt) {
|
|
2810
3289
|
console.log(` Last Review Check: ${new Date(state.lastReviewCheckAt).toLocaleTimeString()}`);
|
|
2811
3290
|
}
|
|
@@ -2813,13 +3292,13 @@ Stopping background agent daemon (PID ${state2?.pid})...`));
|
|
|
2813
3292
|
console.log(` Last Autowork Check: ${new Date(state.lastAutoworkCheckAt).toLocaleTimeString()}`);
|
|
2814
3293
|
}
|
|
2815
3294
|
} else {
|
|
2816
|
-
console.log(` Status: ${
|
|
2817
|
-
console.log(
|
|
3295
|
+
console.log(` Status: ${pc12.gray("STOPPED")}`);
|
|
3296
|
+
console.log(pc12.dim(` Run 'jonah-fleet daemon start' to start the local worker daemon.`));
|
|
2818
3297
|
}
|
|
2819
3298
|
console.log(`
|
|
2820
3299
|
Active Worktrees: ${activeWorktrees.length}`);
|
|
2821
3300
|
for (const wt of activeWorktrees) {
|
|
2822
|
-
console.log(
|
|
3301
|
+
console.log(pc12.dim(` - [${wt.branch}] ${wt.path}`));
|
|
2823
3302
|
}
|
|
2824
3303
|
console.log("");
|
|
2825
3304
|
}
|
|
@@ -2827,10 +3306,10 @@ Stopping background agent daemon (PID ${state2?.pid})...`));
|
|
|
2827
3306
|
// src/index.ts
|
|
2828
3307
|
var program = new Command();
|
|
2829
3308
|
program.name("jonah-fleet").description("Manage autonomous agent fleet, prompt routines, workflows, and skills").version(FLEET_VERSION);
|
|
2830
|
-
program.command("run <routine>").description("Run a specific prompt routine locally in an isolated git worktree").option("-i, --issue <number>", "Targeted issue number for autowork").option("-p, --pr <number>", "Targeted pull request number for peer-review").option("-m, --model <model>", "LLM model override (defaults to gemini-3.7-flash-high)").option("--timeout <duration>", "CLI execution print timeout (default: 30m)").option("--no-worktree", "Execute directly in current directory without creating a git worktree").option("--keep-worktree", "Preserve the git worktree after routine execution completes").option("-d, --dry-run", "Preview prompt and execution parameters without launching agent").action(async (routine, options) => {
|
|
3309
|
+
program.command("run <routine>").description("Run a specific prompt routine locally in an isolated git worktree").option("-i, --issue <number>", "Targeted issue number for autowork").option("-p, --pr <number>", "Targeted pull request number for peer-review").option("-m, --model <model>", "LLM model override (defaults to gemini-3.7-flash-high)").option("--timeout <duration>", "CLI execution print timeout (default: 30m)").option("--no-worktree", "Execute directly in current directory without creating a git worktree").option("--keep-worktree", "Preserve the git worktree after routine execution completes").option("-d, --dry-run", "Preview prompt and execution parameters without launching agent").option("-v, --verbose", "Stream raw agent tokens and logs directly to stdout").action(async (routine, options) => {
|
|
2831
3310
|
await runRoutineCommand(routine, options);
|
|
2832
3311
|
});
|
|
2833
|
-
program.command("daemon [action]").description("Manage background local worker daemon polling for unclaimed issues and pull requests").option("-i, --interval <minutes>", "Legacy global polling interval in minutes (default: 30)").option("--review-interval <minutes>", "Peer Review watchdog cadence in minutes (default: 3)").option("--autowork-interval <minutes>", "Autowork backlog cadence in minutes (default: 30)").option("-r, --routines <list>", "Comma-separated routines to run (default: peer-review,autowork)").option("-m, --model <model>", "LLM model override").option("--foreground", "Run daemon in foreground with live console logs").action(async (action, options) => {
|
|
3312
|
+
program.command("daemon [action]").description("Manage background local worker daemon polling for unclaimed issues and pull requests").option("-i, --interval <minutes>", "Legacy global polling interval in minutes (default: 30)").option("--review-interval <minutes>", "Peer Review watchdog cadence in minutes (default: 3)").option("--autowork-interval <minutes>", "Autowork backlog cadence in minutes (default: 30)").option("-r, --routines <list>", "Comma-separated routines to run (default: peer-review,autowork)").option("-m, --model <model>", "LLM model override").option("--foreground", "Run daemon in foreground with live console logs").option("-v, --verbose", "Stream raw agent tokens and logs directly to stdout").action(async (action, options) => {
|
|
2834
3313
|
await runDaemonCommand(action, options);
|
|
2835
3314
|
});
|
|
2836
3315
|
program.command("init").description("Initialize Jonah Fleet configuration, routines, workflows, and skills in the current repo").option("-p, --preset <preset>", "Preset profile to install (minimal | standard | full)", "standard").option("-f, --force", "Force overwrite existing files", false).option("--stack <stack>", "Override detected tech stack name").option("--package-manager <pm>", "Override package manager (npm, pnpm, yarn, bun, uv, poetry, cargo, go)").option("--test-cmd <cmd>", "Override test execution command").option("--build-cmd <cmd>", "Override build execution command").option("--interactive", "Force interactive prompts for stack configuration").option("--no-interactive", "Disable interactive prompts").action(async (options) => {
|
package/dist/lib/daemon.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface DaemonState {
|
|
|
8
8
|
lastAutoworkCheckAt?: string;
|
|
9
9
|
status: 'idle' | 'working' | 'stopped';
|
|
10
10
|
activeRoutine?: string;
|
|
11
|
+
activeTarget?: string;
|
|
11
12
|
activeWorktree?: string;
|
|
12
13
|
}
|
|
13
14
|
export interface DaemonOptions {
|
|
@@ -17,6 +18,7 @@ export interface DaemonOptions {
|
|
|
17
18
|
routines?: string[];
|
|
18
19
|
model?: string;
|
|
19
20
|
foreground?: boolean;
|
|
21
|
+
verbose?: boolean;
|
|
20
22
|
}
|
|
21
23
|
export declare function getDaemonStatePath(repoRoot: string): string;
|
|
22
24
|
export declare function readDaemonState(repoRoot: string): DaemonState | null;
|
package/dist/lib/daemon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/lib/daemon.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/lib/daemon.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAQpE;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAI3E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CASvD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAYzD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWzE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsD/G;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAanE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2LhG"}
|
package/dist/lib/presets.d.ts
CHANGED
|
@@ -47,6 +47,6 @@ export declare const PRESET_CONFIGS: Record<Exclude<PresetName, 'custom'>, {
|
|
|
47
47
|
}>;
|
|
48
48
|
export declare const ROUTINE_TO_WORKFLOW_MAP: Record<keyof FleetManifest['routines'], string[]>;
|
|
49
49
|
export declare const WORKFLOW_TO_ROUTINE_MAP: Record<string, keyof FleetManifest['routines'] | 'sync-fleet'>;
|
|
50
|
-
export declare const FLEET_VERSION = "1.
|
|
50
|
+
export declare const FLEET_VERSION = "1.5.0";
|
|
51
51
|
export declare const SCHEMA_URL = "https://raw.githubusercontent.com/juliendurandeu/jonah-fleet/main/schema.json";
|
|
52
52
|
//# sourceMappingURL=presets.d.ts.map
|
package/dist/lib/runner.d.ts
CHANGED
|
@@ -8,8 +8,11 @@ export interface RunLocalRoutineOptions {
|
|
|
8
8
|
noWorktree?: boolean;
|
|
9
9
|
keepWorktree?: boolean;
|
|
10
10
|
dryRun?: boolean;
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
showCard?: boolean;
|
|
11
13
|
env?: Record<string, string>;
|
|
12
14
|
onLog?: (chunk: string) => void;
|
|
15
|
+
onTargetDetected?: (target: string) => void;
|
|
13
16
|
}
|
|
14
17
|
export interface RunLocalRoutineResult {
|
|
15
18
|
success: boolean;
|
package/dist/lib/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAoB9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAO,GAC9D,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAOxC;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAgOrG"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface SummaryCardOptions {
|
|
2
|
+
routine: string;
|
|
3
|
+
output?: string;
|
|
4
|
+
repoRoot?: string;
|
|
5
|
+
issue?: string | number;
|
|
6
|
+
pr?: string | number;
|
|
7
|
+
durationMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ErrorCardOptions {
|
|
10
|
+
routine: string;
|
|
11
|
+
exitCode: number;
|
|
12
|
+
repoRoot: string;
|
|
13
|
+
issue?: string | number;
|
|
14
|
+
pr?: string | number;
|
|
15
|
+
durationMs?: number;
|
|
16
|
+
error?: Error;
|
|
17
|
+
}
|
|
18
|
+
export interface ParsedRunSummary {
|
|
19
|
+
routine?: string;
|
|
20
|
+
target?: string;
|
|
21
|
+
decision?: string;
|
|
22
|
+
result?: string;
|
|
23
|
+
duration?: string;
|
|
24
|
+
passes?: Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
status: 'pass' | 'fail' | 'info';
|
|
27
|
+
detail?: string;
|
|
28
|
+
}>;
|
|
29
|
+
actions?: string[];
|
|
30
|
+
logPath?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Strips temporary worktree roots and converts absolute worktree paths to clean relative paths.
|
|
34
|
+
*/
|
|
35
|
+
export declare function sanitizeWorktreePaths(text: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Extracts the '# ... Execution Summary' section from routine output text.
|
|
38
|
+
*/
|
|
39
|
+
export declare function extractExecutionSummary(output: string): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Finds the latest committed run log in .github/prompts/logs/<routine>/*.md.
|
|
42
|
+
*/
|
|
43
|
+
export declare function findLatestRunLog(repoRoot: string, routine: string): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Parses markdown run log files into structured data.
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseRunLog(logContent: string): ParsedRunSummary;
|
|
48
|
+
/**
|
|
49
|
+
* Heuristics to detect active stage from streaming agent tokens.
|
|
50
|
+
*/
|
|
51
|
+
export declare function detectActivePhase(chunk: string, currentPhase?: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Detects if the agent has selected or claimed a specific issue in Scan mode.
|
|
54
|
+
*/
|
|
55
|
+
export declare function detectClaimedIssue(chunk: string): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Detects if the agent has selected a specific pull request in Scan mode.
|
|
58
|
+
*/
|
|
59
|
+
export declare function detectClaimedPR(chunk: string): string | null;
|
|
60
|
+
/**
|
|
61
|
+
* Renders a styled Unicode summary card.
|
|
62
|
+
*/
|
|
63
|
+
export declare function renderSummaryCard(options: SummaryCardOptions): string;
|
|
64
|
+
/**
|
|
65
|
+
* Renders an Error Card with tail of daemon.log.
|
|
66
|
+
*/
|
|
67
|
+
export declare function renderErrorCard(options: ErrorCardOptions): string;
|
|
68
|
+
/**
|
|
69
|
+
* Minimalist zero-dependency terminal spinner.
|
|
70
|
+
*/
|
|
71
|
+
export declare class TerminalSpinner {
|
|
72
|
+
private frames;
|
|
73
|
+
private currentFrame;
|
|
74
|
+
private intervalId;
|
|
75
|
+
private startTime;
|
|
76
|
+
private message;
|
|
77
|
+
private isRunning;
|
|
78
|
+
private isTTY;
|
|
79
|
+
constructor();
|
|
80
|
+
start(initialMessage: string): void;
|
|
81
|
+
update(newMessage: string): void;
|
|
82
|
+
private render;
|
|
83
|
+
stop(): void;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=terminal-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-card.d.ts","sourceRoot":"","sources":["../../src/lib/terminal-card.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc1D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwBrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcjF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CA8EhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,GAAE,MAA4B,GAAG,MAAM,CAuBnG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAsJrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAqDjE;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAsD;IACpE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,KAAK,CAAU;IAEvB,cAEC;IAEM,KAAK,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAazC;IAEM,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAKtC;IAED,OAAO,CAAC,MAAM;IAeP,IAAI,IAAI,IAAI,CAYlB;CACF"}
|
package/package.json
CHANGED