@bridge4dev/runner 0.65.1 → 0.66.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.
@@ -1,6 +1,7 @@
1
1
  import { query } from '@anthropic-ai/claude-agent-sdk';
2
2
  import { assertClaudeInstalled, claudeExecutableOption } from './agent-binary.js';
3
3
  import { scrubbedEnv } from './adapters/claude.js';
4
+ import { activeAccountHome, withAccountHome } from './claude-homes.js';
4
5
  import { gitBranchDiff } from './gitops.js';
5
6
  import { isSecretPath, maskString } from './policy.js';
6
7
  /**
@@ -160,7 +161,9 @@ export async function proposeCommitMessage(input, queryFn = query) {
160
161
  prompt: buildPrompt(input, diff),
161
162
  options: {
162
163
  cwd: input.worktreePath,
163
- env: scrubbedEnv(),
164
+ // The machine's active account (#422), with the same rule as a session:
165
+ // its home, and no operator token above it.
166
+ env: withAccountHome(scrubbedEnv(), activeAccountHome()),
164
167
  // The second place Claude `Options` are built. It must follow the same
165
168
  // constant, or after C3 commit messages would still be written by the
166
169
  // bundled binary while sessions had moved to the system one.
package/dist/config.d.ts CHANGED
@@ -15,12 +15,12 @@ declare const ConfigSchema: z.ZodObject<{
15
15
  name: z.ZodString;
16
16
  token: z.ZodString;
17
17
  }, "strip", z.ZodTypeAny, {
18
- name: string;
19
18
  id: string;
19
+ name: string;
20
20
  token: string;
21
21
  }, {
22
- name: string;
23
22
  id: string;
23
+ name: string;
24
24
  token: string;
25
25
  }>;
26
26
  mcp: z.ZodOptional<z.ZodObject<{
@@ -179,10 +179,13 @@ declare const ConfigSchema: z.ZodObject<{
179
179
  ws_url: string;
180
180
  };
181
181
  server: {
182
- name: string;
183
182
  id: string;
183
+ name: string;
184
184
  token: string;
185
185
  };
186
+ codex?: {
187
+ auth: "link" | "own";
188
+ } | undefined;
186
189
  checkpoints?: {
187
190
  enabled: boolean;
188
191
  } | undefined;
@@ -190,8 +193,8 @@ declare const ConfigSchema: z.ZodObject<{
190
193
  url: string;
191
194
  token: string;
192
195
  } | undefined;
193
- codex?: {
194
- auth: "link" | "own";
196
+ agents?: {
197
+ install_enabled: boolean;
195
198
  } | undefined;
196
199
  limits?: {
197
200
  max_sessions?: number | undefined;
@@ -204,19 +207,19 @@ declare const ConfigSchema: z.ZodObject<{
204
207
  verify?: {
205
208
  enabled: boolean;
206
209
  } | undefined;
207
- agents?: {
208
- install_enabled: boolean;
209
- } | undefined;
210
210
  }, {
211
211
  api: {
212
212
  url: string;
213
213
  ws_url: string;
214
214
  };
215
215
  server: {
216
- name: string;
217
216
  id: string;
217
+ name: string;
218
218
  token: string;
219
219
  };
220
+ codex?: {
221
+ auth?: "link" | "own" | undefined;
222
+ } | undefined;
220
223
  checkpoints?: {
221
224
  enabled?: boolean | undefined;
222
225
  } | undefined;
@@ -224,8 +227,8 @@ declare const ConfigSchema: z.ZodObject<{
224
227
  url: string;
225
228
  token: string;
226
229
  } | undefined;
227
- codex?: {
228
- auth?: "link" | "own" | undefined;
230
+ agents?: {
231
+ install_enabled?: boolean | undefined;
229
232
  } | undefined;
230
233
  limits?: {
231
234
  max_sessions?: number | undefined;
@@ -238,9 +241,6 @@ declare const ConfigSchema: z.ZodObject<{
238
241
  verify?: {
239
242
  enabled?: boolean | undefined;
240
243
  } | undefined;
241
- agents?: {
242
- install_enabled?: boolean | undefined;
243
- } | undefined;
244
244
  }>;
245
245
  export type RunnerConfig = z.infer<typeof ConfigSchema>;
246
246
  export declare function loadConfig(): RunnerConfig | null;
package/dist/index.js CHANGED
@@ -15,6 +15,9 @@ import { loadConfig, mergeIntoPairedConfig, requireConfig, saveConfig, } from '.
15
15
  import { log } from './log.js';
16
16
  import { installIsWritable, installPrefixFor, isSupervisedProcess, restartCapability, manualUpdateCommand, resolveInstalledPackageDir, } from './self-update.js';
17
17
  import { applyStoredClaudeToken } from './agent-auth.js';
18
+ import { discardAbandonedStagingHomes, recoverInterruptedSwaps, refreshAccountIdentity, } from './claude-homes.js';
19
+ import { ACCOUNT_AGENTS, ACCOUNT_COMMANDS } from './account-commands.js';
20
+ import { MACHINE_ACCOUNT_ID } from './login-marks.js';
18
21
  import { Supervisor } from './supervisor.js';
19
22
  import { readStatusFile, isPidAlive, writeStatusFile, STATUS_FRESH_MS } from './status-file.js';
20
23
  import { RunnerWsClient } from './ws-client.js';
@@ -515,6 +518,13 @@ function runnerCapabilities(apiUrlOverride) {
515
518
  * `kind: 'oom'` is inferred from the cgroup counter — see `crash-note.ts`.
516
519
  */
