taskplane 0.1.14 → 0.1.16
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 +317 -9
- package/extensions/taskplane/abort.ts +461 -466
- package/extensions/taskplane/config.ts +17 -12
- package/extensions/taskplane/discovery.ts +168 -32
- package/extensions/taskplane/engine.ts +781 -758
- package/extensions/taskplane/execution.ts +112 -48
- package/extensions/taskplane/extension.ts +780 -693
- package/extensions/taskplane/git.ts +25 -7
- package/extensions/taskplane/index.ts +23 -22
- package/extensions/taskplane/merge.ts +18 -16
- package/extensions/taskplane/messages.ts +146 -134
- package/extensions/taskplane/persistence.ts +1136 -1121
- package/extensions/taskplane/resume.ts +1102 -1092
- package/extensions/taskplane/types.ts +243 -3
- package/extensions/taskplane/waves.ts +894 -900
- package/extensions/taskplane/workspace.ts +382 -0
- package/extensions/taskplane/worktree.ts +113 -11
- package/package.json +1 -1
- package/templates/config/task-orchestrator.yaml +86 -89
- package/templates/config/task-runner.yaml +95 -99
|
@@ -12,7 +12,6 @@ export interface OrchestratorConfig {
|
|
|
12
12
|
max_lanes: number;
|
|
13
13
|
worktree_location: "sibling" | "subdirectory";
|
|
14
14
|
worktree_prefix: string;
|
|
15
|
-
integration_branch: string;
|
|
16
15
|
batch_id_format: "timestamp" | "sequential";
|
|
17
16
|
spawn_mode: "tmux" | "subprocess";
|
|
18
17
|
tmux_prefix: string;
|
|
@@ -60,6 +59,10 @@ export interface ParsedTask {
|
|
|
60
59
|
promptPath: string;
|
|
61
60
|
areaName: string;
|
|
62
61
|
status: "pending" | "complete";
|
|
62
|
+
/** Repo ID declared in the PROMPT metadata (e.g., "api", "frontend"). Undefined if not declared. */
|
|
63
|
+
promptRepoId?: string;
|
|
64
|
+
/** Resolved repo ID after routing precedence (workspace mode only). Undefined in repo mode. */
|
|
65
|
+
resolvedRepoId?: string;
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
/** A wave: a group of tasks whose dependencies are all satisfied */
|
|
@@ -106,6 +109,8 @@ export interface TaskArea {
|
|
|
106
109
|
path: string;
|
|
107
110
|
prefix: string;
|
|
108
111
|
context: string;
|
|
112
|
+
/** Optional repo ID for routing tasks in this area (workspace mode only). */
|
|
113
|
+
repoId?: string;
|
|
109
114
|
}
|
|
110
115
|
|
|
111
116
|
/** Subset of task-runner.yaml that the orchestrator needs */
|
|
@@ -136,7 +141,6 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
|
|
|
136
141
|
max_lanes: 3,
|
|
137
142
|
worktree_location: "subdirectory",
|
|
138
143
|
worktree_prefix: "taskplane-wt",
|
|
139
|
-
integration_branch: "main",
|
|
140
144
|
batch_id_format: "timestamp",
|
|
141
145
|
spawn_mode: "subprocess",
|
|
142
146
|
tmux_prefix: "orch",
|
|
@@ -361,12 +365,31 @@ export interface DiscoveryError {
|
|
|
361
365
|
| "DEP_UNRESOLVED"
|
|
362
366
|
| "DEP_PENDING"
|
|
363
367
|
| "DEP_AMBIGUOUS"
|
|
364
|
-
| "DEP_SOURCE_FALLBACK"
|
|
368
|
+
| "DEP_SOURCE_FALLBACK"
|
|
369
|
+
| "TASK_REPO_UNRESOLVED"
|
|
370
|
+
| "TASK_REPO_UNKNOWN";
|
|
365
371
|
message: string;
|
|
366
372
|
taskPath?: string;
|
|
367
373
|
taskId?: string;
|
|
368
374
|
}
|
|
369
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Discovery error codes that are fatal (block planning/execution).
|
|
378
|
+
*
|
|
379
|
+
* Used by formatDiscoveryResults, extension.ts, and engine.ts for
|
|
380
|
+
* consistent fatal-error classification. Keep in sync with the
|
|
381
|
+
* DiscoveryError.code union above.
|
|
382
|
+
*/
|
|
383
|
+
export const FATAL_DISCOVERY_CODES: ReadonlyArray<DiscoveryError["code"]> = [
|
|
384
|
+
"DUPLICATE_ID",
|
|
385
|
+
"DEP_UNRESOLVED",
|
|
386
|
+
"DEP_PENDING",
|
|
387
|
+
"DEP_AMBIGUOUS",
|
|
388
|
+
"PARSE_MISSING_ID",
|
|
389
|
+
"TASK_REPO_UNRESOLVED",
|
|
390
|
+
"TASK_REPO_UNKNOWN",
|
|
391
|
+
] as const;
|
|
392
|
+
|
|
370
393
|
/** Result of the full discovery pipeline */
|
|
371
394
|
export interface DiscoveryResult {
|
|
372
395
|
pending: Map<string, ParsedTask>;
|
|
@@ -790,6 +813,8 @@ export interface OrchBatchRuntimeState {
|
|
|
790
813
|
phase: OrchBatchPhase;
|
|
791
814
|
/** Unique batch identifier (timestamp format, e.g., "20260308T214300") */
|
|
792
815
|
batchId: string;
|
|
816
|
+
/** Branch that was active when /orch started — used as base for worktrees and merge target */
|
|
817
|
+
baseBranch: string;
|
|
793
818
|
/** Shared pause signal — set by /orch-pause, read by executeLane/executeWave */
|
|
794
819
|
pauseSignal: { paused: boolean };
|
|
795
820
|
/** All wave results in order (grows as waves complete) */
|
|
@@ -866,6 +891,7 @@ export function freshOrchBatchState(): OrchBatchRuntimeState {
|
|
|
866
891
|
return {
|
|
867
892
|
phase: "idle",
|
|
868
893
|
batchId: "",
|
|
894
|
+
baseBranch: "",
|
|
869
895
|
pauseSignal: { paused: false },
|
|
870
896
|
waveResults: [],
|
|
871
897
|
currentWaveIndex: -1,
|
|
@@ -1208,6 +1234,8 @@ export interface PersistedBatchState {
|
|
|
1208
1234
|
phase: OrchBatchPhase;
|
|
1209
1235
|
/** Unique batch identifier (timestamp format) */
|
|
1210
1236
|
batchId: string;
|
|
1237
|
+
/** Branch that was active when /orch started — used as base for worktrees and merge target */
|
|
1238
|
+
baseBranch: string;
|
|
1211
1239
|
/** Epoch ms when batch started */
|
|
1212
1240
|
startedAt: number;
|
|
1213
1241
|
/** Epoch ms when state was last written */
|
|
@@ -1516,3 +1544,215 @@ export interface BatchHistorySummary {
|
|
|
1516
1544
|
/** Max number of batch history entries to retain. */
|
|
1517
1545
|
export const BATCH_HISTORY_MAX_ENTRIES = 100;
|
|
1518
1546
|
|
|
1547
|
+
|
|
1548
|
+
// ── Workspace Mode Types ─────────────────────────────────────────────
|
|
1549
|
+
|
|
1550
|
+
/**
|
|
1551
|
+
* Workspace execution mode.
|
|
1552
|
+
*
|
|
1553
|
+
* Mode behavior contract:
|
|
1554
|
+
* - **"repo"** (default): No workspace config file present. The orchestrator
|
|
1555
|
+
* treats `cwd` as both the workspace root and the single repo root.
|
|
1556
|
+
* All existing monorepo behavior is preserved unchanged.
|
|
1557
|
+
* - **"workspace"**: A `.pi/taskplane-workspace.yaml` file is present and
|
|
1558
|
+
* valid. The orchestrator runs from a non-git workspace root that
|
|
1559
|
+
* coordinates multiple repos and a shared task root.
|
|
1560
|
+
*
|
|
1561
|
+
* Mode determination rules:
|
|
1562
|
+
* 1. No workspace config file → repo mode (non-fatal default, silent).
|
|
1563
|
+
* 2. Workspace config file present + invalid → fatal error with actionable
|
|
1564
|
+
* `WorkspaceConfigError` (never silently falls back to repo mode).
|
|
1565
|
+
* 3. Workspace config file present + valid → workspace mode.
|
|
1566
|
+
*/
|
|
1567
|
+
export type WorkspaceMode = "repo" | "workspace";
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* Configuration for a single repository within a workspace.
|
|
1571
|
+
*
|
|
1572
|
+
* Each repo is identified by a stable ID (e.g., "api", "frontend")
|
|
1573
|
+
* that is used for routing tasks to repos and for display purposes.
|
|
1574
|
+
*/
|
|
1575
|
+
export interface WorkspaceRepoConfig {
|
|
1576
|
+
/** Stable identifier for this repo (e.g., "api", "frontend") */
|
|
1577
|
+
id: string;
|
|
1578
|
+
/** Absolute filesystem path to the repo root (must be a git repo) */
|
|
1579
|
+
path: string;
|
|
1580
|
+
/** Optional default branch override (e.g., "develop", "main"). Falls back to repo HEAD. */
|
|
1581
|
+
defaultBranch?: string;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* Routing configuration for workspace mode.
|
|
1586
|
+
*
|
|
1587
|
+
* Controls where tasks are discovered and which repo receives
|
|
1588
|
+
* unqualified operations.
|
|
1589
|
+
*/
|
|
1590
|
+
export interface WorkspaceRoutingConfig {
|
|
1591
|
+
/**
|
|
1592
|
+
* Absolute path to the shared tasks root directory.
|
|
1593
|
+
* All task areas are resolved relative to this path.
|
|
1594
|
+
* Must exist on disk.
|
|
1595
|
+
*/
|
|
1596
|
+
tasksRoot: string;
|
|
1597
|
+
/**
|
|
1598
|
+
* Default repo ID for operations that don't specify a repo.
|
|
1599
|
+
* Must reference a valid key in `WorkspaceConfig.repos`.
|
|
1600
|
+
*/
|
|
1601
|
+
defaultRepo: string;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
/**
|
|
1605
|
+
* Top-level workspace configuration.
|
|
1606
|
+
*
|
|
1607
|
+
* Loaded from `.pi/taskplane-workspace.yaml` when present.
|
|
1608
|
+
* Immutable after initial validation — never mutated at runtime.
|
|
1609
|
+
*/
|
|
1610
|
+
export interface WorkspaceConfig {
|
|
1611
|
+
/** Active workspace mode */
|
|
1612
|
+
mode: WorkspaceMode;
|
|
1613
|
+
/** Map of repo ID → repo configuration. At least one repo required in workspace mode. */
|
|
1614
|
+
repos: Map<string, WorkspaceRepoConfig>;
|
|
1615
|
+
/** Routing configuration (tasks root, default repo) */
|
|
1616
|
+
routing: WorkspaceRoutingConfig;
|
|
1617
|
+
/** Absolute path to the workspace config file that was loaded */
|
|
1618
|
+
configPath: string;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
/**
|
|
1622
|
+
* Canonical execution context for the orchestrator.
|
|
1623
|
+
*
|
|
1624
|
+
* This is the primary runtime context threaded through orchestrator
|
|
1625
|
+
* entry points. It replaces the previous pattern of passing raw `cwd`
|
|
1626
|
+
* as the sole repo root.
|
|
1627
|
+
*
|
|
1628
|
+
* In repo mode, `workspaceRoot` and `repoRoot` are the same directory.
|
|
1629
|
+
* In workspace mode, `workspaceRoot` is the non-git coordination root
|
|
1630
|
+
* and `repoRoot` is the default repo from the workspace config.
|
|
1631
|
+
*
|
|
1632
|
+
* Design rationale:
|
|
1633
|
+
* - Step 2 (wire orchestrator startup) will construct this from config
|
|
1634
|
+
* loading results and thread it into `executeOrchBatch()` and friends.
|
|
1635
|
+
* - `repoRoot` is always a git repository, preserving the invariant
|
|
1636
|
+
* that git operations (worktree, branch, merge) have a valid target.
|
|
1637
|
+
* - `workspaceConfig` is null in repo mode (no workspace file loaded).
|
|
1638
|
+
*/
|
|
1639
|
+
export interface ExecutionContext {
|
|
1640
|
+
/** Absolute path to the workspace root (cwd in repo mode, workspace dir in workspace mode) */
|
|
1641
|
+
workspaceRoot: string;
|
|
1642
|
+
/** Absolute path to the default/primary git repo root */
|
|
1643
|
+
repoRoot: string;
|
|
1644
|
+
/** Active workspace mode */
|
|
1645
|
+
mode: WorkspaceMode;
|
|
1646
|
+
/** Workspace configuration (null in repo mode) */
|
|
1647
|
+
workspaceConfig: WorkspaceConfig | null;
|
|
1648
|
+
/** Loaded task runner configuration */
|
|
1649
|
+
taskRunnerConfig: TaskRunnerConfig;
|
|
1650
|
+
/** Loaded orchestrator configuration */
|
|
1651
|
+
orchestratorConfig: OrchestratorConfig;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
// ── Workspace Validation Error Types ─────────────────────────────────
|
|
1656
|
+
|
|
1657
|
+
/**
|
|
1658
|
+
* Error codes for workspace configuration validation failures.
|
|
1659
|
+
*
|
|
1660
|
+
* Each code maps to a deterministic validation rule from the workspace
|
|
1661
|
+
* config loading pipeline. Codes are stable and machine-branchable.
|
|
1662
|
+
*
|
|
1663
|
+
* - WORKSPACE_FILE_READ_ERROR: Config file exists but cannot be read (permissions, encoding)
|
|
1664
|
+
* - WORKSPACE_FILE_PARSE_ERROR: Config file contains invalid YAML
|
|
1665
|
+
* - WORKSPACE_MISSING_REPOS: No repos defined in workspace config (at least one required)
|
|
1666
|
+
* - WORKSPACE_REPO_PATH_MISSING: A repo entry has no `path` field
|
|
1667
|
+
* - WORKSPACE_REPO_PATH_NOT_FOUND: A repo's `path` does not exist on disk
|
|
1668
|
+
* - WORKSPACE_REPO_NOT_GIT: A repo's `path` exists but is not a git repository
|
|
1669
|
+
* - WORKSPACE_MISSING_TASKS_ROOT: `routing.tasks_root` is missing or empty
|
|
1670
|
+
* - WORKSPACE_TASKS_ROOT_NOT_FOUND: `routing.tasks_root` path does not exist on disk
|
|
1671
|
+
* - WORKSPACE_MISSING_DEFAULT_REPO: `routing.default_repo` is missing or empty
|
|
1672
|
+
* - WORKSPACE_DEFAULT_REPO_NOT_FOUND: `routing.default_repo` references a repo ID not in the repos map
|
|
1673
|
+
* - WORKSPACE_DUPLICATE_REPO_PATH: Two or more repos share the same filesystem path
|
|
1674
|
+
* - WORKSPACE_SCHEMA_INVALID: Config file has valid YAML but missing/invalid top-level structure
|
|
1675
|
+
*/
|
|
1676
|
+
export type WorkspaceConfigErrorCode =
|
|
1677
|
+
| "WORKSPACE_FILE_READ_ERROR"
|
|
1678
|
+
| "WORKSPACE_FILE_PARSE_ERROR"
|
|
1679
|
+
| "WORKSPACE_MISSING_REPOS"
|
|
1680
|
+
| "WORKSPACE_REPO_PATH_MISSING"
|
|
1681
|
+
| "WORKSPACE_REPO_PATH_NOT_FOUND"
|
|
1682
|
+
| "WORKSPACE_REPO_NOT_GIT"
|
|
1683
|
+
| "WORKSPACE_MISSING_TASKS_ROOT"
|
|
1684
|
+
| "WORKSPACE_TASKS_ROOT_NOT_FOUND"
|
|
1685
|
+
| "WORKSPACE_MISSING_DEFAULT_REPO"
|
|
1686
|
+
| "WORKSPACE_DEFAULT_REPO_NOT_FOUND"
|
|
1687
|
+
| "WORKSPACE_DUPLICATE_REPO_PATH"
|
|
1688
|
+
| "WORKSPACE_SCHEMA_INVALID";
|
|
1689
|
+
|
|
1690
|
+
/**
|
|
1691
|
+
* Typed error class for workspace configuration failures.
|
|
1692
|
+
*
|
|
1693
|
+
* Thrown during workspace config loading/validation when the config file
|
|
1694
|
+
* is present but invalid. Never thrown when no config file exists (that
|
|
1695
|
+
* case silently falls back to repo mode).
|
|
1696
|
+
*
|
|
1697
|
+
* Follows the established pattern of typed error classes in this module
|
|
1698
|
+
* (WorktreeError, ExecutionError, MergeError, StateFileError, ResumeError).
|
|
1699
|
+
*/
|
|
1700
|
+
export class WorkspaceConfigError extends Error {
|
|
1701
|
+
code: WorkspaceConfigErrorCode;
|
|
1702
|
+
/** Optional repo ID that triggered the error (for repo-specific validation failures) */
|
|
1703
|
+
repoId?: string;
|
|
1704
|
+
/** Optional filesystem path related to the error */
|
|
1705
|
+
relatedPath?: string;
|
|
1706
|
+
|
|
1707
|
+
constructor(code: WorkspaceConfigErrorCode, message: string, repoId?: string, relatedPath?: string) {
|
|
1708
|
+
super(message);
|
|
1709
|
+
this.name = "WorkspaceConfigError";
|
|
1710
|
+
this.code = code;
|
|
1711
|
+
this.repoId = repoId;
|
|
1712
|
+
this.relatedPath = relatedPath;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
|
|
1717
|
+
// ── Workspace Defaults ───────────────────────────────────────────────
|
|
1718
|
+
|
|
1719
|
+
/**
|
|
1720
|
+
* Canonical filename for workspace configuration.
|
|
1721
|
+
* Resolved relative to workspace root: `.pi/taskplane-workspace.yaml`
|
|
1722
|
+
*/
|
|
1723
|
+
export const WORKSPACE_CONFIG_FILENAME = "taskplane-workspace.yaml";
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* Resolve the absolute path to the workspace config file.
|
|
1727
|
+
* @param workspaceRoot - Absolute path to the workspace root
|
|
1728
|
+
*/
|
|
1729
|
+
export function workspaceConfigPath(workspaceRoot: string): string {
|
|
1730
|
+
return join(workspaceRoot, ".pi", WORKSPACE_CONFIG_FILENAME);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* Create a default ExecutionContext for repo mode.
|
|
1735
|
+
*
|
|
1736
|
+
* Used when no workspace config file is present. The workspace root
|
|
1737
|
+
* and repo root are the same directory (cwd), preserving existing
|
|
1738
|
+
* monorepo behavior exactly.
|
|
1739
|
+
*
|
|
1740
|
+
* @param cwd - Current working directory (treated as both workspace and repo root)
|
|
1741
|
+
* @param taskRunnerConfig - Loaded task runner config (or defaults)
|
|
1742
|
+
* @param orchestratorConfig - Loaded orchestrator config (or defaults)
|
|
1743
|
+
*/
|
|
1744
|
+
export function createRepoModeContext(
|
|
1745
|
+
cwd: string,
|
|
1746
|
+
taskRunnerConfig: TaskRunnerConfig,
|
|
1747
|
+
orchestratorConfig: OrchestratorConfig,
|
|
1748
|
+
): ExecutionContext {
|
|
1749
|
+
return {
|
|
1750
|
+
workspaceRoot: cwd,
|
|
1751
|
+
repoRoot: cwd,
|
|
1752
|
+
mode: "repo",
|
|
1753
|
+
workspaceConfig: null,
|
|
1754
|
+
taskRunnerConfig,
|
|
1755
|
+
orchestratorConfig,
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
|