@withone/cli 1.42.0 → 1.43.2

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.
@@ -0,0 +1,477 @@
1
+ // src/lib/config.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import os from "os";
5
+ function configDir() {
6
+ return path.join(os.homedir(), ".one");
7
+ }
8
+ function configFile() {
9
+ return path.join(configDir(), "config.json");
10
+ }
11
+ function projectsDir() {
12
+ return path.join(configDir(), "projects");
13
+ }
14
+ function getProjectRoot(cwd = process.cwd()) {
15
+ let dir = path.resolve(cwd);
16
+ const root = path.parse(dir).root;
17
+ while (dir !== root) {
18
+ if (fs.existsSync(path.join(dir, ".git")) || fs.existsSync(path.join(dir, "package.json"))) {
19
+ return dir;
20
+ }
21
+ dir = path.dirname(dir);
22
+ }
23
+ return path.resolve(cwd);
24
+ }
25
+ function getProjectSlug(projectRoot = getProjectRoot()) {
26
+ return projectRoot.replace(/[\\/]/g, "-");
27
+ }
28
+ function getProjectConfigDir(projectRoot = getProjectRoot()) {
29
+ return path.join(projectsDir(), getProjectSlug(projectRoot));
30
+ }
31
+ function getProjectConfigPath(projectRoot = getProjectRoot()) {
32
+ return path.join(getProjectConfigDir(projectRoot), "config.json");
33
+ }
34
+ function getGlobalConfigPath() {
35
+ return configFile();
36
+ }
37
+ function resolveConfig() {
38
+ const projectRoot = getProjectRoot();
39
+ const projectSlug = getProjectSlug(projectRoot);
40
+ const projectPath = getProjectConfigPath(projectRoot);
41
+ if (fs.existsSync(projectPath)) {
42
+ const config = readConfigFile(projectPath);
43
+ if (config) {
44
+ return { config, scope: "project", path: projectPath, projectRoot, projectSlug };
45
+ }
46
+ }
47
+ const root = path.parse(process.cwd()).root;
48
+ let dir = path.resolve(process.cwd());
49
+ while (dir !== root) {
50
+ dir = path.dirname(dir);
51
+ const slug = getProjectSlug(dir);
52
+ const configPath = path.join(projectsDir(), slug, "config.json");
53
+ if (fs.existsSync(configPath)) {
54
+ const config = readConfigFile(configPath);
55
+ if (config) {
56
+ return { config, scope: "project", path: configPath, projectRoot: dir, projectSlug: slug };
57
+ }
58
+ }
59
+ }
60
+ if (fs.existsSync(configFile())) {
61
+ const config = readConfigFile(configFile());
62
+ if (config) {
63
+ return { config, scope: "global", path: configFile(), projectRoot, projectSlug };
64
+ }
65
+ }
66
+ return { config: null, scope: null, path: configFile(), projectRoot, projectSlug };
67
+ }
68
+ function readConfigFile(filePath) {
69
+ try {
70
+ const content = fs.readFileSync(filePath, "utf-8");
71
+ return JSON.parse(content);
72
+ } catch {
73
+ return null;
74
+ }
75
+ }
76
+ function configExists() {
77
+ return resolveConfig().config !== null;
78
+ }
79
+ function globalConfigExists() {
80
+ return fs.existsSync(configFile());
81
+ }
82
+ function projectConfigExists(projectRoot = getProjectRoot()) {
83
+ return fs.existsSync(getProjectConfigPath(projectRoot));
84
+ }
85
+ function readConfig() {
86
+ return resolveConfig().config;
87
+ }
88
+ function readGlobalConfig() {
89
+ if (!fs.existsSync(configFile())) return null;
90
+ return readConfigFile(configFile());
91
+ }
92
+ function readProjectConfig() {
93
+ const projectPath = getProjectConfigPath();
94
+ if (!fs.existsSync(projectPath)) return null;
95
+ return readConfigFile(projectPath);
96
+ }
97
+ function writeConfig(config, scope) {
98
+ const targetScope = scope ?? resolveConfig().scope ?? "global";
99
+ if (targetScope === "project") {
100
+ const dir = getProjectConfigDir();
101
+ if (!fs.existsSync(dir)) {
102
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
103
+ }
104
+ const filePath = getProjectConfigPath();
105
+ fs.writeFileSync(filePath, JSON.stringify(config, null, 2), { mode: 384 });
106
+ return;
107
+ }
108
+ if (!fs.existsSync(configDir())) {
109
+ fs.mkdirSync(configDir(), { mode: 448 });
110
+ }
111
+ fs.writeFileSync(configFile(), JSON.stringify(config, null, 2), { mode: 384 });
112
+ }
113
+ function readOneRc() {
114
+ const rcPath = path.join(process.cwd(), ".onerc");
115
+ if (!fs.existsSync(rcPath)) return {};
116
+ try {
117
+ const content = fs.readFileSync(rcPath, "utf-8");
118
+ const result = {};
119
+ for (const line of content.split("\n")) {
120
+ const trimmed = line.trim();
121
+ if (!trimmed || trimmed.startsWith("#")) continue;
122
+ const eqIndex = trimmed.indexOf("=");
123
+ if (eqIndex === -1) continue;
124
+ const key = trimmed.slice(0, eqIndex).trim();
125
+ const value = trimmed.slice(eqIndex + 1).trim();
126
+ result[key] = value;
127
+ }
128
+ return result;
129
+ } catch {
130
+ return {};
131
+ }
132
+ }
133
+ function getApiKey() {
134
+ if (process.env.ONE_SECRET) return process.env.ONE_SECRET;
135
+ const rc = readOneRc();
136
+ if (rc.ONE_SECRET) return rc.ONE_SECRET;
137
+ return readConfig()?.apiKey ?? null;
138
+ }
139
+ function getOpenAiApiKey() {
140
+ if (process.env.OPENAI_API_KEY) return process.env.OPENAI_API_KEY;
141
+ const rc = readOneRc();
142
+ if (rc.OPENAI_API_KEY) return rc.OPENAI_API_KEY;
143
+ return readConfig()?.openaiApiKey ?? null;
144
+ }
145
+ function setOpenAiApiKey(key) {
146
+ const resolved = resolveConfig();
147
+ if (!resolved.config) {
148
+ throw new Error("No One config found. Run `one init` first.");
149
+ }
150
+ if (key === "") {
151
+ delete resolved.config.openaiApiKey;
152
+ } else {
153
+ resolved.config.openaiApiKey = key;
154
+ }
155
+ writeConfig(resolved.config, resolved.scope ?? "global");
156
+ }
157
+ function getAccessControlFromAllSources() {
158
+ const rc = readOneRc();
159
+ const fileAc = getAccessControl();
160
+ const merged = { ...fileAc };
161
+ if (rc.ONE_PERMISSIONS) {
162
+ merged.permissions = rc.ONE_PERMISSIONS;
163
+ }
164
+ if (rc.ONE_CONNECTION_KEYS) {
165
+ merged.connectionKeys = rc.ONE_CONNECTION_KEYS.split(",").map((s) => s.trim()).filter(Boolean);
166
+ }
167
+ if (rc.ONE_ACTION_IDS) {
168
+ merged.actionIds = rc.ONE_ACTION_IDS.split(",").map((s) => s.trim()).filter(Boolean);
169
+ }
170
+ if (rc.ONE_KNOWLEDGE_AGENT) {
171
+ merged.knowledgeAgent = rc.ONE_KNOWLEDGE_AGENT === "true";
172
+ }
173
+ return merged;
174
+ }
175
+ function getAccessControl() {
176
+ return readConfig()?.accessControl ?? {};
177
+ }
178
+ var DEFAULT_API_BASE = "https://api.withone.ai/v1";
179
+ function getApiBase() {
180
+ const config = readConfig();
181
+ if (config?.apiBase) return `${config.apiBase}/v1`;
182
+ return DEFAULT_API_BASE;
183
+ }
184
+ function updateApiBase(url) {
185
+ const config = readConfig();
186
+ if (!config) return;
187
+ if (url) {
188
+ config.apiBase = url;
189
+ } else {
190
+ delete config.apiBase;
191
+ }
192
+ delete config.whoami;
193
+ writeConfig(config);
194
+ }
195
+ function getCacheTtl() {
196
+ if (process.env.ONE_CACHE_TTL) {
197
+ const val = parseInt(process.env.ONE_CACHE_TTL, 10);
198
+ if (!isNaN(val) && val > 0) return val;
199
+ }
200
+ const config = readConfig();
201
+ if (config?.cacheTtl && config.cacheTtl > 0) return config.cacheTtl;
202
+ return 3600;
203
+ }
204
+ function updateAccessControl(settings) {
205
+ const config = readConfig();
206
+ if (!config) return;
207
+ const cleaned = {};
208
+ if (settings.permissions && settings.permissions !== "admin") {
209
+ cleaned.permissions = settings.permissions;
210
+ }
211
+ if (settings.connectionKeys && !(settings.connectionKeys.length === 1 && settings.connectionKeys[0] === "*")) {
212
+ cleaned.connectionKeys = settings.connectionKeys;
213
+ }
214
+ if (settings.actionIds && !(settings.actionIds.length === 1 && settings.actionIds[0] === "*")) {
215
+ cleaned.actionIds = settings.actionIds;
216
+ }
217
+ if (settings.knowledgeAgent) {
218
+ cleaned.knowledgeAgent = true;
219
+ }
220
+ if (Object.keys(cleaned).length === 0) {
221
+ delete config.accessControl;
222
+ } else {
223
+ config.accessControl = cleaned;
224
+ }
225
+ writeConfig(config);
226
+ }
227
+ function getWhoAmI() {
228
+ return readConfig()?.whoami ?? null;
229
+ }
230
+ function updateWhoAmI(whoami) {
231
+ const config = readConfig();
232
+ if (!config) return;
233
+ config.whoami = whoami;
234
+ writeConfig(config);
235
+ }
236
+ async function ensureWhoAmI(api) {
237
+ const cached = getWhoAmI();
238
+ if (cached) return cached;
239
+ try {
240
+ const whoami = await api.whoami();
241
+ updateWhoAmI(whoami);
242
+ return whoami;
243
+ } catch {
244
+ return null;
245
+ }
246
+ }
247
+ function getEnvFromApiKey(apiKey) {
248
+ return apiKey.startsWith("sk_test_") ? "test" : "live";
249
+ }
250
+
251
+ // src/lib/memory/config.ts
252
+ var DEFAULT_MEMORY_CONFIG = {
253
+ backend: "embedded-postgres",
254
+ plugins: [],
255
+ embedding: {
256
+ provider: "none",
257
+ model: "text-embedding-3-small",
258
+ dimensions: 1536
259
+ },
260
+ defaults: {
261
+ trackAccessOnSearch: true,
262
+ embedOnAdd: true,
263
+ embedOnSync: false
264
+ }
265
+ };
266
+ function getMemoryConfig() {
267
+ const config = readConfig();
268
+ return config?.memory ?? null;
269
+ }
270
+ function getMemoryConfigOrDefault() {
271
+ return getMemoryConfig() ?? DEFAULT_MEMORY_CONFIG;
272
+ }
273
+ function memoryConfigExists() {
274
+ return getMemoryConfig() !== null;
275
+ }
276
+ function updateMemoryConfig(patch, opts = {}) {
277
+ const config = readConfig();
278
+ if (!config) {
279
+ throw new Error("No One config found. Run `one init` first.");
280
+ }
281
+ const current = config.memory ?? DEFAULT_MEMORY_CONFIG;
282
+ const next = opts.replace ? patch : { ...current, ...patch };
283
+ config.memory = next;
284
+ writeConfig(config);
285
+ return next;
286
+ }
287
+ function getEmbeddingApiKey() {
288
+ const fromCore = getOpenAiApiKey();
289
+ if (fromCore) return fromCore;
290
+ const mem = getMemoryConfig();
291
+ return mem?.embedding.apiKey ?? null;
292
+ }
293
+ function setOpenAiApiKey2(key) {
294
+ setOpenAiApiKey(key);
295
+ if (key === "") return;
296
+ const mem = getMemoryConfig();
297
+ if (!mem) return;
298
+ if (mem.embedding.provider === "openai") return;
299
+ updateMemoryConfig({
300
+ ...mem,
301
+ embedding: { ...mem.embedding, provider: "openai" }
302
+ });
303
+ }
304
+
305
+ // src/lib/memory/embedding.ts
306
+ var FETCH_TIMEOUT_MS = 3e4;
307
+ function fetchWithTimeout(url, init, timeoutMs) {
308
+ const ctrl = new AbortController();
309
+ const t = setTimeout(() => ctrl.abort(), timeoutMs);
310
+ return fetch(url, { ...init, signal: ctrl.signal }).finally(() => clearTimeout(t));
311
+ }
312
+ async function embed(text, opts = {}) {
313
+ const clean = text?.trim();
314
+ if (!clean) return null;
315
+ const cfg = getMemoryConfigOrDefault();
316
+ if (cfg.embedding.provider !== "openai") return null;
317
+ const apiKey = getEmbeddingApiKey();
318
+ if (!apiKey) return null;
319
+ const model = opts.model ?? cfg.embedding.model;
320
+ const dimensions = cfg.embedding.dimensions;
321
+ for (let attempt = 0; attempt < 3; attempt++) {
322
+ try {
323
+ const res = await fetchWithTimeout("https://api.openai.com/v1/embeddings", {
324
+ method: "POST",
325
+ headers: {
326
+ "Content-Type": "application/json",
327
+ Authorization: `Bearer ${apiKey}`
328
+ },
329
+ body: JSON.stringify({
330
+ model,
331
+ input: clean.slice(0, 8e3),
332
+ dimensions
333
+ })
334
+ }, FETCH_TIMEOUT_MS);
335
+ if (!res.ok) {
336
+ if (res.status === 429 || res.status >= 500) {
337
+ await sleep(500 * (attempt + 1));
338
+ continue;
339
+ }
340
+ const body2 = await res.text();
341
+ throw new Error(`OpenAI embeddings ${res.status}: ${body2}`);
342
+ }
343
+ const body = await res.json();
344
+ const vector = body.data[0]?.embedding;
345
+ if (!vector || vector.length !== dimensions) {
346
+ throw new Error(`Unexpected embedding shape (got length ${vector?.length})`);
347
+ }
348
+ return { vector, model: `openai:${model}` };
349
+ } catch (err) {
350
+ if (attempt === 2) {
351
+ process.stderr.write(`[mem] embedding failed: ${err instanceof Error ? err.message : String(err)}
352
+ `);
353
+ return null;
354
+ }
355
+ await sleep(500 * (attempt + 1));
356
+ }
357
+ }
358
+ return null;
359
+ }
360
+ async function embedBatch(texts, opts = {}) {
361
+ if (texts.length === 0) return [];
362
+ const cfg = getMemoryConfigOrDefault();
363
+ if (cfg.embedding.provider !== "openai") return texts.map(() => null);
364
+ const apiKey = getEmbeddingApiKey();
365
+ if (!apiKey) return texts.map(() => null);
366
+ const model = opts.model ?? cfg.embedding.model;
367
+ const dimensions = cfg.embedding.dimensions;
368
+ const active = [];
369
+ texts.forEach((t, i) => {
370
+ const clean = t?.trim();
371
+ if (clean) active.push({ index: i, input: clean.slice(0, 8e3) });
372
+ });
373
+ if (active.length === 0) return texts.map(() => null);
374
+ const result = texts.map(() => null);
375
+ for (let attempt = 0; attempt < 3; attempt++) {
376
+ try {
377
+ const res = await fetchWithTimeout("https://api.openai.com/v1/embeddings", {
378
+ method: "POST",
379
+ headers: {
380
+ "Content-Type": "application/json",
381
+ Authorization: `Bearer ${apiKey}`
382
+ },
383
+ body: JSON.stringify({
384
+ model,
385
+ input: active.map((a) => a.input),
386
+ dimensions
387
+ })
388
+ }, FETCH_TIMEOUT_MS);
389
+ if (!res.ok) {
390
+ if (res.status === 429 || res.status >= 500) {
391
+ await sleep(500 * (attempt + 1));
392
+ continue;
393
+ }
394
+ const body2 = await res.text();
395
+ throw new Error(`OpenAI embeddings ${res.status}: ${body2}`);
396
+ }
397
+ const body = await res.json();
398
+ for (const item of body.data) {
399
+ const slot = active[item.index];
400
+ if (!slot) continue;
401
+ result[slot.index] = { vector: item.embedding, model: `openai:${model}` };
402
+ }
403
+ return result;
404
+ } catch (err) {
405
+ if (attempt === 2) {
406
+ process.stderr.write(`[mem] batch embedding failed: ${err instanceof Error ? err.message : String(err)}
407
+ `);
408
+ return result;
409
+ }
410
+ await sleep(500 * (attempt + 1));
411
+ }
412
+ }
413
+ return result;
414
+ }
415
+ function sleep(ms) {
416
+ return new Promise((resolve) => setTimeout(resolve, ms));
417
+ }
418
+ function defaultSearchableText(data, maxLen = 4e3) {
419
+ const parts = [];
420
+ const walk = (value, depth = 0) => {
421
+ if (value === null || value === void 0) return;
422
+ if (typeof value === "string" && value.trim()) {
423
+ parts.push(value.trim());
424
+ return;
425
+ }
426
+ if (typeof value === "number" || typeof value === "boolean") {
427
+ parts.push(String(value));
428
+ return;
429
+ }
430
+ if (depth > 4) return;
431
+ if (Array.isArray(value)) {
432
+ for (const v of value) walk(v, depth + 1);
433
+ return;
434
+ }
435
+ if (typeof value === "object") {
436
+ for (const v of Object.values(value)) walk(v, depth + 1);
437
+ }
438
+ };
439
+ walk(data);
440
+ const joined = parts.join(" ").replace(/\s+/g, " ").trim();
441
+ return joined.length > maxLen ? joined.slice(0, maxLen) : joined;
442
+ }
443
+
444
+ export {
445
+ getProjectRoot,
446
+ getProjectConfigPath,
447
+ getGlobalConfigPath,
448
+ resolveConfig,
449
+ configExists,
450
+ globalConfigExists,
451
+ projectConfigExists,
452
+ readConfig,
453
+ readGlobalConfig,
454
+ readProjectConfig,
455
+ writeConfig,
456
+ getApiKey,
457
+ getOpenAiApiKey,
458
+ getAccessControlFromAllSources,
459
+ getAccessControl,
460
+ getApiBase,
461
+ updateApiBase,
462
+ getCacheTtl,
463
+ updateAccessControl,
464
+ getWhoAmI,
465
+ updateWhoAmI,
466
+ ensureWhoAmI,
467
+ getEnvFromApiKey,
468
+ DEFAULT_MEMORY_CONFIG,
469
+ getMemoryConfig,
470
+ getMemoryConfigOrDefault,
471
+ memoryConfigExists,
472
+ updateMemoryConfig,
473
+ setOpenAiApiKey2 as setOpenAiApiKey,
474
+ embed,
475
+ embedBatch,
476
+ defaultSearchableText
477
+ };
@@ -1,3 +1,8 @@
1
+ import {
2
+ getByDotPath,
3
+ setByDotPath
4
+ } from "./chunk-44CV5IMX.js";
5
+
1
6
  // src/lib/flow-runner.ts
