taskplane 0.5.7 → 0.5.8

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.
@@ -2,8 +2,8 @@
2
2
  * Main batch execution engine
3
3
  * @module orch/engine
4
4
  */
5
- import { existsSync, readFileSync, readdirSync, unlinkSync } from "fs";
6
- import { dirname, join, resolve } from "path";
5
+ import { readFileSync, readdirSync, unlinkSync } from "fs";
6
+ import { join, resolve } from "path";
7
7
 
8
8
  import { formatDiscoveryResults, runDiscovery } from "./discovery.ts";
9
9
  import { execLog, executeWave, tmuxKillSession } from "./execution.ts";
@@ -364,16 +364,6 @@ export async function executeOrchBatch(
364
364
  }
365
365
  }
366
366
 
367
- // ── Workspace mode: commit task artifacts to task-area repos ─
368
- // In workspace mode, workers write .DONE and STATUS.md to the
369
- // canonical task folder (e.g., shared-libs/task-management/...) via
370
- // absolute paths, not to the lane worktree. These changes land as
371
- // uncommitted modifications in the task-area repo's working tree.
372
- // Commit them before the merge step so they appear in the orch branch.
373
- if (workspaceConfig && waveResult.succeededTaskIds.length > 0) {
374
- commitWorkspaceTaskArtifacts(discoveryRef, workspaceRoot ?? repoRoot, waveIdx + 1, batchState.batchId);
375
- }
376
-
377
367
  // ── Wave Merge ───────────────────────────────────────────
378
368
  // Only merge if there are succeeded tasks in this wave
379
369
  let mergeResult: MergeWaveResult | null = null;
@@ -882,78 +872,5 @@ export async function executeOrchBatch(
882
872
  }
883
873
 
884
874
 
885
- // ── Workspace Task Artifact Commit ───────────────────────────────────
886
-
887
- /**
888
- * In workspace mode, commit task artifacts (.DONE, STATUS.md) that workers
889
- * wrote to the canonical task folder in the task-area repo.
890
- *
891
- * Workers write to absolute paths (e.g., shared-libs/task-management/.../TP-002/.DONE)
892
- * which land as uncommitted changes in the task-area repo's working tree.
893
- * This function finds all task-area repos with dirty task files and commits them
894
- * so they appear in the lane branches and merge correctly.
895
- *
896
- * Best-effort: failures are logged but don't block the batch.
897
- */
898
- function commitWorkspaceTaskArtifacts(
899
- discovery: DiscoveryResult | null,
900
- workspaceRoot: string,
901
- waveIndex: number,
902
- batchId: string,
903
- ): void {
904
- if (!discovery) return;
905
-
906
- // Collect unique repo roots that contain task folders
907
- const repoRootsWithTasks = new Set<string>();
908
- for (const [, task] of discovery.pending) {
909
- const taskFolder = resolve(task.taskFolder);
910
- // Walk up to find the git repo root for this task folder
911
- const gitResult = runGit(["rev-parse", "--show-toplevel"], dirname(taskFolder));
912
- if (gitResult.ok) {
913
- repoRootsWithTasks.add(gitResult.stdout.trim().replace(/\\/g, "/"));
914
- }
915
- }
916
-
917
- for (const taskRepoRoot of repoRootsWithTasks) {
918
- // Check for uncommitted changes
919
- const statusResult = runGit(["status", "--porcelain", "--", "task-management/"], taskRepoRoot);
920
- if (!statusResult.ok) {
921
- // Try without path filter (task area might have different name)
922
- const statusAll = runGit(["status", "--porcelain"], taskRepoRoot);
923
- if (!statusAll.ok || !statusAll.stdout.trim()) continue;
924
- }
925
- if (statusResult.ok && !statusResult.stdout.trim()) continue;
926
-
927
- // Stage task artifacts (only .DONE and STATUS.md files)
928
- const lines = (statusResult.stdout || "").split("\n").filter(l => l.trim());
929
- let hasTaskArtifacts = false;
930
- for (const line of lines) {
931
- const file = line.slice(3).trim();
932
- if (file.endsWith(".DONE") || file.endsWith("STATUS.md")) {
933
- const addResult = runGit(["add", file], taskRepoRoot);
934
- if (addResult.ok) hasTaskArtifacts = true;
935
- }
936
- }
937
-
938
- if (!hasTaskArtifacts) continue;
939
-
940
- // Commit
941
- const commitResult = runGit(
942
- ["commit", "-m", `checkpoint: wave ${waveIndex} task artifacts (.DONE, STATUS.md)`],
943
- taskRepoRoot,
944
- );
945
- if (commitResult.ok) {
946
- execLog("batch", batchId, `committed workspace task artifacts`, {
947
- repoRoot: taskRepoRoot,
948
- wave: waveIndex,
949
- });
950
- } else if (!commitResult.stderr.includes("nothing to commit")) {
951
- execLog("batch", batchId, `workspace task artifact commit failed (non-fatal): ${commitResult.stderr.slice(0, 200)}`, {
952
- repoRoot: taskRepoRoot,
953
- });
954
- }
955
- }
956
- }
957
-
958
875
  // ── Dashboard Widget (Step 6) ────────────────────────────────────────