517
520
  ...(LAST_EXIT ? { lastExit: LAST_EXIT } : {}),
521
+ /**
522
+ * #422 (R11): the agents this runner keeps several logins for. Static per
523
+ * version – the LIST of accounts is always asked with `agent_accounts`,
524
+ * never read from here (a snapshot taken at start, #395). The dashboard
525
+ * shows the account window only to an agent named here.
526
+ */
527
+ accounts: [...ACCOUNT_AGENTS],
518
528
  /** Commands beyond the stage-A/B set. */
519
529
  commands: [
520
530
  'purge_session',
@@ -578,6 +588,10 @@ function runnerCapabilities(apiUrlOverride) {
578
588
  // ANSWERS the command, with a sentence saying why — which is a better
579
589
  // outcome than a frame nobody replies to.
580
590
  'runner_restart',
591
+ // #422: list, sign in to, switch and forget agent logins (plan §8).
592
+ // Unconditional: they read and write only the runner's own state, and an
593
+ // agent they do not serve yet is answered with a sentence.
594
+ ...ACCOUNT_COMMANDS,
581
595
  ],
582
596
  };
583
597
  }
@@ -955,6 +969,31 @@ async function cmdDaemon() {
955
969
  if (applyStoredClaudeToken()) {
956
970
  log.info('daemon: using the Claude token stored on this server');
957
971
  }
972
+ /**
973
+ * #422: a swap of Claude homes the previous daemon died inside is finished or
974
+ * undone before anything can run under an account; and who the machine login
975
+ * is gets asked once, in the background (R14 c) – the verdict and the list read
976
+ * the answer, the minute poll never asks.
977
+ */
978
+ try {
979
+ recoverInterruptedSwaps();
980
+ }
981
+ catch (error) {
982
+ log.warn('daemon: could not finish an interrupted swap of Claude homes', {
983
+ error: String(error),
984
+ });
985
+ }
986
+ try {
987
+ // A sign-in the previous daemon accepted but never adopted (S2): nothing can
988
+ // be adopting before the supervisor exists.
989
+ discardAbandonedStagingHomes();
990
+ }
991
+ catch (error) {
992
+ log.warn('daemon: could not remove sign-in homes a previous daemon left', {
993
+ error: String(error),
994
+ });
995
+ }
996
+ void refreshAccountIdentity(MACHINE_ACCOUNT_ID).catch(() => undefined);
958
997
  const agents = installedAgents();
959
998
  const ws = new RunnerWsClient(config.api.ws_url, config.server.token, runnerCapabilities());
960
999
  const codex = agents.includes('codex') ? bootstrapCodex(config) : null;
@@ -1379,6 +1418,15 @@ async function runnerChecks() {
1379
1418
  });
1380
1419
  return checks;
1381
1420
  }
