xytara 1.2.0 → 1.3.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/README.md CHANGED
@@ -30,7 +30,7 @@ The public product loop is:
30
30
 
31
31
  The package and service surfaces both follow that model.
32
32
 
33
- The current built-in catalog now covers a broader first-party `1.2.0` kernel than the original narrow seed, including:
33
+ The current built-in catalog now covers a broader first-party `1.3.0` kernel than the original narrow seed, including:
34
34
 
35
35
  - trust and receipt validation/handoff tasks
36
36
  - runtime consequence tasks
package/index.js CHANGED
@@ -30,11 +30,13 @@ const {
30
30
  summarizeIntegrationSubmissionBundleReview,
31
31
  summarizeIntegrationSubmissionBundleSetReview,
32
32
  summarizeIntegrationRegistrySnapshotReview,
33
- summarizeIntegrationPromotionReadiness
33
+ summarizeIntegrationPromotionReadiness,
34
+ summarizeIntegrationPromotionWorkflow,
35
+ summarizeIntegrationPromotionWorkflowList
34
36
  } = require("./integrations/registry");
35
37
 
36
38
  const COMMERCE_SDK_NAME = "xytara";
37
- const COMMERCE_SDK_VERSION = "1.2.0";
39
+ const COMMERCE_SDK_VERSION = "1.3.0";
38
40
  const COMMERCE_API_VERSION = "v1";
39
41
 
40
42
  function createClient(options) {
@@ -73,5 +75,7 @@ module.exports = {
73
75
  summarizeIntegrationSubmissionBundleSetReview,
74
76
  summarizeIntegrationRegistrySnapshotReview,
75
77
  summarizeIntegrationPromotionReadiness,
78
+ summarizeIntegrationPromotionWorkflow,
79
+ summarizeIntegrationPromotionWorkflowList,
76
80
  validateAdapterImplementation
77
81
  };
@@ -452,6 +452,31 @@ function summarizeCounts(values, fieldName) {
452
452
  }));
453
453
  }
454
454
 
455
+ function summarizeStructuredCounts(entries, fields = []) {
456
+ const rows = Array.isArray(entries) ? entries.filter((entry) => entry && typeof entry === "object") : [];
457
+ const normalizedFields = Array.isArray(fields) ? fields.filter(Boolean) : [];
458
+ const seen = new Map();
459
+
460
+ rows.forEach((entry) => {
461
+ const key = normalizedFields.map((field) => String(entry[field] || "")).join("::");
462
+ if (!seen.has(key)) {
463
+ const item = {};
464
+ normalizedFields.forEach((field) => {
465
+ item[field] = entry[field] || null;
466
+ });
467
+ item.count = 0;
468
+ seen.set(key, item);
469
+ }
470
+ seen.get(key).count += 1;
471
+ });
472
+
473
+ return Array.from(seen.values()).sort((left, right) => {
474
+ const leftKey = normalizedFields.map((field) => String(left[field] || "")).join("::");
475
+ const rightKey = normalizedFields.map((field) => String(right[field] || "")).join("::");
476
+ return leftKey.localeCompare(rightKey);
477
+ });
478
+ }
479
+
455
480
  function buildPromotionReadinessSummary(input = {}) {
456
481
  const registration = input.registration && typeof input.registration === "object" ? input.registration : {};
457
482
  const certification = input.certification && typeof input.certification === "object" ? input.certification : {};
@@ -503,6 +528,204 @@ function buildPromotionReadinessSummary(input = {}) {
503
528
  };
504
529
  }
505
530
 
