@griffin-app/griffin-cli 1.0.3 → 1.0.4

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
@@ -35,18 +35,12 @@ This creates `.griffin/state.json` which tracks:
35
35
 
36
36
  Override project ID with `--project <name>`.
37
37
 
38
- ### 2. Configure Targets
39
-
40
- Add targets to your local environment:
41
-
42
- ```bash
43
- griffin local config add-target --env local --key api --url http://localhost:3000
44
- ```
38
+ ### 2. View Environments
45
39
 
46
40
  View configured environments:
47
41
 
48
42
  ```bash
49
- griffin local config list
43
+ griffin env list
50
44
  ```
51
45
 
52
46
  ### 3. Create Test Plans
@@ -56,10 +50,10 @@ Create test files in `__griffin__/` directories. These files export test plans t
56
50
  ### 4. Run Tests Locally
57
51
 
58
52
  ```bash
59
- griffin local run --env local
53
+ griffin local run local
60
54
  ```
61
55
 
62
- Executes tests locally against configured targets.
56
+ Executes tests locally using variables from `variables.yaml` for the specified environment.
63
57
 
64
58
  ### 5. Connect to Hub (Optional)
65
59
 
@@ -71,32 +65,35 @@ griffin hub connect --url https://hub.example.com --token <token>
71
65
 
72
66
  ```bash
73
67
  griffin hub plan
68
+ griffin hub plan production
74
69
  ```
75
70
 
76
- Shows what will be created, updated, or deleted on the hub.
71
+ Shows what will be created, updated, or deleted on the hub for the specified environment.
77
72
 
78
73
  ### 7. Apply to Hub
79
74
 
80
75
  ```bash
81
76
  griffin hub apply
77
+ griffin hub apply production
82
78
  ```
83
79
 
84
- Syncs plans to the hub.
80
+ Syncs plans to the hub for the specified environment.
85
81
 
86
82
  ### 8. Trigger Hub Run
87
83
 
88
84
  ```bash
89
- griffin hub run --plan <name> --env production
85
+ griffin hub run production --plan <name>
90
86
  ```
91
87
 
92
- Triggers a plan execution on the hub.
88
+ Triggers a plan execution on the hub in the specified environment.
93
89
 
94
90
  ## Commands
95
91
 
96
- Commands are organized into three groups:
92
+ Commands are organized into four groups:
97
93
 
98
94
  - **Top-level**: Project initialization and utilities
99
- - **local**: Local test execution and configuration
95
+ - **env**: Environment management
96
+ - **local**: Local test execution
100
97
  - **hub**: Hub operations (plan sync, remote execution)
101
98
 
102
99
  ### Top-Level Commands
@@ -136,78 +133,34 @@ Generate a cryptographically secure API key for authentication.
136
133
  griffin generate-key
137
134
  ```
138
135
 
139
- ### Local Commands
140
-
141
- #### `griffin local run`
142
-
143
- Run tests locally against configured targets.
144
-
145
- **Options:**
146
-
147
- - `--env <name>` - Environment to run against (uses default if not specified)
136
+ ### Environment Commands
148
137
 
149
- **Example:**
138
+ #### `griffin env list`
150
139
 
151
- ```bash
152
- griffin local run
153
- griffin local run --env staging
154
- ```
155
-
156
- #### `griffin local config list`
157
-
158
- List all local environments and their targets.
140
+ List all available environments.
159
141
 
160
142
  **Example:**
161
143
 
162
144
  ```bash
