vellum 0.0.16 → 0.2.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/.dockerignore +27 -0
- package/.env.example +22 -0
- package/Dockerfile +99 -0
- package/Dockerfile.sandbox +5 -0
- package/README.md +150 -3
- package/bun.lock +1768 -0
- package/bunfig.toml +2 -0
- package/docs/skills.md +158 -0
- package/drizzle/0000_dizzy_maggott.sql +301 -0
- package/drizzle/meta/0000_snapshot.json +1999 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/eslint.config.mjs +17 -0
- package/hook-templates/debug-prompt-logger/hook.json +7 -0
- package/hook-templates/debug-prompt-logger/run.sh +68 -0
- package/knip.json +9 -0
- package/package.json +60 -10
- package/scripts/ipc/check-contract-inventory.ts +104 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +163 -0
- package/scripts/ipc/generate-swift.ts +492 -0
- package/scripts/test-filesystem-tools.sh +48 -0
- package/scripts/test.sh +122 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2079 -0
- package/src/__tests__/account-registry.test.ts +244 -0
- package/src/__tests__/active-skill-tools.test.ts +378 -0
- package/src/__tests__/agent-loop-thinking.test.ts +81 -0
- package/src/__tests__/agent-loop.test.ts +1135 -0
- package/src/__tests__/anthropic-provider.test.ts +778 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
- package/src/__tests__/app-bundler.test.ts +313 -0
- package/src/__tests__/app-executors.test.ts +613 -0
- package/src/__tests__/app-open-proxy.test.ts +62 -0
- package/src/__tests__/asset-materialize-tool.test.ts +451 -0
- package/src/__tests__/asset-search-tool.test.ts +476 -0
- package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
- package/src/__tests__/assistant-attachments.test.ts +437 -0
- package/src/__tests__/assistant-event-hub.test.ts +226 -0
- package/src/__tests__/assistant-event.test.ts +123 -0
- package/src/__tests__/attachments-store.test.ts +547 -0
- package/src/__tests__/attachments.test.ts +134 -0
- package/src/__tests__/audit-log-rotation.test.ts +154 -0
- package/src/__tests__/browser-fill-credential.test.ts +309 -0
- package/src/__tests__/browser-manager.test.ts +203 -0
- package/src/__tests__/browser-runtime-check.test.ts +55 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +67 -0
- package/src/__tests__/browser-skill-endstate.test.ts +198 -0
- package/src/__tests__/bundle-scanner.test.ts +313 -0
- package/src/__tests__/checker.test.ts +3856 -0
- package/src/__tests__/clarification-resolver.test.ts +159 -0
- package/src/__tests__/classifier.test.ts +67 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
- package/src/__tests__/cli-discover.test.ts +85 -0
- package/src/__tests__/cli.test.ts +81 -0
- package/src/__tests__/clipboard.test.ts +80 -0
- package/src/__tests__/commit-guarantee.test.ts +335 -0
- package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
- package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
- package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
- package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
- package/src/__tests__/config-schema.test.ts +720 -0
- package/src/__tests__/conflict-store.test.ts +329 -0
- package/src/__tests__/connection-policy.test.ts +102 -0
- package/src/__tests__/context-memory-e2e.test.ts +434 -0
- package/src/__tests__/context-token-estimator.test.ts +135 -0
- package/src/__tests__/context-window-manager.test.ts +376 -0
- package/src/__tests__/contradiction-checker.test.ts +216 -0
- package/src/__tests__/conversation-store.test.ts +614 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
- package/src/__tests__/credential-broker-server-use.test.ts +554 -0
- package/src/__tests__/credential-broker.test.ts +167 -0
- package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
- package/src/__tests__/credential-metadata-store.test.ts +779 -0
- package/src/__tests__/credential-policy-validate.test.ts +121 -0
- package/src/__tests__/credential-resolve.test.ts +328 -0
- package/src/__tests__/credential-security-e2e.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +563 -0
- package/src/__tests__/credential-selection.test.ts +354 -0
- package/src/__tests__/credential-vault.test.ts +852 -0
- package/src/__tests__/daemon-assistant-events.test.ts +164 -0
- package/src/__tests__/daemon-server-session-init.test.ts +522 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
- package/src/__tests__/diff.test.ts +121 -0
- package/src/__tests__/domain-normalize.test.ts +112 -0
- package/src/__tests__/domain-policy.test.ts +124 -0
- package/src/__tests__/doordash-client.test.ts +186 -0
- package/src/__tests__/doordash-session.test.ts +143 -0
- package/src/__tests__/dynamic-page-surface.test.ts +91 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
- package/src/__tests__/edit-engine.test.ts +180 -0
- package/src/__tests__/email-cli.test.ts +283 -0
- package/src/__tests__/encrypted-store.test.ts +332 -0
- package/src/__tests__/entity-extractor.test.ts +190 -0
- package/src/__tests__/ephemeral-permissions.test.ts +312 -0
- package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
- package/src/__tests__/event-bus.test.ts +222 -0
- package/src/__tests__/file-edit-tool.test.ts +122 -0
- package/src/__tests__/file-ops-service.test.ts +330 -0
- package/src/__tests__/file-read-tool.test.ts +75 -0
- package/src/__tests__/file-write-tool.test.ts +113 -0
- package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
- package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
- package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
- package/src/__tests__/fuzzy-match-property.test.ts +216 -0
- package/src/__tests__/fuzzy-match.test.ts +138 -0
- package/src/__tests__/gemini-image-service.test.ts +261 -0
- package/src/__tests__/gemini-provider.test.ts +651 -0
- package/src/__tests__/get-weather.test.ts +318 -0
- package/src/__tests__/gmail-integration.test.ts +73 -0
- package/src/__tests__/handlers-cu-observation-blob.test.ts +351 -0
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +190 -0
- package/src/__tests__/handlers-slack-config.test.ts +199 -0
- package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
- package/src/__tests__/headless-browser-interactions.test.ts +536 -0
- package/src/__tests__/headless-browser-navigate.test.ts +211 -0
- package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
- package/src/__tests__/history-repair-observability.test.ts +56 -0
- package/src/__tests__/history-repair.test.ts +510 -0
- package/src/__tests__/home-base-bootstrap.test.ts +77 -0
- package/src/__tests__/hooks-blocking.test.ts +128 -0
- package/src/__tests__/hooks-cli.test.ts +144 -0
- package/src/__tests__/hooks-config.test.ts +93 -0
- package/src/__tests__/hooks-discovery.test.ts +199 -0
- package/src/__tests__/hooks-integration.test.ts +189 -0
- package/src/__tests__/hooks-manager.test.ts +187 -0
- package/src/__tests__/hooks-runner.test.ts +178 -0
- package/src/__tests__/hooks-settings.test.ts +154 -0
- package/src/__tests__/hooks-templates.test.ts +137 -0
- package/src/__tests__/hooks-ts-runner.test.ts +125 -0
- package/src/__tests__/hooks-watch.test.ts +100 -0
- package/src/__tests__/host-file-edit-tool.test.ts +104 -0
- package/src/__tests__/host-file-read-tool.test.ts +61 -0
- package/src/__tests__/host-file-write-tool.test.ts +77 -0
- package/src/__tests__/host-shell-tool.test.ts +311 -0
- package/src/__tests__/intent-routing.test.ts +255 -0
- package/src/__tests__/ipc-blob-store.test.ts +315 -0
- package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
- package/src/__tests__/ipc-contract.test.ts +74 -0
- package/src/__tests__/ipc-protocol.test.ts +113 -0
- package/src/__tests__/ipc-snapshot.test.ts +1560 -0
- package/src/__tests__/ipc-validate.test.ts +357 -0
- package/src/__tests__/key-migration.test.ts +183 -0
- package/src/__tests__/keychain.test.ts +258 -0
- package/src/__tests__/llm-usage-store.test.ts +226 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
- package/src/__tests__/managed-store.test.ts +608 -0
- package/src/__tests__/media-generate-image.test.ts +238 -0
- package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
- package/src/__tests__/media-visibility-policy.test.ts +141 -0
- package/src/__tests__/memory-context-benchmark.test.ts +235 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
- package/src/__tests__/memory-query-builder.test.ts +59 -0
- package/src/__tests__/memory-recall-quality.test.ts +846 -0
- package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
- package/src/__tests__/memory-regressions.test.ts +4238 -0
- package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
- package/src/__tests__/migration-cli-flows.test.ts +169 -0
- package/src/__tests__/migration-ordering.test.ts +249 -0
- package/src/__tests__/mock-signup-server.test.ts +528 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +166 -0
- package/src/__tests__/onboarding-template-contract.test.ts +58 -0
- package/src/__tests__/openai-provider.test.ts +753 -0
- package/src/__tests__/parser.test.ts +472 -0
- package/src/__tests__/path-classifier.test.ts +73 -0
- package/src/__tests__/path-policy.test.ts +435 -0
- package/src/__tests__/platform-move-helper.test.ts +99 -0
- package/src/__tests__/platform-socket-path.test.ts +52 -0
- package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
- package/src/__tests__/platform.test.ts +131 -0
- package/src/__tests__/prebuilt-home-base-seed.test.ts +71 -0
- package/src/__tests__/pricing.test.ts +256 -0
- package/src/__tests__/profile-compiler.test.ts +373 -0
- package/src/__tests__/provider-registry-ollama.test.ts +16 -0
- package/src/__tests__/proxy-approval-callback.test.ts +601 -0
- package/src/__tests__/ratelimit.test.ts +297 -0
- package/src/__tests__/registry.test.ts +487 -0
- package/src/__tests__/reminder-store.test.ts +220 -0
- package/src/__tests__/reminder.test.ts +263 -0
- package/src/__tests__/request-file-tool.test.ts +158 -0
- package/src/__tests__/run-orchestrator.test.ts +200 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +190 -0
- package/src/__tests__/runtime-runs-http.test.ts +451 -0
- package/src/__tests__/runtime-runs.test.ts +273 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
- package/src/__tests__/sandbox-host-parity.test.ts +950 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
- package/src/__tests__/script-proxy-certs.test.ts +90 -0
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
- package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
- package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
- package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
- package/src/__tests__/script-proxy-policy.test.ts +310 -0
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
- package/src/__tests__/script-proxy-router.test.ts +180 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
- package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
- package/src/__tests__/secret-allowlist.test.ts +229 -0
- package/src/__tests__/secret-ingress-handler.test.ts +99 -0
- package/src/__tests__/secret-onetime-send.test.ts +130 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
- package/src/__tests__/secret-response-routing.test.ts +93 -0
- package/src/__tests__/secret-scanner-executor.test.ts +348 -0
- package/src/__tests__/secret-scanner.test.ts +857 -0
- package/src/__tests__/secure-keys.test.ts +323 -0
- package/src/__tests__/server-history-render.test.ts +430 -0
- package/src/__tests__/session-abort-tool-results.test.ts +240 -0
- package/src/__tests__/session-conflict-gate.test.ts +697 -0
- package/src/__tests__/session-error.test.ts +341 -0
- package/src/__tests__/session-evictor.test.ts +188 -0
- package/src/__tests__/session-load-history-repair.test.ts +222 -0
- package/src/__tests__/session-pre-run-repair.test.ts +213 -0
- package/src/__tests__/session-profile-injection.test.ts +444 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
- package/src/__tests__/session-queue.test.ts +1462 -0
- package/src/__tests__/session-runtime-assembly.test.ts +315 -0
- package/src/__tests__/session-runtime-workspace.test.ts +183 -0
- package/src/__tests__/session-skill-tools.test.ts +2431 -0
- package/src/__tests__/session-slash-known.test.ts +368 -0
- package/src/__tests__/session-slash-queue.test.ts +288 -0
- package/src/__tests__/session-slash-unknown.test.ts +271 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
- package/src/__tests__/session-undo.test.ts +75 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
- package/src/__tests__/session-workspace-injection.test.ts +327 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
- package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
- package/src/__tests__/shell-credential-ref.test.ts +187 -0
- package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
- package/src/__tests__/shell-parser-property.test.ts +433 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
- package/src/__tests__/signup-e2e.test.ts +352 -0
- package/src/__tests__/size-guard.test.ts +117 -0
- package/src/__tests__/skill-include-graph.test.ts +303 -0
- package/src/__tests__/skill-load-tool.test.ts +409 -0
- package/src/__tests__/skill-script-runner-host.test.ts +489 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
- package/src/__tests__/skill-tool-factory.test.ts +252 -0
- package/src/__tests__/skill-tool-manifest.test.ts +658 -0
- package/src/__tests__/skill-version-hash.test.ts +182 -0
- package/src/__tests__/skills.test.ts +597 -0
- package/src/__tests__/slash-commands-catalog.test.ts +86 -0
- package/src/__tests__/slash-commands-parser.test.ts +119 -0
- package/src/__tests__/slash-commands-resolver.test.ts +193 -0
- package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
- package/src/__tests__/starter-bundle.test.ts +136 -0
- package/src/__tests__/starter-task-flow.test.ts +143 -0
- package/src/__tests__/subagent-manager-notify.test.ts +372 -0
- package/src/__tests__/subagent-tools.test.ts +118 -0
- package/src/__tests__/subagent-types.test.ts +78 -0
- package/src/__tests__/swarm-orchestrator.test.ts +428 -0
- package/src/__tests__/swarm-plan-validator.test.ts +330 -0
- package/src/__tests__/swarm-recursion.test.ts +165 -0
- package/src/__tests__/swarm-router-planner.test.ts +208 -0
- package/src/__tests__/swarm-session-integration.test.ts +274 -0
- package/src/__tests__/swarm-tool.test.ts +145 -0
- package/src/__tests__/swarm-worker-backend.test.ts +129 -0
- package/src/__tests__/swarm-worker-runner.test.ts +272 -0
- package/src/__tests__/system-prompt.test.ts +461 -0
- package/src/__tests__/task-compiler.test.ts +283 -0
- package/src/__tests__/task-runner.test.ts +215 -0
- package/src/__tests__/task-scheduler.test.ts +216 -0
- package/src/__tests__/task-tools.test.ts +602 -0
- package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
- package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
- package/src/__tests__/terminal-sandbox.test.ts +202 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
- package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
- package/src/__tests__/tool-audit-listener.test.ts +112 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +251 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
- package/src/__tests__/tool-executor-redaction.test.ts +289 -0
- package/src/__tests__/tool-executor.test.ts +1971 -0
- package/src/__tests__/tool-metrics-listener.test.ts +225 -0
- package/src/__tests__/tool-notification-listener.test.ts +49 -0
- package/src/__tests__/tool-policy.test.ts +54 -0
- package/src/__tests__/tool-profiling-listener.test.ts +268 -0
- package/src/__tests__/tool-result-truncation.test.ts +217 -0
- package/src/__tests__/tool-trace-listener.test.ts +226 -0
- package/src/__tests__/top-level-renderer.test.ts +121 -0
- package/src/__tests__/top-level-scanner.test.ts +141 -0
- package/src/__tests__/trace-emitter.test.ts +173 -0
- package/src/__tests__/trust-store.test.ts +2030 -0
- package/src/__tests__/turn-commit.test.ts +219 -0
- package/src/__tests__/url-safety.test.ts +418 -0
- package/src/__tests__/weather-skill-regression.test.ts +225 -0
- package/src/__tests__/web-fetch.test.ts +869 -0
- package/src/__tests__/web-search.test.ts +584 -0
- package/src/__tests__/workspace-git-service.test.ts +750 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +347 -0
- package/src/__tests__/workspace-lifecycle.test.ts +292 -0
- package/src/agent/attachments.ts +35 -0
- package/src/agent/loop.ts +500 -0
- package/src/agent/message-types.ts +17 -0
- package/src/autonomy/autonomy-resolver.ts +60 -0
- package/src/autonomy/autonomy-store.ts +122 -0
- package/src/autonomy/disposition-mapper.ts +31 -0
- package/src/autonomy/index.ts +11 -0
- package/src/autonomy/types.ts +39 -0
- package/src/bundler/app-bundler.ts +274 -0
- package/src/bundler/bundle-scanner.ts +535 -0
- package/src/bundler/bundle-signer.ts +124 -0
- package/src/bundler/manifest.ts +21 -0
- package/src/bundler/signature-verifier.ts +184 -0
- package/src/cli/autonomy.ts +188 -0
- package/src/cli/contacts.ts +149 -0
- package/src/cli/doordash.ts +824 -0
- package/src/cli/email-guardrails.ts +200 -0
- package/src/cli/email.ts +405 -0
- package/src/cli/main-screen.tsx +155 -0
- package/src/cli.ts +935 -0
- package/src/config/bundled-skills/.gitkeep +0 -0
- package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
- package/src/config/bundled-skills/agentmail/icon.svg +21 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +1348 -0
- package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
- package/src/config/bundled-skills/app-builder/icon.svg +9 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
- package/src/config/bundled-skills/browser/SKILL.md +28 -0
- package/src/config/bundled-skills/browser/TOOLS.json +234 -0
- package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
- package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
- package/src/config/bundled-skills/google-calendar/types.ts +97 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +137 -0
- package/src/config/bundled-skills/messaging/SKILL.md +126 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +124 -0
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +29 -0
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +27 -0
- package/src/config/bundled-skills/messaging/tools/shared.ts +71 -0
- package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
- package/src/config/bundled-skills/self-upgrade/SKILL.md +74 -0
- package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
- package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
- package/src/config/bundled-skills/weather/SKILL.md +37 -0
- package/src/config/bundled-skills/weather/TOOLS.json +32 -0
- package/src/config/bundled-skills/weather/icon.svg +24 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
- package/src/config/computer-use-prompt.ts +97 -0
- package/src/config/defaults.ts +186 -0
- package/src/config/loader.ts +336 -0
- package/src/config/schema.ts +1004 -0
- package/src/config/skill-state.ts +95 -0
- package/src/config/skills.ts +972 -0
- package/src/config/system-prompt.ts +927 -0
- package/src/config/templates/BOOTSTRAP.md +70 -0
- package/src/config/templates/IDENTITY.md +18 -0
- package/src/config/templates/LOOKS.md +25 -0
- package/src/config/templates/SOUL.md +37 -0
- package/src/config/templates/USER.md +19 -0
- package/src/config/types.ts +32 -0
- package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
- package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +194 -0
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +147 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +105 -0
- package/src/contacts/contact-store.ts +410 -0
- package/src/contacts/index.ts +11 -0
- package/src/contacts/types.ts +28 -0
- package/src/context/token-estimator.ts +108 -0
- package/src/context/tool-result-truncation.ts +128 -0
- package/src/context/window-manager.ts +531 -0
- package/src/daemon/assistant-attachments.ts +679 -0
- package/src/daemon/classifier.ts +108 -0
- package/src/daemon/computer-use-session.ts +900 -0
- package/src/daemon/connection-policy.ts +41 -0
- package/src/daemon/handlers/apps.ts +446 -0
- package/src/daemon/handlers/computer-use.ts +181 -0
- package/src/daemon/handlers/config.ts +434 -0
- package/src/daemon/handlers/diagnostics.ts +334 -0
- package/src/daemon/handlers/documents.ts +184 -0
- package/src/daemon/handlers/home-base.ts +73 -0
- package/src/daemon/handlers/index.ts +355 -0
- package/src/daemon/handlers/misc.ts +323 -0
- package/src/daemon/handlers/open-bundle-handler.ts +80 -0
- package/src/daemon/handlers/publish.ts +182 -0
- package/src/daemon/handlers/sessions.ts +486 -0
- package/src/daemon/handlers/shared.ts +533 -0
- package/src/daemon/handlers/skills.ts +487 -0
- package/src/daemon/handlers/subagents.ts +122 -0
- package/src/daemon/handlers/work-items.ts +176 -0
- package/src/daemon/handlers.ts +17 -0
- package/src/daemon/history-repair.ts +214 -0
- package/src/daemon/ipc-blob-store.ts +231 -0
- package/src/daemon/ipc-contract-inventory.json +407 -0
- package/src/daemon/ipc-contract-inventory.ts +126 -0
- package/src/daemon/ipc-contract.ts +2102 -0
- package/src/daemon/ipc-protocol.ts +70 -0
- package/src/daemon/ipc-validate.ts +171 -0
- package/src/daemon/lifecycle.ts +503 -0
- package/src/daemon/main.ts +15 -0
- package/src/daemon/media-visibility-policy.ts +57 -0
- package/src/daemon/ride-shotgun-handler.ts +244 -0
- package/src/daemon/server.ts +1085 -0
- package/src/daemon/session-attachments.ts +173 -0
- package/src/daemon/session-conflict-gate.ts +219 -0
- package/src/daemon/session-dynamic-profile.ts +63 -0
- package/src/daemon/session-error.ts +269 -0
- package/src/daemon/session-evictor.ts +196 -0
- package/src/daemon/session-history.ts +437 -0
- package/src/daemon/session-memory.ts +212 -0
- package/src/daemon/session-process.ts +264 -0
- package/src/daemon/session-queue-manager.ts +81 -0
- package/src/daemon/session-runtime-assembly.ts +395 -0
- package/src/daemon/session-skill-tools.ts +237 -0
- package/src/daemon/session-slash.ts +302 -0
- package/src/daemon/session-surfaces.ts +624 -0
- package/src/daemon/session-tool-setup.ts +286 -0
- package/src/daemon/session-usage.ts +74 -0
- package/src/daemon/session-workspace.ts +19 -0
- package/src/daemon/session.ts +1651 -0
- package/src/daemon/trace-emitter.ts +82 -0
- package/src/daemon/watch-handler.ts +274 -0
- package/src/doordash/client.ts +905 -0
- package/src/doordash/queries.ts +1312 -0
- package/src/doordash/query-extractor.ts +93 -0
- package/src/doordash/session.ts +82 -0
- package/src/email/provider.ts +117 -0
- package/src/email/providers/agentmail.ts +317 -0
- package/src/email/providers/index.ts +58 -0
- package/src/email/service.ts +303 -0
- package/src/email/types.ts +126 -0
- package/src/events/bus.ts +157 -0
- package/src/events/domain-events.ts +83 -0
- package/src/events/index.ts +18 -0
- package/src/events/tool-audit-listener.ts +80 -0
- package/src/events/tool-domain-event-publisher.ts +111 -0
- package/src/events/tool-metrics-listener.ts +159 -0
- package/src/events/tool-notification-listener.ts +17 -0
- package/src/events/tool-profiling-listener.ts +158 -0
- package/src/events/tool-trace-listener.ts +75 -0
- package/src/export/formatter.ts +96 -0
- package/src/followups/followup-store.ts +166 -0
- package/src/followups/index.ts +10 -0
- package/src/followups/types.ts +23 -0
- package/src/gallery/default-gallery.ts +795 -0
- package/src/gallery/gallery-manifest.ts +24 -0
- package/src/home-base/app-link-store.ts +82 -0
- package/src/home-base/bootstrap.ts +66 -0
- package/src/home-base/prebuilt/index.html +662 -0
- package/src/home-base/prebuilt/seed-metadata.json +21 -0
- package/src/home-base/prebuilt/seed.ts +101 -0
- package/src/home-base/prebuilt-home-base-updater.ts +30 -0
- package/src/hooks/cli.ts +163 -0
- package/src/hooks/config.ts +88 -0
- package/src/hooks/discovery.ts +110 -0
- package/src/hooks/manager.ts +128 -0
- package/src/hooks/runner.ts +123 -0
- package/src/hooks/templates.ts +52 -0
- package/src/hooks/types.ts +72 -0
- package/src/index.ts +1194 -0
- package/src/instrument.ts +60 -0
- package/src/logfire.ts +99 -0
- package/src/media/gemini-image-service.ts +136 -0
- package/src/memory/account-store.ts +108 -0
- package/src/memory/admin.ts +211 -0
- package/src/memory/app-store.ts +556 -0
- package/src/memory/attachments-store.ts +453 -0
- package/src/memory/channel-delivery-store.ts +368 -0
- package/src/memory/checkpoints.ts +52 -0
- package/src/memory/clarification-resolver.ts +297 -0
- package/src/memory/conflict-store.ts +342 -0
- package/src/memory/contradiction-checker.ts +329 -0
- package/src/memory/conversation-key-store.ts +127 -0
- package/src/memory/conversation-store.ts +469 -0
- package/src/memory/db.ts +1105 -0
- package/src/memory/embedding-backend.ts +229 -0
- package/src/memory/embedding-gemini.ts +52 -0
- package/src/memory/embedding-local.ts +75 -0
- package/src/memory/embedding-ollama.ts +55 -0
- package/src/memory/embedding-openai.ts +25 -0
- package/src/memory/entity-extractor.ts +471 -0
- package/src/memory/fingerprint.ts +20 -0
- package/src/memory/indexer.ts +156 -0
- package/src/memory/items-extractor.ts +460 -0
- package/src/memory/job-handlers/backfill.ts +139 -0
- package/src/memory/job-handlers/cleanup.ts +58 -0
- package/src/memory/job-handlers/conflict.ts +99 -0
- package/src/memory/job-handlers/embedding.ts +61 -0
- package/src/memory/job-handlers/extraction.ts +123 -0
- package/src/memory/job-handlers/index-maintenance.ts +54 -0
- package/src/memory/job-handlers/summarization.ts +286 -0
- package/src/memory/job-utils.ts +170 -0
- package/src/memory/jobs-store.ts +400 -0
- package/src/memory/jobs-worker.ts +274 -0
- package/src/memory/llm-request-log-store.ts +45 -0
- package/src/memory/llm-usage-store.ts +62 -0
- package/src/memory/message-content.ts +54 -0
- package/src/memory/profile-compiler.ts +160 -0
- package/src/memory/published-pages-store.ts +137 -0
- package/src/memory/qdrant-client.ts +366 -0
- package/src/memory/qdrant-manager.ts +242 -0
- package/src/memory/query-builder.ts +45 -0
- package/src/memory/retrieval-budget.ts +30 -0
- package/src/memory/retriever.ts +653 -0
- package/src/memory/runs-store.ts +211 -0
- package/src/memory/schema.ts +529 -0
- package/src/memory/search/entity.ts +298 -0
- package/src/memory/search/formatting.ts +207 -0
- package/src/memory/search/lexical.ts +227 -0
- package/src/memory/search/ranking.ts +401 -0
- package/src/memory/search/semantic.ts +121 -0
- package/src/memory/search/types.ts +137 -0
- package/src/memory/segmenter.ts +68 -0
- package/src/memory/shared-app-links-store.ts +138 -0
- package/src/memory/tool-usage-store.ts +62 -0
- package/src/messaging/activity-analyzer.ts +76 -0
- package/src/messaging/draft-store.ts +88 -0
- package/src/messaging/index.ts +3 -0
- package/src/messaging/provider-types.ts +80 -0
- package/src/messaging/provider.ts +43 -0
- package/src/messaging/providers/gmail/adapter.ts +193 -0
- package/src/messaging/providers/gmail/client.ts +204 -0
- package/src/messaging/providers/gmail/types.ts +90 -0
- package/src/messaging/providers/slack/adapter.ts +202 -0
- package/src/messaging/providers/slack/client.ts +198 -0
- package/src/messaging/providers/slack/types.ts +119 -0
- package/src/messaging/registry.ts +34 -0
- package/src/messaging/style-analyzer.ts +158 -0
- package/src/messaging/thread-summarizer.ts +310 -0
- package/src/messaging/triage-engine.ts +321 -0
- package/src/messaging/types.ts +55 -0
- package/src/permissions/checker.ts +636 -0
- package/src/permissions/defaults.ts +243 -0
- package/src/permissions/prompter.ts +102 -0
- package/src/permissions/secret-prompter.ts +114 -0
- package/src/permissions/trust-store.ts +584 -0
- package/src/permissions/types.ts +62 -0
- package/src/playbooks/index.ts +2 -0
- package/src/playbooks/playbook-compiler.ts +90 -0
- package/src/playbooks/types.ts +55 -0
- package/src/providers/anthropic/client.ts +751 -0
- package/src/providers/failover.ts +129 -0
- package/src/providers/fireworks/client.ts +20 -0
- package/src/providers/gemini/client.ts +285 -0
- package/src/providers/ollama/client.ts +30 -0
- package/src/providers/openai/client.ts +337 -0
- package/src/providers/ratelimit.ts +93 -0
- package/src/providers/registry.ts +138 -0
- package/src/providers/retry.ts +106 -0
- package/src/providers/stream-timeout.ts +38 -0
- package/src/providers/types.ts +109 -0
- package/src/runtime/assistant-event-hub.ts +120 -0
- package/src/runtime/assistant-event.ts +82 -0
- package/src/runtime/http-server.ts +478 -0
- package/src/runtime/http-types.ts +68 -0
- package/src/runtime/routes/app-routes.ts +174 -0
- package/src/runtime/routes/attachment-routes.ts +134 -0
- package/src/runtime/routes/channel-routes.ts +342 -0
- package/src/runtime/routes/conversation-routes.ts +349 -0
- package/src/runtime/routes/run-routes.ts +223 -0
- package/src/runtime/routes/secret-routes.ts +76 -0
- package/src/runtime/run-orchestrator.ts +206 -0
- package/src/schedule/schedule-store.ts +452 -0
- package/src/schedule/scheduler.ts +168 -0
- package/src/security/encrypted-store.ts +238 -0
- package/src/security/keychain.ts +252 -0
- package/src/security/oauth2.ts +241 -0
- package/src/security/redaction.ts +89 -0
- package/src/security/secret-allowlist.ts +118 -0
- package/src/security/secret-ingress.ts +57 -0
- package/src/security/secret-scanner.ts +543 -0
- package/src/security/secure-keys.ts +180 -0
- package/src/security/token-manager.ts +141 -0
- package/src/services/published-app-updater.ts +69 -0
- package/src/services/vercel-deploy.ts +73 -0
- package/src/skills/active-skill-tools.ts +81 -0
- package/src/skills/clawhub.ts +414 -0
- package/src/skills/include-graph.ts +146 -0
- package/src/skills/managed-store.ts +233 -0
- package/src/skills/path-classifier.ts +128 -0
- package/src/skills/slash-commands.ts +174 -0
- package/src/skills/tool-manifest.ts +165 -0
- package/src/skills/version-hash.ts +110 -0
- package/src/slack/slack-webhook.ts +61 -0
- package/src/subagent/index.ts +19 -0
- package/src/subagent/manager.ts +477 -0
- package/src/subagent/types.ts +69 -0
- package/src/swarm/backend-claude-code.ts +90 -0
- package/src/swarm/index.ts +44 -0
- package/src/swarm/limits.ts +37 -0
- package/src/swarm/orchestrator.ts +279 -0
- package/src/swarm/plan-validator.ts +151 -0
- package/src/swarm/router-planner.ts +100 -0
- package/src/swarm/router-prompts.ts +36 -0
- package/src/swarm/synthesizer.ts +62 -0
- package/src/swarm/types.ts +62 -0
- package/src/swarm/worker-backend.ts +121 -0
- package/src/swarm/worker-prompts.ts +78 -0
- package/src/swarm/worker-runner.ts +164 -0
- package/src/tasks/SPEC.md +133 -0
- package/src/tasks/candidate-store.ts +86 -0
- package/src/tasks/ephemeral-permissions.ts +41 -0
- package/src/tasks/task-compiler.ts +198 -0
- package/src/tasks/task-runner.ts +85 -0
- package/src/tasks/task-scheduler.ts +20 -0
- package/src/tasks/task-store.ts +127 -0
- package/src/tools/apps/definitions.ts +59 -0
- package/src/tools/apps/executors.ts +313 -0
- package/src/tools/apps/open-proxy.ts +43 -0
- package/src/tools/apps/registry.ts +16 -0
- package/src/tools/assets/materialize.ts +218 -0
- package/src/tools/assets/search.ts +396 -0
- package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
- package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
- package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
- package/src/tools/browser/auth-cache.ts +149 -0
- package/src/tools/browser/auth-detector.ts +347 -0
- package/src/tools/browser/browser-execution.ts +979 -0
- package/src/tools/browser/browser-handoff.ts +79 -0
- package/src/tools/browser/browser-manager.ts +715 -0
- package/src/tools/browser/browser-screencast.ts +217 -0
- package/src/tools/browser/headless-browser.ts +450 -0
- package/src/tools/browser/jit-auth.ts +51 -0
- package/src/tools/browser/network-recorder.ts +348 -0
- package/src/tools/browser/network-recording-types.ts +49 -0
- package/src/tools/browser/recording-store.ts +49 -0
- package/src/tools/browser/runtime-check.ts +43 -0
- package/src/tools/claude-code/claude-code.ts +232 -0
- package/src/tools/computer-use/definitions.ts +443 -0
- package/src/tools/computer-use/registry.ts +22 -0
- package/src/tools/computer-use/request-computer-control.ts +53 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
- package/src/tools/contacts/contact-merge.ts +87 -0
- package/src/tools/contacts/contact-search.ts +102 -0
- package/src/tools/contacts/contact-upsert.ts +137 -0
- package/src/tools/contacts/index.ts +4 -0
- package/src/tools/credentials/account-registry.ts +127 -0
- package/src/tools/credentials/broker-types.ts +107 -0
- package/src/tools/credentials/broker.ts +372 -0
- package/src/tools/credentials/domain-policy.ts +51 -0
- package/src/tools/credentials/host-pattern-match.ts +60 -0
- package/src/tools/credentials/metadata-store.ts +335 -0
- package/src/tools/credentials/policy-types.ts +52 -0
- package/src/tools/credentials/policy-validate.ts +80 -0
- package/src/tools/credentials/resolve.ts +122 -0
- package/src/tools/credentials/selection.ts +159 -0
- package/src/tools/credentials/tool-policy.ts +25 -0
- package/src/tools/credentials/vault.ts +641 -0
- package/src/tools/document/document-tool.ts +165 -0
- package/src/tools/document/editor-template.ts +237 -0
- package/src/tools/document/index.ts +5 -0
- package/src/tools/executor.ts +825 -0
- package/src/tools/filesystem/edit.ts +127 -0
- package/src/tools/filesystem/fuzzy-match.ts +202 -0
- package/src/tools/filesystem/read.ts +71 -0
- package/src/tools/filesystem/view-image.ts +199 -0
- package/src/tools/filesystem/write.ts +79 -0
- package/src/tools/followups/followup_create.ts +118 -0
- package/src/tools/followups/followup_list.ts +100 -0
- package/src/tools/followups/followup_resolve.ts +91 -0
- package/src/tools/followups/index.ts +3 -0
- package/src/tools/host-filesystem/edit.ts +125 -0
- package/src/tools/host-filesystem/read.ts +80 -0
- package/src/tools/host-filesystem/write.ts +76 -0
- package/src/tools/host-terminal/cli-discover.ts +179 -0
- package/src/tools/host-terminal/host-shell.ts +181 -0
- package/src/tools/memory/definitions.ts +69 -0
- package/src/tools/memory/handlers.ts +245 -0
- package/src/tools/memory/register.ts +66 -0
- package/src/tools/network/domain-normalize.ts +85 -0
- package/src/tools/network/script-proxy/certs.ts +237 -0
- package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
- package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
- package/src/tools/network/script-proxy/index.ts +28 -0
- package/src/tools/network/script-proxy/logging.ts +196 -0
- package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
- package/src/tools/network/script-proxy/policy.ts +152 -0
- package/src/tools/network/script-proxy/router.ts +60 -0
- package/src/tools/network/script-proxy/server.ts +136 -0
- package/src/tools/network/script-proxy/session-manager.ts +534 -0
- package/src/tools/network/script-proxy/types.ts +125 -0
- package/src/tools/network/url-safety.ts +227 -0
- package/src/tools/network/web-fetch.ts +701 -0
- package/src/tools/network/web-search.ts +319 -0
- package/src/tools/playbooks/index.ts +5 -0
- package/src/tools/playbooks/playbook-create.ts +140 -0
- package/src/tools/playbooks/playbook-delete.ts +76 -0
- package/src/tools/playbooks/playbook-list.ts +101 -0
- package/src/tools/playbooks/playbook-update.ts +159 -0
- package/src/tools/registry.ts +297 -0
- package/src/tools/reminder/reminder-store.ts +148 -0
- package/src/tools/reminder/reminder.ts +153 -0
- package/src/tools/schedule/create.ts +86 -0
- package/src/tools/schedule/delete.ts +54 -0
- package/src/tools/schedule/list.ts +88 -0
- package/src/tools/schedule/update.ts +97 -0
- package/src/tools/shared/filesystem/edit-engine.ts +56 -0
- package/src/tools/shared/filesystem/errors.ts +85 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
- package/src/tools/shared/filesystem/format-diff.ts +35 -0
- package/src/tools/shared/filesystem/path-policy.ts +125 -0
- package/src/tools/shared/filesystem/size-guard.ts +41 -0
- package/src/tools/shared/filesystem/types.ts +80 -0
- package/src/tools/shared/shell-output.ts +52 -0
- package/src/tools/skills/delete-managed.ts +60 -0
- package/src/tools/skills/load.ts +139 -0
- package/src/tools/skills/sandbox-runner.ts +279 -0
- package/src/tools/skills/scaffold-managed.ts +150 -0
- package/src/tools/skills/script-contract.ts +6 -0
- package/src/tools/skills/skill-script-runner.ts +86 -0
- package/src/tools/skills/skill-tool-factory.ts +64 -0
- package/src/tools/skills/vellum-catalog.ts +217 -0
- package/src/tools/subagent/abort.ts +62 -0
- package/src/tools/subagent/index.ts +5 -0
- package/src/tools/subagent/message.ts +72 -0
- package/src/tools/subagent/read.ts +98 -0
- package/src/tools/subagent/spawn.ts +85 -0
- package/src/tools/subagent/status.ts +74 -0
- package/src/tools/swarm/delegate.ts +182 -0
- package/src/tools/system/request-permission.ts +98 -0
- package/src/tools/tasks/index.ts +25 -0
- package/src/tools/tasks/task-delete.ts +69 -0
- package/src/tools/tasks/task-list.ts +65 -0
- package/src/tools/tasks/task-run.ts +125 -0
- package/src/tools/tasks/task-save.ts +79 -0
- package/src/tools/tasks/work-item-enqueue.ts +176 -0
- package/src/tools/tasks/work-item-list.ts +86 -0
- package/src/tools/terminal/backends/docker.ts +372 -0
- package/src/tools/terminal/backends/native.ts +188 -0
- package/src/tools/terminal/backends/types.ts +26 -0
- package/src/tools/terminal/evaluate-typescript.ts +275 -0
- package/src/tools/terminal/parser.ts +393 -0
- package/src/tools/terminal/safe-env.ts +37 -0
- package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
- package/src/tools/terminal/sandbox.ts +44 -0
- package/src/tools/terminal/shell.ts +257 -0
- package/src/tools/tool-manifest.ts +250 -0
- package/src/tools/types.ts +177 -0
- package/src/tools/ui-surface/definitions.ts +232 -0
- package/src/tools/ui-surface/registry.ts +14 -0
- package/src/tools/watch/screen-watch.ts +128 -0
- package/src/tools/watch/watch-state.ts +119 -0
- package/src/tools/watcher/create.ts +110 -0
- package/src/tools/watcher/delete.ts +53 -0
- package/src/tools/watcher/digest.ts +84 -0
- package/src/tools/watcher/list.ts +90 -0
- package/src/tools/watcher/update.ts +102 -0
- package/src/tools/weather/service.ts +551 -0
- package/src/usage/actors.ts +24 -0
- package/src/usage/types.ts +38 -0
- package/src/util/clipboard.ts +33 -0
- package/src/util/content-id.ts +16 -0
- package/src/util/diff.ts +181 -0
- package/src/util/errors.ts +129 -0
- package/src/util/logger.ts +243 -0
- package/src/util/platform.ts +607 -0
- package/src/util/pricing.ts +150 -0
- package/src/util/spinner.ts +51 -0
- package/src/util/time.ts +16 -0
- package/src/util/xml.ts +4 -0
- package/src/version.ts +3 -0
- package/src/watcher/constants.ts +11 -0
- package/src/watcher/engine.ts +199 -0
- package/src/watcher/provider-registry.ts +15 -0
- package/src/watcher/provider-types.ts +48 -0
- package/src/watcher/providers/gmail.ts +198 -0
- package/src/watcher/providers/google-calendar.ts +228 -0
- package/src/watcher/providers/slack.ts +128 -0
- package/src/watcher/watcher-store.ts +418 -0
- package/src/work-items/work-item-store.ts +91 -0
- package/src/workspace/git-service.ts +620 -0
- package/src/workspace/heartbeat-service.ts +288 -0
- package/src/workspace/top-level-renderer.ts +19 -0
- package/src/workspace/top-level-scanner.ts +41 -0
- package/src/workspace/turn-commit.ts +122 -0
- package/tsconfig.json +21 -0
- package/LICENSE +0 -674
- package/dist/cli.js +0 -569
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, renameSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { getWorkspaceSkillsDir } from '../util/platform.js';
|
|
5
|
+
import { getLogger } from '../util/logger.js';
|
|
6
|
+
|
|
7
|
+
const log = getLogger('managed-store');
|
|
8
|
+
|
|
9
|
+
// ─── Validation ──────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
const VALID_SKILL_ID = /^[a-z0-9][a-z0-9._-]*$/;
|
|
12
|
+
|
|
13
|
+
export function validateManagedSkillId(id: string): string | null {
|
|
14
|
+
if (!id || typeof id !== 'string') return 'skill_id is required';
|
|
15
|
+
if (id.includes('..') || id.includes('/') || id.includes('\\')) {
|
|
16
|
+
return 'skill_id must not contain path traversal characters';
|
|
17
|
+
}
|
|
18
|
+
if (!VALID_SKILL_ID.test(id)) {
|
|
19
|
+
return 'skill_id must start with a lowercase letter or digit and contain only lowercase letters, digits, dots, hyphens, and underscores';
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ─── Path helpers ────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export function getManagedSkillsDir(): string {
|
|
27
|
+
return getWorkspaceSkillsDir();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getManagedSkillDir(id: string): string {
|
|
31
|
+
return join(getManagedSkillsDir(), id);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getSkillsIndexPath(): string {
|
|
35
|
+
return join(getManagedSkillsDir(), 'SKILLS.md');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── SKILL.md generation ─────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
export interface BuildSkillMarkdownInput {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
bodyMarkdown: string;
|
|
44
|
+
emoji?: string;
|
|
45
|
+
userInvocable?: boolean;
|
|
46
|
+
disableModelInvocation?: boolean;
|
|
47
|
+
includes?: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function buildSkillMarkdown(input: BuildSkillMarkdownInput): string {
|
|
51
|
+
const esc = (s: string) => s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
|
|
52
|
+
const lines: string[] = ['---'];
|
|
53
|
+
lines.push(`name: "${esc(input.name)}"`);
|
|
54
|
+
lines.push(`description: "${esc(input.description)}"`);
|
|
55
|
+
if (input.emoji) {
|
|
56
|
+
lines.push(`emoji: "${esc(input.emoji)}"`);
|
|
57
|
+
}
|
|
58
|
+
if (input.userInvocable === false) {
|
|
59
|
+
lines.push('user-invocable: false');
|
|
60
|
+
}
|
|
61
|
+
if (input.disableModelInvocation === true) {
|
|
62
|
+
lines.push('disable-model-invocation: true');
|
|
63
|
+
}
|
|
64
|
+
if (input.includes && input.includes.length > 0) {
|
|
65
|
+
lines.push(`includes: ${JSON.stringify(input.includes)}`);
|
|
66
|
+
}
|
|
67
|
+
lines.push('---');
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(input.bodyMarkdown);
|
|
70
|
+
// Ensure trailing newline
|
|
71
|
+
const content = lines.join('\n');
|
|
72
|
+
return content.endsWith('\n') ? content : content + '\n';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ─── Atomic write ────────────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
function atomicWriteFile(filePath: string, content: string): void {
|
|
78
|
+
const dir = dirname(filePath);
|
|
79
|
+
const tmpPath = join(dir, `.tmp-${randomUUID()}`);
|
|
80
|
+
writeFileSync(tmpPath, content, 'utf-8');
|
|
81
|
+
renameSync(tmpPath, filePath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── SKILLS.md index management ──────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
function readIndexLines(): string[] {
|
|
87
|
+
const indexPath = getSkillsIndexPath();
|
|
88
|
+
if (!existsSync(indexPath)) return [];
|
|
89
|
+
return readFileSync(indexPath, 'utf-8').split('\n');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function writeIndexLines(lines: string[]): void {
|
|
93
|
+
const content = lines.join('\n');
|
|
94
|
+
atomicWriteFile(getSkillsIndexPath(), content.endsWith('\n') ? content : content + '\n');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function indexEntryRegex(id: string): RegExp {
|
|
98
|
+
const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
99
|
+
// Match both - and * bullets, optional backticks, optional markdown link wrapping,
|
|
100
|
+
// and optional /SKILL.md suffix (inside or outside link parens)
|
|
101
|
+
return new RegExp(`^[-*]\\s+(?:\`)?(?:\\[.*?\\]\\()?${escaped}(?:/SKILL\\.md)?(?:\\))?(?:\`)?\\s*$`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function upsertSkillsIndexEntry(id: string): void {
|
|
105
|
+
const lines = readIndexLines();
|
|
106
|
+
const pattern = indexEntryRegex(id);
|
|
107
|
+
if (lines.some((line) => pattern.test(line))) {
|
|
108
|
+
return; // already present
|
|
109
|
+
}
|
|
110
|
+
// Append new entry
|
|
111
|
+
const nonEmpty = lines.filter((l) => l.trim());
|
|
112
|
+
nonEmpty.push(`- ${id}`);
|
|
113
|
+
writeIndexLines(nonEmpty);
|
|
114
|
+
log.info({ id }, 'Added managed skill to SKILLS.md index');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function removeSkillsIndexEntry(id: string): void {
|
|
118
|
+
const lines = readIndexLines();
|
|
119
|
+
const pattern = indexEntryRegex(id);
|
|
120
|
+
const filtered = lines.filter((line) => !pattern.test(line));
|
|
121
|
+
if (filtered.length === lines.length) {
|
|
122
|
+
return; // not found
|
|
123
|
+
}
|
|
124
|
+
writeIndexLines(filtered.filter((l) => l.trim()));
|
|
125
|
+
log.info({ id }, 'Removed managed skill from SKILLS.md index');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── Create / Delete ─────────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
export interface CreateManagedSkillParams {
|
|
131
|
+
id: string;
|
|
132
|
+
name: string;
|
|
133
|
+
description: string;
|
|
134
|
+
bodyMarkdown: string;
|
|
135
|
+
emoji?: string;
|
|
136
|
+
userInvocable?: boolean;
|
|
137
|
+
disableModelInvocation?: boolean;
|
|
138
|
+
overwrite?: boolean;
|
|
139
|
+
addToIndex?: boolean;
|
|
140
|
+
includes?: string[];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface CreateManagedSkillResult {
|
|
144
|
+
created: boolean;
|
|
145
|
+
path: string;
|
|
146
|
+
indexUpdated: boolean;
|
|
147
|
+
error?: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function createManagedSkill(params: CreateManagedSkillParams): CreateManagedSkillResult {
|
|
151
|
+
const validationError = validateManagedSkillId(params.id);
|
|
152
|
+
if (validationError) {
|
|
153
|
+
return { created: false, path: '', indexUpdated: false, error: validationError };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!params.name || !params.name.trim()) {
|
|
157
|
+
return { created: false, path: '', indexUpdated: false, error: 'name is required' };
|
|
158
|
+
}
|
|
159
|
+
if (!params.description || !params.description.trim()) {
|
|
160
|
+
return { created: false, path: '', indexUpdated: false, error: 'description is required' };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const skillDir = getManagedSkillDir(params.id);
|
|
164
|
+
const skillFilePath = join(skillDir, 'SKILL.md');
|
|
165
|
+
|
|
166
|
+
if (existsSync(skillFilePath) && !params.overwrite) {
|
|
167
|
+
return {
|
|
168
|
+
created: false,
|
|
169
|
+
path: skillFilePath,
|
|
170
|
+
indexUpdated: false,
|
|
171
|
+
error: `Managed skill "${params.id}" already exists. Set overwrite=true to replace it.`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const content = buildSkillMarkdown({
|
|
176
|
+
name: params.name,
|
|
177
|
+
description: params.description,
|
|
178
|
+
bodyMarkdown: params.bodyMarkdown,
|
|
179
|
+
emoji: params.emoji,
|
|
180
|
+
userInvocable: params.userInvocable,
|
|
181
|
+
disableModelInvocation: params.disableModelInvocation,
|
|
182
|
+
includes: params.includes,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
mkdirSync(skillDir, { recursive: true });
|
|
186
|
+
atomicWriteFile(skillFilePath, content);
|
|
187
|
+
log.info({ id: params.id, path: skillFilePath }, 'Created managed skill');
|
|
188
|
+
|
|
189
|
+
let indexUpdated = false;
|
|
190
|
+
if (params.addToIndex !== false) {
|
|
191
|
+
upsertSkillsIndexEntry(params.id);
|
|
192
|
+
indexUpdated = true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return { created: true, path: skillFilePath, indexUpdated };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface DeleteManagedSkillResult {
|
|
199
|
+
deleted: boolean;
|
|
200
|
+
indexUpdated: boolean;
|
|
201
|
+
error?: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function deleteManagedSkill(
|
|
205
|
+
id: string,
|
|
206
|
+
removeFromIndex = true,
|
|
207
|
+
): DeleteManagedSkillResult {
|
|
208
|
+
const validationError = validateManagedSkillId(id);
|
|
209
|
+
if (validationError) {
|
|
210
|
+
return { deleted: false, indexUpdated: false, error: validationError };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const skillDir = getManagedSkillDir(id);
|
|
214
|
+
if (!existsSync(skillDir)) {
|
|
215
|
+
return { deleted: false, indexUpdated: false, error: `Managed skill "${id}" not found` };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
rmSync(skillDir, { recursive: true });
|
|
219
|
+
log.info({ id, path: skillDir }, 'Deleted managed skill');
|
|
220
|
+
|
|
221
|
+
let indexUpdated = false;
|
|
222
|
+
if (removeFromIndex) {
|
|
223
|
+
try {
|
|
224
|
+
removeSkillsIndexEntry(id);
|
|
225
|
+
indexUpdated = true;
|
|
226
|
+
} catch (err) {
|
|
227
|
+
// Best-effort: skill dir is already gone, don't fail the whole delete
|
|
228
|
+
log.warn({ id, err }, 'Failed to update skills index after deleting managed skill');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return { deleted: true, indexUpdated };
|
|
233
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { realpathSync, existsSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, resolve, normalize, sep } from 'node:path';
|
|
3
|
+
import { getWorkspaceSkillsDir } from '../util/platform.js';
|
|
4
|
+
import { getBundledSkillsDir } from '../config/skills.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the managed skills root directory. Managed skills are user-installed
|
|
8
|
+
* skills that live under ~/.vellum/workspace/skills.
|
|
9
|
+
*/
|
|
10
|
+
export function getManagedSkillsRoot(): string {
|
|
11
|
+
return normalizeDirPath(getWorkspaceSkillsDir());
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns the bundled skills root directory. Bundled skills ship with the
|
|
16
|
+
* application binary and are read-only.
|
|
17
|
+
*/
|
|
18
|
+
export function getBundledSkillsRoot(): string {
|
|
19
|
+
return normalizeDirPath(getBundledSkillsDir());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Normalizes a directory path to a canonical form suitable for prefix
|
|
24
|
+
* comparison. Resolves relative segments and ensures a trailing separator
|
|
25
|
+
* so that "/foo/bar" won't false-match "/foo/barbaz".
|
|
26
|
+
*
|
|
27
|
+
* When the path exists on disk, realpath is used to resolve symlinks.
|
|
28
|
+
* Otherwise resolve() is used for pure lexical normalization.
|
|
29
|
+
*/
|
|
30
|
+
export function normalizeDirPath(dirPath: string): string {
|
|
31
|
+
// If the path exists, resolve symlinks directly
|
|
32
|
+
if (existsSync(dirPath)) {
|
|
33
|
+
const resolved = realpathSync(dirPath);
|
|
34
|
+
const normalized = normalize(resolved);
|
|
35
|
+
return normalized.endsWith(sep) ? normalized : normalized + sep;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Walk up to find the nearest existing ancestor and resolve through it
|
|
39
|
+
// (mirrors normalizeFilePath behavior for consistency)
|
|
40
|
+
const absPath = resolve(dirPath);
|
|
41
|
+
const segments: string[] = [];
|
|
42
|
+
let current = absPath;
|
|
43
|
+
while (current !== dirname(current)) {
|
|
44
|
+
if (existsSync(current)) {
|
|
45
|
+
const realBase = realpathSync(current);
|
|
46
|
+
const tail = segments.reduceRight((acc, seg) => acc + sep + seg, '');
|
|
47
|
+
const full = normalize(realBase + tail);
|
|
48
|
+
return full.endsWith(sep) ? full : full + sep;
|
|
49
|
+
}
|
|
50
|
+
segments.push(basename(current));
|
|
51
|
+
current = dirname(current);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Nothing on the path exists — fall back to pure lexical resolution
|
|
55
|
+
const normalized = normalize(absPath);
|
|
56
|
+
return normalized.endsWith(sep) ? normalized : normalized + sep;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Normalizes an absolute file path for comparison. Resolves symlinks
|
|
61
|
+
* through the nearest existing ancestor so that a symlinked parent
|
|
62
|
+
* directory is detected even when the leaf file doesn't exist yet.
|
|
63
|
+
*/
|
|
64
|
+
export function normalizeFilePath(filePath: string): string {
|
|
65
|
+
if (existsSync(filePath)) {
|
|
66
|
+
return realpathSync(filePath);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Walk up until we find an ancestor that exists on disk, resolve it,
|
|
70
|
+
// then re-append the tail segments. This catches symlinked parent dirs.
|
|
71
|
+
const resolved = resolve(filePath);
|
|
72
|
+
const segments: string[] = [];
|
|
73
|
+
let current = resolved;
|
|
74
|
+
while (current !== dirname(current)) {
|
|
75
|
+
if (existsSync(current)) {
|
|
76
|
+
const realBase = realpathSync(current);
|
|
77
|
+
return segments.reduceRight((acc, seg) => acc + sep + seg, realBase);
|
|
78
|
+
}
|
|
79
|
+
segments.push(basename(current));
|
|
80
|
+
current = dirname(current);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Nothing on the path exists — fall back to pure lexical resolution
|
|
84
|
+
return resolved;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Returns all known skill root directories as normalized paths with trailing
|
|
89
|
+
* separators. Additional roots (e.g. workspace-local skill directories) can
|
|
90
|
+
* be passed via the `extraRoots` parameter.
|
|
91
|
+
*/
|
|
92
|
+
export function getSkillRoots(extraRoots?: string[]): string[] {
|
|
93
|
+
const roots = [
|
|
94
|
+
getManagedSkillsRoot(),
|
|
95
|
+
getBundledSkillsRoot(),
|
|
96
|
+
];
|
|
97
|
+
if (extraRoots) {
|
|
98
|
+
for (const root of extraRoots) {
|
|
99
|
+
roots.push(normalizeDirPath(root));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return roots;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Checks whether an absolute path falls under any known skill directory.
|
|
107
|
+
*
|
|
108
|
+
* Returns true if the path is inside the managed skills dir, the bundled
|
|
109
|
+
* skills dir, or any of the provided extra roots. The check is
|
|
110
|
+
* symlink-safe: both the candidate path and the skill roots are resolved
|
|
111
|
+
* through realpath when the paths exist on disk.
|
|
112
|
+
*
|
|
113
|
+
* @param absPath - The absolute path to classify.
|
|
114
|
+
* @param extraRoots - Optional additional skill root directories to check.
|
|
115
|
+
* @returns true if the path is inside any skill directory.
|
|
116
|
+
*/
|
|
117
|
+
export function isSkillSourcePath(absPath: string, extraRoots?: string[]): boolean {
|
|
118
|
+
const normalizedPath = normalizeFilePath(absPath);
|
|
119
|
+
const roots = getSkillRoots(extraRoots);
|
|
120
|
+
|
|
121
|
+
for (const root of roots) {
|
|
122
|
+
if (normalizedPath.startsWith(root)) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { SkillSummary } from '../config/skills.js';
|
|
2
|
+
import type { ResolvedSkill } from '../config/skill-state.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parse whether user input starts with a slash-like command token.
|
|
6
|
+
*
|
|
7
|
+
* Rules:
|
|
8
|
+
* - Trim leading whitespace.
|
|
9
|
+
* - Only inspect the first whitespace-delimited token.
|
|
10
|
+
* - A candidate token must begin with `/`.
|
|
11
|
+
* - Return `none` for empty input.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export function extractLeadingToken(input: string): string | null {
|
|
15
|
+
const trimmed = input.trimStart();
|
|
16
|
+
if (!trimmed) return null;
|
|
17
|
+
const firstToken = trimmed.split(/\s/)[0];
|
|
18
|
+
return firstToken || null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function parseSlashCandidate(input: string): { kind: 'none' | 'candidate'; token?: string } {
|
|
22
|
+
const token = extractLeadingToken(input);
|
|
23
|
+
if (!token || !token.startsWith('/')) {
|
|
24
|
+
return { kind: 'none' };
|
|
25
|
+
}
|
|
26
|
+
if (isPathLikeSlashToken(token)) {
|
|
27
|
+
return { kind: 'none' };
|
|
28
|
+
}
|
|
29
|
+
const id = token.slice(1);
|
|
30
|
+
if (!isValidSlashSkillId(id)) {
|
|
31
|
+
return { kind: 'none' };
|
|
32
|
+
}
|
|
33
|
+
return { kind: 'candidate', token };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Validate that a slash skill ID starts with alphanumeric and contains only [A-Za-z0-9._-] */
|
|
37
|
+
export function isValidSlashSkillId(id: string): boolean {
|
|
38
|
+
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Detect filesystem-like paths: tokens containing more than one `/` */
|
|
42
|
+
export function isPathLikeSlashToken(token: string): boolean {
|
|
43
|
+
// Count slashes — a single leading `/` is expected, but any additional `/` means it's a path
|
|
44
|
+
const slashCount = token.split('/').length - 1;
|
|
45
|
+
return slashCount > 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ─── Invocable slash skill catalog ──────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
export interface InvocableSlashSkill {
|
|
51
|
+
canonicalId: string;
|
|
52
|
+
name: string;
|
|
53
|
+
summary: SkillSummary;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build a map of slash-invocable skills keyed by lowercase ID for
|
|
58
|
+
* case-insensitive lookup. Only includes skills that are `userInvocable`
|
|
59
|
+
* and whose resolved state is not `disabled`.
|
|
60
|
+
*/
|
|
61
|
+
export function buildInvocableSlashCatalog(
|
|
62
|
+
catalog: SkillSummary[],
|
|
63
|
+
resolvedStates: ResolvedSkill[],
|
|
64
|
+
): Map<string, InvocableSlashSkill> {
|
|
65
|
+
const stateById = new Map<string, ResolvedSkill>();
|
|
66
|
+
for (const rs of resolvedStates) {
|
|
67
|
+
stateById.set(rs.summary.id, rs);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const result = new Map<string, InvocableSlashSkill>();
|
|
71
|
+
for (const skill of catalog) {
|
|
72
|
+
if (!skill.userInvocable) continue;
|
|
73
|
+
const resolved = stateById.get(skill.id);
|
|
74
|
+
if (!resolved || resolved.state === 'disabled') continue;
|
|
75
|
+
result.set(skill.id.toLowerCase(), {
|
|
76
|
+
canonicalId: skill.id,
|
|
77
|
+
name: skill.name,
|
|
78
|
+
summary: skill,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── Slash command resolution ────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
export type SlashResolution =
|
|
87
|
+
| { kind: 'none' }
|
|
88
|
+
| { kind: 'known'; skillId: string; trailingArgs: string }
|
|
89
|
+
| { kind: 'unknown'; requestedId: string; message: string };
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Resolve user input against the invocable slash catalog.
|
|
93
|
+
*
|
|
94
|
+
* Returns:
|
|
95
|
+
* - `none` if input is not a slash candidate (normal text, path, etc.)
|
|
96
|
+
* - `known` if the slash ID matches an invocable skill (case-insensitive)
|
|
97
|
+
* - `unknown` if it's a valid slash candidate but no matching skill exists
|
|
98
|
+
*/
|
|
99
|
+
export function resolveSlashSkillCommand(
|
|
100
|
+
input: string,
|
|
101
|
+
catalog: Map<string, InvocableSlashSkill>,
|
|
102
|
+
): SlashResolution {
|
|
103
|
+
const candidate = parseSlashCandidate(input);
|
|
104
|
+
if (candidate.kind === 'none') {
|
|
105
|
+
return { kind: 'none' };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const token = candidate.token!;
|
|
109
|
+
const requestedId = token.slice(1);
|
|
110
|
+
const lookupKey = requestedId.toLowerCase();
|
|
111
|
+
|
|
112
|
+
// Extract trailing args: everything after the first token
|
|
113
|
+
const trimmed = input.trimStart();
|
|
114
|
+
const firstSpaceIdx = trimmed.search(/\s/);
|
|
115
|
+
const trailingArgs = firstSpaceIdx === -1 ? '' : trimmed.slice(firstSpaceIdx).trim();
|
|
116
|
+
|
|
117
|
+
const match = catalog.get(lookupKey);
|
|
118
|
+
if (match) {
|
|
119
|
+
return { kind: 'known', skillId: match.canonicalId, trailingArgs };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const availableIds = Array.from(catalog.values())
|
|
123
|
+
.map((s) => s.canonicalId)
|
|
124
|
+
.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }));
|
|
125
|
+
return {
|
|
126
|
+
kind: 'unknown',
|
|
127
|
+
requestedId,
|
|
128
|
+
message: formatUnknownSlashSkillMessage(requestedId, availableIds),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Build a deterministic error message for an unknown slash command.
|
|
134
|
+
*/
|
|
135
|
+
export function formatUnknownSlashSkillMessage(
|
|
136
|
+
requestedId: string,
|
|
137
|
+
availableSkillIds: string[],
|
|
138
|
+
): string {
|
|
139
|
+
const lines = [`Unknown command \`/${requestedId}\`.`];
|
|
140
|
+
if (availableSkillIds.length > 0) {
|
|
141
|
+
lines.push('');
|
|
142
|
+
lines.push('Available slash commands:');
|
|
143
|
+
for (const id of availableSkillIds) {
|
|
144
|
+
lines.push(`- \`/${id}\``);
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
lines.push('');
|
|
148
|
+
lines.push('No slash commands are currently available.');
|
|
149
|
+
}
|
|
150
|
+
return lines.join('\n');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ─── Prompt rewrite for known slash commands ─────────────────────────────────
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Rewrite user input for a known slash command into a model-facing prompt
|
|
157
|
+
* that explicitly instructs the model to invoke the skill.
|
|
158
|
+
*/
|
|
159
|
+
export function rewriteKnownSlashCommandPrompt(params: {
|
|
160
|
+
rawInput: string;
|
|
161
|
+
skillId: string;
|
|
162
|
+
skillName: string;
|
|
163
|
+
trailingArgs: string;
|
|
164
|
+
}): string {
|
|
165
|
+
const lines = [
|
|
166
|
+
`The user invoked the slash command \`/${params.skillId}\`.`,
|
|
167
|
+
`Please invoke the "${params.skillName}" skill (ID: ${params.skillId}).`,
|
|
168
|
+
];
|
|
169
|
+
if (params.trailingArgs) {
|
|
170
|
+
lines.push('');
|
|
171
|
+
lines.push(`User arguments: ${params.trailingArgs}`);
|
|
172
|
+
}
|
|
173
|
+
return lines.join('\n');
|
|
174
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import type { SkillToolManifest, SkillToolEntry } from '../config/skills.js';
|
|
3
|
+
|
|
4
|
+
const VALID_RISK_LEVELS = new Set(['low', 'medium', 'high']);
|
|
5
|
+
const VALID_EXECUTION_TARGETS = new Set(['host', 'sandbox']);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parse and validate a raw TOOLS.json payload into a typed SkillToolManifest.
|
|
9
|
+
* Throws descriptive errors for any validation failure.
|
|
10
|
+
*/
|
|
11
|
+
export function parseToolManifest(raw: unknown): SkillToolManifest {
|
|
12
|
+
if (raw === null || raw === undefined || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
13
|
+
throw new Error('TOOLS.json must be a JSON object');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const obj = raw as Record<string, unknown>;
|
|
17
|
+
|
|
18
|
+
// Validate version
|
|
19
|
+
if (!('version' in obj)) {
|
|
20
|
+
throw new Error('TOOLS.json is missing required field "version"');
|
|
21
|
+
}
|
|
22
|
+
if (obj.version !== 1) {
|
|
23
|
+
throw new Error(`TOOLS.json "version" must be 1, got: ${JSON.stringify(obj.version)}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Validate tools array
|
|
27
|
+
if (!('tools' in obj)) {
|
|
28
|
+
throw new Error('TOOLS.json is missing required field "tools"');
|
|
29
|
+
}
|
|
30
|
+
if (!Array.isArray(obj.tools)) {
|
|
31
|
+
throw new Error('TOOLS.json "tools" must be an array');
|
|
32
|
+
}
|
|
33
|
+
if (obj.tools.length === 0) {
|
|
34
|
+
throw new Error('TOOLS.json "tools" must contain at least one tool entry');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const tools: SkillToolEntry[] = [];
|
|
38
|
+
const seenNames = new Set<string>();
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < obj.tools.length; i++) {
|
|
41
|
+
const entry = obj.tools[i];
|
|
42
|
+
const prefix = `TOOLS.json tools[${i}]`;
|
|
43
|
+
const tool = parseToolEntry(entry, prefix);
|
|
44
|
+
|
|
45
|
+
if (seenNames.has(tool.name)) {
|
|
46
|
+
throw new Error(`${prefix}: duplicate tool name "${tool.name}"`);
|
|
47
|
+
}
|
|
48
|
+
seenNames.add(tool.name);
|
|
49
|
+
|
|
50
|
+
tools.push(tool);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { version: 1, tools };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function parseToolEntry(raw: unknown, prefix: string): SkillToolEntry {
|
|
57
|
+
if (raw === null || raw === undefined || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
58
|
+
throw new Error(`${prefix}: each tool entry must be a JSON object`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const entry = raw as Record<string, unknown>;
|
|
62
|
+
|
|
63
|
+
// name
|
|
64
|
+
if (!('name' in entry) || typeof entry.name !== 'string') {
|
|
65
|
+
throw new Error(`${prefix}: missing or non-string "name"`);
|
|
66
|
+
}
|
|
67
|
+
const name = entry.name.trim();
|
|
68
|
+
if (name.length === 0) {
|
|
69
|
+
throw new Error(`${prefix}: "name" must be a non-empty string`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// description
|
|
73
|
+
if (!('description' in entry) || typeof entry.description !== 'string') {
|
|
74
|
+
throw new Error(`${prefix}: missing or non-string "description"`);
|
|
75
|
+
}
|
|
76
|
+
const description = entry.description.trim();
|
|
77
|
+
if (description.length === 0) {
|
|
78
|
+
throw new Error(`${prefix}: "description" must be a non-empty string`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// category
|
|
82
|
+
if (!('category' in entry) || typeof entry.category !== 'string') {
|
|
83
|
+
throw new Error(`${prefix}: missing or non-string "category"`);
|
|
84
|
+
}
|
|
85
|
+
const category = entry.category.trim();
|
|
86
|
+
if (category.length === 0) {
|
|
87
|
+
throw new Error(`${prefix}: "category" must be a non-empty string`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// risk
|
|
91
|
+
if (!('risk' in entry) || typeof entry.risk !== 'string') {
|
|
92
|
+
throw new Error(`${prefix}: missing or non-string "risk"`);
|
|
93
|
+
}
|
|
94
|
+
if (!VALID_RISK_LEVELS.has(entry.risk)) {
|
|
95
|
+
throw new Error(`${prefix}: "risk" must be one of "low", "medium", "high", got: "${entry.risk}"`);
|
|
96
|
+
}
|
|
97
|
+
const risk = entry.risk as SkillToolEntry['risk'];
|
|
98
|
+
|
|
99
|
+
// input_schema
|
|
100
|
+
if (!('input_schema' in entry) || entry.input_schema === null || typeof entry.input_schema !== 'object' || Array.isArray(entry.input_schema)) {
|
|
101
|
+
throw new Error(`${prefix}: missing or non-object "input_schema"`);
|
|
102
|
+
}
|
|
103
|
+
const input_schema = entry.input_schema as Record<string, unknown>;
|
|
104
|
+
|
|
105
|
+
// executor
|
|
106
|
+
if (!('executor' in entry) || typeof entry.executor !== 'string') {
|
|
107
|
+
throw new Error(`${prefix}: missing or non-string "executor"`);
|
|
108
|
+
}
|
|
109
|
+
const executor = entry.executor;
|
|
110
|
+
if (executor.length === 0) {
|
|
111
|
+
throw new Error(`${prefix}: "executor" must be a non-empty string`);
|
|
112
|
+
}
|
|
113
|
+
validateExecutorPath(executor, prefix);
|
|
114
|
+
|
|
115
|
+
// execution_target
|
|
116
|
+
if (!('execution_target' in entry) || typeof entry.execution_target !== 'string') {
|
|
117
|
+
throw new Error(`${prefix}: missing or non-string "execution_target"`);
|
|
118
|
+
}
|
|
119
|
+
if (!VALID_EXECUTION_TARGETS.has(entry.execution_target)) {
|
|
120
|
+
throw new Error(`${prefix}: "execution_target" must be one of "host", "sandbox", got: "${entry.execution_target}"`);
|
|
121
|
+
}
|
|
122
|
+
const execution_target = entry.execution_target as SkillToolEntry['execution_target'];
|
|
123
|
+
|
|
124
|
+
return { name, description, category, risk, input_schema, executor, execution_target };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Enforce that executor paths are relative and don't escape the skill directory.
|
|
129
|
+
* Rejects absolute paths and paths containing `../`.
|
|
130
|
+
*/
|
|
131
|
+
function validateExecutorPath(executor: string, prefix: string): void {
|
|
132
|
+
if (executor.startsWith('/')) {
|
|
133
|
+
throw new Error(`${prefix}: "executor" must be a relative path, got absolute path: "${executor}"`);
|
|
134
|
+
}
|
|
135
|
+
// Reject path traversal sequences
|
|
136
|
+
const segments = executor.split('/');
|
|
137
|
+
for (const segment of segments) {
|
|
138
|
+
if (segment === '..') {
|
|
139
|
+
throw new Error(`${prefix}: "executor" must not contain ".." path segments: "${executor}"`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Read and parse a TOOLS.json file from disk.
|
|
146
|
+
*/
|
|
147
|
+
export function parseToolManifestFile(filePath: string): SkillToolManifest {
|
|
148
|
+
let content: string;
|
|
149
|
+
try {
|
|
150
|
+
content = readFileSync(filePath, 'utf-8');
|
|
151
|
+
} catch (err) {
|
|
152
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
153
|
+
throw new Error(`Failed to read TOOLS.json at "${filePath}": ${message}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let parsed: unknown;
|
|
157
|
+
try {
|
|
158
|
+
parsed = JSON.parse(content);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
161
|
+
throw new Error(`Failed to parse TOOLS.json at "${filePath}" as JSON: ${message}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return parseToolManifest(parsed);
|
|
165
|
+
}
|