@camstack/addon-admin-ui 1.1.39 → 1.1.40

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 (89) hide show
  1. package/dist/assets/{AddLocationWizard-C6d7Rl2b.js → AddLocationWizard-DH1zgXau.js} +1 -1
  2. package/dist/assets/AddonCollectionPage-C8P99b0n.js +1 -0
  3. package/dist/assets/Addons-ql4qAeON.js +1 -0
  4. package/dist/assets/{AdminTabs-B163y6NF.js → AdminTabs-BFmViSgF.js} +1 -1
  5. package/dist/assets/{BrokerForm-Blc6VNTn.js → BrokerForm-ClAXJAT9.js} +1 -1
  6. package/dist/assets/{Capabilities-CMoqY-Ug.js → Capabilities-BUUnmipR.js} +1 -1
  7. package/dist/assets/{CapabilityBadges-khS3I08e.js → CapabilityBadges-DJ4Ez0Qj.js} +1 -1
  8. package/dist/assets/Cluster-_sIDv3Dx.js +1 -0
  9. package/dist/assets/{Dashboard-BUIPjBAI.js → Dashboard-DkWFR-RK.js} +1 -1
  10. package/dist/assets/Data-B9S8aoV6.js +1 -0
  11. package/dist/assets/{DetectionIntelligence-BWjYUpoc.js → DetectionIntelligence-Db0D7-gq.js} +1 -1
  12. package/dist/assets/DeviceDetail-MyRno8pF.js +2 -0
  13. package/dist/assets/{Devices-BI0K3L20.js → Devices-CYdjYNMa.js} +1 -1
  14. package/dist/assets/{EmbedPlayerPage-DTJcJ-K0.js → EmbedPlayerPage-BxhfuZxm.js} +1 -1
  15. package/dist/assets/{FormBuilder-Dq7rzw2g.js → FormBuilder-CzGQp2IN.js} +1 -1
  16. package/dist/assets/{Identity-BClKA5CP.js → Identity-VBuwkiW_.js} +1 -1
  17. package/dist/assets/IntegrationDetail-Bv6r0j-e.js +1 -0
  18. package/dist/assets/{Integrations-BqqLAeN1.js → Integrations-34-SopSE.js} +1 -1
  19. package/dist/assets/Integrations-VR6uvQtU.js +1 -0
  20. package/dist/assets/{Logs-CBR7x9NW.js → Logs-Bd6dsQiy.js} +1 -1
  21. package/dist/assets/{MotionZonesSettings-BzuwNLPu.js → MotionZonesSettings-CblR7zDg.js} +1 -1
  22. package/dist/assets/MyAccess-D9wXYE6f.js +2 -0
  23. package/dist/assets/Network-B4UJnXGJ.js +1 -0
  24. package/dist/assets/{NodeAddonsSettingsPanel-DLEbHtxx.js → NodeAddonsSettingsPanel-DTo_3cuU.js} +1 -1
  25. package/dist/assets/{NotificationTargets-BiiLAuNs.js → NotificationTargets-BgoTGaHZ.js} +1 -1
  26. package/dist/assets/Pipeline-0vYb0c3Q.js +1 -0
  27. package/dist/assets/{PrivacyMaskSettings-B86k8eCd.js → PrivacyMaskSettings-BvyW7gZf.js} +1 -1
  28. package/dist/assets/ProviderIcon-CS5qVLX5.js +1 -0
  29. package/dist/assets/{ScanNetworkModal-DVZ-75GA.js → ScanNetworkModal-D8l7vvfO.js} +1 -1
  30. package/dist/assets/ServerManagement-CU7yGbqi.js +1 -0
  31. package/dist/assets/{Settings-EwkM7qrL.js → Settings-afXspnHv.js} +1 -1
  32. package/dist/assets/{Showroom-ByaFbcYn.js → Showroom-ByFNrd3B.js} +1 -1
  33. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CJNw3KPL.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DmurZU5p.js} +1 -1
  34. package/dist/assets/{build-cluster-graph-QwpFUUjE.js → build-cluster-graph-BPT-sggI.js} +2 -2
  35. package/dist/assets/circle-check-big-CTwHEGsR.js +1 -0
  36. package/dist/assets/{copy-BwUimuA-.js → copy-Dyvl96ei.js} +1 -1
  37. package/dist/assets/dist-ClgrIx6c.js +7 -0
  38. package/dist/assets/{dist-DAY4wmmI.js → dist-Udv3GGFK.js} +1 -1
  39. package/dist/assets/{download-DDSz9DfI.js → download-BFNY5_CW.js} +1 -1
  40. package/dist/assets/{hostInit-8o1E_qzk.js → hostInit-CagYACyE.js} +1 -1
  41. package/dist/assets/index-3DCschCe.js +4 -0
  42. package/dist/assets/{index-DufitHjX.css → index-BNTiPmxL.css} +1 -1
  43. package/dist/assets/{key-round-DH-NOckT.js → key-round-Bi4e5-k8.js} +1 -1
  44. package/dist/assets/{mf-entry-bootstrap-0-a41549da.js → mf-entry-bootstrap-0-b7b22ad0.js} +2 -2
  45. package/dist/assets/{pencil-D-LLTb5E.js → pencil-DedPunTk.js} +1 -1
  46. package/dist/assets/{player-overlays-2Q1miaEN.js → player-overlays-BrMuuVRR.js} +1 -1
  47. package/dist/assets/plus-r3Kz9Nsb.js +1 -0
  48. package/dist/assets/{radio-DqOn-16x.js → radio-BM7T2fMm.js} +1 -1
  49. package/dist/assets/{refresh-cw-DuM6oiTl.js → refresh-cw-CC8OysCP.js} +1 -1
  50. package/dist/assets/remoteEntry-D9u56wxx.js +1 -0
  51. package/dist/assets/{rotate-ccw-AVemYpzI.js → rotate-ccw-hTTLi20Q.js} +1 -1
  52. package/dist/assets/rotate-cw-BHsfPq8X.js +1 -0
  53. package/dist/assets/search-GJrj432A.js +1 -0
  54. package/dist/assets/{sparkles-UVx0u2KJ.js → sparkles-DURbj_l0.js} +1 -1
  55. package/dist/assets/square-DXUXUdD9.js +1 -0
  56. package/dist/assets/{square-check-big-BUD8eXmE.js → square-check-big-B5WFnMH6.js} +1 -1
  57. package/dist/assets/src-D5vrhmeM.js +7 -0
  58. package/dist/assets/src-ojhqTnBF.js +67 -0
  59. package/dist/assets/{upload-B9TkBT8Q.js → upload-DM5RHvd4.js} +1 -1
  60. package/dist/assets/{useDevice-Dt2O2ZfS.js → useDevice-BQkNwlm7.js} +1 -1
  61. package/dist/assets/{useEventInvalidation-UIA6NlSS.js → useEventInvalidation-BBDMvWpm.js} +1 -1
  62. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CsRvw1py.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-BbV1VRd0.js} +2 -2
  63. package/dist/assets/{wifi-C2e4NNeF.js → wifi-Cr9H7WCZ.js} +1 -1
  64. package/dist/assets/{zap-C-u-esEw.js → zap-BWxQNiSd.js} +1 -1
  65. package/dist/index.html +6 -6
  66. package/dist/server/addon.js +265 -11
  67. package/package.json +1 -1
  68. package/dist/assets/AddonCollectionPage-6BdYLe6i.js +0 -1
  69. package/dist/assets/Addons-DRZkv8if.js +0 -1
  70. package/dist/assets/Cluster-DUuIC1Di.js +0 -1
  71. package/dist/assets/Data-CI9RNUqg.js +0 -1
  72. package/dist/assets/DeviceDetail-ncfqxizt.js +0 -2
  73. package/dist/assets/IntegrationDetail-CddIVuAg.js +0 -1
  74. package/dist/assets/Integrations-Co_wJVPe.js +0 -1
  75. package/dist/assets/MyAccess-DN5XJRXk.js +0 -2
  76. package/dist/assets/Network-DWjMAaiC.js +0 -1
  77. package/dist/assets/Pipeline-CX07C-rk.js +0 -1
  78. package/dist/assets/ProviderIcon-BLTH0Ake.js +0 -1
  79. package/dist/assets/circle-check-big-Ybrsd8CR.js +0 -1
  80. package/dist/assets/dist-BAlJw4R3.js +0 -7
  81. package/dist/assets/index-ByJMV5aQ.js +0 -4
  82. package/dist/assets/plus-BWeUQ-Wm.js +0 -1
  83. package/dist/assets/remoteEntry-zKeZuvbY.js +0 -1
  84. package/dist/assets/rotate-cw-8j5op9rY.js +0 -1
  85. package/dist/assets/search-Cb4-y9a0.js +0 -1
  86. package/dist/assets/server-BKvjFwOh.js +0 -1
  87. package/dist/assets/square-fxMkH5ka.js +0 -1
  88. package/dist/assets/src-CKNSRfvW.js +0 -7
  89. package/dist/assets/src-D37vd48r.js +0 -67
@@ -4629,7 +4629,7 @@ function _instanceof(cls, params = {}) {
4629
4629
  return inst;
4630
4630
  }
4631
4631
  //#endregion
4632
- //#region ../types/dist/sleep-DiQ8xW1M.mjs
4632
+ //#region ../types/dist/sleep-DJaTV2D7.mjs
4633
4633
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4634
4634
  EventCategory["SystemBoot"] = "system.boot";
4635
4635
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5350,10 +5350,6 @@ function hydrateField(field, values) {
5350
5350
  };
5351
5351
  }
5352
5352
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5353
- if (field.type === "password") return {
5354
- ...field,
5355
- value: ""
5356
- };
5357
5353
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5358
5354
  return {
5359
5355
  ...field,
@@ -6737,18 +6733,21 @@ function method(input, output, options) {
6737
6733
  timeoutMs: options?.timeoutMs
6738
6734
  };
6739
6735
  }
6740
- var StaticDirOutputSchema = object({ staticDir: string() });
6741
- var VersionOutputSchema = object({ version: string() });
6736
+ var StaticDirOutputSchema$1 = object({ staticDir: string() });
6737
+ var VersionOutputSchema$1 = object({ version: string() });
6742
6738
  var adminUiCapability = {
6743
6739
  name: "admin-ui",
6744
6740
  scope: "system",
6745
6741
  mode: "singleton",
6746
6742
  internal: true,
6747
6743
  methods: {
6748
- getStaticDir: method(_void(), StaticDirOutputSchema),
6749
- getVersion: method(_void(), VersionOutputSchema)
6744
+ getStaticDir: method(_void(), StaticDirOutputSchema$1),
6745
+ getVersion: method(_void(), VersionOutputSchema$1)
6750
6746
  }
6751
6747
  };
6748
+ var StaticDirOutputSchema = object({ staticDir: string() });
6749
+ var VersionOutputSchema = object({ version: string() });
6750
+ method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
6752
6751
  /**
6753
6752
  * device-ops — device-scoped cap that unifies the per-IDevice operations
6754
6753
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -12605,6 +12604,17 @@ var WidgetMetadataSchema = object({
12605
12604
  deviceContext: boolean().default(false),
12606
12605
  integrationContext: boolean().default(false)
12607
12606
  }),
12607
+ /**
12608
+ * Loadable BEFORE authentication. The normal widget registry listing
12609
+ * (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
12610
+ * (the login page) cannot discover a widget through it. A widget that
12611
+ * declares `preAuth: true` marks itself as safe to mount on a pre-auth
12612
+ * screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
12613
+ * login-method contribution channel (see `login-method.cap.ts`) rather
12614
+ * than the authenticated registry, and its bundle is served by the
12615
+ * public `/api/addon-widgets/:addonId/*` static route. Defaults false.
12616
+ */
12617
+ preAuth: boolean().optional().default(false),
12608
12618
  /** Dashboard placement HINTS (operator can override per instance). */
12609
12619
  defaultSize: WidgetSizeEnum.default("md"),
