@unispechq/unispec-platform 0.2.0 → 0.2.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.
Files changed (44) hide show
  1. package/README.md +21 -41
  2. package/dist/cli.js +2 -3
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/index.d.ts +1 -2
  5. package/dist/commands/index.d.ts.map +1 -1
  6. package/dist/commands/index.js +1 -2
  7. package/dist/commands/index.js.map +1 -1
  8. package/dist/commands/portal.d.ts +3 -0
  9. package/dist/commands/portal.d.ts.map +1 -0
  10. package/dist/commands/portal.js +90 -0
  11. package/dist/commands/portal.js.map +1 -0
  12. package/package.json +1 -1
  13. package/dist/commands/dev.d.ts +0 -3
  14. package/dist/commands/dev.d.ts.map +0 -1
  15. package/dist/commands/dev.js +0 -211
  16. package/dist/commands/dev.js.map +0 -1
  17. package/dist/commands/start.d.ts +0 -3
  18. package/dist/commands/start.d.ts.map +0 -1
  19. package/dist/commands/start.js +0 -125
  20. package/dist/commands/start.js.map +0 -1
  21. package/dist/dev/aggregate.d.ts +0 -15
  22. package/dist/dev/aggregate.d.ts.map +0 -1
  23. package/dist/dev/aggregate.js +0 -56
  24. package/dist/dev/aggregate.js.map +0 -1
  25. package/dist/dev/index.d.ts +0 -3
  26. package/dist/dev/index.d.ts.map +0 -1
  27. package/dist/dev/index.js +0 -3
  28. package/dist/dev/index.js.map +0 -1
  29. package/dist/dev/server.d.ts +0 -17
  30. package/dist/dev/server.d.ts.map +0 -1
  31. package/dist/dev/server.js +0 -503
  32. package/dist/dev/server.js.map +0 -1
  33. package/dist/dev/ui.d.ts +0 -3
  34. package/dist/dev/ui.d.ts.map +0 -1
  35. package/dist/dev/ui.js +0 -93
  36. package/dist/dev/ui.js.map +0 -1
  37. package/dist/workspace/storage.d.ts +0 -7
  38. package/dist/workspace/storage.d.ts.map +0 -1
  39. package/dist/workspace/storage.js +0 -60
  40. package/dist/workspace/storage.js.map +0 -1
  41. package/dist/workspace/types.d.ts +0 -64
  42. package/dist/workspace/types.d.ts.map +0 -1
  43. package/dist/workspace/types.js +0 -2
  44. package/dist/workspace/types.js.map +0 -1
package/README.md CHANGED
@@ -89,59 +89,39 @@ Options:
89
89
  - `--format <format>` — `json|yaml` (for JSON-like targets)
90
90
  - `--output <file>` — write output to file (use `-` for stdout)
91
91
 
92
- ### `unispec dev`
93
- Local orchestrator mode.
92
+ ### `unispec portal <dev|start>`
93
+ Launch UniSpec Portal (Next.js orchestrator).
94
94
 
95
- Serves:
95
+ In the current architecture, `unispec-platform` provides CLI utilities (validate/normalize/diff/convert) and a launcher for `@unispechq/unispec-portal`.
96
96
 
97
- - `GET /` — embedded UI (reads `/unispec.json` in the browser)
98
- - `GET /unispec.json` — aggregated snapshot
99
- - `GET /health` — healthcheck
100
- - `GET /workspace.json` workspace info (enabled when config path is known)
101
- - `GET /workspace/state` workspace state (stored in `.unispec/workspace.json`)
102
- - `PUT /workspace/state` — replace workspace state
103
- - `POST /tests/run` — run workspace tests (suite/flow)
97
+ Examples:
98
+
99
+ ```bash
100
+ unispec portal dev --config ./unispec.config.json
101
+ unispec portal start --config ./unispec.config.json
102
+ ```
104
103
 
105
104
  Options:
106
105
 