163
- griffin local config list
145
+ griffin env list
164
146
  ```
165
147
 
166
- #### `griffin local config add-target`
148
+ Shows all configured environments with an asterisk (*) marking the default environment.
167
149
 
168
- Add a target to a local environment.
169
-
170
- **Options:**
171
-
172
- - `--env <name>` - Environment name (required)
173
- - `--key <key>` - Target key (required)
174
- - `--url <url>` - Target URL (required)
175
-
176
- **Example:**
177
-
178
- ```bash
179
- griffin local config add-target --env local --key api --url http://localhost:3000
180
- griffin local config add-target --env staging --key billing --url http://localhost:3001
181
- ```
182
-
183
- #### `griffin local config remove-target`
150
+ ### Local Commands
184
151
 
185
- Remove a target from a local environment.
152
+ #### `griffin local run [env]`
186
153
 
187
- **Options:**
188
-
189
- - `--env <name>` - Environment name (required)
190
- - `--key <key>` - Target key (required)
154
+ Run tests locally against an environment. Environment can be specified as a positional argument, or uses the default environment if omitted.
191
155
 
192
156
  **Example:**
193
157
 
194
158
  ```bash
195
- griffin local config remove-target --env local --key api
159
+ griffin local run
160
+ griffin local run staging
196
161
  ```
197
162
 
198
- #### `griffin local config set-default-env`
199
-
200
- Set the default environment for local runs.
201
-
202
- **Options:**
203
-
204
- - `--env <name>` - Environment name (required)
205
-
206
- **Example:**
207
-
208
- ```bash
209
- griffin local config set-default-env --env local
210
- ```
163
+ Variables are loaded from `variables.yaml` for the specified environment.
211
164
 
212
165
  ### Hub Commands
213
166
 
@@ -252,20 +205,20 @@ griffin hub runs
252
205
  griffin hub runs --plan health-check --limit 5
253
206
  ```
254
207
 
255
- #### `griffin hub plan`
208
+ #### `griffin hub plan [env]`
256
209
 
257
- Show what changes would be applied to the hub.
210
+ Show what changes would be applied to the hub. Environment can be specified as a positional argument, or uses the default environment if omitted.
258
211
 
259
212
  **Options:**
260
213
 
261
- - `--env <name>` - Environment to plan for (uses default if not specified)
262
214
  - `--json` - Output in JSON format
263
215
 
264
216
  **Example:**
265
217
 
266
218
  ```bash
267
219
  griffin hub plan
268
- griffin hub plan --env production --json
220
+ griffin hub plan production
221
+ griffin hub plan staging --json
269
222
  ```
270
223
 
271
224
  **Exit codes:**
@@ -274,89 +227,43 @@ griffin hub plan --env production --json
274
227
  - `1` - Error
275
228
  - `2` - Changes pending
276
229
 
277
- #### `griffin hub apply`
230
+ #### `griffin hub apply [env]`
278
231
 
279
- Apply changes to the hub.
232
+ Apply changes to the hub. Environment can be specified as a positional argument, or uses the default environment if omitted.
280
233
 
281
234
  **Options:**
282
235
 
283
- - `--env <name>` - Environment to apply to (uses default if not specified)
284
236
  - `--auto-approve` - Skip confirmation prompt
285
237
  - `--dry-run` - Show what would be done without making changes
238
+ - `--prune` - Delete plans on hub that don't exist locally
286
239
 
287
240
  **Example:**
288
241
 
289
242
  ```bash
290
243
  griffin hub apply
291
- griffin hub apply --env production --auto-approve
292
- griffin hub apply --dry-run
244
+ griffin hub apply production --auto-approve
245
+ griffin hub apply staging --dry-run
246
+ griffin hub apply production --prune
293
247
  ```
294
248
 
295
- #### `griffin hub run`
249
+ #### `griffin hub run <env>`
296
250
 
297
- Trigger a plan run on the hub.
251
+ Trigger a plan run on the hub in the specified environment.
298
252
 
299
253
  **Options:**
300
254
 
301
255
  - `--plan <name>` - Plan name to run (required)
302
- - `--env <name>` - Target environment (required)
303
256
  - `--wait` - Wait for run to complete
257
+ - `--force` - Run even if local plan differs from hub
304
258
 
305
259
  **Example:**
306
260
 
