@griffin-app/griffin-cli 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +38 -38
  2. package/dist/cli.js +79 -11
  3. package/dist/commands/apply.js +7 -7
  4. package/dist/commands/deploy.js +1 -1
  5. package/dist/commands/hub/apply.d.ts +1 -1
  6. package/dist/commands/hub/apply.js +17 -17
  7. package/dist/commands/hub/login.js +2 -6
  8. package/dist/commands/hub/metrics.d.ts +12 -0
  9. package/dist/commands/hub/metrics.js +78 -0
  10. package/dist/commands/hub/monitor.d.ts +8 -0
  11. package/dist/commands/hub/monitor.js +75 -0
  12. package/dist/commands/hub/notifications.d.ts +36 -0
  13. package/dist/commands/hub/notifications.js +225 -0
  14. package/dist/commands/hub/plan.d.ts +2 -2
  15. package/dist/commands/hub/plan.js +16 -16
  16. package/dist/commands/hub/run.d.ts +2 -2
  17. package/dist/commands/hub/run.js +33 -33
  18. package/dist/commands/hub/runs.d.ts +1 -1
  19. package/dist/commands/hub/runs.js +4 -4
  20. package/dist/commands/init.js +28 -12
  21. package/dist/commands/local/run.d.ts +2 -2
  22. package/dist/commands/local/run.js +1 -1
  23. package/dist/commands/plan.d.ts +2 -2
  24. package/dist/commands/plan.js +7 -7
  25. package/dist/commands/run-remote.d.ts +1 -1
  26. package/dist/commands/run-remote.js +10 -10
  27. package/dist/commands/validate.d.ts +1 -1
  28. package/dist/commands/validate.js +12 -12
  29. package/dist/core/apply.d.ts +2 -2
  30. package/dist/core/apply.js +25 -25
  31. package/dist/core/apply.test.js +54 -54
  32. package/dist/core/diff.d.ts +14 -14
  33. package/dist/core/diff.js +42 -42
  34. package/dist/core/diff.test.js +34 -34
  35. package/dist/core/discovery.d.ts +6 -6
  36. package/dist/core/discovery.js +20 -20
  37. package/dist/core/monitor-diff.d.ts +41 -0
  38. package/dist/core/monitor-diff.js +257 -0
  39. package/dist/core/plan-diff.d.ts +6 -6
  40. package/dist/core/plan-diff.js +5 -5
  41. package/dist/core/state.js +2 -2
  42. package/dist/core/variables.d.ts +5 -5
  43. package/dist/core/variables.js +7 -7
  44. package/dist/index.d.ts +3 -3
  45. package/dist/index.js +2 -2
  46. package/dist/output/context.d.ts +18 -0
  47. package/dist/output/context.js +22 -0
  48. package/dist/output/index.d.ts +3 -0
  49. package/dist/output/index.js +2 -0
  50. package/dist/output/renderer.d.ts +6 -0
  51. package/dist/output/renderer.js +348 -0
  52. package/dist/output/types.d.ts +153 -0
  53. package/dist/output/types.js +1 -0
  54. package/dist/resolve.d.ts +3 -3
  55. package/dist/resolve.js +9 -9
  56. package/dist/schemas/payload.d.ts +3 -3
  57. package/dist/schemas/payload.js +3 -3
  58. package/dist/schemas/state.d.ts +1 -1
  59. package/dist/schemas/state.js +2 -2
  60. package/dist/test-runner.d.ts +1 -1
  61. package/dist/test-runner.js +13 -13
  62. package/dist/utils/sdk-error.js +2 -0
  63. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
1
  export interface RunLocalOptions {
2
- env?: string;
2
+ env: string;
3
3
  }
4
- export declare function executeRunLocal(options?: RunLocalOptions): Promise<void>;
4
+ export declare function executeRunLocal(options: RunLocalOptions): Promise<void>;
@@ -3,7 +3,7 @@ import { runTestFile } from "../../test-runner.js";
3
3
  import { resolveEnvironment } from "../../core/state.js";
4
4
  import { terminal } from "../../utils/terminal.js";
5
5
  import { basename } from "path";
