@xopcai/xopc 0.0.111 → 0.0.113
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/icons/icon-128.png +0 -0
- package/dist/browser-ext/icons/icon-16.png +0 -0
- package/dist/browser-ext/icons/icon-32.png +0 -0
- package/dist/browser-ext/icons/icon-48.png +0 -0
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/delivery-to.d.ts +3 -3
- package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/apple-touch-icon.png +0 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-zlx9l5Yp.js → agent-avatar-dicebear-CBlklyNr.js} +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +6 -0
- package/dist/gateway/static/root/assets/{agent-defaults-tabbed-page-Bz7JWjRM.js → agent-defaults-tabbed-page-CtwVbjOA.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +71 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DaQwdeCq.js → app-management-settings-panel-28E_WfMe.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-D2zv6r3P.js → appearance-settings-Do1z0XgJ.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BIppe_jj.js → apps-page-xwCsJS15.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DEmu8eH7.js → archive-plugin-BAFlsov_.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-B98lJoN5.js → attachment-load-V3qGPC3x.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-CL9QKmyo.js → binary-plugins-DT8NvA6W.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BOAhMAhT.js → block-editor-CdLMEcHd.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-Br8iRnXp.js → channels-settings-C044DcYk.js} +1 -1
- package/dist/gateway/static/root/assets/{config-api-0o1WYdz2.js → config-api-Bf5mjpu7.js} +1 -1
- package/dist/gateway/static/root/assets/config-reload-event-Bjh2zoKp.js +1 -0
- package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +2 -0
- package/dist/gateway/static/root/assets/cron-api--pAB_rps.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +3 -0
- package/dist/gateway/static/root/assets/dreaming-settings-6UZE1FSK.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-Cjx6pZVz.js → extension-debug-page-BGhE7msg.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BSPNL90V.js → extension-page-CvpI45WG.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-DAmR5FUe.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-Bs7in_4F.js → fetch-NZmjSXLl.js} +1 -1
- package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +2 -0
- package/dist/gateway/static/root/assets/{format-interval-label-CftJ5uXu.js → format-interval-label-qhth3BMV.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Clfck-hW.js → gateway-config-api-CaXBt-9R.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-DphpbLBc.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BkjVJc38.js → gateway-startup-retry-Be1omjh3.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-detail-page-kqJue0sE.js → goal-detail-page-bv0VRDaf.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-CJnzNSDo.js → goals-settings-ceEBjnfc.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-Cp7CPuIn.js → heartbeat-config-api-BzO6G4fD.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-ifSI1Wbh.js → heartbeat-settings-DCST9-du.js} +1 -1
- package/dist/gateway/static/root/assets/index-Cxm6xsps.js +122 -0
- package/dist/gateway/static/root/assets/index-b_R4tKqt.css +1 -0
- package/dist/gateway/static/root/assets/interval-presets-DJmshV8n.js +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings--MI1rYl7.js → keyboard-shortcuts-settings-9AUUlQ5Q.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-BwrVNlyW.js → logs-page-B_wrxhee.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-B_oc9lJe.js → markdown-split-CYYELqAr.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-DLPvB5H3.js → media-plugins-BEcMR2M8.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-rSqAgOi9.js → note-image-lightbox-DNAoPcmm.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-C9ACGEty.js → notes-page-CdkjTch8.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Bw_N2oZi.js → preview-open-alternatives-BPLz0AIv.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-BhcWIKuM.js → remote-access-hub-DSYVAi96.js} +1 -1
- package/dist/gateway/static/root/assets/{save-bar-controls-CNP2jmw0.js → save-bar-controls-CrWwWRVK.js} +1 -1
- package/dist/gateway/static/root/assets/schedule-field-CF2sadvN.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-CDPzua9q.js → schema-form-Di5cKjYE.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-DzkpSDZr.js → sessions-page-CenkcVjF.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-C9bff85B.js → settings-collapsible-section-Chh282jW.js} +1 -1
- package/dist/gateway/static/root/assets/settings-form-section-Dq-83cQd.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-DWK4Zo7s.js → settings-page-DL35U0x0.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DnutoY_S.js → share-preview-page-0FXYnSUA.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-6oRgJMpn.js → shares-settings-DIM3JNsr.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-qP1JDtDd.js → system-settings-panel-W1pTcojB.js} +1 -1
- package/dist/gateway/static/root/assets/use-agent-defaults-form-BVRvkK7m.js +1 -0
- package/dist/gateway/static/root/assets/{use-channel-catalog-C4mg1hjD.js → use-channel-catalog-CgJibfMM.js} +1 -1
- package/dist/gateway/static/root/assets/{use-settings-tab-guard-F6C0mpJt.js → use-settings-tab-guard-Bw_qkRQE.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-BnDDb6qO.js → voice-api-key-field-vYAO71Gn.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-player-store-B2EwIhtY.js → voice-player-store-C7lziaAx.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-CRB7WX9l.js → workflow-page.utils-sgHjOXOm.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-2Fptr0je.js → workflows-page-DYyOTmFx.js} +1 -1
- package/dist/gateway/static/root/favicon-16x16.png +0 -0
- package/dist/gateway/static/root/favicon-32x32.png +0 -0
- package/dist/gateway/static/root/favicon-icon.svg +1 -0
- package/dist/gateway/static/root/favicon.ico +0 -0
- package/dist/gateway/static/root/favicon.png +0 -0
- package/dist/gateway/static/root/favicon.svg +24 -15
- package/dist/gateway/static/root/index.html +11 -10
- package/dist/gateway/static/root/logo-dark.svg +23 -15
- package/dist/gateway/static/root/logo.svg +23 -16
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +28 -2
- package/dist/src/agent/agent-manager.js +82 -11
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/context/workspace.js +1 -1
- package/dist/src/agent/goals/goal-locale.js +2 -2
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +3 -3
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/inbox.js +3 -3
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +3 -0
- package/dist/src/agent/messaging/command-handler.js +5 -0
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/memory/index.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +9 -4
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/reconcile-dreaming-cron.js +8 -5
- package/dist/src/agent/service/reconcile-dreaming-cron.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +10 -5
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +4 -0
- package/dist/src/agent/session/session-config-service.d.ts +8 -0
- package/dist/src/agent/session/session-config-service.js +20 -0
- package/dist/src/agent/session/session-config-service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +2 -2
- package/dist/src/agent/skills/filesystem-watcher.d.ts +19 -0
- package/dist/src/agent/skills/filesystem-watcher.js +182 -0
- package/dist/src/agent/skills/filesystem-watcher.js.map +1 -0
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +30 -36
- package/dist/src/agent/skills/hub-pull.js.map +1 -1
- package/dist/src/agent/skills/index.js +82 -38
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/installer.js +2 -2
- package/dist/src/agent/skills/managed-store.d.ts +19 -0
- package/dist/src/agent/skills/managed-store.js +97 -38
- package/dist/src/agent/skills/managed-store.js.map +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.d.ts +16 -6
- package/dist/src/agent/skills/skill-manager.js +79 -24
- package/dist/src/agent/skills/skill-manager.js.map +1 -1
- package/dist/src/agent/skills/skill-view-path.js +1 -1
- package/dist/src/agent/skills/test-framework.js +1 -1
- package/dist/src/agent/skills/types.d.ts +11 -0
- package/dist/src/agent/skills/watcher.js +1 -1
- package/dist/src/agent/starter-agents.js +1 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +6 -3
- package/dist/src/agent/tools/cronjob-tool.js +58 -23
- package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/find.js +1 -1
- package/dist/src/agent/tools/grep.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workspace-runtime/registry.d.ts +5 -0
- package/dist/src/agent/workspace-runtime/registry.js +7 -0
- package/dist/src/agent/workspace-runtime/registry.js.map +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +42 -0
- package/dist/src/ai-assist/text-assist.js +252 -0
- package/dist/src/ai-assist/text-assist.js.map +1 -0
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/profiles/store.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/cloakbrowser.js +5 -5
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/channels/plugins/types.adapters.d.ts +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +3 -3
- package/dist/src/chat-commands/builtins/system.js +11 -4
- package/dist/src/chat-commands/builtins/system.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +3 -0
- package/dist/src/chat-commands/context.js +7 -0
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +2 -0
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/cron.js +55 -16
- package/dist/src/cli/commands/cron.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/cron-health.js +2 -83
- package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-create.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +2 -2
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension-pack.js +2 -2
- package/dist/src/cli/commands/extension.js +3 -3
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +2 -2
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/skills-test.js +1 -1
- package/dist/src/cli/templates.js +1 -1
- package/dist/src/cli/utils/gateway-client.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/agent-typed-models.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +7 -7
- package/dist/src/config/loader.js +4 -4
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/paths.js +1 -1
- package/dist/src/config/profile.js +1 -1
- package/dist/src/config/reload.js +1 -1
- package/dist/src/config/schema.d.ts +0 -2
- package/dist/src/config/schema.js +0 -3
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +0 -1
- package/dist/src/config/web-patch.js +0 -2
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.js +102 -71
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/index.d.ts +1 -1
- package/dist/src/cron/index.js +3 -3
- package/dist/src/cron/run-log-store.d.ts +1 -0
- package/dist/src/cron/run-log-store.js +4 -2
- package/dist/src/cron/run-log-store.js.map +1 -1
- package/dist/src/cron/schedule.d.ts +10 -0
- package/dist/src/cron/schedule.js +85 -0
- package/dist/src/cron/schedule.js.map +1 -0
- package/dist/src/cron/service.d.ts +34 -77
- package/dist/src/cron/service.js +327 -264
- package/dist/src/cron/service.js.map +1 -1
- package/dist/src/cron/types.d.ts +80 -50
- package/dist/src/cron/validation.d.ts +358 -90
- package/dist/src/cron/validation.js +152 -132
- package/dist/src/cron/validation.js.map +1 -1
- package/dist/src/cron/workflow-run-completion.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +2 -2
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/install.js +2 -2
- package/dist/src/extensions/loader.js +2 -2
- package/dist/src/extensions/lockfile.js +3 -3
- package/dist/src/extensions/security.js +1 -1
- package/dist/src/extensions/update.js +2 -2
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/chat-stream/mapper.d.ts +1 -0
- package/dist/src/gateway/chat-stream/mapper.js +6 -2
- 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/file-path-classifier.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.d.ts +0 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/ai-assist.d.ts +3 -0
- package/dist/src/gateway/hono/routes/ai-assist.js +66 -0
- package/dist/src/gateway/hono/routes/ai-assist.js.map +1 -0
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +7 -0
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/cron.js +24 -5
- package/dist/src/gateway/hono/routes/cron.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/home.js +5 -3
- package/dist/src/gateway/hono/routes/home.js.map +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- 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/models.js +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/marketplace-service.d.ts +22 -10
- package/dist/src/gateway/service/marketplace-service.js +46 -5
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/gateway/service.js +11 -5
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/goals/goal-notifications.js +1 -1
- package/dist/src/goals/goal-workflow-judge.js +3 -3
- package/dist/src/i18n/goals-bundle.js +1 -1
- package/dist/src/i18n/index.js +1 -1
- package/dist/src/i18n/share-tool-bundle.js +2 -2
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +1 -1
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +2 -2
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +1 -1
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/agent-context.js +1 -1
- package/dist/src/notes/service.js +1 -1
- package/dist/src/notes/store.js +2 -2
- package/dist/src/project-trust/trust-store.js +2 -2
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +1 -1
- package/dist/src/providers/model-registry.js +4 -4
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/resolve-session.js +3 -3
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store-reader.d.ts +5 -0
- package/dist/src/session/store-reader.js +1 -0
- package/dist/src/session/store.js +1 -1
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +1 -1
- package/dist/src/storage/sqlite/cron-job-repository.d.ts +6 -0
- package/dist/src/storage/sqlite/cron-job-repository.js +70 -0
- package/dist/src/storage/sqlite/cron-job-repository.js.map +1 -0
- package/dist/src/storage/sqlite/cron-run-repository.js +0 -1
- package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/009_cron_jobs.sql +24 -0
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +4 -4
- 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 +2 -2
- package/dist/src/storage/sqlite/schema.sql +25 -0
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-command-formatters.js +4 -4
- package/dist/src/tui/tui-commands.js +2 -2
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui.js +6 -6
- package/dist/src/tunnel/frpc-binary.js +4 -4
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/logger/streams.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/engine/projector.js +23 -14
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.d.ts +1 -0
- package/dist/src/workflows/engine/workflow-engine.js +36 -0
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +2 -2
- package/dist/src/workflows/service/workflow-session-bridge.js +2 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +2 -3
- package/dist/gateway/static/root/assets/agent-browser-settings-page-B-0zGjt8.js +0 -6
- package/dist/gateway/static/root/assets/agents-DwDnJlXT.js +0 -71
- package/dist/gateway/static/root/assets/connectors-settings-DDvHo9in.js +0 -2
- package/dist/gateway/static/root/assets/cron-api-Dj_UZKST.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-Dv7GII9G.js +0 -1
- package/dist/gateway/static/root/assets/cron-schedule-picker-DH10KgD6.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-L2rgZDQl.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-m_UQYkVc.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CS177xni.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-C0FujUB5.js +0 -2
- package/dist/gateway/static/root/assets/index-COkF54xv.js +0 -121
- package/dist/gateway/static/root/assets/index-DIaSNGEO.css +0 -1
- package/dist/gateway/static/root/assets/interval-presets-B29Ss_2y.js +0 -2
- package/dist/gateway/static/root/assets/messages-Csef1aW7.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DHGiTIvf.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-BM7zlDiT.js +0 -2
- package/dist/gateway/static/root/assets/schedule-field-BPAWui3P.js +0 -1
- package/dist/gateway/static/root/assets/schedule-summary-B-hdSRdR.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BYS-rpzn.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-BsrK7TBF.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DJiksNu4.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CU9i0nJV.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-ERbdWENm.js +0 -2
- package/dist/gateway/static/root/assets/use-agent-defaults-form-D3FGVLZb.js +0 -1
- package/dist/gateway/static/root/favicon-16.png +0 -0
- package/dist/gateway/static/root/favicon-32.png +0 -0
- package/dist/src/cron/persistence.d.ts +0 -62
- package/dist/src/cron/persistence.js +0 -188
- package/dist/src/cron/persistence.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/agent/skills/index.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'fs';\nimport { basename, dirname, join, relative, sep } from 'path';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt } from './format-skills-prompt.js';\nimport { parseRequiredEnvVarNames } from './required-env-vars.js';\nimport { parseSkillMetadata } from './parse-skill-metadata.js';\nimport { parseSkillToolConditions } from './skill-tool-gating.js';\nimport type { Skill, SkillDiagnostic, LoadSkillsResult, SkillConfig, SkillsConfig } from './types.js';\n\nconst log = createLogger('SkillLoader');\n\nconst IGNORE_FILES = ['.gitignore', '.ignore', '.fdignore'];\n\nfunction toPosixPath(p: string): string {\n return p.split(sep).join('/');\n}\n\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n if (trimmed.startsWith('#') && !trimmed.startsWith('\\\\#')) return null;\n\n let pattern = line;\n let negated = false;\n\n if (pattern.startsWith('!')) {\n negated = true;\n pattern = pattern.slice(1);\n } else if (pattern.startsWith('\\\\!')) {\n pattern = pattern.slice(1);\n }\n\n if (pattern.startsWith('/')) {\n pattern = pattern.slice(1);\n }\n\n const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n return negated ? `!${prefixed}` : prefixed;\n}\n\nfunction loadIgnoreRules(dir: string, rootDir: string): Set<string> {\n const ignoredPaths = new Set<string>();\n const relativeDir = relative(rootDir, dir);\n const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : '';\n\n for (const filename of IGNORE_FILES) {\n const ignorePath = join(dir, filename);\n if (!existsSync(ignorePath)) continue;\n\n try {\n const content = readFileSync(ignorePath, 'utf-8');\n for (const line of content.split(/\\r?\\n/)) {\n const pattern = prefixIgnorePattern(line, prefix);\n if (pattern) {\n const fullPattern = pattern.startsWith('!')\n ? `!${prefix}${pattern.slice(1)}`\n : `${prefix}${pattern}`;\n ignoredPaths.add(fullPattern);\n }\n }\n } catch {}\n }\n\n return ignoredPaths;\n}\n\nfunction shouldIgnore(path: string, ignoredPaths: Set<string>): boolean {\n for (const pattern of ignoredPaths) {\n if (pattern.startsWith('!')) {\n const positive = pattern.slice(1);\n if (path === positive || path.startsWith(`${positive}/`)) {\n return false;\n }\n } else {\n if (path === pattern || path.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction discoverSkills(dir: string, source: 'builtin' | 'workspace' | 'global'): Skill[] {\n const skills: Skill[] = [];\n if (!existsSync(dir)) return skills;\n\n function scan(currentDir: string, currentIgnoredPaths: Set<string>) {\n try {\n const entries = readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n\n const fullPath = join(currentDir, entry.name);\n const relPath = toPosixPath(relative(dir, fullPath));\n\n if (shouldIgnore(relPath, currentIgnoredPaths)) continue;\n\n if (entry.isDirectory()) {\n const skillMdPath = join(fullPath, 'SKILL.md');\n const skillRelPath = `${relPath}/`;\n\n const subIgnoredPaths = new Set(currentIgnoredPaths);\n const subIgnoreFile = join(fullPath, '.gitignore');\n if (existsSync(subIgnoreFile)) {\n const subRules = loadIgnoreRules(fullPath, dir);\n for (const rule of subRules) {\n subIgnoredPaths.add(`${skillRelPath}${rule}`);\n }\n }\n\n if (existsSync(skillMdPath) && !shouldIgnore(skillRelPath, currentIgnoredPaths)) {\n const skill = loadSkillFromFile(skillMdPath, source, dir);\n if (skill) skills.push(skill);\n }\n\n scan(fullPath, subIgnoredPaths);\n }\n }\n } catch {}\n }\n\n scan(dir, loadIgnoreRules(dir, dir));\n return skills;\n}\n\nfunction deriveDescriptionFromMarkdown(content: string): string | undefined {\n let fallbackHeading = '';\n\n for (const rawLine of content.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (!line) continue;\n\n const heading = line.match(/^#{1,6}\\s+(.+)$/);\n if (heading) {\n fallbackHeading ||= heading[1]?.trim() ?? '';\n continue;\n }\n\n return line\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1')\n .replace(/[*_`~]/g, '')\n .trim() || undefined;\n }\n\n return fallbackHeading || undefined;\n}\n\nfunction loadSkillFromFile(filePath: string, source: 'builtin' | 'workspace' | 'global', rootDir?: string): Skill | null {\n try {\n const rawContent = readFileSync(filePath, 'utf-8');\n const { frontmatter, content } = parseFrontmatter(rawContent);\n const skillDir = dirname(filePath);\n const parentDirName = basename(skillDir);\n\n const name = (frontmatter.name as string | undefined) || parentDirName;\n const description =\n (frontmatter.description as string | undefined)?.trim() || deriveDescriptionFromMarkdown(content);\n if (!description?.trim()) return null;\n\n // Derive category from directory path: skills/creative/algorithmic-art → 'creative'\n // Only assign a category when the skill is nested at least two levels below rootDir.\n let category: string | undefined;\n if (rootDir) {\n const relDir = toPosixPath(relative(rootDir, skillDir));\n const segments = relDir.split('/');\n if (segments.length > 1) {\n category = segments[0];\n }\n }\n\n const metadata = parseSkillMetadata(frontmatter);\n metadata.name ||= name;\n metadata.description ||= description.trim();\n const toolConditions = parseSkillToolConditions(frontmatter);\n const requiredEnvVarNames = parseRequiredEnvVarNames(frontmatter);\n\n return {\n name,\n description: description.trim(),\n category,\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: frontmatter['disable-model-invocation'] === true,\n metadata,\n toolConditions,\n requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : undefined,\n content,\n };\n } catch {\n return null;\n }\n}\n\nexport function loadSkills(options: {\n workspaceDir?: string;\n globalDir?: string;\n builtinDir?: string;\n extraDirs?: string[];\n}): LoadSkillsResult {\n const { workspaceDir, builtinDir, extraDirs = [] } = options;\n\n const skillMap = new Map<string, Skill>();\n const diagnostics: SkillDiagnostic[] = [];\n\n if (builtinDir) {\n for (const skill of discoverSkills(builtinDir, 'builtin')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n\n const globalDirs = [\n options.globalDir,\n join(resolveStateDir(), 'skills'),\n ].filter((d): d is string => !!d && existsSync(d));\n\n for (const dir of globalDirs) {\n for (const skill of discoverSkills(dir, 'global')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n // Global must win over bundled when names match (Workspace > Global > Bundled).\n skillMap.set(skill.name, skill);\n }\n }\n\n if (workspaceDir) {\n const workspaceSkills = discoverSkills(join(workspaceDir, 'skills'), 'workspace');\n for (const skill of workspaceSkills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n skillMap.set(skill.name, skill);\n }\n }\n\n // Scan extra directories\n for (const extraDir of extraDirs) {\n if (existsSync(extraDir)) {\n for (const skill of discoverSkills(extraDir, 'global')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const merged = Array.from(skillMap.values());\n\n return {\n skills: merged,\n prompt: formatSkillsForPrompt(merged, skillsConfig),\n diagnostics,\n };\n}\n\nexport interface SkillLoader {\n init: (workspace: string, builtin: string | null) => LoadSkillsResult;\n load: () => LoadSkillsResult;\n reload: () => LoadSkillsResult;\n /** Recompute `<available_skills>` from disk-loaded skills and current ~/.xopc/skills.json (no filesystem rescan). */\n refreshPromptFromConfig: () => void;\n getSkills: () => Skill[];\n getPrompt: () => string;\n getDiagnostics: () => SkillDiagnostic[];\n getLastLoadTime: () => number;\n getSkillByName: (name: string) => Skill | undefined;\n getEnabledSkills: (config?: Record<string, SkillConfig>) => Skill[];\n}\n\nexport function createSkillLoader(): SkillLoader {\n let cachedSkills: Skill[] = [];\n let cachedPrompt: string = '';\n let cachedDiagnostics: SkillDiagnostic[] = [];\n let lastLoadTime = 0;\n let workspaceDir: string | undefined;\n let builtinDir: string | undefined;\n let extraDirs: string[] = [];\n\n function updateCache(result: LoadSkillsResult): LoadSkillsResult {\n cachedSkills = result.skills;\n cachedPrompt = result.prompt;\n cachedDiagnostics = result.diagnostics;\n lastLoadTime = Date.now();\n return result;\n }\n\n return {\n init: (workspace: string, builtin: string | null) => {\n workspaceDir = workspace;\n builtinDir = builtin || undefined;\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n load: () => {\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n reload: () => {\n log.info('Reloading skills');\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n\n refreshPromptFromConfig: () => {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n cachedPrompt = formatSkillsForPrompt(cachedSkills, skillsConfig);\n lastLoadTime = Date.now();\n },\n\n getSkills: () => cachedSkills,\n getPrompt: () => cachedPrompt,\n getDiagnostics: () => cachedDiagnostics,\n getLastLoadTime: () => lastLoadTime,\n \n getSkillByName: (name: string) => {\n return cachedSkills.find(s => s.name === name);\n },\n \n getEnabledSkills: (entries?: Record<string, SkillConfig>) => {\n const skillsConfig: SkillsConfig =\n entries !== undefined ? { entries } : createSkillConfigManager(resolveStateDir()).load();\n return cachedSkills.filter(\n (skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig),\n );\n },\n };\n}\n\n// `SkillManager` + sibling types removed from this barrel — `skill-manager.ts`\n// imports `createSkillLoader` from THIS file, so re-exporting it back here\n// formed a circular cycle. External callers should import directly from\n// `./skill-manager.js`.\n\n// Re-export types for convenience\nexport type { \n Skill, \n SkillMetadata, \n SkillConfig,\n SkillInstallSpec,\n SkillInstallResult,\n SkillInstallRequest,\n LoadSkillsResult,\n // Note: SkillDiagnostic is re-exported from skill-manager.ts above\n SkillSnapshot,\n} from './types.js';\n\n// Re-export installer\nexport { \n installSkill, \n findInstallSpec,\n hasBinary,\n getDefaultInstallerPreferences,\n type InstallerPreferences,\n type InstallContext,\n} from './installer.js';\n\n// Re-export scanner\nexport {\n scanSkillDirectory,\n formatScanSummary,\n collectSkillInstallWarnings,\n type ScanSummary,\n type SecurityFinding,\n type Severity,\n} from './scanner.js';\n\n// Re-export config manager\nexport {\n resolveSkillConfig,\n applySkillEnvOverrides,\n getSkillEnvironment,\n createSkillConfigManager,\n isSkillEnabled,\n validateSkillConfig,\n type SkillConfigFile,\n} from './config.js';\n\n// `watcher.ts` re-exports removed — it imports `SkillLoader` from THIS file, so\n// re-exporting back here formed a circular cycle. External callers should\n// import directly from `./watcher.js`.\n\n// Re-export test framework\nexport {\n SkillTestFramework,\n SkillTestRunner,\n formatTestResults,\n formatTestResultsJson,\n formatTestResultsTap,\n type TestResult,\n type TestStatus,\n type SkillTestReport,\n type TestOptions,\n type TestRunnerOptions,\n} from './test-framework.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/agent/skills/index.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'fs';\nimport { basename, dirname, join, relative, sep } from 'path';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt } from './format-skills-prompt.js';\nimport { parseRequiredEnvVarNames } from './required-env-vars.js';\nimport { parseSkillMetadata } from './parse-skill-metadata.js';\nimport { parseSkillToolConditions } from './skill-tool-gating.js';\nimport type { Skill, SkillDiagnostic, LoadSkillsResult, SkillConfig, SkillsConfig } from './types.js';\n\nconst log = createLogger('SkillLoader');\n\nconst IGNORE_FILES = ['.gitignore', '.ignore', '.fdignore'];\n\nfunction toPosixPath(p: string): string {\n return p.split(sep).join('/');\n}\n\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n if (trimmed.startsWith('#') && !trimmed.startsWith('\\\\#')) return null;\n\n let pattern = line;\n let negated = false;\n\n if (pattern.startsWith('!')) {\n negated = true;\n pattern = pattern.slice(1);\n } else if (pattern.startsWith('\\\\!')) {\n pattern = pattern.slice(1);\n }\n\n if (pattern.startsWith('/')) {\n pattern = pattern.slice(1);\n }\n\n const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n return negated ? `!${prefixed}` : prefixed;\n}\n\nfunction loadIgnoreRules(dir: string, rootDir: string): Set<string> {\n const ignoredPaths = new Set<string>();\n const relativeDir = relative(rootDir, dir);\n const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : '';\n\n for (const filename of IGNORE_FILES) {\n const ignorePath = join(dir, filename);\n if (!existsSync(ignorePath)) continue;\n\n try {\n const content = readFileSync(ignorePath, 'utf-8');\n for (const line of content.split(/\\r?\\n/)) {\n const pattern = prefixIgnorePattern(line, prefix);\n if (pattern) {\n const fullPattern = pattern.startsWith('!')\n ? `!${prefix}${pattern.slice(1)}`\n : `${prefix}${pattern}`;\n ignoredPaths.add(fullPattern);\n }\n }\n } catch {}\n }\n\n return ignoredPaths;\n}\n\nfunction shouldIgnore(path: string, ignoredPaths: Set<string>): boolean {\n for (const pattern of ignoredPaths) {\n if (pattern.startsWith('!')) {\n const positive = pattern.slice(1);\n if (path === positive || path.startsWith(`${positive}/`)) {\n return false;\n }\n } else {\n if (path === pattern || path.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction discoverSkills(\n dir: string,\n source: 'builtin' | 'workspace' | 'global',\n): { skills: Skill[]; diagnostics: SkillDiagnostic[] } {\n const skills: Skill[] = [];\n const diagnostics: SkillDiagnostic[] = [];\n if (!existsSync(dir)) return { skills, diagnostics };\n\n function scan(currentDir: string, currentIgnoredPaths: Set<string>) {\n try {\n const entries = readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n\n const fullPath = join(currentDir, entry.name);\n const relPath = toPosixPath(relative(dir, fullPath));\n\n if (shouldIgnore(relPath, currentIgnoredPaths)) continue;\n\n if (entry.isDirectory()) {\n const skillMdPath = join(fullPath, 'SKILL.md');\n const skillRelPath = `${relPath}/`;\n\n const subIgnoredPaths = new Set(currentIgnoredPaths);\n const subIgnoreFile = join(fullPath, '.gitignore');\n if (existsSync(subIgnoreFile)) {\n const subRules = loadIgnoreRules(fullPath, dir);\n for (const rule of subRules) {\n subIgnoredPaths.add(`${skillRelPath}${rule}`);\n }\n }\n\n if (existsSync(skillMdPath) && !shouldIgnore(skillRelPath, currentIgnoredPaths)) {\n const { skill, diagnostic } = loadSkillFromFile(skillMdPath, source, dir);\n if (diagnostic) diagnostics.push(diagnostic);\n if (skill) skills.push(skill);\n }\n\n scan(fullPath, subIgnoredPaths);\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n diagnostics.push({\n type: 'error',\n message: `Failed to scan skills directory: ${message}`,\n path: currentDir,\n });\n }\n }\n\n scan(dir, loadIgnoreRules(dir, dir));\n return { skills, diagnostics };\n}\n\nfunction deriveDescriptionFromMarkdown(content: string): string | undefined {\n let fallbackHeading = '';\n\n for (const rawLine of content.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (!line) continue;\n\n const heading = line.match(/^#{1,6}\\s+(.+)$/);\n if (heading) {\n fallbackHeading ||= heading[1]?.trim() ?? '';\n continue;\n }\n\n return line\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1')\n .replace(/[*_`~]/g, '')\n .trim() || undefined;\n }\n\n return fallbackHeading || undefined;\n}\n\nfunction loadSkillFromFile(\n filePath: string,\n source: 'builtin' | 'workspace' | 'global',\n rootDir?: string,\n): { skill: Skill | null; diagnostic?: SkillDiagnostic } {\n try {\n const rawContent = readFileSync(filePath, 'utf-8');\n const { frontmatter, content } = parseFrontmatter(rawContent);\n const skillDir = dirname(filePath);\n const parentDirName = basename(skillDir);\n\n const name = (frontmatter.name as string | undefined) || parentDirName;\n const description =\n (frontmatter.description as string | undefined)?.trim() || deriveDescriptionFromMarkdown(content);\n if (!description?.trim()) {\n return {\n skill: null,\n diagnostic: {\n type: 'error',\n skillName: name,\n message: `Skill \"${name}\" is missing a description`,\n path: filePath,\n },\n };\n }\n\n // Derive category from directory path: skills/creative/algorithmic-art → 'creative'\n // Only assign a category when the skill is nested at least two levels below rootDir.\n let category: string | undefined;\n if (rootDir) {\n const relDir = toPosixPath(relative(rootDir, skillDir));\n const segments = relDir.split('/');\n if (segments.length > 1) {\n category = segments[0];\n }\n }\n\n const metadata = parseSkillMetadata(frontmatter);\n metadata.name ||= name;\n metadata.description ||= description.trim();\n const toolConditions = parseSkillToolConditions(frontmatter);\n const requiredEnvVarNames = parseRequiredEnvVarNames(frontmatter);\n\n return {\n skill: {\n name,\n description: description.trim(),\n category,\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: frontmatter['disable-model-invocation'] === true,\n metadata,\n toolConditions,\n requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : undefined,\n content,\n },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n skill: null,\n diagnostic: {\n type: 'error',\n message: `Failed to load skill file: ${message}`,\n path: filePath,\n },\n };\n }\n}\n\nexport function loadSkills(options: {\n workspaceDir?: string;\n globalDir?: string;\n builtinDir?: string;\n extraDirs?: string[];\n}): LoadSkillsResult {\n const { workspaceDir, builtinDir, extraDirs = [] } = options;\n\n const skillMap = new Map<string, Skill>();\n const diagnostics: SkillDiagnostic[] = [];\n\n if (builtinDir) {\n const discovered = discoverSkills(builtinDir, 'builtin');\n diagnostics.push(...discovered.diagnostics);\n for (const skill of discovered.skills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n\n const globalDirs = [\n options.globalDir,\n join(resolveStateDir(), 'skills'),\n ].filter((d): d is string => !!d && existsSync(d));\n\n for (const dir of globalDirs) {\n const discovered = discoverSkills(dir, 'global');\n diagnostics.push(...discovered.diagnostics);\n for (const skill of discovered.skills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n // Global must win over bundled when names match (Workspace > Global > Bundled).\n skillMap.set(skill.name, skill);\n }\n }\n\n if (workspaceDir) {\n const discovered = discoverSkills(join(workspaceDir, 'skills'), 'workspace');\n diagnostics.push(...discovered.diagnostics);\n const workspaceSkills = discovered.skills;\n for (const skill of workspaceSkills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n skillMap.set(skill.name, skill);\n }\n }\n\n // Scan extra directories\n for (const extraDir of extraDirs) {\n if (existsSync(extraDir)) {\n const discovered = discoverSkills(extraDir, 'global');\n diagnostics.push(...discovered.diagnostics);\n for (const skill of discovered.skills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const merged = Array.from(skillMap.values());\n\n return {\n skills: merged,\n prompt: formatSkillsForPrompt(merged, skillsConfig),\n diagnostics,\n };\n}\n\nexport interface SkillLoader {\n init: (workspace: string, builtin: string | null) => LoadSkillsResult;\n load: () => LoadSkillsResult;\n reload: () => LoadSkillsResult;\n /** Recompute `<available_skills>` from disk-loaded skills and current ~/.xopc/skills.json (no filesystem rescan). */\n refreshPromptFromConfig: () => void;\n getSkills: () => Skill[];\n getPrompt: () => string;\n getDiagnostics: () => SkillDiagnostic[];\n getLastLoadTime: () => number;\n getSkillByName: (name: string) => Skill | undefined;\n getEnabledSkills: (config?: Record<string, SkillConfig>) => Skill[];\n}\n\nexport function createSkillLoader(): SkillLoader {\n let cachedSkills: Skill[] = [];\n let cachedPrompt: string = '';\n let cachedDiagnostics: SkillDiagnostic[] = [];\n let lastLoadTime = 0;\n let workspaceDir: string | undefined;\n let builtinDir: string | undefined;\n let extraDirs: string[] = [];\n\n function updateCache(result: LoadSkillsResult): LoadSkillsResult {\n cachedSkills = result.skills;\n cachedPrompt = result.prompt;\n cachedDiagnostics = result.diagnostics;\n lastLoadTime = Date.now();\n return result;\n }\n\n return {\n init: (workspace: string, builtin: string | null) => {\n workspaceDir = workspace;\n builtinDir = builtin || undefined;\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n load: () => {\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n reload: () => {\n log.info('Reloading skills');\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n\n refreshPromptFromConfig: () => {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n cachedPrompt = formatSkillsForPrompt(cachedSkills, skillsConfig);\n lastLoadTime = Date.now();\n },\n\n getSkills: () => cachedSkills,\n getPrompt: () => cachedPrompt,\n getDiagnostics: () => cachedDiagnostics,\n getLastLoadTime: () => lastLoadTime,\n \n getSkillByName: (name: string) => {\n return cachedSkills.find(s => s.name === name);\n },\n \n getEnabledSkills: (entries?: Record<string, SkillConfig>) => {\n const skillsConfig: SkillsConfig =\n entries !== undefined ? { entries } : createSkillConfigManager(resolveStateDir()).load();\n return cachedSkills.filter(\n (skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig),\n );\n },\n };\n}\n\n// `SkillManager` + sibling types removed from this barrel — `skill-manager.ts`\n// imports `createSkillLoader` from THIS file, so re-exporting it back here\n// formed a circular cycle. External callers should import directly from\n// `./skill-manager.js`.\n\n// Re-export types for convenience\nexport type { \n Skill, \n SkillMetadata, \n SkillConfig,\n SkillInstallSpec,\n SkillInstallResult,\n SkillInstallRequest,\n LoadSkillsResult,\n // Note: SkillDiagnostic is re-exported from skill-manager.ts above\n SkillSnapshot,\n} from './types.js';\n\n// Re-export installer\nexport { \n installSkill, \n findInstallSpec,\n hasBinary,\n getDefaultInstallerPreferences,\n type InstallerPreferences,\n type InstallContext,\n} from './installer.js';\n\n// Re-export scanner\nexport {\n scanSkillDirectory,\n formatScanSummary,\n collectSkillInstallWarnings,\n type ScanSummary,\n type SecurityFinding,\n type Severity,\n} from './scanner.js';\n\n// Re-export config manager\nexport {\n resolveSkillConfig,\n applySkillEnvOverrides,\n getSkillEnvironment,\n createSkillConfigManager,\n isSkillEnabled,\n validateSkillConfig,\n type SkillConfigFile,\n} from './config.js';\n\n// `watcher.ts` re-exports removed — it imports `SkillLoader` from THIS file, so\n// re-exporting back here formed a circular cycle. External callers should\n// import directly from `./watcher.js`.\n\n// Re-export test framework\nexport {\n SkillTestFramework,\n SkillTestRunner,\n formatTestResults,\n formatTestResultsJson,\n formatTestResultsTap,\n type TestResult,\n type TestStatus,\n type SkillTestReport,\n type TestOptions,\n type TestRunnerOptions,\n} from './test-framework.js';\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { delimiter, join } from "path";
|
|
4
3
|
import { accessSync, constants, existsSync } from "fs";
|
|
5
|
-
import { promisify } from "util";
|
|
6
4
|
import { exec } from "child_process";
|
|
5
|
+
import { delimiter, join } from "path";
|
|
6
|
+
import { promisify } from "util";
|
|
7
7
|
//#region src/agent/skills/installer.ts
|
|
8
8
|
/**
|
|
9
9
|
* Skill Installer
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { type SkillHubLockEntry } from './hub-lock.js';
|
|
6
6
|
export declare const MAX_SKILL_ZIP_BYTES: number;
|
|
7
7
|
export declare function isValidSkillId(id: string): boolean;
|
|
8
|
+
export declare function isManagedSkillTransientDirName(name: string): boolean;
|
|
8
9
|
/** True when `baseDir` is the global managed skills root or a direct child folder. */
|
|
9
10
|
export declare function isUnderManagedSkillsDir(baseDir: string): boolean;
|
|
10
11
|
/** macOS/Windows noise; not part of the skill tree. */
|
|
@@ -19,6 +20,24 @@ export interface ManagedSkillListItem {
|
|
|
19
20
|
}
|
|
20
21
|
export declare function listManagedSkillDirs(): ManagedSkillListItem[];
|
|
21
22
|
export declare function deleteManagedSkill(skillId: string): void;
|
|
23
|
+
export declare function getManagedSkillDir(skillId: string): string;
|
|
24
|
+
export declare function assertManagedSkillDestination(skillId: string): {
|
|
25
|
+
root: string;
|
|
26
|
+
destDir: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function prepareManagedSkillTempDir(skillId: string): {
|
|
29
|
+
root: string;
|
|
30
|
+
destDir: string;
|
|
31
|
+
tempDir: string;
|
|
32
|
+
};
|
|
33
|
+
export declare function promoteManagedSkillTempDir(params: {
|
|
34
|
+
skillId: string;
|
|
35
|
+
tempDir: string;
|
|
36
|
+
overwrite?: boolean;
|
|
37
|
+
}): {
|
|
38
|
+
skillId: string;
|
|
39
|
+
path: string;
|
|
40
|
+
};
|
|
22
41
|
/**
|
|
23
42
|
* Install or replace a skill from a zip buffer. Layout: either `SKILL.md` at archive root
|
|
24
43
|
* or a single top-level folder containing `SKILL.md` (optionally nested one level).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
2
2
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
3
3
|
import { loadSkillsLock } from "./hub-lock.js";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { dirname, join, resolve, sep } from "node:path";
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
6
6
|
import AdmZip from "adm-zip";
|
|
7
7
|
//#region src/agent/skills/managed-store.ts
|
|
8
8
|
/**
|
|
@@ -12,9 +12,14 @@ import AdmZip from "adm-zip";
|
|
|
12
12
|
init_paths();
|
|
13
13
|
const MAX_SKILL_ZIP_BYTES = 15 * 1024 * 1024;
|
|
14
14
|
const SKILL_ID_RE = /^[a-zA-Z0-9]([a-zA-Z0-9._-]{0,62})$/;
|
|
15
|
+
const TEMP_PREFIX = ".tmp-";
|
|
16
|
+
const TRASH_PREFIX = ".trash-";
|
|
15
17
|
function isValidSkillId(id) {
|
|
16
18
|
return SKILL_ID_RE.test(id);
|
|
17
19
|
}
|
|
20
|
+
function isManagedSkillTransientDirName(name) {
|
|
21
|
+
return name.startsWith(TEMP_PREFIX) || name.startsWith(TRASH_PREFIX);
|
|
22
|
+
}
|
|
18
23
|
/** True when `baseDir` is the global managed skills root or a direct child folder. */
|
|
19
24
|
function isUnderManagedSkillsDir(baseDir) {
|
|
20
25
|
const b = resolve(baseDir);
|
|
@@ -89,11 +94,73 @@ function deleteManagedSkill(skillId) {
|
|
|
89
94
|
const rootResolved = resolve(root);
|
|
90
95
|
if (!dir.startsWith(rootResolved + sep) && dir !== rootResolved) throw new Error("Invalid path");
|
|
91
96
|
if (!existsSync(join(dir, "SKILL.md"))) throw new Error("Skill not found");
|
|
92
|
-
|
|
97
|
+
const trashDir = createTransientManagedDir(root, TRASH_PREFIX, skillId);
|
|
98
|
+
renameSync(dir, trashDir);
|
|
99
|
+
rmSync(trashDir, {
|
|
93
100
|
recursive: true,
|
|
94
101
|
force: true
|
|
95
102
|
});
|
|
96
103
|
}
|
|
104
|
+
function createTransientManagedDir(root, prefix, skillId) {
|
|
105
|
+
for (let i = 0; i < 100; i += 1) {
|
|
106
|
+
const dir = join(root, `${prefix}${skillId}-${`${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}-${i}`}`);
|
|
107
|
+
if (!existsSync(dir)) return dir;
|
|
108
|
+
}
|
|
109
|
+
throw new Error("Could not allocate temporary skill directory");
|
|
110
|
+
}
|
|
111
|
+
function getManagedSkillDir(skillId) {
|
|
112
|
+
if (!isValidSkillId(skillId)) throw new Error("Invalid skill id");
|
|
113
|
+
return join(resolveSkillsDir(), skillId);
|
|
114
|
+
}
|
|
115
|
+
function assertManagedSkillDestination(skillId) {
|
|
116
|
+
if (!isValidSkillId(skillId)) throw new Error(`Invalid skill id "${skillId}" (letters, digits, ._-; max 63 chars after first)`);
|
|
117
|
+
const root = resolveSkillsDir();
|
|
118
|
+
mkdirSync(root, { recursive: true });
|
|
119
|
+
const destDir = join(root, skillId);
|
|
120
|
+
const destResolved = resolve(destDir);
|
|
121
|
+
const rootResolved = resolve(root);
|
|
122
|
+
if (!destResolved.startsWith(rootResolved + sep) && destResolved !== rootResolved) throw new Error("Invalid destination path");
|
|
123
|
+
return {
|
|
124
|
+
root,
|
|
125
|
+
destDir
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function prepareManagedSkillTempDir(skillId) {
|
|
129
|
+
const { root, destDir } = assertManagedSkillDestination(skillId);
|
|
130
|
+
const tempDir = createTransientManagedDir(root, TEMP_PREFIX, skillId);
|
|
131
|
+
mkdirSync(tempDir, { recursive: true });
|
|
132
|
+
return {
|
|
133
|
+
root,
|
|
134
|
+
destDir,
|
|
135
|
+
tempDir
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function promoteManagedSkillTempDir(params) {
|
|
139
|
+
const { root, destDir } = assertManagedSkillDestination(params.skillId);
|
|
140
|
+
const tempResolved = resolve(params.tempDir);
|
|
141
|
+
const rootResolved = resolve(root);
|
|
142
|
+
if (!tempResolved.startsWith(rootResolved + sep)) throw new Error("Invalid temporary skill directory");
|
|
143
|
+
if (!existsSync(join(params.tempDir, "SKILL.md"))) throw new Error("Installed tree is missing SKILL.md");
|
|
144
|
+
if (existsSync(destDir)) {
|
|
145
|
+
if (!params.overwrite) throw new Error(`Skill "${params.skillId}" already exists. Pass overwrite to replace.`);
|
|
146
|
+
const trashDir = createTransientManagedDir(root, TRASH_PREFIX, params.skillId);
|
|
147
|
+
renameSync(destDir, trashDir);
|
|
148
|
+
try {
|
|
149
|
+
renameSync(params.tempDir, destDir);
|
|
150
|
+
} catch (err) {
|
|
151
|
+
renameSync(trashDir, destDir);
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
rmSync(trashDir, {
|
|
155
|
+
recursive: true,
|
|
156
|
+
force: true
|
|
157
|
+
});
|
|
158
|
+
} else renameSync(params.tempDir, destDir);
|
|
159
|
+
return {
|
|
160
|
+
skillId: params.skillId,
|
|
161
|
+
path: destDir
|
|
162
|
+
};
|
|
163
|
+
}
|
|
97
164
|
function inferStripPrefix(primary) {
|
|
98
165
|
const parts = primary.split("/").filter(Boolean);
|
|
99
166
|
if (parts.length === 1 && parts[0].toLowerCase() === "skill.md") return "";
|
|
@@ -120,8 +187,6 @@ function installSkillFromZip(buffer, options) {
|
|
|
120
187
|
const outside = names.filter((n) => !n.startsWith(prefixNorm) && !isIgnorableZipEntry(n));
|
|
121
188
|
if (outside.length > 0) throw new Error(`Invalid zip: expected all skill files under "${prefixNorm.replace(/\/$/, "")}/", but found "${outside[0]}". Put SKILL.md and assets in one folder, or zip that folder only.`);
|
|
122
189
|
}
|
|
123
|
-
const root = resolveSkillsDir();
|
|
124
|
-
mkdirSync(root, { recursive: true });
|
|
125
190
|
let targetId = options.skillId?.trim();
|
|
126
191
|
if (!targetId) {
|
|
127
192
|
if (stripPrefix) targetId = stripPrefix.replace(/\/$/, "").split("/")[0] || "";
|
|
@@ -134,46 +199,40 @@ function installSkillFromZip(buffer, options) {
|
|
|
134
199
|
}
|
|
135
200
|
}
|
|
136
201
|
if (!targetId || !isValidSkillId(targetId)) throw new Error("Could not determine skill id: use a folder named with the skill id, pass skillId, or set name: in SKILL.md (letters, digits, ._-)");
|
|
137
|
-
const destDir =
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
202
|
+
const { destDir, tempDir } = prepareManagedSkillTempDir(targetId);
|
|
203
|
+
const tempResolved = resolve(tempDir);
|
|
204
|
+
try {
|
|
205
|
+
if (existsSync(destDir) && !options.overwrite) throw new Error(`Skill "${targetId}" already exists. Pass overwrite to replace.`);
|
|
206
|
+
for (const e of safeEntries) {
|
|
207
|
+
const norm = e.entryName.replace(/\\/g, "/");
|
|
208
|
+
let rel;
|
|
209
|
+
if (stripPrefix) {
|
|
210
|
+
const prefixNorm = stripPrefix.replace(/\\/g, "/");
|
|
211
|
+
if (!norm.startsWith(prefixNorm)) continue;
|
|
212
|
+
rel = norm.slice(prefixNorm.length).replace(/^\//, "");
|
|
213
|
+
} else rel = norm;
|
|
214
|
+
if (!rel || rel.includes("..")) continue;
|
|
215
|
+
const targetPath = join(tempDir, rel);
|
|
216
|
+
const resolvedTarget = resolve(targetPath);
|
|
217
|
+
if (!resolvedTarget.startsWith(tempResolved + sep) && resolvedTarget !== tempResolved) continue;
|
|
218
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
219
|
+
writeFileSync(targetPath, e.getData());
|
|
220
|
+
}
|
|
221
|
+
if (!existsSync(join(tempDir, "SKILL.md"))) throw new Error("Extracted content is missing SKILL.md");
|
|
222
|
+
return promoteManagedSkillTempDir({
|
|
223
|
+
skillId: targetId,
|
|
224
|
+
tempDir,
|
|
225
|
+
overwrite: options.overwrite
|
|
146
226
|
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
for (const e of safeEntries) {
|
|
150
|
-
const norm = e.entryName.replace(/\\/g, "/");
|
|
151
|
-
let rel;
|
|
152
|
-
if (stripPrefix) {
|
|
153
|
-
const prefixNorm = stripPrefix.replace(/\\/g, "/");
|
|
154
|
-
if (!norm.startsWith(prefixNorm)) continue;
|
|
155
|
-
rel = norm.slice(prefixNorm.length).replace(/^\//, "");
|
|
156
|
-
} else rel = norm;
|
|
157
|
-
if (!rel || rel.includes("..")) continue;
|
|
158
|
-
const targetPath = join(destDir, rel);
|
|
159
|
-
const resolvedTarget = resolve(targetPath);
|
|
160
|
-
if (!resolvedTarget.startsWith(destResolved + sep) && resolvedTarget !== destResolved) continue;
|
|
161
|
-
mkdirSync(dirname(targetPath), { recursive: true });
|
|
162
|
-
writeFileSync(targetPath, e.getData());
|
|
163
|
-
}
|
|
164
|
-
if (!existsSync(join(destDir, "SKILL.md"))) {
|
|
165
|
-
rmSync(destDir, {
|
|
227
|
+
} catch (err) {
|
|
228
|
+
rmSync(tempDir, {
|
|
166
229
|
recursive: true,
|
|
167
230
|
force: true
|
|
168
231
|
});
|
|
169
|
-
throw
|
|
232
|
+
throw err;
|
|
170
233
|
}
|
|
171
|
-
return {
|
|
172
|
-
skillId: targetId,
|
|
173
|
-
path: destDir
|
|
174
|
-
};
|
|
175
234
|
}
|
|
176
235
|
//#endregion
|
|
177
|
-
export { MAX_SKILL_ZIP_BYTES, deleteManagedSkill, installSkillFromZip, isIgnorableZipEntry, isUnderManagedSkillsDir, isValidSkillId, listManagedSkillDirs };
|
|
236
|
+
export { MAX_SKILL_ZIP_BYTES, assertManagedSkillDestination, deleteManagedSkill, getManagedSkillDir, installSkillFromZip, isIgnorableZipEntry, isManagedSkillTransientDirName, isUnderManagedSkillsDir, isValidSkillId, listManagedSkillDirs, prepareManagedSkillTempDir, promoteManagedSkillTempDir };
|
|
178
237
|
|
|
179
238
|
//# sourceMappingURL=managed-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-store.js","names":[],"sources":["../../../../src/agent/skills/managed-store.ts"],"sourcesContent":["/**\n * Managed skills live under ~/.xopc/skills (see resolveSkillsDir).\n * Install/update/delete via zip or folder operations; used by gateway API.\n */\n\nimport AdmZip from 'adm-zip';\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join, resolve, sep } from 'node:path';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { loadSkillsLock, type SkillHubLockEntry } from './hub-lock.js';\n\nexport const MAX_SKILL_ZIP_BYTES = 15 * 1024 * 1024;\n\nconst SKILL_ID_RE = /^[a-zA-Z0-9]([a-zA-Z0-9._-]{0,62})$/;\n\nexport function isValidSkillId(id: string): boolean {\n return SKILL_ID_RE.test(id);\n}\n\n/** True when `baseDir` is the global managed skills root or a direct child folder. */\nexport function isUnderManagedSkillsDir(baseDir: string): boolean {\n const b = resolve(baseDir);\n const r = resolve(resolveSkillsDir());\n return b === r || b.startsWith(r + sep);\n}\n\nfunction isSafeZipPath(name: string): boolean {\n if (!name) return false;\n const normalized = name.replace(/\\\\/g, '/');\n if (normalized.includes('..')) return false;\n if (normalized.startsWith('/') || /^\\w:/.test(normalized)) return false;\n for (const p of normalized.split('/')) {\n if (p === '..') return false;\n }\n return true;\n}\n\n/** macOS/Windows noise; not part of the skill tree. */\nexport function isIgnorableZipEntry(name: string): boolean {\n const n = name.replace(/\\\\/g, '/');\n if (n.startsWith('__MACOSX/')) return true;\n const segments = n.split('/').filter(Boolean);\n for (const s of segments) {\n if (s === '.DS_Store' || s === 'Thumbs.db' || s === 'desktop.ini') return true;\n if (s.startsWith('._')) return true;\n }\n return false;\n}\n\nexport interface ManagedSkillListItem {\n id: string;\n name: string;\n description: string;\n path: string;\n /** Set when this folder was installed via `skills hub pull` / lock file. */\n hub?: SkillHubLockEntry;\n}\n\nfunction readSkillMdMeta(skillMdPath: string): { name: string; description: string } {\n try {\n const raw = readFileSync(skillMdPath, 'utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n return {\n name: (frontmatter.name as string) || '',\n description: (frontmatter.description as string)?.trim() || '',\n };\n } catch {\n return { name: '', description: '' };\n }\n}\n\nexport function listManagedSkillDirs(): ManagedSkillListItem[] {\n const root = resolveSkillsDir();\n mkdirSync(root, { recursive: true });\n const lock = loadSkillsLock();\n let dirNames: string[];\n try {\n dirNames = readdirSync(root, { withFileTypes: true })\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch {\n return [];\n }\n const out: ManagedSkillListItem[] = [];\n for (const id of dirNames) {\n if (!isValidSkillId(id)) continue;\n const skillMd = join(root, id, 'SKILL.md');\n if (!existsSync(skillMd)) continue;\n const meta = readSkillMdMeta(skillMd);\n const hub = lock.entries[id];\n out.push({\n id,\n name: meta.name || id,\n description: meta.description || '',\n path: join(root, id),\n ...(hub ? { hub } : {}),\n });\n }\n out.sort((a, b) => a.id.localeCompare(b.id));\n return out;\n}\n\nexport function deleteManagedSkill(skillId: string): void {\n if (!isValidSkillId(skillId)) {\n throw new Error('Invalid skill id');\n }\n const root = resolveSkillsDir();\n const dir = resolve(join(root, skillId));\n const rootResolved = resolve(root);\n if (!dir.startsWith(rootResolved + sep) && dir !== rootResolved) {\n throw new Error('Invalid path');\n }\n if (!existsSync(join(dir, 'SKILL.md'))) {\n throw new Error('Skill not found');\n }\n rmSync(dir, { recursive: true, force: true });\n}\n\nfunction inferStripPrefix(primary: string): string {\n const parts = primary.split('/').filter(Boolean);\n if (parts.length === 1 && parts[0].toLowerCase() === 'skill.md') {\n return '';\n }\n return primary.slice(0, -'SKILL.md'.length);\n}\n\n/**\n * Install or replace a skill from a zip buffer. Layout: either `SKILL.md` at archive root\n * or a single top-level folder containing `SKILL.md` (optionally nested one level).\n */\nexport function installSkillFromZip(\n buffer: Buffer,\n options: { skillId?: string; overwrite?: boolean },\n): { skillId: string; path: string } {\n if (buffer.length > MAX_SKILL_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);\n }\n\n const zip = new AdmZip(buffer);\n const entries = zip\n .getEntries()\n .filter((e) => !e.isDirectory && e.entryName && !isIgnorableZipEntry(e.entryName));\n\n const safeEntries = entries.filter((e) => isSafeZipPath(e.entryName));\n if (safeEntries.length === 0) {\n throw new Error('Zip is empty or invalid');\n }\n\n const names = safeEntries.map((e) => e.entryName.replace(/\\\\/g, '/'));\n const skillMdPaths = names.filter((n) => /(^|\\/)SKILL\\.md$/i.test(n));\n if (skillMdPaths.length === 0) {\n throw new Error('Zip must contain at least one SKILL.md');\n }\n\n const shallow = skillMdPaths.filter((p) => p.split('/').filter(Boolean).length <= 2);\n if (shallow.length === 0) {\n throw new Error(\n 'SKILL.md is nested too deeply; use a zip with SKILL.md at archive root or one folder (e.g. my-skill/SKILL.md)',\n );\n }\n\n shallow.sort((a, b) => a.length - b.length);\n const stripPrefix = inferStripPrefix(shallow[0]);\n\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n const outside = names.filter((n) => !n.startsWith(prefixNorm) && !isIgnorableZipEntry(n));\n if (outside.length > 0) {\n throw new Error(\n `Invalid zip: expected all skill files under \"${prefixNorm.replace(/\\/$/, '')}/\", but found \"${outside[0]}\". ` +\n 'Put SKILL.md and assets in one folder, or zip that folder only.',\n );\n }\n }\n\n const root = resolveSkillsDir();\n mkdirSync(root, { recursive: true });\n\n let targetId = options.skillId?.trim();\n if (!targetId) {\n if (stripPrefix) {\n const first = stripPrefix.replace(/\\/$/, '').split('/')[0];\n targetId = first || '';\n }\n if (!targetId) {\n const skillName = shallow.find((n) => /(^|\\/)SKILL\\.md$/i.test(n)) || '';\n const entry = zip.getEntry(skillName);\n if (!entry) throw new Error('SKILL.md missing');\n const raw = entry.getData().toString('utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n targetId = String(frontmatter.name || '').trim();\n }\n }\n\n if (!targetId || !isValidSkillId(targetId)) {\n throw new Error(\n 'Could not determine skill id: use a folder named with the skill id, pass skillId, or set name: in SKILL.md (letters, digits, ._-)',\n );\n }\n\n const destDir = join(root, targetId);\n const destResolved = resolve(destDir);\n const rootResolved = resolve(root);\n if (!destResolved.startsWith(rootResolved + sep) && destResolved !== rootResolved) {\n throw new Error('Invalid destination');\n }\n\n if (existsSync(destDir)) {\n if (!options.overwrite) {\n throw new Error(`Skill \"${targetId}\" already exists. Pass overwrite to replace.`);\n }\n rmSync(destDir, { recursive: true, force: true });\n }\n mkdirSync(destDir, { recursive: true });\n\n for (const e of safeEntries) {\n const norm = e.entryName.replace(/\\\\/g, '/');\n let rel: string;\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n if (!norm.startsWith(prefixNorm)) continue;\n rel = norm.slice(prefixNorm.length).replace(/^\\//, '');\n } else {\n rel = norm;\n }\n if (!rel || rel.includes('..')) continue;\n\n const targetPath = join(destDir, rel);\n const resolvedTarget = resolve(targetPath);\n if (!resolvedTarget.startsWith(destResolved + sep) && resolvedTarget !== destResolved) {\n continue;\n }\n mkdirSync(dirname(targetPath), { recursive: true });\n writeFileSync(targetPath, e.getData());\n }\n\n if (!existsSync(join(destDir, 'SKILL.md'))) {\n rmSync(destDir, { recursive: true, force: true });\n throw new Error('Extracted content is missing SKILL.md');\n }\n\n return { skillId: targetId, path: destDir };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"managed-store.js","names":[],"sources":["../../../../src/agent/skills/managed-store.ts"],"sourcesContent":["/**\n * Managed skills live under ~/.xopc/skills (see resolveSkillsDir).\n * Install/update/delete via zip or folder operations; used by gateway API.\n */\n\nimport AdmZip from 'adm-zip';\nimport {\n existsSync,\n mkdirSync,\n renameSync,\n readdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join, resolve, sep } from 'node:path';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { loadSkillsLock, type SkillHubLockEntry } from './hub-lock.js';\n\nexport const MAX_SKILL_ZIP_BYTES = 15 * 1024 * 1024;\n\nconst SKILL_ID_RE = /^[a-zA-Z0-9]([a-zA-Z0-9._-]{0,62})$/;\nconst TEMP_PREFIX = '.tmp-';\nconst TRASH_PREFIX = '.trash-';\n\nexport function isValidSkillId(id: string): boolean {\n return SKILL_ID_RE.test(id);\n}\n\nexport function isManagedSkillTransientDirName(name: string): boolean {\n return name.startsWith(TEMP_PREFIX) || name.startsWith(TRASH_PREFIX);\n}\n\n/** True when `baseDir` is the global managed skills root or a direct child folder. */\nexport function isUnderManagedSkillsDir(baseDir: string): boolean {\n const b = resolve(baseDir);\n const r = resolve(resolveSkillsDir());\n return b === r || b.startsWith(r + sep);\n}\n\nfunction isSafeZipPath(name: string): boolean {\n if (!name) return false;\n const normalized = name.replace(/\\\\/g, '/');\n if (normalized.includes('..')) return false;\n if (normalized.startsWith('/') || /^\\w:/.test(normalized)) return false;\n for (const p of normalized.split('/')) {\n if (p === '..') return false;\n }\n return true;\n}\n\n/** macOS/Windows noise; not part of the skill tree. */\nexport function isIgnorableZipEntry(name: string): boolean {\n const n = name.replace(/\\\\/g, '/');\n if (n.startsWith('__MACOSX/')) return true;\n const segments = n.split('/').filter(Boolean);\n for (const s of segments) {\n if (s === '.DS_Store' || s === 'Thumbs.db' || s === 'desktop.ini') return true;\n if (s.startsWith('._')) return true;\n }\n return false;\n}\n\nexport interface ManagedSkillListItem {\n id: string;\n name: string;\n description: string;\n path: string;\n /** Set when this folder was installed via `skills hub pull` / lock file. */\n hub?: SkillHubLockEntry;\n}\n\nfunction readSkillMdMeta(skillMdPath: string): { name: string; description: string } {\n try {\n const raw = readFileSync(skillMdPath, 'utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n return {\n name: (frontmatter.name as string) || '',\n description: (frontmatter.description as string)?.trim() || '',\n };\n } catch {\n return { name: '', description: '' };\n }\n}\n\nexport function listManagedSkillDirs(): ManagedSkillListItem[] {\n const root = resolveSkillsDir();\n mkdirSync(root, { recursive: true });\n const lock = loadSkillsLock();\n let dirNames: string[];\n try {\n dirNames = readdirSync(root, { withFileTypes: true })\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => e.name);\n } catch {\n return [];\n }\n const out: ManagedSkillListItem[] = [];\n for (const id of dirNames) {\n if (!isValidSkillId(id)) continue;\n const skillMd = join(root, id, 'SKILL.md');\n if (!existsSync(skillMd)) continue;\n const meta = readSkillMdMeta(skillMd);\n const hub = lock.entries[id];\n out.push({\n id,\n name: meta.name || id,\n description: meta.description || '',\n path: join(root, id),\n ...(hub ? { hub } : {}),\n });\n }\n out.sort((a, b) => a.id.localeCompare(b.id));\n return out;\n}\n\nexport function deleteManagedSkill(skillId: string): void {\n if (!isValidSkillId(skillId)) {\n throw new Error('Invalid skill id');\n }\n const root = resolveSkillsDir();\n const dir = resolve(join(root, skillId));\n const rootResolved = resolve(root);\n if (!dir.startsWith(rootResolved + sep) && dir !== rootResolved) {\n throw new Error('Invalid path');\n }\n if (!existsSync(join(dir, 'SKILL.md'))) {\n throw new Error('Skill not found');\n }\n const trashDir = createTransientManagedDir(root, TRASH_PREFIX, skillId);\n renameSync(dir, trashDir);\n rmSync(trashDir, { recursive: true, force: true });\n}\n\nfunction createTransientManagedDir(root: string, prefix: string, skillId: string): string {\n for (let i = 0; i < 100; i += 1) {\n const suffix = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}-${i}`;\n const dir = join(root, `${prefix}${skillId}-${suffix}`);\n if (!existsSync(dir)) return dir;\n }\n throw new Error('Could not allocate temporary skill directory');\n}\n\nexport function getManagedSkillDir(skillId: string): string {\n if (!isValidSkillId(skillId)) {\n throw new Error('Invalid skill id');\n }\n return join(resolveSkillsDir(), skillId);\n}\n\nexport function assertManagedSkillDestination(skillId: string): { root: string; destDir: string } {\n if (!isValidSkillId(skillId)) {\n throw new Error(`Invalid skill id \"${skillId}\" (letters, digits, ._-; max 63 chars after first)`);\n }\n const root = resolveSkillsDir();\n mkdirSync(root, { recursive: true });\n const destDir = join(root, skillId);\n const destResolved = resolve(destDir);\n const rootResolved = resolve(root);\n if (!destResolved.startsWith(rootResolved + sep) && destResolved !== rootResolved) {\n throw new Error('Invalid destination path');\n }\n return { root, destDir };\n}\n\nexport function prepareManagedSkillTempDir(skillId: string): { root: string; destDir: string; tempDir: string } {\n const { root, destDir } = assertManagedSkillDestination(skillId);\n const tempDir = createTransientManagedDir(root, TEMP_PREFIX, skillId);\n mkdirSync(tempDir, { recursive: true });\n return { root, destDir, tempDir };\n}\n\nexport function promoteManagedSkillTempDir(params: {\n skillId: string;\n tempDir: string;\n overwrite?: boolean;\n}): { skillId: string; path: string } {\n const { root, destDir } = assertManagedSkillDestination(params.skillId);\n const tempResolved = resolve(params.tempDir);\n const rootResolved = resolve(root);\n if (!tempResolved.startsWith(rootResolved + sep)) {\n throw new Error('Invalid temporary skill directory');\n }\n if (!existsSync(join(params.tempDir, 'SKILL.md'))) {\n throw new Error('Installed tree is missing SKILL.md');\n }\n\n if (existsSync(destDir)) {\n if (!params.overwrite) {\n throw new Error(`Skill \"${params.skillId}\" already exists. Pass overwrite to replace.`);\n }\n const trashDir = createTransientManagedDir(root, TRASH_PREFIX, params.skillId);\n renameSync(destDir, trashDir);\n try {\n renameSync(params.tempDir, destDir);\n } catch (err) {\n renameSync(trashDir, destDir);\n throw err;\n }\n rmSync(trashDir, { recursive: true, force: true });\n } else {\n renameSync(params.tempDir, destDir);\n }\n\n return { skillId: params.skillId, path: destDir };\n}\n\nfunction inferStripPrefix(primary: string): string {\n const parts = primary.split('/').filter(Boolean);\n if (parts.length === 1 && parts[0].toLowerCase() === 'skill.md') {\n return '';\n }\n return primary.slice(0, -'SKILL.md'.length);\n}\n\n/**\n * Install or replace a skill from a zip buffer. Layout: either `SKILL.md` at archive root\n * or a single top-level folder containing `SKILL.md` (optionally nested one level).\n */\nexport function installSkillFromZip(\n buffer: Buffer,\n options: { skillId?: string; overwrite?: boolean },\n): { skillId: string; path: string } {\n if (buffer.length > MAX_SKILL_ZIP_BYTES) {\n throw new Error(`Zip exceeds maximum size (${MAX_SKILL_ZIP_BYTES} bytes)`);\n }\n\n const zip = new AdmZip(buffer);\n const entries = zip\n .getEntries()\n .filter((e) => !e.isDirectory && e.entryName && !isIgnorableZipEntry(e.entryName));\n\n const safeEntries = entries.filter((e) => isSafeZipPath(e.entryName));\n if (safeEntries.length === 0) {\n throw new Error('Zip is empty or invalid');\n }\n\n const names = safeEntries.map((e) => e.entryName.replace(/\\\\/g, '/'));\n const skillMdPaths = names.filter((n) => /(^|\\/)SKILL\\.md$/i.test(n));\n if (skillMdPaths.length === 0) {\n throw new Error('Zip must contain at least one SKILL.md');\n }\n\n const shallow = skillMdPaths.filter((p) => p.split('/').filter(Boolean).length <= 2);\n if (shallow.length === 0) {\n throw new Error(\n 'SKILL.md is nested too deeply; use a zip with SKILL.md at archive root or one folder (e.g. my-skill/SKILL.md)',\n );\n }\n\n shallow.sort((a, b) => a.length - b.length);\n const stripPrefix = inferStripPrefix(shallow[0]);\n\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n const outside = names.filter((n) => !n.startsWith(prefixNorm) && !isIgnorableZipEntry(n));\n if (outside.length > 0) {\n throw new Error(\n `Invalid zip: expected all skill files under \"${prefixNorm.replace(/\\/$/, '')}/\", but found \"${outside[0]}\". ` +\n 'Put SKILL.md and assets in one folder, or zip that folder only.',\n );\n }\n }\n\n let targetId = options.skillId?.trim();\n if (!targetId) {\n if (stripPrefix) {\n const first = stripPrefix.replace(/\\/$/, '').split('/')[0];\n targetId = first || '';\n }\n if (!targetId) {\n const skillName = shallow.find((n) => /(^|\\/)SKILL\\.md$/i.test(n)) || '';\n const entry = zip.getEntry(skillName);\n if (!entry) throw new Error('SKILL.md missing');\n const raw = entry.getData().toString('utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n targetId = String(frontmatter.name || '').trim();\n }\n }\n\n if (!targetId || !isValidSkillId(targetId)) {\n throw new Error(\n 'Could not determine skill id: use a folder named with the skill id, pass skillId, or set name: in SKILL.md (letters, digits, ._-)',\n );\n }\n\n const { destDir, tempDir } = prepareManagedSkillTempDir(targetId);\n const tempResolved = resolve(tempDir);\n try {\n if (existsSync(destDir) && !options.overwrite) {\n throw new Error(`Skill \"${targetId}\" already exists. Pass overwrite to replace.`);\n }\n\n for (const e of safeEntries) {\n const norm = e.entryName.replace(/\\\\/g, '/');\n let rel: string;\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n if (!norm.startsWith(prefixNorm)) continue;\n rel = norm.slice(prefixNorm.length).replace(/^\\//, '');\n } else {\n rel = norm;\n }\n if (!rel || rel.includes('..')) continue;\n\n const targetPath = join(tempDir, rel);\n const resolvedTarget = resolve(targetPath);\n if (!resolvedTarget.startsWith(tempResolved + sep) && resolvedTarget !== tempResolved) {\n continue;\n }\n mkdirSync(dirname(targetPath), { recursive: true });\n writeFileSync(targetPath, e.getData());\n }\n\n if (!existsSync(join(tempDir, 'SKILL.md'))) {\n throw new Error('Extracted content is missing SKILL.md');\n }\n\n return promoteManagedSkillTempDir({\n skillId: targetId,\n tempDir,\n overwrite: options.overwrite,\n });\n } catch (err) {\n rmSync(tempDir, { recursive: true, force: true });\n throw err;\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
|
2
2
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
3
3
|
import { fuzzyFindText, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings } from "../tools/edit-diff.js";
|
|
4
4
|
import { formatScanSummary, scanSkillDirectory } from "./scanner.js";
|
|
5
|
-
import { join, resolve, sep } from "path";
|
|
6
5
|
import { existsSync, realpathSync } from "fs";
|
|
6
|
+
import { join, resolve, sep } from "path";
|
|
7
7
|
import { mkdir, writeFile } from "fs/promises";
|
|
8
8
|
//#region src/agent/skills/skill-manage-ops.ts
|
|
9
9
|
/**
|
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles skill initialization, reloading, and command expansion.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
export interface SkillDiagnostic {
|
|
8
|
-
type: 'collision' | 'warning' | 'error' | 'info';
|
|
9
|
-
skillName: string;
|
|
10
|
-
message: string;
|
|
11
|
-
}
|
|
6
|
+
import type { Skill, SkillDiagnostic, SkillRuntimeStatus } from './types.js';
|
|
12
7
|
export interface SkillLoadResult {
|
|
13
8
|
skills: Skill[];
|
|
14
9
|
prompt: string;
|
|
@@ -20,6 +15,15 @@ export declare class SkillManager {
|
|
|
20
15
|
private skillLoader;
|
|
21
16
|
private workspace;
|
|
22
17
|
private bundledSkillsDir;
|
|
18
|
+
private version;
|
|
19
|
+
private loadedAt;
|
|
20
|
+
private reloadInProgress;
|
|
21
|
+
private reloadPending;
|
|
22
|
+
private lastReloadStartedAt;
|
|
23
|
+
private lastReloadFinishedAt;
|
|
24
|
+
private lastReloadReason;
|
|
25
|
+
private lastReloadOk;
|
|
26
|
+
private lastReloadError;
|
|
23
27
|
constructor(workspace: string, bundledSkillsDir?: string);
|
|
24
28
|
/**
|
|
25
29
|
* Initialize skills from workspace and bundled directories
|
|
@@ -33,6 +37,8 @@ export declare class SkillManager {
|
|
|
33
37
|
* Reload skills from disk
|
|
34
38
|
*/
|
|
35
39
|
reload(): void;
|
|
40
|
+
private runReload;
|
|
41
|
+
private applyLoadResult;
|
|
36
42
|
/**
|
|
37
43
|
* Get the skill prompt to append to system prompt
|
|
38
44
|
*/
|
|
@@ -51,6 +57,10 @@ export declare class SkillManager {
|
|
|
51
57
|
* Get all loaded skills
|
|
52
58
|
*/
|
|
53
59
|
getSkills(): Skill[];
|
|
60
|
+
getDiagnostics(): SkillDiagnostic[];
|
|
61
|
+
getVersion(): string;
|
|
62
|
+
getLoadedAt(): number;
|
|
63
|
+
getStatus(): SkillRuntimeStatus;
|
|
54
64
|
/**
|
|
55
65
|
* Get skill names
|
|
56
66
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveStateDir } from "../../config/paths-state.js";
|
|
2
|
+
import { init_paths, resolveBundledSkillsDir } from "../../config/paths.js";
|
|
2
3
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
4
|
import { init_logger } from "../../utils/logger.js";
|
|
4
|
-
import { init_paths, resolveBundledSkillsDir } from "../../config/paths.js";
|
|
5
5
|
import { createSkillConfigManager, isSkillEnabled } from "./config.js";
|
|
6
6
|
import { formatSkillsForPrompt, selectSkillsVisibleInPrompt } from "./format-skills-prompt.js";
|
|
7
7
|
import { createSkillLoader } from "./index.js";
|
|
@@ -20,6 +20,15 @@ var SkillManager = class {
|
|
|
20
20
|
skillLoader = createSkillLoader();
|
|
21
21
|
workspace;
|
|
22
22
|
bundledSkillsDir;
|
|
23
|
+
version = 0;
|
|
24
|
+
loadedAt = 0;
|
|
25
|
+
reloadInProgress = false;
|
|
26
|
+
reloadPending = false;
|
|
27
|
+
lastReloadStartedAt;
|
|
28
|
+
lastReloadFinishedAt;
|
|
29
|
+
lastReloadReason;
|
|
30
|
+
lastReloadOk;
|
|
31
|
+
lastReloadError;
|
|
23
32
|
constructor(workspace, bundledSkillsDir) {
|
|
24
33
|
this.workspace = workspace;
|
|
25
34
|
this.bundledSkillsDir = bundledSkillsDir || resolveBundledSkillsDir();
|
|
@@ -29,26 +38,7 @@ var SkillManager = class {
|
|
|
29
38
|
* Initialize skills from workspace and bundled directories
|
|
30
39
|
*/
|
|
31
40
|
initialize() {
|
|
32
|
-
|
|
33
|
-
this.skillPrompt = result.prompt;
|
|
34
|
-
this.skills = result.skills;
|
|
35
|
-
for (const diag of result.diagnostics) if (diag.type === "collision") log.warn({
|
|
36
|
-
skill: diag.skillName,
|
|
37
|
-
message: diag.message
|
|
38
|
-
}, "Skill collision");
|
|
39
|
-
else if (diag.type === "warning") log.warn({
|
|
40
|
-
skill: diag.skillName,
|
|
41
|
-
message: diag.message
|
|
42
|
-
}, "Skill warning");
|
|
43
|
-
else if (diag.type === "error") log.error({
|
|
44
|
-
skill: diag.skillName,
|
|
45
|
-
message: diag.message
|
|
46
|
-
}, "Skill error");
|
|
47
|
-
else log.info({
|
|
48
|
-
skill: diag.skillName,
|
|
49
|
-
message: diag.message
|
|
50
|
-
}, "Skill info");
|
|
51
|
-
log.debug({ count: result.skills.length }, "Skills loaded");
|
|
41
|
+
this.runReload("initial", () => this.skillLoader.init(this.workspace, this.bundledSkillsDir));
|
|
52
42
|
}
|
|
53
43
|
/**
|
|
54
44
|
* Recompute skill XML prompt from current skills.json (no disk rescan).
|
|
@@ -56,28 +46,71 @@ var SkillManager = class {
|
|
|
56
46
|
refreshPromptFromConfig() {
|
|
57
47
|
this.skillLoader.refreshPromptFromConfig();
|
|
58
48
|
this.skillPrompt = this.skillLoader.getPrompt();
|
|
49
|
+
this.version += 1;
|
|
50
|
+
this.loadedAt = Date.now();
|
|
51
|
+
this.lastReloadReason = "config";
|
|
52
|
+
this.lastReloadOk = true;
|
|
53
|
+
this.lastReloadError = void 0;
|
|
59
54
|
}
|
|
60
55
|
/**
|
|
61
56
|
* Reload skills from disk
|
|
62
57
|
*/
|
|
63
58
|
reload() {
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
this.runReload("disk", () => this.skillLoader.reload());
|
|
60
|
+
}
|
|
61
|
+
runReload(reason, load) {
|
|
62
|
+
if (this.reloadInProgress) {
|
|
63
|
+
this.reloadPending = true;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
do {
|
|
67
|
+
this.reloadPending = false;
|
|
68
|
+
this.reloadInProgress = true;
|
|
69
|
+
this.lastReloadStartedAt = Date.now();
|
|
70
|
+
this.lastReloadReason = reason;
|
|
71
|
+
try {
|
|
72
|
+
const result = load();
|
|
73
|
+
this.applyLoadResult(result);
|
|
74
|
+
this.lastReloadOk = true;
|
|
75
|
+
this.lastReloadError = void 0;
|
|
76
|
+
log.info({
|
|
77
|
+
count: result.skills.length,
|
|
78
|
+
version: this.version
|
|
79
|
+
}, "Skills reloaded");
|
|
80
|
+
} catch (err) {
|
|
81
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
82
|
+
this.lastReloadOk = false;
|
|
83
|
+
this.lastReloadError = errorMessage;
|
|
84
|
+
log.error({
|
|
85
|
+
err,
|
|
86
|
+
errorMessage
|
|
87
|
+
}, `Skills reload failed: ${errorMessage}`);
|
|
88
|
+
} finally {
|
|
89
|
+
this.lastReloadFinishedAt = Date.now();
|
|
90
|
+
this.reloadInProgress = false;
|
|
91
|
+
}
|
|
92
|
+
} while (this.reloadPending);
|
|
93
|
+
}
|
|
94
|
+
applyLoadResult(result) {
|
|
66
95
|
this.skillPrompt = result.prompt;
|
|
67
96
|
this.skills = result.skills;
|
|
97
|
+
this.version += 1;
|
|
98
|
+
this.loadedAt = Date.now();
|
|
68
99
|
for (const diag of result.diagnostics) if (diag.type === "collision") log.warn({
|
|
69
100
|
skill: diag.skillName,
|
|
101
|
+
path: diag.path,
|
|
70
102
|
message: diag.message
|
|
71
103
|
}, "Skill collision");
|
|
72
104
|
else if (diag.type === "warning") log.warn({
|
|
73
105
|
skill: diag.skillName,
|
|
106
|
+
path: diag.path,
|
|
74
107
|
message: diag.message
|
|
75
108
|
}, "Skill warning");
|
|
76
109
|
else if (diag.type === "error") log.error({
|
|
77
110
|
skill: diag.skillName,
|
|
111
|
+
path: diag.path,
|
|
78
112
|
message: diag.message
|
|
79
113
|
}, "Skill error");
|
|
80
|
-
log.info({ count: result.skills.length }, "Skills reloaded");
|
|
81
114
|
}
|
|
82
115
|
/**
|
|
83
116
|
* Get the skill prompt to append to system prompt
|
|
@@ -108,6 +141,28 @@ var SkillManager = class {
|
|
|
108
141
|
getSkills() {
|
|
109
142
|
return [...this.skills];
|
|
110
143
|
}
|
|
144
|
+
getDiagnostics() {
|
|
145
|
+
return this.skillLoader.getDiagnostics();
|
|
146
|
+
}
|
|
147
|
+
getVersion() {
|
|
148
|
+
return String(this.version);
|
|
149
|
+
}
|
|
150
|
+
getLoadedAt() {
|
|
151
|
+
return this.loadedAt;
|
|
152
|
+
}
|
|
153
|
+
getStatus() {
|
|
154
|
+
return {
|
|
155
|
+
version: this.getVersion(),
|
|
156
|
+
loadedAt: this.loadedAt,
|
|
157
|
+
reloadInProgress: this.reloadInProgress,
|
|
158
|
+
reloadPending: this.reloadPending,
|
|
159
|
+
...this.lastReloadStartedAt !== void 0 ? { lastReloadStartedAt: this.lastReloadStartedAt } : {},
|
|
160
|
+
...this.lastReloadFinishedAt !== void 0 ? { lastReloadFinishedAt: this.lastReloadFinishedAt } : {},
|
|
161
|
+
...this.lastReloadReason !== void 0 ? { lastReloadReason: this.lastReloadReason } : {},
|
|
162
|
+
...this.lastReloadOk !== void 0 ? { lastReloadOk: this.lastReloadOk } : {},
|
|
163
|
+
...this.lastReloadError !== void 0 ? { lastReloadError: this.lastReloadError } : {}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
111
166
|
/**
|
|
112
167
|
* Get skill names
|
|
113
168
|
*/
|