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,300 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildCliRuntimeEnv,
|
|
3
|
+
clearProfileAuthToken,
|
|
4
|
+
getCurrentProfile,
|
|
5
|
+
getDefaultProfileConfigPath,
|
|
6
|
+
loadProfileConfig,
|
|
7
|
+
saveDefaultProfile
|
|
8
|
+
} from "./chunk-ROWQEJRP.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveAuthTokenFromEnv
|
|
11
|
+
} from "./chunk-ISNCLGUZ.js";
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_NOLO_SERVER_URL
|
|
14
|
+
} from "./chunk-OLZBQWZU.js";
|
|
15
|
+
import {
|
|
16
|
+
normalizeServerOrigin
|
|
17
|
+
} from "./chunk-CF7PE763.js";
|
|
18
|
+
|
|
19
|
+
// packages/cli/authCommands.ts
|
|
20
|
+
import { createInterface } from "node:readline/promises";
|
|
21
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
22
|
+
import { spawn } from "node:child_process";
|
|
23
|
+
var LOGIN_HELP_TEXT = `Log in to Nolo and save a local profile.
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
nolo login [--server <url>] [--no-browser] [--token <jwt>] [--manual]
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
--server <url> Nolo server URL (default: ${DEFAULT_NOLO_SERVER_URL})
|
|
30
|
+
--no-browser Print the authorization URL instead of opening a browser
|
|
31
|
+
--token <jwt> Save a token directly without browser authorization
|
|
32
|
+
--manual Prompt to paste a token interactively
|
|
33
|
+
|
|
34
|
+
By default, opens the Nolo website and polls until authorization completes.
|
|
35
|
+
In SSH sessions, use --no-browser and open the printed URL on a machine with a browser
|
|
36
|
+
where you are already logged into Nolo.
|
|
37
|
+
|
|
38
|
+
Note: nolo login only authorizes your Nolo platform account. To let your agents
|
|
39
|
+
call third-party models using your own subscriptions, you also need:
|
|
40
|
+
nolo auth antigravity # Google Antigravity (Gemini 3, Claude, GPT-OSS)
|
|
41
|
+
nolo auth claude # Claude Pro/Max
|
|
42
|
+
nolo auth chatgpt # ChatGPT Plus / OpenAI Codex
|
|
43
|
+
nolo auth xai # xAI Grok (SuperGrok)
|
|
44
|
+
nolo auth cloudflare # Cloudflare OAuth (email routing, etc.)
|
|
45
|
+
See "nolo auth <provider> --help" for details.
|
|
46
|
+
`;
|
|
47
|
+
var LOGOUT_HELP_TEXT = `Log out of Nolo by clearing the saved auth token.
|
|
48
|
+
|
|
49
|
+
Usage:
|
|
50
|
+
nolo logout
|
|
51
|
+
|
|
52
|
+
Keeps other profile settings such as server URL and default agent preferences.
|
|
53
|
+
Does not unset AUTH_TOKEN or other auth-related environment variables.
|
|
54
|
+
`;
|
|
55
|
+
var WHOAMI_HELP_TEXT = `Show the current login state.
|
|
56
|
+
|
|
57
|
+
Usage:
|
|
58
|
+
nolo whoami
|
|
59
|
+
`;
|
|
60
|
+
function wantsHelp(args) {
|
|
61
|
+
return args.includes("--help") || args.includes("-h");
|
|
62
|
+
}
|
|
63
|
+
function formatDuration(ms) {
|
|
64
|
+
const totalSec = Math.max(0, Math.ceil(ms / 1e3));
|
|
65
|
+
const minutes = Math.floor(totalSec / 60);
|
|
66
|
+
const seconds = totalSec % 60;
|
|
67
|
+
if (minutes > 0) return `${minutes}m ${seconds}s`;
|
|
68
|
+
return `${seconds}s`;
|
|
69
|
+
}
|
|
70
|
+
function formatTokenPreview(token) {
|
|
71
|
+
const trimmed = token.trim();
|
|
72
|
+
if (!trimmed) return "";
|
|
73
|
+
return `${trimmed.slice(0, 8)}...`;
|
|
74
|
+
}
|
|
75
|
+
function getArg(args, flag) {
|
|
76
|
+
const index = args.indexOf(flag);
|
|
77
|
+
return index >= 0 ? args[index + 1] : void 0;
|
|
78
|
+
}
|
|
79
|
+
var postJson = async (fetchImpl, url, body) => fetchImpl(url, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: { "Content-Type": "application/json" },
|
|
82
|
+
body: JSON.stringify(body)
|
|
83
|
+
});
|
|
84
|
+
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
85
|
+
var defaultOpenBrowser = async (url) => {
|
|
86
|
+
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
87
|
+
const args = process.platform === "win32" ? ["/c", "start", "", url.replace(/&/g, "^&")] : [url];
|
|
88
|
+
try {
|
|
89
|
+
const child = spawn(command, args, {
|
|
90
|
+
detached: true,
|
|
91
|
+
stdio: "ignore"
|
|
92
|
+
});
|
|
93
|
+
child.unref();
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
async function saveTokenLogin(args) {
|
|
100
|
+
if (!args.authToken.trim()) {
|
|
101
|
+
args.error.error("No auth token provided.");
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
saveDefaultProfile(args.configPath, {
|
|
105
|
+
serverUrl: args.serverUrl,
|
|
106
|
+
authToken: args.authToken.trim()
|
|
107
|
+
});
|
|
108
|
+
args.output.log(`Saved profile default -> ${args.serverUrl}`);
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
async function runWebLogin(args) {
|
|
112
|
+
const startResponse = await postJson(
|
|
113
|
+
args.fetchImpl,
|
|
114
|
+
`${args.serverUrl}/api/v1/users/cli-login/start`,
|
|
115
|
+
{ clientName: "nolo-cli" }
|
|
116
|
+
);
|
|
117
|
+
const start = await startResponse.json().catch(() => ({}));
|
|
118
|
+
if (!startResponse.ok || !start?.deviceCode || !start?.verificationUriComplete) {
|
|
119
|
+
args.error.error(
|
|
120
|
+
`Failed to start web login (${startResponse.status}). Use --token to paste a token manually.`
|
|
121
|
+
);
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
args.output.log("Open this URL to authorize nolo-cli:");
|
|
125
|
+
args.output.log(start.verificationUriComplete);
|
|
126
|
+
args.output.log(`Code: ${start.userCode}`);
|
|
127
|
+
if (!args.noBrowser) {
|
|
128
|
+
const opened = await args.openBrowser(start.verificationUriComplete);
|
|
129
|
+
if (!opened) {
|
|
130
|
+
args.output.log("Could not open a browser automatically. Paste the URL above.");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const intervalMs = Math.max(1, Number(start.interval) || 2) * 1e3;
|
|
134
|
+
const timeoutMs = Math.max(1, Number(start.expiresIn) || 600) * 1e3;
|
|
135
|
+
const deadline = args.now() + timeoutMs;
|
|
136
|
+
const statusLogIntervalMs = 15e3;
|
|
137
|
+
let lastStatusLogAt = 0;
|
|
138
|
+
args.output.log(
|
|
139
|
+
`[nolo] Waiting for browser authorization (${formatDuration(timeoutMs)} remaining)...`
|
|
140
|
+
);
|
|
141
|
+
while (args.now() <= deadline) {
|
|
142
|
+
const pollResponse = await postJson(
|
|
143
|
+
args.fetchImpl,
|
|
144
|
+
`${args.serverUrl}/api/v1/users/cli-login/poll`,
|
|
145
|
+
{ deviceCode: start.deviceCode }
|
|
146
|
+
);
|
|
147
|
+
const poll = await pollResponse.json().catch(() => ({}));
|
|
148
|
+
if (pollResponse.status === 202) {
|
|
149
|
+
const currentTime = args.now();
|
|
150
|
+
if (lastStatusLogAt > 0 && currentTime - lastStatusLogAt >= statusLogIntervalMs) {
|
|
151
|
+
const remainingMs = Math.max(0, deadline - currentTime);
|
|
152
|
+
args.output.log(
|
|
153
|
+
`[nolo] Still waiting... (${formatDuration(remainingMs)} remaining)`
|
|
154
|
+
);
|
|
155
|
+
lastStatusLogAt = currentTime;
|
|
156
|
+
} else if (lastStatusLogAt === 0) {
|
|
157
|
+
lastStatusLogAt = currentTime;
|
|
158
|
+
}
|
|
159
|
+
await args.sleep(intervalMs);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (pollResponse.ok && poll?.token) {
|
|
163
|
+
const approvedServer = typeof poll.serverUrl === "string" && poll.serverUrl.trim() ? normalizeServerOrigin(poll.serverUrl) : args.serverUrl;
|
|
164
|
+
return saveTokenLogin({
|
|
165
|
+
configPath: args.configPath,
|
|
166
|
+
serverUrl: approvedServer,
|
|
167
|
+
authToken: poll.token,
|
|
168
|
+
output: args.output,
|
|
169
|
+
error: args.error
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
args.error.error(
|
|
173
|
+
`Web login failed: ${poll?.error || `HTTP ${pollResponse.status}`}. Use --token to paste a token manually.`
|
|
174
|
+
);
|
|
175
|
+
return 1;
|
|
176
|
+
}
|
|
177
|
+
args.error.error("Web login timed out. Run `nolo login` again or use --token.");
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
async function runLoginCommand(args, deps = {}) {
|
|
181
|
+
const outputTarget = deps.output ?? console;
|
|
182
|
+
const errorTarget = deps.error ?? console;
|
|
183
|
+
if (wantsHelp(args)) {
|
|
184
|
+
outputTarget.log(LOGIN_HELP_TEXT);
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
const configPath = deps.configPath ?? getDefaultProfileConfigPath();
|
|
188
|
+
const serverArg = getArg(args, "--server");
|
|
189
|
+
const tokenArg = getArg(args, "--token");
|
|
190
|
+
const noBrowser = args.includes("--no-browser");
|
|
191
|
+
const serverUrl = (serverArg || DEFAULT_NOLO_SERVER_URL).replace(/\/+$/, "");
|
|
192
|
+
if (tokenArg) {
|
|
193
|
+
return saveTokenLogin({
|
|
194
|
+
configPath,
|
|
195
|
+
serverUrl,
|
|
196
|
+
authToken: tokenArg,
|
|
197
|
+
output: outputTarget,
|
|
198
|
+
error: errorTarget
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (args.includes("--manual")) {
|
|
202
|
+
const rl = createInterface({ input, output });
|
|
203
|
+
const question = deps.question ?? ((prompt) => rl.question(prompt));
|
|
204
|
+
try {
|
|
205
|
+
const authToken = await question("paste auth token: ");
|
|
206
|
+
return saveTokenLogin({
|
|
207
|
+
configPath,
|
|
208
|
+
serverUrl,
|
|
209
|
+
authToken,
|
|
210
|
+
output: outputTarget,
|
|
211
|
+
error: errorTarget
|
|
212
|
+
});
|
|
213
|
+
} finally {
|
|
214
|
+
rl.close();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return runWebLogin({
|
|
218
|
+
configPath,
|
|
219
|
+
serverUrl,
|
|
220
|
+
fetchImpl: deps.fetchImpl ?? fetch,
|
|
221
|
+
openBrowser: deps.openBrowser ?? defaultOpenBrowser,
|
|
222
|
+
sleep: deps.sleep ?? defaultSleep,
|
|
223
|
+
now: deps.now ?? Date.now,
|
|
224
|
+
output: outputTarget,
|
|
225
|
+
error: errorTarget,
|
|
226
|
+
noBrowser
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function runWhoamiCommand(deps = {}) {
|
|
230
|
+
const output2 = deps.output ?? console;
|
|
231
|
+
if (wantsHelp(deps.args ?? [])) {
|
|
232
|
+
output2.log(WHOAMI_HELP_TEXT);
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
const env = deps.env ?? process.env;
|
|
236
|
+
const config = loadProfileConfig(deps.configPath);
|
|
237
|
+
const profile = getCurrentProfile(config);
|
|
238
|
+
const profileToken = profile?.authToken?.trim() ?? "";
|
|
239
|
+
const envToken = resolveAuthTokenFromEnv(env);
|
|
240
|
+
if (!profileToken && !envToken) {
|
|
241
|
+
output2.log("Not logged in. Run: nolo login");
|
|
242
|
+
return 1;
|
|
243
|
+
}
|
|
244
|
+
const runtimeEnv = buildCliRuntimeEnv(env, config);
|
|
245
|
+
const explicitServer = env.NOLO_SERVER || env.NOLO_SERVER_URL || env.BASE_URL;
|
|
246
|
+
if (!profileToken && envToken) {
|
|
247
|
+
output2.log("profile: not logged in (no saved token)");
|
|
248
|
+
if (profile?.serverUrl) {
|
|
249
|
+
output2.log(`profile server: ${profile.serverUrl}`);
|
|
250
|
+
}
|
|
251
|
+
output2.log(`effective server: ${runtimeEnv.NOLO_SERVER ?? resolveServerUrlFallback(profile)}`);
|
|
252
|
+
output2.log(`server source: ${explicitServer ? "env" : profile?.serverUrl ? "profile" : "default"}`);
|
|
253
|
+
output2.log(`env token: ${formatTokenPreview(envToken)} (source: environment)`);
|
|
254
|
+
return 0;
|
|
255
|
+
}
|
|
256
|
+
const effectiveServer = runtimeEnv.NOLO_SERVER ?? profile.serverUrl;
|
|
257
|
+
const effectiveToken = runtimeEnv.AUTH_TOKEN ?? profileToken;
|
|
258
|
+
output2.log(`profile: ${config.currentProfile}`);
|
|
259
|
+
output2.log(`profile server: ${profile.serverUrl}`);
|
|
260
|
+
output2.log(`effective server: ${effectiveServer}`);
|
|
261
|
+
output2.log(`server source: ${explicitServer ? "env" : "profile"}`);
|
|
262
|
+
output2.log(`token: ${formatTokenPreview(effectiveToken)} (source: ${envToken && envToken !== profileToken ? "environment" : "profile"})`);
|
|
263
|
+
if (envToken && envToken !== profileToken) {
|
|
264
|
+
output2.log(`profile token: ${formatTokenPreview(profileToken)} (source: profile, overridden by environment)`);
|
|
265
|
+
}
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
268
|
+
function resolveServerUrlFallback(profile) {
|
|
269
|
+
return profile?.serverUrl ?? DEFAULT_NOLO_SERVER_URL;
|
|
270
|
+
}
|
|
271
|
+
function runLogoutCommand(deps = {}) {
|
|
272
|
+
const output2 = deps.output ?? console;
|
|
273
|
+
if (wantsHelp(deps.args ?? [])) {
|
|
274
|
+
output2.log(LOGOUT_HELP_TEXT);
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
const env = deps.env ?? process.env;
|
|
278
|
+
const configPath = deps.configPath ?? getDefaultProfileConfigPath();
|
|
279
|
+
if (!clearProfileAuthToken(configPath)) {
|
|
280
|
+
output2.log("Not logged in.");
|
|
281
|
+
return 0;
|
|
282
|
+
}
|
|
283
|
+
output2.log("Logged out.");
|
|
284
|
+
if (resolveAuthTokenFromEnv(env)) {
|
|
285
|
+
output2.log(
|
|
286
|
+
"Note: AUTH_TOKEN in the environment is unchanged and may still authenticate commands."
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export {
|
|
293
|
+
LOGIN_HELP_TEXT,
|
|
294
|
+
LOGOUT_HELP_TEXT,
|
|
295
|
+
WHOAMI_HELP_TEXT,
|
|
296
|
+
defaultOpenBrowser,
|
|
297
|
+
runLoginCommand,
|
|
298
|
+
runWhoamiCommand,
|
|
299
|
+
runLogoutCommand
|
|
300
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listUserRecordsFromServers,
|
|
3
|
+
readLiveDbRecordAfterTombstoneMerge
|
|
4
|
+
} from "./chunk-QUWDTOUP.js";
|
|
5
|
+
import {
|
|
6
|
+
agentRecordHasConfiguredCredential
|
|
7
|
+
} from "./chunk-FQZWM5YX.js";
|
|
8
|
+
|
|
9
|
+
// packages/cli/agentListHelpers.ts
|
|
10
|
+
function parseAgentRecordId(privateKey, explicitId) {
|
|
11
|
+
if (explicitId) return explicitId;
|
|
12
|
+
const agentMatch = privateKey.match(/^agent-[^-]+-(.+)$/i);
|
|
13
|
+
return agentMatch?.[1] ?? "";
|
|
14
|
+
}
|
|
15
|
+
function buildCompanionKeys(rawId, userId) {
|
|
16
|
+
return {
|
|
17
|
+
privateKey: `agent-${userId}-${rawId}`,
|
|
18
|
+
publicKey: `agent-pub-${rawId}`
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function normalizeListedAgent(record) {
|
|
22
|
+
const privateKey = typeof record?.dbKey === "string" ? record.dbKey : "";
|
|
23
|
+
const explicitId = typeof record?.id === "string" && record.id ? record.id : void 0;
|
|
24
|
+
const ownerUserId = typeof record?.userId === "string" ? record.userId : "";
|
|
25
|
+
const rawId = explicitId || (ownerUserId && privateKey.startsWith(`agent-${ownerUserId}-`) ? privateKey.slice(`agent-${ownerUserId}-`.length) : parseAgentRecordId(privateKey, explicitId));
|
|
26
|
+
if (!privateKey || !rawId || !ownerUserId) return null;
|
|
27
|
+
const keys = buildCompanionKeys(rawId, ownerUserId);
|
|
28
|
+
const credentialConfigured = agentRecordHasConfiguredCredential(record);
|
|
29
|
+
const credentialRef = typeof record?.credentialRef === "string" && record.credentialRef ? record.credentialRef : void 0;
|
|
30
|
+
const apiKeyRef = typeof record?.apiKeyRef === "string" && record.apiKeyRef ? record.apiKeyRef : void 0;
|
|
31
|
+
return {
|
|
32
|
+
id: rawId,
|
|
33
|
+
privateKey,
|
|
34
|
+
publicKey: keys.publicKey,
|
|
35
|
+
name: typeof record?.name === "string" && record.name ? record.name : "(unnamed)",
|
|
36
|
+
model: typeof record?.model === "string" && record.model ? record.model : "-",
|
|
37
|
+
updatedAt: typeof record?.updatedAt === "string" || typeof record?.updatedAt === "number" ? record.updatedAt : typeof record?.createdAt === "string" || typeof record?.createdAt === "number" ? record.createdAt : typeof record?.created === "string" || typeof record?.created === "number" ? record.created : null,
|
|
38
|
+
isPublicFlag: !!record?.isPublic,
|
|
39
|
+
publicRecordExists: false,
|
|
40
|
+
type: typeof record?.type === "string" ? record.type : null,
|
|
41
|
+
tools: Array.isArray(record?.tools) ? record.tools.filter((tool) => typeof tool === "string") : [],
|
|
42
|
+
credentialConfigured,
|
|
43
|
+
credentialRef,
|
|
44
|
+
apiKeyRef,
|
|
45
|
+
...typeof record?.apiSource === "string" && record.apiSource ? { apiSource: record.apiSource } : {},
|
|
46
|
+
...typeof record?.cliProvider === "string" && record.cliProvider ? { cliProvider: record.cliProvider } : {}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function sortListedAgents(agents) {
|
|
50
|
+
agents.sort((a, b) => {
|
|
51
|
+
const ta = a.updatedAt == null ? 0 : new Date(a.updatedAt).getTime();
|
|
52
|
+
const tb = b.updatedAt == null ? 0 : new Date(b.updatedAt).getTime();
|
|
53
|
+
return tb - ta;
|
|
54
|
+
});
|
|
55
|
+
return agents;
|
|
56
|
+
}
|
|
57
|
+
function parseAgentListArgs(args) {
|
|
58
|
+
return {
|
|
59
|
+
wantJson: args.includes("--json"),
|
|
60
|
+
publicOnly: args.includes("--public-only"),
|
|
61
|
+
idsOnly: args.includes("--ids-only")
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async function listLocalCachedAgents(args) {
|
|
65
|
+
const privateRecords = /* @__PURE__ */ new Map();
|
|
66
|
+
const publicKeys = /* @__PURE__ */ new Set();
|
|
67
|
+
for await (const [key, value] of args.db.iterator({ gte: "", lte: "\uFFFF" })) {
|
|
68
|
+
if (typeof key !== "string" || !value || typeof value !== "object") continue;
|
|
69
|
+
if (key.startsWith(`agent-${args.userId}-`)) {
|
|
70
|
+
privateRecords.set(key, { ...value, dbKey: key });
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (key.startsWith("agent-pub-")) {
|
|
74
|
+
publicKeys.add(key);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const agents = sortListedAgents(
|
|
78
|
+
[...privateRecords.values()].map((record) => normalizeListedAgent(record)).filter((agent) => agent != null)
|
|
79
|
+
);
|
|
80
|
+
for (const agent of agents) {
|
|
81
|
+
agent.publicRecordExists = publicKeys.has(agent.publicKey);
|
|
82
|
+
}
|
|
83
|
+
return agents;
|
|
84
|
+
}
|
|
85
|
+
async function hasReadableRecord(args) {
|
|
86
|
+
try {
|
|
87
|
+
await args.readDbRecord(args);
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function listRemoteAgents(args) {
|
|
94
|
+
const recordGroups = [await args.queryUserRecords({ ...args, type: "agent" })];
|
|
95
|
+
const agents = sortListedAgents(
|
|
96
|
+
recordGroups.flat().map((record) => normalizeListedAgent(record)).filter((agent) => agent != null)
|
|
97
|
+
);
|
|
98
|
+
await Promise.all(
|
|
99
|
+
agents.map(async (agent) => {
|
|
100
|
+
agent.publicRecordExists = await hasReadableRecord({
|
|
101
|
+
authToken: args.authToken,
|
|
102
|
+
dbKey: agent.publicKey,
|
|
103
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
104
|
+
fetchImpl: args.fetchImpl,
|
|
105
|
+
serverUrl: args.serverUrl,
|
|
106
|
+
readDbRecord: args.readDbRecord
|
|
107
|
+
});
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
return agents;
|
|
111
|
+
}
|
|
112
|
+
async function listRemoteAgentsAcrossServers(args) {
|
|
113
|
+
const remoteResult = await listUserRecordsFromServers({
|
|
114
|
+
authToken: args.authToken,
|
|
115
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
116
|
+
fetchImpl: args.fetchImpl,
|
|
117
|
+
label: "agent query",
|
|
118
|
+
serverUrls: args.serverUrls,
|
|
119
|
+
type: "agent",
|
|
120
|
+
userId: args.userId
|
|
121
|
+
});
|
|
122
|
+
const agents = sortListedAgents(
|
|
123
|
+
remoteResult.records.map((record) => normalizeListedAgent(record)).filter((agent) => agent != null)
|
|
124
|
+
);
|
|
125
|
+
return { agents, failures: remoteResult.failures };
|
|
126
|
+
}
|
|
127
|
+
async function listFavoriteAgentIdsAcrossServers(args) {
|
|
128
|
+
const favoritedAtByKey = {};
|
|
129
|
+
await Promise.all(
|
|
130
|
+
args.serverUrls.map(async (serverUrl) => {
|
|
131
|
+
try {
|
|
132
|
+
const res = await args.fetchImpl(`${serverUrl}/rpc/listFavorites`, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: {
|
|
135
|
+
"Content-Type": "application/json",
|
|
136
|
+
Authorization: `Bearer ${args.authToken}`
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify({ targetType: "agent" })
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok) return;
|
|
141
|
+
const data = await res.json().catch(() => ({}));
|
|
142
|
+
const items = Array.isArray(data?.items) ? data.items : [];
|
|
143
|
+
for (const item of items) {
|
|
144
|
+
const id = typeof item?.id === "string" ? item.id : "";
|
|
145
|
+
if (!id) continue;
|
|
146
|
+
const at = Number(item?.favoritedAt) || 0;
|
|
147
|
+
favoritedAtByKey[id] = Math.max(
|
|
148
|
+
favoritedAtByKey[id] ?? 0,
|
|
149
|
+
at || Date.now()
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const ids = Array.isArray(data?.ids) ? data.ids : [];
|
|
153
|
+
for (const id of ids) {
|
|
154
|
+
if (typeof id === "string" && id && !(id in favoritedAtByKey)) {
|
|
155
|
+
favoritedAtByKey[id] = 1;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
return favoritedAtByKey;
|
|
163
|
+
}
|
|
164
|
+
async function decorateAgentsWithPublicStatusAcrossServers(args) {
|
|
165
|
+
await Promise.all(
|
|
166
|
+
args.agents.map(async (agent) => {
|
|
167
|
+
try {
|
|
168
|
+
const result = await readLiveDbRecordAfterTombstoneMerge({
|
|
169
|
+
authToken: args.authToken,
|
|
170
|
+
dbKey: agent.publicKey,
|
|
171
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
172
|
+
fetchImpl: args.fetchImpl,
|
|
173
|
+
serverUrls: args.serverUrls
|
|
174
|
+
});
|
|
175
|
+
agent.publicRecordExists = result.record?.isPublic === true;
|
|
176
|
+
} catch {
|
|
177
|
+
agent.publicRecordExists = false;
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
return args.agents;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export {
|
|
185
|
+
parseAgentListArgs,
|
|
186
|
+
listLocalCachedAgents,
|
|
187
|
+
listRemoteAgents,
|
|
188
|
+
listRemoteAgentsAcrossServers,
|
|
189
|
+
listFavoriteAgentIdsAcrossServers,
|
|
190
|
+
decorateAgentsWithPublicStatusAcrossServers
|
|
191
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compactWhitespace
|
|
3
|
+
} from "./chunk-DWLEOOGR.js";
|
|
4
|
+
|
|
5
|
+
// packages/chat/dialog/dialogTitle.ts
|
|
6
|
+
var GENERATED_DIALOG_TITLE_MAX_CHARS = 36;
|
|
7
|
+
var FALLBACK_DIALOG_TITLE_MAX_CHARS = 24;
|
|
8
|
+
var WRAPPING_QUOTES_RE = /^[`"'“”‘’「」『』《》]+|[`"'“”‘’「」『』《》]+$/gu;
|
|
9
|
+
var TRAILING_TITLE_PUNCTUATION_RE = /[。!?!?;;,,、::]+$/u;
|
|
10
|
+
var clip = (text, maxChars) => text.length <= maxChars ? text : `${text.slice(0, maxChars - 1).trimEnd()}\u2026`;
|
|
11
|
+
var toSingleLine = (value) => value.replace(/\r\n?/g, "\n").split("\n").map((line) => line.trim()).find(Boolean) ?? "";
|
|
12
|
+
var stripTitleFormatting = (value) => value.replace(/^(?:[-*#>]+\s*|\d+\.\s+)/, "").replace(WRAPPING_QUOTES_RE, "").replace(TRAILING_TITLE_PUNCTUATION_RE, "").trim();
|
|
13
|
+
var pickLeadingClause = (value) => {
|
|
14
|
+
const firstLine = toSingleLine(value);
|
|
15
|
+
if (!firstLine) return "";
|
|
16
|
+
const separatorIndexes = [firstLine.indexOf("\uFF1A"), firstLine.indexOf(":")].filter((index) => index > 0).sort((left, right) => left - right);
|
|
17
|
+
for (const index of separatorIndexes) {
|
|
18
|
+
const clause = firstLine.slice(0, index).trim();
|
|
19
|
+
if (clause.length >= 4) return clause;
|
|
20
|
+
}
|
|
21
|
+
return firstLine;
|
|
22
|
+
};
|
|
23
|
+
var normalizeDialogTitle = (rawTitle, maxChars = GENERATED_DIALOG_TITLE_MAX_CHARS) => {
|
|
24
|
+
if (typeof rawTitle !== "string") return "";
|
|
25
|
+
const normalized = stripTitleFormatting(
|
|
26
|
+
compactWhitespace(toSingleLine(rawTitle))
|
|
27
|
+
);
|
|
28
|
+
if (!normalized) return "";
|
|
29
|
+
return clip(normalized, maxChars);
|
|
30
|
+
};
|
|
31
|
+
var buildDialogFallbackTitleFromUserInput = (userInput, maxChars = FALLBACK_DIALOG_TITLE_MAX_CHARS) => {
|
|
32
|
+
if (typeof userInput !== "string") return "";
|
|
33
|
+
const candidate = pickLeadingClause(userInput);
|
|
34
|
+
return normalizeDialogTitle(candidate || userInput, maxChars);
|
|
35
|
+
};
|
|
36
|
+
var buildDialogFallbackTitleFromMessages = (messages) => {
|
|
37
|
+
for (const message of messages) {
|
|
38
|
+
if (message?.role !== "user") continue;
|
|
39
|
+
const title = buildDialogFallbackTitleFromUserInput(message?.content);
|
|
40
|
+
if (title) return title;
|
|
41
|
+
}
|
|
42
|
+
return "";
|
|
43
|
+
};
|
|
44
|
+
var resolveDialogTitle = (generatedTitle, fallbackTitle) => normalizeDialogTitle(generatedTitle) || fallbackTitle.trim();
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
normalizeDialogTitle,
|
|
48
|
+
buildDialogFallbackTitleFromMessages,
|
|
49
|
+
resolveDialogTitle
|
|
50
|
+
};
|