@withone/cli 2.5.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.
@@ -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
- homeDir
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 fs3 from "fs";
12
- import path3 from "path";
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 { exec, spawn } from "child_process";
20
- import { promisify } from "util";
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(path4) {
78
- return this.requestFull({ path: path4 });
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}`;
@@ -314,6 +967,9 @@ var OneApi = class {
314
967
  "x-one-action-id": action._id,
315
968
  "Content-Type": contentType,
316
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(),
317
973
  ...args.headers
318
974
  };
319
975
  const finalActionPath = args.pathVariables ? replacePathVariables(action.path, args.pathVariables) : action.path;
@@ -522,9 +1178,9 @@ var TimeoutError = class extends Error {
522
1178
  function sleep(ms) {
523
1179
  return new Promise((resolve2) => setTimeout(resolve2, ms));
524
1180
  }
525
- function replacePathVariables(path4, variables) {
526
- if (!path4) return path4;
527
- let result = path4;
1181
+ function replacePathVariables(path7, variables) {
1182
+ if (!path7) return path7;
1183
+ let result = path7;
528
1184
  result = result.replace(/\{\{([^}]+)\}\}/g, (_match, variable) => {
529
1185
  const trimmedVariable = variable.trim();
530
1186
  const value = variables[trimmedVariable];
@@ -558,23 +1214,23 @@ function isActionAllowed(actionId, allowedActionIds) {
558
1214
  }
559
1215
 
560
1216
  // src/lib/cache.ts
561
- import fs from "fs";
562
- import path from "path";
1217
+ import fs3 from "fs";
1218
+ import path4 from "path";
563
1219
  function knowledgeDir() {
564
- return path.join(homeDir(), ".one", "cache", "knowledge");
1220
+ return path4.join(homeDir(), ".one", "cache", "knowledge");
565
1221
  }
566
1222
  function legacySearchDir() {
567
- return path.join(homeDir(), ".one", "cache", "search");
1223
+ return path4.join(homeDir(), ".one", "cache", "search");
568
1224
  }
569
1225
  function sanitizeFilename(input) {
570
1226
  return input.replace(/[^a-zA-Z0-9_\-\.]/g, "_");
571
1227
  }
572
1228
  function knowledgeCachePath(actionId) {
573
- return path.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
1229
+ return path4.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
574
1230
  }
575
1231
  function readCache(filePath) {
576
1232
  try {
577
- const content = fs.readFileSync(filePath, "utf-8");
1233
+ const content = fs3.readFileSync(filePath, "utf-8");
578
1234
  return JSON.parse(content);
579
1235
  } catch {
580
1236
  return null;
@@ -582,9 +1238,9 @@ function readCache(filePath) {
582
1238
  }
583
1239
  function writeCache(filePath, entry) {
584
1240
  try {
585
- const dir = path.dirname(filePath);
586
- fs.mkdirSync(dir, { recursive: true });
587
- fs.writeFileSync(filePath, JSON.stringify(entry, null, 2));
1241
+ const dir = path4.dirname(filePath);
1242
+ fs3.mkdirSync(dir, { recursive: true });
1243
+ fs3.writeFileSync(filePath, JSON.stringify(entry, null, 2));
588
1244
  } catch {
589
1245
  }
590
1246
  }
@@ -611,9 +1267,9 @@ function formatAge(seconds) {
611
1267
  function listCacheEntries() {
612
1268
  const entries = [];
613
1269
  try {
614
- for (const file of fs.readdirSync(knowledgeDir())) {
1270
+ for (const file of fs3.readdirSync(knowledgeDir())) {
615
1271
  if (!file.endsWith(".json")) continue;
616
- const filePath = path.join(knowledgeDir(), file);
1272
+ const filePath = path4.join(knowledgeDir(), file);
617
1273
  const entry = readCache(filePath);
618
1274
  if (entry) {
619
1275
  entries.push({ type: "knowledge", filePath, entry });
@@ -627,12 +1283,12 @@ function clearAll() {
627
1283
  let count = 0;
628
1284
  for (const dir of [knowledgeDir(), legacySearchDir()]) {
629
1285
  try {
630
- const files = fs.readdirSync(dir);
1286
+ const files = fs3.readdirSync(dir);
631
1287
  for (const file of files) {
632
- fs.unlinkSync(path.join(dir, file));
1288
+ fs3.unlinkSync(path4.join(dir, file));
633
1289
  count++;
634
1290
  }
635
- fs.rmdirSync(dir);
1291
+ fs3.rmdirSync(dir);
636
1292
  } catch {
637
1293
  }
638
1294
  }
@@ -641,7 +1297,7 @@ function clearAll() {
641
1297
  function clearEntry(actionId) {
642
1298
  const filePath = knowledgeCachePath(actionId);
643
1299
  try {
644
- fs.unlinkSync(filePath);
1300
+ fs3.unlinkSync(filePath);
645
1301
  return true;
646
1302
  } catch {
647
1303
  return false;
@@ -669,27 +1325,27 @@ async function resolveActionDetails(api, actionId, opts = {}) {
669
1325
  });
670
1326
  const cachePath = knowledgeCachePath(actionId);
671
1327
  const raw = useCache ? readCache(cachePath) : null;
672
- const cached = isActionDetailsEntry(raw) ? raw : null;
673
- if (cached && isFresh(cached)) {
674
- return { details: cached.data, cacheHit: true, stale: false, entry: cached };
1328
+ const cached2 = isActionDetailsEntry(raw) ? raw : null;
1329
+ if (cached2 && isFresh(cached2)) {
1330
+ return { details: cached2.data, cacheHit: true, stale: false, entry: cached2 };
675
1331
  }
676
1332
  try {
677
- const result = await api.getActionDetailsWithMeta(actionId, cached?.etag ?? void 0);
678
- if (result.status === 304 && cached) {
679
- cached.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
680
- writeCache(cachePath, cached);
681
- return { details: cached.data, cacheHit: true, stale: false, entry: cached };
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 };
682
1338
  }
683
1339
  const entry = makeCacheEntry(actionId, result.data, result.etag);
684
1340
  writeCache(cachePath, entry);
685
1341
  return { details: result.data, cacheHit: false, stale: false, entry };
686
1342
  } catch (fetchError) {
687
- if (cached) {
1343
+ if (cached2) {
688
1344
  warn(
689
- `Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached))} ago)
1345
+ `Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached2))} ago)
690
1346
  `