107
- - `--config <path>` — path to config file (default: `unispec.config.json|yaml|yml`)
108
- - `--host <host>` — bind host (default: `127.0.0.1`)
109
- - `--port <port>` — bind port (default: `4141`)
110
- - `--watch`watch config/spec files and refresh aggregated snapshot
111
- - `--ui` / `--no-ui` enable/disable embedded UI at `/` (default: enabled)
112
- - `--ui-dev <url>` proxy UI requests to an external dev server (e.g. Next.js) for HMR
113
- - `--portal` — spawn portal server from an installed dependency and proxy UI to it
114
- - `--portal-port <port>` port for portal server (default: `3000`)
106
+ - `--config <path>` — path to config file
107
+ - `--host <host>` — bind host (forwarded to portal)
108
+ - `--port <port>` — bind port (forwarded to portal)
109
+ - `--storage <type>` `json|sqlite` (forwarded to portal)
110
+ - `--data-dir <path>`data directory (forwarded to portal)
111
+ - `--open`open browser (forwarded to portal)
112
+ - `--verbose` — verbose output (forwarded to portal)
113
+ - `--json-errors`output errors as JSON (forwarded to portal)
115
114
  - `--portal-package <name>` — portal package name (default: `@unispechq/unispec-portal`)
116
115
 
117
- Planned responsibilities:
118
-
119
- - Watch local specs and/or connected services
120
- - Aggregate multiple UniSpec documents (microservices mode)
121
- - Serve a local dashboard and endpoints (e.g. `/unispec.json` for aggregated view)
122
- - Provide a single workflow to validate/normalize/diff before publishing to Registry
123
-
124
116
  ---
125
117
 
126
- ## Dev server (local orchestrator)
127
-
128
- `unispec dev` starts a local HTTP API that aggregates multiple UniSpec documents.
118
+ ## Notes
129
119
 
130
- Default bind:
120
+ All orchestration responsibilities (HTTP API, watch mode, workspace storage, and test runner) live in the Portal package.
131
121
 
132
- - Host: `127.0.0.1`
133
- - Port: `4141`
134
-
135
- Endpoints:
136
-
137
- - `GET /health` -> `OK`
138
- - `GET /unispec.json` -> aggregated JSON
139
- - `GET /workspace.json` -> workspace info (paths + API URLs)
140
- - `GET /workspace/state` -> workspace state
141
- - `PUT /workspace/state` -> save workspace state
142
- - `POST /tests/run` -> run tests (suite flow)
122
+ ---
143
123
 
144
- Aggregation format (A):
124
+ ## Aggregation format (A)
145
125
 
