@mcoda/codali 0.1.89 → 0.1.91

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 (105) hide show
  1. package/dist/cli/DatasetCommand.d.ts +38 -0
  2. package/dist/cli/DatasetCommand.d.ts.map +1 -0
  3. package/dist/cli/DatasetCommand.js +959 -0
  4. package/dist/cli/EvalCommand.d.ts +3 -0
  5. package/dist/cli/EvalCommand.d.ts.map +1 -1
  6. package/dist/cli/EvalCommand.js +55 -1
  7. package/dist/cli/ImprovementCommand.d.ts +97 -0
  8. package/dist/cli/ImprovementCommand.d.ts.map +1 -0
  9. package/dist/cli/ImprovementCommand.js +1879 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +15 -0
  12. package/dist/dataset-cli.d.ts +3 -0
  13. package/dist/dataset-cli.d.ts.map +1 -0
  14. package/dist/dataset-cli.js +30 -0
  15. package/dist/eval/CodaliGatewayLiveHarness.d.ts +90 -1
  16. package/dist/eval/CodaliGatewayLiveHarness.d.ts.map +1 -1
  17. package/dist/eval/CodaliGatewayLiveHarness.js +443 -9
  18. package/dist/eval/GatewayDatasetEval.d.ts +70 -0
  19. package/dist/eval/GatewayDatasetEval.d.ts.map +1 -0
  20. package/dist/eval/GatewayDatasetEval.js +477 -0
  21. package/dist/eval/GatewayEvalSuite.d.ts +52 -0
  22. package/dist/eval/GatewayEvalSuite.d.ts.map +1 -1
  23. package/dist/eval/GatewayEvalSuite.js +135 -1
  24. package/dist/gateway/CodaliGateway.d.ts +4 -0
  25. package/dist/gateway/CodaliGateway.d.ts.map +1 -1
  26. package/dist/gateway/CodaliGateway.js +37 -1
  27. package/dist/gateway/CodaliGatewaySchemas.d.ts.map +1 -1
  28. package/dist/gateway/CodaliGatewaySchemas.js +0 -4
  29. package/dist/gateway/CodaliGatewayStore.d.ts.map +1 -1
  30. package/dist/gateway/CodaliGatewayStore.js +1 -0
  31. package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
  32. package/dist/gateway/GatewayPlanner.js +355 -41
  33. package/dist/gateway/GatewayStateMachine.d.ts +1 -0
  34. package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
  35. package/dist/gateway/GatewayStateMachine.js +221 -5
  36. package/dist/improvement/CandidateReleaseBuilder.d.ts +201 -0
  37. package/dist/improvement/CandidateReleaseBuilder.d.ts.map +1 -0
  38. package/dist/improvement/CandidateReleaseBuilder.js +1175 -0
  39. package/dist/improvement/DatasetEligibilityGate.d.ts +75 -0
  40. package/dist/improvement/DatasetEligibilityGate.d.ts.map +1 -0
  41. package/dist/improvement/DatasetEligibilityGate.js +497 -0
  42. package/dist/improvement/DatasetExportManifestReader.d.ts +88 -0
  43. package/dist/improvement/DatasetExportManifestReader.d.ts.map +1 -0
  44. package/dist/improvement/DatasetExportManifestReader.js +333 -0
  45. package/dist/improvement/DocdexRetrievalCandidateBuilder.d.ts +192 -0
  46. package/dist/improvement/DocdexRetrievalCandidateBuilder.d.ts.map +1 -0
  47. package/dist/improvement/DocdexRetrievalCandidateBuilder.js +625 -0
  48. package/dist/improvement/EvalReplayCandidateBuilder.d.ts +173 -0
  49. package/dist/improvement/EvalReplayCandidateBuilder.d.ts.map +1 -0
  50. package/dist/improvement/EvalReplayCandidateBuilder.js +363 -0
  51. package/dist/improvement/FineTuneJobPlanner.d.ts +281 -0
  52. package/dist/improvement/FineTuneJobPlanner.d.ts.map +1 -0
  53. package/dist/improvement/FineTuneJobPlanner.js +823 -0
  54. package/dist/improvement/ImprovementEvalRunner.d.ts +50 -0
  55. package/dist/improvement/ImprovementEvalRunner.d.ts.map +1 -0
  56. package/dist/improvement/ImprovementEvalRunner.js +648 -0
  57. package/dist/improvement/ImprovementPolicy.d.ts +272 -0
  58. package/dist/improvement/ImprovementPolicy.d.ts.map +1 -0
  59. package/dist/improvement/ImprovementPolicy.js +1450 -0
  60. package/dist/improvement/ModelRouterCandidateBuilder.d.ts +186 -0
  61. package/dist/improvement/ModelRouterCandidateBuilder.d.ts.map +1 -0
  62. package/dist/improvement/ModelRouterCandidateBuilder.js +880 -0
  63. package/dist/improvement/OperatorInspector.d.ts +182 -0
  64. package/dist/improvement/OperatorInspector.d.ts.map +1 -0
  65. package/dist/improvement/OperatorInspector.js +604 -0
  66. package/dist/improvement/ProductionGovernance.d.ts +91 -0
  67. package/dist/improvement/ProductionGovernance.d.ts.map +1 -0
  68. package/dist/improvement/ProductionGovernance.js +329 -0
  69. package/dist/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts +152 -0
  70. package/dist/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts.map +1 -0
  71. package/dist/improvement/PromptSchemaToolMetadataCandidateBuilder.js +480 -0
  72. package/dist/improvement/PublishOrchestrator.d.ts +113 -0
  73. package/dist/improvement/PublishOrchestrator.d.ts.map +1 -0
  74. package/dist/improvement/PublishOrchestrator.js +590 -0
  75. package/dist/improvement/ReleaseOutcomeReporter.d.ts +133 -0
  76. package/dist/improvement/ReleaseOutcomeReporter.d.ts.map +1 -0
  77. package/dist/improvement/ReleaseOutcomeReporter.js +501 -0
  78. package/dist/improvement/StorageServiceImprovementClient.d.ts +71 -0
  79. package/dist/improvement/StorageServiceImprovementClient.d.ts.map +1 -0
  80. package/dist/improvement/StorageServiceImprovementClient.js +245 -0
  81. package/dist/index.d.ts +43 -0
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +21 -0
  84. package/dist/runtime/CodaliRuntime.d.ts +0 -2
  85. package/dist/runtime/CodaliRuntime.d.ts.map +1 -1
  86. package/dist/runtime/CodaliRuntime.js +0 -5
  87. package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +138 -0
  88. package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -0
  89. package/dist/storage/CodaliDatasetPrivacyEngine.js +417 -0
  90. package/dist/storage/CodaliFeedbackReviewIngestion.d.ts +50 -0
  91. package/dist/storage/CodaliFeedbackReviewIngestion.d.ts.map +1 -0
  92. package/dist/storage/CodaliFeedbackReviewIngestion.js +141 -0
  93. package/dist/storage/CodaliStorageContracts.d.ts +337 -0
  94. package/dist/storage/CodaliStorageContracts.d.ts.map +1 -0
  95. package/dist/storage/CodaliStorageContracts.js +1555 -0
  96. package/dist/storage/DatasetExportJob.d.ts +51 -0
  97. package/dist/storage/DatasetExportJob.d.ts.map +1 -0
  98. package/dist/storage/DatasetExportJob.js +358 -0
  99. package/dist/storage/DatasetReviewQueue.d.ts +98 -0
  100. package/dist/storage/DatasetReviewQueue.d.ts.map +1 -0
  101. package/dist/storage/DatasetReviewQueue.js +426 -0
  102. package/dist/storage/GatewayDatasetStore.d.ts +233 -0
  103. package/dist/storage/GatewayDatasetStore.d.ts.map +1 -0
  104. package/dist/storage/GatewayDatasetStore.js +2070 -0
  105. package/package.json +5 -4
