@primitivedotdev/cli 1.0.0 → 1.1.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
@@ -48,7 +48,7 @@ Use `primitive signin <email> --signup-code <code> --accept-terms`, then `primit
48
48
 
49
49
  Use `primitive logout --force` to remove local CLI credentials, pending email-code auth state, and stale credential locks without contacting Primitive. This is the recovery command when an interrupted auth command leaves the CLI saying another credential operation is already in progress.
50
50
 
51
- Use `primitive signup <email>` for new account creation, then `primitive signup confirm <email> <code>` with the emailed verification code. Non-interactive signup is available with `--signup-code` and `--accept-terms`.
51
+ Use `primitive signup <email>` for new account creation, then `primitive signup confirm <email> <code>` with the emailed verification code. Non-interactive signup is available with `--accept-terms` (pass `--signup-code <code>` too if you have one).
52
52
 
53
53
  ## Command style
54
54
 
@@ -124,10 +124,11 @@ const pollCliLogin = (options) => (options.client ?? client).post({
124
124
  /**
125
125
  * Start CLI account signup
126
126
  *
127
- * Starts a terminal-native CLI signup. The API validates the signup code,
128
- * creates a pending signup session, sends an email verification code, and
129
- * returns an opaque signup token used by the resend and verify steps. This
130
- * endpoint does not require an API key.
127
+ * Starts a terminal-native CLI signup. `signup_code` is optional;
128
+ * omit it to sign up without one. The API creates a pending signup
129
+ * session, sends an email verification code, and returns an opaque
130
+ * signup token used by the resend and verify steps. This endpoint
131
+ * does not require an API key.
131
132
  *
132
133
  */
133
134
  const startCliSignup = (options) => (options.client ?? client).post({
@@ -156,10 +157,12 @@ const resendCliSignupVerification = (options) => (options.client ?? client).post
156
157
  /**
157
158
  * Verify CLI signup and create OAuth session
158
159
  *
159
- * Verifies the email code for a CLI signup session, creates the account,
160
- * redeems the reserved signup code, creates an org-scoped OAuth CLI
161
- * session, and returns the token set exactly once. This endpoint does not
162
- * require an API key.
160
+ * Verifies the email code for a CLI signup session and creates the
161
+ * account. When the session was started with a `signup_code`, the
162
+ * reserved code is redeemed; sessions started without a code skip
163
+ * the redemption step. Either way an org-scoped OAuth CLI session
164
+ * is created and the token set is returned exactly once. This
165
+ * endpoint does not require an API key.
163
166
  *
164
167
  */
165
168
  const verifyCliSignup = (options) => (options.client ?? client).post({
@@ -173,10 +176,11 @@ const verifyCliSignup = (options) => (options.client ?? client).post({
173
176
  /**
174
177
  * Start agent account signup
175
178
  *
176
- * Starts an agent-native signup session. The API validates the signup code,
177
- * creates a pending signup session, sends an email verification code, and
178
- * returns an opaque signup token used by the resend and verify steps. This
179
- * endpoint does not require an API key.
179
+ * Starts an agent-native signup session. `signup_code` is optional;
180
+ * omit it to sign up without one. The API creates a pending signup
181
+ * session, sends an email verification code, and returns an opaque
182
+ * signup token used by the resend and verify steps. This endpoint
183
+ * does not require an API key.
180
184
  *
181
185
  */
182
186
  const startAgentSignup = (options) => (options.client ?? client).post({
@@ -205,11 +209,15 @@ const resendAgentSignupVerification = (options) => (options.client ?? client).po
205
209
  /**
206
210
  * Verify agent signup and create OAuth tokens
207
211
  *
208
- * Verifies the email code for an agent signup session, creates the account
209
- * when needed, redeems the reserved signup code, mints an org-scoped OAuth
210
- * session for CLI authentication, and returns the raw tokens exactly once.
211
- * For existing users, the optional `org_id` selects which accessible
212
- * workspace should receive the new session.
212
+ * Verifies the email code for an agent signup session and creates
213
+ * the account when needed. When the session was started with a
214
+ * `signup_code`, the reserved code is redeemed; sessions started
215
+ * without a code skip the redemption step. An org-scoped OAuth
216
+ * session for CLI authentication is minted and the raw tokens are
217
+ * returned exactly once. For existing users, the optional `org_id`
218
+ * selects which accessible workspace should receive the new
219
+ * session (no signup-code redemption is performed for existing
220
+ * users regardless of how the session was started).
213
221
  *
214
222
  */
215
223
  const verifyAgentSignup = (options) => (options.client ?? client).post({
@@ -1642,7 +1650,7 @@ const openapiDocument = {
1642
1650
  "/cli/signup/start": { "post": {
1643
1651
  "operationId": "startCliSignup",
1644
1652
  "summary": "Start CLI account signup",
1645
- "description": "Starts a terminal-native CLI signup. The API validates the signup code,\ncreates a pending signup session, sends an email verification code, and\nreturns an opaque signup token used by the resend and verify steps. This\nendpoint does not require an API key.\n",
1653
+ "description": "Starts a terminal-native CLI signup. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
1646
1654
  "tags": ["CLI"],
1647
1655
  "security": [],
1648
1656
  "requestBody": {
@@ -1704,7 +1712,7 @@ const openapiDocument = {
1704
1712
  "/cli/signup/verify": { "post": {
1705
1713
  "operationId": "verifyCliSignup",
1706
1714
  "summary": "Verify CLI signup and create OAuth session",
1707
- "description": "Verifies the email code for a CLI signup session, creates the account,\nredeems the reserved signup code, creates an org-scoped OAuth CLI\nsession, and returns the token set exactly once. This endpoint does not\nrequire an API key.\n",
1715
+ "description": "Verifies the email code for a CLI signup session and creates the\naccount. When the session was started with a `signup_code`, the\nreserved code is redeemed; sessions started without a code skip\nthe redemption step. Either way an org-scoped OAuth CLI session\nis created and the token set is returned exactly once. This\nendpoint does not require an API key.\n",
1708
1716
  "tags": ["CLI"],
1709
1717
  "security": [],
1710
1718
  "requestBody": {
@@ -1733,7 +1741,7 @@ const openapiDocument = {
1733
1741
  "/agent/signup/start": { "post": {
1734
1742
  "operationId": "startAgentSignup",
1735
1743
  "summary": "Start agent account signup",
1736
- "description": "Starts an agent-native signup session. The API validates the signup code,\ncreates a pending signup session, sends an email verification code, and\nreturns an opaque signup token used by the resend and verify steps. This\nendpoint does not require an API key.\n",
1744
+ "description": "Starts an agent-native signup session. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
1737
1745
  "tags": ["Agent"],
1738
1746
  "security": [],
1739
1747
  "requestBody": {
@@ -1795,7 +1803,7 @@ const openapiDocument = {
1795
1803
  "/agent/signup/verify": { "post": {
1796
1804
  "operationId": "verifyAgentSignup",
1797
1805
  "summary": "Verify agent signup and create OAuth tokens",
1798
- "description": "Verifies the email code for an agent signup session, creates the account\nwhen needed, redeems the reserved signup code, mints an org-scoped OAuth\nsession for CLI authentication, and returns the raw tokens exactly once.\nFor existing users, the optional `org_id` selects which accessible\nworkspace should receive the new session.\n",
1806
+ "description": "Verifies the email code for an agent signup session and creates\nthe account when needed. When the session was started with a\n`signup_code`, the reserved code is redeemed; sessions started\nwithout a code skip the redemption step. An org-scoped OAuth\nsession for CLI authentication is minted and the raw tokens are\nreturned exactly once. For existing users, the optional `org_id`\nselects which accessible workspace should receive the new\nsession (no signup-code redemption is performed for existing\nusers regardless of how the session was started).\n",
1799
1807
  "tags": ["Agent"],
1800
1808
  "security": [],
1801
1809
  "requestBody": {
@@ -4045,7 +4053,8 @@ const openapiDocument = {
4045
4053
  "signup_code": {
4046
4054
  "type": "string",
4047
4055
  "minLength": 1,
4048
- "maxLength": 128
4056
+ "maxLength": 128,
4057
+ "description": "Optional signup code. Omit if you do not have one."
4049
4058
  },
4050
4059
  "terms_accepted": {
4051
4060
  "type": "boolean",
@@ -4064,11 +4073,7 @@ const openapiDocument = {
4064
4073
  "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
4065
4074
  }
4066
4075
  },
4067
- "required": [
4068
- "email",
4069
- "signup_code",
4070
- "terms_accepted"
4071
- ]
4076
+ "required": ["email", "terms_accepted"]
4072
4077
  },
4073
4078
  "CliSignupStartResult": {
4074
4079
  "type": "object",
@@ -4233,7 +4238,8 @@ const openapiDocument = {
4233
4238
  "signup_code": {
4234
4239
  "type": "string",
4235
4240
  "minLength": 1,
4236
- "maxLength": 128
4241
+ "maxLength": 128,
4242
+ "description": "Optional signup code. Omit if you do not have one."
4237
4243
  },
4238
4244
  "terms_accepted": {
4239
4245
  "type": "boolean",
@@ -4252,11 +4258,7 @@ const openapiDocument = {
4252
4258
  "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
4253
4259
  }
4254
4260
  },
4255
- "required": [
4256
- "email",
4257
- "signup_code",
4258
- "terms_accepted"
4259
- ]
4261
+ "required": ["email", "terms_accepted"]
4260
4262
  },
4261
4263
  "AgentSignupStartResult": {
4262
4264
  "type": "object",
@@ -7781,7 +7783,7 @@ const operationManifest = [
7781
7783
  "binaryResponse": false,
7782
7784
  "bodyRequired": true,
7783
7785
  "command": "start-agent-signup",
7784
- "description": "Starts an agent-native signup session. The API validates the signup code,\ncreates a pending signup session, sends an email verification code, and\nreturns an opaque signup token used by the resend and verify steps. This\nendpoint does not require an API key.\n",
7786
+ "description": "Starts an agent-native signup session. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
7785
7787
  "hasJsonBody": true,
7786
7788
  "method": "POST",
7787
7789
  "operationId": "startAgentSignup",
@@ -7800,7 +7802,8 @@ const operationManifest = [
7800
7802
  "signup_code": {
7801
7803
  "type": "string",
7802
7804
  "minLength": 1,
7803
- "maxLength": 128
7805
+ "maxLength": 128,
7806
+ "description": "Optional signup code. Omit if you do not have one."
7804
7807
  },
7805
7808
  "terms_accepted": {
7806
7809
  "type": "boolean",
@@ -7819,11 +7822,7 @@ const operationManifest = [
7819
7822
  "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
7820
7823
  }
7821
7824
  },
7822
- "required": [
7823
- "email",
7824
- "signup_code",
7825
- "terms_accepted"
7826
- ]
7825
+ "required": ["email", "terms_accepted"]
7827
7826
  },
7828
7827
  "responseSchema": {
7829
7828
  "type": "object",
@@ -7866,7 +7865,7 @@ const operationManifest = [
7866
7865
  "binaryResponse": false,
7867
7866
  "bodyRequired": true,
7868
7867
  "command": "verify-agent-signup",
7869
- "description": "Verifies the email code for an agent signup session, creates the account\nwhen needed, redeems the reserved signup code, mints an org-scoped OAuth\nsession for CLI authentication, and returns the raw tokens exactly once.\nFor existing users, the optional `org_id` selects which accessible\nworkspace should receive the new session.\n",
7868
+ "description": "Verifies the email code for an agent signup session and creates\nthe account when needed. When the session was started with a\n`signup_code`, the reserved code is redeemed; sessions started\nwithout a code skip the redemption step. An org-scoped OAuth\nsession for CLI authentication is minted and the raw tokens are\nreturned exactly once. For existing users, the optional `org_id`\nselects which accessible workspace should receive the new\nsession (no signup-code redemption is performed for existing\nusers regardless of how the session was started).\n",
7870
7869
  "hasJsonBody": true,
7871
7870
  "method": "POST",
7872
7871
  "operationId": "verifyAgentSignup",
@@ -8236,7 +8235,7 @@ const operationManifest = [
8236
8235
  "binaryResponse": false,
8237
8236
  "bodyRequired": true,
8238
8237
  "command": "start-cli-signup",
8239
- "description": "Starts a terminal-native CLI signup. The API validates the signup code,\ncreates a pending signup session, sends an email verification code, and\nreturns an opaque signup token used by the resend and verify steps. This\nendpoint does not require an API key.\n",
8238
+ "description": "Starts a terminal-native CLI signup. `signup_code` is optional;\nomit it to sign up without one. The API creates a pending signup\nsession, sends an email verification code, and returns an opaque\nsignup token used by the resend and verify steps. This endpoint\ndoes not require an API key.\n",
8240
8239
  "hasJsonBody": true,
8241
8240
  "method": "POST",
8242
8241
  "operationId": "startCliSignup",
@@ -8255,7 +8254,8 @@ const operationManifest = [
8255
8254
  "signup_code": {
8256
8255
  "type": "string",
8257
8256
  "minLength": 1,
8258
- "maxLength": 128
8257
+ "maxLength": 128,
8258
+ "description": "Optional signup code. Omit if you do not have one."
8259
8259
  },
8260
8260
  "terms_accepted": {
8261
8261
  "type": "boolean",
@@ -8274,11 +8274,7 @@ const operationManifest = [
8274
8274
  "description": "Optional client metadata stored with the signup session; serialized JSON must be 2048 bytes or fewer"
8275
8275
  }
8276
8276
  },
8277
- "required": [
8278
- "email",
8279
- "signup_code",
8280
- "terms_accepted"
8281
- ]
8277
+ "required": ["email", "terms_accepted"]
8282
8278
  },
8283
8279
  "responseSchema": {
8284
8280
  "type": "object",
@@ -8321,7 +8317,7 @@ const operationManifest = [
8321
8317
  "binaryResponse": false,
8322
8318
  "bodyRequired": true,
8323
8319
  "command": "verify-cli-signup",
8324
- "description": "Verifies the email code for a CLI signup session, creates the account,\nredeems the reserved signup code, creates an org-scoped OAuth CLI\nsession, and returns the token set exactly once. This endpoint does not\nrequire an API key.\n",
8320
+ "description": "Verifies the email code for a CLI signup session and creates the\naccount. When the session was started with a `signup_code`, the\nreserved code is redeemed; sessions started without a code skip\nthe redemption step. Either way an org-scoped OAuth CLI session\nis created and the token set is returned exactly once. This\nendpoint does not require an API key.\n",
8325
8321
  "hasJsonBody": true,
8326
8322
  "method": "POST",
8327
8323
  "operationId": "verifyCliSignup",
@@ -14566,7 +14562,7 @@ const OPERATION_HINTS = {
14566
14562
  updateFunction: "Tip: prefer `primitive functions redeploy --id <id> --file <bundle>` for file-input ergonomics. This raw command exists for callers passing JSON.",
14567
14563
  createFunctionSecret: "Tip: prefer `primitive functions set-secret --id <id> --key <KEY> --value <value> [--redeploy]` for secret writes that also push the binding live. This raw command exists for callers passing JSON.",
14568
14564
  setFunctionSecret: "Tip: prefer `primitive functions set-secret --id <id> --key <KEY> --value <value> [--redeploy]` for secret writes that also push the binding live. This raw command exists for callers passing JSON.",
14569
- startAgentSignup: "Tip: also pass --signup-code <code> (request from Primitive; invite-only during the agent beta) and --terms-accepted. Capture the signup_token from the response and feed it to `primitive agent verify-agent-signup --signup-token <token> --verification-code <6-digit-code>` (the verify flag accepts --code as an alias). The high-level `primitive signup <email>` command walks an interactive user through both steps with friendlier prompts.",
14565
+ startAgentSignup: "Tip: pass --terms-accepted, and optionally --signup-code <code> if you have one. Capture the signup_token from the response and feed it to `primitive agent verify-agent-signup --signup-token <token> --verification-code <6-digit-code>` (the verify flag accepts --code as an alias). The high-level `primitive signup <email>` command walks an interactive user through both steps with friendlier prompts.",
14570
14566
  verifyAgentSignup: "Tip: pass --verification-code <code> (or --code; both work). The response carries OAuth tokens but not your assigned inbox domain; run `primitive domains list` (or `primitive whoami`) after success to see the managed *.primitive.email address that routes to this account."
14571
14567
  };
14572
14568
  const OPERATION_FLAG_ALIASES = { verifyAgentSignup: { verification_code: ["code"] } };
@@ -16645,8 +16641,8 @@ var DomainsZoneFileCommand = class DomainsZoneFileCommand extends Command {
16645
16641
  };
16646
16642
  //#endregion
16647
16643
  //#region src/oclif/commands/emails-latest.ts
16648
- const DEFAULT_LIMIT$1 = 10;
16649
- const MAX_LIMIT$1 = 100;
16644
+ const DEFAULT_LIMIT$2 = 10;
16645
+ const MAX_LIMIT$2 = 100;
16650
16646
  const SUBJECT_DISPLAY_WIDTH = 50;
16651
16647
  const ADDRESS_DISPLAY_WIDTH = 32;
16652
16648
  const ID_DISPLAY_WIDTH_SHORT = 8;
@@ -16696,10 +16692,10 @@ var EmailsLatestCommand = class EmailsLatestCommand extends Command {
16696
16692
  hidden: true
16697
16693
  }),
16698
16694
  limit: Flags.integer({
16699
- description: `Number of rows to print (1-${MAX_LIMIT$1}, default ${DEFAULT_LIMIT$1}).`,
16700
- default: DEFAULT_LIMIT$1,
16695
+ description: `Number of rows to print (1-${MAX_LIMIT$2}, default ${DEFAULT_LIMIT$2}).`,
16696
+ default: DEFAULT_LIMIT$2,
16701
16697
  min: 1,
16702
- max: MAX_LIMIT$1
16698
+ max: MAX_LIMIT$2
16703
16699
  }),
16704
16700
  json: Flags.boolean({ description: "Print the raw response envelope (with full UUIDs and meta) as JSON on STDOUT instead of the text table. Useful for piping into `jq`, capturing ids for follow-up commands, or scripting." }),
16705
16701
  time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
@@ -17970,8 +17966,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
17970
17966
  name: "Primitive Team",
17971
17967
  url: "https://primitive.dev"
17972
17968
  };
17973
- const SDK_VERSION_RANGE = "^1.0.0";
17974
- const CLI_VERSION_RANGE = "^1.0.0";
17969
+ const SDK_VERSION_RANGE = "^1.1.0";
17970
+ const CLI_VERSION_RANGE = "^1.1.0";
17975
17971
  const ESBUILD_VERSION_RANGE = "^0.27.0";
17976
17972
  function renderHandler() {
17977
17973
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -20214,7 +20210,8 @@ const DEFAULT_SIGNUP_COMMAND_COPY = {
20214
20210
  actionGerund: "creating a new account",
20215
20211
  confirmCommand: (email) => `signup confirm ${email} <code>`,
20216
20212
  resendCommand: (email) => `signup resend ${email}`,
20217
- startCommand: (email) => `signup ${email}`
20213
+ startCommand: (email) => `signup ${email}`,
20214
+ codeRequired: false
20218
20215
  };
20219
20216
  function cliError$2(message) {
20220
20217
  return new Errors.CLIError(message, { exit: 1 });
@@ -20329,7 +20326,7 @@ function readPendingAgentSignupState(configDir, apiBaseUrl) {
20329
20326
  return pending;
20330
20327
  }
20331
20328
  function pendingSignupStartCommand(email) {
20332
- return `primitive signup ${email ?? "<email>"} --signup-code <invite-code> --accept-terms`;
20329
+ return `primitive signup ${email ?? "<email>"} --accept-terms`;
20333
20330
  }
20334
20331
  function buildSignupStatus(params) {
20335
20332
  const copy = params.copy ?? DEFAULT_SIGNUP_COMMAND_COPY;
@@ -20495,16 +20492,17 @@ async function startSignup(params) {
20495
20492
  throw cliError$2(`Pending ${copy.actionNoun} is for ${existingPending.email}. Run \`primitive signup status\` to inspect it, or \`primitive ${copy.startCommand(params.email)} --force\` to replace it.`);
