@qaick/executor 0.1.0-alpha.2 → 0.1.0-alpha.3
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/declared-inputs.d.ts +11 -0
- package/dist/declared-inputs.js +32 -0
- package/dist/executor.js +11 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/migrated-project-engine.js +1 -1
- package/dist/migrated-runner-engine.js +6 -2
- package/dist/migrated-types.d.ts +1 -1
- package/dist/migrated-types.js +1 -1
- package/package.json +13 -5
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ExecutableInput } from '@qaick/contract';
|
|
2
|
+
/** Shared invocation semantics. Never coerce supplied arguments or rewrite declarations. */
|
|
3
|
+
export declare function resolveDeclaredInputs(declarations?: readonly ExecutableInput[], arguments_?: Record<string, unknown>): {
|
|
4
|
+
inputs: {
|
|
5
|
+
[x: string]: unknown;
|
|
6
|
+
};
|
|
7
|
+
issues: {
|
|
8
|
+
code: string;
|
|
9
|
+
message: string;
|
|
10
|
+
}[];
|
|
11
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Shared invocation semantics. Never coerce supplied arguments or rewrite declarations. */
|
|
2
|
+
export function resolveDeclaredInputs(declarations = [], arguments_ = {}) {
|
|
3
|
+
const inputs = { ...arguments_ };
|
|
4
|
+
const issues = [];
|
|
5
|
+
if (!Array.isArray(declarations))
|
|
6
|
+
return { inputs, issues: [{ code: 'INVALID_INPUT', message: 'Declared inputs must be an array.' }] };
|
|
7
|
+
const seen = new Set();
|
|
8
|
+
for (const declaration of declarations) {
|
|
9
|
+
if (!declaration || typeof declaration.name !== 'string' || !declaration.name || seen.has(declaration.name) || !['string', 'number', 'boolean', 'json'].includes(declaration.type) || typeof declaration.required !== 'boolean') {
|
|
10
|
+
issues.push({ code: 'INVALID_INPUT', message: 'Invalid or duplicate declared input.' });
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
seen.add(declaration.name);
|
|
14
|
+
const supplied = Object.hasOwn(arguments_, declaration.name);
|
|
15
|
+
const value = supplied ? arguments_[declaration.name] : declaration.defaultValue;
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
delete inputs[declaration.name];
|
|
18
|
+
if (declaration.required)
|
|
19
|
+
issues.push({ code: 'MISSING_INPUT', message: `Required input ${declaration.name} is missing.` });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const validType = declaration.type === 'number' ? typeof value === 'number' && Number.isFinite(value)
|
|
23
|
+
: declaration.type === 'json' ? typeof value === 'object' && value !== null
|
|
24
|
+
: typeof value === declaration.type;
|
|
25
|
+
if (!validType || (declaration.required && value === '')) {
|
|
26
|
+
issues.push({ code: 'INVALID_INPUT', message: `Input ${declaration.name}: expected ${declaration.type}${declaration.required ? ' (required)' : ''}.` });
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
inputs[declaration.name] = value;
|
|
30
|
+
}
|
|
31
|
+
return { inputs, issues };
|
|
32
|
+
}
|
package/dist/executor.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveDeclaredInputs } from './declared-inputs.js';
|
|
1
2
|
const MAX_TIMEOUT_MS = 300_000;
|
|
2
3
|
export function createExecutor(configuration = {}) {
|
|
3
4
|
return new DefaultExecutor(configuration);
|
|
@@ -180,7 +181,9 @@ export class DefaultExecutor {
|
|
|
180
181
|
timeout = setTimeout(() => { run.timedOut = true; run.abort.abort(); }, timeoutMs);
|
|
181
182
|
this.emit(run, 'run_started', 'created', 'Execution accepted.');
|
|
182
183
|
this.emit(run, 'preflight_started', 'preflighting', 'Validating execution package.');
|
|
183
|
-
const
|
|
184
|
+
const arguments_ = resolveDeclaredInputs(run.request.executionPackage.inputDeclarations, run.request.inputs);
|
|
185
|
+
run.request = { ...run.request, inputs: arguments_.inputs };
|
|
186
|
+
const issues = [...arguments_.issues, ...preflight(run.request.executionPackage, arguments_.inputs, run.request.runtimeValues ?? {})];
|
|
184
187
|
if (issues.length > 0 || run.request.options?.dryRun) {
|
|
185
188
|
const result = this.baseResult(run, startedAt, issues.length > 0 ? 'failed' : 'completed', undefined, issues);
|
|
186
189
|
if (timeout)
|
|
@@ -211,7 +214,11 @@ export class DefaultExecutor {
|
|
|
211
214
|
for (const flow of pkg.flows ?? []) {
|
|
212
215
|
if (run.cancelled || run.abort.signal.aborted)
|
|
213
216
|
throw new Error('Execution cancelled.');
|
|
214
|
-
const
|
|
217
|
+
const arguments_ = resolveDeclaredInputs(flow.inputDeclarations, inputs);
|
|
218
|
+
const issues = [...arguments_.issues, ...preflight({ ...pkg, target: { kind: 'flow', id: flow.id, name: flow.name }, requiredInputs: flow.requiredInputs }, arguments_.inputs, run.request.runtimeValues ?? {})];
|
|
219
|
+
if (issues.length)
|
|
220
|
+
return this.baseResult(run, startedAt, 'failed', undefined, issues, children);
|
|
221
|
+
const child = await this.executeFlow(run, flow.steps, arguments_.inputs, [flow.id], startedAt, { kind: 'flow', id: flow.id, name: flow.name });
|
|
215
222
|
children.push(child);
|
|
216
223
|
if (child.state !== 'completed')
|
|
217
224
|
return this.baseResult(run, startedAt, child.state, child.error, undefined, children);
|
|
@@ -434,8 +441,9 @@ function preflight(pkg, inputs, runtimeValues) {
|
|
|
434
441
|
const issues = [];
|
|
435
442
|
if (!pkg.packageId || !pkg.target?.id)
|
|
436
443
|
issues.push({ code: 'INVALID_PACKAGE', message: 'Execution package identity is incomplete.' });
|
|
444
|
+
const flowInputNames = new Set(pkg.target.kind === 'project' ? (pkg.flows ?? []).flatMap(flow => Array.isArray(flow.inputDeclarations) ? flow.inputDeclarations.flatMap(input => typeof input?.name === 'string' ? [input.name] : []) : []) : []);
|
|
437
445
|
for (const name of pkg.requiredInputs ?? [])
|
|
438
|
-
if (inputs[name] === undefined)
|
|
446
|
+
if (inputs[name] === undefined && !flowInputNames.has(name))
|
|
439
447
|
issues.push({ code: 'MISSING_INPUT', message: `Required input '${name}' is missing.` });
|
|
440
448
|
for (const name of pkg.runtimeRequirements ?? [])
|
|
441
449
|
if (runtimeValues[name] === undefined)
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -90,7 +90,7 @@ export class MigratedProjectRunnerEngine {
|
|
|
90
90
|
}
|
|
91
91
|
const childRequestId = `${request.requestId}:${flow.id}`;
|
|
92
92
|
run.activeRequestId = childRequestId;
|
|
93
|
-
const childPackage = { ...request.executionPackage, target: { kind: 'flow', id: flow.id, name: flow.name }, steps: flow.steps, flows: undefined, requiredInputs: flow.requiredInputs };
|
|
93
|
+
const childPackage = { ...request.executionPackage, target: { kind: 'flow', id: flow.id, name: flow.name }, steps: flow.steps, flows: undefined, requiredInputs: flow.requiredInputs, inputDeclarations: flow.inputDeclarations };
|
|
94
94
|
await this.flowEngine.submit({ requestId: childRequestId, executionPackage: childPackage, inputs, environment: request.environment, runtimeValues: request.runtimeValues, options: request.options, debugSession: request.debugSession });
|
|
95
95
|
for await (const event of this.flowEngine.events(childRequestId))
|
|
96
96
|
this.emit(run, event.type, event.state, `[${flow.name}] ${event.message}`, event.stepId ? { stepId: event.stepId, stepName: event.stepName } : undefined, event.parallel, event.control);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveDeclaredInputs } from './declared-inputs.js';
|
|
1
2
|
import { InMemoryActionAdapter } from './migrated-adapter.js';
|
|
2
3
|
import { hashExecutionPackage } from './migrated-artifact-hash.js';
|
|
3
4
|
import { RUNNER_PACKAGE_SCHEMA_VERSION } from './migrated-types.js';
|
|
@@ -119,7 +120,7 @@ export class MigratedRunnerEngine {
|
|
|
119
120
|
return new Promise(resolve => { const previous = run.resultResolve; run.resultResolve = result => { previous(result); resolve(result); }; });
|
|
120
121
|
}
|
|
121
122
|
async execute(run, resultPromise) {
|
|
122
|
-
|
|
123
|
+
let { request } = run;
|
|
123
124
|
const startedAt = new Date().toISOString();
|
|
124
125
|
run.controlState = 'running';
|
|
125
126
|
this.emit(run, 'run_started', 'created', 'Run accepted.');
|
|
@@ -133,7 +134,10 @@ export class MigratedRunnerEngine {
|
|
|
133
134
|
await resultPromise;
|
|
134
135
|
return;
|
|
135
136
|
}
|
|
136
|
-
const
|
|
137
|
+
const arguments_ = resolveDeclaredInputs(request.executionPackage.inputDeclarations, request.inputs);
|
|
138
|
+
run.request = { ...request, inputs: arguments_.inputs };
|
|
139
|
+
request = run.request;
|
|
140
|
+
const validationIssues = [...arguments_.issues, ...this.validateAll(request.executionPackage, arguments_.inputs, request.runtimeValues ?? {})];
|
|
137
141
|
const validationWarnings = this.validateBrowserWarnings(request.executionPackage);
|
|
138
142
|
if (request.options?.dryRun) {
|
|
139
143
|
const dryRunResult = { requestId: request.requestId, state: validationIssues.length ? 'failed' : 'completed', target: request.executionPackage.target, environment: request.environment, startedAt, finishedAt: new Date().toISOString(), steps: [], terminalReason: validationIssues.length ? 'failed' : 'completed', issues: validationIssues, warnings: validationWarnings, ...(validationIssues.length ? { error: { code: 'DRY_RUN_ISSUES', message: `${validationIssues.length} issue${validationIssues.length === 1 ? '' : 's'} found during dry run.` } } : {}) };
|
package/dist/migrated-types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Compatibility import for Runner modules. The canonical contract is the published @qaick/contract package. */
|
|
2
2
|
export * from '@qaick/contract';
|
|
3
3
|
/** The exact published contract package consumed by this Runner release. */
|
|
4
|
-
export declare const RUNNER_CONTRACT_VERSION: "0.2.
|
|
4
|
+
export declare const RUNNER_CONTRACT_VERSION: "0.2.12";
|
|
5
5
|
export type ExecutionControlState = 'idle' | 'running' | 'pause-requested' | 'paused' | 'resuming' | 'stopped' | 'failed' | 'completed';
|
|
6
6
|
export interface RunnerDebugSession {
|
|
7
7
|
breakpoints: string[];
|
package/dist/migrated-types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Compatibility import for Runner modules. The canonical contract is the published @qaick/contract package. */
|
|
2
2
|
export * from '@qaick/contract';
|
|
3
3
|
/** The exact published contract package consumed by this Runner release. */
|
|
4
|
-
export const RUNNER_CONTRACT_VERSION = '0.2.
|
|
4
|
+
export const RUNNER_CONTRACT_VERSION = '0.2.12';
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qaick/executor",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "Host-neutral QAick action execution primitives.",
|
|
5
|
-
"files": [
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"README.md"
|
|
8
|
+
],
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public",
|
|
14
|
+
"tag": "alpha"
|
|
15
|
+
},
|
|
8
16
|
"repository": {
|
|
9
17
|
"type": "git",
|
|
10
18
|
"url": "git+https://github.com/vladmus/QAICK_Executor.git"
|
|
@@ -26,7 +34,7 @@
|
|
|
26
34
|
"prepublishOnly": "npm run typecheck && npm test && npm run build"
|
|
27
35
|
},
|
|
28
36
|
"dependencies": {
|
|
29
|
-
"@qaick/contract": "0.2.
|
|
37
|
+
"@qaick/contract": "0.2.12"
|
|
30
38
|
},
|
|
31
39
|
"devDependencies": {
|
|
32
40
|
"@types/node": "^24.13.3",
|