primitive-admin 1.1.0-alpha.3 → 1.1.0-alpha.30

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 (77) hide show
  1. package/README.md +125 -21
  2. package/assets/skill/skills/primitive-platform/SKILL.md +167 -0
  3. package/dist/bin/primitive.js +192 -15
  4. package/dist/bin/primitive.js.map +1 -1
  5. package/dist/src/commands/admins.js +107 -0
  6. package/dist/src/commands/admins.js.map +1 -1
  7. package/dist/src/commands/analytics.js +464 -55
  8. package/dist/src/commands/analytics.js.map +1 -1
  9. package/dist/src/commands/apps.js +14 -0
  10. package/dist/src/commands/apps.js.map +1 -1
  11. package/dist/src/commands/auth.js +114 -4
  12. package/dist/src/commands/auth.js.map +1 -1
  13. package/dist/src/commands/blob-buckets.js +354 -0
  14. package/dist/src/commands/blob-buckets.js.map +1 -0
  15. package/dist/src/commands/collection-type-configs.js +178 -0
  16. package/dist/src/commands/collection-type-configs.js.map +1 -0
  17. package/dist/src/commands/collections.js +526 -0
  18. package/dist/src/commands/collections.js.map +1 -0
  19. package/dist/src/commands/cron-triggers.js +364 -0
  20. package/dist/src/commands/cron-triggers.js.map +1 -0
  21. package/dist/src/commands/database-types.js +462 -0
  22. package/dist/src/commands/database-types.js.map +1 -0
  23. package/dist/src/commands/databases.js +942 -57
  24. package/dist/src/commands/databases.js.map +1 -1
  25. package/dist/src/commands/documents.js +510 -2
  26. package/dist/src/commands/documents.js.map +1 -1
  27. package/dist/src/commands/email-templates.js +281 -0
  28. package/dist/src/commands/email-templates.js.map +1 -0
  29. package/dist/src/commands/env.js +260 -0
  30. package/dist/src/commands/env.js.map +1 -0
  31. package/dist/src/commands/group-type-configs.js +189 -0
  32. package/dist/src/commands/group-type-configs.js.map +1 -0
  33. package/dist/src/commands/groups.js +21 -18
  34. package/dist/src/commands/groups.js.map +1 -1
  35. package/dist/src/commands/init.js +649 -149
  36. package/dist/src/commands/init.js.map +1 -1
  37. package/dist/src/commands/integrations.js +481 -20
  38. package/dist/src/commands/integrations.js.map +1 -1
  39. package/dist/src/commands/rule-sets.js +366 -0
  40. package/dist/src/commands/rule-sets.js.map +1 -0
  41. package/dist/src/commands/secrets.js +108 -0
  42. package/dist/src/commands/secrets.js.map +1 -0
  43. package/dist/src/commands/skill.js +29 -0
  44. package/dist/src/commands/skill.js.map +1 -0
  45. package/dist/src/commands/sync.js +1735 -82
  46. package/dist/src/commands/sync.js.map +1 -1
  47. package/dist/src/commands/users.js +382 -1
  48. package/dist/src/commands/users.js.map +1 -1
  49. package/dist/src/commands/webhooks.js +386 -0
  50. package/dist/src/commands/webhooks.js.map +1 -0
  51. package/dist/src/commands/workflows.js +347 -7
  52. package/dist/src/commands/workflows.js.map +1 -1
  53. package/dist/src/lib/api-client.js +714 -23
  54. package/dist/src/lib/api-client.js.map +1 -1
  55. package/dist/src/lib/config.js +51 -53
  56. package/dist/src/lib/config.js.map +1 -1
  57. package/dist/src/lib/constants.js +3 -0
  58. package/dist/src/lib/constants.js.map +1 -0
  59. package/dist/src/lib/credentials-store.js +307 -0
  60. package/dist/src/lib/credentials-store.js.map +1 -0
  61. package/dist/src/lib/env-resolver.js +121 -0
  62. package/dist/src/lib/env-resolver.js.map +1 -0
  63. package/dist/src/lib/init-config.js +87 -0
  64. package/dist/src/lib/init-config.js.map +1 -0
  65. package/dist/src/lib/paginate.js +42 -0
  66. package/dist/src/lib/paginate.js.map +1 -0
  67. package/dist/src/lib/project-config.js +209 -0
  68. package/dist/src/lib/project-config.js.map +1 -0
  69. package/dist/src/lib/skill-installer.js +135 -0
  70. package/dist/src/lib/skill-installer.js.map +1 -0
  71. package/dist/src/lib/sync-paths.js +102 -0
  72. package/dist/src/lib/sync-paths.js.map +1 -0
  73. package/dist/src/lib/template.js +199 -17
  74. package/dist/src/lib/template.js.map +1 -1
  75. package/dist/src/lib/version-check.js +172 -0
  76. package/dist/src/lib/version-check.js.map +1 -0
  77. package/package.json +7 -4
