@flowscripter/dynamic-cli-framework 5.1.1 → 5.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.
@@ -6,8 +6,10 @@ export interface SpawnInterfaceAdapterOptions {
6
6
  }
7
7
  /**
8
8
  * Adapts a {@link SpawnService} to dynamic-plugin-framework's {@link SpawnInterface}, wrapping
9
- * spawned process output in a quoted, marked block via {@link PrinterService} that is cleared
10
- * again once the process exits (subject to {@link SpawnInterfaceAdapterOptions.markMinimumDisplayTimeMs}).
9
+ * spawned process output in a quoted, marked block via {@link PrinterService}. On success the
10
+ * block is cleared once the process exits (subject to
11
+ * {@link SpawnInterfaceAdapterOptions.markMinimumDisplayTimeMs}); on failure the block is left
12
+ * on screen so the diagnostic output from the failing command remains visible.
11
13
  */
12
14
  export default class SpawnInterfaceAdapter implements SpawnInterface {
13
15
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"SpawnInterfaceAdapter.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/SpawnInterfaceAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAE1F,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAOhE,YAAY,EAAE,YAAY,EAC1B,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE,4BAAiC;IAQ/B,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GACvB,OAAO,CAAC,WAAW,CAAC;CA+BxB"}
1
+ {"version":3,"file":"SpawnInterfaceAdapter.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/SpawnInterfaceAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAE1F,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAOhE,YAAY,EAAE,YAAY,EAC1B,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE,4BAAiC;IAQ/B,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GACvB,OAAO,CAAC,WAAW,CAAC;CAsCxB"}
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Adapts a {@link SpawnService} to dynamic-plugin-framework's {@link SpawnInterface}, wrapping
3
- * spawned process output in a quoted, marked block via {@link PrinterService} that is cleared
4
- * again once the process exits (subject to {@link SpawnInterfaceAdapterOptions.markMinimumDisplayTimeMs}).
3
+ * spawned process output in a quoted, marked block via {@link PrinterService}. On success the
4
+ * block is cleared once the process exits (subject to
5
+ * {@link SpawnInterfaceAdapterOptions.markMinimumDisplayTimeMs}); on failure the block is left
6
+ * on screen so the diagnostic output from the failing command remains visible.
5
7
  */
