@velum-labs/cursorkit 0.1.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 (142) hide show
  1. package/DISCLAIMER.md +12 -0
  2. package/README.md +157 -0
  3. package/dist/src/agentTools/diff.d.ts +11 -0
  4. package/dist/src/agentTools/diff.js +88 -0
  5. package/dist/src/agentTools/policy.d.ts +3 -0
  6. package/dist/src/agentTools/policy.js +12 -0
  7. package/dist/src/agentTools/registry.d.ts +114 -0
  8. package/dist/src/agentTools/registry.js +663 -0
  9. package/dist/src/agentTools/results.d.ts +14 -0
  10. package/dist/src/agentTools/results.js +117 -0
  11. package/dist/src/agentTools/schemas.d.ts +3 -0
  12. package/dist/src/agentTools/schemas.js +89 -0
  13. package/dist/src/agentTools/surface.d.ts +11 -0
  14. package/dist/src/agentTools/surface.js +251 -0
  15. package/dist/src/certs.d.ts +8 -0
  16. package/dist/src/certs.js +34 -0
  17. package/dist/src/ck.d.ts +2 -0
  18. package/dist/src/ck.js +6 -0
  19. package/dist/src/ckLauncher.d.ts +150 -0
  20. package/dist/src/ckLauncher.js +1496 -0
  21. package/dist/src/cli.d.ts +2 -0
  22. package/dist/src/cli.js +265 -0
  23. package/dist/src/config.d.ts +52 -0
  24. package/dist/src/config.js +210 -0
  25. package/dist/src/connectEnvelope.d.ts +16 -0
  26. package/dist/src/connectEnvelope.js +70 -0
  27. package/dist/src/desktop.d.ts +19 -0
  28. package/dist/src/desktop.js +167 -0
  29. package/dist/src/desktopConnectProxy.d.ts +26 -0
  30. package/dist/src/desktopConnectProxy.js +175 -0
  31. package/dist/src/extensions/index.d.ts +2 -0
  32. package/dist/src/extensions/index.js +1 -0
  33. package/dist/src/extensions/registry.d.ts +8 -0
  34. package/dist/src/extensions/registry.js +52 -0
  35. package/dist/src/extensions/types.d.ts +42 -0
  36. package/dist/src/extensions/types.js +1 -0
  37. package/dist/src/fixtures/modelFusion.d.ts +103 -0
  38. package/dist/src/fixtures/modelFusion.js +404 -0
  39. package/dist/src/fixtures/replay.d.ts +9 -0
  40. package/dist/src/fixtures/replay.js +41 -0
  41. package/dist/src/fixtures/sanitizer.d.ts +9 -0
  42. package/dist/src/fixtures/sanitizer.js +43 -0
  43. package/dist/src/fixtures/schema.d.ts +38 -0
  44. package/dist/src/fixtures/schema.js +33 -0
  45. package/dist/src/gen/agent/v1/agent_pb.d.ts +21577 -0
  46. package/dist/src/gen/agent/v1/agent_pb.js +5325 -0
  47. package/dist/src/gen/aiserver/v1/aiserver_pb.d.ts +135242 -0
  48. package/dist/src/gen/aiserver/v1/aiserver_pb.js +34430 -0
  49. package/dist/src/gen/anyrun/v1/anyrun_pb.d.ts +1163 -0
  50. package/dist/src/gen/anyrun/v1/anyrun_pb.js +374 -0
  51. package/dist/src/gen/google/protobuf/google_pb.d.ts +142 -0
  52. package/dist/src/gen/google/protobuf/google_pb.js +54 -0
  53. package/dist/src/gen/internapi/v1/internapi_pb.d.ts +121 -0
  54. package/dist/src/gen/internapi/v1/internapi_pb.js +79 -0
  55. package/dist/src/logger.d.ts +8 -0
  56. package/dist/src/logger.js +37 -0
  57. package/dist/src/modelFusion/cursorHarness.d.ts +146 -0
  58. package/dist/src/modelFusion/cursorHarness.js +647 -0
  59. package/dist/src/modelFusion/index.d.ts +4 -0
  60. package/dist/src/modelFusion/index.js +2 -0
  61. package/dist/src/models/registry.d.ts +22 -0
  62. package/dist/src/models/registry.js +30 -0
  63. package/dist/src/proto.d.ts +13 -0
  64. package/dist/src/proto.js +61 -0
  65. package/dist/src/providers/openai.d.ts +64 -0
  66. package/dist/src/providers/openai.js +355 -0
  67. package/dist/src/redaction.d.ts +4 -0
  68. package/dist/src/redaction.js +65 -0
  69. package/dist/src/routeInventory.d.ts +16 -0
  70. package/dist/src/routeInventory.js +39 -0
  71. package/dist/src/routes.d.ts +37 -0
  72. package/dist/src/routes.js +227 -0
  73. package/dist/src/server.d.ts +50 -0
  74. package/dist/src/server.js +1353 -0
  75. package/dist/src/services/agent.d.ts +1 -0
  76. package/dist/src/services/agent.js +7 -0
  77. package/dist/src/services/agentRun.d.ts +60 -0
  78. package/dist/src/services/agentRun.js +391 -0
  79. package/dist/src/services/chat.d.ts +11 -0
  80. package/dist/src/services/chat.js +47 -0
  81. package/dist/src/services/models.d.ts +10 -0
  82. package/dist/src/services/models.js +216 -0
  83. package/dist/src/services/serverConfig.d.ts +2 -0
  84. package/dist/src/services/serverConfig.js +19 -0
  85. package/dist/src/testing/artifacts.d.ts +14 -0
  86. package/dist/src/testing/artifacts.js +92 -0
  87. package/dist/src/testing/cli.d.ts +4 -0
  88. package/dist/src/testing/cli.js +192 -0
  89. package/dist/src/testing/localBackend.d.ts +24 -0
  90. package/dist/src/testing/localBackend.js +310 -0
  91. package/dist/src/testing/processRunner.d.ts +7 -0
  92. package/dist/src/testing/processRunner.js +74 -0
  93. package/dist/src/testing/runner.d.ts +9 -0
  94. package/dist/src/testing/runner.js +85 -0
  95. package/dist/src/testing/scenarios.d.ts +3 -0
  96. package/dist/src/testing/scenarios.js +2535 -0
  97. package/dist/src/testing/types.d.ts +66 -0
  98. package/dist/src/testing/types.js +1 -0
  99. package/dist/src/tools/baselineInventory.d.ts +12 -0
  100. package/dist/src/tools/baselineInventory.js +680 -0
  101. package/dist/src/tools/checkModelFusionProtocol.d.ts +1 -0
  102. package/dist/src/tools/checkModelFusionProtocol.js +274 -0
  103. package/dist/src/tools/checkReleasePublishConfig.d.ts +1 -0
  104. package/dist/src/tools/checkReleasePublishConfig.js +99 -0
  105. package/dist/src/tools/generateProtoInventory.d.ts +1 -0
  106. package/dist/src/tools/generateProtoInventory.js +89 -0
  107. package/dist/src/tools/normalizeGeneratedCode.d.ts +1 -0
  108. package/dist/src/tools/normalizeGeneratedCode.js +18 -0
  109. package/dist/src/tools/releaseCheck.d.ts +26 -0
  110. package/dist/src/tools/releaseCheck.js +367 -0
  111. package/dist/src/trace.d.ts +39 -0
  112. package/dist/src/trace.js +106 -0
  113. package/dist/src/translation.d.ts +6 -0
  114. package/dist/src/translation.js +22 -0
  115. package/dist/src/upstream.d.ts +20 -0
  116. package/dist/src/upstream.js +270 -0
  117. package/docs/configuration.md +55 -0
  118. package/docs/cursor-app.md +263 -0
  119. package/docs/implementation-inventory.json +609 -0
  120. package/docs/learnings.md +363 -0
  121. package/docs/model-fusion-protocol-origin.json +126 -0
  122. package/docs/model-fusion-protocol.md +110 -0
  123. package/docs/plugin-authoring.md +24 -0
  124. package/docs/proto-inventory.md +1477 -0
  125. package/docs/protocol-surface-audit.md +92 -0
  126. package/docs/protocol.md +52 -0
  127. package/docs/refreshing-protos.md +78 -0
  128. package/docs/release-gates.md +110 -0
  129. package/docs/release-summary.json +86 -0
  130. package/docs/route-contract-manifest.json +288 -0
  131. package/docs/route-policy.json +133 -0
  132. package/docs/service-manifest.json +9490 -0
  133. package/docs/test-manifest.json +155 -0
  134. package/docs/testing-harness.md +204 -0
  135. package/docs/troubleshooting.md +36 -0
  136. package/docs/type-manifest-summary.json +28927 -0
  137. package/package.json +93 -0
  138. package/proto/agent/v1/agent.proto +5371 -0
  139. package/proto/aiserver/v1/aiserver.proto +32944 -0
  140. package/proto/anyrun/v1/anyrun.proto +294 -0
  141. package/proto/google/protobuf/google.proto +37 -0
  142. package/proto/internapi/v1/internapi.proto +32 -0
