@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.
Files changed (110) hide show
  1. package/dist/cli/commands/doctor.d.ts +2 -0
  2. package/dist/cli/commands/doctor.d.ts.map +1 -1
  3. package/dist/cli/commands/doctor.js +27 -5
  4. package/dist/cli/commands/doctor.js.map +1 -1
  5. package/dist/cli/commands/loop.d.ts +51 -0
  6. package/dist/cli/commands/loop.d.ts.map +1 -0
  7. package/dist/cli/commands/loop.js +352 -0
  8. package/dist/cli/commands/loop.js.map +1 -0
  9. package/dist/cli/commands/watch/capabilities/budget-check.d.ts +29 -0
  10. package/dist/cli/commands/watch/capabilities/budget-check.d.ts.map +1 -0
  11. package/dist/cli/commands/watch/capabilities/budget-check.js +38 -0
  12. package/dist/cli/commands/watch/capabilities/budget-check.js.map +1 -0
  13. package/dist/cli/commands/watch/capabilities/circuit-breaker.d.ts +52 -0
  14. package/dist/cli/commands/watch/capabilities/circuit-breaker.d.ts.map +1 -0
  15. package/dist/cli/commands/watch/capabilities/circuit-breaker.js +152 -0
  16. package/dist/cli/commands/watch/capabilities/circuit-breaker.js.map +1 -0
  17. package/dist/cli/commands/watch/capabilities/cleanup.d.ts +18 -0
  18. package/dist/cli/commands/watch/capabilities/cleanup.d.ts.map +1 -0
  19. package/dist/cli/commands/watch/capabilities/cleanup.js +135 -0
  20. package/dist/cli/commands/watch/capabilities/cleanup.js.map +1 -0
  21. package/dist/cli/commands/watch/capabilities/execute.d.ts +15 -3
  22. package/dist/cli/commands/watch/capabilities/execute.d.ts.map +1 -1
  23. package/dist/cli/commands/watch/capabilities/execute.js +108 -51
  24. package/dist/cli/commands/watch/capabilities/execute.js.map +1 -1
  25. package/dist/cli/commands/watch/capabilities/fleet-dispatch.d.ts +20 -0
  26. package/dist/cli/commands/watch/capabilities/fleet-dispatch.d.ts.map +1 -0
  27. package/dist/cli/commands/watch/capabilities/fleet-dispatch.js +144 -0
  28. package/dist/cli/commands/watch/capabilities/fleet-dispatch.js.map +1 -0
  29. package/dist/cli/commands/watch/capabilities/health-check.d.ts +29 -0
  30. package/dist/cli/commands/watch/capabilities/health-check.d.ts.map +1 -0
  31. package/dist/cli/commands/watch/capabilities/health-check.js +139 -0
  32. package/dist/cli/commands/watch/capabilities/health-check.js.map +1 -0
  33. package/dist/cli/commands/watch/capabilities/heartbeat.d.ts +48 -0
  34. package/dist/cli/commands/watch/capabilities/heartbeat.d.ts.map +1 -0
  35. package/dist/cli/commands/watch/capabilities/heartbeat.js +115 -0
  36. package/dist/cli/commands/watch/capabilities/heartbeat.js.map +1 -0
  37. package/dist/cli/commands/watch/capabilities/index.d.ts.map +1 -1
  38. package/dist/cli/commands/watch/capabilities/index.js +4 -0
  39. package/dist/cli/commands/watch/capabilities/index.js.map +1 -1
  40. package/dist/cli/commands/watch/capabilities/lockfile.d.ts +30 -0
  41. package/dist/cli/commands/watch/capabilities/lockfile.d.ts.map +1 -0
  42. package/dist/cli/commands/watch/capabilities/lockfile.js +100 -0
  43. package/dist/cli/commands/watch/capabilities/lockfile.js.map +1 -0
  44. package/dist/cli/commands/watch/capabilities/machine-capabilities.d.ts +30 -0
  45. package/dist/cli/commands/watch/capabilities/machine-capabilities.d.ts.map +1 -0
  46. package/dist/cli/commands/watch/capabilities/machine-capabilities.js +103 -0
  47. package/dist/cli/commands/watch/capabilities/machine-capabilities.js.map +1 -0
  48. package/dist/cli/commands/watch/capabilities/post-failure.d.ts +19 -0
  49. package/dist/cli/commands/watch/capabilities/post-failure.d.ts.map +1 -0
  50. package/dist/cli/commands/watch/capabilities/post-failure.js +58 -0
  51. package/dist/cli/commands/watch/capabilities/post-failure.js.map +1 -0
  52. package/dist/cli/commands/watch/capabilities/priority.d.ts +59 -0
  53. package/dist/cli/commands/watch/capabilities/priority.d.ts.map +1 -0
  54. package/dist/cli/commands/watch/capabilities/priority.js +101 -0
  55. package/dist/cli/commands/watch/capabilities/priority.js.map +1 -0
  56. package/dist/cli/commands/watch/capabilities/rate-pool.d.ts +67 -0
  57. package/dist/cli/commands/watch/capabilities/rate-pool.d.ts.map +1 -0
  58. package/dist/cli/commands/watch/capabilities/rate-pool.js +187 -0
  59. package/dist/cli/commands/watch/capabilities/rate-pool.js.map +1 -0
  60. package/dist/cli/commands/watch/capabilities/self-pull.d.ts +4 -1
  61. package/dist/cli/commands/watch/capabilities/self-pull.d.ts.map +1 -1
  62. package/dist/cli/commands/watch/capabilities/self-pull.js +53 -5
  63. package/dist/cli/commands/watch/capabilities/self-pull.js.map +1 -1
  64. package/dist/cli/commands/watch/capabilities/stale-reclaim.d.ts +23 -0
  65. package/dist/cli/commands/watch/capabilities/stale-reclaim.d.ts.map +1 -0
  66. package/dist/cli/commands/watch/capabilities/stale-reclaim.js +87 -0
  67. package/dist/cli/commands/watch/capabilities/stale-reclaim.js.map +1 -0
  68. package/dist/cli/commands/watch/capabilities/webhook-alerts.d.ts +29 -0
  69. package/dist/cli/commands/watch/capabilities/webhook-alerts.d.ts.map +1 -0
  70. package/dist/cli/commands/watch/capabilities/webhook-alerts.js +114 -0
  71. package/dist/cli/commands/watch/capabilities/webhook-alerts.js.map +1 -0
  72. package/dist/cli/commands/watch/config.d.ts +18 -0
  73. package/dist/cli/commands/watch/config.d.ts.map +1 -1
  74. package/dist/cli/commands/watch/config.js +20 -1
  75. package/dist/cli/commands/watch/config.js.map +1 -1
  76. package/dist/cli/commands/watch/health.d.ts +41 -0
  77. package/dist/cli/commands/watch/health.d.ts.map +1 -0
  78. package/dist/cli/commands/watch/health.js +141 -0
  79. package/dist/cli/commands/watch/health.js.map +1 -0
  80. package/dist/cli/commands/watch/index.d.ts +9 -2
  81. package/dist/cli/commands/watch/index.d.ts.map +1 -1
  82. package/dist/cli/commands/watch/index.js +115 -8
  83. package/dist/cli/commands/watch/index.js.map +1 -1
  84. package/dist/cli/commands/watch/types.d.ts +2 -0
  85. package/dist/cli/commands/watch/types.d.ts.map +1 -1
  86. package/dist/cli/commands/watch/verbose.d.ts +12 -0
  87. package/dist/cli/commands/watch/verbose.d.ts.map +1 -0
  88. package/dist/cli/commands/watch/verbose.js +28 -0
  89. package/dist/cli/commands/watch/verbose.js.map +1 -0
  90. package/dist/cli/core/detect-squad-dir.d.ts.map +1 -1
  91. package/dist/cli/core/detect-squad-dir.js +9 -12
  92. package/dist/cli/core/detect-squad-dir.js.map +1 -1
  93. package/dist/cli/core/nap.d.ts.map +1 -1
  94. package/dist/cli/core/nap.js +9 -4
  95. package/dist/cli/core/nap.js.map +1 -1
  96. package/dist/cli/core/upgrade.d.ts +18 -0
  97. package/dist/cli/core/upgrade.d.ts.map +1 -1
  98. package/dist/cli/core/upgrade.js +119 -0
  99. package/dist/cli/core/upgrade.js.map +1 -1
  100. package/dist/cli-entry.js +208 -12
  101. package/dist/cli-entry.js.map +1 -1
  102. package/package.json +5 -1
  103. package/templates/ceremonies.md +28 -0
  104. package/templates/issue-lifecycle.md +2 -1
  105. package/templates/loop.md +46 -0
  106. package/templates/ralph-triage.js +3 -1
  107. package/templates/scribe-charter.md +20 -1
  108. package/templates/squad.agent.md.template +9 -7
  109. package/templates/workflows/squad-triage.yml +4 -2
  110. package/templates/workflows/sync-squad-labels.yml +3 -1
