episoda 0.2.56 → 0.2.58
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.
|
@@ -2726,7 +2726,7 @@ var require_package = __commonJS({
|
|
|
2726
2726
|
"package.json"(exports2, module2) {
|
|
2727
2727
|
module2.exports = {
|
|
2728
2728
|
name: "episoda",
|
|
2729
|
-
version: "0.2.
|
|
2729
|
+
version: "0.2.58",
|
|
2730
2730
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2731
2731
|
main: "dist/index.js",
|
|
2732
2732
|
types: "dist/index.d.ts",
|
|
@@ -8787,6 +8787,9 @@ var Daemon = class _Daemon {
|
|
|
8787
8787
|
this.reconcileWorktrees(projectId, projectPath, client).catch((err) => {
|
|
8788
8788
|
console.warn("[Daemon] EP1003: Reconciliation report failed:", err.message);
|
|
8789
8789
|
});
|
|
8790
|
+
this.reconcilePendingCleanups(projectId, projectPath).catch((err) => {
|
|
8791
|
+
console.warn("[Daemon] EP1047: Cleanup queue reconciliation failed:", err.message);
|
|
8792
|
+
});
|
|
8790
8793
|
});
|
|
8791
8794
|
client.on("module_state_changed", async (message) => {
|
|
8792
8795
|
if (message.type === "module_state_changed") {
|
|
@@ -9229,6 +9232,125 @@ var Daemon = class _Daemon {
|
|
|
9229
9232
|
// EP1025: Removed cleanupModuleWorktree - was dead code (never called).
|
|
9230
9233
|
// Worktree cleanup is handled by server's cleanupWorktreeAsync which sends
|
|
9231
9234
|
// worktree_remove command via WebSocket, handled by GitExecutor.executeWorktreeRemove.
|
|
9235
|
+
/**
|
|
9236
|
+
* EP1047: Process pending cleanup queue entries for this machine
|
|
9237
|
+
*
|
|
9238
|
+
* On daemon startup/reconnect, fetch pending worktree cleanup tasks from the queue
|
|
9239
|
+
* and process them. This catches any cleanups missed while the daemon was offline.
|
|
9240
|
+
*
|
|
9241
|
+
* Flow:
|
|
9242
|
+
* 1. Query server for pending cleanup tasks for this machine
|
|
9243
|
+
* 2. For each task, attempt worktree removal
|
|
9244
|
+
* 3. Report success/failure back to server
|
|
9245
|
+
*/
|
|
9246
|
+
async reconcilePendingCleanups(projectId, projectPath) {
|
|
9247
|
+
if (!this.deviceId) {
|
|
9248
|
+
console.log("[Daemon] EP1047: Cannot reconcile cleanups - deviceId not available yet");
|
|
9249
|
+
return;
|
|
9250
|
+
}
|
|
9251
|
+
console.log(`[Daemon] EP1047: Checking for pending cleanup tasks for machine ${this.deviceId}`);
|
|
9252
|
+
try {
|
|
9253
|
+
const config = await (0, import_core12.loadConfig)();
|
|
9254
|
+
if (!config) {
|
|
9255
|
+
console.log("[Daemon] EP1047: No config loaded, skipping cleanup reconciliation");
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
const apiUrl = config.api_url || "https://episoda.dev";
|
|
9259
|
+
const controller = new AbortController();
|
|
9260
|
+
const timeoutId = setTimeout(() => controller.abort(), 1e4);
|
|
9261
|
+
let response;
|
|
9262
|
+
try {
|
|
9263
|
+
response = await fetchWithAuth(
|
|
9264
|
+
`${apiUrl}/api/cli/background-ops?machine_id=${this.deviceId}`,
|
|
9265
|
+
{ signal: controller.signal }
|
|
9266
|
+
);
|
|
9267
|
+
} finally {
|
|
9268
|
+
clearTimeout(timeoutId);
|
|
9269
|
+
}
|
|
9270
|
+
if (!response.ok) {
|
|
9271
|
+
console.warn(`[Daemon] EP1051: Failed to fetch background operations: ${response.status}`);
|
|
9272
|
+
return;
|
|
9273
|
+
}
|
|
9274
|
+
const data = await response.json();
|
|
9275
|
+
const tasks = data.data?.tasks || [];
|
|
9276
|
+
if (tasks.length === 0) {
|
|
9277
|
+
console.log("[Daemon] EP1051: No pending background operations");
|
|
9278
|
+
return;
|
|
9279
|
+
}
|
|
9280
|
+
console.log(`[Daemon] EP1051: Processing ${tasks.length} pending operation(s)`);
|
|
9281
|
+
const projectRoot = await findProjectRoot(projectPath);
|
|
9282
|
+
if (!projectRoot) {
|
|
9283
|
+
console.warn("[Daemon] EP1051: Could not find project root, skipping operation reconciliation");
|
|
9284
|
+
return;
|
|
9285
|
+
}
|
|
9286
|
+
const worktreeManager = new WorktreeManager(projectRoot);
|
|
9287
|
+
if (!await worktreeManager.initialize()) {
|
|
9288
|
+
console.warn("[Daemon] EP1051: Failed to initialize worktree manager");
|
|
9289
|
+
return;
|
|
9290
|
+
}
|
|
9291
|
+
for (const task of tasks) {
|
|
9292
|
+
const moduleUid = task.payload.module_uid || task.target_id;
|
|
9293
|
+
console.log(`[Daemon] EP1051: Processing ${task.operation_type} for ${moduleUid} (task ${task.id})`);
|
|
9294
|
+
try {
|
|
9295
|
+
if (task.operation_type === "worktree_cleanup") {
|
|
9296
|
+
const result = await worktreeManager.removeWorktree(moduleUid, true);
|
|
9297
|
+
if (result.success) {
|
|
9298
|
+
console.log(`[Daemon] EP1051: Successfully cleaned up worktree for ${moduleUid}`);
|
|
9299
|
+
await this.reportOperationResult(apiUrl, task.id, "complete");
|
|
9300
|
+
} else {
|
|
9301
|
+
if (result.error?.includes("not found") || result.error?.includes("No worktree found")) {
|
|
9302
|
+
console.log(`[Daemon] EP1051: Worktree ${moduleUid} already removed, marking complete`);
|
|
9303
|
+
await this.reportOperationResult(apiUrl, task.id, "complete");
|
|
9304
|
+
} else {
|
|
9305
|
+
console.warn(`[Daemon] EP1051: Cleanup failed for ${moduleUid}: ${result.error}`);
|
|
9306
|
+
await this.reportOperationResult(apiUrl, task.id, "retry", {
|
|
9307
|
+
code: "OPERATION_ERROR",
|
|
9308
|
+
message: result.error || "Unknown error"
|
|
9309
|
+
});
|
|
9310
|
+
}
|
|
9311
|
+
}
|
|
9312
|
+
} else {
|
|
9313
|
+
console.warn(`[Daemon] EP1051: Unknown operation type: ${task.operation_type}`);
|
|
9314
|
+
await this.reportOperationResult(apiUrl, task.id, "fail", {
|
|
9315
|
+
code: "UNKNOWN_OPERATION_TYPE",
|
|
9316
|
+
message: `Daemon cannot process operation type: ${task.operation_type}`
|
|
9317
|
+
});
|
|
9318
|
+
}
|
|
9319
|
+
} catch (error) {
|
|
9320
|
+
console.error(`[Daemon] EP1051: Error processing operation for ${moduleUid}:`, error.message);
|
|
9321
|
+
await this.reportOperationResult(apiUrl, task.id, "retry", {
|
|
9322
|
+
code: "OPERATION_EXCEPTION",
|
|
9323
|
+
message: error.message
|
|
9324
|
+
});
|
|
9325
|
+
}
|
|
9326
|
+
}
|
|
9327
|
+
console.log("[Daemon] EP1051: Operation reconciliation complete");
|
|
9328
|
+
} catch (error) {
|
|
9329
|
+
console.error("[Daemon] EP1051: Operation reconciliation error:", error instanceof Error ? error.message : error);
|
|
9330
|
+
throw error;
|
|
9331
|
+
}
|
|
9332
|
+
}
|
|
9333
|
+
/**
|
|
9334
|
+
* EP1051: Report background operation result to server
|
|
9335
|
+
*/
|
|
9336
|
+
async reportOperationResult(apiUrl, taskId, action, error) {
|
|
9337
|
+
try {
|
|
9338
|
+
const response = await fetchWithAuth(`${apiUrl}/api/cli/background-ops`, {
|
|
9339
|
+
method: "POST",
|
|
9340
|
+
headers: { "Content-Type": "application/json" },
|
|
9341
|
+
body: JSON.stringify({
|
|
9342
|
+
task_id: taskId,
|
|
9343
|
+
action,
|
|
9344
|
+
error
|
|
9345
|
+
})
|
|
9346
|
+
});
|
|
9347
|
+
if (!response.ok) {
|
|
9348
|
+
console.warn(`[Daemon] EP1051: Failed to report operation result: ${response.status}`);
|
|
9349
|
+
}
|
|
9350
|
+
} catch (err) {
|
|
9351
|
+
console.warn(`[Daemon] EP1051: Error reporting operation result: ${err.message}`);
|
|
9352
|
+
}
|
|
9353
|
+
}
|
|
9232
9354
|
/**
|
|
9233
9355
|
* EP1002: Handle worktree_setup command from server
|
|
9234
9356
|
* This provides a unified setup flow for both local and cloud environments.
|