146
126
  ```json
147
127
  {
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
- import { registerConvertCommand, registerDevCommand, registerDiffCommand, registerNormalizeCommand, registerStartCommand, registerValidateCommand, } from "./commands/index.js";
3
+ import { registerConvertCommand, registerDiffCommand, registerNormalizeCommand, registerPortalCommand, registerValidateCommand, } from "./commands/index.js";
4
4
  function errorToJson(err, includeStack) {
5
5
  const message = err instanceof Error ? err.message : String(err);
6
6
  const code = err instanceof Error && "code" in err ? String(err.code) : undefined;
@@ -41,8 +41,7 @@ registerValidateCommand(program);
41
41
  registerNormalizeCommand(program);
42
42
  registerDiffCommand(program);
43
43
  registerConvertCommand(program);
44
- registerDevCommand(program);
45
- registerStartCommand(program);
44
+ registerPortalCommand(program);
46
45
  program.parseAsync(normalizeGlobalOptionsArgv(process.argv)).catch((err) => {
47
46
  const opts = program.opts();
48
47
  const verbose = opts.verbose ?? false;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,SAAS,WAAW,CAAC,GAAY,EAAE,YAAqB;IACtD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,GAAG,YAAY,KAAK,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAE,GAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3F,MAAM,KAAK,GAAG,YAAY,IAAI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACxF,CAAC;AAED,SAAS,0BAA0B,CAAC,IAAc;IAChD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE3B,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/E,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAElB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACf,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM;QACR,CAAC;QAED,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACzB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QAED,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,SAAS,EAAE,GAAG,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,oCAAoC,CAAC;KACjD,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,aAAa,EAAE,+BAA+B,CAAC;KACtD,MAAM,CAAC,WAAW,EAAE,2CAA2C,CAAC;KAChE,MAAM,CAAC,eAAe,EAAE,iCAAiC,CAAC,CAAC;AAE9D,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,wBAAwB,CAAC,OAAO,CAAC,CAAC;AAClC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAE9B,OAAO,CAAC,UAAU,CAAC,0BAA0B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAClF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAiD,CAAC;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,UAAU,GAAI,IAAY,CAAC,YAAY,CAAC,IAAK,IAAY,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC;IAExF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAClF,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,OAAO,IAAI,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,5 @@ export * from "./validate.js";
2
2
  export * from "./normalize.js";
3
3
  export * from "./diff.js";
4
4
  export * from "./convert.js";
5
- export * from "./dev.js";
6
- export * from "./start.js";
5
+ export * from "./portal.js";
7
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -2,6 +2,5 @@ export * from "./validate.js";
2
2
  export * from "./normalize.js";
3
3
  export * from "./diff.js";
4
4
  export * from "./convert.js";
5
- export * from "./dev.js";
6
- export * from "./start.js";
5
+ export * from "./portal.js";
7
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerPortalCommand(program: Command): void;
3
+ //# sourceMappingURL=portal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/commands/portal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoE5D"}
@@ -0,0 +1,90 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join } from "node:path";
4
+ import { readFile } from "node:fs/promises";
5
+ async function resolvePortalBin(portalPackage) {
6
+ const require = createRequire(import.meta.url);
7
+ const pkgJsonPath = require.resolve(`${portalPackage}/package.json`);
8
+ const pkgDir = dirname(pkgJsonPath);
9
+ const pkgRaw = await readFile(pkgJsonPath, "utf8");
10
+ const pkg = JSON.parse(pkgRaw);
11
+ if (!pkg.bin) {
12
+ return null;
13
+ }
14
+ if (typeof pkg.bin === "string") {
15
+ return { binPath: join(pkgDir, pkg.bin), binName: portalPackage };
16
+ }
17
+ const entries = Object.entries(pkg.bin);
18
+ if (entries.length === 0) {
19
+ return null;
20
+ }
21
+ const preferred = entries.find(([name]) => name === "unispec-portal") ?? entries[0];
22
+ return { binPath: join(pkgDir, preferred[1]), binName: preferred[0] };
23
+ }
24
+ function pickArg(options, camel, kebab) {
25
+ const v = options[camel] ?? options[kebab];
26
+ if (v === undefined || v === null)
27
+ return undefined;
28
+ return String(v);
29
+ }
30
+ export function registerPortalCommand(program) {
31
+ const cmd = program
32
+ .command("portal")
33
+ .description("Launch UniSpec Portal (Next.js orchestrator)")
34
+ .option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal");
35
+ const addSharedOptions = (c) => c
36
+ .requiredOption("--config <path>", "Path to unispec config file")
37
+ .option("--host <host>", "Bind host")
38
+ .option("--port <port>", "Bind port")
39
+ .option("--storage <type>", "Storage backend (json|sqlite)")
40
+ .option("--data-dir <path>", "Data directory (default: <configDir>/.unispec)")
41
+ .option("--open", "Open browser")
42
+ .option("--verbose", "Verbose portal output")
43
+ .option("--json-errors", "Output portal errors as JSON");
44
+ for (const mode of ["dev", "start"]) {
45
+ addSharedOptions(cmd
46
+ .command(mode)
47
+ .description(`Run portal in ${mode} mode`)
48
+ .action(async function (options) {
49
+ const parentOpts = this.parent?.opts?.();
50
+ const portalPackage = String(parentOpts?.portalPackage ?? "@unispechq/unispec-portal");
51
+ let resolved = null;
52
+ try {
53
+ resolved = await resolvePortalBin(portalPackage);
54
+ }
55
+ catch (err) {
56
+ const message = err instanceof Error ? err.message : String(err);
57
+ throw new Error(`Failed to resolve portal package '${portalPackage}': ${message}`);
58
+ }
59
+ if (!resolved) {
60
+ throw new Error(`Portal package '${portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
61
+ }
62
+ const args = [resolved.binPath, mode, "--config", String(options.config)];
63
+ const host = pickArg(options, "host", "host");
64
+ if (host)
65
+ args.push("--host", host);
66
+ const port = pickArg(options, "port", "port");
67
+ if (port)
68
+ args.push("--port", port);
69
+ const storage = pickArg(options, "storage", "storage");
70
+ if (storage)
71
+ args.push("--storage", storage);
72
+ const dataDir = pickArg(options, "dataDir", "data-dir");
73
+ if (dataDir)
74
+ args.push("--data-dir", dataDir);
75
+ if (options.open)
76
+ args.push("--open");
77
+ if (options.verbose)
78
+ args.push("--verbose");
79
+ if (options["jsonErrors"] ?? options["json-errors"])
80
+ args.push("--json-errors");
81
+ const child = spawn(process.execPath, args, {
82
+ stdio: "inherit",
83
+ env: { ...process.env },
84
+ });
85
+ const code = await new Promise((resolve) => child.once("exit", (c) => resolve(c ?? 0)));
86
+ process.exitCode = code;
87
+ }));
88
+ }
89
+ }
90
+ //# sourceMappingURL=portal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal.js","sourceRoot":"","sources":["../../src/commands/portal.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unispechq/unispec-platform",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI and local orchestrator for UniSpec (validate/normalize/diff/convert/dev).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,3 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerDevCommand(program: Command): void;
3
- //# sourceMappingURL=dev.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiFzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgLzD"}
@@ -1,211 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { watch } from "node:fs";
3
- import { dirname, isAbsolute, join, resolve } from "node:path";
4
- import { createRequire } from "node:module";
5
- import { readFile } from "node:fs/promises";
6
- import { loadConfig } from "../config/loadConfig.js";
7
- import { findConfigPath } from "../config/loadConfig.js";
8
- import { aggregateFromConfig } from "../dev/aggregate.js";
9
- import { startDevServer } from "../dev/server.js";
10
- function resolveConfigSpecPaths(config, baseDir) {
11
- if (!baseDir)
12
- return config;
13
- const services = Array.isArray(config.services) ? config.services : [];
14
- return {
15
- ...config,
16
- services: services.map((s) => {
17
- const spec = String(s?.spec ?? "");
18
- const resolvedSpec = spec && !isAbsolute(spec) ? resolve(baseDir, spec) : spec;
19
- return {
20
- ...s,
21
- spec: resolvedSpec,
22
- };
23
- }),
24
- };
25
- }
26
- async function resolvePortalBin(portalPackage) {
27
- const require = createRequire(import.meta.url);
28
- const pkgJsonPath = require.resolve(`${portalPackage}/package.json`);
29
- const pkgDir = dirname(pkgJsonPath);
30
- const pkgRaw = await readFile(pkgJsonPath, "utf8");
31
- const pkg = JSON.parse(pkgRaw);
32
- if (!pkg.bin) {
33
- return null;
34
- }
35
- if (typeof pkg.bin === "string") {
36
- return { binPath: join(pkgDir, pkg.bin), binName: portalPackage };
37
- }
38
- const entries = Object.entries(pkg.bin);
39
- if (entries.length === 0) {
40
- return null;
41
- }
42
- const preferred = entries.find(([name]) => name.includes("dev")) ?? entries[0];
43
- return { binPath: join(pkgDir, preferred[1]), binName: preferred[0] };
44
- }
45
- async function spawnPortalDevServer(options) {
46
- const resolved = await resolvePortalBin(options.portalPackage);
47
- if (!resolved) {
48
- throw new Error(`Portal package '${options.portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
49
- }
50
- const args = [resolved.binPath, "--port", String(options.port)];
51
- const child = spawn(process.execPath, args, {
52
- stdio: options.verbose ? "inherit" : "ignore",
53
- env: { ...process.env, PORT: String(options.port) },
54
- });
55
- child.once("exit", (code) => {
56
- if (options.verbose) {
57
- process.stderr.write(`Portal dev server exited with code ${code ?? "null"}\n`);
58
- }
59
- });
60
- return child;
61
- }
62
- export function registerDevCommand(program) {
63
- program
64
- .command("dev")
65
- .description("Local orchestrator mode: aggregate specs and serve a local API")
66
- .option("--config <path>", "Path to unispec config file")
67
- .option("--host <host>", "Host to bind", "127.0.0.1")
68
- .option("--port <port>", "Port to bind", "4141")
69
- .option("--watch", "Watch config/spec files and refresh aggregated snapshot")
70
- .option("--ui", "Serve embedded UI at /", true)
71
- .option("--no-ui", "Disable embedded UI")
72
- .option("--ui-dev <url>", "Proxy UI requests to an external dev server (e.g. Next.js)")
73
- .option("--portal", "Spawn portal server and proxy UI to it")
74
- .option("--portal-port <port>", "Port for portal server", "3000")
75
- .option("--portal-dev", "Spawn portal dev server from an installed dependency and proxy UI to it")
76
- .option("--portal-dev-port <port>", "Port for portal dev server")
77
- .option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal")
78
- .action(async function (options) {
79
- const parentOpts = this.parent?.opts?.();
80
- const verbose = parentOpts?.verbose ?? false;
81
- const host = String(options.host ?? "127.0.0.1");
82
- const port = Number(options.port ?? 4141);
83
- let snapshot;
84
- let snapshotError;
85
- const configPath = await findConfigPath({ explicitPath: options.config });
86
- const configDir = configPath ? dirname(configPath) : undefined;
87
- const workspaceDir = configDir ? join(configDir, ".unispec") : undefined;
88
- const loadAndAggregate = async () => {
89
- const config = await loadConfig({ explicitPath: options.config });
90
- const cfg = resolveConfigSpecPaths(config ?? { version: 1, services: [] }, configDir);
91
- return aggregateFromConfig(cfg);
92
- };
93
- const refreshSnapshot = async () => {
94
- try {
95
- snapshot = await loadAndAggregate();
96
- snapshotError = undefined;
97
- if (verbose) {
98
- process.stderr.write("Refreshed aggregated snapshot\n");
99
- }
100
- }
101
- catch (err) {
102
- const message = err instanceof Error ? err.message : String(err);
103
- snapshotError = { message };
104
- if (verbose) {
105
- process.stderr.write(`Failed to refresh snapshot: ${message}\n`);
106
- }
107
- }
108
- };
109
- await refreshSnapshot();
110
- const getConfig = async () => {
111
- const config = await loadConfig({ explicitPath: options.config });
112
- return resolveConfigSpecPaths(config ?? { version: 1, services: [] }, configDir);
113
- };
114
- const getAggregated = async () => {
115
- if (snapshot) {
116
- return snapshot;
117
- }
118
- if (snapshotError) {
119
- return {
120
- version: 1,
121
- generatedAt: new Date().toISOString(),
122
- services: [
123
- {
124
- name: "orchestrator",
125
- specPath: "config",
126
- valid: false,
127
- errors: [snapshotError],
128
- },
129
- ],
130
- };
131
- }
132
- return loadAndAggregate();
133
- };
134
- let portalChild;
135
- let uiDevUrl = options.uiDev;
136
- const portalEnabled = options.portalDev || options.portal;
137
- const portalPortRaw = options.portalDevPort ?? options.portalPort;
138
- if (portalEnabled) {
139
- if (uiDevUrl) {
140
- throw new Error("--portal cannot be used together with --ui-dev");
141
- }
142
- const portalPort = Number(portalPortRaw ?? 3000);
143
- const portalPackage = String(options.portalPackage ?? "@unispechq/unispec-portal");
144
- uiDevUrl = `http://127.0.0.1:${portalPort}`;
145
- try {
146
- portalChild = await spawnPortalDevServer({ portalPackage, port: portalPort, verbose });
147
- const stop = () => {
148
- try {
149
- portalChild?.kill("SIGINT");
150
- }
151
- catch {
152
- // ignore
153
- }
154
- };
155
- process.once("SIGINT", stop);
156
- process.once("SIGTERM", stop);
157
- process.once("exit", stop);
158
- if (verbose) {
159
- process.stderr.write(`Spawned portal server (${portalPackage}) at ${uiDevUrl}\n`);
160
- }
161
- }
162
- catch (err) {
163
- const message = err instanceof Error ? err.message : String(err);
164
- throw new Error(`Failed to start portal dev server: ${message}`);
165
- }
166
- }
167
- if (options.watch) {
168
- const cfg = await getConfig();
169
- const serviceSpecs = Array.isArray(cfg.services) ? cfg.services.map((s) => String(s.spec ?? "")) : [];
170
- const watchTargets = [
171
- ...(configPath ? [configPath] : []),
172
- ...serviceSpecs.filter(Boolean).map((p) => (isAbsolute(p) ? p : resolve(process.cwd(), p))),
173
- ];
174
- let timer;
175
- const scheduleRefresh = () => {
176
- if (timer)
177
- clearTimeout(timer);
178
- timer = setTimeout(() => {
179
- void refreshSnapshot();
180
- }, 200);
181
- };
182
- for (const target of watchTargets) {
183
- try {
184
- watch(target, { persistent: true }, () => scheduleRefresh());
185
- if (verbose) {
186
- process.stderr.write(`Watching ${target}\n`);
187
- }
188
- }
189
- catch (err) {
190
- if (verbose) {
191
- const message = err instanceof Error ? err.message : String(err);
192
- process.stderr.write(`Failed to watch ${target}: ${message}\n`);
193
- }
194
- }
195
- }
196
- }
197
- await startDevServer({
198
- host,
199
- port,
200
- getConfig,
201
- getAggregated,
202
- verbose,
203
- mode: "dev",
204
- configPath,
205
- workspaceDir,
206
- ui: options.ui,
207
- uiDevUrl,
208
- });
209
- });
210
- }
211
- //# sourceMappingURL=dev.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerStartCommand(program: Command): void;
3
- //# sourceMappingURL=start.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0EzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwF3D"}
@@ -1,125 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { createRequire } from "node:module";
3
- import { readFile } from "node:fs/promises";
4
- import { dirname, isAbsolute, join, resolve } from "node:path";
5
- import { loadConfig, findConfigPath } from "../config/loadConfig.js";
6
- import { startDevServer } from "../dev/server.js";
7
- function resolveConfigSpecPaths(config, baseDir) {
8
- if (!baseDir)
9
- return config;
10
- const services = Array.isArray(config.services) ? config.services : [];
11
- return {
12
- ...config,
13
- services: services.map((s) => {
14
- const spec = String(s?.spec ?? "");
15
- const resolvedSpec = spec && !isAbsolute(spec) ? resolve(baseDir, spec) : spec;
16
- return {
17
- ...s,
18
- spec: resolvedSpec,
19
- };
20
- }),
21
- };
22
- }
23
- async function resolvePortalBin(portalPackage, kind) {
24
- const require = createRequire(import.meta.url);
25
- const pkgJsonPath = require.resolve(`${portalPackage}/package.json`);
26
- const pkgDir = dirname(pkgJsonPath);
27
- const pkgRaw = await readFile(pkgJsonPath, "utf8");
28
- const pkg = JSON.parse(pkgRaw);
29
- if (!pkg.bin)
30
- return null;
31
- if (typeof pkg.bin === "string") {
32
- return join(pkgDir, pkg.bin);
33
- }
34
- const entries = Object.entries(pkg.bin);
35
- if (entries.length === 0)
36
- return null;
37
- const preferred = entries.find(([name]) => name.includes(kind)) ?? entries[0];
38
- return join(pkgDir, preferred[1]);
39
- }
40
- async function spawnPortalServer(options) {
41
- const binPath = await resolvePortalBin(options.portalPackage, options.mode);
42
- if (!binPath) {
43
- throw new Error(`Portal package '${options.portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
44
- }
45
- const args = [binPath, "--port", String(options.port), "--mode", options.mode];
46
- const child = spawn(process.execPath, args, {
47
- stdio: options.verbose ? "inherit" : "ignore",
48
- env: { ...process.env, PORT: String(options.port) },
49
- });
50
- child.once("exit", (code) => {
51
- if (options.verbose) {
52
- process.stderr.write(`Portal server exited with code ${code ?? "null"}\n`);
53
- }
54
- });
55
- return child;
56
- }
57
- export function registerStartCommand(program) {
58
- program
59
- .command("start")
60
- .description("Start a local server (UI + /unispec.json)")
61
- .option("--config <path>", "Path to unispec config file")
62
- .option("--host <host>", "Host to bind", "127.0.0.1")
63
- .option("--port <port>", "Port to bind", "4141")
64
- .option("--ui", "Serve embedded UI at /", true)
65
- .option("--no-ui", "Disable embedded UI")
66
- .option("--ui-url <url>", "Proxy UI requests to an external UI server")
67
- .option("--portal", "Spawn portal server (SSR) from an installed dependency and proxy UI to it")
68
- .option("--portal-port <port>", "Port for portal server", "3000")
69
- .option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal")
70
- .action(async function (options) {
71
- const parentOpts = this.parent?.opts?.();
72
- const verbose = parentOpts?.verbose ?? false;
73
- const host = String(options.host ?? "127.0.0.1");
74
- const port = Number(options.port ?? 4141);
75
- const configPath = await findConfigPath({ explicitPath: options.config });
76
- const configDir = configPath ? dirname(configPath) : undefined;
77
- const workspaceDir = configDir ? join(configDir, ".unispec") : undefined;
78
- const getConfig = async () => {
79
- const config = await loadConfig({ explicitPath: options.config });
80
- return resolveConfigSpecPaths(config ?? { version: 1, services: [] }, configDir);
81
- };
82
- let portalChild;
83
- let uiDevUrl = options.uiUrl;
84
- if (options.portal) {
85
- if (uiDevUrl) {
86
- throw new Error("--portal cannot be used together with --ui-url");
87
- }
88
- const portalPort = Number(options.portalPort ?? 3000);
89
- const portalPackage = String(options.portalPackage ?? "@unispechq/unispec-portal");
90
- uiDevUrl = `http://127.0.0.1:${portalPort}`;
91
- portalChild = await spawnPortalServer({
92
- portalPackage,
93
- port: portalPort,
94
- mode: "start",
95
- verbose,
96
- });
97
- const stop = () => {
98
- try {
99
- portalChild?.kill("SIGINT");
100
- }
101
- catch {
102
- // ignore
103
- }
104
- };
105
- process.once("SIGINT", stop);
106
- process.once("SIGTERM", stop);
107
- process.once("exit", stop);
108
- if (verbose) {
109
- process.stderr.write(`Spawned portal server (${portalPackage}) at ${uiDevUrl}\n`);
110
- }
111
- }
112
- await startDevServer({
113
- host,
114
- port,
115
- getConfig,
116
- verbose,
117
- mode: "start",
118
- configPath,
119
- workspaceDir,
120
- ui: options.ui,
121
- uiDevUrl: uiDevUrl,
122
- });
123
- });
124
- }
125
- //# sourceMappingURL=start.js.map