@griffin-app/griffin-cli 1.0.10 → 1.0.11

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 CHANGED
@@ -197,7 +197,7 @@ integrations
197
197
  .requiredOption("--provider-type <type>", "Provider type (e.g. slack_webhook, datadog)")
198
198
  .requiredOption("--name <name>", "Display name")
199
199
  .option("--environment <env>", "Environment scope (omit for org-wide)")
200
- .option("--enabled/--no-enabled", "Enabled", true)
200
+ .option("--enabled", "Enabled")
201
201
  .option("--json", "Output as JSON")
202
202
  .action(async (options) => {
203
203
  await executeIntegrationsAdd({
@@ -214,7 +214,7 @@ integrations
214
214
  .description("Update an integration")
215
215
  .option("--name <name>", "Display name")
216
216
  .option("--environment <env>", "Environment scope")
217
- .option("--enabled/--no-enabled", "Enabled")
217
+ .option("--enabled", "Enabled")
218
218
  .option("--json", "Output as JSON")
219
219
  .action(async (id, options) => {
220
220
  await executeIntegrationsUpdate({
@@ -232,6 +232,23 @@ integrations
232
232
  .action(async (id) => {
233
233
  await executeIntegrationsRemove({ id });
234
234
  });
235
+ integrations
236
+ .command("connect <provider>")
237
+ .description("Connect an OAuth integration (opens browser)")
238
+ .option("--name <name>", "Display name for the integration")
239
+ .option("--environment <env>", "Environment scope")
240
+ .option("--category <cat>", "Category (default: notifications)")
241
+ .option("--json", "Output integration ID as JSON")
242
+ .action(async (provider, options) => {
243
+ const { executeIntegrationsConnect } = await import("./commands/hub/integrations.js");
244
+ await executeIntegrationsConnect({
245
+ providerType: provider,
246
+ name: options.name,
247
+ environment: options.environment,
248
+ category: options.category,
249
+ json: options.json,
250
+ });
251
+ });
235
252
  // Secrets command group
236
253
  const secrets = hub
237
254
  .command("secrets")
@@ -35,3 +35,11 @@ export interface IntegrationsRemoveOptions {
35
35
  force?: boolean;
36
36
  }
37
37
  export declare function executeIntegrationsRemove(options: IntegrationsRemoveOptions): Promise<void>;
38
+ export interface IntegrationsConnectOptions {
39
+ providerType: string;
40
+ name?: string;
41
+ environment?: string;
42
+ category?: string;
43
+ json?: boolean;
44
+ }
45
+ export declare function executeIntegrationsConnect(options: IntegrationsConnectOptions): Promise<void>;
@@ -1,3 +1,5 @@
1
+ import { exec } from "node:child_process";
2
+ import { platform } from "node:os";
1
3
  import { loadState } from "../../core/state.js";
2
4
  import { getHubCredentials } from "../../core/credentials.js";
3
5
  import { terminal } from "../../utils/terminal.js";
@@ -165,3 +167,89 @@ export async function executeIntegrationsRemove(options) {
165
167
  }
166
168
  terminal.info("Integration removed.");
167
169
  }
170
+ function openBrowser(url) {
171
+ const cmd = platform() === "darwin"
172
+ ? "open"
173
+ : platform() === "win32"
174
+ ? "start"
175
+ : "xdg-open";
176
+ exec(`${cmd} "${url.replace(/"/g, '\\"')}"`, (err) => {
177
+ if (err) {
178
+ terminal.dim(`Could not open browser: ${err.message}`);
179
+ }
180
+ });
181
+ }
182
+ const POLL_INITIAL_MS = 2000;
183
+ const POLL_MAX_MS = 10000;
184
+ const POLL_TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes
185
+ export async function executeIntegrationsConnect(options) {
186
+ const category = options.category ?? "notifications";
187
+ const body = {
188
+ category,
189
+ providerType: options.providerType,
190
+ name: options.name ?? undefined,
191
+ environment: options.environment ?? undefined,
192
+ };
193
+ const result = await hubFetch("/integrations/oauth/initiate", { method: "POST", body });
194
+ if (result.error) {
195
+ terminal.error(result.error);
196
+ process.exit(1);
197
+ }
198
+ const data = result.data;
199
+ if (!data) {
200
+ terminal.error("Initiate failed.");
201
+ process.exit(1);
202
+ }
203
+ terminal.info("Open this URL in your browser to authorize:");
204
+ terminal.log(data.authUrl);
205
+ terminal.blank();
206
+ openBrowser(data.authUrl);
207
+ terminal.info("Waiting for authorization… (polling)");
208
+ const start = Date.now();
209
+ let interval = POLL_INITIAL_MS;
210
+ const poll = async () => {
211
+ const statusResult = await hubFetch(`/integrations/oauth/status/${encodeURIComponent(data.transactionId)}`);
212
+ if (statusResult.error) {
213
+ throw new Error(statusResult.error);
214
+ }
215
+ const status = statusResult.data;
216
+ if (!status) {
217
+ throw new Error("Invalid status response");
218
+ }
219
+ if (status.status !== "pending") {
220
+ return status;
221
+ }
222
+ if (Date.now() - start >= POLL_TIMEOUT_MS) {
223
+ return { status: "expired", errorMessage: "Polling timed out" };
224
+ }
225
+ await new Promise((resolve) => setTimeout(resolve, interval));
226
+ interval = Math.min(interval + 1000, POLL_MAX_MS);
227
+ return poll();
228
+ };
229
+ try {
230
+ const status = await poll();
231
+ if (status.status === "completed" && status.integrationId) {
232
+ if (options.json) {
233
+ terminal.log(JSON.stringify({ integrationId: status.integrationId }, null, 2));
234
+ }
235
+ else {
236
+ terminal.success(`Integration connected: ${status.integrationId}`);
237
+ }
238
+ return;
239
+ }
240
+ if (status.status === "failed") {
241
+ terminal.error(status.errorMessage ?? "Authorization failed");
242
+ process.exit(1);
243
+ }
244
+ if (status.status === "expired") {
245
+ terminal.error(status.errorMessage ?? "Transaction expired");
246
+ process.exit(1);
247
+ }
248
+ terminal.error("Unexpected status");
249
+ process.exit(1);
250
+ }
251
+ catch (err) {
252
+ terminal.error(err instanceof Error ? err.message : "Polling failed");
253
+ process.exit(1);
254
+ }
255
+ }
@@ -1,5 +1,5 @@
1
- import { findTestFiles } from "../../test-discovery.js";
2
- import { runTestFile } from "../../test-runner.js";
1
+ import { findTestFiles } from "../../monitor-discovery.js";
2
+ import { runTestFile } from "../../monitor-runner.js";
3
3
  import { resolveEnvironment } from "../../core/state.js";
4
4
  import { terminal } from "../../utils/terminal.js";
5
5
  import { basename } from "path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@griffin-app/griffin-cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "CLI tool for running and managing griffin API tests",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,7 +24,7 @@
24
24
  "author": "",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
- "@griffin-app/griffin-hub-sdk": "1.0.13",
27
+ "@griffin-app/griffin-hub-sdk": "1.0.14",
28
28
  "@griffin-app/griffin-plan-executor": "0.1.18",
29
29
  "@griffin-app/griffin-ts": "0.1.16",
30
30
  "better-auth": "^1.4.17",