@withone/cli 1.49.0 → 1.51.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 +50 -4
- package/dist/{chunk-2TWFL3CS.js → chunk-D6W756DN.js} +3 -2
- package/dist/{chunk-4WWK3GO5.js → chunk-UV4YYDF3.js} +1 -1
- package/dist/{chunk-7RV7T5PX.js → chunk-Z4KAQGIG.js} +139 -15
- package/dist/{chunk-GXOIR3GF.js → chunk-ZOJW6IMU.js} +278 -13
- package/dist/{flow-runner-IBB42ED2.js → flow-runner-YDKAYGZW.js} +1 -1
- package/dist/index.js +539 -262
- package/dist/{migrate-TRUZVAT5.js → migrate-LXDIZMXH.js} +2 -2
- package/dist/{runtime-2PRVL2NO.js → runtime-HDZCBTWH.js} +1 -1
- package/dist/{schema-LCRWSFD5.js → schema-SYMG6SRC.js} +1 -1
- package/dist/{sql-HG7R2JML.js → sql-AZDCMY7G.js} +2 -2
- package/package.json +2 -1
- package/profiles/fathom/meetings.json +4 -0
- package/profiles/gmail/gmailThreads.json +5 -0
- package/profiles/google-calendar/events.json +5 -1
- package/skills/one/SKILL.md +63 -6
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
getBackend,
|
|
12
12
|
upsertRecord
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-Z4KAQGIG.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/mem/migrate.ts
|
|
16
16
|
import fs4 from "fs";
|
|
@@ -387,6 +387,273 @@ function deleteDatabase(platform) {
|
|
|
387
387
|
if (fs3.existsSync(dbPath + "-shm")) fs3.unlinkSync(dbPath + "-shm");
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
+
// src/lib/memory/sync/mem-writer.ts
|
|
391
|
+
function resolveWildcardPath(root, path5) {
|
|
392
|
+
const segments = path5.split("[]");
|
|
393
|
+
if (segments.length === 1) {
|
|
394
|
+
return [getByDotPath(root, path5)];
|
|
395
|
+
}
|
|
396
|
+
const recurse = (value, idx) => {
|
|
397
|
+
if (value === null || value === void 0) return [];
|
|
398
|
+
const segment = segments[idx];
|
|
399
|
+
const head = segment.startsWith(".") ? segment.slice(1) : segment;
|
|
400
|
+
if (idx === segments.length - 1) {
|
|
401
|
+
if (!Array.isArray(value)) return [];
|
|
402
|
+
if (head === "") return value;
|
|
403
|
+
return value.map((el) => getByDotPath(el, head));
|
|
404
|
+
}
|
|
405
|
+
if (!Array.isArray(value)) return [];
|
|
406
|
+
const results = [];
|
|
407
|
+
for (const el of value) {
|
|
408
|
+
const next = head === "" ? el : getByDotPath(el, head);
|
|
409
|
+
results.push(...recurse(next, idx + 1));
|
|
410
|
+
}
|
|
411
|
+
return results;
|
|
412
|
+
};
|
|
413
|
+
const firstHead = segments[0];
|
|
414
|
+
const firstValue = firstHead === "" ? root : getByDotPath(root, firstHead);
|
|
415
|
+
return recurse(firstValue, 1);
|
|
416
|
+
}
|
|
417
|
+
function extractSearchableFromPaths(record, paths) {
|
|
418
|
+
const parts = [];
|
|
419
|
+
const perPath = [];
|
|
420
|
+
for (const path5 of paths) {
|
|
421
|
+
const values = resolveWildcardPath(record, path5);
|
|
422
|
+
const collected = [];
|
|
423
|
+
const absorb = (v) => {
|
|
424
|
+
if (v === null || v === void 0) return;
|
|
425
|
+
if (typeof v === "string") {
|
|
426
|
+
const t = v.trim();
|
|
427
|
+
if (t) collected.push(t);
|
|
428
|
+
} else if (typeof v === "number" || typeof v === "boolean") {
|
|
429
|
+
collected.push(String(v));
|
|
430
|
+
} else if (Array.isArray(v)) {
|
|
431
|
+
for (const inner of v) absorb(inner);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
for (const v of values) absorb(v);
|
|
435
|
+
if (collected.length > 0) {
|
|
436
|
+
parts.push(...collected);
|
|
437
|
+
perPath.push({ path: path5, found: true, sample: collected.join(" ").slice(0, 80) });
|
|
438
|
+
} else {
|
|
439
|
+
perPath.push({ path: path5, found: false, sample: "" });
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const text = parts.join(" ").replace(/\s+/g, " ").trim();
|
|
443
|
+
return { text, paths: perPath };
|
|
444
|
+
}
|
|
445
|
+
function getSearchablePaths(profile) {
|
|
446
|
+
const paths = profile.memory?.searchable;
|
|
447
|
+
if (!paths || !Array.isArray(paths) || paths.length === 0) return void 0;
|
|
448
|
+
return paths;
|
|
449
|
+
}
|
|
450
|
+
async function writePageToMemory(profile, records, opts = {}) {
|
|
451
|
+
const report = {
|
|
452
|
+
attempted: 0,
|
|
453
|
+
inserted: 0,
|
|
454
|
+
updated: 0,
|
|
455
|
+
skipped: 0,
|
|
456
|
+
preserved: 0,
|
|
457
|
+
sourceKeysSeen: [],
|
|
458
|
+
inserts: [],
|
|
459
|
+
updates: []
|
|
460
|
+
};
|
|
461
|
+
const type = `${profile.platform}/${profile.model}`;
|
|
462
|
+
const embedFlag = opts.embedOverride ?? deriveEmbedFlag(profile);
|
|
463
|
+
const searchablePaths = getSearchablePaths(profile);
|
|
464
|
+
const declaresIdentityKeys = (profile.identityKeys?.length ?? 0) > 0;
|
|
465
|
+
const enrichTimestampField = profile.enrich?.timestampField ?? "_enriched_at";
|
|
466
|
+
for (const record of records) {
|
|
467
|
+
report.attempted++;
|
|
468
|
+
const externalId = getByDotPath(record, profile.idField);
|
|
469
|
+
if (externalId === void 0 || externalId === null || externalId === "") {
|
|
470
|
+
report.skipped++;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
if (typeof externalId === "object") {
|
|
474
|
+
report.skipped++;
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
const sourceKey = `${type}:${String(externalId)}`;
|
|
478
|
+
const alreadyEnriched = opts.alreadyEnrichedIds?.has(String(externalId)) ?? false;
|
|
479
|
+
if (alreadyEnriched) report.preserved++;
|
|
480
|
+
const keys = [sourceKey, ...collectEntityKeys(record, profile)];
|
|
481
|
+
const preEnrichShape = !!profile.enrich && record[enrichTimestampField] == null;
|
|
482
|
+
const identityKeys = !declaresIdentityKeys || preEnrichShape ? void 0 : collectAssociationKeys(record, profile);
|
|
483
|
+
const data = { ...record };
|
|
484
|
+
for (const k of Object.keys(data)) {
|
|
485
|
+
if (k.startsWith("_")) delete data[k];
|
|
486
|
+
}
|
|
487
|
+
const searchable_text = searchablePaths ? extractSearchableFromPaths(record, searchablePaths).text : void 0;
|
|
488
|
+
try {
|
|
489
|
+
const res = await upsertRecord(
|
|
490
|
+
{
|
|
491
|
+
type,
|
|
492
|
+
data,
|
|
493
|
+
keys,
|
|
494
|
+
identity_keys: identityKeys,
|
|
495
|
+
searchable_text,
|
|
496
|
+
sources: {
|
|
497
|
+
[sourceKey]: {
|
|
498
|
+
last_synced_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
499
|
+
metadata: { source: profile.platform }
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
tags: ["synced", profile.platform],
|
|
503
|
+
embed: embedFlag
|
|
504
|
+
},
|
|
505
|
+
// Sync must REPLACE: if a field vanished at the source (phone
|
|
506
|
+
// number removed, Gmail thread archived) it must also vanish
|
|
507
|
+
// from memory. The default merge behaviour is correct for
|
|
508
|
+
// interactive `mem add` / `mem update`, wrong for sync.
|
|
509
|
+
//
|
|
510
|
+
// ...unless this row is already enriched, in which case we are the
|
|
511
|
+
// thin half of the record and must not speak for the whole of it.
|
|
512
|
+
// See the "NEVER DEGRADE" comment above.
|
|
513
|
+
alreadyEnriched ? { embed: embedFlag, replace: false, preserveDerived: true } : { embed: embedFlag, replace: true }
|
|
514
|
+
);
|
|
515
|
+
report.sourceKeysSeen.push(sourceKey);
|
|
516
|
+
if (res.action === "inserted") {
|
|
517
|
+
report.inserted++;
|
|
518
|
+
if (opts.capturePerAction) report.inserts.push(record);
|
|
519
|
+
} else {
|
|
520
|
+
report.updated++;
|
|
521
|
+
if (opts.capturePerAction) report.updates.push(record);
|
|
522
|
+
}
|
|
523
|
+
} catch {
|
|
524
|
+
report.skipped++;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return report;
|
|
528
|
+
}
|
|
529
|
+
function deriveEmbedFlag(profile) {
|
|
530
|
+
if (profile.memory && typeof profile.memory.embed === "boolean") return profile.memory.embed;
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
function deriveIdentityPrefix(dotPath) {
|
|
534
|
+
const lower = dotPath.toLowerCase();
|
|
535
|
+
if (lower.includes("email")) return "email";
|
|
536
|
+
if (lower.includes("phone")) return "phone";
|
|
537
|
+
if (lower.includes("domain")) return "domain";
|
|
538
|
+
return "id";
|
|
539
|
+
}
|
|
540
|
+
var EMAIL_RE = /[A-Za-z0-9._%+'-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
|
|
541
|
+
function identityValuesFor(prefix, raw, opts = {}) {
|
|
542
|
+
if (raw === null || raw === void 0 || typeof raw === "object") return [];
|
|
543
|
+
const s = String(raw);
|
|
544
|
+
if (prefix === "email") {
|
|
545
|
+
const found = (s.match(EMAIL_RE) ?? []).map((e) => e.toLowerCase());
|
|
546
|
+
if (found.length > 0 || !opts.fallbackToScalar) return found;
|
|
547
|
+
}
|
|
548
|
+
const v = s.toLowerCase().trim();
|
|
549
|
+
return v ? [v] : [];
|
|
550
|
+
}
|
|
551
|
+
function tokenizeIdentityPath(path5) {
|
|
552
|
+
const tokens = [];
|
|
553
|
+
const re = /([^.[\]]+)|\[([^\]]*)\]/g;
|
|
554
|
+
let m;
|
|
555
|
+
while ((m = re.exec(path5)) !== null) {
|
|
556
|
+
if (m[1] !== void 0) {
|
|
557
|
+
tokens.push({ type: "field", name: m[1] });
|
|
558
|
+
} else {
|
|
559
|
+
const inner = m[2];
|
|
560
|
+
if (inner === "") tokens.push({ type: "wild" });
|
|
561
|
+
else if (/^\d+$/.test(inner)) tokens.push({ type: "index", i: Number(inner) });
|
|
562
|
+
else {
|
|
563
|
+
const eq = inner.indexOf("=");
|
|
564
|
+
if (eq > 0) {
|
|
565
|
+
const field = inner.slice(0, eq).trim();
|
|
566
|
+
const value = inner.slice(eq + 1).trim().replace(/^['"]|['"]$/g, "");
|
|
567
|
+
tokens.push({ type: "filter", field, value });
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return tokens;
|
|
573
|
+
}
|
|
574
|
+
function resolveIdentityPath(root, path5) {
|
|
575
|
+
let frontier = [root];
|
|
576
|
+
for (const tok of tokenizeIdentityPath(path5)) {
|
|
577
|
+
const next = [];
|
|
578
|
+
for (const cur of frontier) {
|
|
579
|
+
if (cur === null || cur === void 0) continue;
|
|
580
|
+
if (tok.type === "field") {
|
|
581
|
+
if (Array.isArray(cur)) {
|
|
582
|
+
if (/^\d+$/.test(tok.name)) next.push(cur[Number(tok.name)]);
|
|
583
|
+
} else if (typeof cur === "object") {
|
|
584
|
+
next.push(cur[tok.name]);
|
|
585
|
+
}
|
|
586
|
+
} else if (tok.type === "index") {
|
|
587
|
+
if (Array.isArray(cur)) next.push(cur[tok.i]);
|
|
588
|
+
} else if (tok.type === "wild") {
|
|
589
|
+
if (Array.isArray(cur)) next.push(...cur);
|
|
590
|
+
} else {
|
|
591
|
+
if (Array.isArray(cur)) {
|
|
592
|
+
for (const el of cur) {
|
|
593
|
+
if (el && typeof el === "object" && String(el[tok.field] ?? "").toLowerCase() === tok.value.toLowerCase()) {
|
|
594
|
+
next.push(el);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
frontier = next;
|
|
601
|
+
}
|
|
602
|
+
return frontier;
|
|
603
|
+
}
|
|
604
|
+
function keysForEntry(record, prefix, path5) {
|
|
605
|
+
if (!prefix || !path5) return [];
|
|
606
|
+
const out = [];
|
|
607
|
+
for (const raw of resolveIdentityPath(record, path5)) {
|
|
608
|
+
for (const value of identityValuesFor(prefix, raw)) out.push(`${prefix}:${value}`);
|
|
609
|
+
}
|
|
610
|
+
return out;
|
|
611
|
+
}
|
|
612
|
+
function normalizePrefix(prefix) {
|
|
613
|
+
const p2 = prefix.trim().toLowerCase();
|
|
614
|
+
return /^[a-z0-9_]+$/.test(p2) ? p2 : null;
|
|
615
|
+
}
|
|
616
|
+
function dedupe(keys) {
|
|
617
|
+
const seen = /* @__PURE__ */ new Set();
|
|
618
|
+
const out = [];
|
|
619
|
+
for (const k of keys) {
|
|
620
|
+
if (seen.has(k)) continue;
|
|
621
|
+
seen.add(k);
|
|
622
|
+
out.push(k);
|
|
623
|
+
}
|
|
624
|
+
return out;
|
|
625
|
+
}
|
|
626
|
+
function resolveEntityIdentity(record, identityKey) {
|
|
627
|
+
if (!identityKey) return null;
|
|
628
|
+
const prefix = deriveIdentityPrefix(identityKey);
|
|
629
|
+
const values = dedupe(
|
|
630
|
+
resolveIdentityPath(record, identityKey).flatMap((raw) => identityValuesFor(prefix, raw, { fallbackToScalar: true }))
|
|
631
|
+
);
|
|
632
|
+
const value = values.length === 1 ? values[0] : null;
|
|
633
|
+
return { prefix, values, value, key: value ? `${prefix}:${value}` : null };
|
|
634
|
+
}
|
|
635
|
+
function normalizeEntityIdentityValue(identityKey, raw) {
|
|
636
|
+
const values = dedupe(identityValuesFor(deriveIdentityPrefix(identityKey), raw, { fallbackToScalar: true }));
|
|
637
|
+
return values.length === 1 ? values[0] : null;
|
|
638
|
+
}
|
|
639
|
+
function collectEntityKeys(record, profile) {
|
|
640
|
+
const identity = resolveEntityIdentity(record, profile.identityKey);
|
|
641
|
+
return identity?.key ? [identity.key] : [];
|
|
642
|
+
}
|
|
643
|
+
function collectAssociationKeys(record, profile) {
|
|
644
|
+
const out = [];
|
|
645
|
+
for (const entry of profile.identityKeys ?? []) {
|
|
646
|
+
if (!entry || !entry.path || !entry.prefix) continue;
|
|
647
|
+
const prefix = normalizePrefix(entry.prefix);
|
|
648
|
+
if (!prefix) continue;
|
|
649
|
+
out.push(...keysForEntry(record, prefix, entry.path));
|
|
650
|
+
}
|
|
651
|
+
return dedupe(out);
|
|
652
|
+
}
|
|
653
|
+
function collectIdentityKeys(record, profile) {
|
|
654
|
+
return dedupe([...collectEntityKeys(record, profile), ...collectAssociationKeys(record, profile)]);
|
|
655
|
+
}
|
|
656
|
+
|
|
390
657
|
// src/commands/mem/migrate.ts
|
|
391
658
|
async function memMigrateCommand(flags) {
|
|
392
659
|
requireMemoryInit();
|
|
@@ -472,10 +739,10 @@ async function memMigrateCommand(flags) {
|
|
|
472
739
|
const keys = [sourceKey];
|
|
473
740
|
let identityValueNorm = null;
|
|
474
741
|
if (identityKey) {
|
|
475
|
-
const
|
|
476
|
-
if (
|
|
477
|
-
identityValueNorm =
|
|
478
|
-
keys.push(
|
|
742
|
+
const identity = resolveEntityIdentity(hydrated, identityKey);
|
|
743
|
+
if (identity?.key) {
|
|
744
|
+
identityValueNorm = identity.value;
|
|
745
|
+
keys.push(identity.key);
|
|
479
746
|
}
|
|
480
747
|
}
|
|
481
748
|
let mergeTarget = false;
|
|
@@ -658,7 +925,7 @@ async function buildIdentityMap(backend, type, identityKey) {
|
|
|
658
925
|
for (const row of res.rows) {
|
|
659
926
|
const ident = row.ident;
|
|
660
927
|
if (ident === null || ident === void 0 || typeof ident !== "string") continue;
|
|
661
|
-
const norm = ident
|
|
928
|
+
const norm = normalizeEntityIdentityValue(identityKey, ident);
|
|
662
929
|
if (!norm) continue;
|
|
663
930
|
if (!map.has(norm)) {
|
|
664
931
|
map.set(norm, {
|
|
@@ -724,13 +991,6 @@ function resolveBuiltinProfilePath(platform, model) {
|
|
|
724
991
|
const candidate = path4.join(dir, platform, `${model}.json`);
|
|
725
992
|
return fs4.existsSync(candidate) ? candidate : null;
|
|
726
993
|
}
|
|
727
|
-
function deriveIdentityPrefix(path5) {
|
|
728
|
-
const lower = path5.toLowerCase();
|
|
729
|
-
if (lower.includes("email")) return "email";
|
|
730
|
-
if (lower.includes("phone")) return "phone";
|
|
731
|
-
if (lower.includes("domain")) return "domain";
|
|
732
|
-
return "id";
|
|
733
|
-
}
|
|
734
994
|
|
|
735
995
|
export {
|
|
736
996
|
readProfile,
|
|
@@ -753,6 +1013,11 @@ export {
|
|
|
753
1013
|
dropTable,
|
|
754
1014
|
countRecords,
|
|
755
1015
|
deleteDatabase,
|
|
1016
|
+
extractSearchableFromPaths,
|
|
1017
|
+
getSearchablePaths,
|
|
1018
|
+
writePageToMemory,
|
|
1019
|
+
resolveEntityIdentity,
|
|
1020
|
+
collectIdentityKeys,
|
|
756
1021
|
loadBuiltinProfile,
|
|
757
1022
|
listBuiltinProfiles,
|
|
758
1023
|
memMigrateCommand,
|