@xopcai/xopc 0.0.110 → 0.0.112
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/README.md +46 -4
- package/README.zh-CN.md +46 -4
- 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/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/Combination-BzaXOLd9.js +41 -0
- package/dist/gateway/static/root/assets/agent-avatar-dicebear-EhRp-ZMa.js +1 -0
- package/dist/gateway/static/root/assets/agent-browser-settings-page-H4foVCiS.js +6 -0
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-DDNw2oNU.js +1 -0
- package/dist/gateway/static/root/assets/agents-E_X2kzS1.js +71 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-BIy7KEsM.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-DGQG8NwA.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-BZLvInLr.js +1 -0
- package/dist/gateway/static/root/assets/archive-plugin-uuQPupqx.js +1 -0
- package/dist/gateway/static/root/assets/attachment-load-DBkv0cAv.js +2 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CybMSIoS.js → attachment-preview-renderer-DonnL2dL.js} +1 -1
- package/dist/gateway/static/root/assets/binary-plugins-DxxN_VAR.js +2 -0
- package/dist/gateway/static/root/assets/block-editor-CwnUlRmO.js +180 -0
- package/dist/gateway/static/root/assets/channels-settings-BHvUKlzw.js +1 -0
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +1 -0
- package/dist/gateway/static/root/assets/config-api-BD-NcD5d.js +3 -0
- package/dist/gateway/static/root/assets/config-reload-event-Bjh2zoKp.js +1 -0
- package/dist/gateway/static/root/assets/connectors-settings-VBzXcEXL.js +2 -0
- package/dist/gateway/static/root/assets/cron-api-C5DoipZA.js +1 -0
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-BLTpdm34.js +3 -0
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-scene-BHMRVEUS.js +4585 -0
- package/dist/gateway/static/root/assets/dreaming-settings-DSVhXTPq.js +1 -0
- package/dist/gateway/static/root/assets/extension-debug-page-BDHA9o_e.js +1 -0
- package/dist/gateway/static/root/assets/{extension-page-W1wiG38F.js → extension-page-DmDLVSPE.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-1124aHw_.js +1 -0
- package/dist/gateway/static/root/assets/fetch-DOe56Wmy.js +1 -0
- package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +2 -0
- package/dist/gateway/static/root/assets/format-interval-label-tsMSvBSR.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-api-CsD4FC9D.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-HQ8FBhY2.js +1 -0
- package/dist/gateway/static/root/assets/gateway-startup-retry-C1zg7pH3.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-BG3Onph0.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-DgeKn8zL.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-B5nI6lgz.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-config-api-CIv42nJD.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-DFcVuJ3M.js +1 -0
- package/dist/gateway/static/root/assets/html-workspace-editor-CQLWDiwE.js +1 -0
- package/dist/gateway/static/root/assets/index-5A_ZaABy.css +1 -0
- package/dist/gateway/static/root/assets/index-BTmbp2AU.js +121 -0
- package/dist/gateway/static/root/assets/interval-presets-DGP3S7OB.js +1 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-fETaDYQP.js +1 -0
- package/dist/gateway/static/root/assets/locale-store-DjbfSsfA.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-B1-b27lK.js +2 -0
- package/dist/gateway/static/root/assets/markdown-editor-AssmZFx4.js +2 -0
- package/dist/gateway/static/root/assets/markdown-split-CgeBJMOD.js +1 -0
- package/dist/gateway/static/root/assets/media-plugins-C30GzlV2.js +1 -0
- package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +134 -0
- package/dist/gateway/static/root/assets/messages-BUUfPaZ9.js +3 -0
- package/dist/gateway/static/root/assets/middleware-Pd0e8Igk.js +1 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DPcTS1-u.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-xeGb4owe.js +2 -0
- package/dist/gateway/static/root/assets/note-image-lightbox-t1g0qZYh.js +1 -0
- package/dist/gateway/static/root/assets/note-time-hm6JO_Wi.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-C_TdnKBe.js +1 -0
- package/dist/gateway/static/root/assets/preview-open-alternatives-DeWp9x5g.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BtkPmJIN.js +1 -0
- package/dist/gateway/static/root/assets/save-bar-controls-BOaAOJI3.js +1 -0
- package/dist/gateway/static/root/assets/schedule-field-BLWLKqgw.js +1 -0
- package/dist/gateway/static/root/assets/schema-form-plqRFYT8.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-DOUjxzJm.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-qK_bnTrw.js +1 -0
- package/dist/gateway/static/root/assets/settings-collapsible-section-BP5zRrDI.js +1 -0
- package/dist/gateway/static/root/assets/settings-form-section-Bv8MZplG.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-DmDfE1ww.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-BEFwNcIZ.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-4OX1YCgp.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-CbKmJZot.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-YdtnUHtK.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DwW1IzQ0.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-CGy4f_s2.js +1 -0
- package/dist/gateway/static/root/assets/theme-store-CD2wtgZV.js +1 -0
- package/dist/gateway/static/root/assets/use-agent-defaults-form-BMuMvzl_.js +1 -0
- package/dist/gateway/static/root/assets/use-blob-object-url-D4BFuzZB.js +1 -0
- package/dist/gateway/static/root/assets/use-channel-catalog-CjGHnDvN.js +1 -0
- package/dist/gateway/static/root/assets/use-settings-tab-guard-BMMFa0oA.js +1 -0
- package/dist/gateway/static/root/assets/vendor-codemirror-CNP1wPe7.js +45 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-DnRbhMNq.js +1 -0
- package/dist/gateway/static/root/assets/voice-player-store-D5vzWwls.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-page.utils-EYg_xBQS.js → workflow-page.utils-tjGpRVnw.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-DqqHKGj2.js +18 -0
- 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.ico +0 -0
- package/dist/gateway/static/root/favicon.svg +14 -12
- package/dist/gateway/static/root/index.html +18 -15
- 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/checklist-judge.d.ts +5 -0
- package/dist/src/agent/goals/checklist-judge.js +26 -2
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/evaluate-turn.d.ts +5 -1
- package/dist/src/agent/goals/evaluate-turn.js +29 -3
- package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.d.ts +0 -2
- package/dist/src/agent/goals/goal-locale.js +3 -16
- package/dist/src/agent/goals/goal-locale.js.map +1 -1
- package/dist/src/agent/goals/persistent-goal-service.d.ts +9 -0
- package/dist/src/agent/goals/persistent-goal-service.js +3 -2
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.d.ts +7 -0
- package/dist/src/agent/goals/post-turn.js +70 -25
- package/dist/src/agent/goals/post-turn.js.map +1 -1
- package/dist/src/agent/goals/state.d.ts +0 -5
- package/dist/src/agent/goals/state.js +1 -96
- package/dist/src/agent/goals/state.js.map +1 -1
- 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 +7 -0
- package/dist/src/agent/messaging/command-handler.js +11 -2
- 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/direct-turn-helpers.d.ts +2 -0
- package/dist/src/agent/service/direct-turn-helpers.js +3 -2
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +10 -1
- 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 +30 -6
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +12 -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 +8 -3
- package/dist/src/agent/tools/cronjob-tool.js +82 -24
- 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/edit.d.ts +2 -0
- package/dist/src/agent/tools/edit.js +10 -0
- package/dist/src/agent/tools/edit.js.map +1 -1
- package/dist/src/agent/tools/factory.js +17 -4
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +1 -1
- package/dist/src/agent/tools/goal-evidence-recorder.d.ts +6 -0
- package/dist/src/agent/tools/goal-evidence-recorder.js +34 -0
- package/dist/src/agent/tools/goal-evidence-recorder.js.map +1 -0
- package/dist/src/agent/tools/goal-tool.d.ts +19 -0
- package/dist/src/agent/tools/goal-tool.js +101 -0
- package/dist/src/agent/tools/goal-tool.js.map +1 -0
- 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/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/shell.d.ts +2 -0
- package/dist/src/agent/tools/shell.js +17 -2
- package/dist/src/agent/tools/shell.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.d.ts +1 -0
- package/dist/src/agent/tools/workflow-tool.js +11 -3
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/tools/write.d.ts +2 -0
- package/dist/src/agent/tools/write.js +11 -0
- package/dist/src/agent/tools/write.js.map +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 +39 -0
- package/dist/src/ai-assist/text-assist.js +234 -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/attachments/inbound-persist.d.ts +7 -0
- package/dist/src/channels/attachments/inbound-persist.js +20 -2
- package/dist/src/channels/attachments/inbound-persist.js.map +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/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +3 -3
- package/dist/src/chat-commands/builtins/goal.d.ts +1 -1
- package/dist/src/chat-commands/builtins/goal.js +55 -97
- package/dist/src/chat-commands/builtins/goal.js.map +1 -1
- package/dist/src/chat-commands/builtins/subgoal.d.ts +1 -1
- package/dist/src/chat-commands/builtins/subgoal.js +49 -108
- package/dist/src/chat-commands/builtins/subgoal.js.map +1 -1
- 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/builtins/workflow.js +132 -8
- package/dist/src/chat-commands/builtins/workflow.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +6 -0
- package/dist/src/chat-commands/context.js +12 -0
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +7 -0
- package/dist/src/cli/command-catalog.js +43 -0
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/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/goal.d.ts +4 -0
- package/dist/src/cli/commands/goal.js +213 -0
- package/dist/src/cli/commands/goal.js.map +1 -0
- 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/onboard.js +11 -5
- package/dist/src/cli/commands/onboard.js.map +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 +8 -8
- 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 +115 -2
- package/dist/src/config/schema.js +63 -7
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +14 -1
- package/dist/src/config/web-patch.js +45 -8
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.d.ts +2 -0
- package/dist/src/cron/executor.js +126 -70
- 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/job-content.js +1 -0
- package/dist/src/cron/job-content.js.map +1 -1
- 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 +97 -49
- package/dist/src/cron/validation.d.ts +374 -86
- package/dist/src/cron/validation.js +156 -129
- 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 +14 -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/goals.d.ts +1 -1
- package/dist/src/gateway/hono/routes/goals.js +670 -173
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +5 -0
- package/dist/src/gateway/hono/routes/home.js +90 -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/notes.js +20 -14
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +8 -4
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +2 -0
- package/dist/src/gateway/service/agent-runner.js +8 -4
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- 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/run-gateway-agent.d.ts +3 -0
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service.d.ts +8 -0
- package/dist/src/gateway/service.js +79 -6
- 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.d.ts +29 -0
- package/dist/src/goals/goal-notifications.js +154 -0
- package/dist/src/goals/goal-notifications.js.map +1 -0
- package/dist/src/goals/goal-queue-store.d.ts +16 -0
- package/dist/src/goals/goal-queue-store.js +131 -0
- package/dist/src/goals/goal-queue-store.js.map +1 -0
- package/dist/src/goals/goal-queue-types.d.ts +31 -0
- package/dist/src/goals/goal-queue-types.js +1 -0
- package/dist/src/goals/goal-runner.d.ts +17 -0
- package/dist/src/goals/goal-runner.js +127 -0
- package/dist/src/goals/goal-runner.js.map +1 -0
- package/dist/src/goals/goal-service.d.ts +77 -0
- package/dist/src/goals/goal-service.js +261 -0
- package/dist/src/goals/goal-service.js.map +1 -0
- package/dist/src/goals/goal-store.d.ts +38 -0
- package/dist/src/goals/goal-store.js +404 -0
- package/dist/src/goals/goal-store.js.map +1 -0
- package/dist/src/goals/goal-workflow-judge.d.ts +13 -0
- package/dist/src/goals/goal-workflow-judge.js +147 -0
- package/dist/src/goals/goal-workflow-judge.js.map +1 -0
- package/dist/src/goals/index.d.ts +10 -0
- package/dist/src/goals/index.js +7 -0
- package/dist/src/goals/types.d.ts +119 -0
- package/dist/src/goals/types.js +1 -0
- 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.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/006_add_goals.sql +108 -0
- package/dist/src/storage/sqlite/migrations/007_goal_run_judge_schema.sql +4 -0
- package/dist/src/storage/sqlite/migrations/008_goal_queue_workflow_runs.sql +53 -0
- 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 +188 -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/stats.d.ts +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/domain/run.d.ts +1 -0
- package/dist/src/workflows/domain/run.js.map +1 -1
- 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.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +7 -3
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +8 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-index-store.d.ts +8 -0
- package/dist/src/workflows/store/run-index-store.js +58 -0
- package/dist/src/workflows/store/run-index-store.js.map +1 -0
- package/dist/src/workflows/store/run-store.d.ts +2 -0
- package/dist/src/workflows/store/run-store.js +15 -22
- package/dist/src/workflows/store/run-store.js.map +1 -1
- package/package.json +10 -5
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
- package/dist/gateway/static/root/assets/agents-CFFioJCI.js +0 -78
- package/dist/gateway/static/root/assets/apps-page-BYDmkbzG.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CsbDaMvd.js +0 -1
- package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +0 -1
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-Apk-7p4p.js +0 -1
- package/dist/gateway/static/root/assets/dist-DmGDgpy2.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-pxFC-tUa.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-COXSv6xP.js +0 -1
- package/dist/gateway/static/root/assets/fetch-CFdKBnE6.js +0 -1
- package/dist/gateway/static/root/assets/gateway-startup-retry-DdngdObI.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-DcmAMYmN.js +0 -1
- package/dist/gateway/static/root/assets/index-C_2yKRJX.js +0 -4845
- package/dist/gateway/static/root/assets/index-DI5_GsZt.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-DvTWUOzd.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-CZbdugWZ.js +0 -180
- package/dist/gateway/static/root/assets/note-time-RdyBZxj3.js +0 -1
- package/dist/gateway/static/root/assets/notes-page-mEAwy3e1.js +0 -1
- package/dist/gateway/static/root/assets/schema-form-DEvdni_r.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BsgffzV4.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-t6v8Dwb8.js +0 -2
- package/dist/gateway/static/root/assets/settings-form-section-BoYYZmJG.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-ClIthYF8.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-Dd9et7KD.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-DEXtxyfQ.js +0 -2
- package/dist/gateway/static/root/assets/theme-store-BZozwAeK.js +0 -1
- package/dist/gateway/static/root/assets/url-DQRqHuL-.js +0 -3
- package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +0 -45
- package/dist/gateway/static/root/assets/voice-api-key-field-CNrKzQrf.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-EMZkzJNN.js +0 -18
- package/dist/gateway/static/root/favicon-16.png +0 -0
- package/dist/gateway/static/root/favicon-32.png +0 -0
- package/dist/src/agent/goals/checklist-user.d.ts +0 -24
- package/dist/src/agent/goals/checklist-user.js +0 -92
- package/dist/src/agent/goals/checklist-user.js.map +0 -1
- package/dist/src/agent/goals/goal-run-store.d.ts +0 -19
- package/dist/src/agent/goals/goal-run-store.js +0 -138
- package/dist/src/agent/goals/goal-run-store.js.map +0 -1
- package/dist/src/agent/goals/goal-run-types.d.ts +0 -28
- package/dist/src/agent/goals/goal-run-types.js +0 -6
- package/dist/src/agent/goals/goal-run-types.js.map +0 -1
- package/dist/src/agent/goals/patch-from-user-action.d.ts +0 -20
- package/dist/src/agent/goals/patch-from-user-action.js +0 -103
- package/dist/src/agent/goals/patch-from-user-action.js.map +0 -1
- 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
- /package/dist/gateway/static/root/assets/{note-detail-page-D4ZIVQbk.css → block-editor-D4ZIVQbk.css} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { resolveStateDir } from "../../config/paths-state.js";
|
|
2
|
+
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
3
|
+
import { createLogger } from "../../utils/logger/index.js";
|
|
4
|
+
import { init_logger } from "../../utils/logger.js";
|
|
5
|
+
import { createSkillConfigManager } from "./config.js";
|
|
6
|
+
import { isManagedSkillTransientDirName } from "./managed-store.js";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import chokidar from "chokidar";
|
|
9
|
+
//#region src/agent/skills/filesystem-watcher.ts
|
|
10
|
+
init_paths();
|
|
11
|
+
init_logger();
|
|
12
|
+
const log = createLogger("SkillFilesystemWatcher");
|
|
13
|
+
const DEFAULT_DEBOUNCE_MS = 1e3;
|
|
14
|
+
const WATCH_DEPTH = 8;
|
|
15
|
+
const IGNORED_SEGMENTS = new Set([
|
|
16
|
+
".git",
|
|
17
|
+
"node_modules",
|
|
18
|
+
"dist",
|
|
19
|
+
"build",
|
|
20
|
+
".next",
|
|
21
|
+
".nuxt",
|
|
22
|
+
".venv",
|
|
23
|
+
"venv",
|
|
24
|
+
"__pycache__",
|
|
25
|
+
".cache",
|
|
26
|
+
".mypy_cache",
|
|
27
|
+
".pytest_cache"
|
|
28
|
+
]);
|
|
29
|
+
function normalizePath(p) {
|
|
30
|
+
return path.resolve(p);
|
|
31
|
+
}
|
|
32
|
+
function pathSegments(p) {
|
|
33
|
+
return p.split(/[\\/]+/).filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
function hasIgnoredSegment(p) {
|
|
36
|
+
return pathSegments(p).some((segment) => IGNORED_SEGMENTS.has(segment) || isManagedSkillTransientDirName(segment));
|
|
37
|
+
}
|
|
38
|
+
function isSameOrInside(parent, child) {
|
|
39
|
+
const rel = path.relative(parent, child);
|
|
40
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
41
|
+
}
|
|
42
|
+
function isWorkspaceSkillPath(workspaceRoot, candidate) {
|
|
43
|
+
const skillsRoot = path.join(workspaceRoot, "skills");
|
|
44
|
+
return candidate === workspaceRoot || isSameOrInside(skillsRoot, candidate);
|
|
45
|
+
}
|
|
46
|
+
function isWorkspaceSkillsRoot(workspaceRoot, candidate) {
|
|
47
|
+
return candidate === path.join(workspaceRoot, "skills");
|
|
48
|
+
}
|
|
49
|
+
function isSkillMdPath(candidate) {
|
|
50
|
+
return path.basename(candidate).toLowerCase() === "skill.md";
|
|
51
|
+
}
|
|
52
|
+
function readWatcherConfig() {
|
|
53
|
+
const cfg = createSkillConfigManager(resolveStateDir()).load();
|
|
54
|
+
const rawDebounce = cfg.load?.watchDebounceMs;
|
|
55
|
+
return {
|
|
56
|
+
enabled: cfg.load?.watch !== false,
|
|
57
|
+
debounceMs: typeof rawDebounce === "number" && Number.isFinite(rawDebounce) ? Math.max(0, rawDebounce) : DEFAULT_DEBOUNCE_MS
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
var SkillFilesystemWatcher = class {
|
|
61
|
+
targets = /* @__PURE__ */ new Map();
|
|
62
|
+
onChange;
|
|
63
|
+
disposed = false;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
this.onChange = options.onChange;
|
|
66
|
+
this.watchGlobalSkillsDir();
|
|
67
|
+
}
|
|
68
|
+
watchGlobalSkillsDir() {
|
|
69
|
+
this.watchRoot(resolveSkillsDir(), "global");
|
|
70
|
+
}
|
|
71
|
+
watchWorkspace(workspaceDir) {
|
|
72
|
+
const resolved = normalizePath(workspaceDir);
|
|
73
|
+
if (!resolved) return;
|
|
74
|
+
this.watchRoot(resolved, "workspace");
|
|
75
|
+
}
|
|
76
|
+
refreshPrimaryWorkspace(workspaceDir) {
|
|
77
|
+
this.watchGlobalSkillsDir();
|
|
78
|
+
this.watchWorkspace(workspaceDir);
|
|
79
|
+
}
|
|
80
|
+
dispose() {
|
|
81
|
+
this.disposed = true;
|
|
82
|
+
for (const target of this.targets.values()) {
|
|
83
|
+
if (target.timer) clearTimeout(target.timer);
|
|
84
|
+
target.watcher.close().catch((err) => {
|
|
85
|
+
log.warn({
|
|
86
|
+
err,
|
|
87
|
+
root: target.root
|
|
88
|
+
}, "Skill watcher close failed");
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
this.targets.clear();
|
|
92
|
+
}
|
|
93
|
+
watchRoot(root, kind) {
|
|
94
|
+
if (this.disposed) return;
|
|
95
|
+
const { enabled, debounceMs } = readWatcherConfig();
|
|
96
|
+
const resolvedRoot = normalizePath(root);
|
|
97
|
+
const key = `${kind}:${resolvedRoot}`;
|
|
98
|
+
if (!enabled) {
|
|
99
|
+
this.unwatch(key);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (this.targets.get(key)) return;
|
|
103
|
+
const ignored = (watchPath, stats) => {
|
|
104
|
+
const candidate = normalizePath(watchPath);
|
|
105
|
+
if (candidate === resolvedRoot) return false;
|
|
106
|
+
if (hasIgnoredSegment(candidate)) return true;
|
|
107
|
+
if (kind === "workspace" && !isWorkspaceSkillPath(resolvedRoot, candidate)) return true;
|
|
108
|
+
if (kind === "workspace" && isWorkspaceSkillsRoot(resolvedRoot, candidate)) return false;
|
|
109
|
+
if (!stats) return false;
|
|
110
|
+
if (stats?.isDirectory?.()) return false;
|
|
111
|
+
return !isSkillMdPath(candidate);
|
|
112
|
+
};
|
|
113
|
+
const watcher = chokidar.watch(resolvedRoot, {
|
|
114
|
+
ignoreInitial: true,
|
|
115
|
+
followSymlinks: false,
|
|
116
|
+
depth: WATCH_DEPTH,
|
|
117
|
+
awaitWriteFinish: {
|
|
118
|
+
stabilityThreshold: debounceMs,
|
|
119
|
+
pollInterval: 100
|
|
120
|
+
},
|
|
121
|
+
ignored
|
|
122
|
+
});
|
|
123
|
+
const target = {
|
|
124
|
+
key,
|
|
125
|
+
root: resolvedRoot,
|
|
126
|
+
kind,
|
|
127
|
+
watcher
|
|
128
|
+
};
|
|
129
|
+
const schedule = (changedPath) => this.scheduleRefresh(target, changedPath);
|
|
130
|
+
watcher.on("addDir", schedule);
|
|
131
|
+
watcher.on("add", schedule);
|
|
132
|
+
watcher.on("change", schedule);
|
|
133
|
+
watcher.on("unlink", schedule);
|
|
134
|
+
watcher.on("unlinkDir", schedule);
|
|
135
|
+
watcher.on("error", (err) => {
|
|
136
|
+
log.warn({
|
|
137
|
+
err,
|
|
138
|
+
root: resolvedRoot,
|
|
139
|
+
kind
|
|
140
|
+
}, "Skill watcher error");
|
|
141
|
+
});
|
|
142
|
+
this.targets.set(key, target);
|
|
143
|
+
log.info({
|
|
144
|
+
root: resolvedRoot,
|
|
145
|
+
kind
|
|
146
|
+
}, "Watching skill filesystem");
|
|
147
|
+
}
|
|
148
|
+
unwatch(key) {
|
|
149
|
+
const target = this.targets.get(key);
|
|
150
|
+
if (!target) return;
|
|
151
|
+
if (target.timer) clearTimeout(target.timer);
|
|
152
|
+
target.watcher.close().catch((err) => {
|
|
153
|
+
log.warn({
|
|
154
|
+
err,
|
|
155
|
+
root: target.root
|
|
156
|
+
}, "Skill watcher close failed");
|
|
157
|
+
});
|
|
158
|
+
this.targets.delete(key);
|
|
159
|
+
}
|
|
160
|
+
scheduleRefresh(target, changedPath) {
|
|
161
|
+
const { enabled, debounceMs } = readWatcherConfig();
|
|
162
|
+
if (!enabled) {
|
|
163
|
+
this.unwatch(target.key);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
target.pendingPath = changedPath ?? target.pendingPath;
|
|
167
|
+
if (target.timer) clearTimeout(target.timer);
|
|
168
|
+
target.timer = setTimeout(() => {
|
|
169
|
+
target.timer = void 0;
|
|
170
|
+
const pendingPath = target.pendingPath;
|
|
171
|
+
target.pendingPath = void 0;
|
|
172
|
+
this.onChange({
|
|
173
|
+
reason: "watch",
|
|
174
|
+
changedPath: pendingPath
|
|
175
|
+
});
|
|
176
|
+
}, debounceMs);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
//#endregion
|
|
180
|
+
export { SkillFilesystemWatcher };
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=filesystem-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-watcher.js","names":[],"sources":["../../../../src/agent/skills/filesystem-watcher.ts"],"sourcesContent":["import path from 'node:path';\n\nimport chokidar, { type FSWatcher } from 'chokidar';\n\nimport { resolveSkillsDir, resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager } from './config.js';\nimport { isManagedSkillTransientDirName } from './managed-store.js';\n\nconst log = createLogger('SkillFilesystemWatcher');\n\nexport interface SkillFilesystemWatcherOptions {\n onChange: (event: { reason: 'watch'; changedPath?: string }) => void;\n}\n\ntype WatchTarget = {\n key: string;\n root: string;\n kind: 'global' | 'workspace';\n watcher: FSWatcher;\n timer?: NodeJS.Timeout;\n pendingPath?: string;\n};\n\nconst DEFAULT_DEBOUNCE_MS = 1000;\nconst WATCH_DEPTH = 8;\nconst IGNORED_SEGMENTS = new Set([\n '.git',\n 'node_modules',\n 'dist',\n 'build',\n '.next',\n '.nuxt',\n '.venv',\n 'venv',\n '__pycache__',\n '.cache',\n '.mypy_cache',\n '.pytest_cache',\n]);\n\nfunction normalizePath(p: string): string {\n return path.resolve(p);\n}\n\nfunction pathSegments(p: string): string[] {\n return p.split(/[\\\\/]+/).filter(Boolean);\n}\n\nfunction hasIgnoredSegment(p: string): boolean {\n return pathSegments(p).some(\n (segment) => IGNORED_SEGMENTS.has(segment) || isManagedSkillTransientDirName(segment),\n );\n}\n\nfunction isSameOrInside(parent: string, child: string): boolean {\n const rel = path.relative(parent, child);\n return rel === '' || (!!rel && !rel.startsWith('..') && !path.isAbsolute(rel));\n}\n\nfunction isWorkspaceSkillPath(workspaceRoot: string, candidate: string): boolean {\n const skillsRoot = path.join(workspaceRoot, 'skills');\n return candidate === workspaceRoot || isSameOrInside(skillsRoot, candidate);\n}\n\nfunction isWorkspaceSkillsRoot(workspaceRoot: string, candidate: string): boolean {\n return candidate === path.join(workspaceRoot, 'skills');\n}\n\nfunction isSkillMdPath(candidate: string): boolean {\n return path.basename(candidate).toLowerCase() === 'skill.md';\n}\n\nfunction readWatcherConfig(): { enabled: boolean; debounceMs: number } {\n const cfg = createSkillConfigManager(resolveStateDir()).load();\n const rawDebounce = cfg.load?.watchDebounceMs;\n return {\n enabled: cfg.load?.watch !== false,\n debounceMs:\n typeof rawDebounce === 'number' && Number.isFinite(rawDebounce)\n ? Math.max(0, rawDebounce)\n : DEFAULT_DEBOUNCE_MS,\n };\n}\n\nexport class SkillFilesystemWatcher {\n private readonly targets = new Map<string, WatchTarget>();\n private readonly onChange: SkillFilesystemWatcherOptions['onChange'];\n private disposed = false;\n\n constructor(options: SkillFilesystemWatcherOptions) {\n this.onChange = options.onChange;\n this.watchGlobalSkillsDir();\n }\n\n watchGlobalSkillsDir(): void {\n this.watchRoot(resolveSkillsDir(), 'global');\n }\n\n watchWorkspace(workspaceDir: string): void {\n const resolved = normalizePath(workspaceDir);\n if (!resolved) return;\n this.watchRoot(resolved, 'workspace');\n }\n\n refreshPrimaryWorkspace(workspaceDir: string): void {\n this.watchGlobalSkillsDir();\n this.watchWorkspace(workspaceDir);\n }\n\n dispose(): void {\n this.disposed = true;\n for (const target of this.targets.values()) {\n if (target.timer) clearTimeout(target.timer);\n void target.watcher.close().catch((err) => {\n log.warn({ err, root: target.root }, 'Skill watcher close failed');\n });\n }\n this.targets.clear();\n }\n\n private watchRoot(root: string, kind: WatchTarget['kind']): void {\n if (this.disposed) return;\n const { enabled, debounceMs } = readWatcherConfig();\n const resolvedRoot = normalizePath(root);\n const key = `${kind}:${resolvedRoot}`;\n\n if (!enabled) {\n this.unwatch(key);\n return;\n }\n\n const existing = this.targets.get(key);\n if (existing) return;\n\n const ignored = (watchPath: string, stats?: { isDirectory?: () => boolean }) => {\n const candidate = normalizePath(watchPath);\n if (candidate === resolvedRoot) return false;\n if (hasIgnoredSegment(candidate)) return true;\n\n if (kind === 'workspace' && !isWorkspaceSkillPath(resolvedRoot, candidate)) {\n return true;\n }\n\n if (kind === 'workspace' && isWorkspaceSkillsRoot(resolvedRoot, candidate)) return false;\n if (!stats) return false;\n if (stats?.isDirectory?.()) return false;\n return !isSkillMdPath(candidate);\n };\n\n const watcher = chokidar.watch(resolvedRoot, {\n ignoreInitial: true,\n followSymlinks: false,\n depth: WATCH_DEPTH,\n awaitWriteFinish: {\n stabilityThreshold: debounceMs,\n pollInterval: 100,\n },\n ignored,\n });\n\n const target: WatchTarget = { key, root: resolvedRoot, kind, watcher };\n const schedule = (changedPath?: string) => this.scheduleRefresh(target, changedPath);\n\n watcher.on('addDir', schedule);\n watcher.on('add', schedule);\n watcher.on('change', schedule);\n watcher.on('unlink', schedule);\n watcher.on('unlinkDir', schedule);\n watcher.on('error', (err) => {\n log.warn({ err, root: resolvedRoot, kind }, 'Skill watcher error');\n });\n\n this.targets.set(key, target);\n log.info({ root: resolvedRoot, kind }, 'Watching skill filesystem');\n }\n\n private unwatch(key: string): void {\n const target = this.targets.get(key);\n if (!target) return;\n if (target.timer) clearTimeout(target.timer);\n void target.watcher.close().catch((err) => {\n log.warn({ err, root: target.root }, 'Skill watcher close failed');\n });\n this.targets.delete(key);\n }\n\n private scheduleRefresh(target: WatchTarget, changedPath?: string): void {\n const { enabled, debounceMs } = readWatcherConfig();\n if (!enabled) {\n this.unwatch(target.key);\n return;\n }\n\n target.pendingPath = changedPath ?? target.pendingPath;\n if (target.timer) clearTimeout(target.timer);\n target.timer = setTimeout(() => {\n target.timer = undefined;\n const pendingPath = target.pendingPath;\n target.pendingPath = undefined;\n this.onChange({ reason: 'watch', changedPath: pendingPath });\n }, debounceMs);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { join, relative } from "node:path";
|
|
2
|
-
import { createReadStream, existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { createReadStream, existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
4
|
//#region src/agent/skills/hub-hash.ts
|
|
5
5
|
/**
|
|
6
6
|
* Deterministic content hash for a skill directory (for hub lock / drift detection).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { init_paths, resolveSkillsLockPath } from "../../config/paths.js";
|
|
2
1
|
import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
|
|
2
|
+
import { init_paths, resolveSkillsLockPath } from "../../config/paths.js";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
//#region src/agent/skills/hub-lock.ts
|
|
5
5
|
/**
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
2
1
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
3
2
|
import { formatScanSummary, scanSkillDirectory } from "./scanner.js";
|
|
4
3
|
import { getSkillsLockEntry, recordSkillsHubInstall } from "./hub-lock.js";
|
|
5
|
-
import { installSkillFromZip, isValidSkillId } from "./managed-store.js";
|
|
4
|
+
import { installSkillFromZip, isValidSkillId, prepareManagedSkillTempDir, promoteManagedSkillTempDir } from "./managed-store.js";
|
|
6
5
|
import { computeSkillTreeHashSync } from "./hub-hash.js";
|
|
7
|
-
import { tmpdir } from "node:os";
|
|
8
|
-
import { basename, join, normalize, resolve, sep } from "node:path";
|
|
9
6
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { basename, join, normalize, resolve } from "node:path";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
10
9
|
import { fileURLToPath } from "node:url";
|
|
11
10
|
import { execFileSync } from "node:child_process";
|
|
12
11
|
import { fetch } from "undici";
|
|
@@ -14,7 +13,6 @@ import { fetch } from "undici";
|
|
|
14
13
|
/**
|
|
15
14
|
* CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.
|
|
16
15
|
*/
|
|
17
|
-
init_paths();
|
|
18
16
|
function classifyHubSource(raw) {
|
|
19
17
|
const s = raw.trim();
|
|
20
18
|
const lower = s.toLowerCase();
|
|
@@ -70,42 +68,38 @@ async function copySkillTreeToManaged(skillRoot, ctx) {
|
|
|
70
68
|
const targetId = ctx.skillId?.trim() || inferSkillIdFromSkillMd(skillRoot);
|
|
71
69
|
if (!targetId) throw new Error("Could not determine skill id: pass --id <name> (must match managed id rules)");
|
|
72
70
|
if (!isValidSkillId(targetId)) throw new Error(`Invalid skill id "${targetId}" (letters, digits, ._-; max 63 chars after first)`);
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
force: true
|
|
71
|
+
const { destDir, tempDir } = prepareManagedSkillTempDir(targetId);
|
|
72
|
+
try {
|
|
73
|
+
if (existsSync(destDir) && !ctx.force) throw new Error(`Skill "${targetId}" already exists. Use --force to replace.`);
|
|
74
|
+
cpSync(skillRoot, tempDir, { recursive: true });
|
|
75
|
+
if (!existsSync(join(tempDir, "SKILL.md"))) throw new Error("Installed tree is missing SKILL.md");
|
|
76
|
+
await runScan(tempDir, ctx.strictScan);
|
|
77
|
+
const promoted = promoteManagedSkillTempDir({
|
|
78
|
+
skillId: targetId,
|
|
79
|
+
tempDir,
|
|
80
|
+
overwrite: ctx.force
|
|
84
81
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
const hash = computeSkillTreeHashSync(promoted.path);
|
|
83
|
+
recordSkillsHubInstall(targetId, {
|
|
84
|
+
kind: ctx.kind,
|
|
85
|
+
source: ctx.source,
|
|
86
|
+
ref: ctx.kind === "git" ? ctx.ref : void 0,
|
|
87
|
+
subpath: ctx.kind === "git" ? ctx.subpath : void 0
|
|
88
|
+
}, hash);
|
|
89
|
+
return {
|
|
90
|
+
skillId: targetId,
|
|
91
|
+
path: promoted.path,
|
|
92
|
+
contentHash: hash,
|
|
93
|
+
kind: ctx.kind,
|
|
94
|
+
source: ctx.source
|
|
95
|
+
};
|
|
96
|
+
} catch (err) {
|
|
97
|
+
rmSync(tempDir, {
|
|
89
98
|
recursive: true,
|
|
90
99
|
force: true
|
|
91
100
|
});
|
|
92
|
-
throw
|
|
101
|
+
throw err;
|
|
93
102
|
}
|
|
94
|
-
const hash = computeSkillTreeHashSync(dest);
|
|
95
|
-
recordSkillsHubInstall(targetId, {
|
|
96
|
-
kind: ctx.kind,
|
|
97
|
-
source: ctx.source,
|
|
98
|
-
ref: ctx.kind === "git" ? ctx.ref : void 0,
|
|
99
|
-
subpath: ctx.kind === "git" ? ctx.subpath : void 0
|
|
100
|
-
}, hash);
|
|
101
|
-
await runScan(dest, ctx.strictScan);
|
|
102
|
-
return {
|
|
103
|
-
skillId: targetId,
|
|
104
|
-
path: dest,
|
|
105
|
-
contentHash: hash,
|
|
106
|
-
kind: ctx.kind,
|
|
107
|
-
source: ctx.source
|
|
108
|
-
};
|
|
109
103
|
}
|
|
110
104
|
async function pullSkillFromZipBuffer(buf, sourceLabel, options) {
|
|
111
105
|
const r = installSkillFromZip(buf, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hub-pull.js","names":[],"sources":["../../../../src/agent/skills/hub-pull.ts"],"sourcesContent":["/**\n * CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n cpSync,\n existsSync,\n mkdtempSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join, normalize, resolve, sep } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\nimport { fetch } from 'undici';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport { computeSkillTreeHashSync } from './hub-hash.js';\nimport { getSkillsLockEntry, recordSkillsHubInstall } from './hub-lock.js';\nimport type { SkillHubKind } from './hub-lock.js';\nimport { installSkillFromZip, isValidSkillId } from './managed-store.js';\nimport { formatScanSummary, scanSkillDirectory } from './scanner.js';\n\nexport interface HubPullOptions {\n skillId?: string;\n ref?: string;\n subpath?: string;\n force?: boolean;\n /** When true, critical scanner findings fail the install. */\n strictScan?: boolean;\n}\n\nexport interface HubPullResult {\n skillId: string;\n path: string;\n contentHash: string;\n kind: SkillHubKind;\n source: string;\n}\n\nexport function classifyHubSource(raw: string): 'git' | 'archive' {\n const s = raw.trim();\n const lower = s.toLowerCase();\n\n try {\n if (s.startsWith('file:')) {\n const p = fileURLToPath(s);\n const pl = p.toLowerCase();\n if (pl.endsWith('.zip')) return 'archive';\n if (pl.endsWith('.tar.gz') || pl.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n } catch {\n // ignore invalid file URL\n }\n\n if (/^[a-zA-Z]:[\\\\/]/.test(s) || (s.startsWith('/') && !s.startsWith('//'))) {\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n\n try {\n const u = new URL(s);\n const path = u.pathname.toLowerCase();\n if (path.endsWith('.zip')) return 'archive';\n if (path.endsWith('.tar.gz') || path.endsWith('.tgz')) return 'archive';\n } catch {\n // not a URL\n }\n\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n}\n\nexport function findSkillRoot(repoRoot: string, subpath?: string): string {\n const sub = subpath?.trim()\n ? normalize(subpath.trim()).replace(/^[/\\\\]+/, '')\n : '';\n const base = sub ? resolve(repoRoot, sub) : resolve(repoRoot);\n if (!existsSync(base)) {\n throw new Error(`Path not found in source: ${sub || '.'}`);\n }\n if (existsSync(join(base, 'SKILL.md'))) {\n return base;\n }\n const entries = readdirSync(base, { withFileTypes: true }).filter((e) => e.isDirectory());\n if (entries.length === 1) {\n const one = join(base, entries[0].name);\n if (existsSync(join(one, 'SKILL.md'))) {\n return one;\n }\n }\n throw new Error(\n 'Could not locate SKILL.md (expected at root, under --path, or in a single child folder)',\n );\n}\n\nfunction inferSkillIdFromSkillMd(skillRoot: string): string {\n const raw = readFileSync(join(skillRoot, 'SKILL.md'), 'utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n const n = String(frontmatter.name || '').trim();\n if (n && isValidSkillId(n)) {\n return n;\n }\n const dirName = basename(skillRoot);\n if (isValidSkillId(dirName)) {\n return dirName;\n }\n return '';\n}\n\nasync function runScan(dir: string, strict: boolean | undefined): Promise<void> {\n const summary = await scanSkillDirectory(dir);\n const label = basename(dir);\n if (summary.critical > 0 && strict) {\n throw new Error(\n `Security scan reported ${summary.critical} critical finding(s). ${formatScanSummary(summary, label)}`,\n );\n }\n if (summary.critical > 0 || summary.warn > 0) {\n console.warn(formatScanSummary(summary, label));\n }\n}\n\nasync function copySkillTreeToManaged(\n skillRoot: string,\n ctx: HubPullOptions & { kind: SkillHubKind; source: string },\n): Promise<HubPullResult> {\n const targetId = ctx.skillId?.trim() || inferSkillIdFromSkillMd(skillRoot);\n if (!targetId) {\n throw new Error('Could not determine skill id: pass --id <name> (must match managed id rules)');\n }\n if (!isValidSkillId(targetId)) {\n throw new Error(`Invalid skill id \"${targetId}\" (letters, digits, ._-; max 63 chars after first)`);\n }\n\n const rootDir = resolveSkillsDir();\n mkdirSync(rootDir, { recursive: true });\n const dest = join(rootDir, targetId);\n const destResolved = resolve(dest);\n const rootResolved = resolve(rootDir);\n if (!destResolved.startsWith(rootResolved + sep) && destResolved !== rootResolved) {\n throw new Error('Invalid destination path');\n }\n\n if (existsSync(dest)) {\n if (!ctx.force) {\n throw new Error(`Skill \"${targetId}\" already exists. Use --force to replace.`);\n }\n rmSync(dest, { recursive: true, force: true });\n }\n\n cpSync(skillRoot, dest, { recursive: true });\n\n if (!existsSync(join(dest, 'SKILL.md'))) {\n rmSync(dest, { recursive: true, force: true });\n throw new Error('Installed tree is missing SKILL.md');\n }\n\n const hash = computeSkillTreeHashSync(dest);\n recordSkillsHubInstall(\n targetId,\n {\n kind: ctx.kind,\n source: ctx.source,\n ref: ctx.kind === 'git' ? ctx.ref : undefined,\n subpath: ctx.kind === 'git' ? ctx.subpath : undefined,\n },\n hash,\n );\n await runScan(dest, ctx.strictScan);\n\n return {\n skillId: targetId,\n path: dest,\n contentHash: hash,\n kind: ctx.kind,\n source: ctx.source,\n };\n}\n\nasync function pullSkillFromZipBuffer(\n buf: Buffer,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const r = installSkillFromZip(buf, {\n skillId: options.skillId,\n overwrite: options.force ?? false,\n });\n const hash = computeSkillTreeHashSync(r.path);\n recordSkillsHubInstall(r.skillId, { kind: 'archive', source: sourceLabel }, hash);\n await runScan(r.path, options.strictScan);\n return {\n skillId: r.skillId,\n path: r.path,\n contentHash: hash,\n kind: 'archive',\n source: sourceLabel,\n };\n}\n\nasync function pullSkillFromTarFile(\n archivePath: string,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-tar-'));\n try {\n execFileSync('tar', ['-xzf', archivePath, '-C', tmpRoot], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n const skillRoot = findSkillRoot(tmpRoot);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'archive', source: sourceLabel });\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\nasync function pullSkillFromLocalPath(absPath: string, options: HubPullOptions): Promise<HubPullResult> {\n const resolved = resolve(absPath);\n if (!existsSync(resolved)) {\n throw new Error(`Not found: ${resolved}`);\n }\n const st = statSync(resolved);\n if (!st.isFile()) {\n throw new Error('Expected a path to a .zip or .tar.gz file (directories are not supported here)');\n }\n const lower = resolved.toLowerCase();\n if (lower.endsWith('.zip')) {\n const buf = readFileSync(resolved);\n return pullSkillFromZipBuffer(buf, resolved, options);\n }\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n return pullSkillFromTarFile(resolved, resolved, options);\n }\n throw new Error('Unsupported file type (expected .zip, .tar.gz, or .tgz)');\n}\n\nasync function pullSkillFromGit(url: string, options: HubPullOptions): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-hub-'));\n const cloneDir = join(tmpRoot, 'clone');\n try {\n const args = ['clone', '--depth', '1'];\n if (options.ref?.trim()) {\n args.push('--branch', options.ref.trim());\n }\n args.push(url, cloneDir);\n try {\n execFileSync('git', args, { stdio: 'pipe', encoding: 'utf-8' });\n } catch {\n if (options.ref?.trim()) {\n execFileSync('git', ['clone', '--depth', '1', url, cloneDir], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n } else {\n throw new Error(`git clone failed for ${url}`);\n }\n }\n const skillRoot = findSkillRoot(cloneDir, options.subpath);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'git', source: url });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (msg.includes('ENOENT') || msg.includes('git clone failed')) {\n throw new Error(\n `Git operation failed (${msg}). Ensure git is installed and the repository URL is valid.`,\n );\n }\n throw e;\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\n/**\n * Install or replace a skill from a git URL, http(s) archive URL, file:// URL, or local archive path.\n */\nexport async function pullSkillFromSource(\n source: string,\n options: HubPullOptions = {},\n): Promise<HubPullResult> {\n const trimmed = source.trim();\n if (!trimmed) {\n throw new Error('Missing source URL or path');\n }\n\n if (trimmed.startsWith('file:')) {\n return pullSkillFromLocalPath(fileURLToPath(trimmed), options);\n }\n\n if (!/^[a-zA-Z][a-zA-Z+.-]*:\\/\\//.test(trimmed) && existsSync(trimmed)) {\n return pullSkillFromLocalPath(resolve(trimmed), options);\n }\n\n const kind = classifyHubSource(trimmed);\n if (kind === 'archive') {\n const res = await fetch(trimmed);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} while fetching archive`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n const lower = trimmed.toLowerCase();\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-fetch-tar-'));\n const f = join(tmpRoot, 'archive.tgz');\n try {\n mkdirSync(tmpRoot, { recursive: true });\n writeFileSync(f, buf);\n return await pullSkillFromTarFile(f, trimmed, options);\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n }\n return pullSkillFromZipBuffer(buf, trimmed, options);\n }\n\n return pullSkillFromGit(trimmed, options);\n}\n\n/** Re-install from the source recorded in ~/.xopc/skills-lock.json for this skill id. */\nexport async function updateSkillFromLock(\n skillId: string,\n options: Pick<HubPullOptions, 'strictScan'> = {},\n): Promise<HubPullResult> {\n const e = getSkillsLockEntry(skillId);\n if (!e) {\n throw new Error(\n `No hub lock entry for \"${skillId}\". Install with: xopc skills pull <git-or-archive-url>`,\n );\n }\n return pullSkillFromSource(e.source, {\n skillId,\n ref: e.ref,\n subpath: e.subpath,\n force: true,\n strictScan: options.strictScan,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hub-pull.js","names":[],"sources":["../../../../src/agent/skills/hub-pull.ts"],"sourcesContent":["/**\n * CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n cpSync,\n existsSync,\n mkdtempSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join, normalize, resolve } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\nimport { fetch } from 'undici';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { computeSkillTreeHashSync } from './hub-hash.js';\nimport { getSkillsLockEntry, recordSkillsHubInstall } from './hub-lock.js';\nimport type { SkillHubKind } from './hub-lock.js';\nimport {\n installSkillFromZip,\n isValidSkillId,\n prepareManagedSkillTempDir,\n promoteManagedSkillTempDir,\n} from './managed-store.js';\nimport { formatScanSummary, scanSkillDirectory } from './scanner.js';\n\nexport interface HubPullOptions {\n skillId?: string;\n ref?: string;\n subpath?: string;\n force?: boolean;\n /** When true, critical scanner findings fail the install. */\n strictScan?: boolean;\n}\n\nexport interface HubPullResult {\n skillId: string;\n path: string;\n contentHash: string;\n kind: SkillHubKind;\n source: string;\n}\n\nexport function classifyHubSource(raw: string): 'git' | 'archive' {\n const s = raw.trim();\n const lower = s.toLowerCase();\n\n try {\n if (s.startsWith('file:')) {\n const p = fileURLToPath(s);\n const pl = p.toLowerCase();\n if (pl.endsWith('.zip')) return 'archive';\n if (pl.endsWith('.tar.gz') || pl.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n } catch {\n // ignore invalid file URL\n }\n\n if (/^[a-zA-Z]:[\\\\/]/.test(s) || (s.startsWith('/') && !s.startsWith('//'))) {\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n\n try {\n const u = new URL(s);\n const path = u.pathname.toLowerCase();\n if (path.endsWith('.zip')) return 'archive';\n if (path.endsWith('.tar.gz') || path.endsWith('.tgz')) return 'archive';\n } catch {\n // not a URL\n }\n\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n}\n\nexport function findSkillRoot(repoRoot: string, subpath?: string): string {\n const sub = subpath?.trim()\n ? normalize(subpath.trim()).replace(/^[/\\\\]+/, '')\n : '';\n const base = sub ? resolve(repoRoot, sub) : resolve(repoRoot);\n if (!existsSync(base)) {\n throw new Error(`Path not found in source: ${sub || '.'}`);\n }\n if (existsSync(join(base, 'SKILL.md'))) {\n return base;\n }\n const entries = readdirSync(base, { withFileTypes: true }).filter((e) => e.isDirectory());\n if (entries.length === 1) {\n const one = join(base, entries[0].name);\n if (existsSync(join(one, 'SKILL.md'))) {\n return one;\n }\n }\n throw new Error(\n 'Could not locate SKILL.md (expected at root, under --path, or in a single child folder)',\n );\n}\n\nfunction inferSkillIdFromSkillMd(skillRoot: string): string {\n const raw = readFileSync(join(skillRoot, 'SKILL.md'), 'utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n const n = String(frontmatter.name || '').trim();\n if (n && isValidSkillId(n)) {\n return n;\n }\n const dirName = basename(skillRoot);\n if (isValidSkillId(dirName)) {\n return dirName;\n }\n return '';\n}\n\nasync function runScan(dir: string, strict: boolean | undefined): Promise<void> {\n const summary = await scanSkillDirectory(dir);\n const label = basename(dir);\n if (summary.critical > 0 && strict) {\n throw new Error(\n `Security scan reported ${summary.critical} critical finding(s). ${formatScanSummary(summary, label)}`,\n );\n }\n if (summary.critical > 0 || summary.warn > 0) {\n console.warn(formatScanSummary(summary, label));\n }\n}\n\nasync function copySkillTreeToManaged(\n skillRoot: string,\n ctx: HubPullOptions & { kind: SkillHubKind; source: string },\n): Promise<HubPullResult> {\n const targetId = ctx.skillId?.trim() || inferSkillIdFromSkillMd(skillRoot);\n if (!targetId) {\n throw new Error('Could not determine skill id: pass --id <name> (must match managed id rules)');\n }\n if (!isValidSkillId(targetId)) {\n throw new Error(`Invalid skill id \"${targetId}\" (letters, digits, ._-; max 63 chars after first)`);\n }\n\n const { destDir, tempDir } = prepareManagedSkillTempDir(targetId);\n try {\n if (existsSync(destDir) && !ctx.force) {\n throw new Error(`Skill \"${targetId}\" already exists. Use --force to replace.`);\n }\n\n cpSync(skillRoot, tempDir, { recursive: true });\n\n if (!existsSync(join(tempDir, 'SKILL.md'))) {\n throw new Error('Installed tree is missing SKILL.md');\n }\n\n await runScan(tempDir, ctx.strictScan);\n const promoted = promoteManagedSkillTempDir({\n skillId: targetId,\n tempDir,\n overwrite: ctx.force,\n });\n const hash = computeSkillTreeHashSync(promoted.path);\n recordSkillsHubInstall(\n targetId,\n {\n kind: ctx.kind,\n source: ctx.source,\n ref: ctx.kind === 'git' ? ctx.ref : undefined,\n subpath: ctx.kind === 'git' ? ctx.subpath : undefined,\n },\n hash,\n );\n\n return {\n skillId: targetId,\n path: promoted.path,\n contentHash: hash,\n kind: ctx.kind,\n source: ctx.source,\n };\n } catch (err) {\n rmSync(tempDir, { recursive: true, force: true });\n throw err;\n }\n}\n\nasync function pullSkillFromZipBuffer(\n buf: Buffer,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const r = installSkillFromZip(buf, {\n skillId: options.skillId,\n overwrite: options.force ?? false,\n });\n const hash = computeSkillTreeHashSync(r.path);\n recordSkillsHubInstall(r.skillId, { kind: 'archive', source: sourceLabel }, hash);\n await runScan(r.path, options.strictScan);\n return {\n skillId: r.skillId,\n path: r.path,\n contentHash: hash,\n kind: 'archive',\n source: sourceLabel,\n };\n}\n\nasync function pullSkillFromTarFile(\n archivePath: string,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-tar-'));\n try {\n execFileSync('tar', ['-xzf', archivePath, '-C', tmpRoot], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n const skillRoot = findSkillRoot(tmpRoot);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'archive', source: sourceLabel });\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\nasync function pullSkillFromLocalPath(absPath: string, options: HubPullOptions): Promise<HubPullResult> {\n const resolved = resolve(absPath);\n if (!existsSync(resolved)) {\n throw new Error(`Not found: ${resolved}`);\n }\n const st = statSync(resolved);\n if (!st.isFile()) {\n throw new Error('Expected a path to a .zip or .tar.gz file (directories are not supported here)');\n }\n const lower = resolved.toLowerCase();\n if (lower.endsWith('.zip')) {\n const buf = readFileSync(resolved);\n return pullSkillFromZipBuffer(buf, resolved, options);\n }\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n return pullSkillFromTarFile(resolved, resolved, options);\n }\n throw new Error('Unsupported file type (expected .zip, .tar.gz, or .tgz)');\n}\n\nasync function pullSkillFromGit(url: string, options: HubPullOptions): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-hub-'));\n const cloneDir = join(tmpRoot, 'clone');\n try {\n const args = ['clone', '--depth', '1'];\n if (options.ref?.trim()) {\n args.push('--branch', options.ref.trim());\n }\n args.push(url, cloneDir);\n try {\n execFileSync('git', args, { stdio: 'pipe', encoding: 'utf-8' });\n } catch {\n if (options.ref?.trim()) {\n execFileSync('git', ['clone', '--depth', '1', url, cloneDir], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n } else {\n throw new Error(`git clone failed for ${url}`);\n }\n }\n const skillRoot = findSkillRoot(cloneDir, options.subpath);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'git', source: url });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (msg.includes('ENOENT') || msg.includes('git clone failed')) {\n throw new Error(\n `Git operation failed (${msg}). Ensure git is installed and the repository URL is valid.`,\n );\n }\n throw e;\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\n/**\n * Install or replace a skill from a git URL, http(s) archive URL, file:// URL, or local archive path.\n */\nexport async function pullSkillFromSource(\n source: string,\n options: HubPullOptions = {},\n): Promise<HubPullResult> {\n const trimmed = source.trim();\n if (!trimmed) {\n throw new Error('Missing source URL or path');\n }\n\n if (trimmed.startsWith('file:')) {\n return pullSkillFromLocalPath(fileURLToPath(trimmed), options);\n }\n\n if (!/^[a-zA-Z][a-zA-Z+.-]*:\\/\\//.test(trimmed) && existsSync(trimmed)) {\n return pullSkillFromLocalPath(resolve(trimmed), options);\n }\n\n const kind = classifyHubSource(trimmed);\n if (kind === 'archive') {\n const res = await fetch(trimmed);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} while fetching archive`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n const lower = trimmed.toLowerCase();\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-fetch-tar-'));\n const f = join(tmpRoot, 'archive.tgz');\n try {\n mkdirSync(tmpRoot, { recursive: true });\n writeFileSync(f, buf);\n return await pullSkillFromTarFile(f, trimmed, options);\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n }\n return pullSkillFromZipBuffer(buf, trimmed, options);\n }\n\n return pullSkillFromGit(trimmed, options);\n}\n\n/** Re-install from the source recorded in ~/.xopc/skills-lock.json for this skill id. */\nexport async function updateSkillFromLock(\n skillId: string,\n options: Pick<HubPullOptions, 'strictScan'> = {},\n): Promise<HubPullResult> {\n const e = getSkillsLockEntry(skillId);\n if (!e) {\n throw new Error(\n `No hub lock entry for \"${skillId}\". Install with: xopc skills pull <git-or-archive-url>`,\n );\n }\n return pullSkillFromSource(e.source, {\n skillId,\n ref: e.ref,\n subpath: e.subpath,\n force: true,\n strictScan: options.strictScan,\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveStateDir } from "../../config/paths-state.js";
|
|
2
|
+
import { init_paths } 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 } from "../../config/paths.js";
|
|
5
5
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
6
6
|
import { findInstallSpec, getDefaultInstallerPreferences, hasBinary, installSkill } from "./installer.js";
|
|
7
7
|
import { applySkillEnvOverrides, createSkillConfigManager, getSkillEnvironment, isSkillEnabled, resolveSkillConfig, validateSkillConfig } from "./config.js";
|
|
@@ -11,8 +11,8 @@ import { parseRequiredEnvVarNames } from "./required-env-vars.js";
|
|
|
11
11
|
import { formatSkillsForPrompt } from "./format-skills-prompt.js";
|
|
12
12
|
import { parseSkillMetadata } from "./parse-skill-metadata.js";
|
|
13
13
|
import { SkillTestFramework, SkillTestRunner, formatTestResults, formatTestResultsJson, formatTestResultsTap } from "./test-framework.js";
|
|
14
|
-
import { basename, dirname, join, relative, sep } from "path";
|
|
15
14
|
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
15
|
+
import { basename, dirname, join, relative, sep } from "path";
|
|
16
16
|
//#region src/agent/skills/index.ts
|
|
17
17
|
init_paths();
|
|
18
18
|
init_logger();
|
|
@@ -68,7 +68,11 @@ function shouldIgnore(path, ignoredPaths) {
|
|
|
68
68
|
}
|
|
69
69
|
function discoverSkills(dir, source) {
|
|
70
70
|
const skills = [];
|
|
71
|
-
|
|
71
|
+
const diagnostics = [];
|
|
72
|
+
if (!existsSync(dir)) return {
|
|
73
|
+
skills,
|
|
74
|
+
diagnostics
|
|
75
|
+
};
|
|
72
76
|
function scan(currentDir, currentIgnoredPaths) {
|
|
73
77
|
try {
|
|
74
78
|
const entries = readdirSync(currentDir, { withFileTypes: true });
|
|
@@ -86,16 +90,27 @@ function discoverSkills(dir, source) {
|
|
|
86
90
|
for (const rule of subRules) subIgnoredPaths.add(`${skillRelPath}${rule}`);
|
|
87
91
|
}
|
|
88
92
|
if (existsSync(skillMdPath) && !shouldIgnore(skillRelPath, currentIgnoredPaths)) {
|
|
89
|
-
const skill = loadSkillFromFile(skillMdPath, source, dir);
|
|
93
|
+
const { skill, diagnostic } = loadSkillFromFile(skillMdPath, source, dir);
|
|
94
|
+
if (diagnostic) diagnostics.push(diagnostic);
|
|
90
95
|
if (skill) skills.push(skill);
|
|
91
96
|
}
|
|
92
97
|
scan(fullPath, subIgnoredPaths);
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
|
-
} catch {
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
diagnostics.push({
|
|
103
|
+
type: "error",
|
|
104
|
+
message: `Failed to scan skills directory: ${message}`,
|
|
105
|
+
path: currentDir
|
|
106
|
+
});
|
|
107
|
+
}
|
|
96
108
|
}
|
|
97
109
|
scan(dir, loadIgnoreRules(dir, dir));
|
|
98
|
-
return
|
|
110
|
+
return {
|
|
111
|
+
skills,
|
|
112
|
+
diagnostics
|
|
113
|
+
};
|
|
99
114
|
}
|
|
100
115
|
function deriveDescriptionFromMarkdown(content) {
|
|
101
116
|
let fallbackHeading = "";
|
|
@@ -118,7 +133,15 @@ function loadSkillFromFile(filePath, source, rootDir) {
|
|
|
118
133
|
const parentDirName = basename(skillDir);
|
|
119
134
|
const name = frontmatter.name || parentDirName;
|
|
120
135
|
const description = frontmatter.description?.trim() || deriveDescriptionFromMarkdown(content);
|
|
121
|
-
if (!description?.trim()) return
|
|
136
|
+
if (!description?.trim()) return {
|
|
137
|
+
skill: null,
|
|
138
|
+
diagnostic: {
|
|
139
|
+
type: "error",
|
|
140
|
+
skillName: name,
|
|
141
|
+
message: `Skill "${name}" is missing a description`,
|
|
142
|
+
path: filePath
|
|
143
|
+
}
|
|
144
|
+
};
|
|
122
145
|
let category;
|
|
123
146
|
if (rootDir) {
|
|
124
147
|
const segments = toPosixPath(relative(rootDir, skillDir)).split("/");
|
|
@@ -129,7 +152,7 @@ function loadSkillFromFile(filePath, source, rootDir) {
|
|
|
129
152
|
metadata.description ||= description.trim();
|
|
130
153
|
const toolConditions = parseSkillToolConditions(frontmatter);
|
|
131
154
|
const requiredEnvVarNames = parseRequiredEnvVarNames(frontmatter);
|
|
132
|
-
return {
|
|
155
|
+
return { skill: {
|
|
133
156
|
name,
|
|
134
157
|
description: description.trim(),
|
|
135
158
|
category,
|
|
@@ -141,38 +164,55 @@ function loadSkillFromFile(filePath, source, rootDir) {
|
|
|
141
164
|
toolConditions,
|
|
142
165
|
requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : void 0,
|
|
143
166
|
content
|
|
167
|
+
} };
|
|
168
|
+
} catch (err) {
|
|
169
|
+
return {
|
|
170
|
+
skill: null,
|
|
171
|
+
diagnostic: {
|
|
172
|
+
type: "error",
|
|
173
|
+
message: `Failed to load skill file: ${err instanceof Error ? err.message : String(err)}`,
|
|
174
|
+
path: filePath
|
|
175
|
+
}
|
|
144
176
|
};
|
|
145
|
-
} catch {
|
|
146
|
-
return null;
|
|
147
177
|
}
|
|
148
178
|
}
|
|
149
179
|
function loadSkills(options) {
|
|
150
180
|
const { workspaceDir, builtinDir, extraDirs = [] } = options;
|
|
151
181
|
const skillMap = /* @__PURE__ */ new Map();
|
|
152
182
|
const diagnostics = [];
|
|
153
|
-
if (builtinDir)
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
183
|
+
if (builtinDir) {
|
|
184
|
+
const discovered = discoverSkills(builtinDir, "builtin");
|
|
185
|
+
diagnostics.push(...discovered.diagnostics);
|
|
186
|
+
for (const skill of discovered.skills) {
|
|
187
|
+
const existing = skillMap.get(skill.name);
|
|
188
|
+
if (existing) diagnostics.push({
|
|
189
|
+
type: "collision",
|
|
190
|
+
skillName: skill.name,
|
|
191
|
+
message: `Skill "${skill.name}" collision: ${existing.source} overrides ${skill.source}`,
|
|
192
|
+
path: skill.filePath
|
|
193
|
+
});
|
|
194
|
+
else skillMap.set(skill.name, skill);
|
|
195
|
+
}
|
|
162
196
|
}
|
|
163
197
|
const globalDirs = [options.globalDir, join(resolveStateDir(), "skills")].filter((d) => !!d && existsSync(d));
|
|
164
|
-
for (const dir of globalDirs)
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
198
|
+
for (const dir of globalDirs) {
|
|
199
|
+
const discovered = discoverSkills(dir, "global");
|
|
200
|
+
diagnostics.push(...discovered.diagnostics);
|
|
201
|
+
for (const skill of discovered.skills) {
|
|
202
|
+
const existing = skillMap.get(skill.name);
|
|
203
|
+
if (existing) diagnostics.push({
|
|
204
|
+
type: "collision",
|
|
205
|
+
skillName: skill.name,
|
|
206
|
+
message: `Skill "${skill.name}" collision: ${skill.source} overrides ${existing.source}`,
|
|
207
|
+
path: skill.filePath
|
|
208
|
+
});
|
|
209
|
+
skillMap.set(skill.name, skill);
|
|
210
|
+
}
|
|
173
211
|
}
|
|
174
212
|
if (workspaceDir) {
|
|
175
|
-
const
|
|
213
|
+
const discovered = discoverSkills(join(workspaceDir, "skills"), "workspace");
|
|
214
|
+
diagnostics.push(...discovered.diagnostics);
|
|
215
|
+
const workspaceSkills = discovered.skills;
|
|
176
216
|
for (const skill of workspaceSkills) {
|
|
177
217
|
const existing = skillMap.get(skill.name);
|
|
178
218
|
if (existing) diagnostics.push({
|
|
@@ -184,15 +224,19 @@ function loadSkills(options) {
|
|
|
184
224
|
skillMap.set(skill.name, skill);
|
|
185
225
|
}
|
|
186
226
|
}
|
|
187
|
-
for (const extraDir of extraDirs) if (existsSync(extraDir))
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
227
|
+
for (const extraDir of extraDirs) if (existsSync(extraDir)) {
|
|
228
|
+
const discovered = discoverSkills(extraDir, "global");
|
|
229
|
+
diagnostics.push(...discovered.diagnostics);
|
|
230
|
+
for (const skill of discovered.skills) {
|
|
231
|
+
const existing = skillMap.get(skill.name);
|
|
232
|
+
if (existing) diagnostics.push({
|
|
233
|
+
type: "collision",
|
|
234
|
+
skillName: skill.name,
|
|
235
|
+
message: `Skill "${skill.name}" collision: ${existing.source} overrides ${skill.source}`,
|
|
236
|
+
path: skill.filePath
|
|
237
|
+
});
|
|
238
|
+
else skillMap.set(skill.name, skill);
|
|
239
|
+
}
|
|
196
240
|
}
|
|
197
241
|
const skillsConfig = createSkillConfigManager(resolveStateDir()).load();
|
|
198
242
|
const merged = Array.from(skillMap.values());
|