@griffin-app/griffin-cli 1.0.8 → 1.0.9
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/dist/cli.js +61 -37
- package/dist/commands/env.js +2 -7
- package/dist/commands/hub/apply.js +4 -2
- package/dist/commands/hub/login.js +12 -25
- package/dist/commands/hub/monitor.js +4 -2
- package/dist/commands/hub/notifications.d.ts +2 -21
- package/dist/commands/hub/notifications.js +7 -119
- package/dist/commands/hub/run.js +1 -1
- package/dist/commands/hub/secrets.d.ts +35 -0
- package/dist/commands/hub/secrets.js +185 -0
- package/dist/commands/init.js +1 -6
- package/dist/commands/local/run.d.ts +1 -1
- package/dist/core/apply.test.js +3 -1
- package/dist/core/state.d.ts +0 -4
- package/dist/core/state.js +8 -26
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/schemas/state.d.ts +16 -17
- package/dist/schemas/state.js +22 -16
- package/dist/test-runner.js +1 -1
- package/dist/utils/sdk-error.js +0 -2
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -16,7 +16,8 @@ import { executeApply } from "./commands/hub/apply.js";
|
|
|
16
16
|
import { executeRun } from "./commands/hub/run.js";
|
|
17
17
|
import { executeLogin } from "./commands/hub/login.js";
|
|
18
18
|
import { executeLogout } from "./commands/hub/logout.js";
|
|
19
|
-
import { executeNotificationsList,
|
|
19
|
+
import { executeNotificationsList, executeNotificationsTest, } from "./commands/hub/notifications.js";
|
|
20
|
+
import { executeSecretsList, executeSecretsSet, executeSecretsGet, executeSecretsDelete, } from "./commands/hub/secrets.js";
|
|
20
21
|
const program = new Command();
|
|
21
22
|
program
|
|
22
23
|
.name("griffin")
|
|
@@ -53,7 +54,7 @@ env
|
|
|
53
54
|
// Local command group
|
|
54
55
|
const local = program.command("local").description("Local test execution");
|
|
55
56
|
local
|
|
56
|
-
.command("run
|
|
57
|
+
.command("run [env]")
|
|
57
58
|
.description("Run tests locally against an environment")
|
|
58
59
|
.action(async (env, options) => {
|
|
59
60
|
await executeRunLocal({ env });
|
|
@@ -75,15 +76,14 @@ hub
|
|
|
75
76
|
await executeStatus();
|
|
76
77
|
});
|
|
77
78
|
hub
|
|
78
|
-
.command("metrics")
|
|
79
|
+
.command("metrics [env]")
|
|
79
80
|
.description("Show metrics summary from the hub")
|
|
80
81
|
.option("--period <period>", "Time window: 1h, 6h, 24h, 7d, 30d", "24h")
|
|
81
|
-
.option("--environment <env>", "Filter by environment")
|
|
82
82
|
.option("--json", "Output as JSON")
|
|
83
|
-
.action(async (options) => {
|
|
83
|
+
.action(async (env, options) => {
|
|
84
84
|
await executeMetrics({
|
|
85
85
|
period: options.period,
|
|
86
|
-
environment:
|
|
86
|
+
environment: env,
|
|
87
87
|
json: options.json,
|
|
88
88
|
});
|
|
89
89
|
});
|
|
@@ -99,14 +99,14 @@ hub
|
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
101
|
hub
|
|
102
|
-
.command("
|
|
102
|
+
.command("plan [env]")
|
|
103
103
|
.description("Show what changes would be applied")
|
|
104
104
|
.option("--json", "Output in JSON format")
|
|
105
105
|
.action(async (env, options) => {
|
|
106
106
|
await executeMonitor({ ...options, env });
|
|
107
107
|
});
|
|
108
108
|
hub
|
|
109
|
-
.command("apply
|
|
109
|
+
.command("apply [env]")
|
|
110
110
|
.description("Apply changes to the hub")
|
|
111
111
|
.option("--auto-approve", "Skip confirmation prompt")
|
|
112
112
|
.option("--dry-run", "Show what would be done without making changes")
|
|
@@ -115,7 +115,7 @@ hub
|
|
|
115
115
|
await executeApply({ ...options, env });
|
|
116
116
|
});
|
|
117
117
|
hub
|
|
118
|
-
.command("run
|
|
118
|
+
.command("run [env]")
|
|
119
119
|
.description("Trigger a monitor run on the hub")
|
|
120
120
|
.requiredOption("--monitor <name>", "Monitor name to run")
|
|
121
121
|
.option("--wait", "Wait for run to complete")
|
|
@@ -138,7 +138,7 @@ hub
|
|
|
138
138
|
// Notifications command group
|
|
139
139
|
const notifications = hub
|
|
140
140
|
.command("notifications")
|
|
141
|
-
.description("
|
|
141
|
+
.description("View notification rules (rules are defined in monitor DSL and synced via griffin hub apply)");
|
|
142
142
|
notifications
|
|
143
143
|
.command("list")
|
|
144
144
|
.description("List notification rules")
|
|
@@ -152,33 +152,6 @@ notifications
|
|
|
152
152
|
json: options.json,
|
|
153
153
|
});
|
|
154
154
|
});
|
|
155
|
-
notifications
|
|
156
|
-
.command("add")
|
|
157
|
-
.description("Create a notification rule")
|
|
158
|
-
.requiredOption("--name <name>", "Rule name")
|
|
159
|
-
.option("--monitor <id>", "Monitor ID (optional, applies to all if not specified)")
|
|
160
|
-
.option("--environment <env>", "Environment filter")
|
|
161
|
-
.option("--location <loc>", "Location filter")
|
|
162
|
-
.requiredOption("--trigger <trigger>", "Trigger: run_failed, run_recovered, consecutive_failures:N, success_rate_below:threshold:window_min, latency_above:threshold_ms:percentile:window_min")
|
|
163
|
-
.requiredOption("--webhook <url>", "Webhook URL")
|
|
164
|
-
.option("--cooldown <minutes>", "Cooldown period in minutes", "15")
|
|
165
|
-
.action(async (options) => {
|
|
166
|
-
await executeNotificationsAdd({
|
|
167
|
-
name: options.name,
|
|
168
|
-
monitor: options.monitor,
|
|
169
|
-
environment: options.environment,
|
|
170
|
-
location: options.location,
|
|
171
|
-
trigger: options.trigger,
|
|
172
|
-
webhook: options.webhook,
|
|
173
|
-
cooldown: options.cooldown ? parseInt(options.cooldown, 10) : undefined,
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
notifications
|
|
177
|
-
.command("delete <id>")
|
|
178
|
-
.description("Delete a notification rule")
|
|
179
|
-
.action(async (id) => {
|
|
180
|
-
await executeNotificationsDelete({ id });
|
|
181
|
-
});
|
|
182
155
|
notifications
|
|
183
156
|
.command("test")
|
|
184
157
|
.description("Test a webhook configuration")
|
|
@@ -188,5 +161,56 @@ notifications
|
|
|
188
161
|
webhook: options.webhook,
|
|
189
162
|
});
|
|
190
163
|
});
|
|
164
|
+
// Secrets command group
|
|
165
|
+
const secrets = hub
|
|
166
|
+
.command("secrets")
|
|
167
|
+
.description("Manage secrets (platform storage)");
|
|
168
|
+
secrets
|
|
169
|
+
.command("list")
|
|
170
|
+
.description("List secrets for an environment")
|
|
171
|
+
.option("--environment <env>", "Environment name", "default")
|
|
172
|
+
.option("--json", "Output as JSON")
|
|
173
|
+
.action(async (options) => {
|
|
174
|
+
await executeSecretsList({
|
|
175
|
+
environment: options.environment,
|
|
176
|
+
json: options.json,
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
secrets
|
|
180
|
+
.command("set <name>")
|
|
181
|
+
.description("Create or update a secret (prompts for value)")
|
|
182
|
+
.option("--environment <env>", "Environment name", "default")
|
|
183
|
+
.option("--value <value>", "Secret value (avoid for sensitive data)")
|
|
184
|
+
.action(async (name, options) => {
|
|
185
|
+
await executeSecretsSet({
|
|
186
|
+
name,
|
|
187
|
+
environment: options.environment,
|
|
188
|
+
value: options.value,
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
secrets
|
|
192
|
+
.command("get <name>")
|
|
193
|
+
.description("Show secret metadata (not the value)")
|
|
194
|
+
.option("--environment <env>", "Environment name", "default")
|
|
195
|
+
.option("--json", "Output as JSON")
|
|
196
|
+
.action(async (name, options) => {
|
|
197
|
+
await executeSecretsGet({
|
|
198
|
+
name,
|
|
199
|
+
environment: options.environment,
|
|
200
|
+
json: options.json,
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
secrets
|
|
204
|
+
.command("delete <name>")
|
|
205
|
+
.description("Delete a secret")
|
|
206
|
+
.option("--environment <env>", "Environment name", "default")
|
|
207
|
+
.option("--force", "Skip confirmation prompt")
|
|
208
|
+
.action(async (name, options) => {
|
|
209
|
+
await executeSecretsDelete({
|
|
210
|
+
name,
|
|
211
|
+
environment: options.environment,
|
|
212
|
+
force: options.force,
|
|
213
|
+
});
|
|
214
|
+
});
|
|
191
215
|
// Parse arguments
|
|
192
216
|
program.parse();
|
package/dist/commands/env.js
CHANGED
|
@@ -16,13 +16,8 @@ export async function executeEnvList() {
|
|
|
16
16
|
terminal.info("Available environments:");
|
|
17
17
|
terminal.blank();
|
|
18
18
|
for (const envName of environments) {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
? terminal.colors.green("●")
|
|
22
|
-
: terminal.colors.dim("○");
|
|
23
|
-
const envDisplay = isDefault
|
|
24
|
-
? terminal.colors.cyan(envName) + terminal.colors.dim(" (default)")
|
|
25
|
-
: envName;
|
|
19
|
+
const marker = terminal.colors.green("●");
|
|
20
|
+
const envDisplay = terminal.colors.cyan(envName);
|
|
26
21
|
terminal.log(` ${marker} ${envDisplay}`);
|
|
27
22
|
}
|
|
28
23
|
terminal.blank();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadState, resolveEnvironment } from "../../core/state.js";
|
|
2
|
-
import { discoverMonitors, formatDiscoveryErrors } from "../../core/discovery.js";
|
|
2
|
+
import { discoverMonitors, formatDiscoveryErrors, } from "../../core/discovery.js";
|
|
3
3
|
import { computeDiff, formatDiff } from "../../core/diff.js";
|
|
4
4
|
import { applyDiff, formatApplyResult } from "../../core/apply.js";
|
|
5
5
|
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
@@ -42,7 +42,9 @@ export async function executeApply(options) {
|
|
|
42
42
|
}
|
|
43
43
|
spinner.succeed(`Found ${monitors.length} local monitor(s)`);
|
|
44
44
|
// Fetch remote monitors for this project + environment
|
|
45
|
-
const fetchSpinner = terminal
|
|
45
|
+
const fetchSpinner = terminal
|
|
46
|
+
.spinner("Fetching remote monitors...")
|
|
47
|
+
.start();
|
|
46
48
|
const response = await withSDKErrorHandling(() => sdk.getMonitor({
|
|
47
49
|
query: {
|
|
48
50
|
projectId: state.projectId,
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// CLI implementation
|
|
2
2
|
import { createAuthClient } from "better-auth/client";
|
|
3
3
|
import { deviceAuthorizationClient, jwtClient, } from "better-auth/client/plugins";
|
|
4
|
-
import {
|
|
4
|
+
import { loadState, saveState } from "../../core/state.js";
|
|
5
5
|
import { saveHubCredentials } from "../../core/credentials.js";
|
|
6
6
|
import { terminal } from "../../utils/terminal.js";
|
|
7
7
|
import { randomBytes } from "crypto";
|
|
8
|
-
import { createEmptyState } from "../../schemas/state.js";
|
|
9
|
-
const baseURL = "http://localhost:4000/api/auth";
|
|
10
|
-
const hubBaseUrl = "http://localhost:3000";
|
|
11
|
-
//const baseURL = "https://cloud.griffin.app"
|
|
12
8
|
const oauthGrant = "urn:ietf:params:oauth:grant-type:device_code";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
function createAuthClientFromState(state) {
|
|
10
|
+
return createAuthClient({
|
|
11
|
+
baseURL: state.cloud.authUrl,
|
|
12
|
+
plugins: [deviceAuthorizationClient(), jwtClient()],
|
|
13
|
+
});
|
|
14
|
+
}
|
|
17
15
|
async function pollForToken(clientId, deviceCode, interval) {
|
|
16
|
+
const state = await loadState();
|
|
17
|
+
const authClient = createAuthClientFromState(state);
|
|
18
18
|
const { data, error } = await authClient.device.token({
|
|
19
19
|
grant_type: oauthGrant,
|
|
20
20
|
device_code: deviceCode,
|
|
@@ -39,16 +39,9 @@ async function pollForToken(clientId, deviceCode, interval) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
export async function executeLogin() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
state = await loadState();
|
|
46
|
-
clientId = state.hub?.clientId;
|
|
47
|
-
}
|
|
48
|
-
catch (error) { }
|
|
49
|
-
if (!clientId) {
|
|
50
|
-
clientId = randomBytes(16).toString("hex");
|
|
51
|
-
}
|
|
42
|
+
const state = await loadState();
|
|
43
|
+
const clientId = state.hub?.clientId ?? randomBytes(16).toString("hex");
|
|
44
|
+
const authClient = createAuthClientFromState(state);
|
|
52
45
|
const { data } = await authClient.device.code({
|
|
53
46
|
client_id: clientId,
|
|
54
47
|
});
|
|
@@ -69,17 +62,11 @@ export async function executeLogin() {
|
|
|
69
62
|
terminal.success("Login successful");
|
|
70
63
|
terminal.log(` Token saved to user credentials`);
|
|
71
64
|
}
|
|
72
|
-
if (!state) {
|
|
73
|
-
const projectId = await getProjectId();
|
|
74
|
-
state = createEmptyState(projectId);
|
|
75
|
-
}
|
|
76
|
-
// Save hub config to project state (without token)
|
|
77
65
|
await saveState({
|
|
78
66
|
...state,
|
|
79
67
|
hub: {
|
|
80
68
|
...state.hub,
|
|
81
69
|
clientId: clientId,
|
|
82
|
-
baseUrl: hubBaseUrl,
|
|
83
70
|
},
|
|
84
71
|
});
|
|
85
72
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadState, resolveEnvironment } from "../../core/state.js";
|
|
2
|
-
import { discoverMonitors, formatDiscoveryErrors } from "../../core/discovery.js";
|
|
2
|
+
import { discoverMonitors, formatDiscoveryErrors, } from "../../core/discovery.js";
|
|
3
3
|
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
4
4
|
import { computeDiff, formatDiff, formatDiffJson } from "../../core/diff.js";
|
|
5
5
|
import { terminal } from "../../utils/terminal.js";
|
|
@@ -38,7 +38,9 @@ export async function executeMonitor(options) {
|
|
|
38
38
|
// Create SDK clients with credentials
|
|
39
39
|
const sdk = await createSdkWithCredentials(state.hub.baseUrl);
|
|
40
40
|
// Fetch remote monitors for this project + environment
|
|
41
|
-
const fetchSpinner = terminal
|
|
41
|
+
const fetchSpinner = terminal
|
|
42
|
+
.spinner("Fetching remote monitors...")
|
|
43
|
+
.start();
|
|
42
44
|
const response = await withSDKErrorHandling(() => sdk.getMonitor({
|
|
43
45
|
query: {
|
|
44
46
|
projectId: state.projectId,
|
|
@@ -3,33 +3,14 @@ export interface NotificationsListOptions {
|
|
|
3
3
|
enabled?: boolean;
|
|
4
4
|
json?: boolean;
|
|
5
5
|
}
|
|
6
|
-
export interface NotificationsAddOptions {
|
|
7
|
-
name: string;
|
|
8
|
-
monitor?: string;
|
|
9
|
-
environment?: string;
|
|
10
|
-
location?: string;
|
|
11
|
-
trigger: string;
|
|
12
|
-
webhook: string;
|
|
13
|
-
cooldown?: number;
|
|
14
|
-
}
|
|
15
|
-
export interface NotificationsDeleteOptions {
|
|
16
|
-
id: string;
|
|
17
|
-
}
|
|
18
6
|
export interface NotificationsTestOptions {
|
|
19
7
|
webhook: string;
|
|
20
8
|
}
|
|
21
9
|
/**
|
|
22
|
-
* List notification rules
|
|
10
|
+
* List notification rules (read-only).
|
|
11
|
+
* Rules are defined in monitor DSL and synced via `griffin hub apply`.
|
|
23
12
|
*/
|
|
24
13
|
export declare function executeNotificationsList(options: NotificationsListOptions): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Add a notification rule
|
|
27
|
-
*/
|
|
28
|
-
export declare function executeNotificationsAdd(options: NotificationsAddOptions): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* Delete a notification rule
|
|
31
|
-
*/
|
|
32
|
-
export declare function executeNotificationsDelete(options: NotificationsDeleteOptions): Promise<void>;
|
|
33
14
|
/**
|
|
34
15
|
* Test a webhook
|
|
35
16
|
*/
|
|
@@ -3,7 +3,8 @@ import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
|
3
3
|
import { terminal } from "../../utils/terminal.js";
|
|
4
4
|
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
5
5
|
/**
|
|
6
|
-
* List notification rules
|
|
6
|
+
* List notification rules (read-only).
|
|
7
|
+
* Rules are defined in monitor DSL and synced via `griffin hub apply`.
|
|
7
8
|
*/
|
|
8
9
|
export async function executeNotificationsList(options) {
|
|
9
10
|
try {
|
|
@@ -28,26 +29,22 @@ export async function executeNotificationsList(options) {
|
|
|
28
29
|
}
|
|
29
30
|
if (rules.length === 0) {
|
|
30
31
|
terminal.info("No notification rules found.");
|
|
32
|
+
terminal.dim("Define notifications in your monitor DSL and run griffin hub apply.");
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
|
-
terminal.info("Notification Rules");
|
|
35
|
+
terminal.info("Notification Rules (synced from monitor DSL)");
|
|
34
36
|
terminal.blank();
|
|
35
37
|
const table = terminal.table({
|
|
36
|
-
head: ["ID", "
|
|
38
|
+
head: ["ID", "Monitor", "Integration", "Trigger", "Enabled"],
|
|
37
39
|
});
|
|
38
40
|
for (const rule of rules) {
|
|
39
41
|
const triggerDesc = formatTrigger(rule.trigger);
|
|
40
|
-
const channels = rule.channels
|
|
41
|
-
.map((ch) => (ch.type === "webhook" ? "webhook" : ch.type))
|
|
42
|
-
.join(", ");
|
|
43
|
-
const monitorName = rule.monitorId || "all monitors";
|
|
44
42
|
const enabled = rule.enabled ? "✓" : "✗";
|
|
45
43
|
table.push([
|
|
46
44
|
rule.id.substring(0, 8) + "...",
|
|
47
|
-
rule.
|
|
48
|
-
|
|
45
|
+
rule.monitorId ?? "-",
|
|
46
|
+
rule.integrationName ?? "-",
|
|
49
47
|
triggerDesc,
|
|
50
|
-
channels,
|
|
51
48
|
enabled,
|
|
52
49
|
]);
|
|
53
50
|
}
|
|
@@ -58,76 +55,6 @@ export async function executeNotificationsList(options) {
|
|
|
58
55
|
terminal.exit(1);
|
|
59
56
|
}
|
|
60
57
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Add a notification rule
|
|
63
|
-
*/
|
|
64
|
-
export async function executeNotificationsAdd(options) {
|
|
65
|
-
try {
|
|
66
|
-
const state = await loadState();
|
|
67
|
-
if (!state.hub?.baseUrl) {
|
|
68
|
-
terminal.error("Hub connection not configured.");
|
|
69
|
-
terminal.dim("Connect with:");
|
|
70
|
-
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
71
|
-
terminal.exit(1);
|
|
72
|
-
}
|
|
73
|
-
// Parse trigger
|
|
74
|
-
const trigger = parseTrigger(options.trigger);
|
|
75
|
-
if (!trigger) {
|
|
76
|
-
terminal.error(`Invalid trigger: ${options.trigger}. Expected format: type[:value]`);
|
|
77
|
-
terminal.dim("Examples:");
|
|
78
|
-
terminal.dim(" run_failed");
|
|
79
|
-
terminal.dim(" consecutive_failures:3");
|
|
80
|
-
terminal.dim(" success_rate_below:80:60");
|
|
81
|
-
terminal.exit(1);
|
|
82
|
-
}
|
|
83
|
-
const sdk = await createSdkWithCredentials(state.hub.baseUrl);
|
|
84
|
-
const response = await withSDKErrorHandling(() => sdk.postNotificationsRules({
|
|
85
|
-
body: {
|
|
86
|
-
name: options.name,
|
|
87
|
-
monitorId: options.monitor,
|
|
88
|
-
environment: options.environment,
|
|
89
|
-
location: options.location,
|
|
90
|
-
trigger,
|
|
91
|
-
channels: [
|
|
92
|
-
{
|
|
93
|
-
type: "webhook",
|
|
94
|
-
url: options.webhook,
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
cooldownMinutes: options.cooldown,
|
|
98
|
-
},
|
|
99
|
-
}), "Failed to create notification rule");
|
|
100
|
-
const rule = response?.data?.data;
|
|
101
|
-
if (rule) {
|
|
102
|
-
terminal.success(`Created notification rule: ${rule.id}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
terminal.error(error.message);
|
|
107
|
-
terminal.exit(1);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Delete a notification rule
|
|
112
|
-
*/
|
|
113
|
-
export async function executeNotificationsDelete(options) {
|
|
114
|
-
try {
|
|
115
|
-
const state = await loadState();
|
|
116
|
-
if (!state.hub?.baseUrl) {
|
|
117
|
-
terminal.error("Hub connection not configured.");
|
|
118
|
-
terminal.dim("Connect with:");
|
|
119
|
-
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
120
|
-
terminal.exit(1);
|
|
121
|
-
}
|
|
122
|
-
const sdk = await createSdkWithCredentials(state.hub.baseUrl);
|
|
123
|
-
await withSDKErrorHandling(() => sdk.deleteNotificationsRulesById({ path: { id: options.id } }), "Failed to delete notification rule");
|
|
124
|
-
terminal.success(`Deleted notification rule: ${options.id}`);
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
terminal.error(error.message);
|
|
128
|
-
terminal.exit(1);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
58
|
/**
|
|
132
59
|
* Test a webhook
|
|
133
60
|
*/
|
|
@@ -165,45 +92,6 @@ export async function executeNotificationsTest(options) {
|
|
|
165
92
|
terminal.exit(1);
|
|
166
93
|
}
|
|
167
94
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Parse trigger string into trigger object
|
|
170
|
-
*/
|
|
171
|
-
function parseTrigger(triggerStr) {
|
|
172
|
-
const parts = triggerStr.split(":");
|
|
173
|
-
const type = parts[0];
|
|
174
|
-
switch (type) {
|
|
175
|
-
case "run_failed":
|
|
176
|
-
return { type: "run_failed" };
|
|
177
|
-
case "run_recovered":
|
|
178
|
-
return { type: "run_recovered" };
|
|
179
|
-
case "consecutive_failures":
|
|
180
|
-
if (parts.length < 2)
|
|
181
|
-
return null;
|
|
182
|
-
return {
|
|
183
|
-
type: "consecutive_failures",
|
|
184
|
-
threshold: parseInt(parts[1], 10),
|
|
185
|
-
};
|
|
186
|
-
case "success_rate_below":
|
|
187
|
-
if (parts.length < 3)
|
|
188
|
-
return null;
|
|
189
|
-
return {
|
|
190
|
-
type: "success_rate_below",
|
|
191
|
-
threshold: parseFloat(parts[1]),
|
|
192
|
-
window_minutes: parseInt(parts[2], 10),
|
|
193
|
-
};
|
|
194
|
-
case "latency_above":
|
|
195
|
-
if (parts.length < 4)
|
|
196
|
-
return null;
|
|
197
|
-
return {
|
|
198
|
-
type: "latency_above",
|
|
199
|
-
threshold_ms: parseInt(parts[1], 10),
|
|
200
|
-
percentile: parts[2],
|
|
201
|
-
window_minutes: parseInt(parts[3], 10),
|
|
202
|
-
};
|
|
203
|
-
default:
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
95
|
/**
|
|
208
96
|
* Format trigger for display
|
|
209
97
|
*/
|
package/dist/commands/hub/run.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadState, resolveEnvironment } from "../../core/state.js";
|
|
2
2
|
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
3
|
-
import { discoverMonitors, formatDiscoveryErrors } from "../../core/discovery.js";
|
|
3
|
+
import { discoverMonitors, formatDiscoveryErrors, } from "../../core/discovery.js";
|
|
4
4
|
import { computeDiff } from "../../core/diff.js";
|
|
5
5
|
import { terminal } from "../../utils/terminal.js";
|
|
6
6
|
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface SecretsListOptions {
|
|
2
|
+
environment?: string;
|
|
3
|
+
json?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface SecretsSetOptions {
|
|
6
|
+
name: string;
|
|
7
|
+
environment?: string;
|
|
8
|
+
value?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SecretsGetOptions {
|
|
11
|
+
name: string;
|
|
12
|
+
environment?: string;
|
|
13
|
+
json?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface SecretsDeleteOptions {
|
|
16
|
+
name: string;
|
|
17
|
+
environment?: string;
|
|
18
|
+
force?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* List secrets (metadata only)
|
|
22
|
+
*/
|
|
23
|
+
export declare function executeSecretsList(options: SecretsListOptions): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Set a secret (prompts for value if not provided)
|
|
26
|
+
*/
|
|
27
|
+
export declare function executeSecretsSet(options: SecretsSetOptions): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Get secret metadata only
|
|
30
|
+
*/
|
|
31
|
+
export declare function executeSecretsGet(options: SecretsGetOptions): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Delete a secret (with confirmation unless --force)
|
|
34
|
+
*/
|
|
35
|
+
export declare function executeSecretsDelete(options: SecretsDeleteOptions): Promise<void>;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { loadState } from "../../core/state.js";
|
|
3
|
+
import { terminal } from "../../utils/terminal.js";
|
|
4
|
+
import { withSDKErrorHandling } from "../../utils/sdk-error.js";
|
|
5
|
+
import { createSdkWithCredentials } from "../../core/sdk.js";
|
|
6
|
+
const SECRET_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7
|
+
/**
|
|
8
|
+
* List secrets (metadata only)
|
|
9
|
+
*/
|
|
10
|
+
export async function executeSecretsList(options) {
|
|
11
|
+
try {
|
|
12
|
+
const state = await loadState();
|
|
13
|
+
if (!state.hub?.baseUrl) {
|
|
14
|
+
terminal.error("Hub connection not configured.");
|
|
15
|
+
terminal.dim("Connect with:");
|
|
16
|
+
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
17
|
+
terminal.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const baseUrl = state.hub.baseUrl;
|
|
20
|
+
const sdk = await createSdkWithCredentials(baseUrl);
|
|
21
|
+
const env = options.environment ?? "default";
|
|
22
|
+
const response = await withSDKErrorHandling(async () => {
|
|
23
|
+
return sdk.getSecrets({
|
|
24
|
+
query: {
|
|
25
|
+
environment: env,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}, "Failed to list secrets");
|
|
29
|
+
const secrets = response?.data?.data ?? [];
|
|
30
|
+
if (options.json) {
|
|
31
|
+
terminal.log(JSON.stringify(secrets, null, 2));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (secrets.length === 0) {
|
|
35
|
+
terminal.info(`No secrets found for environment "${env}".`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
terminal.info(`Secrets (environment: ${env})`);
|
|
39
|
+
terminal.blank();
|
|
40
|
+
const table = terminal.table({
|
|
41
|
+
head: ["Name", "Created", "Updated"],
|
|
42
|
+
});
|
|
43
|
+
for (const s of secrets) {
|
|
44
|
+
table.push([s.name, s.createdAt ?? "-", s.updatedAt ?? "-"]);
|
|
45
|
+
}
|
|
46
|
+
terminal.log(table.toString());
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
terminal.error(error.message);
|
|
50
|
+
terminal.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set a secret (prompts for value if not provided)
|
|
55
|
+
*/
|
|
56
|
+
export async function executeSecretsSet(options) {
|
|
57
|
+
try {
|
|
58
|
+
if (!SECRET_NAME_REGEX.test(options.name)) {
|
|
59
|
+
terminal.error("Secret name must start with a letter or underscore and contain only letters, numbers, and underscores.");
|
|
60
|
+
terminal.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const state = await loadState();
|
|
63
|
+
if (!state.hub?.baseUrl) {
|
|
64
|
+
terminal.error("Hub connection not configured.");
|
|
65
|
+
terminal.dim("Connect with:");
|
|
66
|
+
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
67
|
+
terminal.exit(1);
|
|
68
|
+
}
|
|
69
|
+
let value = options.value;
|
|
70
|
+
if (value === undefined) {
|
|
71
|
+
value = await promptSecret("Enter secret value:");
|
|
72
|
+
if (!value) {
|
|
73
|
+
terminal.error("Secret value cannot be empty.");
|
|
74
|
+
terminal.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const baseUrl = state.hub.baseUrl;
|
|
78
|
+
const env = options.environment ?? "default";
|
|
79
|
+
const sdk = await createSdkWithCredentials(baseUrl);
|
|
80
|
+
const response = await withSDKErrorHandling(async () => {
|
|
81
|
+
return sdk.putSecretsByName({
|
|
82
|
+
path: { name: options.name },
|
|
83
|
+
body: { value, environment: env },
|
|
84
|
+
});
|
|
85
|
+
}, "Failed to set secret");
|
|
86
|
+
const result = response?.data;
|
|
87
|
+
terminal.success(`Secret "${result.data.name}" saved.`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
terminal.error(error.message);
|
|
91
|
+
terminal.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function promptSecret(promptText) {
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
const rl = createInterface({
|
|
97
|
+
input: process.stdin,
|
|
98
|
+
output: process.stdout,
|
|
99
|
+
});
|
|
100
|
+
rl.question(promptText, (answer) => {
|
|
101
|
+
rl.close();
|
|
102
|
+
resolve(answer.trim());
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get secret metadata only
|
|
108
|
+
*/
|
|
109
|
+
export async function executeSecretsGet(options) {
|
|
110
|
+
try {
|
|
111
|
+
const state = await loadState();
|
|
112
|
+
if (!state.hub?.baseUrl) {
|
|
113
|
+
terminal.error("Hub connection not configured.");
|
|
114
|
+
terminal.dim("Connect with:");
|
|
115
|
+
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
116
|
+
terminal.exit(1);
|
|
117
|
+
}
|
|
118
|
+
const baseUrl = state.hub.baseUrl;
|
|
119
|
+
const env = options.environment ?? "default";
|
|
120
|
+
const sdk = await createSdkWithCredentials(baseUrl);
|
|
121
|
+
const response = await withSDKErrorHandling(async () => {
|
|
122
|
+
return sdk.getSecretsByName({
|
|
123
|
+
path: { name: options.name },
|
|
124
|
+
query: { environment: env },
|
|
125
|
+
});
|
|
126
|
+
}, "Failed to get secret");
|
|
127
|
+
const secret = response?.data?.data;
|
|
128
|
+
if (options.json) {
|
|
129
|
+
terminal.log(JSON.stringify(secret, null, 2));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
terminal.info(`Secret: ${secret.name}`);
|
|
133
|
+
terminal.dim(`Created: ${secret.createdAt ?? "-"}`);
|
|
134
|
+
terminal.dim(`Updated: ${secret.updatedAt ?? "-"}`);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
terminal.error(error.message);
|
|
138
|
+
terminal.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Delete a secret (with confirmation unless --force)
|
|
143
|
+
*/
|
|
144
|
+
export async function executeSecretsDelete(options) {
|
|
145
|
+
try {
|
|
146
|
+
const state = await loadState();
|
|
147
|
+
if (!state.hub?.baseUrl) {
|
|
148
|
+
terminal.error("Hub connection not configured.");
|
|
149
|
+
terminal.dim("Connect with:");
|
|
150
|
+
terminal.dim(" griffin hub connect --url <url> --token <token>");
|
|
151
|
+
terminal.exit(1);
|
|
152
|
+
}
|
|
153
|
+
const baseUrl = state.hub.baseUrl;
|
|
154
|
+
const env = options.environment ?? "default";
|
|
155
|
+
const sdk = await createSdkWithCredentials(baseUrl);
|
|
156
|
+
if (!options.force) {
|
|
157
|
+
const rl = createInterface({
|
|
158
|
+
input: process.stdin,
|
|
159
|
+
output: process.stdout,
|
|
160
|
+
});
|
|
161
|
+
const answer = await new Promise((resolve) => {
|
|
162
|
+
rl.question(`Delete secret "${options.name}" (environment: ${env})? [y/N] `, (a) => {
|
|
163
|
+
rl.close();
|
|
164
|
+
resolve(a.trim().toLowerCase());
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
if (answer !== "y" && answer !== "yes") {
|
|
168
|
+
terminal.info("Aborted.");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const response = await withSDKErrorHandling(async () => {
|
|
173
|
+
return sdk.deleteSecretsByName({
|
|
174
|
+
path: { name: options.name },
|
|
175
|
+
query: { environment: env },
|
|
176
|
+
});
|
|
177
|
+
}, "Failed to delete secret");
|
|
178
|
+
const result = response?.data;
|
|
179
|
+
terminal.success(`Secret deleted.`);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
terminal.error(error.message);
|
|
183
|
+
terminal.exit(1);
|
|
184
|
+
}
|
|
185
|
+
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { initState, stateExists, getStateFilePath,
|
|
3
|
+
import { initState, stateExists, getStateFilePath, } from "../core/state.js";
|
|
4
4
|
import { detectProjectId } from "../core/project.js";
|
|
5
5
|
import { terminal } from "../utils/terminal.js";
|
|
6
6
|
const VARIABLES_FILE = "variables.yaml";
|
|
@@ -34,11 +34,6 @@ export async function executeInit(options) {
|
|
|
34
34
|
// Initialize state file
|
|
35
35
|
await initState(projectId);
|
|
36
36
|
terminal.success(`Created state file: ${terminal.colors.dim(getStateFilePath())}`);
|
|
37
|
-
// Create default environments
|
|
38
|
-
await addEnvironment("dev", {});
|
|
39
|
-
await addEnvironment("staging", {});
|
|
40
|
-
await addEnvironment("production", {});
|
|
41
|
-
terminal.success("Created default environments (dev, staging, production)");
|
|
42
37
|
// Create variables.yaml if it doesn't exist
|
|
43
38
|
const variablesPath = path.join(process.cwd(), VARIABLES_FILE);
|
|
44
39
|
try {
|
package/dist/core/apply.test.js
CHANGED
|
@@ -116,7 +116,9 @@ describe("applyDiff", () => {
|
|
|
116
116
|
it("should apply delete action", async () => {
|
|
117
117
|
const remoteMonitor = createMonitor("old-monitor");
|
|
118
118
|
const diff = {
|
|
119
|
-
actions: [
|
|
119
|
+
actions: [
|
|
120
|
+
{ type: "delete", monitor: null, remoteMonitor, reason: "removed" },
|
|
121
|
+
],
|
|
120
122
|
summary: { creates: 0, updates: 0, deletes: 1, noops: 0 },
|
|
121
123
|
};
|
|
122
124
|
const mockMonitorApi = {
|
package/dist/core/state.d.ts
CHANGED
|
@@ -34,10 +34,6 @@ export declare function addEnvironment(name: string, config: EnvironmentConfig):
|
|
|
34
34
|
* Remove an environment
|
|
35
35
|
*/
|
|
36
36
|
export declare function removeEnvironment(name: string): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* Set the default environment
|
|
39
|
-
*/
|
|
40
|
-
export declare function setDefaultEnvironment(name: string): Promise<void>;
|
|
41
37
|
/**
|
|
42
38
|
* Get the current environment name (from flag, env var, or default)
|
|
43
39
|
*/
|
package/dist/core/state.js
CHANGED
|
@@ -84,10 +84,6 @@ export async function initState(projectId) {
|
|
|
84
84
|
export async function addEnvironment(name, config) {
|
|
85
85
|
const state = await loadState();
|
|
86
86
|
state.environments[name] = config;
|
|
87
|
-
// Set as default if it's the first environment
|
|
88
|
-
if (Object.keys(state.environments).length === 1) {
|
|
89
|
-
state.defaultEnvironment = name;
|
|
90
|
-
}
|
|
91
87
|
await saveState(state);
|
|
92
88
|
}
|
|
93
89
|
/**
|
|
@@ -95,26 +91,13 @@ export async function addEnvironment(name, config) {
|
|
|
95
91
|
*/
|
|
96
92
|
export async function removeEnvironment(name) {
|
|
97
93
|
const state = await loadState();
|
|
98
|
-
if (
|
|
99
|
-
throw new Error(
|
|
94
|
+
if (name === "default") {
|
|
95
|
+
throw new Error("Cannot remove default environment");
|
|
100
96
|
}
|
|
101
|
-
delete state.environments[name];
|
|
102
|
-
// Update default if we removed it
|
|
103
|
-
if (state.defaultEnvironment === name) {
|
|
104
|
-
const remaining = Object.keys(state.environments);
|
|
105
|
-
state.defaultEnvironment = remaining.length > 0 ? remaining[0] : undefined;
|
|
106
|
-
}
|
|
107
|
-
await saveState(state);
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Set the default environment
|
|
111
|
-
*/
|
|
112
|
-
export async function setDefaultEnvironment(name) {
|
|
113
|
-
const state = await loadState();
|
|
114
97
|
if (!(name in state.environments)) {
|
|
115
98
|
throw new Error(`Environment '${name}' does not exist`);
|
|
116
99
|
}
|
|
117
|
-
state.
|
|
100
|
+
delete state.environments[name];
|
|
118
101
|
await saveState(state);
|
|
119
102
|
}
|
|
120
103
|
/**
|
|
@@ -123,14 +106,13 @@ export async function setDefaultEnvironment(name) {
|
|
|
123
106
|
export async function resolveEnvironment(envFlag) {
|
|
124
107
|
const state = await loadState();
|
|
125
108
|
// Priority: CLI flag > ENV var > default > error
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
throw new Error("No environment specified. Pass the environment name as the first argument (e.g. griffin hub apply production). You can also set GRIFFIN_ENV or a default with 'griffin env default <name>'.");
|
|
109
|
+
if (!envFlag) {
|
|
110
|
+
return "default";
|
|
129
111
|
}
|
|
130
|
-
if (!(
|
|
131
|
-
throw new Error(`Environment '${
|
|
112
|
+
if (!(envFlag in state.environments)) {
|
|
113
|
+
throw new Error(`Environment '${envFlag}' not found. Available: ${Object.keys(state.environments).join(", ")}`);
|
|
132
114
|
}
|
|
133
|
-
return
|
|
115
|
+
return envFlag;
|
|
134
116
|
}
|
|
135
117
|
/**
|
|
136
118
|
* Get environment configuration
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { DiffAction, DiffResult } from "./core/diff.js";
|
|
|
5
5
|
export type { ApplyResult, ApplyAction, ApplyError } from "./core/apply.js";
|
|
6
6
|
export { createEmptyState, StateFileSchema, HubConfigSchema, } from "./schemas/state.js";
|
|
7
7
|
export { createEmptyCredentials, CredentialsFileSchema, HubCredentialsSchema, } from "./schemas/credentials.js";
|
|
8
|
-
export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, initState, addEnvironment, removeEnvironment,
|
|
8
|
+
export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, initState, addEnvironment, removeEnvironment, resolveEnvironment, getEnvironment, } from "./core/state.js";
|
|
9
9
|
export { getCredentialsDirPath, getCredentialsFilePath, credentialsExist, loadCredentials, saveCredentials, saveHubCredentials, getHubCredentials, removeHubCredentials, } from "./core/credentials.js";
|
|
10
10
|
export { discoverMonitors, formatDiscoveryErrors } from "./core/discovery.js";
|
|
11
11
|
export { computeDiff, formatDiff, formatDiffJson } from "./core/diff.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Export core functions
|
|
2
2
|
export { createEmptyState, StateFileSchema, HubConfigSchema, } from "./schemas/state.js";
|
|
3
3
|
export { createEmptyCredentials, CredentialsFileSchema, HubCredentialsSchema, } from "./schemas/credentials.js";
|
|
4
|
-
export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, initState, addEnvironment, removeEnvironment,
|
|
4
|
+
export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, initState, addEnvironment, removeEnvironment, resolveEnvironment, getEnvironment, } from "./core/state.js";
|
|
5
5
|
export { getCredentialsDirPath, getCredentialsFilePath, credentialsExist, loadCredentials, saveCredentials, saveHubCredentials, getHubCredentials, removeHubCredentials, } from "./core/credentials.js";
|
|
6
6
|
export { discoverMonitors, formatDiscoveryErrors } from "./core/discovery.js";
|
|
7
7
|
export { computeDiff, formatDiff, formatDiffJson } from "./core/diff.js";
|
package/dist/schemas/state.d.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
|
-
/**
|
|
3
|
-
* State file schema for tracking project configuration
|
|
4
|
-
* Stored in .griffin/state.json
|
|
5
|
-
*
|
|
6
|
-
* Note: The hub is now the source of truth for monitors.
|
|
7
|
-
* This file only stores configuration (project, environments, runner connection).
|
|
8
|
-
*/
|
|
9
2
|
export declare const EnvironmentConfigSchema: Type.TObject<{}>;
|
|
10
3
|
export type EnvironmentConfig = Static<typeof EnvironmentConfigSchema>;
|
|
4
|
+
export declare const CloudConfigSchema: Type.TObject<{
|
|
5
|
+
authUrl: Type.TString;
|
|
6
|
+
}>;
|
|
11
7
|
export declare const HubConfigSchema: Type.TObject<{
|
|
12
8
|
baseUrl: Type.TString;
|
|
13
|
-
clientId: Type.TString
|
|
9
|
+
clientId: Type.TOptional<Type.TString>;
|
|
14
10
|
}>;
|
|
15
11
|
export type HubConfig = Static<typeof HubConfigSchema>;
|
|
16
12
|
export declare const DiscoveryConfigSchema: Type.TObject<{
|
|
@@ -18,15 +14,22 @@ export declare const DiscoveryConfigSchema: Type.TObject<{
|
|
|
18
14
|
ignore: Type.TOptional<Type.TArray<Type.TString>>;
|
|
19
15
|
}>;
|
|
20
16
|
export type DiscoveryConfig = Static<typeof DiscoveryConfigSchema>;
|
|
17
|
+
export declare const EnvironmentsConfigSchema: Type.TIntersect<[Type.TObject<{
|
|
18
|
+
default: Type.TObject<{}>;
|
|
19
|
+
}>, Type.TRecord<"^.*$", Type.TObject<{}>>]>;
|
|
21
20
|
export declare const StateFileSchema: Type.TObject<{
|
|
22
21
|
stateVersion: Type.TLiteral<1>;
|
|
23
22
|
projectId: Type.TString;
|
|
24
|
-
environments: Type.
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
environments: Type.TIntersect<[Type.TObject<{
|
|
24
|
+
default: Type.TObject<{}>;
|
|
25
|
+
}>, Type.TRecord<"^.*$", Type.TObject<{}>>]>;
|
|
26
|
+
hub: Type.TObject<{
|
|
27
27
|
baseUrl: Type.TString;
|
|
28
|
-
clientId: Type.TString
|
|
29
|
-
}
|
|
28
|
+
clientId: Type.TOptional<Type.TString>;
|
|
29
|
+
}>;
|
|
30
|
+
cloud: Type.TObject<{
|
|
31
|
+
authUrl: Type.TString;
|
|
32
|
+
}>;
|
|
30
33
|
discovery: Type.TOptional<Type.TObject<{
|
|
31
34
|
pattern: Type.TOptional<Type.TString>;
|
|
32
35
|
ignore: Type.TOptional<Type.TArray<Type.TString>>;
|
|
@@ -37,7 +40,3 @@ export type StateFile = Static<typeof StateFileSchema>;
|
|
|
37
40
|
* Create an empty state file
|
|
38
41
|
*/
|
|
39
42
|
export declare function createEmptyState(projectId: string): StateFile;
|
|
40
|
-
/**
|
|
41
|
-
* Create state file with a default local environment
|
|
42
|
-
*/
|
|
43
|
-
export declare function createStateWithDefaultEnv(projectId: string): StateFile;
|
package/dist/schemas/state.js
CHANGED
|
@@ -6,24 +6,35 @@ import { Type } from "typebox";
|
|
|
6
6
|
* Note: The hub is now the source of truth for monitors.
|
|
7
7
|
* This file only stores configuration (project, environments, runner connection).
|
|
8
8
|
*/
|
|
9
|
+
const authUrl = "https://www.getgriffinapp.com/api/auth";
|
|
10
|
+
const hubBaseUrl = "https://griffin-hub.fly.dev";
|
|
9
11
|
export const EnvironmentConfigSchema = Type.Object({});
|
|
12
|
+
export const CloudConfigSchema = Type.Object({
|
|
13
|
+
authUrl: Type.String(),
|
|
14
|
+
});
|
|
10
15
|
export const HubConfigSchema = Type.Object({
|
|
11
16
|
baseUrl: Type.String(),
|
|
12
|
-
clientId: Type.String(),
|
|
17
|
+
clientId: Type.Optional(Type.String()),
|
|
13
18
|
});
|
|
14
19
|
export const DiscoveryConfigSchema = Type.Object({
|
|
15
20
|
pattern: Type.Optional(Type.String()),
|
|
16
21
|
ignore: Type.Optional(Type.Array(Type.String())),
|
|
17
22
|
});
|
|
23
|
+
export const EnvironmentsConfigSchema = Type.Intersect([
|
|
24
|
+
Type.Object({
|
|
25
|
+
default: EnvironmentConfigSchema,
|
|
26
|
+
}),
|
|
27
|
+
Type.Record(Type.String(), EnvironmentConfigSchema),
|
|
28
|
+
]);
|
|
18
29
|
// State schema (hub is source of truth for monitors)
|
|
19
30
|
export const StateFileSchema = Type.Object({
|
|
20
31
|
stateVersion: Type.Literal(1),
|
|
21
32
|
projectId: Type.String(),
|
|
22
33
|
// Environment configuration
|
|
23
|
-
environments:
|
|
24
|
-
defaultEnvironment: Type.Optional(Type.String()),
|
|
34
|
+
environments: EnvironmentsConfigSchema,
|
|
25
35
|
// Hub connection (for remote execution)
|
|
26
|
-
hub:
|
|
36
|
+
hub: HubConfigSchema,
|
|
37
|
+
cloud: CloudConfigSchema,
|
|
27
38
|
// Discovery settings
|
|
28
39
|
discovery: Type.Optional(DiscoveryConfigSchema),
|
|
29
40
|
});
|
|
@@ -31,22 +42,17 @@ export const StateFileSchema = Type.Object({
|
|
|
31
42
|
* Create an empty state file
|
|
32
43
|
*/
|
|
33
44
|
export function createEmptyState(projectId) {
|
|
34
|
-
return {
|
|
35
|
-
stateVersion: 1,
|
|
36
|
-
projectId,
|
|
37
|
-
environments: {},
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Create state file with a default local environment
|
|
42
|
-
*/
|
|
43
|
-
export function createStateWithDefaultEnv(projectId) {
|
|
44
45
|
return {
|
|
45
46
|
stateVersion: 1,
|
|
46
47
|
projectId,
|
|
47
48
|
environments: {
|
|
48
|
-
|
|
49
|
+
default: {},
|
|
50
|
+
},
|
|
51
|
+
hub: {
|
|
52
|
+
baseUrl: hubBaseUrl,
|
|
53
|
+
},
|
|
54
|
+
cloud: {
|
|
55
|
+
authUrl: authUrl,
|
|
49
56
|
},
|
|
50
|
-
defaultEnvironment: "local",
|
|
51
57
|
};
|
|
52
58
|
}
|
package/dist/test-runner.js
CHANGED
|
@@ -25,7 +25,7 @@ export async function runTestFile(filePath, envName) {
|
|
|
25
25
|
terminal.dim(`Project ID: ${projectId}`);
|
|
26
26
|
const resolvedMonitor = resolveMonitor(rawMonitor, projectId, envName, variables);
|
|
27
27
|
const secretRegistry = new SecretProviderRegistry();
|
|
28
|
-
secretRegistry.
|
|
28
|
+
secretRegistry.setProvider(new EnvSecretProvider());
|
|
29
29
|
try {
|
|
30
30
|
const result = await executeMonitorV1({
|
|
31
31
|
...resolvedMonitor,
|
package/dist/utils/sdk-error.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griffin-app/griffin-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "CLI tool for running and managing griffin API tests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"author": "",
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@griffin-app/griffin-hub-sdk": "1.0.
|
|
27
|
-
"@griffin-app/griffin-plan-executor": "0.1.
|
|
28
|
-
"@griffin-app/griffin-ts": "0.1.
|
|
26
|
+
"@griffin-app/griffin-hub-sdk": "1.0.10",
|
|
27
|
+
"@griffin-app/griffin-plan-executor": "0.1.16",
|
|
28
|
+
"@griffin-app/griffin-ts": "0.1.15",
|
|
29
29
|
"better-auth": "^1.4.17",
|
|
30
30
|
"cli-table3": "^0.6.5",
|
|
31
31
|
"commander": "^12.1.0",
|