@cohortapp/agent-sdk 2.17.0 → 2.18.4
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/settings.json +18 -0
- package/.env.example +18 -5
- package/README.md +1 -0
- package/bin/maestro.mjs +62 -0
- package/docs/guides/billing-console-keys.md +60 -0
- package/docs/guides/front-door-session.md +54 -9
- package/docs/guides/mac-mini.md +20 -25
- package/docs/guides/setup-wizard.md +1 -1
- package/docs/runbooks/fleet-rollout.md +156 -0
- package/docs/runbooks/mac-mini-bootstrap.md +12 -14
- package/lib/action-executor.js +19 -3
- package/lib/budget-guard.mjs +279 -3
- package/lib/channels/base-adapter.mjs +3 -1
- package/lib/channels/contract.mjs +2 -1
- package/lib/channels/inbox-item.mjs +8 -0
- package/lib/claude-bin.mjs +5 -6
- package/lib/cli/doctor-checks.mjs +141 -10
- package/lib/cli/global-setup-extras.mjs +5 -1
- package/lib/cli/inbox.mjs +100 -15
- package/lib/cli/seat-auth.mjs +463 -0
- package/lib/cli/session.mjs +80 -12
- package/lib/collective/capture.mjs +8 -6
- package/lib/collective/global-config.mjs +63 -1
- package/lib/collective/presence.mjs +142 -5
- package/lib/comms/send-gate.mjs +559 -1
- package/lib/diagnostics/alerts.mjs +49 -0
- package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
- package/lib/engine/agents/definitions.mjs +343 -0
- package/lib/engine/agents/persist.mjs +275 -0
- package/lib/engine/agents/runtime.mjs +748 -0
- package/lib/engine/agents/usage.mjs +95 -0
- package/lib/engine/auth-status.mjs +139 -0
- package/lib/engine/budget.mjs +194 -0
- package/lib/engine/cli.mjs +1204 -0
- package/lib/engine/commands/index.mjs +269 -0
- package/lib/engine/context/budget.mjs +219 -0
- package/lib/engine/context/cache.mjs +125 -0
- package/lib/engine/context/child-env.mjs +215 -0
- package/lib/engine/context/compaction.mjs +342 -0
- package/lib/engine/context/images.mjs +90 -0
- package/lib/engine/context/instructions.mjs +327 -0
- package/lib/engine/context/lazy-instructions.mjs +169 -0
- package/lib/engine/context/manager.mjs +182 -0
- package/lib/engine/context/real-path.mjs +91 -0
- package/lib/engine/context/secret-values.mjs +163 -0
- package/lib/engine/context/settings.mjs +274 -0
- package/lib/engine/context/stream-input.mjs +159 -0
- package/lib/engine/guard.mjs +152 -0
- package/lib/engine/hooks.mjs +713 -0
- package/lib/engine/loop.mjs +560 -0
- package/lib/engine/mcp/client.mjs +254 -0
- package/lib/engine/mcp/config.mjs +301 -0
- package/lib/engine/mcp/http.mjs +201 -0
- package/lib/engine/mcp/index.mjs +146 -0
- package/lib/engine/mcp/jsonrpc.mjs +147 -0
- package/lib/engine/mcp/naming.mjs +66 -0
- package/lib/engine/mcp/resources.mjs +89 -0
- package/lib/engine/mcp/results.mjs +133 -0
- package/lib/engine/mcp/stdio.mjs +137 -0
- package/lib/engine/mcp/supervisor.mjs +116 -0
- package/lib/engine/messages.mjs +104 -0
- package/lib/engine/output/json.mjs +164 -0
- package/lib/engine/output/stream-json.mjs +266 -0
- package/lib/engine/permissions.mjs +845 -0
- package/lib/engine/process-identity.mjs +164 -0
- package/lib/engine/process-tree.mjs +551 -0
- package/lib/engine/prompt.mjs +60 -0
- package/lib/engine/session/store.mjs +299 -0
- package/lib/engine/session-runtime/args.mjs +97 -0
- package/lib/engine/session-runtime/host.mjs +143 -0
- package/lib/engine/session-runtime/inbox.mjs +122 -0
- package/lib/engine/session-runtime/notifications.mjs +129 -0
- package/lib/engine/session-runtime/registry.mjs +328 -0
- package/lib/engine/session-runtime/runner.mjs +344 -0
- package/lib/engine/session-runtime/socket.mjs +212 -0
- package/lib/engine/session-runtime/wakeup.mjs +115 -0
- package/lib/engine/skills/index.mjs +321 -0
- package/lib/engine/tools/bash-background.mjs +533 -0
- package/lib/engine/tools/bash.mjs +216 -0
- package/lib/engine/tools/edit.mjs +97 -0
- package/lib/engine/tools/glob.mjs +81 -0
- package/lib/engine/tools/grep.mjs +224 -0
- package/lib/engine/tools/index.mjs +84 -0
- package/lib/engine/tools/list-agents.mjs +32 -0
- package/lib/engine/tools/ls.mjs +127 -0
- package/lib/engine/tools/monitor.mjs +82 -0
- package/lib/engine/tools/notebook-edit.mjs +218 -0
- package/lib/engine/tools/read.mjs +103 -0
- package/lib/engine/tools/schedule-wakeup.mjs +45 -0
- package/lib/engine/tools/schema.mjs +144 -0
- package/lib/engine/tools/send-message.mjs +77 -0
- package/lib/engine/tools/session.mjs +70 -0
- package/lib/engine/tools/todo.mjs +144 -0
- package/lib/engine/tools/toolsearch.mjs +217 -0
- package/lib/engine/tools/walk.mjs +193 -0
- package/lib/engine/tools/web-switch.mjs +31 -0
- package/lib/engine/tools/webfetch-html.mjs +387 -0
- package/lib/engine/tools/webfetch-net.mjs +340 -0
- package/lib/engine/tools/webfetch.mjs +198 -0
- package/lib/engine/tools/websearch.mjs +91 -0
- package/lib/engine/tools/workflow.mjs +95 -0
- package/lib/engine/tools/write.mjs +76 -0
- package/lib/engine/tui/line-editor.mjs +137 -0
- package/lib/engine/tui/render.mjs +86 -0
- package/lib/engine/tui/tui.mjs +274 -0
- package/lib/engine/wire/anthropic-messages.mjs +263 -0
- package/lib/engine/wire/effort.mjs +36 -0
- package/lib/engine/wire/errors.mjs +496 -0
- package/lib/engine/wire/http.mjs +441 -0
- package/lib/engine/wire/index.mjs +76 -0
- package/lib/engine/wire/openai-chat.mjs +332 -0
- package/lib/engine/wire/prompt-cache.mjs +79 -0
- package/lib/engine/wire/search.mjs +140 -0
- package/lib/engine/wire/sse.mjs +114 -0
- package/lib/engine/wire/stall.mjs +349 -0
- package/lib/engine/wire/token-provider.mjs +175 -0
- package/lib/engine/wire/usage.mjs +192 -0
- package/lib/engine/workflow/host.mjs +524 -0
- package/lib/engine/workflow/journal.mjs +188 -0
- package/lib/engine/workflow/json-schema.mjs +171 -0
- package/lib/engine/workflow/meta.mjs +329 -0
- package/lib/engine/workflow/notifications.mjs +52 -0
- package/lib/engine/workflow/runtime.mjs +447 -0
- package/lib/engine/workflow/sandbox.mjs +534 -0
- package/lib/engine/workflow/worker.mjs +141 -0
- package/lib/engine/workflow/worktree.mjs +74 -0
- package/lib/execution/disposition.mjs +1 -1
- package/lib/execution/intake.mjs +10 -0
- package/lib/execution/surface-policy.mjs +15 -0
- package/lib/learning/curator.mjs +8 -6
- package/lib/learning/reflect.mjs +8 -6
- package/lib/model-router/catalog/cohort.yaml +137 -0
- package/lib/model-router/catalog.mjs +118 -1
- package/lib/model-router/failover.mjs +67 -16
- package/lib/model-router/llm-task.mjs +39 -3
- package/lib/model-router/resolve.mjs +89 -3
- package/lib/model-router/spawn.mjs +46 -47
- package/lib/model-router/taxonomy.mjs +126 -4
- package/lib/org/cost-sync.mjs +141 -11
- package/lib/org/inbound/broadcast.mjs +289 -0
- package/lib/org/inbound/collective.mjs +375 -0
- package/lib/org/inbound/directedness.mjs +96 -8
- package/lib/org/inbound/facts.mjs +78 -2
- package/lib/org/inbound/project.mjs +22 -0
- package/lib/org/inbound/surfaces.mjs +14 -0
- package/lib/org/llm-token.mjs +879 -0
- package/lib/org/mesh.mjs +61 -0
- package/lib/org/messaging.mjs +3 -1
- package/lib/org/protocol.checksum +1 -1
- package/lib/org/protocol.mjs +15 -0
- package/lib/org/quota.mjs +520 -0
- package/lib/org/tool-surface.mjs +104 -16
- package/lib/org/ui-parity.mjs +16 -1
- package/lib/org/work-ledger.mjs +37 -6
- package/lib/rate-guard.mjs +114 -1
- package/lib/resource-governor.mjs +41 -6
- package/lib/runtime/adapter.mjs +823 -0
- package/lib/runtime/child-env.mjs +191 -0
- package/lib/runtime/legacy-shell-guard.mjs +97 -0
- package/lib/runtime/seat-engine.mjs +162 -0
- package/lib/session/ask-ledger.mjs +271 -0
- package/lib/session/current-work.mjs +676 -0
- package/lib/session/feed-core.mjs +40 -3
- package/lib/session/launch-args.mjs +56 -4
- package/lib/session/status-summary.mjs +26 -9
- package/lib/session/upgrade-notice.mjs +42 -0
- package/lib/setup/claude-probe.mjs +117 -13
- package/lib/setup/enrich.mjs +13 -10
- package/lib/setup/sections/model.mjs +39 -13
- package/lib/telemetry/collect.mjs +208 -9
- package/lib/upgrade/ignored-drift.mjs +105 -0
- package/lib/voice/post-call-brief.mjs +30 -17
- package/package.json +13 -3
- package/plugins/maestro-skills/skills/board-work.md +5 -0
- package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
- package/plugins/maestro-skills/skills/main-session.md +18 -7
- package/scripts/ci/check-tarball-fidelity.mjs +126 -2
- package/scripts/ci/run-tests.mjs +47 -19
- package/scripts/cohort-llm/api-key-helper.mjs +92 -0
- package/scripts/collective/hook-runner.mjs +29 -2
- package/scripts/continuous-monitor.sh +13 -0
- package/scripts/cost/track-claude-usage.mjs +15 -0
- package/scripts/daemon/agent-daemon.mjs +408 -20
- package/scripts/daemon/assurance.mjs +48 -12
- package/scripts/daemon/cadence-consumer.mjs +218 -68
- package/scripts/daemon/cadence-handlers.mjs +73 -4
- package/scripts/daemon/classifier.mjs +75 -26
- package/scripts/daemon/context-compiler.mjs +51 -37
- package/scripts/daemon/deliver.mjs +30 -1
- package/scripts/daemon/dispatcher.mjs +595 -149
- package/scripts/daemon/health.mjs +14 -1
- package/scripts/daemon/maestro-daemon.mjs +11 -0
- package/scripts/daemon/prompt-builder.mjs +24 -0
- package/scripts/daemon/responder.mjs +246 -79
- package/scripts/daemon/sdk-version.mjs +98 -16
- package/scripts/eval/probe-gateway.mjs +635 -0
- package/scripts/eval/replay/extract.mjs +270 -0
- package/scripts/eval/replay/grade.mjs +260 -0
- package/scripts/eval/replay/lib/config.mjs +50 -0
- package/scripts/eval/replay/lib/effects.mjs +65 -0
- package/scripts/eval/replay/lib/fixture.mjs +188 -0
- package/scripts/eval/replay/lib/judge.mjs +72 -0
- package/scripts/eval/replay/lib/redact.mjs +136 -0
- package/scripts/eval/replay/lib/sandbox.mjs +170 -0
- package/scripts/eval/replay/lib/schema-check.mjs +63 -0
- package/scripts/eval/replay/lib/transcript.mjs +76 -0
- package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
- package/scripts/eval/replay/report.mjs +185 -0
- package/scripts/eval/replay/run.mjs +404 -0
- package/scripts/fleet/rollout.mjs +1094 -0
- package/scripts/hooks/pre-send-audit.sh +36 -245
- package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
- package/scripts/hooks/validate-state-yaml.sh +190 -0
- package/scripts/huddle/huddle-llm.mjs +361 -0
- package/scripts/huddle/huddle-server.mjs +46 -121
- package/scripts/local-triggers/autoupdate.sh +448 -78
- package/scripts/local-triggers/run-trigger.sh +13 -0
- package/scripts/maintenance/pin-integrity.mjs +364 -0
- package/scripts/poll-slack-events.sh +41 -9
- package/scripts/poller/slack-socket-mode.mjs +28 -3
- package/scripts/session/supervisor.mjs +80 -13
- package/scripts/spawn-session.sh +13 -0
- package/bin/maestro.test.mjs +0 -1574
- package/lib/action-executor.test.mjs +0 -871
- package/lib/archetype.test.mjs +0 -132
- package/lib/assurance/plan-note.test.mjs +0 -234
- package/lib/assurance/room-budget.test.mjs +0 -486
- package/lib/assurance/tier.test.mjs +0 -174
- package/lib/autonomy.test.mjs +0 -66
- package/lib/backlog.test.mjs +0 -302
- package/lib/backup/policy.test.mjs +0 -305
- package/lib/budget-escalate.test.mjs +0 -232
- package/lib/budget-guard.envelope.test.mjs +0 -476
- package/lib/budget-guard.test.mjs +0 -427
- package/lib/cadence-bus-requeue.test.mjs +0 -83
- package/lib/cadence-bus-schedule.test.mjs +0 -194
- package/lib/cadence-bus.test.mjs +0 -720
- package/lib/cadences.test.mjs +0 -230
- package/lib/capability/inventory.test.mjs +0 -232
- package/lib/capability.test.mjs +0 -78
- package/lib/channels/base-adapter.test.mjs +0 -590
- package/lib/channels/channels.test.mjs +0 -371
- package/lib/channels/contract.test.mjs +0 -162
- package/lib/channels/inbox-item.test.mjs +0 -368
- package/lib/channels/orgmail/adapter.test.mjs +0 -448
- package/lib/channels/pairing.test.mjs +0 -270
- package/lib/channels/repeat-suppressor.test.mjs +0 -134
- package/lib/channels/slack-adapter.test.mjs +0 -212
- package/lib/channels/telegram-adapter.test.mjs +0 -306
- package/lib/channels/voice/adapter.test.mjs +0 -278
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
- package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
- package/lib/charter.test.mjs +0 -89
- package/lib/claude-bin.test.mjs +0 -131
- package/lib/cli/board.test.mjs +0 -227
- package/lib/cli/design.test.mjs +0 -270
- package/lib/cli/doctor-checks.test.mjs +0 -336
- package/lib/cli/global-setup-extras.test.mjs +0 -462
- package/lib/cli/inbox.test.mjs +0 -230
- package/lib/cli/session-ack.test.mjs +0 -63
- package/lib/cli/session.test.mjs +0 -613
- package/lib/collective/capture.test.mjs +0 -121
- package/lib/collective/cards.test.mjs +0 -114
- package/lib/collective/config.test.mjs +0 -123
- package/lib/collective/global-config.test.mjs +0 -220
- package/lib/collective/global-skills.test.mjs +0 -126
- package/lib/collective/presence.test.mjs +0 -95
- package/lib/collective/recall.test.mjs +0 -116
- package/lib/collective/vendor-skills.test.mjs +0 -306
- package/lib/comms/send-gate.test.mjs +0 -770
- package/lib/comms.test.mjs +0 -41
- package/lib/context/budget.test.mjs +0 -252
- package/lib/context/history-scope.test.mjs +0 -79
- package/lib/cost/ledger-row.test.mjs +0 -183
- package/lib/design/design-md.test.mjs +0 -318
- package/lib/design/fixtures/DESIGN.golden.md +0 -238
- package/lib/design/fixtures/PRODUCT.golden.md +0 -67
- package/lib/design/fixtures/foundation.json +0 -133
- package/lib/design/refresh-gate.test.mjs +0 -144
- package/lib/design/write.test.mjs +0 -241
- package/lib/diagnostics/alerts.test.mjs +0 -318
- package/lib/diagnostics/backup-freshness.test.mjs +0 -185
- package/lib/diagnostics/counters.test.mjs +0 -206
- package/lib/diagnostics/events.test.mjs +0 -290
- package/lib/diagnostics/otel.test.mjs +0 -196
- package/lib/diagnostics/trace.test.mjs +0 -251
- package/lib/env-compat.test.mjs +0 -104
- package/lib/execution/disposition.test.mjs +0 -553
- package/lib/execution/drive.test.mjs +0 -270
- package/lib/execution/effects.test.mjs +0 -344
- package/lib/execution/intake.test.mjs +0 -389
- package/lib/execution/journal.test.mjs +0 -261
- package/lib/execution/match.test.mjs +0 -235
- package/lib/execution/pipeline.test.mjs +0 -392
- package/lib/execution/route.test.mjs +0 -186
- package/lib/execution/surface-policy.test.mjs +0 -162
- package/lib/fs-atomic.test.mjs +0 -72
- package/lib/fs-ownership.test.mjs +0 -158
- package/lib/goals/admission.test.mjs +0 -164
- package/lib/goals/classify.test.mjs +0 -167
- package/lib/goals/collaborate.test.mjs +0 -336
- package/lib/goals/gaps.test.mjs +0 -284
- package/lib/goals/loop.test.mjs +0 -845
- package/lib/hooks/bus.test.mjs +0 -387
- package/lib/identity/persona.test.mjs +0 -142
- package/lib/kpi-sensors.test.mjs +0 -278
- package/lib/kpi.test.mjs +0 -244
- package/lib/learning/config.test.mjs +0 -75
- package/lib/learning/counters.test.mjs +0 -69
- package/lib/learning/curator-consolidate.test.mjs +0 -238
- package/lib/learning/curator.test.mjs +0 -106
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.test.mjs +0 -125
- package/lib/learning/skill-writer.test.mjs +0 -210
- package/lib/mandate/audit.test.mjs +0 -195
- package/lib/mandate/contract.test.mjs +0 -185
- package/lib/mandate/derive.test.mjs +0 -274
- package/lib/mandate/model.test.mjs +0 -164
- package/lib/mandate/refresh.test.mjs +0 -389
- package/lib/mcp/server.test.mjs +0 -426
- package/lib/model-router/auth-profiles.test.mjs +0 -580
- package/lib/model-router/catalog.test.mjs +0 -385
- package/lib/model-router/economics.test.mjs +0 -438
- package/lib/model-router/failover.test.mjs +0 -439
- package/lib/model-router/health.test.mjs +0 -338
- package/lib/model-router/integration-coverage.test.mjs +0 -831
- package/lib/model-router/integration.test.mjs +0 -564
- package/lib/model-router/ledger.test.mjs +0 -415
- package/lib/model-router/llm-task.test.mjs +0 -392
- package/lib/model-router/org-credentials.test.mjs +0 -265
- package/lib/model-router/pricing-refresh.test.mjs +0 -286
- package/lib/model-router/reconcile.test.mjs +0 -316
- package/lib/model-router/repair.test.mjs +0 -180
- package/lib/model-router/spawn.test.mjs +0 -446
- package/lib/model-router/taxonomy.test.mjs +0 -410
- package/lib/model-router.test.mjs +0 -1207
- package/lib/org/activity.test.mjs +0 -134
- package/lib/org/approvals.test.mjs +0 -216
- package/lib/org/awareness.test.mjs +0 -159
- package/lib/org/board-mine-cache.test.mjs +0 -53
- package/lib/org/board.test.mjs +0 -187
- package/lib/org/bootstrap-context.test.mjs +0 -153
- package/lib/org/client.test.mjs +0 -1206
- package/lib/org/cohort-client.test.mjs +0 -126
- package/lib/org/cost-sync.test.mjs +0 -153
- package/lib/org/doctor.test.mjs +0 -346
- package/lib/org/engagement-ledger.test.mjs +0 -112
- package/lib/org/engagement.test.mjs +0 -739
- package/lib/org/handoff.test.mjs +0 -269
- package/lib/org/inbound/directedness.test.mjs +0 -668
- package/lib/org/inbound/facts.test.mjs +0 -471
- package/lib/org/inbound/hydrate.test.mjs +0 -908
- package/lib/org/inbound/index.test.mjs +0 -429
- package/lib/org/inbound/project.test.mjs +0 -287
- package/lib/org/integration-tools.test.mjs +0 -160
- package/lib/org/keys.test.mjs +0 -92
- package/lib/org/knowledge.test.mjs +0 -326
- package/lib/org/leases.test.mjs +0 -235
- package/lib/org/mesh-directives.test.mjs +0 -110
- package/lib/org/mesh-integration.test.mjs +0 -127
- package/lib/org/mesh.test.mjs +0 -400
- package/lib/org/messaging.test.mjs +0 -471
- package/lib/org/param-contract.test.mjs +0 -477
- package/lib/org/policy.test.mjs +0 -237
- package/lib/org/protocol.checksum.test.mjs +0 -90
- package/lib/org/protocol.test.mjs +0 -323
- package/lib/org/push.test.mjs +0 -792
- package/lib/org/registry.test.mjs +0 -100
- package/lib/org/resource-tools.test.mjs +0 -361
- package/lib/org/tool-access.test.mjs +0 -144
- package/lib/org/tool-surface-integration.test.mjs +0 -120
- package/lib/org/tool-surface.test.mjs +0 -1268
- package/lib/org/typing.test.mjs +0 -291
- package/lib/org/ui-parity.test.mjs +0 -560
- package/lib/org/verify.test.mjs +0 -194
- package/lib/org/work-ledger.test.mjs +0 -273
- package/lib/plan/adoption-e2e.test.mjs +0 -366
- package/lib/plan/budget-enforcement.test.mjs +0 -400
- package/lib/plan/compile.test.mjs +0 -382
- package/lib/plan/emit.test.mjs +0 -269
- package/lib/plan/explain.test.mjs +0 -188
- package/lib/prompts/parallelism.test.mjs +0 -177
- package/lib/rag/rag.test.mjs +0 -505
- package/lib/rate-guard.test.mjs +0 -272
- package/lib/reactive-gate.test.mjs +0 -57
- package/lib/render.test.mjs +0 -68
- package/lib/resource-governor.test.mjs +0 -488
- package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
- package/lib/scheduling/jitter.test.mjs +0 -140
- package/lib/secrets/broker.test.mjs +0 -280
- package/lib/secrets/providers.test.mjs +0 -274
- package/lib/security/audit-engine.test.mjs +0 -424
- package/lib/security/coerce-args.test.mjs +0 -281
- package/lib/security/dangerous-tools.test.mjs +0 -68
- package/lib/security/external-content.test.mjs +0 -84
- package/lib/security/redact.test.mjs +0 -441
- package/lib/security/secret-equal.test.mjs +0 -55
- package/lib/session/config.test.mjs +0 -92
- package/lib/session/feed-core.test.mjs +0 -198
- package/lib/session/first-run.test.mjs +0 -121
- package/lib/session/frontdoor.test.mjs +0 -205
- package/lib/session/handoffs.test.mjs +0 -183
- package/lib/session/identity.test.mjs +0 -180
- package/lib/session/inbox-claims.test.mjs +0 -286
- package/lib/session/launch-args.test.mjs +0 -157
- package/lib/session/liveness.test.mjs +0 -100
- package/lib/session/status-summary.test.mjs +0 -118
- package/lib/session-permissions.test.mjs +0 -120
- package/lib/setup/claude-probe.test.mjs +0 -187
- package/lib/setup/completeness.test.mjs +0 -110
- package/lib/setup/context-pack.test.mjs +0 -89
- package/lib/setup/enrich.test.mjs +0 -115
- package/lib/setup/enroll-from-cohort.test.mjs +0 -300
- package/lib/setup/integration.test.mjs +0 -162
- package/lib/setup/io.test.mjs +0 -77
- package/lib/setup/runner.test.mjs +0 -132
- package/lib/setup/sections/identity.test.mjs +0 -234
- package/lib/setup/sections/inventory.test.mjs +0 -198
- package/lib/setup/sections/learning.test.mjs +0 -81
- package/lib/setup/sections/mandate.test.mjs +0 -388
- package/lib/setup/sections/messaging.test.mjs +0 -127
- package/lib/setup/sections/model.test.mjs +0 -240
- package/lib/setup/sections/org.test.mjs +0 -346
- package/lib/setup/sections/orgmail.test.mjs +0 -118
- package/lib/setup/sections/recovery.test.mjs +0 -98
- package/lib/setup/sections/subagents.test.mjs +0 -429
- package/lib/setup/sections/verify.test.mjs +0 -175
- package/lib/setup/sot.test.mjs +0 -81
- package/lib/setup/state.test.mjs +0 -115
- package/lib/singleton.test.mjs +0 -151
- package/lib/subagents/cli.test.mjs +0 -389
- package/lib/subagents/client.test.mjs +0 -309
- package/lib/subagents/gap.test.mjs +0 -234
- package/lib/subagents/lock.test.mjs +0 -248
- package/lib/subagents/manifest.test.mjs +0 -175
- package/lib/subagents/refs.test.mjs +0 -204
- package/lib/subagents/resolve.test.mjs +0 -422
- package/lib/subagents/schema.test.mjs +0 -328
- package/lib/telemetry/alerts.test.mjs +0 -109
- package/lib/telemetry/collect.test.mjs +0 -1274
- package/lib/tool-definitions-integration.test.mjs +0 -83
- package/lib/tool-definitions.test.mjs +0 -437
- package/lib/upgrade/global-refresh.test.mjs +0 -65
- package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
- package/lib/upgrade/post-steps.test.mjs +0 -200
- package/lib/upgrade/verify.test.mjs +0 -164
- package/lib/util/fetch-timeout.test.mjs +0 -202
- package/lib/util/reconnect.test.mjs +0 -369
- package/lib/util/unhandled.test.mjs +0 -216
- package/lib/voice/outbound.test.mjs +0 -69
- package/lib/voice/session-rotation.test.mjs +0 -114
- package/lib/voice/stt.test.mjs +0 -226
- package/lib/voice/voice.test.mjs +0 -990
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
- package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
- package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
- package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
- package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
- package/scripts/ci/check-skill-packs.test.mjs +0 -495
- package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
- package/scripts/ci/check.test.mjs +0 -194
- package/scripts/ci/conformance-org-api.test.mjs +0 -425
- package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
- package/scripts/collective/hook-runner.test.mjs +0 -173
- package/scripts/cost/fleet-digest.test.mjs +0 -207
- package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
- package/scripts/cost/track-claude-usage.test.mjs +0 -148
- package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
- package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
- package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
- package/scripts/daemon/agent-daemon.test.mjs +0 -995
- package/scripts/daemon/assurance-e2e.test.mjs +0 -613
- package/scripts/daemon/assurance.test.mjs +0 -1791
- package/scripts/daemon/board-mirror.test.mjs +0 -165
- package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
- package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
- package/scripts/daemon/cadence-consumer.test.mjs +0 -776
- package/scripts/daemon/cadence-handlers.test.mjs +0 -837
- package/scripts/daemon/classifier-identity.test.mjs +0 -137
- package/scripts/daemon/classifier.test.mjs +0 -266
- package/scripts/daemon/classify-kind.test.mjs +0 -40
- package/scripts/daemon/context-compiler.test.mjs +0 -406
- package/scripts/daemon/deliver.test.mjs +0 -564
- package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
- package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
- package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
- package/scripts/daemon/dispatcher-session-continuity.test.mjs +0 -365
- package/scripts/daemon/execution-ladder.test.mjs +0 -470
- package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
- package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
- package/scripts/daemon/inbox-deferral.test.mjs +0 -336
- package/scripts/daemon/inbox-wake.test.mjs +0 -199
- package/scripts/daemon/integration.test.mjs +0 -149
- package/scripts/daemon/lib/self-echo.test.mjs +0 -153
- package/scripts/daemon/lib/session-router.test.mjs +0 -554
- package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
- package/scripts/daemon/prompt-builder.test.mjs +0 -556
- package/scripts/daemon/responder-cost.test.mjs +0 -68
- package/scripts/daemon/responder-history.test.mjs +0 -221
- package/scripts/daemon/sdk-version.test.mjs +0 -31
- package/scripts/daemon/session-lock.test.mjs +0 -252
- package/scripts/daemon/session-outcomes.test.mjs +0 -533
- package/scripts/daemon/typing-registry.test.mjs +0 -102
- package/scripts/hooks/pre-send-audit.test.mjs +0 -354
- package/scripts/huddle/huddle-prompt.test.mjs +0 -176
- package/scripts/local-triggers/autoupdate.test.mjs +0 -518
- package/scripts/local-triggers/generate-plists.test.mjs +0 -456
- package/scripts/media-generation/brand-clause.test.mjs +0 -135
- package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
- package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
- package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
- package/scripts/poller/slack-socket-mode.test.mjs +0 -805
- package/scripts/poller-launchd/install.test.mjs +0 -243
- package/scripts/restore-from-backup.test.mjs +0 -181
- package/scripts/session/feed.test.mjs +0 -196
- package/scripts/session/supervisor-sh.test.mjs +0 -218
- package/scripts/session/supervisor.test.mjs +0 -482
- package/scripts/setup/configure-macos.test.mjs +0 -306
- package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
- package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
- package/scripts/setup/generate-capability.test.mjs +0 -134
- package/scripts/setup/init-agent.test.mjs +0 -370
- package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
- package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
- package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
|
@@ -31,6 +31,10 @@ a slower reply, never a dropped one.
|
|
|
31
31
|
counts open handoffs and board items from `state/org/board-mine.json`, the
|
|
32
32
|
daemon's five-minute cache — when that file is missing the count is 0 and
|
|
33
33
|
you run `maestro board mine` yourself.
|
|
34
|
+
`maestro session status` (and the `session_status` tool) also carries
|
|
35
|
+
`currentWork` — what is running, queued and blocked across your sessions on
|
|
36
|
+
this machine; a "what are you doing right now?" is answered from that, not
|
|
37
|
+
from memory.
|
|
34
38
|
|
|
35
39
|
3. Drain what is already waiting: `maestro inbox list --new`, then
|
|
36
40
|
`maestro session handoffs` — anything there arrived while you were down.
|
|
@@ -43,12 +47,14 @@ Each line is a JSON object with a `type`. Handle it in the turn it arrives.
|
|
|
43
47
|
|
|
44
48
|
- `inbound` — `{id, surface, topic, from, channelId, threadId, preview, path}`.
|
|
45
49
|
`maestro inbox show <id>` for the full item, then follow the
|
|
46
|
-
`inbound-triage` skill: reply now, or
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
`inbound-triage` skill: reply now, work it here, or spawn a peer. Saying
|
|
51
|
+
something BEFORE the answer is the exception, not the rule — see that skill's
|
|
52
|
+
one-interim rule. Claim it first (`maestro inbox claim <id>`) so the daemon's
|
|
53
|
+
sweep does not re-deliver it, reply with `maestro inbox reply <id> --text "…"`,
|
|
54
|
+
and close with `maestro inbox done <id>`. Those four commands ALSO write the
|
|
55
|
+
ask's board row — open, running, closed, channel tagged — so there is no
|
|
56
|
+
separate `board track` step to remember; the server's gate decides whether a
|
|
57
|
+
given ask earns a row at all. The reply command is the reply lane: it runs the
|
|
52
58
|
outbound gate — banned phrases, disclosure, barriers and the persona check —
|
|
53
59
|
in-process before anything is sent. In the agent directory the
|
|
54
60
|
`messaging_send` tool is blocked by the repo's own hook; do not try to route
|
|
@@ -62,7 +68,12 @@ Each line is a JSON object with a `type`. Handle it in the turn it arrives.
|
|
|
62
68
|
the old way, so ack promptly and never twice.
|
|
63
69
|
- `directive` — `restart`: finish the current turn, then `maestro session
|
|
64
70
|
restart` (the supervisor brings you back on the same session id).
|
|
65
|
-
`upgrade-available`: same, at the next idle moment. `daemon-
|
|
71
|
+
`upgrade-available`: same, at the next idle moment. `daemon-unhealthy`:
|
|
72
|
+
NOT a restart cue — the hourly autoupdate is reporting the daemon unhealthy
|
|
73
|
+
on the version already installed (`detail.notice.reason` says why: crash
|
|
74
|
+
loop, fatal line, or the org rejecting its beat); there is nothing to
|
|
75
|
+
restart onto, so keep your context, tell your principal and run `maestro
|
|
76
|
+
doctor`. `daemon-stale`: the
|
|
66
77
|
daemon has not beaten for 5 minutes; say so to your principal if it persists
|
|
67
78
|
past a second event, and keep working — the feed still delivers what is on
|
|
68
79
|
disk.
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* pack/install; cf. the broken `validate_outbound.py` cross-tenant link).
|
|
17
17
|
* 3. Requireability — the package main (exports["."], default lib/index.js)
|
|
18
18
|
* is present in the extracted tree, so a consumer's `import` resolves.
|
|
19
|
+
* 4. No tests or fixtures (CF-15) — `*.test.mjs`, `fixtures/`, `test-fixtures/`,
|
|
20
|
+
* `test/` and the replay examples are negated in files[] and must not ship;
|
|
21
|
+
* every relative import/require/`new URL(…, import.meta.url)` in the
|
|
22
|
+
* packaged JS that names a file in the source tree names a packaged file;
|
|
23
|
+
* and every exports[] module and lib/**\/index imports from the extracted
|
|
24
|
+
* tarball (with the source tree's node_modules linked in after the walk).
|
|
19
25
|
*
|
|
20
26
|
* This is a SLOW check (it shells out to `npm pack` and `tar`), so it is wired
|
|
21
27
|
* as its own opt-in npm script (`npm run test:pack`) and is NOT part of the
|
|
@@ -37,6 +43,7 @@ import {
|
|
|
37
43
|
readdirSync,
|
|
38
44
|
lstatSync,
|
|
39
45
|
existsSync,
|
|
46
|
+
symlinkSync,
|
|
40
47
|
} from "node:fs";
|
|
41
48
|
import { tmpdir } from "node:os";
|
|
42
49
|
import path from "node:path";
|
|
@@ -50,8 +57,98 @@ export const FORBIDDEN_PATTERNS = [
|
|
|
50
57
|
{ label: "python bytecode (*.pyc)", re: /\.pyc$/ },
|
|
51
58
|
{ label: "python bytecode (*.pyo)", re: /\.pyo$/ },
|
|
52
59
|
{ label: "bytecode cache dir (__pycache__)", re: /(^|\/)__pycache__(\/|$)/ },
|
|
60
|
+
// CF-15 (W5): tests and their fixtures are not runtime; package.json files[] negates them.
|
|
61
|
+
{ label: "test file (*.test.mjs / *.test.js)", re: /\.test\.(mjs|js|cjs)$/ },
|
|
62
|
+
{ label: "test fixture directory", re: /(^|\/)(fixtures|test-fixtures|__fixtures__)\// },
|
|
63
|
+
{ label: "test directory (test/)", re: /^test\// },
|
|
64
|
+
{ label: "eval example fixtures", re: /^scripts\/eval\/replay\/examples\// },
|
|
53
65
|
];
|
|
54
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Relative module and file references in a JS source: static `import`/`export … from`,
|
|
69
|
+
* literal `import("…")` and `require("…")`, and `new URL("…", import.meta.url)` naming a
|
|
70
|
+
* file (with an extension). Pure.
|
|
71
|
+
* @param {string} source
|
|
72
|
+
* @returns {string[]} the relative specifiers, as written
|
|
73
|
+
*/
|
|
74
|
+
export function relativeReferences(source) {
|
|
75
|
+
const out = new Set();
|
|
76
|
+
const patterns = [
|
|
77
|
+
/\b(?:import|export)\s[^'"`;]*?\bfrom\s*["'](\.{1,2}\/[^"']+)["']/g,
|
|
78
|
+
/\bimport\s*["'](\.{1,2}\/[^"']+)["']/g,
|
|
79
|
+
/\bimport\(\s*["'](\.{1,2}\/[^"']+)["']\s*\)/g,
|
|
80
|
+
/\brequire\(\s*["'](\.{1,2}\/[^"']+)["']\s*\)/g,
|
|
81
|
+
/\bnew URL\(\s*["'](\.{1,2}\/[^"']*\.[A-Za-z0-9]+)["']\s*,\s*import\.meta\.url\s*\)/g,
|
|
82
|
+
];
|
|
83
|
+
for (const re of patterns) for (const m of source.matchAll(re)) out.add(m[1]);
|
|
84
|
+
return [...out];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Every relative reference in the packaged JS that resolves to a file present in
|
|
89
|
+
* the source tree but absent from the tarball — a runtime path the packaging
|
|
90
|
+
* cut off. References that do not resolve in the source tree either (optional,
|
|
91
|
+
* generated or seat-local files) are not a packaging fault and are not reported.
|
|
92
|
+
* Comment lines are skipped. Pure over its inputs.
|
|
93
|
+
* @param {{files:string[], read:(rel:string)=>string, existsInSource:(rel:string)=>boolean}} p
|
|
94
|
+
* @returns {Array<{file:string, ref:string, target:string}>}
|
|
95
|
+
*/
|
|
96
|
+
export function brokenPackagedReferences({ files, read, existsInSource }) {
|
|
97
|
+
const shipped = new Set(files);
|
|
98
|
+
const broken = [];
|
|
99
|
+
for (const file of files) {
|
|
100
|
+
if (!/\.(mjs|js|cjs)$/.test(file)) continue;
|
|
101
|
+
const source = read(file)
|
|
102
|
+
.split("\n")
|
|
103
|
+
.filter((l) => !/^\s*(\/\/|\*|\/\*)/.test(l))
|
|
104
|
+
.join("\n");
|
|
105
|
+
for (const ref of relativeReferences(source)) {
|
|
106
|
+
const target = path.posix.normalize(path.posix.join(path.posix.dirname(file), ref));
|
|
107
|
+
if (shipped.has(target) || !existsInSource(target)) continue;
|
|
108
|
+
broken.push({ file, ref, target });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return broken;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The modules a consumer (or the CLI) imports by name: every exports[] target
|
|
116
|
+
* that is JavaScript, and every lib/**\/index.(mjs|js). Pure.
|
|
117
|
+
* @param {object} pkg @param {string[]} files
|
|
118
|
+
*/
|
|
119
|
+
export function smokeImportTargets(pkg, files) {
|
|
120
|
+
const fromExports = Object.values((pkg && pkg.exports) || {})
|
|
121
|
+
.map((v) => (typeof v === "string" ? v : v && (v.import || v.default)))
|
|
122
|
+
.filter((v) => typeof v === "string" && /\.(mjs|js)$/.test(v))
|
|
123
|
+
.map((v) => v.replace(/^\.\//, ""));
|
|
124
|
+
const indexes = files.filter((f) => /^lib\/(.+\/)?index\.(mjs|js)$/.test(f));
|
|
125
|
+
return [...new Set([...fromExports, ...indexes])].sort();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Import each module in a child node process run in `root`; returns the ones that
|
|
130
|
+
* failed, with the first line of the error. Bounded by `timeoutMs`.
|
|
131
|
+
* @param {string} root @param {string[]} modules @param {number} [timeoutMs]
|
|
132
|
+
* @returns {Array<{module:string, error:string}>}
|
|
133
|
+
*/
|
|
134
|
+
export function smokeImport(root, modules, timeoutMs = 180_000) {
|
|
135
|
+
const script = [
|
|
136
|
+
"const mods = JSON.parse(process.argv[1]);",
|
|
137
|
+
"const failed = [];",
|
|
138
|
+
"for (const m of mods) { try { await import(new URL(m, 'file://' + process.cwd() + '/').href); } catch (e) { failed.push({ module: m, error: String((e && e.message) || e).split('\\n')[0] }); } }",
|
|
139
|
+
"process.stdout.write(JSON.stringify(failed));",
|
|
140
|
+
"process.exit(0);",
|
|
141
|
+
].join("\n");
|
|
142
|
+
const env = { PATH: process.env.PATH || "/usr/bin:/bin", HOME: mkdtempSync(path.join(tmpdir(), "maestro-pack-home-")), NODE_ENV: "production" };
|
|
143
|
+
try {
|
|
144
|
+
const out = execFileSync(process.execPath, ["--input-type=module", "-e", script, JSON.stringify(modules)], { cwd: root, env, encoding: "utf8", timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
|
|
145
|
+
const last = out.trim().split("\n").pop() || "[]";
|
|
146
|
+
return JSON.parse(last);
|
|
147
|
+
} finally {
|
|
148
|
+
try { rmSync(env.HOME, { recursive: true, force: true }); } catch { /* */ }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
55
152
|
/**
|
|
56
153
|
* The "main" file a consumer's bare `import "@cohortapp/agent-sdk"` resolves to.
|
|
57
154
|
* Falls back to lib/index.js (the documented default) when exports["."] is odd.
|
|
@@ -146,9 +243,11 @@ export function checkTarball(opts = {}) {
|
|
|
146
243
|
|
|
147
244
|
// 4) Completeness — every files[] entry must be represented. A directory
|
|
148
245
|
// entry (e.g. "lib/") is satisfied by any packaged path beneath it; a
|
|
149
|
-
// file entry must appear verbatim.
|
|
246
|
+
// file entry must appear verbatim. A negation ("!**/*.test.mjs") removes
|
|
247
|
+
// paths rather than declaring them (CF-15), so it has nothing to find.
|
|
150
248
|
const missing = [];
|
|
151
249
|
for (const decl of filesAllowlist) {
|
|
250
|
+
if (typeof decl !== "string" || decl.startsWith("!")) continue;
|
|
152
251
|
const norm = decl.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
153
252
|
const asDirPrefix = norm + "/";
|
|
154
253
|
const present = filePaths.some(
|
|
@@ -162,12 +261,37 @@ export function checkTarball(opts = {}) {
|
|
|
162
261
|
missing.push(`${mainEntry} (package main / exports["."])`);
|
|
163
262
|
}
|
|
164
263
|
|
|
264
|
+
// 6) CF-15: no packaged module points at a file the packaging left out.
|
|
265
|
+
const broken = brokenPackagedReferences({
|
|
266
|
+
files: filePaths,
|
|
267
|
+
read: (rel) => readFileSync(path.join(pkgRoot, rel), "utf8"),
|
|
268
|
+
existsInSource: (rel) => existsSync(path.join(cwd, rel)),
|
|
269
|
+
});
|
|
270
|
+
for (const b of broken) missing.push(`${b.target} (referenced as "${b.ref}" by ${b.file}, excluded from the tarball)`);
|
|
271
|
+
|
|
272
|
+
// 7) CF-15: every exported entry and lib/**/index imports from the extracted
|
|
273
|
+
// tarball (dependencies from the source tree's node_modules). A module that
|
|
274
|
+
// also fails from the source tree is not a packaging fault.
|
|
275
|
+
let smoked = 0;
|
|
276
|
+
if (opts.smoke !== false) {
|
|
277
|
+
const targets = smokeImportTargets(pkg, filePaths);
|
|
278
|
+
const sourceModules = path.join(cwd, "node_modules");
|
|
279
|
+
if (existsSync(sourceModules)) symlinkSync(sourceModules, path.join(pkgRoot, "node_modules"), "dir");
|
|
280
|
+
const failedPacked = smokeImport(pkgRoot, targets);
|
|
281
|
+
const failedSource = failedPacked.length > 0 ? new Set(smokeImport(cwd, failedPacked.map((f) => f.module)).map((f) => f.module)) : new Set();
|
|
282
|
+
for (const f of failedPacked) {
|
|
283
|
+
if (!failedSource.has(f.module)) missing.push(`${f.module} (does not import from the tarball: ${f.error})`);
|
|
284
|
+
}
|
|
285
|
+
smoked = targets.length;
|
|
286
|
+
}
|
|
287
|
+
|
|
165
288
|
return {
|
|
166
289
|
ok: offenders.length === 0 && missing.length === 0,
|
|
167
290
|
offenders,
|
|
168
291
|
missing,
|
|
169
292
|
tarballFiles: filePaths.length,
|
|
170
293
|
mainEntry,
|
|
294
|
+
smoked,
|
|
171
295
|
};
|
|
172
296
|
} finally {
|
|
173
297
|
try { rmSync(work, { recursive: true, force: true }); } catch { /* */ }
|
|
@@ -184,7 +308,7 @@ export async function run(cwd = REPO_ROOT) {
|
|
|
184
308
|
return 2;
|
|
185
309
|
}
|
|
186
310
|
if (res.ok) {
|
|
187
|
-
console.log(`check-tarball-fidelity: OK (${res.tarballFiles} files; main "${res.mainEntry}" present; no node_modules/.pyc/symlinks)`);
|
|
311
|
+
console.log(`check-tarball-fidelity: OK (${res.tarballFiles} files; main "${res.mainEntry}" present; no node_modules/.pyc/symlinks/tests/fixtures; every relative reference resolves; ${res.smoked} entry modules import from the tarball)`);
|
|
188
312
|
return 0;
|
|
189
313
|
}
|
|
190
314
|
if (res.missing.length) {
|
package/scripts/ci/run-tests.mjs
CHANGED
|
@@ -10,24 +10,31 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Node builtins only (maestro is "type":"module", near-zero-dep by design).
|
|
12
12
|
*
|
|
13
|
-
* Usage: `node scripts/ci/run-tests.mjs`
|
|
13
|
+
* Usage: `node scripts/ci/run-tests.mjs [--list]`
|
|
14
14
|
* exit 0 → all tests passed; non-zero → at least one failed (or none found).
|
|
15
|
+
* `--list` prints the discovered files and runs nothing. It exists so that
|
|
16
|
+
* "what does the suite cover?" has ONE answer. `package.json` used to answer
|
|
17
|
+
* it a second time with a hand-enumerated `test:list`, which had drifted to
|
|
18
|
+
* 46 of 82 files by the time an audit caught it (L25) and was still missing
|
|
19
|
+
* newly added suites afterwards — a second source of truth about coverage
|
|
20
|
+
* that lies is worse than none, because it reads like an inventory.
|
|
15
21
|
*
|
|
16
22
|
* @module scripts/ci/run-tests
|
|
17
23
|
*/
|
|
18
24
|
|
|
19
25
|
import { readdirSync } from "node:fs";
|
|
20
|
-
import { join, dirname } from "node:path";
|
|
26
|
+
import { join, dirname, relative, resolve } from "node:path";
|
|
21
27
|
import { fileURLToPath } from "node:url";
|
|
22
28
|
import { spawnSync } from "node:child_process";
|
|
23
29
|
|
|
24
30
|
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
25
|
-
const ROOTS = ["lib", "scripts", "bin", "services"];
|
|
31
|
+
const ROOTS = ["lib", "scripts", "bin", "services", "test"];
|
|
26
32
|
const SKIP_DIRS = new Set(["node_modules", ".git", "state", "logs", "audit"]);
|
|
27
33
|
|
|
28
34
|
/**
|
|
29
|
-
* Recursively collect `*.test.mjs` files under `dir
|
|
30
|
-
* paths
|
|
35
|
+
* Recursively collect `*.test.mjs` files under `dir`, returning ABSOLUTE
|
|
36
|
+
* paths — `node --test` is spawned with cwd REPO_ROOT, but absolute paths
|
|
37
|
+
* survive a caller that is not. `--list` relativises them for readability.
|
|
31
38
|
* @param {string} dir
|
|
32
39
|
* @returns {string[]}
|
|
33
40
|
*/
|
|
@@ -50,22 +57,43 @@ function findTests(dir) {
|
|
|
50
57
|
return out;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Every test file the suite runs, repo-relative and sorted. The single source
|
|
62
|
+
* of truth about what `npm test` covers.
|
|
63
|
+
* @returns {string[]}
|
|
64
|
+
*/
|
|
65
|
+
export function discoverTests() {
|
|
66
|
+
return ROOTS.flatMap((r) => findTests(join(REPO_ROOT, r))).sort();
|
|
58
67
|
}
|
|
59
68
|
|
|
60
|
-
|
|
69
|
+
function main(argv) {
|
|
70
|
+
const files = discoverTests();
|
|
71
|
+
|
|
72
|
+
if (files.length === 0) {
|
|
73
|
+
console.error("run-tests: no *.test.mjs files found — refusing to report success.");
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (argv.includes("--list")) {
|
|
78
|
+
for (const f of files) console.log(relative(REPO_ROOT, f));
|
|
79
|
+
console.error(`run-tests: ${files.length} test file(s) discovered (nothing was run).`);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log(`run-tests: discovered ${files.length} test file(s).`);
|
|
61
84
|
|
|
62
|
-
const result = spawnSync(process.execPath, ["--test", ...files], {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
85
|
+
const result = spawnSync(process.execPath, ["--test", ...files], {
|
|
86
|
+
cwd: REPO_ROOT,
|
|
87
|
+
stdio: "inherit",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (result.error) {
|
|
91
|
+
console.error("run-tests: failed to launch node --test:", result.error.message);
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
return result.status ?? 1;
|
|
95
|
+
}
|
|
66
96
|
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
process.exit(1);
|
|
97
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
98
|
+
process.exit(main(process.argv.slice(2)));
|
|
70
99
|
}
|
|
71
|
-
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/cohort-llm/api-key-helper.mjs — Claude Code `apiKeyHelper` for a
|
|
4
|
+
* seat retargeted to cohort-llm (the internal "Path B" testbed, design C1).
|
|
5
|
+
*
|
|
6
|
+
* Claude Code runs this in /bin/sh and sends stdout as the request credential
|
|
7
|
+
* (public docs, code.claude.com/docs/en/iam: `apiKeyHelper` ranks below
|
|
8
|
+
* ANTHROPIC_AUTH_TOKEN, so a cohort retarget carries NO auth token and lets this
|
|
9
|
+
* helper supply — and, every CLAUDE_CODE_API_KEY_HELPER_TTL_MS, refresh — the
|
|
10
|
+
* seat token for the whole life of a long session).
|
|
11
|
+
*
|
|
12
|
+
* node scripts/cohort-llm/api-key-helper.mjs [--agent-root <dir>]
|
|
13
|
+
*
|
|
14
|
+
* stdout: exactly one fresh `cst_…` token and a newline. Nothing else ever goes
|
|
15
|
+
* to stdout — anything printed there would be sent as the credential.
|
|
16
|
+
* failure: exit 1 with one line on stderr naming the typed error. The token and
|
|
17
|
+
* the seat's key never appear on stderr.
|
|
18
|
+
*
|
|
19
|
+
* Key resolution: the cached token (state/cohort-llm/token.json) when it is
|
|
20
|
+
* before its refresh point; otherwise the seat's OrgApiKey from config/org.yaml,
|
|
21
|
+
* the environment, or the agent's .env (a retarget child's env is scrubbed of
|
|
22
|
+
* credentials, so the .env is the usual source here).
|
|
23
|
+
*
|
|
24
|
+
* @module scripts/cohort-llm/api-key-helper
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { resolve } from "node:path";
|
|
28
|
+
import { realpathSync } from "node:fs";
|
|
29
|
+
import { pathToFileURL } from "node:url";
|
|
30
|
+
|
|
31
|
+
import { seatTokenManager, redactSecrets, REJECTED_TOKEN_FP_ENV } from "../../lib/org/llm-token.mjs";
|
|
32
|
+
|
|
33
|
+
/** @param {string[]} argv */
|
|
34
|
+
export function parseHelperArgs(argv) {
|
|
35
|
+
const out = { agentRoot: null };
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const a = argv[i];
|
|
38
|
+
if (a === "--agent-root") out.agentRoot = argv[++i] || null;
|
|
39
|
+
else if (a.startsWith("--agent-root=")) out.agentRoot = a.slice("--agent-root=".length) || null;
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {object} [deps]
|
|
46
|
+
* @param {string[]} [deps.argv]
|
|
47
|
+
* @param {object} [deps.env]
|
|
48
|
+
* @param {{write:(s:string)=>unknown}} [deps.stdout]
|
|
49
|
+
* @param {{write:(s:string)=>unknown}} [deps.stderr]
|
|
50
|
+
* @param {typeof fetch} [deps.fetchImpl]
|
|
51
|
+
* @param {() => number} [deps.now]
|
|
52
|
+
* @param {object} [deps.cfg]
|
|
53
|
+
* @returns {Promise<number>} exit code
|
|
54
|
+
*/
|
|
55
|
+
export async function main(deps = {}) {
|
|
56
|
+
const env = deps.env || process.env;
|
|
57
|
+
const stdout = deps.stdout || process.stdout;
|
|
58
|
+
const stderr = deps.stderr || process.stderr;
|
|
59
|
+
const args = parseHelperArgs(deps.argv || process.argv.slice(2));
|
|
60
|
+
const agentRoot = resolve(args.agentRoot || env.AGENT_ROOT || env.AGENT_DIR || process.cwd());
|
|
61
|
+
try {
|
|
62
|
+
const manager = seatTokenManager({ agentRoot, env, cfg: deps.cfg, readDotEnv: true, fetchImpl: deps.fetchImpl, now: deps.now });
|
|
63
|
+
// The engine re-runs this helper after a 401 and names the refused token by
|
|
64
|
+
// fingerprint: the manager serves a replacement if one exists, else re-mints
|
|
65
|
+
// under its per-window cap. A plain run (TTL refresh) never forces a mint.
|
|
66
|
+
const rejectedFp = typeof env[REJECTED_TOKEN_FP_ENV] === "string" ? env[REJECTED_TOKEN_FP_ENV].trim() : "";
|
|
67
|
+
const r = await manager.getToken(rejectedFp ? { rejectedFp } : {});
|
|
68
|
+
if (r.ok && typeof r.token === "string" && r.token) {
|
|
69
|
+
stdout.write(`${r.token}\n`);
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
const e = (r && r.error) || { code: "cohort_unavailable", message: "no token" };
|
|
73
|
+
stderr.write(`cohort-llm api-key-helper: ${e.code}: ${redactSecrets(e.message)}\n`);
|
|
74
|
+
return 1;
|
|
75
|
+
} catch (err) {
|
|
76
|
+
stderr.write(`cohort-llm api-key-helper: cohort_unavailable: ${redactSecrets(err && err.message ? err.message : err)}\n`);
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isEntrypoint() {
|
|
82
|
+
if (!process.argv[1]) return false;
|
|
83
|
+
try {
|
|
84
|
+
return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isEntrypoint()) {
|
|
91
|
+
process.exitCode = await main();
|
|
92
|
+
}
|
|
@@ -77,7 +77,7 @@ async function main() {
|
|
|
77
77
|
|
|
78
78
|
if (event === "prime") {
|
|
79
79
|
const kind = classifyKind(input);
|
|
80
|
-
try { presence.register(SELF_ROOT, { sessionId, cwd, repo, kind }); } catch { /* */ }
|
|
80
|
+
try { presence.register(SELF_ROOT, { sessionId, cwd, repo, kind, ...ownerFields(presence) }); } catch { /* */ }
|
|
81
81
|
if (denied) return; // never inject agent memory (or the persona) into a ring-fenced/client session
|
|
82
82
|
const parts = [];
|
|
83
83
|
try {
|
|
@@ -111,7 +111,15 @@ async function main() {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
if (event === "beat") {
|
|
114
|
-
|
|
114
|
+
// A beat on a session with no record re-registers it: a session that was
|
|
115
|
+
// running before this hook learned to record its OWNER pid (see
|
|
116
|
+
// ownerFields) was reaped on every read, and would otherwise stay
|
|
117
|
+
// invisible until it restarts.
|
|
118
|
+
let beaten = false;
|
|
119
|
+
try { beaten = presence.heartbeat(SELF_ROOT, sessionId); } catch { beaten = false; }
|
|
120
|
+
if (!beaten) {
|
|
121
|
+
try { presence.register(SELF_ROOT, { sessionId, cwd, repo, kind: classifyKind(input), ...ownerFields(presence) }); } catch { /* */ }
|
|
122
|
+
}
|
|
115
123
|
// WS3: nudge the self-learning loop's tool-use counter. Cheap, fail-open,
|
|
116
124
|
// and only when the layer is enabled + the repo isn't denylisted.
|
|
117
125
|
if (!denied) {
|
|
@@ -151,6 +159,25 @@ function buildFrontDoorPrimer(agentRoot) {
|
|
|
151
159
|
mod.buildPrimerContext({ agentJson, agentRoot, status: mod.readSessionStatus(agentRoot, { now: Date.now() }) }));
|
|
152
160
|
}
|
|
153
161
|
|
|
162
|
+
/**
|
|
163
|
+
* The pid, `--name` and process start of the session that RAN this hook.
|
|
164
|
+
* Without this the record carried the hook's own pid, which is dead by the
|
|
165
|
+
* time anyone reads it, so `list()` reaped every interactive session on its
|
|
166
|
+
* first read (see lib/collective/presence.mjs `owningSession`). `pid: null`
|
|
167
|
+
* when the walk finds nothing — liveness then rests on the heartbeat. The
|
|
168
|
+
* start time is the owner's `ps etime`, so a session re-registered by a late
|
|
169
|
+
* beat still says when it OPENED, not when the beat happened.
|
|
170
|
+
*/
|
|
171
|
+
function ownerFields(presence) {
|
|
172
|
+
try {
|
|
173
|
+
if (typeof presence.resolveOwner !== "function") return {};
|
|
174
|
+
const o = presence.resolveOwner();
|
|
175
|
+
return { pid: o.pid, agentName: o.name || "", ...(o.startedAt ? { startedAt: o.startedAt } : {}) };
|
|
176
|
+
} catch {
|
|
177
|
+
return {};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
154
181
|
function classifyKind(input) {
|
|
155
182
|
const src = String(input.source || "").toLowerCase();
|
|
156
183
|
if (src.includes("daemon") || process.env.MAESTRO_DAEMON === "1") return "daemon";
|
|
@@ -9,6 +9,19 @@ set -e
|
|
|
9
9
|
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
AGENT_REPO_DIR="${AGENT_DIR:-$(dirname "$SCRIPT_DIR")}"
|
|
12
|
+
|
|
13
|
+
# Retired on engine-cohort seats (W4-E1): this lane runs claude outside the
|
|
14
|
+
# runtime adapter. The guard exits 3 with the reason when runtime.engine is cohort.
|
|
15
|
+
# Fail closed: when the guard cannot run (no node on PATH — launchd's
|
|
16
|
+
# /usr/bin:/bin — or the guard file is missing), config/agent.json is checked
|
|
17
|
+
# here and an engine-cohort seat is refused all the same.
|
|
18
|
+
LEGACY_GUARD="$(dirname "$SCRIPT_DIR")/lib/runtime/legacy-shell-guard.mjs"
|
|
19
|
+
if [ -f "$LEGACY_GUARD" ] && command -v node >/dev/null 2>&1; then
|
|
20
|
+
node "$LEGACY_GUARD" continuous-monitor.sh "$AGENT_REPO_DIR" || exit $?
|
|
21
|
+
elif [ -f "$AGENT_REPO_DIR/config/agent.json" ] && grep -Eq '"engine"[[:space:]]*:[[:space:]]*"cohort"' "$AGENT_REPO_DIR/config/agent.json"; then
|
|
22
|
+
echo "continuous-monitor.sh is retired on this seat: runtime.engine is \"cohort\", and this legacy lane runs the claude binary directly, outside the runtime adapter (the engine guard could not run: node or $LEGACY_GUARD is unavailable)." >&2
|
|
23
|
+
exit 3
|
|
24
|
+
fi
|
|
12
25
|
# Load agent identity for the LLM prompt
|
|
13
26
|
if [ -f "$AGENT_REPO_DIR/config/agent.env" ]; then
|
|
14
27
|
# shellcheck disable=SC1091
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
* That writes measurement:"unknown" with NULL tokens. It must never write
|
|
23
23
|
* zeros — see "MEASURED, UNKNOWN, N/A" below.
|
|
24
24
|
*
|
|
25
|
+
* A session cohort-llm served (engine cohort, or claude retargeted to the
|
|
26
|
+
* cohort provider) is already metered by the gateway; mark it so org
|
|
27
|
+
* cost-sync does not report it a second time:
|
|
28
|
+
*
|
|
29
|
+
* node scripts/cost/track-claude-usage.mjs record ... \
|
|
30
|
+
* --billed-by cohort-llm --request-ids req_1,req_2
|
|
31
|
+
*
|
|
25
32
|
* 2. `summarise` — Rollup the last N days into state/dashboards/cost-summary.yaml.
|
|
26
33
|
* Called daily (cadence: nightly-cost-rollup) and on demand.
|
|
27
34
|
*
|
|
@@ -266,6 +273,14 @@ function recordCmd(flags) {
|
|
|
266
273
|
};
|
|
267
274
|
if (unmeasuredReason) row.unmeasured_reason = unmeasuredReason;
|
|
268
275
|
if (flags["decision-id"]) row.decision_id = String(flags["decision-id"]);
|
|
276
|
+
// Who metered this session. "cohort-llm": the gateway billed it; the row is
|
|
277
|
+
// kept for the seat's own view and reconciliation, and skipped by org
|
|
278
|
+
// cost-sync (lib/org/cost-sync.mjs) so it is never counted twice.
|
|
279
|
+
if (flags["billed-by"] && flags["billed-by"] !== "true") row.billed_by = String(flags["billed-by"]);
|
|
280
|
+
if (flags["request-ids"] && flags["request-ids"] !== "true") {
|
|
281
|
+
const ids = String(flags["request-ids"]).split(",").map((x) => x.trim()).filter(Boolean);
|
|
282
|
+
if (ids.length) row.gateway_request_ids = ids;
|
|
283
|
+
}
|
|
269
284
|
|
|
270
285
|
if (measurement === "measured") {
|
|
271
286
|
// Cache tokens are billed at their own rates (read 0.1x, write 1.25x) and
|