12610
12620
  allowedSizes: array(WidgetSizeEnum).readonly().default([
@@ -12906,6 +12916,66 @@ method(object({
12906
12916
  password: string()
12907
12917
  }), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
12908
12918
  /**
12919
+ * `login-method` — collection cap through which auth addons contribute
12920
+ * their pre-auth login surfaces to the login page. This is the SINGLE,
12921
+ * generic mechanism that supersedes the dead `auth.listProviders` reader:
12922
+ * every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
12923
+ * `login-method` provider and the PUBLIC `auth.listLoginMethods`
12924
+ * procedure aggregates them for the unauthenticated login page.
12925
+ *
12926
+ * A contribution is a discriminated union on `kind`:
12927
+ *
12928
+ * - `redirect` — a declarative button. The login page renders a generic
12929
+ * button that navigates to `startUrl` (an addon-owned HTTP route).
12930
+ * Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
12931
+ * ZERO shell-side JS. A future SSO addon plugs in the same way — the
12932
+ * login page needs NO change.
12933
+ *
12934
+ * - `widget` — a Module-Federation widget the login page mounts (via
12935
+ * `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
12936
+ * login ceremony, which must run `@simplewebauthn/browser` INSIDE the
12937
+ * addon bundle. The referenced widget also declares `preAuth: true` in
12938
+ * its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
12939
+ * stamps a public `bundleUrl` from `addonId` + `bundle`.
12940
+ *
12941
+ * Every contribution carries a `stage`:
12942
+ * - `primary` — shown on the first credentials screen (OIDC /
12943
+ * magic-link buttons; a future usernameless passkey).
12944
+ * - `second-factor` — shown AFTER the password leg, gated on the
12945
+ * returned `factors` (passkey-as-2FA today).
12946
+ *
12947
+ * `mount: skip` — the cap is read server-side by the core auth router
12948
+ * (`registry.getCollection('login-method')`), never mounted as its own
12949
+ * tRPC router.
12950
+ */
12951
+ /** When a login method renders in the two-phase login flow. */
12952
+ var LoginStageEnum = _enum(["primary", "second-factor"]);
12953
+ /** One login-method contribution — redirect button OR pre-auth widget. */
12954
+ var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
12955
+ kind: literal("redirect"),
12956
+ /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
12957
+ id: string(),
12958
+ /** Operator-facing button label. */
12959
+ label: string(),
12960
+ /** lucide-react icon name. */
12961
+ icon: string().optional(),
12962
+ /** Addon-owned HTTP route the button navigates to (GET). */
12963
+ startUrl: string(),
12964
+ stage: LoginStageEnum
12965
+ }), object({
12966
+ kind: literal("widget"),
12967
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
12968
+ id: string(),
12969
+ /** Owning addon id — drives the public bundle URL + the MF namespace. */
12970
+ addonId: string(),
12971
+ /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
12972
+ bundle: string(),
12973
+ /** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
12974
+ remote: WidgetRemoteSchema,
12975
+ stage: LoginStageEnum
12976
+ })]);
12977
+ method(_void(), array(LoginMethodContributionSchema).readonly());
12978
+ /**
12909
12979
  * Orchestrator-side destination metadata. The orchestrator computes
12910
12980
  * `id = <addonId>:<subId>` from its provider lookup so consumers
12911
12981
  * (admin UI, restore flow) see one canonical key.
@@ -15607,6 +15677,131 @@ method(object({
15607
15677
  auth: "admin"
15608
15678
  });
15609
15679
  /**
15680
+ * server-management — per-NODE singleton capability for a node's ROOT
15681
+ * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
15682
+ * agents).
15683
+ *
15684
+ * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
15685
+ * on agents) carries the whole software stack in its npm dep tree, so ONE
15686
+ * version describes the node. Updates install into
15687
+ * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
15688
+ * starter (probation boot + auto-rollback to N-1).
15689
+ *
15690
+ * Providers:
15691
+ * - HUB: `ServerUpdateService` behind the `server-provided` mount
15692
+ * (`buildServerProviders` in trpc.router.ts) — the default target for
15693
+ * unpinned calls.
15694
+ * - AGENT: `AgentUpdateService` registered by the agent bootstrap under
15695
+ * the synthetic `agent-runtime` addonId and declared in the agent's
15696
+ * `$hub.registerNode` manifest.
15697
+ *
15698
+ * Node routing: singleton caps get the codegen/runtime-builder `nodeId`
15699
+ * injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
15700
+ * SDK) routes the call to that node's provider via the standard remote
15701
+ * proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
15702
+ * in-process provider lookup). No `nodeId` → the hub's own provider.
15703
+ *
15704
+ * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
15705
+ */
15706
+ /**
15707
+ * Where the running hub's code was loaded from:
15708
+ * - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
15709
+ * plain resolution and runtime updates are refused.
15710
+ * - `baked` — the immutable image seed closure (no data-dir root active).
15711
+ * - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
15712
+ */
15713
+ var ServerBootModeSchema = _enum([
15714
+ "workspace",
15715
+ "baked",
15716
+ "data-root"
15717
+ ]);
15718
+ /**
15719
+ * Update lifecycle state:
15720
+ * - `idle` / `checking` / `staging` — steady / in-flight registry work.
15721
+ * - `pending-restart` — a version is staged and the node has NOT yet
15722
+ * restarted onto it (still running the OLD version).
15723
+ * - `awaiting-confirmation` — the node HAS restarted onto the staged version
15724
+ * (it is the active probation boot) and is waiting to confirm boot-health.
15725
+ * Apply/rollback are refused in this state and the node must NOT be
15726
+ * manually restarted, or the probation boot auto-rolls-back.
15727
+ */
15728
+ var ServerUpdateStateSchema = _enum([
15729
+ "idle",
15730
+ "checking",
15731
+ "staging",
15732
+ "pending-restart",
15733
+ "awaiting-confirmation"
15734
+ ]);
15735
+ var ServerRollbackInfoSchema = object({
15736
+ /** The version that failed (or was manually rolled back). */
15737
+ fromVersion: string(),
15738
+ /** The version rolled back to; null = the baked seed. */
15739
+ toVersion: string().nullable(),
15740
+ atMs: number(),
15741
+ reason: string()
15742
+ });
15743
+ var ServerPackageStatusSchema = object({
15744
+ /** Root package name (`@camstack/server` on the hub). */
15745
+ packageName: string(),
15746
+ /** Version of the code the running process ACTUALLY loaded. */
15747
+ runningVersion: string().nullable(),
15748
+ /** Node.js runtime version the node's process runs on (`process.versions.node`). */
15749
+ nodeRuntimeVersion: string().nullable(),
15750
+ /** Active data-dir root version; null when booted from seed/workspace. */
15751
+ activeVersion: string().nullable(),
15752
+ /** N-1 version kept for rollback; null when no previous version exists. */
15753
+ previousVersion: string().nullable(),
15754
+ /** Version of the immutable baked seed closure (image fallback). */
15755
+ seedVersion: string().nullable(),
15756
+ /** Latest registry version from the most recent check (null = never checked). */
15757
+ latestVersion: string().nullable(),
15758
+ updateAvailable: boolean(),
15759
+ bootMode: ServerBootModeSchema,
15760
+ updateState: ServerUpdateStateSchema,
15761
+ /** Version staged + awaiting its probation boot, when one is pending. */
15762
+ pendingVersion: string().nullable(),
15763
+ /** Set when the last freshly-activated version failed its boot health-check. */
15764
+ rolledBack: ServerRollbackInfoSchema.nullable(),
15765
+ /**
15766
+ * True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
15767
+ * hub is running from the baked seed (or workspace) while installed data-dir
15768
+ * versions are being IGNORED. Surfaced as a warning in the UI.
15769
+ */
15770
+ stateFileCorrupt: boolean(),
15771
+ lastCheckedAtMs: number().nullable()
15772
+ });
15773
+ var ServerUpdateCheckResultSchema = object({
15774
+ packageName: string(),
15775
+ runningVersion: string().nullable(),
15776
+ latestVersion: string().nullable(),
15777
+ updateAvailable: boolean(),
15778
+ checkedAtMs: number(),
15779
+ /** Non-null when the registry lookup failed (offline, bad registry, …). */
15780
+ error: string().nullable()
15781
+ });
15782
+ var ServerUpdateActionResultSchema = object({
15783
+ accepted: boolean(),
15784
+ targetVersion: string().nullable(),
15785
+ /** True when a graceful restart was scheduled to apply the change. */
15786
+ restarting: boolean(),
15787
+ message: string()
15788
+ });
15789
+ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
15790
+ kind: "mutation",
15791
+ auth: "admin"
15792
+ }), method(object({
15793
+ /** Explicit target version; omitted = latest from the registry. */
15794
+ version: string().optional() }), ServerUpdateActionResultSchema, {
15795
+ kind: "mutation",
15796
+ auth: "admin"
15797
+ }), method(_void(), ServerUpdateActionResultSchema, {
15798
+ kind: "mutation",
15799
+ auth: "admin"
15800
+ }), method(_void(), ServerUpdateActionResultSchema, {
15801
+ kind: "mutation",
15802
+ auth: "admin"
15803
+ });
15804
+ /**
15610
15805
  * Query filter for settings-store collections.
15611
15806
  */
15612
15807
  var QueryFilterSchema = object({
@@ -17593,6 +17788,16 @@ var TopologyCategorySchema = object({
17593
17788
  healthy: number(),
17594
17789
  addons: array(TopologyCategoryAddonSchema).readonly()
17595
17790
  });
17791
+ /**
17792
+ * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
17793
+ * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
17794
+ * version visibility for the Server management surface. Nullable: offline
17795
+ * rows and pre-phase-2 nodes report none.
17796
+ */
17797
+ var TopologyRootPackageSchema = object({
17798
+ name: string(),
17799
+ version: string()
17800
+ });
17596
17801
  var TopologyNodeSchema = object({
17597
17802
  id: string(),
17598
17803
  name: string(),
@@ -17616,7 +17821,8 @@ var TopologyNodeSchema = object({
17616
17821
  status: string()
17617
17822
  })).readonly(),
17618
17823
  processes: array(TopologyProcessSchema).readonly(),
17619
- categories: array(TopologyCategorySchema).readonly()
17824
+ categories: array(TopologyCategorySchema).readonly(),
17825
+ rootPackage: TopologyRootPackageSchema.nullable()
17620
17826
  });
17621
17827
  var CapUsageEdgeSchema = object({
17622
17828
  callerAddonId: string(),
@@ -20416,6 +20622,12 @@ Object.freeze({
20416
20622
  addonId: null,
20417
20623
  access: "create"
20418
20624
  },
20625
+ "loginMethod.getLoginMethods": {
20626
+ capName: "login-method",
20627
+ capScope: "system",
20628
+ addonId: null,
20629
+ access: "view"
20630
+ },
20419
20631
  "mediaPlayer.next": {
20420
20632
  capName: "media-player",
20421
20633
  capScope: "device",
@@ -21778,6 +21990,36 @@ Object.freeze({
21778
21990
  addonId: null,
21779
21991
  access: "create"
21780
21992
  },
21993
+ "serverManagement.applyServerUpdate": {
21994
+ capName: "server-management",
21995
+ capScope: "system",
21996
+ addonId: null,
21997
+ access: "create"
21998
+ },
21999
+ "serverManagement.checkServerUpdate": {
22000
+ capName: "server-management",
22001
+ capScope: "system",
22002
+ addonId: null,
22003
+ access: "create"
22004
+ },
22005
+ "serverManagement.getServerPackageStatus": {
22006
+ capName: "server-management",
22007
+ capScope: "system",
22008
+ addonId: null,
22009
+ access: "view"
22010
+ },
22011
+ "serverManagement.restartServer": {
22012
+ capName: "server-management",
22013
+ capScope: "system",
22014
+ addonId: null,
22015
+ access: "create"
22016
+ },
22017
+ "serverManagement.rollbackServerUpdate": {
22018
+ capName: "server-management",
22019
+ capScope: "system",
22020
+ addonId: null,
22021
+ access: "create"
22022
+ },
21781
22023
  "settingsStore.count": {
21782
22024
  capName: "settings-store",
21783
22025
  capScope: "system",
@@ -22642,6 +22884,18 @@ Object.freeze({
22642
22884
  addonId: null,
22643
22885
  access: "view"
22644
22886
  },
22887
+ "viewerUi.getStaticDir": {
22888
+ capName: "viewer-ui",
22889
+ capScope: "system",
22890
+ addonId: null,
22891
+ access: "view"
22892
+ },
22893
+ "viewerUi.getVersion": {
22894
+ capName: "viewer-ui",
22895
+ capScope: "system",
22896
+ addonId: null,
22897
+ access: "view"
22898
+ },
22645
22899
  "waterHeater.setAway": {
22646
22900
  capName: "water-heater",
22647
22901
  capScope: "device",
@@ -22828,7 +23082,7 @@ var AdminUIAddon = class extends BaseAddon {
22828
23082
  capability: adminUiCapability,
22829
23083
  provider: {
22830
23084
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
22831
- getVersion: async () => ({ version: "1.1.39" })
23085
+ getVersion: async () => ({ version: "1.1.40" })
22832
23086
  }
22833
23087
  }];
22834
23088
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.1.39",
3
+ "version": "1.1.40",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "CamStack Admin UI — Vite frontend build and server-side addon",
@@ -1 +0,0 @@
1
- import{Ea as e,Et as t,Oa as n,Xi as r,Zi as i,d as a,g as o,m as s,xt as c}from"./src-D37vd48r.js";import{Q as l,S as u,o as d,q as f,x as p,z as m}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DTufy7Ue.js";import{t as h}from"./plus-BWeUQ-Wm.js";import{t as g}from"./refresh-cw-DuM6oiTl.js";import{t as _}from"./square-fxMkH5ka.js";import{H as v,P as y,R as b,V as x,p as S,x as C}from"./index-ByJMV5aQ.js";import{t as w}from"./AdminPage-BwmGKnRf.js";import{t as T}from"./NodeAddonsSettingsPanel-DLEbHtxx.js";var E=x(`play`,[[`polygon`,{points:`6 3 20 12 6 21 6 3`,key:`1oa8hb`}]]);l();function D({addonId:e,fallback:t,tileClassName:n,iconPath:r=`assets/icon.svg`}){let[i,a]=f(!1),o=`/api/addon-assets/${e}/${r}`;return p(`div`,{className:`h-10 w-10 rounded-lg flex items-center justify-center shrink-0 ${n}`,children:i?p(t,{className:`h-5 w-5`}):p(`img`,{src:o,alt:e,className:`h-7 w-7 rounded-md bg-white p-1 ring-1 ring-black/5`,onError:()=>a(!0)})})}l();function O({addonId:e,defaultActivity:t,showActivity:n=!0,maxHeight:r=`max-h-64`,defaultTab:i,capability:a}){let[c,l]=f(t??(i===`events`?`events`:`logs`));return u(`div`,{className:`flex flex-col gap-4`,children:[p(T,{nodeId:`hub`,addonIds:[e],level:`global`,capability:a}),n&&u(`div`,{className:`rounded-lg border border-border bg-surface overflow-hidden`,children:[u(`div`,{className:`flex items-center justify-between px-3 py-2 border-b border-border bg-surface-hover/20`,children:[p(`span`,{className:`text-[11px] font-semibold text-foreground-subtle uppercase tracking-wide`,children:`Activity`}),u(`div`,{className:`flex items-center gap-1`,children:[p(k,{kind:`logs`,active:c===`logs`,onClick:()=>l(`logs`)}),p(k,{kind:`events`,active:c===`events`,onClick:()=>l(`events`)})]})]}),c===`logs`?p(o,{addonId:e,maxHeight:r,showFilters:!1}):p(s,{addonId:e,category:`addon.*`,maxHeight:r})]})]})}function k({kind:e,active:t,onClick:n}){return u(`button`,{onClick:n,className:`inline-flex items-center gap-1 rounded px-2 py-0.5 text-[11px] font-medium transition-colors ${t?`bg-primary/10 text-primary`:`text-foreground-subtle hover:text-foreground hover:bg-surface-hover`}`,children:[p(e===`logs`?S:b,{className:`h-3 w-3`}),e===`logs`?`Logs`:`Events`]})}l();function A(t){let{title:a,subtitle:o,pageIcon:s,itemIcon:c,capability:l,installButtonLabel:d=`Add addon`,items:g,isLoading:_,emptyTitle:b=`No addons installed for this capability`,emptyDescription:x,itemIconColor:S,renderStatusBadges:C,renderPrimaryAction:T,itemError:E,renderExpandedPanel:k,workspaceMaxHeight:A=`max-h-72`,trailing:P,showChrome:F=!1}=t,I=g.length>1,[L,R]=f(()=>g[0]?.addonId??null);m(()=>{L&&(g.some(e=>e.addonId===L)||R(g[0]?.addonId??null))},[g,L]);let z=e=>R(t=>t===e?null:e),B=`/system/addons?capability=${encodeURIComponent(l)}`;return p(w,{icon:F?s:void 0,title:F?a:void 0,subtitle:F?o:void 0,actions:F?p(v,{to:B,children:u(n,{variant:`primary`,size:`sm`,children:[p(h,{className:`h-3.5 w-3.5 mr-1`}),d]})}):void 0,children:_?p(e,{children:p(`div`,{className:`p-6 text-sm text-foreground-subtle`,children:`Loading…`})}):g.length===0?p(e,{children:p(i,{title:b,description:x??`Install an addon that declares the "${l}" capability to get started.`,action:F?p(v,{to:B,children:u(n,{variant:`primary`,size:`sm`,children:[p(h,{className:`h-3.5 w-3.5 mr-1`}),d]})}):void 0})}):u(`div`,{className:`flex flex-col gap-4`,children:[g.map(t=>{let n=!I||L===t.addonId,i=S?.(t)??(t.isActive?`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`:`bg-foreground-subtle/15 text-foreground-subtle`),a=E?.(t)??null;return u(e,{children:[u(`div`,{className:`flex flex-col gap-3 p-4 sm:flex-row sm:items-center ${n?`border-b border-border`:``}`,children:[u(`div`,{className:`flex items-center gap-3 flex-1 min-w-0`,children:[I&&p(`button`,{type:`button`,onClick:()=>z(t.addonId),"aria-label":n?`Collapse`:`Expand`,className:`shrink-0 p-1 rounded hover:bg-foreground-subtle/10 transition-colors`,children:p(y,{className:`h-4 w-4 text-foreground-subtle transition-transform ${n?`rotate-180`:``}`})}),u(`button`,{type:`button`,onClick:()=>I&&z(t.addonId),className:`flex items-center gap-4 flex-1 min-w-0 text-left ${I?`hover:opacity-80 transition-opacity`:``}`,disabled:!I,children:[p(D,{addonId:t.addonId,fallback:c,tileClassName:i}),u(`div`,{className:`flex-1 min-w-0`,children:[u(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[p(`span`,{className:`font-semibold text-foreground`,children:t.displayName}),p(j,{isActive:t.isActive}),C?.(t)]}),p(`div`,{className:`text-xs text-foreground-subtle mt-1 font-mono break-all`,children:t.addonId})]})]})]}),u(`div`,{className:`flex items-center gap-1 shrink-0 flex-wrap justify-end`,children:[T?.(t),p(M,{capName:l,addonId:t.addonId,isActive:t.isActive}),p(N,{addonId:t.addonId,displayName:t.displayName})]})]}),n&&u(`div`,{className:`p-4 flex flex-col gap-3`,children:[a!==null&&p(r,{message:a}),k?.(t),p(O,{addonId:t.addonId,maxHeight:A,capability:l})]})]},t.addonId)}),P]})})}function j({isActive:e}){return p(`span`,{className:`text-[10px] rounded-full px-2 py-0.5 font-medium ${e?`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`:`bg-foreground-subtle/15 text-foreground-subtle`}`,children:e?`Enabled`:`Disabled`})}function M({capName:e,addonId:r,isActive:i}){let a=d(),o=t({onSuccess:()=>{a.invalidateQueries({queryKey:[[`addons`,`listCapabilityProviders`]]})}}),s=o.isPending;return u(n,{size:`sm`,variant:i?`secondary`:`primary`,disabled:s,onClick:()=>o.mutate({capName:e,addonId:r,enabled:!i}),children:[s?p(C,{className:`h-3 w-3 animate-spin`}):p(i?_:E,{className:`h-3 w-3`}),i?`Disable`:`Enable`]})}function N({addonId:e,displayName:t}){let n=d(),r=c({onSuccess:()=>{n.invalidateQueries({queryKey:[[`addons`,`listCapabilityProviders`]]})}});return p(a,{label:`Restart`,icon:g,size:`sm`,title:`Restart "${t}"?`,description:`Restarting the addon bounces its subprocess — the provider will briefly drop and reconnect automatically.`,confirmLabel:`Restart`,triggerVariant:`ghost`,confirmVariant:`danger`,disabled:r.isPending,action:()=>r.mutateAsync({addonId:e})})}export{E as n,A as t};
@@ -1 +0,0 @@
1
- import{Ar as e,At as t,Ct as n,Dt as r,Ir as i,Ot as a,Qi as o,Tt as s,Yi as c,_t as l,bt as u,ct as d,dt as ee,ft as f,g as p,ht as te,kt as m,lt as h,m as g,mt as ne,pt as _,ta as v,ut as re,v as ie,vt as y,wt as ae,xt as oe,yt as se}from"./src-D37vd48r.js";import{I as b,K as x,Q as S,R as ce,S as C,W as w,b as le,o as ue,q as T,x as E,z as D}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DTufy7Ue.js";import{L as O}from"./src-CKNSRfvW.js";import{p as de}from"./player-overlays-2Q1miaEN.js";import{t as k}from"./download-DDSz9DfI.js";import{t as fe}from"./plus-BWeUQ-Wm.js";import{t as A}from"./refresh-cw-DuM6oiTl.js";import{t as j}from"./search-Cb4-y9a0.js";import{t as M}from"./upload-B9TkBT8Q.js";import{A as pe,F as N,G as P,P as F,U as me,V as I,f as he,h as L,i as ge,o as R,p as z,s as _e,x as B}from"./index-ByJMV5aQ.js";import{t as V}from"./AdminPage-BwmGKnRf.js";import{t as ve}from"./NodeAddonsSettingsPanel-DLEbHtxx.js";var ye=I(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),H=I(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]]),U=I(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),be=I(`package`,[[`path`,{d:`M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z`,key:`1a0edw`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}],[`polyline`,{points:`3.29 7 12 12 20.71 7`,key:`ousv84`}],[`path`,{d:`m7.5 4.27 9 5.15`,key:`1c824w`}]]),W=I(`skip-forward`,[[`polygon`,{points:`5 4 15 12 5 20 5 4`,key:`16p6eg`}],[`line`,{x1:`19`,x2:`19`,y1:`5`,y2:`19`,key:`futhcm`}]]);S();var G=new Set([`completed`,`failed`,`partially-failed`,`cancelled`]),K=new Set([`done`,`failed`,`skipped`]);function q(e){return!K.has(e.phase)&&!G.has(e.jobState)}function J(e,t){let n=new Map,r=[...e].sort((e,t)=>e.createdAtMs-t.createdAtMs);for(let e of r){let r=G.has(e.state);for(let i of e.tasks)r&&i.finishedAtMs!==null&&t-i.finishedAtMs>6e4||n.set(i.packageName,{jobId:e.jobId,packageName:i.packageName,phase:i.phase,fromVersion:i.fromVersion,toVersion:i.toVersion,error:i.error,jobState:e.state,finishedAtMs:i.finishedAtMs})}return n}function xe(){let{data:e}=y({activeOnly:!0},{refetchOnWindowFocus:!1,refetchInterval:e=>(e.state.data?.length??0)>0?3e3:!1}),{map:t}=v(O.AddonsJobProgress,e=>e.job.jobId);return w(()=>{let n=new Map;for(let t of e??[])n.set(t.jobId,t);for(let[e,r]of t)n.set(e,r.job);return J([...n.values()],Date.now())},[e,t])}var Y={queued:{icon:H,cls:`bg-muted text-foreground-subtle`,label:`queued`},fetching:{icon:B,cls:`bg-primary/10 text-primary`,label:`fetching`,spin:!0},staged:{icon:B,cls:`bg-primary/10 text-primary`,label:`staged`,spin:!0},validating:{icon:B,cls:`bg-primary/10 text-primary`,label:`validating`,spin:!0},applying:{icon:B,cls:`bg-primary/10 text-primary`,label:`applying`,spin:!0},restarting:{icon:B,cls:`bg-amber-500/10 text-amber-600 dark:text-amber-400`,label:`restarting`,spin:!0},applied:{icon:B,cls:`bg-primary/10 text-primary`,label:`finalizing`,spin:!0},done:{icon:N,cls:`bg-success/10 text-success`,label:`updated`},failed:{icon:U,cls:`bg-danger/10 text-danger`,label:`failed`},skipped:{icon:W,cls:`bg-muted text-foreground-subtle`,label:`skipped`}};function Se({progress:e}){let t=Y[e.phase],n=t.icon,r=e.error??`${e.packageName}: ${e.fromVersion??`?`} → ${e.toVersion}`;return C(`span`,{"data-testid":`addon-job-progress`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded shrink-0 ${t.cls}`,title:r,children:[E(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label,C(`span`,{className:`font-mono`,children:[`→ `,e.toVersion]})]})}function Ce({packageName:e,currentVersion:t,installSource:n,onInstall:r,onClose:i,onSelect:a,selectedVersion:o}){let s=n===`upload`||n===`local`,{data:c,isLoading:l}=_({name:e});return C(`div`,{className:`fixed z-50 w-72 rounded-lg border border-border bg-surface shadow-xl overflow-hidden`,style:{top:`auto`,bottom:`auto`},ref:e=>{if(!e)return;let t=e.parentElement?.getBoundingClientRect();if(!t)return;let n=window.innerHeight-t.bottom,r=t.top;n<280&&r>n?(e.style.bottom=`${window.innerHeight-t.top+4}px`,e.style.top=`auto`):(e.style.top=`${t.bottom+4}px`,e.style.bottom=`auto`),e.style.right=`${window.innerWidth-t.right}px`},onClick:e=>e.stopPropagation(),children:[C(`div`,{className:`flex items-center justify-between px-3 py-2 border-b border-border`,children:[E(`span`,{className:`text-[10px] uppercase tracking-wide text-foreground-subtle font-medium`,children:`Versions`}),E(`button`,{type:`button`,onClick:i,className:`text-foreground-subtle hover:text-foreground`,children:E(ge,{className:`h-3 w-3`})})]}),s&&C(`div`,{className:`flex items-start gap-2 px-3 py-2 border-b border-border bg-cyan-500/10 text-[10px]`,children:[E(M,{className:`h-3 w-3 mt-0.5 text-cyan-500 shrink-0`}),C(`div`,{className:`text-cyan-700 dark:text-cyan-200`,children:[C(`span`,{className:`font-semibold`,children:[n===`upload`?`Uploaded copy`:`Local copy`,` in place.`]}),` `,`Re-install `,E(`span`,{className:`font-mono`,children:t}),` from npm to track upstream releases again.`]})]}),l&&C(`div`,{className:`flex items-center justify-center gap-2 py-6 text-[10px] text-foreground-subtle`,children:[E(B,{className:`h-3.5 w-3.5 animate-spin`}),`Loading versions...`]}),c&&E(`div`,{className:`max-h-64 overflow-auto divide-y divide-border`,children:c.map(e=>{let n=e.version===t,i=a!==void 0&&e.version===o,c=/-(alpha|beta|rc|dev|canary|next)/i.test(e.version),l=C(le,{children:[E(`span`,{className:`font-mono flex-1 text-left ${n?`text-primary font-semibold`:c?`text-amber-400`:`text-foreground`}`,children:e.version}),n&&E(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium bg-primary/10 text-primary`,children:`current`}),e.distTags.map(e=>E(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e===`latest`?`bg-emerald-500/15 text-emerald-400`:e===`beta`?`bg-amber-500/15 text-amber-400`:`bg-gray-500/15 text-gray-400`}`,children:e},e)),e.deprecated&&E(`span`,{className:`text-[9px] text-red-400 line-through`,children:`deprecated`}),E(`span`,{className:`text-[9px] text-foreground-subtle shrink-0`,children:new Date(e.publishedAt).toLocaleDateString()})]});return a?C(`button`,{type:`button`,"aria-label":`Select ${e.version}`,onClick:()=>a(e.version),className:`w-full flex items-center gap-2 px-3 py-2 text-[11px] ${i?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[l,i?E(N,{className:`h-3 w-3 text-primary shrink-0`}):E(`span`,{className:`w-3 shrink-0`})]},e.version):C(`div`,{className:`flex items-center gap-2 px-3 py-2 text-[11px] ${n?`bg-primary/5`:`hover:bg-surface-hover`} transition-colors`,children:[l,n&&!s?E(N,{className:`h-3 w-3 text-primary shrink-0`}):E(`button`,{type:`button`,onClick:()=>r(e.version),className:`shrink-0 rounded p-0.5 hover:bg-primary/20 text-foreground-subtle hover:text-primary transition-colors`,title:n?`Re-install ${e.version} from npm`:`Install ${e.version}`,children:E(k,{className:`h-3 w-3`})})]},e.version)})}),c&&c.length===0&&E(`div`,{className:`py-4 text-center text-[10px] text-foreground-subtle`,children:`No versions found`})]})}var X={queued:{icon:H,bg:`bg-muted text-foreground-subtle`,label:`queued`},updating:{icon:B,bg:`bg-primary/10 text-primary`,label:`updating`,spin:!0},"done-pending-restart":{icon:A,bg:`bg-amber-500/10 text-amber-700`,label:`pending restart`},done:{icon:N,bg:`bg-success/10 text-success`,label:`done`},failed:{icon:U,bg:`bg-danger/10 text-danger`,label:`failed`}};function we({item:e}){let t=X[e.status],n=t.icon;return C(`span`,{className:`inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] rounded ${t.bg}`,title:e.error,children:[E(n,{className:`w-2.5 h-2.5 ${t.spin?`animate-spin`:``}`}),t.label]})}S();var Z=`device-export`;function Te(e){return e.capabilities.some(e=>(typeof e==`string`?e:e.name)===Z)}function Ee({isBundle:e,installSource:t,addonId:n,iconPath:r,color:i}){let[a,o]=T(!1),s=i?{backgroundColor:`${i.startsWith(`#`)?i:`#${i}`}26`}:void 0,c=e?`bg-indigo-500/20 text-indigo-700 dark:text-indigo-300`:`bg-purple-500/20 text-purple-700 dark:text-purple-300`,l=n&&r?`/api/addon-assets/${n}/${r}`:null,u=!!l&&!a;return C(`div`,{className:`relative flex-shrink-0`,children:[E(`div`,{className:`h-9 w-9 rounded-lg flex items-center justify-center ${s?``:c}`,style:s,children:u?E(`img`,{src:l,alt:n,className:`h-5 w-5`,onError:()=>o(!0)}):E(e?be:L,{className:`h-4 w-4`})}),t===`local`&&E(`span`,{className:`absolute -top-1.5 -left-1.5 text-[7px] font-bold leading-none bg-orange-500 text-white px-1 py-0.5 rounded -rotate-12 shadow-sm`,children:`DEV`}),t===`npm`&&E(`span`,{className:`absolute -top-1 -left-1 w-4 h-4 rounded bg-[#cb3837] flex items-center justify-center -rotate-12 shadow-sm`,children:E(`svg`,{viewBox:`0 0 780 250`,className:`w-[11px] h-[11px]`,children:E(`path`,{fill:`#fff`,d:`M240 250h100V50h100v200h340V0H0v250z`})})}),t===`upload`&&E(`span`,{className:`absolute -top-1.5 -left-1.5 flex items-center justify-center h-4 w-4 rounded bg-cyan-500 -rotate-12 shadow-sm`,children:E(M,{className:`h-2.5 w-2.5 text-white`})})]})}function De({version:e,availableUpdate:t,selectedVersion:n,isUpdating:r,installSource:i,disabled:a,onUpdate:o,onOpenPicker:s,children:c}){if(r)return C(`span`,{className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-blue-500/30 bg-blue-500/10 text-blue-400 shrink-0`,children:[E(B,{className:`h-3 w-3 animate-spin`}),`Updating…`]});if(t){let r=n??t;return C(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[o&&C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),o()},disabled:a,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-semibold border border-blue-500/30 bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,title:`Update to ${r}`,children:[E(k,{className:`h-3 w-3`}),`Update`]}),C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),s()},disabled:a,"aria-label":`Select version to install`,title:`Installed ${e} — update available. Selected ${r}; tap to choose another version.`,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-bold font-mono border border-amber-500/40 bg-amber-500/15 text-amber-500 hover:bg-amber-500/25 animate-pulse disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,children:[E(`span`,{className:`font-normal opacity-70`,children:e}),E(`span`,{className:`font-normal opacity-70`,children:`→`}),r,E(F,{className:`h-3 w-3`})]}),c]})}return C(`div`,{className:`relative inline-flex items-center gap-1 shrink-0`,children:[C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),s()},disabled:a,className:[`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-bold font-mono border transition-colors disabled:opacity-50 disabled:cursor-not-allowed`,i===`local`?`border-orange-500/30 bg-orange-500/10 text-orange-400 hover:bg-orange-500/20`:`border-emerald-500/30 bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20`].join(` `),title:`Version ${e} — tap to view all versions`,children:[e,E(F,{className:`h-3 w-3 opacity-50`})]}),c]})}function Oe({addonId:e}){let t=ue(),{data:n=`inherit`}=re({addonId:e}),r=s({onSuccess:()=>{t.invalidateQueries({queryKey:[[`addons`,`getAddonAutoUpdate`]]})}});return E(`div`,{className:`flex rounded-lg border border-border overflow-hidden text-[10px] font-medium`,children:[`inherit`,`off`,`latest`,`beta`].map(t=>E(`button`,{type:`button`,onClick:n=>{n.stopPropagation(),r.mutate({addonId:e,channel:t})},disabled:r.isPending,className:`px-2.5 py-1 transition-colors capitalize ${n===t?t===`inherit`?`bg-gray-700/50 text-gray-700 dark:text-gray-300`:t===`off`?`bg-gray-700 text-gray-700 dark:text-gray-300`:t===`latest`?`bg-blue-500/20 text-blue-400`:`bg-amber-500/20 text-amber-400`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`} ${t===`inherit`?``:`border-l border-border`}`,children:t},t))})}function ke({addon:e,agents:t=[],clusterStatus:r,hideVersion:i,availableUpdate:o,onUpdate:s,isUpdating:l,jobProgress:u,bundle:d,bulkItem:ee,disabledByBulk:f,isSystem:te}){let[m,h]=T(!1),[_,v]=T(!1),[re,y]=T(!1),[ae,se]=T(null);D(()=>{se(null)},[o]);let b=ae??o,[x,S]=T(!1),[ce,w]=T(!1),[O,k]=T(`logs`),j=ue(),M=de(),pe=me(),N=c(),{manifest:P}=e,I=e.installedOn??[],L=!d&&!P.protected&&P.removable!==!1,R=!!d,B=d?.displayName??P.name,V=d?.packageName??P.packageName,H=d?.version??P.packageVersion??P.version,W=d?.installSource??e.installSource,G=d?d.bundle?.description??d.addons[0]?.manifest.description:P.description,K=a({onSuccess:()=>{j.invalidateQueries({queryKey:[[`addons`]]}),j.invalidateQueries({queryKey:[[`addonPages`]]}),j.invalidateQueries({queryKey:[[`capabilities`]]})}}),q=oe({onSuccess:()=>{j.invalidateQueries({queryKey:[[`addons`]]})}}),J=ne({onSuccess:()=>{j.invalidateQueries({queryKey:[[`addons`]]}),j.invalidateQueries({queryKey:[[`addonPages`]]}),j.invalidateQueries({queryKey:[[`capabilities`]]}),j.invalidateQueries({queryKey:[[`integrations`]]})}}),xe=n({onSuccess:()=>{j.invalidateQueries({queryKey:[[`addons`]]}),j.invalidateQueries({queryKey:[[`alerts`]]})}}),Y=e.health,X=Y?.phase===`failed`&&!Y.inGracePeriod,Z=X&&Y?.nextRetryAt&&!Y.retrying;return C(`div`,{className:`rounded-lg border bg-surface overflow-hidden ${X?`border-red-500/50`:`border-border`}`,children:[X&&Y&&C(`div`,{className:`bg-danger/10 border-b border-danger/30 px-4 py-2.5 flex items-start gap-2.5`,children:[E(U,{className:`h-4 w-4 text-danger shrink-0 mt-0.5`}),C(`div`,{className:`flex-1 min-w-0`,children:[C(`div`,{className:`text-xs font-semibold text-danger`,children:[`Failed to load (attempt #`,Y.retryCount,`)`]}),E(`div`,{className:`text-[11px] text-foreground mt-0.5 break-words font-mono`,children:Y.lastError?.message??`Unknown error`}),Z&&Y.nextRetryAt&&C(`div`,{className:`text-[10px] text-foreground-subtle mt-1`,children:[`Auto-retry at `,new Date(Y.nextRetryAt).toLocaleTimeString()]})]}),C(`button`,{type:`button`,disabled:xe.isPending||Y.retrying,onClick:e=>{e.stopPropagation(),xe.mutate({packageName:V})},className:`inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-[11px] font-semibold border border-red-400/40 bg-red-400/10 text-red-700 dark:text-red-300 hover:bg-red-400/20 disabled:opacity-50 disabled:cursor-not-allowed transition-colors shrink-0`,title:`Reset retry counter and force immediate reload`,children:[E(A,{className:`h-3 w-3 ${xe.isPending||Y.retrying?`animate-spin`:``}`}),`Retry now`]})]}),C(`div`,{className:`flex items-start gap-3 px-4 py-3`,children:[E(Ee,{isBundle:R||!!P.components&&P.components.length>1,installSource:W,addonId:R?d.addons[0]?.manifest.id:P.id,iconPath:R?d.bundle?.icon??d.addons[0]?.manifest.icon:P.icon,color:R?d.addons[0]?.manifest.color:P.color}),C(`div`,{className:`flex-1 min-w-0`,children:[C(`div`,{className:`flex items-start justify-between gap-2`,children:[E(`span`,{className:`text-sm font-semibold text-foreground truncate min-w-0`,children:B}),!i&&E(De,{version:H,availableUpdate:o,...b===void 0?{}:{selectedVersion:b},isUpdating:l,installSource:W,disabled:f,...s&&b!==void 0?{onUpdate:()=>s(b)}:{},onOpenPicker:()=>y(e=>!e),children:re&&E(Ce,{packageName:V,currentVersion:H,...W?{installSource:W}:{},...o!==void 0&&b!==void 0?{selectedVersion:b,onSelect:e=>{se(e),y(!1)}}:{},onInstall:e=>{y(!1),J.mutate({packageName:V,version:e})},onClose:()=>y(!1)})})]}),C(`div`,{className:`flex flex-wrap items-center gap-x-1.5 gap-y-1 mt-0.5`,children:[V!==B&&E(`span`,{className:`text-[10px] text-foreground-subtle font-mono truncate max-w-full`,children:V}),R&&C(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium shrink-0 inline-flex items-center gap-1`,children:[E(be,{className:`h-3 w-3`}),d.addons.length]}),te&&C(`span`,{className:`text-[10px] rounded-full bg-amber-500/15 text-amber-700 dark:text-amber-300 px-2 py-0.5 font-medium shrink-0 inline-flex items-center gap-1`,title:`System package — updating restarts the hub`,children:[E(A,{className:`h-3 w-3`}),`System`]}),ee!=null&&E(we,{item:ee}),u!=null&&E(Se,{progress:u})]}),G&&E(`p`,{className:`text-[10px] text-foreground-subtle mt-1 line-clamp-1`,children:G}),!R&&e.process&&C(`div`,{className:`flex flex-wrap items-center gap-1.5 mt-1`,children:[E(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e.process.mode===`forked`?`bg-blue-500/15 text-blue-400`:`bg-gray-500/15 text-gray-400`}`,children:e.process.mode===`forked`?`forked`:`in-process`}),e.process.pid!=null&&C(`span`,{className:`text-[9px] font-mono text-foreground-subtle`,children:[`PID `,e.process.pid]}),E(`span`,{className:`text-[9px] rounded-full px-1.5 py-0.5 font-medium ${e.process.state===`running`?`bg-emerald-500/15 text-emerald-400`:e.process.state===`crashed`||e.process.state===`failed`?`bg-red-500/15 text-red-400`:`bg-gray-500/15 text-gray-400`}`,children:e.process.state})]})]})]}),!R&&C(`div`,{className:`flex items-center gap-1 px-4 py-1.5 border-t border-border/50 bg-surface-hover/20`,children:[C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),q.mutate({addonId:P.id})},disabled:q.isPending||f,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-border text-foreground-subtle hover:text-blue-400 hover:border-blue-500/30 hover:bg-blue-500/10 disabled:opacity-50 transition-colors`,children:[E(A,{className:`h-3 w-3 ${q.isPending?`animate-spin`:``}`}),`Restart`]}),C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),S(e=>!e)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${x?`border-primary/30 bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground hover:border-primary/30 hover:bg-primary/10`}`,children:[E(z,{className:`h-3 w-3`}),`Logs`]}),!R&&C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),w(!0)},className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border transition-colors ${ce?`border-primary/30 bg-primary/10 text-primary`:`border-border text-foreground-subtle hover:text-foreground hover:border-primary/30 hover:bg-primary/10`}`,children:[E(he,{className:`h-3 w-3`}),`Settings`]}),E(`div`,{className:`flex-1`}),L&&C(`button`,{type:`button`,onClick:async e=>{e.stopPropagation(),await N({title:`Uninstall ${P.name}?`,message:`This will remove the addon package and all its data. This action cannot be undone.`,confirmLabel:`Uninstall`,variant:`danger`})&&K.mutate({packageName:P.packageName})},disabled:K.isPending||f,className:`inline-flex items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium border border-border text-foreground-subtle hover:text-red-400 hover:border-red-500/30 hover:bg-red-500/10 disabled:opacity-50 transition-colors`,children:[E(_e,{className:`h-3 w-3`}),K.isPending?`Removing...`:`Uninstall`]})]}),r&&r.nodes.length>1&&!R&&C(`div`,{className:`border-t border-border px-4 py-2 bg-muted/10`,children:[E(`div`,{className:`text-[10px] font-medium text-foreground-subtle mb-1.5`,children:`Cluster Deployment`}),E(`div`,{className:`space-y-1`,children:r.nodes.map(e=>C(`div`,{className:`flex items-center gap-2 text-[10px]`,children:[E(`div`,{className:`h-1.5 w-1.5 rounded-full shrink-0 ${e.status===`offline`?`bg-muted-foreground/30`:e.synced?`bg-success`:`bg-amber-500`}`}),E(`span`,{className:`font-medium text-foreground min-w-[60px]`,children:e.name}),E(`span`,{className:`font-mono text-foreground-subtle`,children:e.version}),!e.synced&&e.status!==`offline`&&E(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-400 border border-amber-500/20`,children:`outdated`}),e.status===`offline`&&E(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-muted text-muted-foreground`,children:`offline`}),e.synced&&e.status!==`offline`&&E(`span`,{className:`text-[9px] text-success`,children:`synced`})]},e.nodeId))})]}),x&&!R&&C(`div`,{className:`border-t border-border`,children:[C(`div`,{className:`flex items-center px-4 py-1 bg-surface-hover/20 border-b border-border/50`,children:[C(`div`,{className:`flex rounded border border-border overflow-hidden text-[9px]`,children:[E(`button`,{type:`button`,onClick:()=>k(`logs`),className:`px-2 py-0.5 transition-colors ${O===`logs`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Logs`}),E(`button`,{type:`button`,onClick:()=>k(`events`),className:`px-2 py-0.5 border-l border-border transition-colors ${O===`events`?`bg-primary/10 text-primary`:`text-foreground-subtle hover:bg-surface-hover`}`,children:`Events`})]}),E(`div`,{className:`flex-1`}),E(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),S(!1)},className:`text-foreground-subtle hover:text-foreground`,children:E(ge,{className:`h-3.5 w-3.5`})})]}),O===`logs`&&E(p,{addonId:P.id,maxHeight:`max-h-64`,showFilters:!1}),O===`events`&&E(g,{addonId:P.id,category:`addon.*`,maxHeight:`max-h-64`})]}),R&&C(le,{children:[E(`button`,{type:`button`,onClick:()=>h(e=>!e),className:`w-full flex items-center justify-center border-t border-border py-1 hover:bg-surface-hover/50 transition-colors`,children:E(m?ye:F,{className:`h-3.5 w-3.5 text-foreground-subtle`})}),m&&E(`div`,{className:`border-t border-border px-3 py-2 space-y-2`,children:d.addons.map(e=>E(ke,{addon:e,agents:t,hideVersion:!0},e.manifest.id))})]}),ce&&!R&&E(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4`,onClick:()=>w(!1),children:C(`div`,{className:`w-full max-w-lg max-h-[80vh] rounded-xl border border-border bg-surface shadow-2xl flex flex-col overflow-hidden`,onClick:e=>e.stopPropagation(),children:[C(`div`,{className:`flex items-center justify-between px-5 py-3 border-b border-border flex-shrink-0`,children:[C(`div`,{className:`flex items-center gap-2`,children:[E(he,{className:`h-4 w-4 text-primary`}),C(`h2`,{className:`text-sm font-semibold text-foreground`,children:[B,` Settings`]})]}),E(`button`,{onClick:()=>w(!1),className:`text-foreground-subtle hover:text-foreground transition-colors p-1 rounded`,children:E(ge,{className:`h-4 w-4`})})]}),C(`div`,{className:`flex-1 overflow-y-auto px-5 py-4 space-y-4`,children:[E(ve,{nodeId:`hub`,addonIds:[P.id],level:`global`}),Te(P)&&C(`div`,{children:[E(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Device export`}),E(ie,{addonId:P.id,trpc:M.trpcClient,onOpenDevice:e=>pe(`/devices/${e}`)})]}),W===`npm`&&C(`div`,{children:[E(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Auto-Update`}),E(Oe,{addonId:P.id})]}),P.components&&P.components.length>0&&C(`div`,{children:[C(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:[`Components (`,P.components.length,`)`]}),E(`div`,{className:`flex flex-wrap gap-1`,children:P.components.map(e=>E(`span`,{className:`text-[10px] rounded bg-background border border-border px-1.5 py-0.5 text-foreground-subtle font-mono`,children:e},e))})]}),t.length>=2&&C(`div`,{children:[E(`div`,{className:`text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-2`,children:`Installed on`}),C(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:[I.length===0&&E(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Hub (local)`}),I.map(e=>E(`span`,{className:`rounded-full bg-surface-hover border border-border px-2 py-0.5 text-[10px] text-foreground-subtle`,children:e},e)),C(`div`,{className:`relative`,children:[C(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),v(e=>!e)},className:`inline-flex items-center gap-1 rounded-full border border-dashed border-border px-2 py-0.5 text-[10px] text-foreground-subtle hover:text-foreground hover:border-primary transition-colors`,title:`Install on more agents`,children:[E(fe,{className:`h-3 w-3`}),`Add agent`]}),_&&C(`div`,{className:`absolute left-0 top-full mt-1 z-10 min-w-[160px] rounded-md border border-border bg-surface shadow-lg overflow-hidden`,children:[t.filter(e=>!e.isHub&&!I.includes(e.name)).map(e=>E(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),v(!1)},className:`w-full text-left px-3 py-1.5 text-[10px] text-foreground hover:bg-surface-hover transition-colors`,children:e.name},e.id)),t.filter(e=>!e.isHub&&!I.includes(e.name)).length===0&&E(`div`,{className:`px-3 py-1.5 text-[10px] text-foreground-subtle`,children:`No available agents`})]})]})]})]})]}),E(`div`,{className:`flex items-center justify-end px-5 py-3 border-t border-border flex-shrink-0`,children:E(`button`,{type:`button`,onClick:()=>w(!1),className:`rounded-lg border border-border px-3 py-1.5 text-xs font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors`,children:`Close`})})]})})]})}S();var Ae=`.tgz,.tar.gz,.zip`;function je({onUploadSuccess:e}){let[t,n]=T(!1),r=x(null),i=b(async t=>{n(!0);let r=new FormData;r.append(`file`,t);let i=localStorage.getItem(`camstack_admin_token`)??``;try{(await(await fetch(`/api/addons/upload`,{method:`POST`,headers:{Authorization:`Bearer ${i}`},body:r})).json()).success&&e()}finally{n(!1)}},[e]);return C(le,{children:[E(`input`,{ref:r,type:`file`,accept:Ae,onChange:b(e=>{let t=e.target.files?.[0];t&&i(t),e.target.value=``},[i]),className:`hidden`}),C(`button`,{type:`button`,onClick:()=>r.current?.click(),disabled:t,className:`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,children:[t?E(B,{className:`w-3.5 h-3.5 animate-spin`}):E(M,{className:`w-3.5 h-3.5`}),t?`Uploading...`:`Upload`]})]})}function Me({pending:e,onCancel:t,onConfirm:n,isPending:r,error:i}){return E(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/60`,children:C(`div`,{className:`bg-surface border border-border rounded-md shadow-xl p-5 max-w-md w-full mx-4 space-y-3`,children:[C(`div`,{className:`flex items-center gap-2`,children:[E(R,{className:`w-4 h-4 text-amber-700`}),E(`h3`,{className:`text-sm font-medium text-foreground`,children:`Update system package?`})]}),C(`div`,{className:`space-y-2 text-[11px] text-foreground-subtle`,children:[C(`div`,{children:[E(`span`,{className:`font-mono text-foreground`,children:e.packageName}),E(`span`,{className:`mx-1`,children:`·`}),C(`span`,{className:`font-mono`,children:[`v`,e.fromVersion]}),E(`span`,{className:`mx-1`,children:`→`}),C(`span`,{className:`font-mono text-amber-700`,children:[`v`,e.toVersion]})]}),E(`div`,{className:`rounded border border-amber-500/30 bg-amber-500/10 p-2 text-amber-800`,children:`The hub will restart immediately after the install. Any in-flight requests will be dropped. The reconnect typically takes ~10 seconds.`}),i!==null&&E(`div`,{className:`rounded border border-danger/40 bg-danger/10 p-2 text-danger`,children:i})]}),C(`div`,{className:`flex justify-end gap-2 pt-1`,children:[E(`button`,{type:`button`,onClick:t,disabled:r,className:`px-3 py-1.5 text-[11px] rounded bg-surface hover:bg-surface-hover border border-border disabled:opacity-50`,children:`Cancel`}),C(`button`,{type:`button`,onClick:n,disabled:r,className:`inline-flex items-center gap-1.5 px-3 py-1.5 text-[11px] rounded bg-amber-500/20 text-amber-800 hover:bg-amber-500/30 border border-amber-500/40 font-medium disabled:opacity-50`,children:[r?E(B,{className:`w-3 h-3 animate-spin`}):E(k,{className:`w-3 h-3`}),`Update & restart`]})]})]})})}S();function Ne(e){return/fetch failed|failed to fetch|network\s?error|load failed|socket|connection|disconnect|aborted|abort|timeout|timed out|ECONNRESET|ECONNREFUSED|terminated/i.test(e)}function Pe(e,t){let n=e??`hub-only`;return n===`any-node`?!0:n===`hub-only`?t:!t}function Fe(e){let t=e;if(!t?.manifest)return null;let n={...t.manifest,name:t.manifest.name??t.manifest.id,version:t.manifest.version??`0.0.0`,capabilities:t.manifest.capabilities??[]},r=t.process,i=r?{pid:r.pid,mode:r.mode===`forked`?`forked`:`in-process`,state:r.state??`unknown`}:void 0,a=t.health,o=t.declaration?.execution,s=t.manifest.execution,c=o?.placement??s?.placement;return{manifest:n,enabled:!0,source:t.source,installSource:t.installSource,installedOn:[],...i?{process:i}:{},hasBackup:t.hasBackup,...a?{health:a}:{},...c?{placement:c}:{}}}function Ie(e){let t=new Map,n=[];for(let r of e){let e=r.manifest.packageName;if(!e){n.push(r);continue}let i=t.get(e);if(i)i.addons.push(r);else{let n=r.manifest.bundle,i={packageName:e,displayName:n?.displayName??r.manifest.packageDisplayName??r.manifest.name,version:r.manifest.packageVersion,addons:[r],...r.installSource===void 0?{}:{installSource:r.installSource},...n===void 0?{}:{bundle:n}};t.set(e,i)}}let r=[];for(let e of t.values())e.bundle!==void 0||e.addons.length>=2?r.push({bundle:e,representative:e.addons[0]}):r.push(e.addons[0]);return r.push(...n),r}function Q(e){return`bundle`in e}function Le({addons:e,clusterStatus:n,selectedNode:i,onRefresh:a,isRefreshing:o}){let s=ue(),[u,p]=T(``),te=ce(u),[h,g]=T(!1),_=x(null);D(()=>{if(!h)return;let e=e=>{_.current&&!_.current.contains(e.target)&&g(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[h]);let{data:v}=se({nodeId:i.id}),re=w(()=>{let e=new Map;for(let t of v??[])e.set(t.name,t.latestVersion);return e},[v]),[ie,y]=T(()=>new Set),[oe,S]=T(()=>new Map),le=b(e=>{y(t=>new Set(t).add(e))},[]),O=b(e=>{y(t=>{if(!t.has(e))return t;let n=new Set(t);return n.delete(e),n})},[]),de=b((e,t)=>{S(n=>new Map(n).set(e,t))},[]),fe=b(e=>{S(t=>{if(!t.has(e))return t;let n=new Map(t);return n.delete(e),n})},[]),M=t({onMutate:e=>{le(e.name),fe(e.name)},onSuccess:(e,t)=>{O(t.name);let n=e;if(n&&n.success===!1){de(t.name,n.error??`Update failed (no error message returned by server)`);return}s.invalidateQueries({queryKey:[[`addons`]]}),s.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]})},onError:(e,t)=>{O(t.name),de(t.name,e instanceof Error?e.message:String(e))}}),F=xe(),me=x(new Set);D(()=>{let e=new Set;for(let[t,n]of F)q(n)&&e.add(t);let t=[...me.current].some(t=>!e.has(t));me.current=e,t&&(s.invalidateQueries({queryKey:[[`addons`]]}),s.invalidateQueries({queryKey:[[`addons`,`listUpdates`]]}))},[F,s]);let{data:I}=ee(void 0),he=d({onSuccess:()=>{s.invalidateQueries({queryKey:[[`addons`,`getAutoUpdateSettings`]]})}}),{data:L,isFetching:ge}=ae({query:te||void 0},{enabled:h}),R=r(),{data:z}=f(void 0),_e=z?.requestedAt,[V,ve]=T(null),[ye,H]=T(!1);D(()=>{if(z?.kind===`framework-bulk-update`&&z.requestedAt!==V){ve(z.requestedAt),H(!0);let e=window.setTimeout(()=>H(!1),6e3);return()=>window.clearTimeout(e)}},[_e,V,z]);let{data:U}=l(void 0),be=w(()=>new Map((U??[]).map(e=>[e.packageName,e])),[U]),[W,G]=T(null),[K,J]=T(null),Y=x(null),Se=b(()=>{Y.current!==null&&(window.clearTimeout(Y.current),Y.current=null)},[]),Ce=m({onSuccess:()=>{Se(),G(null),s.invalidateQueries({queryKey:[[`addons`]]})},onError:e=>{Se();let t=e instanceof Error?e.message:String(e);if(Ne(t)){G(null),J(null);return}J(t)}}),X=c(),we=b(async()=>{let e=v??[];e.length!==0&&(e.some(e=>e.isSystem)&&!await X({title:`Update all — includes a system package`,message:`This batch updates a system package (@camstack/system). The hub will restart automatically once the framework update completes. In-flight requests are dropped; reconnect typically takes ~10 seconds.`,confirmLabel:`Update all & restart`,variant:`warning`})||await R.mutateAsync({kind:`update`,targets:e.map(e=>({name:e.name,version:e.latestVersion})),nodeIds:[i.id]}))},[v,i.id,R,X]),Z=ne({onSuccess:()=>{s.invalidateQueries({queryKey:[[`addons`]]}),s.invalidateQueries({queryKey:[[`addonPages`]]}),s.invalidateQueries({queryKey:[[`capabilities`]]}),s.invalidateQueries({queryKey:[[`integrations`]]})}}),[Te,Ee]=T(`type`),[De,Oe]=T(()=>typeof window>`u`?`grouped`:window.localStorage.getItem(`camstack.addons.viewMode`)===`flat`?`flat`:`grouped`),Ae=e=>{Oe(e),typeof window<`u`&&window.localStorage.setItem(`camstack.addons.viewMode`,e)},[Fe,Le]=P(),$=Fe.get(`capability`),Re=w(()=>{let t=i.isHub?e:e.filter(e=>Pe(e.placement,i.isHub));return $&&(t=t.filter(e=>(e.manifest.capabilities??[]).some(e=>(typeof e==`string`?e:e.name)===$))),t},[e,i.isHub,$]),ze=()=>{let e=new URLSearchParams(Fe);e.delete(`capability`),Le(e,{replace:!0})},Be=De===`flat`?Re:Ie(Re),Ve=w(()=>{let e=[...Be];switch(Te){case`type`:e.sort((e,t)=>{let n=+!Q(e),r=+!Q(t);if(n!==r)return n-r;let i=Q(e)?e.bundle.displayName:e.manifest.name,a=Q(t)?t.bundle.displayName:t.manifest.name;return i.localeCompare(a)});break;case`name`:e.sort((e,t)=>{let n=Q(e)?e.bundle.displayName:e.manifest.name,r=Q(t)?t.bundle.displayName:t.manifest.name;return n.localeCompare(r)});break;case`source`:e.sort((e,t)=>{let n=Q(e)?e.bundle.installSource??``:e.installSource??``,r=Q(t)?t.bundle.installSource??``:t.installSource??``;return n.localeCompare(r)});break}return e},[Be,Te]);return C(`div`,{className:`space-y-4`,children:[[...oe.entries()].map(([e,t])=>E(`div`,{className:`rounded-md border border-danger/30 bg-danger/5 px-3 py-2 text-[11px]`,children:C(`div`,{className:`flex items-start justify-between gap-3`,children:[C(`div`,{className:`space-y-0.5`,children:[C(`div`,{className:`font-medium text-danger`,children:[`Failed to update `,e]}),E(`div`,{className:`text-foreground-subtle font-mono`,children:t})]}),E(`button`,{type:`button`,onClick:()=>fe(e),className:`text-foreground-subtle hover:text-foreground text-[10px]`,children:`dismiss`})]})},e)),C(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[C(`div`,{className:`flex items-center gap-1.5`,children:[E(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Sort:`}),C(`select`,{value:Te,onChange:e=>Ee(e.target.value),className:`rounded-md border border-border bg-surface px-2 py-1.5 text-[11px] text-foreground focus:outline-none focus:border-primary/50`,children:[E(`option`,{value:`type`,children:`Bundles first`}),E(`option`,{value:`name`,children:`Name`}),E(`option`,{value:`source`,children:`Install source`})]})]}),C(`div`,{className:`flex items-center gap-1.5`,children:[E(`span`,{className:`text-[10px] text-foreground-subtle`,children:`View:`}),E(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`grouped`,`flat`].map(e=>E(`button`,{type:`button`,onClick:()=>Ae(e),className:`px-2.5 py-1.5 transition-colors capitalize ${De===e?`bg-primary/10 text-primary`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`}`,title:e===`grouped`?`Group multi-addon packages into a bundle card`:`Show every addon as its own card`,children:e},e))})]}),i.isHub&&C(`div`,{className:`flex items-center gap-1.5`,children:[E(A,{className:`h-3 w-3 text-foreground-subtle`}),E(`span`,{className:`text-[10px] text-foreground-subtle`,children:`Auto-Update:`}),E(`div`,{className:`flex rounded-md border border-border overflow-hidden text-[10px] font-medium`,children:[`off`,`latest`,`beta`].map(e=>E(`button`,{type:`button`,onClick:()=>he.mutate({channel:e}),disabled:he.isPending,className:`px-2.5 py-1.5 transition-colors capitalize ${I?.channel===e?e===`off`?`bg-gray-700 text-gray-200`:e===`latest`?`bg-blue-500/20 text-blue-400`:`bg-amber-500/20 text-amber-400`:`bg-transparent text-foreground-subtle hover:bg-surface-hover`} ${e===`off`?``:`border-l border-border`}`,children:e},e))})]}),(v?.length??0)>0&&C(`button`,{type:`button`,onClick:()=>void we(),disabled:R.isPending,className:`flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 border border-blue-500/30 disabled:opacity-50 transition-colors font-medium`,children:[R.isPending?E(B,{className:`w-3 h-3 animate-spin`}):E(k,{className:`w-3 h-3`}),R.isPending?`Updating…`:`Update All (${v.length})`]}),C(`button`,{type:`button`,onClick:a,disabled:o||R.isPending,className:`flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,children:[E(A,{className:`w-3 h-3 ${o?`animate-spin`:``}`}),`Refresh`]})]}),C(`div`,{className:`flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3`,children:[C(`div`,{className:`relative flex-1 min-w-0 sm:min-w-[200px]`,ref:_,children:[E(j,{className:`absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-foreground-subtle`}),E(`input`,{type:`text`,value:u,onChange:e=>{p(e.target.value),g(!0)},onFocus:()=>g(!0),placeholder:`Search addons on npm...`,disabled:R.isPending,className:`w-full rounded-lg border border-border bg-background pl-9 pr-3 py-2 text-xs text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary disabled:opacity-50 disabled:cursor-not-allowed`}),ge&&E(B,{className:`absolute right-2.5 top-1/2 -translate-y-1/2 h-3 w-3 text-foreground-subtle animate-spin`}),h&&L&&L.length>0&&C(`div`,{className:`absolute left-0 right-0 top-full mt-1 z-40 rounded-lg border border-border bg-surface shadow-xl overflow-hidden`,children:[L.length>0&&C(`div`,{className:`px-3 py-1.5 text-[10px] uppercase tracking-wide text-foreground-subtle border-b border-border`,children:[`npm results (`,L.length,`)`]}),L&&L.length>0&&E(`div`,{className:`max-h-72 overflow-auto divide-y divide-border`,children:L.map(e=>C(`div`,{className:`flex items-center gap-3 px-3 py-2 hover:bg-surface-hover transition-colors`,children:[E(`div`,{className:`w-6 h-6 rounded-md bg-primary/10 flex items-center justify-center text-primary text-[9px] font-bold shrink-0`,children:e.name.replace(`@camstack/addon-`,``).charAt(0).toUpperCase()}),C(`div`,{className:`flex-1 min-w-0`,children:[C(`div`,{className:`flex items-baseline gap-2 min-w-0`,children:[E(`span`,{className:`text-[11px] font-semibold break-words`,children:e.name.replace(/^@camstack\/(addon-)?/,``)}),C(`span`,{className:`text-[10px] text-foreground-subtle shrink-0`,children:[`v`,e.version]})]}),E(`div`,{className:`font-mono text-[9px] text-foreground-subtle/80 truncate`,children:e.name}),e.description&&E(`div`,{className:`text-[10px] text-foreground-subtle truncate`,children:e.description})]}),e.installed?C(`span`,{className:`inline-flex items-center gap-1 px-2 py-1 text-[10px] font-medium rounded-md border border-emerald-500/30 bg-emerald-500/10 text-emerald-400 shrink-0`,children:[E(N,{className:`h-3 w-3`}),e.installedVersion??`Installed`]}):C(`button`,{type:`button`,onClick:()=>Z.mutate({packageName:e.name}),disabled:Z.isPending,className:`inline-flex items-center gap-1 px-2 py-1 text-[10px] font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors shrink-0`,children:[Z.isPending?E(B,{className:`h-3 w-3 animate-spin`}):E(k,{className:`h-3 w-3`}),`Install`]})]},e.name))})]})]}),E(je,{onUploadSuccess:()=>{s.invalidateQueries({queryKey:[[`addons`]]}),a()}})]}),$&&C(`div`,{className:`flex items-center gap-2 px-3 py-2 rounded-lg bg-primary/10 border border-primary/30 text-sm`,children:[E(`span`,{className:`text-foreground-subtle`,children:`Filtering by capability:`}),E(`span`,{className:`font-mono text-primary font-semibold`,children:$}),E(`button`,{type:`button`,onClick:ze,className:`ml-auto text-xs text-foreground-subtle hover:text-foreground underline`,children:`Clear`})]}),ye&&C(`div`,{className:`fixed top-4 right-4 z-50 flex items-start gap-2 px-3 py-2.5 rounded-md border border-green-500/30 bg-green-500/10 shadow-lg backdrop-blur-sm max-w-sm pointer-events-auto`,children:[E(pe,{className:`w-4 h-4 shrink-0 mt-0.5 text-green-400`}),C(`div`,{children:[E(`div`,{className:`text-[11px] font-semibold text-foreground`,children:`Bulk update completed`}),E(`div`,{className:`text-[10px] text-foreground-subtle mt-0.5`,children:`System packages updated — hub restarted successfully.`})]})]}),Re.length===0&&E(`div`,{className:`text-xs text-foreground-subtle`,children:e.length===0?`No addons installed`:$?`No installed addons declare the "${$}" capability. Browse the npm catalog above to find a compatible addon.`:`No addons compatible with ${i.name} (placement filter active)`}),E(`div`,{className:`space-y-2`,children:Ve.map(e=>{let t=Q(e)?e.bundle.packageName:e.manifest.packageName,r=re.get(t),a=Q(e)?e.representative:e,o=be.has(t),s=r?o?e=>G({packageName:t,fromVersion:be.get(t)?.currentVersion??a.manifest.packageVersion??a.manifest.version,toVersion:e}):e=>M.mutate({name:t,version:e,nodeId:i.id}):void 0,c=F.get(t)??null,l=c!==null&&q(c);return E(ke,{addon:a,clusterStatus:n?.[a.manifest.id],bundle:Q(e)?e.bundle:void 0,availableUpdate:r,isUpdating:ie.has(t)||l,jobProgress:c,onUpdate:s,isSystem:o,disabledByBulk:R.isPending},Q(e)?t:e.manifest.id)})}),W!==null&&E(Me,{pending:W,onCancel:()=>{G(null),J(null)},onConfirm:()=>{J(null),Ce.mutate({packageName:W.packageName,version:W.toVersion}),Se(),Y.current=window.setTimeout(()=>{Y.current=null,G(null),J(null)},15e3)},isPending:Ce.isPending,error:K})]})}function $(){let t=ue(),{data:n,isLoading:r,isError:a}=te(),{data:s}=e(void 0),{data:c}=i(void 0,{refetchInterval:1e4}),l=w(()=>{let e=new Map;e.set(`hub`,{id:`hub`,name:`Hub`,isHub:!0});for(let t of c??[]){let n=String(t.id??``);n&&e.set(n,{id:n,name:String(t.name??n),isHub:!!t.isHub})}return[...e.values()]},[c]),[d,ee]=T(`hub`),f=l.find(e=>e.id===d)??l[0],p=h(),m=u(),g=p.isPending||m.isPending,ne=async()=>{await p.mutateAsync({nodeId:d}),await m.mutateAsync(),t.invalidateQueries({queryKey:[[`addons`]]})},_=x(p);_.current=p,D(()=>{_.current.mutate({nodeId:`hub`})},[]);let v=(n??[]).map(Fe).filter(e=>e!==null);return C(V,{children:[C(`div`,{className:`flex items-center justify-between gap-3 flex-wrap`,children:[E(o,{selectedNodeId:d,onSelect:ee}),C(`div`,{className:`flex items-center gap-3 flex-wrap`,children:[!r&&!a&&C(`span`,{className:`text-[10px] rounded-full bg-primary/10 text-primary px-2 py-0.5 font-medium`,children:[v.length,` installed`]}),C(`button`,{type:`button`,onClick:()=>void ne(),disabled:g,className:`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] rounded-md bg-surface hover:bg-surface-hover border border-border disabled:opacity-50 transition-colors`,title:`Re-fetch addons + check npm for new versions`,children:[E(A,{className:`w-3 h-3 ${g?`animate-spin`:``}`}),`Check for updates`]})]})]}),!f.isHub&&C(`div`,{className:`rounded-md border border-warning/30 bg-warning/5 px-3 py-2 text-[11px] text-foreground-subtle`,children:[`Showing only addons compatible with`,` `,E(`span`,{className:`font-medium text-foreground`,children:f.name}),` — agents only run`,` `,E(`code`,{className:`font-mono`,children:`agent-only`}),` and`,` `,E(`code`,{className:`font-mono`,children:`any-node`}),` addons. Install / uninstall is hub-driven; agents auto-sync from the hub.`]}),r&&E(`div`,{className:`text-xs text-foreground-subtle animate-pulse`,children:`Loading…`}),a&&E(`div`,{className:`text-xs text-danger`,children:`Failed to load addons`}),!r&&!a&&E(Le,{addons:v,clusterStatus:s,selectedNode:f,onRefresh:()=>void ne(),isRefreshing:g})]})}export{$ as AddonsPage};
@@ -1 +0,0 @@
1
- import{Fr as e,Ir as t,Lr as n,Mr as r,Nr as i,Pr as a,Tr as o,Yi as s,_a as c,ea as l,ei as u,g as d,ga as f,ha as p,hi as m,jr as h,m as g,ma as _,na as v,wr as y}from"./src-D37vd48r.js";import{I as b,K as x,Q as S,S as C,W as w,o as T,q as E,x as D,z as O}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DTufy7Ue.js";import{p as k}from"./player-overlays-2Q1miaEN.js";import{t as A}from"./pencil-D-LLTb5E.js";import{t as j}from"./radio-DqOn-16x.js";import{t as M}from"./refresh-cw-DuM6oiTl.js";import{t as N}from"./rotate-cw-8j5op9rY.js";import{t as P}from"./server-BKvjFwOh.js";import{t as F}from"./upload-B9TkBT8Q.js";import{F as I,L,M as R,P as z,V as B,i as V,k as H,o as U,p as W,s as G,x as K}from"./index-ByJMV5aQ.js";import{n as q,t as J}from"./build-cluster-graph-QwpFUUjE.js";import{t as Y}from"./format-size-CO9d3C3-.js";import{t as X}from"./NodeAddonsSettingsPanel-DLEbHtxx.js";var Z=B(`git-fork`,[[`circle`,{cx:`12`,cy:`18`,r:`3`,key:`1mpf1b`}],[`circle`,{cx:`6`,cy:`6`,r:`3`,key:`1lh9wr`}],[`circle`,{cx:`18`,cy:`6`,r:`3`,key:`1h7g24`}],[`path`,{d:`M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9`,key:`1uq4wg`}],[`path`,{d:`M12 12v3`,key:`158kv8`}]]),Q=B(`memory-stick`,[[`path`,{d:`M6 19v-3`,key:`1nvgqn`}],[`path`,{d:`M10 19v-3`,key:`iu8nkm`}],[`path`,{d:`M14 19v-3`,key:`kcehxu`}],[`path`,{d:`M18 19v-3`,key:`1vh91z`}],[`path`,{d:`M8 11V9`,key:`63erz4`}],[`path`,{d:`M16 11V9`,key:`fru6f3`}],[`path`,{d:`M12 11V9`,key:`ha00sb`}],[`path`,{d:`M2 15h20`,key:`16ne18`}],[`path`,{d:`M2 7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v1.1a2 2 0 0 0 0 3.837V17a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-5.1a2 2 0 0 0 0-3.837Z`,key:`lhddv3`}]]),$=B(`skull`,[[`path`,{d:`m12.5 17-.5-1-.5 1h1z`,key:`3me087`}],[`path`,{d:`M15 22a1 1 0 0 0 1-1v-1a2 2 0 0 0 1.56-3.25 8 8 0 1 0-11.12 0A2 2 0 0 0 8 20v1a1 1 0 0 0 1 1z`,key:`1o5pge`}],[`circle`,{cx:`15`,cy:`12`,r:`1`,key:`1tmaij`}],[`circle`,{cx:`9`,cy:`12`,r:`1`,key:`1vctgf`}]]),ee=B(`table-2`,[[`path`,{d:`M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18`,key:`gugj83`}]]);S();function te(e){let t=new FormData;return t.append(`file`,e.file,e.file.name),t.append(`nodeId`,e.nodeId),e.addonId&&t.append(`addonId`,e.addonId),new Promise((n,r)=>{let i=new XMLHttpRequest;i.open(`POST`,`/api/addons/upload`),e.token&&i.setRequestHeader(`Authorization`,`Bearer ${e.token}`),i.upload.addEventListener(`progress`,t=>{t.lengthComputable&&e.onProgress(Math.round(t.loaded/t.total*100))}),i.addEventListener(`load`,()=>{let e;try{e=JSON.parse(i.responseText)}catch{r(Error(`HTTP ${i.status}`));return}i.status>=200&&i.status<300?n(e):r(Error(e.error??`HTTP ${i.status}`))}),i.addEventListener(`error`,()=>r(Error(`Network error during upload`))),i.addEventListener(`abort`,()=>r(Error(`Upload aborted`))),i.send(t)})}function ne({nodeId:e,addons:t,isHub:r}){let a=T(),o=s(),[c,l]=E(null),[u,d]=E(null),[f,p]=E(!1),[m,g]=E(null),[_,v]=E(0),y=x(null),b=i(),S=n(),w=h({nodeId:e}),O=w.data??[],k=new Map(t.map(e=>[e.id,e.capabilities])),A=O.length>0?O.map(e=>({id:e.id,status:e.status,capabilities:k.get(e.id)??[],version:e.version,packageName:e.packageName})):t.map(e=>({id:e.id,status:e.status,capabilities:e.capabilities,version:void 0,packageName:void 0})),j=()=>{a.invalidateQueries({queryKey:[[`nodes`,`topology`]]}),w.refetch()},M=async t=>{l(t);try{await b.mutateAsync({nodeId:e,addonId:t}),j()}catch(e){console.error(`Failed to restart addon:`,e)}finally{l(null)}},P=async t=>{if(await o({title:`Uninstall addon`,message:`Remove "${t}" from ${e}? The addon directory will be deleted on disk.`,confirmLabel:`Uninstall`,variant:`danger`})){d(t);try{await S.mutateAsync({nodeId:e,addonId:t}),j()}catch(e){console.error(`Failed to uninstall addon:`,e)}finally{d(null)}}},I=C(`div`,{className:`flex items-center gap-2 mb-2`,children:[D(`input`,{ref:y,type:`file`,accept:`.tgz,.tar.gz`,className:`hidden`,onChange:async t=>{let n=t.target.files?.[0];if(n){t.target.value=``,g(null),p(!0),v(0);try{await te({file:n,nodeId:e,token:localStorage.getItem(`camstack_admin_token`),onProgress:v}),j()}catch(e){g(e instanceof Error?e.message:String(e))}finally{p(!1),v(0)}}}}),C(`button`,{onClick:()=>y.current?.click(),disabled:f,className:`inline-flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1 text-[11px] font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors disabled:opacity-50`,children:[f?D(K,{className:`h-3 w-3 animate-spin`}):D(F,{className:`h-3 w-3`}),f?`Uploading… ${_}%`:`Upload addon (.tgz)`]}),f&&D(`div`,{className:`flex-1 h-1 rounded-full bg-muted overflow-hidden max-w-[140px]`,children:D(`div`,{className:`h-full bg-primary transition-all`,style:{width:`${_}%`}})}),m&&D(`span`,{className:`text-[10px] text-destructive`,children:m})]});return A.length===0?C(`div`,{children:[I,D(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:w.isLoading?`Loading addons…`:`No addons on this node`})]}):C(`div`,{children:[I,C(`table`,{className:`w-full text-xs`,children:[D(`thead`,{children:C(`tr`,{className:`text-muted-foreground text-left`,children:[D(`th`,{className:`py-2 font-medium`,children:`Addon`}),D(`th`,{className:`py-2 font-medium`,children:`Version`}),D(`th`,{className:`py-2 font-medium`,children:`Capabilities`}),D(`th`,{className:`py-2 font-medium`,children:`Status`}),D(`th`,{className:`py-2 font-medium w-16`})]})}),D(`tbody`,{children:A.map(e=>C(`tr`,{className:`border-t border-border/50`,children:[C(`td`,{className:`py-2 font-medium`,children:[D(`div`,{children:e.id}),e.packageName&&D(`div`,{className:`text-[9px] text-muted-foreground`,children:e.packageName})]}),D(`td`,{className:`py-2 text-muted-foreground`,children:e.version??`—`}),D(`td`,{className:`py-2`,children:D(`div`,{className:`flex flex-wrap gap-1`,children:e.capabilities.length>0?e.capabilities.map(e=>D(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-blue-500/10 text-blue-400`,children:e},e)):D(`span`,{className:`text-muted-foreground`,children:`—`})})}),D(`td`,{className:`py-2`,children:D(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded-full ${e.status===`running`?`bg-success/10 text-success`:e.status===`error`?`bg-destructive/10 text-destructive`:`bg-muted text-muted-foreground`}`,children:e.status})}),D(`td`,{className:`py-2`,children:C(`div`,{className:`flex items-center gap-1 justify-end`,children:[D(`button`,{onClick:()=>M(e.id),disabled:c===e.id||u===e.id,className:`p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart ${e.id}`,children:D(N,{className:`h-3 w-3 ${c===e.id?`animate-spin`:``}`})}),D(`button`,{onClick:()=>P(e.id),disabled:c===e.id||u===e.id,className:`p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-50`,title:`Uninstall ${e.id}`,children:u===e.id?D(K,{className:`h-3 w-3 animate-spin`}):D(G,{className:`h-3 w-3`})})]})})]},e.id))})]})]})}S();function re(e){if(e<60)return`${e}s`;let t=Math.floor(e/60);if(t<60)return`${t}m`;let n=Math.floor(t/60);return n<24?`${n}h ${t%60}m`:`${Math.floor(n/24)}d ${n%24}h`}function ie({state:e}){return D(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded-full ${e===`running`?`bg-success/10 text-success`:e===`crashed`||e===`failed`?`bg-destructive/10 text-destructive`:`bg-muted text-muted-foreground`}`,children:e})}var ae=[`trace`,`debug`,`info`,`warn`,`error`];function oe({proc:t,nodeId:n,defaultExpanded:r,activePanel:o,onTogglePanel:s}){let l=t.services??[],u=l.length===1,[m,h]=E(u||r),[v,y]=E(null),[b,x]=E(`info`),S=t.name.includes(`(core)`),w=i(),T=a(),O=e(),k=async e=>{y(e);try{await w.mutateAsync({nodeId:n,addonId:e})}catch(e){console.error(`Failed to restart addon:`,e)}finally{y(null)}},A=async()=>{y(t.name);try{await T.mutateAsync({nodeId:n,processName:t.name})}catch(e){console.error(`Failed to restart process:`,e)}finally{y(null)}},M=async e=>{let r=`${n}/${t.name}`;try{await O.mutateAsync({nodeId:r,level:e}),x(e)}catch(e){console.error(`Failed to set log level:`,e)}};return C(`div`,{className:`border border-border/50 rounded-lg overflow-hidden`,children:[C(`div`,{role:u?void 0:`button`,tabIndex:u?void 0:0,onClick:u?void 0:()=>h(!m),onKeyDown:u?void 0:e=>{(e.key===`Enter`||e.key===` `)&&h(!m)},className:`flex items-center gap-2 w-full px-3 py-2 bg-muted/20 transition-colors text-left select-none ${u?``:`hover:bg-muted/40 cursor-pointer`}`,children:[u?D(`span`,{className:`h-3 w-3 shrink-0`}):D(m?z:R,{className:`h-3 w-3 text-muted-foreground shrink-0`}),S?D(P,{className:`h-3.5 w-3.5 text-primary shrink-0`}):D(L,{className:`h-3.5 w-3.5 text-amber-500 shrink-0`}),D(`span`,{className:`text-xs font-semibold flex-1`,children:t.name}),C(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[`PID `,t.pid]}),D(ie,{state:t.state}),C(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[t.cpuPercent,`% CPU`]}),D(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:Y(t.memoryRss)}),D(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:re(t.uptimeSeconds)}),!S&&C(`div`,{className:`flex items-center gap-1`,onClick:e=>e.stopPropagation(),children:[C(_,{children:[D(c,{className:`text-[9px] px-1.5 py-0.5 rounded border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors font-mono`,title:`Set log level`,children:b}),D(p,{align:`end`,className:`min-w-[70px] py-0.5`,children:ae.map(e=>D(f,{onClick:()=>M(e),className:`h-auto px-2 py-1 text-[10px] font-mono ${e===b?`text-primary font-semibold`:``}`,children:e},e))})]}),D(`button`,{onClick:A,disabled:v===t.name,className:`p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart process`,children:D(N,{className:`h-3 w-3 ${v===t.name?`animate-spin`:``}`})})]})]}),m&&l.length>0&&D(`div`,{className:`divide-y divide-border/30`,children:l.map(e=>C(`div`,{children:[C(`div`,{className:`flex items-center gap-2 px-3 py-1.5 pl-9 hover:bg-muted/10 transition-colors`,children:[D(`div`,{className:`h-1.5 w-1.5 rounded-full shrink-0 ${e.status===`running`?`bg-success`:`bg-muted-foreground/30`}`}),D(`span`,{className:`text-xs font-medium flex-1 min-w-0 truncate`,children:e.addonId}),e.capabilities.length>0&&C(`div`,{className:`flex gap-1 flex-shrink-0`,children:[e.capabilities.slice(0,3).map(e=>D(`span`,{className:`text-[9px] px-1 py-0.5 rounded bg-blue-500/10 text-blue-400 truncate max-w-[80px]`,children:e},e)),e.capabilities.length>3&&C(`span`,{className:`text-[9px] text-muted-foreground`,children:[`+`,e.capabilities.length-3]})]}),C(`div`,{className:`flex items-center gap-1 shrink-0`,children:[D(`button`,{onClick:()=>s(e.addonId,`logs`),className:`p-0.5 rounded transition-colors ${o?.addonId===e.addonId&&o.type===`logs`?`bg-primary/10 text-primary`:`hover:bg-muted text-muted-foreground hover:text-foreground`}`,title:`Show logs for ${e.addonId}`,children:D(W,{className:`h-3 w-3`})}),D(`button`,{onClick:()=>s(e.addonId,`events`),className:`p-0.5 rounded transition-colors ${o?.addonId===e.addonId&&o.type===`events`?`bg-primary/10 text-primary`:`hover:bg-muted text-muted-foreground hover:text-foreground`}`,title:`Show events for ${e.addonId}`,children:D(j,{className:`h-3 w-3`})}),D(`button`,{onClick:()=>k(e.addonId),disabled:v===e.addonId,className:`p-0.5 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50`,title:`Restart ${e.addonId}`,children:D(N,{className:`h-3 w-3 ${v===e.addonId?`animate-spin`:``}`})})]})]}),o?.addonId===e.addonId&&o.type===`logs`&&D(`div`,{className:`border-t border-border/40 bg-muted/5`,children:D(d,{addonId:e.addonId,agentId:n,maxHeight:`max-h-48`,showFilters:!1,onClose:()=>s(e.addonId,`logs`)})}),o?.addonId===e.addonId&&o.type===`events`&&D(`div`,{className:`border-t border-border/40 bg-muted/5`,children:D(g,{addonId:e.addonId,category:`addon.*`,maxHeight:`max-h-48`,onClose:()=>s(e.addonId,`events`)})})]},e.addonId))}),m&&l.length===0&&D(`div`,{className:`px-3 py-2 pl-9 text-[10px] text-muted-foreground`,children:`No services`})]})}function se({nodeId:e,processes:t}){let[n,r]=E(null),i=(e,t)=>{r(n=>n?.addonId===e&&n.type===t?null:{addonId:e,type:t})};return t.length===0?D(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No processes on this node`}):D(`div`,{className:`space-y-2 py-1`,children:t.map((t,r)=>D(oe,{proc:t,nodeId:e,defaultExpanded:r===0,activePanel:n,onTogglePanel:i},t.name))})}S();function ce(e){return e<60?`${e}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:e<86400?`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`:`${Math.floor(e/86400)}d ${Math.floor(e%86400/3600)}h`}function le(e,t=80){return e.length<=t?e:`…${e.slice(e.length-t+1)}`}function ue({nodeId:e}){let t=T(),n=s(),[r,i]=E(`all`),a=l(`metrics.node-processes-snapshot`,t=>t.nodeId===e),{data:c}=o({nodeId:e}),u=a?.processes??c,d=w(()=>u?[...u]:[],[u]),f=w(()=>r===`ghost`?d.filter(e=>e.classification===`ghost`):d,[d,r]),p=w(()=>{let e=d.filter(e=>e.classification===`ghost`),t=new Map;for(let n of e)t.has(n.ppid)||t.set(n.ppid,[]),t.get(n.ppid).push(n);return[...t.entries()].filter(([,e])=>e.length>1).map(([e,t])=>({ppid:e,children:t})).toSorted((e,t)=>t.children.length-e.children.length)},[d]),m=y({onSettled:()=>{t.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]})}}),h=w(()=>{let e=new Map;for(let t of d)e.set(t.pid,t.classification);return e},[d]),g=async(t,r)=>{if(t.classification===`root`||t.classification===`system`)return;let i=t.classification===`ghost`?`ghost`:t.addonId??`process`,a=r?`SIGKILL`:`SIGTERM`;await n({title:`Send ${a}?`,message:`Target pid ${t.pid} (${i}) on node ${e}.`,confirmLabel:`Send ${a}`,variant:`danger`})&&m.mutate({nodeId:e,pid:t.pid,force:r})},_=async(t,n)=>{try{await m.mutateAsync({nodeId:e,pid:t,force:n})}catch{}},v=async r=>{let i=h.get(r.ppid);if(i===`root`||i===`system`){await n({title:`Cannot kill protected ancestor`,message:i===`root`?`pid ${r.ppid} is the current node supervisor. Restart the node via the cluster page instead.`:`pid ${r.ppid} is a system ancestor (concurrently / vite / npm wrapper). Killing it would tear down the dev tree.`,confirmLabel:`OK`,cancelLabel:`Close`,variant:`warning`});return}await n({title:`Kill ghost parent + ${r.children.length} child(ren)?`,message:`SIGKILL parent pid ${r.ppid} and SIGTERM ${r.children.length} ghost child(ren) on node ${e}.`,confirmLabel:`Kill all`,variant:`danger`})&&(await Promise.all([_(r.ppid,!0),...r.children.map(e=>_(e.pid,!1))]),t.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]}))},b=async()=>{let r=d.filter(e=>e.classification===`ghost`);r.length!==0&&await n({title:`Kill all ${r.length} ghost process(es)?`,message:`SIGKILL ${r.length} ghost process(es) on node ${e}. This is irreversible.`,confirmLabel:`Kill all`,variant:`danger`})&&(await Promise.all(r.map(e=>_(e.pid,!0))),t.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]}))},x=d.filter(e=>e.classification===`ghost`).length,S=d.filter(e=>e.classification===`managed`).length,O=d.filter(e=>e.classification===`root`).length,k=d.filter(e=>e.classification===`system`).length;return C(`div`,{className:`space-y-4`,children:[C(`div`,{className:`flex items-start justify-between gap-4`,children:[C(`p`,{className:`text-[11px] text-foreground-subtle`,children:[`ps`," scan + kernel `$process.list` cross-reference. Ghosts = camstack-shaped commands with no managed binding (usually orphaned to ppid=1). Refreshes every 10s."]}),C(`button`,{type:`button`,onClick:()=>t.invalidateQueries({queryKey:[[`metricsProvider`,`listNodeProcesses`]]}),className:`inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[11px] text-foreground hover:bg-surface-hover`,children:[D(M,{className:`h-3 w-3`}),` Refresh`]})]}),C(`div`,{className:`grid grid-cols-4 gap-3`,children:[C(`div`,{className:`rounded-lg border border-border p-3`,children:[D(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:`Root`}),D(`div`,{className:`text-xl font-semibold text-foreground`,children:O})]}),C(`div`,{className:`rounded-lg border border-border p-3`,children:[D(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:`Managed`}),D(`div`,{className:`text-xl font-semibold text-foreground`,children:S})]}),C(`div`,{className:`rounded-lg border border-border p-3`,children:[D(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle`,children:`System`}),D(`div`,{className:`text-xl font-semibold text-foreground`,children:k})]}),C(`div`,{className:`rounded-lg border p-3 ${x>0?`border-destructive/40 bg-destructive/5`:`border-border`}`,children:[C(`div`,{className:`text-[10px] uppercase tracking-wider text-foreground-subtle flex items-center gap-1`,children:[x>0&&D($,{className:`h-3 w-3 text-destructive`}),` Ghosts`]}),D(`div`,{className:`text-xl font-semibold ${x>0?`text-destructive`:`text-foreground`}`,children:x})]})]}),p.length>0&&C(`div`,{className:`rounded-lg border border-amber-500/40 bg-amber-500/5 p-3`,children:[C(`div`,{className:`flex items-center gap-1 text-[11px] font-semibold text-amber-400 mb-2`,children:[D(U,{className:`h-3 w-3`}),` Recurring ghost parents (`,p.length,`)`]}),D(`div`,{className:`space-y-1.5`,children:p.map(e=>C(`div`,{className:`text-[11px] text-foreground flex items-center justify-between gap-2`,children:[C(`div`,{className:`flex items-center gap-2`,children:[C(`span`,{className:`font-mono text-foreground-subtle`,children:[`ppid `,e.ppid]}),C(`span`,{children:[`→ `,e.children.length,` ghost(s)`]})]}),C(`button`,{type:`button`,disabled:m.isPending,onClick:()=>{v(e)},className:`inline-flex items-center gap-1 rounded border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-[10px] text-amber-400 hover:bg-amber-500/20 disabled:opacity-30`,children:[D($,{className:`h-3 w-3`}),` Kill parent + `,e.children.length]})]},e.ppid))})]}),C(`div`,{className:`flex items-center justify-between gap-2 text-[11px]`,children:[C(`div`,{className:`flex items-center gap-2`,children:[D(`span`,{className:`text-foreground-subtle`,children:`Filter:`}),C(`button`,{type:`button`,className:`px-2 py-0.5 rounded ${r===`all`?`bg-primary text-primary-foreground`:`border border-border text-foreground hover:bg-surface-hover`}`,onClick:()=>i(`all`),children:[`All (`,d.length,`)`]}),C(`button`,{type:`button`,className:`px-2 py-0.5 rounded ${r===`ghost`?`bg-destructive text-destructive-foreground`:`border border-border text-foreground hover:bg-surface-hover`}`,onClick:()=>i(`ghost`),children:[`Ghost only (`,x,`)`]})]}),x>0&&C(`button`,{type:`button`,disabled:m.isPending,onClick:()=>{b()},className:`inline-flex items-center gap-1 rounded border border-destructive/40 bg-destructive/10 px-2 py-1 text-[11px] font-medium text-destructive hover:bg-destructive/20 disabled:opacity-30`,children:[D($,{className:`h-3 w-3`}),` Kill all `,x,` ghost(s)`]})]}),D(`div`,{className:`rounded-lg border border-border overflow-x-auto`,children:C(`table`,{className:`w-full text-xs`,children:[D(`thead`,{className:`bg-surface`,children:C(`tr`,{className:`text-foreground-subtle text-[10px] uppercase tracking-wider`,children:[D(`th`,{className:`text-left px-3 py-2`,children:`Class`}),D(`th`,{className:`text-right px-3 py-2`,children:`PID`}),D(`th`,{className:`text-right px-3 py-2`,children:`PPID`}),D(`th`,{className:`text-left px-3 py-2`,children:`Addon`}),D(`th`,{className:`text-left px-3 py-2`,children:`Command`}),D(`th`,{className:`text-right px-3 py-2`,children:`CPU%`}),D(`th`,{className:`text-right px-3 py-2`,children:`RSS`}),D(`th`,{className:`text-right px-3 py-2`,children:`Uptime`}),D(`th`,{className:`w-44`})]})}),C(`tbody`,{children:[f.length===0&&D(`tr`,{children:D(`td`,{colSpan:9,className:`px-3 py-4 text-center text-foreground-subtle text-[11px]`,children:r===`ghost`?`No ghost processes detected.`:`Scanning…`})}),f.map(e=>C(`tr`,{className:`border-t border-border ${e.classification===`ghost`?`bg-destructive/5`:``}`,children:[D(`td`,{className:`px-3 py-2`,children:D(`span`,{className:`inline-block rounded-full px-1.5 py-0.5 text-[10px] font-medium ${e.classification===`ghost`?`bg-destructive/20 text-destructive`:e.classification===`root`?`bg-sky-500/20 text-sky-400`:e.classification===`system`?`bg-foreground-subtle/20 text-foreground-subtle`:`bg-success/20 text-success`}`,children:e.classification})}),D(`td`,{className:`px-3 py-2 text-right font-mono text-foreground`,children:e.pid}),C(`td`,{className:`px-3 py-2 text-right font-mono text-foreground-subtle`,children:[e.ppid,e.orphaned?` ⚠`:``]}),D(`td`,{className:`px-3 py-2 text-foreground-subtle text-[11px]`,children:e.addonId??`—`}),D(`td`,{className:`px-3 py-2 font-mono text-[10px] text-foreground-subtle break-all`,children:le(e.command)}),D(`td`,{className:`px-3 py-2 text-right text-foreground`,children:e.cpuPercent.toFixed(1)}),D(`td`,{className:`px-3 py-2 text-right text-foreground`,children:Y(e.memoryRssBytes)}),D(`td`,{className:`px-3 py-2 text-right text-foreground-subtle`,children:ce(e.uptimeSec)}),D(`td`,{className:`px-3 py-2 text-right`,children:C(`div`,{className:`inline-flex gap-1`,children:[C(`button`,{type:`button`,disabled:m.isPending||e.classification===`root`||e.classification===`system`,onClick:()=>{g(e,!1)},title:`SIGTERM`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 rounded border border-border text-[10px] text-foreground hover:bg-surface-hover disabled:opacity-30`,children:[D(G,{className:`h-3 w-3`}),` Term`]}),C(`button`,{type:`button`,disabled:m.isPending||e.classification===`root`||e.classification===`system`,onClick:()=>{g(e,!0)},title:`SIGKILL`,className:`inline-flex items-center gap-1 px-1.5 py-0.5 rounded border border-destructive/30 text-[10px] text-destructive hover:bg-destructive/10 disabled:opacity-30`,children:[D($,{className:`h-3 w-3`}),` Kill`]})]})})]},e.pid))]})]})}),m.isError&&C(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-[11px] text-destructive`,children:[`Kill failed:`,` `,m.error instanceof Error?m.error.message:`unknown`]})]})}function de({nodeId:e,addonIds:t}){return t.length===0?D(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No addons on this node`}):D(`div`,{className:`w-full py-2`,children:D(X,{nodeId:e,addonIds:t,level:`global`})})}S();function fe({nodeId:e,addons:t}){let n=T(),{data:r,isLoading:i}=u({nodeId:e}),a=w(()=>{let e=new Map;for(let n of t)for(let t of n.capabilities){let r=e.get(t)??[];r.push(n.id),e.set(t,r)}return[...e.entries()].toSorted(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({capName:e,providers:t}))},[t]),o=m({onSuccess:()=>{n.invalidateQueries({queryKey:[[`pipelineOrchestrator`,`getCapabilityBindings`]]})}});return a.length===0?D(`div`,{className:`py-4 text-xs text-muted-foreground text-center`,children:`No capabilities on this node`}):C(`table`,{className:`w-full text-xs`,children:[D(`thead`,{children:C(`tr`,{className:`text-muted-foreground text-left`,children:[D(`th`,{className:`py-2 font-medium w-1/2`,children:`Capability`}),D(`th`,{className:`py-2 font-medium`,children:`Bound provider`})]})}),D(`tbody`,{children:a.map(({capName:t,providers:n})=>{let a=r?.[t]??n[0]??``,s=n.length===1;return C(`tr`,{className:`border-t border-border/50`,children:[D(`td`,{className:`py-2 font-medium`,children:t}),D(`td`,{className:`py-2`,children:D(`select`,{value:a,onChange:n=>o.mutate({nodeId:e,capName:t,addonId:n.target.value}),disabled:s||o.isPending||i,className:`w-full rounded-md border border-border bg-surface px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary disabled:opacity-60`,title:s?`Only one provider installed — choice becomes available once a second addon registers this capability`:void 0,children:n.map(e=>D(`option`,{value:e,children:e},e))})})]},t)})})]})}S();function pe(e){if(e==null)return`—`;let t=Math.floor(e/1e3),n=Math.floor(t/86400),r=Math.floor(t%86400/3600),i=Math.floor(t%3600/60);return n>0?`${n}d ${r}h ${i}m`:r>0?`${r}h ${i}m`:`${i}m`}function me(e){let[t,n]=E(!1),[i,a]=E(e.name),o=T(),s=r({onSuccess:()=>{o.invalidateQueries({queryKey:[[`nodes`,`topology`]]})}}),c=(e.localIps??[]).filter(e=>!e.includes(`:`)),l=(e.localIps??[]).filter(e=>e.includes(`:`)),u=async()=>{if(!i.trim()||i===e.name){n(!1);return}try{await s.mutateAsync({nodeId:e.nodeId,name:i.trim()}),n(!1)}catch(e){console.error(`Rename failed:`,e)}},d=[[`Node ID`,D(`span`,{className:`font-mono text-xs`,children:e.nodeId})],[`Display Name`,t?C(`div`,{className:`flex items-center gap-1.5`,children:[D(`input`,{type:`text`,className:`flex-1 px-2 py-0.5 text-xs border border-border rounded bg-background focus:outline-none focus:ring-1 focus:ring-primary`,value:i,onChange:e=>a(e.target.value),onKeyDown:e=>{e.key===`Enter`&&u(),e.key===`Escape`&&n(!1)},disabled:s.isPending,autoFocus:!0}),D(`button`,{onClick:()=>void u(),disabled:s.isPending,className:`p-0.5 text-success hover:bg-success/10 rounded`,title:`Save`,children:D(I,{className:`h-3.5 w-3.5`})}),D(`button`,{onClick:()=>n(!1),className:`p-0.5 text-muted-foreground hover:bg-muted rounded`,title:`Cancel`,children:D(V,{className:`h-3.5 w-3.5`})})]}):C(`div`,{className:`flex items-center gap-1.5`,children:[D(`span`,{className:`text-xs`,children:e.name}),!e.isHub&&D(`button`,{onClick:()=>{a(e.name),n(!0)},className:`p-0.5 text-muted-foreground hover:text-primary rounded`,title:`Rename`,children:D(A,{className:`h-3 w-3`})})]})],[`Hostname`,D(`span`,{className:`text-xs`,children:e.hostname})],[`Role`,e.isHub?D(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-primary/10 text-primary font-medium`,children:`Hub`}):D(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-medium`,children:`Agent`})],[`Platform`,C(`span`,{className:`text-xs`,children:[e.platform,` / `,e.arch]})],[`CPU`,C(`span`,{className:`text-xs`,children:[e.cpuModel??`—`,` (`,e.cpuCores,` cores)`]})],[`Memory`,D(`span`,{className:`text-xs`,children:e.memoryMB>0?`${(e.memoryMB/1024).toFixed(1)} GB`:`—`})],[`Uptime`,D(`span`,{className:`text-xs`,children:pe(e.uptime)})],[`Engines`,e.engines.length>0?D(`div`,{className:`flex flex-wrap gap-1`,children:e.engines.map(e=>D(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e))}):D(`span`,{className:`text-xs text-muted-foreground`,children:`—`})]];return c.length>0&&d.push([`IPv4`,D(`div`,{className:`flex flex-wrap gap-1.5`,children:c.map((e,t)=>D(`span`,{className:`font-mono text-xs px-1.5 py-0.5 rounded bg-muted`,children:e},`${e}-${t}`))})]),l.length>0&&d.push([`IPv6`,D(`div`,{className:`flex flex-wrap gap-1.5`,children:l.map((e,t)=>D(`span`,{className:`font-mono text-[10px] px-1.5 py-0.5 rounded bg-muted truncate max-w-[280px]`,title:e,children:e},`${e}-${t}`))})]),D(`div`,{className:`py-2`,children:D(`table`,{className:`w-full text-sm`,children:D(`tbody`,{children:d.map(([e,t],n)=>C(`tr`,{className:n%2==0?`bg-muted/20`:``,children:[D(`td`,{className:`py-1.5 px-2 text-xs font-medium text-muted-foreground w-28 align-top whitespace-nowrap`,children:e}),D(`td`,{className:`py-1.5 px-2`,children:t})]},e))})})})}S();function he({node:e}){let t=k(),[n,r]=E(`info`),[i,a]=E(!1),o=e.processes??[],s=e.addons.map(e=>e.id),c=async()=>{if(!i){a(!0);try{await Promise.allSettled([t.trpcClient.pipelineOrchestrator.removeAgentSettings.mutate({agentNodeId:e.id}),t.trpcClient.clusterNodes.forgetNode.mutate({nodeId:e.id})])}finally{a(!1)}}};return e.isOnline?C(`div`,{className:`border border-border rounded-xl overflow-hidden`,children:[C(`div`,{className:`flex items-center gap-3 px-4 py-3 bg-muted/30 border-b border-border`,children:[D(`div`,{className:`w-2.5 h-2.5 rounded-full bg-success`}),D(`span`,{className:`text-sm font-semibold`,children:e.name}),C(`span`,{className:`text-xs text-muted-foreground`,children:[e.cpuModel??e.platform,` ·`,` `,e.memoryMB>0?`${Math.round(e.memoryMB/1024)}GB`:``,` · `,e.arch]}),e.engines.map(e=>D(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e)),C(`div`,{className:`ml-auto flex gap-3 text-xs text-muted-foreground`,children:[C(`span`,{className:`flex items-center gap-1`,children:[D(H,{className:`h-3 w-3`}),` `,e.cpuPercent,`%`]}),C(`span`,{className:`flex items-center gap-1`,children:[D(Q,{className:`h-3 w-3`}),` `,e.memoryPercent,`%`]})]})]}),D(`div`,{className:`flex border-b border-border px-4`,children:[`info`,`addons`,`forks`,`processes`,`settings`,`capabilities`].map(t=>D(`button`,{onClick:()=>r(t),className:`px-3 py-2 text-xs font-medium border-b-2 transition-colors ${n===t?`border-primary text-primary`:`border-transparent text-muted-foreground hover:text-foreground`}`,children:t===`info`?`Info`:t===`addons`?`Addons (${e.addons.length})`:t===`forks`?`Forks (${o.length})`:t===`processes`?`Processes`:t===`settings`?`Settings`:`Capabilities`},t))}),C(`div`,{className:`px-4 py-2`,children:[n===`info`&&D(me,{nodeId:e.id,name:e.name,hostname:e.hostname,platform:e.platform,arch:e.arch,cpuModel:e.cpuModel,cpuCores:e.cpuCores,memoryMB:e.memoryMB,engines:e.engines,isHub:e.isHub,uptime:e.uptime,localIps:e.localIps}),n===`addons`&&D(ne,{nodeId:e.id,addons:e.addons,isHub:e.isHub}),n===`forks`&&D(se,{nodeId:e.id,processes:o}),n===`processes`&&D(ue,{nodeId:e.id}),n===`settings`&&D(de,{nodeId:e.id,addonIds:s}),n===`capabilities`&&D(fe,{nodeId:e.id,addons:e.addons})]})]}):C(`div`,{className:`border border-border rounded-xl overflow-hidden opacity-60`,children:[C(`div`,{className:`flex items-center gap-3 px-4 py-3 bg-muted/30`,children:[D(`div`,{className:`w-2.5 h-2.5 rounded-full bg-destructive`}),D(`span`,{className:`text-sm font-semibold`,children:e.name}),C(`span`,{className:`text-xs text-muted-foreground`,children:[e.cpuModel??e.platform,` ·`,` `,e.memoryMB>0?`${Math.round(e.memoryMB/1024)}GB`:``,` · `,e.arch]}),e.engines.map(e=>D(`span`,{className:`text-[9px] px-1.5 py-0.5 rounded-full bg-purple-500/10 text-purple-400 font-medium`,children:e},e)),D(`span`,{className:`ml-auto text-xs px-2 py-0.5 rounded-full bg-destructive/10 text-destructive`,children:`offline`})]}),C(`div`,{className:`flex items-center justify-between gap-3 px-4 py-3`,children:[C(`span`,{className:`text-xs text-muted-foreground`,children:[e.lastSeen?`Last seen ${new Date(e.lastSeen).toLocaleString()} — `:``,e.addons.length,` addon`,e.addons.length===1?``:`s`,` assigned; will resume when node reconnects`]}),C(`button`,{type:`button`,onClick:()=>void c(),disabled:i,title:`Forget this node — removes its saved history and pipeline assignments`,className:`flex items-center gap-1 text-xs px-2 py-1 rounded-md border border-border text-muted-foreground hover:text-destructive hover:border-destructive/50 disabled:opacity-50 transition-colors`,children:[D(G,{className:`h-3 w-3`}),i?`Forgetting…`:`Forget node`]})]})]})}S();function ge({nodes:e,focusNodeId:t,focusNonce:n}){let r=[...e].toSorted((e,t)=>e.isHub?-1:t.isHub?1:e.isOnline&&!t.isOnline?-1:!e.isOnline&&t.isOnline?1:e.name.localeCompare(t.name)),i=x(null);return O(()=>{if(!t)return;let e=i.current?.querySelector(`#node-card-${CSS.escape(t)}`);e&&e.scrollIntoView({behavior:`smooth`,block:`start`})},[t,n]),D(`div`,{ref:i,className:`flex flex-col gap-4`,children:r.map(e=>D(`div`,{id:`node-card-${e.id}`,children:D(he,{node:e})},e.id))})}S();function _e(e){let[t,n]=E(()=>typeof window<`u`?window.matchMedia(e).matches:!1);return O(()=>{let t=window.matchMedia(e),r=e=>n(e.matches);return t.addEventListener(`change`,r),()=>t.removeEventListener(`change`,r)},[e]),t}function ve(){let{data:e,isLoading:n}=t(void 0,{staleTime:1/0}),[r,i]=E(null);return v(`cluster.topology-snapshot`,e=>{let t=e.data?.nodes;Array.isArray(t)&&i(t)}),{nodes:w(()=>r??e??[],[r,e]),isLoading:n&&!r}}function ye(){let[e,t]=E(`table`),[n,r]=E(void 0),[i,a]=E(0),o=_e(`(max-width: 767px)`),s=o&&e===`graph`?`table`:e,{nodes:c,isLoading:l}=ve(),u=w(()=>J(c),[c]),d=c.filter(e=>e.isOnline).length,f=c.filter(e=>!e.isOnline).length,p=b(e=>{t(`table`),r(e),a(e=>e+1)},[]),m=(n,r,i)=>C(`button`,{onClick:()=>t(n),className:`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-colors ${e===n?`bg-primary text-primary-foreground`:`text-muted-foreground hover:text-foreground`}`,children:[D(i,{className:`h-3.5 w-3.5`}),r]});return C(`div`,{className:`flex flex-col h-full gap-4 p-4`,children:[C(`div`,{className:`flex items-center justify-between gap-2 flex-wrap`,children:[C(`div`,{className:`flex items-center gap-2`,children:[d>0&&C(`span`,{className:`text-xs px-2 py-0.5 rounded-full bg-success/10 text-success`,children:[d,` online`]}),f>0&&C(`span`,{className:`text-xs px-2 py-0.5 rounded-full bg-destructive/10 text-destructive`,children:[f,` offline`]})]}),C(`div`,{className:`flex gap-0.5 p-1 rounded-lg bg-muted`,children:[m(`table`,`Table`,ee),!o&&m(`graph`,`Graph`,Z)]})]}),l?D(`div`,{className:`flex items-center justify-center flex-1 text-muted-foreground`,children:`Loading cluster topology...`}):s===`graph`?D(q,{graph:u,onOpenNodeDetail:p}):D(`div`,{className:`flex-1 overflow-auto`,children:D(ge,{nodes:c,focusNodeId:n,focusNonce:i})})]})}export{ye as ClusterPage};