@decohere/cli 0.0.1-dev.110 → 0.0.1-dev.111

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.
@@ -35,6 +35,7 @@ class RootModule {
35
35
  #command;
36
36
  #modules;
37
37
  #lastResponse = {};
38
+ #stop;
38
39
  constructor(manifestClasses, config){
39
40
  const modules = manifestClasses.map((ManifestClass)=>{
40
41
  const manifest = new ManifestClass();
@@ -42,6 +43,14 @@ class RootModule {
42
43
  });
43
44
  this.#modules = modules;
44
45
  this.#command = new _rootcommand.RootCommand(modules, config.configFile);
46
+ // Before the command runs, not after it returns: a stop signal while `flux serve` boots
47
+ // (`docker stop` during start-up) is held for the shutdown below instead of killing the
48
+ // process before anything is disposed.
49
+ this.#command.hook("preAction", (_root, actionCommand)=>{
50
+ if (actionCommand instanceof _cli.DecohereCommand && actionCommand.runsUntilStopped(actionCommand.opts())) {
51
+ this.#stop ??= stopSignal();
52
+ }
53
+ });
45
54
  }
46
55
  onResponse = (_moduleId, response)=>{
47
56
  this.#lastResponse = response;
@@ -52,7 +61,8 @@ class RootModule {
52
61
  from: "user"
53
62
  } : undefined);
54
63
  if (this.isBlocking(this.#lastResponse)) {
55
- await untilStopSignal();
64
+ this.#stop ??= stopSignal();
65
+ await this.#stop.received;
56
66
  }
57
67
  return this.#lastResponse;
58
68
  } catch (error) {
@@ -61,6 +71,8 @@ class RootModule {
61
71
  }
62
72
  throw error;
63
73
  } finally{
74
+ this.#stop?.dispose();
75
+ this.#stop = undefined;
64
76
  await this[Symbol.asyncDispose]();
65
77
  }
66
78
  }
@@ -98,17 +110,23 @@ RootModule = _ts_decorate([
98
110
  typeof Record === "undefined" ? Object : Record
99
111
  ])
100
112
  ], RootModule);
101
- /**
102
- * Resolves on Ctrl+C (SIGINT) or SIGTERM (Docker, CI, process managers), so long-running
103
- * commands like `flux serve` shut down cleanly either way (#520).
104
- */ function untilStopSignal() {
105
- return new Promise((resolve)=>{
106
- const stop = ()=>{
107
- process.off("SIGINT", stop);
108
- process.off("SIGTERM", stop);
109
- resolve();
110
- };
111
- process.once("SIGINT", stop);
112
- process.once("SIGTERM", stop);
113
+ function stopSignal() {
114
+ let onSignal = ()=>{};
115
+ const received = new Promise((resolve)=>{
116
+ onSignal = resolve;
113
117
  });
118
+ const stop = ()=>{
119
+ dispose();
120
+ onSignal();
121
+ };
122
+ const dispose = ()=>{
123
+ process.off("SIGINT", stop);
124
+ process.off("SIGTERM", stop);
125
+ };
126
+ process.once("SIGINT", stop);
127
+ process.once("SIGTERM", stop);
128
+ return {
129
+ received,
130
+ dispose
131
+ };
114
132
  }
@@ -8,7 +8,7 @@ function _ts_metadata(k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  }
10
10
  import { UserConfigFactory } from "@decohere/mesh";
11
- import { CommandResponse } from "@decohere/nexus/cli";
11
+ import { CommandResponse, DecohereCommand } from "@decohere/nexus/cli";
12
12
  import { Trace } from "@decohere/nexus/diagnostics";
13
13
  import { CommanderError } from "commander";
14
14
  import { ModuleFactory } from "./module.factory.js";
@@ -25,6 +25,7 @@ export class RootModule {
25
25
  #command;
26
26
  #modules;
27
27
  #lastResponse = {};
28
+ #stop;
28
29
  constructor(manifestClasses, config){
29
30
  const modules = manifestClasses.map((ManifestClass)=>{
30
31
  const manifest = new ManifestClass();
@@ -32,6 +33,14 @@ export class RootModule {
32
33
  });
33
34
  this.#modules = modules;
34
35
  this.#command = new RootCommand(modules, config.configFile);
36
+ // Before the command runs, not after it returns: a stop signal while `flux serve` boots
37
+ // (`docker stop` during start-up) is held for the shutdown below instead of killing the
38
+ // process before anything is disposed.
39
+ this.#command.hook("preAction", (_root, actionCommand)=>{
40
+ if (actionCommand instanceof DecohereCommand && actionCommand.runsUntilStopped(actionCommand.opts())) {
41
+ this.#stop ??= stopSignal();
42
+ }
43
+ });
35
44
  }
36
45
  onResponse = (_moduleId, response)=>{
37
46
  this.#lastResponse = response;
@@ -42,7 +51,8 @@ export class RootModule {
42
51
  from: "user"
43
52
  } : undefined);
44
53
  if (this.isBlocking(this.#lastResponse)) {
45
- await untilStopSignal();
54
+ this.#stop ??= stopSignal();
55
+ await this.#stop.received;
46
56
  }
47
57
  return this.#lastResponse;
48
58
  } catch (error) {
@@ -51,6 +61,8 @@ export class RootModule {
51
61
  }
52
62
  throw error;
53
63
  } finally{
64
+ this.#stop?.dispose();
65
+ this.#stop = undefined;
54
66
  await this[Symbol.asyncDispose]();
55
67
  }
56
68
  }
@@ -88,17 +100,23 @@ RootModule = _ts_decorate([
88
100
  typeof Record === "undefined" ? Object : Record
89
101
  ])
90
102
  ], RootModule);