package/README.md CHANGED
@@ -150,12 +150,13 @@ Manage users within an app.
150
150
 
151
151
  ```bash
152
152
  primitive users list [app-id] # List users
153
+ primitive users create <email> [--role admin|member] # Create/add user by email
153
154
  primitive users invite [app-id] <email> [--role admin] # Invite user
154
155
  primitive users remove [app-id] <user-id> # Remove user
155
156
  primitive users set-role [app-id] <user-id> <role> # Change role
156
157
  primitive users transfer-owner [app-id] <new-owner-id> # Transfer ownership
157
- primitive users invitations list [app-id] # List pending invitations
158
- primitive users invitations delete [app-id] <inv-id> # Delete invitation
158
+ primitive users mint-jwt <user-id> [--role <role>] # Mint test JWT (dev/test only)
159
+ primitive users invitations [app-id] # List pending invitations
159
160
  ```
160
161
 
161
162
  ### Waitlist
@@ -197,6 +198,26 @@ primitive integrations secrets add <id> --data '{"apiKey":"..."}'
197
198
  primitive integrations secrets archive <id> <secret-id>
198
199
  ```
199
200
 
201
+ ### Secrets
202
+
203
+ Manage encrypted app secrets (API keys, tokens, credentials). Values are encrypted at rest and never displayed after creation.
204
+
205
+ ```bash
206
+ primitive secrets list [--app <app-id>] # List secrets (values never shown)
207
+ primitive secrets set <KEY> --value <value> [--summary <text>] # Create or update a secret
208
+ primitive secrets delete <KEY> # Delete a secret
209
+ ```
210
+
211
+ **Examples:**
212
+ ```bash
213
+ primitive secrets set OPENAI_API_KEY --value "sk-..." --summary "Production key"
214
+ primitive secrets set STRIPE_SECRET --value "sk_live_..."
215
+ primitive secrets list --json
216
+ primitive secrets delete STRIPE_SECRET
217
+ ```
218
+
219
+ Keys must be uppercase letters, digits, and underscores (e.g., `OPENAI_API_KEY`). Max 100 secrets per app, 2 KB per value. The `set` command is an upsert — it creates or updates automatically. Use `{{secrets.KEY}}` in workflows and `secrets.KEY` in CEL rules.
220
+
200
221
  ### Prompts
201
222
 
202
223
  Manage LLM prompt configurations.
@@ -267,12 +288,13 @@ primitive tokens revoke <token-id> [app-id] # Revoke t
267
288
 
268
289
  ### Databases
269
290
 
270
- Manage online databases, permissions, and group permissions.
291
+ Manage online databases and permissions. `list` returns databases the user has direct access to; group-shared databases are listed via `primitive groups databases`.
271
292
 
272
293
  ```bash
273
- primitive databases list [app-id] # List databases
294
+ primitive databases list [app-id] # List databases (direct access)
274
295
  primitive databases create <title> [app-id] # Create database
275
296
  primitive databases get <database-id> [app-id] # Get details
297
+ primitive databases update <database-id> [options] # Update title or type
276
298
  primitive databases delete <database-id> [app-id] # Delete database
277
299
  ```
278
300
 
@@ -283,14 +305,68 @@ primitive databases permissions grant <database-id> --user-id <uid> --permission
283
305
  primitive databases permissions revoke <database-id> <user-id> [app-id]
284
306
  ```
285
307
 
