taskplane 0.20.3 → 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.
- package/extensions/taskplane/extension.ts +21 -133
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
):
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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 worker;
|
|
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
|
|
1395
|
-
//
|
|
1396
|
-
let activeWorker:
|
|
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 (
|
|
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
|
|
2205
|
-
if (
|
|
2206
|
-
|
|
2207
|
-
|
|
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
|
-
|
|
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 {
|