@scarn/sdk 0.0.0 → 0.8.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 → chunk-0y2fy5en.js} +7 -7
- package/dist/{chunk-91p9vzcs.js → chunk-3ctaaseb.js} +405 -402
- package/dist/{chunk-9s07v9r1.js → chunk-4ggr8af6.js} +8 -8
- package/dist/chunk-5zsavw98.js +91 -0
- package/dist/chunk-63f90zky.js +39 -0
- package/dist/{chunk-tfm5hjzm.js → chunk-700xe701.js} +9 -9
- package/dist/{chunk-njd6npf0.js → chunk-ar6hcj1r.js} +6 -6
- package/dist/chunk-cdanncng.js +74 -0
- package/dist/chunk-dp86pa6m.js +68 -0
- package/dist/chunk-e1h021kq.js +86 -0
- package/dist/{chunk-ny07ncb9.js → chunk-gds7w7zh.js} +35 -35
- package/dist/chunk-k4y5qt4y.js +14 -0
- package/dist/{chunk-eg1hcvhb.js → chunk-mz53r914.js} +16 -16
- package/dist/{chunk-631ffb6r.js → chunk-ngy1fdcx.js} +10 -10
- package/dist/chunk-p7yrcmqm.js +322 -0
- package/dist/{chunk-h9yxx0hd.js → chunk-rt9tq4j6.js} +7 -7
- package/dist/{chunk-dnn39qt4.js → chunk-skzxcba3.js} +2960 -2217
- package/dist/{chunk-ynk2bjae.js → chunk-vfeytkqx.js} +89 -88
- package/dist/{chunk-56e4kp0a.js → chunk-y2pv8d6a.js} +19 -19
- package/dist/chunk-y64skrwp.js +17 -0
- package/dist/{chunk-rq3q8vg7.js → chunk-yjtaq94c.js} +69 -69
- package/dist/{chunk-qpw5wt1p.js → chunk-zm72ksz0.js} +26 -27
- package/dist/client.js +53 -52
- package/dist/contracts/artifact-markers.js +12 -11
- package/dist/contracts/artifacts.js +23 -21
- package/dist/contracts/pipeline-document/index.js +94 -92
- package/dist/contracts/step-artifact-submissions.js +17 -20
- package/dist/defaults/index.js +140 -139
- package/dist/definitions/pipelines/index.js +22 -20
- package/dist/definitions/steps/index.js +70 -67
- package/dist/definitions/validation/index.js +15 -13
- package/dist/devcontainer-config-path.js +11 -9
- package/dist/env-vars.js +33 -31
- package/dist/eslint.js +2 -0
- package/dist/generated/types.gen.d.ts +7 -0
- package/dist/git-url/git-repo-identity.js +2 -0
- package/dist/health-checks.js +17 -15
- package/dist/index.js +280 -277
- package/dist/jsonc.js +8 -7
- package/dist/managed-runtimes.js +11 -9
- package/dist/opencode-mcp.js +27 -25
- package/dist/pipelines/index.js +78 -75
- package/dist/push/code-step-lookup.js +8 -7
- package/dist/push/index.js +51 -52
- package/dist/repo-config.js +21 -19
- package/dist/scarn-config-parser.js +6 -5
- package/package.json +1 -1
- package/dist/chunk-4vehh3dq.js +0 -333
- package/dist/chunk-5mmj03ah.js +0 -1074
- package/dist/chunk-b21233rt.js +0 -78
- package/dist/chunk-g0rdnn0r.js +0 -95
- package/dist/chunk-p6kc9wq8.js +0 -97
- package/dist/chunk-s0gap8r8.js +0 -14
- package/dist/chunk-zpqyjgb4.js +0 -49
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
exports_external
|
|
4
|
+
} from "./chunk-skzxcba3.js";
|
|
5
5
|
|
|
6
6
|
// src/devcontainer-config-path.ts
|
|
7
|
-
var
|
|
8
|
-
var
|
|
7
|
+
var MAX_DEVCONTAINER_CONFIG_PATH_LENGTH = 255;
|
|
8
|
+
var DEVCONTAINER_CONFIG_BASENAMES = [
|
|
9
9
|
"devcontainer.json",
|
|
10
10
|
".devcontainer.json"
|
|
11
11
|
];
|
|
12
12
|
var LEADING_CURRENT_DIR = /^(?:\.\/)+/;
|
|
13
13
|
var DRIVE_LETTER = /^[A-Za-z]:/;
|
|
14
|
-
function
|
|
14
|
+
function normalizeDevcontainerConfigPath(path) {
|
|
15
15
|
return path.replace(LEADING_CURRENT_DIR, "");
|
|
16
16
|
}
|
|
17
17
|
function basenameOf(path) {
|
|
18
18
|
return path.slice(Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) + 1);
|
|
19
19
|
}
|
|
20
|
-
var
|
|
20
|
+
var devcontainerConfigPathSchema = exports_external.string().max(MAX_DEVCONTAINER_CONFIG_PATH_LENGTH).overwrite(normalizeDevcontainerConfigPath).refine((path) => !path.includes("\\"), {
|
|
21
21
|
message: "must use forward slashes, not backslashes"
|
|
22
22
|
}).refine((path) => !path.startsWith("/") && !DRIVE_LETTER.test(path), {
|
|
23
23
|
message: "must be relative to the repository root, not absolute"
|
|
24
24
|
}).refine((path) => !path.split("/").includes(".."), {
|
|
25
25
|
message: 'must not contain a ".." segment'
|
|
26
|
-
}).refine((path) =>
|
|
26
|
+
}).refine((path) => DEVCONTAINER_CONFIG_BASENAMES.includes(basenameOf(path)), {
|
|
27
27
|
message: 'must end in "devcontainer.json" or ".devcontainer.json"'
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
export {
|
|
30
|
+
export { MAX_DEVCONTAINER_CONFIG_PATH_LENGTH, DEVCONTAINER_CONFIG_BASENAMES, normalizeDevcontainerConfigPath, devcontainerConfigPathSchema };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
exports_external
|
|
4
|
+
} from "./chunk-skzxcba3.js";
|
|
5
|
+
|
|
6
|
+
// src/env-vars.ts
|
|
7
|
+
var ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
8
|
+
var RESERVED_ENV_VAR_NAMES = [
|
|
9
|
+
"HOME",
|
|
10
|
+
"XDG_CONFIG_HOME",
|
|
11
|
+
"XDG_DATA_HOME",
|
|
12
|
+
"OPENCODE_CONFIG_CONTENT",
|
|
13
|
+
"npm_config_cache"
|
|
14
|
+
];
|
|
15
|
+
var RESERVED_ENV_VAR_PREFIX = "SCARN_";
|
|
16
|
+
var MAX_ENV_VARS = 64;
|
|
17
|
+
var MAX_ENV_VAR_NAME_LENGTH = 128;
|
|
18
|
+
var MAX_ENV_VAR_VALUE_LENGTH = 4096;
|
|
19
|
+
var INPUT_TOKEN_PATTERN = /\{\{input\.[^}]+\}\}/;
|
|
20
|
+
function containsInputToken(value) {
|
|
21
|
+
return INPUT_TOKEN_PATTERN.test(value);
|
|
22
|
+
}
|
|
23
|
+
function isReservedEnvVarName(name) {
|
|
24
|
+
return name.startsWith(RESERVED_ENV_VAR_PREFIX) || RESERVED_ENV_VAR_NAMES.includes(name);
|
|
25
|
+
}
|
|
26
|
+
var envVarNameSchema = exports_external.string().max(MAX_ENV_VAR_NAME_LENGTH).regex(ENV_VAR_NAME_PATTERN, "must match /^[A-Z_][A-Z0-9_]*$/").refine((name) => !isReservedEnvVarName(name), {
|
|
27
|
+
message: `is reserved (SCARN_*, ${RESERVED_ENV_VAR_NAMES.join(", ")})`
|
|
28
|
+
});
|
|
29
|
+
var envVarValueSchema = exports_external.string().max(MAX_ENV_VAR_VALUE_LENGTH);
|
|
30
|
+
var envVarAppliesValues = ["agent", "setup", "both"];
|
|
31
|
+
var envVarAppliesSchema = exports_external.enum(envVarAppliesValues).default("agent");
|
|
32
|
+
function appliesToAgent(applies) {
|
|
33
|
+
return applies !== "setup";
|
|
34
|
+
}
|
|
35
|
+
function appliesToSetup(applies) {
|
|
36
|
+
return applies === "setup" || applies === "both";
|
|
37
|
+
}
|
|
38
|
+
function isUninheritableWorkerEnvVarName(name) {
|
|
39
|
+
return name.toUpperCase().startsWith(RESERVED_ENV_VAR_PREFIX);
|
|
40
|
+
}
|
|
41
|
+
var valueEnvVarSchema = exports_external.object({
|
|
42
|
+
name: envVarNameSchema,
|
|
43
|
+
source: exports_external.literal("value"),
|
|
44
|
+
value: envVarValueSchema,
|
|
45
|
+
secret: exports_external.boolean(),
|
|
46
|
+
applies: envVarAppliesSchema
|
|
47
|
+
}).strict().refine((entry) => !entry.secret || containsInputToken(entry.value), {
|
|
48
|
+
path: ["value"],
|
|
49
|
+
message: "a secret value must contain an {{input.\u2026}} token; a static secret would be stored in plaintext. Use Env.inherit({ secret: true }) instead"
|
|
50
|
+
});
|
|
51
|
+
var inheritEnvVarSchema = exports_external.object({
|
|
52
|
+
name: envVarNameSchema,
|
|
53
|
+
source: exports_external.literal("inherit"),
|
|
54
|
+
from: exports_external.string().max(MAX_ENV_VAR_NAME_LENGTH).regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "must be a valid environment variable name").refine((from) => !isUninheritableWorkerEnvVarName(from), {
|
|
55
|
+
message: `cannot read worker variables starting with ${RESERVED_ENV_VAR_PREFIX}`
|
|
56
|
+
}),
|
|
57
|
+
secret: exports_external.boolean(),
|
|
58
|
+
optional: exports_external.boolean(),
|
|
59
|
+
default: envVarValueSchema.optional(),
|
|
60
|
+
mcp: exports_external.string().min(1).optional(),
|
|
61
|
+
applies: envVarAppliesSchema
|
|
62
|
+
}).strict().refine((entry) => !(entry.secret && entry.default !== undefined), {
|
|
63
|
+
path: ["default"],
|
|
64
|
+
message: "a secret cannot carry a default; it would be stored in plaintext"
|
|
65
|
+
});
|
|
66
|
+
var envVarSpecSchema = exports_external.discriminatedUnion("source", [
|
|
67
|
+
valueEnvVarSchema,
|
|
68
|
+
inheritEnvVarSchema
|
|
69
|
+
]);
|
|
70
|
+
var envVarsSchema = exports_external.array(envVarSpecSchema).max(MAX_ENV_VARS).refine((entries) => new Set(entries.map((entry) => entry.name)).size === entries.length, { message: "environment variable names must be unique" });
|
|
71
|
+
var storedEnvVarsSchema = exports_external.array(exports_external.discriminatedUnion("source", [
|
|
72
|
+
exports_external.object({
|
|
73
|
+
name: exports_external.string(),
|
|
74
|
+
source: exports_external.literal("value"),
|
|
75
|
+
value: exports_external.string(),
|
|
76
|
+
secret: exports_external.boolean(),
|
|
77
|
+
applies: exports_external.enum(envVarAppliesValues).default("agent")
|
|
78
|
+
}),
|
|
79
|
+
exports_external.object({
|
|
80
|
+
name: exports_external.string(),
|
|
81
|
+
source: exports_external.literal("inherit"),
|
|
82
|
+
from: exports_external.string(),
|
|
83
|
+
secret: exports_external.boolean(),
|
|
84
|
+
optional: exports_external.boolean(),
|
|
85
|
+
default: exports_external.string().optional(),
|
|
86
|
+
mcp: exports_external.string().optional(),
|
|
87
|
+
applies: exports_external.enum(envVarAppliesValues).default("agent")
|
|
88
|
+
})
|
|
89
|
+
]));
|
|
90
|
+
|
|
91
|
+
export { ENV_VAR_NAME_PATTERN, RESERVED_ENV_VAR_NAMES, RESERVED_ENV_VAR_PREFIX, MAX_ENV_VARS, MAX_ENV_VAR_NAME_LENGTH, MAX_ENV_VAR_VALUE_LENGTH, containsInputToken, isReservedEnvVarName, envVarAppliesValues, appliesToAgent, appliesToSetup, isUninheritableWorkerEnvVarName, envVarSpecSchema, envVarsSchema, storedEnvVarsSchema };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
exports_external
|
|
4
|
+
} from "./chunk-skzxcba3.js";
|
|
5
|
+
|
|
6
|
+
// src/health-checks.ts
|
|
7
|
+
var healthCheckSeverityValues = ["required", "warn"];
|
|
8
|
+
var healthCheckBaseSchema = exports_external.object({
|
|
9
|
+
name: exports_external.string().trim().min(1).optional(),
|
|
10
|
+
severity: exports_external.enum(healthCheckSeverityValues).default("required"),
|
|
11
|
+
timeoutSeconds: exports_external.number().gt(0).max(3600).default(15),
|
|
12
|
+
serialGroup: exports_external.string().trim().min(1).optional()
|
|
13
|
+
});
|
|
14
|
+
var toolHealthCheckSchema = healthCheckBaseSchema.extend({
|
|
15
|
+
kind: exports_external.literal("tool").default("tool"),
|
|
16
|
+
tool: exports_external.string().trim().min(1),
|
|
17
|
+
mcp: exports_external.string().trim().min(1).optional(),
|
|
18
|
+
args: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
19
|
+
}).strict();
|
|
20
|
+
var cliHealthCheckSchema = healthCheckBaseSchema.extend({
|
|
21
|
+
kind: exports_external.literal("cli"),
|
|
22
|
+
command: exports_external.array(exports_external.string().min(1)).min(1),
|
|
23
|
+
expectExitCode: exports_external.int().default(0)
|
|
24
|
+
}).strict();
|
|
25
|
+
function injectDefaultKind(value) {
|
|
26
|
+
if (typeof value === "object" && value !== null && !("kind" in value)) {
|
|
27
|
+
return { ...value, kind: "tool" };
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
var healthCheckSchema = exports_external.preprocess(injectDefaultKind, exports_external.discriminatedUnion("kind", [toolHealthCheckSchema, cliHealthCheckSchema]));
|
|
32
|
+
var healthChecksSchema = exports_external.array(healthCheckSchema);
|
|
33
|
+
var stepToolHealthCheckSchema = toolHealthCheckSchema.omit({ mcp: true }).strict();
|
|
34
|
+
var stepHealthChecksInputSchema = exports_external.array(exports_external.preprocess(injectDefaultKind, exports_external.discriminatedUnion("kind", [
|
|
35
|
+
stepToolHealthCheckSchema,
|
|
36
|
+
cliHealthCheckSchema
|
|
37
|
+
])));
|
|
38
|
+
|
|
39
|
+
export { healthCheckSeverityValues, toolHealthCheckSchema, cliHealthCheckSchema, healthCheckSchema, healthChecksSchema, stepToolHealthCheckSchema, stepHealthChecksInputSchema };
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
ScarnClient,
|
|
4
|
+
TaskRuns,
|
|
5
|
+
createClient
|
|
6
|
+
} from "./chunk-vfeytkqx.js";
|
|
7
7
|
// src/task-plane-client.ts
|
|
8
8
|
function unwrap(result) {
|
|
9
9
|
if (result.error)
|
|
10
10
|
throw new Error(JSON.stringify(result.error));
|
|
11
11
|
return result.data;
|
|
12
12
|
}
|
|
13
|
-
function
|
|
13
|
+
function createTaskPlaneClient(baseUrl, options) {
|
|
14
14
|
const client = createClient({ baseUrl, headers: options?.headers });
|
|
15
|
-
return buildTaskPlaneClient(new
|
|
15
|
+
return buildTaskPlaneClient(new TaskRuns({ client }));
|
|
16
16
|
}
|
|
17
17
|
var buildTaskPlaneClient = (taskRuns) => {
|
|
18
18
|
return {
|
|
@@ -92,9 +92,9 @@ var buildTaskPlaneClient = (taskRuns) => {
|
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
// src/client.ts
|
|
95
|
-
function
|
|
95
|
+
function createScarnClient(baseUrl) {
|
|
96
96
|
const client = createClient({ baseUrl });
|
|
97
|
-
return new
|
|
97
|
+
return new ScarnClient({ client });
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export {
|
|
100
|
+
export { createTaskPlaneClient, createScarnClient };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/push/code-step-lookup.ts
|
|
3
|
-
function
|
|
3
|
+
function isStepDefinitionSpec(value) {
|
|
4
4
|
if (typeof value !== "object" && typeof value !== "function")
|
|
5
5
|
return false;
|
|
6
6
|
if (value === null)
|
|
@@ -8,18 +8,18 @@ function isStepDefinitionSpec2(value) {
|
|
|
8
8
|
const obj = value;
|
|
9
9
|
return typeof obj["key"] === "string" && typeof obj["name"] === "string" && typeof obj["version"] === "number" && (obj["kind"] === "user_defined" || obj["kind"] === "code");
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function stepsInModule(mod) {
|
|
12
12
|
const found = new Set;
|
|
13
13
|
for (const [exportName, value] of Object.entries(mod)) {
|
|
14
|
-
if (exportName !== "default" &&
|
|
14
|
+
if (exportName !== "default" && isStepDefinitionSpec(value)) {
|
|
15
15
|
found.add(value);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
return [...found];
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function findCodeStepInModule(mod, key) {
|
|
21
21
|
const fns = new Set;
|
|
22
|
-
for (const spec of
|
|
22
|
+
for (const spec of stepsInModule(mod)) {
|
|
23
23
|
if (spec.kind !== "code" || spec.key !== key)
|
|
24
24
|
continue;
|
|
25
25
|
const fn = spec.entrypoint?.fn;
|
|
@@ -32,4 +32,4 @@ function findCodeStepInModule2(mod, key) {
|
|
|
32
32
|
return fns.values().next().value;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export {
|
|
35
|
+
export { isStepDefinitionSpec, stepsInModule, findCodeStepInModule };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
exports_external
|
|
4
|
+
} from "./chunk-skzxcba3.js";
|
|
5
|
+
|
|
6
|
+
// src/repo-config.ts
|
|
7
|
+
var MAX_REPO_COMMIT_MESSAGE_LENGTH = 500;
|
|
8
|
+
var REPO_COMMIT_MESSAGE_TOKEN_ROOTS = [
|
|
9
|
+
"input",
|
|
10
|
+
"result"
|
|
11
|
+
];
|
|
12
|
+
var TOKEN_PATTERN = /\{\{([^}]+)\}\}/g;
|
|
13
|
+
function findDisallowedCommitMessageTokenRoots(message) {
|
|
14
|
+
const disallowed = [];
|
|
15
|
+
for (const match of message.matchAll(TOKEN_PATTERN)) {
|
|
16
|
+
const root = (match[1] ?? "").split(".")[0] ?? "";
|
|
17
|
+
if (!REPO_COMMIT_MESSAGE_TOKEN_ROOTS.includes(root))
|
|
18
|
+
disallowed.push(root);
|
|
19
|
+
}
|
|
20
|
+
return disallowed;
|
|
21
|
+
}
|
|
22
|
+
var repoCommitMessageSchema = exports_external.string().max(MAX_REPO_COMMIT_MESSAGE_LENGTH).refine((message) => !/[\r\n]/.test(message), {
|
|
23
|
+
message: "must be a single line"
|
|
24
|
+
}).refine((message) => findDisallowedCommitMessageTokenRoots(message).length === 0, {
|
|
25
|
+
message: `may only use {{${REPO_COMMIT_MESSAGE_TOKEN_ROOTS.join(".\u2026}}, {{")}.\u2026}} tokens`
|
|
26
|
+
});
|
|
27
|
+
var onPushFailureSchema = exports_external.enum(["fail", "warn"]);
|
|
28
|
+
var repoConfigInputSchema = exports_external.discriminatedUnion("mode", [
|
|
29
|
+
exports_external.object({ mode: exports_external.literal("none") }).strict(),
|
|
30
|
+
exports_external.object({ mode: exports_external.literal("readOnly") }).strict(),
|
|
31
|
+
exports_external.object({
|
|
32
|
+
mode: exports_external.literal("readWrite"),
|
|
33
|
+
message: repoCommitMessageSchema.nullish(),
|
|
34
|
+
onPushFailure: onPushFailureSchema.optional()
|
|
35
|
+
}).strict()
|
|
36
|
+
]);
|
|
37
|
+
var repoConfigSchema = exports_external.discriminatedUnion("mode", [
|
|
38
|
+
exports_external.object({ mode: exports_external.literal("none") }).strict(),
|
|
39
|
+
exports_external.object({ mode: exports_external.literal("readOnly") }).strict(),
|
|
40
|
+
exports_external.object({
|
|
41
|
+
mode: exports_external.literal("readWrite"),
|
|
42
|
+
message: repoCommitMessageSchema.nullable(),
|
|
43
|
+
onPushFailure: onPushFailureSchema
|
|
44
|
+
}).strict()
|
|
45
|
+
]);
|
|
46
|
+
var REPO_RUNTIME_SUPPORT = {
|
|
47
|
+
workspace: {
|
|
48
|
+
modes: ["readOnly", "readWrite"],
|
|
49
|
+
default: "readWrite",
|
|
50
|
+
unsupportedBecause: "a devcontainer step reads its config from the clone"
|
|
51
|
+
},
|
|
52
|
+
no_workspace: {
|
|
53
|
+
modes: ["none"],
|
|
54
|
+
default: "none",
|
|
55
|
+
unsupportedBecause: "a host step has no clone"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
function repoRuntimeMismatch(executionMode, mode) {
|
|
59
|
+
const support = REPO_RUNTIME_SUPPORT[executionMode];
|
|
60
|
+
return support.modes.includes(mode) ? null : support.unsupportedBecause;
|
|
61
|
+
}
|
|
62
|
+
function resolveRepoConfig(executionMode, input) {
|
|
63
|
+
const mode = input?.mode ?? REPO_RUNTIME_SUPPORT[executionMode].default;
|
|
64
|
+
if (mode !== "readWrite")
|
|
65
|
+
return { mode };
|
|
66
|
+
const readWrite = input?.mode === "readWrite" ? input : undefined;
|
|
67
|
+
return {
|
|
68
|
+
mode,
|
|
69
|
+
message: readWrite?.message ?? null,
|
|
70
|
+
onPushFailure: readWrite?.onPushFailure ?? "fail"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { MAX_REPO_COMMIT_MESSAGE_LENGTH, REPO_COMMIT_MESSAGE_TOKEN_ROOTS, findDisallowedCommitMessageTokenRoots, repoCommitMessageSchema, repoConfigInputSchema, repoConfigSchema, REPO_RUNTIME_SUPPORT, repoRuntimeMismatch, resolveRepoConfig };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/contracts/pipeline-document/built-ins.ts
|
|
3
|
+
var BUILT_IN_ERRORS = [
|
|
4
|
+
"Scarn.All",
|
|
5
|
+
"Scarn.StepFailed",
|
|
6
|
+
"Scarn.HealthCheckFailed",
|
|
7
|
+
"Scarn.Timeout",
|
|
8
|
+
"Scarn.HeartbeatTimeout",
|
|
9
|
+
"Scarn.MaxRunsExceeded",
|
|
10
|
+
"Scarn.MaxTurnsExceeded",
|
|
11
|
+
"Scarn.ConditionError",
|
|
12
|
+
"Scarn.ArgsError"
|
|
13
|
+
];
|
|
14
|
+
var WAIT_ERRORS = [
|
|
15
|
+
"Scarn.All",
|
|
16
|
+
"Scarn.MaxRunsExceeded",
|
|
17
|
+
"Scarn.ArgsError"
|
|
18
|
+
];
|
|
19
|
+
function decisionResultSchema(actions) {
|
|
20
|
+
const keys = [...new Set(actions.map((action) => action.key))];
|
|
21
|
+
return {
|
|
22
|
+
title: "DecisionResult",
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
action: keys.length === 0 ? { type: "string" } : { type: "string", enum: keys },
|
|
26
|
+
body: { type: ["string", "null"] }
|
|
27
|
+
},
|
|
28
|
+
required: ["action", "body"],
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
var REPLY_RESULT_SCHEMA = {
|
|
33
|
+
title: "ReplyResult",
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
replied: { type: "boolean" },
|
|
37
|
+
body: { type: ["string", "null"] },
|
|
38
|
+
commentId: { type: ["string", "null"] }
|
|
39
|
+
},
|
|
40
|
+
required: ["replied", "body", "commentId"],
|
|
41
|
+
additionalProperties: false
|
|
42
|
+
};
|
|
43
|
+
var CONVERSATION_RESULT_SCHEMA = {
|
|
44
|
+
title: "ConversationResult",
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
conversationId: { type: "string" },
|
|
48
|
+
summary: { type: "string" }
|
|
49
|
+
},
|
|
50
|
+
required: ["conversationId", "summary"],
|
|
51
|
+
additionalProperties: false
|
|
52
|
+
};
|
|
53
|
+
var REPLY_INPUT_SCHEMA = {
|
|
54
|
+
type: "array",
|
|
55
|
+
items: { type: "string" }
|
|
56
|
+
};
|
|
57
|
+
var ERROR_SCHEMA = {
|
|
58
|
+
title: "Error",
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
name: { type: "string" },
|
|
62
|
+
message: { type: "string" },
|
|
63
|
+
cause: {}
|
|
64
|
+
},
|
|
65
|
+
required: ["name", "message"]
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { BUILT_IN_ERRORS, WAIT_ERRORS, decisionResultSchema, REPLY_RESULT_SCHEMA, CONVERSATION_RESULT_SCHEMA, REPLY_INPUT_SCHEMA, ERROR_SCHEMA };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
exports_external
|
|
4
|
+
} from "./chunk-skzxcba3.js";
|
|
5
|
+
|
|
6
|
+
// src/opencode-mcp.ts
|
|
7
|
+
var nonEmptyStringSchema = exports_external.string().trim().min(1);
|
|
8
|
+
var mcpStringMapSchema = exports_external.record(exports_external.string(), exports_external.string());
|
|
9
|
+
var positiveIntSchema = exports_external.int().gt(0).max(Number.MAX_SAFE_INTEGER);
|
|
10
|
+
var openCodeMcpTimeoutSchema = exports_external.object({
|
|
11
|
+
startup: positiveIntSchema.optional(),
|
|
12
|
+
catalog: positiveIntSchema.optional(),
|
|
13
|
+
execution: positiveIntSchema.optional()
|
|
14
|
+
}).strict();
|
|
15
|
+
var openCodeMcpProtocolSchema = exports_external.enum([
|
|
16
|
+
"legacy",
|
|
17
|
+
"auto",
|
|
18
|
+
"2026-07-28"
|
|
19
|
+
]);
|
|
20
|
+
var sharedServerFields = {
|
|
21
|
+
disabled: exports_external.boolean().optional(),
|
|
22
|
+
codemode: exports_external.boolean().optional(),
|
|
23
|
+
timeout: openCodeMcpTimeoutSchema.optional(),
|
|
24
|
+
protocol: openCodeMcpProtocolSchema.optional()
|
|
25
|
+
};
|
|
26
|
+
var openCodeMcpLocalConfigSchema = exports_external.object({
|
|
27
|
+
type: exports_external.literal("local"),
|
|
28
|
+
command: exports_external.array(nonEmptyStringSchema).min(1),
|
|
29
|
+
cwd: exports_external.string().optional(),
|
|
30
|
+
environment: mcpStringMapSchema.optional(),
|
|
31
|
+
...sharedServerFields
|
|
32
|
+
}).strict();
|
|
33
|
+
var openCodeMcpOAuthConfigSchema = exports_external.object({
|
|
34
|
+
client_id: exports_external.string().optional(),
|
|
35
|
+
client_secret: exports_external.string().optional(),
|
|
36
|
+
scope: exports_external.string().optional(),
|
|
37
|
+
callback_port: positiveIntSchema.optional(),
|
|
38
|
+
redirect_uri: exports_external.string().optional(),
|
|
39
|
+
auth_server_metadata_url: exports_external.string().optional()
|
|
40
|
+
}).strict();
|
|
41
|
+
var openCodeMcpRemoteConfigSchema = exports_external.object({
|
|
42
|
+
type: exports_external.literal("remote"),
|
|
43
|
+
url: exports_external.string(),
|
|
44
|
+
headers: mcpStringMapSchema.optional(),
|
|
45
|
+
oauth: exports_external.union([openCodeMcpOAuthConfigSchema, exports_external.literal(false)]).optional(),
|
|
46
|
+
...sharedServerFields
|
|
47
|
+
}).strict();
|
|
48
|
+
var openCodeMcpRefConfigSchema = exports_external.object({
|
|
49
|
+
type: exports_external.literal("ref"),
|
|
50
|
+
name: nonEmptyStringSchema.optional(),
|
|
51
|
+
...sharedServerFields
|
|
52
|
+
}).strict();
|
|
53
|
+
var openCodeResolvedMcpServerConfigSchema = exports_external.discriminatedUnion("type", [openCodeMcpLocalConfigSchema, openCodeMcpRemoteConfigSchema]);
|
|
54
|
+
var openCodeResolvedMcpServersSchema = exports_external.record(exports_external.string(), openCodeResolvedMcpServerConfigSchema);
|
|
55
|
+
var openCodeMcpServerConfigSchema = exports_external.discriminatedUnion("type", [
|
|
56
|
+
openCodeMcpLocalConfigSchema,
|
|
57
|
+
openCodeMcpRemoteConfigSchema,
|
|
58
|
+
openCodeMcpRefConfigSchema
|
|
59
|
+
]);
|
|
60
|
+
var openCodeMcpServersSchema = exports_external.record(exports_external.string(), openCodeMcpServerConfigSchema);
|
|
61
|
+
var ENV_PLACEHOLDER_PATTERN = /\{env:[A-Za-z_][A-Za-z0-9_]*\}/gu;
|
|
62
|
+
var ENV_PLACEHOLDER_NAME_PATTERN = /\{env:([^}]+)\}/gu;
|
|
63
|
+
var AUTH_SCHEME_PATTERN = /^(?:bearer|basic|token)\s+/iu;
|
|
64
|
+
function isEnvPlaceholderValue(value) {
|
|
65
|
+
if (value.match(ENV_PLACEHOLDER_PATTERN) === null)
|
|
66
|
+
return false;
|
|
67
|
+
return value.trim().replace(AUTH_SCHEME_PATTERN, "").replace(ENV_PLACEHOLDER_PATTERN, "").trim() === "";
|
|
68
|
+
}
|
|
69
|
+
function collectEnvPlaceholderNames(value) {
|
|
70
|
+
const names = new Set;
|
|
71
|
+
const visit = (item) => {
|
|
72
|
+
if (typeof item === "string") {
|
|
73
|
+
for (const match of item.matchAll(ENV_PLACEHOLDER_NAME_PATTERN)) {
|
|
74
|
+
if (match[1] !== undefined)
|
|
75
|
+
names.add(match[1]);
|
|
76
|
+
}
|
|
77
|
+
} else if (typeof item === "object" && item !== null) {
|
|
78
|
+
for (const child of Object.values(item))
|
|
79
|
+
visit(child);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
visit(value);
|
|
83
|
+
return [...names].sort();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { openCodeMcpTimeoutSchema, openCodeMcpProtocolSchema, openCodeMcpLocalConfigSchema, openCodeMcpOAuthConfigSchema, openCodeMcpRemoteConfigSchema, openCodeMcpRefConfigSchema, openCodeResolvedMcpServerConfigSchema, openCodeResolvedMcpServersSchema, openCodeMcpServerConfigSchema, openCodeMcpServersSchema, isEnvPlaceholderValue, collectEnvPlaceholderNames };
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
findArtifactFields2
|
|
6
|
-
} from "./chunk-56e4kp0a.js";
|
|
3
|
+
envVarsSchema
|
|
4
|
+
} from "./chunk-5zsavw98.js";
|
|
7
5
|
import {
|
|
8
|
-
|
|
9
|
-
} from "./chunk-
|
|
6
|
+
devcontainerConfigPathSchema
|
|
7
|
+
} from "./chunk-4ggr8af6.js";
|
|
10
8
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
MANAGED_RUNTIME_IDS,
|
|
10
|
+
isManagedRuntimeId
|
|
11
|
+
} from "./chunk-k4y5qt4y.js";
|
|
13
12
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from "./chunk-
|
|
13
|
+
repoConfigInputSchema,
|
|
14
|
+
repoRuntimeMismatch
|
|
15
|
+
} from "./chunk-cdanncng.js";
|
|
17
16
|
import {
|
|
18
|
-
|
|
19
|
-
} from "./chunk-
|
|
17
|
+
findArtifactMarkers
|
|
18
|
+
} from "./chunk-ngy1fdcx.js";
|
|
20
19
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
EMBEDDABLE_ARTIFACT_EXTENSIONS,
|
|
21
|
+
artifactPlatforms,
|
|
22
|
+
findArtifactFields
|
|
23
|
+
} from "./chunk-y2pv8d6a.js";
|
|
24
24
|
|
|
25
25
|
// src/definitions/validation/validate-artifacts.ts
|
|
26
26
|
function checkArtifactFields(steps) {
|
|
27
27
|
const issues = [];
|
|
28
28
|
for (const step of steps) {
|
|
29
|
-
for (const field of
|
|
29
|
+
for (const field of findArtifactFields(step.resultSchemaJson ?? null)) {
|
|
30
30
|
if (!field.inArray)
|
|
31
31
|
continue;
|
|
32
32
|
issues.push({
|
|
@@ -40,7 +40,7 @@ function checkArtifactFields(steps) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// src/definitions/validation/validation-issue.ts
|
|
43
|
-
function
|
|
43
|
+
function listPaths(paths, limit = 24) {
|
|
44
44
|
if (paths.length === 0)
|
|
45
45
|
return "";
|
|
46
46
|
if (paths.length <= limit)
|
|
@@ -53,7 +53,7 @@ var isPlaceholder = (key) => /^<[^<>]*>$/.test(key);
|
|
|
53
53
|
function stepMarkers(step) {
|
|
54
54
|
if (!step.prompt)
|
|
55
55
|
return [];
|
|
56
|
-
return
|
|
56
|
+
return findArtifactMarkers(step.prompt).flatMap((marker) => marker.ref.type === "signal" && !isPlaceholder(marker.ref.stepKey) && !isPlaceholder(marker.ref.signalKey) ? [
|
|
57
57
|
{
|
|
58
58
|
kind: marker.kind,
|
|
59
59
|
stepKey: marker.ref.stepKey,
|
|
@@ -64,8 +64,8 @@ function stepMarkers(step) {
|
|
|
64
64
|
var markerLabel = (marker) => `${marker.kind === "embed" ? "Artifact.embed" : "Artifact.link"}(` + `"signal/${marker.stepKey}/${marker.resultPath}")`;
|
|
65
65
|
function checkMarkerTargets(steps, stepsByKey) {
|
|
66
66
|
const issues = [];
|
|
67
|
-
const embeddable = new Set(
|
|
68
|
-
...
|
|
67
|
+
const embeddable = new Set(artifactPlatforms.flatMap((platform) => [
|
|
68
|
+
...EMBEDDABLE_ARTIFACT_EXTENSIONS[platform]
|
|
69
69
|
]));
|
|
70
70
|
for (const step of steps) {
|
|
71
71
|
for (const marker of stepMarkers(step)) {
|
|
@@ -76,14 +76,14 @@ function checkMarkerTargets(steps, stepsByKey) {
|
|
|
76
76
|
for (const target of targets) {
|
|
77
77
|
if (!target.resultSchemaJson)
|
|
78
78
|
continue;
|
|
79
|
-
const fields =
|
|
79
|
+
const fields = findArtifactFields(target.resultSchemaJson);
|
|
80
80
|
const field = fields.find((candidate) => candidate.path === marker.resultPath);
|
|
81
81
|
if (!field) {
|
|
82
82
|
const declared = fields.map((candidate) => candidate.path);
|
|
83
83
|
issues.push({
|
|
84
84
|
check: "artifact-marker",
|
|
85
85
|
severity: "error",
|
|
86
|
-
message: `${where}, but step "${target.key}" has no artifact field at ` + `"${marker.resultPath}". Artifact fields on "${target.key}": ` + `${declared.length > 0 ?
|
|
86
|
+
message: `${where}, but step "${target.key}" has no artifact field at ` + `"${marker.resultPath}". Artifact fields on "${target.key}": ` + `${declared.length > 0 ? listPaths(declared) : "(none)"}.`
|
|
87
87
|
});
|
|
88
88
|
continue;
|
|
89
89
|
}
|
|
@@ -116,7 +116,7 @@ function checkEnv(steps) {
|
|
|
116
116
|
continue;
|
|
117
117
|
issues.push(...checkEnvMcpOwners(step));
|
|
118
118
|
issues.push(...checkEnvApplies(step));
|
|
119
|
-
const result =
|
|
119
|
+
const result = envVarsSchema.safeParse(step.envJson);
|
|
120
120
|
if (result.success)
|
|
121
121
|
continue;
|
|
122
122
|
for (const issue of result.error.issues) {
|
|
@@ -145,7 +145,7 @@ function checkEnvMcpOwners(step) {
|
|
|
145
145
|
issues.push({
|
|
146
146
|
check: "env-var-mcp",
|
|
147
147
|
severity: "error",
|
|
148
|
-
message: `Step "${step.key}" env var #${String(index + 1)} ("${entry.name}") ` + `belongs to MCP server "${entry.mcp}", but the step declares no MCP ` + `server with that key. Declared servers: ` + `${serverKeys.length > 0 ?
|
|
148
|
+
message: `Step "${step.key}" env var #${String(index + 1)} ("${entry.name}") ` + `belongs to MCP server "${entry.mcp}", but the step declares no MCP ` + `server with that key. Declared servers: ` + `${serverKeys.length > 0 ? listPaths(serverKeys) : "(none)"}.`
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
return issues;
|
|
@@ -182,7 +182,7 @@ function checkRepo(steps) {
|
|
|
182
182
|
if (!step.repo)
|
|
183
183
|
continue;
|
|
184
184
|
const where = `Step "${step.key}" repo`;
|
|
185
|
-
const parsed =
|
|
185
|
+
const parsed = repoConfigInputSchema.safeParse(step.repo);
|
|
186
186
|
if (!parsed.success) {
|
|
187
187
|
for (const issue of parsed.error.issues) {
|
|
188
188
|
const field = issue.path.map(String).join(".");
|
|
@@ -195,7 +195,7 @@ function checkRepo(steps) {
|
|
|
195
195
|
continue;
|
|
196
196
|
}
|
|
197
197
|
const executionMode = step.executionMode ?? "workspace";
|
|
198
|
-
const mismatch =
|
|
198
|
+
const mismatch = repoRuntimeMismatch(executionMode, parsed.data.mode);
|
|
199
199
|
if (mismatch === null)
|
|
200
200
|
continue;
|
|
201
201
|
issues.push({
|
|
@@ -229,7 +229,7 @@ function checkRuntime(steps) {
|
|
|
229
229
|
message: `${where}: a devcontainer config needs a workspace, but the step runs on the host (executionMode "no_workspace"). Use Runtime.devcontainer({ config }) or drop the config.`
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
|
-
const result =
|
|
232
|
+
const result = devcontainerConfigPathSchema.safeParse(step.devcontainerConfigPath);
|
|
233
233
|
if (result.success)
|
|
234
234
|
continue;
|
|
235
235
|
for (const issue of result.error.issues) {
|
|
@@ -247,8 +247,8 @@ function checkManagedRuntime(step) {
|
|
|
247
247
|
return [];
|
|
248
248
|
const where = `Step "${step.key}" managedRuntime "${step.managedRuntime}"`;
|
|
249
249
|
const problems = [];
|
|
250
|
-
if (!
|
|
251
|
-
problems.push(`unknown managed runtime; expected one of ${
|
|
250
|
+
if (!isManagedRuntimeId(step.managedRuntime)) {
|
|
251
|
+
problems.push(`unknown managed runtime; expected one of ${MANAGED_RUNTIME_IDS.join(", ")}`);
|
|
252
252
|
}
|
|
253
253
|
if (step.kind !== "code") {
|
|
254
254
|
problems.push("managed runtimes are only supported for code steps. Use Runtime.devcontainer() or Runtime.host() for defineStep");
|
|
@@ -286,7 +286,7 @@ function checkHealthChecks(steps) {
|
|
|
286
286
|
issues.push({
|
|
287
287
|
check: "health-check-mcp-server",
|
|
288
288
|
severity: "error",
|
|
289
|
-
message: `${where} names MCP server "${check.mcp}", but the step declares no ` + `such server in mcps. Declared servers: ${mcpServerKeys.length > 0 ?
|
|
289
|
+
message: `${where} names MCP server "${check.mcp}", but the step declares no ` + `such server in mcps. Declared servers: ${mcpServerKeys.length > 0 ? listPaths([...mcpServerKeys].sort()) : "(none)"}.`
|
|
290
290
|
});
|
|
291
291
|
}
|
|
292
292
|
const prefix = `${check.mcp}_`;
|
|
@@ -301,7 +301,7 @@ function checkHealthChecks(steps) {
|
|
|
301
301
|
}
|
|
302
302
|
return issues;
|
|
303
303
|
}
|
|
304
|
-
function
|
|
304
|
+
function validateDefinitionSpecs(steps) {
|
|
305
305
|
const stepsByKey = new Map;
|
|
306
306
|
for (const step of steps) {
|
|
307
307
|
const existing = stepsByKey.get(step.key);
|
|
@@ -319,12 +319,12 @@ function validateDefinitionSpecs2(steps) {
|
|
|
319
319
|
...checkRepo(steps)
|
|
320
320
|
];
|
|
321
321
|
}
|
|
322
|
-
function
|
|
323
|
-
const issues =
|
|
322
|
+
function assertValidDefinitionSpecs(steps) {
|
|
323
|
+
const issues = validateDefinitionSpecs(steps).filter((issue) => issue.severity === "error");
|
|
324
324
|
if (issues.length === 0)
|
|
325
325
|
return;
|
|
326
326
|
const header = issues.length === 1 ? "Definition validation failed:" : `Definition validation failed with ${String(issues.length)} problems:`;
|
|
327
327
|
throw new Error([header, ...issues.map((issue) => ` \u2022 ${issue.message}`)].join(`
|
|
328
328
|
`));
|
|
329
329
|
}
|
|
330
|
-
export {
|
|
330
|
+
export { listPaths, validateDefinitionSpecs, assertValidDefinitionSpecs };
|