agent-relay-server 0.62.3 → 0.63.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.
Files changed (160) hide show
  1. package/docs/openapi.json +1 -1
  2. package/package.json +2 -2
  3. package/public/assets/{MessageBubble-DRrxfjyT.js → MessageBubble-Cl6ufPHw.js} +2 -2
  4. package/public/assets/MessageBubble-Cl6ufPHw.js.map +1 -0
  5. package/public/assets/{PlanGraphPanel-Dp2eYazz.js → PlanGraphPanel-BnfjmkQ8.js} +2 -2
  6. package/public/assets/{PlanGraphPanel-Dp2eYazz.js.map → PlanGraphPanel-BnfjmkQ8.js.map} +1 -1
  7. package/public/assets/{activity--t0U2yzq.js → activity-aFxvGLtd.js} +2 -2
  8. package/public/assets/{activity--t0U2yzq.js.map → activity-aFxvGLtd.js.map} +1 -1
  9. package/public/assets/{agent-profiles-BMtJYzxn.js → agent-profiles-B4mleUDz.js} +2 -2
  10. package/public/assets/{agent-profiles-BMtJYzxn.js.map → agent-profiles-B4mleUDz.js.map} +1 -1
  11. package/public/assets/{agents-Ck9AePlc.js → agents-DW5djToQ.js} +2 -2
  12. package/public/assets/{agents-Ck9AePlc.js.map → agents-DW5djToQ.js.map} +1 -1
  13. package/public/assets/{analytics-CzfK387L.js → analytics-CRi6thtg.js} +2 -2
  14. package/public/assets/{analytics-CzfK387L.js.map → analytics-CRi6thtg.js.map} +1 -1
  15. package/public/assets/{automation-Cgw8vtE8.js → automation-Do4OpauI.js} +2 -2
  16. package/public/assets/{automation-Cgw8vtE8.js.map → automation-Do4OpauI.js.map} +1 -1
  17. package/public/assets/{branch-state-badge-DnEEPtOP.js → branch-state-badge-D3W3w7zz.js} +2 -2
  18. package/public/assets/{branch-state-badge-DnEEPtOP.js.map → branch-state-badge-D3W3w7zz.js.map} +1 -1
  19. package/public/assets/{channels-Dc3L2MQs.js → channels-BytdR9NS.js} +2 -2
  20. package/public/assets/{channels-Dc3L2MQs.js.map → channels-BytdR9NS.js.map} +1 -1
  21. package/public/assets/{chat-Fc6iJ7sa.js → chat-CvaQ2czL.js} +2 -2
  22. package/public/assets/{chat-Fc6iJ7sa.js.map → chat-CvaQ2czL.js.map} +1 -1
  23. package/public/assets/{connectors-Dc2ttGWs.js → connectors-BLQDp8Bc.js} +2 -2
  24. package/public/assets/{connectors-Dc2ttGWs.js.map → connectors-BLQDp8Bc.js.map} +1 -1
  25. package/public/assets/{display-DzNvOu1j.js → display-B06I5sqa.js} +3 -3
  26. package/public/assets/display-B06I5sqa.js.map +1 -0
  27. package/public/assets/{formatted-body-impl-Bg-gx7rG.js → formatted-body-impl-0Lf8e1Ic.js} +2 -2
  28. package/public/assets/{formatted-body-impl-Bg-gx7rG.js.map → formatted-body-impl-0Lf8e1Ic.js.map} +1 -1
  29. package/public/assets/{index-BeDncjN4.js → index-C3su8ezq.js} +6 -6
  30. package/public/assets/{index-BeDncjN4.js.map → index-C3su8ezq.js.map} +1 -1
  31. package/public/assets/{insights-c08aW-7n.js → insights-64uExH1E.js} +2 -2
  32. package/public/assets/{insights-c08aW-7n.js.map → insights-64uExH1E.js.map} +1 -1
  33. package/public/assets/{integrations-BwpgcqnF.js → integrations-HyC1EaIp.js} +2 -2
  34. package/public/assets/{integrations-BwpgcqnF.js.map → integrations-HyC1EaIp.js.map} +1 -1
  35. package/public/assets/{maintenance-CTKP0kWB.js → maintenance-EVBpKH07.js} +2 -2
  36. package/public/assets/{maintenance-CTKP0kWB.js.map → maintenance-EVBpKH07.js.map} +1 -1
  37. package/public/assets/{managed-agents-BofCxo8d.js → managed-agents-BLZPxGuw.js} +2 -2
  38. package/public/assets/{managed-agents-BofCxo8d.js.map → managed-agents-BLZPxGuw.js.map} +1 -1
  39. package/public/assets/{markdown-preview-impl-CQ-6BIb8.js → markdown-preview-impl-Bg6rCWYN.js} +2 -2
  40. package/public/assets/{markdown-preview-impl-CQ-6BIb8.js.map → markdown-preview-impl-Bg6rCWYN.js.map} +1 -1
  41. package/public/assets/{memory-DvfXjMoi.js → memory-Bjr8bgjj.js} +2 -2
  42. package/public/assets/{memory-DvfXjMoi.js.map → memory-Bjr8bgjj.js.map} +1 -1
  43. package/public/assets/{messages-C9VsPzZ_.js → messages-CRYw1F4z.js} +2 -2
  44. package/public/assets/{messages-C9VsPzZ_.js.map → messages-CRYw1F4z.js.map} +1 -1
  45. package/public/assets/{orchestrators-MffVueeE.js → orchestrators-D-co1vdp.js} +2 -2
  46. package/public/assets/{orchestrators-MffVueeE.js.map → orchestrators-D-co1vdp.js.map} +1 -1
  47. package/public/assets/{overview-BSVajefM.js → overview-Ddy5czri.js} +2 -2
  48. package/public/assets/{overview-BSVajefM.js.map → overview-Ddy5czri.js.map} +1 -1
  49. package/public/assets/{pairs-B5711-Cs.js → pairs-CFVM8uHL.js} +2 -2
  50. package/public/assets/{pairs-B5711-Cs.js.map → pairs-CFVM8uHL.js.map} +1 -1
  51. package/public/assets/{security-DkUwK9Vj.js → security-Df4_76bh.js} +2 -2
  52. package/public/assets/{security-DkUwK9Vj.js.map → security-Df4_76bh.js.map} +1 -1
  53. package/public/assets/{select-DrM2RRiT.js → select-Cq3BBnL9.js} +2 -2
  54. package/public/assets/{select-DrM2RRiT.js.map → select-Cq3BBnL9.js.map} +1 -1
  55. package/public/assets/{settings-DdKCb-vy.js → settings-DOLEYXZL.js} +2 -2
  56. package/public/assets/{settings-DdKCb-vy.js.map → settings-DOLEYXZL.js.map} +1 -1
  57. package/public/assets/{store-iTiheuTD.js → store-C1E8jmNE.js} +4 -4
  58. package/public/assets/store-C1E8jmNE.js.map +1 -0
  59. package/public/assets/{tasks-e1y1PFfO.js → tasks-BcsmPi9_.js} +2 -2
  60. package/public/assets/{tasks-e1y1PFfO.js.map → tasks-BcsmPi9_.js.map} +1 -1
  61. package/public/assets/{teams-BUcxoGC_.js → teams-BQrV3eKI.js} +2 -2
  62. package/public/assets/{teams-BUcxoGC_.js.map → teams-BQrV3eKI.js.map} +1 -1
  63. package/public/assets/{terminal-viewer-impl-CmZjQOB2.js → terminal-viewer-impl-Dle04qpH.js} +2 -2
  64. package/public/assets/{terminal-viewer-impl-CmZjQOB2.js.map → terminal-viewer-impl-Dle04qpH.js.map} +1 -1
  65. package/public/assets/{work-queue-CXBQx43n.js → work-queue-BLhTLg4o.js} +2 -2
  66. package/public/assets/{work-queue-CXBQx43n.js.map → work-queue-BLhTLg4o.js.map} +1 -1
  67. package/public/assets/{workspaces-D2EfZh9a.js → workspaces-4NCNTmRQ.js} +3 -3
  68. package/public/assets/{workspaces-D2EfZh9a.js.map → workspaces-4NCNTmRQ.js.map} +1 -1
  69. package/public/index.html +3 -3
  70. package/src/agent-ref.ts +8 -6
  71. package/src/automations/constants.ts +12 -0
  72. package/src/automations/cron.ts +129 -0
  73. package/src/automations/crud.ts +84 -0
  74. package/src/automations/dispatch.ts +275 -0
  75. package/src/automations/index.ts +5 -0
  76. package/src/automations/reconcile.ts +245 -0
  77. package/src/automations/storage.ts +181 -0
  78. package/src/automations/types.ts +16 -0
  79. package/src/automations/validation.ts +140 -0
  80. package/src/automations.ts +1 -1045
  81. package/src/db/activity.ts +1 -1
  82. package/src/db/agent-predicates.ts +9 -0
  83. package/src/db/agent-search.ts +2 -2
  84. package/src/db/agents.ts +13 -41
  85. package/src/db/artifacts.ts +8 -8
  86. package/src/db/channel-identity.ts +38 -0
  87. package/src/db/channels.ts +37 -61
  88. package/src/db/continuation-archives.ts +4 -4
  89. package/src/db/delivery.ts +7 -12
  90. package/src/db/inbox.ts +1 -1
  91. package/src/db/integrations.ts +4 -4
  92. package/src/db/issue-lifecycle.ts +6 -6
  93. package/src/db/mappers.ts +1 -2
  94. package/src/db/merge-lease.ts +3 -3
  95. package/src/db/message-claims.ts +16 -0
  96. package/src/db/message-queries.ts +8 -0
  97. package/src/db/message-reads.ts +26 -9
  98. package/src/db/messages.ts +17 -41
  99. package/src/db/notification-subscriptions.ts +2 -2
  100. package/src/db/orchestrators.ts +4 -4
  101. package/src/db/pair-maintenance.ts +9 -0
  102. package/src/db/pairs.ts +10 -18
  103. package/src/db/plans.ts +1 -1
  104. package/src/db/policy-runtime.ts +14 -0
  105. package/src/db/project-entries.ts +1 -1
  106. package/src/db/projects.ts +2 -2
  107. package/src/db/shared.ts +7 -0
  108. package/src/db/stats.ts +2 -2
  109. package/src/db/task-core.ts +18 -0
  110. package/src/db/task-maintenance.ts +24 -0
  111. package/src/db/tasks.ts +5 -17
  112. package/src/db/teams.ts +3 -3
  113. package/src/db/workspaces.ts +6 -6
  114. package/src/issue-tracker/github.ts +3 -3
  115. package/src/maintenance/constants.ts +35 -0
  116. package/src/maintenance/events.ts +32 -0
  117. package/src/maintenance/index.ts +7 -0
  118. package/src/maintenance/jobs.ts +340 -0
  119. package/src/maintenance/orphaned-sessions.ts +86 -0
  120. package/src/maintenance/scheduler.ts +231 -0
  121. package/src/maintenance/teams.ts +65 -0
  122. package/src/maintenance/types.ts +31 -0
  123. package/src/maintenance/workspaces.ts +251 -0
  124. package/src/maintenance.ts +1 -1099
  125. package/src/mcp/identity.ts +131 -0
  126. package/src/mcp/index.ts +208 -0
  127. package/src/mcp/tools-messaging.ts +459 -0
  128. package/src/mcp/tools-spawn.ts +145 -0
  129. package/src/mcp/tools-workspace.ts +227 -0
  130. package/src/mcp/types.ts +24 -0
  131. package/src/mcp/validation.ts +104 -0
  132. package/src/mcp.ts +1 -1319
  133. package/src/notification-router.ts +2 -2
  134. package/src/notification-rules.ts +2 -2
  135. package/src/project-ingest.ts +3 -3
  136. package/src/project-instructions.ts +1 -1
  137. package/src/provider-config-store.ts +3 -3
  138. package/src/provider-state.ts +1 -1
  139. package/src/reviewer-pipeline.ts +1 -1
  140. package/src/self-resume.ts +3 -7
  141. package/src/services/agent-action.ts +2 -2
  142. package/src/services/issue-activity.ts +0 -4
  143. package/src/services/issue-associations.ts +2 -2
  144. package/src/services/issue-lifecycle.ts +7 -7
  145. package/src/services/managed-running.ts +1 -1
  146. package/src/services/parity-harness.ts +3 -3
  147. package/src/services/plan-graph.ts +3 -3
  148. package/src/services/send-message.ts +16 -12
  149. package/src/services/shutdown-agent.ts +2 -2
  150. package/src/services/team-templates.ts +2 -2
  151. package/src/services/team.ts +2 -2
  152. package/src/settings/modules.ts +1 -1
  153. package/src/settings/registry.ts +3 -3
  154. package/src/spawn-command.ts +1 -1
  155. package/src/sse.ts +0 -4
  156. package/src/workspace-actions.ts +1 -1
  157. package/src/workspace-probe.ts +3 -7
  158. package/public/assets/MessageBubble-DRrxfjyT.js.map +0 -1
  159. package/public/assets/display-DzNvOu1j.js.map +0 -1
  160. package/public/assets/store-iTiheuTD.js.map +0 -1
