@songsid/agend 2.1.4-beta.24 → 2.1.4-beta.26
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/backend/claude-code.d.ts +23 -21
- package/dist/backend/claude-code.js +24 -22
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/channel/types.d.ts +1 -1
- package/dist/fleet-context.d.ts +23 -0
- package/dist/fleet-manager.d.ts +46 -0
- package/dist/fleet-manager.js +272 -0
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +16 -0
- package/dist/instance-lifecycle.js +44 -2
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +44 -0
- package/dist/locale.js.map +1 -1
- package/dist/login-flows.d.ts +79 -0
- package/dist/login-flows.js +152 -0
- package/dist/login-flows.js.map +1 -0
- package/dist/login-manager.d.ts +63 -0
- package/dist/login-manager.js +134 -0
- package/dist/login-manager.js.map +1 -0
- package/dist/tmux-manager.d.ts +6 -0
- package/dist/tmux-manager.js +12 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.d.ts +6 -0
- package/dist/topic-commands.js +53 -0
- package/dist/topic-commands.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,20 +23,28 @@ export declare class ClaudeCodeBackend implements CliBackend {
|
|
|
23
23
|
getReadyPattern(): RegExp;
|
|
24
24
|
/**
|
|
25
25
|
* The live spinner line, which is on screen only while generating. Captured from
|
|
26
|
-
*
|
|
26
|
+
* running panes and their pipe-pane recordings:
|
|
27
27
|
*
|
|
28
28
|
* working → `✢ Accomplishing… (11m 26s · ↓ 38.0k tokens)`
|
|
29
29
|
* idle → `✻ Worked for 6m 49s`
|
|
30
30
|
*
|
|
31
31
|
* Both panes also showed `❯` and the `ok` statusline, which is why neither of
|
|
32
|
-
* those can carry the distinction. The discriminator is the
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* those can carry the distinction. The discriminator is the rotating glyph plus
|
|
33
|
+
* Claude's one-word spinner label ending in an ellipsis. The completed line is
|
|
34
|
+
* past tense with no ellipsis. The verb and glyph both rotate, so neither
|
|
35
|
+
* specific value is matched.
|
|
35
36
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* Claude Code 2.1.239 paints that line incrementally. For roughly the first
|
|
38
|
+
* three seconds — and briefly during later repaints — capture-pane can see only
|
|
39
|
+
* `* Nesting…` before `(3s · ↓ 9 tokens)` is appended. It also emits hyphenated
|
|
40
|
+
* labels such as `Razzle-dazzling…` and `Sock-hopping…`. Requiring the elapsed
|
|
41
|
+
* counter and a letters-only verb made both real shapes look idle. Since `❯`
|
|
42
|
+
* remains visible throughout generation, a settled capture in either shape
|
|
43
|
+
* retired Cancel and the progress bubble while the turn was still running.
|
|
44
|
+
*
|
|
45
|
+
* The animation cycles through six measured frames, including one plain ASCII
|
|
46
|
+
* asterisk. The older leading class required a non-ASCII glyph, so sampling a
|
|
47
|
+
* continuously working pane 50 times at 250ms produced:
|
|
40
48
|
*
|
|
41
49
|
* ✻ 11/11 ✽ 10/10 ✢ 10/10 · 9/9 ✶ 4/4 * 0/6 ← U+002A never matched
|
|
42
50
|
*
|
|
@@ -46,19 +54,13 @@ export declare class ClaudeCodeBackend implements CliBackend {
|
|
|
46
54
|
* retired cancel buttons mid-turn. 12% of frames, so it hit some turns and not
|
|
47
55
|
* others.
|
|
48
56
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* Deliberately narrow, because the cost is asymmetric. Missing the spinner just
|
|
57
|
-
* restores today's behaviour; matching prose that happens to sit on a *stable*
|
|
58
|
-
* pane would hold the instance in `working` forever — no auto-pause, no cancel
|
|
59
|
-
* button retirement, and eventually a bogus hang alert. So the line must start
|
|
60
|
-
* with a non-ASCII, non-letter glyph and carry a single word ending in `…`:
|
|
61
|
-
* `- Something… (5s)` and `I waited… (30s) for the build` are both rejected.
|
|
57
|
+
* Deliberately narrow, because the cost is asymmetric. Matching prose that
|
|
58
|
+
* happens to sit on a *stable* pane would hold the instance in `working`
|
|
59
|
+
* forever — no auto-pause, no cancel-button retirement, and eventually a bogus
|
|
60
|
+
* hang alert. Therefore this accepts only Claude's six measured spinner glyphs,
|
|
61
|
+
* exactly one word (optionally hyphenated), and the Unicode ellipsis. Markdown
|
|
62
|
+
* prose such as `* bullet point…`, `- Something…`, and a completed
|
|
63
|
+
* `✻ Worked for 6m 49s` remain rejected.
|
|
62
64
|
*
|
|
63
65
|
* Note when this actually decides anything: while the CLI really is generating,
|
|
64
66
|
* the elapsed counter ticks, the pane changes, and motion already reports
|
|
@@ -123,20 +123,28 @@ export class ClaudeCodeBackend {
|
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
125
|
* The live spinner line, which is on screen only while generating. Captured from
|
|
126
|
-
*
|
|
126
|
+
* running panes and their pipe-pane recordings:
|
|
127
127
|
*
|
|
128
128
|
* working → `✢ Accomplishing… (11m 26s · ↓ 38.0k tokens)`
|
|
129
129
|
* idle → `✻ Worked for 6m 49s`
|
|
130
130
|
*
|
|
131
131
|
* Both panes also showed `❯` and the `ok` statusline, which is why neither of
|
|
132
|
-
* those can carry the distinction. The discriminator is the
|
|
133
|
-
*
|
|
134
|
-
*
|
|
132
|
+
* those can carry the distinction. The discriminator is the rotating glyph plus
|
|
133
|
+
* Claude's one-word spinner label ending in an ellipsis. The completed line is
|
|
134
|
+
* past tense with no ellipsis. The verb and glyph both rotate, so neither
|
|
135
|
+
* specific value is matched.
|
|
135
136
|
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
137
|
+
* Claude Code 2.1.239 paints that line incrementally. For roughly the first
|
|
138
|
+
* three seconds — and briefly during later repaints — capture-pane can see only
|
|
139
|
+
* `* Nesting…` before `(3s · ↓ 9 tokens)` is appended. It also emits hyphenated
|
|
140
|
+
* labels such as `Razzle-dazzling…` and `Sock-hopping…`. Requiring the elapsed
|
|
141
|
+
* counter and a letters-only verb made both real shapes look idle. Since `❯`
|
|
142
|
+
* remains visible throughout generation, a settled capture in either shape
|
|
143
|
+
* retired Cancel and the progress bubble while the turn was still running.
|
|
144
|
+
*
|
|
145
|
+
* The animation cycles through six measured frames, including one plain ASCII
|
|
146
|
+
* asterisk. The older leading class required a non-ASCII glyph, so sampling a
|
|
147
|
+
* continuously working pane 50 times at 250ms produced:
|
|
140
148
|
*
|
|
141
149
|
* ✻ 11/11 ✽ 10/10 ✢ 10/10 · 9/9 ✶ 4/4 * 0/6 ← U+002A never matched
|
|
142
150
|
*
|
|
@@ -146,19 +154,13 @@ export class ClaudeCodeBackend {
|
|
|
146
154
|
* retired cancel buttons mid-turn. 12% of frames, so it hit some turns and not
|
|
147
155
|
* others.
|
|
148
156
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* Deliberately narrow, because the cost is asymmetric. Missing the spinner just
|
|
157
|
-
* restores today's behaviour; matching prose that happens to sit on a *stable*
|
|
158
|
-
* pane would hold the instance in `working` forever — no auto-pause, no cancel
|
|
159
|
-
* button retirement, and eventually a bogus hang alert. So the line must start
|
|
160
|
-
* with a non-ASCII, non-letter glyph and carry a single word ending in `…`:
|
|
161
|
-
* `- Something… (5s)` and `I waited… (30s) for the build` are both rejected.
|
|
157
|
+
* Deliberately narrow, because the cost is asymmetric. Matching prose that
|
|
158
|
+
* happens to sit on a *stable* pane would hold the instance in `working`
|
|
159
|
+
* forever — no auto-pause, no cancel-button retirement, and eventually a bogus
|
|
160
|
+
* hang alert. Therefore this accepts only Claude's six measured spinner glyphs,
|
|
161
|
+
* exactly one word (optionally hyphenated), and the Unicode ellipsis. Markdown
|
|
162
|
+
* prose such as `* bullet point…`, `- Something…`, and a completed
|
|
163
|
+
* `✻ Worked for 6m 49s` remain rejected.
|
|
162
164
|
*
|
|
163
165
|
* Note when this actually decides anything: while the CLI really is generating,
|
|
164
166
|
* the elapsed counter ticks, the pane changes, and motion already reports
|
|
@@ -166,7 +168,7 @@ export class ClaudeCodeBackend {
|
|
|
166
168
|
* an in-progress spinner — which is exactly the hang this is meant to surface.
|
|
167
169
|
*/
|
|
168
170
|
getBusyPattern() {
|
|
169
|
-
return /^[ \t]*
|
|
171
|
+
return /^[ \t]*[✻✽✢·✶*][ \t]+\p{L}+(?:-\p{L}+)*…(?:[ \t]+\([^\n]*)?[ \t]*$/mu;
|
|
170
172
|
}
|
|
171
173
|
getContextUsage() {
|
|
172
174
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/backend/claude-code.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/backend/claude-code.ts"],"names":[],"mappings":"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"}
|
package/dist/channel/types.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface InstanceStatusData {
|
|
|
10
10
|
costCents: number;
|
|
11
11
|
}
|
|
12
12
|
export interface AlertData {
|
|
13
|
-
type: "hang" | "cost_warn" | "cost_limit" | "schedule_deferred" | "rotation" | "cancel" | "interactive_prompt" | "exit_restart" | "clear_confirm" | "tip";
|
|
13
|
+
type: "hang" | "cost_warn" | "cost_limit" | "schedule_deferred" | "rotation" | "cancel" | "interactive_prompt" | "exit_restart" | "clear_confirm" | "tip" | "login";
|
|
14
14
|
instanceName: string;
|
|
15
15
|
message: string;
|
|
16
16
|
choices?: Choice[];
|
package/dist/fleet-context.d.ts
CHANGED
|
@@ -93,6 +93,29 @@ export interface FleetContext {
|
|
|
93
93
|
promptTip?(generalName: string, adapter: import("./channel/types.js").ChannelAdapter, chatId: string, threadId?: string): Promise<"posted" | "empty" | "unavailable">;
|
|
94
94
|
/** Persistently enable advanced tips without waiting for the dismissal threshold. */
|
|
95
95
|
unlockAdvancedTips?(userId: string): boolean;
|
|
96
|
+
/** `/login` backend chooser buttons. Caller enforces fleet-admin. */
|
|
97
|
+
promptLoginBackends?(chat: {
|
|
98
|
+
adapter: import("./channel/types.js").ChannelAdapter;
|
|
99
|
+
adapterId: string;
|
|
100
|
+
chatId: string;
|
|
101
|
+
threadId?: string;
|
|
102
|
+
}): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Start a remote login session for one backend; returns a status line, or
|
|
105
|
+
* null when a still-valid-auth confirmation prompt was posted instead.
|
|
106
|
+
*/
|
|
107
|
+
startLoginSession?(backend: string, chat: {
|
|
108
|
+
adapter: import("./channel/types.js").ChannelAdapter;
|
|
109
|
+
adapterId: string;
|
|
110
|
+
chatId: string;
|
|
111
|
+
threadId?: string;
|
|
112
|
+
}, opts?: {
|
|
113
|
+
skipAuthCheck?: boolean;
|
|
114
|
+
}): Promise<string | null>;
|
|
115
|
+
/** Paste admin-supplied text (auth code / start URL) into the login window. */
|
|
116
|
+
loginSubmitInput?(text: string): Promise<string>;
|
|
117
|
+
/** Abort the active login session. */
|
|
118
|
+
cancelLoginSession?(): Promise<string>;
|
|
96
119
|
/** Human-readable effective model for an instance (resolves inherited defaults). */
|
|
97
120
|
modelDisplayForInstance?(name: string): string;
|
|
98
121
|
/**
|
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -811,6 +811,52 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
811
811
|
private isDeliveryEpochCurrent;
|
|
812
812
|
/** Invalidate work queued before a user cancel and wake idle-gate waiters. */
|
|
813
813
|
private cancelPendingDeliveries;
|
|
814
|
+
private activeLogin;
|
|
815
|
+
/** Post the backend chooser for a bare `/login`. Caller enforces admin. */
|
|
816
|
+
promptLoginBackends(chat: {
|
|
817
|
+
adapter: ChannelAdapter;
|
|
818
|
+
adapterId: string;
|
|
819
|
+
chatId: string;
|
|
820
|
+
threadId?: string;
|
|
821
|
+
}): Promise<void>;
|
|
822
|
+
/**
|
|
823
|
+
* Start a login session for one backend. Caller enforces admin.
|
|
824
|
+
* Returns a status line to post, or null when a confirmation prompt was
|
|
825
|
+
* posted instead (auth still valid — see the pre-check below).
|
|
826
|
+
*/
|
|
827
|
+
startLoginSession(backendArg: string, chat: {
|
|
828
|
+
adapter: ChannelAdapter;
|
|
829
|
+
adapterId: string;
|
|
830
|
+
chatId: string;
|
|
831
|
+
threadId?: string;
|
|
832
|
+
}, opts?: {
|
|
833
|
+
skipAuthCheck?: boolean;
|
|
834
|
+
}): Promise<string | null>;
|
|
835
|
+
/** Create the login window and session (pre-check already settled). */
|
|
836
|
+
private launchLoginSession;
|
|
837
|
+
/** `/login code <text>` — paste admin-supplied text into the login window. */
|
|
838
|
+
loginSubmitInput(text: string): Promise<string>;
|
|
839
|
+
/** `/login cancel` — abort the active session and remove its window. */
|
|
840
|
+
cancelLoginSession(): Promise<string>;
|
|
841
|
+
/**
|
|
842
|
+
* The URL (+ code) is a live credential: whoever completes it binds THEIR
|
|
843
|
+
* account to this fleet's CLI. Telegram gets an HTML spoiler (same treatment
|
|
844
|
+
* as the dashboard token); other adapters get plain text with the warning.
|
|
845
|
+
*/
|
|
846
|
+
private sendLoginSecret;
|
|
847
|
+
/**
|
|
848
|
+
* After a successful login: wake the paused instances of that backend AND
|
|
849
|
+
* restart the running ones — a live CLI holds the old token in memory and
|
|
850
|
+
* only re-reads credentials on process start (a paused instance's CLI is
|
|
851
|
+
* already dead, so waking it respawns with the new token for free).
|
|
852
|
+
*/
|
|
853
|
+
private recoverBackendInstances;
|
|
854
|
+
/** Backend chooser button → start that backend's login session. */
|
|
855
|
+
private handleLoginBackendSelect;
|
|
856
|
+
/** Re-login confirmation (auth pre-check said credentials still work). */
|
|
857
|
+
private handleLoginConfirm;
|
|
858
|
+
/** Kiro provider button → drive the CLI's arrow-key selector. */
|
|
859
|
+
private handleLoginMenuSelect;
|
|
814
860
|
queueMirrorMessage(text: string): void;
|
|
815
861
|
/** Push an SSE event to all connected Web UI clients. */
|
|
816
862
|
emitSseEvent(event: string, data: unknown): void;
|
package/dist/fleet-manager.js
CHANGED
|
@@ -44,6 +44,8 @@ import { outboundHandlers } from "./outbound-handlers.js";
|
|
|
44
44
|
import { handleWebRequest, broadcastSseEvent } from "./web-api.js";
|
|
45
45
|
import { handleViewRequest, isViewPath } from "./view-api.js";
|
|
46
46
|
import { handleUsageRequest, isUsagePath, usageProviderIdForBackend } from "./usage/usage-api.js";
|
|
47
|
+
import { LOGIN_FLOWS, LOGIN_BACKEND_ALIASES, checkAuthStatus } from "./login-flows.js";
|
|
48
|
+
import { LoginSession } from "./login-manager.js";
|
|
47
49
|
import { handleSettingsRequest } from "./settings-api.js";
|
|
48
50
|
import { setLocale, detectLocale, getLocale, t } from "./locale.js";
|
|
49
51
|
import { handleAgentRequest } from "./agent-endpoint.js";
|
|
@@ -209,6 +211,9 @@ const HANG_CALLBACK_PREFIX = "hang:";
|
|
|
209
211
|
const CLEAR_CONFIRM_CALLBACK_PREFIX = "clear-confirm:";
|
|
210
212
|
const TIP_DISMISS_CALLBACK_PREFIX = "tip-dismiss:";
|
|
211
213
|
const TIP_UNLOCK_CALLBACK_PREFIX = "tip-unlock:";
|
|
214
|
+
const LOGIN_CALLBACK_PREFIX = "login:";
|
|
215
|
+
const LOGIN_MENU_CALLBACK_PREFIX = "login-menu:";
|
|
216
|
+
const LOGIN_CONFIRM_CALLBACK_PREFIX = "login-confirm:";
|
|
212
217
|
const CLEAR_CONFIRM_TIMEOUT_MS = 15_000;
|
|
213
218
|
/** Default lifetime for long-lived nonce prompts (clear overrides this to 15s). */
|
|
214
219
|
const NONCE_BUTTON_TIMEOUT_MS = 15 * 60_000;
|
|
@@ -2364,6 +2369,12 @@ export class FleetManager {
|
|
|
2364
2369
|
return;
|
|
2365
2370
|
if (await this.handleTipUnlock(data, adapterId, this.adapter ?? undefined))
|
|
2366
2371
|
return;
|
|
2372
|
+
if (await this.handleLoginBackendSelect(data, adapterId, this.adapter ?? undefined))
|
|
2373
|
+
return;
|
|
2374
|
+
if (await this.handleLoginMenuSelect(data, adapterId, this.adapter ?? undefined))
|
|
2375
|
+
return;
|
|
2376
|
+
if (await this.handleLoginConfirm(data, adapterId, this.adapter ?? undefined))
|
|
2377
|
+
return;
|
|
2367
2378
|
if (await this.handleClearConfirmation(data, adapterId, this.adapter ?? undefined))
|
|
2368
2379
|
return;
|
|
2369
2380
|
if (await this.handleExitRestartPrompt(data, adapterId, this.adapter ?? undefined))
|
|
@@ -2737,6 +2748,12 @@ export class FleetManager {
|
|
|
2737
2748
|
return;
|
|
2738
2749
|
if (await this.handleTipUnlock(data, adapterId, adapter))
|
|
2739
2750
|
return;
|
|
2751
|
+
if (await this.handleLoginBackendSelect(data, adapterId, adapter))
|
|
2752
|
+
return;
|
|
2753
|
+
if (await this.handleLoginMenuSelect(data, adapterId, adapter))
|
|
2754
|
+
return;
|
|
2755
|
+
if (await this.handleLoginConfirm(data, adapterId, adapter))
|
|
2756
|
+
return;
|
|
2740
2757
|
if (await this.handleClearConfirmation(data, adapterId, adapter))
|
|
2741
2758
|
return;
|
|
2742
2759
|
if (await this.handleExitRestartPrompt(data, adapterId, adapter))
|
|
@@ -6175,6 +6192,261 @@ export class FleetManager {
|
|
|
6175
6192
|
check();
|
|
6176
6193
|
return next;
|
|
6177
6194
|
}
|
|
6195
|
+
// ── Remote CLI login (`/login`) ──────────────────────────────────────────
|
|
6196
|
+
//
|
|
6197
|
+
// One session at a time, in a dedicated tmux window — never an instance
|
|
6198
|
+
// pane. Credentials are per-backend (codex homes symlink auth.json to the
|
|
6199
|
+
// shared ~/.codex; the other CLIs use one real home), so a single sign-in
|
|
6200
|
+
// repairs every instance of that backend, and instance delivery, pane-state
|
|
6201
|
+
// detection, tool progress, and mcp_proxy_reply never observe login output.
|
|
6202
|
+
activeLogin = null;
|
|
6203
|
+
/** Post the backend chooser for a bare `/login`. Caller enforces admin. */
|
|
6204
|
+
async promptLoginBackends(chat) {
|
|
6205
|
+
const configured = new Set();
|
|
6206
|
+
for (const [, config] of Object.entries(this.fleetConfig?.instances ?? {})) {
|
|
6207
|
+
configured.add(config.backend ?? this.fleetConfig?.defaults?.backend ?? "claude-code");
|
|
6208
|
+
}
|
|
6209
|
+
const choices = Object.keys(LOGIN_FLOWS)
|
|
6210
|
+
.filter(backend => configured.size === 0 || configured.has(backend))
|
|
6211
|
+
.map(backend => ({ action: backend, label: backend }));
|
|
6212
|
+
if (choices.length === 0) {
|
|
6213
|
+
await chat.adapter.sendText(chat.chatId, t("login.unsupported", [...configured].join(", ")), { threadId: chat.threadId });
|
|
6214
|
+
return;
|
|
6215
|
+
}
|
|
6216
|
+
await this.postNonceButtonPrompt({
|
|
6217
|
+
prefix: LOGIN_CALLBACK_PREFIX,
|
|
6218
|
+
alertType: "login",
|
|
6219
|
+
instanceName: "login",
|
|
6220
|
+
adapter: chat.adapter,
|
|
6221
|
+
adapterId: chat.adapterId,
|
|
6222
|
+
chatId: chat.chatId,
|
|
6223
|
+
threadId: chat.threadId,
|
|
6224
|
+
message: t("login.choose_backend"),
|
|
6225
|
+
choices,
|
|
6226
|
+
expiredText: t("buttons.stale"),
|
|
6227
|
+
});
|
|
6228
|
+
}
|
|
6229
|
+
/**
|
|
6230
|
+
* Start a login session for one backend. Caller enforces admin.
|
|
6231
|
+
* Returns a status line to post, or null when a confirmation prompt was
|
|
6232
|
+
* posted instead (auth still valid — see the pre-check below).
|
|
6233
|
+
*/
|
|
6234
|
+
async startLoginSession(backendArg, chat, opts = {}) {
|
|
6235
|
+
const backend = LOGIN_BACKEND_ALIASES[backendArg.toLowerCase()] ?? backendArg.toLowerCase();
|
|
6236
|
+
const flow = LOGIN_FLOWS[backend];
|
|
6237
|
+
if (!flow)
|
|
6238
|
+
return t("login.unsupported", backendArg);
|
|
6239
|
+
if (this.activeLogin)
|
|
6240
|
+
return t("login.busy", this.activeLogin.backend);
|
|
6241
|
+
// Token-free pre-check (5s cap): re-login while auth still works is
|
|
6242
|
+
// usually a mistake, so it needs a confirmed click. An invalid OR
|
|
6243
|
+
// uncertain result (timeout, missing binary) proceeds straight to login —
|
|
6244
|
+
// an unreliable probe must never block the re-login the admin asked for.
|
|
6245
|
+
if (!opts.skipAuthCheck && flow.authCheck) {
|
|
6246
|
+
const status = await checkAuthStatus(flow.authCheck);
|
|
6247
|
+
if (status === "valid") {
|
|
6248
|
+
await this.postNonceButtonPrompt({
|
|
6249
|
+
prefix: LOGIN_CONFIRM_CALLBACK_PREFIX,
|
|
6250
|
+
alertType: "login",
|
|
6251
|
+
instanceName: backend,
|
|
6252
|
+
adapter: chat.adapter,
|
|
6253
|
+
adapterId: chat.adapterId,
|
|
6254
|
+
chatId: chat.chatId,
|
|
6255
|
+
threadId: chat.threadId,
|
|
6256
|
+
message: t("login.still_valid", backend),
|
|
6257
|
+
choices: [
|
|
6258
|
+
{ action: "go", label: t("login.relogin_go") },
|
|
6259
|
+
{ action: "cancel", label: t("login.relogin_cancel") },
|
|
6260
|
+
],
|
|
6261
|
+
expiredText: t("buttons.stale"),
|
|
6262
|
+
});
|
|
6263
|
+
return null;
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
return this.launchLoginSession(flow, backend, chat);
|
|
6267
|
+
}
|
|
6268
|
+
/** Create the login window and session (pre-check already settled). */
|
|
6269
|
+
async launchLoginSession(flow, backend, chat) {
|
|
6270
|
+
if (this.activeLogin)
|
|
6271
|
+
return t("login.busy", this.activeLogin.backend);
|
|
6272
|
+
const sessionName = getTmuxSession();
|
|
6273
|
+
await TmuxManager.ensureSession(sessionName);
|
|
6274
|
+
const tmux = new TmuxManager(sessionName, "");
|
|
6275
|
+
const session = new LoginSession(flow, tmux, {
|
|
6276
|
+
onMenu: async (options) => {
|
|
6277
|
+
await this.postNonceButtonPrompt({
|
|
6278
|
+
prefix: LOGIN_MENU_CALLBACK_PREFIX,
|
|
6279
|
+
alertType: "login",
|
|
6280
|
+
instanceName: backend,
|
|
6281
|
+
adapter: chat.adapter,
|
|
6282
|
+
adapterId: chat.adapterId,
|
|
6283
|
+
chatId: chat.chatId,
|
|
6284
|
+
threadId: chat.threadId,
|
|
6285
|
+
message: t("login.choose_provider"),
|
|
6286
|
+
choices: options.map((label, index) => ({ action: String(index), label })),
|
|
6287
|
+
expiredText: t("buttons.stale"),
|
|
6288
|
+
});
|
|
6289
|
+
},
|
|
6290
|
+
onAuthHint: async (url, code) => {
|
|
6291
|
+
await this.sendLoginSecret(chat, backend, url, code);
|
|
6292
|
+
},
|
|
6293
|
+
onNeedInput: async (promptExcerpt) => {
|
|
6294
|
+
await chat.adapter.sendText(chat.chatId, t("login.need_input", backend, promptExcerpt), { threadId: chat.threadId }).catch(() => { });
|
|
6295
|
+
},
|
|
6296
|
+
onDone: async ({ ok, detail }) => {
|
|
6297
|
+
this.activeLogin = null;
|
|
6298
|
+
let text;
|
|
6299
|
+
if (ok) {
|
|
6300
|
+
const { woken, restarted } = await this.recoverBackendInstances(backend);
|
|
6301
|
+
const none = t("login.none");
|
|
6302
|
+
text = t("login.success", backend, woken.length ? woken.join(", ") : none, restarted.length ? restarted.join(", ") : none);
|
|
6303
|
+
}
|
|
6304
|
+
else if (detail === "cancelled") {
|
|
6305
|
+
text = t("login.cancelled", backend);
|
|
6306
|
+
}
|
|
6307
|
+
else {
|
|
6308
|
+
text = t("login.failed", backend, detail);
|
|
6309
|
+
}
|
|
6310
|
+
await chat.adapter.sendText(chat.chatId, text, { threadId: chat.threadId }).catch(() => { });
|
|
6311
|
+
},
|
|
6312
|
+
}, this.logger);
|
|
6313
|
+
// Claim the slot before the first await so two admins racing /login cannot
|
|
6314
|
+
// both create windows; release on startup failure.
|
|
6315
|
+
this.activeLogin = { session, backend, chat };
|
|
6316
|
+
try {
|
|
6317
|
+
await session.start();
|
|
6318
|
+
}
|
|
6319
|
+
catch (err) {
|
|
6320
|
+
this.activeLogin = null;
|
|
6321
|
+
return t("login.failed", backend, err.message);
|
|
6322
|
+
}
|
|
6323
|
+
return t("login.started", backend);
|
|
6324
|
+
}
|
|
6325
|
+
/** `/login code <text>` — paste admin-supplied text into the login window. */
|
|
6326
|
+
async loginSubmitInput(text) {
|
|
6327
|
+
if (!this.activeLogin)
|
|
6328
|
+
return t("login.no_session");
|
|
6329
|
+
const ok = await this.activeLogin.session.submitInput(text);
|
|
6330
|
+
return ok ? t("login.input_sent") : t("login.input_failed");
|
|
6331
|
+
}
|
|
6332
|
+
/** `/login cancel` — abort the active session and remove its window. */
|
|
6333
|
+
async cancelLoginSession() {
|
|
6334
|
+
if (!this.activeLogin)
|
|
6335
|
+
return t("login.no_session");
|
|
6336
|
+
const backend = this.activeLogin.backend;
|
|
6337
|
+
await this.activeLogin.session.cancel();
|
|
6338
|
+
return t("login.cancelled", backend);
|
|
6339
|
+
}
|
|
6340
|
+
/**
|
|
6341
|
+
* The URL (+ code) is a live credential: whoever completes it binds THEIR
|
|
6342
|
+
* account to this fleet's CLI. Telegram gets an HTML spoiler (same treatment
|
|
6343
|
+
* as the dashboard token); other adapters get plain text with the warning.
|
|
6344
|
+
*/
|
|
6345
|
+
async sendLoginSecret(chat, backend, url, code) {
|
|
6346
|
+
const codeLine = code ? `\n${t("login.auth_code", code)}` : "";
|
|
6347
|
+
try {
|
|
6348
|
+
if (chat.adapter.type === "telegram") {
|
|
6349
|
+
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
6350
|
+
await chat.adapter.sendText(chat.chatId, `${esc(t("login.auth_hint", backend))}\n<tg-spoiler>${esc(url)}${esc(codeLine)}</tg-spoiler>`, { threadId: chat.threadId, format: "html" });
|
|
6351
|
+
}
|
|
6352
|
+
else {
|
|
6353
|
+
await chat.adapter.sendText(chat.chatId, `${t("login.auth_hint", backend)}\n${url}${codeLine}`, { threadId: chat.threadId });
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
6356
|
+
catch (err) {
|
|
6357
|
+
this.logger.warn({ err: err.message, backend }, "Failed to deliver login URL");
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
/**
|
|
6361
|
+
* After a successful login: wake the paused instances of that backend AND
|
|
6362
|
+
* restart the running ones — a live CLI holds the old token in memory and
|
|
6363
|
+
* only re-reads credentials on process start (a paused instance's CLI is
|
|
6364
|
+
* already dead, so waking it respawns with the new token for free).
|
|
6365
|
+
*/
|
|
6366
|
+
async recoverBackendInstances(backend) {
|
|
6367
|
+
const woken = [];
|
|
6368
|
+
const restarted = [];
|
|
6369
|
+
for (const [name, config] of Object.entries(this.fleetConfig?.instances ?? {})) {
|
|
6370
|
+
const effective = config.backend ?? this.fleetConfig?.defaults?.backend ?? "claude-code";
|
|
6371
|
+
if (effective !== backend)
|
|
6372
|
+
continue;
|
|
6373
|
+
const status = this.getInstanceStatus(name);
|
|
6374
|
+
try {
|
|
6375
|
+
if (status === "paused") {
|
|
6376
|
+
if (this.daemons.has(name))
|
|
6377
|
+
await this.lifecycle.wake(name, 30_000);
|
|
6378
|
+
else
|
|
6379
|
+
await this.startPersistedPausedInstance(name);
|
|
6380
|
+
woken.push(name);
|
|
6381
|
+
}
|
|
6382
|
+
else if (status === "running") {
|
|
6383
|
+
await this.restartSingleInstance(name);
|
|
6384
|
+
restarted.push(name);
|
|
6385
|
+
}
|
|
6386
|
+
}
|
|
6387
|
+
catch (err) {
|
|
6388
|
+
this.logger.warn({ err: err.message, name, status }, "Post-login recovery failed");
|
|
6389
|
+
}
|
|
6390
|
+
}
|
|
6391
|
+
return { woken, restarted };
|
|
6392
|
+
}
|
|
6393
|
+
/** Backend chooser button → start that backend's login session. */
|
|
6394
|
+
async handleLoginBackendSelect(data, callbackAdapterId, receivingAdapter) {
|
|
6395
|
+
const claimed = this.consumeNonceCallback(LOGIN_CALLBACK_PREFIX, /^login:([0-9a-f]+):([a-z][a-z-]*)$/, data, callbackAdapterId, receivingAdapter);
|
|
6396
|
+
if (claimed === null)
|
|
6397
|
+
return false;
|
|
6398
|
+
if (claimed === "consumed")
|
|
6399
|
+
return true;
|
|
6400
|
+
const { entry, action: backend } = claimed;
|
|
6401
|
+
await this.retireNonceButtons(entry, entry.messageId ?? data.messageId, t("login.starting_backend", backend));
|
|
6402
|
+
const text = await this.startLoginSession(backend, {
|
|
6403
|
+
adapter: entry.adapter,
|
|
6404
|
+
adapterId: entry.adapterId,
|
|
6405
|
+
chatId: entry.chatId,
|
|
6406
|
+
threadId: entry.threadId,
|
|
6407
|
+
});
|
|
6408
|
+
if (text)
|
|
6409
|
+
await entry.adapter.sendText(entry.chatId, text, { threadId: entry.threadId }).catch(() => { });
|
|
6410
|
+
return true;
|
|
6411
|
+
}
|
|
6412
|
+
/** Re-login confirmation (auth pre-check said credentials still work). */
|
|
6413
|
+
async handleLoginConfirm(data, callbackAdapterId, receivingAdapter) {
|
|
6414
|
+
const claimed = this.consumeNonceCallback(LOGIN_CONFIRM_CALLBACK_PREFIX, /^login-confirm:([0-9a-f]+):(go|cancel)$/, data, callbackAdapterId, receivingAdapter);
|
|
6415
|
+
if (claimed === null)
|
|
6416
|
+
return false;
|
|
6417
|
+
if (claimed === "consumed")
|
|
6418
|
+
return true;
|
|
6419
|
+
const { entry, action } = claimed;
|
|
6420
|
+
const backend = entry.instanceName;
|
|
6421
|
+
if (action === "cancel") {
|
|
6422
|
+
await this.retireNonceButtons(entry, entry.messageId ?? data.messageId, t("login.cancelled", backend));
|
|
6423
|
+
return true;
|
|
6424
|
+
}
|
|
6425
|
+
await this.retireNonceButtons(entry, entry.messageId ?? data.messageId, t("login.starting_backend", backend));
|
|
6426
|
+
const text = await this.startLoginSession(backend, {
|
|
6427
|
+
adapter: entry.adapter,
|
|
6428
|
+
adapterId: entry.adapterId,
|
|
6429
|
+
chatId: entry.chatId,
|
|
6430
|
+
threadId: entry.threadId,
|
|
6431
|
+
}, { skipAuthCheck: true });
|
|
6432
|
+
if (text)
|
|
6433
|
+
await entry.adapter.sendText(entry.chatId, text, { threadId: entry.threadId }).catch(() => { });
|
|
6434
|
+
return true;
|
|
6435
|
+
}
|
|
6436
|
+
/** Kiro provider button → drive the CLI's arrow-key selector. */
|
|
6437
|
+
async handleLoginMenuSelect(data, callbackAdapterId, receivingAdapter) {
|
|
6438
|
+
const claimed = this.consumeNonceCallback(LOGIN_MENU_CALLBACK_PREFIX, /^login-menu:([0-9a-f]+):(\d)$/, data, callbackAdapterId, receivingAdapter);
|
|
6439
|
+
if (claimed === null)
|
|
6440
|
+
return false;
|
|
6441
|
+
if (claimed === "consumed")
|
|
6442
|
+
return true;
|
|
6443
|
+
const { entry, action } = claimed;
|
|
6444
|
+
const index = Number(action);
|
|
6445
|
+
const label = this.activeLogin?.session.flow.menu?.options[index] ?? action;
|
|
6446
|
+
const ok = await this.activeLogin?.session.selectMenuOption(index) ?? false;
|
|
6447
|
+
await this.retireNonceButtons(entry, entry.messageId ?? data.messageId, ok ? t("login.provider_selected", label) : t("login.no_session"));
|
|
6448
|
+
return true;
|
|
6449
|
+
}
|
|
6178
6450
|
queueMirrorMessage(text) {
|
|
6179
6451
|
const mirrorTopicId = this.fleetConfig?.channel?.mirror_topic_id;
|
|
6180
6452
|
if (mirrorTopicId == null || !this.adapter)
|