agent-relay-runner 0.127.5 → 0.127.7

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.
@@ -1,5 +1,4 @@
1
1
  import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { readFile } from "node:fs/promises";
3
2
  import { homedir } from "node:os";
4
3
  import { dirname, join, resolve } from "node:path";
5
4
  import { type Message } from "agent-relay-sdk";
@@ -9,18 +8,22 @@ import { tmuxCommand, tmuxHasSession } from "agent-relay-sdk/tmux-utils";
9
8
  import { profileAllowsRelayFeature, type ManagedProcess, type ProviderAdapter, type ProviderConfig, type ProviderStatusUpdate, type RunnerSpawnConfig, type SemanticStatus, type SpawnArgs } from "../adapter";
10
9
  import { computeLivenessSignal, type LivenessInputs } from "../liveness";
11
10
  import type { LivenessSignal } from "agent-relay-sdk";
12
- import { collectClaudeSessionEvents } from "./claude-transcript";
13
- import type { SessionEvent } from "../session-insights";
14
11
  import { prepareClaudeProfileHome, profileUsesClaudeHostProviderGlobals } from "../profile-home";
15
12
  import { assembleLaunch, materializeLaunchAssembly, sessionStatusLineSettingsArgs, stripSettingsArgs } from "../launch-assembly";
16
13
  import { claudeProviderMessageText } from "./claude-delivery";
17
14
  import { claudeProbeActivity, readManagedClaudeStatus, resolveClaudePid, type ClaudeProbeActivity } from "./claude-session-probe";
18
- import { evaluateClaudePromptGatePane, initialClaudePromptGatePaneState, type ClaudePromptGatePaneState } from "../claude-prompt-gates";
15
+ import { evaluateClaudePromptGatePane, initialClaudePromptGatePaneState, type ClaudePromptGatePaneState } from "./claude-prompt-gates";
19
16
  import { claudePaneLooksReady, claudePaneIsBusy, claudeRateLimitStatus, claudeConnectionRetryStatus, claudeModelUnavailableStatus } from "./claude-status-detectors";
20
17
  import { launcherScriptPathForSession } from "../session-scratch";
18
+ import { ClaudeSessionCapture, collectClaudeTranscriptArchiveSegment, collectClaudeTranscriptSessionEvents } from "./claude-session-capture";
19
+ import { claudePermissionPromptHandler } from "./claude-permission";
21
20
 
