@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.
Files changed (3) hide show
  1. package/README.md +17 -1
  2. package/dist/index.js +49 -12
  3. 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, finish organization setup and connect your integrations in the app, then rerun `tc login` if prompted. No provider reconnection is required just to authorize the CLI.
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 = verificationUrl(
3479
- registration.verification_uri,
3480
- requestId
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
- program2.command("login").description(
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trillioncore/cli",
3
- "version": "1.0.0-next.11",
3
+ "version": "1.0.0-next.13",
4
4
  "description": "Trillioncore v1 CLI: sign in and read your authorized integration records",
5
5
  "type": "module",
6
6
  "license": "MIT",