@withone/cli 1.44.1 → 1.45.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.
@@ -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,159 @@ 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 cachePath = knowledgeCachePath(actionId);
676
+ const raw = useCache ? readCache(cachePath) : null;
677
+ const cached = isActionDetailsEntry(raw) ? raw : null;
678
+ if (cached && isFresh(cached)) {
679
+ return { details: cached.data, cacheHit: true, entry: cached };
680
+ }
681
+ try {
682
+ const result = await api.getActionDetailsWithMeta(actionId, cached?.etag ?? void 0);
683
+ if (result.status === 304 && cached) {
684
+ cached.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
685
+ writeCache(cachePath, cached);
686
+ return { details: cached.data, cacheHit: true, entry: cached };
687
+ }
688
+ const entry = makeCacheEntry(actionId, result.data, result.etag);
689
+ writeCache(cachePath, entry);
690
+ return { details: result.data, cacheHit: false, entry };
691
+ } catch (fetchError) {
692
+ if (cached) {
693
+ process.stderr.write(
694
+ `Warning: serving cached action details (network unavailable, cached ${formatAge(getAge(cached))} ago)
695
+ `
696
+ );
697
+ return { details: cached.data, cacheHit: true, entry: cached };
698
+ }
699
+ throw fetchError;
700
+ }
701
+ }
702
+
547
703
  // src/lib/validate.ts