1421
+ /** « · account <email> (saved)» – nothing for the machine login nobody named. */
1422
+ function accountLine(account) {
1423
+ if (!account)
1424
+ return '';
1425
+ if (account.id === MACHINE_ACCOUNT_ID) {
1426
+ return account.email ? ` · machine login ${account.email}` : '';
1427
+ }
1428
+ return ` · saved account ${account.email ?? account.id}`;
1429
+ }
1382
1430
  async function agentChecks() {
1383
1431
  const me = runnerIdentity();
1384
1432
  // The probes log a verdict line each, which belongs in the journal, not in
@@ -1440,8 +1488,12 @@ async function agentChecks() {
1440
1488
  checks.push({
1441
1489
  ok: signedIn,
1442
1490
  name: `${agent} login`,
1491
+ // Which account the verdict is about (#422): the same rule as the panel,
1492
+ // read from the same file, so doctor and the dashboard cannot answer about
1493
+ // two different logins on one machine.
1443
1494
  detail: (info.detail ?? info.status) +
1444
- (info.expiresAt ? ` · until ${formatLocalDay(info.expiresAt)}` : ''),
1495
+ (info.expiresAt ? ` · until ${formatLocalDay(info.expiresAt)}` : '') +
1496
+ accountLine(info.activeAccount),
1445
1497
  ...(signedIn
1446
1498
  ? {}
1447
1499
  : {
@@ -0,0 +1,31 @@
1
+ import type { RelayAgentName } from './agent-registry.js';
2
+ /**
3
+ * What the agent actually experienced with a sign-in — per agent AND per account.
4
+ *
5
+ * The credentials file cannot tell us the provider revoked a login: the refresh
6
+ * token still sits there, dated. The one authority on that is a real refusal
7
+ * from a real run — so a session that failed to authenticate demotes the file's
8
+ * verdict for a while, and any successful turn clears it again.
9
+ *
10
+ * Moved out of `auth-relay.ts` for #422 and keyed by account as well as agent.
11
+ * With several Claude logins on one machine «Claude was refused» stopped being
12
+ * a statement about anything: the session that was refused ran under ONE
13
+ * account, and the machine may have been switched to another since. The mark
14
+ * belongs to the account the session started under (R14) – which is why both
15
+ * the account list (`claude-homes.ts`) and the panel verdict (`auth-relay.ts`)
16
+ * read it from here rather than each keeping a copy.
17
+ *
18
+ * Process memory on purpose: no protocol, no disk. The consequence is worth
19
+ * naming — restarting the daemon forgets the refusal and the panel goes back
20
+ * to trusting the file until the next session tries. (A saved account also
21
+ * carries a mark on disk, D2 – see `markLoginExpired` in `claude-homes.ts`.)
22
+ */
23
+ /** The machine's own login – the one row every agent has. */
24
+ export declare const MACHINE_ACCOUNT_ID = "machine";
25
+ /** A session under this agent and account was just refused. */
26
+ export declare function noteRefusal(agent: RelayAgentName, accountId?: string): void;
27
+ /** The sign-in worked again. Answers whether a refusal was being held. */
28
+ export declare function clearRefusal(agent: RelayAgentName, accountId?: string): boolean;
29
+ /** Is a refusal still being held against this agent and account? */
30
+ export declare function refusalActive(agent: RelayAgentName, accountId?: string): boolean;
31
+ //# sourceMappingURL=login-marks.d.ts.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * What the agent actually experienced with a sign-in — per agent AND per account.
3
+ *
4
+ * The credentials file cannot tell us the provider revoked a login: the refresh
5
+ * token still sits there, dated. The one authority on that is a real refusal
6
+ * from a real run — so a session that failed to authenticate demotes the file's
7
+ * verdict for a while, and any successful turn clears it again.
8
+ *
9
+ * Moved out of `auth-relay.ts` for #422 and keyed by account as well as agent.
10
+ * With several Claude logins on one machine «Claude was refused» stopped being
11
+ * a statement about anything: the session that was refused ran under ONE
12
+ * account, and the machine may have been switched to another since. The mark
13
+ * belongs to the account the session started under (R14) – which is why both
14
+ * the account list (`claude-homes.ts`) and the panel verdict (`auth-relay.ts`)
15
+ * read it from here rather than each keeping a copy.
16
+ *
17
+ * Process memory on purpose: no protocol, no disk. The consequence is worth
18
+ * naming — restarting the daemon forgets the refusal and the panel goes back
19
+ * to trusting the file until the next session tries. (A saved account also
20
+ * carries a mark on disk, D2 – see `markLoginExpired` in `claude-homes.ts`.)
21
+ */
22
+ /** The machine's own login – the one row every agent has. */
23
+ export const MACHINE_ACCOUNT_ID = 'machine';
24
+ const AUTH_FAILURE_TTL_MS = 15 * 60_000;
25
+ const refusals = new Map();
26
+ const keyOf = (agent, accountId) => `${agent}:${accountId}`;
27
+ /** A session under this agent and account was just refused. */
28
+ export function noteRefusal(agent, accountId = MACHINE_ACCOUNT_ID) {
29
+ refusals.set(keyOf(agent, accountId), Date.now());
30
+ }
31
+ /** The sign-in worked again. Answers whether a refusal was being held. */
32
+ export function clearRefusal(agent, accountId = MACHINE_ACCOUNT_ID) {
33
+ return refusals.delete(keyOf(agent, accountId));
34
+ }
35
+ /** Is a refusal still being held against this agent and account? */
36
+ export function refusalActive(agent, accountId = MACHINE_ACCOUNT_ID) {
37
+ const key = keyOf(agent, accountId);
38
+ const at = refusals.get(key);
39
+ if (at === undefined)
40
+ return false;
41
+ if (Date.now() - at > AUTH_FAILURE_TTL_MS) {
42
+ refusals.delete(key);
43
+ return false;
44
+ }
45
+ return true;
46
+ }
47
+ //# sourceMappingURL=login-marks.js.map
@@ -235,11 +235,11 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
235
235
  token: string;
236
236
  }>>;
237
237
  }, "strip", z.ZodTypeAny, {
238
- mode: "ask" | "plan" | "auto" | "full";
239
- agent: "CLAUDE" | "CODEX";
240
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
238
+ mode: "plan" | "ask" | "auto" | "full";
241
239
  id: string;
240
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
242
241
  kind: "TICKET" | "CHAT";
242
+ agent: "CLAUDE" | "CODEX";
243
243
  model: string | null;
244
244
  effort: string | null;
245
245
  prompt: string;
@@ -286,10 +286,10 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
286
286
  baseSha?: string | undefined;
287
287
  } | undefined;
288
288
  }, {
289
- agent: "CLAUDE" | "CODEX";
290
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
291
289
  id: string;
290
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
292
291
  kind: "TICKET" | "CHAT";
292
+ agent: "CLAUDE" | "CODEX";
293
293
  prompt: string;
294
294
  providerSessionId: string | null;
295
295
  workspace: {
@@ -316,7 +316,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
316
316
  url: string;
317
317
  token: string;
318
318
  } | undefined;
319
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
319
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
320
320
  workMode?: unknown;
321
321
  model?: string | null | undefined;
322
322
  effort?: string | null | undefined;
@@ -385,8 +385,8 @@ export declare const QuestionAnswerArgsSchema: z.ZodObject<{
385
385
  }>, "many">>;
386
386
  readonly text: z.ZodOptional<z.ZodString>;
387
387
  }, "strip", z.ZodTypeAny, {
388
- askId: string;
389
388
  action: "answer" | "discuss";
389
+ askId: string;
390
390
  text?: string | undefined;
391
391
  answers?: {
392
392
  values: string[];
@@ -395,8 +395,8 @@ export declare const QuestionAnswerArgsSchema: z.ZodObject<{
395
395
  notes?: string | undefined;
396
396
  }[] | undefined;
397
397
  }, {
398
- askId: string;
399
398
  action: "answer" | "discuss";
399
+ askId: string;
400
400
  text?: string | undefined;
401
401
  answers?: {
402
402
  values: string[];
@@ -685,11 +685,11 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
685
685
  token: string;
686
686
  }>>;
687
687
  }, "strip", z.ZodTypeAny, {
688
- mode: "ask" | "plan" | "auto" | "full";
689
- agent: "CLAUDE" | "CODEX";
690
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
688
+ mode: "plan" | "ask" | "auto" | "full";
691
689
  id: string;
690
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
692
691
  kind: "TICKET" | "CHAT";
692
+ agent: "CLAUDE" | "CODEX";
693
693
  model: string | null;
694
694
  effort: string | null;
695
695
  prompt: string;
@@ -736,10 +736,10 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
736
736
  baseSha?: string | undefined;
737
737
  } | undefined;
738
738
  }, {
739
- agent: "CLAUDE" | "CODEX";
740
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
741
739
  id: string;
740
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
742
741
  kind: "TICKET" | "CHAT";
742
+ agent: "CLAUDE" | "CODEX";
743
743
  prompt: string;
744
744
  providerSessionId: string | null;
745
745
  workspace: {
@@ -766,7 +766,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
766
766
  url: string;
767
767
  token: string;
768
768
  } | undefined;
769
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
769
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
770
770
  workMode?: unknown;
771
771
  model?: string | null | undefined;
772
772
  effort?: string | null | undefined;
@@ -785,11 +785,11 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
785
785
  }, "strip", z.ZodTypeAny, {
786
786
  type: "hello_ack";
787
787
  sessions: {
788
- mode: "ask" | "plan" | "auto" | "full";
789
- agent: "CLAUDE" | "CODEX";
790
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
788
+ mode: "plan" | "ask" | "auto" | "full";
791
789
  id: string;
790
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
792
791
  kind: "TICKET" | "CHAT";
792
+ agent: "CLAUDE" | "CODEX";
793
793
  model: string | null;
794
794
  effort: string | null;
795
795
  prompt: string;
@@ -842,10 +842,10 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
842
842
  }, {
843
843
  type: "hello_ack";
844
844
  sessions: {
845
- agent: "CLAUDE" | "CODEX";
846
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
847
845
  id: string;
846
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
848
847
  kind: "TICKET" | "CHAT";
848
+ agent: "CLAUDE" | "CODEX";
849
849
  prompt: string;
850
850
  providerSessionId: string | null;
851
851
  workspace: {
@@ -872,7 +872,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
872
872
  url: string;
873
873
  token: string;
874
874
  } | undefined;
875
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
875
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
876
876
  workMode?: unknown;
877
877
  model?: string | null | undefined;
878
878
  effort?: string | null | undefined;
@@ -1154,11 +1154,11 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1154
1154
  token: string;
1155
1155
  }>>;
1156
1156
  }, "strip", z.ZodTypeAny, {
1157
- mode: "ask" | "plan" | "auto" | "full";
1158
- agent: "CLAUDE" | "CODEX";
1159
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1157
+ mode: "plan" | "ask" | "auto" | "full";
1160
1158
  id: string;
1159
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1161
1160
  kind: "TICKET" | "CHAT";
1161
+ agent: "CLAUDE" | "CODEX";
1162
1162
  model: string | null;
1163
1163
  effort: string | null;
1164
1164
  prompt: string;
@@ -1205,10 +1205,10 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1205
1205
  baseSha?: string | undefined;
1206
1206
  } | undefined;
1207
1207
  }, {
1208
- agent: "CLAUDE" | "CODEX";
1209
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1210
1208
  id: string;
1209
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1211
1210
  kind: "TICKET" | "CHAT";
1211
+ agent: "CLAUDE" | "CODEX";
1212
1212
  prompt: string;
1213
1213
  providerSessionId: string | null;
1214
1214
  workspace: {
@@ -1235,7 +1235,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1235
1235
  url: string;
1236
1236
  token: string;
1237
1237
  } | undefined;
1238
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
1238
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
1239
1239
  workMode?: unknown;
1240
1240
  model?: string | null | undefined;
1241
1241
  effort?: string | null | undefined;
@@ -1253,11 +1253,11 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1253
1253
  }>;
1254
1254
  }, "strip", z.ZodTypeAny, {
1255
1255
  session: {
1256
- mode: "ask" | "plan" | "auto" | "full";
1257
- agent: "CLAUDE" | "CODEX";
1258
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1256
+ mode: "plan" | "ask" | "auto" | "full";
1259
1257
  id: string;
1258
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1260
1259
  kind: "TICKET" | "CHAT";
1260
+ agent: "CLAUDE" | "CODEX";
1261
1261
  model: string | null;
1262
1262
  effort: string | null;
1263
1263
  prompt: string;
@@ -1307,10 +1307,10 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1307
1307
  type: "session_start";
1308
1308
  }, {
1309
1309
  session: {
1310
- agent: "CLAUDE" | "CODEX";
1311
- status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1312
1310
  id: string;
1311
+ status: "RUNNING" | "FAILED" | "STARTING" | "WAITING_INPUT" | "WAITING_PERMISSION" | "REVIEW" | "DONE" | "STOPPED";
1313
1312
  kind: "TICKET" | "CHAT";
1313
+ agent: "CLAUDE" | "CODEX";
1314
1314
  prompt: string;
1315
1315
  providerSessionId: string | null;
1316
1316
  workspace: {
@@ -1337,7 +1337,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1337
1337
  url: string;
1338
1338
  token: string;
1339
1339
  } | undefined;
1340
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
1340
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
1341
1341
  workMode?: unknown;
1342
1342
  model?: string | null | undefined;
1343
1343
  effort?: string | null | undefined;
@@ -1440,8 +1440,8 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1440
1440
  }, "strip", z.ZodTypeAny, {
1441
1441
  sessionId: string;
1442
1442
  type: "question_answer";
1443
- askId: string;
1444
1443
  action: "answer" | "discuss";
1444
+ askId: string;
1445
1445
  text?: string | undefined;
1446
1446
  answers?: {
1447
1447
  values: string[];
@@ -1452,8 +1452,8 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1452
1452
  }, {
1453
1453
  sessionId: string;
1454
1454
  type: "question_answer";
1455
- askId: string;
1456
1455
  action: "answer" | "discuss";
1456
+ askId: string;
1457
1457
  text?: string | undefined;
1458
1458
  answers?: {
1459
1459
  values: string[];
@@ -1513,8 +1513,8 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1513
1513
  }, "strip", z.ZodTypeAny, {
1514
1514
  type: "workspace_settings";
1515
1515
  workspaceId: string;
1516
- agentAutoCommit?: boolean | undefined;
1517
1516
  trustMode?: "STRICT" | "NORMAL" | "AUTO" | undefined;
1517
+ agentAutoCommit?: boolean | undefined;
1518
1518
  agentPushBan?: boolean | undefined;
1519
1519
  agentProtectedBranches?: string[] | undefined;
1520
1520
  agentAllowForcePush?: boolean | undefined;
@@ -1523,8 +1523,8 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1523
1523
  }, {
1524
1524
  type: "workspace_settings";
1525
1525
  workspaceId: string;
1526
- agentAutoCommit?: boolean | undefined;
1527
1526
  trustMode?: "STRICT" | "NORMAL" | "AUTO" | undefined;
1527
+ agentAutoCommit?: boolean | undefined;
1528
1528
  agentPushBan?: boolean | undefined;
1529
1529
  agentProtectedBranches?: string[] | undefined;
1530
1530
  agentAllowForcePush?: boolean | undefined;
@@ -1539,13 +1539,13 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
1539
1539
  }, "strip", z.ZodTypeAny, {
1540
1540
  sessionId: string;
1541
1541
  type: "session_settings";
1542
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
1542
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
1543
1543
  model?: string | undefined;
1544
1544
  effort?: string | null | undefined;
1545
1545
  }, {
1546
1546
  sessionId: string;
1547
1547
  type: "session_settings";
1548
- mode?: "ask" | "plan" | "auto" | "full" | undefined;
1548
+ mode?: "plan" | "ask" | "auto" | "full" | undefined;
1549
1549
  model?: string | undefined;
1550
1550
  effort?: string | null | undefined;
1551
1551
  }>, z.ZodObject<{
package/dist/protocol.js CHANGED
@@ -430,7 +430,9 @@ export const GatewayFrameSchema = z.discriminatedUnion('type', [
430
430
  // git_branches, update_from_base, git_push, git_refs, workspace_state,
431
431
  // recipe_state, verify_start, verify_status, verify_cancel,
432
432
  // preview_checkout, preview_stop, propose_commit_message, git_stage,
433
- // git_unstage, git_discard, git_pull, git_merge_abort, fs_publish.
433
+ // git_unstage, git_discard, git_pull, git_merge_abort, fs_publish,
434
+ // agent_accounts, agent_account_login_start, agent_account_login_code,
435
+ // agent_account_activate, agent_account_forget (#422).
434
436
  name: z.string().min(1).max(64),
435
437
  workspaceId: z.string().optional(),
436
438
  sessionId: z.string().optional(),
@@ -19,6 +19,7 @@ import { applySession, gitBranches, gitCommit, gitDiff, gitLog, gitPush, gitRefs
19
19
  import { fsView } from './fsview.js';
20
20
  import { publishFile } from './file-publish.js';
21
21
  import { agentAuthStatuses, AuthRelay, clearAgentAuthFailure, noteAgentAuthFailure, } from './auth-relay.js';
22
+ import { isAccountCommand, runAccountCommand } from './account-commands.js';
22
23
  import { isSupervisedProcess, selfUpdate } from './self-update.js';
23
24
  import { installAgent } from './agent-install.js';
24
25
  import { autoUpdateRefusal, claimAgentAutoUpdate } from './agent-auto-update.js';
@@ -2702,7 +2703,7 @@ export class Supervisor {
2702
2703
  const { descriptor } = running;
2703
2704
  try {
2704
2705
  for await (const event of session.events) {
2705
- this.forwardEvent(running, event);
2706
+ this.forwardEvent(running, event, session);
2706
2707
  }
2707
2708
  }
2708
2709
  catch (error) {
@@ -3618,7 +3619,14 @@ export class Supervisor {
3618
3619
  this.syncBudgetClock(running);
3619
3620
  this.reportStatus(running.descriptor.id, 'RUNNING', {});
3620
3621
  }
3621
- forwardEvent(running, event) {
3622
+ forwardEvent(running, event,
3623
+ /**
3624
+ * The process this event came from (#422). A refusal and a working turn are
3625
+ * attributed to the account THAT process started under – read off the
3626
+ * session that produced the event, not off whatever holds the slot by the
3627
+ * time the event is handled.
3628
+ */
3629
+ source = running.session) {
3622
3630
  const { descriptor } = running;
3623
3631
  // Ticket #225: ANY event is the process proving it came up — its own
3624
3632
  // capabilities probe answers within about two seconds of a healthy launch,
@@ -3812,7 +3820,7 @@ export class Supervisor {
3812
3820
  if (event.code === 'auth_expired') {
3813
3821
  const refused = relayAgent(String(descriptor.agent).toLowerCase());
3814
3822
  if (refused)
3815
- noteAgentAuthFailure(refused);
3823
+ noteAgentAuthFailure(refused, source?.accountId);
3816
3824
  }
3817
3825
  // Only `auth_missing` is worth a relaunch, and the distinction is the
3818
3826
  // adapter's own (`probeAuth`), not a guess from prose.
@@ -3917,7 +3925,7 @@ export class Supervisor {
3917
3925
  if (event.role === 'assistant') {
3918
3926
  const working = relayAgent(String(descriptor.agent).toLowerCase());
3919
3927
  if (working)
3920
- clearAgentAuthFailure(working);
3928
+ clearAgentAuthFailure(working, source?.accountId);
3921
3929
  }
3922
3930
  this.sendEvent(running, 'message', { role: event.role, text: event.text });
3923
3931
  return;
@@ -7483,6 +7491,11 @@ export class Supervisor {
7483
7491
  });
7484
7492
  }
7485
7493
  default:
7494
+ // #422: the five account commands – their own module, one door each
7495
+ // over `claude-homes.ts` (plan §8).
7496
+ if (isAccountCommand(frame.name)) {
7497
+ return void reply(await runAccountCommand(frame.name, frame.args ?? {}, this.authRelay));
7498
+ }
7486
7499
  return void reply({ ok: false, error: `Unknown command` });
7487
7500
  }
7488
7501
  }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const RUNNER_VERSION = "0.65.1";
1
+ export declare const RUNNER_VERSION = "0.66.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Kept in sync with package.json by the release script (manual for now).
2
- export const RUNNER_VERSION = '0.65.1';
2
+ export const RUNNER_VERSION = '0.66.0';
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge4dev/runner",
3
- "version": "0.65.1",
3
+ "version": "0.66.0",
4
4
  "description": "DevBridge dev runner — connects a dev server to DevBridge and runs agent sessions (Claude Code / Codex)",
5
5
  "homepage": "https://bridge4.dev",
6
6
  "license": "MIT",