@phuetz/code-buddy 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +211 -163
- package/dist/agent/autonomous/agentic-coding-contract.d.ts +12 -12
- package/dist/agent/base-agent.d.ts +4 -0
- package/dist/agent/base-agent.js +6 -0
- package/dist/agent/codebuddy-agent.d.ts +1 -1
- package/dist/agent/codebuddy-agent.js +69 -14
- package/dist/agent/execution/agent-executor.js +122 -12
- package/dist/agent/execution/tool-dependency-graph.js +7 -0
- package/dist/agent/execution/tool-hooks.d.ts +6 -0
- package/dist/agent/execution/tool-hooks.js +13 -5
- package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
- package/dist/agent/execution/tool-selection-strategy.js +67 -10
- package/dist/agent/extended-thinking.d.ts +8 -0
- package/dist/agent/extended-thinking.js +27 -0
- package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
- package/dist/agent/facades/infrastructure-facade.js +15 -6
- package/dist/agent/hermes-browser-backends.js +151 -11
- package/dist/agent/hermes-claw-migrate.d.ts +59 -0
- package/dist/agent/hermes-claw-migrate.js +427 -26
- package/dist/agent/hermes-parity-manifest.js +78 -71
- package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
- package/dist/agent/hermes-runtime-lifecycle.js +468 -0
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
- package/dist/agent/middleware/visual-validation-middleware.js +67 -0
- package/dist/agent/model-benchmark.d.ts +77 -0
- package/dist/agent/model-benchmark.js +309 -0
- package/dist/agent/model-tier.d.ts +14 -0
- package/dist/agent/model-tier.js +71 -0
- package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
- package/dist/agent/multi-agent/multi-agent-system.js +3 -1
- package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
- package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
- package/dist/agent/multi-agent/session-tools.js +22 -5
- package/dist/agent/reasoning/mcts.js +20 -6
- package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
- package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
- package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
- package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
- package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
- package/dist/agent/self-improvement/authored-tool-store.js +57 -0
- package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
- package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
- package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
- package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
- package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
- package/dist/agent/self-improvement/self-knowledge.js +24 -0
- package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
- package/dist/agent/self-improvement/skill-benchmark.js +22 -0
- package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
- package/dist/agent/self-improvement/skill-consolidator.js +137 -0
- package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
- package/dist/agent/self-improvement/skill-engine.js +87 -0
- package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
- package/dist/agent/self-improvement/skill-gate.js +62 -0
- package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
- package/dist/agent/self-improvement/skill-mutator.js +223 -0
- package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
- package/dist/agent/self-improvement/skill-proposer.js +82 -0
- package/dist/agent/self-improvement/skill-types.d.ts +41 -0
- package/dist/agent/self-improvement/skill-types.js +13 -0
- package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
- package/dist/agent/self-improvement/tool-benchmark.js +37 -0
- package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
- package/dist/agent/self-improvement/tool-engine.js +101 -0
- package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
- package/dist/agent/self-improvement/tool-gate.js +78 -0
- package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
- package/dist/agent/self-improvement/tool-proposer.js +34 -0
- package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
- package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
- package/dist/agent/self-improvement/tool-types.d.ts +48 -0
- package/dist/agent/self-improvement/tool-types.js +9 -0
- package/dist/agent/self-improvement/types.d.ts +3 -1
- package/dist/agent/session-end-flush.d.ts +6 -1
- package/dist/agent/session-end-flush.js +20 -4
- package/dist/agent/streaming/streaming-handler.d.ts +7 -0
- package/dist/agent/streaming/streaming-handler.js +8 -1
- package/dist/agent/tool-executor.js +1 -0
- package/dist/agent/tool-handler.d.ts +5 -0
- package/dist/agent/tool-handler.js +133 -4
- package/dist/browser-automation/browser-operator-executor.js +15 -0
- package/dist/browser-automation/browser-use-runner.d.ts +96 -0
- package/dist/browser-automation/browser-use-runner.js +492 -0
- package/dist/browser-automation/camofox-runner.d.ts +107 -0
- package/dist/browser-automation/camofox-runner.js +287 -0
- package/dist/channels/dingtalk/index.js +3 -0
- package/dist/channels/discord/client.d.ts +9 -0
- package/dist/channels/discord/client.js +12 -0
- package/dist/channels/feishu/index.d.ts +167 -1
- package/dist/channels/feishu/index.js +432 -7
- package/dist/channels/gateway-lifecycle.d.ts +132 -0
- package/dist/channels/gateway-lifecycle.js +219 -0
- package/dist/channels/google-chat/index.d.ts +5 -1
- package/dist/channels/google-chat/index.js +5 -1
- package/dist/channels/imessage/index.d.ts +14 -0
- package/dist/channels/imessage/index.js +64 -17
- package/dist/channels/index.d.ts +4 -0
- package/dist/channels/index.js +4 -0
- package/dist/channels/irc/index.d.ts +73 -3
- package/dist/channels/irc/index.js +446 -11
- package/dist/channels/line/index.js +3 -0
- package/dist/channels/mattermost/index.d.ts +51 -4
- package/dist/channels/mattermost/index.js +303 -20
- package/dist/channels/nextcloud-talk/index.d.ts +89 -8
- package/dist/channels/nextcloud-talk/index.js +367 -16
- package/dist/channels/nostr/index.d.ts +121 -1
- package/dist/channels/nostr/index.js +396 -8
- package/dist/channels/ntfy/index.js +3 -0
- package/dist/channels/qq/index.js +3 -0
- package/dist/channels/slash-parity.d.ts +117 -0
- package/dist/channels/slash-parity.js +185 -0
- package/dist/channels/synology-chat/index.js +3 -0
- package/dist/channels/teams/index.d.ts +3 -0
- package/dist/channels/teams/index.js +3 -0
- package/dist/channels/telegram/client.d.ts +9 -0
- package/dist/channels/telegram/client.js +12 -0
- package/dist/channels/twilio-voice/index.js +3 -0
- package/dist/channels/webchat/index.d.ts +7 -1
- package/dist/channels/webchat/index.js +7 -1
- package/dist/channels/wecom/index.js +3 -0
- package/dist/channels/weixin/index.js +3 -0
- package/dist/channels/zalo/index.js +3 -0
- package/dist/cli/config-loader.js +1 -1
- package/dist/codebuddy/client.d.ts +30 -1
- package/dist/codebuddy/client.js +167 -20
- package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
- package/dist/codebuddy/providers/provider-chatgpt-responses.js +7 -1
- package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
- package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
- package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
- package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
- package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
- package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
- package/dist/codebuddy/tool-definitions/index.js +2 -1
- package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
- package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
- package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
- package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
- package/dist/codebuddy/tools.d.ts +8 -1
- package/dist/codebuddy/tools.js +67 -24
- package/dist/commands/cli/hermes-commands.js +108 -0
- package/dist/commands/cli/improve-command.js +123 -0
- package/dist/commands/cli/native-engine-commands.js +102 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +2 -2
- package/dist/commands/goal-cli.d.ts +30 -0
- package/dist/commands/goal-cli.js +210 -27
- package/dist/commands/handlers/goal-handler.d.ts +9 -2
- package/dist/commands/handlers/goal-handler.js +36 -9
- package/dist/commands/handlers/infra-handlers.js +36 -0
- package/dist/commands/handlers/memory-handlers.js +96 -1
- package/dist/commands/handlers/missing-handlers.d.ts +1 -1
- package/dist/commands/handlers/missing-handlers.js +26 -3
- package/dist/commands/headless-slash.d.ts +2 -0
- package/dist/commands/headless-slash.js +12 -0
- package/dist/commands/llm-provider-resolution.d.ts +5 -3
- package/dist/commands/llm-provider-resolution.js +87 -33
- package/dist/commands/ollama.d.ts +25 -0
- package/dist/commands/ollama.js +100 -0
- package/dist/commands/provider.d.ts +5 -0
- package/dist/commands/provider.js +106 -55
- package/dist/commands/skills-cli/index.js +123 -0
- package/dist/commands/slash/builtin-commands.js +1 -1
- package/dist/commands/spec-next.js +2 -1
- package/dist/commands/spec-plan.js +5 -16
- package/dist/commands/tunnel.d.ts +2 -0
- package/dist/commands/tunnel.js +48 -0
- package/dist/companion/percepts.js +11 -1
- package/dist/config/config-resolver.d.ts +2 -1
- package/dist/config/config-resolver.js +54 -41
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.js +7 -0
- package/dist/config/env-schema.js +756 -0
- package/dist/config/model-tools.js +4 -4
- package/dist/config/toml-config.d.ts +16 -0
- package/dist/config/toml-config.js +3 -0
- package/dist/context/bootstrap-loader.js +6 -23
- package/dist/context/context-manager-v2.js +1 -0
- package/dist/context/import-directive-parser.d.ts +4 -0
- package/dist/context/import-directive-parser.js +51 -6
- package/dist/context/instruction-excludes.d.ts +30 -1
- package/dist/context/instruction-excludes.js +71 -1
- package/dist/context/jit-context.d.ts +8 -10
- package/dist/context/jit-context.js +28 -106
- package/dist/context/project-context.d.ts +90 -0
- package/dist/context/project-context.js +295 -0
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +3 -3
- package/dist/daemon/autonomous-loop.d.ts +31 -1
- package/dist/daemon/autonomous-loop.js +91 -4
- package/dist/daemon/colab-goal.js +9 -1
- package/dist/daemon/cron-agent-bridge.d.ts +12 -3
- package/dist/daemon/cron-agent-bridge.js +25 -9
- package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
- package/dist/desktop/codebuddy-engine-adapter.js +257 -80
- package/dist/desktop/engine-adapter.d.ts +14 -0
- package/dist/desktop-automation/automation-manager.js +16 -0
- package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
- package/dist/desktop-automation/omniparser-runner.js +115 -0
- package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
- package/dist/desktop-automation/smart-snapshot.js +72 -5
- package/dist/doctor/index.js +40 -23
- package/dist/events/types.d.ts +11 -0
- package/dist/fleet/colab-store.js +14 -2
- package/dist/fleet/peer-session-bridge.js +50 -12
- package/dist/fleet/peer-tool-bridge.js +14 -0
- package/dist/goals/goal-decomposer.d.ts +27 -0
- package/dist/goals/goal-decomposer.js +293 -0
- package/dist/goals/goal-judge-client.d.ts +15 -0
- package/dist/goals/goal-judge-client.js +45 -0
- package/dist/goals/goal-judge.d.ts +2 -0
- package/dist/goals/goal-judge.js +35 -6
- package/dist/goals/goal-loop.d.ts +14 -0
- package/dist/goals/goal-loop.js +47 -2
- package/dist/goals/goal-manager.d.ts +6 -0
- package/dist/goals/goal-manager.js +67 -14
- package/dist/goals/goal-state.d.ts +13 -0
- package/dist/goals/goal-state.js +83 -13
- package/dist/goals/goal-store.d.ts +3 -0
- package/dist/goals/goal-store.js +31 -15
- package/dist/harness/contract.d.ts +28 -28
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/identity/identity-manager.js +3 -2
- package/dist/index.js +481 -26
- package/dist/input/text-to-speech.d.ts +2 -6
- package/dist/input/text-to-speech.js +2 -27
- package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
- package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
- package/dist/integrations/tailscale.d.ts +13 -0
- package/dist/integrations/tailscale.js +87 -34
- package/dist/knowledge/workspace-indexer.js +53 -9
- package/dist/mcp/client.js +1 -0
- package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
- package/dist/mcp/mcp-desktop-tools.js +158 -0
- package/dist/mcp/mcp-resources.js +2 -3
- package/dist/mcp/mcp-server.js +2 -0
- package/dist/memory/enhanced-memory.d.ts +10 -0
- package/dist/memory/enhanced-memory.js +33 -2
- package/dist/memory/index.d.ts +3 -1
- package/dist/memory/index.js +4 -1
- package/dist/memory/memory-auto-proposer.d.ts +23 -0
- package/dist/memory/memory-auto-proposer.js +308 -0
- package/dist/memory/memory-candidate-queue.d.ts +92 -0
- package/dist/memory/memory-candidate-queue.js +261 -0
- package/dist/memory/persistent-memory.d.ts +45 -2
- package/dist/memory/persistent-memory.js +236 -40
- package/dist/ml/bayesian-qualifier.d.ts +1 -1
- package/dist/ml/bayesian-qualifier.js +35 -2
- package/dist/openclaw/gateway-bridge.js +5 -0
- package/dist/plugins/marketplace.d.ts +1 -0
- package/dist/plugins/marketplace.js +7 -0
- package/dist/prompts/execution-discipline.d.ts +14 -0
- package/dist/prompts/execution-discipline.js +29 -0
- package/dist/prompts/variation-injector.js +9 -2
- package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
- package/dist/protocols/acp/acp-agentic-runner.js +115 -18
- package/dist/protocols/acp/acp-session-store.d.ts +23 -0
- package/dist/protocols/acp/acp-session-store.js +77 -0
- package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
- package/dist/protocols/acp/acp-stdio-server.js +71 -16
- package/dist/providers/active-llm-registry.d.ts +37 -0
- package/dist/providers/active-llm-registry.js +186 -0
- package/dist/providers/auxiliary-provider.d.ts +25 -0
- package/dist/providers/auxiliary-provider.js +192 -0
- package/dist/providers/codex-oauth.d.ts +1 -1
- package/dist/providers/codex-oauth.js +27 -4
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/provider-catalog.d.ts +70 -0
- package/dist/providers/provider-catalog.js +738 -0
- package/dist/providers/provider-fallback.d.ts +35 -0
- package/dist/providers/provider-fallback.js +171 -0
- package/dist/providers/xai-oauth.d.ts +128 -0
- package/dist/providers/xai-oauth.js +735 -0
- package/dist/scheduler/cron-scheduler.d.ts +15 -3
- package/dist/scheduler/cron-scheduler.js +53 -7
- package/dist/scheduler/script-runner.d.ts +2 -0
- package/dist/scheduler/script-runner.js +19 -4
- package/dist/scheduler/watchdog-handlers.js +7 -20
- package/dist/search/usearch-index.js +7 -2
- package/dist/security/tool-policy/tool-groups.js +2 -0
- package/dist/sensory/dreaming.d.ts +45 -0
- package/dist/sensory/dreaming.js +114 -0
- package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
- package/dist/sensory/heartbeat-scheduler.js +72 -0
- package/dist/sensory/reactions.d.ts +24 -0
- package/dist/sensory/reactions.js +31 -0
- package/dist/sensory/screen-reaction.d.ts +23 -0
- package/dist/sensory/screen-reaction.js +59 -0
- package/dist/sensory/sensory-bridge.d.ts +23 -0
- package/dist/sensory/sensory-bridge.js +85 -0
- package/dist/sensory/sensory-memory.d.ts +20 -0
- package/dist/sensory/sensory-memory.js +39 -0
- package/dist/sensory/speech-reaction.d.ts +21 -0
- package/dist/sensory/speech-reaction.js +83 -0
- package/dist/sensory/vision-reaction.d.ts +31 -0
- package/dist/sensory/vision-reaction.js +74 -0
- package/dist/server/index.js +106 -2
- package/dist/server/routes/mobile.d.ts +12 -4
- package/dist/server/routes/mobile.js +116 -1
- package/dist/server/tls-config.d.ts +35 -0
- package/dist/server/tls-config.js +142 -0
- package/dist/server/tunnel-manager.d.ts +20 -0
- package/dist/server/tunnel-manager.js +58 -0
- package/dist/server/websocket/fleet-bridge.js +5 -0
- package/dist/services/prompt-builder.d.ts +11 -0
- package/dist/services/prompt-builder.js +124 -17
- package/dist/shared/engine-types.d.ts +15 -1
- package/dist/sidecar/sidecar-bridge.d.ts +1 -0
- package/dist/sidecar/sidecar-bridge.js +21 -10
- package/dist/skills/parser.js +3 -0
- package/dist/skills/skill-importer.d.ts +58 -0
- package/dist/skills/skill-importer.js +261 -0
- package/dist/skills/skill-sources.d.ts +20 -0
- package/dist/skills/skill-sources.js +102 -0
- package/dist/skills/types.d.ts +6 -0
- package/dist/spec/spec-store.js +8 -1
- package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
- package/dist/talk-mode/providers/audioreader-tts.js +8 -8
- package/dist/templates/project-scaffolding.js +3 -2
- package/dist/themes/theme-schema.d.ts +10 -10
- package/dist/tools/application-profiles.js +38 -0
- package/dist/tools/bash/bash-tool.d.ts +1 -0
- package/dist/tools/bash/bash-tool.js +16 -2
- package/dist/tools/bash/command-validator.js +3 -0
- package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
- package/dist/tools/bash/rtk-rewrite.js +100 -0
- package/dist/tools/bash/streaming-executor.js +14 -1
- package/dist/tools/computer-control-tool.d.ts +16 -1
- package/dist/tools/computer-control-tool.js +317 -5
- package/dist/tools/document-generator.d.ts +14 -0
- package/dist/tools/document-generator.js +79 -0
- package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
- package/dist/tools/execute-code-rpc-invoker.js +46 -5
- package/dist/tools/metadata.js +28 -0
- package/dist/tools/office-macro-tool.d.ts +10 -0
- package/dist/tools/office-macro-tool.js +93 -0
- package/dist/tools/register-tool-handler.d.ts +25 -0
- package/dist/tools/register-tool-handler.js +100 -0
- package/dist/tools/registry/index.d.ts +2 -1
- package/dist/tools/registry/index.js +2 -1
- package/dist/tools/registry/memory-tools.d.ts +20 -0
- package/dist/tools/registry/memory-tools.js +225 -3
- package/dist/tools/registry/multimodal-tools.js +2 -2
- package/dist/tools/registry/vision-tools.d.ts +33 -0
- package/dist/tools/registry/vision-tools.js +308 -6
- package/dist/tools/registry/windows-tools.d.ts +2 -0
- package/dist/tools/registry/windows-tools.js +47 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +8 -0
- package/dist/tools/route-peer-tool.js +14 -0
- package/dist/tools/screenshot-tool.js +14 -2
- package/dist/tools/text-to-speech-tool.d.ts +1 -1
- package/dist/tools/text-to-speech-tool.js +2 -12
- package/dist/tools/tool-selector.js +3 -59
- package/dist/utils/config-validation/schema.d.ts +40 -7
- package/dist/utils/config-validation/schema.js +130 -1
- package/dist/utils/cost-tracker.js +21 -1
- package/dist/utils/disk-guard.d.ts +180 -0
- package/dist/utils/disk-guard.js +404 -0
- package/dist/utils/init-project.d.ts +7 -0
- package/dist/utils/init-project.js +37 -0
- package/dist/utils/interactive-setup.js +35 -2
- package/dist/utils/model-utils.js +11 -2
- package/dist/utils/output-sanitizer.js +11 -0
- package/dist/utils/provider-detector.d.ts +8 -7
- package/dist/utils/provider-detector.js +19 -77
- package/dist/utils/settings-manager.d.ts +19 -0
- package/dist/utils/token-display.d.ts +3 -3
- package/dist/utils/token-display.js +22 -4
- package/dist/wizard/onboarding.d.ts +39 -0
- package/dist/wizard/onboarding.js +433 -21
- package/dist/wizard/provider-onboarding.d.ts +8 -23
- package/dist/wizard/provider-onboarding.js +39 -158
- package/package.json +4 -2
- package/dist/plugins/provider-onboarding.d.ts +0 -23
- package/dist/plugins/provider-onboarding.js +0 -116
- package/dist/utils/kokoro-tts.d.ts +0 -8
- package/dist/utils/kokoro-tts.js +0 -67
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill importer — bring EXTERNAL skills (a Hermes repo, any skills directory)
|
|
3
|
+
* into Code Buddy, safely. External skills are untrusted and get injected into the
|
|
4
|
+
* agent's context, so the firewall gates every one (SKILL.md + its scripts) before
|
|
5
|
+
* install. Hermes nests 1–3 levels but our registry walks 1 level → flatten; Hermes
|
|
6
|
+
* tags live under `metadata.hermes.tags` but our discovery scores top-level `tags` +
|
|
7
|
+
* `nativeEngine.triggers` → remap, else an imported skill is invisible to matching.
|
|
8
|
+
*
|
|
9
|
+
* Imported skills are namespaced `imported-*` (distinct provenance; never touched by
|
|
10
|
+
* the self-improvement engine) and installed flat (1 level) under a tier root.
|
|
11
|
+
*
|
|
12
|
+
* @module skills/skill-importer
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import os from 'os';
|
|
17
|
+
import * as yaml from 'yaml';
|
|
18
|
+
import { scanSkillFirewall } from '../security/skill-scanner.js';
|
|
19
|
+
import { parseSkillFile, validateSkill } from './parser.js';
|
|
20
|
+
import { logger } from '../utils/logger.js';
|
|
21
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
22
|
+
const SUPPORT_DIRS = ['references', 'templates', 'scripts', 'assets', 'workflows', 'tests'];
|
|
23
|
+
const SKIP_DIRS = new Set(['.git', 'index-cache', '.archive', 'node_modules', '.sources-cache']);
|
|
24
|
+
export const IMPORTED_PREFIX = 'imported-';
|
|
25
|
+
function defaultDestRoot() {
|
|
26
|
+
return path.join(os.homedir(), '.codebuddy', 'skills', 'managed');
|
|
27
|
+
}
|
|
28
|
+
/** Recursively find skill directories (those containing a SKILL.md). Skips operational dirs. */
|
|
29
|
+
export function findSkillDirs(root) {
|
|
30
|
+
const out = [];
|
|
31
|
+
const walk = (dir) => {
|
|
32
|
+
let entries;
|
|
33
|
+
try {
|
|
34
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (entries.some((e) => e.isFile() && e.name.toLowerCase() === 'skill.md')) {
|
|
40
|
+
out.push(dir);
|
|
41
|
+
// don't descend into a skill's own support dirs
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
for (const e of entries) {
|
|
45
|
+
if (!e.isDirectory() || e.name.startsWith('.') || SKIP_DIRS.has(e.name))
|
|
46
|
+
continue;
|
|
47
|
+
walk(path.join(dir, e.name));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
walk(root);
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
function slugify(raw) {
|
|
54
|
+
const base = String(raw).trim().toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
55
|
+
return base.startsWith(IMPORTED_PREFIX) ? base : `${IMPORTED_PREFIX}${base || 'skill'}`;
|
|
56
|
+
}
|
|
57
|
+
function normalizeTags(raw) {
|
|
58
|
+
const list = Array.isArray(raw) ? raw : [];
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const t of list) {
|
|
62
|
+
const s = String(t).trim().toLowerCase();
|
|
63
|
+
if (s && !seen.has(s)) {
|
|
64
|
+
seen.add(s);
|
|
65
|
+
out.push(s);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
const STOPWORDS = new Set([
|
|
71
|
+
'the', 'and', 'for', 'with', 'your', 'via', 'into', 'from', 'that', 'this', 'use', 'using', 'create',
|
|
72
|
+
'creates', 'creating', 'a', 'an', 'or', 'to', 'of', 'in', 'on', 'as', 'by', 'it', 'is', 'are', 'add',
|
|
73
|
+
'list', 'get', 'set', 'run', 'when', 'how', 'you', 'can', 'will', 'their', 'them', 'they', 'about',
|
|
74
|
+
]);
|
|
75
|
+
/** Derive discovery triggers (the primary matcher) from the name + tags + description keywords. */
|
|
76
|
+
function deriveTriggers(rawName, tags, description = '') {
|
|
77
|
+
const nameWords = String(rawName).toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= 3);
|
|
78
|
+
const descWords = String(description)
|
|
79
|
+
.toLowerCase()
|
|
80
|
+
.split(/[^a-z0-9]+/)
|
|
81
|
+
.filter((w) => w.length >= 4 && !STOPWORDS.has(w));
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
const out = [];
|
|
84
|
+
for (const t of [String(rawName).toLowerCase(), ...tags, ...nameWords, ...descWords]) {
|
|
85
|
+
if (t && !seen.has(t)) {
|
|
86
|
+
seen.add(t);
|
|
87
|
+
out.push(t);
|
|
88
|
+
}
|
|
89
|
+
if (out.length >= 12)
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/** Extract discovery tags from any source layout: top-level `tags`, or `metadata.<source>.tags`. */
|
|
95
|
+
function extractTags(rawFm) {
|
|
96
|
+
if (Array.isArray(rawFm.tags))
|
|
97
|
+
return rawFm.tags;
|
|
98
|
+
const meta = rawFm.metadata;
|
|
99
|
+
if (meta && typeof meta === 'object') {
|
|
100
|
+
for (const v of Object.values(meta)) {
|
|
101
|
+
if (v && typeof v === 'object' && Array.isArray(v.tags)) {
|
|
102
|
+
return v.tags;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
/** Map prerequisites/requires from any source → our SkillRequirements.tools. */
|
|
109
|
+
function extractRequiresTools(rawFm) {
|
|
110
|
+
const out = new Set();
|
|
111
|
+
const add = (v) => {
|
|
112
|
+
if (Array.isArray(v))
|
|
113
|
+
for (const x of v)
|
|
114
|
+
if (typeof x === 'string')
|
|
115
|
+
out.add(x);
|
|
116
|
+
};
|
|
117
|
+
// Hermes: prerequisites.commands
|
|
118
|
+
const prereq = rawFm.prerequisites;
|
|
119
|
+
if (prereq)
|
|
120
|
+
add(prereq.commands);
|
|
121
|
+
// OpenClaw (and others): metadata.<source>.requires.bins
|
|
122
|
+
const meta = rawFm.metadata;
|
|
123
|
+
if (meta && typeof meta === 'object') {
|
|
124
|
+
for (const v of Object.values(meta)) {
|
|
125
|
+
const req = v?.requires;
|
|
126
|
+
if (req)
|
|
127
|
+
add(req.bins);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return [...out];
|
|
131
|
+
}
|
|
132
|
+
/** Build a Code-Buddy-shaped SKILL.md from a raw (e.g. Hermes) frontmatter object + body. */
|
|
133
|
+
export function remapSkill(rawFm, body, opts) {
|
|
134
|
+
const description = String(rawFm.description ?? '').trim() || `Imported skill ${opts.slug}`;
|
|
135
|
+
const tags = normalizeTags(extractTags(rawFm));
|
|
136
|
+
const requiresTools = extractRequiresTools(rawFm);
|
|
137
|
+
const author = Array.isArray(rawFm.author) ? rawFm.author.join(', ') : rawFm.author;
|
|
138
|
+
const meta = {
|
|
139
|
+
name: opts.slug,
|
|
140
|
+
description,
|
|
141
|
+
...(rawFm.version ? { version: rawFm.version } : {}),
|
|
142
|
+
...(author ? { author } : {}),
|
|
143
|
+
...(rawFm.license ? { license: rawFm.license } : {}),
|
|
144
|
+
...(rawFm.platforms ? { platforms: rawFm.platforms } : {}),
|
|
145
|
+
tags,
|
|
146
|
+
nativeEngine: { triggers: deriveTriggers(String(rawFm.name ?? opts.slug), tags, description) },
|
|
147
|
+
...(requiresTools.length ? { requires: { tools: requiresTools } } : {}),
|
|
148
|
+
imported: true,
|
|
149
|
+
source: opts.source,
|
|
150
|
+
...(opts.pinned ? { pinned: true } : {}),
|
|
151
|
+
};
|
|
152
|
+
return `---\n${yaml.stringify(meta)}---\n\n${body.trim()}\n`;
|
|
153
|
+
}
|
|
154
|
+
function copySupportDirs(srcDir, destDir) {
|
|
155
|
+
for (const sub of SUPPORT_DIRS) {
|
|
156
|
+
const from = path.join(srcDir, sub);
|
|
157
|
+
if (fs.existsSync(from) && fs.statSync(from).isDirectory()) {
|
|
158
|
+
fs.cpSync(from, path.join(destDir, sub), {
|
|
159
|
+
recursive: true,
|
|
160
|
+
// never follow symlinks out of the source tree
|
|
161
|
+
filter: (s) => {
|
|
162
|
+
try {
|
|
163
|
+
return !fs.lstatSync(s).isSymbolicLink();
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Import skills from a directory. Pure-ish: writes nothing when dryRun. */
|
|
174
|
+
export function importSkills(sourceDir, options = {}) {
|
|
175
|
+
const destRoot = options.destRoot ?? defaultDestRoot();
|
|
176
|
+
const source = options.source ?? 'import';
|
|
177
|
+
const dryRun = options.dryRun ?? false;
|
|
178
|
+
const pinByDefault = options.pinByDefault ?? true;
|
|
179
|
+
const report = { imported: [], quarantined: [], review: [], skipped: [], total: 0, dryRun };
|
|
180
|
+
const skillDirs = findSkillDirs(sourceDir);
|
|
181
|
+
report.total = skillDirs.length;
|
|
182
|
+
for (const skillDir of skillDirs) {
|
|
183
|
+
const rel = path.relative(sourceDir, skillDir);
|
|
184
|
+
if (options.category && !rel.includes(options.category)) {
|
|
185
|
+
report.skipped.push({ sourcePath: rel, reason: 'filtered by --category' });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const skillMd = fs.existsSync(path.join(skillDir, 'SKILL.md'))
|
|
189
|
+
? path.join(skillDir, 'SKILL.md')
|
|
190
|
+
: path.join(skillDir, 'skill.md');
|
|
191
|
+
const content = fs.readFileSync(skillMd, 'utf-8');
|
|
192
|
+
// Compatibility check.
|
|
193
|
+
try {
|
|
194
|
+
const skill = parseSkillFile(content, skillMd, 'managed');
|
|
195
|
+
const v = validateSkill(skill);
|
|
196
|
+
if (!v.valid) {
|
|
197
|
+
report.skipped.push({ sourcePath: rel, reason: `invalid: ${v.errors.join('; ')}` });
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
report.skipped.push({ sourcePath: rel, reason: `parse error: ${err instanceof Error ? err.message : String(err)}` });
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
// Firewall gate (scans SKILL.md + scripts/support files recursively).
|
|
206
|
+
const fw = scanSkillFirewall(skillDir);
|
|
207
|
+
if (fw.quarantineRequired) {
|
|
208
|
+
report.quarantined.push({ sourcePath: rel, reason: fw.summary, verdict: String(fw.verdict) });
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (String(fw.verdict) === 'review' && !options.includeReview) {
|
|
212
|
+
report.review.push({ sourcePath: rel, reason: fw.summary, verdict: 'review' });
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
// Remap + flatten + install.
|
|
216
|
+
const m = content.match(FRONTMATTER_RE);
|
|
217
|
+
if (!m) {
|
|
218
|
+
report.skipped.push({ sourcePath: rel, reason: 'missing frontmatter' });
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
let rawFm;
|
|
222
|
+
try {
|
|
223
|
+
rawFm = (yaml.parse(m[1]) ?? {});
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
report.skipped.push({ sourcePath: rel, reason: 'unparseable frontmatter' });
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const slug = slugify(String(rawFm.name ?? path.basename(skillDir)));
|
|
230
|
+
const destDir = path.join(destRoot, slug);
|
|
231
|
+
if (fs.existsSync(destDir) && !options.overwrite) {
|
|
232
|
+
report.skipped.push({ sourcePath: rel, reason: `conflict: ${slug} already imported` });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (!dryRun) {
|
|
236
|
+
try {
|
|
237
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
238
|
+
fs.writeFileSync(path.join(destDir, 'SKILL.md'), remapSkill(rawFm, m[2], { slug, source, pinned: pinByDefault }), 'utf-8');
|
|
239
|
+
copySupportDirs(skillDir, destDir);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
report.skipped.push({ sourcePath: rel, reason: `write error: ${err instanceof Error ? err.message : String(err)}` });
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
report.imported.push({ name: slug, sourcePath: rel, verdict: String(fw.verdict) });
|
|
247
|
+
}
|
|
248
|
+
if (!dryRun && report.imported.length > 0) {
|
|
249
|
+
void (async () => {
|
|
250
|
+
try {
|
|
251
|
+
const { getSkillRegistry } = await import('./registry.js');
|
|
252
|
+
await getSkillRegistry().reloadAll();
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
logger.debug(`skill reload after import failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
256
|
+
}
|
|
257
|
+
})();
|
|
258
|
+
}
|
|
259
|
+
return report;
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=skill-importer.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill sources — a small "referential" of named places skills can be imported
|
|
3
|
+
* from. A source is a local directory or a git repo. Persisted to
|
|
4
|
+
* `~/.codebuddy/skill-sources.json`. The importer resolves a source to a local
|
|
5
|
+
* directory (cloning/pulling a git source into a cache) and then runs the same
|
|
6
|
+
* firewall-gated import path.
|
|
7
|
+
*
|
|
8
|
+
* @module skills/skill-sources
|
|
9
|
+
*/
|
|
10
|
+
export interface SkillSource {
|
|
11
|
+
name: string;
|
|
12
|
+
type: 'dir' | 'git';
|
|
13
|
+
location: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function listSources(): SkillSource[];
|
|
16
|
+
export declare function getSource(name: string): SkillSource | undefined;
|
|
17
|
+
export declare function addSource(name: string, location: string, type?: 'dir' | 'git'): SkillSource;
|
|
18
|
+
export declare function removeSource(name: string): boolean;
|
|
19
|
+
/** Resolve a source to a local directory (clone/pull a git source into the cache). */
|
|
20
|
+
export declare function resolveSourceDir(source: SkillSource): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill sources — a small "referential" of named places skills can be imported
|
|
3
|
+
* from. A source is a local directory or a git repo. Persisted to
|
|
4
|
+
* `~/.codebuddy/skill-sources.json`. The importer resolves a source to a local
|
|
5
|
+
* directory (cloning/pulling a git source into a cache) and then runs the same
|
|
6
|
+
* firewall-gated import path.
|
|
7
|
+
*
|
|
8
|
+
* @module skills/skill-sources
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import os from 'os';
|
|
13
|
+
import { execFileSync } from 'child_process';
|
|
14
|
+
import { logger } from '../utils/logger.js';
|
|
15
|
+
function configPath() {
|
|
16
|
+
return path.join(os.homedir(), '.codebuddy', 'skill-sources.json');
|
|
17
|
+
}
|
|
18
|
+
function cacheRoot() {
|
|
19
|
+
return path.join(os.homedir(), '.codebuddy', 'skills', '.sources-cache');
|
|
20
|
+
}
|
|
21
|
+
/** Best-effort: locate the OpenClaw skills dir (it lives inside the npm global package). */
|
|
22
|
+
function findOpenclawSkillsDir() {
|
|
23
|
+
const candidates = [path.join(os.homedir(), '.openclaw', 'skills')];
|
|
24
|
+
const nvmRoot = path.join(os.homedir(), '.nvm', 'versions', 'node');
|
|
25
|
+
try {
|
|
26
|
+
for (const v of fs.readdirSync(nvmRoot)) {
|
|
27
|
+
candidates.push(path.join(nvmRoot, v, 'lib', 'node_modules', 'openclaw', 'skills'));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
/* no nvm */
|
|
32
|
+
}
|
|
33
|
+
candidates.push('/usr/local/lib/node_modules/openclaw/skills', '/usr/lib/node_modules/openclaw/skills');
|
|
34
|
+
return candidates.find((c) => fs.existsSync(c));
|
|
35
|
+
}
|
|
36
|
+
function read() {
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(fs.readFileSync(configPath(), 'utf-8'));
|
|
39
|
+
if (Array.isArray(parsed.sources))
|
|
40
|
+
return { schemaVersion: 1, sources: parsed.sources };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* no config yet */
|
|
44
|
+
}
|
|
45
|
+
// Seed known local skill repos as default `dir` sources when present.
|
|
46
|
+
const seed = [];
|
|
47
|
+
const hermes = path.join(os.homedir(), '.hermes', 'skills');
|
|
48
|
+
if (fs.existsSync(hermes))
|
|
49
|
+
seed.push({ name: 'hermes', type: 'dir', location: hermes });
|
|
50
|
+
const openclaw = findOpenclawSkillsDir();
|
|
51
|
+
if (openclaw)
|
|
52
|
+
seed.push({ name: 'openclaw', type: 'dir', location: openclaw });
|
|
53
|
+
return { schemaVersion: 1, sources: seed };
|
|
54
|
+
}
|
|
55
|
+
function write(file) {
|
|
56
|
+
fs.mkdirSync(path.dirname(configPath()), { recursive: true });
|
|
57
|
+
fs.writeFileSync(configPath(), JSON.stringify(file, null, 2), 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
export function listSources() {
|
|
60
|
+
return read().sources;
|
|
61
|
+
}
|
|
62
|
+
export function getSource(name) {
|
|
63
|
+
return read().sources.find((s) => s.name === name);
|
|
64
|
+
}
|
|
65
|
+
export function addSource(name, location, type = location.endsWith('.git') || location.includes('://') ? 'git' : 'dir') {
|
|
66
|
+
const file = read();
|
|
67
|
+
const source = { name, type, location };
|
|
68
|
+
file.sources = file.sources.filter((s) => s.name !== name);
|
|
69
|
+
file.sources.push(source);
|
|
70
|
+
write(file);
|
|
71
|
+
return source;
|
|
72
|
+
}
|
|
73
|
+
export function removeSource(name) {
|
|
74
|
+
const file = read();
|
|
75
|
+
const before = file.sources.length;
|
|
76
|
+
file.sources = file.sources.filter((s) => s.name !== name);
|
|
77
|
+
if (file.sources.length === before)
|
|
78
|
+
return false;
|
|
79
|
+
write(file);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
/** Resolve a source to a local directory (clone/pull a git source into the cache). */
|
|
83
|
+
export function resolveSourceDir(source) {
|
|
84
|
+
if (source.type === 'dir')
|
|
85
|
+
return source.location;
|
|
86
|
+
// git: shallow clone or pull into the cache.
|
|
87
|
+
const dir = path.join(cacheRoot(), source.name);
|
|
88
|
+
fs.mkdirSync(cacheRoot(), { recursive: true });
|
|
89
|
+
try {
|
|
90
|
+
if (fs.existsSync(path.join(dir, '.git'))) {
|
|
91
|
+
execFileSync('git', ['-C', dir, 'pull', '--ff-only', '--depth', '1'], { stdio: 'ignore' });
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
execFileSync('git', ['clone', '--depth', '1', source.location, dir], { stdio: 'ignore' });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
logger.warn(`skill source "${source.name}": git fetch failed — ${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
}
|
|
100
|
+
return dir;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=skill-sources.js.map
|
package/dist/skills/types.d.ts
CHANGED
|
@@ -28,6 +28,12 @@ export interface SkillMetadata {
|
|
|
28
28
|
contextFork?: boolean;
|
|
29
29
|
/** CC11: If true, skill content is returned directly without LLM invocation */
|
|
30
30
|
disableModelInvocation?: boolean;
|
|
31
|
+
/** Self-improvement: if true, curation won't overwrite/remove/consolidate this skill */
|
|
32
|
+
pinned?: boolean;
|
|
33
|
+
/** Provenance: this skill was imported from an external source. */
|
|
34
|
+
imported?: boolean;
|
|
35
|
+
/** Provenance: label of the source it was imported from (e.g. "hermes"). */
|
|
36
|
+
source?: string;
|
|
31
37
|
}
|
|
32
38
|
export interface SkillRequirements {
|
|
33
39
|
/** Required tools */
|
package/dist/spec/spec-store.js
CHANGED
|
@@ -58,6 +58,7 @@ export class SpecTransitionError extends Error {
|
|
|
58
58
|
// Singleton registry (one store per working directory)
|
|
59
59
|
// ============================================================================
|
|
60
60
|
const registry = new Map();
|
|
61
|
+
let lastStoryCreatedAt = 0;
|
|
61
62
|
export function getSpecStore(workDir = process.cwd()) {
|
|
62
63
|
const key = path.resolve(workDir);
|
|
63
64
|
if (!registry.has(key)) {
|
|
@@ -73,6 +74,7 @@ export function getSpecStore(workDir = process.cwd()) {
|
|
|
73
74
|
/** Test helper: drop cached store instances. */
|
|
74
75
|
export function resetSpecStores() {
|
|
75
76
|
registry.clear();
|
|
77
|
+
lastStoryCreatedAt = 0;
|
|
76
78
|
}
|
|
77
79
|
/** Whether `from → to` is a legal story status transition. */
|
|
78
80
|
export function isLegalTransition(from, to) {
|
|
@@ -211,7 +213,7 @@ export class SpecStore {
|
|
|
211
213
|
const title = (input.title ?? '').trim();
|
|
212
214
|
if (!title)
|
|
213
215
|
throw new Error('Story title is required.');
|
|
214
|
-
const now =
|
|
216
|
+
const now = nextStoryCreatedAt();
|
|
215
217
|
const allowedPaths = cleanList(input.allowedPaths);
|
|
216
218
|
const verification = cleanList(input.verification);
|
|
217
219
|
const story = {
|
|
@@ -479,6 +481,11 @@ function parseFrontmatter(content) {
|
|
|
479
481
|
function randomId() {
|
|
480
482
|
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 7)}`;
|
|
481
483
|
}
|
|
484
|
+
function nextStoryCreatedAt() {
|
|
485
|
+
const now = Date.now();
|
|
486
|
+
lastStoryCreatedAt = now > lastStoryCreatedAt ? now : lastStoryCreatedAt + 1;
|
|
487
|
+
return lastStoryCreatedAt;
|
|
488
|
+
}
|
|
482
489
|
/** Trim, drop blanks, and de-duplicate a string list (used for contract fields). */
|
|
483
490
|
function cleanList(values) {
|
|
484
491
|
if (!Array.isArray(values))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AudioReader TTS Provider
|
|
3
3
|
*
|
|
4
|
-
* Uses a local AudioReader API
|
|
4
|
+
* Uses a local AudioReader API for high-quality,
|
|
5
5
|
* free text-to-speech synthesis via an OpenAI-compatible REST API.
|
|
6
6
|
*/
|
|
7
7
|
import type { TTSProviderConfig, Voice, SynthesisOptions, SynthesisResult } from '../types.js';
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AudioReader TTS Provider
|
|
3
3
|
*
|
|
4
|
-
* Uses a local AudioReader API
|
|
4
|
+
* Uses a local AudioReader API for high-quality,
|
|
5
5
|
* free text-to-speech synthesis via an OpenAI-compatible REST API.
|
|
6
6
|
*/
|
|
7
7
|
const DEFAULT_BASE_URL = 'http://localhost:8000';
|
|
8
|
-
const DEFAULT_MODEL = '
|
|
8
|
+
const DEFAULT_MODEL = 'audioreader';
|
|
9
9
|
const DEFAULT_VOICE = 'ff_siwis';
|
|
10
|
-
/** Known
|
|
11
|
-
const
|
|
10
|
+
/** Known AudioReader voices with metadata */
|
|
11
|
+
const AUDIOREADER_VOICES = {
|
|
12
12
|
ff_siwis: { name: 'Siwis', language: 'fr-FR', gender: 'female' },
|
|
13
13
|
af_bella: { name: 'Bella', language: 'en-US', gender: 'female' },
|
|
14
14
|
af_heart: { name: 'Heart', language: 'en-US', gender: 'female' },
|
|
@@ -20,7 +20,7 @@ const KOKORO_VOICES = {
|
|
|
20
20
|
bf_emma: { name: 'Emma', language: 'en-GB', gender: 'female' },
|
|
21
21
|
bm_george: { name: 'George', language: 'en-GB', gender: 'male' },
|
|
22
22
|
};
|
|
23
|
-
/** OpenAI voice name to
|
|
23
|
+
/** OpenAI voice name to AudioReader voice mapping */
|
|
24
24
|
const OPENAI_VOICE_MAP = {
|
|
25
25
|
alloy: 'af_bella',
|
|
26
26
|
echo: 'am_adam',
|
|
@@ -74,7 +74,7 @@ export class AudioReaderTTSProvider {
|
|
|
74
74
|
catch {
|
|
75
75
|
// Fall back to known voices
|
|
76
76
|
}
|
|
77
|
-
return Object.keys(
|
|
77
|
+
return Object.keys(AUDIOREADER_VOICES).map(id => this.buildVoice(id));
|
|
78
78
|
}
|
|
79
79
|
async synthesize(text, options) {
|
|
80
80
|
if (!this.initialized) {
|
|
@@ -131,11 +131,11 @@ export class AudioReaderTTSProvider {
|
|
|
131
131
|
return voice;
|
|
132
132
|
}
|
|
133
133
|
buildVoice(id) {
|
|
134
|
-
const meta =
|
|
134
|
+
const meta = AUDIOREADER_VOICES[id];
|
|
135
135
|
return {
|
|
136
136
|
id: `audioreader-${id}`,
|
|
137
137
|
name: meta?.name ?? id,
|
|
138
|
-
description: `AudioReader
|
|
138
|
+
description: `AudioReader voice - ${meta?.name ?? id}`,
|
|
139
139
|
language: meta?.language ?? 'en-US',
|
|
140
140
|
gender: meta?.gender ?? 'female',
|
|
141
141
|
provider: 'audioreader',
|
|
@@ -12,6 +12,7 @@ import * as path from 'path';
|
|
|
12
12
|
import { existsSync } from 'fs';
|
|
13
13
|
import { EventEmitter } from 'events';
|
|
14
14
|
import { spawn } from 'child_process';
|
|
15
|
+
import { performance } from 'perf_hooks';
|
|
15
16
|
// ============================================================================
|
|
16
17
|
// Built-in Templates
|
|
17
18
|
// ============================================================================
|
|
@@ -641,7 +642,7 @@ export class TemplateEngine extends EventEmitter {
|
|
|
641
642
|
* Generate project from template
|
|
642
643
|
*/
|
|
643
644
|
async generate(options) {
|
|
644
|
-
const startTime =
|
|
645
|
+
const startTime = performance.now();
|
|
645
646
|
const warnings = [];
|
|
646
647
|
const filesCreated = [];
|
|
647
648
|
// Get template
|
|
@@ -737,7 +738,7 @@ export class TemplateEngine extends EventEmitter {
|
|
|
737
738
|
success: true,
|
|
738
739
|
projectPath,
|
|
739
740
|
filesCreated,
|
|
740
|
-
duration:
|
|
741
|
+
duration: Math.max(1, Math.ceil(performance.now() - startTime)),
|
|
741
742
|
warnings,
|
|
742
743
|
nextSteps,
|
|
743
744
|
};
|
|
@@ -58,11 +58,11 @@ export declare const themeColorsSchema: z.ZodObject<{
|
|
|
58
58
|
primary: string;
|
|
59
59
|
toolResult: string;
|
|
60
60
|
secondary: string;
|
|
61
|
+
border: string;
|
|
61
62
|
userMessage: string;
|
|
62
63
|
accent: string;
|
|
63
64
|
textMuted: string;
|
|
64
65
|
textDim: string;
|
|
65
|
-
border: string;
|
|
66
66
|
borderActive: string;
|
|
67
67
|
borderBusy: string;
|
|
68
68
|
assistantMessage: string;
|
|
@@ -81,11 +81,11 @@ export declare const themeColorsSchema: z.ZodObject<{
|
|
|
81
81
|
primary: string;
|
|
82
82
|
toolResult: string;
|
|
83
83
|
secondary: string;
|
|
84
|
+
border: string;
|
|
84
85
|
userMessage: string;
|
|
85
86
|
accent: string;
|
|
86
87
|
textMuted: string;
|
|
87
88
|
textDim: string;
|
|
88
|
-
border: string;
|
|
89
89
|
borderActive: string;
|
|
90
90
|
borderBusy: string;
|
|
91
91
|
assistantMessage: string;
|
|
@@ -135,11 +135,11 @@ export declare const themeSchema: z.ZodObject<{
|
|
|
135
135
|
primary: string;
|
|
136
136
|
toolResult: string;
|
|
137
137
|
secondary: string;
|
|
138
|
+
border: string;
|
|
138
139
|
userMessage: string;
|
|
139
140
|
accent: string;
|
|
140
141
|
textMuted: string;
|
|
141
142
|
textDim: string;
|
|
142
|
-
border: string;
|
|
143
143
|
borderActive: string;
|
|
144
144
|
borderBusy: string;
|
|
145
145
|
assistantMessage: string;
|
|
@@ -158,11 +158,11 @@ export declare const themeSchema: z.ZodObject<{
|
|
|
158
158
|
primary: string;
|
|
159
159
|
toolResult: string;
|
|
160
160
|
secondary: string;
|
|
161
|
+
border: string;
|
|
161
162
|
userMessage: string;
|
|
162
163
|
accent: string;
|
|
163
164
|
textMuted: string;
|
|
164
165
|
textDim: string;
|
|
165
|
-
border: string;
|
|
166
166
|
borderActive: string;
|
|
167
167
|
borderBusy: string;
|
|
168
168
|
assistantMessage: string;
|
|
@@ -206,11 +206,11 @@ export declare const themeSchema: z.ZodObject<{
|
|
|
206
206
|
primary: string;
|
|
207
207
|
toolResult: string;
|
|
208
208
|
secondary: string;
|
|
209
|
+
border: string;
|
|
209
210
|
userMessage: string;
|
|
210
211
|
accent: string;
|
|
211
212
|
textMuted: string;
|
|
212
213
|
textDim: string;
|
|
213
|
-
border: string;
|
|
214
214
|
borderActive: string;
|
|
215
215
|
borderBusy: string;
|
|
216
216
|
assistantMessage: string;
|
|
@@ -243,11 +243,11 @@ export declare const themeSchema: z.ZodObject<{
|
|
|
243
243
|
primary: string;
|
|
244
244
|
toolResult: string;
|
|
245
245
|
secondary: string;
|
|
246
|
+
border: string;
|
|
246
247
|
userMessage: string;
|
|
247
248
|
accent: string;
|
|
248
249
|
textMuted: string;
|
|
249
250
|
textDim: string;
|
|
250
|
-
border: string;
|
|
251
251
|
borderActive: string;
|
|
252
252
|
borderBusy: string;
|
|
253
253
|
assistantMessage: string;
|
|
@@ -320,13 +320,13 @@ export declare const themePreferencesSchema: z.ZodObject<{
|
|
|
320
320
|
primary?: string | undefined;
|
|
321
321
|
toolResult?: string | undefined;
|
|
322
322
|
secondary?: string | undefined;
|
|
323
|
+
border?: string | undefined;
|
|
323
324
|
userMessage?: string | undefined;
|
|
324
325
|
accent?: string | undefined;
|
|
325
326
|
textMuted?: string | undefined;
|
|
326
327
|
textDim?: string | undefined;
|
|
327
328
|
background?: string | undefined;
|
|
328
329
|
backgroundAlt?: string | undefined;
|
|
329
|
-
border?: string | undefined;
|
|
330
330
|
borderActive?: string | undefined;
|
|
331
331
|
borderBusy?: string | undefined;
|
|
332
332
|
assistantMessage?: string | undefined;
|
|
@@ -343,13 +343,13 @@ export declare const themePreferencesSchema: z.ZodObject<{
|
|
|
343
343
|
primary?: string | undefined;
|
|
344
344
|
toolResult?: string | undefined;
|
|
345
345
|
secondary?: string | undefined;
|
|
346
|
+
border?: string | undefined;
|
|
346
347
|
userMessage?: string | undefined;
|
|
347
348
|
accent?: string | undefined;
|
|
348
349
|
textMuted?: string | undefined;
|
|
349
350
|
textDim?: string | undefined;
|
|
350
351
|
background?: string | undefined;
|
|
351
352
|
backgroundAlt?: string | undefined;
|
|
352
|
-
border?: string | undefined;
|
|
353
353
|
borderActive?: string | undefined;
|
|
354
354
|
borderBusy?: string | undefined;
|
|
355
355
|
assistantMessage?: string | undefined;
|
|
@@ -375,13 +375,13 @@ export declare const themePreferencesSchema: z.ZodObject<{
|
|
|
375
375
|
primary?: string | undefined;
|
|
376
376
|
toolResult?: string | undefined;
|
|
377
377
|
secondary?: string | undefined;
|
|
378
|
+
border?: string | undefined;
|
|
378
379
|
userMessage?: string | undefined;
|
|
379
380
|
accent?: string | undefined;
|
|
380
381
|
textMuted?: string | undefined;
|
|
381
382
|
textDim?: string | undefined;
|
|
382
383
|
background?: string | undefined;
|
|
383
384
|
backgroundAlt?: string | undefined;
|
|
384
|
-
border?: string | undefined;
|
|
385
385
|
borderActive?: string | undefined;
|
|
386
386
|
borderBusy?: string | undefined;
|
|
387
387
|
assistantMessage?: string | undefined;
|
|
@@ -407,13 +407,13 @@ export declare const themePreferencesSchema: z.ZodObject<{
|
|
|
407
407
|
primary?: string | undefined;
|
|
408
408
|
toolResult?: string | undefined;
|
|
409
409
|
secondary?: string | undefined;
|
|
410
|
+
border?: string | undefined;
|
|
410
411
|
userMessage?: string | undefined;
|
|
411
412
|
accent?: string | undefined;
|
|
412
413
|
textMuted?: string | undefined;
|
|
413
414
|
textDim?: string | undefined;
|
|
414
415
|
background?: string | undefined;
|
|
415
416
|
backgroundAlt?: string | undefined;
|
|
416
|
-
border?: string | undefined;
|
|
417
417
|
borderActive?: string | undefined;
|
|
418
418
|
borderBusy?: string | undefined;
|
|
419
419
|
assistantMessage?: string | undefined;
|