taskplane 0.25.6 → 0.25.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.
@@ -30,12 +30,14 @@ import {
30
30
  runtimeRegistryPath,
31
31
  runtimeAgentEventsPath,
32
32
  runtimeLaneSnapshotPath,
33
+ runtimeMergeSnapshotPath,
33
34
  validateAgentManifest,
34
35
  type RuntimeAgentId,
35
36
  type RuntimeAgentManifest,
36
37
  type RuntimeAgentRole,
37
38
  type RuntimeAgentStatus,
38
39
  type RuntimeRegistry,
40
+ type RuntimeMergeSnapshot,
39
41
  type PacketPaths,
40
42
  } from "./types.ts";
41
43
 
@@ -362,3 +364,53 @@ export function readLaneSnapshot(
362
364
  return null;
363
365
  }
364
366
  }
367
+
368
+ /**
369
+ * Write a V2 merge agent snapshot to disk (atomic rename).
370
+ *
371
+ * Stored in the `lanes/` directory alongside lane snapshots so the dashboard
372
+ * server picks it up with the same scan that reads lane-N.json files.
373
+ *
374
+ * @param stateRoot - Repository root (where `.pi/` lives)
375
+ * @param batchId - Current batch identifier
376
+ * @param mergeNumber - 1-indexed merge agent number
377
+ * @param snapshot - Snapshot data to persist
378
+ *
379
+ * @since TP-164
380
+ */
381
+ export function writeMergeSnapshot(
382
+ stateRoot: string,
383
+ batchId: string,
384
+ mergeNumber: number,
385
+ snapshot: RuntimeMergeSnapshot,
386
+ ): void {
387
+ const path = runtimeMergeSnapshotPath(stateRoot, batchId, mergeNumber);
388
+ mkdirSync(dirname(path), { recursive: true });
389
+ const tmpPath = path + ".tmp";
390
+ writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2) + "\n", "utf-8");
391
+ renameSync(tmpPath, path);
392
+ }
393
+
394
+ /**
395
+ * Read a V2 merge agent snapshot from disk.
396
+ * Returns null if the file does not exist or is unreadable.
397
+ *
398
+ * @param stateRoot - Repository root (where `.pi/` lives)
399
+ * @param batchId - Current batch identifier
400
+ * @param mergeNumber - 1-indexed merge agent number
401
+ *
402
+ * @since TP-164
403
+ */
404
+ export function readMergeSnapshot(
405
+ stateRoot: string,
406
+ batchId: string,
407
+ mergeNumber: number,
408
+ ): RuntimeMergeSnapshot | null {
409
+ try {
410
+ const p = runtimeMergeSnapshotPath(stateRoot, batchId, mergeNumber);
411
+ if (!existsSync(p)) return null;
412
+ return JSON.parse(readFileSync(p, "utf-8")) as RuntimeMergeSnapshot;
413
+ } catch {
414
+ return null;
415
+ }
416
+ }
@@ -8,7 +8,7 @@ import { join } from "path";
8
8
  import { assembleDiagnosticInput, emitDiagnosticReports } from "./diagnostic-reports.ts";
9
9
  import { runDiscovery } from "./discovery.ts";
10
10
  import { executeOrchBatch } from "./engine.ts";
11
- import { computeTransitiveDependents, execLog, executeLaneV2, executeWave, resolveCanonicalTaskPaths } from "./execution.ts";
11
+ import { buildReviewerEnv, computeTransitiveDependents, execLog, executeLaneV2, executeWave, resolveCanonicalTaskPaths } from "./execution.ts";
12
12
  import type { MonitorUpdateCallback, RuntimeBackend } from "./execution.ts";
13
13
  import { selectRuntimeBackend } from "./engine.ts";
14
14
  import { readRegistrySnapshot, isTerminalStatus, isProcessAlive } from "./process-registry.ts";
