@proletariat/cli 0.3.95 → 0.3.97
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/commands/config/index.js +1 -1
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/db/repair.js +160 -35
- package/dist/commands/db/repair.js.map +1 -1
- package/dist/commands/gc.d.ts +14 -0
- package/dist/commands/gc.js +208 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/linear/connect.d.ts +5 -0
- package/dist/commands/linear/connect.js +84 -0
- package/dist/commands/linear/connect.js.map +1 -1
- package/dist/commands/pr/merge.js +1 -1
- package/dist/commands/pr/merge.js.map +1 -1
- package/dist/commands/session/attach.d.ts +3 -3
- package/dist/commands/session/attach.js +37 -79
- package/dist/commands/session/attach.js.map +1 -1
- package/dist/commands/session/exec.js +1 -1
- package/dist/commands/session/exec.js.map +1 -1
- package/dist/commands/session/health.js +1 -1
- package/dist/commands/session/health.js.map +1 -1
- package/dist/commands/session/inspect.js +1 -1
- package/dist/commands/session/inspect.js.map +1 -1
- package/dist/commands/session/list.d.ts +1 -0
- package/dist/commands/session/list.js +111 -78
- package/dist/commands/session/list.js.map +1 -1
- package/dist/commands/session/peek.js +1 -1
- package/dist/commands/session/peek.js.map +1 -1
- package/dist/commands/session/poke.js +1 -1
- package/dist/commands/session/poke.js.map +1 -1
- package/dist/commands/session/prune.js +50 -11
- package/dist/commands/session/prune.js.map +1 -1
- package/dist/commands/session/restart.js +1 -1
- package/dist/commands/session/restart.js.map +1 -1
- package/dist/commands/session/watch.d.ts +1 -0
- package/dist/commands/session/watch.js +46 -2
- package/dist/commands/session/watch.js.map +1 -1
- package/dist/commands/{action → sync}/index.d.ts +2 -6
- package/dist/commands/sync/index.js +68 -0
- package/dist/commands/sync/index.js.map +1 -0
- package/dist/commands/sync/pause.d.ts +10 -0
- package/dist/commands/sync/pause.js +35 -0
- package/dist/commands/sync/pause.js.map +1 -0
- package/dist/commands/sync/queue.d.ts +10 -0
- package/dist/commands/sync/queue.js +106 -0
- package/dist/commands/sync/queue.js.map +1 -0
- package/dist/commands/sync/resume.d.ts +10 -0
- package/dist/commands/sync/resume.js +34 -0
- package/dist/commands/sync/resume.js.map +1 -0
- package/dist/commands/sync/start.d.ts +11 -0
- package/dist/commands/sync/start.js +73 -0
- package/dist/commands/sync/start.js.map +1 -0
- package/dist/commands/sync/status.d.ts +10 -0
- package/dist/commands/sync/status.js +40 -0
- package/dist/commands/sync/status.js.map +1 -0
- package/dist/commands/sync/stop.d.ts +10 -0
- package/dist/commands/sync/stop.js +39 -0
- package/dist/commands/sync/stop.js.map +1 -0
- package/dist/commands/ticket/create.js +1 -1
- package/dist/commands/ticket/create.js.map +1 -1
- package/dist/commands/ticket/edit.js +1 -1
- package/dist/commands/ticket/edit.js.map +1 -1
- package/dist/commands/ticket/list.js +1 -1
- package/dist/commands/ticket/list.js.map +1 -1
- package/dist/commands/ticket/update.js +1 -1
- package/dist/commands/ticket/update.js.map +1 -1
- package/dist/commands/work/complete.d.ts +1 -0
- package/dist/commands/work/complete.js +27 -25
- package/dist/commands/work/complete.js.map +1 -1
- package/dist/commands/work/drop.d.ts +14 -0
- package/dist/commands/work/drop.js +215 -0
- package/dist/commands/work/drop.js.map +1 -0
- package/dist/commands/work/ready.d.ts +1 -0
- package/dist/commands/work/ready.js +26 -25
- package/dist/commands/work/ready.js.map +1 -1
- package/dist/commands/work/resolve.js +1 -1
- package/dist/commands/work/resolve.js.map +1 -1
- package/dist/commands/work/ship.d.ts +1 -0
- package/dist/commands/work/ship.js +33 -32
- package/dist/commands/work/ship.js.map +1 -1
- package/dist/commands/work/start.d.ts +2 -0
- package/dist/commands/work/start.js +172 -125
- package/dist/commands/work/start.js.map +1 -1
- package/dist/commands/work/stop.d.ts +1 -0
- package/dist/commands/work/stop.js +40 -0
- package/dist/commands/work/stop.js.map +1 -1
- package/dist/lib/agents/commands.js +7 -5
- package/dist/lib/agents/commands.js.map +1 -1
- package/dist/lib/dashboard/data.js +1 -1
- package/dist/lib/dashboard/data.js.map +1 -1
- package/dist/lib/database/db-safety.d.ts +22 -0
- package/dist/lib/database/db-safety.js +91 -4
- package/dist/lib/database/db-safety.js.map +1 -1
- package/dist/lib/database/drizzle-schema.d.ts +17 -0
- package/dist/lib/database/drizzle-schema.js +1 -0
- package/dist/lib/database/drizzle-schema.js.map +1 -1
- package/dist/lib/database/index.d.ts +1 -1
- package/dist/lib/database/index.js +1 -1
- package/dist/lib/database/index.js.map +1 -1
- package/dist/lib/database/migrations/0017_drop_agent_work_fk.d.ts +13 -0
- package/dist/lib/database/migrations/0017_drop_agent_work_fk.js +85 -0
- package/dist/lib/database/migrations/0017_drop_agent_work_fk.js.map +1 -0
- package/dist/lib/database/migrations/0018_create_ticket_refs.d.ts +11 -0
- package/dist/lib/database/migrations/0018_create_ticket_refs.js +40 -0
- package/dist/lib/database/migrations/0018_create_ticket_refs.js.map +1 -0
- package/dist/lib/database/migrations/0019_gc_artifact_cleanup.d.ts +9 -0
- package/dist/lib/database/migrations/0019_gc_artifact_cleanup.js +23 -0
- package/dist/lib/database/migrations/0019_gc_artifact_cleanup.js.map +1 -0
- package/dist/lib/database/migrations/0020_transition_map.d.ts +2 -0
- package/dist/lib/database/migrations/0020_transition_map.js +27 -0
- package/dist/lib/database/migrations/0020_transition_map.js.map +1 -0
- package/dist/lib/database/migrations/index.js +8 -0
- package/dist/lib/database/migrations/index.js.map +1 -1
- package/dist/lib/execution/config.d.ts +10 -0
- package/dist/lib/execution/config.js +24 -0
- package/dist/lib/execution/config.js.map +1 -1
- package/dist/lib/execution/devcontainer.js +1 -1
- package/dist/lib/execution/devcontainer.js.map +1 -1
- package/dist/lib/execution/preflight.d.ts +51 -0
- package/dist/lib/execution/preflight.js +278 -0
- package/dist/lib/execution/preflight.js.map +1 -0
- package/dist/lib/execution/runners/docker-management.d.ts +9 -0
- package/dist/lib/execution/runners/docker-management.js +14 -3
- package/dist/lib/execution/runners/docker-management.js.map +1 -1
- package/dist/lib/execution/runners/prompt-builder.d.ts +6 -0
- package/dist/lib/execution/runners/prompt-builder.js +53 -10
- package/dist/lib/execution/runners/prompt-builder.js.map +1 -1
- package/dist/lib/execution/runners/shared.d.ts +1 -1
- package/dist/lib/execution/runners/shared.js +1 -1
- package/dist/lib/execution/runners/shared.js.map +1 -1
- package/dist/lib/execution/session-utils.d.ts +39 -0
- package/dist/lib/execution/session-utils.js +111 -0
- package/dist/lib/execution/session-utils.js.map +1 -1
- package/dist/lib/execution/spawner.d.ts +11 -1
- package/dist/lib/execution/spawner.js +46 -17
- package/dist/lib/execution/spawner.js.map +1 -1
- package/dist/lib/execution/storage.js +2 -1
- package/dist/lib/execution/storage.js.map +1 -1
- package/dist/lib/execution/ticket-refs.d.ts +71 -0
- package/dist/lib/execution/ticket-refs.js +125 -0
- package/dist/lib/execution/ticket-refs.js.map +1 -0
- package/dist/lib/execution/types.d.ts +7 -2
- package/dist/lib/execution/types.js +5 -3
- package/dist/lib/execution/types.js.map +1 -1
- package/dist/lib/external-issues/utils.d.ts +25 -0
- package/dist/lib/external-issues/utils.js +32 -0
- package/dist/lib/external-issues/utils.js.map +1 -0
- package/dist/lib/gc/index.d.ts +179 -0
- package/dist/lib/gc/index.js +655 -0
- package/dist/lib/gc/index.js.map +1 -0
- package/dist/lib/mcp/tools/action.js +1 -1
- package/dist/lib/mcp/tools/action.js.map +1 -1
- package/dist/lib/mcp/tools/ticket.js +1 -1
- package/dist/lib/mcp/tools/ticket.js.map +1 -1
- package/dist/lib/orchestrate/actions.js +30 -0
- package/dist/lib/orchestrate/actions.js.map +1 -1
- package/dist/lib/orchestrate/poller.js +3 -3
- package/dist/lib/orchestrate/poller.js.map +1 -1
- package/dist/lib/orchestrate/presets.js +2 -1
- package/dist/lib/orchestrate/presets.js.map +1 -1
- package/dist/lib/orchestrate/types.d.ts +1 -1
- package/dist/lib/orchestrate/types.js +1 -0
- package/dist/lib/orchestrate/types.js.map +1 -1
- package/dist/lib/pmo/index.js +1 -1
- package/dist/lib/pmo/index.js.map +1 -1
- package/dist/lib/pmo/markdown.js +1 -1
- package/dist/lib/pmo/markdown.js.map +1 -1
- package/dist/lib/pmo/schema.d.ts +3 -1
- package/dist/lib/pmo/schema.js +26 -2
- package/dist/lib/pmo/schema.js.map +1 -1
- package/dist/lib/pmo/storage/actions.js +1 -1
- package/dist/lib/pmo/storage/actions.js.map +1 -1
- package/dist/lib/pmo/storage/base.js +37 -15
- package/dist/lib/pmo/storage/base.js.map +1 -1
- package/dist/lib/pmo/storage/projects.js +2 -1
- package/dist/lib/pmo/storage/projects.js.map +1 -1
- package/dist/lib/pmo/storage/statuses.js +1 -1
- package/dist/lib/pmo/storage/statuses.js.map +1 -1
- package/dist/lib/pmo/storage/subtasks.js +1 -1
- package/dist/lib/pmo/storage/subtasks.js.map +1 -1
- package/dist/lib/pmo/storage/templates.js +1 -1
- package/dist/lib/pmo/storage/templates.js.map +1 -1
- package/dist/lib/pmo/storage/tickets.js +2 -1
- package/dist/lib/pmo/storage/tickets.js.map +1 -1
- package/dist/lib/pmo/storage/workflow-rules.js +1 -1
- package/dist/lib/pmo/storage/workflow-rules.js.map +1 -1
- package/dist/lib/pmo/utils.d.ts +6 -189
- package/dist/lib/pmo/utils.js +6 -306
- package/dist/lib/pmo/utils.js.map +1 -1
- package/dist/lib/prompt-json.d.ts +31 -0
- package/dist/lib/prompt-json.js.map +1 -1
- package/dist/lib/providers/auto-mapper.d.ts +45 -0
- package/dist/lib/providers/auto-mapper.js +115 -0
- package/dist/lib/providers/auto-mapper.js.map +1 -0
- package/dist/lib/providers/state-intents.d.ts +20 -0
- package/dist/lib/providers/state-intents.js +61 -7
- package/dist/lib/providers/state-intents.js.map +1 -1
- package/dist/lib/providers/state-resolution.d.ts +15 -11
- package/dist/lib/providers/state-resolution.js +54 -48
- package/dist/lib/providers/state-resolution.js.map +1 -1
- package/dist/lib/providers/transition-map.d.ts +59 -0
- package/dist/lib/providers/transition-map.js +113 -0
- package/dist/lib/providers/transition-map.js.map +1 -0
- package/dist/lib/session/heartbeat.js +1 -1
- package/dist/lib/session/heartbeat.js.map +1 -1
- package/dist/lib/session/index.d.ts +3 -1
- package/dist/lib/session/index.js +3 -1
- package/dist/lib/session/index.js.map +1 -1
- package/dist/lib/session/tmux-watchdog.d.ts +157 -0
- package/dist/lib/session/tmux-watchdog.js +424 -0
- package/dist/lib/session/tmux-watchdog.js.map +1 -0
- package/dist/lib/session/watcher.d.ts +22 -4
- package/dist/lib/session/watcher.js +66 -8
- package/dist/lib/session/watcher.js.map +1 -1
- package/dist/lib/sync/daemon-process.d.ts +9 -0
- package/dist/lib/sync/daemon-process.js +184 -0
- package/dist/lib/sync/daemon-process.js.map +1 -0
- package/dist/lib/sync/daemon.d.ts +39 -0
- package/dist/lib/sync/daemon.js +91 -0
- package/dist/lib/sync/daemon.js.map +1 -0
- package/dist/lib/sync/engine.d.ts +38 -0
- package/dist/lib/sync/engine.js +145 -0
- package/dist/lib/sync/engine.js.map +1 -0
- package/dist/lib/sync/merge-queue.d.ts +116 -0
- package/dist/lib/sync/merge-queue.js +321 -0
- package/dist/lib/sync/merge-queue.js.map +1 -0
- package/dist/lib/sync/reconciler.d.ts +44 -0
- package/dist/lib/sync/reconciler.js +88 -0
- package/dist/lib/sync/reconciler.js.map +1 -0
- package/dist/lib/utils/text.d.ts +44 -0
- package/dist/lib/utils/text.js +72 -0
- package/dist/lib/utils/text.js.map +1 -0
- package/dist/lib/work-lifecycle/post-execution.js +1 -1
- package/dist/lib/work-lifecycle/post-execution.js.map +1 -1
- package/dist/lib/work-lifecycle/settings.d.ts +138 -0
- package/dist/lib/work-lifecycle/settings.js +213 -0
- package/dist/lib/work-lifecycle/settings.js.map +1 -0
- package/dist/lib/work-lifecycle/transition.d.ts +73 -0
- package/dist/lib/work-lifecycle/transition.js +124 -0
- package/dist/lib/work-lifecycle/transition.js.map +1 -0
- package/oclif.manifest.json +3235 -3380
- package/package.json +1 -1
- package/dist/commands/action/create.d.ts +0 -26
- package/dist/commands/action/create.js +0 -245
- package/dist/commands/action/create.js.map +0 -1
- package/dist/commands/action/delete.d.ts +0 -18
- package/dist/commands/action/delete.js +0 -78
- package/dist/commands/action/delete.js.map +0 -1
- package/dist/commands/action/index.js +0 -103
- package/dist/commands/action/index.js.map +0 -1
- package/dist/commands/action/list.d.ts +0 -15
- package/dist/commands/action/list.js +0 -90
- package/dist/commands/action/list.js.map +0 -1
- package/dist/commands/action/run.d.ts +0 -20
- package/dist/commands/action/run.js +0 -188
- package/dist/commands/action/run.js.map +0 -1
- package/dist/commands/action/show.d.ts +0 -17
- package/dist/commands/action/show.js +0 -78
- package/dist/commands/action/show.js.map +0 -1
- package/dist/commands/action/update.d.ts +0 -27
- package/dist/commands/action/update.js +0 -288
- package/dist/commands/action/update.js.map +0 -1
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
* that can't self-report (OOM kills, zombie processes, container crashes).
|
|
7
7
|
*
|
|
8
8
|
* Architecture:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Phase 0: Tmux server health check — detect full server crashes (PRLT-1115)
|
|
10
|
+
* Phase 1: Record heartbeats for alive agents (tmux pane inspection)
|
|
11
|
+
* Phase 2: Detect stale executions that exceeded the timeout
|
|
12
|
+
* Phase 3: Act on stale executions — mark failed, kill containers, fire events
|
|
13
13
|
*/
|
|
14
14
|
import { ExecutionStorage } from '../execution/storage.js';
|
|
15
15
|
import { recordAllHeartbeats, detectStaleExecutions, killContainer, } from './heartbeat.js';
|
|
16
|
+
import { TmuxWatchdog, formatCrashNotification, sendDesktopNotification, } from './tmux-watchdog.js';
|
|
16
17
|
// =============================================================================
|
|
17
18
|
// Session Watcher
|
|
18
19
|
// =============================================================================
|
|
@@ -22,18 +23,40 @@ export class SessionWatcher {
|
|
|
22
23
|
intervalMinutes;
|
|
23
24
|
timeoutMinutes;
|
|
24
25
|
autoKill;
|
|
26
|
+
autoRecover;
|
|
25
27
|
log;
|
|
26
28
|
onStaleDetected;
|
|
29
|
+
onCrashDetected;
|
|
27
30
|
timer = null;
|
|
28
31
|
running = false;
|
|
32
|
+
watchdog;
|
|
33
|
+
isFirstCycle = true;
|
|
29
34
|
constructor(options) {
|
|
30
35
|
this.db = options.db;
|
|
31
36
|
this.storage = new ExecutionStorage(options.db);
|
|
32
37
|
this.intervalMinutes = options.intervalMinutes ?? 5;
|
|
33
38
|
this.timeoutMinutes = options.timeoutMinutes ?? 15;
|
|
34
39
|
this.autoKill = options.autoKill ?? true;
|
|
40
|
+
this.autoRecover = options.autoRecover ?? true;
|
|
35
41
|
this.log = options.log ?? (() => { });
|
|
36
42
|
this.onStaleDetected = options.onStaleDetected;
|
|
43
|
+
this.onCrashDetected = options.onCrashDetected;
|
|
44
|
+
this.watchdog = new TmuxWatchdog({
|
|
45
|
+
storage: this.storage,
|
|
46
|
+
autoRecover: this.autoRecover,
|
|
47
|
+
log: this.log,
|
|
48
|
+
onCrashDetected: async (event) => {
|
|
49
|
+
// Send desktop notification
|
|
50
|
+
const notification = formatCrashNotification(event);
|
|
51
|
+
this.log(notification);
|
|
52
|
+
sendDesktopNotification('prlt: tmux server crash', `${event.affectedExecutions.length} agent(s) affected. ` +
|
|
53
|
+
`${event.recoveredSessions.length} recovered.`);
|
|
54
|
+
// Fire user callback
|
|
55
|
+
if (this.onCrashDetected) {
|
|
56
|
+
await this.onCrashDetected(event);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
});
|
|
37
60
|
}
|
|
38
61
|
/**
|
|
39
62
|
* Run a single watch cycle.
|
|
@@ -45,7 +68,25 @@ export class SessionWatcher {
|
|
|
45
68
|
heartbeatsUpdated: 0,
|
|
46
69
|
staleExecutions: [],
|
|
47
70
|
containersKilled: 0,
|
|
71
|
+
crashEvents: [],
|
|
72
|
+
crashRecoveries: 0,
|
|
48
73
|
};
|
|
74
|
+
// Phase 0: Tmux server health check (PRLT-1115)
|
|
75
|
+
// Detect full server crashes before doing individual heartbeat checks.
|
|
76
|
+
// On the first cycle, seed the watchdog state without triggering crash detection.
|
|
77
|
+
if (this.isFirstCycle) {
|
|
78
|
+
const activeExecs = [
|
|
79
|
+
...this.storage.listExecutions({ status: 'running' }),
|
|
80
|
+
...this.storage.listExecutions({ status: 'starting' }),
|
|
81
|
+
];
|
|
82
|
+
this.watchdog.seedServerState(activeExecs);
|
|
83
|
+
this.isFirstCycle = false;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const watchdogResult = await this.watchdog.checkAndRecover();
|
|
87
|
+
result.crashEvents = watchdogResult.crashEvents;
|
|
88
|
+
result.crashRecoveries = watchdogResult.totalRecovered;
|
|
89
|
+
}
|
|
49
90
|
// Phase 1: Record heartbeats for all active executions
|
|
50
91
|
// This is the "push" side — we check tmux panes and update heartbeats
|
|
51
92
|
const heartbeats = recordAllHeartbeats(this.storage);
|
|
@@ -88,7 +129,8 @@ export class SessionWatcher {
|
|
|
88
129
|
if (this.running)
|
|
89
130
|
return;
|
|
90
131
|
this.running = true;
|
|
91
|
-
this.log(`[watcher] Starting session watcher (interval: ${this.intervalMinutes}m, timeout: ${this.timeoutMinutes}m,
|
|
132
|
+
this.log(`[watcher] Starting session watcher (interval: ${this.intervalMinutes}m, timeout: ${this.timeoutMinutes}m, ` +
|
|
133
|
+
`auto-kill: ${this.autoKill}, auto-recover: ${this.autoRecover})`);
|
|
92
134
|
// Run initial cycle
|
|
93
135
|
void this.runCycleWithErrorHandling();
|
|
94
136
|
// Start polling
|
|
@@ -124,14 +166,30 @@ export class SessionWatcher {
|
|
|
124
166
|
intervalMinutes: this.intervalMinutes,
|
|
125
167
|
timeoutMinutes: this.timeoutMinutes,
|
|
126
168
|
autoKill: this.autoKill,
|
|
169
|
+
autoRecover: this.autoRecover,
|
|
127
170
|
};
|
|
128
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Get the tmux watchdog instance (for testing/diagnostics).
|
|
174
|
+
*/
|
|
175
|
+
getWatchdog() {
|
|
176
|
+
return this.watchdog;
|
|
177
|
+
}
|
|
129
178
|
async runCycleWithErrorHandling() {
|
|
130
179
|
try {
|
|
131
180
|
const result = await this.runCycle();
|
|
132
|
-
if (result.staleExecutions.length > 0) {
|
|
133
|
-
|
|
134
|
-
`${result.
|
|
181
|
+
if (result.staleExecutions.length > 0 || result.crashEvents.length > 0) {
|
|
182
|
+
const parts = [
|
|
183
|
+
`${result.checked} checked`,
|
|
184
|
+
`${result.heartbeatsUpdated} heartbeats`,
|
|
185
|
+
`${result.staleExecutions.length} stale`,
|
|
186
|
+
`${result.containersKilled} killed`,
|
|
187
|
+
];
|
|
188
|
+
if (result.crashEvents.length > 0) {
|
|
189
|
+
parts.push(`${result.crashEvents.length} crash(es)`);
|
|
190
|
+
parts.push(`${result.crashRecoveries} recovered`);
|
|
191
|
+
}
|
|
192
|
+
this.log(`[watcher] Cycle complete: ${parts.join(', ')}`);
|
|
135
193
|
}
|
|
136
194
|
}
|
|
137
195
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/lib/session/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE1D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,GAEd,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/lib/session/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Process
|
|
3
|
+
*
|
|
4
|
+
* This is the background process spawned by `prlt sync start`.
|
|
5
|
+
* It runs a sync cycle and merge queue cycle on a configurable interval.
|
|
6
|
+
*
|
|
7
|
+
* Args: [hqPath, intervalSeconds]
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import { openWorkspaceDatabase } from '../database/index.js';
|
|
11
|
+
import { getPMOContext } from '../pmo/pmo-context.js';
|
|
12
|
+
import { runSyncCycle } from './engine.js';
|
|
13
|
+
import { runMergeQueueCycle } from './merge-queue.js';
|
|
14
|
+
import { removeDaemonPid, getDaemonLogPath } from './daemon.js';
|
|
15
|
+
import { GCScheduler, collectGCCandidates, executeGC, } from '../gc/index.js';
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const hqPath = args[0];
|
|
18
|
+
const intervalSeconds = parseInt(args[1] || '60', 10);
|
|
19
|
+
if (!hqPath) {
|
|
20
|
+
console.error('Usage: daemon-process <hqPath> [intervalSeconds]');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const logPath = getDaemonLogPath(hqPath);
|
|
24
|
+
function log(msg) {
|
|
25
|
+
const timestamp = new Date().toISOString();
|
|
26
|
+
const line = `[${timestamp}] ${msg}\n`;
|
|
27
|
+
fs.appendFileSync(logPath, line);
|
|
28
|
+
}
|
|
29
|
+
async function getProjectId() {
|
|
30
|
+
const context = await getPMOContext();
|
|
31
|
+
const projects = await context.storage.listProjects();
|
|
32
|
+
await context.storage.close();
|
|
33
|
+
if (projects.length === 0) {
|
|
34
|
+
throw new Error('No projects found');
|
|
35
|
+
}
|
|
36
|
+
return projects[0].id;
|
|
37
|
+
}
|
|
38
|
+
// GC scheduler with 1-hour grace period — persists across daemon cycles
|
|
39
|
+
const gcScheduler = new GCScheduler(60 * 60 * 1000);
|
|
40
|
+
/** Map ticket priority strings to numeric values (lower = higher priority). */
|
|
41
|
+
function priorityToNumber(priority) {
|
|
42
|
+
switch (priority) {
|
|
43
|
+
case 'P0': return 0;
|
|
44
|
+
case 'P1': return 1;
|
|
45
|
+
case 'P2': return 2;
|
|
46
|
+
case 'P3': return 3;
|
|
47
|
+
default: return 3;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function cycle() {
|
|
51
|
+
let db;
|
|
52
|
+
try {
|
|
53
|
+
db = openWorkspaceDatabase(hqPath);
|
|
54
|
+
const context = await getPMOContext();
|
|
55
|
+
const projectId = await getProjectId();
|
|
56
|
+
const storage = context.storage;
|
|
57
|
+
// Phase 1: Reconciliation — sync ticket state with PR state
|
|
58
|
+
const report = await runSyncCycle(db, storage, projectId, {
|
|
59
|
+
cwd: hqPath,
|
|
60
|
+
log,
|
|
61
|
+
});
|
|
62
|
+
if (report.applied.length > 0) {
|
|
63
|
+
log(`Applied ${report.applied.length} correction(s)`);
|
|
64
|
+
}
|
|
65
|
+
if (report.failed.length > 0) {
|
|
66
|
+
log(`Failed ${report.failed.length} correction(s)`);
|
|
67
|
+
}
|
|
68
|
+
// Phase 2: Merge Queue — sequential rebase-test-merge pipeline
|
|
69
|
+
try {
|
|
70
|
+
// Build priority map from tickets for queue ordering
|
|
71
|
+
const branchPriorities = new Map();
|
|
72
|
+
const startedTickets = await storage.listTickets(projectId, { statusCategory: 'started' });
|
|
73
|
+
for (const ticket of startedTickets) {
|
|
74
|
+
if (ticket.branch) {
|
|
75
|
+
branchPriorities.set(ticket.branch, priorityToNumber(ticket.priority));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const mqResult = runMergeQueueCycle({
|
|
79
|
+
hqPath,
|
|
80
|
+
cwd: hqPath,
|
|
81
|
+
log,
|
|
82
|
+
branchPriorities,
|
|
83
|
+
});
|
|
84
|
+
if (mqResult.action !== 'none' && mqResult.action !== 'paused') {
|
|
85
|
+
log(`Merge queue: ${mqResult.action}${mqResult.prNumber ? ` PR #${mqResult.prNumber}` : ''}${mqResult.reason ? ` — ${mqResult.reason}` : ''}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (mqErr) {
|
|
89
|
+
const mqMsg = mqErr instanceof Error ? mqErr.message : String(mqErr);
|
|
90
|
+
log(`Merge queue error: ${mqMsg}`);
|
|
91
|
+
}
|
|
92
|
+
// Phase 3: Garbage Collection — schedule cleanup for merged PRs, run ready cleanups
|
|
93
|
+
try {
|
|
94
|
+
// Schedule GC for any tickets that just moved to Done (PR merged)
|
|
95
|
+
const mergedActions = report.applied.filter(a => a.type === 'move_to_done');
|
|
96
|
+
if (mergedActions.length > 0) {
|
|
97
|
+
const completedTickets = await storage.listTickets(projectId, { statusCategory: 'completed' });
|
|
98
|
+
for (const action of mergedActions) {
|
|
99
|
+
const ticket = completedTickets.find(t => t.id === action.ticketId);
|
|
100
|
+
if (ticket?.branch) {
|
|
101
|
+
gcScheduler.schedule(ticket.branch);
|
|
102
|
+
log(`GC: Scheduled cleanup for branch ${ticket.branch} (1hr grace period)`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Process any ready cleanups (grace period expired)
|
|
107
|
+
const readyBranches = gcScheduler.getReady();
|
|
108
|
+
if (readyBranches.length > 0) {
|
|
109
|
+
log(`GC: Processing ${readyBranches.length} cleanup(s) past grace period`);
|
|
110
|
+
const candidates = collectGCCandidates({
|
|
111
|
+
hqPath,
|
|
112
|
+
staleDays: 7,
|
|
113
|
+
log,
|
|
114
|
+
});
|
|
115
|
+
// Only clean up the branches that are ready
|
|
116
|
+
const readySet = new Set(readyBranches);
|
|
117
|
+
const readyCandidates = candidates.filter(c => readySet.has(c.branch));
|
|
118
|
+
if (readyCandidates.length > 0) {
|
|
119
|
+
const result = executeGC(readyCandidates, {
|
|
120
|
+
hqPath,
|
|
121
|
+
execute: true,
|
|
122
|
+
log,
|
|
123
|
+
});
|
|
124
|
+
if (result.worktreesRemoved.length > 0) {
|
|
125
|
+
log(`GC: Removed ${result.worktreesRemoved.length} worktree(s), ${result.containersRemoved.length} container(s), ${result.branchesPruned.length} branch(es)`);
|
|
126
|
+
}
|
|
127
|
+
if (result.errors.length > 0) {
|
|
128
|
+
log(`GC: ${result.errors.length} error(s): ${result.errors.join('; ')}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Mark as completed regardless of whether cleanup was needed
|
|
132
|
+
for (const branch of readyBranches) {
|
|
133
|
+
gcScheduler.complete(branch);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (gcErr) {
|
|
138
|
+
const gcMsg = gcErr instanceof Error ? gcErr.message : String(gcErr);
|
|
139
|
+
log(`GC error: ${gcMsg}`);
|
|
140
|
+
}
|
|
141
|
+
await context.storage.close();
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
145
|
+
log(`Error: ${msg}`);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
if (db) {
|
|
149
|
+
try {
|
|
150
|
+
db.close();
|
|
151
|
+
}
|
|
152
|
+
catch { }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Signal handling
|
|
157
|
+
process.on('SIGTERM', () => {
|
|
158
|
+
log('Received SIGTERM — shutting down');
|
|
159
|
+
removeDaemonPid(hqPath);
|
|
160
|
+
process.exit(0);
|
|
161
|
+
});
|
|
162
|
+
process.on('SIGINT', () => {
|
|
163
|
+
log('Received SIGINT — shutting down');
|
|
164
|
+
removeDaemonPid(hqPath);
|
|
165
|
+
process.exit(0);
|
|
166
|
+
});
|
|
167
|
+
// Main loop
|
|
168
|
+
log(`Daemon started (PID ${process.pid}, interval ${intervalSeconds}s)`);
|
|
169
|
+
async function run() {
|
|
170
|
+
// Run initial cycle immediately
|
|
171
|
+
await cycle();
|
|
172
|
+
// Then schedule periodic runs
|
|
173
|
+
setInterval(() => {
|
|
174
|
+
cycle().catch(err => {
|
|
175
|
+
log(`Unhandled error in cycle: ${err}`);
|
|
176
|
+
});
|
|
177
|
+
}, intervalSeconds * 1000);
|
|
178
|
+
}
|
|
179
|
+
run().catch(err => {
|
|
180
|
+
log(`Fatal: ${err}`);
|
|
181
|
+
removeDaemonPid(hqPath);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=daemon-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-process.js","sourceRoot":"","sources":["../../../src/lib/sync/daemon-process.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Daemon
|
|
3
|
+
*
|
|
4
|
+
* Manages a background process that periodically runs the sync engine.
|
|
5
|
+
* Uses a PID file in the HQ directory to track the daemon process.
|
|
6
|
+
*/
|
|
7
|
+
export interface DaemonInfo {
|
|
8
|
+
pid: number;
|
|
9
|
+
startedAt: string;
|
|
10
|
+
intervalSeconds: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the path to the daemon PID file.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getDaemonPidPath(hqPath: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Get the path to the daemon log file.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getDaemonLogPath(hqPath: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Read daemon info from PID file.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getDaemonInfo(hqPath: string): DaemonInfo | null;
|
|
24
|
+
/**
|
|
25
|
+
* Write daemon info to PID file.
|
|
26
|
+
*/
|
|
27
|
+
export declare function writeDaemonInfo(hqPath: string, info: DaemonInfo): void;
|
|
28
|
+
/**
|
|
29
|
+
* Remove daemon PID file.
|
|
30
|
+
*/
|
|
31
|
+
export declare function removeDaemonPid(hqPath: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Check if a daemon process is alive by PID.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isDaemonRunning(hqPath: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Stop the daemon process.
|
|
38
|
+
*/
|
|
39
|
+
export declare function stopDaemon(hqPath: string): boolean;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Daemon
|
|
3
|
+
*
|
|
4
|
+
* Manages a background process that periodically runs the sync engine.
|
|
5
|
+
* Uses a PID file in the HQ directory to track the daemon process.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
const DAEMON_PID_FILE = 'sync-daemon.pid';
|
|
10
|
+
const DAEMON_LOG_FILE = 'sync-daemon.log';
|
|
11
|
+
/**
|
|
12
|
+
* Get the path to the daemon PID file.
|
|
13
|
+
*/
|
|
14
|
+
export function getDaemonPidPath(hqPath) {
|
|
15
|
+
return path.join(hqPath, '.proletariat', DAEMON_PID_FILE);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get the path to the daemon log file.
|
|
19
|
+
*/
|
|
20
|
+
export function getDaemonLogPath(hqPath) {
|
|
21
|
+
return path.join(hqPath, '.proletariat', DAEMON_LOG_FILE);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read daemon info from PID file.
|
|
25
|
+
*/
|
|
26
|
+
export function getDaemonInfo(hqPath) {
|
|
27
|
+
const pidPath = getDaemonPidPath(hqPath);
|
|
28
|
+
try {
|
|
29
|
+
const content = fs.readFileSync(pidPath, 'utf-8');
|
|
30
|
+
return JSON.parse(content);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Write daemon info to PID file.
|
|
38
|
+
*/
|
|
39
|
+
export function writeDaemonInfo(hqPath, info) {
|
|
40
|
+
const pidPath = getDaemonPidPath(hqPath);
|
|
41
|
+
fs.writeFileSync(pidPath, JSON.stringify(info, null, 2));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Remove daemon PID file.
|
|
45
|
+
*/
|
|
46
|
+
export function removeDaemonPid(hqPath) {
|
|
47
|
+
const pidPath = getDaemonPidPath(hqPath);
|
|
48
|
+
try {
|
|
49
|
+
fs.unlinkSync(pidPath);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// File may not exist
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if a daemon process is alive by PID.
|
|
57
|
+
*/
|
|
58
|
+
export function isDaemonRunning(hqPath) {
|
|
59
|
+
const info = getDaemonInfo(hqPath);
|
|
60
|
+
if (!info)
|
|
61
|
+
return false;
|
|
62
|
+
try {
|
|
63
|
+
// Sending signal 0 checks if process exists without killing it
|
|
64
|
+
process.kill(info.pid, 0);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Process doesn't exist — clean up stale PID file
|
|
69
|
+
removeDaemonPid(hqPath);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop the daemon process.
|
|
75
|
+
*/
|
|
76
|
+
export function stopDaemon(hqPath) {
|
|
77
|
+
const info = getDaemonInfo(hqPath);
|
|
78
|
+
if (!info)
|
|
79
|
+
return false;
|
|
80
|
+
try {
|
|
81
|
+
process.kill(info.pid, 'SIGTERM');
|
|
82
|
+
removeDaemonPid(hqPath);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Process may already be dead
|
|
87
|
+
removeDaemonPid(hqPath);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/lib/sync/daemon.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC,MAAM,eAAe,GAAG,iBAAiB,CAAA;AACzC,MAAM,eAAe,GAAG,iBAAiB,CAAA;AAQzC;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,eAAe,CAAC,CAAA;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,eAAe,CAAC,CAAA;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACxC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACjD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAA;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,IAAgB;IAC9D,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACxC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACxC,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAA;IAEvB,IAAI,CAAC;QACH,+DAA+D;QAC/D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;QAClD,eAAe,CAAC,MAAM,CAAC,CAAA;QACvB,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAA;IAEvB,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACjC,eAAe,CAAC,MAAM,CAAC,CAAA;QACvB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;QAC9B,eAAe,CAAC,MAAM,CAAC,CAAA;QACvB,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Engine
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the reconciliation process: gathers ticket state and PR state,
|
|
5
|
+
* runs the reconciler, and applies corrective actions through providers.
|
|
6
|
+
*
|
|
7
|
+
* This is the "run once" engine. The daemon wraps this with a polling loop.
|
|
8
|
+
*/
|
|
9
|
+
import type Database from 'better-sqlite3';
|
|
10
|
+
import type { ProviderStorage } from '../providers/types.js';
|
|
11
|
+
import type { PMOStorage } from '../pmo/types.js';
|
|
12
|
+
import { type ReconcileAction, type ReconcileResult } from './reconciler.js';
|
|
13
|
+
export interface SyncEngineOptions {
|
|
14
|
+
/** Working directory for git/gh operations */
|
|
15
|
+
cwd?: string;
|
|
16
|
+
/** Callback for logging */
|
|
17
|
+
log?: (msg: string) => void;
|
|
18
|
+
/** If true, don't actually move tickets — just report what would happen */
|
|
19
|
+
dryRun?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface SyncReport {
|
|
22
|
+
result: ReconcileResult;
|
|
23
|
+
applied: ReconcileAction[];
|
|
24
|
+
skipped: ReconcileAction[];
|
|
25
|
+
failed: Array<{
|
|
26
|
+
action: ReconcileAction;
|
|
27
|
+
error: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Run a single reconciliation cycle.
|
|
32
|
+
*
|
|
33
|
+
* 1. List all tickets in started/review states
|
|
34
|
+
* 2. For each, check PR status
|
|
35
|
+
* 3. Run reconciler to determine actions
|
|
36
|
+
* 4. Apply actions through providers
|
|
37
|
+
*/
|
|
38
|
+
export declare function runSyncCycle(db: Database.Database, storage: PMOStorage & ProviderStorage, projectId: string, options?: SyncEngineOptions): Promise<SyncReport>;
|