@mastra/code-sdk 0.0.0-livekit-beta-v3-20260709031728
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/CHANGELOG.md +41 -0
- package/LICENSE.md +30 -0
- package/README.md +50 -0
- package/dist/acp/agent.d.ts +35 -0
- package/dist/acp/agent.d.ts.map +1 -0
- package/dist/acp/agent.js +173 -0
- package/dist/acp/agent.js.map +1 -0
- package/dist/acp/event-mapper.d.ts +22 -0
- package/dist/acp/event-mapper.d.ts.map +1 -0
- package/dist/acp/event-mapper.js +166 -0
- package/dist/acp/event-mapper.js.map +1 -0
- package/dist/acp/index.d.ts +8 -0
- package/dist/acp/index.d.ts.map +1 -0
- package/dist/acp/index.js +54 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/acp/server.d.ts +7 -0
- package/dist/acp/server.d.ts.map +1 -0
- package/dist/acp/server.js +34 -0
- package/dist/acp/server.js.map +1 -0
- package/dist/acp.d.ts +2 -0
- package/dist/acp.d.ts.map +1 -0
- package/dist/acp.js +5 -0
- package/dist/acp.js.map +1 -0
- package/dist/agents/instructions.d.ts +6 -0
- package/dist/agents/instructions.d.ts.map +1 -0
- package/dist/agents/instructions.js +41 -0
- package/dist/agents/instructions.js.map +1 -0
- package/dist/agents/mastracode-gateway.d.ts +65 -0
- package/dist/agents/mastracode-gateway.d.ts.map +1 -0
- package/dist/agents/mastracode-gateway.js +442 -0
- package/dist/agents/mastracode-gateway.js.map +1 -0
- package/dist/agents/memory.d.ts +13 -0
- package/dist/agents/memory.d.ts.map +1 -0
- package/dist/agents/memory.js +107 -0
- package/dist/agents/memory.js.map +1 -0
- package/dist/agents/model.d.ts +55 -0
- package/dist/agents/model.d.ts.map +1 -0
- package/dist/agents/model.js +115 -0
- package/dist/agents/model.js.map +1 -0
- package/dist/agents/modes/build.d.ts +10 -0
- package/dist/agents/modes/build.d.ts.map +1 -0
- package/dist/agents/modes/build.js +45 -0
- package/dist/agents/modes/build.js.map +1 -0
- package/dist/agents/modes/explore.d.ts +10 -0
- package/dist/agents/modes/explore.d.ts.map +1 -0
- package/dist/agents/modes/explore.js +38 -0
- package/dist/agents/modes/explore.js.map +1 -0
- package/dist/agents/modes/plan.d.ts +6 -0
- package/dist/agents/modes/plan.d.ts.map +1 -0
- package/dist/agents/modes/plan.js +38 -0
- package/dist/agents/modes/plan.js.map +1 -0
- package/dist/agents/prompts/agent-instructions.d.ts +20 -0
- package/dist/agents/prompts/agent-instructions.d.ts.map +1 -0
- package/dist/agents/prompts/agent-instructions.js +82 -0
- package/dist/agents/prompts/agent-instructions.js.map +1 -0
- package/dist/agents/prompts/build.d.ts +12 -0
- package/dist/agents/prompts/build.d.ts.map +1 -0
- package/dist/agents/prompts/build.js +73 -0
- package/dist/agents/prompts/build.js.map +1 -0
- package/dist/agents/prompts/fast.d.ts +5 -0
- package/dist/agents/prompts/fast.d.ts.map +1 -0
- package/dist/agents/prompts/fast.js +22 -0
- package/dist/agents/prompts/fast.js.map +1 -0
- package/dist/agents/prompts/index.d.ts +19 -0
- package/dist/agents/prompts/index.d.ts.map +1 -0
- package/dist/agents/prompts/index.js +57 -0
- package/dist/agents/prompts/index.js.map +1 -0
- package/dist/agents/prompts/model.d.ts +5 -0
- package/dist/agents/prompts/model.d.ts.map +1 -0
- package/dist/agents/prompts/model.js +22 -0
- package/dist/agents/prompts/model.js.map +1 -0
- package/dist/agents/prompts/plan.d.ts +6 -0
- package/dist/agents/prompts/plan.d.ts.map +1 -0
- package/dist/agents/prompts/plan.js +107 -0
- package/dist/agents/prompts/plan.js.map +1 -0
- package/dist/agents/prompts/tool-guidance.d.ts +13 -0
- package/dist/agents/prompts/tool-guidance.d.ts.map +1 -0
- package/dist/agents/prompts/tool-guidance.js +181 -0
- package/dist/agents/prompts/tool-guidance.js.map +1 -0
- package/dist/agents/sandbox-filesystem.d.ts +89 -0
- package/dist/agents/sandbox-filesystem.d.ts.map +1 -0
- package/dist/agents/sandbox-filesystem.js +268 -0
- package/dist/agents/sandbox-filesystem.js.map +1 -0
- package/dist/agents/sandbox-reattach.d.ts +19 -0
- package/dist/agents/sandbox-reattach.d.ts.map +1 -0
- package/dist/agents/sandbox-reattach.js +17 -0
- package/dist/agents/sandbox-reattach.js.map +1 -0
- package/dist/agents/thread-caveman-state.d.ts +17 -0
- package/dist/agents/thread-caveman-state.d.ts.map +1 -0
- package/dist/agents/thread-caveman-state.js +96 -0
- package/dist/agents/thread-caveman-state.js.map +1 -0
- package/dist/agents/tool-availability.d.ts +10 -0
- package/dist/agents/tool-availability.d.ts.map +1 -0
- package/dist/agents/tool-availability.js +105 -0
- package/dist/agents/tool-availability.js.map +1 -0
- package/dist/agents/tools.d.ts +18 -0
- package/dist/agents/tools.d.ts.map +1 -0
- package/dist/agents/tools.js +126 -0
- package/dist/agents/tools.js.map +1 -0
- package/dist/agents/workspace.d.ts +22 -0
- package/dist/agents/workspace.d.ts.map +1 -0
- package/dist/agents/workspace.js +194 -0
- package/dist/agents/workspace.js.map +1 -0
- package/dist/analytics.d.ts +18 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +152 -0
- package/dist/analytics.js.map +1 -0
- package/dist/auth/index.d.ts +9 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/pkce.d.ts +13 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +21 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/providers/anthropic.d.ts +17 -0
- package/dist/auth/providers/anthropic.d.ts.map +1 -0
- package/dist/auth/providers/anthropic.js +94 -0
- package/dist/auth/providers/anthropic.js.map +1 -0
- package/dist/auth/providers/github-copilot.d.ts +100 -0
- package/dist/auth/providers/github-copilot.d.ts.map +1 -0
- package/dist/auth/providers/github-copilot.js +302 -0
- package/dist/auth/providers/github-copilot.js.map +1 -0
- package/dist/auth/providers/openai-codex.d.ts +95 -0
- package/dist/auth/providers/openai-codex.d.ts.map +1 -0
- package/dist/auth/providers/openai-codex.js +527 -0
- package/dist/auth/providers/openai-codex.js.map +1 -0
- package/dist/auth/storage.d.ts +91 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +187 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/auth/types.d.ts +68 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +1 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/clipboard/index.d.ts +26 -0
- package/dist/clipboard/index.d.ts.map +1 -0
- package/dist/clipboard/index.js +192 -0
- package/dist/clipboard/index.js.map +1 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +23 -0
- package/dist/constants.js.map +1 -0
- package/dist/error-classification.d.ts +10 -0
- package/dist/error-classification.d.ts.map +1 -0
- package/dist/error-classification.js +14 -0
- package/dist/error-classification.js.map +1 -0
- package/dist/evals/context-builder.d.ts +41 -0
- package/dist/evals/context-builder.d.ts.map +1 -0
- package/dist/evals/context-builder.js +120 -0
- package/dist/evals/context-builder.js.map +1 -0
- package/dist/evals/index.d.ts +4 -0
- package/dist/evals/index.d.ts.map +1 -0
- package/dist/evals/index.js +8 -0
- package/dist/evals/index.js.map +1 -0
- package/dist/evals/scorers/classify-command.d.ts +31 -0
- package/dist/evals/scorers/classify-command.d.ts.map +1 -0
- package/dist/evals/scorers/classify-command.js +52 -0
- package/dist/evals/scorers/classify-command.js.map +1 -0
- package/dist/evals/scorers/efficiency.d.ts +44 -0
- package/dist/evals/scorers/efficiency.d.ts.map +1 -0
- package/dist/evals/scorers/efficiency.js +201 -0
- package/dist/evals/scorers/efficiency.js.map +1 -0
- package/dist/evals/scorers/extract-tools.d.ts +25 -0
- package/dist/evals/scorers/extract-tools.d.ts.map +1 -0
- package/dist/evals/scorers/extract-tools.js +56 -0
- package/dist/evals/scorers/extract-tools.js.map +1 -0
- package/dist/evals/scorers/index.d.ts +3 -0
- package/dist/evals/scorers/index.d.ts.map +1 -0
- package/dist/evals/scorers/index.js +7 -0
- package/dist/evals/scorers/index.js.map +1 -0
- package/dist/evals/scorers/outcome.d.ts +49 -0
- package/dist/evals/scorers/outcome.d.ts.map +1 -0
- package/dist/evals/scorers/outcome.js +238 -0
- package/dist/evals/scorers/outcome.js.map +1 -0
- package/dist/headless/cli.d.ts +42 -0
- package/dist/headless/cli.d.ts.map +1 -0
- package/dist/headless/cli.js +196 -0
- package/dist/headless/cli.js.map +1 -0
- package/dist/headless/flags.d.ts +33 -0
- package/dist/headless/flags.d.ts.map +1 -0
- package/dist/headless/flags.js +188 -0
- package/dist/headless/flags.js.map +1 -0
- package/dist/headless/format.d.ts +38 -0
- package/dist/headless/format.d.ts.map +1 -0
- package/dist/headless/format.js +85 -0
- package/dist/headless/format.js.map +1 -0
- package/dist/headless/index.d.ts +25 -0
- package/dist/headless/index.d.ts.map +1 -0
- package/dist/headless/index.js +32 -0
- package/dist/headless/index.js.map +1 -0
- package/dist/headless/policy.d.ts +17 -0
- package/dist/headless/policy.d.ts.map +1 -0
- package/dist/headless/policy.js +38 -0
- package/dist/headless/policy.js.map +1 -0
- package/dist/headless/run-mc.d.ts +7 -0
- package/dist/headless/run-mc.d.ts.map +1 -0
- package/dist/headless/run-mc.js +296 -0
- package/dist/headless/run-mc.js.map +1 -0
- package/dist/headless/types.d.ts +134 -0
- package/dist/headless/types.d.ts.map +1 -0
- package/dist/headless/types.js +9 -0
- package/dist/headless/types.js.map +1 -0
- package/dist/hooks/config.d.ts +11 -0
- package/dist/hooks/config.d.ts.map +1 -0
- package/dist/hooks/config.js +78 -0
- package/dist/hooks/config.js.map +1 -0
- package/dist/hooks/executor.d.ts +13 -0
- package/dist/hooks/executor.d.ts.map +1 -0
- package/dist/hooks/executor.js +125 -0
- package/dist/hooks/executor.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +16 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/manager.d.ts +47 -0
- package/dist/hooks/manager.d.ts.map +1 -0
- package/dist/hooks/manager.js +284 -0
- package/dist/hooks/manager.js.map +1 -0
- package/dist/hooks/types.d.ts +152 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +7 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +241 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +712 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/ipc-reporter.d.ts +14 -0
- package/dist/ipc/ipc-reporter.d.ts.map +1 -0
- package/dist/ipc/ipc-reporter.js +24 -0
- package/dist/ipc/ipc-reporter.js.map +1 -0
- package/dist/lsp/client.d.ts +56 -0
- package/dist/lsp/client.d.ts.map +1 -0
- package/dist/lsp/client.js +309 -0
- package/dist/lsp/client.js.map +1 -0
- package/dist/lsp/index.d.ts +4 -0
- package/dist/lsp/index.d.ts.map +1 -0
- package/dist/lsp/index.js +9 -0
- package/dist/lsp/index.js.map +1 -0
- package/dist/lsp/language.d.ts +9 -0
- package/dist/lsp/language.d.ts.map +1 -0
- package/dist/lsp/language.js +48 -0
- package/dist/lsp/language.js.map +1 -0
- package/dist/lsp/manager.d.ts +34 -0
- package/dist/lsp/manager.d.ts.map +1 -0
- package/dist/lsp/manager.js +97 -0
- package/dist/lsp/manager.js.map +1 -0
- package/dist/lsp/server.d.ts +27 -0
- package/dist/lsp/server.d.ts.map +1 -0
- package/dist/lsp/server.js +128 -0
- package/dist/lsp/server.js.map +1 -0
- package/dist/lsp/workspace.d.ts +9 -0
- package/dist/lsp/workspace.d.ts.map +1 -0
- package/dist/lsp/workspace.js +52 -0
- package/dist/lsp/workspace.js.map +1 -0
- package/dist/mcp/config.d.ts +34 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +205 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +10 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +49 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +374 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/mcp/types.d.ts +85 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +1 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/onboarding/custom-packs.d.ts +7 -0
- package/dist/onboarding/custom-packs.d.ts.map +1 -0
- package/dist/onboarding/custom-packs.js +20 -0
- package/dist/onboarding/custom-packs.js.map +1 -0
- package/dist/onboarding/custom-providers.d.ts +4 -0
- package/dist/onboarding/custom-providers.d.ts.map +1 -0
- package/dist/onboarding/custom-providers.js +28 -0
- package/dist/onboarding/custom-providers.js.map +1 -0
- package/dist/onboarding/index.d.ts +5 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +21 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/om-settings.d.ts +20 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -0
- package/dist/onboarding/om-settings.js +26 -0
- package/dist/onboarding/om-settings.js.map +1 -0
- package/dist/onboarding/packs.d.ts +48 -0
- package/dist/onboarding/packs.d.ts.map +1 -0
- package/dist/onboarding/packs.js +111 -0
- package/dist/onboarding/packs.js.map +1 -0
- package/dist/onboarding/settings.d.ts +323 -0
- package/dist/onboarding/settings.d.ts.map +1 -0
- package/dist/onboarding/settings.js +594 -0
- package/dist/onboarding/settings.js.map +1 -0
- package/dist/permissions.d.ts +55 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +119 -0
- package/dist/permissions.js.map +1 -0
- package/dist/plugin.d.ts +81 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +30 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugins/dependencies.d.ts +9 -0
- package/dist/plugins/dependencies.d.ts.map +1 -0
- package/dist/plugins/dependencies.js +141 -0
- package/dist/plugins/dependencies.js.map +1 -0
- package/dist/plugins/install.d.ts +21 -0
- package/dist/plugins/install.d.ts.map +1 -0
- package/dist/plugins/install.js +200 -0
- package/dist/plugins/install.js.map +1 -0
- package/dist/plugins/loader.d.ts +15 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +221 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manager.d.ts +60 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +378 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/manifest.d.ts +14 -0
- package/dist/plugins/manifest.d.ts.map +1 -0
- package/dist/plugins/manifest.js +75 -0
- package/dist/plugins/manifest.js.map +1 -0
- package/dist/plugins/package-link.d.ts +3 -0
- package/dist/plugins/package-link.d.ts.map +1 -0
- package/dist/plugins/package-link.js +77 -0
- package/dist/plugins/package-link.js.map +1 -0
- package/dist/plugins/paths.d.ts +10 -0
- package/dist/plugins/paths.d.ts.map +1 -0
- package/dist/plugins/paths.js +26 -0
- package/dist/plugins/paths.js.map +1 -0
- package/dist/plugins/registry.d.ts +8 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +96 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/scaffold.d.ts +10 -0
- package/dist/plugins/scaffold.d.ts.map +1 -0
- package/dist/plugins/scaffold.js +152 -0
- package/dist/plugins/scaffold.js.map +1 -0
- package/dist/plugins/types.d.ts +45 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +1 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/processors/plan-rejection-abort.d.ts +12 -0
- package/dist/processors/plan-rejection-abort.d.ts.map +1 -0
- package/dist/processors/plan-rejection-abort.js +53 -0
- package/dist/processors/plan-rejection-abort.js.map +1 -0
- package/dist/providers/amazon-bedrock-gateway.d.ts +40 -0
- package/dist/providers/amazon-bedrock-gateway.d.ts.map +1 -0
- package/dist/providers/amazon-bedrock-gateway.js +79 -0
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -0
- package/dist/providers/amazon-bedrock.d.ts +28 -0
- package/dist/providers/amazon-bedrock.d.ts.map +1 -0
- package/dist/providers/amazon-bedrock.js +62 -0
- package/dist/providers/amazon-bedrock.js.map +1 -0
- package/dist/providers/claude-max.d.ts +50 -0
- package/dist/providers/claude-max.d.ts.map +1 -0
- package/dist/providers/claude-max.js +151 -0
- package/dist/providers/claude-max.js.map +1 -0
- package/dist/providers/github-copilot.d.ts +58 -0
- package/dist/providers/github-copilot.d.ts.map +1 -0
- package/dist/providers/github-copilot.js +263 -0
- package/dist/providers/github-copilot.js.map +1 -0
- package/dist/providers/openai-codex.d.ts +70 -0
- package/dist/providers/openai-codex.d.ts.map +1 -0
- package/dist/providers/openai-codex.js +291 -0
- package/dist/providers/openai-codex.js.map +1 -0
- package/dist/schema.d.ts +167 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +92 -0
- package/dist/schema.js.map +1 -0
- package/dist/theme-palette.d.ts +17 -0
- package/dist/theme-palette.d.ts.map +1 -0
- package/dist/theme-palette.js +17 -0
- package/dist/theme-palette.js.map +1 -0
- package/dist/tool-names.d.ts +73 -0
- package/dist/tool-names.d.ts.map +1 -0
- package/dist/tool-names.js +43 -0
- package/dist/tool-names.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/request-sandbox-access.d.ts +6 -0
- package/dist/tools/request-sandbox-access.d.ts.map +1 -0
- package/dist/tools/request-sandbox-access.js +88 -0
- package/dist/tools/request-sandbox-access.js.map +1 -0
- package/dist/tools/utils.d.ts +20 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +22 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools/web-search.d.ts +35 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +65 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/utils/binaries.d.ts +7 -0
- package/dist/utils/binaries.d.ts.map +1 -0
- package/dist/utils/binaries.js +74 -0
- package/dist/utils/binaries.js.map +1 -0
- package/dist/utils/debug-log.d.ts +12 -0
- package/dist/utils/debug-log.d.ts.map +1 -0
- package/dist/utils/debug-log.js +55 -0
- package/dist/utils/debug-log.js.map +1 -0
- package/dist/utils/errors.d.ts +36 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +207 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/gateway-sync.d.ts +26 -0
- package/dist/utils/gateway-sync.d.ts.map +1 -0
- package/dist/utils/gateway-sync.js +49 -0
- package/dist/utils/gateway-sync.js.map +1 -0
- package/dist/utils/plan-diff.d.ts +25 -0
- package/dist/utils/plan-diff.d.ts.map +1 -0
- package/dist/utils/plan-diff.js +43 -0
- package/dist/utils/plan-diff.js.map +1 -0
- package/dist/utils/plans.d.ts +56 -0
- package/dist/utils/plans.d.ts.map +1 -0
- package/dist/utils/plans.js +99 -0
- package/dist/utils/plans.js.map +1 -0
- package/dist/utils/project.d.ts +161 -0
- package/dist/utils/project.d.ts.map +1 -0
- package/dist/utils/project.js +302 -0
- package/dist/utils/project.js.map +1 -0
- package/dist/utils/signals-pubsub.d.ts +41 -0
- package/dist/utils/signals-pubsub.d.ts.map +1 -0
- package/dist/utils/signals-pubsub.js +104 -0
- package/dist/utils/signals-pubsub.js.map +1 -0
- package/dist/utils/slash-command-loader.d.ts +48 -0
- package/dist/utils/slash-command-loader.d.ts.map +1 -0
- package/dist/utils/slash-command-loader.js +155 -0
- package/dist/utils/slash-command-loader.js.map +1 -0
- package/dist/utils/slash-command-processor.d.ts +14 -0
- package/dist/utils/slash-command-processor.d.ts.map +1 -0
- package/dist/utils/slash-command-processor.js +96 -0
- package/dist/utils/slash-command-processor.js.map +1 -0
- package/dist/utils/stdin-pipe.d.ts +33 -0
- package/dist/utils/stdin-pipe.d.ts.map +1 -0
- package/dist/utils/stdin-pipe.js +72 -0
- package/dist/utils/stdin-pipe.js.map +1 -0
- package/dist/utils/storage-factory.d.ts +50 -0
- package/dist/utils/storage-factory.d.ts.map +1 -0
- package/dist/utils/storage-factory.js +98 -0
- package/dist/utils/storage-factory.js.map +1 -0
- package/dist/utils/thread-lock.d.ts +26 -0
- package/dist/utils/thread-lock.d.ts.map +1 -0
- package/dist/utils/thread-lock.js +108 -0
- package/dist/utils/thread-lock.js.map +1 -0
- package/dist/utils/token-estimator.d.ts +3 -0
- package/dist/utils/token-estimator.d.ts.map +1 -0
- package/dist/utils/token-estimator.js +21 -0
- package/dist/utils/token-estimator.js.map +1 -0
- package/dist/utils/update-check.d.ts +52 -0
- package/dist/utils/update-check.d.ts.map +1 -0
- package/dist/utils/update-check.js +177 -0
- package/dist/utils/update-check.js.map +1 -0
- package/dist/voice/stt-registry.d.ts +64 -0
- package/dist/voice/stt-registry.d.ts.map +1 -0
- package/dist/voice/stt-registry.js +126 -0
- package/dist/voice/stt-registry.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/project.ts"],"sourcesContent":["/**\n * Project detection utilities\n *\n * Detects project identity from git repo or filesystem path.\n * Handles git worktrees by finding the main repository.\n */\n\nimport { execFile, execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nexport interface ProjectInfo {\n /** Unique resource ID for this project (used for thread grouping) */\n resourceId: string;\n /** Human-readable project name */\n name: string;\n /** Absolute path to the project root */\n rootPath: string;\n /** Git remote URL if available */\n gitUrl?: string;\n /** Current git branch */\n gitBranch?: string;\n /** Whether this is a git worktree */\n isWorktree: boolean;\n /** Path to main git repo (different from rootPath if worktree) */\n mainRepoPath?: string;\n /** Whether the resourceId was explicitly overridden (env var or config) */\n resourceIdOverride?: boolean;\n}\n\n/**\n * Run a git command and return stdout, or undefined if it fails\n */\nfunction git(args: string, cwd: string): string | undefined {\n try {\n return execSync(`git ${args}`, {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Slugify a string for use in IDs\n */\nfunction slugify(str: string): string {\n return str\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\n/**\n * Create a short hash of a string\n */\nfunction shortHash(str: string): string {\n return createHash('sha256').update(str).digest('hex').slice(0, 12);\n}\n\n/**\n * Normalize a git URL to a canonical form for comparison\n * - Removes .git suffix\n * - Converts SSH to HTTPS format for consistency\n * - Lowercases\n */\nfunction normalizeGitUrl(url: string): string {\n return url\n .replace(/\\.git$/, '')\n .replace(/^git@([^:]+):/, 'https://$1/')\n .replace(/^ssh:\\/\\/git@/, 'https://')\n .toLowerCase();\n}\n\n/**\n * Detect project info from a directory path\n */\nexport function detectProject(projectPath: string): ProjectInfo {\n const absolutePath = path.resolve(projectPath);\n\n // Check if this is a git repo\n const gitDir = git('rev-parse --git-dir', absolutePath);\n const isGitRepo = gitDir !== undefined;\n\n let rootPath = absolutePath;\n let gitUrl: string | undefined;\n let gitBranch: string | undefined;\n let isWorktree = false;\n let mainRepoPath: string | undefined;\n\n if (isGitRepo) {\n // Get the repo root (handles being in a subdirectory)\n rootPath = git('rev-parse --show-toplevel', absolutePath) || absolutePath;\n\n // Check for worktree - git-common-dir differs from git-dir in worktrees\n const commonDir = git('rev-parse --git-common-dir', absolutePath);\n if (commonDir && commonDir !== '.git' && commonDir !== gitDir) {\n isWorktree = true;\n // The common dir is inside the main repo's .git folder\n mainRepoPath = path.dirname(path.resolve(rootPath, commonDir));\n }\n\n // Get remote URL (prefer origin, fall back to first remote)\n gitUrl = git('remote get-url origin', absolutePath);\n if (!gitUrl) {\n const remotes = git('remote', absolutePath);\n if (remotes) {\n const firstRemote = remotes.split('\\n')[0];\n if (firstRemote) {\n gitUrl = git(`remote get-url ${firstRemote}`, absolutePath);\n }\n }\n }\n\n // Get current branch\n gitBranch = git('rev-parse --abbrev-ref HEAD', absolutePath);\n }\n\n // Generate resource ID\n // Priority: normalized git URL > main repo path (for worktrees) > absolute path\n let resourceIdSource: string;\n if (gitUrl) {\n resourceIdSource = normalizeGitUrl(gitUrl);\n } else if (mainRepoPath) {\n resourceIdSource = mainRepoPath;\n } else {\n resourceIdSource = rootPath;\n }\n\n // Create a readable but unique resource ID\n // Format: slugified-name-shorthash\n const baseName = gitUrl\n ? gitUrl\n .split('/')\n .pop()\n ?.replace(/\\.git$/, '') || 'project'\n : path.basename(rootPath);\n\n const resourceId = `${slugify(baseName)}-${shortHash(resourceIdSource)}`;\n\n return {\n resourceId,\n name: baseName,\n rootPath,\n gitUrl,\n gitBranch,\n isWorktree,\n mainRepoPath,\n };\n}\n\n/**\n * Get the current git branch for a given directory.\n * Lightweight alternative to detectProject() for refreshing just the branch.\n */\nexport function getCurrentGitBranch(cwd: string): string | undefined {\n return git('rev-parse --abbrev-ref HEAD', cwd);\n}\n\n/**\n * Async version of getCurrentGitBranch — avoids blocking the event loop\n * with execSync. Falls back to undefined on any failure.\n */\nexport function getCurrentGitBranchAsync(cwd: string): Promise<string | undefined> {\n return new Promise(resolve => {\n execFile('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, encoding: 'utf-8' }, (err, stdout) => {\n if (err) {\n resolve(undefined);\n return;\n }\n const branch = stdout.trim();\n resolve(branch || undefined);\n });\n });\n}\n\n/**\n * Get the application data directory for mastracode\n * - macOS: ~/Library/Application Support/mastracode\n * - Linux: ~/.local/share/mastracode\n * - Windows: %APPDATA%/mastracode\n */\nexport function getAppDataDir(): string {\n if (process.env.MASTRA_APP_DATA_DIR) {\n fs.mkdirSync(process.env.MASTRA_APP_DATA_DIR, { recursive: true });\n return process.env.MASTRA_APP_DATA_DIR;\n }\n\n const platform = os.platform();\n let baseDir: string;\n\n if (platform === 'darwin') {\n baseDir = path.join(os.homedir(), 'Library', 'Application Support');\n } else if (platform === 'win32') {\n baseDir = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');\n } else {\n // Linux and others - follow XDG spec\n baseDir = process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share');\n }\n\n const appDir = path.join(baseDir, 'mastracode');\n\n // Ensure directory exists\n if (!fs.existsSync(appDir)) {\n fs.mkdirSync(appDir, { recursive: true });\n }\n\n return appDir;\n}\n/**\n * Get the database path for mastracode\n * Can be overridden with the MASTRA_DB_PATH environment variable for debugging.\n */\nexport function getDatabasePath(): string {\n if (process.env.MASTRA_DB_PATH) {\n return process.env.MASTRA_DB_PATH;\n }\n return path.join(getAppDataDir(), 'mastra.db');\n}\n\n/**\n * Get the vector database path for mastracode.\n * Separate from the main DB to avoid bloating it with embedding data.\n */\nexport function getVectorDatabasePath(): string {\n return path.join(getAppDataDir(), 'mastra-vectors.db');\n}\n\n/**\n * Get the observability DuckDB database path for mastracode.\n * Separate from the main DB — DuckDB is used for OLAP-style trace/score/feedback queries.\n * Can be overridden with the MASTRA_OBSERVABILITY_DB_PATH environment variable.\n */\nexport function getObservabilityDatabasePath(): string {\n if (process.env.MASTRA_OBSERVABILITY_DB_PATH) {\n return process.env.MASTRA_OBSERVABILITY_DB_PATH;\n }\n return path.join(getAppDataDir(), 'observability.duckdb');\n}\n\nimport type { StorageBackend, StorageSettings } from '../onboarding/settings.js';\n\n/**\n * LibSQL storage configuration.\n */\nexport interface LibSQLStorageConfig {\n backend: 'libsql';\n url: string;\n authToken?: string;\n isRemote: boolean;\n /**\n * Optional explicit url for the recall vector DB. When omitted, the factory\n * uses the shared default vector file. Per-tenant storage sets this so each\n * tenant's recall vectors live in their own isolated DB, not a shared file.\n */\n vectorUrl?: string;\n /** Auth token for the vector DB when `vectorUrl` points at a remote libSQL. */\n vectorAuthToken?: string;\n}\n\n/**\n * PostgreSQL storage configuration.\n */\nexport interface PgStorageConfig {\n backend: 'pg';\n connectionString?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n schemaName?: string;\n disableInit?: boolean;\n skipDefaultIndexes?: boolean;\n}\n\n/**\n * Resolved storage configuration for either backend.\n */\nexport type StorageConfig = LibSQLStorageConfig | PgStorageConfig;\n\n/**\n * Get the resolved storage configuration.\n *\n * Priority (highest to lowest):\n * 1. Environment variables: MASTRA_STORAGE_BACKEND + backend-specific vars\n * 2. Global settings (from /settings): settings.storage\n * 3. Legacy config files: .mastracode/database.json (LibSQL only)\n * 4. Local file database (LibSQL default)\n *\n * For PG, the env vars are:\n * MASTRA_STORAGE_BACKEND=pg\n * MASTRA_PG_CONNECTION_STRING or MASTRA_PG_HOST/PORT/DATABASE/USER/PASSWORD\n * MASTRA_PG_SCHEMA_NAME (optional)\n *\n * For LibSQL, the legacy env vars still work:\n * MASTRA_DB_URL + MASTRA_DB_AUTH_TOKEN\n */\nexport function getStorageConfig(\n projectDir?: string,\n storageSettings?: StorageSettings,\n configDirName = DEFAULT_CONFIG_DIR,\n): StorageConfig {\n // 1. Environment variable — explicit backend selection\n const envBackend = process.env.MASTRA_STORAGE_BACKEND as StorageBackend | undefined;\n\n if (envBackend === 'pg') {\n return resolvePgFromEnv();\n }\n\n // Legacy LibSQL env vars (MASTRA_DB_URL) — treat as explicit libsql\n if (envBackend === 'libsql' || process.env.MASTRA_DB_URL) {\n return resolveLibSQLFromEnv();\n }\n\n // 2. Global settings (from /settings)\n if (storageSettings && storageSettings.backend === 'pg') {\n return resolvePgFromSettings(storageSettings);\n }\n\n if (storageSettings && storageSettings.backend === 'libsql' && storageSettings.libsql.url) {\n return {\n backend: 'libsql',\n url: storageSettings.libsql.url,\n authToken: storageSettings.libsql.authToken,\n isRemote: !storageSettings.libsql.url.startsWith('file:'),\n };\n }\n\n // 3. Legacy project/global config files (.mastracode/database.json)\n if (projectDir) {\n const projectConfig = loadDatabaseConfig(path.join(projectDir, configDirName, 'database.json'));\n if (projectConfig) return projectConfig;\n }\n const globalConfig = loadDatabaseConfig(path.join(os.homedir(), configDirName, 'database.json'));\n if (globalConfig) return globalConfig;\n\n // 4. Default: local LibSQL file database\n return {\n backend: 'libsql',\n url: `file:${getDatabasePath()}`,\n isRemote: false,\n };\n}\n\nfunction resolveLibSQLFromEnv(): LibSQLStorageConfig {\n const url = process.env.MASTRA_DB_URL!;\n return {\n backend: 'libsql',\n url,\n authToken: process.env.MASTRA_DB_AUTH_TOKEN,\n isRemote: !url.startsWith('file:'),\n };\n}\n\nfunction resolvePgFromEnv(): PgStorageConfig {\n const connectionString = process.env.MASTRA_PG_CONNECTION_STRING;\n if (connectionString) {\n return {\n backend: 'pg',\n connectionString,\n schemaName: process.env.MASTRA_PG_SCHEMA_NAME,\n };\n }\n\n // Host/port style\n return {\n backend: 'pg',\n host: process.env.MASTRA_PG_HOST,\n port: process.env.MASTRA_PG_PORT ? parseInt(process.env.MASTRA_PG_PORT, 10) : undefined,\n database: process.env.MASTRA_PG_DATABASE,\n user: process.env.MASTRA_PG_USER,\n password: process.env.MASTRA_PG_PASSWORD,\n schemaName: process.env.MASTRA_PG_SCHEMA_NAME,\n };\n}\n\nfunction resolvePgFromSettings(settings: StorageSettings): PgStorageConfig {\n const pg = settings.pg;\n return {\n backend: 'pg',\n connectionString: pg.connectionString,\n host: pg.host,\n port: pg.port,\n database: pg.database,\n user: pg.user,\n password: pg.password,\n schemaName: pg.schemaName,\n disableInit: pg.disableInit,\n skipDefaultIndexes: pg.skipDefaultIndexes,\n };\n}\n\n/**\n * Load database config from a legacy JSON file.\n * Expected format: { \"url\": \"libsql://...\", \"authToken\": \"...\" }\n */\nfunction loadDatabaseConfig(filePath: string): LibSQLStorageConfig | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (typeof parsed?.url === 'string' && parsed.url) {\n return {\n backend: 'libsql',\n url: parsed.url,\n authToken: typeof parsed.authToken === 'string' ? parsed.authToken : undefined,\n isRemote: !parsed.url.startsWith('file:'),\n };\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the current user identity.\n *\n * Priority:\n * 1. MASTRA_USER_ID environment variable\n * 2. git config user.email (from project dir or global)\n * 3. OS username as fallback\n */\nexport function getUserId(projectDir?: string): string {\n // 1. Environment variable override\n if (process.env.MASTRA_USER_ID) {\n return process.env.MASTRA_USER_ID;\n }\n\n // 2. git user.email\n const cwd = projectDir || process.cwd();\n const email = git('config user.email', cwd);\n if (email) {\n return email;\n }\n\n // 3. OS username fallback\n return os.userInfo().username || 'unknown';\n}\n\n/**\n * Get the current user's display name.\n *\n * Priority:\n * 1. git config user.name\n * 2. OS username as fallback\n */\nexport function getUserName(projectDir?: string): string {\n const cwd = projectDir || process.cwd();\n const name = git('config user.name', cwd);\n if (name) {\n return name;\n }\n return os.userInfo().username || 'unknown';\n}\n\n/**\n * Observational memory scope: \"thread\" (per-conversation) or \"resource\" (shared across threads).\n */\nexport type OmScope = 'thread' | 'resource';\n\n/**\n * Get the configured observational memory scope.\n *\n * Priority:\n * 1. MASTRA_OM_SCOPE environment variable (\"thread\" or \"resource\")\n * 2. Project config: .mastracode/database.json → omScope\n * 3. Global config: ~/.mastracode/database.json → omScope\n * 4. Default: \"thread\"\n */\nexport function getOmScope(projectDir?: string, configDirName = DEFAULT_CONFIG_DIR): OmScope {\n // 1. Environment variable\n const envScope = process.env.MASTRA_OM_SCOPE;\n if (envScope === 'thread' || envScope === 'resource') {\n return envScope;\n }\n\n // 2. Project-level config\n if (projectDir) {\n const scope = loadOmScopeFromConfig(path.join(projectDir, configDirName, 'database.json'));\n if (scope) return scope;\n }\n\n // 3. Global config\n const scope = loadOmScopeFromConfig(path.join(os.homedir(), configDirName, 'database.json'));\n if (scope) return scope;\n\n // 4. Default\n return 'thread';\n}\n\nfunction loadOmScopeFromConfig(filePath: string): OmScope | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed?.omScope === 'thread' || parsed?.omScope === 'resource') {\n return parsed.omScope;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get an explicit resource ID override, if configured.\n *\n * Resource IDs act as shared tags — two users who set the same resourceId\n * will share threads and observations for that resource.\n *\n * Priority:\n * 1. MASTRA_RESOURCE_ID environment variable\n * 2. Project config: .mastracode/database.json → resourceId\n * 3. Global config: ~/.mastracode/database.json → resourceId\n * 4. null (use auto-detected value)\n */\nexport function getResourceIdOverride(projectDir?: string, configDirName = DEFAULT_CONFIG_DIR): string | null {\n // 1. Environment variable\n if (process.env.MASTRA_RESOURCE_ID) {\n return process.env.MASTRA_RESOURCE_ID;\n }\n\n // 2. Project-level config\n if (projectDir) {\n const rid = loadStringField(path.join(projectDir, configDirName, 'database.json'), 'resourceId');\n if (rid) return rid;\n }\n\n // 3. Global config\n const rid = loadStringField(path.join(os.homedir(), configDirName, 'database.json'), 'resourceId');\n if (rid) return rid;\n\n return null;\n}\n\nfunction loadStringField(filePath: string, field: string): string | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw);\n const value = parsed?.[field];\n if (typeof value === 'string' && value) {\n return value;\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":["scope","rid"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { PubSub, UnixSocketPubSub } from '@mastra/core/events';
|
|
2
|
+
import type { PubSubDeliveryMode, Event, EventCallback, SubscribeOptions } from '@mastra/core/events';
|
|
3
|
+
/**
|
|
4
|
+
* A PubSub that manages one Unix socket per topic for cross-process signal
|
|
5
|
+
* coordination within a mastracode resource.
|
|
6
|
+
*
|
|
7
|
+
* Socket paths use `/tmp/mc/<resourceId>/<sanitized-topic>.sock` for
|
|
8
|
+
* inspectability and automatic OS cleanup. Each topic gets its own isolated
|
|
9
|
+
* socket so broker election and message routing are per-topic.
|
|
10
|
+
*
|
|
11
|
+
* Stale sockets from crashed processes are handled by
|
|
12
|
+
* {@link UnixSocketPubSub}'s built-in election logic: it detects
|
|
13
|
+
* ECONNREFUSED on a dead broker socket, unlinks it, and re-elects.
|
|
14
|
+
* No blanket cleanup is needed here — that would break concurrent
|
|
15
|
+
* mc instances sharing the same resourceId.
|
|
16
|
+
*/
|
|
17
|
+
declare class SignalsPubSub extends PubSub {
|
|
18
|
+
#private;
|
|
19
|
+
constructor(resourceId: string);
|
|
20
|
+
get supportedModes(): ReadonlyArray<PubSubDeliveryMode>;
|
|
21
|
+
publish(topic: string, event: Omit<Event, 'id' | 'createdAt'>, options?: {
|
|
22
|
+
localOnly?: boolean;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void>;
|
|
25
|
+
unsubscribe(topic: string, cb: EventCallback): Promise<void>;
|
|
26
|
+
flush(): Promise<void>;
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
/** Get the underlying socket for a topic (for testing/inspection). */
|
|
29
|
+
getSocket(topic: string): UnixSocketPubSub | undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates a per-topic PubSub backed by Unix sockets for cross-process signal
|
|
33
|
+
* and workflow event coordination within a mastracode resource.
|
|
34
|
+
*
|
|
35
|
+
* Each topic gets its own Unix socket under `/tmp/mc/<resourceId>/`.
|
|
36
|
+
* Stale sockets from crashed processes are handled by the underlying
|
|
37
|
+
* {@link UnixSocketPubSub}'s broker election logic.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createSignalsPubSub(resourceId: string): SignalsPubSub;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=signals-pubsub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals-pubsub.d.ts","sourceRoot":"","sources":["../../src/utils/signals-pubsub.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAItG;;;;;;;;;;;;;GAaG;AACH,cAAM,aAAc,SAAQ,MAAM;;gBAMpB,UAAU,EAAE,MAAM;IAK9B,IAAa,cAAc,IAAI,aAAa,CAAC,kBAAkB,CAAC,CAE/D;IAEK,OAAO,CACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,EACtC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAChC,OAAO,CAAC,IAAI,CAAC;IAKV,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtF,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,sEAAsE;IACtE,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;CAmEvD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAErE"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { PubSub, UnixSocketPubSub } from "@mastra/core/events";
|
|
5
|
+
const THREAD_STREAM_PREFIX = "agent.thread-stream.";
|
|
6
|
+
class SignalsPubSub extends PubSub {
|
|
7
|
+
#resourceId;
|
|
8
|
+
#sockets = /* @__PURE__ */ new Map();
|
|
9
|
+
#pending = /* @__PURE__ */ new Map();
|
|
10
|
+
#closed = false;
|
|
11
|
+
constructor(resourceId) {
|
|
12
|
+
super();
|
|
13
|
+
this.#resourceId = resourceId;
|
|
14
|
+
}
|
|
15
|
+
get supportedModes() {
|
|
16
|
+
return ["push"];
|
|
17
|
+
}
|
|
18
|
+
async publish(topic, event, options) {
|
|
19
|
+
const socket = await this.#getOrCreate(topic);
|
|
20
|
+
await socket.publish(topic, event, options);
|
|
21
|
+
}
|
|
22
|
+
async subscribe(topic, cb, options) {
|
|
23
|
+
const socket = await this.#getOrCreate(topic);
|
|
24
|
+
await socket.subscribe(topic, cb, options);
|
|
25
|
+
}
|
|
26
|
+
async unsubscribe(topic, cb) {
|
|
27
|
+
const socket = this.#sockets.get(this.#topicKey(topic));
|
|
28
|
+
if (!socket) return;
|
|
29
|
+
await socket.unsubscribe(topic, cb);
|
|
30
|
+
}
|
|
31
|
+
async flush() {
|
|
32
|
+
await Promise.all([...this.#sockets.values()].map((s) => s.flush()));
|
|
33
|
+
}
|
|
34
|
+
async close() {
|
|
35
|
+
this.#closed = true;
|
|
36
|
+
await Promise.allSettled([...this.#sockets.values()].map((s) => s.close()));
|
|
37
|
+
this.#sockets.clear();
|
|
38
|
+
}
|
|
39
|
+
/** Get the underlying socket for a topic (for testing/inspection). */
|
|
40
|
+
getSocket(topic) {
|
|
41
|
+
return this.#sockets.get(this.#topicKey(topic));
|
|
42
|
+
}
|
|
43
|
+
async #getOrCreate(topic) {
|
|
44
|
+
if (this.#closed) throw new Error("SignalsPubSub is closed");
|
|
45
|
+
const key = this.#topicKey(topic);
|
|
46
|
+
const existing = this.#sockets.get(key);
|
|
47
|
+
if (existing) return existing;
|
|
48
|
+
let inflight = this.#pending.get(key);
|
|
49
|
+
if (!inflight) {
|
|
50
|
+
inflight = this.#initSocket(topic, key);
|
|
51
|
+
this.#pending.set(key, inflight);
|
|
52
|
+
}
|
|
53
|
+
const socket = await inflight;
|
|
54
|
+
if (this.#closed) throw new Error("SignalsPubSub is closed");
|
|
55
|
+
return socket;
|
|
56
|
+
}
|
|
57
|
+
async #initSocket(topic, key) {
|
|
58
|
+
try {
|
|
59
|
+
const socketPath = await this.#socketPath(topic);
|
|
60
|
+
if (this.#closed) throw new Error("SignalsPubSub is closed");
|
|
61
|
+
const socket = new UnixSocketPubSub(socketPath);
|
|
62
|
+
this.#sockets.set(key, socket);
|
|
63
|
+
return socket;
|
|
64
|
+
} finally {
|
|
65
|
+
this.#pending.delete(key);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async #socketPath(topic) {
|
|
69
|
+
let key = this.#topicKey(topic);
|
|
70
|
+
const dir = join("/tmp/mc", this.#resourceId);
|
|
71
|
+
await mkdir(dir, { recursive: true });
|
|
72
|
+
const candidate = join(dir, `${key}.sock`);
|
|
73
|
+
if (Buffer.byteLength(candidate) > 104) {
|
|
74
|
+
key = createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
75
|
+
return join(dir, `${key}.sock`);
|
|
76
|
+
}
|
|
77
|
+
return candidate;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Derive a filesystem-safe key for the topic. Thread-stream topics embed
|
|
81
|
+
* a threadId; all other topics use a sanitized version of the topic name.
|
|
82
|
+
*/
|
|
83
|
+
#topicKey(topic) {
|
|
84
|
+
if (topic.startsWith(THREAD_STREAM_PREFIX)) {
|
|
85
|
+
const encoded = topic.slice(THREAD_STREAM_PREFIX.length);
|
|
86
|
+
try {
|
|
87
|
+
const decoded = decodeURIComponent(encoded);
|
|
88
|
+
const separatorIdx = decoded.indexOf("\0");
|
|
89
|
+
if (separatorIdx !== -1) {
|
|
90
|
+
return decoded.slice(separatorIdx + 1);
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return topic.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function createSignalsPubSub(resourceId) {
|
|
99
|
+
return new SignalsPubSub(resourceId);
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
createSignalsPubSub
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=signals-pubsub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/signals-pubsub.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { PubSub, UnixSocketPubSub } from '@mastra/core/events';\nimport type { PubSubDeliveryMode, Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nconst THREAD_STREAM_PREFIX = 'agent.thread-stream.';\n\n/**\n * A PubSub that manages one Unix socket per topic for cross-process signal\n * coordination within a mastracode resource.\n *\n * Socket paths use `/tmp/mc/<resourceId>/<sanitized-topic>.sock` for\n * inspectability and automatic OS cleanup. Each topic gets its own isolated\n * socket so broker election and message routing are per-topic.\n *\n * Stale sockets from crashed processes are handled by\n * {@link UnixSocketPubSub}'s built-in election logic: it detects\n * ECONNREFUSED on a dead broker socket, unlinks it, and re-elects.\n * No blanket cleanup is needed here — that would break concurrent\n * mc instances sharing the same resourceId.\n */\nclass SignalsPubSub extends PubSub {\n readonly #resourceId: string;\n readonly #sockets = new Map<string, UnixSocketPubSub>();\n readonly #pending = new Map<string, Promise<UnixSocketPubSub>>();\n #closed = false;\n\n constructor(resourceId: string) {\n super();\n this.#resourceId = resourceId;\n }\n\n override get supportedModes(): ReadonlyArray<PubSubDeliveryMode> {\n return ['push'];\n }\n\n async publish(\n topic: string,\n event: Omit<Event, 'id' | 'createdAt'>,\n options?: { localOnly?: boolean },\n ): Promise<void> {\n const socket = await this.#getOrCreate(topic);\n await socket.publish(topic, event, options);\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n const socket = await this.#getOrCreate(topic);\n await socket.subscribe(topic, cb, options);\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n const socket = this.#sockets.get(this.#topicKey(topic));\n if (!socket) return;\n await socket.unsubscribe(topic, cb);\n }\n\n async flush(): Promise<void> {\n await Promise.all([...this.#sockets.values()].map(s => s.flush()));\n }\n\n async close(): Promise<void> {\n this.#closed = true;\n await Promise.allSettled([...this.#sockets.values()].map(s => s.close()));\n this.#sockets.clear();\n }\n\n /** Get the underlying socket for a topic (for testing/inspection). */\n getSocket(topic: string): UnixSocketPubSub | undefined {\n return this.#sockets.get(this.#topicKey(topic));\n }\n\n async #getOrCreate(topic: string): Promise<UnixSocketPubSub> {\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n const key = this.#topicKey(topic);\n const existing = this.#sockets.get(key);\n if (existing) return existing;\n // Deduplicate concurrent callers so only one socket is created per topic.\n let inflight = this.#pending.get(key);\n if (!inflight) {\n inflight = this.#initSocket(topic, key);\n this.#pending.set(key, inflight);\n }\n const socket = await inflight;\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n return socket;\n }\n\n async #initSocket(topic: string, key: string): Promise<UnixSocketPubSub> {\n try {\n const socketPath = await this.#socketPath(topic);\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n const socket = new UnixSocketPubSub(socketPath);\n this.#sockets.set(key, socket);\n return socket;\n } finally {\n this.#pending.delete(key);\n }\n }\n\n async #socketPath(topic: string): Promise<string> {\n let key = this.#topicKey(topic);\n const dir = join('/tmp/mc', this.#resourceId);\n await mkdir(dir, { recursive: true });\n const candidate = join(dir, `${key}.sock`);\n // macOS sun_path limit is 104 bytes; Linux is 108. Use 104 as the\n // conservative bound. When the path is too long, replace the key with\n // a short hash so the socket can still be created.\n if (Buffer.byteLength(candidate) > 104) {\n key = createHash('sha256').update(key).digest('hex').slice(0, 16);\n return join(dir, `${key}.sock`);\n }\n return candidate;\n }\n\n /**\n * Derive a filesystem-safe key for the topic. Thread-stream topics embed\n * a threadId; all other topics use a sanitized version of the topic name.\n */\n #topicKey(topic: string): string {\n if (topic.startsWith(THREAD_STREAM_PREFIX)) {\n const encoded = topic.slice(THREAD_STREAM_PREFIX.length);\n try {\n const decoded = decodeURIComponent(encoded);\n const separatorIdx = decoded.indexOf('\\0');\n if (separatorIdx !== -1) {\n return decoded.slice(separatorIdx + 1);\n }\n } catch {\n // Malformed URI — fall through to sanitized fallback.\n }\n }\n // Fallback: use the topic directly (sanitized for filesystem)\n return topic.replace(/[^a-zA-Z0-9_-]/g, '_');\n }\n}\n\n/**\n * Creates a per-topic PubSub backed by Unix sockets for cross-process signal\n * and workflow event coordination within a mastracode resource.\n *\n * Each topic gets its own Unix socket under `/tmp/mc/<resourceId>/`.\n * Stale sockets from crashed processes are handled by the underlying\n * {@link UnixSocketPubSub}'s broker election logic.\n */\nexport function createSignalsPubSub(resourceId: string): SignalsPubSub {\n return new SignalsPubSub(resourceId);\n}\n"],"mappings":"AAAA,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,YAAY;AAErB,SAAS,QAAQ,wBAAwB;AAGzC,MAAM,uBAAuB;AAgB7B,MAAM,sBAAsB,OAAO;AAAA,EACxB;AAAA,EACA,WAAW,oBAAI,IAA8B;AAAA,EAC7C,WAAW,oBAAI,IAAuC;AAAA,EAC/D,UAAU;AAAA,EAEV,YAAY,YAAoB;AAC9B,UAAM;AACN,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,IAAa,iBAAoD;AAC/D,WAAO,CAAC,MAAM;AAAA,EAChB;AAAA,EAEA,MAAM,QACJ,OACA,OACA,SACe;AACf,UAAM,SAAS,MAAM,KAAK,aAAa,KAAK;AAC5C,UAAM,OAAO,QAAQ,OAAO,OAAO,OAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAU,OAAe,IAAmB,SAA2C;AAC3F,UAAM,SAAS,MAAM,KAAK,aAAa,KAAK;AAC5C,UAAM,OAAO,UAAU,OAAO,IAAI,OAAO;AAAA,EAC3C;AAAA,EAEA,MAAM,YAAY,OAAe,IAAkC;AACjE,UAAM,SAAS,KAAK,SAAS,IAAI,KAAK,UAAU,KAAK,CAAC;AACtD,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,YAAY,OAAO,EAAE;AAAA,EACpC;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,MAAM,CAAC,CAAC;AAAA,EACnE;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,UAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,MAAM,CAAC,CAAC;AACxE,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA,EAGA,UAAU,OAA6C;AACrD,WAAO,KAAK,SAAS,IAAI,KAAK,UAAU,KAAK,CAAC;AAAA,EAChD;AAAA,EAEA,MAAM,aAAa,OAA0C;AAC3D,QAAI,KAAK,QAAS,OAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAM,MAAM,KAAK,UAAU,KAAK;AAChC,UAAM,WAAW,KAAK,SAAS,IAAI,GAAG;AACtC,QAAI,SAAU,QAAO;AAErB,QAAI,WAAW,KAAK,SAAS,IAAI,GAAG;AACpC,QAAI,CAAC,UAAU;AACb,iBAAW,KAAK,YAAY,OAAO,GAAG;AACtC,WAAK,SAAS,IAAI,KAAK,QAAQ;AAAA,IACjC;AACA,UAAM,SAAS,MAAM;AACrB,QAAI,KAAK,QAAS,OAAM,IAAI,MAAM,yBAAyB;AAC3D,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,OAAe,KAAwC;AACvE,QAAI;AACF,YAAM,aAAa,MAAM,KAAK,YAAY,KAAK;AAC/C,UAAI,KAAK,QAAS,OAAM,IAAI,MAAM,yBAAyB;AAC3D,YAAM,SAAS,IAAI,iBAAiB,UAAU;AAC9C,WAAK,SAAS,IAAI,KAAK,MAAM;AAC7B,aAAO;AAAA,IACT,UAAE;AACA,WAAK,SAAS,OAAO,GAAG;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAgC;AAChD,QAAI,MAAM,KAAK,UAAU,KAAK;AAC9B,UAAM,MAAM,KAAK,WAAW,KAAK,WAAW;AAC5C,UAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,YAAY,KAAK,KAAK,GAAG,GAAG,OAAO;AAIzC,QAAI,OAAO,WAAW,SAAS,IAAI,KAAK;AACtC,YAAM,WAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAChE,aAAO,KAAK,KAAK,GAAG,GAAG,OAAO;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,OAAuB;AAC/B,QAAI,MAAM,WAAW,oBAAoB,GAAG;AAC1C,YAAM,UAAU,MAAM,MAAM,qBAAqB,MAAM;AACvD,UAAI;AACF,cAAM,UAAU,mBAAmB,OAAO;AAC1C,cAAM,eAAe,QAAQ,QAAQ,IAAI;AACzC,YAAI,iBAAiB,IAAI;AACvB,iBAAO,QAAQ,MAAM,eAAe,CAAC;AAAA,QACvC;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,MAAM,QAAQ,mBAAmB,GAAG;AAAA,EAC7C;AACF;AAUO,SAAS,oBAAoB,YAAmC;AACrE,SAAO,IAAI,cAAc,UAAU;AACrC;","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata for a slash command
|
|
3
|
+
*/
|
|
4
|
+
export interface SlashCommandMetadata {
|
|
5
|
+
/** Command name (e.g., "git:commit") */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Human-readable description */
|
|
8
|
+
description: string;
|
|
9
|
+
/** The command template with variables */
|
|
10
|
+
template: string;
|
|
11
|
+
/** Source file path */
|
|
12
|
+
sourcePath: string;
|
|
13
|
+
/** Namespace derived from directory structure */
|
|
14
|
+
namespace?: string;
|
|
15
|
+
/** Whether this command should also be exposed as /goal/<name> */
|
|
16
|
+
goal?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse a command file and extract metadata and template
|
|
20
|
+
* Supports both frontmatter-based and plain markdown files
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseCommandFile(filePath: string, baseDir?: string): Promise<SlashCommandMetadata | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Extract command name from file path
|
|
25
|
+
* Converts path like "git/commit.md" to "git:commit"
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractCommandName(filePath: string, baseDir: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Recursively scan a directory for command files.
|
|
30
|
+
* @param dirPath - Current directory to scan
|
|
31
|
+
* @param rootDir - Original root commands directory (used for namespace derivation).
|
|
32
|
+
* When omitted the first call sets it to dirPath.
|
|
33
|
+
*/
|
|
34
|
+
export declare function scanCommandDirectory(dirPath: string, rootDir?: string): Promise<SlashCommandMetadata[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Load custom slash commands from all configured directories
|
|
37
|
+
* Priority: mastra project > claude project > opencode project > mastra user > claude user > opencode user
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadCustomCommands(projectDir?: string, configDirName?: string, extraCommandDirs?: string[]): Promise<SlashCommandMetadata[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the commands directory path for a project
|
|
42
|
+
*/
|
|
43
|
+
export declare function getProjectCommandsDir(projectDir: string, configDirName?: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Initialize a commands directory with an example command
|
|
46
|
+
*/
|
|
47
|
+
export declare function initCommandsDirectory(projectDir: string, configDirName?: string): Promise<void>;
|
|
48
|
+
//# sourceMappingURL=slash-command-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slash-command-loader.d.ts","sourceRoot":"","sources":["../../src/utils/slash-command-loader.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAqD/G;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAY5E;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA2B7G;AACD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,SAAqB,EAClC,gBAAgB,GAAE,MAAM,EAAO,GAC9B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA4DjC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,SAAqB,GAAG,MAAM,CAEpG;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,SAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BjH"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import { DEFAULT_CONFIG_DIR } from "../constants.js";
|
|
5
|
+
async function parseCommandFile(filePath, baseDir) {
|
|
6
|
+
try {
|
|
7
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
8
|
+
const trimmedContent = content.trim();
|
|
9
|
+
if (!trimmedContent.startsWith("---")) {
|
|
10
|
+
const name2 = baseDir ? extractCommandName(filePath, baseDir) : path.basename(filePath, ".md");
|
|
11
|
+
return {
|
|
12
|
+
name: name2,
|
|
13
|
+
description: "",
|
|
14
|
+
template: content,
|
|
15
|
+
sourcePath: filePath
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const parts = content.split("---");
|
|
19
|
+
if (parts.length < 3) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const frontmatter = parts[1].trim();
|
|
23
|
+
const template = parts.slice(2).join("---").trim();
|
|
24
|
+
const metadata = parseYaml(frontmatter);
|
|
25
|
+
let name;
|
|
26
|
+
if (typeof metadata?.name === "string" && metadata.name) {
|
|
27
|
+
name = metadata.name;
|
|
28
|
+
} else if (baseDir) {
|
|
29
|
+
name = extractCommandName(filePath, baseDir);
|
|
30
|
+
} else {
|
|
31
|
+
name = path.basename(filePath, ".md");
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
name,
|
|
35
|
+
description: typeof metadata?.description === "string" ? metadata.description : "",
|
|
36
|
+
template,
|
|
37
|
+
sourcePath: filePath,
|
|
38
|
+
namespace: typeof metadata?.namespace === "string" ? metadata.namespace : void 0,
|
|
39
|
+
goal: metadata?.goal === true
|
|
40
|
+
};
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(`Error parsing command file ${filePath}:`, error);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function extractCommandName(filePath, baseDir) {
|
|
47
|
+
const relativePath = path.relative(baseDir, filePath);
|
|
48
|
+
const dirName = path.dirname(relativePath);
|
|
49
|
+
const baseName = path.basename(relativePath, ".md");
|
|
50
|
+
if (dirName === "." || dirName === "") {
|
|
51
|
+
return baseName;
|
|
52
|
+
}
|
|
53
|
+
const namespace = dirName.replace(/[\\/]/g, ":");
|
|
54
|
+
return `${namespace}:${baseName}`;
|
|
55
|
+
}
|
|
56
|
+
async function scanCommandDirectory(dirPath, rootDir) {
|
|
57
|
+
const baseDir = rootDir ?? dirPath;
|
|
58
|
+
const commands = [];
|
|
59
|
+
try {
|
|
60
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
63
|
+
if (entry.isDirectory()) {
|
|
64
|
+
const subCommands = await scanCommandDirectory(fullPath, baseDir);
|
|
65
|
+
commands.push(...subCommands);
|
|
66
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
67
|
+
const command = await parseCommandFile(fullPath, baseDir);
|
|
68
|
+
if (command) {
|
|
69
|
+
commands.push(command);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
return commands;
|
|
76
|
+
}
|
|
77
|
+
async function loadCustomCommands(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraCommandDirs = []) {
|
|
78
|
+
const commandMap = /* @__PURE__ */ new Map();
|
|
79
|
+
const addCommands = (newCommands) => {
|
|
80
|
+
for (const cmd of newCommands) {
|
|
81
|
+
commandMap.set(cmd.name, cmd);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
85
|
+
if (homeDir) {
|
|
86
|
+
const opencodeUserDir = path.join(homeDir, ".opencode", "command");
|
|
87
|
+
const opencodeUserCommands = await scanCommandDirectory(opencodeUserDir);
|
|
88
|
+
addCommands(opencodeUserCommands);
|
|
89
|
+
}
|
|
90
|
+
if (homeDir) {
|
|
91
|
+
const claudeUserDir = path.join(homeDir, ".claude", "commands");
|
|
92
|
+
const claudeUserCommands = await scanCommandDirectory(claudeUserDir);
|
|
93
|
+
addCommands(claudeUserCommands);
|
|
94
|
+
}
|
|
95
|
+
if (homeDir) {
|
|
96
|
+
const mastraUserDir = path.join(homeDir, configDirName, "commands");
|
|
97
|
+
const mastraUserCommands = await scanCommandDirectory(mastraUserDir);
|
|
98
|
+
addCommands(mastraUserCommands);
|
|
99
|
+
}
|
|
100
|
+
if (projectDir) {
|
|
101
|
+
const opencodeProjectDir = path.join(projectDir, ".opencode", "command");
|
|
102
|
+
const opencodeProjectCommands = await scanCommandDirectory(opencodeProjectDir);
|
|
103
|
+
addCommands(opencodeProjectCommands);
|
|
104
|
+
}
|
|
105
|
+
if (projectDir) {
|
|
106
|
+
const claudeProjectDir = path.join(projectDir, ".claude", "commands");
|
|
107
|
+
const claudeProjectCommands = await scanCommandDirectory(claudeProjectDir);
|
|
108
|
+
addCommands(claudeProjectCommands);
|
|
109
|
+
}
|
|
110
|
+
if (projectDir) {
|
|
111
|
+
const mastraProjectDir = path.join(projectDir, configDirName, "commands");
|
|
112
|
+
const mastraProjectCommands = await scanCommandDirectory(mastraProjectDir);
|
|
113
|
+
addCommands(mastraProjectCommands);
|
|
114
|
+
}
|
|
115
|
+
for (const commandsDir of extraCommandDirs) {
|
|
116
|
+
addCommands(await scanCommandDirectory(commandsDir));
|
|
117
|
+
}
|
|
118
|
+
return Array.from(commandMap.values());
|
|
119
|
+
}
|
|
120
|
+
function getProjectCommandsDir(projectDir, configDirName = DEFAULT_CONFIG_DIR) {
|
|
121
|
+
return path.join(projectDir, configDirName, "commands");
|
|
122
|
+
}
|
|
123
|
+
async function initCommandsDirectory(projectDir, configDirName = DEFAULT_CONFIG_DIR) {
|
|
124
|
+
const commandsDir = getProjectCommandsDir(projectDir, configDirName);
|
|
125
|
+
try {
|
|
126
|
+
await fs.mkdir(commandsDir, { recursive: true });
|
|
127
|
+
const examplePath = path.join(commandsDir, "example.md");
|
|
128
|
+
const exampleContent = `---
|
|
129
|
+
name: example
|
|
130
|
+
description: An example slash command
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
This is an example slash command template.
|
|
134
|
+
You can use variables like $ARGUMENTS or $1, $2 for positional args.
|
|
135
|
+
You can also include file content with @filename.
|
|
136
|
+
Shell commands with !command will be executed and output included.
|
|
137
|
+
`;
|
|
138
|
+
try {
|
|
139
|
+
await fs.access(examplePath);
|
|
140
|
+
} catch {
|
|
141
|
+
await fs.writeFile(examplePath, exampleContent, "utf-8");
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error("Error initializing commands directory:", error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
extractCommandName,
|
|
149
|
+
getProjectCommandsDir,
|
|
150
|
+
initCommandsDirectory,
|
|
151
|
+
loadCustomCommands,
|
|
152
|
+
parseCommandFile,
|
|
153
|
+
scanCommandDirectory
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=slash-command-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/slash-command-loader.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\n\n/**\n * Metadata for a slash command\n */\nexport interface SlashCommandMetadata {\n /** Command name (e.g., \"git:commit\") */\n name: string;\n /** Human-readable description */\n description: string;\n /** The command template with variables */\n template: string;\n /** Source file path */\n sourcePath: string;\n /** Namespace derived from directory structure */\n namespace?: string;\n /** Whether this command should also be exposed as /goal/<name> */\n goal?: boolean;\n}\n\n/**\n * Parse a command file and extract metadata and template\n * Supports both frontmatter-based and plain markdown files\n */\nexport async function parseCommandFile(filePath: string, baseDir?: string): Promise<SlashCommandMetadata | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const trimmedContent = content.trim();\n\n // Check if file has frontmatter (starts with ---)\n if (!trimmedContent.startsWith('---')) {\n // No frontmatter - treat entire file as template\n // Derive name from file path\n const name = baseDir ? extractCommandName(filePath, baseDir) : path.basename(filePath, '.md');\n\n return {\n name,\n description: '',\n template: content,\n sourcePath: filePath,\n };\n }\n\n // Split frontmatter and template\n const parts = content.split('---');\n if (parts.length < 3) {\n return null;\n }\n\n const frontmatter = parts[1]!.trim();\n const template = parts.slice(2).join('---').trim();\n\n // Parse YAML frontmatter\n const metadata = parseYaml(frontmatter) as Record<string, unknown>;\n\n // Derive name from file path if not specified in frontmatter\n let name: string;\n if (typeof metadata?.name === 'string' && metadata.name) {\n name = metadata.name;\n } else if (baseDir) {\n name = extractCommandName(filePath, baseDir);\n } else {\n name = path.basename(filePath, '.md');\n }\n\n return {\n name,\n description: typeof metadata?.description === 'string' ? metadata.description : '',\n template,\n sourcePath: filePath,\n namespace: typeof metadata?.namespace === 'string' ? metadata.namespace : undefined,\n goal: metadata?.goal === true,\n };\n } catch (error) {\n console.error(`Error parsing command file ${filePath}:`, error);\n return null;\n }\n}\n\n/**\n * Extract command name from file path\n * Converts path like \"git/commit.md\" to \"git:commit\"\n */\nexport function extractCommandName(filePath: string, baseDir: string): string {\n const relativePath = path.relative(baseDir, filePath);\n const dirName = path.dirname(relativePath);\n const baseName = path.basename(relativePath, '.md');\n\n if (dirName === '.' || dirName === '') {\n return baseName;\n }\n\n // Replace path separators with colons for namespacing\n const namespace = dirName.replace(/[\\\\/]/g, ':');\n return `${namespace}:${baseName}`;\n}\n\n/**\n * Recursively scan a directory for command files.\n * @param dirPath - Current directory to scan\n * @param rootDir - Original root commands directory (used for namespace derivation).\n * When omitted the first call sets it to dirPath.\n */\nexport async function scanCommandDirectory(dirPath: string, rootDir?: string): Promise<SlashCommandMetadata[]> {\n const baseDir = rootDir ?? dirPath;\n const commands: SlashCommandMetadata[] = [];\n\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n // Recursively scan subdirectories, preserving the root directory for namespace derivation\n const subCommands = await scanCommandDirectory(fullPath, baseDir);\n commands.push(...subCommands);\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n // Parse markdown command files, passing the root commands dir as baseDir for name derivation\n const command = await parseCommandFile(fullPath, baseDir);\n if (command) {\n commands.push(command);\n }\n }\n }\n } catch {\n // Directory doesn't exist or can't be read - silently skip\n }\n\n return commands;\n}\n/**\n * Load custom slash commands from all configured directories\n * Priority: mastra project > claude project > opencode project > mastra user > claude user > opencode user\n */\nexport async function loadCustomCommands(\n projectDir?: string,\n configDirName = DEFAULT_CONFIG_DIR,\n extraCommandDirs: string[] = [],\n): Promise<SlashCommandMetadata[]> {\n // Use a Map so later (higher priority) sources override earlier ones with the same name\n const commandMap = new Map<string, SlashCommandMetadata>();\n\n const addCommands = (newCommands: SlashCommandMetadata[]) => {\n for (const cmd of newCommands) {\n commandMap.set(cmd.name, cmd);\n }\n };\n\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n\n // 1. Load from opencode user directory ~/.opencode/command (lowest priority)\n if (homeDir) {\n const opencodeUserDir = path.join(homeDir, '.opencode', 'command');\n const opencodeUserCommands = await scanCommandDirectory(opencodeUserDir);\n addCommands(opencodeUserCommands);\n }\n\n // 2. Load from claude user directory ~/.claude/commands (Claude Code compat)\n if (homeDir) {\n const claudeUserDir = path.join(homeDir, '.claude', 'commands');\n const claudeUserCommands = await scanCommandDirectory(claudeUserDir);\n addCommands(claudeUserCommands);\n }\n\n // 3. Load from mastra user directory ~/<configDirName>/commands\n if (homeDir) {\n const mastraUserDir = path.join(homeDir, configDirName, 'commands');\n const mastraUserCommands = await scanCommandDirectory(mastraUserDir);\n addCommands(mastraUserCommands);\n }\n\n // 4. Load from opencode project directory .opencode/command\n if (projectDir) {\n const opencodeProjectDir = path.join(projectDir, '.opencode', 'command');\n const opencodeProjectCommands = await scanCommandDirectory(opencodeProjectDir);\n addCommands(opencodeProjectCommands);\n }\n\n // 5. Load from claude project directory .claude/commands (Claude Code compat)\n if (projectDir) {\n const claudeProjectDir = path.join(projectDir, '.claude', 'commands');\n const claudeProjectCommands = await scanCommandDirectory(claudeProjectDir);\n addCommands(claudeProjectCommands);\n }\n\n // 6. Load from mastra project directory <configDirName>/commands\n if (projectDir) {\n const mastraProjectDir = path.join(projectDir, configDirName, 'commands');\n const mastraProjectCommands = await scanCommandDirectory(mastraProjectDir);\n addCommands(mastraProjectCommands);\n }\n\n // 7. Load from active plugin command directories (highest priority)\n for (const commandsDir of extraCommandDirs) {\n addCommands(await scanCommandDirectory(commandsDir));\n }\n\n return Array.from(commandMap.values());\n}\n\n/**\n * Get the commands directory path for a project\n */\nexport function getProjectCommandsDir(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(projectDir, configDirName, 'commands');\n}\n\n/**\n * Initialize a commands directory with an example command\n */\nexport async function initCommandsDirectory(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): Promise<void> {\n const commandsDir = getProjectCommandsDir(projectDir, configDirName);\n\n try {\n await fs.mkdir(commandsDir, { recursive: true });\n\n // Create an example command\n const examplePath = path.join(commandsDir, 'example.md');\n const exampleContent = `---\nname: example\ndescription: An example slash command\n---\n\nThis is an example slash command template.\nYou can use variables like \\$ARGUMENTS or \\$1, \\$2 for positional args.\nYou can also include file content with @filename.\nShell commands with !command will be executed and output included.\n`;\n\n try {\n await fs.access(examplePath);\n // File already exists, don't overwrite\n } catch {\n await fs.writeFile(examplePath, exampleContent, 'utf-8');\n }\n } catch (error) {\n console.error('Error initializing commands directory:', error);\n }\n}\n"],"mappings":"AAAA,SAAS,YAAY,UAAU;AAC/B,YAAY,UAAU;AACtB,SAAS,SAAS,iBAAiB;AACnC,SAAS,0BAA0B;AAwBnC,eAAsB,iBAAiB,UAAkB,SAAwD;AAC/G,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,SAAS,UAAU,OAAO;AACnD,UAAM,iBAAiB,QAAQ,KAAK;AAGpC,QAAI,CAAC,eAAe,WAAW,KAAK,GAAG;AAGrC,YAAMA,QAAO,UAAU,mBAAmB,UAAU,OAAO,IAAI,KAAK,SAAS,UAAU,KAAK;AAE5F,aAAO;AAAA,QACL,MAAAA;AAAA,QACA,aAAa;AAAA,QACb,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAAA,IACF;AAGA,UAAM,QAAQ,QAAQ,MAAM,KAAK;AACjC,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,MAAM,CAAC,EAAG,KAAK;AACnC,UAAM,WAAW,MAAM,MAAM,CAAC,EAAE,KAAK,KAAK,EAAE,KAAK;AAGjD,UAAM,WAAW,UAAU,WAAW;AAGtC,QAAI;AACJ,QAAI,OAAO,UAAU,SAAS,YAAY,SAAS,MAAM;AACvD,aAAO,SAAS;AAAA,IAClB,WAAW,SAAS;AAClB,aAAO,mBAAmB,UAAU,OAAO;AAAA,IAC7C,OAAO;AACL,aAAO,KAAK,SAAS,UAAU,KAAK;AAAA,IACtC;AAEA,WAAO;AAAA,MACL;AAAA,MACA,aAAa,OAAO,UAAU,gBAAgB,WAAW,SAAS,cAAc;AAAA,MAChF;AAAA,MACA,YAAY;AAAA,MACZ,WAAW,OAAO,UAAU,cAAc,WAAW,SAAS,YAAY;AAAA,MAC1E,MAAM,UAAU,SAAS;AAAA,IAC3B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,8BAA8B,QAAQ,KAAK,KAAK;AAC9D,WAAO;AAAA,EACT;AACF;AAMO,SAAS,mBAAmB,UAAkB,SAAyB;AAC5E,QAAM,eAAe,KAAK,SAAS,SAAS,QAAQ;AACpD,QAAM,UAAU,KAAK,QAAQ,YAAY;AACzC,QAAM,WAAW,KAAK,SAAS,cAAc,KAAK;AAElD,MAAI,YAAY,OAAO,YAAY,IAAI;AACrC,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,QAAQ,QAAQ,UAAU,GAAG;AAC/C,SAAO,GAAG,SAAS,IAAI,QAAQ;AACjC;AAQA,eAAsB,qBAAqB,SAAiB,SAAmD;AAC7G,QAAM,UAAU,WAAW;AAC3B,QAAM,WAAmC,CAAC;AAE1C,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAEjE,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,KAAK,KAAK,SAAS,MAAM,IAAI;AAE9C,UAAI,MAAM,YAAY,GAAG;AAEvB,cAAM,cAAc,MAAM,qBAAqB,UAAU,OAAO;AAChE,iBAAS,KAAK,GAAG,WAAW;AAAA,MAC9B,WAAW,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,KAAK,GAAG;AAEvD,cAAM,UAAU,MAAM,iBAAiB,UAAU,OAAO;AACxD,YAAI,SAAS;AACX,mBAAS,KAAK,OAAO;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;AAKA,eAAsB,mBACpB,YACA,gBAAgB,oBAChB,mBAA6B,CAAC,GACG;AAEjC,QAAM,aAAa,oBAAI,IAAkC;AAEzD,QAAM,cAAc,CAAC,gBAAwC;AAC3D,eAAW,OAAO,aAAa;AAC7B,iBAAW,IAAI,IAAI,MAAM,GAAG;AAAA,IAC9B;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,IAAI,QAAQ,QAAQ,IAAI;AAGhD,MAAI,SAAS;AACX,UAAM,kBAAkB,KAAK,KAAK,SAAS,aAAa,SAAS;AACjE,UAAM,uBAAuB,MAAM,qBAAqB,eAAe;AACvE,gBAAY,oBAAoB;AAAA,EAClC;AAGA,MAAI,SAAS;AACX,UAAM,gBAAgB,KAAK,KAAK,SAAS,WAAW,UAAU;AAC9D,UAAM,qBAAqB,MAAM,qBAAqB,aAAa;AACnE,gBAAY,kBAAkB;AAAA,EAChC;AAGA,MAAI,SAAS;AACX,UAAM,gBAAgB,KAAK,KAAK,SAAS,eAAe,UAAU;AAClE,UAAM,qBAAqB,MAAM,qBAAqB,aAAa;AACnE,gBAAY,kBAAkB;AAAA,EAChC;AAGA,MAAI,YAAY;AACd,UAAM,qBAAqB,KAAK,KAAK,YAAY,aAAa,SAAS;AACvE,UAAM,0BAA0B,MAAM,qBAAqB,kBAAkB;AAC7E,gBAAY,uBAAuB;AAAA,EACrC;AAGA,MAAI,YAAY;AACd,UAAM,mBAAmB,KAAK,KAAK,YAAY,WAAW,UAAU;AACpE,UAAM,wBAAwB,MAAM,qBAAqB,gBAAgB;AACzE,gBAAY,qBAAqB;AAAA,EACnC;AAGA,MAAI,YAAY;AACd,UAAM,mBAAmB,KAAK,KAAK,YAAY,eAAe,UAAU;AACxE,UAAM,wBAAwB,MAAM,qBAAqB,gBAAgB;AACzE,gBAAY,qBAAqB;AAAA,EACnC;AAGA,aAAW,eAAe,kBAAkB;AAC1C,gBAAY,MAAM,qBAAqB,WAAW,CAAC;AAAA,EACrD;AAEA,SAAO,MAAM,KAAK,WAAW,OAAO,CAAC;AACvC;AAKO,SAAS,sBAAsB,YAAoB,gBAAgB,oBAA4B;AACpG,SAAO,KAAK,KAAK,YAAY,eAAe,UAAU;AACxD;AAKA,eAAsB,sBAAsB,YAAoB,gBAAgB,oBAAmC;AACjH,QAAM,cAAc,sBAAsB,YAAY,aAAa;AAEnE,MAAI;AACF,UAAM,GAAG,MAAM,aAAa,EAAE,WAAW,KAAK,CAAC;AAG/C,UAAM,cAAc,KAAK,KAAK,aAAa,YAAY;AACvD,UAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWvB,QAAI;AACF,YAAM,GAAG,OAAO,WAAW;AAAA,IAE7B,QAAQ;AACN,YAAM,GAAG,UAAU,aAAa,gBAAgB,OAAO;AAAA,IACzD;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,0CAA0C,KAAK;AAAA,EAC/D;AACF;","names":["name"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SlashCommandMetadata } from './slash-command-loader.js';
|
|
2
|
+
/**
|
|
3
|
+
* Process a slash command by replacing variables and executing shell commands
|
|
4
|
+
*/
|
|
5
|
+
export declare function processSlashCommand(command: SlashCommandMetadata, args: string[], workingDir: string): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Format a command for display in help/autocomplete
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatCommandForDisplay(command: SlashCommandMetadata): string;
|
|
10
|
+
/**
|
|
11
|
+
* Group commands by namespace for display
|
|
12
|
+
*/
|
|
13
|
+
export declare function groupCommandsByNamespace(commands: SlashCommandMetadata[]): Map<string, SlashCommandMetadata[]>;
|
|
14
|
+
//# sourceMappingURL=slash-command-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slash-command-processor.d.ts","sourceRoot":"","sources":["../../src/utils/slash-command-processor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,oBAAoB,EAC7B,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AA0FD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAQ7E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAc9G"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
async function processSlashCommand(command, args, workingDir) {
|
|
5
|
+
const { result: withArgs, shouldAppendRawArgs } = replaceArguments(command.template, args);
|
|
6
|
+
let result = withArgs;
|
|
7
|
+
result = await replaceShellOutput(result, workingDir);
|
|
8
|
+
result = await replaceFileReferences(result, workingDir);
|
|
9
|
+
if (shouldAppendRawArgs) {
|
|
10
|
+
result = result.trimEnd() + `
|
|
11
|
+
|
|
12
|
+
ARGUMENTS: ${args.join(" ")}`;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
function replaceArguments(template, args) {
|
|
17
|
+
let result = template;
|
|
18
|
+
const hasArgumentsVar = /\$ARGUMENTS/.test(template);
|
|
19
|
+
const hasPositionalVar = /\$[1-9]\d*/.test(template);
|
|
20
|
+
result = result.replace(/\$ARGUMENTS/g, args.join(" "));
|
|
21
|
+
args.forEach((_, index) => {
|
|
22
|
+
const argNumber = index + 1;
|
|
23
|
+
const pattern = new RegExp(`\\$${argNumber}\\+`, "g");
|
|
24
|
+
result = result.replace(pattern, args.slice(index).join(" "));
|
|
25
|
+
});
|
|
26
|
+
args.forEach((arg, index) => {
|
|
27
|
+
const pattern = new RegExp(`\\$${index + 1}`, "g");
|
|
28
|
+
result = result.replace(pattern, arg);
|
|
29
|
+
});
|
|
30
|
+
result = result.replace(/\$[1-9]\d*\+?/g, "");
|
|
31
|
+
return {
|
|
32
|
+
result,
|
|
33
|
+
shouldAppendRawArgs: !hasArgumentsVar && !hasPositionalVar && args.length > 0
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function replaceShellOutput(template, workingDir) {
|
|
37
|
+
const shellPattern = /!`([^`]+)`/g;
|
|
38
|
+
const matches = [...template.matchAll(shellPattern)];
|
|
39
|
+
let result = template;
|
|
40
|
+
for (const match of matches) {
|
|
41
|
+
const [fullMatch, command] = match;
|
|
42
|
+
try {
|
|
43
|
+
const output = execSync(command, {
|
|
44
|
+
cwd: workingDir,
|
|
45
|
+
encoding: "utf-8",
|
|
46
|
+
timeout: 3e4,
|
|
47
|
+
maxBuffer: 1024 * 1024
|
|
48
|
+
// 1MB buffer
|
|
49
|
+
});
|
|
50
|
+
result = result.replace(fullMatch, output.trim());
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`Error executing shell command "${command}":`, error);
|
|
53
|
+
result = result.replace(fullMatch, `[Error: Failed to execute "${command}"]`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
async function replaceFileReferences(template, workingDir) {
|
|
59
|
+
const filePattern = /@([\w./-]+)/g;
|
|
60
|
+
const matches = [...template.matchAll(filePattern)];
|
|
61
|
+
let result = template;
|
|
62
|
+
for (const match of matches) {
|
|
63
|
+
const [fullMatch, filePath] = match;
|
|
64
|
+
try {
|
|
65
|
+
const fullPath = path.resolve(workingDir, filePath);
|
|
66
|
+
const content = await fs.readFile(fullPath, "utf-8");
|
|
67
|
+
result = result.replace(fullMatch, content);
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
function formatCommandForDisplay(command) {
|
|
74
|
+
const parts = [command.name];
|
|
75
|
+
if (command.description) {
|
|
76
|
+
parts.push(`- ${command.description}`);
|
|
77
|
+
}
|
|
78
|
+
return parts.join(" ");
|
|
79
|
+
}
|
|
80
|
+
function groupCommandsByNamespace(commands) {
|
|
81
|
+
const groups = /* @__PURE__ */ new Map();
|
|
82
|
+
for (const command of commands) {
|
|
83
|
+
const namespace = command.namespace || command.name.split(":")[0] || "general";
|
|
84
|
+
if (!groups.has(namespace)) {
|
|
85
|
+
groups.set(namespace, []);
|
|
86
|
+
}
|
|
87
|
+
groups.get(namespace).push(command);
|
|
88
|
+
}
|
|
89
|
+
return groups;
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
formatCommandForDisplay,
|
|
93
|
+
groupCommandsByNamespace,
|
|
94
|
+
processSlashCommand
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=slash-command-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/slash-command-processor.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport type { SlashCommandMetadata } from './slash-command-loader.js';\n\n/**\n * Process a slash command by replacing variables and executing shell commands\n */\nexport async function processSlashCommand(\n command: SlashCommandMetadata,\n args: string[],\n workingDir: string,\n): Promise<string> {\n const { result: withArgs, shouldAppendRawArgs } = replaceArguments(command.template, args);\n let result = withArgs;\n\n // Replace shell commands\n result = await replaceShellOutput(result, workingDir);\n\n // Replace file references\n result = await replaceFileReferences(result, workingDir);\n\n // Append raw args after shell/file processing to avoid executing user input\n if (shouldAppendRawArgs) {\n result = result.trimEnd() + `\\n\\nARGUMENTS: ${args.join(' ')}`;\n }\n\n return result;\n}\n\n/**\n * Replace argument variables in template\n * $ARGUMENTS - all arguments joined\n * $1, $2, etc. - positional arguments\n */\nfunction replaceArguments(template: string, args: string[]): { result: string; shouldAppendRawArgs: boolean } {\n let result = template;\n\n // Check if template references any argument variables\n const hasArgumentsVar = /\\$ARGUMENTS/.test(template);\n const hasPositionalVar = /\\$[1-9]\\d*/.test(template);\n\n // Replace $ARGUMENTS with all args joined\n result = result.replace(/\\$ARGUMENTS/g, args.join(' '));\n\n // Replace range arguments $1+, $2+, etc. before single positional arguments.\n args.forEach((_, index) => {\n const argNumber = index + 1;\n const pattern = new RegExp(`\\\\\\$${argNumber}\\\\+`, 'g');\n result = result.replace(pattern, args.slice(index).join(' '));\n });\n\n // Replace positional arguments $1, $2, etc.\n args.forEach((arg, index) => {\n const pattern = new RegExp(`\\\\\\$${index + 1}`, 'g');\n result = result.replace(pattern, arg);\n });\n\n // Clear unused positional and range arguments\n result = result.replace(/\\$[1-9]\\d*\\+?/g, '');\n\n return {\n result,\n shouldAppendRawArgs: !hasArgumentsVar && !hasPositionalVar && args.length > 0,\n };\n}\n\n/**\n * Replace shell command references with their output\n * Format: !`command`\n */\nasync function replaceShellOutput(template: string, workingDir: string): Promise<string> {\n const shellPattern = /!`([^`]+)`/g;\n const matches = [...template.matchAll(shellPattern)];\n\n let result = template;\n for (const match of matches) {\n const [fullMatch, command] = match;\n try {\n const output = execSync(command!, {\n cwd: workingDir,\n encoding: 'utf-8',\n timeout: 30000,\n maxBuffer: 1024 * 1024, // 1MB buffer\n });\n result = result.replace(fullMatch, output.trim());\n } catch (error) {\n console.error(`Error executing shell command \"${command}\":`, error);\n result = result.replace(fullMatch, `[Error: Failed to execute \"${command}\"]`);\n }\n }\n\n return result;\n}\n\n/**\n * Replace file references with file content\n * Format: @filename or @path/to/file\n */\nasync function replaceFileReferences(template: string, workingDir: string): Promise<string> {\n const filePattern = /@([\\w./-]+)/g;\n const matches = [...template.matchAll(filePattern)];\n\n let result = template;\n for (const match of matches) {\n const [fullMatch, filePath] = match;\n try {\n const fullPath = path.resolve(workingDir, filePath!);\n const content = await fs.readFile(fullPath, 'utf-8');\n result = result.replace(fullMatch, content);\n } catch {\n // Leave literal @mentions/search qualifiers such as @me intact when they do not resolve to files.\n }\n }\n\n return result;\n}\n\n/**\n * Format a command for display in help/autocomplete\n */\nexport function formatCommandForDisplay(command: SlashCommandMetadata): string {\n const parts = [command.name];\n\n if (command.description) {\n parts.push(`- ${command.description}`);\n }\n\n return parts.join(' ');\n}\n\n/**\n * Group commands by namespace for display\n */\nexport function groupCommandsByNamespace(commands: SlashCommandMetadata[]): Map<string, SlashCommandMetadata[]> {\n const groups = new Map<string, SlashCommandMetadata[]>();\n\n for (const command of commands) {\n const namespace = command.namespace || command.name.split(':')[0] || 'general';\n\n if (!groups.has(namespace)) {\n groups.set(namespace, []);\n }\n\n groups.get(namespace)!.push(command);\n }\n\n return groups;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean up raw piped output so the agent sees readable text, not terminal
|
|
3
|
+
* control noise.
|
|
4
|
+
*
|
|
5
|
+
* 1. Strip all ANSI escape sequences (colors, cursor movement, line clears).
|
|
6
|
+
* 2. Simulate carriage-return overwrites: for each line, split on `\r` and
|
|
7
|
+
* keep only the last segment — this is what the terminal would display
|
|
8
|
+
* after a spinner/progress bar finishes.
|
|
9
|
+
* 3. Collapse runs of blank lines.
|
|
10
|
+
*/
|
|
11
|
+
export declare function sanitizePipedOutput(raw: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* If stdin is a pipe (not a TTY), read **all** data until EOF and return it as
|
|
14
|
+
* a string. The returned promise only resolves once the write end of the pipe
|
|
15
|
+
* is closed — i.e. the sending process has fully exited — so callers are
|
|
16
|
+
* guaranteed to receive the complete output, not a partial snapshot from a
|
|
17
|
+
* program that writes progressively.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` when:
|
|
20
|
+
* - stdin is a TTY (interactive terminal)
|
|
21
|
+
* - the pipe was empty or contained only whitespace
|
|
22
|
+
*/
|
|
23
|
+
export declare function drainPipedStdin(): Promise<string | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Reopen `/dev/tty` (or `CON` on Windows) as `process.stdin` so that the
|
|
26
|
+
* interactive TUI can read keyboard input after the original piped stdin has
|
|
27
|
+
* been consumed.
|
|
28
|
+
*
|
|
29
|
+
* @returns `true` if the swap succeeded, `false` if a TTY could not be opened
|
|
30
|
+
* (e.g. running in a headless CI container with no controlling terminal).
|
|
31
|
+
*/
|
|
32
|
+
export declare function reopenStdinFromTTY(): boolean;
|
|
33
|
+
//# sourceMappingURL=stdin-pipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdin-pipe.d.ts","sourceRoot":"","sources":["../../src/utils/stdin-pipe.ts"],"names":[],"mappings":"AAYA;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA0BvD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2C9D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAmB5C"}
|