307
261
  ```bash
308
- griffin hub run --plan health-check --env production
309
- griffin hub run --plan health-check --env staging --wait
310
- ```
311
-
312
- #### `griffin hub config list`
313
-
314
- List all hub target configurations.
315
-
316
- **Options:**
317
-
318
- - `--org <id>` - Filter by organization ID
319
- - `--env <name>` - Filter by environment name
320
-
321
- **Example:**
322
-
323
- ```bash
324
- griffin hub config list
325
- griffin hub config list --org acme --env production
262
+ griffin hub run production --plan health-check
263
+ griffin hub run staging --plan health-check --wait
264
+ griffin hub run production --plan api-check --force
326
265
  ```
327
266
 
328
- #### `griffin hub config add-target`
329
-
330
- Add a target to hub configuration.
331
-
332
- **Options:**
333
-
334
- - `--org <id>` - Organization ID (required)
335
- - `--env <name>` - Environment name (required)
336
- - `--key <key>` - Target key (required)
337
- - `--url <url>` - Target URL (required)
338
-
339
- **Example:**
340
-
341
- ```bash
342
- griffin hub config add-target --org acme --env production --key api --url https://api.example.com
343
- ```
344
-
345
- #### `griffin hub config remove-target`
346
-
347
- Remove a target from hub configuration.
348
-
349
- **Options:**
350
-
351
- - `--org <id>` - Organization ID (required)
352
- - `--env <name>` - Environment name (required)
353
- - `--key <key>` - Target key (required)
354
-
355
- **Example:**
356
-
357
- ```bash
358
- griffin hub config remove-target --org acme --env production --key api
359
- ```
360
267
 
361
268
  ## Configuration
362
269
 
@@ -370,15 +277,10 @@ Griffin stores configuration in `.griffin/state.json`:
370
277
 
371
278
  ```json
372
279
  {
373
- "stateVersion": 3,
280
+ "stateVersion": 1,
374
281
  "projectId": "my-project",
375
282
  "environments": {
376
- "local": {
377
- "targets": {
378
- "api": "http://localhost:3000",
379
- "billing": "http://localhost:3001"
380
- }
381
- }
283
+ "local": {}
382
284
  },
383
285
  "defaultEnvironment": "local",
384
286
  "runner": {
@@ -388,37 +290,43 @@ Griffin stores configuration in `.griffin/state.json`:
388
290
  "discovery": {
389
291
  "pattern": "**/__griffin__/*.{ts,js}",
390
292
  "ignore": ["node_modules/**", "dist/**"]
391
- },
392
- "plans": {
393
- "local": []
394
293
  }
395
294
  }
396
295
  ```
397
296
 
398
297
  **Important:** Add `.griffin/` to `.gitignore` as it contains local state and potentially sensitive tokens.
399
298
 
400
- ## Environments and Targets
299
+ ## Environments and Variables
401
300
 
402
- Griffin uses environments to organize target configurations. Each environment contains multiple named targets (key-value pairs of target keys to URLs).
301
+ Griffin uses environments to organize test configurations. Each environment maps to a section in `variables.yaml` which contains environment-specific variable values.
403
302
 
404
- **Local environments:**
303
+ **Example `variables.yaml`:**
405
304
 
406
- - Defined in `.griffin/state.json`
407
- - Used for local test execution
408
- - Managed via `griffin local config` commands
305
+ ```yaml
306
+ environments:
307
+ local:
308
+ api_host: "localhost:3000"
309
+ api_key: "local-test-key"
310
+ staging:
311
+ api_host: "staging.example.com"
312
+ api_key: "staging-key"
313
+ production:
314
+ api_host: "api.example.com"
315
+ api_key: "prod-key"
316
+ ```
409
317
 
410
318
  **Example workflow:**
411
319
 