531
+ function summarizePromotionBlockerCategories(blockers = []) {
532
+ const values = Array.isArray(blockers) ? blockers : [];
533
+ const categories = [];
534
+ if (values.some((entry) => entry === "registration_state_missing")) {
535
+ categories.push({
536
+ category: "registration",
537
+ severity: "high",
538
+ owner: "integration_author"
539
+ });
540
+ }
541
+ if (values.some((entry) => entry === "certification_state_missing" || entry === "not_certified")) {
542
+ categories.push({
543
+ category: "certification",
544
+ severity: "high",
545
+ owner: "review_operator"
546
+ });
547
+ }
548
+ if (values.some((entry) => entry === "integration_maturity_missing" || entry === "not_marked_production_default")) {
549
+ categories.push({
550
+ category: "maturity",
551
+ severity: "medium",
552
+ owner: "review_operator"
553
+ });
554
+ }
555
+ if (values.some((entry) => entry === "default_selection_disabled" || entry === "still_requires_explicit_selection")) {
556
+ categories.push({
557
+ category: "selection",
558
+ severity: "medium",
559
+ owner: "platform_operator"
560
+ });
561
+ }
562
+ if (values.some((entry) => entry === "not_bundled_for_default_rollout")) {
563
+ categories.push({
564
+ category: "rollout",
565
+ severity: "low",
566
+ owner: "release_operator"
567
+ });
568
+ }
569
+ return summarizeStructuredCounts(categories, ["category", "severity", "owner"]);
570
+ }
571
+
572
+ function buildCertificationGapSummary(readiness = {}, integration = {}) {
573
+ const blockers = Array.isArray(readiness.blockers) ? readiness.blockers : [];
574
+ const certificationScope = Array.isArray(integration.certification_scope) ? integration.certification_scope.filter(Boolean) : [];
575
+ const verifiedWith = integration.registration && Array.isArray(integration.registration.verified_with)
576
+ ? integration.registration.verified_with.filter(Boolean)
577
+ : [];
578
+ const missingRequirements = [];
579
+ const productionReady = readiness.production_default_ready === true;
580
+
581
+ if (blockers.includes("certification_state_missing") || blockers.includes("not_certified")) {
582
+ missingRequirements.push("certification_state");
583
+ }
584
+ if (!productionReady && certificationScope.length < 1) {
585
+ missingRequirements.push("certification_scope");
586
+ }
587
+ if (!productionReady && verifiedWith.length < 1) {
588
+ missingRequirements.push("verified_with");
589
+ }
590
+
591
+ return {
592
+ certification_state: readiness.certification_state || null,
593
+ certification_scope_count: certificationScope.length,
594
+ verified_with_count: verifiedWith.length,
595
+ missing_requirements: missingRequirements,
596
+ certifiable: missingRequirements.length === 0
597
+ };
598
+ }
599
+
600
+ function buildNextTransitionSummary(readiness = {}) {
601
+ const blockers = Array.isArray(readiness.blockers) ? readiness.blockers : [];
602
+ if (readiness.production_default_ready === true) {
603
+ return {
604
+ action: "maintain_production_default",
605
+ reason: "integration already satisfies production-default posture",
606
+ requirements: [],
607
+ later_actions: []
608
+ };
609
+ }
610
+ if (blockers.includes("registration_state_missing")) {
611
+ return {
612
+ action: "register_integration",
613
+ reason: "integration is missing a registration state",
614
+ requirements: ["registration_state"],
615
+ later_actions: ["complete_certification", "promote_maturity", "enable_default_selection", "bundle_for_default_rollout"]
616
+ };
617
+ }
618
+ if (blockers.includes("not_certified") || blockers.includes("certification_state_missing")) {
619
+ return {
620
+ action: "complete_certification",
621
+ reason: "integration is not yet certified",
622
+ requirements: ["certification_state"],
623
+ later_actions: ["promote_maturity", "enable_default_selection", "bundle_for_default_rollout"]
624
+ };
625
+ }
626
+ if (blockers.includes("not_marked_production_default") || blockers.includes("integration_maturity_missing")) {
627
+ return {
628
+ action: "promote_maturity",
629
+ reason: "integration maturity is not yet aligned with production default rollout",
630
+ requirements: ["integration_maturity"],
631
+ later_actions: ["enable_default_selection", "bundle_for_default_rollout"]
632
+ };
633
+ }
634
+ if (blockers.includes("default_selection_disabled") || blockers.includes("still_requires_explicit_selection")) {
635
+ return {
636
+ action: "enable_default_selection",
637
+ reason: "integration remains explicit-selection only",
638
+ requirements: ["default_selection_enabled", "requires_explicit_selection=false"],
639
+ later_actions: blockers.includes("not_bundled_for_default_rollout") ? ["bundle_for_default_rollout"] : []
640
+ };
641
+ }
642
+ if (blockers.includes("not_bundled_for_default_rollout")) {
643
+ return {
644
+ action: "bundle_for_default_rollout",
645
+ reason: "integration is not yet bundled for production default rollout",
646
+ requirements: ["bundled=true"],
647
+ later_actions: []
648
+ };
649
+ }
650
+ return {
651
+ action: "review_manually",
652
+ reason: "integration posture needs operator review",
653
+ requirements: [],
654
+ later_actions: []
655
+ };
656
+ }
657
+
658
+ function buildPromotionRecommendationSummary(readiness = {}) {
659
+ const nextTransition = buildNextTransitionSummary(readiness);
660
+ if (readiness.production_default_ready === true) {
661
+ return {
662
+ recommendation: "eligible_for_production_default",
663
+ rationale: "integration is ready for production-default posture"
664
+ };
665
+ }
666
+ if (readiness.review_ready === true && readiness.default_eligible === false) {
667
+ return {
668
+ recommendation: "keep_staged_until_requirements_clear",
669
+ rationale: nextTransition.reason
670
+ };
671
+ }
672
+ if (readiness.review_ready === true) {
673
+ return {
674
+ recommendation: "review_for_promotion",
675
+ rationale: nextTransition.reason
676
+ };
677
+ }
678
+ return {
679
+ recommendation: "complete_prerequisites_first",
680
+ rationale: nextTransition.reason
681
+ };
682
+ }
683
+
684
+ function buildPromotionActionQueues(integrations = []) {
685
+ const rows = Array.isArray(integrations) ? integrations.filter((entry) => entry && entry.next_transition) : [];
686
+ const groups = new Map();
687
+
688
+ rows.forEach((entry) => {
689
+ const action = entry.next_transition && entry.next_transition.action
690
+ ? entry.next_transition.action
691
+ : "review_manually";
692
+ if (!groups.has(action)) {
693
+ groups.set(action, []);
694
+ }
695
+ groups.get(action).push(entry);
696
+ });
697
+
698
+ return Array.from(groups.keys()).sort().map((action) => {
699
+ const entries = groups.get(action) || [];
700
+ const blockerEntries = entries.flatMap((entry) => entry.blocker_categories || []);
701
+ return {
702
+ action,
703
+ count: entries.length,
704
+ recommendation_counts: summarizeCounts(
705
+ entries.map((entry) => entry.promotion_recommendation && entry.promotion_recommendation.recommendation).filter(Boolean),
706
+ "recommendation"
707
+ ),
708
+ owner_queue: summarizeCounts(
709
+ blockerEntries.map((entry) => entry.owner).filter(Boolean),
710
+ "owner"
711
+ ),
712
+ severity_queue: summarizeCounts(
713
+ blockerEntries.map((entry) => entry.severity).filter(Boolean),
714
+ "severity"
715
+ ),
716
+ integration_ids: entries.map((entry) => entry.integration_id).filter(Boolean).sort(),
717
+ integrations: entries.map((entry) => ({
718
+ integration_id: entry.integration_id,
719
+ display_name: entry.display_name,
720
+ adapter_class: entry.adapter_class,
721
+ recommendation: entry.promotion_recommendation && entry.promotion_recommendation.recommendation,
722
+ review_ready: entry.promotion_readiness && entry.promotion_readiness.review_ready === true,
723
+ production_default_ready: entry.promotion_readiness && entry.promotion_readiness.production_default_ready === true
724
+ }))
725
+ };
726
+ });
727
+ }
728
+
506
729
  function buildSubmissionBundleReviewWarnings(bundle) {
507
730
  const warnings = [];
508
731
  const registrationRecord = bundle && bundle.registration_record && typeof bundle.registration_record === "object"
@@ -723,6 +946,55 @@ function summarizeIntegrationPromotionReadiness(integrationOrId) {
723
946
  };
724
947
  }
