@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.
@@ -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
- 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
+ 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(path4) {
78
- return this.requestFull({ path: path4 });
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(path4, variables) {
526
- if (!path4) return path4;
527
- let result = path4;
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 fs from "fs";
562
- import path from "path";
1223
+ import fs3 from "fs";
1224
+ import path4 from "path";
563
1225
  function knowledgeDir() {
564
- return path.join(homeDir(), ".one", "cache", "knowledge");
1226
+ return path4.join(homeDir(), ".one", "cache", "knowledge");
565
1227
  }
566
1228
  function legacySearchDir() {
567
- return path.join(homeDir(), ".one", "cache", "search");
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 path.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
1235
+ return path4.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
574
1236
  }
575
1237
  function readCache(filePath) {
576
1238
  try {
577
- const content = fs.readFileSync(filePath, "utf-8");
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 = path.dirname(filePath);
586
- fs.mkdirSync(dir, { recursive: true });
587
- fs.writeFileSync(filePath, JSON.stringify(entry, null, 2));
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 fs.readdirSync(knowledgeDir())) {
1276
+ for (const file of fs3.readdirSync(knowledgeDir())) {
615
1277
  if (!file.endsWith(".json")) continue;
616
- const filePath = path.join(knowledgeDir(), file);
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 = fs.readdirSync(dir);
1292
+ const files = fs3.readdirSync(dir);
631
1293
  for (const file of files) {
632
- fs.unlinkSync(path.join(dir, file));
1294
+ fs3.unlinkSync(path4.join(dir, file));
633
1295
  count++;
634
1296
  }
635
- fs.rmdirSync(dir);
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
- fs.unlinkSync(filePath);
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 cached = isActionDetailsEntry(raw) ? raw : null;
673
- if (cached && isFresh(cached)) {
674
- return { details: cached.data, cacheHit: true, stale: false, entry: cached };
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, 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 };
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 (cached) {
1349
+ if (cached2) {
688
1350
  warn(
689
- `Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached))} ago)
1351
+ `Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached2))} ago)
690
1352
  `
691
1353
  );
692
- return { details: cached.data, cacheHit: true, stale: true, entry: cached };
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 path4 = `${basePath}${field}`;
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 "${path4}" is required but missing`);
2232
+ if (rule.required) out.push(`field "${path7}" is required but missing`);
1571
2233
  continue;
1572
2234
  }
1573
- checkFileReadRule(obj[field], rule, path4, out);
2235
+ checkFileReadRule(obj[field], rule, path7, out);
1574
2236
  }
1575
2237
  }
1576
- function checkFileReadRule(value, rule, path4, out) {
2238
+ function checkFileReadRule(value, rule, path7, out) {
1577
2239
  if (rule.type && !matchesLeafType(value, rule.type)) {
1578
- out.push(`field "${path4}" expected ${rule.type} but got ${actualType(value)}`);
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 "${path4}" value ${JSON.stringify(value)} is not one of [${rule.enum.map((e) => JSON.stringify(e)).join(", ")}]`);
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 "${path4}" expected array but got ${actualType(value)}`);
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 "${path4}" expected array of length ${rule.length} but got length ${value.length}`);
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 "${path4}" expected at least ${rule.minItems} item${rule.minItems === 1 ? "" : "s"} but got ${value.length}`);
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 "${path4}" expected at most ${rule.maxItems} item${rule.maxItems === 1 ? "" : "s"} but got ${value.length}`);
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, `${path4}[${i}]`, out));
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, `${path4}.`, out);
2268
+ collectFileReadViolations(value, rule.properties, `${path7}.`, out);
1607
2269
  } else if (!rule.type) {
1608
- out.push(`field "${path4}" expected object but got ${actualType(value)}`);
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 (path2.isAbsolute(modulePath)) {
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 = path2.resolve(rootDir, modulePath);
2090
- const relFromRoot = path2.relative(rootDir, absPath);
2091
- if (relFromRoot.startsWith("..") || path2.isAbsolute(relFromRoot)) {
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 (!fs2.existsSync(absPath)) {
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 = path2.resolve(filePath);
2243
- const content = fs2.readFileSync(resolvedPath, "utf-8");
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 = path2.resolve(filePath);
2255
- const dir = path2.dirname(resolvedPath);
2256
- if (!fs2.existsSync(dir)) {
2257
- fs2.mkdirSync(dir, { recursive: true });
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
- fs2.appendFileSync(resolvedPath, stringContent);
2923
+ fs4.appendFileSync(resolvedPath, stringContent);
2262
2924
  } else {
2263
- fs2.writeFileSync(resolvedPath, stringContent);
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-4A5ANCTT.js");
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 = path2.join(
2406
- os.tmpdir(),
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
- fs2.writeFileSync(tmp, json, { encoding: "utf-8" });
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
- fs2.unlinkSync(tmp);
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 (!fs3.existsSync(dir)) {
2847
- fs3.mkdirSync(dir, { recursive: true });
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 = path3.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
2869
- this.logPath = path3.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
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
- fs3.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
3572
+ fs5.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
2911
3573
  }
2912
3574
  saveState() {
2913
- fs3.writeFileSync(this.statePath, JSON.stringify(this.state, stripStepsAlias, 2));
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 path3.join(RUNS_DIR, `${flowKey}-${runId}.state.json`);
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 = fs3.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
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 = fs3.readFileSync(path3.join(RUNS_DIR, files[0]), "utf-8");
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 = path3.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
3031
- runner.logPath = path3.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
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 = fs3.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
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 = fs3.readFileSync(path3.join(RUNS_DIR, file), "utf-8");
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 path3.resolve(keyOrPath);
3715
+ return path6.resolve(keyOrPath);
3054
3716
  }
3055
3717
  if (keyOrPath.includes("\\")) {
3056
- return path3.resolve(keyOrPath);
3718
+ return path6.resolve(keyOrPath);
3057
3719
  }
3058
3720
  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;
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 = 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 })) {
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 = path3.join(flowsDir, entry.name, keyOrPath, "flow.json");
3074
- if (fs3.existsSync(nested)) return nested;
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 = path3.dirname(flowFilePath);
3081
- const base = path3.basename(flowFilePath);
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 (!fs3.existsSync(filePath)) {
3749
+ if (!fs5.existsSync(filePath)) {
3088
3750
  throw new Error(`Flow not found: ${filePath}`);
3089
3751
  }
3090
- const content = fs3.readFileSync(filePath, "utf-8");
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 = path3.resolve(FLOWS_DIR);
3138
- if (!fs3.existsSync(flowsDir)) return [];
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 = fs3.readFileSync(filePath, "utf-8");
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: path3.basename(filePath) === "flow.json" ? "folder" : "legacy",
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 fs3.readdirSync(dir, { withFileTypes: true })) {
3828
+ for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
3167
3829
  if (entry.name.startsWith(".")) continue;
3168
- const full = path3.join(dir, entry.name);
3830
+ const full = path6.join(dir, entry.name);
3169
3831
  if (entry.isDirectory()) {
3170
- const flowJson = path3.join(full, "flow.json");
3171
- if (fs3.existsSync(flowJson)) {
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 = path3.resolve(outputPath);
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 ? 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)) {
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 = path3.dirname(flowPath);
3870
+ const dir = path6.dirname(flowPath);
3209
3871
  ensureDir(dir);
3210
- if (path3.basename(flowPath) === "flow.json") {
3211
- ensureDir(path3.join(dir, "lib"));
3872
+ if (path6.basename(flowPath) === "flow.json") {
3873
+ ensureDir(path6.join(dir, "lib"));
3212
3874
  }
3213
- fs3.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
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,