20496
20493
  }
20497
20494
  if (params.flags.force) deletePendingAgentSignup(params.configDir);
20498
- const promptRequiredFn = params.deps.promptRequired ?? promptRequired;
20499
20495
  const confirmTermsFn = params.deps.confirmTerms ?? confirmTerms;
20496
+ const promptRequiredFn = params.deps.promptRequired ?? promptRequired;
20500
20497
  const startFn = params.deps.startAgentSignup ?? startAgentSignup;
20501
- const signupCode = params.flags["signup-code"] ?? await promptRequiredFn("Signup code: ");
20498
+ const rawSignupCode = params.flags["signup-code"];
20499
+ const signupCode = (rawSignupCode && rawSignupCode.trim().length > 0 ? rawSignupCode : void 0) ?? (copy.codeRequired ? await promptRequiredFn("Signup code: ") : void 0);
20502
20500
  if (!params.flags["accept-terms"]) await confirmTermsFn();
20503
20501
  const started = await startFn({
20504
20502
  body: {
20505
20503
  device_name: params.flags["device-name"] ?? hostname(),
20506
20504
  email: params.email,
20507
- signup_code: signupCode,
20505
+ ...signupCode ? { signup_code: signupCode } : {},
20508
20506
  terms_accepted: true
20509
20507
  },
20510
20508
  client: params.apiClient.client,
@@ -20734,7 +20732,7 @@ function commonStartFlags() {
20734
20732
  description: "Replace saved credentials or pending signup state when needed"
20735
20733
  }),
20736
20734
  "signup-code": Flags.string({
20737
- description: "Signup code required to create an account",
20735
+ description: "Optional signup code. Omit if you do not have one.",
20738
20736
  env: "PRIMITIVE_SIGNUP_CODE"
20739
20737
  })
20740
20738
  };
