@unispechq/unispec-platform 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -204
- package/dist/cli.js +7 -5
- package/dist/cli.js.map +1 -1
- package/dist/commands/index.d.ts +1 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -2
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/portal.d.ts +4 -0
- package/dist/commands/portal.d.ts.map +1 -0
- package/dist/commands/portal.js +94 -0
- package/dist/commands/portal.js.map +1 -0
- package/package.json +2 -2
- package/dist/commands/dev.d.ts +0 -3
- package/dist/commands/dev.d.ts.map +0 -1
- package/dist/commands/dev.js +0 -211
- package/dist/commands/dev.js.map +0 -1
- package/dist/commands/start.d.ts +0 -3
- package/dist/commands/start.d.ts.map +0 -1
- package/dist/commands/start.js +0 -125
- package/dist/commands/start.js.map +0 -1
- package/dist/dev/aggregate.d.ts +0 -15
- package/dist/dev/aggregate.d.ts.map +0 -1
- package/dist/dev/aggregate.js +0 -56
- package/dist/dev/aggregate.js.map +0 -1
- package/dist/dev/index.d.ts +0 -3
- package/dist/dev/index.d.ts.map +0 -1
- package/dist/dev/index.js +0 -3
- package/dist/dev/index.js.map +0 -1
- package/dist/dev/server.d.ts +0 -17
- package/dist/dev/server.d.ts.map +0 -1
- package/dist/dev/server.js +0 -503
- package/dist/dev/server.js.map +0 -1
- package/dist/dev/ui.d.ts +0 -3
- package/dist/dev/ui.d.ts.map +0 -1
- package/dist/dev/ui.js +0 -93
- package/dist/dev/ui.js.map +0 -1
- package/dist/workspace/storage.d.ts +0 -7
- package/dist/workspace/storage.d.ts.map +0 -1
- package/dist/workspace/storage.js +0 -60
- package/dist/workspace/storage.js.map +0 -1
- package/dist/workspace/types.d.ts +0 -64
- package/dist/workspace/types.d.ts.map +0 -1
- package/dist/workspace/types.js +0 -2
- package/dist/workspace/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# UniSpec Platform
|
|
2
2
|
|
|
3
|
-
**CLI and
|
|
3
|
+
**UniSpec CLI utilities and portal launcher**
|
|
4
4
|
|
|
5
|
-
This repository contains the
|
|
5
|
+
This repository contains the UniSpec CLI utilities and a launcher for `@unispechq/unispec-portal`.
|
|
6
6
|
It builds on top of:
|
|
7
7
|
|
|
8
8
|
- `unispec-spec` — the UniSpec format definition (schemas, examples, reference docs)
|
|
@@ -23,8 +23,7 @@ This repository is in early development.
|
|
|
23
23
|
Current focus:
|
|
24
24
|
|
|
25
25
|
- Provide a stable CLI surface for `validate`, `normalize`, `diff`, `convert`
|
|
26
|
-
-
|
|
27
|
-
- Prepare integration points for the future `unispec-registry` (publish/read)
|
|
26
|
+
- Provide a stable launcher for `unispec portal <dev|start>`
|
|
28
27
|
|
|
29
28
|
---
|
|
30
29
|
|
|
@@ -34,9 +33,9 @@ Current focus:
|
|
|
34
33
|
unispec-platform/
|
|
35
34
|
├─ src/
|
|
36
35
|
│ ├─ cli.ts # CLI entrypoint
|
|
37
|
-
│ ├─ commands/ # Command registration (validate/normalize/diff/convert/
|
|
36
|
+
│ ├─ commands/ # Command registration (validate/normalize/diff/convert/portal)
|
|
38
37
|
│ ├─ io/ # File IO + output helpers
|
|
39
|
-
│ └─ config/ # Config loading
|
|
38
|
+
│ └─ config/ # Config loading
|
|
40
39
|
├─ package.json
|
|
41
40
|
├─ tsconfig.json
|
|
42
41
|
└─ README.md
|
|
@@ -89,218 +88,35 @@ Options:
|
|
|
89
88
|
- `--format <format>` — `json|yaml` (for JSON-like targets)
|
|
90
89
|
- `--output <file>` — write output to file (use `-` for stdout)
|
|
91
90
|
|
|
92
|
-
### `unispec dev
|
|
93
|
-
|
|
91
|
+
### `unispec portal <dev|start>`
|
|
92
|
+
Launch UniSpec Portal (Next.js orchestrator).
|
|
94
93
|
|
|
95
|
-
|
|
94
|
+
In the current architecture, `unispec-platform` provides CLI utilities (validate/normalize/diff/convert) and a launcher for `@unispechq/unispec-portal`.
|
|
96
95
|
|
|
97
|
-
|
|
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)
|
|
104
|
-
|
|
105
|
-
Options:
|
|
106
|
-
|
|
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`)
|
|
115
|
-
- `--portal-package <name>` — portal package name (default: `@unispechq/unispec-portal`)
|
|
116
|
-
|
|
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
|
-
---
|
|
125
|
-
|
|
126
|
-
## Dev server (local orchestrator)
|
|
127
|
-
|
|
128
|
-
`unispec dev` starts a local HTTP API that aggregates multiple UniSpec documents.
|
|
129
|
-
|
|
130
|
-
Default bind:
|
|
131
|
-
|
|
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)
|
|
143
|
-
|
|
144
|
-
Aggregation format (A):
|
|
145
|
-
|
|
146
|
-
```json
|
|
147
|
-
{
|
|
148
|
-
"version": 1,
|
|
149
|
-
"generatedAt": "2025-12-28T12:00:00.000Z",
|
|
150
|
-
"services": [
|
|
151
|
-
{
|
|
152
|
-
"name": "users",
|
|
153
|
-
"specPath": "./services/users/unispec.yaml",
|
|
154
|
-
"valid": true,
|
|
155
|
-
"spec": {}
|
|
156
|
-
}
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
If at least one service is invalid, `/unispec.json` responds with status `422` and includes per-service errors.
|
|
162
|
-
|
|
163
|
-
### Example
|
|
164
|
-
|
|
165
|
-
Start the server:
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
npm run dev -- dev --verbose
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Run using the bundled examples:
|
|
96
|
+
Examples:
|
|
172
97
|
|
|
173
98
|
```bash
|
|
174
|
-
|
|
99
|
+
unispec portal dev --config ./unispec.config.json
|
|
100
|
+
unispec portal start --config ./unispec.config.json
|
|
175
101
|
```
|
|
176
102
|
|
|
177
|
-
Then open:
|
|
178
|
-
|
|
179
|
-
- `http://127.0.0.1:4141/health`
|
|
180
|
-
- `http://127.0.0.1:4141/unispec.json`
|
|
181
|
-
- `http://127.0.0.1:4141/`
|
|
182
|
-
|
|
183
|
-
### `unispec start`
|
|
184
|
-
Production-like server mode.
|
|
185
|
-
|
|
186
|
-
`unispec start` runs the same HTTP surface as `unispec dev`, but is intended for long-running use.
|
|
187
|
-
|
|
188
103
|
Options:
|
|
189
104
|
|
|
190
105
|
- `--config <path>` — path to config file
|
|
191
|
-
- `--host <host>` — bind host (
|
|
192
|
-
- `--port <port>` — bind port (
|
|
193
|
-
- `--
|
|
194
|
-
- `--
|
|
195
|
-
- `--
|
|
196
|
-
- `--
|
|
106
|
+
- `--host <host>` — bind host (forwarded to portal)
|
|
107
|
+
- `--port <port>` — bind port (forwarded to portal)
|
|
108
|
+
- `--storage <type>` — `json|sqlite` (forwarded to portal)
|
|
109
|
+
- `--data-dir <path>` — data directory (forwarded to portal)
|
|
110
|
+
- `--open` — open browser (forwarded to portal)
|
|
111
|
+
- `--verbose` — verbose output (forwarded to portal)
|
|
112
|
+
- `--json-errors` — output errors as JSON (forwarded to portal)
|
|
197
113
|
- `--portal-package <name>` — portal package name (default: `@unispechq/unispec-portal`)
|
|
198
114
|
|
|
199
|
-
### Portal package contract
|
|
200
|
-
|
|
201
|
-
When using `--portal`, the portal package is expected to provide a single runnable `bin` entry which supports:
|
|
202
|
-
|
|
203
|
-
- `--port <port>`
|
|
204
|
-
- `--mode dev|start`
|
|
205
|
-
|
|
206
|
-
Example:
|
|
207
|
-
|
|
208
|
-
```bash
|
|
209
|
-
unispec-portal --mode dev --port 3000
|
|
210
|
-
unispec-portal --mode start --port 3000
|
|
211
|
-
```
|
|
212
|
-
|
|
213
115
|
---
|
|
214
116
|
|
|
215
|
-
##
|
|
216
|
-
|
|
217
|
-
Workspace data is stored in `.unispec/workspace.json` next to your config file. This file is not part of UniSpec.
|
|
218
|
-
|
|
219
|
-
### Workspace endpoints
|
|
220
|
-
|
|
221
|
-
- `GET /workspace.json` — info for clients (mode, configPath, storage paths, and API URLs)
|
|
222
|
-
- `GET /workspace/state` — workspace state JSON
|
|
223
|
-
- `PUT /workspace/state` — replace workspace state JSON (atomic write)
|
|
224
|
-
|
|
225
|
-
### Endpoint IDs
|
|
226
|
-
|
|
227
|
-
Workspace entities reference endpoints using:
|
|
228
|
-
|
|
229
|
-
```
|
|
230
|
-
{serviceName}:{METHOD}:{path}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
Example:
|
|
117
|
+
## Notes
|
|
234
118
|
|
|
235
|
-
|
|
236
|
-
users:GET:/users
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
## Workspace tests
|
|
242
|
-
|
|
243
|
-
Tests are stored in workspace state as YAML or JSON strings and can be run through:
|
|
244
|
-
|
|
245
|
-
- `POST /tests/run` with `{ "suiteId": "..." }` or `{ "testIds": ["..."] }`
|
|
246
|
-
|
|
247
|
-
### YAML/JSON test format (single request)
|
|
248
|
-
|
|
249
|
-
```yaml
|
|
250
|
-
request:
|
|
251
|
-
method: GET
|
|
252
|
-
url: "http://127.0.0.1:4141/health"
|
|
253
|
-
expect:
|
|
254
|
-
status: 200
|
|
255
|
-
bodyContains: "OK"
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Multi-step tests (flow)
|
|
259
|
-
|
|
260
|
-
```yaml
|
|
261
|
-
steps:
|
|
262
|
-
- name: health
|
|
263
|
-
request:
|
|
264
|
-
method: GET
|
|
265
|
-
url: "http://127.0.0.1:4141/health"
|
|
266
|
-
expect:
|
|
267
|
-
status: 200
|
|
268
|
-
bodyContains: "OK"
|
|
269
|
-
extract:
|
|
270
|
-
st:
|
|
271
|
-
from: status
|
|
272
|
-
|
|
273
|
-
- name: unispec
|
|
274
|
-
request:
|
|
275
|
-
method: GET
|
|
276
|
-
url: "http://127.0.0.1:4141/unispec.json"
|
|
277
|
-
expect:
|
|
278
|
-
status: 200
|
|
279
|
-
jsonContains:
|
|
280
|
-
version: 1
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### Variables and interpolation
|
|
284
|
-
|
|
285
|
-
You can extract variables and use them with `{{var}}` in URL/headers/body:
|
|
286
|
-
|
|
287
|
-
```yaml
|
|
288
|
-
steps:
|
|
289
|
-
- request:
|
|
290
|
-
method: GET
|
|
291
|
-
url: "https://example.com/api/session"
|
|
292
|
-
extract:
|
|
293
|
-
token:
|
|
294
|
-
from: json
|
|
295
|
-
path: "$.token"
|
|
296
|
-
- request:
|
|
297
|
-
method: GET
|
|
298
|
-
url: "https://example.com/api/me"
|
|
299
|
-
headers:
|
|
300
|
-
authorization: "Bearer {{token}}"
|
|
301
|
-
expect:
|
|
302
|
-
status: 200
|
|
303
|
-
```
|
|
119
|
+
All orchestration responsibilities (HTTP API, watch mode, workspace storage, and test runner) live in the Portal package.
|
|
304
120
|
|
|
305
121
|
---
|
|
306
122
|
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { registerConvertCommand, registerDiffCommand, registerNormalizeCommand, registerPortalCommand, registerValidateCommand, } from "./commands/index.js";
|
|
4
5
|
function errorToJson(err, includeStack) {
|
|
5
6
|
const message = err instanceof Error ? err.message : String(err);
|
|
6
7
|
const code = err instanceof Error && "code" in err ? String(err.code) : undefined;
|
|
@@ -30,10 +31,12 @@ function normalizeGlobalOptionsArgv(argv) {
|
|
|
30
31
|
return [...head, ...extracted, ...remaining];
|
|
31
32
|
}
|
|
32
33
|
const program = new Command();
|
|
34
|
+
const require = createRequire(import.meta.url);
|
|
35
|
+
const pkg = require("../package.json");
|
|
33
36
|
program
|
|
34
37
|
.name("unispec")
|
|
35
|
-
.description("UniSpec CLI and
|
|
36
|
-
.version("0.
|
|
38
|
+
.description("UniSpec CLI and portal launcher")
|
|
39
|
+
.version(String(pkg.version ?? "0.0.0"))
|
|
37
40
|
.option("-q, --quiet", "Suppress non-essential output")
|
|
38
41
|
.option("--verbose", "Enable verbose diagnostic output (stderr)")
|
|
39
42
|
.option("--json-errors", "Output errors as JSON to stderr");
|
|
@@ -41,8 +44,7 @@ registerValidateCommand(program);
|
|
|
41
44
|
registerNormalizeCommand(program);
|
|
42
45
|
registerDiffCommand(program);
|
|
43
46
|
registerConvertCommand(program);
|
|
44
|
-
|
|
45
|
-
registerStartCommand(program);
|
|
47
|
+
registerPortalCommand(program);
|
|
46
48
|
program.parseAsync(normalizeGlobalOptionsArgv(process.argv)).catch((err) => {
|
|
47
49
|
const opts = program.opts();
|
|
48
50
|
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,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/commands/index.js
CHANGED
|
@@ -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,
|
|
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,4 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export declare function buildPortalNodeArgs(binPath: string, mode: "dev" | "start", options: Record<string, unknown>): string[];
|
|
3
|
+
export declare function registerPortalCommand(program: Command): void;
|
|
4
|
+
//# 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,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAoBtH;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoD5D"}
|
|
@@ -0,0 +1,94 @@
|
|
|
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 buildPortalNodeArgs(binPath, mode, options) {
|
|
31
|
+
const args = [binPath, mode, "--config", String(options.config)];
|
|
32
|
+
const host = pickArg(options, "host", "host");
|
|
33
|
+
if (host)
|
|
34
|
+
args.push("--host", host);
|
|
35
|
+
const port = pickArg(options, "port", "port");
|
|
36
|
+
if (port)
|
|
37
|
+
args.push("--port", port);
|
|
38
|
+
const storage = pickArg(options, "storage", "storage");
|
|
39
|
+
if (storage)
|
|
40
|
+
args.push("--storage", storage);
|
|
41
|
+
const dataDir = pickArg(options, "dataDir", "data-dir");
|
|
42
|
+
if (dataDir)
|
|
43
|
+
args.push("--data-dir", dataDir);
|
|
44
|
+
if (options.open)
|
|
45
|
+
args.push("--open");
|
|
46
|
+
if (options.verbose)
|
|
47
|
+
args.push("--verbose");
|
|
48
|
+
if (options["jsonErrors"] ?? options["json-errors"])
|
|
49
|
+
args.push("--json-errors");
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
export function registerPortalCommand(program) {
|
|
53
|
+
const cmd = program
|
|
54
|
+
.command("portal")
|
|
55
|
+
.description("Launch UniSpec Portal (Next.js orchestrator)")
|
|
56
|
+
.option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal");
|
|
57
|
+
const addSharedOptions = (c) => c
|
|
58
|
+
.requiredOption("--config <path>", "Path to unispec config file")
|
|
59
|
+
.option("--host <host>", "Bind host")
|
|
60
|
+
.option("--port <port>", "Bind port")
|
|
61
|
+
.option("--storage <type>", "Storage backend (json|sqlite)")
|
|
62
|
+
.option("--data-dir <path>", "Data directory (default: <configDir>/.unispec)")
|
|
63
|
+
.option("--open", "Open browser")
|
|
64
|
+
.option("--verbose", "Verbose portal output")
|
|
65
|
+
.option("--json-errors", "Output portal errors as JSON");
|
|
66
|
+
for (const mode of ["dev", "start"]) {
|
|
67
|
+
addSharedOptions(cmd
|
|
68
|
+
.command(mode)
|
|
69
|
+
.description(`Run portal in ${mode} mode`)
|
|
70
|
+
.action(async function (options) {
|
|
71
|
+
const parentOpts = this.parent?.opts?.();
|
|
72
|
+
const portalPackage = String(parentOpts?.portalPackage ?? "@unispechq/unispec-portal");
|
|
73
|
+
let resolved = null;
|
|
74
|
+
try {
|
|
75
|
+
resolved = await resolvePortalBin(portalPackage);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
79
|
+
throw new Error(`Failed to resolve portal package '${portalPackage}': ${message}`);
|
|
80
|
+
}
|
|
81
|
+
if (!resolved) {
|
|
82
|
+
throw new Error(`Portal package '${portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
|
|
83
|
+
}
|
|
84
|
+
const args = buildPortalNodeArgs(resolved.binPath, mode, options);
|
|
85
|
+
const child = spawn(process.execPath, args, {
|
|
86
|
+
stdio: "inherit",
|
|
87
|
+
env: { ...process.env },
|
|
88
|
+
});
|
|
89
|
+
const code = await new Promise((resolve) => child.once("exit", (c) => resolve(c ?? 0)));
|
|
90
|
+
process.exitCode = code;
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# 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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unispechq/unispec-platform",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "CLI
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "UniSpec CLI utilities (validate/normalize/diff/convert) and portal launcher.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
package/dist/commands/dev.d.ts
DELETED
|
@@ -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"}
|