725
948
 
949
+ function summarizeIntegrationPromotionWorkflow(integrationOrId) {
950
+ const summary = summarizeIntegrationPromotionReadiness(integrationOrId);
951
+ if (!summary.ok) {
952
+ return summary;
953
+ }
954
+ const readiness = clone(summary.promotion_readiness || {});
955
+ return {
956
+ ...summary,
957
+ certification_gaps: buildCertificationGapSummary(readiness, summary),
958
+ blocker_categories: summarizePromotionBlockerCategories(readiness.blockers),
959
+ next_transition: buildNextTransitionSummary(readiness),
960
+ promotion_recommendation: buildPromotionRecommendationSummary(readiness)
961
+ };
962
+ }
963
+
964
+ function summarizeIntegrationPromotionWorkflowList(filters = {}) {
965
+ const integrations = listIntegrations(filters).map((integration) => summarizeIntegrationPromotionWorkflow(integration));
966
+ const blockerCategoryEntries = integrations.flatMap((entry) => entry.blocker_categories || []);
967
+ return {
968
+ ok: true,
969
+ integration_count: integrations.length,
970
+ review_ready_count: integrations.filter((entry) => entry.promotion_readiness.review_ready).length,
971
+ production_default_ready_count: integrations.filter((entry) => entry.promotion_readiness.production_default_ready).length,
972
+ certifiable_count: integrations.filter((entry) => entry.certification_gaps.certifiable).length,
973
+ next_actions: summarizeCounts(
974
+ integrations.map((entry) => entry.next_transition.action).filter(Boolean),
975
+ "action"
976
+ ),
977
+ recommendations: summarizeCounts(
978
+ integrations.map((entry) => entry.promotion_recommendation.recommendation).filter(Boolean),
979
+ "recommendation"
980
+ ),
981
+ blocker_categories: summarizeStructuredCounts(
982
+ blockerCategoryEntries,
983
+ ["category", "severity", "owner"]
984
+ ),
985
+ owner_queue: summarizeCounts(
986
+ blockerCategoryEntries.map((entry) => entry.owner).filter(Boolean),
987
+ "owner"
988
+ ),
989
+ severity_queue: summarizeCounts(
990
+ blockerCategoryEntries.map((entry) => entry.severity).filter(Boolean),
991
+ "severity"
992
+ ),
993
+ next_action_queues: buildPromotionActionQueues(integrations),
994
+ integrations
995
+ };
996
+ }
997
+
726
998
  function buildBuiltInIntegrations() {
727
999
  const httpTaskRefs = collectTaskRefsByAdapter("http");
728
1000
  const mcpTaskRefs = collectTaskRefsByAdapter("mcp");
@@ -735,7 +1007,7 @@ function buildBuiltInIntegrations() {
735
1007
  display_name: "Built-In HTTP Execution",
736
1008
  description: "Default execution path for task and workflow lanes served directly by xytara.",
737
1009
  adapter_class: "execution_adapter",
738
- adapter_version: "1.2.0",
1010
+ adapter_version: "1.3.0",
739
1011
  interface_version: "commerce-adapter-interface/v1",
740
1012
  bundled: true,
741
1013
  source: "builtin",
@@ -798,7 +1070,7 @@ function buildBuiltInIntegrations() {
798
1070
  display_name: "Built-In MCP Protocol Lane",
799
1071
  description: "Built-in machine protocol lane for MCP tool discovery and invocation through the commerce flow.",
800
1072
  adapter_class: "agent_protocol_adapter",
801
- adapter_version: "1.2.0",
1073
+ adapter_version: "1.3.0",
802
1074
  interface_version: "commerce-adapter-interface/v1",
803
1075
  bundled: true,
804
1076
  source: "builtin",
@@ -857,7 +1129,7 @@ function buildBuiltInIntegrations() {
857
1129
  display_name: "Built-In x402 Payment Admission",
858
1130
  description: "Built-in exact-payment challenge lane for x402-style machine payment admission.",
859
1131
  adapter_class: "payment_rail_adapter",
860
- adapter_version: "1.2.0",
1132
+ adapter_version: "1.3.0",
861
1133
  interface_version: "commerce-adapter-interface/v1",
862
1134
  bundled: true,
863
1135
  source: "builtin",
@@ -916,7 +1188,7 @@ function buildBuiltInIntegrations() {
916
1188
  display_name: "Built-In Chain Settlement",
917
1189
  description: "Built-in settlement lane spanning the canonical chain-backed settlement profiles bundled in xytara.",
918
1190
  adapter_class: "settlement_adapter",
919
- adapter_version: "1.2.0",
1191
+ adapter_version: "1.3.0",
920
1192
  interface_version: "commerce-adapter-interface/v1",
921
1193
  bundled: true,
922
1194
  source: "builtin",
@@ -979,7 +1251,7 @@ function buildBuiltInIntegrations() {
979
1251
  display_name: "Built-In Registry Identity Surface",
980
1252
  description: "Built-in registry and anchoring surface used by trust, registry, and lifecycle records.",
981
1253
  adapter_class: "identity_registry_adapter",
982
- adapter_version: "1.2.0",
1254
+ adapter_version: "1.3.0",
983
1255
  interface_version: "commerce-adapter-interface/v1",
984
1256
  bundled: true,
985
1257
  source: "builtin",
@@ -1323,6 +1595,14 @@ function summarizeIntegrationSettlementModes(filters = {}) {
1323
1595
  };
1324
1596
  }
1325
1597
 
1598
+ // 1.3.0 Phase 1 anchor:
1599
+ // The next workflow layer should stay read-only and build on top of
1600
+ // summarizeIntegrationPromotionReadiness(...), adding:
1601
+ // - promotion recommendation summaries
1602
+ // - next eligible transition summaries
1603
+ // - normalized blocker categories
1604
+ // without introducing mutation flows or persistent registry state.
1605
+
1326
1606
  module.exports = {
1327
1607
  getIntegration,
1328
1608
  listIntegrations,
@@ -1349,6 +1629,8 @@ module.exports = {
1349
1629
  summarizeIntegrationSubmissionBundleSetReview,
1350
1630
  summarizeIntegrationRegistrySnapshotReview,
1351
1631
  summarizeIntegrationPromotionReadiness,
1632
+ summarizeIntegrationPromotionWorkflow,
1633
+ summarizeIntegrationPromotionWorkflowList,
1352
1634
  createRegisteredIntegrationFromManifest,
1353
1635
  buildIntegrationRegistrationView,
1354
1636
  buildIntegrationView
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xytara",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Machine commerce SDK for discovery, quoting, execution, lifecycle inspection, and adapters.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
package/server.js CHANGED
@@ -53,6 +53,8 @@ const {
53
53
  getIntegration,
54
54
  listIntegrations,
55
55
  summarizeIntegrationPromotionReadiness,
56
+ summarizeIntegrationPromotionWorkflow,
57
+ summarizeIntegrationPromotionWorkflowList,
56
58
  summarizeIntegrationRegistrySnapshotReview,
57
59
  summarizeIntegrationSubmissionBundleReview,
58
60
  summarizeIntegrationSubmissionBundleSetReview,
@@ -340,6 +342,24 @@ async function routeRequest(req, res) {
340
342
  return;
341
343
  }
342
344
 
345
+ if (req.method === "GET" && url.pathname === "/v1/integrations/promotion-workflow") {
346
+ const response = buildIntegrationListResponse({
347
+ ...summarizeIntegrationPromotionWorkflowList({
348
+ adapter_class: url.searchParams.get("class"),
349
+ protocol: url.searchParams.get("protocol"),
350
+ settlement_mode: url.searchParams.get("settlement_mode"),
351
+ capability: url.searchParams.get("capability"),
352
+ task_ref: url.searchParams.get("task_ref"),
353
+ source: url.searchParams.get("source"),
354
+ certification_state: url.searchParams.get("certification_state"),
355
+ integration_maturity: url.searchParams.get("integration_maturity"),
356
+ bundled: url.searchParams.get("bundled")
357
+ })
358
+ });
359
+ sendJson(res, response.status, response.payload);
360
+ return;
361
+ }
362
+
343
363
  if (req.method === "GET" && url.pathname.startsWith("/v1/integrations/") && url.pathname.endsWith("/promotion-readiness")) {
344
364
  const integrationId = getDecodedSuffixId(
345
365
  url.pathname.slice(0, -"/promotion-readiness".length),
@@ -352,6 +372,18 @@ async function routeRequest(req, res) {
352
372
  return;
353
373
  }
354
374
 
375
+ if (req.method === "GET" && url.pathname.startsWith("/v1/integrations/") && url.pathname.endsWith("/promotion-workflow")) {
376
+ const integrationId = getDecodedSuffixId(
377
+ url.pathname.slice(0, -"/promotion-workflow".length),
378
+ "/v1/integrations/"
379
+ );
380
+ const response = buildIntegrationListResponse(
381
+ summarizeIntegrationPromotionWorkflow(integrationId)
382
+ );
383
+ sendJson(res, response.status || 200, response.payload || response);
384
+ return;
385
+ }
386
+
355
387
  if (req.method === "GET" && url.pathname.startsWith("/v1/integrations/")) {
356
388
  const integrationId = getDecodedSuffixId(url.pathname, "/v1/integrations/");
357
389
  const response = buildIntegrationDetailResponse(getIntegration(integrationId));