pilotswarm 0.5.42 → 0.5.44

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 (111) hide show
  1. package/mcp/README.md +25 -1
  2. package/mcp/dist/src/auth.d.ts.map +1 -1
  3. package/mcp/dist/src/auth.js +5 -3
  4. package/mcp/dist/src/auth.js.map +1 -1
  5. package/mcp/dist/src/resources/models.d.ts.map +1 -1
  6. package/mcp/dist/src/resources/models.js +21 -14
  7. package/mcp/dist/src/resources/models.js.map +1 -1
  8. package/mcp/dist/src/server.d.ts.map +1 -1
  9. package/mcp/dist/src/server.js +2 -0
  10. package/mcp/dist/src/server.js.map +1 -1
  11. package/mcp/dist/src/tools/agent-packages.d.ts.map +1 -1
  12. package/mcp/dist/src/tools/agent-packages.js +28 -16
  13. package/mcp/dist/src/tools/agent-packages.js.map +1 -1
  14. package/mcp/dist/src/tools/models.d.ts.map +1 -1
  15. package/mcp/dist/src/tools/models.js +55 -47
  16. package/mcp/dist/src/tools/models.js.map +1 -1
  17. package/mcp/dist/src/tools/providers.d.ts +18 -0
  18. package/mcp/dist/src/tools/providers.d.ts.map +1 -0
  19. package/mcp/dist/src/tools/providers.js +284 -0
  20. package/mcp/dist/src/tools/providers.js.map +1 -0
  21. package/mcp/dist/src/tools/sessions.d.ts.map +1 -1
  22. package/mcp/dist/src/tools/sessions.js +10 -1
  23. package/mcp/dist/src/tools/sessions.js.map +1 -1
  24. package/mcp/dist/src/tools/system.js +2 -2
  25. package/mcp/dist/src/tools/system.js.map +1 -1
  26. package/mcp/dist/src/util/respond.d.ts.map +1 -1
  27. package/mcp/dist/src/util/respond.js +6 -0
  28. package/mcp/dist/src/util/respond.js.map +1 -1
  29. package/package.json +3 -3
  30. package/tui/README.md +8 -5
  31. package/tui/src/agents-cli.js +80 -78
  32. package/tui/src/app.js +119 -17
  33. package/tui/src/node-sdk-transport.js +150 -347
  34. package/ui/core/src/controller.js +1079 -23
  35. package/ui/core/src/reducer.js +649 -1
  36. package/ui/core/src/selectors.js +891 -6
  37. package/ui/core/src/state.js +163 -3
  38. package/ui/react/src/components.js +146 -4
  39. package/ui/react/src/web-app.js +1732 -50
  40. package/web/README.md +4 -4
  41. package/web/api/router.js +33 -0
  42. package/web/dist/assets/{abnfDiagram-VRR7QNED-Jh9nLlRI.js → abnfDiagram-VRR7QNED-67Q0WWge.js} +1 -1
  43. package/web/dist/assets/{arc-CmN4jFMW.js → arc-BvcYFngS.js} +1 -1
  44. package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-DgUSVwl7.js → architectureDiagram-ZJ3FMSHR-CPBN0rk8.js} +1 -1
  45. package/web/dist/assets/{blockDiagram-677ZJIJ3-CCJEXNgp.js → blockDiagram-677ZJIJ3-D_hp1Oah.js} +1 -1
  46. package/web/dist/assets/{c4Diagram-LMCZKHZV-DG11zUre.js → c4Diagram-LMCZKHZV-DAOVGMIW.js} +1 -1
  47. package/web/dist/assets/channel-DiW7lUT8.js +1 -0
  48. package/web/dist/assets/{chunk-2Q5K7J3B-Cl8MUWGh.js → chunk-2Q5K7J3B-DajZuaot.js} +1 -1
  49. package/web/dist/assets/{chunk-32BRIVSS-BaLutEQY.js → chunk-32BRIVSS-C6pXBsgt.js} +1 -1
  50. package/web/dist/assets/{chunk-5VM5RSS4-BOPcnMeW.js → chunk-5VM5RSS4-780edrmi.js} +1 -1
  51. package/web/dist/assets/{chunk-EX3LRPZG-bY2tdfJ2.js → chunk-EX3LRPZG-C0e4NVuz.js} +1 -1
  52. package/web/dist/assets/{chunk-JWPE2WC7-CASBfQW6.js → chunk-JWPE2WC7-uRe83I6C.js} +1 -1
  53. package/web/dist/assets/{chunk-MOJQB5TN-WrEHfiAj.js → chunk-MOJQB5TN-B0WPoPjh.js} +1 -1
  54. package/web/dist/assets/{chunk-RYQCIY6F-XQoZii_K.js → chunk-RYQCIY6F-eRFuHHyG.js} +1 -1
  55. package/web/dist/assets/{chunk-V7JOEXUC-BvA5V7VF.js → chunk-V7JOEXUC-C8FDXprk.js} +1 -1
  56. package/web/dist/assets/{chunk-VR4S4FIN-SK_jCKYo.js → chunk-VR4S4FIN-DPFpLQdB.js} +1 -1
  57. package/web/dist/assets/{chunk-XXDRQBXY-CtZZImS8.js → chunk-XXDRQBXY-CoGQOPKW.js} +1 -1
  58. package/web/dist/assets/classDiagram-OUVF2IWQ-CpAhBd5x.js +1 -0
  59. package/web/dist/assets/classDiagram-v2-EOCWNBFH-CpAhBd5x.js +1 -0
  60. package/web/dist/assets/{cose-bilkent-JH36ORCC-PRXhsdiX.js → cose-bilkent-JH36ORCC-BTBSfO5v.js} +1 -1
  61. package/web/dist/assets/{cynefin-VYW2F7L2-CzUocqvb.js → cynefin-VYW2F7L2-DgTkQEoK.js} +1 -1
  62. package/web/dist/assets/{cynefinDiagram-TSTJHNR4-DYGEqQ23.js → cynefinDiagram-TSTJHNR4-DiBMlKoP.js} +1 -1
  63. package/web/dist/assets/{dagre-VKFMJZFB-CAyb_zBo.js → dagre-VKFMJZFB-Qv-4dcbk.js} +1 -1
  64. package/web/dist/assets/{diagram-FQU43EPY-CvpXMmL-.js → diagram-FQU43EPY-CgyAb7yx.js} +1 -1
  65. package/web/dist/assets/{diagram-G47NLZAW-DBQRZJS0.js → diagram-G47NLZAW-BxN-KcGp.js} +1 -1
  66. package/web/dist/assets/{diagram-NH7WQ7WH-BGzD61gL.js → diagram-NH7WQ7WH-BiellpWz.js} +1 -1
  67. package/web/dist/assets/{diagram-OA4YK3LP-DqQf4oMW.js → diagram-OA4YK3LP-C8Ktgrwv.js} +1 -1
  68. package/web/dist/assets/{diagram-WEI45ONY-CYHoWtg7.js → diagram-WEI45ONY-Bj5K1X91.js} +1 -1
  69. package/web/dist/assets/{ebnfDiagram-CCIWWBDH-oMOMgcs8.js → ebnfDiagram-CCIWWBDH-DNQI2XT9.js} +1 -1
  70. package/web/dist/assets/{erDiagram-Q63AITRT-DaZaseAH.js → erDiagram-Q63AITRT-D5Xkllu6.js} +1 -1
  71. package/web/dist/assets/{flowDiagram-23GEKE2U-BIe9TtAL.js → flowDiagram-23GEKE2U-DJpTtMuj.js} +1 -1
  72. package/web/dist/assets/{ganttDiagram-NO4QXBWP-DitrY3hM.js → ganttDiagram-NO4QXBWP-C-EQlCJf.js} +1 -1
  73. package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-DRjIH_99.js → gitGraphDiagram-IHSO6WYX-C8vpSbvW.js} +1 -1
  74. package/web/dist/assets/index-C2ioXNJJ.js +24 -0
  75. package/web/dist/assets/index-CVYm02UI.css +1 -0
  76. package/web/dist/assets/{infoDiagram-FWYZ7A6U-BJCx4g9_.js → infoDiagram-FWYZ7A6U-CKNzsR3r.js} +1 -1
  77. package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-CLxmaTWp.js → ishikawaDiagram-FXEZZL3T-CjyQq3lf.js} +1 -1
  78. package/web/dist/assets/{journeyDiagram-5HDEW3XC-D2_VI8CC.js → journeyDiagram-5HDEW3XC-CK3EEkJt.js} +1 -1
  79. package/web/dist/assets/{kanban-definition-HUTT4EX6-DnUq9E7I.js → kanban-definition-HUTT4EX6-CHQ8YkPx.js} +1 -1
  80. package/web/dist/assets/{linear-mKMwWrAB.js → linear-CUYirs1h.js} +1 -1
  81. package/web/dist/assets/{mermaid.core-CApAWULn.js → mermaid.core-Di8sQC4g.js} +4 -4
  82. package/web/dist/assets/{mindmap-definition-LN4V7U3C-D2twxIMO.js → mindmap-definition-LN4V7U3C-D38dmHP5.js} +1 -1
  83. package/web/dist/assets/{papaparse.min-BhDLFNak.js → papaparse.min-DWBU_pXS.js} +1 -1
  84. package/web/dist/assets/{pegDiagram-2B236MQR-D2RtIeDP.js → pegDiagram-2B236MQR-BU759QCo.js} +1 -1
  85. package/web/dist/assets/{pieDiagram-ENE6RG2P-vonumKaj.js → pieDiagram-ENE6RG2P-BbpfHbsj.js} +1 -1
  86. package/web/dist/assets/pilotswarm-DrM3pXOV.js +97 -0
  87. package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-CAZL1kJH.js → quadrantDiagram-ABIIQ3AL-BYZ3XHZn.js} +1 -1
  88. package/web/dist/assets/{railroadDiagram-RFXS5EU6-CgpDomFp.js → railroadDiagram-RFXS5EU6-D18gkZBJ.js} +1 -1
  89. package/web/dist/assets/{requirementDiagram-TGXJPOKE-9B6yfsXV.js → requirementDiagram-TGXJPOKE-D6vo26Ib.js} +1 -1
  90. package/web/dist/assets/{sankeyDiagram-HTMAVEWB-B_FAnwxi.js → sankeyDiagram-HTMAVEWB-CxQwXnRE.js} +1 -1
  91. package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-BbL6OCms.js → sequenceDiagram-DBY2YBRQ-CfGisw4A.js} +1 -1
  92. package/web/dist/assets/{sizeCapture-X5ZJPWSS-DIRKFU8M.js → sizeCapture-X5ZJPWSS-BDK7-yA-.js} +1 -1
  93. package/web/dist/assets/{stateDiagram-2N3HPSRC-pUX5NF32.js → stateDiagram-2N3HPSRC-8IyidYSV.js} +1 -1
  94. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-F7qYkvpr.js +1 -0
  95. package/web/dist/assets/{swimlanes-5IMT3BWC-DO7BjQ4-.js → swimlanes-5IMT3BWC-CgNqXCvM.js} +2 -2
  96. package/web/dist/assets/swimlanesDiagram-G3AALYLV-CUKrHLkY.js +8 -0
  97. package/web/dist/assets/{timeline-definition-FHXFAJF6-BcbYRQ7s.js → timeline-definition-FHXFAJF6-DAJsGj6d.js} +1 -1
  98. package/web/dist/assets/{vennDiagram-L72KCM5P-CUt_orN5.js → vennDiagram-L72KCM5P-DDVdvG5k.js} +1 -1
  99. package/web/dist/assets/{wardleyDiagram-EHGQE667-BlUPWQdi.js → wardleyDiagram-EHGQE667-CiAs_m72.js} +1 -1
  100. package/web/dist/assets/{xychartDiagram-FW5EYKEG-CDW7A5_U.js → xychartDiagram-FW5EYKEG-D6OLJtsD.js} +1 -1
  101. package/web/dist/index.html +3 -3
  102. package/web/runtime.js +220 -2
  103. package/web/server.js +35 -7
  104. package/web/dist/assets/channel-BQBGhjIw.js +0 -1
  105. package/web/dist/assets/classDiagram-OUVF2IWQ-BIr20mVO.js +0 -1
  106. package/web/dist/assets/classDiagram-v2-EOCWNBFH-BIr20mVO.js +0 -1
  107. package/web/dist/assets/index-Cl6-pI9g.js +0 -24
  108. package/web/dist/assets/index-DRLA5aNR.css +0 -1
  109. package/web/dist/assets/pilotswarm-DETFHWYc.js +0 -97
  110. package/web/dist/assets/stateDiagram-v2-6OUMAXLB-J_okbpZN.js +0 -1
  111. package/web/dist/assets/swimlanesDiagram-G3AALYLV-gTxQyRZa.js +0 -8
