@gajae-gateway/cli 0.1.2 → 0.1.3
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/main.js +50 -2
- package/dist/restart-stack.d.ts +9 -0
- package/dist/restart-stack.d.ts.map +1 -1
- package/dist/services.d.ts +5 -0
- package/dist/services.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/restart-stack.ts +70 -2
- package/src/services.ts +11 -1
package/dist/main.js
CHANGED
|
@@ -129,7 +129,8 @@ function renderList(columns, rows, options, envelope) {
|
|
|
129
129
|
|
|
130
130
|
// src/restart-stack.ts
|
|
131
131
|
import { randomUUID } from "crypto";
|
|
132
|
-
import { mkdir as mkdir2, readFile as readFile2, rename, stat, writeFile as writeFile2 } from "fs/promises";
|
|
132
|
+
import { access, mkdir as mkdir2, readFile as readFile2, rename, stat, writeFile as writeFile2 } from "fs/promises";
|
|
133
|
+
import { homedir as homedir2 } from "os";
|
|
133
134
|
import { join as join2 } from "path";
|
|
134
135
|
|
|
135
136
|
// src/services.ts
|
|
@@ -288,6 +289,12 @@ function systemdUnitDir(env, userHome) {
|
|
|
288
289
|
const base = env.XDG_CONFIG_HOME || join(userHome, ".config");
|
|
289
290
|
return join(base, "systemd", "user");
|
|
290
291
|
}
|
|
292
|
+
function launchAgentPlistPath(spec, launchAgentsDir) {
|
|
293
|
+
return join(launchAgentsDir, `dev.gajaeway.${spec.id}.plist`);
|
|
294
|
+
}
|
|
295
|
+
function systemdUnitPath(spec, unitDir) {
|
|
296
|
+
return join(unitDir, systemdUnitName(spec));
|
|
297
|
+
}
|
|
291
298
|
function restartStackCommands(platform, uid) {
|
|
292
299
|
if (platform === "linux")
|
|
293
300
|
return [["systemctl", "--user", "restart", GATEWAY_UNIT]];
|
|
@@ -462,6 +469,33 @@ function defaultServiceProbe(platform) {
|
|
|
462
469
|
async function defaultBinaryModifiedAt(path) {
|
|
463
470
|
return (await stat(path)).mtimeMs;
|
|
464
471
|
}
|
|
472
|
+
function defaultIsServiceInstalled(options) {
|
|
473
|
+
return async (label) => {
|
|
474
|
+
const spec = serviceSpecs().find((s) => s.label === label);
|
|
475
|
+
if (spec === undefined)
|
|
476
|
+
return false;
|
|
477
|
+
if (options.platform === "darwin") {
|
|
478
|
+
const userHome2 = options.env.HOME || homedir2();
|
|
479
|
+
const agentsDir = options.launchAgentsDir || join2(userHome2, "Library", "LaunchAgents");
|
|
480
|
+
const plistPath = launchAgentPlistPath(spec, agentsDir);
|
|
481
|
+
try {
|
|
482
|
+
await access(plistPath);
|
|
483
|
+
return true;
|
|
484
|
+
} catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const userHome = options.env.HOME || homedir2();
|
|
489
|
+
const unitDirPath = options.unitDir || systemdUnitDir(options.env, userHome);
|
|
490
|
+
const unitPath = systemdUnitPath(spec, unitDirPath);
|
|
491
|
+
try {
|
|
492
|
+
await access(unitPath);
|
|
493
|
+
return true;
|
|
494
|
+
} catch {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
}
|
|
465
499
|
function floorSecond(ms) {
|
|
466
500
|
return Math.floor(ms / 1000) * 1000;
|
|
467
501
|
}
|
|
@@ -470,6 +504,12 @@ async function runRestartStack(options) {
|
|
|
470
504
|
const runner = options.runner ?? defaultCommandRunner;
|
|
471
505
|
const probe = options.probe ?? defaultServiceProbe(platform);
|
|
472
506
|
const modifiedAt = options.binaryModifiedAt ?? defaultBinaryModifiedAt;
|
|
507
|
+
const isInstalled = options.isServiceInstalled ?? defaultIsServiceInstalled({
|
|
508
|
+
platform,
|
|
509
|
+
env: options.env ?? process.env,
|
|
510
|
+
launchAgentsDir: options.launchAgentsDir,
|
|
511
|
+
unitDir: options.unitDir
|
|
512
|
+
});
|
|
473
513
|
const now = options.now ?? Date.now;
|
|
474
514
|
const sleep = options.sleep ?? ((ms) => Bun.sleep(ms));
|
|
475
515
|
const timeoutMs = options.verifyTimeoutMs ?? VERIFY_TIMEOUT_MS;
|
|
@@ -486,6 +526,13 @@ async function runRestartStack(options) {
|
|
|
486
526
|
continue;
|
|
487
527
|
}
|
|
488
528
|
try {
|
|
529
|
+
const installed = await isInstalled(step.label);
|
|
530
|
+
if (!installed) {
|
|
531
|
+
step.result = "skipped";
|
|
532
|
+
step.detail = "service is not installed";
|
|
533
|
+
await writeReceipt(options.home, receipt);
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
489
536
|
if (step.command !== undefined) {
|
|
490
537
|
issuedAt = now();
|
|
491
538
|
const status = await runner(step.command);
|
|
@@ -501,8 +548,9 @@ async function runRestartStack(options) {
|
|
|
501
548
|
step.result = "failed";
|
|
502
549
|
step.detail = error instanceof Error ? error.message : String(error);
|
|
503
550
|
}
|
|
504
|
-
if (step.result !== "ok")
|
|
551
|
+
if (step.result !== "ok" && step.result !== "skipped") {
|
|
505
552
|
receipt.state = step.result === "stale" ? "stale" : "failed";
|
|
553
|
+
}
|
|
506
554
|
await writeReceipt(options.home, receipt);
|
|
507
555
|
}
|
|
508
556
|
if (receipt.state === "running")
|
package/dist/restart-stack.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export interface ServiceProcess {
|
|
|
42
42
|
}
|
|
43
43
|
export type CommandRunner = (command: readonly string[]) => number | PromiseLike<number>;
|
|
44
44
|
export type ServiceProbe = (label: string) => Promise<ServiceProcess | undefined>;
|
|
45
|
+
export type IsServiceInstalled = (label: string) => Promise<boolean>;
|
|
45
46
|
export interface RunRestartOptions {
|
|
46
47
|
readonly home: string;
|
|
47
48
|
readonly id: string;
|
|
@@ -49,6 +50,8 @@ export interface RunRestartOptions {
|
|
|
49
50
|
readonly uid?: number;
|
|
50
51
|
readonly runner?: CommandRunner;
|
|
51
52
|
readonly probe?: ServiceProbe;
|
|
53
|
+
/** Checks if a service is installed; if not provided, defaults to checking the service manager's files. */
|
|
54
|
+
readonly isServiceInstalled?: IsServiceInstalled;
|
|
52
55
|
/** Epoch ms modification time of a deployed binary. */
|
|
53
56
|
readonly binaryModifiedAt?: (path: string) => Promise<number>;
|
|
54
57
|
readonly now?: () => number;
|
|
@@ -56,6 +59,12 @@ export interface RunRestartOptions {
|
|
|
56
59
|
/** How long one service may take to come back verified; covers the gateway's ordered shutdown. */
|
|
57
60
|
readonly verifyTimeoutMs?: number;
|
|
58
61
|
readonly pollMs?: number;
|
|
62
|
+
/** Environment variables; used to determine systemd unit dir on linux. Defaults to process.env. */
|
|
63
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
64
|
+
/** LaunchAgents directory on darwin. Defaults to ~/Library/LaunchAgents. */
|
|
65
|
+
readonly launchAgentsDir?: string;
|
|
66
|
+
/** systemd unit directory on linux. Defaults to $XDG_CONFIG_HOME/systemd/user. */
|
|
67
|
+
readonly unitDir?: string;
|
|
59
68
|
}
|
|
60
69
|
export declare function restartReceiptPath(home: string): string;
|
|
61
70
|
export declare function readRestartReceipt(home: string): Promise<RestartReceipt | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restart-stack.d.ts","sourceRoot":"","sources":["../src/restart-stack.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"restart-stack.d.ts","sourceRoot":"","sources":["../src/restart-stack.ts"],"names":[],"mappings":"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"}
|
package/dist/services.d.ts
CHANGED
|
@@ -52,6 +52,11 @@ export declare function escapeXml(value: string): string;
|
|
|
52
52
|
export declare function renderLaunchAgent(spec: ServiceSpec, binDir: string, home: string, path: string): string;
|
|
53
53
|
export declare function systemdUnitName(spec: ServiceSpec): string;
|
|
54
54
|
export declare function renderSystemdUnit(spec: ServiceSpec, binDir: string, home: string, path: string): string;
|
|
55
|
+
export declare function systemdUnitDir(env: NodeJS.ProcessEnv, userHome: string): string;
|
|
56
|
+
/** Gets the path where a service's LaunchAgent plist is stored on darwin. */
|
|
57
|
+
export declare function launchAgentPlistPath(spec: ServiceSpec, launchAgentsDir: string): string;
|
|
58
|
+
/** Gets the path where a service's systemd unit file is stored on linux. */
|
|
59
|
+
export declare function systemdUnitPath(spec: ServiceSpec, unitDir: string): string;
|
|
55
60
|
/**
|
|
56
61
|
* The ordered commands that realign the whole stack.
|
|
57
62
|
*
|
package/dist/services.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gajae-gateway/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Owner CLI for the gajaeway gateway: status, sessions, chat, monitors, and worker lanes over the gateway socket. Requires the Bun runtime (uses Bun.file/Bun.spawn).",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"prepublishOnly": "bun run build"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@gajae-gateway/sdk": "0.1.
|
|
45
|
-
"@gajae-gateway/protocol": "0.1.
|
|
44
|
+
"@gajae-gateway/sdk": "0.1.3",
|
|
45
|
+
"@gajae-gateway/protocol": "0.1.3"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
48
|
"bun": ">=1.4.0"
|
package/src/restart-stack.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { access, mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import {
|
|
5
6
|
currentPlatform,
|
|
7
|
+
launchAgentPlistPath,
|
|
6
8
|
restartOrder,
|
|
7
9
|
restartStackCommands,
|
|
8
10
|
type ServicePlatform,
|
|
9
11
|
serviceSpecs,
|
|
12
|
+
systemdUnitDir,
|
|
10
13
|
systemdUnitName,
|
|
14
|
+
systemdUnitPath,
|
|
11
15
|
} from "./services";
|
|
12
16
|
|
|
13
17
|
/**
|
|
@@ -58,6 +62,7 @@ export interface ServiceProcess {
|
|
|
58
62
|
|
|
59
63
|
export type CommandRunner = (command: readonly string[]) => number | PromiseLike<number>;
|
|
60
64
|
export type ServiceProbe = (label: string) => Promise<ServiceProcess | undefined>;
|
|
65
|
+
export type IsServiceInstalled = (label: string) => Promise<boolean>;
|
|
61
66
|
|
|
62
67
|
export interface RunRestartOptions {
|
|
63
68
|
readonly home: string;
|
|
@@ -66,6 +71,8 @@ export interface RunRestartOptions {
|
|
|
66
71
|
readonly uid?: number;
|
|
67
72
|
readonly runner?: CommandRunner;
|
|
68
73
|
readonly probe?: ServiceProbe;
|
|
74
|
+
/** Checks if a service is installed; if not provided, defaults to checking the service manager's files. */
|
|
75
|
+
readonly isServiceInstalled?: IsServiceInstalled;
|
|
69
76
|
/** Epoch ms modification time of a deployed binary. */
|
|
70
77
|
readonly binaryModifiedAt?: (path: string) => Promise<number>;
|
|
71
78
|
readonly now?: () => number;
|
|
@@ -73,6 +80,12 @@ export interface RunRestartOptions {
|
|
|
73
80
|
/** How long one service may take to come back verified; covers the gateway's ordered shutdown. */
|
|
74
81
|
readonly verifyTimeoutMs?: number;
|
|
75
82
|
readonly pollMs?: number;
|
|
83
|
+
/** Environment variables; used to determine systemd unit dir on linux. Defaults to process.env. */
|
|
84
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
85
|
+
/** LaunchAgents directory on darwin. Defaults to ~/Library/LaunchAgents. */
|
|
86
|
+
readonly launchAgentsDir?: string;
|
|
87
|
+
/** systemd unit directory on linux. Defaults to $XDG_CONFIG_HOME/systemd/user. */
|
|
88
|
+
readonly unitDir?: string;
|
|
76
89
|
}
|
|
77
90
|
|
|
78
91
|
const RECEIPT_FILE = "restart-stack.json";
|
|
@@ -166,6 +179,42 @@ async function defaultBinaryModifiedAt(path: string): Promise<number> {
|
|
|
166
179
|
return (await stat(path)).mtimeMs;
|
|
167
180
|
}
|
|
168
181
|
|
|
182
|
+
/** Checks if a service is installed by verifying the service manager's definition file exists. */
|
|
183
|
+
function defaultIsServiceInstalled(options: {
|
|
184
|
+
readonly platform: ServicePlatform;
|
|
185
|
+
readonly env: NodeJS.ProcessEnv;
|
|
186
|
+
readonly launchAgentsDir?: string;
|
|
187
|
+
readonly unitDir?: string;
|
|
188
|
+
}): IsServiceInstalled {
|
|
189
|
+
return async (label: string) => {
|
|
190
|
+
const spec = serviceSpecs().find((s) => s.label === label);
|
|
191
|
+
if (spec === undefined) return false;
|
|
192
|
+
|
|
193
|
+
if (options.platform === "darwin") {
|
|
194
|
+
const userHome = options.env.HOME || homedir();
|
|
195
|
+
const agentsDir = options.launchAgentsDir || join(userHome, "Library", "LaunchAgents");
|
|
196
|
+
const plistPath = launchAgentPlistPath(spec, agentsDir);
|
|
197
|
+
try {
|
|
198
|
+
await access(plistPath);
|
|
199
|
+
return true;
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// linux
|
|
206
|
+
const userHome = options.env.HOME || homedir();
|
|
207
|
+
const unitDirPath = options.unitDir || systemdUnitDir(options.env, userHome);
|
|
208
|
+
const unitPath = systemdUnitPath(spec, unitDirPath);
|
|
209
|
+
try {
|
|
210
|
+
await access(unitPath);
|
|
211
|
+
return true;
|
|
212
|
+
} catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
169
218
|
function floorSecond(ms: number): number {
|
|
170
219
|
return Math.floor(ms / 1_000) * 1_000;
|
|
171
220
|
}
|
|
@@ -180,6 +229,14 @@ export async function runRestartStack(options: RunRestartOptions): Promise<Resta
|
|
|
180
229
|
const runner = options.runner ?? defaultCommandRunner;
|
|
181
230
|
const probe = options.probe ?? defaultServiceProbe(platform);
|
|
182
231
|
const modifiedAt = options.binaryModifiedAt ?? defaultBinaryModifiedAt;
|
|
232
|
+
const isInstalled =
|
|
233
|
+
options.isServiceInstalled ??
|
|
234
|
+
defaultIsServiceInstalled({
|
|
235
|
+
platform,
|
|
236
|
+
env: options.env ?? process.env,
|
|
237
|
+
launchAgentsDir: options.launchAgentsDir,
|
|
238
|
+
unitDir: options.unitDir,
|
|
239
|
+
});
|
|
183
240
|
const now = options.now ?? Date.now;
|
|
184
241
|
const sleep = options.sleep ?? ((ms: number) => Bun.sleep(ms));
|
|
185
242
|
const timeoutMs = options.verifyTimeoutMs ?? VERIFY_TIMEOUT_MS;
|
|
@@ -201,6 +258,15 @@ export async function runRestartStack(options: RunRestartOptions): Promise<Resta
|
|
|
201
258
|
continue;
|
|
202
259
|
}
|
|
203
260
|
try {
|
|
261
|
+
// Check if the service is installed before trying to restart it
|
|
262
|
+
const installed = await isInstalled(step.label);
|
|
263
|
+
if (!installed) {
|
|
264
|
+
step.result = "skipped";
|
|
265
|
+
step.detail = "service is not installed";
|
|
266
|
+
await writeReceipt(options.home, receipt);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
204
270
|
if (step.command !== undefined) {
|
|
205
271
|
issuedAt = now();
|
|
206
272
|
const status = await runner(step.command);
|
|
@@ -215,7 +281,9 @@ export async function runRestartStack(options: RunRestartOptions): Promise<Resta
|
|
|
215
281
|
step.result = "failed";
|
|
216
282
|
step.detail = error instanceof Error ? error.message : String(error);
|
|
217
283
|
}
|
|
218
|
-
if (step.result !== "ok"
|
|
284
|
+
if (step.result !== "ok" && step.result !== "skipped") {
|
|
285
|
+
receipt.state = step.result === "stale" ? "stale" : "failed";
|
|
286
|
+
}
|
|
219
287
|
await writeReceipt(options.home, receipt);
|
|
220
288
|
}
|
|
221
289
|
if (receipt.state === "running") receipt.state = "ok";
|
package/src/services.ts
CHANGED
|
@@ -235,11 +235,21 @@ export function renderSystemdUnit(spec: ServiceSpec, binDir: string, home: strin
|
|
|
235
235
|
return unit.join("\n");
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
function systemdUnitDir(env: NodeJS.ProcessEnv, userHome: string): string {
|
|
238
|
+
export function systemdUnitDir(env: NodeJS.ProcessEnv, userHome: string): string {
|
|
239
239
|
const base = env.XDG_CONFIG_HOME || join(userHome, ".config");
|
|
240
240
|
return join(base, "systemd", "user");
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
/** Gets the path where a service's LaunchAgent plist is stored on darwin. */
|
|
244
|
+
export function launchAgentPlistPath(spec: ServiceSpec, launchAgentsDir: string): string {
|
|
245
|
+
return join(launchAgentsDir, `dev.gajaeway.${spec.id}.plist`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Gets the path where a service's systemd unit file is stored on linux. */
|
|
249
|
+
export function systemdUnitPath(spec: ServiceSpec, unitDir: string): string {
|
|
250
|
+
return join(unitDir, systemdUnitName(spec));
|
|
251
|
+
}
|
|
252
|
+
|
|
243
253
|
/**
|
|
244
254
|
* The ordered commands that realign the whole stack.
|
|
245
255
|
*
|