@hexclave/cli 1.0.59 → 1.0.60

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexclave/cli",
3
- "version": "1.0.59",
3
+ "version": "1.0.60",
4
4
  "repository": "https://github.com/hexclave/hexclave",
5
5
  "description": "The CLI for Hexclave. https://hexclave.com",
6
6
  "main": "dist/index.js",
@@ -25,9 +25,9 @@
25
25
  "commander": "^13.1.0",
26
26
  "extract-zip": "^2.0.1",
27
27
  "jiti": "^2.4.2",
28
- "@hexclave/shared-backend": "1.0.59",
29
- "@hexclave/shared": "1.0.59",
30
- "@hexclave/js": "1.0.59"
28
+ "@hexclave/js": "1.0.60",
29
+ "@hexclave/shared": "1.0.60",
30
+ "@hexclave/shared-backend": "1.0.60"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "20.17.6",
@@ -3,7 +3,7 @@ import { tmpdir } from "os";
3
3
  import { join } from "path";
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { recordLocalDashboardProcess } from "../lib/dev-env-state.js";
6
- import { configErrorLogPrefix, devDashboardCommandFromEnv, isHeartbeatResponse, isVersionNewer, killLocalDashboard, processExists, shouldRestartDashboard } from "./dev.js";
6
+ import { configErrorLogPrefix, devDashboardCommandFromEnv, isHeartbeatResponse, isVersionNewer, killLocalDashboard, logConfigSyncEvents, processExists, shouldRestartDashboard } from "./dev.js";
7
7
 
8
8
  describe("isVersionNewer", () => {
9
9
  it("compares core versions numerically", () => {
@@ -103,6 +103,11 @@ describe("isHeartbeatResponse", () => {
103
103
  expect(isHeartbeatResponse({
104
104
  ok: true,
105
105
  config_sync_events: [
106
+ {
107
+ config_file_path: "/app/hexclave.config.ts",
108
+ status: "syncing",
109
+ created_at_millis: 1_717_999_999_999,
110
+ },
106
111
  {
107
112
  config_file_path: "/app/hexclave.config.ts",
108
113
  status: "success",
@@ -142,6 +147,37 @@ describe("isHeartbeatResponse", () => {
142
147
  });
143
148
  });
144
149
 
150
+ describe("logConfigSyncEvents", () => {
151
+ afterEach(() => {
152
+ vi.restoreAllMocks();
153
+ });
154
+
155
+ it("reports detection before confirming a successful sync", () => {
156
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
157
+
158
+ logConfigSyncEvents({
159
+ ok: true,
160
+ config_sync_events: [
161
+ {
162
+ config_file_path: "/app/hexclave.config.ts",
163
+ status: "syncing",
164
+ created_at_millis: 1_718_000_000_000,
165
+ },
166
+ {
167
+ config_file_path: "/app/hexclave.config.ts",
168
+ status: "success",
169
+ created_at_millis: 1_718_000_000_001,
170
+ },
171
+ ],
172
+ });
173
+
174
+ expect(warn.mock.calls).toEqual([
175
+ ["[Hexclave] Detected change to config file at /app/hexclave.config.ts. Syncing..."],
176
+ ["[Hexclave] Updated config sync successful!"],
177
+ ]);
178
+ });
179
+ });
180
+
145
181
  describe("killLocalDashboard", () => {
146
182
  let tempDir: string;
147
183
 
@@ -25,6 +25,8 @@ type ConfigSyncEventBase = {
25
25
  };
26
26
 
27
27
  type ConfigSyncEvent = ConfigSyncEventBase & ({
28
+ status: "syncing",
29
+ } | {
28
30
  status: "success",
29
31
  } | {
30
32
  status: "error",
@@ -38,7 +40,7 @@ type HeartbeatResponse = {
38
40
  config_sync_events?: ConfigSyncEvent[],
39
41
  };
40
42
 
41
- const HEARTBEAT_INTERVAL_MS = 5_000;
43
+ const HEARTBEAT_INTERVAL_MS = 1_000;
42
44
  const HEARTBEAT_STOP_POLL_MS = 100;
43
45
  const DASHBOARD_RESTART_MIN_UPTIME_MS = 5_000;
44
46
  const DASHBOARD_START_TIMEOUT_MS = 60_000;
@@ -568,7 +570,7 @@ function isConfigSyncEvent(value: unknown): value is ConfigSyncEvent {
568
570
  ) {
569
571
  return false;
570
572
  }
571
- if (value.status === "success") {
573
+ if (value.status === "syncing" || value.status === "success") {
572
574
  return true;
573
575
  }
574
576
  return (
@@ -611,10 +613,12 @@ function logBrowserSecretConfirmationCode(response: HeartbeatResponse): void {
611
613
  : `Dashboard browser confirmation code: ${response.browser_secret_confirmation_code} (expires in ${expiresInSeconds}s)`);
612
614
  }
613
615
 
614
- function logConfigSyncEvents(response: HeartbeatResponse): void {
616
+ export function logConfigSyncEvents(response: HeartbeatResponse): void {
615
617
  for (const event of response.config_sync_events ?? []) {
616
- if (event.status === "success") {
617
- logDev(`Config synced to development environment project: ${event.config_file_path}`);
618
+ if (event.status === "syncing") {
619
+ logDev(`Detected change to config file at ${event.config_file_path}. Syncing...`);
620
+ } else if (event.status === "success") {
621
+ logDev("Updated config sync successful!");
618
622
  } else {
619
623
  logDevConfigError(`Config sync failed for ${event.config_file_path}: ${event.error_message}`);
620
624
  }