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.56",
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.