crewly 1.0.7 → 1.0.10
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/LICENSE +1 -1
- package/README.md +50 -3
- package/config/constants.ts +59 -0
- package/config/index.ts +2 -0
- package/config/roles/architect/prompt.md +17 -5
- package/config/roles/backend-developer/prompt.md +35 -5
- package/config/roles/designer/prompt.md +17 -5
- package/config/roles/developer/prompt.md +43 -9
- package/config/roles/frontend-developer/prompt.md +35 -5
- package/config/roles/fullstack-dev/prompt.md +35 -5
- package/config/roles/generalist/prompt.md +18 -5
- package/config/roles/orchestrator/prompt.md +126 -3
- package/config/roles/product-manager/prompt.md +24 -9
- package/config/roles/qa/prompt.md +35 -5
- package/config/roles/qa-engineer/prompt.md +35 -5
- package/config/roles/sales/prompt.md +17 -5
- package/config/roles/support/prompt.md +17 -5
- package/config/roles/tpm/prompt.md +17 -5
- package/config/skills/agent/_common/lib.sh +4 -0
- package/config/skills/agent/core/accept-task/execute.sh +21 -0
- package/config/skills/agent/core/accept-task/instructions.md +20 -0
- package/config/skills/agent/core/accept-task/skill.json +20 -0
- package/config/skills/agent/core/block-task/execute.sh +26 -0
- package/config/skills/agent/core/block-task/instructions.md +22 -0
- package/config/skills/agent/core/block-task/skill.json +20 -0
- package/config/skills/agent/core/check-quality-gates/execute.sh +20 -0
- package/config/skills/agent/core/check-quality-gates/instructions.md +23 -0
- package/config/skills/agent/core/check-quality-gates/skill.json +20 -0
- package/config/skills/agent/core/complete-task/execute.sh +29 -0
- package/config/skills/agent/core/complete-task/instructions.md +53 -0
- package/config/skills/agent/core/complete-task/skill.json +20 -0
- package/config/skills/agent/core/get-my-context/execute.sh +23 -0
- package/config/skills/agent/core/get-my-context/instructions.md +21 -0
- package/config/skills/agent/core/get-my-context/skill.json +20 -0
- package/config/skills/agent/core/get-sops/execute.sh +24 -0
- package/config/skills/agent/core/get-sops/instructions.md +21 -0
- package/config/skills/agent/core/get-sops/skill.json +20 -0
- package/config/skills/agent/core/get-team-status/execute.sh +8 -0
- package/config/skills/agent/core/get-team-status/instructions.md +17 -0
- package/config/skills/agent/core/get-team-status/skill.json +20 -0
- package/config/skills/agent/core/heartbeat/execute.sh +22 -0
- package/config/skills/agent/core/heartbeat/instructions.md +23 -0
- package/config/skills/agent/core/heartbeat/skill.json +20 -0
- package/config/skills/agent/core/manage-knowledge/execute.sh +60 -0
- package/config/skills/agent/core/manage-knowledge/instructions.md +46 -0
- package/config/skills/agent/core/marketplace-search/execute.sh +77 -0
- package/config/skills/agent/core/marketplace-search/instructions.md +59 -0
- package/config/skills/agent/core/marketplace-search/skill.json +20 -0
- package/config/skills/agent/core/query-knowledge/execute.sh +30 -0
- package/config/skills/agent/core/query-knowledge/instructions.md +47 -0
- package/config/skills/agent/core/query-knowledge/skill.json +20 -0
- package/config/skills/agent/core/read-task/execute.sh +15 -0
- package/config/skills/agent/core/read-task/instructions.md +19 -0
- package/config/skills/agent/core/read-task/skill.json +20 -0
- package/config/skills/agent/core/recall/execute.sh +24 -0
- package/config/skills/agent/core/recall/instructions.md +23 -0
- package/config/skills/agent/core/recall/skill.json +20 -0
- package/config/skills/agent/core/record-learning/execute.sh +29 -0
- package/config/skills/agent/core/record-learning/instructions.md +24 -0
- package/config/skills/agent/core/record-learning/skill.json +20 -0
- package/config/skills/agent/core/register-self/execute.sh +28 -0
- package/config/skills/agent/core/register-self/instructions.md +18 -0
- package/config/skills/agent/core/register-self/skill.json +20 -0
- package/config/skills/agent/core/remember/execute.sh +29 -0
- package/config/skills/agent/core/remember/instructions.md +24 -0
- package/config/skills/agent/core/remember/skill.json +20 -0
- package/config/skills/agent/core/report-progress/execute.sh +28 -0
- package/config/skills/agent/core/report-progress/instructions.md +25 -0
- package/config/skills/agent/core/report-progress/skill.json +20 -0
- package/config/skills/agent/core/report-status/execute.sh +35 -0
- package/config/skills/agent/core/report-status/instructions.md +36 -0
- package/config/skills/agent/core/report-status/skill.json +20 -0
- package/config/skills/agent/core/send-chat-response/execute.sh +26 -0
- package/config/skills/agent/core/send-chat-response/instructions.md +22 -0
- package/config/skills/agent/core/send-chat-response/skill.json +20 -0
- package/config/skills/agent/core/send-message/execute.sh +17 -0
- package/config/skills/agent/core/send-message/instructions.md +20 -0
- package/config/skills/agent/core/send-message/skill.json +20 -0
- package/config/skills/orchestrator/complete-task/execute.sh +1 -0
- package/config/skills/orchestrator/delegate-task/execute.sh +1 -1
- package/config/skills/registry.json +850 -0
- package/config/templates/agent-claude-md.md +16 -0
- package/config/templates/research-team.json +22 -0
- package/config/templates/startup-team.json +22 -0
- package/config/templates/web-dev-team.json +22 -0
- package/dist/backend/backend/src/constants.d.ts +127 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +119 -8
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/index.d.ts +1 -1
- package/dist/backend/backend/src/controllers/marketplace/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/index.js +1 -1
- package/dist/backend/backend/src/controllers/marketplace/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.d.ts +64 -8
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js +194 -96
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js +7 -2
- package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +7 -0
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +174 -4
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +34 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.js +2 -0
- package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +8 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +89 -17
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts +265 -0
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +811 -0
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.js +11 -4
- package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts +11 -0
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js +18 -0
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +12 -0
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +51 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.d.ts +6 -0
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.d.ts.map +1 -1
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.js +10 -0
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.js.map +1 -1
- package/dist/backend/backend/src/services/index.d.ts +3 -0
- package/dist/backend/backend/src/services/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/index.js +5 -0
- package/dist/backend/backend/src/services/index.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/index.d.ts +1 -0
- package/dist/backend/backend/src/services/marketplace/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/index.js +2 -0
- package/dist/backend/backend/src/services/marketplace/index.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.d.ts +10 -9
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js +262 -73
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-submission.service.d.ts +71 -0
- package/dist/backend/backend/src/services/marketplace/marketplace-submission.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/marketplace/marketplace-submission.service.js +339 -0
- package/dist/backend/backend/src/services/marketplace/marketplace-submission.service.js.map +1 -0
- package/dist/backend/backend/src/services/marketplace/marketplace.service.d.ts +4 -15
- package/dist/backend/backend/src/services/marketplace/marketplace.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace.service.js +172 -27
- package/dist/backend/backend/src/services/marketplace/marketplace.service.js.map +1 -1
- package/dist/backend/backend/src/services/mcp-client.d.ts +233 -0
- package/dist/backend/backend/src/services/mcp-client.d.ts.map +1 -0
- package/dist/backend/backend/src/services/mcp-client.js +297 -0
- package/dist/backend/backend/src/services/mcp-client.js.map +1 -0
- package/dist/backend/backend/src/services/mcp-server.d.ts +167 -0
- package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -0
- package/dist/backend/backend/src/services/mcp-server.js +586 -0
- package/dist/backend/backend/src/services/mcp-server.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts +32 -2
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.js +85 -4
- package/dist/backend/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts +10 -0
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +129 -41
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js +31 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -1
- package/dist/backend/backend/src/services/quality/index.d.ts +1 -0
- package/dist/backend/backend/src/services/quality/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/quality/index.js +1 -0
- package/dist/backend/backend/src/services/quality/index.js.map +1 -1
- package/dist/backend/backend/src/services/quality/task-output-validator.service.d.ts +84 -0
- package/dist/backend/backend/src/services/quality/task-output-validator.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/quality/task-output-validator.service.js +163 -0
- package/dist/backend/backend/src/services/quality/task-output-validator.service.js.map +1 -0
- package/dist/backend/backend/src/services/runtime-adapter.d.ts +254 -0
- package/dist/backend/backend/src/services/runtime-adapter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-adapter.js +201 -0
- package/dist/backend/backend/src/services/runtime-adapter.js.map +1 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts +19 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +31 -2
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-backend.interface.d.ts +14 -0
- package/dist/backend/backend/src/services/session/session-backend.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-backend.interface.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts +9 -0
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.js +24 -1
- package/dist/backend/backend/src/services/session/session-command-helper.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-catalog.service.d.ts +7 -13
- package/dist/backend/backend/src/services/skill/skill-catalog.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-catalog.service.js +38 -47
- package/dist/backend/backend/src/services/skill/skill-catalog.service.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill.service.d.ts +3 -0
- package/dist/backend/backend/src/services/skill/skill.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill.service.js +17 -0
- package/dist/backend/backend/src/services/skill/skill.service.js.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts +2 -2
- package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.js +2 -0
- package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +1 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js +2 -0
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/marketplace.types.d.ts +37 -0
- package/dist/backend/backend/src/types/marketplace.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/messaging.types.d.ts +9 -6
- package/dist/backend/backend/src/types/messaging.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/messaging.types.js +10 -3
- package/dist/backend/backend/src/types/messaging.types.js.map +1 -1
- package/dist/backend/backend/src/types/task-output.types.d.ts +78 -0
- package/dist/backend/backend/src/types/task-output.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/task-output.types.js +27 -0
- package/dist/backend/backend/src/types/task-output.types.js.map +1 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +13 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.js +12 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
- package/dist/backend/config/constants.d.ts +41 -0
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +57 -0
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/backend/config/index.d.ts +2 -2
- package/dist/backend/config/index.d.ts.map +1 -1
- package/dist/backend/config/index.js +2 -2
- package/dist/backend/config/index.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +817 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -0
- package/dist/cli/backend/src/constants.js +603 -0
- package/dist/cli/backend/src/constants.js.map +1 -0
- package/dist/cli/backend/src/models/Project.d.ts +18 -0
- package/dist/cli/backend/src/models/Project.d.ts.map +1 -0
- package/dist/cli/backend/src/models/Project.js +70 -0
- package/dist/cli/backend/src/models/Project.js.map +1 -0
- package/dist/cli/backend/src/models/ScheduledMessage.d.ts +27 -0
- package/dist/cli/backend/src/models/ScheduledMessage.d.ts.map +1 -0
- package/dist/cli/backend/src/models/ScheduledMessage.js +50 -0
- package/dist/cli/backend/src/models/ScheduledMessage.js.map +1 -0
- package/dist/cli/backend/src/models/Team.d.ts +20 -0
- package/dist/cli/backend/src/models/Team.d.ts.map +1 -0
- package/dist/cli/backend/src/models/Team.js +120 -0
- package/dist/cli/backend/src/models/Team.js.map +1 -0
- package/dist/cli/backend/src/models/Ticket.d.ts +24 -0
- package/dist/cli/backend/src/models/Ticket.d.ts.map +1 -0
- package/dist/cli/backend/src/models/Ticket.js +102 -0
- package/dist/cli/backend/src/models/Ticket.js.map +1 -0
- package/dist/cli/backend/src/models/index.d.ts +5 -0
- package/dist/cli/backend/src/models/index.d.ts.map +1 -0
- package/dist/cli/backend/src/models/index.js +5 -0
- package/dist/cli/backend/src/models/index.js.map +1 -0
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.d.ts +40 -0
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.d.ts.map +1 -0
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.js +74 -0
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.js.map +1 -0
- package/dist/cli/backend/src/services/core/config.service.d.ts +91 -0
- package/dist/cli/backend/src/services/core/config.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/core/config.service.js +246 -0
- package/dist/cli/backend/src/services/core/config.service.js.map +1 -0
- package/dist/cli/backend/src/services/core/logger.service.d.ts +70 -0
- package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/core/logger.service.js +350 -0
- package/dist/cli/backend/src/services/core/logger.service.js.map +1 -0
- package/dist/cli/backend/src/services/core/storage.service.d.ts +269 -0
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/core/storage.service.js +1406 -0
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -0
- package/dist/cli/backend/src/services/core/teams-backup.service.d.ts +92 -0
- package/dist/cli/backend/src/services/core/teams-backup.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/core/teams-backup.service.js +120 -0
- package/dist/cli/backend/src/services/core/teams-backup.service.js.map +1 -0
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts +125 -0
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +247 -0
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -0
- package/dist/cli/backend/src/services/knowledge/knowledge.service.d.ts +153 -0
- package/dist/cli/backend/src/services/knowledge/knowledge.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/knowledge/knowledge.service.js +409 -0
- package/dist/cli/backend/src/services/knowledge/knowledge.service.js.map +1 -0
- package/dist/cli/backend/src/services/mcp-server.d.ts +167 -0
- package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -0
- package/dist/cli/backend/src/services/mcp-server.js +586 -0
- package/dist/cli/backend/src/services/mcp-server.js.map +1 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts +259 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.js +539 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.js.map +1 -0
- package/dist/cli/backend/src/services/memory/memory.service.d.ts +306 -0
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/memory.service.js +517 -0
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -0
- package/dist/cli/backend/src/services/memory/project-memory.service.d.ts +252 -0
- package/dist/cli/backend/src/services/memory/project-memory.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/project-memory.service.js +600 -0
- package/dist/cli/backend/src/services/memory/project-memory.service.js.map +1 -0
- package/dist/cli/backend/src/types/auto-assign.types.d.ts +271 -0
- package/dist/cli/backend/src/types/auto-assign.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/auto-assign.types.js +136 -0
- package/dist/cli/backend/src/types/auto-assign.types.js.map +1 -0
- package/dist/cli/backend/src/types/budget.types.d.ts +217 -0
- package/dist/cli/backend/src/types/budget.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/budget.types.js +82 -0
- package/dist/cli/backend/src/types/budget.types.js.map +1 -0
- package/dist/cli/backend/src/types/chat.types.d.ts +550 -0
- package/dist/cli/backend/src/types/chat.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/chat.types.js +743 -0
- package/dist/cli/backend/src/types/chat.types.js.map +1 -0
- package/dist/cli/backend/src/types/continuation.types.d.ts +237 -0
- package/dist/cli/backend/src/types/continuation.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/continuation.types.js +10 -0
- package/dist/cli/backend/src/types/continuation.types.js.map +1 -0
- package/dist/cli/backend/src/types/index.d.ts +164 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -0
- package/dist/cli/backend/src/types/index.js +25 -0
- package/dist/cli/backend/src/types/index.js.map +1 -0
- package/dist/cli/backend/src/types/knowledge.types.d.ts +195 -0
- package/dist/cli/backend/src/types/knowledge.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/knowledge.types.js +38 -0
- package/dist/cli/backend/src/types/knowledge.types.js.map +1 -0
- package/dist/cli/backend/src/types/memory.types.d.ts +587 -0
- package/dist/cli/backend/src/types/memory.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/memory.types.js +47 -0
- package/dist/cli/backend/src/types/memory.types.js.map +1 -0
- package/dist/cli/backend/src/types/quality-gate.types.d.ts +171 -0
- package/dist/cli/backend/src/types/quality-gate.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/quality-gate.types.js +42 -0
- package/dist/cli/backend/src/types/quality-gate.types.js.map +1 -0
- package/dist/cli/backend/src/types/role.types.d.ts +260 -0
- package/dist/cli/backend/src/types/role.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/role.types.js +238 -0
- package/dist/cli/backend/src/types/role.types.js.map +1 -0
- package/dist/cli/backend/src/types/scheduler.types.d.ts +254 -0
- package/dist/cli/backend/src/types/scheduler.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/scheduler.types.js +32 -0
- package/dist/cli/backend/src/types/scheduler.types.js.map +1 -0
- package/dist/cli/backend/src/types/settings.types.d.ts +178 -0
- package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/settings.types.js +206 -0
- package/dist/cli/backend/src/types/settings.types.js.map +1 -0
- package/dist/cli/backend/src/types/skill.types.d.ts +515 -0
- package/dist/cli/backend/src/types/skill.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/skill.types.js +481 -0
- package/dist/cli/backend/src/types/skill.types.js.map +1 -0
- package/dist/cli/backend/src/types/sop.types.d.ts +224 -0
- package/dist/cli/backend/src/types/sop.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/sop.types.js +85 -0
- package/dist/cli/backend/src/types/sop.types.js.map +1 -0
- package/dist/cli/backend/src/types/task-output.types.d.ts +78 -0
- package/dist/cli/backend/src/types/task-output.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/task-output.types.js +27 -0
- package/dist/cli/backend/src/types/task-output.types.js.map +1 -0
- package/dist/cli/backend/src/utils/file-io.utils.d.ts +102 -0
- package/dist/cli/backend/src/utils/file-io.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/file-io.utils.js +214 -0
- package/dist/cli/backend/src/utils/file-io.utils.js.map +1 -0
- package/dist/cli/backend/src/utils/terminal-output.utils.d.ts +54 -0
- package/dist/cli/backend/src/utils/terminal-output.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/terminal-output.utils.js +97 -0
- package/dist/cli/backend/src/utils/terminal-output.utils.js.map +1 -0
- package/dist/cli/cli/src/commands/mcp-server.d.ts +38 -0
- package/dist/cli/cli/src/commands/mcp-server.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/mcp-server.js +49 -0
- package/dist/cli/cli/src/commands/mcp-server.js.map +1 -0
- package/dist/cli/cli/src/commands/onboard.d.ts +72 -8
- package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/onboard.js +306 -33
- package/dist/cli/cli/src/commands/onboard.js.map +1 -1
- package/dist/cli/cli/src/commands/publish.d.ts +35 -0
- package/dist/cli/cli/src/commands/publish.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/publish.js +93 -0
- package/dist/cli/cli/src/commands/publish.js.map +1 -0
- package/dist/cli/cli/src/commands/seed-marketplace.d.ts +28 -0
- package/dist/cli/cli/src/commands/seed-marketplace.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/seed-marketplace.js +148 -0
- package/dist/cli/cli/src/commands/seed-marketplace.js.map +1 -0
- package/dist/cli/cli/src/index.js +23 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/cli/src/utils/archive-creator.d.ts +82 -0
- package/dist/cli/cli/src/utils/archive-creator.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/archive-creator.js +105 -0
- package/dist/cli/cli/src/utils/archive-creator.js.map +1 -0
- package/dist/cli/cli/src/utils/marketplace.d.ts +17 -4
- package/dist/cli/cli/src/utils/marketplace.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/marketplace.js +172 -58
- package/dist/cli/cli/src/utils/marketplace.js.map +1 -1
- package/dist/cli/cli/src/utils/package-validator.d.ts +62 -0
- package/dist/cli/cli/src/utils/package-validator.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/package-validator.js +122 -0
- package/dist/cli/cli/src/utils/package-validator.js.map +1 -0
- package/dist/cli/cli/src/utils/templates.d.ts +71 -0
- package/dist/cli/cli/src/utils/templates.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/templates.js +91 -0
- package/dist/cli/cli/src/utils/templates.js.map +1 -0
- package/dist/cli/config/constants.d.ts +41 -0
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +57 -0
- package/dist/cli/config/constants.js.map +1 -1
- package/dist/cli/config/index.d.ts +2 -2
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +2 -2
- package/dist/cli/config/index.js.map +1 -1
- package/frontend/dist/assets/{index-523c7fce.js → index-0a245b0d.js} +247 -247
- package/frontend/dist/assets/{index-4c050f52.css → index-6972eeee.css} +1 -1
- package/frontend/dist/assets/nunito-cyrillic-400-normal-e44e669f.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-400-normal-ff8e8bdd.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-500-normal-2159679b.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-500-normal-61a3b80e.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-600-normal-ac046097.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-600-normal-e61eb97b.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-700-normal-8fcefcc9.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-700-normal-b9684104.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-800-normal-40253beb.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-800-normal-d80292de.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-400-normal-20d73ae7.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-400-normal-d48c37c9.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-500-normal-16197abd.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-500-normal-9dcfe9b5.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-600-normal-d53e9851.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-600-normal-e3d0201f.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-700-normal-5936f6ac.woff2 +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-700-normal-c8c02775.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-800-normal-217b8f51.woff +0 -0
- package/frontend/dist/assets/nunito-cyrillic-ext-800-normal-796cf7bd.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-400-normal-a5906e15.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-400-normal-b51e7635.woff +0 -0
- package/frontend/dist/assets/nunito-latin-500-normal-23ae3083.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-500-normal-be14dbc6.woff +0 -0
- package/frontend/dist/assets/nunito-latin-600-normal-06a9c8b3.woff +0 -0
- package/frontend/dist/assets/nunito-latin-600-normal-45f437de.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-700-normal-ce9107dc.woff +0 -0
- package/frontend/dist/assets/nunito-latin-700-normal-fa89300b.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-800-normal-0ca02785.woff +0 -0
- package/frontend/dist/assets/nunito-latin-800-normal-2363d3ed.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-ext-400-normal-67250a41.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-ext-400-normal-d7e2415e.woff +0 -0
- package/frontend/dist/assets/nunito-latin-ext-500-normal-06f35d1c.woff +0 -0
- package/frontend/dist/assets/nunito-latin-ext-500-normal-343e7adc.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-ext-600-normal-5a8efd17.woff +0 -0
- package/frontend/dist/assets/nunito-latin-ext-600-normal-a7ba5f4f.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-ext-700-normal-0a4e4a02.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-ext-700-normal-0c607961.woff +0 -0
- package/frontend/dist/assets/nunito-latin-ext-800-normal-39f54b55.woff2 +0 -0
- package/frontend/dist/assets/nunito-latin-ext-800-normal-466d0211.woff +0 -0
- package/frontend/dist/assets/nunito-vietnamese-400-normal-2a755616.woff2 +0 -0
- package/frontend/dist/assets/nunito-vietnamese-400-normal-9c01ea9f.woff +0 -0
- package/frontend/dist/assets/nunito-vietnamese-500-normal-452e5e08.woff +0 -0
- package/frontend/dist/assets/nunito-vietnamese-500-normal-dc98d965.woff2 +0 -0
- package/frontend/dist/assets/nunito-vietnamese-600-normal-2ffbb85f.woff +0 -0
- package/frontend/dist/assets/nunito-vietnamese-600-normal-cf95b95d.woff2 +0 -0
- package/frontend/dist/assets/nunito-vietnamese-700-normal-0e29c28c.woff2 +0 -0
- package/frontend/dist/assets/nunito-vietnamese-700-normal-7793b75e.woff +0 -0
- package/frontend/dist/assets/nunito-vietnamese-800-normal-5baf507e.woff +0 -0
- package/frontend/dist/assets/nunito-vietnamese-800-normal-fac6740e.woff2 +0 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +16 -6
- package/config/skills/chrome-browser/instructions.md +0 -42
- package/config/skills/chrome-browser/skill.json +0 -39
- package/config/skills/nano-banana-image/generate.sh +0 -73
- package/config/skills/nano-banana-image/instructions.md +0 -50
- package/config/skills/nano-banana-image/skill.json +0 -39
- package/config/skills/playwright-chrome-browser/instructions.md +0 -95
- package/config/skills/playwright-chrome-browser/skill.json +0 -44
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marketplace Submission Service
|
|
3
|
+
*
|
|
4
|
+
* Handles skill submissions to the marketplace, including validation,
|
|
5
|
+
* archive storage, and review workflow management.
|
|
6
|
+
*
|
|
7
|
+
* Submissions are stored locally in ~/.crewly/marketplace/submissions/
|
|
8
|
+
* with a manifest.json tracking all submissions and their status.
|
|
9
|
+
*
|
|
10
|
+
* @module services/marketplace/marketplace-submission.service
|
|
11
|
+
*/
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
import { mkdir, readFile, writeFile, copyFile, rm } from 'fs/promises';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
16
|
+
import { createHash, randomUUID } from 'crypto';
|
|
17
|
+
import * as tar from 'tar';
|
|
18
|
+
import { MARKETPLACE_CONSTANTS } from '../../constants.js';
|
|
19
|
+
const MARKETPLACE_DIR = path.join(homedir(), '.crewly', MARKETPLACE_CONSTANTS.DIR_NAME);
|
|
20
|
+
const SUBMISSIONS_DIR = path.join(MARKETPLACE_DIR, MARKETPLACE_CONSTANTS.SUBMISSIONS_DIR);
|
|
21
|
+
const SUBMISSIONS_MANIFEST_PATH = path.join(SUBMISSIONS_DIR, 'manifest.json');
|
|
22
|
+
/** Kebab-case pattern for skill IDs */
|
|
23
|
+
const KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
24
|
+
/** Semver pattern (major.minor.patch) */
|
|
25
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+$/;
|
|
26
|
+
/**
|
|
27
|
+
* Loads the submissions manifest from disk.
|
|
28
|
+
*
|
|
29
|
+
* Returns an empty manifest if the file does not exist or is unparsable.
|
|
30
|
+
*
|
|
31
|
+
* @returns The submissions manifest
|
|
32
|
+
*/
|
|
33
|
+
export async function loadSubmissionsManifest() {
|
|
34
|
+
try {
|
|
35
|
+
const data = await readFile(SUBMISSIONS_MANIFEST_PATH, 'utf-8');
|
|
36
|
+
return JSON.parse(data);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return { schemaVersion: 1, submissions: [] };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Saves the submissions manifest to disk.
|
|
44
|
+
*
|
|
45
|
+
* Creates the submissions directory if it does not exist.
|
|
46
|
+
*
|
|
47
|
+
* @param manifest - The manifest to persist
|
|
48
|
+
*/
|
|
49
|
+
export async function saveSubmissionsManifest(manifest) {
|
|
50
|
+
await mkdir(SUBMISSIONS_DIR, { recursive: true });
|
|
51
|
+
await writeFile(SUBMISSIONS_MANIFEST_PATH, JSON.stringify(manifest, null, 2) + '\n');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validates a skill.json manifest from a submitted archive.
|
|
55
|
+
*
|
|
56
|
+
* @param manifest - Parsed skill.json content
|
|
57
|
+
* @returns Array of validation error messages (empty if valid)
|
|
58
|
+
*/
|
|
59
|
+
function validateSkillManifest(manifest) {
|
|
60
|
+
const errors = [];
|
|
61
|
+
if (!manifest.id || typeof manifest.id !== 'string') {
|
|
62
|
+
errors.push('skill.json missing required field: id');
|
|
63
|
+
}
|
|
64
|
+
else if (!KEBAB_CASE_RE.test(manifest.id)) {
|
|
65
|
+
errors.push(`skill.json id must be kebab-case: "${manifest.id}"`);
|
|
66
|
+
}
|
|
67
|
+
if (!manifest.name || typeof manifest.name !== 'string') {
|
|
68
|
+
errors.push('skill.json missing required field: name');
|
|
69
|
+
}
|
|
70
|
+
if (!manifest.description || typeof manifest.description !== 'string') {
|
|
71
|
+
errors.push('skill.json missing required field: description');
|
|
72
|
+
}
|
|
73
|
+
if (!manifest.version || typeof manifest.version !== 'string') {
|
|
74
|
+
errors.push('skill.json missing required field: version');
|
|
75
|
+
}
|
|
76
|
+
else if (!SEMVER_RE.test(manifest.version)) {
|
|
77
|
+
errors.push(`skill.json version must be semver (x.y.z): "${manifest.version}"`);
|
|
78
|
+
}
|
|
79
|
+
if (!manifest.category || typeof manifest.category !== 'string') {
|
|
80
|
+
errors.push('skill.json missing required field: category');
|
|
81
|
+
}
|
|
82
|
+
if (!Array.isArray(manifest.assignableRoles) || manifest.assignableRoles.length === 0) {
|
|
83
|
+
errors.push('skill.json must have a non-empty assignableRoles array');
|
|
84
|
+
}
|
|
85
|
+
if (!Array.isArray(manifest.tags) || manifest.tags.length === 0) {
|
|
86
|
+
errors.push('skill.json must have a non-empty tags array');
|
|
87
|
+
}
|
|
88
|
+
return errors;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Submits a skill package (tar.gz archive) to the marketplace for review.
|
|
92
|
+
*
|
|
93
|
+
* Performs the following steps:
|
|
94
|
+
* 1. Verifies the archive exists and is a tar.gz
|
|
95
|
+
* 2. Extracts and validates skill.json from the archive
|
|
96
|
+
* 3. Checks for duplicate submissions
|
|
97
|
+
* 4. Stores the archive in the submissions directory
|
|
98
|
+
* 5. Creates a submission record in the manifest
|
|
99
|
+
*
|
|
100
|
+
* @param archivePath - Path to the tar.gz archive to submit
|
|
101
|
+
* @returns Operation result with the submission record
|
|
102
|
+
*/
|
|
103
|
+
export async function submitSkill(archivePath) {
|
|
104
|
+
try {
|
|
105
|
+
if (!existsSync(archivePath)) {
|
|
106
|
+
return { success: false, message: `Archive not found: ${archivePath}` };
|
|
107
|
+
}
|
|
108
|
+
if (!archivePath.endsWith('.tar.gz')) {
|
|
109
|
+
return { success: false, message: 'Archive must be a .tar.gz file' };
|
|
110
|
+
}
|
|
111
|
+
// Extract skill.json first, then read archive for checksum (avoids reading file twice)
|
|
112
|
+
let skillManifest;
|
|
113
|
+
try {
|
|
114
|
+
skillManifest = await extractSkillJson(archivePath);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
118
|
+
return { success: false, message: `Invalid skill archive: ${msg}` };
|
|
119
|
+
}
|
|
120
|
+
// Compute checksum
|
|
121
|
+
const archiveData = await readFile(archivePath);
|
|
122
|
+
const hash = createHash('sha256').update(archiveData).digest('hex');
|
|
123
|
+
const checksum = `sha256:${hash}`;
|
|
124
|
+
// Validate skill.json
|
|
125
|
+
const validationErrors = validateSkillManifest(skillManifest);
|
|
126
|
+
if (validationErrors.length > 0) {
|
|
127
|
+
return { success: false, message: `Validation failed: ${validationErrors.join('; ')}` };
|
|
128
|
+
}
|
|
129
|
+
const skillId = skillManifest.id;
|
|
130
|
+
// Check for duplicate submissions
|
|
131
|
+
const manifest = await loadSubmissionsManifest();
|
|
132
|
+
const existing = manifest.submissions.find((s) => s.skillId === skillId && s.status === 'pending');
|
|
133
|
+
if (existing) {
|
|
134
|
+
return { success: false, message: `Skill "${skillId}" already has a pending submission` };
|
|
135
|
+
}
|
|
136
|
+
// Store the archive
|
|
137
|
+
await mkdir(SUBMISSIONS_DIR, { recursive: true });
|
|
138
|
+
const storedArchiveName = `${skillId}-${skillManifest.version}.tar.gz`;
|
|
139
|
+
const storedArchivePath = path.join(SUBMISSIONS_DIR, storedArchiveName);
|
|
140
|
+
await copyFile(archivePath, storedArchivePath);
|
|
141
|
+
// Create submission record
|
|
142
|
+
const submission = {
|
|
143
|
+
id: randomUUID(),
|
|
144
|
+
skillId,
|
|
145
|
+
name: skillManifest.name,
|
|
146
|
+
description: skillManifest.description,
|
|
147
|
+
author: skillManifest.author || 'Community',
|
|
148
|
+
version: skillManifest.version,
|
|
149
|
+
category: skillManifest.category,
|
|
150
|
+
tags: skillManifest.tags,
|
|
151
|
+
license: skillManifest.license || 'MIT',
|
|
152
|
+
status: 'pending',
|
|
153
|
+
archivePath: storedArchivePath,
|
|
154
|
+
checksum,
|
|
155
|
+
sizeBytes: archiveData.length,
|
|
156
|
+
metadata: {
|
|
157
|
+
assignableRoles: skillManifest.assignableRoles,
|
|
158
|
+
triggers: skillManifest.triggers || [],
|
|
159
|
+
},
|
|
160
|
+
submittedAt: new Date().toISOString(),
|
|
161
|
+
};
|
|
162
|
+
manifest.submissions.push(submission);
|
|
163
|
+
await saveSubmissionsManifest(manifest);
|
|
164
|
+
return {
|
|
165
|
+
success: true,
|
|
166
|
+
message: `Skill "${submission.name}" submitted for review`,
|
|
167
|
+
submission,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
172
|
+
return { success: false, message: `Submission failed: ${msg}` };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Lists all submissions, optionally filtered by status.
|
|
177
|
+
*
|
|
178
|
+
* @param status - Optional status filter
|
|
179
|
+
* @returns Array of submissions
|
|
180
|
+
*/
|
|
181
|
+
export async function listSubmissions(status) {
|
|
182
|
+
const manifest = await loadSubmissionsManifest();
|
|
183
|
+
if (status) {
|
|
184
|
+
return manifest.submissions.filter((s) => s.status === status);
|
|
185
|
+
}
|
|
186
|
+
return manifest.submissions;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Gets a single submission by ID.
|
|
190
|
+
*
|
|
191
|
+
* @param id - Submission ID
|
|
192
|
+
* @returns The submission, or null if not found
|
|
193
|
+
*/
|
|
194
|
+
export async function getSubmission(id) {
|
|
195
|
+
const manifest = await loadSubmissionsManifest();
|
|
196
|
+
return manifest.submissions.find((s) => s.id === id) || null;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Reviews a submission — approving or rejecting it.
|
|
200
|
+
*
|
|
201
|
+
* When approved, the skill is added to the local registry and becomes
|
|
202
|
+
* available for installation. When rejected, the archive is removed.
|
|
203
|
+
*
|
|
204
|
+
* @param id - Submission ID
|
|
205
|
+
* @param action - 'approve' or 'reject'
|
|
206
|
+
* @param notes - Optional review notes
|
|
207
|
+
* @returns Operation result
|
|
208
|
+
*/
|
|
209
|
+
export async function reviewSubmission(id, action, notes) {
|
|
210
|
+
const manifest = await loadSubmissionsManifest();
|
|
211
|
+
const submission = manifest.submissions.find((s) => s.id === id);
|
|
212
|
+
if (!submission) {
|
|
213
|
+
return { success: false, message: `Submission not found: ${id}` };
|
|
214
|
+
}
|
|
215
|
+
if (submission.status !== 'pending') {
|
|
216
|
+
return { success: false, message: `Submission already ${submission.status}` };
|
|
217
|
+
}
|
|
218
|
+
const newStatus = action === 'approve' ? 'approved' : 'rejected';
|
|
219
|
+
submission.status = newStatus;
|
|
220
|
+
submission.reviewedAt = new Date().toISOString();
|
|
221
|
+
submission.reviewNotes = notes;
|
|
222
|
+
if (action === 'approve') {
|
|
223
|
+
// Add to local registry by creating the item in the assets directory
|
|
224
|
+
const assetsDir = path.join(MARKETPLACE_DIR, 'assets', 'skills', submission.skillId);
|
|
225
|
+
await mkdir(assetsDir, { recursive: true });
|
|
226
|
+
const assetArchiveName = `${submission.skillId}-${submission.version}.tar.gz`;
|
|
227
|
+
const assetPath = path.join(assetsDir, assetArchiveName);
|
|
228
|
+
if (existsSync(submission.archivePath)) {
|
|
229
|
+
await copyFile(submission.archivePath, assetPath);
|
|
230
|
+
}
|
|
231
|
+
// Add to local registry file
|
|
232
|
+
await addToLocalRegistry(submission, assetArchiveName);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Remove archive for rejected submissions
|
|
236
|
+
if (existsSync(submission.archivePath)) {
|
|
237
|
+
await rm(submission.archivePath, { force: true });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
await saveSubmissionsManifest(manifest);
|
|
241
|
+
return {
|
|
242
|
+
success: true,
|
|
243
|
+
message: action === 'approve'
|
|
244
|
+
? `Approved "${submission.name}" — now available in marketplace`
|
|
245
|
+
: `Rejected "${submission.name}"`,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Adds an approved submission to the local registry file.
|
|
250
|
+
*
|
|
251
|
+
* The local registry augments the remote registry so that locally
|
|
252
|
+
* published skills appear in the marketplace alongside remote ones.
|
|
253
|
+
*
|
|
254
|
+
* @param submission - The approved submission
|
|
255
|
+
* @param archiveFilename - Name of the archive file in assets/
|
|
256
|
+
*/
|
|
257
|
+
async function addToLocalRegistry(submission, archiveFilename) {
|
|
258
|
+
const localRegistryPath = path.join(MARKETPLACE_DIR, MARKETPLACE_CONSTANTS.LOCAL_REGISTRY_FILE);
|
|
259
|
+
let registry;
|
|
260
|
+
try {
|
|
261
|
+
const data = await readFile(localRegistryPath, 'utf-8');
|
|
262
|
+
registry = JSON.parse(data);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
registry = { items: [] };
|
|
266
|
+
}
|
|
267
|
+
// Remove any existing entry for this skill
|
|
268
|
+
registry.items = registry.items.filter((i) => i.id !== submission.skillId);
|
|
269
|
+
// Add the new entry
|
|
270
|
+
const item = {
|
|
271
|
+
id: submission.skillId,
|
|
272
|
+
type: 'skill',
|
|
273
|
+
name: submission.name,
|
|
274
|
+
description: submission.description,
|
|
275
|
+
author: submission.author,
|
|
276
|
+
version: submission.version,
|
|
277
|
+
category: submission.category,
|
|
278
|
+
tags: submission.tags,
|
|
279
|
+
license: submission.license,
|
|
280
|
+
downloads: 0,
|
|
281
|
+
rating: 0,
|
|
282
|
+
createdAt: submission.submittedAt,
|
|
283
|
+
updatedAt: submission.reviewedAt || submission.submittedAt,
|
|
284
|
+
assets: {
|
|
285
|
+
archive: `skills/${submission.skillId}/${archiveFilename}`,
|
|
286
|
+
checksum: submission.checksum,
|
|
287
|
+
sizeBytes: submission.sizeBytes,
|
|
288
|
+
},
|
|
289
|
+
metadata: submission.metadata,
|
|
290
|
+
};
|
|
291
|
+
registry.items.push(item);
|
|
292
|
+
await writeFile(localRegistryPath, JSON.stringify(registry, null, 2) + '\n');
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Extracts and parses skill.json from a tar.gz archive.
|
|
296
|
+
*
|
|
297
|
+
* Handles archives with various prefix structures (skill-id/skill.json,
|
|
298
|
+
* skill-name/skill.json, or flat skill.json).
|
|
299
|
+
*
|
|
300
|
+
* @param archivePath - Path to the tar.gz archive
|
|
301
|
+
* @returns Parsed skill.json content
|
|
302
|
+
* @throws Error if skill.json is not found or invalid
|
|
303
|
+
*/
|
|
304
|
+
async function extractSkillJson(archivePath) {
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
let settled = false;
|
|
307
|
+
const chunks = [];
|
|
308
|
+
const extract = tar.t({
|
|
309
|
+
file: archivePath,
|
|
310
|
+
onReadEntry: (entry) => {
|
|
311
|
+
const entryPath = entry.path;
|
|
312
|
+
// Match skill.json at any level
|
|
313
|
+
if (entryPath.endsWith('skill.json') && !settled) {
|
|
314
|
+
settled = true;
|
|
315
|
+
entry.on('data', (chunk) => chunks.push(chunk));
|
|
316
|
+
entry.on('end', () => {
|
|
317
|
+
try {
|
|
318
|
+
const content = Buffer.concat(chunks).toString('utf-8');
|
|
319
|
+
resolve(JSON.parse(content));
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
reject(new Error(`Invalid JSON in skill.json: ${err instanceof Error ? err.message : String(err)}`));
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
extract.then(() => {
|
|
329
|
+
if (!settled) {
|
|
330
|
+
reject(new Error('skill.json not found in archive'));
|
|
331
|
+
}
|
|
332
|
+
}).catch((err) => {
|
|
333
|
+
if (!settled) {
|
|
334
|
+
reject(err);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=marketplace-submission.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace-submission.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/marketplace/marketplace-submission.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module services/marketplace/marketplace.service
|
|
9
9
|
*/
|
|
10
|
-
import { MarketplaceRegistry, MarketplaceItemWithStatus, MarketplaceFilter, InstalledItemsManifest, InstalledItemRecord } from '../../types/marketplace.types.js';
|
|
10
|
+
import { MarketplaceRegistry, MarketplaceItemWithStatus, MarketplaceFilter, InstalledItemsManifest, InstalledItemRecord, type MarketplaceItemType } from '../../types/marketplace.types.js';
|
|
11
11
|
/**
|
|
12
12
|
* Fetches the marketplace registry from the Crewly webapp API.
|
|
13
|
-
* Uses in-memory caching with a 1-hour TTL.
|
|
13
|
+
* Uses in-memory caching with a 1-hour TTL. Concurrent callers share
|
|
14
|
+
* the same in-flight request to avoid duplicate network fetches.
|
|
14
15
|
*
|
|
15
16
|
* On network failure, falls back to the previously cached registry
|
|
16
17
|
* if one is available. Throws only when no cached data exists.
|
|
@@ -79,19 +80,7 @@ export declare function getInstalledItems(): Promise<InstalledItemRecord[]>;
|
|
|
79
80
|
* @returns Matching items with install status
|
|
80
81
|
*/
|
|
81
82
|
export declare function searchItems(query: string): Promise<MarketplaceItemWithStatus[]>;
|
|
82
|
-
|
|
83
|
-
* Returns the local install path for a marketplace item.
|
|
84
|
-
*
|
|
85
|
-
* Maps item types to directory names:
|
|
86
|
-
* - 'skill' -> 'skills'
|
|
87
|
-
* - 'model' -> 'models'
|
|
88
|
-
* - 'role' -> 'roles'
|
|
89
|
-
*
|
|
90
|
-
* @param type - The marketplace item type
|
|
91
|
-
* @param id - The marketplace item ID
|
|
92
|
-
* @returns Absolute path to the item's install directory
|
|
93
|
-
*/
|
|
94
|
-
export declare function getInstallPath(type: string, id: string): string;
|
|
83
|
+
export declare function getInstallPath(type: MarketplaceItemType, id: string): string;
|
|
95
84
|
/**
|
|
96
85
|
* Resets the in-memory registry cache.
|
|
97
86
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marketplace.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/marketplace/marketplace.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EACL,mBAAmB,EAEnB,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"marketplace.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/marketplace/marketplace.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EACL,mBAAmB,EAEnB,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,mBAAmB,EACzB,MAAM,kCAAkC,CAAC;AAyB1C;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAuBtF;AA+HD;;;;;;;GAOG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAOpE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlF;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAOnF;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAuChG;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAG9E;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAGxE;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAErF;AA0CD,wBAAgB,cAAc,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAM5E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC"}
|
|
@@ -10,17 +10,29 @@
|
|
|
10
10
|
import { homedir } from 'os';
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
13
|
-
|
|
14
|
-
const REGISTRY_ENDPOINT = '/api/registry';
|
|
15
|
-
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
|
13
|
+
import { MARKETPLACE_CONSTANTS } from '../../constants.js';
|
|
16
14
|
const CREWLY_HOME = path.join(homedir(), '.crewly');
|
|
17
|
-
const MARKETPLACE_DIR = path.join(CREWLY_HOME,
|
|
18
|
-
const MANIFEST_PATH = path.join(MARKETPLACE_DIR,
|
|
15
|
+
const MARKETPLACE_DIR = path.join(CREWLY_HOME, MARKETPLACE_CONSTANTS.DIR_NAME);
|
|
16
|
+
const MANIFEST_PATH = path.join(MARKETPLACE_DIR, MARKETPLACE_CONSTANTS.MANIFEST_FILE);
|
|
17
|
+
const LOCAL_REGISTRY_PATH = path.join(MARKETPLACE_DIR, MARKETPLACE_CONSTANTS.LOCAL_REGISTRY_FILE);
|
|
18
|
+
/** Pattern for valid marketplace item IDs: lowercase alphanumeric with hyphens */
|
|
19
|
+
const VALID_ITEM_ID_PATTERN = /^[a-z0-9][a-z0-9\-]*$/;
|
|
19
20
|
let cachedRegistry = null;
|
|
20
21
|
let cacheTimestamp = 0;
|
|
22
|
+
let fetchInFlight = null;
|
|
23
|
+
/**
|
|
24
|
+
* Validates that a marketplace item ID is safe (no path traversal).
|
|
25
|
+
*
|
|
26
|
+
* @param id - The item ID to validate
|
|
27
|
+
* @returns True if the ID matches the allowed pattern
|
|
28
|
+
*/
|
|
29
|
+
function isValidItemId(id) {
|
|
30
|
+
return VALID_ITEM_ID_PATTERN.test(id);
|
|
31
|
+
}
|
|
21
32
|
/**
|
|
22
33
|
* Fetches the marketplace registry from the Crewly webapp API.
|
|
23
|
-
* Uses in-memory caching with a 1-hour TTL.
|
|
34
|
+
* Uses in-memory caching with a 1-hour TTL. Concurrent callers share
|
|
35
|
+
* the same in-flight request to avoid duplicate network fetches.
|
|
24
36
|
*
|
|
25
37
|
* On network failure, falls back to the previously cached registry
|
|
26
38
|
* if one is available. Throws only when no cached data exists.
|
|
@@ -31,19 +43,140 @@ let cacheTimestamp = 0;
|
|
|
31
43
|
*/
|
|
32
44
|
export async function fetchRegistry(forceRefresh = false) {
|
|
33
45
|
const now = Date.now();
|
|
34
|
-
if (!forceRefresh && cachedRegistry && now - cacheTimestamp < CACHE_TTL) {
|
|
46
|
+
if (!forceRefresh && cachedRegistry && now - cacheTimestamp < MARKETPLACE_CONSTANTS.CACHE_TTL) {
|
|
35
47
|
return cachedRegistry;
|
|
36
48
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
// When forceRefresh is true, wait for any in-flight request to complete
|
|
50
|
+
// before starting a new fetch to avoid returning stale data
|
|
51
|
+
if (forceRefresh && fetchInFlight) {
|
|
52
|
+
await fetchInFlight.catch(() => { });
|
|
53
|
+
// Fall through to start a new fetch
|
|
54
|
+
}
|
|
55
|
+
// Deduplicate concurrent requests
|
|
56
|
+
if (fetchInFlight) {
|
|
57
|
+
return fetchInFlight;
|
|
58
|
+
}
|
|
59
|
+
fetchInFlight = doFetchRegistry(now).finally(() => {
|
|
60
|
+
fetchInFlight = null;
|
|
61
|
+
});
|
|
62
|
+
return fetchInFlight;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Internal fetch implementation. Separated to enable in-flight deduplication.
|
|
66
|
+
*
|
|
67
|
+
* Fetches from two sources in parallel:
|
|
68
|
+
* 1. Public registry -- GitHub raw content (config/skills/registry.json in crewly repo)
|
|
69
|
+
* 2. Premium registry -- crewly.stevesprompt.com/api/registry/skills (private/paid skills)
|
|
70
|
+
*
|
|
71
|
+
* Results are merged with local registry items (locally published skills).
|
|
72
|
+
*
|
|
73
|
+
* When both remote sources fail and no local items exist, the empty registry
|
|
74
|
+
* is returned but NOT cached so the next call will retry immediately.
|
|
75
|
+
*/
|
|
76
|
+
async function doFetchRegistry(now) {
|
|
77
|
+
// Fetch public and premium registries in parallel
|
|
78
|
+
const [publicResult, premiumResult] = await Promise.allSettled([
|
|
79
|
+
fetchPublicRegistry(),
|
|
80
|
+
fetchPremiumRegistry(),
|
|
81
|
+
]);
|
|
82
|
+
const publicItems = publicResult.status === 'fulfilled' ? publicResult.value : [];
|
|
83
|
+
const premiumItems = premiumResult.status === 'fulfilled' ? premiumResult.value : [];
|
|
84
|
+
// If both failed and we have a cache, return cache
|
|
85
|
+
if (publicItems.length === 0 && premiumItems.length === 0 && cachedRegistry) {
|
|
86
|
+
return cachedRegistry;
|
|
87
|
+
}
|
|
88
|
+
// Merge: public + premium (premium overwrites by ID if conflict)
|
|
89
|
+
const mergedMap = new Map();
|
|
90
|
+
for (const item of publicItems) {
|
|
91
|
+
mergedMap.set(item.id, item);
|
|
92
|
+
}
|
|
93
|
+
for (const item of premiumItems) {
|
|
94
|
+
mergedMap.set(item.id, item);
|
|
95
|
+
}
|
|
96
|
+
// Merge locally published skills
|
|
97
|
+
const localItems = await loadLocalRegistry();
|
|
98
|
+
for (const item of localItems) {
|
|
99
|
+
if (!mergedMap.has(item.id)) {
|
|
100
|
+
mergedMap.set(item.id, item);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const registry = {
|
|
104
|
+
schemaVersion: MARKETPLACE_CONSTANTS.SCHEMA_VERSION,
|
|
105
|
+
lastUpdated: new Date().toISOString(),
|
|
106
|
+
cdnBaseUrl: MARKETPLACE_CONSTANTS.PUBLIC_CDN_BASE,
|
|
107
|
+
items: Array.from(mergedMap.values()),
|
|
108
|
+
};
|
|
109
|
+
// Only cache non-empty registries so that next call retries on total failure
|
|
110
|
+
if (mergedMap.size > 0) {
|
|
111
|
+
cachedRegistry = registry;
|
|
112
|
+
cacheTimestamp = now;
|
|
113
|
+
}
|
|
114
|
+
return registry;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Fetches items from the public registry (GitHub raw content).
|
|
118
|
+
*
|
|
119
|
+
* @returns Array of public marketplace items, empty on failure
|
|
120
|
+
*/
|
|
121
|
+
async function fetchPublicRegistry() {
|
|
122
|
+
try {
|
|
123
|
+
const res = await fetch(MARKETPLACE_CONSTANTS.PUBLIC_REGISTRY_URL, {
|
|
124
|
+
signal: AbortSignal.timeout(MARKETPLACE_CONSTANTS.REGISTRY_FETCH_TIMEOUT),
|
|
125
|
+
});
|
|
126
|
+
if (res.ok) {
|
|
127
|
+
const data = (await res.json());
|
|
128
|
+
return data.items || [];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Public registry unavailable -- continue with empty
|
|
133
|
+
}
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Fetches items from the premium registry (crewly.stevesprompt.com).
|
|
138
|
+
*
|
|
139
|
+
* @returns Array of premium marketplace items with premium flag, empty on failure
|
|
140
|
+
*/
|
|
141
|
+
async function fetchPremiumRegistry() {
|
|
142
|
+
try {
|
|
143
|
+
const url = `${MARKETPLACE_CONSTANTS.PREMIUM_BASE_URL}${MARKETPLACE_CONSTANTS.PREMIUM_REGISTRY_ENDPOINT}`;
|
|
144
|
+
const res = await fetch(url, {
|
|
145
|
+
signal: AbortSignal.timeout(MARKETPLACE_CONSTANTS.REGISTRY_FETCH_TIMEOUT),
|
|
146
|
+
});
|
|
147
|
+
if (res.ok) {
|
|
148
|
+
const data = (await res.json());
|
|
149
|
+
return (data.items || []).map((item) => ({
|
|
150
|
+
...item,
|
|
151
|
+
metadata: { ...item.metadata, premium: true },
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Premium registry unavailable -- continue without premium skills
|
|
157
|
+
}
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Loads locally published marketplace items from the local registry file.
|
|
162
|
+
*
|
|
163
|
+
* These are skills that were submitted and approved through the local
|
|
164
|
+
* submission workflow.
|
|
165
|
+
*
|
|
166
|
+
* @returns Array of locally published marketplace items
|
|
167
|
+
*/
|
|
168
|
+
async function loadLocalRegistry() {
|
|
169
|
+
try {
|
|
170
|
+
const data = await readFile(LOCAL_REGISTRY_PATH, 'utf-8');
|
|
171
|
+
const registry = JSON.parse(data);
|
|
172
|
+
if (!Array.isArray(registry.items)) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
return registry.items;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return [];
|
|
43
179
|
}
|
|
44
|
-
cachedRegistry = (await res.json());
|
|
45
|
-
cacheTimestamp = now;
|
|
46
|
-
return cachedRegistry;
|
|
47
180
|
}
|
|
48
181
|
/**
|
|
49
182
|
* Loads the locally installed items manifest from disk.
|
|
@@ -84,7 +217,9 @@ export async function getItem(id) {
|
|
|
84
217
|
const item = registry.items.find((i) => i.id === id);
|
|
85
218
|
if (!item)
|
|
86
219
|
return null;
|
|
87
|
-
|
|
220
|
+
const manifest = await loadManifest();
|
|
221
|
+
const installedMap = new Map(manifest.items.map((r) => [r.id, r]));
|
|
222
|
+
return enrichWithStatusFromMap(item, installedMap);
|
|
88
223
|
}
|
|
89
224
|
/**
|
|
90
225
|
* Lists marketplace items with optional filtering, enriched with install status.
|
|
@@ -98,7 +233,8 @@ export async function getItem(id) {
|
|
|
98
233
|
*/
|
|
99
234
|
export async function listItems(filter) {
|
|
100
235
|
const registry = await fetchRegistry();
|
|
101
|
-
|
|
236
|
+
// Shallow copy to avoid mutating the cached registry's items array via .sort()
|
|
237
|
+
let items = [...registry.items];
|
|
102
238
|
if (filter?.type) {
|
|
103
239
|
items = items.filter((i) => i.type === filter.type);
|
|
104
240
|
}
|
|
@@ -125,7 +261,9 @@ export async function listItems(filter) {
|
|
|
125
261
|
items.sort((a, b) => b.downloads - a.downloads);
|
|
126
262
|
}
|
|
127
263
|
const manifest = await loadManifest();
|
|
128
|
-
|
|
264
|
+
// Use Map for O(n+m) enrichment instead of O(n*m) linear scan per item
|
|
265
|
+
const installedMap = new Map(manifest.items.map((r) => [r.id, r]));
|
|
266
|
+
return items.map((i) => enrichWithStatusFromMap(i, installedMap));
|
|
129
267
|
}
|
|
130
268
|
/**
|
|
131
269
|
* Returns marketplace items that have updates available.
|
|
@@ -160,17 +298,14 @@ export async function searchItems(query) {
|
|
|
160
298
|
return listItems({ search: query });
|
|
161
299
|
}
|
|
162
300
|
/**
|
|
163
|
-
* Enriches a marketplace item with its local install status.
|
|
164
|
-
*
|
|
165
|
-
* Compares the registry item against the local manifest to determine
|
|
166
|
-
* whether the item is not installed, installed, or has an update available.
|
|
301
|
+
* Enriches a marketplace item with its local install status using a pre-built Map.
|
|
167
302
|
*
|
|
168
303
|
* @param item - The marketplace item from the registry
|
|
169
|
-
* @param
|
|
304
|
+
* @param installedMap - Map of installed item ID to record for O(1) lookup
|
|
170
305
|
* @returns The item enriched with installStatus and optional installedVersion
|
|
171
306
|
*/
|
|
172
|
-
function
|
|
173
|
-
const installed =
|
|
307
|
+
function enrichWithStatusFromMap(item, installedMap) {
|
|
308
|
+
const installed = installedMap.get(item.id);
|
|
174
309
|
if (!installed) {
|
|
175
310
|
return { ...item, installStatus: 'not_installed' };
|
|
176
311
|
}
|
|
@@ -190,9 +325,18 @@ function enrichWithStatus(item, manifest) {
|
|
|
190
325
|
* @param type - The marketplace item type
|
|
191
326
|
* @param id - The marketplace item ID
|
|
192
327
|
* @returns Absolute path to the item's install directory
|
|
328
|
+
* @throws Error if the id contains path traversal characters
|
|
193
329
|
*/
|
|
330
|
+
const TYPE_DIR_MAP = {
|
|
331
|
+
skill: 'skills',
|
|
332
|
+
model: 'models',
|
|
333
|
+
role: 'roles',
|
|
334
|
+
};
|
|
194
335
|
export function getInstallPath(type, id) {
|
|
195
|
-
|
|
336
|
+
if (!isValidItemId(id)) {
|
|
337
|
+
throw new Error(`Invalid marketplace item ID "${id}": must match ${VALID_ITEM_ID_PATTERN}`);
|
|
338
|
+
}
|
|
339
|
+
const typeDir = TYPE_DIR_MAP[type];
|
|
196
340
|
return path.join(MARKETPLACE_DIR, typeDir, id);
|
|
197
341
|
}
|
|
198
342
|
/**
|
|
@@ -203,5 +347,6 @@ export function getInstallPath(type, id) {
|
|
|
203
347
|
export function resetRegistryCache() {
|
|
204
348
|
cachedRegistry = null;
|
|
205
349
|
cacheTimestamp = 0;
|
|
350
|
+
fetchInFlight = null;
|
|
206
351
|
}
|
|
207
352
|
//# sourceMappingURL=marketplace.service.js.map
|