22
21
  export class ClaudeAdapter implements ProviderAdapter {
23
22
  readonly provider = "claude";
23
+ readonly statusSourceId = "claude";
24
+ private readonly paneSourceId = `${this.statusSourceId}-pane`;
25
+ readonly stopObligationPath = "claude-stop";
26
+ readonly permissionPromptHandler = claudePermissionPromptHandler;
24
27
  readonly compactSupportsInstructions = true;
25
28
  // #352: initial prompt is seeded as Claude's positional launch arg (buildSpawnArgs) — reliable,
26
29
  // no send-keys/onboarding race; tells the runner to skip the redundant post-launch delivery.
@@ -31,6 +34,16 @@ export class ClaudeAdapter implements ProviderAdapter {
31
34
  private modelUnavailableReported = false;
32
35
  private connectionRetryActive = false;
33
36
  private promptGatePaneState: ClaudePromptGatePaneState = initialClaudePromptGatePaneState();
37
+ private readonly sessionCapture = new ClaudeSessionCapture();
38
+ readonly onSessionEvent = this.sessionCapture.onSessionEvent.bind(this.sessionCapture);
39
+ readonly onSessionEvents = this.sessionCapture.onSessionEvents.bind(this.sessionCapture);
40
+ readonly captureSessionTurn = this.sessionCapture.captureSessionTurn.bind(this.sessionCapture);
41
+ readonly handleUserPrompt = this.sessionCapture.handleUserPrompt.bind(this.sessionCapture);
42
+ readonly drainSessionTrace = this.sessionCapture.drainReasoningTail.bind(this.sessionCapture);
43
+ readonly settleSessionTraceForToolUse = this.sessionCapture.settlePollForToolUse.bind(this.sessionCapture);
44
+ readonly stopSessionTrace = this.sessionCapture.stopSessionTrace.bind(this.sessionCapture);
45
+ readonly collectSessionEvents = collectClaudeTranscriptSessionEvents;
46
+ readonly collectSessionArchiveSegment = collectClaudeTranscriptArchiveSegment;
34
47
 
35
48
  onStatusChange(cb: (status: ProviderStatusUpdate) => void): void {
36
49
  this.statusCb = cb;
@@ -91,28 +104,6 @@ export class ClaudeAdapter implements ProviderAdapter {
91
104
  return { method: "tmux-inject", command: "/clear" };
92
105
  }
93
106
 
94
- // #183/#184: parse the full Claude transcript into the shared SessionEvent stream. The
95
- // runner slices per-segment, so we return the whole transcript's events each call.
96
- async collectSessionEvents(_process: ManagedProcess, ctx: { transcriptPath?: string }): Promise<SessionEvent[] | null> {
97
- if (!ctx.transcriptPath) return null;
98
- let jsonl: string;
99
- try {
100
- jsonl = await readFile(ctx.transcriptPath, "utf8");
101
- } catch {
102
- return null;
103
- }
104
- return collectClaudeSessionEvents(jsonl);
105
- }
106
-
107
- async collectSessionArchiveSegment(_process: ManagedProcess, ctx: { transcriptPath?: string }): Promise<string | null> {
108
- if (!ctx.transcriptPath) return null;
109
- try {
110
- return await readFile(ctx.transcriptPath, "utf8");
111
- } catch {
112
- return null;
113
- }
114
- }
115
-
116
107
  async interrupt(process: ManagedProcess): Promise<Record<string, unknown>> {
117
108
  const session = process.meta?.tmuxSession as string | undefined;
118
109
  const socket = process.meta?.tmuxSocket as string | undefined;
@@ -434,6 +425,7 @@ export class ClaudeAdapter implements ProviderAdapter {
434
425
  const promptGate = evaluateClaudePromptGatePane(pane, this.promptGatePaneState, {
435
426
  sessionName,
436
427
  busy: claudePaneIsBusy(pane),
428
+ sourceId: this.paneSourceId,
437
429
  });
438
430
  this.promptGatePaneState = promptGate.state;
439
431
  if (promptGate.action) {
@@ -9,7 +9,7 @@
9
9
  // executes CODEX_HOME/hooks.json for these event names (Stop/PreToolUse/…), not just that the
10
10
  // version string clears the gate. The version probe is necessary but not sufficient.
11
11
 
12
- import { codexVersionOverrideFromEnv } from "./config";
12
+ import { codexVersionOverrideFromEnv } from "../config";
13
13
 
14
14
  // Codex releases from this version on ship stable hooks with Claude-compatible events.
15
15
  const CODEX_HOOKS_MIN_VERSION = [0, 124, 0] as const;
@@ -8,20 +8,20 @@ const PASSIVE_QUOTA_SAMPLE_STALE_MS = 10 * 60_000;
8
8
  const PASSIVE_QUOTA_LEASE_MAX_TTL_MS = 10 * 60_000;
9
9
  const PASSIVE_QUOTA_LEASE_PADDING_MS = 60_000;
10
10
 
11
- interface ClaudeQuotaHarvestOptions {
11
+ interface ProviderQuotaHarvestOptions {
12
12
  agentId: string;
13
13
  provider: string;
14
14
  http: () => Pick<RelayHttpClient, "acquireProviderQuotaPublisherLease" | "getProviderQuotaConfig" | "upsertProviderQuota">;
15
15
  }
16
16
 
17
- export class ClaudeQuotaHarvest {
17
+ export class ProviderQuotaHarvest {
18
18
  private config = { ...DEFAULT_PROVIDER_QUOTA_CONFIG };
19
19
  private configRefreshAt = 0;
20
20
  private lastReportAt?: number;
21
21
  private lease?: { accountKey: string; leaseToken: string; expiresAt: number };
22
22
  private nextLeaseAttemptAt?: number;
23
23
 
24
- constructor(private readonly options: ClaudeQuotaHarvestOptions) {}
24
+ constructor(private readonly options: ProviderQuotaHarvestOptions) {}
25
25
 
26
26
  async publish(): Promise<void> {
27
27
  if (this.options.provider !== "claude") return;