@withone/cli 2.5.0 → 2.7.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 +3 -1
- 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-MRQ47KSZ.js → chunk-UP2L4XJH.js} +792 -119
- package/dist/{chunk-NOFJ4NYD.js → chunk-VMFWA43Q.js} +5 -77
- package/dist/{flow-runner-4A5ANCTT.js → flow-runner-K73VDSS3.js} +2 -1
- package/dist/index.js +697 -1321
- 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 +1 -1
|
@@ -3,21 +3,677 @@ 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
|
+
var CALLER_MODEL_HEADER = "x-one-agent-model";
|
|
669
|
+
function callerHeaders(env = process.env, model) {
|
|
670
|
+
const headers = { [CALLER_SOURCE_HEADER]: "cli" };
|
|
671
|
+
const launcher = detectLauncher(env);
|
|
672
|
+
if (launcher) headers[CALLER_AGENT_HEADER] = launcher;
|
|
673
|
+
const declared = model?.trim();
|
|
674
|
+
if (declared) headers[CALLER_MODEL_HEADER] = declared;
|
|
675
|
+
return headers;
|
|
676
|
+
}
|
|
21
677
|
|
|
22
678
|
// src/lib/api.ts
|
|
23
679
|
import { createWriteStream } from "fs";
|
|
@@ -74,8 +730,8 @@ var OneApi = class {
|
|
|
74
730
|
this.apiBase = apiBase ?? "https://api.withone.ai/v1";
|
|
75
731
|
}
|
|
76
732
|
apiBase;
|
|
77
|
-
async request(
|
|
78
|
-
return this.requestFull({ path:
|
|
733
|
+
async request(path7) {
|
|
734
|
+
return this.requestFull({ path: path7 });
|
|
79
735
|
}
|
|
80
736
|
async requestFull(opts) {
|
|
81
737
|
let url = `${this.apiBase}${opts.path}`;
|
|
@@ -228,13 +884,16 @@ var OneApi = class {
|
|
|
228
884
|
/**
|
|
229
885
|
* The action for each intent, across platforms, in one call: search plus
|
|
230
886
|
* One's decision model, which picks among the candidates. Core caps a call
|
|
231
|
-
* at 10 intents and refuses more with a 400 naming the cap.
|
|
887
|
+
* at 10 intents and refuses more with a 400 naming the cap. `aiModel` is the
|
|
888
|
+
* model the agent says it is running as, sent beside the CLI and harness.
|
|
232
889
|
*/
|
|
233
|
-
async findActions(requests, task, knowledgeAgent) {
|
|
890
|
+
async findActions(requests, task, knowledgeAgent, aiModel) {
|
|
234
891
|
const response = await this.requestFull({
|
|
235
892
|
path: "/available-actions/find",
|
|
236
893
|
method: "POST",
|
|
237
|
-
body: { requests, ...task ? { task } : {}, knowledgeAgent }
|
|
894
|
+
body: { requests, ...task ? { task } : {}, knowledgeAgent },
|
|
895
|
+
// Who asked, for the record of what agents ask a find.
|
|
896
|
+
headers: callerHeaders(process.env, aiModel)
|
|
238
897
|
});
|
|
239
898
|
return Array.isArray(response) ? response : [];
|
|
240
899
|
}
|
|
@@ -314,6 +973,9 @@ var OneApi = class {
|
|
|
314
973
|
"x-one-action-id": action._id,
|
|
315
974
|
"Content-Type": contentType,
|
|
316
975
|
Accept: "application/json, text/event-stream, */*",
|
|
976
|
+
// Who is calling, for the Logs page. Before the caller's own headers so
|
|
977
|
+
// an explicit --headers value still wins.
|
|
978
|
+
...callerHeaders(),
|
|
317
979
|
...args.headers
|
|
318
980
|
};
|
|
319
981
|
const finalActionPath = args.pathVariables ? replacePathVariables(action.path, args.pathVariables) : action.path;
|
|
@@ -522,9 +1184,9 @@ var TimeoutError = class extends Error {
|
|
|
522
1184
|
function sleep(ms) {
|
|
523
1185
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
524
1186
|
}
|
|
525
|
-
function replacePathVariables(
|
|
526
|
-
if (!
|
|
527
|
-
let result =
|
|
1187
|
+
function replacePathVariables(path7, variables) {
|
|
1188
|
+
if (!path7) return path7;
|
|
1189
|
+
let result = path7;
|
|
528
1190
|
result = result.replace(/\{\{([^}]+)\}\}/g, (_match, variable) => {
|
|
529
1191
|
const trimmedVariable = variable.trim();
|
|
530
1192
|
const value = variables[trimmedVariable];
|
|
@@ -558,23 +1220,23 @@ function isActionAllowed(actionId, allowedActionIds) {
|
|
|
558
1220
|
}
|
|
559
1221
|
|
|
560
1222
|
// src/lib/cache.ts
|
|
561
|
-
import
|
|
562
|
-
import
|
|
1223
|
+
import fs3 from "fs";
|
|
1224
|
+
import path4 from "path";
|
|
563
1225
|
function knowledgeDir() {
|
|
564
|
-
return
|
|
1226
|
+
return path4.join(homeDir(), ".one", "cache", "knowledge");
|
|
565
1227
|
}
|
|
566
1228
|
function legacySearchDir() {
|
|
567
|
-
return
|
|
1229
|
+
return path4.join(homeDir(), ".one", "cache", "search");
|
|
568
1230
|
}
|
|
569
1231
|
function sanitizeFilename(input) {
|
|
570
1232
|
return input.replace(/[^a-zA-Z0-9_\-\.]/g, "_");
|
|
571
1233
|
}
|
|
572
1234
|
function knowledgeCachePath(actionId) {
|
|
573
|
-
return
|
|
1235
|
+
return path4.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
|
|
574
1236
|
}
|
|
575
1237
|
function readCache(filePath) {
|
|
576
1238
|
try {
|
|
577
|
-
const content =
|
|
1239
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
578
1240
|
return JSON.parse(content);
|
|
579
1241
|
} catch {
|
|
580
1242
|
return null;
|
|
@@ -582,9 +1244,9 @@ function readCache(filePath) {
|
|
|
582
1244
|
}
|
|
583
1245
|
function writeCache(filePath, entry) {
|
|
584
1246
|
try {
|
|
585
|
-
const dir =
|
|
586
|
-
|
|
587
|
-
|
|
1247
|
+
const dir = path4.dirname(filePath);
|
|
1248
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1249
|
+
fs3.writeFileSync(filePath, JSON.stringify(entry, null, 2));
|
|
588
1250
|
} catch {
|
|
589
1251
|
}
|
|
590
1252
|
}
|
|
@@ -611,9 +1273,9 @@ function formatAge(seconds) {
|
|
|
611
1273
|
function listCacheEntries() {
|
|
612
1274
|
const entries = [];
|
|
613
1275
|
try {
|
|
614
|
-
for (const file of
|
|
1276
|
+
for (const file of fs3.readdirSync(knowledgeDir())) {
|
|
615
1277
|
if (!file.endsWith(".json")) continue;
|
|
616
|
-
const filePath =
|
|
1278
|
+
const filePath = path4.join(knowledgeDir(), file);
|
|
617
1279
|
const entry = readCache(filePath);
|
|
618
1280
|
if (entry) {
|
|
619
1281
|
entries.push({ type: "knowledge", filePath, entry });
|
|
@@ -627,12 +1289,12 @@ function clearAll() {
|
|
|
627
1289
|
let count = 0;
|
|
628
1290
|
for (const dir of [knowledgeDir(), legacySearchDir()]) {
|
|
629
1291
|
try {
|
|
630
|
-
const files =
|
|
1292
|
+
const files = fs3.readdirSync(dir);
|
|
631
1293
|
for (const file of files) {
|
|
632
|
-
|
|
1294
|
+
fs3.unlinkSync(path4.join(dir, file));
|
|
633
1295
|
count++;
|
|
634
1296
|
}
|
|
635
|
-
|
|
1297
|
+
fs3.rmdirSync(dir);
|
|
636
1298
|
} catch {
|
|
637
1299
|
}
|
|
638
1300
|
}
|
|
@@ -641,7 +1303,7 @@ function clearAll() {
|
|
|
641
1303
|
function clearEntry(actionId) {
|
|
642
1304
|
const filePath = knowledgeCachePath(actionId);
|
|
643
1305
|
try {
|
|
644
|
-
|
|
1306
|
+
fs3.unlinkSync(filePath);
|
|
645
1307
|
return true;
|
|
646
1308
|
} catch {
|
|
647
1309
|
return false;
|
|
@@ -669,27 +1331,27 @@ async function resolveActionDetails(api, actionId, opts = {}) {
|
|
|
669
1331
|
});
|
|
670
1332
|
const cachePath = knowledgeCachePath(actionId);
|
|
671
1333
|
const raw = useCache ? readCache(cachePath) : null;
|
|
672
|
-
const
|
|
673
|
-
if (
|
|
674
|
-
return { details:
|
|
1334
|
+
const cached2 = isActionDetailsEntry(raw) ? raw : null;
|
|
1335
|
+
if (cached2 && isFresh(cached2)) {
|
|
1336
|
+
return { details: cached2.data, cacheHit: true, stale: false, entry: cached2 };
|
|
675
1337
|
}
|
|
676
1338
|
try {
|
|
677
|
-
const result = await api.getActionDetailsWithMeta(actionId,
|
|
678
|
-
if (result.status === 304 &&
|
|
679
|
-
|
|
680
|
-
writeCache(cachePath,
|
|
681
|
-
return { details:
|
|
1339
|
+
const result = await api.getActionDetailsWithMeta(actionId, cached2?.etag ?? void 0);
|
|
1340
|
+
if (result.status === 304 && cached2) {
|
|
1341
|
+
cached2.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1342
|
+
writeCache(cachePath, cached2);
|
|
1343
|
+
return { details: cached2.data, cacheHit: true, stale: false, entry: cached2 };
|
|
682
1344
|
}
|
|
683
1345
|
const entry = makeCacheEntry(actionId, result.data, result.etag);
|
|
684
1346
|
writeCache(cachePath, entry);
|
|
685
1347
|
return { details: result.data, cacheHit: false, stale: false, entry };
|
|
686
1348
|
} catch (fetchError) {
|
|
687
|
-
if (
|
|
1349
|
+
if (cached2) {
|
|
688
1350
|
warn(
|
|
689
|
-
`Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(
|
|
1351
|
+
`Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached2))} ago)
|
|
690
1352
|
`
|
|
691
1353
|
);
|
|
692
|
-
return { details:
|
|
1354
|
+
return { details: cached2.data, cacheHit: true, stale: true, entry: cached2 };
|
|
693
1355
|
}
|
|
694
1356
|
throw fetchError;
|
|
695
1357
|
}
|
|
@@ -1564,48 +2226,48 @@ function collectFileReadViolations(value, schema, basePath, out) {
|
|
|
1564
2226
|
const obj = value;
|
|
1565
2227
|
for (const [field, raw] of Object.entries(schema)) {
|
|
1566
2228
|
const rule = asFieldSchema(raw);
|
|
1567
|
-
const
|
|
2229
|
+
const path7 = `${basePath}${field}`;
|
|
1568
2230
|
const present = Object.prototype.hasOwnProperty.call(obj, field) && obj[field] !== void 0;
|
|
1569
2231
|
if (!present) {
|
|
1570
|
-
if (rule.required) out.push(`field "${
|
|
2232
|
+
if (rule.required) out.push(`field "${path7}" is required but missing`);
|
|
1571
2233
|
continue;
|
|
1572
2234
|
}
|
|
1573
|
-
checkFileReadRule(obj[field], rule,
|
|
2235
|
+
checkFileReadRule(obj[field], rule, path7, out);
|
|
1574
2236
|
}
|
|
1575
2237
|
}
|
|
1576
|
-
function checkFileReadRule(value, rule,
|
|
2238
|
+
function checkFileReadRule(value, rule, path7, out) {
|
|
1577
2239
|
if (rule.type && !matchesLeafType(value, rule.type)) {
|
|
1578
|
-
out.push(`field "${
|
|
2240
|
+
out.push(`field "${path7}" expected ${rule.type} but got ${actualType(value)}`);
|
|
1579
2241
|
return;
|
|
1580
2242
|
}
|
|
1581
2243
|
if (Array.isArray(rule.enum) && !rule.enum.some((e) => e === value)) {
|
|
1582
|
-
out.push(`field "${
|
|
2244
|
+
out.push(`field "${path7}" value ${JSON.stringify(value)} is not one of [${rule.enum.map((e) => JSON.stringify(e)).join(", ")}]`);
|
|
1583
2245
|
}
|
|
1584
2246
|
const hasArrayConstraint = rule.items !== void 0 || rule.minItems !== void 0 || rule.maxItems !== void 0 || rule.length !== void 0;
|
|
1585
2247
|
if (hasArrayConstraint) {
|
|
1586
2248
|
if (!Array.isArray(value)) {
|
|
1587
|
-
if (!rule.type) out.push(`field "${
|
|
2249
|
+
if (!rule.type) out.push(`field "${path7}" expected array but got ${actualType(value)}`);
|
|
1588
2250
|
} else {
|
|
1589
2251
|
if (rule.length !== void 0 && value.length !== rule.length) {
|
|
1590
|
-
out.push(`field "${
|
|
2252
|
+
out.push(`field "${path7}" expected array of length ${rule.length} but got length ${value.length}`);
|
|
1591
2253
|
}
|
|
1592
2254
|
if (rule.minItems !== void 0 && value.length < rule.minItems) {
|
|
1593
|
-
out.push(`field "${
|
|
2255
|
+
out.push(`field "${path7}" expected at least ${rule.minItems} item${rule.minItems === 1 ? "" : "s"} but got ${value.length}`);
|
|
1594
2256
|
}
|
|
1595
2257
|
if (rule.maxItems !== void 0 && value.length > rule.maxItems) {
|
|
1596
|
-
out.push(`field "${
|
|
2258
|
+
out.push(`field "${path7}" expected at most ${rule.maxItems} item${rule.maxItems === 1 ? "" : "s"} but got ${value.length}`);
|
|
1597
2259
|
}
|
|
1598
2260
|
if (rule.items !== void 0) {
|
|
1599
2261
|
const itemRule = asFieldSchema(rule.items);
|
|
1600
|
-
value.forEach((el, i) => checkFileReadRule(el, itemRule, `${
|
|
2262
|
+
value.forEach((el, i) => checkFileReadRule(el, itemRule, `${path7}[${i}]`, out));
|
|
1601
2263
|
}
|
|
1602
2264
|
}
|
|
1603
2265
|
}
|
|
1604
2266
|
if (rule.properties) {
|
|
1605
2267
|
if (isPlainObjectValue(value)) {
|
|
1606
|
-
collectFileReadViolations(value, rule.properties, `${
|
|
2268
|
+
collectFileReadViolations(value, rule.properties, `${path7}.`, out);
|
|
1607
2269
|
} else if (!rule.type) {
|
|
1608
|
-
out.push(`field "${
|
|
2270
|
+
out.push(`field "${path7}" expected object but got ${actualType(value)}`);
|
|
1609
2271
|
}
|
|
1610
2272
|
}
|
|
1611
2273
|
}
|
|
@@ -2083,15 +2745,15 @@ async function executeCodeModule(stepId, modulePath, context, options) {
|
|
|
2083
2745
|
if (!rootDir) {
|
|
2084
2746
|
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.`);
|
|
2085
2747
|
}
|
|
2086
|
-
if (
|
|
2748
|
+
if (path5.isAbsolute(modulePath)) {
|
|
2087
2749
|
throw new Error(`Code module path must be relative to the flow root, got absolute: "${modulePath}"`);
|
|
2088
2750
|
}
|
|
2089
|
-
const absPath =
|
|
2090
|
-
const relFromRoot =
|
|
2091
|
-
if (relFromRoot.startsWith("..") ||
|
|
2751
|
+
const absPath = path5.resolve(rootDir, modulePath);
|
|
2752
|
+
const relFromRoot = path5.relative(rootDir, absPath);
|
|
2753
|
+
if (relFromRoot.startsWith("..") || path5.isAbsolute(relFromRoot)) {
|
|
2092
2754
|
throw new Error(`Code module "${modulePath}" resolves outside the flow directory`);
|
|
2093
2755
|
}
|
|
2094
|
-
if (!
|
|
2756
|
+
if (!fs4.existsSync(absPath)) {
|
|
2095
2757
|
throw new Error(`Code module not found: ${absPath}`);
|
|
2096
2758
|
}
|
|
2097
2759
|
const { env: _omitEnv, ...safeContext } = context;
|
|
@@ -2239,8 +2901,8 @@ async function executeParallelStep(step, context, api, permissions, allowedActio
|
|
|
2239
2901
|
function executeFileReadStep(step, context) {
|
|
2240
2902
|
const config = step.fileRead;
|
|
2241
2903
|
const filePath = resolveValue(config.path, context);
|
|
2242
|
-
const resolvedPath =
|
|
2243
|
-
const content =
|
|
2904
|
+
const resolvedPath = path5.resolve(filePath);
|
|
2905
|
+
const content = fs4.readFileSync(resolvedPath, "utf-8");
|
|
2244
2906
|
const output = config.parseJson ? JSON.parse(stripCodeFences(content)) : content;
|
|
2245
2907
|
if (config.parseJson && config.schema) {
|
|
2246
2908
|
assertMatchesFileReadSchema(output, config.schema, step.id);
|
|
@@ -2251,16 +2913,16 @@ function executeFileWriteStep(step, context) {
|
|
|
2251
2913
|
const config = step.fileWrite;
|
|
2252
2914
|
const filePath = resolveValue(config.path, context);
|
|
2253
2915
|
const content = resolveValue(config.content, context);
|
|
2254
|
-
const resolvedPath =
|
|
2255
|
-
const dir =
|
|
2256
|
-
if (!
|
|
2257
|
-
|
|
2916
|
+
const resolvedPath = path5.resolve(filePath);
|
|
2917
|
+
const dir = path5.dirname(resolvedPath);
|
|
2918
|
+
if (!fs4.existsSync(dir)) {
|
|
2919
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
2258
2920
|
}
|
|
2259
2921
|
const stringContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
2260
2922
|
if (config.append) {
|
|
2261
|
-
|
|
2923
|
+
fs4.appendFileSync(resolvedPath, stringContent);
|
|
2262
2924
|
} else {
|
|
2263
|
-
|
|
2925
|
+
fs4.writeFileSync(resolvedPath, stringContent);
|
|
2264
2926
|
}
|
|
2265
2927
|
return { status: "success", output: { path: resolvedPath, bytesWritten: stringContent.length }, response: { path: resolvedPath } };
|
|
2266
2928
|
}
|
|
@@ -2299,7 +2961,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
2299
2961
|
if (flowStack.includes(resolvedKey)) {
|
|
2300
2962
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
2301
2963
|
}
|
|
2302
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
2964
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-K73VDSS3.js");
|
|
2303
2965
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
2304
2966
|
const subContext = await executeFlow(
|
|
2305
2967
|
subFlow,
|
|
@@ -2402,11 +3064,11 @@ function resolveBashEnv(envConfig, context, stepId) {
|
|
|
2402
3064
|
if ("json" in obj) {
|
|
2403
3065
|
const resolved2 = resolveValue(obj.json, context);
|
|
2404
3066
|
const json = JSON.stringify(resolved2 ?? null);
|
|
2405
|
-
const tmp =
|
|
2406
|
-
|
|
3067
|
+
const tmp = path5.join(
|
|
3068
|
+
os2.tmpdir(),
|
|
2407
3069
|
`one-flow-${stepId}-${key}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`
|
|
2408
3070
|
);
|
|
2409
|
-
|
|
3071
|
+
fs4.writeFileSync(tmp, json, { encoding: "utf-8" });
|
|
2410
3072
|
tempFiles.push(tmp);
|
|
2411
3073
|
out[key] = tmp;
|
|
2412
3074
|
continue;
|
|
@@ -2453,7 +3115,7 @@ async function executeBashStep(step, context, options) {
|
|
|
2453
3115
|
} finally {
|
|
2454
3116
|
for (const tmp of tempFiles) {
|
|
2455
3117
|
try {
|
|
2456
|
-
|
|
3118
|
+
fs4.unlinkSync(tmp);
|
|
2457
3119
|
} catch {
|
|
2458
3120
|
}
|
|
2459
3121
|
}
|
|
@@ -2843,8 +3505,8 @@ var FLOWS_DIR = ".one/flows";
|
|
|
2843
3505
|
var RUNS_DIR = ".one/flows/.runs";
|
|
2844
3506
|
var LOGS_DIR = ".one/flows/.logs";
|
|
2845
3507
|
function ensureDir(dir) {
|
|
2846
|
-
if (!
|
|
2847
|
-
|
|
3508
|
+
if (!fs5.existsSync(dir)) {
|
|
3509
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
2848
3510
|
}
|
|
2849
3511
|
}
|
|
2850
3512
|
function generateRunId() {
|
|
@@ -2865,8 +3527,8 @@ var FlowRunner = class _FlowRunner {
|
|
|
2865
3527
|
this.flowKey = flow.key;
|
|
2866
3528
|
ensureDir(RUNS_DIR);
|
|
2867
3529
|
ensureDir(LOGS_DIR);
|
|
2868
|
-
this.statePath =
|
|
2869
|
-
this.logPath =
|
|
3530
|
+
this.statePath = path6.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
|
|
3531
|
+
this.logPath = path6.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
|
|
2870
3532
|
const resolvedInputs = { ...inputs };
|
|
2871
3533
|
for (const [name, decl] of Object.entries(flow.inputs)) {
|
|
2872
3534
|
if (resolvedInputs[name] === void 0 && decl.default !== void 0) {
|
|
@@ -2907,10 +3569,10 @@ var FlowRunner = class _FlowRunner {
|
|
|
2907
3569
|
msg,
|
|
2908
3570
|
...data
|
|
2909
3571
|
};
|
|
2910
|
-
|
|
3572
|
+
fs5.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
|
|
2911
3573
|
}
|
|
2912
3574
|
saveState() {
|
|
2913
|
-
|
|
3575
|
+
fs5.writeFileSync(this.statePath, JSON.stringify(this.state, stripStepsAlias, 2));
|
|
2914
3576
|
}
|
|
2915
3577
|
createEventHandler(externalHandler) {
|
|
2916
3578
|
return (event) => {
|
|
@@ -3008,14 +3670,14 @@ var FlowRunner = class _FlowRunner {
|
|
|
3008
3670
|
}
|
|
3009
3671
|
/** Path to a run's persisted state file. The post-mortem artifact surfaced by `one flow inspect`. */
|
|
3010
3672
|
static statePathFor(flowKey, runId) {
|
|
3011
|
-
return
|
|
3673
|
+
return path6.join(RUNS_DIR, `${flowKey}-${runId}.state.json`);
|
|
3012
3674
|
}
|
|
3013
3675
|
static loadRunState(runId) {
|
|
3014
3676
|
ensureDir(RUNS_DIR);
|
|
3015
|
-
const files =
|
|
3677
|
+
const files = fs5.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
|
|
3016
3678
|
if (files.length === 0) return null;
|
|
3017
3679
|
try {
|
|
3018
|
-
const content =
|
|
3680
|
+
const content = fs5.readFileSync(path6.join(RUNS_DIR, files[0]), "utf-8");
|
|
3019
3681
|
return JSON.parse(content);
|
|
3020
3682
|
} catch {
|
|
3021
3683
|
return null;
|
|
@@ -3027,17 +3689,17 @@ var FlowRunner = class _FlowRunner {
|
|
|
3027
3689
|
runner.flowKey = state.flowKey;
|
|
3028
3690
|
runner.state = state;
|
|
3029
3691
|
runner.paused = false;
|
|
3030
|
-
runner.statePath =
|
|
3031
|
-
runner.logPath =
|
|
3692
|
+
runner.statePath = path6.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
|
|
3693
|
+
runner.logPath = path6.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
|
|
3032
3694
|
return runner;
|
|
3033
3695
|
}
|
|
3034
3696
|
static listRuns(flowKey) {
|
|
3035
3697
|
ensureDir(RUNS_DIR);
|
|
3036
|
-
const files =
|
|
3698
|
+
const files = fs5.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
|
|
3037
3699
|
const runs = [];
|
|
3038
3700
|
for (const file of files) {
|
|
3039
3701
|
try {
|
|
3040
|
-
const content =
|
|
3702
|
+
const content = fs5.readFileSync(path6.join(RUNS_DIR, file), "utf-8");
|
|
3041
3703
|
const state = JSON.parse(content);
|
|
3042
3704
|
if (!flowKey || state.flowKey === flowKey) {
|
|
3043
3705
|
runs.push(state);
|
|
@@ -3050,44 +3712,44 @@ var FlowRunner = class _FlowRunner {
|
|
|
3050
3712
|
};
|
|
3051
3713
|
function resolveFlowPath(keyOrPath) {
|
|
3052
3714
|
if (keyOrPath.endsWith(".json")) {
|
|
3053
|
-
return
|
|
3715
|
+
return path6.resolve(keyOrPath);
|
|
3054
3716
|
}
|
|
3055
3717
|
if (keyOrPath.includes("\\")) {
|
|
3056
|
-
return
|
|
3718
|
+
return path6.resolve(keyOrPath);
|
|
3057
3719
|
}
|
|
3058
3720
|
if (keyOrPath.includes("/")) {
|
|
3059
|
-
const nestedFolder =
|
|
3060
|
-
if (
|
|
3061
|
-
const literal =
|
|
3062
|
-
if (
|
|
3721
|
+
const nestedFolder = path6.resolve(FLOWS_DIR, keyOrPath, "flow.json");
|
|
3722
|
+
if (fs5.existsSync(nestedFolder)) return nestedFolder;
|
|
3723
|
+
const literal = path6.resolve(keyOrPath);
|
|
3724
|
+
if (fs5.existsSync(literal)) return literal;
|
|
3063
3725
|
return nestedFolder;
|
|
3064
3726
|
}
|
|
3065
|
-
const folderPath =
|
|
3066
|
-
if (
|
|
3067
|
-
const legacyPath =
|
|
3068
|
-
if (
|
|
3069
|
-
const flowsDir =
|
|
3070
|
-
if (
|
|
3071
|
-
for (const entry of
|
|
3727
|
+
const folderPath = path6.resolve(FLOWS_DIR, keyOrPath, "flow.json");
|
|
3728
|
+
if (fs5.existsSync(folderPath)) return folderPath;
|
|
3729
|
+
const legacyPath = path6.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
|
|
3730
|
+
if (fs5.existsSync(legacyPath)) return legacyPath;
|
|
3731
|
+
const flowsDir = path6.resolve(FLOWS_DIR);
|
|
3732
|
+
if (fs5.existsSync(flowsDir)) {
|
|
3733
|
+
for (const entry of fs5.readdirSync(flowsDir, { withFileTypes: true })) {
|
|
3072
3734
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
3073
|
-
const nested =
|
|
3074
|
-
if (
|
|
3735
|
+
const nested = path6.join(flowsDir, entry.name, keyOrPath, "flow.json");
|
|
3736
|
+
if (fs5.existsSync(nested)) return nested;
|
|
3075
3737
|
}
|
|
3076
3738
|
}
|
|
3077
3739
|
return folderPath;
|
|
3078
3740
|
}
|
|
3079
3741
|
function getFlowRootDir(flowFilePath) {
|
|
3080
|
-
const dir =
|
|
3081
|
-
const base =
|
|
3742
|
+
const dir = path6.dirname(flowFilePath);
|
|
3743
|
+
const base = path6.basename(flowFilePath);
|
|
3082
3744
|
if (base === "flow.json") return dir;
|
|
3083
3745
|
return dir;
|
|
3084
3746
|
}
|
|
3085
3747
|
function loadFlowWithMeta(keyOrPath) {
|
|
3086
3748
|
const filePath = resolveFlowPath(keyOrPath);
|
|
3087
|
-
if (!
|
|
3749
|
+
if (!fs5.existsSync(filePath)) {
|
|
3088
3750
|
throw new Error(`Flow not found: ${filePath}`);
|
|
3089
3751
|
}
|
|
3090
|
-
const content =
|
|
3752
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
3091
3753
|
const flow = JSON.parse(content);
|
|
3092
3754
|
return { flow, filePath, rootDir: getFlowRootDir(filePath) };
|
|
3093
3755
|
}
|
|
@@ -3134,13 +3796,13 @@ function summarizeFlowInputs(flow) {
|
|
|
3134
3796
|
}));
|
|
3135
3797
|
}
|
|
3136
3798
|
function listFlows() {
|
|
3137
|
-
const flowsDir =
|
|
3138
|
-
if (!
|
|
3799
|
+
const flowsDir = path6.resolve(FLOWS_DIR);
|
|
3800
|
+
if (!fs5.existsSync(flowsDir)) return [];
|
|
3139
3801
|
const flows = [];
|
|
3140
3802
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
3141
3803
|
const readFlowFile = (filePath, group) => {
|
|
3142
3804
|
try {
|
|
3143
|
-
const content =
|
|
3805
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
3144
3806
|
const flow = JSON.parse(content);
|
|
3145
3807
|
const nsKey = group ? `${group}/${flow.key}` : flow.key;
|
|
3146
3808
|
if (seenKeys.has(nsKey)) return;
|
|
@@ -3152,7 +3814,7 @@ function listFlows() {
|
|
|
3152
3814
|
inputCount: Object.keys(flow.inputs).length,
|
|
3153
3815
|
stepCount: flow.steps.length,
|
|
3154
3816
|
path: filePath,
|
|
3155
|
-
layout:
|
|
3817
|
+
layout: path6.basename(filePath) === "flow.json" ? "folder" : "legacy",
|
|
3156
3818
|
group,
|
|
3157
3819
|
stepTypes: collectStepTypes(flow),
|
|
3158
3820
|
requiresBash: flowRequiresBash(flow),
|
|
@@ -3163,12 +3825,12 @@ function listFlows() {
|
|
|
3163
3825
|
}
|
|
3164
3826
|
};
|
|
3165
3827
|
const scanDir = (dir, group) => {
|
|
3166
|
-
for (const entry of
|
|
3828
|
+
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
3167
3829
|
if (entry.name.startsWith(".")) continue;
|
|
3168
|
-
const full =
|
|
3830
|
+
const full = path6.join(dir, entry.name);
|
|
3169
3831
|
if (entry.isDirectory()) {
|
|
3170
|
-
const flowJson =
|
|
3171
|
-
if (
|
|
3832
|
+
const flowJson = path6.join(full, "flow.json");
|
|
3833
|
+
if (fs5.existsSync(flowJson)) {
|
|
3172
3834
|
readFlowFile(flowJson, group);
|
|
3173
3835
|
} else {
|
|
3174
3836
|
if (!group) {
|
|
@@ -3186,7 +3848,7 @@ function listFlows() {
|
|
|
3186
3848
|
function saveFlow(flow, outputPath, group) {
|
|
3187
3849
|
let flowPath;
|
|
3188
3850
|
if (outputPath) {
|
|
3189
|
-
flowPath =
|
|
3851
|
+
flowPath = path6.resolve(outputPath);
|
|
3190
3852
|
} else {
|
|
3191
3853
|
let bareKey = flow.key;
|
|
3192
3854
|
let resolvedGroup = group;
|
|
@@ -3196,25 +3858,36 @@ function saveFlow(flow, outputPath, group) {
|
|
|
3196
3858
|
resolvedGroup = resolvedGroup || parts.join("/");
|
|
3197
3859
|
flow.key = bareKey;
|
|
3198
3860
|
}
|
|
3199
|
-
const basePath = resolvedGroup ?
|
|
3200
|
-
const legacyPath =
|
|
3201
|
-
const folderPath =
|
|
3202
|
-
if (!resolvedGroup &&
|
|
3861
|
+
const basePath = resolvedGroup ? path6.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path6.resolve(FLOWS_DIR, bareKey);
|
|
3862
|
+
const legacyPath = path6.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
|
|
3863
|
+
const folderPath = path6.join(basePath, "flow.json");
|
|
3864
|
+
if (!resolvedGroup && fs5.existsSync(legacyPath) && !fs5.existsSync(folderPath)) {
|
|
3203
3865
|
flowPath = legacyPath;
|
|
3204
3866
|
} else {
|
|
3205
3867
|
flowPath = folderPath;
|
|
3206
3868
|
}
|
|
3207
3869
|
}
|
|
3208
|
-
const dir =
|
|
3870
|
+
const dir = path6.dirname(flowPath);
|
|
3209
3871
|
ensureDir(dir);
|
|
3210
|
-
if (
|
|
3211
|
-
ensureDir(
|
|
3872
|
+
if (path6.basename(flowPath) === "flow.json") {
|
|
3873
|
+
ensureDir(path6.join(dir, "lib"));
|
|
3212
3874
|
}
|
|
3213
|
-
|
|
3875
|
+
fs5.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
|
|
3214
3876
|
return flowPath;
|
|
3215
3877
|
}
|
|
3216
3878
|
|
|
3217
3879
|
export {
|
|
3880
|
+
installMcpConfig,
|
|
3881
|
+
getAgentStatuses,
|
|
3882
|
+
cliVersion,
|
|
3883
|
+
recordCommand,
|
|
3884
|
+
flushUsageRollups,
|
|
3885
|
+
drainQueue,
|
|
3886
|
+
flush,
|
|
3887
|
+
maybeShowTelemetryNotice,
|
|
3888
|
+
collectInstallContext,
|
|
3889
|
+
installContextToParams,
|
|
3890
|
+
describeInstallContext,
|
|
3218
3891
|
ApiError,
|
|
3219
3892
|
OneApi,
|
|
3220
3893
|
TimeoutError,
|