@oxygen-agent/cli 1.64.5 → 1.99.1
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/README.md +1 -1
- package/dist/browser-login.js +1 -1
- package/dist/credentials.d.ts +13 -5
- package/dist/credentials.js +114 -19
- package/dist/http-client.d.ts +5 -1
- package/dist/http-client.js +23 -2
- package/dist/index.js +1417 -306
- package/dist/skills.d.ts +8 -2
- package/dist/skills.js +67 -17
- package/dist/update.js +2 -5
- package/dist/windows-shim.d.ts +7 -0
- package/dist/windows-shim.js +21 -0
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/file-import.js +156 -6
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +115 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +1 -1
- package/node_modules/@oxygen/workflows/dist/index.d.ts +91 -0
- package/node_modules/@oxygen/workflows/dist/index.js +232 -1
- package/package.json +1 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export declare const WORKFLOW_MANIFEST_VERSION = 1;
|
|
2
2
|
export declare const WORKFLOW_COMPILER_VERSION = "oxygen-workflows-v1";
|
|
3
3
|
export declare const DURABLE_RECIPE_COMPILER_VERSION = "oxygen-recipes-v2";
|
|
4
|
+
export declare const BLUEPRINT_VERSION = 1;
|
|
5
|
+
export declare const BLUEPRINT_COMPILER_VERSION = "oxygen-blueprints-v1";
|
|
4
6
|
export declare const MAX_RECIPE_BUNDLE_BYTES = 2000000;
|
|
7
|
+
export declare const MAX_BLUEPRINT_BYTES = 4000000;
|
|
5
8
|
export declare const DEFAULT_WORKFLOW_CRON_TIMEZONE = "UTC";
|
|
6
9
|
export type WorkflowMode = "dry_run" | "live" | "smoke_test";
|
|
7
10
|
export type WorkflowTriggerType = "api" | "webhook" | "cron" | "event";
|
|
@@ -100,6 +103,72 @@ export type RecipeManifest = {
|
|
|
100
103
|
created_at: string;
|
|
101
104
|
};
|
|
102
105
|
export type AnyWorkflowManifest = WorkflowManifest | RecipeManifest;
|
|
106
|
+
export type BlueprintColumnInput = {
|
|
107
|
+
key?: string;
|
|
108
|
+
label: string;
|
|
109
|
+
dataType?: string;
|
|
110
|
+
kind?: string;
|
|
111
|
+
semanticType?: string | null;
|
|
112
|
+
definition?: Record<string, unknown>;
|
|
113
|
+
};
|
|
114
|
+
export type BlueprintTable = {
|
|
115
|
+
ref: string;
|
|
116
|
+
name: string;
|
|
117
|
+
description?: string;
|
|
118
|
+
columns: BlueprintColumnInput[];
|
|
119
|
+
metadata?: Record<string, unknown>;
|
|
120
|
+
};
|
|
121
|
+
export type BlueprintColumnGraft = {
|
|
122
|
+
table_ref: string;
|
|
123
|
+
column: BlueprintColumnInput;
|
|
124
|
+
};
|
|
125
|
+
export type BlueprintPromptKind = "ai_column_system" | "scoring_rubric" | "other";
|
|
126
|
+
export type BlueprintPromptTemplate = {
|
|
127
|
+
slug: string;
|
|
128
|
+
name: string;
|
|
129
|
+
description?: string | null;
|
|
130
|
+
kind: BlueprintPromptKind;
|
|
131
|
+
body: string;
|
|
132
|
+
};
|
|
133
|
+
export type BlueprintIntegrationRequirement = {
|
|
134
|
+
kind: string;
|
|
135
|
+
purpose?: string;
|
|
136
|
+
required?: boolean;
|
|
137
|
+
};
|
|
138
|
+
export type BlueprintByokRequirement = {
|
|
139
|
+
kind: "openai" | "anthropic" | "google" | "openrouter" | string;
|
|
140
|
+
required?: boolean;
|
|
141
|
+
};
|
|
142
|
+
export type BlueprintRequires = {
|
|
143
|
+
integrations?: BlueprintIntegrationRequirement[];
|
|
144
|
+
context_keys?: string[];
|
|
145
|
+
byok?: BlueprintByokRequirement[];
|
|
146
|
+
};
|
|
147
|
+
export type BlueprintWorkflow = {
|
|
148
|
+
manifest: AnyWorkflowManifest;
|
|
149
|
+
table_refs?: Record<string, string>;
|
|
150
|
+
prompt_template_slugs?: string[];
|
|
151
|
+
};
|
|
152
|
+
export type Blueprint = {
|
|
153
|
+
blueprint_version: typeof BLUEPRINT_VERSION;
|
|
154
|
+
id: string;
|
|
155
|
+
name: string;
|
|
156
|
+
summary: string;
|
|
157
|
+
tags: string[];
|
|
158
|
+
audience?: string[];
|
|
159
|
+
requires: BlueprintRequires;
|
|
160
|
+
input_schema?: JsonSchema;
|
|
161
|
+
tables: BlueprintTable[];
|
|
162
|
+
column_grafts?: BlueprintColumnGraft[];
|
|
163
|
+
prompt_templates: BlueprintPromptTemplate[];
|
|
164
|
+
workflows: BlueprintWorkflow[];
|
|
165
|
+
exported_at: string;
|
|
166
|
+
exported_from?: {
|
|
167
|
+
oxygen_version?: string;
|
|
168
|
+
};
|
|
169
|
+
source_hash: string;
|
|
170
|
+
compiler_version: typeof BLUEPRINT_COMPILER_VERSION;
|
|
171
|
+
};
|
|
103
172
|
export type WorkflowApplyInput = {
|
|
104
173
|
manifest: WorkflowManifest;
|
|
105
174
|
};
|
|
@@ -229,6 +298,28 @@ export declare function lintRecipeManifest(// skipcq: JS-R1005
|
|
|
229
298
|
value: unknown, options?: WorkflowManifestValidationOptions): WorkflowLintResult;
|
|
230
299
|
export declare function assertRecipeManifest(value: unknown, options?: WorkflowManifestValidationOptions): asserts value is RecipeManifest;
|
|
231
300
|
export declare function assertWorkflowManifest(value: unknown, options?: WorkflowManifestValidationOptions): asserts value is WorkflowManifest;
|
|
301
|
+
export declare function isBlueprint(value: unknown): value is Blueprint;
|
|
302
|
+
export declare function lintBlueprint(// skipcq: JS-R1005
|
|
303
|
+
value: unknown, options?: WorkflowManifestValidationOptions): WorkflowLintResult;
|
|
304
|
+
export declare function assertBlueprint(value: unknown, options?: WorkflowManifestValidationOptions): asserts value is Blueprint;
|
|
305
|
+
export declare function buildBlueprint(input: {
|
|
306
|
+
id: string;
|
|
307
|
+
name: string;
|
|
308
|
+
summary?: string;
|
|
309
|
+
tags?: string[];
|
|
310
|
+
audience?: string[];
|
|
311
|
+
requires?: BlueprintRequires;
|
|
312
|
+
inputSchema?: JsonSchema;
|
|
313
|
+
tables: BlueprintTable[];
|
|
314
|
+
columnGrafts?: BlueprintColumnGraft[];
|
|
315
|
+
promptTemplates?: BlueprintPromptTemplate[];
|
|
316
|
+
workflows: BlueprintWorkflow[];
|
|
317
|
+
exportedFrom?: {
|
|
318
|
+
oxygen_version?: string;
|
|
319
|
+
};
|
|
320
|
+
exportedAt?: Date;
|
|
321
|
+
sourceHash?: string;
|
|
322
|
+
}): Blueprint;
|
|
232
323
|
export declare function validateJsonSchemaValue(value: unknown, schema: JsonSchema | undefined, path?: string): JsonSchemaValidationIssue[];
|
|
233
324
|
export declare function assertRecipeBundleSafe(bundle: string): void;
|
|
234
325
|
export declare function lintRecipeBundleSafety(bundle: string, path?: string): WorkflowLintIssue[];
|
|
@@ -3,7 +3,10 @@ import * as vm from "node:vm"; // skipcq: JS-C1003
|
|
|
3
3
|
export const WORKFLOW_MANIFEST_VERSION = 1;
|
|
4
4
|
export const WORKFLOW_COMPILER_VERSION = "oxygen-workflows-v1";
|
|
5
5
|
export const DURABLE_RECIPE_COMPILER_VERSION = "oxygen-recipes-v2";
|
|
6
|
+
export const BLUEPRINT_VERSION = 1;
|
|
7
|
+
export const BLUEPRINT_COMPILER_VERSION = "oxygen-blueprints-v1";
|
|
6
8
|
export const MAX_RECIPE_BUNDLE_BYTES = 2_000_000;
|
|
9
|
+
export const MAX_BLUEPRINT_BYTES = 4_000_000;
|
|
7
10
|
export const DEFAULT_WORKFLOW_CRON_TIMEZONE = "UTC";
|
|
8
11
|
// Compatibility and determinism lint only. The Vercel sandbox process,
|
|
9
12
|
// denied network policy, and runtime global guards are the security boundary.
|
|
@@ -380,6 +383,234 @@ export function assertWorkflowManifest(value, options = {}) {
|
|
|
380
383
|
const first = result.issues[0];
|
|
381
384
|
throw new Error(first ? `${first.code}: ${first.message}` : "Invalid workflow manifest.");
|
|
382
385
|
}
|
|
386
|
+
export function isBlueprint(value) {
|
|
387
|
+
return isRecord(value)
|
|
388
|
+
&& value.blueprint_version === BLUEPRINT_VERSION
|
|
389
|
+
&& value.compiler_version === BLUEPRINT_COMPILER_VERSION;
|
|
390
|
+
}
|
|
391
|
+
const BLUEPRINT_REF_PATTERN = /^[a-z][a-z0-9_-]{0,79}$/;
|
|
392
|
+
const BLUEPRINT_PROMPT_SLUG_PATTERN = /^[a-z][a-z0-9_-]{0,119}$/;
|
|
393
|
+
export function lintBlueprint(// skipcq: JS-R1005
|
|
394
|
+
value, options = {}) {
|
|
395
|
+
const issues = [];
|
|
396
|
+
const add = (path, code, message) => issues.push({ path, code, message });
|
|
397
|
+
if (!isRecord(value)) {
|
|
398
|
+
add("$", "invalid_blueprint", "Blueprint must be an object.");
|
|
399
|
+
return { ok: false, issues };
|
|
400
|
+
}
|
|
401
|
+
if (value.blueprint_version !== BLUEPRINT_VERSION) {
|
|
402
|
+
add("$.blueprint_version", "invalid_blueprint_version", "Blueprint version must be 1.");
|
|
403
|
+
}
|
|
404
|
+
if (value.compiler_version !== BLUEPRINT_COMPILER_VERSION) {
|
|
405
|
+
add("$.compiler_version", "invalid_compiler_version", `Blueprint compiler_version must be '${BLUEPRINT_COMPILER_VERSION}'.`);
|
|
406
|
+
}
|
|
407
|
+
if (!isNonEmptyString(value.id))
|
|
408
|
+
add("$.id", "invalid_blueprint_id", "Blueprint id is required.");
|
|
409
|
+
if (!isNonEmptyString(value.name))
|
|
410
|
+
add("$.name", "invalid_blueprint_name", "Blueprint name is required.");
|
|
411
|
+
if (typeof value.summary !== "string")
|
|
412
|
+
add("$.summary", "invalid_summary", "Blueprint summary must be a string.");
|
|
413
|
+
if (!Array.isArray(value.tags)) {
|
|
414
|
+
add("$.tags", "invalid_tags", "Blueprint tags must be an array of strings.");
|
|
415
|
+
}
|
|
416
|
+
if (!isNonEmptyString(value.exported_at)) {
|
|
417
|
+
add("$.exported_at", "invalid_exported_at", "Blueprint exported_at must be an ISO timestamp.");
|
|
418
|
+
}
|
|
419
|
+
if (!isNonEmptyString(value.source_hash)) {
|
|
420
|
+
add("$.source_hash", "missing_source_hash", "Blueprint source_hash is required.");
|
|
421
|
+
}
|
|
422
|
+
const tableRefs = new Set();
|
|
423
|
+
if (!Array.isArray(value.tables)) {
|
|
424
|
+
add("$.tables", "invalid_tables", "Blueprint tables must be an array.");
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
value.tables.forEach((table, index) => {
|
|
428
|
+
const path = `$.tables.${index}`;
|
|
429
|
+
if (!isRecord(table)) {
|
|
430
|
+
add(path, "invalid_table", "Blueprint table must be an object.");
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
if (!isNonEmptyString(table.ref) || !BLUEPRINT_REF_PATTERN.test(table.ref)) {
|
|
434
|
+
add(`${path}.ref`, "invalid_table_ref", "Blueprint table ref must be lowercase kebab/snake_case (a-z0-9_-).");
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
if (tableRefs.has(table.ref)) {
|
|
438
|
+
add(`${path}.ref`, "duplicate_table_ref", `Blueprint table ref '${table.ref}' is duplicated.`);
|
|
439
|
+
}
|
|
440
|
+
tableRefs.add(table.ref);
|
|
441
|
+
}
|
|
442
|
+
if (!isNonEmptyString(table.name))
|
|
443
|
+
add(`${path}.name`, "invalid_table_name", "Blueprint table name is required.");
|
|
444
|
+
if (!Array.isArray(table.columns) || table.columns.length === 0) {
|
|
445
|
+
add(`${path}.columns`, "invalid_table_columns", "Blueprint table must declare at least one column.");
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
table.columns.forEach((column, columnIndex) => {
|
|
449
|
+
const columnPath = `${path}.columns.${columnIndex}`;
|
|
450
|
+
if (!isRecord(column)) {
|
|
451
|
+
add(columnPath, "invalid_column", "Blueprint column must be an object.");
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (!isNonEmptyString(column.label)) {
|
|
455
|
+
add(`${columnPath}.label`, "invalid_column_label", "Blueprint column label is required.");
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
if (value.column_grafts !== undefined) {
|
|
462
|
+
if (!Array.isArray(value.column_grafts)) {
|
|
463
|
+
add("$.column_grafts", "invalid_column_grafts", "Blueprint column_grafts must be an array.");
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
value.column_grafts.forEach((graft, index) => {
|
|
467
|
+
const path = `$.column_grafts.${index}`;
|
|
468
|
+
if (!isRecord(graft)) {
|
|
469
|
+
add(path, "invalid_column_graft", "Column graft must be an object.");
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
if (!isNonEmptyString(graft.table_ref) || !tableRefs.has(graft.table_ref)) {
|
|
473
|
+
add(`${path}.table_ref`, "invalid_graft_ref", "Column graft table_ref must match a declared blueprint table ref.");
|
|
474
|
+
}
|
|
475
|
+
if (!isRecord(graft.column) || !isNonEmptyString(graft.column.label)) {
|
|
476
|
+
add(`${path}.column`, "invalid_graft_column", "Column graft column must be an object with a label.");
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const promptSlugs = new Set();
|
|
482
|
+
if (!Array.isArray(value.prompt_templates)) {
|
|
483
|
+
add("$.prompt_templates", "invalid_prompt_templates", "Blueprint prompt_templates must be an array.");
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
value.prompt_templates.forEach((prompt, index) => {
|
|
487
|
+
const path = `$.prompt_templates.${index}`;
|
|
488
|
+
if (!isRecord(prompt)) {
|
|
489
|
+
add(path, "invalid_prompt", "Blueprint prompt must be an object.");
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (!isNonEmptyString(prompt.slug) || !BLUEPRINT_PROMPT_SLUG_PATTERN.test(prompt.slug)) {
|
|
493
|
+
add(`${path}.slug`, "invalid_prompt_slug", "Prompt slug must be lowercase kebab/snake_case (a-z0-9_-).");
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
if (promptSlugs.has(prompt.slug)) {
|
|
497
|
+
add(`${path}.slug`, "duplicate_prompt_slug", `Prompt slug '${prompt.slug}' is duplicated.`);
|
|
498
|
+
}
|
|
499
|
+
promptSlugs.add(prompt.slug);
|
|
500
|
+
}
|
|
501
|
+
if (!isNonEmptyString(prompt.name))
|
|
502
|
+
add(`${path}.name`, "invalid_prompt_name", "Prompt name is required.");
|
|
503
|
+
if (!isNonEmptyString(prompt.body))
|
|
504
|
+
add(`${path}.body`, "invalid_prompt_body", "Prompt body is required.");
|
|
505
|
+
if (prompt.kind !== "ai_column_system" && prompt.kind !== "scoring_rubric" && prompt.kind !== "other") {
|
|
506
|
+
add(`${path}.kind`, "invalid_prompt_kind", "Prompt kind must be ai_column_system, scoring_rubric, or other.");
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
if (!Array.isArray(value.workflows)) {
|
|
511
|
+
add("$.workflows", "invalid_workflows", "Blueprint workflows must be an array.");
|
|
512
|
+
}
|
|
513
|
+
else if (value.workflows.length === 0) {
|
|
514
|
+
add("$.workflows", "missing_workflows", "Blueprint must include at least one workflow.");
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
value.workflows.forEach((entry, index) => {
|
|
518
|
+
const path = `$.workflows.${index}`;
|
|
519
|
+
if (!isRecord(entry)) {
|
|
520
|
+
add(path, "invalid_workflow_entry", "Workflow entry must be an object.");
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
const manifest = entry.manifest;
|
|
524
|
+
const manifestResult = lintWorkflowManifest(manifest, options);
|
|
525
|
+
if (!manifestResult.ok) {
|
|
526
|
+
manifestResult.issues.forEach((issue) => {
|
|
527
|
+
add(`${path}.manifest${issue.path.replace(/^\$/, "")}`, issue.code, issue.message);
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
if (entry.table_refs !== undefined && !isRecord(entry.table_refs)) {
|
|
531
|
+
add(`${path}.table_refs`, "invalid_workflow_table_refs", "Workflow table_refs must be an object map.");
|
|
532
|
+
}
|
|
533
|
+
else if (isRecord(entry.table_refs)) {
|
|
534
|
+
for (const refName of Object.keys(entry.table_refs)) {
|
|
535
|
+
if (!tableRefs.has(refName)) {
|
|
536
|
+
add(`${path}.table_refs.${refName}`, "unknown_workflow_table_ref", `Workflow references table ref '${refName}' which is not declared on this blueprint.`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (entry.prompt_template_slugs !== undefined) {
|
|
541
|
+
if (!Array.isArray(entry.prompt_template_slugs)) {
|
|
542
|
+
add(`${path}.prompt_template_slugs`, "invalid_prompt_slug_list", "Workflow prompt_template_slugs must be an array of strings.");
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
entry.prompt_template_slugs.forEach((slug, slugIndex) => {
|
|
546
|
+
if (!isNonEmptyString(slug)) {
|
|
547
|
+
add(`${path}.prompt_template_slugs.${slugIndex}`, "invalid_prompt_slug", "Workflow prompt slug references must be non-empty strings.");
|
|
548
|
+
}
|
|
549
|
+
else if (!promptSlugs.has(slug)) {
|
|
550
|
+
add(`${path}.prompt_template_slugs.${slugIndex}`, "unknown_prompt_slug", `Workflow references prompt slug '${slug}' which is not declared on this blueprint.`);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
const requires = value.requires;
|
|
558
|
+
if (!isRecord(requires)) {
|
|
559
|
+
add("$.requires", "invalid_requires", "Blueprint requires must be an object.");
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
if (requires.integrations !== undefined) {
|
|
563
|
+
if (!Array.isArray(requires.integrations)) {
|
|
564
|
+
add("$.requires.integrations", "invalid_requires_integrations", "Blueprint requires.integrations must be an array.");
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
requires.integrations.forEach((entry, index) => {
|
|
568
|
+
const path = `$.requires.integrations.${index}`;
|
|
569
|
+
if (!isRecord(entry)) {
|
|
570
|
+
add(path, "invalid_integration", "Integration requirement must be an object.");
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (!isNonEmptyString(entry.kind)) {
|
|
574
|
+
add(`${path}.kind`, "invalid_integration_kind", "Integration requirement kind is required (e.g. 'instantly', 'apollo').");
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
if (requires.context_keys !== undefined && !Array.isArray(requires.context_keys)) {
|
|
580
|
+
add("$.requires.context_keys", "invalid_context_keys", "Blueprint requires.context_keys must be an array of strings.");
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return { ok: issues.length === 0, issues };
|
|
584
|
+
}
|
|
585
|
+
export function assertBlueprint(value, options = {}) {
|
|
586
|
+
const result = lintBlueprint(value, options);
|
|
587
|
+
if (result.ok)
|
|
588
|
+
return;
|
|
589
|
+
const first = result.issues[0];
|
|
590
|
+
throw new Error(first ? `${first.code}: ${first.message}` : "Invalid blueprint.");
|
|
591
|
+
}
|
|
592
|
+
export function buildBlueprint(input) {
|
|
593
|
+
const draft = {
|
|
594
|
+
blueprint_version: BLUEPRINT_VERSION,
|
|
595
|
+
id: input.id,
|
|
596
|
+
name: input.name,
|
|
597
|
+
summary: input.summary ?? "",
|
|
598
|
+
tags: Array.isArray(input.tags) ? Array.from(new Set(input.tags.filter(Boolean))) : [],
|
|
599
|
+
...(input.audience ? { audience: input.audience } : {}),
|
|
600
|
+
requires: input.requires ?? {},
|
|
601
|
+
...(input.inputSchema ? { input_schema: input.inputSchema } : {}),
|
|
602
|
+
tables: input.tables,
|
|
603
|
+
...(input.columnGrafts && input.columnGrafts.length > 0 ? { column_grafts: input.columnGrafts } : {}),
|
|
604
|
+
prompt_templates: input.promptTemplates ?? [],
|
|
605
|
+
workflows: input.workflows,
|
|
606
|
+
exported_at: (input.exportedAt ?? new Date()).toISOString(),
|
|
607
|
+
...(input.exportedFrom ? { exported_from: input.exportedFrom } : {}),
|
|
608
|
+
compiler_version: BLUEPRINT_COMPILER_VERSION,
|
|
609
|
+
};
|
|
610
|
+
const sourceHash = input.sourceHash
|
|
611
|
+
?? hashWorkflowSource(JSON.stringify(draft, workflowJsonReplacer));
|
|
612
|
+
return { ...draft, source_hash: sourceHash };
|
|
613
|
+
}
|
|
383
614
|
export function validateJsonSchemaValue(value, schema, path = "$") {
|
|
384
615
|
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
385
616
|
return [];
|
|
@@ -808,7 +1039,7 @@ function validateRecipeBundleSafety(source, path, add) {
|
|
|
808
1039
|
}
|
|
809
1040
|
}
|
|
810
1041
|
function isWorkflowToolRejected(toolId) {
|
|
811
|
-
return toolId === "run_javascript" || toolId === "custom_http"
|
|
1042
|
+
return toolId === "run_javascript" || toolId === "custom_http";
|
|
812
1043
|
}
|
|
813
1044
|
const CRON_FIELD_LIMITS = [
|
|
814
1045
|
{ name: "minute", min: 0, max: 59 },
|