@@ -11,6 +11,7 @@ const DEFAULTS = {
11
11
  execute: false,
12
12
  maxConcurrent: 1,
13
13
  timeout: 30,
14
+ dispatchMode: undefined,
14
15
  capabilities: {},
15
16
  };
16
17
  /**
@@ -42,11 +43,19 @@ export function loadWatchConfig(teamRoot, cliOverrides) {
42
43
  timeout: cliOverrides.timeout ?? fileConfig.timeout ?? DEFAULTS.timeout,
43
44
  copilotFlags: cliOverrides.copilotFlags ?? fileConfig.copilotFlags ?? DEFAULTS.copilotFlags,
44
45
  agentCmd: cliOverrides.agentCmd ?? fileConfig.agentCmd ?? DEFAULTS.agentCmd,
46
+ dispatchMode: cliOverrides.dispatchMode ?? fileConfig.dispatchMode ?? DEFAULTS.dispatchMode,
47
+ logFile: cliOverrides.logFile ?? fileConfig.logFile ?? DEFAULTS.logFile,
45
48
  capabilities: {
46
49
  ...DEFAULTS.capabilities,
47
50
  ...(fileConfig.capabilities ?? {}),
48
51
  ...(cliOverrides.capabilities ?? {}),
49
52
  },
53
+ verbose: cliOverrides.verbose ?? fileConfig.verbose ?? false,
54
+ authUser: cliOverrides.authUser ?? fileConfig.authUser,
55
+ webhookUrl: cliOverrides.webhookUrl ?? fileConfig.webhookUrl,
56
+ alertThreshold: cliOverrides.alertThreshold ?? fileConfig.alertThreshold,
57
+ maxBudget: cliOverrides.maxBudget ?? fileConfig.maxBudget,
58
+ machineCapabilities: cliOverrides.machineCapabilities ?? fileConfig.machineCapabilities,
50
59
  };
51
60
  return merged;
52
61
  }
@@ -65,9 +74,19 @@ function normalizeFileConfig(raw) {
65
74
  result.copilotFlags = raw['copilotFlags'];
66
75
  if (typeof raw['agentCmd'] === 'string')
67
76
  result.agentCmd = raw['agentCmd'];
77
+ if (typeof raw['verbose'] === 'boolean')
78
+ result.verbose = raw['verbose'];
79
+ if (typeof raw['dispatchMode'] === 'string') {
80
+ const mode = raw['dispatchMode'];
81
+ if (mode === 'fleet' || mode === 'task' || mode === 'hybrid') {
82
+ result.dispatchMode = mode;
83
+ }
84
+ }
85
+ if (typeof raw['logFile'] === 'string')
86
+ result.logFile = raw['logFile'];
68
87
  // Everything else is a capability key
69
88
  const caps = {};
70
- const reserved = new Set(['interval', 'execute', 'maxConcurrent', 'timeout', 'copilotFlags', 'agentCmd']);
89
+ const reserved = new Set(['interval', 'execute', 'maxConcurrent', 'timeout', 'copilotFlags', 'agentCmd', 'verbose', 'dispatchMode', 'logFile']);
71
90
  for (const [key, value] of Object.entries(raw)) {
72
91
  if (reserved.has(key))
73
92
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/cli/commands/watch/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/cli/commands/watch/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Watch health check — reports status of a running watch instance.
3
+ *
4
+ * Reads the PID file (stored in OS temp dir) written at watch startup to
5
+ * determine whether a watch process is alive, its uptime, auth account, and
6
+ * whether auth has drifted since launch.
7
+ */
8
+ /** Shape of the PID file written by runWatch at startup. */
9
+ export interface WatchPidInfo {
10
+ pid: number;
11
+ startedAt: string;
12
+ user: string;
13
+ interval: number;
14
+ capabilities: string[];
15
+ repo: string;
16
+ }
17
+ /**
18
+ * Path to the PID file in the OS temp directory.
19
+ * Uses an MD5 hash of the repo path so different clones/worktrees get
20
+ * unique PID files without polluting the repo (avoids accidental commits).
21
+ */
22
+ export declare function getPidPath(teamRoot: string): string;
23
+ /**
24
+ * Write the PID file at watch startup.
25
+ * The caller is responsible for registering exit handlers to clean up.
26
+ */
27
+ export declare function writePidFile(teamRoot: string, info: WatchPidInfo): void;
28
+ /** Remove the PID file (best-effort, swallows errors). */
29
+ export declare function removePidFile(teamRoot: string): void;
30
+ /**
31
+ * Check if a process with the given PID is still alive.
32
+ * Uses `process.kill(pid, 0)` — signal 0 tests existence without killing.
33
+ */
34
+ export declare function isProcessAlive(pid: number): boolean;
35
+ /**
36
+ * Run the watch health check and return a formatted status string.
37
+ *
38
+ * @param teamRoot - The repository root (directory containing `.squad/`).
39
+ */
40
+ export declare function getWatchHealth(teamRoot: string): string;
41
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/watch/health.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAGvE;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWnD;AAgCD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAwDvD"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Watch health check — reports status of a running watch instance.
3
+ *
4
+ * Reads the PID file (stored in OS temp dir) written at watch startup to
5
+ * determine whether a watch process is alive, its uptime, auth account, and
6
+ * whether auth has drifted since launch.
7
+ */
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import os from 'node:os';
11
+ import crypto from 'node:crypto';
12
+ import { execFileSync } from 'node:child_process';
13
+ /**
14
+ * Path to the PID file in the OS temp directory.
15
+ * Uses an MD5 hash of the repo path so different clones/worktrees get
16
+ * unique PID files without polluting the repo (avoids accidental commits).
17
+ */
18
+ export function getPidPath(teamRoot) {
19
+ const hash = crypto.createHash('md5').update(teamRoot).digest('hex').slice(0, 12);
20
+ return path.join(os.tmpdir(), `squad-watch-${hash}.json`);
21
+ }
22
+ /**
23
+ * Write the PID file at watch startup.
24
+ * The caller is responsible for registering exit handlers to clean up.
25
+ */
26
+ export function writePidFile(teamRoot, info) {
27
+ const pidPath = getPidPath(teamRoot);
28
+ fs.writeFileSync(pidPath, JSON.stringify(info, null, 2));
29
+ }
30
+ /** Remove the PID file (best-effort, swallows errors). */
31
+ export function removePidFile(teamRoot) {
32
+ try {
33
+ fs.unlinkSync(getPidPath(teamRoot));
34
+ }
35
+ catch { /* already gone */ }
36
+ }
37
+ /**
38
+ * Check if a process with the given PID is still alive.
39
+ * Uses `process.kill(pid, 0)` — signal 0 tests existence without killing.
40
+ */
41
+ export function isProcessAlive(pid) {
42
+ try {
43
+ process.kill(pid, 0);
44
+ return true;
45
+ }
46
+ catch (e) {
47
+ // EPERM means the process exists but we lack permission to signal it
48
+ if (e && typeof e === 'object' && 'code' in e && e.code === 'EPERM') {
49
+ return true;
50
+ }
51
+ return false;
52
+ }
53
+ }
54
+ /** Format a duration in milliseconds to a human-readable string. */
55
+ function formatUptime(ms) {
56
+ const totalMinutes = Math.floor(ms / 60_000);
57
+ const hours = Math.floor(totalMinutes / 60);
58
+ const minutes = totalMinutes % 60;
59
+ if (hours > 0)
60
+ return `${hours}h ${minutes}m`;
61
+ return `${minutes}m`;
62
+ }
63
+ /**
64
+ * Returns the currently active `gh` account, or undefined.
65
+ * Duplicated from index.ts to avoid circular imports — the canonical
66
+ * version lives in `getActiveGhUser()` in the watch index.
67
+ */
68
+ /** Probes gh auth status — captures both stdout and stderr since gh may write to either. */
69
+ function probeCurrentGhUser() {
70
+ try {
71
+ const result = execFileSync('gh', ['auth', 'status', '--active'], {
72
+ encoding: 'utf-8',
73
+ stdio: ['pipe', 'pipe', 'pipe'],
74
+ });
75
+ const match = result.match(/account\s+(\S+)/);
76
+ return match?.[1];
77
+ }
78
+ catch (e) {
79
+ const stderr = e.stderr ?? '';
80
+ const match = stderr.match(/account\s+(\S+)/);
81
+ return match?.[1];
82
+ }
83
+ }
84
+ /**
85
+ * Run the watch health check and return a formatted status string.
86
+ *
87
+ * @param teamRoot - The repository root (directory containing `.squad/`).
88
+ */
89
+ export function getWatchHealth(teamRoot) {
90
+ const pidPath = getPidPath(teamRoot);
91
+ if (!fs.existsSync(pidPath)) {
92
+ return '📋 No watch instance detected.\n Start one with: squad watch --execute --interval 5';
93
+ }
94
+ let info;
95
+ try {
96
+ info = JSON.parse(fs.readFileSync(pidPath, 'utf-8'));
97
+ }
98
+ catch {
99
+ return `⚠ Corrupt PID file — cannot read watch status.\n Delete ${pidPath} and restart.`;
100
+ }
101
+ // Validate minimal fields
102
+ if (typeof info.pid !== 'number') {
103
+ return `⚠ Invalid PID file (missing pid).\n Delete ${pidPath} and restart.`;
104
+ }
105
+ // Check if the process is actually running
106
+ if (!isProcessAlive(info.pid)) {
107
+ // Stale PID file — process died without cleanup
108
+ removePidFile(teamRoot);
109
+ return `⚠ Stale watch detected (PID ${info.pid} is dead). Cleaned up.\n Restart with: squad watch --execute --interval 5`;
110
+ }
111
+ // Process is alive — build status report
112
+ // Validate startedAt before computing uptime
113
+ if (!info.startedAt || isNaN(new Date(info.startedAt).getTime())) {
114
+ return `⚠ Invalid PID file (bad startedAt).
115
+ Delete ${pidPath} and restart.`;
116
+ }
117
+ const uptime = formatUptime(Date.now() - new Date(info.startedAt).getTime());
118
+ const lines = [
119
+ '🔄 Watch Instance — RUNNING',
120
+ '━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
121
+ ` PID: ${info.pid}`,
122
+ ` Uptime: ${uptime}`,
123
+ ` Auth: ${info.user}`,
124
+ ` Interval: ${info.interval}m`,
125
+ ` Repo: ${info.repo}`,
126
+ ` Capabilities: ${(info.capabilities ?? []).join(', ') || '(none)'}`,
127
+ ];
128
+ // Auth drift detection — compare current gh user vs recorded
129
+ const currentUser = probeCurrentGhUser();
130
+ if (currentUser && currentUser !== info.user) {
131
+ lines.push(` ⚠ AUTH DRIFT: Expected ${info.user}, current is ${currentUser}`);
132
+ }
133
+ else if (currentUser) {
134
+ lines.push(' Auth status: ✓ matches expected');
135
+ }
136
+ else {
137
+ lines.push(' Auth status: ? could not verify');
138
+ }
139
+ return lines.join('\n');
140
+ }
141
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../../src/cli/commands/watch/health.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,8 @@ export { loadWatchConfig } from './config.js';
12
12
  export type { WatchCapability, WatchContext, WatchPhase, PreflightResult, CapabilityResult } from './types.js';
