shadok-ai 0.17.7 → 0.17.8

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/README.md CHANGED
@@ -487,6 +487,20 @@ is never shown. It is valid for about a year; re-run the card (or `/mttoken`)
487
487
  before it expires. The shell path still works as a fallback: `claude setup-token`
488
488
  and store the result as the vault secret `MT_CLAUDE_OAUTH_TOKEN`.
489
489
 
490
+ **Connectors: token vs login.** That token can only make model requests — it
491
+ does **not** carry your claude.ai **Connectors** (Slack, Google Workspace,
492
+ Microsoft 365, Atlassian, …). If you want agents to use your connectors, switch
493
+ the instance's **agent auth mode** to **login**: instead of the token, each OS
494
+ user (the shared *commons* user, plus each private group's user) does a one-time
495
+ `claude auth login` from the cockpit, into its own home, and its agents then see
496
+ the connectors. The trade-off is lifetime: a login lasts about a **month** (vs a
497
+ year for the token) and is **per user**, so the cockpit shows a status row per
498
+ user and reminds you to reconnect before each lapses. The default stays
499
+ **token** — nothing changes until an admin switches. A login is never shared
500
+ across OS users (Claude rewrites the credential single-owner on refresh), which
501
+ is why each user logs in separately. Design:
502
+ `docs/superpowers/specs/2026-11-04-connectors-via-global-login-design.md`.
503
+
490
504
  Telegram stays single-owner, and there are no
491
505
  disk quotas yet. Design: `docs/superpowers/specs/2026-10-29-multi-tenant-scoped-isolation-design.md`.
492
506
 
@@ -0,0 +1,36 @@
1
+ /** The credential file a login writes, under the user's own home. */
2
+ export declare function credPathForHome(home: string): string;
3
+ /**
4
+ * Whether `home` holds a login, and when it lapses — the two facts the cockpit
5
+ * needs for the per-user status row. NEVER returns the token value; reads only
6
+ * `refreshToken` presence and `refreshTokenExpiresAt` (~1 month).
7
+ */
8
+ export declare function agentLoginInfo(home: string): {
9
+ loggedIn: boolean;
10
+ expiresAt: number | null;
11
+ };
12
+ export declare function agentLoginPending(user: string): boolean;
13
+ export declare function cancelAgentLogin(user: string): void;
14
+ /**
15
+ * Start `claude auth login --claudeai` as `user` (HOME `home`) in a detached
16
+ * tmux pane and resolve the OAuth URL. Reuses a live flow that already printed a
17
+ * URL (a reload must not kill the link the operator is looking at — each flow
18
+ * carries its own PKCE challenge).
19
+ */
20
+ export declare function startAgentLogin(user: string, home: string): Promise<{
21
+ url: string;
22
+ } | {
23
+ error: string;
24
+ }>;
25
+ /**
26
+ * Submit the pasted code for `user`'s login. Types it into the masked box, waits
27
+ * for it to land, presses Enter, then watches for SUCCESS (a fresh credential
28
+ * file in the user's home) or the invalid-code refusal. The credential is never
29
+ * read for its contents, logged, or returned.
30
+ */
31
+ export declare function submitAgentLoginCode(user: string, code: string): Promise<{
32
+ ok: true;
33
+ } | {
34
+ ok: false;
35
+ error: string;
36
+ }>;
@@ -0,0 +1,240 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { claudeCommand } from "./claude-bin.js";
5
+ import { tmuxAvailable, tmuxHasSession, tmuxKillSession } from "./tmux.js";
6
+ import { dropArgv } from "./osusers.js";
7
+ import { parseSetupTokenUrl, parseSetupTokenOutcome } from "./setup-token.js";
8
+ /**
9
+ * In-cockpit `claude auth login --claudeai` for a SINGLE OS user, in `login`
10
+ * auth mode (`config.agentAuth === "login"`). Unlike `setup-token.ts` (which
11
+ * mints the server-owned long-lived token and runs as the server user), this
12
+ * drives an interactive subscription login AS a dropped user (`main`, or a
13
+ * private group's `sk-*`), so the credential lands in THAT user's own
14
+ * `~/.claude/.credentials.json` and that user's agents get the account's
15
+ * claude.ai connectors.
16
+ *
17
+ * Why per-user and never shared across users: `claude` refreshes the on-disk
18
+ * credential by write-new-then-rename, leaving it owned by the refresher in mode
19
+ * 600 — so a credential shared between DIFFERENT OS users locks the others out on
20
+ * the first refresh (measured, ledger `[45be]`/`[2d5c]`). Same-user agents share
21
+ * one login natively (one uid, one real file); that is all we rely on.
22
+ *
23
+ * Mechanics mirror `setup-token.ts`: a detached tmux pane (a real TTY for the
24
+ * CLI's `isatty` gate; `capture-pane -p` reads already-rendered text), the pane
25
+ * set wide so the ~350-char URL never wraps, and the SAME OAuth screens — so the
26
+ * URL and invalid-code parsers are reused from there. The difference is success
27
+ * detection: there is no token on screen; success is the credential FILE
28
+ * appearing in the user's home (an observed fact, invariant 27). The credential
29
+ * value is never read for its contents, logged, or returned.
30
+ *
31
+ * Design: docs/superpowers/specs/2026-11-04-connectors-via-global-login-design.md
32
+ */
33
+ /** The OAuth URL expires anyway; a child holding the session forever is worse. */
34
+ const FLOW_IDLE_MS = 10 * 60_000;
35
+ /** Wide enough that the ~350-char authorize URL never wraps. */
36
+ const PANE_COLS = 400;
37
+ const PANE_ROWS = 50;
38
+ /** One flow per OS user; the tmux session name is derived from the user. */
39
+ function sessionFor(user) {
40
+ return `sk-login-${user}`;
41
+ }
42
+ /** The credential file a login writes, under the user's own home. */
43
+ export function credPathForHome(home) {
44
+ return path.join(home, ".claude", ".credentials.json");
45
+ }
46
+ /**
47
+ * Whether `home` holds a login, and when it lapses — the two facts the cockpit
48
+ * needs for the per-user status row. NEVER returns the token value; reads only
49
+ * `refreshToken` presence and `refreshTokenExpiresAt` (~1 month).
50
+ */
51
+ export function agentLoginInfo(home) {
52
+ try {
53
+ const d = JSON.parse(fs.readFileSync(credPathForHome(home), "utf8"));
54
+ const o = d.claudeAiOauth ?? d;
55
+ return {
56
+ loggedIn: !!o.refreshToken,
57
+ expiresAt: typeof o.refreshTokenExpiresAt === "number" ? o.refreshTokenExpiresAt : null,
58
+ };
59
+ }
60
+ catch {
61
+ return { loggedIn: false, expiresAt: null };
62
+ }
63
+ }
64
+ const flows = new Map();
65
+ function tmux(args, input) {
66
+ return execFileSync("tmux", args, {
67
+ encoding: "utf8",
68
+ input,
69
+ timeout: 10_000,
70
+ maxBuffer: 8 * 1024 * 1024,
71
+ stdio: ["pipe", "pipe", "ignore"],
72
+ });
73
+ }
74
+ function capture(session) {
75
+ try {
76
+ return tmux(["capture-pane", "-t", session, "-p"]);
77
+ }
78
+ catch {
79
+ return "";
80
+ }
81
+ }
82
+ function sleep(ms) {
83
+ return new Promise((r) => setTimeout(r, ms));
84
+ }
85
+ /** mtime of the credential file in ms, or 0 if absent/unreadable. */
86
+ function credMtime(home) {
87
+ try {
88
+ return fs.statSync(credPathForHome(home)).mtimeMs;
89
+ }
90
+ catch {
91
+ return 0;
92
+ }
93
+ }
94
+ export function agentLoginPending(user) {
95
+ const f = flows.get(user);
96
+ return !!f && !f.ended && tmuxHasSession(sessionFor(user));
97
+ }
98
+ export function cancelAgentLogin(user) {
99
+ const f = flows.get(user);
100
+ if (f)
101
+ clearTimeout(f.timer);
102
+ tmuxKillSession(sessionFor(user));
103
+ flows.delete(user);
104
+ }
105
+ /**
106
+ * Start `claude auth login --claudeai` as `user` (HOME `home`) in a detached
107
+ * tmux pane and resolve the OAuth URL. Reuses a live flow that already printed a
108
+ * URL (a reload must not kill the link the operator is looking at — each flow
109
+ * carries its own PKCE challenge).
110
+ */
111
+ export async function startAgentLogin(user, home) {
112
+ const session = sessionFor(user);
113
+ const live = flows.get(user);
114
+ if (live && !live.ended && live.url && tmuxHasSession(session))
115
+ return { url: live.url };
116
+ cancelAgentLogin(user);
117
+ if (!tmuxAvailable())
118
+ return { error: "tmux is not available on this host — it is required to run the login" };
119
+ // Drop to the target user (setpriv) and run the login. `env` unsets any
120
+ // inherited CLAUDE*/CLAUDECODE/AI_AGENT vars (a parent token or child-session
121
+ // marker must not reach this login) and sets the user's own HOME so the
122
+ // credential lands in that home; BROWSER is neutralised so the CLI never opens
123
+ // a tab on the server. Each token single-quoted for the shell tmux runs.
124
+ const bin = claudeCommand();
125
+ const drop = dropArgv(user, bin, ["auth", "login", "--claudeai"]);
126
+ const unset = Object.keys(process.env)
127
+ .filter((k) => /^(CLAUDE|CLAUDECODE|AI_AGENT)/.test(k))
128
+ .flatMap((k) => ["-u", k]);
129
+ const cmd = [
130
+ "env",
131
+ ...unset,
132
+ `HOME=${home}`,
133
+ `USER=${user}`,
134
+ `LOGNAME=${user}`,
135
+ "TERM=xterm-256color",
136
+ "BROWSER=/usr/bin/true",
137
+ drop.cmd,
138
+ ...drop.argv,
139
+ ]
140
+ .map((a) => `'${String(a).replace(/'/g, "'\\''")}'`)
141
+ .join(" ");
142
+ try {
143
+ tmuxKillSession(session);
144
+ tmux(["new-session", "-d", "-s", session, "-x", String(PANE_COLS), "-y", String(PANE_ROWS), cmd]);
145
+ }
146
+ catch (e) {
147
+ return { error: "could not start the login: " + (e instanceof Error ? e.message : String(e)) };
148
+ }
149
+ const f = {
150
+ user,
151
+ home,
152
+ url: null,
153
+ ended: false,
154
+ priorMtime: credMtime(home),
155
+ timer: setTimeout(() => cancelAgentLogin(user), FLOW_IDLE_MS),
156
+ };
157
+ flows.set(user, f);
158
+ const deadline = Date.now() + 30_000;
159
+ while (Date.now() < deadline) {
160
+ if (flows.get(user) !== f || f.ended)
161
+ return { error: "the login ended before printing a URL" };
162
+ if (!tmuxHasSession(session)) {
163
+ cancelAgentLogin(user);
164
+ return { error: "the login ended before printing a URL" };
165
+ }
166
+ const url = parseSetupTokenUrl(capture(session));
167
+ if (url) {
168
+ f.url = url;
169
+ return { url };
170
+ }
171
+ await sleep(300);
172
+ }
173
+ cancelAgentLogin(user);
174
+ return { error: "the login printed no URL within 30s" };
175
+ }
176
+ /**
177
+ * Submit the pasted code for `user`'s login. Types it into the masked box, waits
178
+ * for it to land, presses Enter, then watches for SUCCESS (a fresh credential
179
+ * file in the user's home) or the invalid-code refusal. The credential is never
180
+ * read for its contents, logged, or returned.
181
+ */
182
+ export async function submitAgentLoginCode(user, code) {
183
+ const session = sessionFor(user);
184
+ const f = flows.get(user);
185
+ if (!f || f.ended || !tmuxHasSession(session))
186
+ return { ok: false, error: "no login is in progress for this user — start one first" };
187
+ const trimmed = code.trim();
188
+ if (!trimmed)
189
+ return { ok: false, error: "empty code" };
190
+ clearTimeout(f.timer);
191
+ f.timer = setTimeout(() => cancelAgentLogin(user), FLOW_IDLE_MS);
192
+ try {
193
+ tmux(["send-keys", "-t", session, "-l", "--", trimmed]);
194
+ }
195
+ catch {
196
+ return { ok: false, error: "the login ended — start a new one and try again" };
197
+ }
198
+ const entered = Date.now() + 4_000;
199
+ while (Date.now() < entered) {
200
+ const line = capture(session).split("\n").find((l) => /Paste code here/i.test(l)) ?? "";
201
+ if (/Paste code here[^>]*>\s*\S/i.test(line))
202
+ break;
203
+ await sleep(200);
204
+ }
205
+ try {
206
+ tmux(["send-keys", "-t", session, "Enter"]);
207
+ }
208
+ catch {
209
+ return { ok: false, error: "the login ended — start a new one and try again" };
210
+ }
211
+ const deadline = Date.now() + 30_000;
212
+ while (Date.now() < deadline) {
213
+ // Success is the credential file appearing (or being rewritten) — a fresh
214
+ // mtime beats the one captured at start. We never read its contents.
215
+ if (credMtime(f.home) > f.priorMtime) {
216
+ cancelAgentLogin(user);
217
+ return { ok: true };
218
+ }
219
+ if (parseSetupTokenOutcome(capture(session)) === "invalid-code") {
220
+ try {
221
+ tmux(["send-keys", "-t", session, "Enter"]); // back to the paste prompt
222
+ }
223
+ catch {
224
+ /* session gone — the next submit reports it */
225
+ }
226
+ return { ok: false, error: "Invalid code. Please make sure the full code was copied." };
227
+ }
228
+ if (!tmuxHasSession(session)) {
229
+ f.ended = true;
230
+ cancelAgentLogin(user);
231
+ // The pane can exit right after writing the credential; re-check the file.
232
+ return credMtime(f.home) > f.priorMtime
233
+ ? { ok: true }
234
+ : { ok: false, error: "the login ended — start a new one and try again" };
235
+ }
236
+ await sleep(300);
237
+ }
238
+ return { ok: false, error: "the login did not complete within 30s" };
239
+ }
240
+ //# sourceMappingURL=agent-login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-login.js","sourceRoot":"","sources":["../src/agent-login.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -77,6 +77,19 @@ export interface Config {
77
77
  * name and palette.
78
78
  */
79
79
  cockpitMuted?: Record<string, boolean>;
80
+ /**
81
+ * Per launch-directory agent auth mode (multi-tenant only), keyed by absolute
82
+ * cwd. `"token"` (default, absent) = the ~1-year `setup-token`
83
+ * (`MT_CLAUDE_OAUTH_TOKEN`) injected into every dropped agent — no claude.ai
84
+ * connectors. `"login"` = no token injection; each OS user (commons `main` +
85
+ * each private group's `sk-*`) does its own interactive `claude auth login`
86
+ * once into its OWN home, so agents get the account's connectors (~1 month,
87
+ * per-user reconnect). Cross-user credential sharing is never used (the refresh
88
+ * rewrite is single-owner, see the design doc); only same-user agents share a
89
+ * login, which they do natively. Takes effect at an agent's next (re)spawn.
90
+ * Design: docs/superpowers/specs/2026-11-04-connectors-via-global-login-design.md
91
+ */
92
+ agentAuth?: Record<string, "token" | "login">;
80
93
  /**
81
94
  * Per launch-directory two-factor sign-in (a passkey after the password),
82
95
  * keyed by absolute cwd. Absent = off. Turned on from the Users panel, under
@@ -128,6 +141,17 @@ export declare function mutedForCwd(cfg: Config, cwd: string): boolean;
128
141
  * removes the entry — the default is "not muted", stored as absent.
129
142
  */
130
143
  export declare function setMutedForCwd(cfg: Config, cwd: string, on: boolean): void;
144
+ /**
145
+ * This instance's agent auth mode: `"login"` only when explicitly set, else
146
+ * `"token"` (the default and today's behaviour). Any unknown value reads as
147
+ * `"token"` — a malformed config never silently switches auth.
148
+ */
149
+ export declare function agentAuthForCwd(cfg: Config, cwd: string): "token" | "login";
150
+ /**
151
+ * Set (or clear) this directory's agent auth mode and persist. `"token"` (the
152
+ * default) removes the entry, so the instance falls back to it.
153
+ */
154
+ export declare function setAgentAuthForCwd(cfg: Config, cwd: string, mode: "token" | "login"): void;
131
155
  /** The model backend chosen for the instance launched in `cwd`, or null. */
132
156
  export declare function backendForCwd(cfg: Config, cwd: string): ConfiguredBackend | null;
133
157
  /** Set (or clear, with null) that backend and persist. */
package/dist/config.js CHANGED
@@ -90,6 +90,26 @@ export function setMutedForCwd(cfg, cwd, on) {
90
90
  delete cfg.cockpitMuted[cwd];
91
91
  saveConfig(cfg);
92
92
  }
93
+ /**
94
+ * This instance's agent auth mode: `"login"` only when explicitly set, else
95
+ * `"token"` (the default and today's behaviour). Any unknown value reads as
96
+ * `"token"` — a malformed config never silently switches auth.
97
+ */
98
+ export function agentAuthForCwd(cfg, cwd) {
99
+ return cfg.agentAuth?.[cwd] === "login" ? "login" : "token";
100
+ }
101
+ /**
102
+ * Set (or clear) this directory's agent auth mode and persist. `"token"` (the
103
+ * default) removes the entry, so the instance falls back to it.
104
+ */
105
+ export function setAgentAuthForCwd(cfg, cwd, mode) {
106
+ cfg.agentAuth ??= {};
107
+ if (mode === "login")
108
+ cfg.agentAuth[cwd] = "login";
109
+ else
110
+ delete cfg.agentAuth[cwd];
111
+ saveConfig(cfg);
112
+ }
93
113
  /** The model backend chosen for the instance launched in `cwd`, or null. */
94
114
  export function backendForCwd(cfg, cwd) {
95
115
  return cfg.modelBackend?.[cwd] ?? null;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -22,6 +22,7 @@ import { PtyPilot } from "./session.js";
22
22
  import { ensureClaudeHome, ensureProjectTrusted, getDefaultModel, setDefaultModel, parseClaudeVersion, seedPlan, settingsPlan, } from "./claude-home.js";
23
23
  import { authStatus, cancelLogin, invalidateAuthStatus, startLogin, submitLoginCode } from "./claude-auth.js";
24
24
  import { startSetupToken, submitSetupTokenCode, cancelSetupToken } from "./setup-token.js";
25
+ import { startAgentLogin, submitAgentLoginCode, cancelAgentLogin, agentLoginPending, agentLoginInfo, } from "./agent-login.js";
25
26
  import { readTokenExpiry } from "./claude-creds.js";
26
27
  import { starCount } from "./stars.js";
27
28
  import { announceFirstAgent, countMainChannels, ensureFirstAgent, firstAgentStatus, settleFirstAgent, } from "./first-agent.js";
@@ -58,7 +59,7 @@ import { ledgerFileFor, scopeVisible, recordIntoTable, saveLedger, mintLedgerId,
58
59
  import { rowKind } from "../context/ledger-skill/ledger-core.mjs";
59
60
  import { linkRefusal, markAgentPrompt, notificationText, } from "./kinship.js";
60
61
  import { talkVerdict, talkLetter } from "./talk.js";
61
- import { loadConfig, saveConfig, telegramConfig, applyTelegramPatch, titleForCwd, setTitleForCwd, themeForCwd, setThemeForCwd, mutedForCwd, setMutedForCwd, twoFactorForCwd, setTwoFactorForCwd, backendForCwd, setBackendForCwd, } from "./config.js";
62
+ import { loadConfig, saveConfig, telegramConfig, applyTelegramPatch, titleForCwd, setTitleForCwd, themeForCwd, setThemeForCwd, mutedForCwd, setMutedForCwd, agentAuthForCwd, setAgentAuthForCwd, twoFactorForCwd, setTwoFactorForCwd, backendForCwd, setBackendForCwd, } from "./config.js";
62
63
  import { secretsFor, secretsForProfile, secretNamesForProfile, secretNames, setSecret, deleteSecret, setSecretSharing, setSecretProfiles, secretWriteVerdict, secretWriteDecision, secretOwnerGroup, visibleSecrets, RESERVED_SECRET_NAMES, MT_CLAUDE_OAUTH_TOKEN_NAME, longLivedTokenInfo, loadVault, recordOrigin, originProfile, } from "./secrets.js";
63
64
  import { recordSecretAudit, readSecretAudit, filterAudit, spawnActor, httpActor, profileSecretDiff, } from "./secret-audit.js";
64
65
  import { getProfile, profileArgs, permissionModeArgs, isPermissionMode, isEffortLevel, mcpServersVerdict, envVarsNote, seedDefaultProfiles, migrateToTracking, seedTweakProfile, loadProfiles, upsertProfile, removeProfile, promptEditVerdict, secretAttachVerdict, READONLY_DENY, TWEAK_PROFILE_NAME, promptOrigin, effectiveProfile, shippedProfile, } from "./profiles.js";
@@ -1756,6 +1757,79 @@ app.delete("/mt-token", (req, res) => {
1756
1757
  cancelSetupToken();
1757
1758
  res.json({ ok: true });
1758
1759
  });
1760
+ // --- Per-user subscription LOGIN ("login" auth mode, src/agent-login.ts) ----
1761
+ // The alternative to the injected token: in "login" mode each OS user (commons
1762
+ // `main` + each private/restricted group's own user) does its own interactive
1763
+ // `claude auth login`, so its agents get the account's claude.ai connectors. A
1764
+ // login is per-user because `claude`'s refresh rewrite is single-owner — it
1765
+ // cannot be shared across OS users (see the connectors-via-global-login design).
1766
+ // Same admin+browser+multi-tenant gate as /mt-token.
1767
+ /** The OS users that each need their own login: commons + every group that has
1768
+ * its own OS user (private/restricted). Deduped; mono-tenant yields none. */
1769
+ function loginUsers() {
1770
+ const out = [];
1771
+ const commons = commonsOsUser({ migrated: groupsMigrated, mode: DEPLOYMENT_MODE });
1772
+ if (commons)
1773
+ out.push({ user: commons, home: agentStateHome(commons), label: "commons" });
1774
+ for (const g of loadGroups()) {
1775
+ const u = osUserFor(g);
1776
+ if (u && !out.some((x) => x.user === u))
1777
+ out.push({ user: u, home: agentStateHome(u), label: g.name || g.id });
1778
+ }
1779
+ return out;
1780
+ }
1781
+ app.get("/agent-login", (req, res) => {
1782
+ if (!mtTokenGate(req, res))
1783
+ return;
1784
+ const mode = agentAuthForCwd(loadConfig(), process.cwd());
1785
+ const users = loginUsers().map(({ user, home, label }) => {
1786
+ const info = agentLoginInfo(home);
1787
+ return { user, label, loggedIn: info.loggedIn, expiresAt: info.expiresAt, pending: agentLoginPending(user) };
1788
+ });
1789
+ res.json({ mode, users });
1790
+ });
1791
+ app.post("/agent-login/mode", (req, res) => {
1792
+ if (!mtTokenGate(req, res))
1793
+ return;
1794
+ const want = req.body?.mode === "login" ? "login" : "token";
1795
+ const cfg = loadConfig();
1796
+ const changed = agentAuthForCwd(cfg, process.cwd()) !== want;
1797
+ setAgentAuthForCwd(cfg, process.cwd(), want);
1798
+ // The auth wiring is a spawn-time decision — restart agents so it lands at once.
1799
+ if (changed)
1800
+ restartAllSessions();
1801
+ res.json({ mode: want, restarted: changed });
1802
+ });
1803
+ app.post("/agent-login/start", async (req, res) => {
1804
+ if (!mtTokenGate(req, res))
1805
+ return;
1806
+ const user = typeof req.body?.user === "string" ? req.body.user : "";
1807
+ const target = loginUsers().find((u) => u.user === user);
1808
+ if (!target)
1809
+ return res.status(400).json({ error: "unknown user" });
1810
+ const r = await startAgentLogin(target.user, target.home);
1811
+ if ("error" in r)
1812
+ return res.status(502).json(r);
1813
+ res.json(r); // {url}
1814
+ });
1815
+ app.post("/agent-login/code", async (req, res) => {
1816
+ if (!mtTokenGate(req, res))
1817
+ return;
1818
+ const user = typeof req.body?.user === "string" ? req.body.user : "";
1819
+ const code = typeof req.body?.code === "string" ? req.body.code : "";
1820
+ if (!loginUsers().some((u) => u.user === user))
1821
+ return res.status(400).json({ error: "unknown user" });
1822
+ const r = await submitAgentLoginCode(user, code);
1823
+ res.status(r.ok ? 200 : 400).json(r); // {ok} — never the credential
1824
+ });
1825
+ app.delete("/agent-login", (req, res) => {
1826
+ if (!mtTokenGate(req, res))
1827
+ return;
1828
+ const user = typeof req.body?.user === "string" ? req.body.user : "";
1829
+ if (user)
1830
+ cancelAgentLogin(user);
1831
+ res.json({ ok: true });
1832
+ });
1759
1833
  // --- Model backend (src/backend.ts) ---------------------------------------
1760
1834
  // The instance-wide source for every agent's backend variables: the backend
1761
1835
  // chosen in the cockpit if any, else shadok's own environment. Read on every
@@ -4932,8 +5006,15 @@ group) {
4932
5006
  ensureAgentSshKey(user, home);
4933
5007
  }
4934
5008
  // Isolated groups share the subscription token, injected in the forced-last
4935
- // env layer. Mono-tenant (no user) reads and passes nothing.
4936
- const oauthToken = user
5009
+ // env layer — but ONLY in "token" auth mode. In "login" mode the server
5010
+ // injects NO token: `CLAUDE_CODE_OAUTH_TOKEN` outranks (and suppresses) a
5011
+ // subscription login, and that login is exactly what carries the claude.ai
5012
+ // connectors this mode exists for. The agent then authenticates from its own
5013
+ // home's `claude auth login` credential (one per OS user; see src/agent-login.ts
5014
+ // and the connectors-via-global-login design). Mono-tenant (no user) passes
5015
+ // nothing either way.
5016
+ const authMode = agentAuthForCwd(loadConfig(), process.cwd());
5017
+ const oauthToken = user && authMode === "token"
4937
5018
  ? secretsFor([MT_CLAUDE_OAUTH_TOKEN_NAME], MAIN_GROUP_ID)[MT_CLAUDE_OAUTH_TOKEN_NAME]
4938
5019
  : undefined;
4939
5020
  return USE_TMUX