6
- export async function executeRunLocal(options = {}) {
6
+ export async function executeRunLocal(options) {
7
7
  try {
8
8
  // Resolve environment
9
9
  const envName = await resolveEnvironment(options.env);
@@ -1,8 +1,8 @@
1
- export interface PlanOptions {
1
+ export interface MonitorOptions {
2
2
  json?: boolean;
3
3
  env?: string;
4
4
  }
5
5
  /**
6
6
  * Show what changes would be applied
7
7
  */
8
- export declare function executePlan(options: PlanOptions): Promise<void>;
8
+ export declare function executeMonitor(options: MonitorOptions): Promise<void>;
@@ -1,11 +1,11 @@
1
1
  import { loadState, resolveEnvironment } from "../core/state.js";
2
- import { discoverPlans, formatDiscoveryErrors } from "../core/discovery.js";
2
+ import { discoverMonitors, formatDiscoveryErrors } from "../core/discovery.js";
3
3
  import { createSdkClients } from "../core/sdk.js";
4
4
  import { computeDiff, formatDiff, formatDiffJson } from "../core/diff.js";
5
5
  /**
6
6
  * Show what changes would be applied
7
7
  */
8
- export async function executePlan(options) {
8
+ export async function executeMonitor(options) {
9
9
  try {
10
10
  // Load state
11
11
  const state = await loadState();
@@ -17,13 +17,13 @@ export async function executePlan(options) {
17
17
  console.log(" griffin runner set --base-url <url> --api-token <token>");
18
18
  process.exit(1);
19
19
  }
20
- // Discover local plans
20
+ // Discover local monitors
21
21
  const discoveryPattern = state.discovery?.pattern || "**/__griffin__/*.{ts,js}";
22
22
  const discoveryIgnore = state.discovery?.ignore || [
23
23
  "node_modules/**",
24
24
  "dist/**",
25
25
  ];
26
- const { plans, errors } = await discoverPlans(discoveryPattern, discoveryIgnore);
26
+ const { monitors, errors } = await discoverMonitors(discoveryPattern, discoveryIgnore);
27
27
  if (errors.length > 0) {
28
28
  console.error(formatDiscoveryErrors(errors));
29
29
  process.exit(1);
@@ -33,11 +33,11 @@ export async function executePlan(options) {
33
33
  baseUrl: state.runner.baseUrl,
34
34
  apiToken: state.runner.apiToken || undefined,
35
35
  });
36
- // Fetch remote plans for this project
36
+ // Fetch remote monitors for this project
37
37
  const response = await planApi.planGet(state.projectId);
38
- const remotePlans = response.data.data.map((p) => p);
38
+ const remoteMonitors = response.data.data.map((p) => p);
39
39
  // Compute diff for this environment
40
- const diff = computeDiff(plans.map((p) => p.plan), state, remotePlans, envName);
40
+ const diff = computeDiff(monitors.map((p) => p.monitor), state, remoteMonitors, envName);
41
41
  // Output
42
42
  if (options.json) {
43
43
  console.log(formatDiffJson(diff));
@@ -6,6 +6,6 @@ export interface RunOptions {
6
6
  targetEnv?: string;
7
7
  }
8
8
  /**
9
- * Trigger a plan run on the runner
9
+ * Trigger a monitor run on the runner
10
10
  */
11
11
  export declare function executeRun(options: RunOptions): Promise<void>;
@@ -1,13 +1,13 @@
1
1
  import { loadState, resolveEnvironment } from "../core/state.js";
2
2
  import { createSdkClients } from "../core/sdk.js";
3
3
  /**
4
- * Trigger a plan run on the runner
4
+ * Trigger a monitor run on the runner
5
5
  */
6
6
  export async function executeRun(options) {
7
7
  try {
8
- // TODO: remove this. Users shoud be able to execute all plans if they want.
8
+ // TODO: remove this. Users shoud be able to execute all monitors if they want.
9
9
  if (!options.planId && !options.planName) {
10
- console.error("Error: Either --plan-id or --plan-name must be provided");
10
+ console.error("Error: Either --monitor-id or --monitor-name must be provided");
11
11
  process.exit(1);
12
12
  }
13
13
  if (!options.targetEnv) {
@@ -27,24 +27,24 @@ export async function executeRun(options) {
27
27
  baseUrl: state.runner.baseUrl,
28
28
  apiToken: state.runner.apiToken || undefined,
29
29
  });
30
- // Resolve plan ID from name if needed
30
+ // Resolve monitor ID from name if needed
31
31
  let planId = options.planId;
32
32
  if (!planId && options.planName) {
33
33
  // Resolve environment to search in
34
34
  const envName = await resolveEnvironment(options.env);
35
- const envPlans = state.plans[envName] || [];
36
- const stateEntry = envPlans.find((p) => p.planName === options.planName);
35
+ const envMonitors = state.monitors[envName] || [];
36
+ const stateEntry = envMonitors.find((p) => p.planName === options.planName);
37
37
  if (!stateEntry) {
38
- console.error(`Error: Plan "${options.planName}" not found in state`);
39
- console.error("Run 'griffin apply' to sync your plans first");
38
+ console.error(`Error: Monitor "${options.planName}" not found in state`);
39
+ console.error("Run 'griffin apply' to sync your monitors first");
40
40
  process.exit(1);
41
41
  }
42
42
  planId = stateEntry.planId;
43
43
  }
44
44
  // Trigger the run with environment
45
- console.log(`Triggering run for plan: ${planId}`);
45
+ console.log(`Triggering run for monitor: ${planId}`);
46
46
  console.log(`Target environment: ${options.targetEnv}`);
47
- const response = await runsApi.runsTriggerPlanIdPost(planId, {
47
+ const response = await runsApi.runsTriggerMonitorIdPost(planId, {
48
48
  environment: options.targetEnv,
49
49
  });
50
50
  console.log(`Run ID: ${response.data.data.id}`);
@@ -1,4 +1,4 @@
1
1
  /**
2
- * Validate test plan files without syncing
2
+ * Validate test monitor files without syncing
3
3
  */
4
4
  export declare function executeValidate(): Promise<void>;
@@ -1,11 +1,11 @@
1
1
  import { loadState } from "../core/state.js";
2
- import { discoverPlans, formatDiscoveryErrors } from "../core/discovery.js";
2
+ import { discoverMonitors, formatDiscoveryErrors } from "../core/discovery.js";
3
3
  import { terminal } from "../utils/terminal.js";
4
4
  /**
5
- * Validate test plan files without syncing
5
+ * Validate test monitor files without syncing
6
6
  */
7
7
  export async function executeValidate() {
8
- const spinner = terminal.spinner("Validating test plans...").start();
8
+ const spinner = terminal.spinner("Validating test monitors...").start();
9
9
  try {
10
10
  // Load state for discovery settings
11
11
  const state = await loadState();
@@ -14,8 +14,8 @@ export async function executeValidate() {
14
14
  "node_modules/**",
15
15
  "dist/**",
16
16
  ];
17
- // Discover plans
18
- const { plans, errors } = await discoverPlans(discoveryPattern, discoveryIgnore);
17
+ // Discover monitors
18
+ const { monitors, errors } = await discoverMonitors(discoveryPattern, discoveryIgnore);
19
19
  // Report errors
20
20
  if (errors.length > 0) {
21
21
  spinner.fail(`Validation failed with ${errors.length} error(s)`);
@@ -24,20 +24,20 @@ export async function executeValidate() {
24
24
  terminal.exit(1);
25
25
  }
26
26
  // Report success
27
- spinner.succeed(`Found ${terminal.colors.bold(plans.length.toString())} valid plan(s)`);
27
+ spinner.succeed(`Found ${terminal.colors.bold(monitors.length.toString())} valid monitor(s)`);
28
28
  terminal.blank();
29
- for (const { plan, filePath, exportName } of plans) {
29
+ for (const { monitor, filePath, exportName } of monitors) {
30
30
  const shortPath = filePath.replace(process.cwd(), ".");
31
31
  const exportInfo = exportName === "default" ? "" : terminal.colors.dim(` (${exportName})`);
32
- terminal.log(` ${terminal.colors.green("●")} ${terminal.colors.cyan(plan.name)}${exportInfo}`);
32
+ terminal.log(` ${terminal.colors.green("●")} ${terminal.colors.cyan(monitor.name)}${exportInfo}`);
33
33
  terminal.dim(` ${shortPath}`);
34
- terminal.dim(` Nodes: ${plan.nodes.length}, Edges: ${plan.edges.length}`);
35
- if (plan.frequency) {
36
- terminal.dim(` Schedule: Every ${plan.frequency.every} ${plan.frequency.unit}`);
34
+ terminal.dim(` Nodes: ${monitor.nodes.length}, Edges: ${monitor.edges.length}`);
35
+ if (monitor.frequency) {
36
+ terminal.dim(` Schedule: Every ${monitor.frequency.every} ${monitor.frequency.unit}`);
37
37
  }
38
38
  terminal.blank();
39
39
  }
40
- terminal.success("All plans are valid");
40
+ terminal.success("All monitors are valid");
41
41
  }
42
42
  catch (error) {
43
43
  spinner.fail("Validation failed");
@@ -7,7 +7,7 @@ export interface ApplyResult {
7
7
  }
8
8
  export interface ApplyAction {
9
9
  type: "create" | "update" | "delete";
10
- planName: string;
10
+ monitorName: string;
11
11
  success: boolean;
12
12
  error?: string;
13
13
  }
@@ -17,7 +17,7 @@ export interface ApplyError {
17
17
  }
18
18
  /**
19
19
  * Apply diff actions to the hub.
20
- * CLI injects both project and environment into plan payloads.
20
+ * CLI injects both project and environment into monitor payloads.
21
21
  */
22
22
  export declare function applyDiff(diff: DiffResult, sdk: GriffinHubSdk, options?: {
23
23
  dryRun?: boolean;
@@ -2,7 +2,7 @@ import { terminal } from "../utils/terminal.js";
2
2
  import { withSDKErrorHandling } from "../utils/sdk-error.js";
3
3
  /**
4
4
  * Apply diff actions to the hub.
5
- * CLI injects both project and environment into plan payloads.
5
+ * CLI injects both project and environment into monitor payloads.
6
6
  */
7
7
  export async function applyDiff(diff, sdk, options) {
8
8
  const applied = [];
@@ -16,7 +16,7 @@ export async function applyDiff(diff, sdk, options) {
16
16
  for (const action of actionsToApply) {
17
17
  try {
18
18
  if (options?.dryRun) {
19
- terminal.dim(`[DRY RUN] Would ${action.type} plan: ${action.plan?.name || action.remotePlan?.name}`);
19
+ terminal.dim(`[DRY RUN] Would ${action.type} monitor: ${action.monitor?.name || action.remoteMonitor?.name}`);
20
20
  continue;
21
21
  }
22
22
  switch (action.type) {
@@ -39,7 +39,7 @@ export async function applyDiff(diff, sdk, options) {
39
39
  });
40
40
  applied.push({
41
41
  type: action.type,
42
- planName: action.plan?.name || action.remotePlan?.name || "unknown",
42
+ monitorName: action.monitor?.name || action.remoteMonitor?.name || "unknown",
43
43
  success: false,
44
44
  error: error.message,
45
45
  });
@@ -55,57 +55,57 @@ export async function applyDiff(diff, sdk, options) {
55
55
  * Apply a create action
56
56
  */
57
57
  async function applyCreate(action, sdk, applied) {
58
- const resolvedPlan = action.plan;
58
+ const resolvedMonitor = action.monitor;
59
59
  //const variables = await loadVariables(environment);
60
- //const resolvedPlan = resolvePlan(plan, projectId, environment, variables);
61
- const { data: createdPlan } = await sdk.postPlan({
62
- body: resolvedPlan,
60
+ //const resolvedMonitor = resolveMonitor(monitor, projectId, environment, variables);
61
+ const { data: createdMonitor } = await sdk.postMonitor({
62
+ body: resolvedMonitor,
63
63
  });
64
64
  applied.push({
65
65
  type: "create",
66
- planName: createdPlan.data.name,
66
+ monitorName: createdMonitor.data.name,
67
67
  success: true,
68
68
  });
69
- terminal.success(`Created: ${terminal.colors.cyan(createdPlan.data.name)}`);
69
+ terminal.success(`Created: ${terminal.colors.cyan(createdMonitor.data.name)}`);
70
70
  }
71
71
  /**
72
72
  * Apply an update action
73
73
  */
74
74
  async function applyUpdate(action, sdk, applied) {
75
- const resolvedPlan = action.plan;
76
- //const remotePlan = action.remotePlan!;
75
+ const resolvedMonitor = action.monitor;
76
+ //const remoteMonitor = action.remoteMonitor!;
77
77
  //const variables = await loadVariables(environment);
78
- //const resolvedPlan = resolvePlan(plan, projectId, environment, variables);
79
- // Use the remote plan's ID for the update
80
- await sdk.putPlanById({
78
+ //const resolvedMonitor = resolveMonitor(monitor, projectId, environment, variables);
79
+ // Use the remote monitor's ID for the update
80
+ await sdk.putMonitorById({
81
81
  path: {
82
- id: action.remotePlan.id,
82
+ id: action.remoteMonitor.id,
83
83
  },
84
- body: resolvedPlan,
84
+ body: resolvedMonitor,
85
85
  });
86
86
  applied.push({
87
87
  type: "update",
88
- planName: action.remotePlan.name,
88
+ monitorName: action.remoteMonitor.name,
89
89
  success: true,
90
90
  });
91
- terminal.success(`Updated: ${terminal.colors.cyan(action.remotePlan.name)}`);
91
+ terminal.success(`Updated: ${terminal.colors.cyan(action.remoteMonitor.name)}`);
92
92
  }
93
93
  /**
94
94
  * Apply a delete action
95
95
  */
96
96
  async function applyDelete(action, sdk, applied) {
97
- const remotePlan = action.remotePlan;
98
- await withSDKErrorHandling(() => sdk.deletePlanById({
97
+ const remoteMonitor = action.remoteMonitor;
98
+ await withSDKErrorHandling(() => sdk.deleteMonitorById({
99
99
  path: {
100
- id: remotePlan.id,
100
+ id: remoteMonitor.id,
101
101
  },
102
- }), `Failed to delete plan "${remotePlan.name}"`);
102
+ }), `Failed to delete monitor "${remoteMonitor.name}"`);
103
103
  applied.push({
104
104
  type: "delete",
105
- planName: remotePlan.name,
105
+ monitorName: remoteMonitor.name,
106
106
  success: true,
107
107
  });
108
- terminal.success(`Deleted: ${terminal.colors.cyan(remotePlan.name)}`);
108
+ terminal.success(`Deleted: ${terminal.colors.cyan(remoteMonitor.name)}`);
109
109
  }
110
110
  /**
111
111
  * Format apply result for display
@@ -121,7 +121,7 @@ export function formatApplyResult(result) {
121
121
  for (const action of result.applied) {
122
122
  const icon = action.success ? "✓" : "✗";
123
123
  const status = action.success ? action.type : `${action.type} (failed)`;
124
- lines.push(` ${icon} ${action.planName} - ${status}`);
124
+ lines.push(` ${icon} ${action.monitorName} - ${status}`);
125
125
  if (action.error) {
126
126
  lines.push(` Error: ${action.error}`);
127
127
  }
@@ -1,9 +1,9 @@
1
1
  import { describe, it, expect, vi } from "vitest";
2
2
  import { applyDiff } from "./apply.js";
3
- // Helper to create a minimal test plan
4
- function createPlan(name) {
3
+ // Helper to create a minimal test monitor
4
+ function createMonitor(name) {
5
5
  return {
6
- id: `plan-${name}`,
6
+ id: `monitor-${name}`,
7
7
  name,
8
8
  project: "test-project",
9
9
  environment: "test",
@@ -19,92 +19,92 @@ describe("applyDiff", () => {
19
19
  actions: [],
20
20
  summary: { creates: 0, updates: 0, deletes: 0, noops: 0 },
21
21
  };
22
- const mockPlanApi = {};
23
- const result = await applyDiff(diff, mockPlanApi);
22
+ const mockMonitorApi = {};
23
+ const result = await applyDiff(diff, mockMonitorApi);
24
24
  expect(result.success).toBe(true);
25
25
  expect(result.applied).toHaveLength(0);
26
26
  expect(result.errors).toHaveLength(0);
27
27
  });
28
28
  it("should skip noop actions", async () => {
29
- const plan = createPlan("health-check");
29
+ const monitor = createMonitor("health-check");
30
30
  const diff = {
31
31
  actions: [
32
32
  {
33
33
  type: "noop",
34
- plan: plan,
35
- remotePlan: plan,
34
+ monitor: monitor,
35
+ remoteMonitor: monitor,
36
36
  reason: "unchanged",
37
37
  },
38
38
  ],
39
39
  summary: { creates: 0, updates: 0, deletes: 0, noops: 1 },
40
40
  };
41
- const mockPlanApi = {};
42
- const result = await applyDiff(diff, mockPlanApi);
41
+ const mockMonitorApi = {};
42
+ const result = await applyDiff(diff, mockMonitorApi);
43
43
  expect(result.success).toBe(true);
44
44
  expect(result.applied).toHaveLength(0);
45
45
  });
46
46
  it("should apply create action", async () => {
47
- const plan = createPlan("new-plan");
47
+ const monitor = createMonitor("new-monitor");
48
48
  const diff = {
49
49
  actions: [
50
50
  {
51
51
  type: "create",
52
- plan: plan,
53
- remotePlan: null,
52
+ monitor: monitor,
53
+ remoteMonitor: null,
54
54
  reason: "new",
55
55
  },
56
56
  ],
57
57
  summary: { creates: 1, updates: 0, deletes: 0, noops: 0 },
58
58
  };
59
- const mockPlanApi = {
60
- postPlan: vi.fn().mockResolvedValue({
61
- data: { data: { ...plan, id: "created-id" } },
59
+ const mockMonitorApi = {
60
+ postMonitor: vi.fn().mockResolvedValue({
61
+ data: { data: { ...monitor, id: "created-id" } },
62
62
  }),
63
63
  };
64
- const result = await applyDiff(diff, mockPlanApi);
64
+ const result = await applyDiff(diff, mockMonitorApi);
65
65
  expect(result.success).toBe(true);
66
66
  expect(result.applied).toHaveLength(1);
67
67
  expect(result.applied[0].type).toBe("create");
68
- expect(result.applied[0].planName).toBe("new-plan");
68
+ expect(result.applied[0].monitorName).toBe("new-monitor");
69
69
  expect(result.applied[0].success).toBe(true);
70
70
  // Verify the API was called with injected project and environment
71
- expect(mockPlanApi.postPlan).toHaveBeenCalledWith(expect.objectContaining({
71
+ expect(mockMonitorApi.postMonitor).toHaveBeenCalledWith(expect.objectContaining({
72
72
  body: expect.objectContaining({
73
- name: "new-plan",
73
+ name: "new-monitor",
74
74
  project: "test-project",
75
75
  environment: "test",
76
76
  }),
77
77
  }));
78
78
  });
79
79
  it("should apply update action", async () => {
80
- const localPlan = createPlan("existing-plan");
81
- const remotePlan = { ...localPlan, id: "remote-id" };
80
+ const localMonitor = createMonitor("existing-monitor");
81
+ const remoteMonitor = { ...localMonitor, id: "remote-id" };
82
82
  const diff = {
83
83
  actions: [
84
84
  {
85
85
  type: "update",
86
- plan: localPlan,
87
- remotePlan: remotePlan,
86
+ monitor: localMonitor,
87
+ remoteMonitor: remoteMonitor,
88
88
  reason: "changed",
89
89
  },
90
90
  ],
91
91
  summary: { creates: 0, updates: 1, deletes: 0, noops: 0 },
92
92
  };
93
- const mockPlanApi = {
94
- putPlanById: vi.fn().mockResolvedValue({
95
- data: { data: remotePlan },
93
+ const mockMonitorApi = {
94
+ putMonitorById: vi.fn().mockResolvedValue({
95
+ data: { data: remoteMonitor },
96
96
  }),
97
97
  };
98
- const result = await applyDiff(diff, mockPlanApi);
98
+ const result = await applyDiff(diff, mockMonitorApi);
99
99
  expect(result.success).toBe(true);
100
100
  expect(result.applied).toHaveLength(1);
101
101
  expect(result.applied[0].type).toBe("update");
102
- expect(result.applied[0].planName).toBe("existing-plan");
102
+ expect(result.applied[0].monitorName).toBe("existing-monitor");
103
103
  expect(result.applied[0].success).toBe(true);
104
- // Verify the API was called with the remote plan's ID
105
- expect(mockPlanApi.putPlanById).toHaveBeenCalledWith(expect.objectContaining({
104
+ // Verify the API was called with the remote monitor's ID
105
+ expect(mockMonitorApi.putMonitorById).toHaveBeenCalledWith(expect.objectContaining({
106
106
  body: expect.objectContaining({
107
- name: "existing-plan",
107
+ name: "existing-monitor",
108
108
  project: "test-project",
109
109
  environment: "test",
110
110
  }),
@@ -114,44 +114,44 @@ describe("applyDiff", () => {
114
114
  }));
115
115
  });
116
116
  it("should apply delete action", async () => {
117
- const remotePlan = createPlan("old-plan");
117
+ const remoteMonitor = createMonitor("old-monitor");
118
118
  const diff = {
119
- actions: [{ type: "delete", plan: null, remotePlan, reason: "removed" }],
119
+ actions: [{ type: "delete", monitor: null, remoteMonitor, reason: "removed" }],
120
120
  summary: { creates: 0, updates: 0, deletes: 1, noops: 0 },
121
121
  };
122
- const mockPlanApi = {
123
- deletePlanById: vi.fn().mockResolvedValue({}),
122
+ const mockMonitorApi = {
123
+ deleteMonitorById: vi.fn().mockResolvedValue({}),
124
124
  };
125
- const result = await applyDiff(diff, mockPlanApi);
125
+ const result = await applyDiff(diff, mockMonitorApi);
126
126
  expect(result.success).toBe(true);
127
127
  expect(result.applied).toHaveLength(1);
128
128
  expect(result.applied[0].type).toBe("delete");
129
- expect(result.applied[0].planName).toBe("old-plan");
129
+ expect(result.applied[0].monitorName).toBe("old-monitor");
130
130
  expect(result.applied[0].success).toBe(true);
131
- // Verify the API was called with the remote plan's ID
132
- expect(mockPlanApi.deletePlanById).toHaveBeenCalledWith({
131
+ // Verify the API was called with the remote monitor's ID
132
+ expect(mockMonitorApi.deleteMonitorById).toHaveBeenCalledWith({
133
133
  path: {
134
- id: remotePlan.id,
134
+ id: remoteMonitor.id,
135
135
  },
136
136
  });
137
137
  });
138
138
  it("should handle errors gracefully", async () => {
139
- const plan = createPlan("failing-plan");
139
+ const monitor = createMonitor("failing-monitor");
140
140
  const diff = {
141
141
  actions: [
142
142
  {
143
143
  type: "create",
144
- plan: plan,
145
- remotePlan: null,
144
+ monitor: monitor,
145
+ remoteMonitor: null,
146
146
  reason: "new",
147
147
  },
148
148
  ],
149
149
  summary: { creates: 1, updates: 0, deletes: 0, noops: 0 },
150
150
  };
151
- const mockPlanApi = {
152
- postPlan: vi.fn().mockRejectedValue(new Error("API Error")),
151
+ const mockMonitorApi = {
152
+ postMonitor: vi.fn().mockRejectedValue(new Error("API Error")),
153
153
  };
154
- const result = await applyDiff(diff, mockPlanApi);
154
+ const result = await applyDiff(diff, mockMonitorApi);
155
155
  expect(result.success).toBe(false);
156
156
  expect(result.errors).toHaveLength(1);
157
157
  expect(result.applied).toHaveLength(1);
@@ -159,26 +159,26 @@ describe("applyDiff", () => {
159
159
  expect(result.applied[0].error).toBe("API Error");
160
160
  });
161
161
  it("should skip actions in dry-run mode", async () => {
162
- const plan = createPlan("dry-run-plan");
162
+ const monitor = createMonitor("dry-run-monitor");
163
163
  const diff = {
164
164
  actions: [
165
165
  {
166
166
  type: "create",
167
- plan: plan,
168
- remotePlan: null,
167
+ monitor: monitor,
168
+ remoteMonitor: null,
169
169
  reason: "new",
170
170
  },
171
171
  ],
172
172
  summary: { creates: 1, updates: 0, deletes: 0, noops: 0 },
173
173
  };
174
- const mockPlanApi = {
175
- postPlan: vi.fn(),
174
+ const mockMonitorApi = {
175
+ postMonitor: vi.fn(),
176
176
  };
177
- const result = await applyDiff(diff, mockPlanApi, {
177
+ const result = await applyDiff(diff, mockMonitorApi, {
178
178
  dryRun: true,
179
179
  });
180
180
  expect(result.success).toBe(true);
181
181
  expect(result.applied).toHaveLength(0);
182
- expect(mockPlanApi.postPlan).not.toHaveBeenCalled();
182
+ expect(mockMonitorApi.postMonitor).not.toHaveBeenCalled();
183
183
  });
184
184
  });
@@ -1,13 +1,13 @@
1
- import type { PlanV1 } from "@griffin-app/griffin-hub-sdk";
2
- import { type PlanChanges } from "./plan-diff.js";
1
+ import type { MonitorV1 } from "@griffin-app/griffin-hub-sdk";
2
+ import { type MonitorChanges } from "./monitor-diff.js";
3
3
  export type DiffActionType = "create" | "update" | "delete" | "noop";
4
- export type ResolvedPlan = Omit<PlanV1, "id">;
4
+ export type ResolvedMonitor = Omit<MonitorV1, "id">;
5
5
  export interface DiffAction {
6
6
  type: DiffActionType;
7
- plan: ResolvedPlan | null;
8
- remotePlan: PlanV1 | null;
7
+ monitor: ResolvedMonitor | null;
8
+ remoteMonitor: MonitorV1 | null;
9
9
  reason: string;
10
- changes?: PlanChanges;
10
+ changes?: MonitorChanges;
11
11
  }
12
12
  export interface DiffResult {
13
13
  actions: DiffAction[];
@@ -22,17 +22,17 @@ export interface DiffOptions {
22
22
  includeDeletions: boolean;
23
23
  }
24
24
  /**
25
- * Compute diff between local plans and remote plans (hub is source of truth).
26
- * Local plans should be resolved (variables replaced with actual values) before calling this.
27
- * Plans are matched by name.
25
+ * Compute diff between local monitors and remote monitors (hub is source of truth).
26
+ * Local monitors should be resolved (variables replaced with actual values) before calling this.
27
+ * Monitors are matched by name.
28
28
  *
29
29
  * Rules:
30
- * - CREATE: Plan exists locally but not on hub
31
- * - UPDATE: Plan exists in both, but content differs
32
- * - DELETE: Plan exists on hub but not locally (only if includeDeletions is true)
33
- * - NOOP: Plan exists in both with same content
30
+ * - CREATE: Monitor exists locally but not on hub
31
+ * - UPDATE: Monitor exists in both, but content differs
32
+ * - DELETE: Monitor exists on hub but not locally (only if includeDeletions is true)
33
+ * - NOOP: Monitor exists in both with same content
34
34
  */
35
- export declare function computeDiff(localPlans: ResolvedPlan[], remotePlans: PlanV1[], options: DiffOptions): DiffResult;
35
+ export declare function computeDiff(localMonitors: ResolvedMonitor[], remoteMonitors: MonitorV1[], options: DiffOptions): DiffResult;
36
36
  /**
37
37
  * Format diff result as human-readable text with granular changes
38
38
  */