@@ -57,7 +57,7 @@ export interface NotificationScope {
57
57
  paths?: string[];
58
58
  }
59
59
 
60
- export interface NotificationMessage {
60
+ interface NotificationMessage {
61
61
  subject?: string;
62
62
  body: string;
63
63
  payload?: Record<string, unknown>;
@@ -67,7 +67,7 @@ export interface NotificationMessage {
67
67
  replyExpected?: boolean;
68
68
  }
69
69
 
70
- export interface RouteNotificationInput {
70
+ interface RouteNotificationInput {
71
71
  type: NotificationType;
72
72
  scope: NotificationScope;
73
73
  /**
@@ -33,7 +33,7 @@ export interface NotificationRule {
33
33
  evaluate(agent: AgentCard, ctx: NotificationRuleContext): RuleDecision;
34
34
  }
35
35
 
36
- export interface AudienceMember {
36
+ interface AudienceMember {
37
37
  agentId: string;
38
38
  /** The rule whose decision was decisive (last non-abstain wins) — carried for explainability (#446). */
39
39
  matchedRule: string;
@@ -161,7 +161,7 @@ export function setSubscriptionRules(rules: NotificationRule[]): void {
161
161
  }
162
162
 
163
163
  /** The effective ordered rule list for a type: its registered defaults, then subscription overrides. */
164
- export function audienceRulesFor(type: NotificationType): NotificationRule[] {
164
+ function audienceRulesFor(type: NotificationType): NotificationRule[] {
165
165
  const defaults = audienceRegistry.get(type);
166
166
  if (!defaults) return [];
167
167
  return subscriptionRules.length === 0 ? defaults : [...defaults, ...subscriptionRules];
@@ -16,7 +16,7 @@ import type { ProjectEntry } from "./types";
16
16
 
17
17
  const INGEST_FILENAME = "CLAUDE.md";
18
18
 
19
- export interface ParsedSection {
19
+ interface ParsedSection {
20
20
  /** Heading text (the entry title). For pre-heading preamble content: "(preamble)". */
21
21
  title: string;
22
22
  /** Section body — lines under the heading up to the next heading, trimmed. May be "". */
@@ -25,14 +25,14 @@ export interface ParsedSection {
25
25
  anchor: string;
26
26
  }
27
27
 
28
- export interface IngestRootResult {
28
+ interface IngestRootResult {
29
29
  rootPath: string;
30
30
  filePath: string;
31
31
  found: boolean;
32
32
  sections: number;
33
33
  }
34
34
 
35
- export interface IngestResult {
35
+ interface IngestResult {
36
36
  projectId: string;
37
37
  created: number;
38
38
  updated: number;
@@ -31,7 +31,7 @@ export interface ProjectInstructionPolicy {
31
31
  policy?: ProjectInstructionPolicyName;
32
32
  }
33
33
 
34
- export interface ComposeProjectInstructionsOptions {
34
+ interface ComposeProjectInstructionsOptions {
35
35
  /** Named policy selecting the included source set. Default `all`. */
36
36
  policy?: ProjectInstructionPolicyName;
37
37
  /** Explicit source set; overrides `policy` when given (the low-level lever). */
@@ -24,15 +24,15 @@ export const VALID_PROVIDER_CONFIGS = SPAWN_PROVIDERS;
24
24
  type ProviderConfigProvider = string;
25
25
  type ProviderConfigEntry = ConfigEntry<ProviderConfig>;
26
26
 
27
- export function defaultProviderConfigHost(): string {
27
+ function defaultProviderConfigHost(): string {
28
28
  return hostname();
29
29
  }
30
30
 
31
- export function providerConfigKey(host: string, provider: string): string {
31
+ function providerConfigKey(host: string, provider: string): string {
32
32
  return `${normalizeProviderConfigHost(host)}/${normalizeProviderConfigProvider(provider)}`;
33
33
  }
34
34
 
35
- export function parseProviderConfigKey(key: string): { host: string; provider: ProviderConfigProvider } | null {
35
+ function parseProviderConfigKey(key: string): { host: string; provider: ProviderConfigProvider } | null {
36
36
  const slash = key.lastIndexOf("/");
37
37
  if (slash <= 0 || slash === key.length - 1) return null;
38
38
  const host = cleanString(key.slice(0, slash), "host", { required: true, max: 120 })!;
@@ -6,7 +6,7 @@ import { isRecord } from "agent-relay-sdk";
6
6
  // the transient-agent reaper (don't reap a held agent), and the rate-limit
7
7
  // resume sweep. The dashboard has its own client-side copy in display.ts.
8
8
 
9
- export interface ProviderStateView {
9
+ interface ProviderStateView {
10
10
  state: string;
11
11
  reason?: string;
12
12
  label?: string;
@@ -9,7 +9,7 @@ import type { Command, WorkspaceMergePreview, WorkspaceRecord } from "./types";
9
9
 
10
10
  type ReviewDecision = "APPROVED" | "CHANGES_REQUESTED" | "REVIEW_REQUIRED";
11
11
 
12
- export function parsePrNumber(prUrl: string | undefined): number | undefined {
12
+ function parsePrNumber(prUrl: string | undefined): number | undefined {
13
13
  if (!prUrl) return undefined;
14
14
  const match = prUrl.match(/\/pull\/(\d+)(?:\D|$)/);
15
15
  if (!match) return undefined;
@@ -14,7 +14,7 @@ import { emitRelayEvent } from "./events";
14
14
  import { routeNotification } from "./notification-router";
15
15
  import type { AgentCard, Command, ContinuationEnvelope, ContinuationLedgerEntry, SelfResumeMode } from "./types";
16
16
 
17
- export interface CompactAndResumeInput {
17
+ interface CompactAndResumeInput {
18
18
  agentId: string;
19
19
  workingState: string;
20
20
  ruledOut?: unknown;
@@ -22,7 +22,7 @@ export interface CompactAndResumeInput {
22
22
  objective?: string;
23
23
  }
24
24
 
25
- export interface CompactAndResumeResult {
25
+ interface CompactAndResumeResult {
26
26
  ok: boolean;
27
27
  mode: SelfResumeMode;
28
28
  envelope: ContinuationEnvelope;
@@ -110,7 +110,7 @@ export function enqueueContinuationInjectionAfterClear(command: Command): Comman
110
110
  return inject;
111
111
  }
112
112
 
113
- export function renderContinuation(envelope: ContinuationEnvelope): string {
113
+ function renderContinuation(envelope: ContinuationEnvelope): string {
114
114
  const ledger = envelope.ledger.length
115
115
  ? envelope.ledger.map((entry) => `- gen ${entry.gen} @ ${new Date(entry.at).toISOString()}: ${entry.ruledOut}${entry.why ? `; why: ${entry.why}` : ""}`).join("\n")
116
116
  : "- none";
@@ -231,7 +231,3 @@ function ledgerEntry(ruledOut: string, why: string, generation: number, now: num
231
231
  if (!cleaned) throw new ValidationError("ruledOut entries cannot be blank");
232
232
  return { gen: generation, ruledOut: cleaned, why, at: now };
233
233
  }
234
-
235
- export function continuationForAgent(agentId: string): ContinuationEnvelope | null {
236
- return getContinuationEnvelope(agentId);
237
- }
@@ -8,7 +8,7 @@ import type { AgentCard, Command } from "../types";
8
8
 
9
9
  export type AgentAction = "compact" | "clearContext" | "inject";
10
10
 
11
- export interface AgentActionInput {
11
+ interface AgentActionInput {
12
12
  agentId: string;
13
13
  action: AgentAction;
14
14
  message?: string;
@@ -16,7 +16,7 @@ export interface AgentActionInput {
16
16
  requestedBy?: string;
17
17
  }
18
18
 
19
- export interface AgentActionResult {
19
+ interface AgentActionResult {
20
20
  action: AgentAction;
21
21
  command: Command;
22
22
  }
@@ -24,7 +24,3 @@ export function recordAndEmitIssueActivity(input: RecordIssueActivityInput) {
24
24
  emitActivityEvent(event);
25
25
  return event;
26
26
  }
27
-
28
- export function resolveIssueActivityMapping(input: { issueRefId?: string; issueRef?: string; defaultRepo?: string; provider?: IssueProvider }) {
29
- return resolveIssueActivityRef(input);
30
- }
@@ -8,7 +8,7 @@ import { getIssueRef, resolveIssueRefByExternalKey, resolveIssueRefFromString }
8
8
  import type { IssueAssociationEntityType, IssueAssociationIssue, IssueProvider } from "../types";
9
9
  import { ValidationError } from "../db/connection";
10
10
 
11
- export interface ResolveAssociationIssueInput {
11
+ interface ResolveAssociationIssueInput {
12
12
  issueRefId?: string;
13
13
  ref?: string;
14
14
  defaultRepo?: string;
@@ -19,7 +19,7 @@ export interface ResolveAssociationIssueInput {
19
19
  title?: string;
20
20
  }
21
21
 
22
- export interface AssociateIssueInput extends ResolveAssociationIssueInput {
22
+ interface AssociateIssueInput extends ResolveAssociationIssueInput {
23
23
  entityType: IssueAssociationEntityType;
24
24
  entityId: string;
25
25
  }
@@ -17,7 +17,7 @@ type LifecycleWorkspace = Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "
17
17
  type AdapterResolver = (ref: IssueRef) => IssueTrackerAdapter;
18
18
  type LogFn = (message: string) => void;
19
19
 
20
- export interface LandedIssueLifecycleInput {
20
+ interface LandedIssueLifecycleInput {
21
21
  workspace: LifecycleWorkspace;
22
22
  mergedSha?: string;
23
23
  subject?: string;
@@ -31,7 +31,7 @@ export interface LandedIssueLifecycleInput {
31
31
  prLand?: boolean;
32
32
  }
33
33
 
34
- export interface ReopenIssueLifecycleInput {
34
+ interface ReopenIssueLifecycleInput {
35
35
  issueRefId?: string;
36
36
  ref?: string;
37
37
  defaultRepo?: string;
@@ -46,19 +46,19 @@ export interface ReopenIssueLifecycleInput {
46
46
  entityId?: string;
47
47
  }
48
48
 
49
- export interface IssueLifecycleOptions {
49
+ interface IssueLifecycleOptions {
50
50
  adapterResolver?: AdapterResolver;
51
51
  log?: LogFn;
52
52
  }
53
53
 
54
- export type LandIssueRefSource = "association" | "commit" | "backlink";
54
+ type LandIssueRefSource = "association" | "commit" | "backlink";
55
55
 
56
- export type CloseIssueLifecycleResult =
56
+ type CloseIssueLifecycleResult =
57
57
  | { issueRef: IssueRef; action: "closed"; source: LandIssueRefSource; landKey: string }
58
58
  | { issueRef: IssueRef; action: "skipped"; reason: "already-closed" | "already-processed"; landKey: string }
59
59
  | { issueRef: IssueRef; action: "failed"; error: string; landKey: string };
60
60
 
61
- export type ReopenIssueLifecycleResult =
61
+ type ReopenIssueLifecycleResult =
62
62
  | { issueRef: IssueRef; action: "reopened"; landKey: string }
63
63
  | { issueRef: IssueRef; action: "skipped"; reason: "already-open"; landKey: string }
64
64
  | { issueRef: IssueRef; action: "failed"; error: string; landKey: string };
@@ -210,7 +210,7 @@ export function parseBacklinkIssueRefs(text: string | undefined, fallbackDefault
210
210
  return issueRefMap(refs);
211
211
  }
212
212
 
213
- export function resolveIssueRefsForLand(input: LandedIssueLifecycleInput): { source: LandIssueRefSource; refs: IssueRef[] } {
213
+ function resolveIssueRefsForLand(input: LandedIssueLifecycleInput): { source: LandIssueRefSource; refs: IssueRef[] } {
214
214
  const associated = associatedIssueRefs(input.workspace);
215
215
  if (associated.length > 0) return { source: "association", refs: associated };
216
216
  const fallbackDefaultRepo = landDefaultRepo(input.workspace);
@@ -19,7 +19,7 @@ import { emitMessageAvailable, emitMessageDeliveryUpdated, emitNewMessage } from
19
19
  import type { AuthContext } from "./auth-context";
20
20
  import type { ManagedAgentState } from "../types";
21
21
 
22
- export interface ManagedRunningInput {
22
+ interface ManagedRunningInput {
23
23
  policyName?: string;
24
24
  spawnRequestId?: string;
25
25
  agentId: string;
@@ -15,7 +15,7 @@ import { subscribeRelayEvents } from "../events";
15
15
  /** An emitted relay event, normalized to the fields parity compares — volatile
16
16
  * `seq`/`timestamp` are deliberately dropped so only behavior, not ordering noise,
17
17
  * is asserted. */
18
- export interface CapturedEvent {
18
+ interface CapturedEvent {
19
19
  type: string;
20
20
  source: string;
21
21
  subject?: string;
@@ -36,7 +36,7 @@ export interface Capture<S> {
36
36
  * settled so the harness can snapshot. Keep the abstraction swappable: a later slice
37
37
  * can replace a direct-call transport with an end-to-end HTTP one without reshaping
38
38
  * the harness. */
39
- export interface ParityTransport<C> {
39
+ interface ParityTransport<C> {
40
40
  id: string;
41
41
  invoke(ctx: C): Promise<void>;
42
42
  }
@@ -57,7 +57,7 @@ export interface ParityOp<C, S> {
57
57
  }
58
58
 
59
59
  /** Drive one transport in isolation and capture everything it produced. */
60
- export async function captureTransport<C, S>(
60
+ async function captureTransport<C, S>(
61
61
  op: ParityOp<C, S>,
62
62
  transportId: string,
63
63
  ctx: C,
@@ -9,7 +9,7 @@ import type { AgentCard, Plan, PlanEdge, PlanNode, PlanOwnerRef, PlanStatus } fr
9
9
 
10
10
  export const PLAN_STATUSES = ["pending", "in-progress", "landed", "blocked"] as const;
11
11
 
12
- export interface PlanNodeInput {
12
+ interface PlanNodeInput {
13
13
  id?: unknown;
14
14
  label?: unknown;
15
15
  scopeBlurb?: unknown;
@@ -21,7 +21,7 @@ export interface PlanNodeInput {
21
21
  blackboardRefs?: unknown;
22
22
  }
23
23
 
24
- export interface PlanNodePatch {
24
+ interface PlanNodePatch {
25
25
  label?: unknown;
26
26
  scopeBlurb?: unknown;
27
27
  ownerRef?: unknown;
@@ -32,7 +32,7 @@ export interface PlanNodePatch {
32
32
  blackboardRefs?: unknown;
33
33
  }
34
34
 
35
- export interface PlanCreateInput {
35
+ interface PlanCreateInput {
36
36
  threadId: unknown;
37
37
  teamId?: unknown;
38
38
  channel?: unknown;
@@ -22,7 +22,14 @@
22
22
  // OUT OF SCOPE (transport-edge, excluded from the parity facet): automatic memory injection
23
23
  // (needs request-derived context) and per-transport audit (HTTP domain row vs MCP tool-call row).
24
24
  import { isMechanicalMessageKind, isRecord, isReservedAgentId } from "agent-relay-sdk";
25
- import { ValidationError, getMessage, listAgents, sendMessageWithResult, channelObligationAnsweredBy } from "../db";
25
+ import {
26
+ ValidationError,
27
+ getMessage,
28
+ listAgents,
29
+ sendMessageWithResult,
30
+ channelObligationAnsweredBy,
31
+ spawnObligationAnsweredBy,
32
+ } from "../db";
26
33
  import { planSend, type DeliveryReceipt } from "../agent-ref";
27
34
  import { emitMessageQueued, emitNewMessage } from "../sse";
28
35
  import { getLifecycleManager } from "../lifecycle-manager";
@@ -32,14 +39,14 @@ import type { AuthContext } from "./auth-context";
32
39
  import type { IntegrationTokenConfig } from "../config";
33
40
  import type { Message, SendMessageInput } from "../types";
34
41
 
35
- export interface SendMessageResult {
42
+ interface SendMessageResult {
36
43
  message: Message;
37
44
  created: boolean;
38
45
  /** Synchronous delivery receipt (live recipients / queued / store-ahead). */
39
46
  receipt: DeliveryReceipt;
40
47
  }
41
48
 
42
- export interface SendMessageOptions {
49
+ interface SendMessageOptions {
43
50
  /** The integration token when the MCP caller authenticated with one. AuthContext stays lean
44
51
  * (foundation contract) — the integration-specific target policy rides here, not on the ctx. */
45
52
  integration?: IntegrationTokenConfig | null;
@@ -159,16 +166,13 @@ export function sendMessageService(
159
166
  // Resolve BEFORE authorize so both run against the canonical id (kills the HTTP-authorizes-raw
160
167
  // vs MCP-authorizes-resolved drift).
161
168
  const receipt = resolveSendTarget(input, input.from);
162
- // Channel-answer linking: an agent answering the human through a channel bridge posts a body-less
163
- // message to the channel agent (e.g. `agent-relay /message telegram '{"action":"reply",...}'`) that
164
- // carries no reply/conversation linkage, so its reply obligation never clears and the Stop hook nags
165
- // it into a redundant `/reply` that leaks back to the human as a second message. When the agent has
166
- // exactly ONE open obligation on that channel this send is unambiguously the answer — link it here,
167
- // at send time, so the obligation clears with no extra message. (`channelObligationAnsweredBy` is a
168
- // no-op unless `to` resolved to a channel agent with a single open obligation; deciding at send time
169
- // — not query time — keeps a later sibling conversation from retroactively mis-attributing it.)
169
+ // Reply-obligation linking: some real answers are ordinary sends without replyTo/thread linkage.
170
+ // Channel bridge replies and spawn report-backs both have a single unambiguous open obligation case;
171
+ // link those at send time so the obligation clears with one message and the Stop hook does not nag
172
+ // the agent into a redundant `/reply`.
170
173
  if (!input.replyTo && !isMechanicalMessageKind(input.kind)) {
171
- const answered = channelObligationAnsweredBy(input.from, input.to);
174
+ const answered = channelObligationAnsweredBy(input.from, input.to)
175
+ ?? spawnObligationAnsweredBy(input.from, input.to);
172
176
  if (answered !== null) input.replyTo = answered;
173
177
  }
174
178
  authorizeSend(input, ctx, opts, reservedSink);
@@ -50,7 +50,7 @@ export class ShutdownTargetError extends Error {}
50
50
 
51
51
  type OnlineOrchestrator = NonNullable<ReturnType<typeof getOrchestrator>>;
52
52
 
53
- export interface ShutdownAgentInput {
53
+ interface ShutdownAgentInput {
54
54
  agentId?: string;
55
55
  policyName?: string;
56
56
  spawnRequestId?: string;
@@ -69,7 +69,7 @@ export interface ShutdownAgentInput {
69
69
  auditMetadata?: Record<string, unknown>;
70
70
  }
71
71
 
72
- export interface ShutdownAgentResult {
72
+ interface ShutdownAgentResult {
73
73
  command: Command;
74
74
  orchestratorId: string;
75
75
  agent: AgentCard | null;
@@ -8,7 +8,7 @@ import { setCallerTeamBrief } from "./team";
8
8
  import { spawnAgent, type SpawnAgentInput, type SpawnAgentResult } from "./spawn-agent";
9
9
  import type { AgentLifecycle, SpawnApprovalMode, SpawnProvider, TeamTemplate, TeamTemplateCompositionEntry, WorkspaceMode } from "../types";
10
10
 
11
- export interface TeamTemplateInstantiateInput {
11
+ interface TeamTemplateInstantiateInput {
12
12
  slug: string;
13
13
  orchestratorId?: unknown;
14
14
  cwd?: unknown;
@@ -19,7 +19,7 @@ export interface TeamTemplateInstantiateInput {
19
19
  waitForRegistrationMs?: unknown;
20
20
  }
21
21
 
22
- export interface TeamTemplateInstantiateResult {
22
+ interface TeamTemplateInstantiateResult {
23
23
  template: TeamTemplate;
24
24
  team: ReturnType<typeof setCallerTeamBrief>["team"];
25
25
  spawned: SpawnAgentResult[];
@@ -7,7 +7,7 @@ import type { Team } from "../types";
7
7
  export class TeamAuthError extends Error {}
8
8
  export class TeamNotFoundError extends Error {}
9
9
 
10
- export interface TeamPayload {
10
+ interface TeamPayload {
11
11
  team: Team;
12
12
  roster: ReturnType<typeof getTeamRoster>;
13
13
  brief: string | null;
@@ -16,7 +16,7 @@ export interface TeamPayload {
16
16
  issues: ReturnType<typeof listIssueRefsForEntity>;
17
17
  }
18
18
 
19
- export interface TeamBriefInput {
19
+ interface TeamBriefInput {
20
20
  title?: string;
21
21
  brief?: string;
22
22
  definitionOfDone?: string;
@@ -73,7 +73,7 @@ export function registerChannelTypeSetting(input: {
73
73
  });
74
74
  }
75
75
 
76
- export interface ProviderSettingsDeclaration {
76
+ interface ProviderSettingsDeclaration {
77
77
  provider: string;
78
78
  defaults: ProviderConfig;
79
79
  display?: Partial<SettingDisplay>;
@@ -41,7 +41,7 @@ const ajv = new Ajv({ allErrors: true, strict: false });
41
41
  * The registry resolves any omitted read/write scope to the fail-closed admin
42
42
  * default and returns a fully-populated `SettingDescriptor`.
43
43
  */
44
- export type SettingRegistration<T = unknown> = Omit<SettingDescriptor<T>, "scope"> & {
44
+ type SettingRegistration<T = unknown> = Omit<SettingDescriptor<T>, "scope"> & {
45
45
  scope?: Partial<SettingScope>;
46
46
  };
47
47
 
@@ -236,7 +236,7 @@ const PROVIDER_REASONING_CAPTURE_SCHEMA: JSONSchema = {
236
236
  };
237
237
 
238
238
  export const PROVIDER_CONFIG_NAMESPACE = "provider-config";
239
- export const PROVIDER_CONFIG_SCHEMA: JSONSchema = {
239
+ const PROVIDER_CONFIG_SCHEMA: JSONSchema = {
240
240
  type: "object",
241
241
  additionalProperties: false,
242
242
  required: [
@@ -280,7 +280,7 @@ let seeded = false;
280
280
  * called lazily by the read accessors). #386 adds module-contributed descriptors
281
281
  * on top via `registerSetting`.
282
282
  */
283
- export function seedBuiltInSettings(): void {
283
+ function seedBuiltInSettings(): void {
284
284
  if (seeded) return;
285
285
  seeded = true;
286
286
 
@@ -7,7 +7,7 @@ import { ValidationError } from "./db";
7
7
  import { effectiveProviderCatalogList } from "./provider-catalog-store";
8
8
 
9
9
  /** Resolved provider/model/effort triple — the output shape of every model-resolution wrapper. */
10
- export interface SpawnModelParams {
10
+ interface SpawnModelParams {
11
11
  model?: string;
12
12
  providerModel?: string;
13
13
  effort?: string;
package/src/sse.ts CHANGED
@@ -198,10 +198,6 @@ export function emitOrchestratorStatus(orchestratorId: string) {
198
198
  emitRelayEvent({ type: "orchestrator.status", source: "server", subject: orchestratorId, data: data as unknown as Record<string, unknown> });
199
199
  }
200
200
 
201
- export function emitOrchestratorRemoved(orchestratorId: string) {
202
- emitRelayEvent({ type: "orchestrator.removed", source: "server", subject: orchestratorId, data: { id: orchestratorId } });
203
- }
204
-
205
201
  export function emitPoolBindingChanged(bindingId: string, channelId: string, previousAgentId: string | null, newAgentId: string | null) {
206
202
  emitRelayEvent({ type: "channel.pool.changed", source: "server", subject: bindingId, data: { bindingId, channelId, previousAgentId, newAgentId, at: Date.now() } });
207
203
  }
@@ -310,7 +310,7 @@ export function buildWorkspaceCleanupCommand(
310
310
 
311
311
  // Build a `workspace.deps-refresh` command for a worktree's owning orchestrator
312
312
  // (issue #51). checkOnly just reports staleness. Same owner-resolution as cleanup.
313
- export function buildWorkspaceDepsRefreshCommand(
313
+ function buildWorkspaceDepsRefreshCommand(
314
314
  workspace: WorkspaceRecord,
315
315
  requestedBy: string,
316
316
  checkOnly: boolean,
@@ -9,7 +9,6 @@
9
9
  // Both funnel the "apply the host's ahead/dirty counts to the row + emit on flip"
10
10
  // rule through `applyBranchFreshness` so it can't drift between the two surfaces.
11
11
 
12
- import { isAbsolute, relative, resolve } from "node:path";
13
12
  import { RELAY_TOKEN_HEADER } from "agent-relay-sdk";
14
13
  import {
15
14
  emitWorkspaceChange,
@@ -17,16 +16,13 @@ import {
17
16
  ownedIsolatedWorkspace,
18
17
  patchWorkspaceMetadata,
19
18
  } from "./db";
19
+ import { isPathWithinBase } from "./utils";
20
20
  import { deriveBranchState } from "./workspace-phase";
21
21
  import type { AgentCard, WorkspaceMergePreview, WorkspaceRecord } from "./types";
22
22
 
23
23
  /** True when `path` is the base dir itself or nested inside it (containment via
24
24
  * resolve+relative, never string startsWith — see CLAUDE.md path-containment rule). */
25
- export function workspacePathWithinBase(path: string | undefined, baseDir: string | undefined): boolean {
26
- if (!path || !baseDir) return false;
27
- const rel = relative(resolve(baseDir), resolve(path));
28
- return rel === "" || (!!rel && !rel.startsWith("..") && !isAbsolute(rel));
29
- }
25
+ export const workspacePathWithinBase = isPathWithinBase;
30
26
 
31
27
  /** Ask the owning host whether a worktree can still merge cleanly (+ ahead/dirty/PR
32
28
  * state). Returns null on any transport/host failure — callers skip rather than act
@@ -75,7 +71,7 @@ export function applyBranchFreshness(
75
71
  return false;
76
72
  }
77
73
 
78
- export interface ProbeResult {
74
+ interface ProbeResult {
79
75
  /** True when the host preview came back and freshness was applied. */
80
76
  probed: boolean;
81
77
  /** True when the derived branch-state badge flipped (⚪↔🟡). */