@withone/cli 1.44.2 → 1.45.1

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.
@@ -2,16 +2,19 @@ import {
2
2
  getByDotPath,
3
3
  setByDotPath
4
4
  } from "./chunk-44CV5IMX.js";
5
+ import {
6
+ getCacheTtl
7
+ } from "./chunk-TVIZC7AC.js";
5
8
 
6
9
  // src/lib/flow-runner.ts
7
- import fs2 from "fs";
8
- import path2 from "path";
10
+ import fs3 from "fs";
11
+ import path3 from "path";
9
12
  import crypto from "crypto";
10
13
 
11
14
  // src/lib/flow-engine.ts
12
- import fs from "fs";
13
- import os from "os";
14
- import path from "path";
15
+ import fs2 from "fs";
16
+ import os2 from "os";
17
+ import path2 from "path";
15
18
  import { exec, spawn } from "child_process";
16
19
  import { promisify } from "util";
17
20
 
@@ -45,8 +48,8 @@ var OneApi = class {
45
48
  this.apiBase = apiBase ?? "https://api.withone.ai/v1";
46
49
  }
47
50
  apiBase;
48
- async request(path3) {
49
- return this.requestFull({ path: path3 });
51
+ async request(path4) {
52
+ return this.requestFull({ path: path4 });
50
53
  }
51
54
  async requestFull(opts) {
52
55
  let url = `${this.apiBase}${opts.path}`;
@@ -231,7 +234,12 @@ var OneApi = class {
231
234
  const data = text ? JSON.parse(text) : {};
232
235
  return { data, etag, status: response.status };
233
236
  }
234
- async getActionKnowledgeWithMeta(actionId, ifNoneMatch) {
237
+ /**
238
+ * Full action details (method, path, tags, ioSchema, knowledge) with ETag
239
+ * support. This is what the knowledge cache stores: caching the complete
240
+ * object lets `actions execute` reuse it and skip its preflight round trip.
241
+ */
242
+ async getActionDetailsWithMeta(actionId, ifNoneMatch) {
235
243
  const result = await this.requestWithMeta({
236
244
  path: "/knowledge",
237
245
  queryParams: { _id: actionId },
@@ -244,12 +252,7 @@ var OneApi = class {
244
252
  if (actions.length === 0) {
245
253
  throw new ApiError(404, `Action with ID ${actionId} not found`);
246
254
  }
247
- const action = actions[0];
248
- const knowledge = {
249
- knowledge: action.knowledge || "No knowledge was found",
250
- method: action.method || "No method was found"
251
- };
252
- return { data: knowledge, etag: result.etag, status: result.status };
255
+ return { data: actions[0], etag: result.etag, status: result.status };
253
256
  }
254
257
  async searchActionsWithMeta(platform, query, agentType, ifNoneMatch) {
255
258
  const isKnowledgeAgent = agentType === "knowledge";
@@ -478,9 +481,9 @@ var TimeoutError = class extends Error {
478
481
  function sleep(ms) {
479
482
  return new Promise((resolve2) => setTimeout(resolve2, ms));
480
483
  }
481
- function replacePathVariables(path3, variables) {
482
- if (!path3) return path3;
483
- let result = path3;
484
+ function replacePathVariables(path4, variables) {
485
+ if (!path4) return path4;
486
+ let result = path4;
484
487
  result = result.replace(/\{\{([^}]+)\}\}/g, (_match, variable) => {
485
488
  const trimmedVariable = variable.trim();
486
489
  const value = variables[trimmedVariable];
@@ -544,6 +547,162 @@ Read the API documentation below to identify which parameters are path variables
544
547
  ${knowledge}`;
545
548
  }
546
549
 
550
+ // src/lib/cache.ts
551
+ import fs from "fs";
552
+ import path from "path";
553
+ import os from "os";
554
+ function knowledgeDir() {
555
+ return path.join(os.homedir(), ".one", "cache", "knowledge");
556
+ }
557
+ function searchDir() {
558
+ return path.join(os.homedir(), ".one", "cache", "search");
559
+ }
560
+ function sanitizeFilename(input) {
561
+ return input.replace(/[^a-zA-Z0-9_\-\.]/g, "_");
562
+ }
563
+ function knowledgeCachePath(actionId) {
564
+ return path.join(knowledgeDir(), `${sanitizeFilename(actionId)}.json`);
565
+ }
566
+ function searchCachePath(platform, query, type) {
567
+ const key = `${platform}_${sanitizeFilename(query)}_${type || "knowledge"}`;
568
+ return path.join(searchDir(), `${key}.json`);
569
+ }
570
+ function readCache(filePath) {
571
+ try {
572
+ const content = fs.readFileSync(filePath, "utf-8");
573
+ return JSON.parse(content);
574
+ } catch {
575
+ return null;
576
+ }
577
+ }
578
+ function writeCache(filePath, entry) {
579
+ try {
580
+ const dir = path.dirname(filePath);
581
+ fs.mkdirSync(dir, { recursive: true });
582
+ fs.writeFileSync(filePath, JSON.stringify(entry, null, 2));
583
+ } catch {
584
+ }
585
+ }
586
+ function isFresh(entry) {
587
+ const cachedTime = new Date(entry.cachedAt).getTime();
588
+ const now = Date.now();
589
+ return now - cachedTime < entry.ttl * 1e3;
590
+ }
591
+ function getAge(entry) {
592
+ return Math.floor((Date.now() - new Date(entry.cachedAt).getTime()) / 1e3);
593
+ }
594
+ function buildCacheMeta(entry, hit) {
595
+ if (!entry) {
596
+ return { hit: false, age: 0, fresh: false };
597
+ }
598
+ return {
599
+ hit,
600
+ age: getAge(entry),
601
+ fresh: isFresh(entry)
602
+ };
603
+ }
604
+ function formatAge(seconds) {
605
+ if (seconds < 60) return `${seconds}s`;
606
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
607
+ if (seconds < 86400) {
608
+ const h2 = Math.floor(seconds / 3600);
609
+ const m = Math.floor(seconds % 3600 / 60);
610
+ return m > 0 ? `${h2}h ${m}m` : `${h2}h`;
611
+ }
612
+ const d = Math.floor(seconds / 86400);
613
+ const h = Math.floor(seconds % 86400 / 3600);
614
+ return h > 0 ? `${d}d ${h}h` : `${d}d`;
615
+ }
616
+ function listCacheEntries() {
617
+ const entries = [];
618
+ for (const [dir, type] of [[knowledgeDir(), "knowledge"], [searchDir(), "search"]]) {
619
+ try {
620
+ const files = fs.readdirSync(dir);
621
+ for (const file of files) {
622
+ if (!file.endsWith(".json")) continue;
623
+ const filePath = path.join(dir, file);
624
+ const entry = readCache(filePath);
625
+ if (entry) {
626
+ entries.push({ type, filePath, entry });
627
+ }
628
+ }
629
+ } catch {
630
+ }
631
+ }
632
+ return entries;
633
+ }
634
+ function clearAll() {
635
+ let count = 0;
636
+ for (const dir of [knowledgeDir(), searchDir()]) {
637
+ try {
638
+ const files = fs.readdirSync(dir);
639
+ for (const file of files) {
640
+ fs.unlinkSync(path.join(dir, file));
641
+ count++;
642
+ }
643
+ fs.rmdirSync(dir);
644
+ } catch {
645
+ }
646
+ }
647
+ return count;
648
+ }
649
+ function clearEntry(actionId) {
650
+ const filePath = knowledgeCachePath(actionId);
651
+ try {
652
+ fs.unlinkSync(filePath);
653
+ return true;
654
+ } catch {
655
+ return false;
656
+ }
657
+ }
658
+ function makeCacheEntry(key, data, etag) {
659
+ return {
660
+ key,
661
+ etag,
662
+ cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
663
+ ttl: getCacheTtl(),
664
+ data
665
+ };
666
+ }
667
+
668
+ // src/lib/action-details.ts
669
+ function isActionDetailsEntry(entry) {
670
+ const data = entry?.data;
671
+ return !!data && typeof data._id === "string" && typeof data.path === "string" && typeof data.method === "string";
672
+ }
673
+ async function resolveActionDetails(api, actionId, opts = {}) {
674
+ const useCache = opts.useCache !== false;
675
+ const warn = opts.warn ?? ((m) => {
676
+ process.stderr.write(m);
677
+ });
678
+ const cachePath = knowledgeCachePath(actionId);
679
+ const raw = useCache ? readCache(cachePath) : null;
680
+ const cached = isActionDetailsEntry(raw) ? raw : null;
681
+ if (cached && isFresh(cached)) {
682
+ return { details: cached.data, cacheHit: true, stale: false, entry: cached };
683
+ }
684
+ try {
685
+ const result = await api.getActionDetailsWithMeta(actionId, cached?.etag ?? void 0);
686
+ if (result.status === 304 && cached) {
687
+ cached.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
688
+ writeCache(cachePath, cached);
689
+ return { details: cached.data, cacheHit: true, stale: false, entry: cached };
690
+ }
691
+ const entry = makeCacheEntry(actionId, result.data, result.etag);
692
+ writeCache(cachePath, entry);
693
+ return { details: result.data, cacheHit: false, stale: false, entry };
694
+ } catch (fetchError) {
695
+ if (cached) {
696
+ warn(
697
+ `Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached))} ago)
698
+ `
699
+ );
700
+ return { details: cached.data, cacheHit: true, stale: true, entry: cached };
701
+ }
702
+ throw fetchError;
703
+ }
704
+ }
705
+
547
706
  // src/lib/validate.ts
548
707
  var SCHEMA_GROUP_TO_FLAG = {
549
708
  path: "--path-vars",
@@ -816,7 +975,7 @@ async function executeActionStep(step, context, api, permissions, allowedActionI
816
975
  if (!isActionAllowed(actionId, allowedActionIds)) {
817
976
  throw new Error(`Action "${actionId}" is not in the allowed action list`);
818
977
  }
819
- const actionDetails = await api.getActionDetails(actionId);
978
+ const { details: actionDetails } = await resolveActionDetails(api, actionId);
820
979
  if (!isMethodAllowed(actionDetails.method, permissions)) {
821
980
  throw new Error(`Method "${actionDetails.method}" is not allowed under "${permissions}" permission level`);
822
981
  }
@@ -899,15 +1058,15 @@ async function executeCodeModule(stepId, modulePath, context, options) {
899
1058
  if (!rootDir) {
900
1059
  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.`);
901
1060
  }
902
- if (path.isAbsolute(modulePath)) {
1061
+ if (path2.isAbsolute(modulePath)) {
903
1062
  throw new Error(`Code module path must be relative to the flow root, got absolute: "${modulePath}"`);
904
1063
  }
905
- const absPath = path.resolve(rootDir, modulePath);
906
- const relFromRoot = path.relative(rootDir, absPath);
907
- if (relFromRoot.startsWith("..") || path.isAbsolute(relFromRoot)) {
1064
+ const absPath = path2.resolve(rootDir, modulePath);
1065
+ const relFromRoot = path2.relative(rootDir, absPath);
1066
+ if (relFromRoot.startsWith("..") || path2.isAbsolute(relFromRoot)) {
908
1067
  throw new Error(`Code module "${modulePath}" resolves outside the flow directory`);
909
1068
  }
910
- if (!fs.existsSync(absPath)) {
1069
+ if (!fs2.existsSync(absPath)) {
911
1070
  throw new Error(`Code module not found: ${absPath}`);
912
1071
  }
913
1072
  const { env: _omitEnv, ...safeContext } = context;
@@ -1055,8 +1214,8 @@ async function executeParallelStep(step, context, api, permissions, allowedActio
1055
1214
  function executeFileReadStep(step, context) {
1056
1215
  const config = step.fileRead;
1057
1216
  const filePath = resolveValue(config.path, context);
1058
- const resolvedPath = path.resolve(filePath);
1059
- const content = fs.readFileSync(resolvedPath, "utf-8");
1217
+ const resolvedPath = path2.resolve(filePath);
1218
+ const content = fs2.readFileSync(resolvedPath, "utf-8");
1060
1219
  const output = config.parseJson ? JSON.parse(stripCodeFences(content)) : content;
1061
1220
  return { status: "success", output, response: output };
1062
1221
  }
@@ -1064,16 +1223,16 @@ function executeFileWriteStep(step, context) {
1064
1223
  const config = step.fileWrite;
1065
1224
  const filePath = resolveValue(config.path, context);
1066
1225
  const content = resolveValue(config.content, context);
1067
- const resolvedPath = path.resolve(filePath);
1068
- const dir = path.dirname(resolvedPath);
1069
- if (!fs.existsSync(dir)) {
1070
- fs.mkdirSync(dir, { recursive: true });
1226
+ const resolvedPath = path2.resolve(filePath);
1227
+ const dir = path2.dirname(resolvedPath);
1228
+ if (!fs2.existsSync(dir)) {
1229
+ fs2.mkdirSync(dir, { recursive: true });
1071
1230
  }
1072
1231
  const stringContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1073
1232
  if (config.append) {
1074
- fs.appendFileSync(resolvedPath, stringContent);
1233
+ fs2.appendFileSync(resolvedPath, stringContent);
1075
1234
  } else {
1076
- fs.writeFileSync(resolvedPath, stringContent);
1235
+ fs2.writeFileSync(resolvedPath, stringContent);
1077
1236
  }
1078
1237
  return { status: "success", output: { path: resolvedPath, bytesWritten: stringContent.length }, response: { path: resolvedPath } };
1079
1238
  }
@@ -1112,7 +1271,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
1112
1271
  if (flowStack.includes(resolvedKey)) {
1113
1272
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
1114
1273
  }
1115
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-EXZ77YLF.js");
1274
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-6KN2ZVXB.js");
1116
1275
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
1117
1276
  const subContext = await executeFlow(
1118
1277
  subFlow,
@@ -1215,11 +1374,11 @@ function resolveBashEnv(envConfig, context, stepId) {
1215
1374
  if ("json" in obj) {
1216
1375
  const resolved2 = resolveValue(obj.json, context);
1217
1376
  const json = JSON.stringify(resolved2 ?? null);
1218
- const tmp = path.join(
1219
- os.tmpdir(),
1377
+ const tmp = path2.join(
1378
+ os2.tmpdir(),
1220
1379
  `one-flow-${stepId}-${key}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`
1221
1380
  );
1222
- fs.writeFileSync(tmp, json, { encoding: "utf-8" });
1381
+ fs2.writeFileSync(tmp, json, { encoding: "utf-8" });
1223
1382
  tempFiles.push(tmp);
1224
1383
  out[key] = tmp;
1225
1384
  continue;
@@ -1266,7 +1425,7 @@ async function executeBashStep(step, context, options) {
1266
1425
  } finally {
1267
1426
  for (const tmp of tempFiles) {
1268
1427
  try {
1269
- fs.unlinkSync(tmp);
1428
+ fs2.unlinkSync(tmp);
1270
1429
  } catch {
1271
1430
  }
1272
1431
  }
@@ -1347,7 +1506,7 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
1347
1506
  if (step.type === "action" && step.action) {
1348
1507
  const actionId = resolveValue(step.action.actionId, context);
1349
1508
  try {
1350
- const actionDetails = await api.getActionDetails(actionId);
1509
+ const { details: actionDetails } = await resolveActionDetails(api, actionId);
1351
1510
  if (!options.skipValidation) {
1352
1511
  const data = step.action.data ? resolveValue(step.action.data, context) : void 0;
1353
1512
  const pathVars = step.action.pathVars ? resolveValue(step.action.pathVars, context) : void 0;
@@ -2389,8 +2548,8 @@ var FLOWS_DIR = ".one/flows";
2389
2548
  var RUNS_DIR = ".one/flows/.runs";
2390
2549
  var LOGS_DIR = ".one/flows/.logs";
2391
2550
  function ensureDir(dir) {
2392
- if (!fs2.existsSync(dir)) {
2393
- fs2.mkdirSync(dir, { recursive: true });
2551
+ if (!fs3.existsSync(dir)) {
2552
+ fs3.mkdirSync(dir, { recursive: true });
2394
2553
  }
2395
2554
  }
2396
2555
  function generateRunId() {
@@ -2408,8 +2567,8 @@ var FlowRunner = class _FlowRunner {
2408
2567
  this.flowKey = flow.key;
2409
2568
  ensureDir(RUNS_DIR);
2410
2569
  ensureDir(LOGS_DIR);
2411
- this.statePath = path2.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
2412
- this.logPath = path2.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
2570
+ this.statePath = path3.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
2571
+ this.logPath = path3.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
2413
2572
  const resolvedInputs = { ...inputs };
2414
2573
  for (const [name, decl] of Object.entries(flow.inputs)) {
2415
2574
  if (resolvedInputs[name] === void 0 && decl.default !== void 0) {
@@ -2450,10 +2609,10 @@ var FlowRunner = class _FlowRunner {
2450
2609
  msg,
2451
2610
  ...data
2452
2611
  };
2453
- fs2.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
2612
+ fs3.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
2454
2613
  }
2455
2614
  saveState() {
2456
- fs2.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
2615
+ fs3.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
2457
2616
  }
2458
2617
  createEventHandler(externalHandler) {
2459
2618
  return (event) => {
@@ -2551,10 +2710,10 @@ var FlowRunner = class _FlowRunner {
2551
2710
  }
2552
2711
  static loadRunState(runId) {
2553
2712
  ensureDir(RUNS_DIR);
2554
- const files = fs2.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
2713
+ const files = fs3.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
2555
2714
  if (files.length === 0) return null;
2556
2715
  try {
2557
- const content = fs2.readFileSync(path2.join(RUNS_DIR, files[0]), "utf-8");
2716
+ const content = fs3.readFileSync(path3.join(RUNS_DIR, files[0]), "utf-8");
2558
2717
  return JSON.parse(content);
2559
2718
  } catch {
2560
2719
  return null;
@@ -2566,17 +2725,17 @@ var FlowRunner = class _FlowRunner {
2566
2725
  runner.flowKey = state.flowKey;
2567
2726
  runner.state = state;
2568
2727
  runner.paused = false;
2569
- runner.statePath = path2.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
2570
- runner.logPath = path2.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
2728
+ runner.statePath = path3.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
2729
+ runner.logPath = path3.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
2571
2730
  return runner;
2572
2731
  }
2573
2732
  static listRuns(flowKey) {
2574
2733
  ensureDir(RUNS_DIR);
2575
- const files = fs2.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
2734
+ const files = fs3.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
2576
2735
  const runs = [];
2577
2736
  for (const file of files) {
2578
2737
  try {
2579
- const content = fs2.readFileSync(path2.join(RUNS_DIR, file), "utf-8");
2738
+ const content = fs3.readFileSync(path3.join(RUNS_DIR, file), "utf-8");
2580
2739
  const state = JSON.parse(content);
2581
2740
  if (!flowKey || state.flowKey === flowKey) {
2582
2741
  runs.push(state);
@@ -2589,44 +2748,44 @@ var FlowRunner = class _FlowRunner {
2589
2748
  };
2590
2749
  function resolveFlowPath(keyOrPath) {
2591
2750
  if (keyOrPath.endsWith(".json")) {
2592
- return path2.resolve(keyOrPath);
2751
+ return path3.resolve(keyOrPath);
2593
2752
  }
2594
2753
  if (keyOrPath.includes("\\")) {
2595
- return path2.resolve(keyOrPath);
2754
+ return path3.resolve(keyOrPath);
2596
2755
  }
2597
2756
  if (keyOrPath.includes("/")) {
2598
- const nestedFolder = path2.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2599
- if (fs2.existsSync(nestedFolder)) return nestedFolder;
2600
- const literal = path2.resolve(keyOrPath);
2601
- if (fs2.existsSync(literal)) return literal;
2757
+ const nestedFolder = path3.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2758
+ if (fs3.existsSync(nestedFolder)) return nestedFolder;
2759
+ const literal = path3.resolve(keyOrPath);
2760
+ if (fs3.existsSync(literal)) return literal;
2602
2761
  return nestedFolder;
2603
2762
  }
2604
- const folderPath = path2.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2605
- if (fs2.existsSync(folderPath)) return folderPath;
2606
- const legacyPath = path2.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
2607
- if (fs2.existsSync(legacyPath)) return legacyPath;
2608
- const flowsDir = path2.resolve(FLOWS_DIR);
2609
- if (fs2.existsSync(flowsDir)) {
2610
- for (const entry of fs2.readdirSync(flowsDir, { withFileTypes: true })) {
2763
+ const folderPath = path3.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2764
+ if (fs3.existsSync(folderPath)) return folderPath;
2765
+ const legacyPath = path3.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
2766
+ if (fs3.existsSync(legacyPath)) return legacyPath;
2767
+ const flowsDir = path3.resolve(FLOWS_DIR);
2768
+ if (fs3.existsSync(flowsDir)) {
2769
+ for (const entry of fs3.readdirSync(flowsDir, { withFileTypes: true })) {
2611
2770
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
2612
- const nested = path2.join(flowsDir, entry.name, keyOrPath, "flow.json");
2613
- if (fs2.existsSync(nested)) return nested;
2771
+ const nested = path3.join(flowsDir, entry.name, keyOrPath, "flow.json");
2772
+ if (fs3.existsSync(nested)) return nested;
2614
2773
  }
2615
2774
  }
2616
2775
  return folderPath;
2617
2776
  }
2618
2777
  function getFlowRootDir(flowFilePath) {
2619
- const dir = path2.dirname(flowFilePath);
2620
- const base = path2.basename(flowFilePath);
2778
+ const dir = path3.dirname(flowFilePath);
2779
+ const base = path3.basename(flowFilePath);
2621
2780
  if (base === "flow.json") return dir;
2622
2781
  return dir;
2623
2782
  }
2624
2783
  function loadFlowWithMeta(keyOrPath) {
2625
2784
  const filePath = resolveFlowPath(keyOrPath);
2626
- if (!fs2.existsSync(filePath)) {
2785
+ if (!fs3.existsSync(filePath)) {
2627
2786
  throw new Error(`Flow not found: ${filePath}`);
2628
2787
  }
2629
- const content = fs2.readFileSync(filePath, "utf-8");
2788
+ const content = fs3.readFileSync(filePath, "utf-8");
2630
2789
  const flow = JSON.parse(content);
2631
2790
  return { flow, filePath, rootDir: getFlowRootDir(filePath) };
2632
2791
  }
@@ -2673,13 +2832,13 @@ function summarizeFlowInputs(flow) {
2673
2832
  }));
2674
2833
  }
2675
2834
  function listFlows() {
2676
- const flowsDir = path2.resolve(FLOWS_DIR);
2677
- if (!fs2.existsSync(flowsDir)) return [];
2835
+ const flowsDir = path3.resolve(FLOWS_DIR);
2836
+ if (!fs3.existsSync(flowsDir)) return [];
2678
2837
  const flows = [];
2679
2838
  const seenKeys = /* @__PURE__ */ new Set();
2680
2839
  const readFlowFile = (filePath, group) => {
2681
2840
  try {
2682
- const content = fs2.readFileSync(filePath, "utf-8");
2841
+ const content = fs3.readFileSync(filePath, "utf-8");
2683
2842
  const flow = JSON.parse(content);
2684
2843
  const nsKey = group ? `${group}/${flow.key}` : flow.key;
2685
2844
  if (seenKeys.has(nsKey)) return;
@@ -2691,7 +2850,7 @@ function listFlows() {
2691
2850
  inputCount: Object.keys(flow.inputs).length,
2692
2851
  stepCount: flow.steps.length,
2693
2852
  path: filePath,
2694
- layout: path2.basename(filePath) === "flow.json" ? "folder" : "legacy",
2853
+ layout: path3.basename(filePath) === "flow.json" ? "folder" : "legacy",
2695
2854
  group,
2696
2855
  stepTypes: collectStepTypes(flow),
2697
2856
  requiresBash: flowRequiresBash(flow),
@@ -2702,12 +2861,12 @@ function listFlows() {
2702
2861
  }
2703
2862
  };
2704
2863
  const scanDir = (dir, group) => {
2705
- for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
2864
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
2706
2865
  if (entry.name.startsWith(".")) continue;
2707
- const full = path2.join(dir, entry.name);
2866
+ const full = path3.join(dir, entry.name);
2708
2867
  if (entry.isDirectory()) {
2709
- const flowJson = path2.join(full, "flow.json");
2710
- if (fs2.existsSync(flowJson)) {
2868
+ const flowJson = path3.join(full, "flow.json");
2869
+ if (fs3.existsSync(flowJson)) {
2711
2870
  readFlowFile(flowJson, group);
2712
2871
  } else {
2713
2872
  if (!group) {
@@ -2725,7 +2884,7 @@ function listFlows() {
2725
2884
  function saveFlow(flow, outputPath, group) {
2726
2885
  let flowPath;
2727
2886
  if (outputPath) {
2728
- flowPath = path2.resolve(outputPath);
2887
+ flowPath = path3.resolve(outputPath);
2729
2888
  } else {
2730
2889
  let bareKey = flow.key;
2731
2890
  let resolvedGroup = group;
@@ -2735,21 +2894,21 @@ function saveFlow(flow, outputPath, group) {
2735
2894
  resolvedGroup = resolvedGroup || parts.join("/");
2736
2895
  flow.key = bareKey;
2737
2896
  }
2738
- const basePath = resolvedGroup ? path2.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path2.resolve(FLOWS_DIR, bareKey);
2739
- const legacyPath = path2.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
2740
- const folderPath = path2.join(basePath, "flow.json");
2741
- if (!resolvedGroup && fs2.existsSync(legacyPath) && !fs2.existsSync(folderPath)) {
2897
+ const basePath = resolvedGroup ? path3.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path3.resolve(FLOWS_DIR, bareKey);
2898
+ const legacyPath = path3.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
2899
+ const folderPath = path3.join(basePath, "flow.json");
2900
+ if (!resolvedGroup && fs3.existsSync(legacyPath) && !fs3.existsSync(folderPath)) {
2742
2901
  flowPath = legacyPath;
2743
2902
  } else {
2744
2903
  flowPath = folderPath;
2745
2904
  }
2746
2905
  }
2747
- const dir = path2.dirname(flowPath);
2906
+ const dir = path3.dirname(flowPath);
2748
2907
  ensureDir(dir);
2749
- if (path2.basename(flowPath) === "flow.json") {
2750
- ensureDir(path2.join(dir, "lib"));
2908
+ if (path3.basename(flowPath) === "flow.json") {
2909
+ ensureDir(path3.join(dir, "lib"));
2751
2910
  }
2752
- fs2.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
2911
+ fs3.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
2753
2912
  return flowPath;
2754
2913
  }
2755
2914
 
@@ -2762,6 +2921,19 @@ export {
2762
2921
  isActionAllowed,
2763
2922
  buildActionKnowledgeWithGuidance,
2764
2923
  validateActionInput,
2924
+ knowledgeCachePath,
2925
+ searchCachePath,
2926
+ readCache,
2927
+ writeCache,
2928
+ isFresh,
2929
+ getAge,
2930
+ buildCacheMeta,
2931
+ formatAge,
2932
+ listCacheEntries,
2933
+ clearAll,
2934
+ clearEntry,
2935
+ makeCacheEntry,
2936
+ resolveActionDetails,
2765
2937
  FLOW_SCHEMA,
2766
2938
  getStepTypeDescriptor,
2767
2939
  getNestedStepsKeys,
@@ -1,8 +1,10 @@
1
1
  import {
2
- getMemoryConfigOrDefault,
2
+ getMemoryConfigOrDefault
3
+ } from "./chunk-77564KWS.js";
4
+ import {
3
5
  getOpenAiApiKey,
4
6
  readConfig
5
- } from "./chunk-ZD5S4IWT.js";
7
+ } from "./chunk-TVIZC7AC.js";
6
8
 
7
9
  // src/lib/output.ts
8
10
  import * as p from "@clack/prompts";
@@ -4,9 +4,11 @@ import {
4
4
  embed,
5
5
  getMemoryConfig,
6
6
  getMemoryConfigOrDefault,
7
- getOpenAiApiKey,
8
7
  updateMemoryConfig
9
- } from "./chunk-ZD5S4IWT.js";
8
+ } from "./chunk-77564KWS.js";
9
+ import {
10
+ getOpenAiApiKey
11
+ } from "./chunk-TVIZC7AC.js";
10
12
 
11
13
  // src/lib/memory/schema.ts
12
14
  var SCHEMA_VERSION = "2.1.0";
@@ -3,10 +3,10 @@ import {
3
3
  isAgentMode,
4
4
  json,
5
5
  requireMemoryInit
6
- } from "./chunk-MNNKOQ6V.js";
6
+ } from "./chunk-KH4ERRJ5.js";
7
7
  import {
8
8
  getBackend
9
- } from "./chunk-YBEVCY4D.js";
9
+ } from "./chunk-TGWQUBKA.js";
10
10
 
11
11
  // src/commands/mem/sql.ts
12
12
  async function memSqlCommand(sql) {