@songsid/agend 2.3.5-alpha.3 → 2.3.5-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +52 -0
- package/dist/accounts-view.d.ts +97 -0
- package/dist/accounts-view.js +116 -0
- package/dist/accounts-view.js.map +1 -0
- package/dist/agent-cli-instructions.md +1 -1
- package/dist/agent-credentials.d.ts +24 -0
- package/dist/agent-credentials.js +66 -0
- package/dist/agent-credentials.js.map +1 -0
- package/dist/agent-endpoint.d.ts +3 -1
- package/dist/agent-endpoint.js +13 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.js +1 -1
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-runtime-api.d.ts +4 -0
- package/dist/agent-runtime-api.js +59 -0
- package/dist/agent-runtime-api.js.map +1 -0
- package/dist/agent-runtime-change.d.ts +76 -0
- package/dist/agent-runtime-change.js +114 -0
- package/dist/agent-runtime-change.js.map +1 -0
- package/dist/agent-workspace.d.ts +93 -0
- package/dist/agent-workspace.js +353 -0
- package/dist/agent-workspace.js.map +1 -0
- package/dist/auth-api.d.ts +27 -0
- package/dist/auth-api.js +168 -3
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/session-authorizations.d.ts +28 -4
- package/dist/authority/session-authorizations.js +63 -17
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/backend/antigravity.js +3 -1
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/codex-footer-hints.d.ts +7 -0
- package/dist/backend/codex-footer-hints.js +41 -0
- package/dist/backend/codex-footer-hints.js.map +1 -0
- package/dist/backend/codex-metadata.d.ts +14 -0
- package/dist/backend/codex-metadata.js +45 -0
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex-quota-history.d.ts +7 -0
- package/dist/backend/codex-quota-history.js +57 -0
- package/dist/backend/codex-quota-history.js.map +1 -0
- package/dist/backend/codex-session-lookup.d.ts +6 -0
- package/dist/backend/codex-session-lookup.js +1 -1
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex-speed.d.ts +14 -0
- package/dist/backend/codex-speed.js +35 -0
- package/dist/backend/codex-speed.js.map +1 -0
- package/dist/backend/codex.d.ts +7 -0
- package/dist/backend/codex.js +85 -24
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok-weekly-reset.d.ts +24 -0
- package/dist/backend/grok-weekly-reset.js +95 -0
- package/dist/backend/grok-weekly-reset.js.map +1 -0
- package/dist/backend/grok.d.ts +30 -1
- package/dist/backend/grok.js +301 -54
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +3 -0
- package/dist/backend/kiro.js +50 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.js +5 -3
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/native-pane.d.ts +3 -1
- package/dist/backend/native-pane.js +2 -2
- package/dist/backend/native-pane.js.map +1 -1
- package/dist/backend/types.d.ts +13 -1
- package/dist/backend/types.js +3 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/build-provenance-cli.d.ts +3 -0
- package/dist/build-provenance-cli.js +11 -0
- package/dist/build-provenance-cli.js.map +1 -0
- package/dist/build-provenance.d.ts +20 -0
- package/dist/build-provenance.js +67 -0
- package/dist/build-provenance.js.map +1 -0
- package/dist/build-provenance.json +1 -0
- package/dist/cache-ledger.d.ts +95 -0
- package/dist/cache-ledger.js +276 -4
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-service.d.ts +5 -0
- package/dist/cache-service.js +16 -4
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.js +11 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +51 -0
- package/dist/channel/adapters/telegram.js +235 -17
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +3 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +2 -0
- package/dist/claude-auth-status.d.ts +48 -0
- package/dist/claude-auth-status.js +149 -0
- package/dist/claude-auth-status.js.map +1 -0
- package/dist/cli.js +138 -37
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +21 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/cross-instance-notice.d.ts +10 -0
- package/dist/cross-instance-notice.js +67 -5
- package/dist/cross-instance-notice.js.map +1 -1
- package/dist/daemon.d.ts +70 -1
- package/dist/daemon.js +547 -25
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +8 -0
- package/dist/dashboard-permissions.js +16 -0
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +23 -1
- package/dist/delivery-consumed-watch.js +30 -3
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +1 -1
- package/dist/delivery-reconciliation.js +1 -1
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/doctor.js +20 -9
- package/dist/doctor.js.map +1 -1
- package/dist/export-import.d.ts +7 -0
- package/dist/export-import.js +44 -10
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -0
- package/dist/fleet-manager.d.ts +362 -7
- package/dist/fleet-manager.js +1522 -91
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-windows-runtime.d.ts +8 -2
- package/dist/fleet-windows-runtime.js +93 -6
- package/dist/fleet-windows-runtime.js.map +1 -1
- package/dist/general-knowledge/skills/concepts/SKILL.md +425 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +1 -0
- package/dist/general-knowledge/skills/fleet-health/SKILL.md +2 -2
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -1
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +41 -4
- package/dist/general-knowledge/skills/session-management/SKILL.md +1 -1
- package/dist/general-knowledge/skills/tui-effort/SKILL.md +10 -10
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +31 -15
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/general-role.d.ts +1 -1
- package/dist/general-role.js +1 -0
- package/dist/general-role.js.map +1 -1
- package/dist/hub/admission.d.ts +28 -0
- package/dist/hub/admission.js +62 -0
- package/dist/hub/admission.js.map +1 -0
- package/dist/hub/attachments/limits.d.ts +20 -0
- package/dist/hub/attachments/limits.js +48 -0
- package/dist/hub/attachments/limits.js.map +1 -0
- package/dist/hub/attachments/store.d.ts +116 -0
- package/dist/hub/attachments/store.js +246 -0
- package/dist/hub/attachments/store.js.map +1 -0
- package/dist/hub/audit/index.d.ts +62 -0
- package/dist/hub/audit/index.js +344 -0
- package/dist/hub/audit/index.js.map +1 -0
- package/dist/hub/browser-certificate.d.ts +38 -0
- package/dist/hub/browser-certificate.js +247 -0
- package/dist/hub/browser-certificate.js.map +1 -0
- package/dist/hub/buttons-model.d.ts +9 -0
- package/dist/hub/buttons-model.js +42 -0
- package/dist/hub/buttons-model.js.map +1 -0
- package/dist/hub/buttons.d.ts +54 -0
- package/dist/hub/buttons.js +346 -0
- package/dist/hub/buttons.js.map +1 -0
- package/dist/hub/catalog.d.ts +74 -0
- package/dist/hub/catalog.js +195 -0
- package/dist/hub/catalog.js.map +1 -0
- package/dist/hub/client.d.ts +69 -0
- package/dist/hub/client.js +300 -0
- package/dist/hub/client.js.map +1 -0
- package/dist/hub/compose/member.d.ts +139 -0
- package/dist/hub/compose/member.js +450 -0
- package/dist/hub/compose/member.js.map +1 -0
- package/dist/hub/compose/server.d.ts +77 -0
- package/dist/hub/compose/server.js +349 -0
- package/dist/hub/compose/server.js.map +1 -0
- package/dist/hub/compose/views.d.ts +12 -0
- package/dist/hub/compose/views.js +4 -0
- package/dist/hub/compose/views.js.map +1 -0
- package/dist/hub/db.d.ts +56 -0
- package/dist/hub/db.js +188 -0
- package/dist/hub/db.js.map +1 -0
- package/dist/hub/directory/config.d.ts +39 -0
- package/dist/hub/directory/config.js +108 -0
- package/dist/hub/directory/config.js.map +1 -0
- package/dist/hub/directory/directory.d.ts +18 -0
- package/dist/hub/directory/directory.js +320 -0
- package/dist/hub/directory/directory.js.map +1 -0
- package/dist/hub/directory/index.d.ts +7 -0
- package/dist/hub/directory/index.js +4 -0
- package/dist/hub/directory/index.js.map +1 -0
- package/dist/hub/directory/profiles.d.ts +41 -0
- package/dist/hub/directory/profiles.js +90 -0
- package/dist/hub/directory/profiles.js.map +1 -0
- package/dist/hub/directory/types.d.ts +71 -0
- package/dist/hub/directory/types.js +14 -0
- package/dist/hub/directory/types.js.map +1 -0
- package/dist/hub/execution/cli-provider.d.ts +23 -0
- package/dist/hub/execution/cli-provider.js +341 -0
- package/dist/hub/execution/cli-provider.js.map +1 -0
- package/dist/hub/execution/index.d.ts +13 -0
- package/dist/hub/execution/index.js +8 -0
- package/dist/hub/execution/index.js.map +1 -0
- package/dist/hub/execution/model-broker.d.ts +24 -0
- package/dist/hub/execution/model-broker.js +208 -0
- package/dist/hub/execution/model-broker.js.map +1 -0
- package/dist/hub/execution/provider-setup.d.ts +11 -0
- package/dist/hub/execution/provider-setup.js +21 -0
- package/dist/hub/execution/provider-setup.js.map +1 -0
- package/dist/hub/execution/sandbox-runner.d.ts +1 -0
- package/dist/hub/execution/sandbox-runner.js +221 -0
- package/dist/hub/execution/sandbox-runner.js.map +1 -0
- package/dist/hub/execution/service.d.ts +136 -0
- package/dist/hub/execution/service.js +459 -0
- package/dist/hub/execution/service.js.map +1 -0
- package/dist/hub/execution/store.d.ts +61 -0
- package/dist/hub/execution/store.js +182 -0
- package/dist/hub/execution/store.js.map +1 -0
- package/dist/hub/execution/views.d.ts +20 -0
- package/dist/hub/execution/views.js +48 -0
- package/dist/hub/execution/views.js.map +1 -0
- package/dist/hub/http/compose.d.ts +20 -0
- package/dist/hub/http/compose.js +518 -0
- package/dist/hub/http/compose.js.map +1 -0
- package/dist/hub/http/core.d.ts +49 -0
- package/dist/hub/http/core.js +124 -0
- package/dist/hub/http/core.js.map +1 -0
- package/dist/hub/http/deps.d.ts +61 -0
- package/dist/hub/http/deps.js +2 -0
- package/dist/hub/http/deps.js.map +1 -0
- package/dist/hub/http/schema.d.ts +14 -0
- package/dist/hub/http/schema.js +80 -0
- package/dist/hub/http/schema.js.map +1 -0
- package/dist/hub/identity.d.ts +32 -0
- package/dist/hub/identity.js +80 -0
- package/dist/hub/identity.js.map +1 -0
- package/dist/hub/init/browser-certificate.d.ts +9 -0
- package/dist/hub/init/browser-certificate.js +78 -0
- package/dist/hub/init/browser-certificate.js.map +1 -0
- package/dist/hub/init/browser-tls.d.ts +18 -0
- package/dist/hub/init/browser-tls.js +62 -0
- package/dist/hub/init/browser-tls.js.map +1 -0
- package/dist/hub/init/cli.d.ts +3 -0
- package/dist/hub/init/cli.js +83 -0
- package/dist/hub/init/cli.js.map +1 -0
- package/dist/hub/init/directory-certificate.d.ts +24 -0
- package/dist/hub/init/directory-certificate.js +222 -0
- package/dist/hub/init/directory-certificate.js.map +1 -0
- package/dist/hub/init/existing-fleet.d.ts +6 -0
- package/dist/hub/init/existing-fleet.js +58 -0
- package/dist/hub/init/existing-fleet.js.map +1 -0
- package/dist/hub/init/handoff.d.ts +8 -0
- package/dist/hub/init/handoff.js +36 -0
- package/dist/hub/init/handoff.js.map +1 -0
- package/dist/hub/init/identity.d.ts +5 -0
- package/dist/hub/init/identity.js +24 -0
- package/dist/hub/init/identity.js.map +1 -0
- package/dist/hub/init/initializer.d.ts +24 -0
- package/dist/hub/init/initializer.js +385 -0
- package/dist/hub/init/initializer.js.map +1 -0
- package/dist/hub/init/inventory.d.ts +17 -0
- package/dist/hub/init/inventory.js +33 -0
- package/dist/hub/init/inventory.js.map +1 -0
- package/dist/hub/init/layout.d.ts +32 -0
- package/dist/hub/init/layout.js +53 -0
- package/dist/hub/init/layout.js.map +1 -0
- package/dist/hub/init/network.d.ts +18 -0
- package/dist/hub/init/network.js +104 -0
- package/dist/hub/init/network.js.map +1 -0
- package/dist/hub/init/plan-digest.d.ts +5 -0
- package/dist/hub/init/plan-digest.js +47 -0
- package/dist/hub/init/plan-digest.js.map +1 -0
- package/dist/hub/init/prompt.d.ts +26 -0
- package/dist/hub/init/prompt.js +110 -0
- package/dist/hub/init/prompt.js.map +1 -0
- package/dist/hub/init/secret-file.d.ts +1 -0
- package/dist/hub/init/secret-file.js +59 -0
- package/dist/hub/init/secret-file.js.map +1 -0
- package/dist/hub/init/text.d.ts +127 -0
- package/dist/hub/init/text.js +247 -0
- package/dist/hub/init/text.js.map +1 -0
- package/dist/hub/init/types.d.ts +114 -0
- package/dist/hub/init/types.js +9 -0
- package/dist/hub/init/types.js.map +1 -0
- package/dist/hub/init/wizard.d.ts +34 -0
- package/dist/hub/init/wizard.js +554 -0
- package/dist/hub/init/wizard.js.map +1 -0
- package/dist/hub/initialization.d.ts +23 -0
- package/dist/hub/initialization.js +28 -0
- package/dist/hub/initialization.js.map +1 -0
- package/dist/hub/member/agent-mode.d.ts +6 -0
- package/dist/hub/member/agent-mode.js +23 -0
- package/dist/hub/member/agent-mode.js.map +1 -0
- package/dist/hub/member/attachments.d.ts +29 -0
- package/dist/hub/member/attachments.js +107 -0
- package/dist/hub/member/attachments.js.map +1 -0
- package/dist/hub/member/exposure-api.d.ts +87 -0
- package/dist/hub/member/exposure-api.js +64 -0
- package/dist/hub/member/exposure-api.js.map +1 -0
- package/dist/hub/member/exposures.d.ts +123 -0
- package/dist/hub/member/exposures.js +282 -0
- package/dist/hub/member/exposures.js.map +1 -0
- package/dist/hub/member/pairing-api.d.ts +85 -0
- package/dist/hub/member/pairing-api.js +385 -0
- package/dist/hub/member/pairing-api.js.map +1 -0
- package/dist/hub/member/quota.d.ts +20 -0
- package/dist/hub/member/quota.js +98 -0
- package/dist/hub/member/quota.js.map +1 -0
- package/dist/hub/member-journal.d.ts +104 -0
- package/dist/hub/member-journal.js +336 -0
- package/dist/hub/member-journal.js.map +1 -0
- package/dist/hub/member-reconciliation.d.ts +14 -0
- package/dist/hub/member-reconciliation.js +97 -0
- package/dist/hub/member-reconciliation.js.map +1 -0
- package/dist/hub/mount.d.ts +39 -0
- package/dist/hub/mount.js +123 -0
- package/dist/hub/mount.js.map +1 -0
- package/dist/hub/pairing-client.d.ts +17 -0
- package/dist/hub/pairing-client.js +108 -0
- package/dist/hub/pairing-client.js.map +1 -0
- package/dist/hub/pairing.d.ts +65 -0
- package/dist/hub/pairing.js +211 -0
- package/dist/hub/pairing.js.map +1 -0
- package/dist/hub/policy.d.ts +63 -0
- package/dist/hub/policy.js +147 -0
- package/dist/hub/policy.js.map +1 -0
- package/dist/hub/preview.d.ts +32 -0
- package/dist/hub/preview.js +64 -0
- package/dist/hub/preview.js.map +1 -0
- package/dist/hub/private-files.d.ts +5 -0
- package/dist/hub/private-files.js +44 -0
- package/dist/hub/private-files.js.map +1 -0
- package/dist/hub/profile.d.ts +59 -0
- package/dist/hub/profile.js +73 -0
- package/dist/hub/profile.js.map +1 -0
- package/dist/hub/protocol.d.ts +779 -0
- package/dist/hub/protocol.js +93 -0
- package/dist/hub/protocol.js.map +1 -0
- package/dist/hub/quota.d.ts +24 -0
- package/dist/hub/quota.js +112 -0
- package/dist/hub/quota.js.map +1 -0
- package/dist/hub/representative.d.ts +141 -0
- package/dist/hub/representative.js +528 -0
- package/dist/hub/representative.js.map +1 -0
- package/dist/hub/retention.d.ts +17 -0
- package/dist/hub/retention.js +45 -0
- package/dist/hub/retention.js.map +1 -0
- package/dist/hub/rooms.d.ts +120 -0
- package/dist/hub/rooms.js +535 -0
- package/dist/hub/rooms.js.map +1 -0
- package/dist/hub/runtime.d.ts +106 -0
- package/dist/hub/runtime.js +298 -0
- package/dist/hub/runtime.js.map +1 -0
- package/dist/hub/server.d.ts +56 -0
- package/dist/hub/server.js +202 -0
- package/dist/hub/server.js.map +1 -0
- package/dist/hub/service-start.d.ts +17 -0
- package/dist/hub/service-start.js +109 -0
- package/dist/hub/service-start.js.map +1 -0
- package/dist/hub/sessions.d.ts +53 -0
- package/dist/hub/sessions.js +196 -0
- package/dist/hub/sessions.js.map +1 -0
- package/dist/hub/socket.d.ts +24 -0
- package/dist/hub/socket.js +79 -0
- package/dist/hub/socket.js.map +1 -0
- package/dist/hub/store.d.ts +77 -0
- package/dist/hub/store.js +88 -0
- package/dist/hub/store.js.map +1 -0
- package/dist/hub/tls.d.ts +31 -0
- package/dist/hub/tls.js +135 -0
- package/dist/hub/tls.js.map +1 -0
- package/dist/hub/types.d.ts +401 -0
- package/dist/hub/types.js +2 -0
- package/dist/hub/types.js.map +1 -0
- package/dist/hub/validation.d.ts +33 -0
- package/dist/hub/validation.js +136 -0
- package/dist/hub/validation.js.map +1 -0
- package/dist/hub/version-floor.d.ts +10 -0
- package/dist/hub/version-floor.js +45 -0
- package/dist/hub/version-floor.js.map +1 -0
- package/dist/hub-browser-certificate-policy.d.ts +31 -0
- package/dist/hub-browser-certificate-policy.js +25 -0
- package/dist/hub-browser-certificate-policy.js.map +1 -0
- package/dist/hub-membership-settings.d.ts +6 -0
- package/dist/hub-membership-settings.js +21 -0
- package/dist/hub-membership-settings.js.map +1 -0
- package/dist/hub-mode.d.ts +15 -0
- package/dist/hub-mode.js +17 -0
- package/dist/hub-mode.js.map +1 -0
- package/dist/hub-pairing-summary.d.ts +48 -0
- package/dist/hub-pairing-summary.js +36 -0
- package/dist/hub-pairing-summary.js.map +1 -0
- package/dist/hub-report-target.d.ts +32 -0
- package/dist/hub-report-target.js +33 -0
- package/dist/hub-report-target.js.map +1 -0
- package/dist/hub-retention-policy.d.ts +14 -0
- package/dist/hub-retention-policy.js +15 -0
- package/dist/hub-retention-policy.js.map +1 -0
- package/dist/instance-config-impact.js +3 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +17 -2
- package/dist/instance-lifecycle.js +58 -8
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instance-topic-delete.d.ts +77 -0
- package/dist/instance-topic-delete.js +123 -0
- package/dist/instance-topic-delete.js.map +1 -0
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-engine-status.d.ts +11 -0
- package/dist/kiro-engine-status.js +6 -0
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/launchd-service-domain.d.ts +5 -0
- package/dist/launchd-service-domain.js +21 -0
- package/dist/launchd-service-domain.js.map +1 -0
- package/dist/locale.js +125 -3
- package/dist/locale.js.map +1 -1
- package/dist/log-service.d.ts +28 -0
- package/dist/log-service.js +29 -0
- package/dist/log-service.js.map +1 -1
- package/dist/log-steps.d.ts +4 -3
- package/dist/log-steps.js +32 -7
- package/dist/log-steps.js.map +1 -1
- package/dist/logger.d.ts +16 -2
- package/dist/logger.js +346 -66
- package/dist/logger.js.map +1 -1
- package/dist/login-flows.d.ts +15 -7
- package/dist/login-flows.js +29 -3
- package/dist/login-flows.js.map +1 -1
- package/dist/login-manager.js +25 -4
- package/dist/login-manager.js.map +1 -1
- package/dist/ls-rows.js +3 -4
- package/dist/ls-rows.js.map +1 -1
- package/dist/missed-offline.d.ts +25 -0
- package/dist/missed-offline.js +79 -0
- package/dist/missed-offline.js.map +1 -0
- package/dist/native-instance-api.d.ts +0 -1
- package/dist/native-instance-api.js +15 -3
- package/dist/native-instance-api.js.map +1 -1
- package/dist/native-instance-input.d.ts +3 -0
- package/dist/native-instance-input.js +6 -1
- package/dist/native-instance-input.js.map +1 -1
- package/dist/native-instance-registry.d.ts +6 -0
- package/dist/native-instance-registry.js +24 -0
- package/dist/native-instance-registry.js.map +1 -1
- package/dist/native-mcp.d.ts +3 -0
- package/dist/native-mcp.js +15 -2
- package/dist/native-mcp.js.map +1 -1
- package/dist/native-pane-lifecycle.d.ts +8 -0
- package/dist/native-pane-lifecycle.js +13 -4
- package/dist/native-pane-lifecycle.js.map +1 -1
- package/dist/native-pane-manager.js +17 -9
- package/dist/native-pane-manager.js.map +1 -1
- package/dist/needs-you-hub.d.ts +9 -1
- package/dist/needs-you-hub.js +46 -8
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +47 -2
- package/dist/needs-you.js +31 -3
- package/dist/needs-you.js.map +1 -1
- package/dist/office-share-page.js +3 -3
- package/dist/office-share-page.js.map +1 -1
- package/dist/office-share.d.ts +11 -0
- package/dist/office-share.js +14 -0
- package/dist/office-share.js.map +1 -1
- package/dist/office-talk.d.ts +26 -0
- package/dist/office-talk.js +50 -0
- package/dist/office-talk.js.map +1 -0
- package/dist/outbound-handlers.d.ts +14 -0
- package/dist/outbound-handlers.js +49 -6
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +33 -1
- package/dist/outbound-schemas.js +29 -16
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-quota-history.d.ts +9 -0
- package/dist/pane-quota-history.js +67 -0
- package/dist/pane-quota-history.js.map +1 -0
- package/dist/pause-marker.d.ts +1 -1
- package/dist/pause-marker.js +1 -1
- package/dist/pause-marker.js.map +1 -1
- package/dist/platform-general.d.ts +46 -0
- package/dist/platform-general.js +91 -0
- package/dist/platform-general.js.map +1 -0
- package/dist/public-web-gateway.js +7 -0
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +6 -0
- package/dist/public-web-link.js +9 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/queued-handoffs.d.ts +33 -0
- package/dist/queued-handoffs.js +75 -0
- package/dist/queued-handoffs.js.map +1 -0
- package/dist/quickstart.d.ts +13 -0
- package/dist/quickstart.js +81 -5
- package/dist/quickstart.js.map +1 -1
- package/dist/quota-notice.d.ts +7 -0
- package/dist/quota-notice.js +40 -0
- package/dist/quota-notice.js.map +1 -1
- package/dist/reply-buttons-controller.js +10 -6
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-polls.d.ts +2 -2
- package/dist/reply-polls.js +3 -3
- package/dist/reply-polls.js.map +1 -1
- package/dist/runtime-api.d.ts +2 -0
- package/dist/runtime-api.js +106 -13
- package/dist/runtime-api.js.map +1 -1
- package/dist/runtime-build-info.d.ts +9 -0
- package/dist/runtime-build-info.js +59 -0
- package/dist/runtime-build-info.js.map +1 -0
- package/dist/runtime-bundle.d.ts +6 -1
- package/dist/runtime-bundle.js +17 -9
- package/dist/runtime-bundle.js.map +1 -1
- package/dist/runtime-cli.d.ts +13 -1
- package/dist/runtime-cli.js +173 -19
- package/dist/runtime-cli.js.map +1 -1
- package/dist/runtime-client-store.d.ts +27 -1
- package/dist/runtime-client-store.js +86 -6
- package/dist/runtime-client-store.js.map +1 -1
- package/dist/runtime-client.d.ts +74 -0
- package/dist/runtime-client.js +336 -26
- package/dist/runtime-client.js.map +1 -1
- package/dist/runtime-connection.d.ts +22 -0
- package/dist/runtime-connection.js +93 -0
- package/dist/runtime-connection.js.map +1 -0
- package/dist/runtime-coordinator.d.ts +16 -0
- package/dist/runtime-coordinator.js +287 -62
- package/dist/runtime-coordinator.js.map +1 -1
- package/dist/runtime-credential-profiles.d.ts +78 -0
- package/dist/runtime-credential-profiles.js +280 -0
- package/dist/runtime-credential-profiles.js.map +1 -0
- package/dist/runtime-install.d.ts +50 -0
- package/dist/runtime-install.js +186 -0
- package/dist/runtime-install.js.map +1 -0
- package/dist/runtime-pane-assets.d.ts +1 -1
- package/dist/runtime-pane-assets.js +1 -1
- package/dist/runtime-pane-assets.js.map +1 -1
- package/dist/runtime-pane-boot.d.ts +7 -0
- package/dist/runtime-pane-boot.js +23 -0
- package/dist/runtime-pane-boot.js.map +1 -1
- package/dist/runtime-pane-codex-index.d.ts +10 -1
- package/dist/runtime-pane-codex-index.js +131 -27
- package/dist/runtime-pane-codex-index.js.map +1 -1
- package/dist/runtime-pane-host.d.ts +19 -0
- package/dist/runtime-pane-host.js +50 -7
- package/dist/runtime-pane-host.js.map +1 -1
- package/dist/runtime-pane-link.d.ts +7 -0
- package/dist/runtime-pane-link.js +93 -2
- package/dist/runtime-pane-link.js.map +1 -1
- package/dist/runtime-pane-mcp-relay.d.ts +1 -0
- package/dist/runtime-pane-mcp-relay.js +10 -0
- package/dist/runtime-pane-mcp-relay.js.map +1 -1
- package/dist/runtime-pane-mcp.d.ts +4 -0
- package/dist/runtime-pane-mcp.js +6 -3
- package/dist/runtime-pane-mcp.js.map +1 -1
- package/dist/runtime-pane-native.d.ts +32 -2
- package/dist/runtime-pane-native.js +55 -6
- package/dist/runtime-pane-native.js.map +1 -1
- package/dist/runtime-pane-port.d.ts +5 -0
- package/dist/runtime-pane-port.js +17 -1
- package/dist/runtime-pane-port.js.map +1 -1
- package/dist/runtime-pane-process.d.ts +1 -1
- package/dist/runtime-pane-process.js +11 -2
- package/dist/runtime-pane-process.js.map +1 -1
- package/dist/runtime-pane-protocol.d.ts +11 -1
- package/dist/runtime-pane-protocol.js +27 -5
- package/dist/runtime-pane-protocol.js.map +1 -1
- package/dist/runtime-pane-quota-history.d.ts +6 -0
- package/dist/runtime-pane-quota-history.js +44 -0
- package/dist/runtime-pane-quota-history.js.map +1 -0
- package/dist/runtime-pane-service.d.ts +5 -0
- package/dist/runtime-pane-service.js +47 -12
- package/dist/runtime-pane-service.js.map +1 -1
- package/dist/runtime-pane-transcript.d.ts +5 -0
- package/dist/runtime-pane-transcript.js +66 -5
- package/dist/runtime-pane-transcript.js.map +1 -1
- package/dist/runtime-pane-worker.js +19 -6
- package/dist/runtime-pane-worker.js.map +1 -1
- package/dist/runtime-protocol.d.ts +30 -2
- package/dist/runtime-protocol.js +30 -0
- package/dist/runtime-protocol.js.map +1 -1
- package/dist/runtime-update-activity.d.ts +21 -0
- package/dist/runtime-update-activity.js +51 -0
- package/dist/runtime-update-activity.js.map +1 -0
- package/dist/runtime-update-artifact.d.ts +31 -0
- package/dist/runtime-update-artifact.js +252 -0
- package/dist/runtime-update-artifact.js.map +1 -0
- package/dist/runtime-update-install.d.ts +31 -0
- package/dist/runtime-update-install.js +205 -0
- package/dist/runtime-update-install.js.map +1 -0
- package/dist/runtime-update-journal.d.ts +44 -0
- package/dist/runtime-update-journal.js +121 -0
- package/dist/runtime-update-journal.js.map +1 -0
- package/dist/runtime-update-lock.d.ts +48 -0
- package/dist/runtime-update-lock.js +217 -0
- package/dist/runtime-update-lock.js.map +1 -0
- package/dist/runtime-update-owners.d.ts +29 -0
- package/dist/runtime-update-owners.js +240 -0
- package/dist/runtime-update-owners.js.map +1 -0
- package/dist/runtime-update-protocol.d.ts +15 -0
- package/dist/runtime-update-protocol.js +13 -0
- package/dist/runtime-update-protocol.js.map +1 -0
- package/dist/runtime-windows-bridge.d.ts +2 -1
- package/dist/runtime-windows-bridge.js +11 -1
- package/dist/runtime-windows-bridge.js.map +1 -1
- package/dist/scheduler/db.d.ts +2 -1
- package/dist/scheduler/db.js +23 -9
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/task-board-text.js +1 -1
- package/dist/scheduler/task-board-text.js.map +1 -1
- package/dist/scheduler/task-board.d.ts +13 -0
- package/dist/scheduler/task-board.js +28 -3
- package/dist/scheduler/task-board.js.map +1 -1
- package/dist/service-drain.d.ts +19 -0
- package/dist/service-drain.js +64 -0
- package/dist/service-drain.js.map +1 -0
- package/dist/service-installer.d.ts +7 -2
- package/dist/service-installer.js +13 -10
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.d.ts +20 -0
- package/dist/settings-api.js +414 -4
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.d.ts +6 -0
- package/dist/settings-baseline.js +3 -1
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.js +29 -6
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.d.ts +13 -0
- package/dist/settings-effect.js +98 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +3 -0
- package/dist/settings-http-confirmation.js +28 -1
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-instance-patch.js +27 -0
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-wizard.js +6 -2
- package/dist/setup-wizard.js.map +1 -1
- package/dist/task-board-tool.d.ts +13 -1
- package/dist/task-board-tool.js +104 -4
- package/dist/task-board-tool.js.map +1 -1
- package/dist/task-board-waker.d.ts +6 -0
- package/dist/task-board-waker.js +4 -0
- package/dist/task-board-waker.js.map +1 -1
- package/dist/tmux-binary.d.ts +59 -0
- package/dist/tmux-binary.js +200 -0
- package/dist/tmux-binary.js.map +1 -0
- package/dist/tmux-control.js +4 -4
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.js +32 -1
- package/dist/tmux-exec-helper.js.map +1 -1
- package/dist/tmux-manager.d.ts +1 -1
- package/dist/tmux-manager.js +45 -36
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.js +4 -3
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.d.ts +5 -2
- package/dist/tool-permissions.js +6 -5
- package/dist/tool-permissions.js.map +1 -1
- package/dist/tool-progress.d.ts +2 -0
- package/dist/tool-progress.js +19 -3
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-commands.js +10 -5
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.d.ts +20 -0
- package/dist/transcript-monitor.js +47 -3
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-needles.d.ts +7 -0
- package/dist/transcript-needles.js +9 -1
- package/dist/transcript-needles.js.map +1 -1
- package/dist/transcript-records.d.ts +1 -1
- package/dist/transcript-records.js +2 -1
- package/dist/transcript-records.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/ui/account-identity.js +27 -0
- package/dist/ui/accounts-view.js +214 -0
- package/dist/ui/agent-runtime-settings.js +68 -0
- package/dist/ui/agent-runtime.js +20 -2
- package/dist/ui/backend-signin.js +39 -21
- package/dist/ui/chat-ambient.js +1 -1
- package/dist/ui/chat-md-strings.js +3 -0
- package/dist/ui/chat-render.js +3 -670
- package/dist/ui/chat-store.js +1 -1
- package/dist/ui/chat-strings.js +3 -333
- package/dist/ui/chat-thread.js +3 -919
- package/dist/ui/chat-time.js +3 -80
- package/dist/ui/chat-tour.js +1 -1
- package/dist/ui/credential-profile-select.js +54 -0
- package/dist/ui/fleet-office-dialogue.d.ts +30 -0
- package/dist/ui/fleet-office-dialogue.js +382 -0
- package/dist/ui/fleet-office-pack.d.ts +9 -0
- package/dist/ui/fleet-office-pack.js +76 -4
- package/dist/ui/fleet-office-skin.js +23 -5
- package/dist/ui/fleet-office-store.js +5 -0
- package/dist/ui/fleet-office.js +173 -6
- package/dist/ui/fleet-task-card.js +10 -6
- package/dist/ui/fleet-task-common.js +12 -2
- package/dist/ui/fleet-task-menu.js +188 -0
- package/dist/ui/fleet-task-stats.js +124 -0
- package/dist/ui/fleet-task-view.js +340 -0
- package/dist/ui/fleet-tasks.js +131 -43
- package/dist/ui/fleet-usage.js +90 -27
- package/dist/ui/html-attachment.js +3 -40
- package/dist/ui/hub-agent-copy.js +23 -0
- package/dist/ui/hub-button-actions.js +65 -0
- package/dist/ui/hub-chat-store.js +158 -0
- package/dist/ui/hub-chat-strings.js +77 -0
- package/dist/ui/hub-client.js +329 -0
- package/dist/ui/hub-owner-strings.js +51 -0
- package/dist/ui/hub-provider-guidance.js +31 -0
- package/dist/ui/hub-quota.js +85 -0
- package/dist/ui/hub-strings.js +162 -0
- package/dist/ui/hub-switcher.js +27 -0
- package/dist/ui/native-instance-settings.js +5 -8
- package/dist/ui/native-pane-recovery.js +1 -1
- package/dist/ui/office-share-page.js +4 -2
- package/dist/ui/panel-chat.js +36 -49
- package/dist/ui/panel-details.js +1 -1
- package/dist/ui/panel-fleet.js +82 -12
- package/dist/ui/panel-hub.js +619 -0
- package/dist/ui/panel-log.js +2 -2
- package/dist/ui/panel-needs.js +24 -8
- package/dist/ui/panel-runtimes.js +239 -45
- package/dist/ui/panel-settings.js +266 -192
- package/dist/ui/panel-windows-cli.js +88 -42
- package/dist/ui/preview-pages.js +1 -1
- package/dist/ui/preview-panel.js +92 -6
- package/dist/ui/preview-versions.js +1 -1
- package/dist/ui/preview.js +3 -476
- package/dist/ui/runtime-commands.d.ts +4 -0
- package/dist/ui/runtime-commands.js +59 -0
- package/dist/ui/search-dialog.js +2 -0
- package/dist/ui/settings-access-strings.js +42 -0
- package/dist/ui/settings-agent-filters.js +94 -0
- package/dist/ui/settings-appearance.js +122 -23
- package/dist/ui/settings-build-version.js +35 -0
- package/dist/ui/settings-codex-copy.js +19 -0
- package/dist/ui/settings-devices.js +253 -0
- package/dist/ui/settings-dialogs.js +33 -12
- package/dist/ui/settings-guests.js +25 -11
- package/dist/ui/settings-hub-browser-certificate.js +74 -0
- package/dist/ui/settings-hub-membership.js +72 -0
- package/dist/ui/settings-hub-retention.js +52 -0
- package/dist/ui/settings-hub.js +196 -0
- package/dist/ui/settings-layout.js +242 -0
- package/dist/ui/settings-model.js +24 -2
- package/dist/ui/settings-outside.js +104 -38
- package/dist/ui/settings-registry.js +9 -4
- package/dist/ui/settings-shared-strings.js +143 -0
- package/dist/ui/settings-shared.js +345 -0
- package/dist/ui/settings-shortcuts.js +65 -0
- package/dist/ui/settings-strings.js +89 -32
- package/dist/ui/settings-web-authority.js +17 -11
- package/dist/ui/shared/accounts.css +15 -0
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-needs.js +1 -1
- package/dist/ui/shared/app-route.js +6 -1
- package/dist/ui/shared/app-session.js +6 -2
- package/dist/ui/shared/app-shell.js +81 -15
- package/dist/ui/shared/app.css +1114 -13
- package/dist/ui/shared/app.js +12 -3
- package/dist/ui/shared/chat-composer.js +68 -0
- package/dist/ui/shared/chat-md-strings.js +9 -0
- package/dist/ui/shared/chat-render.js +682 -0
- package/dist/ui/shared/chat-strings.js +333 -0
- package/dist/ui/shared/chat-thread.js +969 -0
- package/dist/ui/shared/chat-time.js +80 -0
- package/dist/ui/shared/header-tools.js +3 -5
- package/dist/ui/shared/html-attachment.js +42 -0
- package/dist/ui/shared/hub-chat.css +85 -0
- package/dist/ui/shared/hub-owner.css +33 -0
- package/dist/ui/shared/hub-quota.css +8 -0
- package/dist/ui/shared/hub.css +71 -0
- package/dist/ui/shared/instance-nav.js +3 -2
- package/dist/ui/shared/machine-name.js +13 -0
- package/dist/ui/shared/page-head.js +8 -0
- package/dist/ui/shared/panel-view.js +77 -4
- package/dist/ui/shared/preview.js +476 -0
- package/dist/ui/shared/runtime-install.css +26 -0
- package/dist/ui/shared/settings-width.js +31 -0
- package/dist/ui/shared/side-rail.js +15 -0
- package/dist/ui/shared/signin.js +172 -0
- package/dist/ui/shared/task-board.css +95 -0
- package/dist/ui/shared/tokens.css +1 -0
- package/dist/ui/shared/ui-dialog.js +2 -2
- package/dist/ui/shared/ui-menu.js +3 -3
- package/dist/ui/shared/usage-dialog.js +18 -1
- package/dist/ui/shared/view-history.css +17 -0
- package/dist/ui/shared/view-history.js +438 -0
- package/dist/ui/shared/view-strings.js +16 -0
- package/dist/ui/shared/workspace.css +20 -0
- package/dist/ui/signin.html +21 -0
- package/dist/ui/windows-cli-catalog.js +41 -12
- package/dist/ui/workspace-panel.js +189 -0
- package/dist/ui/workspace-strings.js +35 -0
- package/dist/unattended-install.d.ts +11 -2
- package/dist/unattended-install.js +41 -6
- package/dist/unattended-install.js.map +1 -1
- package/dist/usage/capacity.d.ts +69 -0
- package/dist/usage/capacity.js +119 -0
- package/dist/usage/capacity.js.map +1 -0
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +3 -0
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/profile-timeline.d.ts +16 -0
- package/dist/usage/profile-timeline.js +58 -0
- package/dist/usage/profile-timeline.js.map +1 -0
- package/dist/usage/providers.js +2 -1
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/quota-history.d.ts +43 -0
- package/dist/usage/quota-history.js +168 -0
- package/dist/usage/quota-history.js.map +1 -0
- package/dist/usage/usage-api.d.ts +31 -0
- package/dist/usage/usage-api.js +80 -1
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.d.ts +25 -1
- package/dist/usage-report.js +55 -4
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.d.ts +6 -1
- package/dist/usage-rollup.js +16 -4
- package/dist/usage-rollup.js.map +1 -1
- package/dist/view-api.d.ts +16 -0
- package/dist/view-api.js +105 -23
- package/dist/view-api.js.map +1 -1
- package/dist/view-history.d.ts +84 -0
- package/dist/view-history.js +116 -0
- package/dist/view-history.js.map +1 -0
- package/dist/web-api.d.ts +49 -2
- package/dist/web-api.js +279 -8
- package/dist/web-api.js.map +1 -1
- package/dist/web-backend-login.d.ts +23 -1
- package/dist/web-backend-login.js +11 -17
- package/dist/web-backend-login.js.map +1 -1
- package/dist/web-device-login.d.ts +153 -0
- package/dist/web-device-login.js +278 -0
- package/dist/web-device-login.js.map +1 -0
- package/dist/web-office-skins.d.ts +9 -0
- package/dist/web-office-skins.js +16 -1
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-session-authorization.d.ts +13 -2
- package/dist/web-session-authorization.js +10 -3
- package/dist/web-session-authorization.js.map +1 -1
- package/dist/web-session.d.ts +35 -0
- package/dist/web-session.js +7 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +6 -0
- package/dist/web-shell-routes.js +7 -0
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-terminal.d.ts +4 -30
- package/dist/web-terminal.js +9 -6
- package/dist/web-terminal.js.map +1 -1
- package/dist/windows-agents.d.ts +4 -1
- package/dist/windows-agents.js +14 -10
- package/dist/windows-agents.js.map +1 -1
- package/dist/windows-cli-api.d.ts +12 -1
- package/dist/windows-cli-api.js +29 -2
- package/dist/windows-cli-api.js.map +1 -1
- package/dist/windows-cli-providers.d.ts +0 -9
- package/dist/windows-cli-providers.js +4 -9
- package/dist/windows-cli-providers.js.map +1 -1
- package/dist/windows-cli-worker.d.ts +25 -0
- package/dist/windows-cli-worker.js +98 -7
- package/dist/windows-cli-worker.js.map +1 -1
- package/dist/windows-cli.d.ts +11 -0
- package/dist/windows-cli.js +17 -3
- package/dist/windows-cli.js.map +1 -1
- package/dist/yaml-shared-nodes.js +8 -3
- package/dist/yaml-shared-nodes.js.map +1 -1
- package/launcher/agend-install.cjs +8 -1
- package/launcher/launchd-session-type.cjs +14 -0
- package/launcher/postinstall.cjs +27 -2
- package/launcher/private-home.cjs +1 -1
- package/launcher/tmux-bundle.cjs +247 -0
- package/package.json +3 -2
- package/templates/launchd.plist.ejs +3 -1
- package/templates/runtime-install/install.ps1 +270 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// Refs #3061 (P2a, P2b): Settings → Access & security → Sign-in & authorization → "Devices & sign-in", on a fleet with no chat
|
|
2
|
+
// connection. P2b: the signed-in devices — each with how it was approved (sign-in code / device code / host / authenticator),
|
|
3
|
+
// whether its owner is verified and when it was last active, this one marked, and a Sign out for the others that only the
|
|
4
|
+
// verified owner gets (POST /ui/devices/signout; the server decides, a disabled button is only the page saying so). The QR
|
|
5
|
+
// code on a new device's sign-in page opens this page at ?approve=<code>: the dialog opens with the code filled in — the
|
|
6
|
+
// person still presses Continue and Allow. "Add device" opens a dialog: type the 8-character code a new device is showing on its sign-in page (the
|
|
7
|
+
// device chose "Sign in with another device"), see who is asking — its label, whether it came from this computer or
|
|
8
|
+
// the network, its address and the time left — and Allow or Deny. Approving copies nothing from this device: the new
|
|
9
|
+
// browser signs itself in with a session of its own, and owner authorization is not part of it.
|
|
10
|
+
//
|
|
11
|
+
// Only the verified owner may approve (GET /ui/devices' `owner`): this computer's admin here, or signed in from outside
|
|
12
|
+
// with the authenticator's code. Anyone else sees the card, the explanation and a disabled button. The server decides
|
|
13
|
+
// that on every request and refuses everything else regardless (POST /ui/devices/{lookup,approve,deny} → 403).
|
|
14
|
+
// Refs #3061 (review of P2b): with web authorization off nobody is an owner, so nobody can add a device or sign another out —
|
|
15
|
+
// the card says so and points to `agend web-token rotate` on the AgEnD computer (which ends every session); and the
|
|
16
|
+
// confirm screen leads with where the request is from and its address (the device name is the browser's own word and can be
|
|
17
|
+
// faked) and says to allow only when the new device shows the same code.
|
|
18
|
+
// The words are English and 繁體中文, as everything in src/ui (tests/i18n-ui-literals-2390.test.ts).
|
|
19
|
+
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
20
|
+
import { t, register } from "/assets/app-i18n.js";
|
|
21
|
+
import { Dialog } from "/assets/ui-dialog.js";
|
|
22
|
+
import { api } from "./settings-confirm.js";
|
|
23
|
+
|
|
24
|
+
register("devices", {
|
|
25
|
+
en: {
|
|
26
|
+
title: "Devices & sign-in", lead: "Sign in a new device with an 8-character code. You approve it here, on a device that is already signed in as the owner.",
|
|
27
|
+
add: "Add device", noCopy: "Approving does not copy this device's sign-in. The new device gets a session of its own.",
|
|
28
|
+
ownerOnly: "Only a device whose owner is verified can add a device. Use the AgEnD computer, or sign in with the authenticator app.",
|
|
29
|
+
dlgTitle: "Add device", dlgLead: "On the new device, choose “Sign in with another device”, then enter the code it shows.",
|
|
30
|
+
codeLabel: "Code on the new device", find: "Continue",
|
|
31
|
+
confirmTitle: "Allow this device to sign in?", device: "Device", from: "From", address: "Address", left: "Time left", code: "Code",
|
|
32
|
+
fromHost: "This computer", fromNetwork: "The network (LAN or tailnet)",
|
|
33
|
+
grants: "General web actions only. Owner authorization is not included; it is verified separately.",
|
|
34
|
+
sameCode: "Only allow this if the new device's screen shows this same code. The device name comes from the browser and can be faked, so go by where it is from and its address.",
|
|
35
|
+
allow: "Allow", deny: "Deny", back: "Back", done: "Done",
|
|
36
|
+
approved: "Approved. The new device signs in within a few seconds.", denied: "Denied. The new device was told it may not sign in.",
|
|
37
|
+
notFound: "No device is waiting with that code. Check the code on the new device; it may have expired.",
|
|
38
|
+
expired: "That code has expired. Ask the new device for a new one.",
|
|
39
|
+
paused: "Too many wrong codes. Try again in {0}.", decided: "That request was already decided.",
|
|
40
|
+
lostOwner: "This device can no longer approve sign-ins: its owner verification has ended.",
|
|
41
|
+
minutes: "{0} minutes", minute: "1 minute",
|
|
42
|
+
listTitle: "Signed-in devices", refresh: "Refresh", approvedBy: "Approved by {0}",
|
|
43
|
+
viaCode: "sign-in code", viaDevice: "device code", viaHost: "this computer", viaTotp: "authenticator app",
|
|
44
|
+
ownerOk: "Owner verified", ownerNo: "Signed in, owner not verified yet",
|
|
45
|
+
signOutOwnerOnly: "Only a device whose owner is verified can sign out another device.",
|
|
46
|
+
signOutTitle: "Sign out this device?", signOutLead: "{0} will have to sign in again.", signOutGo: "Sign out",
|
|
47
|
+
signedOut: "{0} was signed out.", alreadyGone: "That device is already signed out.",
|
|
48
|
+
notSaved: "Signed out for now, but the change could not be saved: a restart may bring the session back. Fix the permissions on ~/.agend/web-sessions.json and sign it out again.",
|
|
49
|
+
authorityOffA: "Web authorization is off, so no device is the owner: none can add a device or sign another one out. To sign the other devices out, run ",
|
|
50
|
+
authorityOffB: " on the AgEnD computer. It ends every session, this one included, and every device has to sign in again.",
|
|
51
|
+
},
|
|
52
|
+
"zh-TW": {
|
|
53
|
+
title: "裝置與登入", lead: "用 8 碼代碼讓新裝置登入。在已登入且已驗證擁有者的裝置上,到這裡核准。",
|
|
54
|
+
add: "新增裝置", noCopy: "核准不會複製這台裝置的登入狀態,新裝置會取得自己的工作階段。",
|
|
55
|
+
ownerOnly: "只有已驗證擁有者的裝置才能新增裝置。請使用 AgEnD 電腦,或用驗證器 App 登入。",
|
|
56
|
+
dlgTitle: "新增裝置", dlgLead: "在新裝置上選「使用其他裝置登入」,再輸入它顯示的代碼。",
|
|
57
|
+
codeLabel: "新裝置上的代碼", find: "繼續",
|
|
58
|
+
confirmTitle: "允許這台裝置登入?", device: "裝置", from: "來源", address: "位址", left: "剩餘時間", code: "代碼",
|
|
59
|
+
fromHost: "這台電腦", fromNetwork: "網路(區網或 tailnet)",
|
|
60
|
+
grants: "只能使用一般的網頁功能,不含擁有者授權;擁有者授權需另外驗證。",
|
|
61
|
+
sameCode: "只有新裝置的畫面上顯示的是同一組代碼時才允許。裝置名稱來自瀏覽器、可能被偽造,請以來源和位址為準。",
|
|
62
|
+
allow: "允許", deny: "拒絕", back: "返回", done: "完成",
|
|
63
|
+
approved: "已核准。新裝置幾秒內就會登入。", denied: "已拒絕。新裝置會收到不能登入的通知。",
|
|
64
|
+
notFound: "沒有等待中的裝置使用這組代碼。請確認新裝置上的代碼;它可能已失效。",
|
|
65
|
+
expired: "這組代碼已失效。請讓新裝置重新取得代碼。",
|
|
66
|
+
paused: "錯誤次數太多,請 {0} 後再試。", decided: "這個請求已經處理過了。",
|
|
67
|
+
lostOwner: "這台裝置已不能核准登入:它的擁有者驗證已結束。",
|
|
68
|
+
minutes: "{0} 分鐘", minute: "1 分鐘",
|
|
69
|
+
listTitle: "已登入的裝置", refresh: "重新整理", approvedBy: "核准方式:{0}",
|
|
70
|
+
viaCode: "登入碼", viaDevice: "裝置代碼", viaHost: "主機", viaTotp: "驗證器 App",
|
|
71
|
+
ownerOk: "已驗證擁有者", ownerNo: "已登入,尚未驗證擁有者",
|
|
72
|
+
signOutOwnerOnly: "只有已驗證擁有者的裝置才能登出其他裝置。",
|
|
73
|
+
signOutTitle: "登出這台裝置?", signOutLead: "{0} 需要重新登入。", signOutGo: "登出",
|
|
74
|
+
signedOut: "已登出 {0}。", alreadyGone: "這台裝置已經登出了。",
|
|
75
|
+
notSaved: "暫時登出了,但變更沒能存檔:重新啟動後這個工作階段可能會回來。請修正 ~/.agend/web-sessions.json 的權限,再登出一次。",
|
|
76
|
+
authorityOffA: "網頁授權已關閉,所以沒有任何裝置是擁有者:不能新增裝置,也不能登出其他裝置。要登出其他裝置,請在 AgEnD 電腦上執行 ",
|
|
77
|
+
authorityOffB: "。這個指令會結束所有工作階段(包括目前這個),每台裝置都要重新登入。",
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
const td = (k, ...v) => t(`devices.${k}`, ...v);
|
|
81
|
+
/** The one thing that signs other devices out when nobody is an owner: a command, the same in both languages. */
|
|
82
|
+
export const ROTATE_COMMAND = "agend web-token rotate";
|
|
83
|
+
|
|
84
|
+
/** A wait as words: "2 minutes" / 「2 分鐘」 (rounded up). */
|
|
85
|
+
export function pauseWords(ms) {
|
|
86
|
+
const minutes = Math.max(1, Math.ceil(ms / 60000));
|
|
87
|
+
return minutes === 1 ? td("minute") : td("minutes", minutes);
|
|
88
|
+
}
|
|
89
|
+
/** How long ago, as words ("just now", "5 min ago", "2 h ago"; the app menu's own). */
|
|
90
|
+
export function agoWords(ms, now = Date.now()) {
|
|
91
|
+
const m = Math.round((now - ms) / 60000);
|
|
92
|
+
return m < 1 ? t("app.justNow") : m < 90 ? t("app.minAgo", m) : t("app.hrAgo", Math.round(m / 60));
|
|
93
|
+
}
|
|
94
|
+
/** The code a QR link carries (?approve=XXXX-XXXX), or "" when the address carries none or something else. */
|
|
95
|
+
export function approveCodeFrom(search) {
|
|
96
|
+
try {
|
|
97
|
+
const v = new URLSearchParams(search || "").get("approve");
|
|
98
|
+
return v && /^[0-9A-Za-z-]{8,12}$/.test(v) ? v : "";
|
|
99
|
+
} catch { return ""; }
|
|
100
|
+
}
|
|
101
|
+
/** The time left as m:ss. */
|
|
102
|
+
export function leftClock(ms) {
|
|
103
|
+
const s = Math.max(0, Math.ceil(ms / 1000));
|
|
104
|
+
return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function DevicesCard() {
|
|
108
|
+
const [s, setS] = useState(null);
|
|
109
|
+
// step: "code" (type it) | "confirm" (who is asking) | "done" (what happened). `msg`: a line under the field.
|
|
110
|
+
const [dlg, setDlg] = useState(null), [code, setCode] = useState(""), [msg, setMsg] = useState(""), [busy, setBusy] = useState(false), [now, setNow] = useState(Date.now());
|
|
111
|
+
// P2b: the device being signed out (asked to confirm), and the line saying how that went.
|
|
112
|
+
const [out, setOut] = useState(null), [note, setNote] = useState(null);
|
|
113
|
+
const live = useRef({ mounted: true, deepLink: false });
|
|
114
|
+
// The QR link (?approve=<code>) is read once, and taken out of the address so a reload does not open it again and the code
|
|
115
|
+
// does not stay in the history. Only the verified owner gets the dialog; anyone else just sees the card.
|
|
116
|
+
const takeDeepLink = (owner) => {
|
|
117
|
+
if (live.current.deepLink) return;
|
|
118
|
+
live.current.deepLink = true;
|
|
119
|
+
const wanted = approveCodeFrom(globalThis.location && globalThis.location.search);
|
|
120
|
+
if (!wanted) return;
|
|
121
|
+
try {
|
|
122
|
+
const url = new URL(globalThis.location.href);
|
|
123
|
+
url.searchParams.delete("approve");
|
|
124
|
+
globalThis.history.replaceState(globalThis.history.state, "", url.pathname + url.search + url.hash);
|
|
125
|
+
} catch { /* the address stays; nothing breaks */ }
|
|
126
|
+
if (owner) { setDlg({ step: "code" }); setCode(wanted); setMsg(""); setNow(Date.now()); }
|
|
127
|
+
};
|
|
128
|
+
const load = async () => {
|
|
129
|
+
let r = null;
|
|
130
|
+
try { r = await api("/ui/devices"); } catch { r = null; }
|
|
131
|
+
if (live.current.mounted && r && r.ok && r.body && typeof r.body === "object") { setS(r.body); if (r.body.webOnly) takeDeepLink(r.body.owner === true); }
|
|
132
|
+
};
|
|
133
|
+
useEffect(() => { live.current.mounted = true; load(); return () => { live.current.mounted = false; }; }, []);
|
|
134
|
+
// The confirm screen counts down; a request that ran out goes back to the field with the reason.
|
|
135
|
+
const step = dlg && dlg.step, expiresAt = dlg && dlg.request && dlg.request.expiresAt;
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (step !== "confirm") return undefined;
|
|
138
|
+
const timer = setInterval(() => setNow(Date.now()), 1000);
|
|
139
|
+
return () => clearInterval(timer);
|
|
140
|
+
}, [step]);
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (step === "confirm" && expiresAt && now >= expiresAt) { setDlg({ step: "code" }); setMsg(td("expired")); }
|
|
143
|
+
}, [now, step, expiresAt]);
|
|
144
|
+
if (!s || !s.webOnly) return null;
|
|
145
|
+
|
|
146
|
+
const close = () => { setDlg(null); setCode(""); setMsg(""); if (dlg && dlg.step === "done") load(); };
|
|
147
|
+
// A button the page disabled never reaches here in a browser; the guard is for anything that calls it anyway (the server refuses a non-owner regardless).
|
|
148
|
+
const open = () => { if (!s.owner) return; setDlg({ step: "code" }); setCode(""); setMsg(""); setNow(Date.now()); };
|
|
149
|
+
// What the server said, as a line for the person (a code that names nothing, a pause, an ended authority…).
|
|
150
|
+
const reason = (r) => {
|
|
151
|
+
const why = r.body && r.body.error;
|
|
152
|
+
if (r.status === 404) return td("notFound");
|
|
153
|
+
if (r.status === 429) return td("paused", pauseWords(Number(r.body && r.body.retryAfterMs) || 60000));
|
|
154
|
+
if (r.status === 409 || why === "already_decided") return td("decided");
|
|
155
|
+
if (r.status === 403) return td("lostOwner");
|
|
156
|
+
return t("app.failed");
|
|
157
|
+
};
|
|
158
|
+
const post = async (op, body) => {
|
|
159
|
+
setBusy(true); setMsg("");
|
|
160
|
+
try { return await api(`/ui/devices/${op}`, { method: "POST", body: JSON.stringify(body) }); }
|
|
161
|
+
catch { return { ok: false, status: 0, body: null }; }
|
|
162
|
+
finally { if (live.current.mounted) setBusy(false); }
|
|
163
|
+
};
|
|
164
|
+
const find = async () => {
|
|
165
|
+
const r = await post("lookup", { code });
|
|
166
|
+
if (!live.current.mounted) return;
|
|
167
|
+
if (r.ok && r.body && r.body.request) { setNow(Date.now()); setDlg({ step: "confirm", request: r.body.request }); return; }
|
|
168
|
+
setMsg(reason(r));
|
|
169
|
+
if (r.status === 403) load();
|
|
170
|
+
};
|
|
171
|
+
const decide = async (op) => {
|
|
172
|
+
const r = await post(op, { code: dlg.request.code });
|
|
173
|
+
if (!live.current.mounted) return;
|
|
174
|
+
if (r.ok) { setDlg({ step: "done", outcome: op }); return; }
|
|
175
|
+
setDlg({ step: "code" }); setMsg(reason(r));
|
|
176
|
+
if (r.status === 403) load();
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// P2b: sign another device out. The button is only offered to the owner and the server checks again (403 otherwise).
|
|
180
|
+
const askSignOut = (device) => { if (s.owner && !device.current) { setNote(null); setOut({ handle: device.handle, label: device.label }); } };
|
|
181
|
+
const signOut = async () => {
|
|
182
|
+
const target = out;
|
|
183
|
+
if (!target) return;
|
|
184
|
+
setBusy(true);
|
|
185
|
+
let r;
|
|
186
|
+
try { r = await api("/ui/devices/signout", { method: "POST", body: JSON.stringify({ handle: target.handle }) }); }
|
|
187
|
+
catch { r = { ok: false, status: 0, body: null }; }
|
|
188
|
+
if (!live.current.mounted) return;
|
|
189
|
+
setBusy(false); setOut(null);
|
|
190
|
+
if (r.ok) setNote({ ok: true, text: td("signedOut", target.label) });
|
|
191
|
+
else if (r.status === 404) setNote({ ok: false, text: td("alreadyGone") });
|
|
192
|
+
else if (r.status === 403) setNote({ ok: false, text: td("lostOwner") });
|
|
193
|
+
else if (r.body && r.body.error === "not_durable") setNote({ ok: false, text: td("notSaved") });
|
|
194
|
+
else setNote({ ok: false, text: t("app.failed") });
|
|
195
|
+
load();
|
|
196
|
+
};
|
|
197
|
+
// Web authorization off (the server says so): nobody is an owner, whoever is looking — "use the AgEnD computer" would not help.
|
|
198
|
+
const authorityOff = s.authority === false;
|
|
199
|
+
const devices = Array.isArray(s.devices) ? s.devices : [];
|
|
200
|
+
const others = devices.filter((d) => !d.current).length;
|
|
201
|
+
const viaText = (via) => td({ device: "viaDevice", host: "viaHost", totp: "viaTotp" }[via] || "viaCode");
|
|
202
|
+
|
|
203
|
+
const request = dlg && dlg.request;
|
|
204
|
+
const body = !dlg ? null : dlg.step === "code" ? html`
|
|
205
|
+
<p class="note" id="devLead">${td("dlgLead")}</p>
|
|
206
|
+
<div class="field"><label for="devCodeInput">${td("codeLabel")}</label>
|
|
207
|
+
<input id="devCodeInput" class="s-dev-code" type="text" autocomplete="off" autocapitalize="characters" autocorrect="off" spellcheck=${false}
|
|
208
|
+
maxlength="12" placeholder="XXXX-XXXX" value=${code} onInput=${(e) => { setCode(e.target.value); setMsg(""); }} /></div>
|
|
209
|
+
${msg ? html`<p class="feedback error" role="alert" id="devMsg">${msg}</p>` : null}`
|
|
210
|
+
: dlg.step === "confirm" ? html`
|
|
211
|
+
<p class="note" id="devConfirmLead">${td("confirmTitle")}</p>
|
|
212
|
+
<dl class="s-dev-facts" id="devFacts">
|
|
213
|
+
<div class="s-dev-key"><dt>${td("from")}</dt><dd id="devFrom">${td(request.peer === "host" ? "fromHost" : "fromNetwork")}</dd></div>
|
|
214
|
+
<div class="s-dev-key"><dt>${td("address")}</dt><dd id="devAddress">${request.address}</dd></div>
|
|
215
|
+
<div><dt>${td("code")}</dt><dd><code id="devCodeShown">${request.code}</code></dd></div>
|
|
216
|
+
<div><dt>${td("device")}</dt><dd id="devLabel">${request.label}</dd></div>
|
|
217
|
+
<div><dt>${td("left")}</dt><dd id="devLeft">${leftClock(request.expiresAt - now)}</dd></div>
|
|
218
|
+
</dl>
|
|
219
|
+
<p class="note s-va-warn" id="devSameCode">${td("sameCode")}</p>
|
|
220
|
+
<p class="note" id="devGrants">${td("grants")}</p>
|
|
221
|
+
<p class="note" id="devNoCopy">${td("noCopy")}</p>`
|
|
222
|
+
: html`<p class="note" role="status" id="devDone">${td(dlg.outcome === "approve" ? "approved" : "denied")}</p>`;
|
|
223
|
+
const actions = !dlg ? null : dlg.step === "code" ? html`
|
|
224
|
+
<button type="button" class="btn" id="devCancel" disabled=${busy} onClick=${close}>${t("app.cancel")}</button>
|
|
225
|
+
<button type="button" class="btn btn-primary" id="devFind" disabled=${busy || code.replace(/[^0-9A-Za-z]/g, "").length < 8} onClick=${find}>${td("find")}</button>`
|
|
226
|
+
: dlg.step === "confirm" ? html`
|
|
227
|
+
<button type="button" class="btn" id="devBack" disabled=${busy} onClick=${() => { setDlg({ step: "code" }); setMsg(""); }}>${td("back")}</button>
|
|
228
|
+
<button type="button" class="btn btn-danger" id="devDeny" disabled=${busy} onClick=${() => decide("deny")}>${td("deny")}</button>
|
|
229
|
+
<button type="button" class="btn btn-primary" id="devAllow" disabled=${busy} onClick=${() => decide("approve")}>${td("allow")}</button>`
|
|
230
|
+
: html`<button type="button" class="btn btn-primary" id="devDoneBtn" onClick=${close}>${td("done")}</button>`;
|
|
231
|
+
return html`<section class="card s-devices" id="devicesCard"><header class="s-auth-section-head"><div><h3>${td("title")}</h3><p id="devicesLead">${td("lead")}</p></div></header>
|
|
232
|
+
<p class="note" id="devicesNoCopy">${td("noCopy")}</p>
|
|
233
|
+
${devices.length ? html`<div class="s-dev-listhead"><h4 id="devicesListTitle">${td("listTitle")}</h4>
|
|
234
|
+
<button type="button" class="btn btn-sm" id="devicesRefresh" onClick=${load}>${td("refresh")}</button></div>
|
|
235
|
+
<ul class="s-dev-list" id="devicesList">${devices.map((d) => html`<li class=${`s-dev-row${d.current ? " current" : ""}`} key=${d.handle} data-handle=${d.handle}>
|
|
236
|
+
<div class="s-dev-main">
|
|
237
|
+
<span class="s-dev-name">${d.label}${d.current ? html` <span class="tag" data-this-device="1">${t("app.thisDevice")}</span>` : null}</span>
|
|
238
|
+
<span class="s-dev-meta">${td("approvedBy", viaText(d.via))} · <span data-owner=${d.ownerVerified ? "yes" : "no"}>${td(d.ownerVerified ? "ownerOk" : "ownerNo")}</span> · ${t("app.lastActive", agoWords(d.lastSeen))}</span>
|
|
239
|
+
</div>
|
|
240
|
+
${d.current ? null : html`<button type="button" class="btn btn-sm btn-danger" data-signout=${d.handle} disabled=${!s.owner || busy} onClick=${() => askSignOut(d)}>${t("app.signOut")}</button>`}
|
|
241
|
+
</li>`)}</ul>
|
|
242
|
+
${others && !s.owner && !authorityOff ? html`<p class="note" id="devicesSignOutOwnerOnly">${td("signOutOwnerOnly")}</p>` : null}
|
|
243
|
+
${note ? html`<p class=${`note ${note.ok ? "" : "error"}`} role=${note.ok ? "status" : "alert"} id="devicesNote">${note.text}</p>` : null}` : null}
|
|
244
|
+
${authorityOff ? html`<p class="note s-va-warn" id="devicesAuthorityOff">${td("authorityOffA")}<code id="devicesRotate">${ROTATE_COMMAND}</code>${td("authorityOffB")}</p>`
|
|
245
|
+
: !s.owner ? html`<p class="note" id="devicesOwnerOnly">${td("ownerOnly")}</p>` : null}
|
|
246
|
+
<div class="save-row"><button type="button" class="btn btn-primary" id="devicesAdd" disabled=${!s.owner} onClick=${open}>${td("add")}</button></div>
|
|
247
|
+
${dlg ? html`<${Dialog} title=${td("dlgTitle")} onClose=${close} busy=${busy} actions=${actions}>${body}</${Dialog}>` : null}
|
|
248
|
+
${out ? html`<${Dialog} title=${td("signOutTitle")} onClose=${() => { if (!busy) setOut(null); }} busy=${busy} actions=${html`
|
|
249
|
+
<button type="button" class="btn" id="devSignOutCancel" disabled=${busy} onClick=${() => setOut(null)}>${t("app.cancel")}</button>
|
|
250
|
+
<button type="button" class="btn btn-danger" id="devSignOutGo" disabled=${busy} onClick=${signOut}>${td("signOutGo")}</button>`}>
|
|
251
|
+
<p class="note" id="devSignOutLead">${td("signOutLead", out.label)}</p></${Dialog}>` : null}
|
|
252
|
+
</section>`;
|
|
253
|
+
}
|
|
@@ -17,7 +17,9 @@ import { startOperation } from "./settings-apply.js";
|
|
|
17
17
|
import { goToTarget } from "./settings-registry.js";
|
|
18
18
|
import { sectionPath } from "/assets/app-route.js";
|
|
19
19
|
import { backendLabel } from "/assets/instance-nav.js";
|
|
20
|
+
import {AgentRuntimeSettings} from "./agent-runtime-settings.js";
|
|
20
21
|
import "./settings-strings.js"; // its words, wherever a picker of this file is used (#2072: Fleet's create dialog too)
|
|
22
|
+
import "./settings-shared-strings.js"; // the words Shared agent settings added and this file draws (backendNotInstalledHost, changeInDefaults, …)
|
|
21
23
|
import { backendChoices, modelChoices, OTHER_MODEL, useBackendRows, useModelCatalogState } from "./settings-catalog.js";
|
|
22
24
|
import {
|
|
23
25
|
ACCESS_MODES, AGENT_MODES, CH_TYPES, DASHBOARD_CHOICES, DASHBOARD_FEATURES, HANG_TIMEOUT_DEFAULT_MINUTES, LOG_LEVELS, TOOL_PROGRESS, TOOL_SETS,
|
|
@@ -25,6 +27,11 @@ import {
|
|
|
25
27
|
chLabel, dashboardDefault, hasOwn, impactOf, newConnectionImpact, nonNegative, nonNegativeInteger, positive, replyGuardSupported, sameValue, visibilityDefault,
|
|
26
28
|
classicWebEchoEffective, toolSetDefault, worstImpact,
|
|
27
29
|
} from "./settings-model.js";
|
|
30
|
+
import "./settings-codex-copy.js"; // M-2446: the Speed field's words (a retained old settings-strings lacks them)
|
|
31
|
+
import { AccountSelect } from "./accounts-view.js"; // #3212: the Account field (a new module: never a stale named import)
|
|
32
|
+
/** M-2446: Codex speed choices (backend_options.codex.speed); "" = unset. Local, not imported: a stale tab may keep an
|
|
33
|
+
* older settings-model.js, and a new named import would fail this module's load. */
|
|
34
|
+
const CODEX_SPEED_CHOICES = ["", "standard", "fast"];
|
|
28
35
|
/** #2342: a field by id, for recordEdit before a pick or a reset writes it. */
|
|
29
36
|
const byId = (id) => (typeof document !== "undefined" ? document.getElementById(id) : null);
|
|
30
37
|
|
|
@@ -44,11 +51,11 @@ export function Select({ value, options, onChange, disabled, id, label }) {
|
|
|
44
51
|
* #2072: a backend field shows every backend with what this host says about it — one it cannot run is disabled with
|
|
45
52
|
* why (not installed, not signed in, too old); one not checked yet stays selectable; the current value always can be.
|
|
46
53
|
*/
|
|
47
|
-
export function BackendSelect({ value, onChange, disabled, id }) {
|
|
54
|
+
export function BackendSelect({ value, onChange, disabled, id, hostOnly }) {
|
|
48
55
|
const rows = useBackendRows();
|
|
49
56
|
const known = backendOptions(value).filter((o) => !o.unavailable).map((o) => o.value);
|
|
50
57
|
const opts = backendChoices(known, rows || [], value, {
|
|
51
|
-
notInstalled: tn("backendNotInstalled"), notSignedIn: tn("backendNotSignedIn"), tooOld: (v) => tn("backendTooOld", v),
|
|
58
|
+
notInstalled: tn(hostOnly ? "backendNotInstalledHost" : "backendNotInstalled"), notSignedIn: tn("backendNotSignedIn"), tooOld: (v) => tn("backendTooOld", v),
|
|
52
59
|
unchecked: tn("backendUnchecked"), removed: (v) => tn("backendUnavailable", v),
|
|
53
60
|
});
|
|
54
61
|
return html`<select id=${id} value=${value} disabled=${disabled} onChange=${(e) => onChange(e.target.value)}>
|
|
@@ -85,12 +92,12 @@ export function Label({ text, schema, field, htmlFor, mark }) {
|
|
|
85
92
|
return html`<label for=${htmlFor}>${text}${mark ? html` ${mark}` : null}${field ? html` <${Impact} schema=${schema} field=${field} />` : null}</label>`;
|
|
86
93
|
}
|
|
87
94
|
/** #2347 §10: the mark of a value nobody set — what is in effect is the built-in default. */
|
|
88
|
-
export function DefaultMark() {
|
|
89
|
-
return html`<span class="tag s-default">${tn("defaultMark")}</span>`;
|
|
95
|
+
export function DefaultMark({ tip }) {
|
|
96
|
+
return html`<span class="tag s-default" title=${tip || undefined}>${tn("defaultMark")}</span>`;
|
|
90
97
|
}
|
|
91
98
|
/** #2347 §10: what an empty field means — the value in effect, in plain text, and where it comes from (the mark, or why). */
|
|
92
|
-
export function InEffect({ text, why }) {
|
|
93
|
-
return html`<p class="s-effect">${tn("inEffect", text)} ${why ? html`<span class="tag">${why}</span>` : html`<${DefaultMark} />`}</p>`;
|
|
99
|
+
export function InEffect({ text, why, tip }) {
|
|
100
|
+
return html`<p class="s-effect">${tn("inEffect", text)} ${why ? html`<span class="tag">${why}</span>` : html`<${DefaultMark} tip=${tip} />`}</p>`;
|
|
94
101
|
}
|
|
95
102
|
/**
|
|
96
103
|
* #2347 §10: what an inherited field inherits — its value, marked "default" when nobody set it there either — and a
|
|
@@ -146,9 +153,9 @@ export function ChipList({ items, onChange, placeholder, label }) {
|
|
|
146
153
|
const replyHint = (backend, mode, kiroUi) => (replyGuardSupported(backend, mode, kiroUi) ? tn("replyGuardSupported") : tn("replyGuardUnsupported", backend, mode));
|
|
147
154
|
|
|
148
155
|
/** The dialog every editor uses: Cancel / Stage change; the footer says what the changes made so far will cost (#2346: only the fields that changed). */
|
|
149
|
-
function EditDialog({ title, subtitle, onClose, onStage, impacts, schema, children, ready = true, wide = true }) {
|
|
156
|
+
function EditDialog({ title, subtitle, onClose, onStage, impacts, schema, children, ready = true, wide = true, drawer = false }) {
|
|
150
157
|
const kinds = [...new Set((impacts || []).map((f) => impactOf(schema, f)))];
|
|
151
|
-
return html`<${Dialog} title=${title} label=${subtitle ? `${title} — ${subtitle}` : title} onClose=${onClose} wide=${wide}
|
|
158
|
+
return html`<${Dialog} title=${title} label=${subtitle ? `${title} — ${subtitle}` : title} onClose=${onClose} wide=${wide} drawer=${drawer}
|
|
152
159
|
actions=${html`${kinds.length ? html`<span class="note dlg-impact">${kinds.map(impactText).join(" · ")}</span>` : null}
|
|
153
160
|
<button type="button" class="btn" onClick=${onClose}>${tn("cancel")}</button>
|
|
154
161
|
<button type="button" class="btn btn-primary" disabled=${!ready} onClick=${onStage}>${tn("modalDone")}</button>`}>
|
|
@@ -288,7 +295,17 @@ export function AgentDialog({ name, inst, ctx, onClose }) {
|
|
|
288
295
|
const generalError = otherGeneral ? tn("oneGeneral", ctx.shortName(otherGeneral[0], otherGeneral[1])) : "";
|
|
289
296
|
const failoverWarn = !f.inherit.model_failover && !f.model_failover.trim() ? "failoverEmpty" : "";
|
|
290
297
|
const ready = !errors.auto && !errors.hang && !generalError;
|
|
291
|
-
|
|
298
|
+
// #3212: the agent's own credential profile for its CLI ("" = none: it follows the fleet default). Host agents only.
|
|
299
|
+
const acctBackend = f.backend || defaults.backend || "claude-code";
|
|
300
|
+
const ownAccount = (inst.backend_options && inst.backend_options[acctBackend] && inst.backend_options[acctBackend].credential_profile) || "";
|
|
301
|
+
const [acct, setAcct] = useState(ownAccount);
|
|
302
|
+
const pending = () => {
|
|
303
|
+
const patch = agentPatch({ ...f, status_emojis: emojis.value }, inst, defaults, visibilityBaseline, emojis.baseline);
|
|
304
|
+
if (inst.runtime === "windows" || acct === ownAccount) return patch;
|
|
305
|
+
const opts = { ...(patch.backend_options || {}) };
|
|
306
|
+
opts[acctBackend] = { ...(opts[acctBackend] || {}), credential_profile: acct || null };
|
|
307
|
+
return { ...patch, backend_options: opts };
|
|
308
|
+
};
|
|
292
309
|
const stage = () => {
|
|
293
310
|
if (!ready) return;
|
|
294
311
|
const patch = pending();
|
|
@@ -302,16 +319,20 @@ export function AgentDialog({ name, inst, ctx, onClose }) {
|
|
|
302
319
|
const inh = (k, value, target, kind, set = hasOwn(defaults, k)) => ({ text: valueText(value, kind), builtin: !set, from: target ? inAgentDefaults(target) : null });
|
|
303
320
|
const inheritedBackend = !inst.backend && f.backend === (defaults.backend || "claude-code");
|
|
304
321
|
const L = (text, field, id) => html`<${Label} text=${text} schema=${schema} field=${field} htmlFor=${id} />`;
|
|
305
|
-
return html`<${EditDialog} title=${ctx.shortName(name, inst)} subtitle=${tn("idLine", name)} onClose=${onClose} onStage=${stage} ready=${ready} impacts=${Object.keys(pending()).map((k) => `instance.${k}`)} schema=${schema}>
|
|
322
|
+
return html`<${EditDialog} title=${ctx.shortName(name, inst)} subtitle=${tn("idLine", name)} onClose=${onClose} onStage=${stage} ready=${ready} drawer=${true} impacts=${Object.keys(pending()).map((k) => `instance.${k}`)} schema=${schema}>
|
|
323
|
+
<${AgentRuntimeSettings} name=${name} inst=${{...inst,backend:f.backend}} inherited=${inheritedBackend ? html`<${Inherited} ...${inh("backend", f.backend, "#g-be", "backend")} />` : null} disabled=${Object.keys(pending()).length>0||ctx.staged?.size>0} onChanged=${()=>{ctx.reload();onClose();}}/>
|
|
306
324
|
<div class="grid2">
|
|
307
325
|
<div class="field">${L(tn("displayName"), "instance.display_name", "ag-dn")}
|
|
308
326
|
<${Override} inherit=${f.inherit.display_name} onInherit=${setInherit("display_name")} inherited=${inh("display_name", defaults.display_name || name, null, "", !!defaults.display_name)}>
|
|
309
327
|
<input id="ag-dn" type="text" placeholder=${name} disabled=${f.inherit.display_name} value=${shown("display_name", f.display_name, defaults.display_name || "")} onInput=${(e) => set("display_name")(e.target.value)} /></${Override}></div>
|
|
310
328
|
<div class="field">${L(tn("description"), "instance.description", "ag-desc")}<input id="ag-desc" type="text" value=${f.description} onInput=${(e) => set("description")(e.target.value)} /></div>
|
|
311
|
-
<div class="field">${L(tn("backend"), "instance.backend", "ag-be")}<${BackendSelect} id="ag-be" value=${f.backend} onChange=${set("backend")} />
|
|
312
|
-
${inheritedBackend ? html`<${Inherited} ...${inh("backend", f.backend, "#g-be", "backend")} />` : null}</div>
|
|
313
329
|
<div class="field">${L(tn("model"), "instance.model", "ag-model")}<${ModelSelect} id="ag-model" value=${f.model} onChange=${set("model")}
|
|
314
330
|
backend=${f.backend || defaults.backend || "claude-code"} instance=${name} inherit=${tn("inheritValue", defaults.model || tn("modelCliDefault"))} /></div>
|
|
331
|
+
${(f.backend || defaults.backend || "claude-code") === "codex" && inst.runtime !== "windows" ? html`<div class="field codex-speed">${L(tn("codexSpeed"), "instance.backend_options", "ag-speed")}
|
|
332
|
+
<${Select} id="ag-speed" value=${f.codex_speed} onChange=${set("codex_speed")}
|
|
333
|
+
options=${CODEX_SPEED_CHOICES.map((v) => ({ value: v, label: tn(v === "fast" ? "codexSpeedFast" : v === "standard" ? "codexSpeedStandard" : "codexSpeedDefault") }))} />
|
|
334
|
+
<p class="note">${tn("codexSpeedHint")}</p></div>` : null}
|
|
335
|
+
${inst.runtime !== "windows" && ["claude-code", "codex", "kiro-cli"].includes(acctBackend) ? html`<${AccountSelect} id="ag-account" backend=${acctBackend} value=${acct} onChange=${setAcct} />` : null}
|
|
315
336
|
</div>
|
|
316
337
|
<div class="field">${L(tn("workingDir"), "instance.working_directory", "ag-wd")}<input id="ag-wd" type="text" value=${f.working_directory} onInput=${(e) => set("working_directory")(e.target.value)} /></div>
|
|
317
338
|
<div class="field">${L(`${tn("autoPause")} (${tn("minutes")})`, "instance.auto_pause_after", "ag-auto")}
|
|
@@ -16,6 +16,7 @@ import { confirmDialog } from "/assets/ui-confirm.js";
|
|
|
16
16
|
import { api } from "./settings-confirm.js";
|
|
17
17
|
import { DEFAULT_SCHEMA, impactOf } from "./settings-model.js";
|
|
18
18
|
import "./settings-strings.js";
|
|
19
|
+
import { layoutText } from "./settings-layout.js";
|
|
19
20
|
|
|
20
21
|
const tn = (k, ...v) => t(`settings.${k}`, ...v);
|
|
21
22
|
const PLATFORMS = { discord: "Discord", telegram: "Telegram" };
|
|
@@ -93,6 +94,7 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
93
94
|
const [overview, setOverview] = useState(null), [failed, setFailed] = useState(false);
|
|
94
95
|
const [people, setPeople] = useState(null), [query, setQuery] = useState(""), [editing, setEditing] = useState(null);
|
|
95
96
|
const [sendState, setSendState] = useState({}), [now, setNow] = useState(() => Date.now());
|
|
97
|
+
const [viewedGuest, setViewedGuest] = useState(null);
|
|
96
98
|
const [status, setStatus] = useState(null); // { kind: "waiting" } | { kind: "failed", error }
|
|
97
99
|
const load = async () => {
|
|
98
100
|
let r = null;
|
|
@@ -211,6 +213,7 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
211
213
|
};
|
|
212
214
|
|
|
213
215
|
const rows = f.grants ? [...new Set([...Object.keys(f.grants), ...Object.keys(original.grants || {})])] : [];
|
|
216
|
+
const activeGuest = rows.includes(editing) ? editing : rows.includes(viewedGuest) ? viewedGuest : rows[0];
|
|
214
217
|
const q = query.trim().toLowerCase();
|
|
215
218
|
const candidates = (people || []).filter((p) => !(f.grants && own(f.grants, accountKey(p))))
|
|
216
219
|
.filter((p) => !q || [p.name, p.username, p.userId].some((x) => typeof x === "string" && x.toLowerCase().includes(q))).slice(0, 8);
|
|
@@ -218,21 +221,32 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
218
221
|
return html`<section class="card s-guests" id="guests"><h3>${tn("guestsTitle")}</h3>
|
|
219
222
|
<p class="note">${tn("grantsHint")}</p>
|
|
220
223
|
<fieldset class="s-guest-fields" disabled=${readOnly}>
|
|
221
|
-
<label class=${`check${f.enabled !== original.enabled ? " s-dirty" : ""}`}><input id="guestsEnabled" type="checkbox" checked=${f.enabled} onChange=${(e) => set({ enabled: e.target.checked })} /><span>${tn("guestsEnabled")}</span></label>
|
|
224
|
+
<div class="s-guest-policy"><div> <label class=${`check${f.enabled !== original.enabled ? " s-dirty" : ""}`}><input class="s-ui-toggle" id="guestsEnabled" type="checkbox" checked=${f.enabled} onChange=${(e) => set({ enabled: e.target.checked })} /><span>${tn("guestsEnabled")}</span></label>
|
|
222
225
|
<p class="note">${tn("guestsEnabledHint")}</p>
|
|
223
|
-
<label class=${`check${f.chat !== original.chat ? " s-dirty" : ""}`}><input id="guestsChat" type="checkbox" checked=${f.chat} onChange=${(e) => set({ chat: e.target.checked })} /><span>${tn("guestsChat")}</span></label>
|
|
226
|
+
</div><div> <label class=${`check${f.chat !== original.chat ? " s-dirty" : ""}`}><input class="s-ui-toggle" id="guestsChat" type="checkbox" checked=${f.chat} onChange=${(e) => set({ chat: e.target.checked })} /><span>${tn("guestsChat")}</span></label>
|
|
224
227
|
<p class="note">${tn("guestsChatHint")}</p>
|
|
228
|
+
</div></div>
|
|
225
229
|
${failed ? html`<p class="note" role="status">${tn("guestsLoadFailed")} <button type="button" class="btn btn-sm" onClick=${load}>${t("app.retry")}</button></p>`
|
|
226
230
|
: !overview ? html`<p class="note">${t("app.loading")}</p>` : null}
|
|
227
231
|
${!f.grants && overview ? html`<div class="g-legacy"><p class="note">${tn("grantsLegacy")}</p>
|
|
228
232
|
${readOnly ? null : html`<button type="button" class="btn btn-sm" id="grantsConvert" onClick=${convert}>${tn("grantsConvert")}</button>`}</div>` : null}
|
|
229
|
-
|
|
230
|
-
|
|
233
|
+
<div class="s-guest-workbench"><section class="s-guest-list-card"><h4>${layoutText("revGuestManagement")}</h4>
|
|
234
|
+
<div class="s-guest-columns" aria-hidden="true"><span>${tn("guestsTitle")}</span><span>${layoutText("revVisibleAgents")}</span><span>${layoutText("revGuestLevel")}</span><span>${tn("settingsButton")}</span></div>
|
|
235
|
+
${!rows.length ? html`<p class="note" id="grantsNone">${tn("grantsNoneYet")}</p>` : html`<ul class="guest-list">${rows.map(k => {
|
|
236
|
+
const person=who(k), grant=f.grants?.[k] || original.grants?.[k];
|
|
237
|
+
return html`<li key=${k} class=${`guest-summary${activeGuest === k ? " is-selected" : ""}`}>
|
|
238
|
+
<span class="g-summary-name"><strong>${person.name}</strong><small>${PLATFORMS[person.platform] || person.platform}</small></span>
|
|
239
|
+
<span class="g-summary-agents">${(grant?.instances || []).map(n => html`<span key=${n}>${shownName(rooms,n)}</span>`)}</span>
|
|
240
|
+
<span>${tn(levelOf(grant) === "trusted" ? "grantsLevelTrusted" : "grantsLevelChat")}</span>
|
|
241
|
+
<button type="button" class="btn btn-sm" aria-pressed=${activeGuest === k ? "true" : "false"} aria-controls=${`guest-detail-${encodeURIComponent(k)}`} onClick=${() => {setViewedGuest(k);setEditing(k);}}>${tn("settingsButton")}</button>
|
|
242
|
+
</li>`;
|
|
243
|
+
})}</ul>`}</section>
|
|
244
|
+
<aside class="s-guest-detail-card" aria-label=${layoutText("revGuestDetail")}>${rows.map((k) => {
|
|
231
245
|
const person = who(k), draft = f.grants && f.grants[k], saved = original.grants && original.grants[k];
|
|
232
246
|
const removed = !draft, added = !saved, dirty = removed || added || !sameGrant(draft, saved);
|
|
233
247
|
const applied = !!saved && saved.instances.length > 0 && !dirty;
|
|
234
248
|
const ss = sendState[k] || {}, cooling = ss.until && ss.until > now;
|
|
235
|
-
return html`<
|
|
249
|
+
return html`<section key=${k} hidden=${!readOnly && activeGuest !== k} id=${`guest-detail-${encodeURIComponent(k)}`} class=${`guest-row${dirty ? " s-dirty" : ""}${removed ? " g-removed" : ""}`} data-account=${k}>
|
|
236
250
|
<div class="g-head"><span class="g-av" aria-hidden="true">${(person.name || "?").slice(0, 1).toUpperCase()}</span>
|
|
237
251
|
<div class="g-id"><strong>${person.name}</strong> <span class="note">${PLATFORMS[person.platform] || person.platform}${person.username ? ` · @${person.username}` : ""}</span></div>
|
|
238
252
|
${removed ? html`<span class="g-state">${tn("grantsWillBeRemoved")}</span>` : added ? html`<span class="g-state">${tn("grantsNew")}</span>` : pill(person)}</div>
|
|
@@ -255,23 +269,23 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
255
269
|
: html`<button type="button" class="btn btn-sm" onClick=${() => setGrant(k, { ...saved })}>${tn("grantsUndoRemove")}</button>`}
|
|
256
270
|
${person.guest && (person.guest.sessions || person.guest.devices) ? html`<button type="button" class="btn btn-sm" onClick=${() => signOut(person)}>${tn("guestSignOut")}</button>` : null}
|
|
257
271
|
</div>`}
|
|
258
|
-
</
|
|
259
|
-
})}</
|
|
260
|
-
${readOnly ? null : html`<
|
|
272
|
+
</section>`;
|
|
273
|
+
})}${!rows.length ? html`<p class="note">${layoutText("revSelectGuest")}</p>` : null}</aside></div>
|
|
274
|
+
${readOnly ? null : html`<details class="s-guest-add"><summary>${tn("grantsAdd")}</summary><div>
|
|
261
275
|
<input type="search" class="input g-search" id="grantsSearch" value=${query} aria-label=${tn("grantsSearch")} placeholder=${tn("grantsSearch")} onInput=${(e) => setQuery(e.target.value)} />
|
|
262
276
|
${people === null ? html`<p class="note">${t("app.loading")}</p>` : !candidates.length ? html`<p class="note" id="grantsNoPeople">${tn("grantsNoPeople")}</p>`
|
|
263
277
|
: html`<ul class="g-pick">${candidates.map((p) => html`<li key=${accountKey(p)} class="g-cand" data-account=${accountKey(p)}>
|
|
264
278
|
<span class="g-av" aria-hidden="true">${(p.name || "?").slice(0, 1).toUpperCase()}</span>
|
|
265
279
|
<div class="g-id"><strong>${p.name}</strong> <span class="note">${PLATFORMS[p.platform] || p.platform}${p.username ? ` · @${p.username}` : ""} · <span class="g-when">${tn("grantsLastSeen", new Date(p.lastSeen).toLocaleString())}</span></span>
|
|
266
280
|
${p.instances && p.instances.length ? html`<div class="note">${wroteTo(p.instances)}</div>` : null}</div>
|
|
267
|
-
<button type="button" class="btn btn-sm" onClick=${() => { const k = accountKey(p); setGrant(k, { ...(p.name ? { name: p.name } : {}), instances: choosable.filter((n) => (p.instances || []).includes(n)) }); setEditing(k); }}>${tn("grantsChoose")}</button></li>`)}</ul>`}
|
|
281
|
+
<button type="button" class="btn btn-sm" onClick=${() => { const k = accountKey(p); setGrant(k, { ...(p.name ? { name: p.name } : {}), instances: choosable.filter((n) => (p.instances || []).includes(n)) }); setEditing(k); }}>${tn("grantsChoose")}</button></li>`)}</ul>`}</div></details>`}
|
|
268
282
|
</fieldset>
|
|
269
|
-
${overview && overview.audit ? html`<
|
|
283
|
+
${overview && overview.audit ? html`<details class="s-guest-audit"><summary>${tn("grantsRecent")}</summary>${!overview.audit.length ? html`<p class="note" id="grantsRecentNone">${tn("grantsRecentNone")}</p>`
|
|
270
284
|
: html`<ul class="g-audit" id="grantsRecentList">${overview.audit.map((e, i) => html`<li key=${`${e.at}-${i}`} class="g-audit-row" data-kind=${e.kind}>
|
|
271
285
|
<span class="g-when">${new Date(e.at).toLocaleString()}</span> <strong>${e.name}</strong>
|
|
272
286
|
${e.kind === "grant" ? html`${e.added.map((n) => html` <span key=${`+${n}`} class="g-wrote g-add">+${n}</span>`)}${e.removed.map((n) => html` <span key=${`-${n}`} class="g-wrote g-del">−${n}</span>`)}${e.level ? html` <span class="g-wrote g-level-to">${tn("grantsAuditLevel", tn(e.level === "trusted" ? "grantsLevelTrusted" : "grantsLevelChat"))}</span>` : null}
|
|
273
287
|
<span class="note"> · <span class="g-wrote">${tn(e.via === "confirmed" ? "grantsAuditConfirmed" : "grantsAuditDirect")}</span>${e.endedSessions ? html` · <span class="g-wrote">${tn("grantsAuditEnded", e.endedSessions)}</span>` : null}</span>`
|
|
274
|
-
: html` <span class="note">${e.outcome === "sent" ? tn("grantsAuditCodeSent") : tn("grantsAuditCodeNot", auditOutcome(e.outcome))}</span>`}</li>`)}</ul>`}
|
|
288
|
+
: html` <span class="note">${e.outcome === "sent" ? tn("grantsAuditCodeSent") : tn("grantsAuditCodeNot", auditOutcome(e.outcome))}</span>`}</li>`)}</ul>`}</details>` : null}
|
|
275
289
|
${status && status.kind === "waiting" ? html`<p class="note" role="status">${tn("grantsWaiting")}</p>` : null}
|
|
276
290
|
${status && status.kind === "failed" ? html`<p class="note g-error" role="alert">${tn("grantsSaveFailed", status.error)}</p>` : null}
|
|
277
291
|
</section>`;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Lazy host-only card. Own every string so a retained Settings shell can load this newer card.
|
|
2
|
+
import { html, useEffect, useState } from "/assets/app-html.js";
|
|
3
|
+
import { register, t } from "/assets/app-i18n.js";
|
|
4
|
+
import { api, confirmedWrite } from "./settings-confirm.js";
|
|
5
|
+
register("hubBrowserCertificate", {
|
|
6
|
+
en: {
|
|
7
|
+
title: "Hub browser certificate", fingerprint: "SHA-256 fingerprint", expires: "Expires", generate: "Generate self-signed certificate",
|
|
8
|
+
import: "Import a certificate and private key", certificateFile: "Certificate file", keyFile: "Private key file",
|
|
9
|
+
hint: "File paths are relative to the AgEnD home on the Hub computer. Both files and their parent directories must be private to its owner. The certificate must cover the Hub web address.",
|
|
10
|
+
boundary: "This changes browser HTTPS only. Member pairing and its transport certificate stay the same.",
|
|
11
|
+
prepare: "Prepare replacement", replace: "Confirm replacement", saved: "Browser certificate replaced. New connections use it.",
|
|
12
|
+
restart: "The replacement is saved. Restart the Hub to activate it.",
|
|
13
|
+
selfSigned: "Self-signed certificate: browsers will warn unless you trust it separately. Confirm the fingerprint before trusting it.",
|
|
14
|
+
failed: "The certificate could not be prepared or saved. Check the private file paths, key match, web hostname and expiry, or that OpenSSL is installed for generation. Reload and try again.",
|
|
15
|
+
conflict: "The certificate or proposal changed or expired. Reload and prepare it again.",
|
|
16
|
+
unavailable: "Start the initialized Hub to view or replace its browser certificate.",
|
|
17
|
+
},
|
|
18
|
+
"zh-TW": {
|
|
19
|
+
title: "Hub 瀏覽器憑證", fingerprint: "SHA-256 指紋", expires: "到期時間", generate: "產生新的自簽憑證",
|
|
20
|
+
import: "匯入憑證與私鑰", certificateFile: "憑證檔案", keyFile: "私鑰檔案",
|
|
21
|
+
hint: "檔案路徑相對於 Hub 電腦上的 AgEnD 主目錄。兩個檔案及其上層目錄都必須僅供擁有者存取;憑證必須涵蓋 Hub 網址。",
|
|
22
|
+
boundary: "這只會變更瀏覽器 HTTPS;成員配對及其傳輸憑證保持不變。",
|
|
23
|
+
prepare: "準備替換憑證", replace: "確認替換", saved: "已替換瀏覽器憑證;新連線會使用新憑證。",
|
|
24
|
+
restart: "已儲存替換憑證,請重新啟動 Hub 以套用。",
|
|
25
|
+
selfSigned: "自簽憑證:除非另外設定信任,否則瀏覽器會顯示警告。請先核對指紋再信任。",
|
|
26
|
+
failed: "無法準備或儲存憑證。請檢查私有檔案路徑、私鑰是否相符、網址主機名稱與到期時間;產生憑證需要安裝 OpenSSL。請重新整理後再試。",
|
|
27
|
+
conflict: "憑證或提案已變更或過期,請重新整理後重新準備。", unavailable: "請先啟動已初始化的 Hub,再查看或替換瀏覽器憑證。",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const copy = key => t(`hubBrowserCertificate.${key}`), path = "/api/settings/hub/browser-certificate";
|
|
31
|
+
export function HubBrowserCertificateSettings() {
|
|
32
|
+
const [view, setView] = useState(null), [mode, setMode] = useState("generate"), [certFile, setCertFile] = useState(""), [keyFile, setKeyFile] = useState("");
|
|
33
|
+
const [proposal, setProposal] = useState(null), [busy, setBusy] = useState(false), [messageKey, setMessageKey] = useState("");
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
let live = true;
|
|
36
|
+
api(path).then(r => { if (live) { if (r.ok && r.body?.certificate) setView(r.body.certificate); else setMessageKey("unavailable"); } },
|
|
37
|
+
() => { if (live) setMessageKey("unavailable"); });
|
|
38
|
+
return () => { live = false; };
|
|
39
|
+
}, []);
|
|
40
|
+
const fail = r => setMessageKey(r?.body?.error === "conflict" ? "conflict" : "failed");
|
|
41
|
+
const prepare = async e => {
|
|
42
|
+
e.preventDefault(); if (!view || busy) return;
|
|
43
|
+
setBusy(true); setProposal(null); setMessageKey("");
|
|
44
|
+
try {
|
|
45
|
+
const body = { mode, revision: view.revision, ...(mode === "import" ? { certificateFile: certFile, keyFile } : {}) };
|
|
46
|
+
const r = await api(`${path}/prepare`, { method: "POST", body: JSON.stringify(body) });
|
|
47
|
+
if (r.ok && r.body?.proposal) setProposal(r.body.proposal); else fail(r);
|
|
48
|
+
} catch { fail(); } finally { setBusy(false); }
|
|
49
|
+
};
|
|
50
|
+
const replace = async () => {
|
|
51
|
+
if (!proposal || busy) return;
|
|
52
|
+
setBusy(true); setMessageKey("");
|
|
53
|
+
try {
|
|
54
|
+
const r = await confirmedWrite(`${path}/apply`, { method: "POST", label: copy("title"), body: { reference: proposal.reference, revision: proposal.revision } });
|
|
55
|
+
if (r.ok && r.body?.certificate) { setView(r.body.certificate); setProposal(null); setMessageKey(r.body.certificate.restartRequired ? "restart" : "saved"); }
|
|
56
|
+
else fail(r);
|
|
57
|
+
} catch { fail(); } finally { setBusy(false); }
|
|
58
|
+
};
|
|
59
|
+
const details = info => html`<dl class="s-web-ro"><dt>${copy("fingerprint")}</dt><dd>${info.fingerprint256}</dd><dt>${copy("expires")}</dt><dd>${info.validTo}</dd></dl>`;
|
|
60
|
+
return html`<section class="card hub-browser-certificate"><h3>${copy("title")}</h3><p class="note">${copy("boundary")}</p>
|
|
61
|
+
${view ? html`${details(view.selected)}${view.restartRequired ? html`<p role="status">${copy("restart")}</p>` : null}
|
|
62
|
+
<form class="form" onSubmit=${prepare}><label class="field"><select aria-label=${copy("title")} value=${mode} disabled=${busy} onChange=${e => { setMode(e.target.value); setProposal(null); }}>
|
|
63
|
+
<option value="generate">${copy("generate")}</option><option value="import">${copy("import")}</option></select></label>
|
|
64
|
+
${mode === "import" ? html`<p class="note">${copy("hint")}</p><div class="grid2">
|
|
65
|
+
<label class="field">${copy("certificateFile")}<input value=${certFile} disabled=${busy} onInput=${e => { setCertFile(e.target.value); setProposal(null); }} /></label>
|
|
66
|
+
<label class="field">${copy("keyFile")}<input value=${keyFile} disabled=${busy} onInput=${e => { setKeyFile(e.target.value); setProposal(null); }} /></label>
|
|
67
|
+
</div>` : null}
|
|
68
|
+
<button class="btn" disabled=${busy || (mode === "import" && (!certFile || !keyFile))}>${copy("prepare")}</button>
|
|
69
|
+
</form>` : null}
|
|
70
|
+
${proposal ? html`<div class="hub-certificate-proposal">${details(proposal.certificate)}${proposal.certificate.selfSigned ? html`<p role="note">${copy("selfSigned")}</p>` : null}
|
|
71
|
+
<button class="btn" disabled=${busy} onClick=${replace}>${copy("replace")}</button></div>` : null}
|
|
72
|
+
${messageKey ? html`<p role="status">${copy(messageKey)}</p>` : null}
|
|
73
|
+
</section>`;
|
|
74
|
+
}
|