286
- **Group permissions:**
308
+ Permission values: `owner` (set at creation), `manager`
309
+
310
+ **Metadata:**
311
+ ```bash
312
+ primitive databases metadata update <database-id> --data '{"key":"value"}' # Merge-update metadata
313
+ ```
314
+
315
+ **Operations:**
316
+ ```bash
317
+ primitive databases operations list <database-id> [app-id] # List registered operations
318
+ primitive databases operations execute <database-id> <op-name> --params '{}' # Execute operation
319
+ primitive databases operations execute <database-id> <op-name> --token <jwt> # Execute as specific user
320
+ ```
321
+
322
+ The `--token` flag lets you execute an operation as a specific user using a test JWT from `users mint-jwt`. Useful for testing access rules.
323
+
324
+ **Records (schema introspection):**
325
+ ```bash
326
+ primitive databases records models <database-id> [app-id] # List model names
327
+ primitive databases records describe <database-id> <model> [app-id] # Show inferred schema
328
+ ```
329
+
330
+ **Indexes:**
331
+ ```bash
332
+ primitive databases indexes list <database-id> [--model <name>] # List indexes
333
+ primitive databases indexes create <database-id> <model> <field> [options] # Create index
334
+ primitive databases indexes drop <database-id> <model> <field> # Drop index
335
+ ```
336
+
337
+ **Export / Import:**
338
+ ```bash
339
+ primitive databases export [app-id] <database-id> --output <dir> # Export records, indexes, constraints
340
+ primitive databases import [app-id] <path> --overwrite --dry-run # Import from export directory
341
+ ```
342
+
343
+ Export creates a directory with `metadata.json`, `records.jsonl`, `indexes.json`, and `constraints.json`. Import restores records and indexes into a new or existing database. Database type config (operations, triggers, access rules) is managed separately via `primitive sync` — run `sync push` on the target app before importing.
344
+
345
+ ### Documents
346
+
347
+ Manage document ownership, group permissions, and export/import.
348
+
349
+ ```bash
350
+ primitive documents transfer-owner [app-id] <document-id> <new-owner-id> # Transfer ownership
351
+ ```
352
+
353
+ **Group permissions on documents:**
354
+ ```bash
355
+ primitive documents group-permissions list <document-id>
356
+ primitive documents group-permissions grant <document-id> --group-type <type> --group-id <id> --permission <perm>
357
+ primitive documents group-permissions revoke <document-id> <group-type> <group-id>
358
+ ```
359
+
360
+ Permission values: `read-write`, `reader`
361
+
362
+ **Export / Import:**
287
363
  ```bash
288
- primitive databases group-permissions list <database-id> [app-id]
289
- primitive databases group-permissions grant <database-id> --group-type <type> --group-id <id> --permission <perm> [app-id]
290
- primitive databases group-permissions revoke <database-id> <group-type> <group-id> [app-id]
364
+ primitive documents export [app-id] <document-id> --output <dir> # Export Yjs state, blobs, permissions, aliases
365
+ primitive documents export-all [app-id] --user-id <id> --owned-only # Export all docs for a user
366
+ primitive documents import [app-id] <path> --overwrite --aliases overwrite|skip --dry-run # Import from export
291
367
  ```
292
368
 
293
- Permission values: `owner`, `read-write`, `reader`
369
+ Export creates a directory per document with `metadata.json`, `document.yjs` (Yjs state), `permissions.json` (for reference), and `blobs/` (attachments). Permissions are exported for reference but not restored during import — the importing admin is the new owner and manages sharing in the target app. Document IDs are preserved across import. User-scoped aliases can be restored with `--aliases overwrite` (update existing) or `--aliases skip` (keep existing, default).
294
370
 
295
371
  ### Groups
296
372
 
