workspai 0.76.0 → 0.77.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.
- package/README.md +2 -2
- package/contracts/create-planner-capabilities.v1.json +24 -0
- package/contracts/runtime-command-surface.v1.json +3 -1
- package/contracts/workspace-intelligence/workspace-model.v1.json +4 -0
- package/contracts/workspace-intelligence-architecture.v1.json +3 -1
- package/dist/analyze-TJM66CPF.js +1 -0
- package/dist/autopilot-release-C7Q4OTPY.js +1 -0
- package/dist/capabilities-command-TIBIKWPK.js +1 -0
- package/dist/{chunk-Z2M2XCIB.js → chunk-223SWPTL.js} +1 -1
- package/dist/{chunk-RKFTUIZ4.js → chunk-3EMAC3MF.js} +1 -1
- package/dist/{chunk-BZLDCASY.js → chunk-3EPR3D5Q.js} +1 -1
- package/dist/{chunk-PUH3TSPC.js → chunk-3SQIV3F4.js} +1 -1
- package/dist/{chunk-HRGIHWYH.js → chunk-475GQJ2D.js} +1 -1
- package/dist/{chunk-FBF767WP.js → chunk-47UR6ZH4.js} +1 -1
- package/dist/{chunk-AGI46TSQ.js → chunk-4CXV3PPV.js} +1 -1
- package/dist/chunk-4ZUBPFSO.js +6 -0
- package/dist/chunk-5KXOV7W4.js +1 -0
- package/dist/{chunk-4MXKXHLW.js → chunk-DWKCFHHL.js} +1 -1
- package/dist/{chunk-L6VNI4DN.js → chunk-E7WJ2QX7.js} +1 -1
- package/dist/{chunk-KW35SWG6.js → chunk-GLBFY7AB.js} +2 -2
- package/dist/{chunk-KO4DM2AV.js → chunk-HRVHQBTA.js} +1 -1
- package/dist/{chunk-X7MDTBX5.js → chunk-IAXRGH4Q.js} +1 -1
- package/dist/{chunk-QIPW3G2H.js → chunk-IDETNYCF.js} +1 -1
- package/dist/{chunk-YLLCZMKP.js → chunk-IHWS3ALP.js} +1 -1
- package/dist/{chunk-R3Z4LY3O.js → chunk-J2MPBSQJ.js} +1 -1
- package/dist/{chunk-FD2ZGGCQ.js → chunk-JVZA35OL.js} +1 -1
- package/dist/{chunk-H4YHIOCT.js → chunk-LUPKDFQ3.js} +3 -3
- package/dist/chunk-N7DOKE7V.js +2 -0
- package/dist/{chunk-TJ3MDZMC.js → chunk-O3TVVQ6X.js} +1 -1
- package/dist/{chunk-4BBFEHPL.js → chunk-QCX6BO2M.js} +1 -1
- package/dist/{chunk-PSQPKK6H.js → chunk-SC43A6LH.js} +52 -52
- package/dist/chunk-SEZTSMRR.js +1 -0
- package/dist/{chunk-TFFNHWXY.js → chunk-TGNPMOM6.js} +1 -1
- package/dist/chunk-UNEK3VVR.js +2684 -0
- package/dist/{chunk-2I2A55RE.js → chunk-UP3UWAJV.js} +1 -1
- package/dist/{chunk-IKNWNGLY.js → chunk-UTIK3K3M.js} +1 -1
- package/dist/{chunk-UOTOJJI4.js → chunk-V6HVDVKJ.js} +5 -5
- package/dist/chunk-WC2K5QFI.js +10 -0
- package/dist/{chunk-ZXQC36NJ.js → chunk-X5XFT5UZ.js} +1 -1
- package/dist/{chunk-23CNBYIW.js → chunk-ZIWWE4BQ.js} +1 -1
- package/dist/{create-ZRUQ3KNZ.js → create-YPAZJYCE.js} +1 -1
- package/dist/{doctor-7V7LJLHX.js → doctor-W5PXJ5FL.js} +1 -1
- package/dist/{goal-lifecycle-EM4DUJCR.js → goal-lifecycle-5R55CA7H.js} +1 -1
- package/dist/{goal-pack-YMWZHAH6.js → goal-pack-IS6GGJPH.js} +1 -1
- package/dist/index.js +256 -247
- package/dist/{pipeline-6MBH3MU2.js → pipeline-LW3SW2WT.js} +1 -1
- package/dist/{project-agent-entry-ZXAE2MAJ.js → project-agent-entry-5TYKK5IV.js} +1 -1
- package/dist/{project-intelligence-lens-NBTPOK2R.js → project-intelligence-lens-TEOSTKNU.js} +1 -1
- package/dist/{project-test-coverage-HOZC72EK.js → project-test-coverage-T4TIWGKN.js} +1 -1
- package/dist/{proof-carrying-change-WJFAKK3C.js → proof-carrying-change-2TKRADCW.js} +1 -1
- package/dist/{verified-goal-B7EX2PBE.js → verified-goal-RN4TOV34.js} +1 -1
- package/dist/{workspace-EBPYCSEM.js → workspace-A33YMF2N.js} +1 -1
- package/dist/{workspace-agent-sync-Y4F6FBBC.js → workspace-agent-sync-VCA4G4DT.js} +1 -1
- package/dist/{workspace-context-Y7F7GJCQ.js → workspace-context-YBWLSKR6.js} +1 -1
- package/dist/{workspace-contract-XJMWMVQE.js → workspace-contract-3QUZDBMM.js} +1 -1
- package/dist/{workspace-explain-T2J5ZLY7.js → workspace-explain-NXYRAQFI.js} +1 -1
- package/dist/{workspace-foundation-2UP6IMTH.js → workspace-foundation-DZ52PECX.js} +1 -1
- package/dist/{workspace-graph-stream-MZVL3OCX.js → workspace-graph-stream-4VT46HZ7.js} +1 -1
- package/dist/{workspace-intelligence-FZRQIFFM.js → workspace-intelligence-FKYQQDJ6.js} +1 -1
- package/dist/{workspace-intelligence-runner-IXT62JG7.js → workspace-intelligence-runner-3K2JZH6Q.js} +1 -1
- package/dist/{workspace-knowledge-graph-EFC4TUDZ.js → workspace-knowledge-graph-CPBKNXQI.js} +1 -1
- package/dist/workspace-knowledge-graph-snapshot-67XDXUOT.js +1 -0
- package/dist/{workspace-mcp-serve-C42UUU7W.js → workspace-mcp-serve-UXPKX7K6.js} +1 -1
- package/dist/{workspace-model-72SJ6WXT.js → workspace-model-POCPMNRT.js} +1 -1
- package/dist/{workspace-onboarding-TFDAIHTS.js → workspace-onboarding-KLG3GG7S.js} +1 -1
- package/dist/{workspace-registry-summary-ZNTXSUI4.js → workspace-registry-summary-M4WMFDQ4.js} +1 -1
- package/dist/{workspace-repair-engine-542TAL3Z.js → workspace-repair-engine-2VGN42QD.js} +1 -1
- package/dist/workspace-run-5YQR7GEZ.js +1 -0
- package/dist/{workspace-verify-UXKENOQU.js → workspace-verify-PLAKTF3J.js} +1 -1
- package/dist/{workspace-watch-DV5AHLOK.js → workspace-watch-VNU4KVYN.js} +1 -1
- package/docs/README.md +2 -0
- package/docs/agent-framework-adapters.md +4 -0
- package/docs/ci-workflows.md +12 -1
- package/docs/commands-reference.md +2 -0
- package/docs/create-planner-capabilities.md +1 -0
- package/docs/creating-workspaces-and-projects.md +24 -7
- package/docs/doctor-command.md +3 -0
- package/docs/model-gateways.md +204 -0
- package/docs/native-kit-baselines.md +2 -1
- package/package.json +3 -1
- package/scripts/enterprise-package-smoke.mjs +102 -0
- package/dist/analyze-QVRVJB7I.js +0 -1
- package/dist/autopilot-release-DOGIETAT.js +0 -1
- package/dist/capabilities-command-FYBUVHZ7.js +0 -1
- package/dist/chunk-4R44E7HN.js +0 -6
- package/dist/chunk-5S6IZ6PY.js +0 -2
- package/dist/chunk-NSC4VWV2.js +0 -1
- package/dist/chunk-QFDTKOYS.js +0 -2649
- package/dist/chunk-QVFIR64T.js +0 -10
- package/dist/chunk-VODNLROY.js +0 -1
- package/dist/workspace-knowledge-graph-snapshot-QIMF7TCF.js +0 -1
- package/dist/workspace-run-NAPJYNSZ.js +0 -1
|
@@ -16,9 +16,9 @@ For a compact list of command syntax, see
|
|
|
16
16
|
A **workspace** is the shared home for related projects, rules, and saved
|
|
17
17
|
Workspai reports.
|
|
18
18
|
|
|
19
|
-
A **project** is an application, service,
|
|
20
|
-
API, Go service, Spring Boot service, .NET API, frontend application,
|
|
21
|
-
Microsoft Agent Framework entrypoint.
|
|
19
|
+
A **project** is an application, service, governed agent, or model gateway, such as a FastAPI
|
|
20
|
+
API, Go service, Spring Boot service, .NET API, frontend application,
|
|
21
|
+
Microsoft Agent Framework entrypoint, or OpenRouter AI Gateway.
|
|
22
22
|
|
|
23
23
|
The canonical commands are:
|
|
24
24
|
|
|
@@ -42,6 +42,7 @@ does not have exactly the same behavior.
|
|
|
42
42
|
| Turn the current folder into a workspace before creating | `npx workspai create project gofiber.standard api --create-workspace --yes` |
|
|
43
43
|
| Create a project without workspace management | `npx workspai create project gofiber.standard api --no-workspace --yes` |
|
|
44
44
|
| Create a governed Microsoft Agent Framework project | `npx workspai create project agent.microsoft.python support-agent` |
|
|
45
|
+
| Create a server-owned OpenRouter AI Gateway | `npx workspai create project gateway.openrouter.typescript model-gateway` |
|
|
45
46
|
| Preview a supported create plan | `npx workspai create project frontend.nextjs web --dry-run` |
|
|
46
47
|
|
|
47
48
|
# Creating a workspace
|
|
@@ -418,6 +419,21 @@ npx workspai change verify --change <change-id> --json
|
|
|
418
419
|
independent proof for this scaffold. See
|
|
419
420
|
[Agent Framework Adapter Contract](./agent-framework-adapters.md).
|
|
420
421
|
|
|
422
|
+
## AI Gateway kits
|
|
423
|
+
|
|
424
|
+
| Kit | Runtime | Tested baseline | Layout |
|
|
425
|
+
| --- | --- | --- | --- |
|
|
426
|
+
| `gateway.openrouter.typescript` | Node.js | `@openrouter/sdk` `1.3.11`, TypeScript `5.9.3`, `@types/node` `22.20.3` | Server-owned OpenRouter Client SDK starter with `gateway.policy.json`, credentialless `node:test`, and `.env.example` |
|
|
427
|
+
| `gateway.openrouter.python` | Python | `openrouter` `1.2.11` | Server-owned OpenRouter Client SDK starter with `gateway.policy.json`, credentialless `unittest`, and `.env.example` |
|
|
428
|
+
|
|
429
|
+
Interactive `workspai create` shows these kits under **AI Gateway** with the
|
|
430
|
+
hint **Unified model access and routing**. A model identifier is runtime
|
|
431
|
+
configuration, not a kit. Create does not install dependencies, call a model,
|
|
432
|
+
or store credentials. Attach is not supported for Gateway in this release.
|
|
433
|
+
The official Go Client SDK remains beta (`v0.8.11` on
|
|
434
|
+
2026-09-21) and is not admitted. See
|
|
435
|
+
[AI Gateway](./model-gateways.md).
|
|
436
|
+
|
|
421
437
|
## Desktop, extension, and additional backend generators
|
|
422
438
|
|
|
423
439
|
| Category | Project | Kit | Creation owner |
|
|
@@ -428,10 +444,11 @@ independent proof for this scaffold. See
|
|
|
428
444
|
| Desktop | Electron Forge | `desktop.electron` | create-electron-app |
|
|
429
445
|
| Extension | VS Code Extension | `extension.vscode` | generator-code |
|
|
430
446
|
|
|
431
|
-
Every generated project receives a canonical `kind` and `category`. The
|
|
432
|
-
user-facing creation categories are `backend`, `frontend`, `desktop`, `agent`,
|
|
433
|
-
they remain visible in the Workspace Model and
|
|
434
|
-
not have to guess a project’s role from its
|
|
447
|
+
Every generated project receives a canonical `kind` and `category`. The
|
|
448
|
+
user-facing creation categories are `backend`, `frontend`, `desktop`, `agent`,
|
|
449
|
+
`gateway`, and `extension`; they remain visible in the Workspace Model and
|
|
450
|
+
Knowledge Graph so consumers do not have to guess a project’s role from its
|
|
451
|
+
runtime.
|
|
435
452
|
|
|
436
453
|
Official generators may download packages and therefore need network access.
|
|
437
454
|
Each available integration requests the upstream latest stable channel rather
|
package/docs/doctor-command.md
CHANGED
|
@@ -781,6 +781,9 @@ These fields are designed for release gates and extension timeline cards that mu
|
|
|
781
781
|
dependency manifests under `agents/primary` and aims Python/`uv`, Node
|
|
782
782
|
`npm --prefix`, or .NET repair commands at that runtime, not at a phantom
|
|
783
783
|
project-root manifest.
|
|
784
|
+
- OpenRouter AI Gateway projects keep `kind` as `gateway` and `framework` as
|
|
785
|
+
`openrouter`. Doctor uses the project-root Node or Python runtime, not the
|
|
786
|
+
Agent Framework nested layout.
|
|
784
787
|
|
|
785
788
|
## Project JSON fields (AI/automation)
|
|
786
789
|
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# AI Gateway
|
|
2
|
+
|
|
3
|
+
AI Gateway is a first-class Workspai project category for unified model access
|
|
4
|
+
and routing. It is not an Agent Framework.
|
|
5
|
+
|
|
6
|
+
## Why Gateway is not Agent Framework
|
|
7
|
+
|
|
8
|
+
Agent Framework owns agent loops, tools, handoffs, state, and orchestration.
|
|
9
|
+
AI Gateway owns model and provider access, routing preferences, fallbacks,
|
|
10
|
+
privacy policy, and normalized transport behavior.
|
|
11
|
+
|
|
12
|
+
A model identifier is runtime configuration, not a project kit. Workspai owns
|
|
13
|
+
project generation, governance, context, lifecycle, verification, workspace
|
|
14
|
+
integration, and proof. OpenRouter owns provider and model routing. Generated
|
|
15
|
+
projects do not reimplement OpenRouter's routing algorithms.
|
|
16
|
+
|
|
17
|
+
Future agent-to-gateway composition should consume the generated Model Gateway
|
|
18
|
+
port. Do not copy these templates into an Agent Framework kit.
|
|
19
|
+
|
|
20
|
+
## Current kits
|
|
21
|
+
|
|
22
|
+
These kits ship as source-ready. That is not Workspai release admission and
|
|
23
|
+
does not label them `stable` or `qualified`. SDK `1.x` stability is an upstream
|
|
24
|
+
classification, not a Workspai release gate.
|
|
25
|
+
|
|
26
|
+
| Kit | Runtime | Official Client SDK | Reviewed |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| `gateway.openrouter.typescript` | Node.js `>=20` | `@openrouter/sdk` `1.3.11` | 2026-09-21 |
|
|
29
|
+
| `gateway.openrouter.python` | Python `>=3.10` | `openrouter` `1.2.11` | 2026-09-21 |
|
|
30
|
+
|
|
31
|
+
Aliases: `openrouter.typescript`, `gateway.openrouter.ts`, `openrouter-typescript`,
|
|
32
|
+
and the matching Python aliases. Bare `openrouter` is not an alias.
|
|
33
|
+
|
|
34
|
+
Interactive Create shows **AI Gateway** with the hint **Unified model access
|
|
35
|
+
and routing** after at least one gateway kit is registered. Labels are:
|
|
36
|
+
|
|
37
|
+
- `AI Gateway · OpenRouter · TypeScript`
|
|
38
|
+
- `AI Gateway · OpenRouter · Python`
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx workspai create project gateway.openrouter.typescript <name>
|
|
42
|
+
npx workspai create project gateway.openrouter.python <name>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Create does not install dependencies, call a model, or write credentials.
|
|
46
|
+
|
|
47
|
+
Attach is not supported for AI Gateway in this release. Do not use
|
|
48
|
+
`agent framework attach` or any gateway-specific attach command. Adopt an
|
|
49
|
+
existing OpenRouter project only by creating a new gateway kit or by adding
|
|
50
|
+
the generated starter beside user-owned code. Repeated Create is not Attach.
|
|
51
|
+
|
|
52
|
+
## Version upgrades
|
|
53
|
+
|
|
54
|
+
Exact SDK pins live only in
|
|
55
|
+
[`version-baselines.v1.json`](../src/model-gateways/version-baselines.v1.json).
|
|
56
|
+
`releaseChannel: stable` means the upstream SDK release is stable. It does not
|
|
57
|
+
mean the Workspai adapter passed Linux, macOS, and Windows qualification.
|
|
58
|
+
|
|
59
|
+
The supported upgrade path is read-only until a human reviews the proposal:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
discover → propose → review → qualify → merge
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm --workspace workspai run propose:model-gateway:versions -- \
|
|
67
|
+
--baseline src/model-gateways/version-baselines.v1.json \
|
|
68
|
+
--report test-results/model-gateway-version-discovery.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The command does not commit, push, open a pull request, or write the baseline
|
|
72
|
+
unless `--write` is passed after the on-disk file matches the validated
|
|
73
|
+
in-memory document and every candidate agrees across registry and GitHub.
|
|
74
|
+
A normal SDK upgrade should not require editing generator source when the
|
|
75
|
+
upstream contract is compatible. Three-OS qualification must be green on the
|
|
76
|
+
same commit before a Workspai release can present these kits as qualified.
|
|
77
|
+
|
|
78
|
+
## Intentionally unsupported languages
|
|
79
|
+
|
|
80
|
+
The official Go SDK (`github.com/OpenRouterTeam/go-sdk`) was evaluated on
|
|
81
|
+
2026-09-21. The upstream README classifies the current `0.x` line as beta and
|
|
82
|
+
warns that breaking changes may ship in minor releases. proxy.golang.org
|
|
83
|
+
reported `v0.8.11`. Go is excluded from the stable Create surface until
|
|
84
|
+
upstream classifies a release line as stable.
|
|
85
|
+
|
|
86
|
+
The OpenRouter Agent SDK (`@openrouter/agent`) belongs to the agent-runtime
|
|
87
|
+
dimension. It is not used by AI Gateway kits and is not added as
|
|
88
|
+
`agent.openrouter.typescript` in this family.
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
Required environment:
|
|
93
|
+
|
|
94
|
+
- `OPENROUTER_API_KEY` — server-side only
|
|
95
|
+
- `OPENROUTER_MODEL` — chosen by the operator; Workspai does not default a
|
|
96
|
+
billable model
|
|
97
|
+
|
|
98
|
+
Optional attribution maps to the official SDK fields:
|
|
99
|
+
|
|
100
|
+
- TypeScript: `httpReferer`, `appTitle` via `OPENROUTER_HTTP_REFERER` and
|
|
101
|
+
`OPENROUTER_APP_TITLE`
|
|
102
|
+
- Python: `http_referer`, `x_open_router_title` via `OPENROUTER_HTTP_REFERER`
|
|
103
|
+
and `OPENROUTER_X_OPEN_ROUTER_TITLE`
|
|
104
|
+
|
|
105
|
+
Routing and privacy policy live in source-controlled `gateway.policy.json`.
|
|
106
|
+
Field names match the pinned SDK for that language. Unknown fields are rejected
|
|
107
|
+
fail-closed in both languages. Supported controls:
|
|
108
|
+
|
|
109
|
+
| Official field | TypeScript policy | Python policy | Validation |
|
|
110
|
+
| --- | --- | --- | --- |
|
|
111
|
+
| model fallbacks | `models` | `models` | unique non-empty strings; must not repeat `OPENROUTER_MODEL` |
|
|
112
|
+
| `allowFallbacks` | `allowFallbacks` | `allow_fallbacks` | boolean when present |
|
|
113
|
+
| `order` / `only` / `ignore` | same camelCase | same snake_case | unique non-empty strings; `only`∩`ignore` empty; `order` must not include ignored providers |
|
|
114
|
+
| `sort` | string or `{ by, partition }` | string or `{ by, partition }` | `price`/`throughput`/`latency`/`exacto`; `partition` is `model` or `none` |
|
|
115
|
+
| `quantizations` | camelCase list | snake_case list | pinned SDK enum values |
|
|
116
|
+
| `requireParameters` | `requireParameters` | `require_parameters` | boolean when present |
|
|
117
|
+
| `zdr` | `zdr` | `zdr` | boolean; cannot combine with `dataCollection`/`data_collection` `allow` |
|
|
118
|
+
| `dataCollection` | `dataCollection` | `data_collection` | `allow` or `deny` |
|
|
119
|
+
| `enforceDistillableText` | `enforceDistillableText` | `enforce_distillable_text` | boolean when present; both pinned SDKs expose this field |
|
|
120
|
+
| `maxPrice` | `maxPrice` | `max_price` | object with `prompt`/`completion`/`request`/`image`/`audio` as non-negative numeric strings that remain finite after numeric interpretation |
|
|
121
|
+
| `preferredMinThroughput` | number or `{ p50, p75, p90, p99 }` | same | finite non-negative numbers |
|
|
122
|
+
| `preferredMaxLatency` | number or `{ p50, p75, p90, p99 }` | same | finite non-negative numbers |
|
|
123
|
+
| timeout | `timeoutMs` | `timeout_ms` | integer 1–600000; env overrides with a digit string |
|
|
124
|
+
| attribution | `httpReferer`, `appTitle` | `http_referer`, `x_open_router_title` | strings when present |
|
|
125
|
+
|
|
126
|
+
`exacto` is part of the pinned SDK `ProviderSort` enums, not a Workspai extension.
|
|
127
|
+
Malformed JSON and wrong types raise `GatewayConfigurationError` before SDK
|
|
128
|
+
construction. Contradictory policy, including ZDR combined with
|
|
129
|
+
`dataCollection: "allow"`, fails before a network request.
|
|
130
|
+
|
|
131
|
+
Omitted privacy or routing fields leave OpenRouter upstream defaults in
|
|
132
|
+
effect. The SDKs document `dataCollection` / `data_collection` default as
|
|
133
|
+
`allow` when unset. Application-side retries are set to strategy `none` so they
|
|
134
|
+
cannot duplicate billable requests. OpenRouter may still apply provider
|
|
135
|
+
fallbacks when `allowFallbacks` / `allow_fallbacks` is not `false`.
|
|
136
|
+
|
|
137
|
+
Capabilities such as tools, JSON schema, structured output, images, audio, and
|
|
138
|
+
embeddings vary by model and provider. These starters only claim chat
|
|
139
|
+
generation and streaming.
|
|
140
|
+
|
|
141
|
+
## Security
|
|
142
|
+
|
|
143
|
+
- Never commit, log, or serialize API keys.
|
|
144
|
+
- Generated clients are server-side only. Do not expose `OPENROUTER_API_KEY`
|
|
145
|
+
through browser bundles or frontend environment prefixes such as `VITE_` or
|
|
146
|
+
`NEXT_PUBLIC_`.
|
|
147
|
+
- Diagnostics redact Authorization headers, API keys, URL secrets, and request
|
|
148
|
+
bodies.
|
|
149
|
+
- TLS verification is not disabled.
|
|
150
|
+
- Telemetry and prompt recording are not added.
|
|
151
|
+
|
|
152
|
+
## Lifecycle
|
|
153
|
+
|
|
154
|
+
After local install, documented commands are:
|
|
155
|
+
|
|
156
|
+
TypeScript: `npm install`, `npm test`, `npm run typecheck`, `npm run build`,
|
|
157
|
+
`npm run smoke`, `npm start`.
|
|
158
|
+
|
|
159
|
+
Python: create a virtualenv, `python -m pip install -e .`, `python -m compileall .`,
|
|
160
|
+
`python -m unittest discover -s tests`, `python main.py --smoke`, `python main.py`.
|
|
161
|
+
|
|
162
|
+
Workspace Run uses those same manifests and the generated project's declared
|
|
163
|
+
polyglot unit commands. Stage commands, including `&&` chains and a multi-step
|
|
164
|
+
`start`, run as argv. They are not passed to a shell, so an absolute interpreter
|
|
165
|
+
path cannot be expanded by `/bin/sh`. `test` and `--smoke` inject a fake
|
|
166
|
+
transport. They do not require a live `OPENROUTER_API_KEY`.
|
|
167
|
+
|
|
168
|
+
Streaming uses the official Client SDK event stream. Opening and iterating the
|
|
169
|
+
stream are both normalized: configuration errors stay configuration errors,
|
|
170
|
+
timeouts and caller aborts stay recognizable, and other failures become
|
|
171
|
+
`GatewayUpstreamError` with redacted messages and preserved status / request id /
|
|
172
|
+
retry-after when the SDK exposes them. Cleanup is once-only and prefers, in
|
|
173
|
+
order: async iterator `return()` / generator `close()`, then SDK `close()`, then
|
|
174
|
+
SDK `cancel()`. A cleanup failure does not replace the primary error or convert
|
|
175
|
+
a successful completion into an error.
|
|
176
|
+
|
|
177
|
+
The TypeScript starter forwards `AbortSignal` through `chat.send` options,
|
|
178
|
+
including an already-aborted signal. Pinned `@openrouter/sdk` `1.3.11`
|
|
179
|
+
`EventStream` extends `ReadableStream` and does not expose a dedicated `close()`.
|
|
180
|
+
Cancellation is `ReadableStream` async-iterator `return()` → `cancel()`. If the
|
|
181
|
+
stream has already errored, `cancel()` may be a no-op; the gateway still drops
|
|
182
|
+
its own reference and remains usable for a later request. The Python starter
|
|
183
|
+
closes the SDK iterator first (`EventStream.generator.close()`), which is the
|
|
184
|
+
consumer `generator.close()` path. Python does not expose `AbortSignal`.
|
|
185
|
+
Application-side retries stay disabled. Timeouts use SDK `timeoutMs` /
|
|
186
|
+
`timeout_ms`. An empty successful completion returns an empty string.
|
|
187
|
+
|
|
188
|
+
Exact pins live in
|
|
189
|
+
[`version-baselines.v1.json`](../src/model-gateways/version-baselines.v1.json).
|
|
190
|
+
Do not copy versions into unrelated files.
|
|
191
|
+
|
|
192
|
+
## Qualification boundary
|
|
193
|
+
|
|
194
|
+
Workspai source readiness is not release qualification. These kits are not
|
|
195
|
+
described as `stable`, `release-ready`, `admitted`, or `qualified` until Linux,
|
|
196
|
+
macOS, and Windows CI prove generated-project installation and lifecycle on the
|
|
197
|
+
same commit SHA, and a later admission change records that evidence. The
|
|
198
|
+
dedicated workflow is `.github/workflows/model-gateway-qualification.yml`.
|
|
199
|
+
Path-triggered runs and manual `full` mode each qualify both the TypeScript and
|
|
200
|
+
Python OpenRouter adapters on Linux, macOS, and Windows. Manual `fast` mode
|
|
201
|
+
stays on Linux. There is no unused kit axis. Discovery is
|
|
202
|
+
`.github/workflows/model-gateway-version-discovery.yml`. Its job summary shows
|
|
203
|
+
the sdk-core candidate diff when registry and GitHub agree. A green job that
|
|
204
|
+
skipped installation or lifecycle is not qualified.
|
|
@@ -15,7 +15,8 @@ CLI, such as Next.js, Astro, Angular, Vue, Svelte, Nuxt, or React Native.
|
|
|
15
15
|
Governed Microsoft Agent Framework and OpenAI Agents SDK kits are versioned
|
|
16
16
|
separately through the
|
|
17
17
|
[Agent Framework Adapter Contract](./agent-framework-adapters.md); they are
|
|
18
|
-
not native HTTP service generators.
|
|
18
|
+
not native HTTP service generators. OpenRouter AI Gateway kits are versioned
|
|
19
|
+
through [AI Gateway](./model-gateways.md) and are not Agent Framework kits.
|
|
19
20
|
|
|
20
21
|
## Current tested baseline
|
|
21
22
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workspai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Open-source workspace intelligence CLI for software systems: create, adopt, govern, verify, and align polyglot workspaces for humans, CI, IDEs, and AI agents.",
|
|
6
6
|
"keywords": [
|
|
@@ -120,6 +120,8 @@
|
|
|
120
120
|
"verify:agent-framework:matrix": "tsx scripts/verify-agent-framework-conformance.ts --reports test-results/agent-framework-conformance",
|
|
121
121
|
"discover:agent-framework:versions": "tsx scripts/discover-agent-framework-versions.ts",
|
|
122
122
|
"propose:agent-framework:versions": "tsx scripts/propose-agent-framework-version-update.ts",
|
|
123
|
+
"discover:model-gateway:versions": "tsx scripts/propose-model-gateway-version-update.ts",
|
|
124
|
+
"propose:model-gateway:versions": "tsx scripts/propose-model-gateway-version-update.ts",
|
|
123
125
|
"promote:agent-framework:admission": "tsx scripts/promote-agent-framework-release-admission.ts",
|
|
124
126
|
"prepush:test:runtime-contract": "node scripts/run-cached-prepush-gate.mjs runtime-contract",
|
|
125
127
|
"test:runtime-matrix:full": "node scripts/runtime-acceptance-matrix.mjs --full",
|
|
@@ -719,10 +719,112 @@ for (const relativePath of [
|
|
|
719
719
|
assertFile(relativePath);
|
|
720
720
|
}
|
|
721
721
|
|
|
722
|
+
function smokeCreateOpenRouterGatewayKits() {
|
|
723
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workspai-gateway-kit-smoke-'));
|
|
724
|
+
const workspaceName = 'gateway-kit-workspace';
|
|
725
|
+
const workspacePath = path.join(tempDir, workspaceName);
|
|
726
|
+
const createWorkspace = spawnSync(
|
|
727
|
+
process.execPath,
|
|
728
|
+
[
|
|
729
|
+
cliPath,
|
|
730
|
+
'create',
|
|
731
|
+
'workspace',
|
|
732
|
+
workspaceName,
|
|
733
|
+
'--output',
|
|
734
|
+
tempDir,
|
|
735
|
+
'--profile',
|
|
736
|
+
'minimal',
|
|
737
|
+
'--skip-python-engine',
|
|
738
|
+
'--skip-git',
|
|
739
|
+
'--yes',
|
|
740
|
+
],
|
|
741
|
+
{ cwd: tempDir, encoding: 'utf8', env: cliEnv(), stdio: ['ignore', 'pipe', 'pipe'] }
|
|
742
|
+
);
|
|
743
|
+
if (createWorkspace.status !== 0) {
|
|
744
|
+
fail(
|
|
745
|
+
`gateway kit workspace creation failed with exit ${createWorkspace.status}\n${createWorkspace.stdout}\n${createWorkspace.stderr}`
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const scenarios = [
|
|
750
|
+
{
|
|
751
|
+
kit: 'gateway.openrouter.typescript',
|
|
752
|
+
name: 'openrouter-ts-gateway',
|
|
753
|
+
expectedFiles: [
|
|
754
|
+
'README.md',
|
|
755
|
+
'.env.example',
|
|
756
|
+
'.gitignore',
|
|
757
|
+
'gateway.policy.json',
|
|
758
|
+
'package.json',
|
|
759
|
+
'tsconfig.json',
|
|
760
|
+
'src/port.ts',
|
|
761
|
+
'src/config.ts',
|
|
762
|
+
'src/openrouter-gateway.ts',
|
|
763
|
+
'src/main.ts',
|
|
764
|
+
'tests/gateway.test.ts',
|
|
765
|
+
'.workspai/project.json',
|
|
766
|
+
],
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
kit: 'gateway.openrouter.python',
|
|
770
|
+
name: 'openrouter-py-gateway',
|
|
771
|
+
expectedFiles: [
|
|
772
|
+
'README.md',
|
|
773
|
+
'.env.example',
|
|
774
|
+
'.gitignore',
|
|
775
|
+
'gateway.policy.json',
|
|
776
|
+
'pyproject.toml',
|
|
777
|
+
'main.py',
|
|
778
|
+
'src/model_gateway/port.py',
|
|
779
|
+
'src/model_gateway/config.py',
|
|
780
|
+
'src/model_gateway/gateway.py',
|
|
781
|
+
'src/model_gateway/main.py',
|
|
782
|
+
'tests/test_gateway.py',
|
|
783
|
+
'.workspai/project.json',
|
|
784
|
+
],
|
|
785
|
+
},
|
|
786
|
+
];
|
|
787
|
+
try {
|
|
788
|
+
for (const scenario of scenarios) {
|
|
789
|
+
const result = spawnSync(
|
|
790
|
+
process.execPath,
|
|
791
|
+
[cliPath, 'create', 'project', scenario.kit, scenario.name, '--skip-git', '--yes'],
|
|
792
|
+
{
|
|
793
|
+
cwd: workspacePath,
|
|
794
|
+
encoding: 'utf8',
|
|
795
|
+
env: cliEnv(),
|
|
796
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
if (result.status !== 0) {
|
|
800
|
+
fail(
|
|
801
|
+
`${scenario.kit} create failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
const combined = `${result.stdout}\n${result.stderr}`;
|
|
805
|
+
if (/openrouter\.ai|chat\.completions|Authorization: Bearer/i.test(combined)) {
|
|
806
|
+
fail(`${scenario.kit} create output looks like a live model call\n${combined}`);
|
|
807
|
+
}
|
|
808
|
+
assertGeneratedProject(path.join(workspacePath, scenario.name), scenario.expectedFiles);
|
|
809
|
+
const envExample = fs.readFileSync(
|
|
810
|
+
path.join(workspacePath, scenario.name, '.env.example'),
|
|
811
|
+
'utf8'
|
|
812
|
+
);
|
|
813
|
+
if (/sk-or-[A-Za-z0-9]/.test(envExample) || /OPENROUTER_API_KEY=.+/.test(envExample)) {
|
|
814
|
+
fail(`${scenario.kit} .env.example must not contain a credential value`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
log(`verified ${scenarios.length} model gateway create scenarios`);
|
|
818
|
+
} finally {
|
|
819
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
722
823
|
assertPackContents();
|
|
723
824
|
assertCliContracts();
|
|
724
825
|
smokeCreateNpmBackedKits();
|
|
725
826
|
smokeCreateAgentFrameworkKits();
|
|
827
|
+
smokeCreateOpenRouterGatewayKits();
|
|
726
828
|
smokeCreateOfflineFallbackKits();
|
|
727
829
|
|
|
728
830
|
log('enterprise package smoke passed');
|
package/dist/analyze-QVRVJB7I.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{b as printAnalyzeReport,a as runAnalyze}from'./chunk-Z2M2XCIB.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{b as AUTOPILOT_RELEASE_ALIAS_FILENAME,a as AUTOPILOT_RELEASE_LAST_RUN_FILENAME,c as runAutopilotRelease}from'./chunk-L6VNI4DN.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{b as runDoctorCapabilities}from'./chunk-4R44E7HN.js';
|
package/dist/chunk-4R44E7HN.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import {a}from'./chunk-NS53IPAC.js';import {a as a$1}from'./chunk-SVO2GGTV.js';import {h as h$1}from'./chunk-BLEIUQL6.js';import {s,b,a as a$2,d,c}from'./chunk-ODK4LCEL.js';import pe from'path';import h from'chalk';import {createHash}from'crypto';var F="workspai.doctor-adapter.v1",D=["runtime","dependency","security","configuration","test","quality"];function A(e){return e.trim().toLowerCase().replace(/[^a-z0-9+.#-]+/g,"-")}function ae(e){if(e.contractVersion!==F)throw new Error(`Unsupported Doctor adapter contract: ${e.contractVersion}`);if(!e.id.trim())throw new Error("Doctor adapter id must not be empty.");if(e.runtimeFamilies.length===0)throw new Error(`Doctor adapter ${e.id} must own at least one runtime family.`);if(e.platforms.length===0)throw new Error(`Doctor adapter ${e.id} must declare supported platforms.`);let i=e.domains.map(t=>t.domain);if(i.length!==D.length||new Set(i).size!==D.length||D.some(t=>!i.includes(t)))throw new Error(`Doctor adapter ${e.id} must declare every canonical diagnostic domain exactly once.`);for(let t of e.domains)if(t.level==="unsupported"&&t.limitations.length===0)throw new Error(`Doctor adapter ${e.id} must explain unsupported ${t.domain} coverage.`)}var $=class{#e=new Map;#i=new Map;#t=new Map;register(i){ae(i);let t=A(i.id);if(this.#e.has(t))throw new Error(`Doctor adapter id is already registered: ${i.id}`);let s=[...i.runtimeFamilies,...i.aliases].map(A);for(let c of s){let a=this.#i.get(c);if(a)throw new Error(`Doctor runtime ${c} is already owned by adapter ${a}.`)}for(let c of i.frameworks.map(A)){let a=this.#t.get(c);if(a)throw new Error(`Doctor framework ${c} is already owned by adapter ${a}.`)}let r=structuredClone(i);this.#e.set(t,r);for(let c of s)this.#i.set(c,t);for(let c of i.frameworks.map(A))this.#t.set(c,t);return this}resolveWithDiagnostics(i){let t=i.runtimeFamily?this.#i.get(A(i.runtimeFamily)):void 0,s=i.framework?this.#t.get(A(i.framework)):void 0;if(t&&s&&t!==s)return {status:"conflict",descriptor:null,runtimeOwner:t,frameworkOwner:s};let r=t??s;return {status:r?"matched":"unresolved",descriptor:r?structuredClone(this.#e.get(r)??null):null,...t?{runtimeOwner:t}:{},...s?{frameworkOwner:s}:{}}}resolve(i){return this.resolveWithDiagnostics(i).descriptor}list(){return [...this.#e.values()].map(i=>structuredClone(i)).sort((i,t)=>i.id.localeCompare(t.id))}};var Y=[...D],W=["linux","darwin","win32"],re=[{id:"node",aliases:["nodejs","javascript","typescript"],frameworks:["NestJS","Next.js","Remix","Nuxt","React","Vue","Angular","SvelteKit","Svelte","Vite","Astro","Solid","Express","Fastify","Koa","Electron","VS Code Extension"],tier:"first-class",native:Y},{id:"python",aliases:["py"],frameworks:["FastAPI","Django","Flask","Python"],tier:"first-class",native:Y},{id:"go",aliases:["golang"],frameworks:["Go","Go/Fiber","Go/Gin","Echo"],tier:"first-class",native:["runtime","dependency","test","quality"],portable:["security","configuration"]},{id:"java",aliases:["jvm"],frameworks:["Java","Spring Boot"],tier:"first-class",native:["runtime","dependency","test","quality"],portable:["security","configuration"]},{id:"dotnet",aliases:[".net","csharp","c#"],frameworks:["ASP.NET"],tier:"first-class",native:["runtime","dependency","test","quality"],portable:["security","configuration"]},{id:"rust",aliases:["cargo"],frameworks:["Rust","Axum"],tier:"first-class",native:["runtime","dependency","test","quality"],portable:["security","configuration"]},{id:"php",aliases:["composer"],frameworks:["PHP","Laravel"],tier:"first-class",native:["runtime","dependency","security"],portable:["configuration","test","quality"]},{id:"ruby",aliases:["bundler"],frameworks:["Ruby","Ruby on Rails"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"elixir",aliases:["beam"],frameworks:["Elixir","Phoenix"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"clojure",frameworks:["Clojure"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"deno",frameworks:["Deno"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"bun",frameworks:["Bun"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"scala",frameworks:["Scala"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"kotlin",frameworks:["Kotlin"],tier:"extended",portable:["runtime","dependency","configuration","test","quality"],observable:["security"]},{id:"c",aliases:["c-lang"],frameworks:["C"],tier:"extended",portable:["runtime","dependency","test","quality"],observable:["configuration"],limitations:["Security diagnosis requires a declared native scanner or workspace adapter."]},{id:"cpp",aliases:["c++","cplusplus"],frameworks:["C++"],tier:"extended",portable:["runtime","dependency","test","quality"],observable:["configuration"],limitations:["Security diagnosis requires a declared native scanner or workspace adapter."]}];function oe(e,i){let t={runtime:["project markers","entrypoints","toolchain evidence"],dependency:["dependency manifests","lockfiles","installed-tree evidence"],security:["runtime-native audit","advisory evidence"],configuration:["environment contracts","deployment/container markers"],test:["test scripts","test configuration","coverage evidence"],quality:["lint/format/static-analysis contracts"]};return [`${e} adapter`,...t[i]]}function ce(e,i){return e.native?.includes(i)?"native":e.portable?.includes(i)?"portable":e.observable?.includes(i)?"observable":"unsupported"}function le(e){let i=D.map(t=>{let s=ce(e,t);return {domain:t,level:s,evidenceSources:s==="unsupported"?[]:oe(e.id,t),limitations:s==="unsupported"?[`${e.id} has no built-in ${t} provider; declare a workspace adapter.`]:s==="observable"?[`${t} evidence is observable but not runtime-native for ${e.id}.`]:[]}});return {contractVersion:F,id:`builtin.${e.id}`,runtimeFamilies:[e.id],aliases:e.aliases??[],frameworks:e.frameworks,projectKinds:["backend","frontend","desktop","extension","fullstack","generic"],tier:e.tier,platforms:[...W],domains:i,repairModes:["typed-operation","structured-invocation","manual-guidance"],source:"builtin",limitations:e.limitations??[]}}function de(){return {contractVersion:F,id:"builtin.unknown",runtimeFamilies:["unknown"],aliases:["generic","unrecognized"],frameworks:["Unknown"],projectKinds:["backend","frontend","desktop","extension","fullstack","generic"],tier:"fallback",platforms:[...W],domains:D.map(e=>({domain:e,level:e==="security"?"unsupported":"observable",evidenceSources:e==="security"?[]:["portable workspace markers","declared custom checks"],limitations:[e==="security"?"No safe security claim is possible without a runtime-native audit provider.":`Only portable ${e} evidence is available until a runtime adapter is registered.`]})),repairModes:["manual-guidance"],source:"builtin",limitations:["Unknown runtimes are fail-closed: missing domain evidence is reported as unknown, never healthy.","Automatic repair is unavailable until a typed adapter owns the runtime."]}}function P(){let e=new $;for(let i of re)e.register(le(i));return e.register(de()),e}function J(e,i=P()){let t=i.resolveWithDiagnostics(e),s=t.descriptor??i.resolve({runtimeFamily:"unknown"});if(!s)throw new Error("Doctor fallback adapter is not registered.");let r=c=>s.domains.filter(a=>a.level===c).map(a=>a.domain);return {registryVersion:b,adapterId:s.id,runtimeFamily:s.runtimeFamilies[0]??"unknown",tier:s.tier,confidence:s.tier==="first-class"?"high":s.tier==="extended"?"medium":"low",nativeDomains:r("native"),portableDomains:r("portable"),observableDomains:r("observable"),unsupportedDomains:r("unsupported"),limitations:[...t.status==="conflict"?[`Runtime/framework ownership conflict (${t.runtimeOwner} vs ${t.frameworkOwner}); Doctor failed closed instead of selecting an ambiguous adapter.`]:[],...s.limitations,...s.domains.flatMap(c=>c.limitations)]}}function K(e={}){let i=P(),t=i.list(),s=i.resolveWithDiagnostics({runtimeFamily:e.runtime,framework:e.framework}),r=e.runtime||e.framework?[s.descriptor]:t;if((e.runtime||e.framework)&&!r[0]){let a=i.resolve({runtimeFamily:"unknown"});a&&(s.status==="conflict"&&a.limitations.unshift(`Runtime/framework ownership conflict (${s.runtimeOwner} vs ${s.frameworkOwner}); Doctor failed closed instead of selecting an ambiguous adapter.`),r[0]=a);}let c=r.filter(a=>!!a);return {schemaVersion:a$2,registryVersion:b,generatedBy:"workspai",policy:{unknownIsHealthy:false,unsupportedIsHealthy:false,repairRequiresTypedOperation:true,canonicalDomains:[...D]},summary:{adapterCount:c.length,firstClassRuntimes:c.filter(a=>a.tier==="first-class").length,extendedRuntimes:c.filter(a=>a.tier==="extended").length,fallbackRuntimes:c.filter(a=>a.tier==="fallback").length,frameworkCount:new Set(c.flatMap(a=>a.frameworks)).size,platformCount:new Set(c.flatMap(a=>a.platforms)).size},adapters:c}}var me=["runtime","dependency","security","configuration","test","quality"];function I(e){return createHash("sha256").update(e).digest("hex").slice(0,12)}function S(e){return e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}function Q(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g," ").replace(/\s+/g," ").trim()}function ge(e,i){let t=Q(e);return t?i.some(s=>[s.reason,s.recommendation??""].map(Q).filter(Boolean).some(c=>c===t||c.includes(t)||t.includes(c))):true}function fe(e){return e.status==="fail"?"blocking":e.status==="warn"?"advisory":"informational"}function X(e){return e.issueClass==="dependency"?"dependency":e.issueClass==="security"?"security":e.issueClass==="environment"||e.issueClass==="configuration"||e.issueClass==="container"||e.issueClass==="deployment"||e.issueClass==="workspace-contract"?"configuration":e.issueClass==="test"?"test":e.issueClass==="quality"||e.issueClass==="custom"?"quality":e.issueClass==="runtime"||e.issueClass==="framework"||e.issueClass==="source-tree"?"runtime":null}function ye(e,i){return me.map(t=>{let s=e.filter(o=>X(o)===t),r=e.filter(o=>o.applicability!=="not-applicable"&&X(o)===t),c=i.unsupportedDomains.includes(t);if(r.length===0){let o=s.some(d=>d.applicability==="not-applicable");return {id:t,status:o?"not-applicable":"not-run",observationCount:0,blockingFindings:0,advisoryFindings:0,reason:o?`${t} checks ran and found no declared intent requiring this domain.`:c?`${t} is unsupported by Doctor adapter ${i.adapterId}; no healthy claim is allowed.`:`No ${t} diagnostic observation was produced.`}}let a=r.some(o=>o.freshness?.status==="stale"||o.freshness?.status==="unknown"),p=r.filter(o=>o.status==="fail").length,m=r.filter(o=>o.status==="warn").length,C=p>0||m>0;return {id:t,status:a?"stale":C?"findings":c?"not-run":"clean",observationCount:r.length,blockingFindings:p,advisoryFindings:m,reason:a?`${t} evidence is stale or has unknown freshness.`:C?`${t} diagnostics produced findings.`:c?`${t} observations cannot establish complete health because adapter ${i.adapterId} declares the domain unsupported.`:`${t} diagnostics completed without findings.`}})}function De(e){if(e.status==="pass")return "not-needed";let i=e.repairCapability;return i?i.status==="manual"||i.requiresReview?"manual":i.status!=="available"||!i.canAutoFix?"unavailable":i.requiresApproval?"approval-required":"automatic":"unavailable"}function be(e){if(e.freshness?.status==="stale"||e.freshness?.status==="unknown")return {label:"low",score:.35,state:"unknown"};let i=!!(e.issueClass&&e.issueClass!=="unknown"),t=!!(e.repairCapability?.operation?.type||e.repairCapability?.invocation?.executable);return i&&t&&e.repairIntent?.confidence==="high"?{label:"high",score:.95,state:"confirmed"}:i&&(e.status==="fail"||e.status==="warn")?{label:"medium",score:t?.82:.68,state:"candidate"}:e.status==="pass"?{label:"high",score:.98,state:"confirmed"}:{label:"low",score:.3,state:"unknown"}}function ve(e,i){let t=[{kind:"probe",role:"observation",ref:`probe:${e.id}`,claim:e.reason}];for(let r of e.repairCapability?.files??[])t.push({kind:"file",role:"repair-target",ref:r.split(pe.sep).join("/"),claim:"Structured repair capability declared this path as an affected target."});if(e.repairCapability?.invocation?.executable){let r=e.repairCapability.invocation;t.push({kind:"command",role:"verification",ref:[r.executable,...r.args??[]].join(" "),claim:"Structured command invocation is available for this diagnostic path."});}if(e.issueClass==="security"&&/(?:dependency|audit|vulnerab|security-hygiene)/i.test(`${e.id} ${e.label}`))for(let r of i??[])t.push({kind:"dependency",role:"subject",ref:r.version?`${r.name}@${r.version}`:r.name,claim:r.advisoryIds&&r.advisoryIds.length>0?`Dependency is referenced by ${r.advisoryIds.join(", ")}.`:"Dependency is present in security audit evidence."});return t}function we(e,i){let t=i.issueClass?.trim()||"unknown",s=be(i);return {id:`${S(i.id)}:${I(`${e.projectPath}\0${i.id}`)}`,causalKey:[S(e.projectName),I(e.projectPath),S(t),S(i.id)].join(":"),projectName:e.projectName,projectPath:e.projectPath,probeId:i.id,label:i.label,status:fe(i),severity:i.severity,issueClass:t,operationalImpact:i.operationalImpact?.trim()||"developer-friction",applicability:i.applicability??"applicable",confidence:s.label,confidenceScore:s.score,diagnosisState:s.state,symptom:i.reason,...i.recommendation?{recommendation:i.recommendation}:{},proofs:ve(i,e.dependencySubjects),repair:{disposition:De(i),...i.repairCapability?.id?{capabilityId:i.repairCapability.id}:{},...i.repairCapability?.operation?.type?{operationType:i.repairCapability.operation.type}:{},...i.repairCapability?.verifyCommand?{verifyCommand:i.repairCapability.verifyCommand}:{},requiresFreshEvidence:i.repairIntent?.requiresFreshEvidence===true||i.freshness?.verifyBeforeUse===true}}}function he(e,i,t){let s=`legacy-runtime-issue-${t+1}`;return {id:`${s}:${I(`${e.projectPath}\0${i}`)}`,causalKey:[S(e.projectName),I(e.projectPath),"unknown",I(i)].join(":"),projectName:e.projectName,projectPath:e.projectPath,probeId:s,label:"Runtime diagnostic issue",status:"blocking",severity:"error",issueClass:"unknown",operationalImpact:"runtime-risk",applicability:"applicable",confidence:"low",confidenceScore:.25,diagnosisState:"unknown",symptom:i,proofs:[{kind:"unknown",role:"observation",ref:`legacy-issue:${t+1}`,claim:i}],repair:{disposition:"unavailable",requiresFreshEvidence:true}}}function Z(e){let i=[...e.probes],t=[...new Set((e.runtimeFamilies&&e.runtimeFamilies.length>0?e.runtimeFamilies:[e.runtimeFamily??"unknown"]).filter(Boolean))],s=e.runtimeFamily??t[0]??"unknown",r=t.filter(n=>n!==s&&n!=="unknown"),c=J({runtimeFamily:e.runtimeFamily,framework:e.framework},e.adapterRegistry),a$1=ye(i,c),p=(e.legacyIssues??[]).filter(n=>!ge(n,i)),m=new Map;for(let n of i){let l=m.get(n.id)??new Set;l.add(n.status),m.set(n.id,l);}let C=[...m.entries()].filter(([,n])=>n.size>1).map(([n,l])=>({probeId:n,statuses:[...l].sort(),reason:"The same diagnostic probe produced contradictory states in one project scan."})),o=[...i.filter(n=>n.applicability!=="not-applicable"&&n.status!=="pass").map(n=>we(e,n)),...p.map((n,l)=>he(e,n,l))],d={blocking:4,unknown:3,advisory:2,informational:1},O=new Map;for(let n of o){let l=O.get(n.causalKey)??[];l.push(n),O.set(n.causalKey,l);}let g=[...O.values()].map(n=>{let u=[...n].sort((f,j)=>d[j.status]-d[f.status]||j.confidenceScore-f.confidenceScore||f.id.localeCompare(j.id)).at(0);if(!u)throw new Error("Doctor diagnosis causal group cannot be empty.");let G=structuredClone(u);return G.proofs=[...new Map(n.flatMap(f=>f.proofs).map(f=>[`${f.kind}:${f.role}:${f.ref}:${f.claim}`,f])).values()],G}).sort((n,l)=>n.causalKey.localeCompare(l.causalKey)||n.id.localeCompare(l.id)),k=new Map;for(let n of g){let l=k.get(n.causalKey)??[];l.push(n),k.set(n.causalKey,l);}let b=[...k.entries()].map(([n,l])=>({causalKey:n,issueClass:l[0]?.issueClass??"unknown",status:l.some(u=>u.status==="blocking")?"blocking":l.some(u=>u.status==="advisory")?"advisory":l.some(u=>u.status==="unknown")?"unknown":"informational",findingIds:l.map(u=>u.id),projectPaths:[...new Set(l.map(u=>u.projectPath))],repairable:l.some(u=>u.repair.disposition==="automatic"||u.repair.disposition==="approval-required")})),v=[...g.filter(n=>n.diagnosisState==="unknown"||n.issueClass==="unknown"||n.applicability==="unknown").map(n=>({id:`unknown:${n.id}`,probeId:n.probeId,reason:n.issueClass==="unknown"?"The observation is real, but Doctor cannot yet bind it to a typed issue class.":"Evidence is insufficient or stale for a confirmed diagnosis."})),...a$1.filter(n=>n.status==="not-run"||n.status==="stale").map(n=>({id:`unknown:domain:${n.id}:${I(e.projectPath)}`,reason:n.reason})),...r.map(n=>({id:`unknown:runtime:${S(n)}:${I(e.projectPath)}`,reason:e.projectArchetype==="platform"?`${n} is part of this cross-language platform, but only portable evidence and the primary ${s} runtime adapter were evaluated. Add a typed ${n} adapter before making runtime-specific health claims.`:`${n} was detected inside this composite project boundary, but the ${s} adapter is the only runtime-specific adapter evaluated for this scan. Declare a nested project boundary or a typed Doctor adapter before treating ${n} as healthy.`}))],y=g.filter(n=>n.diagnosisState!=="unknown").length,x=g.length===0?100:y/g.length*100,ie=a$1.filter(n=>n.status!=="not-run"&&n.status!=="stale").length/a$1.length*100,U=t.filter(n=>n!=="unknown").length,te=s!=="unknown"&&t.includes(s)?1:0,ne=U===0?0:te/U*100,se=Math.round(Math.min(x,ie,ne)*100)/100;return {schemaVersion:a,engineVersion:"universal-diagnosis-v1",project:{name:e.projectName,path:e.projectPath,runtimeFamily:e.runtimeFamily??"unknown",runtimeFamilies:t,framework:e.framework??"Unknown",projectKind:e.projectKind??"generic"},capability:c,domains:a$1,coverage:{totalObservations:i.length+p.length,evaluatedObservations:i.filter(n=>n.applicability!=="not-applicable").length,passingObservations:i.filter(n=>n.applicability!=="not-applicable"&&n.status==="pass").length,blockingFindings:g.filter(n=>n.status==="blocking").length,advisoryFindings:g.filter(n=>n.status==="advisory").length,unknownFindings:v.length,repairableFindings:g.filter(n=>n.repair.disposition==="automatic"||n.repair.disposition==="approval-required").length,manualFindings:g.filter(n=>n.repair.disposition==="manual").length,unsupportedFindings:g.filter(n=>n.repair.disposition==="unavailable").length,contradictionCount:C.length,diagnosisCompleteness:se},findings:g,causalGroups:b,unknowns:v,contradictions:C}}function w(e){let i=e.severity??"error",t=e.repair??"unavailable";return {id:e.id,label:e.label,status:i==="error"?"fail":"warn",severity:i,reason:`${e.label} detected by the validation corpus.`,issueClass:e.issueClass,operationalImpact:i==="error"?"release-risk":"ci-risk",repairIntent:{confidence:e.confidence??"medium",requiresFreshEvidence:true},...t==="unavailable"?{}:{repairCapability:{id:`repair.${e.id}`,status:t==="manual"?"manual":"available",canAutoFix:t==="automatic"||t==="approval-required",requiresApproval:t==="approval-required",requiresReview:t==="manual",operation:{type:"validation-operation"},verifyCommand:"npx workspai doctor project --json"}}}}var Ce=[{id:"runtime-missing",diseaseClass:"runtime",description:"Required runtime is absent.",probe:w({id:"runtime-missing",label:"Runtime missing",issueClass:"runtime"}),expected:{finding:true,domain:"runtime",status:"blocking",diagnosisState:"candidate",repairDisposition:"unavailable"}},{id:"dependencies-missing",diseaseClass:"dependency",description:"Installed dependency tree is absent.",probe:w({id:"dependencies-missing",label:"Dependencies missing",issueClass:"dependency",repair:"automatic",confidence:"high"}),expected:{finding:true,domain:"dependency",status:"blocking",diagnosisState:"confirmed",repairDisposition:"automatic"}},{id:"security-advisory",diseaseClass:"security",description:"A runtime-native audit reports a blocking advisory.",probe:w({id:"security-advisory",label:"Security advisory",issueClass:"security",repair:"approval-required",confidence:"high"}),expected:{finding:true,domain:"security",status:"blocking",diagnosisState:"confirmed",repairDisposition:"approval-required"}},{id:"environment-contract",diseaseClass:"configuration",description:"Environment/configuration contract is incomplete.",probe:w({id:"environment-contract",label:"Environment contract incomplete",issueClass:"environment",severity:"warn",repair:"manual"}),expected:{finding:true,domain:"configuration",status:"advisory",diagnosisState:"candidate",repairDisposition:"manual"}},{id:"container-contract",diseaseClass:"configuration",description:"Container delivery contract is incomplete.",probe:w({id:"container-contract",label:"Container contract incomplete",issueClass:"container",severity:"warn"}),expected:{finding:true,domain:"configuration",status:"advisory",diagnosisState:"candidate",repairDisposition:"unavailable"}},{id:"tests-missing",diseaseClass:"test",description:"No deterministic test surface is declared.",probe:w({id:"tests-missing",label:"Tests missing",issueClass:"test",severity:"warn",repair:"manual"}),expected:{finding:true,domain:"test",status:"advisory",diagnosisState:"candidate",repairDisposition:"manual"}},{id:"quality-missing",diseaseClass:"quality",description:"No lint/format/static-analysis surface is declared.",probe:w({id:"quality-missing",label:"Quality tooling missing",issueClass:"quality",severity:"warn"}),expected:{finding:true,domain:"quality",status:"advisory",diagnosisState:"candidate",repairDisposition:"unavailable"}},{id:"stale-evidence",diseaseClass:"freshness",description:"Evidence is stale and must not be treated as confirmed.",probe:{...w({id:"stale-evidence",label:"Stale evidence",issueClass:"security"}),freshness:{status:"stale",verifyBeforeUse:true}},expected:{finding:true,domain:"security",status:"blocking",diagnosisState:"unknown",repairDisposition:"unavailable"}},{id:"unknown-disease",diseaseClass:"unknown",description:"A real symptom cannot be bound to a typed disease class.",probe:w({id:"unknown-disease",label:"Unknown disease",issueClass:"unknown"}),expected:{finding:true,status:"blocking",diagnosisState:"unknown",repairDisposition:"unavailable"}},{id:"healthy-runtime",diseaseClass:"healthy-control",description:"Healthy evidence must not become a finding.",probe:{id:"healthy-runtime",label:"Healthy runtime",status:"pass",severity:"info",reason:"Runtime evidence is healthy.",issueClass:"runtime",operationalImpact:"none"},expected:{finding:false,domain:"runtime"}}];function _(e){return Math.round(e*1e4)/1e4}function ee(){let i=P().list(),t=i.flatMap(o=>Ce.map(d=>{let O=o.runtimeFamilies[0]??"unknown",g=o.frameworks[0]??"Unknown",k=Z({projectName:`validation-${o.id}-${d.id}`,projectPath:`/virtual/doctor-validation/${o.id}/${d.id}`,runtimeFamily:O,framework:g,projectKind:"generic",probes:[d.probe]}),b=k.findings.find(x=>x.probeId===d.probe.id),N=k.domains.find(x=>x.observationCount>0)?.id,v={finding:!!b,...N?{domain:N}:{},...b?.status?{status:b.status}:{},...b?.diagnosisState?{diagnosisState:b.diagnosisState}:{},...b?.repair.disposition?{repairDisposition:b.repair.disposition}:{}},y=[];return v.finding!==d.expected.finding&&y.push("finding-presence"),d.expected.domain&&v.domain!==d.expected.domain&&y.push("domain"),d.expected.status&&v.status!==d.expected.status&&y.push("status"),d.expected.diagnosisState&&v.diagnosisState!==d.expected.diagnosisState&&y.push("diagnosis-state"),d.expected.repairDisposition&&v.repairDisposition!==d.expected.repairDisposition&&y.push("repair-disposition"),k.capability.adapterId!==o.id&&y.push("adapter-binding"),{id:`${o.id}:${d.id}`,passed:y.length===0,expected:d.expected,actual:v,failures:y}})),s=t.filter(o=>o.expected.finding),r=t.filter(o=>!o.expected.finding),c$1=s.filter(o=>o.actual.finding).length,a=s.length-c$1,p=r.filter(o=>!o.actual.finding).length,m=r.length-p,C=new Set(t.map(o=>o.actual.domain).filter(o=>!!o));return {schemaVersion:c,corpusVersion:d,capabilityRegistryVersion:b,scope:"synthetic-contract-corpus",summary:{totalCases:t.length,passedCases:t.filter(o=>o.passed).length,failedCases:t.filter(o=>!o.passed).length,truePositives:c$1,trueNegatives:p,falsePositives:m,falseNegatives:a,precision:_(c$1/Math.max(1,c$1+m)),recall:_(c$1/Math.max(1,c$1+a)),domainCoverage:_(C.size/D.length),runtimeAdapterCoverage:_(new Set(t.map(o=>o.id.split(":",1)[0])).size/Math.max(1,i.length)),runtimeAdaptersExercised:i.length,declaredPlatforms:new Set(i.flatMap(o=>o.platforms)).size},cases:t,limitations:["Precision and recall describe the versioned synthetic contract corpus, not every public repository.","Every registered runtime adapter is exercised against the same disease corpus; this proves contract behavior, not tool availability on a host.","Runtime-native fixture and real Linux, macOS, and Windows acceptance gates remain separate evidence surfaces."]}}async function Qe(e={}){let i=K({runtime:e.runtime,framework:e.framework}),t=e.validate?ee():void 0,s$1,r;if(e.write){let a=e.workspace?pe.resolve(e.workspace):a$1(process.cwd());if(!a)return e.json?console.log(JSON.stringify({schemaVersion:i.schemaVersion,status:"error",error:{code:"doctor.capabilities.workspace-not-found",message:"--write requires a Workspai workspace or --workspace <path>."}},null,2)):console.log(h.red("Doctor capabilities could not be written: no workspace found.")),1;let p=K();s$1=await h$1(a,s.doctorCapabilities.artifactPath,p),t&&(r=await h$1(a,s.doctorValidation.artifactPath,t));}let c={...i,...t?{validation:t}:{},...s$1?{artifactPath:s$1}:{},...r?{validationArtifactPath:r}:{}};if(e.json)e.quiet||console.log(JSON.stringify(c,null,2));else if(!e.quiet){console.log(h.bold.cyan(`
|
|
2
|
-
\u{1FA7A} Workspai Doctor capabilities
|
|
3
|
-
`)),console.log(`${i.summary.adapterCount} adapter(s) \xB7 ${i.summary.frameworkCount} framework mapping(s) \xB7 ${i.summary.platformCount} platform(s)`);for(let a of i.adapters){let p=a.domains.map(m=>`${m.domain}:${m.level}`).join(" \xB7 ");console.log(h.bold(`
|
|
4
|
-
${a.runtimeFamilies.join(", ")} \xB7 ${a.tier}`)),console.log(h.gray(p));for(let m of a.limitations)console.log(h.yellow(` ! ${m}`));}if(t){let a=t.summary,p=a.failedCases===0?h.green:h.red;console.log(p(`
|
|
5
|
-
Validation ${a.passedCases}/${a.totalCases} \xB7 precision ${a.precision} \xB7 recall ${a.recall}`));}s$1&&console.log(h.gray(`
|
|
6
|
-
Capabilities: ${s$1}`)),r&&console.log(h.gray(`Validation: ${r}`));}return t&&t.summary.failedCases>0?1:0}export{Z as a,Qe as b};
|
package/dist/chunk-5S6IZ6PY.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import {b as b$1}from'./chunk-B6FJ6RG6.js';import {k as k$1,q as q$1,G as G$1,I}from'./chunk-QFDTKOYS.js';import {c}from'./chunk-TJ3MDZMC.js';import {e,f}from'./chunk-EFHSRPW7.js';import {b}from'./chunk-UJXE4UAX.js';import {m,l}from'./chunk-VQZ5PI5J.js';import {promises}from'fs';import c$1 from'path';import $,{homedir}from'os';import {pathToFileURL}from'url';import u from'process';import Y from'fs-extra';var g=["backend","frontend","desktop","agent","extension","gaming"],R=[{id:"backend",label:"Backend",hint:"APIs and services"},{id:"frontend",label:"Frontend",hint:"Web applications"},{id:"desktop",label:"Desktop",hint:"Native desktop applications"},{id:"agent",label:"AI Agent",hint:"Governed agent runtimes"},{id:"extension",label:"Extension",hint:"Editor and platform extensions"},{id:"gaming",label:"Gaming",hint:"Game runtimes and tooling"}];function L(e){let o=e.label.indexOf(" \u2014 ");return o>=0?e.label.slice(o+3).trim():e.label.trim()}function G(e){return g.includes(e.category)?e.category:null}function A(e){let t=c().flatMap(r=>{let s=G(r);return s?[{value:r.id,label:`${W(s)} \xB7 ${L(r)}`,hint:`${r.runtime} \xB7 tested baseline`,name:r.label,category:s}]:[]}),o=k$1().map(r=>({value:r.kitId,label:`Frontend \xB7 ${r.displayName}`,hint:"official \xB7 latest stable",name:`${r.displayName} \u2014 ${r.framework}`,category:"frontend"})),n=q$1().map(r=>({value:r.kitId,label:`${W(r.category)} \xB7 ${r.displayName}`,hint:`${r.runtimeCandidates.join(" + ")} \xB7 official latest stable`,name:`${r.displayName} \u2014 ${r.category}`,category:r.category})),i=G$1().map(r=>({value:r.id,label:`AI Agent \xB7 ${r.label}`,hint:`${r.runtime} \xB7 ${I(r)?"release-admitted baseline":"published baseline"}`,name:r.label,category:"agent"})),a=[...t,...o,...n,...i].filter(r=>!e||r.category===e).sort((r,s)=>{let p=g.indexOf(r.category),D=g.indexOf(s.category);return p-D||(r.label??"").localeCompare(s.label??"")});return F(a),a}function oe(){let e=new Set(A().map(t=>t.category));return R.filter(t=>e.has(t.id)).map(t=>({value:t.id,label:t.label,hint:t.hint}))}function W(e){return e.charAt(0).toUpperCase()+e.slice(1)}function F(e){let t=new Set,o=new Set;for(let n of e){let i=n.label??n.name??String(n.value),a=String(n.value);if(t.has(i))throw new Error(`Duplicate kit picker label: ${i}`);if(o.has(a))throw new Error(`Duplicate kit picker value: ${a}`);t.add(i),o.add(a);}}var O=".workspairc.json",M=".rapidkitrc.json",V=["workspai.config.js","workspai.config.mjs","workspai.config.cjs","rapidkit.config.js","rapidkit.config.mjs","rapidkit.config.cjs"],J=["workspai.config.json","rapidkit.config.json"];function S(e){return typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT"}function y(e,t){let o=t instanceof Error?t.message:String(t),n=e.endsWith(".js")&&/module is not defined in ES module scope/i.test(o)?' CommonJS syntax in a .js config is not valid when the project package uses "type": "module"; rename the file to .cjs or use export default.':"";return `Failed to load Workspai config at ${e}.${n} Cause: ${o}`}async function Se(){for(let e$1 of [c$1.join($.homedir(),O),c$1.join($.homedir(),M)])try{let t=await promises.readFile(e$1,"utf-8"),o=JSON.parse(t);return e.debug(`Loaded config from ${e$1}`),o}catch{}return e.debug("No user config found, using defaults"),{}}async function Te(e$1=process.cwd(),t={}){let o=e$1,n=c$1.parse(o).root;for(;o!==n;){for(let i of J){let a=c$1.join(o,i);try{let r=await promises.readFile(a,"utf-8"),s=JSON.parse(r);if(!s||typeof s!="object"||Array.isArray(s))throw new Error("configuration root must be a JSON object");return e.debug(`Loaded data-only Workspai config from ${i}`),s}catch(r){if(S(r))continue;throw new Error(y(a,r))}}for(let i of V){let a=c$1.join(o,i);try{await promises.access(a);}catch(r){if(S(r))continue;throw new Error(y(a,r))}if(e.debug(`Found config file: ${a}`),!t.trustExecutableConfig)throw new Error(`Refusing to execute Workspai config at ${a} without explicit trust. Use a data-only workspai.config.json file, pass --trust-config, or set WORKSPAI_TRUST_CONFIG=1.`);try{let s=await import(pathToFileURL(a).href),p=s.default||s;return e.debug(`Loaded Workspai config from ${i}`),p}catch(r){throw new Error(y(a,r))}}o=c$1.dirname(o);}return e.debug("No Workspai config file found, using defaults"),{}}function Ne(e,t,o){return {author:o.author||t.workspace?.defaultAuthor||e.author,pythonVersion:o.pythonVersion||t.workspace?.pythonVersion||e.pythonVersion,defaultInstallMethod:o.defaultInstallMethod||t.workspace?.installMethod||e.defaultInstallMethod,defaultKit:o.defaultKit||t.projects?.defaultKit||e.defaultKit,skipGit:o.skipGit??t.projects?.skipGit??e.skipGit,license:o.license||e.license,testRapidKitPath:o.testRapidKitPath||e.testRapidKitPath}}function _e(e){return f("DEV_PATH")||e.testRapidKitPath||void 0}var k=class extends Error{constructor(o,n){super(["Workspai workspaces cannot be nested.",`Target: ${o}`,`Containing workspace: ${n}`,"Choose Managed home or pass --output <path> with a location outside the current workspace."].join(`
|
|
2
|
-
`));this.targetPath=o;this.containingWorkspacePath=n;this.name="NestedWorkspaceCreationError";}targetPath;containingWorkspacePath;code="WORKSPACE_NESTING_NOT_SUPPORTED"};async function B(e){try{return !!await Y.stat(e)}catch{return false}}function H(e,t){let o=e.indexOf(t);if(o>=0&&o+1<e.length)return e[o+1];let n=e.find(i=>i.startsWith(`${t}=`));if(n)return n.slice(t.length+1)}function q(e){return e.includes("--here")}async function N(e){let t=c$1.resolve(e);for(;;){let o=[c$1.join(t,".workspai-workspace"),c$1.join(t,".rapidkit-workspace"),c$1.join(t,".workspai","workspace.json"),c$1.join(t,".rapidkit","workspace.json")];if((await Promise.all(o.map(B))).some(Boolean))return t;let n=c$1.dirname(t);if(n===t)return;t=n;}}async function Ye(e){let t=c$1.resolve(e),o=await N(c$1.dirname(t));if(o)throw new k(t,o)}async function z(e,t=homedir()){let n=[{value:"managed",label:"Managed home",hint:l(t)}];return await N(e)||n.push({value:"here",label:"Current directory",hint:e}),n}function _(e,t=u.cwd()){if(q(e))return c$1.resolve(t);let o=H(e,"--output");if(o)return c$1.resolve(o)}function Be(e,t=u.cwd()){let o=c$1.resolve(e),n=c$1.resolve(t),i=c$1.relative(n,o);return i.length>0&&!i.startsWith("..")&&!c$1.isAbsolute(i)?`cd ${i}`:`cd ${o}`}function He(e,t={}){let o=t.argv??[],n=t.outputParent??_(o,u.cwd());return m(e.trim(),{homeDir:t.homeDir,outputDir:n})}function qe(e,t,o={}){return e?c$1.resolve(e)===c$1.resolve(t)?true:o.outputParent===void 0:false}async function ze(e,t={}){let o=t.cwd??u.cwd(),n=t.homeDir??homedir(),i=_(e,o);if(i!==void 0)return i;let a=t.hasYes??(e.includes("--yes")||e.includes("-y"));if(!(t.interactive??(!a&&!!u.stdin.isTTY&&!b())))return;let s=await z(o,n);if(s.length===1)return;let{location:p}=await b$1([{type:"rawlist",name:"location",message:"Where should the workspace be created?",choices:s,default:0}]);if(p==="here")return c$1.resolve(o)}export{A as a,oe as b,Se as c,Te as d,Ne as e,_e as f,Ye as g,Be as h,He as i,qe as j,ze as k};
|
package/dist/chunk-NSC4VWV2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import {j,m,e}from'./chunk-H4YHIOCT.js';import {u}from'./chunk-VQZ5PI5J.js';import {t}from'./chunk-ODK4LCEL.js';import u$1 from'path';import d from'fs-extra';import {parse}from'yaml';import w from'fs';var F=new Set(["backend","desktop","extension","service","frontend","worker","agent","platform","library","infra","docs","test-suite","unknown"]),O=new Set([".git",".workspai","vendor","node_modules","test","tests","testdata","fixtures","samples","examples","third_party"]),I=new Set([...O,".cache",".venv","build","dist","target"]);async function L(e){let n=0,t=async(o,r)=>{if(r>5)return false;let s;try{s=await d.readdir(o,{withFileTypes:true});}catch{return false}for(let a of s.sort((f,l)=>f.name.localeCompare(l.name))){if(a.isFile()&&a.name==="main.go"){let f=await d.readFile(u$1.join(o,a.name),"utf8").catch(()=>"");if(/^\s*package\s+main\b/m.test(f)&&(n+=1,n>1))return true}if(a.isDirectory()&&!O.has(a.name)&&await t(u$1.join(o,a.name),r+1))return true}return false};return t(e,0)}async function M(e,n){if(n!=="c"&&n!=="cpp")return false;let t=new Set,o=async(r,s)=>{if(s>3||t.size>=3)return;let a;try{a=await d.readdir(r,{withFileTypes:true});}catch{return}for(let f of a)if(f.isFile()){let l=f.name.toLowerCase();l==="cmakelists.txt"||l==="meson.build"?t.add("native"):l==="pyproject.toml"||l==="setup.py"?t.add("python"):l==="description"&&u$1.basename(r).toLowerCase()==="r"?t.add("r"):l.endsWith(".gemspec")?t.add("ruby"):l==="pom.xml"||l==="build.gradle"||l==="build.gradle.kts"?t.add("java"):l==="cargo.toml"?t.add("rust"):l==="go.mod"?t.add("go"):l==="package.json"&&t.add("node");}else f.isDirectory()&&!I.has(f.name)&&await o(u$1.join(r,f.name),s+1);};return await o(e,0),t.has("native")&&t.size>=3}async function K(e){if((((await d.readFile(u$1.join(e,"pom.xml"),"utf8").catch(()=>"")).match(/<modules\b[^>]*>([\s\S]*?)<\/modules>/iu)?.[1]??"").match(/<module\b[^>]*>[^<]+<\/module>/giu)??[]).length>=2)return true;for(let o of ["settings.gradle","settings.gradle.kts"]){let r=await d.readFile(u$1.join(e,o),"utf8").catch(()=>"");if(!r)continue;if(new Set([...r.matchAll(/['"](:[^'"]+)['"]/gu)].map(a=>a[1])).size>=2)return true}return false}async function $(e){for(let n of ["compose.yaml","compose.yml","docker-compose.yaml","docker-compose.yml"]){let t=await d.readFile(u$1.join(e,n),"utf8").catch(()=>"");if(t)try{let r=parse(t)?.services??{},s=Object.entries(r).map(([i,p])=>{let g=(()=>{if(typeof p?.build=="string")return `${p.build}|Dockerfile`;if(!p?.build||typeof p.build!="object")return null;let c=p.build.context;if(typeof c!="string"||c.length===0)return null;let j="dockerfile"in p.build&&typeof p.build.dockerfile=="string"?p.build.dockerfile:"Dockerfile";return `${c}|${j}`})();return g?{serviceName:i,service:p,identity:g.replaceAll("\\","/").replace(/\/$/,"")}:null}).filter(i=>i!==null);if(new Set(s.map(i=>i.identity)).size<2)continue;let f=new Set(s.map(i=>i.serviceName)),l=new Set(s.filter(({service:i})=>Array.isArray(i.ports)&&i.ports.length>0).map(({identity:i})=>i)),y=s.some(({service:i})=>(Array.isArray(i.depends_on)?i.depends_on:i.depends_on&&typeof i.depends_on=="object"?Object.keys(i.depends_on):[]).some(g=>typeof g=="string"&&f.has(g)));if(l.size>=2||y)return true}catch{}}return false}async function A(e){try{if(!await d.pathExists(e))return null;let n=await d.readJSON(e);return n&&typeof n=="object"?n:null}catch{return null}}async function z(e){for(let n of e){let t=await A(n);if(t)return t}return null}function S(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return F.has(n)?n==="service"?"backend":n:null}function re(e){switch(e){case "backend":case "service":case "worker":return "backend";case "agent":return "agent";case "frontend":case "desktop":case "extension":case "library":case "platform":return e;case "infra":return "infrastructure";case "docs":return "documentation";case "test-suite":return "quality";default:return "unknown"}}async function oe(e$1,n,t={}){let o=n??await z(u(e$1,"project.json")),r=j(o)?null:o,s=r===null&&o!==null?m(e$1,null):null,a=S(r?.kind)??S(r?.type);if(a)return a==="worker"&&typeof r?.framework=="string"&&(r.framework.trim().toLowerCase()==="microsoft-agent-framework"||r.framework.trim().toLowerCase()==="openai-agents")?"agent":a;let f=typeof r?.kit_name=="string"?r.kit_name:typeof r?.kit=="string"?r.kit:t.kit,l=typeof r?.framework=="string"?r.framework:t.framework??s?.key,y=typeof r?.runtime=="string"?r.runtime:t.runtime??s?.runtime,i=`${typeof f=="string"?f:""} ${l??""} ${y??""}`.trim().toLowerCase();if(await $(e$1))return "platform";if(/\b(tauri|electron|wails|desktop)\b/.test(i))return "desktop";if(/\b(vscode-extension|visual studio code extension|jetbrains-plugin|browser-extension)\b/.test(i))return "extension";let p=await d.readFile(u$1.join(e$1,"Cargo.toml"),"utf8").catch(()=>""),g=/^\s*\[workspace\]\s*$/m.test(p)&&!/^\s*\[package\]\s*$/m.test(p),c=await A(u$1.join(e$1,"package.json"));if(c!==null&&(Array.isArray(c.workspaces)||c.workspaces!==null&&typeof c.workspaces=="object")||g||e(e$1))return "platform";if(/\b(frontend|nextjs|next\.js|react|vue|svelte|vite|angular|astro|remix|nuxt)\b/.test(i))return "frontend";if(/\b(fastapi|nestjs|springboot|spring boot|gofiber|gogin|webapi|django|flask|express|fastify|laravel|rails|phoenix|axum|actix|rocket)\b/.test(i))return "backend";if(c){let m={...c.dependencies??{},...c.devDependencies??{}},D=c.scripts??{},b=Object.values(D).filter(k=>typeof k=="string").join(" ").toLowerCase(),_=c.engines??{},N=Array.isArray(c.categories)?c.categories.filter(k=>typeof k=="string"):[];if(m["@tauri-apps/api"]||m["@tauri-apps/cli"]||await d.pathExists(u$1.join(e$1,"src-tauri","tauri.conf.json"))||await d.pathExists(u$1.join(e$1,"src-tauri","tauri.conf.json5"))||m.electron||m["@electron-forge/cli"]||b.includes("electron-forge")||b.includes("electron "))return "desktop";if(typeof _.vscode=="string"||N.some(k=>k.toLowerCase()==="extension packs")||c.publisher&&(c.activationEvents||c.contributes))return "extension";if(m.next||m.react||m.vue||m.svelte||m.vite||m["@angular/core"]||b.includes("next ")||b.includes("vite "))return "frontend";if(c.private===true&&!m.express&&!m["@nestjs/core"])return "library"}return g||await K(e$1)||await d.pathExists(u$1.join(e$1,"go.work"))||await d.pathExists(u$1.join(e$1,"go.mod"))&&await L(e$1)?"platform":await M(e$1,y)?"library":await d.pathExists(u$1.join(e$1,"compose.yaml"))||await d.pathExists(u$1.join(e$1,"compose.yml"))||await d.pathExists(u$1.join(e$1,"docker-compose.yml"))||await d.pathExists(u$1.join(e$1,"docker-compose.yaml"))||await d.pathExists(u$1.join(e$1,"terraform.tf"))?"infra":"backend"}var B={ci:[".github/workflows",".gitlab-ci.yml",".circleci/config.yml","azure-pipelines.yml","bitbucket-pipelines.yml","cloudbuild.yaml","Jenkinsfile",".buildkite/pipeline.yml","prow"],release:[".changeset",".releaserc",".releaserc.json","release.config.js",".goreleaser.yml",".goreleaser.yaml","RELEASING.md","RELEASE.md","tools/release","scripts/release","docs/release","doc/release","build/release.sh","hack/lib/release.sh"],ownership:[".github/CODEOWNERS",".gitlab/CODEOWNERS","CODEOWNERS","docs/CODEOWNERS","OWNERS","OWNERS_ALIASES","MAINTAINERS"]},J=/(?:^|[-_.])(?:release|publish|publishing|distribution)(?:[-_.]|$)/i,V={ci:/\b(?:prow|buildkite|jenkins|teamcity|travis|external ci|test-infra)\b/i,release:/\b(?:release automation|release engineering|release infrastructure|external release)\b/i,ownership:/\b(?:external ownership|central owners|maintainer team|code owners)\b/i};async function U(e,n){let t=[];for(let o of n)try{await w.promises.access(u$1.join(e,o),w.constants.F_OK),t.push(o);}catch{}return t}async function Y(e,n){let t=["README.md","CONTRIBUTING.md","DEVELOPMENT.md","docs/devel/README.md"],o=[];for(let r of t)try{let s=u$1.join(e,r),a=await w.promises.stat(s);if(!a.isFile()||a.size>1024*1024)continue;let f=await w.promises.readFile(s,"utf8");n.test(f)&&o.push(r);}catch{}return o}async function q(e){let n=u$1.join(e,".github","workflows");try{return (await w.promises.readdir(n,{withFileTypes:true})).filter(o=>o.isFile()&&/\.(?:ya?ml)$/i.test(o.name)&&J.test(o.name)).map(o=>`.github/workflows/${o.name}`).sort()}catch{return []}}function H(e,n){let t$1=e?.[n];return t$1?.mode?{status:t$1.mode==="external"?"external-declared":"repository",provider:t$1.provider?.trim()||null,evidence:[t.workspaceContract],reference:t$1.reference?.trim()||null}:null}async function v(e,n,t){let o=H(n,t);if(o)return o;let r=[...await U(e,B[t]),...t==="release"?await q(e):[]];if(r.length>0)return {status:"repository",provider:null,evidence:r,reference:null};let s=await Y(e,V[t]);return s.length>0?{status:"external-observed",provider:null,evidence:s,reference:null}:{status:"unknown",provider:null,evidence:[],reference:null}}async function ue(e){let[n,t,o]=await Promise.all([v(e.projectPath,e.declaration,"ci"),v(e.projectPath,e.declaration,"release"),v(e.projectPath,e.declaration,"ownership")]);return {schemaVersion:"workspai.project-governance.v1",ci:n,release:t,ownership:o}}export{re as a,oe as b,ue as c};
|