taskplane 0.10.2 → 0.12.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.
@@ -134,6 +134,13 @@ export interface TaskRunnerConfig {
134
134
  reference_docs: Record<string, string>;
135
135
  /** Named testing/verification commands (e.g., { test: "npx vitest run" }). Used for baseline fingerprinting (TP-032). */
136
136
  testing_commands?: Record<string, string>;
137
+ /**
138
+ * Model fallback behavior when a configured model becomes unavailable mid-batch.
139
+ * - `"inherit"` (default): Retry without explicit model (session model fallback).
140
+ * - `"fail"`: No model substitution — normal failure path.
141
+ * @since TP-055
142
+ */
143
+ model_fallback?: "inherit" | "fail";
137
144
  }
138
145
 
139
146
  /** Result of a preflight check */
@@ -204,6 +211,7 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
204
211
  export const DEFAULT_TASK_RUNNER_CONFIG: TaskRunnerConfig = {
205
212
  task_areas: {},
206
213
  reference_docs: {},
214
+ model_fallback: "inherit",
207
215
  };
208
216
 
209
217
 
@@ -1268,6 +1276,100 @@ export const MERGE_SPAWN_RETRY_MAX = 2;
1268
1276
  */
1269
1277
  export const MERGE_TIMEOUT_MAX_RETRIES = 2;
1270
1278
 
1279
+ // ── Merge Health Monitoring Constants (TP-056) ───────────────────────
1280
+
1281
+ /**
1282
+ * Polling interval for merge health monitor (ms).
1283
+ * Independent of the merge result poll — runs on its own cadence.
1284
+ * @since TP-056
1285
+ */
1286
+ export const MERGE_HEALTH_POLL_INTERVAL_MS = 2 * 60 * 1000; // 2 minutes
1287
+
1288
+ /**
1289
+ * Threshold (ms) after which a merge session with no new output
1290
+ * is classified as "possibly stalled" and a warning event is emitted.
1291
+ * @since TP-056
1292
+ */
1293
+ export const MERGE_HEALTH_WARNING_THRESHOLD_MS = 10 * 60 * 1000; // 10 minutes
1294
+
1295
+ /**
1296
+ * Threshold (ms) after which a merge session with no new output
1297
+ * is classified as "stuck" and a stuck event is emitted.
1298
+ * @since TP-056
1299
+ */
1300
+ export const MERGE_HEALTH_STUCK_THRESHOLD_MS = 20 * 60 * 1000; // 20 minutes
1301
+
1302
+ /**
1303
+ * Number of lines to capture from the bottom of a tmux pane
1304
+ * for activity detection via snapshot comparison.
1305
+ * @since TP-056
1306
+ */
1307
+ export const MERGE_HEALTH_CAPTURE_LINES = 10;
1308
+
1309
+ // ── Merge Health Event Types (TP-056) ────────────────────────────────
1310
+
1311
+ /**
1312
+ * Health classification for a merge session.
1313
+ *
1314
+ * - `healthy`: Session alive, output changing
1315
+ * - `warning`: Session alive, no new output for MERGE_HEALTH_WARNING_THRESHOLD_MS
1316
+ * - `dead`: Session gone, no result file
1317
+ * - `stuck`: Session alive, no new output for MERGE_HEALTH_STUCK_THRESHOLD_MS
1318
+ *
1319
+ * @since TP-056
1320
+ */
1321
+ export type MergeHealthStatus = "healthy" | "warning" | "dead" | "stuck";
1322
+
1323
+ /**
1324
+ * Engine event types for merge health monitoring.
1325
+ *
1326
+ * These extend the EngineEventType union and are emitted to the
1327
+ * unified events.jsonl for supervisor consumption.
1328
+ *
1329
+ * @since TP-056
1330
+ */
1331
+ export type MergeHealthEventType =
1332
+ | "merge_health_warning"
1333
+ | "merge_health_dead"
1334
+ | "merge_health_stuck";
1335
+
1336
+ /**
1337
+ * Snapshot of a merge session's pane output at a point in time.
1338
+ * Used for activity detection by comparing successive snapshots.
1339
+ *
1340
+ * @since TP-056
1341
+ */
1342
+ export interface MergeSessionSnapshot {
1343
+ /** Captured pane content (last N lines) */
1344
+ content: string;
1345
+ /** Epoch ms when the snapshot was taken */
1346
+ capturedAt: number;
1347
+ }
1348
+
1349
+ /**
1350
+ * Per-session health tracking state.
1351
+ *
1352
+ * @since TP-056
1353
+ */
1354
+ export interface MergeSessionHealthState {
1355
+ /** TMUX session name */
1356
+ sessionName: string;
1357
+ /** Lane number this session belongs to */
1358
+ laneNumber: number;
1359
+ /** Last captured pane snapshot */
1360
+ lastSnapshot: MergeSessionSnapshot | null;
1361
+ /** Epoch ms when the last output change was detected */
1362
+ lastActivityAt: number;
1363
+ /** Current health classification */
1364
+ status: MergeHealthStatus;
1365
+ /** Whether a warning event has been emitted (prevent duplicates) */
1366
+ warningEmitted: boolean;
1367
+ /** Whether a stuck event has been emitted (prevent duplicates) */
1368
+ stuckEmitted: boolean;
1369
+ /** Whether a dead event has been emitted (prevent duplicates) */
1370
+ deadEmitted: boolean;
1371
+ }
1372
+
1271
1373
 