412
320
  ```bash
413
- # Create local environment with targets
414
- griffin local config add-target --env local --key api --url http://localhost:3000
415
- griffin local config add-target --env local --key billing --url http://localhost:3001
321
+ # List available environments
322
+ griffin env list
416
323
 
417
- # Set default environment
418
- griffin local config set-default-env --env local
324
+ # Run tests against different environments
325
+ griffin local run local
326
+ griffin local run staging
419
327
 
420
- # Run tests using default environment
421
- griffin local run
328
+ # Sync to hub for specific environment
329
+ griffin hub apply production
422
330
  ```
423
331
 
424
332
  ## Test Plan Discovery
@@ -448,10 +356,7 @@ Required endpoints:
448
356
  - `GET /plan` - List plans
449
357
  - `GET /runs` - List runs
450
358
  - `GET /runs/:id` - Get run details
451
- - `POST /runs/trigger/:id` - Trigger run
452
- - `GET /config` - List configurations
453
- - `PUT /config/:org/:env/targets/:key` - Set target
454
- - `DELETE /config/:org/:env/targets/:key` - Delete target
359
+ - `POST /runs/trigger/:planId` - Trigger run
455
360
 
456
361
  ## Development
457
362
 
@@ -476,16 +381,15 @@ griffin-cli/
476
381
  ├── src/
477
382
  │ ├── commands/ # Command implementations
478
383
  │ │ ├── local/ # Local execution commands
479
- │ │ │ ├── run.ts
480
- │ │ │ └── config.ts
384
+ │ │ │ └── run.ts
481
385
  │ │ ├── hub/ # Hub operation commands
482
386
  │ │ │ ├── connect.ts
483
387
  │ │ │ ├── status.ts
484
388
  │ │ │ ├── runs.ts
485
389
  │ │ │ ├── plan.ts
486
390
  │ │ │ ├── apply.ts
487
- │ │ │ ├── run.ts
488
- │ │ │ └── config.ts
391
+ │ │ │ └── run.ts
392
+ │ │ ├── env.ts # Environment commands
489
393
  │ │ ├── init.ts
490
394
  │ │ ├── validate.ts
491
395
  │ │ └── generate-key.ts
@@ -495,9 +399,9 @@ griffin-cli/
495
399
  │ │ ├── diff.ts # Diff computation
496
400
  │ │ ├── discovery.ts # Plan discovery
497
401
  │ │ ├── state.ts # State management
402
+ │ │ ├── variables.ts # Variable resolution
498
403
  │ │ └── project.ts # Project detection
499
404
  │ ├── schemas/ # Type definitions
500
- │ │ ├── payload.ts # Plan payload schemas
501
405
  │ │ └── state.ts # State file schemas
502
406
  │ ├── cli.ts # CLI entry point
503
407
  │ └── index.ts # Public API exports
package/dist/cli.js CHANGED
@@ -3,6 +3,7 @@ import { Command } from "commander";
3
3
  import { executeInit } from "./commands/init.js";
4
4
  import { executeValidate } from "./commands/validate.js";
5
5
  import { executeGenerateKey } from "./commands/generate-key.js";
6
+ import { executeEnvList } from "./commands/env.js";
6
7
  // Local commands
7
8
  import { executeRunLocal } from "./commands/local/run.js";
8
9
  // Hub commands
@@ -37,14 +38,21 @@ program
37
38
  .action(async () => {
38
39
  await executeGenerateKey();
39
40
  });
41
+ // Environment command group
42
+ const env = program.command("env").description("Manage environments");
43
+ env
44
+ .command("list")
45
+ .description("List all available environments")
46
+ .action(async () => {
47
+ await executeEnvList();
48
+ });
40
49
  // Local command group
41
50
  const local = program.command("local").description("Local test execution");
42
51
  local
43
- .command("run")
52
+ .command("run [env]")
44
53
  .description("Run tests locally against an environment")
45
- .option("--env <name>", "Environment to run against (uses default if not specified)")
46
- .action(async (options) => {
47
- await executeRunLocal(options);
54
+ .action(async (env, options) => {
55
+ await executeRunLocal({ env });
48
56
  });
49
57
  // Hub command group
50
58
  const hub = program.command("hub").description("Griffin Hub operations");
@@ -74,32 +82,29 @@ hub
74
82
  });