6
8
  export default class SpawnInterfaceAdapter {
7
9
  #spawnService;
@@ -32,7 +34,15 @@ export default class SpawnInterfaceAdapter {
32
34
  await writeQueue;
33
35
  this.#printerService.endQuote();
34
36
  this.#printerService.endMark();
35
- await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
37
+ if (result.ok) {
38
+ await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
39
+ }
40
+ else {
41
+ // Leave the marked/quoted output on screen so the failing command's diagnostic output is
42
+ // visible, but still reset the mark/quote bookkeeping so a subsequent spawn() can start a
43
+ // fresh mark region.
44
+ this.#printerService.discardMark();
45
+ }
36
46
  if (result.ok) {
37
47
  return { ok: true, exitCode: result.exitCode };
38
48
  }
@@ -53,6 +53,12 @@ export default class DefaultPrinterService implements PrinterService {
53
53
  endQuote(): void;
54
54
  startMark(): void;
55
55
  endMark(): void;
56
+ /**
57
+ * Stop tracking rows for the current mark region without erasing them - e.g. when the marked
58
+ * output should be left on screen (such as a spawned command's output on failure), but the
59
+ * mark/quote bookkeeping still needs to be reset so a later startMark() doesn't throw.
60
+ */
61
+ discardMark(): void;
56
62
  clearMarked(minimumDisplayTimeMs?: number): Promise<void>;
57
63
  setLevel(level: Level): Promise<void>;
58
64
  getLevel(): Level;
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultPrinterService.d.ts","sourceRoot":"","sources":["../../../../src/service/printer/DefaultPrinterService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DefaultPrinterService.d.ts","sourceRoot":"","sources":["../../../../src/service/printer/DefaultPrinterService.ts"],"names":[],"mappings":"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"}
@@ -241,6 +241,18 @@ export default class DefaultPrinterService {
241
241
  }
242
242
  this.#markEndedAt = Date.now();
243
243
  }
244
+ /**
245
+ * Stop tracking rows for the current mark region without erasing them - e.g. when the marked
246
+ * output should be left on screen (such as a spawned command's output on failure), but the
247
+ * mark/quote bookkeeping still needs to be reset so a later startMark() doesn't throw.
248
+ */
249
+ discardMark() {
250
+ if (this.#markedLineCount === undefined) {
251
+ throw new Error("discardMark() called without a preceding startMark()");
252
+ }
253
+ this.#markedLineCount = undefined;
254
+ this.#markEndedAt = undefined;
255
+ }
244
256
  async clearMarked(minimumDisplayTimeMs = 0) {
245
257
  if (this.#markedLineCount === undefined || this.#markEndedAt === undefined) {
246
258
  throw new Error("clearMarked() called without a preceding endMark()");
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultSpawnService.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/DefaultSpawnService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,yCAAyC,CAAC;AAOjD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAa3E;AAED,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,YAAY;;IAIvD,eAAe,CAAC,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI;IAkDjF,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC;CA8ExB"}
1
+ {"version":3,"file":"DefaultSpawnService.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/DefaultSpawnService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,yCAAyC,CAAC;AAOjD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAa3E;AAED,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,YAAY;;IAIvD,eAAe,CAAC,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI;IAkDjF,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC;CAuFxB"}
@@ -99,14 +99,21 @@ export default class DefaultSpawnService {
99
99
  }
100
100
  await this.#terminate(proc, command);
101
101
  });
102
+ // These are intentionally not awaited here - they only complete once the child's stdout/
103
+ // stderr streams reach EOF, which can happen slightly after proc.exited resolves. They are
104
+ // awaited below, before returning, so that every onOutput callback (and thus every write it
105
+ // triggers) is guaranteed to have completed before the caller acts on the result.
106
+ let pipeStdout = Promise.resolve();
107
+ let pipeStderr = Promise.resolve();
102
108
  if (mode === "wrapped" && options.onOutput) {
103
109
  const onOutput = options.onOutput;
104
- void this.#pipeLines(proc.stdout, "stdout", onOutput);
105
- void this.#pipeLines(proc.stderr, "stderr", onOutput);
110
+ pipeStdout = this.#pipeLines(proc.stdout, "stdout", onOutput);
111
+ pipeStderr = this.#pipeLines(proc.stderr, "stderr", onOutput);
106
112
  }
107
113
  try {
108
114
  if (options.timeoutMs === undefined) {
109
115
  const exitCode = await proc.exited;
116
+ await Promise.all([pipeStdout, pipeStderr]);
110
117
  settled = true;
111
118
  return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
112
119
  }
@@ -121,10 +128,12 @@ export default class DefaultSpawnService {
121
128
  if (timedOut) {
122
129
  logger.debug(() => `Command '${command.join(" ")}' timed out after ${options.timeoutMs}ms`);
123
130
  await this.#terminate(proc, command);
131
+ await Promise.all([pipeStdout, pipeStderr]);
124
132
  settled = true;
125
133
  return { ok: false, timedOut: true };
126
134
  }
127
135
  const exitCode = await proc.exited;
136
+ await Promise.all([pipeStdout, pipeStderr]);
128
137
  settled = true;
129
138
  return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
130
139
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowscripter/dynamic-cli-framework",
3
- "version": "5.1.1",
3
+ "version": "5.1.3",
4
4
  "description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
5
5
  "keywords": [
6
6
  "bun",
@@ -48,7 +48,7 @@
48
48
  "build": "tsc -p tsconfig.build.json"
49
49
  },
50
50
  "dependencies": {
51
- "@flowscripter/dynamic-cli-framework-api": "^2.0.0",
51
+ "@flowscripter/dynamic-cli-framework-api": "^2.1.0",
52
52
  "@flowscripter/dynamic-plugin-framework": "2.1.1",
53
53
  "emphasize": "^7.0.0",
54
54
  "fastest-levenshtein": "^1.0.16",
@@ -8,8 +8,10 @@ export interface SpawnInterfaceAdapterOptions {
8
8
 
9
9
  /**
10
10
  * Adapts a {@link SpawnService} to dynamic-plugin-framework's {@link SpawnInterface}, wrapping
11
- * spawned process output in a quoted, marked block via {@link PrinterService} that is cleared
12
- * again once the process exits (subject to {@link SpawnInterfaceAdapterOptions.markMinimumDisplayTimeMs}).
11
+ * spawned process output in a quoted, marked block via {@link PrinterService}. On success the
12
+ * block is cleared once the process exits (subject to
13
+ * {@link SpawnInterfaceAdapterOptions.markMinimumDisplayTimeMs}); on failure the block is left
14
+ * on screen so the diagnostic output from the failing command remains visible.
13
15
  */
14
16
  export default class SpawnInterfaceAdapter implements SpawnInterface {
15
17
  readonly #spawnService: SpawnService;
@@ -53,7 +55,14 @@ export default class SpawnInterfaceAdapter implements SpawnInterface {
53
55
 
54
56
  this.#printerService.endQuote();
55
57
  this.#printerService.endMark();
56
- await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
58
+ if (result.ok) {
59
+ await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
60
+ } else {
61
+ // Leave the marked/quoted output on screen so the failing command's diagnostic output is
62
+ // visible, but still reset the mark/quote bookkeeping so a subsequent spawn() can start a
63
+ // fresh mark region.
64
+ this.#printerService.discardMark();
65
+ }
57
66
 
58
67
  if (result.ok) {
59
68
  return { ok: true, exitCode: result.exitCode };
@@ -312,6 +312,19 @@ export default class DefaultPrinterService implements PrinterService {
312
312
  this.#markEndedAt = Date.now();
313
313
  }
314
314
 
315
+ /**
316
+ * Stop tracking rows for the current mark region without erasing them - e.g. when the marked
317
+ * output should be left on screen (such as a spawned command's output on failure), but the
318
+ * mark/quote bookkeeping still needs to be reset so a later startMark() doesn't throw.
319
+ */
320
+ public discardMark(): void {
321
+ if (this.#markedLineCount === undefined) {
322
+ throw new Error("discardMark() called without a preceding startMark()");
323
+ }
324
+ this.#markedLineCount = undefined;
325
+ this.#markEndedAt = undefined;
326
+ }
327
+
315
328
  public async clearMarked(minimumDisplayTimeMs = 0): Promise<void> {
316
329
  if (this.#markedLineCount === undefined || this.#markEndedAt === undefined) {
317
330
  throw new Error("clearMarked() called without a preceding endMark()");
@@ -129,15 +129,22 @@ export default class DefaultSpawnService implements SpawnService {
129
129
  await this.#terminate(proc, command);
130
130
  });
131
131
 
132
+ // These are intentionally not awaited here - they only complete once the child's stdout/
133
+ // stderr streams reach EOF, which can happen slightly after proc.exited resolves. They are
134
+ // awaited below, before returning, so that every onOutput callback (and thus every write it
135
+ // triggers) is guaranteed to have completed before the caller acts on the result.
136
+ let pipeStdout: Promise<void> = Promise.resolve();
137
+ let pipeStderr: Promise<void> = Promise.resolve();
132
138
  if (mode === "wrapped" && options.onOutput) {
133
139
  const onOutput = options.onOutput;
134
- void this.#pipeLines(proc.stdout, "stdout", onOutput);
135
- void this.#pipeLines(proc.stderr, "stderr", onOutput);
140
+ pipeStdout = this.#pipeLines(proc.stdout, "stdout", onOutput);
141
+ pipeStderr = this.#pipeLines(proc.stderr, "stderr", onOutput);
136
142
  }
137
143
 
138
144
  try {
139
145
  if (options.timeoutMs === undefined) {
140
146
  const exitCode = await proc.exited;
147
+ await Promise.all([pipeStdout, pipeStderr]);
141
148
  settled = true;
142
149
  return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
143
150
  }
@@ -154,11 +161,13 @@ export default class DefaultSpawnService implements SpawnService {
154
161
  if (timedOut) {
155
162
  logger.debug(() => `Command '${command.join(" ")}' timed out after ${options.timeoutMs}ms`);
156
163
  await this.#terminate(proc, command);
164
+ await Promise.all([pipeStdout, pipeStderr]);
157
165
  settled = true;
158
166
  return { ok: false, timedOut: true };
159
167
  }
160
168
 
161
169
  const exitCode = await proc.exited;
170
+ await Promise.all([pipeStdout, pipeStderr]);
162
171
  settled = true;
163
172
  return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
164
173
  } finally {