@withone/cli 2.4.0 → 2.6.0
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 +13 -11
- package/dist/{chunk-6FA7KUNQ.js → chunk-4KX5ZERS.js} +797 -116
- package/dist/{chunk-7FPQOAQ4.js → chunk-O3HDWHHS.js} +5 -3
- package/dist/{chunk-XKUTG7JD.js → chunk-PUQKTRYC.js} +5 -3
- package/dist/chunk-Q6PWTATS.js +79 -0
- package/dist/{chunk-NOFJ4NYD.js → chunk-VMFWA43Q.js} +5 -77
- package/dist/{flow-runner-SFECNAO2.js → flow-runner-FME4AVVN.js} +2 -1
- package/dist/index.js +830 -1350
- package/dist/{migrate-3LSEIPRF.js → migrate-KWEEEQ3E.js} +3 -2
- package/dist/{schema-FICQRMZ7.js → schema-YJ7JTGFL.js} +5 -3
- package/dist/{sql-AKQSXRV2.js → sql-NDMMFQP6.js} +3 -2
- package/package.json +1 -1
- package/skills/one/SKILL.md +3 -1
|
@@ -3,21 +3,674 @@ import {
|
|
|
3
3
|
setByDotPath
|
|
4
4
|
} from "./chunk-44CV5IMX.js";
|
|
5
5
|
import {
|
|
6
|
+
isAgentMode
|
|
7
|
+
} from "./chunk-Q6PWTATS.js";
|
|
8
|
+
import {
|
|
9
|
+
appendAnalyticsQueue,
|
|
10
|
+
appendUsageLog,
|
|
11
|
+
claimUsageLog,
|
|
12
|
+
getApiKey,
|
|
6
13
|
getCacheTtl,
|
|
7
|
-
|
|
14
|
+
getDeviceId,
|
|
15
|
+
getEnvFromApiKey,
|
|
16
|
+
getProjectRoot,
|
|
17
|
+
getWhoAmI,
|
|
18
|
+
homeDir,
|
|
19
|
+
markTelemetryNoticeShown,
|
|
20
|
+
readAnalyticsQueue,
|
|
21
|
+
readConfig,
|
|
22
|
+
readUsageState,
|
|
23
|
+
telemetryNoticeShown,
|
|
24
|
+
writeAnalyticsQueue,
|
|
25
|
+
writeUsageLog,
|
|
26
|
+
writeUsageState
|
|
8
27
|
} from "./chunk-HTXZZQ6U.js";
|
|
9
28
|
|
|
10
29
|
// src/lib/flow-runner.ts
|
|
11
|
-
import
|
|
12
|
-
import
|
|
30
|
+
import fs5 from "fs";
|
|
31
|
+
import path6 from "path";
|
|
13
32
|
import crypto from "crypto";
|
|
14
33
|
|
|
15
34
|
// src/lib/flow-engine.ts
|
|
35
|
+
import fs4 from "fs";
|
|
36
|
+
import os2 from "os";
|
|
37
|
+
import path5 from "path";
|
|
38
|
+
import { exec, spawn } from "child_process";
|
|
39
|
+
import { promisify } from "util";
|
|
40
|
+
|
|
41
|
+
// src/lib/install-context.ts
|
|
16
42
|
import fs2 from "fs";
|
|
17
43
|
import os from "os";
|
|
44
|
+
import path3 from "path";
|
|
45
|
+
|
|
46
|
+
// src/lib/agents.ts
|
|
47
|
+
import fs from "fs";
|
|
48
|
+
import path from "path";
|
|
49
|
+
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
50
|
+
function expandPath(p) {
|
|
51
|
+
if (p.startsWith("~/")) {
|
|
52
|
+
return path.join(homeDir(), p.slice(2));
|
|
53
|
+
}
|
|
54
|
+
return p;
|
|
55
|
+
}
|
|
56
|
+
function getClaudeDesktopConfigPath() {
|
|
57
|
+
switch (process.platform) {
|
|
58
|
+
case "darwin":
|
|
59
|
+
return "~/Library/Application Support/Claude/claude_desktop_config.json";
|
|
60
|
+
case "win32":
|
|
61
|
+
return path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
62
|
+
default:
|
|
63
|
+
return "~/.config/Claude/claude_desktop_config.json";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function getClaudeDesktopDetectDir() {
|
|
67
|
+
switch (process.platform) {
|
|
68
|
+
case "darwin":
|
|
69
|
+
return "~/Library/Application Support/Claude";
|
|
70
|
+
case "win32":
|
|
71
|
+
return path.join(process.env.APPDATA || "", "Claude");
|
|
72
|
+
default:
|
|
73
|
+
return "~/.config/Claude";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function getWindsurfConfigPath() {
|
|
77
|
+
if (process.platform === "win32") {
|
|
78
|
+
return path.join(homeDir(), ".codeium", "windsurf", "mcp_config.json");
|
|
79
|
+
}
|
|
80
|
+
return "~/.codeium/windsurf/mcp_config.json";
|
|
81
|
+
}
|
|
82
|
+
function getWindsurfDetectDir() {
|
|
83
|
+
if (process.platform === "win32") {
|
|
84
|
+
return path.join(homeDir(), ".codeium", "windsurf");
|
|
85
|
+
}
|
|
86
|
+
return "~/.codeium/windsurf";
|
|
87
|
+
}
|
|
88
|
+
function getCursorConfigPath() {
|
|
89
|
+
if (process.platform === "win32") {
|
|
90
|
+
return path.join(homeDir(), ".cursor", "mcp.json");
|
|
91
|
+
}
|
|
92
|
+
return "~/.cursor/mcp.json";
|
|
93
|
+
}
|
|
94
|
+
function getAgents() {
|
|
95
|
+
return [
|
|
96
|
+
{
|
|
97
|
+
id: "claude-code",
|
|
98
|
+
name: "Claude Code",
|
|
99
|
+
configPath: "~/.claude.json",
|
|
100
|
+
configKey: "mcpServers",
|
|
101
|
+
detectDir: "~/.claude",
|
|
102
|
+
projectConfigPath: ".mcp.json"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "claude-desktop",
|
|
106
|
+
name: "Claude Desktop",
|
|
107
|
+
configPath: getClaudeDesktopConfigPath(),
|
|
108
|
+
configKey: "mcpServers",
|
|
109
|
+
detectDir: getClaudeDesktopDetectDir()
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "cursor",
|
|
113
|
+
name: "Cursor",
|
|
114
|
+
configPath: getCursorConfigPath(),
|
|
115
|
+
configKey: "mcpServers",
|
|
116
|
+
detectDir: "~/.cursor",
|
|
117
|
+
projectConfigPath: ".cursor/mcp.json"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "windsurf",
|
|
121
|
+
name: "Windsurf",
|
|
122
|
+
configPath: getWindsurfConfigPath(),
|
|
123
|
+
configKey: "mcpServers",
|
|
124
|
+
detectDir: getWindsurfDetectDir()
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "codex",
|
|
128
|
+
name: "Codex",
|
|
129
|
+
configPath: "~/.codex/config.toml",
|
|
130
|
+
configKey: "mcp_servers",
|
|
131
|
+
detectDir: "~/.codex",
|
|
132
|
+
projectConfigPath: ".codex/config.toml",
|
|
133
|
+
configFormat: "toml"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "kiro",
|
|
137
|
+
name: "Kiro",
|
|
138
|
+
configPath: "~/.kiro/settings/mcp.json",
|
|
139
|
+
configKey: "mcpServers",
|
|
140
|
+
detectDir: "~/.kiro",
|
|
141
|
+
projectConfigPath: ".kiro/settings/mcp.json"
|
|
142
|
+
}
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
function detectInstalledAgents() {
|
|
146
|
+
return getAgents().filter((agent) => {
|
|
147
|
+
const detectDir = expandPath(agent.detectDir);
|
|
148
|
+
return fs.existsSync(detectDir);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function getAgentConfigPath(agent, scope = "global") {
|
|
152
|
+
if (scope === "project" && agent.projectConfigPath) {
|
|
153
|
+
return path.join(process.cwd(), agent.projectConfigPath);
|
|
154
|
+
}
|
|
155
|
+
return expandPath(agent.configPath);
|
|
156
|
+
}
|
|
157
|
+
function readAgentConfig(agent, scope = "global") {
|
|
158
|
+
const configPath = getAgentConfigPath(agent, scope);
|
|
159
|
+
if (!fs.existsSync(configPath)) {
|
|
160
|
+
return {};
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
164
|
+
if (agent.configFormat === "toml") {
|
|
165
|
+
return parseToml(content);
|
|
166
|
+
}
|
|
167
|
+
return JSON.parse(content);
|
|
168
|
+
} catch {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function writeAgentConfig(agent, config, scope = "global") {
|
|
173
|
+
const configPath = getAgentConfigPath(agent, scope);
|
|
174
|
+
const configDir = path.dirname(configPath);
|
|
175
|
+
if (!fs.existsSync(configDir)) {
|
|
176
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
177
|
+
}
|
|
178
|
+
if (agent.configFormat === "toml") {
|
|
179
|
+
fs.writeFileSync(configPath, stringifyToml(config));
|
|
180
|
+
} else {
|
|
181
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function getMcpServerConfig(apiKey, accessControl) {
|
|
185
|
+
const env = {
|
|
186
|
+
ONE_SECRET: apiKey
|
|
187
|
+
};
|
|
188
|
+
if (accessControl) {
|
|
189
|
+
if (accessControl.permissions && accessControl.permissions !== "admin") {
|
|
190
|
+
env.ONE_PERMISSIONS = accessControl.permissions;
|
|
191
|
+
}
|
|
192
|
+
if (accessControl.connectionKeys && !(accessControl.connectionKeys.length === 1 && accessControl.connectionKeys[0] === "*")) {
|
|
193
|
+
env.ONE_CONNECTION_KEYS = accessControl.connectionKeys.join(",");
|
|
194
|
+
}
|
|
195
|
+
if (accessControl.actionIds && !(accessControl.actionIds.length === 1 && accessControl.actionIds[0] === "*")) {
|
|
196
|
+
env.ONE_ACTION_IDS = accessControl.actionIds.join(",");
|
|
197
|
+
}
|
|
198
|
+
if (accessControl.knowledgeAgent) {
|
|
199
|
+
env.ONE_KNOWLEDGE_AGENT = "true";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
command: "npx",
|
|
204
|
+
args: ["-y", "@withone/mcp"],
|
|
205
|
+
env
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function installMcpConfig(agent, apiKey, scope = "global", accessControl) {
|
|
209
|
+
const config = readAgentConfig(agent, scope);
|
|
210
|
+
const configKey = agent.configKey;
|
|
211
|
+
const mcpServers = config[configKey] || {};
|
|
212
|
+
mcpServers["one"] = getMcpServerConfig(apiKey, accessControl);
|
|
213
|
+
config[configKey] = mcpServers;
|
|
214
|
+
writeAgentConfig(agent, config, scope);
|
|
215
|
+
}
|
|
216
|
+
function isMcpInstalled(agent, scope = "global") {
|
|
217
|
+
const config = readAgentConfig(agent, scope);
|
|
218
|
+
const configKey = agent.configKey;
|
|
219
|
+
const mcpServers = config[configKey];
|
|
220
|
+
return mcpServers?.["one"] !== void 0;
|
|
221
|
+
}
|
|
222
|
+
function getAgentStatuses() {
|
|
223
|
+
return getAgents().map((agent) => {
|
|
224
|
+
const detected = fs.existsSync(expandPath(agent.detectDir));
|
|
225
|
+
const globalMcp = detected && isMcpInstalled(agent, "global");
|
|
226
|
+
const projectMcp = agent.projectConfigPath ? isMcpInstalled(agent, "project") : null;
|
|
227
|
+
return { agent, detected, globalMcp, projectMcp };
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/lib/analytics.ts
|
|
232
|
+
import { createRequire as createRequire2 } from "module";
|
|
233
|
+
import { randomUUID, createHash } from "crypto";
|
|
234
|
+
import pc from "picocolors";
|
|
235
|
+
|
|
236
|
+
// src/lib/version.ts
|
|
237
|
+
import { createRequire } from "module";
|
|
238
|
+
import { existsSync } from "fs";
|
|
18
239
|
import path2 from "path";
|
|
19
|
-
import {
|
|
20
|
-
|
|
240
|
+
import { fileURLToPath } from "url";
|
|
241
|
+
var require2 = createRequire(import.meta.url);
|
|
242
|
+
var cached = null;
|
|
243
|
+
function cliVersion() {
|
|
244
|
+
if (cached !== null) return cached;
|
|
245
|
+
const dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
246
|
+
for (let i = 1; i <= 4; i++) {
|
|
247
|
+
const candidate = path2.resolve(dir, ...Array(i).fill(".."), "package.json");
|
|
248
|
+
if (!existsSync(candidate)) continue;
|
|
249
|
+
try {
|
|
250
|
+
const version = require2(candidate).version;
|
|
251
|
+
if (version) {
|
|
252
|
+
cached = version;
|
|
253
|
+
return cached;
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
cached = "unknown";
|
|
259
|
+
return cached;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/lib/analytics.ts
|
|
263
|
+
var require3 = createRequire2(import.meta.url);
|
|
264
|
+
var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
265
|
+
var DEFAULT_POSTHOG_KEY = "phc_a9ok4w0uxiZcVoSWOISIlin85lHMXQD3vWPaYnuRlRV";
|
|
266
|
+
var SEND_MAX_ATTEMPTS = 3;
|
|
267
|
+
var QUEUE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
268
|
+
var EXIT_GRACE_MS = 300;
|
|
269
|
+
var inFlight = /* @__PURE__ */ new Set();
|
|
270
|
+
var pending = /* @__PURE__ */ new Set();
|
|
271
|
+
var dispatched = /* @__PURE__ */ new Set();
|
|
272
|
+
var delivered = /* @__PURE__ */ new Set();
|
|
273
|
+
var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
274
|
+
function uuidFromInsertId(insertId) {
|
|
275
|
+
if (UUID_SHAPE.test(insertId)) return insertId.toLowerCase();
|
|
276
|
+
const h = createHash("sha1").update(`one-cli-event:${insertId}`).digest("hex");
|
|
277
|
+
const variant = (parseInt(h[16], 16) & 3 | 8).toString(16);
|
|
278
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-5${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
|
|
279
|
+
}
|
|
280
|
+
function posthogHost() {
|
|
281
|
+
return process.env.ONE_POSTHOG_HOST || DEFAULT_POSTHOG_HOST;
|
|
282
|
+
}
|
|
283
|
+
function posthogKey() {
|
|
284
|
+
return process.env.ONE_POSTHOG_KEY || DEFAULT_POSTHOG_KEY;
|
|
285
|
+
}
|
|
286
|
+
function envName() {
|
|
287
|
+
const key = getApiKey();
|
|
288
|
+
return key ? getEnvFromApiKey(key) : "live";
|
|
289
|
+
}
|
|
290
|
+
function isOn(value) {
|
|
291
|
+
return value === "1" || value === "true";
|
|
292
|
+
}
|
|
293
|
+
function debugLog(message) {
|
|
294
|
+
if (isOn(process.env.ONE_ANALYTICS_DEBUG)) {
|
|
295
|
+
process.stderr.write(`[analytics] ${message}
|
|
296
|
+
`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function isTelemetryDisabled() {
|
|
300
|
+
if (isOn(process.env.ONE_NO_TELEMETRY) || isOn(process.env.ONE_DISABLE_TELEMETRY)) return true;
|
|
301
|
+
if (isOn(process.env.DO_NOT_TRACK)) return true;
|
|
302
|
+
if (isOn(process.env.CI)) return true;
|
|
303
|
+
if (readConfig()?.telemetry === "off") return true;
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
function distinctId() {
|
|
307
|
+
return getWhoAmI()?.user?.id ?? getDeviceId();
|
|
308
|
+
}
|
|
309
|
+
function isAuthenticated() {
|
|
310
|
+
return !!getWhoAmI()?.user || !!getApiKey();
|
|
311
|
+
}
|
|
312
|
+
function baseProperties() {
|
|
313
|
+
return {
|
|
314
|
+
$lib: "one-cli",
|
|
315
|
+
cli_version: cliVersion(),
|
|
316
|
+
agent_mode: isAgentMode(),
|
|
317
|
+
env: envName(),
|
|
318
|
+
os: process.platform,
|
|
319
|
+
arch: process.arch,
|
|
320
|
+
node_version: process.versions.node,
|
|
321
|
+
authenticated: isAuthenticated()
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function personSet() {
|
|
325
|
+
const whoami = getWhoAmI();
|
|
326
|
+
if (!whoami?.user) return void 0;
|
|
327
|
+
const set = {};
|
|
328
|
+
if (whoami.user.email) set.email = whoami.user.email;
|
|
329
|
+
if (whoami.user.name) set.name = whoami.user.name;
|
|
330
|
+
if (whoami.organization?.id) set.organization_id = whoami.organization.id;
|
|
331
|
+
return Object.keys(set).length ? set : void 0;
|
|
332
|
+
}
|
|
333
|
+
function send(item) {
|
|
334
|
+
const insertId = item.properties.$insert_id;
|
|
335
|
+
if (insertId) dispatched.add(insertId);
|
|
336
|
+
const controller = new AbortController();
|
|
337
|
+
inFlight.add(controller);
|
|
338
|
+
const run = (async () => {
|
|
339
|
+
try {
|
|
340
|
+
const res = await fetch(`${posthogHost()}/i/v0/e/`, {
|
|
341
|
+
method: "POST",
|
|
342
|
+
headers: { "Content-Type": "application/json" },
|
|
343
|
+
body: JSON.stringify({
|
|
344
|
+
api_key: posthogKey(),
|
|
345
|
+
event: item.event,
|
|
346
|
+
distinct_id: item.distinct_id,
|
|
347
|
+
// PostHog's dedupe key — a re-sent copy is dropped on ingest.
|
|
348
|
+
uuid: item.uuid ?? (insertId ? uuidFromInsertId(insertId) : void 0),
|
|
349
|
+
properties: item.properties,
|
|
350
|
+
timestamp: item.timestamp
|
|
351
|
+
}),
|
|
352
|
+
signal: controller.signal
|
|
353
|
+
});
|
|
354
|
+
if (res.ok && insertId) delivered.add(insertId);
|
|
355
|
+
debugLog(`"${item.event}" -> HTTP ${res.status}${res.ok ? "" : " (retry next run)"}`);
|
|
356
|
+
} catch (err) {
|
|
357
|
+
debugLog(`"${item.event}" not sent: ${err instanceof Error ? err.message : String(err)} (retry next run)`);
|
|
358
|
+
} finally {
|
|
359
|
+
inFlight.delete(controller);
|
|
360
|
+
}
|
|
361
|
+
})();
|
|
362
|
+
pending.add(run);
|
|
363
|
+
void run.finally(() => pending.delete(run));
|
|
364
|
+
}
|
|
365
|
+
function capture(event, properties = {}, opts = {}) {
|
|
366
|
+
if (isTelemetryDisabled()) {
|
|
367
|
+
debugLog(`disabled \u2014 skipping "${event}"`);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const did = opts.distinctId ?? distinctId();
|
|
371
|
+
const props = { ...baseProperties(), ...properties };
|
|
372
|
+
if (props.$insert_id === void 0) props.$insert_id = randomUUID();
|
|
373
|
+
const insertId = props.$insert_id;
|
|
374
|
+
if (opts.personProfile === false) {
|
|
375
|
+
props.$process_person_profile = false;
|
|
376
|
+
} else if (did === distinctId()) {
|
|
377
|
+
const set = personSet();
|
|
378
|
+
if (set) props.$set = set;
|
|
379
|
+
}
|
|
380
|
+
const item = {
|
|
381
|
+
event,
|
|
382
|
+
distinct_id: did,
|
|
383
|
+
properties: props,
|
|
384
|
+
timestamp: opts.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
385
|
+
uuid: uuidFromInsertId(insertId)
|
|
386
|
+
};
|
|
387
|
+
appendAnalyticsQueue(JSON.stringify(item));
|
|
388
|
+
}
|
|
389
|
+
var ROLLUP_WINDOW_MS = 5 * 60 * 1e3;
|
|
390
|
+
var ROLLUP_MAX_BATCH = 500;
|
|
391
|
+
function utcDay(ts) {
|
|
392
|
+
return new Date(ts).toISOString().slice(0, 10);
|
|
393
|
+
}
|
|
394
|
+
var PRE_AUTH_COMMANDS = /* @__PURE__ */ new Set([
|
|
395
|
+
"init",
|
|
396
|
+
"login",
|
|
397
|
+
"logout",
|
|
398
|
+
"guide",
|
|
399
|
+
"platforms",
|
|
400
|
+
"onboard",
|
|
401
|
+
"config",
|
|
402
|
+
"update",
|
|
403
|
+
"help"
|
|
404
|
+
]);
|
|
405
|
+
function shouldRecord(commandPath2) {
|
|
406
|
+
if (isAuthenticated()) return true;
|
|
407
|
+
return PRE_AUTH_COMMANDS.has(commandPath2.split(" ")[0]);
|
|
408
|
+
}
|
|
409
|
+
function recordCommand(command) {
|
|
410
|
+
if (isTelemetryDisabled()) {
|
|
411
|
+
writeUsageLog([]);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const cmdPath = commandPath(command);
|
|
415
|
+
if (!shouldRecord(cmdPath)) return;
|
|
416
|
+
const did = distinctId();
|
|
417
|
+
const entry = { ts: Date.now(), command: cmdPath, agent: isAgentMode(), did };
|
|
418
|
+
appendUsageLog(JSON.stringify(entry));
|
|
419
|
+
const today = utcDay(entry.ts);
|
|
420
|
+
const state = readUsageState();
|
|
421
|
+
const firstTouch = state.lastDay !== today || state.distinctId !== did;
|
|
422
|
+
flushUsageRollups({ force: firstTouch });
|
|
423
|
+
if (firstTouch) writeUsageState({ lastDay: today, distinctId: did });
|
|
424
|
+
}
|
|
425
|
+
function flushUsageRollups(opts = {}) {
|
|
426
|
+
if (isTelemetryDisabled()) {
|
|
427
|
+
writeUsageLog([]);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const lines = claimUsageLog();
|
|
431
|
+
if (!lines || lines.length === 0) return;
|
|
432
|
+
const entries = [];
|
|
433
|
+
for (const line of lines) {
|
|
434
|
+
try {
|
|
435
|
+
const e = JSON.parse(line);
|
|
436
|
+
if (e && typeof e.ts === "number" && typeof e.command === "string" && typeof e.did === "string") {
|
|
437
|
+
entries.push(e);
|
|
438
|
+
}
|
|
439
|
+
} catch {
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (entries.length === 0) return;
|
|
443
|
+
const currentDid = entries[entries.length - 1].did;
|
|
444
|
+
const now = Date.now();
|
|
445
|
+
const groups = /* @__PURE__ */ new Map();
|
|
446
|
+
for (const e of entries) {
|
|
447
|
+
const g = groups.get(e.did);
|
|
448
|
+
if (g) g.push(e);
|
|
449
|
+
else groups.set(e.did, [e]);
|
|
450
|
+
}
|
|
451
|
+
const kept = [];
|
|
452
|
+
for (const [did, group] of groups) {
|
|
453
|
+
const due = opts.force === true || did !== currentDid || // a superseded login's batch — flush it now
|
|
454
|
+
group.length >= ROLLUP_MAX_BATCH || now - group[0].ts >= ROLLUP_WINDOW_MS;
|
|
455
|
+
if (due) emitRollup(did, group);
|
|
456
|
+
else kept.push(...group);
|
|
457
|
+
}
|
|
458
|
+
for (const e of kept) appendUsageLog(JSON.stringify(e));
|
|
459
|
+
}
|
|
460
|
+
function emitRollup(did, group) {
|
|
461
|
+
const byCommand = {};
|
|
462
|
+
let agentCount = 0;
|
|
463
|
+
for (const e of group) {
|
|
464
|
+
byCommand[e.command] = (byCommand[e.command] ?? 0) + 1;
|
|
465
|
+
if (e.agent) agentCount += 1;
|
|
466
|
+
}
|
|
467
|
+
const insertId = createHash("sha1").update(`${did}|${group.map((e) => `${e.ts}:${e.command}:${e.agent ? 1 : 0}`).join("|")}`).digest("hex");
|
|
468
|
+
capture(
|
|
469
|
+
"CLI Usage Rollup",
|
|
470
|
+
{
|
|
471
|
+
command_count: group.length,
|
|
472
|
+
by_command: byCommand,
|
|
473
|
+
agent_count: agentCount,
|
|
474
|
+
human_count: group.length - agentCount,
|
|
475
|
+
window_start: new Date(group[0].ts).toISOString(),
|
|
476
|
+
window_end: new Date(group[group.length - 1].ts).toISOString(),
|
|
477
|
+
$insert_id: insertId
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
distinctId: did,
|
|
481
|
+
timestamp: new Date(group[group.length - 1].ts).toISOString(),
|
|
482
|
+
// Rollups bill at the anonymous rate; the person already exists.
|
|
483
|
+
personProfile: false
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
debugLog(`rollup \u2014 ${group.length} command(s) for ${did}`);
|
|
487
|
+
}
|
|
488
|
+
function commandPath(command) {
|
|
489
|
+
const parts = [];
|
|
490
|
+
let current = command;
|
|
491
|
+
while (current && current.name() && current.name() !== "one") {
|
|
492
|
+
parts.unshift(current.name());
|
|
493
|
+
current = current.parent;
|
|
494
|
+
}
|
|
495
|
+
return parts.join(" ") || command.name();
|
|
496
|
+
}
|
|
497
|
+
function drainQueue() {
|
|
498
|
+
if (isTelemetryDisabled()) {
|
|
499
|
+
writeAnalyticsQueue([]);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const now = Date.now();
|
|
503
|
+
const kept = [];
|
|
504
|
+
let changed = false;
|
|
505
|
+
for (const line of readAnalyticsQueue()) {
|
|
506
|
+
let item;
|
|
507
|
+
try {
|
|
508
|
+
item = JSON.parse(line);
|
|
509
|
+
} catch {
|
|
510
|
+
changed = true;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
const insertId = item?.properties?.$insert_id;
|
|
514
|
+
if (!insertId) {
|
|
515
|
+
changed = true;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
const age = now - Date.parse(item.timestamp);
|
|
519
|
+
const attempts = item.attempts ?? 0;
|
|
520
|
+
if (!(age < QUEUE_MAX_AGE_MS) || attempts >= SEND_MAX_ATTEMPTS) {
|
|
521
|
+
debugLog(`"${item.event}" dropped (${attempts} attempts, ${Math.round(age / 6e4)} min old)`);
|
|
522
|
+
changed = true;
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (dispatched.has(insertId)) {
|
|
526
|
+
kept.push(line);
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
item.attempts = attempts + 1;
|
|
530
|
+
if (!item.uuid) item.uuid = uuidFromInsertId(insertId);
|
|
531
|
+
kept.push(JSON.stringify(item));
|
|
532
|
+
changed = true;
|
|
533
|
+
send(item);
|
|
534
|
+
}
|
|
535
|
+
if (changed) writeAnalyticsQueue(kept);
|
|
536
|
+
}
|
|
537
|
+
async function flush() {
|
|
538
|
+
if (pending.size > 0) {
|
|
539
|
+
await Promise.race([
|
|
540
|
+
Promise.allSettled([...pending]),
|
|
541
|
+
new Promise((resolve2) => setTimeout(resolve2, EXIT_GRACE_MS))
|
|
542
|
+
]);
|
|
543
|
+
}
|
|
544
|
+
for (const controller of inFlight) controller.abort();
|
|
545
|
+
const remaining = readAnalyticsQueue().filter((line) => {
|
|
546
|
+
try {
|
|
547
|
+
const item = JSON.parse(line);
|
|
548
|
+
const id = item.properties?.$insert_id;
|
|
549
|
+
if (!id || delivered.has(id)) return false;
|
|
550
|
+
return (item.attempts ?? 0) < SEND_MAX_ATTEMPTS;
|
|
551
|
+
} catch {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
writeAnalyticsQueue(remaining);
|
|
556
|
+
dispatched.clear();
|
|
557
|
+
delivered.clear();
|
|
558
|
+
}
|
|
559
|
+
function maybeShowTelemetryNotice() {
|
|
560
|
+
if (isTelemetryDisabled() || isAgentMode()) return;
|
|
561
|
+
if (telemetryNoticeShown()) return;
|
|
562
|
+
markTelemetryNoticeShown();
|
|
563
|
+
process.stderr.write(
|
|
564
|
+
pc.dim(
|
|
565
|
+
"One CLI collects usage analytics (which commands run, linked to your One account) to improve the product.\nNo arguments, inputs, or secrets are ever collected. Opt out anytime with ONE_NO_TELEMETRY=1.\n"
|
|
566
|
+
)
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// src/lib/install-context.ts
|
|
571
|
+
var EXTRA_HARNESS_DIRS = [
|
|
572
|
+
{ id: "gemini-cli", dir: ".gemini" },
|
|
573
|
+
{ id: "openclaw", dir: ".openclaw" },
|
|
574
|
+
{ id: "hermes", dir: ".hermes" },
|
|
575
|
+
{ id: "devin", dir: ".devin" }
|
|
576
|
+
];
|
|
577
|
+
var LAUNCHER_ENV = [
|
|
578
|
+
{ id: "claude-code", vars: ["CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT"] },
|
|
579
|
+
{ id: "codex", vars: ["CODEX_SANDBOX", "CODEX_CI", "CODEX_THREAD_ID"] },
|
|
580
|
+
{ id: "gemini-cli", vars: ["GEMINI_CLI"] },
|
|
581
|
+
// CURSOR_TRACE_ID is deliberately absent: Cursor exports it into every
|
|
582
|
+
// integrated-terminal shell, so it marks the editor, not an agent.
|
|
583
|
+
{ id: "cursor", vars: ["CURSOR_AGENT"] },
|
|
584
|
+
{ id: "windsurf", vars: ["WINDSURF_AGENT"] },
|
|
585
|
+
{ id: "kiro", vars: ["KIRO_AGENT"] },
|
|
586
|
+
{ id: "openclaw", vars: ["OPENCLAW_AGENT", "OPENCLAW_SESSION"] },
|
|
587
|
+
{ id: "hermes", vars: ["HERMES_AGENT", "HERMES_SESSION"] },
|
|
588
|
+
{ id: "devin", vars: ["DEVIN_SESSION_ID"] }
|
|
589
|
+
];
|
|
590
|
+
function detectLauncher(env = process.env) {
|
|
591
|
+
for (const entry of LAUNCHER_ENV) {
|
|
592
|
+
if (entry.vars.some((v) => env[v] !== void 0 && env[v] !== "")) return entry.id;
|
|
593
|
+
}
|
|
594
|
+
return void 0;
|
|
595
|
+
}
|
|
596
|
+
function detectInstalledHarnesses() {
|
|
597
|
+
const ids = new Set(detectInstalledAgents().map((a) => a.id));
|
|
598
|
+
for (const { id, dir } of EXTRA_HARNESS_DIRS) {
|
|
599
|
+
if (fs2.existsSync(path3.join(homeDir(), dir))) ids.add(id);
|
|
600
|
+
}
|
|
601
|
+
return [...ids].sort();
|
|
602
|
+
}
|
|
603
|
+
function tryRead(read) {
|
|
604
|
+
try {
|
|
605
|
+
const value = read();
|
|
606
|
+
return value === null || value === "" ? void 0 : value;
|
|
607
|
+
} catch {
|
|
608
|
+
return void 0;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function collectInstallContext(opts) {
|
|
612
|
+
const env = opts.env ?? process.env;
|
|
613
|
+
const ctx = {
|
|
614
|
+
scope: opts.scope,
|
|
615
|
+
harnesses: tryRead(() => detectInstalledHarnesses()) ?? []
|
|
616
|
+
};
|
|
617
|
+
if (opts.scope === "project") {
|
|
618
|
+
ctx.path = opts.projectRoot ?? tryRead(() => getProjectRoot());
|
|
619
|
+
}
|
|
620
|
+
ctx.host = tryRead(() => os.hostname());
|
|
621
|
+
ctx.os = process.platform;
|
|
622
|
+
ctx.osVersion = tryRead(() => os.release());
|
|
623
|
+
ctx.arch = process.arch;
|
|
624
|
+
ctx.user = tryRead(() => os.userInfo().username);
|
|
625
|
+
if (!isTelemetryDisabled()) ctx.device = tryRead(() => getDeviceId());
|
|
626
|
+
const cli = tryRead(() => cliVersion());
|
|
627
|
+
ctx.cli = cli === "unknown" ? void 0 : cli;
|
|
628
|
+
ctx.launcher = detectLauncher(env);
|
|
629
|
+
return ctx;
|
|
630
|
+
}
|
|
631
|
+
function installContextToParams(ctx) {
|
|
632
|
+
const params = new URLSearchParams();
|
|
633
|
+
const set = (key, value) => {
|
|
634
|
+
if (value !== void 0 && value !== "") params.set(key, value);
|
|
635
|
+
};
|
|
636
|
+
set("scope", ctx.scope);
|
|
637
|
+
set("path", ctx.path);
|
|
638
|
+
set("host", ctx.host);
|
|
639
|
+
set("os", ctx.os);
|
|
640
|
+
set("osv", ctx.osVersion);
|
|
641
|
+
set("arch", ctx.arch);
|
|
642
|
+
set("user", ctx.user);
|
|
643
|
+
set("device", ctx.device);
|
|
644
|
+
set("cli", ctx.cli);
|
|
645
|
+
if (ctx.harnesses.length > 0) params.set("harnesses", ctx.harnesses.join(","));
|
|
646
|
+
set("launcher", ctx.launcher);
|
|
647
|
+
return params;
|
|
648
|
+
}
|
|
649
|
+
function describeInstallContext(ctx) {
|
|
650
|
+
const lines = [`scope: ${ctx.scope}`];
|
|
651
|
+
if (ctx.path) lines.push(`path: ${ctx.path}`);
|
|
652
|
+
if (ctx.host || ctx.os) {
|
|
653
|
+
const osPart = [ctx.os, ctx.osVersion].filter(Boolean).join(" ");
|
|
654
|
+
const detail = [osPart, ctx.arch].filter(Boolean).join(", ");
|
|
655
|
+
lines.push(`machine: ${ctx.host ?? "unknown"}${detail ? ` (${detail})` : ""}`);
|
|
656
|
+
}
|
|
657
|
+
if (ctx.user) lines.push(`user: ${ctx.user}`);
|
|
658
|
+
if (ctx.device) lines.push(`device: ${ctx.device}`);
|
|
659
|
+
if (ctx.harnesses.length > 0) lines.push(`harnesses: ${ctx.harnesses.join(", ")}`);
|
|
660
|
+
if (ctx.launcher) lines.push(`launched by: ${ctx.launcher}`);
|
|
661
|
+
if (ctx.cli) lines.push(`cli: ${ctx.cli}`);
|
|
662
|
+
return lines.join("\n");
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/lib/caller.ts
|
|
666
|
+
var CALLER_SOURCE_HEADER = "x-one-source";
|
|
667
|
+
var CALLER_AGENT_HEADER = "x-one-agent";
|
|
668
|
+
function callerHeaders(env = process.env) {
|
|
669
|
+
const headers = { [CALLER_SOURCE_HEADER]: "cli" };
|
|
670
|
+
const launcher = detectLauncher(env);
|
|
671
|
+
if (launcher) headers[CALLER_AGENT_HEADER] = launcher;
|
|
672
|
+
return headers;
|
|
673
|
+
}
|
|
21
674
|
|
|
22
675
|
// src/lib/api.ts
|
|
23
676
|
import { createWriteStream } from "fs";
|
|
@@ -74,8 +727,8 @@ var OneApi = class {
|
|
|
74
727
|
this.apiBase = apiBase ?? "https://api.withone.ai/v1";
|
|
75
728
|
}
|
|
76
729
|
apiBase;
|
|
77
|
-
async request(
|
|
78
|
-
return this.requestFull({ path:
|
|
730
|
+
async request(path7) {
|
|
731
|
+
return this.requestFull({ path: path7 });
|
|
79
732
|
}
|
|
80
733
|
async requestFull(opts) {
|
|
81
734
|
let url = `${this.apiBase}${opts.path}`;
|
|
@@ -104,6 +757,20 @@ var OneApi = class {
|
|
|
104
757
|
if (!text) return {};
|
|
105
758
|
return JSON.parse(text);
|
|
106
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* The calling key's own access, as One enforces it: `GET /v1/access/me`.
|
|
762
|
+
* Resolves `null` for a key with no restrictions. Throws `ApiError` when the
|
|
763
|
+
* API does not answer it (for example an older backend without the route).
|
|
764
|
+
*/
|
|
765
|
+
async getOwnAccess() {
|
|
766
|
+
const body = await this.request("/access/me");
|
|
767
|
+
if (body === null) return null;
|
|
768
|
+
if (typeof body !== "object" || !("rules" in body || "methods" in body)) {
|
|
769
|
+
throw new ApiError(502, "Unexpected answer from /access/me");
|
|
770
|
+
}
|
|
771
|
+
const doc = body;
|
|
772
|
+
return { methods: doc.methods ?? null, rules: doc.rules ?? null };
|
|
773
|
+
}
|
|
107
774
|
async whoami() {
|
|
108
775
|
return this.request("/users/whoami");
|
|
109
776
|
}
|
|
@@ -300,6 +967,9 @@ var OneApi = class {
|
|
|
300
967
|
"x-one-action-id": action._id,
|
|
301
968
|
"Content-Type": contentType,
|
|
302
969
|
Accept: "application/json, text/event-stream, */*",
|
|
970
|
+
// Who is calling, for the Logs page. Before the caller's own headers so
|
|
971
|
+
// an explicit --headers value still wins.
|
|
972
|
+
...callerHeaders(),
|
|
303
973
|
...args.headers
|
|
304
974
|
};
|
|
305
975
|
const finalActionPath = args.pathVariables ? replacePathVariables(action.path, args.pathVariables) : action.path;
|
|
@@ -508,9 +1178,9 @@ var TimeoutError = class extends Error {
|
|
|
508
1178
|
function sleep(ms) {
|
|
509
1179
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
510
1180
|
}
|
|
511
|
-
function replacePathVariables(
|
|
512
|
-
if (!
|
|
513
|
-
let result =
|
|
1181
|
+
function replacePathVariables(path7, variables) {
|
|
1182
|
+
if (!path7) return path7;
|
|
1183
|
+
let result = path7;
|
|
514
1184
|
result = result.replace(/\{\{([^}]+)\}\}/g, (_match, variable) => {
|
|
515
1185
|
const trimmedVariable = variable.trim();
|
|
516
1186
|
const value = variables[trimmedVariable];
|
|
@@ -544,23 +1214,23 @@ function isActionAllowed(actionId, allowedActionIds) {
|
|
|
544
1214
|
}
|
|
545
1215
|
|
|
546
1216
|
// src/lib/cache.ts
|
|
547
|
-
import
|
|
548
|
-
import
|
|
1217
|
+
import fs3 from "fs";
|
|
1218
|
+
import path4 from "path";
|
|
549
1219
|
function knowledgeDir() {
|
|
550
|
-
return
|
|
1220
|
+
return path4.join(homeDir(), ".one", "cache", "knowledge");
|
|
551
1221
|
}
|
|
552
1222
|
function legacySearchDir() {
|
|
553
|
-
return
|
|
1223
|
+
return path4.join(homeDir(), ".one", "cache", "search");
|
|
554
1224
|
}
|
|
555
1225
|
function sanitizeFilename(input) {
|
|
556
1226
|
return input.replace(/[^a-zA-Z0-9_\-\.]/g, "_");
|
|
557
1227
|
}
|
|
558
1228
|
function knowledgeCachePath(actionId) {
|
|
559
|
-
return
|
|
1229
|
+
return path4.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
|
|
560
1230
|
}
|
|
561
1231
|
function readCache(filePath) {
|
|
562
1232
|
try {
|
|
563
|
-
const content =
|
|
1233
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
564
1234
|
return JSON.parse(content);
|
|
565
1235
|
} catch {
|
|
566
1236
|
return null;
|
|
@@ -568,9 +1238,9 @@ function readCache(filePath) {
|
|
|
568
1238
|
}
|
|
569
1239
|
function writeCache(filePath, entry) {
|
|
570
1240
|
try {
|
|
571
|
-
const dir =
|
|
572
|
-
|
|
573
|
-
|
|
1241
|
+
const dir = path4.dirname(filePath);
|
|
1242
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1243
|
+
fs3.writeFileSync(filePath, JSON.stringify(entry, null, 2));
|
|
574
1244
|
} catch {
|
|
575
1245
|
}
|
|
576
1246
|
}
|
|
@@ -597,9 +1267,9 @@ function formatAge(seconds) {
|
|
|
597
1267
|
function listCacheEntries() {
|
|
598
1268
|
const entries = [];
|
|
599
1269
|
try {
|
|
600
|
-
for (const file of
|
|
1270
|
+
for (const file of fs3.readdirSync(knowledgeDir())) {
|
|
601
1271
|
if (!file.endsWith(".json")) continue;
|
|
602
|
-
const filePath =
|
|
1272
|
+
const filePath = path4.join(knowledgeDir(), file);
|
|
603
1273
|
const entry = readCache(filePath);
|
|
604
1274
|
if (entry) {
|
|
605
1275
|
entries.push({ type: "knowledge", filePath, entry });
|
|
@@ -613,12 +1283,12 @@ function clearAll() {
|
|
|
613
1283
|
let count = 0;
|
|
614
1284
|
for (const dir of [knowledgeDir(), legacySearchDir()]) {
|
|
615
1285
|
try {
|
|
616
|
-
const files =
|
|
1286
|
+
const files = fs3.readdirSync(dir);
|
|
617
1287
|
for (const file of files) {
|
|
618
|
-
|
|
1288
|
+
fs3.unlinkSync(path4.join(dir, file));
|
|
619
1289
|
count++;
|
|
620
1290
|
}
|
|
621
|
-
|
|
1291
|
+
fs3.rmdirSync(dir);
|
|
622
1292
|
} catch {
|
|
623
1293
|
}
|
|
624
1294
|
}
|
|
@@ -627,7 +1297,7 @@ function clearAll() {
|
|
|
627
1297
|
function clearEntry(actionId) {
|
|
628
1298
|
const filePath = knowledgeCachePath(actionId);
|
|
629
1299
|
try {
|
|
630
|
-
|
|
1300
|
+
fs3.unlinkSync(filePath);
|
|
631
1301
|
return true;
|
|
632
1302
|
} catch {
|
|
633
1303
|
return false;
|
|
@@ -655,27 +1325,27 @@ async function resolveActionDetails(api, actionId, opts = {}) {
|
|
|
655
1325
|
});
|
|
656
1326
|
const cachePath = knowledgeCachePath(actionId);
|
|
657
1327
|
const raw = useCache ? readCache(cachePath) : null;
|
|
658
|
-
const
|
|
659
|
-
if (
|
|
660
|
-
return { details:
|
|
1328
|
+
const cached2 = isActionDetailsEntry(raw) ? raw : null;
|
|
1329
|
+
if (cached2 && isFresh(cached2)) {
|
|
1330
|
+
return { details: cached2.data, cacheHit: true, stale: false, entry: cached2 };
|
|
661
1331
|
}
|
|
662
1332
|
try {
|
|
663
|
-
const result = await api.getActionDetailsWithMeta(actionId,
|
|
664
|
-
if (result.status === 304 &&
|
|
665
|
-
|
|
666
|
-
writeCache(cachePath,
|
|
667
|
-
return { details:
|
|
1333
|
+
const result = await api.getActionDetailsWithMeta(actionId, cached2?.etag ?? void 0);
|
|
1334
|
+
if (result.status === 304 && cached2) {
|
|
1335
|
+
cached2.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1336
|
+
writeCache(cachePath, cached2);
|
|
1337
|
+
return { details: cached2.data, cacheHit: true, stale: false, entry: cached2 };
|
|
668
1338
|
}
|
|
669
1339
|
const entry = makeCacheEntry(actionId, result.data, result.etag);
|
|
670
1340
|
writeCache(cachePath, entry);
|
|
671
1341
|
return { details: result.data, cacheHit: false, stale: false, entry };
|
|
672
1342
|
} catch (fetchError) {
|
|
673
|
-
if (
|
|
1343
|
+
if (cached2) {
|
|
674
1344
|
warn(
|
|
675
|
-
`Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(
|
|
1345
|
+
`Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached2))} ago)
|
|
676
1346
|
`
|
|
677
1347
|
);
|
|
678
|
-
return { details:
|
|
1348
|
+
return { details: cached2.data, cacheHit: true, stale: true, entry: cached2 };
|
|
679
1349
|
}
|
|
680
1350
|
throw fetchError;
|
|
681
1351
|
}
|
|
@@ -1550,48 +2220,48 @@ function collectFileReadViolations(value, schema, basePath, out) {
|
|
|
1550
2220
|
const obj = value;
|
|
1551
2221
|
for (const [field, raw] of Object.entries(schema)) {
|
|
1552
2222
|
const rule = asFieldSchema(raw);
|
|
1553
|
-
const
|
|
2223
|
+
const path7 = `${basePath}${field}`;
|
|
1554
2224
|
const present = Object.prototype.hasOwnProperty.call(obj, field) && obj[field] !== void 0;
|
|
1555
2225
|
if (!present) {
|
|
1556
|
-
if (rule.required) out.push(`field "${
|
|
2226
|
+
if (rule.required) out.push(`field "${path7}" is required but missing`);
|
|
1557
2227
|
continue;
|
|
1558
2228
|
}
|
|
1559
|
-
checkFileReadRule(obj[field], rule,
|
|
2229
|
+
checkFileReadRule(obj[field], rule, path7, out);
|
|
1560
2230
|
}
|
|
1561
2231
|
}
|
|
1562
|
-
function checkFileReadRule(value, rule,
|
|
2232
|
+
function checkFileReadRule(value, rule, path7, out) {
|
|
1563
2233
|
if (rule.type && !matchesLeafType(value, rule.type)) {
|
|
1564
|
-
out.push(`field "${
|
|
2234
|
+
out.push(`field "${path7}" expected ${rule.type} but got ${actualType(value)}`);
|
|
1565
2235
|
return;
|
|
1566
2236
|
}
|
|
1567
2237
|
if (Array.isArray(rule.enum) && !rule.enum.some((e) => e === value)) {
|
|
1568
|
-
out.push(`field "${
|
|
2238
|
+
out.push(`field "${path7}" value ${JSON.stringify(value)} is not one of [${rule.enum.map((e) => JSON.stringify(e)).join(", ")}]`);
|
|
1569
2239
|
}
|
|
1570
2240
|
const hasArrayConstraint = rule.items !== void 0 || rule.minItems !== void 0 || rule.maxItems !== void 0 || rule.length !== void 0;
|
|
1571
2241
|
if (hasArrayConstraint) {
|
|
1572
2242
|
if (!Array.isArray(value)) {
|
|
1573
|
-
if (!rule.type) out.push(`field "${
|
|
2243
|
+
if (!rule.type) out.push(`field "${path7}" expected array but got ${actualType(value)}`);
|
|
1574
2244
|
} else {
|
|
1575
2245
|
if (rule.length !== void 0 && value.length !== rule.length) {
|
|
1576
|
-
out.push(`field "${
|
|
2246
|
+
out.push(`field "${path7}" expected array of length ${rule.length} but got length ${value.length}`);
|
|
1577
2247
|
}
|
|
1578
2248
|
if (rule.minItems !== void 0 && value.length < rule.minItems) {
|
|
1579
|
-
out.push(`field "${
|
|
2249
|
+
out.push(`field "${path7}" expected at least ${rule.minItems} item${rule.minItems === 1 ? "" : "s"} but got ${value.length}`);
|
|
1580
2250
|
}
|
|
1581
2251
|
if (rule.maxItems !== void 0 && value.length > rule.maxItems) {
|
|
1582
|
-
out.push(`field "${
|
|
2252
|
+
out.push(`field "${path7}" expected at most ${rule.maxItems} item${rule.maxItems === 1 ? "" : "s"} but got ${value.length}`);
|
|
1583
2253
|
}
|
|
1584
2254
|
if (rule.items !== void 0) {
|
|
1585
2255
|
const itemRule = asFieldSchema(rule.items);
|
|
1586
|
-
value.forEach((el, i) => checkFileReadRule(el, itemRule, `${
|
|
2256
|
+
value.forEach((el, i) => checkFileReadRule(el, itemRule, `${path7}[${i}]`, out));
|
|
1587
2257
|
}
|
|
1588
2258
|
}
|
|
1589
2259
|
}
|
|
1590
2260
|
if (rule.properties) {
|
|
1591
2261
|
if (isPlainObjectValue(value)) {
|
|
1592
|
-
collectFileReadViolations(value, rule.properties, `${
|
|
2262
|
+
collectFileReadViolations(value, rule.properties, `${path7}.`, out);
|
|
1593
2263
|
} else if (!rule.type) {
|
|
1594
|
-
out.push(`field "${
|
|
2264
|
+
out.push(`field "${path7}" expected object but got ${actualType(value)}`);
|
|
1595
2265
|
}
|
|
1596
2266
|
}
|
|
1597
2267
|
}
|
|
@@ -2069,15 +2739,15 @@ async function executeCodeModule(stepId, modulePath, context, options) {
|
|
|
2069
2739
|
if (!rootDir) {
|
|
2070
2740
|
throw new Error(`Code step "${stepId}" uses module "${modulePath}" but no flow rootDir is available. Flows that use code modules must be loaded via loadFlowWithMeta.`);
|
|
2071
2741
|
}
|
|
2072
|
-
if (
|
|
2742
|
+
if (path5.isAbsolute(modulePath)) {
|
|
2073
2743
|
throw new Error(`Code module path must be relative to the flow root, got absolute: "${modulePath}"`);
|
|
2074
2744
|
}
|
|
2075
|
-
const absPath =
|
|
2076
|
-
const relFromRoot =
|
|
2077
|
-
if (relFromRoot.startsWith("..") ||
|
|
2745
|
+
const absPath = path5.resolve(rootDir, modulePath);
|
|
2746
|
+
const relFromRoot = path5.relative(rootDir, absPath);
|
|
2747
|
+
if (relFromRoot.startsWith("..") || path5.isAbsolute(relFromRoot)) {
|
|
2078
2748
|
throw new Error(`Code module "${modulePath}" resolves outside the flow directory`);
|
|
2079
2749
|
}
|
|
2080
|
-
if (!
|
|
2750
|
+
if (!fs4.existsSync(absPath)) {
|
|
2081
2751
|
throw new Error(`Code module not found: ${absPath}`);
|
|
2082
2752
|
}
|
|
2083
2753
|
const { env: _omitEnv, ...safeContext } = context;
|
|
@@ -2225,8 +2895,8 @@ async function executeParallelStep(step, context, api, permissions, allowedActio
|
|
|
2225
2895
|
function executeFileReadStep(step, context) {
|
|
2226
2896
|
const config = step.fileRead;
|
|
2227
2897
|
const filePath = resolveValue(config.path, context);
|
|
2228
|
-
const resolvedPath =
|
|
2229
|
-
const content =
|
|
2898
|
+
const resolvedPath = path5.resolve(filePath);
|
|
2899
|
+
const content = fs4.readFileSync(resolvedPath, "utf-8");
|
|
2230
2900
|
const output = config.parseJson ? JSON.parse(stripCodeFences(content)) : content;
|
|
2231
2901
|
if (config.parseJson && config.schema) {
|
|
2232
2902
|
assertMatchesFileReadSchema(output, config.schema, step.id);
|
|
@@ -2237,16 +2907,16 @@ function executeFileWriteStep(step, context) {
|
|
|
2237
2907
|
const config = step.fileWrite;
|
|
2238
2908
|
const filePath = resolveValue(config.path, context);
|
|
2239
2909
|
const content = resolveValue(config.content, context);
|
|
2240
|
-
const resolvedPath =
|
|
2241
|
-
const dir =
|
|
2242
|
-
if (!
|
|
2243
|
-
|
|
2910
|
+
const resolvedPath = path5.resolve(filePath);
|
|
2911
|
+
const dir = path5.dirname(resolvedPath);
|
|
2912
|
+
if (!fs4.existsSync(dir)) {
|
|
2913
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
2244
2914
|
}
|
|
2245
2915
|
const stringContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
2246
2916
|
if (config.append) {
|
|
2247
|
-
|
|
2917
|
+
fs4.appendFileSync(resolvedPath, stringContent);
|
|
2248
2918
|
} else {
|
|
2249
|
-
|
|
2919
|
+
fs4.writeFileSync(resolvedPath, stringContent);
|
|
2250
2920
|
}
|
|
2251
2921
|
return { status: "success", output: { path: resolvedPath, bytesWritten: stringContent.length }, response: { path: resolvedPath } };
|
|
2252
2922
|
}
|
|
@@ -2285,7 +2955,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
2285
2955
|
if (flowStack.includes(resolvedKey)) {
|
|
2286
2956
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
2287
2957
|
}
|
|
2288
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
2958
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-FME4AVVN.js");
|
|
2289
2959
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
2290
2960
|
const subContext = await executeFlow(
|
|
2291
2961
|
subFlow,
|
|
@@ -2388,11 +3058,11 @@ function resolveBashEnv(envConfig, context, stepId) {
|
|
|
2388
3058
|
if ("json" in obj) {
|
|
2389
3059
|
const resolved2 = resolveValue(obj.json, context);
|
|
2390
3060
|
const json = JSON.stringify(resolved2 ?? null);
|
|
2391
|
-
const tmp =
|
|
2392
|
-
|
|
3061
|
+
const tmp = path5.join(
|
|
3062
|
+
os2.tmpdir(),
|
|
2393
3063
|
`one-flow-${stepId}-${key}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`
|
|
2394
3064
|
);
|
|
2395
|
-
|
|
3065
|
+
fs4.writeFileSync(tmp, json, { encoding: "utf-8" });
|
|
2396
3066
|
tempFiles.push(tmp);
|
|
2397
3067
|
out[key] = tmp;
|
|
2398
3068
|
continue;
|
|
@@ -2439,7 +3109,7 @@ async function executeBashStep(step, context, options) {
|
|
|
2439
3109
|
} finally {
|
|
2440
3110
|
for (const tmp of tempFiles) {
|
|
2441
3111
|
try {
|
|
2442
|
-
|
|
3112
|
+
fs4.unlinkSync(tmp);
|
|
2443
3113
|
} catch {
|
|
2444
3114
|
}
|
|
2445
3115
|
}
|
|
@@ -2829,8 +3499,8 @@ var FLOWS_DIR = ".one/flows";
|
|
|
2829
3499
|
var RUNS_DIR = ".one/flows/.runs";
|
|
2830
3500
|
var LOGS_DIR = ".one/flows/.logs";
|
|
2831
3501
|
function ensureDir(dir) {
|
|
2832
|
-
if (!
|
|
2833
|
-
|
|
3502
|
+
if (!fs5.existsSync(dir)) {
|
|
3503
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
2834
3504
|
}
|
|
2835
3505
|
}
|
|
2836
3506
|
function generateRunId() {
|
|
@@ -2851,8 +3521,8 @@ var FlowRunner = class _FlowRunner {
|
|
|
2851
3521
|
this.flowKey = flow.key;
|
|
2852
3522
|
ensureDir(RUNS_DIR);
|
|
2853
3523
|
ensureDir(LOGS_DIR);
|
|
2854
|
-
this.statePath =
|
|
2855
|
-
this.logPath =
|
|
3524
|
+
this.statePath = path6.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
|
|
3525
|
+
this.logPath = path6.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
|
|
2856
3526
|
const resolvedInputs = { ...inputs };
|
|
2857
3527
|
for (const [name, decl] of Object.entries(flow.inputs)) {
|
|
2858
3528
|
if (resolvedInputs[name] === void 0 && decl.default !== void 0) {
|
|
@@ -2893,10 +3563,10 @@ var FlowRunner = class _FlowRunner {
|
|
|
2893
3563
|
msg,
|
|
2894
3564
|
...data
|
|
2895
3565
|
};
|
|
2896
|
-
|
|
3566
|
+
fs5.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
|
|
2897
3567
|
}
|
|
2898
3568
|
saveState() {
|
|
2899
|
-
|
|
3569
|
+
fs5.writeFileSync(this.statePath, JSON.stringify(this.state, stripStepsAlias, 2));
|
|
2900
3570
|
}
|
|
2901
3571
|
createEventHandler(externalHandler) {
|
|
2902
3572
|
return (event) => {
|
|
@@ -2994,14 +3664,14 @@ var FlowRunner = class _FlowRunner {
|
|
|
2994
3664
|
}
|
|
2995
3665
|
/** Path to a run's persisted state file. The post-mortem artifact surfaced by `one flow inspect`. */
|
|
2996
3666
|
static statePathFor(flowKey, runId) {
|
|
2997
|
-
return
|
|
3667
|
+
return path6.join(RUNS_DIR, `${flowKey}-${runId}.state.json`);
|
|
2998
3668
|
}
|
|
2999
3669
|
static loadRunState(runId) {
|
|
3000
3670
|
ensureDir(RUNS_DIR);
|
|
3001
|
-
const files =
|
|
3671
|
+
const files = fs5.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
|
|
3002
3672
|
if (files.length === 0) return null;
|
|
3003
3673
|
try {
|
|
3004
|
-
const content =
|
|
3674
|
+
const content = fs5.readFileSync(path6.join(RUNS_DIR, files[0]), "utf-8");
|
|
3005
3675
|
return JSON.parse(content);
|
|
3006
3676
|
} catch {
|
|
3007
3677
|
return null;
|
|
@@ -3013,17 +3683,17 @@ var FlowRunner = class _FlowRunner {
|
|
|
3013
3683
|
runner.flowKey = state.flowKey;
|
|
3014
3684
|
runner.state = state;
|
|
3015
3685
|
runner.paused = false;
|
|
3016
|
-
runner.statePath =
|
|
3017
|
-
runner.logPath =
|
|
3686
|
+
runner.statePath = path6.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
|
|
3687
|
+
runner.logPath = path6.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
|
|
3018
3688
|
return runner;
|
|
3019
3689
|
}
|
|
3020
3690
|
static listRuns(flowKey) {
|
|
3021
3691
|
ensureDir(RUNS_DIR);
|
|
3022
|
-
const files =
|
|
3692
|
+
const files = fs5.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
|
|
3023
3693
|
const runs = [];
|
|
3024
3694
|
for (const file of files) {
|
|
3025
3695
|
try {
|
|
3026
|
-
const content =
|
|
3696
|
+
const content = fs5.readFileSync(path6.join(RUNS_DIR, file), "utf-8");
|
|
3027
3697
|
const state = JSON.parse(content);
|
|
3028
3698
|
if (!flowKey || state.flowKey === flowKey) {
|
|
3029
3699
|
runs.push(state);
|
|
@@ -3036,44 +3706,44 @@ var FlowRunner = class _FlowRunner {
|
|
|
3036
3706
|
};
|
|
3037
3707
|
function resolveFlowPath(keyOrPath) {
|
|
3038
3708
|
if (keyOrPath.endsWith(".json")) {
|
|
3039
|
-
return
|
|
3709
|
+
return path6.resolve(keyOrPath);
|
|
3040
3710
|
}
|
|
3041
3711
|
if (keyOrPath.includes("\\")) {
|
|
3042
|
-
return
|
|
3712
|
+
return path6.resolve(keyOrPath);
|
|
3043
3713
|
}
|
|
3044
3714
|
if (keyOrPath.includes("/")) {
|
|
3045
|
-
const nestedFolder =
|
|
3046
|
-
if (
|
|
3047
|
-
const literal =
|
|
3048
|
-
if (
|
|
3715
|
+
const nestedFolder = path6.resolve(FLOWS_DIR, keyOrPath, "flow.json");
|
|
3716
|
+
if (fs5.existsSync(nestedFolder)) return nestedFolder;
|
|
3717
|
+
const literal = path6.resolve(keyOrPath);
|
|
3718
|
+
if (fs5.existsSync(literal)) return literal;
|
|
3049
3719
|
return nestedFolder;
|
|
3050
3720
|
}
|
|
3051
|
-
const folderPath =
|
|
3052
|
-
if (
|
|
3053
|
-
const legacyPath =
|
|
3054
|
-
if (
|
|
3055
|
-
const flowsDir =
|
|
3056
|
-
if (
|
|
3057
|
-
for (const entry of
|
|
3721
|
+
const folderPath = path6.resolve(FLOWS_DIR, keyOrPath, "flow.json");
|
|
3722
|
+
if (fs5.existsSync(folderPath)) return folderPath;
|
|
3723
|
+
const legacyPath = path6.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
|
|
3724
|
+
if (fs5.existsSync(legacyPath)) return legacyPath;
|
|
3725
|
+
const flowsDir = path6.resolve(FLOWS_DIR);
|
|
3726
|
+
if (fs5.existsSync(flowsDir)) {
|
|
3727
|
+
for (const entry of fs5.readdirSync(flowsDir, { withFileTypes: true })) {
|
|
3058
3728
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
3059
|
-
const nested =
|
|
3060
|
-
if (
|
|
3729
|
+
const nested = path6.join(flowsDir, entry.name, keyOrPath, "flow.json");
|
|
3730
|
+
if (fs5.existsSync(nested)) return nested;
|
|
3061
3731
|
}
|
|
3062
3732
|
}
|
|
3063
3733
|
return folderPath;
|
|
3064
3734
|
}
|
|
3065
3735
|
function getFlowRootDir(flowFilePath) {
|
|
3066
|
-
const dir =
|
|
3067
|
-
const base =
|
|
3736
|
+
const dir = path6.dirname(flowFilePath);
|
|
3737
|
+
const base = path6.basename(flowFilePath);
|
|
3068
3738
|
if (base === "flow.json") return dir;
|
|
3069
3739
|
return dir;
|
|
3070
3740
|
}
|
|
3071
3741
|
function loadFlowWithMeta(keyOrPath) {
|
|
3072
3742
|
const filePath = resolveFlowPath(keyOrPath);
|
|
3073
|
-
if (!
|
|
3743
|
+
if (!fs5.existsSync(filePath)) {
|
|
3074
3744
|
throw new Error(`Flow not found: ${filePath}`);
|
|
3075
3745
|
}
|
|
3076
|
-
const content =
|
|
3746
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
3077
3747
|
const flow = JSON.parse(content);
|
|
3078
3748
|
return { flow, filePath, rootDir: getFlowRootDir(filePath) };
|
|
3079
3749
|
}
|
|
@@ -3120,13 +3790,13 @@ function summarizeFlowInputs(flow) {
|
|
|
3120
3790
|
}));
|
|
3121
3791
|
}
|
|
3122
3792
|
function listFlows() {
|
|
3123
|
-
const flowsDir =
|
|
3124
|
-
if (!
|
|
3793
|
+
const flowsDir = path6.resolve(FLOWS_DIR);
|
|
3794
|
+
if (!fs5.existsSync(flowsDir)) return [];
|
|
3125
3795
|
const flows = [];
|
|
3126
3796
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
3127
3797
|
const readFlowFile = (filePath, group) => {
|
|
3128
3798
|
try {
|
|
3129
|
-
const content =
|
|
3799
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
3130
3800
|
const flow = JSON.parse(content);
|
|
3131
3801
|
const nsKey = group ? `${group}/${flow.key}` : flow.key;
|
|
3132
3802
|
if (seenKeys.has(nsKey)) return;
|
|
@@ -3138,7 +3808,7 @@ function listFlows() {
|
|
|
3138
3808
|
inputCount: Object.keys(flow.inputs).length,
|
|
3139
3809
|
stepCount: flow.steps.length,
|
|
3140
3810
|
path: filePath,
|
|
3141
|
-
layout:
|
|
3811
|
+
layout: path6.basename(filePath) === "flow.json" ? "folder" : "legacy",
|
|
3142
3812
|
group,
|
|
3143
3813
|
stepTypes: collectStepTypes(flow),
|
|
3144
3814
|
requiresBash: flowRequiresBash(flow),
|
|
@@ -3149,12 +3819,12 @@ function listFlows() {
|
|
|
3149
3819
|
}
|
|
3150
3820
|
};
|
|
3151
3821
|
const scanDir = (dir, group) => {
|
|
3152
|
-
for (const entry of
|
|
3822
|
+
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
3153
3823
|
if (entry.name.startsWith(".")) continue;
|
|
3154
|
-
const full =
|
|
3824
|
+
const full = path6.join(dir, entry.name);
|
|
3155
3825
|
if (entry.isDirectory()) {
|
|
3156
|
-
const flowJson =
|
|
3157
|
-
if (
|
|
3826
|
+
const flowJson = path6.join(full, "flow.json");
|
|
3827
|
+
if (fs5.existsSync(flowJson)) {
|
|
3158
3828
|
readFlowFile(flowJson, group);
|
|
3159
3829
|
} else {
|
|
3160
3830
|
if (!group) {
|
|
@@ -3172,7 +3842,7 @@ function listFlows() {
|
|
|
3172
3842
|
function saveFlow(flow, outputPath, group) {
|
|
3173
3843
|
let flowPath;
|
|
3174
3844
|
if (outputPath) {
|
|
3175
|
-
flowPath =
|
|
3845
|
+
flowPath = path6.resolve(outputPath);
|
|
3176
3846
|
} else {
|
|
3177
3847
|
let bareKey = flow.key;
|
|
3178
3848
|
let resolvedGroup = group;
|
|
@@ -3182,25 +3852,36 @@ function saveFlow(flow, outputPath, group) {
|
|
|
3182
3852
|
resolvedGroup = resolvedGroup || parts.join("/");
|
|
3183
3853
|
flow.key = bareKey;
|
|
3184
3854
|
}
|
|
3185
|
-
const basePath = resolvedGroup ?
|
|
3186
|
-
const legacyPath =
|
|
3187
|
-
const folderPath =
|
|
3188
|
-
if (!resolvedGroup &&
|
|
3855
|
+
const basePath = resolvedGroup ? path6.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path6.resolve(FLOWS_DIR, bareKey);
|
|
3856
|
+
const legacyPath = path6.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
|
|
3857
|
+
const folderPath = path6.join(basePath, "flow.json");
|
|
3858
|
+
if (!resolvedGroup && fs5.existsSync(legacyPath) && !fs5.existsSync(folderPath)) {
|
|
3189
3859
|
flowPath = legacyPath;
|
|
3190
3860
|
} else {
|
|
3191
3861
|
flowPath = folderPath;
|
|
3192
3862
|
}
|
|
3193
3863
|
}
|
|
3194
|
-
const dir =
|
|
3864
|
+
const dir = path6.dirname(flowPath);
|
|
3195
3865
|
ensureDir(dir);
|
|
3196
|
-
if (
|
|
3197
|
-
ensureDir(
|
|
3866
|
+
if (path6.basename(flowPath) === "flow.json") {
|
|
3867
|
+
ensureDir(path6.join(dir, "lib"));
|
|
3198
3868
|
}
|
|
3199
|
-
|
|
3869
|
+
fs5.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
|
|
3200
3870
|
return flowPath;
|
|
3201
3871
|
}
|
|
3202
3872
|
|
|
3203
3873
|
export {
|
|
3874
|
+
installMcpConfig,
|
|
3875
|
+
getAgentStatuses,
|
|
3876
|
+
cliVersion,
|
|
3877
|
+
recordCommand,
|
|
3878
|
+
flushUsageRollups,
|
|
3879
|
+
drainQueue,
|
|
3880
|
+
flush,
|
|
3881
|
+
maybeShowTelemetryNotice,
|
|
3882
|
+
collectInstallContext,
|
|
3883
|
+
installContextToParams,
|
|
3884
|
+
describeInstallContext,
|
|
3204
3885
|
ApiError,
|
|
3205
3886
|
OneApi,
|
|
3206
3887
|
TimeoutError,
|