taskplane 0.2.7 → 0.2.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.
@@ -76,11 +76,59 @@ function resolveTaskFolder(task, state) {
76
76
  const laneNum = task.laneNumber;
77
77
  const lane = (state?.lanes || []).find((l) => l.laneNumber === laneNum);
78
78
  if (!lane || !lane.worktreePath) return task.taskFolder;
79
+
80
+ // In workspace mode, the worktree is inside a specific repo, not the workspace root.
81
+ // The task folder path needs to be made relative to the repo root (parent of the worktree),
82
+ // not the workspace root. Detect this by finding the repo root from the worktree path.
79
83
  const taskFolderAbs = path.resolve(task.taskFolder);
84
+ const worktreeAbs = path.resolve(lane.worktreePath);
85
+
86
+ // Try to find the repo root: walk up from the worktree path looking for which
87
+ // ancestor is a prefix of the task folder. The worktree is at <repoRoot>/.worktrees/<name>
88
+ // or a sibling, so the repo root is typically 2 levels up from a subdirectory worktree.
89
+ // Heuristic: find the longest common ancestor between taskFolder and worktree's repo root.
80
90
  const repoRootAbs = path.resolve(REPO_ROOT);
81
- const rel = path.relative(repoRootAbs, taskFolderAbs);
91
+
92
+ // First try: relative to workspace root (works in repo mode where workspace = repo)
93
+ let rel = path.relative(repoRootAbs, taskFolderAbs);
82
94
  if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) return task.taskFolder;
83
- return path.join(lane.worktreePath, rel);
95
+
96
+ // Check if joining with worktree produces a valid path
97
+ const candidate = path.join(worktreeAbs, rel);
98
+ try {
99
+ if (fs.existsSync(candidate)) return candidate;
100
+ } catch { /* fall through */ }
101
+
102
+ // Second try: the worktree is inside a repo subdirectory of the workspace root.
103
+ // Strip the repo prefix from the task folder path to get the repo-relative path.
104
+ // e.g., taskFolder = "workspace/platform-docs/task-mgmt/DOC-001/"
105
+ // worktree = "workspace/platform-docs/.worktrees/wt-1/"
106
+ // repo-relative = "task-mgmt/DOC-001/"
107
+ // Find the repo by checking which workspace repo path is a prefix of the task folder.
108
+ const repoRoots = [];
109
+ try {
110
+ const stateMode = state.mode;
111
+ if (stateMode === "workspace" && state.repos) {
112
+ for (const r of state.repos) repoRoots.push(path.resolve(r.path));
113
+ }
114
+ } catch { /* no repo info in state */ }
115
+
116
+ // Also try inferring repo root from worktree path pattern:
117
+ // .worktrees/<name> → parent is repo root; sibling worktrees → shared parent
118
+ const worktreeParent = path.dirname(worktreeAbs);
119
+ const worktreeGrandparent = path.dirname(worktreeParent);
120
+ for (const possibleRepoRoot of [worktreeGrandparent, ...repoRoots]) {
121
+ const repoRel = path.relative(possibleRepoRoot, taskFolderAbs);
122
+ if (repoRel && !repoRel.startsWith("..") && !path.isAbsolute(repoRel)) {
123
+ const repoCandidate = path.join(worktreeAbs, repoRel);
124
+ try {
125
+ if (fs.existsSync(repoCandidate)) return repoCandidate;
126
+ } catch { continue; }
127
+ }
128
+ }
129
+
130
+ // Fallback: return original task folder (might work if not in worktree)
131
+ return task.taskFolder;
84
132
  }
85
133
 
86
134
  function parseStatusMd(taskFolder) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",