@tagma/sdk 0.7.1 → 0.7.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/README.md +84 -44
- package/dist/bootstrap.d.ts +20 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +21 -11
- package/dist/bootstrap.js.map +1 -1
- package/dist/core/run-context.d.ts +3 -0
- package/dist/core/run-context.d.ts.map +1 -1
- package/dist/core/run-context.js +2 -0
- package/dist/core/run-context.js.map +1 -1
- package/dist/core/task-executor.d.ts.map +1 -1
- package/dist/core/task-executor.js +11 -33
- package/dist/core/task-executor.js.map +1 -1
- package/dist/engine.d.ts +6 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +3 -0
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins.d.ts +2 -2
- package/dist/plugins.d.ts.map +1 -1
- package/dist/registry.d.ts +10 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +64 -25
- package/dist/registry.js.map +1 -1
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +8 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +1 -7
- package/dist/schema.js.map +1 -1
- package/dist/tagma.d.ts +11 -1
- package/dist/tagma.d.ts.map +1 -1
- package/dist/tagma.js +6 -0
- package/dist/tagma.js.map +1 -1
- package/dist/validate-raw.d.ts.map +1 -1
- package/dist/validate-raw.js +1 -101
- package/dist/validate-raw.js.map +1 -1
- package/package.json +2 -2
- package/src/bootstrap.ts +23 -14
- package/src/core/run-context.test.ts +12 -0
- package/src/core/run-context.ts +4 -0
- package/src/core/task-executor.ts +15 -41
- package/src/engine.ts +8 -0
- package/src/index.ts +5 -0
- package/src/plugin-registry.test.ts +138 -1
- package/src/plugins.ts +5 -2
- package/src/registry.ts +81 -26
- package/src/runtime.ts +20 -0
- package/src/schema-ports.test.ts +23 -0
- package/src/schema.ts +1 -7
- package/src/tagma.test.ts +72 -1
- package/src/tagma.ts +16 -1
- package/src/validate-raw.ts +1 -117
package/src/validate-raw.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
// Returns a flat list of ValidationError objects. An empty array means valid.
|
|
8
8
|
|
|
9
9
|
import type {
|
|
10
|
-
PortDef,
|
|
11
10
|
PortType,
|
|
12
11
|
RawPipelineConfig,
|
|
13
12
|
RawTaskConfig,
|
|
@@ -461,83 +460,6 @@ const VALID_PORT_TYPES: ReadonlySet<PortType> = new Set([
|
|
|
461
460
|
// template grammar unambiguous.
|
|
462
461
|
const PORT_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
463
462
|
|
|
464
|
-
function validatePortList(
|
|
465
|
-
list: readonly PortDef[] | undefined,
|
|
466
|
-
basePath: string,
|
|
467
|
-
kind: 'inputs' | 'outputs',
|
|
468
|
-
errors: ValidationError[],
|
|
469
|
-
): void {
|
|
470
|
-
if (!list) return;
|
|
471
|
-
if (!Array.isArray(list)) {
|
|
472
|
-
errors.push({
|
|
473
|
-
path: basePath,
|
|
474
|
-
message: `ports.${kind} must be an array`,
|
|
475
|
-
});
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
const seen = new Set<string>();
|
|
479
|
-
for (let i = 0; i < list.length; i++) {
|
|
480
|
-
const port = list[i];
|
|
481
|
-
const path = `${basePath}[${i}]`;
|
|
482
|
-
if (!port || typeof port !== 'object') {
|
|
483
|
-
errors.push({ path, message: `ports.${kind}[${i}] must be an object` });
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
if (typeof port.name !== 'string' || !port.name.trim()) {
|
|
487
|
-
errors.push({ path: `${path}.name`, message: 'port.name is required' });
|
|
488
|
-
continue;
|
|
489
|
-
}
|
|
490
|
-
if (!PORT_NAME_RE.test(port.name)) {
|
|
491
|
-
errors.push({
|
|
492
|
-
path: `${path}.name`,
|
|
493
|
-
message: `port name "${port.name}" is invalid. Must match /^[A-Za-z_][A-Za-z0-9_]*$/ (letters, digits, underscores; starts with letter/underscore).`,
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
if (seen.has(port.name)) {
|
|
497
|
-
errors.push({
|
|
498
|
-
path,
|
|
499
|
-
message: `Duplicate ports.${kind} name "${port.name}"`,
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
seen.add(port.name);
|
|
503
|
-
if (!VALID_PORT_TYPES.has(port.type)) {
|
|
504
|
-
errors.push({
|
|
505
|
-
path: `${path}.type`,
|
|
506
|
-
message: `port "${port.name}": type must be one of ${[...VALID_PORT_TYPES].join(', ')} (got ${JSON.stringify(port.type)})`,
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
if (port.type === 'enum') {
|
|
510
|
-
if (!Array.isArray(port.enum) || port.enum.length === 0) {
|
|
511
|
-
errors.push({
|
|
512
|
-
path: `${path}.enum`,
|
|
513
|
-
message: `port "${port.name}": enum type requires a non-empty "enum" array`,
|
|
514
|
-
});
|
|
515
|
-
} else if (port.enum.some((v: unknown) => typeof v !== 'string')) {
|
|
516
|
-
errors.push({
|
|
517
|
-
path: `${path}.enum`,
|
|
518
|
-
message: `port "${port.name}": enum values must all be strings`,
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
if (kind === 'outputs' && (port.required === true || port.from !== undefined)) {
|
|
523
|
-
// `required` / `from` are input-only concepts 鈥?outputs are
|
|
524
|
-
// always "produced when the task succeeds". Warn softly so the
|
|
525
|
-
// YAML doesn't silently accept meaningless fields.
|
|
526
|
-
errors.push({
|
|
527
|
-
path,
|
|
528
|
-
severity: 'warning',
|
|
529
|
-
message: `port "${port.name}": "required" and "from" are input-only; ignored on outputs`,
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
if (port.from !== undefined && typeof port.from !== 'string') {
|
|
533
|
-
errors.push({
|
|
534
|
-
path: `${path}.from`,
|
|
535
|
-
message: `port "${port.name}": "from" must be a string (got ${typeof port.from})`,
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
463
|
function validateBindingMap(
|
|
542
464
|
value: unknown,
|
|
543
465
|
basePath: string,
|
|
@@ -609,38 +531,6 @@ function validateBindingMap(
|
|
|
609
531
|
}
|
|
610
532
|
}
|
|
611
533
|
|
|
612
|
-
function validateBindingPortNameOverlap(
|
|
613
|
-
task: RawTaskConfig,
|
|
614
|
-
taskPath: string,
|
|
615
|
-
errors: ValidationError[],
|
|
616
|
-
): void {
|
|
617
|
-
const looseInputs = objectKeys(task.inputs);
|
|
618
|
-
const looseOutputs = objectKeys(task.outputs);
|
|
619
|
-
const strictInputs = new Set(
|
|
620
|
-
Array.isArray(task.ports?.inputs) ? task.ports.inputs.map((p) => p?.name) : [],
|
|
621
|
-
);
|
|
622
|
-
const strictOutputs = new Set(
|
|
623
|
-
Array.isArray(task.ports?.outputs) ? task.ports.outputs.map((p) => p?.name) : [],
|
|
624
|
-
);
|
|
625
|
-
|
|
626
|
-
for (const name of looseInputs) {
|
|
627
|
-
if (strictInputs.has(name)) {
|
|
628
|
-
errors.push({
|
|
629
|
-
path: `${taskPath}.inputs.${name}`,
|
|
630
|
-
message: `task input binding "${name}" duplicates strict ports.inputs; choose one layer for this name`,
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
for (const name of looseOutputs) {
|
|
635
|
-
if (strictOutputs.has(name)) {
|
|
636
|
-
errors.push({
|
|
637
|
-
path: `${taskPath}.outputs.${name}`,
|
|
638
|
-
message: `task output binding "${name}" duplicates strict ports.outputs; choose one layer for this name`,
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
534
|
function objectKeys(value: unknown): string[] {
|
|
645
535
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return [];
|
|
646
536
|
return Object.keys(value as Record<string, unknown>);
|
|
@@ -701,7 +591,6 @@ function validateTaskPorts(
|
|
|
701
591
|
|
|
702
592
|
validateBindingMap(task.inputs, `${taskPath}.inputs`, 'inputs', errors);
|
|
703
593
|
validateBindingMap(task.outputs, `${taskPath}.outputs`, 'outputs', errors);
|
|
704
|
-
validateBindingPortNameOverlap(task, taskPath, errors);
|
|
705
594
|
validateInputBindingSources(task, trackId, taskPath, index, errors);
|
|
706
595
|
|
|
707
596
|
if (ports !== undefined) {
|
|
@@ -717,7 +606,7 @@ function validateTaskPorts(
|
|
|
717
606
|
// Collect placeholder references 鈹€鈹€
|
|
718
607
|
// `{{inputs.X}}` is valid in both prompt and command text. The set of
|
|
719
608
|
// names a task may legally reference differs by task kind:
|
|
720
|
-
// - Command Task: its own declared `
|
|
609
|
+
// - Command Task: its own declared `inputs`
|
|
721
610
|
// - Prompt Task: the union of direct-upstream Command outputs
|
|
722
611
|
const referenced = new Set<string>();
|
|
723
612
|
if (typeof task.prompt === 'string') {
|
|
@@ -887,11 +776,6 @@ function validateInferredPromptPortConflicts(
|
|
|
887
776
|
}
|
|
888
777
|
}
|
|
889
778
|
|
|
890
|
-
/** Minimal shape fingerprint for conflict detection: type + enum set. */
|
|
891
|
-
function portShapeKey(port: PortDef): string {
|
|
892
|
-
return bindingShapeKey(port);
|
|
893
|
-
}
|
|
894
|
-
|
|
895
779
|
function bindingShapeKey(port: { type?: PortType; enum?: readonly string[] }): string {
|
|
896
780
|
if ((port.type ?? 'json') !== 'enum') return String(port.type ?? 'json');
|
|
897
781
|
const enums = Array.isArray(port.enum) ? [...port.enum].sort().join('|') : '';
|