@withone/cli 1.57.0 → 1.57.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.
package/README.md CHANGED
@@ -377,7 +377,7 @@ Note: execution responses are never cached — the action always runs live. Only
377
377
 
378
378
  ### `one mem` — unified memory store
379
379
 
380
- One ships a local memory store (a real Postgres process bootstrapped on demand via the bundled `embedded-postgres` plugin, with a `postgres` plugin for remote/self-hosted) that backs both user-authored notes and synced platform data. **Zero-config** — the first `one mem` call on a fresh machine auto-initializes the cluster at `~/.one/pg/cluster/` and writes a daemon PID file so subsequent CLI invocations reuse it.
380
+ One ships a local memory store (a real Postgres process bootstrapped on demand via the bundled `embedded-postgres` plugin, with a `postgres` plugin for remote/self-hosted) that backs both user-authored notes and synced platform data. **Zero-config** — the first `one mem` call on a fresh machine auto-initializes the cluster at `~/.one/pg/cluster/` and writes a daemon PID file so subsequent CLI invocations reuse it. The daemon listens on port 5434, moving to the next free port if another program already holds it; pin a port with `one mem config set embedded-postgres.port <n>`.
381
381
 
382
382
  ```bash
383
383
  # User memories — works immediately on a new install
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-OLQ55K6B.js";
7
7
  import {
8
8
  getBackend
9
- } from "./chunk-VH46MAE4.js";
9
+ } from "./chunk-IMU2X3ZV.js";
10
10
 
11
11
  // src/commands/mem/sql.ts
12
12
  async function memSqlCommand(sql) {
@@ -1456,12 +1456,333 @@ var postgresPlugin = {
1456
1456
  };
1457
1457
 
1458
1458
  // src/lib/memory/plugins/embedded-postgres/index.ts
1459
+ import path2 from "path";
1460
+
1461
+ // src/lib/memory/plugins/embedded-postgres/daemon.ts
1459
1462
  import fs from "fs";
1460
1463
  import net from "net";
1461
1464
  import path from "path";
1462
1465
  import { createRequire } from "module";
1463
- import { spawn } from "child_process";
1466
+ import { spawn, spawnSync } from "child_process";
1464
1467
  var requireFromHere = createRequire(import.meta.url);
1468
+ var PG_PORT_OFFSET = 1e3;
1469
+ var PORT_SEARCH_SPAN = 20;
1470
+ var LOG_MAX_BYTES = 10 * 1024 * 1024;
1471
+ var LOG_KEEP_BYTES = 1024 * 1024;
1472
+ var DEFAULT_STOP_TIMEOUT_MS = 15e3;
1473
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
1474
+ function pidFilePath(dataDir) {
1475
+ return path.join(dataDir, ".pgserve.json");
1476
+ }
1477
+ function readPidFile(dataDir) {
1478
+ try {
1479
+ return JSON.parse(fs.readFileSync(pidFilePath(dataDir), "utf8"));
1480
+ } catch {
1481
+ return null;
1482
+ }
1483
+ }
1484
+ function writePidFile(dataDir, rec) {
1485
+ fs.mkdirSync(dataDir, { recursive: true });
1486
+ fs.writeFileSync(pidFilePath(dataDir), JSON.stringify(rec, null, 2), { mode: 384 });
1487
+ }
1488
+ function isPidAlive(pid) {
1489
+ try {
1490
+ process.kill(pid, 0);
1491
+ return true;
1492
+ } catch {
1493
+ return false;
1494
+ }
1495
+ }
1496
+ async function waitForExit(pid, timeoutMs) {
1497
+ const deadline = Date.now() + timeoutMs;
1498
+ while (isPidAlive(pid)) {
1499
+ if (Date.now() >= deadline) return false;
1500
+ await sleep(50);
1501
+ }
1502
+ return true;
1503
+ }
1504
+ function signal(pid, sig) {
1505
+ try {
1506
+ process.kill(pid, sig);
1507
+ } catch {
1508
+ }
1509
+ }
1510
+ function canBind(host, port) {
1511
+ return new Promise((resolve) => {
1512
+ const server = net.createServer();
1513
+ server.once("error", () => resolve(false));
1514
+ server.listen({ port, host, exclusive: true }, () => server.close(() => resolve(true)));
1515
+ });
1516
+ }
1517
+ async function portPairFree(host, port) {
1518
+ return port + PG_PORT_OFFSET <= 65535 && await canBind(host, port) && await canBind("127.0.0.1", port + PG_PORT_OFFSET);
1519
+ }
1520
+ async function choosePort(host, preferred, explicit) {
1521
+ if (await portPairFree(host, preferred)) return preferred;
1522
+ const hint = 'set a different "memory.embedded-postgres.port" in ~/.one/config.json';
1523
+ if (explicit) {
1524
+ throw new Error(
1525
+ `Port ${preferred} (or ${preferred + PG_PORT_OFFSET}, its internal Postgres port) on ${host} is already in use by another program, so the embedded Postgres can't start there. Free it, or ${hint}.`
1526
+ );
1527
+ }
1528
+ for (let port = preferred + 1; port <= preferred + PORT_SEARCH_SPAN; port++) {
1529
+ if (await portPairFree(host, port)) return port;
1530
+ }
1531
+ throw new Error(
1532
+ `Ports ${preferred}-${preferred + PORT_SEARCH_SPAN} on ${host} are all already in use, so the embedded Postgres can't start. Free one, or ${hint}.`
1533
+ );
1534
+ }
1535
+ function readRange(file, start, length) {
1536
+ const fd = fs.openSync(file, "r");
1537
+ try {
1538
+ const buf = Buffer.alloc(length);
1539
+ const n = fs.readSync(fd, buf, 0, length, start);
1540
+ return buf.subarray(0, n);
1541
+ } finally {
1542
+ fs.closeSync(fd);
1543
+ }
1544
+ }
1545
+ function fileSize(file) {
1546
+ try {
1547
+ return fs.statSync(file).size;
1548
+ } catch {
1549
+ return 0;
1550
+ }
1551
+ }
1552
+ function trimLog(logPath, maxBytes = LOG_MAX_BYTES, keepBytes = LOG_KEEP_BYTES) {
1553
+ const size = fileSize(logPath);
1554
+ if (size <= maxBytes) return;
1555
+ const tail = readRange(logPath, size - keepBytes, keepBytes);
1556
+ const nl = tail.indexOf(10);
1557
+ const kept = nl === -1 ? tail : tail.subarray(nl + 1);
1558
+ const notice = `[one] pgserve.log passed ${maxBytes} bytes; kept the last ${kept.length} (${(/* @__PURE__ */ new Date()).toISOString()})
1559
+ `;
1560
+ fs.writeFileSync(logPath, Buffer.concat([Buffer.from(notice), kept]));
1561
+ }
1562
+ function logSince(logPath, offset, maxBytes = 2e3) {
1563
+ const size = fileSize(logPath);
1564
+ const start = Math.max(offset, size - maxBytes);
1565
+ if (size <= start) return "";
1566
+ return readRange(logPath, start, size - start).toString("utf8").replace(/\x1b\[[0-9;]*m/g, "").trim();
1567
+ }
1568
+ function lockIsStale(lockPath, ttlMs) {
1569
+ try {
1570
+ if (Date.now() - fs.statSync(lockPath).mtimeMs > ttlMs) return true;
1571
+ const { pid } = JSON.parse(fs.readFileSync(lockPath, "utf8"));
1572
+ return typeof pid === "number" && !isPidAlive(pid);
1573
+ } catch {
1574
+ return false;
1575
+ }
1576
+ }
1577
+ async function withStartupLock(dataDir, waitMs, fn) {
1578
+ const lockPath = path.join(dataDir, ".pgserve.lock");
1579
+ const deadline = Date.now() + waitMs;
1580
+ for (; ; ) {
1581
+ try {
1582
+ fs.writeFileSync(lockPath, JSON.stringify({ pid: process.pid, startedAt: Date.now() }), { flag: "wx" });
1583
+ break;
1584
+ } catch (err) {
1585
+ if (err.code !== "EEXIST") throw err;
1586
+ }
1587
+ if (lockIsStale(lockPath, waitMs)) {
1588
+ fs.rmSync(lockPath, { force: true });
1589
+ continue;
1590
+ }
1591
+ if (Date.now() >= deadline) {
1592
+ throw new Error(`Timed out waiting for another \`one\` process to start the embedded Postgres (lock: ${lockPath}).`);
1593
+ }
1594
+ await sleep(100);
1595
+ }
1596
+ try {
1597
+ return await fn();
1598
+ } finally {
1599
+ fs.rmSync(lockPath, { force: true });
1600
+ }
1601
+ }
1602
+ function readPostmasterPid(clusterDir) {
1603
+ try {
1604
+ const lines = fs.readFileSync(path.join(clusterDir, "postmaster.pid"), "utf8").split("\n");
1605
+ const pid = Number.parseInt(lines[0] ?? "", 10);
1606
+ const port = Number.parseInt(lines[3] ?? "", 10);
1607
+ return pid > 0 && port > 0 ? { pid, port } : null;
1608
+ } catch {
1609
+ return null;
1610
+ }
1611
+ }
1612
+ function pgserveOwner(postmasterPid, deps) {
1613
+ const ppid = deps.processInfo(postmasterPid)?.ppid;
1614
+ if (!ppid || ppid <= 1) return null;
1615
+ const command = deps.processInfo(ppid)?.command ?? "";
1616
+ return /pgserve[\\/]bin[\\/]postgres-server\.js/.test(command) ? ppid : null;
1617
+ }
1618
+ async function stopStaleCluster(clusterDir, deps, timeoutMs) {
1619
+ const holder = readPostmasterPid(clusterDir);
1620
+ if (!holder || !isPidAlive(holder.pid)) return;
1621
+ if (await deps.probe(holder.port, "postmaster") !== "ours") return;
1622
+ const owner = pgserveOwner(holder.pid, deps);
1623
+ if (owner !== null) {
1624
+ signal(owner, "SIGTERM");
1625
+ if (!await waitForExit(owner, timeoutMs)) signal(owner, "SIGKILL");
1626
+ }
1627
+ if (!isPidAlive(holder.pid)) return;
1628
+ signal(holder.pid, "SIGINT");
1629
+ if (!await waitForExit(holder.pid, timeoutMs)) {
1630
+ throw new Error(
1631
+ `The embedded Postgres (PID ${holder.pid}) is holding ${clusterDir} and did not stop. Stop it (kill ${holder.pid}) and retry.`
1632
+ );
1633
+ }
1634
+ }
1635
+ async function findHealthyDaemon(dataDir, deps) {
1636
+ const rec = readPidFile(dataDir);
1637
+ if (!rec || !isPidAlive(rec.pid)) return null;
1638
+ return await deps.probe(rec.port, "router") === "ours" ? rec.port : null;
1639
+ }
1640
+ function pgserveArgs(cfg, clusterDir, port) {
1641
+ const args = [
1642
+ "--data",
1643
+ clusterDir,
1644
+ "--port",
1645
+ String(port),
1646
+ "--host",
1647
+ cfg.host,
1648
+ "--log",
1649
+ cfg.logLevel,
1650
+ "--no-stats",
1651
+ // Single process. In cluster mode a worker that can't bind the port is
1652
+ // re-forked immediately, forever, each crash logging a full stack trace.
1653
+ "--no-cluster"
1654
+ ];
1655
+ if (cfg.pgvector) args.push("--pgvector");
1656
+ return args;
1657
+ }
1658
+ async function waitUntilServing(child, cfg, port, deps, log) {
1659
+ const deadline = Date.now() + cfg.startupTimeoutMs;
1660
+ const details = () => {
1661
+ const tail = logSince(log.path, log.offset);
1662
+ return `
1663
+ Log: ${log.path}${tail ? `
1664
+ ${tail}` : ""}`;
1665
+ };
1666
+ for (; ; ) {
1667
+ const exit = child.exitStatus();
1668
+ if (exit) throw new Error(`pgserve exited (${exit}) before it was ready.${details()}`);
1669
+ if (await deps.probe(port, "router") === "ours") return;
1670
+ if (Date.now() >= deadline) {
1671
+ throw new Error(
1672
+ `pgserve did not start serving on ${cfg.host}:${port} within ${Math.round(cfg.startupTimeoutMs / 1e3)}s.${details()}`
1673
+ );
1674
+ }
1675
+ await sleep(250);
1676
+ }
1677
+ }
1678
+ async function ensureRunning(cfg, deps) {
1679
+ const reused = await findHealthyDaemon(cfg.dataDir, deps);
1680
+ if (reused !== null) return reused;
1681
+ fs.mkdirSync(cfg.dataDir, { recursive: true });
1682
+ const stopTimeoutMs = deps.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS;
1683
+ return withStartupLock(cfg.dataDir, cfg.startupTimeoutMs + 3 * stopTimeoutMs, async () => {
1684
+ const raced = await findHealthyDaemon(cfg.dataDir, deps);
1685
+ if (raced !== null) return raced;
1686
+ const clusterDir = path.join(cfg.dataDir, "cluster");
1687
+ fs.mkdirSync(clusterDir, { recursive: true });
1688
+ await stopStaleCluster(clusterDir, deps, stopTimeoutMs);
1689
+ const port = await choosePort(cfg.host, cfg.port, cfg.portExplicit);
1690
+ const logPath = path.join(cfg.dataDir, "pgserve.log");
1691
+ trimLog(logPath);
1692
+ const log = { path: logPath, offset: fileSize(logPath) };
1693
+ const fd = fs.openSync(logPath, "a");
1694
+ let child;
1695
+ try {
1696
+ child = deps.spawnPgserve(pgserveArgs(cfg, clusterDir, port), fd);
1697
+ } finally {
1698
+ fs.closeSync(fd);
1699
+ }
1700
+ await waitUntilServing(child, cfg, port, deps, log);
1701
+ writePidFile(cfg.dataDir, {
1702
+ pid: child.pid,
1703
+ port,
1704
+ dataDir: cfg.dataDir,
1705
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
1706
+ });
1707
+ return port;
1708
+ });
1709
+ }
1710
+ function sameDir(a, b) {
1711
+ const norm = (p) => {
1712
+ let r = path.resolve(p);
1713
+ try {
1714
+ r = fs.realpathSync.native(r);
1715
+ } catch {
1716
+ }
1717
+ return process.platform === "win32" ? r.toLowerCase() : r;
1718
+ };
1719
+ return a !== "" && norm(a) === norm(b);
1720
+ }
1721
+ async function probeDataDirectory(Client, target, clusterDir) {
1722
+ const client = new Client({ ...target, connectionTimeoutMillis: 3e3, query_timeout: 3e3 });
1723
+ client.on("error", () => {
1724
+ });
1725
+ try {
1726
+ await client.connect();
1727
+ } catch (err) {
1728
+ return err.code === "ECONNREFUSED" ? "down" : "other";
1729
+ }
1730
+ try {
1731
+ const { rows } = await client.query("SHOW data_directory");
1732
+ return sameDir(String(rows[0]?.data_directory ?? ""), clusterDir) ? "ours" : "other";
1733
+ } catch {
1734
+ return "other";
1735
+ } finally {
1736
+ await client.end().catch(() => {
1737
+ });
1738
+ }
1739
+ }
1740
+ function resolvePgserveBin() {
1741
+ const pkg = requireFromHere.resolve("pgserve/package.json");
1742
+ return path.resolve(path.dirname(pkg), "bin/pgserve-wrapper.cjs");
1743
+ }
1744
+ function spawnPgserve(args, logFd, cwd) {
1745
+ const child = spawn(process.execPath, [resolvePgserveBin(), ...args], {
1746
+ detached: true,
1747
+ stdio: ["ignore", logFd, logFd],
1748
+ // pgserve resolves the bundled bun binary relative to its own package
1749
+ // location, not cwd, so cwd doesn't matter — but pin it for clarity.
1750
+ cwd
1751
+ });
1752
+ let status = null;
1753
+ child.once("error", (err) => {
1754
+ status = `failed to start: ${err.message}`;
1755
+ });
1756
+ child.once("exit", (code, sig) => {
1757
+ status = sig ? `signal ${sig}` : `code ${code}`;
1758
+ });
1759
+ child.unref();
1760
+ if (typeof child.pid !== "number") {
1761
+ throw new Error("Failed to spawn pgserve \u2014 no PID returned.");
1762
+ }
1763
+ return { pid: child.pid, exitStatus: () => status };
1764
+ }
1765
+ function processInfo(pid) {
1766
+ if (process.platform === "win32") return null;
1767
+ const res = spawnSync("ps", ["-o", "ppid=", "-o", "command=", "-p", String(pid)], { encoding: "utf8" });
1768
+ const match = /^(\d+)\s+(.*)$/.exec((res.stdout ?? "").trim());
1769
+ return match ? { ppid: Number(match[1]), command: match[2] } : null;
1770
+ }
1771
+ function nodeDaemonDeps(cfg, Client, router) {
1772
+ const clusterDir = path.join(cfg.dataDir, "cluster");
1773
+ const direct = { user: "postgres", password: "postgres", database: "postgres" };
1774
+ return {
1775
+ probe: (port, via) => probeDataDirectory(
1776
+ Client,
1777
+ via === "router" ? { host: cfg.host, port, ...router } : { host: "127.0.0.1", port, ...direct },
1778
+ clusterDir
1779
+ ),
1780
+ spawnPgserve: (args, logFd) => spawnPgserve(args, logFd, cfg.dataDir),
1781
+ processInfo
1782
+ };
1783
+ }
1784
+
1785
+ // src/lib/memory/plugins/embedded-postgres/index.ts
1465
1786
  var BASE_CAPABILITIES = {
1466
1787
  vectorSearch: true,
1467
1788
  fullTextSearch: true,
@@ -1477,13 +1798,14 @@ var DEFAULTS = {
1477
1798
  // `path.join(homeDir(), ...)` here would capture the home directory before
1478
1799
  // ONE_HOME could take effect. See lib/home.ts.
1479
1800
  get dataDir() {
1480
- return path.join(homeDir(), ".one", "pg");
1801
+ return path2.join(homeDir(), ".one", "pg");
1481
1802
  },
1482
1803
  database: "one_mem",
1483
1804
  schema: "public",
1484
1805
  pgvector: true,
1485
1806
  host: "127.0.0.1",
1486
1807
  port: 5434,
1808
+ portExplicit: false,
1487
1809
  // pgserve auto-provisions databases; the bundled superuser is `postgres`
1488
1810
  // with no password by default. We don't expose the password to the user
1489
1811
  // since the daemon only listens on 127.0.0.1.
@@ -1501,6 +1823,7 @@ function parseConfig2(raw) {
1501
1823
  pgvector: r.pgvector ?? DEFAULTS.pgvector,
1502
1824
  host: r.host ?? DEFAULTS.host,
1503
1825
  port: r.port ?? DEFAULTS.port,
1826
+ portExplicit: r.port !== void 0,
1504
1827
  user: r.user ?? DEFAULTS.user,
1505
1828
  password: r.password ?? DEFAULTS.password,
1506
1829
  logLevel: r.logLevel ?? DEFAULTS.logLevel,
@@ -1547,104 +1870,6 @@ function wrapClient2(pool) {
1547
1870
  }
1548
1871
  };
1549
1872
  }
1550
- function pidFilePath(dataDir) {
1551
- return path.join(dataDir, ".pgserve.json");
1552
- }
1553
- function readPidFile(dataDir) {
1554
- try {
1555
- const raw = fs.readFileSync(pidFilePath(dataDir), "utf8");
1556
- return JSON.parse(raw);
1557
- } catch {
1558
- return null;
1559
- }
1560
- }
1561
- function writePidFile(dataDir, rec) {
1562
- fs.mkdirSync(dataDir, { recursive: true });
1563
- fs.writeFileSync(pidFilePath(dataDir), JSON.stringify(rec, null, 2), { mode: 384 });
1564
- }
1565
- function isPidAlive(pid) {
1566
- try {
1567
- process.kill(pid, 0);
1568
- return true;
1569
- } catch {
1570
- return false;
1571
- }
1572
- }
1573
- async function isPortListening(host, port, timeoutMs = 1e3) {
1574
- return new Promise((resolve) => {
1575
- const socket = new net.Socket();
1576
- let resolved = false;
1577
- const finish = (ok) => {
1578
- if (resolved) return;
1579
- resolved = true;
1580
- socket.destroy();
1581
- resolve(ok);
1582
- };
1583
- socket.setTimeout(timeoutMs);
1584
- socket.once("connect", () => finish(true));
1585
- socket.once("timeout", () => finish(false));
1586
- socket.once("error", () => finish(false));
1587
- socket.connect(port, host);
1588
- });
1589
- }
1590
- async function waitForPort(host, port, deadlineAt) {
1591
- while (Date.now() < deadlineAt) {
1592
- if (await isPortListening(host, port)) return;
1593
- await new Promise((r) => setTimeout(r, 250));
1594
- }
1595
- throw new Error(
1596
- `pgserve did not start listening on ${host}:${port} within ${Math.round((deadlineAt - Date.now() + 3e4) / 1e3)}s. Check the data dir for the postgres log, or remove ${path.basename(pidFilePath("<dataDir>"))} and retry.`
1597
- );
1598
- }
1599
- function resolvePgserveBin() {
1600
- const pkg = requireFromHere.resolve("pgserve/package.json");
1601
- return path.resolve(path.dirname(pkg), "bin/pgserve-wrapper.cjs");
1602
- }
1603
- async function ensureRunning(cfg) {
1604
- const existing = readPidFile(cfg.dataDir);
1605
- if (existing && isPidAlive(existing.pid)) {
1606
- if (await isPortListening(cfg.host, existing.port)) {
1607
- cfg.port = existing.port;
1608
- return;
1609
- }
1610
- }
1611
- fs.mkdirSync(cfg.dataDir, { recursive: true });
1612
- const clusterDir = path.join(cfg.dataDir, "cluster");
1613
- fs.mkdirSync(clusterDir, { recursive: true });
1614
- const args = [
1615
- "--data",
1616
- clusterDir,
1617
- "--port",
1618
- String(cfg.port),
1619
- "--host",
1620
- cfg.host,
1621
- "--log",
1622
- cfg.logLevel,
1623
- "--no-stats"
1624
- ];
1625
- if (cfg.pgvector) args.push("--pgvector");
1626
- const bin = resolvePgserveBin();
1627
- const out = fs.openSync(path.join(cfg.dataDir, "pgserve.log"), "a");
1628
- const child = spawn(process.execPath, [bin, ...args], {
1629
- detached: true,
1630
- stdio: ["ignore", out, out],
1631
- // pgserve resolves the bundled bun binary relative to its own package
1632
- // location, not cwd, so cwd doesn't matter — but pin it for clarity.
1633
- cwd: cfg.dataDir
1634
- });
1635
- child.unref();
1636
- if (typeof child.pid !== "number") {
1637
- throw new Error("Failed to spawn pgserve \u2014 no PID returned.");
1638
- }
1639
- const deadlineAt = Date.now() + cfg.startupTimeoutMs;
1640
- await waitForPort(cfg.host, cfg.port, deadlineAt);
1641
- writePidFile(cfg.dataDir, {
1642
- pid: child.pid,
1643
- port: cfg.port,
1644
- dataDir: cfg.dataDir,
1645
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
1646
- });
1647
- }
1648
1873
  async function probePgvector(client) {
1649
1874
  try {
1650
1875
  await client.query("CREATE EXTENSION IF NOT EXISTS vector");
@@ -1662,12 +1887,20 @@ var LazyEmbeddedPostgresBackend = class {
1662
1887
  }
1663
1888
  async ensure() {
1664
1889
  if (this.backend) return this.backend;
1665
- await ensureRunning(this.config);
1666
1890
  const pgMod = await import("pg").catch((err) => {
1667
1891
  const msg = err instanceof Error ? err.message : String(err);
1668
1892
  throw new Error(`pg is not installed. Run \`npm i pg\` or pick a different backend. (${msg})`);
1669
1893
  });
1670
- const PoolCtor = pgMod.Pool ?? pgMod.default.Pool;
1894
+ const pgExports = pgMod.Pool ? pgMod : pgMod.default;
1895
+ const PoolCtor = pgExports.Pool;
1896
+ this.config.port = await ensureRunning(
1897
+ this.config,
1898
+ nodeDaemonDeps(this.config, pgExports.Client, {
1899
+ user: this.config.user,
1900
+ password: this.config.password,
1901
+ database: this.config.database
1902
+ })
1903
+ );
1671
1904
  const pool = new PoolCtor({
1672
1905
  host: this.config.host,
1673
1906
  port: this.config.port,
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  getBackend,
12
12
  upsertRecord
13
- } from "./chunk-VH46MAE4.js";
13
+ } from "./chunk-IMU2X3ZV.js";
14
14
 
15
15
  // src/commands/mem/migrate.ts
16
16
  import fs4 from "fs";
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  } from "./chunk-QCXFSOTS.js";
36
36
  import {
37
37
  memSqlCommand
38
- } from "./chunk-KAF5SVJS.js";
38
+ } from "./chunk-GKAIRI4Y.js";
39
39
  import {
40
40
  collectIdentityKeys,
41
41
  countRecords,
@@ -66,7 +66,7 @@ import {
66
66
  writeDraftProfile,
67
67
  writePageToMemory,
68
68
  writeProfile
69
- } from "./chunk-XWTV7FA3.js";
69
+ } from "./chunk-YTM6HJKA.js";
70
70
  import {
71
71
  getByDotPath
72
72
  } from "./chunk-44CV5IMX.js";
@@ -100,7 +100,7 @@ import {
100
100
  listBackendPlugins,
101
101
  loadBackendFromConfig,
102
102
  updateRecord
103
- } from "./chunk-VH46MAE4.js";
103
+ } from "./chunk-IMU2X3ZV.js";
104
104
  import {
105
105
  DEFAULT_MEMORY_CONFIG,
106
106
  defaultSearchableText,
@@ -7231,7 +7231,7 @@ async function syncModel(api, profile, options) {
7231
7231
  updateModelState(platform, model, { status: "failed", pagesProcessed, lastCursor }),
7232
7232
  (async () => {
7233
7233
  try {
7234
- const { getBackend: getBackend2 } = await import("./runtime-65IPTPVD.js");
7234
+ const { getBackend: getBackend2 } = await import("./runtime-SX36HGBA.js");
7235
7235
  const backend = await getBackend2();
7236
7236
  await Promise.race([
7237
7237
  backend.close(),
@@ -7597,7 +7597,7 @@ async function syncModel(api, profile, options) {
7597
7597
  db.exec(`DROP TABLE IF EXISTS _seen_ids`);
7598
7598
  }
7599
7599
  if (options.toMemory !== false) {
7600
- const backend = await (await import("./runtime-65IPTPVD.js")).getBackend();
7600
+ const backend = await (await import("./runtime-SX36HGBA.js")).getBackend();
7601
7601
  const type = `${platform}/${model}`;
7602
7602
  const existing = await backend.listKeysByType(type);
7603
7603
  const sourcePrefix = `${type}:`;
@@ -7698,7 +7698,7 @@ async function syncModel(api, profile, options) {
7698
7698
  let statusCounts;
7699
7699
  if (options.toMemory !== false) {
7700
7700
  try {
7701
- const backend = await (await import("./runtime-65IPTPVD.js")).getBackend();
7701
+ const backend = await (await import("./runtime-SX36HGBA.js")).getBackend();
7702
7702
  const typeName = `${platform}/${model}`;
7703
7703
  const [active, archived] = await Promise.all([
7704
7704
  backend.count(typeName, { status: "active" }),
@@ -9420,7 +9420,7 @@ ${result.total} results`);
9420
9420
  }
9421
9421
  }
9422
9422
  async function syncSqlCommand(platformModel, sql) {
9423
- const { syncSqlCommand: runSyncSql } = await import("./sql-QIVDWTL3.js");
9423
+ const { syncSqlCommand: runSyncSql } = await import("./sql-SYCWUPNP.js");
9424
9424
  await runSyncSql(platformModel, sql);
9425
9425
  }
9426
9426
  async function syncDeleteCommand(platformModel, options) {
@@ -9498,7 +9498,7 @@ async function syncDeleteCommand(platformModel, options) {
9498
9498
  async function maybeAutoMigrateLegacy(platform, models) {
9499
9499
  const dbSize = getDatabaseSize(platform);
9500
9500
  if (!dbSize || dbSize === "0 B") return;
9501
- const { getBackend: getBackend2 } = await import("./runtime-65IPTPVD.js");
9501
+ const { getBackend: getBackend2 } = await import("./runtime-SX36HGBA.js");
9502
9502
  const backend = await getBackend2();
9503
9503
  let memoryHasData = false;
9504
9504
  for (const model of models) {
@@ -9514,7 +9514,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
9514
9514
  ` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
9515
9515
  `
9516
9516
  );
9517
- const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-IJI3BTWL.js");
9517
+ const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-TACDLGPD.js");
9518
9518
  await memMigrateCommand3({ platform, yes: true });
9519
9519
  return;
9520
9520
  }
@@ -9523,7 +9523,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
9523
9523
  initialValue: true
9524
9524
  });
9525
9525
  if (p7.isCancel(shouldMigrate) || !shouldMigrate) return;
9526
- const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-IJI3BTWL.js");
9526
+ const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-TACDLGPD.js");
9527
9527
  await memMigrateCommand2({ platform, yes: true });
9528
9528
  }
9529
9529
  async function syncSuggestSearchableCommand(platformModel, options = {}) {
@@ -9584,7 +9584,7 @@ async function syncSuggestSearchableCommand(platformModel, options = {}) {
9584
9584
  async function syncListCommand(platform) {
9585
9585
  const profiles = listProfiles(platform);
9586
9586
  const state = await readSyncState();
9587
- const { getBackend: getBackend2 } = await import("./runtime-65IPTPVD.js");
9587
+ const { getBackend: getBackend2 } = await import("./runtime-SX36HGBA.js");
9588
9588
  const backend = await getBackend2();
9589
9589
  const syncs = await Promise.all(profiles.map(async (p10) => {
9590
9590
  const modelState = state[p10.platform]?.[p10.model];
@@ -9860,7 +9860,7 @@ function registerSyncSubcommands(sync) {
9860
9860
  await syncSqlCommand(platformModel, sql);
9861
9861
  });
9862
9862
  sync.command("schema <platform/model>").description("Inspect the JSON structure of synced records (field paths, types, examples) \u2014 useful before writing `sync sql` queries").action(async (platformModel) => {
9863
- const { syncSchemaCommand } = await import("./schema-OO4WK5ND.js");
9863
+ const { syncSchemaCommand } = await import("./schema-RJC2WQQ6.js");
9864
9864
  await syncSchemaCommand(platformModel);
9865
9865
  });
9866
9866
  sync.command("delete <platform/model>").description('Delete records from local sync data (e.g. one sync delete notion/pages --id "abc-123")').option("--id <value>", "Delete record by ID").option("--where <conditions>", 'Delete records matching conditions (e.g. "status=archived")').option("--where-sql <predicate>", `Delete using a raw SQL WHERE clause (e.g. "json_extract(data, '$.type') = 'promotion'")`).option("--yes", "Skip confirmation prompt").action(async (platformModel, options) => {
@@ -11627,6 +11627,8 @@ The unified memory store is a local, pluggable database (\`embedded-postgres\` b
11627
11627
  The first \`one mem\` call on a fresh install auto-initializes:
11628
11628
  - Backend: \`embedded-postgres\` (Postgres 18 via pgserve; downloads ~52MB of binaries on first use, ~2s on later boots)
11629
11629
  - Cluster path: \`~/.one/pg/cluster/\`, daemon PID/port at \`~/.one/pg/.pgserve.json\`
11630
+ - Port: \`5434\` by default. If another program already holds it (a database tunnel, another Postgres), the daemon starts on the next free port and records it in \`.pgserve.json\`. A port pinned with \`mem config set embedded-postgres.port <n>\` is never moved \u2014 a conflict there is an error naming the port.
11631
+ - Self-healing: a running daemon is reused only when the Postgres on its port reports this cluster's data directory. A Postgres left holding the cluster by a dead or stuck pgserve is stopped and a fresh daemon started. \`pgserve.log\` is trimmed to its last 1 MB once it passes 10 MB.
11630
11632
  - Embedding provider: \`openai\` if a key is already resolvable AND pgvector is loadable; else \`none\`
11631
11633
 
11632
11634
  If pgvector isn't installed in the bundled Postgres (the default binary distribution doesn't ship it yet), the schema applies cleanly without an \`embedding\` column, all FTS paths work, and \`mem doctor\` emits an \`_upgrade\` block pointing at \`brew install pgvector\` when an OpenAI key is present.
@@ -12277,8 +12279,9 @@ Every \`sync X\` command is also exposed as \`mem sync X\` \u2014 same handlers,
12277
12279
  logs/{platform}.log # cron run logs
12278
12280
  locks/{platform}_{model}/ # cross-process sync locks
12279
12281
  ~/.one/pg/cluster/ # unified memory store \u2014 embedded Postgres data dir
12280
- ~/.one/pg/.pgserve.json # daemon PID/port file (cleared on stop)
12281
- ~/.one/pg/pgserve.log # daemon stdout/stderr
12282
+ ~/.one/pg/.pgserve.json # daemon PID/port file
12283
+ ~/.one/pg/.pgserve.lock # held while a CLI process starts the daemon
12284
+ ~/.one/pg/pgserve.log # daemon stdout/stderr (trimmed to 1 MB past 10 MB)
12282
12285
  ~/.one/config.json # apiKey + openaiApiKey + memory config block
12283
12286
  ~/.one/sync/
12284
12287
  schedules.json # global schedule registry
@@ -3,10 +3,10 @@ import {
3
3
  dotPathToJsonbExpr,
4
4
  memMigrateCommand,
5
5
  reviveStringifiedJson
6
- } from "./chunk-XWTV7FA3.js";
6
+ } from "./chunk-YTM6HJKA.js";
7
7
  import "./chunk-44CV5IMX.js";
8
8
  import "./chunk-OLQ55K6B.js";
9
- import "./chunk-VH46MAE4.js";
9
+ import "./chunk-IMU2X3ZV.js";
10
10
  import "./chunk-YMUY55U2.js";
11
11
  import "./chunk-6UB623BG.js";
12
12
  export {
@@ -5,7 +5,7 @@ import {
5
5
  resetBackendSingleton,
6
6
  updateRecord,
7
7
  upsertRecord
8
- } from "./chunk-VH46MAE4.js";
8
+ } from "./chunk-IMU2X3ZV.js";
9
9
  import "./chunk-YMUY55U2.js";
10
10
  import "./chunk-6UB623BG.js";
11
11
  export {
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-OLQ55K6B.js";
7
7
  import {
8
8
  getBackend
9
- } from "./chunk-VH46MAE4.js";
9
+ } from "./chunk-IMU2X3ZV.js";
10
10
  import "./chunk-YMUY55U2.js";
11
11
  import "./chunk-6UB623BG.js";
12
12
 
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  memSqlCommand,
3
3
  syncSqlCommand
4
- } from "./chunk-KAF5SVJS.js";
4
+ } from "./chunk-GKAIRI4Y.js";
5
5
  import "./chunk-OLQ55K6B.js";
6
- import "./chunk-VH46MAE4.js";
6
+ import "./chunk-IMU2X3ZV.js";
7
7
  import "./chunk-YMUY55U2.js";
8
8
  import "./chunk-6UB623BG.js";
9
9
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.57.0",
3
+ "version": "1.57.1",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [
@@ -192,7 +192,7 @@ Knowledge and search responses are cached locally (`~/.one/cache/`). Subsequent
192
192
 
193
193
  One ships a local memory store (a real Postgres process bootstrapped on demand via the bundled `embedded-postgres` plugin, with a `postgres` plugin available for remote/self-hosted Postgres) that backs both user-authored notes and synced platform data. `one mem <cmd>` is the primary surface; `one sync` is a namespaced alias (`one mem sync ...`) that writes synced rows into the same store.
194
194
 
195
- **Zero-config.** The first `one mem` call on a new machine auto-initializes — no separate `mem init` step required. The `embedded-postgres` plugin downloads its Postgres binaries on first run (~52MB) and writes a daemon PID/port file at `~/.one/pg/.pgserve.json` so subsequent CLI invocations reuse the running cluster. If an OpenAI key is already resolvable (env, `.onerc`, or `config.openaiApiKey`), embeddings enable automatically and search becomes hybrid FTS + semantic. Otherwise you get FTS-only with a structured `_upgrade` hint on every response telling the user how to upgrade.
195
+ **Zero-config.** The first `one mem` call on a new machine auto-initializes — no separate `mem init` step required. The `embedded-postgres` plugin downloads its Postgres binaries on first run (~52MB) and writes a daemon PID/port file at `~/.one/pg/.pgserve.json` so subsequent CLI invocations reuse the running cluster. The daemon listens on 5434, or the next free port if another program holds it; pin one with `one --agent mem config set embedded-postgres.port <n>` (a conflict on a pinned port is an error, not a silent move). If an OpenAI key is already resolvable (env, `.onerc`, or `config.openaiApiKey`), embeddings enable automatically and search becomes hybrid FTS + semantic. Otherwise you get FTS-only with a structured `_upgrade` hint on every response telling the user how to upgrade.
196
196
 
197
197
  **Listing synced rows.** `mem list <type>` takes a positional namespaced type — there is no `--platform` flag. Synced rows live under `<platform>/<model>` types:
198
198