episoda 0.2.98 → 0.2.100

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.
@@ -2786,7 +2786,7 @@ var require_package = __commonJS({
2786
2786
  "package.json"(exports2, module2) {
2787
2787
  module2.exports = {
2788
2788
  name: "episoda",
2789
- version: "0.2.98",
2789
+ version: "0.2.100",
2790
2790
  description: "CLI tool for Episoda local development workflow orchestration",
2791
2791
  main: "dist/index.js",
2792
2792
  types: "dist/index.d.ts",
@@ -8485,8 +8485,10 @@ ${message}`;
8485
8485
  "--output-format",
8486
8486
  "stream-json",
8487
8487
  // Structured streaming output
8488
- "--verbose"
8488
+ "--verbose",
8489
8489
  // Required for stream-json with --print
8490
+ "--include-partial-messages"
8491
+ // EP1191: Enable incremental streaming chunks
8490
8492
  ];
8491
8493
  if (session.credentials.preferredModel) {
8492
8494
  args.push("--model", session.credentials.preferredModel);
@@ -8644,14 +8646,25 @@ ${message}`;
8644
8646
  });
8645
8647
  let stdoutBuffer = "";
8646
8648
  let extractedSessionId;
8649
+ let stdoutEventCount = 0;
8650
+ let chunksSent = 0;
8651
+ const streamStartTime = Date.now();
8647
8652
  childProcess.stdout?.on("data", (data) => {
8648
- stdoutBuffer += data.toString();
8653
+ const rawData = data.toString();
8654
+ stdoutBuffer += rawData;
8655
+ stdoutEventCount++;
8656
+ if (stdoutEventCount <= 5) {
8657
+ console.log(`[AgentManager] EP1191: stdout event ${stdoutEventCount} - ${rawData.length} chars: ${rawData.substring(0, 200)}${rawData.length > 200 ? "..." : ""}`);
8658
+ }
8649
8659
  const lines = stdoutBuffer.split("\n");
8650
8660
  stdoutBuffer = lines.pop() || "";
8651
8661
  for (const line of lines) {
8652
8662
  if (!line.trim()) continue;
8653
8663
  try {
8654
8664
  const parsed = JSON.parse(line);
8665
+ if (stdoutEventCount <= 10 || chunksSent === 0) {
8666
+ console.log(`[AgentManager] EP1191: Parsed event type: ${parsed.type}`);
8667
+ }
8655
8668
  if (provider === "codex") {
8656
8669
  switch (parsed.type) {
8657
8670
  case "thread.started":
@@ -8687,6 +8700,10 @@ ${message}`;
8687
8700
  if (parsed.message?.content) {
8688
8701
  for (const block of parsed.message.content) {
8689
8702
  if (block.type === "text" && block.text) {
8703
+ chunksSent++;
8704
+ if (chunksSent <= 5) {
8705
+ console.log(`[AgentManager] EP1191: Sending chunk ${chunksSent} via assistant event - ${block.text.length} chars`);
8706
+ }
8690
8707
  onChunk(block.text);
8691
8708
  }
8692
8709
  }
@@ -8694,6 +8711,10 @@ ${message}`;
8694
8711
  break;
8695
8712
  case "content_block_delta":
8696
8713
  if (parsed.delta?.text) {
8714
+ chunksSent++;
8715
+ if (chunksSent <= 5) {
8716
+ console.log(`[AgentManager] EP1191: Sending chunk ${chunksSent} via content_block_delta - ${parsed.delta.text.length} chars`);
8717
+ }
8697
8718
  onChunk(parsed.delta.text);
8698
8719
  }
8699
8720
  break;
@@ -8735,7 +8756,8 @@ ${message}`;
8735
8756
  stderrBuffer += data.toString();
8736
8757
  });
8737
8758
  childProcess.on("exit", (code, signal) => {
8738
- console.log(`[AgentManager] ${provider} CLI exited for session ${sessionId}: code=${code}, signal=${signal}`);
8759
+ const duration = Date.now() - streamStartTime;
8760
+ console.log(`[AgentManager] EP1191: ${provider} CLI exited for session ${sessionId}: code=${code}, signal=${signal}, duration=${duration}ms, stdoutEvents=${stdoutEventCount}, chunksSent=${chunksSent}`);
8739
8761
  this.processes.delete(sessionId);
8740
8762
  this.removePidFile(sessionId);
8741
8763
  if (code === 0) {
@@ -10143,8 +10165,14 @@ var Daemon = class _Daemon {
10143
10165
  const cmd = message.command;
10144
10166
  console.log(`[Daemon] EP912: Received agent command for ${projectId}:`, cmd.action);
10145
10167
  client.updateActivity();
10168
+ let daemonChunkCount = 0;
10169
+ const daemonStreamStart = Date.now();
10146
10170
  const createStreamingCallbacks = (sessionId, commandId) => ({
10147
10171
  onChunk: async (chunk) => {
10172
+ daemonChunkCount++;
10173
+ if (daemonChunkCount <= 5) {
10174
+ console.log(`[Daemon] EP1191: Forwarding chunk ${daemonChunkCount} via WebSocket - ${chunk.length} chars`);
10175
+ }
10148
10176
  try {
10149
10177
  await client.send({
10150
10178
  type: "agent_result",
@@ -10156,6 +10184,8 @@ var Daemon = class _Daemon {
10156
10184
  }
10157
10185
  },
10158
10186
  onComplete: async (claudeSessionId) => {
10187
+ const duration = Date.now() - daemonStreamStart;
10188
+ console.log(`[Daemon] EP1191: Stream complete - ${daemonChunkCount} chunks forwarded in ${duration}ms`);
10159
10189
  try {
10160
10190
  await client.send({
10161
10191
  type: "agent_result",
@@ -10167,6 +10197,8 @@ var Daemon = class _Daemon {
10167
10197
  }
10168
10198
  },
10169
10199
  onError: async (error) => {
10200
+ const duration = Date.now() - daemonStreamStart;
10201
+ console.log(`[Daemon] EP1191: Stream error after ${daemonChunkCount} chunks in ${duration}ms - ${error}`);
10170
10202
  try {
10171
10203
  await client.send({
10172
10204
  type: "agent_result",
@@ -10924,130 +10956,8 @@ var Daemon = class _Daemon {
10924
10956
  }
10925
10957
  }
10926
10958
  // EP1025: Removed cleanupModuleWorktree - was dead code (never called).
10927
- // Worktree cleanup is handled by server's cleanupWorktreeAsync which sends
10928
- // worktree_remove command via WebSocket, handled by GitExecutor.executeWorktreeRemove.
10929
- /**
10930
- * EP1047: Process pending cleanup queue entries for this machine
10931
- *
10932
- * @deprecated EP1091: No longer called on connect. Server-side cron now processes
10933
- * the cleanup queue and sends WebSocket commands to connected daemons. This is
10934
- * more reliable than daemon-side polling since it works even if daemon stays connected.
10935
- *
10936
- * Kept for potential manual invocation or debugging purposes.
10937
- *
10938
- * Flow:
10939
- * 1. Query server for pending cleanup tasks for this machine
10940
- * 2. For each task, attempt worktree removal
10941
- * 3. Report success/failure back to server
10942
- */
10943
- async reconcilePendingCleanups(projectId, projectPath) {
10944
- if (!this.machineUuid) {
10945
- console.log("[Daemon] EP1047: Cannot reconcile cleanups - machineUuid not available yet");
10946
- return;
10947
- }
10948
- console.log(`[Daemon] EP1047: Checking for pending cleanup tasks for machine ${this.machineUuid}`);
10949
- try {
10950
- const config = await (0, import_core13.loadConfig)();
10951
- if (!config) {
10952
- console.log("[Daemon] EP1047: No config loaded, skipping cleanup reconciliation");
10953
- return;
10954
- }
10955
- const apiUrl = config.api_url || "https://episoda.dev";
10956
- const controller = new AbortController();
10957
- const timeoutId = setTimeout(() => controller.abort(), 1e4);
10958
- let response;
10959
- try {
10960
- response = await fetchWithAuth(
10961
- `${apiUrl}/api/cli/background-ops?machine_id=${this.machineUuid}`,
10962
- { signal: controller.signal }
10963
- );
10964
- } finally {
10965
- clearTimeout(timeoutId);
10966
- }
10967
- if (!response.ok) {
10968
- console.warn(`[Daemon] EP1051: Failed to fetch background operations: ${response.status}`);
10969
- return;
10970
- }
10971
- const data = await response.json();
10972
- const tasks = data.tasks || [];
10973
- if (tasks.length === 0) {
10974
- console.log("[Daemon] EP1051: No pending background operations");
10975
- return;
10976
- }
10977
- console.log(`[Daemon] EP1051: Processing ${tasks.length} pending operation(s)`);
10978
- const projectRoot = await findProjectRoot(projectPath);
10979
- if (!projectRoot) {
10980
- console.warn("[Daemon] EP1051: Could not find project root, skipping operation reconciliation");
10981
- return;
10982
- }
10983
- const worktreeManager = new WorktreeManager(projectRoot);
10984
- if (!await worktreeManager.initialize()) {
10985
- console.warn("[Daemon] EP1051: Failed to initialize worktree manager");
10986
- return;
10987
- }
10988
- for (const task of tasks) {
10989
- const moduleUid = task.payload.module_uid || task.target_id;
10990
- console.log(`[Daemon] EP1051: Processing ${task.operation_type} for ${moduleUid} (task ${task.id})`);
10991
- try {
10992
- if (task.operation_type === "worktree_cleanup") {
10993
- const result = await worktreeManager.removeWorktree(moduleUid, true);
10994
- if (result.success) {
10995
- console.log(`[Daemon] EP1051: Successfully cleaned up worktree for ${moduleUid}`);
10996
- await this.reportOperationResult(apiUrl, task.id, "complete");
10997
- } else {
10998
- if (result.error?.includes("not found") || result.error?.includes("No worktree found")) {
10999
- console.log(`[Daemon] EP1051: Worktree ${moduleUid} already removed, marking complete`);
11000
- await this.reportOperationResult(apiUrl, task.id, "complete");
11001
- } else {
11002
- console.warn(`[Daemon] EP1051: Cleanup failed for ${moduleUid}: ${result.error}`);
11003
- await this.reportOperationResult(apiUrl, task.id, "retry", {
11004
- code: "OPERATION_ERROR",
11005
- message: result.error || "Unknown error"
11006
- });
11007
- }
11008
- }
11009
- } else {
11010
- console.warn(`[Daemon] EP1051: Unknown operation type: ${task.operation_type}`);
11011
- await this.reportOperationResult(apiUrl, task.id, "fail", {
11012
- code: "UNKNOWN_OPERATION_TYPE",
11013
- message: `Daemon cannot process operation type: ${task.operation_type}`
11014
- });
11015
- }
11016
- } catch (error) {
11017
- console.error(`[Daemon] EP1051: Error processing operation for ${moduleUid}:`, error.message);
11018
- await this.reportOperationResult(apiUrl, task.id, "retry", {
11019
- code: "OPERATION_EXCEPTION",
11020
- message: error.message
11021
- });
11022
- }
11023
- }
11024
- console.log("[Daemon] EP1051: Operation reconciliation complete");
11025
- } catch (error) {
11026
- console.error("[Daemon] EP1051: Operation reconciliation error:", error instanceof Error ? error.message : error);
11027
- throw error;
11028
- }
11029
- }
11030
- /**
11031
- * EP1051: Report background operation result to server
11032
- */
11033
- async reportOperationResult(apiUrl, taskId, action, error) {
11034
- try {
11035
- const response = await fetchWithAuth(`${apiUrl}/api/cli/background-ops`, {
11036
- method: "POST",
11037
- headers: { "Content-Type": "application/json" },
11038
- body: JSON.stringify({
11039
- task_id: taskId,
11040
- action,
11041
- error
11042
- })
11043
- });
11044
- if (!response.ok) {
11045
- console.warn(`[Daemon] EP1051: Failed to report operation result: ${response.status}`);
11046
- }
11047
- } catch (err) {
11048
- console.warn(`[Daemon] EP1051: Error reporting operation result: ${err.message}`);
11049
- }
11050
- }
10959
+ // EP1188: Background ops queue removed - worktree cleanup now handled by Inngest events
10960
+ // (worktree/cleanup) which send WebSocket commands to connected daemons via ws-proxy.
11051
10961
  /**
11052
10962
  * EP1002: Handle worktree_setup command from server
11053
10963
  * This provides a unified setup flow for both local and cloud environments.