windows-development-sandbox 1.20.0 → 1.23.1
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/config.example.json +8 -1
- package/dist/app/features/access/access.def.js +5 -2
- package/dist/app/features/access/access.run.js +7 -3
- package/dist/app/features/accounts/accounts.def.d.ts +29 -1
- package/dist/app/features/accounts/accounts.def.js +10 -4
- package/dist/app/features/accounts/accounts.run.d.ts +1 -0
- package/dist/app/features/accounts/accounts.run.js +7 -2
- package/dist/app/features/accounts/services.def.d.ts +4 -1
- package/dist/app/features/accounts/services.def.js +15 -14
- package/dist/app/features/accounts/services.run.d.ts +1 -0
- package/dist/app/features/accounts/services.run.js +41 -15
- package/dist/app/features/defs.d.ts +39 -2
- package/dist/app/features/engine/engine.run.js +1 -1
- package/dist/app/features/github/github.def.d.ts +44 -3
- package/dist/app/features/github/github.def.js +145 -63
- package/dist/app/features/github/github.run.d.ts +9 -2
- package/dist/app/features/github/github.run.js +43 -5
- package/dist/app/features/health/health.def.js +8 -2
- package/dist/app/features/logs/logs.def.js +0 -8
- package/dist/app/features/projects/projects.def.js +2 -2
- package/dist/app/features/projects/projects.run.js +5 -5
- package/dist/app/features/sandbox/sandbox.def.js +7 -3
- package/dist/app/features/sessions/sessions.def.d.ts +4 -4
- package/dist/app/features/sessions/sessions.def.js +0 -5
- package/dist/app/features/sessions/sessions.run.d.ts +1 -1
- package/dist/app/features/sessions/sessions.run.js +2 -2
- package/dist/app/features/settings/categories.def.js +2 -0
- package/dist/app/features/settings/settings-rows.js +1 -1
- package/dist/app/features/settings/settings.def.js +1 -1
- package/dist/app/features/settings/settings.run.js +3 -3
- package/dist/app/features/storage/storage.run.js +18 -9
- package/dist/app/features/updates/update-lines.js +2 -2
- package/dist/app/features/updates/updates.def.js +1 -1
- package/dist/app/features/updates/updates.run.js +1 -1
- package/dist/app/features/web/web.def.js +2 -2
- package/dist/app/features/web/web.run.js +12 -4
- package/dist/app/kernel/errors.d.ts +7 -0
- package/dist/app/kernel/errors.js +18 -3
- package/dist/app/kernel/rpc.d.ts +5 -0
- package/dist/app/kernel/view.d.ts +11 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-DK4NTBUF.js → chunk-7YPEDAJD.js} +172 -48
- package/dist/bin/{chunk-2IMT7ZCT.js → chunk-QFSJX2KW.js} +1 -1
- package/dist/bin/{chunk-Z2P5OGKL.js → chunk-USTRSHIE.js} +2436 -1693
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/manifest.d.ts +2 -2
- package/dist/cli/manifest.js +2 -1
- package/dist/cli/menu/coverage-exempt.d.ts +17 -0
- package/dist/cli/menu/coverage-exempt.js +61 -0
- package/dist/cli/menu/io-menu.d.ts +2 -0
- package/dist/cli/menu/io-menu.js +50 -5
- package/dist/cli/menu/pages/accounts-page.js +1 -1
- package/dist/cli/menu/pages/agents-page.js +8 -2
- package/dist/cli/menu/pages/maintenance-page.d.ts +6 -0
- package/dist/cli/menu/pages/maintenance-page.js +9 -2
- package/dist/cli/menu/pages/sessions-page.d.ts +2 -0
- package/dist/cli/menu/pages/sessions-page.js +12 -4
- package/dist/cli/menu/pages/settings-page.js +12 -1
- package/dist/cli/menu/remote-menu.js +1 -1
- package/dist/cli/menu/shell.d.ts +5 -0
- package/dist/cli/menu/shell.js +13 -0
- package/dist/cli/report.js +2 -0
- package/dist/cli/tui/app.d.ts +5 -0
- package/dist/cli/tui/app.js +2 -0
- package/dist/core/config/defaults.js +3 -1
- package/dist/core/schema/accounts.d.ts +6 -0
- package/dist/core/schema/accounts.js +13 -11
- package/dist/core/schema/config.d.ts +20 -8
- package/dist/core/schema/config.js +4 -4
- package/dist/core/schema/github.js +1 -1
- package/dist/core/schema/profile.js +8 -4
- package/dist/core/schema/resume.js +1 -1
- package/dist/core/schema/sandbox.js +3 -3
- package/dist/core/schema/vpn.js +1 -1
- package/dist/core/schema/web.js +3 -3
- package/dist/core/types.d.ts +6 -0
- package/dist/core/util/errors.d.ts +11 -1
- package/dist/core/util/errors.js +7 -1
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- package/dist/guest/accounts/adapter.d.ts +2 -0
- package/dist/guest/accounts/adapters.js +4 -0
- package/dist/guest/accounts/apply.d.ts +6 -2
- package/dist/guest/accounts/kinds/cfx.d.ts +7 -0
- package/dist/guest/accounts/kinds/cfx.js +33 -3
- package/dist/guest/accounts/kinds/comet.d.ts +7 -0
- package/dist/guest/accounts/kinds/comet.js +50 -0
- package/dist/guest/accounts/kinds/perplexity.d.ts +2 -0
- package/dist/guest/accounts/kinds/perplexity.js +12 -0
- package/dist/guest/accounts/watch.d.ts +2 -0
- package/dist/guest/accounts/watch.js +12 -2
- package/dist/guest/agents/agent-installer.js +1 -1
- package/dist/guest/agents/profile-links.d.ts +2 -0
- package/dist/guest/agents/profile-links.js +18 -4
- package/dist/guest/apps/after-install.js +19 -0
- package/dist/guest/apps/app-installer.d.ts +11 -0
- package/dist/guest/apps/app-installer.js +69 -6
- package/dist/guest/apps/comet-unpack.d.ts +20 -0
- package/dist/guest/apps/comet-unpack.js +127 -0
- package/dist/guest/apps/index.d.ts +1 -1
- package/dist/guest/apps/index.js +1 -1
- package/dist/guest/apps/resolvers-agents-web.d.ts +2 -0
- package/dist/guest/apps/resolvers-agents-web.js +7 -0
- package/dist/guest/apps/resolvers.js +2 -0
- package/dist/guest/apps/shortcuts.d.ts +2 -0
- package/dist/guest/apps/shortcuts.js +1 -0
- package/dist/guest/apps/unpack.js +14 -4
- package/dist/guest/boot/boot.d.ts +45 -16
- package/dist/guest/boot/boot.js +316 -145
- package/dist/guest/boot/graph.d.ts +252 -0
- package/dist/guest/boot/graph.js +257 -0
- package/dist/guest/boot/guide-lines.d.ts +25 -0
- package/dist/guest/boot/guide-lines.js +41 -0
- package/dist/guest/boot/guide.d.ts +1 -4
- package/dist/guest/boot/guide.js +6 -8
- package/dist/guest/boot/runner.d.ts +77 -0
- package/dist/guest/boot/runner.js +215 -0
- package/dist/guest/browser/cdp.d.ts +71 -0
- package/dist/guest/browser/cdp.js +306 -0
- package/dist/guest/browser/comet.d.ts +28 -0
- package/dist/guest/browser/comet.js +155 -0
- package/dist/guest/daemon/project-provisioner.js +6 -1
- package/dist/guest/devtools/fivem.d.ts +1 -1
- package/dist/guest/devtools/fivem.js +243 -3
- package/dist/guest/entries/daemon.js +2 -0
- package/dist/guest/runtime/log.d.ts +12 -0
- package/dist/guest/runtime/log.js +29 -5
- package/dist/guest/runtime/pools.d.ts +24 -0
- package/dist/guest/runtime/pools.js +60 -0
- package/dist/guest/runtime/process.d.ts +4 -0
- package/dist/guest/runtime/process.js +38 -1
- package/dist/guest/runtime/status.d.ts +5 -1
- package/dist/guest/runtime/status.js +19 -0
- package/dist/guest/setup/addon-mcp.d.ts +1 -1
- package/dist/guest/setup/addon-mcp.js +52 -12
- package/dist/guest/setup/agent-addons.d.ts +3 -2
- package/dist/guest/setup/agent-addons.js +12 -3
- package/dist/guest/setup/environment.d.ts +1 -1
- package/dist/guest/setup/environment.js +25 -12
- package/dist/guest/setup/headroom.d.ts +8 -3
- package/dist/guest/setup/headroom.js +44 -15
- package/dist/guest/setup/path-plan.d.ts +28 -0
- package/dist/guest/setup/path-plan.js +69 -2
- package/dist/guest/setup/shell-path.d.ts +1 -1
- package/dist/guest/setup/shell-path.js +3 -3
- package/dist/guest/toolchains/fivem/artifacts.d.ts +48 -1
- package/dist/guest/toolchains/fivem/artifacts.js +97 -4
- package/dist/guest/toolchains/fivem/fivem.d.ts +32 -1
- package/dist/guest/toolchains/fivem/fivem.js +168 -3
- package/dist/guest/toolchains/fivem/scaffold.d.ts +35 -0
- package/dist/guest/toolchains/fivem/scaffold.js +105 -0
- package/dist/guest/toolchains/fivem/serve-plan.d.ts +34 -0
- package/dist/guest/toolchains/fivem/serve-plan.js +61 -0
- package/dist/guest/toolchains/languages/go.js +1 -1
- package/dist/guest/toolchains/languages/node.js +2 -1
- package/dist/guest/toolchains/languages/php.d.ts +2 -0
- package/dist/guest/toolchains/languages/php.js +13 -1
- package/dist/guest/toolchains/languages/python-tools.js +1 -1
- package/dist/guest/toolchains/languages/ruby.js +1 -1
- package/dist/guest/toolchains/native/binstall.js +1 -1
- package/dist/guest/toolchains/native/msvc/packages.js +10 -4
- package/dist/guest/toolchains/native/rust.d.ts +2 -0
- package/dist/guest/toolchains/native/rust.js +11 -4
- package/dist/guest/toolchains/native/unreal.d.ts +2 -0
- package/dist/guest/toolchains/native/unreal.js +16 -6
- package/dist/guest/toolchains/native/vcruntime.d.ts +2 -0
- package/dist/guest/toolchains/native/vcruntime.js +10 -2
- package/dist/guest/toolchains/native/visual-studio.d.ts +3 -0
- package/dist/guest/toolchains/native/visual-studio.js +44 -26
- package/dist/guest/toolchains/native/vs-request.d.ts +2 -0
- package/dist/guest/toolchains/native/vs-request.js +2 -0
- package/dist/guest/toolchains/plan.js +19 -8
- package/dist/guest/toolchains/scheduler.d.ts +2 -21
- package/dist/guest/toolchains/scheduler.js +7 -121
- package/dist/guest/toolchains/setup.d.ts +15 -2
- package/dist/guest/toolchains/setup.js +39 -20
- package/dist/guest/toolchains/split.d.ts +28 -0
- package/dist/guest/toolchains/split.js +60 -0
- package/dist/guest/toolchains/steam/client.js +2 -1
- package/dist/guest/toolchains/step-scheduler.d.ts +51 -0
- package/dist/guest/toolchains/step-scheduler.js +147 -0
- package/dist/guest/toolchains/step.d.ts +13 -0
- package/dist/guest/toolchains/tools/git.js +18 -0
- package/dist/guest/vpn/openvpn.js +3 -4
- package/dist/guest/vpn/wireguard.js +11 -4
- package/dist/host/accounts/deliver.js +7 -0
- package/dist/host/accounts/handoff.js +2 -6
- package/dist/host/accounts/index.d.ts +1 -1
- package/dist/host/accounts/index.js +1 -1
- package/dist/host/accounts/kinds/cfx.d.ts +1 -1
- package/dist/host/accounts/kinds/cfx.js +47 -4
- package/dist/host/accounts/kinds/comet.d.ts +2 -0
- package/dist/host/accounts/kinds/comet.js +6 -0
- package/dist/host/accounts/kinds/perplexity.d.ts +2 -0
- package/dist/host/accounts/kinds/perplexity.js +30 -0
- package/dist/host/accounts/leases.d.ts +7 -1
- package/dist/host/accounts/leases.js +13 -2
- package/dist/host/accounts/source.d.ts +7 -1
- package/dist/host/accounts/source.js +27 -0
- package/dist/host/accounts/sources.js +4 -0
- package/dist/host/github/deliver.d.ts +1 -1
- package/dist/host/github/deliver.js +20 -1
- package/dist/host/github/index.d.ts +2 -1
- package/dist/host/github/index.js +1 -0
- package/dist/host/github/token.d.ts +13 -1
- package/dist/host/github/token.js +19 -2
- package/dist/host/github/verify.d.ts +27 -0
- package/dist/host/github/verify.js +61 -0
- package/dist/host/launch/hints/fivem.d.ts +3 -1
- package/dist/host/launch/hints/fivem.js +68 -2
- package/dist/host/launch/session-file.js +4 -0
- package/dist/host/launch/toolchains.d.ts +2 -1
- package/dist/host/launch/toolchains.js +5 -3
- package/dist/host/profile/claude-login.d.ts +2 -2
- package/dist/host/profile/claude-login.js +4 -3
- package/dist/host/vpn/nordvpn.d.ts +2 -4
- package/dist/host/vpn/nordvpn.js +2 -24
- package/dist/runtime/agent.js +405 -90
- package/dist/runtime/daemon.js +3010 -1383
- package/dist/runtime/db.js +333 -90
- package/dist/runtime/main.js +4720 -1954
- package/dist/runtime/netproxy.js +286 -69
- package/dist/runtime/tool.js +2852 -1780
- package/dist/runtime/view.js +286 -69
- package/dist/selftest/accounts.test.js +1 -1
- package/dist/selftest/agent-paths.test.js +39 -1
- package/dist/selftest/agent-settings.test.js +6 -0
- package/dist/selftest/agents-web.test.d.ts +2 -0
- package/dist/selftest/agents-web.test.js +647 -0
- package/dist/selftest/app.test.js +5 -2
- package/dist/selftest/boot-runner.test.d.ts +2 -0
- package/dist/selftest/boot-runner.test.js +456 -0
- package/dist/selftest/channel.test.js +15 -0
- package/dist/selftest/fivem.test.js +249 -3
- package/dist/selftest/github.test.js +94 -9
- package/dist/selftest/guest-boot.test.js +3 -0
- package/dist/selftest/health.test.js +1 -1
- package/dist/selftest/index.js +8 -0
- package/dist/selftest/layout.test.js +5 -0
- package/dist/selftest/menu-coverage.test.d.ts +2 -0
- package/dist/selftest/menu-coverage.test.js +46 -0
- package/dist/selftest/menu-screens.js +37 -1
- package/dist/selftest/persisted-installs.test.js +6 -3
- package/dist/selftest/service-accounts.test.js +3 -2
- package/dist/selftest/support/engine-golden.js +27 -0
- package/dist/selftest/support/fixtures.d.ts +6 -0
- package/dist/selftest/support/web-preview.d.ts +34 -1
- package/dist/selftest/support/web-preview.js +21 -18
- package/dist/selftest/toolchains.test.js +23 -1
- package/dist/selftest/ui-text.test.d.ts +7 -0
- package/dist/selftest/ui-text.test.js +300 -0
- package/dist/shared/accounts/anthropic.d.ts +1 -1
- package/dist/shared/accounts/anthropic.js +9 -8
- package/dist/shared/accounts/index.d.ts +2 -0
- package/dist/shared/accounts/index.js +2 -0
- package/dist/shared/accounts/kinds/comet.d.ts +12 -0
- package/dist/shared/accounts/kinds/comet.js +64 -0
- package/dist/shared/accounts/kinds/perplexity.d.ts +8 -0
- package/dist/shared/accounts/kinds/perplexity.js +37 -0
- package/dist/shared/accounts/kinds.d.ts +24 -5
- package/dist/shared/accounts/kinds.js +86 -4
- package/dist/shared/accounts/payloads.d.ts +81 -0
- package/dist/shared/accounts/payloads.js +39 -1
- package/dist/shared/apps/agent-addons.d.ts +33 -5
- package/dist/shared/apps/agent-addons.js +95 -3
- package/dist/shared/apps/catalogue-agents-web.d.ts +14 -0
- package/dist/shared/apps/catalogue-agents-web.js +112 -0
- package/dist/shared/apps/catalogue-modding.js +32 -1
- package/dist/shared/apps/catalogue.d.ts +27 -3
- package/dist/shared/apps/catalogue.js +2 -1
- package/dist/shared/apps/index.d.ts +3 -1
- package/dist/shared/apps/index.js +3 -1
- package/dist/shared/channel/schema.d.ts +21 -3
- package/dist/shared/channel/schema.js +7 -0
- package/dist/shared/channel/secrets.d.ts +19 -0
- package/dist/shared/concurrency/index.d.ts +3 -0
- package/dist/shared/concurrency/index.js +3 -0
- package/dist/shared/concurrency/installer-retry.d.ts +6 -0
- package/dist/shared/concurrency/installer-retry.js +10 -0
- package/dist/shared/concurrency/limiter.d.ts +19 -0
- package/dist/shared/concurrency/limiter.js +67 -0
- package/dist/shared/concurrency/pools.d.ts +7 -0
- package/dist/shared/concurrency/pools.js +9 -0
- package/dist/shared/download/archive.d.ts +2 -0
- package/dist/shared/download/archive.js +11 -1
- package/dist/shared/download/bounded-fetch.d.ts +13 -0
- package/dist/shared/download/bounded-fetch.js +40 -0
- package/dist/shared/download/downloader.d.ts +5 -0
- package/dist/shared/download/downloader.js +50 -38
- package/dist/shared/download/index.d.ts +2 -1
- package/dist/shared/download/index.js +2 -1
- package/dist/shared/readiness.d.ts +2 -2
- package/dist/shared/readiness.js +2 -2
- package/dist/web/index.html +1 -1
- package/dist/web/{main-OUUQYNK4.js → main-CCILLX2M.js} +67 -67
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/package.json +1 -1
- package/sandbox/addons/browser-use-mcp/requirements.in +1 -0
- package/sandbox/addons/browser-use-mcp/requirements.txt +2350 -0
- package/sandbox/addons/chrome-devtools-mcp/package-lock.json +38 -0
- package/sandbox/addons/chrome-devtools-mcp/package.json +7 -0
- package/sandbox/addons/comet-mcp/package-lock.json +1277 -0
- package/sandbox/addons/comet-mcp/package.json +7 -0
- package/sandbox/addons/perplexity-mcp/package-lock.json +1655 -0
- package/sandbox/addons/perplexity-mcp/package.json +7 -0
- package/sandbox/scripts/add-firewall-port.ps1 +18 -4
- package/sandbox/scripts/set-machine-environment.ps1 +30 -15
- package/sandbox/templates/fivem/README.txt +6 -2
- package/sandbox/templates/fivem/cs/Client/Client.csproj +15 -0
- package/sandbox/templates/fivem/cs/Client/ClientMain.cs +20 -0
- package/sandbox/templates/fivem/cs/Server/Server.csproj +14 -0
- package/sandbox/templates/fivem/cs/Server/ServerMain.cs +20 -0
- package/sandbox/templates/fivem/cs/fxmanifest.lua +11 -0
- package/sandbox/templates/fivem/js/client.js +12 -0
- package/sandbox/templates/fivem/js/fxmanifest.lua +9 -0
- package/sandbox/templates/fivem/js/server.js +6 -0
- package/sandbox/templates/fivem/lua/client.lua +8 -0
- package/sandbox/templates/fivem/lua/fxmanifest.lua +10 -0
- package/sandbox/templates/fivem/lua/server.lua +6 -0
- package/sandbox/templates/fivem/server.cfg +37 -0
- package/sandbox/templates/fivem/ts/build.js +17 -0
- package/sandbox/templates/fivem/ts/fxmanifest.lua +9 -0
- package/sandbox/templates/fivem/ts/package.json +16 -0
- package/sandbox/templates/fivem/ts/src/client/client.ts +12 -0
- package/sandbox/templates/fivem/ts/src/client/tsconfig.json +13 -0
- package/sandbox/templates/fivem/ts/src/server/server.ts +6 -0
- package/sandbox/templates/fivem/ts/src/server/tsconfig.json +13 -0
- package/schemas/config.schema.json +56 -27
- package/schemas/sandbox-config.schema.json +37 -14
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// What the menu and the web say never tells the user to type a command ("we don't develop a menu to tell people to run
|
|
2
|
+
// commands"): every page of every view, built from sample data, is read for command lines, banned words and command
|
|
3
|
+
// links, and so is every message an operation can fail with (the *.run.ts sources). Text for the command line only
|
|
4
|
+
// is marked (`only: 'cli'` notes, `Empty.cliText`, `next`) and is not read. An exemption names the text and the reason.
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { sandboxPage } from '../app/features/sandbox/index.js';
|
|
8
|
+
import { sessionsPage } from '../app/features/sessions/index.js';
|
|
9
|
+
import { agentsPage } from '../app/features/agents/index.js';
|
|
10
|
+
import { accountsPage, servicePage } from '../app/features/accounts/index.js';
|
|
11
|
+
import { projectsPage } from '../app/features/projects/index.js';
|
|
12
|
+
import { healthPage } from '../app/features/health/index.js';
|
|
13
|
+
import { dataPage } from '../app/features/data/index.js';
|
|
14
|
+
import { storagePage } from '../app/features/storage/index.js';
|
|
15
|
+
import { logsPage } from '../app/features/logs/index.js';
|
|
16
|
+
import { auditPage, auditListing, listAudit } from '../app/features/audit/index.js';
|
|
17
|
+
import { updatesPage } from '../app/features/updates/index.js';
|
|
18
|
+
import { enginePage } from '../app/features/engine/index.js';
|
|
19
|
+
import { webPage } from '../app/features/web/index.js';
|
|
20
|
+
import { vpnPage } from '../app/features/vpn/index.js';
|
|
21
|
+
import { githubPage } from '../app/features/github/index.js';
|
|
22
|
+
import { accessPage } from '../app/features/access/index.js';
|
|
23
|
+
import { appsPage, listApps } from '../app/features/apps/index.js';
|
|
24
|
+
import { settingsPage } from '../app/features/settings/index.js';
|
|
25
|
+
import { QUERIES } from '../app/features/defs.js';
|
|
26
|
+
import { pageActions } from '../app/kernel/index.js';
|
|
27
|
+
import { readQuery } from '../app/registry.js';
|
|
28
|
+
import { COMMANDS } from '../cli/manifest.js';
|
|
29
|
+
import { renderScreens } from './menu-screens.js';
|
|
30
|
+
import { sampleAccess, sampleAccounts, sampleAgents, sampleAuditLog, sampleContained, sampleData, sampleEngines, sampleHealth, sampleLogs, sampleLogTail, sampleProjects, sampleSessions, sampleStatus, sampleStorage, sampleUpdates, } from './support/web-preview.js';
|
|
31
|
+
/**
|
|
32
|
+
* Words the menu and the web never show (the glossary fills this in during the wording pass). "(Beta)" is on the
|
|
33
|
+
* list from the plan but waits for round 3: it is in about twenty setting titles that wording pass renames at once.
|
|
34
|
+
*/
|
|
35
|
+
const BANNED = [/\bnot available yet\b/i];
|
|
36
|
+
/** Text that is allowed to name a command: where, which text, and why. Keep this list short. */
|
|
37
|
+
const EXEMPT = [];
|
|
38
|
+
/** Every visible string of a page: what a person reads in the menu or the web (CLI-only text is left out). */
|
|
39
|
+
export function visibleText(page) {
|
|
40
|
+
const out = [page.title];
|
|
41
|
+
const add = (...texts) => {
|
|
42
|
+
for (const t of texts)
|
|
43
|
+
if (t)
|
|
44
|
+
out.push(t);
|
|
45
|
+
};
|
|
46
|
+
const act = (a) => add(a.label, a.verb, a.description);
|
|
47
|
+
if (page.notice && page.notice.only !== 'cli')
|
|
48
|
+
add(page.notice.text);
|
|
49
|
+
if (page.empty) {
|
|
50
|
+
add(page.empty.title, page.empty.text);
|
|
51
|
+
if (page.empty.action)
|
|
52
|
+
act(page.empty.action);
|
|
53
|
+
}
|
|
54
|
+
for (const a of page.actions ?? [])
|
|
55
|
+
act(a);
|
|
56
|
+
for (const s of page.sections) {
|
|
57
|
+
add(s.title, s.summary, s.description, ...(s.text ?? []));
|
|
58
|
+
for (const f of s.facts ?? [])
|
|
59
|
+
add(f.label, f.value, f.description, ...(f.details ?? []));
|
|
60
|
+
for (const n of s.notes ?? [])
|
|
61
|
+
if (n.only !== 'cli')
|
|
62
|
+
add(n.text);
|
|
63
|
+
for (const a of s.actions ?? [])
|
|
64
|
+
act(a);
|
|
65
|
+
for (const i of s.items ?? []) {
|
|
66
|
+
add(i.label, i.hint, i.description, i.keys, i.disabled, i.group, ...(i.details ?? []), ...(i.badges ?? []).map((b) => b.text));
|
|
67
|
+
for (const a of [...(i.primary ? [i.primary] : []), ...(i.actions ?? [])])
|
|
68
|
+
act(a);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/** The commands a person could be told to type: `sandbox <name>` for every command, and the internal `_web`. */
|
|
74
|
+
function commandPattern() {
|
|
75
|
+
const names = new Set(COMMANDS.map((c) => c.name));
|
|
76
|
+
const words = [...names].filter((n) => /^[a-z_][a-z0-9-]*$/.test(n)).map((n) => n.replace(/-/g, '\\-'));
|
|
77
|
+
return new RegExp('\\bsandbox (?:' + words.join('|') + ')\\b');
|
|
78
|
+
}
|
|
79
|
+
/** What is wrong with a text, or undefined. */
|
|
80
|
+
export function textProblem(text, where, command = commandPattern()) {
|
|
81
|
+
if (EXEMPT.some((e) => e.where === where && text.includes(e.text)))
|
|
82
|
+
return undefined;
|
|
83
|
+
const hit = command.exec(text);
|
|
84
|
+
if (hit)
|
|
85
|
+
return 'names a command (' + hit[0] + ')';
|
|
86
|
+
const banned = BANNED.find((b) => b.test(text));
|
|
87
|
+
if (banned)
|
|
88
|
+
return 'uses ' + banned;
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
function serviceRow(over) {
|
|
92
|
+
return {
|
|
93
|
+
kind: 'steam',
|
|
94
|
+
label: 'Steam',
|
|
95
|
+
share: false,
|
|
96
|
+
state: 'none',
|
|
97
|
+
source: null,
|
|
98
|
+
savedAt: null,
|
|
99
|
+
summary: null,
|
|
100
|
+
heldBy: null,
|
|
101
|
+
usedBy: ['fivem'],
|
|
102
|
+
usedFor: 'fivem',
|
|
103
|
+
warnings: ['Steam allows one sign-in at a time.'],
|
|
104
|
+
canImport: true,
|
|
105
|
+
canLogin: true,
|
|
106
|
+
needsFile: false,
|
|
107
|
+
ready: true,
|
|
108
|
+
...over,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Every page the shared core builds, in the states that print the most text. */
|
|
112
|
+
async function samplePages(dir) {
|
|
113
|
+
const configPath = path.join(dir, 'config.json');
|
|
114
|
+
fs.writeFileSync(configPath, '{}\n');
|
|
115
|
+
fs.mkdirSync(path.join(dir, 'project'), { recursive: true });
|
|
116
|
+
const ctx = {
|
|
117
|
+
loaded: { configPath },
|
|
118
|
+
options: { workspace: path.join(dir, 'project') },
|
|
119
|
+
storageRoot: path.join(dir, 'storage'),
|
|
120
|
+
dataPath: path.join(dir, 'data'),
|
|
121
|
+
};
|
|
122
|
+
const query = (id) => QUERIES.find((q) => q.id === id);
|
|
123
|
+
const settings = await readQuery(query('settings.list'), ctx, { scope: 'user' });
|
|
124
|
+
const apps = (await readQuery(listApps, ctx, { scope: 'user' }));
|
|
125
|
+
const audit = sampleAuditLog(path.join(dir, 'audit'));
|
|
126
|
+
const listing = (enabled) => auditListing(audit, { enabled, days: 7, maxMb: 100 }, listAudit.input.parse({}), path.join(dir, 'audit'));
|
|
127
|
+
const services = (state, share) => ({
|
|
128
|
+
services: [
|
|
129
|
+
serviceRow({ state, share, source: state === 'saved' ? 'pc' : null, summary: state === 'saved' ? 'josh' : null }),
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
const health = sampleHealth();
|
|
133
|
+
const accounts = sampleAccounts();
|
|
134
|
+
const vpn = (login, enabled) => ({
|
|
135
|
+
enabled,
|
|
136
|
+
provider: 'nordvpn',
|
|
137
|
+
protocol: 'udp',
|
|
138
|
+
country: 'Netherlands',
|
|
139
|
+
killSwitch: true,
|
|
140
|
+
login,
|
|
141
|
+
loginSavedAt: login === 'saved' ? '2026-10-14T09:30:00.000Z' : null,
|
|
142
|
+
running: null,
|
|
143
|
+
lastFailure: null,
|
|
144
|
+
});
|
|
145
|
+
const github = (token, shareToken) => ({
|
|
146
|
+
shareToken,
|
|
147
|
+
gitAccess: 'full',
|
|
148
|
+
token,
|
|
149
|
+
kind: token === 'saved' ? 'fine-grained' : null,
|
|
150
|
+
savedAt: token === 'saved' ? '2026-10-14T09:30:00.000Z' : null,
|
|
151
|
+
});
|
|
152
|
+
const pages = [];
|
|
153
|
+
const add = (name, page) => pages.push({ name, page });
|
|
154
|
+
for (const running of [true, false]) {
|
|
155
|
+
add('sandbox ' + running, sandboxPage(sampleStatus(running)));
|
|
156
|
+
add('sessions ' + running, sessionsPage(sampleSessions(running)));
|
|
157
|
+
add('projects ' + running, projectsPage(sampleProjects(running)));
|
|
158
|
+
}
|
|
159
|
+
add('projects empty', projectsPage({ all: false, roots: [], exclude: [], projects: [] }));
|
|
160
|
+
const status = sampleStatus(false);
|
|
161
|
+
add('sandbox leftover', sandboxPage({ ...status, leftover: { text: 'Windows Sandbox programs are left over.' } }));
|
|
162
|
+
add('sandbox ended', sandboxPage({ ...status, lastEnd: { text: 'It ended without being closed.', at: '2026-11-01T10:00:00.000Z' } }));
|
|
163
|
+
add('sandbox no account', sandboxPage({
|
|
164
|
+
...sampleStatus(true),
|
|
165
|
+
sandbox: { ...status.sandbox, running: true, account: null, headless: true },
|
|
166
|
+
}));
|
|
167
|
+
add('agents', agentsPage(sampleAgents(), { enabled: false, dir: 'C:/x', found: [] }));
|
|
168
|
+
add('accounts', accountsPage(accounts, services('saved', true), github('saved', true)));
|
|
169
|
+
add('accounts none', accountsPage({ ...accounts, agents: accounts.agents.map((a) => ({ ...a, accounts: [] })) }, services('none', false)));
|
|
170
|
+
for (const state of ['none', 'saved', 'unreadable'])
|
|
171
|
+
for (const share of [false, true])
|
|
172
|
+
add('service ' + state + share, servicePage(services(state, share).services[0]));
|
|
173
|
+
add('health', healthPage(health));
|
|
174
|
+
add('health none', healthPage({ last: null }));
|
|
175
|
+
add('data', dataPage(sampleData()));
|
|
176
|
+
add('storage', storagePage(sampleStorage(), sampleContained()));
|
|
177
|
+
add('storage unavailable', storagePage(sampleStorage(), {
|
|
178
|
+
...sampleContained(),
|
|
179
|
+
available: false,
|
|
180
|
+
reasons: ['No.'],
|
|
181
|
+
fixes: ['Do this.'],
|
|
182
|
+
}));
|
|
183
|
+
const logs = sampleLogs();
|
|
184
|
+
add('logs', logsPage(logs, sampleLogTail({})));
|
|
185
|
+
add('logs none', logsPage({ ...logs, files: [], crash: false }));
|
|
186
|
+
add('audit', auditPage(listing(true)));
|
|
187
|
+
add('audit off', auditPage(listing(false)));
|
|
188
|
+
const updates = sampleUpdates();
|
|
189
|
+
add('updates', updatesPage(updates, '1.5.0'));
|
|
190
|
+
add('updates current', updatesPage({ ...updates, failed: null, previous: null, autoUpdate: false }, null));
|
|
191
|
+
add('updates unmanaged', updatesPage({ ...updates, managed: false }, null));
|
|
192
|
+
add('engine', enginePage(sampleEngines()));
|
|
193
|
+
add('web off', webPage({ running: false, port: null, address: null }));
|
|
194
|
+
add('web on', webPage({ running: true, port: 47800, address: 'http://127.0.0.1:47800/' }));
|
|
195
|
+
add('web lan problem', webPage({ running: true, port: 47800, address: 'http://127.0.0.1:47800/', lanProblem: 'No network.' }));
|
|
196
|
+
add('access', accessPage(sampleAccess()));
|
|
197
|
+
add('access off', accessPage({
|
|
198
|
+
...sampleAccess(),
|
|
199
|
+
lan: { enabled: false, running: false, address: null, fingerprint: null, problem: null, network: null },
|
|
200
|
+
devices: [],
|
|
201
|
+
windows: [],
|
|
202
|
+
users: [],
|
|
203
|
+
pending: null,
|
|
204
|
+
}));
|
|
205
|
+
for (const login of ['none', 'saved', 'unreadable'])
|
|
206
|
+
add('vpn ' + login, vpnPage(vpn(login, login === 'saved')));
|
|
207
|
+
for (const token of ['none', 'saved', 'unreadable'])
|
|
208
|
+
for (const share of [false, true])
|
|
209
|
+
add('github ' + token + share, githubPage(github(token, share)));
|
|
210
|
+
add('settings', settingsPage(settings));
|
|
211
|
+
add('apps', appsPage(apps));
|
|
212
|
+
return pages;
|
|
213
|
+
}
|
|
214
|
+
/** Message and fix strings of the operations: lines of *.run.ts files that quote a command. */
|
|
215
|
+
function runSourceLines(root) {
|
|
216
|
+
const found = [];
|
|
217
|
+
const walk = (dir) => {
|
|
218
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
219
|
+
const full = path.join(dir, entry.name);
|
|
220
|
+
if (entry.isDirectory())
|
|
221
|
+
walk(full);
|
|
222
|
+
else if (entry.name.endsWith('.run.ts')) {
|
|
223
|
+
fs.readFileSync(full, 'utf8')
|
|
224
|
+
.split(/\r?\n/)
|
|
225
|
+
.forEach((text, i) => {
|
|
226
|
+
if (!/^\s*(\/\/|\*|\/\*)/.test(text))
|
|
227
|
+
found.push({ where: path.relative(root, full).replace(/\\/g, '/'), line: i + 1, text });
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
walk(root);
|
|
233
|
+
return found;
|
|
234
|
+
}
|
|
235
|
+
/** Lines of the run files that may name a command, because only the command line shows them. */
|
|
236
|
+
const CLI_ONLY_LINES = [
|
|
237
|
+
{
|
|
238
|
+
where: '*',
|
|
239
|
+
text: 'cli:',
|
|
240
|
+
why: 'the command line of an ErrorAction: only the CLI prints it (never sent to the menu or the web)',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
where: 'data/data.run.ts',
|
|
244
|
+
text: 'storageShare',
|
|
245
|
+
why: '"sandbox storage" is the name of the storage drive note, not a command',
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
where: 'data/data.run.ts',
|
|
249
|
+
text: 'Name them:',
|
|
250
|
+
why: 'noTerminal fix: shown only when there is no terminal (the command line)',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
where: 'health/health.run.ts',
|
|
254
|
+
text: "command: 'sandbox repair'",
|
|
255
|
+
why: 'the repair log records the command that ran',
|
|
256
|
+
},
|
|
257
|
+
{ where: 'projects/projects.run.ts', text: 'next:', why: '`next` is printed by the command line only' },
|
|
258
|
+
{ where: 'sandbox/sandbox.run.ts', text: 'Stop it anyway with:', why: 'noTerminal fix: command line only' },
|
|
259
|
+
{
|
|
260
|
+
where: 'storage/storage.run.ts',
|
|
261
|
+
text: "const fix = 'Use: sandbox storage",
|
|
262
|
+
why: 'noTerminal fix: command line only',
|
|
263
|
+
},
|
|
264
|
+
];
|
|
265
|
+
export const uiTextSuite = {
|
|
266
|
+
name: 'ui-text',
|
|
267
|
+
title: 'menu and web text: no page, message or fix tells the user to run a command',
|
|
268
|
+
run: async (t) => {
|
|
269
|
+
const command = commandPattern();
|
|
270
|
+
t.section('pages');
|
|
271
|
+
const dir = t.dir('ui-text', 'pages');
|
|
272
|
+
const pages = await samplePages(dir);
|
|
273
|
+
const problems = pages.flatMap(({ name, page }) => visibleText(page).flatMap((text) => {
|
|
274
|
+
const why = textProblem(text, name, command);
|
|
275
|
+
return why ? [name + ': "' + text.slice(0, 140) + '" ' + why] : [];
|
|
276
|
+
}));
|
|
277
|
+
if (process.env.UI_TEXT_DUMP)
|
|
278
|
+
fs.writeFileSync(process.env.UI_TEXT_DUMP, problems.join('\n'));
|
|
279
|
+
t.equal(problems, [], 'no page of any view names a command or uses a banned word');
|
|
280
|
+
const commandLinks = pages.flatMap(({ name, page }) => pageActions(page).flatMap((a) => (a.kind === 'link' && a.target.kind === 'command' ? [name] : [])));
|
|
281
|
+
t.equal(commandLinks, [], 'no page links to a command line');
|
|
282
|
+
t.section('messages');
|
|
283
|
+
const lines = runSourceLines(path.join(process.cwd(), 'src', 'app', 'features'));
|
|
284
|
+
const loose = lines
|
|
285
|
+
.filter((l) => command.test(l.text) &&
|
|
286
|
+
!CLI_ONLY_LINES.some((e) => (e.where === '*' || e.where === l.where) && l.text.includes(e.text)))
|
|
287
|
+
.map((l) => l.where + ':' + l.line + ' ' + l.text.trim().slice(0, 140));
|
|
288
|
+
t.equal(loose, [], 'no operation message or fix names a command (use failWith, an action or a CLI-only field)');
|
|
289
|
+
t.section('menu screens');
|
|
290
|
+
const screens = renderScreens(t.dir('ui-text', 'screens'));
|
|
291
|
+
const screenProblems = screens
|
|
292
|
+
.split('\n')
|
|
293
|
+
.filter((l) => !l.startsWith('==='))
|
|
294
|
+
.flatMap((l) => {
|
|
295
|
+
const why = textProblem(l, 'menu', command);
|
|
296
|
+
return why ? [l.trim().slice(0, 140) + ' ' + why] : [];
|
|
297
|
+
});
|
|
298
|
+
t.equal(screenProblems, [], 'no menu screen names a command');
|
|
299
|
+
},
|
|
300
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const ANTHROPIC_KEY_PATTERN: RegExp;
|
|
2
|
-
/** The only part of a key ever shown: sk-ant
|
|
2
|
+
/** The only part of a key ever shown: its own prefix (sk-ant-, skt-ant-), then ..., then its last 4 characters. */
|
|
3
3
|
export declare const ANTHROPIC_KEY_HINT: RegExp;
|
|
4
4
|
/** What is wrong with a typed or found API key, or null when it has the right shape. Never quotes the key. */
|
|
5
5
|
export declare function anthropicKeyProblem(key: string): string | null;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
// The
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// The shape of an Anthropic API key, for the host and the web (no node imports). Any key from the Claude Console is
|
|
2
|
+
// accepted, whatever its prefix (sk-ant-api03-..., skt-ant-usr-... and others): only text with spaces or other odd
|
|
3
|
+
// characters, or under 20 characters, is refused. Subscription tokens and Admin keys are refused by name.
|
|
4
|
+
export const ANTHROPIC_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]{19,511}$/;
|
|
5
|
+
/** The only part of a key ever shown: its own prefix (sk-ant-, skt-ant-), then ..., then its last 4 characters. */
|
|
6
|
+
export const ANTHROPIC_KEY_HINT = /^([A-Za-z0-9]{1,8}-?[A-Za-z]*-?)?\.\.\.[A-Za-z0-9_.-]{4}$/;
|
|
6
7
|
/** What is wrong with a typed or found API key, or null when it has the right shape. Never quotes the key. */
|
|
7
8
|
export function anthropicKeyProblem(key) {
|
|
8
|
-
if (ANTHROPIC_KEY_PATTERN.test(key))
|
|
9
|
-
return null;
|
|
10
9
|
if (key.startsWith('sk-ant-oat'))
|
|
11
10
|
return 'That is a Claude subscription token (from claude setup-token), not an API key. Save the subscription login instead.';
|
|
12
11
|
if (key.startsWith('sk-ant-admin'))
|
|
13
12
|
return 'That is an Admin key: it cannot run Claude. Make an API key instead.';
|
|
14
|
-
|
|
13
|
+
if (ANTHROPIC_KEY_PATTERN.test(key))
|
|
14
|
+
return null;
|
|
15
|
+
return 'That does not look like an API key: paste the whole key (letters, digits, - and _, no spaces).';
|
|
15
16
|
}
|
|
@@ -3,4 +3,6 @@ export * from './payloads.js';
|
|
|
3
3
|
export { fingerprint } from './fingerprint.js';
|
|
4
4
|
export { epicSettingsFile, MAX_EPIC_INI_BYTES, readEpicLogin, withEpicLogin, type EpicPayload } from './kinds/epic.js';
|
|
5
5
|
export * from './kinds/steam.js';
|
|
6
|
+
export { PERPLEXITY_ENV, perplexityKeyFromText, perplexitySummary, type PerplexityPayload, } from './kinds/perplexity.js';
|
|
7
|
+
export { cometPayloadFromCookies, cometSummary, cookiesToRestore, type CometPayload } from './kinds/comet.js';
|
|
6
8
|
export * from './anthropic.js';
|
|
@@ -5,4 +5,6 @@ export * from './payloads.js';
|
|
|
5
5
|
export { fingerprint } from './fingerprint.js';
|
|
6
6
|
export { epicSettingsFile, MAX_EPIC_INI_BYTES, readEpicLogin, withEpicLogin } from './kinds/epic.js';
|
|
7
7
|
export * from './kinds/steam.js';
|
|
8
|
+
export { PERPLEXITY_ENV, perplexityKeyFromText, perplexitySummary, } from './kinds/perplexity.js';
|
|
9
|
+
export { cometPayloadFromCookies, cometSummary, cookiesToRestore } from './kinds/comet.js';
|
|
8
10
|
export * from './anthropic.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CometCookie, Payload } from '../payloads.js';
|
|
2
|
+
export type CometPayload = Payload<'comet'>;
|
|
3
|
+
/**
|
|
4
|
+
* The sign-in among the cookies Comet reports (every site's, as Storage.getCookies returns them): the allow-listed,
|
|
5
|
+
* persistent HttpOnly ones, in a fixed order so the same sign-in always looks the same. Null when there is none (signed
|
|
6
|
+
* out), or when there are more than a sign-in could need.
|
|
7
|
+
*/
|
|
8
|
+
export declare function cometPayloadFromCookies(cookies: readonly unknown[], nowSeconds: number): CometPayload | null;
|
|
9
|
+
/** The cookies still valid now, for Storage.setCookies (an expired one would only be thrown away by Comet). */
|
|
10
|
+
export declare function cookiesToRestore(p: CometPayload, nowSeconds: number): CometCookie[];
|
|
11
|
+
/** One line for the status: how many cookies, never their values. */
|
|
12
|
+
export declare function cometSummary(p: CometPayload): string;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Comet's sign-in, as the sandbox keeps it: only the perplexity.ai cookies that hold a sign-in (persistent, HttpOnly),
|
|
2
|
+
// read from Comet over the DevTools protocol (Storage.getCookies) and written back the same way. Pure: the sandbox
|
|
3
|
+
// side (guest/accounts/kinds/comet.ts) talks to Comet, the self-test checks the filter. Never passwords, other sites,
|
|
4
|
+
// localStorage or history: those are not cookies of an allowed domain, and nothing else is asked for.
|
|
5
|
+
import { cometCookieDomainAllowed, CometPayloadSchema, MAX_COMET_COOKIES } from '../payloads.js';
|
|
6
|
+
/** Cloudflare's bot and clearance cookies: tied to one machine and address, and renewed every few minutes. */
|
|
7
|
+
const MACHINE_BOUND = /^(__cf_bm|cf_clearance|_cfuvid|__cflb)$/i;
|
|
8
|
+
/** Expiry is kept to the hour, so a cookie re-sent with a later expiry on every page is not a new sign-in. */
|
|
9
|
+
const EXPIRY_STEP = 3600;
|
|
10
|
+
const SAME_SITE = ['Strict', 'Lax', 'None'];
|
|
11
|
+
/** One CDP cookie as a kept cookie, or null when it is not one to keep. */
|
|
12
|
+
function keptCookie(raw, nowSeconds) {
|
|
13
|
+
if (typeof raw !== 'object' || raw === null)
|
|
14
|
+
return null;
|
|
15
|
+
const c = raw;
|
|
16
|
+
if (typeof c.name !== 'string' || typeof c.value !== 'string' || typeof c.domain !== 'string')
|
|
17
|
+
return null;
|
|
18
|
+
if (!cometCookieDomainAllowed(c.domain) || MACHINE_BOUND.test(c.name))
|
|
19
|
+
return null;
|
|
20
|
+
// A sign-in is a persistent HttpOnly cookie of the site itself: no session cookies, script cookies or partitions.
|
|
21
|
+
if (c.httpOnly !== true || c.session === true || c.partitionKey !== undefined)
|
|
22
|
+
return null;
|
|
23
|
+
if (typeof c.expires !== 'number' || !Number.isFinite(c.expires) || c.expires <= nowSeconds)
|
|
24
|
+
return null;
|
|
25
|
+
const cookie = {
|
|
26
|
+
name: c.name,
|
|
27
|
+
value: c.value,
|
|
28
|
+
domain: c.domain,
|
|
29
|
+
path: typeof c.path === 'string' && c.path ? c.path : '/',
|
|
30
|
+
expires: Math.floor(c.expires / EXPIRY_STEP) * EXPIRY_STEP,
|
|
31
|
+
secure: c.secure === true,
|
|
32
|
+
httpOnly: true,
|
|
33
|
+
...(typeof c.sameSite === 'string' && SAME_SITE.includes(c.sameSite)
|
|
34
|
+
? { sameSite: c.sameSite }
|
|
35
|
+
: {}),
|
|
36
|
+
};
|
|
37
|
+
const parsed = CometPayloadSchema.shape.cookies.element.safeParse(cookie);
|
|
38
|
+
return parsed.success ? parsed.data : null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The sign-in among the cookies Comet reports (every site's, as Storage.getCookies returns them): the allow-listed,
|
|
42
|
+
* persistent HttpOnly ones, in a fixed order so the same sign-in always looks the same. Null when there is none (signed
|
|
43
|
+
* out), or when there are more than a sign-in could need.
|
|
44
|
+
*/
|
|
45
|
+
export function cometPayloadFromCookies(cookies, nowSeconds) {
|
|
46
|
+
const kept = cookies.flatMap((c) => {
|
|
47
|
+
const k = keptCookie(c, nowSeconds);
|
|
48
|
+
return k ? [k] : [];
|
|
49
|
+
});
|
|
50
|
+
if (!kept.length || kept.length > MAX_COMET_COOKIES)
|
|
51
|
+
return null;
|
|
52
|
+
kept.sort((a, b) => (a.domain + ' ' + a.path + ' ' + a.name < b.domain + ' ' + b.path + ' ' + b.name ? -1 : 1));
|
|
53
|
+
const parsed = CometPayloadSchema.safeParse({ cookies: kept });
|
|
54
|
+
return parsed.success ? parsed.data : null;
|
|
55
|
+
}
|
|
56
|
+
/** The cookies still valid now, for Storage.setCookies (an expired one would only be thrown away by Comet). */
|
|
57
|
+
export function cookiesToRestore(p, nowSeconds) {
|
|
58
|
+
return CometPayloadSchema.parse(p).cookies.filter((c) => c.expires === undefined || c.expires > nowSeconds);
|
|
59
|
+
}
|
|
60
|
+
/** One line for the status: how many cookies, never their values. */
|
|
61
|
+
export function cometSummary(p) {
|
|
62
|
+
const n = p.cookies.length;
|
|
63
|
+
return n + ' perplexity.ai sign-in cookie' + (n === 1 ? '' : 's');
|
|
64
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Payload } from '../payloads.js';
|
|
2
|
+
export type PerplexityPayload = Payload<'perplexity'>;
|
|
3
|
+
/** The variable the agent's sessions get, and the one the MCP servers read. */
|
|
4
|
+
export declare const PERPLEXITY_ENV = "PERPLEXITY_API_KEY";
|
|
5
|
+
/** The key in a file's text: its PERPLEXITY_API_KEY line (the last one wins, as in .env files), or the key alone. */
|
|
6
|
+
export declare function perplexityKeyFromText(text: string): PerplexityPayload | null;
|
|
7
|
+
/** pplx-... and the key's last 4 characters, for the status; never the key. */
|
|
8
|
+
export declare function perplexitySummary(p: PerplexityPayload): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// A Perplexity API key: typed, or taken from a file that holds it (a .env line PERPLEXITY_API_KEY=..., or the key
|
|
2
|
+
// alone). Pure text handling: only that one line is read, every other line of a .env file is ignored and never kept.
|
|
3
|
+
import { PerplexityPayloadSchema } from '../payloads.js';
|
|
4
|
+
/** The variable the agent's sessions get, and the one the MCP servers read. */
|
|
5
|
+
export const PERPLEXITY_ENV = 'PERPLEXITY_API_KEY';
|
|
6
|
+
const ENV_LINE = /^\s*(?:export\s+)?PERPLEXITY_API_KEY\s*=\s*(.*)$/;
|
|
7
|
+
/** More lines than a file within the import bound (64 KB) can have. */
|
|
8
|
+
const MAX_LINES = 100_000;
|
|
9
|
+
/** A value as written in a .env line: quotes taken off, a trailing comment dropped. */
|
|
10
|
+
function unquote(raw) {
|
|
11
|
+
const v = raw.trim();
|
|
12
|
+
const quoted = /^(["'])(.*)\1$/.exec(v);
|
|
13
|
+
if (quoted)
|
|
14
|
+
return quoted[2];
|
|
15
|
+
return v.replace(/\s+#.*$/, '').trim();
|
|
16
|
+
}
|
|
17
|
+
/** The key in a file's text: its PERPLEXITY_API_KEY line (the last one wins, as in .env files), or the key alone. */
|
|
18
|
+
export function perplexityKeyFromText(text) {
|
|
19
|
+
const lines = text.replace(/^\uFEFF/, '').split(/\r?\n/, MAX_LINES);
|
|
20
|
+
let value = null;
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
const m = ENV_LINE.exec(line);
|
|
23
|
+
if (m)
|
|
24
|
+
value = unquote(m[1]);
|
|
25
|
+
}
|
|
26
|
+
if (value === null) {
|
|
27
|
+
const words = lines.map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
|
|
28
|
+
if (words.length === 1)
|
|
29
|
+
value = words[0];
|
|
30
|
+
}
|
|
31
|
+
const parsed = value === null ? null : PerplexityPayloadSchema.safeParse({ apiKey: value });
|
|
32
|
+
return parsed?.success ? parsed.data : null;
|
|
33
|
+
}
|
|
34
|
+
/** pplx-... and the key's last 4 characters, for the status; never the key. */
|
|
35
|
+
export function perplexitySummary(p) {
|
|
36
|
+
return 'pplx-...' + p.apiKey.slice(-4);
|
|
37
|
+
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
export declare const SERVICE_KINDS: readonly ["epic", "steam", "unity", "cfx", "keystore", "play", "expo", "appstore"];
|
|
1
|
+
export declare const SERVICE_KINDS: readonly ["epic", "steam", "unity", "cfx", "keystore", "play", "expo", "appstore", "perplexity", "comet"];
|
|
2
2
|
export type ServiceKind = (typeof SERVICE_KINDS)[number];
|
|
3
|
-
/** The toolchains a sign-in
|
|
4
|
-
export type
|
|
5
|
-
|
|
3
|
+
/** The toolchains a sign-in can serve (each is a key of `toolchains`). */
|
|
4
|
+
export type ToolchainUser = 'unreal' | 'steam' | 'unity' | 'fivem' | 'android' | 'flutter' | 'reactNative' | 'godot' | 'dotnet';
|
|
5
|
+
/** The apps a sign-in can serve: on when one of APP_USERS' apps is in apps.install. */
|
|
6
|
+
export type AppUser = 'perplexity' | 'comet';
|
|
7
|
+
/** What a sign-in serves (it is handed over only when one of them is on for the boot). */
|
|
8
|
+
export type UsedBy = ToolchainUser | AppUser;
|
|
9
|
+
/** The toolchains a sign-in can serve. */
|
|
10
|
+
export declare const USED_BY: readonly ToolchainUser[];
|
|
11
|
+
/** The apps (apps.install ids) that turn each app user on. */
|
|
12
|
+
export declare const APP_USERS: {
|
|
13
|
+
readonly [U in AppUser]: readonly string[];
|
|
14
|
+
};
|
|
6
15
|
/** Where a saved sign-in came from: this PC's program, a file you gave, values you typed, or a sandbox. */
|
|
7
16
|
export type AccountSource = 'pc' | 'file' | 'typed' | 'sandbox';
|
|
8
17
|
export declare const ACCOUNT_SOURCES: readonly AccountSource[];
|
|
@@ -13,6 +22,8 @@ export interface ServiceField {
|
|
|
13
22
|
readonly secret: boolean;
|
|
14
23
|
readonly optional?: boolean;
|
|
15
24
|
readonly pattern?: RegExp;
|
|
25
|
+
/** Asked only by `login` (typed) or only by `import --from` (file); both when not set. */
|
|
26
|
+
readonly only?: 'typed' | 'file';
|
|
16
27
|
}
|
|
17
28
|
export interface ServiceSpec<K extends ServiceKind = ServiceKind> {
|
|
18
29
|
readonly kind: K;
|
|
@@ -26,16 +37,24 @@ export interface ServiceSpec<K extends ServiceKind = ServiceKind> {
|
|
|
26
37
|
readonly returns: boolean;
|
|
27
38
|
/** The largest payload (its JSON) accepted from a file or a sandbox. */
|
|
28
39
|
readonly maxBytes: number;
|
|
40
|
+
/** The largest file `import --from` reads, when it holds more than the payload (a .env file); default maxBytes. */
|
|
41
|
+
readonly maxFileBytes?: number;
|
|
29
42
|
/** Shown on every surface. */
|
|
30
43
|
readonly warnings: readonly string[];
|
|
31
44
|
/** What `login` asks for, or what `import --from` needs besides the file. */
|
|
32
45
|
readonly fields: readonly ServiceField[];
|
|
33
46
|
}
|
|
47
|
+
/** A Perplexity API key: pplx- and its body. */
|
|
48
|
+
export declare const PERPLEXITY_KEY_PATTERN: RegExp;
|
|
34
49
|
export declare const SERVICE_SPECS: {
|
|
35
50
|
readonly [K in ServiceKind]: ServiceSpec<K>;
|
|
36
51
|
};
|
|
37
52
|
/** Where a sandbox leaves a renewed sign-in, under the data folder: state\accounts\<kind>.json. */
|
|
38
53
|
export declare const HANDOFF_PARTS: readonly ["state", "accounts"];
|
|
39
54
|
export declare function isServiceKind(value: string): value is ServiceKind;
|
|
40
|
-
/**
|
|
55
|
+
/** What a sign-in serves, for a sentence: "unreal", "reactNative or flutter", "the Comet app". */
|
|
56
|
+
export declare function usedByText(usedBy: readonly string[]): string;
|
|
57
|
+
/** The app users that the chosen apps (apps.install) turn on. */
|
|
58
|
+
export declare function appUsersOn(install: readonly string[]): AppUser[];
|
|
59
|
+
/** Whether a sign-in is wanted when these toolchains (and apps) are on. */
|
|
41
60
|
export declare function serviceWanted(kind: ServiceKind, on: ReadonlySet<UsedBy>): boolean;
|