@flowscripter/dynamic-cli-framework 2.1.0 → 2.2.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.
Files changed (31) hide show
  1. package/dist/index.d.ts +5 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -1
  4. package/dist/src/cli/BaseCLI.d.ts +1 -0
  5. package/dist/src/cli/BaseCLI.d.ts.map +1 -1
  6. package/dist/src/cli/BaseCLI.js +6 -0
  7. package/dist/src/cli/BaseCLIFeatureOptions.d.ts +1 -0
  8. package/dist/src/cli/BaseCLIFeatureOptions.d.ts.map +1 -1
  9. package/dist/src/service/plugin/DefaultPluginService.d.ts +1 -1
  10. package/dist/src/service/plugin/DefaultPluginService.d.ts.map +1 -1
  11. package/dist/src/service/plugin/DefaultPluginServiceProvider.d.ts +3 -2
  12. package/dist/src/service/plugin/DefaultPluginServiceProvider.d.ts.map +1 -1
  13. package/dist/src/service/plugin/DefaultPluginServiceProvider.js +22 -2
  14. package/dist/src/service/plugin/SpawnInterfaceAdapter.d.ts +19 -0
  15. package/dist/src/service/plugin/SpawnInterfaceAdapter.d.ts.map +1 -0
  16. package/dist/src/service/plugin/SpawnInterfaceAdapter.js +40 -0
  17. package/dist/src/service/spawn/DefaultSpawnService.d.ts +7 -0
  18. package/dist/src/service/spawn/DefaultSpawnService.d.ts.map +1 -0
  19. package/dist/src/service/spawn/DefaultSpawnService.js +94 -0
  20. package/dist/src/service/spawn/SpawnServiceProvider.d.ts +12 -0
  21. package/dist/src/service/spawn/SpawnServiceProvider.d.ts.map +1 -0
  22. package/dist/src/service/spawn/SpawnServiceProvider.js +24 -0
  23. package/index.ts +10 -1
  24. package/package.json +3 -3
  25. package/src/cli/BaseCLI.ts +7 -0
  26. package/src/cli/BaseCLIFeatureOptions.ts +1 -0
  27. package/src/service/plugin/DefaultPluginService.ts +1 -1
  28. package/src/service/plugin/DefaultPluginServiceProvider.ts +39 -3
  29. package/src/service/plugin/SpawnInterfaceAdapter.ts +62 -0
  30. package/src/service/spawn/DefaultSpawnService.ts +119 -0
  31. package/src/service/spawn/SpawnServiceProvider.ts +32 -0
