taskplane 0.24.24 → 0.24.26
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/bin/taskplane.mjs +5 -4
- package/extensions/taskplane/engine.ts +39 -0
- package/package.json +1 -1
package/bin/taskplane.mjs
CHANGED
|
@@ -1747,9 +1747,9 @@ async function cmdInit(args) {
|
|
|
1747
1747
|
} catch {}
|
|
1748
1748
|
return null;
|
|
1749
1749
|
})();
|
|
1750
|
-
const workspaceTasksRoot = existingWorkspaceJson?.routing?.tasks_root
|
|
1750
|
+
const workspaceTasksRoot = (existingWorkspaceJson?.routing?.tasks_root
|
|
1751
1751
|
|| existingRootYaml?.routing?.tasks_root
|
|
1752
|
-
|| "taskplane-tasks";
|
|
1752
|
+
|| "taskplane-tasks").replace(/\\/g, "/");
|
|
1753
1753
|
const workspaceDefaultRepo = existingWorkspaceJson?.routing?.default_repo
|
|
1754
1754
|
|| existingRootYaml?.routing?.default_repo
|
|
1755
1755
|
|| configRepo;
|
|
@@ -2285,7 +2285,7 @@ function getPresetVars(preset, projectRoot, tasksRootOverride = null) {
|
|
|
2285
2285
|
max_lanes: 3,
|
|
2286
2286
|
worktree_prefix: `${slug}-wt`,
|
|
2287
2287
|
session_prefix: `${slug}-orch`,
|
|
2288
|
-
tasks_root: tasksRootOverride || "taskplane-tasks",
|
|
2288
|
+
tasks_root: (tasksRootOverride || "taskplane-tasks").replace(/\\/g, "/"),
|
|
2289
2289
|
default_area: "general",
|
|
2290
2290
|
default_prefix: "TP",
|
|
2291
2291
|
test_cmd,
|
|
@@ -2302,7 +2302,8 @@ async function getInteractiveVars(projectRoot, tasksRootOverride = null) {
|
|
|
2302
2302
|
const project_name = await ask("Project name", dirName);
|
|
2303
2303
|
const maxLanesInput = await ask("Max parallel lanes", "3");
|
|
2304
2304
|
const max_lanes = parseInt(maxLanesInput, 10) || 3;
|
|
2305
|
-
const
|
|
2305
|
+
const tasks_root_raw = tasksRootOverride || await ask("Tasks directory", "taskplane-tasks");
|
|
2306
|
+
const tasks_root = tasks_root_raw.trim().replace(/\\/g, "/").replace(/^\.\//g, "").replace(/\/+$/g, "");
|
|
2306
2307
|
const default_area = await ask("Default area name", "general");
|
|
2307
2308
|
const default_prefix = await ask("Task ID prefix", "TP");
|
|
2308
2309
|
const test_cmd = await ask("Test command (agents run this to verify work — blank to skip)", detected.test || "");
|
|
@@ -2908,6 +2908,45 @@ export async function executeOrchBatch(
|
|
|
2908
2908
|
return hasSucceeded && hasHardFailure;
|
|
2909
2909
|
});
|
|
2910
2910
|
|
|
2911
|
+
// ── Safety net: auto-commit uncommitted artifacts before merge ──
|
|
2912
|
+
// Workers should commit at step boundaries, but may leave uncommitted
|
|
2913
|
+
// files (especially for level-0 / fast tasks). Check each merge-candidate
|
|
2914
|
+
// lane worktree and auto-commit any remaining changes so they're included
|
|
2915
|
+
// in the merge. Skips lanes with only failed/stalled tasks (no merge).
|
|
2916
|
+
for (const lane of waveResult.allocatedLanes) {
|
|
2917
|
+
if (!lane.worktreePath || !existsSync(lane.worktreePath)) continue;
|
|
2918
|
+
// Only check lanes that have at least one succeeded task (merge candidates)
|
|
2919
|
+
const laneOutcome = laneOutcomeByNumber.get(lane.laneNumber);
|
|
2920
|
+
if (!laneOutcome) continue;
|
|
2921
|
+
const hasSucceeded = laneOutcome.tasks.some(t => t.status === "succeeded");
|
|
2922
|
+
if (!hasSucceeded) continue;
|
|
2923
|
+
try {
|
|
2924
|
+
const addResult = runGit(["add", "-A"], lane.worktreePath);
|
|
2925
|
+
if (!addResult.ok) {
|
|
2926
|
+
execLog("merge", batchState.batchId, `safety-net: git add failed in ${lane.laneId}`, { stderr: addResult.stderr });
|
|
2927
|
+
continue;
|
|
2928
|
+
}
|
|
2929
|
+
const statusResult = runGit(["status", "--porcelain"], lane.worktreePath);
|
|
2930
|
+
if (!statusResult.ok || !statusResult.stdout?.trim()) continue;
|
|
2931
|
+
const taskIds = lane.tasks.map(t => t.taskId).join(", ");
|
|
2932
|
+
const commitResult = runGit(
|
|
2933
|
+
["commit", "-m", `safety-net: uncommitted artifacts for ${taskIds}`],
|
|
2934
|
+
lane.worktreePath,
|
|
2935
|
+
);
|
|
2936
|
+
if (commitResult.ok) {
|
|
2937
|
+
execLog("merge", batchState.batchId, `safety-net: auto-committed uncommitted files in ${lane.laneId}`, {
|
|
2938
|
+
worktree: lane.worktreePath,
|
|
2939
|
+
taskIds,
|
|
2940
|
+
files: statusResult.stdout.trim(),
|
|
2941
|
+
});
|
|
2942
|
+
} else {
|
|
2943
|
+
execLog("merge", batchState.batchId, `safety-net: commit failed in ${lane.laneId}`, { stderr: commitResult.stderr });
|
|
2944
|
+
}
|
|
2945
|
+
} catch (err: any) {
|
|
2946
|
+
execLog("merge", batchState.batchId, `safety-net: unexpected error in ${lane.laneId}`, { error: err?.message });
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2911
2950
|
if (succeededSegmentTaskIdsForMerge.length > 0) {
|
|
2912
2951
|
const mergeableLaneCount = waveResult.allocatedLanes.filter(lane => {
|
|
2913
2952
|
const outcome = laneOutcomeByNumber.get(lane.laneNumber);
|