548
704
  var SCHEMA_GROUP_TO_FLAG = {
549
705
  path: "--path-vars",
@@ -816,7 +972,7 @@ async function executeActionStep(step, context, api, permissions, allowedActionI
816
972
  if (!isActionAllowed(actionId, allowedActionIds)) {
817
973
  throw new Error(`Action "${actionId}" is not in the allowed action list`);
818
974
  }
819
- const actionDetails = await api.getActionDetails(actionId);
975
+ const { details: actionDetails } = await resolveActionDetails(api, actionId);
820
976
  if (!isMethodAllowed(actionDetails.method, permissions)) {
821
977
  throw new Error(`Method "${actionDetails.method}" is not allowed under "${permissions}" permission level`);
822
978
  }
@@ -899,15 +1055,15 @@ async function executeCodeModule(stepId, modulePath, context, options) {
899
1055
  if (!rootDir) {
900
1056
  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
1057
  }
902
- if (path.isAbsolute(modulePath)) {
1058
+ if (path2.isAbsolute(modulePath)) {
903
1059
  throw new Error(`Code module path must be relative to the flow root, got absolute: "${modulePath}"`);
904
1060
  }
905
- const absPath = path.resolve(rootDir, modulePath);
906
- const relFromRoot = path.relative(rootDir, absPath);
907
- if (relFromRoot.startsWith("..") || path.isAbsolute(relFromRoot)) {
1061
+ const absPath = path2.resolve(rootDir, modulePath);
1062
+ const relFromRoot = path2.relative(rootDir, absPath);
1063
+ if (relFromRoot.startsWith("..") || path2.isAbsolute(relFromRoot)) {
908
1064
  throw new Error(`Code module "${modulePath}" resolves outside the flow directory`);
909
1065
  }
910
- if (!fs.existsSync(absPath)) {
1066
+ if (!fs2.existsSync(absPath)) {
911
1067
  throw new Error(`Code module not found: ${absPath}`);
912
1068
  }
913
1069
  const { env: _omitEnv, ...safeContext } = context;
@@ -1055,8 +1211,8 @@ async function executeParallelStep(step, context, api, permissions, allowedActio
1055
1211
  function executeFileReadStep(step, context) {
1056
1212
  const config = step.fileRead;
1057
1213
  const filePath = resolveValue(config.path, context);
1058
- const resolvedPath = path.resolve(filePath);
1059
- const content = fs.readFileSync(resolvedPath, "utf-8");
1214
+ const resolvedPath = path2.resolve(filePath);
1215
+ const content = fs2.readFileSync(resolvedPath, "utf-8");
1060
1216
  const output = config.parseJson ? JSON.parse(stripCodeFences(content)) : content;
1061
1217
  return { status: "success", output, response: output };
1062
1218
  }
@@ -1064,16 +1220,16 @@ function executeFileWriteStep(step, context) {
1064
1220
  const config = step.fileWrite;
1065
1221
  const filePath = resolveValue(config.path, context);
1066
1222
  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 });
1223
+ const resolvedPath = path2.resolve(filePath);
1224
+ const dir = path2.dirname(resolvedPath);
1225
+ if (!fs2.existsSync(dir)) {
1226
+ fs2.mkdirSync(dir, { recursive: true });
1071
1227
  }
1072
1228
  const stringContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1073
1229
  if (config.append) {
1074
- fs.appendFileSync(resolvedPath, stringContent);
1230
+ fs2.appendFileSync(resolvedPath, stringContent);
1075
1231
  } else {
1076
- fs.writeFileSync(resolvedPath, stringContent);
1232
+ fs2.writeFileSync(resolvedPath, stringContent);
1077
1233
  }
1078
1234
  return { status: "success", output: { path: resolvedPath, bytesWritten: stringContent.length }, response: { path: resolvedPath } };
1079
1235
  }
@@ -1112,7 +1268,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
1112
1268
  if (flowStack.includes(resolvedKey)) {
1113
1269
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
1114
1270
  }
1115
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-EXZ77YLF.js");
1271
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-FQVTF36N.js");
1116
1272
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
1117
1273
  const subContext = await executeFlow(
1118
1274
  subFlow,
@@ -1215,11 +1371,11 @@ function resolveBashEnv(envConfig, context, stepId) {
1215
1371
  if ("json" in obj) {
1216
1372
  const resolved2 = resolveValue(obj.json, context);
1217
1373
  const json = JSON.stringify(resolved2 ?? null);
1218
- const tmp = path.join(
1219
- os.tmpdir(),
1374
+ const tmp = path2.join(
1375
+ os2.tmpdir(),
1220
1376
  `one-flow-${stepId}-${key}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`
1221
1377
  );
1222
- fs.writeFileSync(tmp, json, { encoding: "utf-8" });
1378
+ fs2.writeFileSync(tmp, json, { encoding: "utf-8" });
1223
1379
  tempFiles.push(tmp);
1224
1380
  out[key] = tmp;
1225
1381
  continue;
@@ -1266,7 +1422,7 @@ async function executeBashStep(step, context, options) {
1266
1422
  } finally {
1267
1423
  for (const tmp of tempFiles) {
1268
1424
  try {
1269
- fs.unlinkSync(tmp);
1425
+ fs2.unlinkSync(tmp);
1270
1426
  } catch {
1271
1427
  }
1272
1428
  }
@@ -1347,7 +1503,7 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
1347
1503
  if (step.type === "action" && step.action) {
1348
1504
  const actionId = resolveValue(step.action.actionId, context);
1349
1505
  try {
1350
- const actionDetails = await api.getActionDetails(actionId);
1506
+ const { details: actionDetails } = await resolveActionDetails(api, actionId);
1351
1507
  if (!options.skipValidation) {
1352
1508
  const data = step.action.data ? resolveValue(step.action.data, context) : void 0;
1353
1509
  const pathVars = step.action.pathVars ? resolveValue(step.action.pathVars, context) : void 0;
@@ -2389,8 +2545,8 @@ var FLOWS_DIR = ".one/flows";
2389
2545
  var RUNS_DIR = ".one/flows/.runs";
2390
2546
  var LOGS_DIR = ".one/flows/.logs";
2391
2547
  function ensureDir(dir) {
2392
- if (!fs2.existsSync(dir)) {
2393
- fs2.mkdirSync(dir, { recursive: true });
2548
+ if (!fs3.existsSync(dir)) {
2549
+ fs3.mkdirSync(dir, { recursive: true });
2394
2550
  }
2395
2551
  }
2396
2552
  function generateRunId() {
@@ -2408,8 +2564,8 @@ var FlowRunner = class _FlowRunner {
2408
2564
  this.flowKey = flow.key;
2409
2565
  ensureDir(RUNS_DIR);
2410
2566
  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`);
2567
+ this.statePath = path3.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
2568
+ this.logPath = path3.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
2413
2569
  const resolvedInputs = { ...inputs };
2414
2570
  for (const [name, decl] of Object.entries(flow.inputs)) {
2415
2571
  if (resolvedInputs[name] === void 0 && decl.default !== void 0) {
@@ -2450,10 +2606,10 @@ var FlowRunner = class _FlowRunner {
2450
2606
  msg,
2451
2607
  ...data
2452
2608
  };
2453
- fs2.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
2609
+ fs3.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
2454
2610
  }
2455
2611
  saveState() {
2456
- fs2.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
2612
+ fs3.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
2457
2613
  }
2458
2614
  createEventHandler(externalHandler) {
2459
2615
  return (event) => {
@@ -2551,10 +2707,10 @@ var FlowRunner = class _FlowRunner {
2551
2707
  }
2552
2708
  static loadRunState(runId) {
2553
2709
  ensureDir(RUNS_DIR);
2554
- const files = fs2.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
2710
+ const files = fs3.readdirSync(RUNS_DIR).filter((f) => f.includes(runId) && f.endsWith(".state.json"));
2555
2711
  if (files.length === 0) return null;
2556
2712
  try {
2557
- const content = fs2.readFileSync(path2.join(RUNS_DIR, files[0]), "utf-8");
2713
+ const content = fs3.readFileSync(path3.join(RUNS_DIR, files[0]), "utf-8");
2558
2714
  return JSON.parse(content);
2559
2715
  } catch {
2560
2716
  return null;
@@ -2566,17 +2722,17 @@ var FlowRunner = class _FlowRunner {
2566
2722
  runner.flowKey = state.flowKey;
2567
2723
  runner.state = state;
2568
2724
  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`);
2725
+ runner.statePath = path3.join(RUNS_DIR, `${state.flowKey}-${state.runId}.state.json`);
2726
+ runner.logPath = path3.join(LOGS_DIR, `${state.flowKey}-${state.runId}.log`);
2571
2727
  return runner;
2572
2728
  }
2573
2729
  static listRuns(flowKey) {
2574
2730
  ensureDir(RUNS_DIR);
2575
- const files = fs2.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
2731
+ const files = fs3.readdirSync(RUNS_DIR).filter((f) => f.endsWith(".state.json"));
2576
2732
  const runs = [];
2577
2733
  for (const file of files) {
2578
2734
  try {
2579
- const content = fs2.readFileSync(path2.join(RUNS_DIR, file), "utf-8");
2735
+ const content = fs3.readFileSync(path3.join(RUNS_DIR, file), "utf-8");
2580
2736
  const state = JSON.parse(content);
2581
2737
  if (!flowKey || state.flowKey === flowKey) {
2582
2738
  runs.push(state);
@@ -2589,44 +2745,44 @@ var FlowRunner = class _FlowRunner {
2589
2745
  };
2590
2746
  function resolveFlowPath(keyOrPath) {
2591
2747
  if (keyOrPath.endsWith(".json")) {
2592
- return path2.resolve(keyOrPath);
2748
+ return path3.resolve(keyOrPath);
2593
2749
  }
2594
2750
  if (keyOrPath.includes("\\")) {
2595
- return path2.resolve(keyOrPath);
2751
+ return path3.resolve(keyOrPath);
2596
2752
  }
2597
2753
  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;
2754
+ const nestedFolder = path3.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2755
+ if (fs3.existsSync(nestedFolder)) return nestedFolder;
2756
+ const literal = path3.resolve(keyOrPath);
2757
+ if (fs3.existsSync(literal)) return literal;
2602
2758
  return nestedFolder;
2603
2759
  }
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 })) {
2760
+ const folderPath = path3.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2761
+ if (fs3.existsSync(folderPath)) return folderPath;
2762
+ const legacyPath = path3.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
2763
+ if (fs3.existsSync(legacyPath)) return legacyPath;
2764
+ const flowsDir = path3.resolve(FLOWS_DIR);
2765
+ if (fs3.existsSync(flowsDir)) {
2766
+ for (const entry of fs3.readdirSync(flowsDir, { withFileTypes: true })) {
2611
2767
  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;
2768
+ const nested = path3.join(flowsDir, entry.name, keyOrPath, "flow.json");
2769
+ if (fs3.existsSync(nested)) return nested;
2614
2770
  }
2615
2771
  }
2616
2772
  return folderPath;
2617
2773
  }
2618
2774
  function getFlowRootDir(flowFilePath) {
2619
- const dir = path2.dirname(flowFilePath);
2620
- const base = path2.basename(flowFilePath);
2775
+ const dir = path3.dirname(flowFilePath);
2776
+ const base = path3.basename(flowFilePath);
2621
2777
  if (base === "flow.json") return dir;
2622
2778
  return dir;
2623
2779
  }
2624
2780
  function loadFlowWithMeta(keyOrPath) {
2625
2781
  const filePath = resolveFlowPath(keyOrPath);
2626
- if (!fs2.existsSync(filePath)) {
2782
+ if (!fs3.existsSync(filePath)) {
2627
2783
  throw new Error(`Flow not found: ${filePath}`);
2628
2784
  }
2629
- const content = fs2.readFileSync(filePath, "utf-8");
2785
+ const content = fs3.readFileSync(filePath, "utf-8");
2630
2786
  const flow = JSON.parse(content);
2631
2787
  return { flow, filePath, rootDir: getFlowRootDir(filePath) };
2632
2788
  }
@@ -2673,13 +2829,13 @@ function summarizeFlowInputs(flow) {
2673
2829
  }));
2674
2830
  }
2675
2831
  function listFlows() {
2676
- const flowsDir = path2.resolve(FLOWS_DIR);
2677
- if (!fs2.existsSync(flowsDir)) return [];
2832
+ const flowsDir = path3.resolve(FLOWS_DIR);
2833
+ if (!fs3.existsSync(flowsDir)) return [];
2678
2834
  const flows = [];
2679
2835
  const seenKeys = /* @__PURE__ */ new Set();
2680
2836
  const readFlowFile = (filePath, group) => {
2681
2837
  try {
2682
- const content = fs2.readFileSync(filePath, "utf-8");
2838
+ const content = fs3.readFileSync(filePath, "utf-8");
2683
2839
  const flow = JSON.parse(content);
2684
2840
  const nsKey = group ? `${group}/${flow.key}` : flow.key;
2685
2841
  if (seenKeys.has(nsKey)) return;
@@ -2691,7 +2847,7 @@ function listFlows() {
2691
2847
  inputCount: Object.keys(flow.inputs).length,
2692
2848
  stepCount: flow.steps.length,
2693
2849
  path: filePath,
2694
- layout: path2.basename(filePath) === "flow.json" ? "folder" : "legacy",
2850
+ layout: path3.basename(filePath) === "flow.json" ? "folder" : "legacy",
2695
2851
  group,
2696
2852
  stepTypes: collectStepTypes(flow),
2697
2853
  requiresBash: flowRequiresBash(flow),
@@ -2702,12 +2858,12 @@ function listFlows() {
2702
2858
  }
2703
2859
  };
2704
2860
  const scanDir = (dir, group) => {
2705
- for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
2861
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
2706
2862
  if (entry.name.startsWith(".")) continue;
2707
- const full = path2.join(dir, entry.name);
2863
+ const full = path3.join(dir, entry.name);
2708
2864
  if (entry.isDirectory()) {
2709
- const flowJson = path2.join(full, "flow.json");
2710
- if (fs2.existsSync(flowJson)) {
2865
+ const flowJson = path3.join(full, "flow.json");
2866
+ if (fs3.existsSync(flowJson)) {
2711
2867
  readFlowFile(flowJson, group);
2712
2868
  } else {
2713
2869
  if (!group) {
@@ -2725,7 +2881,7 @@ function listFlows() {
2725
2881
  function saveFlow(flow, outputPath, group) {
2726
2882
  let flowPath;
2727
2883
  if (outputPath) {
2728
- flowPath = path2.resolve(outputPath);
2884
+ flowPath = path3.resolve(outputPath);
2729
2885
  } else {
2730
2886
  let bareKey = flow.key;
2731
2887
  let resolvedGroup = group;
@@ -2735,21 +2891,21 @@ function saveFlow(flow, outputPath, group) {
2735
2891
  resolvedGroup = resolvedGroup || parts.join("/");
2736
2892
  flow.key = bareKey;
2737
2893
  }
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)) {
2894
+ const basePath = resolvedGroup ? path3.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path3.resolve(FLOWS_DIR, bareKey);
2895
+ const legacyPath = path3.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
2896
+ const folderPath = path3.join(basePath, "flow.json");
2897
+ if (!resolvedGroup && fs3.existsSync(legacyPath) && !fs3.existsSync(folderPath)) {
2742
2898
  flowPath = legacyPath;
2743
2899
  } else {
2744
2900
  flowPath = folderPath;
2745
2901
  }
2746
2902
  }
2747
- const dir = path2.dirname(flowPath);
2903
+ const dir = path3.dirname(flowPath);
2748
2904
  ensureDir(dir);
2749
- if (path2.basename(flowPath) === "flow.json") {
2750
- ensureDir(path2.join(dir, "lib"));
2905
+ if (path3.basename(flowPath) === "flow.json") {
2906
+ ensureDir(path3.join(dir, "lib"));
2751
2907
  }
2752
- fs2.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
2908
+ fs3.writeFileSync(flowPath, JSON.stringify(flow, null, 2) + "\n");
2753
2909
  return flowPath;
2754
2910
  }
2755
2911
 
@@ -2762,6 +2918,19 @@ export {
2762
2918
  isActionAllowed,
2763
2919
  buildActionKnowledgeWithGuidance,
2764
2920
  validateActionInput,
2921
+ knowledgeCachePath,
2922
+ searchCachePath,
2923
+ readCache,
2924
+ writeCache,
2925
+ isFresh,
2926
+ getAge,
2927
+ buildCacheMeta,
2928
+ formatAge,
2929
+ listCacheEntries,
2930
+ clearAll,
2931
+ clearEntry,
2932
+ makeCacheEntry,
2933
+ resolveActionDetails,
2765
2934
  FLOW_SCHEMA,
2766
2935
  getStepTypeDescriptor,
2767
2936
  getNestedStepsKeys,
@@ -6,11 +6,11 @@ import {
6
6
  note,
7
7
  okJson,
8
8
  requireMemoryInit
9
- } from "./chunk-MNNKOQ6V.js";
9
+ } from "./chunk-KH4ERRJ5.js";
10
10
  import {
11
11
  getBackend,
12
12
  upsertRecord
13
- } from "./chunk-YBEVCY4D.js";
13
+ } from "./chunk-TGWQUBKA.js";
14
14
 
15
15
  // src/commands/mem/migrate.ts
16
16
  import fs4 from "fs";
@@ -2,7 +2,8 @@ import {
2
2
  defaultSearchableText,
3
3
  embed,
4
4
  embedBatch
5
- } from "./chunk-ZD5S4IWT.js";
5
+ } from "./chunk-77564KWS.js";
6
+ import "./chunk-TVIZC7AC.js";
6
7
  export {
7
8
  defaultSearchableText,
8
9
  embed,
@@ -11,8 +11,9 @@ import {
11
11
  saveFlow,
12
12
  summarizeFlowInputs,
13
13
  walkSteps
14
- } from "./chunk-YGOS6KEC.js";
14
+ } from "./chunk-UXKF6AEG.js";
15
15
  import "./chunk-44CV5IMX.js";
16
+ import "./chunk-TVIZC7AC.js";
16
17
  export {
17
18
  FlowRunner,
18
19
  collectStepTypes,