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 +14 -0
- package/dist/agent-login.d.ts +36 -0
- package/dist/agent-login.js +240 -0
- package/dist/agent-login.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +20 -0
- package/dist/config.js.map +1 -1
- package/dist/server.js +84 -3
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +143 -0
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;
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
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
|
|
4936
|
-
|
|
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
|