taskplane 0.20.4 → 0.20.5

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.
@@ -5,7 +5,8 @@ import { execSync, execFileSync } from "child_process";
5
5
  import { writeFileSync, unlinkSync, mkdirSync, existsSync, readdirSync } from "fs";
6
6
  import { join, dirname } from "path";
7
7
  import { fileURLToPath } from "url";
8
- import { fork, type ChildProcess } from "child_process";
8
+ // child_process.fork() disabled Node v25 blocks .ts in node_modules.
9
+ // Re-enable when engine-worker ships as pre-compiled .js bundle.
9
10
 
10
11
  // Direct imports — avoid barrel (index.ts) to prevent loading the entire module graph.
11
12
  // Each import targets the specific module where the symbol is defined.
@@ -935,22 +936,14 @@ export function startBatchInWorker(
935
936
  updateWidget: () => void,
936
937
  onMonitorUpdate?: (state: import("./types.ts").MonitorState) => void,
937
938
  onTerminal?: () => void,
938
- ): ChildProcess | null {
939
- const workerPath = resolveEngineWorkerPath();
940
-
941
- let child: ChildProcess;
942
- try {
943
- child = fork(workerPath, [], {
944
- execArgv: ["--experimental-transform-types", "--no-warnings"],
945
- env: { ...process.env, TASKPLANE_ENGINE_FORK: "1" },
946
- serialization: "advanced",
947
- });
948
- } catch (spawnErr: unknown) {
949
- const errMsg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
950
- ctx.ui.notify(
951
- `⚠️ Engine process spawn failed: ${errMsg}\n Falling back to main-thread execution.`,
952
- "warning",
953
- );
939
+ ): null {
940
+ // ── Main-thread execution (TP-071 fork disabled) ─────────────
941
+ // Node v25 blocks .ts files inside node_modules regardless of
942
+ // --experimental-strip-types or --experimental-transform-types.
943
+ // Until we ship a pre-compiled engine bundle, the engine runs on
944
+ // the main thread via startBatchAsync(). The supervisor stays
945
+ // responsive because engine work is async I/O (tmux, git, fs).
946
+ {
954
947
  // Construct fallback engine function from workerData and run on main thread
955
948
  const wsConfig = wkData.workspaceConfig
956
949
  ? deserializeWorkspaceConfig(wkData.workspaceConfig)
@@ -983,98 +976,6 @@ export function startBatchInWorker(
983
976
  startBatchAsync(fallbackFn, batchState, ctx, updateWidget, onTerminal);
984
977
  return null;
985
978
  }
986
-
987
- // Send workerData as first IPC message (fork doesn't have workerData)
988
- child.send({ type: "init", data: wkData });
989
-
990
- // Terminal settlement guard (R001 §3): ensures onTerminal fires at most once.
991
- // The child can emit error + complete messages, followed by exit event.
992
- // Without this guard, summary/integration/supervisor flows would fire multiple times.
993
- let settled = false;
994
- const settle = () => {
995
- if (settled) return;
996
- settled = true;
997
- onTerminal?.();
998
- };
999
-
1000
- child.on("message", (msg: WorkerToMainMessage) => {
1001
- switch (msg.type) {
1002
- case "notify":
1003
- ctx.ui.notify(msg.msg, msg.level);
1004
- updateWidget();
1005
- break;
1006
-
1007
- case "monitor-update":
1008
- onMonitorUpdate?.(msg.state);
1009
- break;
1010
-
1011
- case "engine-event":
1012
- // Engine events are already persisted to events.jsonl by the child.
1013
- // No additional handling needed on the main thread.
1014
- break;
1015
-
1016
- case "state-sync":
1017
- applySerializedState(batchState, msg.state);
1018
- updateWidget();
1019
- break;
1020
-
1021
- case "complete":
1022
- applySerializedState(batchState, msg.state);
1023
- updateWidget();
1024
- settle();
1025
- break;
1026
-
1027
- case "error":
1028
- if (batchState.phase !== "completed" && batchState.phase !== "failed") {
1029
- batchState.phase = "failed";
1030
- batchState.endedAt = Date.now();
1031
- batchState.errors.push(`Unhandled engine error: ${msg.message}`);
1032
- }
1033
- ctx.ui.notify(
1034
- `❌ Engine crashed with unhandled error: ${msg.message}\n` +
1035
- ` Batch ${batchState.batchId} marked as failed.`,
1036
- "error",
1037
- );
1038
- updateWidget();
1039
- break;
1040
- }
1041
- });
1042
-
1043
- child.on("error", (err: Error) => {
1044
- // Child process encountered an error
1045
- if (batchState.phase !== "completed" && batchState.phase !== "failed") {
1046
- batchState.phase = "failed";
1047
- batchState.endedAt = Date.now();
1048
- batchState.errors.push(`Engine process error: ${err.message}`);
1049
- }
1050
- ctx.ui.notify(
1051
- `❌ Engine process error: ${err.message}\n` +
1052
- ` Batch ${batchState.batchId} marked as failed.`,
1053
- "error",
1054
- );
1055
- updateWidget();
1056
- settle();
1057
- });
1058
-
1059
- child.on("exit", (code: number | null) => {
1060
- if (code !== 0 && !settled) {
1061
- // Non-zero exit that wasn't handled by 'error' or 'complete'
1062
- if (batchState.phase !== "completed" && batchState.phase !== "failed") {
1063
- batchState.phase = "failed";
1064
- batchState.endedAt = Date.now();
1065
- batchState.errors.push(`Engine process exited with code ${code}`);
1066
- }
1067
- ctx.ui.notify(
1068
- `❌ Engine process exited unexpectedly (code ${code}).`,
1069
- "error",
1070
- );
1071
- updateWidget();
1072
- }
1073
- // Always settle on exit — ensures cleanup runs even on clean exit
1074
- settle();
1075
- });
1076
-
1077
- return child;
1078
979
  }
1079
980
 
1080
981
  // ── TP-043 R002-2: Integration Executor Builder ─────────────────────
@@ -1391,9 +1292,9 @@ export default function (pi: ExtensionAPI) {
1391
1292
  let orchWidgetCtx: ExtensionContext | undefined;
1392
1293
  let latestMonitorState: MonitorState | null = null;
1393
1294
 
1394
- // ── TP-071: Active engine child process ──────────────────────────
1395
- // Tracked so pause/abort can send control messages to the engine.
1396
- let activeWorker: ChildProcess | null = null;
1295
+ // ── TP-071: Active engine handle (currently unused — fork disabled) ──
1296
+ // Will be restored when engine-worker ships as pre-compiled .js bundle.
1297
+ let activeWorker: null = null;
1397
1298
 
1398
1299
  // ── Supervisor State (TP-041) ────────────────────────────────────
1399
1300
  let supervisorState = freshSupervisorState();
@@ -2010,8 +1911,8 @@ export default function (pi: ExtensionAPI) {
2010
1911
  return ORCH_MESSAGES.pauseAlreadyPaused(orchBatchState.batchId);
2011
1912
  }
2012
1913
  orchBatchState.pauseSignal.paused = true;
2013
- // TP-071: Forward pause to engine process (its pauseSignal is separate)
2014
- activeWorker?.send({ type: "pause" });
1914
+ // TP-071: Forward pause to engine process (disabled fork not active)
1915
+ // activeWorker?.send({ type: "pause" });
2015
1916
  updateOrchWidget();
2016
1917
  return ORCH_MESSAGES.pauseActivated(orchBatchState.batchId);
2017
1918
  }
@@ -2201,16 +2102,10 @@ export default function (pi: ExtensionAPI) {
2201
2102
  orchBatchState.pauseSignal.paused = true;
2202
2103
  messages.push(" ✓ Pause signal set on in-memory batch state");
2203
2104
  }
2204
- // TP-071: Forward pause to engine and kill on hard abort
2205
- if (activeWorker) {
2206
- activeWorker.send({ type: "pause" });
2207
- if (hard) {
2208
- activeWorker.kill();
2209
- activeWorker = null;
2210
- messages.push(" ✓ Engine process killed (hard abort)");
2211
- } else {
2212
- messages.push(" ✓ Pause signal forwarded to engine process");
2213
- }
2105
+ // TP-071: Forward pause to engine (disabled fork not active)
2106
+ if (false as boolean) {
2107
+ // Will be restored when engine-worker ships as pre-compiled .js bundle
2108
+ messages.push(" ✓ Pause signal forwarded to engine process");
2214
2109
  }
2215
2110
 
2216
2111
  // Step 3: Check what we're aborting
@@ -3287,15 +3182,8 @@ export default function (pi: ExtensionAPI) {
3287
3182
  // Ensure supervisor lockfile/heartbeat are cleaned up on normal session exit.
3288
3183
  // This avoids leaving a live-looking lock when the process exits cleanly.
3289
3184
  pi.on("session_end", async () => {
3290
- // TP-071: Kill engine process on session exit
3291
- if (activeWorker) {
3292
- try {
3293
- activeWorker.kill();
3294
- activeWorker = null;
3295
- } catch {
3296
- // Best effort — process may already be dead
3297
- }
3298
- }
3185
+ // TP-071: Kill engine process on session exit (disabled — fork not active)
3186
+ // Will be restored when engine-worker ships as pre-compiled .js bundle
3299
3187
  try {
3300
3188
  await deactivateSupervisor(pi, supervisorState);
3301
3189
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.20.4",
3
+ "version": "0.20.5",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",