@shipfox/api-definitions 10.2.0 → 12.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/.turbo/turbo-build.log +13 -12
- package/CHANGELOG.md +91 -0
- package/dist/core/entities/index.d.ts +1 -0
- package/dist/core/entities/index.d.ts.map +1 -1
- package/dist/core/entities/index.js +1 -0
- package/dist/core/entities/index.js.map +1 -1
- package/dist/core/entities/sync-state.d.ts +4 -0
- package/dist/core/entities/sync-state.d.ts.map +1 -1
- package/dist/core/entities/sync-state.js +10 -0
- package/dist/core/entities/sync-state.js.map +1 -1
- package/dist/core/entities/validation-warning.d.ts +6 -0
- package/dist/core/entities/validation-warning.d.ts.map +1 -0
- package/dist/core/entities/validation-warning.js +3 -0
- package/dist/core/entities/validation-warning.js.map +1 -0
- package/dist/core/parse-definition.d.ts +9 -7
- package/dist/core/parse-definition.d.ts.map +1 -1
- package/dist/core/parse-definition.js +14 -2
- package/dist/core/parse-definition.js.map +1 -1
- package/dist/core/sync-definitions.d.ts +2 -0
- package/dist/core/sync-definitions.d.ts.map +1 -1
- package/dist/core/sync-definitions.js +6 -5
- package/dist/core/sync-definitions.js.map +1 -1
- package/dist/core/validate-definition.d.ts +9 -5
- package/dist/core/validate-definition.d.ts.map +1 -1
- package/dist/core/validate-definition.js +23 -2
- package/dist/core/validate-definition.js.map +1 -1
- package/dist/core/workflow-model/index.d.ts +1 -1
- package/dist/core/workflow-model/index.d.ts.map +1 -1
- package/dist/core/workflow-model/index.js.map +1 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.d.ts +3 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.d.ts.map +1 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.js.map +1 -1
- package/dist/core/workflow-model/normalize-if-condition.d.ts +0 -1
- package/dist/core/workflow-model/normalize-if-condition.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-if-condition.js +0 -1
- package/dist/core/workflow-model/normalize-if-condition.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-checkout.d.ts +15 -3
- package/dist/core/workflow-model/normalize-job-checkout.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-job-checkout.js +83 -4
- package/dist/core/workflow-model/normalize-job-checkout.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-listening.js +0 -1
- package/dist/core/workflow-model/normalize-job-listening.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-success.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-job-success.js +0 -1
- package/dist/core/workflow-model/normalize-job-success.js.map +1 -1
- package/dist/core/workflow-model/normalize-jobs.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-jobs.js +310 -45
- package/dist/core/workflow-model/normalize-jobs.js.map +1 -1
- package/dist/core/workflow-model/normalize-step-gate.js +0 -1
- package/dist/core/workflow-model/normalize-step-gate.js.map +1 -1
- package/dist/core/workflow-model/normalize-triggers.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-triggers.js +0 -1
- package/dist/core/workflow-model/normalize-triggers.js.map +1 -1
- package/dist/core/workflow-model/normalize-workflow-document.d.ts +3 -0
- package/dist/core/workflow-model/normalize-workflow-document.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-workflow-document.js +34 -4
- package/dist/core/workflow-model/normalize-workflow-document.js.map +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.d.ts +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.d.ts.map +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.js +27 -57
- package/dist/core/workflow-model/parse-interpolation-field.js.map +1 -1
- package/dist/core/workflow-model/validate-literal-name.d.ts +12 -0
- package/dist/core/workflow-model/validate-literal-name.d.ts.map +1 -0
- package/dist/core/workflow-model/validate-literal-name.js +36 -0
- package/dist/core/workflow-model/validate-literal-name.js.map +1 -0
- package/dist/core/workflow-model/validate-predicate-expression.d.ts +1 -2
- package/dist/core/workflow-model/validate-predicate-expression.d.ts.map +1 -1
- package/dist/core/workflow-model/validate-predicate-expression.js +31 -90
- package/dist/core/workflow-model/validate-predicate-expression.js.map +1 -1
- package/dist/core/workflow-model/validation-issue.d.ts +2 -1
- package/dist/core/workflow-model/validation-issue.d.ts.map +1 -1
- package/dist/core/workflow-model/validation-issue.js +8 -2
- package/dist/core/workflow-model/validation-issue.js.map +1 -1
- package/dist/core/workflow-model/workflow-field-label.d.ts.map +1 -1
- package/dist/core/workflow-model/workflow-field-label.js +16 -2
- package/dist/core/workflow-model/workflow-field-label.js.map +1 -1
- package/dist/db/db.d.ts +38 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/schema/sync-states.d.ts +19 -0
- package/dist/db/schema/sync-states.d.ts.map +1 -1
- package/dist/db/schema/sync-states.js +3 -1
- package/dist/db/schema/sync-states.js.map +1 -1
- package/dist/db/sync-states.d.ts +2 -1
- package/dist/db/sync-states.d.ts.map +1 -1
- package/dist/db/sync-states.js +4 -0
- package/dist/db/sync-states.js.map +1 -1
- package/dist/presentation/dto/definition.d.ts.map +1 -1
- package/dist/presentation/dto/definition.js +2 -1
- package/dist/presentation/dto/definition.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -0
- package/dist/presentation/routes/project-access.d.ts.map +1 -1
- package/dist/presentation/routes/validate-definition.d.ts.map +1 -1
- package/dist/presentation/routes/validate-definition.js +5 -3
- package/dist/presentation/routes/validate-definition.js.map +1 -1
- package/dist/temporal/activities/sync-activities.d.ts +6 -2
- package/dist/temporal/activities/sync-activities.d.ts.map +1 -1
- package/dist/temporal/activities/sync-activities.js +8 -1
- package/dist/temporal/activities/sync-activities.js.map +1 -1
- package/dist/temporal/workflows/definition-sync.js +4 -1
- package/dist/temporal/workflows/definition-sync.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +9029 -3
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0002_lumpy_ben_parker.sql +1 -0
- package/drizzle/meta/0002_snapshot.json +534 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +14 -14
- package/src/core/entities/index.ts +1 -0
- package/src/core/entities/sync-state.ts +23 -0
- package/src/core/entities/validation-warning.ts +5 -0
- package/src/core/parse-definition-warnings.test.ts +33 -0
- package/src/core/parse-definition.test.ts +7 -1
- package/src/core/parse-definition.ts +28 -10
- package/src/core/sync-definitions.test.ts +39 -0
- package/src/core/sync-definitions.ts +14 -4
- package/src/core/validate-definition.test.ts +128 -0
- package/src/core/validate-definition.ts +39 -8
- package/src/core/workflow-model/README.md +2 -2
- package/src/core/workflow-model/index.ts +1 -0
- package/src/core/workflow-model/invalid-workflow-model-error.ts +8 -2
- package/src/core/workflow-model/normalize-if-condition.ts +0 -2
- package/src/core/workflow-model/normalize-job-checkout.ts +105 -8
- package/src/core/workflow-model/normalize-job-listening.ts +0 -1
- package/src/core/workflow-model/normalize-job-success.ts +0 -1
- package/src/core/workflow-model/normalize-jobs.ts +330 -49
- package/src/core/workflow-model/normalize-step-gate.ts +0 -1
- package/src/core/workflow-model/normalize-triggers.ts +0 -1
- package/src/core/workflow-model/normalize-workflow-document.test.ts +759 -185
- package/src/core/workflow-model/normalize-workflow-document.ts +29 -4
- package/src/core/workflow-model/parse-interpolation-field.ts +50 -79
- package/src/core/workflow-model/validate-literal-name.ts +64 -0
- package/src/core/workflow-model/validate-predicate-expression.test.ts +153 -15
- package/src/core/workflow-model/validate-predicate-expression.ts +52 -120
- package/src/core/workflow-model/validation-issue.ts +4 -0
- package/src/core/workflow-model/workflow-field-label.ts +16 -2
- package/src/core/workflow-yaml/README.md +2 -2
- package/src/db/schema/sync-states.ts +4 -1
- package/src/db/sync-states.test.ts +57 -0
- package/src/db/sync-states.ts +6 -0
- package/src/presentation/dto/definition.ts +1 -0
- package/src/presentation/routes/create-definition.test.ts +3 -3
- package/src/presentation/routes/get-definition.test.ts +1 -1
- package/src/presentation/routes/list-definitions.test.ts +2 -1
- package/src/presentation/routes/validate-definition.test.ts +1 -0
- package/src/presentation/routes/validate-definition.ts +7 -1
- package/src/temporal/activities/sync-activities.test.ts +16 -0
- package/src/temporal/activities/sync-activities.ts +18 -3
- package/src/temporal/workflows/definition-sync.ts +1 -1
- package/test/agent-validation-catalog.ts +17 -0
- package/test/fixtures/valid-listening-job.yml +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { buildTypedRootsEnvironment } from '@shipfox/expression';
|
|
1
|
+
import { buildTypedRootsEnvironment, classifyShellCodePosition, hoistPlannedRunCommand, UnsafeRunInterpolationError } from '@shipfox/expression';
|
|
2
2
|
import { canonicalizeLabels, findInvalidLabels, MAX_RUNNER_LABEL_LENGTH, MAX_RUNNER_LABELS, RUNNER_LABEL_PATTERN } from '@shipfox/runner-labels';
|
|
3
3
|
import { normalizeAgentIntegrations } from './normalize-agent-integrations.js';
|
|
4
4
|
import { normalizeEnv } from './normalize-env.js';
|
|
5
5
|
import { normalizeIfCondition } from './normalize-if-condition.js';
|
|
6
|
-
import { normalizeJobCheckout } from './normalize-job-checkout.js';
|
|
6
|
+
import { normalizeCheckout, normalizeJobCheckout } from './normalize-job-checkout.js';
|
|
7
7
|
import { normalizeJobListening } from './normalize-job-listening.js';
|
|
8
8
|
import { normalizeJobSuccess } from './normalize-job-success.js';
|
|
9
9
|
import { normalizeNeeds } from './normalize-needs.js';
|
|
@@ -12,6 +12,7 @@ import { normalizeStepOutputs } from './normalize-step-outputs.js';
|
|
|
12
12
|
import { parseDurationMs } from './parse-duration-ms.js';
|
|
13
13
|
import { parseInterpolationField } from './parse-interpolation-field.js';
|
|
14
14
|
import { stableId } from './stable-id.js';
|
|
15
|
+
import { unescapeLiteralName, validateLiteralName } from './validate-literal-name.js';
|
|
15
16
|
import { issue } from './validation-issue.js';
|
|
16
17
|
export function normalizeJobs(document, jobIdBySourceName, issues, stepSourceLocations, context) {
|
|
17
18
|
const entries = Object.entries(document.jobs);
|
|
@@ -109,6 +110,8 @@ function normalizeJob(params) {
|
|
|
109
110
|
sourceName: params.sourceName,
|
|
110
111
|
jobId: id,
|
|
111
112
|
job: params.job,
|
|
113
|
+
workflowEnvKeys: Object.keys(params.document.env ?? {}),
|
|
114
|
+
jobEnvKeys: Object.keys(params.job.env ?? {}),
|
|
112
115
|
issues: params.issues,
|
|
113
116
|
stepSourceLocations: params.stepSourceLocations,
|
|
114
117
|
fillSite: stepFillSite,
|
|
@@ -125,7 +128,9 @@ function normalizeJob(params) {
|
|
|
125
128
|
issues: params.issues,
|
|
126
129
|
defaultRunnerLabels: params.context.defaultRunnerLabels
|
|
127
130
|
});
|
|
128
|
-
const checkout = normalizeJobCheckout(
|
|
131
|
+
const checkout = normalizeJobCheckout({
|
|
132
|
+
checkout: params.job.checkout
|
|
133
|
+
});
|
|
129
134
|
const jobEnv = normalizeEnv({
|
|
130
135
|
env: params.job.env,
|
|
131
136
|
path: [
|
|
@@ -147,7 +152,6 @@ function normalizeJob(params) {
|
|
|
147
152
|
const condition = normalizeIfCondition({
|
|
148
153
|
field: 'job.if',
|
|
149
154
|
source: params.job.if,
|
|
150
|
-
site: 'job-activation',
|
|
151
155
|
path: [
|
|
152
156
|
'jobs',
|
|
153
157
|
params.sourceName,
|
|
@@ -185,21 +189,37 @@ function normalizeJob(params) {
|
|
|
185
189
|
issues: params.issues,
|
|
186
190
|
allowedJobReferences
|
|
187
191
|
});
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
if (params.job.name !== undefined) {
|
|
193
|
+
validateLiteralName({
|
|
194
|
+
field: 'job.name',
|
|
195
|
+
dynamicField: 'execution_name',
|
|
196
|
+
source: params.job.name,
|
|
197
|
+
path: [
|
|
198
|
+
'jobs',
|
|
199
|
+
params.sourceName,
|
|
200
|
+
'name'
|
|
201
|
+
],
|
|
202
|
+
message: 'Job name must be literal. Move runtime interpolation to execution_name.',
|
|
203
|
+
issues: params.issues
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const name = params.job.name === undefined ? undefined : unescapeLiteralName(params.job.name);
|
|
207
|
+
const executionName = params.job.execution_name === undefined ? undefined : parseInterpolationField({
|
|
208
|
+
field: 'job.execution_name',
|
|
209
|
+
source: params.job.execution_name,
|
|
191
210
|
path: [
|
|
192
211
|
'jobs',
|
|
193
212
|
params.sourceName,
|
|
194
|
-
'
|
|
213
|
+
'execution_name'
|
|
195
214
|
],
|
|
196
215
|
issues: params.issues,
|
|
216
|
+
fillSite: 'execution-creation',
|
|
197
217
|
allowedJobReferences,
|
|
198
218
|
typeOverlay: upstreamJobsTypeOverlay
|
|
199
219
|
}) ?? [
|
|
200
220
|
{
|
|
201
221
|
kind: 'literal',
|
|
202
|
-
value: params.job.
|
|
222
|
+
value: params.job.execution_name
|
|
203
223
|
}
|
|
204
224
|
];
|
|
205
225
|
return {
|
|
@@ -232,6 +252,9 @@ function normalizeJob(params) {
|
|
|
232
252
|
...name === undefined ? {} : {
|
|
233
253
|
name
|
|
234
254
|
},
|
|
255
|
+
...executionName === undefined ? {} : {
|
|
256
|
+
executionName
|
|
257
|
+
},
|
|
235
258
|
...jobEnv,
|
|
236
259
|
dependencies,
|
|
237
260
|
steps
|
|
@@ -367,12 +390,15 @@ function isScalarExpressionType(type) {
|
|
|
367
390
|
}
|
|
368
391
|
function normalizeJobSteps(params) {
|
|
369
392
|
const usedStepIds = new Map();
|
|
370
|
-
return params.job.steps.
|
|
393
|
+
return params.job.steps.flatMap((step, index)=>{
|
|
394
|
+
const normalized = normalizeStep({
|
|
371
395
|
step,
|
|
372
396
|
index,
|
|
373
397
|
sourceName: params.sourceName,
|
|
374
398
|
jobId: params.jobId,
|
|
375
399
|
allSteps: params.job.steps,
|
|
400
|
+
workflowEnvKeys: params.workflowEnvKeys,
|
|
401
|
+
jobEnvKeys: params.jobEnvKeys,
|
|
376
402
|
usedStepIds,
|
|
377
403
|
issues: params.issues,
|
|
378
404
|
stepSourceLocations: params.stepSourceLocations,
|
|
@@ -382,7 +408,11 @@ function normalizeJobSteps(params) {
|
|
|
382
408
|
upstreamJobs: params.upstreamJobs,
|
|
383
409
|
directNeedJobs: params.directNeedJobs,
|
|
384
410
|
context: params.context
|
|
385
|
-
})
|
|
411
|
+
});
|
|
412
|
+
return normalized === undefined ? [] : [
|
|
413
|
+
normalized
|
|
414
|
+
];
|
|
415
|
+
});
|
|
386
416
|
}
|
|
387
417
|
function normalizeStep(params) {
|
|
388
418
|
const stepKey = params.step.key;
|
|
@@ -442,7 +472,6 @@ function normalizeStep(params) {
|
|
|
442
472
|
const condition = normalizeIfCondition({
|
|
443
473
|
field: 'step.if',
|
|
444
474
|
source: params.step.if,
|
|
445
|
-
site: 'step-dispatch',
|
|
446
475
|
path: [
|
|
447
476
|
'jobs',
|
|
448
477
|
params.sourceName,
|
|
@@ -484,6 +513,21 @@ function normalizeStep(params) {
|
|
|
484
513
|
allowedJobReferences: params.allowedJobReferences,
|
|
485
514
|
typeOverlay
|
|
486
515
|
});
|
|
516
|
+
const workingDirectory = params.step.working_directory === undefined ? undefined : parseInterpolationField({
|
|
517
|
+
field: 'step.working_directory',
|
|
518
|
+
source: params.step.working_directory,
|
|
519
|
+
path: [
|
|
520
|
+
'jobs',
|
|
521
|
+
params.sourceName,
|
|
522
|
+
'steps',
|
|
523
|
+
params.index,
|
|
524
|
+
'working_directory'
|
|
525
|
+
],
|
|
526
|
+
issues: params.issues,
|
|
527
|
+
fillSite: params.fillSite,
|
|
528
|
+
allowedJobReferences: params.allowedJobReferences,
|
|
529
|
+
typeOverlay
|
|
530
|
+
});
|
|
487
531
|
const stepBase = {
|
|
488
532
|
id: stepId,
|
|
489
533
|
...stepKey === undefined ? {} : {
|
|
@@ -492,6 +536,9 @@ function normalizeStep(params) {
|
|
|
492
536
|
...params.step.name === undefined ? {} : {
|
|
493
537
|
name: params.step.name
|
|
494
538
|
},
|
|
539
|
+
...params.step.working_directory === undefined ? {} : {
|
|
540
|
+
workingDirectory: params.step.working_directory
|
|
541
|
+
},
|
|
495
542
|
...outputs === undefined ? {} : {
|
|
496
543
|
outputs
|
|
497
544
|
},
|
|
@@ -511,7 +558,10 @@ function normalizeStep(params) {
|
|
|
511
558
|
stepBase,
|
|
512
559
|
sourceName: params.sourceName,
|
|
513
560
|
stepIndex: params.index,
|
|
561
|
+
workflowEnvKeys: params.workflowEnvKeys,
|
|
562
|
+
jobEnvKeys: params.jobEnvKeys,
|
|
514
563
|
name,
|
|
564
|
+
workingDirectory,
|
|
515
565
|
issues: params.issues,
|
|
516
566
|
fillSite: params.fillSite,
|
|
517
567
|
allowedJobReferences: params.allowedJobReferences,
|
|
@@ -525,6 +575,7 @@ function normalizeStep(params) {
|
|
|
525
575
|
sourceName: params.sourceName,
|
|
526
576
|
stepIndex: params.index,
|
|
527
577
|
name,
|
|
578
|
+
workingDirectory,
|
|
528
579
|
issues: params.issues,
|
|
529
580
|
fillSite: params.fillSite,
|
|
530
581
|
allowedJobReferences: params.allowedJobReferences,
|
|
@@ -532,9 +583,51 @@ function normalizeStep(params) {
|
|
|
532
583
|
context: params.context
|
|
533
584
|
});
|
|
534
585
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
586
|
+
if (params.step.checkout !== undefined) {
|
|
587
|
+
return normalizeCheckoutStep({
|
|
588
|
+
step: params.step,
|
|
589
|
+
stepBase,
|
|
590
|
+
name,
|
|
591
|
+
sourceName: params.sourceName,
|
|
592
|
+
stepIndex: params.index,
|
|
593
|
+
issues: params.issues,
|
|
594
|
+
fillSite: params.fillSite,
|
|
595
|
+
allowedJobReferences: params.allowedJobReferences,
|
|
596
|
+
typeOverlay
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
// Keep the model-step union honest if callers bypass the document parser.
|
|
600
|
+
throw new Error(`Workflow step "${stepId}" is neither a run, agent, nor checkout step`);
|
|
601
|
+
}
|
|
602
|
+
function normalizeCheckoutStep(params) {
|
|
603
|
+
const checkout = params.step.checkout;
|
|
604
|
+
if (checkout === undefined) {
|
|
605
|
+
throw new Error('Checkout step normalization requires checkout settings');
|
|
606
|
+
}
|
|
607
|
+
const normalizedCheckout = normalizeCheckout({
|
|
608
|
+
checkout,
|
|
609
|
+
issues: params.issues,
|
|
610
|
+
path: [
|
|
611
|
+
'jobs',
|
|
612
|
+
params.sourceName,
|
|
613
|
+
'steps',
|
|
614
|
+
params.stepIndex,
|
|
615
|
+
'checkout'
|
|
616
|
+
],
|
|
617
|
+
fillSite: params.fillSite,
|
|
618
|
+
allowedJobReferences: params.allowedJobReferences,
|
|
619
|
+
typeOverlay: params.typeOverlay
|
|
620
|
+
});
|
|
621
|
+
return {
|
|
622
|
+
...params.stepBase,
|
|
623
|
+
kind: 'checkout',
|
|
624
|
+
checkout: normalizedCheckout,
|
|
625
|
+
...params.name === undefined ? {} : {
|
|
626
|
+
templates: {
|
|
627
|
+
name: params.name
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
};
|
|
538
631
|
}
|
|
539
632
|
function normalizeRunStep(params) {
|
|
540
633
|
if (params.step.run === undefined) {
|
|
@@ -569,9 +662,25 @@ function normalizeRunStep(params) {
|
|
|
569
662
|
allowedJobReferences: params.allowedJobReferences,
|
|
570
663
|
typeOverlay: params.typeOverlay
|
|
571
664
|
});
|
|
665
|
+
addReevaluatingCommandWarnings({
|
|
666
|
+
command: commandTemplate,
|
|
667
|
+
source: params.step.run,
|
|
668
|
+
workflowEnvKeys: params.workflowEnvKeys,
|
|
669
|
+
jobEnvKeys: params.jobEnvKeys,
|
|
670
|
+
stepEnvKeys: Object.keys(params.step.env ?? {}),
|
|
671
|
+
path: [
|
|
672
|
+
'jobs',
|
|
673
|
+
params.sourceName,
|
|
674
|
+
'steps',
|
|
675
|
+
params.stepIndex,
|
|
676
|
+
'run'
|
|
677
|
+
],
|
|
678
|
+
issues: params.issues
|
|
679
|
+
});
|
|
572
680
|
const templates = optionalRunStepTemplates({
|
|
573
681
|
command: commandTemplate,
|
|
574
682
|
name: params.name,
|
|
683
|
+
workingDirectory: params.workingDirectory,
|
|
575
684
|
env: stepEnv.templates?.env
|
|
576
685
|
});
|
|
577
686
|
return {
|
|
@@ -589,6 +698,90 @@ function normalizeRunStep(params) {
|
|
|
589
698
|
}
|
|
590
699
|
};
|
|
591
700
|
}
|
|
701
|
+
function addReevaluatingCommandWarnings(params) {
|
|
702
|
+
const envKeys = new Set([
|
|
703
|
+
...params.workflowEnvKeys,
|
|
704
|
+
...params.jobEnvKeys,
|
|
705
|
+
...params.stepEnvKeys
|
|
706
|
+
]);
|
|
707
|
+
let hoisted;
|
|
708
|
+
try {
|
|
709
|
+
hoisted = hoistPlannedRunCommand({
|
|
710
|
+
field: {
|
|
711
|
+
segments: params.command ?? [
|
|
712
|
+
{
|
|
713
|
+
kind: 'literal',
|
|
714
|
+
value: params.source
|
|
715
|
+
}
|
|
716
|
+
]
|
|
717
|
+
},
|
|
718
|
+
reservedNames: envKeys
|
|
719
|
+
});
|
|
720
|
+
} catch (error) {
|
|
721
|
+
if (!(error instanceof UnsafeRunInterpolationError)) return;
|
|
722
|
+
for (const occurrence of error.occurrences){
|
|
723
|
+
params.issues.push(issue({
|
|
724
|
+
code: 're-evaluating-command',
|
|
725
|
+
message: unsafeInterpolationWarningMessage(occurrence),
|
|
726
|
+
path: params.path,
|
|
727
|
+
severity: 'warning'
|
|
728
|
+
}));
|
|
729
|
+
}
|
|
730
|
+
if (error.partial === undefined) return;
|
|
731
|
+
hoisted = error.partial;
|
|
732
|
+
}
|
|
733
|
+
try {
|
|
734
|
+
const matches = classifyShellCodePosition({
|
|
735
|
+
command: hoisted.command,
|
|
736
|
+
workflowDataNames: [
|
|
737
|
+
...envKeys,
|
|
738
|
+
...hoisted.bindings.map((binding)=>binding.name)
|
|
739
|
+
]
|
|
740
|
+
}).matches;
|
|
741
|
+
for (const match of matches){
|
|
742
|
+
params.issues.push(issue({
|
|
743
|
+
code: 're-evaluating-command',
|
|
744
|
+
message: reevaluatingCommandWarningMessage(match.construct, match.name),
|
|
745
|
+
path: params.path,
|
|
746
|
+
severity: 'warning'
|
|
747
|
+
}));
|
|
748
|
+
}
|
|
749
|
+
} catch {
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function unsafeInterpolationWarningMessage(error) {
|
|
754
|
+
const regionLabel = {
|
|
755
|
+
single: 'single-quoted shell text',
|
|
756
|
+
double: 'double-quoted shell text',
|
|
757
|
+
'dollar-single': 'ANSI-C shell text',
|
|
758
|
+
'dollar-double': 'dollar-double-quoted shell text',
|
|
759
|
+
'paren-sub': 'command substitution',
|
|
760
|
+
arith: 'shell arithmetic',
|
|
761
|
+
backtick: 'backtick substitution',
|
|
762
|
+
'param-brace': 'shell parameter expansion',
|
|
763
|
+
heredoc: 'a heredoc',
|
|
764
|
+
'line-comment': 'a shell comment',
|
|
765
|
+
escape: 'a shell escape'
|
|
766
|
+
}[error.region];
|
|
767
|
+
return `Value "${error.source}" is inside ${regionLabel} and will be re-executed as code. Hoisting cannot protect it; move the interpolation to a normal quoted argument instead.`;
|
|
768
|
+
}
|
|
769
|
+
function reevaluatingCommandWarningMessage(construct, name) {
|
|
770
|
+
const constructLabel = {
|
|
771
|
+
eval: 'eval',
|
|
772
|
+
'sh-c': 'sh -c',
|
|
773
|
+
'bash-c': 'bash -c',
|
|
774
|
+
source: 'source',
|
|
775
|
+
let: 'let',
|
|
776
|
+
'declare-i': 'declare -i',
|
|
777
|
+
arithmetic: 'shell arithmetic',
|
|
778
|
+
awk: 'awk',
|
|
779
|
+
jq: 'jq',
|
|
780
|
+
sed: 'sed',
|
|
781
|
+
'xargs-sh-c': 'xargs sh -c'
|
|
782
|
+
}[construct];
|
|
783
|
+
return `Value "$${name}" is passed to ${constructLabel} and re-executed as code. Hoisting cannot protect it; pass the value to a fixed program instead.`;
|
|
784
|
+
}
|
|
592
785
|
function normalizeAgentStep(params) {
|
|
593
786
|
if (params.step.prompt === undefined) {
|
|
594
787
|
throw new Error('Agent step normalization requires a prompt');
|
|
@@ -638,12 +831,28 @@ function normalizeAgentStep(params) {
|
|
|
638
831
|
allowedJobReferences: params.allowedJobReferences,
|
|
639
832
|
typeOverlay: params.typeOverlay
|
|
640
833
|
});
|
|
834
|
+
const thinkingTemplate = params.step.thinking === undefined ? undefined : parseInterpolationField({
|
|
835
|
+
field: 'agent.thinking',
|
|
836
|
+
source: params.step.thinking,
|
|
837
|
+
path: [
|
|
838
|
+
'jobs',
|
|
839
|
+
params.sourceName,
|
|
840
|
+
'steps',
|
|
841
|
+
params.stepIndex,
|
|
842
|
+
'thinking'
|
|
843
|
+
],
|
|
844
|
+
issues: params.issues,
|
|
845
|
+
fillSite: params.fillSite,
|
|
846
|
+
allowedJobReferences: params.allowedJobReferences,
|
|
847
|
+
typeOverlay: params.typeOverlay
|
|
848
|
+
});
|
|
641
849
|
validateAgentStep({
|
|
642
850
|
step: params.step,
|
|
643
851
|
sourceName: params.sourceName,
|
|
644
852
|
stepIndex: params.stepIndex,
|
|
645
853
|
issues: params.issues,
|
|
646
|
-
|
|
854
|
+
validateLiteralModel: params.step.model !== undefined && !hasInterpolationSyntax(params.step.model),
|
|
855
|
+
validateLiteralProvider: params.step.provider !== undefined && !hasInterpolationSyntax(params.step.provider),
|
|
647
856
|
agentValidationCatalog: params.context.agentValidationCatalog
|
|
648
857
|
});
|
|
649
858
|
const integrations = normalizeAgentIntegrations({
|
|
@@ -657,7 +866,9 @@ function normalizeAgentStep(params) {
|
|
|
657
866
|
prompt: promptTemplate,
|
|
658
867
|
model: modelTemplate,
|
|
659
868
|
provider: providerTemplate,
|
|
660
|
-
|
|
869
|
+
thinking: thinkingTemplate,
|
|
870
|
+
name: params.name,
|
|
871
|
+
workingDirectory: params.workingDirectory
|
|
661
872
|
});
|
|
662
873
|
return {
|
|
663
874
|
...params.stepBase,
|
|
@@ -689,46 +900,88 @@ function normalizeAgentStep(params) {
|
|
|
689
900
|
function validateAgentStep(params) {
|
|
690
901
|
validateHarnessThinking(params);
|
|
691
902
|
validateHarnessTools(params);
|
|
692
|
-
if (!params.validateLiteralProvider) return;
|
|
693
903
|
const providerId = params.step.provider;
|
|
694
|
-
if (providerId === undefined) return;
|
|
695
|
-
const provider = params.agentValidationCatalog.providers.find((entry)=>entry.id === providerId);
|
|
696
904
|
const harness = params.step.harness;
|
|
697
|
-
|
|
698
|
-
if (
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
905
|
+
const provider = providerId === undefined ? undefined : params.agentValidationCatalog.providers.find((entry)=>entry.id === providerId);
|
|
906
|
+
if (params.validateLiteralProvider && providerId !== undefined) {
|
|
907
|
+
if (provider === undefined) {
|
|
908
|
+
if (harness === undefined || harness === 'pi') return;
|
|
909
|
+
params.issues.push(issue({
|
|
910
|
+
code: 'invalid-provider',
|
|
911
|
+
message: `Provider "${providerId}" is not supported.`,
|
|
912
|
+
path: [
|
|
913
|
+
'jobs',
|
|
914
|
+
params.sourceName,
|
|
915
|
+
'steps',
|
|
916
|
+
params.stepIndex,
|
|
917
|
+
'provider'
|
|
918
|
+
],
|
|
919
|
+
details: {
|
|
920
|
+
provider: providerId
|
|
921
|
+
}
|
|
922
|
+
}));
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
if (provider.support_status !== 'supported') {
|
|
926
|
+
params.issues.push(issue({
|
|
927
|
+
code: 'invalid-provider',
|
|
928
|
+
message: `Provider "${providerId}" is not supported.`,
|
|
929
|
+
path: [
|
|
930
|
+
'jobs',
|
|
931
|
+
params.sourceName,
|
|
932
|
+
'steps',
|
|
933
|
+
params.stepIndex,
|
|
934
|
+
'provider'
|
|
935
|
+
],
|
|
936
|
+
details: {
|
|
937
|
+
provider: providerId
|
|
938
|
+
}
|
|
939
|
+
}));
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
if (harness === undefined) return;
|
|
943
|
+
const descriptor = params.agentValidationCatalog.harnesses.find((entry)=>entry.id === harness);
|
|
944
|
+
if (!descriptor?.supported_provider_ids.includes(providerId)) {
|
|
945
|
+
params.issues.push(issue({
|
|
946
|
+
code: 'harness-provider-incompatible',
|
|
947
|
+
message: `Harness "${harness}" does not support provider: ${providerId}. Supported providers: ${descriptor?.supported_provider_ids.join(', ') ?? ''}.`,
|
|
948
|
+
path: [
|
|
949
|
+
'jobs',
|
|
950
|
+
params.sourceName,
|
|
951
|
+
'steps',
|
|
952
|
+
params.stepIndex,
|
|
953
|
+
'provider'
|
|
954
|
+
],
|
|
955
|
+
details: {
|
|
956
|
+
harness,
|
|
957
|
+
provider: providerId,
|
|
958
|
+
supportedProviders: descriptor?.supported_provider_ids ?? []
|
|
959
|
+
}
|
|
960
|
+
}));
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
714
963
|
}
|
|
715
|
-
if (harness === undefined) return;
|
|
964
|
+
if (!params.validateLiteralModel || providerId === undefined || harness === undefined) return;
|
|
965
|
+
if (provider === undefined || provider.support_status !== 'supported') return;
|
|
966
|
+
const model = params.step.model;
|
|
967
|
+
if (model === undefined) return;
|
|
716
968
|
const descriptor = params.agentValidationCatalog.harnesses.find((entry)=>entry.id === harness);
|
|
717
|
-
|
|
969
|
+
const modelIds = descriptor?.model_ids_by_provider?.[providerId];
|
|
970
|
+
if (modelIds === undefined || modelIds.includes(model)) return;
|
|
718
971
|
params.issues.push(issue({
|
|
719
|
-
code: '
|
|
720
|
-
message: `
|
|
972
|
+
code: 'invalid-model',
|
|
973
|
+
message: `Agent model "${model}" is not available for harness "${harness}" and provider "${providerId}".`,
|
|
721
974
|
path: [
|
|
722
975
|
'jobs',
|
|
723
976
|
params.sourceName,
|
|
724
977
|
'steps',
|
|
725
978
|
params.stepIndex,
|
|
726
|
-
'
|
|
979
|
+
'model'
|
|
727
980
|
],
|
|
728
981
|
details: {
|
|
729
982
|
harness,
|
|
730
983
|
provider: providerId,
|
|
731
|
-
|
|
984
|
+
model
|
|
732
985
|
}
|
|
733
986
|
}));
|
|
734
987
|
}
|
|
@@ -778,6 +1031,9 @@ function validateHarnessTools(params) {
|
|
|
778
1031
|
function validateHarnessThinking(params) {
|
|
779
1032
|
const { harness, thinking } = params.step;
|
|
780
1033
|
if (harness === undefined || thinking === undefined) return;
|
|
1034
|
+
// An interpolated level is only known when the step dispatches, so the agent
|
|
1035
|
+
// module checks it against the resolved harness there.
|
|
1036
|
+
if (hasInterpolationSyntax(thinking)) return;
|
|
781
1037
|
const supportedLevels = params.agentValidationCatalog.harnesses.find((entry)=>entry.id === harness)?.thinking_levels ?? [];
|
|
782
1038
|
if (supportedLevels.includes(thinking)) return;
|
|
783
1039
|
params.issues.push(issue({
|
|
@@ -895,7 +1151,7 @@ function validateRunnerLabels(params) {
|
|
|
895
1151
|
}
|
|
896
1152
|
}
|
|
897
1153
|
function optionalRunStepTemplates(params) {
|
|
898
|
-
if (params.command === undefined && params.name === undefined && params.env === undefined) {
|
|
1154
|
+
if (params.command === undefined && params.name === undefined && params.workingDirectory === undefined && params.env === undefined) {
|
|
899
1155
|
return undefined;
|
|
900
1156
|
}
|
|
901
1157
|
return {
|
|
@@ -905,13 +1161,16 @@ function optionalRunStepTemplates(params) {
|
|
|
905
1161
|
...params.name === undefined ? {} : {
|
|
906
1162
|
name: params.name
|
|
907
1163
|
},
|
|
1164
|
+
...params.workingDirectory === undefined ? {} : {
|
|
1165
|
+
workingDirectory: params.workingDirectory
|
|
1166
|
+
},
|
|
908
1167
|
...params.env === undefined ? {} : {
|
|
909
1168
|
env: params.env
|
|
910
1169
|
}
|
|
911
1170
|
};
|
|
912
1171
|
}
|
|
913
1172
|
function optionalAgentStepTemplates(params) {
|
|
914
|
-
if (params.prompt === undefined && params.model === undefined && params.provider === undefined && params.name === undefined) {
|
|
1173
|
+
if (params.prompt === undefined && params.model === undefined && params.provider === undefined && params.thinking === undefined && params.name === undefined && params.workingDirectory === undefined) {
|
|
915
1174
|
return undefined;
|
|
916
1175
|
}
|
|
917
1176
|
return {
|
|
@@ -924,8 +1183,14 @@ function optionalAgentStepTemplates(params) {
|
|
|
924
1183
|
...params.provider === undefined ? {} : {
|
|
925
1184
|
provider: params.provider
|
|
926
1185
|
},
|
|
1186
|
+
...params.thinking === undefined ? {} : {
|
|
1187
|
+
thinking: params.thinking
|
|
1188
|
+
},
|
|
927
1189
|
...params.name === undefined ? {} : {
|
|
928
1190
|
name: params.name
|
|
1191
|
+
},
|
|
1192
|
+
...params.workingDirectory === undefined ? {} : {
|
|
1193
|
+
workingDirectory: params.workingDirectory
|
|
929
1194
|
}
|
|
930
1195
|
};
|
|
931
1196
|
}
|