@@ -0,0 +1,590 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import path from "node:path";
4
+ import { buildCodaliCandidateReleasePlan, } from "./CandidateReleaseBuilder.js";
5
+ import { buildCodaliImprovementEvalScorecard, } from "./ImprovementEvalRunner.js";
6
+ import { CODALI_IMPROVEMENT_CONTRACT_SCHEMA_VERSION, createCodaliImprovementPolicy, evaluateCodaliImprovementPolicy, } from "./ImprovementPolicy.js";
7
+ export const CODALI_PUBLISH_ORCHESTRATOR_SCHEMA_VERSION = "codali.improvement.publish.v1";
8
+ export const CODALI_PUBLISH_RELEASE_WORKFLOW_FILE = ".github/workflows/release.yml";
9
+ export const DEFAULT_CODALI_PUBLISH_NPM_REGISTRY = "https://registry.npmjs.org/";
10
+ const defaultCommandRunner = (command, args, options) => {
11
+ const result = spawnSync(command, args, {
12
+ cwd: options.cwd,
13
+ encoding: "utf8",
14
+ });
15
+ return {
16
+ exitCode: typeof result.status === "number" ? result.status : 1,
17
+ stdout: result.stdout ?? "",
18
+ stderr: result.stderr ?? "",
19
+ error: result.error ? String(result.error) : undefined,
20
+ };
21
+ };
22
+ const stableJson = (value) => {
23
+ if (Array.isArray(value))
24
+ return `[${value.map((item) => stableJson(item)).join(",")}]`;
25
+ if (value && typeof value === "object") {
26
+ return `{${Object.entries(value)
27
+ .filter(([, item]) => item !== undefined)
28
+ .sort(([left], [right]) => left.localeCompare(right))
29
+ .map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`)
30
+ .join(",")}}`;
31
+ }
32
+ return JSON.stringify(value);
33
+ };
34
+ const stableId = (prefix, value) => `${prefix}-${createHash("sha256").update(stableJson(value)).digest("hex").slice(0, 16)}`;
35
+ const uniqueStrings = (values) => Array.from(new Set(values.filter((value) => typeof value === "string" && value.trim().length > 0))).sort();
36
+ const toPosixPath = (value) => value.split(path.sep).join("/");
37
+ const normalizeCandidateDirectories = (repoRoot, directories) => directories?.map((directory) => path.isAbsolute(directory) ? directory : path.resolve(repoRoot, directory));
38
+ const parseGitStatus = (stdout) => stdout
39
+ .split(/\r?\n/u)
40
+ .map((line) => line.trimEnd())
41
+ .filter(Boolean)
42
+ .map((line) => {
43
+ const status = line.slice(0, 2).trim() || line.slice(0, 2);
44
+ const rawPath = line.slice(3).trim();
45
+ const renamedPath = rawPath.includes(" -> ")
46
+ ? rawPath.slice(rawPath.lastIndexOf(" -> ") + 4)
47
+ : rawPath;
48
+ return {
49
+ status,
50
+ path: toPosixPath(renamedPath.replace(/^"|"$/g, "")),
51
+ };
52
+ });
53
+ const commandStep = (command, args, executed, result) => ({
54
+ command,
55
+ args,
56
+ executed,
57
+ ...(result
58
+ ? {
59
+ exitCode: result.exitCode,
60
+ stdout: result.stdout,
61
+ stderr: result.stderr,
62
+ error: result.error,
63
+ }
64
+ : {}),
65
+ });
66
+ const readCommitGuard = (input) => {
67
+ if (!input.required) {
68
+ return {
69
+ required: false,
70
+ status: "skipped",
71
+ commitSha: input.commitSha,
72
+ dirtyFileCount: 0,
73
+ dirtyFilesSample: [],
74
+ reasons: [],
75
+ };
76
+ }
77
+ const commitSha = input.commitSha ?? (() => {
78
+ const result = input.commandRunner("git", ["rev-parse", "HEAD"], {
79
+ cwd: input.repoRoot,
80
+ });
81
+ return result.exitCode === 0 && !result.error
82
+ ? result.stdout.trim()
83
+ : undefined;
84
+ })();
85
+ const entries = input.dirtyEntries
86
+ ? [...input.dirtyEntries]
87
+ : (() => {
88
+ const result = input.commandRunner("git", ["status", "--porcelain"], {
89
+ cwd: input.repoRoot,
90
+ });
91
+ if (result.exitCode !== 0 || result.error)
92
+ return undefined;
93
+ return parseGitStatus(result.stdout);
94
+ })();
95
+ if (!commitSha || !entries) {
96
+ return {
97
+ required: true,
98
+ status: "unavailable",
99
+ commitSha,
100
+ dirtyFileCount: 0,
101
+ dirtyFilesSample: [],
102
+ reasons: [!commitSha ? "candidate_commit_sha_unavailable" : "candidate_git_status_unavailable"],
103
+ };
104
+ }
105
+ const dirtyFiles = uniqueStrings(entries.map((entry) => entry.path));
106
+ return {
107
+ required: true,
108
+ status: dirtyFiles.length ? "dirty" : "clean",
109
+ commitSha,
110
+ dirtyFileCount: dirtyFiles.length,
111
+ dirtyFilesSample: dirtyFiles.slice(0, 20),
112
+ reasons: dirtyFiles.length ? ["candidate_commit_not_clean"] : [],
113
+ };
114
+ };
115
+ const createPublishPolicy = (input) => createCodaliImprovementPolicy({
116
+ policyId: `publish-policy-level-${input.releaseLevel}`,
117
+ releaseLevel: input.releaseLevel,
118
+ scope: input.scope,
119
+ allowedArtifactTypes: input.releaseLevel >= 4
120
+ ? ["stable_npm_release", "release_notes", "scorecard", "prerelease_tag"]
121
+ : input.releaseLevel >= 3
122
+ ? ["prerelease_tag", "release_notes", "scorecard"]
123
+ : ["scorecard", "release_notes"],
124
+ maxExamples: 0,
125
+ maxObjectBytes: 1,
126
+ storageMode: "local_only",
127
+ exportEnabled: false,
128
+ trainingEnabled: false,
129
+ autoTagEnabled: input.autoTagEnabled,
130
+ autoPublishEnabled: input.autoPublishEnabled,
131
+ metadata: {
132
+ source: "codali improve publish",
133
+ schemaVersion: CODALI_PUBLISH_ORCHESTRATOR_SCHEMA_VERSION,
134
+ },
135
+ });
136
+ const releaseScopeFor = (releaseBuild, fallback) => fallback ?? releaseBuild.release.scope;
137
+ const releaseLevelFor = (releaseBuild, fallback) => fallback ?? releaseBuild.release.releaseLevel;
138
+ const publisher = () => ({
139
+ type: "github_actions_release_workflow",
140
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
141
+ localNpmPublishAllowed: false,
142
+ note: "npm publish remains delegated to the existing GitHub Actions release workflow.",
143
+ });
144
+ const plannedWorkflowRun = () => ({
145
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
146
+ source: "planned",
147
+ status: "not_requested",
148
+ });
149
+ const normalizeWorkflowRun = (input) => {
150
+ if (!input)
151
+ return undefined;
152
+ return {
153
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
154
+ source: "ingested",
155
+ status: input.status ?? "unknown",
156
+ conclusion: input.conclusion,
157
+ runId: input.runId,
158
+ headSha: input.headSha,
159
+ url: input.url,
160
+ error: input.error,
161
+ };
162
+ };
163
+ const parseGhRunList = (payload, commitSha) => {
164
+ const parsed = JSON.parse(payload);
165
+ if (!Array.isArray(parsed))
166
+ return undefined;
167
+ const runs = parsed.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item)));
168
+ const matched = commitSha
169
+ ? runs.find((run) => run.headSha === commitSha) ?? runs[0]
170
+ : runs[0];
171
+ if (!matched)
172
+ return undefined;
173
+ return {
174
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
175
+ source: "gh_cli",
176
+ runId: typeof matched.databaseId === "number"
177
+ ? String(matched.databaseId)
178
+ : typeof matched.runId === "string"
179
+ ? matched.runId
180
+ : undefined,
181
+ status: matched.status === "queued" ||
182
+ matched.status === "in_progress" ||
183
+ matched.status === "completed"
184
+ ? matched.status
185
+ : "unknown",
186
+ conclusion: typeof matched.conclusion === "string"
187
+ ? matched.conclusion
188
+ : undefined,
189
+ headSha: typeof matched.headSha === "string" ? matched.headSha : undefined,
190
+ url: typeof matched.url === "string" ? matched.url : undefined,
191
+ };
192
+ };
193
+ const resolveWorkflowRun = (input) => {
194
+ const ingested = normalizeWorkflowRun(input.workflowRun);
195
+ if (ingested)
196
+ return ingested;
197
+ const args = [
198
+ "run",
199
+ "list",
200
+ "--workflow",
201
+ CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
202
+ "--json",
203
+ "databaseId,status,conclusion,headSha,url,event,displayTitle",
204
+ "--limit",
205
+ "20",
206
+ ];
207
+ if (input.dryRun || !input.pollActions) {
208
+ input.commands.push(commandStep("gh", args, false));
209
+ return plannedWorkflowRun();
210
+ }
211
+ const result = input.commandRunner("gh", args, { cwd: input.repoRoot });
212
+ input.commands.push(commandStep("gh", args, true, result));
213
+ if (result.exitCode !== 0 || result.error) {
214
+ return {
215
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
216
+ source: "gh_cli",
217
+ status: "unknown",
218
+ error: result.error ?? result.stderr ?? "gh run list failed",
219
+ };
220
+ }
221
+ try {
222
+ return parseGhRunList(result.stdout, input.commitSha) ?? {
223
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
224
+ source: "gh_cli",
225
+ status: "unknown",
226
+ error: "release workflow run not found",
227
+ };
228
+ }
229
+ catch (error) {
230
+ return {
231
+ workflowFile: CODALI_PUBLISH_RELEASE_WORKFLOW_FILE,
232
+ source: "gh_cli",
233
+ status: "unknown",
234
+ error: error instanceof Error ? error.message : String(error),
235
+ };
236
+ }
237
+ };
238
+ const packageNamesFor = (releaseBuild, explicitPackageNames) => explicitPackageNames?.length
239
+ ? uniqueStrings([...explicitPackageNames])
240
+ : uniqueStrings(releaseBuild.releasePlan.packageVersions.targets
241
+ .filter((target) => !target.privatePackage)
242
+ .map((target) => target.packageName));
243
+ const resolveNpmVersions = (input) => {
244
+ const ingested = new Map(input.ingestedVersions?.map((item) => [item.packageName, item.version]) ?? []);
245
+ return input.packageNames.map((packageName) => {
246
+ const args = ["view", packageName, "version", "--registry", input.registry];
247
+ const ingestedVersion = ingested.get(packageName);
248
+ if (ingestedVersion !== undefined) {
249
+ return {
250
+ packageName,
251
+ expectedVersion: input.expectedVersion,
252
+ registry: input.registry,
253
+ observedVersion: ingestedVersion,
254
+ status: ingestedVersion === input.expectedVersion ? "verified" : "mismatch",
255
+ command: ["npm", ...args],
256
+ };
257
+ }
258
+ if (input.dryRun || !input.verifyNpm) {
259
+ input.commands.push(commandStep("npm", args, false));
260
+ return {
261
+ packageName,
262
+ expectedVersion: input.expectedVersion,
263
+ registry: input.registry,
264
+ status: "planned",
265
+ command: ["npm", ...args],
266
+ };
267
+ }
268
+ const result = input.commandRunner("npm", args, { cwd: input.repoRoot });
269
+ input.commands.push(commandStep("npm", args, true, result));
270
+ if (result.exitCode !== 0 || result.error) {
271
+ return {
272
+ packageName,
273
+ expectedVersion: input.expectedVersion,
274
+ registry: input.registry,
275
+ status: "unavailable",
276
+ command: ["npm", ...args],
277
+ error: result.error ?? result.stderr ?? "npm view failed",
278
+ };
279
+ }
280
+ const observedVersion = result.stdout.trim();
281
+ return {
282
+ packageName,
283
+ expectedVersion: input.expectedVersion,
284
+ registry: input.registry,
285
+ observedVersion,
286
+ status: observedVersion === input.expectedVersion ? "verified" : "mismatch",
287
+ command: ["npm", ...args],
288
+ };
289
+ });
290
+ };
291
+ const blockedReasonsFor = (input) => uniqueStrings([
292
+ ...input.releaseBuild.blockedReasons,
293
+ input.mode === "auto_tag" && !input.autoTagAllowed ? "auto_tag_policy_blocked" : undefined,
294
+ input.mode === "auto_tag" && !input.publishStableAllowed
295
+ ? "stable_publish_policy_blocked"
296
+ : undefined,
297
+ input.mode === "auto_tag" && input.scorecard && !input.scorecard.releaseApproval.tagAllowed
298
+ ? "scorecard_tag_blocked"
299
+ : undefined,
300
+ input.mode === "auto_tag" && input.scorecard && !input.scorecard.releaseApproval.publishAllowed
301
+ ? "scorecard_publish_blocked"
302
+ : undefined,
303
+ input.mode === "auto_tag" && !input.scorecard ? "scorecard_required_for_auto_tag" : undefined,
304
+ input.mode === "auto_tag" && input.commitGuard.status === "dirty"
305
+ ? "candidate_commit_not_clean"
306
+ : undefined,
307
+ input.mode === "auto_tag" && input.commitGuard.status === "unavailable"
308
+ ? "candidate_commit_guard_unavailable"
309
+ : undefined,
310
+ ...input.commitGuard.reasons,
311
+ ]);
312
+ const runAutoTag = (input) => {
313
+ if (input.blockedReasons.length > 0 || !input.commitSha) {
314
+ input.commands.push(commandStep("git", ["tag", "-a", input.tagName, input.commitSha ?? "HEAD", "-m", input.tagMessage], false));
315
+ input.commands.push(commandStep("git", ["push", "origin", input.tagName], false));
316
+ return [];
317
+ }
318
+ const tagArgs = ["tag", "-a", input.tagName, input.commitSha, "-m", input.tagMessage];
319
+ const pushArgs = ["push", "origin", input.tagName];
320
+ if (input.dryRun) {
321
+ input.commands.push(commandStep("git", tagArgs, false));
322
+ input.commands.push(commandStep("git", pushArgs, false));
323
+ return [];
324
+ }
325
+ const tagResult = input.commandRunner("git", tagArgs, { cwd: input.repoRoot });
326
+ input.commands.push(commandStep("git", tagArgs, true, tagResult));
327
+ if (tagResult.exitCode !== 0 || tagResult.error) {
328
+ return ["tag_create_failed"];
329
+ }
330
+ const pushResult = input.commandRunner("git", pushArgs, { cwd: input.repoRoot });
331
+ input.commands.push(commandStep("git", pushArgs, true, pushResult));
332
+ return pushResult.exitCode === 0 && !pushResult.error
333
+ ? []
334
+ : ["tag_push_failed"];
335
+ };
336
+ const statusFor = (input) => {
337
+ if (input.blockedReasons.length > 0)
338
+ return "blocked";
339
+ if (input.tagErrors.length > 0)
340
+ return "failed";
341
+ if (input.workflowRun.status === "completed" &&
342
+ input.workflowRun.conclusion !== undefined &&
343
+ input.workflowRun.conclusion !== "success") {
344
+ return "workflow_failed";
345
+ }
346
+ if (input.npmVersions.some((item) => item.status === "mismatch" || item.status === "unavailable")) {
347
+ return "workflow_failed";
348
+ }
349
+ if (input.workflowRun.status === "completed" && input.workflowRun.conclusion === "success") {
350
+ return input.npmVersions.length > 0 && input.npmVersions.every((item) => item.status === "verified")
351
+ ? "published_verified"
352
+ : "workflow_succeeded";
353
+ }
354
+ if (input.workflowRun.status === "queued" || input.workflowRun.status === "in_progress") {
355
+ return "workflow_queued";
356
+ }
357
+ if (input.mode === "auto_tag" && !input.dryRun)
358
+ return "tagged";
359
+ return "planned";
360
+ };
361
+ const outcomeStatusFor = (status) => {
362
+ if (status === "blocked")
363
+ return "blocked";
364
+ if (status === "failed" || status === "workflow_failed")
365
+ return "failed";
366
+ if (status === "published_verified")
367
+ return "succeeded";
368
+ return "succeeded";
369
+ };
370
+ export const runCodaliPublishOrchestrator = async (input) => {
371
+ const dryRun = input.dryRun ?? true;
372
+ const mode = input.mode ?? "branch_only";
373
+ const repoRoot = path.resolve(input.repoRoot ?? process.cwd());
374
+ const commandRunner = input.commandRunner ?? defaultCommandRunner;
375
+ const now = input.now ?? (() => new Date());
376
+ const candidateDirectories = normalizeCandidateDirectories(repoRoot, input.candidateDirectories);
377
+ const releaseBuild = await buildCodaliCandidateReleasePlan({
378
+ candidateId: input.candidateId,
379
+ candidatePath: input.candidatePath,
380
+ candidateDirectories,
381
+ repoRoot,
382
+ scope: input.scope,
383
+ releaseLevel: input.releaseLevel,
384
+ dryRun: true,
385
+ runId: input.runId,
386
+ candidateDate: input.candidateDate,
387
+ dirtyEntries: input.dirtyEntries,
388
+ commandRunner,
389
+ });
390
+ const scope = releaseScopeFor(releaseBuild, input.scope);
391
+ const releaseLevel = releaseLevelFor(releaseBuild, input.releaseLevel);
392
+ const policy = input.policy ?? createPublishPolicy({
393
+ releaseLevel,
394
+ scope,
395
+ autoTagEnabled: input.autoTagEnabled ?? false,
396
+ autoPublishEnabled: input.autoPublishEnabled ?? false,
397
+ });
398
+ const policyDecisions = {
399
+ autoTag: evaluateCodaliImprovementPolicy(policy, {
400
+ action: "auto_tag",
401
+ releaseLevel,
402
+ scope,
403
+ artifactType: "prerelease_tag",
404
+ }),
405
+ publishStable: evaluateCodaliImprovementPolicy(policy, {
406
+ action: "publish_stable",
407
+ releaseLevel,
408
+ scope,
409
+ artifactType: "stable_npm_release",
410
+ }),
411
+ };
412
+ const scorecard = mode === "auto_tag"
413
+ ? input.scorecard ?? await buildCodaliImprovementEvalScorecard({
414
+ candidateId: input.candidateId,
415
+ candidatePath: input.candidatePath,
416
+ candidateDirectories,
417
+ approvedPaths: releaseBuild.candidateWorkspace.approvedPaths,
418
+ now,
419
+ })
420
+ : input.scorecard;
421
+ const commitGuard = readCommitGuard({
422
+ repoRoot,
423
+ required: mode === "auto_tag",
424
+ commitSha: input.commitSha,
425
+ dirtyEntries: input.dirtyEntries,
426
+ commandRunner,
427
+ });
428
+ const commands = [];
429
+ const initialBlockedReasons = blockedReasonsFor({
430
+ mode,
431
+ releaseBuild,
432
+ scorecard,
433
+ commitGuard,
434
+ autoTagAllowed: policyDecisions.autoTag.allowed,
435
+ publishStableAllowed: policyDecisions.publishStable.allowed,
436
+ });
437
+ const tagErrors = mode === "auto_tag"
438
+ ? runAutoTag({
439
+ dryRun,
440
+ repoRoot,
441
+ tagName: releaseBuild.releasePlan.futureTag,
442
+ tagMessage: releaseBuild.releasePlan.tag.message,
443
+ commitSha: commitGuard.commitSha,
444
+ blockedReasons: initialBlockedReasons,
445
+ commandRunner,
446
+ commands,
447
+ })
448
+ : [];
449
+ const workflowRun = resolveWorkflowRun({
450
+ dryRun,
451
+ pollActions: input.pollActions ?? false,
452
+ repoRoot,
453
+ commitSha: commitGuard.commitSha,
454
+ workflowRun: input.workflowRun,
455
+ commandRunner,
456
+ commands,
457
+ });
458
+ const packageNames = packageNamesFor(releaseBuild, input.npmPackages);
459
+ const npmVersions = resolveNpmVersions({
460
+ dryRun,
461
+ verifyNpm: input.verifyNpm ?? (workflowRun.status === "completed" && workflowRun.conclusion === "success"),
462
+ repoRoot,
463
+ packageNames,
464
+ expectedVersion: releaseBuild.releasePlan.version,
465
+ registry: input.npmRegistry ?? DEFAULT_CODALI_PUBLISH_NPM_REGISTRY,
466
+ ingestedVersions: input.npmVersions,
467
+ commandRunner,
468
+ commands,
469
+ });
470
+ const blockedReasons = uniqueStrings([...initialBlockedReasons, ...tagErrors]);
471
+ const status = statusFor({
472
+ mode,
473
+ dryRun,
474
+ blockedReasons,
475
+ tagErrors,
476
+ workflowRun,
477
+ npmVersions,
478
+ });
479
+ const outcome = {
480
+ schemaVersion: CODALI_IMPROVEMENT_CONTRACT_SCHEMA_VERSION,
481
+ outcomeId: stableId("publish-outcome", {
482
+ candidateId: input.candidateId,
483
+ mode,
484
+ status,
485
+ tagName: releaseBuild.releasePlan.futureTag,
486
+ commitSha: commitGuard.commitSha,
487
+ workflowRunId: workflowRun.runId,
488
+ npmVersions,
489
+ }),
490
+ releaseId: releaseBuild.release.releaseId,
491
+ scope,
492
+ status: outcomeStatusFor(status),
493
+ published: status === "published_verified",
494
+ tagged: status === "tagged" || status === "workflow_queued" ||
495
+ status === "workflow_succeeded" || status === "published_verified",
496
+ trainingUsed: false,
497
+ exportUsed: false,
498
+ createdAt: now().toISOString(),
499
+ ...(blockedReasons.length ? { reasons: blockedReasons } : {}),
500
+ metadata: {
501
+ schemaVersion: CODALI_PUBLISH_ORCHESTRATOR_SCHEMA_VERSION,
502
+ dryRun,
503
+ mode,
504
+ status,
505
+ releaseWorkflow: publisher(),
506
+ branchName: releaseBuild.candidateWorkspace.branchName,
507
+ tagName: releaseBuild.releasePlan.futureTag,
508
+ commitSha: commitGuard.commitSha,
509
+ workflowRunId: workflowRun.runId,
510
+ workflowRun,
511
+ npmVersions,
512
+ commitGuard,
513
+ policyDecisions,
514
+ scorecardStatus: scorecard?.scorecard.status,
515
+ releaseApproval: scorecard?.releaseApproval,
516
+ commands,
517
+ blockedReasons,
518
+ },
519
+ };
520
+ return {
521
+ schemaVersion: CODALI_PUBLISH_ORCHESTRATOR_SCHEMA_VERSION,
522
+ dryRun,
523
+ mode,
524
+ status,
525
+ candidateId: input.candidateId,
526
+ releaseBuild,
527
+ scorecard,
528
+ policy,
529
+ policyDecisions,
530
+ publisher: publisher(),
531
+ commitGuard,
532
+ workflowRun,
533
+ npmVersions,
534
+ commands,
535
+ blockedReasons,
536
+ outcome,
537
+ };
538
+ };
539
+ export const writeCodaliPublishToStorageService = async (input) => {
540
+ const metadata = input.result.outcome.metadata ?? {};
541
+ const runWrite = await input.client.recordRun({
542
+ scope: input.scope,
543
+ idempotencyKey: `improvement-publish:${input.result.candidateId}:${input.result.releaseBuild.releasePlan.futureTag}`,
544
+ body: {
545
+ improvement_run_id: input.scope.runId,
546
+ run_kind: "release_publish",
547
+ status: input.result.outcome.status === "blocked"
548
+ ? "blocked"
549
+ : input.result.outcome.status === "failed"
550
+ ? "failed"
551
+ : "completed",
552
+ source_export_id: input.result.candidateId,
553
+ metadata: {
554
+ ...metadata,
555
+ tagName: input.result.releaseBuild.releasePlan.futureTag,
556
+ commitSha: input.result.commitGuard.commitSha,
557
+ workflowRunId: input.result.workflowRun.runId,
558
+ npmVersions: input.result.npmVersions,
559
+ status: input.result.status,
560
+ },
561
+ },
562
+ });
563
+ const candidateWrite = await input.client.recordCandidate({
564
+ scope: input.scope,
565
+ idempotencyKey: `improvement-publish-candidate:${input.result.candidateId}:${input.result.releaseBuild.releasePlan.futureTag}`,
566
+ body: {
567
+ candidate_id: input.result.candidateId,
568
+ improvement_run_id: input.scope.runId,
569
+ source_export_id: input.result.candidateId,
570
+ source_record_ids: [],
571
+ candidate_kind: "release",
572
+ candidate_ref: input.result.releaseBuild.releasePlan.futureTag,
573
+ status: input.result.outcome.published
574
+ ? "released"
575
+ : input.result.outcome.status === "blocked"
576
+ ? "blocked"
577
+ : "accepted",
578
+ metadata: {
579
+ ...metadata,
580
+ releaseId: input.result.releaseBuild.release.releaseId,
581
+ tagName: input.result.releaseBuild.releasePlan.futureTag,
582
+ commitSha: input.result.commitGuard.commitSha,
583
+ workflowRunId: input.result.workflowRun.runId,
584
+ npmVersions: input.result.npmVersions,
585
+ status: input.result.status,
586
+ },
587
+ },
588
+ });
589
+ return [runWrite, candidateWrite];
590
+ };