@trillioncore/cli 1.0.0-next.11 → 1.0.0-next.13
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 +17 -1
- package/dist/index.js +49 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,20 @@ The `tc` CLI signs you into Trillioncore and reads the organizations and integra
|
|
|
4
4
|
|
|
5
5
|
**Requirements:** Node.js 22+, a browser on any device, and a Trillioncore deployment with CLI device login enabled. This is a fresh v1 preview, not v0 command parity; v0 configuration is not imported.
|
|
6
6
|
|
|
7
|
+
## For agents: install and set up Trillioncore for a person
|
|
8
|
+
|
|
9
|
+
When a person asks you to install or set up Trillioncore, run these steps in order:
|
|
10
|
+
|
|
11
|
+
1. Ask whether they already have a Trillioncore account. For a new organization, ask what to call it.
|
|
12
|
+
2. New account: `npm exec --yes --package=@trillioncore/cli@next -- tc signup --organization-name '<name>'`.
|
|
13
|
+
Existing account, new organization: `... tc create-organization --name '<name>'`.
|
|
14
|
+
Existing account and organization: `... tc login`.
|
|
15
|
+
3. The command waits up to five minutes for the browser. Run it in the background with output to a file, and add `--no-browser` when the person's browser is on another machine. Read the URL and the separate eight-character code from the output and relay both to the person. They sign up with their provider (for example Google or Microsoft), confirm the organization name, enter the code, and choose access. Wait for the command to print `Signed in`.
|
|
16
|
+
4. Run `tc whoami --json` to confirm the identity.
|
|
17
|
+
5. Relay the printed `Next:` link. The person connects data sources under Integrations in the app. Then use `tc index`, `tc search`, and `tc get`.
|
|
18
|
+
|
|
19
|
+
Do not ask the person for tokens, passwords, or the verification code in chat. They enter the code only in their browser. Creating an organization makes the person its administrator; it does not approve CLI access by itself.
|
|
20
|
+
|
|
7
21
|
## Get started
|
|
8
22
|
|
|
9
23
|
Once `@next` is published and the hosted login rollout is enabled:
|
|
@@ -20,13 +34,15 @@ npm exec --yes --package=@trillioncore/cli@next -- tc logout
|
|
|
20
34
|
|
|
21
35
|
`tc login` registers a five-minute request and prints a browser URL plus a separate eight-character code. Open the URL on any device and enter the code shown in your terminal. Keep the code private and approve only a login you started. The CLI polls without a callback listener, tunnel, or copied token. After approval it verifies your identity, saves the private session, and acknowledges delivery.
|
|
22
36
|
|
|
23
|
-
Browser sign-in lets you choose one or more organizations and explicitly select enabled accounts within each. Membership alone does not authorize a CLI connection; current organization and account permissions still apply. For a brand-new account,
|
|
37
|
+
Browser sign-in lets you choose one or more organizations and explicitly select enabled accounts within each. Membership alone does not authorize a CLI connection; current organization and account permissions still apply. For a brand-new account, use `tc signup`; the browser asks for an organization name and continues without a rerun. No provider reconnection is required just to authorize the CLI.
|
|
24
38
|
|
|
25
39
|
Prefer `npm exec` during evaluation. `npm install -g @trillioncore/cli@next` replaces your local `tc` executable, even though publishing `next` does not change the npm `latest` tag.
|
|
26
40
|
|
|
27
41
|
## Commands
|
|
28
42
|
|
|
29
43
|
- `login [--no-browser] [--api-url <origin>]`: browser authorization, organization/account selection, and durable local session storage.
|
|
44
|
+
- `signup [--organization-name <name>] [--no-browser] [--api-url <origin>]`: create an account on the sign-up screen, name a new organization (you become its administrator), then finish the same device approval as `login`.
|
|
45
|
+
- `create-organization [--name <name>] [--no-browser] [--api-url <origin>]`: an existing account creates another organization in the browser and becomes its administrator. The CLI then signs in through the same device approval, because a new organization needs its own approval. `tc login` also asks a signed-in person with no organization to name one.
|
|
30
46
|
- `whoami [--json]`: verify the signed-in identity without printing credentials.
|
|
31
47
|
- `logout`: revoke the CLI connection on the server and remove its local session. `--local-only` only forgets local credentials; use the app's **Tokens** page to revoke server access if offline.
|
|
32
48
|
- `organizations [--json]`: list only currently approved organizations, with `--limit` and `--cursor` pagination.
|
package/dist/index.js
CHANGED
|
@@ -3405,10 +3405,22 @@ function verificationUrl(value, requestId) {
|
|
|
3405
3405
|
);
|
|
3406
3406
|
}
|
|
3407
3407
|
}
|
|
3408
|
+
function organizationSetupUrl(url, options) {
|
|
3409
|
+
if (!options.signUp && !options.createOrganization) return url;
|
|
3410
|
+
const next = new URL(url);
|
|
3411
|
+
if (options.signUp) next.pathname = "/connect/cli/sign-up";
|
|
3412
|
+
else next.searchParams.set("create", "organization");
|
|
3413
|
+
if (options.organizationName)
|
|
3414
|
+
next.searchParams.set("name", options.organizationName);
|
|
3415
|
+
return next.toString();
|
|
3416
|
+
}
|
|
3408
3417
|
async function login(options = {}, environment = process.env) {
|
|
3409
3418
|
const issuer = loginOrigin(
|
|
3410
3419
|
options.apiUrl ?? environment.TRILLIONCORE_CLI_API_URL ?? environment.TRILLIONCORE_API_URL ?? DEFAULT_API
|
|
3411
3420
|
);
|
|
3421
|
+
const organizationName = options.organizationName?.trim();
|
|
3422
|
+
if (organizationName !== void 0 && (!organizationName || organizationName.length > 100 || /[\u0000-\u001f\u007f-\u009f]/.test(organizationName)))
|
|
3423
|
+
throw new Error("Organization name must be 1-100 printable characters.");
|
|
3412
3424
|
const abort = new AbortController();
|
|
3413
3425
|
const verifier = randomBytes2(32).toString("base64url");
|
|
3414
3426
|
const alphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
@@ -3475,9 +3487,9 @@ async function login(options = {}, environment = process.env) {
|
|
|
3475
3487
|
() => stop("Sign-in timed out. Run tc login again."),
|
|
3476
3488
|
deadline - Date.now()
|
|
3477
3489
|
);
|
|
3478
|
-
const authorization =
|
|
3479
|
-
registration.verification_uri,
|
|
3480
|
-
|
|
3490
|
+
const authorization = organizationSetupUrl(
|
|
3491
|
+
verificationUrl(registration.verification_uri, requestId),
|
|
3492
|
+
{ ...options, ...organizationName ? { organizationName } : {} }
|
|
3481
3493
|
);
|
|
3482
3494
|
if (options.onAuthorizationUrl)
|
|
3483
3495
|
await options.onAuthorizationUrl(authorization, userCode);
|
|
@@ -3551,7 +3563,7 @@ Only approve a login you started. Keep the code private.`
|
|
|
3551
3563
|
"Signed in, but delivery acknowledgement failed. The temporary delivery expires automatically."
|
|
3552
3564
|
)
|
|
3553
3565
|
);
|
|
3554
|
-
return { issuer, ...who };
|
|
3566
|
+
return { issuer, appUrl: new URL(authorization).origin, ...who };
|
|
3555
3567
|
} catch (error) {
|
|
3556
3568
|
if (!persisted)
|
|
3557
3569
|
await revoke(credentials).catch(
|
|
@@ -3651,6 +3663,12 @@ async function logout(localOnly = false, environment = process.env) {
|
|
|
3651
3663
|
|
|
3652
3664
|
// ../../packages/types/dist/integrations.js
|
|
3653
3665
|
var INTEGRATION_PROVIDER_DEFINITIONS = {
|
|
3666
|
+
beads: {
|
|
3667
|
+
description: "Issues and project work",
|
|
3668
|
+
nativeRecordKinds: ["beads_issue"],
|
|
3669
|
+
modelVisibility: "declared",
|
|
3670
|
+
identity: { source: "externalAccountId", kind: "account-id", prefix: "Tracker ID: ", unavailable: "Tracker identity unavailable" }
|
|
3671
|
+
},
|
|
3654
3672
|
fathom: {
|
|
3655
3673
|
description: "Meeting transcripts",
|
|
3656
3674
|
nativeRecordKinds: ["transcript"],
|
|
@@ -3682,6 +3700,13 @@ var INTEGRATION_PROVIDER_DEFINITIONS = {
|
|
|
3682
3700
|
modelVisibility: "declared",
|
|
3683
3701
|
identity: { source: "externalAccountId", kind: "email", prefix: "", unavailable: "Account email unavailable" }
|
|
3684
3702
|
},
|
|
3703
|
+
plaid: {
|
|
3704
|
+
// SQL-only: one Plaid Item (bank login) publishes accounts and transactions tables.
|
|
3705
|
+
description: "Bank accounts and transactions",
|
|
3706
|
+
nativeRecordKinds: [],
|
|
3707
|
+
modelVisibility: "declared",
|
|
3708
|
+
identity: { source: "unavailable", unavailable: "Account identity unavailable" }
|
|
3709
|
+
},
|
|
3685
3710
|
slack: {
|
|
3686
3711
|
// Slack workspace identity is retained in the Airbyte binding. The visible local account
|
|
3687
3712
|
// identifier is deliberately unique so an organization can keep separate connections.
|
|
@@ -3719,7 +3744,7 @@ function integrationProviderDefinition(provider) {
|
|
|
3719
3744
|
}
|
|
3720
3745
|
|
|
3721
3746
|
// ../../packages/types/dist/agent.js
|
|
3722
|
-
var AGENT_SOURCE_TYPES = ["fathom", "fireflies", "harvest", "outlook", "gmail", "slack", "postgres", "github", "google_analytics"];
|
|
3747
|
+
var AGENT_SOURCE_TYPES = ["fathom", "fireflies", "harvest", "outlook", "gmail", "slack", "postgres", "github", "google_analytics", "plaid", "beads"];
|
|
3723
3748
|
var AGENT_SEARCH_FILTER_TYPES = [...AGENT_SOURCE_TYPES, "email"];
|
|
3724
3749
|
function presentAgentIndex(result, resourceKey) {
|
|
3725
3750
|
if (resourceKey !== void 0)
|
|
@@ -3860,6 +3885,7 @@ function agentRecovery(code) {
|
|
|
3860
3885
|
join_not_approved: "This ordered join does not match exactly one approved FK. Inspect the target schemas and relationships with index. Query each approved table separately with projected columns and LIMIT, then correlate observed keys outside SQL. Similar column names do not establish a relationship.",
|
|
3861
3886
|
dataset_unavailable: "The synchronized dataset is unavailable. Inspect account index operations and freshness; retry after a published dataset is available. Do not fall back to live.",
|
|
3862
3887
|
forbidden: "The request is not authorized. Select an approved organization and connection; do not infer whether another resource exists.",
|
|
3888
|
+
subscription_required: "This organization needs an active subscription. An administrator can start one at app.trillioncore.com. Tell the person this, and do not retry.",
|
|
3863
3889
|
not_found: "The resource is unavailable in the authorized catalog. Return to index and use a returned path or key.",
|
|
3864
3890
|
unsupported: "This operation is unsupported. Use the operations advertised by index.",
|
|
3865
3891
|
unavailable: "The request could not be completed. Check arguments and access, or retry later."
|
|
@@ -4018,7 +4044,7 @@ function parseErrorEnvelope(value) {
|
|
|
4018
4044
|
if (typeof record.code !== "string" || typeof record.message !== "string") {
|
|
4019
4045
|
return null;
|
|
4020
4046
|
}
|
|
4021
|
-
if (["invalid_path", "account_required", "sql_rejected", "dataset_unavailable"].includes(record.code)) return agentRecovery(record.code);
|
|
4047
|
+
if (["invalid_path", "account_required", "sql_rejected", "dataset_unavailable", "subscription_required"].includes(record.code)) return agentRecovery(record.code);
|
|
4022
4048
|
if (!["organization_required", "invalid_input", "forbidden", "not_found", "unsupported", "unavailable"].includes(
|
|
4023
4049
|
record.code
|
|
4024
4050
|
)) {
|
|
@@ -4604,17 +4630,19 @@ function createProgram(overrides = {}) {
|
|
|
4604
4630
|
};
|
|
4605
4631
|
const program2 = new Command();
|
|
4606
4632
|
program2.name("tc").description("Trillioncore CLI \u2014 authorized integration record access").version(CLI_VERSION).helpCommand(false);
|
|
4607
|
-
|
|
4608
|
-
"Sign in through your browser and choose an organization and accounts"
|
|
4609
|
-
).option("--api-url <origin>", "Trillioncore API origin").option("--no-browser", "Print the sign-in URL without opening a browser").action(async (options) => {
|
|
4633
|
+
const signIn = async (options, setup = {}) => {
|
|
4610
4634
|
try {
|
|
4611
4635
|
const result = await login({
|
|
4612
|
-
apiUrl: options.apiUrl,
|
|
4613
|
-
noBrowser: options.browser === false
|
|
4636
|
+
...options.apiUrl !== void 0 ? { apiUrl: options.apiUrl } : {},
|
|
4637
|
+
noBrowser: options.browser === false,
|
|
4638
|
+
...setup,
|
|
4639
|
+
...options.organizationName !== void 0 ? { organizationName: options.organizationName } : {}
|
|
4614
4640
|
});
|
|
4615
4641
|
console.log(
|
|
4616
4642
|
`Signed in as ${result.email.replace(/[\u0000-\u001f\u007f-\u009f]/g, "")} to ${(result.organizationName ?? "your approved organizations").replace(/[\u0000-\u001f\u007f-\u009f]/g, "")}.`
|
|
4617
4643
|
);
|
|
4644
|
+
if (setup.signUp || setup.createOrganization)
|
|
4645
|
+
console.log(`Next: connect your data sources under Integrations at ${result.appUrl}`);
|
|
4618
4646
|
if (process.env.TRILLIONCORE_TOKEN || process.env.TRILLIONCORE_ORG_ID)
|
|
4619
4647
|
console.error(
|
|
4620
4648
|
"Manual token/organization environment overrides are set. Unset both to use this browser session."
|
|
@@ -4622,7 +4650,16 @@ function createProgram(overrides = {}) {
|
|
|
4622
4650
|
} catch (error) {
|
|
4623
4651
|
writeError(error, false);
|
|
4624
4652
|
}
|
|
4625
|
-
}
|
|
4653
|
+
};
|
|
4654
|
+
program2.command("login").description(
|
|
4655
|
+
"Sign in through your browser and choose an organization and accounts"
|
|
4656
|
+
).option("--api-url <origin>", "Trillioncore API origin").option("--no-browser", "Print the sign-in URL without opening a browser").action((options) => signIn(options));
|
|
4657
|
+
program2.command("signup").description(
|
|
4658
|
+
"Create a Trillioncore account and organization in your browser, then sign in this CLI"
|
|
4659
|
+
).option("--api-url <origin>", "Trillioncore API origin").option("--no-browser", "Print the sign-up URL without opening a browser").option("--organization-name <name>", "Suggested organization name; the browser asks to confirm it").action((options) => signIn(options, { signUp: true }));
|
|
4660
|
+
program2.command("create-organization").description(
|
|
4661
|
+
"Create another organization in your browser; you become its administrator and this CLI signs in to it"
|
|
4662
|
+
).option("--name <name>", "Suggested organization name; the browser asks to confirm it").option("--api-url <origin>", "Trillioncore API origin").option("--no-browser", "Print the URL without opening a browser").action((options) => signIn({ ...options, organizationName: options.name }, { createOrganization: true }));
|
|
4626
4663
|
program2.command("whoami").description("Verify your current CLI identity").option("-j, --json", "Output identity without credentials").action(async (options) => {
|
|
4627
4664
|
try {
|
|
4628
4665
|
const result = await whoami();
|