@bradygaster/squad-cli 0.9.2-insider.5 → 0.9.3-insider.1
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/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +27 -5
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/loop.d.ts +51 -0
- package/dist/cli/commands/loop.d.ts.map +1 -0
- package/dist/cli/commands/loop.js +352 -0
- package/dist/cli/commands/loop.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/budget-check.d.ts +29 -0
- package/dist/cli/commands/watch/capabilities/budget-check.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/budget-check.js +38 -0
- package/dist/cli/commands/watch/capabilities/budget-check.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/circuit-breaker.d.ts +52 -0
- package/dist/cli/commands/watch/capabilities/circuit-breaker.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/circuit-breaker.js +152 -0
- package/dist/cli/commands/watch/capabilities/circuit-breaker.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/cleanup.d.ts +18 -0
- package/dist/cli/commands/watch/capabilities/cleanup.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/cleanup.js +135 -0
- package/dist/cli/commands/watch/capabilities/cleanup.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/execute.d.ts +15 -3
- package/dist/cli/commands/watch/capabilities/execute.d.ts.map +1 -1
- package/dist/cli/commands/watch/capabilities/execute.js +108 -51
- package/dist/cli/commands/watch/capabilities/execute.js.map +1 -1
- package/dist/cli/commands/watch/capabilities/fleet-dispatch.d.ts +20 -0
- package/dist/cli/commands/watch/capabilities/fleet-dispatch.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/fleet-dispatch.js +144 -0
- package/dist/cli/commands/watch/capabilities/fleet-dispatch.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/health-check.d.ts +29 -0
- package/dist/cli/commands/watch/capabilities/health-check.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/health-check.js +139 -0
- package/dist/cli/commands/watch/capabilities/health-check.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/heartbeat.d.ts +48 -0
- package/dist/cli/commands/watch/capabilities/heartbeat.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/heartbeat.js +115 -0
- package/dist/cli/commands/watch/capabilities/heartbeat.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/index.d.ts.map +1 -1
- package/dist/cli/commands/watch/capabilities/index.js +4 -0
- package/dist/cli/commands/watch/capabilities/index.js.map +1 -1
- package/dist/cli/commands/watch/capabilities/lockfile.d.ts +30 -0
- package/dist/cli/commands/watch/capabilities/lockfile.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/lockfile.js +100 -0
- package/dist/cli/commands/watch/capabilities/lockfile.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/machine-capabilities.d.ts +30 -0
- package/dist/cli/commands/watch/capabilities/machine-capabilities.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/machine-capabilities.js +103 -0
- package/dist/cli/commands/watch/capabilities/machine-capabilities.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/post-failure.d.ts +19 -0
- package/dist/cli/commands/watch/capabilities/post-failure.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/post-failure.js +58 -0
- package/dist/cli/commands/watch/capabilities/post-failure.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/priority.d.ts +59 -0
- package/dist/cli/commands/watch/capabilities/priority.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/priority.js +101 -0
- package/dist/cli/commands/watch/capabilities/priority.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/rate-pool.d.ts +67 -0
- package/dist/cli/commands/watch/capabilities/rate-pool.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/rate-pool.js +187 -0
- package/dist/cli/commands/watch/capabilities/rate-pool.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/self-pull.d.ts +4 -1
- package/dist/cli/commands/watch/capabilities/self-pull.d.ts.map +1 -1
- package/dist/cli/commands/watch/capabilities/self-pull.js +53 -5
- package/dist/cli/commands/watch/capabilities/self-pull.js.map +1 -1
- package/dist/cli/commands/watch/capabilities/stale-reclaim.d.ts +23 -0
- package/dist/cli/commands/watch/capabilities/stale-reclaim.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/stale-reclaim.js +87 -0
- package/dist/cli/commands/watch/capabilities/stale-reclaim.js.map +1 -0
- package/dist/cli/commands/watch/capabilities/webhook-alerts.d.ts +29 -0
- package/dist/cli/commands/watch/capabilities/webhook-alerts.d.ts.map +1 -0
- package/dist/cli/commands/watch/capabilities/webhook-alerts.js +114 -0
- package/dist/cli/commands/watch/capabilities/webhook-alerts.js.map +1 -0
- package/dist/cli/commands/watch/config.d.ts +18 -0
- package/dist/cli/commands/watch/config.d.ts.map +1 -1
- package/dist/cli/commands/watch/config.js +20 -1
- package/dist/cli/commands/watch/config.js.map +1 -1
- package/dist/cli/commands/watch/health.d.ts +41 -0
- package/dist/cli/commands/watch/health.d.ts.map +1 -0
- package/dist/cli/commands/watch/health.js +141 -0
- package/dist/cli/commands/watch/health.js.map +1 -0
- package/dist/cli/commands/watch/index.d.ts +9 -2
- package/dist/cli/commands/watch/index.d.ts.map +1 -1
- package/dist/cli/commands/watch/index.js +115 -8
- package/dist/cli/commands/watch/index.js.map +1 -1
- package/dist/cli/commands/watch/types.d.ts +2 -0
- package/dist/cli/commands/watch/types.d.ts.map +1 -1
- package/dist/cli/commands/watch/verbose.d.ts +12 -0
- package/dist/cli/commands/watch/verbose.d.ts.map +1 -0
- package/dist/cli/commands/watch/verbose.js +28 -0
- package/dist/cli/commands/watch/verbose.js.map +1 -0
- package/dist/cli/core/detect-squad-dir.d.ts.map +1 -1
- package/dist/cli/core/detect-squad-dir.js +9 -12
- package/dist/cli/core/detect-squad-dir.js.map +1 -1
- package/dist/cli/core/nap.d.ts.map +1 -1
- package/dist/cli/core/nap.js +9 -4
- package/dist/cli/core/nap.js.map +1 -1
- package/dist/cli/core/upgrade.d.ts +18 -0
- package/dist/cli/core/upgrade.d.ts.map +1 -1
- package/dist/cli/core/upgrade.js +119 -0
- package/dist/cli/core/upgrade.js.map +1 -1
- package/dist/cli-entry.js +208 -12
- package/dist/cli-entry.js.map +1 -1
- package/package.json +5 -1
- package/templates/ceremonies.md +28 -0
- package/templates/issue-lifecycle.md +2 -1
- package/templates/loop.md +46 -0
- package/templates/ralph-triage.js +3 -1
- package/templates/scribe-charter.md +20 -1
- package/templates/squad.agent.md.template +9 -7
- package/templates/workflows/squad-triage.yml +4 -2
- package/templates/workflows/sync-squad-labels.yml +3 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lockfile utility — per-repo lock with PID, timestamp, and stale detection.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 lockfile logic.
|
|
5
|
+
* Written BEFORE a round (status=running) and AFTER (status=idle/error).
|
|
6
|
+
* External tools (e.g., squad-monitor) can read this file to know if
|
|
7
|
+
* a watch process is active.
|
|
8
|
+
*
|
|
9
|
+
* This is a utility module — not a WatchCapability.
|
|
10
|
+
*/
|
|
11
|
+
export interface LockfileData {
|
|
12
|
+
pid: number;
|
|
13
|
+
status: 'running' | 'idle' | 'error';
|
|
14
|
+
round: number;
|
|
15
|
+
lastRun: string;
|
|
16
|
+
exitCode: number;
|
|
17
|
+
consecutiveFailures: number;
|
|
18
|
+
started: string;
|
|
19
|
+
directory: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Acquire a lockfile for this watch process.
|
|
23
|
+
* Returns false if another non-stale process holds the lock.
|
|
24
|
+
*/
|
|
25
|
+
export declare function acquireLock(teamRoot: string): boolean;
|
|
26
|
+
/** Update the lockfile with current round state. */
|
|
27
|
+
export declare function updateLock(teamRoot: string, status: 'running' | 'idle' | 'error', round: number, exitCode?: number, consecutiveFailures?: number): void;
|
|
28
|
+
/** Release the lockfile on shutdown. */
|
|
29
|
+
export declare function releaseLock(teamRoot: string): void;
|
|
30
|
+
//# sourceMappingURL=lockfile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/lockfile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAiCrD;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,EACpC,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAU,EACpB,mBAAmB,GAAE,MAAU,GAC9B,IAAI,CAiBN;AAED,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAUlD"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lockfile utility — per-repo lock with PID, timestamp, and stale detection.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 lockfile logic.
|
|
5
|
+
* Written BEFORE a round (status=running) and AFTER (status=idle/error).
|
|
6
|
+
* External tools (e.g., squad-monitor) can read this file to know if
|
|
7
|
+
* a watch process is active.
|
|
8
|
+
*
|
|
9
|
+
* This is a utility module — not a WatchCapability.
|
|
10
|
+
*/
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
const STALE_THRESHOLD_MS = 30 * 60 * 1000; // 30 minutes
|
|
14
|
+
/**
|
|
15
|
+
* Acquire a lockfile for this watch process.
|
|
16
|
+
* Returns false if another non-stale process holds the lock.
|
|
17
|
+
*/
|
|
18
|
+
export function acquireLock(teamRoot) {
|
|
19
|
+
const lockPath = getLockPath(teamRoot);
|
|
20
|
+
if (fs.existsSync(lockPath)) {
|
|
21
|
+
try {
|
|
22
|
+
const existing = JSON.parse(fs.readFileSync(lockPath, 'utf-8'));
|
|
23
|
+
// Check if the PID is still alive
|
|
24
|
+
if (isProcessAlive(existing.pid)) {
|
|
25
|
+
// Check if it's stale
|
|
26
|
+
const age = Date.now() - new Date(existing.lastRun).getTime();
|
|
27
|
+
if (age < STALE_THRESHOLD_MS) {
|
|
28
|
+
return false; // Another active process holds the lock
|
|
29
|
+
}
|
|
30
|
+
// Stale — we can take over
|
|
31
|
+
}
|
|
32
|
+
// Dead or stale PID — safe to overwrite
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Corrupt lockfile — overwrite
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
writeLock(teamRoot, {
|
|
39
|
+
pid: process.pid,
|
|
40
|
+
status: 'running',
|
|
41
|
+
round: 0,
|
|
42
|
+
lastRun: new Date().toISOString(),
|
|
43
|
+
exitCode: 0,
|
|
44
|
+
consecutiveFailures: 0,
|
|
45
|
+
started: new Date().toISOString(),
|
|
46
|
+
directory: teamRoot,
|
|
47
|
+
});
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
/** Update the lockfile with current round state. */
|
|
51
|
+
export function updateLock(teamRoot, status, round, exitCode = 0, consecutiveFailures = 0) {
|
|
52
|
+
const lockPath = getLockPath(teamRoot);
|
|
53
|
+
let existing = {};
|
|
54
|
+
try {
|
|
55
|
+
existing = JSON.parse(fs.readFileSync(lockPath, 'utf-8'));
|
|
56
|
+
}
|
|
57
|
+
catch { /* use defaults */ }
|
|
58
|
+
writeLock(teamRoot, {
|
|
59
|
+
pid: process.pid,
|
|
60
|
+
status,
|
|
61
|
+
round,
|
|
62
|
+
lastRun: new Date().toISOString(),
|
|
63
|
+
exitCode,
|
|
64
|
+
consecutiveFailures,
|
|
65
|
+
started: existing.started ?? new Date().toISOString(),
|
|
66
|
+
directory: teamRoot,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Release the lockfile on shutdown. */
|
|
70
|
+
export function releaseLock(teamRoot) {
|
|
71
|
+
const lockPath = getLockPath(teamRoot);
|
|
72
|
+
try {
|
|
73
|
+
if (fs.existsSync(lockPath)) {
|
|
74
|
+
const data = JSON.parse(fs.readFileSync(lockPath, 'utf-8'));
|
|
75
|
+
if (data.pid === process.pid) {
|
|
76
|
+
fs.unlinkSync(lockPath);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch { /* best-effort */ }
|
|
81
|
+
}
|
|
82
|
+
function getLockPath(teamRoot) {
|
|
83
|
+
return path.join(teamRoot, '.ralph-watch.lock');
|
|
84
|
+
}
|
|
85
|
+
function writeLock(teamRoot, data) {
|
|
86
|
+
try {
|
|
87
|
+
fs.writeFileSync(getLockPath(teamRoot), JSON.stringify(data, null, 2), 'utf-8');
|
|
88
|
+
}
|
|
89
|
+
catch { /* best-effort */ }
|
|
90
|
+
}
|
|
91
|
+
function isProcessAlive(pid) {
|
|
92
|
+
try {
|
|
93
|
+
process.kill(pid, 0);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=lockfile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/lockfile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine capability checking — match issue needs:* labels to local machine.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 `Test-MachineCapability`.
|
|
5
|
+
* Reads `needs:*` labels from issues and compares against a local
|
|
6
|
+
* capabilities list provided via:
|
|
7
|
+
* 1. CLI flag: --capabilities gpu,browser,docker
|
|
8
|
+
* 2. Config: watch.capabilities["machine-capabilities"].list
|
|
9
|
+
* 3. Auto-detect: probe for common tools (nvidia-smi, playwright, docker)
|
|
10
|
+
*
|
|
11
|
+
* This is a utility module — not a WatchCapability.
|
|
12
|
+
*/
|
|
13
|
+
export interface MachineCapabilityResult {
|
|
14
|
+
canHandle: boolean;
|
|
15
|
+
reason: string;
|
|
16
|
+
missing?: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface MachineCapabilityConfig {
|
|
19
|
+
/** Explicit list of capabilities this machine has. */
|
|
20
|
+
list?: string[];
|
|
21
|
+
/** Whether to auto-detect capabilities (default: true). */
|
|
22
|
+
autoDetect?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Detect capabilities available on this machine. */
|
|
25
|
+
export declare function detectCapabilities(config?: MachineCapabilityConfig): Promise<string[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Check if this machine can handle an issue based on its needs:* labels.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkMachineCapability(issueLabels: string[], machineCaps: string[]): MachineCapabilityResult;
|
|
30
|
+
//# sourceMappingURL=machine-capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-capabilities.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/machine-capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAyCD,qDAAqD;AACrD,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAW5F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,uBAAuB,CAqBzB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine capability checking — match issue needs:* labels to local machine.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 `Test-MachineCapability`.
|
|
5
|
+
* Reads `needs:*` labels from issues and compares against a local
|
|
6
|
+
* capabilities list provided via:
|
|
7
|
+
* 1. CLI flag: --capabilities gpu,browser,docker
|
|
8
|
+
* 2. Config: watch.capabilities["machine-capabilities"].list
|
|
9
|
+
* 3. Auto-detect: probe for common tools (nvidia-smi, playwright, docker)
|
|
10
|
+
*
|
|
11
|
+
* This is a utility module — not a WatchCapability.
|
|
12
|
+
*/
|
|
13
|
+
import { execFile } from 'node:child_process';
|
|
14
|
+
import { promisify } from 'node:util';
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
16
|
+
/** Probes for common capabilities on the local machine. */
|
|
17
|
+
const CAPABILITY_PROBES = {
|
|
18
|
+
gpu: async () => {
|
|
19
|
+
try {
|
|
20
|
+
await execFileAsync('nvidia-smi', ['--query-gpu=name', '--format=csv,noheader'], { timeout: 5_000 });
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
browser: async () => {
|
|
28
|
+
try {
|
|
29
|
+
await execFileAsync('npx', ['playwright', '--version'], { timeout: 10_000 });
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
docker: async () => {
|
|
37
|
+
try {
|
|
38
|
+
await execFileAsync('docker', ['info'], { timeout: 5_000 });
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
node: async () => {
|
|
46
|
+
try {
|
|
47
|
+
await execFileAsync('node', ['--version'], { timeout: 5_000 });
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
python: async () => {
|
|
55
|
+
try {
|
|
56
|
+
await execFileAsync('python3', ['--version'], { timeout: 5_000 });
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
try {
|
|
61
|
+
await execFileAsync('python', ['--version'], { timeout: 5_000 });
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
/** Detect capabilities available on this machine. */
|
|
71
|
+
export async function detectCapabilities(config) {
|
|
72
|
+
const caps = new Set(config?.list ?? []);
|
|
73
|
+
if (config?.autoDetect !== false) {
|
|
74
|
+
const probes = Object.entries(CAPABILITY_PROBES).map(async ([name, probe]) => {
|
|
75
|
+
if (await probe())
|
|
76
|
+
caps.add(name);
|
|
77
|
+
});
|
|
78
|
+
await Promise.all(probes);
|
|
79
|
+
}
|
|
80
|
+
return [...caps];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if this machine can handle an issue based on its needs:* labels.
|
|
84
|
+
*/
|
|
85
|
+
export function checkMachineCapability(issueLabels, machineCaps) {
|
|
86
|
+
const needsLabels = issueLabels
|
|
87
|
+
.filter(l => l.startsWith('needs:'))
|
|
88
|
+
.map(l => l.replace(/^needs:/, ''));
|
|
89
|
+
if (needsLabels.length === 0) {
|
|
90
|
+
return { canHandle: true, reason: 'No needs:* labels on issue' };
|
|
91
|
+
}
|
|
92
|
+
const capSet = new Set(machineCaps.map(c => c.toLowerCase()));
|
|
93
|
+
const missing = needsLabels.filter(need => !capSet.has(need.toLowerCase()));
|
|
94
|
+
if (missing.length === 0) {
|
|
95
|
+
return { canHandle: true, reason: 'All required capabilities present' };
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
canHandle: false,
|
|
99
|
+
reason: `Missing capabilities: ${missing.join(', ')}`,
|
|
100
|
+
missing,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=machine-capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-capabilities.js","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/machine-capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-failure remediation — tiered self-healing response.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 `Invoke-PostFailureRemediation`.
|
|
5
|
+
* Tiered response based on consecutive failure count:
|
|
6
|
+
* Tier 1 (≥3): Reset circuit breaker state
|
|
7
|
+
* Tier 2 (≥6): Re-verify auth
|
|
8
|
+
* Tier 3 (≥9): Git pull to get latest fixes
|
|
9
|
+
* Tier 4 (≥15): Extended pause + webhook alert
|
|
10
|
+
*
|
|
11
|
+
* This is a utility module — called from the main watch loop on errors.
|
|
12
|
+
*/
|
|
13
|
+
import type { ModelCircuitBreaker } from './circuit-breaker.js';
|
|
14
|
+
export interface RemediationResult {
|
|
15
|
+
actions: string[];
|
|
16
|
+
pauseSeconds: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function runPostFailureRemediation(consecutiveFailures: number, round: number, teamRoot: string, circuitBreaker?: ModelCircuitBreaker): Promise<RemediationResult>;
|
|
19
|
+
//# sourceMappingURL=post-failure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-failure.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/post-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAIhE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,yBAAyB,CAC7C,mBAAmB,EAAE,MAAM,EAC3B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,mBAAmB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CA4C5B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-failure remediation — tiered self-healing response.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 `Invoke-PostFailureRemediation`.
|
|
5
|
+
* Tiered response based on consecutive failure count:
|
|
6
|
+
* Tier 1 (≥3): Reset circuit breaker state
|
|
7
|
+
* Tier 2 (≥6): Re-verify auth
|
|
8
|
+
* Tier 3 (≥9): Git pull to get latest fixes
|
|
9
|
+
* Tier 4 (≥15): Extended pause + webhook alert
|
|
10
|
+
*
|
|
11
|
+
* This is a utility module — called from the main watch loop on errors.
|
|
12
|
+
*/
|
|
13
|
+
import { execFile } from 'node:child_process';
|
|
14
|
+
import { promisify } from 'node:util';
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
16
|
+
export async function runPostFailureRemediation(consecutiveFailures, round, teamRoot, circuitBreaker) {
|
|
17
|
+
const actions = [];
|
|
18
|
+
let pauseSeconds = 0;
|
|
19
|
+
if (consecutiveFailures >= 3 && consecutiveFailures < 6) {
|
|
20
|
+
// Tier 1: Reset circuit breaker
|
|
21
|
+
if (circuitBreaker) {
|
|
22
|
+
circuitBreaker.reset();
|
|
23
|
+
actions.push('Tier1: Reset circuit breaker to defaults');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (consecutiveFailures >= 6 && consecutiveFailures < 9) {
|
|
27
|
+
// Tier 2: Re-verify gh auth
|
|
28
|
+
try {
|
|
29
|
+
const { stdout } = await execFileAsync('gh', ['api', 'user', '--jq', '.login'], {
|
|
30
|
+
timeout: 10_000,
|
|
31
|
+
});
|
|
32
|
+
actions.push(`Tier2: GH auth verified (${stdout.trim()})`);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
actions.push('Tier2: GH auth still failing');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (consecutiveFailures >= 9 && consecutiveFailures < 15) {
|
|
39
|
+
// Tier 3: Git pull latest
|
|
40
|
+
try {
|
|
41
|
+
await execFileAsync('git', ['pull', '--rebase', '--quiet'], {
|
|
42
|
+
cwd: teamRoot,
|
|
43
|
+
timeout: 30_000,
|
|
44
|
+
});
|
|
45
|
+
actions.push('Tier3: Git pull --rebase succeeded');
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
actions.push('Tier3: Git pull failed');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (consecutiveFailures >= 15) {
|
|
52
|
+
// Tier 4: Extended pause
|
|
53
|
+
pauseSeconds = 30 * 60; // 30 minutes
|
|
54
|
+
actions.push(`Tier4: ${consecutiveFailures} failures — pausing ${pauseSeconds / 60} minutes`);
|
|
55
|
+
}
|
|
56
|
+
return { actions, pauseSeconds };
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=post-failure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-failure.js","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/post-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAO1C,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,mBAA2B,EAC3B,KAAa,EACb,QAAgB,EAChB,cAAoC;IAEpC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,IAAI,mBAAmB,IAAI,CAAC,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;QACxD,gCAAgC;QAChC,IAAI,cAAc,EAAE,CAAC;YACnB,cAAc,CAAC,KAAK,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,IAAI,mBAAmB,IAAI,CAAC,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;QACxD,4BAA4B;QAC5B,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE;gBAC9E,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,IAAI,mBAAmB,IAAI,CAAC,IAAI,mBAAmB,GAAG,EAAE,EAAE,CAAC;QACzD,0BAA0B;QAC1B,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE;gBAC1D,GAAG,EAAE,QAAQ;gBACb,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,IAAI,mBAAmB,IAAI,EAAE,EAAE,CAAC;QAC9B,yBAAyB;QACzB,YAAY,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,aAAa;QACrC,OAAO,CAAC,IAAI,CAAC,UAAU,mBAAmB,uBAAuB,YAAY,GAAG,EAAE,UAAU,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue priority scoring — weigh issues for execution order.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 issue scoring logic.
|
|
5
|
+
* Factors:
|
|
6
|
+
* - Priority labels: P0 (100), P1 (60), P2 (30), P3 (10)
|
|
7
|
+
* - Age bonus: +1 per day open (max +30)
|
|
8
|
+
* - Staleness: +20 if no activity in 7+ days
|
|
9
|
+
* - Bug label: +15
|
|
10
|
+
* - Size labels: size:S +10, size:M 0, size:L -5
|
|
11
|
+
*
|
|
12
|
+
* This is a utility module — not a WatchCapability.
|
|
13
|
+
* Used by the execute capability to sort issues before picking work.
|
|
14
|
+
*/
|
|
15
|
+
export interface ScoredIssue {
|
|
16
|
+
number: number;
|
|
17
|
+
title: string;
|
|
18
|
+
labels: Array<{
|
|
19
|
+
name: string;
|
|
20
|
+
}>;
|
|
21
|
+
score: number;
|
|
22
|
+
breakdown: Record<string, number>;
|
|
23
|
+
}
|
|
24
|
+
export interface PriorityConfig {
|
|
25
|
+
/** Weight multipliers — override defaults. */
|
|
26
|
+
weights?: Partial<PriorityWeights>;
|
|
27
|
+
}
|
|
28
|
+
export interface PriorityWeights {
|
|
29
|
+
p0: number;
|
|
30
|
+
p1: number;
|
|
31
|
+
p2: number;
|
|
32
|
+
p3: number;
|
|
33
|
+
agePerDay: number;
|
|
34
|
+
ageMax: number;
|
|
35
|
+
staleThresholdDays: number;
|
|
36
|
+
staleBonus: number;
|
|
37
|
+
bugBonus: number;
|
|
38
|
+
sizeSBonus: number;
|
|
39
|
+
sizeLPenalty: number;
|
|
40
|
+
}
|
|
41
|
+
export interface IssueLike {
|
|
42
|
+
number: number;
|
|
43
|
+
title: string;
|
|
44
|
+
labels: Array<{
|
|
45
|
+
name: string;
|
|
46
|
+
}>;
|
|
47
|
+
createdAt?: string | Date;
|
|
48
|
+
updatedAt?: string | Date;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Score a single issue for execution priority.
|
|
52
|
+
* Higher score = should be picked first.
|
|
53
|
+
*/
|
|
54
|
+
export declare function scoreIssue(issue: IssueLike, config?: PriorityConfig): ScoredIssue;
|
|
55
|
+
/**
|
|
56
|
+
* Score and sort a batch of issues, highest score first.
|
|
57
|
+
*/
|
|
58
|
+
export declare function rankIssues(issues: IssueLike[], config?: PriorityConfig): ScoredIssue[];
|
|
59
|
+
//# sourceMappingURL=priority.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priority.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/priority.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAgBD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,WAAW,CA8DjF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,WAAW,EAAE,CAItF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue priority scoring — weigh issues for execution order.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 issue scoring logic.
|
|
5
|
+
* Factors:
|
|
6
|
+
* - Priority labels: P0 (100), P1 (60), P2 (30), P3 (10)
|
|
7
|
+
* - Age bonus: +1 per day open (max +30)
|
|
8
|
+
* - Staleness: +20 if no activity in 7+ days
|
|
9
|
+
* - Bug label: +15
|
|
10
|
+
* - Size labels: size:S +10, size:M 0, size:L -5
|
|
11
|
+
*
|
|
12
|
+
* This is a utility module — not a WatchCapability.
|
|
13
|
+
* Used by the execute capability to sort issues before picking work.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_WEIGHTS = {
|
|
16
|
+
p0: 100,
|
|
17
|
+
p1: 60,
|
|
18
|
+
p2: 30,
|
|
19
|
+
p3: 10,
|
|
20
|
+
agePerDay: 1,
|
|
21
|
+
ageMax: 30,
|
|
22
|
+
staleThresholdDays: 7,
|
|
23
|
+
staleBonus: 20,
|
|
24
|
+
bugBonus: 15,
|
|
25
|
+
sizeSBonus: 10,
|
|
26
|
+
sizeLPenalty: -5,
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Score a single issue for execution priority.
|
|
30
|
+
* Higher score = should be picked first.
|
|
31
|
+
*/
|
|
32
|
+
export function scoreIssue(issue, config) {
|
|
33
|
+
const w = { ...DEFAULT_WEIGHTS, ...(config?.weights ?? {}) };
|
|
34
|
+
const breakdown = {};
|
|
35
|
+
let score = 0;
|
|
36
|
+
const labels = new Set(issue.labels.map(l => l.name.toLowerCase()));
|
|
37
|
+
// Priority label scoring
|
|
38
|
+
if (labels.has('p0') || labels.has('priority:p0') || labels.has('priority:critical')) {
|
|
39
|
+
breakdown['priority'] = w.p0;
|
|
40
|
+
}
|
|
41
|
+
else if (labels.has('p1') || labels.has('priority:p1') || labels.has('priority:high')) {
|
|
42
|
+
breakdown['priority'] = w.p1;
|
|
43
|
+
}
|
|
44
|
+
else if (labels.has('p2') || labels.has('priority:p2') || labels.has('priority:medium')) {
|
|
45
|
+
breakdown['priority'] = w.p2;
|
|
46
|
+
}
|
|
47
|
+
else if (labels.has('p3') || labels.has('priority:p3') || labels.has('priority:low')) {
|
|
48
|
+
breakdown['priority'] = w.p3;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
breakdown['priority'] = w.p2; // Default to P2 if unlabeled
|
|
52
|
+
}
|
|
53
|
+
score += breakdown['priority'];
|
|
54
|
+
// Age bonus
|
|
55
|
+
if (issue.createdAt) {
|
|
56
|
+
const created = new Date(issue.createdAt);
|
|
57
|
+
const ageDays = Math.floor((Date.now() - created.getTime()) / (1000 * 60 * 60 * 24));
|
|
58
|
+
const ageScore = Math.min(ageDays * w.agePerDay, w.ageMax);
|
|
59
|
+
breakdown['age'] = ageScore;
|
|
60
|
+
score += ageScore;
|
|
61
|
+
}
|
|
62
|
+
// Staleness bonus
|
|
63
|
+
if (issue.updatedAt) {
|
|
64
|
+
const updated = new Date(issue.updatedAt);
|
|
65
|
+
const staleDays = Math.floor((Date.now() - updated.getTime()) / (1000 * 60 * 60 * 24));
|
|
66
|
+
if (staleDays >= w.staleThresholdDays) {
|
|
67
|
+
breakdown['stale'] = w.staleBonus;
|
|
68
|
+
score += w.staleBonus;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Bug label bonus
|
|
72
|
+
if (labels.has('bug') || labels.has('type:bug')) {
|
|
73
|
+
breakdown['bug'] = w.bugBonus;
|
|
74
|
+
score += w.bugBonus;
|
|
75
|
+
}
|
|
76
|
+
// Size label adjustment
|
|
77
|
+
if (labels.has('size:s') || labels.has('size:small')) {
|
|
78
|
+
breakdown['size'] = w.sizeSBonus;
|
|
79
|
+
score += w.sizeSBonus;
|
|
80
|
+
}
|
|
81
|
+
else if (labels.has('size:l') || labels.has('size:large') || labels.has('size:xl')) {
|
|
82
|
+
breakdown['size'] = w.sizeLPenalty;
|
|
83
|
+
score += w.sizeLPenalty;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
number: issue.number,
|
|
87
|
+
title: issue.title,
|
|
88
|
+
labels: issue.labels,
|
|
89
|
+
score,
|
|
90
|
+
breakdown,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Score and sort a batch of issues, highest score first.
|
|
95
|
+
*/
|
|
96
|
+
export function rankIssues(issues, config) {
|
|
97
|
+
return issues
|
|
98
|
+
.map(i => scoreIssue(i, config))
|
|
99
|
+
.sort((a, b) => b.score - a.score);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=priority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priority.js","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/priority.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA6BH,MAAM,eAAe,GAAoB;IACvC,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,EAAE;IACV,kBAAkB,EAAE,CAAC;IACrB,UAAU,EAAE,EAAE;IACd,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE,EAAE;IACd,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC;AAUF;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgB,EAAE,MAAuB;IAClE,MAAM,CAAC,GAAoB,EAAE,GAAG,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;IAC9E,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAEpE,yBAAyB;IACzB,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACrF,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC;SAAM,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QACxF,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC;SAAM,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC1F,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC;SAAM,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACvF,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,6BAA6B;IAC7D,CAAC;IACD,KAAK,IAAI,SAAS,CAAC,UAAU,CAAE,CAAC;IAEhC,YAAY;IACZ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACrF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAC3D,SAAS,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;QAC5B,KAAK,IAAI,QAAQ,CAAC;IACpB,CAAC;IAED,kBAAkB;IAClB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACvF,IAAI,SAAS,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;YACtC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;YAClC,KAAK,IAAI,CAAC,CAAC,UAAU,CAAC;QACxB,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QAChD,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC9B,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,wBAAwB;IACxB,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QACrD,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;QACjC,KAAK,IAAI,CAAC,CAAC,UAAU,CAAC;IACxB,CAAC;SAAM,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACrF,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC;QACnC,KAAK,IAAI,CAAC,CAAC,YAAY,CAAC;IAC1B,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK;QACL,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB,EAAE,MAAuB;IACrE,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;SAC/B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cooperative Rate Pool — shared API call budget across Ralph instances.
|
|
3
|
+
*
|
|
4
|
+
* Ported from ralph-watch.ps1 `New-RatePool` / `Read-RatePool` /
|
|
5
|
+
* `Write-RatePool` / `Update-RatePool` budget coordination logic.
|
|
6
|
+
*
|
|
7
|
+
* Multiple Ralph instances on different machines (or in different
|
|
8
|
+
* terminals) share a single `.squad/ralph-rate-pool.json` file.
|
|
9
|
+
* Advisory file-based locking (read-modify-write with PID stamps)
|
|
10
|
+
* keeps the pool consistent without an external lock manager.
|
|
11
|
+
*
|
|
12
|
+
* Config (via squad.config.ts → watch.ratePool):
|
|
13
|
+
* maxCallsPerInterval – max API calls in the window (default: 50)
|
|
14
|
+
* intervalSeconds – window length in seconds (default: 600)
|
|
15
|
+
* poolFile – override path (default: .squad/ralph-rate-pool.json)
|
|
16
|
+
*/
|
|
17
|
+
export interface RatePoolConfig {
|
|
18
|
+
maxCallsPerInterval?: number;
|
|
19
|
+
intervalSeconds?: number;
|
|
20
|
+
poolFile?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface RatePoolMachineEntry {
|
|
23
|
+
lastActive: string;
|
|
24
|
+
pid: number;
|
|
25
|
+
slotsHeld: number;
|
|
26
|
+
}
|
|
27
|
+
export interface RatePoolState {
|
|
28
|
+
windowStart: string;
|
|
29
|
+
slotsUsed: number;
|
|
30
|
+
maxSlots: number;
|
|
31
|
+
intervalSeconds: number;
|
|
32
|
+
machines: Record<string, RatePoolMachineEntry>;
|
|
33
|
+
}
|
|
34
|
+
export interface PoolStatus {
|
|
35
|
+
available: boolean;
|
|
36
|
+
slotsUsed: number;
|
|
37
|
+
maxSlots: number;
|
|
38
|
+
remaining: number;
|
|
39
|
+
windowSecondsLeft: number;
|
|
40
|
+
activeMachines: number;
|
|
41
|
+
}
|
|
42
|
+
export declare class RatePool {
|
|
43
|
+
private readonly poolPath;
|
|
44
|
+
private readonly maxSlots;
|
|
45
|
+
private readonly intervalSeconds;
|
|
46
|
+
constructor(squadDir: string, config?: RatePoolConfig);
|
|
47
|
+
/**
|
|
48
|
+
* Try to acquire a slot from the shared pool.
|
|
49
|
+
* Returns `true` if a slot was reserved, `false` if budget is exhausted.
|
|
50
|
+
*/
|
|
51
|
+
acquireSlot(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Release a slot back to the pool.
|
|
54
|
+
* Safe to call even if no slot is held (clamps to zero).
|
|
55
|
+
*/
|
|
56
|
+
releaseSlot(): void;
|
|
57
|
+
/** Return a snapshot of the current pool status. */
|
|
58
|
+
getPoolStatus(): PoolStatus;
|
|
59
|
+
private newPool;
|
|
60
|
+
/** Read with retry + window-expiry reset (mirrors Read-RatePool). */
|
|
61
|
+
private read;
|
|
62
|
+
/** Atomic write: temp file → rename (mirrors Write-RatePool). */
|
|
63
|
+
private write;
|
|
64
|
+
private touchMachine;
|
|
65
|
+
private pruneStale;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=rate-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-pool.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/watch/capabilities/rate-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,MAAM,WAAW,cAAc;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAsBD,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAE7B,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc;IASrD;;;OAGG;IACH,WAAW,IAAI,OAAO;IAatB;;;OAGG;IACH,WAAW,IAAI,IAAI;IAOnB,oDAAoD;IACpD,aAAa,IAAI,UAAU;IAoB3B,OAAO,CAAC,OAAO;IAUf,qEAAqE;IACrE,OAAO,CAAC,IAAI;IA8CZ,iEAAiE;IACjE,OAAO,CAAC,KAAK;IAgCb,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;CAQnB"}
|