2
7
  import fs2 from "fs";
3
8
  import path2 from "path";
@@ -571,40 +576,6 @@ function validateActionInput(action, args) {
571
576
  return { valid: false, missing };
572
577
  }
573
578
 
574
- // src/lib/dot-path.ts
575
- function getByDotPath(obj, dotPath) {
576
- const parts = dotPath.split(".").flatMap((part) => {
577
- const bracketMatch = part.match(/^([^[]+)\[(\d+)\]$/);
578
- if (bracketMatch) {
579
- return [bracketMatch[1], bracketMatch[2]];
580
- }
581
- return [part];
582
- });
583
- let current = obj;
584
- for (const part of parts) {
585
- if (current === null || current === void 0) return void 0;
586
- if (Array.isArray(current) && /^\d+$/.test(part)) {
587
- current = current[parseInt(part, 10)];
588
- } else if (typeof current === "object") {
589
- current = current[part];
590
- } else {
591
- return void 0;
592
- }
593
- }
594
- return current;
595
- }
596
- function setByDotPath(obj, dotPath, value) {
597
- const parts = dotPath.split(".");
598
- let current = obj;
599
- for (let i = 0; i < parts.length - 1; i++) {
600
- if (current[parts[i]] === void 0 || current[parts[i]] === null) {
601
- current[parts[i]] = {};
602
- }
603
- current = current[parts[i]];
604
- }
605
- current[parts[parts.length - 1]] = value;
606
- }
607
-
608
579
  // src/lib/flow-engine.ts
609
580
  var execAsync = promisify(exec);
610
581
  function sleep2(ms) {
@@ -1140,7 +1111,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
1140
1111
  if (flowStack.includes(resolvedKey)) {
1141
1112
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
1142
1113
  }
1143
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-Y2CXXU3U.js");
1114
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-XSJ4US5S.js");
1144
1115
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
1145
1116
  const subContext = await executeFlow(
1146
1117
  subFlow,
@@ -2794,7 +2765,6 @@ export {
2794
2765
  getStepTypeDescriptor,
2795
2766
  getNestedStepsKeys,
2796
2767
  generateFlowGuide,
2797
- getByDotPath,
2798
2768
  FlowRunner,
2799
2769
  resolveFlowPath,
2800
2770
  getFlowRootDir,
@@ -0,0 +1,158 @@
1
+ import {
2
+ getMemoryConfigOrDefault,
3
+ getOpenAiApiKey,
4
+ readConfig
5
+ } from "./chunk-AU2ZEEMS.js";
6
+
7
+ // src/lib/output.ts
8
+ import * as p from "@clack/prompts";
9
+ var _agentMode = false;
10
+ function setAgentMode(value) {
11
+ _agentMode = value;
12
+ }
13
+ function isAgentMode() {
14
+ return _agentMode || process.env.ONE_AGENT === "1";
15
+ }
16
+ function createSpinner() {
17
+ if (isAgentMode()) {
18
+ return { start() {
19
+ }, stop() {
20
+ } };
21
+ }
22
+ return p.spinner();
23
+ }
24
+ function intro2(msg) {
25
+ if (!isAgentMode()) p.intro(msg);
26
+ }
27
+ function outro2(msg) {
28
+ if (!isAgentMode()) p.outro(msg);
29
+ }
30
+ function note2(msg, title) {
31
+ if (!isAgentMode()) p.note(msg, title);
32
+ }
33
+ function cancel2(msg) {
34
+ if (!isAgentMode()) p.cancel(msg);
35
+ }
36
+ function json(data) {
37
+ process.stdout.write(JSON.stringify(data) + "\n");
38
+ }
39
+ function error(message, exitCode = 1) {
40
+ if (isAgentMode()) {
41
+ json({ error: message });
42
+ } else {
43
+ p.cancel(message);
44
+ }
45
+ process.exit(exitCode);
46
+ }
47
+
48
+ // src/commands/mem/util.ts
49
+ function requireMemoryInit() {
50
+ if (!readConfig()) {
51
+ error("No One config found. Run `one init` first.");
52
+ }
53
+ }
54
+ function parseJsonArg(arg, field = "data") {
55
+ try {
56
+ const parsed = JSON.parse(arg);
57
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
58
+ error(`${field} must be a JSON object, not ${Array.isArray(parsed) ? "an array" : typeof parsed}.`);
59
+ }
60
+ return parsed;
61
+ } catch (err) {
62
+ error(`Invalid JSON for ${field}: ${err instanceof Error ? err.message : String(err)}`);
63
+ }
64
+ }
65
+ function parseCsv(value) {
66
+ if (!value) return void 0;
67
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
68
+ }
69
+ function parsePositiveInt(value, fallback, label = "value") {
70
+ if (value === void 0) return fallback;
71
+ const n = Number.parseInt(value, 10);
72
+ if (!Number.isFinite(n) || n <= 0) {
73
+ error(`${label} must be a positive integer`);
74
+ }
75
+ return n;
76
+ }
77
+ function printRecord(record) {
78
+ if (isAgentMode()) {
79
+ json(record);
80
+ return;
81
+ }
82
+ console.log(JSON.stringify(record, null, 2));
83
+ }
84
+ function printList(items) {
85
+ if (isAgentMode()) {
86
+ json({ items, total: items.length });
87
+ return;
88
+ }
89
+ if (items.length === 0) {
90
+ console.log("(no results)");
91
+ return;
92
+ }
93
+ console.log(JSON.stringify(items, null, 2));
94
+ }
95
+ function okJson(payload) {
96
+ if (isAgentMode()) {
97
+ json(payload);
98
+ return;
99
+ }
100
+ console.log(JSON.stringify(payload, null, 2));
101
+ }
102
+ function semanticSearchUpgradeHint(opts = {}) {
103
+ const cfg = getMemoryConfigOrDefault();
104
+ const keyPresent = !!getOpenAiApiKey();
105
+ const providerOn = cfg.embedding.provider === "openai";
106
+ if (opts.vectorSearchAvailable === false) {
107
+ return {
108
+ capability: "semantic_search",
109
+ available: true,
110
+ currentMode: "fts_only",
111
+ how: "Install pgvector for the bundled Postgres: `brew install pgvector` (or point at a remote Postgres with pgvector via `one mem config set backend postgres`)",
112
+ benefit: "Ranks memories by meaning, not just keyword overlap \u2014 finds relevant records even when the query and the data use different words."
113
+ };
114
+ }
115
+ if (providerOn && keyPresent) return null;
116
+ if (!keyPresent) {
117
+ return {
118
+ capability: "semantic_search",
119
+ available: true,
120
+ currentMode: "fts_only",
121
+ how: 'Add an OpenAI key: `one init` (then "Add OpenAI key"), or `one mem config set embedding.apiKey sk-...`',
122
+ benefit: "Ranks memories by meaning, not just keyword overlap \u2014 finds relevant records even when the query and the data use different words."
123
+ };
124
+ }
125
+ return {
126
+ capability: "semantic_search",
127
+ available: true,
128
+ currentMode: "fts_only",
129
+ how: "Flip the provider on: `one mem config set embedding.provider openai`",
130
+ benefit: "Ranks memories by meaning, not just keyword overlap."
131
+ };
132
+ }
133
+ function semanticSearchUpgradeLine(opts = {}) {
134
+ const hint = semanticSearchUpgradeHint(opts);
135
+ if (!hint) return "";
136
+ return `tip: semantic search available \u2014 ${hint.how}`;
137
+ }
138
+
139
+ export {
140
+ setAgentMode,
141
+ isAgentMode,
142
+ createSpinner,
143
+ intro2 as intro,
144
+ outro2 as outro,
145
+ note2 as note,
146
+ cancel2 as cancel,
147
+ json,
148
+ error,
149
+ requireMemoryInit,
150
+ parseJsonArg,
151
+ parseCsv,
152
+ parsePositiveInt,
153
+ printRecord,
154
+ printList,
155
+ okJson,
156
+ semanticSearchUpgradeHint,
157
+ semanticSearchUpgradeLine
158
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ defaultSearchableText,
3
+ embed,
4
+ embedBatch
5
+ } from "./chunk-AU2ZEEMS.js";
6
+ export {
7
+ defaultSearchableText,
8
+ embed,
9
+ embedBatch
10
+ };