91
- /**
92
- * Resolves on Ctrl+C (SIGINT) or SIGTERM (Docker, CI, process managers), so long-running
93
- * commands like `flux serve` shut down cleanly either way (#520).
94
- */ function untilStopSignal() {
95
- return new Promise((resolve)=>{
96
- const stop = ()=>{
97
- process.off("SIGINT", stop);
98
- process.off("SIGTERM", stop);
99
- resolve();
100
- };
101
- process.once("SIGINT", stop);
102
- process.once("SIGTERM", stop);
103
+ function stopSignal() {
104
+ let onSignal = ()=>{};
105
+ const received = new Promise((resolve)=>{
106
+ onSignal = resolve;
103
107
  });
108
+ const stop = ()=>{
109
+ dispose();
110
+ onSignal();
111
+ };
112
+ const dispose = ()=>{
113
+ process.off("SIGINT", stop);
114
+ process.off("SIGTERM", stop);
115
+ };
116
+ process.once("SIGINT", stop);
117
+ process.once("SIGTERM", stop);
118
+ return {
119
+ received,
120
+ dispose
121
+ };
104
122
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decohere/cli",
3
- "version": "0.0.1-dev.110",
3
+ "version": "0.0.1-dev.111",
4
4
  "description": "CLI for the Decohere toolchain — build, serve, publish, and manage TypeScript monorepos",
5
5
  "keywords": [
6
6
  "typescript",
@@ -28,15 +28,15 @@
28
28
  "test": "echo \"Error: no test specified\" && exit 1"
29
29
  },
30
30
  "dependencies": {
31
- "@decohere/create": "0.0.1-dev.110",
32
- "@decohere/crucible": "0.0.1-dev.110",
33
- "@decohere/flux": "0.0.1-dev.110",
34
- "@decohere/forge": "0.0.1-dev.110",
35
- "@decohere/mesh": "0.0.1-dev.110",
36
- "@decohere/nexus": "0.0.1-dev.110",
37
- "@decohere/scaffold": "0.0.1-dev.110",
38
- "@decohere/scribe": "0.0.1-dev.110",
39
- "@decohere/scribe-pino": "0.0.1-dev.110",
31
+ "@decohere/create": "0.0.1-dev.111",
32
+ "@decohere/crucible": "0.0.1-dev.111",
33
+ "@decohere/flux": "0.0.1-dev.111",
34
+ "@decohere/forge": "0.0.1-dev.111",
35
+ "@decohere/mesh": "0.0.1-dev.111",
36
+ "@decohere/nexus": "0.0.1-dev.111",
37
+ "@decohere/scaffold": "0.0.1-dev.111",
38
+ "@decohere/scribe": "0.0.1-dev.111",
39
+ "@decohere/scribe-pino": "0.0.1-dev.111",
40
40
  "commander": "^13.1.0",
41
41
  "pino-pretty": "^13.1.3"
42
42
  },