@agentproto/runtime 5.2.1 → 5.3.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/README.md +18 -0
- package/dist/bundles.d.ts +67 -0
- package/dist/bundles.mjs +173 -0
- package/dist/bundles.mjs.map +1 -0
- package/dist/catalog-models.d.ts +2 -3
- package/dist/config-DcESQDmZ.d.ts +748 -0
- package/dist/config-schema.d.ts +9 -3
- package/dist/config-schema.mjs +134 -12
- package/dist/config-schema.mjs.map +1 -1
- package/dist/config.d.ts +2 -611
- package/dist/config.mjs +141 -14
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +674 -541
- package/dist/index.mjs +10599 -4135
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-imports.d.ts +73 -1
- package/dist/mcp-imports.mjs +146 -4
- package/dist/mcp-imports.mjs.map +1 -1
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/{session-config-RyRL2AbD.d.ts → session-config-DxIIuJFY.d.ts} +1 -1
- package/dist/session-presence.mjs +132 -11
- package/dist/session-presence.mjs.map +1 -1
- package/dist/session-story.mjs +1 -0
- package/dist/session-story.mjs.map +1 -1
- package/dist/{sessions-g4fw_zKx.d.ts → sessions-DKm6Wqro.d.ts} +647 -12
- package/dist/{spawn-defaults-CHvz85DD.d.ts → spawn-defaults-Cp9SGZex.d.ts} +103 -2
- package/dist/user-presets.d.ts +5 -3
- package/package.json +45 -32
- package/dist/context-continuity-BfNVbX5W.d.ts +0 -104
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { R as RouteSpec, S as SessionConfig, P as Posture, E as EffortLevel, C as ContextProfile, A as AuthMethod } from './session-config-
|
|
3
|
-
import {
|
|
2
|
+
import { R as RouteSpec, S as SessionConfig, P as Posture, E as EffortLevel, C as ContextProfile, A as AuthMethod } from './session-config-DxIIuJFY.js';
|
|
3
|
+
import { a as SpawnBrowserMode, R as ResolvedContextContinuityPolicy } from './spawn-defaults-Cp9SGZex.js';
|
|
4
4
|
import { AcpPermissionResolution, AcpMcpServer } from '@agentproto/acp';
|
|
5
5
|
import { SessionMode } from '@agentproto/acp/client';
|
|
6
6
|
import { ChildProcess } from 'node:child_process';
|
|
7
7
|
import { CostBudget } from '@agentproto/auth';
|
|
8
|
+
import { h as WorktreeIsolationMode } from './config-DcESQDmZ.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Typed, best-effort persistence for the last-seen provider "remaining quota"
|
|
@@ -524,6 +525,210 @@ interface UsageDescriptorFields extends Omit<UsageDetail, "turns"> {
|
|
|
524
525
|
*/
|
|
525
526
|
declare function projectSessionUsage(desc: UsageDescriptorFields): SessionUsage;
|
|
526
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Per-session process-tree resource sampler - answers "which session is
|
|
530
|
+
* eating this host" without a hand-written `ps` walk.
|
|
531
|
+
*
|
|
532
|
+
* One process-table read (`ps` on macOS/Linux, `/proc` as the Linux fallback
|
|
533
|
+
* when `ps` is missing) is attributed to sessions by climbing DOWN the tree
|
|
534
|
+
* from each live session's adapter pid, which the registry already knows -
|
|
535
|
+
* no env scraping for a session whose pid is known. Whatever is left over is
|
|
536
|
+
* bucketed:
|
|
537
|
+
*
|
|
538
|
+
* - `daemon` the daemon process itself + its own non-session children
|
|
539
|
+
* - `provisioning` daemon children spawned while a worktree provision is in
|
|
540
|
+
* flight (setup hooks: `pnpm install`, builds) - work that
|
|
541
|
+
* is not attached to a session yet
|
|
542
|
+
* - `orphans` processes that look agentproto-owned (a dead session's
|
|
543
|
+
* adapter-config dir / worktree in their args, or an
|
|
544
|
+
* `AGENTPROTO_SESSION_ID` / adapter-config env marker on a
|
|
545
|
+
* reparented process) but belong to no live session.
|
|
546
|
+
* Reported only - never killed.
|
|
547
|
+
*
|
|
548
|
+
* The expensive part (table + host reads) is cached for a short TTL and
|
|
549
|
+
* de-duplicated while in flight; attribution over the cached table is pure
|
|
550
|
+
* and cheap, so a burst of `session_list`/CLI/HTTP callers costs one `ps`.
|
|
551
|
+
*
|
|
552
|
+
* `%CPU` is whatever `ps` reports: the kernel's decayed (macOS) or
|
|
553
|
+
* lifetime-average (Linux) figure, not an instantaneous delta. That is the
|
|
554
|
+
* right lens for "what has this session been costing", and the same number an
|
|
555
|
+
* operator reads off `ps`/`top` - but it lags a sudden spike.
|
|
556
|
+
*/
|
|
557
|
+
|
|
558
|
+
/** One row of the host process table. */
|
|
559
|
+
interface ProcRow {
|
|
560
|
+
pid: number;
|
|
561
|
+
ppid: number;
|
|
562
|
+
uid: number;
|
|
563
|
+
/** Resident set size in KiB (`ps` reports KiB on both macOS and Linux). */
|
|
564
|
+
rssKib: number;
|
|
565
|
+
/** `%CPU` as reported by the OS (may exceed 100 for multi-threaded work). */
|
|
566
|
+
cpuPercent: number;
|
|
567
|
+
/** Seconds since the process started. */
|
|
568
|
+
elapsedSec: number;
|
|
569
|
+
/** Full command line as one string. */
|
|
570
|
+
args: string;
|
|
571
|
+
}
|
|
572
|
+
/** Where the process table comes from. Injectable for tests. */
|
|
573
|
+
type ProcessTableSource = () => Promise<ProcRow[]>;
|
|
574
|
+
/**
|
|
575
|
+
* Collapse a raw command line to the short name an operator reads:
|
|
576
|
+
* `node …/pnpm.cjs install` → `pnpm install`, a vitest fork worker →
|
|
577
|
+
* `vitest`, `…/@esbuild/darwin-arm64/bin/esbuild --service` → `esbuild`,
|
|
578
|
+
* `…/claude-code/cli.js` → `claude`. Unrecognised node scripts stay `node`;
|
|
579
|
+
* anything else is its executable's basename (a macOS `.app` bundle is the
|
|
580
|
+
* app's name). Pure - no filesystem access.
|
|
581
|
+
*/
|
|
582
|
+
declare function normalizeCommand(args: string): string;
|
|
583
|
+
interface CommandGroupStats {
|
|
584
|
+
/** Normalized command name (`pnpm install`, `vitest`, `git`, …). */
|
|
585
|
+
name: string;
|
|
586
|
+
count: number;
|
|
587
|
+
rssBytes: number;
|
|
588
|
+
cpuPercent: number;
|
|
589
|
+
}
|
|
590
|
+
interface ProcessDetail {
|
|
591
|
+
pid: number;
|
|
592
|
+
ppid: number;
|
|
593
|
+
/** Normalized name. */
|
|
594
|
+
command: string;
|
|
595
|
+
/** Raw command line, truncated. */
|
|
596
|
+
args: string;
|
|
597
|
+
rssBytes: number;
|
|
598
|
+
cpuPercent: number;
|
|
599
|
+
elapsedSec: number;
|
|
600
|
+
/** True when the process was attributed by env/args marker rather than by
|
|
601
|
+
* descent from the session's adapter pid (a reparented stray). */
|
|
602
|
+
detached?: boolean;
|
|
603
|
+
}
|
|
604
|
+
interface ResourceStats {
|
|
605
|
+
rssBytes: number;
|
|
606
|
+
cpuPercent: number;
|
|
607
|
+
procCount: number;
|
|
608
|
+
/** Top command groups by RSS. */
|
|
609
|
+
topCommands: CommandGroupStats[];
|
|
610
|
+
/** Every process, largest RSS first - populated by `detail: "full"` only. */
|
|
611
|
+
processes?: ProcessDetail[];
|
|
612
|
+
}
|
|
613
|
+
interface SessionResourceStats extends ResourceStats {
|
|
614
|
+
sessionId: string;
|
|
615
|
+
/** The adapter pid the tree was climbed from. */
|
|
616
|
+
pid: number;
|
|
617
|
+
}
|
|
618
|
+
interface OrphanGroup extends ResourceStats {
|
|
619
|
+
/** Top of the orphaned subtree. */
|
|
620
|
+
pid: number;
|
|
621
|
+
command: string;
|
|
622
|
+
elapsedSec: number;
|
|
623
|
+
/** Session id the markers point at, when one was recoverable. */
|
|
624
|
+
sessionHint?: string;
|
|
625
|
+
/** Why this looks agentproto-owned. */
|
|
626
|
+
reason: string;
|
|
627
|
+
}
|
|
628
|
+
interface ProvisionInFlight {
|
|
629
|
+
sessionId?: string;
|
|
630
|
+
label?: string;
|
|
631
|
+
cwd: string;
|
|
632
|
+
startedAt: string;
|
|
633
|
+
}
|
|
634
|
+
interface ProvisioningStats extends ResourceStats {
|
|
635
|
+
inFlight: ProvisionInFlight[];
|
|
636
|
+
}
|
|
637
|
+
interface HostInfo {
|
|
638
|
+
platform: NodeJS.Platform;
|
|
639
|
+
cpuCount: number;
|
|
640
|
+
/** 1/5/15-minute load averages. */
|
|
641
|
+
loadAvg: [number, number, number];
|
|
642
|
+
totalMemBytes: number;
|
|
643
|
+
/** Memory available for new work - `MemAvailable` on Linux, free +
|
|
644
|
+
* reclaimable pages on macOS, `os.freemem()` elsewhere. */
|
|
645
|
+
freeMemBytes: number;
|
|
646
|
+
}
|
|
647
|
+
type StatsDetail = "summary" | "full";
|
|
648
|
+
interface ProcessStatsReport {
|
|
649
|
+
sampledAt: string;
|
|
650
|
+
detail: StatsDetail;
|
|
651
|
+
host: HostInfo;
|
|
652
|
+
sessions: SessionResourceStats[];
|
|
653
|
+
daemon: ResourceStats & {
|
|
654
|
+
pid: number;
|
|
655
|
+
};
|
|
656
|
+
provisioning: ProvisioningStats;
|
|
657
|
+
orphans: OrphanGroup[];
|
|
658
|
+
/** Sessions + daemon + provisioning. Orphans are reported separately and
|
|
659
|
+
* are NOT in this sum (they belong to nobody). */
|
|
660
|
+
totals: {
|
|
661
|
+
rssBytes: number;
|
|
662
|
+
cpuPercent: number;
|
|
663
|
+
procCount: number;
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
interface ProvisionTracker {
|
|
667
|
+
begin(info: {
|
|
668
|
+
sessionId?: string;
|
|
669
|
+
label?: string;
|
|
670
|
+
cwd: string;
|
|
671
|
+
}): () => void;
|
|
672
|
+
list(): ProvisionInFlight[];
|
|
673
|
+
}
|
|
674
|
+
/** Run `fn` (a worktree provision) with the tracker marking it in flight. */
|
|
675
|
+
declare function trackWorktreeProvision<T>(info: {
|
|
676
|
+
sessionId?: string;
|
|
677
|
+
label?: string;
|
|
678
|
+
cwd: string;
|
|
679
|
+
}, fn: () => Promise<T>, tracker?: ProvisionTracker): Promise<T>;
|
|
680
|
+
type HostInfoSource = () => Promise<HostInfo>;
|
|
681
|
+
/** Read `pid → session id` markers from the environment of `pids`. Best
|
|
682
|
+
* effort: Linux reads `/proc/<pid>/environ` (own uid only); macOS asks
|
|
683
|
+
* `ps -E`, which some hardened setups blank out - a miss just means a stray
|
|
684
|
+
* is judged by its command line alone. Never throws. */
|
|
685
|
+
type EnvHintReader = (pids: readonly number[]) => Promise<Map<number, string>>;
|
|
686
|
+
/** The slice of a registry descriptor the service reads. */
|
|
687
|
+
interface StatsSessionDescriptor {
|
|
688
|
+
id: string;
|
|
689
|
+
pid?: number | null;
|
|
690
|
+
status: string;
|
|
691
|
+
adapterConfigDir?: string;
|
|
692
|
+
worktreePath?: string;
|
|
693
|
+
label?: string;
|
|
694
|
+
name?: string;
|
|
695
|
+
kind?: string;
|
|
696
|
+
adapterSlug?: string;
|
|
697
|
+
}
|
|
698
|
+
interface ProcessStatsServiceOptions {
|
|
699
|
+
table?: ProcessTableSource;
|
|
700
|
+
host?: HostInfoSource;
|
|
701
|
+
envHints?: EnvHintReader;
|
|
702
|
+
tracker?: ProvisionTracker;
|
|
703
|
+
daemonPid?: number;
|
|
704
|
+
uid?: number;
|
|
705
|
+
/** How long a sampled table is reused. Default 3000 ms. */
|
|
706
|
+
ttlMs?: number;
|
|
707
|
+
now?: () => number;
|
|
708
|
+
}
|
|
709
|
+
interface ProcessStatsService {
|
|
710
|
+
report(sessions: readonly StatsSessionDescriptor[], opts?: {
|
|
711
|
+
detail?: StatsDetail;
|
|
712
|
+
fresh?: boolean;
|
|
713
|
+
}): Promise<ProcessStatsReport>;
|
|
714
|
+
}
|
|
715
|
+
declare function createProcessStatsService(opts?: ProcessStatsServiceOptions): ProcessStatsService;
|
|
716
|
+
/** Process-wide sampler shared by every surface (MCP, HTTP, CLI-over-HTTP),
|
|
717
|
+
* so one `ps` per TTL serves them all. */
|
|
718
|
+
declare function getProcessStatsService(): ProcessStatsService;
|
|
719
|
+
interface LabeledSessionStats extends SessionResourceStats {
|
|
720
|
+
label?: string;
|
|
721
|
+
name?: string;
|
|
722
|
+
kind?: string;
|
|
723
|
+
status: string;
|
|
724
|
+
adapterSlug?: string;
|
|
725
|
+
}
|
|
726
|
+
interface LabeledProcessStatsReport extends Omit<ProcessStatsReport, "sessions"> {
|
|
727
|
+
sessions: LabeledSessionStats[];
|
|
728
|
+
/** Set for a subtree-scoped caller: host-wide buckets are withheld. */
|
|
729
|
+
scoped?: true;
|
|
730
|
+
}
|
|
731
|
+
|
|
527
732
|
/**
|
|
528
733
|
* McpAppsHostService — the daemon as the MCP client that fetches MCP App
|
|
529
734
|
* UIs (spec 2026-01-26) on behalf of a session's chat UI.
|
|
@@ -860,7 +1065,7 @@ interface ActivityRunStepSlice {
|
|
|
860
1065
|
interface ActivityWorkflowStageSlice {
|
|
861
1066
|
index: number;
|
|
862
1067
|
label?: string;
|
|
863
|
-
status: "pending" | "running" | "done" | "failed" | "skipped";
|
|
1068
|
+
status: "pending" | "running" | "done" | "failed" | "skipped" | "cancelled";
|
|
864
1069
|
steps: readonly ActivityRunStepSlice[];
|
|
865
1070
|
}
|
|
866
1071
|
/** Structural slice of a `WorkflowRun` (`workflow_list` rows). */
|
|
@@ -1421,10 +1626,22 @@ interface CompletionPolicySupervisor {
|
|
|
1421
1626
|
*
|
|
1422
1627
|
* State machine (deliberately small):
|
|
1423
1628
|
* pending ⇄ in_progress → done | failed
|
|
1424
|
-
*
|
|
1629
|
+
* in_progress ⇄ awaiting_approval → cancelled (denied)
|
|
1630
|
+
* pending | in_progress | awaiting_approval → cancelled
|
|
1425
1631
|
* done → pending only via an explicit reopen (creator/operator; bumps rev,
|
|
1426
1632
|
* records who in `meta.reopenedBy` — no silent resurrection)
|
|
1427
1633
|
*
|
|
1634
|
+
* Approval gate — `awaiting_approval` (E1b, on top of E1a's approvals
|
|
1635
|
+
* engine): a task parked on one or more `approvalIds` (with an optional
|
|
1636
|
+
* `artifacts` trail pointing at session artifacts or approval payloads).
|
|
1637
|
+
* `linkApproval` is the synchronous wiring point a caller uses at
|
|
1638
|
+
* `approval_request` time (see `session-event-bus.ts`'s
|
|
1639
|
+
* `ApprovalRequestedEvent` doc); `task_update` can set the same fields
|
|
1640
|
+
* directly. The ledger itself subscribes to `approval:decided`: approved →
|
|
1641
|
+
* `in_progress`; denied → `cancelled` with `meta.reason = "denied"` — a
|
|
1642
|
+
* SYSTEM transition, not subject to the update() ACL (mirrors `settleVerify`
|
|
1643
|
+
* and `releaseTask` below).
|
|
1644
|
+
*
|
|
1428
1645
|
* Ownership (two roles, no per-field matrix):
|
|
1429
1646
|
* - `owner` absent = claimable. Claim is CAS — succeeds only if `owner` is
|
|
1430
1647
|
* absent AND `rev` matches; sets in_progress, appends to `sessions[]`.
|
|
@@ -1483,7 +1700,7 @@ interface CompletionPolicySupervisor {
|
|
|
1483
1700
|
* turn-end-based auto-completion: a turn ending is not a task being done.
|
|
1484
1701
|
*/
|
|
1485
1702
|
|
|
1486
|
-
declare const TASK_STATUSES: readonly ["pending", "in_progress", "done", "failed", "cancelled"];
|
|
1703
|
+
declare const TASK_STATUSES: readonly ["pending", "in_progress", "awaiting_approval", "done", "failed", "cancelled"];
|
|
1487
1704
|
type TaskStatus = (typeof TASK_STATUSES)[number];
|
|
1488
1705
|
/** Parse a raw query/body value into a TaskStatus, or undefined when it
|
|
1489
1706
|
* isn't one — the `parseActivityState` idiom for the `/tasks` routes. */
|
|
@@ -1508,6 +1725,20 @@ type TaskVerification = {
|
|
|
1508
1725
|
kind: "human";
|
|
1509
1726
|
ts: string;
|
|
1510
1727
|
};
|
|
1728
|
+
/**
|
|
1729
|
+
* A link on a task, pointing either at a durable session artifact
|
|
1730
|
+
* (`session-artifacts.ts` — content-addressed, `sessionId` + `key` +
|
|
1731
|
+
* `sha256`) or at one of E1a's approval payloads (`approvalId`, resolved
|
|
1732
|
+
* through the approvals engine). Opaque to the ledger — it never dereferences
|
|
1733
|
+
* either shape, only stores and returns it.
|
|
1734
|
+
*/
|
|
1735
|
+
type TaskArtifactLink = {
|
|
1736
|
+
sessionId: string;
|
|
1737
|
+
key: string;
|
|
1738
|
+
sha256: string;
|
|
1739
|
+
} | {
|
|
1740
|
+
approvalId: string;
|
|
1741
|
+
};
|
|
1511
1742
|
interface TaskRecord {
|
|
1512
1743
|
taskId: string;
|
|
1513
1744
|
/** Scope — see the board rules in the module docblock. */
|
|
@@ -1521,6 +1752,13 @@ interface TaskRecord {
|
|
|
1521
1752
|
createdBy: string;
|
|
1522
1753
|
/** INFORMATIONAL in v1 — no scheduler reads it. */
|
|
1523
1754
|
blockedBy?: string[];
|
|
1755
|
+
/** Approvals (E1a's `ApprovalRecord.id`s) gating this task. Set via
|
|
1756
|
+
* `linkApproval` or `task_update`. Driving one into `awaiting_approval`
|
|
1757
|
+
* requires this to end up non-empty. */
|
|
1758
|
+
approvalIds?: string[];
|
|
1759
|
+
/** Evidence trail — session artifacts and/or approval payload pointers.
|
|
1760
|
+
* See {@link TaskArtifactLink}. */
|
|
1761
|
+
artifacts?: TaskArtifactLink[];
|
|
1524
1762
|
/** Every session that ever claimed this task (append-only) — one of the
|
|
1525
1763
|
* two edges the Activity projector will join on later. */
|
|
1526
1764
|
sessions?: string[];
|
|
@@ -1672,6 +1910,12 @@ interface TaskUpdateInput {
|
|
|
1672
1910
|
};
|
|
1673
1911
|
/** Free-text note, stamped into `meta.note` (last-write-wins). */
|
|
1674
1912
|
note?: string;
|
|
1913
|
+
/** Replace the linked approval ids. Owner-settable (like `note`) — not
|
|
1914
|
+
* gated behind the manager-only field-edit check. */
|
|
1915
|
+
approvalIds?: string[];
|
|
1916
|
+
/** Replace the linked artifact/approval evidence trail. Owner-settable,
|
|
1917
|
+
* same as `approvalIds`. */
|
|
1918
|
+
artifacts?: TaskArtifactLink[];
|
|
1675
1919
|
}
|
|
1676
1920
|
/**
|
|
1677
1921
|
* Every write verb answers with this three-way union: applied / rev-CAS
|
|
@@ -1699,6 +1943,17 @@ interface TaskLedger {
|
|
|
1699
1943
|
get(taskId: string, caller: TaskCaller): TaskRecord | undefined;
|
|
1700
1944
|
claim(input: TaskClaimInput, caller: TaskCaller): TaskWriteResult;
|
|
1701
1945
|
update(input: TaskUpdateInput, caller: TaskCaller): TaskWriteResult;
|
|
1946
|
+
/**
|
|
1947
|
+
* Link an approval to a task — the synchronous wiring point a caller uses
|
|
1948
|
+
* at `approval_request` time (see `ApprovalRequestedEvent`'s doc in
|
|
1949
|
+
* `session-event-bus.ts`): appends `approvalId` to `approvalIds`
|
|
1950
|
+
* (idempotent) and, when the task is `in_progress`, moves it to
|
|
1951
|
+
* `awaiting_approval`. Requires owner or manager; the task must already be
|
|
1952
|
+
* `in_progress` or `awaiting_approval` (a pending/closed task has nothing
|
|
1953
|
+
* running to wait on). No `rev` — this is an internal wiring verb, not a
|
|
1954
|
+
* caller-facing CAS write.
|
|
1955
|
+
*/
|
|
1956
|
+
linkApproval(taskId: string, approvalId: string, caller: TaskCaller): TaskWriteResult;
|
|
1702
1957
|
/** The caller's default board — the spawn-stamped `meta.boardId` (when
|
|
1703
1958
|
* present) else `tree:<root>` for a session caller, `ws:<workspaceSlug>`
|
|
1704
1959
|
* for the operator. Exposed so the tool/HTTP layers can echo it without
|
|
@@ -1783,7 +2038,7 @@ declare function isProviderLimitError(message: string | undefined): boolean;
|
|
|
1783
2038
|
* and session_monitor MCP tool (long-poll multiplexed).
|
|
1784
2039
|
*/
|
|
1785
2040
|
|
|
1786
|
-
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:awaiting-input-flagged" | "session:awaiting-question-answered" | "session:permission-request" | "session:permission-resolved" | "session:exited" | "session:reaped" | "session:stalled" | "session:stall-cleared" | "session:watcher-attached" | "session:watcher-detached" | "session:bg-tasks-parked" | "session:bg-tasks-cleared" | "session:bg-task" | "session:resumed" | "session:spawned" | "session:command-done" | "session:model-changed" | "session:config-changed" | "session:renamed" | "session:pinned-changed" | "session:artifact-added" | "session:artifact-pinned-changed" | "session:message" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed" | "activity:changed" | "task:changed" | "workflow:gate-report" | "workflow:suspended" | "workflow:suspend-resumed" | "session:harness-warning";
|
|
2041
|
+
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:awaiting-input-flagged" | "session:awaiting-question-answered" | "session:permission-request" | "session:permission-resolved" | "session:exited" | "session:reaped" | "session:stalled" | "session:stall-cleared" | "session:watcher-attached" | "session:watcher-detached" | "session:bg-tasks-parked" | "session:bg-tasks-cleared" | "session:bg-task" | "session:resumed" | "session:spawned" | "session:provisioning" | "session:command-done" | "session:model-changed" | "session:config-changed" | "session:renamed" | "session:pinned-changed" | "session:artifact-added" | "session:artifact-pinned-changed" | "session:message" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed" | "activity:changed" | "task:changed" | "workflow:gate-report" | "workflow:suspended" | "workflow:suspend-resumed" | "session:harness-warning" | "approval:requested" | "approval:decided" | "approval:consumed" | "approval:expired";
|
|
1787
2042
|
/**
|
|
1788
2043
|
* Fixed severity vocabulary for a judge-gate finding (WP-D). Deliberately
|
|
1789
2044
|
* small and fixed so `policy_status` output is comparable across different
|
|
@@ -2375,6 +2630,25 @@ interface SessionSpawnedEvent {
|
|
|
2375
2630
|
depth: number;
|
|
2376
2631
|
ts: string;
|
|
2377
2632
|
}
|
|
2633
|
+
/**
|
|
2634
|
+
* Emitted as a session's worktree provisioning moves through the daemon-wide
|
|
2635
|
+
* provisioning queue: `queued` (waiting for a heavy-phase slot; `position` is
|
|
2636
|
+
* the 1-based projected dispatch order), `started` (slot granted, heavy
|
|
2637
|
+
* segment running), `phase` (entered another heavy phase), `done` (finished;
|
|
2638
|
+
* `outcome` says how). `phase` names the heavy phase concerned. For a
|
|
2639
|
+
* synchronous `agent_start` the `sessionId` is the id the session will have
|
|
2640
|
+
* once provisioning finishes (no registry row exists before then).
|
|
2641
|
+
*/
|
|
2642
|
+
interface SessionProvisioningEvent {
|
|
2643
|
+
type: "session:provisioning";
|
|
2644
|
+
sessionId: string;
|
|
2645
|
+
kind: "queued" | "started" | "phase" | "done";
|
|
2646
|
+
phase?: "worktree" | "clone" | "deps" | "copy" | "setup";
|
|
2647
|
+
position?: number;
|
|
2648
|
+
outcome?: "ok" | "failed" | "cancelled";
|
|
2649
|
+
label?: string;
|
|
2650
|
+
ts: string;
|
|
2651
|
+
}
|
|
2378
2652
|
/** Emitted by the supervisor when a completion policy's gate passes. */
|
|
2379
2653
|
interface PolicyPassedEvent {
|
|
2380
2654
|
type: "policy:passed";
|
|
@@ -2575,7 +2849,55 @@ interface SessionHarnessWarningEvent {
|
|
|
2575
2849
|
label?: string;
|
|
2576
2850
|
ts: string;
|
|
2577
2851
|
}
|
|
2578
|
-
|
|
2852
|
+
/**
|
|
2853
|
+
* Emitted by the approvals engine (`approvals/engine.ts`) when an
|
|
2854
|
+
* `approval_request` (MCP or `POST /approvals`) raises a new pending
|
|
2855
|
+
* approval. `taskId` is present when the request is linked to a task —
|
|
2856
|
+
* the task ledger uses it for nothing (linking already happened
|
|
2857
|
+
* synchronously at request time via `TaskLedger.linkApproval`); it rides
|
|
2858
|
+
* here purely for a listener's convenience.
|
|
2859
|
+
*/
|
|
2860
|
+
interface ApprovalRequestedEvent {
|
|
2861
|
+
type: "approval:requested";
|
|
2862
|
+
approvalId: string;
|
|
2863
|
+
kind: string;
|
|
2864
|
+
taskId?: string;
|
|
2865
|
+
ts: string;
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Emitted once a human decides a pending approval through a declared
|
|
2869
|
+
* channel (`web_click`, `ui_card`) — never for anything else. The task
|
|
2870
|
+
* ledger subscribes to this: a task in `awaiting_approval` whose
|
|
2871
|
+
* `approvalIds` contains `approvalId` moves to `in_progress` on
|
|
2872
|
+
* `decision:"approved"`, or `cancelled` (`meta.reason:"denied"`) on
|
|
2873
|
+
* `decision:"denied"`.
|
|
2874
|
+
*/
|
|
2875
|
+
interface ApprovalDecidedEvent {
|
|
2876
|
+
type: "approval:decided";
|
|
2877
|
+
approvalId: string;
|
|
2878
|
+
decision: "approved" | "denied";
|
|
2879
|
+
channel: "web_click" | "ui_card";
|
|
2880
|
+
taskId?: string;
|
|
2881
|
+
ts: string;
|
|
2882
|
+
}
|
|
2883
|
+
/** Emitted when `approval_consume` (or its HTTP twin) atomically consumes
|
|
2884
|
+
* an approved approval — the gated action is now cleared to run exactly
|
|
2885
|
+
* once. */
|
|
2886
|
+
interface ApprovalConsumedEvent {
|
|
2887
|
+
type: "approval:consumed";
|
|
2888
|
+
approvalId: string;
|
|
2889
|
+
taskId?: string;
|
|
2890
|
+
ts: string;
|
|
2891
|
+
}
|
|
2892
|
+
/** Emitted when a pending approval's `expiresAt` (or its owning task's end)
|
|
2893
|
+
* lapses before a human decided. */
|
|
2894
|
+
interface ApprovalExpiredEvent {
|
|
2895
|
+
type: "approval:expired";
|
|
2896
|
+
approvalId: string;
|
|
2897
|
+
taskId?: string;
|
|
2898
|
+
ts: string;
|
|
2899
|
+
}
|
|
2900
|
+
type SessionEvent = SessionTurnEndEvent | SessionAwaitingInputEvent | SessionAwaitingInputFlaggedEvent | SessionAwaitingQuestionAnsweredEvent | SessionPermissionRequestEvent | SessionPermissionResolvedEvent | SessionExitedEvent | SessionReapedEvent | SessionStalledEvent | SessionStallClearedEvent | SessionWatcherAttachedEvent | SessionWatcherDetachedEvent | SessionBgTasksParkedEvent | SessionBgTasksClearedEvent | SessionBgTaskEvent | SessionResumedEvent | SessionSpawnedEvent | SessionProvisioningEvent | SessionCommandDoneEvent | SessionModelChangedEvent | SessionConfigChangedEvent | SessionRenamedEvent | SessionPinnedEvent | SessionArtifactAddedEvent | SessionArtifactPinnedEvent | SessionMessageEvent | PolicyPassedEvent | PolicyFailedEvent | PolicyCommitReadyEvent | PolicyCommittedEvent | CronFiredEvent | CronSucceededEvent | CronFailedEvent | ActivityChangedEvent | TaskChangedEvent | WorkflowGateReportEvent | WorkflowApprovalRequestedEvent | WorkflowApprovalResolvedEvent | WorkflowSuspendedEvent | WorkflowSuspendResumedEvent | SessionHarnessWarningEvent | ApprovalRequestedEvent | ApprovalDecidedEvent | ApprovalConsumedEvent | ApprovalExpiredEvent;
|
|
2579
2901
|
interface SessionEventBus {
|
|
2580
2902
|
emit(ev: SessionEvent): void;
|
|
2581
2903
|
/** Subscribe to a specific event type. Returns an unsubscribe fn. */
|
|
@@ -2951,6 +3273,264 @@ interface SessionAppServeInfo {
|
|
|
2951
3273
|
message?: string;
|
|
2952
3274
|
}
|
|
2953
3275
|
|
|
3276
|
+
/**
|
|
3277
|
+
* Policy layer for `agent_start.worktree` — the config-driven decision of
|
|
3278
|
+
* WHETHER to isolate a spawn into its own git worktree, kept deliberately
|
|
3279
|
+
* separate from HOW one is provisioned.
|
|
3280
|
+
*
|
|
3281
|
+
* This module holds no dependency on `@agentproto/worktree`. Same reasoning
|
|
3282
|
+
* as `worktree-identity.ts`'s docblock, only stronger: provisioning runs the
|
|
3283
|
+
* `worktree.provision` TOOL (git + the base tree's `agentproto.json` setup
|
|
3284
|
+
* hooks), which would drag the driver/harness/provider graph into
|
|
3285
|
+
* `@agentproto/runtime` for a capability the runtime only ever *triggers*.
|
|
3286
|
+
* So the concrete provisioner is an INJECTED PORT ({@link WorktreeProvisioner})
|
|
3287
|
+
* wired at the composition root by a host that already depends on the
|
|
3288
|
+
* worktree package (the CLI). The runtime owns only the pure decision
|
|
3289
|
+
* ({@link decideWorktreeIsolation}) and the config/env resolution
|
|
3290
|
+
* ({@link loadWorktreeIsolation}) — both trivially unit-testable without git.
|
|
3291
|
+
*
|
|
3292
|
+
* Mirrors `agent_start.sandbox`'s `resolveSandboxProvider` injection shape,
|
|
3293
|
+
* except sandbox can default its resolver inside the runtime (the runtime
|
|
3294
|
+
* depends on `@agentproto/sandbox`); worktree cannot, so an unwired daemon
|
|
3295
|
+
* simply has no provisioner and a spawn that would need one fails loud rather
|
|
3296
|
+
* than silently spawning unisolated.
|
|
3297
|
+
*/
|
|
3298
|
+
|
|
3299
|
+
/** Env override for the isolation policy. Highest-priority source, ahead of
|
|
3300
|
+
* the `worktrees.isolation` config field — see `loadWorktreeIsolation`. */
|
|
3301
|
+
declare const WORKTREE_ISOLATION_ENV = "AGENTPROTO_WORKTREES_ISOLATION";
|
|
3302
|
+
/** Env override for the daemon-wide cap on concurrently running HEAVY
|
|
3303
|
+
* worktree-provisioning segments (`depsCmd` etc.). Highest-priority source,
|
|
3304
|
+
* ahead of `worktrees.provisionConcurrency`. Enforced by
|
|
3305
|
+
* `@agentproto/worktree`'s scheduler (which reads the same env name); the
|
|
3306
|
+
* runtime only carries the name and the default for the config registry. */
|
|
3307
|
+
declare const WORKTREE_PROVISION_CONCURRENCY_ENV = "AGENTPROTO_WORKTREES_PROVISION_CONCURRENCY";
|
|
3308
|
+
/** Default cap on concurrently running heavy provisioning segments. Mirrors
|
|
3309
|
+
* `@agentproto/worktree`'s `DEFAULT_PROVISION_CONCURRENCY` (a CLI test pins
|
|
3310
|
+
* the two together — the runtime takes no dependency on that package). */
|
|
3311
|
+
declare const DEFAULT_WORKTREE_PROVISION_CONCURRENCY = 2;
|
|
3312
|
+
/** The default when nothing is configured. Back-compat-preserving: a caller
|
|
3313
|
+
* that passes no `worktree` field spawns exactly where it asked. */
|
|
3314
|
+
declare const DEFAULT_WORKTREE_ISOLATION: WorktreeIsolationMode;
|
|
3315
|
+
/**
|
|
3316
|
+
* The `agent_start.worktree` field. `true` isolates with an auto-minted slug;
|
|
3317
|
+
* an object additionally pins the slug and/or base ref, and can opt into
|
|
3318
|
+
* async provisioning (`async: true` — see `WorktreeRequest.async`); `false`
|
|
3319
|
+
* (or omitted) is "no explicit request" — the policy mode decides.
|
|
3320
|
+
*/
|
|
3321
|
+
type WorktreeField = boolean | {
|
|
3322
|
+
slug?: string;
|
|
3323
|
+
base?: string;
|
|
3324
|
+
async?: boolean;
|
|
3325
|
+
};
|
|
3326
|
+
/** The caller's explicit request, normalized — `undefined` when the field is
|
|
3327
|
+
* absent or `false`, otherwise the (possibly empty) slug/base overrides. */
|
|
3328
|
+
interface WorktreeRequest {
|
|
3329
|
+
slug?: string;
|
|
3330
|
+
base?: string;
|
|
3331
|
+
/** Return a real, registered session as soon as it's minted, provisioning
|
|
3332
|
+
* the worktree in the BACKGROUND instead of blocking `agent_start`'s
|
|
3333
|
+
* response on `git worktree add` + the repo's setup hooks (which can run
|
|
3334
|
+
* minutes — see `session-spawn.ts`'s async-provision branch).
|
|
3335
|
+
*
|
|
3336
|
+
* DEFAULTS TO TRUE for any spawn that provisions a worktree, UNLESS this
|
|
3337
|
+
* spawn also carries `wait` (which needs a first turn to block on — see
|
|
3338
|
+
* `worktree_async_wait_conflict` — so the presence of `wait` alone falls
|
|
3339
|
+
* back to the synchronous path rather than conflicting by default). That
|
|
3340
|
+
* default is applied by `session-spawn.ts` itself (WP-H), not by this
|
|
3341
|
+
* field or `normalizeWorktreeField` — the normalizer leaves `async`
|
|
3342
|
+
* exactly as the caller sent it (`undefined` when omitted; see its own
|
|
3343
|
+
* test), so a caller inspecting the normalized request never sees a
|
|
3344
|
+
* value it didn't write. WP-H incident: the synchronous contract this
|
|
3345
|
+
* field opts OUT of — hold the RPC open for however long setup hooks
|
|
3346
|
+
* take, routinely minutes — is exactly what let a client's own request
|
|
3347
|
+
* timeout retry into a second live agent sharing the first one's
|
|
3348
|
+
* worktree (closed on the other side too — see `session-spawn.ts`'s
|
|
3349
|
+
* `findWorktreeLabelCwdCollision`, which now refuses that retry outright
|
|
3350
|
+
* rather than merely warning). Pass `false` explicitly to keep the old
|
|
3351
|
+
* blocking ok/fail contract (this package's own `worktree_provision_failed`
|
|
3352
|
+
* test coverage exercises it deliberately synchronous). */
|
|
3353
|
+
async?: boolean;
|
|
3354
|
+
}
|
|
3355
|
+
/** What the runtime hands the provisioner. `cwd` is where the session would
|
|
3356
|
+
* otherwise spawn; the provisioner resolves the owning repo from it. */
|
|
3357
|
+
interface WorktreeProvisionRequest {
|
|
3358
|
+
cwd: string;
|
|
3359
|
+
/** Explicit slug from the caller; omitted ⇒ the provisioner mints a
|
|
3360
|
+
* collision-free one (see the host implementation). */
|
|
3361
|
+
slug?: string;
|
|
3362
|
+
/** Base ref the worktree branch is cut from; omitted ⇒ the provisioner's
|
|
3363
|
+
* default (`origin/main`). */
|
|
3364
|
+
base?: string;
|
|
3365
|
+
/** Free-text label (the session's `label`) the provisioner may fold into a
|
|
3366
|
+
* minted slug for human readability. Never load-bearing for correctness. */
|
|
3367
|
+
labelHint?: string;
|
|
3368
|
+
/** Absolute path the provisioner should append the setup hooks' FULL
|
|
3369
|
+
* stdout+stderr to (see `worktree.provision`'s `setupLogPath` input and
|
|
3370
|
+
* `@agentproto/worktree`'s `runSetup`). `session-spawn.ts` passes the
|
|
3371
|
+
* spawning session's own transcript dir here, so a failing setup hook's
|
|
3372
|
+
* full output survives even after a subsequently-reclaimed worktree is
|
|
3373
|
+
* gone — the short `HookError` message alone only carries a filtered
|
|
3374
|
+
* tail. Omitted callers (e.g. `agentproto worktree new`, no session to
|
|
3375
|
+
* log into) simply get no persisted log. */
|
|
3376
|
+
setupLogPath?: string;
|
|
3377
|
+
/** Re-run a failing `worktree.setup` command exactly once before giving
|
|
3378
|
+
* up — see `worktree.provision`'s `retrySetupOnFailure` input and
|
|
3379
|
+
* `runSetup`'s doc for why this is a bounded complement, not a
|
|
3380
|
+
* substitute, and why the daemon opts in while `agentproto worktree new`
|
|
3381
|
+
* doesn't. */
|
|
3382
|
+
retrySetupOnFailure?: boolean;
|
|
3383
|
+
/** Cancels this provisioning: a queued one is dropped from the daemon-wide
|
|
3384
|
+
* provisioning queue, a running one has its child process tree killed (no
|
|
3385
|
+
* orphaned `pnpm install`). The provisioner then rejects. */
|
|
3386
|
+
signal?: AbortSignal;
|
|
3387
|
+
/** Whose spawn this is, for the scheduler's fair-share dispatch (the parent
|
|
3388
|
+
* session id, or an anonymous key for a top-level spawn). */
|
|
3389
|
+
callerId?: string;
|
|
3390
|
+
/** Progress of the heavy provisioning segment (queued / started / phase /
|
|
3391
|
+
* done). Best-effort; never throws into the provisioner. */
|
|
3392
|
+
onProgress?: (progress: WorktreeProvisionProgress) => void;
|
|
3393
|
+
}
|
|
3394
|
+
/** Phases of a worktree provisioning. `worktree` is the unthrottled
|
|
3395
|
+
* `git worktree add` step; the rest are the throttled heavy ones. */
|
|
3396
|
+
type WorktreeProvisionPhase = "worktree" | "clone" | "deps" | "copy" | "setup";
|
|
3397
|
+
/** Structural mirror of `@agentproto/worktree`'s `ProvisionProgress` (the
|
|
3398
|
+
* runtime deliberately takes no dependency on that package). */
|
|
3399
|
+
type WorktreeProvisionProgress = {
|
|
3400
|
+
kind: "queued";
|
|
3401
|
+
position: number;
|
|
3402
|
+
phase: WorktreeProvisionPhase;
|
|
3403
|
+
} | {
|
|
3404
|
+
kind: "started";
|
|
3405
|
+
phase: WorktreeProvisionPhase;
|
|
3406
|
+
} | {
|
|
3407
|
+
kind: "phase";
|
|
3408
|
+
phase: WorktreeProvisionPhase;
|
|
3409
|
+
} | {
|
|
3410
|
+
kind: "done";
|
|
3411
|
+
outcome: "ok" | "failed" | "cancelled";
|
|
3412
|
+
};
|
|
3413
|
+
/** The provisioner's outcome. `isolated: false` is NOT a failure — it means
|
|
3414
|
+
* there was nothing to isolate (`cwd` sits in no git repo), and the caller
|
|
3415
|
+
* should spawn plain at the original cwd. A genuine failure throws. */
|
|
3416
|
+
type WorktreeProvisionOutcome = {
|
|
3417
|
+
isolated: true;
|
|
3418
|
+
cwd: string;
|
|
3419
|
+
branch: string;
|
|
3420
|
+
} | {
|
|
3421
|
+
isolated: false;
|
|
3422
|
+
reason: "not-a-git-repo";
|
|
3423
|
+
};
|
|
3424
|
+
/**
|
|
3425
|
+
* Injected port: provision a git worktree for `req.cwd` and return the
|
|
3426
|
+
* worktree's own cwd for the spawn to land in. Wired at the composition root
|
|
3427
|
+
* by the CLI (over `@agentproto/worktree`); absent on a bare runtime.
|
|
3428
|
+
*/
|
|
3429
|
+
type WorktreeProvisioner = (req: WorktreeProvisionRequest) => Promise<WorktreeProvisionOutcome>;
|
|
3430
|
+
/**
|
|
3431
|
+
* Injected port: best-effort attempt to reclaim ONE worktree by path, called
|
|
3432
|
+
* when its session reaches a terminal state (see
|
|
3433
|
+
* `SessionDescriptor.worktreeAutoProvisioned` and `createSessionsRegistry`'s
|
|
3434
|
+
* `runWorktreeAutoReclaim` option in `sessions.ts`). Deliberately scoped to
|
|
3435
|
+
* exactly the one path a session's own exit is allowed to touch — never a
|
|
3436
|
+
* repo-wide sweep. The implementation (wired by the CLI over
|
|
3437
|
+
* `@agentproto/worktree`'s `reclaimOneWorktree`) re-classifies fresh and only
|
|
3438
|
+
* ever removes the worktree when that comes back `reclaim` (merged-or-fresh,
|
|
3439
|
+
* clean, idle) — a dirty or held worktree is simply left alone. Must never
|
|
3440
|
+
* reject in a way the caller can't safely ignore; `sessions.ts` treats any
|
|
3441
|
+
* rejection as "couldn't reclaim this time, leave it for a manual or
|
|
3442
|
+
* scheduled `gc` sweep" and logs rather than lets it interrupt session
|
|
3443
|
+
* teardown. Absent on a bare runtime — auto-reclaim is simply skipped, and a
|
|
3444
|
+
* caller-explicit worktree request is never routed through this port at all
|
|
3445
|
+
* (see `WorktreeDecision.provision.implicit`).
|
|
3446
|
+
*/
|
|
3447
|
+
type WorktreeAutoReclaimer = (worktreePath: string) => Promise<void>;
|
|
3448
|
+
/** The pure decision's three outcomes. `spawn-in-place` may carry a `warn`:
|
|
3449
|
+
* a non-fatal notice the caller should surface (the child is about to run in
|
|
3450
|
+
* a shared, dirty checkout it doesn't own). A `warn` never blocks the spawn —
|
|
3451
|
+
* it's the loud-but-legitimate middle ground between silently spawning into a
|
|
3452
|
+
* shared tree and hard-rejecting an in-place spawn that's normal at depth.
|
|
3453
|
+
* `provision.implicit` is `true` exactly when the caller made no explicit
|
|
3454
|
+
* `worktree` request and the `"always"` policy provisioned one anyway (the
|
|
3455
|
+
* worktree the caller never asked to keep) — `false` whenever the request
|
|
3456
|
+
* came from the caller itself (`on-request`'s only path here, or `"always"`
|
|
3457
|
+
* with an explicit field). This is the signal `session-spawn.ts` threads
|
|
3458
|
+
* onto the session descriptor so exit-time auto-reclaim (`sessions.ts`)
|
|
3459
|
+
* only ever touches a worktree the daemon minted on its own — a worktree a
|
|
3460
|
+
* caller explicitly asked to keep is never auto-removed. */
|
|
3461
|
+
type WorktreeDecision = {
|
|
3462
|
+
action: "spawn-in-place";
|
|
3463
|
+
warn?: string;
|
|
3464
|
+
} | {
|
|
3465
|
+
action: "provision";
|
|
3466
|
+
request: WorktreeRequest;
|
|
3467
|
+
implicit: boolean;
|
|
3468
|
+
} | {
|
|
3469
|
+
action: "reject";
|
|
3470
|
+
message: string;
|
|
3471
|
+
};
|
|
3472
|
+
/**
|
|
3473
|
+
* Normalize the raw field into an explicit request, or `undefined` when the
|
|
3474
|
+
* caller made no request (`false` / omitted). An object with no overrides
|
|
3475
|
+
* still counts as a request (`{}`) — the caller opted in, just without pins.
|
|
3476
|
+
*/
|
|
3477
|
+
declare function normalizeWorktreeField(field: WorktreeField | undefined): WorktreeRequest | undefined;
|
|
3478
|
+
/**
|
|
3479
|
+
* The resolution matrix — mode × explicit-request × depth — with no side
|
|
3480
|
+
* effects. Every branch is exercised in `worktree-isolation.test.ts`.
|
|
3481
|
+
*
|
|
3482
|
+
* Depth-0 gate: a nested spawn (`depth > 0`, i.e. made through the scoped
|
|
3483
|
+
* orchestrator sub-gateway) NEVER provisions a worktree of its own — it
|
|
3484
|
+
* inherits its parent's ground, per AIP-46 §Delegation. This bites before
|
|
3485
|
+
* the mode is even consulted, so `always` too provisions only at the root.
|
|
3486
|
+
* But "never provisions" is NOT "silently ignore an explicit request": a
|
|
3487
|
+
* nested caller that passes an EXPLICIT `worktree` (`true` / `{slug}`) asked
|
|
3488
|
+
* for isolation and would silently get none — the spawn quietly runs in the
|
|
3489
|
+
* shared checkout, exactly the footgun that nearly clobbered a shared tree.
|
|
3490
|
+
* So an explicit request at depth > 0 is REJECTED loudly (same shape as the
|
|
3491
|
+
* `never`-policy reject below), pointing the caller at sandbox isolation —
|
|
3492
|
+
* child isolation is the sandbox, not a second worktree. Only the IMPLICIT/
|
|
3493
|
+
* absent case (`undefined` / `false`) stays an in-place spawn: the child is
|
|
3494
|
+
* meant to share the parent's tree and made no request to the contrary.
|
|
3495
|
+
*
|
|
3496
|
+
* That implicit case still has a footgun, though: the inherited cwd may be a
|
|
3497
|
+
* LIVE, DIRTY, shared checkout (the real repo, not a daemon-provisioned
|
|
3498
|
+
* worktree) — spawning in place there lets a nested child edit a tree someone
|
|
3499
|
+
* else is actively working in. We don't hard-reject it (implicit in-place is
|
|
3500
|
+
* legitimate and common), but we DON'T stay silent either: when the caller
|
|
3501
|
+
* hands us `sharedDirtyCwd` (an impure signal it computed — see
|
|
3502
|
+
* `session-spawn.ts`), the in-place spawn carries a `warn`. A caller that
|
|
3503
|
+
* genuinely intends it passes `allowSharedCwd` to acknowledge and silence the
|
|
3504
|
+
* warning. The signal is only consulted for the implicit nested case; every
|
|
3505
|
+
* other branch ignores it, keeping the root matrix unchanged.
|
|
3506
|
+
*/
|
|
3507
|
+
declare function decideWorktreeIsolation(input: {
|
|
3508
|
+
mode: WorktreeIsolationMode;
|
|
3509
|
+
field: WorktreeField | undefined;
|
|
3510
|
+
depth: number;
|
|
3511
|
+
/** Impure signal, computed by the caller (never inside this pure fn): the
|
|
3512
|
+
* inherited cwd is a git work tree that is DIRTY and NOT a daemon-
|
|
3513
|
+
* provisioned worktree — i.e. a shared checkout the child would edit in
|
|
3514
|
+
* place. Only consulted for an implicit nested spawn. */
|
|
3515
|
+
sharedDirtyCwd?: boolean;
|
|
3516
|
+
/** Caller's explicit acknowledgement that spawning into a shared dirty cwd
|
|
3517
|
+
* is intended — silences the `sharedDirtyCwd` warning. */
|
|
3518
|
+
allowSharedCwd?: boolean;
|
|
3519
|
+
}): WorktreeDecision;
|
|
3520
|
+
/** Parse a raw string into a valid mode, or `undefined` when it isn't one. */
|
|
3521
|
+
declare function parseWorktreeIsolationMode(raw: string | undefined): WorktreeIsolationMode | undefined;
|
|
3522
|
+
/**
|
|
3523
|
+
* Resolve the effective isolation mode: env > config field > default. Mirrors
|
|
3524
|
+
* `resolveWorktreesRoot`'s precedence (there's no flag layer — this is read
|
|
3525
|
+
* daemon-side at spawn, not from an invocation). Never throws: an unreadable
|
|
3526
|
+
* config falls through to the default.
|
|
3527
|
+
*/
|
|
3528
|
+
declare function loadWorktreeIsolation(loadCfg?: () => Promise<{
|
|
3529
|
+
worktrees?: {
|
|
3530
|
+
isolation?: WorktreeIsolationMode;
|
|
3531
|
+
};
|
|
3532
|
+
}>): Promise<WorktreeIsolationMode>;
|
|
3533
|
+
|
|
2954
3534
|
/** One background task as mirrored onto `SessionDescriptor.backgroundTasks`. */
|
|
2955
3535
|
interface SessionBackgroundTask {
|
|
2956
3536
|
taskId: string;
|
|
@@ -3649,6 +4229,24 @@ interface SessionHandoff {
|
|
|
3649
4229
|
/** ISO 8601 timestamp the handoff spawn completed. */
|
|
3650
4230
|
at: string;
|
|
3651
4231
|
}
|
|
4232
|
+
/**
|
|
4233
|
+
* Where a still-`starting` session's worktree provisioning stands in the
|
|
4234
|
+
* daemon-wide provisioning queue (heavy phases, `depsCmd` above all, are
|
|
4235
|
+
* throttled so a burst of spawns cannot melt the host). Present only while
|
|
4236
|
+
* provisioning is in flight; cleared when it finishes, fails, or is cancelled.
|
|
4237
|
+
*/
|
|
4238
|
+
interface SessionProvisioning {
|
|
4239
|
+
/** `queued`: waiting for a heavy-phase slot. `running`: provisioning is
|
|
4240
|
+
* actually executing (the cheap prep, or a granted heavy segment). */
|
|
4241
|
+
state: "queued" | "running";
|
|
4242
|
+
/** 1-based projected dispatch position; only while `queued`. */
|
|
4243
|
+
position?: number;
|
|
4244
|
+
/** The phase queued for (`queued`) or currently executing (`running`). */
|
|
4245
|
+
phase: WorktreeProvisionPhase;
|
|
4246
|
+
/** ISO-8601 instant provisioning began (the spawn), constant across the
|
|
4247
|
+
* queued and running states so `now - startedAt` is the total wait. */
|
|
4248
|
+
startedAt: string;
|
|
4249
|
+
}
|
|
3652
4250
|
interface SessionDescriptor {
|
|
3653
4251
|
id: string;
|
|
3654
4252
|
kind: SessionKind;
|
|
@@ -3658,6 +4256,9 @@ interface SessionDescriptor {
|
|
|
3658
4256
|
command: string;
|
|
3659
4257
|
pid: number | null;
|
|
3660
4258
|
status: SessionStatus;
|
|
4259
|
+
/** Worktree-provisioning progress of a `starting` row — see
|
|
4260
|
+
* {@link SessionProvisioning}. Absent once the session left `starting`. */
|
|
4261
|
+
provisioning?: SessionProvisioning;
|
|
3661
4262
|
/** Unambiguous liveness signal, stamped at read time (list()/get()/
|
|
3662
4263
|
* findByIdOrName) — true iff `status` is "running" or "starting", the
|
|
3663
4264
|
* same test the daemon uses internally (validateAgentTurn). Ephemeral:
|
|
@@ -3788,6 +4389,11 @@ interface SessionDescriptor {
|
|
|
3788
4389
|
* `withMemory: true`) since it costs a `ps` spawn; absent otherwise, and
|
|
3789
4390
|
* absent for a row with no `pid` or that `ps` didn't report. */
|
|
3790
4391
|
rssBytes?: number;
|
|
4392
|
+
/** Process-tree resource sample for this session (`process-stats.ts`):
|
|
4393
|
+
* RSS, %CPU, process count, top commands by RSS - plus, at `stats:"full"`,
|
|
4394
|
+
* every process. Ephemeral and opt-in (`session_list`/`agent_sessions_list`
|
|
4395
|
+
* `stats`), never persisted; absent for a row with no live process. */
|
|
4396
|
+
stats?: Omit<SessionResourceStats, "sessionId">;
|
|
3791
4397
|
/** Count of live supervisors currently blocked waiting on this session —
|
|
3792
4398
|
* HTTP `GET /sessions/:id/wait` long-polls and `session_monitor`
|
|
3793
4399
|
* subscriptions, both via `monitorSessionWait` (#session-visibility).
|
|
@@ -4611,10 +5217,13 @@ interface SessionDescriptor {
|
|
|
4611
5217
|
contextContinuityAckedAtPct?: number;
|
|
4612
5218
|
/** Id of the most recent checkpoint created for this session. */
|
|
4613
5219
|
checkpointId?: string;
|
|
4614
|
-
/**
|
|
5220
|
+
/** The source session id when this row continues another one: a
|
|
5221
|
+
* continue-fresh handoff OR a revival (restart / cron / sentinel / inbound
|
|
5222
|
+
* wake / direct resume of the same adapter conversation — also recorded as
|
|
5223
|
+
* `resumedFrom`). Absent on a row that started a conversation. */
|
|
4615
5224
|
continuedFrom?: string;
|
|
4616
|
-
/**
|
|
4617
|
-
*
|
|
5225
|
+
/** The row that continued this one (the inverse of `continuedFrom`); the
|
|
5226
|
+
* latest continuation wins when a row is revived more than once. */
|
|
4618
5227
|
continuedTo?: string;
|
|
4619
5228
|
/** Set alongside `continuedFrom` on the NEW session — the harness the
|
|
4620
5229
|
* checkpoint moved from/to and when. Present on every `continue_fresh`
|
|
@@ -4749,6 +5358,9 @@ interface SessionSummary {
|
|
|
4749
5358
|
command: string;
|
|
4750
5359
|
pid: number | null;
|
|
4751
5360
|
status: SessionStatus;
|
|
5361
|
+
/** Worktree-provisioning progress while `starting` — see
|
|
5362
|
+
* `SessionDescriptor.provisioning`. */
|
|
5363
|
+
provisioning?: SessionProvisioning;
|
|
4752
5364
|
startedAt: string;
|
|
4753
5365
|
endedAt?: string;
|
|
4754
5366
|
exitCode?: number;
|
|
@@ -4820,6 +5432,9 @@ interface SessionSummary {
|
|
|
4820
5432
|
* `SessionDescriptor.lastTurnErroredAt`. Stamped at turn-end, cleared on
|
|
4821
5433
|
* the next turn that completes without one. */
|
|
4822
5434
|
lastTurnErroredAt?: string;
|
|
5435
|
+
/** `SessionDescriptor.lastError` (spawn/crash cause), capped at 2000 chars
|
|
5436
|
+
* for the list projection. Lets a list view say WHY an errored row died. */
|
|
5437
|
+
lastError?: string;
|
|
4823
5438
|
origin?: string;
|
|
4824
5439
|
parentSessionId?: string;
|
|
4825
5440
|
depth?: number;
|
|
@@ -5088,6 +5703,13 @@ interface SessionsRegistry {
|
|
|
5088
5703
|
* killed it mid-provision. A terminal descriptor is never resurrected.
|
|
5089
5704
|
* Also a no-op for an unknown id (the row was removed entirely). */
|
|
5090
5705
|
settlePendingAgent(id: string, outcome: PendingAgentOutcome): void;
|
|
5706
|
+
/** Record a provisioning progress report for `id`: updates the row's
|
|
5707
|
+
* {@link SessionProvisioning} (`queued` / `started` / `phase`; `done`
|
|
5708
|
+
* clears it) and emits `session:provisioning` on the bus. Also emits for an
|
|
5709
|
+
* id with no registry row (a synchronous provision, whose session doesn't
|
|
5710
|
+
* exist until it finishes) — only the descriptor update is skipped. Never
|
|
5711
|
+
* touches a row that already left `starting`. */
|
|
5712
|
+
reportProvisioning(id: string, progress: WorktreeProvisionProgress): void;
|
|
5091
5713
|
/** Spawn a process under a real PTY (node-pty). Bytes flow through
|
|
5092
5714
|
* the registry's byte ring buffer + emitter; attach with
|
|
5093
5715
|
* `attachPty(id, ...)`. Throws when the registry was constructed
|
|
@@ -5401,6 +6023,13 @@ interface SessionsRegistry {
|
|
|
5401
6023
|
* builds the fully-typed event (axis + value already reflected on the new
|
|
5402
6024
|
* descriptor); the registry only forwards it. */
|
|
5403
6025
|
emitConfigChanged(ev: SessionConfigChangedEvent): void;
|
|
6026
|
+
/**
|
|
6027
|
+
* Announce a `session:harness-warning` for a session — an explicit,
|
|
6028
|
+
* non-fatal "the host could not honor part of what was asked" notice (the
|
|
6029
|
+
* app-boundary fs zones not enforceable on this harness, …). Best-effort
|
|
6030
|
+
* observability; no-op when the registry has no event bus.
|
|
6031
|
+
*/
|
|
6032
|
+
emitHarnessWarning(sessionId: string, warnings: readonly string[], label?: string): void;
|
|
5404
6033
|
/**
|
|
5405
6034
|
* Switch the reasoning/compute budget (effort) on a LIVE agent-cli session
|
|
5406
6035
|
* without restarting it — the live-effort verb (SPEC §4.2, build step 5),
|
|
@@ -6074,7 +6703,13 @@ interface SpawnAgentInput {
|
|
|
6074
6703
|
/** `SpawnAgentInput` minus the fields that only exist once the driver's
|
|
6075
6704
|
* `startSession` has actually run — see `spawnAgentPending`'s doc for why
|
|
6076
6705
|
* everything else is safe to record up front. */
|
|
6077
|
-
type SpawnAgentPendingInput = Omit<SpawnAgentInput, "agentSession" | "commandPreview" | "resumable" | "nativeTerminalResume" | "initialPrompt"
|
|
6706
|
+
type SpawnAgentPendingInput = Omit<SpawnAgentInput, "agentSession" | "commandPreview" | "resumable" | "nativeTerminalResume" | "initialPrompt"> & {
|
|
6707
|
+
/** Invoked once when the placeholder reaches a terminal status (killed, or
|
|
6708
|
+
* settled failed) while provisioning may still be in flight — the hook
|
|
6709
|
+
* that aborts the provisioner so a killed spawn leaves no queued entry
|
|
6710
|
+
* and no orphaned install. Never invoked after a successful settle. */
|
|
6711
|
+
onCancel?: () => void;
|
|
6712
|
+
};
|
|
6078
6713
|
/** The deferred outcome `settlePendingAgent` resolves a placeholder with —
|
|
6079
6714
|
* see that method's doc. */
|
|
6080
6715
|
type PendingAgentOutcome = {
|
|
@@ -6228,4 +6863,4 @@ interface RecordOpenedPrInput {
|
|
|
6228
6863
|
url: string;
|
|
6229
6864
|
}
|
|
6230
6865
|
|
|
6231
|
-
export {
|
|
6866
|
+
export { DEFAULT_WORKTREE_PROVISION_CONCURRENCY as $, type ActivityPolicySlice as A, type UsageRollup as B, type CompletionPolicySupervisor as C, type RemainingQuotaReader as D, type UsageSnapshotRecord as E, type SessionAwaitingQuestion as F, type PolicyRunState as G, type PtyFactory as H, type WorktreeAutoReclaimer as I, type ActivityKind as J, type ActivitySource as K, type ActivityState as L, type MessageUrgency as M, type ActivityWaitingOn as N, type AnthropicReaderConfig as O, type PrResolvedState as P, type QuotaReadableProfile as Q, type RestartPolicy as R, type SessionEvent as S, type TaskLedger as T, type UserPreset as U, AnthropicRemainingQuotaReader as V, type WorktreeProvisioner as W, type AttachPolicyInput as X, type CommandGroupStats as Y, type CommitSpec as Z, DEFAULT_WORKTREE_ISOLATION as _, type SessionEventType as a, type TaskUpdateInput as a$, type EagerResumeFailReason as a0, type EagerResumeOutcome as a1, type EagerResumeSkipReason as a2, type GateSpec as a3, type HostInfo as a4, type JudgeGateSpec as a5, type LabeledProcessStatsReport as a6, type LabeledSessionStats as a7, MAX_MESSAGE_DATA_BYTES as a8, MESSAGE_KINDS as a9, type SessionCurrentPhase as aA, type SessionKind as aB, type SessionMessageFrom as aC, type SessionOutcome as aD, type SessionOutcomeArtifact as aE, type SessionOutcomeCompact as aF, type SessionOutcomeLink as aG, type SessionResourceStats as aH, type SessionSnapshots as aI, type SessionStatus as aJ, type ShellGateSpec as aK, type SpawnAgentInput as aL, type SpawnSessionInput as aM, type StatsDetail as aN, type StoredProfileQuota as aO, TASK_STATUSES as aP, type TaskCaller as aQ, type TaskChangedEvent as aR, type TaskClaimInput as aS, type TaskCreateInput as aT, type TaskGateOutcome as aU, type TaskGateRunner as aV, type TaskLedgerRegistry as aW, type TaskLedgerSessionSlice as aX, type TaskListFilter as aY, type TaskRecord as aZ, type TaskStatus as a_, MESSAGE_PREAMBLE as aa, MESSAGE_TAG as ab, MESSAGE_URGENCIES as ac, type MessageDeliveryVia as ad, type MessageFilter as ae, type MessageRelation as af, type MessageTreeNode as ag, type OnFailSpec as ah, type OrphanGroup as ai, type PendingPermission as aj, type PermissionRespondInput as ak, type PermissionRespondResult as al, type PolicyRunStatus as am, type PricingResolver as an, type ProcessDetail as ao, type ProcessStatsReport as ap, type ProcessStatsService as aq, type QuotaStoreFile as ar, type QuotaStoreOptions as as, type RegisterBrowserInput as at, type RegisterSessionInput as au, type RemainingQuota as av, type ResourceStats as aw, ResumeDisabledError as ax, SESSION_END_REASONS as ay, SESSION_ID_ENV as az, type SessionEventBus as b, sanitizeLabel as b$, type TaskVerification as b0, type TaskVerifySupervisor as b1, type TaskWriteResult as b2, type TokenPricing as b3, type UsageBucket as b4, type UsageComputeInput as b5, type UsageDetail as b6, type UsageSource as b7, type UserPresetsFile as b8, WORKSPACE_SLUG_ENV as b9, isProviderLimitError as bA, isTerminalActivityState as bB, listUserPresets as bC, loadQuotaStore as bD, loadUserPresets as bE, loadWorktreeIsolation as bF, matchesMessageFilter as bG, messageFrom as bH, mintMessageId as bI, normalizeCommand as bJ, normalizeWorktreeField as bK, parseAnthropicRateLimitHeaders as bL, parseTaskStatus as bM, parseWindow as bN, parseWorktreeIsolationMode as bO, pickUsageDetail as bP, policyToActivities as bQ, policyWatchesSession as bR, prToActivities as bS, projectSessionUsage as bT, readProfileQuota as bU, recordProfileQuota as bV, renderInboxDigest as bW, renderSessionMessage as bX, renderSessionMessages as bY, resolveRelation as bZ, rollupUsage as b_, WORKTREE_ISOLATION_ENV as ba, WORKTREE_PROVISION_CONCURRENCY_ENV as bb, type WorktreeDecision as bc, type WorktreeProvisionOutcome as bd, type WorktreeProvisionPhase as be, type WorktreeProvisionProgress as bf, type WorktreeProvisionRequest as bg, type WorktreeRequest as bh, activityCounts as bi, compactOutcome as bj, createProcessStatsService as bk, createSessionMessage as bl, createSupervisorTaskGateRunner as bm, createTaskLedger as bn, decideWorktreeIsolation as bo, deleteUserPreset as bp, deriveSessionOutcome as bq, deriveSessionUsage as br, escapeHumanPrompt as bs, escapeMessageBody as bt, filterActivities as bu, getProcessStatsService as bv, getUserPreset as bw, isClosedTaskStatus as bx, isKnownSessionEndReason as by, isMessageAllowed as bz, type SessionsRegistry as c, saveUserPreset as c0, trackWorktreeProvision as c1, turnToActivities as c2, userPresetsPath as c3, workflowToActivities as c4, type RecentSpawnConfig as c5, deriveRecentSpawnConfigs as c6, touchUserPreset as c7, userPresetSchema as c8, type SessionDescriptor as d, type SessionEndReason as e, type ActivityListFilter as f, type ActivityRecord as g, type ActivityTurnSession as h, type ActivityPrSession as i, type ActivityWorkflowRunSlice as j, type ActivityTaskSlice as k, type AgentsMdResolution as l, type SandboxAppServeSpec as m, type WorktreeField as n, type AgentSessionLike as o, type UsageReadContext as p, type UsageReadResult as q, type MessageKind as r, type SessionMessage as s, type AgentStreamEvent as t, type SessionUsage as u, type ToolCallRecord as v, type StatsSessionDescriptor as w, type ProcRow as x, type ProvisionInFlight as y, type ProvisionTracker as z };
|