@@ -17,15 +17,8 @@ import {
17
17
  ATTACHMENT_MAX_BYTES,
18
18
  ATTACHMENTS_MAX_COUNT,
19
19
  ATTACHMENTS_MAX_TOTAL_BYTES,
20
- PgSessionCatalog,
21
- publishAgentPackageDir,
22
- publishPackedAgentPackage,
23
- deleteAgentPackageEverywhere,
24
- fetchAgentPackageTarGz,
25
- readAgentPackageTarGz,
26
20
  listBundledAgentNames,
27
21
  normalizeAgentName,
28
- AgentPackageValidationError,
29
22
  } from "pilotswarm-sdk";
30
23
  import { startEmbeddedWorkers, stopEmbeddedWorkers } from "./embedded-workers.js";
31
24
  import { getPluginDirsFromEnv } from "./plugin-config.js";
@@ -542,6 +535,7 @@ export class NodeSdkTransport {
542
535
  }
543
536
  : {};
544
537
  this.client = null;
538
+ this.artifactStore = createArtifactStore();
545
539
  this.mgmt = new PilotSwarmManagementClient({
546
540
  store,
547
541
  ...(useManagedIdentity !== undefined ? { useManagedIdentity } : {}),
@@ -550,8 +544,8 @@ export class NodeSdkTransport {
550
544
  ...this.enhancedFacts,
551
545
  pluginDirs: this.pluginDirs,
552
546
  blobEnabled: Boolean(process.env.AZURE_STORAGE_ACCOUNT_URL || process.env.AZURE_STORAGE_CONNECTION_STRING),
547
+ artifactStore: this.artifactStore,
553
548
  });
554
- this.artifactStore = createArtifactStore();
555
549
  this.sessionHandles = new Map();
556
550
  this.workers = [];
557
551
  this.sessionPolicy = null;
@@ -619,10 +613,7 @@ export class NodeSdkTransport {
619
613
  this.client ? this.client.stop() : Promise.resolve(),
620
614
  this.mgmt.stop(),
621
615
  stopEmbeddedWorkers(this.workers),
622
- this._agentPkgCatalog ? this._agentPkgCatalog.close() : Promise.resolve(),
623
616
  ]);
