macroclaw 0.13.0 → 0.15.0

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": "macroclaw",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "Telegram-to-Claude-Code bridge",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/cli.test.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { describe, expect, it, mock } from "bun:test";
2
2
  import { runCommand } from "citty";
3
3
  import { Cli, createReadlineIo, handleError } from "./cli";
4
- import type { SystemService } from "./service";
5
4
  import { SettingsManager } from "./settings";
6
5
  import type { SetupWizard } from "./setup";
6
+ import type { SystemServiceManager } from "./system-service";
7
7
 
8
8
  // Only mock ./index — safe since no other test imports it
9
9
  const mockStart = mock(async () => {});
@@ -109,17 +109,18 @@ describe("Cli.setup", () => {
109
109
  });
110
110
  });
111
111
 
112
- function mockService(overrides?: Partial<SystemService>): SystemService {
112
+ function mockService(overrides?: Record<string, unknown>): SystemServiceManager {
113
113
  return {
114
114
  install: mock(() => ""),
115
115
  uninstall: mock(() => {}),
116
116
  start: mock(() => ""),
117
117
  stop: mock(() => {}),
118
- update: mock(() => ""),
118
+ update: mock(() => ({ previousVersion: "0.6.0", currentVersion: "0.7.0" })),
119
+ isRunning: false,
119
120
  status: mock(() => ({ installed: false, running: false, platform: "systemd" as const })),
120
121
  logs: mock(() => "journalctl -u macroclaw -n 50 --no-pager"),
121
122
  ...overrides,
122
- };
123
+ } as unknown as SystemServiceManager;
123
124
  }
124
125
 
125
126
  describe("Cli.service", () => {
@@ -151,11 +152,26 @@ describe("Cli.service", () => {
151
152
  expect(stop).toHaveBeenCalled();
152
153
  });
153
154
 
154
- it("runs update action", () => {
155
- const update = mock(() => "tail -f /logs");
156
- const cli = new Cli({ systemService: mockService({ update }) });
155
+ it("runs update action — stops and starts when running", () => {
156
+ const stop = mock(() => {});
157
+ const start = mock(() => "tail -f /logs");
158
+ const update = mock(() => ({ previousVersion: "0.6.0", currentVersion: "0.7.0" }));
159
+ const cli = new Cli({ systemService: mockService({ stop, start, update, isRunning: true }) });
157
160
  cli.service("update");
161
+ expect(stop).toHaveBeenCalled();
158
162
  expect(update).toHaveBeenCalled();
163
+ expect(start).toHaveBeenCalled();
164
+ });
165
+
166
+ it("runs update action — skips stop but still starts when not running", () => {
167
+ const stop = mock(() => {});
168
+ const start = mock(() => "tail -f /logs");
169
+ const update = mock(() => ({ previousVersion: "0.6.0", currentVersion: "0.7.0" }));
170
+ const cli = new Cli({ systemService: mockService({ stop, start, update, isRunning: false }) });
171
+ cli.service("update");
172
+ expect(stop).not.toHaveBeenCalled();
173
+ expect(update).toHaveBeenCalled();
174
+ expect(start).toHaveBeenCalled();
159
175
  });
160
176
 
161
177
  it("runs status action", () => {
package/src/cli.ts CHANGED
@@ -2,20 +2,20 @@ import {execSync} from "node:child_process";
2
2
  import {createInterface} from "node:readline";
3
3
  import {defineCommand} from "citty";
4
4
  import pkg from "../package.json" with {type: "json"};
5
- import {ServiceManager, type SystemService} from "./service";
6
5
  import {loadSessions} from "./sessions";
7
6
  import {SettingsManager} from "./settings";
8
7
  import {type SetupIo, SetupWizard} from "./setup";
8
+ import {SystemServiceManager} from "./system-service";
9
9
 
10
10
  export class Cli {
11
11
  readonly #settingsManager: SettingsManager;
12
12
  readonly #setupWizard: SetupWizard;
13
- readonly #serviceManager: SystemService;
13
+ readonly #serviceManager: SystemServiceManager;
14
14
 
15
- constructor(opts?: { wizard?: SetupWizard; settings?: SettingsManager; systemService?: SystemService }) {
15
+ constructor(opts?: { wizard?: SetupWizard; settings?: SettingsManager; systemService?: SystemServiceManager }) {
16
16
  this.#settingsManager = opts?.settings ?? new SettingsManager();
17
17
  this.#setupWizard = opts?.wizard ?? new SetupWizard(createReadlineIo());
18
- this.#serviceManager = opts?.systemService ?? new ServiceManager();
18
+ this.#serviceManager = opts?.systemService ?? new SystemServiceManager();
19
19
  }
20
20
 
21
21
  async setup(): Promise<void> {
@@ -55,8 +55,19 @@ export class Cli {
55
55
  console.log("Service stopped.");
56
56
  break;
57
57
  case "update": {
58
- const logCmd = this.#serviceManager.update();
59
- console.log(`Service updated. Check logs:\n ${logCmd}`);
58
+ if (this.#serviceManager.isRunning) {
59
+ this.#serviceManager.stop();
60
+ console.log("Service stopped.");
61
+ }
62
+ const result = this.#serviceManager.update();
63
+ if (result.previousVersion === result.currentVersion) {
64
+ console.log(`macroclaw v${result.currentVersion} (already up to date)`);
65
+ } else {
66
+ console.log(`Updated macroclaw v${result.previousVersion} → v${result.currentVersion}`);
67
+ }
68
+
69
+ const logCmd = this.#serviceManager.start();
70
+ console.log(`Service started. Check logs:\n ${logCmd}`);
60
71
  break;
61
72
  }
62
73
  case "status": {
package/src/setup.ts CHANGED
@@ -128,7 +128,7 @@ export class SetupWizard {
128
128
  }
129
129
 
130
130
  try {
131
- const svc = this.#serviceInstaller ?? new (await import("./service")).ServiceManager();
131
+ const svc = this.#serviceInstaller ?? new (await import("./system-service")).SystemServiceManager();
132
132
  const logCmd = svc.install(oauthToken);
133
133
  this.#io.write(`Service installed and started. Check logs:\n ${logCmd}\n`);
134
134
  } catch (err) {