@fased/fased 0.1.59 → 0.1.61
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/CHANGELOG.md +11 -0
- package/LICENSE +0 -0
- package/assets/avatar-placeholder.svg +0 -0
- package/assets/chrome-extension/README.md +0 -0
- package/assets/chrome-extension/background-utils.js +0 -0
- package/assets/chrome-extension/background.js +0 -0
- package/assets/chrome-extension/icons/icon128.png +0 -0
- package/assets/chrome-extension/icons/icon16.png +0 -0
- package/assets/chrome-extension/icons/icon32.png +0 -0
- package/assets/chrome-extension/icons/icon48.png +0 -0
- package/assets/chrome-extension/manifest.json +0 -0
- package/assets/chrome-extension/options-validation.js +0 -0
- package/assets/chrome-extension/options.html +0 -0
- package/assets/chrome-extension/options.js +0 -0
- package/config/official-external-plugin-catalog.json +0 -0
- package/config/sat-runtime.env +0 -0
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/HOOK.md +0 -0
- package/dist/bundled/bootstrap-extra-files/HOOK.md +0 -0
- package/dist/bundled/command-logger/HOOK.md +0 -0
- package/dist/bundled/session-memory/HOOK.md +0 -0
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/canvas-host/a2ui/index.html +0 -0
- package/dist/cli/daemon-cli/install.js +10 -0
- package/dist/cli/update-cli/update-command.js +73 -7
- package/dist/commands/daemon-install-helpers.js +2 -1
- package/dist/control-ui/apple-touch-icon.png +0 -0
- package/dist/control-ui/assets/{app-S_jg-ADS.js → app-BXA4gPvN.js} +3 -3
- package/dist/control-ui/assets/{index-C22rDOFm.js → index-D2QbJhVg.js} +3 -3
- package/dist/control-ui/boot-watchdog.js +0 -0
- package/dist/control-ui/fased-logo.svg +0 -0
- package/dist/control-ui/favicon-32.png +0 -0
- package/dist/control-ui/favicon.ico +0 -0
- package/dist/control-ui/favicon.svg +0 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/manifest.webmanifest +0 -0
- package/dist/control-ui/version.json +1 -1
- package/dist/daemon/program-args.js +34 -0
- package/dist/export-html/template.css +0 -0
- package/dist/export-html/template.html +0 -0
- package/dist/export-html/template.js +0 -0
- package/dist/export-html/vendor/highlight.min.js +0 -0
- package/dist/export-html/vendor/marked.min.js +0 -0
- package/dist/infra/managed-runtime-bootstrap.js +106 -0
- package/dist/plugin-sdk/{audio-preflight-CxZixyhW.js → audio-preflight-Bv0hUOWL.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
- package/dist/plugin-sdk/{chunk-items-Cy9a3X7x.js → chunk-items-Bk--NU3E.js} +1 -1
- package/dist/plugin-sdk/command-status.js +1 -1
- package/dist/plugin-sdk/{config-schema-D8E0LX8X.js → config-schema-CGW6J3Pv.js} +7 -7
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +3 -3
- package/dist/plugin-sdk/index.d.ts +5 -5
- package/dist/plugin-sdk/index.js +1 -1
- package/dist/plugin-sdk/{monitor-CFHFAUOj.js → monitor-B71iwAgC.js} +3 -3
- package/dist/plugin-sdk/{monitor-xS9A8Upr.js → monitor-B9Cmt_Je.js} +3 -3
- package/dist/plugin-sdk/{openresponses-http-BcUbeVV6.js → openresponses-http-Du4GMmwo.js} +1 -1
- package/dist/plugin-sdk/{pairing-message-CxonJmwM.d.ts → pairing-message-BMkkS038.d.ts} +1 -1
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
- package/dist/plugin-sdk/sat-runtime.d.ts +2 -2
- package/dist/plugin-sdk/sat-runtime.js +1 -1
- package/dist/plugin-sdk/{slack-DXYGbizH.js → slack-D_bbE6Yd.js} +3 -3
- package/dist/plugin-sdk/slack.d.ts +3 -3
- package/dist/plugin-sdk/{sticker-cache-Dr3rYfU1.js → sticker-cache-Dqo9nRhi.js} +2 -2
- package/dist/plugin-sdk/{telegram-actions-Besbw_Hg.js → telegram-actions-Cnag7JTH.js} +2 -2
- package/dist/plugin-sdk/telegram.d.ts +3 -3
- package/dist/plugin-sdk/{tmp-fased-dir-DQ00xQ5D.d.ts → tmp-fased-dir-BdFQvrvw.d.ts} +1 -1
- package/dist/plugin-sdk/{types-B6zx-Dl2.d.ts → types-BYDL6dQj.d.ts} +1 -1
- package/dist/plugin-sdk/{types-eUM7hcDz.d.ts → types-CLIvQaVg.d.ts} +3 -3
- package/dist/plugin-sdk/{web-Q1-G--JH.js → web-BInKQkc4.js} +1 -1
- package/dist/plugin-sdk/whatsapp.d.ts +3 -3
- package/docs/reference/templates/AGENTS.dev.md +0 -0
- package/docs/reference/templates/AGENTS.md +0 -0
- package/docs/reference/templates/BOOT.md +0 -0
- package/docs/reference/templates/BOOTSTRAP.md +0 -0
- package/docs/reference/templates/HEARTBEAT.md +0 -0
- package/docs/reference/templates/IDENTITY.dev.md +0 -0
- package/docs/reference/templates/IDENTITY.md +0 -0
- package/docs/reference/templates/SOUL.dev.md +0 -0
- package/docs/reference/templates/SOUL.md +0 -0
- package/docs/reference/templates/TOOLS.dev.md +0 -0
- package/docs/reference/templates/TOOLS.md +0 -0
- package/docs/reference/templates/USER.dev.md +0 -0
- package/docs/reference/templates/USER.md +0 -0
- package/extensions/acpx/fased.plugin.json +0 -0
- package/extensions/acpx/package.json +1 -1
- package/extensions/acpx/skills/acp-router/SKILL.md +0 -0
- package/extensions/acpx/src/config.ts +0 -0
- package/extensions/acpx/src/ensure.ts +0 -0
- package/extensions/acpx/src/mcp-readonly-tool-registry.ts +0 -0
- package/extensions/acpx/src/mcp-status-adapter.ts +0 -0
- package/extensions/acpx/src/runtime-internals/events.ts +0 -0
- package/extensions/acpx/src/runtime-internals/process.ts +0 -0
- package/extensions/acpx/src/runtime-internals/shared.ts +0 -0
- package/extensions/acpx/src/runtime.ts +0 -0
- package/extensions/acpx/src/service.ts +0 -0
- package/extensions/bluebubbles/README.md +0 -0
- package/extensions/bluebubbles/fased.plugin.json +0 -0
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/bluebubbles/src/account-resolve.ts +0 -0
- package/extensions/bluebubbles/src/accounts.ts +0 -0
- package/extensions/bluebubbles/src/actions.ts +0 -0
- package/extensions/bluebubbles/src/attachments.ts +0 -0
- package/extensions/bluebubbles/src/channel.ts +0 -0
- package/extensions/bluebubbles/src/chat.ts +0 -0
- package/extensions/bluebubbles/src/config-schema.ts +0 -0
- package/extensions/bluebubbles/src/history.ts +0 -0
- package/extensions/bluebubbles/src/media-send.ts +0 -0
- package/extensions/bluebubbles/src/monitor-normalize.ts +0 -0
- package/extensions/bluebubbles/src/monitor-processing.ts +0 -0
- package/extensions/bluebubbles/src/monitor-reply-cache.ts +0 -0
- package/extensions/bluebubbles/src/monitor-shared.ts +0 -0
- package/extensions/bluebubbles/src/monitor.ts +0 -0
- package/extensions/bluebubbles/src/multipart.ts +0 -0
- package/extensions/bluebubbles/src/onboarding.ts +0 -0
- package/extensions/bluebubbles/src/probe.ts +0 -0
- package/extensions/bluebubbles/src/reactions.ts +0 -0
- package/extensions/bluebubbles/src/request-url.ts +0 -0
- package/extensions/bluebubbles/src/runtime.ts +0 -0
- package/extensions/bluebubbles/src/send-helpers.ts +0 -0
- package/extensions/bluebubbles/src/send.ts +0 -0
- package/extensions/bluebubbles/src/targets.ts +0 -0
- package/extensions/bluebubbles/src/test-mocks.ts +0 -0
- package/extensions/bluebubbles/src/types.ts +0 -0
- package/extensions/copilot-proxy/README.md +0 -0
- package/extensions/copilot-proxy/fased.plugin.json +0 -0
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/device-pair/fased.plugin.json +0 -0
- package/extensions/diagnostics-otel/fased.plugin.json +0 -0
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/diagnostics-otel/src/service.ts +0 -0
- package/extensions/fased-federation/README.md +0 -0
- package/extensions/fased-federation/fased.plugin.json +0 -0
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/README.md +0 -0
- package/extensions/google-gemini-cli-auth/fased.plugin.json +0 -0
- package/extensions/google-gemini-cli-auth/oauth.ts +0 -0
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/fased.plugin.json +0 -0
- package/extensions/imessage/package.json +1 -1
- package/extensions/imessage/src/channel.ts +0 -0
- package/extensions/imessage/src/runtime.ts +0 -0
- package/extensions/irc/fased.plugin.json +0 -0
- package/extensions/irc/package.json +1 -1
- package/extensions/irc/src/accounts.ts +0 -0
- package/extensions/irc/src/channel.ts +0 -0
- package/extensions/irc/src/client.ts +0 -0
- package/extensions/irc/src/config-schema.ts +0 -0
- package/extensions/irc/src/connect-options.ts +0 -0
- package/extensions/irc/src/control-chars.ts +0 -0
- package/extensions/irc/src/inbound.ts +0 -0
- package/extensions/irc/src/monitor.ts +0 -0
- package/extensions/irc/src/normalize.ts +0 -0
- package/extensions/irc/src/onboarding.ts +0 -0
- package/extensions/irc/src/policy.ts +0 -0
- package/extensions/irc/src/probe.ts +0 -0
- package/extensions/irc/src/protocol.ts +0 -0
- package/extensions/irc/src/runtime.ts +0 -0
- package/extensions/irc/src/send.ts +0 -0
- package/extensions/irc/src/types.ts +0 -0
- package/extensions/line/fased.plugin.json +0 -0
- package/extensions/line/package.json +1 -1
- package/extensions/line/src/card-command.ts +0 -0
- package/extensions/line/src/channel.ts +0 -0
- package/extensions/line/src/runtime.ts +0 -0
- package/extensions/llm-task/README.md +0 -0
- package/extensions/llm-task/fased.plugin.json +0 -0
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/README.md +0 -0
- package/extensions/lobster/SKILL.md +0 -0
- package/extensions/lobster/fased.plugin.json +0 -0
- package/extensions/lobster/package.json +1 -1
- package/extensions/lobster/src/test-helpers.ts +0 -0
- package/extensions/lobster/src/windows-spawn.ts +0 -0
- package/extensions/matrix/CHANGELOG.md +12 -0
- package/extensions/matrix/fased.plugin.json +0 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/actions.ts +0 -0
- package/extensions/matrix/src/channel.ts +0 -0
- package/extensions/matrix/src/config-schema.ts +0 -0
- package/extensions/matrix/src/directory-live.ts +0 -0
- package/extensions/matrix/src/group-mentions.ts +0 -0
- package/extensions/matrix/src/matrix/accounts.ts +0 -0
- package/extensions/matrix/src/matrix/actions/client.ts +0 -0
- package/extensions/matrix/src/matrix/actions/limits.ts +0 -0
- package/extensions/matrix/src/matrix/actions/messages.ts +0 -0
- package/extensions/matrix/src/matrix/actions/pins.ts +0 -0
- package/extensions/matrix/src/matrix/actions/reactions.ts +0 -0
- package/extensions/matrix/src/matrix/actions/room.ts +0 -0
- package/extensions/matrix/src/matrix/actions/summary.ts +0 -0
- package/extensions/matrix/src/matrix/actions/types.ts +0 -0
- package/extensions/matrix/src/matrix/actions.ts +0 -0
- package/extensions/matrix/src/matrix/active-client.ts +0 -0
- package/extensions/matrix/src/matrix/client/config.ts +0 -0
- package/extensions/matrix/src/matrix/client/create-client.ts +0 -0
- package/extensions/matrix/src/matrix/client/logging.ts +0 -0
- package/extensions/matrix/src/matrix/client/runtime.ts +0 -0
- package/extensions/matrix/src/matrix/client/shared.ts +0 -0
- package/extensions/matrix/src/matrix/client/storage.ts +0 -0
- package/extensions/matrix/src/matrix/client/types.ts +0 -0
- package/extensions/matrix/src/matrix/client-bootstrap.ts +0 -0
- package/extensions/matrix/src/matrix/client.ts +0 -0
- package/extensions/matrix/src/matrix/credentials.ts +0 -0
- package/extensions/matrix/src/matrix/deps.ts +0 -0
- package/extensions/matrix/src/matrix/format.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/access-policy.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/allowlist.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/auto-join.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/direct.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/events.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/handler.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/inbound-body.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/location.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/media.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/mentions.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/replies.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/room-info.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/rooms.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/threads.ts +0 -0
- package/extensions/matrix/src/matrix/monitor/types.ts +0 -0
- package/extensions/matrix/src/matrix/poll-types.ts +0 -0
- package/extensions/matrix/src/matrix/probe.ts +0 -0
- package/extensions/matrix/src/matrix/send/client.ts +0 -0
- package/extensions/matrix/src/matrix/send/formatting.ts +0 -0
- package/extensions/matrix/src/matrix/send/media.ts +0 -0
- package/extensions/matrix/src/matrix/send/targets.ts +0 -0
- package/extensions/matrix/src/matrix/send/types.ts +0 -0
- package/extensions/matrix/src/matrix/send-queue.ts +0 -0
- package/extensions/matrix/src/matrix/send.ts +0 -0
- package/extensions/matrix/src/onboarding.ts +0 -0
- package/extensions/matrix/src/outbound.ts +0 -0
- package/extensions/matrix/src/resolve-targets.ts +0 -0
- package/extensions/matrix/src/runtime.ts +0 -0
- package/extensions/matrix/src/tool-actions.ts +0 -0
- package/extensions/matrix/src/types.ts +0 -0
- package/extensions/mattermost/fased.plugin.json +0 -0
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/channel.ts +0 -0
- package/extensions/mattermost/src/config-schema.ts +0 -0
- package/extensions/mattermost/src/group-mentions.ts +0 -0
- package/extensions/mattermost/src/mattermost/accounts.ts +0 -0
- package/extensions/mattermost/src/mattermost/client.ts +0 -0
- package/extensions/mattermost/src/mattermost/monitor-auth.ts +0 -0
- package/extensions/mattermost/src/mattermost/monitor-helpers.ts +0 -0
- package/extensions/mattermost/src/mattermost/monitor-onchar.ts +0 -0
- package/extensions/mattermost/src/mattermost/monitor-websocket.ts +0 -0
- package/extensions/mattermost/src/mattermost/monitor.ts +0 -0
- package/extensions/mattermost/src/mattermost/probe.ts +0 -0
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +0 -0
- package/extensions/mattermost/src/mattermost/reactions.ts +0 -0
- package/extensions/mattermost/src/mattermost/reconnect.ts +0 -0
- package/extensions/mattermost/src/mattermost/send.ts +0 -0
- package/extensions/mattermost/src/normalize.ts +0 -0
- package/extensions/mattermost/src/onboarding-helpers.ts +0 -0
- package/extensions/mattermost/src/onboarding.ts +0 -0
- package/extensions/mattermost/src/runtime.ts +0 -0
- package/extensions/mattermost/src/types.ts +0 -0
- package/extensions/memory-core/fased.plugin.json +0 -0
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/config.ts +0 -0
- package/extensions/memory-lancedb/fased.plugin.json +0 -0
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/README.md +0 -0
- package/extensions/minimax-portal-auth/fased.plugin.json +0 -0
- package/extensions/minimax-portal-auth/oauth.ts +0 -0
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +12 -0
- package/extensions/msteams/fased.plugin.json +0 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/msteams/src/attachments/download.ts +0 -0
- package/extensions/msteams/src/attachments/graph.ts +0 -0
- package/extensions/msteams/src/attachments/html.ts +0 -0
- package/extensions/msteams/src/attachments/payload.ts +0 -0
- package/extensions/msteams/src/attachments/remote-media.ts +0 -0
- package/extensions/msteams/src/attachments/shared.ts +0 -0
- package/extensions/msteams/src/attachments/types.ts +0 -0
- package/extensions/msteams/src/attachments.ts +0 -0
- package/extensions/msteams/src/channel.ts +0 -0
- package/extensions/msteams/src/conversation-store-fs.ts +0 -0
- package/extensions/msteams/src/conversation-store-memory.ts +0 -0
- package/extensions/msteams/src/conversation-store.ts +0 -0
- package/extensions/msteams/src/directory-live.ts +0 -0
- package/extensions/msteams/src/errors.ts +0 -0
- package/extensions/msteams/src/file-consent-helpers.ts +0 -0
- package/extensions/msteams/src/file-consent.ts +0 -0
- package/extensions/msteams/src/file-lock.ts +0 -0
- package/extensions/msteams/src/graph-chat.ts +0 -0
- package/extensions/msteams/src/graph-upload.ts +0 -0
- package/extensions/msteams/src/graph-users.ts +0 -0
- package/extensions/msteams/src/graph.ts +0 -0
- package/extensions/msteams/src/inbound.ts +0 -0
- package/extensions/msteams/src/media-helpers.ts +0 -0
- package/extensions/msteams/src/mentions.ts +0 -0
- package/extensions/msteams/src/messenger.ts +0 -0
- package/extensions/msteams/src/monitor-handler/inbound-media.ts +0 -0
- package/extensions/msteams/src/monitor-handler/message-handler.ts +0 -0
- package/extensions/msteams/src/monitor-handler.ts +0 -0
- package/extensions/msteams/src/monitor-types.ts +0 -0
- package/extensions/msteams/src/monitor.ts +0 -0
- package/extensions/msteams/src/onboarding.ts +0 -0
- package/extensions/msteams/src/outbound.ts +0 -0
- package/extensions/msteams/src/pending-uploads.ts +0 -0
- package/extensions/msteams/src/policy.ts +0 -0
- package/extensions/msteams/src/polls-store-memory.ts +0 -0
- package/extensions/msteams/src/polls.ts +0 -0
- package/extensions/msteams/src/probe.ts +0 -0
- package/extensions/msteams/src/reply-dispatcher.ts +0 -0
- package/extensions/msteams/src/resolve-allowlist.ts +0 -0
- package/extensions/msteams/src/runtime.ts +0 -0
- package/extensions/msteams/src/sdk-types.ts +0 -0
- package/extensions/msteams/src/sdk.ts +0 -0
- package/extensions/msteams/src/send-context.ts +0 -0
- package/extensions/msteams/src/send.ts +0 -0
- package/extensions/msteams/src/sent-message-cache.ts +0 -0
- package/extensions/msteams/src/storage.ts +0 -0
- package/extensions/msteams/src/store-fs.ts +0 -0
- package/extensions/msteams/src/test-runtime.ts +0 -0
- package/extensions/msteams/src/token-response.ts +0 -0
- package/extensions/msteams/src/token.ts +0 -0
- package/extensions/nextcloud-talk/fased.plugin.json +0 -0
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nextcloud-talk/src/accounts.ts +0 -0
- package/extensions/nextcloud-talk/src/config-schema.ts +0 -0
- package/extensions/nextcloud-talk/src/format.ts +0 -0
- package/extensions/nextcloud-talk/src/inbound.ts +0 -0
- package/extensions/nextcloud-talk/src/monitor.ts +0 -0
- package/extensions/nextcloud-talk/src/normalize.ts +0 -0
- package/extensions/nextcloud-talk/src/onboarding.ts +0 -0
- package/extensions/nextcloud-talk/src/policy.ts +0 -0
- package/extensions/nextcloud-talk/src/replay-guard.ts +0 -0
- package/extensions/nextcloud-talk/src/room-info.ts +0 -0
- package/extensions/nextcloud-talk/src/runtime.ts +0 -0
- package/extensions/nextcloud-talk/src/send.ts +0 -0
- package/extensions/nextcloud-talk/src/signature.ts +0 -0
- package/extensions/nextcloud-talk/src/types.ts +0 -0
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/README.md +0 -0
- package/extensions/nostr/fased.plugin.json +0 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/nostr/src/channel.ts +0 -0
- package/extensions/nostr/src/config-schema.ts +0 -0
- package/extensions/nostr/src/metrics.ts +0 -0
- package/extensions/nostr/src/nostr-bus.ts +0 -0
- package/extensions/nostr/src/nostr-profile-http.ts +0 -0
- package/extensions/nostr/src/nostr-profile-import.ts +0 -0
- package/extensions/nostr/src/nostr-profile.ts +0 -0
- package/extensions/nostr/src/nostr-state-store.ts +0 -0
- package/extensions/nostr/src/onboarding.ts +0 -0
- package/extensions/nostr/src/runtime.ts +0 -0
- package/extensions/nostr/src/seen-tracker.ts +0 -0
- package/extensions/nostr/src/types.ts +0 -0
- package/extensions/nostr/test/setup.ts +0 -0
- package/extensions/open-prose/README.md +0 -0
- package/extensions/open-prose/fased.plugin.json +0 -0
- package/extensions/open-prose/package.json +1 -1
- package/extensions/open-prose/skills/prose/LICENSE +0 -0
- package/extensions/open-prose/skills/prose/SKILL.md +0 -0
- package/extensions/open-prose/skills/prose/alt-borges.md +0 -0
- package/extensions/open-prose/skills/prose/alts/arabian-nights.md +0 -0
- package/extensions/open-prose/skills/prose/alts/borges.md +0 -0
- package/extensions/open-prose/skills/prose/alts/folk.md +0 -0
- package/extensions/open-prose/skills/prose/alts/homer.md +0 -0
- package/extensions/open-prose/skills/prose/alts/kafka.md +0 -0
- package/extensions/open-prose/skills/prose/compiler.md +0 -0
- package/extensions/open-prose/skills/prose/examples/01-hello-world.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/02-research-and-summarize.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/03-code-review.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/04-write-and-refine.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/05-debug-issue.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/06-explain-codebase.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/07-refactor.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/08-blog-post.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/09-research-with-agents.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/10-code-review-agents.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/11-skills-and-imports.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/12-secure-agent-permissions.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/13-variables-and-context.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/14-composition-blocks.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/15-inline-sequences.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/16-parallel-reviews.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/17-parallel-research.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/18-mixed-parallel-sequential.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/19-advanced-parallel.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/20-fixed-loops.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/21-pipeline-operations.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/22-error-handling.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/23-retry-with-backoff.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/24-choice-blocks.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/25-conditionals.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/26-parameterized-blocks.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/27-string-interpolation.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/28-automated-pr-review.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/28-gas-town.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/29-captains-chair.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/30-captains-chair-simple.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/31-captains-chair-with-memory.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/33-pr-review-autofix.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/34-content-pipeline.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/35-feature-factory.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/36-bug-hunter.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/37-the-forge.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/38-skill-scan.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/39-architect-by-simulation.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/40-rlm-self-refine.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/41-rlm-divide-conquer.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/42-rlm-filter-recurse.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/43-rlm-pairwise.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/44-run-endpoint-ux-test.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/45-plugin-release.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/45-run-endpoint-ux-test-with-remediation.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/46-run-endpoint-ux-test-fast.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/46-workflow-crystallizer.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/47-language-self-improvement.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/48-habit-miner.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/49-prose-run-retrospective.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/README.md +0 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/README.md +0 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/iterative-refinement.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/parallel-review.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/simple-pipeline.prose +0 -0
- package/extensions/open-prose/skills/prose/examples/roadmap/syntax/open-prose-syntax.prose +0 -0
- package/extensions/open-prose/skills/prose/guidance/antipatterns.md +0 -0
- package/extensions/open-prose/skills/prose/guidance/patterns.md +0 -0
- package/extensions/open-prose/skills/prose/guidance/system-prompt.md +0 -0
- package/extensions/open-prose/skills/prose/help.md +0 -0
- package/extensions/open-prose/skills/prose/lib/README.md +0 -0
- package/extensions/open-prose/skills/prose/lib/calibrator.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/cost-analyzer.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/error-forensics.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/inspector.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/profiler.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/program-improver.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/project-memory.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/user-memory.prose +0 -0
- package/extensions/open-prose/skills/prose/lib/vm-improver.prose +0 -0
- package/extensions/open-prose/skills/prose/primitives/session.md +0 -0
- package/extensions/open-prose/skills/prose/prose.md +0 -0
- package/extensions/open-prose/skills/prose/state/filesystem.md +0 -0
- package/extensions/open-prose/skills/prose/state/in-context.md +0 -0
- package/extensions/open-prose/skills/prose/state/postgres.md +0 -0
- package/extensions/open-prose/skills/prose/state/sqlite.md +0 -0
- package/extensions/phone-control/fased.plugin.json +0 -0
- package/extensions/qwen-portal-auth/README.md +0 -0
- package/extensions/qwen-portal-auth/fased.plugin.json +0 -0
- package/extensions/qwen-portal-auth/oauth.ts +0 -0
- package/extensions/sat-mining/fased.plugin.json +0 -0
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/sat-mining/skills/sat-mining/SKILL.md +0 -0
- package/extensions/sat-mining/src/audit-store.ts +0 -0
- package/extensions/sat-mining/src/auto-planner.ts +0 -0
- package/extensions/sat-mining/src/chain-time.ts +0 -0
- package/extensions/sat-mining/src/client.ts +0 -0
- package/extensions/sat-mining/src/cycle-progress.ts +0 -0
- package/extensions/sat-mining/src/dispute-review.ts +0 -0
- package/extensions/sat-mining/src/hash-spec.ts +0 -0
- package/extensions/sat-mining/src/planner-analytics.ts +0 -0
- package/extensions/sat-mining/src/planner-outcomes.ts +0 -0
- package/extensions/sat-mining/src/planner-policy-eval.ts +0 -0
- package/extensions/sat-mining/src/planner-policy.ts +0 -0
- package/extensions/sat-mining/src/recovery-service.ts +0 -0
- package/extensions/sat-mining/src/replay.ts +0 -0
- package/extensions/sat-mining/src/service-read-timeout.ts +0 -0
- package/extensions/sat-mining/src/strategy-base.ts +0 -0
- package/extensions/sat-mining/src/strategy-engine.ts +0 -0
- package/extensions/sat-mining/src/strategy-validate.ts +0 -0
- package/extensions/shared/resolve-target-test-helpers.ts +0 -0
- package/extensions/signal/fased.plugin.json +0 -0
- package/extensions/signal/package.json +1 -1
- package/extensions/signal/src/channel.ts +0 -0
- package/extensions/signal/src/runtime.ts +0 -0
- package/extensions/synology-chat/fased.plugin.json +0 -0
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/synology-chat/src/accounts.ts +0 -0
- package/extensions/synology-chat/src/channel.ts +0 -0
- package/extensions/synology-chat/src/client.ts +0 -0
- package/extensions/synology-chat/src/runtime.ts +0 -0
- package/extensions/synology-chat/src/security.ts +0 -0
- package/extensions/synology-chat/src/types.ts +0 -0
- package/extensions/synology-chat/src/webhook-handler.ts +0 -0
- package/extensions/talk-voice/fased.plugin.json +0 -0
- package/extensions/thread-ownership/fased.plugin.json +0 -0
- package/extensions/tlon/README.md +0 -0
- package/extensions/tlon/fased.plugin.json +0 -0
- package/extensions/tlon/package.json +1 -1
- package/extensions/tlon/src/account-fields.ts +0 -0
- package/extensions/tlon/src/channel.ts +0 -0
- package/extensions/tlon/src/config-schema.ts +0 -0
- package/extensions/tlon/src/monitor/discovery.ts +0 -0
- package/extensions/tlon/src/monitor/history.ts +0 -0
- package/extensions/tlon/src/monitor/processed-messages.ts +0 -0
- package/extensions/tlon/src/monitor/utils.ts +0 -0
- package/extensions/tlon/src/onboarding.ts +0 -0
- package/extensions/tlon/src/runtime.ts +0 -0
- package/extensions/tlon/src/targets.ts +0 -0
- package/extensions/tlon/src/types.ts +0 -0
- package/extensions/tlon/src/urbit/auth.ts +0 -0
- package/extensions/tlon/src/urbit/base-url.ts +0 -0
- package/extensions/tlon/src/urbit/channel-client.ts +0 -0
- package/extensions/tlon/src/urbit/channel-ops.ts +0 -0
- package/extensions/tlon/src/urbit/context.ts +0 -0
- package/extensions/tlon/src/urbit/errors.ts +0 -0
- package/extensions/tlon/src/urbit/fetch.ts +0 -0
- package/extensions/tlon/src/urbit/send.ts +0 -0
- package/extensions/tlon/src/urbit/sse-client.ts +0 -0
- package/extensions/twitch/CHANGELOG.md +12 -0
- package/extensions/twitch/README.md +0 -0
- package/extensions/twitch/fased.plugin.json +0 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/twitch/src/access-control.ts +0 -0
- package/extensions/twitch/src/actions.ts +0 -0
- package/extensions/twitch/src/client-manager-registry.ts +0 -0
- package/extensions/twitch/src/config-schema.ts +0 -0
- package/extensions/twitch/src/config.ts +0 -0
- package/extensions/twitch/src/monitor.ts +0 -0
- package/extensions/twitch/src/onboarding.ts +0 -0
- package/extensions/twitch/src/outbound.ts +0 -0
- package/extensions/twitch/src/probe.ts +0 -0
- package/extensions/twitch/src/resolver.ts +0 -0
- package/extensions/twitch/src/runtime.ts +0 -0
- package/extensions/twitch/src/send.ts +0 -0
- package/extensions/twitch/src/status.ts +0 -0
- package/extensions/twitch/src/test-fixtures.ts +0 -0
- package/extensions/twitch/src/twitch-client.ts +0 -0
- package/extensions/twitch/src/utils/markdown.ts +0 -0
- package/extensions/twitch/src/utils/twitch.ts +0 -0
- package/extensions/twitch/test/setup.ts +0 -0
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/README.md +0 -0
- package/extensions/voice-call/fased.plugin.json +0 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/voice-call/src/allowlist.ts +0 -0
- package/extensions/voice-call/src/cli.ts +0 -0
- package/extensions/voice-call/src/core-bridge.ts +0 -0
- package/extensions/voice-call/src/http-headers.ts +0 -0
- package/extensions/voice-call/src/manager/context.ts +0 -0
- package/extensions/voice-call/src/manager/events.ts +0 -0
- package/extensions/voice-call/src/manager/lookup.ts +0 -0
- package/extensions/voice-call/src/manager/outbound.ts +0 -0
- package/extensions/voice-call/src/manager/state.ts +0 -0
- package/extensions/voice-call/src/manager/store.ts +0 -0
- package/extensions/voice-call/src/manager/timers.ts +0 -0
- package/extensions/voice-call/src/manager/twiml.ts +0 -0
- package/extensions/voice-call/src/manager.ts +0 -0
- package/extensions/voice-call/src/media-stream.ts +0 -0
- package/extensions/voice-call/src/providers/base.ts +0 -0
- package/extensions/voice-call/src/providers/mock.ts +0 -0
- package/extensions/voice-call/src/providers/plivo.ts +0 -0
- package/extensions/voice-call/src/providers/shared/guarded-json-api.ts +0 -0
- package/extensions/voice-call/src/providers/stt-openai-realtime.ts +0 -0
- package/extensions/voice-call/src/providers/telnyx.ts +0 -0
- package/extensions/voice-call/src/providers/tts-openai.ts +0 -0
- package/extensions/voice-call/src/providers/twilio/api.ts +0 -0
- package/extensions/voice-call/src/providers/twilio/webhook.ts +0 -0
- package/extensions/voice-call/src/providers/twilio.ts +0 -0
- package/extensions/voice-call/src/response-generator.ts +0 -0
- package/extensions/voice-call/src/runtime.ts +0 -0
- package/extensions/voice-call/src/telephony-audio.ts +0 -0
- package/extensions/voice-call/src/telephony-tts.ts +0 -0
- package/extensions/voice-call/src/tunnel.ts +0 -0
- package/extensions/voice-call/src/types.ts +0 -0
- package/extensions/voice-call/src/utils.ts +0 -0
- package/extensions/voice-call/src/voice-mapping.ts +0 -0
- package/extensions/voice-call/src/webhook/stale-call-reaper.ts +0 -0
- package/extensions/voice-call/src/webhook-security.ts +0 -0
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/README.md +0 -0
- package/extensions/zalo/fased.plugin.json +0 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalo/src/accounts.ts +0 -0
- package/extensions/zalo/src/actions.ts +0 -0
- package/extensions/zalo/src/api.ts +0 -0
- package/extensions/zalo/src/channel.ts +0 -0
- package/extensions/zalo/src/config-schema.ts +0 -0
- package/extensions/zalo/src/group-access.ts +0 -0
- package/extensions/zalo/src/monitor.ts +0 -0
- package/extensions/zalo/src/monitor.webhook.ts +0 -0
- package/extensions/zalo/src/onboarding.ts +0 -0
- package/extensions/zalo/src/probe.ts +0 -0
- package/extensions/zalo/src/proxy.ts +0 -0
- package/extensions/zalo/src/runtime.ts +0 -0
- package/extensions/zalo/src/send.ts +0 -0
- package/extensions/zalo/src/status-issues.ts +0 -0
- package/extensions/zalo/src/token.ts +0 -0
- package/extensions/zalo/src/types.ts +0 -0
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/README.md +0 -0
- package/extensions/zalouser/fased.plugin.json +0 -0
- package/extensions/zalouser/package.json +1 -1
- package/extensions/zalouser/src/accounts.ts +0 -0
- package/extensions/zalouser/src/channel.ts +0 -0
- package/extensions/zalouser/src/config-schema.ts +0 -0
- package/extensions/zalouser/src/monitor.ts +0 -0
- package/extensions/zalouser/src/onboarding.ts +0 -0
- package/extensions/zalouser/src/probe.ts +0 -0
- package/extensions/zalouser/src/runtime.ts +0 -0
- package/extensions/zalouser/src/send.ts +0 -0
- package/extensions/zalouser/src/status-issues.ts +0 -0
- package/extensions/zalouser/src/tool.ts +0 -0
- package/extensions/zalouser/src/types.ts +0 -0
- package/extensions/zalouser/src/zca.ts +0 -0
- package/package.json +8 -2
- package/scripts/fased-launcher-runtime.mjs +0 -0
- package/scripts/fased-managed-launcher.sh +60 -0
- package/scripts/fased-managed-service.sh +57 -0
- package/scripts/fased-managed-updater.mjs +879 -0
- package/scripts/install-managed-runtime.mjs +239 -0
- package/scripts/managed-runtime-layout.mjs +188 -0
- package/scripts/run-node.mjs +0 -0
- package/shared/sat-hash-v1.json +0 -0
- package/skills/1password/SKILL.md +0 -0
- package/skills/1password/references/cli-examples.md +0 -0
- package/skills/1password/references/get-started.md +0 -0
- package/skills/apple-notes/SKILL.md +0 -0
- package/skills/apple-reminders/SKILL.md +0 -0
- package/skills/bear-notes/SKILL.md +0 -0
- package/skills/blogwatcher/SKILL.md +0 -0
- package/skills/blucli/SKILL.md +0 -0
- package/skills/bluebubbles/SKILL.md +0 -0
- package/skills/camsnap/SKILL.md +0 -0
- package/skills/canvas/SKILL.md +0 -0
- package/skills/clawhub/SKILL.md +0 -0
- package/skills/coding-agent/SKILL.md +0 -0
- package/skills/diagram-maker/SKILL.md +0 -0
- package/skills/diagram-maker/references/excalidraw-patterns.md +0 -0
- package/skills/diagram-maker/references/svg-template.md +0 -0
- package/skills/discord/SKILL.md +0 -0
- package/skills/eightctl/SKILL.md +0 -0
- package/skills/food-order/SKILL.md +0 -0
- package/skills/gemini/SKILL.md +0 -0
- package/skills/gh-issues/SKILL.md +0 -0
- package/skills/gifgrep/SKILL.md +0 -0
- package/skills/github/SKILL.md +0 -0
- package/skills/gog/SKILL.md +0 -0
- package/skills/goplaces/SKILL.md +0 -0
- package/skills/healthcheck/SKILL.md +0 -0
- package/skills/himalaya/SKILL.md +0 -0
- package/skills/himalaya/references/configuration.md +0 -0
- package/skills/himalaya/references/message-composition.md +0 -0
- package/skills/imsg/SKILL.md +0 -0
- package/skills/mcporter/SKILL.md +0 -0
- package/skills/model-usage/SKILL.md +0 -0
- package/skills/model-usage/references/codexbar-cli.md +0 -0
- package/skills/model-usage/scripts/model_usage.py +0 -0
- package/skills/model-usage/scripts/test_model_usage.py +0 -0
- package/skills/nano-banana-pro/SKILL.md +0 -0
- package/skills/nano-pdf/SKILL.md +0 -0
- package/skills/node-connect/SKILL.md +0 -0
- package/skills/node-inspect-debugger/SKILL.md +0 -0
- package/skills/notion/SKILL.md +0 -0
- package/skills/obsidian/SKILL.md +0 -0
- package/skills/openai-image-gen/SKILL.md +0 -0
- package/skills/openai-image-gen/scripts/gen.py +0 -0
- package/skills/openai-image-gen/scripts/test_gen.py +0 -0
- package/skills/openai-whisper/SKILL.md +0 -0
- package/skills/openai-whisper-api/SKILL.md +0 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +0 -0
- package/skills/opencode/SKILL.md +0 -0
- package/skills/openhue/SKILL.md +0 -0
- package/skills/oracle/SKILL.md +0 -0
- package/skills/ordercli/SKILL.md +0 -0
- package/skills/peekaboo/SKILL.md +0 -0
- package/skills/python-debugpy/SKILL.md +0 -0
- package/skills/sag/SKILL.md +0 -0
- package/skills/session-logs/SKILL.md +0 -0
- package/skills/sherpa-onnx-tts/SKILL.md +0 -0
- package/skills/skill-creator/SKILL.md +0 -0
- package/skills/skill-creator/license.txt +0 -0
- package/skills/skill-creator/scripts/init_skill.py +0 -0
- package/skills/skill-creator/scripts/package_skill.py +0 -0
- package/skills/skill-creator/scripts/quick_validate.py +0 -0
- package/skills/skill-creator/scripts/test_package_skill.py +0 -0
- package/skills/skill-creator/scripts/test_quick_validate.py +0 -0
- package/skills/skill-workshop/SKILL.md +0 -0
- package/skills/slack/SKILL.md +0 -0
- package/skills/songsee/SKILL.md +0 -0
- package/skills/sonoscli/SKILL.md +0 -0
- package/skills/spotify-player/SKILL.md +0 -0
- package/skills/summarize/SKILL.md +0 -0
- package/skills/things-mac/SKILL.md +0 -0
- package/skills/tmux/SKILL.md +0 -0
- package/skills/trello/SKILL.md +0 -0
- package/skills/video-frames/SKILL.md +0 -0
- package/skills/video-frames/scripts/frame.sh +0 -0
- package/skills/voice-call/SKILL.md +0 -0
- package/skills/wacli/SKILL.md +0 -0
- package/skills/wallet-actions/SKILL.md +0 -0
- package/skills/weather/SKILL.md +0 -0
- package/skills/xurl/SKILL.md +0 -0
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import fsp from "node:fs/promises";
|
|
6
|
+
import http from "node:http";
|
|
7
|
+
import https from "node:https";
|
|
8
|
+
import os from "node:os";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { Readable } from "node:stream";
|
|
11
|
+
import { pipeline } from "node:stream/promises";
|
|
12
|
+
import { pathToFileURL } from "node:url";
|
|
13
|
+
import { promisify } from "node:util";
|
|
14
|
+
import {
|
|
15
|
+
assertManagedRuntime,
|
|
16
|
+
atomicSymlink,
|
|
17
|
+
atomicWriteJson,
|
|
18
|
+
buildManagedInstallManifest,
|
|
19
|
+
copyExecutable,
|
|
20
|
+
readHostedRuntimeMetadata,
|
|
21
|
+
readManagedInstallManifest,
|
|
22
|
+
readPackageVersion,
|
|
23
|
+
resolveLinkTarget,
|
|
24
|
+
resolveManagedRuntimePaths,
|
|
25
|
+
} from "./managed-runtime-layout.mjs";
|
|
26
|
+
|
|
27
|
+
const execFileAsync = promisify(execFile);
|
|
28
|
+
const DEFAULT_RELEASE_BASE_URL = "https://github.com/fased-ai/fased/releases/download";
|
|
29
|
+
const DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
30
|
+
const DEFAULT_TIMEOUT_MS = 20 * 60_000;
|
|
31
|
+
|
|
32
|
+
async function measureStage(timings, name, operation) {
|
|
33
|
+
const startedAt = Date.now();
|
|
34
|
+
try {
|
|
35
|
+
return await operation();
|
|
36
|
+
} finally {
|
|
37
|
+
timings.push({ name, durationMs: Date.now() - startedAt });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function formatDuration(durationMs) {
|
|
42
|
+
return durationMs < 1000 ? `${durationMs}ms` : `${(durationMs / 1000).toFixed(2)}s`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseArgs(argv) {
|
|
46
|
+
if (argv[0] !== "update") {
|
|
47
|
+
return { delegate: true, args: argv };
|
|
48
|
+
}
|
|
49
|
+
if (argv[1] && !argv[1].startsWith("-") && argv[1] !== "status") {
|
|
50
|
+
return { delegate: true, args: argv };
|
|
51
|
+
}
|
|
52
|
+
const status = argv[1] === "status";
|
|
53
|
+
const tokens = status ? argv.slice(2) : argv.slice(1);
|
|
54
|
+
const options = {
|
|
55
|
+
status,
|
|
56
|
+
dryRun: false,
|
|
57
|
+
json: false,
|
|
58
|
+
restart: true,
|
|
59
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
60
|
+
channel: null,
|
|
61
|
+
channelExplicit: false,
|
|
62
|
+
tag: null,
|
|
63
|
+
};
|
|
64
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
65
|
+
const token = tokens[index];
|
|
66
|
+
if (token === "--json") {
|
|
67
|
+
options.json = true;
|
|
68
|
+
} else if (token === "--dry-run") {
|
|
69
|
+
options.dryRun = true;
|
|
70
|
+
} else if (token === "--no-restart") {
|
|
71
|
+
options.restart = false;
|
|
72
|
+
} else if (token === "--restart") {
|
|
73
|
+
options.restart = true;
|
|
74
|
+
} else if (token === "--timeout") {
|
|
75
|
+
const value = Number.parseInt(tokens[index + 1] || "", 10);
|
|
76
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
77
|
+
throw new Error("--timeout must be a positive integer (seconds)");
|
|
78
|
+
}
|
|
79
|
+
options.timeoutMs = value * 1000;
|
|
80
|
+
index += 1;
|
|
81
|
+
} else if (token === "--channel") {
|
|
82
|
+
options.channel = String(tokens[index + 1] || "").trim();
|
|
83
|
+
options.channelExplicit = true;
|
|
84
|
+
index += 1;
|
|
85
|
+
} else if (token === "--tag") {
|
|
86
|
+
options.tag = String(tokens[index + 1] || "").trim();
|
|
87
|
+
index += 1;
|
|
88
|
+
} else if (token === "--yes" || token === "--safe-fallback") {
|
|
89
|
+
// Compatibility flags do not change the managed artifact transaction.
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error(`Unsupported managed update option: ${token}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (options.channelExplicit && options.channel === "dev") {
|
|
95
|
+
return { delegate: true, args: argv };
|
|
96
|
+
}
|
|
97
|
+
if (options.channelExplicit && !new Set(["stable", "beta"]).has(options.channel)) {
|
|
98
|
+
throw new Error('--channel must be "stable" or "beta" for a managed installation');
|
|
99
|
+
}
|
|
100
|
+
return { delegate: false, options };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function compareVersions(left, right) {
|
|
104
|
+
const parse = (value) => {
|
|
105
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(
|
|
106
|
+
String(value || "").trim(),
|
|
107
|
+
);
|
|
108
|
+
return match
|
|
109
|
+
? {
|
|
110
|
+
core: match.slice(1, 4).map(Number),
|
|
111
|
+
prerelease: match[4]?.split(".") ?? [],
|
|
112
|
+
}
|
|
113
|
+
: null;
|
|
114
|
+
};
|
|
115
|
+
const a = parse(left);
|
|
116
|
+
const b = parse(right);
|
|
117
|
+
if (!a || !b) {
|
|
118
|
+
return left === right ? 0 : null;
|
|
119
|
+
}
|
|
120
|
+
for (let index = 0; index < 3; index += 1) {
|
|
121
|
+
if (a.core[index] !== b.core[index]) {
|
|
122
|
+
return a.core[index] < b.core[index] ? -1 : 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (a.prerelease.length === 0 || b.prerelease.length === 0) {
|
|
126
|
+
return a.prerelease.length === b.prerelease.length ? 0 : a.prerelease.length === 0 ? 1 : -1;
|
|
127
|
+
}
|
|
128
|
+
const length = Math.max(a.prerelease.length, b.prerelease.length);
|
|
129
|
+
for (let index = 0; index < length; index += 1) {
|
|
130
|
+
const leftPart = a.prerelease[index];
|
|
131
|
+
const rightPart = b.prerelease[index];
|
|
132
|
+
if (leftPart === undefined || rightPart === undefined) {
|
|
133
|
+
return leftPart === rightPart ? 0 : leftPart === undefined ? -1 : 1;
|
|
134
|
+
}
|
|
135
|
+
if (leftPart === rightPart) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const leftNumeric = /^\d+$/.test(leftPart);
|
|
139
|
+
const rightNumeric = /^\d+$/.test(rightPart);
|
|
140
|
+
if (leftNumeric && rightNumeric) {
|
|
141
|
+
return Number(leftPart) < Number(rightPart) ? -1 : 1;
|
|
142
|
+
}
|
|
143
|
+
if (leftNumeric !== rightNumeric) {
|
|
144
|
+
return leftNumeric ? -1 : 1;
|
|
145
|
+
}
|
|
146
|
+
return leftPart < rightPart ? -1 : 1;
|
|
147
|
+
}
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function resolveArchitecture() {
|
|
152
|
+
if (process.platform !== "linux") {
|
|
153
|
+
throw new Error(`Managed release artifacts are not available for ${process.platform}.`);
|
|
154
|
+
}
|
|
155
|
+
if (process.arch === "x64") {
|
|
156
|
+
return "x64";
|
|
157
|
+
}
|
|
158
|
+
if (process.arch === "arm64") {
|
|
159
|
+
return "arm64";
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`Managed release artifacts are not available for ${process.arch}.`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function fetchJson(url, timeoutMs) {
|
|
165
|
+
const response = await fetch(url, {
|
|
166
|
+
headers: { accept: "application/json", "cache-control": "no-cache" },
|
|
167
|
+
signal: AbortSignal.timeout(Math.min(timeoutMs, 15_000)),
|
|
168
|
+
cache: "no-store",
|
|
169
|
+
});
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
throw new Error(`Request failed (${response.status}): ${url}`);
|
|
172
|
+
}
|
|
173
|
+
return await response.json();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function resolveTargetVersion(options) {
|
|
177
|
+
const explicit = options.tag?.replace(/^@fased\/fased@/, "").replace(/^v/, "");
|
|
178
|
+
if (explicit && /^\d+\.\d+\.\d+(?:[-+].*)?$/.test(explicit)) {
|
|
179
|
+
return explicit;
|
|
180
|
+
}
|
|
181
|
+
const registry = (process.env.npm_config_registry || DEFAULT_REGISTRY).replace(/\/$/, "");
|
|
182
|
+
const payload = await fetchJson(
|
|
183
|
+
`${registry}/@fased%2ffased?fased_update=${Date.now()}`,
|
|
184
|
+
options.timeoutMs,
|
|
185
|
+
);
|
|
186
|
+
const tag = explicit || (options.channel === "beta" ? "beta" : "latest");
|
|
187
|
+
const version = payload?.["dist-tags"]?.[tag];
|
|
188
|
+
if (typeof version !== "string" || !version.trim()) {
|
|
189
|
+
throw new Error(`npm dist-tag ${tag} did not resolve to a Fased version.`);
|
|
190
|
+
}
|
|
191
|
+
return version.trim();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function resolveConfiguredChannel(options, configPath) {
|
|
195
|
+
if (options.channelExplicit) {
|
|
196
|
+
try {
|
|
197
|
+
const config = JSON.parse(await fsp.readFile(configPath, "utf8"));
|
|
198
|
+
config.update = { ...config.update, channel: options.channel };
|
|
199
|
+
await atomicWriteJson(configPath, config, 0o600);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (error?.code !== "ENOENT") {
|
|
202
|
+
throw new Error(`Could not persist update channel: ${error.message}`, { cause: error });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return options.channel;
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
const config = JSON.parse(await fsp.readFile(configPath, "utf8"));
|
|
209
|
+
const stored = String(config?.update?.channel || "").trim();
|
|
210
|
+
if (new Set(["stable", "beta", "dev"]).has(stored)) {
|
|
211
|
+
return stored;
|
|
212
|
+
}
|
|
213
|
+
} catch {
|
|
214
|
+
// Missing or invalid config uses the stable channel.
|
|
215
|
+
}
|
|
216
|
+
return "stable";
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function sha256File(filePath) {
|
|
220
|
+
const hash = createHash("sha256");
|
|
221
|
+
await pipeline(fs.createReadStream(filePath), hash);
|
|
222
|
+
return hash.digest("hex");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function fetchText(url, timeoutMs) {
|
|
226
|
+
const response = await fetch(url, {
|
|
227
|
+
headers: { "cache-control": "no-cache" },
|
|
228
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
229
|
+
cache: "no-store",
|
|
230
|
+
});
|
|
231
|
+
if (!response.ok) {
|
|
232
|
+
throw new Error(`Download failed (${response.status}): ${url}`);
|
|
233
|
+
}
|
|
234
|
+
return await response.text();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function downloadToFile(url, destination, timeoutMs) {
|
|
238
|
+
const response = await fetch(url, {
|
|
239
|
+
headers: { "cache-control": "no-cache" },
|
|
240
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
241
|
+
cache: "no-store",
|
|
242
|
+
});
|
|
243
|
+
if (!response.ok || !response.body) {
|
|
244
|
+
throw new Error(`Download failed (${response.status}): ${url}`);
|
|
245
|
+
}
|
|
246
|
+
await fsp.mkdir(path.dirname(destination), { recursive: true });
|
|
247
|
+
await pipeline(
|
|
248
|
+
Readable.fromWeb(response.body),
|
|
249
|
+
fs.createWriteStream(destination, { mode: 0o600 }),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async function downloadVerifiedAsset({ releaseUrl, assetName, destinationDir, timeoutMs }) {
|
|
254
|
+
const checksum = await fetchText(`${releaseUrl}/${assetName}.sha256`, timeoutMs);
|
|
255
|
+
const expected = checksum
|
|
256
|
+
.split(/\r?\n/)
|
|
257
|
+
.map((line) => line.trim().split(/\s+/))
|
|
258
|
+
.find((parts) => parts[1]?.replace(/^\*/, "") === assetName)?.[0]
|
|
259
|
+
?.toLowerCase();
|
|
260
|
+
if (!expected || !/^[a-f0-9]{64}$/.test(expected)) {
|
|
261
|
+
throw new Error(`Release checksum is invalid for ${assetName}.`);
|
|
262
|
+
}
|
|
263
|
+
const destination = path.join(destinationDir, assetName);
|
|
264
|
+
await downloadToFile(`${releaseUrl}/${assetName}`, destination, timeoutMs);
|
|
265
|
+
const actual = await sha256File(destination);
|
|
266
|
+
if (actual !== expected) {
|
|
267
|
+
throw new Error(`Checksum mismatch for ${assetName}.`);
|
|
268
|
+
}
|
|
269
|
+
return destination;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function runFile(command, args, options = {}) {
|
|
273
|
+
try {
|
|
274
|
+
const result = await execFileAsync(command, args, {
|
|
275
|
+
cwd: options.cwd,
|
|
276
|
+
env: options.env,
|
|
277
|
+
timeout: options.timeoutMs || DEFAULT_TIMEOUT_MS,
|
|
278
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
279
|
+
encoding: "utf8",
|
|
280
|
+
});
|
|
281
|
+
return { ok: true, stdout: result.stdout || "", stderr: result.stderr || "" };
|
|
282
|
+
} catch (error) {
|
|
283
|
+
return {
|
|
284
|
+
ok: false,
|
|
285
|
+
stdout: error?.stdout || "",
|
|
286
|
+
stderr: error?.stderr || error?.message || String(error),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function archiveEntryIsSafe(entry, allowedRoot) {
|
|
292
|
+
const normalized = String(entry || "").replace(/\/+$/, "");
|
|
293
|
+
if (!normalized || normalized.includes("\\") || path.posix.isAbsolute(normalized)) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
const parts = normalized.split("/");
|
|
297
|
+
if (parts[0] !== allowedRoot) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
return parts.every((part) => part !== "" && part !== "." && part !== "..");
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async function assertArchiveSafe(archivePath, allowedRoot) {
|
|
304
|
+
const listed = await runFile("tar", ["-tzf", archivePath], { timeoutMs: 120_000 });
|
|
305
|
+
if (!listed.ok) {
|
|
306
|
+
throw new Error(`Could not inspect release archive: ${listed.stderr.trim()}`);
|
|
307
|
+
}
|
|
308
|
+
for (const entry of listed.stdout.split(/\r?\n/).filter(Boolean)) {
|
|
309
|
+
if (archiveEntryIsSafe(entry, allowedRoot)) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
throw new Error(`Unsafe release archive entry: ${entry}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function extractArchive(archivePath, destination, timeoutMs) {
|
|
317
|
+
await fsp.mkdir(destination, { recursive: true });
|
|
318
|
+
const result = await runFile("tar", ["-xzf", archivePath, "-C", destination], { timeoutMs });
|
|
319
|
+
if (!result.ok) {
|
|
320
|
+
throw new Error(`Release extraction failed: ${result.stderr.trim()}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function ensureDependencyLayer({
|
|
325
|
+
dependencyHash,
|
|
326
|
+
releaseUrl,
|
|
327
|
+
arch,
|
|
328
|
+
paths,
|
|
329
|
+
temporaryRoot,
|
|
330
|
+
timeoutMs,
|
|
331
|
+
}) {
|
|
332
|
+
const dependencyRoot = path.join(
|
|
333
|
+
paths.stateDir,
|
|
334
|
+
"install-cache",
|
|
335
|
+
"hosted-dependencies",
|
|
336
|
+
dependencyHash,
|
|
337
|
+
);
|
|
338
|
+
const nodeModules = path.join(dependencyRoot, "node_modules");
|
|
339
|
+
try {
|
|
340
|
+
await fsp.access(nodeModules);
|
|
341
|
+
return nodeModules;
|
|
342
|
+
} catch {
|
|
343
|
+
// Download and activate below.
|
|
344
|
+
}
|
|
345
|
+
const assetName = `fased-hosted-deps-linux-${arch}-${dependencyHash}.tar.gz`;
|
|
346
|
+
const archive = await downloadVerifiedAsset({
|
|
347
|
+
releaseUrl,
|
|
348
|
+
assetName,
|
|
349
|
+
destinationDir: temporaryRoot,
|
|
350
|
+
timeoutMs,
|
|
351
|
+
});
|
|
352
|
+
await assertArchiveSafe(archive, "node_modules");
|
|
353
|
+
const staging = `${dependencyRoot}.staging-${process.pid}-${Date.now()}`;
|
|
354
|
+
await fsp.rm(staging, { recursive: true, force: true });
|
|
355
|
+
await extractArchive(archive, staging, timeoutMs);
|
|
356
|
+
await fsp.access(path.join(staging, "node_modules"));
|
|
357
|
+
await fsp.mkdir(path.dirname(dependencyRoot), { recursive: true });
|
|
358
|
+
try {
|
|
359
|
+
await fsp.rename(staging, dependencyRoot);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (error?.code !== "EEXIST" && error?.code !== "ENOTEMPTY") {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
await fsp.rm(staging, { recursive: true, force: true });
|
|
365
|
+
}
|
|
366
|
+
await fsp.access(nodeModules);
|
|
367
|
+
return nodeModules;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function smokeRuntime(runtimeRoot, timeoutMs) {
|
|
371
|
+
const temporaryHome = await fsp.mkdtemp(path.join(os.tmpdir(), "fased-managed-smoke-"));
|
|
372
|
+
const env = {
|
|
373
|
+
...process.env,
|
|
374
|
+
HOME: temporaryHome,
|
|
375
|
+
FASED_STATE_DIR: path.join(temporaryHome, ".fased"),
|
|
376
|
+
FASED_CONFIG_PATH: path.join(temporaryHome, ".fased", "fased.json"),
|
|
377
|
+
FASED_RUNTIME_SOURCE: "managed-package",
|
|
378
|
+
};
|
|
379
|
+
try {
|
|
380
|
+
for (const args of [["--version"], ["plugins", "doctor"]]) {
|
|
381
|
+
const result = await runFile(
|
|
382
|
+
process.execPath,
|
|
383
|
+
[path.join(runtimeRoot, "fased.mjs"), ...args],
|
|
384
|
+
{
|
|
385
|
+
env,
|
|
386
|
+
timeoutMs,
|
|
387
|
+
},
|
|
388
|
+
);
|
|
389
|
+
if (!result.ok) {
|
|
390
|
+
throw new Error(`Staged runtime smoke failed: ${(result.stderr || result.stdout).trim()}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
} finally {
|
|
394
|
+
await fsp.rm(temporaryHome, { recursive: true, force: true });
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function readGatewayEndpoint(configPath) {
|
|
399
|
+
try {
|
|
400
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
401
|
+
return {
|
|
402
|
+
port: Number.isInteger(config?.gateway?.port) ? config.gateway.port : 18789,
|
|
403
|
+
tls: config?.gateway?.tls?.enabled === true,
|
|
404
|
+
};
|
|
405
|
+
} catch {
|
|
406
|
+
return { port: 18789, tls: false };
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async function probeGatewayIdentity(configPath, expectedVersion, timeoutMs = 5000) {
|
|
411
|
+
const endpoint = readGatewayEndpoint(configPath);
|
|
412
|
+
const client = endpoint.tls ? https : http;
|
|
413
|
+
return await new Promise((resolve) => {
|
|
414
|
+
const request = client.get(
|
|
415
|
+
{
|
|
416
|
+
hostname: "127.0.0.1",
|
|
417
|
+
port: endpoint.port,
|
|
418
|
+
path: "/healthz",
|
|
419
|
+
timeout: timeoutMs,
|
|
420
|
+
...(endpoint.tls ? { rejectUnauthorized: false } : {}),
|
|
421
|
+
},
|
|
422
|
+
(response) => {
|
|
423
|
+
let body = "";
|
|
424
|
+
response.setEncoding("utf8");
|
|
425
|
+
response.on("data", (chunk) => {
|
|
426
|
+
body += chunk;
|
|
427
|
+
});
|
|
428
|
+
response.on("end", () => {
|
|
429
|
+
try {
|
|
430
|
+
const payload = JSON.parse(body);
|
|
431
|
+
resolve({
|
|
432
|
+
ok:
|
|
433
|
+
response.statusCode === 200 &&
|
|
434
|
+
payload?.version === expectedVersion &&
|
|
435
|
+
new Set(["managed-package", "packaged-runtime"]).has(payload?.runtimeSource),
|
|
436
|
+
payload,
|
|
437
|
+
});
|
|
438
|
+
} catch (error) {
|
|
439
|
+
resolve({ ok: false, error: error.message });
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
);
|
|
444
|
+
request.on("timeout", () => request.destroy(new Error("Gateway probe timed out")));
|
|
445
|
+
request.on("error", (error) => resolve({ ok: false, error: error.message }));
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async function refreshGateway(runtimeRoot, manifest, timeoutMs) {
|
|
450
|
+
const cli = path.join(runtimeRoot, "fased.mjs");
|
|
451
|
+
const env = {
|
|
452
|
+
...process.env,
|
|
453
|
+
FASED_STATE_DIR: manifest.stateDir,
|
|
454
|
+
FASED_CONFIG_PATH: manifest.configPath,
|
|
455
|
+
FASED_MANAGED_INSTALL_MANIFEST: path.join(manifest.stateDir, "install.json"),
|
|
456
|
+
FASED_MANAGED_RUNTIME_ROOT: runtimeRoot,
|
|
457
|
+
FASED_RUNTIME_SOURCE: "managed-package",
|
|
458
|
+
};
|
|
459
|
+
const installArgs = [cli, "gateway", "install", "--force"];
|
|
460
|
+
if (manifest.profile === "hosting") {
|
|
461
|
+
installArgs.push("--system");
|
|
462
|
+
}
|
|
463
|
+
const installed = await runFile(process.execPath, installArgs, { env, timeoutMs });
|
|
464
|
+
if (!installed.ok) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
`Gateway service installation failed: ${(installed.stderr || installed.stdout).trim()}`,
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
const restarted = await runFile(process.execPath, [cli, "gateway", "restart"], {
|
|
470
|
+
env,
|
|
471
|
+
timeoutMs,
|
|
472
|
+
});
|
|
473
|
+
if (!restarted.ok) {
|
|
474
|
+
throw new Error(`Gateway restart failed: ${(restarted.stderr || restarted.stdout).trim()}`);
|
|
475
|
+
}
|
|
476
|
+
const deadline = Date.now() + Math.min(timeoutMs, 60_000);
|
|
477
|
+
let last = null;
|
|
478
|
+
while (Date.now() < deadline) {
|
|
479
|
+
last = await probeGatewayIdentity(manifest.configPath, manifest.runtime.activeVersion, 3000);
|
|
480
|
+
if (last.ok) {
|
|
481
|
+
const plugins = await runFile(process.execPath, [cli, "plugins", "doctor"], {
|
|
482
|
+
env,
|
|
483
|
+
timeoutMs: Math.min(timeoutMs, 60_000),
|
|
484
|
+
});
|
|
485
|
+
if (!plugins.ok) {
|
|
486
|
+
throw new Error(`Plugin verification failed: ${(plugins.stderr || plugins.stdout).trim()}`);
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
491
|
+
}
|
|
492
|
+
throw new Error(
|
|
493
|
+
`Gateway did not report runtime v${manifest.runtime.activeVersion}: ${JSON.stringify(last?.payload || last?.error || null)}`,
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async function replaceCompatibilityLink(paths) {
|
|
498
|
+
const target = paths.compatibilityPackageRoot;
|
|
499
|
+
await fsp.mkdir(path.dirname(target), { recursive: true });
|
|
500
|
+
try {
|
|
501
|
+
const stat = await fsp.lstat(target);
|
|
502
|
+
if (stat.isSymbolicLink()) {
|
|
503
|
+
await fsp.rm(target, { force: true });
|
|
504
|
+
} else {
|
|
505
|
+
throw new Error(`Compatibility package root is not installer-owned: ${target}`);
|
|
506
|
+
}
|
|
507
|
+
} catch (error) {
|
|
508
|
+
if (error?.code !== "ENOENT") {
|
|
509
|
+
throw error;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
await atomicSymlink(paths.currentLink, target);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function updateStableComponents(paths, runtimeRoot) {
|
|
516
|
+
const scripts = path.join(runtimeRoot, "scripts");
|
|
517
|
+
await copyExecutable(path.join(scripts, "fased-managed-launcher.sh"), paths.launcherPath);
|
|
518
|
+
await copyExecutable(path.join(scripts, "fased-managed-service.sh"), paths.serviceLauncherPath);
|
|
519
|
+
await copyExecutable(
|
|
520
|
+
path.join(scripts, "managed-runtime-layout.mjs"),
|
|
521
|
+
path.join(paths.updaterDir, "managed-runtime-layout.mjs"),
|
|
522
|
+
);
|
|
523
|
+
await copyExecutable(path.join(scripts, "fased-managed-updater.mjs"), paths.updaterPath);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async function acquireUpdateLock(stateDir) {
|
|
527
|
+
const lockPath = path.join(stateDir, "update.lock");
|
|
528
|
+
await fsp.mkdir(stateDir, { recursive: true });
|
|
529
|
+
try {
|
|
530
|
+
const handle = await fsp.open(lockPath, "wx", 0o600);
|
|
531
|
+
await handle.writeFile(
|
|
532
|
+
`${JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() })}\n`,
|
|
533
|
+
);
|
|
534
|
+
await handle.close();
|
|
535
|
+
} catch (error) {
|
|
536
|
+
if (error?.code !== "EEXIST") {
|
|
537
|
+
throw error;
|
|
538
|
+
}
|
|
539
|
+
let active = false;
|
|
540
|
+
try {
|
|
541
|
+
const existing = JSON.parse(await fsp.readFile(lockPath, "utf8"));
|
|
542
|
+
if (Number.isInteger(existing.pid)) {
|
|
543
|
+
process.kill(existing.pid, 0);
|
|
544
|
+
active = true;
|
|
545
|
+
}
|
|
546
|
+
} catch {
|
|
547
|
+
active = false;
|
|
548
|
+
}
|
|
549
|
+
if (active) {
|
|
550
|
+
throw new Error(`Another Fased update is already running (${lockPath}).`, {
|
|
551
|
+
cause: error,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
await fsp.rm(lockPath, { force: true });
|
|
555
|
+
return await acquireUpdateLock(stateDir);
|
|
556
|
+
}
|
|
557
|
+
return async () => await fsp.rm(lockPath, { force: true });
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async function delegateToRuntime(args, paths) {
|
|
561
|
+
const currentRoot = await resolveLinkTarget(paths.currentLink);
|
|
562
|
+
if (!currentRoot) {
|
|
563
|
+
throw new Error("Managed runtime is missing; run the official repair installer once.");
|
|
564
|
+
}
|
|
565
|
+
const result = await runFile(process.execPath, [path.join(currentRoot, "fased.mjs"), ...args], {
|
|
566
|
+
env: {
|
|
567
|
+
...process.env,
|
|
568
|
+
FASED_MANAGED_RUNTIME_ROOT: currentRoot,
|
|
569
|
+
FASED_RUNTIME_SOURCE: "managed-package",
|
|
570
|
+
},
|
|
571
|
+
});
|
|
572
|
+
process.stdout.write(result.stdout);
|
|
573
|
+
process.stderr.write(result.stderr);
|
|
574
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
async function cleanupReleases(paths, keepRoots) {
|
|
578
|
+
const keep = new Set(keepRoots.filter(Boolean).map((value) => path.resolve(value)));
|
|
579
|
+
const entries = await fsp.readdir(paths.releasesDir, { withFileTypes: true }).catch(() => []);
|
|
580
|
+
for (const entry of entries) {
|
|
581
|
+
if (
|
|
582
|
+
!entry.isDirectory() ||
|
|
583
|
+
!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?(?:\.repair-\d+-\d+)?$/.test(
|
|
584
|
+
entry.name,
|
|
585
|
+
)
|
|
586
|
+
) {
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
const target = path.join(paths.releasesDir, entry.name);
|
|
590
|
+
if (!keep.has(path.resolve(target))) {
|
|
591
|
+
await fsp.rm(target, { recursive: true, force: true });
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
async function updateManagedRuntime(options) {
|
|
597
|
+
const commandStartedAt = Date.now();
|
|
598
|
+
const timings = [];
|
|
599
|
+
const paths = resolveManagedRuntimePaths();
|
|
600
|
+
const existingManifest = readManagedInstallManifest(paths.manifestPath);
|
|
601
|
+
if (!existingManifest) {
|
|
602
|
+
throw new Error(
|
|
603
|
+
"Managed installation manifest is missing; run the official repair installer once.",
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
const currentRoot = await resolveLinkTarget(paths.currentLink);
|
|
607
|
+
const currentVersion = currentRoot
|
|
608
|
+
? (await readPackageVersion(currentRoot)) || existingManifest.runtime.activeVersion
|
|
609
|
+
: existingManifest.runtime.activeVersion;
|
|
610
|
+
const targetVersion = await measureStage(timings, "release resolution", () =>
|
|
611
|
+
resolveTargetVersion(options),
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
if (options.status || options.dryRun) {
|
|
615
|
+
const available = compareVersions(currentVersion, targetVersion) === -1;
|
|
616
|
+
const result = {
|
|
617
|
+
install: `managed ${existingManifest.profile}`,
|
|
618
|
+
currentVersion,
|
|
619
|
+
targetVersion,
|
|
620
|
+
available,
|
|
621
|
+
dryRun: options.dryRun,
|
|
622
|
+
updaterVersion: existingManifest.updater?.version || "unknown",
|
|
623
|
+
};
|
|
624
|
+
if (options.json) {
|
|
625
|
+
console.log(JSON.stringify({ ok: true, ...result }));
|
|
626
|
+
} else {
|
|
627
|
+
console.log("Fased Agent update status\n");
|
|
628
|
+
console.log(`Install: managed ${existingManifest.profile}`);
|
|
629
|
+
console.log(`Current: ${currentVersion}`);
|
|
630
|
+
console.log(`Target: ${targetVersion}`);
|
|
631
|
+
console.log(available ? `Update available: ${targetVersion}` : "Update: current");
|
|
632
|
+
if (options.dryRun && available) {
|
|
633
|
+
console.log("Action: verified artifact transaction with Gateway health rollback");
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const releaseLock = await acquireUpdateLock(paths.stateDir);
|
|
640
|
+
try {
|
|
641
|
+
const comparison = compareVersions(currentVersion, targetVersion);
|
|
642
|
+
let repairCurrentFiles = false;
|
|
643
|
+
if (comparison === 0) {
|
|
644
|
+
try {
|
|
645
|
+
if (!currentRoot) {
|
|
646
|
+
throw new Error("current runtime link is missing");
|
|
647
|
+
}
|
|
648
|
+
await assertManagedRuntime(currentRoot, currentVersion);
|
|
649
|
+
} catch {
|
|
650
|
+
repairCurrentFiles = true;
|
|
651
|
+
}
|
|
652
|
+
if (!repairCurrentFiles) {
|
|
653
|
+
const identity = await probeGatewayIdentity(
|
|
654
|
+
existingManifest.configPath,
|
|
655
|
+
currentVersion,
|
|
656
|
+
2000,
|
|
657
|
+
);
|
|
658
|
+
if (!identity.ok && options.restart && currentRoot) {
|
|
659
|
+
await refreshGateway(currentRoot, existingManifest, options.timeoutMs);
|
|
660
|
+
} else if (!identity.ok && !options.restart) {
|
|
661
|
+
throw new Error("Installed files are current, but Gateway runtime identity is stale.");
|
|
662
|
+
}
|
|
663
|
+
if (options.json) {
|
|
664
|
+
console.log(JSON.stringify({ ok: true, alreadyCurrent: true, current: currentVersion }));
|
|
665
|
+
} else {
|
|
666
|
+
console.log(`Already current: ${currentVersion}`);
|
|
667
|
+
}
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (!repairCurrentFiles && comparison === 1) {
|
|
672
|
+
throw new Error(
|
|
673
|
+
`Refusing to downgrade managed runtime from ${currentVersion} to ${targetVersion} without an explicit release recovery workflow.`,
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
if (!options.restart) {
|
|
677
|
+
throw new Error(
|
|
678
|
+
"Managed transactional updates require service restart and health verification.",
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const arch = resolveArchitecture();
|
|
683
|
+
const baseUrl = (
|
|
684
|
+
process.env.FASED_HOSTED_ARTIFACT_BASE_URL || DEFAULT_RELEASE_BASE_URL
|
|
685
|
+
).replace(/\/$/, "");
|
|
686
|
+
const releaseUrl = `${baseUrl}/v${targetVersion}`;
|
|
687
|
+
const updateCacheRoot = path.join(paths.stateDir, "install-cache");
|
|
688
|
+
await fsp.mkdir(updateCacheRoot, { recursive: true });
|
|
689
|
+
const temporaryRoot = await fsp.mkdtemp(
|
|
690
|
+
path.join(updateCacheRoot, `managed-update-${targetVersion}-`),
|
|
691
|
+
);
|
|
692
|
+
let activated = false;
|
|
693
|
+
let previousRoot = currentRoot;
|
|
694
|
+
let previousManifest = existingManifest;
|
|
695
|
+
try {
|
|
696
|
+
const assetName = `fased-hosted-app-linux-${arch}-v${targetVersion}.tar.gz`;
|
|
697
|
+
const archive = await measureStage(timings, "application download and checksum", () =>
|
|
698
|
+
downloadVerifiedAsset({
|
|
699
|
+
releaseUrl,
|
|
700
|
+
assetName,
|
|
701
|
+
destinationDir: temporaryRoot,
|
|
702
|
+
timeoutMs: options.timeoutMs,
|
|
703
|
+
}),
|
|
704
|
+
);
|
|
705
|
+
await measureStage(timings, "application archive verification", () =>
|
|
706
|
+
assertArchiveSafe(archive, "package"),
|
|
707
|
+
);
|
|
708
|
+
const extracted = path.join(temporaryRoot, "extract");
|
|
709
|
+
await measureStage(timings, "application extraction", () =>
|
|
710
|
+
extractArchive(archive, extracted, options.timeoutMs),
|
|
711
|
+
);
|
|
712
|
+
const stagedRoot = path.join(extracted, "package");
|
|
713
|
+
const metadata = await readHostedRuntimeMetadata(stagedRoot);
|
|
714
|
+
if (!metadata) {
|
|
715
|
+
throw new Error("Hosted app metadata is missing or invalid.");
|
|
716
|
+
}
|
|
717
|
+
const nodeModules = await measureStage(timings, "dependency layer", () =>
|
|
718
|
+
ensureDependencyLayer({
|
|
719
|
+
dependencyHash: metadata.dependencyHash,
|
|
720
|
+
releaseUrl,
|
|
721
|
+
arch,
|
|
722
|
+
paths,
|
|
723
|
+
temporaryRoot,
|
|
724
|
+
timeoutMs: options.timeoutMs,
|
|
725
|
+
}),
|
|
726
|
+
);
|
|
727
|
+
await fsp.symlink(nodeModules, path.join(stagedRoot, "node_modules"), "dir");
|
|
728
|
+
await assertManagedRuntime(stagedRoot, targetVersion);
|
|
729
|
+
await measureStage(timings, "staged runtime smoke", () =>
|
|
730
|
+
smokeRuntime(stagedRoot, options.timeoutMs),
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
let releaseRoot = path.join(paths.releasesDir, targetVersion);
|
|
734
|
+
if (repairCurrentFiles) {
|
|
735
|
+
releaseRoot = path.join(
|
|
736
|
+
paths.releasesDir,
|
|
737
|
+
`${targetVersion}.repair-${Date.now()}-${process.pid}`,
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
const releaseExists = await fsp
|
|
741
|
+
.lstat(releaseRoot)
|
|
742
|
+
.then(() => true)
|
|
743
|
+
.catch(() => false);
|
|
744
|
+
if (releaseExists) {
|
|
745
|
+
try {
|
|
746
|
+
await assertManagedRuntime(releaseRoot, targetVersion);
|
|
747
|
+
} catch {
|
|
748
|
+
await fsp.rm(releaseRoot, { recursive: true, force: true });
|
|
749
|
+
await fsp.rename(stagedRoot, releaseRoot);
|
|
750
|
+
}
|
|
751
|
+
} else {
|
|
752
|
+
await fsp.mkdir(paths.releasesDir, { recursive: true });
|
|
753
|
+
await fsp.rename(stagedRoot, releaseRoot);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const nextManifest = buildManagedInstallManifest({
|
|
757
|
+
paths,
|
|
758
|
+
profile: existingManifest.profile,
|
|
759
|
+
version: targetVersion,
|
|
760
|
+
dependencyHash: metadata.dependencyHash,
|
|
761
|
+
previousVersion: currentVersion,
|
|
762
|
+
});
|
|
763
|
+
await measureStage(timings, "runtime activation", async () => {
|
|
764
|
+
if (previousRoot && path.resolve(previousRoot) !== path.resolve(releaseRoot)) {
|
|
765
|
+
await atomicSymlink(previousRoot, paths.previousLink);
|
|
766
|
+
}
|
|
767
|
+
await atomicSymlink(releaseRoot, paths.currentLink);
|
|
768
|
+
await replaceCompatibilityLink(paths);
|
|
769
|
+
await atomicWriteJson(paths.manifestPath, nextManifest, 0o600);
|
|
770
|
+
});
|
|
771
|
+
activated = true;
|
|
772
|
+
|
|
773
|
+
try {
|
|
774
|
+
await measureStage(timings, "Gateway refresh and health", () =>
|
|
775
|
+
refreshGateway(releaseRoot, nextManifest, options.timeoutMs),
|
|
776
|
+
);
|
|
777
|
+
} catch (error) {
|
|
778
|
+
if (previousRoot) {
|
|
779
|
+
await atomicSymlink(previousRoot, paths.currentLink);
|
|
780
|
+
await replaceCompatibilityLink(paths);
|
|
781
|
+
await atomicWriteJson(paths.manifestPath, previousManifest, 0o600);
|
|
782
|
+
await refreshGateway(previousRoot, previousManifest, options.timeoutMs).catch(
|
|
783
|
+
() => undefined,
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
throw new Error(`Update rolled back after health verification failed: ${error.message}`, {
|
|
787
|
+
cause: error,
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
await measureStage(timings, "updater and rollback cleanup", async () => {
|
|
792
|
+
await updateStableComponents(paths, releaseRoot);
|
|
793
|
+
await cleanupReleases(paths, [releaseRoot, previousRoot]);
|
|
794
|
+
});
|
|
795
|
+
timings.push({ name: "total", durationMs: Date.now() - commandStartedAt });
|
|
796
|
+
if (options.json) {
|
|
797
|
+
console.log(
|
|
798
|
+
JSON.stringify({
|
|
799
|
+
ok: true,
|
|
800
|
+
before: currentVersion,
|
|
801
|
+
after: targetVersion,
|
|
802
|
+
mode: repairCurrentFiles ? "managed-artifact-repair" : "managed-artifact-transaction",
|
|
803
|
+
timings,
|
|
804
|
+
}),
|
|
805
|
+
);
|
|
806
|
+
} else {
|
|
807
|
+
console.log(
|
|
808
|
+
repairCurrentFiles
|
|
809
|
+
? `Repaired Fased runtime ${targetVersion}`
|
|
810
|
+
: `Updated Fased ${currentVersion} -> ${targetVersion}`,
|
|
811
|
+
);
|
|
812
|
+
console.log(
|
|
813
|
+
repairCurrentFiles
|
|
814
|
+
? "Update mode: verified same-version artifact repair"
|
|
815
|
+
: "Update mode: managed artifact transaction",
|
|
816
|
+
);
|
|
817
|
+
console.log("Gateway: verified");
|
|
818
|
+
console.log("Timing:");
|
|
819
|
+
for (const timing of timings) {
|
|
820
|
+
console.log(` ${timing.name}: ${formatDuration(timing.durationMs)}`);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
} finally {
|
|
824
|
+
await fsp.rm(temporaryRoot, { recursive: true, force: true });
|
|
825
|
+
if (!activated) {
|
|
826
|
+
const active = readManagedInstallManifest(paths.manifestPath);
|
|
827
|
+
if (active?.runtime?.activeVersion !== currentVersion && previousRoot) {
|
|
828
|
+
await atomicSymlink(previousRoot, paths.currentLink).catch(() => undefined);
|
|
829
|
+
await replaceCompatibilityLink(paths).catch(() => undefined);
|
|
830
|
+
await atomicWriteJson(paths.manifestPath, previousManifest, 0o600).catch(() => undefined);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
} finally {
|
|
835
|
+
await releaseLock();
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
export async function run(argv = process.argv.slice(2)) {
|
|
840
|
+
const parsed = parseArgs(argv);
|
|
841
|
+
const paths = resolveManagedRuntimePaths();
|
|
842
|
+
if (parsed.delegate) {
|
|
843
|
+
await delegateToRuntime(parsed.args, paths);
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const manifest = readManagedInstallManifest(paths.manifestPath);
|
|
847
|
+
if (!manifest) {
|
|
848
|
+
throw new Error(
|
|
849
|
+
"Managed installation manifest is missing; run the official repair installer once.",
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
parsed.options.channel = await resolveConfiguredChannel(parsed.options, manifest.configPath);
|
|
853
|
+
if (parsed.options.channel === "dev") {
|
|
854
|
+
await delegateToRuntime(
|
|
855
|
+
parsed.options.status ? argv : ["update", "--channel", "dev", ...argv.slice(1)],
|
|
856
|
+
paths,
|
|
857
|
+
);
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
await updateManagedRuntime(parsed.options);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
864
|
+
try {
|
|
865
|
+
await run();
|
|
866
|
+
} catch (error) {
|
|
867
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
868
|
+
process.exit(1);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
export const __testing = {
|
|
873
|
+
compareVersions,
|
|
874
|
+
parseArgs,
|
|
875
|
+
resolveArchitecture,
|
|
876
|
+
archiveEntryIsSafe,
|
|
877
|
+
assertArchiveSafe,
|
|
878
|
+
probeGatewayIdentity,
|
|
879
|
+
};
|