@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.
Files changed (56) hide show
  1. package/README.md +84 -44
  2. package/dist/bootstrap.d.ts +20 -0
  3. package/dist/bootstrap.d.ts.map +1 -1
  4. package/dist/bootstrap.js +21 -11
  5. package/dist/bootstrap.js.map +1 -1
  6. package/dist/core/run-context.d.ts +3 -0
  7. package/dist/core/run-context.d.ts.map +1 -1
  8. package/dist/core/run-context.js +2 -0
  9. package/dist/core/run-context.js.map +1 -1
  10. package/dist/core/task-executor.d.ts.map +1 -1
  11. package/dist/core/task-executor.js +11 -33
  12. package/dist/core/task-executor.js.map +1 -1
  13. package/dist/engine.d.ts +6 -0
  14. package/dist/engine.d.ts.map +1 -1
  15. package/dist/engine.js +3 -0
  16. package/dist/engine.js.map +1 -1
  17. package/dist/index.d.ts +3 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/plugins.d.ts +2 -2
  22. package/dist/plugins.d.ts.map +1 -1
  23. package/dist/registry.d.ts +10 -4
  24. package/dist/registry.d.ts.map +1 -1
  25. package/dist/registry.js +64 -25
  26. package/dist/registry.js.map +1 -1
  27. package/dist/runtime.d.ts +9 -0
  28. package/dist/runtime.d.ts.map +1 -0
  29. package/dist/runtime.js +8 -0
  30. package/dist/runtime.js.map +1 -0
  31. package/dist/schema.d.ts.map +1 -1
  32. package/dist/schema.js +1 -7
  33. package/dist/schema.js.map +1 -1
  34. package/dist/tagma.d.ts +11 -1
  35. package/dist/tagma.d.ts.map +1 -1
  36. package/dist/tagma.js +6 -0
  37. package/dist/tagma.js.map +1 -1
  38. package/dist/validate-raw.d.ts.map +1 -1
  39. package/dist/validate-raw.js +1 -101
  40. package/dist/validate-raw.js.map +1 -1
  41. package/package.json +2 -2
  42. package/src/bootstrap.ts +23 -14
  43. package/src/core/run-context.test.ts +12 -0
  44. package/src/core/run-context.ts +4 -0
  45. package/src/core/task-executor.ts +15 -41
  46. package/src/engine.ts +8 -0
  47. package/src/index.ts +5 -0
  48. package/src/plugin-registry.test.ts +138 -1
  49. package/src/plugins.ts +5 -2
  50. package/src/registry.ts +81 -26
  51. package/src/runtime.ts +20 -0
  52. package/src/schema-ports.test.ts +23 -0
  53. package/src/schema.ts +1 -7
  54. package/src/tagma.test.ts +72 -1
  55. package/src/tagma.ts +16 -1
  56. package/src/validate-raw.ts +1 -117
@@ -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 `ports.inputs`
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('|') : '';