@withone/cli 1.53.0 → 1.54.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.
@@ -143,6 +143,15 @@ function loadBuiltinProfile(platform, model) {
143
143
  return null;
144
144
  }
145
145
  }
146
+ var CAPABILITY_FIELDS = ["identityKeys", "identityKey", "enrich", "dateFilter", "memory"];
147
+ function findMissingBuiltinCapabilities(platform, model, installed) {
148
+ if (!installed) return [];
149
+ const builtin = loadBuiltinProfile(platform, model);
150
+ if (!builtin) return [];
151
+ return CAPABILITY_FIELDS.filter(
152
+ (field) => builtin[field] !== void 0 && installed[field] === void 0
153
+ );
154
+ }
146
155
  function listBuiltinProfiles(platform) {
147
156
  const dir = getProfilesDir();
148
157
  if (!dir) return [];
@@ -1070,6 +1079,7 @@ export {
1070
1079
  resolveEntityIdentity,
1071
1080
  collectIdentityKeys,
1072
1081
  loadBuiltinProfile,
1082
+ findMissingBuiltinCapabilities,
1073
1083
  listBuiltinProfiles,
1074
1084
  memMigrateCommand,
1075
1085
  buildIdentityMap,
package/dist/index.js CHANGED
@@ -45,6 +45,7 @@ import {
45
45
  ensureTable,
46
46
  evolveSchema,
47
47
  extractSearchableFromPaths,
48
+ findMissingBuiltinCapabilities,
48
49
  generateTemplate,
49
50
  getDatabaseSize,
50
51
  getSearchablePaths,
@@ -65,7 +66,7 @@ import {
65
66
  writeDraftProfile,
66
67
  writePageToMemory,
67
68
  writeProfile
68
- } from "./chunk-IKYXS7EI.js";
69
+ } from "./chunk-XN4ZWMLX.js";
69
70
  import {
70
71
  getByDotPath
71
72
  } from "./chunk-44CV5IMX.js";
@@ -7829,7 +7830,12 @@ async function syncProfilesCommand(platform) {
7829
7830
  model: p10.model,
7830
7831
  description: p10.description,
7831
7832
  hasEnrich: !!p10.enrich,
7832
- hasIdentityKey: !!p10.identityKey
7833
+ // `identityKey` (singular) is the entity-merge key; `identityKeys`
7834
+ // (plural, #167) are non-merging association keys. Reading only the
7835
+ // singular reported hasIdentityKey:false for gmail/gcal/fathom — the
7836
+ // three profiles the plural form was added for. (#129/#130)
7837
+ hasIdentityKey: !!p10.identityKey || !!p10.identityKeys,
7838
+ hasIdentityKeys: !!p10.identityKeys
7833
7839
  })),
7834
7840
  total: profiles.length,
7835
7841
  _hint: profiles.length > 0 ? "Use a built-in profile: one --agent sync init <platform> <model>" : "No built-in profiles found. Use sync init to auto-infer from action knowledge."
@@ -7846,7 +7852,7 @@ async function syncProfilesCommand(platform) {
7846
7852
  for (const p10 of profiles) {
7847
7853
  const extras = [];
7848
7854
  if (p10.enrich) extras.push("enrich");
7849
- if (p10.identityKey) extras.push("identity");
7855
+ if (p10.identityKey || p10.identityKeys) extras.push("identity");
7850
7856
  if (p10.dateFilter) extras.push("incremental");
7851
7857
  const tags = extras.length > 0 ? ` ${pc9.dim(`[${extras.join(", ")}]`)}` : "";
7852
7858
  console.log(` ${pc9.bold(`${p10.platform}/${p10.model}`.padEnd(35))} ${p10.description}${tags}`);
@@ -8158,6 +8164,15 @@ async function syncRunCommand(platform, options) {
8158
8164
  if (!options.dryRun) {
8159
8165
  await maybeAutoMigrateLegacy(platform, toSync.map((p10) => p10.model));
8160
8166
  }
8167
+ const profileDrift = toSync.map((p10) => ({ model: p10.model, missing: findMissingBuiltinCapabilities(platform, p10.model, p10) })).filter((d) => d.missing.length > 0);
8168
+ if (profileDrift.length > 0 && !isAgentMode()) {
8169
+ for (const d of profileDrift) {
8170
+ console.log(
8171
+ ` ${pc9.yellow("!")} ${platform}/${d.model} is missing ${d.missing.map((f) => pc9.bold(f)).join(", ")} from the current built-in profile.
8172
+ Run ${pc9.bold(`one sync init ${platform} ${d.model}`)} to pick ${d.missing.length > 1 ? "them" : "it"} up.`
8173
+ );
8174
+ }
8175
+ }
8161
8176
  const results = [];
8162
8177
  for (const profile of toSync) {
8163
8178
  try {
@@ -8181,7 +8196,19 @@ async function syncRunCommand(platform, options) {
8181
8196
  }
8182
8197
  }
8183
8198
  if (isAgentMode()) {
8184
- json({ platform, results });
8199
+ json({
8200
+ platform,
8201
+ results,
8202
+ // Surfaced to agents too: a profile silently missing a capability the
8203
+ // built-in now declares is invisible in the record counts. (#129/#130)
8204
+ ...profileDrift.length > 0 ? {
8205
+ profileDrift: profileDrift.map((d) => ({
8206
+ model: d.model,
8207
+ missingFields: d.missing,
8208
+ fix: `one sync init ${platform} ${d.model}`
8209
+ }))
8210
+ } : {}
8211
+ });
8185
8212
  return;
8186
8213
  }
8187
8214
  for (const r of results) {
@@ -8352,7 +8379,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
8352
8379
  ` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
8353
8380
  `
8354
8381
  );
8355
- const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-U2MZVGU6.js");
8382
+ const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-UGDDHWGY.js");
8356
8383
  await memMigrateCommand3({ platform, yes: true });
8357
8384
  return;
8358
8385
  }
@@ -8361,7 +8388,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
8361
8388
  initialValue: true
8362
8389
  });
8363
8390
  if (p7.isCancel(shouldMigrate) || !shouldMigrate) return;
8364
- const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-U2MZVGU6.js");
8391
+ const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-UGDDHWGY.js");
8365
8392
  await memMigrateCommand2({ platform, yes: true });
8366
8393
  }
