@cohortapp/agent-sdk 2.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/.claude/commands/init-agent.md +104 -0
- package/.claude/commands/init-maestro.md +1187 -0
- package/.claude/settings.json +161 -0
- package/.env.example +216 -0
- package/README.md +632 -0
- package/agents/browser-operator/agent.md +52 -0
- package/agents/calendar-ops/agent.md +50 -0
- package/agents/communications/agent.md +96 -0
- package/agents/decision-log/agent.md +65 -0
- package/agents/desktop-operator/agent.md +59 -0
- package/agents/gmail-operator/agent.md +62 -0
- package/agents/inbound-dispatcher/agent.md +66 -0
- package/agents/inbox-processor/agent.md +39 -0
- package/agents/pmo-execution/agent.md +60 -0
- package/agents/session-spawner/agent.md +64 -0
- package/agents/slack-operator/agent.md +60 -0
- package/agents/whatsapp-operator/agent.md +60 -0
- package/agents/workflow-automation/agent.md +61 -0
- package/archetypes/altitudes/c-suite.yaml +58 -0
- package/archetypes/altitudes/founder.yaml +68 -0
- package/archetypes/altitudes/senior-manager.yaml +63 -0
- package/archetypes/altitudes/svp.yaml +60 -0
- package/archetypes/altitudes/vp.yaml +50 -0
- package/archetypes/archetype.schema.json +77 -0
- package/archetypes/base.yaml +47 -0
- package/archetypes/capabilities/commercial-leader.yaml +159 -0
- package/archetypes/capabilities/compliance-officer.yaml +159 -0
- package/archetypes/capabilities/executive-operator.yaml +169 -0
- package/archetypes/capabilities/finance-leader.yaml +162 -0
- package/archetypes/capabilities/operations-leader.yaml +154 -0
- package/archetypes/capabilities/product-leader.yaml +148 -0
- package/archetypes/capabilities/technical-leader.yaml +146 -0
- package/archetypes/functions/commercial-leader.yaml +62 -0
- package/archetypes/functions/compliance-officer.yaml +64 -0
- package/archetypes/functions/executive-operator.yaml +70 -0
- package/archetypes/functions/finance-leader.yaml +70 -0
- package/archetypes/functions/operations-leader.yaml +62 -0
- package/archetypes/functions/product-leader.yaml +61 -0
- package/archetypes/functions/technical-leader.yaml +57 -0
- package/bin/cohort-mcp.mjs +81 -0
- package/bin/maestro.mjs +3516 -0
- package/bin/maestro.test.mjs +1015 -0
- package/desktop-control/README.md +56 -0
- package/desktop-control/app-profiles/gmail.yaml +120 -0
- package/desktop-control/app-profiles/slack.yaml +315 -0
- package/desktop-control/app-profiles/whatsapp.yaml +107 -0
- package/docs/architecture/agent-topology.md +2239 -0
- package/docs/architecture/archetype-agent-factory.md +110 -0
- package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
- package/docs/architecture/continuous-monitoring.md +221 -0
- package/docs/architecture/mcp-capability-map.md +585 -0
- package/docs/architecture/system-architecture.md +1272 -0
- package/docs/company-context/README.md +40 -0
- package/docs/guides/agent-persona-setup.md +600 -0
- package/docs/guides/agents-observe-setup.md +64 -0
- package/docs/guides/billing-console-keys.md +88 -0
- package/docs/guides/ccxray-diagnostics.md +65 -0
- package/docs/guides/channel-bus.md +127 -0
- package/docs/guides/claude-mem-setup.md +79 -0
- package/docs/guides/claude-pace-setup.md +56 -0
- package/docs/guides/claudraband-sessions.md +98 -0
- package/docs/guides/clawteam-swarm.md +116 -0
- package/docs/guides/code-review-graph-setup.md +86 -0
- package/docs/guides/email-setup.md +431 -0
- package/docs/guides/mac-mini.md +119 -0
- package/docs/guides/media-generation-setup.md +349 -0
- package/docs/guides/model-routing.md +162 -0
- package/docs/guides/observability-otel.md +265 -0
- package/docs/guides/org-onboarding.md +132 -0
- package/docs/guides/outbound-governance-setup.md +437 -0
- package/docs/guides/pdf-generation-setup.md +315 -0
- package/docs/guides/poller-daemon-setup.md +563 -0
- package/docs/guides/rag-context-setup.md +459 -0
- package/docs/guides/self-optimization-pattern.md +82 -0
- package/docs/guides/setup-wizard.md +178 -0
- package/docs/guides/slack-setup.md +350 -0
- package/docs/guides/telegram-setup.md +227 -0
- package/docs/guides/twilio-subaccounts-setup.md +223 -0
- package/docs/guides/verification.md +128 -0
- package/docs/guides/voice-mode.md +188 -0
- package/docs/guides/voice-sms-setup.md +698 -0
- package/docs/guides/webhook-relay-setup.md +349 -0
- package/docs/guides/whatsapp-setup.md +288 -0
- package/docs/prompts/board-pack-cover-template.md +36 -0
- package/docs/prompts/decision-recommendation-template.md +88 -0
- package/docs/prompts/followup-message-template.md +141 -0
- package/docs/prompts/investor-letter-template.md +52 -0
- package/docs/prompts/morning-brief-template.md +82 -0
- package/docs/prompts/presentation-template.md +58 -0
- package/docs/prompts/weekly-strategic-memo-template.md +104 -0
- package/docs/research/hallucinated-tool-output-investigation.md +151 -0
- package/docs/runbooks/backup-restore.md +205 -0
- package/docs/runbooks/cohort-cutover.md +129 -0
- package/docs/runbooks/fleet-operations.md +200 -0
- package/docs/runbooks/incident-response.md +226 -0
- package/docs/runbooks/mac-mini-bootstrap.md +431 -0
- package/docs/runbooks/perpetual-operations.md +509 -0
- package/docs/runbooks/recovery-and-failover.md +260 -0
- package/framework-features.json +267 -0
- package/ingest/README.md +87 -0
- package/lib/action-executor.js +689 -0
- package/lib/action-executor.test.mjs +871 -0
- package/lib/agent-root.mjs +37 -0
- package/lib/archetype.mjs +236 -0
- package/lib/archetype.test.mjs +132 -0
- package/lib/autonomy.mjs +114 -0
- package/lib/autonomy.test.mjs +66 -0
- package/lib/backlog.mjs +358 -0
- package/lib/backlog.test.mjs +266 -0
- package/lib/budget-guard.mjs +279 -0
- package/lib/budget-guard.test.mjs +291 -0
- package/lib/cadence-bus-schedule.test.mjs +194 -0
- package/lib/cadence-bus.mjs +1120 -0
- package/lib/cadence-bus.test.mjs +720 -0
- package/lib/cadences.mjs +205 -0
- package/lib/cadences.test.mjs +125 -0
- package/lib/capability.mjs +154 -0
- package/lib/capability.test.mjs +78 -0
- package/lib/channels/base-adapter.mjs +719 -0
- package/lib/channels/base-adapter.test.mjs +590 -0
- package/lib/channels/channel.mjs +128 -0
- package/lib/channels/channels.test.mjs +371 -0
- package/lib/channels/contract.mjs +215 -0
- package/lib/channels/contract.test.mjs +137 -0
- package/lib/channels/conversation-resolver.mjs +95 -0
- package/lib/channels/gmail/adapter.mjs +87 -0
- package/lib/channels/inbox-item.mjs +255 -0
- package/lib/channels/inbox-item.test.mjs +335 -0
- package/lib/channels/index.mjs +94 -0
- package/lib/channels/orgmail/adapter.mjs +353 -0
- package/lib/channels/orgmail/adapter.test.mjs +311 -0
- package/lib/channels/pairing.mjs +363 -0
- package/lib/channels/pairing.test.mjs +270 -0
- package/lib/channels/registry.mjs +164 -0
- package/lib/channels/slack/adapter.mjs +317 -0
- package/lib/channels/slack-adapter.test.mjs +212 -0
- package/lib/channels/sms/adapter.mjs +43 -0
- package/lib/channels/telegram/adapter.mjs +432 -0
- package/lib/channels/telegram-adapter.test.mjs +306 -0
- package/lib/channels/voice/adapter.mjs +301 -0
- package/lib/channels/voice/adapter.test.mjs +278 -0
- package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
- package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
- package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
- package/lib/charter.mjs +256 -0
- package/lib/charter.test.mjs +89 -0
- package/lib/claude-bin.mjs +134 -0
- package/lib/claude-bin.test.mjs +75 -0
- package/lib/collective/capture.mjs +185 -0
- package/lib/collective/capture.test.mjs +121 -0
- package/lib/collective/cards.mjs +201 -0
- package/lib/collective/cards.test.mjs +114 -0
- package/lib/collective/config.mjs +186 -0
- package/lib/collective/config.test.mjs +123 -0
- package/lib/collective/global-config.mjs +113 -0
- package/lib/collective/global-config.test.mjs +75 -0
- package/lib/collective/presence.mjs +201 -0
- package/lib/collective/presence.test.mjs +95 -0
- package/lib/collective/recall.mjs +215 -0
- package/lib/collective/recall.test.mjs +116 -0
- package/lib/comms/send-gate.mjs +554 -0
- package/lib/comms/send-gate.test.mjs +577 -0
- package/lib/comms.mjs +67 -0
- package/lib/comms.test.mjs +41 -0
- package/lib/diagnostics/alerts.mjs +424 -0
- package/lib/diagnostics/alerts.test.mjs +318 -0
- package/lib/diagnostics/backup-freshness.mjs +188 -0
- package/lib/diagnostics/backup-freshness.test.mjs +185 -0
- package/lib/diagnostics/counters.mjs +269 -0
- package/lib/diagnostics/counters.test.mjs +206 -0
- package/lib/diagnostics/events.mjs +188 -0
- package/lib/diagnostics/events.test.mjs +290 -0
- package/lib/diagnostics/otel.mjs +237 -0
- package/lib/diagnostics/otel.test.mjs +196 -0
- package/lib/diagnostics/trace.mjs +216 -0
- package/lib/diagnostics/trace.test.mjs +251 -0
- package/lib/env-compat.mjs +74 -0
- package/lib/env-compat.test.mjs +104 -0
- package/lib/feature-init.mjs +331 -0
- package/lib/fs-atomic.mjs +112 -0
- package/lib/fs-atomic.test.mjs +72 -0
- package/lib/fs-ownership.mjs +111 -0
- package/lib/fs-ownership.test.mjs +158 -0
- package/lib/hooks/bus.mjs +347 -0
- package/lib/hooks/bus.test.mjs +387 -0
- package/lib/index.js +16 -0
- package/lib/learning/config.mjs +106 -0
- package/lib/learning/config.test.mjs +75 -0
- package/lib/learning/counters.mjs +156 -0
- package/lib/learning/counters.test.mjs +69 -0
- package/lib/learning/curator-consolidate.test.mjs +238 -0
- package/lib/learning/curator.mjs +453 -0
- package/lib/learning/curator.test.mjs +106 -0
- package/lib/learning/log.mjs +40 -0
- package/lib/learning/reflect.mjs +534 -0
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.mjs +352 -0
- package/lib/learning/session-index.test.mjs +125 -0
- package/lib/learning/skill-writer.mjs +474 -0
- package/lib/learning/skill-writer.test.mjs +210 -0
- package/lib/mcp/server.mjs +328 -0
- package/lib/mcp/server.test.mjs +400 -0
- package/lib/model-router/auth-profiles.mjs +758 -0
- package/lib/model-router/auth-profiles.test.mjs +580 -0
- package/lib/model-router/catalog/anthropic.yaml +153 -0
- package/lib/model-router/catalog/deepseek.yaml +86 -0
- package/lib/model-router/catalog/moonshot.yaml +81 -0
- package/lib/model-router/catalog/qwen.yaml +114 -0
- package/lib/model-router/catalog.mjs +925 -0
- package/lib/model-router/catalog.test.mjs +385 -0
- package/lib/model-router/economics.mjs +564 -0
- package/lib/model-router/economics.test.mjs +344 -0
- package/lib/model-router/failover.mjs +298 -0
- package/lib/model-router/failover.test.mjs +439 -0
- package/lib/model-router/health.mjs +453 -0
- package/lib/model-router/health.test.mjs +338 -0
- package/lib/model-router/integration-coverage.test.mjs +829 -0
- package/lib/model-router/integration.test.mjs +564 -0
- package/lib/model-router/ledger.mjs +402 -0
- package/lib/model-router/ledger.test.mjs +382 -0
- package/lib/model-router/llm-task.mjs +515 -0
- package/lib/model-router/llm-task.test.mjs +392 -0
- package/lib/model-router/org-credentials.mjs +260 -0
- package/lib/model-router/org-credentials.test.mjs +265 -0
- package/lib/model-router/pricing-refresh.mjs +463 -0
- package/lib/model-router/pricing-refresh.test.mjs +286 -0
- package/lib/model-router/reconcile.mjs +429 -0
- package/lib/model-router/reconcile.test.mjs +316 -0
- package/lib/model-router/repair.mjs +471 -0
- package/lib/model-router/repair.test.mjs +180 -0
- package/lib/model-router/resolve.mjs +1206 -0
- package/lib/model-router/spawn.mjs +497 -0
- package/lib/model-router/spawn.test.mjs +425 -0
- package/lib/model-router/taxonomy.mjs +893 -0
- package/lib/model-router/taxonomy.test.mjs +410 -0
- package/lib/model-router.mjs +677 -0
- package/lib/model-router.test.mjs +907 -0
- package/lib/org/activity.mjs +211 -0
- package/lib/org/activity.test.mjs +134 -0
- package/lib/org/approvals.mjs +448 -0
- package/lib/org/approvals.test.mjs +216 -0
- package/lib/org/awareness.mjs +222 -0
- package/lib/org/awareness.test.mjs +159 -0
- package/lib/org/board.mjs +229 -0
- package/lib/org/board.test.mjs +177 -0
- package/lib/org/bootstrap-context.mjs +169 -0
- package/lib/org/bootstrap-context.test.mjs +153 -0
- package/lib/org/client.mjs +1628 -0
- package/lib/org/client.test.mjs +1107 -0
- package/lib/org/cohort-client.mjs +67 -0
- package/lib/org/cohort-client.test.mjs +126 -0
- package/lib/org/cost-sync.mjs +227 -0
- package/lib/org/cost-sync.test.mjs +153 -0
- package/lib/org/doctor.mjs +212 -0
- package/lib/org/doctor.test.mjs +212 -0
- package/lib/org/handoff.mjs +293 -0
- package/lib/org/handoff.test.mjs +269 -0
- package/lib/org/integration-tools.mjs +182 -0
- package/lib/org/integration-tools.test.mjs +160 -0
- package/lib/org/keys.mjs +131 -0
- package/lib/org/keys.test.mjs +92 -0
- package/lib/org/knowledge.mjs +463 -0
- package/lib/org/knowledge.test.mjs +319 -0
- package/lib/org/leases.mjs +335 -0
- package/lib/org/leases.test.mjs +235 -0
- package/lib/org/mesh-integration.test.mjs +127 -0
- package/lib/org/mesh.mjs +459 -0
- package/lib/org/mesh.test.mjs +345 -0
- package/lib/org/messaging.mjs +503 -0
- package/lib/org/messaging.test.mjs +238 -0
- package/lib/org/policy.mjs +345 -0
- package/lib/org/policy.test.mjs +237 -0
- package/lib/org/protocol.checksum +1 -0
- package/lib/org/protocol.checksum.test.mjs +90 -0
- package/lib/org/protocol.mjs +967 -0
- package/lib/org/protocol.test.mjs +264 -0
- package/lib/org/registry.mjs +194 -0
- package/lib/org/registry.test.mjs +100 -0
- package/lib/org/tool-surface-integration.test.mjs +120 -0
- package/lib/org/tool-surface.mjs +2535 -0
- package/lib/org/tool-surface.test.mjs +589 -0
- package/lib/org/ui-parity.mjs +3236 -0
- package/lib/org/ui-parity.test.mjs +348 -0
- package/lib/org/verify.mjs +176 -0
- package/lib/org/verify.test.mjs +194 -0
- package/lib/rag/embed.mjs +188 -0
- package/lib/rag/indexer.mjs +425 -0
- package/lib/rag/rag.test.mjs +505 -0
- package/lib/rag/search.mjs +475 -0
- package/lib/rate-guard.mjs +246 -0
- package/lib/rate-guard.test.mjs +201 -0
- package/lib/render.mjs +112 -0
- package/lib/render.test.mjs +68 -0
- package/lib/resource-governor.mjs +297 -0
- package/lib/resource-governor.test.mjs +262 -0
- package/lib/scheduling/dynamic-jobs.mjs +675 -0
- package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
- package/lib/scheduling/jitter.mjs +0 -0
- package/lib/scheduling/jitter.test.mjs +140 -0
- package/lib/secrets/broker.mjs +315 -0
- package/lib/secrets/broker.test.mjs +280 -0
- package/lib/secrets/providers.mjs +461 -0
- package/lib/secrets/providers.test.mjs +274 -0
- package/lib/security/audit-engine.mjs +684 -0
- package/lib/security/audit-engine.test.mjs +389 -0
- package/lib/security/coerce-args.mjs +552 -0
- package/lib/security/coerce-args.test.mjs +281 -0
- package/lib/security/dangerous-tools.mjs +97 -0
- package/lib/security/dangerous-tools.test.mjs +68 -0
- package/lib/security/external-content.mjs +145 -0
- package/lib/security/external-content.test.mjs +67 -0
- package/lib/security/redact.mjs +592 -0
- package/lib/security/redact.test.mjs +441 -0
- package/lib/security/secret-equal.mjs +73 -0
- package/lib/security/secret-equal.test.mjs +55 -0
- package/lib/session-permissions.mjs +101 -0
- package/lib/session-permissions.test.mjs +100 -0
- package/lib/setup/claude-probe.mjs +74 -0
- package/lib/setup/completeness.mjs +175 -0
- package/lib/setup/completeness.test.mjs +110 -0
- package/lib/setup/context-pack.mjs +173 -0
- package/lib/setup/context-pack.test.mjs +89 -0
- package/lib/setup/enrich.mjs +277 -0
- package/lib/setup/enrich.test.mjs +115 -0
- package/lib/setup/enroll-from-cohort.mjs +441 -0
- package/lib/setup/enroll-from-cohort.test.mjs +233 -0
- package/lib/setup/integration.test.mjs +162 -0
- package/lib/setup/io.mjs +360 -0
- package/lib/setup/io.test.mjs +77 -0
- package/lib/setup/run-generator.mjs +81 -0
- package/lib/setup/runner.mjs +244 -0
- package/lib/setup/runner.test.mjs +132 -0
- package/lib/setup/sections/comms.mjs +173 -0
- package/lib/setup/sections/company.mjs +120 -0
- package/lib/setup/sections/enrich.mjs +138 -0
- package/lib/setup/sections/identity.mjs +182 -0
- package/lib/setup/sections/identity.test.mjs +140 -0
- package/lib/setup/sections/learning.mjs +153 -0
- package/lib/setup/sections/learning.test.mjs +81 -0
- package/lib/setup/sections/messaging.mjs +219 -0
- package/lib/setup/sections/messaging.test.mjs +127 -0
- package/lib/setup/sections/model.mjs +102 -0
- package/lib/setup/sections/operating-model.mjs +78 -0
- package/lib/setup/sections/org.mjs +475 -0
- package/lib/setup/sections/org.test.mjs +313 -0
- package/lib/setup/sections/orgmail.mjs +173 -0
- package/lib/setup/sections/orgmail.test.mjs +118 -0
- package/lib/setup/sections/recovery.mjs +159 -0
- package/lib/setup/sections/recovery.test.mjs +98 -0
- package/lib/setup/sections/tools.mjs +132 -0
- package/lib/setup/sections/verify.mjs +97 -0
- package/lib/setup/sot.mjs +205 -0
- package/lib/setup/sot.test.mjs +81 -0
- package/lib/setup/state.mjs +151 -0
- package/lib/setup/state.test.mjs +92 -0
- package/lib/singleton.js +229 -0
- package/lib/singleton.test.mjs +135 -0
- package/lib/telemetry/alerts.mjs +216 -0
- package/lib/telemetry/alerts.test.mjs +109 -0
- package/lib/telemetry/collect.mjs +512 -0
- package/lib/telemetry/collect.test.mjs +202 -0
- package/lib/tool-definitions-integration.test.mjs +83 -0
- package/lib/tool-definitions.js +738 -0
- package/lib/tool-definitions.test.mjs +437 -0
- package/lib/util/fetch-timeout.mjs +136 -0
- package/lib/util/fetch-timeout.test.mjs +202 -0
- package/lib/util/reconnect.mjs +343 -0
- package/lib/util/reconnect.test.mjs +369 -0
- package/lib/util/unhandled.mjs +205 -0
- package/lib/util/unhandled.test.mjs +216 -0
- package/lib/voice/context-loader.mjs +466 -0
- package/lib/voice/index.mjs +100 -0
- package/lib/voice/openai-realtime.mjs +510 -0
- package/lib/voice/outbound.mjs +542 -0
- package/lib/voice/outbound.test.mjs +69 -0
- package/lib/voice/post-call-brief.mjs +428 -0
- package/lib/voice/provider.mjs +52 -0
- package/lib/voice/session-rotation.mjs +257 -0
- package/lib/voice/stt.mjs +161 -0
- package/lib/voice/stt.test.mjs +226 -0
- package/lib/voice/tool-bridge.mjs +370 -0
- package/lib/voice/tts.mjs +104 -0
- package/lib/voice/twilio-sip-bridge.mjs +288 -0
- package/lib/voice/voice.test.mjs +990 -0
- package/mcp/README.md +80 -0
- package/package.json +151 -0
- package/plugins/maestro-skills/plugin.json +139 -0
- package/plugins/maestro-skills/skills/agents-observe.md +110 -0
- package/plugins/maestro-skills/skills/board-deck.md +68 -0
- package/plugins/maestro-skills/skills/books-close.md +77 -0
- package/plugins/maestro-skills/skills/brand-steward.md +121 -0
- package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
- package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
- package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
- package/plugins/maestro-skills/skills/claude-pace.md +61 -0
- package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
- package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
- package/plugins/maestro-skills/skills/decision-brief.md +89 -0
- package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
- package/plugins/maestro-skills/skills/draft-comms.md +84 -0
- package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
- package/plugins/maestro-skills/skills/files-find.md +65 -0
- package/plugins/maestro-skills/skills/generative-ui.md +228 -0
- package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
- package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
- package/plugins/maestro-skills/skills/mail-triage.md +86 -0
- package/plugins/maestro-skills/skills/morning-brief.md +54 -0
- package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
- package/plugins/maestro-skills/skills/org-board.md +133 -0
- package/plugins/maestro-skills/skills/org-credential.md +68 -0
- package/plugins/maestro-skills/skills/org-recall.md +81 -0
- package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
- package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
- package/plugins/maestro-skills/skills/router-why.md +78 -0
- package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
- package/plugins/maestro-skills/skills/session-search.md +71 -0
- package/plugins/maestro-skills/skills/set-reminder.md +93 -0
- package/plugins/maestro-skills/skills/slack-followup.md +64 -0
- package/plugins/maestro-skills/skills/team-activity.md +86 -0
- package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
- package/policies/action-classification.yaml +114 -0
- package/policies/ai-disclosure.yaml +294 -0
- package/policies/communication-style.md +139 -0
- package/policies/information-barriers.yaml +118 -0
- package/policies/prompt-injection-defence.yaml +138 -0
- package/public/assets/icon-dark.png +0 -0
- package/public/assets/icon-dark.svg +9 -0
- package/public/assets/icon-light.svg +9 -0
- package/public/assets/logo-dark.svg +15 -0
- package/public/assets/logo-light.svg +15 -0
- package/scaffold/.mcp.json +7 -0
- package/scaffold/CLAUDE.md +368 -0
- package/scaffold/config/agent.json +55 -0
- package/scaffold/config/agent.ts +76 -0
- package/scaffold/config/agent.ts.example +89 -0
- package/scaffold/config/alerts.yaml +23 -0
- package/scaffold/config/allowlist.yaml.example +25 -0
- package/scaffold/config/caller-id-map.yaml +46 -0
- package/scaffold/config/collective.yaml +49 -0
- package/scaffold/config/company.json +20 -0
- package/scaffold/config/known-agents.json +6 -0
- package/scaffold/config/learning.yaml +55 -0
- package/scaffold/config/model-routing.yaml.example +104 -0
- package/scaffold/config/org.yaml +25 -0
- package/scaffold/config/orgmail.yaml.example +19 -0
- package/scaffold/config/recovery.yaml +72 -0
- package/scaffold/config/secrets.yaml +27 -0
- package/scaffold/config/slack.yaml.example +35 -0
- package/scaffold/config/telegram.yaml.example +38 -0
- package/scaffold/config/voice.yaml.example +89 -0
- package/scaffold/config/whatsapp.yaml.example +39 -0
- package/schedules/README.md +49 -0
- package/schedules/triggers/backlog-executor.md +102 -0
- package/schedules/triggers/brand-steward.md +72 -0
- package/schedules/triggers/daily-evening-wrap.md +159 -0
- package/schedules/triggers/daily-midday-sweep.md +58 -0
- package/schedules/triggers/daily-morning-brief.md +55 -0
- package/schedules/triggers/directory-hygiene.md +81 -0
- package/schedules/triggers/dynamic-jobs.md +40 -0
- package/schedules/triggers/inbox-processor.md +115 -0
- package/schedules/triggers/meeting-action-capture.md +60 -0
- package/schedules/triggers/meeting-prep.md +69 -0
- package/schedules/triggers/messaging-inbound.md +50 -0
- package/schedules/triggers/org-pulse.md +24 -0
- package/schedules/triggers/quarterly-self-assessment.md +54 -0
- package/schedules/triggers/weekly-engineering-health.md +37 -0
- package/schedules/triggers/weekly-execution.md +65 -0
- package/schedules/triggers/weekly-hiring.md +53 -0
- package/schedules/triggers/weekly-priorities.md +38 -0
- package/schedules/triggers/weekly-strategic-memo.md +124 -0
- package/scripts/archive-email.sh +55 -0
- package/scripts/cadence/cadence-status.mjs +36 -0
- package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
- package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
- package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
- package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
- package/scripts/ci/check-docs-accuracy.mjs +493 -0
- package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
- package/scripts/ci/check-exports-exist.mjs +140 -0
- package/scripts/ci/check-files-exist.mjs +107 -0
- package/scripts/ci/check-no-build-artifacts.mjs +111 -0
- package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
- package/scripts/ci/check-no-confidential.mjs +198 -0
- package/scripts/ci/check-no-conflict-markers.mjs +169 -0
- package/scripts/ci/check-no-residual-identity.mjs +163 -0
- package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
- package/scripts/ci/check-tarball-fidelity.mjs +205 -0
- package/scripts/ci/check-unresolved-tokens.mjs +83 -0
- package/scripts/ci/check.mjs +109 -0
- package/scripts/ci/check.test.mjs +194 -0
- package/scripts/ci/run-coverage.mjs +82 -0
- package/scripts/ci/run-tests.mjs +71 -0
- package/scripts/cloud-relay/README.md +59 -0
- package/scripts/cloud-relay/index.mjs +233 -0
- package/scripts/cloud-relay/package.json +15 -0
- package/scripts/cloud-relay/railway.json +13 -0
- package/scripts/cloud-relay/voice/README.md +94 -0
- package/scripts/cloud-relay/voice/package-lock.json +39 -0
- package/scripts/cloud-relay/voice/package.json +16 -0
- package/scripts/cloud-relay/voice/railway.json +13 -0
- package/scripts/cloud-relay/voice/server.mjs +532 -0
- package/scripts/collective/hook-runner.mjs +211 -0
- package/scripts/collective/hook-runner.test.mjs +90 -0
- package/scripts/collective/org-pulse.mjs +72 -0
- package/scripts/collective/org-sync.mjs +61 -0
- package/scripts/collective/recall.mjs +45 -0
- package/scripts/collective/who.mjs +30 -0
- package/scripts/comms-monitor.sh +288 -0
- package/scripts/configure-whatsapp-sandbox.sh +201 -0
- package/scripts/continuous-monitor.sh +91 -0
- package/scripts/cost/fleet-digest.mjs +407 -0
- package/scripts/cost/fleet-digest.test.mjs +207 -0
- package/scripts/cost/track-claude-usage.mjs +169 -0
- package/scripts/daemon/agent-daemon.mjs +989 -0
- package/scripts/daemon/agent-daemon.test.mjs +525 -0
- package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
- package/scripts/daemon/cadence-consumer.mjs +1080 -0
- package/scripts/daemon/cadence-consumer.test.mjs +770 -0
- package/scripts/daemon/cadence-handlers.mjs +1121 -0
- package/scripts/daemon/cadence-handlers.test.mjs +617 -0
- package/scripts/daemon/classifier.mjs +704 -0
- package/scripts/daemon/classifier.test.mjs +238 -0
- package/scripts/daemon/classify-kind.mjs +54 -0
- package/scripts/daemon/classify-kind.test.mjs +40 -0
- package/scripts/daemon/context-compiler.mjs +605 -0
- package/scripts/daemon/context-compiler.test.mjs +300 -0
- package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
- package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
- package/scripts/daemon/dispatcher.mjs +1516 -0
- package/scripts/daemon/health.mjs +72 -0
- package/scripts/daemon/inbox-deferral.mjs +210 -0
- package/scripts/daemon/inbox-deferral.test.mjs +242 -0
- package/scripts/daemon/integration.test.mjs +149 -0
- package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
- package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
- package/scripts/daemon/launchd-wrapper.sh +91 -0
- package/scripts/daemon/lib/session-router.mjs +274 -0
- package/scripts/daemon/lib/session-router.test.mjs +295 -0
- package/scripts/daemon/maestro-daemon.mjs +275 -0
- package/scripts/daemon/prompt-builder.mjs +685 -0
- package/scripts/daemon/prompt-builder.test.mjs +213 -0
- package/scripts/daemon/responder.mjs +854 -0
- package/scripts/daemon/session-lock.mjs +721 -0
- package/scripts/daemon/session-lock.test.mjs +252 -0
- package/scripts/daemon/session-outcomes.mjs +640 -0
- package/scripts/daemon/session-outcomes.test.mjs +533 -0
- package/scripts/daemon/typing-registry.mjs +90 -0
- package/scripts/daemon/typing-registry.test.mjs +77 -0
- package/scripts/daemon/voice-webhook-server.mjs +804 -0
- package/scripts/decisions/capture-decision.mjs +116 -0
- package/scripts/disclosure_assessment.py +873 -0
- package/scripts/disclosure_boundaries.py +562 -0
- package/scripts/email-signature-principal.html +52 -0
- package/scripts/email-signature.html +60 -0
- package/scripts/email_quote_thread.py +167 -0
- package/scripts/email_thread_dedup.py +362 -0
- package/scripts/emergency-stop.sh +81 -0
- package/scripts/healthcheck.sh +116 -0
- package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
- package/scripts/hooks/block-mcp-slack-send.sh +7 -0
- package/scripts/hooks/post-action-log.sh +126 -0
- package/scripts/hooks/pre-send-audit.sh +174 -0
- package/scripts/hooks/pre-send-audit.test.mjs +215 -0
- package/scripts/hooks/session-end-log.sh +27 -0
- package/scripts/hooks/session-start-banner.sh +115 -0
- package/scripts/huddle/audio-bridge.mjs +664 -0
- package/scripts/huddle/boot-slack-cdp.sh +102 -0
- package/scripts/huddle/huddle-controller.mjs +942 -0
- package/scripts/huddle/huddle-server.mjs +1229 -0
- package/scripts/huddle/launch-slack.sh +232 -0
- package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
- package/scripts/huddle/package-lock.json +62 -0
- package/scripts/huddle/package.json +22 -0
- package/scripts/huddle/setup-audio.sh +239 -0
- package/scripts/huddle/start-call.mjs +318 -0
- package/scripts/huddle/test-pipeline.mjs +263 -0
- package/scripts/learning/consolidate-skills.mjs +72 -0
- package/scripts/learning/session-search.mjs +125 -0
- package/scripts/llm_email_dedup.py +442 -0
- package/scripts/local-triggers/generate-plists.sh +432 -0
- package/scripts/local-triggers/generate-plists.test.mjs +413 -0
- package/scripts/local-triggers/install-all.sh +49 -0
- package/scripts/local-triggers/plists/.gitkeep +0 -0
- package/scripts/local-triggers/run-trigger.sh +63 -0
- package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
- package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
- package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
- package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
- package/scripts/maintenance/backup-to-cloud.sh +124 -0
- package/scripts/maintenance/health-check.sh +377 -0
- package/scripts/media-generation/README.md +105 -0
- package/scripts/media-generation/gemini-image-client.mjs +173 -0
- package/scripts/media-generation/generate-assets.mjs +289 -0
- package/scripts/media-generation/veo-video-client.mjs +219 -0
- package/scripts/org/send-orgmail.mjs +227 -0
- package/scripts/outbound-dedup-cleanup.sh +43 -0
- package/scripts/outbound-dedup.sh +477 -0
- package/scripts/outbound_dedup.py +115 -0
- package/scripts/parse-voice-transcript.mjs +481 -0
- package/scripts/pdf-generation/README.md +63 -0
- package/scripts/pdf-generation/build-document.mjs +247 -0
- package/scripts/pdf-generation/templates/board-pack.latex +136 -0
- package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
- package/scripts/pdf-generation/templates/memo.latex +114 -0
- package/scripts/poll-slack-events.sh +35 -0
- package/scripts/poller/calendar-poller.mjs +12 -0
- package/scripts/poller/gmail-poller.mjs +192 -0
- package/scripts/poller/imap-client.mjs +289 -0
- package/scripts/poller/inbox-scan-poller.mjs +156 -0
- package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
- package/scripts/poller/index.mjs +73 -0
- package/scripts/poller/intra-session-check.mjs +285 -0
- package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
- package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
- package/scripts/poller/secondary-gmail-poller.mjs +132 -0
- package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
- package/scripts/poller/slack-poller.mjs +854 -0
- package/scripts/poller/slack-socket-mode.mjs +917 -0
- package/scripts/poller/slack-socket-mode.test.mjs +753 -0
- package/scripts/poller/trigger.mjs +75 -0
- package/scripts/poller/utils.mjs +371 -0
- package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
- package/scripts/poller/voice-poller.mjs +236 -0
- package/scripts/poller-launchd/install.sh +66 -0
- package/scripts/poller-launchd/poller.plist.template +40 -0
- package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
- package/scripts/post-interaction-indexer.py +1598 -0
- package/scripts/pre-draft-context.py +994 -0
- package/scripts/pre_draft_lookup.py +258 -0
- package/scripts/rag/build-index.mjs +47 -0
- package/scripts/rag/ingest.mjs +111 -0
- package/scripts/rag/search.mjs +119 -0
- package/scripts/rag-indexer.py +629 -0
- package/scripts/restore-from-backup.sh +248 -0
- package/scripts/restore-from-backup.test.mjs +178 -0
- package/scripts/resume-operations.sh +80 -0
- package/scripts/search-secondary-inbox.py +181 -0
- package/scripts/secondary-inbox-poller.py +437 -0
- package/scripts/self-optimization/compute-metrics.py +398 -0
- package/scripts/send-email-as-principal.py +369 -0
- package/scripts/send-email-threaded.py +392 -0
- package/scripts/send-email-with-attachment.py +377 -0
- package/scripts/send-email.sh +131 -0
- package/scripts/send-sms.sh +175 -0
- package/scripts/send-whatsapp.sh +292 -0
- package/scripts/session-start.sh +106 -0
- package/scripts/setup/boot-claude-session.sh +94 -0
- package/scripts/setup/configure-macos.sh +674 -0
- package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
- package/scripts/setup/configure-voice-tunnel.mjs +182 -0
- package/scripts/setup/generate-agent-env.mjs +92 -0
- package/scripts/setup/generate-agent-package-json.mjs +222 -0
- package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
- package/scripts/setup/generate-autonomy.mjs +60 -0
- package/scripts/setup/generate-backlog.mjs +101 -0
- package/scripts/setup/generate-cadences.mjs +92 -0
- package/scripts/setup/generate-capability.mjs +162 -0
- package/scripts/setup/generate-charter.mjs +76 -0
- package/scripts/setup/generate-comms.mjs +59 -0
- package/scripts/setup/generate-company.mjs +92 -0
- package/scripts/setup/init-agent.sh +547 -0
- package/scripts/setup/init-agent.test.mjs +151 -0
- package/scripts/setup/init-archetype.mjs +74 -0
- package/scripts/setup/init-backup.mjs +54 -0
- package/scripts/setup/init-cadence-bus.mjs +60 -0
- package/scripts/setup/init-channel-bus.mjs +46 -0
- package/scripts/setup/init-cost-tracking.mjs +45 -0
- package/scripts/setup/init-decision-capture.mjs +66 -0
- package/scripts/setup/init-known-agents.mjs +57 -0
- package/scripts/setup/init-learning.mjs +70 -0
- package/scripts/setup/init-memory-executive.mjs +45 -0
- package/scripts/setup/init-model-router.mjs +124 -0
- package/scripts/setup/init-rag.mjs +174 -0
- package/scripts/setup/init-session-router.mjs +38 -0
- package/scripts/setup/init-slack-socket-mode.mjs +260 -0
- package/scripts/setup/init-telegram.mjs +165 -0
- package/scripts/setup/init-voice-realtime.mjs +204 -0
- package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
- package/scripts/setup/install-dev-tools.sh +150 -0
- package/scripts/setup/lib/install-plist.mjs +95 -0
- package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
- package/scripts/setup/render-environment-yaml.mjs +133 -0
- package/scripts/slack-events-ctl.sh +177 -0
- package/scripts/slack-events-server.mjs +1045 -0
- package/scripts/slack-react.mjs +89 -0
- package/scripts/slack-responded.sh +232 -0
- package/scripts/slack-send.sh +287 -0
- package/scripts/slack-typing.mjs +196 -0
- package/scripts/slack-upload-v2.py +95 -0
- package/scripts/sms-handler.mjs +450 -0
- package/scripts/spawn-session.sh +120 -0
- package/scripts/sync-protocol.mjs +217 -0
- package/scripts/system-verify.sh +184 -0
- package/scripts/test-email-thread-dedup.py +239 -0
- package/scripts/test-information-barriers.py +484 -0
- package/scripts/test-llm-email-dedup.py +251 -0
- package/scripts/test-pre-draft-integration.py +203 -0
- package/scripts/test-rag-phase2.sh +442 -0
- package/scripts/test-rag-search.sh +251 -0
- package/scripts/test-voice-parser.mjs +316 -0
- package/scripts/user-context-search.py +659 -0
- package/scripts/validate_outbound.py +1504 -0
- package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
- package/scripts/watchdog/force-reboot.sh +157 -0
- package/scripts/watchdog/memory-watchdog.sh +473 -0
- package/scripts/whatsapp-handler.mjs +538 -0
- package/teams/desktop-operations.yaml +34 -0
- package/teams/executive-office.yaml +27 -0
- package/teams/legal-and-regulatory.yaml +24 -0
- package/teams/platform-and-engineering.yaml +23 -0
- package/teams/strategy-and-growth.yaml +29 -0
- package/workflows/continuous/backlog-executor.yaml +141 -0
- package/workflows/continuous/inbound-monitor.yaml +168 -0
- package/workflows/daily/applicant-triage.yaml +197 -0
- package/workflows/daily/comms-triage.yaml +80 -0
- package/workflows/daily/evening-wrap.yaml +105 -0
- package/workflows/daily/morning-brief.yaml +164 -0
- package/workflows/daily/slack-followup-sweep.yaml +87 -0
- package/workflows/event-driven/README.md +50 -0
- package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
- package/workflows/event-driven/pr-review.yaml +107 -0
- package/workflows/monthly/board-readiness.yaml +76 -0
- package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
- package/workflows/session-protocol.md +171 -0
- package/workflows/weekly/engineering-health.yaml +154 -0
- package/workflows/weekly/hiring-review.yaml +169 -0
- package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
- package/workflows/weekly/strategic-memo.yaml +79 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* coerce-args.mjs — best-effort JSON-Schema argument coercion + required-field
|
|
3
|
+
* validation for tool calls.
|
|
4
|
+
*
|
|
5
|
+
* LLMs frequently emit tool arguments with the wrong JSON primitive type: a
|
|
6
|
+
* number arrives as the string "3", a boolean as "true", an integer as "5".
|
|
7
|
+
* Rather than reject the call outright, this module walks the tool's JSON
|
|
8
|
+
* Schema and coerces each value toward the declared type — "3" -> 3,
|
|
9
|
+
* "true" -> true — fills in declared defaults, and recurses through nested
|
|
10
|
+
* objects and arrays. Every step is a *no-op when it cannot coerce safely*:
|
|
11
|
+
* if a value can't be turned into the target type it is left untouched, so a
|
|
12
|
+
* downstream validator still sees (and can reject) genuinely bad input.
|
|
13
|
+
*
|
|
14
|
+
* Ported and adapted from OpenClaw (packages/llm-core/src/validation.ts,
|
|
15
|
+
* coerceWithJsonSchema and helpers) for the maestro ESM model. The TypeBox-
|
|
16
|
+
* coupled half of the original — Compile/Value.Convert and the
|
|
17
|
+
* validateToolArguments wrapper — is intentionally NOT ported (it pulls in the
|
|
18
|
+
* typebox dependency). The one place the original leaned on TypeBox, picking
|
|
19
|
+
* the winning branch of an anyOf/oneOf union, is reimplemented here with a
|
|
20
|
+
* small pure-JS structural validator (validateAgainstSchema) so the port stays
|
|
21
|
+
* dependency-free.
|
|
22
|
+
*
|
|
23
|
+
* Pure functions; no dependencies. Node builtins only (structuredClone is
|
|
24
|
+
* global in Node 17+).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/* ------------------------------------------------------------------ *
|
|
28
|
+
* type helpers
|
|
29
|
+
* ------------------------------------------------------------------ */
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {unknown} value
|
|
33
|
+
* @returns {boolean} true for any non-null object (including arrays).
|
|
34
|
+
*/
|
|
35
|
+
function isRecord(value) {
|
|
36
|
+
return typeof value === "object" && value !== null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A plain (non-array) object.
|
|
41
|
+
* @param {unknown} value
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
function isPlainObject(value) {
|
|
45
|
+
return isRecord(value) && !Array.isArray(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A value that looks like a JSON Schema fragment (any object).
|
|
50
|
+
* @param {unknown} value
|
|
51
|
+
* @returns {boolean}
|
|
52
|
+
*/
|
|
53
|
+
function isJsonSchemaObject(value) {
|
|
54
|
+
return isRecord(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Normalise schema.type (string | string[] | undefined) into a string[].
|
|
59
|
+
* @param {Record<string, any>} schema
|
|
60
|
+
* @returns {string[]}
|
|
61
|
+
*/
|
|
62
|
+
function getSchemaTypes(schema) {
|
|
63
|
+
if (typeof schema.type === "string") {
|
|
64
|
+
return [schema.type];
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(schema.type)) {
|
|
67
|
+
return schema.type.filter((type) => typeof type === "string");
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Does a runtime value already satisfy a single JSON Schema primitive type?
|
|
74
|
+
* @param {unknown} value
|
|
75
|
+
* @param {string} type
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
function matchesJsonType(value, type) {
|
|
79
|
+
switch (type) {
|
|
80
|
+
case "number":
|
|
81
|
+
return typeof value === "number";
|
|
82
|
+
case "integer":
|
|
83
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
84
|
+
case "boolean":
|
|
85
|
+
return typeof value === "boolean";
|
|
86
|
+
case "string":
|
|
87
|
+
return typeof value === "string";
|
|
88
|
+
case "null":
|
|
89
|
+
return value === null;
|
|
90
|
+
case "array":
|
|
91
|
+
return Array.isArray(value);
|
|
92
|
+
case "object":
|
|
93
|
+
return isPlainObject(value);
|
|
94
|
+
default:
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* ------------------------------------------------------------------ *
|
|
100
|
+
* number parsing (strict JSON-style tokens only)
|
|
101
|
+
* ------------------------------------------------------------------ */
|
|
102
|
+
|
|
103
|
+
const JSON_NUMBER_TOKEN_RE = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:e[+-]?\d+)?$/iu;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse a string into a finite number, but only if it is a clean numeric
|
|
107
|
+
* token (no trailing units, hex, Infinity, etc.). Returns undefined otherwise.
|
|
108
|
+
* @param {string} value
|
|
109
|
+
* @returns {number|undefined}
|
|
110
|
+
*/
|
|
111
|
+
function parseJsonNumberString(value) {
|
|
112
|
+
const trimmed = value.trim();
|
|
113
|
+
if (!trimmed || !JSON_NUMBER_TOKEN_RE.test(trimmed)) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const parsed = Number(trimmed);
|
|
117
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Like parseJsonNumberString but only accepts safe integers.
|
|
122
|
+
* @param {string} value
|
|
123
|
+
* @returns {number|undefined}
|
|
124
|
+
*/
|
|
125
|
+
function parseJsonIntegerString(value) {
|
|
126
|
+
const parsed = parseJsonNumberString(value);
|
|
127
|
+
return parsed !== undefined && Number.isSafeInteger(parsed) ? parsed : undefined;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ------------------------------------------------------------------ *
|
|
131
|
+
* primitive coercion
|
|
132
|
+
* ------------------------------------------------------------------ */
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Coerce a single value toward one JSON Schema primitive type. Returns the
|
|
136
|
+
* coerced value, or the original value unchanged if it cannot be coerced
|
|
137
|
+
* safely. (Identity return is used by the caller to detect "no change".)
|
|
138
|
+
* @param {unknown} value
|
|
139
|
+
* @param {string} type
|
|
140
|
+
* @returns {unknown}
|
|
141
|
+
*/
|
|
142
|
+
function coercePrimitiveByType(value, type) {
|
|
143
|
+
switch (type) {
|
|
144
|
+
case "number": {
|
|
145
|
+
if (value === null) {
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
149
|
+
const parsed = parseJsonNumberString(value);
|
|
150
|
+
if (parsed !== undefined) {
|
|
151
|
+
return parsed;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === "boolean") {
|
|
155
|
+
return value ? 1 : 0;
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
case "integer": {
|
|
160
|
+
if (value === null) {
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
164
|
+
const parsed = parseJsonIntegerString(value);
|
|
165
|
+
if (parsed !== undefined) {
|
|
166
|
+
return parsed;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (typeof value === "boolean") {
|
|
170
|
+
return value ? 1 : 0;
|
|
171
|
+
}
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
case "boolean": {
|
|
175
|
+
if (value === null) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (typeof value === "string") {
|
|
179
|
+
if (value === "true") {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
if (value === "false") {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (typeof value === "number") {
|
|
187
|
+
if (value === 1) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
if (value === 0) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
case "string": {
|
|
197
|
+
if (value === null) {
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
201
|
+
return String(value);
|
|
202
|
+
}
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
case "null": {
|
|
206
|
+
if (value === "" || value === 0 || value === false) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return value;
|
|
210
|
+
}
|
|
211
|
+
default:
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* ------------------------------------------------------------------ *
|
|
217
|
+
* structural validation (pure-JS replacement for the TypeBox check that
|
|
218
|
+
* the original used only to pick the winning anyOf/oneOf branch)
|
|
219
|
+
* ------------------------------------------------------------------ */
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Best-effort structural check that a value satisfies a JSON Schema fragment.
|
|
223
|
+
* This is deliberately lenient — it only understands the keywords this module
|
|
224
|
+
* coerces against (type, properties, required, items). Unknown keywords are
|
|
225
|
+
* ignored. It exists solely to disambiguate union branches; it is NOT a
|
|
226
|
+
* complete JSON Schema validator.
|
|
227
|
+
* @param {unknown} value
|
|
228
|
+
* @param {Record<string, any>} schema
|
|
229
|
+
* @returns {boolean}
|
|
230
|
+
*/
|
|
231
|
+
function validateAgainstSchema(value, schema) {
|
|
232
|
+
if (!isJsonSchemaObject(schema)) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (Array.isArray(schema.allOf)) {
|
|
237
|
+
if (!schema.allOf.every((sub) => validateAgainstSchema(value, sub))) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (Array.isArray(schema.anyOf)) {
|
|
242
|
+
if (!schema.anyOf.some((sub) => validateAgainstSchema(value, sub))) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (Array.isArray(schema.oneOf)) {
|
|
247
|
+
const matches = schema.oneOf.filter((sub) => validateAgainstSchema(value, sub));
|
|
248
|
+
if (matches.length !== 1) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const types = getSchemaTypes(schema);
|
|
254
|
+
if (types.length > 0 && !types.some((t) => matchesJsonType(value, t))) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (isPlainObject(value)) {
|
|
259
|
+
if (Array.isArray(schema.required)) {
|
|
260
|
+
for (const key of schema.required) {
|
|
261
|
+
if (!(key in value)) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (schema.properties && isJsonSchemaObject(schema.properties)) {
|
|
267
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
268
|
+
if (key in value && !validateAgainstSchema(value[key], propSchema)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (Array.isArray(value) && schema.items !== undefined) {
|
|
276
|
+
if (Array.isArray(schema.items)) {
|
|
277
|
+
for (let i = 0; i < value.length; i++) {
|
|
278
|
+
const itemSchema = schema.items[i];
|
|
279
|
+
if (itemSchema && !validateAgainstSchema(value[i], itemSchema)) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
} else if (isJsonSchemaObject(schema.items)) {
|
|
284
|
+
for (const item of value) {
|
|
285
|
+
if (!validateAgainstSchema(item, schema.items)) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* ------------------------------------------------------------------ *
|
|
296
|
+
* recursive coercion
|
|
297
|
+
* ------------------------------------------------------------------ */
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Coerce the properties (and additionalProperties) of an object in place.
|
|
301
|
+
* Also fills in declared `default`s for missing properties.
|
|
302
|
+
* @param {Record<string, unknown>} value
|
|
303
|
+
* @param {Record<string, any>} schema
|
|
304
|
+
* @returns {void}
|
|
305
|
+
*/
|
|
306
|
+
function applySchemaObjectCoercion(value, schema) {
|
|
307
|
+
const properties = schema.properties;
|
|
308
|
+
const definedKeys = new Set(properties ? Object.keys(properties) : []);
|
|
309
|
+
|
|
310
|
+
if (properties && isJsonSchemaObject(properties)) {
|
|
311
|
+
for (const [key, propertySchema] of Object.entries(properties)) {
|
|
312
|
+
if (key in value) {
|
|
313
|
+
value[key] = coerceWithJsonSchema(value[key], propertySchema);
|
|
314
|
+
} else if (isJsonSchemaObject(propertySchema) && "default" in propertySchema) {
|
|
315
|
+
// Fill declared defaults for absent properties, then coerce the
|
|
316
|
+
// default itself (defaults are usually already well-typed, but this
|
|
317
|
+
// keeps the behaviour consistent and lets a default flow through
|
|
318
|
+
// nested object/array coercion too).
|
|
319
|
+
value[key] = coerceWithJsonSchema(
|
|
320
|
+
structuredCloneSafe(propertySchema.default),
|
|
321
|
+
propertySchema,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (schema.additionalProperties && isJsonSchemaObject(schema.additionalProperties)) {
|
|
328
|
+
for (const [key, propertyValue] of Object.entries(value)) {
|
|
329
|
+
if (!definedKeys.has(key)) {
|
|
330
|
+
value[key] = coerceWithJsonSchema(propertyValue, schema.additionalProperties);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Coerce the elements of an array in place against schema.items.
|
|
338
|
+
* @param {unknown[]} value
|
|
339
|
+
* @param {Record<string, any>} schema
|
|
340
|
+
* @returns {void}
|
|
341
|
+
*/
|
|
342
|
+
function applySchemaArrayCoercion(value, schema) {
|
|
343
|
+
if (Array.isArray(schema.items)) {
|
|
344
|
+
for (let index = 0; index < value.length; index++) {
|
|
345
|
+
const itemSchema = schema.items[index];
|
|
346
|
+
if (itemSchema) {
|
|
347
|
+
value[index] = coerceWithJsonSchema(value[index], itemSchema);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (isJsonSchemaObject(schema.items)) {
|
|
354
|
+
for (let index = 0; index < value.length; index++) {
|
|
355
|
+
value[index] = coerceWithJsonSchema(value[index], schema.items);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Try each branch of an anyOf/oneOf union: coerce a clone against the branch
|
|
362
|
+
* and keep the first result that structurally validates. Falls back to the
|
|
363
|
+
* original value if no branch produces a valid result.
|
|
364
|
+
* @param {unknown} value
|
|
365
|
+
* @param {Record<string, any>[]} schemas
|
|
366
|
+
* @returns {unknown}
|
|
367
|
+
*/
|
|
368
|
+
function coerceWithUnionSchema(value, schemas) {
|
|
369
|
+
for (const schema of schemas) {
|
|
370
|
+
const candidate = structuredCloneSafe(value);
|
|
371
|
+
const coerced = coerceWithJsonSchema(candidate, schema);
|
|
372
|
+
if (validateAgainstSchema(coerced, schema)) {
|
|
373
|
+
return coerced;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return value;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* structuredClone is global in Node 17+, but guard for primitives (cheaper and
|
|
381
|
+
* avoids any host without it choking on simple values).
|
|
382
|
+
* @template T
|
|
383
|
+
* @param {T} value
|
|
384
|
+
* @returns {T}
|
|
385
|
+
*/
|
|
386
|
+
function structuredCloneSafe(value) {
|
|
387
|
+
if (value === null || typeof value !== "object") {
|
|
388
|
+
return value;
|
|
389
|
+
}
|
|
390
|
+
if (typeof structuredClone === "function") {
|
|
391
|
+
return structuredClone(value);
|
|
392
|
+
}
|
|
393
|
+
return JSON.parse(JSON.stringify(value));
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Core recursive coercion. Given a value and a JSON Schema fragment, returns a
|
|
398
|
+
* value coerced toward the schema's declared type(s), recursing into objects
|
|
399
|
+
* and arrays and resolving allOf/anyOf/oneOf on a best-effort basis. Mutates
|
|
400
|
+
* objects/arrays in place (callers that need immutability should clone first —
|
|
401
|
+
* see coerceArgs).
|
|
402
|
+
* @param {unknown} value
|
|
403
|
+
* @param {Record<string, any>} schema
|
|
404
|
+
* @returns {unknown}
|
|
405
|
+
*/
|
|
406
|
+
function coerceWithJsonSchema(value, schema) {
|
|
407
|
+
if (!isJsonSchemaObject(schema)) {
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
let nextValue = value;
|
|
412
|
+
|
|
413
|
+
if (Array.isArray(schema.allOf)) {
|
|
414
|
+
for (const nested of schema.allOf) {
|
|
415
|
+
nextValue = coerceWithJsonSchema(nextValue, nested);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (Array.isArray(schema.anyOf)) {
|
|
420
|
+
nextValue = coerceWithUnionSchema(nextValue, schema.anyOf);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (Array.isArray(schema.oneOf)) {
|
|
424
|
+
nextValue = coerceWithUnionSchema(nextValue, schema.oneOf);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const schemaTypes = getSchemaTypes(schema);
|
|
428
|
+
// For a union of types (e.g. ["string","number"]) only coerce if the value
|
|
429
|
+
// matches none of them; otherwise leave a value that already fits one member.
|
|
430
|
+
const matchesUnionMember =
|
|
431
|
+
schemaTypes.length > 1 &&
|
|
432
|
+
schemaTypes.some((schemaType) => matchesJsonType(nextValue, schemaType));
|
|
433
|
+
if (schemaTypes.length > 0 && !matchesUnionMember) {
|
|
434
|
+
for (const schemaType of schemaTypes) {
|
|
435
|
+
const candidate = coercePrimitiveByType(nextValue, schemaType);
|
|
436
|
+
if (candidate !== nextValue) {
|
|
437
|
+
nextValue = candidate;
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (schemaTypes.includes("object") && isPlainObject(nextValue)) {
|
|
444
|
+
applySchemaObjectCoercion(nextValue, schema);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (schemaTypes.includes("array") && Array.isArray(nextValue)) {
|
|
448
|
+
applySchemaArrayCoercion(nextValue, schema);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return nextValue;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* ------------------------------------------------------------------ *
|
|
455
|
+
* public API
|
|
456
|
+
* ------------------------------------------------------------------ */
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Coerce tool-call arguments toward a JSON Schema, filling declared defaults
|
|
460
|
+
* and recursing into nested objects/arrays. Best-effort and non-destructive:
|
|
461
|
+
* the input is deep-cloned first (never mutated), and any value that cannot be
|
|
462
|
+
* coerced safely is returned unchanged so a strict validator downstream can
|
|
463
|
+
* still reject it.
|
|
464
|
+
*
|
|
465
|
+
* @param {unknown} value The arguments object (or any value) to coerce.
|
|
466
|
+
* @param {Record<string, any>} schema A JSON Schema fragment.
|
|
467
|
+
* @returns {unknown} A new, coerced value.
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* coerceArgs({ count: "3", on: "true" },
|
|
471
|
+
* { type: "object", properties: {
|
|
472
|
+
* count: { type: "integer" }, on: { type: "boolean" } } });
|
|
473
|
+
* // => { count: 3, on: true }
|
|
474
|
+
*/
|
|
475
|
+
export function coerceArgs(value, schema) {
|
|
476
|
+
if (!isJsonSchemaObject(schema)) {
|
|
477
|
+
return value;
|
|
478
|
+
}
|
|
479
|
+
const clone = structuredCloneSafe(value);
|
|
480
|
+
return coerceWithJsonSchema(clone, schema);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Check that an object contains every property listed in `schema.required`.
|
|
485
|
+
* Recurses one level into `properties` whose sub-schema also declares
|
|
486
|
+
* `required`, reporting nested misses with dotted paths (e.g. "address.zip").
|
|
487
|
+
*
|
|
488
|
+
* Note: a missing top-level value (non-object) is reported as every required
|
|
489
|
+
* key missing. This is a structural required-presence check only — it does NOT
|
|
490
|
+
* type-check present values (use coerceArgs + a full validator for that).
|
|
491
|
+
*
|
|
492
|
+
* @param {unknown} value The object to check.
|
|
493
|
+
* @param {Record<string, any>} schema A JSON Schema fragment.
|
|
494
|
+
* @returns {{ ok: boolean, missing: string[] }}
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* validateRequired({ a: 1 }, { required: ["a", "b"] });
|
|
498
|
+
* // => { ok: false, missing: ["b"] }
|
|
499
|
+
*/
|
|
500
|
+
export function validateRequired(value, schema) {
|
|
501
|
+
const missing = [];
|
|
502
|
+
collectMissingRequired(value, schema, "", missing);
|
|
503
|
+
return { ok: missing.length === 0, missing };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* @param {unknown} value
|
|
508
|
+
* @param {Record<string, any>} schema
|
|
509
|
+
* @param {string} prefix Dotted path prefix for nested reporting.
|
|
510
|
+
* @param {string[]} out Accumulator for missing dotted paths.
|
|
511
|
+
* @returns {void}
|
|
512
|
+
*/
|
|
513
|
+
function collectMissingRequired(value, schema, prefix, out) {
|
|
514
|
+
if (!isJsonSchemaObject(schema)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
519
|
+
const valueIsObject = isPlainObject(value);
|
|
520
|
+
|
|
521
|
+
for (const key of required) {
|
|
522
|
+
if (typeof key !== "string") {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (!valueIsObject || !(key in value)) {
|
|
526
|
+
out.push(prefix ? `${prefix}.${key}` : key);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Recurse one level into declared object properties that are present, so a
|
|
531
|
+
// nested required miss (e.g. address.zip) is also surfaced.
|
|
532
|
+
if (valueIsObject && schema.properties && isJsonSchemaObject(schema.properties)) {
|
|
533
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
534
|
+
if (!isJsonSchemaObject(propSchema)) {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
const present = key in value;
|
|
538
|
+
const childRequired = Array.isArray(propSchema.required) && propSchema.required.length > 0;
|
|
539
|
+
// Only descend when the property is present (an absent object property is
|
|
540
|
+
// already flagged at this level if it was required) and the child itself
|
|
541
|
+
// declares required keys to check.
|
|
542
|
+
if (present && childRequired) {
|
|
543
|
+
collectMissingRequired(
|
|
544
|
+
value[key],
|
|
545
|
+
propSchema,
|
|
546
|
+
prefix ? `${prefix}.${key}` : key,
|
|
547
|
+
out,
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|