taskplane 0.10.0 → 0.10.2
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/dashboard/public/app.js
CHANGED
|
@@ -531,11 +531,11 @@ function renderLanesTasks(batch, tmuxSessions) {
|
|
|
531
531
|
|
|
532
532
|
// Worker stats from lane state sidecar + telemetry badges
|
|
533
533
|
let workerHtml = "";
|
|
534
|
-
const telemBadges = task.status !== "pending" ? telemetryBadgesHtml(tel, reviewerActive) : "";
|
|
535
534
|
// Reviewer sub-row should only appear under the task currently being reviewed,
|
|
536
535
|
// not all tasks in the lane. The lane-state sidecar is per-lane (shared by all
|
|
537
536
|
// tasks in the lane), so check that the sidecar's current taskId matches this task.
|
|
538
537
|
const reviewerActive = ls && ls.reviewerStatus === "running" && ls.taskId === task.taskId;
|
|
538
|
+
const telemBadges = task.status !== "pending" ? telemetryBadgesHtml(tel, reviewerActive) : "";
|
|
539
539
|
if (ls && ls.workerStatus === "running" && task.status === "running") {
|
|
540
540
|
const elapsed = ls.workerElapsed ? `${Math.round(ls.workerElapsed / 1000)}s` : "";
|
|
541
541
|
const tools = ls.workerToolCount || 0;
|
|
@@ -12,43 +12,81 @@ import type { AllocatedLane, AllocatedTask, DependencyGraph, LaneExecutionResult
|
|
|
12
12
|
import { allocateLanes } from "./waves.ts";
|
|
13
13
|
import { runGit } from "./git.ts";
|
|
14
14
|
|
|
15
|
-
// ──
|
|
15
|
+
// ── Taskplane Package File Resolution ────────────────────────────────
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Cached result of `npm root -g` to avoid repeated child process spawns.
|
|
19
|
+
* null = not yet resolved, "" = resolution failed.
|
|
20
|
+
*/
|
|
21
|
+
let _npmGlobalRoot: string | null = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the global npm root directory via `npm root -g`.
|
|
25
|
+
* Result is cached for the process lifetime.
|
|
26
|
+
*/
|
|
27
|
+
function getNpmGlobalRoot(): string {
|
|
28
|
+
if (_npmGlobalRoot !== null) return _npmGlobalRoot;
|
|
29
|
+
try {
|
|
30
|
+
const result = spawnSync("npm", ["root", "-g"], {
|
|
31
|
+
encoding: "utf-8",
|
|
32
|
+
timeout: 5000,
|
|
33
|
+
shell: true,
|
|
34
|
+
});
|
|
35
|
+
_npmGlobalRoot = result.stdout?.trim() || "";
|
|
36
|
+
} catch {
|
|
37
|
+
_npmGlobalRoot = "";
|
|
38
|
+
}
|
|
39
|
+
return _npmGlobalRoot;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a file path within the taskplane package.
|
|
19
44
|
*
|
|
20
45
|
* Resolution order:
|
|
21
|
-
* 1. Local project: {repoRoot}/
|
|
22
|
-
* 2.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
46
|
+
* 1. Local project: {repoRoot}/{relPath} (for taskplane development)
|
|
47
|
+
* 2. `npm root -g` based: {npmGlobalRoot}/taskplane/{relPath}
|
|
48
|
+
* (covers Homebrew, nvm, volta, pnpm, and any custom npm prefix)
|
|
49
|
+
* 3. Well-known global npm paths (Windows/macOS/Linux):
|
|
50
|
+
* - {APPDATA}/npm/node_modules/taskplane/{relPath}
|
|
51
|
+
* - {HOME}/.npm-global/lib/node_modules/taskplane/{relPath}
|
|
52
|
+
* - /usr/local/lib/node_modules/taskplane/{relPath}
|
|
53
|
+
* - /opt/homebrew/lib/node_modules/taskplane/{relPath}
|
|
54
|
+
* 4. Peer of pi's package: resolve from pi's binary location
|
|
55
|
+
*
|
|
56
|
+
* @param repoRoot - Absolute path to the project root
|
|
57
|
+
* @param relPath - Relative path within the taskplane package (e.g., "bin/rpc-wrapper.mjs")
|
|
58
|
+
* @returns Absolute path to the resolved file
|
|
27
59
|
*/
|
|
28
|
-
function
|
|
29
|
-
const extFile = join("extensions", "task-runner.ts");
|
|
30
|
-
|
|
60
|
+
function resolveTaskplanePackageFile(repoRoot: string, relPath: string): string {
|
|
31
61
|
// 1. Local project (taskplane development)
|
|
32
|
-
const localPath = join(resolve(repoRoot),
|
|
62
|
+
const localPath = join(resolve(repoRoot), relPath);
|
|
33
63
|
if (existsSync(localPath)) return localPath;
|
|
34
64
|
|
|
35
|
-
// 2. Global npm install paths
|
|
36
|
-
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
37
65
|
const candidates: string[] = [];
|
|
66
|
+
|
|
67
|
+
// 2. Dynamic: `npm root -g` (covers ALL npm setups: nvm, Homebrew, volta, etc.)
|
|
68
|
+
const npmRoot = getNpmGlobalRoot();
|
|
69
|
+
if (npmRoot) {
|
|
70
|
+
candidates.push(join(npmRoot, "taskplane", relPath));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 3. Well-known static paths
|
|
74
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
38
75
|
if (process.env.APPDATA) {
|
|
39
|
-
candidates.push(join(process.env.APPDATA, "npm", "node_modules", "taskplane",
|
|
76
|
+
candidates.push(join(process.env.APPDATA, "npm", "node_modules", "taskplane", relPath));
|
|
40
77
|
}
|
|
41
78
|
if (home) {
|
|
42
|
-
candidates.push(join(home, "AppData", "Roaming", "npm", "node_modules", "taskplane",
|
|
43
|
-
candidates.push(join(home, ".npm-global", "lib", "node_modules", "taskplane",
|
|
79
|
+
candidates.push(join(home, "AppData", "Roaming", "npm", "node_modules", "taskplane", relPath));
|
|
80
|
+
candidates.push(join(home, ".npm-global", "lib", "node_modules", "taskplane", relPath));
|
|
44
81
|
}
|
|
45
|
-
candidates.push(join("/usr", "local", "lib", "node_modules", "taskplane",
|
|
82
|
+
candidates.push(join("/usr", "local", "lib", "node_modules", "taskplane", relPath));
|
|
83
|
+
candidates.push(join("/opt", "homebrew", "lib", "node_modules", "taskplane", relPath));
|
|
46
84
|
|
|
47
|
-
//
|
|
85
|
+
// 4. Peer of pi's package
|
|
48
86
|
try {
|
|
49
87
|
const piPath = process.argv[1] || "";
|
|
50
88
|
const piPkgDir = resolve(piPath, "..", "..");
|
|
51
|
-
candidates.push(join(piPkgDir, "..", "taskplane",
|
|
89
|
+
candidates.push(join(piPkgDir, "..", "taskplane", relPath));
|
|
52
90
|
} catch { /* ignore */ }
|
|
53
91
|
|
|
54
92
|
for (const candidate of candidates) {
|
|
@@ -59,51 +97,24 @@ function resolveTaskRunnerExtensionPath(repoRoot: string): string {
|
|
|
59
97
|
return localPath;
|
|
60
98
|
}
|
|
61
99
|
|
|
100
|
+
// ── Task Runner Extension Path Resolution ────────────────────────────
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Find the task-runner extension path for lane sessions.
|
|
104
|
+
* @see resolveTaskplanePackageFile for resolution order
|
|
105
|
+
*/
|
|
106
|
+
function resolveTaskRunnerExtensionPath(repoRoot: string): string {
|
|
107
|
+
return resolveTaskplanePackageFile(repoRoot, join("extensions", "task-runner.ts"));
|
|
108
|
+
}
|
|
109
|
+
|
|
62
110
|
// ── RPC Wrapper Path Resolution ──────────────────────────────────────
|
|
63
111
|
|
|
64
112
|
/**
|
|
65
113
|
* Find the rpc-wrapper.mjs path for lane sessions.
|
|
66
|
-
*
|
|
67
|
-
* Resolution order mirrors resolveTaskRunnerExtensionPath:
|
|
68
|
-
* 1. Local project: {repoRoot}/bin/rpc-wrapper.mjs (for taskplane dev)
|
|
69
|
-
* 2. Global npm (Windows): {APPDATA}/npm/node_modules/taskplane/bin/rpc-wrapper.mjs
|
|
70
|
-
* 3. Global npm (Unix): /usr/local/lib/node_modules/taskplane/bin/rpc-wrapper.mjs
|
|
71
|
-
* 4. npm peer: resolve from pi's location
|
|
72
|
-
*
|
|
73
|
-
* @throws ExecutionError if rpc-wrapper.mjs cannot be found anywhere
|
|
114
|
+
* @see resolveTaskplanePackageFile for resolution order
|
|
74
115
|
*/
|
|
75
116
|
export function resolveRpcWrapperPath(repoRoot: string): string {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// 1. Local project (taskplane development)
|
|
79
|
-
const localPath = join(resolve(repoRoot), wrapperFile);
|
|
80
|
-
if (existsSync(localPath)) return localPath;
|
|
81
|
-
|
|
82
|
-
// 2. Global npm install paths
|
|
83
|
-
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
84
|
-
const candidates: string[] = [];
|
|
85
|
-
if (process.env.APPDATA) {
|
|
86
|
-
candidates.push(join(process.env.APPDATA, "npm", "node_modules", "taskplane", wrapperFile));
|
|
87
|
-
}
|
|
88
|
-
if (home) {
|
|
89
|
-
candidates.push(join(home, "AppData", "Roaming", "npm", "node_modules", "taskplane", wrapperFile));
|
|
90
|
-
candidates.push(join(home, ".npm-global", "lib", "node_modules", "taskplane", wrapperFile));
|
|
91
|
-
}
|
|
92
|
-
candidates.push(join("/usr", "local", "lib", "node_modules", "taskplane", wrapperFile));
|
|
93
|
-
|
|
94
|
-
// 3. Peer of pi's package
|
|
95
|
-
try {
|
|
96
|
-
const piPath = process.argv[1] || "";
|
|
97
|
-
const piPkgDir = resolve(piPath, "..", "..");
|
|
98
|
-
candidates.push(join(piPkgDir, "..", "taskplane", wrapperFile));
|
|
99
|
-
} catch { /* ignore */ }
|
|
100
|
-
|
|
101
|
-
for (const candidate of candidates) {
|
|
102
|
-
if (existsSync(candidate)) return candidate;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Fallback: return the local path (will fail at spawn time with a clear error)
|
|
106
|
-
return localPath;
|
|
117
|
+
return resolveTaskplanePackageFile(repoRoot, join("bin", "rpc-wrapper.mjs"));
|
|
107
118
|
}
|
|
108
119
|
|
|
109
120
|
// ── Telemetry Helpers ────────────────────────────────────────────────
|