Releases: withoneai/cli
v1.43.4
v1.43.3
Fix: one --agent mem search exits in ~300ms instead of hanging for ~10s after the JSON response prints.
Root cause: node-pg Pool's default idleTimeoutMillis: 10000 kept the still-idle pooled connection alive after the query completed, so the event loop sat for the full 10 seconds before the process could exit. The mem_hybrid_search SQL itself was 37ms; the OpenAI embed call was 200ms; the actual work always finished in ~700ms — the rest was just the idle-timeout drain.
Fix: closeBackendIfCached() helper in runtime.ts, called from the program's postAction hook. Awaits the cached backend promise (if any) and calls backend.close() so every command that touched memory drains its pool before exit. No-op when no mem/sync command instantiated a backend; errors are swallowed (we're shutting down). Idle-timeout stays at the node-pg default during a command so sequential queries reuse one pool connection.
Verified against ~/CEO with 14,543 records:
- Before: ~10.4s per
mem searchinvocation - After: 300–420ms warm, ~2s cold
98/98 tests pass.
v1.43.2
Folds the standalone @withone/mem package into the One CLI as a pluggable memory subsystem, makes it the primary target for sync, and introduces a real-Postgres-by-default story for new users.
Default backend: embedded-postgres
New installs get a real local Postgres process via pgserve (Postgres 18, cluster bootstrapped at ~/.one/pg/cluster/). PGlite repeatedly corrupted during real syncs against ~250M of Gmail data, so it's been retired from the product surface — unregistered from the plugin registry, removed from mem init, mem config, and the help/doctor diagnostics. The plugin source remains in tree as a dev-only unit-test fixture; not bundled, not selectable.
- First boot downloads ~52MB of Postgres binaries; later boots are ~2s.
- The daemon survives across CLI invocations via a
.pgserve.jsonPID/port file. Multiple One CLI processes share one cluster. - pgserve auto-provisions databases on first connect.
- Long-term convergence: same cluster will host
one-run's tables once it adopts pgserve too.
Runtime pgvector detection
The plugin probes CREATE EXTENSION IF NOT EXISTS vector once at first connect. Available → vectorSearch: true, schema applies the vector block (extension, embedding columns, HNSW index, hybrid_search function), and the vector-aware mem_upsert_by_keys overrides the no-vector variant. Not available → vectorSearch: false, FTS-only, with a structured _upgrade hint on mem doctor, mem search, and mem status pointing at brew install pgvector. Reversible — install pgvector later and the next ensureSchema picks it up via IF NOT EXISTS ALTERs.
What's new in the unification
- Zero-config memory — auto-initializes the configured backend on first call. No
mem initprerequisite. - Top-level OpenAI key — stored as
config.openaiApiKey, same precedence chain asONE_SECRET. - Upgrade hints —
mem status/mem search/mem doctorcarry a structured_upgradeblock when semantic search is available but off. Three variants: no OpenAI key, key but provider=none, and now: backend without pgvector. - Agent-declared
memory.searchable— profiles carry dot-paths that drive embedded + FTS text. Supports numeric indexes and[]wildcards. - Memory-primary sync — every
sync runwrites intomem_records. SQLite dual-write retained only for enrich profiles. one mem syncalias — full alias ofone sync, single command tree.- Sync state moves to
mem_sync_statetable — legacy.one/sync/state/*.jsonauto-migrated on first access. sync query --wheresupports dotted paths (values.job_title[0].value like %Engineering%).- Replace-semantics upsert — synced rows replace
data,tags,searchable_text,content_hashwholesale so fields removed upstream actually disappear from memory. - Deterministic merge —
ORDER BY r.updated_at DESC NULLS LAST, r.id ASC LIMIT 1so multi-row key overlap doesn't pick a random winner. - Schema race fix —
ensureSchemaruns insideclient.transaction(...)with apg_advisory_xact_lock, pinned to a single connection so concurrent CLI processes can't race onCREATE EXTENSION/CREATE OR REPLACE FUNCTION.
Migration
one mem migrate reads legacy .one/sync/data/*.db files into the unified store. Self-heals stale installed-profile idField against the in-tree built-in (with --no-heal opt-out and full transparency in agent JSON: originalIdField, healedTo, builtinNewerThanInstalled, plus a tailored note). Read-only on the user's SQLite — no journal_mode rewrite, no -wal/-shm siblings, no destructive corruption-recovery rename. --cleanup --dry-run previews the file list before touching anything.
Verified end-to-end against 14,543 rows of real production data
| Total | Inserted | MergedByIdentity | Skipped |
|---|---|---|---|
| 14,543 | 24 | 3,474 | 0 |
Idempotency: re-running migrate produces 0 new inserts; all updates. Concurrency: 3 parallel mem doctor runs all green. mem migrate dry-run does not create -wal/-shm siblings.
Deprecations (non-breaking)
--to-memoryflag onsync run— silent no-op (memory always written). Use--no-memoryto opt out.sync sql— errors with a pointer tomem search/mem list.- PGlite — retired from the product surface.
Schema version 2.1.0.
v1.42.0
New one relay platforms command — discover which platforms support webhook relay and how many event types each exposes, without having to guess-and-check with relay event-types <platform>.
$ one relay platforms
Platform Event types
─────────────── ───────────
airtable 3
attio 27
stripe 224
...
$ one --agent relay platforms
{"platforms":[{"platform":"airtable","eventTypeCount":3}, ...]}Also fixes a bug where sync always hit prod because OneApi was constructed without apiBase. #124
v1.41.0
Late-bound connection refs in flow action steps. Re-auth no longer breaks flows.
```json
"connection": { "platform": "gmail" } // single account
"connection": { "platform": "gmail", "tag": "work@example.com" } // multi-account
```
Resolution runs at flow-execute time. The connection list is fetched once per flow run and cached on the flow context — a many-step flow does ONE `listConnections` round-trip regardless of step count. Selectors work inside the ref's `tag` field for multi-tenant flows.
Backwards compatible: literal `connectionKey` still works.
Companion to v1.40.0 (sync). #121
v1.40.0
Late-bound connection refs in sync profiles. Re-auth no longer breaks profiles.
```json
"connection": { "platform": "gmail" } // single account
"connection": { "platform": "gmail", "tag": "work@example.com" } // multi-account
```
Resolution runs at sync test/run time. After `one add gmail` (re-auth), the next sync picks up the fresh key automatically — no manual edits across profiles.
Backwards compatible: literal `connectionKey` still works. Built-in profiles migrated.
Closes #114. Partial fix for #113 (closed). Flow engine support to follow.
v1.39.1
Hard-block custom actions in sync test (and sync init auto-validation).
Follow-up to #118: the previous fix added the guard in sync run and enrich, but sync test was missing it — so a profile pointing at a custom action would pass test and only fail later at run time. The check now lives in testSyncProfile so every entry point rejects custom actions consistently.
v1.39.0
fix: hard-block custom actions in sync
Sync refuses profiles referencing custom/composer actions (tag custom). Both the list action and any enrich action must be passthrough — custom actions run on a small shared fleet that collapses under sync-scale load and often expect filters in the request body that sync doesn't send.
Changes
discoverModelsfilters customs at resolution and drops models with no passthrough variant —sync models <platform>only returns syncable modelssync runaborts with a clear error pointing atone actions searchand the flow alternative when the list or enrich action is taggedcustom- Docs updated: guide, skill, README
Why
The symptoms were empty results (withoneai/knowledge#65) and a feature request for body-param support (#116). Neither is the right fix — sync should never use custom actions. Custom actions are for one-off agent use only.
Closes #116, closes withoneai/knowledge#65. Shipped in #118.
v1.38.0
What's new
- Root-array response support for sync. Profiles can now set
resultsPathto""/"$"/"."when the API returns a bare array at the root (e.g. Hacker News/v0/topstories.json→[9129911, 9129199, ...]). - Primitive-array auto-wrapping. Arrays of numbers/strings/bools are wrapped as
{ [idField]: String(value) }so they flow through the existing schema-inference and upsert pipeline with no downstream special-casing. - Built-in profile:
hacker-news/topStories—one sync init hacker-news topStoriesnow works out of the box. - Clearer extraction errors. When
resultsPathdoesn't resolve to an array, the error now names the profile (platform/model), the path, and the actual top-level type of the response.
Profile validation no longer rejects an empty resultsPath (only undefined). Existing object-rooted profiles (Attio, Gmail, Fathom, Calendar, Notion, Stripe) are unchanged.
PR: #117
v1.37.3
Fix: eliminate cross-platform sync state race. Concurrent syncs (cron firing all platforms at once) were racing on the shared .one/sync/sync_state.json — failed renames wedged models in status=syncing, and the read-modify-write could silently lose an update. State is now stored per-platform/per-model at .one/sync/state/<platform>/<model>.json so each writer owns its own file. Legacy file is migrated on first read.