@withone/cli 1.48.0 → 1.50.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.
- package/README.md +43 -1
- package/dist/{chunk-H2PP5XEQ.js → chunk-4WWK3GO5.js} +2 -2
- package/dist/{chunk-BHAEEALR.js → chunk-7RV7T5PX.js} +179 -22
- package/dist/{chunk-BV2NYIA7.js → chunk-C7DWZ7B5.js} +59 -10
- package/dist/{chunk-M326Y5X6.js → chunk-CLJFSFFM.js} +1 -1
- package/dist/{chunk-2TWFL3CS.js → chunk-D6W756DN.js} +3 -2
- package/dist/{chunk-QE6Z676D.js → chunk-GXOIR3GF.js} +2 -2
- package/dist/{embedding-K2CFCLXI.js → embedding-2YB6CGBA.js} +1 -1
- package/dist/{flow-runner-IBB42ED2.js → flow-runner-YDKAYGZW.js} +1 -1
- package/dist/index.js +246 -29
- package/dist/{migrate-CO4LQVY6.js → migrate-TRUZVAT5.js} +4 -4
- package/dist/{runtime-V4PXJJUV.js → runtime-2PRVL2NO.js} +4 -2
- package/dist/{schema-UC4LBV5V.js → schema-LCRWSFD5.js} +3 -3
- package/dist/sql-HG7R2JML.js +12 -0
- package/package.json +1 -1
- package/skills/one/SKILL.md +24 -1
- package/dist/sql-CBZQHP4R.js +0 -12
package/README.md
CHANGED
|
@@ -179,7 +179,7 @@ Opens your browser, you authorize, done. The CLI polls until the connection is l
|
|
|
179
179
|
|
|
180
180
|
### `one list`
|
|
181
181
|
|
|
182
|
-
List your active connections with their status and
|
|
182
|
+
List your active connections with their status, connection keys, and what your access config lets you run on each.
|
|
183
183
|
|
|
184
184
|
```bash
|
|
185
185
|
one list
|
|
@@ -193,6 +193,37 @@ one list
|
|
|
193
193
|
|
|
194
194
|
You need the connection key (rightmost column) when executing actions.
|
|
195
195
|
|
|
196
|
+
**Access reporting.** Every connection carries an `access` field describing what the current [access control](#one-config) config permits — so an agent knows its reach up front instead of discovering it as a failure mid-workflow. Three policies:
|
|
197
|
+
|
|
198
|
+
| Policy | Means | Shown when |
|
|
199
|
+
|--------|-------|-----------|
|
|
200
|
+
| `{"policy": "full"}` | Every action on the connection | Default (admin, no action allowlist) |
|
|
201
|
+
| `{"policy": "methods", "methods": ["GET"]}` | Only actions with those HTTP methods | Permission level is `read` or `write` |
|
|
202
|
+
| `{"policy": "actions", "actions": [{"actionId": "...", "title": "...", "method": "..."}]}` | Only these specific actions | An action allowlist is configured |
|
|
203
|
+
|
|
204
|
+
An action allowlist wins over the permission level (and is then method-filtered by it). When the policy is `actions`, those actions are exactly what may run — no `actions search` needed.
|
|
205
|
+
|
|
206
|
+
```jsonc
|
|
207
|
+
// one --agent list
|
|
208
|
+
{
|
|
209
|
+
"total": 2,
|
|
210
|
+
"showing": 2,
|
|
211
|
+
"connections": [
|
|
212
|
+
{
|
|
213
|
+
"platform": "gmail",
|
|
214
|
+
"state": "operational",
|
|
215
|
+
"key": "live::gmail::default::abc123",
|
|
216
|
+
"access": { "policy": "methods", "methods": ["GET"] }
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
"accessHint": "Permission level \"read\": only GET actions will execute."
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
`knowledgeOnly: true` appears when knowledge-only mode is on (execution disabled), and `unresolvedActionIds` lists any allowlisted action ids that could not be looked up. In human output, an `Access` column and a summary note appear only when access is actually scoped.
|
|
224
|
+
|
|
225
|
+
This mirrors the `access` field on the One MCP server's `list_one_integrations` tool, so both surfaces report access the same way.
|
|
226
|
+
|
|
196
227
|
### `one connection delete <connection-key>`
|
|
197
228
|
|
|
198
229
|
Remove a connection by its key.
|
|
@@ -329,9 +360,18 @@ One ships a local memory store (a real Postgres process bootstrapped on demand v
|
|
|
329
360
|
```bash
|
|
330
361
|
# User memories — works immediately on a new install
|
|
331
362
|
one mem add note '{"content":"Design review is Thursday"}' --tags work --weight 7
|
|
363
|
+
one mem update <id> '{"status":"done"}' # merges into data; refreshes searchable_text
|
|
332
364
|
one mem search "design review" # hybrid FTS + semantic (if key set)
|
|
333
365
|
one mem list note --limit 20
|
|
334
366
|
|
|
367
|
+
# Identity keys are a first-class column (unique across ACTIVE records; archiving
|
|
368
|
+
# frees them). Manage them after creation with `mem key` — NOT via `mem update`.
|
|
369
|
+
one mem key <id> --add email:x@y.com # also --remove / --set <csv>
|
|
370
|
+
|
|
371
|
+
# Backfill searchable_text for rows that landed NULL or with UUID-noise-heavy text
|
|
372
|
+
# (drops ids/timestamps, leads with name/title/email). No embedding provider needed.
|
|
373
|
+
one mem reindex --searchable --type attio/attioPeople
|
|
374
|
+
|
|
335
375
|
# Listing synced platform rows — type is positional and namespaced as <platform>/<model>;
|
|
336
376
|
# there is NO --platform flag and NO platform column in the schema.
|
|
337
377
|
one mem list "gmail/threads"
|
|
@@ -567,6 +607,8 @@ one config
|
|
|
567
607
|
|
|
568
608
|
Settings propagate automatically to all installed agent configs.
|
|
569
609
|
|
|
610
|
+
Run [`one list`](#one-list) to see the effect: each connection reports an `access` field describing exactly what these settings let you run on it.
|
|
611
|
+
|
|
570
612
|
#### `one config skills status` / `one config skills sync`
|
|
571
613
|
|
|
572
614
|
`one init` copies the packaged skill files (`SKILL.md`, `references/`) into `~/.agents/skills/one/` and symlinks per-agent paths to that canonical directory. When the CLI self-updates, the skill files in the canonical dir would normally stay frozen at the version that was installed. To prevent stale docs, every CLI command checks a `.one-cli-version` marker in the canonical dir and silently refreshes the skill files if they don't match the running CLI version. No user action required.
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
isAgentMode,
|
|
4
4
|
json,
|
|
5
5
|
requireMemoryInit
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CLJFSFFM.js";
|
|
7
7
|
import {
|
|
8
8
|
getBackend
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7RV7T5PX.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/mem/sql.ts
|
|
12
12
|
async function memSqlCommand(sql) {
|
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
getMemoryConfig,
|
|
6
6
|
getMemoryConfigOrDefault,
|
|
7
7
|
updateMemoryConfig
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-C7DWZ7B5.js";
|
|
9
9
|
import {
|
|
10
10
|
getOpenAiApiKey
|
|
11
11
|
} from "./chunk-SO323PZP.js";
|
|
12
12
|
|
|
13
13
|
// src/lib/memory/schema.ts
|
|
14
|
-
var SCHEMA_VERSION = "2.
|
|
14
|
+
var SCHEMA_VERSION = "2.2.0";
|
|
15
15
|
var EXTENSIONS_SQL = ``;
|
|
16
16
|
var VECTOR_EXTENSION_SQL = `
|
|
17
17
|
CREATE EXTENSION IF NOT EXISTS vector;
|
|
@@ -105,19 +105,31 @@ BEGIN
|
|
|
105
105
|
END $$;
|
|
106
106
|
`;
|
|
107
107
|
var FUNCTIONS_SQL = `
|
|
108
|
-
-- Enforce
|
|
108
|
+
-- Enforce uniqueness of the "keys" array across ACTIVE records only.
|
|
109
|
+
--
|
|
110
|
+
-- Scoping to active is deliberate: an archived record must not squat on a
|
|
111
|
+
-- key forever. If it did, re-adding the same identity (e.g. a person who
|
|
112
|
+
-- was archived and re-surfaced) would hard-fail with 23505 and the key
|
|
113
|
+
-- could never be reclaimed. So:
|
|
114
|
+
-- - Only ACTIVE incoming rows are checked (an archived NEW row can hold
|
|
115
|
+
-- any keys, including ones a live record also holds \u2014 provenance).
|
|
116
|
+
-- - Conflicts are only raised against other ACTIVE records.
|
|
117
|
+
-- Array-overlap uniqueness can't be expressed as a partial UNIQUE index
|
|
118
|
+
-- (btree can't index "arrays overlap"), so the invariant lives here in a
|
|
119
|
+
-- trigger. find-by-source, key lookups, and mem_upsert_by_keys all
|
|
120
|
+
-- prefer active rows to match this scoping (see below).
|
|
109
121
|
CREATE OR REPLACE FUNCTION mem_enforce_key_uniqueness()
|
|
110
122
|
RETURNS TRIGGER LANGUAGE plpgsql AS $$
|
|
111
123
|
DECLARE
|
|
112
124
|
conflicting_id UUID;
|
|
113
125
|
BEGIN
|
|
114
|
-
IF NEW.keys IS NULL THEN RETURN NEW; END IF;
|
|
126
|
+
IF NEW.keys IS NULL OR NEW.status <> 'active' THEN RETURN NEW; END IF;
|
|
115
127
|
SELECT id INTO conflicting_id
|
|
116
128
|
FROM mem_records
|
|
117
|
-
WHERE keys && NEW.keys AND id != NEW.id
|
|
129
|
+
WHERE keys && NEW.keys AND id != NEW.id AND status = 'active'
|
|
118
130
|
LIMIT 1;
|
|
119
131
|
IF conflicting_id IS NOT NULL THEN
|
|
120
|
-
RAISE EXCEPTION 'Key conflict: one or more keys in % already exist on record %',
|
|
132
|
+
RAISE EXCEPTION 'Key conflict: one or more keys in % already exist on active record %',
|
|
121
133
|
NEW.keys, conflicting_id USING ERRCODE = 'unique_violation';
|
|
122
134
|
END IF;
|
|
123
135
|
RETURN NEW;
|
|
@@ -224,14 +236,15 @@ DECLARE
|
|
|
224
236
|
BEGIN
|
|
225
237
|
-- Deterministic pick when more than one row's keys[] overlap p_keys
|
|
226
238
|
-- (e.g. the incoming row identity-merges with an old Attio-id row AND
|
|
227
|
-
-- a newer email-keyed row from a separate sync).
|
|
228
|
-
--
|
|
229
|
-
--
|
|
230
|
-
--
|
|
239
|
+
-- a newer email-keyed row from a separate sync). Active rows win over
|
|
240
|
+
-- archived (key uniqueness is scoped to active, so an archived dupe may
|
|
241
|
+
-- coexist \u2014 never merge into it when a live owner exists); then newest-
|
|
242
|
+
-- updated; ties broken by id. Without ORDER BY, PG returns whichever
|
|
243
|
+
-- row the planner surfaces first, breaking the keys-are-unique invariant.
|
|
231
244
|
SELECT r.id INTO existing_id
|
|
232
245
|
FROM mem_records r
|
|
233
246
|
WHERE r.keys && p_keys
|
|
234
|
-
ORDER BY r.updated_at DESC NULLS LAST, r.id ASC
|
|
247
|
+
ORDER BY (r.status = 'active') DESC, r.updated_at DESC NULLS LAST, r.id ASC
|
|
235
248
|
LIMIT 1;
|
|
236
249
|
|
|
237
250
|
IF existing_id IS NOT NULL THEN
|
|
@@ -308,12 +321,12 @@ DECLARE
|
|
|
308
321
|
BEGIN
|
|
309
322
|
v_embedding := CASE WHEN p_embedding IS NOT NULL THEN p_embedding::vector ELSE NULL END;
|
|
310
323
|
|
|
311
|
-
-- See no-vector variant for ORDER BY rationale (
|
|
312
|
-
-- when multiple rows' keys overlap p_keys).
|
|
324
|
+
-- See no-vector variant for ORDER BY rationale (active-preferred,
|
|
325
|
+
-- deterministic pick when multiple rows' keys overlap p_keys).
|
|
313
326
|
SELECT r.id INTO existing_id
|
|
314
327
|
FROM mem_records r
|
|
315
328
|
WHERE r.keys && p_keys
|
|
316
|
-
ORDER BY r.updated_at DESC NULLS LAST, r.id ASC
|
|
329
|
+
ORDER BY (r.status = 'active') DESC, r.updated_at DESC NULLS LAST, r.id ASC
|
|
317
330
|
LIMIT 1;
|
|
318
331
|
|
|
319
332
|
IF existing_id IS NOT NULL THEN
|
|
@@ -478,6 +491,13 @@ function hotColumnIndexName(type, jsonPath) {
|
|
|
478
491
|
|
|
479
492
|
// src/lib/memory/plugins/postgres-core/backend.ts
|
|
480
493
|
var SCHEMA_LOCK_ID = 7193095520723763200n.toString();
|
|
494
|
+
function isUniqueViolation(err) {
|
|
495
|
+
if (!err || typeof err !== "object") return false;
|
|
496
|
+
const e = err;
|
|
497
|
+
if (e.code === "23505") return true;
|
|
498
|
+
const msg = typeof e.message === "string" ? e.message : "";
|
|
499
|
+
return /23505|unique_violation|Key conflict/i.test(msg);
|
|
500
|
+
}
|
|
481
501
|
function toRecord(row) {
|
|
482
502
|
return {
|
|
483
503
|
id: row.id,
|
|
@@ -512,6 +532,10 @@ var CoreBackend = class {
|
|
|
512
532
|
}
|
|
513
533
|
async ensureSchema() {
|
|
514
534
|
const caps = this.caps;
|
|
535
|
+
try {
|
|
536
|
+
if (await this.getSchemaVersion() === SCHEMA_VERSION) return;
|
|
537
|
+
} catch {
|
|
538
|
+
}
|
|
515
539
|
await this.client.transaction(async (tx) => {
|
|
516
540
|
try {
|
|
517
541
|
await tx.query(`SELECT pg_advisory_xact_lock(${SCHEMA_LOCK_ID}::bigint)`);
|
|
@@ -623,6 +647,9 @@ var CoreBackend = class {
|
|
|
623
647
|
const searchable = patch.searchable_text ?? existing.searchable_text ?? null;
|
|
624
648
|
const hash = patch.content_hash ?? existing.content_hash ?? null;
|
|
625
649
|
const weight = patch.weight ?? existing.weight;
|
|
650
|
+
const textChanged = searchable !== (existing.searchable_text ?? null);
|
|
651
|
+
const clearEmbedding = textChanged && this.caps.vectorSearch;
|
|
652
|
+
const embeddingReset = clearEmbedding ? `, embedding = NULL, embedded_at = NULL, embedding_model = NULL` : "";
|
|
626
653
|
const res = await this.client.query(
|
|
627
654
|
`UPDATE mem_records
|
|
628
655
|
SET data = $2::jsonb,
|
|
@@ -631,13 +658,46 @@ var CoreBackend = class {
|
|
|
631
658
|
sources = $5::jsonb,
|
|
632
659
|
searchable_text = $6,
|
|
633
660
|
content_hash = $7,
|
|
634
|
-
weight = $8
|
|
661
|
+
weight = $8${embeddingReset}
|
|
635
662
|
WHERE id = $1
|
|
636
663
|
RETURNING *`,
|
|
637
664
|
[id, JSON.stringify(data), tags, keys, JSON.stringify(sources), searchable, hash, weight]
|
|
638
665
|
);
|
|
639
666
|
return res.rows[0] ? toRecord(res.rows[0]) : null;
|
|
640
667
|
}
|
|
668
|
+
async updateKeys(id, keys) {
|
|
669
|
+
try {
|
|
670
|
+
return await this.client.transaction(async (tx) => {
|
|
671
|
+
const exists = await tx.query(
|
|
672
|
+
`SELECT id FROM mem_records WHERE id = $1`,
|
|
673
|
+
[id]
|
|
674
|
+
);
|
|
675
|
+
if (!exists.rows[0]) return { status: "not_found" };
|
|
676
|
+
const conflict = await tx.query(
|
|
677
|
+
`SELECT r.id, r.type,
|
|
678
|
+
(SELECT k FROM unnest($2::text[]) AS k WHERE k = ANY(r.keys) LIMIT 1) AS key
|
|
679
|
+
FROM mem_records r
|
|
680
|
+
WHERE r.keys && $2::text[] AND r.id != $1 AND r.status = 'active'
|
|
681
|
+
LIMIT 1`,
|
|
682
|
+
[id, keys]
|
|
683
|
+
);
|
|
684
|
+
const c = conflict.rows[0];
|
|
685
|
+
if (c) {
|
|
686
|
+
return { status: "conflict", key: c.key, recordId: c.id, recordType: c.type };
|
|
687
|
+
}
|
|
688
|
+
const res = await tx.query(
|
|
689
|
+
`UPDATE mem_records SET keys = $2::text[] WHERE id = $1 RETURNING *`,
|
|
690
|
+
[id, keys.length > 0 ? keys : null]
|
|
691
|
+
);
|
|
692
|
+
return { status: "ok", record: toRecord(res.rows[0]) };
|
|
693
|
+
});
|
|
694
|
+
} catch (err) {
|
|
695
|
+
if (isUniqueViolation(err)) {
|
|
696
|
+
return { status: "conflict", key: keys[0] ?? "", recordId: "unknown", recordType: "unknown" };
|
|
697
|
+
}
|
|
698
|
+
throw err;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
641
701
|
async remove(id) {
|
|
642
702
|
const res = await this.client.query(`DELETE FROM mem_records WHERE id = $1`, [id]);
|
|
643
703
|
return (res.rowCount ?? 0) > 0;
|
|
@@ -651,12 +711,30 @@ var CoreBackend = class {
|
|
|
651
711
|
return (res.rowCount ?? 0) > 0;
|
|
652
712
|
}
|
|
653
713
|
async unarchive(id) {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
714
|
+
try {
|
|
715
|
+
const res = await this.client.query(
|
|
716
|
+
`UPDATE mem_records SET status = 'active', archived_reason = NULL
|
|
717
|
+
WHERE id = $1 AND status = 'archived'`,
|
|
718
|
+
[id]
|
|
719
|
+
);
|
|
720
|
+
return (res.rowCount ?? 0) > 0;
|
|
721
|
+
} catch (err) {
|
|
722
|
+
if (!isUniqueViolation(err)) throw err;
|
|
723
|
+
const owner = await this.client.query(
|
|
724
|
+
`SELECT r.id, r.type,
|
|
725
|
+
(SELECT k FROM unnest(a.keys) AS k
|
|
726
|
+
WHERE k = ANY(r.keys) LIMIT 1) AS key
|
|
727
|
+
FROM mem_records a
|
|
728
|
+
JOIN mem_records r
|
|
729
|
+
ON r.keys && a.keys AND r.id != a.id AND r.status = 'active'
|
|
730
|
+
WHERE a.id = $1
|
|
731
|
+
LIMIT 1`,
|
|
732
|
+
[id]
|
|
733
|
+
);
|
|
734
|
+
const o = owner.rows[0];
|
|
735
|
+
const detail = o ? `key "${o.key}" was reclaimed by active record ${o.id} (type ${o.type}) \u2014 re-key it or archive that record first` : `one of its keys was reclaimed by another active record`;
|
|
736
|
+
throw new Error(`Cannot unarchive ${id}: ${detail}`);
|
|
737
|
+
}
|
|
660
738
|
}
|
|
661
739
|
async list(type, opts = {}) {
|
|
662
740
|
const limit = opts.limit ?? 100;
|
|
@@ -733,6 +811,48 @@ var CoreBackend = class {
|
|
|
733
811
|
[id, literal, model]
|
|
734
812
|
);
|
|
735
813
|
}
|
|
814
|
+
async listForSearchableBackfill(opts = {}) {
|
|
815
|
+
const limit = opts.limit ?? 1e3;
|
|
816
|
+
const offset = opts.offset ?? 0;
|
|
817
|
+
const params = [];
|
|
818
|
+
const clauses = [`status = 'active'`];
|
|
819
|
+
if (opts.type) {
|
|
820
|
+
params.push(opts.type);
|
|
821
|
+
clauses.push(`type = $${params.length}`);
|
|
822
|
+
}
|
|
823
|
+
if (opts.onlyNull) {
|
|
824
|
+
clauses.push(`(searchable_text IS NULL OR searchable_text = '')`);
|
|
825
|
+
}
|
|
826
|
+
params.push(limit);
|
|
827
|
+
params.push(offset);
|
|
828
|
+
const res = await this.client.query(
|
|
829
|
+
`SELECT id, type, data, searchable_text
|
|
830
|
+
FROM mem_records
|
|
831
|
+
WHERE ${clauses.join(" AND ")}
|
|
832
|
+
ORDER BY id ASC
|
|
833
|
+
LIMIT $${params.length - 1} OFFSET $${params.length}`,
|
|
834
|
+
params
|
|
835
|
+
);
|
|
836
|
+
return res.rows;
|
|
837
|
+
}
|
|
838
|
+
async updateSearchableText(id, text) {
|
|
839
|
+
if (this.caps.vectorSearch) {
|
|
840
|
+
await this.client.query(
|
|
841
|
+
`UPDATE mem_records
|
|
842
|
+
SET searchable_text = $2,
|
|
843
|
+
embedding = NULL,
|
|
844
|
+
embedded_at = NULL,
|
|
845
|
+
embedding_model = NULL
|
|
846
|
+
WHERE id = $1`,
|
|
847
|
+
[id, text]
|
|
848
|
+
);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
await this.client.query(
|
|
852
|
+
`UPDATE mem_records SET searchable_text = $2 WHERE id = $1`,
|
|
853
|
+
[id, text]
|
|
854
|
+
);
|
|
855
|
+
}
|
|
736
856
|
async listKeysByType(type) {
|
|
737
857
|
const res = await this.client.query(
|
|
738
858
|
`SELECT id, keys FROM mem_records WHERE type = $1 AND status = 'active'`,
|
|
@@ -871,7 +991,10 @@ var CoreBackend = class {
|
|
|
871
991
|
}
|
|
872
992
|
async findBySource(sourceKey) {
|
|
873
993
|
const res = await this.client.query(
|
|
874
|
-
`SELECT * FROM mem_records
|
|
994
|
+
`SELECT * FROM mem_records
|
|
995
|
+
WHERE $1 = ANY(keys)
|
|
996
|
+
ORDER BY (status = 'active') DESC, updated_at DESC
|
|
997
|
+
LIMIT 1`,
|
|
875
998
|
[sourceKey]
|
|
876
999
|
);
|
|
877
1000
|
return res.rows[0] ? toRecord(res.rows[0]) : null;
|
|
@@ -1105,6 +1228,9 @@ var LazyPostgresBackend = class {
|
|
|
1105
1228
|
async update(...a) {
|
|
1106
1229
|
return (await this.ensure()).update(...a);
|
|
1107
1230
|
}
|
|
1231
|
+
async updateKeys(...a) {
|
|
1232
|
+
return (await this.ensure()).updateKeys(...a);
|
|
1233
|
+
}
|
|
1108
1234
|
async remove(...a) {
|
|
1109
1235
|
return (await this.ensure()).remove(...a);
|
|
1110
1236
|
}
|
|
@@ -1126,9 +1252,15 @@ var LazyPostgresBackend = class {
|
|
|
1126
1252
|
async listKeysByType(...a) {
|
|
1127
1253
|
return (await this.ensure()).listKeysByType(...a);
|
|
1128
1254
|
}
|
|
1255
|
+
async listForSearchableBackfill(...a) {
|
|
1256
|
+
return (await this.ensure()).listForSearchableBackfill(...a);
|
|
1257
|
+
}
|
|
1129
1258
|
async updateEmbedding(...a) {
|
|
1130
1259
|
return (await this.ensure()).updateEmbedding(...a);
|
|
1131
1260
|
}
|
|
1261
|
+
async updateSearchableText(...a) {
|
|
1262
|
+
return (await this.ensure()).updateSearchableText(...a);
|
|
1263
|
+
}
|
|
1132
1264
|
async raw(sql, params) {
|
|
1133
1265
|
const b = await this.ensure();
|
|
1134
1266
|
if (!b.raw) throw new Error("Backend does not support raw SQL");
|
|
@@ -1451,6 +1583,9 @@ var LazyEmbeddedPostgresBackend = class {
|
|
|
1451
1583
|
async update(...a) {
|
|
1452
1584
|
return (await this.ensure()).update(...a);
|
|
1453
1585
|
}
|
|
1586
|
+
async updateKeys(...a) {
|
|
1587
|
+
return (await this.ensure()).updateKeys(...a);
|
|
1588
|
+
}
|
|
1454
1589
|
async remove(...a) {
|
|
1455
1590
|
return (await this.ensure()).remove(...a);
|
|
1456
1591
|
}
|
|
@@ -1472,9 +1607,15 @@ var LazyEmbeddedPostgresBackend = class {
|
|
|
1472
1607
|
async listKeysByType(...a) {
|
|
1473
1608
|
return (await this.ensure()).listKeysByType(...a);
|
|
1474
1609
|
}
|
|
1610
|
+
async listForSearchableBackfill(...a) {
|
|
1611
|
+
return (await this.ensure()).listForSearchableBackfill(...a);
|
|
1612
|
+
}
|
|
1475
1613
|
async updateEmbedding(...a) {
|
|
1476
1614
|
return (await this.ensure()).updateEmbedding(...a);
|
|
1477
1615
|
}
|
|
1616
|
+
async updateSearchableText(...a) {
|
|
1617
|
+
return (await this.ensure()).updateSearchableText(...a);
|
|
1618
|
+
}
|
|
1478
1619
|
async raw(sql, params) {
|
|
1479
1620
|
const b = await this.ensure();
|
|
1480
1621
|
if (!b.raw) throw new Error("Backend does not support raw SQL");
|
|
@@ -1671,6 +1812,21 @@ async function addRecord(input, opts = {}) {
|
|
|
1671
1812
|
};
|
|
1672
1813
|
return backend.insert(prepared);
|
|
1673
1814
|
}
|
|
1815
|
+
async function updateRecord(id, patch) {
|
|
1816
|
+
const backend = await getBackend();
|
|
1817
|
+
const existing = await backend.getById(id);
|
|
1818
|
+
if (!existing) return null;
|
|
1819
|
+
const mergedData = patch.data ? { ...existing.data, ...patch.data } : existing.data;
|
|
1820
|
+
const dataChanged = patch.data !== void 0;
|
|
1821
|
+
const searchable_text = patch.searchable_text ?? (dataChanged ? defaultSearchableText(mergedData) : existing.searchable_text ?? void 0);
|
|
1822
|
+
const content_hash = patch.content_hash ?? (dataChanged ? contentHash(mergedData) : existing.content_hash ?? void 0);
|
|
1823
|
+
return backend.update(id, {
|
|
1824
|
+
...patch,
|
|
1825
|
+
data: mergedData,
|
|
1826
|
+
searchable_text,
|
|
1827
|
+
content_hash
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1674
1830
|
async function upsertRecord(input, opts = {}) {
|
|
1675
1831
|
const backend = await getBackend();
|
|
1676
1832
|
const { searchable_text, content_hash, embedding, embedding_model } = await prepareRecord(input, opts, "sync");
|
|
@@ -1706,5 +1862,6 @@ export {
|
|
|
1706
1862
|
resetBackendSingleton,
|
|
1707
1863
|
closeBackendIfCached,
|
|
1708
1864
|
addRecord,
|
|
1865
|
+
updateRecord,
|
|
1709
1866
|
upsertRecord
|
|
1710
1867
|
};
|
|
@@ -172,29 +172,78 @@ async function embedBatch(texts, opts = {}) {
|
|
|
172
172
|
function sleep(ms) {
|
|
173
173
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
174
174
|
}
|
|
175
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
176
|
+
var TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
177
|
+
var NOISE_KEY_RE = /(^|_)(id|ids|uuid|guid|url|href|link|avatar|photo|icon|hash|token|slug)$/i;
|
|
178
|
+
var NOISE_KEY_EXACT = /* @__PURE__ */ new Set([
|
|
179
|
+
"attribute_type",
|
|
180
|
+
"actor_type",
|
|
181
|
+
"created_by_actor",
|
|
182
|
+
"active_from",
|
|
183
|
+
"active_until",
|
|
184
|
+
"created_at",
|
|
185
|
+
"updated_at",
|
|
186
|
+
"last_synced_at"
|
|
187
|
+
]);
|
|
188
|
+
var CONTAINER_KEYS = /* @__PURE__ */ new Set([
|
|
189
|
+
"values",
|
|
190
|
+
"value",
|
|
191
|
+
"data",
|
|
192
|
+
"attributes",
|
|
193
|
+
"properties",
|
|
194
|
+
"items",
|
|
195
|
+
"records",
|
|
196
|
+
"result",
|
|
197
|
+
"results",
|
|
198
|
+
"fields"
|
|
199
|
+
]);
|
|
200
|
+
var PRIORITY_KEY_RE = /(^|_)(name|full_name|first_name|last_name|display_name|title|job_title|role|position|email|email_address|company|organization|org|description|bio|summary|headline|label|subject|content|body|text_content)$/i;
|
|
175
201
|
function defaultSearchableText(data, maxLen = 4e3) {
|
|
176
|
-
const
|
|
177
|
-
const
|
|
202
|
+
const priority = [];
|
|
203
|
+
const normal = [];
|
|
204
|
+
const push = (key, text) => {
|
|
205
|
+
if (key && PRIORITY_KEY_RE.test(key)) priority.push(text);
|
|
206
|
+
else normal.push(text);
|
|
207
|
+
};
|
|
208
|
+
const walk = (value, key, depth) => {
|
|
178
209
|
if (value === null || value === void 0) return;
|
|
179
|
-
if (typeof value === "string"
|
|
180
|
-
|
|
210
|
+
if (typeof value === "string") {
|
|
211
|
+
const t = value.trim();
|
|
212
|
+
if (!t) return;
|
|
213
|
+
if (UUID_RE.test(t) || TIMESTAMP_RE.test(t)) return;
|
|
214
|
+
if (key && NOISE_KEY_RE.test(key)) return;
|
|
215
|
+
push(key, t);
|
|
181
216
|
return;
|
|
182
217
|
}
|
|
183
218
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
184
|
-
|
|
219
|
+
if (key && NOISE_KEY_RE.test(key)) return;
|
|
220
|
+
push(key, String(value));
|
|
185
221
|
return;
|
|
186
222
|
}
|
|
187
|
-
if (depth >
|
|
223
|
+
if (depth > 6) return;
|
|
188
224
|
if (Array.isArray(value)) {
|
|
189
|
-
for (const v of value) walk(v, depth + 1);
|
|
225
|
+
for (const v of value) walk(v, key, depth + 1);
|
|
190
226
|
return;
|
|
191
227
|
}
|
|
192
228
|
if (typeof value === "object") {
|
|
193
|
-
for (const v of Object.
|
|
229
|
+
for (const [k, v] of Object.entries(value)) {
|
|
230
|
+
const lower = k.toLowerCase();
|
|
231
|
+
if (NOISE_KEY_EXACT.has(lower) || NOISE_KEY_RE.test(k)) continue;
|
|
232
|
+
const nextKey = CONTAINER_KEYS.has(lower) ? key : k;
|
|
233
|
+
walk(v, nextKey, depth + 1);
|
|
234
|
+
}
|
|
194
235
|
}
|
|
195
236
|
};
|
|
196
|
-
walk(data);
|
|
197
|
-
const
|
|
237
|
+
walk(data, void 0, 0);
|
|
238
|
+
const seen = /* @__PURE__ */ new Set();
|
|
239
|
+
const ordered = [];
|
|
240
|
+
for (const t of [...priority, ...normal]) {
|
|
241
|
+
const norm = t.toLowerCase();
|
|
242
|
+
if (seen.has(norm)) continue;
|
|
243
|
+
seen.add(norm);
|
|
244
|
+
ordered.push(t);
|
|
245
|
+
}
|
|
246
|
+
const joined = ordered.join(" ").replace(/\s+/g, " ").trim();
|
|
198
247
|
return joined.length > maxLen ? joined.slice(0, maxLen) : joined;
|
|
199
248
|
}
|
|
200
249
|
|
|
@@ -2319,7 +2319,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
2319
2319
|
if (flowStack.includes(resolvedKey)) {
|
|
2320
2320
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
2321
2321
|
}
|
|
2322
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
2322
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-YDKAYGZW.js");
|
|
2323
2323
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
2324
2324
|
const subContext = await executeFlow(
|
|
2325
2325
|
subFlow,
|
|
@@ -3238,11 +3238,11 @@ export {
|
|
|
3238
3238
|
ApiError,
|
|
3239
3239
|
OneApi,
|
|
3240
3240
|
TimeoutError,
|
|
3241
|
+
PERMISSION_METHODS,
|
|
3241
3242
|
filterByPermissions,
|
|
3242
3243
|
isMethodAllowed,
|
|
3243
3244
|
isActionAllowed,
|
|
3244
3245
|
buildActionKnowledgeWithGuidance,
|
|
3245
|
-
validateActionInput,
|
|
3246
3246
|
knowledgeCachePath,
|
|
3247
3247
|
searchCachePath,
|
|
3248
3248
|
readCache,
|
|
@@ -3256,6 +3256,7 @@ export {
|
|
|
3256
3256
|
clearEntry,
|
|
3257
3257
|
makeCacheEntry,
|
|
3258
3258
|
resolveActionDetails,
|
|
3259
|
+
validateActionInput,
|
|
3259
3260
|
FLOW_SCHEMA,
|
|
3260
3261
|
getStepTypeDescriptor,
|
|
3261
3262
|
getNestedStepsKeys,
|
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
note,
|
|
7
7
|
okJson,
|
|
8
8
|
requireMemoryInit
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CLJFSFFM.js";
|
|
10
10
|
import {
|
|
11
11
|
getBackend,
|
|
12
12
|
upsertRecord
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-7RV7T5PX.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/mem/migrate.ts
|
|
16
16
|
import fs4 from "fs";
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
FLOW_SCHEMA,
|
|
4
4
|
FlowRunner,
|
|
5
5
|
OneApi,
|
|
6
|
+
PERMISSION_METHODS,
|
|
6
7
|
TimeoutError,
|
|
7
8
|
buildActionKnowledgeWithGuidance,
|
|
8
9
|
buildCacheMeta,
|
|
@@ -31,10 +32,10 @@ import {
|
|
|
31
32
|
validateActionInput,
|
|
32
33
|
walkSteps,
|
|
33
34
|
writeCache
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-D6W756DN.js";
|
|
35
36
|
import {
|
|
36
37
|
memSqlCommand
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-4WWK3GO5.js";
|
|
38
39
|
import {
|
|
39
40
|
countRecords,
|
|
40
41
|
deleteDatabase,
|
|
@@ -59,7 +60,7 @@ import {
|
|
|
59
60
|
upsertRecords,
|
|
60
61
|
writeDraftProfile,
|
|
61
62
|
writeProfile
|
|
62
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-GXOIR3GF.js";
|
|
63
64
|
import {
|
|
64
65
|
getByDotPath
|
|
65
66
|
} from "./chunk-44CV5IMX.js";
|
|
@@ -83,7 +84,7 @@ import {
|
|
|
83
84
|
semanticSearchUpgradeLine,
|
|
84
85
|
setAgentMode,
|
|
85
86
|
silenceWarningsInAgentMode
|
|
86
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-CLJFSFFM.js";
|
|
87
88
|
import {
|
|
88
89
|
SCHEMA_VERSION,
|
|
89
90
|
addRecord,
|
|
@@ -92,8 +93,9 @@ import {
|
|
|
92
93
|
getBackendPlugin,
|
|
93
94
|
listBackendPlugins,
|
|
94
95
|
loadBackendFromConfig,
|
|
96
|
+
updateRecord,
|
|
95
97
|
upsertRecord
|
|
96
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-7RV7T5PX.js";
|
|
97
99
|
import {
|
|
98
100
|
DEFAULT_MEMORY_CONFIG,
|
|
99
101
|
defaultSearchableText,
|
|
@@ -103,7 +105,7 @@ import {
|
|
|
103
105
|
memoryConfigExists,
|
|
104
106
|
setOpenAiApiKey,
|
|
105
107
|
updateMemoryConfig
|
|
106
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-C7DWZ7B5.js";
|
|
107
109
|
import {
|
|
108
110
|
appendAnalyticsQueue,
|
|
109
111
|
appendUsageLog,
|
|
@@ -1941,6 +1943,54 @@ function maskApiKey(key) {
|
|
|
1941
1943
|
import * as p4 from "@clack/prompts";
|
|
1942
1944
|
import pc4 from "picocolors";
|
|
1943
1945
|
|
|
1946
|
+
// src/lib/access.ts
|
|
1947
|
+
async function resolveAllowedActions(api, actionIds) {
|
|
1948
|
+
if (actionIds.includes("*")) return [];
|
|
1949
|
+
const resolved = await Promise.all(
|
|
1950
|
+
actionIds.map(async (actionId) => {
|
|
1951
|
+
try {
|
|
1952
|
+
const { details } = await resolveActionDetails(api, actionId, { warn: () => {
|
|
1953
|
+
} });
|
|
1954
|
+
if (!details.connectionPlatform) return null;
|
|
1955
|
+
return {
|
|
1956
|
+
actionId,
|
|
1957
|
+
title: details.title,
|
|
1958
|
+
method: details.method,
|
|
1959
|
+
platform: details.connectionPlatform
|
|
1960
|
+
};
|
|
1961
|
+
} catch {
|
|
1962
|
+
return null;
|
|
1963
|
+
}
|
|
1964
|
+
})
|
|
1965
|
+
);
|
|
1966
|
+
return resolved.filter((a) => a !== null);
|
|
1967
|
+
}
|
|
1968
|
+
function computeConnectionAccess(platform, permissions, allowedActionIds, grantedActions) {
|
|
1969
|
+
if (!allowedActionIds.includes("*")) {
|
|
1970
|
+
const actions2 = grantedActions.filter((a) => a.platform === platform).map(({ actionId, title, method }) => ({ actionId, title, method }));
|
|
1971
|
+
return { policy: "actions", actions: actions2 };
|
|
1972
|
+
}
|
|
1973
|
+
const methods = PERMISSION_METHODS[permissions];
|
|
1974
|
+
if (methods !== null) {
|
|
1975
|
+
return { policy: "methods", methods };
|
|
1976
|
+
}
|
|
1977
|
+
return { policy: "full" };
|
|
1978
|
+
}
|
|
1979
|
+
function formatAccess(access, maxActions = 2) {
|
|
1980
|
+
switch (access.policy) {
|
|
1981
|
+
case "full":
|
|
1982
|
+
return "full";
|
|
1983
|
+
case "methods":
|
|
1984
|
+
return access.methods.join(", ");
|
|
1985
|
+
case "actions": {
|
|
1986
|
+
if (access.actions.length === 0) return "none";
|
|
1987
|
+
const shown = access.actions.slice(0, maxActions).map((a) => `${a.title} (${a.method})`);
|
|
1988
|
+
const rest = access.actions.length - shown.length;
|
|
1989
|
+
return rest > 0 ? `${shown.join(", ")} +${rest} more` : shown.join(", ");
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1944
1994
|
// src/lib/platforms.ts
|
|
1945
1995
|
function findPlatform(platforms, query) {
|
|
1946
1996
|
const normalizedQuery = query.toLowerCase().trim();
|
|
@@ -2154,8 +2204,16 @@ async function connectionListCommand(options) {
|
|
|
2154
2204
|
try {
|
|
2155
2205
|
const allConnections = await api.listConnections();
|
|
2156
2206
|
const ac = getAccessControlFromAllSources();
|
|
2207
|
+
const permissions = ac.permissions || "admin";
|
|
2157
2208
|
const allowedKeys = ac.connectionKeys || ["*"];
|
|
2209
|
+
const actionIds = ac.actionIds || ["*"];
|
|
2210
|
+
const knowledgeOnly = ac.knowledgeAgent || false;
|
|
2158
2211
|
const accessFiltered = allowedKeys.includes("*") ? allConnections : allConnections.filter((conn) => allowedKeys.includes(conn.key));
|
|
2212
|
+
const resolvedActions = await resolveAllowedActions(api, actionIds);
|
|
2213
|
+
const unresolvedActionIds = actionIds.includes("*") ? [] : actionIds.filter((id) => !resolvedActions.some((a) => a.actionId === id));
|
|
2214
|
+
const grantedActions = resolvedActions.filter((a) => isMethodAllowed(a.method, permissions));
|
|
2215
|
+
const accessFor = (platform) => computeConnectionAccess(platform, permissions, actionIds, grantedActions);
|
|
2216
|
+
const hintText = accessHint(permissions, actionIds, knowledgeOnly);
|
|
2159
2217
|
const searchQuery = options?.search?.toLowerCase();
|
|
2160
2218
|
const filtered = searchQuery ? accessFiltered.filter((conn) => conn.platform.toLowerCase().includes(searchQuery)) : accessFiltered;
|
|
2161
2219
|
const limitArg = options?.limit ? parseInt(options.limit, 10) : void 0;
|
|
@@ -2171,8 +2229,12 @@ async function connectionListCommand(options) {
|
|
|
2171
2229
|
state: conn.state,
|
|
2172
2230
|
key: conn.key,
|
|
2173
2231
|
...conn.name && { name: conn.name },
|
|
2174
|
-
...conn.tags?.length && { tags: conn.tags }
|
|
2232
|
+
...conn.tags?.length && { tags: conn.tags },
|
|
2233
|
+
access: accessFor(conn.platform)
|
|
2175
2234
|
})),
|
|
2235
|
+
...knowledgeOnly && { knowledgeOnly: true },
|
|
2236
|
+
...unresolvedActionIds.length > 0 && { unresolvedActionIds },
|
|
2237
|
+
...hintText && { accessHint: hintText },
|
|
2176
2238
|
...limited.length < filtered.length && {
|
|
2177
2239
|
hint: `Showing ${limited.length} of ${filtered.length} connections. Use --search <query> to filter by platform or --limit <n> to see more.`
|
|
2178
2240
|
}
|
|
@@ -2205,20 +2267,34 @@ Add one with: ${pc4.cyan("one connection add gmail")}`,
|
|
|
2205
2267
|
platform: conn.platform,
|
|
2206
2268
|
state: conn.state,
|
|
2207
2269
|
key: conn.key,
|
|
2208
|
-
tags: conn.tags?.length ? conn.tags.join(", ") : ""
|
|
2270
|
+
tags: conn.tags?.length ? conn.tags.join(", ") : "",
|
|
2271
|
+
access: formatAccess(accessFor(conn.platform))
|
|
2209
2272
|
}));
|
|
2210
2273
|
const hasTags = rows.some((r) => r.tags);
|
|
2274
|
+
const hasScopedAccess = rows.some((r) => r.access !== "full");
|
|
2211
2275
|
printTable(
|
|
2212
2276
|
[
|
|
2213
2277
|
{ key: "status", label: "" },
|
|
2214
2278
|
{ key: "platform", label: "Platform" },
|
|
2215
2279
|
{ key: "state", label: "Status" },
|
|
2216
2280
|
{ key: "key", label: "Connection Key", color: pc4.dim },
|
|
2217
|
-
...hasTags ? [{ key: "tags", label: "Tags", color: pc4.dim }] : []
|
|
2281
|
+
...hasTags ? [{ key: "tags", label: "Tags", color: pc4.dim }] : [],
|
|
2282
|
+
...hasScopedAccess ? [{ key: "access", label: "Access", color: pc4.yellow }] : []
|
|
2218
2283
|
],
|
|
2219
2284
|
rows
|
|
2220
2285
|
);
|
|
2221
2286
|
console.log();
|
|
2287
|
+
if (hintText) {
|
|
2288
|
+
const lines = [hintText];
|
|
2289
|
+
if (unresolvedActionIds.length > 0) {
|
|
2290
|
+
lines.push(
|
|
2291
|
+
`Could not resolve ${unresolvedActionIds.length} allowlisted action id(s): ${unresolvedActionIds.join(", ")}`
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
p4.note(`${wrapText(lines.join("\n"))}
|
|
2295
|
+
|
|
2296
|
+
Change it with: ${pc4.cyan("one config")}`, "Access");
|
|
2297
|
+
}
|
|
2222
2298
|
if (displayed.length < filtered.length) {
|
|
2223
2299
|
p4.note(
|
|
2224
2300
|
`Showing ${displayed.length} of ${filtered.length}. Increase --limit or run without it to see all.`,
|
|
@@ -2291,6 +2367,37 @@ async function connectionDeleteCommand(connectionKey, options) {
|
|
|
2291
2367
|
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2292
2368
|
}
|
|
2293
2369
|
}
|
|
2370
|
+
function accessHint(permissions, actionIds, knowledgeOnly) {
|
|
2371
|
+
const parts = [];
|
|
2372
|
+
if (!actionIds.includes("*")) {
|
|
2373
|
+
parts.push(
|
|
2374
|
+
"Action-scoped: each connection's `access.actions` are the only actions you may run \u2014 use them directly, no `actions search` needed."
|
|
2375
|
+
);
|
|
2376
|
+
} else if (permissions !== "admin") {
|
|
2377
|
+
const methods = PERMISSION_METHODS[permissions]?.join(", ") ?? "";
|
|
2378
|
+
parts.push(`Permission level "${permissions}": only ${methods} actions will execute.`);
|
|
2379
|
+
}
|
|
2380
|
+
if (knowledgeOnly) {
|
|
2381
|
+
parts.push("Knowledge-only mode: `actions execute` is disabled \u2014 read knowledge and write code instead.");
|
|
2382
|
+
}
|
|
2383
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
2384
|
+
}
|
|
2385
|
+
function wrapText(text5, width = 72) {
|
|
2386
|
+
return text5.split("\n").map((paragraph) => {
|
|
2387
|
+
const lines = [];
|
|
2388
|
+
let line = "";
|
|
2389
|
+
for (const word of paragraph.split(/\s+/)) {
|
|
2390
|
+
if (line && line.length + 1 + word.length > width) {
|
|
2391
|
+
lines.push(line);
|
|
2392
|
+
line = word;
|
|
2393
|
+
} else {
|
|
2394
|
+
line = line ? `${line} ${word}` : word;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
if (line) lines.push(line);
|
|
2398
|
+
return lines.join("\n");
|
|
2399
|
+
}).join("\n");
|
|
2400
|
+
}
|
|
2294
2401
|
function getStatusIndicator(state) {
|
|
2295
2402
|
switch (state) {
|
|
2296
2403
|
case "operational":
|
|
@@ -6062,7 +6169,7 @@ async function syncModel(api, profile, options) {
|
|
|
6062
6169
|
updateModelState(platform, model, { status: "failed", pagesProcessed, lastCursor }),
|
|
6063
6170
|
(async () => {
|
|
6064
6171
|
try {
|
|
6065
|
-
const { getBackend: getBackend2 } = await import("./runtime-
|
|
6172
|
+
const { getBackend: getBackend2 } = await import("./runtime-2PRVL2NO.js");
|
|
6066
6173
|
const backend = await getBackend2();
|
|
6067
6174
|
await Promise.race([
|
|
6068
6175
|
backend.close(),
|
|
@@ -6417,7 +6524,7 @@ async function syncModel(api, profile, options) {
|
|
|
6417
6524
|
db.exec(`DROP TABLE IF EXISTS _seen_ids`);
|
|
6418
6525
|
}
|
|
6419
6526
|
if (options.toMemory !== false) {
|
|
6420
|
-
const backend = await (await import("./runtime-
|
|
6527
|
+
const backend = await (await import("./runtime-2PRVL2NO.js")).getBackend();
|
|
6421
6528
|
const type = `${platform}/${model}`;
|
|
6422
6529
|
const existing = await backend.listKeysByType(type);
|
|
6423
6530
|
const sourcePrefix = `${type}:`;
|
|
@@ -6497,7 +6604,7 @@ async function syncModel(api, profile, options) {
|
|
|
6497
6604
|
let statusCounts;
|
|
6498
6605
|
if (options.toMemory !== false) {
|
|
6499
6606
|
try {
|
|
6500
|
-
const backend = await (await import("./runtime-
|
|
6607
|
+
const backend = await (await import("./runtime-2PRVL2NO.js")).getBackend();
|
|
6501
6608
|
const typeName = `${platform}/${model}`;
|
|
6502
6609
|
const [active, archived] = await Promise.all([
|
|
6503
6610
|
backend.count(typeName, { status: "active" }),
|
|
@@ -8130,7 +8237,7 @@ ${result.total} results`);
|
|
|
8130
8237
|
}
|
|
8131
8238
|
}
|
|
8132
8239
|
async function syncSqlCommand(platformModel, sql) {
|
|
8133
|
-
const { syncSqlCommand: runSyncSql } = await import("./sql-
|
|
8240
|
+
const { syncSqlCommand: runSyncSql } = await import("./sql-HG7R2JML.js");
|
|
8134
8241
|
await runSyncSql(platformModel, sql);
|
|
8135
8242
|
}
|
|
8136
8243
|
async function syncDeleteCommand(platformModel, options) {
|
|
@@ -8208,7 +8315,7 @@ async function syncDeleteCommand(platformModel, options) {
|
|
|
8208
8315
|
async function maybeAutoMigrateLegacy(platform, models) {
|
|
8209
8316
|
const dbSize = getDatabaseSize(platform);
|
|
8210
8317
|
if (!dbSize || dbSize === "0 B") return;
|
|
8211
|
-
const { getBackend: getBackend2 } = await import("./runtime-
|
|
8318
|
+
const { getBackend: getBackend2 } = await import("./runtime-2PRVL2NO.js");
|
|
8212
8319
|
const backend = await getBackend2();
|
|
8213
8320
|
let memoryHasData = false;
|
|
8214
8321
|
for (const model of models) {
|
|
@@ -8224,7 +8331,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
8224
8331
|
` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
|
|
8225
8332
|
`
|
|
8226
8333
|
);
|
|
8227
|
-
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-
|
|
8334
|
+
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-TRUZVAT5.js");
|
|
8228
8335
|
await memMigrateCommand3({ platform, yes: true });
|
|
8229
8336
|
return;
|
|
8230
8337
|
}
|
|
@@ -8233,7 +8340,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
8233
8340
|
initialValue: true
|
|
8234
8341
|
});
|
|
8235
8342
|
if (p7.isCancel(shouldMigrate) || !shouldMigrate) return;
|
|
8236
|
-
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-
|
|
8343
|
+
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-TRUZVAT5.js");
|
|
8237
8344
|
await memMigrateCommand2({ platform, yes: true });
|
|
8238
8345
|
}
|
|
8239
8346
|
async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
@@ -8294,7 +8401,7 @@ async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
|
8294
8401
|
async function syncListCommand(platform) {
|
|
8295
8402
|
const profiles = listProfiles(platform);
|
|
8296
8403
|
const state = await readSyncState();
|
|
8297
|
-
const { getBackend: getBackend2 } = await import("./runtime-
|
|
8404
|
+
const { getBackend: getBackend2 } = await import("./runtime-2PRVL2NO.js");
|
|
8298
8405
|
const backend = await getBackend2();
|
|
8299
8406
|
const syncs = await Promise.all(profiles.map(async (p10) => {
|
|
8300
8407
|
const modelState = state[p10.platform]?.[p10.model];
|
|
@@ -8569,7 +8676,7 @@ function registerSyncSubcommands(sync) {
|
|
|
8569
8676
|
await syncSqlCommand(platformModel, sql);
|
|
8570
8677
|
});
|
|
8571
8678
|
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) => {
|
|
8572
|
-
const { syncSchemaCommand } = await import("./schema-
|
|
8679
|
+
const { syncSchemaCommand } = await import("./schema-LCRWSFD5.js");
|
|
8573
8680
|
await syncSchemaCommand(platformModel);
|
|
8574
8681
|
});
|
|
8575
8682
|
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) => {
|
|
@@ -9015,11 +9122,41 @@ async function memGetCommand(id, flags) {
|
|
|
9015
9122
|
async function memUpdateCommand(id, patchRaw) {
|
|
9016
9123
|
requireMemoryInit();
|
|
9017
9124
|
const patch = parseJsonArg(patchRaw, "patch");
|
|
9018
|
-
|
|
9019
|
-
|
|
9125
|
+
if (patch && typeof patch === "object" && !Array.isArray(patch) && "keys" in patch) {
|
|
9126
|
+
error("`keys` is not a data field. Use `one mem key <id> --set <csv>` (or --add/--remove) to change a record's keys.");
|
|
9127
|
+
}
|
|
9128
|
+
const updated = await updateRecord(id, { data: patch });
|
|
9020
9129
|
if (!updated) error(`Record ${id} not found`);
|
|
9021
9130
|
printRecord(updated);
|
|
9022
9131
|
}
|
|
9132
|
+
async function memKeyCommand(id, flags) {
|
|
9133
|
+
requireMemoryInit();
|
|
9134
|
+
const backend = await getBackend();
|
|
9135
|
+
const setList = parseCsv(flags.set);
|
|
9136
|
+
const addList = parseCsv(flags.add) ?? [];
|
|
9137
|
+
const removeList = parseCsv(flags.remove) ?? [];
|
|
9138
|
+
if (!setList && addList.length === 0 && removeList.length === 0) {
|
|
9139
|
+
error("Pass at least one of --add <csv>, --remove <csv>, or --set <csv>.");
|
|
9140
|
+
}
|
|
9141
|
+
const existing = await backend.getById(id);
|
|
9142
|
+
if (!existing) error(`Record ${id} not found`);
|
|
9143
|
+
let next;
|
|
9144
|
+
if (setList) {
|
|
9145
|
+
next = setList;
|
|
9146
|
+
} else {
|
|
9147
|
+
const removeSet = new Set(removeList);
|
|
9148
|
+
next = [...existing.keys ?? [], ...addList].filter((k) => !removeSet.has(k));
|
|
9149
|
+
}
|
|
9150
|
+
next = [...new Set(next)];
|
|
9151
|
+
const outcome = await backend.updateKeys(id, next);
|
|
9152
|
+
if (outcome.status === "not_found") error(`Record ${id} not found`);
|
|
9153
|
+
if (outcome.status === "conflict") {
|
|
9154
|
+
error(
|
|
9155
|
+
`Key "${outcome.key}" is already owned by active record ${outcome.recordId} (type ${outcome.recordType}). Keys must be unique across active records \u2014 archive or re-key that record first.`
|
|
9156
|
+
);
|
|
9157
|
+
}
|
|
9158
|
+
printRecord(outcome.record);
|
|
9159
|
+
}
|
|
9023
9160
|
async function memArchiveCommand(id, flags) {
|
|
9024
9161
|
requireMemoryInit();
|
|
9025
9162
|
const backend = await getBackend();
|
|
@@ -9216,7 +9353,7 @@ async function memDoctorCommand() {
|
|
|
9216
9353
|
}
|
|
9217
9354
|
if (cfg.embedding.provider === "openai") {
|
|
9218
9355
|
try {
|
|
9219
|
-
const { embed: embed2 } = await import("./embedding-
|
|
9356
|
+
const { embed: embed2 } = await import("./embedding-2YB6CGBA.js");
|
|
9220
9357
|
const result = await embed2("connectivity check");
|
|
9221
9358
|
checks.push({
|
|
9222
9359
|
name: "OpenAI embedding provider reachable",
|
|
@@ -9375,6 +9512,9 @@ async function memVacuumCommand() {
|
|
|
9375
9512
|
}
|
|
9376
9513
|
async function memReindexCommand(flags) {
|
|
9377
9514
|
requireMemoryInit();
|
|
9515
|
+
if (flags.searchable) {
|
|
9516
|
+
return memReindexSearchableCommand(flags);
|
|
9517
|
+
}
|
|
9378
9518
|
const backend = await getBackend();
|
|
9379
9519
|
const cfg = getMemoryConfigOrDefault();
|
|
9380
9520
|
if (cfg.embedding.provider !== "openai") {
|
|
@@ -9437,6 +9577,58 @@ async function memReindexCommand(flags) {
|
|
|
9437
9577
|
force: !!flags.force
|
|
9438
9578
|
});
|
|
9439
9579
|
}
|
|
9580
|
+
async function memReindexSearchableCommand(flags) {
|
|
9581
|
+
const backend = await getBackend();
|
|
9582
|
+
const onlyNull = !flags.all;
|
|
9583
|
+
const totalCap = flags.limit ? parsePositiveInt(flags.limit, 1e6, "limit") : 1e6;
|
|
9584
|
+
const PAGE = 500;
|
|
9585
|
+
let considered = 0;
|
|
9586
|
+
let updated = 0;
|
|
9587
|
+
let unchanged = 0;
|
|
9588
|
+
let emptied = 0;
|
|
9589
|
+
let offset = 0;
|
|
9590
|
+
while (considered < totalCap) {
|
|
9591
|
+
const pageSize = Math.min(PAGE, totalCap - considered);
|
|
9592
|
+
const rows = await backend.listForSearchableBackfill({
|
|
9593
|
+
type: flags.type,
|
|
9594
|
+
onlyNull,
|
|
9595
|
+
limit: pageSize,
|
|
9596
|
+
offset
|
|
9597
|
+
});
|
|
9598
|
+
if (rows.length === 0) break;
|
|
9599
|
+
considered += rows.length;
|
|
9600
|
+
let updatedThisPage = 0;
|
|
9601
|
+
for (const r of rows) {
|
|
9602
|
+
const next = defaultSearchableText(r.data);
|
|
9603
|
+
if (!next) {
|
|
9604
|
+
emptied++;
|
|
9605
|
+
continue;
|
|
9606
|
+
}
|
|
9607
|
+
if (next === (r.searchable_text ?? "")) {
|
|
9608
|
+
unchanged++;
|
|
9609
|
+
continue;
|
|
9610
|
+
}
|
|
9611
|
+
await backend.updateSearchableText(r.id, next);
|
|
9612
|
+
updated++;
|
|
9613
|
+
updatedThisPage++;
|
|
9614
|
+
}
|
|
9615
|
+
offset += onlyNull ? rows.length - updatedThisPage : rows.length;
|
|
9616
|
+
if (!isAgentMode()) {
|
|
9617
|
+
process.stderr.write(` searchable: updated ${updated} / considered ${considered}\r`);
|
|
9618
|
+
}
|
|
9619
|
+
}
|
|
9620
|
+
if (!isAgentMode()) process.stderr.write("\n");
|
|
9621
|
+
okJson({
|
|
9622
|
+
status: "ok",
|
|
9623
|
+
mode: "searchable",
|
|
9624
|
+
type: flags.type ?? null,
|
|
9625
|
+
scope: onlyNull ? "null_only" : "all",
|
|
9626
|
+
considered,
|
|
9627
|
+
updated,
|
|
9628
|
+
unchanged,
|
|
9629
|
+
emptied
|
|
9630
|
+
});
|
|
9631
|
+
}
|
|
9440
9632
|
|
|
9441
9633
|
// src/commands/mem.ts
|
|
9442
9634
|
function memStatusCommand() {
|
|
@@ -9475,11 +9667,12 @@ function registerMemoryCommands(program2) {
|
|
|
9475
9667
|
);
|
|
9476
9668
|
mem.command("doctor").description("Diagnose schema, indexes, plugin resolution, connectivity, embeddings").action(memDoctorCommand);
|
|
9477
9669
|
mem.command("vacuum").description("Run backend maintenance (VACUUM ANALYZE on tables)").action(memVacuumCommand);
|
|
9478
|
-
mem.command("reindex").description("Backfill embeddings
|
|
9670
|
+
mem.command("reindex").description("Backfill embeddings (default) or searchable_text (--searchable)").option("--type <type>", "Restrict to one record type, e.g. attio/attioPeople").option("--model <name>", "Override the embedding model").option("--force", "Re-embed even rows that already have a matching embedding", false).option("--batch <n>", "OpenAI calls per batch (default 50)", "50").option("--limit <n>", "Safety cap on total records to scan (default 100000)").option("--searchable", "Regenerate searchable_text (NULL or stale vs. data) instead of embeddings", false).option("--all", "With --searchable: also rewrite rows whose text is stale, not just NULL", false).action(memReindexCommand);
|
|
9479
9671
|
mem.command("sql <query>").description("Run a read-only SELECT / WITH / EXPLAIN against the memory store").action(memSqlCommand);
|
|
9480
9672
|
mem.command("add <type> <data>").description("Add a new memory record (data is JSON)").option("--tags <csv>", "Comma-separated tags").option("--keys <csv>", "Comma-separated keys (prefixed, e.g. email:x@y.com)").option("--weight <n>", "Importance 1-10 (default 5)").option("--embed", "Force embedding for this record").option("--no-embed", "Skip embedding for this record").action(memAddCommand);
|
|
9481
9673
|
mem.command("get <id>").description("Get a record by id").option("--links", "Include outgoing and incoming links", false).action(memGetCommand);
|
|
9482
|
-
mem.command("update <id> <patch>").description("Update a record (patch is JSON merged into data)").action(memUpdateCommand);
|
|
9674
|
+
mem.command("update <id> <patch>").description("Update a record (patch is JSON merged into data; regenerates searchable_text)").action(memUpdateCommand);
|
|
9675
|
+
mem.command("key <id>").description("Manage a record's identity keys (unique across active records)").option("--add <csv>", "Keys to add (comma-separated, e.g. email:x@y.com)").option("--remove <csv>", "Keys to remove (comma-separated)").option("--set <csv>", "Replace all keys with this comma-separated list").action((id, flags) => memKeyCommand(id, flags));
|
|
9483
9676
|
mem.command("archive <id>").description("Archive a record").option("--reason <text>", "Why it was archived (user_archived | deleted_upstream | superseded | \u2026)").action(memArchiveCommand);
|
|
9484
9677
|
mem.command("weight <id> <n>").description("Set record relevance weight (1-10)").action(memWeightCommand);
|
|
9485
9678
|
mem.command("flush <id>").description("Reset access count for a record").action(memFlushCommand);
|
|
@@ -9690,7 +9883,7 @@ Search for actions, read their docs, and execute them. This is the core workflow
|
|
|
9690
9883
|
|
|
9691
9884
|
**Quick start:**
|
|
9692
9885
|
\`\`\`bash
|
|
9693
|
-
one --agent connection list # See connected platforms
|
|
9886
|
+
one --agent connection list # See connected platforms + your access on each
|
|
9694
9887
|
one --agent connection delete <connection-key> # Remove a connection
|
|
9695
9888
|
one --agent actions search <platform> "<query>" -t execute # Find an action
|
|
9696
9889
|
one --agent actions knowledge <platform> <actionId> # Read docs (REQUIRED)
|
|
@@ -9779,6 +9972,7 @@ Request specific sections:
|
|
|
9779
9972
|
- Always use the **exact action ID** from search results \u2014 don't guess
|
|
9780
9973
|
- Always read **knowledge** before executing any action
|
|
9781
9974
|
- Connection keys come from \`one connection list\` \u2014 don't hardcode them
|
|
9975
|
+
- \`connection list\` also reports an \`access\` field per connection (\`full\` / \`methods\` / \`actions\`) \u2014 read it before planning so you don't propose an action the access config will reject
|
|
9782
9976
|
- Skills stay in lockstep with the CLI version automatically \u2014 every command checks a \`.one-cli-version\` marker in the canonical skill dir and refreshes the files if the CLI has been upgraded. Check manually with \`one config skills status\`; force a resync with \`one config skills sync\`
|
|
9783
9977
|
`;
|
|
9784
9978
|
var GUIDE_ACTIONS = `# One Actions \u2014 Reference
|
|
@@ -9793,7 +9987,17 @@ Always follow this sequence. Never skip the knowledge step.
|
|
|
9793
9987
|
one --agent connection list
|
|
9794
9988
|
\`\`\`
|
|
9795
9989
|
|
|
9796
|
-
Returns platforms, status, connection keys, and
|
|
9990
|
+
Returns platforms, status, connection keys, tags, and an \`access\` field per connection describing what the current access config lets you run there:
|
|
9991
|
+
|
|
9992
|
+
| \`access\` | Meaning |
|
|
9993
|
+
|----------|---------|
|
|
9994
|
+
| \`{"policy": "full"}\` | Every action on the connection |
|
|
9995
|
+
| \`{"policy": "methods", "methods": ["GET"]}\` | Only actions with these HTTP methods will execute |
|
|
9996
|
+
| \`{"policy": "actions", "actions": [{"actionId", "title", "method"}]}\` | Only these exact actions \u2014 use them directly, skip \`actions search\` |
|
|
9997
|
+
|
|
9998
|
+
Also present when relevant: \`knowledgeOnly: true\` (execution disabled \u2014 read knowledge and write code instead), \`unresolvedActionIds\` (allowlisted ids that could not be looked up), and \`accessHint\` (a one-line summary of the restriction).
|
|
9999
|
+
|
|
10000
|
+
Read \`access\` before planning \u2014 it prevents proposing an action the config will reject. Change it with \`one config\`.
|
|
9797
10001
|
|
|
9798
10002
|
### 1b. Delete a Connection
|
|
9799
10003
|
|
|
@@ -10122,10 +10326,19 @@ one --agent mem add note '{"content":"..."}' --tags work,urgent --weight 8 --key
|
|
|
10122
10326
|
# Get (optionally with links)
|
|
10123
10327
|
one --agent mem get <id> --links
|
|
10124
10328
|
|
|
10125
|
-
# Update (shallow merge into data)
|
|
10329
|
+
# Update (shallow merge into data; regenerates searchable_text from the merged data)
|
|
10126
10330
|
one --agent mem update <id> '{"status":"done"}'
|
|
10127
10331
|
|
|
10128
|
-
#
|
|
10332
|
+
# Manage identity keys AFTER creation (keys are a first-class column, NOT data).
|
|
10333
|
+
# Unique across ACTIVE records \u2014 a clear error names the record that owns a taken key.
|
|
10334
|
+
one --agent mem key <id> --add email:new@x.com
|
|
10335
|
+
one --agent mem key <id> --remove email:old@x.com
|
|
10336
|
+
one --agent mem key <id> --set 'email:a@x.com,phone:+1555' # replace all keys
|
|
10337
|
+
# NOTE: passing keys to 'mem update' is rejected \u2014 keys are not a data field.
|
|
10338
|
+
|
|
10339
|
+
# Archive / unarchive. Archiving FREES a record's keys: an archived record no
|
|
10340
|
+
# longer blocks a new active record from reusing the same key (uniqueness is
|
|
10341
|
+
# scoped to active records).
|
|
10129
10342
|
one --agent mem archive <id> --reason superseded
|
|
10130
10343
|
|
|
10131
10344
|
# List by type \u2014 type is positional. Synced rows are namespaced as <platform>/<model>.
|
|
@@ -10191,8 +10404,12 @@ one --agent mem status # backend, provider, _upgrade hint
|
|
|
10191
10404
|
one --agent mem doctor # 7-check health report
|
|
10192
10405
|
one --agent mem vacuum # backend maintenance (VACUUM ANALYZE)
|
|
10193
10406
|
one --agent mem reindex # re-embed records under current model
|
|
10407
|
+
one --agent mem reindex --searchable # backfill searchable_text where NULL
|
|
10408
|
+
one --agent mem reindex --searchable --type attio/attioPeople --all # also rewrite stale text
|
|
10194
10409
|
\`\`\`
|
|
10195
10410
|
|
|
10411
|
+
\`mem reindex --searchable\` regenerates \`searchable_text\` from each record's own \`data\` (no embedding provider needed). It fixes rows that landed with NULL searchable_text and, thanks to the cleaned-up text builder, drops UUID/timestamp noise and leads with name/title/email fields so FTS ranks on what humans search. Regenerated rows are re-queued for embedding on the next \`mem reindex\`.
|
|
10412
|
+
|
|
10196
10413
|
## Admin
|
|
10197
10414
|
|
|
10198
10415
|
\`\`\`bash
|
|
@@ -11356,7 +11573,7 @@ program.name("one").option("--agent", "Machine-readable JSON output (no colors,
|
|
|
11356
11573
|
one whoami Show current user, organization, and project
|
|
11357
11574
|
|
|
11358
11575
|
Workflow (use these in order):
|
|
11359
|
-
1. one list List
|
|
11576
|
+
1. one list List connected platforms, keys, and your access on each
|
|
11360
11577
|
2. one actions search <platform> <q> Search for actions using natural language
|
|
11361
11578
|
3. one actions knowledge <plat> <id> Get full docs for an action (ALWAYS do this before execute)
|
|
11362
11579
|
4. one actions execute <p> <id> <key> Execute the action
|
|
@@ -11614,7 +11831,7 @@ var connection = program.command("connection").description("Manage connections")
|
|
|
11614
11831
|
connection.command("add [platform]").alias("a").description("Add a new connection").option("--tag <name>", "Tag the new connection (disambiguates multiple connections per platform in sync/flow profiles)").action(async (platform, options) => {
|
|
11615
11832
|
await connectionAddCommand(platform, { tag: options.tag });
|
|
11616
11833
|
});
|
|
11617
|
-
connection.command("list").alias("ls").description("List your connections").option("-s, --search <query>", "Filter connections by platform name").option("-l, --limit <n>", "Max connections to return (agent mode default: 20)").action(async (options) => {
|
|
11834
|
+
connection.command("list").alias("ls").description("List your connections and what your access config lets you run on each").option("-s, --search <query>", "Filter connections by platform name").option("-l, --limit <n>", "Max connections to return (agent mode default: 20)").action(async (options) => {
|
|
11618
11835
|
await connectionListCommand(options);
|
|
11619
11836
|
});
|
|
11620
11837
|
connection.command("delete <connection-key>").alias("rm").description("Delete a connection").option("-f, --force", "Skip confirmation prompt").action(async (connectionKey, options) => {
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
dotPathToJsonbExpr,
|
|
4
4
|
memMigrateCommand,
|
|
5
5
|
reviveStringifiedJson
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GXOIR3GF.js";
|
|
7
7
|
import "./chunk-44CV5IMX.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-CLJFSFFM.js";
|
|
9
|
+
import "./chunk-7RV7T5PX.js";
|
|
10
|
+
import "./chunk-C7DWZ7B5.js";
|
|
11
11
|
import "./chunk-SO323PZP.js";
|
|
12
12
|
export {
|
|
13
13
|
buildIdentityMap,
|
|
@@ -3,14 +3,16 @@ import {
|
|
|
3
3
|
closeBackendIfCached,
|
|
4
4
|
getBackend,
|
|
5
5
|
resetBackendSingleton,
|
|
6
|
+
updateRecord,
|
|
6
7
|
upsertRecord
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-7RV7T5PX.js";
|
|
9
|
+
import "./chunk-C7DWZ7B5.js";
|
|
9
10
|
import "./chunk-SO323PZP.js";
|
|
10
11
|
export {
|
|
11
12
|
addRecord,
|
|
12
13
|
closeBackendIfCached,
|
|
13
14
|
getBackend,
|
|
14
15
|
resetBackendSingleton,
|
|
16
|
+
updateRecord,
|
|
15
17
|
upsertRecord
|
|
16
18
|
};
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
note,
|
|
4
4
|
okJson,
|
|
5
5
|
requireMemoryInit
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CLJFSFFM.js";
|
|
7
7
|
import {
|
|
8
8
|
getBackend
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-7RV7T5PX.js";
|
|
10
|
+
import "./chunk-C7DWZ7B5.js";
|
|
11
11
|
import "./chunk-SO323PZP.js";
|
|
12
12
|
|
|
13
13
|
// src/lib/memory/sync/schema.ts
|
package/package.json
CHANGED
package/skills/one/SKILL.md
CHANGED
|
@@ -45,7 +45,21 @@ Always follow this sequence when the user wants to do something on a connected p
|
|
|
45
45
|
one --agent connection list
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Returns connected platforms with their connection keys (needed for execution)
|
|
48
|
+
Returns connected platforms with their connection keys (needed for execution), platform names in kebab-case (needed for searching), and an `access` field per connection telling you what you may run there.
|
|
49
|
+
|
|
50
|
+
**Read `access` before you plan a workflow** — it saves you from discovering a restriction as a 403 halfway through:
|
|
51
|
+
|
|
52
|
+
| `access` | What it means |
|
|
53
|
+
|----------|---------------|
|
|
54
|
+
| `{"policy": "full"}` | Every action on this connection is available |
|
|
55
|
+
| `{"policy": "methods", "methods": ["GET"]}` | Only actions with these HTTP methods will execute — don't propose writes |
|
|
56
|
+
| `{"policy": "actions", "actions": [...]}` | Only these exact actions may run. Each has `actionId`, `title`, `method` — **use them directly and skip `actions search`** |
|
|
57
|
+
|
|
58
|
+
Two more fields appear only when relevant:
|
|
59
|
+
- `"knowledgeOnly": true` — `actions execute` is disabled. Read knowledge and write integration code instead of executing.
|
|
60
|
+
- `"unresolvedActionIds": [...]` — allowlisted ids that couldn't be looked up; treat them as unavailable and tell the user.
|
|
61
|
+
|
|
62
|
+
An empty `actions` array means the allowlist grants nothing on that connection — say so rather than searching for alternatives.
|
|
49
63
|
|
|
50
64
|
### 1b. Delete a connection
|
|
51
65
|
|
|
@@ -170,10 +184,19 @@ Underneath, the store has no `platform` column — `type` is the only platform-s
|
|
|
170
184
|
```bash
|
|
171
185
|
# User memories
|
|
172
186
|
one --agent mem add note '{"content":"..."}' --tags work --weight 7
|
|
187
|
+
one --agent mem update <id> '{"status":"done"}' # merges into data; refreshes searchable_text
|
|
173
188
|
one --agent mem search "deadline" # hybrid if key set, else FTS
|
|
174
189
|
one --agent mem list note --limit 20
|
|
175
190
|
one --agent mem link <from-id> <to-id> relates_to --bi
|
|
176
191
|
|
|
192
|
+
# Identity keys (first-class column, NOT data). Unique across ACTIVE records;
|
|
193
|
+
# archiving a record frees its keys. `mem update '{"keys":[...]}'` is rejected.
|
|
194
|
+
one --agent mem key <id> --add email:x@y.com # add/--remove/--set
|
|
195
|
+
one --agent mem find-by-source email:x@y.com # prefers the active owner
|
|
196
|
+
|
|
197
|
+
# Backfill searchable_text (no embedding provider needed) — fixes NULL/noisy text
|
|
198
|
+
one --agent mem reindex --searchable --type attio/attioPeople
|
|
199
|
+
|
|
177
200
|
# Status + diagnostics
|
|
178
201
|
one --agent mem status # backend, provider, _upgrade hint
|
|
179
202
|
one --agent mem doctor # full health report
|
package/dist/sql-CBZQHP4R.js
DELETED