@xopcai/xopc 0.0.127 → 0.0.129
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CgGgO4OV.js → agent-avatar-dicebear-DHzfg5D-.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CMxKKFQD.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-ptk9c5BN.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-BnHQW7Hv.js → appearance-settings-bYeEj3IW.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-DdZvDf5B.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-5NXT7Zqv.js → archive-plugin-Dy6lsTHw.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DghwhYe0.js → attachment-load-qOtBYR6Y.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-DYmESgwl.js → automation-suggestion-card-BFH-RfaV.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-B8JTjkCr.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DSbPKdWX.js → binary-plugins-DJvi_thc.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CoZ-_np-.js → block-editor-DlMnizlt.js} +4 -4
- package/dist/gateway/static/root/assets/browser-settings-page-slHLiZgi.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-D4q7vHVJ.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Dng8Grpv.js +1 -0
- package/dist/gateway/static/root/assets/channel-recipient-api-BrW5Kcgc.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-KIsISXw0.js +1 -0
- package/dist/gateway/static/root/assets/{code-editor-gbRgS14t.js → code-editor--tMO38Tr.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-C5fx4Qs9.js +2 -0
- package/dist/gateway/static/root/assets/desktop-pet-Jmdn6q47.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-npJ0Oh5p.js → desktop-pet-settings-B-u63N4e.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BR2ItBuf.js → directory-picker-path-field-8p1ehIHn.js} +1 -1
- package/dist/gateway/static/root/assets/dreaming-settings-CCkKP-I4.js +3 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-Tl0f1rNv.js → extension-debug-page-DJ1ABK95.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Ck7QuwE3.js → extension-page-CP9P2lGM.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-DnhU-tx0.js +1 -0
- package/dist/gateway/static/root/assets/fetch-BMjlW0g1.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-api-CjxDn46s.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-TING7224.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Yh8h3hkj.js → gateway-startup-retry-CY5W2Pp4.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-2lPbGfp3.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-DHWVRafk.js +4 -0
- package/dist/gateway/static/root/assets/goals-config-api-BqhuxG8P.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-CMk-9ZYN.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-BHzOAU_l.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-BQIm0P3V.js +1 -0
- package/dist/gateway/static/root/assets/{html-workspace-editor-DV90ddkE.js → html-workspace-editor-COqmtESs.js} +1 -1
- package/dist/gateway/static/root/assets/index-C4k6QSXw.js +257 -0
- package/dist/gateway/static/root/assets/index-EKmpPvZj.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CfQrt_Rb.js → keyboard-shortcuts-settings-BrENZzM7.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-BiL302Ve.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-editor-BFOjBBla.js → markdown-editor-jD1LPiP-.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-BwiMdCf_.js → markdown-split-BYF4ReGM.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-DhoizyZv.js → media-plugins-CpQDz-QJ.js} +1 -1
- package/dist/gateway/static/root/assets/messages-YzjnURPJ.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-CFPpl3Cq.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-BurgcdVZ.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-BAELRM_O.js +2 -0
- package/dist/gateway/static/root/assets/{page-tabs-DDC2t4Z8.js → page-tabs-RnYYOIWO.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BTmk-XDM.js → preview-open-alternatives-CTRt06Ri.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-iXX1Ceo2.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-GDVTFAY7.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BUrbUnwv.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-DqU-yKIh.js → save-bar-controls-c4pZeikq.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CUttkoSB.js → schedule-field-Cb6R7iuP.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CVSQA9nI.js → schema-form-BqET_hEP.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CiOreA2k.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-C-qvptlu.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-CK7ogS-P.js → settings-collapsible-section-DuOvqNsI.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Bugp38Fa.js → settings-form-section-DptSsbWd.js} +1 -1
- package/dist/gateway/static/root/assets/settings-loading-skeleton-BlVfBCb9.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-DBRWwdhh.js → settings-page-layout-DVt69dJJ.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-xQx2Pkg5.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-DWB8VdLK.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-8m_ACH0z.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-CgxfhNxI.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BBFUOxmf.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-bo695odu.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DJ6YuLqR.js → system-settings-panel-CW22OkZ4.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-B0T7N8Km.js → typed-models-lib-BqpGAKxV.js} +1 -1
- package/dist/gateway/static/root/assets/url-DFGNSBNT.js +1 -0
- package/dist/gateway/static/root/assets/use-channel-catalog-CPdJ0o0i.js +1 -0
- package/dist/gateway/static/root/assets/user-profile-settings-panel-CERVLuaW.js +1 -0
- package/dist/gateway/static/root/assets/{utils-CehXcWAY.js → utils-BnmysurA.js} +1 -1
- package/dist/gateway/static/root/assets/vendor-codemirror-C1WKjCk5.js +45 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-Jr3jvPcB.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-B-8rex4u.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-c4jeaohQ.js → workflow-run-setup-panel-Ci9GSPnS.js} +2 -2
- package/dist/gateway/static/root/assets/{workflow-start-dialog-ENRHjoqa.js → workflow-start-dialog-BhDj8pqH.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-Brb3UGvs.js +18 -0
- package/dist/gateway/static/root/index.html +7 -6
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +3 -0
- package/dist/src/agent/agent-manager.js +14 -6
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/capabilities/definitions.d.ts +14 -0
- package/dist/src/agent/capabilities/definitions.js +19 -0
- package/dist/src/agent/capabilities/definitions.js.map +1 -1
- package/dist/src/agent/goals/post-turn.js +23 -2
- package/dist/src/agent/goals/post-turn.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +4 -0
- package/dist/src/agent/messaging/command-handler.js +6 -0
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -0
- package/dist/src/agent/service.js +23 -0
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/skills/hub-lock.d.ts +5 -5
- package/dist/src/agent/skills/hub-lock.js +12 -12
- package/dist/src/agent/skills/hub-lock.js.map +1 -1
- package/dist/src/agent/skills/hub-pull.d.ts +15 -0
- package/dist/src/agent/skills/hub-pull.js +299 -24
- package/dist/src/agent/skills/hub-pull.js.map +1 -1
- package/dist/src/agent/skills/index.js +4 -40
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/install-target.d.ts +3 -0
- package/dist/src/agent/skills/install-target.js +11 -0
- package/dist/src/agent/skills/install-target.js.map +1 -0
- package/dist/src/agent/skills/managed-store.d.ts +5 -3
- package/dist/src/agent/skills/managed-store.js +10 -9
- package/dist/src/agent/skills/managed-store.js.map +1 -1
- package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +5 -3
- package/dist/src/agent/skills/marketplace/adapters/store/adapter.js.map +1 -1
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.d.ts +21 -1
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +62 -6
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js.map +1 -1
- package/dist/src/agent/skills/marketplace/resolve-adapter.js +1 -1
- package/dist/src/agent/skills/marketplace/resolve-adapter.js.map +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +2 -2
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -6
- package/dist/src/agent/skills/skill-manager.js.map +1 -1
- package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
- package/dist/src/agent/skills/workspace-skills-dir.js +5 -1
- package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -1
- package/dist/src/agent/tools/automation-tool.d.ts +6 -6
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +20 -20
- package/dist/src/agent/tools/composio-tool.d.ts +3 -3
- package/dist/src/agent/tools/desktop-pet-tool.d.ts +7 -7
- package/dist/src/agent/tools/factory.d.ts +3 -0
- package/dist/src/agent/tools/factory.js +6 -1
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/goal-tool.d.ts +16 -16
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/skill-install-tool.d.ts +28 -0
- package/dist/src/agent/tools/skill-install-tool.js +81 -0
- package/dist/src/agent/tools/skill-install-tool.js.map +1 -0
- package/dist/src/agent/tools/skill-manage-tool.js +3 -6
- package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
- package/dist/src/agent/tools/tool-manual-tool.d.ts +2 -2
- package/dist/src/agent/tools/xopc-use-tool.d.ts +5 -5
- package/dist/src/automations/domain/types.d.ts +1 -0
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/automations/service/automation-service.js +9 -0
- package/dist/src/automations/service/automation-service.js.map +1 -1
- package/dist/src/browser/schemas.d.ts +52 -52
- package/dist/src/capabilities/store-connector.d.ts +17 -0
- package/dist/src/capabilities/store-connector.js +191 -0
- package/dist/src/capabilities/store-connector.js.map +1 -0
- package/dist/src/chat-commands/builtins/skill.d.ts +1 -0
- package/dist/src/chat-commands/builtins/skill.js +132 -0
- package/dist/src/chat-commands/builtins/skill.js.map +1 -0
- package/dist/src/chat-commands/context.d.ts +3 -0
- package/dist/src/chat-commands/context.js +2 -0
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +17 -0
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/connectors.d.ts +4 -0
- package/dist/src/cli/commands/connectors.js +96 -0
- package/dist/src/cli/commands/connectors.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/profile.js +1 -1
- package/dist/src/cli/commands/skills.js +1 -1
- package/dist/src/cli/commands/tunnel.js +1 -1
- package/dist/src/cli/commands/update.js +1 -1
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/config/schema.js +2 -2
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/connectors/health.js +1 -1
- package/dist/src/connectors/install.js +3 -1
- package/dist/src/connectors/install.js.map +1 -1
- package/dist/src/connectors/materialize.js +2 -0
- package/dist/src/connectors/materialize.js.map +1 -1
- package/dist/src/connectors/types.d.ts +19 -1
- package/dist/src/extensions/install.js +1 -1
- package/dist/src/extensions/types/manifest.d.ts +1 -1
- package/dist/src/extensions/update.js +5 -3
- package/dist/src/extensions/update.js.map +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +5 -1
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +2 -0
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/middleware/auth.d.ts +2 -2
- package/dist/src/gateway/hono/middleware/logger.d.ts +1 -1
- package/dist/src/gateway/hono/middleware/route-errors.d.ts +1 -1
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +2 -2
- package/dist/src/gateway/hono/routes/capabilities.d.ts +3 -0
- package/dist/src/gateway/hono/routes/capabilities.js +79 -0
- package/dist/src/gateway/hono/routes/capabilities.js.map +1 -0
- package/dist/src/gateway/hono/routes/commands-skills.js +81 -3
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +2 -2
- package/dist/src/gateway/hono/routes/goals.js +212 -3
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +1 -1
- package/dist/src/gateway/hono/routes/mobile.d.ts +3 -0
- package/dist/src/gateway/hono/routes/mobile.js +113 -0
- package/dist/src/gateway/hono/routes/mobile.js.map +1 -0
- package/dist/src/gateway/hono/routes/projects.js +17 -0
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +4 -1
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.d.ts +3 -3
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/service/marketplace-service.d.ts +23 -1
- package/dist/src/gateway/service/marketplace-service.js +57 -6
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +12 -2
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-contract-draft.d.ts +15 -0
- package/dist/src/goals/goal-contract-draft.js +114 -0
- package/dist/src/goals/goal-contract-draft.js.map +1 -0
- package/dist/src/goals/goal-evidence-review.d.ts +15 -0
- package/dist/src/goals/goal-evidence-review.js +91 -0
- package/dist/src/goals/goal-evidence-review.js.map +1 -0
- package/dist/src/goals/goal-runner.js +3 -1
- package/dist/src/goals/goal-runner.js.map +1 -1
- package/dist/src/goals/goal-service.d.ts +17 -1
- package/dist/src/goals/goal-service.js +44 -3
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/goals/goal-store.d.ts +18 -1
- package/dist/src/goals/goal-store.js +190 -1
- package/dist/src/goals/goal-store.js.map +1 -1
- package/dist/src/goals/index.d.ts +4 -0
- package/dist/src/goals/index.js +3 -1
- package/dist/src/goals/types.d.ts +42 -0
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/mobile/notification-service.d.ts +8 -0
- package/dist/src/mobile/notification-service.js +139 -0
- package/dist/src/mobile/notification-service.js.map +1 -0
- package/dist/src/mobile/notification-store.d.ts +28 -0
- package/dist/src/mobile/notification-store.js +134 -0
- package/dist/src/mobile/notification-store.js.map +1 -0
- package/dist/src/mobile/notification-types.d.ts +37 -0
- package/dist/src/mobile/notification-types.js +11 -0
- package/dist/src/mobile/notification-types.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/026_goal_contracts.sql +10 -0
- package/dist/src/storage/sqlite/migrations/027_mobile_notifications.sql +43 -0
- package/dist/src/storage/sqlite/migrations/028_goal_evidence_requirements.sql +47 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +44 -0
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/package.json +1 -1
- package/skills/THIRD_PARTY_NOTICES.md +16 -0
- package/skills/creative/algorithmic-art/SKILL.md +37 -0
- package/skills/creative/algorithmic-art/templates/generator-template.js +27 -0
- package/skills/creative/algorithmic-art/templates/viewer.html +27 -0
- package/skills/documents/doc-coauthoring/SKILL.md +40 -0
- package/skills/documents/doc-coauthoring/references/reader-review.md +9 -0
- package/skills/documents/docx/SKILL.md +40 -0
- package/skills/documents/docx/references/editing-checklist.md +8 -0
- package/skills/documents/docx/scripts/inspect_ooxml.py +36 -0
- package/skills/documents/docx/scripts/render_docx.py +33 -0
- package/skills/documents/pdf/SKILL.md +47 -0
- package/skills/documents/pdf/references/operations.md +16 -0
- package/skills/documents/pdf/scripts/inspect_pdf.py +41 -0
- package/skills/documents/pdf/scripts/render_pdf.py +32 -0
- package/skills/documents/pptx/SKILL.md +41 -0
- package/skills/documents/pptx/references/qa-checklist.md +6 -0
- package/skills/documents/pptx/scripts/inspect_ooxml.py +34 -0
- package/skills/documents/pptx/scripts/render_pptx.py +33 -0
- package/skills/engineering/define-goal/SKILL.md +41 -0
- package/skills/engineering/define-goal/references/objective-rubric.md +12 -0
- package/dist/gateway/static/root/assets/agents-k59l7NMb.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-DeQsTsyy.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-BG9b4abG.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-De8mVutL.js +0 -4
- package/dist/gateway/static/root/assets/browser-settings-page-C_ZRa4LF.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-hny224j-.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Drc0qLsw.js +0 -1
- package/dist/gateway/static/root/assets/channel-recipient-api-DAlOHxKJ.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CA20zBV9.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-qMyMB5te.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-XG6Vb_fZ.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-CkUZ997f.js +0 -3
- package/dist/gateway/static/root/assets/extension-settings-page-3RMhQtZ3.js +0 -1
- package/dist/gateway/static/root/assets/fetch-pg2ErdAk.js +0 -1
- package/dist/gateway/static/root/assets/gateway-config-api-DbG97ia2.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-B8cyqKk-.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-DmeW7Zz3.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DrTyGbVD.js +0 -1
- package/dist/gateway/static/root/assets/goals-config-api-CxCWGIBB.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-DV1bJhIh.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-9DrfOkP5.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-KaDpZrv0.js +0 -1
- package/dist/gateway/static/root/assets/index-C2F0Clvm.js +0 -256
- package/dist/gateway/static/root/assets/index-COQSX5d_.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-C9dpiNTF.js +0 -2
- package/dist/gateway/static/root/assets/messages-DmnbiNxU.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-zdCdmBmH.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-MpGeFfPt.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-DYCM3yd2.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-Cu0ElRnS.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DakNaUjZ.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DYKjt7L9.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CcGHDsz1.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CuFdeKNu.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-0AJoUvxi.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-D6a_hEk7.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-BtsuETKF.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-CcEFT7S9.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BcN_RuTD.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BbRZZZA5.js +0 -2
- package/dist/gateway/static/root/assets/use-channel-catalog-C6vrxdzZ.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-DZ0nKMgj.js +0 -1
- package/dist/gateway/static/root/assets/vendor-codemirror-BvNgyE1Q.js +0 -45
- package/dist/gateway/static/root/assets/voice-api-key-field-2QKflCx8.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-DfJnuWq1.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BJwwFTm_.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-api-client.js","names":[],"sources":["../../../../../../../src/agent/skills/marketplace/adapters/store/store-api-client.ts"],"sourcesContent":["/**\n * HTTP client for the public xopc-store-compatible REST API (packages list, detail, zip download).\n * Used by the store marketplace adapter and SSRF-safe download helpers.\n *\n * Facade: {@link ../../../skills-marketplace.js}.\n */\n\nimport type { Config } from '../../../../../config/schema.js';\nimport { MAX_EXTENSION_STORE_ZIP_BYTES } from '../../../../../extensions/store-zip-limits.js';\nimport { isValidSkillId, MAX_SKILL_ZIP_BYTES } from '../../../managed-store.js';\nimport type { SkillMarkdownPreviewPayload } from '../../../types.js';\n\nconst DEFAULT_STORE_BASE = 'https://store.xopc.ai';\n\n/**\n * Marketplace provider identifier. Dynamic — extensions can register additional providers\n * via `api.registerMarketplaceAdapter()`. Built-in values: 'store', 'skillhub', 'clawhub'.\n */\nexport type SkillsMarketplaceProvider = string;\n\nexport interface SkillsStoreListParams {\n q?: string;\n page?: number;\n pageSize?: number;\n sort?: 'downloads' | 'newest';\n /** Adapter-defined category id (exact match against package `categories`). */\n category?: string;\n}\n\n/** Category option for marketplace filter chips (from adapter). */\nexport interface MarketplaceCategoryOption {\n id: string;\n label: string;\n}\n\n/** Mirrors xopc-store GET /api/v1/packages list response (subset used by UI). */\nexport interface SkillsStorePackageListItem {\n id: string;\n name: string;\n type: string;\n description: string;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion?: string;\n updatedAt: string;\n /** Taxonomy / tags from the marketplace (adapter-specific). */\n categories?: string[];\n tags?: string[];\n stars?: number;\n /** Short provenance label for the row (e.g. ClawHub). */\n sourceLabel?: string;\n}\n\n/** Unified marketplace package list item (works for all adapters). */\nexport type MarketplacePackageListItem = SkillsStorePackageListItem;\n\nexport interface SkillsStoreListResponse {\n items: SkillsStorePackageListItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n}\n\nexport function resolveSkillsStoreBaseUrl(config: Config): string {\n const env = process.env.XOPC_SKILLS_STORE_URL?.trim();\n if (env) {\n try {\n return normalizeBaseUrl(new URL(env).toString());\n } catch {\n // fall through\n }\n }\n const fromConfig = config.gateway?.skillsStoreBaseUrl?.trim();\n if (fromConfig) {\n try {\n return normalizeBaseUrl(new URL(fromConfig).toString());\n } catch {\n return DEFAULT_STORE_BASE;\n }\n }\n return DEFAULT_STORE_BASE;\n}\n\nexport { MAX_EXTENSION_STORE_ZIP_BYTES };\n\n/**\n * Base URL for extension downloads (defaults to skills store host — usually store.xopc.ai).\n * Override with `XOPC_EXTENSIONS_STORE_URL`.\n */\nexport function resolveExtensionsStoreBaseUrl(config: Config): string {\n const env = process.env.XOPC_EXTENSIONS_STORE_URL?.trim();\n if (env) {\n try {\n return normalizeBaseUrl(new URL(env).toString());\n } catch {\n // fall through\n }\n }\n return resolveSkillsStoreBaseUrl(config);\n}\n\nfunction normalizeBaseUrl(url: string): string {\n return url.replace(/\\/$/, '');\n}\n\nexport function getStoreOrigin(baseUrl: string): string {\n const u = new URL(baseUrl);\n return `${u.protocol}//${u.host}`;\n}\n\n/**\n * Allow download URLs whose origin matches the configured store base (SSRF guard).\n * Production store is HTTPS-only; local dev (`http://localhost` / `127.0.0.1`) may use HTTP.\n */\nexport function assertDownloadUrlAllowed(downloadUrl: string, storeBaseUrl: string): URL {\n let u: URL;\n try {\n u = new URL(downloadUrl);\n } catch {\n throw new Error('Invalid download URL from store');\n }\n const allowed = new URL(storeBaseUrl);\n const localHttpDev =\n allowed.protocol === 'http:' &&\n (allowed.hostname === 'localhost' || allowed.hostname === '127.0.0.1');\n if (localHttpDev) {\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n throw new Error('Download URL must use HTTP or HTTPS');\n }\n } else if (u.protocol !== 'https:') {\n throw new Error('Download URL must use HTTPS');\n }\n if (u.host !== allowed.host) {\n throw new Error('Download URL host does not match configured store host');\n }\n return u;\n}\n\nasync function fetchJson<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await fetch(url, {\n ...init,\n headers: { Accept: 'application/json', ...init?.headers },\n });\n const text = await res.text();\n if (!res.ok) {\n let msg = `Store request failed (${res.status})`;\n try {\n const j = JSON.parse(text) as { error?: { message?: string } };\n if (j.error?.message) msg = j.error.message;\n } catch {\n if (text) msg = text.slice(0, 200);\n }\n throw new Error(msg);\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new Error('Store returned invalid JSON');\n }\n}\n\nexport async function listSkillPackages(\n storeBaseUrl: string,\n params: SkillsStoreListParams,\n): Promise<SkillsStoreListResponse> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const sp = new URLSearchParams();\n sp.set('type', 'skill');\n if (params.q?.trim()) sp.set('q', params.q.trim());\n if (params.page != null) sp.set('page', String(params.page));\n if (params.pageSize != null) sp.set('pageSize', String(params.pageSize));\n if (params.sort) sp.set('sort', params.sort);\n if (params.category?.trim()) sp.set('category', params.category.trim());\n\n const url = `${base}/api/v1/packages?${sp.toString()}`;\n return fetchJson<SkillsStoreListResponse>(url);\n}\n\n/** GET /api/v1/packages/:name — published skill package (public). */\nexport interface MarketplacePackageDetail {\n id: string;\n name: string;\n type: string;\n description: string;\n readme: string | null;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion: {\n version: string;\n changelog: string | null;\n publishedAt: string;\n };\n}\n\nexport async function fetchMarketplacePackageDetail(\n storeBaseUrl: string,\n packageName: string,\n): Promise<MarketplacePackageDetail> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName.trim());\n return fetchJson<MarketplacePackageDetail>(`${base}/api/v1/packages/${enc}`);\n}\n\nexport async function resolveSkillZipDownloadUrl(\n storeBaseUrl: string,\n packageName: string,\n version?: string,\n): Promise<{ downloadUrl: string; version: string }> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName);\n if (version?.trim()) {\n const v = encodeURIComponent(version.trim());\n const detail = await fetchJson<{\n downloadUrl: string;\n version: string;\n }>(`${base}/api/v1/packages/${enc}/versions/${v}`);\n if (!detail.downloadUrl) {\n throw new Error('Store version has no download URL');\n }\n assertDownloadUrlAllowed(detail.downloadUrl, base);\n return { downloadUrl: detail.downloadUrl, version: detail.version };\n }\n\n const pkg = await fetchJson<{\n name: string;\n latestVersion: { downloadUrl: string; version: string };\n }>(`${base}/api/v1/packages/${enc}`);\n if (!pkg.latestVersion?.downloadUrl) {\n throw new Error('Package has no published version');\n }\n assertDownloadUrlAllowed(pkg.latestVersion.downloadUrl, base);\n return {\n downloadUrl: pkg.latestVersion.downloadUrl,\n version: pkg.latestVersion.version,\n };\n}\n\nexport async function downloadSkillZipBuffer(\n storeBaseUrl: string,\n downloadUrl: string,\n): Promise<Buffer> {\n const base = normalizeBaseUrl(storeBaseUrl);\n assertDownloadUrlAllowed(downloadUrl, base);\n\n const res = await fetch(downloadUrl, { redirect: 'follow' });\n if (!res.ok) {\n throw new Error(`Failed to download skill archive (${res.status})`);\n }\n const len = res.headers.get('content-length');\n if (len) {\n const n = Number(len);\n if (Number.isFinite(n) && n > MAX_SKILL_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);\n }\n }\n const ab = await res.arrayBuffer();\n const buf = Buffer.from(ab);\n if (buf.length > MAX_SKILL_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);\n }\n return buf;\n}\n\n/** GET /api/v1/packages/:name — subset used for extension installs. */\nexport interface StorePublishedPackageHead {\n name: string;\n type: string;\n latestVersion: {\n version: string;\n downloadUrl: string;\n checksum?: string;\n integrity?: string;\n sha256?: string;\n };\n}\n\nexport async function resolveExtensionZipDownloadUrl(\n storeBaseUrl: string,\n packageName: string,\n version?: string,\n): Promise<{ downloadUrl: string; version: string; integrity?: string }> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName.trim());\n const meta = await fetchJson<StorePublishedPackageHead>(`${base}/api/v1/packages/${enc}`);\n if (meta.type !== 'extension') {\n throw new Error(\n `Package \"${packageName}\" has type \"${meta.type}\" (expected extension). ` +\n 'Use `xopc skills install` for skills.',\n );\n }\n if (version?.trim()) {\n const v = encodeURIComponent(version.trim());\n const detail = await fetchJson<{\n downloadUrl: string;\n version: string;\n checksum?: string;\n integrity?: string;\n sha256?: string;\n }>(`${base}/api/v1/packages/${enc}/versions/${v}`);\n if (!detail.downloadUrl) {\n throw new Error('Store version has no download URL');\n }\n assertDownloadUrlAllowed(detail.downloadUrl, base);\n return {\n downloadUrl: detail.downloadUrl,\n version: detail.version,\n integrity: detail.integrity ?? detail.checksum ?? detail.sha256,\n };\n }\n const lv = meta.latestVersion;\n if (!lv?.downloadUrl) {\n throw new Error('Package has no published version');\n }\n assertDownloadUrlAllowed(lv.downloadUrl, base);\n return {\n downloadUrl: lv.downloadUrl,\n version: lv.version,\n integrity: lv.integrity ?? lv.checksum ?? lv.sha256,\n };\n}\n\nexport async function downloadExtensionStoreZipBuffer(\n storeBaseUrl: string,\n downloadUrl: string,\n): Promise<Buffer> {\n const base = normalizeBaseUrl(storeBaseUrl);\n assertDownloadUrlAllowed(downloadUrl, base);\n const res = await fetch(downloadUrl, { redirect: 'follow' });\n if (!res.ok) {\n throw new Error(`Failed to download extension archive (${res.status})`);\n }\n const len = res.headers.get('content-length');\n if (len) {\n const n = Number(len);\n if (Number.isFinite(n) && n > MAX_EXTENSION_STORE_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`);\n }\n }\n const ab = await res.arrayBuffer();\n const buf = Buffer.from(ab);\n if (buf.length > MAX_EXTENSION_STORE_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`);\n }\n return buf;\n}\n\nexport function skillIdForMarketplaceInstall(packageName: string): string | undefined {\n const trimmed = packageName.trim();\n if (!trimmed) return undefined;\n return isValidSkillId(trimmed) ? trimmed : undefined;\n}\n\n/**\n * Unified marketplace list response (adapter fills `provider`).\n */\nexport interface UnifiedMarketplaceListResponse {\n items: MarketplacePackageListItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n provider: string;\n}\n\n/**\n * Unified marketplace package detail response.\n */\nexport interface UnifiedMarketplacePackageDetail extends MarketplacePackageDetail {\n provider: string;\n /** Gateway-normalized structured meta + body rendered by the console. */\n skillDocPreview: SkillMarkdownPreviewPayload;\n /** SkillHub-specific fields */\n skillHubInfo?: {\n category: string;\n installs: number;\n stars: number;\n securityReports?: {\n keen?: { status: string; statusText: string; reportUrl?: string };\n sanbu?: { status: string; statusText: string; reportUrl?: string };\n };\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store-api-client.js","names":[],"sources":["../../../../../../../src/agent/skills/marketplace/adapters/store/store-api-client.ts"],"sourcesContent":["/**\n * HTTP client for the public xopc-store-compatible REST API (packages list, detail, zip download).\n * Used by the store marketplace adapter and SSRF-safe download helpers.\n *\n * Facade: {@link ../../../skills-marketplace.js}.\n */\n\nimport { createHash } from 'node:crypto';\n\nimport type { Config } from '../../../../../config/schema.js';\nimport { MAX_EXTENSION_STORE_ZIP_BYTES } from '../../../../../extensions/store-zip-limits.js';\nimport { isValidSkillId, MAX_SKILL_ZIP_BYTES } from '../../../managed-store.js';\nimport type { SkillMarkdownPreviewPayload } from '../../../types.js';\n\nconst DEFAULT_STORE_BASE = 'https://store.xopc.ai';\n\n/**\n * Marketplace provider identifier. Dynamic — extensions can register additional providers\n * via `api.registerMarketplaceAdapter()`. Built-in values: 'store', 'skillhub', 'clawhub'.\n */\nexport type SkillsMarketplaceProvider = string;\n\nexport interface SkillsStoreListParams {\n q?: string;\n page?: number;\n pageSize?: number;\n sort?: 'downloads' | 'newest';\n /** Adapter-defined category id (exact match against package `categories`). */\n category?: string;\n}\n\n/** Category option for marketplace filter chips (from adapter). */\nexport interface MarketplaceCategoryOption {\n id: string;\n label: string;\n}\n\n/** Mirrors xopc-store GET /api/v1/packages list response (subset used by UI). */\nexport interface SkillsStorePackageListItem {\n id: string;\n name: string;\n type: string;\n description: string;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion?: string;\n updatedAt: string;\n /** Taxonomy / tags from the marketplace (adapter-specific). */\n categories?: string[];\n tags?: string[];\n stars?: number;\n /** Short provenance label for the row (e.g. ClawHub). */\n sourceLabel?: string;\n}\n\n/** Unified marketplace package list item (works for all adapters). */\nexport type MarketplacePackageListItem = SkillsStorePackageListItem;\n\nexport interface SkillsStoreListResponse {\n items: SkillsStorePackageListItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n}\n\nexport function resolveSkillsStoreBaseUrl(config: Config): string {\n const env = process.env.XOPC_SKILLS_STORE_URL?.trim();\n if (env) {\n try {\n return normalizeBaseUrl(new URL(env).toString());\n } catch {\n // fall through\n }\n }\n const fromConfig = config.gateway?.skillsStoreBaseUrl?.trim();\n if (fromConfig) {\n try {\n return normalizeBaseUrl(new URL(fromConfig).toString());\n } catch {\n return DEFAULT_STORE_BASE;\n }\n }\n return DEFAULT_STORE_BASE;\n}\n\nexport { MAX_EXTENSION_STORE_ZIP_BYTES };\n\n/**\n * Base URL for extension downloads (defaults to skills store host — usually store.xopc.ai).\n * Override with `XOPC_EXTENSIONS_STORE_URL`.\n */\nexport function resolveExtensionsStoreBaseUrl(config: Config): string {\n const env = process.env.XOPC_EXTENSIONS_STORE_URL?.trim();\n if (env) {\n try {\n return normalizeBaseUrl(new URL(env).toString());\n } catch {\n // fall through\n }\n }\n return resolveSkillsStoreBaseUrl(config);\n}\n\nfunction normalizeBaseUrl(url: string): string {\n return url.replace(/\\/$/, '');\n}\n\nexport function getStoreOrigin(baseUrl: string): string {\n const u = new URL(baseUrl);\n return `${u.protocol}//${u.host}`;\n}\n\n/**\n * Allow download URLs whose origin matches the configured store base (SSRF guard).\n * Production store is HTTPS-only; local dev (`http://localhost` / `127.0.0.1`) may use HTTP.\n */\nexport function assertDownloadUrlAllowed(downloadUrl: string, storeBaseUrl: string): URL {\n let u: URL;\n try {\n u = new URL(downloadUrl);\n } catch {\n throw new Error('Invalid download URL from store');\n }\n const allowed = new URL(storeBaseUrl);\n const localHttpDev =\n allowed.protocol === 'http:' &&\n (allowed.hostname === 'localhost' || allowed.hostname === '127.0.0.1');\n if (localHttpDev) {\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n throw new Error('Download URL must use HTTP or HTTPS');\n }\n } else if (u.protocol !== 'https:') {\n throw new Error('Download URL must use HTTPS');\n }\n if (u.host !== allowed.host) {\n throw new Error('Download URL host does not match configured store host');\n }\n return u;\n}\n\nasync function fetchJson<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await fetch(url, {\n ...init,\n headers: { Accept: 'application/json', ...init?.headers },\n });\n const text = await res.text();\n if (!res.ok) {\n let msg = `Store request failed (${res.status})`;\n try {\n const j = JSON.parse(text) as { error?: { message?: string } };\n if (j.error?.message) msg = j.error.message;\n } catch {\n if (text) msg = text.slice(0, 200);\n }\n throw new Error(msg);\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new Error('Store returned invalid JSON');\n }\n}\n\nexport async function listSkillPackages(\n storeBaseUrl: string,\n params: SkillsStoreListParams,\n): Promise<SkillsStoreListResponse> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const sp = new URLSearchParams();\n sp.set('type', 'skill');\n if (params.q?.trim()) sp.set('q', params.q.trim());\n if (params.page != null) sp.set('page', String(params.page));\n if (params.pageSize != null) sp.set('pageSize', String(params.pageSize));\n if (params.sort) sp.set('sort', params.sort);\n if (params.category?.trim()) sp.set('category', params.category.trim());\n\n const url = `${base}/api/v1/packages?${sp.toString()}`;\n return fetchJson<SkillsStoreListResponse>(url);\n}\n\n/** Public connector catalog exposed by xopc-store. */\nexport async function listConnectorPackages(\n storeBaseUrl: string,\n params: SkillsStoreListParams,\n): Promise<SkillsStoreListResponse> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const sp = new URLSearchParams();\n sp.set('type', 'connector');\n if (params.q?.trim()) sp.set('q', params.q.trim());\n if (params.page != null) sp.set('page', String(params.page));\n if (params.pageSize != null) sp.set('pageSize', String(params.pageSize));\n if (params.sort) sp.set('sort', params.sort);\n if (params.category?.trim()) sp.set('category', params.category.trim());\n return fetchJson<SkillsStoreListResponse>(`${base}/api/v1/packages?${sp.toString()}`);\n}\n\n/** GET /api/v1/packages/:name — published skill package (public). */\nexport interface MarketplacePackageDetail {\n id: string;\n name: string;\n type: string;\n description: string;\n readme: string | null;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion: {\n version: string;\n changelog: string | null;\n publishedAt: string;\n };\n}\n\nexport interface StoreConnectorPackageDetail {\n id: string;\n name: string;\n type: 'connector';\n description: string;\n latestVersion: {\n version: string;\n manifest: unknown;\n downloadUrl: string;\n sha256: string | null;\n };\n}\n\nexport async function fetchStoreConnectorPackageDetail(\n storeBaseUrl: string,\n packageName: string,\n version?: string,\n): Promise<StoreConnectorPackageDetail> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName.trim());\n const pkg = await fetchJson<StoreConnectorPackageDetail>(`${base}/api/v1/packages/${enc}`);\n if (pkg.type !== 'connector') {\n throw new Error(`Package \"${packageName}\" has type \"${pkg.type}\" (expected connector).`);\n }\n if (!version?.trim() || version.trim() === pkg.latestVersion.version) {\n assertDownloadUrlAllowed(pkg.latestVersion.downloadUrl, base);\n return pkg;\n }\n const resolvedVersion = encodeURIComponent(version.trim());\n const detail = await fetchJson<{\n version: string;\n manifest: unknown;\n downloadUrl: string;\n sha256: string | null;\n }>(`${base}/api/v1/packages/${enc}/versions/${resolvedVersion}`);\n assertDownloadUrlAllowed(detail.downloadUrl, base);\n return { ...pkg, latestVersion: detail };\n}\n\nexport async function fetchMarketplacePackageDetail(\n storeBaseUrl: string,\n packageName: string,\n): Promise<MarketplacePackageDetail> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName.trim());\n return fetchJson<MarketplacePackageDetail>(`${base}/api/v1/packages/${enc}`);\n}\n\nexport async function resolveSkillZipDownloadUrl(\n storeBaseUrl: string,\n packageName: string,\n version?: string,\n): Promise<{ downloadUrl: string; version: string; sha256?: string }> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName);\n if (version?.trim()) {\n const v = encodeURIComponent(version.trim());\n const detail = await fetchJson<{\n downloadUrl: string;\n version: string;\n sha256?: string | null;\n }>(`${base}/api/v1/packages/${enc}/versions/${v}`);\n if (!detail.downloadUrl) {\n throw new Error('Store version has no download URL');\n }\n assertDownloadUrlAllowed(detail.downloadUrl, base);\n return {\n downloadUrl: detail.downloadUrl,\n version: detail.version,\n ...(detail.sha256 ? { sha256: detail.sha256 } : {}),\n };\n }\n\n const pkg = await fetchJson<{\n name: string;\n latestVersion: { downloadUrl: string; version: string; sha256?: string | null };\n }>(`${base}/api/v1/packages/${enc}`);\n if (!pkg.latestVersion?.downloadUrl) {\n throw new Error('Package has no published version');\n }\n assertDownloadUrlAllowed(pkg.latestVersion.downloadUrl, base);\n return {\n downloadUrl: pkg.latestVersion.downloadUrl,\n version: pkg.latestVersion.version,\n ...(pkg.latestVersion.sha256 ? { sha256: pkg.latestVersion.sha256 } : {}),\n };\n}\n\n/** Verify Store-provided immutable artifact digest before any local installation. */\nexport function verifyStoreArtifactSha256(buffer: Buffer, expected: string | null | undefined): void {\n if (!expected || !/^[a-f0-9]{64}$/i.test(expected)) {\n throw new Error('Store version is missing a valid SHA-256 checksum');\n }\n const actual = createHash('sha256').update(buffer).digest('hex');\n if (actual !== expected.toLowerCase()) {\n throw new Error('Store artifact checksum verification failed');\n }\n}\n\nexport async function downloadSkillZipBuffer(\n storeBaseUrl: string,\n downloadUrl: string,\n expectedSha256?: string,\n): Promise<Buffer> {\n const base = normalizeBaseUrl(storeBaseUrl);\n assertDownloadUrlAllowed(downloadUrl, base);\n\n const res = await fetch(downloadUrl, { redirect: 'follow' });\n if (!res.ok) {\n throw new Error(`Failed to download skill archive (${res.status})`);\n }\n const len = res.headers.get('content-length');\n if (len) {\n const n = Number(len);\n if (Number.isFinite(n) && n > MAX_SKILL_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);\n }\n }\n const ab = await res.arrayBuffer();\n const buf = Buffer.from(ab);\n if (buf.length > MAX_SKILL_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);\n }\n if (expectedSha256 !== undefined) verifyStoreArtifactSha256(buf, expectedSha256);\n return buf;\n}\n\n/** GET /api/v1/packages/:name — subset used for extension installs. */\nexport interface StorePublishedPackageHead {\n name: string;\n type: string;\n latestVersion: {\n version: string;\n downloadUrl: string;\n checksum?: string;\n integrity?: string;\n sha256?: string;\n };\n}\n\nexport async function resolveExtensionZipDownloadUrl(\n storeBaseUrl: string,\n packageName: string,\n version?: string,\n): Promise<{ downloadUrl: string; version: string; integrity?: string; sha256?: string }> {\n const base = normalizeBaseUrl(storeBaseUrl);\n const enc = encodeURIComponent(packageName.trim());\n const meta = await fetchJson<StorePublishedPackageHead>(`${base}/api/v1/packages/${enc}`);\n if (meta.type !== 'extension') {\n throw new Error(\n `Package \"${packageName}\" has type \"${meta.type}\" (expected extension). ` +\n 'Use `xopc skills install` for skills.',\n );\n }\n if (version?.trim()) {\n const v = encodeURIComponent(version.trim());\n const detail = await fetchJson<{\n downloadUrl: string;\n version: string;\n checksum?: string;\n integrity?: string;\n sha256?: string;\n }>(`${base}/api/v1/packages/${enc}/versions/${v}`);\n if (!detail.downloadUrl) {\n throw new Error('Store version has no download URL');\n }\n assertDownloadUrlAllowed(detail.downloadUrl, base);\n return {\n downloadUrl: detail.downloadUrl,\n version: detail.version,\n integrity: detail.integrity ?? detail.checksum ?? detail.sha256,\n ...(detail.sha256 ? { sha256: detail.sha256 } : {}),\n };\n }\n const lv = meta.latestVersion;\n if (!lv?.downloadUrl) {\n throw new Error('Package has no published version');\n }\n assertDownloadUrlAllowed(lv.downloadUrl, base);\n return {\n downloadUrl: lv.downloadUrl,\n version: lv.version,\n integrity: lv.integrity ?? lv.checksum ?? lv.sha256,\n ...(lv.sha256 ? { sha256: lv.sha256 } : {}),\n };\n}\n\nexport async function downloadExtensionStoreZipBuffer(\n storeBaseUrl: string,\n downloadUrl: string,\n): Promise<Buffer> {\n const base = normalizeBaseUrl(storeBaseUrl);\n assertDownloadUrlAllowed(downloadUrl, base);\n const res = await fetch(downloadUrl, { redirect: 'follow' });\n if (!res.ok) {\n throw new Error(`Failed to download extension archive (${res.status})`);\n }\n const len = res.headers.get('content-length');\n if (len) {\n const n = Number(len);\n if (Number.isFinite(n) && n > MAX_EXTENSION_STORE_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`);\n }\n }\n const ab = await res.arrayBuffer();\n const buf = Buffer.from(ab);\n if (buf.length > MAX_EXTENSION_STORE_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`);\n }\n return buf;\n}\n\nexport async function downloadConnectorStoreZipBuffer(\n storeBaseUrl: string,\n downloadUrl: string,\n): Promise<Buffer> {\n const base = normalizeBaseUrl(storeBaseUrl);\n assertDownloadUrlAllowed(downloadUrl, base);\n const res = await fetch(downloadUrl, { redirect: 'error' });\n if (!res.ok) {\n throw new Error(`Failed to download connector archive (${res.status})`);\n }\n const maxBytes = 1024 * 1024;\n const len = res.headers.get('content-length');\n if (len && Number(len) > maxBytes) {\n throw new Error(`Connector archive exceeds maximum size (${maxBytes} bytes)`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n if (buf.length > maxBytes) {\n throw new Error(`Connector archive exceeds maximum size (${maxBytes} bytes)`);\n }\n return buf;\n}\n\nexport function skillIdForMarketplaceInstall(packageName: string): string | undefined {\n const trimmed = packageName.trim();\n if (!trimmed) return undefined;\n return isValidSkillId(trimmed) ? trimmed : undefined;\n}\n\n/**\n * Unified marketplace list response (adapter fills `provider`).\n */\nexport interface UnifiedMarketplaceListResponse {\n items: MarketplacePackageListItem[];\n meta: { page: number; pageSize: number; total: number; totalPages: number };\n provider: string;\n}\n\n/**\n * Unified marketplace package detail response.\n */\nexport interface UnifiedMarketplacePackageDetail extends MarketplacePackageDetail {\n provider: string;\n /** Gateway-normalized structured meta + body rendered by the console. */\n skillDocPreview: SkillMarkdownPreviewPayload;\n /** SkillHub-specific fields */\n skillHubInfo?: {\n category: string;\n installs: number;\n stars: number;\n securityReports?: {\n keen?: { status: string; statusText: string; reportUrl?: string };\n sanbu?: { status: string; statusText: string; reportUrl?: string };\n };\n };\n}\n"],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ function resolveSkillsMarketplaceProvider(config) {
|
|
|
9
9
|
if (env && isRegisteredProvider(env)) return env;
|
|
10
10
|
const fromConfig = config.gateway?.skillsMarketplaceProvider?.trim().toLowerCase();
|
|
11
11
|
if (fromConfig && isRegisteredProvider(fromConfig)) return fromConfig;
|
|
12
|
-
return "
|
|
12
|
+
return "store";
|
|
13
13
|
}
|
|
14
14
|
function getMarketplaceProviderDisplayName(provider) {
|
|
15
15
|
return getProviderDisplayName(provider);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-adapter.js","names":[],"sources":["../../../../../src/agent/skills/marketplace/resolve-adapter.ts"],"sourcesContent":["import type { Config } from '../../../config/schema.js';\n\nimport type { SkillsMarketplaceAdapter } from './adapter.types.js';\nimport {\n getRegisteredAdapter,\n getProviderDisplayName,\n isRegisteredProvider,\n getRegisteredAdapterIds,\n} from './registry.js';\n\n// Side-effect imports: each built-in adapter self-registers into the registry.\nimport './adapters/store/adapter.js';\nimport './adapters/skillhub/adapter.js';\nimport './adapters/clawhub/adapter.js';\n\n/** Resolve the default marketplace provider from env / config. */\nexport function resolveSkillsMarketplaceProvider(config: Config): string {\n const env = process.env.XOPC_SKILLS_MARKETPLACE_PROVIDER?.trim().toLowerCase();\n if (env && isRegisteredProvider(env)) {\n return env;\n }\n const fromConfig = config.gateway?.skillsMarketplaceProvider?.trim().toLowerCase();\n if (fromConfig && isRegisteredProvider(fromConfig)) {\n return fromConfig;\n }\n return '
|
|
1
|
+
{"version":3,"file":"resolve-adapter.js","names":[],"sources":["../../../../../src/agent/skills/marketplace/resolve-adapter.ts"],"sourcesContent":["import type { Config } from '../../../config/schema.js';\n\nimport type { SkillsMarketplaceAdapter } from './adapter.types.js';\nimport {\n getRegisteredAdapter,\n getProviderDisplayName,\n isRegisteredProvider,\n getRegisteredAdapterIds,\n} from './registry.js';\n\n// Side-effect imports: each built-in adapter self-registers into the registry.\nimport './adapters/store/adapter.js';\nimport './adapters/skillhub/adapter.js';\nimport './adapters/clawhub/adapter.js';\n\n/** Resolve the default marketplace provider from env / config. */\nexport function resolveSkillsMarketplaceProvider(config: Config): string {\n const env = process.env.XOPC_SKILLS_MARKETPLACE_PROVIDER?.trim().toLowerCase();\n if (env && isRegisteredProvider(env)) {\n return env;\n }\n const fromConfig = config.gateway?.skillsMarketplaceProvider?.trim().toLowerCase();\n if (fromConfig && isRegisteredProvider(fromConfig)) {\n return fromConfig;\n }\n return 'store';\n}\n\nexport function getMarketplaceProviderDisplayName(provider: string): string {\n return getProviderDisplayName(provider);\n}\n\nexport function getMarketplaceAdapterForProvider(id: string): SkillsMarketplaceAdapter {\n const adapter = getRegisteredAdapter(id);\n if (!adapter) {\n throw new Error(`Unknown marketplace provider: \"${id}\". Registered: ${getRegisteredAdapterIds().join(', ')}`);\n }\n return adapter;\n}\n\nexport function getMarketplaceAdapter(config: Config): SkillsMarketplaceAdapter {\n return getMarketplaceAdapterForProvider(resolveSkillsMarketplaceProvider(config));\n}\n\nexport { listRegisteredProviders, isRegisteredProvider } from './registry.js';\n"],"mappings":";;;;;;AAgBA,SAAgB,iCAAiC,QAAwB;CACvE,MAAM,MAAM,QAAQ,IAAI,kCAAkC,MAAM,CAAC,aAAa;AAC9E,KAAI,OAAO,qBAAqB,IAAI,CAClC,QAAO;CAET,MAAM,aAAa,OAAO,SAAS,2BAA2B,MAAM,CAAC,aAAa;AAClF,KAAI,cAAc,qBAAqB,WAAW,CAChD,QAAO;AAET,QAAO;;AAGT,SAAgB,kCAAkC,UAA0B;AAC1E,QAAO,uBAAuB,SAAS;;AAGzC,SAAgB,iCAAiC,IAAsC;CACrF,MAAM,UAAU,qBAAqB,GAAG;AACxC,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,kCAAkC,GAAG,iBAAiB,yBAAyB,CAAC,KAAK,KAAK,GAAG;AAE/G,QAAO;;AAGT,SAAgB,sBAAsB,QAA0C;AAC9E,QAAO,iCAAiC,iCAAiC,OAAO,CAAC"}
|
|
@@ -22,8 +22,8 @@ const DEFAULT_MAX_SKILL_MD_CHARS = 1e5;
|
|
|
22
22
|
const DEFAULT_MAX_SUPPORT_FILE_BYTES = 1048576;
|
|
23
23
|
function effectiveAgentWritePolicy(cfg) {
|
|
24
24
|
const p = cfg?.agentWritePolicy;
|
|
25
|
-
if (p === "workspace" || p === "both") return p;
|
|
26
|
-
return "
|
|
25
|
+
if (p === "global" || p === "workspace" || p === "both") return p;
|
|
26
|
+
return "both";
|
|
27
27
|
}
|
|
28
28
|
function maxSkillMdChars(_cfg) {
|
|
29
29
|
return DEFAULT_MAX_SKILL_MD_CHARS;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-manage-ops.js","names":[],"sources":["../../../../src/agent/skills/skill-manage-ops.ts"],"sourcesContent":["/**\n * Shared logic for the skill_manage agent tool (create / edit / patch / delete / write_file / remove_file).\n */\n\nimport { existsSync, realpathSync } from 'fs';\nimport { join, resolve, sep } from 'path';\nimport { mkdir, writeFile } from 'fs/promises';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport type { Skill } from './types.js';\nimport type { SkillsConfig } from './types.js';\nimport { scanSkillDirectory, formatScanSummary } from './scanner.js';\nimport { resolveWorkspaceSkillsDir } from './workspace-skills-dir.js';\n\nexport const SKILL_MANAGE_ALLOWED_SUBDIRS = new Set(['references', 'templates', 'scripts', 'assets']);\n\nexport const SKILL_MANAGE_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;\nexport const DEFAULT_MAX_SKILL_MD_CHARS = 100_000;\nexport const DEFAULT_MAX_SUPPORT_FILE_BYTES = 1_048_576;\n\nexport type AgentWritePolicy = 'global' | 'workspace' | 'both';\n\nexport function effectiveAgentWritePolicy(cfg?: SkillsConfig): AgentWritePolicy {\n const p = cfg?.agentWritePolicy;\n if (p === 'workspace' || p === 'both') return p;\n return 'global';\n}\n\nexport function maxSkillMdChars(_cfg?: SkillsConfig): number {\n return DEFAULT_MAX_SKILL_MD_CHARS;\n}\n\nexport function maxSupportFileBytes(cfg?: SkillsConfig): number {\n const n = cfg?.limits?.maxSkillFileBytes;\n if (typeof n === 'number' && n > 0) return n;\n return DEFAULT_MAX_SUPPORT_FILE_BYTES;\n}\n\nexport function validateSkillNameSegment(name: string, label: string): string | null {\n if (!name?.trim()) return `${label} is required.`;\n if (name.length > 64) return `${label} must be at most 64 characters.`;\n if (!SKILL_MANAGE_NAME_RE.test(name)) {\n return `${label} must match ${SKILL_MANAGE_NAME_RE}: lowercase letters, digits, ., _, -`;\n }\n return null;\n}\n\nexport function validateSkillMdContent(\n content: string,\n expectedName: string,\n maxChars: number,\n): { ok: true } | { ok: false; error: string } {\n if (!content.trim()) return { ok: false, error: 'Content cannot be empty.' };\n if (content.length > maxChars) {\n return { ok: false, error: `SKILL.md exceeds limit (${maxChars} characters).` };\n }\n if (!content.startsWith('---')) {\n return { ok: false, error: 'SKILL.md must start with YAML frontmatter (---).' };\n }\n const close = /\\r?\\n---\\s*\\r?\\n/.exec(content.slice(3));\n if (!close) {\n return { ok: false, error: 'Frontmatter must be closed with a line --- before the body.' };\n }\n const { frontmatter, content: body } = parseFrontmatter<Record<string, unknown>>(content);\n const name = frontmatter.name;\n const desc = frontmatter.description;\n if (typeof name !== 'string' || !name.trim()) {\n return { ok: false, error: 'Frontmatter must include a string name field.' };\n }\n if (typeof desc !== 'string' || !desc.trim()) {\n return { ok: false, error: 'Frontmatter must include a string description field.' };\n }\n if (name.trim() !== expectedName) {\n return {\n ok: false,\n error: `Frontmatter name \"${name.trim()}\" must match skill name \"${expectedName}\".`,\n };\n }\n if (!body?.trim()) {\n return { ok: false, error: 'SKILL.md must have a non-empty body after frontmatter.' };\n }\n return { ok: true };\n}\n\nfunction resolvedPathPrefix(dir: string): string {\n const r = resolve(dir);\n return r.endsWith(sep) ? r : r + sep;\n}\n\n/** Whether `filePath` is equal to `dir` or strictly inside it (resolved). */\nexport function isPathInsideDir(dir: string, filePath: string): boolean {\n try {\n const base = resolve(dir);\n const target = resolve(filePath);\n const baseReal = existsSync(base) ? realpathSync(base) : base;\n const targetReal = existsSync(target) ? realpathSync(target) : target;\n const prefix = resolvedPathPrefix(baseReal);\n return targetReal === baseReal || targetReal.startsWith(prefix);\n } catch {\n return false;\n }\n}\n\nexport function resolveGlobalSkillsRoot(): string {\n return resolveSkillsDir();\n}\n\nexport function resolveWorkspaceSkillsRoot(workspace: string): string {\n return resolveWorkspaceSkillsDir(workspace);\n}\n\nexport function canWriteToPath(\n skillBaseDir: string,\n workspace: string,\n policy: AgentWritePolicy,\n): boolean {\n try {\n const baseResolved = existsSync(skillBaseDir) ? realpathSync(skillBaseDir) : resolve(skillBaseDir);\n const globalRoot = resolveGlobalSkillsRoot();\n const wsRoot = resolveWorkspaceSkillsRoot(workspace);\n const underGlobal = isPathInsideDir(globalRoot, baseResolved);\n const underWs = isPathInsideDir(wsRoot, baseResolved);\n if (policy === 'global') return underGlobal;\n if (policy === 'workspace') return underWs;\n return underGlobal || underWs;\n } catch {\n return false;\n }\n}\n\nexport function mutatableSkillOrNull(\n skill: Skill | undefined,\n workspace: string,\n policy: AgentWritePolicy,\n): Skill | null {\n if (!skill) return null;\n if (skill.source === 'builtin' || skill.source === 'extra') return null;\n if (!canWriteToPath(skill.baseDir, workspace, policy)) return null;\n return skill;\n}\n\nexport function validateSupportingRelativePath(filePath: string): string | null {\n if (!filePath?.trim()) return 'file_path is required.';\n const norm = filePath.replace(/\\\\/g, '/');\n if (norm.includes('..')) return \"Path traversal ('..') is not allowed.\";\n if (norm.startsWith('/') || /^[A-Za-z]:/.test(norm)) {\n return 'file_path must be relative to the skill directory.';\n }\n const parts = norm.split('/').filter(Boolean);\n if (parts.length < 2) {\n return 'Provide a file path with a subdirectory, e.g. references/notes.md';\n }\n if (!SKILL_MANAGE_ALLOWED_SUBDIRS.has(parts[0]!)) {\n return `File must be under one of: ${[...SKILL_MANAGE_ALLOWED_SUBDIRS].join(', ')}.`;\n }\n return null;\n}\n\nexport async function atomicWriteUtf8(filePath: string, content: string): Promise<void> {\n const dir = resolve(filePath, '..');\n await mkdir(dir, { recursive: true });\n await writeFile(filePath, content, 'utf-8');\n}\n\n/** Scan skill dir; returns error message if critical findings (caller rolls back). */\nexport async function scanSkillDirOrError(skillDir: string, skillName: string): Promise<string | null> {\n const summary = await scanSkillDirectory(skillDir);\n if (summary.critical > 0) {\n return `Security scan blocked this change:\\n${formatScanSummary(summary, skillName)}`;\n }\n return null;\n}\n\nexport function resolveCreateSkillDir(\n name: string,\n category: string | undefined,\n writeTarget: 'global' | 'workspace',\n workspace: string,\n policy: AgentWritePolicy,\n): { ok: true; dir: string } | { ok: false; error: string } {\n if (writeTarget === 'global' && policy === 'workspace') {\n return { ok: false, error: 'Creating under global skills is not allowed (skills.agentWritePolicy).' };\n }\n if (writeTarget === 'workspace' && policy === 'global') {\n return { ok: false, error: 'Creating under workspace skills is not allowed (skills.agentWritePolicy).' };\n }\n const root =\n writeTarget === 'global' ? resolveGlobalSkillsRoot() : resolveWorkspaceSkillsRoot(workspace);\n const dir = category?.trim() ? join(root, category.trim(), name) : join(root, name);\n return { ok: true, dir };\n}\n\nexport function ensureCategorySegment(category: string | undefined): string | null {\n if (category === undefined || category === null || category === '') return null;\n if (typeof category !== 'string') return 'category must be a string.';\n const c = category.trim();\n if (!c) return null;\n if (c.includes('/') || c.includes('\\\\')) return 'category must be a single path segment.';\n return validateSkillNameSegment(c, 'category');\n}\n\nimport { normalizeToLF, restoreLineEndings, fuzzyFindText, normalizeForFuzzyMatch } from '../tools/edit-diff.js';\n\nfunction detectLineEnding(content: string): '\\r\\n' | '\\n' {\n const crlfIdx = content.indexOf('\\r\\n');\n const lfIdx = content.indexOf('\\n');\n if (lfIdx === -1) return '\\n';\n if (crlfIdx === -1) return '\\n';\n return crlfIdx < lfIdx ? '\\r\\n' : '\\n';\n}\n\nexport function applyPatchToContent(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean,\n): { ok: true; next: string; replacements: number } | { ok: false; error: string } {\n if (!oldString) return { ok: false, error: 'old_string is required for patch.' };\n if (newString === undefined) {\n return { ok: false, error: 'new_string is required (use empty string to delete matched text).' };\n }\n\n const lineEnding = detectLineEnding(content);\n const normalized = normalizeToLF(content);\n const oldN = normalizeToLF(oldString);\n const newN = normalizeToLF(newString);\n\n if (replaceAll) {\n const parts = normalized.split(oldN);\n const count = parts.length - 1;\n if (count === 0) {\n return { ok: false, error: 'old_string not found for replace_all.' };\n }\n const merged = parts.join(newN);\n return { ok: true, next: restoreLineEndings(merged, lineEnding), replacements: count };\n }\n\n const match = fuzzyFindText(normalized, oldN);\n if (!match.found) {\n return { ok: false, error: 'old_string not found in file.' };\n }\n const base = match.contentForReplacement;\n const fuzzyContent = normalizeForFuzzyMatch(normalizeToLF(base));\n const fuzzyOld = normalizeForFuzzyMatch(oldN);\n const occurrences = fuzzyOld ? fuzzyContent.split(fuzzyOld).length - 1 : 0;\n if (occurrences > 1) {\n return { ok: false, error: `Found ${occurrences} matches; narrow old_string or use replace_all.` };\n }\n const next =\n base.slice(0, match.index) + newN + base.slice(match.index + match.matchLength);\n return { ok: true, next: restoreLineEndings(next, lineEnding), replacements: 1 };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skill-manage-ops.js","names":[],"sources":["../../../../src/agent/skills/skill-manage-ops.ts"],"sourcesContent":["/**\n * Shared logic for the skill_manage agent tool (create / edit / patch / delete / write_file / remove_file).\n */\n\nimport { existsSync, realpathSync } from 'fs';\nimport { join, resolve, sep } from 'path';\nimport { mkdir, writeFile } from 'fs/promises';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport type { Skill } from './types.js';\nimport type { SkillsConfig } from './types.js';\nimport { scanSkillDirectory, formatScanSummary } from './scanner.js';\nimport { resolveWorkspaceSkillsDir } from './workspace-skills-dir.js';\n\nexport const SKILL_MANAGE_ALLOWED_SUBDIRS = new Set(['references', 'templates', 'scripts', 'assets']);\n\nexport const SKILL_MANAGE_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;\nexport const DEFAULT_MAX_SKILL_MD_CHARS = 100_000;\nexport const DEFAULT_MAX_SUPPORT_FILE_BYTES = 1_048_576;\n\nexport type AgentWritePolicy = 'global' | 'workspace' | 'both';\n\nexport function effectiveAgentWritePolicy(cfg?: SkillsConfig): AgentWritePolicy {\n const p = cfg?.agentWritePolicy;\n if (p === 'global' || p === 'workspace' || p === 'both') return p;\n return 'both';\n}\n\nexport function maxSkillMdChars(_cfg?: SkillsConfig): number {\n return DEFAULT_MAX_SKILL_MD_CHARS;\n}\n\nexport function maxSupportFileBytes(cfg?: SkillsConfig): number {\n const n = cfg?.limits?.maxSkillFileBytes;\n if (typeof n === 'number' && n > 0) return n;\n return DEFAULT_MAX_SUPPORT_FILE_BYTES;\n}\n\nexport function validateSkillNameSegment(name: string, label: string): string | null {\n if (!name?.trim()) return `${label} is required.`;\n if (name.length > 64) return `${label} must be at most 64 characters.`;\n if (!SKILL_MANAGE_NAME_RE.test(name)) {\n return `${label} must match ${SKILL_MANAGE_NAME_RE}: lowercase letters, digits, ., _, -`;\n }\n return null;\n}\n\nexport function validateSkillMdContent(\n content: string,\n expectedName: string,\n maxChars: number,\n): { ok: true } | { ok: false; error: string } {\n if (!content.trim()) return { ok: false, error: 'Content cannot be empty.' };\n if (content.length > maxChars) {\n return { ok: false, error: `SKILL.md exceeds limit (${maxChars} characters).` };\n }\n if (!content.startsWith('---')) {\n return { ok: false, error: 'SKILL.md must start with YAML frontmatter (---).' };\n }\n const close = /\\r?\\n---\\s*\\r?\\n/.exec(content.slice(3));\n if (!close) {\n return { ok: false, error: 'Frontmatter must be closed with a line --- before the body.' };\n }\n const { frontmatter, content: body } = parseFrontmatter<Record<string, unknown>>(content);\n const name = frontmatter.name;\n const desc = frontmatter.description;\n if (typeof name !== 'string' || !name.trim()) {\n return { ok: false, error: 'Frontmatter must include a string name field.' };\n }\n if (typeof desc !== 'string' || !desc.trim()) {\n return { ok: false, error: 'Frontmatter must include a string description field.' };\n }\n if (name.trim() !== expectedName) {\n return {\n ok: false,\n error: `Frontmatter name \"${name.trim()}\" must match skill name \"${expectedName}\".`,\n };\n }\n if (!body?.trim()) {\n return { ok: false, error: 'SKILL.md must have a non-empty body after frontmatter.' };\n }\n return { ok: true };\n}\n\nfunction resolvedPathPrefix(dir: string): string {\n const r = resolve(dir);\n return r.endsWith(sep) ? r : r + sep;\n}\n\n/** Whether `filePath` is equal to `dir` or strictly inside it (resolved). */\nexport function isPathInsideDir(dir: string, filePath: string): boolean {\n try {\n const base = resolve(dir);\n const target = resolve(filePath);\n const baseReal = existsSync(base) ? realpathSync(base) : base;\n const targetReal = existsSync(target) ? realpathSync(target) : target;\n const prefix = resolvedPathPrefix(baseReal);\n return targetReal === baseReal || targetReal.startsWith(prefix);\n } catch {\n return false;\n }\n}\n\nexport function resolveGlobalSkillsRoot(): string {\n return resolveSkillsDir();\n}\n\nexport function resolveWorkspaceSkillsRoot(workspace: string): string {\n return resolveWorkspaceSkillsDir(workspace);\n}\n\nexport function canWriteToPath(\n skillBaseDir: string,\n workspace: string,\n policy: AgentWritePolicy,\n): boolean {\n try {\n const baseResolved = existsSync(skillBaseDir) ? realpathSync(skillBaseDir) : resolve(skillBaseDir);\n const globalRoot = resolveGlobalSkillsRoot();\n const wsRoot = resolveWorkspaceSkillsRoot(workspace);\n const underGlobal = isPathInsideDir(globalRoot, baseResolved);\n const underWs = isPathInsideDir(wsRoot, baseResolved);\n if (policy === 'global') return underGlobal;\n if (policy === 'workspace') return underWs;\n return underGlobal || underWs;\n } catch {\n return false;\n }\n}\n\nexport function mutatableSkillOrNull(\n skill: Skill | undefined,\n workspace: string,\n policy: AgentWritePolicy,\n): Skill | null {\n if (!skill) return null;\n if (skill.source === 'builtin' || skill.source === 'extra') return null;\n if (!canWriteToPath(skill.baseDir, workspace, policy)) return null;\n return skill;\n}\n\nexport function validateSupportingRelativePath(filePath: string): string | null {\n if (!filePath?.trim()) return 'file_path is required.';\n const norm = filePath.replace(/\\\\/g, '/');\n if (norm.includes('..')) return \"Path traversal ('..') is not allowed.\";\n if (norm.startsWith('/') || /^[A-Za-z]:/.test(norm)) {\n return 'file_path must be relative to the skill directory.';\n }\n const parts = norm.split('/').filter(Boolean);\n if (parts.length < 2) {\n return 'Provide a file path with a subdirectory, e.g. references/notes.md';\n }\n if (!SKILL_MANAGE_ALLOWED_SUBDIRS.has(parts[0]!)) {\n return `File must be under one of: ${[...SKILL_MANAGE_ALLOWED_SUBDIRS].join(', ')}.`;\n }\n return null;\n}\n\nexport async function atomicWriteUtf8(filePath: string, content: string): Promise<void> {\n const dir = resolve(filePath, '..');\n await mkdir(dir, { recursive: true });\n await writeFile(filePath, content, 'utf-8');\n}\n\n/** Scan skill dir; returns error message if critical findings (caller rolls back). */\nexport async function scanSkillDirOrError(skillDir: string, skillName: string): Promise<string | null> {\n const summary = await scanSkillDirectory(skillDir);\n if (summary.critical > 0) {\n return `Security scan blocked this change:\\n${formatScanSummary(summary, skillName)}`;\n }\n return null;\n}\n\nexport function resolveCreateSkillDir(\n name: string,\n category: string | undefined,\n writeTarget: 'global' | 'workspace',\n workspace: string,\n policy: AgentWritePolicy,\n): { ok: true; dir: string } | { ok: false; error: string } {\n if (writeTarget === 'global' && policy === 'workspace') {\n return { ok: false, error: 'Creating under global skills is not allowed (skills.agentWritePolicy).' };\n }\n if (writeTarget === 'workspace' && policy === 'global') {\n return { ok: false, error: 'Creating under workspace skills is not allowed (skills.agentWritePolicy).' };\n }\n const root =\n writeTarget === 'global' ? resolveGlobalSkillsRoot() : resolveWorkspaceSkillsRoot(workspace);\n const dir = category?.trim() ? join(root, category.trim(), name) : join(root, name);\n return { ok: true, dir };\n}\n\nexport function ensureCategorySegment(category: string | undefined): string | null {\n if (category === undefined || category === null || category === '') return null;\n if (typeof category !== 'string') return 'category must be a string.';\n const c = category.trim();\n if (!c) return null;\n if (c.includes('/') || c.includes('\\\\')) return 'category must be a single path segment.';\n return validateSkillNameSegment(c, 'category');\n}\n\nimport { normalizeToLF, restoreLineEndings, fuzzyFindText, normalizeForFuzzyMatch } from '../tools/edit-diff.js';\n\nfunction detectLineEnding(content: string): '\\r\\n' | '\\n' {\n const crlfIdx = content.indexOf('\\r\\n');\n const lfIdx = content.indexOf('\\n');\n if (lfIdx === -1) return '\\n';\n if (crlfIdx === -1) return '\\n';\n return crlfIdx < lfIdx ? '\\r\\n' : '\\n';\n}\n\nexport function applyPatchToContent(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean,\n): { ok: true; next: string; replacements: number } | { ok: false; error: string } {\n if (!oldString) return { ok: false, error: 'old_string is required for patch.' };\n if (newString === undefined) {\n return { ok: false, error: 'new_string is required (use empty string to delete matched text).' };\n }\n\n const lineEnding = detectLineEnding(content);\n const normalized = normalizeToLF(content);\n const oldN = normalizeToLF(oldString);\n const newN = normalizeToLF(newString);\n\n if (replaceAll) {\n const parts = normalized.split(oldN);\n const count = parts.length - 1;\n if (count === 0) {\n return { ok: false, error: 'old_string not found for replace_all.' };\n }\n const merged = parts.join(newN);\n return { ok: true, next: restoreLineEndings(merged, lineEnding), replacements: count };\n }\n\n const match = fuzzyFindText(normalized, oldN);\n if (!match.found) {\n return { ok: false, error: 'old_string not found in file.' };\n }\n const base = match.contentForReplacement;\n const fuzzyContent = normalizeForFuzzyMatch(normalizeToLF(base));\n const fuzzyOld = normalizeForFuzzyMatch(oldN);\n const occurrences = fuzzyOld ? fuzzyContent.split(fuzzyOld).length - 1 : 0;\n if (occurrences > 1) {\n return { ok: false, error: `Found ${occurrences} matches; narrow old_string or use replace_all.` };\n }\n const next =\n base.slice(0, match.index) + newN + base.slice(match.index + match.matchLength);\n return { ok: true, next: restoreLineEndings(next, lineEnding), replacements: 1 };\n}\n"],"mappings":";;;;;;;;;;;;YASyD;AAMzD,MAAa,+BAA+B,IAAI,IAAI;CAAC;CAAc;CAAa;CAAW;CAAS,CAAC;AAErG,MAAa,uBAAuB;AACpC,MAAa,6BAA6B;AAC1C,MAAa,iCAAiC;AAI9C,SAAgB,0BAA0B,KAAsC;CAC9E,MAAM,IAAI,KAAK;AACf,KAAI,MAAM,YAAY,MAAM,eAAe,MAAM,OAAQ,QAAO;AAChE,QAAO;;AAGT,SAAgB,gBAAgB,MAA6B;AAC3D,QAAO;;AAGT,SAAgB,oBAAoB,KAA4B;CAC9D,MAAM,IAAI,KAAK,QAAQ;AACvB,KAAI,OAAO,MAAM,YAAY,IAAI,EAAG,QAAO;AAC3C,QAAO;;AAGT,SAAgB,yBAAyB,MAAc,OAA8B;AACnF,KAAI,CAAC,MAAM,MAAM,CAAE,QAAO,GAAG,MAAM;AACnC,KAAI,KAAK,SAAS,GAAI,QAAO,GAAG,MAAM;AACtC,KAAI,CAAC,qBAAqB,KAAK,KAAK,CAClC,QAAO,GAAG,MAAM,cAAc,qBAAqB;AAErD,QAAO;;AAGT,SAAgB,uBACd,SACA,cACA,UAC6C;AAC7C,KAAI,CAAC,QAAQ,MAAM,CAAE,QAAO;EAAE,IAAI;EAAO,OAAO;EAA4B;AAC5E,KAAI,QAAQ,SAAS,SACnB,QAAO;EAAE,IAAI;EAAO,OAAO,2BAA2B,SAAS;EAAgB;AAEjF,KAAI,CAAC,QAAQ,WAAW,MAAM,CAC5B,QAAO;EAAE,IAAI;EAAO,OAAO;EAAoD;AAGjF,KAAI,CADU,mBAAmB,KAAK,QAAQ,MAAM,EAAE,CAC5C,CACR,QAAO;EAAE,IAAI;EAAO,OAAO;EAA+D;CAE5F,MAAM,EAAE,aAAa,SAAS,SAAS,iBAA0C,QAAQ;CACzF,MAAM,OAAO,YAAY;CACzB,MAAM,OAAO,YAAY;AACzB,KAAI,OAAO,SAAS,YAAY,CAAC,KAAK,MAAM,CAC1C,QAAO;EAAE,IAAI;EAAO,OAAO;EAAiD;AAE9E,KAAI,OAAO,SAAS,YAAY,CAAC,KAAK,MAAM,CAC1C,QAAO;EAAE,IAAI;EAAO,OAAO;EAAwD;AAErF,KAAI,KAAK,MAAM,KAAK,aAClB,QAAO;EACL,IAAI;EACJ,OAAO,qBAAqB,KAAK,MAAM,CAAC,2BAA2B,aAAa;EACjF;AAEH,KAAI,CAAC,MAAM,MAAM,CACf,QAAO;EAAE,IAAI;EAAO,OAAO;EAA0D;AAEvF,QAAO,EAAE,IAAI,MAAM;;AAGrB,SAAS,mBAAmB,KAAqB;CAC/C,MAAM,IAAI,QAAQ,IAAI;AACtB,QAAO,EAAE,SAAS,IAAI,GAAG,IAAI,IAAI;;;AAInC,SAAgB,gBAAgB,KAAa,UAA2B;AACtE,KAAI;EACF,MAAM,OAAO,QAAQ,IAAI;EACzB,MAAM,SAAS,QAAQ,SAAS;EAChC,MAAM,WAAW,WAAW,KAAK,GAAG,aAAa,KAAK,GAAG;EACzD,MAAM,aAAa,WAAW,OAAO,GAAG,aAAa,OAAO,GAAG;EAC/D,MAAM,SAAS,mBAAmB,SAAS;AAC3C,SAAO,eAAe,YAAY,WAAW,WAAW,OAAO;SACzD;AACN,SAAO;;;AAIX,SAAgB,0BAAkC;AAChD,QAAO,kBAAkB;;AAG3B,SAAgB,2BAA2B,WAA2B;AACpE,QAAO,0BAA0B,UAAU;;AAG7C,SAAgB,eACd,cACA,WACA,QACS;AACT,KAAI;EACF,MAAM,eAAe,WAAW,aAAa,GAAG,aAAa,aAAa,GAAG,QAAQ,aAAa;EAClG,MAAM,aAAa,yBAAyB;EAC5C,MAAM,SAAS,2BAA2B,UAAU;EACpD,MAAM,cAAc,gBAAgB,YAAY,aAAa;EAC7D,MAAM,UAAU,gBAAgB,QAAQ,aAAa;AACrD,MAAI,WAAW,SAAU,QAAO;AAChC,MAAI,WAAW,YAAa,QAAO;AACnC,SAAO,eAAe;SAChB;AACN,SAAO;;;AAIX,SAAgB,qBACd,OACA,WACA,QACc;AACd,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,MAAM,WAAW,aAAa,MAAM,WAAW,QAAS,QAAO;AACnE,KAAI,CAAC,eAAe,MAAM,SAAS,WAAW,OAAO,CAAE,QAAO;AAC9D,QAAO;;AAGT,SAAgB,+BAA+B,UAAiC;AAC9E,KAAI,CAAC,UAAU,MAAM,CAAE,QAAO;CAC9B,MAAM,OAAO,SAAS,QAAQ,OAAO,IAAI;AACzC,KAAI,KAAK,SAAS,KAAK,CAAE,QAAO;AAChC,KAAI,KAAK,WAAW,IAAI,IAAI,aAAa,KAAK,KAAK,CACjD,QAAO;CAET,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;AAC7C,KAAI,MAAM,SAAS,EACjB,QAAO;AAET,KAAI,CAAC,6BAA6B,IAAI,MAAM,GAAI,CAC9C,QAAO,8BAA8B,CAAC,GAAG,6BAA6B,CAAC,KAAK,KAAK,CAAC;AAEpF,QAAO;;AAGT,eAAsB,gBAAgB,UAAkB,SAAgC;AAEtF,OAAM,MADM,QAAQ,UAAU,KACf,EAAE,EAAE,WAAW,MAAM,CAAC;AACrC,OAAM,UAAU,UAAU,SAAS,QAAQ;;;AAI7C,eAAsB,oBAAoB,UAAkB,WAA2C;CACrG,MAAM,UAAU,MAAM,mBAAmB,SAAS;AAClD,KAAI,QAAQ,WAAW,EACrB,QAAO,uCAAuC,kBAAkB,SAAS,UAAU;AAErF,QAAO;;AAGT,SAAgB,sBACd,MACA,UACA,aACA,WACA,QAC0D;AAC1D,KAAI,gBAAgB,YAAY,WAAW,YACzC,QAAO;EAAE,IAAI;EAAO,OAAO;EAA0E;AAEvG,KAAI,gBAAgB,eAAe,WAAW,SAC5C,QAAO;EAAE,IAAI;EAAO,OAAO;EAA6E;CAE1G,MAAM,OACJ,gBAAgB,WAAW,yBAAyB,GAAG,2BAA2B,UAAU;AAE9F,QAAO;EAAE,IAAI;EAAM,KADP,UAAU,MAAM,GAAG,KAAK,MAAM,SAAS,MAAM,EAAE,KAAK,GAAG,KAAK,MAAM,KAAK;EAC3D;;AAG1B,SAAgB,sBAAsB,UAA6C;AACjF,KAAI,aAAa,KAAA,KAAa,aAAa,QAAQ,aAAa,GAAI,QAAO;AAC3E,KAAI,OAAO,aAAa,SAAU,QAAO;CACzC,MAAM,IAAI,SAAS,MAAM;AACzB,KAAI,CAAC,EAAG,QAAO;AACf,KAAI,EAAE,SAAS,IAAI,IAAI,EAAE,SAAS,KAAK,CAAE,QAAO;AAChD,QAAO,yBAAyB,GAAG,WAAW;;AAKhD,SAAS,iBAAiB,SAAgC;CACxD,MAAM,UAAU,QAAQ,QAAQ,OAAO;CACvC,MAAM,QAAQ,QAAQ,QAAQ,KAAK;AACnC,KAAI,UAAU,GAAI,QAAO;AACzB,KAAI,YAAY,GAAI,QAAO;AAC3B,QAAO,UAAU,QAAQ,SAAS;;AAGpC,SAAgB,oBACd,SACA,WACA,WACA,YACiF;AACjF,KAAI,CAAC,UAAW,QAAO;EAAE,IAAI;EAAO,OAAO;EAAqC;AAChF,KAAI,cAAc,KAAA,EAChB,QAAO;EAAE,IAAI;EAAO,OAAO;EAAqE;CAGlG,MAAM,aAAa,iBAAiB,QAAQ;CAC5C,MAAM,aAAa,cAAc,QAAQ;CACzC,MAAM,OAAO,cAAc,UAAU;CACrC,MAAM,OAAO,cAAc,UAAU;AAErC,KAAI,YAAY;EACd,MAAM,QAAQ,WAAW,MAAM,KAAK;EACpC,MAAM,QAAQ,MAAM,SAAS;AAC7B,MAAI,UAAU,EACZ,QAAO;GAAE,IAAI;GAAO,OAAO;GAAyC;AAGtE,SAAO;GAAE,IAAI;GAAM,MAAM,mBADV,MAAM,KAAK,KACwB,EAAE,WAAW;GAAE,cAAc;GAAO;;CAGxF,MAAM,QAAQ,cAAc,YAAY,KAAK;AAC7C,KAAI,CAAC,MAAM,MACT,QAAO;EAAE,IAAI;EAAO,OAAO;EAAiC;CAE9D,MAAM,OAAO,MAAM;CACnB,MAAM,eAAe,uBAAuB,cAAc,KAAK,CAAC;CAChE,MAAM,WAAW,uBAAuB,KAAK;CAC7C,MAAM,cAAc,WAAW,aAAa,MAAM,SAAS,CAAC,SAAS,IAAI;AACzE,KAAI,cAAc,EAChB,QAAO;EAAE,IAAI;EAAO,OAAO,SAAS,YAAY;EAAkD;AAIpG,QAAO;EAAE,IAAI;EAAM,MAAM,mBADvB,KAAK,MAAM,GAAG,MAAM,MAAM,GAAG,OAAO,KAAK,MAAM,MAAM,QAAQ,MAAM,YAAY,EAC/B,WAAW;EAAE,cAAc;EAAG"}
|
|
@@ -97,12 +97,7 @@ var SkillManager = class {
|
|
|
97
97
|
this.skills = result.skills;
|
|
98
98
|
this.version += 1;
|
|
99
99
|
this.loadedAt = Date.now();
|
|
100
|
-
for (const diag of result.diagnostics) if (diag.type === "
|
|
101
|
-
skill: diag.skillName,
|
|
102
|
-
path: diag.path,
|
|
103
|
-
message: diag.message
|
|
104
|
-
}, "Skill collision");
|
|
105
|
-
else if (diag.type === "warning") log.warn({
|
|
100
|
+
for (const diag of result.diagnostics) if (diag.type === "warning") log.warn({
|
|
106
101
|
skill: diag.skillName,
|
|
107
102
|
path: diag.path,
|
|
108
103
|
message: diag.message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-manager.js","names":[],"sources":["../../../../src/agent/skills/skill-manager.ts"],"sourcesContent":["/**\n * Skill Manager - Manages skills loading and expansion\n *\n * Handles skill initialization, reloading, and command expansion.\n */\n\nimport { createSkillLoader } from './index.js';\nimport { resolveBundledSkillsDir, resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt, selectSkillsVisibleInPrompt } from './format-skills-prompt.js';\nimport type {\n LoadSkillsResult,\n Skill,\n SkillDiagnostic,\n SkillRuntimeStatus,\n} from './types.js';\n\nconst log = createLogger('SkillManager');\nconst SKILL_TOKEN_RE = /\\/skill:([A-Za-z0-9][A-Za-z0-9._-]*)/g;\n\nexport interface SkillLoadResult {\n skills: Skill[];\n prompt: string;\n diagnostics: SkillDiagnostic[];\n}\n\nexport class SkillManager {\n private skillPrompt: string = '';\n private skills: Skill[] = [];\n private skillLoader = createSkillLoader();\n private workspace: string;\n private bundledSkillsDir: string;\n private version = 0;\n private loadedAt = 0;\n private reloadInProgress = false;\n private reloadPending = false;\n private lastReloadStartedAt: number | undefined;\n private lastReloadFinishedAt: number | undefined;\n private lastReloadReason: SkillRuntimeStatus['lastReloadReason'];\n private lastReloadOk: boolean | undefined;\n private lastReloadError: string | undefined;\n\n constructor(workspace: string, bundledSkillsDir?: string) {\n this.workspace = workspace;\n this.bundledSkillsDir = bundledSkillsDir || resolveBundledSkillsDir();\n this.initialize();\n }\n\n /**\n * Initialize skills from workspace and bundled directories\n */\n private initialize(): void {\n this.runReload('initial', () => this.skillLoader.init(this.workspace, this.bundledSkillsDir));\n }\n\n /**\n * Recompute skill XML prompt from current skills.json (no disk rescan).\n */\n refreshPromptFromConfig(): void {\n this.skillLoader.refreshPromptFromConfig();\n this.skillPrompt = this.skillLoader.getPrompt();\n this.version += 1;\n this.loadedAt = Date.now();\n this.lastReloadReason = 'config';\n this.lastReloadOk = true;\n this.lastReloadError = undefined;\n }\n\n /**\n * Reload skills from disk\n */\n reload(): void {\n this.runReload('disk', () => this.skillLoader.reload());\n }\n\n private runReload(reason: NonNullable<SkillRuntimeStatus['lastReloadReason']>, load: () => LoadSkillsResult): void {\n if (this.reloadInProgress) {\n this.reloadPending = true;\n return;\n }\n\n do {\n this.reloadPending = false;\n this.reloadInProgress = true;\n this.lastReloadStartedAt = Date.now();\n this.lastReloadReason = reason;\n try {\n const result = load();\n this.applyLoadResult(result);\n this.lastReloadOk = true;\n this.lastReloadError = undefined;\n log.info({ count: result.skills.length, version: this.version }, 'Skills reloaded');\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n this.lastReloadOk = false;\n this.lastReloadError = errorMessage;\n log.error({ err, errorMessage }, `Skills reload failed: ${errorMessage}`);\n } finally {\n this.lastReloadFinishedAt = Date.now();\n this.reloadInProgress = false;\n }\n } while (this.reloadPending);\n }\n\n private applyLoadResult(result: LoadSkillsResult): void {\n this.skillPrompt = result.prompt;\n this.skills = result.skills;\n this.version += 1;\n this.loadedAt = Date.now();\n\n for (const diag of result.diagnostics) {\n if (diag.type === 'collision') {\n log.warn({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill collision');\n } else if (diag.type === 'warning') {\n log.warn({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill warning');\n } else if (diag.type === 'error') {\n log.error({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill error');\n }\n }\n }\n\n /**\n * Get the skill prompt to append to system prompt\n */\n getPrompt(): string {\n return this.skillPrompt;\n }\n\n /**\n * `<available_skills>` XML with optional per-agent allowlist and/or tool-based gating.\n * When both arguments are omitted, returns the cached prompt from disk load (no tool gating).\n */\n getPromptForSkillAllowlist(\n allowlist: string[] | undefined,\n registeredToolNames?: string[],\n ): string {\n if (allowlist === undefined && registeredToolNames === undefined) {\n return this.getPrompt();\n }\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return formatSkillsForPrompt(this.getSkills(), skillsConfig, {\n skillAllowlist: allowlist,\n registeredToolNames,\n });\n }\n\n /** Skills visible for prompts and skills_list given the same indexing options as {@link getPromptForSkillAllowlist}. */\n selectSkillsForAgentIndexing(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return selectSkillsVisibleInPrompt(this.getSkills(), skillsConfig, options);\n }\n\n /**\n * Get all loaded skills\n */\n getSkills(): Skill[] {\n return [...this.skills];\n }\n\n getDiagnostics(): SkillDiagnostic[] {\n return this.skillLoader.getDiagnostics();\n }\n\n getVersion(): string {\n return String(this.version);\n }\n\n getLoadedAt(): number {\n return this.loadedAt;\n }\n\n getStatus(): SkillRuntimeStatus {\n return {\n version: this.getVersion(),\n loadedAt: this.loadedAt,\n reloadInProgress: this.reloadInProgress,\n reloadPending: this.reloadPending,\n ...(this.lastReloadStartedAt !== undefined ? { lastReloadStartedAt: this.lastReloadStartedAt } : {}),\n ...(this.lastReloadFinishedAt !== undefined ? { lastReloadFinishedAt: this.lastReloadFinishedAt } : {}),\n ...(this.lastReloadReason !== undefined ? { lastReloadReason: this.lastReloadReason } : {}),\n ...(this.lastReloadOk !== undefined ? { lastReloadOk: this.lastReloadOk } : {}),\n ...(this.lastReloadError !== undefined ? { lastReloadError: this.lastReloadError } : {}),\n };\n }\n\n /**\n * Get skill names\n */\n getSkillNames(): string[] {\n return this.skills.map((s) => s.name);\n }\n\n /** Names of skills included in the agent system prompt (`<available_skills>`). */\n getSkillNamesForPrompt(): string[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills()\n .filter((s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig))\n .map((s) => s.name);\n }\n\n /**\n * Skills that are enabled for model discovery (respects skills.json and requirement checks).\n */\n getEnabledSkills(): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills().filter(\n (s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig),\n );\n }\n\n /**\n * Like {@link getEnabledSkills} plus optional allowlist and tool gating (matches `<available_skills>`).\n */\n getEnabledSkillsForAgentSession(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n return this.selectSkillsForAgentIndexing(options);\n }\n\n getActivatedCapabilitiesForText(\n text: string,\n options?: { skillAllowlist?: string[]; registeredToolNames?: string[] },\n ): string[] {\n if (!text.includes('/skill:')) return [];\n const selected = new Set<string>();\n for (const match of text.matchAll(SKILL_TOKEN_RE)) {\n if (match[1]) selected.add(match[1]);\n }\n if (selected.size === 0) return [];\n\n const visible = this.selectSkillsForAgentIndexing(options);\n const activeCapabilities = new Set<string>();\n for (const skill of visible) {\n if (!selected.has(skill.name)) continue;\n for (const capabilityName of skill.metadata.xopc?.activatesCapabilities ?? []) {\n const trimmed = capabilityName.trim();\n if (trimmed) activeCapabilities.add(trimmed);\n }\n }\n return [...activeCapabilities];\n }\n\n /**\n * Find a skill by name\n */\n findSkill(name: string): Skill | undefined {\n return this.skills.find(s => s.name === name);\n }\n\n /**\n * Check if a skill exists\n */\n hasSkill(name: string): boolean {\n return this.skills.some(s => s.name === name);\n }\n\n /**\n * Expand a skill command into a full skill block\n */\n expandCommand(text: string, options?: { skillAllowlist?: string[]; registeredToolNames?: string[] }): string {\n if (!text.startsWith('/skill:')) {\n return text;\n }\n\n const { skillName, args } = this.parseSkillCommand(text);\n const visible = this.selectSkillsForAgentIndexing(options);\n const skill = visible.find((s) => s.name === skillName);\n\n if (!skill) {\n log.warn({ skillName }, 'Skill not visible for expansion');\n return text;\n }\n\n return this.buildSkillBlock(skill, args);\n }\n\n /**\n * Parse a /skill: command\n */\n private parseSkillCommand(text: string): { skillName: string; args?: string } {\n // Format: /skill:name args...\n const withoutPrefix = text.slice(7); // Remove '/skill:'\n const spaceIndex = withoutPrefix.indexOf(' ');\n\n if (spaceIndex === -1) {\n return { skillName: withoutPrefix.trim() };\n }\n\n return {\n skillName: withoutPrefix.slice(0, spaceIndex).trim(),\n args: withoutPrefix.slice(spaceIndex + 1).trim(),\n };\n }\n\n /**\n * Build a skill block for inclusion in the prompt\n */\n private buildSkillBlock(skill: Skill, args?: string): string {\n let block = `\\n\\n## Skill: ${skill.name}\\n\\n`;\n \n if (skill.description) {\n block += `${skill.description}\\n\\n`;\n }\n\n // Include raw skill content (SKILL.md content)\n if (skill.content) {\n block += `${skill.content}\\n\\n`;\n }\n\n if (args) {\n block += `**Arguments**: ${args}\\n\\n`;\n }\n\n return block;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skill-manager.js","names":[],"sources":["../../../../src/agent/skills/skill-manager.ts"],"sourcesContent":["/**\n * Skill Manager - Manages skills loading and expansion\n *\n * Handles skill initialization, reloading, and command expansion.\n */\n\nimport { createSkillLoader } from './index.js';\nimport { resolveBundledSkillsDir, resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt, selectSkillsVisibleInPrompt } from './format-skills-prompt.js';\nimport type {\n LoadSkillsResult,\n Skill,\n SkillDiagnostic,\n SkillRuntimeStatus,\n} from './types.js';\n\nconst log = createLogger('SkillManager');\nconst SKILL_TOKEN_RE = /\\/skill:([A-Za-z0-9][A-Za-z0-9._-]*)/g;\n\nexport interface SkillLoadResult {\n skills: Skill[];\n prompt: string;\n diagnostics: SkillDiagnostic[];\n}\n\nexport class SkillManager {\n private skillPrompt: string = '';\n private skills: Skill[] = [];\n private skillLoader = createSkillLoader();\n private workspace: string;\n private bundledSkillsDir: string;\n private version = 0;\n private loadedAt = 0;\n private reloadInProgress = false;\n private reloadPending = false;\n private lastReloadStartedAt: number | undefined;\n private lastReloadFinishedAt: number | undefined;\n private lastReloadReason: SkillRuntimeStatus['lastReloadReason'];\n private lastReloadOk: boolean | undefined;\n private lastReloadError: string | undefined;\n\n constructor(workspace: string, bundledSkillsDir?: string) {\n this.workspace = workspace;\n this.bundledSkillsDir = bundledSkillsDir || resolveBundledSkillsDir();\n this.initialize();\n }\n\n /**\n * Initialize skills from workspace and bundled directories\n */\n private initialize(): void {\n this.runReload('initial', () => this.skillLoader.init(this.workspace, this.bundledSkillsDir));\n }\n\n /**\n * Recompute skill XML prompt from current skills.json (no disk rescan).\n */\n refreshPromptFromConfig(): void {\n this.skillLoader.refreshPromptFromConfig();\n this.skillPrompt = this.skillLoader.getPrompt();\n this.version += 1;\n this.loadedAt = Date.now();\n this.lastReloadReason = 'config';\n this.lastReloadOk = true;\n this.lastReloadError = undefined;\n }\n\n /**\n * Reload skills from disk\n */\n reload(): void {\n this.runReload('disk', () => this.skillLoader.reload());\n }\n\n private runReload(reason: NonNullable<SkillRuntimeStatus['lastReloadReason']>, load: () => LoadSkillsResult): void {\n if (this.reloadInProgress) {\n this.reloadPending = true;\n return;\n }\n\n do {\n this.reloadPending = false;\n this.reloadInProgress = true;\n this.lastReloadStartedAt = Date.now();\n this.lastReloadReason = reason;\n try {\n const result = load();\n this.applyLoadResult(result);\n this.lastReloadOk = true;\n this.lastReloadError = undefined;\n log.info({ count: result.skills.length, version: this.version }, 'Skills reloaded');\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n this.lastReloadOk = false;\n this.lastReloadError = errorMessage;\n log.error({ err, errorMessage }, `Skills reload failed: ${errorMessage}`);\n } finally {\n this.lastReloadFinishedAt = Date.now();\n this.reloadInProgress = false;\n }\n } while (this.reloadPending);\n }\n\n private applyLoadResult(result: LoadSkillsResult): void {\n this.skillPrompt = result.prompt;\n this.skills = result.skills;\n this.version += 1;\n this.loadedAt = Date.now();\n\n for (const diag of result.diagnostics) {\n if (diag.type === 'warning') {\n log.warn({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill warning');\n } else if (diag.type === 'error') {\n log.error({ skill: diag.skillName, path: diag.path, message: diag.message }, 'Skill error');\n }\n }\n }\n\n /**\n * Get the skill prompt to append to system prompt\n */\n getPrompt(): string {\n return this.skillPrompt;\n }\n\n /**\n * `<available_skills>` XML with optional per-agent allowlist and/or tool-based gating.\n * When both arguments are omitted, returns the cached prompt from disk load (no tool gating).\n */\n getPromptForSkillAllowlist(\n allowlist: string[] | undefined,\n registeredToolNames?: string[],\n ): string {\n if (allowlist === undefined && registeredToolNames === undefined) {\n return this.getPrompt();\n }\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return formatSkillsForPrompt(this.getSkills(), skillsConfig, {\n skillAllowlist: allowlist,\n registeredToolNames,\n });\n }\n\n /** Skills visible for prompts and skills_list given the same indexing options as {@link getPromptForSkillAllowlist}. */\n selectSkillsForAgentIndexing(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return selectSkillsVisibleInPrompt(this.getSkills(), skillsConfig, options);\n }\n\n /**\n * Get all loaded skills\n */\n getSkills(): Skill[] {\n return [...this.skills];\n }\n\n getDiagnostics(): SkillDiagnostic[] {\n return this.skillLoader.getDiagnostics();\n }\n\n getVersion(): string {\n return String(this.version);\n }\n\n getLoadedAt(): number {\n return this.loadedAt;\n }\n\n getStatus(): SkillRuntimeStatus {\n return {\n version: this.getVersion(),\n loadedAt: this.loadedAt,\n reloadInProgress: this.reloadInProgress,\n reloadPending: this.reloadPending,\n ...(this.lastReloadStartedAt !== undefined ? { lastReloadStartedAt: this.lastReloadStartedAt } : {}),\n ...(this.lastReloadFinishedAt !== undefined ? { lastReloadFinishedAt: this.lastReloadFinishedAt } : {}),\n ...(this.lastReloadReason !== undefined ? { lastReloadReason: this.lastReloadReason } : {}),\n ...(this.lastReloadOk !== undefined ? { lastReloadOk: this.lastReloadOk } : {}),\n ...(this.lastReloadError !== undefined ? { lastReloadError: this.lastReloadError } : {}),\n };\n }\n\n /**\n * Get skill names\n */\n getSkillNames(): string[] {\n return this.skills.map((s) => s.name);\n }\n\n /** Names of skills included in the agent system prompt (`<available_skills>`). */\n getSkillNamesForPrompt(): string[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills()\n .filter((s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig))\n .map((s) => s.name);\n }\n\n /**\n * Skills that are enabled for model discovery (respects skills.json and requirement checks).\n */\n getEnabledSkills(): Skill[] {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n return this.getSkills().filter(\n (s) => !s.disableModelInvocation && isSkillEnabled(s, skillsConfig),\n );\n }\n\n /**\n * Like {@link getEnabledSkills} plus optional allowlist and tool gating (matches `<available_skills>`).\n */\n getEnabledSkillsForAgentSession(options?: {\n skillAllowlist?: string[];\n registeredToolNames?: string[];\n }): Skill[] {\n return this.selectSkillsForAgentIndexing(options);\n }\n\n getActivatedCapabilitiesForText(\n text: string,\n options?: { skillAllowlist?: string[]; registeredToolNames?: string[] },\n ): string[] {\n if (!text.includes('/skill:')) return [];\n const selected = new Set<string>();\n for (const match of text.matchAll(SKILL_TOKEN_RE)) {\n if (match[1]) selected.add(match[1]);\n }\n if (selected.size === 0) return [];\n\n const visible = this.selectSkillsForAgentIndexing(options);\n const activeCapabilities = new Set<string>();\n for (const skill of visible) {\n if (!selected.has(skill.name)) continue;\n for (const capabilityName of skill.metadata.xopc?.activatesCapabilities ?? []) {\n const trimmed = capabilityName.trim();\n if (trimmed) activeCapabilities.add(trimmed);\n }\n }\n return [...activeCapabilities];\n }\n\n /**\n * Find a skill by name\n */\n findSkill(name: string): Skill | undefined {\n return this.skills.find(s => s.name === name);\n }\n\n /**\n * Check if a skill exists\n */\n hasSkill(name: string): boolean {\n return this.skills.some(s => s.name === name);\n }\n\n /**\n * Expand a skill command into a full skill block\n */\n expandCommand(text: string, options?: { skillAllowlist?: string[]; registeredToolNames?: string[] }): string {\n if (!text.startsWith('/skill:')) {\n return text;\n }\n\n const { skillName, args } = this.parseSkillCommand(text);\n const visible = this.selectSkillsForAgentIndexing(options);\n const skill = visible.find((s) => s.name === skillName);\n\n if (!skill) {\n log.warn({ skillName }, 'Skill not visible for expansion');\n return text;\n }\n\n return this.buildSkillBlock(skill, args);\n }\n\n /**\n * Parse a /skill: command\n */\n private parseSkillCommand(text: string): { skillName: string; args?: string } {\n // Format: /skill:name args...\n const withoutPrefix = text.slice(7); // Remove '/skill:'\n const spaceIndex = withoutPrefix.indexOf(' ');\n\n if (spaceIndex === -1) {\n return { skillName: withoutPrefix.trim() };\n }\n\n return {\n skillName: withoutPrefix.slice(0, spaceIndex).trim(),\n args: withoutPrefix.slice(spaceIndex + 1).trim(),\n };\n }\n\n /**\n * Build a skill block for inclusion in the prompt\n */\n private buildSkillBlock(skill: Skill, args?: string): string {\n let block = `\\n\\n## Skill: ${skill.name}\\n\\n`;\n \n if (skill.description) {\n block += `${skill.description}\\n\\n`;\n }\n\n // Include raw skill content (SKILL.md content)\n if (skill.content) {\n block += `${skill.content}\\n\\n`;\n }\n\n if (args) {\n block += `**Arguments**: ${args}\\n\\n`;\n }\n\n return block;\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,10 +2,14 @@ import { join } from "node:path";
|
|
|
2
2
|
//#region src/agent/skills/workspace-skills-dir.ts
|
|
3
3
|
const PROJECT_XOPC_DIR = ".xopc";
|
|
4
4
|
const PROJECT_SKILLS_DIR = "skills";
|
|
5
|
+
const PROJECT_SKILLS_LOCK = "skills-lock.json";
|
|
5
6
|
function resolveWorkspaceSkillsDir(workspaceDir) {
|
|
6
7
|
return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_DIR);
|
|
7
8
|
}
|
|
9
|
+
function resolveWorkspaceSkillsLockPath(workspaceDir) {
|
|
10
|
+
return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_LOCK);
|
|
11
|
+
}
|
|
8
12
|
//#endregion
|
|
9
|
-
export { resolveWorkspaceSkillsDir };
|
|
13
|
+
export { resolveWorkspaceSkillsDir, resolveWorkspaceSkillsLockPath };
|
|
10
14
|
|
|
11
15
|
//# sourceMappingURL=workspace-skills-dir.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-skills-dir.js","names":[],"sources":["../../../../src/agent/skills/workspace-skills-dir.ts"],"sourcesContent":["import { join } from 'node:path';\n\nconst PROJECT_XOPC_DIR = '.xopc';\nconst PROJECT_SKILLS_DIR = 'skills';\n\nexport function resolveWorkspaceSkillsDir(workspaceDir: string): string {\n return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_DIR);\n}\n"],"mappings":";;AAEA,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;
|
|
1
|
+
{"version":3,"file":"workspace-skills-dir.js","names":[],"sources":["../../../../src/agent/skills/workspace-skills-dir.ts"],"sourcesContent":["import { join } from 'node:path';\n\nconst PROJECT_XOPC_DIR = '.xopc';\nconst PROJECT_SKILLS_DIR = 'skills';\nconst PROJECT_SKILLS_LOCK = 'skills-lock.json';\n\nexport function resolveWorkspaceSkillsDir(workspaceDir: string): string {\n return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_DIR);\n}\n\nexport function resolveWorkspaceSkillsLockPath(workspaceDir: string): string {\n return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_LOCK);\n}\n"],"mappings":";;AAEA,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAE5B,SAAgB,0BAA0B,cAA8B;AACtE,QAAO,KAAK,cAAc,kBAAkB,mBAAmB;;AAGjE,SAAgB,+BAA+B,cAA8B;AAC3E,QAAO,KAAK,cAAc,kBAAkB,oBAAoB"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
2
2
|
import type { AutomationService } from '../../automations/index.js';
|
|
3
|
-
declare const AutomationToolSchema: import("@sinclair/typebox
|
|
4
|
-
action: import("@sinclair/typebox
|
|
5
|
-
automationId: import("@sinclair/typebox
|
|
6
|
-
automation: import("@sinclair/typebox
|
|
7
|
-
patch: import("@sinclair/typebox
|
|
8
|
-
limit: import("@sinclair/typebox
|
|
3
|
+
declare const AutomationToolSchema: import("@sinclair/typebox").TObject<{
|
|
4
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"list">, import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"update">, import("@sinclair/typebox").TLiteral<"delete">, import("@sinclair/typebox").TLiteral<"run">, import("@sinclair/typebox").TLiteral<"pause">, import("@sinclair/typebox").TLiteral<"resume">, import("@sinclair/typebox").TLiteral<"history">]>;
|
|
5
|
+
automationId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
6
|
+
automation: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TAny>;
|
|
7
|
+
patch: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TAny>;
|
|
8
|
+
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
9
9
|
}>;
|
|
10
10
|
export interface AutomationToolDeps {
|
|
11
11
|
getAutomationService: () => AutomationService | undefined;
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.
|
|
3
3
|
*/
|
|
4
|
-
export declare const BrowserUsePipelineSchema: import("@sinclair/typebox
|
|
5
|
-
yaml: import("@sinclair/typebox
|
|
6
|
-
path: import("@sinclair/typebox
|
|
7
|
-
args: import("@sinclair/typebox
|
|
8
|
-
dryRun: import("@sinclair/typebox
|
|
4
|
+
export declare const BrowserUsePipelineSchema: import("@sinclair/typebox").TObject<{
|
|
5
|
+
yaml: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
6
|
+
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
7
|
+
args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
8
|
+
dryRun: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
9
9
|
}>;
|
|
10
|
-
export declare const BrowserUseOptionsSchema: import("@sinclair/typebox
|
|
11
|
-
timeout: import("@sinclair/typebox
|
|
12
|
-
headless: import("@sinclair/typebox
|
|
10
|
+
export declare const BrowserUseOptionsSchema: import("@sinclair/typebox").TObject<{
|
|
11
|
+
timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
12
|
+
headless: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
13
13
|
}>;
|
|
14
|
-
export declare const BrowserUseSchema: import("@sinclair/typebox
|
|
15
|
-
mode: import("@sinclair/typebox
|
|
16
|
-
command: import("@sinclair/typebox
|
|
17
|
-
args: import("@sinclair/typebox
|
|
18
|
-
pipeline: import("@sinclair/typebox
|
|
19
|
-
yaml: import("@sinclair/typebox
|
|
20
|
-
path: import("@sinclair/typebox
|
|
21
|
-
args: import("@sinclair/typebox
|
|
22
|
-
dryRun: import("@sinclair/typebox
|
|
14
|
+
export declare const BrowserUseSchema: import("@sinclair/typebox").TObject<{
|
|
15
|
+
mode: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"command">, import("@sinclair/typebox").TLiteral<"pipeline">, import("@sinclair/typebox").TLiteral<"inspect">, import("@sinclair/typebox").TLiteral<"close">]>;
|
|
16
|
+
command: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
17
|
+
args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
18
|
+
pipeline: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
19
|
+
yaml: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
20
|
+
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
21
|
+
args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
22
|
+
dryRun: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
23
23
|
}>>;
|
|
24
|
-
options: import("@sinclair/typebox
|
|
25
|
-
timeout: import("@sinclair/typebox
|
|
26
|
-
headless: import("@sinclair/typebox
|
|
24
|
+
options: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
25
|
+
timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
26
|
+
headless: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
27
27
|
}>>;
|
|
28
28
|
}>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
2
2
|
import type { Config } from '../../config/schema.js';
|
|
3
|
-
declare const ComposioExecuteSchema: import("@sinclair/typebox
|
|
4
|
-
slug: import("@sinclair/typebox
|
|
5
|
-
arguments: import("@sinclair/typebox
|
|
3
|
+
declare const ComposioExecuteSchema: import("@sinclair/typebox").TObject<{
|
|
4
|
+
slug: import("@sinclair/typebox").TString;
|
|
5
|
+
arguments: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TAny>;
|
|
6
6
|
}>;
|
|
7
7
|
export declare function createComposioExecuteTool(getConfig: () => Config | undefined): AgentTool<typeof ComposioExecuteSchema, {}> | null;
|
|
8
8
|
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { AgentToolWithMetadata } from './metadata.js';
|
|
2
|
-
declare const DesktopPetCreateSchema: import("@sinclair/typebox
|
|
3
|
-
mode: import("@sinclair/typebox
|
|
4
|
-
petId: import("@sinclair/typebox
|
|
5
|
-
prompt: import("@sinclair/typebox
|
|
6
|
-
name: import("@sinclair/typebox
|
|
7
|
-
description: import("@sinclair/typebox
|
|
8
|
-
overwrite: import("@sinclair/typebox
|
|
2
|
+
declare const DesktopPetCreateSchema: import("@sinclair/typebox").TObject<{
|
|
3
|
+
mode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"update">]>>;
|
|
4
|
+
petId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
5
|
+
prompt: import("@sinclair/typebox").TString;
|
|
6
|
+
name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
7
|
+
description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
8
|
+
overwrite: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
9
9
|
}>;
|
|
10
10
|
export type DesktopPetCreateDetails = {
|
|
11
11
|
ok: true;
|
|
@@ -10,6 +10,7 @@ import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
|
10
10
|
import type { Model, Api } from '@earendil-works/pi-ai';
|
|
11
11
|
import type { Config } from '../../config/schema.js';
|
|
12
12
|
import type { MessageBus } from '../../infra/bus/index.js';
|
|
13
|
+
import { type SkillInstallToolOptions, type SkillInstallToolResult } from './index.js';
|
|
13
14
|
import type { MemoryManager } from '../memory/manager.js';
|
|
14
15
|
import type { SessionStore } from '../../session/store.js';
|
|
15
16
|
import type { GatewayClarifyRequestFn } from './clarify-tool.js';
|
|
@@ -62,6 +63,8 @@ export interface ToolFactoryDeps {
|
|
|
62
63
|
getSkillPassthroughEnvVarNames?: () => string[];
|
|
63
64
|
/** Add declared env names for the current session (no values stored). */
|
|
64
65
|
registerSkillEnvPassthrough?: (names: string[]) => void;
|
|
66
|
+
/** Install managed skills from explicit sources when a capability/tool enables it. */
|
|
67
|
+
installSkillFromSource?: (opts: SkillInstallToolOptions) => Promise<SkillInstallToolResult>;
|
|
65
68
|
}
|
|
66
69
|
export interface CreateCoreToolsOptions {
|
|
67
70
|
/** Workspace root for file/command tools (defaults to factory workspace). */
|
|
@@ -36,6 +36,7 @@ import { createGoalTool } from "./goal-tool.js";
|
|
|
36
36
|
import { createXopcUseTool } from "./xopc-use-tool.js";
|
|
37
37
|
import { createSkillViewTool, createSkillsListTool } from "./skills-tools.js";
|
|
38
38
|
import { createSkillManageTool } from "./skill-manage-tool.js";
|
|
39
|
+
import { createSkillInstallTool } from "./skill-install-tool.js";
|
|
39
40
|
import { createToolManualTool } from "./tool-manual-tool.js";
|
|
40
41
|
import { createDesktopPetTool } from "./desktop-pet-tool.js";
|
|
41
42
|
import { createImageTool } from "./image-tool.js";
|
|
@@ -296,11 +297,15 @@ var AgentToolsFactory = class {
|
|
|
296
297
|
if (disabled?.has(toolName) || toolNames.has(toolName)) continue;
|
|
297
298
|
toolNames.add(toolName);
|
|
298
299
|
if (toolName === "create_desktop_pet") raw.push(createDesktopPetTool());
|
|
300
|
+
if (toolName === "skill_install") raw.push(createSkillInstallTool({
|
|
301
|
+
installSkillFromSource: this.deps.installSkillFromSource,
|
|
302
|
+
getSessionKey: () => this.deps.getCurrentContext()?.sessionKey
|
|
303
|
+
}));
|
|
299
304
|
}
|
|
300
305
|
return wrapToolsWithProtection(raw, this.deps.toolExecutorConfig);
|
|
301
306
|
}
|
|
302
307
|
getLazyCapabilityToolNames() {
|
|
303
|
-
return ["create_desktop_pet"];
|
|
308
|
+
return ["create_desktop_pet", ...this.deps.installSkillFromSource ? ["skill_install"] : []];
|
|
304
309
|
}
|
|
305
310
|
createAllTools(coreOptions) {
|
|
306
311
|
const coreTools = this.createCoreTools(coreOptions);
|