@procedures/mark 0.11.0 → 0.12.1
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/CHANGELOG.md +60 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/manifest.json +2 -2
- package/dist/server-mode.d.ts +9 -2
- package/dist/server-mode.d.ts.map +1 -1
- package/dist/server-mode.js +49 -63
- package/dist/server-mode.js.map +1 -1
- package/package.json +49 -49
- package/src/server-mode.ts +50 -70
package/dist/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 2,
|
|
3
|
-
"fingerprint": "
|
|
4
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"fingerprint": "d8e41c9e0413c3f03b257c77a49d65a34258f327d1224a6afbdbe1a6c8f3bc0b",
|
|
4
|
+
"generatedAt": "2026-10-18T14:36:24.669Z",
|
|
5
5
|
"commands": [
|
|
6
6
|
{
|
|
7
7
|
"path": [
|
package/dist/server-mode.d.ts
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* via HTTP. The server has the registry of mark (the module of each package, roadmap 3.1) and
|
|
6
6
|
* the host policy of the core (roadmap 2.3): the token in the lockfile, and the topics of
|
|
7
7
|
* `--events`. With `--fs-root`, each procedure keeps its paths in the root, or the root refuses it.
|
|
8
|
+
*
|
|
9
|
+
* The server is the background host of `mark` (decision D17): it runs under `run()` of
|
|
10
|
+
* `@mark1russell7/service` through `runProcedureHost()`, with the profile `daemon` (CLI-8). The
|
|
11
|
+
* runner owns the signals, the stop in stages and the exit. The lockfile is a dependency of the
|
|
12
|
+
* service: its connect writes it, and its close removes it after the listeners close.
|
|
8
13
|
*/
|
|
14
|
+
import type { ProcedureHostRunConfig } from "@procedures/server";
|
|
9
15
|
export interface ServerModeOptions {
|
|
10
16
|
port: number;
|
|
11
17
|
host?: string;
|
|
@@ -20,9 +26,10 @@ export interface ServerModeOptions {
|
|
|
20
26
|
fsRoot?: string | undefined;
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
|
-
* Start CLI in server mode
|
|
29
|
+
* Start CLI in server mode. The promise ends when the lifecycle of the server ends. `run` gives
|
|
30
|
+
* the options of `run()`, for a test: a process port and a clock.
|
|
24
31
|
*/
|
|
25
|
-
export declare function startServerMode(options: ServerModeOptions): Promise<void>;
|
|
32
|
+
export declare function startServerMode(options: ServerModeOptions, run?: ProcedureHostRunConfig["run"]): Promise<void>;
|
|
26
33
|
/**
|
|
27
34
|
* The port number of a `--port` value. An invalid port is an error (before, it became 3000:
|
|
28
35
|
* deep dive CLI-16).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-mode.d.ts","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server-mode.d.ts","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAMjE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvC,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAuCD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,CAAC,EAAE,sBAAsB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqFpH;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,2CAA2C;AAC3C,eAAO,MAAM,iBAAiB,YAAI,MAAM,EAAE,WAAW,EAAE,MAAM,CAAU,CAAC;AAExE;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAM3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAUzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAWzD"}
|
package/dist/server-mode.js
CHANGED
|
@@ -5,12 +5,16 @@
|
|
|
5
5
|
* via HTTP. The server has the registry of mark (the module of each package, roadmap 3.1) and
|
|
6
6
|
* the host policy of the core (roadmap 2.3): the token in the lockfile, and the topics of
|
|
7
7
|
* `--events`. With `--fs-root`, each procedure keeps its paths in the root, or the root refuses it.
|
|
8
|
+
*
|
|
9
|
+
* The server is the background host of `mark` (decision D17): it runs under `run()` of
|
|
10
|
+
* `@mark1russell7/service` through `runProcedureHost()`, with the profile `daemon` (CLI-8). The
|
|
11
|
+
* runner owns the signals, the stop in stages and the exit. The lockfile is a dependency of the
|
|
12
|
+
* service: its connect writes it, and its close removes it after the listeners close.
|
|
8
13
|
*/
|
|
9
14
|
import { print } from "./print.js";
|
|
10
15
|
import { loadEcosystemRegistry } from "./ecosystem.js";
|
|
11
16
|
import { randomBytes } from "node:crypto";
|
|
12
|
-
import {
|
|
13
|
-
import { seconds } from "@procedures/client";
|
|
17
|
+
import { getLockfilePath, currentBuild } from "./lockfile.js";
|
|
14
18
|
/**
|
|
15
19
|
* Build transport configuration array
|
|
16
20
|
*/
|
|
@@ -38,9 +42,10 @@ function buildTransports(options) {
|
|
|
38
42
|
return transports;
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
41
|
-
* Start CLI in server mode
|
|
45
|
+
* Start CLI in server mode. The promise ends when the lifecycle of the server ends. `run` gives
|
|
46
|
+
* the options of `run()`, for a test: a process port and a clock.
|
|
42
47
|
*/
|
|
43
|
-
export async function startServerMode(options) {
|
|
48
|
+
export async function startServerMode(options, run) {
|
|
44
49
|
const { port = 3000, verbose = false } = options;
|
|
45
50
|
print.info("Starting CLI server mode...");
|
|
46
51
|
// The registry of mark (roadmap 3.1): the module of each workspace package, with the server
|
|
@@ -66,42 +71,49 @@ export async function startServerMode(options) {
|
|
|
66
71
|
// The bus is the global bus, which is also the ctx.bus of the procedures.
|
|
67
72
|
const events = [...(options.events ?? [])];
|
|
68
73
|
const { hostPolicy } = await import("@procedures/client");
|
|
69
|
-
const {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
await
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
...(fsRoot !== undefined ? { fsRoot } : {}),
|
|
74
|
+
const { peerHostOptions } = await import("@procedures/peer");
|
|
75
|
+
const { runProcedureHost } = await import("@procedures/server");
|
|
76
|
+
const id = `peer-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
77
|
+
// The lockfile for client discovery. A client uses this server only from the same folder,
|
|
78
|
+
// with the same build of mark, and when host.info answers its token with this peer id.
|
|
79
|
+
const shown = host === "0.0.0.0" ? "localhost" : host;
|
|
80
|
+
const endpoint = options.transport === "websocket" ? `ws://${shown}:${port}/ws` : `http://${shown}:${port}/api`;
|
|
81
|
+
const running = await runProcedureHost({
|
|
82
|
+
name: "mark-server",
|
|
83
|
+
mode: "background",
|
|
84
|
+
host: peerHostOptions({ id, transports, registry, policy: hostPolicy({ token, events: { topics: events } }) }, "procedures"),
|
|
85
|
+
lockfile: {
|
|
86
|
+
pid: process.pid,
|
|
87
|
+
port,
|
|
88
|
+
transport: options.transport ?? "http",
|
|
89
|
+
endpoint,
|
|
90
|
+
startedAt: new Date().toISOString(),
|
|
91
|
+
token,
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
build: currentBuild(),
|
|
94
|
+
peerId: id,
|
|
95
|
+
// A client uses this server only with the same --fs-root (or none)
|
|
96
|
+
...(fsRoot !== undefined ? { fsRoot } : {}),
|
|
97
|
+
},
|
|
98
|
+
log: (line) => print.info(line),
|
|
99
|
+
...(run ? { run } : {}),
|
|
96
100
|
});
|
|
101
|
+
if (running.life.state !== "running") {
|
|
102
|
+
// The startup failed: the lifecycle stops the parts that started, and the process exits with 1
|
|
103
|
+
print.error("The server did not start:");
|
|
104
|
+
for (const error of running.life.errors)
|
|
105
|
+
print.error(` ${error}`);
|
|
106
|
+
await running.life.done;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
97
109
|
print.success("\nCLI Server running!");
|
|
98
110
|
print.info(` PID: ${process.pid}`);
|
|
99
|
-
print.info(` Server ID: ${
|
|
100
|
-
print.info(` Procedures: ${
|
|
111
|
+
print.info(` Server ID: ${running.host.id}`);
|
|
112
|
+
print.info(` Procedures: ${running.host.server.procedureCount}`);
|
|
101
113
|
print.info(` Lockfile: ${getLockfilePath()}`);
|
|
102
114
|
print.info("\nEndpoints:");
|
|
103
|
-
for (const
|
|
104
|
-
print.info(` [${
|
|
115
|
+
for (const each of running.host.info.endpoints()) {
|
|
116
|
+
print.info(` [${each.type}] ${each.address}`);
|
|
105
117
|
}
|
|
106
118
|
print.info(events.length > 0 ? `\nEvent topics (events.subscribe): ${events.join(", ")}` : "\nEvent topics: none (--events adds them)");
|
|
107
119
|
if (fsRoot !== undefined) {
|
|
@@ -109,34 +121,8 @@ export async function startServerMode(options) {
|
|
|
109
121
|
print.info(` Refused under the root: ${refusedUnderRoot?.length ?? 0} procedures that the root cannot confine`);
|
|
110
122
|
}
|
|
111
123
|
print.info("\nPress Ctrl+C to stop.");
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
// without a stop (roadmap R5).
|
|
115
|
-
let stopping = false;
|
|
116
|
-
const cleanup = async () => {
|
|
117
|
-
if (stopping)
|
|
118
|
-
process.exit(1);
|
|
119
|
-
stopping = true;
|
|
120
|
-
print.info("\nStopping server...");
|
|
121
|
-
removeLockfileForPort(port);
|
|
122
|
-
const limit = setTimeout(() => process.exit(1), 10_000);
|
|
123
|
-
limit.unref();
|
|
124
|
-
try {
|
|
125
|
-
// The calls in flight have 5 seconds to end (roadmap R14)
|
|
126
|
-
await peer.stop({ grace: seconds(5) });
|
|
127
|
-
process.exit(0);
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
print.error(`The server did not stop cleanly: ${error instanceof Error ? error.message : String(error)}`);
|
|
131
|
-
process.exit(1);
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
process.on("SIGINT", cleanup);
|
|
135
|
-
process.on("SIGTERM", cleanup);
|
|
136
|
-
// Keep the process alive
|
|
137
|
-
await new Promise(() => {
|
|
138
|
-
// Never resolves - keeps process running
|
|
139
|
-
});
|
|
124
|
+
// A signal starts the stop in stages, and the runner ends the process (CLI-8)
|
|
125
|
+
await running.life.done;
|
|
140
126
|
}
|
|
141
127
|
/**
|
|
142
128
|
* The port number of a `--port` value. An invalid port is an error (before, it became 3000:
|
package/dist/server-mode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-mode.js","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server-mode.js","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/mark",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.1",
|
|
5
5
|
"description": "mark: one CLI for every procedure package. It finds the procedures, parses flags by their Zod types, runs local or through a fast warm server, and asks for missing arguments.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"cli",
|
|
@@ -52,16 +52,16 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@clack/prompts": "^0.7.0",
|
|
55
|
-
"@procedures/cli-run": "0.
|
|
56
|
-
"@procedures/client": "0.
|
|
57
|
-
"@procedures/lib": "0.
|
|
58
|
-
"@procedures/mcp-dev-tools": "0.
|
|
59
|
-
"@procedures/peer": "0.
|
|
60
|
-
"@procedures/pnpm": "0.
|
|
61
|
-
"@procedures/procedure": "0.
|
|
62
|
-
"@procedures/server": "0.
|
|
63
|
-
"@procedures/shell": "0.
|
|
64
|
-
"@procedures/vitest": "0.
|
|
55
|
+
"@procedures/cli-run": "0.12.1",
|
|
56
|
+
"@procedures/client": "0.12.1",
|
|
57
|
+
"@procedures/lib": "0.12.1",
|
|
58
|
+
"@procedures/mcp-dev-tools": "0.12.1",
|
|
59
|
+
"@procedures/peer": "0.12.1",
|
|
60
|
+
"@procedures/pnpm": "0.12.1",
|
|
61
|
+
"@procedures/procedure": "0.12.1",
|
|
62
|
+
"@procedures/server": "0.12.1",
|
|
63
|
+
"@procedures/shell": "0.12.1",
|
|
64
|
+
"@procedures/vitest": "0.12.1",
|
|
65
65
|
"chalk": "^5.3.0",
|
|
66
66
|
"cli-table3": "^0.6.5",
|
|
67
67
|
"ora": "^8.0.0",
|
|
@@ -70,44 +70,44 @@
|
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@mark1russell7/cue": "^1.0.0",
|
|
73
|
-
"@procedures/archive": "0.
|
|
74
|
-
"@procedures/bundle-assistant": "0.
|
|
75
|
-
"@procedures/bundle-dev": "0.
|
|
76
|
-
"@procedures/bundle-mcp": "0.
|
|
77
|
-
"@procedures/claude-cli": "0.
|
|
78
|
-
"@procedures/compiler": "0.
|
|
79
|
-
"@procedures/cue": "0.
|
|
80
|
-
"@procedures/dag": "0.
|
|
81
|
-
"@procedures/docker": "0.
|
|
82
|
-
"@procedures/env": "0.
|
|
83
|
-
"@procedures/exif": "0.
|
|
84
|
-
"@procedures/fs": "0.
|
|
85
|
-
"@procedures/geo": "0.
|
|
86
|
-
"@procedures/gh": "0.
|
|
87
|
-
"@procedures/git": "0.
|
|
88
|
-
"@procedures/http": "0.
|
|
89
|
-
"@procedures/ics": "0.
|
|
90
|
-
"@procedures/ios-backup": "0.
|
|
91
|
-
"@procedures/json": "0.
|
|
92
|
-
"@procedures/llm": "0.
|
|
93
|
-
"@procedures/mail": "0.
|
|
94
|
-
"@procedures/mongo": "0.
|
|
95
|
-
"@procedures/node": "0.
|
|
96
|
-
"@procedures/notify": "0.
|
|
97
|
-
"@procedures/npm": "0.
|
|
98
|
-
"@procedures/pdf": "0.
|
|
99
|
-
"@procedures/privacy-scan": "0.
|
|
100
|
-
"@procedures/restic": "0.
|
|
101
|
-
"@procedures/s3": "0.
|
|
102
|
-
"@procedures/schedule": "0.
|
|
103
|
-
"@procedures/snapshot": "0.
|
|
104
|
-
"@procedures/splay": "0.
|
|
105
|
-
"@procedures/sqlite": "0.
|
|
106
|
-
"@procedures/store": "0.
|
|
107
|
-
"@procedures/systems": "0.
|
|
108
|
-
"@procedures/tailscale": "0.
|
|
109
|
-
"@procedures/vite": "0.
|
|
110
|
-
"@procedures/weather": "0.
|
|
73
|
+
"@procedures/archive": "0.12.1",
|
|
74
|
+
"@procedures/bundle-assistant": "0.12.1",
|
|
75
|
+
"@procedures/bundle-dev": "0.12.1",
|
|
76
|
+
"@procedures/bundle-mcp": "0.12.1",
|
|
77
|
+
"@procedures/claude-cli": "0.12.1",
|
|
78
|
+
"@procedures/compiler": "0.12.1",
|
|
79
|
+
"@procedures/cue": "0.12.1",
|
|
80
|
+
"@procedures/dag": "0.12.1",
|
|
81
|
+
"@procedures/docker": "0.12.1",
|
|
82
|
+
"@procedures/env": "0.12.1",
|
|
83
|
+
"@procedures/exif": "0.12.1",
|
|
84
|
+
"@procedures/fs": "0.12.1",
|
|
85
|
+
"@procedures/geo": "0.12.1",
|
|
86
|
+
"@procedures/gh": "0.12.1",
|
|
87
|
+
"@procedures/git": "0.12.1",
|
|
88
|
+
"@procedures/http": "0.12.1",
|
|
89
|
+
"@procedures/ics": "0.12.1",
|
|
90
|
+
"@procedures/ios-backup": "0.12.1",
|
|
91
|
+
"@procedures/json": "0.12.1",
|
|
92
|
+
"@procedures/llm": "0.12.1",
|
|
93
|
+
"@procedures/mail": "0.12.1",
|
|
94
|
+
"@procedures/mongo": "0.12.1",
|
|
95
|
+
"@procedures/node": "0.12.1",
|
|
96
|
+
"@procedures/notify": "0.12.1",
|
|
97
|
+
"@procedures/npm": "0.12.1",
|
|
98
|
+
"@procedures/pdf": "0.12.1",
|
|
99
|
+
"@procedures/privacy-scan": "0.12.1",
|
|
100
|
+
"@procedures/restic": "0.12.1",
|
|
101
|
+
"@procedures/s3": "0.12.1",
|
|
102
|
+
"@procedures/schedule": "0.12.1",
|
|
103
|
+
"@procedures/snapshot": "0.12.1",
|
|
104
|
+
"@procedures/splay": "0.12.1",
|
|
105
|
+
"@procedures/sqlite": "0.12.1",
|
|
106
|
+
"@procedures/store": "0.12.1",
|
|
107
|
+
"@procedures/systems": "0.12.1",
|
|
108
|
+
"@procedures/tailscale": "0.12.1",
|
|
109
|
+
"@procedures/vite": "0.12.1",
|
|
110
|
+
"@procedures/weather": "0.12.1",
|
|
111
111
|
"@types/node": "^22.0.0",
|
|
112
112
|
"fast-check": "^4.10.2",
|
|
113
113
|
"typescript": "^7.0.2",
|
package/src/server-mode.ts
CHANGED
|
@@ -5,13 +5,18 @@
|
|
|
5
5
|
* via HTTP. The server has the registry of mark (the module of each package, roadmap 3.1) and
|
|
6
6
|
* the host policy of the core (roadmap 2.3): the token in the lockfile, and the topics of
|
|
7
7
|
* `--events`. With `--fs-root`, each procedure keeps its paths in the root, or the root refuses it.
|
|
8
|
+
*
|
|
9
|
+
* The server is the background host of `mark` (decision D17): it runs under `run()` of
|
|
10
|
+
* `@mark1russell7/service` through `runProcedureHost()`, with the profile `daemon` (CLI-8). The
|
|
11
|
+
* runner owns the signals, the stop in stages and the exit. The lockfile is a dependency of the
|
|
12
|
+
* service: its connect writes it, and its close removes it after the listeners close.
|
|
8
13
|
*/
|
|
9
14
|
|
|
15
|
+
import type { ProcedureHostRunConfig } from "@procedures/server";
|
|
10
16
|
import { print } from "./print.js";
|
|
11
17
|
import { loadEcosystemRegistry } from "./ecosystem.js";
|
|
12
18
|
import { randomBytes } from "node:crypto";
|
|
13
|
-
import {
|
|
14
|
-
import { seconds } from "@procedures/client";
|
|
19
|
+
import { getLockfilePath, currentBuild } from "./lockfile.js";
|
|
15
20
|
|
|
16
21
|
export interface ServerModeOptions {
|
|
17
22
|
port: number;
|
|
@@ -27,12 +32,6 @@ export interface ServerModeOptions {
|
|
|
27
32
|
fsRoot?: string | undefined;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
interface ServerCreateResult {
|
|
31
|
-
serverId: string;
|
|
32
|
-
endpoints: Array<{ type: string; address: string }>;
|
|
33
|
-
procedureCount: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
35
|
/**
|
|
37
36
|
* Build transport configuration array
|
|
38
37
|
*/
|
|
@@ -71,9 +70,10 @@ function buildTransports(options: ServerModeOptions) {
|
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
/**
|
|
74
|
-
* Start CLI in server mode
|
|
73
|
+
* Start CLI in server mode. The promise ends when the lifecycle of the server ends. `run` gives
|
|
74
|
+
* the options of `run()`, for a test: a process port and a clock.
|
|
75
75
|
*/
|
|
76
|
-
export async function startServerMode(options: ServerModeOptions): Promise<void> {
|
|
76
|
+
export async function startServerMode(options: ServerModeOptions, run?: ProcedureHostRunConfig["run"]): Promise<void> {
|
|
77
77
|
const { port = 3000, verbose = false } = options;
|
|
78
78
|
|
|
79
79
|
print.info("Starting CLI server mode...");
|
|
@@ -104,44 +104,50 @@ export async function startServerMode(options: ServerModeOptions): Promise<void>
|
|
|
104
104
|
// The bus is the global bus, which is also the ctx.bus of the procedures.
|
|
105
105
|
const events = [...(options.events ?? [])];
|
|
106
106
|
const { hostPolicy } = await import("@procedures/client");
|
|
107
|
-
const {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
...(fsRoot !== undefined ? { fsRoot } : {}),
|
|
107
|
+
const { peerHostOptions } = await import("@procedures/peer");
|
|
108
|
+
const { runProcedureHost } = await import("@procedures/server");
|
|
109
|
+
const id = `peer-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
110
|
+
|
|
111
|
+
// The lockfile for client discovery. A client uses this server only from the same folder,
|
|
112
|
+
// with the same build of mark, and when host.info answers its token with this peer id.
|
|
113
|
+
const shown = host === "0.0.0.0" ? "localhost" : host;
|
|
114
|
+
const endpoint = options.transport === "websocket" ? `ws://${shown}:${port}/ws` : `http://${shown}:${port}/api`;
|
|
115
|
+
const running = await runProcedureHost({
|
|
116
|
+
name: "mark-server",
|
|
117
|
+
mode: "background",
|
|
118
|
+
host: peerHostOptions({ id, transports, registry, policy: hostPolicy({ token, events: { topics: events } }) }, "procedures"),
|
|
119
|
+
lockfile: {
|
|
120
|
+
pid: process.pid,
|
|
121
|
+
port,
|
|
122
|
+
transport: options.transport ?? "http",
|
|
123
|
+
endpoint,
|
|
124
|
+
startedAt: new Date().toISOString(),
|
|
125
|
+
token,
|
|
126
|
+
cwd: process.cwd(),
|
|
127
|
+
build: currentBuild(),
|
|
128
|
+
peerId: id,
|
|
129
|
+
// A client uses this server only with the same --fs-root (or none)
|
|
130
|
+
...(fsRoot !== undefined ? { fsRoot } : {}),
|
|
131
|
+
},
|
|
132
|
+
log: (line) => print.info(line),
|
|
133
|
+
...(run ? { run } : {}),
|
|
135
134
|
});
|
|
135
|
+
if (running.life.state !== "running") {
|
|
136
|
+
// The startup failed: the lifecycle stops the parts that started, and the process exits with 1
|
|
137
|
+
print.error("The server did not start:");
|
|
138
|
+
for (const error of running.life.errors) print.error(` ${error}`);
|
|
139
|
+
await running.life.done;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
136
142
|
|
|
137
143
|
print.success("\nCLI Server running!");
|
|
138
144
|
print.info(` PID: ${process.pid}`);
|
|
139
|
-
print.info(` Server ID: ${
|
|
140
|
-
print.info(` Procedures: ${
|
|
145
|
+
print.info(` Server ID: ${running.host.id}`);
|
|
146
|
+
print.info(` Procedures: ${running.host.server.procedureCount}`);
|
|
141
147
|
print.info(` Lockfile: ${getLockfilePath()}`);
|
|
142
148
|
print.info("\nEndpoints:");
|
|
143
|
-
for (const
|
|
144
|
-
print.info(` [${
|
|
149
|
+
for (const each of running.host.info.endpoints()) {
|
|
150
|
+
print.info(` [${each.type}] ${each.address}`);
|
|
145
151
|
}
|
|
146
152
|
print.info(events.length > 0 ? `\nEvent topics (events.subscribe): ${events.join(", ")}` : "\nEvent topics: none (--events adds them)");
|
|
147
153
|
if (fsRoot !== undefined) {
|
|
@@ -150,34 +156,8 @@ export async function startServerMode(options: ServerModeOptions): Promise<void>
|
|
|
150
156
|
}
|
|
151
157
|
print.info("\nPress Ctrl+C to stop.");
|
|
152
158
|
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
// without a stop (roadmap R5).
|
|
156
|
-
let stopping = false;
|
|
157
|
-
const cleanup = async () => {
|
|
158
|
-
if (stopping) process.exit(1);
|
|
159
|
-
stopping = true;
|
|
160
|
-
print.info("\nStopping server...");
|
|
161
|
-
removeLockfileForPort(port);
|
|
162
|
-
const limit = setTimeout(() => process.exit(1), 10_000);
|
|
163
|
-
limit.unref();
|
|
164
|
-
try {
|
|
165
|
-
// The calls in flight have 5 seconds to end (roadmap R14)
|
|
166
|
-
await peer.stop({ grace: seconds(5) });
|
|
167
|
-
process.exit(0);
|
|
168
|
-
} catch (error) {
|
|
169
|
-
print.error(`The server did not stop cleanly: ${error instanceof Error ? error.message : String(error)}`);
|
|
170
|
-
process.exit(1);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
process.on("SIGINT", cleanup);
|
|
175
|
-
process.on("SIGTERM", cleanup);
|
|
176
|
-
|
|
177
|
-
// Keep the process alive
|
|
178
|
-
await new Promise(() => {
|
|
179
|
-
// Never resolves - keeps process running
|
|
180
|
-
});
|
|
159
|
+
// A signal starts the stop in stages, and the runner ends the process (CLI-8)
|
|
160
|
+
await running.life.done;
|
|
181
161
|
}
|
|
182
162
|
|
|
183
163
|
/**
|