@@ -1461,7 +1461,7 @@ export async function resumeOrchBatch(
1461
1461
  const laneResult = await executeLaneV2(
1462
1462
  lane, orchConfig, laneRepoRoot, batchState.pauseSignal,
1463
1463
  workspaceRoot, !!workspaceConfig,
1464
- { ORCH_BATCH_ID: batchState.batchId },
1464
+ { ORCH_BATCH_ID: batchState.batchId, ...buildReviewerEnv(runnerConfig.reviewer) },
1465
1465
  emitAlert,
1466
1466
  );
1467
1467
  const taskResult = laneResult.tasks.find(t => t.taskId === task.taskId);
@@ -1543,7 +1543,7 @@ export async function resumeOrchBatch(
1543
1543
  const laneResult = await executeLaneV2(
1544
1544
  lane, orchConfig, reExecRepoRoot, batchState.pauseSignal,
1545
1545
  workspaceRoot, !!workspaceConfig,
1546
- { ORCH_BATCH_ID: batchState.batchId },
1546
+ { ORCH_BATCH_ID: batchState.batchId, ...buildReviewerEnv(runnerConfig.reviewer) },
1547
1547
  emitAlert,
1548
1548
  );
1549
1549
  const taskResult = laneResult.tasks.find(t => t.taskId === task.taskId);
@@ -1994,6 +1994,7 @@ export async function resumeOrchBatch(
1994
1994
  resumeBackend,
1995
1995
  emitAlert,
1996
1996
  supervisorAutonomy,
1997
+ runnerConfig.reviewer,
1997
1998
  );
1998
1999
 
1999
2000
  batchState.waveResults.push(waveResult);
@@ -291,6 +291,19 @@ export interface TaskRunnerConfig {
291
291
  * @since TP-055
292
292
  */
293
293
  model_fallback?: "inherit" | "fail";
294
+ /**
295
+ * Reviewer agent model/thinking/tools configuration.
296
+ * Threaded through to `spawnReviewer()` via env vars.
297
+ * @since TP-160
298
+ */
299
+ reviewer?: {
300
+ /** Model string (empty = inherit session default) */
301
+ model: string;
302
+ /** Thinking mode ("on" | "off" | budget string, empty = inherit) */
303
+ thinking: string;
304
+ /** Comma-separated tool allowlist */
305
+ tools: string;
306
+ };
294
307
  }
295
308
 
296
309
  /** Result of a preflight check */
@@ -4062,6 +4075,50 @@ export function runtimeLaneSnapshotPath(stateRoot: string, batchId: string, lane
4062
4075
  return `${stateRoot}/.pi/runtime/${batchId}/lanes/lane-${laneNumber}.json`;
4063
4076
  }
4064
4077
 
4078
+ /**
4079
+ * Telemetry snapshot for a merge agent.
4080
+ *
4081
+ * Written to `.pi/runtime/{batchId}/lanes/merge-{mergeNumber}.json` alongside
4082
+ * lane snapshots so the dashboard can display live merge-phase telemetry.
4083
+ * Follows the same file-backed pattern as {@link RuntimeLaneSnapshot} but is
4084
+ * simpler — merge agents have no reviewer, progress tracking, or repoId.
4085
+ *
4086
+ * @since TP-164
4087
+ */
4088
+ export interface RuntimeMergeSnapshot {
4089
+ /** Batch this merge agent belongs to */
4090
+ batchId: string;
4091
+ /** 1-indexed merge agent number (e.g. 1 for "orch-henry-merge-1") */
4092
+ mergeNumber: number;
4093
+ /** Stable agent session name (e.g. "orch-henry-merge-1") */
4094
+ sessionName: string;
4095
+ /** Wave index this merge agent is processing (0-indexed, 0 when unknown) */
4096
+ waveIndex: number;
4097
+ /** Merge agent lifecycle status */
4098
+ status: "running" | "complete" | "failed";
4099
+ /** Live telemetry snapshot for the merge agent (null when not yet started) */
4100
+ agent: RuntimeAgentTelemetrySnapshot | null;
4101
+ /** Epoch ms when this snapshot was last updated */
4102
+ updatedAt: number;
4103
+ }
4104
+
4105
+ /**
4106
+ * Resolve the path for a merge agent snapshot file.
4107
+ *
4108
+ * Snapshots are stored alongside lane snapshots in the `lanes/` directory so
4109
+ * the dashboard server's directory scan picks them up automatically.
4110
+ *
4111
+ * @param stateRoot - Repository root (where `.pi/` lives)
4112
+ * @param batchId - Current batch identifier
4113
+ * @param mergeNumber - 1-indexed merge agent number
4114
+ * @returns Absolute path to the merge snapshot JSON file
4115
+ *
4116
+ * @since TP-164
4117
+ */
4118
+ export function runtimeMergeSnapshotPath(stateRoot: string, batchId: string, mergeNumber: number): string {
4119
+ return `${stateRoot}/.pi/runtime/${batchId}/lanes/merge-${mergeNumber}.json`;
4120
+ }
4121
+
4065
4122
  /**
4066
4123
  * Resolve the path for the batch runtime registry.
4067
4124
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.25.6",
3
+ "version": "0.25.8",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",