959
876
 
@@ -2,9 +2,9 @@
2
2
  * Merge orchestration, merge agents, merge worktree
3
3
  * @module orch/merge
4
4
  */
5
- import { readFileSync, writeFileSync, existsSync, unlinkSync } from "fs";
5
+ import { readFileSync, writeFileSync, existsSync, unlinkSync, copyFileSync, mkdirSync } from "fs";
6
6
  import { spawnSync } from "child_process";
7
- import { join } from "path";
7
+ import { join, dirname } from "path";
8
8
 
9
9
  import { buildLaneEnvVars, buildTmuxSpawnArgs, execLog, tmuxHasSession, tmuxKillSession, toTmuxPath } from "./execution.ts";
10
10
  import { resolveOperatorId } from "./naming.ts";
@@ -755,6 +755,55 @@ export function mergeWave(
755
755
  }
756
756
  }
757
757
 
758
+ // ── Stage workspace task artifacts into merge worktree ──────────
759
+ // In workspace mode, workers write .DONE and STATUS.md to the canonical
760
+ // task folder (e.g., shared-libs/task-management/...) which is the repo's
761
+ // checked-out working tree (develop). These files need to be on the orch
762
+ // branch, not develop. Copy them into the merge worktree (which is on the
763
+ // orch branch's temp) and commit, so they're included in the update-ref.
764
+ if (mergeWorkDir) {
765
+ const statusResult = spawnSync("git", ["status", "--porcelain"], { cwd: repoRoot, encoding: "utf-8" });
766
+ if (statusResult.status === 0 && statusResult.stdout) {
767
+ const lines = statusResult.stdout.split("\n").filter((l: string) => l.trim());
768
+ const artifactFiles = lines
769
+ .map((l: string) => l.slice(3).trim())
770
+ .filter((f: string) => f.endsWith(".DONE") || f.endsWith("STATUS.md"));
771
+
772
+ if (artifactFiles.length > 0) {
773
+ let staged = 0;
774
+ for (const file of artifactFiles) {
775
+ const srcPath = join(repoRoot, file);
776
+ const destPath = join(mergeWorkDir, file);
777
+ try {
778
+ if (existsSync(srcPath)) {
779
+ mkdirSync(dirname(destPath), { recursive: true });
780
+ copyFileSync(srcPath, destPath);
781
+ spawnSync("git", ["add", file], { cwd: mergeWorkDir });
782
+ staged++;
783
+ }
784
+ } catch { /* best effort */ }
785
+ }
786
+ if (staged > 0) {
787
+ spawnSync("git", ["commit", "-m", `checkpoint: wave ${waveIndex} task artifacts (.DONE, STATUS.md)`], { cwd: mergeWorkDir });
788
+ execLog("merge", `W${waveIndex}`, `committed ${staged} task artifact(s) to merge worktree`);
789
+
790
+ // Restore the repo's working tree — remove the artifacts from develop's working tree
791
+ // so they don't cause conflicts on /orch-integrate
792
+ for (const file of artifactFiles) {
793
+ spawnSync("git", ["checkout", "--", file], { cwd: repoRoot });
794
+ }
795
+ // Also remove any untracked .DONE files
796
+ for (const file of artifactFiles) {
797
+ if (file.endsWith(".DONE")) {
798
+ const srcPath = join(repoRoot, file);
799
+ try { if (existsSync(srcPath)) unlinkSync(srcPath); } catch { /* best effort */ }
800
+ }
801
+ }
802
+ }
803
+ }
804
+ }
805
+ }
806
+
758
807
  // ── Update target branch ref and clean up merge worktree ────────
759
808
  const anySuccess = laneResults.some(
760
809
  r => r.result?.status === "SUCCESS" || r.result?.status === "CONFLICT_RESOLVED",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",