691
1347
  );
692
- return { details: cached.data, cacheHit: true, stale: true, entry: cached };
1348
+ return { details: cached2.data, cacheHit: true, stale: true, entry: cached2 };
693
1349
  }
694
1350
  throw fetchError;
695
1351
  }
@@ -1564,48 +2220,48 @@ function collectFileReadViolations(value, schema, basePath, out) {
1564
2220
  const obj = value;
1565
2221
  for (const [field, raw] of Object.entries(schema)) {
1566
2222
  const rule = asFieldSchema(raw);
1567
- const path4 = `${basePath}${field}`;
2223
+ const path7 = `${basePath}${field}`;
1568
2224
  const present = Object.prototype.hasOwnProperty.call(obj, field) && obj[field] !== void 0;
1569
2225
  if (!present) {
1570
- if (rule.required) out.push(`field "${path4}" is required but missing`);
2226
+ if (rule.required) out.push(`field "${path7}" is required but missing`);
1571
2227
  continue;
1572
2228
  }
1573
- checkFileReadRule(obj[field], rule, path4, out);
2229
+ checkFileReadRule(obj[field], rule, path7, out);
1574
2230
  }
1575
2231
  }
1576
- function checkFileReadRule(value, rule, path4, out) {
2232
+ function checkFileReadRule(value, rule, path7, out) {
1577
2233
  if (rule.type && !matchesLeafType(value, rule.type)) {
1578
- out.push(`field "${path4}" expected ${rule.type} but got ${actualType(value)}`);
2234
+ out.push(`field "${path7}" expected ${rule.type} but got ${actualType(value)}`);
1579
2235
  return;
1580
2236
  }
1581
2237
  if (Array.isArray(rule.enum) && !rule.enum.some((e) => e === value)) {
1582
- out.push(`field "${path4}" value ${JSON.stringify(value)} is not one of [${rule.enum.map((e) => JSON.stringify(e)).join(", ")}]`);
2238
+ out.push(`field "${path7}" value ${JSON.stringify(value)} is not one of [${rule.enum.map((e) => JSON.stringify(e)).join(", ")}]`);
1583
2239
  }
1584
2240
  const hasArrayConstraint = rule.items !== void 0 || rule.minItems !== void 0 || rule.maxItems !== void 0 || rule.length !== void 0;
1585
2241
  if (hasArrayConstraint) {
1586
2242
  if (!Array.isArray(value)) {
1587
- if (!rule.type) out.push(`field "${path4}" expected array but got ${actualType(value)}`);
2243
+ if (!rule.type) out.push(`field "${path7}" expected array but got ${actualType(value)}`);
1588
2244
  } else {
1589
2245
  if (rule.length !== void 0 && value.length !== rule.length) {
1590
- out.push(`field "${path4}" expected array of length ${rule.length} but got length ${value.length}`);
2246
+ out.push(`field "${path7}" expected array of length ${rule.length} but got length ${value.length}`);
1591
2247
  }
1592
2248
  if (rule.minItems !== void 0 && value.length < rule.minItems) {
1593
- out.push(`field "${path4}" expected at least ${rule.minItems} item${rule.minItems === 1 ? "" : "s"} but got ${value.length}`);
2249
+ out.push(`field "${path7}" expected at least ${rule.minItems} item${rule.minItems === 1 ? "" : "s"} but got ${value.length}`);
1594
2250
  }
1595
2251
  if (rule.maxItems !== void 0 && value.length > rule.maxItems) {
1596
- out.push(`field "${path4}" expected at most ${rule.maxItems} item${rule.maxItems === 1 ? "" : "s"} but got ${value.length}`);
2252
+ out.push(`field "${path7}" expected at most ${rule.maxItems} item${rule.maxItems === 1 ? "" : "s"} but got ${value.length}`);
1597
2253
  }
1598
2254
  if (rule.items !== void 0) {
1599
2255
  const itemRule = asFieldSchema(rule.items);
1600
- value.forEach((el, i) => checkFileReadRule(el, itemRule, `${path4}[${i}]`, out));
2256
+ value.forEach((el, i) => checkFileReadRule(el, itemRule, `${path7}[${i}]`, out));
1601
2257
  }
1602
2258
  }
1603
2259
  }
1604
2260
  if (rule.properties) {
1605
2261
  if (isPlainObjectValue(value)) {
1606
- collectFileReadViolations(value, rule.properties, `${path4}.`, out);
2262
+ collectFileReadViolations(value, rule.properties, `${path7}.`, out);
1607
2263
  } else if (!rule.type) {
1608
- out.push(`field "${path4}" expected object but got ${actualType(value)}`);
2264
+ out.push(`field "${path7}" expected object but got ${actualType(value)}`);
1609
2265
  }
1610
2266
  }
1611
2267
  }
@@ -2083,15 +2739,15 @@ async function executeCodeModule(stepId, modulePath, context, options) {
2083
2739
  if (!rootDir) {
2084
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.`);
2085
2741
  }
2086
- if (path2.isAbsolute(modulePath)) {
2742
+ if (path5.isAbsolute(modulePath)) {
2087
2743
  throw new Error(`Code module path must be relative to the flow root, got absolute: "${modulePath}"`);
2088
2744
  }
2089
- const absPath = path2.resolve(rootDir, modulePath);
2090
- const relFromRoot = path2.relative(rootDir, absPath);
2091
- if (relFromRoot.startsWith("..") || path2.isAbsolute(relFromRoot)) {
2745
+ const absPath = path5.resolve(rootDir, modulePath);
2746
+ const relFromRoot = path5.relative(rootDir, absPath);
2747
+ if (relFromRoot.startsWith("..") || path5.isAbsolute(relFromRoot)) {
2092
2748
  throw new Error(`Code module "${modulePath}" resolves outside the flow directory`);
2093
2749
  }
2094
- if (!fs2.existsSync(absPath)) {
2750
+ if (!fs4.existsSync(absPath)) {
2095
2751
  throw new Error(`Code module not found: ${absPath}`);
2096
2752
  }
2097
2753
  const { env: _omitEnv, ...safeContext } = context;
@@ -2239,8 +2895,8 @@ async function executeParallelStep(step, context, api, permissions, allowedActio
2239
2895
  function executeFileReadStep(step, context) {
2240
2896
  const config = step.fileRead;
2241
2897
  const filePath = resolveValue(config.path, context);
2242
- const resolvedPath = path2.resolve(filePath);
2243
- const content = fs2.readFileSync(resolvedPath, "utf-8");
2898
+ const resolvedPath = path5.resolve(filePath);
2899
+ const content = fs4.readFileSync(resolvedPath, "utf-8");
2244
2900
  const output = config.parseJson ? JSON.parse(stripCodeFences(content)) : content;
2245
2901
  if (config.parseJson && config.schema) {
2246
2902
  assertMatchesFileReadSchema(output, config.schema, step.id);
@@ -2251,16 +2907,16 @@ function executeFileWriteStep(step, context) {
2251
2907
  const config = step.fileWrite;
2252
2908
  const filePath = resolveValue(config.path, context);
2253
2909
  const content = resolveValue(config.content, context);
2254
- const resolvedPath = path2.resolve(filePath);
2255
- const dir = path2.dirname(resolvedPath);
2256
- if (!fs2.existsSync(dir)) {
2257
- fs2.mkdirSync(dir, { recursive: true });
2910
+ const resolvedPath = path5.resolve(filePath);
2911
+ const dir = path5.dirname(resolvedPath);
2912
+ if (!fs4.existsSync(dir)) {
2913
+ fs4.mkdirSync(dir, { recursive: true });
2258
2914
  }
2259
2915
  const stringContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
2260
2916
  if (config.append) {
2261
- fs2.appendFileSync(resolvedPath, stringContent);
2917
+ fs4.appendFileSync(resolvedPath, stringContent);
2262
2918
  } else {
2263
- fs2.writeFileSync(resolvedPath, stringContent);
2919
+ fs4.writeFileSync(resolvedPath, stringContent);
2264
2920
  }
2265
2921
  return { status: "success", output: { path: resolvedPath, bytesWritten: stringContent.length }, response: { path: resolvedPath } };
2266
2922
  }
@@ -2299,7 +2955,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
2299
2955
  if (flowStack.includes(resolvedKey)) {
2300
2956
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
2301
2957
  }
2302
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-4A5ANCTT.js");
2958
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-FME4AVVN.js");
2303
2959
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
2304
2960
  const subContext = await executeFlow(
2305
2961
  subFlow,
@@ -2402,11 +3058,11 @@ function resolveBashEnv(envConfig, context, stepId) {
2402
3058
  if ("json" in obj) {
2403
3059
  const resolved2 = resolveValue(obj.json, context);
2404
3060
  const json = JSON.stringify(resolved2 ?? null);
2405
- const tmp = path2.join(
2406
- os.tmpdir(),
3061
+ const tmp = path5.join(
3062
+ os2.tmpdir(),
2407
3063
  `one-flow-${stepId}-${key}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`
2408
3064
  );
2409
- fs2.writeFileSync(tmp, json, { encoding: "utf-8" });
3065
+ fs4.writeFileSync(tmp, json, { encoding: "utf-8" });
2410
3066
  tempFiles.push(tmp);
2411
3067
  out[key] = tmp;
2412
3068
  continue;
@@ -2453,7 +3109,7 @@ async function executeBashStep(step, context, options) {
2453
3109
  } finally {
2454
3110
  for (const tmp of tempFiles) {
2455
3111
  try {
2456
- fs2.unlinkSync(tmp);
3112
+ fs4.unlinkSync(tmp);
2457
3113
  } catch {
2458
3114
  }
2459
3115
  }
@@ -2843,8 +3499,8 @@ var FLOWS_DIR = ".one/flows";
2843
3499
  var RUNS_DIR = ".one/flows/.runs";
2844
3500
  var LOGS_DIR = ".one/flows/.logs";
2845
3501
  function ensureDir(dir) {
2846
- if (!fs3.existsSync(dir)) {
2847
- fs3.mkdirSync(dir, { recursive: true });
3502
+ if (!fs5.existsSync(dir)) {
3503
+ fs5.mkdirSync(dir, { recursive: true });
2848
3504
  }
2849
3505
  }
2850
3506
  function generateRunId() {
@@ -2865,8 +3521,8 @@ var FlowRunner = class _FlowRunner {
2865
3521
  this.flowKey = flow.key;
2866
3522
  ensureDir(RUNS_DIR);
2867
3523
  ensureDir(LOGS_DIR);
2868
- this.statePath = path3.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
2869
- this.logPath = path3.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
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`);
2870
3526
  const resolvedInputs = { ...inputs };
2871
3527
  for (const [name, decl] of Object.entries(flow.inputs)) {
2872
3528
  if (resolvedInputs[name] === void 0 && decl.default !== void 0) {
@@ -2907,10 +3563,10 @@ var FlowRunner = class _FlowRunner {
2907
3563
  msg,
2908
3564
  ...data
2909
3565
  };
2910
- fs3.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
3566
+ fs5.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
2911
3567
  }
2912
3568
  saveState() {
2913
- fs3.writeFileSync(this.statePath, JSON.stringify(this.state, stripStepsAlias, 2));
3569
+ fs5.writeFileSync(this.statePath, JSON.stringify(this.state, stripStepsAlias, 2));
2914
3570
  }
2915
3571
  createEventHandler(externalHandler) {
2916
3572
  return (event) => {
@@ -3008,14 +3664,14 @@ var FlowRunner = class _FlowRunner {
3008
3664
  }
3009
3665
  /** Path to a run's persisted state file. The post-mortem artifact surfaced by `one flow inspect`. */
3010
3666
  static statePathFor(flowKey, runId) {
3011
- return path3.join(RUNS_DIR, `${flowKey}-${runId}.state.json`);
3667
+ return path6.join(RUNS_DIR, `${flowKey}-${runId}.state.json`);
3012
3668
  }
3013
3669
  static loadRunState(runId) {
3014
3670
  ensureDir(RUNS_DIR);
3015
- const files = fs3.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
3671
+ const files = fs5.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
3016
3672
  if (files.length === 0) return null;
3017
3673
  try {
3018
- const content = fs3.readFileSync(path3.join(RUNS_DIR, files[0]), "utf-8");
3674
+ const content = fs5.readFileSync(path6.join(RUNS_DIR, files[0]), "utf-8");
3019
3675
  return JSON.parse(content);
3020
3676
  } catch {
3021
3677
  return null;
@@ -3027,17 +3683,17 @@ var FlowRunner = class _FlowRunner {
3027
3683
  runner.flowKey = state.flowKey;
3028
3684
  runner.state = state;
3029
3685
  runner.paused = false;
3030
- runner.statePath = path3.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
3031
- runner.logPath = path3.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
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`);
3032
3688
  return runner;
3033
3689
  }
3034
3690
  static listRuns(flowKey) {
3035
3691
  ensureDir(RUNS_DIR);
3036
- const files = fs3.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
3692
+ const files = fs5.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
3037
3693
  const runs = [];
3038
3694
  for (const file of files) {
3039
3695
  try {
3040
- const content = fs3.readFileSync(path3.join(RUNS_DIR, file), "utf-8");
3696
+ const content = fs5.readFileSync(path6.join(RUNS_DIR, file), "utf-8");
3041
3697
  const state = JSON.parse(content);
3042
3698
  if (!flowKey || state.flowKey === flowKey) {
3043
3699
  runs.push(state);
@@ -3050,44 +3706,44 @@ var FlowRunner = class _FlowRunner {
3050
3706
  };
3051
3707
  function resolveFlowPath(keyOrPath) {
3052
3708
  if (keyOrPath.endsWith(".json")) {
3053
- return path3.resolve(keyOrPath);
3709
+ return path6.resolve(keyOrPath);
3054
3710
  }
3055
3711
  if (keyOrPath.includes("\\")) {
3056
- return path3.resolve(keyOrPath);
3712
+ return path6.resolve(keyOrPath);
3057
3713
  }
3058
3714
  if (keyOrPath.includes("/")) {
3059
- const nestedFolder = path3.resolve(FLOWS_DIR, keyOrPath, "flow.json");
3060
- if (fs3.existsSync(nestedFolder)) return nestedFolder;
3061
- const literal = path3.resolve(keyOrPath);
3062
- if (fs3.existsSync(literal)) return literal;
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;
3063
3719
  return nestedFolder;
3064
3720
  }
3065
- const folderPath = path3.resolve(FLOWS_DIR, keyOrPath, "flow.json");
3066
- if (fs3.existsSync(folderPath)) return folderPath;
3067
- const legacyPath = path3.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
3068
- if (fs3.existsSync(legacyPath)) return legacyPath;
3069
- const flowsDir = path3.resolve(FLOWS_DIR);
3070
- if (fs3.existsSync(flowsDir)) {
3071
- for (const entry of fs3.readdirSync(flowsDir, { withFileTypes: true })) {
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 })) {
3072
3728
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
3073
- const nested = path3.join(flowsDir, entry.name, keyOrPath, "flow.json");
3074
- if (fs3.existsSync(nested)) return nested;
3729
+ const nested = path6.join(flowsDir, entry.name, keyOrPath, "flow.json");
3730
+ if (fs5.existsSync(nested)) return nested;
3075
3731
  }
3076
3732
  }
3077
3733
  return folderPath;
3078
3734
  }
3079
3735
  function getFlowRootDir(flowFilePath) {
3080
- const dir = path3.dirname(flowFilePath);
3081
- const base = path3.basename(flowFilePath);
3736
+ const dir = path6.dirname(flowFilePath);
3737
+ const base = path6.basename(flowFilePath);
3082
3738
  if (base === "flow.json") return dir;
3083
3739
  return dir;
3084
3740
  }
3085
3741
  function loadFlowWithMeta(keyOrPath) {
3086
3742
  const filePath = resolveFlowPath(keyOrPath);
3087
- if (!fs3.existsSync(filePath)) {
3743
+ if (!fs5.existsSync(filePath)) {
3088
3744
  throw new Error(`Flow not found: ${filePath}`);
3089
3745
  }
3090
- const content = fs3.readFileSync(filePath, "utf-8");
3746
+ const content = fs5.readFileSync(filePath, "utf-8");
3091
3747
  const flow = JSON.parse(content);
3092
3748
  return { flow, filePath, rootDir: getFlowRootDir(filePath) };
3093
3749
  }
@@ -3134,13 +3790,13 @@ function summarizeFlowInputs(flow) {
3134
3790
  }));
3135
3791
  }
3136
3792
  function listFlows() {
3137
- const flowsDir = path3.resolve(FLOWS_DIR);
3138
- if (!fs3.existsSync(flowsDir)) return [];
3793
+ const flowsDir = path6.resolve(FLOWS_DIR);
3794
+ if (!fs5.existsSync(flowsDir)) return [];
3139
3795
  const flows = [];
3140
3796
  const seenKeys = /* @__PURE__ */ new Set();
3141
3797
  const readFlowFile = (filePath, group) => {
3142
3798
  try {
3143
- const content = fs3.readFileSync(filePath, "utf-8");
3799
+ const content = fs5.readFileSync(filePath, "utf-8");
3144
3800
  const flow = JSON.parse(content);
3145
3801
  const nsKey = group ? `${group}/${flow.key}` : flow.key;
3146
3802
  if (seenKeys.has(nsKey)) return;
@@ -3152,7 +3808,7 @@ function listFlows() {
3152
3808
  inputCount: Object.keys(flow.inputs).length,
3153
3809
  stepCount: flow.steps.length,
3154
3810
  path: filePath,
3155
- layout: path3.basename(filePath) === "flow.json" ? "folder" : "legacy",
3811
+ layout: path6.basename(filePath) === "flow.json" ? "folder" : "legacy",
3156
3812
  group,
3157
3813
  stepTypes: collectStepTypes(flow),
3158
3814
  requiresBash: flowRequiresBash(flow),
@@ -3163,12 +3819,12 @@ function listFlows() {
3163
3819
  }
3164
3820
  };
3165
3821
  const scanDir = (dir, group) => {
3166
- for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
3822
+ for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
3167
3823
  if (entry.name.startsWith(".")) continue;
3168
- const full = path3.join(dir, entry.name);
3824
+ const full = path6.join(dir, entry.name);
3169
3825
  if (entry.isDirectory()) {
3170
- const flowJson = path3.join(full, "flow.json");
3171
- if (fs3.existsSync(flowJson)) {
3826
+ const flowJson = path6.join(full, "flow.json");
3827
+ if (fs5.existsSync(flowJson)) {
3172
3828
  readFlowFile(flowJson, group);
3173
3829
  } else {
3174
3830
  if (!group) {
@@ -3186,7 +3842,7 @@ function listFlows() {
3186
3842
  function saveFlow(flow, outputPath, group) {
3187
3843
  let flowPath;
3188
3844
  if (outputPath) {
3189
- flowPath = path3.resolve(outputPath);
3845
+ flowPath = path6.resolve(outputPath);
3190
3846
  } else {
3191
3847
  let bareKey = flow.key;
3192
3848
  let resolvedGroup = group;
@@ -3196,25 +3852,36 @@ function saveFlow(flow, outputPath, group) {
3196
3852
  resolvedGroup = resolvedGroup || parts.join("/");
3197
3853
  flow.key = bareKey;
3198
3854
  }
3199
- const basePath = resolvedGroup ? path3.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path3.resolve(FLOWS_DIR, bareKey);
3200
- const legacyPath = path3.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
3201
- const folderPath = path3.join(basePath, "flow.json");
3202
- if (!resolvedGroup && fs3.existsSync(legacyPath) && !fs3.existsSync(folderPath)) {
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)) {
3203
3859
  flowPath = legacyPath;
3204
3860
  } else {
3205
3861
  flowPath = folderPath;
3206
3862
  }
3207
3863
  }
3208
- const dir = path3.dirname(flowPath);
3864
+ const dir = path6.dirname(flowPath);
3209
3865
  ensureDir(dir);
3210
- if (path3.basename(flowPath) === "flow.json") {
3211
- ensureDir(path3.join(dir, "lib"));
3866
+ if (path6.basename(flowPath) === "flow.json") {
3867
+ ensureDir(path6.join(dir, "lib"));
3212
3868
  }
3213
- fs3.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
3869
+ fs5.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
3214
3870
  return flowPath;
3215
3871
  }
3216
3872
 
3217
3873
  export {
3874
+ installMcpConfig,
3875
+ getAgentStatuses,
3876
+ cliVersion,
3877
+ recordCommand,
3878
+ flushUsageRollups,
3879
+ drainQueue,
3880
+ flush,
3881
+ maybeShowTelemetryNotice,
3882
+ collectInstallContext,
3883
+ installContextToParams,
3884
+ describeInstallContext,
3218
3885
  ApiError,
3219
3886
  OneApi,
3220
3887
  TimeoutError,