@@ -317,20 +393,46 @@ primitive groups members set-role <group-type> <group-id> <user-id> <role> [app-
317
393
  primitive groups memberships <user-id> [app-id] # List user's group memberships
318
394
  ```
319
395
 
396
+ **Group resource access:**
397
+ ```bash
398
+ primitive groups documents <group-type> <group-id> # List documents a group can access
399
+ ```
400
+
401
+ Group permissions on documents are managed via `primitive documents group-permissions` (see [Documents](#documents) above).
402
+
320
403
  ### Analytics
321
404
 
322
405
  View usage analytics for an app.
323
406
 
324
407
  ```bash
325
- primitive analytics overview [app-id] # Activity overview
326
- primitive analytics top-users [app-id] # Most active users
327
- primitive analytics user [app-id] <user-ulid> # User activity details
328
- primitive analytics integrations [app-id] # Integration metrics
408
+ # Overview & active users
409
+ primitive analytics overview [app-id] # DAU / WAU / MAU + growth
410
+ primitive analytics daily-active [app-id] # Daily active users time series
411
+ primitive analytics rolling-active [app-id] # Rolling active users (28 points)
412
+ primitive analytics cohort-retention [app-id] # Weekly cohort retention matrix
413
+
414
+ # Users
415
+ primitive analytics top-users [app-id] # Most active users
416
+ primitive analytics user-search [app-id] --query <q> # Search by email or ULID
417
+ primitive analytics user-detail <user-ulid> [app-id] # User activity breakdown
418
+ primitive analytics user-snapshot <user-ulid> [app-id] # Latest context snapshot
419
+
420
+ # Events
421
+ primitive analytics events [app-id] # Paginated event feed
422
+ primitive analytics events-grouped [app-id] # Events grouped by dimension
423
+
424
+ # Features
425
+ primitive analytics integrations [app-id] # Integration usage metrics
426
+ primitive analytics workflows [app-id] # Top workflows by runs
427
+ primitive analytics prompts [app-id] # Top prompts by executions
329
428
  ```
330
429
 
331
- **Options:**
332
- - `--window-days <n>` - Time window (default: 30)
333
- - `--limit <n>` - Result limit for top-users
430
+ **Common options:**
431
+ - `--window-days <n>` - Time window in days (default varies per command)
432
+ - `--limit <n>` - Result limit (top-users, workflows, prompts)
433
+ - `--group-by <dim>` - Dimension for events-grouped (action, feature, route, country, deviceType, plan, day)
434
+ - `--page <n>` - Page number for events feed (0-based)
435
+ - `--json` - Output raw JSON
334
436
 
335
437
  ### Admins (Super-Admin Only)
336
438
 
@@ -545,11 +647,13 @@ cli/tests/
545
647
  config.test.ts # Credentials and config management
546
648
  output.test.ts # Output formatting functions
547
649
  integration/
548
- api-client.test.ts # API client HTTP tests
549
- commands.test.ts # CLI command tests
550
- tokens.test.ts # Token lifecycle tests
551
- databases.test.ts # Database CRUD, permissions, group permissions tests
552
- groups.test.ts # Group CRUD, members, memberships tests
650
+ api-client.test.ts # API client HTTP tests
651
+ commands.test.ts # CLI command tests
652
+ tokens.test.ts # Token lifecycle tests
653
+ databases.test.ts # Database CRUD, permissions, group permissions tests
654
+ documents.test.ts # Document group permissions, group resource listing tests
655
+ groups.test.ts # Group CRUD, members, memberships tests
656
+ classroom-e2e.test.ts # End-to-end classroom app workflow (types, rules, operations, access)
553
657
  ```
554
658
 
555
659
  ## Troubleshooting
@@ -0,0 +1,167 @@
1
+ ---
2
+ name: primitive-platform
3
+ description: >
4
+ Expert guide for building applications on the Primitive platform. MUST be used whenever the user
5
+ is writing code that uses js-bao, js-bao-wss-client, primitive-app components, or any Primitive
6
+ platform feature (documents, databases, workflows, prompts, integrations, blobs, authentication,
7
+ users/groups). Also trigger whenever about to run any `primitive` CLI command (e.g., primitive sync, primitive integrations, primitive apps, primitive use) to ensure Step 0 CLI verification is performed first. After writing or modifying code that touches Primitive
8
+ APIs, this skill cross-references the implementation against official guides and automatically
9
+ corrects common mistakes. Use this skill even if the user doesn't explicitly ask for it —
10
+ any Primitive-related code should be validated against current best practices.
11
+ allowed-tools: Bash, Read, Edit, Write, Glob, Grep, Agent
12
+ ---
13
+
14
+ # Primitive Platform Development Guide
15
+
16
+ You are an expert on the Primitive platform. Your job is to help developers write correct,
17
+ idiomatic Primitive code by leveraging the CLI's built-in guide system and enforcing best practices.
18
+
19
+ **The CLI guides are the single source of truth.** Never hardcode or memorize guide content —
20
+ always fetch the latest from the CLI.
21
+
22
+ ## Step 0: Verify CLI Configuration
23
+
24
+ The Primitive CLI maintains state for the **currently active server endpoint and app**. Before
25
+ running any CLI commands, confirm you're targeting the correct environment:
26
+
27
+ 1. **Check for a `.env` file** in the project root (e.g., `.env`, `.env.local`, `.env.development`).
28
+ It typically contains `PRIMITIVE_API_URL` or similar variables that set the server endpoint,
29
+ and may reference a specific app ID.
30
+ 2. **Run a CLI command and read its output.** The CLI prints the active server URL and app context
31
+ at the top of most command outputs — verify these match the project's intended environment.
32
+ 3. **Use inspection commands** to confirm current state:
33
+
34
+ ```bash
35
+ primitive whoami # Shows authenticated user, app ID, and server endpoint
36
+ ```
37
+
38
+ **Why this matters:** If the CLI is pointed at the wrong server (e.g., production instead of
39
+ development) or the wrong app, commands like `primitive sync push` will modify the wrong
40
+ environment. Always verify before running mutating operations.
41
+
42
+ ## Step 1: Discover Available Guides
43
+
44
+ Before writing or reviewing any Primitive code, run:
45
+
46
+ ```bash
47
+ primitive guides list
48
+ ```
49
+
50
+ This returns the full list of available guide topics with descriptions, keywords, and use cases.
51
+ Use this output to determine which guides are relevant to the current task.
52
+
53
+ ## Step 2: Fetch the Relevant Guides
54
+
55
+ For each relevant topic identified in Step 1, fetch the full guide:
56
+
57
+ ```bash
58
+ primitive guides get <topic>
59
+ ```
60
+
61
+ **Always fetch guide(s) BEFORE writing code.** If multiple features are involved, fetch multiple
62
+ guides. The guides contain:
63
+ - Complete API documentation with method signatures
64
+ - Working code examples (TypeScript/JavaScript)
65
+ - Common patterns and anti-patterns
66
+ - Configuration examples (TOML files for `primitive sync`)
67
+ - Decision frameworks for architecture choices
68
+
69
+ **Do not guess or assume API patterns.** If you're unsure about a method signature, parameter,
70
+ or pattern, fetch the guide. The guides are comprehensive and authoritative.
71
+
72
+ ## Step 3: Write Code Following Guide Patterns
73
+
74
+ When writing Primitive code:
75
+
76
+ 1. **Follow the patterns from the fetched guides exactly** — method names, argument order, lifecycle patterns
77
+ 2. **Use `primitive sync`** for all backend configuration (workflows, prompts, integrations, databases)
78
+ 3. **Configuration lives in TOML files** in version control, pushed via `primitive sync push`
79
+ 4. **Run `pnpm codegen`** after creating or modifying js-bao models
80
+
81
+ ## Step 4: Post-Code Review (Automatic)
82
+
83
+ After writing or modifying Primitive-related code, **automatically perform this review**:
84
+
85
+ ### 4a. Identify What Was Written
86
+ Determine which Primitive features the new/modified code touches by scanning for:
87
+ - Import statements from `js-bao`, `js-bao-wss-client`, or `primitive-app`
88
+ - Primitive API calls (documents.open, databases.connect, workflows, etc.)
89
+ - Model definitions, schemas, queries
90
+ - Configuration files (TOML for sync)
91
+
92
+ ### 4b. Fetch and Cross-Reference
93
+ Run `primitive guides list` to identify which guides cover the features used, then fetch each one:
94
+ ```bash
95
+ primitive guides get <topic>
96
+ ```
97
+
98
+ Compare the written code against the guide content:
99
+ - **API usage patterns** — Are methods called correctly with proper arguments?
100
+ - **Lifecycle management** — Are documents opened before queries? Is auth checked first?
101
+ - **Access control** — Are CEL expressions or permissions configured properly?
102
+ - **Anti-patterns** — Does the code do anything the guide explicitly warns against?
103
+ - **Missing steps** — Does the code need `pnpm codegen`, `primitive sync push`, or other follow-up?
104
+
105
+ ### 4c. Report and Fix
106
+ If issues are found:
107
+ 1. **Explain the issue** — cite the specific guide section that applies
108
+ 2. **Show the fix** — provide corrected code
109
+ 3. **Apply the fix** — edit the file directly (don't just suggest, actually fix it)
110
+ 4. **Note any CLI commands needed** — e.g., `pnpm codegen` or `primitive sync push`
111
+
112
+ If no issues are found, briefly confirm the code follows best practices.
113
+
114
+ ## CLI Quick Reference
115
+
116
+ Remind users of these essential commands when relevant:
117
+
118
+ ```bash
119
+ # Verify current configuration (DO THIS FIRST)
120
+ primitive whoami # Check authenticated user, app ID, and server endpoint
121
+ primitive status # Check active app context and server
122
+ # Also check .env / .env.local / .env.development in the project for
123
+ # PRIMITIVE_API_URL or app ID settings — these control which server the CLI targets.
124
+
125
+ # Setup
126
+ npm install -g primitive-admin # Install CLI
127
+ primitive login # Authenticate
128
+ primitive use "My App" # Set app context
129
+
130
+ # Guides (the most important commands for development)
131
+ primitive guides list # See all available guides with topics and descriptions
132
+ primitive guides get <topic> # Read detailed guide for a specific topic
133
+
134
+ # Configuration as Code
135
+ primitive sync init --dir ./config # Initialize config directory
136
+ primitive sync pull --dir ./config # Pull config from server
137
+ primitive sync push --dir ./config # Push config to server
138
+ primitive sync diff --dir ./config # Preview changes before push
139
+
140
+ # Common operations
141
+ primitive apps list # List apps
142
+ primitive apps create "Name" # Create app
143
+ ```
144
+
145
+ ## When the User is Starting a New Feature
146
+
147
+ If the user describes a new feature they want to build:
148
+
149
+ 1. **Verify CLI configuration** per Step 0 — confirm the server endpoint and app ID match the
150
+ project's intended environment before running any commands
151
+ 2. **Run `primitive guides list`** to discover available topics
152
+ 3. **Identify which guides are relevant** to their feature from the list output
153
+ 4. **Fetch those guides** with `primitive guides get <topic>`
154
+ 5. **Recommend a data modeling approach** based on the guide content. If requirements are unclear or ambiguous, **ask the user clarifying questions before proceeding** — it's much easier to get the data model right upfront than to migrate later
155
+ 6. **Outline the implementation steps** referencing specific patterns from the guides
156
+ 7. **Write the code** following the patterns exactly
157
+ 8. **Review automatically** per Step 4 above
158
+
159
+ ## When the User Asks "How Do I...?"
160
+
161
+ For any question about Primitive platform capabilities:
162
+
163
+ 1. **Run `primitive guides list`** to find the relevant topic
164
+ 2. **Fetch the guide**: `primitive guides get <topic>`
165
+ 3. **Answer from the guide content** — don't guess or make up APIs
166
+ 4. **Include working code examples** from the guide
167
+ 5. **Point the user to the guide** for further reading: "You can see more examples by running `primitive guides get <topic>`"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from "commander";
2
+ import { Command, CommanderError } from "commander";
3
3
  import { readFileSync } from "fs";
4
4
  import { fileURLToPath } from "url";
5
5
  import { dirname, resolve } from "path";
@@ -9,6 +9,8 @@ import { registerAppsCommands } from "../src/commands/apps.js";
9
9
  import { registerUsersCommands } from "../src/commands/users.js";
10
10
  import { registerWaitlistCommands } from "../src/commands/waitlist.js";
11
11
  import { registerIntegrationsCommands } from "../src/commands/integrations.js";
12
+ import { registerWebhooksCommands } from "../src/commands/webhooks.js";
13
+ import { registerCronTriggersCommands } from "../src/commands/cron-triggers.js";
12
14
  import { registerPromptsCommands } from "../src/commands/prompts.js";
13
15
  import { registerWorkflowsCommands } from "../src/commands/workflows.js";
14
16
  import { registerAdminsCommands } from "../src/commands/admins.js";
@@ -20,46 +22,189 @@ import { registerComparisonsCommands } from "../src/commands/comparisons.js";
20
22
  import { registerTokensCommands } from "../src/commands/tokens.js";
21
23
  import { registerDatabasesCommands } from "../src/commands/databases.js";
22
24
  import { registerGroupsCommands } from "../src/commands/groups.js";
25
+ import { registerRuleSetsCommands } from "../src/commands/rule-sets.js";
26
+ import { registerGroupTypeConfigsCommands } from "../src/commands/group-type-configs.js";
27
+ import { registerDatabaseTypesCommands } from "../src/commands/database-types.js";
23
28
  import { registerGuidesCommands } from "../src/commands/guides.js";
24
29
  import { registerDocumentsCommands } from "../src/commands/documents.js";
30
+ import chalk from "chalk";
31
+ import { registerEmailTemplatesCommands } from "../src/commands/email-templates.js";
32
+ import { registerCollectionsCommands } from "../src/commands/collections.js";
33
+ import { registerCollectionTypeConfigsCommands } from "../src/commands/collection-type-configs.js";
25
34
  import { error } from "../src/lib/output.js";
26
35
  import { ApiError } from "../src/lib/api-client.js";
36
+ import { checkForUpdate } from "../src/lib/version-check.js";
37
+ import { loadCredentials } from "../src/lib/config.js";
38
+ import { checkSkillStatus } from "../src/lib/skill-installer.js";
39
+ import { registerSkillCommands } from "../src/commands/skill.js";
40
+ import { registerSecretsCommands } from "../src/commands/secrets.js";
41
+ import { registerBlobBucketsCommands } from "../src/commands/blob-buckets.js";
42
+ import { registerEnvCommands } from "../src/commands/env.js";
43
+ import { setCurrentEnvName, getCurrentEnvNameSafe, getProjectConfig, } from "../src/lib/env-resolver.js";
44
+ import { ProjectConfigError, PROJECT_CONFIG_DISPLAY_NAME, findProjectConfigPath } from "../src/lib/project-config.js";
27
45
  const __filename = fileURLToPath(import.meta.url);
28
46
  const __dirname = dirname(__filename);
29
47
  const pkg = JSON.parse(readFileSync(resolve(__dirname, "../../package.json"), "utf-8"));
48
+ const isVersionFlag = process.argv.includes("--version") || process.argv.includes("-V");
49
+ const subcommand = process.argv[2];
50
+ const isJsonOutput = process.argv.includes("--json");
51
+ const skipHeader = isVersionFlag || isJsonOutput || subcommand === "login" || subcommand === "logout" || subcommand === "token";
52
+ // --env <name> is a global option that must be applied BEFORE any command
53
+ // code runs, because loadCredentials() and getServerUrl() both consult the
54
+ // active environment. Commander only parses options during .parse(), so we
55
+ // pre-extract it here via a tiny manual scan. The actual option is still
56
+ // registered on the program below so it appears in --help.
57
+ function preParseEnvFlag() {
58
+ const argv = process.argv;
59
+ for (let i = 2; i < argv.length; i++) {
60
+ const a = argv[i];
61
+ if (a === "--env" || a === "-e") {
62
+ return argv[i + 1] || null;
63
+ }
64
+ if (a.startsWith("--env="))
65
+ return a.slice("--env=".length);
66
+ }
67
+ return null;
68
+ }
69
+ const preParsedEnv = preParseEnvFlag();
70
+ if (preParsedEnv) {
71
+ setCurrentEnvName(preParsedEnv);
72
+ }
73
+ // Surface project-config errors loudly and early. A broken config file
74
+ // should fail fast with a clear message rather than producing cryptic
75
+ // "Not logged in" errors deeper in.
76
+ try {
77
+ getProjectConfig();
78
+ }
79
+ catch (err) {
80
+ if (err instanceof ProjectConfigError) {
81
+ error(err.message);
82
+ if (err.path)
83
+ error(` at ${err.path}`);
84
+ process.exit(1);
85
+ }
86
+ throw err;
87
+ }
88
+ // If the user explicitly passed --env <name>, verify it resolves to a
89
+ // real environment NOW so we don't silently fall back to legacy creds.
90
+ if (preParsedEnv) {
91
+ try {
92
+ const project = getProjectConfig();
93
+ if (!project) {
94
+ error(`--env was given but no ${PROJECT_CONFIG_DISPLAY_NAME} was found in this directory or any parent.`);
95
+ process.exit(1);
96
+ }
97
+ if (!project.environments[preParsedEnv]) {
98
+ const available = Object.keys(project.environments).join(", ") || "(none)";
99
+ error(`Environment "${preParsedEnv}" is not defined in ${PROJECT_CONFIG_DISPLAY_NAME}. Available: ${available}`);
100
+ process.exit(1);
101
+ }
102
+ }
103
+ catch (err) {
104
+ if (err instanceof ProjectConfigError) {
105
+ error(err.message);
106
+ process.exit(1);
107
+ }
108
+ throw err;
109
+ }
110
+ }
111
+ if (!skipHeader) {
112
+ const creds = loadCredentials();
113
+ // In project mode the env may declare an appId even before login.
114
+ // Show that so the header is useful during `env add` / `login` flows.
115
+ const envNameForHeader = getCurrentEnvNameSafe();
116
+ let headerAppId = creds?.currentAppId;
117
+ let headerAppName = creds?.currentAppName;
118
+ if (envNameForHeader && (!headerAppId || !headerAppName)) {
119
+ try {
120
+ const envCfg = getProjectConfig()?.environments[envNameForHeader];
121
+ headerAppId = headerAppId || envCfg?.appId;
122
+ headerAppName = headerAppName || envCfg?.appName;
123
+ }
124
+ catch {
125
+ // ignore
126
+ }
127
+ }
128
+ const appInfo = headerAppName
129
+ ? `${headerAppName} (${headerAppId})`
130
+ : headerAppId || "None set";
131
+ // Prefer the active environment's apiUrl so the header stays correct
132
+ // even before you've logged in. Only fall back to credentials' serverUrl
133
+ // in legacy mode.
134
+ let server = creds?.serverUrl;
135
+ if (envNameForHeader) {
136
+ try {
137
+ const env = getProjectConfig()?.environments[envNameForHeader];
138
+ if (env)
139
+ server = env.apiUrl;
140
+ }
141
+ catch {
142
+ // fall through
143
+ }
144
+ }
145
+ server = server || "Not configured";
146
+ const projectConfigPath = findProjectConfigPath();
147
+ const envLabel = envNameForHeader
148
+ ? ` | Env: ${envNameForHeader}`
149
+ : projectConfigPath
150
+ ? " | Env: (none selected)"
151
+ : "";
152
+ console.log(chalk.dim(`CLI Version: ${pkg.version}${envLabel} | App: ${appInfo} | Server: ${server}`));
153
+ console.log();
154
+ }
30
155
  const program = new Command();
31
156
  program
32
157
  .name("primitive")
158
+ .exitOverride()
33
159
  .description(`CLI for administering Primitive applications.
34
160
 
35
161
  Manage apps, users, integrations, prompts, workflows, and more from the command line.
36
162
  Supports TOML-based configuration sync for version-controlled app settings.`)
37
163
  .version(pkg.version)
164
+ // Global --env flag. Parsed above in preParseEnvFlag too; declaring it
165
+ // here so commander shows it in help output and forwards it to
166
+ // subcommands.
167
+ .option("-e, --env <name>", "Named environment from .primitive/config.json (e.g. dev, prod)")
38
168
  .addHelpText("after", `
39
169
  Examples:
40
- $ primitive login # Authenticate via browser OAuth
41
- $ primitive use "My App" # Set working app context
42
- $ primitive users list # List users (uses current app)
43
- $ primitive integrations list --json # JSON output for scripting
44
- $ primitive sync pull --dir ./config # Export config to TOML files
170
+ $ primitive init my-app # Scaffold a new project + .primitive/config.json
171
+ $ primitive env list # Show environments
172
+ $ primitive env add prod --api-url ... # Add a new environment
173
+ $ primitive --env prod users list # Run a command against a specific env
174
+ $ primitive login # Authenticate via browser OAuth
175
+ $ primitive sync pull # Pull config (auto per-env path)
45
176
 
46
- Authentication:
47
- Credentials are stored in ~/.primitive/credentials.json
177
+ Project configuration (.primitive/config.json):
178
+ In a directory with a .primitive/config.json (or any subdirectory of one),
179
+ the CLI operates in project mode: credentials and sync state live under
180
+ <projectRoot>/.primitive/ and each named environment is isolated.
181
+ Without a .primitive/config.json the CLI runs in legacy mode, reading
182
+ credentials from ~/.primitive/credentials.json.
183
+
184
+ Environment selection (project mode):
185
+ 1. --env <name> flag
186
+ 2. PRIMITIVE_ENV env var
187
+ 3. "defaultEnvironment" in .primitive/config.json
188
+ 4. The only environment, if there's exactly one
48
189
 
49
190
  App Context:
50
- Set with 'primitive use <app>' to avoid passing --app to every command.
51
- Most commands accept --app flag to override the current context.
191
+ Bind an app to an environment via "appId" in .primitive/config.json, or
192
+ run 'primitive use <app>' to set one in credentials. Most commands accept
193
+ --app to override.
52
194
 
53
195
  Documentation:
54
196
  See https://primitive-labs.github.io/primitive-docs/ for full documentation.
55
197
  `);
56
198
  // Register all command groups (init first, then logically grouped)
57
199
  registerInitCommand(program);
200
+ registerEnvCommands(program);
58
201
  registerAuthCommands(program);
59
202
  registerAppsCommands(program);
60
203
  registerUsersCommands(program);
61
204
  registerWaitlistCommands(program);
62
205
  registerIntegrationsCommands(program);
206
+ registerWebhooksCommands(program);
207
+ registerCronTriggersCommands(program);
63
208
  registerPromptsCommands(program);
64
209
  registerWorkflowsCommands(program);
65
210
  registerAdminsCommands(program);
@@ -71,24 +216,56 @@ registerComparisonsCommands(program);
71
216
  registerTokensCommands(program);
72
217
  registerDatabasesCommands(program);
73
218
  registerGroupsCommands(program);
219
+ registerRuleSetsCommands(program);
220
+ registerGroupTypeConfigsCommands(program);
221
+ registerDatabaseTypesCommands(program);
74
222
  registerGuidesCommands(program);
75
223
  registerDocumentsCommands(program);
224
+ registerEmailTemplatesCommands(program);
225
+ registerCollectionsCommands(program);
226
+ registerCollectionTypeConfigsCommands(program);
227
+ registerSkillCommands(program);
228
+ registerSecretsCommands(program);
229
+ registerBlobBucketsCommands(program);
76
230
  // Global error handler
77
231
  program.hook("preAction", () => {
78
232
  // Reset API client state before each command
79
233
  });
234
+ // Commands that should never show post-command messages (update check, skill status)
235
+ const suppressPostMessages = isJsonOutput || subcommand === "token";
236
+ async function runPostCommandMessages() {
237
+ if (suppressPostMessages)
238
+ return;
239
+ // Claude Code skill: auto-update if installed, or show hint if not.
240
+ // Skip for `init` (handles its own prompt), `skill` (explicit management),
241
+ // and non-interactive contexts (--json, --version, token, etc.).
242
+ if (!skipHeader && subcommand !== "skill" && subcommand !== "init") {
243
+ await checkSkillStatus();
244
+ }
245
+ await checkForUpdate(pkg.version);
246
+ }
80
247
  // Parse and execute
81
- program.parseAsync(process.argv).catch((err) => {
248
+ program.parseAsync(process.argv)
249
+ .then(async () => {
250
+ await runPostCommandMessages();
251
+ })
252
+ .catch(async (err) => {
253
+ // Commander throws CommanderError for help display, version flag, etc.
254
+ // Run post-command messages then exit with the intended code.
255
+ if (err instanceof CommanderError) {
256
+ await runPostCommandMessages();
257
+ process.exit(err.exitCode);
258
+ }
82
259
  if (err instanceof ApiError) {
83
260
  error(err.message);
84
261
  if (err.statusCode === 401) {
85
262
  error("Try running 'primitive login' to authenticate.");
86
263
  }
264
+ await runPostCommandMessages();
87
265
  process.exit(err.statusCode === 401 ? 2 : 1);
88
266
  }
89
- else {
90
- error(err.message || "An unexpected error occurred");
91
- process.exit(1);
92
- }
267
+ error(err.message || "An unexpected error occurred");
268
+ await runPostCommandMessages();
269
+ process.exit(1);
93
270
  });
94
271
  //# sourceMappingURL=primitive.js.map