@withone/cli 1.54.0 → 1.55.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
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
<a href="https://withone.ai/knowledge"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fapi.withone.ai%2Fopen%2Fcount%2Ftools" alt="tools"></a>
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
|
-
One gives your AI agent authenticated access to
|
|
27
|
+
One gives your AI agent authenticated access to 600+ platforms - Gmail, Slack, Shopify, HubSpot, Stripe, Notion, and everything else - through a single interface. No API keys to juggle, no OAuth flows to build, no request formats to memorize. Connect a platform once, and your agent can search for actions, read the docs, and execute API calls in seconds.
|
|
28
28
|
|
|
29
29
|
## Install
|
|
30
30
|
|
|
@@ -48,7 +48,10 @@ one login # Opens browser for authentication (global or per-directo
|
|
|
48
48
|
one logout # Clear credentials (with scope picker and confirmation)
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Requires Node.js 18+.
|
|
51
|
+
Requires Node.js 18+. `one sync` additionally needs Node 20+, because its
|
|
52
|
+
local SQLite engine (`better-sqlite3`, an optional dependency) ships prebuilt
|
|
53
|
+
binaries only for Node 20 and above. On Node 18 every other command works
|
|
54
|
+
normally; `one sync` reports that the engine isn't installed.
|
|
52
55
|
|
|
53
56
|
## Quick start
|
|
54
57
|
|
|
@@ -241,7 +244,7 @@ Shows the connection details and asks for confirmation before deleting. Use `--f
|
|
|
241
244
|
|
|
242
245
|
### `one platforms`
|
|
243
246
|
|
|
244
|
-
Browse all
|
|
247
|
+
Browse all 600+ available platforms.
|
|
245
248
|
|
|
246
249
|
```bash
|
|
247
250
|
one platforms # all platforms
|
|
@@ -523,7 +523,9 @@ async function writePageToMemory(profile, records, opts = {}) {
|
|
|
523
523
|
const searchablePaths = getSearchablePaths(profile);
|
|
524
524
|
const declaresIdentityKeys = (profile.identityKeys?.length ?? 0) > 0;
|
|
525
525
|
const enrichTimestampField = profile.enrich?.timestampField ?? "_enriched_at";
|
|
526
|
-
for (const
|
|
526
|
+
for (const rawRecord of records) {
|
|
527
|
+
const derived = deriveFields(rawRecord, profile.derive);
|
|
528
|
+
const record = Object.keys(derived).length > 0 ? { ...rawRecord, ...derived } : rawRecord;
|
|
527
529
|
report.attempted++;
|
|
528
530
|
const externalId = getByDotPath(record, profile.idField);
|
|
529
531
|
if (externalId === void 0 || externalId === null || externalId === "") {
|
|
@@ -608,6 +610,24 @@ function identityValuesFor(prefix, raw, opts = {}) {
|
|
|
608
610
|
const v = s.toLowerCase().trim();
|
|
609
611
|
return v ? [v] : [];
|
|
610
612
|
}
|
|
613
|
+
function deriveFields(record, derive) {
|
|
614
|
+
const out = {};
|
|
615
|
+
if (!derive) return out;
|
|
616
|
+
for (const [field, spec] of Object.entries(derive)) {
|
|
617
|
+
const { path: path5, extract } = typeof spec === "string" ? { path: spec, extract: void 0 } : spec;
|
|
618
|
+
if (!path5) continue;
|
|
619
|
+
const values = resolveIdentityPath(record, path5).filter((v) => v !== null && v !== void 0 && typeof v !== "object");
|
|
620
|
+
if (values.length === 0) continue;
|
|
621
|
+
if (extract === "email") {
|
|
622
|
+
const emails = values.flatMap((v) => identityValuesFor("email", v));
|
|
623
|
+
if (emails.length === 0) continue;
|
|
624
|
+
out[field] = emails[0];
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
out[field] = values[0];
|
|
628
|
+
}
|
|
629
|
+
return out;
|
|
630
|
+
}
|
|
611
631
|
function tokenizeIdentityPath(path5) {
|
|
612
632
|
const tokens = [];
|
|
613
633
|
const re = /([^.[\]]+)|\[([^\]]*)\]/g;
|
package/dist/index.js
CHANGED
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
writeDraftProfile,
|
|
67
67
|
writePageToMemory,
|
|
68
68
|
writeProfile
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-FS4HAKZ6.js";
|
|
70
70
|
import {
|
|
71
71
|
getByDotPath
|
|
72
72
|
} from "./chunk-44CV5IMX.js";
|
|
@@ -1104,7 +1104,7 @@ async function loginCommand() {
|
|
|
1104
1104
|
console.log(pc15.cyan(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1105
1105
|
console.log(pc15.cyan(" \u2502"));
|
|
1106
1106
|
console.log(pc15.cyan(" \u2502 The One CLI (`one`) is now installed on this machine. It"));
|
|
1107
|
-
console.log(pc15.cyan(" \u2502 lets you interact with
|
|
1107
|
+
console.log(pc15.cyan(" \u2502 lets you interact with 600+ third-party platforms (Gmail,"));
|
|
1108
1108
|
console.log(pc15.cyan(" \u2502 Slack, Shopify, HubSpot, Stripe, GitHub, etc.) through"));
|
|
1109
1109
|
console.log(pc15.cyan(" \u2502 their APIs. Whenever you need to interact with any"));
|
|
1110
1110
|
console.log(pc15.cyan(" \u2502 third-party platform or external service, use the `one`"));
|
|
@@ -1711,7 +1711,7 @@ function printOnboardingPrompt() {
|
|
|
1711
1711
|
console.log(pc2.cyan(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1712
1712
|
console.log(pc2.cyan(" \u2502"));
|
|
1713
1713
|
console.log(pc2.cyan(" \u2502 The One CLI (`one`) is now installed on this machine. It"));
|
|
1714
|
-
console.log(pc2.cyan(" \u2502 lets you interact with
|
|
1714
|
+
console.log(pc2.cyan(" \u2502 lets you interact with 600+ third-party platforms (Gmail,"));
|
|
1715
1715
|
console.log(pc2.cyan(" \u2502 Slack, Shopify, HubSpot, Stripe, GitHub, etc.) through"));
|
|
1716
1716
|
console.log(pc2.cyan(" \u2502 their APIs. Whenever you need to interact with any"));
|
|
1717
1717
|
console.log(pc2.cyan(" \u2502 third-party platform or external service, use the `one`"));
|
|
@@ -1888,7 +1888,7 @@ async function promptConnectIntegrations(apiKey, connParams) {
|
|
|
1888
1888
|
label: i.label,
|
|
1889
1889
|
hint: i.hint
|
|
1890
1890
|
})),
|
|
1891
|
-
{ value: "more", label: "Browse all
|
|
1891
|
+
{ value: "more", label: "Browse all 600+ platforms" },
|
|
1892
1892
|
{ value: "skip", label: "Skip for now", hint: "you can always run one add later" }
|
|
1893
1893
|
];
|
|
1894
1894
|
const message = first ? "Connect your first integration?" : "Connect another?";
|
|
@@ -5888,6 +5888,21 @@ async function enrichPhase(api, db, config2, model, idField, connectionKey, plat
|
|
|
5888
5888
|
const duration = elapsed < 1e3 ? `${elapsed}ms` : elapsed < 6e4 ? `${(elapsed / 1e3).toFixed(1)}s` : `${Math.floor(elapsed / 6e4)}m ${Math.floor(elapsed % 6e4 / 1e3)}s`;
|
|
5889
5889
|
return { enriched, skipped, rateLimited, total, duration };
|
|
5890
5890
|
}
|
|
5891
|
+
async function enrichOneForPreview(api, profile, record, connectionKey) {
|
|
5892
|
+
const config2 = profile.enrich;
|
|
5893
|
+
if (!config2) return null;
|
|
5894
|
+
try {
|
|
5895
|
+
const detailAction = (await resolveActionDetails(api, config2.actionId)).details;
|
|
5896
|
+
const detail = await enrichSingleRow(api, detailAction, config2, record, connectionKey, profile.platform);
|
|
5897
|
+
if (!detail) return null;
|
|
5898
|
+
let enrichedData = detail;
|
|
5899
|
+
if (config2.fields && config2.fields.length > 0) enrichedData = pickFields(enrichedData, config2.fields);
|
|
5900
|
+
if (config2.exclude && config2.exclude.length > 0) stripExcludedFields(enrichedData, config2.exclude);
|
|
5901
|
+
return config2.merge !== false ? deepMerge(record, enrichedData) : { ...enrichedData, [profile.idField]: record[profile.idField] };
|
|
5902
|
+
} catch {
|
|
5903
|
+
return null;
|
|
5904
|
+
}
|
|
5905
|
+
}
|
|
5891
5906
|
async function enrichSingleRow(api, detailAction, config2, row, connectionKey, platform) {
|
|
5892
5907
|
const pathVars = interpolateParams(config2.pathVars, row);
|
|
5893
5908
|
const queryParams = interpolateParams(config2.queryParams, row);
|
|
@@ -6879,7 +6894,14 @@ async function testSyncProfile(api, profile) {
|
|
|
6879
6894
|
}));
|
|
6880
6895
|
report.sample = first;
|
|
6881
6896
|
report.samples = records.slice(0, SEARCHABLE_SAMPLE_SIZE);
|
|
6882
|
-
|
|
6897
|
+
if (profile.enrich && (profile.identityKeys?.length ?? 0) > 0 && report.samples.length > 0) {
|
|
6898
|
+
const merged = await enrichOneForPreview(api, profile, report.samples[0], connectionKey);
|
|
6899
|
+
if (merged) {
|
|
6900
|
+
const preview = buildIdentityKeysPreview([merged], profile);
|
|
6901
|
+
if (preview) report.identityKeysPreview = { ...preview, previewedAfterEnrich: true };
|
|
6902
|
+
}
|
|
6903
|
+
}
|
|
6904
|
+
report.identityKeysPreview ??= buildIdentityKeysPreview(report.samples, profile);
|
|
6883
6905
|
report.ok = checks.every((c) => c.ok);
|
|
6884
6906
|
return report;
|
|
6885
6907
|
}
|
|
@@ -8379,7 +8401,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
8379
8401
|
` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
|
|
8380
8402
|
`
|
|
8381
8403
|
);
|
|
8382
|
-
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-
|
|
8404
|
+
const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-37A463L6.js");
|
|
8383
8405
|
await memMigrateCommand3({ platform, yes: true });
|
|
8384
8406
|
return;
|
|
8385
8407
|
}
|
|
@@ -8388,7 +8410,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
|
|
|
8388
8410
|
initialValue: true
|
|
8389
8411
|
});
|
|
8390
8412
|
if (p7.isCancel(shouldMigrate) || !shouldMigrate) return;
|
|
8391
|
-
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-
|
|
8413
|
+
const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-37A463L6.js");
|
|
8392
8414
|
await memMigrateCommand2({ platform, yes: true });
|
|
8393
8415
|
}
|
|
8394
8416
|
async function syncSuggestSearchableCommand(platformModel, options = {}) {
|
|
@@ -10036,7 +10058,7 @@ Before using any feature, read its guide section first: \`one guide actions\`, \
|
|
|
10036
10058
|
|
|
10037
10059
|
## Features
|
|
10038
10060
|
|
|
10039
|
-
### 1. Actions \u2014 Execute API calls on
|
|
10061
|
+
### 1. Actions \u2014 Execute API calls on 600+ platforms
|
|
10040
10062
|
Search for actions, read their docs, and execute them. This is the core workflow.
|
|
10041
10063
|
|
|
10042
10064
|
**Quick start:**
|
|
@@ -10859,6 +10881,30 @@ Enrichment runs after list sync completes (Phase 2), not inline. It's inherently
|
|
|
10859
10881
|
|
|
10860
10882
|
**Limitation:** Each profile supports one enrich action. If you need multiple enrichments (e.g. both summary and transcript from Fathom), create a second profile/model for the second enrichment.
|
|
10861
10883
|
|
|
10884
|
+
## Derived fields (\`derive\`)
|
|
10885
|
+
|
|
10886
|
+
Add flat, queryable top-level fields computed from paths already in the record \u2014 no shell, no \`jq\`:
|
|
10887
|
+
|
|
10888
|
+
\`\`\`json
|
|
10889
|
+
{
|
|
10890
|
+
"derive": {
|
|
10891
|
+
"from_email": {
|
|
10892
|
+
"path": "messages[0].payload.headers[name=From].value",
|
|
10893
|
+
"extract": "email"
|
|
10894
|
+
},
|
|
10895
|
+
"company": "organization.name"
|
|
10896
|
+
}
|
|
10897
|
+
}
|
|
10898
|
+
\`\`\`
|
|
10899
|
+
|
|
10900
|
+
- Paths use the same resolver as \`identityKeys\`, so \`[]\` wildcards, \`[0]\` indexes and \`[name=From]\` filters all work
|
|
10901
|
+
- \`extract: "email"\` pulls the address out of a display-name header (\`"Jane <jane@acme.com>"\` \u2192 \`jane@acme.com\`), lowercased
|
|
10902
|
+
- A path resolving to nothing **omits** the field rather than writing null, so \`--where\` filters behave
|
|
10903
|
+
- A path resolving to several values takes the first \u2014 it's a flat field by definition, and the path syntax lets you be specific
|
|
10904
|
+
- Applied on both sync phases, so an enriching profile gets the same field whether the record came from the list or the detail pass
|
|
10905
|
+
|
|
10906
|
+
**Prefer \`derive\` over \`transform\` for extracting a field.** \`transform\` spawns \`sh -c\`, so it needs \`jq\` (or whatever you invoke) on PATH and does nothing on Windows. \`derive\` is pure and works everywhere \u2014 which is why the built-in \`gmail/gmailThreads\` profile uses it for \`from_email\`. Reach for \`transform\` when you need real computation, not field extraction.
|
|
10907
|
+
|
|
10862
10908
|
## Record Transform
|
|
10863
10909
|
|
|
10864
10910
|
Pipe records through any shell command or flow between fetch and store. The command receives a JSON array on stdin and must return a JSON array on stdout.
|
|
@@ -10933,7 +10979,9 @@ Two ways to tag a record with a cross-platform identifier (e.g. email), dependin
|
|
|
10933
10979
|
]}
|
|
10934
10980
|
\`\`\`
|
|
10935
10981
|
|
|
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.
|
|
10982
|
+
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.
|
|
10983
|
+
|
|
10984
|
+
\`sync test\` previews how many identity keys each record resolves. For an **enriching** profile the participant paths live in the detail payload, so \`sync test\` spends one detail call on the first sample and previews against the merged shape \u2014 you see the keys a real sync would write, not zero plus a promise. If that call can't be made (rate limit, permissions), it falls back to the list-shape preview and says the keys resolve after enrichment.
|
|
10937
10985
|
|
|
10938
10986
|
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
10987
|
|
|
@@ -11229,7 +11277,7 @@ function buildStep1() {
|
|
|
11229
11277
|
nextCommand: "one onboard --step 2",
|
|
11230
11278
|
message: `# One CLI \u2014 Agent Onboarding
|
|
11231
11279
|
|
|
11232
|
-
You now have access to the One CLI. It connects you to
|
|
11280
|
+
You now have access to the One CLI. It connects you to 600+ platforms
|
|
11233
11281
|
(Gmail, Slack, Stripe, Notion, etc.) \u2014 you'll learn the details shortly.
|
|
11234
11282
|
|
|
11235
11283
|
IMPORTANT: Your only task right now is to send the message below to the
|
|
@@ -11239,7 +11287,7 @@ Do not offer demos yet. Just send this message and wait for their reply:
|
|
|
11239
11287
|
---
|
|
11240
11288
|
|
|
11241
11289
|
I just got access to the One CLI \u2014 it connects me to your platforms like
|
|
11242
|
-
Gmail, Slack, Stripe, and
|
|
11290
|
+
Gmail, Slack, Stripe, and 600+ others so I can work with them directly.
|
|
11243
11291
|
I'll show you what I can do in a moment.
|
|
11244
11292
|
|
|
11245
11293
|
First, one quick setup step: right now only this conversation knows about
|
|
@@ -11268,7 +11316,7 @@ If they declined, skip this section.
|
|
|
11268
11316
|
## One CLI \u2014 Platform Integrations
|
|
11269
11317
|
|
|
11270
11318
|
The One CLI (\`one\`) is installed and configured on this machine. It is a
|
|
11271
|
-
command-line tool that gives AI agents the ability to interact with
|
|
11319
|
+
command-line tool that gives AI agents the ability to interact with 600+
|
|
11272
11320
|
third-party platforms (Gmail, Slack, Shopify, HubSpot, Stripe, GitHub,
|
|
11273
11321
|
Notion, Salesforce, etc.) through a single, unified interface.
|
|
11274
11322
|
|
|
@@ -11363,7 +11411,7 @@ function buildStep3(connections) {
|
|
|
11363
11411
|
The user can connect any of these popular platforms:
|
|
11364
11412
|
Gmail, Google Calendar, Slack, Notion, Shopify, Stripe, HubSpot, GitHub,
|
|
11365
11413
|
Salesforce, QuickBooks, Asana, Jira, Linear, Intercom, Zendesk, Twilio,
|
|
11366
|
-
and
|
|
11414
|
+
and 600+ more. Run \`one platforms\` for the full list.`);
|
|
11367
11415
|
sections.push("## Onboarding complete!\n\nYou're all set. Use `one --agent guide` any time you need the full reference.");
|
|
11368
11416
|
return {
|
|
11369
11417
|
step: 3,
|
|
@@ -11394,7 +11442,7 @@ platform before you can start using actions. Suggest they run:
|
|
|
11394
11442
|
one add slack
|
|
11395
11443
|
one add <any-platform>
|
|
11396
11444
|
|
|
11397
|
-
Run \`one platforms\` to see all
|
|
11445
|
+
Run \`one platforms\` to see all 600+ available platforms.`;
|
|
11398
11446
|
}
|
|
11399
11447
|
const header = `## Current State
|
|
11400
11448
|
|
|
@@ -11831,7 +11879,7 @@ silenceWarningsInAgentMode();
|
|
|
11831
11879
|
var require4 = createRequire3(import.meta.url);
|
|
11832
11880
|
var { version } = require4("../package.json");
|
|
11833
11881
|
var program = new Command();
|
|
11834
|
-
program.name("one").option("--agent", "Machine-readable JSON output (no colors, spinners, or prompts)").description(`One CLI \u2014 Connect AI agents to
|
|
11882
|
+
program.name("one").option("--agent", "Machine-readable JSON output (no colors, spinners, or prompts)").description(`One CLI \u2014 Connect AI agents to 600+ platforms through one interface.
|
|
11835
11883
|
|
|
11836
11884
|
Setup:
|
|
11837
11885
|
one login Authenticate via browser (opens app.withone.ai)
|
|
@@ -11903,7 +11951,7 @@ program.name("one").option("--agent", "Machine-readable JSON output (no colors,
|
|
|
11903
11951
|
-d '{"to":"j@example.com","subject":"Hello","body":"Hi!","connectionKey":"live::gmail::default::abc123"}'
|
|
11904
11952
|
|
|
11905
11953
|
Platform names are lowercase; multi-word names use dashes (e.g. hubspot, ship-station, google-calendar).
|
|
11906
|
-
Run 'one platforms' to browse all
|
|
11954
|
+
Run 'one platforms' to browse all 600+ available platforms.`).version(version);
|
|
11907
11955
|
var updateCheckPromise;
|
|
11908
11956
|
program.hook("preAction", (thisCommand, actionCommand) => {
|
|
11909
11957
|
const opts = program.opts();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@withone/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.0",
|
|
4
4
|
"description": "CLI for managing One",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
38
|
"@electric-sql/pglite": "^0.2.17",
|
|
39
|
-
"better-sqlite3": "^11.
|
|
39
|
+
"better-sqlite3": "^12.11.1",
|
|
40
40
|
"pg": "^8.20.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
{ "prefix": "email", "path": "messages[].payload.headers[name=Cc].value" },
|
|
22
22
|
{ "prefix": "email", "path": "messages[].payload.headers[name=Bcc].value" }
|
|
23
23
|
],
|
|
24
|
+
"derive": {
|
|
25
|
+
"from_email": {
|
|
26
|
+
"path": "messages[0].payload.headers[name=From].value",
|
|
27
|
+
"extract": "email"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
24
30
|
"enrich": {
|
|
25
31
|
"actionId": "conn_mod_def::GJ3ok0Eq0R8::AAzgZVLqTg2iBuITKpJLZg",
|
|
26
32
|
"pathVars": { "userId": "me", "id": "{id}" },
|
package/skills/one/SKILL.md
CHANGED
|
@@ -20,7 +20,7 @@ description: |
|
|
|
20
20
|
|
|
21
21
|
# One CLI
|
|
22
22
|
|
|
23
|
-
You have access to the One CLI which lets you interact with
|
|
23
|
+
You have access to the One CLI which lets you interact with 600+ third-party platforms through their APIs. Always include the `--agent` flag right after `one` for structured JSON output.
|
|
24
24
|
|
|
25
25
|
If the user wants a separate API key / connections for a specific project (vs. their default), walk them through running `one init` from that project folder and picking the "project" scope — see `references/scoping.md`. For monorepo subprojects (where a parent already has `.git`/`package.json`), have them `mkdir .one` in the subproject first so the config is keyed to that dir, not the monorepo root.
|
|
26
26
|
|
|
@@ -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
|
+
**Extracting a flat field? Use `derive`, not `transform`.** `derive` computes top-level fields from paths already in the record (`"derive": { "from_email": { "path": "messages[0].payload.headers[name=From].value", "extract": "email" } }`), using the same path syntax as `identityKeys`. `transform` spawns `sh -c`, so it needs `jq` on PATH and silently does nothing on Windows — never put one in a profile you intend to share. A path that resolves to nothing omits the field rather than writing null.
|
|
315
|
+
|
|
314
316
|
**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
317
|
|
|
316
318
|
**Cross-platform identity on a profile.** Two separate fields, and picking the wrong one silently mangles data:
|