75
83
  });
76
84
  hub
77
- .command("plan")
85
+ .command("plan [env]")
78
86
  .description("Show what changes would be applied")
79
- .option("--env <name>", "Environment to plan for (uses default if not specified)")
80
87
  .option("--json", "Output in JSON format")
81
- .action(async (options) => {
82
- await executePlan(options);
88
+ .action(async (env, options) => {
89
+ await executePlan({ ...options, env });
83
90
  });
84
91
  hub
85
- .command("apply")
92
+ .command("apply [env]")
86
93
  .description("Apply changes to the hub")
87
- .option("--env <name>", "Environment to apply to (uses default if not specified)")
88
94
  .option("--auto-approve", "Skip confirmation prompt")
89
95
  .option("--dry-run", "Show what would be done without making changes")
90
96
  .option("--prune", "Delete plans on hub that don't exist locally")
91
- .action(async (options) => {
92
- await executeApply(options);
97
+ .action(async (env, options) => {
98
+ await executeApply({ ...options, env });
93
99
  });
94
100
  hub
95
- .command("run")
101
+ .command("run <env>")
96
102
  .description("Trigger a plan run on the hub")
97
103
  .requiredOption("--plan <name>", "Plan name to run")
98
- .requiredOption("--env <name>", "Target environment")
99
104
  .option("--wait", "Wait for run to complete")
100
105
  .option("--force", "Run even if local plan differs from hub")
101
- .action(async (options) => {
102
- await executeRun(options);
106
+ .action(async (env, options) => {
107
+ await executeRun({ ...options, env });
103
108
  });
104
109
  // Parse arguments
105
110
  program.parse();
@@ -1,25 +1,4 @@
1
- export interface EnvAddOptions {
2
- baseUrl: string;
3
- }
4
- export interface EnvRemoveOptions {
5
- name: string;
6
- }
7
- export interface EnvDefaultOptions {
8
- name: string;
9
- }
10
1
  /**
11
- * List all environments
2
+ * List all available environments
12
3
  */
13
4
  export declare function executeEnvList(): Promise<void>;
14
- /**
15
- * Add or update an environment
16
- */
17
- export declare function executeEnvAdd(name: string, options: EnvAddOptions): Promise<void>;
18
- /**
19
- * Remove an environment
20
- */
21
- export declare function executeEnvRemove(name: string): Promise<void>;
22
- /**
23
- * Set default environment
24
- */
25
- export declare function executeEnvDefault(name: string): Promise<void>;
@@ -1,121 +1,32 @@
1
- import { loadState, addEnvironment, removeEnvironment, setDefaultEnvironment, } from "../core/state.js";
1
+ import { loadState } from "../core/state.js";
2
+ import { terminal } from "../utils/terminal.js";
2
3
  /**
3
- * List all environments
4
+ * List all available environments
4
5
  */
5
6
  export async function executeEnvList() {
6
7
  try {
7
8
  const state = await loadState();
8
- const envNames = Object.keys(state.environments);
9
- if (envNames.length === 0) {
10
- console.log("No environments configured.");
11
- console.log("");
12
- console.log("Add an environment with:");
13
- console.log(" griffin env add <name> --base-url <url>");
9
+ const environments = Object.keys(state.environments);
10
+ if (environments.length === 0) {
11
+ terminal.warn("No environments configured.");
12
+ terminal.blank();
13
+ terminal.dim("Run 'griffin init' to set up your project.");
14
14
  return;
15
15
  }
16
- console.log("Environments:");
17
- console.log("");
18
- envNames.forEach((name) => {
19
- const config = state.environments[name];
20
- const isDefault = name === state.defaultEnvironment;
21
- const marker = isDefault ? " (default)" : "";
22
- console.log(` ${name}${marker}`);
23
- console.log(` URL: ${config.baseUrl}`);
24
- });
25
- console.log("");
26
- }
27
- catch (error) {
28
- console.error(`Error: ${error.message}`);
29
- process.exit(1);
30
- }
31
- }
32
- /**
33
- * Add or update an environment
34
- */
35
- export async function executeEnvAdd(name, options) {
36
- try {
37
- const state = await loadState();
38
- const isUpdate = name in state.environments;
39
- await addEnvironment(name, { baseUrl: options.baseUrl });
40
- if (isUpdate) {
41
- console.log(`✓ Updated environment '${name}'`);
42
- }
43
- else {
44
- console.log(`✓ Added environment '${name}'`);
45
- }
46
- console.log(` URL: ${options.baseUrl}`);
47
- // Show if this was set as default
48
- const updatedState = await loadState();
49
- if (updatedState.defaultEnvironment === name && !isUpdate) {
50
- console.log(" (set as default - first environment)");
51
- }
52
- console.log("");
53
- }
54
- catch (error) {
55
- console.error(`Error: ${error.message}`);
56
- process.exit(1);
57
- }
58
- }
59
- /**
60
- * Remove an environment
61
- */
62
- export async function executeEnvRemove(name) {
63
- try {
64
- const state = await loadState();
65
- // Check if environment exists
66
- if (!(name in state.environments)) {
67
- console.error(`Error: Environment '${name}' does not exist`);
68
- console.log("");
69
- console.log("Available environments:");
70
- Object.keys(state.environments).forEach((env) => {
71
- console.log(` - ${env}`);
72
- });
73
- process.exit(1);
74
- }
75
- // Warn if there are plans in this environment
76
- const planCount = state.plans[name]?.length || 0;
77
- if (planCount > 0) {
78
- console.log(`Warning: Environment '${name}' has ${planCount} synced plan(s).`);
79
- console.log("This will remove all plan state for this environment.");
80
- console.log("");
81
- }
82
- await removeEnvironment(name);
83
- console.log(`✓ Removed environment '${name}'`);
84
- // Show new default if it changed
85
- const updatedState = await loadState();
86
- if (updatedState.defaultEnvironment &&
87
- updatedState.defaultEnvironment !== name) {
88
- console.log(` New default: ${updatedState.defaultEnvironment}`);
89
- }
90
- console.log("");
91
- }
92
- catch (error) {
93
- console.error(`Error: ${error.message}`);
94
- process.exit(1);
95
- }
96
- }
97
- /**
98
- * Set default environment
99
- */
100
- export async function executeEnvDefault(name) {
101
- try {
102
- const state = await loadState();
103
- // Check if environment exists
104
- if (!(name in state.environments)) {
105
- console.error(`Error: Environment '${name}' does not exist`);
106
- console.log("");
107
- console.log("Available environments:");
108
- Object.keys(state.environments).forEach((env) => {
109
- console.log(` - ${env}`);
110
- });
111
- process.exit(1);
16
+ terminal.info("Available environments:");
17
+ terminal.blank();
18
+ for (const envName of environments) {
19
+ const isDefault = state.defaultEnvironment === envName;
20
+ const marker = isDefault ? terminal.colors.green("●") : terminal.colors.dim("○");
21
+ const envDisplay = isDefault
22
+ ? terminal.colors.cyan(envName) + terminal.colors.dim(" (default)")
23
+ : envName;
24
+ terminal.log(` ${marker} ${envDisplay}`);
112
25
  }
113
- await setDefaultEnvironment(name);
114
- console.log(`✓ Set '${name}' as default environment`);
115
- console.log("");
26
+ terminal.blank();
116
27
  }
117
28
  catch (error) {
118
- console.error(`Error: ${error.message}`);
119
- process.exit(1);
29
+ terminal.error(error.message);
30
+ terminal.exit(1);
120
31
  }
121
32
  }