@@ -20748,6 +20746,7 @@ var SignupCommand = class SignupCommand extends Command {
20748
20746
  static summary = "Start account signup";
20749
20747
  static examples = [
20750
20748
  "<%= config.bin %> signup user@example.com",
20749
+ "<%= config.bin %> signup user@example.com --accept-terms",
20751
20750
  "<%= config.bin %> signup user@example.com --signup-code invite-code --accept-terms",
20752
20751
  "<%= config.bin %> signup confirm user@example.com 123456"
20753
20752
  ];
@@ -21223,8 +21222,8 @@ var ReplyCommand = class ReplyCommand extends Command {
21223
21222
  };
21224
21223
  //#endregion
21225
21224
  //#region src/oclif/commands/semantic-search.ts
21226
- const DEFAULT_LIMIT = 10;
21227
- const MAX_LIMIT = 100;
21225
+ const DEFAULT_LIMIT$1 = 10;
21226
+ const MAX_LIMIT$1 = 100;
21228
21227
  const SCORE_WIDTH = 7;
21229
21228
  const SOURCE_WIDTH = 4;
21230
21229
  const SUBJECT_WIDTH = 40;
@@ -21290,10 +21289,10 @@ var SemanticSearchCommand = class SemanticSearchCommand extends Command {
21290
21289
  "date-from": Flags.string({ description: "Only include mail at or after this ISO-8601 timestamp." }),
21291
21290
  "date-to": Flags.string({ description: "Only include mail at or before this ISO-8601 timestamp." }),
21292
21291
  limit: Flags.integer({
21293
- description: `Maximum results to return (1-${MAX_LIMIT}, default ${DEFAULT_LIMIT}).`,
21294
- default: DEFAULT_LIMIT,
21292
+ description: `Maximum results to return (1-${MAX_LIMIT$1}, default ${DEFAULT_LIMIT$1}).`,
21293
+ default: DEFAULT_LIMIT$1,
21295
21294
  min: 1,
21296
- max: MAX_LIMIT
21295
+ max: MAX_LIMIT$1
21297
21296
  }),
21298
21297
  cursor: Flags.string({ description: "Opaque pagination cursor from a prior response's meta.cursor." }),
21299
21298
  json: Flags.boolean({ description: "Print the raw response envelope as JSON on STDOUT instead of the text table." }),
@@ -21350,6 +21349,230 @@ var SemanticSearchCommand = class SemanticSearchCommand extends Command {
21350
21349
  }
21351
21350
  };
21352
21351
  //#endregion
21352
+ //#region src/oclif/commands/search.ts
21353
+ const DEFAULT_LIMIT = 10;
21354
+ const MAX_LIMIT = 100;
21355
+ const LEXICAL_ONLY_FLAGS = [
21356
+ "from",
21357
+ "to",
21358
+ "subject",
21359
+ "body",
21360
+ "domain",
21361
+ "domain-id",
21362
+ "has-attachment",
21363
+ "status",
21364
+ "sort",
21365
+ "snippet",
21366
+ "include-facets"
21367
+ ];
21368
+ var SearchCommand = class SearchCommand extends Command {
21369
+ static description = `Search received (default) or both received and sent mail (with --mode).
21370
+
21371
+ Default behavior is lexical full-text matching: the positional query is sent as \`q=<query>\` to the inbound search endpoint, which matches against subject, body, sender, and recipient in a single pass. Structured filters (--from, --to, --subject, --body, --domain, --has-attachment, --date-from, --date-to, --status) AND with the text query.
21372
+
21373
+ Pass --mode to switch to the cross-corpus semantic backend (covers inbound and outbound). \`--mode keyword\` is plain full-text; \`--mode semantic\` is embedding-only; \`--mode hybrid\` blends both. Semantic modes require the Pro plan with the semantic_search_enabled entitlement.
21374
+
21375
+ Output is a fixed-width text table by default (header on STDERR so rows stay grep/awk-friendly). Use --json for the raw envelope.`;
21376
+ static summary = "Search mail (lexical by default; --mode for semantic)";
21377
+ static examples = [
21378
+ "<%= config.bin %> search \"invoice\"",
21379
+ "<%= config.bin %> search \"renewal\" --from acme.com",
21380
+ "<%= config.bin %> search \"kickoff\" --mode hybrid",
21381
+ "<%= config.bin %> search \"shipping\" --mode keyword --corpus outbound",
21382
+ "<%= config.bin %> search \"needle\" --json | jq '.data[0].id'"
21383
+ ];
21384
+ static args = { query: Args.string({
21385
+ description: "The search query. Matched against every indexed field (subject, body, sender, recipient) when lexical; against the embedding when semantic.",
21386
+ required: true
21387
+ }) };
21388
+ static flags = {
21389
+ "api-key": Flags.string({
21390
+ description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
21391
+ env: "PRIMITIVE_API_KEY"
21392
+ }),
21393
+ "api-base-url": Flags.string({
21394
+ description: API_BASE_URL_FLAG_DESCRIPTION,
21395
+ env: "PRIMITIVE_API_BASE_URL",
21396
+ hidden: true
21397
+ }),
21398
+ mode: Flags.string({
21399
+ description: "Switch to the cross-corpus semantic backend. Omit for the default lexical backend.",
21400
+ options: [
21401
+ "hybrid",
21402
+ "semantic",
21403
+ "keyword"
21404
+ ]
21405
+ }),
21406
+ from: Flags.string({ description: "Lexical only. Filter by sender address or sender domain." }),
21407
+ to: Flags.string({ description: "Lexical only. Filter by recipient address or recipient domain." }),
21408
+ subject: Flags.string({ description: "Lexical only. Full-text search restricted to the subject." }),
21409
+ body: Flags.string({ description: "Lexical only. Full-text search restricted to the parsed text body." }),
21410
+ domain: Flags.string({ description: "Lexical only. Filter by the recipient's mail domain." }),
21411
+ "domain-id": Flags.string({ description: "Lexical only. Filter by domain ID." }),
21412
+ "has-attachment": Flags.string({
21413
+ description: "Lexical only. Filter by whether the email has one or more attachments.",
21414
+ options: ["true", "false"]
21415
+ }),
21416
+ status: Flags.string({
21417
+ description: "Lexical only. Filter by parse status.",
21418
+ options: [
21419
+ "pending",
21420
+ "accepted",
21421
+ "completed",
21422
+ "rejected"
21423
+ ]
21424
+ }),
21425
+ sort: Flags.string({
21426
+ description: "Lexical only. Result ordering.",
21427
+ options: [
21428
+ "relevance",
21429
+ "received_at_desc",
21430
+ "received_at_asc"
21431
+ ]
21432
+ }),
21433
+ snippet: Flags.string({
21434
+ description: "Lexical only. Include match-centered subject/body highlights on each row.",
21435
+ options: ["true", "false"]
21436
+ }),
21437
+ "include-facets": Flags.string({
21438
+ description: "Lexical only. Include facet counts for sender, domain, status, and attachment presence.",
21439
+ options: ["true", "false"]
21440
+ }),
21441
+ corpus: Flags.string({
21442
+ description: "Semantic only. Restrict to inbound or outbound mail. Pass twice to include both (the default).",
21443
+ options: ["inbound", "outbound"],
21444
+ multiple: true
21445
+ }),
21446
+ "date-from": Flags.string({ description: "Only include mail at or after this ISO-8601 timestamp." }),
21447
+ "date-to": Flags.string({ description: "Only include mail at or before this ISO-8601 timestamp." }),
21448
+ limit: Flags.integer({
21449
+ description: `Maximum results to return (1-${MAX_LIMIT}, default ${DEFAULT_LIMIT}).`,
21450
+ default: DEFAULT_LIMIT,
21451
+ min: 1,
21452
+ max: MAX_LIMIT
21453
+ }),
21454
+ cursor: Flags.string({ description: "Opaque pagination cursor from a prior response's meta.cursor." }),
21455
+ json: Flags.boolean({ description: "Print the raw response envelope as JSON on STDOUT instead of the text table." }),
21456
+ envelope: Flags.boolean({ description: "Lexical text-table only. Surface the next pagination cursor (if any) on STDERR below the table. Has no effect with --json; --json already prints the full envelope including meta." }),
21457
+ time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
21458
+ };
21459
+ async run() {
21460
+ const { args, flags } = await this.parse(SearchCommand);
21461
+ await runWithTiming(flags.time, async () => {
21462
+ const { apiClient, auth, baseUrlOverridden } = await createAuthenticatedCliApiClient({
21463
+ apiKey: flags["api-key"],
21464
+ apiBaseUrl: flags["api-base-url"],
21465
+ configDir: this.config.configDir
21466
+ });
21467
+ const handleError = (error) => {
21468
+ const errorPayload = extractErrorPayload(error);
21469
+ writeErrorWithHints(errorPayload);
21470
+ surfaceUnauthorizedHint({
21471
+ auth,
21472
+ baseUrlOverridden,
21473
+ configDir: this.config.configDir,
21474
+ payload: errorPayload
21475
+ });
21476
+ process.exitCode = 1;
21477
+ };
21478
+ if (flags.mode) {
21479
+ if (flags.envelope) {
21480
+ process.stderr.write("--envelope only applies to lexical mode. Use --json for the raw semantic envelope.\n");
21481
+ process.exitCode = 2;
21482
+ return;
21483
+ }
21484
+ const incompatible = LEXICAL_ONLY_FLAGS.filter((name) => flags[name] !== void 0);
21485
+ if (incompatible.length > 0) {
21486
+ const isOne = incompatible.length === 1;
21487
+ process.stderr.write(`Flag${isOne ? "" : "s"} --${incompatible.join(", --")} only ${isOne ? "applies" : "apply"} to the lexical backend. Omit --mode to use ${isOne ? "it" : "them"}.\n`);
21488
+ process.exitCode = 2;
21489
+ return;
21490
+ }
21491
+ const result = await semanticSearch({
21492
+ client: apiClient.client,
21493
+ body: {
21494
+ query: args.query,
21495
+ mode: flags.mode,
21496
+ ...flags.corpus ? { corpus: flags.corpus } : {},
21497
+ ...flags["date-from"] ? { date_from: flags["date-from"] } : {},
21498
+ ...flags["date-to"] ? { date_to: flags["date-to"] } : {},
21499
+ limit: flags.limit,
21500
+ ...flags.cursor ? { cursor: flags.cursor } : {}
21501
+ },
21502
+ responseStyle: "fields"
21503
+ });
21504
+ if (result.error) {
21505
+ handleError(result.error);
21506
+ return;
21507
+ }
21508
+ const envelope = result.data;
21509
+ if (flags.json) {
21510
+ this.log(JSON.stringify(envelope ?? null, null, 2));
21511
+ return;
21512
+ }
21513
+ const rows = envelope?.data ?? [];
21514
+ if (rows.length === 0) {
21515
+ process.stderr.write("No matching mail.\n");
21516
+ return;
21517
+ }
21518
+ process.stderr.write(`${formatHeader()}\n`);
21519
+ for (const row of rows) this.log(formatRow(row));
21520
+ const nextCursor = envelope?.meta?.cursor ?? null;
21521
+ if (nextCursor) process.stderr.write(`\nNext page: pass --cursor ${nextCursor}\n`);
21522
+ return;
21523
+ }
21524
+ if (flags.corpus && flags.corpus.length > 0) {
21525
+ process.stderr.write("--corpus only applies to semantic mode. Pass --mode keyword|semantic|hybrid to enable it.\n");
21526
+ process.exitCode = 2;
21527
+ return;
21528
+ }
21529
+ const query = {
21530
+ q: flags.domain ? `${args.query} domain:${quoteDslValue(flags.domain)}` : args.query,
21531
+ limit: flags.limit
21532
+ };
21533
+ if (flags.from) query.from = flags.from;
21534
+ if (flags.to) query.to = flags.to;
21535
+ if (flags.subject) query.subject = flags.subject;
21536
+ if (flags.body) query.body = flags.body;
21537
+ if (flags["domain-id"]) query.domain_id = flags["domain-id"];
21538
+ if (flags["has-attachment"]) query.has_attachment = flags["has-attachment"];
21539
+ if (flags.status) query.status = flags.status;
21540
+ if (flags.sort) query.sort = flags.sort;
21541
+ if (flags.snippet) query.snippet = flags.snippet;
21542
+ if (flags["include-facets"]) query.include_facets = flags["include-facets"];
21543
+ if (flags["date-from"]) query.date_from = flags["date-from"];
21544
+ if (flags["date-to"]) query.date_to = flags["date-to"];
21545
+ if (flags.cursor) query.cursor = flags.cursor;
21546
+ const result = await searchEmails({
21547
+ client: apiClient.client,
21548
+ query,
21549
+ responseStyle: "fields"
21550
+ });
21551
+ if (result.error) {
21552
+ handleError(result.error);
21553
+ return;
21554
+ }
21555
+ const envelope = result.data;
21556
+ if (flags.json) {
21557
+ this.log(JSON.stringify(envelope ?? null, null, 2));
21558
+ return;
21559
+ }
21560
+ const rows = envelope?.data ?? [];
21561
+ if (rows.length === 0) {
21562
+ process.stderr.write("No matching mail.\n");
21563
+ return;
21564
+ }
21565
+ const idWidth = pickIdWidth(Boolean(process.stdout.isTTY));
21566
+ process.stderr.write(`${formatHeader$1(idWidth)}\n`);
21567
+ for (const row of rows) this.log(formatRow$1(row, idWidth));
21568
+ if (flags.envelope) {
21569
+ const nextCursor = envelope?.meta?.cursor ?? null;
21570
+ if (nextCursor) process.stderr.write(`\nNext page: pass --cursor ${nextCursor}\n`);
21571
+ }
21572
+ });
21573
+ }
21574
+ };
21575
+ //#endregion
21353
21576
  //#region src/oclif/commands/send.ts
21354
21577
  var SendCommand = class SendCommand extends Command {
21355
21578
  static description = `Send an outbound email. Agent-grade shortcut for \`sending send\` with sensible defaults.
@@ -21469,35 +21692,40 @@ const SIGNIN_OTP_COPY = {
21469
21692
  actionGerund: "signing in",
21470
21693
  confirmCommand: (email) => `signin otp confirm ${email} <code>`,
21471
21694
  resendCommand: (email) => `signin otp resend ${email}`,
21472
- startCommand: (email) => `signin otp ${email}`
21695
+ startCommand: (email) => `signin otp ${email}`,
21696
+ codeRequired: true
21473
21697
  };
21474
21698
  const SIGNIN_EMAIL_COPY = {
21475
21699
  actionNoun: "sign-in",
21476
21700
  actionGerund: "signing in",
21477
21701
  confirmCommand: (email) => `signin confirm ${email} <code>`,
21478
21702
  resendCommand: (email) => `signin resend ${email}`,
21479
- startCommand: (email) => `signin ${email}`
21703
+ startCommand: (email) => `signin ${email}`,
21704
+ codeRequired: true
21480
21705
  };
21481
21706
  const LOGIN_EMAIL_COPY = {
21482
21707
  actionNoun: "login",
21483
21708
  actionGerund: "logging in",
21484
21709
  confirmCommand: (email) => `login confirm ${email} <code>`,
21485
21710
  resendCommand: (email) => `login resend ${email}`,
21486
- startCommand: (email) => `login ${email}`
21711
+ startCommand: (email) => `login ${email}`,
21712
+ codeRequired: true
21487
21713
  };
21488
21714
  const LOGIN_OTP_COPY = {
21489
21715
  actionNoun: "login",
21490
21716
  actionGerund: "logging in",
21491
21717
  confirmCommand: (email) => `login otp confirm ${email} <code>`,
21492
21718
  resendCommand: (email) => `login otp resend ${email}`,
21493
- startCommand: (email) => `login otp ${email}`
21719
+ startCommand: (email) => `login otp ${email}`,
21720
+ codeRequired: true
21494
21721
  };
21495
21722
  const OTP_COPY = {
21496
21723
  actionNoun: "email-code auth",
21497
21724
  actionGerund: "authenticating",
21498
21725
  confirmCommand: (email) => `otp confirm ${email} <code>`,
21499
21726
  resendCommand: (email) => `otp resend ${email}`,
21500
- startCommand: (email) => `otp ${email}`
21727
+ startCommand: (email) => `otp ${email}`,
21728
+ codeRequired: true
21501
21729
  };
21502
21730
  function acquireCredentialsLock(configDir) {
21503
21731
  try {
@@ -22170,7 +22398,8 @@ function resolveOperationAlias(id) {
22170
22398
  const OVERRIDDEN_OPERATION_IDS = new Set([
22171
22399
  "domains:download-domain-zone-file",
22172
22400
  "functions:test-function",
22173
- "inbox:get-inbox-status"
22401
+ "inbox:get-inbox-status",
22402
+ "search:semantic-search"
22174
22403
  ]);
22175
22404
  const generatedCommands = Object.fromEntries(operationManifest.filter((operation) => !OVERRIDDEN_OPERATION_IDS.has(operationId(operation))).map((operation) => [operationId(operation), createOperationCommand(operation)]));
22176
22405
  const COMMANDS = {
@@ -22214,7 +22443,9 @@ const COMMANDS = {
22214
22443
  "emails:latest": EmailsLatestCommand,
22215
22444
  "emails:watch": EmailsWatchCommand,
22216
22445
  "emails:wait": EmailsWaitCommand,
22446
+ search: SearchCommand,
22217
22447
  "semantic-search": SemanticSearchCommand,
22448
+ "search:semantic-search": SemanticSearchCommand,
22218
22449
  "domains:zone-file": DomainsZoneFileCommand,
22219
22450
  "domains:download-domain-zone-file": DomainsZoneFileCommand,
22220
22451
  "inbox:setup": InboxSetupCommand,
@@ -113,8 +113,9 @@ function loggedOutSignupHint() {
113
113
  return [
114
114
  "New to Primitive?",
115
115
  " You or your user don't have an account yet?",
116
- " Run `primitive signup <email> --signup-code <invite-code> --accept-terms`",
117
- " to create an account, get your own domain, and get started now.",
116
+ " Run `primitive signup <email> --accept-terms`",
117
+ " to create an account and get started.",
118
+ " Add `--signup-code <code>` if you have one.",
118
119
  ""
119
120
  ].join("\n");
120
121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitivedotdev/cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -62,7 +62,8 @@
62
62
  "description": "List, inspect, and wait for received emails. Prefer task aliases like `primitive emails list`, `primitive emails get`, `primitive emails latest`, `primitive emails wait`, and `primitive emails watch`; generated API names remain available for compatibility."
63
63
  },
64
64
  "search": {
65
- "description": "Semantic, hybrid, and keyword search across received and sent mail. Use `primitive semantic-search <query>`."
65
+ "description": "Cross-corpus semantic search. Prefer `primitive search <query>` for lexical inbound search and `primitive semantic-search <query>` for meaning-aware ranking across inbound and outbound.",
66
+ "hidden": true
66
67
  },
67
68
  "sending": {
68
69
  "description": "Send outbound emails. Prefer `primitive send` for fresh sends and `primitive reply --id <inbound-id>` for replies. Use `primitive domains list` or `primitive inbox status` to find usable sender domains for --from; `primitive sending permissions` lists recipient-scope destinations you may send to."