@fased/fased 0.1.56 → 0.1.58
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/dist/acp/client.js +2 -2
- package/dist/acp/secret-file.js +2 -2
- package/dist/agents/agent-scope.js +2 -2
- package/dist/agents/apply-patch.js +8 -8
- package/dist/agents/auth-profiles/paths.js +2 -2
- package/dist/agents/auth-profiles/store.js +2 -2
- package/dist/agents/bash-tools.shared.js +2 -2
- package/dist/agents/cli-credentials.js +4 -4
- package/dist/agents/current-model-catalog.js +5 -2
- package/dist/agents/docs-path.js +3 -3
- package/dist/agents/embedded-pi-mcp.js +4 -4
- package/dist/agents/identity-avatar.js +3 -3
- package/dist/agents/identity-file.js +2 -2
- package/dist/agents/model-catalog-snapshot.js +124 -0
- package/dist/agents/model-catalog-status.js +6 -1
- package/dist/agents/openai-codex-app-server.js +35 -10
- package/dist/agents/openai-codex-runtime-component.js +39 -0
- package/dist/agents/pi-embedded-runner/compact.js +1 -1
- package/dist/agents/pi-embedded-runner/extra-params.js +28 -16
- package/dist/agents/pi-embedded-runner/run/attempt.js +1 -1
- package/dist/agents/pi-embedded-runner/session-manager-init.js +5 -20
- package/dist/agents/pi-embedded-subscribe.raw-stream.js +3 -3
- package/dist/agents/pi-extensions/compaction-safeguard.js +3 -3
- package/dist/agents/pi-model-discovery.js +6 -6
- package/dist/agents/pi-project-settings.js +3 -3
- package/dist/agents/provider-extension-catalog-manifest.js +2 -2
- package/dist/agents/sandbox/fs-bridge.js +2 -2
- package/dist/agents/session-dirs.js +4 -4
- package/dist/agents/session-write-lock.js +13 -13
- package/dist/agents/shell-utils.js +5 -5
- package/dist/agents/skills/bundled-dir.js +4 -4
- package/dist/agents/skills/local-loader.js +6 -6
- package/dist/agents/skills/plugin-skills.js +2 -2
- package/dist/agents/skills/workspace.js +13 -13
- package/dist/agents/skills-install-download.js +7 -7
- package/dist/agents/skills-install-plan.js +2 -2
- package/dist/agents/skills-install.js +2 -2
- package/dist/agents/skills-status.js +2 -2
- package/dist/agents/subagent-depth.js +2 -2
- package/dist/agents/system-prompt-params.js +2 -2
- package/dist/agents/tools/session-status-tool.js +1 -1
- package/dist/agents/workspace.js +22 -22
- package/dist/auto-reply/reply/agent-runner-execution.js +2 -2
- package/dist/auto-reply/reply/agent-runner.js +2 -2
- package/dist/auto-reply/reply/commands-export-session.js +7 -7
- package/dist/auto-reply/reply/post-compaction-audit.js +3 -3
- package/dist/auto-reply/reply/post-compaction-context.js +3 -3
- package/dist/auto-reply/reply/session.js +3 -3
- package/dist/auto-reply/skill-commands.js +3 -3
- package/dist/auto-reply/status.js +6 -6
- package/dist/brand.js +1 -1
- package/dist/browser/chrome.executables.js +3 -3
- package/dist/browser/chrome.js +3 -3
- package/dist/browser/chrome.profile-decoration.js +6 -6
- package/dist/browser/profiles-service.js +2 -2
- package/dist/browser/server-context.js +2 -2
- package/dist/browser/trash.js +4 -4
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/canvas-host/server.js +4 -4
- package/dist/capabilities/catalog.js +3 -3
- package/dist/capabilities/install.js +43 -0
- package/dist/channels/plugins/catalog.js +3 -3
- package/dist/cli/browser-cli-extension.js +6 -6
- package/dist/cli/command-format.js +2 -2
- package/dist/cli/components-cli.js +9 -31
- package/dist/cli/cron-cli/register.cron-simple.js +2 -2
- package/dist/cli/dns-cli.js +9 -9
- package/dist/cli/gateway-cli/dev.js +5 -5
- package/dist/cli/gateway-cli/run.js +2 -2
- package/dist/cli/hooks-cli.js +6 -6
- package/dist/cli/lightweight/gateway-runtime-probe.js +2 -2
- package/dist/cli/memory-cli.js +7 -7
- package/dist/cli/nodes-media-utils.js +2 -2
- package/dist/cli/plugins-cli.js +5 -5
- package/dist/cli/secrets-cli.js +3 -3
- package/dist/cli/update-cli/update-command.js +50 -12
- package/dist/cli/windows-argv.js +2 -2
- package/dist/commands/agent.js +1 -1
- package/dist/commands/auth-choice.apply.openai.js +9 -0
- package/dist/commands/auth-choice.apply.plugin-provider.js +1 -1
- package/dist/commands/dashboard-link.js +3 -3
- package/dist/commands/doctor-install.js +5 -5
- package/dist/commands/doctor-memory-search.js +2 -2
- package/dist/commands/doctor-platform-notes.js +2 -2
- package/dist/commands/doctor-sandbox.js +2 -2
- package/dist/commands/doctor-state-integrity.js +23 -23
- package/dist/commands/doctor-workspace.js +3 -3
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/managed-up.js +2 -2
- package/dist/commands/onboard-auth.credentials.js +3 -3
- package/dist/commands/onboard-channels.js +1 -1
- package/dist/commands/onboarding/plugin-install.js +4 -4
- package/dist/commands/sessions-cleanup.js +2 -2
- package/dist/commands/signal-install.js +6 -6
- package/dist/commands/status-all/channels.js +2 -2
- package/dist/commands/wallet.js +47 -47
- package/dist/config/cache-utils.js +2 -2
- package/dist/config/includes.js +5 -5
- package/dist/config/io.js +2 -2
- package/dist/config/paths.js +3 -3
- package/dist/config/sat-runtime-ids.js +3 -3
- package/dist/config/sessions/disk-budget.js +6 -6
- package/dist/config/sessions/paths.js +2 -2
- package/dist/config/sessions/store.js +17 -17
- package/dist/config/sessions/transcript.js +4 -4
- package/dist/config/talk.js +2 -2
- package/dist/control-ui/assets/{app-D7TXyNRi.js → app-CpgQGqe6.js} +1689 -1689
- package/dist/control-ui/assets/{index-BmSBom-w.js → index-DiBBflpv.js} +3 -3
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/cron/service/store.js +2 -2
- package/dist/cron/store.js +6 -6
- package/dist/daemon/systemd-system.js +5 -5
- package/dist/discord/monitor/thread-bindings.state.js +2 -2
- package/dist/extensions/sat-mining/src/sat-bond-layout.js +9 -9
- package/dist/gateway/control-ui-boot-check.js +6 -6
- package/dist/gateway/control-ui-login.js +7 -7
- package/dist/gateway/control-ui.js +9 -9
- package/dist/gateway/hooks-mapping.js +4 -4
- package/dist/gateway/protocol/schema/agents-models-skills.js +43 -1
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +4 -4
- package/dist/gateway/server-methods/chat.js +3 -3
- package/dist/gateway/server-methods/hooks.js +1 -1
- package/dist/gateway/server-methods/models.js +12 -5
- package/dist/gateway/server-methods/plugins-marketplace.js +3 -3
- package/dist/gateway/server-methods/services.js +1 -1
- package/dist/gateway/server-methods/sessions.js +7 -7
- package/dist/gateway/server-methods/usage.js +2 -2
- package/dist/gateway/server.impl.js +3 -3
- package/dist/gateway/session-compaction-checkpoints.js +4 -4
- package/dist/gateway/session-utils.fs.js +24 -24
- package/dist/gateway/session-utils.js +6 -6
- package/dist/gateway/sessions-patch.js +1 -1
- package/dist/hooks/bundled-dir.js +4 -4
- package/dist/hooks/gmail-setup-utils.js +6 -6
- package/dist/hooks/import-url.js +2 -2
- package/dist/hooks/loader.js +4 -4
- package/dist/hooks/workspace.js +7 -7
- package/dist/infra/archive.js +17 -17
- package/dist/infra/boundary-file-read.js +2 -2
- package/dist/infra/boundary-path.js +15 -15
- package/dist/infra/brew.js +2 -2
- package/dist/infra/control-ui-assets.js +14 -14
- package/dist/infra/device-auth-store.js +8 -8
- package/dist/infra/device-identity.js +8 -8
- package/dist/infra/dotenv.js +2 -2
- package/dist/infra/exec-approvals.js +8 -8
- package/dist/infra/exec-command-resolution.js +4 -4
- package/dist/infra/exec-safe-bin-trust.js +2 -2
- package/dist/infra/fased-root.js +5 -5
- package/dist/infra/fs-safe.js +14 -14
- package/dist/infra/gateway-lock.js +11 -11
- package/dist/infra/git-commit.js +5 -5
- package/dist/infra/git-root.js +4 -4
- package/dist/infra/hosted-runtime-artifact.js +3 -3
- package/dist/infra/is-main.js +2 -2
- package/dist/infra/json-file.js +7 -7
- package/dist/infra/outbound/delivery-queue.js +16 -16
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/ports-lsof.js +4 -4
- package/dist/infra/provider-usage.auth.js +3 -3
- package/dist/infra/safe-open-sync.js +2 -2
- package/dist/infra/session-cost-usage.js +9 -9
- package/dist/infra/shell-env.js +2 -2
- package/dist/infra/state-migrations.fs.js +6 -6
- package/dist/infra/state-migrations.js +23 -23
- package/dist/infra/tmp-fased-dir.js +6 -6
- package/dist/infra/widearea-dns.js +3 -3
- package/dist/infra/wsl.js +2 -2
- package/dist/light-update-status.js +11 -11
- package/dist/line/accounts.js +2 -2
- package/dist/line/download.js +2 -2
- package/dist/logging/config.js +3 -3
- package/dist/logging/logger.js +7 -7
- package/dist/managed/federation.js +3 -3
- package/dist/managed/tunnel.js +3 -3
- package/dist/media/store.js +13 -13
- package/dist/media-understanding/runner.js +3 -3
- package/dist/memory/embeddings.js +2 -2
- package/dist/memory/internal.js +10 -10
- package/dist/memory/manager-sync-ops.js +7 -7
- package/dist/memory/repair-executor.js +17 -17
- package/dist/node-host/invoke-system-run-plan.js +8 -8
- package/dist/node-host/invoke.js +2 -2
- package/dist/node-host/runner.js +3 -3
- package/dist/pairing/pairing-store.js +3 -3
- package/dist/plugin-sdk/{accounts-DzWlKv1U.js → accounts-BJuN64m-.js} +1 -1
- package/dist/plugin-sdk/{actions-BplQVLL6.js → actions-DaEvM9Bl.js} +2 -2
- package/dist/plugin-sdk/{active-listener-x4MLhYUw.js → active-listener-B8Kuanet.js} +1 -1
- package/dist/plugin-sdk/{agent-scope-BbgPlhtw.js → agent-scope-CCjfjKoO.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-G8h3Sn8_.js → audio-preflight-D7tCO0EH.js} +31 -31
- package/dist/plugin-sdk/{audit-CWknklvI.js → audit-CVWH4BVP.js} +1 -1
- package/dist/plugin-sdk/{channel-access-a9Dnfw7-.js → channel-access-CH9FAS-I.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-CD4QDN5E.js → channel-access-configure-CI0je66H.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
- package/dist/plugin-sdk/channel-plugin-common.js +5 -5
- package/dist/plugin-sdk/{chunk-B8EZkwiT.js → chunk-01oBnQjh.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-CEPklxGe.js → chunk-items-D2zDJ8q8.js} +1 -1
- package/dist/plugin-sdk/command-status.js +31 -31
- package/dist/plugin-sdk/{commands-registry-BfEa4tFA.js → commands-registry-ckg4fhYa.js} +2 -2
- package/dist/plugin-sdk/{common-CbfckC19.js → common-zHvdO8ly.js} +1 -1
- package/dist/plugin-sdk/{config-Bt5GhnA-.js → config-DrhYEiCM.js} +1128 -3
- package/dist/plugin-sdk/{config-schema-B9DKr6J5.js → config-schema-BtjeV5Hm.js} +1765 -1412
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +3 -3
- package/dist/plugin-sdk/discord.js +22 -22
- package/dist/plugin-sdk/{filesystem-manager-BGGGrkiN.js → filesystem-manager-ZoHU8oA7.js} +2 -2
- package/dist/plugin-sdk/{fs-safe-xBqok6yR.js → fs-safe-g4g7GT02.js} +2 -2
- package/dist/plugin-sdk/{handle-action-DbzZFYnG.js → handle-action-5dhYpMbP.js} +17 -17
- package/dist/plugin-sdk/{helpers-CluGKuIV.js → helpers-E9aafRzA.js} +1 -1
- package/dist/plugin-sdk/{image-ops-CUaLtIFj.js → image-ops-D2U9ctmu.js} +1 -1
- package/dist/plugin-sdk/index.d.ts +5 -5
- package/dist/plugin-sdk/index.js +33 -33
- package/dist/plugin-sdk/json-store.js +6 -6
- package/dist/plugin-sdk/{login-DJuHYDiK.js → login-hql0fNuL.js} +3 -3
- package/dist/plugin-sdk/{login-qr-CbHL5ayf.js → login-qr-DJJ0svux.js} +4 -4
- package/dist/plugin-sdk/{manager-oHAvZCT3.js → manager-ciNnAMBn.js} +4 -4
- package/dist/plugin-sdk/{markdown-tables-Mkx7k92Y.js → markdown-tables-BKxbua_h.js} +1 -1
- package/dist/plugin-sdk/{media-CA8sTmVE.js → media-DUIZ6x9H.js} +4 -4
- package/dist/plugin-sdk/{memory-search-VFll-AIb.js → memory-search-DTjIMw8J.js} +1 -1
- package/dist/plugin-sdk/{monitor-CZrN9pev.js → monitor-CNSGw4uQ.js} +35 -35
- package/dist/plugin-sdk/{monitor-CmwGqNyV.js → monitor-D-giXewh.js} +38 -38
- package/dist/plugin-sdk/{openresponses-http-CWOd4war.js → openresponses-http-dbTd8UMk.js} +31 -31
- package/dist/plugin-sdk/{optional-runtime-dependency-DKmk9PZa.js → optional-runtime-dependency-CKsJL1PD.js} +1 -1
- package/dist/plugin-sdk/{outbound-0oN9IfNw.js → outbound-DhGrjRft.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-DdVkqUzE.js → outbound-attachment-DAF8huFz.js} +2 -2
- package/dist/plugin-sdk/{pairing-message-ClqhfCUk.js → pairing-message-BsJVvXkb.js} +1 -1
- package/dist/plugin-sdk/{pairing-message-BMkkS038.d.ts → pairing-message-C403mq4K.d.ts} +1 -1
- package/dist/plugin-sdk/{pairing-store-B01mCSct.js → pairing-store-DwM-BNbj.js} +2 -2
- package/dist/plugin-sdk/{path-alias-guards-BJZD5JMJ.js → path-alias-guards-DjgDArrp.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-Buz0JC1Y.js → pi-model-discovery-DkIdlJvJ.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DuwuoteY.js → pi-model-discovery-runtime-Cv7okUMt.js} +3 -3
- package/dist/plugin-sdk/{probe--7xtfzMm.js → probe-CJb5uR8B.js} +1 -1
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
- package/dist/plugin-sdk/{pw-ai-B0domrii.js → pw-ai-Dxd87W3J.js} +6 -6
- package/dist/plugin-sdk/{qmd-manager-CFFeM4Fl.js → qmd-manager-DSyx77KY.js} +1 -1
- package/dist/plugin-sdk/{replies-1macZ1mZ.js → replies-Bx61SvAC.js} +2 -2
- package/dist/plugin-sdk/{reply-prefix-ClpxvL_w.js → reply-prefix-CeVw7Mn2.js} +1 -1
- package/dist/plugin-sdk/{probe-xY3Ky0Tx.js → resolve-channels-_-nV-EK2.js} +3 -2
- package/dist/plugin-sdk/{resolve-outbound-target-BdH6LUoW.js → resolve-outbound-target-bc-FpPZg.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-CkNIKKEW.js → resolve-route-D0eBYPtb.js} +2 -2
- package/dist/plugin-sdk/{retry-policy-9ybIh4Fq.js → retry-policy-HTrC4zfC.js} +1 -1
- package/dist/plugin-sdk/{runtime-Dy420wBu.js → runtime-BVkIrYLQ.js} +4 -4
- package/dist/plugin-sdk/{runtime-dependency-CIw9t7-k.js → runtime-dependency-B2PqMdBu.js} +13 -13
- package/dist/plugin-sdk/{sandbox-paths-w64tYl0v.js → sandbox-paths-Dx2lUqCu.js} +2 -2
- package/dist/plugin-sdk/sat-runtime.d.ts +2 -2
- package/dist/plugin-sdk/sat-runtime.js +31 -31
- package/dist/plugin-sdk/{send-J4JWKP62.js → send-BGDGzxUu.js} +6 -6
- package/dist/plugin-sdk/{send-BQUtCJFW.js → send-C3QWSYLR.js} +8 -8
- package/dist/plugin-sdk/{send-Dqes9tdU.js → send-DT2egZNK.js} +7 -7
- package/dist/plugin-sdk/{send-2VcOMTN5.js → send-DgzZUx2i.js} +5 -5
- package/dist/plugin-sdk/{send-DPJIIYAs.js → send-KJy3ajA3.js} +6 -6
- package/dist/plugin-sdk/{session-C_n2S5ub.js → session-BCIEFOu1.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-B7wx9ax8.js → skill-commands-CyIkcR8P.js} +4 -4
- package/dist/plugin-sdk/{slack-BouRQG-W.js → slack-DjKNh2uh.js} +47 -47
- package/dist/plugin-sdk/{slack-actions-CasHVtiq.js → slack-actions-CeM9LWDp.js} +14 -14
- package/dist/plugin-sdk/slack.d.ts +3 -3
- package/dist/plugin-sdk/slack.js +12 -12
- package/dist/plugin-sdk/{sticker-cache-BvGEUas3.js → sticker-cache-DcWzQ2wx.js} +3 -3
- package/dist/plugin-sdk/{tables-CjlQJV4r.js → tables-B2iehyjG.js} +1 -1
- package/dist/plugin-sdk/{targets-QfP164Dh.js → targets-BPket0SF.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-CwYjV6Db.js → telegram-actions-Cx_HWVht.js} +34 -34
- package/dist/plugin-sdk/telegram.d.ts +3 -3
- package/dist/plugin-sdk/telegram.js +9 -9
- package/dist/plugin-sdk/{thread-bindings.lifecycle-DU4iX_Jr.js → thread-bindings.lifecycle-CYH69SIw.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-BgYWFjNF.js → thread-bindings.state-BN6461WG.js} +2 -2
- package/dist/plugin-sdk/{tmp-fased-dir-BdFQvrvw.d.ts → tmp-fased-dir-Ouj58axY.d.ts} +1 -1
- package/dist/plugin-sdk/{types-BYDL6dQj.d.ts → types-B4hj6HgR.d.ts} +1 -1
- package/dist/plugin-sdk/{types-CLIvQaVg.d.ts → types-dWZFX1fk.d.ts} +2 -2
- package/dist/plugin-sdk/{web-D0yENDve.js → web-vR-oNiBv.js} +36 -36
- package/dist/plugin-sdk/{whatsapp-actions-BT2nPLyo.js → whatsapp-actions-BYNf8ceY.js} +16 -16
- package/dist/plugin-sdk/{whatsapp-heartbeat-CiABSZ6G.js → whatsapp-heartbeat-DZwa8MF0.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +3 -3
- package/dist/plugin-sdk/whatsapp.js +13 -13
- package/dist/plugin-sdk/{wsl-B_ojyEtC.js → wsl-WGtdw_6h.js} +3 -3
- package/dist/plugins/bundled-dir.js +3 -3
- package/dist/plugins/discovery.js +11 -11
- package/dist/plugins/lifecycle.js +1 -1
- package/dist/plugins/loader.js +13 -13
- package/dist/plugins/manifest-registry.js +28 -2
- package/dist/plugins/manifest.js +6 -4
- package/dist/plugins/marketplace.js +1 -1
- package/dist/plugins/path-safety.js +3 -3
- package/dist/plugins/status-cache.js +9 -9
- package/dist/plugins/update.js +4 -4
- package/dist/plugins/web-search-install-catalog.js +3 -3
- package/dist/providers/openai-codex-model-discovery.js +11 -1
- package/dist/providers/runtime-model-catalog.js +2 -2
- package/dist/secrets/apply.js +16 -16
- package/dist/secrets/audit.js +11 -11
- package/dist/secrets/shared.js +9 -9
- package/dist/security/scan-paths.js +2 -2
- package/dist/shared/config-eval.js +2 -2
- package/dist/shared/pid-alive.js +2 -2
- package/dist/tasks/standing-orders.js +5 -5
- package/dist/tasks/task-flow-registry.js +5 -5
- package/dist/tasks/task-registry.js +5 -5
- package/dist/tasks/workflow-definitions.js +6 -6
- package/dist/telegram/token.js +5 -5
- package/dist/utils.js +5 -5
- package/dist/wallet/local-socket-signer-broker.js +16 -16
- package/dist/wallet/providers/embedded-keystore-adapter.js +5 -5
- package/dist/wallet/providers/local-socket-signer-adapter.js +2 -2
- package/dist/wallet/wallet-approval-auth.js +5 -5
- package/dist/wallet/wallet-audit-log.js +5 -5
- package/dist/wallet/wallet-custody.js +21 -21
- package/dist/wallet/wallet-inbound-events.js +5 -5
- package/dist/wallet/wallet-observability.js +5 -5
- package/dist/wallet/wallet-policy.js +9 -9
- package/dist/wallet/wallet-provider-registry.js +7 -7
- package/dist/wallet/wallet-runtime-config.js +3 -3
- package/dist/wallet/wallet-secrets-store.js +22 -22
- package/dist/wallet/wallet-send-approvals.js +5 -5
- package/dist/wallet/wallet-settlement-links.js +5 -5
- package/dist/web/accounts.js +3 -3
- package/dist/web/auth-store.js +18 -18
- package/dist/web/session.js +4 -4
- package/dist/wizard/host-security-capability.js +2 -2
- package/dist/wizard/onboarding.finalize.js +1 -1
- package/dist/wizard/onboarding.host-security.js +7 -7
- package/dist/wizard/onboarding.js +7 -7
- package/dist/wizard/onboarding.wallet.js +44 -44
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +12 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +12 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +12 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/dist/plugin-sdk/resolve-channels-CwB2_019.js +0 -4
- /package/dist/plugin-sdk/{resolve-users-Cxb5wpAQ.js → resolve-users-DN9VQBwv.js} +0 -0
|
@@ -2,9 +2,9 @@ import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js";
|
|
|
2
2
|
import { c as CHANNEL_IDS, f as normalizeChatChannelId, t as createSubsystemLogger, u as CORE_RUNTIME_CHANNEL_IDS } from "./subsystem-DBPNbQDQ.js";
|
|
3
3
|
import { c as expandHomePrefix, n as resolveConfigPath, o as resolveOAuthPath, r as resolveDefaultConfigCandidates, s as resolveStateDir, u as resolveRequiredHomeDir } from "./paths-BEmvSyOV.js";
|
|
4
4
|
import { C as isPlainObject$2, c as isRecord$3, h as resolveUserPath, p as resolveConfigDir, t as CONFIG_DIR } from "./utils-CYk9EKoq.js";
|
|
5
|
-
import {
|
|
5
|
+
import { H as resolveAgentModelFallbackValues, I as isNotFoundPathError, L as isPathInside$2, O as resolveFasedAgentPackageRootSync, R as isSymlinkOpenError, U as resolveAgentModelPrimaryValue, V as MAX_AGENT_MODEL_FALLBACKS, W as toAgentModelListLike, i as resolveAgentConfig, j as openBoundaryFileSync, k as canUseBoundaryFileOpen, l as resolveAgentWorkspaceDir, o as resolveAgentEffectiveModelPrimary, u as resolveDefaultAgentId } from "./agent-scope-CCjfjKoO.js";
|
|
6
6
|
import { h as isBlockedObjectKey, s as normalizeAgentId, t as DEFAULT_AGENT_ID } from "./session-key-HSJ2KQTc.js";
|
|
7
|
-
import { n as runExec } from "./exec-DQ8j4Fm3.js";
|
|
7
|
+
import { n as runExec, t as runCommandWithTimeout } from "./exec-DQ8j4Fm3.js";
|
|
8
8
|
import { n as redactSensitiveText } from "./redact-Bm8vu_ju.js";
|
|
9
9
|
import { a as saveJsonFile, i as loadJsonFile, r as resolveCopilotApiToken, t as DEFAULT_COPILOT_API_BASE_URL } from "./github-copilot-token-CUK__1s1.js";
|
|
10
10
|
import { t as runTasksWithConcurrency } from "./run-with-concurrency-BsDJWzgM.js";
|
|
@@ -31,10 +31,64 @@ import AjvPkg from "ajv";
|
|
|
31
31
|
import { z } from "zod";
|
|
32
32
|
|
|
33
33
|
//#region src/plugins/slots.ts
|
|
34
|
+
const SLOT_BY_KIND = { memory: "memory" };
|
|
34
35
|
const DEFAULT_SLOT_BY_KEY = { memory: "memory-core" };
|
|
36
|
+
function slotKeyForPluginKind(kind) {
|
|
37
|
+
if (!kind) return null;
|
|
38
|
+
return SLOT_BY_KIND[kind] ?? null;
|
|
39
|
+
}
|
|
35
40
|
function defaultSlotIdForKey(slotKey) {
|
|
36
41
|
return DEFAULT_SLOT_BY_KEY[slotKey];
|
|
37
42
|
}
|
|
43
|
+
function applyExclusiveSlotSelection(params) {
|
|
44
|
+
const slotKey = slotKeyForPluginKind(params.selectedKind);
|
|
45
|
+
if (!slotKey) return {
|
|
46
|
+
config: params.config,
|
|
47
|
+
warnings: [],
|
|
48
|
+
changed: false
|
|
49
|
+
};
|
|
50
|
+
const warnings = [];
|
|
51
|
+
const pluginsConfig = params.config.plugins ?? {};
|
|
52
|
+
const prevSlot = pluginsConfig.slots?.[slotKey];
|
|
53
|
+
const slots = {
|
|
54
|
+
...pluginsConfig.slots,
|
|
55
|
+
[slotKey]: params.selectedId
|
|
56
|
+
};
|
|
57
|
+
const inferredPrevSlot = prevSlot ?? defaultSlotIdForKey(slotKey);
|
|
58
|
+
if (inferredPrevSlot && inferredPrevSlot !== params.selectedId) warnings.push(`Exclusive slot "${slotKey}" switched from "${inferredPrevSlot}" to "${params.selectedId}".`);
|
|
59
|
+
const entries = { ...pluginsConfig.entries };
|
|
60
|
+
const disabledIds = [];
|
|
61
|
+
if (params.registry) for (const plugin of params.registry.plugins) {
|
|
62
|
+
if (plugin.id === params.selectedId) continue;
|
|
63
|
+
if (plugin.kind !== params.selectedKind) continue;
|
|
64
|
+
const entry = entries[plugin.id];
|
|
65
|
+
if (!entry || entry.enabled !== false) {
|
|
66
|
+
entries[plugin.id] = {
|
|
67
|
+
...entry,
|
|
68
|
+
enabled: false
|
|
69
|
+
};
|
|
70
|
+
disabledIds.push(plugin.id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (disabledIds.length > 0) warnings.push(`Disabled other "${slotKey}" slot plugins: ${disabledIds.toSorted().join(", ")}.`);
|
|
74
|
+
if (!(prevSlot !== params.selectedId || disabledIds.length > 0)) return {
|
|
75
|
+
config: params.config,
|
|
76
|
+
warnings: [],
|
|
77
|
+
changed: false
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
config: {
|
|
81
|
+
...params.config,
|
|
82
|
+
plugins: {
|
|
83
|
+
...pluginsConfig,
|
|
84
|
+
slots,
|
|
85
|
+
entries
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
warnings,
|
|
89
|
+
changed: true
|
|
90
|
+
};
|
|
91
|
+
}
|
|
38
92
|
|
|
39
93
|
//#endregion
|
|
40
94
|
//#region src/plugins/config-state.ts
|
|
@@ -1216,6 +1270,17 @@ function resolveArchiveKind(filePath) {
|
|
|
1216
1270
|
if (TAR_SUFFIXES.some((suffix) => lower.endsWith(suffix))) return "tar";
|
|
1217
1271
|
return null;
|
|
1218
1272
|
}
|
|
1273
|
+
async function resolvePackedRootDir(extractDir) {
|
|
1274
|
+
const direct = path.join(extractDir, "package");
|
|
1275
|
+
try {
|
|
1276
|
+
if ((await fs$1.stat(direct)).isDirectory()) return direct;
|
|
1277
|
+
} catch {}
|
|
1278
|
+
const dirs = (await fs$1.readdir(extractDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1279
|
+
if (dirs.length !== 1) throw new Error(`unexpected archive layout (dirs: ${dirs.join(", ")})`);
|
|
1280
|
+
const onlyDir = dirs[0];
|
|
1281
|
+
if (!onlyDir) throw new Error("unexpected archive layout (no package dir found)");
|
|
1282
|
+
return path.join(extractDir, onlyDir);
|
|
1283
|
+
}
|
|
1219
1284
|
async function withTimeout(promise, timeoutMs, label) {
|
|
1220
1285
|
let timeoutId;
|
|
1221
1286
|
try {
|
|
@@ -1473,9 +1538,351 @@ async function extractArchive(params) {
|
|
|
1473
1538
|
limits: params.limits
|
|
1474
1539
|
}), params.timeoutMs, label);
|
|
1475
1540
|
}
|
|
1541
|
+
async function fileExists(filePath) {
|
|
1542
|
+
try {
|
|
1543
|
+
await fs$1.stat(filePath);
|
|
1544
|
+
return true;
|
|
1545
|
+
} catch {
|
|
1546
|
+
return false;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
async function readJsonFile(filePath) {
|
|
1550
|
+
const raw = await fs$1.readFile(filePath, "utf-8");
|
|
1551
|
+
return JSON.parse(raw);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
//#endregion
|
|
1555
|
+
//#region src/infra/install-source-utils.ts
|
|
1556
|
+
async function withTempDir(prefix, fn) {
|
|
1557
|
+
const tmpDir = await fs$1.mkdtemp(path.join(os.tmpdir(), prefix));
|
|
1558
|
+
try {
|
|
1559
|
+
return await fn(tmpDir);
|
|
1560
|
+
} finally {
|
|
1561
|
+
await fs$1.rm(tmpDir, {
|
|
1562
|
+
recursive: true,
|
|
1563
|
+
force: true
|
|
1564
|
+
}).catch(() => void 0);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
async function resolveArchiveSourcePath(archivePath) {
|
|
1568
|
+
const resolved = resolveUserPath(archivePath);
|
|
1569
|
+
if (!await fileExists(resolved)) return {
|
|
1570
|
+
ok: false,
|
|
1571
|
+
error: `archive not found: ${resolved}`
|
|
1572
|
+
};
|
|
1573
|
+
if (!resolveArchiveKind(resolved)) return {
|
|
1574
|
+
ok: false,
|
|
1575
|
+
error: `unsupported archive: ${resolved}`
|
|
1576
|
+
};
|
|
1577
|
+
return {
|
|
1578
|
+
ok: true,
|
|
1579
|
+
path: resolved
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
function toOptionalString(value) {
|
|
1583
|
+
if (typeof value !== "string") return;
|
|
1584
|
+
const trimmed = value.trim();
|
|
1585
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1586
|
+
}
|
|
1587
|
+
function parseResolvedSpecFromId(id) {
|
|
1588
|
+
const at = id.lastIndexOf("@");
|
|
1589
|
+
if (at <= 0 || at >= id.length - 1) return;
|
|
1590
|
+
const name = id.slice(0, at).trim();
|
|
1591
|
+
const version = id.slice(at + 1).trim();
|
|
1592
|
+
if (!name || !version) return;
|
|
1593
|
+
return `${name}@${version}`;
|
|
1594
|
+
}
|
|
1595
|
+
function normalizeNpmPackEntry(entry) {
|
|
1596
|
+
if (!entry || typeof entry !== "object") return null;
|
|
1597
|
+
const rec = entry;
|
|
1598
|
+
const name = toOptionalString(rec.name);
|
|
1599
|
+
const version = toOptionalString(rec.version);
|
|
1600
|
+
const id = toOptionalString(rec.id);
|
|
1601
|
+
const resolvedSpec = (name && version ? `${name}@${version}` : void 0) ?? (id ? parseResolvedSpecFromId(id) : void 0);
|
|
1602
|
+
return {
|
|
1603
|
+
filename: toOptionalString(rec.filename),
|
|
1604
|
+
metadata: {
|
|
1605
|
+
name,
|
|
1606
|
+
version,
|
|
1607
|
+
resolvedSpec,
|
|
1608
|
+
integrity: toOptionalString(rec.integrity),
|
|
1609
|
+
shasum: toOptionalString(rec.shasum)
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
function parseNpmPackJsonOutput(raw) {
|
|
1614
|
+
const trimmed = raw.trim();
|
|
1615
|
+
if (!trimmed) return null;
|
|
1616
|
+
const candidates = [trimmed];
|
|
1617
|
+
const arrayStart = trimmed.indexOf("[");
|
|
1618
|
+
if (arrayStart > 0) candidates.push(trimmed.slice(arrayStart));
|
|
1619
|
+
for (const candidate of candidates) {
|
|
1620
|
+
let parsed;
|
|
1621
|
+
try {
|
|
1622
|
+
parsed = JSON.parse(candidate);
|
|
1623
|
+
} catch {
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
const entries = Array.isArray(parsed) ? parsed : [parsed];
|
|
1627
|
+
let fallback = null;
|
|
1628
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
1629
|
+
const normalized = normalizeNpmPackEntry(entries[i]);
|
|
1630
|
+
if (!normalized) continue;
|
|
1631
|
+
if (!fallback) fallback = normalized;
|
|
1632
|
+
if (normalized.filename) return normalized;
|
|
1633
|
+
}
|
|
1634
|
+
if (fallback) return fallback;
|
|
1635
|
+
}
|
|
1636
|
+
return null;
|
|
1637
|
+
}
|
|
1638
|
+
function parsePackedArchiveFromStdout(stdout) {
|
|
1639
|
+
const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1640
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
1641
|
+
const match = lines[index]?.match(/([^\s"']+\.tgz)/);
|
|
1642
|
+
if (match?.[1]) return match[1];
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
async function findPackedArchiveInDir(cwd) {
|
|
1646
|
+
const archives = (await fs$1.readdir(cwd, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isFile() && entry.name.endsWith(".tgz"));
|
|
1647
|
+
if (archives.length === 0) return;
|
|
1648
|
+
if (archives.length === 1) return archives[0]?.name;
|
|
1649
|
+
const sortedByMtime = await Promise.all(archives.map(async (entry) => ({
|
|
1650
|
+
name: entry.name,
|
|
1651
|
+
mtimeMs: (await fs$1.stat(path.join(cwd, entry.name))).mtimeMs
|
|
1652
|
+
})));
|
|
1653
|
+
sortedByMtime.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
1654
|
+
return sortedByMtime[0]?.name;
|
|
1655
|
+
}
|
|
1656
|
+
async function packNpmSpecToArchive(params) {
|
|
1657
|
+
const res = await runCommandWithTimeout([
|
|
1658
|
+
"npm",
|
|
1659
|
+
"pack",
|
|
1660
|
+
params.spec,
|
|
1661
|
+
"--ignore-scripts",
|
|
1662
|
+
"--json"
|
|
1663
|
+
], {
|
|
1664
|
+
timeoutMs: Math.max(params.timeoutMs, 3e5),
|
|
1665
|
+
cwd: params.cwd,
|
|
1666
|
+
env: {
|
|
1667
|
+
COREPACK_ENABLE_DOWNLOAD_PROMPT: "0",
|
|
1668
|
+
NPM_CONFIG_IGNORE_SCRIPTS: "true"
|
|
1669
|
+
}
|
|
1670
|
+
});
|
|
1671
|
+
if (res.code !== 0) {
|
|
1672
|
+
const raw = res.stderr.trim() || res.stdout.trim();
|
|
1673
|
+
if (/E404|is not in this registry/i.test(raw)) return {
|
|
1674
|
+
ok: false,
|
|
1675
|
+
error: `Package not found on npm: ${params.spec}. See https://docs.fased.ai/tools/plugin for installable plugins.`
|
|
1676
|
+
};
|
|
1677
|
+
return {
|
|
1678
|
+
ok: false,
|
|
1679
|
+
error: `npm pack failed: ${raw}`
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
const parsedJson = parseNpmPackJsonOutput(res.stdout || "");
|
|
1683
|
+
let packed = parsedJson?.filename ?? parsePackedArchiveFromStdout(res.stdout || "");
|
|
1684
|
+
if (!packed) packed = await findPackedArchiveInDir(params.cwd);
|
|
1685
|
+
if (!packed) return {
|
|
1686
|
+
ok: false,
|
|
1687
|
+
error: "npm pack produced no archive"
|
|
1688
|
+
};
|
|
1689
|
+
let archivePath = path.isAbsolute(packed) ? packed : path.join(params.cwd, packed);
|
|
1690
|
+
if (!await fileExists(archivePath)) {
|
|
1691
|
+
const fallbackPacked = await findPackedArchiveInDir(params.cwd);
|
|
1692
|
+
if (!fallbackPacked) return {
|
|
1693
|
+
ok: false,
|
|
1694
|
+
error: "npm pack produced no archive"
|
|
1695
|
+
};
|
|
1696
|
+
archivePath = path.join(params.cwd, fallbackPacked);
|
|
1697
|
+
}
|
|
1698
|
+
return {
|
|
1699
|
+
ok: true,
|
|
1700
|
+
archivePath,
|
|
1701
|
+
metadata: parsedJson?.metadata ?? {}
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
//#endregion
|
|
1706
|
+
//#region src/infra/install-flow.ts
|
|
1707
|
+
async function withExtractedArchiveRoot(params) {
|
|
1708
|
+
return await withTempDir(params.tempDirPrefix, async (tmpDir) => {
|
|
1709
|
+
const extractDir = path.join(tmpDir, "extract");
|
|
1710
|
+
await fs$1.mkdir(extractDir, { recursive: true });
|
|
1711
|
+
params.logger?.info?.(`Extracting ${params.archivePath}…`);
|
|
1712
|
+
try {
|
|
1713
|
+
await extractArchive({
|
|
1714
|
+
archivePath: params.archivePath,
|
|
1715
|
+
destDir: extractDir,
|
|
1716
|
+
timeoutMs: params.timeoutMs,
|
|
1717
|
+
logger: params.logger
|
|
1718
|
+
});
|
|
1719
|
+
} catch (err) {
|
|
1720
|
+
return {
|
|
1721
|
+
ok: false,
|
|
1722
|
+
error: `failed to extract archive: ${String(err)}`
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
let rootDir = "";
|
|
1726
|
+
try {
|
|
1727
|
+
rootDir = await resolveInstallRootDir(extractDir, params.rootMarkers);
|
|
1728
|
+
} catch (err) {
|
|
1729
|
+
return {
|
|
1730
|
+
ok: false,
|
|
1731
|
+
error: String(err)
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
return await params.onExtracted(rootDir);
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
async function hasAnyRootMarker(rootDir, rootMarkers) {
|
|
1738
|
+
for (const marker of rootMarkers) {
|
|
1739
|
+
if (!marker || path.isAbsolute(marker) || marker.includes("..")) continue;
|
|
1740
|
+
if (await fileExists(path.join(rootDir, marker))) return true;
|
|
1741
|
+
}
|
|
1742
|
+
return false;
|
|
1743
|
+
}
|
|
1744
|
+
async function resolveInstallRootDir(extractDir, rootMarkers) {
|
|
1745
|
+
const markers = rootMarkers?.filter(Boolean) ?? [];
|
|
1746
|
+
if (markers.length === 0) return await resolvePackedRootDir(extractDir);
|
|
1747
|
+
if (await hasAnyRootMarker(extractDir, markers)) return extractDir;
|
|
1748
|
+
const entries = await fs$1.readdir(extractDir, { withFileTypes: true });
|
|
1749
|
+
const markerDirs = [];
|
|
1750
|
+
for (const entry of entries) {
|
|
1751
|
+
if (!entry.isDirectory()) continue;
|
|
1752
|
+
if (await hasAnyRootMarker(path.join(extractDir, entry.name), markers)) markerDirs.push(entry.name);
|
|
1753
|
+
}
|
|
1754
|
+
if (markerDirs.length === 1) return path.join(extractDir, markerDirs[0]);
|
|
1755
|
+
if (markerDirs.length > 1) throw new Error(`unexpected archive layout (marker dirs: ${markerDirs.join(", ")})`);
|
|
1756
|
+
return await resolvePackedRootDir(extractDir);
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
//#endregion
|
|
1760
|
+
//#region src/infra/install-mode-options.ts
|
|
1761
|
+
function resolveInstallModeOptions(params, defaultLogger) {
|
|
1762
|
+
return {
|
|
1763
|
+
logger: params.logger ?? defaultLogger,
|
|
1764
|
+
mode: params.mode ?? "install",
|
|
1765
|
+
dryRun: params.dryRun ?? false
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
function resolveTimedInstallModeOptions(params, defaultLogger, defaultTimeoutMs = 12e4) {
|
|
1769
|
+
return {
|
|
1770
|
+
...resolveInstallModeOptions(params, defaultLogger),
|
|
1771
|
+
timeoutMs: params.timeoutMs ?? defaultTimeoutMs
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
//#endregion
|
|
1776
|
+
//#region src/infra/install-package-dir.ts
|
|
1777
|
+
function isObjectRecord(value) {
|
|
1778
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1779
|
+
}
|
|
1780
|
+
async function sanitizeManifestForNpmInstall(targetDir) {
|
|
1781
|
+
const manifestPath = path.join(targetDir, "package.json");
|
|
1782
|
+
let manifestRaw = "";
|
|
1783
|
+
try {
|
|
1784
|
+
manifestRaw = await fs$1.readFile(manifestPath, "utf-8");
|
|
1785
|
+
} catch {
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
let manifest;
|
|
1789
|
+
try {
|
|
1790
|
+
const parsed = JSON.parse(manifestRaw);
|
|
1791
|
+
if (!isObjectRecord(parsed)) return;
|
|
1792
|
+
manifest = parsed;
|
|
1793
|
+
} catch {
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
const devDependencies = manifest.devDependencies;
|
|
1797
|
+
if (!isObjectRecord(devDependencies)) return;
|
|
1798
|
+
const filteredEntries = Object.entries(devDependencies).filter(([, rawSpec]) => {
|
|
1799
|
+
return !(typeof rawSpec === "string" ? rawSpec.trim() : "").startsWith("workspace:");
|
|
1800
|
+
});
|
|
1801
|
+
if (filteredEntries.length === Object.keys(devDependencies).length) return;
|
|
1802
|
+
if (filteredEntries.length === 0) delete manifest.devDependencies;
|
|
1803
|
+
else manifest.devDependencies = Object.fromEntries(filteredEntries);
|
|
1804
|
+
await fs$1.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf-8");
|
|
1805
|
+
}
|
|
1806
|
+
async function installPackageDir(params) {
|
|
1807
|
+
params.logger?.info?.(`Installing to ${params.targetDir}…`);
|
|
1808
|
+
let backupDir = null;
|
|
1809
|
+
if (params.mode === "update" && await fileExists(params.targetDir)) {
|
|
1810
|
+
const backupRoot = path.join(path.dirname(params.targetDir), ".fased-install-backups");
|
|
1811
|
+
backupDir = path.join(backupRoot, `${path.basename(params.targetDir)}-${Date.now()}`);
|
|
1812
|
+
await fs$1.mkdir(backupRoot, { recursive: true });
|
|
1813
|
+
await fs$1.rename(params.targetDir, backupDir);
|
|
1814
|
+
}
|
|
1815
|
+
const rollback = async () => {
|
|
1816
|
+
if (!backupDir) return;
|
|
1817
|
+
await fs$1.rm(params.targetDir, {
|
|
1818
|
+
recursive: true,
|
|
1819
|
+
force: true
|
|
1820
|
+
}).catch(() => void 0);
|
|
1821
|
+
await fs$1.rename(backupDir, params.targetDir).catch(() => void 0);
|
|
1822
|
+
};
|
|
1823
|
+
try {
|
|
1824
|
+
await fs$1.cp(params.sourceDir, params.targetDir, { recursive: true });
|
|
1825
|
+
} catch (err) {
|
|
1826
|
+
await rollback();
|
|
1827
|
+
return {
|
|
1828
|
+
ok: false,
|
|
1829
|
+
error: `${params.copyErrorPrefix}: ${String(err)}`
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
try {
|
|
1833
|
+
await params.afterCopy?.();
|
|
1834
|
+
} catch (err) {
|
|
1835
|
+
await rollback();
|
|
1836
|
+
return {
|
|
1837
|
+
ok: false,
|
|
1838
|
+
error: `post-copy validation failed: ${String(err)}`
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
if (params.hasDeps) {
|
|
1842
|
+
await sanitizeManifestForNpmInstall(params.targetDir);
|
|
1843
|
+
params.logger?.info?.(params.depsLogMessage);
|
|
1844
|
+
const npmRes = await runCommandWithTimeout([
|
|
1845
|
+
"npm",
|
|
1846
|
+
"install",
|
|
1847
|
+
"--omit=dev",
|
|
1848
|
+
"--loglevel=error",
|
|
1849
|
+
"--ignore-scripts",
|
|
1850
|
+
"--legacy-peer-deps"
|
|
1851
|
+
], {
|
|
1852
|
+
timeoutMs: Math.max(params.timeoutMs, 3e5),
|
|
1853
|
+
cwd: params.targetDir
|
|
1854
|
+
});
|
|
1855
|
+
if (npmRes.code !== 0) {
|
|
1856
|
+
await rollback();
|
|
1857
|
+
return {
|
|
1858
|
+
ok: false,
|
|
1859
|
+
error: `npm install failed: ${npmRes.stderr.trim() || npmRes.stdout.trim()}`
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
try {
|
|
1864
|
+
await params.afterInstall?.();
|
|
1865
|
+
} catch (err) {
|
|
1866
|
+
await rollback();
|
|
1867
|
+
return {
|
|
1868
|
+
ok: false,
|
|
1869
|
+
error: `post-install validation failed: ${String(err)}`
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
if (backupDir) await fs$1.rm(backupDir, {
|
|
1873
|
+
recursive: true,
|
|
1874
|
+
force: true
|
|
1875
|
+
}).catch(() => void 0);
|
|
1876
|
+
return { ok: true };
|
|
1877
|
+
}
|
|
1476
1878
|
|
|
1477
1879
|
//#endregion
|
|
1478
1880
|
//#region src/infra/install-safe-path.ts
|
|
1881
|
+
function unscopedPackageName(name) {
|
|
1882
|
+
const trimmed = name.trim();
|
|
1883
|
+
if (!trimmed) return trimmed;
|
|
1884
|
+
return trimmed.includes("/") ? trimmed.split("/").pop() ?? trimmed : trimmed;
|
|
1885
|
+
}
|
|
1479
1886
|
function safeDirName(input) {
|
|
1480
1887
|
const trimmed = input.trim();
|
|
1481
1888
|
if (!trimmed) return trimmed;
|
|
@@ -1496,6 +1903,150 @@ function resolveSafeInstallDir(params) {
|
|
|
1496
1903
|
};
|
|
1497
1904
|
}
|
|
1498
1905
|
|
|
1906
|
+
//#endregion
|
|
1907
|
+
//#region src/infra/npm-integrity.ts
|
|
1908
|
+
async function resolveNpmIntegrityDrift(params) {
|
|
1909
|
+
if (!params.expectedIntegrity || !params.resolution.integrity) return { proceed: true };
|
|
1910
|
+
if (params.expectedIntegrity === params.resolution.integrity) return { proceed: true };
|
|
1911
|
+
const integrityDrift = {
|
|
1912
|
+
expectedIntegrity: params.expectedIntegrity,
|
|
1913
|
+
actualIntegrity: params.resolution.integrity
|
|
1914
|
+
};
|
|
1915
|
+
const payload = params.createPayload({
|
|
1916
|
+
spec: params.spec,
|
|
1917
|
+
expectedIntegrity: integrityDrift.expectedIntegrity,
|
|
1918
|
+
actualIntegrity: integrityDrift.actualIntegrity,
|
|
1919
|
+
resolution: params.resolution
|
|
1920
|
+
});
|
|
1921
|
+
let proceed = true;
|
|
1922
|
+
if (params.onIntegrityDrift) proceed = await params.onIntegrityDrift(payload);
|
|
1923
|
+
else params.warn?.(payload);
|
|
1924
|
+
return {
|
|
1925
|
+
integrityDrift,
|
|
1926
|
+
proceed,
|
|
1927
|
+
payload
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
async function resolveNpmIntegrityDriftWithDefaultMessage(params) {
|
|
1931
|
+
const driftResult = await resolveNpmIntegrityDrift({
|
|
1932
|
+
spec: params.spec,
|
|
1933
|
+
expectedIntegrity: params.expectedIntegrity,
|
|
1934
|
+
resolution: params.resolution,
|
|
1935
|
+
createPayload: (drift) => ({ ...drift }),
|
|
1936
|
+
onIntegrityDrift: params.onIntegrityDrift,
|
|
1937
|
+
warn: (driftPayload) => {
|
|
1938
|
+
params.warn?.(`Integrity drift detected for ${driftPayload.resolution.resolvedSpec ?? driftPayload.spec}: expected ${driftPayload.expectedIntegrity}, got ${driftPayload.actualIntegrity}`);
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1941
|
+
if (!driftResult.proceed && driftResult.payload) return {
|
|
1942
|
+
integrityDrift: driftResult.integrityDrift,
|
|
1943
|
+
error: `aborted: npm package integrity drift detected for ${driftResult.payload.resolution.resolvedSpec ?? driftResult.payload.spec}`
|
|
1944
|
+
};
|
|
1945
|
+
return { integrityDrift: driftResult.integrityDrift };
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
//#endregion
|
|
1949
|
+
//#region src/infra/npm-pack-install.ts
|
|
1950
|
+
async function installFromNpmSpecArchiveWithInstaller(params) {
|
|
1951
|
+
return await installFromNpmSpecArchive({
|
|
1952
|
+
tempDirPrefix: params.tempDirPrefix,
|
|
1953
|
+
spec: params.spec,
|
|
1954
|
+
timeoutMs: params.timeoutMs,
|
|
1955
|
+
expectedIntegrity: params.expectedIntegrity,
|
|
1956
|
+
onIntegrityDrift: params.onIntegrityDrift,
|
|
1957
|
+
warn: params.warn,
|
|
1958
|
+
installFromArchive: async ({ archivePath }) => await params.installFromArchive({
|
|
1959
|
+
archivePath,
|
|
1960
|
+
...params.archiveInstallParams
|
|
1961
|
+
})
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1964
|
+
function isSuccessfulInstallResult(result) {
|
|
1965
|
+
return result.ok;
|
|
1966
|
+
}
|
|
1967
|
+
function describeMissingNpmPackMetadata(metadata) {
|
|
1968
|
+
const missing = [];
|
|
1969
|
+
if (!metadata.name) missing.push("name");
|
|
1970
|
+
if (!metadata.version) missing.push("version");
|
|
1971
|
+
if (!metadata.integrity && !metadata.shasum) missing.push("integrity or shasum");
|
|
1972
|
+
return missing;
|
|
1973
|
+
}
|
|
1974
|
+
function validateNpmPackMetadata(params) {
|
|
1975
|
+
const missing = describeMissingNpmPackMetadata(params.metadata);
|
|
1976
|
+
if (missing.length === 0) return null;
|
|
1977
|
+
return `npm pack did not report ${missing.join(", ")} for ${params.spec}; refusing unpinned npm plugin install`;
|
|
1978
|
+
}
|
|
1979
|
+
function finalizeNpmSpecArchiveInstall(flowResult) {
|
|
1980
|
+
if (!flowResult.ok) return flowResult;
|
|
1981
|
+
const installResult = flowResult.installResult;
|
|
1982
|
+
if (!isSuccessfulInstallResult(installResult)) return installResult;
|
|
1983
|
+
return {
|
|
1984
|
+
...installResult,
|
|
1985
|
+
npmResolution: flowResult.npmResolution,
|
|
1986
|
+
...flowResult.integrityDrift ? { integrityDrift: flowResult.integrityDrift } : {}
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
async function installFromNpmSpecArchive(params) {
|
|
1990
|
+
return await withTempDir(params.tempDirPrefix, async (tmpDir) => {
|
|
1991
|
+
const packedResult = await packNpmSpecToArchive({
|
|
1992
|
+
spec: params.spec,
|
|
1993
|
+
timeoutMs: params.timeoutMs,
|
|
1994
|
+
cwd: tmpDir
|
|
1995
|
+
});
|
|
1996
|
+
if (!packedResult.ok) return packedResult;
|
|
1997
|
+
const metadataError = validateNpmPackMetadata({
|
|
1998
|
+
spec: params.spec,
|
|
1999
|
+
metadata: packedResult.metadata
|
|
2000
|
+
});
|
|
2001
|
+
if (metadataError) return {
|
|
2002
|
+
ok: false,
|
|
2003
|
+
error: metadataError
|
|
2004
|
+
};
|
|
2005
|
+
const npmResolution = {
|
|
2006
|
+
...packedResult.metadata,
|
|
2007
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2008
|
+
};
|
|
2009
|
+
const driftResult = await resolveNpmIntegrityDriftWithDefaultMessage({
|
|
2010
|
+
spec: params.spec,
|
|
2011
|
+
expectedIntegrity: params.expectedIntegrity,
|
|
2012
|
+
resolution: npmResolution,
|
|
2013
|
+
onIntegrityDrift: params.onIntegrityDrift,
|
|
2014
|
+
warn: params.warn
|
|
2015
|
+
});
|
|
2016
|
+
if (driftResult.error) return {
|
|
2017
|
+
ok: false,
|
|
2018
|
+
error: driftResult.error
|
|
2019
|
+
};
|
|
2020
|
+
return {
|
|
2021
|
+
ok: true,
|
|
2022
|
+
installResult: await params.installFromArchive({ archivePath: packedResult.archivePath }),
|
|
2023
|
+
npmResolution,
|
|
2024
|
+
integrityDrift: driftResult.integrityDrift
|
|
2025
|
+
};
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
//#endregion
|
|
2030
|
+
//#region src/infra/npm-registry-spec.ts
|
|
2031
|
+
function validateRegistryNpmSpec(rawSpec) {
|
|
2032
|
+
const spec = rawSpec.trim();
|
|
2033
|
+
if (!spec) return "missing npm spec";
|
|
2034
|
+
if (/\s/.test(spec)) return "unsupported npm spec: whitespace is not allowed";
|
|
2035
|
+
if (spec.includes("://")) return "unsupported npm spec: URLs are not allowed";
|
|
2036
|
+
if (spec.includes("#")) return "unsupported npm spec: git refs are not allowed";
|
|
2037
|
+
if (spec.includes(":")) return "unsupported npm spec: protocol specs are not allowed";
|
|
2038
|
+
const at = spec.lastIndexOf("@");
|
|
2039
|
+
const hasVersion = at > 0;
|
|
2040
|
+
const name = hasVersion ? spec.slice(0, at) : spec;
|
|
2041
|
+
const version = hasVersion ? spec.slice(at + 1) : "";
|
|
2042
|
+
if (!(name.startsWith("@") ? /^@[a-z0-9][a-z0-9-._~]*\/[a-z0-9][a-z0-9-._~]*$/.test(name) : /^[a-z0-9][a-z0-9-._~]*$/.test(name))) return "unsupported npm spec: expected <name> or <name>@<version> from the npm registry";
|
|
2043
|
+
if (hasVersion) {
|
|
2044
|
+
if (!version) return "unsupported npm spec: missing version/tag after @";
|
|
2045
|
+
if (/[\\/]/.test(version)) return "unsupported npm spec: invalid version/tag";
|
|
2046
|
+
}
|
|
2047
|
+
return null;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
1499
2050
|
//#endregion
|
|
1500
2051
|
//#region src/security/scan-paths.ts
|
|
1501
2052
|
function isPathInside$1(basePath, candidatePath) {
|
|
@@ -1504,6 +2055,9 @@ function isPathInside$1(basePath, candidatePath) {
|
|
|
1504
2055
|
const rel = path.relative(base, candidate);
|
|
1505
2056
|
return rel === "" || !rel.startsWith(`..${path.sep}`) && rel !== ".." && !path.isAbsolute(rel);
|
|
1506
2057
|
}
|
|
2058
|
+
function extensionUsesSkippedScannerPath(entry) {
|
|
2059
|
+
return entry.split(/[\\/]+/).filter(Boolean).some((segment) => segment === "node_modules" || segment.startsWith(".") && segment !== "." && segment !== "..");
|
|
2060
|
+
}
|
|
1507
2061
|
|
|
1508
2062
|
//#endregion
|
|
1509
2063
|
//#region src/infra/errors.ts
|
|
@@ -1519,6 +2073,12 @@ function extractErrorCode(err) {
|
|
|
1519
2073
|
function isErrno(err) {
|
|
1520
2074
|
return Boolean(err && typeof err === "object" && "code" in err);
|
|
1521
2075
|
}
|
|
2076
|
+
/**
|
|
2077
|
+
* Check if an error has a specific errno code.
|
|
2078
|
+
*/
|
|
2079
|
+
function hasErrnoCode(err, code) {
|
|
2080
|
+
return isErrno(err) && err.code === code;
|
|
2081
|
+
}
|
|
1522
2082
|
function formatErrorMessage(err) {
|
|
1523
2083
|
let formatted;
|
|
1524
2084
|
if (err instanceof Error) formatted = err.message || err.name || "Error";
|
|
@@ -1539,7 +2099,243 @@ function formatUncaughtError(err) {
|
|
|
1539
2099
|
|
|
1540
2100
|
//#endregion
|
|
1541
2101
|
//#region src/security/skill-scanner.ts
|
|
2102
|
+
const SCANNABLE_EXTENSIONS = new Set([
|
|
2103
|
+
".js",
|
|
2104
|
+
".ts",
|
|
2105
|
+
".mjs",
|
|
2106
|
+
".cjs",
|
|
2107
|
+
".mts",
|
|
2108
|
+
".cts",
|
|
2109
|
+
".jsx",
|
|
2110
|
+
".tsx"
|
|
2111
|
+
]);
|
|
2112
|
+
const DEFAULT_MAX_SCAN_FILES = 500;
|
|
1542
2113
|
const DEFAULT_MAX_FILE_BYTES = 1024 * 1024;
|
|
2114
|
+
function isScannable(filePath) {
|
|
2115
|
+
return SCANNABLE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
2116
|
+
}
|
|
2117
|
+
const LINE_RULES = [
|
|
2118
|
+
{
|
|
2119
|
+
ruleId: "dangerous-exec",
|
|
2120
|
+
severity: "critical",
|
|
2121
|
+
message: "Shell command execution detected (child_process)",
|
|
2122
|
+
pattern: /\b(exec|execSync|spawn|spawnSync|execFile|execFileSync)\s*\(/,
|
|
2123
|
+
requiresContext: /child_process/
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
ruleId: "dynamic-code-execution",
|
|
2127
|
+
severity: "critical",
|
|
2128
|
+
message: "Dynamic code execution detected",
|
|
2129
|
+
pattern: /\beval\s*\(|new\s+Function\s*\(/
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
ruleId: "crypto-mining",
|
|
2133
|
+
severity: "critical",
|
|
2134
|
+
message: "Possible crypto-mining reference detected",
|
|
2135
|
+
pattern: /stratum\+tcp|stratum\+ssl|coinhive|cryptonight|xmrig/i
|
|
2136
|
+
},
|
|
2137
|
+
{
|
|
2138
|
+
ruleId: "suspicious-network",
|
|
2139
|
+
severity: "warn",
|
|
2140
|
+
message: "WebSocket connection to non-standard port",
|
|
2141
|
+
pattern: /new\s+WebSocket\s*\(\s*["']wss?:\/\/[^"']*:(\d+)/
|
|
2142
|
+
}
|
|
2143
|
+
];
|
|
2144
|
+
const STANDARD_PORTS = new Set([
|
|
2145
|
+
80,
|
|
2146
|
+
443,
|
|
2147
|
+
8080,
|
|
2148
|
+
8443,
|
|
2149
|
+
3e3
|
|
2150
|
+
]);
|
|
2151
|
+
const SOURCE_RULES = [
|
|
2152
|
+
{
|
|
2153
|
+
ruleId: "potential-exfiltration",
|
|
2154
|
+
severity: "warn",
|
|
2155
|
+
message: "File read combined with network send — possible data exfiltration",
|
|
2156
|
+
pattern: /readFileSync|readFile/,
|
|
2157
|
+
requiresContext: /\bfetch\b|\bpost\b|http\.request/i
|
|
2158
|
+
},
|
|
2159
|
+
{
|
|
2160
|
+
ruleId: "obfuscated-code",
|
|
2161
|
+
severity: "warn",
|
|
2162
|
+
message: "Hex-encoded string sequence detected (possible obfuscation)",
|
|
2163
|
+
pattern: /(\\x[0-9a-fA-F]{2}){6,}/
|
|
2164
|
+
},
|
|
2165
|
+
{
|
|
2166
|
+
ruleId: "obfuscated-code",
|
|
2167
|
+
severity: "warn",
|
|
2168
|
+
message: "Large base64 payload with decode call detected (possible obfuscation)",
|
|
2169
|
+
pattern: /(?:atob|Buffer\.from)\s*\(\s*["'][A-Za-z0-9+/=]{200,}["']/
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
ruleId: "env-harvesting",
|
|
2173
|
+
severity: "critical",
|
|
2174
|
+
message: "Environment variable access combined with network send — possible credential harvesting",
|
|
2175
|
+
pattern: /process\.env/,
|
|
2176
|
+
requiresContext: /\bfetch\b|\bpost\b|http\.request/i
|
|
2177
|
+
}
|
|
2178
|
+
];
|
|
2179
|
+
function truncateEvidence(evidence, maxLen = 120) {
|
|
2180
|
+
if (evidence.length <= maxLen) return evidence;
|
|
2181
|
+
return `${evidence.slice(0, maxLen)}…`;
|
|
2182
|
+
}
|
|
2183
|
+
function scanSource(source, filePath) {
|
|
2184
|
+
const findings = [];
|
|
2185
|
+
const lines = source.split("\n");
|
|
2186
|
+
const matchedLineRules = /* @__PURE__ */ new Set();
|
|
2187
|
+
for (const rule of LINE_RULES) {
|
|
2188
|
+
if (matchedLineRules.has(rule.ruleId)) continue;
|
|
2189
|
+
if (rule.requiresContext && !rule.requiresContext.test(source)) continue;
|
|
2190
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2191
|
+
const line = lines[i];
|
|
2192
|
+
const match = rule.pattern.exec(line);
|
|
2193
|
+
if (!match) continue;
|
|
2194
|
+
if (rule.ruleId === "suspicious-network") {
|
|
2195
|
+
const port = parseInt(match[1], 10);
|
|
2196
|
+
if (STANDARD_PORTS.has(port)) continue;
|
|
2197
|
+
}
|
|
2198
|
+
findings.push({
|
|
2199
|
+
ruleId: rule.ruleId,
|
|
2200
|
+
severity: rule.severity,
|
|
2201
|
+
file: filePath,
|
|
2202
|
+
line: i + 1,
|
|
2203
|
+
message: rule.message,
|
|
2204
|
+
evidence: truncateEvidence(line.trim())
|
|
2205
|
+
});
|
|
2206
|
+
matchedLineRules.add(rule.ruleId);
|
|
2207
|
+
break;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
const matchedSourceRules = /* @__PURE__ */ new Set();
|
|
2211
|
+
for (const rule of SOURCE_RULES) {
|
|
2212
|
+
const ruleKey = `${rule.ruleId}::${rule.message}`;
|
|
2213
|
+
if (matchedSourceRules.has(ruleKey)) continue;
|
|
2214
|
+
if (!rule.pattern.test(source)) continue;
|
|
2215
|
+
if (rule.requiresContext && !rule.requiresContext.test(source)) continue;
|
|
2216
|
+
let matchLine = 0;
|
|
2217
|
+
let matchEvidence = "";
|
|
2218
|
+
for (let i = 0; i < lines.length; i++) if (rule.pattern.test(lines[i])) {
|
|
2219
|
+
matchLine = i + 1;
|
|
2220
|
+
matchEvidence = lines[i].trim();
|
|
2221
|
+
break;
|
|
2222
|
+
}
|
|
2223
|
+
if (matchLine === 0) {
|
|
2224
|
+
matchLine = 1;
|
|
2225
|
+
matchEvidence = source.slice(0, 120);
|
|
2226
|
+
}
|
|
2227
|
+
findings.push({
|
|
2228
|
+
ruleId: rule.ruleId,
|
|
2229
|
+
severity: rule.severity,
|
|
2230
|
+
file: filePath,
|
|
2231
|
+
line: matchLine,
|
|
2232
|
+
message: rule.message,
|
|
2233
|
+
evidence: truncateEvidence(matchEvidence)
|
|
2234
|
+
});
|
|
2235
|
+
matchedSourceRules.add(ruleKey);
|
|
2236
|
+
}
|
|
2237
|
+
return findings;
|
|
2238
|
+
}
|
|
2239
|
+
function normalizeScanOptions(opts) {
|
|
2240
|
+
return {
|
|
2241
|
+
includeFiles: opts?.includeFiles ?? [],
|
|
2242
|
+
maxFiles: Math.max(1, opts?.maxFiles ?? DEFAULT_MAX_SCAN_FILES),
|
|
2243
|
+
maxFileBytes: Math.max(1, opts?.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES)
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
2246
|
+
async function walkDirWithLimit(dirPath, maxFiles) {
|
|
2247
|
+
const files = [];
|
|
2248
|
+
const stack = [dirPath];
|
|
2249
|
+
while (stack.length > 0 && files.length < maxFiles) {
|
|
2250
|
+
const currentDir = stack.pop();
|
|
2251
|
+
if (!currentDir) break;
|
|
2252
|
+
const entries = await fs$1.readdir(currentDir, { withFileTypes: true });
|
|
2253
|
+
for (const entry of entries) {
|
|
2254
|
+
if (files.length >= maxFiles) break;
|
|
2255
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2256
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
2257
|
+
if (entry.isDirectory()) stack.push(fullPath);
|
|
2258
|
+
else if (isScannable(entry.name)) files.push(fullPath);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
return files;
|
|
2262
|
+
}
|
|
2263
|
+
async function resolveForcedFiles(params) {
|
|
2264
|
+
if (params.includeFiles.length === 0) return [];
|
|
2265
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2266
|
+
const out = [];
|
|
2267
|
+
for (const rawIncludePath of params.includeFiles) {
|
|
2268
|
+
const includePath = path.resolve(params.rootDir, rawIncludePath);
|
|
2269
|
+
if (!isPathInside$1(params.rootDir, includePath)) continue;
|
|
2270
|
+
if (!isScannable(includePath)) continue;
|
|
2271
|
+
if (seen.has(includePath)) continue;
|
|
2272
|
+
let st = null;
|
|
2273
|
+
try {
|
|
2274
|
+
st = await fs$1.stat(includePath);
|
|
2275
|
+
} catch (err) {
|
|
2276
|
+
if (hasErrnoCode(err, "ENOENT")) continue;
|
|
2277
|
+
throw err;
|
|
2278
|
+
}
|
|
2279
|
+
if (!st?.isFile()) continue;
|
|
2280
|
+
out.push(includePath);
|
|
2281
|
+
seen.add(includePath);
|
|
2282
|
+
}
|
|
2283
|
+
return out;
|
|
2284
|
+
}
|
|
2285
|
+
async function collectScannableFiles(dirPath, opts) {
|
|
2286
|
+
const forcedFiles = await resolveForcedFiles({
|
|
2287
|
+
rootDir: dirPath,
|
|
2288
|
+
includeFiles: opts.includeFiles
|
|
2289
|
+
});
|
|
2290
|
+
if (forcedFiles.length >= opts.maxFiles) return forcedFiles.slice(0, opts.maxFiles);
|
|
2291
|
+
const walkedFiles = await walkDirWithLimit(dirPath, opts.maxFiles);
|
|
2292
|
+
const seen = new Set(forcedFiles.map((f) => path.resolve(f)));
|
|
2293
|
+
const out = [...forcedFiles];
|
|
2294
|
+
for (const walkedFile of walkedFiles) {
|
|
2295
|
+
if (out.length >= opts.maxFiles) break;
|
|
2296
|
+
const resolved = path.resolve(walkedFile);
|
|
2297
|
+
if (seen.has(resolved)) continue;
|
|
2298
|
+
out.push(walkedFile);
|
|
2299
|
+
seen.add(resolved);
|
|
2300
|
+
}
|
|
2301
|
+
return out;
|
|
2302
|
+
}
|
|
2303
|
+
async function readScannableSource(filePath, maxFileBytes) {
|
|
2304
|
+
let st = null;
|
|
2305
|
+
try {
|
|
2306
|
+
st = await fs$1.stat(filePath);
|
|
2307
|
+
} catch (err) {
|
|
2308
|
+
if (hasErrnoCode(err, "ENOENT")) return null;
|
|
2309
|
+
throw err;
|
|
2310
|
+
}
|
|
2311
|
+
if (!st?.isFile() || st.size > maxFileBytes) return null;
|
|
2312
|
+
try {
|
|
2313
|
+
return await fs$1.readFile(filePath, "utf-8");
|
|
2314
|
+
} catch (err) {
|
|
2315
|
+
if (hasErrnoCode(err, "ENOENT")) return null;
|
|
2316
|
+
throw err;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
async function scanDirectoryWithSummary(dirPath, opts) {
|
|
2320
|
+
const scanOptions = normalizeScanOptions(opts);
|
|
2321
|
+
const files = await collectScannableFiles(dirPath, scanOptions);
|
|
2322
|
+
const allFindings = [];
|
|
2323
|
+
let scannedFiles = 0;
|
|
2324
|
+
for (const file of files) {
|
|
2325
|
+
const source = await readScannableSource(file, scanOptions.maxFileBytes);
|
|
2326
|
+
if (source == null) continue;
|
|
2327
|
+
scannedFiles += 1;
|
|
2328
|
+
const findings = scanSource(source, file);
|
|
2329
|
+
allFindings.push(...findings);
|
|
2330
|
+
}
|
|
2331
|
+
return {
|
|
2332
|
+
scannedFiles,
|
|
2333
|
+
critical: allFindings.filter((f) => f.severity === "critical").length,
|
|
2334
|
+
warn: allFindings.filter((f) => f.severity === "warn").length,
|
|
2335
|
+
info: allFindings.filter((f) => f.severity === "info").length,
|
|
2336
|
+
findings: allFindings
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
1543
2339
|
|
|
1544
2340
|
//#endregion
|
|
1545
2341
|
//#region src/project.ts
|
|
@@ -1736,6 +2532,7 @@ function loadPluginManifest(rootDir) {
|
|
|
1736
2532
|
manifestPath
|
|
1737
2533
|
};
|
|
1738
2534
|
const enabledByDefault = raw.enabledByDefault === true;
|
|
2535
|
+
const runtimeOnly = raw.runtimeOnly === true;
|
|
1739
2536
|
const legacyPluginIds = normalizeStringList(raw.legacyPluginIds);
|
|
1740
2537
|
const autoEnableWhenConfiguredProviders = normalizeStringList(raw.autoEnableWhenConfiguredProviders);
|
|
1741
2538
|
const kind = typeof raw.kind === "string" ? raw.kind : void 0;
|
|
@@ -1758,6 +2555,7 @@ function loadPluginManifest(rootDir) {
|
|
|
1758
2555
|
manifest: {
|
|
1759
2556
|
id,
|
|
1760
2557
|
configSchema,
|
|
2558
|
+
...runtimeOnly ? { runtimeOnly: true } : {},
|
|
1761
2559
|
...enabledByDefault ? { enabledByDefault } : {},
|
|
1762
2560
|
...legacyPluginIds.length > 0 ? { legacyPluginIds } : {},
|
|
1763
2561
|
...autoEnableWhenConfiguredProviders.length > 0 ? { autoEnableWhenConfiguredProviders } : {},
|
|
@@ -1790,14 +2588,120 @@ function getPackageManifestMetadata(manifest) {
|
|
|
1790
2588
|
return manifest[MANIFEST_KEY];
|
|
1791
2589
|
}
|
|
1792
2590
|
|
|
2591
|
+
//#endregion
|
|
2592
|
+
//#region src/plugins/package-extensions.ts
|
|
2593
|
+
function normalizeEntry(entry) {
|
|
2594
|
+
if (typeof entry !== "string") return null;
|
|
2595
|
+
const trimmed = entry.trim();
|
|
2596
|
+
if (!trimmed || path.isAbsolute(trimmed)) return null;
|
|
2597
|
+
const normalized = trimmed.replace(/^\.\/+/, "");
|
|
2598
|
+
if (!normalized || normalized === "." || normalized === "..") return null;
|
|
2599
|
+
return normalized;
|
|
2600
|
+
}
|
|
2601
|
+
async function inferExtensionsFromLegacyPluginManifest(params) {
|
|
2602
|
+
if (!params.pluginManifest) return [];
|
|
2603
|
+
const packageDir = path.resolve(params.packageDir);
|
|
2604
|
+
const candidates = [
|
|
2605
|
+
params.manifest.main,
|
|
2606
|
+
params.manifest.module,
|
|
2607
|
+
...DEFAULT_PLUGIN_ENTRY_CANDIDATES
|
|
2608
|
+
];
|
|
2609
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2610
|
+
const entries = [];
|
|
2611
|
+
for (const candidate of candidates) {
|
|
2612
|
+
const normalized = normalizeEntry(candidate);
|
|
2613
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
2614
|
+
seen.add(normalized);
|
|
2615
|
+
const resolved = path.resolve(packageDir, normalized);
|
|
2616
|
+
if (!isPathInside$1(packageDir, resolved)) continue;
|
|
2617
|
+
if (await fileExists(resolved)) entries.push(normalized);
|
|
2618
|
+
}
|
|
2619
|
+
return entries;
|
|
2620
|
+
}
|
|
2621
|
+
async function resolvePluginPackageExtensions(params) {
|
|
2622
|
+
let manifestKey = null;
|
|
2623
|
+
let extensions = params.manifest[MANIFEST_KEY]?.extensions;
|
|
2624
|
+
if (Array.isArray(extensions)) manifestKey = MANIFEST_KEY;
|
|
2625
|
+
if (Array.isArray(extensions)) {
|
|
2626
|
+
const list = extensions.map((e) => typeof e === "string" ? e.trim() : "").filter(Boolean);
|
|
2627
|
+
if (list.length === 0) throw new Error(`package.json ${manifestKey ?? MANIFEST_KEY}.extensions is empty`);
|
|
2628
|
+
return {
|
|
2629
|
+
extensions: list,
|
|
2630
|
+
source: "fased"
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
const inferred = await inferExtensionsFromLegacyPluginManifest(params);
|
|
2634
|
+
if (inferred.length > 0) return {
|
|
2635
|
+
extensions: inferred,
|
|
2636
|
+
source: "legacy-plugin-manifest"
|
|
2637
|
+
};
|
|
2638
|
+
throw new Error(`package.json missing ${MANIFEST_KEY}.extensions`);
|
|
2639
|
+
}
|
|
2640
|
+
|
|
1793
2641
|
//#endregion
|
|
1794
2642
|
//#region src/plugins/install.ts
|
|
2643
|
+
function normalizeExpectedPluginIds(params) {
|
|
2644
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2645
|
+
for (const raw of [params.expectedPluginId, ...params.expectedPluginIds ?? []]) {
|
|
2646
|
+
const trimmed = typeof raw === "string" ? raw.trim() : "";
|
|
2647
|
+
if (!trimmed) continue;
|
|
2648
|
+
ids.add(unscopedPackageName(trimmed));
|
|
2649
|
+
}
|
|
2650
|
+
return [...ids].toSorted((left, right) => left.localeCompare(right));
|
|
2651
|
+
}
|
|
2652
|
+
const defaultLogger = {};
|
|
1795
2653
|
function validatePluginId(pluginId) {
|
|
1796
2654
|
if (!pluginId) return "invalid plugin name: missing";
|
|
1797
2655
|
if (pluginId === "." || pluginId === "..") return "invalid plugin name: reserved path segment";
|
|
1798
2656
|
if (pluginId.includes("/") || pluginId.includes("\\")) return "invalid plugin name: path separators not allowed";
|
|
1799
2657
|
return null;
|
|
1800
2658
|
}
|
|
2659
|
+
function countManifestEntries(value) {
|
|
2660
|
+
return Object.keys(value ?? {}).length;
|
|
2661
|
+
}
|
|
2662
|
+
function listManifestKeys(value) {
|
|
2663
|
+
return Object.keys(value ?? {}).map((entry) => entry.trim()).filter(Boolean).toSorted((left, right) => left.localeCompare(right));
|
|
2664
|
+
}
|
|
2665
|
+
function isTypeScriptExtensionEntry(entry) {
|
|
2666
|
+
const ext = path.extname(entry.trim()).toLowerCase();
|
|
2667
|
+
return ext === ".ts" || ext === ".tsx" || ext === ".mts" || ext === ".cts";
|
|
2668
|
+
}
|
|
2669
|
+
function buildRuntimeWarnings(extensions) {
|
|
2670
|
+
const sourceEntries = extensions.map((entry) => entry.trim()).filter(Boolean).filter(isTypeScriptExtensionEntry).toSorted((left, right) => left.localeCompare(right));
|
|
2671
|
+
if (sourceEntries.length === 0) return [];
|
|
2672
|
+
return [`package exposes TypeScript extension ${sourceEntries.length === 1 ? "entry" : "entries"} (${sourceEntries.join(", ")}); publish compiled JavaScript runtime output before enabling this plugin`];
|
|
2673
|
+
}
|
|
2674
|
+
function buildInstallPackageReview(params) {
|
|
2675
|
+
const dependencyKinds = [];
|
|
2676
|
+
const dependencyCount = countManifestEntries(params.manifest.dependencies);
|
|
2677
|
+
const optionalDependencyCount = countManifestEntries(params.manifest.optionalDependencies);
|
|
2678
|
+
const peerDependencyCount = countManifestEntries(params.manifest.peerDependencies);
|
|
2679
|
+
const totalDependencyCount = dependencyCount + optionalDependencyCount + peerDependencyCount;
|
|
2680
|
+
if (dependencyCount > 0) dependencyKinds.push(`dependencies:${dependencyCount}`);
|
|
2681
|
+
if (optionalDependencyCount > 0) dependencyKinds.push(`optionalDependencies:${optionalDependencyCount}`);
|
|
2682
|
+
if (peerDependencyCount > 0) dependencyKinds.push(`peerDependencies:${peerDependencyCount}`);
|
|
2683
|
+
const scriptNames = listManifestKeys(params.manifest.scripts);
|
|
2684
|
+
const dependencyWarnings = totalDependencyCount > 0 ? [`package declares ${totalDependencyCount} dependenc${totalDependencyCount === 1 ? "y" : "ies"}; Fased installs runtime dependencies with npm --ignore-scripts`] : [];
|
|
2685
|
+
const scriptWarnings = scriptNames.length > 0 ? [`package declares npm scripts (${scriptNames.join(", ")}); Fased pack/install paths use --ignore-scripts`] : [];
|
|
2686
|
+
const runtimeWarnings = buildRuntimeWarnings(params.extensions);
|
|
2687
|
+
return {
|
|
2688
|
+
pluginId: params.pluginId,
|
|
2689
|
+
packageName: params.manifest.name || void 0,
|
|
2690
|
+
version: params.manifest.version || void 0,
|
|
2691
|
+
extensions: params.extensions,
|
|
2692
|
+
kind: params.pluginManifest?.kind,
|
|
2693
|
+
channels: params.pluginManifest?.channels ?? [],
|
|
2694
|
+
providers: params.pluginManifest?.providers ?? [],
|
|
2695
|
+
skills: params.pluginManifest?.skills ?? [],
|
|
2696
|
+
tools: params.pluginManifest?.contracts?.tools ?? [],
|
|
2697
|
+
dependencyCount: totalDependencyCount,
|
|
2698
|
+
dependencyKinds,
|
|
2699
|
+
scriptNames,
|
|
2700
|
+
dependencyWarnings,
|
|
2701
|
+
scriptWarnings,
|
|
2702
|
+
runtimeWarnings
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
1801
2705
|
function resolvePluginInstallDir(pluginId, extensionsDir) {
|
|
1802
2706
|
const extensionsBase = extensionsDir ? resolveUserPath(extensionsDir) : path.join(CONFIG_DIR, "extensions");
|
|
1803
2707
|
const pluginIdError = validatePluginId(pluginId);
|
|
@@ -1810,6 +2714,197 @@ function resolvePluginInstallDir(pluginId, extensionsDir) {
|
|
|
1810
2714
|
if (!targetDirResult.ok) throw new Error(targetDirResult.error);
|
|
1811
2715
|
return targetDirResult.path;
|
|
1812
2716
|
}
|
|
2717
|
+
async function installPluginFromPackageDir(params) {
|
|
2718
|
+
const { logger, timeoutMs, mode, dryRun } = resolveTimedInstallModeOptions(params, defaultLogger);
|
|
2719
|
+
const manifestPath = path.join(params.packageDir, "package.json");
|
|
2720
|
+
if (!await fileExists(manifestPath)) return {
|
|
2721
|
+
ok: false,
|
|
2722
|
+
error: "extracted package missing package.json"
|
|
2723
|
+
};
|
|
2724
|
+
let manifest;
|
|
2725
|
+
try {
|
|
2726
|
+
manifest = await readJsonFile(manifestPath);
|
|
2727
|
+
} catch (err) {
|
|
2728
|
+
return {
|
|
2729
|
+
ok: false,
|
|
2730
|
+
error: `invalid package.json: ${String(err)}`
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
const pkgName = typeof manifest.name === "string" ? manifest.name : "";
|
|
2734
|
+
const npmPluginId = pkgName ? unscopedPackageName(pkgName) : "plugin";
|
|
2735
|
+
const pluginManifestResult = loadPluginManifest(params.packageDir);
|
|
2736
|
+
const manifestPlugin = pluginManifestResult.ok && pluginManifestResult.manifest.id ? pluginManifestResult.manifest : void 0;
|
|
2737
|
+
const manifestPluginId = pluginManifestResult.ok && pluginManifestResult.manifest.id ? unscopedPackageName(pluginManifestResult.manifest.id) : void 0;
|
|
2738
|
+
let extensions;
|
|
2739
|
+
try {
|
|
2740
|
+
const resolvedExtensions = await resolvePluginPackageExtensions({
|
|
2741
|
+
manifest,
|
|
2742
|
+
packageDir: params.packageDir,
|
|
2743
|
+
pluginManifest: manifestPlugin
|
|
2744
|
+
});
|
|
2745
|
+
extensions = resolvedExtensions.extensions;
|
|
2746
|
+
if (resolvedExtensions.source === "legacy-plugin-manifest") logger.info?.(`Plugin "${manifestPlugin?.id ?? npmPluginId}" uses legacy plugin manifest entry inference; prefer package.json fased.extensions for new packages.`);
|
|
2747
|
+
} catch (err) {
|
|
2748
|
+
return {
|
|
2749
|
+
ok: false,
|
|
2750
|
+
error: String(err)
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
const pluginId = manifestPluginId ?? npmPluginId;
|
|
2754
|
+
const pluginIdError = validatePluginId(pluginId);
|
|
2755
|
+
if (pluginIdError) return {
|
|
2756
|
+
ok: false,
|
|
2757
|
+
error: pluginIdError
|
|
2758
|
+
};
|
|
2759
|
+
const expectedPluginIds = normalizeExpectedPluginIds(params);
|
|
2760
|
+
if (expectedPluginIds.length > 0 && !expectedPluginIds.includes(pluginId)) return {
|
|
2761
|
+
ok: false,
|
|
2762
|
+
error: `plugin id mismatch: expected ${expectedPluginIds.join(" or ")}, got ${pluginId}`
|
|
2763
|
+
};
|
|
2764
|
+
if (manifestPluginId && manifestPluginId !== npmPluginId) logger.info?.(`Plugin manifest id "${manifestPluginId}" differs from npm package name "${npmPluginId}"; using manifest id as the config key.`);
|
|
2765
|
+
const packageDir = path.resolve(params.packageDir);
|
|
2766
|
+
const forcedScanEntries = [];
|
|
2767
|
+
for (const entry of extensions) {
|
|
2768
|
+
const resolvedEntry = path.resolve(packageDir, entry);
|
|
2769
|
+
if (!isPathInside$1(packageDir, resolvedEntry)) {
|
|
2770
|
+
logger.warn?.(`extension entry escapes plugin directory and will not be scanned: ${entry}`);
|
|
2771
|
+
continue;
|
|
2772
|
+
}
|
|
2773
|
+
if (extensionUsesSkippedScannerPath(entry)) logger.warn?.(`extension entry is in a hidden/node_modules path and will receive targeted scan coverage: ${entry}`);
|
|
2774
|
+
forcedScanEntries.push(resolvedEntry);
|
|
2775
|
+
}
|
|
2776
|
+
try {
|
|
2777
|
+
const scanSummary = await scanDirectoryWithSummary(params.packageDir, { includeFiles: forcedScanEntries });
|
|
2778
|
+
if (scanSummary.critical > 0) {
|
|
2779
|
+
const criticalDetails = scanSummary.findings.filter((f) => f.severity === "critical").map((f) => `${f.message} (${f.file}:${f.line})`).join("; ");
|
|
2780
|
+
logger.warn?.(`WARNING: Plugin "${pluginId}" contains dangerous code patterns: ${criticalDetails}`);
|
|
2781
|
+
} else if (scanSummary.warn > 0) logger.warn?.(`Plugin "${pluginId}" has ${scanSummary.warn} suspicious code pattern(s). Run "fased security audit --deep" for details.`);
|
|
2782
|
+
} catch (err) {
|
|
2783
|
+
logger.warn?.(`Plugin "${pluginId}" code safety scan failed (${String(err)}). Installation continues; run "fased security audit --deep" after install.`);
|
|
2784
|
+
}
|
|
2785
|
+
const extensionsDir = params.extensionsDir ? resolveUserPath(params.extensionsDir) : path.join(CONFIG_DIR, "extensions");
|
|
2786
|
+
await fs$1.mkdir(extensionsDir, { recursive: true });
|
|
2787
|
+
const targetDirResult = resolveSafeInstallDir({
|
|
2788
|
+
baseDir: extensionsDir,
|
|
2789
|
+
id: pluginId,
|
|
2790
|
+
invalidNameMessage: "invalid plugin name: path traversal detected"
|
|
2791
|
+
});
|
|
2792
|
+
if (!targetDirResult.ok) return {
|
|
2793
|
+
ok: false,
|
|
2794
|
+
error: targetDirResult.error
|
|
2795
|
+
};
|
|
2796
|
+
const targetDir = targetDirResult.path;
|
|
2797
|
+
if (mode === "install" && await fileExists(targetDir)) return {
|
|
2798
|
+
ok: false,
|
|
2799
|
+
error: `plugin already exists: ${targetDir} (delete it first)`
|
|
2800
|
+
};
|
|
2801
|
+
if (dryRun) return {
|
|
2802
|
+
ok: true,
|
|
2803
|
+
pluginId,
|
|
2804
|
+
targetDir,
|
|
2805
|
+
manifestName: pkgName || void 0,
|
|
2806
|
+
version: typeof manifest.version === "string" ? manifest.version : void 0,
|
|
2807
|
+
extensions,
|
|
2808
|
+
review: buildInstallPackageReview({
|
|
2809
|
+
pluginId,
|
|
2810
|
+
manifest,
|
|
2811
|
+
extensions,
|
|
2812
|
+
pluginManifest: manifestPlugin
|
|
2813
|
+
})
|
|
2814
|
+
};
|
|
2815
|
+
const hasDeps = Boolean(manifest.dependencies && Object.keys(manifest.dependencies).length > 0 || manifest.optionalDependencies && Object.keys(manifest.optionalDependencies).length > 0);
|
|
2816
|
+
const installRes = await installPackageDir({
|
|
2817
|
+
sourceDir: params.packageDir,
|
|
2818
|
+
targetDir,
|
|
2819
|
+
mode,
|
|
2820
|
+
timeoutMs,
|
|
2821
|
+
logger,
|
|
2822
|
+
copyErrorPrefix: "failed to copy plugin",
|
|
2823
|
+
hasDeps,
|
|
2824
|
+
depsLogMessage: "Installing plugin dependencies…",
|
|
2825
|
+
afterCopy: async () => {
|
|
2826
|
+
for (const entry of extensions) {
|
|
2827
|
+
const resolvedEntry = path.resolve(targetDir, entry);
|
|
2828
|
+
if (!isPathInside$1(targetDir, resolvedEntry)) {
|
|
2829
|
+
logger.warn?.(`extension entry escapes plugin directory: ${entry}`);
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
if (!await fileExists(resolvedEntry)) logger.warn?.(`extension entry not found: ${entry}`);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
if (!installRes.ok) return installRes;
|
|
2837
|
+
return {
|
|
2838
|
+
ok: true,
|
|
2839
|
+
pluginId,
|
|
2840
|
+
targetDir,
|
|
2841
|
+
manifestName: pkgName || void 0,
|
|
2842
|
+
version: typeof manifest.version === "string" ? manifest.version : void 0,
|
|
2843
|
+
extensions,
|
|
2844
|
+
review: buildInstallPackageReview({
|
|
2845
|
+
pluginId,
|
|
2846
|
+
manifest,
|
|
2847
|
+
extensions,
|
|
2848
|
+
pluginManifest: manifestPlugin
|
|
2849
|
+
})
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
async function installPluginFromArchive(params) {
|
|
2853
|
+
const logger = params.logger ?? defaultLogger;
|
|
2854
|
+
const timeoutMs = params.timeoutMs ?? 12e4;
|
|
2855
|
+
const mode = params.mode ?? "install";
|
|
2856
|
+
const archivePathResult = await resolveArchiveSourcePath(params.archivePath);
|
|
2857
|
+
if (!archivePathResult.ok) return archivePathResult;
|
|
2858
|
+
const archivePath = archivePathResult.path;
|
|
2859
|
+
return await withExtractedArchiveRoot({
|
|
2860
|
+
archivePath,
|
|
2861
|
+
tempDirPrefix: "fased-plugin-",
|
|
2862
|
+
timeoutMs,
|
|
2863
|
+
logger,
|
|
2864
|
+
onExtracted: async (packageDir) => await installPluginFromPackageDir({
|
|
2865
|
+
packageDir,
|
|
2866
|
+
extensionsDir: params.extensionsDir,
|
|
2867
|
+
timeoutMs,
|
|
2868
|
+
logger,
|
|
2869
|
+
mode,
|
|
2870
|
+
dryRun: params.dryRun,
|
|
2871
|
+
expectedPluginId: params.expectedPluginId,
|
|
2872
|
+
expectedPluginIds: params.expectedPluginIds
|
|
2873
|
+
})
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
async function installPluginFromNpmSpec(params) {
|
|
2877
|
+
const { logger, timeoutMs, mode, dryRun } = resolveTimedInstallModeOptions(params, defaultLogger);
|
|
2878
|
+
const expectedPluginId = params.expectedPluginId;
|
|
2879
|
+
const expectedPluginIds = params.expectedPluginIds;
|
|
2880
|
+
const spec = params.spec.trim();
|
|
2881
|
+
const specError = validateRegistryNpmSpec(spec);
|
|
2882
|
+
if (specError) return {
|
|
2883
|
+
ok: false,
|
|
2884
|
+
error: specError
|
|
2885
|
+
};
|
|
2886
|
+
logger.info?.(`Downloading ${spec}…`);
|
|
2887
|
+
return finalizeNpmSpecArchiveInstall(await installFromNpmSpecArchiveWithInstaller({
|
|
2888
|
+
tempDirPrefix: "fased-npm-pack-",
|
|
2889
|
+
spec,
|
|
2890
|
+
timeoutMs,
|
|
2891
|
+
expectedIntegrity: params.expectedIntegrity,
|
|
2892
|
+
onIntegrityDrift: params.onIntegrityDrift,
|
|
2893
|
+
warn: (message) => {
|
|
2894
|
+
logger.warn?.(message);
|
|
2895
|
+
},
|
|
2896
|
+
installFromArchive: installPluginFromArchive,
|
|
2897
|
+
archiveInstallParams: {
|
|
2898
|
+
extensionsDir: params.extensionsDir,
|
|
2899
|
+
timeoutMs,
|
|
2900
|
+
logger,
|
|
2901
|
+
mode,
|
|
2902
|
+
dryRun,
|
|
2903
|
+
expectedPluginId,
|
|
2904
|
+
expectedPluginIds
|
|
2905
|
+
}
|
|
2906
|
+
}));
|
|
2907
|
+
}
|
|
1813
2908
|
|
|
1814
2909
|
//#endregion
|
|
1815
2910
|
//#region src/plugins/uninstall.ts
|
|
@@ -6568,6 +7663,13 @@ const PLUGIN_ORIGIN_RANK = {
|
|
|
6568
7663
|
const registryCache = /* @__PURE__ */ new Map();
|
|
6569
7664
|
const DEFAULT_MANIFEST_CACHE_MS = 200;
|
|
6570
7665
|
const LEGACY_REMOVED_PLUGIN_IDS$2 = /* @__PURE__ */ new Set();
|
|
7666
|
+
function isRuntimeOnlyComponent(params) {
|
|
7667
|
+
if (params.manifest.runtimeOnly === true) return true;
|
|
7668
|
+
return params.manifest.id === "openai-runtime" && params.candidate.packageName === "@fased/openai-runtime";
|
|
7669
|
+
}
|
|
7670
|
+
function clearPluginManifestRegistryCache() {
|
|
7671
|
+
registryCache.clear();
|
|
7672
|
+
}
|
|
6571
7673
|
function resolveManifestCacheMs(env) {
|
|
6572
7674
|
const raw = env.FASED_PLUGIN_MANIFEST_CACHE_MS?.trim();
|
|
6573
7675
|
if (raw === "" || raw === "0") return 0;
|
|
@@ -6625,6 +7727,7 @@ function buildRecord(params) {
|
|
|
6625
7727
|
});
|
|
6626
7728
|
return {
|
|
6627
7729
|
id: params.manifest.id,
|
|
7730
|
+
runtimeOnly: isRuntimeOnlyComponent(params) ? true : void 0,
|
|
6628
7731
|
name: normalizeManifestLabel(params.manifest.name) ?? params.candidate.packageName,
|
|
6629
7732
|
description: normalizeManifestLabel(params.manifest.description) ?? params.candidate.packageDescription,
|
|
6630
7733
|
version: normalizeManifestLabel(params.manifest.version) ?? params.candidate.packageVersion,
|
|
@@ -6739,6 +7842,25 @@ function loadPluginManifestRegistry(params) {
|
|
|
6739
7842
|
}
|
|
6740
7843
|
continue;
|
|
6741
7844
|
}
|
|
7845
|
+
if (isRuntimeOnlyComponent({
|
|
7846
|
+
manifest,
|
|
7847
|
+
candidate
|
|
7848
|
+
}) && records[existing.recordIndex]?.runtimeOnly === true) {
|
|
7849
|
+
if (PLUGIN_ORIGIN_RANK[candidate.origin] < PLUGIN_ORIGIN_RANK[existing.candidate.origin]) {
|
|
7850
|
+
records[existing.recordIndex] = buildRecord({
|
|
7851
|
+
manifest,
|
|
7852
|
+
candidate,
|
|
7853
|
+
manifestPath: manifestRes.manifestPath,
|
|
7854
|
+
schemaCacheKey,
|
|
7855
|
+
configSchema
|
|
7856
|
+
});
|
|
7857
|
+
seenIds.set(manifest.id, {
|
|
7858
|
+
candidate,
|
|
7859
|
+
recordIndex: existing.recordIndex
|
|
7860
|
+
});
|
|
7861
|
+
}
|
|
7862
|
+
continue;
|
|
7863
|
+
}
|
|
6742
7864
|
diagnostics.push({
|
|
6743
7865
|
level: "warn",
|
|
6744
7866
|
pluginId: manifest.id,
|
|
@@ -11910,6 +13032,9 @@ function cloneCurrentModelProvider(provider) {
|
|
|
11910
13032
|
}))
|
|
11911
13033
|
};
|
|
11912
13034
|
}
|
|
13035
|
+
function listCurrentModelCatalogProviderIds() {
|
|
13036
|
+
return Object.keys(CURRENT_MODEL_PROVIDER_CATALOG).map(normalizeModelCatalogProviderId).filter(Boolean).toSorted((left, right) => left.localeCompare(right));
|
|
13037
|
+
}
|
|
11913
13038
|
function listCurrentModelCatalogRows() {
|
|
11914
13039
|
return Object.entries(CURRENT_MODEL_PROVIDER_CATALOG).flatMap(([provider, providerConfig]) => normalizeProviderCatalogRows({
|
|
11915
13040
|
provider,
|
|
@@ -23419,4 +24544,4 @@ async function writeConfigFile(cfg, options = {}) {
|
|
|
23419
24544
|
}
|
|
23420
24545
|
|
|
23421
24546
|
//#endregion
|
|
23422
|
-
export { resetConfigOverrides as $,
|
|
24547
|
+
export { resetConfigOverrides as $, supportsXHighThinking as $i, ANTHROPIC_MODEL_IDS as $n, QWEN_API_MODEL_IDS as $r, resolveSubagentSpawnModelSelection as $t, GroupPolicySchema as A, applyExclusiveSlotSelection as Aa, isStandardProviderCatalogEntry as Ai, listProvidersWithStoredCredentials as An, MINIMAX_MODEL_IDS as Ar, isSafeExecutableValue as At, MODEL_APIS as B, SYNTHETIC_MODEL_IDS as Bi, findNormalizedProviderValue$1 as Bn, OLLAMA_ROUTE_ID as Br, buildModelAliasIndex as Bt, resolveIMessageAttachmentRoots as C, parseBooleanValue as Ca, XIAOMI_PROVIDER_BRAND_ID as Ci, isProfileInCooldown as Cn, KIMI_CODING_ROUTE_ID as Cr, unwrapKnownDispatchWrapperInvocation as Ct, BlockStreamingCoalesceSchema as D, resolveEffectiveEnableState as Da, ZAI_ROUTE_ID as Di, resolveApiKeyForProfile as Dn, LMSTUDIO_ROUTE_ID as Dr, normalizeSafeBinProfileFixtures as Dt, ToolPolicySchema as E, normalizePluginsConfig as Ea, ZAI_PROVIDER_BRAND_ID as Ei, resolveProfilesUnavailableReason as En, LMSTUDIO_PROVIDER_BRAND_ID as Er, SAFE_BIN_PROFILES as Et, TtsConfigSchema as F, LITELLM_BASE_URL as Fi, resolveFasedAgentDir as Fn, MISTRAL_ROUTE_ID as Fr, resolveTelegramPreviewStreamMode as Ft, isAvatarDataUrl as G, CLOUDFLARE_AI_GATEWAY_ROUTE_ID as Gi, isPathInside as Gn, OPENCODE_ZEN_PROVIDER_BRAND_ID as Gr, normalizeModelRef as Gt, parseDurationMs as H, HUGGINGFACE_MODEL_IDS as Hi, clearPluginManifestRegistryCache as Hn, OPENAI_API_ROUTE_ID as Hr, inferUniqueProviderFromConfiguredModels as Ht, TtsModeSchema as I, XIAOMI_MODEL_IDS as Ii, acquireFileLock as In, MOONSHOT_MODEL_IDS as Ir, DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH as It, isSupportedLocalAvatarExtension as J, formatXHighModelHint as Ji, isPrivateNetworkBaseUrl as Jn, OPENROUTER_PROVIDER_BRAND_ID as Jr, resolveConfiguredModelRef as Jt, isAvatarHttpUrl as K, BASE_THINKING_LEVELS as Ki, safeStatSync as Kn, OPENCODE_ZEN_ROUTE_ID as Kr, normalizeProviderId as Kt, TtsProviderSchema as L, VERCEL_AI_GATEWAY_MODEL_IDS as Li, withFileLock as Ln, MOONSHOT_PROVIDER_BRAND_ID as Lr, resolveAgentMaxConcurrent as Lt, MarkdownTableModeSchema as M, lookupProviderManifestModelCapability as Mi, ensureAuthProfileStore as Mn, MINIMAX_PROVIDER_BRAND_ID as Mr, resolveDiscordPreviewStreamMode as Mt, ReplyRuntimeConfigSchemaShape as N, providerModelRecommendationRank as Ni, resolveAuthStorePathForDisplay as Nn, MISTRAL_MODEL_IDS as Nr, resolveSlackNativeStreaming as Nt, DmConfigSchema as O, resolveMemorySlotDecision as Oa, getProviderBrandManifestForRoute as Oi, dedupeProfileIds as On, MINIMAX_API_ROUTE_ID as Or, resolveSafeBinProfiles as Ot, TtsAutoSchema as P, resolveProviderRouteModelCapability as Pi, resolveFasedAgentAgentDir as Pn, MISTRAL_PROVIDER_BRAND_ID as Pr, resolveSlackStreamingMode as Pt, getConfigOverrides as Q, supportsThinkingLevel as Qi, splitTrailingAuthProfile as Qn, QIANFAN_ROUTE_ID as Qr, resolveReasoningDefault as Qt, normalizeAllowFrom as R, VENICE_MODEL_IDS as Ri, resolveProcessScopedMap as Rn, MOONSHOT_ROUTE_ID as Rr, buildAllowedModelSet as Rt, mergeInboundPathRoots as S, isTruthyEnvValue as Sa, XAI_ROUTE_ID as Si, getSoonestCooldownExpiry as Sn, KIMI_CODING_MODEL_IDS as Sr, isShellWrapperExecutable as St, normalizeScpRemoteHost as T, isPluginRuntimeSessionReadAllowed as Ta, ZAI_MODEL_IDS as Ti, markAuthProfileUsed as Tn, LITELLM_ROUTE_ID as Tr, splitShellArgs as Tt, parseByteSize as U, CLOUDFLARE_AI_GATEWAY_MODEL_IDS as Ui, loadPluginManifestRegistry as Un, OPENAI_CODEX_ROUTE_ID as Ur, isCliProvider as Ut, getBlockedNetworkModeReason as V, OPENCODE_ZEN_MODEL_IDS as Vi, normalizeProviderId$1 as Vn, OPENAI_API_MODEL_IDS as Vr, findNormalizedProviderValue as Vt, AVATAR_MAX_BYTES as W, CLOUDFLARE_AI_GATEWAY_PROVIDER_BRAND_ID as Wi, discoverFasedAgentPlugins as Wn, OPENAI_PROVIDER_BRAND_ID as Wr, modelKey as Wt, resolveAvatarMime as X, normalizeThinkLevel as Xi, assertSecretInputResolved as Xn, QIANFAN_MODEL_IDS as Xr, resolveExplicitConfiguredModelRef as Xt, isWorkspaceRelativeAvatarPath as Y, listThinkingLevels as Yi, normalizeSecretInput as Yn, OPENROUTER_ROUTE_ID as Yr, resolveDefaultModelForAgent as Yt, validateJsonSchemaValue as Z, resolveModelThinkingCapability as Zi, coerceSecretRef as Zn, QIANFAN_PROVIDER_BRAND_ID as Zr, resolveModelRefFromString as Zt, TELEGRAM_COMMAND_NAME_PATTERN as _, isDangerousHostInheritedEnvVarName as _a, VOLCENGINE_PLAN_ROUTE_ID as _i, normalizeModelCatalogModelId as _n, GOOGLE_GEMINI_CLI_ROUTE_ID as _r, matchAllowlist as _t, readConfigFileSnapshotForWrite as a, resolvePluginInstallDir as aa, SYNTHETIC_ROUTE_ID as ai, getApiKeyForModel as an, BYTEPLUS_PLAN_ROUTE_ID as ar, unsetConfigValueAtPath as at, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS as b, formatCliCommand as ba, XAI_MODEL_IDS as bi, auth_profiles_exports as bn, HUGGINGFACE_PROVIDER_BRAND_ID as br, extractShellWrapperInlineCommand as bt, validateConfigObjectWithPlugins as c, extractErrorCode as ca, VENICE_PROVIDER_BRAND_ID as ci, resolveApiKeyForProvider as cn, CHUTES_MODEL_IDS as cr, isTrustedSafeBinPath as ct, GoogleChatConfigSchema as d, isErrno as da, VERCEL_AI_GATEWAY_ROUTE_ID as di, CURRENT_MODEL_PROVIDER_CATALOG as dn, COPILOT_PROVIDER_BRAND_ID as dr, validateSafeBinArgv as dt, DEFAULT_CONTEXT_TOKENS as ea, QWEN_API_ROUTE_ID as ei, resolveThinkingDefault as en, ANTHROPIC_PROVIDER_BRAND_ID as er, setConfigOverride as et, IMessageConfigSchema as f, extractArchive as fa, VLLM_PROVIDER_BRAND_ID as fi, cloneCurrentModelProvider as fn, COPILOT_PROXY_MODEL_IDS as fr, analyzeShellCommand as ft, TelegramConfigSchema as g, isDangerousHostEnvVarName as ga, VOLCENGINE_MODEL_IDS as gi, mergeModelCatalogRowsByAuthority as gn, GOOGLE_API_ROUTE_ID as gr, DEFAULT_SAFE_BINS as gt, SlackConfigSchema as h, isDangerousHostEnvOverrideVarName as ha, VOLCENGINE_CODING_ROUTE_ID as hi, buildModelCatalogMergeKey as hn, CUSTOM_PROVIDER_ROUTE_ID as hr, splitCommandChain as ht, readConfigFileSnapshot as i, installPluginFromNpmSpec as ia, SYNTHETIC_PROVIDER_BRAND_ID as ii, resolveImplicitProviders as in, BYTEPLUS_MODEL_IDS as ir, setConfigValueAtPath as it, MarkdownConfigSchema as j, listProviderBrandManifests as ji, markAuthProfileGood as jn, MINIMAX_PORTAL_ROUTE_ID as jr, mapStreamingModeToSlackLegacyDraftStreamMode as jt, DmPolicySchema as k, resolvePluginAdminRpcActionGrant as ka, isOpenAISignInRuntimeModelSupported as ki, listProfilesForProvider as kn, MINIMAX_CN_ROUTE_ID as kr, applyMergePatch as kt, WhatsAppConfigSchema as l, formatErrorMessage as la, VENICE_ROUTE_ID as li, resolveEnvApiKey as ln, CHUTES_PROVIDER_BRAND_ID as lr, listWritableExplicitTrustedSafeBinDirs as lt, SignalConfigSchema as m, resolveShellEnvFallbackTimeoutMs as ma, VOLCENGINE_CODING_MODEL_IDS as mi, listCurrentModelCatalogRows as mn, CUSTOM_PROVIDER_BRAND_ID as mr, isWindowsPlatform as mt, loadConfig as n, DEFAULT_PROVIDER as na, QWEN_CODING_PLAN_ROUTE_ID as ni, normalizeProviders as nn, BYTEPLUS_CODING_MODEL_IDS as nr, getConfigValueAtPath as nt, resolveConfigSnapshotHash as o, getPackageManifestMetadata as oa, TOGETHER_PROVIDER_BRAND_ID as oi, getCustomProviderApiKey as on, BYTEPLUS_PROVIDER_BRAND_ID as or, ensurePluginAllowlisted as ot, MSTeamsConfigSchema as p, getShellPathFromLoginShell as pa, VLLM_ROUTE_ID as pi, listCurrentModelCatalogProviderIds as pn, COPILOT_PROXY_ROUTE_ID as pr, buildEnforcedShellCommand as pt, isPathWithinRoot as q, formatThinkingLevels as qi, resolveAuthProfileDisplayLabel as qn, OPENROUTER_MODEL_IDS as qr, parseModelRef as qt, parseConfigJson5 as r, VERSION as ra, QWEN_PROVIDER_BRAND_ID as ri, resolveImplicitCopilotProvider as rn, BYTEPLUS_CODING_ROUTE_ID as rr, parseConfigPath as rt, writeConfigFile as s, MANIFEST_KEY as sa, TOGETHER_ROUTE_ID as si, requireApiKey as sn, BYTEPLUS_ROUTE_ID as sr, getTrustedSafeBinDirs as st, createConfigIO as t, DEFAULT_MODEL as ta, QWEN_CODING_PLAN_MODEL_IDS as ti, normalizeGoogleModelId as tn, ANTHROPIC_ROUTE_ID as tr, unsetConfigOverride as tt, DiscordConfigSchema as u, formatUncaughtError as ua, VERCEL_AI_GATEWAY_PROVIDER_BRAND_ID as ui, resolveModelAuthMode as un, CHUTES_ROUTE_ID as ur, normalizeTrustedSafeBinDirs as ut, normalizeTelegramCommandName as v, sanitizeHostExecEnv as va, VOLCENGINE_PROVIDER_BRAND_ID as vi, normalizeModelCatalogProviderId as vn, GOOGLE_GEMINI_MODEL_IDS as vr, resolveAllowlistCandidatePath as vt, resolveIMessageRemoteAttachmentRoots as w, applyTestPluginDefaults as wa, XIAOMI_ROUTE_ID as wi, markAuthProfileFailure as wn, LITELLM_PROVIDER_BRAND_ID as wr, unwrapKnownShellMultiplexerInvocation as wt, isInboundPathAllowed as x, resolveCliName as xa, XAI_PROVIDER_BRAND_ID as xi, resolveAuthProfileOrder as xn, HUGGINGFACE_ROUTE_ID as xr, isDispatchWrapperExecutable as xt, resolveTelegramCustomCommands as y, resolveOwnerDisplaySetting as ya, VOLCENGINE_ROUTE_ID as yi, normalizeProviderCatalogRows as yn, GOOGLE_PROVIDER_BRAND_ID as yr, resolveCommandResolutionFromArgv as yt, requireOpenAllowFrom as z, TOGETHER_MODEL_IDS as zi, isPidAlive as zn, OLLAMA_PROVIDER_BRAND_ID as zr, buildConfiguredAllowlistKeys as zt };
|