@pinet/broker-core 0.2.2 → 0.2.6

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/types.d.ts CHANGED
@@ -1,6 +1,265 @@
1
1
  import type { PinetMailClass } from "./mail-classification.js";
2
2
  export declare const DEFAULT_EXTERNAL_THREAD_SOURCE = "external";
3
3
  export type AgentSupervisionState = "root" | "supervised" | "orphaned" | "stopping";
4
+ export type AgentLifecycleState = "live" | "active" | "grace" | "idle" | "hibernating" | "hibernated" | "waking" | "reap-candidate" | "terminated";
5
+ export type AgentHibernatePolicy = "auto" | "never" | "manual";
6
+ export interface HibernateEligibility {
7
+ eligible: boolean;
8
+ reason: string;
9
+ }
10
+ export type AgentLifecycleOperation = "hibernate" | "wake";
11
+ export interface AgentLifecycleLease {
12
+ agentId: string;
13
+ operation: AgentLifecycleOperation;
14
+ fenceToken: number;
15
+ ownerBrokerInstanceId: string;
16
+ leaseId: string;
17
+ acquiredAt: string;
18
+ expiresAt: string;
19
+ attempt: number;
20
+ triggerMessageId: number | null;
21
+ }
22
+ export interface AgentLifecycleRetentionInfo {
23
+ retainedCount: number;
24
+ prunedCount: number;
25
+ lastPrunedAt: string | null;
26
+ }
27
+ /** Optional structured telemetry captured alongside lifecycle events. */
28
+ export interface AgentLifecycleEventMetrics {
29
+ fenceToken?: number | null;
30
+ queueDepth?: number | null;
31
+ oldestQueueAgeMs?: number | null;
32
+ durationMs?: number | null;
33
+ rssBytesBefore?: number | null;
34
+ rssBytesAfter?: number | null;
35
+ }
36
+ export interface AgentLifecycleTransitionInput extends AgentLifecycleEventMetrics {
37
+ agentId: string;
38
+ expectedVersion: number;
39
+ toState: AgentLifecycleState;
40
+ reason: string;
41
+ actor: string;
42
+ correlationId: string;
43
+ triggerSource?: string;
44
+ /**
45
+ * Optional strict lease-identity binding for fenced transitions. When
46
+ * `fenceToken` is presented these tighten the fence check so that only the
47
+ * live, matching lease can drive the transition: `leaseId` must equal the
48
+ * held lease's id, `expectedOperation` its operation, and (with `now`) the
49
+ * lease must be unexpired. This rejects an expired, superseded, or
50
+ * wrong-operation lease that would otherwise pass on the fence token alone.
51
+ */
52
+ leaseId?: string;
53
+ expectedOperation?: AgentLifecycleOperation;
54
+ now?: number;
55
+ }
56
+ /**
57
+ * Audit-only lifecycle event that records an outcome (typically a refusal,
58
+ * fenced stale attempt, or duplicate-launch prevention) without transitioning
59
+ * the agent's lifecycle state.
60
+ */
61
+ export interface AgentLifecycleEventInput extends AgentLifecycleEventMetrics {
62
+ agentId: string;
63
+ fromState: AgentLifecycleState;
64
+ toState: AgentLifecycleState;
65
+ lifecycleVersion: number;
66
+ reason: string;
67
+ actor: string;
68
+ correlationId: string;
69
+ outcome: string;
70
+ errorCode?: string | null;
71
+ triggerSource?: string;
72
+ }
73
+ export interface AgentLifecycleEvent {
74
+ id: number;
75
+ correlationId: string;
76
+ agentId: string;
77
+ fromState: AgentLifecycleState;
78
+ toState: AgentLifecycleState;
79
+ lifecycleVersion: number;
80
+ fenceToken: number | null;
81
+ reason: string;
82
+ triggerSource: string | null;
83
+ actor: string;
84
+ outcome: string;
85
+ errorCode: string | null;
86
+ queueDepth: number | null;
87
+ oldestQueueAgeMs: number | null;
88
+ durationMs: number | null;
89
+ rssBytesBefore: number | null;
90
+ rssBytesAfter: number | null;
91
+ createdAt: string;
92
+ }
93
+ /**
94
+ * Durable, sanitized launch/resume manifest for a broker-managed follower.
95
+ *
96
+ * This is the record used to cold-wake exactly the same logical agent. It must
97
+ * never persist secrets, tokens, prompt/message bodies, or an unrestricted
98
+ * environment: only an env allowlist and opaque credential references. Secrets
99
+ * are injected from broker memory/config at launch time.
100
+ */
101
+ interface AgentRuntimeSpecBase {
102
+ agentId: string;
103
+ stableId: string;
104
+ brokerOwnerId: string;
105
+ cwd: string;
106
+ repoRoot: string;
107
+ worktreePath: string;
108
+ executable: string;
109
+ /** Argument vector without secrets; credential values are references only. */
110
+ argv: string[];
111
+ /** Allowlisted environment variable names (never values). */
112
+ envAllowlist: string[];
113
+ /** Opaque, broker-resolvable session resume reference (not a raw path). */
114
+ sessionResumeRef: string;
115
+ configFingerprint: string;
116
+ expectedHost: string;
117
+ expectedUser: string;
118
+ launchSource: string;
119
+ /**
120
+ * Canonical, broker-derived VCS identity (`owner/repo`) captured at spawn from
121
+ * the runtime's git remote — NEVER inferred from filesystem directory names.
122
+ * The repo allowlist authorization matches this exactly, so distinct roots
123
+ * that share their final path segments never collapse onto one authorization
124
+ * identity and a repo shares one identity with all of its worktrees. `null`
125
+ * when no remote was resolvable at spawn (the fail-closed gate then refuses).
126
+ */
127
+ vcsIdentity: string | null;
128
+ createdAt: string;
129
+ updatedAt: string;
130
+ }
131
+ export type AgentRuntimeSpec = (AgentRuntimeSpecBase & {
132
+ runtimeKind: "tmux";
133
+ /** Canonical tmux server socket path recorded at launch; never searched for. */
134
+ tmuxSocket: string;
135
+ tmuxSession: string;
136
+ /** Fully-qualified tmux target (session:window.pane) recorded at launch. */
137
+ tmuxTarget: string;
138
+ }) | (AgentRuntimeSpecBase & {
139
+ runtimeKind: "herdr";
140
+ /** Pinet-owned named Herdr server session. */
141
+ herdrSession: string;
142
+ /** Dedicated XDG_CONFIG_HOME whose config enables durable pane history. */
143
+ herdrConfigDir: string;
144
+ herdrPaneId: string;
145
+ /** Server-owned pane shell PID captured at launch for cleanup fencing. */
146
+ herdrShellPid: number;
147
+ });
148
+ export type TmuxAgentRuntimeSpec = Extract<AgentRuntimeSpec, {
149
+ runtimeKind: "tmux";
150
+ }>;
151
+ type RuntimeSpecWithoutTimestamps<T extends AgentRuntimeSpec> = T extends AgentRuntimeSpec ? Omit<T, "createdAt" | "updatedAt"> : never;
152
+ export type AgentRuntimeSpecInput = RuntimeSpecWithoutTimestamps<AgentRuntimeSpec>;
153
+ /**
154
+ * Client-facing redacted view of a runtime spec. Raw stable paths, private
155
+ * socket paths, and env details are withheld unless an authorized operator
156
+ * requests full inspection.
157
+ */
158
+ export interface RedactedAgentRuntimeSpec {
159
+ agentId: string;
160
+ session: AgentSessionSummary;
161
+ repo: string | null;
162
+ hasWorktree: boolean;
163
+ runtimeKind: AgentRuntimeSpec["runtimeKind"];
164
+ /** Legacy tmux presence flag retained for client compatibility. */
165
+ hasTmuxSession: boolean;
166
+ configFingerprint: string;
167
+ expectedHost: string;
168
+ launchSource: string;
169
+ envAllowlistCount: number;
170
+ updatedAt: string;
171
+ }
172
+ /**
173
+ * Receipt confirming a follower cooperatively flushed a checkpoint before a
174
+ * clean process exit. `hibernateSafe=false` records a refusal reason so the
175
+ * orchestrator fails closed rather than exiting an unsafe runtime.
176
+ */
177
+ export interface AgentCheckpointReceipt {
178
+ agentId: string;
179
+ runtimeGeneration: number;
180
+ correlationId: string;
181
+ hibernateSafe: boolean;
182
+ reason: string | null;
183
+ sessionResumeRef: string | null;
184
+ pendingInboxCount: number;
185
+ rssBytes: number | null;
186
+ createdAt: string;
187
+ }
188
+ export type AgentCheckpointReceiptInput = Omit<AgentCheckpointReceipt, "createdAt">;
189
+ /**
190
+ * Single-winner wake reservation. Exactly one may exist per agent; it binds the
191
+ * wake lease/fence to the specific runtime generation the broker will accept on
192
+ * registration. Any registration presenting a different generation/lease/fence
193
+ * is a stale runtime and is rejected.
194
+ */
195
+ export interface AgentWakeReservation {
196
+ agentId: string;
197
+ wakeLeaseId: string;
198
+ fenceToken: number;
199
+ reservedGeneration: number;
200
+ /** Fresh per-attempt token distinguishing this reservation from a retry's. */
201
+ reservationNonce: string;
202
+ correlationId: string;
203
+ createdAt: string;
204
+ }
205
+ export interface AcceptRuntimeGenerationInput {
206
+ agentId: string;
207
+ wakeLeaseId: string;
208
+ fenceToken: number;
209
+ reservedGeneration: number;
210
+ /** Must equal the current reservation's nonce; fences out superseded attempts. */
211
+ reservationNonce: string;
212
+ /** Epoch ms for lease-expiry comparison. Defaults to Date.now(). */
213
+ now?: number;
214
+ }
215
+ /**
216
+ * Durable record of the EXACT wake fence that accepted a generation, written in
217
+ * the acceptance transaction. Enables idempotent re-binding of a runtime whose
218
+ * acceptance committed but whose register RPC response was lost to a broker crash
219
+ * (so the client replays its single-use wake fence). Superseded by the next wake
220
+ * reservation so a stale fence cannot rebind during a fresh wake window.
221
+ */
222
+ export interface AgentWakeAcceptanceReceipt {
223
+ agentId: string;
224
+ stableId: string;
225
+ wakeLeaseId: string;
226
+ fenceToken: number;
227
+ reservedGeneration: number;
228
+ reservationNonce: string;
229
+ acceptedAt: string;
230
+ }
231
+ export type RuntimeGenerationAcceptance = {
232
+ accepted: true;
233
+ runtimeGeneration: number;
234
+ } | {
235
+ accepted: false;
236
+ reason: string;
237
+ };
238
+ export type WakeTriggerKind = "slack_thread" | "direct_a2a" | "lane_assignment" | "scheduled" | "manual";
239
+ export interface AgentWakeQueueEntry {
240
+ id: number;
241
+ agentId: string;
242
+ repoRoot: string | null;
243
+ triggerKind: WakeTriggerKind;
244
+ triggerMessageId: number | null;
245
+ /** Lower sorts first; targeted (direct/affinity) work uses a smaller value. */
246
+ priority: number;
247
+ reason: string;
248
+ correlationId: string;
249
+ status: "queued" | "dispatching" | "done" | "cancelled";
250
+ attempt: number;
251
+ enqueuedAt: string;
252
+ updatedAt: string;
253
+ }
254
+ export interface EnqueueWakeInput {
255
+ agentId: string;
256
+ repoRoot?: string | null;
257
+ triggerKind: WakeTriggerKind;
258
+ triggerMessageId?: number | null;
259
+ priority?: number;
260
+ reason: string;
261
+ correlationId: string;
262
+ }
4
263
  export interface AgentInfo {
5
264
  id: string;
6
265
  stableId?: string | null;
@@ -24,15 +283,31 @@ export interface AgentInfo {
24
283
  resumableUntil?: string | null;
25
284
  idleSince?: string | null;
26
285
  lastActivity?: string | null;
286
+ lifecycleState?: AgentLifecycleState;
287
+ lifecycleVersion?: number;
288
+ hibernatePolicy?: AgentHibernatePolicy;
289
+ graceUntil?: string | null;
290
+ idleEligibleAt?: string | null;
291
+ hibernatedAt?: string | null;
292
+ terminatedAt?: string | null;
293
+ hibernateReason?: string | null;
294
+ lastWakeReason?: string | null;
295
+ runtimeGeneration?: number;
27
296
  outboundCount?: number;
28
297
  pendingInboxCount?: number;
29
298
  }
30
299
  export type AgentSessionKind = "session" | "leaf" | "cwd" | "broker" | "unknown";
31
300
  export interface AgentSessionSummary {
32
301
  kind: AgentSessionKind;
33
- /** Broker-safe, path-free stable session reference such as "session:1a2b3c4d5e6f". */
302
+ /**
303
+ * Broker-safe, path-free session reference of the form "<kind>:#<fp>" where
304
+ * <fp> is a stable, non-reversible fingerprint of the raw session resume ref.
305
+ * The raw payload (which for cwd/leaf kinds may be a filesystem path) is never
306
+ * surfaced.
307
+ */
34
308
  ref: string;
35
309
  host?: string | null;
310
+ /** True when the raw ref payload looked path-like (still never exposed). */
36
311
  hasPath?: boolean;
37
312
  }
38
313
  export type ClientAgentInfo = Omit<AgentInfo, "stableId"> & {
@@ -45,6 +320,8 @@ export interface AgentSessionSearchOptions {
45
320
  threadId?: string;
46
321
  repo?: string;
47
322
  worktreePath?: string;
323
+ runtimeLocator?: string;
324
+ /** Legacy tmux-only locator filter retained for wire compatibility. */
48
325
  tmuxSession?: string;
49
326
  since?: string;
50
327
  until?: string;
@@ -69,6 +346,9 @@ export interface AgentSessionSearchInfo {
69
346
  repoRoot: string | null;
70
347
  worktreePath: string | null;
71
348
  branch: string | null;
349
+ runtimeKind: AgentRuntimeSpec["runtimeKind"] | null;
350
+ runtimeLocator: string | null;
351
+ /** Legacy tmux-only locator retained for wire compatibility. */
72
352
  tmuxSession: string | null;
73
353
  brokerManaged: boolean;
74
354
  brokerManagedBy: string | null;
@@ -328,6 +608,12 @@ export declare const RPC_INTERNAL_ERROR = -32603;
328
608
  export declare const RPC_AUTH_REQUIRED = -32001;
329
609
  export declare const RPC_AGENT_NAME_CONFLICT = -32002;
330
610
  export declare const RPC_AGENT_STABLE_ID_CONFLICT = -32003;
611
+ /**
612
+ * A registration targeted a durable hibernation identity but did not present a
613
+ * valid broker-issued wake fence (missing/stale wake lease, fence token, or
614
+ * runtime generation). Only a broker-initiated fenced wake may revive it.
615
+ */
616
+ export declare const RPC_AGENT_WAKE_FENCE_REJECTED = -32004;
331
617
  import { buildCompatibilityInstanceScope as _buildCompatibilityInstanceScope, buildCompatibilityWorkspaceScope as _buildCompatibilityWorkspaceScope, buildRuntimeScopeCarrier as _buildRuntimeScopeCarrier } from "@pinet/transport-core";
332
618
  import type { InboundMessage as _InboundMessage, NormalizedMessageContent as _NormalizedMessageContent, OutboundAttachmentFile as _OutboundAttachmentFile, OutboundMessage as _OutboundMessage, AdapterCapabilityRequest as _AdapterCapabilityRequest, AdapterCapabilityResult as _AdapterCapabilityResult, AdapterCapabilityEffects as _AdapterCapabilityEffects, AdapterThreadClaimEffect as _AdapterThreadClaimEffect, MessageAdapter as _MessageAdapter, RuntimeScopeCarrier as _RuntimeScopeCarrier, WorkspaceInstallScopeCarrier as _WorkspaceInstallScopeCarrier, InstanceScopeCarrier as _InstanceScopeCarrier } from "@pinet/transport-core";
333
619
  export type InboundMessage = _InboundMessage;
@@ -375,3 +661,4 @@ export interface BrokerDBInterface {
375
661
  claimThread(threadId: string, agentId: string, source?: string, channel?: string): boolean;
376
662
  queueMessage(agentId: string, message: InboundMessage): void;
377
663
  }
664
+ export {};
package/dist/types.js CHANGED
@@ -9,6 +9,12 @@ export const RPC_INTERNAL_ERROR = -32603;
9
9
  export const RPC_AUTH_REQUIRED = -32001;
10
10
  export const RPC_AGENT_NAME_CONFLICT = -32002;
11
11
  export const RPC_AGENT_STABLE_ID_CONFLICT = -32003;
12
+ /**
13
+ * A registration targeted a durable hibernation identity but did not present a
14
+ * valid broker-issued wake fence (missing/stale wake lease, fence token, or
15
+ * runtime generation). Only a broker-initiated fenced wake may revive it.
16
+ */
17
+ export const RPC_AGENT_WAKE_FENCE_REJECTED = -32004;
12
18
  // ─── Message adapter (canonical transport contracts) ─────
13
19
  import { buildCompatibilityInstanceScope as _buildCompatibilityInstanceScope, buildCompatibilityWorkspaceScope as _buildCompatibilityWorkspaceScope, buildRuntimeScopeCarrier as _buildRuntimeScopeCarrier, } from "@pinet/transport-core";
14
20
  export const buildCompatibilityWorkspaceScope = _buildCompatibilityWorkspaceScope;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@pinet/broker-core",
3
- "version": "0.2.2",
3
+ "version": "0.2.6",
4
4
  "type": "module",
5
5
  "description": "Transport-neutral broker kernel primitives for pi transports",
6
6
  "author": "Will Porcellini <5994936+gugu91@users.noreply.github.com>",
7
7
  "license": "MIT",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "git+https://github.com/gugu91/extensions.git",
10
+ "url": "git+https://github.com/gugu91/pinet.git",
11
11
  "directory": "broker-core"
12
12
  },
13
13
  "publishConfig": {
@@ -38,12 +38,12 @@
38
38
  "scripts": {
39
39
  "build": "node ../scripts/build-package.mjs",
40
40
  "prepack": "pnpm run build",
41
- "lint": "eslint . --ext .ts",
41
+ "lint": "oxlint .",
42
42
  "typecheck": "tsc --noEmit",
43
- "test": "vitest run *.test.ts"
43
+ "test": "vitest run --config ../vitest.config.ts *.test.ts"
44
44
  },
45
45
  "dependencies": {
46
- "@pinet/transport-core": "0.2.2"
46
+ "@pinet/transport-core": "0.2.6"
47
47
  },
48
48
  "types": "./dist/index.d.ts"
49
49
  }