624
- this._agentPkgCatalog = null;
625
- this._agentPkgCatalogPromise = null;
626
617
  this.client = null;
627
618
  }
628
619
 
@@ -664,13 +655,8 @@ export class NodeSdkTransport {
664
655
 
665
656
  /** Registry package agents as creatable-agent entries, viewer-scoped. */
666
657
  async _listRegistryCreatableAgents(viewer, isAdmin) {
667
- const ctx = await this._agentPackagesContext();
668
- if (!ctx) return [];
669
658
  try {
670
- const packages = await ctx.catalog.listAgentPackages(
671
- viewer ? { provider: viewer.provider, subject: viewer.subject } : null,
672
- Boolean(isAdmin),
673
- );
659
+ const packages = await this.mgmt.listAgentPackages(viewer, Boolean(isAdmin));
674
660
  // Ownership is decided HERE, where the viewer's identity is known.
675
661
  // An ADMIN sees every user's user-scoped packages, so "scope is
676
662
  // user" does not mean "mine" — grouping on scope alone filed other
@@ -748,116 +734,19 @@ export class NodeSdkTransport {
748
734
  return match.name;
749
735
  }
750
736
 
751
- /**
752
- * Lazy direct-store registry context; null in pure web/client setups AND
753
- * on init failure. A failed init is NEVER cached — the portal boots
754
- * alongside 8 workers all polling the migration advisory lock, and one
755
- * transient contention loss must not permanently reduce the catalog to
756
- * baked agents (observed live: a cached rejection made every later
757
- * listCreatableAgents union silently registry-less until pod restart).
758
- */
759
- async _agentPackagesContext() {
760
- if (!this.store || !this.artifactStore) return null;
761
- if (this._agentPkgCatalog) {
762
- return { catalog: this._agentPkgCatalog, artifactStore: this.artifactStore };
763
- }
764
- try {
765
- this._agentPkgCatalogPromise ??= (async () => {
766
- const catalog = await PgSessionCatalog.create(this.store, process.env.PILOTSWARM_CMS_SCHEMA || undefined, {
767
- ...(this.useManagedIdentity !== undefined ? { useManagedIdentity: this.useManagedIdentity } : {}),
768
- ...(this.aadDbUser ? { aadUser: this.aadDbUser } : {}),
769
- });
770
- await catalog.initialize();
771
- this._agentPkgCatalog = catalog;
772
- return catalog;
773
- })();
774
- await this._agentPkgCatalogPromise;
775
- } catch (err) {
776
- this._agentPkgCatalogPromise = null;
777
- console.warn(`[transport] agent-package registry init failed (will retry on next call): ${err?.message || err}`);
778
- return null;
779
- }
780
- return { catalog: this._agentPkgCatalog, artifactStore: this.artifactStore };
781
- }
782
-
783
- _requirePrincipal(owner, isAdmin) {
784
- // Shape-checked, not just truthy: the portal runtime always passes a
785
- // real principal here, but a caller that skips the owner/isAdmin args
786
- // (direct-mode TUI) must fail closed with this clear error — never
787
- // flow a garbage object into the registry as an identity.
788
- if (owner && typeof owner.provider === "string" && typeof owner.subject === "string") {
789
- return { provider: owner.provider, subject: owner.subject };
790
- }
791
- if (isAdmin) return null; // anonymous deployments: admin-equivalent
792
- const err = new Error("agent-package operations require an authenticated principal");
793
- err.code = "FORBIDDEN";
794
- throw err;
795
- }
796
-
797
- _createdByLabel(owner) {
798
- return owner?.email || owner?.displayName || (owner ? `${owner.provider}:${owner.subject}` : "system");
799
- }
800
-
801
- /**
802
- * The registry raises typed failures as MESSAGE PREFIXES
803
- * (AGENT_PACKAGE_FORBIDDEN: …). Attach the matching error.code so the
804
- * router maps them to 403/404/409 instead of a generic 500 — without
805
- * this, "you don't own this package" reaches the browser as
806
- * "Internal server error".
807
- */
808
- async _mapAgentPackageErrors(run) {
809
- try {
810
- return await run();
811
- } catch (error) {
812
- const message = String(error?.message || "");
813
- if (!error?.code) {
814
- if (/AGENT_(?:PACKAGE|SOURCE)_[A-Z_]*FORBIDDEN/.test(message)) error.code = "FORBIDDEN";
815
- else if (/AGENT_(?:PACKAGE|SOURCE)_[A-Z_]*NOT_FOUND/.test(message)) error.code = "NOT_FOUND";
816
- else if (/AGENT_PACKAGE_(?:SEMVER_CONFLICT|SCOPE_MISMATCH)/.test(message)) error.code = "CONFLICT";
817
- else if (/AGENT_PACKAGE_BAD_SCOPE/.test(message)) error.code = "INVALID_REQUEST";
818
- }
819
- throw error;
820
- }
821
- }
822
-
823
737
  // ── Agent packages: registry CRUD (portal ops surface) ──────
824
738
 
825
- async listAgentPackages(owner, isAdmin) {
826
- const ctx = await this._agentPackagesContext();
827
- if (!ctx) return [];
828
- return ctx.catalog.listAgentPackages(this._requirePrincipal(owner, isAdmin), Boolean(isAdmin));
829
- }
830
-
831
- /**
832
- * Normalize wire selector params ({scope, ownerProvider, ownerSubject})
833
- * into the catalog's AgentPackageSelector — which same-named copy an op
834
- * means. Authorization is NOT decided here: the registry procs re-check
835
- * ownership against the RESOLVED row, so a non-admin naming someone
836
- * else's copy still gets FORBIDDEN/invisible from the database.
837
- */
838
- _packageSelector(selector, isAdmin = false) {
839
- if (!selector || typeof selector !== "object") return null;
840
- const scope = selector.scope === "shared" || selector.scope === "user" ? selector.scope : null;
841
- const provider = typeof selector.ownerProvider === "string" && selector.ownerProvider.trim() ? selector.ownerProvider.trim() : null;
842
- const subject = typeof selector.ownerSubject === "string" && selector.ownerSubject.trim() ? selector.ownerSubject.trim() : null;
843
- // The owner override targets ANOTHER user's copy, which only an admin
844
- // may do. For a non-admin it is dropped, NOT honored-then-denied:
845
- // resolving a foreign package and letting the proc answer FORBIDDEN vs
846
- // NOT_FOUND would be an existence oracle. Dropped, a non-admin's
847
- // selector falls back to own-then-shared resolution, which can only
848
- // ever reach their own or shared packages.
849
- const owner = isAdmin && provider && subject ? { provider, subject } : null;
850
- if (!scope && !owner) return null;
851
- return {
852
- ...(scope ? { scope } : {}),
853
- ...(owner ? { owner } : {}),
854
- };
739
+ async listAgentPackages(owner = this.currentUser, isAdmin = true) {
740
+ return this.mgmt.listAgentPackages(owner, Boolean(isAdmin));
855
741
  }
856
742
 
857
743
  async getAgentPackage(name, owner, isAdmin, selector = null) {
858
- const ctx = await this._agentPackagesContext();
859
- if (!ctx) return null;
860
- return ctx.catalog.getAgentPackage(name, this._requirePrincipal(owner, isAdmin), Boolean(isAdmin), this._packageSelector(selector, Boolean(isAdmin)));
744
+ if (arguments.length <= 2) {
745
+ selector = owner ?? null;
746
+ owner = this.currentUser;
747
+ isAdmin = true;
748
+ }
749
+ return this.mgmt.getAgentPackage(name, owner, Boolean(isAdmin), selector);
861
750
  }
862
751
 
863
752
 
@@ -865,68 +754,47 @@ export class NodeSdkTransport {
865
754
 
866
755
 
867
756
  async listAgentWorkerState() {
868
- const ctx = await this._agentPackagesContext();
869
- if (!ctx) return [];
870
- return ctx.catalog.listAgentWorkerState();
757
+ return this.mgmt.listAgentWorkerState();
871
758
  }
872
759
 
873
760
  async listWorkers() {
874
- const ctx = await this._agentPackagesContext();
875
- if (!ctx) return [];
876
- return ctx.catalog.listWorkers();
761
+ return this.mgmt.listWorkers();
877
762
  }
878
763
 
879
764
  async setAgentPackageScope(name, scope, owner, isAdmin, selector = null) {
880
- const ctx = await this._agentPackagesContext();
881
- if (!ctx) throw new Error("agent packages are not available on this deployment");
882
- const targetScope = scope === "shared" ? "shared" : "user";
883
- const ownerOverride = this._packageSelector(selector, Boolean(isAdmin))?.owner ?? null;
884
- // The SOURCE copy is implied by the direction, but the two directions
885
- // need different selectors — and passing an explicit scope selector
886
- // DISABLES the SQL admin/NULL-owner fallback (it fires only when the
887
- // selector scope is NULL), so name-only is used wherever it resolves
888
- // correctly:
889
- // demote (target user): must move the globally-unique SHARED copy,
890
- // so select scope 'shared' explicitly — the shared row is unique,
891
- // no owner fallback is needed to find it.
892
- // promote (target shared): ordinary own-copy-then-shared resolution
893
- // already lands on the caller's own USER copy, and keeping the
894
- // selector NULL preserves the admin/NULL-owner fallback for
895
- // packages minted without an owner. An admin acting on ANOTHER
896
- // user's copy passes that owner explicitly.
897
- let sourceSelector = null;
898
- if (targetScope === "user") {
899
- sourceSelector = { scope: "shared", ...(ownerOverride ? { owner: ownerOverride } : {}) };
900
- } else if (ownerOverride) {
901
- sourceSelector = { scope: "user", owner: ownerOverride };
902
- }
903
- await this._mapAgentPackageErrors(() => ctx.catalog.setAgentPackageScope(name, targetScope,
904
- this._requirePrincipal(owner, isAdmin), Boolean(isAdmin), sourceSelector));
905
- return { ok: true };
765
+ if (arguments.length <= 3) {
766
+ selector = owner ?? null;
767
+ owner = this.currentUser;
768
+ isAdmin = true;
769
+ }
770
+ return this.mgmt.setAgentPackageScope(name, scope, owner, Boolean(isAdmin), selector);
906
771
  }
907
772
 
908
773
  async setAgentPackageEnabled(name, enabled, owner, isAdmin, selector = null) {
909
- const ctx = await this._agentPackagesContext();
910
- if (!ctx) throw new Error("agent packages are not available on this deployment");
911
- await this._mapAgentPackageErrors(() => ctx.catalog.setAgentPackageEnabled(name, Boolean(enabled),
912
- this._requirePrincipal(owner, isAdmin), Boolean(isAdmin), this._packageSelector(selector, Boolean(isAdmin))));
913
- return { ok: true };
774
+ if (arguments.length <= 3) {
775
+ selector = owner ?? null;
776
+ owner = this.currentUser;
777
+ isAdmin = true;
778
+ }
779
+ return this.mgmt.setAgentPackageEnabled(name, enabled, owner, Boolean(isAdmin), selector);
914
780
  }
915
781
 
916
782
  async pinAgentPackageVersion(name, semver, owner, isAdmin, selector = null) {
917
- const ctx = await this._agentPackagesContext();
918
- if (!ctx) throw new Error("agent packages are not available on this deployment");
919
- await this._mapAgentPackageErrors(() => ctx.catalog.pinAgentPackageVersion(name, String(semver || ""),
920
- this._requirePrincipal(owner, isAdmin), Boolean(isAdmin), this._packageSelector(selector, Boolean(isAdmin))));
921
- return { ok: true };
783
+ if (arguments.length <= 3) {
784
+ selector = owner ?? null;
785
+ owner = this.currentUser;
786
+ isAdmin = true;
787
+ }
788
+ return this.mgmt.pinAgentPackageVersion(name, semver, owner, Boolean(isAdmin), selector);
922
789
  }
923
790
 
924
791
  async deleteAgentPackage(name, owner, isAdmin, selector = null) {
925
- const ctx = await this._agentPackagesContext();
926
- if (!ctx) throw new Error("agent packages are not available on this deployment");
927
- await this._mapAgentPackageErrors(() => deleteAgentPackageEverywhere(ctx, name, this._requirePrincipal(owner, isAdmin), Boolean(isAdmin), this._packageSelector(selector, Boolean(isAdmin))));
928
- this._agentPkgTarCache?.clear?.();
929
- return { ok: true };
792
+ if (arguments.length <= 2) {
793
+ selector = owner ?? null;
794
+ owner = this.currentUser;
795
+ isAdmin = true;
796
+ }
797
+ return this.mgmt.deleteAgentPackage(name, owner, Boolean(isAdmin), selector);
930
798
  }
931
799
 
932
800
  /**
@@ -936,88 +804,29 @@ export class NodeSdkTransport {
936
804
  * promote MOVES a row and refuses when the shared name already exists;
937
805
  * this adds a version to it instead.
938
806
  */
939
- async republishAgentPackageVersion(name, semver, targetScope, owner, isAdmin) {
940
- const ctx = await this._agentPackagesContext();
941
- if (!ctx) throw new Error("agent packages are not available on this deployment");
942
- const principal = this._requirePrincipal(owner, isAdmin);
943
- const target = targetScope === "shared" ? "shared" : "user";
944
- const sourceScope = target === "shared" ? "user" : "shared";
945
- return await this._mapAgentPackageErrors(async () => {
946
- const detail = await ctx.catalog.getAgentPackage(name, principal, Boolean(isAdmin), { scope: sourceScope });
947
- if (!detail) {
948
- const err = new Error(`AGENT_PACKAGE_NOT_FOUND: no ${sourceScope}-scope package named "${name}" to republish from`);
949
- throw err;
950
- }
951
- const wanted = String(semver || "").trim();
952
- const version = wanted
953
- ? detail.versions.find((v) => v.semver === wanted)
954
- : detail.versions.find((v) => v.versionId === detail.activeVersionId) ?? detail.versions[0];
955
- if (!version) {
956
- throw new Error(`AGENT_PACKAGE_VERSION_NOT_FOUND: ${name}@${wanted || "(active)"} is not a published ${sourceScope} version`);
957
- }
958
- const targz = await fetchAgentPackageTarGz(ctx.artifactStore, version.artifactFilename, version.sha256);
959
- const outcome = await publishPackedAgentPackage(ctx, {
960
- manifest: version.manifest,
961
- targz,
962
- sha256: version.sha256,
963
- scope: target,
964
- owner: principal,
965
- createdBy: `${this._createdByLabel(owner)} (republish of ${sourceScope} ${name}@${version.semver})`,
966
- isAdmin: Boolean(isAdmin),
967
- });
968
- const { manifest: _m, ...summary } = outcome;
969
- return summary;
807
+ async republishAgentPackageVersion(name, semver, targetScope, owner, isAdmin, opts = {}) {
808
+ if (arguments.length <= 4) {
809
+ opts = { selector: owner ?? null };
810
+ owner = this.currentUser;
811
+ isAdmin = true;
812
+ }
813
+ return this.mgmt.republishAgentPackageVersion(name, semver, targetScope, owner, Boolean(isAdmin), {
814
+ createdBy: opts.createdBy || owner?.email || owner?.displayName
815
+ || (owner?.provider && owner?.subject ? `${owner.provider}:${owner.subject}` : "system"),
816
+ selector: opts.selector ?? null,
970
817
  });
971
818
  }
972
819
 
973
820
  /** Inline-files upload → the one publish pipeline. ≤ 2 MB decoded. */
974
821
  async uploadAgentPackage(files, scope, owner, isAdmin) {
975
- const ctx = await this._agentPackagesContext();
976
- if (!ctx) throw new Error("agent packages are not available on this deployment");
977
- const principal = this._requirePrincipal(owner, isAdmin);
978
- if (!Array.isArray(files) || files.length === 0) {
979
- throw new Error("upload requires files: [{ path, contentBase64 }]");
980
- }
981
- if (files.length > 2000) throw new Error("upload exceeds 2000 files");
982
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "ps-agent-upload-"));
983
- try {
984
- let total = 0;
985
- for (const file of files) {
986
- const rel = String(file?.path || "");
987
- if (!rel || rel.startsWith("/") || rel.includes("\\") || rel.split("/").some((p) => p === "..")) {
988
- throw new Error(`upload file path is not a safe relative path: ${rel}`);
989
- }
990
- const bytes = Buffer.from(String(file?.contentBase64 || ""), "base64");
991
- total += bytes.length;
992
- if (total > 2 * 1024 * 1024) throw new Error("upload exceeds the 2 MB envelope — use a repo/url source or the CLI for larger packages");
993
- const target = path.resolve(tmp, rel);
994
- if (target !== tmp && !target.startsWith(tmp + path.sep)) {
995
- throw new Error(`upload file path escapes the package root: ${rel}`);
996
- }
997
- fs.mkdirSync(path.dirname(target), { recursive: true });
998
- fs.writeFileSync(target, bytes);
999
- }
1000
- const outcome = await this._mapAgentPackageErrors(() => publishAgentPackageDir(ctx, {
1001
- dir: tmp,
1002
- scope: scope === "shared" ? "shared" : "user",
1003
- owner: principal,
1004
- createdBy: this._createdByLabel(owner),
1005
- isAdmin: Boolean(isAdmin),
1006
- validate: { reservedAgentNames: this._reservedAgentNames() },
1007
- }));
1008
- const { manifest: _m, ...summary } = outcome;
1009
- return summary;
1010
- } catch (err) {
1011
- if (err instanceof AgentPackageValidationError) {
1012
- const wrapped = new Error(err.message);
1013
- wrapped.code = "VALIDATION_FAILED";
1014
- wrapped.validation = err.validation;
1015
- throw wrapped;
1016
- }
1017
- throw err;
1018
- } finally {
1019
- fs.rmSync(tmp, { recursive: true, force: true });
822
+ if (arguments.length <= 2) {
823
+ owner = this.currentUser;
824
+ isAdmin = true;
1020
825
  }
826
+ return this.mgmt.uploadAgentPackage(files, scope, owner, Boolean(isAdmin), {
827
+ createdBy: owner?.email || owner?.displayName || undefined,
828
+ reservedAgentNames: this._reservedAgentNames(),
829
+ });
1021
830
  }
1022
831
 
1023
832
  _reservedAgentNames() {
@@ -1036,76 +845,31 @@ export class NodeSdkTransport {
1036
845
  return this._reservedNamesCache;
1037
846
  }
1038
847
 
1039
- // ── Agent packages: workspace viewer (tree + file preview) ──
1040
-
1041
- async _agentPackageEntries(name, semver, owner, isAdmin, selector = null) {
1042
- const ctx = await this._agentPackagesContext();
1043
- if (!ctx) throw new Error("agent packages are not available on this deployment");
1044
- const detail = await ctx.catalog.getAgentPackage(name, this._requirePrincipal(owner, isAdmin), Boolean(isAdmin), this._packageSelector(selector, Boolean(isAdmin)));
1045
- if (!detail) throw Object.assign(new Error(`package "${name}" not found`), { code: "NOT_FOUND" });
1046
- const version = semver
1047
- ? detail.versions.find((v) => v.semver === semver)
1048
- : detail.versions.find((v) => v.versionId === detail.activeVersionId) ?? detail.versions[0];
1049
- if (!version) throw Object.assign(new Error(`package "${name}" has no ${semver ? `version ${semver}` : "versions"}`), { code: "NOT_FOUND" });
1050
- const cacheKey = `${name}@${version.semver}.${version.sha256.slice(0, 12)}`;
1051
- this._agentPkgTarCache ??= new Map();
1052
- let entries = this._agentPkgTarCache.get(cacheKey);
1053
- if (!entries) {
1054
- const targz = await this._mapAgentPackageErrors(
1055
- () => fetchAgentPackageTarGz(ctx.artifactStore, version.artifactFilename, version.sha256),
1056
- );
1057
- entries = readAgentPackageTarGz(targz);
1058
- this._agentPkgTarCache.set(cacheKey, entries);
1059
- // Bound by BYTES (the real resource), not just entry count.
1060
- const bytesOf = (list) => list.reduce((sum, e) => sum + e.body.length, 0);
1061
- let totalBytes = 0;
1062
- for (const cached of this._agentPkgTarCache.values()) totalBytes += bytesOf(cached);
1063
- while ((totalBytes > 64 * 1024 * 1024 || this._agentPkgTarCache.size > 6)
1064
- && this._agentPkgTarCache.size > 1) {
1065
- const oldest = this._agentPkgTarCache.keys().next().value;
1066
- totalBytes -= bytesOf(this._agentPkgTarCache.get(oldest));
1067
- this._agentPkgTarCache.delete(oldest);
1068
- }
848
+ async getAgentPackageTree(name, semver, owner, isAdmin, selector = null) {
849
+ if (arguments.length <= 3) {
850
+ selector = owner ?? null;
851
+ owner = this.currentUser;
852
+ isAdmin = true;
1069
853
  }
1070
- return { entries, version };
854
+ return this.mgmt.getAgentPackageTree(name, semver, owner, Boolean(isAdmin), selector);
1071
855
  }
1072
856
 
1073
- async getAgentPackageTree(name, semver, owner, isAdmin, selector = null) {
1074
- const { entries, version } = await this._agentPackageEntries(name, semver, owner, isAdmin, selector);
1075
- const dirs = new Set();
1076
- const files = [];
1077
- for (const entry of entries) {
1078
- files.push({ path: entry.name, size: entry.body.length });
1079
- const parts = entry.name.split("/");
1080
- for (let i = 1; i < parts.length; i++) dirs.add(parts.slice(0, i).join("/"));
1081
- }
1082
- files.sort((a, b) => (a.path < b.path ? -1 : 1));
1083
- return {
1084
- name,
1085
- semver: version.semver,
1086
- sha256: version.sha256,
1087
- dirs: [...dirs].sort(),
1088
- files,
1089
- };
857
+ async getAgentPackageFile(name, semver, filePath, owner, isAdmin, selector = null) {
858
+ if (arguments.length <= 4) {
859
+ selector = owner ?? null;
860
+ owner = this.currentUser;
861
+ isAdmin = true;
862
+ }
863
+ return this.mgmt.getAgentPackageFile(name, semver, filePath, owner, Boolean(isAdmin), selector);
1090
864
  }
1091
865
 
1092
- async getAgentPackageFile(name, semver, filePath, owner, isAdmin, selector = null) {
1093
- const { entries, version } = await this._agentPackageEntries(name, semver, owner, isAdmin, selector);
1094
- const rel = String(filePath || "");
1095
- const entry = entries.find((candidate) => candidate.name === rel);
1096
- if (!entry) throw Object.assign(new Error(`"${rel}" is not in ${name}@${version.semver}`), { code: "NOT_FOUND" });
1097
- const MAX_PREVIEW = 256 * 1024;
1098
- const body = entry.body.subarray(0, MAX_PREVIEW);
1099
- const isBinary = body.includes(0);
1100
- return {
1101
- name,
1102
- semver: version.semver,
1103
- path: rel,
1104
- size: entry.body.length,
1105
- truncated: entry.body.length > MAX_PREVIEW,
1106
- encoding: isBinary ? "base64" : "utf8",
1107
- content: isBinary ? body.toString("base64") : body.toString("utf8"),
1108
- };
866
+ async downloadAgentPackage(name, semver, owner, isAdmin, selector = null) {
867
+ if (arguments.length <= 3) {
868
+ selector = owner ?? null;
869
+ owner = this.currentUser;
870
+ isAdmin = true;
871
+ }
872
+ return this.mgmt.downloadAgentPackage(name, semver, owner, Boolean(isAdmin), selector);
1109
873
  }
1110
874
 
1111
875
  getWorkerCount() {
@@ -1525,40 +1289,16 @@ export class NodeSdkTransport {
1525
1289
  }
1526
1290
 
1527
1291
  async assertSessionModelCreatable({ model, owner } = {}) {
1528
- const effectiveModel = model || this.mgmt.getDefaultModel();
1529
- if (!effectiveModel || typeof this.mgmt.getModelCredentialStatus !== "function") return effectiveModel;
1530
-
1531
- const credentialStatus = this.mgmt.getModelCredentialStatus(effectiveModel);
1532
- if (credentialStatus.providerType !== "github") return effectiveModel;
1533
- if (credentialStatus.credentialAvailable) return effectiveModel;
1534
-
1535
- const principal = owner ? normalizeUserPrincipal(owner) : resolveUserPrincipalFor(this, null);
1536
- const profile = principal
1537
- ? await this.mgmt.getUserProfile(principal).catch(() => null)
1538
- : null;
1539
- if (profile?.githubCopilotKeySet === true) return effectiveModel;
1540
-
1541
- // The caller never picked this Copilot model — it came from the
1542
- // catalog default. Fall back to the first non-Copilot model instead
1543
- // of failing a session the user has no key for.
1544
- if (!model && typeof this.mgmt.listModels === "function") {
1545
- const fallback = (this.mgmt.listModels() || [])
1546
- .find((entry) => entry?.providerType !== "github" && entry?.qualifiedName);
1547
- if (fallback) return fallback.qualifiedName;
1548
- }
1549
-
1550
- throw Object.assign(
1551
- new Error(
1552
- "GitHub Copilot key missing or invalid. Set GITHUB_TOKEN on the worker or configure your per-user GitHub Copilot key in Admin before using GitHub Copilot models.",
1553
- ),
1554
- { code: "GHCP_KEY_MISSING", status: 400 },
1555
- );
1292
+ // Compatibility method retained for callers/tests. It deliberately
1293
+ // does not resolve, default, or substitute a model: PilotSwarmClient
1294
+ // is the trusted authority that joins provider scope, credentials and
1295
+ // defaults, then stamps the exact model before orchestration starts.
1296
+ return model || null;
1556
1297
  }
1557
1298
 
1558
1299
  async createSession({ model, reasoningEffort, contextTier, owner, groupId, visibility } = {}) {
1559
- const effectiveModel = await this.assertSessionModelCreatable({ model, owner });
1560
1300
  const session = await this.client.createSession({
1561
- ...(effectiveModel ? { model: effectiveModel } : {}),
1301
+ ...(model ? { model } : {}),
1562
1302
  ...(reasoningEffort ? { reasoningEffort } : {}),
1563
1303
  ...(contextTier ? { contextTier } : {}),
1564
1304
  ...(owner ? { owner } : {}),
@@ -1566,7 +1306,13 @@ export class NodeSdkTransport {
1566
1306
  ...(visibility ? { visibility } : {}),
1567
1307
  });
1568
1308
  this.sessionHandles.set(session.sessionId, session);
1569
- return { sessionId: session.sessionId, model: effectiveModel, reasoningEffort: reasoningEffort || undefined, contextTier: contextTier || undefined };
1309
+ const created = await this.mgmt.getSession(session.sessionId).catch(() => null);
1310
+ return {
1311
+ sessionId: session.sessionId,
1312
+ model: created?.model || null,
1313
+ reasoningEffort: created?.reasoningEffort || reasoningEffort || undefined,
1314
+ contextTier: created?.contextTier || contextTier || undefined,
1315
+ };
1570
1316
  }
1571
1317
 
1572
1318
  async createSessionForAgent(agentName, { model, reasoningEffort, contextTier, title, splash, splashMobile, initialPrompt, owner, isAdmin, groupId, visibility } = {}) {
@@ -1575,9 +1321,8 @@ export class NodeSdkTransport {
1575
1321
  // CANONICAL catalog name (the client's allowlist and the CMS row use
1576
1322
  // exact names; only the worker resolver is fuzzy).
1577
1323
  const canonicalName = await this._authorizePackageAgentCreate(agentName, owner ?? null, isAdmin ?? false);
1578
- const effectiveModel = await this.assertSessionModelCreatable({ model, owner });
1579
1324
  const session = await this.client.createSessionForAgent(canonicalName, {
1580
- ...(effectiveModel ? { model: effectiveModel } : {}),
1325
+ ...(model ? { model } : {}),
1581
1326
  ...(reasoningEffort ? { reasoningEffort } : {}),
1582
1327
  ...(contextTier ? { contextTier } : {}),
1583
1328
  ...(title ? { title } : {}),
@@ -1589,10 +1334,11 @@ export class NodeSdkTransport {
1589
1334
  ...(visibility ? { visibility } : {}),
1590
1335
  });
1591
1336
  this.sessionHandles.set(session.sessionId, session);
1337
+ const created = await this.mgmt.getSession(session.sessionId).catch(() => null);
1592
1338
  return {
1593
1339
  sessionId: session.sessionId,
1594
- model: effectiveModel,
1595
- reasoningEffort: reasoningEffort || undefined,
1340
+ model: created?.model || null,
1341
+ reasoningEffort: created?.reasoningEffort || reasoningEffort || undefined,
1596
1342
  agentName,
1597
1343
  };
1598
1344
  }
@@ -1747,8 +1493,65 @@ export class NodeSdkTransport {
1747
1493
  await this.mgmt.deleteSessionGroup(groupId);
1748
1494
  }
1749
1495
 
1750
- async listModels() {
1751
- return this.mgmt.listModels();
1496
+ async listModels(viewer = undefined) {
1497
+ const hasExplicitViewer = viewer && typeof viewer === "object"
1498
+ && Object.prototype.hasOwnProperty.call(viewer, "principal");
1499
+ const resolvedViewer = hasExplicitViewer ? viewer : await this._modelProviderViewer();
1500
+ return await this.mgmt.listRuntimeModels(resolvedViewer);
1501
+ }
1502
+
1503
+ async _modelProviderViewer() {
1504
+ const principal = resolveUserPrincipalFor(this, null);
1505
+ const profile = await this.mgmt.getUserProfile(principal).catch(() => null);
1506
+ return { principal, isAdmin: Boolean(profile?.isAdmin) };
1507
+ }
1508
+
1509
+ async listProviders() {
1510
+ return this.mgmt.listProviders(await this._modelProviderViewer());
1511
+ }
1512
+
1513
+ async getModelDefaults() {
1514
+ return this.mgmt.getModelDefaults(await this._modelProviderViewer());
1515
+ }
1516
+
1517
+ async createProvider(input) {
1518
+ return this.mgmt.createProvider(await this._modelProviderViewer(), input || {});
1519
+ }
1520
+
1521
+ async createMyProvider(input) {
1522
+ return this.mgmt.createMyProvider(await this._modelProviderViewer(), input || {});
1523
+ }
1524
+
1525
+ async deleteProvider(name) {
1526
+ return this.mgmt.deleteProvider(await this._modelProviderViewer(), name);
1527
+ }
1528
+
1529
+ async deleteMyProvider(name) {
1530
+ return this.mgmt.deleteMyProvider(await this._modelProviderViewer(), name);
1531
+ }
1532
+
1533
+ async clearProviderRoutingDependencies(name) {
1534
+ return this.mgmt.clearProviderRoutingDependencies(await this._modelProviderViewer(), name);
1535
+ }
1536
+
1537
+ async setModelDefault(input) {
1538
+ return this.mgmt.setModelDefault(await this._modelProviderViewer(), input || {});
1539
+ }
1540
+
1541
+ async setProviderSystemUse(input) {
1542
+ return this.mgmt.setProviderSystemUse(await this._modelProviderViewer(), input || {});
1543
+ }
1544
+
1545
+ async setSystemModelDefault(input) {
1546
+ return this.mgmt.setSystemModelDefault(await this._modelProviderViewer(), input || {});
1547
+ }
1548
+
1549
+ async setSystemSessionModel(input) {
1550
+ return this.mgmt.setSystemSessionModel(await this._modelProviderViewer(), input || {});
1551
+ }
1552
+
1553
+ async clearSystemSessionModel(agentId) {
1554
+ return this.mgmt.clearSystemSessionModel(await this._modelProviderViewer(), agentId);
1752
1555
  }
1753
1556
 
1754
1557
  async listArtifacts(sessionId) {