@griffin-app/griffin-cli 1.0.2 → 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 +69 -165
- package/dist/cli.js +21 -16
- package/dist/commands/env.d.ts +1 -22
- package/dist/commands/env.js +20 -109
- package/dist/commands/generate-key.js +16 -10
- package/dist/commands/hub/apply.js +51 -30
- package/dist/commands/hub/connect.js +7 -6
- package/dist/commands/hub/plan.js +31 -17
- package/dist/commands/hub/run.js +81 -52
- package/dist/commands/hub/runs.js +77 -37
- package/dist/commands/hub/status.js +12 -11
- package/dist/commands/init.js +32 -24
- package/dist/commands/local/run.js +30 -16
- package/dist/commands/validate.js +18 -17
- package/dist/core/apply.d.ts +2 -2
- package/dist/core/apply.js +33 -34
- package/dist/core/apply.test.js +45 -12
- package/dist/core/diff.d.ts +5 -5
- package/dist/core/diff.test.js +20 -11
- package/dist/core/discovery.d.ts +2 -3
- package/dist/core/discovery.js +3 -10
- package/dist/core/plan-diff.d.ts +4 -4
- package/dist/core/plan-diff.js +4 -3
- package/dist/core/sdk.d.ts +3 -11
- package/dist/core/sdk.js +14 -18
- package/dist/core/variables.js +14 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/resolve.d.ts +3 -0
- package/dist/resolve.js +9 -0
- package/dist/schemas/state.js +1 -3
- package/dist/test-runner.js +18 -22
- package/dist/utils/console.d.ts +5 -0
- package/dist/utils/console.js +5 -0
- package/dist/utils/terminal.d.ts +100 -0
- package/dist/utils/terminal.js +148 -0
- package/package.json +8 -4
package/dist/core/discovery.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type RawTestPlan = Omit<TestPlanV1, "id" | "environment" | "project">;
|
|
1
|
+
import type { PlanDSL } from "@griffin-app/griffin-ts/types";
|
|
3
2
|
export interface DiscoveredPlan {
|
|
4
|
-
plan:
|
|
3
|
+
plan: PlanDSL;
|
|
5
4
|
filePath: string;
|
|
6
5
|
exportName: string;
|
|
7
6
|
}
|
package/dist/core/discovery.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { glob } from "glob";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import {
|
|
4
|
+
import { PlanDSLSchema } from "@griffin-app/griffin-ts/schema";
|
|
5
5
|
import { Value } from "typebox/value";
|
|
6
|
-
import { Type } from "typebox";
|
|
7
|
-
const RawTestPlanSchema = Type.Omit(TestPlanV1Schema, [
|
|
8
|
-
"id",
|
|
9
|
-
"environment",
|
|
10
|
-
"project",
|
|
11
|
-
]);
|
|
12
6
|
/**
|
|
13
7
|
* Discover and load test plan files from the filesystem
|
|
14
8
|
*/
|
|
@@ -21,7 +15,6 @@ export async function discoverPlans(pattern, ignore) {
|
|
|
21
15
|
absolute: true,
|
|
22
16
|
cwd: process.cwd(),
|
|
23
17
|
});
|
|
24
|
-
console.log(`Found ${files.length} test file(s)`);
|
|
25
18
|
// Load each file
|
|
26
19
|
for (const filePath of files) {
|
|
27
20
|
try {
|
|
@@ -38,7 +31,7 @@ export async function discoverPlans(pattern, ignore) {
|
|
|
38
31
|
return { plans, errors };
|
|
39
32
|
}
|
|
40
33
|
function isPlan(value) {
|
|
41
|
-
return Value.Check(
|
|
34
|
+
return Value.Check(PlanDSLSchema, value);
|
|
42
35
|
}
|
|
43
36
|
/**
|
|
44
37
|
* Load plans from a single file
|
|
@@ -60,7 +53,7 @@ async function loadPlansFromFile(filePath) {
|
|
|
60
53
|
});
|
|
61
54
|
}
|
|
62
55
|
else {
|
|
63
|
-
const errors = Value.Errors(
|
|
56
|
+
const errors = Value.Errors(PlanDSLSchema, module.default);
|
|
64
57
|
throw new Error(`Default export is not a valid TestPlan. Got: ${JSON.stringify(errors, null, 2)}`);
|
|
65
58
|
}
|
|
66
59
|
}
|
package/dist/core/plan-diff.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
1
|
+
import type { PlanDSL } from "@griffin-app/griffin-ts/types";
|
|
2
|
+
import { PlanV1 } from "@griffin-app/griffin-hub-sdk";
|
|
3
3
|
import { NodeType } from "@griffin-app/griffin-ts/schema";
|
|
4
4
|
/**
|
|
5
5
|
* Represents a change to a single field
|
|
@@ -15,7 +15,7 @@ export interface FieldChange {
|
|
|
15
15
|
export interface NodeChange {
|
|
16
16
|
type: "add" | "remove" | "modify";
|
|
17
17
|
nodeId: string;
|
|
18
|
-
nodeType: NodeType;
|
|
18
|
+
nodeType: NodeType.ASSERTION | NodeType.ENDPOINT | NodeType.WAIT;
|
|
19
19
|
summary: string;
|
|
20
20
|
fieldChanges: FieldChange[];
|
|
21
21
|
}
|
|
@@ -39,4 +39,4 @@ export interface PlanChanges {
|
|
|
39
39
|
/**
|
|
40
40
|
* Compare two test plans and return granular changes
|
|
41
41
|
*/
|
|
42
|
-
export declare function comparePlans(local:
|
|
42
|
+
export declare function comparePlans(local: PlanDSL, remote: PlanV1): PlanChanges;
|
package/dist/core/plan-diff.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import objectHash from "object-hash";
|
|
2
|
+
import { NodeType } from "@griffin-app/griffin-ts/schema";
|
|
2
3
|
/**
|
|
3
4
|
* Compare two test plans and return granular changes
|
|
4
5
|
*/
|
|
@@ -116,13 +117,13 @@ function compareNodeFields(local, remote) {
|
|
|
116
117
|
return changes;
|
|
117
118
|
}
|
|
118
119
|
switch (local.type) {
|
|
119
|
-
case
|
|
120
|
+
case NodeType.ENDPOINT:
|
|
120
121
|
compareEndpointFields(local, remote, changes);
|
|
121
122
|
break;
|
|
122
|
-
case
|
|
123
|
+
case NodeType.WAIT:
|
|
123
124
|
compareWaitFields(local, remote, changes);
|
|
124
125
|
break;
|
|
125
|
-
case
|
|
126
|
+
case NodeType.ASSERTION:
|
|
126
127
|
compareAssertionFields(local, remote, changes);
|
|
127
128
|
break;
|
|
128
129
|
}
|
package/dist/core/sdk.d.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { TestPlanV1 } from "@griffin-app/griffin-ts/types";
|
|
1
|
+
import { GriffinHubSdk } from "@griffin-app/griffin-hub-sdk";
|
|
3
2
|
/**
|
|
4
3
|
* Create configured SDK API instances
|
|
5
4
|
*/
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function createSdk(config: {
|
|
7
6
|
baseUrl: string;
|
|
8
7
|
apiToken?: string;
|
|
9
|
-
}):
|
|
10
|
-
planApi: PlanApi;
|
|
11
|
-
runsApi: RunsApi;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Inject projectId into a plan payload before sending to runner
|
|
15
|
-
*/
|
|
16
|
-
export declare function injectProjectId(plan: Omit<TestPlanV1, "project">, projectId: string): TestPlanV1;
|
|
8
|
+
}): GriffinHubSdk;
|
package/dist/core/sdk.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GriffinHubSdk } from "@griffin-app/griffin-hub-sdk";
|
|
2
|
+
import { createClient } from "@griffin-app/griffin-hub-sdk/client";
|
|
2
3
|
/**
|
|
3
4
|
* Create configured SDK API instances
|
|
4
5
|
*/
|
|
5
|
-
export function
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
accessToken: config.apiToken,
|
|
6
|
+
export function createSdk(config) {
|
|
7
|
+
const client = createClient({
|
|
8
|
+
baseURL: config.baseUrl,
|
|
9
9
|
});
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
...plan,
|
|
21
|
-
project: projectId,
|
|
22
|
-
};
|
|
10
|
+
client.setConfig({
|
|
11
|
+
auth() {
|
|
12
|
+
return config.apiToken;
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const sdk = new GriffinHubSdk({
|
|
16
|
+
client: client,
|
|
17
|
+
});
|
|
18
|
+
return sdk;
|
|
23
19
|
}
|
package/dist/core/variables.js
CHANGED
|
@@ -46,6 +46,17 @@ function isVariableRef(value) {
|
|
|
46
46
|
return (typeof varData.key === "string" &&
|
|
47
47
|
(varData.template === undefined || typeof varData.template === "string"));
|
|
48
48
|
}
|
|
49
|
+
function isStringLiteral(value) {
|
|
50
|
+
if (typeof value !== "object" || value === null) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const obj = value;
|
|
54
|
+
if (!("$literal" in obj) ||
|
|
55
|
+
typeof obj.$literal !== "string") {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
49
60
|
/**
|
|
50
61
|
* Resolve a single variable reference to its string value.
|
|
51
62
|
*
|
|
@@ -83,6 +94,9 @@ export function resolveVariablesInPlan(obj, variables) {
|
|
|
83
94
|
if (isVariableRef(obj)) {
|
|
84
95
|
return resolveVariable(obj, variables);
|
|
85
96
|
}
|
|
97
|
+
if (isStringLiteral(obj)) {
|
|
98
|
+
return obj.$literal;
|
|
99
|
+
}
|
|
86
100
|
// Recursively process arrays
|
|
87
101
|
if (Array.isArray(obj)) {
|
|
88
102
|
return obj.map((item) => resolveVariablesInPlan(item, variables));
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, i
|
|
|
7
7
|
export { discoverPlans, formatDiscoveryErrors } from "./core/discovery.js";
|
|
8
8
|
export { computeDiff, formatDiff, formatDiffJson } from "./core/diff.js";
|
|
9
9
|
export { applyDiff, formatApplyResult } from "./core/apply.js";
|
|
10
|
-
export {
|
|
10
|
+
export { createSdk } from "./core/sdk.js";
|
|
11
11
|
export { detectProjectId } from "./core/project.js";
|
|
12
12
|
export { executeInit } from "./commands/init.js";
|
|
13
13
|
export { executeValidate } from "./commands/validate.js";
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { getStateDirPath, getStateFilePath, stateExists, loadState, saveState, i
|
|
|
4
4
|
export { discoverPlans, formatDiscoveryErrors } from "./core/discovery.js";
|
|
5
5
|
export { computeDiff, formatDiff, formatDiffJson } from "./core/diff.js";
|
|
6
6
|
export { applyDiff, formatApplyResult } from "./core/apply.js";
|
|
7
|
-
export {
|
|
7
|
+
export { createSdk } from "./core/sdk.js";
|
|
8
8
|
export { detectProjectId } from "./core/project.js";
|
|
9
9
|
// Export command executors (for programmatic use)
|
|
10
10
|
export { executeInit } from "./commands/init.js";
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { resolveVariablesInPlan } from "./core/variables.js";
|
|
2
|
+
export function resolvePlan(plan, projectId, envName, variables) {
|
|
3
|
+
const resolvedPlan = resolveVariablesInPlan(plan, variables);
|
|
4
|
+
return {
|
|
5
|
+
...resolvedPlan,
|
|
6
|
+
project: projectId,
|
|
7
|
+
environment: envName,
|
|
8
|
+
};
|
|
9
|
+
}
|
package/dist/schemas/state.js
CHANGED
|
@@ -6,9 +6,7 @@ import { Type } from "typebox";
|
|
|
6
6
|
* Note: The hub is now the source of truth for plans.
|
|
7
7
|
* This file only stores configuration (project, environments, runner connection).
|
|
8
8
|
*/
|
|
9
|
-
export const EnvironmentConfigSchema = Type.Object({
|
|
10
|
-
// Empty for now - may be used for environment-specific config in the future
|
|
11
|
-
});
|
|
9
|
+
export const EnvironmentConfigSchema = Type.Object({});
|
|
12
10
|
export const RunnerConfigSchema = Type.Object({
|
|
13
11
|
baseUrl: Type.String(),
|
|
14
12
|
apiToken: Type.Optional(Type.String()),
|
package/dist/test-runner.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import "tsx";
|
|
2
2
|
import { Value } from "typebox/value";
|
|
3
3
|
import { executePlanV1, AxiosAdapter, EnvSecretProvider, SecretProviderRegistry, } from "@griffin-app/griffin-plan-executor";
|
|
4
|
-
import {
|
|
5
|
-
import { Type } from "typebox";
|
|
4
|
+
import { PlanDSLSchema } from "@griffin-app/griffin-ts/schema";
|
|
6
5
|
import { randomUUID } from "crypto";
|
|
7
|
-
import { loadVariables
|
|
6
|
+
import { loadVariables } from "./core/variables.js";
|
|
8
7
|
import { getProjectId } from "./core/state.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import { resolvePlan } from "./resolve.js";
|
|
9
|
+
import { terminal } from "./utils/terminal.js";
|
|
10
|
+
function validateDsl(plan) {
|
|
11
|
+
const errors = Value.Errors(PlanDSLSchema, plan);
|
|
12
|
+
if (errors.length > 0) {
|
|
13
|
+
throw new Error(`Invalid plan: ${JSON.stringify([...errors], null, 2)}`);
|
|
14
|
+
}
|
|
15
|
+
return plan;
|
|
16
|
+
}
|
|
14
17
|
/**
|
|
15
18
|
* Runs a TypeScript test file and executes the resulting JSON plan.
|
|
16
19
|
*/
|
|
@@ -18,31 +21,24 @@ export async function runTestFile(filePath, envName) {
|
|
|
18
21
|
const variables = await loadVariables(envName);
|
|
19
22
|
const projectId = await getProjectId();
|
|
20
23
|
const defaultExport = await import(filePath);
|
|
21
|
-
const rawPlan = defaultExport.default;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const resolvedPlan = resolveVariablesInPlan(rawPlan, variables);
|
|
24
|
+
const rawPlan = validateDsl(defaultExport.default);
|
|
25
|
+
terminal.dim(`Project ID: ${projectId}`);
|
|
26
|
+
const resolvedPlan = resolvePlan(rawPlan, projectId, envName, variables);
|
|
25
27
|
const secretRegistry = new SecretProviderRegistry();
|
|
26
28
|
secretRegistry.register(new EnvSecretProvider());
|
|
27
29
|
try {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
...parsedPlan,
|
|
30
|
+
const result = await executePlanV1({
|
|
31
|
+
...resolvedPlan,
|
|
31
32
|
id: randomUUID(),
|
|
32
|
-
|
|
33
|
-
environment: envName,
|
|
34
|
-
};
|
|
35
|
-
const result = await executePlanV1(syntheticPlan, "default-org", {
|
|
33
|
+
}, "default-org", {
|
|
36
34
|
mode: "local",
|
|
37
35
|
httpClient: new AxiosAdapter(),
|
|
38
36
|
secretRegistry: secretRegistry,
|
|
39
37
|
});
|
|
40
|
-
console.log(JSON.stringify(result, null, 2));
|
|
41
38
|
return result;
|
|
42
39
|
}
|
|
43
40
|
catch (error) {
|
|
44
|
-
|
|
45
|
-
throw new Error(`Invalid plan: ${JSON.stringify([...errors], null, 2)}: ${error}`);
|
|
41
|
+
throw new Error(`Error executing plan: ${error instanceof Error ? error.message : String(error)}`);
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
44
|
//function findWorkspaceRoot(): string {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Ora } from "ora";
|
|
2
|
+
import Table from "cli-table3";
|
|
3
|
+
/**
|
|
4
|
+
* Color utilities
|
|
5
|
+
*/
|
|
6
|
+
export declare const colors: {
|
|
7
|
+
readonly cyan: import("picocolors/types").Formatter;
|
|
8
|
+
readonly green: import("picocolors/types").Formatter;
|
|
9
|
+
readonly yellow: import("picocolors/types").Formatter;
|
|
10
|
+
readonly red: import("picocolors/types").Formatter;
|
|
11
|
+
readonly blue: import("picocolors/types").Formatter;
|
|
12
|
+
readonly magenta: import("picocolors/types").Formatter;
|
|
13
|
+
readonly gray: import("picocolors/types").Formatter;
|
|
14
|
+
readonly dim: import("picocolors/types").Formatter;
|
|
15
|
+
readonly bold: import("picocolors/types").Formatter;
|
|
16
|
+
readonly underline: import("picocolors/types").Formatter;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Unified Terminal interface for all CLI interactions
|
|
20
|
+
*/
|
|
21
|
+
export declare class Terminal {
|
|
22
|
+
/**
|
|
23
|
+
* Log info message with icon
|
|
24
|
+
*/
|
|
25
|
+
info(message: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Log success message with icon
|
|
28
|
+
*/
|
|
29
|
+
success(message: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Log warning message with icon
|
|
32
|
+
*/
|
|
33
|
+
warn(message: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Log error message with icon to stderr
|
|
36
|
+
*/
|
|
37
|
+
error(message: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Log plain message (no styling)
|
|
40
|
+
*/
|
|
41
|
+
log(message: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Log dimmed/secondary message
|
|
44
|
+
*/
|
|
45
|
+
dim(message: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Log a blank line
|
|
48
|
+
*/
|
|
49
|
+
blank(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Create a spinner for async operations
|
|
52
|
+
*/
|
|
53
|
+
spinner(text: string): Ora;
|
|
54
|
+
/**
|
|
55
|
+
* Ask for confirmation (yes/no)
|
|
56
|
+
*/
|
|
57
|
+
confirm(message: string, initial?: boolean): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Prompt user to select from a list
|
|
60
|
+
*/
|
|
61
|
+
select<T extends string>(message: string, choices: T[]): Promise<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Prompt user for text input
|
|
64
|
+
*/
|
|
65
|
+
input(message: string, initial?: string): Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Create a formatted table
|
|
68
|
+
*/
|
|
69
|
+
table(options?: {
|
|
70
|
+
head?: string[];
|
|
71
|
+
colWidths?: number[];
|
|
72
|
+
}): Table.Table;
|
|
73
|
+
/**
|
|
74
|
+
* Print a formatted table
|
|
75
|
+
*/
|
|
76
|
+
printTable(data: Array<Record<string, any>>, columns?: string[]): void;
|
|
77
|
+
/**
|
|
78
|
+
* Access to color functions
|
|
79
|
+
*/
|
|
80
|
+
get colors(): {
|
|
81
|
+
readonly cyan: import("picocolors/types").Formatter;
|
|
82
|
+
readonly green: import("picocolors/types").Formatter;
|
|
83
|
+
readonly yellow: import("picocolors/types").Formatter;
|
|
84
|
+
readonly red: import("picocolors/types").Formatter;
|
|
85
|
+
readonly blue: import("picocolors/types").Formatter;
|
|
86
|
+
readonly magenta: import("picocolors/types").Formatter;
|
|
87
|
+
readonly gray: import("picocolors/types").Formatter;
|
|
88
|
+
readonly dim: import("picocolors/types").Formatter;
|
|
89
|
+
readonly bold: import("picocolors/types").Formatter;
|
|
90
|
+
readonly underline: import("picocolors/types").Formatter;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Exit process with error code
|
|
94
|
+
*/
|
|
95
|
+
exit(code: number): never;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Default terminal instance
|
|
99
|
+
*/
|
|
100
|
+
export declare const terminal: Terminal;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import enquirer from "enquirer";
|
|
4
|
+
import Table from "cli-table3";
|
|
5
|
+
/**
|
|
6
|
+
* Color utilities
|
|
7
|
+
*/
|
|
8
|
+
export const colors = {
|
|
9
|
+
cyan: pc.cyan,
|
|
10
|
+
green: pc.green,
|
|
11
|
+
yellow: pc.yellow,
|
|
12
|
+
red: pc.red,
|
|
13
|
+
blue: pc.blue,
|
|
14
|
+
magenta: pc.magenta,
|
|
15
|
+
gray: pc.gray,
|
|
16
|
+
dim: pc.dim,
|
|
17
|
+
bold: pc.bold,
|
|
18
|
+
underline: pc.underline,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Unified Terminal interface for all CLI interactions
|
|
22
|
+
*/
|
|
23
|
+
export class Terminal {
|
|
24
|
+
/**
|
|
25
|
+
* Log info message with icon
|
|
26
|
+
*/
|
|
27
|
+
info(message) {
|
|
28
|
+
console.log(pc.blue("ℹ"), message);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Log success message with icon
|
|
32
|
+
*/
|
|
33
|
+
success(message) {
|
|
34
|
+
console.log(pc.green("✔"), message);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Log warning message with icon
|
|
38
|
+
*/
|
|
39
|
+
warn(message) {
|
|
40
|
+
console.log(pc.yellow("⚠"), message);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Log error message with icon to stderr
|
|
44
|
+
*/
|
|
45
|
+
error(message) {
|
|
46
|
+
console.error(pc.red("✖"), message);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Log plain message (no styling)
|
|
50
|
+
*/
|
|
51
|
+
log(message) {
|
|
52
|
+
console.log(message);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Log dimmed/secondary message
|
|
56
|
+
*/
|
|
57
|
+
dim(message) {
|
|
58
|
+
console.log(pc.dim(message));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Log a blank line
|
|
62
|
+
*/
|
|
63
|
+
blank() {
|
|
64
|
+
console.log("");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a spinner for async operations
|
|
68
|
+
*/
|
|
69
|
+
spinner(text) {
|
|
70
|
+
return ora(text);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Ask for confirmation (yes/no)
|
|
74
|
+
*/
|
|
75
|
+
async confirm(message, initial = false) {
|
|
76
|
+
const response = await enquirer.prompt({
|
|
77
|
+
type: "confirm",
|
|
78
|
+
name: "confirmed",
|
|
79
|
+
message,
|
|
80
|
+
initial,
|
|
81
|
+
});
|
|
82
|
+
return response.confirmed;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Prompt user to select from a list
|
|
86
|
+
*/
|
|
87
|
+
async select(message, choices) {
|
|
88
|
+
const response = await enquirer.prompt({
|
|
89
|
+
type: "select",
|
|
90
|
+
name: "selected",
|
|
91
|
+
message,
|
|
92
|
+
choices,
|
|
93
|
+
});
|
|
94
|
+
return response.selected;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Prompt user for text input
|
|
98
|
+
*/
|
|
99
|
+
async input(message, initial) {
|
|
100
|
+
const response = await enquirer.prompt({
|
|
101
|
+
type: "input",
|
|
102
|
+
name: "value",
|
|
103
|
+
message,
|
|
104
|
+
initial,
|
|
105
|
+
});
|
|
106
|
+
return response.value;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a formatted table
|
|
110
|
+
*/
|
|
111
|
+
table(options) {
|
|
112
|
+
return new Table({
|
|
113
|
+
head: options?.head,
|
|
114
|
+
style: { head: ["cyan"] },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Print a formatted table
|
|
119
|
+
*/
|
|
120
|
+
printTable(data, columns) {
|
|
121
|
+
if (data.length === 0) {
|
|
122
|
+
this.dim("(no data)");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const cols = columns || Object.keys(data[0]);
|
|
126
|
+
const table = this.table({ head: cols });
|
|
127
|
+
for (const row of data) {
|
|
128
|
+
table.push(cols.map((col) => row[col]?.toString() || ""));
|
|
129
|
+
}
|
|
130
|
+
console.log(table.toString());
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Access to color functions
|
|
134
|
+
*/
|
|
135
|
+
get colors() {
|
|
136
|
+
return colors;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Exit process with error code
|
|
140
|
+
*/
|
|
141
|
+
exit(code) {
|
|
142
|
+
process.exit(code);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Default terminal instance
|
|
147
|
+
*/
|
|
148
|
+
export const terminal = new Terminal();
|
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.4",
|
|
4
4
|
"description": "CLI tool for running and managing griffin API tests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,12 +23,16 @@
|
|
|
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.2",
|
|
27
|
+
"@griffin-app/griffin-plan-executor": "0.1.10",
|
|
28
|
+
"@griffin-app/griffin-ts": "0.1.8",
|
|
29
|
+
"cli-table3": "^0.6.5",
|
|
29
30
|
"commander": "^12.1.0",
|
|
31
|
+
"enquirer": "^2.4.1",
|
|
30
32
|
"glob": "^11.0.0",
|
|
31
33
|
"object-hash": "^3.0.0",
|
|
34
|
+
"ora": "^8.1.1",
|
|
35
|
+
"picocolors": "^1.1.1",
|
|
32
36
|
"typebox": "^1.0.78",
|
|
33
37
|
"yaml": "^2.8.2"
|
|
34
38
|
},
|