@martintrojer/mu 0.4.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -62,13 +62,13 @@ declare class SchemaTooOldError extends Error implements HasNextSteps {
62
62
  constructor(detectedVersion: number, requiredVersion: number);
63
63
  errorNextSteps(): NextStep[];
64
64
  }
65
- /** The schema version a fresh DB starts at. v7 drops the
66
- * `approvals` table on top of v6 (which added 5 archive_* tables
67
- * on top of v5's surrogate-PK substrate; docs/ARCHITECTURE.md §
68
- * Surrogate-PK + SDK-boundary discipline). The refusal floor is
69
- * v5 — pre-v5 DBs throw `SchemaTooOldError`; v5 v6 → v7 DBs
70
- * are forward-bumped in place by `applySchema`. */
71
- declare const CURRENT_SCHEMA_VERSION = 7;
65
+ /** The schema version a fresh DB starts at. v8 adds the
66
+ * machine_identity and workstream_sync sync substrate on top of v7
67
+ * (which dropped the approvals table), v6 (which added 5 archive_*
68
+ * tables), and v5's surrogate-PK substrate. The refusal floor is
69
+ * v5 — pre-v5 DBs throw `SchemaTooOldError`; v5+ DBs are
70
+ * forward-bumped in place by `applySchema`. */
71
+ declare const CURRENT_SCHEMA_VERSION = 8;
72
72
  /** Tables a healthy DB must contain. Single source of truth so
73
73
  * `mu doctor` and any other consumer don't drift. Adding a new table
74
74
  * = one new entry here AND a CREATE TABLE in CURRENT_SCHEMA. (Schema
@@ -471,23 +471,11 @@ declare namespace tmux$1 {
471
471
  /**
472
472
  * What kind of reconciliation pass to run.
473
473
  *
474
- * "full" Default for `mu agent list`. Prunes ghosts (deleting
475
- * the registry row, which fires the deleteAgent reaper
476
- * that flips IN_PROGRESS tasks back to OPEN with
477
- * [reaper] notes), runs status detection against
478
- * surviving panes, surfaces orphans.
479
- *
480
- * "status-only" The "freshen the operator's view" mode. Runs status
481
- * detection (DB writes that update agent status +
482
- * pane title — desired side-effects of a refresh) and
483
- * orphan surface. Does NOT prune (so a dead pane's
484
- * row stays visible until a real `mu agent list`) and
485
- * does NOT reap. Used by `mu state` and
486
- * `mu agent attach` — the verbs an operator polls to
487
- * answer "is worker-X busy or idle right
488
- * now?". Status detection skips placeholder agents
489
- * whose pane id starts with `%pending-` (mid-spawn,
490
- * no usable scrollback yet).
474
+ * "full" Default for `mu state` and `mu agent list`. Prunes
475
+ * ghosts (deleting the registry row, which fires the
476
+ * deleteAgent reaper that flips IN_PROGRESS tasks back
477
+ * to OPEN with [reaper] notes), runs status detection
478
+ * against surviving panes, surfaces orphans.
491
479
  *
492
480
  * "report-only" Pure observation. Counts would-be-pruned ghosts
493
481
  * without deleting; skips status detection entirely
@@ -498,13 +486,11 @@ declare namespace tmux$1 {
498
486
  * snap_undo_reconcile_destroys_recovered_agents) and
499
487
  * `mu doctor` (read-only diagnostic).
500
488
  *
501
- * Surfaced live by bug_pane_title_glyph_stuck_at_needs_input: the
502
- * old `dryRun: boolean` flag conflated "don't prune" with "don't
503
- * detect status", so state-card pollers showed stale status
504
- * indefinitely. Splitting prune-suppression from status-suppression
505
- * is the fix.
489
+ * Mid-spawn placeholders are protected directly in the prune loop, so read
490
+ * paths no longer need a separate mode just to avoid racing spawn's workspace
491
+ * pre-stage.
506
492
  */
