taskplane 0.1.17 → 0.2.0
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 +155 -1
- package/dashboard/public/index.html +3 -0
- package/dashboard/public/style.css +63 -0
- package/dashboard/server.cjs +5 -0
- package/extensions/taskplane/abort.ts +24 -3
- package/extensions/taskplane/discovery.ts +24 -0
- package/extensions/taskplane/engine.ts +57 -61
- package/extensions/taskplane/execution.ts +4 -2
- package/extensions/taskplane/extension.ts +11 -0
- package/extensions/taskplane/index.ts +1 -0
- package/extensions/taskplane/merge.ts +250 -6
- package/extensions/taskplane/messages.ts +207 -3
- package/extensions/taskplane/naming.ts +117 -0
- package/extensions/taskplane/persistence.ts +174 -24
- package/extensions/taskplane/resume.ts +329 -76
- package/extensions/taskplane/types.ts +153 -6
- package/extensions/taskplane/waves.ts +386 -94
- package/extensions/taskplane/workspace.ts +17 -0
- package/extensions/taskplane/worktree.ts +57 -31
- package/package.json +1 -1
- package/skills/create-taskplane-task/SKILL.md +363 -326
- package/skills/create-taskplane-task/references/prompt-template.md +245 -246
- package/templates/agents/task-reviewer.md +109 -81
- package/templates/agents/task-worker.md +159 -140
- package/templates/config/task-orchestrator.yaml +7 -2
|
@@ -15,6 +15,8 @@ export interface OrchestratorConfig {
|
|
|
15
15
|
batch_id_format: "timestamp" | "sequential";
|
|
16
16
|
spawn_mode: "tmux" | "subprocess";
|
|
17
17
|
tmux_prefix: string;
|
|
18
|
+
/** Optional operator identifier. Auto-detected from OS username if empty. */
|
|
19
|
+
operator_id: string;
|
|
18
20
|
};
|
|
19
21
|
dependencies: {
|
|
20
22
|
source: "prompt" | "agent";
|
|
@@ -76,6 +78,8 @@ export interface LaneAssignment {
|
|
|
76
78
|
taskId: string;
|
|
77
79
|
lane: number;
|
|
78
80
|
task: ParsedTask;
|
|
81
|
+
/** Repo ID this task targets (workspace mode only). Undefined in repo mode. */
|
|
82
|
+
repoId?: string;
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
/** Runtime state of the entire batch execution */
|
|
@@ -144,6 +148,7 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
|
|
|
144
148
|
batch_id_format: "timestamp",
|
|
145
149
|
spawn_mode: "subprocess",
|
|
146
150
|
tmux_prefix: "orch",
|
|
151
|
+
operator_id: "",
|
|
147
152
|
},
|
|
148
153
|
dependencies: {
|
|
149
154
|
source: "prompt",
|
|
@@ -222,6 +227,8 @@ export interface CreateWorktreeOptions {
|
|
|
222
227
|
baseBranch: string;
|
|
223
228
|
/** Worktree directory prefix (e.g. "taskplane-wt") */
|
|
224
229
|
prefix: string;
|
|
230
|
+
/** Operator identifier (sanitized, e.g., "henrylach") */
|
|
231
|
+
opId: string;
|
|
225
232
|
/** Full orchestrator config (optional; used for worktree_location) */
|
|
226
233
|
config?: OrchestratorConfig;
|
|
227
234
|
}
|
|
@@ -367,7 +374,8 @@ export interface DiscoveryError {
|
|
|
367
374
|
| "DEP_AMBIGUOUS"
|
|
368
375
|
| "DEP_SOURCE_FALLBACK"
|
|
369
376
|
| "TASK_REPO_UNRESOLVED"
|
|
370
|
-
| "TASK_REPO_UNKNOWN"
|
|
377
|
+
| "TASK_REPO_UNKNOWN"
|
|
378
|
+
| "TASK_ROUTING_STRICT";
|
|
371
379
|
message: string;
|
|
372
380
|
taskPath?: string;
|
|
373
381
|
taskId?: string;
|
|
@@ -388,6 +396,7 @@ export const FATAL_DISCOVERY_CODES: ReadonlyArray<DiscoveryError["code"]> = [
|
|
|
388
396
|
"PARSE_MISSING_ID",
|
|
389
397
|
"TASK_REPO_UNRESOLVED",
|
|
390
398
|
"TASK_REPO_UNKNOWN",
|
|
399
|
+
"TASK_ROUTING_STRICT",
|
|
391
400
|
] as const;
|
|
392
401
|
|
|
393
402
|
/** Result of the full discovery pipeline */
|
|
@@ -477,7 +486,7 @@ export interface AllocatedTask {
|
|
|
477
486
|
* between Step 1 (allocation) and Step 2 (execution).
|
|
478
487
|
*/
|
|
479
488
|
export interface AllocatedLane {
|
|
480
|
-
/** Lane number (1-indexed, deterministic) */
|
|
489
|
+
/** Lane number (1-indexed, deterministic, globally unique across repos) */
|
|
481
490
|
laneNumber: number;
|
|
482
491
|
/** Lane identifier for display and logging (e.g., "lane-1") */
|
|
483
492
|
laneId: string;
|
|
@@ -495,6 +504,8 @@ export interface AllocatedLane {
|
|
|
495
504
|
estimatedLoad: number;
|
|
496
505
|
/** Total estimated duration in minutes (sum of task durations) */
|
|
497
506
|
estimatedMinutes: number;
|
|
507
|
+
/** Repo ID this lane targets (workspace mode only). Undefined in repo mode. */
|
|
508
|
+
repoId?: string;
|
|
498
509
|
}
|
|
499
510
|
|
|
500
511
|
|
|
@@ -815,6 +826,8 @@ export interface OrchBatchRuntimeState {
|
|
|
815
826
|
batchId: string;
|
|
816
827
|
/** Branch that was active when /orch started — used as base for worktrees and merge target */
|
|
817
828
|
baseBranch: string;
|
|
829
|
+
/** Workspace execution mode (v2). Defaults to "repo" for backward compatibility. */
|
|
830
|
+
mode: WorkspaceMode;
|
|
818
831
|
/** Shared pause signal — set by /orch-pause, read by executeLane/executeWave */
|
|
819
832
|
pauseSignal: { paused: boolean };
|
|
820
833
|
/** All wave results in order (grows as waves complete) */
|
|
@@ -892,6 +905,7 @@ export function freshOrchBatchState(): OrchBatchRuntimeState {
|
|
|
892
905
|
phase: "idle",
|
|
893
906
|
batchId: "",
|
|
894
907
|
baseBranch: "",
|
|
908
|
+
mode: "repo",
|
|
895
909
|
pauseSignal: { paused: false },
|
|
896
910
|
waveResults: [],
|
|
897
911
|
currentWaveIndex: -1,
|
|
@@ -965,6 +979,8 @@ export interface MergeLaneResult {
|
|
|
965
979
|
result: MergeResult | null;
|
|
966
980
|
error: string | null;
|
|
967
981
|
durationMs: number;
|
|
982
|
+
/** Repo ID this lane targeted (workspace mode only). Undefined in repo mode. */
|
|
983
|
+
repoId?: string;
|
|
968
984
|
}
|
|
969
985
|
|
|
970
986
|
/** Overall wave merge outcome. */
|
|
@@ -975,6 +991,22 @@ export interface MergeWaveResult {
|
|
|
975
991
|
failedLane: number | null;
|
|
976
992
|
failureReason: string | null;
|
|
977
993
|
totalDurationMs: number;
|
|
994
|
+
/** Per-repo merge outcomes (populated in workspace mode; empty in repo mode). */
|
|
995
|
+
repoResults?: RepoMergeOutcome[];
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/** Per-repo merge outcome within a wave merge. */
|
|
999
|
+
export interface RepoMergeOutcome {
|
|
1000
|
+
/** Repo ID (undefined in repo mode default group). */
|
|
1001
|
+
repoId: string | undefined;
|
|
1002
|
+
/** Merge status for this repo. */
|
|
1003
|
+
status: "succeeded" | "failed" | "partial";
|
|
1004
|
+
/** Lane results belonging to this repo. */
|
|
1005
|
+
laneResults: MergeLaneResult[];
|
|
1006
|
+
/** Failed lane number within this repo (null if all succeeded). */
|
|
1007
|
+
failedLane: number | null;
|
|
1008
|
+
/** Failure reason within this repo (null if all succeeded). */
|
|
1009
|
+
failureReason: string | null;
|
|
978
1010
|
}
|
|
979
1011
|
|
|
980
1012
|
// ── Merge Error Types ────────────────────────────────────────────────
|
|
@@ -1107,9 +1139,21 @@ export interface OrchDashboardViewModel {
|
|
|
1107
1139
|
/**
|
|
1108
1140
|
* Current schema version for batch-state.json.
|
|
1109
1141
|
* Increment when the persisted schema changes in incompatible ways.
|
|
1110
|
-
*
|
|
1142
|
+
*
|
|
1143
|
+
* Version history:
|
|
1144
|
+
* v1 — Original schema (TS-009). No repo-aware fields on task records.
|
|
1145
|
+
* Lane records had optional `repoId` but it was not validated.
|
|
1146
|
+
* v2 — Repo-aware records (TP-006). Adds `repoId` and `resolvedRepoId`
|
|
1147
|
+
* to task records. Formalizes `repoId` on lane records. Adds
|
|
1148
|
+
* `mode` field to top-level state.
|
|
1149
|
+
*
|
|
1150
|
+
* Compatibility policy:
|
|
1151
|
+
* - loadBatchState() accepts v1 files and auto-upconverts to v2 in memory
|
|
1152
|
+
* (via upconvertV1toV2()). The on-disk file is NOT rewritten.
|
|
1153
|
+
* - saveBatchState() always writes v2.
|
|
1154
|
+
* - Schema versions > 2 are rejected with STATE_SCHEMA_INVALID.
|
|
1111
1155
|
*/
|
|
1112
|
-
export const BATCH_STATE_SCHEMA_VERSION =
|
|
1156
|
+
export const BATCH_STATE_SCHEMA_VERSION = 2;
|
|
1113
1157
|
|
|
1114
1158
|
/**
|
|
1115
1159
|
* Canonical file path for persisted batch state.
|
|
@@ -1154,6 +1198,25 @@ export class StateFileError extends Error {
|
|
|
1154
1198
|
*
|
|
1155
1199
|
* Contains everything `/orch-resume` needs to reconstruct
|
|
1156
1200
|
* task progress without re-running discovery.
|
|
1201
|
+
*
|
|
1202
|
+
* Repo-aware fields (v2):
|
|
1203
|
+
* `repoId` and `resolvedRepoId` capture task-to-repo attribution
|
|
1204
|
+
* so resume can reconstruct repo routing without re-running discovery.
|
|
1205
|
+
*
|
|
1206
|
+
* Mode semantics:
|
|
1207
|
+
* - **repo mode**: Both fields are `undefined`. Tasks implicitly target
|
|
1208
|
+
* the single repository (cwd). No repo routing needed.
|
|
1209
|
+
* - **workspace mode**: `repoId` is the repo ID declared in PROMPT.md
|
|
1210
|
+
* (may be `undefined` if the task didn't declare one). `resolvedRepoId`
|
|
1211
|
+
* is the final repo ID after applying the routing precedence chain
|
|
1212
|
+
* (prompt → area → workspace default). Always a non-empty string in
|
|
1213
|
+
* workspace mode for tasks that passed routing validation.
|
|
1214
|
+
*
|
|
1215
|
+
* Source of truth:
|
|
1216
|
+
* - For allocated tasks: derived from `ParsedTask.promptRepoId` and
|
|
1217
|
+
* `ParsedTask.resolvedRepoId` via `serializeBatchState()`.
|
|
1218
|
+
* - For unallocated/pending tasks: derived from the same ParsedTask
|
|
1219
|
+
* fields via discovery enrichment in `persistRuntimeState()`.
|
|
1157
1220
|
*/
|
|
1158
1221
|
export interface PersistedTaskRecord {
|
|
1159
1222
|
/** Task identifier (e.g., "TO-014") */
|
|
@@ -1174,6 +1237,17 @@ export interface PersistedTaskRecord {
|
|
|
1174
1237
|
doneFileFound: boolean;
|
|
1175
1238
|
/** Human-readable exit reason (if completed/failed) */
|
|
1176
1239
|
exitReason: string;
|
|
1240
|
+
/**
|
|
1241
|
+
* Repo ID declared in the task's PROMPT.md metadata (v2).
|
|
1242
|
+
* Undefined in repo mode or if the task didn't declare a repo.
|
|
1243
|
+
*/
|
|
1244
|
+
repoId?: string;
|
|
1245
|
+
/**
|
|
1246
|
+
* Resolved repo ID after applying routing precedence (v2).
|
|
1247
|
+
* Undefined in repo mode. In workspace mode, this is the final
|
|
1248
|
+
* repo target after prompt → area → workspace-default fallback.
|
|
1249
|
+
*/
|
|
1250
|
+
resolvedRepoId?: string;
|
|
1177
1251
|
}
|
|
1178
1252
|
|
|
1179
1253
|
/**
|
|
@@ -1181,6 +1255,21 @@ export interface PersistedTaskRecord {
|
|
|
1181
1255
|
*
|
|
1182
1256
|
* Captures worktree/branch assignment so `/orch-resume` can
|
|
1183
1257
|
* reconnect to existing worktrees without re-allocation.
|
|
1258
|
+
*
|
|
1259
|
+
* Repo-aware contract (v2):
|
|
1260
|
+
* `repoId` captures which repository this lane targets.
|
|
1261
|
+
*
|
|
1262
|
+
* Mode semantics:
|
|
1263
|
+
* - **repo mode**: `repoId` is `undefined`. The lane's worktree is
|
|
1264
|
+
* created from the single repository (cwd). All lanes share the
|
|
1265
|
+
* same repo implicitly.
|
|
1266
|
+
* - **workspace mode**: `repoId` is a non-empty string matching a
|
|
1267
|
+
* key in `WorkspaceConfig.repos`. All tasks assigned to this lane
|
|
1268
|
+
* target the same repo. Lane allocation guarantees repo affinity
|
|
1269
|
+
* (no lane mixes tasks from different repos).
|
|
1270
|
+
*
|
|
1271
|
+
* Source of truth: derived from `AllocatedLane.repoId` during
|
|
1272
|
+
* serialization in `serializeBatchState()`.
|
|
1184
1273
|
*/
|
|
1185
1274
|
export interface PersistedLaneRecord {
|
|
1186
1275
|
/** Lane number (1-indexed) */
|
|
@@ -1195,6 +1284,12 @@ export interface PersistedLaneRecord {
|
|
|
1195
1284
|
branch: string;
|
|
1196
1285
|
/** Task IDs assigned to this lane in execution order */
|
|
1197
1286
|
taskIds: string[];
|
|
1287
|
+
/**
|
|
1288
|
+
* Repo ID this lane targets (v2).
|
|
1289
|
+
* Undefined in repo mode. Non-empty string in workspace mode,
|
|
1290
|
+
* matching a key in `WorkspaceConfig.repos`.
|
|
1291
|
+
*/
|
|
1292
|
+
repoId?: string;
|
|
1198
1293
|
}
|
|
1199
1294
|
|
|
1200
1295
|
/**
|
|
@@ -1210,6 +1305,31 @@ export interface PersistedMergeResult {
|
|
|
1210
1305
|
failedLane: number | null;
|
|
1211
1306
|
/** Failure reason (null if all succeeded) */
|
|
1212
1307
|
failureReason: string | null;
|
|
1308
|
+
/**
|
|
1309
|
+
* Per-repo merge outcomes (v2, TP-009).
|
|
1310
|
+
* Populated in workspace mode when MergeWaveResult.repoResults is available.
|
|
1311
|
+
* Undefined/absent in repo mode or for older state files. Dashboard treats
|
|
1312
|
+
* absence as single-repo merge.
|
|
1313
|
+
*/
|
|
1314
|
+
repoResults?: PersistedRepoMergeOutcome[];
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* Persisted per-repo merge outcome within a wave merge.
|
|
1319
|
+
* Serializable subset of RepoMergeOutcome — excludes full MergeLaneResult
|
|
1320
|
+
* objects (which contain detailed merge agent result JSON) to keep state file compact.
|
|
1321
|
+
*/
|
|
1322
|
+
export interface PersistedRepoMergeOutcome {
|
|
1323
|
+
/** Repo ID. Undefined for the default group in repo mode. */
|
|
1324
|
+
repoId: string | undefined;
|
|
1325
|
+
/** Merge status for this repo. */
|
|
1326
|
+
status: "succeeded" | "failed" | "partial";
|
|
1327
|
+
/** Lane numbers involved in this repo's merge. */
|
|
1328
|
+
laneNumbers: number[];
|
|
1329
|
+
/** Failed lane number within this repo (null if all succeeded). */
|
|
1330
|
+
failedLane: number | null;
|
|
1331
|
+
/** Failure reason within this repo (null if all succeeded). */
|
|
1332
|
+
failureReason: string | null;
|
|
1213
1333
|
}
|
|
1214
1334
|
|
|
1215
1335
|
/**
|
|
@@ -1226,9 +1346,16 @@ export interface PersistedMergeResult {
|
|
|
1226
1346
|
* - Merge results are summarized (not full MergeWaveResult) for size
|
|
1227
1347
|
* - `updatedAt` is monotonic (epoch ms) for staleness detection
|
|
1228
1348
|
* - `lastError` captures most recent error without PII
|
|
1349
|
+
*
|
|
1350
|
+
* v2 additions (TP-006):
|
|
1351
|
+
* - `mode` field captures workspace vs repo mode at batch start
|
|
1352
|
+
* - Task records include `repoId` and `resolvedRepoId` for repo attribution
|
|
1353
|
+
* - Lane records formalize `repoId` contract per mode
|
|
1354
|
+
* - v1 files are auto-upconverted: `mode` defaults to "repo", task/lane
|
|
1355
|
+
* `repoId` fields default to `undefined` (omitted from JSON)
|
|
1229
1356
|
*/
|
|
1230
1357
|
export interface PersistedBatchState {
|
|
1231
|
-
/** Schema version — must equal BATCH_STATE_SCHEMA_VERSION */
|
|
1358
|
+
/** Schema version — must equal BATCH_STATE_SCHEMA_VERSION (currently 2) */
|
|
1232
1359
|
schemaVersion: number;
|
|
1233
1360
|
/** Current batch execution phase */
|
|
1234
1361
|
phase: OrchBatchPhase;
|
|
@@ -1236,6 +1363,13 @@ export interface PersistedBatchState {
|
|
|
1236
1363
|
batchId: string;
|
|
1237
1364
|
/** Branch that was active when /orch started — used as base for worktrees and merge target */
|
|
1238
1365
|
baseBranch: string;
|
|
1366
|
+
/**
|
|
1367
|
+
* Workspace execution mode at batch start (v2).
|
|
1368
|
+
* - "repo": Single-repo mode (default, backward-compatible).
|
|
1369
|
+
* - "workspace": Multi-repo workspace mode.
|
|
1370
|
+
* Defaults to "repo" when loading v1 state files.
|
|
1371
|
+
*/
|
|
1372
|
+
mode: WorkspaceMode;
|
|
1239
1373
|
/** Epoch ms when batch started */
|
|
1240
1374
|
startedAt: number;
|
|
1241
1375
|
/** Epoch ms when state was last written */
|
|
@@ -1326,7 +1460,7 @@ export interface ReconciledTaskState {
|
|
|
1326
1460
|
/** Whether the lane worktree still exists on disk */
|
|
1327
1461
|
worktreeExists: boolean;
|
|
1328
1462
|
/** Action the resume engine should take */
|
|
1329
|
-
action: "reconnect" | "mark-complete" | "mark-failed" | "re-execute" | "skip";
|
|
1463
|
+
action: "reconnect" | "mark-complete" | "mark-failed" | "re-execute" | "skip" | "pending";
|
|
1330
1464
|
}
|
|
1331
1465
|
|
|
1332
1466
|
/**
|
|
@@ -1599,6 +1733,19 @@ export interface WorkspaceRoutingConfig {
|
|
|
1599
1733
|
* Must reference a valid key in `WorkspaceConfig.repos`.
|
|
1600
1734
|
*/
|
|
1601
1735
|
defaultRepo: string;
|
|
1736
|
+
/**
|
|
1737
|
+
* When true, every task MUST declare an explicit execution target
|
|
1738
|
+
* (via `## Execution Target` section or inline `**Repo:**` in PROMPT.md).
|
|
1739
|
+
* Area-level and workspace-default fallbacks are still used for
|
|
1740
|
+
* validation (unknown-repo checks) but NOT for automatic resolution.
|
|
1741
|
+
*
|
|
1742
|
+
* This prevents accidental misrouting in large multi-team workspaces
|
|
1743
|
+
* where task authors must be intentional about which repo a task targets.
|
|
1744
|
+
*
|
|
1745
|
+
* Default: false (permissive — existing precedence chain applies).
|
|
1746
|
+
* Only meaningful in workspace mode.
|
|
1747
|
+
*/
|
|
1748
|
+
strict?: boolean;
|
|
1602
1749
|
}
|
|
1603
1750
|
|
|
1604
1751
|
/**
|