nolo-cli 0.6.1 → 0.8.0-alpha.10
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/_executeModel-CPDNUUQV.js +198 -0
- package/action-PAXRPJJF.js +27 -0
- package/addContentAction-CZVWF3QZ.js +25 -0
- package/addDialogAgentAction-CCIDTPHC.js +67 -0
- package/agentDeleteCommand-OSUMJMZM.js +323 -0
- package/agentEmailCommands-OQTJIPQU.js +621 -0
- package/agentListCommands-FATQEUYT.js +219 -0
- package/agentMachineCommands-6LZWF4GL.js +421 -0
- package/agentPullCommand-O2MTUAFR.js +122 -0
- package/agentRecordCommands-TIHFU65Z.js +89 -0
- package/agentRunCommand-R64Y3HCH.js +102 -0
- package/agentRunControl-K4VKNEHF.js +57 -0
- package/agentRuntimeLocal-6PIWAHLQ.js +99 -0
- package/agentSlice-TP4VARJF.js +41 -0
- package/authCommand-WXMD3IPR.js +574 -0
- package/authCommands-X74AFDTC.js +26 -0
- package/chunk-2EISRLRC.js +238 -0
- package/chunk-2FTTDCD4.js +675 -0
- package/chunk-2MALU52L.js +51 -0
- package/chunk-2TPUKEU7.js +1078 -0
- package/chunk-3ASDTTEI.js +1774 -0
- package/chunk-3EUW3WEO.js +8 -0
- package/chunk-3LY4F7SV.js +9293 -0
- package/chunk-4CQLVGRV.js +50 -0
- package/chunk-4IJYA27C.js +342 -0
- package/chunk-4SN6J65J.js +38 -0
- package/chunk-4VNS5WPM.js +42 -0
- package/chunk-572EKYLF.js +792 -0
- package/chunk-5MIDPSSK.js +206 -0
- package/chunk-5MMAK75Q.js +15 -0
- package/chunk-5VV37AT4.js +222 -0
- package/chunk-63W5N6P3.js +150 -0
- package/chunk-6A5EF6IR.js +929 -0
- package/chunk-6HYVJV7B.js +102 -0
- package/chunk-6P2WX5IA.js +3631 -0
- package/chunk-6WD3OOJS.js +20 -0
- package/chunk-ATNTHIZI.js +13 -0
- package/chunk-AUGHVUFE.js +69 -0
- package/chunk-AVMKZHBC.js +85 -0
- package/chunk-AZPCASRE.js +36 -0
- package/chunk-BNMT7YY5.js +34 -0
- package/chunk-BR2WP3DF.js +548 -0
- package/chunk-BSTNFPHD.js +231 -0
- package/chunk-BU4OPIXC.js +171 -0
- package/chunk-CF2WZF4N.js +134 -0
- package/chunk-CF7PE763.js +10 -0
- package/chunk-CKOJQDKR.js +198 -0
- package/chunk-CM54RSSA.js +206 -0
- package/chunk-CWMSB67P.js +34 -0
- package/chunk-DA2OEKS6.js +27 -0
- package/chunk-DFFIZ25G.js +30 -0
- package/chunk-DWLEOOGR.js +8 -0
- package/chunk-DZ3XJVET.js +231 -0
- package/chunk-EHLHSX7R.js +1433 -0
- package/chunk-ELRRLDWI.js +478 -0
- package/chunk-EYEEHCU4.js +3066 -0
- package/chunk-FQZWM5YX.js +628 -0
- package/chunk-G3SUCT4W.js +8 -0
- package/chunk-G5H7RNFL.js +807 -0
- package/chunk-GAKEBQD6.js +30 -0
- package/chunk-GBRG75BQ.js +86 -0
- package/chunk-H2RMRZJE.js +113 -0
- package/chunk-H33743XH.js +25 -0
- package/chunk-HD63YREL.js +19 -0
- package/chunk-HEIIIZBX.js +104 -0
- package/chunk-HNMXYYJR.js +12 -0
- package/chunk-HOMYP7GZ.js +2152 -0
- package/chunk-HZFOMJRA.js +4300 -0
- package/chunk-IAXBCTTE.js +175 -0
- package/chunk-IDZTNRP2.js +85 -0
- package/chunk-IHHA5Y2S.js +9013 -0
- package/chunk-ISNCLGUZ.js +146 -0
- package/chunk-IYQV26RA.js +138 -0
- package/chunk-J4576WMJ.js +91 -0
- package/chunk-JBTJAPUF.js +35 -0
- package/chunk-JZPBVBIY.js +94 -0
- package/chunk-KQHGZWSV.js +63 -0
- package/chunk-KUG52IAP.js +8 -0
- package/chunk-KX6YBIHG.js +8 -0
- package/chunk-LCBAMY2M.js +60 -0
- package/chunk-LM25IZBJ.js +902 -0
- package/chunk-LM6IYQ3F.js +16 -0
- package/chunk-M76ECQRD.js +13658 -0
- package/chunk-MRC4Q34M.js +188 -0
- package/chunk-NEMRK4EK.js +944 -0
- package/chunk-NXZGF7F7.js +2878 -0
- package/chunk-OF5H3QWS.js +300 -0
- package/chunk-OLZBQWZU.js +6 -0
- package/chunk-OOYVBFM7.js +191 -0
- package/chunk-OWOHNGCN.js +50 -0
- package/chunk-PN7AFLOK.js +3401 -0
- package/chunk-POCFIDGQ.js +562 -0
- package/chunk-Q6WACBKB.js +1949 -0
- package/chunk-QFV2OAIM.js +421 -0
- package/chunk-QJ6V2NIN.js +1447 -0
- package/chunk-QSJ3HFEF.js +8 -0
- package/chunk-QUWDTOUP.js +190 -0
- package/chunk-QYXLLLGL.js +4519 -0
- package/chunk-ROWQEJRP.js +139 -0
- package/chunk-S7Z2HMCN.js +25 -0
- package/chunk-TDIQFT2F.js +301 -0
- package/chunk-TILFE6LV.js +381 -0
- package/chunk-TKOUBWBO.js +24674 -0
- package/chunk-TYH5JE6N.js +27158 -0
- package/chunk-U4TRT5V4.js +246 -0
- package/chunk-U6VC4MU4.js +8 -0
- package/chunk-UAD2WT54.js +64 -0
- package/chunk-USZMK5UT.js +105 -0
- package/chunk-VEJLAVTC.js +2052 -0
- package/chunk-VF4K2QE6.js +21 -0
- package/chunk-VHBWHNVT.js +59 -0
- package/chunk-VIDPVFP3.js +20 -0
- package/chunk-VP4WJWKW.js +8882 -0
- package/chunk-VQ2AJRGD.js +148 -0
- package/chunk-W4NVOSFF.js +37 -0
- package/chunk-WWC7I6TA.js +8 -0
- package/chunk-X7W4TNB4.js +1550 -0
- package/chunk-XDVAYP26.js +537 -0
- package/chunk-XKIMRZO2.js +221 -0
- package/chunk-Y5GCAMGP.js +9 -0
- package/chunk-YWPXYBY7.js +360 -0
- package/chunk-Z4NR32XR.js +50 -0
- package/chunk-ZNFJWEN4.js +56 -0
- package/cliExecutor-DNE7TCC4.js +36 -0
- package/clipboardy-BVE3LVEH.js +12001 -0
- package/createAgentAutomationAction-KLKS2HGU.js +864 -0
- package/createDialogAction-Z33JMBF5.js +52 -0
- package/createPageAction-AQVNOAAI.js +169 -0
- package/db-HCJ5PRB5.js +271 -0
- package/dbSlice-C4UJLRZP.js +59 -0
- package/deleteFile-4SKGPHOZ.js +41 -0
- package/dialogCommands-W5PD6MZU.js +59 -0
- package/dialogSlice-RBJYVSAR.js +146 -0
- package/docCreateCommands-MM34S4Z3.js +215 -0
- package/docDeleteCommands-JJTU722V.js +176 -0
- package/docReadCommands-GLYDMCTU.js +129 -0
- package/docStore-5TYME4DO.js +96 -0
- package/docUpdateCommands-ZCGQ7URR.js +313 -0
- package/fetchMessages-JOCYIFKL.js +16 -0
- package/getPricing-PWPJ6MNV.js +30 -0
- package/handleSendMessageAction-KA2MRW6E.js +183 -0
- package/index.js +184 -112254
- package/lib-FYYBQIXS.js +19839 -0
- package/localDialogRead-D3BELSTF.js +26 -0
- package/localFirstLog-DHNOY2NA.js +19 -0
- package/localRuntimeAuthority-TEGCOWX4.js +471 -0
- package/localRuntimeDb-LGDF6FQP.js +12 -0
- package/machineCommands-ZB5WUSPF.js +774 -0
- package/machineInfo-M6KB6HZN.js +10 -0
- package/machineWsRunDispatch-GWCAPPCM.js +105 -0
- package/memoryCommands-O4MIPIWQ.js +476 -0
- package/models-XLEOET3E.js +9 -0
- package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
- package/package.json +3 -25
- package/read-RIJCIVKX.js +17 -0
- package/readDocTool-GZD2N3LO.js +16 -0
- package/readlineWorkspace-FEDY44AA.js +5357 -0
- package/removeDialogAgentAction-CXLST3N6.js +72 -0
- package/runAgentClientLoop-W4NKE64V.js +288 -0
- package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
- package/setDialogExtraReferencesAction-LP6VYGU7.js +59 -0
- package/setPrimaryDialogAgentAction-D3GGH23T.js +79 -0
- package/settingSlice-J4I3Z5H7.js +198 -0
- package/skillSummaryMarker-42HKSXYY.js +9 -0
- package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
- package/slateUtils-2M7MUTWX.js +19 -0
- package/spaceCommands-LC4FDAKE.js +450 -0
- package/spaceSlice-32XOGBEF.js +145 -0
- package/streamAgentChatTurn-YQW32AQH.js +4503 -0
- package/tableCommands-GOFP7QKA.js +1286 -0
- package/toolApiClient-QI3YBNWB.js +26 -0
- package/tools-XGTFRYD7.js +83 -0
- package/understanding-HCSFPE7R.js +318 -0
- package/updateCommands-VOSPKXFF.js +31 -0
- package/updateDialogTitleAction-4LHQDNHQ.js +185 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultOpenBrowser
|
|
3
|
+
} from "./chunk-OF5H3QWS.js";
|
|
4
|
+
import {
|
|
5
|
+
generateCloudflareEmailRoutingToken,
|
|
6
|
+
parseFlagWithOptionalValue,
|
|
7
|
+
runCloudflareOAuthLogin,
|
|
8
|
+
upsertEnvVariable
|
|
9
|
+
} from "./chunk-4IJYA27C.js";
|
|
10
|
+
import {
|
|
11
|
+
generatePkcePair,
|
|
12
|
+
runAntigravityOAuthLogin,
|
|
13
|
+
runCursorOAuthLogin,
|
|
14
|
+
runOpenAiCodexBrowserPkce,
|
|
15
|
+
runOpenAiCodexDeviceCode,
|
|
16
|
+
runXaiOAuthDeviceCode,
|
|
17
|
+
runXaiOAuthLogin,
|
|
18
|
+
startCallbackServer
|
|
19
|
+
} from "./chunk-EHLHSX7R.js";
|
|
20
|
+
import {
|
|
21
|
+
buildEnvFromProfile,
|
|
22
|
+
loadProfileConfig
|
|
23
|
+
} from "./chunk-ROWQEJRP.js";
|
|
24
|
+
import "./chunk-ISNCLGUZ.js";
|
|
25
|
+
import "./chunk-OLZBQWZU.js";
|
|
26
|
+
import {
|
|
27
|
+
createOAuthTokenStore
|
|
28
|
+
} from "./chunk-JZPBVBIY.js";
|
|
29
|
+
import {
|
|
30
|
+
toErrorMessage
|
|
31
|
+
} from "./chunk-HNMXYYJR.js";
|
|
32
|
+
import "./chunk-WWC7I6TA.js";
|
|
33
|
+
import "./chunk-4SN6J65J.js";
|
|
34
|
+
import "./chunk-LCBAMY2M.js";
|
|
35
|
+
import "./chunk-3EUW3WEO.js";
|
|
36
|
+
import "./chunk-CF7PE763.js";
|
|
37
|
+
import "./chunk-G3SUCT4W.js";
|
|
38
|
+
import "./chunk-KUG52IAP.js";
|
|
39
|
+
import "./chunk-4VNS5WPM.js";
|
|
40
|
+
|
|
41
|
+
// packages/cli/oauth/flows/anthropic.ts
|
|
42
|
+
import { randomBytes } from "node:crypto";
|
|
43
|
+
import { createInterface } from "node:readline/promises";
|
|
44
|
+
var ANTHROPIC_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
45
|
+
var ANTHROPIC_OAUTH_AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
46
|
+
var ANTHROPIC_OAUTH_TOKEN_URL = "https://api.anthropic.com/v1/oauth/token";
|
|
47
|
+
var ANTHROPIC_OAUTH_CALLBACK_PORT = 54545;
|
|
48
|
+
var ANTHROPIC_OAUTH_REDIRECT_URI = `http://localhost:${ANTHROPIC_OAUTH_CALLBACK_PORT}/callback`;
|
|
49
|
+
var ANTHROPIC_OAUTH_SCOPES = [
|
|
50
|
+
"org:create_api_key",
|
|
51
|
+
"user:profile",
|
|
52
|
+
"user:inference",
|
|
53
|
+
"user:sessions:claude_code",
|
|
54
|
+
"user:mcp_servers",
|
|
55
|
+
"user:file_upload"
|
|
56
|
+
];
|
|
57
|
+
var ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
|
|
58
|
+
function buildAnthropicAuthorizeUrl(args) {
|
|
59
|
+
const params = new URLSearchParams({
|
|
60
|
+
code: "true",
|
|
61
|
+
client_id: ANTHROPIC_OAUTH_CLIENT_ID,
|
|
62
|
+
response_type: "code",
|
|
63
|
+
redirect_uri: args.redirectUri ?? ANTHROPIC_OAUTH_REDIRECT_URI,
|
|
64
|
+
scope: ANTHROPIC_OAUTH_SCOPES.join(" "),
|
|
65
|
+
code_challenge: args.challenge,
|
|
66
|
+
code_challenge_method: "S256",
|
|
67
|
+
state: args.state
|
|
68
|
+
});
|
|
69
|
+
return `${ANTHROPIC_OAUTH_AUTHORIZE_URL}?${params.toString()}`;
|
|
70
|
+
}
|
|
71
|
+
function parseManualAuthorization(raw, expectedState) {
|
|
72
|
+
const value = raw.trim();
|
|
73
|
+
if (!value) throw new Error("No authorization code was provided.");
|
|
74
|
+
try {
|
|
75
|
+
const url = new URL(value);
|
|
76
|
+
const code2 = url.searchParams.get("code")?.trim();
|
|
77
|
+
const state = url.searchParams.get("state")?.trim();
|
|
78
|
+
if (code2 && state === expectedState) return { code: code2, state };
|
|
79
|
+
throw new Error("Claude OAuth state verification failed.");
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error instanceof Error && error.message.includes("state verification")) {
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const separator = value.lastIndexOf("#");
|
|
86
|
+
if (separator < 0) return { code: value, state: expectedState };
|
|
87
|
+
const code = value.slice(0, separator).trim();
|
|
88
|
+
const returnedState = value.slice(separator + 1).trim();
|
|
89
|
+
if (!code || returnedState !== expectedState) {
|
|
90
|
+
throw new Error("Claude OAuth state verification failed.");
|
|
91
|
+
}
|
|
92
|
+
return { code, state: returnedState };
|
|
93
|
+
}
|
|
94
|
+
function tokenError(payload, status) {
|
|
95
|
+
const detail = typeof payload.error_description === "string" ? payload.error_description : typeof payload.error === "string" ? payload.error : `HTTP ${status}`;
|
|
96
|
+
return `Claude OAuth token exchange failed: ${detail}`;
|
|
97
|
+
}
|
|
98
|
+
async function exchangeAnthropicAuthorizationCode(args) {
|
|
99
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
100
|
+
const response = await fetchImpl(ANTHROPIC_OAUTH_TOKEN_URL, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: { "Content-Type": "application/json" },
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
grant_type: "authorization_code",
|
|
105
|
+
client_id: ANTHROPIC_OAUTH_CLIENT_ID,
|
|
106
|
+
code: args.code,
|
|
107
|
+
state: args.state,
|
|
108
|
+
redirect_uri: args.redirectUri ?? ANTHROPIC_OAUTH_REDIRECT_URI,
|
|
109
|
+
code_verifier: args.verifier
|
|
110
|
+
}),
|
|
111
|
+
signal: AbortSignal.timeout(3e4)
|
|
112
|
+
});
|
|
113
|
+
const payload = await response.json().catch(() => ({}));
|
|
114
|
+
if (!response.ok) throw new Error(tokenError(payload, response.status));
|
|
115
|
+
if (typeof payload.access_token !== "string" || !payload.access_token) {
|
|
116
|
+
throw new Error("Claude OAuth token exchange response missing access_token.");
|
|
117
|
+
}
|
|
118
|
+
const now = args.now?.() ?? Date.now();
|
|
119
|
+
const expiresIn = typeof payload.expires_in === "number" && Number.isFinite(payload.expires_in) ? payload.expires_in : void 0;
|
|
120
|
+
const accountId = typeof payload.account?.uuid === "string" ? payload.account.uuid : void 0;
|
|
121
|
+
const email = typeof payload.account?.email_address === "string" ? payload.account.email_address : void 0;
|
|
122
|
+
const organizationId = typeof payload.organization?.uuid === "string" ? payload.organization.uuid : void 0;
|
|
123
|
+
const organizationName = typeof payload.organization?.name === "string" ? payload.organization.name : void 0;
|
|
124
|
+
return {
|
|
125
|
+
provider: "claude",
|
|
126
|
+
accessToken: payload.access_token,
|
|
127
|
+
...typeof payload.refresh_token === "string" && payload.refresh_token ? { refreshToken: payload.refresh_token } : {},
|
|
128
|
+
...expiresIn !== void 0 ? { expiresAt: now + expiresIn * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS } : {},
|
|
129
|
+
...typeof payload.scope === "string" ? { scope: payload.scope } : {},
|
|
130
|
+
...accountId ? { accountId } : {},
|
|
131
|
+
...email || organizationId || organizationName ? { metadata: { email, organizationId, organizationName } } : {},
|
|
132
|
+
obtainedAt: now
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async function defaultReadLine(prompt) {
|
|
136
|
+
const terminal = createInterface({ input: process.stdin, output: process.stdout });
|
|
137
|
+
try {
|
|
138
|
+
return await terminal.question(prompt);
|
|
139
|
+
} finally {
|
|
140
|
+
terminal.close();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function runAnthropicOAuthLogin(deps = {}) {
|
|
144
|
+
const output = deps.output ?? console;
|
|
145
|
+
const error = deps.error ?? console;
|
|
146
|
+
const state = randomBytes(24).toString("base64url");
|
|
147
|
+
const pkce = generatePkcePair();
|
|
148
|
+
const preferredCallbackPort = deps.callbackPort ?? ANTHROPIC_OAUTH_CALLBACK_PORT;
|
|
149
|
+
const callbackServerFactory = deps.callbackServerFactory ?? startCallbackServer;
|
|
150
|
+
const callback = deps.manualCode ? null : await callbackServerFactory({
|
|
151
|
+
port: preferredCallbackPort,
|
|
152
|
+
hostname: "127.0.0.1",
|
|
153
|
+
timeoutMs: 5 * 6e4,
|
|
154
|
+
fallbackToRandomPort: true
|
|
155
|
+
});
|
|
156
|
+
const redirectUri = callback ? `http://localhost:${callback.port}/callback` : `http://localhost:${preferredCallbackPort}/callback`;
|
|
157
|
+
const authUrl = buildAnthropicAuthorizeUrl({
|
|
158
|
+
state,
|
|
159
|
+
challenge: pkce.challenge,
|
|
160
|
+
redirectUri
|
|
161
|
+
});
|
|
162
|
+
output.log(
|
|
163
|
+
`Open this URL to authorize Claude Pro/Max:
|
|
164
|
+
${authUrl}`
|
|
165
|
+
);
|
|
166
|
+
if (callback && callback.port !== preferredCallbackPort) {
|
|
167
|
+
output.log(
|
|
168
|
+
`Port ${preferredCallbackPort} is busy; using callback port ${callback.port}.`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (deps.openBrowser) {
|
|
172
|
+
try {
|
|
173
|
+
await deps.openBrowser(authUrl);
|
|
174
|
+
} catch (cause) {
|
|
175
|
+
error.error(`Could not open the browser automatically: ${String(cause)}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
let code = "";
|
|
179
|
+
let returnedState = state;
|
|
180
|
+
if (deps.manualCode) {
|
|
181
|
+
const raw = await (deps.readLine ?? defaultReadLine)(
|
|
182
|
+
"Paste the final callback URL or authorization code: "
|
|
183
|
+
);
|
|
184
|
+
({ code, state: returnedState } = parseManualAuthorization(raw, state));
|
|
185
|
+
} else {
|
|
186
|
+
if (!callback) throw new Error("Claude OAuth callback server did not start.");
|
|
187
|
+
try {
|
|
188
|
+
const result = await callback.waitForCode();
|
|
189
|
+
if (result.state !== state) {
|
|
190
|
+
throw new Error("Claude OAuth state verification failed.");
|
|
191
|
+
}
|
|
192
|
+
code = result.code;
|
|
193
|
+
returnedState = result.state;
|
|
194
|
+
} finally {
|
|
195
|
+
await callback.close().catch(() => void 0);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return exchangeAnthropicAuthorizationCode({
|
|
199
|
+
code,
|
|
200
|
+
state: returnedState,
|
|
201
|
+
verifier: pkce.verifier,
|
|
202
|
+
redirectUri,
|
|
203
|
+
...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {},
|
|
204
|
+
...deps.now ? { now: deps.now } : {}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// packages/cli/oauth/authCommand.ts
|
|
209
|
+
var SYNC_HELP_LINE = ` --sync-to-server After local save, push the credential to your nolo server.
|
|
210
|
+
--sync-only Push ~/.nolo/credentials/<provider>.json to the server without re-login.`;
|
|
211
|
+
var CHATGPT_HELP_TEXT = `Authorize nolo-cli to call the OpenAI Codex / ChatGPT Plus API on your behalf.
|
|
212
|
+
|
|
213
|
+
This authorizes model API access only. It does NOT log you into the Nolo platform.
|
|
214
|
+
To manage agents, docs, spaces, and other Nolo resources, run "nolo login" first.
|
|
215
|
+
|
|
216
|
+
Usage:
|
|
217
|
+
nolo auth chatgpt [--browser] [--no-browser] [--sync-to-server] [--help]
|
|
218
|
+
|
|
219
|
+
Options:
|
|
220
|
+
--browser Use the local browser PKCE flow instead of the device-code flow.
|
|
221
|
+
--no-browser Print the authorization URL only (device-code flow).
|
|
222
|
+
${SYNC_HELP_LINE}
|
|
223
|
+
--help, -h Show this help and exit.
|
|
224
|
+
|
|
225
|
+
The default flow is device-code, which works headless: open the printed URL on any
|
|
226
|
+
machine with a browser where you are already logged into ChatGPT. After approval, the
|
|
227
|
+
access and refresh tokens are stored in ~/.nolo/credentials/chatgpt.json.
|
|
228
|
+
|
|
229
|
+
Agents can reference the stored token by setting apiKeyRef: "chatgpt" with
|
|
230
|
+
apiSource: "custom" and provider: "openai".
|
|
231
|
+
`;
|
|
232
|
+
var XAI_HELP_TEXT = `Authorize nolo-cli to call the xAI Grok API via your SuperGrok subscription.
|
|
233
|
+
|
|
234
|
+
This authorizes model API access only. It does NOT log you into the Nolo platform.
|
|
235
|
+
To manage agents, docs, spaces, and other Nolo resources, run "nolo login" first.
|
|
236
|
+
|
|
237
|
+
Usage:
|
|
238
|
+
nolo auth xai [--browser] [--device-code] [--no-browser] [--sync-to-server] [--help]
|
|
239
|
+
|
|
240
|
+
Default (interactive desktop): OIDC PKCE loopback on 127.0.0.1:56121.
|
|
241
|
+
Headless / SSH / Docker: use --device-code or --no-browser (RFC 8628 device
|
|
242
|
+
authorization; no localhost callback). After approval, tokens are stored in
|
|
243
|
+
~/.nolo/credentials/xai.json.
|
|
244
|
+
|
|
245
|
+
The OAuth client_id is the same fixed value used by NousResearch/hermes-agent
|
|
246
|
+
(MIT), oh-my-pi, and OpenClaw; xAI does not publish a public client registration flow.
|
|
247
|
+
|
|
248
|
+
Options:
|
|
249
|
+
--browser Use the browser PKCE loopback flow (default for xAI).
|
|
250
|
+
--device-code Use RFC 8628 device authorization (headless-friendly).
|
|
251
|
+
--no-browser Same as --device-code for xAI (no loopback listener).
|
|
252
|
+
${SYNC_HELP_LINE}
|
|
253
|
+
--help, -h Show this help and exit.
|
|
254
|
+
|
|
255
|
+
Agents can reference the stored token by setting apiKeyRef: "xai" with
|
|
256
|
+
apiSource: "custom" and provider: "xai".
|
|
257
|
+
`;
|
|
258
|
+
var ANTIGRAVITY_HELP_TEXT = `Authorize nolo-cli to call Google Antigravity (Gemini 3, Claude, GPT-OSS) via your Google account.
|
|
259
|
+
|
|
260
|
+
This authorizes model API access only. It does NOT log you into the Nolo platform.
|
|
261
|
+
To manage agents, docs, spaces, and other Nolo resources, run "nolo login" first.
|
|
262
|
+
|
|
263
|
+
Usage:
|
|
264
|
+
nolo auth antigravity [--browser] [--no-browser] [--sync-to-server] [--help]
|
|
265
|
+
|
|
266
|
+
Opens a browser to https://accounts.google.com (OIDC PKCE loopback on 127.0.0.1:51121).
|
|
267
|
+
After approval, the flow provisions a Cloud Code Assist project and stores the
|
|
268
|
+
access and refresh tokens in ~/.nolo/credentials/antigravity.json.
|
|
269
|
+
|
|
270
|
+
The OAuth client_id/secret are the same base64-decoded values used by
|
|
271
|
+
oh-my-pi; Google does not publish a public Cloud Code Assist client registration.
|
|
272
|
+
|
|
273
|
+
Options:
|
|
274
|
+
--browser Use the browser PKCE flow (default for antigravity).
|
|
275
|
+
--no-browser Print the authorization URL only.
|
|
276
|
+
${SYNC_HELP_LINE}
|
|
277
|
+
--help, -h Show this help and exit.
|
|
278
|
+
|
|
279
|
+
Agents can reference the stored token by setting apiKeyRef: "antigravity" with
|
|
280
|
+
apiSource: "custom" and provider: "google-antigravity".
|
|
281
|
+
`;
|
|
282
|
+
var CLAUDE_HELP_TEXT = `Authorize nolo-cli to call Anthropic Claude with your Claude Pro/Max subscription.
|
|
283
|
+
|
|
284
|
+
This authorizes model API access only. It does NOT log you into the Nolo platform.
|
|
285
|
+
To manage agents, docs, spaces, and other Nolo resources, run "nolo login" first.
|
|
286
|
+
|
|
287
|
+
Usage:
|
|
288
|
+
nolo auth claude [--browser] [--no-browser] [--sync-to-server] [--help]
|
|
289
|
+
|
|
290
|
+
The default flow returns to a loopback callback on localhost:54545. With
|
|
291
|
+
--no-browser, paste the final callback URL or authorization code into the
|
|
292
|
+
terminal. Tokens are stored in ~/.nolo/credentials/claude.json.
|
|
293
|
+
|
|
294
|
+
Options:
|
|
295
|
+
--browser Open the Anthropic authorization page (default).
|
|
296
|
+
--no-browser Print the authorization URL without opening a browser.
|
|
297
|
+
${SYNC_HELP_LINE}
|
|
298
|
+
--help, -h Show this help and exit.
|
|
299
|
+
|
|
300
|
+
Agents can reference the stored token with apiKeyRef: "claude", provider:
|
|
301
|
+
"anthropic", and model such as "claude-sonnet-5".
|
|
302
|
+
`;
|
|
303
|
+
var CURSOR_HELP_TEXT = `Authorize nolo-cli to call Cursor models via your Cursor Pro subscription.
|
|
304
|
+
|
|
305
|
+
This authorizes model API access only. It does NOT log you into the Nolo
|
|
306
|
+
platform. To manage agents, docs, spaces, and other Nolo resources, run
|
|
307
|
+
"nolo login" first.
|
|
308
|
+
|
|
309
|
+
Usage: nolo auth cursor [--no-browser] [--sync-to-server] [--help]
|
|
310
|
+
|
|
311
|
+
The flow opens https://cursor.com/loginDeepControl in your browser and polls
|
|
312
|
+
https://api2.cursor.sh/auth/poll until you approve. There is no loopback
|
|
313
|
+
callback \u2014 this is a poll-based device flow, so it works in headless / SSH /
|
|
314
|
+
Docker environments too.
|
|
315
|
+
|
|
316
|
+
After approval, tokens are stored in ~/.nolo/credentials/cursor.json.
|
|
317
|
+
Agents can reference the stored token with apiKeyRef: "cursor".
|
|
318
|
+
|
|
319
|
+
Options:
|
|
320
|
+
--no-browser Print the authorization URL without opening a browser.
|
|
321
|
+
${SYNC_HELP_LINE}
|
|
322
|
+
--help, -h Show this help and exit.
|
|
323
|
+
`;
|
|
324
|
+
var CLOUDFLARE_HELP_TEXT = `Authorize nolo-cli to manage Cloudflare resources on your behalf.
|
|
325
|
+
|
|
326
|
+
This authorizes Cloudflare API access only. It does NOT log you into the Nolo platform.
|
|
327
|
+
To manage agents, docs, spaces, and other Nolo resources, run "nolo login" first.
|
|
328
|
+
|
|
329
|
+
Usage:
|
|
330
|
+
nolo auth cloudflare [--client-id <id>] [--scope <scopes>] [--generate-token] [--zone-name <domain>] [--token-name <label>] [--browser] [--no-browser] [--sync-to-server] [--help]
|
|
331
|
+
|
|
332
|
+
Opens a browser to https://dash.cloudflare.com (OAuth 2.0 PKCE loopback on
|
|
333
|
+
127.0.0.1:56122). After approval, the OAuth access token is stored locally in
|
|
334
|
+
~/.nolo/credentials/cloudflare.json.
|
|
335
|
+
|
|
336
|
+
To use this flow you must first create a Cloudflare OAuth client in the
|
|
337
|
+
Cloudflare Dashboard (Manage Account > OAuth clients) and obtain a client_id.
|
|
338
|
+
You can also create the client via the Cloudflare API:
|
|
339
|
+
POST /accounts/{account_id}/oauth_clients
|
|
340
|
+
|
|
341
|
+
Set the client ID via the environment variable:
|
|
342
|
+
CLOUDFLARE_OAUTH_CLIENT_ID
|
|
343
|
+
|
|
344
|
+
Override requested scopes via:
|
|
345
|
+
CLOUDFLARE_OAUTH_SCOPE
|
|
346
|
+
|
|
347
|
+
Default scopes: account:read zone:read zone:edit user:read user:edit
|
|
348
|
+
|
|
349
|
+
With --generate-token, the command will also use the OAuth access token to
|
|
350
|
+
programmatically create a long-lived Cloudflare API token scoped to the
|
|
351
|
+
specified zone with the Email Routing Edit permission.
|
|
352
|
+
|
|
353
|
+
Options:
|
|
354
|
+
--client-id <id> Use this OAuth client ID for this run.
|
|
355
|
+
--scope <scopes> Space-separated scopes (overrides env var for this run).
|
|
356
|
+
--generate-token Also create a Zone:Email Routing:Edit API token.
|
|
357
|
+
--zone-name <domain> Zone domain for token generation (default: nolo.chat).
|
|
358
|
+
--token-name <label> Name for the generated API token.
|
|
359
|
+
--write-to-env [path] Append or update CLOUDFLARE_EMAIL_ROUTING_API_TOKEN in the env file (default: .env).
|
|
360
|
+
--browser Use the browser PKCE flow (default for cloudflare).
|
|
361
|
+
--no-browser Print the authorization URL only.
|
|
362
|
+
${SYNC_HELP_LINE}
|
|
363
|
+
--help, -h Show this help and exit.
|
|
364
|
+
`;
|
|
365
|
+
var HELP_BY_PROVIDER = {
|
|
366
|
+
chatgpt: CHATGPT_HELP_TEXT,
|
|
367
|
+
xai: XAI_HELP_TEXT,
|
|
368
|
+
antigravity: ANTIGRAVITY_HELP_TEXT,
|
|
369
|
+
claude: CLAUDE_HELP_TEXT,
|
|
370
|
+
cloudflare: CLOUDFLARE_HELP_TEXT,
|
|
371
|
+
cursor: CURSOR_HELP_TEXT
|
|
372
|
+
};
|
|
373
|
+
function resolveServerSyncConfig() {
|
|
374
|
+
const envServer = process.env.NOLO_SERVER?.trim() || process.env.NOLO_SERVER_URL?.trim() || process.env.BASE_URL?.trim() || "";
|
|
375
|
+
const envToken = process.env.AUTH_TOKEN?.trim() || process.env.NOLO_AUTH_TOKEN?.trim() || "";
|
|
376
|
+
if (envServer && envToken) {
|
|
377
|
+
return { serverOrigin: envServer.replace(/\/+$/, ""), authToken: envToken };
|
|
378
|
+
}
|
|
379
|
+
let profileServer = "";
|
|
380
|
+
let profileToken = "";
|
|
381
|
+
try {
|
|
382
|
+
const config = loadProfileConfig();
|
|
383
|
+
const profileEnv = buildEnvFromProfile(config);
|
|
384
|
+
profileServer = profileEnv.NOLO_SERVER?.trim() || "";
|
|
385
|
+
profileToken = profileEnv.AUTH_TOKEN?.trim() || "";
|
|
386
|
+
} catch {
|
|
387
|
+
}
|
|
388
|
+
const serverOrigin = (envServer || profileServer).replace(/\/+$/, "");
|
|
389
|
+
const authToken = envToken || profileToken;
|
|
390
|
+
if (serverOrigin && authToken) {
|
|
391
|
+
return { serverOrigin, authToken };
|
|
392
|
+
}
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
async function syncCredentialToServer(provider, credential, deps) {
|
|
396
|
+
const output = deps.output ?? console;
|
|
397
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
398
|
+
const syncConfig = (deps.resolveServerSyncConfig ?? resolveServerSyncConfig)();
|
|
399
|
+
if (!syncConfig) {
|
|
400
|
+
output.log(
|
|
401
|
+
`[nolo] Warning: --sync-to-server requires NOLO_SERVER and AUTH_TOKEN env vars, or a configured profile. Skipping server sync.`
|
|
402
|
+
);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const { serverOrigin, authToken } = syncConfig;
|
|
406
|
+
const url = `${serverOrigin}/api/oauth/${provider}/sync`;
|
|
407
|
+
try {
|
|
408
|
+
const res = await fetchImpl(url, {
|
|
409
|
+
method: "POST",
|
|
410
|
+
headers: {
|
|
411
|
+
"Content-Type": "application/json",
|
|
412
|
+
Authorization: `Bearer ${authToken}`
|
|
413
|
+
},
|
|
414
|
+
body: JSON.stringify({
|
|
415
|
+
accessToken: credential.accessToken,
|
|
416
|
+
refreshToken: credential.refreshToken,
|
|
417
|
+
expiresAt: credential.expiresAt,
|
|
418
|
+
scope: credential.scope,
|
|
419
|
+
idToken: credential.idToken,
|
|
420
|
+
accountId: credential.accountId,
|
|
421
|
+
email: credential.metadata?.email,
|
|
422
|
+
metadata: credential.metadata
|
|
423
|
+
})
|
|
424
|
+
});
|
|
425
|
+
if (res.ok) {
|
|
426
|
+
output.log(`[nolo] Synced to ${serverOrigin}`);
|
|
427
|
+
} else {
|
|
428
|
+
let errorDetail = "";
|
|
429
|
+
try {
|
|
430
|
+
const body = await res.json();
|
|
431
|
+
errorDetail = body?.error || "";
|
|
432
|
+
} catch {
|
|
433
|
+
}
|
|
434
|
+
output.log(
|
|
435
|
+
`[nolo] Warning: server sync failed (${res.status}${errorDetail ? `: ${errorDetail}` : ""}). Token saved locally.`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
} catch (err) {
|
|
439
|
+
output.log(
|
|
440
|
+
`[nolo] Warning: server sync failed (${err?.message ?? "network error"}). Token saved locally.`
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async function runAuthProviderCommand(provider, args, _ctx, deps = {}) {
|
|
445
|
+
const output = deps.output ?? console;
|
|
446
|
+
const error = deps.error ?? console;
|
|
447
|
+
const tokenStore = deps.tokenStore ?? createOAuthTokenStore();
|
|
448
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
449
|
+
output.log(HELP_BY_PROVIDER[provider]);
|
|
450
|
+
return 0;
|
|
451
|
+
}
|
|
452
|
+
const useBrowser = args.includes("--browser");
|
|
453
|
+
const noBrowser = args.includes("--no-browser") || deps.noBrowserByDefault;
|
|
454
|
+
const syncOnly = args.includes("--sync-only");
|
|
455
|
+
const syncToServer = args.includes("--sync-to-server") || syncOnly;
|
|
456
|
+
const generateToken = args.includes("--generate-token");
|
|
457
|
+
const writeToEnvRaw = parseFlagWithOptionalValue(args, "--write-to-env");
|
|
458
|
+
const writeToEnvPath = typeof writeToEnvRaw === "string" ? writeToEnvRaw : writeToEnvRaw === true ? ".env" : void 0;
|
|
459
|
+
const openBrowser = noBrowser ? void 0 : deps.openBrowser ?? defaultOpenBrowser;
|
|
460
|
+
if (syncOnly) {
|
|
461
|
+
const credential = tokenStore.read(provider);
|
|
462
|
+
if (!credential) {
|
|
463
|
+
error.error(
|
|
464
|
+
`[nolo] No local ${provider} credential. Run: nolo auth ${provider}`
|
|
465
|
+
);
|
|
466
|
+
return 1;
|
|
467
|
+
}
|
|
468
|
+
await syncCredentialToServer(provider, credential, deps);
|
|
469
|
+
return 0;
|
|
470
|
+
}
|
|
471
|
+
const flowDeps = {
|
|
472
|
+
...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {},
|
|
473
|
+
...deps.sleep ? { sleep: deps.sleep } : {},
|
|
474
|
+
...deps.now ? { now: deps.now } : {},
|
|
475
|
+
...deps.readLine ? { readLine: deps.readLine } : {},
|
|
476
|
+
...noBrowser ? { manualCode: true } : {},
|
|
477
|
+
openBrowser,
|
|
478
|
+
output,
|
|
479
|
+
error
|
|
480
|
+
};
|
|
481
|
+
const clientIdFlag = args.find((arg, index) => arg === "--client-id" && index + 1 < args.length) ? args[args.indexOf("--client-id") + 1] : void 0;
|
|
482
|
+
const scopeFlag = args.find((arg, index) => arg === "--scope" && index + 1 < args.length) ? args[args.indexOf("--scope") + 1] : void 0;
|
|
483
|
+
const zoneNameFlag = args.find((arg, index) => arg === "--zone-name" && index + 1 < args.length) ? args[args.indexOf("--zone-name") + 1] : void 0;
|
|
484
|
+
const tokenNameFlag = args.find((arg, index) => arg === "--token-name" && index + 1 < args.length) ? args[args.indexOf("--token-name") + 1] : void 0;
|
|
485
|
+
try {
|
|
486
|
+
let credential;
|
|
487
|
+
if (provider === "chatgpt") {
|
|
488
|
+
credential = useBrowser ? await runOpenAiCodexBrowserPkce(flowDeps) : await runOpenAiCodexDeviceCode(flowDeps);
|
|
489
|
+
} else if (provider === "xai") {
|
|
490
|
+
const useDeviceCode = !useBrowser && (args.includes("--device-code") || noBrowser);
|
|
491
|
+
credential = useDeviceCode ? await runXaiOAuthDeviceCode(flowDeps) : await runXaiOAuthLogin(flowDeps);
|
|
492
|
+
} else if (provider === "claude") {
|
|
493
|
+
credential = await runAnthropicOAuthLogin(flowDeps);
|
|
494
|
+
} else if (provider === "cursor") {
|
|
495
|
+
credential = await runCursorOAuthLogin(flowDeps);
|
|
496
|
+
} else if (provider === "cloudflare") {
|
|
497
|
+
credential = await runCloudflareOAuthLogin({
|
|
498
|
+
...flowDeps,
|
|
499
|
+
...clientIdFlag ? { clientId: clientIdFlag } : {},
|
|
500
|
+
...scopeFlag ? { scope: scopeFlag } : {}
|
|
501
|
+
});
|
|
502
|
+
if (generateToken) {
|
|
503
|
+
const zoneName = zoneNameFlag ?? process.env.CLOUDFLARE_ZONE_NAME ?? "nolo.chat";
|
|
504
|
+
const tokenName = tokenNameFlag ?? `nolo-email-routing-${zoneName}`;
|
|
505
|
+
const { token, zoneId } = await generateCloudflareEmailRoutingToken({
|
|
506
|
+
accessToken: credential.accessToken,
|
|
507
|
+
zoneName,
|
|
508
|
+
tokenName,
|
|
509
|
+
fetchImpl: deps.fetchImpl ?? fetch
|
|
510
|
+
});
|
|
511
|
+
output.log(
|
|
512
|
+
`[nolo] Generated Cloudflare API token for zone ${zoneName} (${zoneId}).
|
|
513
|
+
Store it as CLOUDFLARE_EMAIL_ROUTING_API_TOKEN:
|
|
514
|
+
${token}
|
|
515
|
+
`
|
|
516
|
+
);
|
|
517
|
+
if (writeToEnvPath) {
|
|
518
|
+
upsertEnvVariable(
|
|
519
|
+
writeToEnvPath,
|
|
520
|
+
"CLOUDFLARE_EMAIL_ROUTING_API_TOKEN",
|
|
521
|
+
token
|
|
522
|
+
);
|
|
523
|
+
output.log(
|
|
524
|
+
`[nolo] Updated ${writeToEnvPath} with CLOUDFLARE_EMAIL_ROUTING_API_TOKEN.`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
} else {
|
|
529
|
+
credential = await runAntigravityOAuthLogin(flowDeps);
|
|
530
|
+
}
|
|
531
|
+
tokenStore.write(provider, credential);
|
|
532
|
+
const accountLabel = credential.metadata?.email ?? credential.accountId ?? "";
|
|
533
|
+
output.log(
|
|
534
|
+
`[nolo] ${provider} authorization saved` + (accountLabel ? ` for ${accountLabel}` : "") + `.`
|
|
535
|
+
);
|
|
536
|
+
if (syncToServer) {
|
|
537
|
+
await syncCredentialToServer(provider, credential, deps);
|
|
538
|
+
}
|
|
539
|
+
return 0;
|
|
540
|
+
} catch (err) {
|
|
541
|
+
error.error(
|
|
542
|
+
`nolo auth ${provider} failed: ${toErrorMessage(err)}`
|
|
543
|
+
);
|
|
544
|
+
return 1;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async function runAuthChatgptCommand(args, ctx, deps) {
|
|
548
|
+
return runAuthProviderCommand("chatgpt", args, ctx, deps);
|
|
549
|
+
}
|
|
550
|
+
async function runAuthXaiCommand(args, ctx, deps) {
|
|
551
|
+
return runAuthProviderCommand("xai", args, ctx, deps);
|
|
552
|
+
}
|
|
553
|
+
async function runAuthAntigravityCommand(args, ctx, deps) {
|
|
554
|
+
return runAuthProviderCommand("antigravity", args, ctx, deps);
|
|
555
|
+
}
|
|
556
|
+
async function runAuthCloudflareCommand(args, ctx, deps) {
|
|
557
|
+
return runAuthProviderCommand("cloudflare", args, ctx, deps);
|
|
558
|
+
}
|
|
559
|
+
async function runAuthClaudeCommand(args, ctx, deps) {
|
|
560
|
+
return runAuthProviderCommand("claude", args, ctx, deps);
|
|
561
|
+
}
|
|
562
|
+
async function runAuthCursorCommand(args, ctx, deps) {
|
|
563
|
+
return runAuthProviderCommand("cursor", args, ctx, deps);
|
|
564
|
+
}
|
|
565
|
+
export {
|
|
566
|
+
resolveServerSyncConfig,
|
|
567
|
+
runAuthAntigravityCommand,
|
|
568
|
+
runAuthChatgptCommand,
|
|
569
|
+
runAuthClaudeCommand,
|
|
570
|
+
runAuthCloudflareCommand,
|
|
571
|
+
runAuthCursorCommand,
|
|
572
|
+
runAuthProviderCommand,
|
|
573
|
+
runAuthXaiCommand
|
|
574
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LOGIN_HELP_TEXT,
|
|
3
|
+
LOGOUT_HELP_TEXT,
|
|
4
|
+
WHOAMI_HELP_TEXT,
|
|
5
|
+
defaultOpenBrowser,
|
|
6
|
+
runLoginCommand,
|
|
7
|
+
runLogoutCommand,
|
|
8
|
+
runWhoamiCommand
|
|
9
|
+
} from "./chunk-OF5H3QWS.js";
|
|
10
|
+
import "./chunk-ROWQEJRP.js";
|
|
11
|
+
import "./chunk-ISNCLGUZ.js";
|
|
12
|
+
import "./chunk-OLZBQWZU.js";
|
|
13
|
+
import "./chunk-4SN6J65J.js";
|
|
14
|
+
import "./chunk-LCBAMY2M.js";
|
|
15
|
+
import "./chunk-CF7PE763.js";
|
|
16
|
+
import "./chunk-G3SUCT4W.js";
|
|
17
|
+
import "./chunk-4VNS5WPM.js";
|
|
18
|
+
export {
|
|
19
|
+
LOGIN_HELP_TEXT,
|
|
20
|
+
LOGOUT_HELP_TEXT,
|
|
21
|
+
WHOAMI_HELP_TEXT,
|
|
22
|
+
defaultOpenBrowser,
|
|
23
|
+
runLoginCommand,
|
|
24
|
+
runLogoutCommand,
|
|
25
|
+
runWhoamiCommand
|
|
26
|
+
};
|