8367
8394
  async function syncSuggestSearchableCommand(platformModel, options = {}) {
@@ -10908,6 +10935,10 @@ Two ways to tag a record with a cross-platform identifier (e.g. email), dependin
10908
10935
 
10909
10936
  Each \`path\` supports \`[]\` wildcards (one key per element) and a \`[name=From]\` equality filter (e.g. Gmail \`messages[].payload.headers[name=From].value\`). \`email\`-prefixed values are email-extracted, so display-name headers (\`"Jane <jane@acme.com>"\`) and comma-lists normalize cleanly. Values are lowercased/trimmed/deduped. \`sync test\` previews how many identity keys each record resolves.
10910
10937
 
10938
+ The built-in \`gmail/gmailThreads\` profile collects From/To/**Cc/Bcc**. Gmail only returns a \`Bcc\` header on messages the authenticated user sent \u2014 it is stripped for recipients \u2014 so Bcc keys appear on your own sent threads and nowhere else.
10939
+
10940
+ **Upgrading an existing profile.** \`sync run\` reads only your on-disk profile at \`.one/sync/profiles/<platform>_<model>.json\` \u2014 it never merges built-in updates, so a profile created before a capability shipped will not have it. \`sync run\` now warns when the shipped built-in declares \`identityKeys\`, \`identityKey\`, \`enrich\`, \`dateFilter\`, or \`memory\` that your copy lacks, and \`--agent\` output carries a \`profileDrift\` array with the same information. Run \`one sync init <platform> <model>\` to pick the fields up (it patches, preserving your edits).
10941
+
10911
10942
  Query everything sharing an identity key, grouped by type:
10912
10943
 
10913
10944
  \`\`\`bash
@@ -3,7 +3,7 @@ import {
3
3
  dotPathToJsonbExpr,
4
4
  memMigrateCommand,
5
5
  reviveStringifiedJson
6
- } from "./chunk-IKYXS7EI.js";
6
+ } from "./chunk-XN4ZWMLX.js";
7
7
  import "./chunk-44CV5IMX.js";
8
8
  import "./chunk-GNSR3NYN.js";
9
9
  import "./chunk-DDCDPVJH.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.53.0",
3
+ "version": "1.54.0",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [
@@ -18,7 +18,8 @@
18
18
  "identityKeys": [
19
19
  { "prefix": "email", "path": "messages[].payload.headers[name=From].value" },
20
20
  { "prefix": "email", "path": "messages[].payload.headers[name=To].value" },
21
- { "prefix": "email", "path": "messages[].payload.headers[name=Cc].value" }
21
+ { "prefix": "email", "path": "messages[].payload.headers[name=Cc].value" },
22
+ { "prefix": "email", "path": "messages[].payload.headers[name=Bcc].value" }
22
23
  ],
23
24
  "enrich": {
24
25
  "actionId": "conn_mod_def::GJ3ok0Eq0R8::AAzgZVLqTg2iBuITKpJLZg",
@@ -311,6 +311,8 @@ Without declared paths, the default walker concatenates every string in the reco
311
311
 
312
312
  **Connections are late-bound** — profiles use `"connection": { "platform": "<name>" }`, not literal `connectionKey` strings. The key is resolved at sync time, so `one add <platform>` (re-auth) doesn't break the profile. For multi-account platforms, add `"tag": "<connection-tag>"` to disambiguate, and create the tagged connection with `one add <platform> --tag <name>`. Don't hardcode connection keys in profiles.
313
313
 
314
+ **Installed profiles do not auto-update.** `sync run` reads only `.one/sync/profiles/<platform>_<model>.json` and never merges the shipped built-in, so a profile created before a capability shipped silently lacks it — a pre-#167 gmail profile writes zero identity keys, forever, with no change in record counts. `sync run` warns when the built-in declares `identityKeys` / `identityKey` / `enrich` / `dateFilter` / `memory` that your copy lacks (agent mode: a `profileDrift` array). Fix with `one sync init <platform> <model>`, which patches rather than overwrites.
315
+
314
316
  **Cross-platform identity on a profile.** Two separate fields, and picking the wrong one silently mangles data:
315
317
 
316
318
  - `"identityKey": "properties.email"` — singular. "This record IS this entity." One dot-path; the value lands in `keys[]` and MERGES records for the same entity across platforms (HubSpot + Attio for one person collapse into a single record).