@@ -0,0 +1,274 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { MODEL_FUSION_SCHEMA_BUNDLE_HASH } from "../fixtures/modelFusion.js";
5
+ const ROOT = process.cwd();
6
+ const ORIGIN_MANIFEST_PATH = "docs/model-fusion-protocol-origin.json";
7
+ const PROTOCOL_DOC_PATH = "docs/model-fusion-protocol.md";
8
+ const PACKAGE_JSON_PATH = "package.json";
9
+ const PROTOCOL_PACKAGE_NAME = "@velum-labs/model-fusion-protocol";
10
+ const CONTRACT_FIXTURE_ROOT = "fixtures/model-fusion-contract";
11
+ const CURSOR_HARNESS_PROTO_PATH = "proto/model_fusion/v1/cursor_harness.proto";
12
+ const CURSOR_HARNESS_TS_PATH = "src/gen/model_fusion/v1/cursor_harness_pb.ts";
13
+ const CURSOR_HARNESS_OPENAPI_PATH = "docs/model-fusion-cursor-harness.openapi.yaml";
14
+ const CURSOR_HARNESS_OPENAPI_TS_PATH = "src/gen/model_fusion/cursor_harness_openapi.ts";
15
+ export function checkModelFusionProtocol() {
16
+ const errors = [];
17
+ const manifest = readManifest(errors);
18
+ const packageJson = readPackageJson(errors);
19
+ if (manifest !== undefined) {
20
+ checkManifest(manifest, packageJson, errors);
21
+ }
22
+ checkFixtureBundleHashes(errors);
23
+ checkNoLocalProtocolMirrors(errors);
24
+ checkProtocolDocs(errors);
25
+ return errors;
26
+ }
27
+ function readManifest(errors) {
28
+ try {
29
+ return JSON.parse(fs.readFileSync(resolvePath(ORIGIN_MANIFEST_PATH), "utf8"));
30
+ }
31
+ catch (error) {
32
+ errors.push(`${ORIGIN_MANIFEST_PATH}: ${error instanceof Error ? error.message : String(error)}`);
33
+ return undefined;
34
+ }
35
+ }
36
+ function readPackageJson(errors) {
37
+ try {
38
+ return JSON.parse(fs.readFileSync(resolvePath(PACKAGE_JSON_PATH), "utf8"));
39
+ }
40
+ catch (error) {
41
+ errors.push(`${PACKAGE_JSON_PATH}: ${error instanceof Error ? error.message : String(error)}`);
42
+ return undefined;
43
+ }
44
+ }
45
+ function checkManifest(manifest, packageJson, errors) {
46
+ if (manifest.schemaVersion !== 1) {
47
+ errors.push(`${ORIGIN_MANIFEST_PATH}: schemaVersion must be 1`);
48
+ }
49
+ if (manifest.canonicalSpec !==
50
+ "https://github.com/velum-labs/openclaw-shared/blob/main/spec/2026-06-16-model-fusion-protocol-packaging-spec.md") {
51
+ errors.push(`${ORIGIN_MANIFEST_PATH}: canonicalSpec must point at the shared protocol packaging spec`);
52
+ }
53
+ if (manifest.schemaBundleHash !== MODEL_FUSION_SCHEMA_BUNDLE_HASH) {
54
+ errors.push(`${ORIGIN_MANIFEST_PATH}: schemaBundleHash ${manifest.schemaBundleHash} does not match MODEL_FUSION_SCHEMA_BUNDLE_HASH ${MODEL_FUSION_SCHEMA_BUNDLE_HASH}`);
55
+ }
56
+ if (manifest.serviceIdl?.sourceOfTruth !== "openapi-3.1") {
57
+ errors.push(`${ORIGIN_MANIFEST_PATH}: serviceIdl.sourceOfTruth must be openapi-3.1`);
58
+ }
59
+ if (manifest.serviceIdl?.openapi !== "v1-http-json-source-of-truth") {
60
+ errors.push(`${ORIGIN_MANIFEST_PATH}: serviceIdl.openapi must be v1-http-json-source-of-truth`);
61
+ }
62
+ if (manifest.protobufBuf?.v1Required !== false) {
63
+ errors.push(`${ORIGIN_MANIFEST_PATH}: protobufBuf.v1Required must be false`);
64
+ }
65
+ if (manifest.protobufBuf?.status !==
66
+ "reserved-for-future-internal-streaming-connect-grpc") {
67
+ errors.push(`${ORIGIN_MANIFEST_PATH}: protobufBuf.status must reserve protobuf/Buf for future internal streaming/Connect/gRPC`);
68
+ }
69
+ if (manifest.persistedRecordFormat?.sourceOfTruth !== "json-schema") {
70
+ errors.push(`${ORIGIN_MANIFEST_PATH}: persistedRecordFormat.sourceOfTruth must be json-schema`);
71
+ }
72
+ checkPackageConsumptionOrBlocker(manifest, packageJson, errors);
73
+ for (const schema of [
74
+ "harness-run-request.v1",
75
+ "harness-run-result.v1",
76
+ "cursor-run-request.v1",
77
+ "cursor-run-result.v1",
78
+ ]) {
79
+ if (!manifest.persistedJsonSchemas.includes(schema)) {
80
+ errors.push(`${ORIGIN_MANIFEST_PATH}: missing persisted JSON schema ${schema}`);
81
+ }
82
+ }
83
+ if (manifest.packages?.typescript?.name !== "@velum-labs/model-fusion-protocol") {
84
+ errors.push(`${ORIGIN_MANIFEST_PATH}: TypeScript package target must be @velum-labs/model-fusion-protocol`);
85
+ }
86
+ if (manifest.packages?.typescript?.generatedFrom !==
87
+ "fusionkit JSON Schema and OpenAPI 3.1 contracts") {
88
+ errors.push(`${ORIGIN_MANIFEST_PATH}: TypeScript package must be generated from fusionkit JSON Schema and OpenAPI 3.1 contracts`);
89
+ }
90
+ const pythonIndexes = manifest.packages?.python?.preferredPrivateIndexes ?? [];
91
+ for (const index of ["Cloudsmith", "CodeArtifact", "Gemfury"]) {
92
+ if (!pythonIndexes.includes(index)) {
93
+ errors.push(`${ORIGIN_MANIFEST_PATH}: Python private index plan must include ${index}`);
94
+ }
95
+ }
96
+ const shortTermOptions = manifest.packages?.python?.shortTermOptions ?? [];
97
+ if (!shortTermOptions.includes("GitHub Releases wheels") ||
98
+ !shortTermOptions.includes("uv git deps")) {
99
+ errors.push(`${ORIGIN_MANIFEST_PATH}: Python short-term plan must include GitHub Releases wheels and uv git deps`);
100
+ }
101
+ if (manifest.packages?.python?.generatedFrom !==
102
+ "fusionkit JSON Schema and OpenAPI 3.1 contracts") {
103
+ errors.push(`${ORIGIN_MANIFEST_PATH}: Python package must be generated from fusionkit JSON Schema and OpenAPI 3.1 contracts`);
104
+ }
105
+ const cursorBoundary = manifest.serviceBoundaries?.find((boundary) => boundary.service === "CursorHarnessHttpApi");
106
+ if (cursorBoundary?.openapi !== undefined) {
107
+ errors.push(`${ORIGIN_MANIFEST_PATH}: CursorHarnessHttpApi must not point at a local OpenAPI mirror while @velum-labs/model-fusion-protocol is unavailable`);
108
+ }
109
+ if (cursorBoundary?.canonicalSource !== "fusionkit") {
110
+ errors.push(`${ORIGIN_MANIFEST_PATH}: CursorHarnessHttpApi canonicalSource must be fusionkit`);
111
+ }
112
+ const followUps = manifest.followUpWorkOutsideCursorkit ?? [];
113
+ for (const expected of [
114
+ "OpenAPI 3.1 source",
115
+ "@velum-labs/model-fusion-protocol",
116
+ "velum-model-fusion-protocol wheels",
117
+ "TS OpenAPI client/types",
118
+ "TS durable-record validators/types",
119
+ "Python OpenAPI client/models",
120
+ "JSON Schema/Pydantic validators",
121
+ "JSON Schema bundle metadata",
122
+ ]) {
123
+ if (!followUps.some((item) => item.includes(expected))) {
124
+ errors.push(`${ORIGIN_MANIFEST_PATH}: followUpWorkOutsideCursorkit must mention ${expected}`);
125
+ }
126
+ }
127
+ }
128
+ function checkPackageConsumptionOrBlocker(manifest, packageJson, errors) {
129
+ const consumedVersion = packageJson?.dependencies?.[PROTOCOL_PACKAGE_NAME] ??
130
+ packageJson?.devDependencies?.[PROTOCOL_PACKAGE_NAME];
131
+ if (consumedVersion !== undefined) {
132
+ const pin = packageJson?.modelFusionProtocol;
133
+ if (pin?.packageName !== PROTOCOL_PACKAGE_NAME) {
134
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.packageName must be ${PROTOCOL_PACKAGE_NAME}`);
135
+ }
136
+ if (pin?.schemaBundleHash !== manifest.schemaBundleHash) {
137
+ errors.push(`${PACKAGE_JSON_PATH}: consumed protocol package schema bundle hash must match ${ORIGIN_MANIFEST_PATH}`);
138
+ }
139
+ if (pin?.version !== consumedVersion.replace(/^[~^]/, "")) {
140
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.version must match consumed ${PROTOCOL_PACKAGE_NAME} version`);
141
+ }
142
+ checkInstalledProtocolPackageMetadata(manifest, pin, errors);
143
+ return;
144
+ }
145
+ if (manifest.packages?.typescript?.currentStatus !==
146
+ "blocked-missing-registry-package") {
147
+ errors.push(`${ORIGIN_MANIFEST_PATH}: packages.typescript.currentStatus must document blocked-missing-registry-package when ${PROTOCOL_PACKAGE_NAME} is absent`);
148
+ }
149
+ if (manifest.mergeBlocker?.status !== "blocked") {
150
+ errors.push(`${ORIGIN_MANIFEST_PATH}: mergeBlocker.status must be blocked`);
151
+ }
152
+ if (!manifest.mergeBlocker?.reason?.includes(PROTOCOL_PACKAGE_NAME)) {
153
+ errors.push(`${ORIGIN_MANIFEST_PATH}: mergeBlocker.reason must mention ${PROTOCOL_PACKAGE_NAME}`);
154
+ }
155
+ for (const expected of [
156
+ `Publish ${PROTOCOL_PACKAGE_NAME}`,
157
+ `Add ${PROTOCOL_PACKAGE_NAME}`,
158
+ "Replace local model-fusion contract mirrors",
159
+ "schema bundle hash matches",
160
+ ]) {
161
+ if (!manifest.mergeBlocker?.requiredBeforeReady?.some((item) => item.includes(expected))) {
162
+ errors.push(`${ORIGIN_MANIFEST_PATH}: mergeBlocker.requiredBeforeReady must mention ${expected}`);
163
+ }
164
+ }
165
+ }
166
+ function checkInstalledProtocolPackageMetadata(manifest, pin, errors) {
167
+ const packageMetadataPath = resolvePath("node_modules/@velum-labs/model-fusion-protocol/protocol-package.json");
168
+ let metadata;
169
+ try {
170
+ metadata = JSON.parse(fs.readFileSync(packageMetadataPath, "utf8"));
171
+ }
172
+ catch (error) {
173
+ errors.push(`${PROTOCOL_PACKAGE_NAME}: installed protocol-package.json is required: ${error instanceof Error ? error.message : String(error)}`);
174
+ return;
175
+ }
176
+ if (metadata.package_name !== PROTOCOL_PACKAGE_NAME) {
177
+ errors.push(`${PROTOCOL_PACKAGE_NAME}: protocol-package.json package_name must be ${PROTOCOL_PACKAGE_NAME}`);
178
+ }
179
+ if (metadata.version !== pin?.version) {
180
+ errors.push(`${PROTOCOL_PACKAGE_NAME}: protocol-package.json version must match ${PACKAGE_JSON_PATH} modelFusionProtocol.version`);
181
+ }
182
+ if (metadata.schema_bundle_hash !== manifest.schemaBundleHash) {
183
+ errors.push(`${PROTOCOL_PACKAGE_NAME}: protocol-package.json schema_bundle_hash must match ${ORIGIN_MANIFEST_PATH}`);
184
+ }
185
+ }
186
+ function checkFixtureBundleHashes(errors) {
187
+ for (const fixturePath of listJsonFiles(resolvePath(CONTRACT_FIXTURE_ROOT))) {
188
+ const relativePath = path.relative(ROOT, fixturePath);
189
+ const parsed = JSON.parse(fs.readFileSync(fixturePath, "utf8"));
190
+ if (parsed.schema_bundle_hash !== MODEL_FUSION_SCHEMA_BUNDLE_HASH) {
191
+ errors.push(`${relativePath}: schema_bundle_hash ${String(parsed.schema_bundle_hash)} does not match ${MODEL_FUSION_SCHEMA_BUNDLE_HASH}`);
192
+ }
193
+ }
194
+ }
195
+ function checkNoLocalProtocolMirrors(errors) {
196
+ for (const relativePath of [
197
+ CURSOR_HARNESS_PROTO_PATH,
198
+ CURSOR_HARNESS_TS_PATH,
199
+ CURSOR_HARNESS_OPENAPI_PATH,
200
+ CURSOR_HARNESS_OPENAPI_TS_PATH,
201
+ ]) {
202
+ if (fs.existsSync(resolvePath(relativePath))) {
203
+ errors.push(`${relativePath}: local model-fusion protocol mirrors are not merge-ready; consume ${PROTOCOL_PACKAGE_NAME} or document the missing-package blocker`);
204
+ }
205
+ }
206
+ }
207
+ function checkProtocolDocs(errors) {
208
+ const doc = readRequiredText(PROTOCOL_DOC_PATH, errors);
209
+ if (doc === undefined) {
210
+ return;
211
+ }
212
+ const normalizedDoc = doc.replace(/\s+/g, " ");
213
+ for (const expected of [
214
+ "fusionkit",
215
+ "@velum-labs/model-fusion-protocol",
216
+ "OpenAPI 3.1 is the source of truth",
217
+ "Service/API clients and request/response models should be generated from OpenAPI specs",
218
+ "Durable record validators and record types should be generated from the JSON Schema bundle",
219
+ "JSON Schema remains the persisted audit and benchmark record format",
220
+ "Protobuf/Buf is reserved for later internal streaming",
221
+ "openapi-typescript",
222
+ "openapi-fetch",
223
+ "openapi-python-client",
224
+ "datamodel-code-generator",
225
+ "Published package consumption",
226
+ "installed as a cursorkit dev dependency",
227
+ "Cloudsmith",
228
+ "CodeArtifact",
229
+ "Gemfury",
230
+ "GitHub Releases wheels",
231
+ "uv",
232
+ "HarnessExecutorService",
233
+ "Cursor harness OpenAPI",
234
+ "MlxProviderService",
235
+ "Benchmark execution",
236
+ "Follow-up outside cursorkit",
237
+ ]) {
238
+ if (!normalizedDoc.includes(expected)) {
239
+ errors.push(`${PROTOCOL_DOC_PATH}: missing ${expected}`);
240
+ }
241
+ }
242
+ }
243
+ function readRequiredText(relativePath, errors) {
244
+ try {
245
+ return fs.readFileSync(resolvePath(relativePath), "utf8");
246
+ }
247
+ catch (error) {
248
+ errors.push(`${relativePath}: ${error instanceof Error ? error.message : String(error)}`);
249
+ return undefined;
250
+ }
251
+ }
252
+ function listJsonFiles(directory) {
253
+ const entries = fs.readdirSync(directory, { withFileTypes: true });
254
+ return entries.flatMap((entry) => {
255
+ const fullPath = path.join(directory, entry.name);
256
+ if (entry.isDirectory()) {
257
+ return listJsonFiles(fullPath);
258
+ }
259
+ return entry.isFile() && entry.name.endsWith(".json") ? [fullPath] : [];
260
+ });
261
+ }
262
+ function resolvePath(relativePath) {
263
+ return path.resolve(ROOT, relativePath);
264
+ }
265
+ if (process.argv[1] !== undefined &&
266
+ import.meta.url === pathToFileURL(process.argv[1]).href) {
267
+ const errors = checkModelFusionProtocol();
268
+ if (errors.length > 0) {
269
+ for (const error of errors) {
270
+ console.error(error);
271
+ }
272
+ process.exitCode = 1;
273
+ }
274
+ }
@@ -0,0 +1 @@
1
+ export declare function checkReleasePublishConfig(repoRoot?: string): string[];
@@ -0,0 +1,99 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { MODEL_FUSION_SCHEMA_BUNDLE_HASH } from "../fixtures/modelFusion.js";
5
+ const PACKAGE_JSON_PATH = "package.json";
6
+ const PROTOCOL_ORIGIN_PATH = "docs/model-fusion-protocol-origin.json";
7
+ const PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org";
8
+ const CANONICAL_PACKAGE_NAME = "@velum-labs/cursorkit";
9
+ const CANONICAL_REPOSITORY_URL = "git+https://github.com/velum-labs/cursorkit.git";
10
+ const PROTOCOL_PACKAGE_NAME = "@velum-labs/model-fusion-protocol";
11
+ const PROTOCOL_CONTRACTS = "json-schema+openapi-3.1";
12
+ export function checkReleasePublishConfig(repoRoot = process.cwd()) {
13
+ const errors = [];
14
+ const packageJson = readJson(repoRoot, PACKAGE_JSON_PATH, errors);
15
+ const protocolOrigin = readJson(repoRoot, PROTOCOL_ORIGIN_PATH, errors);
16
+ if (packageJson === undefined || protocolOrigin === undefined) {
17
+ return errors;
18
+ }
19
+ checkPackageMetadata(packageJson, errors);
20
+ checkProtocolPin(packageJson, protocolOrigin, errors);
21
+ return errors;
22
+ }
23
+ function checkPackageMetadata(packageJson, errors) {
24
+ if (packageJson.name !== CANONICAL_PACKAGE_NAME) {
25
+ errors.push(`${PACKAGE_JSON_PATH}: name must be ${CANONICAL_PACKAGE_NAME}`);
26
+ }
27
+ if (packageJson.repository?.url !== CANONICAL_REPOSITORY_URL) {
28
+ errors.push(`${PACKAGE_JSON_PATH}: repository.url must be ${CANONICAL_REPOSITORY_URL}`);
29
+ }
30
+ // @velum-labs/cursorkit publishes to public npm (no manual deploys): the release
31
+ // workflow runs only on a reviewed GitHub Release and publishes with
32
+ // provenance, so the publish posture is asserted here.
33
+ if (packageJson.publishConfig?.registry !== PUBLIC_NPM_REGISTRY) {
34
+ errors.push(`${PACKAGE_JSON_PATH}: publishConfig.registry must be ${PUBLIC_NPM_REGISTRY}`);
35
+ }
36
+ if (packageJson.publishConfig?.access !== "public") {
37
+ errors.push(`${PACKAGE_JSON_PATH}: publishConfig.access must be public`);
38
+ }
39
+ if (packageJson.publishConfig?.provenance !== true) {
40
+ errors.push(`${PACKAGE_JSON_PATH}: publishConfig.provenance must be true for supply-chain provenance`);
41
+ }
42
+ if (packageJson.private !== false) {
43
+ errors.push(`${PACKAGE_JSON_PATH}: private must be false so the release workflow can publish`);
44
+ }
45
+ }
46
+ function checkProtocolPin(packageJson, protocolOrigin, errors) {
47
+ const pin = packageJson.modelFusionProtocol;
48
+ if (pin === undefined) {
49
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol pin is required`);
50
+ return;
51
+ }
52
+ if (pin.packageName !== PROTOCOL_PACKAGE_NAME) {
53
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.packageName must be ${PROTOCOL_PACKAGE_NAME}`);
54
+ }
55
+ if (pin.version === undefined ||
56
+ !/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(pin.version)) {
57
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.version must be a pinned semver version`);
58
+ }
59
+ if (pin.schemaBundleHash !== MODEL_FUSION_SCHEMA_BUNDLE_HASH) {
60
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.schemaBundleHash must match ${MODEL_FUSION_SCHEMA_BUNDLE_HASH}`);
61
+ }
62
+ if (pin.schemaBundleHash !== protocolOrigin.schemaBundleHash) {
63
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.schemaBundleHash must match ${PROTOCOL_ORIGIN_PATH}`);
64
+ }
65
+ if (pin.packageName !== protocolOrigin.packages?.typescript?.name) {
66
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.packageName must match ${PROTOCOL_ORIGIN_PATH}`);
67
+ }
68
+ if (pin.contracts !== PROTOCOL_CONTRACTS) {
69
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.contracts must be ${PROTOCOL_CONTRACTS}`);
70
+ }
71
+ if (pin.origin !== "fusionkit") {
72
+ errors.push(`${PACKAGE_JSON_PATH}: modelFusionProtocol.origin must be fusionkit`);
73
+ }
74
+ if (protocolOrigin.serviceIdl?.sourceOfTruth !== "openapi-3.1") {
75
+ errors.push(`${PROTOCOL_ORIGIN_PATH}: serviceIdl.sourceOfTruth must be openapi-3.1 for v1 release publishing`);
76
+ }
77
+ if (protocolOrigin.persistedRecordFormat?.sourceOfTruth !== "json-schema") {
78
+ errors.push(`${PROTOCOL_ORIGIN_PATH}: persistedRecordFormat.sourceOfTruth must be json-schema for v1 release publishing`);
79
+ }
80
+ }
81
+ function readJson(repoRoot, relativePath, errors) {
82
+ try {
83
+ return JSON.parse(fs.readFileSync(path.resolve(repoRoot, relativePath), "utf8"));
84
+ }
85
+ catch (error) {
86
+ errors.push(`${relativePath}: ${error instanceof Error ? error.message : String(error)}`);
87
+ return undefined;
88
+ }
89
+ }
90
+ if (process.argv[1] !== undefined &&
91
+ import.meta.url === pathToFileURL(process.argv[1]).href) {
92
+ const errors = checkReleasePublishConfig();
93
+ if (errors.length > 0) {
94
+ for (const error of errors) {
95
+ console.error(error);
96
+ }
97
+ process.exitCode = 1;
98
+ }
99
+ }
@@ -0,0 +1 @@
1
+ export declare function generateProtoInventory(repoRoot?: string): void;
@@ -0,0 +1,89 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { listProtoFiles, resolveProtoDirectory } from "../proto.js";
4
+ export function generateProtoInventory(repoRoot = process.cwd()) {
5
+ const protoDir = resolveProtoDirectory();
6
+ const serviceMethods = [];
7
+ const types = [];
8
+ for (const file of listProtoFiles(protoDir)) {
9
+ const content = fs.readFileSync(file, "utf8");
10
+ const packageName = /^package\s+([a-zA-Z0-9_.]+);/m.exec(content)?.[1] ?? "unknown";
11
+ for (const match of content.matchAll(/^message\s+([A-Za-z0-9_]+)\s+\{/gm)) {
12
+ types.push({ packageName, kind: "message", name: match[1] ?? "unknown" });
13
+ }
14
+ for (const match of content.matchAll(/^enum\s+([A-Za-z0-9_]+)\s+\{/gm)) {
15
+ types.push({ packageName, kind: "enum", name: match[1] ?? "unknown" });
16
+ }
17
+ for (const serviceMatch of content.matchAll(/^service\s+([A-Za-z0-9_]+)\s+\{([\s\S]*?)^}/gm)) {
18
+ const service = serviceMatch[1] ?? "unknown";
19
+ const body = serviceMatch[2] ?? "";
20
+ for (const rpcMatch of body.matchAll(/^\s*rpc\s+([A-Za-z0-9_]+)\(([^)]+)\)\s+returns\s+\((stream\s+)?([^)]+)\)/gm)) {
21
+ serviceMethods.push({
22
+ packageName,
23
+ service,
24
+ method: rpcMatch[1] ?? "unknown",
25
+ inputType: rpcMatch[2] ?? "unknown",
26
+ outputType: rpcMatch[4] ?? "unknown",
27
+ serverStreaming: rpcMatch[3] !== undefined,
28
+ });
29
+ }
30
+ }
31
+ }
32
+ const docsDir = path.join(repoRoot, "docs");
33
+ fs.mkdirSync(docsDir, { recursive: true });
34
+ fs.writeFileSync(path.join(docsDir, "service-manifest.json"), `${JSON.stringify(serviceMethods, null, 2)}\n`);
35
+ fs.writeFileSync(path.join(docsDir, "type-manifest-summary.json"), `${JSON.stringify(types, null, 2)}\n`);
36
+ fs.writeFileSync(path.join(docsDir, "proto-inventory.md"), renderInventory(protoDir, serviceMethods, types));
37
+ }
38
+ function renderInventory(protoDir, serviceMethods, types) {
39
+ const services = new Map();
40
+ for (const method of serviceMethods) {
41
+ const key = `${method.packageName}.${method.service}`;
42
+ services.set(key, [...(services.get(key) ?? []), method]);
43
+ }
44
+ const streamingMethods = serviceMethods.filter((method) => method.serverStreaming).length;
45
+ const messages = types.filter((type) => type.kind === "message").length;
46
+ const enums = types.filter((type) => type.kind === "enum").length;
47
+ const lines = [
48
+ "# Proto Inventory",
49
+ "",
50
+ `Generated from the default proto directory: \`${path.relative(process.cwd(), protoDir)}\`.`,
51
+ "",
52
+ "## Extraction Summary",
53
+ "",
54
+ `- Services: ${services.size} total`,
55
+ `- RPC methods: ${serviceMethods.length} total`,
56
+ `- Server-streaming RPC methods: ${streamingMethods} total`,
57
+ `- Top-level messages: ${messages}`,
58
+ `- Top-level enums: ${enums}`,
59
+ `- Proto files: ${listProtoFiles(protoDir)
60
+ .map((file) => `\`${path.relative(process.cwd(), file)}\``)
61
+ .join(", ")}`,
62
+ "",
63
+ "## Important Caveats",
64
+ "",
65
+ "- Runtime interception remains route-policy allowlisted and fixture-backed.",
66
+ "- Unknown endpoints pass through unchanged by default.",
67
+ "- The extractor still logs a non-fatal Cursor bundle `TypeError` after processing services, then writes proto files successfully.",
68
+ "",
69
+ "## Services",
70
+ "",
71
+ ];
72
+ let index = 1;
73
+ for (const [service, methods] of Array.from(services.entries()).sort()) {
74
+ lines.push(`${index}. \`${service}\`: ${methods.length} RPCs${methods.some((method) => method.serverStreaming) ? `, ${methods.filter((method) => method.serverStreaming).length} streaming` : ""}`);
75
+ index++;
76
+ }
77
+ lines.push("", "## Service Methods", "");
78
+ for (const [service, methods] of Array.from(services.entries()).sort()) {
79
+ lines.push(`### \`${service}\``, "");
80
+ for (const method of methods) {
81
+ lines.push(`- \`${method.method}(${method.inputType}) returns (${method.serverStreaming ? "stream " : ""}${method.outputType})\``);
82
+ }
83
+ lines.push("");
84
+ }
85
+ return `${lines.join("\n")}\n`;
86
+ }
87
+ if (import.meta.url === `file://${process.argv[1]}`) {
88
+ generateProtoInventory();
89
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const GENERATED_ROOT = path.resolve(process.cwd(), "src", "gen");
4
+ function normalizeGeneratedFiles(directory) {
5
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
6
+ const fullPath = path.join(directory, entry.name);
7
+ if (entry.isDirectory()) {
8
+ normalizeGeneratedFiles(fullPath);
9
+ }
10
+ else if (entry.isFile() && entry.name.endsWith(".ts")) {
11
+ const content = fs.readFileSync(fullPath, "utf8");
12
+ fs.writeFileSync(fullPath, `${content.trimEnd()}\n`);
13
+ }
14
+ }
15
+ }
16
+ if (fs.existsSync(GENERATED_ROOT)) {
17
+ normalizeGeneratedFiles(GENERATED_ROOT);
18
+ }
@@ -0,0 +1,26 @@
1
+ export type GateStatus = "passed" | "failed" | "skipped_with_reason";
2
+ export type ReleaseCategoryId = "baseline-drift" | "static" | "protocol" | "mlx" | "tool" | "desktop-optional-live" | "reliability-security" | "packaging" | "final-gate";
3
+ export interface ReleaseGateStatusInput {
4
+ id: string;
5
+ status: GateStatus;
6
+ categories: ReleaseCategoryId[];
7
+ }
8
+ export interface OptionalLiveSuite {
9
+ id: string;
10
+ category: ReleaseCategoryId;
11
+ status: "skipped_with_reason";
12
+ reason: string;
13
+ command: string;
14
+ prerequisites: string[];
15
+ }
16
+ export interface ReleaseCategoryStatus {
17
+ id: ReleaseCategoryId;
18
+ status: GateStatus;
19
+ gateIds: string[];
20
+ optionalSuiteIds: string[];
21
+ summary: string;
22
+ }
23
+ export declare const REQUIRED_PACKAGE_ENTRIES: readonly ["package/package.json", "package/README.md", "package/DISCLAIMER.md", "package/dist/src/cli.js", "package/dist/src/cli.d.ts", "package/dist/src/ck.js", "package/dist/src/ck.d.ts", "package/proto/agent/v1/agent.proto", "package/proto/aiserver/v1/aiserver.proto", "package/docs/protocol.md", "package/docs/release-gates.md", "package/docs/testing-harness.md", "package/docs/test-manifest.json", "package/docs/route-contract-manifest.json", "package/docs/release-summary.json"];
24
+ export declare const EXCLUDED_PACKAGE_ENTRY_PREFIXES: readonly ["package/examples/"];
25
+ export declare function runReleaseCheck(repoRoot?: string): number;
26
+ export declare function buildReleaseCategoryStatuses(results: ReleaseGateStatusInput[], optionalSuites?: OptionalLiveSuite[]): ReleaseCategoryStatus[];