workspai 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +624 -0
  3. package/contracts/agent-customization-pack.v1.json +229 -0
  4. package/contracts/analyze-last-run.v1.json +106 -0
  5. package/contracts/artifact-remediation-plan.v1.json +163 -0
  6. package/contracts/backend-import-stack-parity.snapshot.json +37 -0
  7. package/contracts/cli-log-event.v1.json +51 -0
  8. package/contracts/create-planner-capabilities.v1.json +251 -0
  9. package/contracts/doctor-project-evidence.v1.json +304 -0
  10. package/contracts/doctor-remediation-plan.v1.json +496 -0
  11. package/contracts/doctor-workspace-evidence.v1.json +315 -0
  12. package/contracts/extension-cli-compatibility.v1.json +26 -0
  13. package/contracts/infra-stack.v1.json +305 -0
  14. package/contracts/module-layout.v1.json +34 -0
  15. package/contracts/module-support.v1.json +20 -0
  16. package/contracts/pipeline-last-run.v1.json +80 -0
  17. package/contracts/release-readiness.v1.json +60 -0
  18. package/contracts/runtime-command-surface.v1.json +364 -0
  19. package/contracts/workspace-intelligence/agent-action-outcome.v1.json +38 -0
  20. package/contracts/workspace-intelligence/blocker-resolution.v1.json +65 -0
  21. package/contracts/workspace-intelligence/doctor-fix-result.v1.json +44 -0
  22. package/contracts/workspace-intelligence/fact-freshness.v1.json +58 -0
  23. package/contracts/workspace-intelligence/studio-blocker-handoff.v1.json +115 -0
  24. package/contracts/workspace-intelligence/workspace-context.v1.json +142 -0
  25. package/contracts/workspace-intelligence/workspace-contract-verify.v1.json +51 -0
  26. package/contracts/workspace-intelligence/workspace-dependency-graph.v1.json +152 -0
  27. package/contracts/workspace-intelligence/workspace-explain.v1.json +31 -0
  28. package/contracts/workspace-intelligence/workspace-impact.v1.json +114 -0
  29. package/contracts/workspace-intelligence/workspace-intelligence-history.v1.json +40 -0
  30. package/contracts/workspace-intelligence/workspace-model-diff.v1.json +105 -0
  31. package/contracts/workspace-intelligence/workspace-model-snapshot.v1.json +36 -0
  32. package/contracts/workspace-intelligence/workspace-model.v1.json +135 -0
  33. package/contracts/workspace-intelligence/workspace-operational-skill.v1.json +37 -0
  34. package/contracts/workspace-intelligence/workspace-skills-index.v1.json +27 -0
  35. package/contracts/workspace-intelligence/workspace-verify.v1.json +213 -0
  36. package/contracts/workspace-registry.v1.json +83 -0
  37. package/contracts/workspace-run-last.v1.json +112 -0
  38. package/data/modules-embeddings.json +16953 -0
  39. package/dist/analyze-5BU4QIPK.js +1 -0
  40. package/dist/artifact-remediation-plan-5GJWPPRS.js +3 -0
  41. package/dist/autopilot-release-QYUOVB26.js +1 -0
  42. package/dist/chunk-22DT744Z.js +1 -0
  43. package/dist/chunk-2E6WGUN6.js +1 -0
  44. package/dist/chunk-2FIX2MDC.js +1 -0
  45. package/dist/chunk-3KXW53QI.js +1 -0
  46. package/dist/chunk-3ZK2GU7C.js +1 -0
  47. package/dist/chunk-4KUIFXHM.js +5 -0
  48. package/dist/chunk-54XJNLYC.js +13 -0
  49. package/dist/chunk-5SWNSJGW.js +1 -0
  50. package/dist/chunk-5XATWNME.js +1 -0
  51. package/dist/chunk-753LOKFZ.js +2 -0
  52. package/dist/chunk-7YHK5NM3.js +2 -0
  53. package/dist/chunk-A5FBGRJA.js +1 -0
  54. package/dist/chunk-AAKUNWPR.js +78 -0
  55. package/dist/chunk-AFSZHLQT.js +1 -0
  56. package/dist/chunk-AQ4XZZC6.js +1 -0
  57. package/dist/chunk-CVTCPPEF.js +1 -0
  58. package/dist/chunk-DNAY5ALC.js +1 -0
  59. package/dist/chunk-EWYYLJQY.js +2 -0
  60. package/dist/chunk-GSWPGELT.js +2 -0
  61. package/dist/chunk-GZTYAEWX.js +1 -0
  62. package/dist/chunk-HTYMXMQM.js +1 -0
  63. package/dist/chunk-IBJEQHJR.js +205 -0
  64. package/dist/chunk-ICGWHIMK.js +1 -0
  65. package/dist/chunk-JEI6BTZI.js +3 -0
  66. package/dist/chunk-JHC6SCJC.js +1 -0
  67. package/dist/chunk-LO4C4VXR.js +4 -0
  68. package/dist/chunk-LPZFK3Y6.js +920 -0
  69. package/dist/chunk-LUP4U6EE.js +1 -0
  70. package/dist/chunk-LYC6AIF2.js +2 -0
  71. package/dist/chunk-LZQNVH7D.js +1 -0
  72. package/dist/chunk-NAAQMSO3.js +1 -0
  73. package/dist/chunk-NFUXULIF.js +1 -0
  74. package/dist/chunk-OCGZNSOE.js +1 -0
  75. package/dist/chunk-OJEWQO3Z.js +33 -0
  76. package/dist/chunk-OL64GWQC.js +9 -0
  77. package/dist/chunk-PI5KUXDA.js +7 -0
  78. package/dist/chunk-PYCJWW4B.js +1 -0
  79. package/dist/chunk-RE773WOX.js +13 -0
  80. package/dist/chunk-RO73VVHW.js +2 -0
  81. package/dist/chunk-S5KTATOU.js +1 -0
  82. package/dist/chunk-SI3AQKIP.js +1 -0
  83. package/dist/chunk-T3GJ7YVG.js +1 -0
  84. package/dist/chunk-T6OR6YOI.js +2 -0
  85. package/dist/chunk-VRDF2J46.js +653 -0
  86. package/dist/chunk-VZKSNUEE.js +2 -0
  87. package/dist/chunk-WU4ZRRA5.js +4 -0
  88. package/dist/chunk-XEJD4KCV.js +33 -0
  89. package/dist/chunk-XZGVNGRB.js +1 -0
  90. package/dist/chunk-Y45WZR5N.js +5 -0
  91. package/dist/create-WRZO4HK2.js +1 -0
  92. package/dist/demo-kit-AJ5LIM5G.js +149 -0
  93. package/dist/doctor-MF3M3FS3.js +1 -0
  94. package/dist/dotnet-webapi-clean-IPY3MCGQ.js +425 -0
  95. package/dist/gofiber-standard-N5N3QGH3.js +1397 -0
  96. package/dist/gogin-standard-LAWQTBWL.js +1459 -0
  97. package/dist/imported-projects-registry-FOIE27WT.js +1 -0
  98. package/dist/index.d.ts +141 -0
  99. package/dist/index.js +454 -0
  100. package/dist/managed-agent-markers-AXUM75OE.js +8 -0
  101. package/dist/module-layout-NZ43RSC5.js +1 -0
  102. package/dist/pipeline-QCUHFWDY.js +5 -0
  103. package/dist/platform-capabilities-XAVU4HSM.js +1 -0
  104. package/dist/pythonRapidkitExec-3L3XJBSY.js +1 -0
  105. package/dist/springboot-standard-OZYF7ZM7.js +697 -0
  106. package/dist/workspace-PR6VZRBG.js +1 -0
  107. package/dist/workspace-agent-sync-KTYF3HQR.js +1 -0
  108. package/dist/workspace-archive-GCZNI44O.js +3 -0
  109. package/dist/workspace-context-QUTOP2XV.js +1 -0
  110. package/dist/workspace-contract-XUGMCUSQ.js +1 -0
  111. package/dist/workspace-explain-JEONEGZZ.js +1 -0
  112. package/dist/workspace-explain-contract-DNS2YEL7.js +1 -0
  113. package/dist/workspace-feedback-R6H4UFZB.js +1 -0
  114. package/dist/workspace-foundation-KGSV4E6D.js +1 -0
  115. package/dist/workspace-graph-2A5THUCI.js +1 -0
  116. package/dist/workspace-history-CGCK2DJI.js +1 -0
  117. package/dist/workspace-intelligence-QJGVL37U.js +1 -0
  118. package/dist/workspace-marker-SMBC3Z2Q.js +1 -0
  119. package/dist/workspace-mcp-serve-AK4MYEHQ.js +3 -0
  120. package/dist/workspace-model-PNXXOGPO.js +1 -0
  121. package/dist/workspace-python-engine-state-MTWIIZPY.js +2 -0
  122. package/dist/workspace-registry-summary-RUJE6RPH.js +1 -0
  123. package/dist/workspace-run-Y7YMUIHX.js +1 -0
  124. package/dist/workspace-verify-WSDUUTR5.js +1 -0
  125. package/dist/workspace-watch-AGPOJ74Q.js +1 -0
  126. package/docs/AI_DYNAMIC_INTEGRATION.md +440 -0
  127. package/docs/AI_EXAMPLES.md +419 -0
  128. package/docs/AI_FEATURES.md +460 -0
  129. package/docs/AI_QUICKSTART.md +245 -0
  130. package/docs/DEVELOPMENT.md +90 -0
  131. package/docs/From Code to Shared Understanding.png +0 -0
  132. package/docs/OPEN_SOURCE_USER_SCENARIOS.md +170 -0
  133. package/docs/OPTIMIZATION_GUIDE.md +504 -0
  134. package/docs/PACKAGE_MANAGER_POLICY.md +25 -0
  135. package/docs/README.md +125 -0
  136. package/docs/SECURITY.md +63 -0
  137. package/docs/SETUP.md +107 -0
  138. package/docs/UTILITIES.md +221 -0
  139. package/docs/WORKSPACE_MARKER_SPEC.md +276 -0
  140. package/docs/ci-workflows.md +59 -0
  141. package/docs/commands-reference.md +172 -0
  142. package/docs/config-file-guide.md +299 -0
  143. package/docs/contracts/ARTIFACT_CATALOG.md +333 -0
  144. package/docs/contracts/CLI_LOG_EVENT_STREAM.md +123 -0
  145. package/docs/contracts/COMMAND_OWNERSHIP_MATRIX.md +138 -0
  146. package/docs/contracts/NAMING_AND_COEXISTENCE.md +60 -0
  147. package/docs/contracts/README.md +86 -0
  148. package/docs/contracts/RUNTIME_ACCEPTANCE_MATRIX.md +98 -0
  149. package/docs/contracts/RUNTIME_SUPPORT_MATRIX.md +75 -0
  150. package/docs/contracts/rapidkit-cli-contracts.json +239 -0
  151. package/docs/create-planner-capabilities.md +81 -0
  152. package/docs/doctor-command.md +467 -0
  153. package/docs/examples/ci-agent-grounding.yml +65 -0
  154. package/docs/from-code-to-shared-understanding.md +45 -0
  155. package/docs/governance-policy.enterprise.example.json +40 -0
  156. package/docs/mirror-config.enterprise.example.json +60 -0
  157. package/docs/policies.workspace.example.yml +23 -0
  158. package/docs/workspace-operations.md +160 -0
  159. package/docs/workspace-run.md +104 -0
  160. package/package.json +179 -0
  161. package/rapidkit.config.example.cjs +62 -0
  162. package/scripts/check-agent-customization-drift.mjs +78 -0
  163. package/scripts/check-cli-resolution.cjs +72 -0
  164. package/scripts/enforce-package-manager.cjs +10 -0
  165. package/scripts/enterprise-package-smoke.mjs +463 -0
  166. package/scripts/prepack-enterprise.mjs +43 -0
  167. package/templates/generator.js +179 -0
  168. package/templates/kits/fastapi-ddd/README.md.j2 +117 -0
  169. package/templates/kits/fastapi-ddd/common/env.example.j2 +10 -0
  170. package/templates/kits/fastapi-ddd/env.example.j2 +1 -0
  171. package/templates/kits/fastapi-ddd/pyproject.toml.j2 +64 -0
  172. package/templates/kits/fastapi-ddd/src/__init__.py.j2 +3 -0
  173. package/templates/kits/fastapi-ddd/src/app/__init__.py.j2 +11 -0
  174. package/templates/kits/fastapi-ddd/src/app/application/__init__.py.j2 +5 -0
  175. package/templates/kits/fastapi-ddd/src/app/application/interfaces.py.j2 +43 -0
  176. package/templates/kits/fastapi-ddd/src/app/application/use_cases/__init__.py.j2 +6 -0
  177. package/templates/kits/fastapi-ddd/src/app/application/use_cases/health.py.j2 +14 -0
  178. package/templates/kits/fastapi-ddd/src/app/application/use_cases/notes.py.j2 +24 -0
  179. package/templates/kits/fastapi-ddd/src/app/config/__init__.py.j2 +16 -0
  180. package/templates/kits/fastapi-ddd/src/app/domain/__init__.py.j2 +3 -0
  181. package/templates/kits/fastapi-ddd/src/app/domain/models/__init__.py.j2 +6 -0
  182. package/templates/kits/fastapi-ddd/src/app/domain/models/health.py.j2 +16 -0
  183. package/templates/kits/fastapi-ddd/src/app/domain/models/note.py.j2 +27 -0
  184. package/templates/kits/fastapi-ddd/src/app/infrastructure/__init__.py.j2 +5 -0
  185. package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/__init__.py.j2 +6 -0
  186. package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/health.py.j2 +17 -0
  187. package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/notes.py.j2 +28 -0
  188. package/templates/kits/fastapi-ddd/src/app/main.py.j2 +61 -0
  189. package/templates/kits/fastapi-ddd/src/app/presentation/__init__.py.j2 +3 -0
  190. package/templates/kits/fastapi-ddd/src/app/presentation/api/__init__.py.j2 +5 -0
  191. package/templates/kits/fastapi-ddd/src/app/presentation/api/dependencies/__init__.py.j2 +19 -0
  192. package/templates/kits/fastapi-ddd/src/app/presentation/api/router.py.j2 +10 -0
  193. package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/__init__.py.j2 +5 -0
  194. package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/health.py.j2 +27 -0
  195. package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/notes.py.j2 +50 -0
  196. package/templates/kits/fastapi-ddd/src/app/shared/__init__.py.j2 +5 -0
  197. package/templates/kits/fastapi-ddd/src/app/shared/result.py.j2 +28 -0
  198. package/templates/kits/fastapi-ddd/src/cli.py.j2 +170 -0
  199. package/templates/kits/fastapi-ddd/src/main.py.j2 +35 -0
  200. package/templates/kits/fastapi-ddd/src/modules/__init__.py.j2 +3 -0
  201. package/templates/kits/fastapi-ddd/src/routing/__init__.py.j2 +13 -0
  202. package/templates/kits/fastapi-ddd/src/routing/health.py.j2 +7 -0
  203. package/templates/kits/fastapi-ddd/src/routing/notes.py.j2 +7 -0
  204. package/templates/kits/fastapi-ddd/tests/__init__.py.j2 +1 -0
  205. package/templates/kits/fastapi-ddd/tests/test_app_factory.py.j2 +22 -0
  206. package/templates/kits/fastapi-ddd/tests/test_health.py.j2 +17 -0
  207. package/templates/kits/fastapi-ddd/tests/test_notes.py.j2 +27 -0
  208. package/templates/kits/fastapi-standard/README.md.j2 +140 -0
  209. package/templates/kits/fastapi-standard/common/env.example.j2 +10 -0
  210. package/templates/kits/fastapi-standard/env.example.j2 +1 -0
  211. package/templates/kits/fastapi-standard/pyproject.toml.j2 +64 -0
  212. package/templates/kits/fastapi-standard/src/__init__.py.j2 +3 -0
  213. package/templates/kits/fastapi-standard/src/cli.py.j2 +171 -0
  214. package/templates/kits/fastapi-standard/src/main.py.j2 +66 -0
  215. package/templates/kits/fastapi-standard/src/modules/__init__.py.j2 +3 -0
  216. package/templates/kits/fastapi-standard/src/routing/__init__.py.j2 +16 -0
  217. package/templates/kits/fastapi-standard/src/routing/examples.py.j2 +71 -0
  218. package/templates/kits/fastapi-standard/src/routing/health.py.j2 +22 -0
  219. package/templates/kits/fastapi-standard/tests/__init__.py.j2 +1 -0
  220. package/templates/kits/fastapi-standard/tests/test_examples.py.j2 +29 -0
  221. package/templates/kits/fastapi-standard/tests/test_health.py.j2 +17 -0
  222. package/templates/kits/nestjs-standard/Dockerfile.j2 +41 -0
  223. package/templates/kits/nestjs-standard/README.md.j2 +134 -0
  224. package/templates/kits/nestjs-standard/docker-compose.yml.j2 +94 -0
  225. package/templates/kits/nestjs-standard/docs/README.md.j2 +15 -0
  226. package/templates/kits/nestjs-standard/env.example.j2 +18 -0
  227. package/templates/kits/nestjs-standard/eslint.config.cjs.j2 +9 -0
  228. package/templates/kits/nestjs-standard/jest.config.ts.j2 +28 -0
  229. package/templates/kits/nestjs-standard/nest-cli.json.j2 +10 -0
  230. package/templates/kits/nestjs-standard/package.json.j2 +101 -0
  231. package/templates/kits/nestjs-standard/src/app.controller.ts.j2 +14 -0
  232. package/templates/kits/nestjs-standard/src/app.module.ts.j2 +26 -0
  233. package/templates/kits/nestjs-standard/src/app.service.ts.j2 +16 -0
  234. package/templates/kits/nestjs-standard/src/auth/auth.controller.ts.j2 +20 -0
  235. package/templates/kits/nestjs-standard/src/auth/auth.module.ts.j2 +13 -0
  236. package/templates/kits/nestjs-standard/src/auth/auth.service.ts.j2 +6 -0
  237. package/templates/kits/nestjs-standard/src/auth/entities/token.entity.ts.j2 +3 -0
  238. package/templates/kits/nestjs-standard/src/auth/entities/user.entity.ts.j2 +3 -0
  239. package/templates/kits/nestjs-standard/src/auth/entities/webauthn.entity.ts.j2 +3 -0
  240. package/templates/kits/nestjs-standard/src/config/configuration.ts.j2 +85 -0
  241. package/templates/kits/nestjs-standard/src/config/index.ts.j2 +2 -0
  242. package/templates/kits/nestjs-standard/src/config/validation.ts.j2 +21 -0
  243. package/templates/kits/nestjs-standard/src/examples/dto/create-note.dto.ts.j2 +11 -0
  244. package/templates/kits/nestjs-standard/src/examples/examples.controller.ts.j2 +24 -0
  245. package/templates/kits/nestjs-standard/src/examples/examples.module.ts.j2 +10 -0
  246. package/templates/kits/nestjs-standard/src/examples/examples.service.ts.j2 +33 -0
  247. package/templates/kits/nestjs-standard/src/main.ts.j2 +53 -0
  248. package/templates/kits/nestjs-standard/src/modules/index.ts.j2 +25 -0
  249. package/templates/kits/nestjs-standard/test/app.controller.spec.ts.j2 +24 -0
  250. package/templates/kits/nestjs-standard/test/app.e2e-spec.ts.j2 +60 -0
  251. package/templates/kits/nestjs-standard/test/examples.controller.spec.ts.j2 +28 -0
  252. package/templates/kits/nestjs-standard/test/jest-e2e.json.j2 +15 -0
  253. package/templates/kits/nestjs-standard/tsconfig.build.json.j2 +12 -0
  254. package/templates/kits/nestjs-standard/tsconfig.json.j2 +26 -0
  255. package/workspai.config.example.cjs +62 -0
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execFileSync } = require('node:child_process');
4
+ const path = require('node:path');
5
+ const process = require('node:process');
6
+
7
+ function isWindows() {
8
+ return process.platform === 'win32';
9
+ }
10
+
11
+ function npmGlobalBinDir() {
12
+ const prefix = process.env.npm_config_prefix;
13
+ if (!prefix) return null;
14
+ return isWindows() ? prefix : path.join(prefix, 'bin');
15
+ }
16
+
17
+ const PRIMARY_COMMAND = 'workspai';
18
+
19
+ function resolveCommandCandidates(commandName) {
20
+ const command = isWindows() ? 'where' : 'which';
21
+ const args = isWindows() ? [commandName] : ['-a', commandName];
22
+ try {
23
+ return execFileSync(command, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
24
+ .split(/\r?\n/)
25
+ .map((line) => line.trim())
26
+ .filter(Boolean);
27
+ } catch {
28
+ return [];
29
+ }
30
+ }
31
+
32
+ function normalize(value) {
33
+ return value.replace(/\\/g, '/').toLowerCase();
34
+ }
35
+
36
+ function main() {
37
+ // On Windows, PATH ordering can route a globally installed CLI name to the
38
+ // wrong shim. Workspai publishes only the `workspai` binary; the legacy
39
+ // `rapidkit` alias is intentionally owned by the legacy package/Python Core.
40
+ if (!isWindows()) return;
41
+
42
+ const candidates = resolveCommandCandidates(PRIMARY_COMMAND);
43
+ if (candidates.length <= 1) return;
44
+
45
+ const npmBin = npmGlobalBinDir();
46
+ const expectedPrefix = npmBin ? normalize(npmBin) : null;
47
+ const first = normalize(candidates[0]);
48
+ const npmShimIsFirst = expectedPrefix ? first.startsWith(expectedPrefix) : false;
49
+
50
+ if (npmShimIsFirst) return;
51
+
52
+ const npmCandidate = expectedPrefix
53
+ ? candidates.find((candidate) => normalize(candidate).startsWith(expectedPrefix))
54
+ : null;
55
+
56
+ console.warn('');
57
+ console.warn('[workspai] Windows CLI resolution warning');
58
+ console.warn(`The first \`${PRIMARY_COMMAND}\` command on PATH is not the npm global shim.`);
59
+ console.warn(`First match: ${candidates[0]}`);
60
+ if (npmCandidate) {
61
+ console.warn(`npm shim: ${npmCandidate}`);
62
+ }
63
+ console.warn('');
64
+ console.warn('This can make `workspai doctor workspace`, `workspai workspace ...`,');
65
+ console.warn('and other npm-owned commands route to an unexpected executable.');
66
+ console.warn('');
67
+ console.warn('Fix: move the npm global bin directory before Python Scripts in PATH, or run:');
68
+ console.warn(' npx --yes workspai <command>');
69
+ console.warn('');
70
+ }
71
+
72
+ main();
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ const userAgent = process.env.npm_config_user_agent || '';
4
+ const usingNpm = userAgent.startsWith('npm/');
5
+
6
+ if (!usingNpm) {
7
+ console.error('❌ Workspai uses npm as the only supported package manager for development.');
8
+ console.error('Please run: npm install');
9
+ process.exit(1);
10
+ }
@@ -0,0 +1,463 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import process from 'node:process';
8
+
9
+ const repoRoot = process.cwd();
10
+ const cliPath = path.join(repoRoot, 'dist', 'index.js');
11
+
12
+ function fail(message) {
13
+ console.error(`[enterprise-package-smoke] ${message}`);
14
+ process.exit(1);
15
+ }
16
+
17
+ function log(message) {
18
+ console.log(`[enterprise-package-smoke] ${message}`);
19
+ }
20
+
21
+ function cliEnv(extraEnv = {}) {
22
+ const env = { ...process.env, ...extraEnv };
23
+ delete env.NODE_ENV;
24
+ delete env.NODE_OPTIONS;
25
+ for (const key of Object.keys(env)) {
26
+ if (key.startsWith('VITEST')) {
27
+ delete env[key];
28
+ }
29
+ }
30
+ return env;
31
+ }
32
+
33
+ function commandExists(command, args = ['--version']) {
34
+ const result = spawnSync(command, args, { stdio: 'ignore' });
35
+ return result.status === 0;
36
+ }
37
+
38
+ function resolveNpmInvocation() {
39
+ const npmExecPath = process.env.npm_execpath;
40
+ if (npmExecPath && fs.existsSync(npmExecPath)) {
41
+ return { command: process.execPath, prefixArgs: [npmExecPath] };
42
+ }
43
+
44
+ if (commandExists('corepack')) {
45
+ return { command: 'corepack', prefixArgs: ['npm'] };
46
+ }
47
+
48
+ if (commandExists('npm')) {
49
+ return { command: 'npm', prefixArgs: [] };
50
+ }
51
+
52
+ fail('could not resolve npm. Install npm or enable corepack before packaging.');
53
+ }
54
+
55
+ function run(command, args, options = {}) {
56
+ const result = spawnSync(command, args, {
57
+ cwd: repoRoot,
58
+ encoding: 'utf8',
59
+ stdio: ['ignore', 'pipe', 'pipe'],
60
+ ...options,
61
+ env: cliEnv(options.env),
62
+ });
63
+ if (result.status !== 0) {
64
+ fail(
65
+ `command failed (${result.status}): ${command} ${args.join(' ')}\n${result.stdout ?? ''}\n${result.stderr ?? ''}`
66
+ );
67
+ }
68
+ return result.stdout ?? '';
69
+ }
70
+
71
+ function runToFile(command, args, options = {}) {
72
+ const outputPath = path.join(
73
+ os.tmpdir(),
74
+ `rapidkit-enterprise-command-${process.pid}-${Date.now()}-${Math.random()
75
+ .toString(16)
76
+ .slice(2)}.out`
77
+ );
78
+ const fd = fs.openSync(outputPath, 'w');
79
+ try {
80
+ const result = spawnSync(command, args, {
81
+ cwd: repoRoot,
82
+ encoding: 'utf8',
83
+ stdio: ['ignore', fd, 'pipe'],
84
+ ...options,
85
+ env: cliEnv(options.env),
86
+ });
87
+ if (result.status !== 0) {
88
+ fail(
89
+ `command failed (${result.status}): ${command} ${args.join(' ')}\n${result.stderr ?? ''}`
90
+ );
91
+ }
92
+ } finally {
93
+ fs.closeSync(fd);
94
+ }
95
+
96
+ try {
97
+ return fs.readFileSync(outputPath, 'utf8');
98
+ } finally {
99
+ fs.rmSync(outputPath, { force: true });
100
+ }
101
+ }
102
+
103
+ function runNpm(args) {
104
+ const npm = resolveNpmInvocation();
105
+ const isolatedCache = path.join(os.tmpdir(), `rapidkit-enterprise-npm-cache-${process.pid}`);
106
+ fs.mkdirSync(isolatedCache, { recursive: true });
107
+ return runToFile(npm.command, [...npm.prefixArgs, ...args], {
108
+ env: {
109
+ ...cliEnv(),
110
+ npm_config_user_agent: process.env.npm_config_user_agent || 'npm/10 rapidkit-smoke',
111
+ npm_config_cache: isolatedCache,
112
+ },
113
+ });
114
+ }
115
+
116
+ function runCli(args) {
117
+ const outputPath = path.join(
118
+ os.tmpdir(),
119
+ `rapidkit-enterprise-cli-${process.pid}-${Date.now()}-${Math.random()
120
+ .toString(16)
121
+ .slice(2)}.out`
122
+ );
123
+ const fd = fs.openSync(outputPath, 'w');
124
+ try {
125
+ const result = spawnSync(process.execPath, [cliPath, ...args], {
126
+ cwd: repoRoot,
127
+ encoding: 'utf8',
128
+ env: cliEnv(),
129
+ stdio: ['ignore', fd, 'pipe'],
130
+ });
131
+ if (result.status !== 0) {
132
+ fail(
133
+ `CLI command failed (${result.status}): node dist/index.js ${args.join(' ')}\n${
134
+ result.stderr ?? ''
135
+ }`
136
+ );
137
+ }
138
+ } finally {
139
+ fs.closeSync(fd);
140
+ }
141
+
142
+ try {
143
+ return fs.readFileSync(outputPath, 'utf8');
144
+ } finally {
145
+ fs.rmSync(outputPath, { force: true });
146
+ }
147
+ }
148
+
149
+ function assertFile(relativePath) {
150
+ const absolutePath = path.join(repoRoot, relativePath);
151
+ if (!fs.existsSync(absolutePath)) {
152
+ fail(`missing required file: ${relativePath}`);
153
+ }
154
+ }
155
+
156
+ function assertNodeExecutable(relativePath) {
157
+ run(process.execPath, [path.join(repoRoot, relativePath)]);
158
+ }
159
+
160
+ function parseTrailingJson(stdout) {
161
+ const trimmed = stdout.trim();
162
+ const start = trimmed.lastIndexOf('\n{');
163
+ const jsonText = start >= 0 ? trimmed.slice(start + 1) : trimmed;
164
+ try {
165
+ return JSON.parse(jsonText);
166
+ } catch (error) {
167
+ fail(`failed to parse CLI JSON output: ${error instanceof Error ? error.message : error}`);
168
+ }
169
+ }
170
+
171
+ function parseTrailingJsonArray(stdout) {
172
+ const trimmed = stdout.trim();
173
+ const start = trimmed.lastIndexOf('\n[');
174
+ const jsonText = start >= 0 ? trimmed.slice(start + 1) : trimmed;
175
+ try {
176
+ return JSON.parse(jsonText);
177
+ } catch (error) {
178
+ fail(`failed to parse npm JSON output: ${error instanceof Error ? error.message : error}`);
179
+ }
180
+ }
181
+
182
+ const REQUIRED_PACKAGE_FILES = [
183
+ 'dist/index.js',
184
+ 'contracts/runtime-command-surface.v1.json',
185
+ 'contracts/extension-cli-compatibility.v1.json',
186
+ 'data/modules-embeddings.json',
187
+ 'templates/kits/fastapi-standard/README.md.j2',
188
+ 'templates/kits/fastapi-ddd/README.md.j2',
189
+ 'templates/kits/nestjs-standard/package.json.j2',
190
+ 'workspai.config.example.cjs',
191
+ 'rapidkit.config.example.cjs',
192
+ 'scripts/check-cli-resolution.cjs',
193
+ 'scripts/enforce-package-manager.cjs',
194
+ ];
195
+
196
+ const FORBIDDEN_PACKAGE_FILES = [
197
+ 'workspai.config.example.js',
198
+ 'rapidkit.config.example.js',
199
+ ];
200
+
201
+ function isPublishedByFilesPolicy(packageJson, assetPath) {
202
+ const files = packageJson.files ?? [];
203
+ return files.some(
204
+ (entry) => entry === assetPath || assetPath.startsWith(`${entry.replace(/\/$/, '')}/`)
205
+ );
206
+ }
207
+
208
+ function assertPackageFilesPolicy(requiredFiles) {
209
+ const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
210
+ if (packageJson.name !== 'workspai') {
211
+ fail(`package.json#name must be workspai, got ${packageJson.name}`);
212
+ }
213
+ if (packageJson.bin?.workspai !== 'dist/index.js') {
214
+ fail('package.json#bin.workspai must point to dist/index.js');
215
+ }
216
+ if ('rapidkit' in (packageJson.bin ?? {})) {
217
+ fail('package.json#bin.rapidkit must stay in the legacy rapidkit package, not workspai');
218
+ }
219
+ for (const required of requiredFiles) {
220
+ if (!isPublishedByFilesPolicy(packageJson, required)) {
221
+ fail(`package.json#files does not publish ${required}`);
222
+ }
223
+ assertFile(required);
224
+ }
225
+ for (const forbidden of FORBIDDEN_PACKAGE_FILES) {
226
+ if (isPublishedByFilesPolicy(packageJson, forbidden) || fs.existsSync(path.join(repoRoot, forbidden))) {
227
+ fail(`forbidden legacy package file is still present or published: ${forbidden}`);
228
+ }
229
+ }
230
+ assertNodeExecutable('workspai.config.example.cjs');
231
+ assertNodeExecutable('rapidkit.config.example.cjs');
232
+ }
233
+
234
+ function assertPackContents() {
235
+ if (process.env.RAPIDKIT_ENTERPRISE_PREPACK === '1') {
236
+ assertPackageFilesPolicy(REQUIRED_PACKAGE_FILES);
237
+ log('verified package.json#files payload policy for prepack lifecycle');
238
+ return;
239
+ }
240
+
241
+ const output = runNpm(['pack', '--dry-run', '--json', '--ignore-scripts']);
242
+ const packuments = parseTrailingJsonArray(output);
243
+
244
+ const files = new Set(
245
+ (packuments?.[0]?.files ?? [])
246
+ .map((entry) => entry?.path)
247
+ .filter((entry) => typeof entry === 'string')
248
+ );
249
+
250
+ const missingRequired = REQUIRED_PACKAGE_FILES.filter((required) => !files.has(required));
251
+ const forbiddenPresent = FORBIDDEN_PACKAGE_FILES.filter((forbidden) => files.has(forbidden));
252
+ if (forbiddenPresent.length > 0) {
253
+ fail(`npm pack includes forbidden legacy config example(s): ${forbiddenPresent.join(', ')}`);
254
+ }
255
+ if (missingRequired.length > 0) {
256
+ assertPackageFilesPolicy(missingRequired);
257
+ log(
258
+ `npm pack dry-run omitted ${missingRequired.length} ignored generated asset(s); verified package.json#files policy and on-disk assets`
259
+ );
260
+ }
261
+
262
+ for (const forbiddenPrefix of [
263
+ 'node_modules/',
264
+ '.rapidkit/',
265
+ '.venv/',
266
+ 'coverage/',
267
+ 'test-results/',
268
+ 'src/',
269
+ ]) {
270
+ const leaked = [...files].find((entry) => entry.startsWith(forbiddenPrefix));
271
+ if (leaked) {
272
+ fail(`npm pack payload leaks dev/local artifact: ${leaked}`);
273
+ }
274
+ }
275
+
276
+ log(`verified npm pack payload (${files.size} files)`);
277
+ }
278
+
279
+ function assertCliContracts() {
280
+ const version = parseTrailingJson(runCli(['--version', '--json']));
281
+ if (version.schemaVersion !== 'rapidkit-version-v1') {
282
+ fail(`unexpected version schema: ${version.schemaVersion}`);
283
+ }
284
+ if (!version.contracts?.runtimeCommandSurface) {
285
+ fail('version contract does not advertise runtimeCommandSurface');
286
+ }
287
+
288
+ const commands = parseTrailingJson(runCli(['commands', '--json']));
289
+ if (commands.schemaVersion !== 'rapidkit-command-capabilities-v1') {
290
+ fail(`unexpected commands schema: ${commands.schemaVersion}`);
291
+ }
292
+ for (const topLevel of ['create', 'workspace', 'doctor', 'bootstrap']) {
293
+ if (!commands.commandMap?.[topLevel]) {
294
+ fail(`commands surface is missing top-level command: ${topLevel}`);
295
+ }
296
+ }
297
+ for (const subcommand of ['model', 'snapshot', 'diff', 'impact', 'verify', 'context', 'explain']) {
298
+ if (!commands.workspace?.intelligenceSubcommands?.includes(subcommand)) {
299
+ fail(`workspace intelligence surface is missing subcommand: ${subcommand}`);
300
+ }
301
+ }
302
+
303
+ log(`verified CLI contract surfaces for v${version.version}`);
304
+ }
305
+
306
+ function assertGeneratedProject(projectPath, expectedFiles) {
307
+ for (const relativePath of expectedFiles) {
308
+ const absolutePath = path.join(projectPath, relativePath);
309
+ if (!fs.existsSync(absolutePath)) {
310
+ fail(`generated project ${path.basename(projectPath)} is missing ${relativePath}`);
311
+ }
312
+ }
313
+ }
314
+
315
+ function smokeCreateNpmBackedKits() {
316
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rapidkit-enterprise-smoke-'));
317
+ const scenarios = [
318
+ {
319
+ kit: 'gofiber.standard',
320
+ name: 'enterprise-fiber',
321
+ extraArgs: [],
322
+ expectedFiles: ['go.mod', 'cmd/server/main.go', '.workspai/project.json', 'rapidkit'],
323
+ },
324
+ {
325
+ kit: 'gogin.standard',
326
+ name: 'enterprise-gin',
327
+ extraArgs: [],
328
+ expectedFiles: ['go.mod', 'cmd/server/main.go', '.workspai/project.json', 'rapidkit'],
329
+ },
330
+ {
331
+ kit: 'springboot.standard',
332
+ name: 'enterprise-spring',
333
+ extraArgs: ['--java-version', '21'],
334
+ expectedFiles: ['pom.xml', 'src/main/resources/application.yml', '.workspai/project.json', 'rapidkit'],
335
+ },
336
+ {
337
+ kit: 'dotnet.webapi.clean',
338
+ name: 'enterprise-dotnet',
339
+ extraArgs: ['--target-framework', 'net8.0'],
340
+ expectedFiles: ['src/Program.cs', 'src/enterprise-dotnet.csproj', '.workspai/project.json', 'rapidkit'],
341
+ },
342
+ ];
343
+
344
+ try {
345
+ for (const scenario of scenarios) {
346
+ const args = [
347
+ cliPath,
348
+ 'create',
349
+ 'project',
350
+ scenario.kit,
351
+ scenario.name,
352
+ '--output',
353
+ tempDir,
354
+ '--skip-git',
355
+ '--skip-install',
356
+ ...scenario.extraArgs,
357
+ ];
358
+ const result = spawnSync(process.execPath, args, {
359
+ cwd: tempDir,
360
+ encoding: 'utf8',
361
+ env: cliEnv(),
362
+ stdio: ['ignore', 'pipe', 'pipe'],
363
+ });
364
+ if (result.status !== 0) {
365
+ fail(
366
+ `${scenario.kit} smoke create failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
367
+ );
368
+ }
369
+ assertGeneratedProject(path.join(tempDir, scenario.name), scenario.expectedFiles);
370
+ }
371
+ } finally {
372
+ fs.rmSync(tempDir, { recursive: true, force: true });
373
+ }
374
+
375
+ log(`verified ${scenarios.length} npm-backed create scenarios`);
376
+ }
377
+
378
+ function smokeCreateOfflineFallbackKits() {
379
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rapidkit-enterprise-fallback-'));
380
+ const scenarios = [
381
+ {
382
+ kit: 'fastapi.standard',
383
+ name: 'enterprise-fastapi',
384
+ expectedFiles: [
385
+ 'pyproject.toml',
386
+ 'src/main.py',
387
+ 'src/routing/health.py',
388
+ 'src/routing/examples.py',
389
+ 'tests/test_health.py',
390
+ 'tests/test_examples.py',
391
+ '.env.example',
392
+ '.workspai/project.json',
393
+ 'rapidkit',
394
+ ],
395
+ },
396
+ {
397
+ kit: 'nestjs.standard',
398
+ name: 'enterprise-nestjs',
399
+ expectedFiles: [
400
+ 'package.json',
401
+ 'src/main.ts',
402
+ 'src/examples/examples.module.ts',
403
+ '.env.example',
404
+ '.workspai/project.json',
405
+ 'rapidkit',
406
+ ],
407
+ },
408
+ ];
409
+
410
+ try {
411
+ for (const scenario of scenarios) {
412
+ const result = spawnSync(
413
+ process.execPath,
414
+ [
415
+ cliPath,
416
+ 'create',
417
+ 'project',
418
+ scenario.kit,
419
+ scenario.name,
420
+ '--output',
421
+ tempDir,
422
+ '--skip-git',
423
+ '--skip-install',
424
+ ],
425
+ {
426
+ cwd: tempDir,
427
+ encoding: 'utf8',
428
+ env: cliEnv({
429
+ RAPIDKIT_FORCE_OFFLINE_CREATE_FALLBACK: '1',
430
+ }),
431
+ stdio: ['ignore', 'pipe', 'pipe'],
432
+ }
433
+ );
434
+ if (result.status !== 0) {
435
+ fail(
436
+ `${scenario.kit} offline fallback smoke failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
437
+ );
438
+ }
439
+ assertGeneratedProject(path.join(tempDir, scenario.name), scenario.expectedFiles);
440
+ }
441
+ } finally {
442
+ fs.rmSync(tempDir, { recursive: true, force: true });
443
+ }
444
+
445
+ log(`verified ${scenarios.length} offline fallback create scenarios`);
446
+ }
447
+
448
+ for (const relativePath of [
449
+ 'package.json',
450
+ 'dist/index.js',
451
+ 'contracts/runtime-command-surface.v1.json',
452
+ 'contracts/extension-cli-compatibility.v1.json',
453
+ 'data/modules-embeddings.json',
454
+ ]) {
455
+ assertFile(relativePath);
456
+ }
457
+
458
+ assertPackContents();
459
+ assertCliContracts();
460
+ smokeCreateNpmBackedKits();
461
+ smokeCreateOfflineFallbackKits();
462
+
463
+ log('enterprise package smoke passed');
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import process from 'node:process';
7
+
8
+ const repoRoot = process.cwd();
9
+
10
+ function fail(message) {
11
+ console.error(`[prepack-enterprise] ${message}`);
12
+ process.exit(1);
13
+ }
14
+
15
+ function runNode(args, label, extraEnv = {}) {
16
+ console.log(`[prepack-enterprise] ${label}`);
17
+ execFileSync(process.execPath, args, {
18
+ cwd: repoRoot,
19
+ stdio: 'inherit',
20
+ env: {
21
+ ...process.env,
22
+ ...extraEnv,
23
+ npm_config_user_agent: process.env.npm_config_user_agent || 'npm/10 workspai-prepack',
24
+ },
25
+ });
26
+ }
27
+
28
+ let tsupCli = path.join(repoRoot, 'node_modules', 'tsup', 'dist', 'cli-default.js');
29
+ if (!fs.existsSync(tsupCli)) {
30
+ tsupCli = path.join(repoRoot, '..', '..', 'node_modules', 'tsup', 'dist', 'cli-default.js');
31
+ }
32
+ if (!fs.existsSync(tsupCli)) {
33
+ fail(`missing tsup CLI at ${tsupCli}; run npm ci before packaging`);
34
+ }
35
+
36
+ runNode([tsupCli], 'building dist');
37
+ runNode(['scripts/prepare-mock-embeddings.mjs'], 'preparing packaged embeddings');
38
+ runNode(['scripts/verify-package-cli.mjs'], 'verifying bundled CLI command ownership');
39
+ runNode(['scripts/enterprise-package-smoke.mjs'], 'running enterprise package smoke', {
40
+ RAPIDKIT_ENTERPRISE_PREPACK: '1',
41
+ });
42
+
43
+ console.log('[prepack-enterprise] prepack checks passed');