agent-relay-sdk 0.2.7 → 0.2.9

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/src/types.ts CHANGED
@@ -450,6 +450,9 @@ export interface Message {
450
450
  reactions?: MessageReaction[];
451
451
  readBy: string[];
452
452
  createdAt: number;
453
+ // True event time (#196). Equals createdAt for messages posted live; differs only when a
454
+ // Runner backfilled a message queued during an outage. Read `occurredAt ?? createdAt`.
455
+ occurredAt?: number;
453
456
  }
454
457
 
455
458
  export interface ReplyObligation {
@@ -537,6 +540,10 @@ export interface SendMessageInput {
537
540
  attachments?: AttachmentRef[];
538
541
  payload?: Record<string, unknown>;
539
542
  meta?: Record<string, unknown>;
543
+ // Epoch-ms event time, stamped when the event actually occurred (#196). When a Runner
544
+ // queues a message through its durable outbox during a server outage, this preserves the
545
+ // true time rather than the (later) server receive time. Defaults server-side to created_at.
546
+ occurredAt?: number;
540
547
  }
541
548
 
542
549
  export type ConnectorKind = "channel" | "event" | "provider" | "orchestrator";
@@ -1123,10 +1130,29 @@ export interface ActivityEventInput {
1123
1130
  // --- Orchestrators ---
1124
1131
 
1125
1132
  export type OrchestratorStatus = "online" | "offline";
1126
- export type SpawnProvider = "claude" | "codex";
1127
- export type SpawnApprovalMode = "open" | "guarded" | "read-only";
1133
+
1134
+ /** Spawn providers the runtime tuple is the single source of truth; the type derives from it. */
1135
+ export const SPAWN_PROVIDERS = ["claude", "codex"] as const;
1136
+ export type SpawnProvider = (typeof SPAWN_PROVIDERS)[number];
1137
+ export function isSpawnProvider(value: unknown): value is SpawnProvider {
1138
+ return typeof value === "string" && (SPAWN_PROVIDERS as readonly string[]).includes(value);
1139
+ }
1140
+
1141
+ /** Approval modes — runtime tuple + derived type. */
1142
+ export const APPROVAL_MODES = ["open", "guarded", "read-only"] as const;
1143
+ export type SpawnApprovalMode = (typeof APPROVAL_MODES)[number];
1144
+ export function isApprovalMode(value: unknown): value is SpawnApprovalMode {
1145
+ return typeof value === "string" && (APPROVAL_MODES as readonly string[]).includes(value);
1146
+ }
1147
+
1128
1148
  export type SpawnEffort = "low" | "medium" | "high" | "xhigh" | "max";
1129
- export type WorkspaceMode = "isolated" | "shared" | "inherit";
1149
+
1150
+ /** Workspace modes — runtime tuple + derived type + guard. */
1151
+ export const VALID_WORKSPACE_MODES = ["isolated", "shared", "inherit"] as const;
1152
+ export type WorkspaceMode = (typeof VALID_WORKSPACE_MODES)[number];
1153
+ export function isWorkspaceMode(value: unknown): value is WorkspaceMode {
1154
+ return typeof value === "string" && (VALID_WORKSPACE_MODES as readonly string[]).includes(value);
1155
+ }
1130
1156
  export type WorkspaceStatus = "active" | "ready" | "conflict" | "review_requested" | "merge_planned" | "merged" | "abandoned" | "cleanup_requested" | "cleaned";
1131
1157
 
1132
1158
  /** How a workspace's work is integrated back into its base branch. */
@@ -1187,6 +1213,8 @@ export interface WorkspaceGitState {
1187
1213
  lastCommit?: WorkspaceGitCommit;
1188
1214
  /** Ref/sha the ahead/behind counts were computed against. */
1189
1215
  baseRef?: string;
1216
+ /** Branch currently checked out in the worktree (for recorded-vs-live mismatch). */
1217
+ branch?: string;
1190
1218
  /** Set when the worktree path no longer exists on disk. */
1191
1219
  missing?: boolean;
1192
1220
  /** Populated when git interrogation failed. */
@@ -1255,12 +1283,44 @@ export interface WorkspaceMergeResult {
1255
1283
  mergedSha?: string;
1256
1284
  branchDeleted?: boolean;
1257
1285
  worktreeRemoved?: boolean;
1286
+ /** Fresh branch the worktree was recycled onto after a land-and-continue merge
1287
+ * (#206) — the relay repoints the workspace row at it. Absent for terminal lands. */
1288
+ newBranch?: string;
1289
+ /** True when the landed base branch was pushed to its upstream (origin). */
1290
+ pushed?: boolean;
1258
1291
  /** Resulting workspace status the relay should record. */
1259
1292
  status: WorkspaceStatus;
1260
1293
  /** Populated when the merge could not complete. */
1261
1294
  error?: string;
1262
1295
  }
1263
1296
 
1297
+ /**
1298
+ * Joined steward briefing for one workspace (#208): the row, owner + orchestrator
1299
+ * liveness, live git state, recorded-vs-live branch mismatch, any active steward
1300
+ * claim, and a recommended next action — so a steward (or release agent) doesn't
1301
+ * reconstruct it from ad-hoc shell + API calls.
1302
+ */
1303
+ export interface WorkspaceDiagnostics {
1304
+ workspaceId: string;
1305
+ status: WorkspaceStatus;
1306
+ mode: WorkspaceMode;
1307
+ repoRoot: string;
1308
+ worktreePath?: string;
1309
+ recordedBranch?: string;
1310
+ liveBranch?: string;
1311
+ baseRef?: string;
1312
+ branchMismatch?: boolean;
1313
+ owner?: { id?: string; status?: string; online: boolean };
1314
+ orchestrator?: { id?: string; online: boolean };
1315
+ /** Active claim that auto-merge yields to (#208), if held and unexpired. */
1316
+ claim?: { by?: string; purpose?: string; expiresAt?: number };
1317
+ /** Live worktree git state (proxied from the host); absent when unavailable. */
1318
+ gitState?: WorkspaceGitState;
1319
+ /** Why git state is absent (host offline, no worktree, …). */
1320
+ gitStateUnavailable?: string;
1321
+ recommendation: { action: "merge" | "rebase" | "cleanup" | "review" | "wait" | "none"; confidence: "high" | "medium" | "low"; reason: string };
1322
+ }
1323
+
1264
1324
  /** One changed file in a workspace diff against its base. */
1265
1325
  export interface WorkspaceDiffFile {
1266
1326
  path: string;
@@ -1313,6 +1373,14 @@ export interface WorkspaceDepsProvision {
1313
1373
  error?: string;
1314
1374
  }
1315
1375
 
1376
+ /** Result of symlinking configured untracked files/dirs from main into an isolated worktree. */
1377
+ export interface WorkspaceSymlinkProvision {
1378
+ /** Relative paths (from repo root) that were symlinked from the main checkout. */
1379
+ linked: string[];
1380
+ /** Per-pattern failures, if any (best-effort: a failure never blocks the spawn). */
1381
+ errors?: string[];
1382
+ }
1383
+
1316
1384
  export interface WorkspaceMetadata {
1317
1385
  id?: string;
1318
1386
  mode: WorkspaceMode;
@@ -1326,6 +1394,8 @@ export interface WorkspaceMetadata {
1326
1394
  status?: WorkspaceStatus;
1327
1395
  stewardAgentId?: string;
1328
1396
  deps?: WorkspaceDepsProvision;
1397
+ /** Configured untracked files/dirs symlinked from main (see WorkspaceConfig.symlinkPaths). */
1398
+ symlinks?: WorkspaceSymlinkProvision;
1329
1399
  probe?: WorkspaceProbe;
1330
1400
  }
1331
1401
 
@@ -1521,6 +1591,21 @@ export interface StewardConfig {
1521
1591
  keepaliveSeconds: number;
1522
1592
  }
1523
1593
 
1594
+ /**
1595
+ * Global workspace provisioning config for isolated worktrees (the dashboard "Workspace"
1596
+ * spawn option). A fresh git worktree only contains git-tracked files; node_modules are
1597
+ * symlinked from main automatically, and these additional untracked paths are too.
1598
+ */
1599
+ export interface WorkspaceConfig {
1600
+ /**
1601
+ * Files or filename patterns to symlink from the main checkout into each isolated
1602
+ * worktree. Plain names ("AGENTS.md", ".claude-rig") match files and directories;
1603
+ * entries containing glob metacharacters (*?[]{}) are expanded against main. A path
1604
+ * is only linked if it actually exists in main — missing entries are ignored.
1605
+ */
1606
+ symlinkPaths: string[];
1607
+ }
1608
+
1524
1609
  /**
1525
1610
  * Continuous self-improvement ("Insights") module config — feature toggles for the
1526
1611
  * dogfooding flywheel (see docs/self-improvement.md, epic #183). Everything here is
@@ -2062,3 +2147,33 @@ export interface HealthReport {
2062
2147
  generatedAt: number;
2063
2148
  checks: HealthCheck[];
2064
2149
  }
2150
+
2151
+ // --- Shared micro-helpers (single source of truth; do not re-declare per file) ---
2152
+
2153
+ /** True for a non-null, non-array object. The canonical type guard for the whole repo. */
2154
+ export function isRecord(value: unknown): value is Record<string, unknown> {
2155
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2156
+ }
2157
+
2158
+ /**
2159
+ * Narrow `unknown` to a non-empty trimmed string, else `undefined`.
2160
+ * Settled semantics: whitespace-only is treated as empty (returns `undefined`).
2161
+ */
2162
+ export function stringValue(value: unknown): string | undefined {
2163
+ if (typeof value !== "string") return undefined;
2164
+ const trimmed = value.trim();
2165
+ return trimmed.length > 0 ? trimmed : undefined;
2166
+ }
2167
+
2168
+ /** Extract a human-readable message from any thrown value. */
2169
+ export function errMessage(error: unknown): string {
2170
+ return error instanceof Error ? error.message : String(error);
2171
+ }
2172
+
2173
+ // --- Relay connection defaults ---
2174
+
2175
+ /** Default port the relay server listens on. */
2176
+ export const DEFAULT_RELAY_PORT = 4850;
2177
+
2178
+ /** Default relay base URL. Loopback spelling settled on `127.0.0.1` (not `localhost`). */
2179
+ export const DEFAULT_RELAY_URL = `http://127.0.0.1:${DEFAULT_RELAY_PORT}`;