@scarn/sdk 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4361gxk0.js +166 -0
- package/dist/chunk-4vehh3dq.js +333 -0
- package/dist/chunk-56e4kp0a.js +162 -0
- package/dist/chunk-5mmj03ah.js +1074 -0
- package/dist/chunk-631ffb6r.js +57 -0
- package/dist/chunk-91p9vzcs.js +1453 -0
- package/dist/chunk-9s07v9r1.js +30 -0
- package/dist/chunk-b21233rt.js +78 -0
- package/dist/chunk-dnn39qt4.js +13539 -0
- package/dist/chunk-eg1hcvhb.js +300 -0
- package/dist/chunk-g0rdnn0r.js +95 -0
- package/dist/chunk-h9yxx0hd.js +116 -0
- package/dist/chunk-njd6npf0.js +35 -0
- package/dist/chunk-ny07ncb9.js +330 -0
- package/dist/chunk-p6kc9wq8.js +97 -0
- package/dist/chunk-qpw5wt1p.js +257 -0
- package/dist/chunk-rq3q8vg7.js +1094 -0
- package/dist/chunk-s0gap8r8.js +14 -0
- package/dist/chunk-tfm5hjzm.js +100 -0
- package/dist/chunk-ynk2bjae.js +1686 -0
- package/dist/chunk-zpqyjgb4.js +49 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +57 -0
- package/dist/contracts/artifact-markers.d.ts +42 -0
- package/dist/contracts/artifact-markers.js +15 -0
- package/dist/contracts/artifacts.d.ts +67 -0
- package/dist/contracts/artifacts.js +25 -0
- package/dist/contracts/pipeline-document/built-ins.d.ts +23 -0
- package/dist/contracts/pipeline-document/conditions/operators.d.ts +8 -0
- package/dist/contracts/pipeline-document/index.d.ts +11 -0
- package/dist/contracts/pipeline-document/index.js +97 -0
- package/dist/contracts/pipeline-document/json.d.ts +35 -0
- package/dist/contracts/pipeline-document/routes.d.ts +16 -0
- package/dist/contracts/pipeline-document/schema.d.ts +780 -0
- package/dist/contracts/pipeline-document/step-contract.d.ts +11 -0
- package/dist/contracts/step-artifact-submissions.d.ts +71 -0
- package/dist/contracts/step-artifact-submissions.js +174 -0
- package/dist/defaults/atomic-json-file.d.ts +10 -0
- package/dist/defaults/auth-file.d.ts +14 -0
- package/dist/defaults/base-url.d.ts +1 -0
- package/dist/defaults/config-file.d.ts +46 -0
- package/dist/defaults/home-dir.d.ts +3 -0
- package/dist/defaults/index.d.ts +12 -0
- package/dist/defaults/index.js +1239 -0
- package/dist/defaults/legacy-config-migration.d.ts +27 -0
- package/dist/defaults/load-push-defaults.d.ts +25 -0
- package/dist/defaults/project-config.d.ts +32 -0
- package/dist/defaults/project-ref.d.ts +34 -0
- package/dist/definitions/artifacts/artifact.d.ts +62 -0
- package/dist/definitions/artifacts/index.d.ts +1 -0
- package/dist/definitions/pipelines/define-default-pipeline-assignment.d.ts +263 -0
- package/dist/definitions/pipelines/index.d.ts +3 -0
- package/dist/definitions/pipelines/index.js +24 -0
- package/dist/definitions/pipelines/pipeline-definitions-client.d.ts +208 -0
- package/dist/definitions/pipelines/work-item-fields.d.ts +93 -0
- package/dist/definitions/steps/compile-mcps.d.ts +34 -0
- package/dist/definitions/steps/define-code-step.d.ts +84 -0
- package/dist/definitions/steps/define-mcp.d.ts +79 -0
- package/dist/definitions/steps/define-step.d.ts +137 -0
- package/dist/definitions/steps/env.d.ts +136 -0
- package/dist/definitions/steps/index.d.ts +14 -0
- package/dist/definitions/steps/index.js +73 -0
- package/dist/definitions/steps/mcp-server-config.d.ts +102 -0
- package/dist/definitions/steps/prompt-template.d.ts +24 -0
- package/dist/definitions/steps/repo.d.ts +67 -0
- package/dist/definitions/steps/runtime.d.ts +115 -0
- package/dist/definitions/steps/step-definitions-client.d.ts +400 -0
- package/dist/definitions/steps/step-features.d.ts +109 -0
- package/dist/definitions/steps/step-handle.d.ts +25 -0
- package/dist/definitions/steps/step-ref.d.ts +19 -0
- package/dist/definitions/validation/index.d.ts +2 -0
- package/dist/definitions/validation/index.js +17 -0
- package/dist/definitions/validation/validate-artifact-markers.d.ts +3 -0
- package/dist/definitions/validation/validate-artifacts.d.ts +7 -0
- package/dist/definitions/validation/validate-definition-specs.d.ts +16 -0
- package/dist/definitions/validation/validate-env.d.ts +15 -0
- package/dist/definitions/validation/validate-repo.d.ts +13 -0
- package/dist/definitions/validation/validate-runtime.d.ts +12 -0
- package/dist/definitions/validation/validation-issue.d.ts +11 -0
- package/dist/devcontainer-config-path.d.ts +21 -0
- package/dist/devcontainer-config-path.js +13 -0
- package/dist/env-vars.d.ts +136 -0
- package/dist/env-vars.js +35 -0
- package/dist/eslint.d.ts +42 -0
- package/dist/eslint.js +125 -0
- package/dist/generated/client/client.gen.d.ts +2 -0
- package/dist/generated/client/index.d.ts +8 -0
- package/dist/generated/client/types.gen.d.ts +117 -0
- package/dist/generated/client/utils.gen.d.ts +33 -0
- package/dist/generated/client.gen.d.ts +12 -0
- package/dist/generated/core/auth.gen.d.ts +18 -0
- package/dist/generated/core/bodySerializer.gen.d.ts +25 -0
- package/dist/generated/core/params.gen.d.ts +43 -0
- package/dist/generated/core/pathSerializer.gen.d.ts +33 -0
- package/dist/generated/core/queryKeySerializer.gen.d.ts +18 -0
- package/dist/generated/core/serverSentEvents.gen.d.ts +71 -0
- package/dist/generated/core/types.gen.d.ts +78 -0
- package/dist/generated/core/utils.gen.d.ts +19 -0
- package/dist/generated/index.d.ts +2 -0
- package/dist/generated/sdk.gen.d.ts +302 -0
- package/dist/generated/types.gen.d.ts +18368 -0
- package/dist/git-url/git-remote.d.ts +30 -0
- package/dist/git-url/git-repo-identity.d.ts +44 -0
- package/dist/git-url/git-repo-identity.js +159 -0
- package/dist/git-url/parse-git-host.d.ts +23 -0
- package/dist/health-checks.d.ts +169 -0
- package/dist/health-checks.js +19 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +293 -0
- package/dist/jsonc.d.ts +3 -0
- package/dist/jsonc.js +11 -0
- package/dist/managed-runtimes.d.ts +20 -0
- package/dist/managed-runtimes.js +13 -0
- package/dist/opencode-mcp.d.ts +313 -0
- package/dist/opencode-mcp.js +29 -0
- package/dist/pipelines/chain.d.ts +7 -0
- package/dist/pipelines/compile-args.d.ts +12 -0
- package/dist/pipelines/compile-chain.d.ts +9 -0
- package/dist/pipelines/compile-checks.d.ts +16 -0
- package/dist/pipelines/compile-state.d.ts +30 -0
- package/dist/pipelines/condition-data.d.ts +78 -0
- package/dist/pipelines/conditions.d.ts +47 -0
- package/dist/pipelines/context.d.ts +16 -0
- package/dist/pipelines/define-pipeline.d.ts +32 -0
- package/dist/pipelines/each.d.ts +5 -0
- package/dist/pipelines/errors.d.ts +26 -0
- package/dist/pipelines/handles.d.ts +29 -0
- package/dist/pipelines/index.d.ts +18 -0
- package/dist/pipelines/index.js +80 -0
- package/dist/pipelines/model.d.ts +103 -0
- package/dist/pipelines/nodes.d.ts +54 -0
- package/dist/pipelines/ref-types.d.ts +54 -0
- package/dist/pipelines/refs.d.ts +80 -0
- package/dist/pipelines/registry.d.ts +12 -0
- package/dist/pipelines/source.d.ts +17 -0
- package/dist/pipelines/types.d.ts +160 -0
- package/dist/push/code-step-lookup.d.ts +32 -0
- package/dist/push/code-step-lookup.js +11 -0
- package/dist/push/collect-definitions.d.ts +70 -0
- package/dist/push/collect-pipeline-documents.d.ts +14 -0
- package/dist/push/index.d.ts +6 -0
- package/dist/push/index.js +328 -0
- package/dist/push/push-from-directory.d.ts +37 -0
- package/dist/repo-config.d.ts +80 -0
- package/dist/repo-config.js +23 -0
- package/dist/scarn-config-parser.d.ts +29 -0
- package/dist/scarn-config-parser.js +9 -0
- package/dist/task-plane-client.d.ts +489 -0
- package/dist/z.d.ts +7 -0
- package/package.json +132 -4
- package/README.md +0 -3
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import"../chunk-eg1hcvhb.js";
|
|
3
|
+
import {
|
|
4
|
+
isStepDefinitionSpec2,
|
|
5
|
+
stepsInModule2
|
|
6
|
+
} from "../chunk-njd6npf0.js";
|
|
7
|
+
import {
|
|
8
|
+
createClient,
|
|
9
|
+
Projects2
|
|
10
|
+
} from "../chunk-ynk2bjae.js";
|
|
11
|
+
import {
|
|
12
|
+
PipelineDefinitionsApiError2,
|
|
13
|
+
createPipelineDefinitionsClient2,
|
|
14
|
+
DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2,
|
|
15
|
+
serializeDefaultPipelineAssignment2,
|
|
16
|
+
isDefaultPipelineAssignmentSpec2
|
|
17
|
+
} from "../chunk-qpw5wt1p.js";
|
|
18
|
+
import"../chunk-56e4kp0a.js";
|
|
19
|
+
import"../chunk-631ffb6r.js";
|
|
20
|
+
import"../chunk-zpqyjgb4.js";
|
|
21
|
+
import"../chunk-9s07v9r1.js";
|
|
22
|
+
import"../chunk-s0gap8r8.js";
|
|
23
|
+
import"../chunk-p6kc9wq8.js";
|
|
24
|
+
import {
|
|
25
|
+
toStepSpec2,
|
|
26
|
+
createStepDefinitionsClient2
|
|
27
|
+
} from "../chunk-91p9vzcs.js";
|
|
28
|
+
import"../chunk-b21233rt.js";
|
|
29
|
+
import"../chunk-g0rdnn0r.js";
|
|
30
|
+
import {
|
|
31
|
+
assertValidDefinitionSpecs2
|
|
32
|
+
} from "../chunk-ny07ncb9.js";
|
|
33
|
+
import {
|
|
34
|
+
string,
|
|
35
|
+
unknown,
|
|
36
|
+
object,
|
|
37
|
+
looseObject
|
|
38
|
+
} from "../chunk-dnn39qt4.js";
|
|
39
|
+
|
|
40
|
+
// src/push/collect-definitions.ts
|
|
41
|
+
import { existsSync, readdirSync } from "fs";
|
|
42
|
+
import { join, relative, resolve } from "path";
|
|
43
|
+
import { pathToFileURL } from "url";
|
|
44
|
+
var INTERNAL_SCRIPT_NAMES = new Set([
|
|
45
|
+
"push.ts",
|
|
46
|
+
"push.mjs",
|
|
47
|
+
"push.js",
|
|
48
|
+
".scarn-studio-collect.mjs",
|
|
49
|
+
".scarn-build.ts"
|
|
50
|
+
]);
|
|
51
|
+
var PIPELINE_BUILDER_DIR = ".scarn/pipeline-builder";
|
|
52
|
+
function createCollectionState() {
|
|
53
|
+
return { stepMap: new Map, codeSteps: new Map };
|
|
54
|
+
}
|
|
55
|
+
function registerCodeStep(state, spec, sourceFile) {
|
|
56
|
+
const fn = spec.entrypoint?.fn;
|
|
57
|
+
if (spec.kind !== "code" || !fn)
|
|
58
|
+
return;
|
|
59
|
+
const existing = state.codeSteps.get(spec.key);
|
|
60
|
+
if (!existing) {
|
|
61
|
+
state.codeSteps.set(spec.key, { version: spec.version, fn, sourceFile });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (existing.version !== spec.version) {
|
|
65
|
+
throw new Error(`Code step "${spec.key}" is defined with different versions ` + `(v${String(existing.version)} in ${existing.sourceFile}, v${String(spec.version)} in ${sourceFile}). ` + `A code step is found by key alone, so give each code step a unique key.`);
|
|
66
|
+
}
|
|
67
|
+
if (existing.fn !== fn) {
|
|
68
|
+
throw new Error(`Code step "${spec.key}" is defined with different fn references ` + `(${existing.sourceFile} and ${sourceFile}). ` + `A code step is found by key alone, so give each code step a unique key.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function resolveCodeStepEntrypoint(spec, absoluteFilePath, absDir) {
|
|
72
|
+
if (spec.kind !== "code")
|
|
73
|
+
return toStepSpec2(spec);
|
|
74
|
+
if (!spec.entrypoint?.fn) {
|
|
75
|
+
throw new Error(`Code step "${spec.key}" (kind: "code") has no entrypoint.fn. ` + `Build it with codeStep({ fn, ... }) from "@scarn/sdk/definitions/steps".`);
|
|
76
|
+
}
|
|
77
|
+
const resolved = toStepSpec2(spec);
|
|
78
|
+
delete resolved.entrypoint;
|
|
79
|
+
resolved.entrypointJson = {
|
|
80
|
+
sourceFile: join(PIPELINE_BUILDER_DIR, relative(absDir, absoluteFilePath))
|
|
81
|
+
};
|
|
82
|
+
return resolved;
|
|
83
|
+
}
|
|
84
|
+
async function importModule(path) {
|
|
85
|
+
return await import(pathToFileURL(path).href);
|
|
86
|
+
}
|
|
87
|
+
function listSourceFiles(absDir) {
|
|
88
|
+
const allFiles = readdirSync(absDir).filter((file) => file.endsWith(".ts") || file.endsWith(".js"));
|
|
89
|
+
return allFiles.filter((file) => !INTERNAL_SCRIPT_NAMES.has(file) && file !== DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2);
|
|
90
|
+
}
|
|
91
|
+
function fileNameWithoutExtension(file) {
|
|
92
|
+
return file.replace(/\.(ts|js)$/, "");
|
|
93
|
+
}
|
|
94
|
+
async function collectFile(absoluteFilePath, absDir, state) {
|
|
95
|
+
const mod = await importModule(absoluteFilePath);
|
|
96
|
+
for (const step of stepsInModule2(mod)) {
|
|
97
|
+
registerCodeStep(state, step, absoluteFilePath);
|
|
98
|
+
}
|
|
99
|
+
for (const [exportName, value] of Object.entries(mod)) {
|
|
100
|
+
if (exportName === "default" || !isStepDefinitionSpec2(value))
|
|
101
|
+
continue;
|
|
102
|
+
const resolved = resolveCodeStepEntrypoint(value, absoluteFilePath, absDir);
|
|
103
|
+
state.stepMap.set(`${resolved.key}@v${String(resolved.version)}`, resolved);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function collectDefinitionsFromDirectory(dir) {
|
|
107
|
+
const absDir = resolve(dir);
|
|
108
|
+
const sourceFiles = listSourceFiles(absDir);
|
|
109
|
+
const state = createCollectionState();
|
|
110
|
+
for (const file of sourceFiles) {
|
|
111
|
+
await collectFile(join(absDir, file), absDir, state);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
steps: [...state.stepMap.values()],
|
|
115
|
+
defaultPipelineAssignment: await collectDefaultPipelineAssignment(absDir)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function collectDefinitionsFromDirectoryTolerant(dir) {
|
|
119
|
+
const absDir = resolve(dir);
|
|
120
|
+
const sourceFiles = listSourceFiles(absDir);
|
|
121
|
+
const state = createCollectionState();
|
|
122
|
+
const brokenPipelines = [];
|
|
123
|
+
for (const file of sourceFiles) {
|
|
124
|
+
try {
|
|
125
|
+
await collectFile(join(absDir, file), absDir, state);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
brokenPipelines.push({
|
|
128
|
+
key: fileNameWithoutExtension(file),
|
|
129
|
+
message: error instanceof Error ? error.message : String(error)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
let defaultPipelineAssignment = null;
|
|
134
|
+
try {
|
|
135
|
+
defaultPipelineAssignment = await collectDefaultPipelineAssignment(absDir);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
brokenPipelines.push({
|
|
138
|
+
key: fileNameWithoutExtension(DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2),
|
|
139
|
+
message: error instanceof Error ? error.message : String(error)
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
steps: [...state.stepMap.values()],
|
|
144
|
+
defaultPipelineAssignment,
|
|
145
|
+
brokenPipelines
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async function collectDefaultPipelineAssignment(absDir) {
|
|
149
|
+
const path = join(absDir, DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2);
|
|
150
|
+
if (!existsSync(path))
|
|
151
|
+
return null;
|
|
152
|
+
const mod = await importModule(path);
|
|
153
|
+
const spec = mod["default"];
|
|
154
|
+
if (!isDefaultPipelineAssignmentSpec2(spec)) {
|
|
155
|
+
throw new Error(`${DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2} must have a default export produced by defaultPipelineAssignment(({ assign, skip, ... }) => ({ default: ..., rules: [...] })). Got: ${typeof spec}`);
|
|
156
|
+
}
|
|
157
|
+
return spec;
|
|
158
|
+
}
|
|
159
|
+
// src/push/collect-pipeline-documents.ts
|
|
160
|
+
import { readdirSync as readdirSync2, readFileSync } from "fs";
|
|
161
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
162
|
+
var NON_PIPELINE_JSON = new Set([
|
|
163
|
+
"package.json",
|
|
164
|
+
"package-lock.json",
|
|
165
|
+
"tsconfig.json",
|
|
166
|
+
"jsconfig.json",
|
|
167
|
+
"deno.json"
|
|
168
|
+
]);
|
|
169
|
+
var pipelineDocumentSchema = looseObject({ nodes: unknown() });
|
|
170
|
+
var documentHeaderSchema = object({
|
|
171
|
+
key: string().min(1),
|
|
172
|
+
title: string().optional()
|
|
173
|
+
});
|
|
174
|
+
function collectPipelineDocuments(dir) {
|
|
175
|
+
const absDir = resolve2(dir);
|
|
176
|
+
const files = readdirSync2(absDir).filter((file) => file.endsWith(".json") && !NON_PIPELINE_JSON.has(file)).sort();
|
|
177
|
+
const byKey = new Map;
|
|
178
|
+
for (const file of files) {
|
|
179
|
+
const parsed = pipelineDocumentSchema.safeParse(parseJsonFile(join2(absDir, file), file));
|
|
180
|
+
if (!parsed.success)
|
|
181
|
+
continue;
|
|
182
|
+
const document = parsed.data;
|
|
183
|
+
const header = documentHeaderSchema.safeParse(document);
|
|
184
|
+
if (!header.success) {
|
|
185
|
+
throw new Error(`${file} has no "key": every pipeline document names the pipeline it publishes to.`);
|
|
186
|
+
}
|
|
187
|
+
const { key, title } = header.data;
|
|
188
|
+
const existing = byKey.get(key);
|
|
189
|
+
if (existing) {
|
|
190
|
+
throw new Error(`${existing.file} and ${file} are both pipeline "${key}". Delete the stale one and build again.`);
|
|
191
|
+
}
|
|
192
|
+
byKey.set(key, { file, key, title, document });
|
|
193
|
+
}
|
|
194
|
+
return [...byKey.values()];
|
|
195
|
+
}
|
|
196
|
+
function parseJsonFile(path, file) {
|
|
197
|
+
try {
|
|
198
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
199
|
+
} catch (error) {
|
|
200
|
+
throw new Error(`${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// src/push/push-from-directory.ts
|
|
204
|
+
async function pushFromDirectory(dir, opts) {
|
|
205
|
+
const log = opts.log ?? ((msg) => {
|
|
206
|
+
console.warn(msg);
|
|
207
|
+
});
|
|
208
|
+
const headers = { Authorization: `Bearer ${opts.accessToken}` };
|
|
209
|
+
const collected = await collectDefinitionsFromDirectory(dir);
|
|
210
|
+
const { steps } = collected;
|
|
211
|
+
const documents = collectPipelineDocuments(dir);
|
|
212
|
+
log(`Found ${String(steps.length)} step(s) and ${String(documents.length)} pipeline document(s).`);
|
|
213
|
+
assertValidDefinitionSpecs2(steps);
|
|
214
|
+
const stepsClient = createStepDefinitionsClient2(opts.baseUrl);
|
|
215
|
+
for (const spec of steps) {
|
|
216
|
+
await stepsClient.upsertFromSpec(opts.projectId, spec, { headers });
|
|
217
|
+
log(`\u2713 step ${spec.key} v${String(spec.version)} \u2192 upserted`);
|
|
218
|
+
}
|
|
219
|
+
const pipelinesClient = createPipelineDefinitionsClient2(opts.baseUrl);
|
|
220
|
+
const publishedPipelines = [];
|
|
221
|
+
const unchangedPipelines = [];
|
|
222
|
+
if (documents.length > 0) {
|
|
223
|
+
const serverPipelines = await pipelinesClient.listByProjectId(opts.projectId, { headers });
|
|
224
|
+
const idByKey = new Map(serverPipelines.map((p) => [p.key, p.id]));
|
|
225
|
+
for (const document of documents) {
|
|
226
|
+
const published = await publishPipelineDocument(document, idByKey.get(document.key), opts.projectId, headers, pipelinesClient, log);
|
|
227
|
+
(published ? publishedPipelines : unchangedPipelines).push(document.key);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const syncedDefaultPipelineAssignment = collected.defaultPipelineAssignment ? await syncDefaultPipelineAssignment(collected.defaultPipelineAssignment, opts, headers, pipelinesClient, log) : false;
|
|
231
|
+
return {
|
|
232
|
+
pushedSteps: steps.length,
|
|
233
|
+
publishedPipelines,
|
|
234
|
+
unchangedPipelines,
|
|
235
|
+
syncedDefaultPipelineAssignment
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
async function publishPipelineDocument({ file, key, title, document }, pipelineDefinitionId, projectId, headers, pipelinesClient, log) {
|
|
239
|
+
try {
|
|
240
|
+
if (pipelineDefinitionId === undefined) {
|
|
241
|
+
await pipelinesClient.create({ projectId, key, name: title ?? key, document }, { headers });
|
|
242
|
+
log(`\u2713 pipeline ${key} \u2192 created and published (${file})`);
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
const result = await pipelinesClient.publishVersion(pipelineDefinitionId, document, { headers });
|
|
246
|
+
const version = String(result.version.version);
|
|
247
|
+
log(result.published ? `\u2713 pipeline ${key} v${version} \u2192 published (${file})` : `\u2713 pipeline ${key} v${version} \u2192 unchanged (${file})`);
|
|
248
|
+
return result.published;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if (error instanceof PipelineDefinitionsApiError2) {
|
|
251
|
+
const issues = error.issues.map((issue) => issue.hint === undefined ? ` ${issue.path || "/"}: ${issue.message}` : ` ${issue.path || "/"}: ${issue.message}. ${issue.hint}`);
|
|
252
|
+
throw new Error([`Could not publish ${file}: ${error.message}`, ...issues].join(`
|
|
253
|
+
`), { cause: error });
|
|
254
|
+
}
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async function syncDefaultPipelineAssignment(spec, opts, headers, pipelinesClient, log) {
|
|
259
|
+
const serialized = serializeDefaultPipelineAssignment2(spec);
|
|
260
|
+
const serverPipelines = await pipelinesClient.listByProjectId(opts.projectId, {
|
|
261
|
+
headers
|
|
262
|
+
});
|
|
263
|
+
const pipelineKeyToId = new Map(serverPipelines.map((p) => [p.key, p.id]));
|
|
264
|
+
const referencedKeys = new Set;
|
|
265
|
+
referencedKeys.add(serialized.pipelineDefinitionKey);
|
|
266
|
+
for (const rule of serialized.rulesJson.rules) {
|
|
267
|
+
if (rule.event.type === "assign" && typeof rule.event.params?.["pipelineKey"] === "string") {
|
|
268
|
+
referencedKeys.add(rule.event.params["pipelineKey"]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
for (const key of referencedKeys) {
|
|
272
|
+
if (!pipelineKeyToId.has(key)) {
|
|
273
|
+
throw new Error(`${DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2} references pipeline "${key}", ` + `but no pipeline with that key was found on the server. ` + `Run \`scarn pipelines build\` to write ${key}.json next to its source, then push again.`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const pipelineDefinitionId = pipelineKeyToId.get(serialized.pipelineDefinitionKey);
|
|
277
|
+
if (!pipelineDefinitionId) {
|
|
278
|
+
throw new Error(`Pipeline key "${serialized.pipelineDefinitionKey}" was not found on the server.`);
|
|
279
|
+
}
|
|
280
|
+
const resolvedRules = serialized.rulesJson.rules.map((rule) => {
|
|
281
|
+
if (rule.event.type === "assign" && typeof rule.event.params?.["pipelineKey"] === "string") {
|
|
282
|
+
const pKey = rule.event.params["pipelineKey"];
|
|
283
|
+
const pId = pipelineKeyToId.get(pKey);
|
|
284
|
+
if (!pId) {
|
|
285
|
+
throw new Error(`${DEFAULT_PIPELINE_ASSIGNMENT_FILENAME2} assign() references pipeline "${pKey}" ` + `which was not found on the server.`);
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
...rule,
|
|
289
|
+
event: {
|
|
290
|
+
...rule.event,
|
|
291
|
+
params: {
|
|
292
|
+
...rule.event.params,
|
|
293
|
+
pipelineDefinitionId: pId
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return rule;
|
|
299
|
+
});
|
|
300
|
+
const projectsClient = new Projects2({
|
|
301
|
+
client: createClient({ baseUrl: opts.baseUrl })
|
|
302
|
+
});
|
|
303
|
+
const result = await projectsClient.updateProjectDefaultPipelineAssignment({
|
|
304
|
+
path: { projectId: opts.projectId },
|
|
305
|
+
body: {
|
|
306
|
+
defaultPipelineAssignment: {
|
|
307
|
+
pipelineDefinitionId,
|
|
308
|
+
rulesJson: { rules: resolvedRules },
|
|
309
|
+
defaultEventType: serialized.defaultEventType,
|
|
310
|
+
defaultEventParamsJson: serialized.defaultEventParamsJson,
|
|
311
|
+
allowedEventTypes: serialized.allowedEventTypes
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
headers
|
|
315
|
+
});
|
|
316
|
+
if (result.error) {
|
|
317
|
+
throw new Error(`Failed to update project default pipeline assignment: ${JSON.stringify(result.error)}`);
|
|
318
|
+
}
|
|
319
|
+
log(`\u2713 default pipeline assignment \u2192 synced (primary pipeline: ${serialized.pipelineDefinitionKey})`);
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
export {
|
|
323
|
+
PIPELINE_BUILDER_DIR,
|
|
324
|
+
collectDefinitionsFromDirectory,
|
|
325
|
+
collectDefinitionsFromDirectoryTolerant,
|
|
326
|
+
collectPipelineDocuments,
|
|
327
|
+
pushFromDirectory
|
|
328
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface PushFromDirectoryOptions {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
projectId: string;
|
|
4
|
+
accessToken: string;
|
|
5
|
+
/** Override the logger; defaults to console.log. */
|
|
6
|
+
log?: (message: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface PushFromDirectoryResult {
|
|
9
|
+
pushedSteps: number;
|
|
10
|
+
/** Keys of the pipelines that got a new active version. */
|
|
11
|
+
publishedPipelines: string[];
|
|
12
|
+
/** Keys of the pipelines whose document matched their latest version. */
|
|
13
|
+
unchangedPipelines: string[];
|
|
14
|
+
/** true if the default pipeline assignment was synced to the server. */
|
|
15
|
+
syncedDefaultPipelineAssignment: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Pushes a pipeline-builder directory to the server, in three passes:
|
|
19
|
+
*
|
|
20
|
+
* 1. Upserts every step exported from the `.ts`/`.js` files (except the push
|
|
21
|
+
* script itself and `default-pipeline-assignment.ts`).
|
|
22
|
+
* 2. Publishes every built pipeline document (`<key>.json`, from
|
|
23
|
+
* `scarn pipelines build`), creating the pipeline when its key is new.
|
|
24
|
+
* The server pins each document to the steps just pushed; a document
|
|
25
|
+
* identical to its latest version publishes nothing.
|
|
26
|
+
* 3. Syncs `default-pipeline-assignment.ts`, when present, as the project
|
|
27
|
+
* default pipeline assignment. Every pipeline it assigns must exist by now.
|
|
28
|
+
*
|
|
29
|
+
* Collection (`collectDefinitionsFromDirectory`, `collectPipelineDocuments`)
|
|
30
|
+
* and step validation (`validateDefinitionSpecs`) are offline and run before
|
|
31
|
+
* the first mutating request, so an invalid batch fails without half-pushing.
|
|
32
|
+
*
|
|
33
|
+
* Designed to run on the user's native runtime (bun, node-with-tsx, deno),
|
|
34
|
+
* NOT inside a `bun --compile`'d binary — that runtime can't resolve scoped
|
|
35
|
+
* package `exports` field remappings from external user files.
|
|
36
|
+
*/
|
|
37
|
+
export declare function pushFromDirectory(dir: string, opts: PushFromDirectoryOptions): Promise<PushFromDirectoryResult>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Wire schema for a step's repository access (`repo`): what the worker does
|
|
4
|
+
* with the clone.
|
|
5
|
+
*
|
|
6
|
+
* - `none`: no repository. The worker does not clone, branch, commit or push.
|
|
7
|
+
* - `readOnly`: clones and checks out the base branch, but creates no work
|
|
8
|
+
* branch, commits nothing and pushes nothing.
|
|
9
|
+
* - `readWrite`: creates a work branch, commits and pushes. `message` is the
|
|
10
|
+
* commit message template (`{{input.…}}` and `{{result.…}}` tokens only) and
|
|
11
|
+
* `onPushFailure` picks whether a failed push fails the step.
|
|
12
|
+
*
|
|
13
|
+
* Two shapes of the same data. `RepoConfigInput` is what an author or API client
|
|
14
|
+
* sends and may leave things out; `RepoConfig` is what is stored, returned and
|
|
15
|
+
* handed to the worker, fully resolved by `resolveRepoConfig`. A resolved
|
|
16
|
+
* `RepoConfig` is also a valid `RepoConfigInput`, so a client can send back what
|
|
17
|
+
* it read (hence a `null` message is accepted on input).
|
|
18
|
+
*
|
|
19
|
+
* Which modes each runtime accepts is `REPO_RUNTIME_SUPPORT`; a new runtime adds
|
|
20
|
+
* a row there instead of changing the schema.
|
|
21
|
+
*/
|
|
22
|
+
export declare const MAX_REPO_COMMIT_MESSAGE_LENGTH = 500;
|
|
23
|
+
export declare const REPO_COMMIT_MESSAGE_TOKEN_ROOTS: readonly string[];
|
|
24
|
+
export type RepoMode = "none" | "readOnly" | "readWrite";
|
|
25
|
+
export type RepoOnPushFailure = "fail" | "warn";
|
|
26
|
+
export type RepoExecutionMode = "workspace" | "no_workspace";
|
|
27
|
+
/**
|
|
28
|
+
* The root segment of every `{{…}}` token in `message` that is not one of
|
|
29
|
+
* `REPO_COMMIT_MESSAGE_TOKEN_ROOTS`, in order of appearance. Tokens are parsed
|
|
30
|
+
* the way `renderPromptTemplate` renders them.
|
|
31
|
+
*/
|
|
32
|
+
export declare function findDisallowedCommitMessageTokenRoots(message: string): string[];
|
|
33
|
+
export declare const repoCommitMessageSchema: z.ZodString;
|
|
34
|
+
export declare const repoConfigInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
35
|
+
mode: z.ZodLiteral<"none">;
|
|
36
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
37
|
+
mode: z.ZodLiteral<"readOnly">;
|
|
38
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
39
|
+
mode: z.ZodLiteral<"readWrite">;
|
|
40
|
+
message: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
|
+
onPushFailure: z.ZodOptional<z.ZodEnum<{
|
|
42
|
+
warn: "warn";
|
|
43
|
+
fail: "fail";
|
|
44
|
+
}>>;
|
|
45
|
+
}, z.core.$strict>], "mode">;
|
|
46
|
+
export declare const repoConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
47
|
+
mode: z.ZodLiteral<"none">;
|
|
48
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
49
|
+
mode: z.ZodLiteral<"readOnly">;
|
|
50
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
51
|
+
mode: z.ZodLiteral<"readWrite">;
|
|
52
|
+
message: z.ZodNullable<z.ZodString>;
|
|
53
|
+
onPushFailure: z.ZodEnum<{
|
|
54
|
+
warn: "warn";
|
|
55
|
+
fail: "fail";
|
|
56
|
+
}>;
|
|
57
|
+
}, z.core.$strict>], "mode">;
|
|
58
|
+
export type RepoConfigInput = z.input<typeof repoConfigInputSchema>;
|
|
59
|
+
export type RepoConfig = z.output<typeof repoConfigSchema>;
|
|
60
|
+
type RepoRuntimeSupport = {
|
|
61
|
+
readonly modes: readonly RepoMode[];
|
|
62
|
+
readonly default: RepoMode;
|
|
63
|
+
/** Why the modes outside `modes` are rejected. */
|
|
64
|
+
readonly unsupportedBecause: string;
|
|
65
|
+
};
|
|
66
|
+
/** Which `repo` modes each execution mode accepts, and its default. */
|
|
67
|
+
export declare const REPO_RUNTIME_SUPPORT: Record<RepoExecutionMode, RepoRuntimeSupport>;
|
|
68
|
+
/**
|
|
69
|
+
* Why `mode` cannot be used with `executionMode`, or `null` when the pair is
|
|
70
|
+
* valid.
|
|
71
|
+
*/
|
|
72
|
+
export declare function repoRuntimeMismatch(executionMode: RepoExecutionMode, mode: RepoMode): string | null;
|
|
73
|
+
/**
|
|
74
|
+
* Fills what an author left out: an omitted `repo` becomes the runtime's default
|
|
75
|
+
* (`readWrite` for `workspace`, `none` for `no_workspace`), an omitted
|
|
76
|
+
* `onPushFailure` becomes `"fail"` and an omitted `message` becomes `null`.
|
|
77
|
+
* Does not check the runtime pairing; that is the caller's invariant.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveRepoConfig(executionMode: RepoExecutionMode, input?: RepoConfigInput | null): RepoConfig;
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
MAX_REPO_COMMIT_MESSAGE_LENGTH2,
|
|
4
|
+
REPO_COMMIT_MESSAGE_TOKEN_ROOTS2,
|
|
5
|
+
findDisallowedCommitMessageTokenRoots2,
|
|
6
|
+
repoCommitMessageSchema2,
|
|
7
|
+
repoConfigInputSchema2,
|
|
8
|
+
repoConfigSchema2,
|
|
9
|
+
REPO_RUNTIME_SUPPORT2,
|
|
10
|
+
repoRuntimeMismatch2,
|
|
11
|
+
resolveRepoConfig2
|
|
12
|
+
} from "./chunk-b21233rt.js";
|
|
13
|
+
export {
|
|
14
|
+
MAX_REPO_COMMIT_MESSAGE_LENGTH2 as MAX_REPO_COMMIT_MESSAGE_LENGTH,
|
|
15
|
+
REPO_COMMIT_MESSAGE_TOKEN_ROOTS2 as REPO_COMMIT_MESSAGE_TOKEN_ROOTS,
|
|
16
|
+
REPO_RUNTIME_SUPPORT2 as REPO_RUNTIME_SUPPORT,
|
|
17
|
+
findDisallowedCommitMessageTokenRoots2 as findDisallowedCommitMessageTokenRoots,
|
|
18
|
+
repoCommitMessageSchema2 as repoCommitMessageSchema,
|
|
19
|
+
repoConfigInputSchema2 as repoConfigInputSchema,
|
|
20
|
+
repoConfigSchema2 as repoConfigSchema,
|
|
21
|
+
repoRuntimeMismatch2 as repoRuntimeMismatch,
|
|
22
|
+
resolveRepoConfig2 as resolveRepoConfig
|
|
23
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const SCARN_CONFIG_RELATIVE_PATH = ".scarn/scarn.jsonc";
|
|
2
|
+
export type ScarnCommandDefinition = {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
run: string;
|
|
6
|
+
cwd: string | null;
|
|
7
|
+
};
|
|
8
|
+
export type ScarnServiceDefinition = {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
run: string;
|
|
12
|
+
cwd: string | null;
|
|
13
|
+
dependsOn: string[];
|
|
14
|
+
expose: {
|
|
15
|
+
targetPort: number;
|
|
16
|
+
protocol: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export type ScarnConfig = {
|
|
20
|
+
commands: ScarnCommandDefinition[];
|
|
21
|
+
services: ScarnServiceDefinition[];
|
|
22
|
+
};
|
|
23
|
+
export type ParseScarnConfigResult = {
|
|
24
|
+
found: false;
|
|
25
|
+
} | {
|
|
26
|
+
found: true;
|
|
27
|
+
config: ScarnConfig;
|
|
28
|
+
};
|
|
29
|
+
export declare function parseScarnConfig(workspacePath: string): Promise<ParseScarnConfigResult>;
|