507
- type ReconcileMode = "full" | "status-only" | "report-only";
493
+ type ReconcileMode = "full" | "report-only";
508
494
  interface ReconcileOptions {
509
495
  /** The workstream whose registry rows we're reconciling. */
510
496
  workstream: string;
@@ -526,9 +512,9 @@ interface ReconcileOptions {
526
512
  mode?: ReconcileMode;
527
513
  }
528
514
  interface ReconcileReport {
529
- /** Number of registry rows whose pane was gone. In status-only and
530
- * report-only modes this is the count of rows that WOULD have
531
- * been pruned; in `full` mode it's the count actually deleted. */
515
+ /** Number of registry rows whose pane was gone. In `report-only` mode
516
+ * this is the count of rows that WOULD have been pruned; in `full`
517
+ * mode it's the count actually deleted. */
532
518
  prunedGhosts: number;
533
519
  /** Number of agents whose status was changed by scrollback detection.
534
520
  * Always 0 in `report-only` mode (status detection is skipped). */
@@ -1287,6 +1273,9 @@ declare function updateAgentStatus(db: Db, name: string, status: AgentStatus, wo
1287
1273
  * initial render before status detection runs, and 'spawning' is a
1288
1274
  * transient state. */
1289
1275
  declare const STATUS_EMOJI: Record<AgentStatus, string>;
1276
+ /** Single rendering helper for agent status glyphs. Keep callers off
1277
+ * STATUS_EMOJI indexing so glyph fallback policy stays centralised. */
1278
+ declare function agentStatusGlyph(status: AgentStatus): string;
1290
1279
  /** Build the pane title for `agent` based on current DB state.
1291
1280
  * Pure (no tmux side effect; no DB write). Read-only on the DB. */
1292
1281
  declare function composeAgentTitle(db: Db, agent: AgentRow): string;
@@ -1411,22 +1400,16 @@ interface ListLiveAgentsOptions {
1411
1400
  /**
1412
1401
  * Which kind of reconciliation pass to run. Forwarded to
1413
1402
  * `reconcile()`'s same-name option. Default `"full"` (the
1414
- * documented mutating behaviour `mu agent list` has always had).
1403
+ * documented mutating behaviour `mu agent list` has always had,
1404
+ * now also used by `mu state` and `mu agent attach`).
1415
1405
  *
1416
- * Read-only callers split two ways:
1417
- * - `mu state`, `mu agent attach`
1418
- * `"status-only"`: refresh status + title (writes to DB),
1419
- * skip prune + reap. The operator's primary signal
1420
- * (busy/needs_input) stays fresh without a periodic poll
1421
- * racing in-flight spawns.
1422
- * - `mu doctor`, `mu undo` → `"report-only"`: count drift,
1423
- * mutate nothing. `mu undo` MUST use this so a post-restore
1424
- * reconcile doesn't delete the rows the snapshot just
1425
- * restored (snap_undo_reconcile_destroys_recovered_agents).
1406
+ * `mu doctor` and `mu undo` pass `"report-only"`: count drift,
1407
+ * mutate nothing. `mu undo` MUST use this so a post-restore
1408
+ * reconcile doesn't delete the rows the snapshot just restored
1409
+ * (snap_undo_reconcile_destroys_recovered_agents).
1426
1410
  *
1427
- * Skipping prune is what protects mid-spawn placeholders (pane
1428
- * id `%pending-<name>`) from being treated as ghosts and pruned
1429
- * out from under `createWorkspace`'s FK insert
1411
+ * Mid-spawn placeholders (pane id `%pending-<name>`) are protected
1412
+ * directly in reconcile's prune loop, independent of mode
1430
1413
  * (bug_agent_spawn_workspace_fk_failure).
1431
1414
  *
1432
1415
  * BREAKING: this replaces the previous `dryRun?: boolean`
@@ -1445,11 +1428,10 @@ interface LiveAgentsView {
1445
1428
  }
1446
1429
  /**
1447
1430
  * Return the live, reality-reconciled view of agents in a workstream.
1448
- * `mu agent list` calls this with `mode: "full"` (mutating); status
1449
- * pollers (`mu state`, `mu agent attach`) call it with
1450
- * `mode: "status-only"` to refresh status without pruning; read-only
1451
- * diagnostic / restore paths (`mu doctor`, `mu undo`) call it with
1452
- * `mode: "report-only"` to mutate nothing at all.
1431
+ * `mu state`, `mu agent list`, and `mu agent attach` call this with the
1432
+ * default `mode: "full"` (mutating); read-only diagnostic / restore paths
1433
+ * (`mu doctor`, `mu undo`) call it with `mode: "report-only"` to mutate
1434
+ * nothing at all.
1453
1435
  */
1454
1436
  declare function listLiveAgents(db: Db, opts: ListLiveAgentsOptions): Promise<LiveAgentsView>;
1455
1437
 
@@ -1636,6 +1618,26 @@ interface SearchArchivesOptions {
1636
1618
  /** LIKE-search archived task titles AND archived note content. */
1637
1619
  declare function searchArchives(db: Db, opts: SearchArchivesOptions): ArchiveSearchHit[];
1638
1620
 
1621
+ declare class ArchiveSourceAmbiguousError extends Error implements HasNextSteps {
1622
+ readonly label: string;
1623
+ readonly sources: readonly string[];
1624
+ readonly name = "ArchiveSourceAmbiguousError";
1625
+ constructor(label: string, sources: readonly string[]);
1626
+ errorNextSteps(): NextStep[];
1627
+ }
1628
+ interface RestoreArchiveOptions {
1629
+ sourceWorkstream?: string;
1630
+ }
1631
+ interface RestoreArchiveResult {
1632
+ archiveLabel: string;
1633
+ sourceWorkstream: string;
1634
+ workstreamName: string;
1635
+ restoredTasks: number;
1636
+ restoredEdges: number;
1637
+ restoredNotes: number;
1638
+ }
1639
+ declare function restoreArchive(db: Db, label: string, asWorkstream: string, opts?: RestoreArchiveOptions): RestoreArchiveResult;
1640
+
1639
1641
  type TaskStatus = "OPEN" | "IN_PROGRESS" | "CLOSED" | "REJECTED" | "DEFERRED";
1640
1642
  /** Every legal task status, in canonical order (matches the schema
1641
1643
  * CHECK clause). Exported so CLI surfaces (`--status` validators,
@@ -2860,6 +2862,164 @@ declare function loadFullDag(db: Db, workstream: string, opts?: LoadFullDagOptio
2860
2862
  declare function renderForest(roots: readonly TaskRow[], edges: ReadonlyMap<string, readonly string[]>, statusFn: TaskStatusLabelFn, tasksByName?: ReadonlyMap<string, TaskRow>, opts?: RenderTreeOptions): string;
2861
2863
  declare function renderTaskTree(db: Db, workstream: string, root: TaskRow, direction: "blockers" | "dependents", statusFn: TaskStatusLabelFn, opts?: RenderTreeOptions): string;
2862
2864
 
2865
+ declare class DbReplayWorkstreamMissingError extends Error implements HasNextSteps {
2866
+ readonly workstream: string;
2867
+ readonly name = "DbReplayWorkstreamMissingError";
2868
+ constructor(workstream: string);
2869
+ errorNextSteps(): NextStep[];
2870
+ }
2871
+ interface DbReplayTaskConflict {
2872
+ localId: string;
2873
+ local: {
2874
+ title: string;
2875
+ status: string;
2876
+ };
2877
+ sidecar: {
2878
+ title: string;
2879
+ status: string;
2880
+ };
2881
+ }
2882
+ declare class DbReplayLocalIdConflictError extends Error implements HasNextSteps {
2883
+ readonly workstream: string;
2884
+ readonly conflicts: readonly DbReplayTaskConflict[];
2885
+ readonly name = "DbReplayLocalIdConflictError";
2886
+ constructor(workstream: string, conflicts: readonly DbReplayTaskConflict[]);
2887
+ errorNextSteps(): NextStep[];
2888
+ }
2889
+ interface ReplayDbOptions {
2890
+ apply?: boolean;
2891
+ tasks?: readonly string[];
2892
+ notes?: readonly string[];
2893
+ all?: boolean;
2894
+ }
2895
+ interface DbReplayTaskItem {
2896
+ localId: string;
2897
+ title: string;
2898
+ status: string;
2899
+ impact: number;
2900
+ effortDays: number;
2901
+ createdAt: string;
2902
+ updatedAt: string;
2903
+ }
2904
+ interface DbReplayNoteItem {
2905
+ taskLocalId: string;
2906
+ author: string | null;
2907
+ content: string;
2908
+ createdAt: string;
2909
+ hash: string;
2910
+ }
2911
+ interface DbReplayEdgeItem {
2912
+ fromLocalId: string;
2913
+ toLocalId: string;
2914
+ createdAt: string;
2915
+ }
2916
+ interface DbReplayPlan {
2917
+ sourceFile: string;
2918
+ workstream: string;
2919
+ tasks: DbReplayTaskItem[];
2920
+ notes: DbReplayNoteItem[];
2921
+ edges: DbReplayEdgeItem[];
2922
+ conflicts: DbReplayTaskConflict[];
2923
+ }
2924
+ interface DbReplayResult extends DbReplayPlan {
2925
+ dryRun: boolean;
2926
+ applied: boolean;
2927
+ snapshotId?: number;
2928
+ added: {
2929
+ tasks: number;
2930
+ notes: number;
2931
+ edges: number;
2932
+ };
2933
+ warnings: string[];
2934
+ }
2935
+ declare function replayDb(db: Db, file: string, opts?: ReplayDbOptions): DbReplayResult;
2936
+ declare function buildReplayPlan(localDb: Db, sidecarDb: Db, sourceFile: string): DbReplayPlan;
2937
+
2938
+ interface DbExportManifestWorkstream {
2939
+ name: string;
2940
+ tasks: number;
2941
+ edges: number;
2942
+ notes: number;
2943
+ latestSeq: number;
2944
+ }
2945
+ interface DbExportManifest {
2946
+ muVersion: string;
2947
+ schemaVersion: number;
2948
+ machineId: string;
2949
+ hostname: string | null;
2950
+ exportedAt: string;
2951
+ workstreams: DbExportManifestWorkstream[];
2952
+ }
2953
+ interface ExportDbOptions {
2954
+ force?: boolean;
2955
+ }
2956
+ interface ExportDbResult {
2957
+ file: string;
2958
+ manifestPath: string;
2959
+ manifest: DbExportManifest;
2960
+ overwritten: boolean;
2961
+ }
2962
+ declare class DbExportTargetExistsError extends Error implements HasNextSteps {
2963
+ readonly file: string;
2964
+ readonly name = "DbExportTargetExistsError";
2965
+ constructor(file: string);
2966
+ errorNextSteps(): NextStep[];
2967
+ }
2968
+ declare class DbImportManifestMissingError extends Error implements HasNextSteps {
2969
+ readonly manifestPath: string;
2970
+ readonly name = "DbImportManifestMissingError";
2971
+ constructor(manifestPath: string);
2972
+ errorNextSteps(): NextStep[];
2973
+ }
2974
+ declare class DbImportSchemaTooOldError extends Error implements HasNextSteps {
2975
+ readonly sourceVersion: number;
2976
+ readonly name = "DbImportSchemaTooOldError";
2977
+ constructor(sourceVersion: number);
2978
+ errorNextSteps(): NextStep[];
2979
+ }
2980
+ declare class DbImportSchemaTooNewError extends Error implements HasNextSteps {
2981
+ readonly sourceVersion: number;
2982
+ readonly name = "DbImportSchemaTooNewError";
2983
+ constructor(sourceVersion: number);
2984
+ errorNextSteps(): NextStep[];
2985
+ }
2986
+ declare class DbImportSourceStaleError extends Error implements HasNextSteps {
2987
+ readonly workstreams: readonly string[];
2988
+ readonly name = "DbImportSourceStaleError";
2989
+ constructor(workstreams: readonly string[]);
2990
+ errorNextSteps(): NextStep[];
2991
+ }
2992
+ declare class DbImportConflictError extends Error implements HasNextSteps {
2993
+ readonly workstreams: readonly string[];
2994
+ readonly name = "DbImportConflictError";
2995
+ constructor(workstreams: readonly string[]);
2996
+ errorNextSteps(): NextStep[];
2997
+ }
2998
+ type DbImportDecision = "IDENTICAL" | "FAST_FORWARD" | "LOCAL_AHEAD" | "CONFLICT" | "IMPORT" | "LEAVE_ALONE";
2999
+ interface DbImportSummaryItem {
3000
+ workstream: string;
3001
+ decision: DbImportDecision;
3002
+ delta: Record<string, unknown>;
3003
+ needs?: string;
3004
+ parkPath?: string;
3005
+ }
3006
+ interface ImportDbOptions {
3007
+ apply?: boolean;
3008
+ forceSource?: boolean;
3009
+ onlyWorkstreams?: readonly string[];
3010
+ }
3011
+ interface ImportDbResult {
3012
+ machineId: string;
3013
+ sourceFile: string;
3014
+ dryRun: boolean;
3015
+ applied: boolean;
3016
+ snapshotId?: number;
3017
+ summary: DbImportSummaryItem[];
3018
+ }
3019
+ declare function exportDb(db: Db, file: string, opts?: ExportDbOptions): ExportDbResult;
3020
+ declare function importDb(db: Db, file: string, opts?: ImportDbOptions): ImportDbResult;
3021
+ declare function buildImportPlan(localDb: Db, manifest: DbExportManifest, sourceFile: string, onlyWorkstreams?: readonly string[]): DbImportSummaryItem[];
3022
+
2863
3023
  interface Track {
2864
3024
  /** Goal tasks (no outgoing edges) belonging to this track. */
2865
3025
  roots: TaskRow[];
@@ -3011,6 +3171,12 @@ declare function exportArchive(db: Db, opts: ExportArchiveOptions): ExportArchiv
3011
3171
  declare function isValidWorkstreamName(name: string): boolean;
3012
3172
  /** Thrown by `ensureWorkstream` and `mu workstream init` when the name
3013
3173
  * doesn't match the rules. */
3174
+ declare class WorkstreamExistsError extends Error implements HasNextSteps {
3175
+ readonly workstream: string;
3176
+ readonly name: string;
3177
+ constructor(workstream: string);
3178
+ errorNextSteps(): NextStep[];
3179
+ }
3014
3180
  declare class WorkstreamNameInvalidError extends Error implements HasNextSteps {
3015
3181
  readonly attempted: string;
3016
3182
  readonly name = "WorkstreamNameInvalidError";
@@ -3058,6 +3224,15 @@ interface WorkstreamSummary {
3058
3224
  * otherwise such rows are orphaned forever (the previous
3059
3225
  * `nothingToDo` heuristic short-circuited on them). */
3060
3226
  registered: boolean;
3227
+ /** "Presumed parked on another machine" derived signal. Present
3228
+ * iff `parkedStatus(db, name)` reports `parked: true` (most recent
3229
+ * agent_logs row is a `db export` event, no alive agents, no
3230
+ * IN_PROGRESS tasks, threshold elapsed). Consumed by
3231
+ * `mu workstream list` and the TUI tab strip / workstreams card.
3232
+ * See src/parked.ts. */
3233
+ parked?: {
3234
+ sinceDays: number;
3235
+ };
3061
3236
  }
3062
3237
  interface DestroyResult {
3063
3238
  /** True iff `tmux kill-session` actually killed something. */
@@ -3168,82 +3343,6 @@ interface ExportResult {
3168
3343
  */
3169
3344
  declare function exportWorkstream(db: Db, opts: ExportWorkstreamOptions): ExportResult;
3170
3345
 
3171
- declare class ImportBucketInvalidError extends Error implements HasNextSteps {
3172
- readonly bucketDir: string;
3173
- readonly reason: string;
3174
- readonly name = "ImportBucketInvalidError";
3175
- constructor(bucketDir: string, reason: string);
3176
- errorNextSteps(): NextStep[];
3177
- }
3178
- declare class WorkstreamAlreadyExistsError extends Error implements HasNextSteps {
3179
- readonly workstream: string;
3180
- readonly name = "WorkstreamAlreadyExistsError";
3181
- constructor(workstream: string);
3182
- errorNextSteps(): NextStep[];
3183
- }
3184
- declare class ImportFrontmatterParseError extends Error implements HasNextSteps {
3185
- readonly path: string;
3186
- readonly line: number;
3187
- readonly raw: string;
3188
- readonly name = "ImportFrontmatterParseError";
3189
- constructor(path: string, line: number, raw: string);
3190
- errorNextSteps(): NextStep[];
3191
- }
3192
- declare class ImportEdgeRefMissingError extends Error implements HasNextSteps {
3193
- readonly fromTask: string;
3194
- readonly toTask: string;
3195
- readonly direction: "blocked_by" | "blocks";
3196
- readonly name = "ImportEdgeRefMissingError";
3197
- constructor(fromTask: string, toTask: string, direction: "blocked_by" | "blocks");
3198
- errorNextSteps(): NextStep[];
3199
- }
3200
- interface ImportBucketOptions {
3201
- bucketDir: string;
3202
- /** Rename the (single) source workstream on import. Only valid when
3203
- * the bucket has exactly one source-ws subdir (after applying any
3204
- * `sourceWs` filter); otherwise rejected with an
3205
- * ImportBucketInvalidError. */
3206
- workstreamOverride?: string;
3207
- /** Restrict the import to a subset of source-ws subdirs (by name).
3208
- * Each name must be a key in the bucket manifest's `sources` map;
3209
- * otherwise ImportSourceNotInBucketError is raised. Mutually
3210
- * exclusive with the per-source-ws-subdir invocation form (Form 1):
3211
- * passing this flag against a Form 1 path raises
3212
- * ImportBucketInvalidError. Empty array is treated as "no filter";
3213
- * the CLI rejects an explicitly-empty `--source-ws ,,`. */
3214
- sourceWs?: string[];
3215
- /** Walk + parse but write nothing to the DB. */
3216
- dryRun?: boolean;
3217
- }
3218
- interface ImportSourceResult {
3219
- workstreamName: string;
3220
- tasksImported: number;
3221
- edgesImported: number;
3222
- notesImported: number;
3223
- tombstonesSkipped: number;
3224
- /** Per-source-ws errors that did NOT roll back this source. Empty
3225
- * on success. (Sibling failures live in their own entry.) */
3226
- errors: string[];
3227
- }
3228
- interface ImportBucketResult {
3229
- bucketLabel: string | null;
3230
- bucketVersion: number;
3231
- sources: ImportSourceResult[];
3232
- }
3233
- /**
3234
- * Import a v0.3 bucket directory back into the DB. One source-ws
3235
- * subdirectory becomes one workstream + N tasks + M edges + K notes.
3236
- * Per source-ws transactional: a failure in source A rolls back A
3237
- * but leaves source B's import committed.
3238
- *
3239
- * Throws on unrecoverable bucket-level errors (no manifest,
3240
- * --workstream override against multi-source). Per-source
3241
- * errors (frontmatter parse, edge ref, target name collision) leave
3242
- * the failing source's `errors` array populated and that source's
3243
- * counts at zero; siblings still attempt their own import.
3244
- */
3245
- declare function importBucket(db: Db, opts: ImportBucketOptions): ImportBucketResult;
3246
-
3247
3346
  type LogKind = "message" | "event" | "broadcast" | string;
3248
3347
  interface LogRow {
3249
3348
  /** Monotonic AUTOINCREMENT id. Use as the cursor for `--since`. */
@@ -3300,7 +3399,7 @@ declare function listLogs(db: Db, opts?: ListLogsOptions): LogRow[];
3300
3399
  * by `mu log --tail` to start the cursor at "now" so the subscriber
3301
3400
  * only sees NEW entries unless they explicitly pass `--since 0`.
3302
3401
  */
3303
- declare function latestSeq(db: Db): number;
3402
+ declare function latestSeq(db: Db, workstreamId?: number): number;
3304
3403
  /**
3305
3404
  * One-line helper for state-changing SDK functions to auto-emit a
3306
3405
  * `kind='event'` log entry. Called AFTER the mutation succeeds, only
@@ -3483,8 +3582,9 @@ declare function loadWorkstreamSnapshotFast(db: Db, workstream: string, opts?: L
3483
3582
  * doctor, which reports over those slow-tier observations). Returns only the
3484
3583
  * fields the fast snapshot deliberately leaves empty or undecorated.
3485
3584
  *
3486
- * status-only refresh: don't prune mid-spawn placeholders or reap
3487
- * unreachable agents every render-mode is a polling read surface.
3585
+ * The slow snapshot tier runs full reconciliation: missing panes are
3586
+ * reaped, while mid-spawn placeholders remain protected by the prune
3587
+ * loop's pending-pane guard.
3488
3588
  */
3489
3589
  declare function loadWorkstreamSnapshotSlow(db: Db, workstream: string, opts?: LoadWorkstreamSnapshotOptions, baseSnapshot?: WorkstreamSnapshot): Promise<WorkstreamSnapshotSlowFields>;
3490
3590
  /** Merge the latest slow-tier subprocess observations into a fresh fast tier. */
@@ -3619,4 +3719,36 @@ declare function deleteSnapshot(db: Db, snapshotId: number): DeleteSnapshotResul
3619
3719
 
3620
3720
  declare function restoreSnapshot(db: Db, snapshotId: number): RestoreSnapshotResult;
3621
3721
 
3622
- export { type AddNoteOptions, type AddTaskOptions, type AddToArchiveResult, type AdoptAgentOptions, type AdoptAgentResult, AgentDiedOnSpawnError, AgentExistsError, AgentNotFoundError, AgentNotInWorkstreamError, type AgentRow, AgentSpawnCliNotFoundError, AgentSpawnStartupError, type AgentStatus, type AppendLogOptions, type Archive, ArchiveAlreadyExistsError, ArchiveLabelInvalidError, ArchiveNotFoundError, type ArchiveSearchHit, type ArchiveSourceSummary, type ArchiveSummary, type ArchivedTaskRow, type BlockEdgeResult, CURRENT_SCHEMA_VERSION, type CaptureOptions, type CaptureSnapshotResult, type ClaimResult, type ClaimTaskOptions, ClaimerNotRegisteredError, type ClassifiedEvent, type CloseAgentOptions, type CloseAgentResult, type CommandResolutionResult, type CommandResolver, CrossWorkstreamEdgeError, CycleError, type Db, type DeleteSnapshotResult, type DeleteTaskResult, type DestroyResult, type DetectedStatus, type DoctorCheck, type DoctorStatus, type DoctorSummary, EVENT_VERB_PREFIXES, EXPECTED_TABLES, type EvidenceOption, type ExportArchiveOptions, type ExportArchiveResult, type ExportManifest, type ExportResult, type ExportSource, type ExportSourceManifest, type ExportTaskEntry, type ExportWorkstreamOptions, type FreeAgentResult, type FullDag, HomeDirAsProjectRootError, type IdFromTitleResult, ImportBucketInvalidError, type ImportBucketOptions, type ImportBucketResult, ImportEdgeRefMissingError, ImportFrontmatterParseError, type ImportSourceResult, type InsertAgentInput, type KickAgentOptions, type KickAgentResult, type KickProcessExecutor, type KickSignal, type ListArchivedTasksOptions, type ListLiveAgentsOptions, type ListLogsOptions, type ListNotesOptions, type ListReadyOptions, type ListSnapshotsOptions, type ListTasksOptions, type LiveAgentsView, type LoadFullDagOptions, type LoadWorkstreamSnapshotOptions, type LogKind, type LogRow, type NewSessionOptions, type NewWindowOptions, NoForegroundProcessError, type OpenDbOptions, type OwnedTasksSummary, PANE_ID_RE, PaneNotFoundError, type PruneMode, type PruneOptions, PruneOptionsInvalidError, type PruneResult, type ReconcileMode, type ReconcileOptions, type ReconcileReport, type RejectDeferOptions, type RejectDeferResult, type ReleaseResult, type ReleaseTaskOptions, type RemoveBlockEdgeResult, type RemoveFromArchiveResult, type RenderBucketInput, type RenderBucketResult, type ReparentTaskResult, type RestoreSnapshotResult, type RoiBucket, STATUSES_TERMINAL_OR_PARKED, STATUS_EMOJI, SchemaTooOldError, type SearchArchivesOptions, type SearchTasksOptions, type SendOptions, type SetStatusResult, type SlugifyResult, SnapshotFileMissingError, SnapshotNotFoundError, type SnapshotRow, SnapshotVersionMismatchError, type SpawnAgentOptions, type SplitWindowOptions, type StrandedWorkspaceOrphan, TASK_STATUSES, TASK_STATUS_LIST, TaskAlreadyOwnedError, type TaskEdgeWithStatus, type TaskEdges, type TaskEdgesWithStatus, TaskExistsError, TaskHasOpenDependentsError, TaskNotFoundError, TaskNotInWorkstreamError, type TaskNoteRow, type TaskRow, type TaskStatus, type TaskWaitOptions, type TaskWaitRef, type TaskWaitResult, type TaskWaitTaskState, TmuxError, type TmuxExecResult, type TmuxExecutor, type TmuxPane, type TmuxSession, type TmuxWindow, type Track, type UpdateTaskOptions, type UpdateTaskResult, type VcsBackend, type VcsBackendName, type CreateWorkspaceOptions$1 as VcsCreateWorkspaceOptions, type CreateWorkspaceResult as VcsCreateWorkspaceResult, type FreeWorkspaceOptions$1 as VcsFreeWorkspaceOptions, type FreeWorkspaceResult$1 as VcsFreeWorkspaceResult, WORKSPACE_STALE_THRESHOLD, type CreateWorkspaceOptions as WorkspaceCreateOptions, WorkspaceExistsError, type WorkspaceFailure, type FreeWorkspaceOptions as WorkspaceFreeOptions, type FreeWorkspaceResult as WorkspaceFreeResult, WorkspaceNotFoundError, type WorkspaceOrphan, WorkspacePathNotEmptyError, WorkspacePreservedError, type RecreateWorkspaceOptions as WorkspaceRecreateOptions, type RecreateWorkspaceResult as WorkspaceRecreateResult, type WorkspaceRow, type WorkspaceStaleness, WorkstreamAlreadyExistsError, WorkstreamNameInvalidError, type WorkstreamOptions, type WorkstreamSnapshot, type WorkstreamSnapshotSlowFields, type WorkstreamSummary, addBlockEdge, addNote, addTask, addToArchive, adoptAgent, agentStatusHistogram, appendLog, assertValidPaneId, backendByName, capturePane, captureSnapshot, checkCommandResolvable, claimTask, classifyEventVerb, closeAgent, closeTask, composeAgentTitle, countProblems, createArchive, createWorkspace, currentAgentName, currentPaneTitle, decorateWithDirty, decorateWithStaleness, defaultDbPath, defaultSendDelayMs, defaultSpawnLivenessMs, defaultStateDir, deferTask, deleteAgent, deleteArchive, deleteSnapshot, deleteTask, destroyWorkstream, detectBackend, detectPiStatus, emitEvent, ensureWorkstream, envVarNameForCli, exportArchive, exportSourceForWorkstream, exportSourcesForArchive, exportWorkstream, extractTail, foregroundPgid, freeAgent, freeWorkspace, gcMaxAgeDays, gcMaxCount, gcSnapshots, getAgent, getAgentByPane, getArchive, getParallelTracks, getPrerequisites, getTask, getTaskEdges, getTaskEdgesWithStatus, getWaitPollCount, getWorkspaceForAgent, getWorkspaceStaleness, gitBackend, idFromTitle, idFromTitleVerbose, importBucket, insertAgent, isKickSignal, isStaleVersion, isTaskStatus, isValidAgentName, isValidArchiveLabel, isValidPaneId, isValidTaskId, isValidWorkstreamName, isWorkspaceStale, jjBackend, kickAgent, killPane, killSession, latestSeq, listAgents, listAllOrphanWorkspaces, listArchivedTasks, listArchives, listBlocked, listGoals, listInProgress, listLiveAgents, listLogs, listNotes, listPanes, listPanesInSession, listReady, listRecentClosed, listSessions, listSnapshots, listTasks, listTasksByOwner, listWindows, listWorkspaceOrphans, listWorkspaces, listWorkstreams, loadDoctorChecks, loadDoctorSummary, loadFullDag, loadWorkstreamSnapshot, loadWorkstreamSnapshotFast, loadWorkstreamSnapshotSlow, mergeSnapshotFastSlow, newSession, newSessionWithPane, newWindow, noneBackend, openDb, openTask, paneExists, paneTTY, parseAgentNameFromTitle, parsePsTtyOutput, pruneSnapshots, readAgent, reconcile, recreateWorkspace, refreshAgentTitle, rejectTask, releaseTask, remediationParagraph, removeBlockEdge, removeFromArchive, renderForest, renderTaskTree, renderToBucket, reparentTask, resetCommandResolverForTests, resetKickProcessExecutor, resetSleep, resetTmuxExecutor, resetWaitPollCount, resolveActorIdentity, resolveCliCommand, resolveCliCommandWithSource, restoreSnapshot, roiBucket, searchArchives, searchTasks, selectLayout, sendToAgent, sendToPane, sessionExists, setCommandResolverForTests, setKickProcessExecutor, setPaneTitle, setSleepForTests, setTaskStatus, setTmuxExecutor, setWaitSleepForTests, setWaitStuckWarnForTests, slBackend, sleep, slugifyTitle, slugifyTitleVerbose, snapshotFileSize, snapshotsDir, spawnAgent, splitWindow, summarizeOwnedTasks, summarizeWorkstream, tmux$1 as tmux, updateAgentStatus, updateTask, waitForTasks, workspacePath, workspacesRoot, yankCommandForCheck };
3722
+ /** Days that must have elapsed since the most recent `db export`
3723
+ * event before a workstream is considered parked. Default 1: prevents
3724
+ * a same-session "I exported to verify" from instantly flipping the
3725
+ * TUI tab to dim. Tuning higher would just delay the banner. */
3726
+ declare const WORKSTREAM_PARKED_THRESHOLD_DAYS = 1;
3727
+ interface ParkedStatus {
3728
+ parked: boolean;
3729
+ /** Whole days since the most recent `db export` event. Present iff
3730
+ * `parked === true`. */
3731
+ sinceDays?: number;
3732
+ }
3733
+ /**
3734
+ * Compute the parked status for one workstream. Pure read; no writes.
3735
+ *
3736
+ * Returns `{ parked: false }` when:
3737
+ * - the workstream has no `db export` event in agent_logs, OR
3738
+ * - any agent_logs row newer than the most recent `db export` exists
3739
+ * (i.e. local activity since export), OR
3740
+ * - the workstream has any alive agents (status != 'closed'), OR
3741
+ * - the workstream has any IN_PROGRESS tasks, OR
3742
+ * - the most recent `db export` is younger than the threshold.
3743
+ *
3744
+ * Otherwise returns `{ parked: true, sinceDays: <whole days> }`.
3745
+ *
3746
+ * `now` defaults to wall-clock; tests pass it explicitly to keep the
3747
+ * threshold edge deterministic.
3748
+ */
3749
+ declare function parkedStatus(db: Db, workstream: string, opts?: {
3750
+ now?: Date;
3751
+ thresholdDays?: number;
3752
+ }): ParkedStatus;
3753
+
3754
+ export { type AddNoteOptions, type AddTaskOptions, type AddToArchiveResult, type AdoptAgentOptions, type AdoptAgentResult, AgentDiedOnSpawnError, AgentExistsError, AgentNotFoundError, AgentNotInWorkstreamError, type AgentRow, AgentSpawnCliNotFoundError, AgentSpawnStartupError, type AgentStatus, type AppendLogOptions, type Archive, ArchiveAlreadyExistsError, ArchiveLabelInvalidError, ArchiveNotFoundError, type ArchiveSearchHit, ArchiveSourceAmbiguousError, type ArchiveSourceSummary, type ArchiveSummary, type ArchivedTaskRow, type BlockEdgeResult, CURRENT_SCHEMA_VERSION, type CaptureOptions, type CaptureSnapshotResult, type ClaimResult, type ClaimTaskOptions, ClaimerNotRegisteredError, type ClassifiedEvent, type CloseAgentOptions, type CloseAgentResult, type CommandResolutionResult, type CommandResolver, CrossWorkstreamEdgeError, CycleError, type Db, type DbExportManifest, type DbExportManifestWorkstream, DbExportTargetExistsError, DbImportConflictError, type DbImportDecision, DbImportManifestMissingError, DbImportSchemaTooNewError, DbImportSchemaTooOldError, DbImportSourceStaleError, type DbImportSummaryItem, type DbReplayEdgeItem, DbReplayLocalIdConflictError, type DbReplayNoteItem, type DbReplayPlan, type DbReplayResult, type DbReplayTaskConflict, type DbReplayTaskItem, DbReplayWorkstreamMissingError, type DeleteSnapshotResult, type DeleteTaskResult, type DestroyResult, type DetectedStatus, type DoctorCheck, type DoctorStatus, type DoctorSummary, EVENT_VERB_PREFIXES, EXPECTED_TABLES, type EvidenceOption, type ExportArchiveOptions, type ExportArchiveResult, type ExportDbOptions, type ExportDbResult, type ExportManifest, type ExportResult, type ExportSource, type ExportSourceManifest, type ExportTaskEntry, type ExportWorkstreamOptions, type FreeAgentResult, type FullDag, HomeDirAsProjectRootError, type IdFromTitleResult, type ImportDbOptions, type ImportDbResult, type InsertAgentInput, type KickAgentOptions, type KickAgentResult, type KickProcessExecutor, type KickSignal, type ListArchivedTasksOptions, type ListLiveAgentsOptions, type ListLogsOptions, type ListNotesOptions, type ListReadyOptions, type ListSnapshotsOptions, type ListTasksOptions, type LiveAgentsView, type LoadFullDagOptions, type LoadWorkstreamSnapshotOptions, type LogKind, type LogRow, type NewSessionOptions, type NewWindowOptions, NoForegroundProcessError, type OpenDbOptions, type OwnedTasksSummary, PANE_ID_RE, PaneNotFoundError, type ParkedStatus, type PruneMode, type PruneOptions, PruneOptionsInvalidError, type PruneResult, type ReconcileMode, type ReconcileOptions, type ReconcileReport, type RejectDeferOptions, type RejectDeferResult, type ReleaseResult, type ReleaseTaskOptions, type RemoveBlockEdgeResult, type RemoveFromArchiveResult, type RenderBucketInput, type RenderBucketResult, type ReparentTaskResult, type ReplayDbOptions, type RestoreArchiveOptions, type RestoreArchiveResult, type RestoreSnapshotResult, type RoiBucket, STATUSES_TERMINAL_OR_PARKED, STATUS_EMOJI, SchemaTooOldError, type SearchArchivesOptions, type SearchTasksOptions, type SendOptions, type SetStatusResult, type SlugifyResult, SnapshotFileMissingError, SnapshotNotFoundError, type SnapshotRow, SnapshotVersionMismatchError, type SpawnAgentOptions, type SplitWindowOptions, type StrandedWorkspaceOrphan, TASK_STATUSES, TASK_STATUS_LIST, TaskAlreadyOwnedError, type TaskEdgeWithStatus, type TaskEdges, type TaskEdgesWithStatus, TaskExistsError, TaskHasOpenDependentsError, TaskNotFoundError, TaskNotInWorkstreamError, type TaskNoteRow, type TaskRow, type TaskStatus, type TaskWaitOptions, type TaskWaitRef, type TaskWaitResult, type TaskWaitTaskState, TmuxError, type TmuxExecResult, type TmuxExecutor, type TmuxPane, type TmuxSession, type TmuxWindow, type Track, type UpdateTaskOptions, type UpdateTaskResult, type VcsBackend, type VcsBackendName, type CreateWorkspaceOptions$1 as VcsCreateWorkspaceOptions, type CreateWorkspaceResult as VcsCreateWorkspaceResult, type FreeWorkspaceOptions$1 as VcsFreeWorkspaceOptions, type FreeWorkspaceResult$1 as VcsFreeWorkspaceResult, WORKSPACE_STALE_THRESHOLD, WORKSTREAM_PARKED_THRESHOLD_DAYS, type CreateWorkspaceOptions as WorkspaceCreateOptions, WorkspaceExistsError, type WorkspaceFailure, type FreeWorkspaceOptions as WorkspaceFreeOptions, type FreeWorkspaceResult as WorkspaceFreeResult, WorkspaceNotFoundError, type WorkspaceOrphan, WorkspacePathNotEmptyError, WorkspacePreservedError, type RecreateWorkspaceOptions as WorkspaceRecreateOptions, type RecreateWorkspaceResult as WorkspaceRecreateResult, type WorkspaceRow, type WorkspaceStaleness, WorkstreamExistsError, WorkstreamNameInvalidError, type WorkstreamOptions, type WorkstreamSnapshot, type WorkstreamSnapshotSlowFields, type WorkstreamSummary, addBlockEdge, addNote, addTask, addToArchive, adoptAgent, agentStatusGlyph, agentStatusHistogram, appendLog, assertValidPaneId, backendByName, buildImportPlan, buildReplayPlan, capturePane, captureSnapshot, checkCommandResolvable, claimTask, classifyEventVerb, closeAgent, closeTask, composeAgentTitle, countProblems, createArchive, createWorkspace, currentAgentName, currentPaneTitle, decorateWithDirty, decorateWithStaleness, defaultDbPath, defaultSendDelayMs, defaultSpawnLivenessMs, defaultStateDir, deferTask, deleteAgent, deleteArchive, deleteSnapshot, deleteTask, destroyWorkstream, detectBackend, detectPiStatus, emitEvent, ensureWorkstream, envVarNameForCli, exportArchive, exportDb, exportSourceForWorkstream, exportSourcesForArchive, exportWorkstream, extractTail, foregroundPgid, freeAgent, freeWorkspace, gcMaxAgeDays, gcMaxCount, gcSnapshots, getAgent, getAgentByPane, getArchive, getParallelTracks, getPrerequisites, getTask, getTaskEdges, getTaskEdgesWithStatus, getWaitPollCount, getWorkspaceForAgent, getWorkspaceStaleness, gitBackend, idFromTitle, idFromTitleVerbose, importDb, insertAgent, isKickSignal, isStaleVersion, isTaskStatus, isValidAgentName, isValidArchiveLabel, isValidPaneId, isValidTaskId, isValidWorkstreamName, isWorkspaceStale, jjBackend, kickAgent, killPane, killSession, latestSeq, listAgents, listAllOrphanWorkspaces, listArchivedTasks, listArchives, listBlocked, listGoals, listInProgress, listLiveAgents, listLogs, listNotes, listPanes, listPanesInSession, listReady, listRecentClosed, listSessions, listSnapshots, listTasks, listTasksByOwner, listWindows, listWorkspaceOrphans, listWorkspaces, listWorkstreams, loadDoctorChecks, loadDoctorSummary, loadFullDag, loadWorkstreamSnapshot, loadWorkstreamSnapshotFast, loadWorkstreamSnapshotSlow, mergeSnapshotFastSlow, newSession, newSessionWithPane, newWindow, noneBackend, openDb, openTask, paneExists, paneTTY, parkedStatus, parseAgentNameFromTitle, parsePsTtyOutput, pruneSnapshots, readAgent, reconcile, recreateWorkspace, refreshAgentTitle, rejectTask, releaseTask, remediationParagraph, removeBlockEdge, removeFromArchive, renderForest, renderTaskTree, renderToBucket, reparentTask, replayDb, resetCommandResolverForTests, resetKickProcessExecutor, resetSleep, resetTmuxExecutor, resetWaitPollCount, resolveActorIdentity, resolveCliCommand, resolveCliCommandWithSource, restoreArchive, restoreSnapshot, roiBucket, searchArchives, searchTasks, selectLayout, sendToAgent, sendToPane, sessionExists, setCommandResolverForTests, setKickProcessExecutor, setPaneTitle, setSleepForTests, setTaskStatus, setTmuxExecutor, setWaitSleepForTests, setWaitStuckWarnForTests, slBackend, sleep, slugifyTitle, slugifyTitleVerbose, snapshotFileSize, snapshotsDir, spawnAgent, splitWindow, summarizeOwnedTasks, summarizeWorkstream, tmux$1 as tmux, updateAgentStatus, updateTask, waitForTasks, workspacePath, workspacesRoot, yankCommandForCheck };