package/dist/index.d.ts CHANGED
@@ -43,6 +43,10 @@ export { SHUTDOWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
43
43
  export type { ShutdownService } from "@flowscripter/dynamic-cli-framework-api";
44
44
  export { default as DefaultShutdownService } from "./src/service/shutdown/DefaultShutdownService.ts";
45
45
  export { default as ShutdownServiceProvider } from "./src/service/shutdown/ShutdownServiceProvider.ts";
46
+ export { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
47
+ export type { SpawnOptions, SpawnResult, SpawnService, } from "@flowscripter/dynamic-cli-framework-api";
48
+ export { default as DefaultSpawnService } from "./src/service/spawn/DefaultSpawnService.ts";
49
+ export { default as SpawnServiceProvider } from "./src/service/spawn/SpawnServiceProvider.ts";
46
50
  export { SYNTAX_HIGHLIGHTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
47
51
  export type { SyntaxHighlighterService } from "@flowscripter/dynamic-cli-framework-api";
48
52
  export type { ColorScheme } from "@flowscripter/dynamic-cli-framework-api";
@@ -112,5 +116,5 @@ export type { default as Styler } from "./src/terminal/Styler.ts";
112
116
  export type { default as KeyReader, KeyEvent } from "./src/terminal/KeyReader.ts";
113
117
  export { SpecialKey } from "./src/terminal/KeyReader.ts";
114
118
  export { default as TtyKeyReader } from "./src/terminal/TtyKeyReader.ts";
115
- export { launchMultiCommandCLI, launchSingleCommandCLI, launchDynamicPluginMultiCommandCLI, } from "./src/launcher.ts";
119
+ export { launchDynamicPluginMultiCommandCLI, launchMultiCommandCLI, launchSingleCommandCLI, } from "./src/launcher.ts";
116
120
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -20,6 +20,9 @@ export { default as PrinterServiceProvider } from "./src/service/printer/Printer
20
20
  export { SHUTDOWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
21
21
  export { default as DefaultShutdownService } from "./src/service/shutdown/DefaultShutdownService.js";
22
22
  export { default as ShutdownServiceProvider } from "./src/service/shutdown/ShutdownServiceProvider.js";
23
+ export { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
24
+ export { default as DefaultSpawnService } from "./src/service/spawn/DefaultSpawnService.js";
25
+ export { default as SpawnServiceProvider } from "./src/service/spawn/SpawnServiceProvider.js";
23
26
  export { SYNTAX_HIGHLIGHTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
24
27
  export { default as DefaultSyntaxHighlighterService } from "./src/service/syntaxHighlighter/DefaultSyntaxHighlighterService.js";
25
28
  export { default as SyntaxHighlighterServiceProvider } from "./src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.js";
@@ -68,4 +71,4 @@ export { default as DynamicPluginRuntimeCLI } from "./src/cli/DynamicPluginRunti
68
71
  export { SpecialKey } from "./src/terminal/KeyReader.js";
69
72
  export { default as TtyKeyReader } from "./src/terminal/TtyKeyReader.js";
70
73
  // Convenience functions
71
- export { launchMultiCommandCLI, launchSingleCommandCLI, launchDynamicPluginMultiCommandCLI, } from "./src/launcher.js";
74
+ export { launchDynamicPluginMultiCommandCLI, launchMultiCommandCLI, launchSingleCommandCLI, } from "./src/launcher.js";
@@ -24,6 +24,7 @@ import type BaseCLIFeatureOptions from "./BaseCLIFeatureOptions.ts";
24
24
  * Optionally enabled via {@link BaseCLIFeatureOptions}:
25
25
  *
26
26
  * * {@link ImagePrinterServiceProvider}
27
+ * * {@link SpawnServiceProvider}
27
28
  *
28
29
  * `keyReader` is optional. If omitted, or if the stderr {@link Terminal} is not a TTY, prompting is
29
30
  * unavailable: {@link PrompterServiceProvider} (and {@link ArgumentPrompterServiceProvider}, if
@@ -1 +1 @@
1
- {"version":3,"file":"BaseCLI.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yCAAyC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4BzE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAC;AAChD,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAC;AAYpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,OAAO,OAAO,OAAQ,YAAW,GAAG;;gBAavC,SAAS,EAAE,SAAS,EACpB,oBAAoB,EAAE,cAAc,EACpC,oBAAoB,EAAE,cAAc,EACpC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,QAAQ,EACxB,cAAc,EAAE,QAAQ,EACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,qBAAqB;IA2DjC;;;;;;;OAOG;IACI,kBAAkB,CAAC,eAAe,EAAE,eAAe;IAI1D;;;;;;;;OAQG;IACI,UAAU,CAAC,OAAO,EAAE,OAAO;IAU5B,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;CAmL3D"}
1
+ {"version":3,"file":"BaseCLI.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yCAAyC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4BzE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAC;AAChD,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAC;AAapE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,OAAO,OAAO,OAAQ,YAAW,GAAG;;gBAavC,SAAS,EAAE,SAAS,EACpB,oBAAoB,EAAE,cAAc,EACpC,oBAAoB,EAAE,cAAc,EACpC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,QAAQ,EACxB,cAAc,EAAE,QAAQ,EACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,qBAAqB;IA4DjC;;;;;;;OAOG;IACI,kBAAkB,CAAC,eAAe,EAAE,eAAe;IAI1D;;;;;;;;OAQG;IACI,UAAU,CAAC,OAAO,EAAE,OAAO;IAU5B,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;CAuL3D"}
@@ -25,6 +25,7 @@ import ArgumentPrompterServiceProvider from "../service/argumentPrompter/Argumen
25
25
  import DefaultCompletionService from "../service/completion/DefaultCompletionService.js";
26
26
  import CompletionServiceProvider from "../service/completion/CompletionServiceProvider.js";
27
27
  import ImagePrinterServiceProvider from "../service/imagePrinter/ImagePrinterServiceProvider.js";
28
+ import SpawnServiceProvider from "../service/spawn/SpawnServiceProvider.js";
28
29
  const logger = getLogger("BaseCLI");
29
30
  /**
30
31
  * Base implementation of a {@link CLI}.
@@ -42,6 +43,7 @@ const logger = getLogger("BaseCLI");
42
43
  * Optionally enabled via {@link BaseCLIFeatureOptions}:
43
44
  *
44
45
  * * {@link ImagePrinterServiceProvider}
46
+ * * {@link SpawnServiceProvider}
45
47
  *
46
48
  * `keyReader` is optional. If omitted, or if the stderr {@link Terminal} is not a TTY, prompting is
47
49
  * unavailable: {@link PrompterServiceProvider} (and {@link ArgumentPrompterServiceProvider}, if
@@ -89,6 +91,7 @@ export default class BaseCLI {
89
91
  argumentPrompterServiceEnabled: false,
90
92
  completionServiceEnabled: false,
91
93
  imagePrinterServiceEnabled: false,
94
+ spawnServiceEnabled: false,
92
95
  validateAllCommands: false,
93
96
  promptingEnabled: true,
94
97
  ...options,
@@ -181,6 +184,9 @@ export default class BaseCLI {
181
184
  logger.debug("Skipping ImagePrinterServiceProvider: imagePrinterServiceEnabled is true but stdout is not a TTY");
182
185
  }
183
186
  }
187
+ if (this.#options.spawnServiceEnabled) {
188
+ this.addServiceProvider(new SpawnServiceProvider(58));
189
+ }
184
190
  if (this.#options.completionServiceEnabled) {
185
191
  const completionService = new DefaultCompletionService();
186
192
  this.addServiceProvider(new CompletionServiceProvider(5, completionService, this.#commandRegistry));
@@ -6,6 +6,7 @@ export default interface BaseCLIFeatureOptions {
6
6
  readonly argumentPrompterServiceEnabled?: boolean;
7
7
  readonly completionServiceEnabled?: boolean;
8
8
  readonly imagePrinterServiceEnabled?: boolean;
9
+ readonly spawnServiceEnabled?: boolean;
9
10
  readonly validateAllCommands?: boolean;
10
11
  readonly promptingEnabled?: boolean;
11
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BaseCLIFeatureOptions.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLIFeatureOptions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,qBAAqB;IAC5C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAClD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IAC9C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC"}
1
+ {"version":3,"file":"BaseCLIFeatureOptions.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLIFeatureOptions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,qBAAqB;IAC5C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAClD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IAC9C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC"}
@@ -1,5 +1,5 @@
1
1
  import type { PluginService } from "@flowscripter/dynamic-cli-framework-api";
2
- import type { MarketplacePluginManager, VersionedPluginDescriptor, SearchQuery } from "@flowscripter/dynamic-plugin-framework";
2
+ import type { MarketplacePluginManager, SearchQuery, VersionedPluginDescriptor } from "@flowscripter/dynamic-plugin-framework";
3
3
  export default class DefaultPluginService implements PluginService {
4
4
  #private;
5
5
  constructor(pluginManager: MarketplacePluginManager);
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultPluginService.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/DefaultPluginService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EACzB,WAAW,EACZ,MAAM,wCAAwC,CAAC;AAEhD,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,aAAa;;gBAGpD,aAAa,EAAE,wBAAwB;IAInD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAIlF,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,aAAa,IAAI,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAInE,eAAe,IAAI,aAAa,CAAC;QAC/B,UAAU,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QAChD,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CAGH"}
1
+ {"version":3,"file":"DefaultPluginService.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/DefaultPluginService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EACV,wBAAwB,EACxB,WAAW,EACX,yBAAyB,EAC1B,MAAM,wCAAwC,CAAC;AAEhD,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,aAAa;;gBAGpD,aAAa,EAAE,wBAAwB;IAInD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAIlF,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,aAAa,IAAI,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAInE,eAAe,IAAI,aAAa,CAAC;QAC/B,UAAU,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QAChD,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CAGH"}
@@ -2,12 +2,13 @@ import type { ServiceInfo, ServiceProvider } from "@flowscripter/dynamic-cli-fra
2
2
  import type { Context } from "@flowscripter/dynamic-cli-framework-api";
3
3
  import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
4
4
  import type { MarketplacePluginManager } from "@flowscripter/dynamic-plugin-framework";
5
+ import { type SpawnInterfaceAdapterOptions } from "./SpawnInterfaceAdapter.ts";
5
6
  export default class DefaultPluginServiceProvider implements ServiceProvider {
6
7
  #private;
7
8
  readonly serviceId = "PLUGIN_SERVICE";
8
9
  readonly servicePriority: number;
9
- constructor(pluginManager: MarketplacePluginManager, servicePriority?: number);
10
+ constructor(pluginManager: MarketplacePluginManager, servicePriority?: number, spawnInterfaceAdapterOptions?: SpawnInterfaceAdapterOptions);
10
11
  getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo>;
11
- initService(_context: Context): Promise<void>;
12
+ initService(context: Context): Promise<void>;
12
13
  }
13
14
  //# sourceMappingURL=DefaultPluginServiceProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultPluginServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/DefaultPluginServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAKvF,MAAM,CAAC,OAAO,OAAO,4BAA6B,YAAW,eAAe;;IAC1E,QAAQ,CAAC,SAAS,oBAAqB;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;gBAIrB,aAAa,EAAE,wBAAwB,EAAE,eAAe,SAAK;IAKnE,cAAc,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ3D,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CACpD"}
1
+ {"version":3,"file":"DefaultPluginServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/plugin/DefaultPluginServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EACV,wBAAwB,EAEzB,MAAM,wCAAwC,CAAC;AAIhD,OAA8B,EAC5B,KAAK,4BAA4B,EAClC,MAAM,4BAA4B,CAAC;AAKpC,MAAM,CAAC,OAAO,OAAO,4BAA6B,YAAW,eAAe;;IAC1E,QAAQ,CAAC,SAAS,oBAAqB;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;gBAM/B,aAAa,EAAE,wBAAwB,EACvC,eAAe,SAAK,EACpB,4BAA4B,GAAE,4BAAiC;IAO3D,cAAc,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAQjE,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB7C"}
@@ -1,14 +1,20 @@
1
+ import { PRINTER_SERVICE_ID, SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
1
2
  import { PLUGIN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
2
3
  import DefaultPluginService from "./DefaultPluginService.js";
3
4
  import { PluginGroupCommand } from "./command/PluginGroupCommand.js";
5
+ import SpawnInterfaceAdapter, {} from "./SpawnInterfaceAdapter.js";
6
+ import getLogger from "../../util/logger.js";
7
+ const logger = getLogger("DefaultPluginServiceProvider");
4
8
  export default class DefaultPluginServiceProvider {
5
9
  serviceId = PLUGIN_SERVICE_ID;
6
10
  servicePriority;
7
11
  #pluginManager;
12
+ #spawnInterfaceAdapterOptions;
8
13
  #pluginService;
9
- constructor(pluginManager, servicePriority = 50) {
14
+ constructor(pluginManager, servicePriority = 50, spawnInterfaceAdapterOptions = {}) {
10
15
  this.#pluginManager = pluginManager;
11
16
  this.servicePriority = servicePriority;
17
+ this.#spawnInterfaceAdapterOptions = spawnInterfaceAdapterOptions;
12
18
  }
13
19
  async getServiceInfo(_cliConfig) {
14
20
  this.#pluginService = new DefaultPluginService(this.#pluginManager);
@@ -17,5 +23,19 @@ export default class DefaultPluginServiceProvider {
17
23
  commands: [new PluginGroupCommand()],
18
24
  };
19
25
  }
20
- async initService(_context) { }
26
+ initService(context) {
27
+ if (!context.doesServiceExist(SPAWN_SERVICE_ID)) {
28
+ logger.debug("SpawnService not available, plugin manager will spawn processes directly");
29
+ return Promise.resolve();
30
+ }
31
+ if (!("setSpawn" in this.#pluginManager)) {
32
+ logger.debug("Plugin manager does not support SpawnCapable, skipping spawn injection");
33
+ return Promise.resolve();
34
+ }
35
+ const spawnService = context.getServiceById(SPAWN_SERVICE_ID);
36
+ const printerService = context.getServiceById(PRINTER_SERVICE_ID);
37
+ const adapter = new SpawnInterfaceAdapter(spawnService, printerService, this.#spawnInterfaceAdapterOptions);
38
+ this.#pluginManager.setSpawn(adapter);
39
+ return Promise.resolve();
40
+ }
21
41
  }
@@ -0,0 +1,19 @@
1
+ import type { PrinterService, SpawnService } from "@flowscripter/dynamic-cli-framework-api";
2
+ import type { SpawnInterface, SpawnResult } from "@flowscripter/dynamic-plugin-framework";
3
+ export interface SpawnInterfaceAdapterOptions {
4
+ quoteColor?: string;
5
+ markMinimumDisplayTimeMs?: number;
6
+ }
7
+ /**
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}).
11
+ */
12
+ export default class SpawnInterfaceAdapter implements SpawnInterface {
13
+ #private;
14
+ constructor(spawnService: SpawnService, printerService: PrinterService, options?: SpawnInterfaceAdapterOptions);
15
+ spawn(command: ReadonlyArray<string>, options: {
16
+ cwd: string;
17
+ }): Promise<SpawnResult>;
18
+ }
19
+ //# sourceMappingURL=SpawnInterfaceAdapter.d.ts.map
@@ -0,0 +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;CA4BxB"}
@@ -0,0 +1,40 @@
1
+ /**
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}).
5
+ */
6
+ export default class SpawnInterfaceAdapter {
7
+ #spawnService;
8
+ #printerService;
9
+ #quoteColor;
10
+ #markMinimumDisplayTimeMs;
11
+ constructor(spawnService, printerService, options = {}) {
12
+ this.#spawnService = spawnService;
13
+ this.#printerService = printerService;
14
+ this.#quoteColor = options.quoteColor;
15
+ this.#markMinimumDisplayTimeMs = options.markMinimumDisplayTimeMs ?? 1000;
16
+ }
17
+ async spawn(command, options) {
18
+ this.#printerService.startQuote(this.#quoteColor);
19
+ this.#printerService.startMark();
20
+ // onOutput is synchronous and may be called concurrently for stdout/stderr lines, but
21
+ // printerService.info() is async and must not be invoked concurrently with itself - queue
22
+ // writes so they're applied one at a time, in call order.
23
+ let writeQueue = Promise.resolve();
24
+ const onOutput = (line) => {
25
+ writeQueue = writeQueue.then(() => this.#printerService.info(`${line}\n`));
26
+ };
27
+ const result = await this.#spawnService.spawn(command, {
28
+ cwd: options.cwd,
29
+ stdio: "wrapped",
30
+ onOutput,
31
+ });
32
+ await writeQueue;
33
+ this.#printerService.endQuote();
34
+ this.#printerService.endMark();
35
+ await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
36
+ return result.ok
37
+ ? { ok: true, exitCode: result.exitCode }
38
+ : { ok: false, exitCode: result.exitCode, error: result.error };
39
+ }
40
+ }
@@ -0,0 +1,7 @@
1
+ import type { PrinterService, ShutdownService, SpawnOptions, SpawnResult, SpawnService } from "@flowscripter/dynamic-cli-framework-api";
2
+ export default class DefaultSpawnService implements SpawnService {
3
+ #private;
4
+ setDependencies(printerService: PrinterService, shutdownService: ShutdownService): void;
5
+ spawn(command: ReadonlyArray<string>, options?: SpawnOptions): Promise<SpawnResult>;
6
+ }
7
+ //# sourceMappingURL=DefaultSpawnService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultSpawnService.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/DefaultSpawnService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,YAAY,EACb,MAAM,yCAAyC,CAAC;AAOjD,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,YAAY;;IAIvD,eAAe,CAAC,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI;IAkCjF,KAAK,CAChB,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC;CAgExB"}
@@ -0,0 +1,94 @@
1
+ import getLogger from "../../util/logger.js";
2
+ const logger = getLogger("DefaultSpawnService");
3
+ const SHUTDOWN_GRACE_PERIOD_MS = 5000;
4
+ export default class DefaultSpawnService {
5
+ #printerService;
6
+ #shutdownService;
7
+ setDependencies(printerService, shutdownService) {
8
+ this.#printerService = printerService;
9
+ this.#shutdownService = shutdownService;
10
+ }
11
+ async #pipeLines(stream, streamName, onOutput) {
12
+ if (typeof stream !== "object" || stream === null) {
13
+ return;
14
+ }
15
+ const decoder = new TextDecoder();
16
+ const reader = stream.getReader();
17
+ let buffer = "";
18
+ for (;;) {
19
+ const { done, value } = await reader.read();
20
+ if (done) {
21
+ break;
22
+ }
23
+ buffer += decoder.decode(value, { stream: true });
24
+ let newlineIndex = buffer.indexOf("\n");
25
+ while (newlineIndex !== -1) {
26
+ onOutput(buffer.slice(0, newlineIndex), streamName);
27
+ buffer = buffer.slice(newlineIndex + 1);
28
+ newlineIndex = buffer.indexOf("\n");
29
+ }
30
+ }
31
+ if (buffer.length > 0) {
32
+ onOutput(buffer, streamName);
33
+ }
34
+ }
35
+ async spawn(command, options = {}) {
36
+ if (this.#printerService === undefined || this.#shutdownService === undefined) {
37
+ throw new Error("DefaultSpawnService.spawn() called before setDependencies()");
38
+ }
39
+ const printerService = this.#printerService;
40
+ const shutdownService = this.#shutdownService;
41
+ const stdio = options.stdio ?? "inherit";
42
+ const longRunning = options.longRunning ?? true;
43
+ if (stdio === "inherit") {
44
+ await printerService.hideSpinner();
45
+ await printerService.hideAllProgressBars();
46
+ }
47
+ let proc;
48
+ try {
49
+ proc = Bun.spawn([...command], {
50
+ cwd: options.cwd,
51
+ stdout: stdio === "wrapped" ? "pipe" : "inherit",
52
+ stderr: stdio === "wrapped" ? "pipe" : "inherit",
53
+ });
54
+ }
55
+ catch (error) {
56
+ logger.debug(() => `Failed to launch command '${command.join(" ")}': ${error}`);
57
+ return { ok: false, error: error };
58
+ }
59
+ let settled = false;
60
+ if (longRunning) {
61
+ shutdownService.enterLongRunningMode();
62
+ }
63
+ shutdownService.addShutdownListener(async () => {
64
+ if (settled) {
65
+ return;
66
+ }
67
+ logger.debug(() => `Sending SIGTERM to spawned command '${command.join(" ")}'`);
68
+ proc.kill("SIGTERM");
69
+ await Promise.race([
70
+ proc.exited.then(() => { }),
71
+ new Promise((resolve) => setTimeout(resolve, SHUTDOWN_GRACE_PERIOD_MS)),
72
+ ]);
73
+ if (!settled) {
74
+ logger.debug(() => `Sending SIGKILL to spawned command '${command.join(" ")}'`);
75
+ proc.kill("SIGKILL");
76
+ }
77
+ });
78
+ if (stdio === "wrapped" && options.onOutput) {
79
+ const onOutput = options.onOutput;
80
+ void this.#pipeLines(proc.stdout, "stdout", onOutput);
81
+ void this.#pipeLines(proc.stderr, "stderr", onOutput);
82
+ }
83
+ try {
84
+ const exitCode = await proc.exited;
85
+ settled = true;
86
+ return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
87
+ }
88
+ finally {
89
+ if (longRunning) {
90
+ shutdownService.leaveLongRunningMode();
91
+ }
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,12 @@
1
+ import type { ServiceInfo, ServiceProvider } from "@flowscripter/dynamic-cli-framework-api";
2
+ import type { Context } from "@flowscripter/dynamic-cli-framework-api";
3
+ import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
4
+ export default class SpawnServiceProvider implements ServiceProvider {
5
+ #private;
6
+ readonly serviceId: string;
7
+ readonly servicePriority: number;
8
+ constructor(servicePriority: number);
9
+ getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo>;
10
+ initService(context: Context): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=SpawnServiceProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpawnServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/spawn/SpawnServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,eAAe;;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAoB;IAC9C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;gBAGd,eAAe,EAAE,MAAM;IAInC,cAAc,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ3D,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAMpD"}
@@ -0,0 +1,24 @@
1
+ import { PRINTER_SERVICE_ID, SHUTDOWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
2
+ import { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
3
+ import DefaultSpawnService from "./DefaultSpawnService.js";
4
+ export default class SpawnServiceProvider {
5
+ serviceId = SPAWN_SERVICE_ID;
6
+ servicePriority;
7
+ #spawnService;
8
+ constructor(servicePriority) {
9
+ this.servicePriority = servicePriority;
10
+ }
11
+ getServiceInfo(_cliConfig) {
12
+ this.#spawnService = new DefaultSpawnService();
13
+ return Promise.resolve({
14
+ service: this.#spawnService,
15
+ commands: [],
16
+ });
17
+ }
18
+ initService(context) {
19
+ const printerService = context.getServiceById(PRINTER_SERVICE_ID);
20
+ const shutdownService = context.getServiceById(SHUTDOWN_SERVICE_ID);
21
+ this.#spawnService.setDependencies(printerService, shutdownService);
22
+ return Promise.resolve();
23
+ }
24
+ }
package/index.ts CHANGED
@@ -78,6 +78,15 @@ export type { ShutdownService } from "@flowscripter/dynamic-cli-framework-api";
78
78
  export { default as DefaultShutdownService } from "./src/service/shutdown/DefaultShutdownService.ts";
79
79
  export { default as ShutdownServiceProvider } from "./src/service/shutdown/ShutdownServiceProvider.ts";
80
80
 
81
+ export { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
82
+ export type {
83
+ SpawnOptions,
84
+ SpawnResult,
85
+ SpawnService,
86
+ } from "@flowscripter/dynamic-cli-framework-api";
87
+ export { default as DefaultSpawnService } from "./src/service/spawn/DefaultSpawnService.ts";
88
+ export { default as SpawnServiceProvider } from "./src/service/spawn/SpawnServiceProvider.ts";
89
+
81
90
  export { SYNTAX_HIGHLIGHTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
82
91
  export type { SyntaxHighlighterService } from "@flowscripter/dynamic-cli-framework-api";
83
92
  export type { ColorScheme } from "@flowscripter/dynamic-cli-framework-api";
@@ -192,7 +201,7 @@ export { default as TtyKeyReader } from "./src/terminal/TtyKeyReader.ts";
192
201
 
193
202
  // Convenience functions
194
203
  export {
204
+ launchDynamicPluginMultiCommandCLI,
195
205
  launchMultiCommandCLI,
196
206
  launchSingleCommandCLI,
197
- launchDynamicPluginMultiCommandCLI,
198
207
  } from "./src/launcher.ts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowscripter/dynamic-cli-framework",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
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,8 +48,8 @@
48
48
  "build": "tsc -p tsconfig.build.json"
49
49
  },
50
50
  "dependencies": {
51
- "@flowscripter/dynamic-cli-framework-api": "^1.0.1",
52
- "@flowscripter/dynamic-plugin-framework": "1.10.1",
51
+ "@flowscripter/dynamic-cli-framework-api": "^1.1.1",
52
+ "@flowscripter/dynamic-plugin-framework": "1.11.0",
53
53
  "emphasize": "^7.0.0",
54
54
  "fastest-levenshtein": "^1.0.16",
55
55
  "figlet": "^1.11.0",
@@ -51,6 +51,7 @@ import ArgumentPrompterServiceProvider from "../service/argumentPrompter/Argumen
51
51
  import DefaultCompletionService from "../service/completion/DefaultCompletionService.ts";
52
52
  import CompletionServiceProvider from "../service/completion/CompletionServiceProvider.ts";
53
53
  import ImagePrinterServiceProvider from "../service/imagePrinter/ImagePrinterServiceProvider.ts";
54
+ import SpawnServiceProvider from "../service/spawn/SpawnServiceProvider.ts";
54
55
  const logger = getLogger("BaseCLI");
55
56
 
56
57
  /**
@@ -69,6 +70,7 @@ const logger = getLogger("BaseCLI");
69
70
  * Optionally enabled via {@link BaseCLIFeatureOptions}:
70
71
  *
71
72
  * * {@link ImagePrinterServiceProvider}
73
+ * * {@link SpawnServiceProvider}
72
74
  *
73
75
  * `keyReader` is optional. If omitted, or if the stderr {@link Terminal} is not a TTY, prompting is
74
76
  * unavailable: {@link PrompterServiceProvider} (and {@link ArgumentPrompterServiceProvider}, if
@@ -130,6 +132,7 @@ export default class BaseCLI implements CLI {
130
132
  argumentPrompterServiceEnabled: false,
131
133
  completionServiceEnabled: false,
132
134
  imagePrinterServiceEnabled: false,
135
+ spawnServiceEnabled: false,
133
136
  validateAllCommands: false,
134
137
  promptingEnabled: true,
135
138
  ...options,
@@ -262,6 +265,10 @@ export default class BaseCLI implements CLI {
262
265
  }
263
266
  }
264
267
 
268
+ if (this.#options.spawnServiceEnabled) {
269
+ this.addServiceProvider(new SpawnServiceProvider(58));
270
+ }
271
+
265
272
  if (this.#options.completionServiceEnabled) {
266
273
  const completionService = new DefaultCompletionService();
267
274
  this.addServiceProvider(
@@ -6,6 +6,7 @@ export default interface BaseCLIFeatureOptions {
6
6
  readonly argumentPrompterServiceEnabled?: boolean;
7
7
  readonly completionServiceEnabled?: boolean;
8
8
  readonly imagePrinterServiceEnabled?: boolean;
9
+ readonly spawnServiceEnabled?: boolean;
9
10
  readonly validateAllCommands?: boolean;
10
11
  readonly promptingEnabled?: boolean;
11
12
  }
@@ -1,8 +1,8 @@
1
1
  import type { PluginService } from "@flowscripter/dynamic-cli-framework-api";
2
2
  import type {
3
3
  MarketplacePluginManager,
4
- VersionedPluginDescriptor,
5
4
  SearchQuery,
5
+ VersionedPluginDescriptor,
6
6
  } from "@flowscripter/dynamic-plugin-framework";
7
7
 
8
8
  export default class DefaultPluginService implements PluginService {
@@ -1,20 +1,37 @@
1
1
  import type { ServiceInfo, ServiceProvider } from "@flowscripter/dynamic-cli-framework-api";
2
2
  import type { Context } from "@flowscripter/dynamic-cli-framework-api";
3
3
  import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
4
- import type { MarketplacePluginManager } from "@flowscripter/dynamic-plugin-framework";
4
+ import type { PrinterService, SpawnService } from "@flowscripter/dynamic-cli-framework-api";
5
+ import { PRINTER_SERVICE_ID, SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
6
+ import type {
7
+ MarketplacePluginManager,
8
+ SpawnCapable,
9
+ } from "@flowscripter/dynamic-plugin-framework";
5
10
  import { PLUGIN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
6
11
  import DefaultPluginService from "./DefaultPluginService.ts";
7
12
  import { PluginGroupCommand } from "./command/PluginGroupCommand.ts";
13
+ import SpawnInterfaceAdapter, {
14
+ type SpawnInterfaceAdapterOptions,
15
+ } from "./SpawnInterfaceAdapter.ts";
16
+ import getLogger from "../../util/logger.ts";
17
+
18
+ const logger = getLogger("DefaultPluginServiceProvider");
8
19
 
9
20
  export default class DefaultPluginServiceProvider implements ServiceProvider {
10
21
  readonly serviceId = PLUGIN_SERVICE_ID;
11
22
  readonly servicePriority: number;
12
23
  readonly #pluginManager: MarketplacePluginManager;
24
+ readonly #spawnInterfaceAdapterOptions: SpawnInterfaceAdapterOptions;
13
25
  #pluginService: DefaultPluginService | undefined;
14
26
 
15
- constructor(pluginManager: MarketplacePluginManager, servicePriority = 50) {
27
+ constructor(
28
+ pluginManager: MarketplacePluginManager,
29
+ servicePriority = 50,
30
+ spawnInterfaceAdapterOptions: SpawnInterfaceAdapterOptions = {},
31
+ ) {
16
32
  this.#pluginManager = pluginManager;
17
33
  this.servicePriority = servicePriority;
34
+ this.#spawnInterfaceAdapterOptions = spawnInterfaceAdapterOptions;
18
35
  }
19
36
 
20
37
  async getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
@@ -25,5 +42,24 @@ export default class DefaultPluginServiceProvider implements ServiceProvider {
25
42
  };
26
43
  }
27
44
 
28
- async initService(_context: Context): Promise<void> {}
45
+ initService(context: Context): Promise<void> {
46
+ if (!context.doesServiceExist(SPAWN_SERVICE_ID)) {
47
+ logger.debug("SpawnService not available, plugin manager will spawn processes directly");
48
+ return Promise.resolve();
49
+ }
50
+ if (!("setSpawn" in this.#pluginManager)) {
51
+ logger.debug("Plugin manager does not support SpawnCapable, skipping spawn injection");
52
+ return Promise.resolve();
53
+ }
54
+
55
+ const spawnService = context.getServiceById(SPAWN_SERVICE_ID) as SpawnService;
56
+ const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
57
+ const adapter = new SpawnInterfaceAdapter(
58
+ spawnService,
59
+ printerService,
60
+ this.#spawnInterfaceAdapterOptions,
61
+ );
62
+ (this.#pluginManager as unknown as SpawnCapable).setSpawn(adapter);
63
+ return Promise.resolve();
64
+ }
29
65
  }
@@ -0,0 +1,62 @@
1
+ import type { PrinterService, SpawnService } from "@flowscripter/dynamic-cli-framework-api";
2
+ import type { SpawnInterface, SpawnResult } from "@flowscripter/dynamic-plugin-framework";
3
+
4
+ export interface SpawnInterfaceAdapterOptions {
5
+ quoteColor?: string;
6
+ markMinimumDisplayTimeMs?: number;
7
+ }
8
+
9
+ /**
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}).
13
+ */
14
+ export default class SpawnInterfaceAdapter implements SpawnInterface {
15
+ readonly #spawnService: SpawnService;
16
+ readonly #printerService: PrinterService;
17
+ readonly #quoteColor: string | undefined;
18
+ readonly #markMinimumDisplayTimeMs: number;
19
+
20
+ public constructor(
21
+ spawnService: SpawnService,
22
+ printerService: PrinterService,
23
+ options: SpawnInterfaceAdapterOptions = {},
24
+ ) {
25
+ this.#spawnService = spawnService;
26
+ this.#printerService = printerService;
27
+ this.#quoteColor = options.quoteColor;
28
+ this.#markMinimumDisplayTimeMs = options.markMinimumDisplayTimeMs ?? 1000;
29
+ }
30
+
31
+ public async spawn(
32
+ command: ReadonlyArray<string>,
33
+ options: { cwd: string },
34
+ ): Promise<SpawnResult> {
35
+ this.#printerService.startQuote(this.#quoteColor);
36
+ this.#printerService.startMark();
37
+
38
+ // onOutput is synchronous and may be called concurrently for stdout/stderr lines, but
39
+ // printerService.info() is async and must not be invoked concurrently with itself - queue
40
+ // writes so they're applied one at a time, in call order.
41
+ let writeQueue: Promise<void> = Promise.resolve();
42
+ const onOutput = (line: string): void => {
43
+ writeQueue = writeQueue.then(() => this.#printerService.info(`${line}\n`));
44
+ };
45
+
46
+ const result = await this.#spawnService.spawn(command, {
47
+ cwd: options.cwd,
48
+ stdio: "wrapped",
49
+ onOutput,
50
+ });
51
+
52
+ await writeQueue;
53
+
54
+ this.#printerService.endQuote();
55
+ this.#printerService.endMark();
56
+ await this.#printerService.clearMarked(this.#markMinimumDisplayTimeMs);
57
+
58
+ return result.ok
59
+ ? { ok: true, exitCode: result.exitCode }
60
+ : { ok: false, exitCode: result.exitCode, error: result.error };
61
+ }
62
+ }
@@ -0,0 +1,119 @@
1
+ import type {
2
+ PrinterService,
3
+ ShutdownService,
4
+ SpawnOptions,
5
+ SpawnResult,
6
+ SpawnService,
7
+ } from "@flowscripter/dynamic-cli-framework-api";
8
+ import getLogger from "../../util/logger.ts";
9
+
10
+ const logger = getLogger("DefaultSpawnService");
11
+
12
+ const SHUTDOWN_GRACE_PERIOD_MS = 5000;
13
+
14
+ export default class DefaultSpawnService implements SpawnService {
15
+ #printerService: PrinterService | undefined;
16
+ #shutdownService: ShutdownService | undefined;
17
+
18
+ public setDependencies(printerService: PrinterService, shutdownService: ShutdownService): void {
19
+ this.#printerService = printerService;
20
+ this.#shutdownService = shutdownService;
21
+ }
22
+
23
+ async #pipeLines(
24
+ stream: ReadableStream<Uint8Array> | number | undefined,
25
+ streamName: "stdout" | "stderr",
26
+ onOutput: (line: string, stream: "stdout" | "stderr") => void,
27
+ ): Promise<void> {
28
+ if (typeof stream !== "object" || stream === null) {
29
+ return;
30
+ }
31
+ const decoder = new TextDecoder();
32
+ const reader = stream.getReader();
33
+ let buffer = "";
34
+ for (;;) {
35
+ const { done, value } = await reader.read();
36
+ if (done) {
37
+ break;
38
+ }
39
+ buffer += decoder.decode(value, { stream: true });
40
+ let newlineIndex = buffer.indexOf("\n");
41
+ while (newlineIndex !== -1) {
42
+ onOutput(buffer.slice(0, newlineIndex), streamName);
43
+ buffer = buffer.slice(newlineIndex + 1);
44
+ newlineIndex = buffer.indexOf("\n");
45
+ }
46
+ }
47
+ if (buffer.length > 0) {
48
+ onOutput(buffer, streamName);
49
+ }
50
+ }
51
+
52
+ public async spawn(
53
+ command: ReadonlyArray<string>,
54
+ options: SpawnOptions = {},
55
+ ): Promise<SpawnResult> {
56
+ if (this.#printerService === undefined || this.#shutdownService === undefined) {
57
+ throw new Error("DefaultSpawnService.spawn() called before setDependencies()");
58
+ }
59
+ const printerService = this.#printerService;
60
+ const shutdownService = this.#shutdownService;
61
+ const stdio = options.stdio ?? "inherit";
62
+ const longRunning = options.longRunning ?? true;
63
+
64
+ if (stdio === "inherit") {
65
+ await printerService.hideSpinner();
66
+ await printerService.hideAllProgressBars();
67
+ }
68
+
69
+ let proc;
70
+ try {
71
+ proc = Bun.spawn([...command], {
72
+ cwd: options.cwd,
73
+ stdout: stdio === "wrapped" ? "pipe" : "inherit",
74
+ stderr: stdio === "wrapped" ? "pipe" : "inherit",
75
+ });
76
+ } catch (error) {
77
+ logger.debug(() => `Failed to launch command '${command.join(" ")}': ${error}`);
78
+ return { ok: false, error: error as Error };
79
+ }
80
+
81
+ let settled = false;
82
+
83
+ if (longRunning) {
84
+ shutdownService.enterLongRunningMode();
85
+ }
86
+
87
+ shutdownService.addShutdownListener(async () => {
88
+ if (settled) {
89
+ return;
90
+ }
91
+ logger.debug(() => `Sending SIGTERM to spawned command '${command.join(" ")}'`);
92
+ proc.kill("SIGTERM");
93
+ await Promise.race([
94
+ proc.exited.then(() => {}),
95
+ new Promise<void>((resolve) => setTimeout(resolve, SHUTDOWN_GRACE_PERIOD_MS)),
96
+ ]);
97
+ if (!settled) {
98
+ logger.debug(() => `Sending SIGKILL to spawned command '${command.join(" ")}'`);
99
+ proc.kill("SIGKILL");
100
+ }
101
+ });
102
+
103
+ if (stdio === "wrapped" && options.onOutput) {
104
+ const onOutput = options.onOutput;
105
+ void this.#pipeLines(proc.stdout, "stdout", onOutput);
106
+ void this.#pipeLines(proc.stderr, "stderr", onOutput);
107
+ }
108
+
109
+ try {
110
+ const exitCode = await proc.exited;
111
+ settled = true;
112
+ return exitCode === 0 ? { ok: true, exitCode } : { ok: false, exitCode };
113
+ } finally {
114
+ if (longRunning) {
115
+ shutdownService.leaveLongRunningMode();
116
+ }
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,32 @@
1
+ import type { ServiceInfo, ServiceProvider } from "@flowscripter/dynamic-cli-framework-api";
2
+ import type { Context } from "@flowscripter/dynamic-cli-framework-api";
3
+ import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
4
+ import type { PrinterService, ShutdownService } from "@flowscripter/dynamic-cli-framework-api";
5
+ import { PRINTER_SERVICE_ID, SHUTDOWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
6
+ import { SPAWN_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
7
+ import DefaultSpawnService from "./DefaultSpawnService.ts";
8
+
9
+ export default class SpawnServiceProvider implements ServiceProvider {
10
+ readonly serviceId: string = SPAWN_SERVICE_ID;
11
+ readonly servicePriority: number;
12
+ #spawnService: DefaultSpawnService | undefined;
13
+
14
+ public constructor(servicePriority: number) {
15
+ this.servicePriority = servicePriority;
16
+ }
17
+
18
+ public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
19
+ this.#spawnService = new DefaultSpawnService();
20
+ return Promise.resolve({
21
+ service: this.#spawnService,
22
+ commands: [],
23
+ });
24
+ }
25
+
26
+ public initService(context: Context): Promise<void> {
27
+ const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
28
+ const shutdownService = context.getServiceById(SHUTDOWN_SERVICE_ID) as ShutdownService;
29
+ this.#spawnService!.setDependencies(printerService, shutdownService);
30
+ return Promise.resolve();
31
+ }
32
+ }