1272
1374
  // ── Merge Retry Policy Matrix (TP-033 Step 2) ───────────────────────
1273
1375
 
@@ -1384,7 +1486,8 @@ export const MERGE_FAILURE_CLASSIFICATIONS: readonly MergeFailureClassification[
1384
1486
  export type Tier0RecoveryPattern =
1385
1487
  | "worker_crash"
1386
1488
  | "stale_worktree"
1387
- | "cleanup_gate";
1489
+ | "cleanup_gate"
1490
+ | "model_fallback";
1388
1491
 
1389
1492
  /**
1390
1493
  * Exit classifications that are eligible for automatic Tier 0 retry.
@@ -1398,6 +1501,7 @@ export type Tier0RecoveryPattern =
1398
1501
  */
1399
1502
  export const TIER0_RETRYABLE_CLASSIFICATIONS: ReadonlySet<string> = new Set([
1400
1503
  "api_error",
1504
+ "model_access_error",
1401
1505
  "process_crash",
1402
1506
  "session_vanished",
1403
1507
  ]);
@@ -1444,6 +1548,11 @@ export const TIER0_RETRY_BUDGETS: Readonly<Record<Tier0RecoveryPattern, Tier0Ret
1444
1548
  cooldownMs: 2_000,
1445
1549
  backoffMultiplier: 1.0,
1446
1550
  },
1551
+ model_fallback: {
1552
+ maxRetries: 1,
1553
+ cooldownMs: 3_000,
1554
+ backoffMultiplier: 1.0,
1555
+ },
1447
1556
  };
1448
1557
 
1449
1558
  /**
@@ -1457,6 +1566,7 @@ export const TIER0_RETRY_BUDGETS: Readonly<Record<Tier0RecoveryPattern, Tier0Ret
1457
1566
  * @since TP-039
1458
1567
  */
1459
1568
  export type Tier0EscalationPattern = Tier0RecoveryPattern | "merge_timeout";
1569
+ // Note: model_fallback is already included via Tier0RecoveryPattern
1460
1570
 
1461
1571
  /**
1462
1572
  * Context payload emitted when Tier 0 retries are exhausted and the
@@ -1541,6 +1651,9 @@ export type EngineEventType =
1541
1651
  | "merge_start"
1542
1652
  | "merge_success"
1543
1653
  | "merge_failed"
1654
+ | "merge_health_warning"
1655
+ | "merge_health_dead"
1656
+ | "merge_health_stuck"
1544
1657
  | "batch_complete"
1545
1658
  | "batch_paused";
1546
1659
 
@@ -1606,6 +1719,15 @@ export interface EngineEvent {
1606
1719
  blockedTasks?: number;
1607
1720
  /** Batch duration in milliseconds (for batch_complete) */
1608
1721
  batchDurationMs?: number;
1722
+
1723
+ // ── Merge health monitoring fields (TP-056) ──────────────────
1724
+
1725
+ /** TMUX session name (for merge_health_* events) */
1726
+ sessionName?: string;
1727
+ /** Merge health status classification (for merge_health_* events) */
1728
+ healthStatus?: MergeHealthStatus;
1729
+ /** Minutes since last activity (for merge_health_warning, merge_health_stuck) */
1730
+ stalledMinutes?: number;
1609
1731
  }
1610
1732
 
1611
1733
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.10.2",
3
+ "version": "0.12.0",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",