@fased/fased 0.1.56 → 0.1.57
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/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/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-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/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-DltSyY4Y.js} +1689 -1689
- package/dist/control-ui/assets/{index-BmSBom-w.js → index-D5JlBp7f.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-CmMwe9Dt.js} +1 -1
- package/dist/plugin-sdk/{actions-BplQVLL6.js → actions-DYViFQiX.js} +2 -2
- package/dist/plugin-sdk/{active-listener-x4MLhYUw.js → active-listener-DVbpcisf.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-D-Mfay8i.js} +31 -31
- package/dist/plugin-sdk/{audit-CWknklvI.js → audit-JImYFOzJ.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-CD4QDN5E.js → channel-access-configure-B_qYjml8.js} +1 -1
- package/dist/plugin-sdk/{channel-access-a9Dnfw7-.js → channel-access-cxCK2mci.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-CF8nvZNj.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-CEPklxGe.js → chunk-items-yLFoO571.js} +1 -1
- package/dist/plugin-sdk/command-status.js +31 -31
- package/dist/plugin-sdk/{commands-registry-BfEa4tFA.js → commands-registry-CK4KmMG0.js} +2 -2
- package/dist/plugin-sdk/{common-CbfckC19.js → common-Cky4hpqr.js} +1 -1
- package/dist/plugin-sdk/{config-Bt5GhnA-.js → config-Dbxj_jUP.js} +1125 -3
- package/dist/plugin-sdk/{config-schema-B9DKr6J5.js → config-schema-aKPMn6ML.js} +1749 -1387
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +4 -4
- 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-BSNDD2Vc.js} +17 -17
- package/dist/plugin-sdk/{helpers-CluGKuIV.js → helpers-CDo2XBSr.js} +1 -1
- package/dist/plugin-sdk/{image-ops-CUaLtIFj.js → image-ops-DbeBxbn4.js} +1 -1
- package/dist/plugin-sdk/index.d.ts +15 -15
- 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-CWXvFTd8.js} +3 -3
- package/dist/plugin-sdk/{login-qr-CbHL5ayf.js → login-qr-CJB2zjmM.js} +4 -4
- package/dist/plugin-sdk/{manager-oHAvZCT3.js → manager-CbiFFLKS.js} +4 -4
- package/dist/plugin-sdk/{markdown-tables-Mkx7k92Y.js → markdown-tables-Bskt9r8i.js} +1 -1
- package/dist/plugin-sdk/{media-CA8sTmVE.js → media-B3aAg5rh.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-BJs6z7AT.js} +35 -35
- package/dist/plugin-sdk/{monitor-CmwGqNyV.js → monitor-BYGbTI5V.js} +36 -36
- package/dist/plugin-sdk/{openresponses-http-CWOd4war.js → openresponses-http-BGCl2dS2.js} +31 -31
- package/dist/plugin-sdk/{optional-runtime-dependency-DKmk9PZa.js → optional-runtime-dependency-BlTVkcAg.js} +1 -1
- package/dist/plugin-sdk/{outbound-0oN9IfNw.js → outbound-CIemga5_.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-DdVkqUzE.js → outbound-attachment-2RckWqrk.js} +2 -2
- package/dist/plugin-sdk/{pairing-message-BMkkS038.d.ts → pairing-message-C403mq4K.d.ts} +1 -1
- package/dist/plugin-sdk/{pairing-message-ClqhfCUk.js → pairing-message-r-VQfhFB.js} +1 -1
- package/dist/plugin-sdk/{pairing-store-B01mCSct.js → pairing-store-uPnLfGgB.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-BpEilAym.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DuwuoteY.js → pi-model-discovery-runtime-DwNdFaz-.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-H7UgunQQ.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-CKMwkH4G.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-B68fSoGi.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-CkNIKKEW.js → resolve-route-B8fOfihG.js} +2 -2
- package/dist/plugin-sdk/{retry-policy-9ybIh4Fq.js → retry-policy-B6GQldxB.js} +1 -1
- package/dist/plugin-sdk/{runtime-dependency-CIw9t7-k.js → runtime-dependency-DlqVSsSs.js} +4 -4
- package/dist/plugin-sdk/{runtime-Dy420wBu.js → runtime-nVJl3PlS.js} +4 -4
- 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-BQUtCJFW.js → send-BCJ4hi3t.js} +8 -8
- package/dist/plugin-sdk/{send-DPJIIYAs.js → send-BHokB4TR.js} +6 -6
- package/dist/plugin-sdk/{send-2VcOMTN5.js → send-CPK_HlYW.js} +5 -5
- package/dist/plugin-sdk/{send-J4JWKP62.js → send-D3DQOg2a.js} +6 -6
- package/dist/plugin-sdk/{send-Dqes9tdU.js → send-hSu1HWms.js} +7 -7
- package/dist/plugin-sdk/{session-C_n2S5ub.js → session-DQ4Dr-mf.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-B7wx9ax8.js → skill-commands-CmdoKLh_.js} +4 -4
- package/dist/plugin-sdk/{slack-BouRQG-W.js → slack-B70NHpMF.js} +47 -47
- package/dist/plugin-sdk/{slack-actions-CasHVtiq.js → slack-actions-fSmP981b.js} +14 -14
- package/dist/plugin-sdk/slack.d.ts +4 -4
- package/dist/plugin-sdk/slack.js +12 -12
- package/dist/plugin-sdk/{sticker-cache-BvGEUas3.js → sticker-cache-B4dG2sKU.js} +3 -3
- package/dist/plugin-sdk/{tables-CjlQJV4r.js → tables-EX4Hy-a-.js} +1 -1
- package/dist/plugin-sdk/{targets-QfP164Dh.js → targets-BeGUCGWK.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-CwYjV6Db.js → telegram-actions-CM8SJgc9.js} +34 -34
- package/dist/plugin-sdk/telegram.d.ts +4 -4
- package/dist/plugin-sdk/telegram.js +9 -9
- package/dist/plugin-sdk/{thread-bindings.lifecycle-DU4iX_Jr.js → thread-bindings.lifecycle-tHK_1mvp.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-BgYWFjNF.js → thread-bindings.state-D7xG1GHu.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-BFolfZ3i.js} +36 -36
- package/dist/plugin-sdk/{whatsapp-actions-BT2nPLyo.js → whatsapp-actions-CYmleHCz.js} +16 -16
- package/dist/plugin-sdk/{whatsapp-heartbeat-CiABSZ6G.js → whatsapp-heartbeat-BEwm4GK3.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +9 -9
- package/dist/plugin-sdk/whatsapp.js +13 -13
- package/dist/plugin-sdk/{wsl-B_ojyEtC.js → wsl-BtMDzMv5.js} +3 -3
- package/dist/plugin-sdk/{zod-schema.providers-core-CIzCjXH9.d.ts → zod-schema.providers-core-FaYR6KdD.d.ts} +61 -61
- 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 +6 -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 +6 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +6 -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 +6 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +6 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +6 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +6 -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,
|
|
@@ -23419,4 +24541,4 @@ async function writeConfigFile(cfg, options = {}) {
|
|
|
23419
24541
|
}
|
|
23420
24542
|
|
|
23421
24543
|
//#endregion
|
|
23422
|
-
export { resetConfigOverrides as $,
|
|
24544
|
+
export { resetConfigOverrides as $, DEFAULT_CONTEXT_TOKENS as $i, ANTHROPIC_PROVIDER_BRAND_ID as $n, QWEN_API_ROUTE_ID as $r, resolveSubagentSpawnModelSelection as $t, GroupPolicySchema as A, listProviderBrandManifests as Ai, markAuthProfileGood as An, MINIMAX_PORTAL_ROUTE_ID as Ar, isSafeExecutableValue as At, MODEL_APIS as B, OPENCODE_ZEN_MODEL_IDS as Bi, normalizeProviderId$1 as Bn, OPENAI_API_MODEL_IDS as Br, buildModelAliasIndex as Bt, resolveIMessageAttachmentRoots as C, applyTestPluginDefaults as Ca, XIAOMI_ROUTE_ID as Ci, markAuthProfileFailure as Cn, LITELLM_PROVIDER_BRAND_ID as Cr, unwrapKnownDispatchWrapperInvocation as Ct, BlockStreamingCoalesceSchema as D, resolveMemorySlotDecision as Da, getProviderBrandManifestForRoute as Di, dedupeProfileIds as Dn, MINIMAX_API_ROUTE_ID as Dr, normalizeSafeBinProfileFixtures as Dt, ToolPolicySchema as E, resolveEffectiveEnableState as Ea, ZAI_ROUTE_ID as Ei, resolveApiKeyForProfile as En, LMSTUDIO_ROUTE_ID as Er, SAFE_BIN_PROFILES as Et, TtsConfigSchema as F, XIAOMI_MODEL_IDS as Fi, acquireFileLock as Fn, MOONSHOT_MODEL_IDS as Fr, resolveTelegramPreviewStreamMode as Ft, isAvatarDataUrl as G, BASE_THINKING_LEVELS as Gi, safeStatSync as Gn, OPENCODE_ZEN_ROUTE_ID as Gr, normalizeModelRef as Gt, parseDurationMs as H, CLOUDFLARE_AI_GATEWAY_MODEL_IDS as Hi, loadPluginManifestRegistry as Hn, OPENAI_CODEX_ROUTE_ID as Hr, inferUniqueProviderFromConfiguredModels as Ht, TtsModeSchema as I, VERCEL_AI_GATEWAY_MODEL_IDS as Ii, withFileLock as In, MOONSHOT_PROVIDER_BRAND_ID as Ir, DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH as It, isSupportedLocalAvatarExtension as J, listThinkingLevels as Ji, normalizeSecretInput as Jn, OPENROUTER_ROUTE_ID as Jr, resolveConfiguredModelRef as Jt, isAvatarHttpUrl as K, formatThinkingLevels as Ki, resolveAuthProfileDisplayLabel as Kn, OPENROUTER_MODEL_IDS as Kr, normalizeProviderId as Kt, TtsProviderSchema as L, VENICE_MODEL_IDS as Li, resolveProcessScopedMap as Ln, MOONSHOT_ROUTE_ID as Lr, resolveAgentMaxConcurrent as Lt, MarkdownTableModeSchema as M, providerModelRecommendationRank as Mi, resolveAuthStorePathForDisplay as Mn, MISTRAL_MODEL_IDS as Mr, resolveDiscordPreviewStreamMode as Mt, ReplyRuntimeConfigSchemaShape as N, resolveProviderRouteModelCapability as Ni, resolveFasedAgentAgentDir as Nn, MISTRAL_PROVIDER_BRAND_ID as Nr, resolveSlackNativeStreaming as Nt, DmConfigSchema as O, resolvePluginAdminRpcActionGrant as Oa, isOpenAISignInRuntimeModelSupported as Oi, listProfilesForProvider as On, MINIMAX_CN_ROUTE_ID as Or, resolveSafeBinProfiles as Ot, TtsAutoSchema as P, LITELLM_BASE_URL as Pi, resolveFasedAgentDir as Pn, MISTRAL_ROUTE_ID as Pr, resolveSlackStreamingMode as Pt, getConfigOverrides as Q, supportsXHighThinking as Qi, ANTHROPIC_MODEL_IDS as Qn, QWEN_API_MODEL_IDS as Qr, resolveReasoningDefault as Qt, normalizeAllowFrom as R, TOGETHER_MODEL_IDS as Ri, isPidAlive as Rn, OLLAMA_PROVIDER_BRAND_ID as Rr, buildAllowedModelSet as Rt, mergeInboundPathRoots as S, parseBooleanValue as Sa, XIAOMI_PROVIDER_BRAND_ID as Si, isProfileInCooldown as Sn, KIMI_CODING_ROUTE_ID as Sr, isShellWrapperExecutable as St, normalizeScpRemoteHost as T, normalizePluginsConfig as Ta, ZAI_PROVIDER_BRAND_ID as Ti, resolveProfilesUnavailableReason as Tn, LMSTUDIO_PROVIDER_BRAND_ID as Tr, splitShellArgs as Tt, parseByteSize as U, CLOUDFLARE_AI_GATEWAY_PROVIDER_BRAND_ID as Ui, discoverFasedAgentPlugins as Un, OPENAI_PROVIDER_BRAND_ID as Ur, isCliProvider as Ut, getBlockedNetworkModeReason as V, HUGGINGFACE_MODEL_IDS as Vi, clearPluginManifestRegistryCache as Vn, OPENAI_API_ROUTE_ID as Vr, findNormalizedProviderValue as Vt, AVATAR_MAX_BYTES as W, CLOUDFLARE_AI_GATEWAY_ROUTE_ID as Wi, isPathInside as Wn, OPENCODE_ZEN_PROVIDER_BRAND_ID as Wr, modelKey as Wt, resolveAvatarMime as X, resolveModelThinkingCapability as Xi, coerceSecretRef as Xn, QIANFAN_PROVIDER_BRAND_ID as Xr, resolveExplicitConfiguredModelRef as Xt, isWorkspaceRelativeAvatarPath as Y, normalizeThinkLevel as Yi, assertSecretInputResolved as Yn, QIANFAN_MODEL_IDS as Yr, resolveDefaultModelForAgent as Yt, validateJsonSchemaValue as Z, supportsThinkingLevel as Zi, splitTrailingAuthProfile as Zn, QIANFAN_ROUTE_ID as Zr, resolveModelRefFromString as Zt, TELEGRAM_COMMAND_NAME_PATTERN as _, sanitizeHostExecEnv as _a, VOLCENGINE_PROVIDER_BRAND_ID as _i, normalizeModelCatalogProviderId as _n, GOOGLE_GEMINI_MODEL_IDS as _r, matchAllowlist as _t, readConfigFileSnapshotForWrite as a, getPackageManifestMetadata as aa, TOGETHER_PROVIDER_BRAND_ID as ai, getApiKeyForModel as an, BYTEPLUS_PROVIDER_BRAND_ID as ar, unsetConfigValueAtPath as at, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS as b, resolveCliName as ba, XAI_PROVIDER_BRAND_ID as bi, resolveAuthProfileOrder as bn, HUGGINGFACE_ROUTE_ID as br, extractShellWrapperInlineCommand as bt, validateConfigObjectWithPlugins as c, formatErrorMessage as ca, VENICE_ROUTE_ID as ci, resolveApiKeyForProvider as cn, CHUTES_PROVIDER_BRAND_ID as cr, isTrustedSafeBinPath as ct, GoogleChatConfigSchema as d, extractArchive as da, VLLM_PROVIDER_BRAND_ID as di, CURRENT_MODEL_PROVIDER_CATALOG as dn, COPILOT_PROXY_MODEL_IDS as dr, validateSafeBinArgv as dt, DEFAULT_MODEL as ea, QWEN_CODING_PLAN_MODEL_IDS as ei, resolveThinkingDefault as en, ANTHROPIC_ROUTE_ID as er, setConfigOverride as et, IMessageConfigSchema as f, getShellPathFromLoginShell as fa, VLLM_ROUTE_ID as fi, cloneCurrentModelProvider as fn, COPILOT_PROXY_ROUTE_ID as fr, analyzeShellCommand as ft, TelegramConfigSchema as g, isDangerousHostInheritedEnvVarName as ga, VOLCENGINE_PLAN_ROUTE_ID as gi, normalizeModelCatalogModelId as gn, GOOGLE_GEMINI_CLI_ROUTE_ID as gr, DEFAULT_SAFE_BINS as gt, SlackConfigSchema as h, isDangerousHostEnvVarName as ha, VOLCENGINE_MODEL_IDS as hi, mergeModelCatalogRowsByAuthority as hn, GOOGLE_API_ROUTE_ID as hr, splitCommandChain as ht, readConfigFileSnapshot as i, resolvePluginInstallDir as ia, SYNTHETIC_ROUTE_ID as ii, resolveImplicitProviders as in, BYTEPLUS_PLAN_ROUTE_ID as ir, setConfigValueAtPath as it, MarkdownConfigSchema as j, lookupProviderManifestModelCapability as ji, ensureAuthProfileStore as jn, MINIMAX_PROVIDER_BRAND_ID as jr, mapStreamingModeToSlackLegacyDraftStreamMode as jt, DmPolicySchema as k, applyExclusiveSlotSelection as ka, isStandardProviderCatalogEntry as ki, listProvidersWithStoredCredentials as kn, MINIMAX_MODEL_IDS as kr, applyMergePatch as kt, WhatsAppConfigSchema as l, formatUncaughtError as la, VERCEL_AI_GATEWAY_PROVIDER_BRAND_ID as li, resolveEnvApiKey as ln, CHUTES_ROUTE_ID as lr, listWritableExplicitTrustedSafeBinDirs as lt, SignalConfigSchema as m, isDangerousHostEnvOverrideVarName as ma, VOLCENGINE_CODING_ROUTE_ID as mi, buildModelCatalogMergeKey as mn, CUSTOM_PROVIDER_ROUTE_ID as mr, isWindowsPlatform as mt, loadConfig as n, VERSION as na, QWEN_PROVIDER_BRAND_ID as ni, normalizeProviders as nn, BYTEPLUS_CODING_ROUTE_ID as nr, getConfigValueAtPath as nt, resolveConfigSnapshotHash as o, MANIFEST_KEY as oa, TOGETHER_ROUTE_ID as oi, getCustomProviderApiKey as on, BYTEPLUS_ROUTE_ID as or, ensurePluginAllowlisted as ot, MSTeamsConfigSchema as p, resolveShellEnvFallbackTimeoutMs as pa, VOLCENGINE_CODING_MODEL_IDS as pi, listCurrentModelCatalogRows as pn, CUSTOM_PROVIDER_BRAND_ID as pr, buildEnforcedShellCommand as pt, isPathWithinRoot as q, formatXHighModelHint as qi, isPrivateNetworkBaseUrl as qn, OPENROUTER_PROVIDER_BRAND_ID as qr, parseModelRef as qt, parseConfigJson5 as r, installPluginFromNpmSpec as ra, SYNTHETIC_PROVIDER_BRAND_ID as ri, resolveImplicitCopilotProvider as rn, BYTEPLUS_MODEL_IDS as rr, parseConfigPath as rt, writeConfigFile as s, extractErrorCode as sa, VENICE_PROVIDER_BRAND_ID as si, requireApiKey as sn, CHUTES_MODEL_IDS as sr, getTrustedSafeBinDirs as st, createConfigIO as t, DEFAULT_PROVIDER as ta, QWEN_CODING_PLAN_ROUTE_ID as ti, normalizeGoogleModelId as tn, BYTEPLUS_CODING_MODEL_IDS as tr, unsetConfigOverride as tt, DiscordConfigSchema as u, isErrno as ua, VERCEL_AI_GATEWAY_ROUTE_ID as ui, resolveModelAuthMode as un, COPILOT_PROVIDER_BRAND_ID as ur, normalizeTrustedSafeBinDirs as ut, normalizeTelegramCommandName as v, resolveOwnerDisplaySetting as va, VOLCENGINE_ROUTE_ID as vi, normalizeProviderCatalogRows as vn, GOOGLE_PROVIDER_BRAND_ID as vr, resolveAllowlistCandidatePath as vt, resolveIMessageRemoteAttachmentRoots as w, isPluginRuntimeSessionReadAllowed as wa, ZAI_MODEL_IDS as wi, markAuthProfileUsed as wn, LITELLM_ROUTE_ID as wr, unwrapKnownShellMultiplexerInvocation as wt, isInboundPathAllowed as x, isTruthyEnvValue as xa, XAI_ROUTE_ID as xi, getSoonestCooldownExpiry as xn, KIMI_CODING_MODEL_IDS as xr, isDispatchWrapperExecutable as xt, resolveTelegramCustomCommands as y, formatCliCommand as ya, XAI_MODEL_IDS as yi, auth_profiles_exports as yn, HUGGINGFACE_PROVIDER_BRAND_ID as yr, resolveCommandResolutionFromArgv as yt, requireOpenAllowFrom as z, SYNTHETIC_MODEL_IDS as zi, findNormalizedProviderValue$1 as zn, OLLAMA_ROUTE_ID as zr, buildConfiguredAllowlistKeys as zt };
|