13
13
  export { CapabilityRegistry } from './registry.js';
14
14
  export { createDefaultRegistry } from './capabilities/index.js';
15
+ export { createVerboseLogger, type VerboseLogger } from './verbose.js';
16
+ export { getWatchHealth, writePidFile, removePidFile, getPidPath, isProcessAlive, type WatchPidInfo } from './health.js';
15
17
  /** Normalized work item for watch operations. */
16
18
  export interface WatchWorkItem {
17
19
  number: number;
@@ -53,7 +55,12 @@ export interface BoardState {
53
55
  readyToMerge: number;
54
56
  executed: number;
55
57
  }
56
- export declare function reportBoard(state: BoardState, round: number): void;
58
+ export interface ReportBoardOptions {
59
+ notifyLevel?: 'all' | 'important' | 'none';
60
+ machineName?: string;
61
+ repoName?: string;
62
+ }
63
+ export declare function reportBoard(state: BoardState, round: number, options?: ReportBoardOptions): void;
57
64
  /**
58
65
  * Legacy WatchOptions type — still accepted by runWatch for backward
59
66
  * compatibility. New code should use {@link WatchConfig} instead.
@@ -75,7 +82,7 @@ export interface WatchOptions {
75
82
  decisionHygiene?: boolean;
76
83
  channelRouting?: boolean;
77
84
  }
78
- export { findExecutableIssues } from './capabilities/execute.js';
85
+ export { findExecutableIssues, classifyIssue } from './capabilities/execute.js';
79
86
  export declare function buildAgentCommand(issue: WatchWorkItem, teamRoot: string, options: WatchOptions): {
80
87
  cmd: string;
81
88
  args: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/watch/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/watch/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8BH,OAAO,KAAK,EAAE,eAAe,EAA2C,MAAM,iCAAiC,CAAC;AAEhH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/G,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAIzH,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,SAAS,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrC;AAED,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAmFD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAyBhG;AAoUD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA2BD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEhF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,GACpB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CASjC;AAED,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9D;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB/C;AAID;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA4V/F"}
@@ -6,6 +6,7 @@
6
6
  * always runs — it is not an opt-in capability.
7
7
  */
8
8
  import path from 'node:path';
9
+ import fs from 'node:fs';
9
10
  import { execFile, execFileSync } from 'node:child_process';
10
11
  import { promisify } from 'node:util';
11
12
  import { FSStorageProvider } from '@bradygaster/squad-sdk';
@@ -21,9 +22,12 @@ import { ghAvailable, ghAuthenticated, ghRateLimitCheck, isRateLimitError } from
21
22
  import { PredictiveCircuitBreaker, getTrafficLight, } from '@bradygaster/squad-sdk/ralph/rate-limiting';
22
23
  import { createPlatformAdapter } from '@bradygaster/squad-sdk/platform';
23
24
  import { createDefaultRegistry } from './capabilities/index.js';
25
+ import { createVerboseLogger } from './verbose.js';
24
26
  export { loadWatchConfig } from './config.js';
25
27
  export { CapabilityRegistry } from './registry.js';
26
28
  export { createDefaultRegistry } from './capabilities/index.js';
29
+ export { createVerboseLogger } from './verbose.js';
30
+ export { getWatchHealth, writePidFile, removePidFile, getPidPath, isProcessAlive } from './health.js';
27
31
  // ── SDK Mapping Helpers ──────────────────────────────────────────
28
32
  function toWatchWorkItem(wi) {
29
33
  return {
@@ -96,13 +100,21 @@ async function editWorkItem(adapter, id, options) {
96
100
  }
97
101
  }
98
102
  }
99
- export function reportBoard(state, round) {
103
+ export function reportBoard(state, round, options) {
104
+ const level = options?.notifyLevel ?? 'all';
100
105
  const total = Object.values(state).reduce((a, b) => a + b, 0);
106
+ if (level === 'none')
107
+ return;
108
+ if (level === 'important' && total === 0)
109
+ return;
101
110
  if (total === 0) {
102
111
  console.log(`${DIM}📋 Board is clear — Ralph is idling${RESET}`);
103
112
  return;
104
113
  }
105
- console.log(`\n${BOLD}🔄 Ralph Round ${round}${RESET}`);
114
+ const suffix = options?.machineName || options?.repoName
115
+ ? ` (${[options.machineName, options.repoName].filter(Boolean).join(' · ')})`
116
+ : '';
117
+ console.log(`\n${BOLD}🔄 Ralph — Round ${round}${suffix}${RESET}`);
106
118
  console.log('━'.repeat(30));
107
119
  if (state.untriaged > 0)
108
120
  console.log(` 🔴 Untriaged: ${state.untriaged}`);
@@ -125,10 +137,14 @@ export function reportBoard(state, round) {
125
137
  function emptyBoardState() {
126
138
  return { untriaged: 0, assigned: 0, drafts: 0, needsReview: 0, changesRequested: 0, ciFailures: 0, readyToMerge: 0, executed: 0 };
127
139
  }
128
- async function checkPRs(roster, adapter) {
140
+ async function checkPRs(roster, adapter, vlog) {
129
141
  const timestamp = new Date().toLocaleTimeString();
130
142
  const prs = await listWatchPullRequests(adapter, { state: 'open', limit: 20 });
131
143
  const squadPRs = prs.filter(pr => pr.labels.some(l => l.name.startsWith('squad')) || pr.headRefName.startsWith('squad/'));
144
+ vlog?.log(`PRs found: ${prs.length} total`);
145
+ for (const pr of squadPRs) {
146
+ vlog?.log(` PR #${pr.number}: "${pr.title}" draft=${pr.isDraft} review=${pr.reviewDecision ?? 'none'}`);
147
+ }
132
148
  if (squadPRs.length === 0) {
133
149
  return { drafts: 0, needsReview: 0, changesRequested: 0, ciFailures: 0, readyToMerge: 0, totalOpen: 0 };
134
150
  }
@@ -182,10 +198,16 @@ const BLOCKED_LABELS = new Set([
182
198
  'status:scheduled', 'status:needs-action', 'status:needs-decision',
183
199
  'status:needs-review', 'pending-user', 'do-not-merge',
184
200
  ]);
185
- async function runCheck(rules, modules, roster, hasCopilot, autoAssign, capabilities, adapter) {
201
+ async function runCheck(rules, modules, roster, hasCopilot, autoAssign, capabilities, adapter, vlog) {
186
202
  const timestamp = new Date().toLocaleTimeString();
187
203
  try {
188
204
  const issues = await listWatchWorkItems(adapter, { label: 'squad', state: 'open', limit: 20 });
205
+ vlog?.log(`Issues found: ${issues.length} total`);
206
+ for (const issue of issues) {
207
+ const labels = issue.labels?.map((l) => l.name).join(', ') ?? 'none';
208
+ const assignees = issue.assignees?.map((a) => a.login).join(', ') ?? 'none';
209
+ vlog?.log(` #${issue.number}: "${issue.title}" [${labels}] assignees=[${assignees}]`);
210
+ }
189
211
  const { filterByCapabilities } = await import('@bradygaster/squad-sdk/ralph/capabilities');
190
212
  const { handled: capableIssues, skipped: incapableIssues } = filterByCapabilities(issues, capabilities);
191
213
  for (const { issue, missing } of incapableIssues) {
@@ -235,7 +257,7 @@ async function runCheck(rules, modules, roster, hasCopilot, autoAssign, capabili
235
257
  console.error(`${RED}✗${RESET} [${timestamp}] Failed to assign @copilot to #${issue.number}: ${e.message}`);
236
258
  }
237
259
  }
238
- const prState = await checkPRs(roster, adapter);
260
+ const prState = await checkPRs(roster, adapter, vlog);
239
261
  return { untriaged: untriaged.length, assigned: assignedIssues.length, executed: 0, ...prState };
240
262
  }
241
263
  catch (e) {
@@ -313,7 +335,7 @@ async function runPhase(phase, enabled, context, config) {
313
335
  ...context,
314
336
  config: typeof capConfig === 'object' && capConfig !== null
315
337
  ? capConfig
316
- : { enabled: !!capConfig, maxConcurrent: config.maxConcurrent, timeout: config.timeout },
338
+ : { enabled: !!capConfig, maxConcurrent: config.maxConcurrent, timeout: config.timeout, dispatchMode: config.dispatchMode },
317
339
  };
318
340
  const result = await cap.execute(capContext);
319
341
  results.set(cap.name, result);
@@ -398,7 +420,7 @@ function legacyToConfig(options) {
398
420
  };
399
421
  }
400
422
  // ── Exported helpers (backward compat) ───────────────────────────
401
- export { findExecutableIssues } from './capabilities/execute.js';
423
+ export { findExecutableIssues, classifyIssue } from './capabilities/execute.js';
402
424
  export function buildAgentCommand(issue, teamRoot, options) {
403
425
  const prompt = `Work on issue #${issue.number}: ${issue.title}. Read the issue body for full details.`;
404
426
  if (options.agentCmd) {
@@ -484,6 +506,31 @@ export async function runWatch(dest, options) {
484
506
  catch (err) {
485
507
  return fatal(`Could not detect platform: ${err.message}`);
486
508
  }
509
+ // Verbose logger
510
+ const vlog = createVerboseLogger(config.verbose ?? false);
511
+ vlog.section('Startup');
512
+ vlog.table({
513
+ repo: teamRoot,
514
+ platform: adapter.type,
515
+ // This table only prints when verbose mode is active, so verbose is always true here.
516
+ verbose: config.verbose ?? false,
517
+ interval: `${config.interval}m`,
518
+ execute: config.execute ?? false,
519
+ agentCmd: config.agentCmd ?? '(default: gh copilot)',
520
+ dispatchMode: config.capabilities['wave-dispatch'] ? 'wave' : 'task',
521
+ maxConcurrent: config.maxConcurrent ?? 1,
522
+ });
523
+ // Auth check (verbose only — avoid unnecessary process spawn on every startup)
524
+ if (config.verbose && adapter.type === 'github') {
525
+ try {
526
+ const authOut = execFileSync('gh', ['auth', 'status'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
527
+ const activeAccount = authOut.match(/Logged in to .* account (\S+)/)?.[1];
528
+ vlog.log(`Auth: ${activeAccount ?? 'unknown'}`);
529
+ }
530
+ catch {
531
+ vlog.warn('gh auth status failed — API calls may fail silently');
532
+ }
533
+ }
487
534
  // Verify platform CLI availability
488
535
  if (adapter.type === 'github') {
489
536
  if (!(await ghAvailable()))
@@ -520,6 +567,20 @@ export async function runWatch(dest, options) {
520
567
  if (roster.length === 0) {
521
568
  fatal('No squad members found in team.md');
522
569
  }
570
+ // Pre-create squad member labels so addTag never fails on missing labels
571
+ if (adapter.ensureTag) {
572
+ for (const member of roster) {
573
+ try {
574
+ await adapter.ensureTag(member.label, { color: 'd4c5f9', description: `Squad triage: ${member.name}` });
575
+ }
576
+ catch { /* best-effort — continue if label creation fails */ }
577
+ }
578
+ try {
579
+ await adapter.ensureTag('squad:copilot', { color: 'd4c5f9', description: 'Squad triage: Copilot coding agent' });
580
+ }
581
+ catch { /* best-effort */ }
582
+ console.log(`${DIM}Labels: ensured ${roster.length + 1} squad labels exist${RESET}`);
583
+ }
523
584
  const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot');
524
585
  const autoAssign = content.includes('<!-- copilot-auto-assign: true -->');
525
586
  const monitorSessionId = 'ralph-watch';
@@ -545,6 +606,7 @@ export async function runWatch(dest, options) {
545
606
  config: {},
546
607
  agentCmd: config.agentCmd,
547
608
  copilotFlags: config.copilotFlags,
609
+ verbose: config.verbose,
548
610
  };
549
611
  const enabledCapabilities = await preflightCapabilities(registry, config, baseContext);
550
612
  // Print startup banner
@@ -558,7 +620,30 @@ export async function runWatch(dest, options) {
558
620
  if (config.execute) {
559
621
  console.log(`${DIM}Max concurrent: ${config.maxConcurrent} | Timeout: ${config.timeout}m${RESET}`);
560
622
  }
623
+ // Warn when fleet dispatch mode is set but the fleet-dispatch capability is not enabled
624
+ if ((config.dispatchMode === 'fleet' || config.dispatchMode === 'hybrid') &&
625
+ !enabledCapabilities.some(c => c.name === 'fleet-dispatch')) {
626
+ console.warn(`${YELLOW}⚠${RESET} dispatchMode="${config.dispatchMode}" but fleet-dispatch capability is not enabled. Read-heavy issues will not be batched.`);
627
+ }
561
628
  console.log();
629
+ // Fix 2: Set up log-file tee (after banner so the banner itself is captured too)
630
+ let logStream;
631
+ if (config.logFile) {
632
+ const resolvedLogFile = path.resolve(config.logFile);
633
+ logStream = fs.createWriteStream(resolvedLogFile, { flags: 'a' });
634
+ const origLog = console.log.bind(console);
635
+ console.log = (...args) => {
636
+ origLog(...args);
637
+ const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);
638
+ const line = args.map(a => (typeof a === 'string' ? a : String(a))).join(' ');
639
+ // Strip ANSI escape codes for the file
640
+ const plain = line.replace(/\x1b\[[0-9;]*m/g, '');
641
+ logStream.write(`[${timestamp}] ${plain}\n`);
642
+ };
643
+ console.log(`${DIM}Log file: ${resolvedLogFile}${RESET}`);
644
+ }
645
+ // Fix 3: Immediate visual feedback after banner
646
+ console.log(`Running first check now...`);
562
647
  // Initialize circuit breaker (#515)
563
648
  const circuitBreaker = new PredictiveCircuitBreaker();
564
649
  let cbState = loadCBState(squadDirInfo.path);
@@ -566,6 +651,7 @@ export async function runWatch(dest, options) {
566
651
  let roundInProgress = false;
567
652
  async function executeRound() {
568
653
  const ts = new Date().toLocaleTimeString();
654
+ const roundStart = Date.now();
569
655
  // Circuit breaker gate
570
656
  if (cbState.status === 'open') {
571
657
  const elapsed = Date.now() - new Date(cbState.openedAt).getTime();
@@ -606,6 +692,9 @@ export async function runWatch(dest, options) {
606
692
  }
607
693
  round++;
608
694
  const roundContext = { ...baseContext, round };
695
+ // Fix 1: Print round start marker
696
+ console.log(`\n${DIM}Starting round ${round}...${RESET}`);
697
+ vlog.section(`Round ${round}`);
609
698
  // Phase 1: pre-scan (self-pull, subsquad discovery)
610
699
  await runPhase('pre-scan', enabledCapabilities, roundContext, config);
611
700
  // SubSquad discovery (informational, not a capability)
@@ -614,7 +703,7 @@ export async function runWatch(dest, options) {
614
703
  console.log(`${DIM}📂 Discovered ${subSquads.length} subsquad(s): ${subSquads.map(s => s.name).join(', ')}${RESET}`);
615
704
  }
616
705
  // Core: triage (always runs — not a capability)
617
- const roundState = await runCheck(rules, modules, roster, hasCopilot, autoAssign, capabilities, adapter);
706
+ const roundState = await runCheck(rules, modules, roster, hasCopilot, autoAssign, capabilities, adapter, vlog);
618
707
  // Phase 2: post-triage (two-pass hydration)
619
708
  await runPhase('post-triage', enabledCapabilities, roundContext, config);
620
709
  // Phase 3: post-execute (execute issues, wave dispatch, board updates)
@@ -633,7 +722,21 @@ export async function runWatch(dest, options) {
633
722
  timestamp: new Date(),
634
723
  });
635
724
  await monitor.healthCheck();
725
+ // Verbose board counters
726
+ vlog.table({
727
+ untriaged: roundState.untriaged,
728
+ assigned: roundState.assigned,
729
+ drafts: roundState.drafts,
730
+ needsReview: roundState.needsReview,
731
+ changesRequested: roundState.changesRequested,
732
+ ciFailures: roundState.ciFailures,
733
+ readyToMerge: roundState.readyToMerge,
734
+ executed: roundState.executed,
735
+ });
636
736
  reportBoard(roundState, round);
737
+ // Fix 1: Print next poll time
738
+ const nextPollTime = new Date(Date.now() + interval * 60 * 1000);
739
+ console.log(`${DIM}Next poll at ${nextPollTime.toLocaleTimeString()}${RESET}`);
637
740
  // Post-round: update circuit breaker on success
638
741
  if (cbState.status === 'half-open') {
639
742
  cbState.consecutiveSuccesses++;
@@ -649,6 +752,9 @@ export async function runWatch(dest, options) {
649
752
  cbState.consecutiveFailures = 0;
650
753
  }
651
754
  saveCBState(squadDirInfo.path, cbState);
755
+ const roundEnd = Date.now();
756
+ const elapsed = ((roundEnd - roundStart) / 1000).toFixed(1);
757
+ vlog.log(`Round ${round} complete (${elapsed}s)`);
652
758
  }
653
759
  // Run immediately, then on interval
654
760
  await executeRound();
@@ -695,6 +801,7 @@ export async function runWatch(dest, options) {
695
801
  await monitor.stop();
696
802
  saveCBState(squadDirInfo.path, cbState);
697
803
  console.log(`\n${DIM}🔄 Ralph — Watch stopped${RESET}`);
804
+ logStream?.end();
698
805
  resolve();
699
806
  };
700
807
  process.on('SIGINT', shutdown);