@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
package/.claude/settings.json
CHANGED
|
@@ -122,6 +122,15 @@
|
|
|
122
122
|
"command": "./scripts/hooks/block-mcp-cohort-send.sh"
|
|
123
123
|
}
|
|
124
124
|
]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"matcher": "Write|Edit",
|
|
128
|
+
"hooks": [
|
|
129
|
+
{
|
|
130
|
+
"type": "command",
|
|
131
|
+
"command": "node ./scripts/hooks/pre-write-yaml-validate.mjs"
|
|
132
|
+
}
|
|
133
|
+
]
|
|
125
134
|
}
|
|
126
135
|
],
|
|
127
136
|
"PostToolUse": [
|
|
@@ -133,6 +142,15 @@
|
|
|
133
142
|
"command": "./scripts/hooks/post-action-log.sh"
|
|
134
143
|
}
|
|
135
144
|
]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"matcher": "Bash|Write|Edit",
|
|
148
|
+
"hooks": [
|
|
149
|
+
{
|
|
150
|
+
"type": "command",
|
|
151
|
+
"command": "./scripts/hooks/validate-state-yaml.sh"
|
|
152
|
+
}
|
|
153
|
+
]
|
|
136
154
|
}
|
|
137
155
|
],
|
|
138
156
|
"Stop": [
|
package/.env.example
CHANGED
|
@@ -63,7 +63,7 @@ COHORT_AGENT_EMAIL=
|
|
|
63
63
|
# is in effect and what `claude auth status` reports (presence of a credential,
|
|
64
64
|
# not its validity — a bad token surfaces on the first real spawn).
|
|
65
65
|
#
|
|
66
|
-
# Option A — subscription OAuth token
|
|
66
|
+
# Option A — subscription OAuth token (NOT the fleet posture — see Option C)
|
|
67
67
|
# On ANY machine where you are logged in to Claude Code, run
|
|
68
68
|
# claude setup-token
|
|
69
69
|
# and paste the long-lived token below, together with
|
|
@@ -72,25 +72,38 @@ COHORT_AGENT_EMAIL=
|
|
|
72
72
|
# keychain login is NOT relied on because it expires headlessly. The token is
|
|
73
73
|
# per seat; mint a fresh one with the same command when it is rejected.
|
|
74
74
|
# Headless setup reads it from the environment: CLAUDE_CODE_OAUTH_TOKEN=… maestro setup --headless
|
|
75
|
+
# It still RUNS, but it has no per-agent ceiling and no central spend
|
|
76
|
+
# visibility: do NOT provision a new agent seat on it (gate G4).
|
|
75
77
|
CLAUDE_CODE_OAUTH_TOKEN=
|
|
76
78
|
|
|
77
79
|
# Option B — keychain login on this machine (interactive / dev boxes only)
|
|
78
80
|
# `claude login` here, leave CLAUDE_CODE_OAUTH_TOKEN and ANTHROPIC_API_KEY
|
|
79
81
|
# empty, set MAESTRO_PREFER_SUBSCRIPTION_AUTH=1. Doctor warns: the login
|
|
80
|
-
# expires headlessly and
|
|
82
|
+
# expires headlessly and an agent seat belongs on Option C.
|
|
81
83
|
#
|
|
82
84
|
# Set to 1 for Option A and Option B: every claude spawn strips
|
|
83
85
|
# ANTHROPIC_API_KEY from its env so claude rides the subscription (token or
|
|
84
86
|
# keychain) — routine cadence ticks then cost zero API credits.
|
|
85
87
|
MAESTRO_PREFER_SUBSCRIPTION_AUTH=
|
|
86
88
|
|
|
87
|
-
# Option C — API key (pay-per-token)
|
|
88
|
-
# Set ANTHROPIC_API_KEY to a valid sk-ant-api03-... key
|
|
89
|
-
#
|
|
89
|
+
# Option C — API key (pay-per-token) ← THE FLEET POSTURE (agent seats)
|
|
90
|
+
# Set ANTHROPIC_API_KEY to a valid sk-ant-api03-... key created INSIDE a
|
|
91
|
+
# Console workspace with a monthly spend cap, one workspace per agent, and
|
|
92
|
+
# leave the two above empty. Get one:
|
|
93
|
+
# https://console.anthropic.com/settings/keys
|
|
90
94
|
# Doctor validates it against api.anthropic.com on every run; an invalid
|
|
91
95
|
# key cascades 401s through every sub-session spawn.
|
|
96
|
+
# Runbook: docs/guides/billing-console-keys.md
|
|
92
97
|
ANTHROPIC_API_KEY=
|
|
93
98
|
|
|
99
|
+
# OPTIONAL — Arm the G4 guard. `maestro doctor` and `maestro seat-auth` WARN on
|
|
100
|
+
# a seat still using subscription OAuth (and on a seat carrying both rails,
|
|
101
|
+
# which is ambiguous about where its spend lands). Set this to 1 and those
|
|
102
|
+
# warnings become failures — do that once the fleet has migrated, so a seat that
|
|
103
|
+
# regresses to a subscription token announces itself. Never fails an
|
|
104
|
+
# engine=cohort seat that holds no Anthropic credential: that is its posture.
|
|
105
|
+
MAESTRO_REQUIRE_CONSOLE_KEY=
|
|
106
|
+
|
|
94
107
|
# OPTIONAL — Supplemental model access (GPT-4, embeddings)
|
|
95
108
|
# Get your key: https://platform.openai.com/api-keys
|
|
96
109
|
# Subscription: OpenAI API plan (pay-per-token)
|
package/README.md
CHANGED
|
@@ -161,6 +161,7 @@ Verifies the agent installation end-to-end. Checks include:
|
|
|
161
161
|
- **Config:** `config/environment.yaml`, `config/contacts.yaml`, `config/priorities.yaml`, `config/sla-defaults.yaml`.
|
|
162
162
|
- **State:** `state/dashboards/executive-summary.yaml`, `state/queues/action-stack.yaml`, `knowledge/decisions/decision-schema.yaml`.
|
|
163
163
|
- **Environment:** `.env` file with `ANTHROPIC_API_KEY` (required), `SLACK_USER_TOKEN`, `GMAIL_APP_PASSWORD` (optional).
|
|
164
|
+
- **Billing rail (G4):** which Claude rail this seat is on — `api-key` (the fleet posture: a per-agent Console key in a capped workspace), `subscription`, `both` (ambiguous, flagged loudly) or `neither`. Variable **names** only; no credential value is ever printed. A warning today; `MAESTRO_REQUIRE_CONSOLE_KEY=1` turns it into a failure once the fleet has migrated. `maestro seat-auth --row` prints the paste-able inventory row and `maestro seat-auth --fleet` the template it pastes into — see [billing: Console API keys](docs/guides/billing-console-keys.md).
|
|
164
165
|
- **Dependencies:** `node_modules` installed, Claude CLI available, jq available, emergency-stop script present.
|
|
165
166
|
|
|
166
167
|
Doctor exits non-zero when issues are found and prints actionable remediation (most commonly: `npx @cohortapp/agent-sdk upgrade`). Doctor also verifies the collective-memory wiring (see below).
|
package/bin/maestro.mjs
CHANGED
|
@@ -37,6 +37,7 @@ import { runAudit, applyFixes, buildAttestation } from "../lib/security/audit-en
|
|
|
37
37
|
import { selectProvider } from "../lib/secrets/providers.mjs";
|
|
38
38
|
import { syncSecrets, rotateSecret, makeBroker, auditLogPath } from "../lib/secrets/broker.mjs";
|
|
39
39
|
import { applyBrandEnvCompat } from "../lib/env-compat.mjs";
|
|
40
|
+
import { buildIgnoredDriftReport, formatIgnoredLine, IGNORED_DRIFT_REL } from "../lib/upgrade/ignored-drift.mjs";
|
|
40
41
|
|
|
41
42
|
// Fleet back-compat FIRST: bridge NEOLITH_* ⇄ COHORT_* env names before any
|
|
42
43
|
// env-first resolution below — installed hosts still export the legacy names.
|
|
@@ -1249,6 +1250,8 @@ Per-file behaviour:
|
|
|
1249
1250
|
const counts = { added: 0, updated: 0, same: 0, ignored: 0, preserved: 0, mergeKept: 0, forced: 0, pruned: 0, pruneKept: 0 };
|
|
1250
1251
|
const preservedFiles = [];
|
|
1251
1252
|
const ignoredFiles = [];
|
|
1253
|
+
// repoRel → the upstream file the protection kept out (null when upstream ships nothing there): the drift report's input.
|
|
1254
|
+
const ignoredSources = new Map();
|
|
1252
1255
|
const prunedFiles = [];
|
|
1253
1256
|
const pruneKeptFiles = [];
|
|
1254
1257
|
// What upstream ships right now — becomes this machine's provenance record.
|
|
@@ -1276,6 +1279,7 @@ Per-file behaviour:
|
|
|
1276
1279
|
if (isIgnored) {
|
|
1277
1280
|
counts.ignored++;
|
|
1278
1281
|
ignoredFiles.push(repoRel);
|
|
1282
|
+
ignoredSources.set(repoRel, srcFile);
|
|
1279
1283
|
if (flags.verbose) console.log(` · ${repoRel} (ignored via .maestroignore)`);
|
|
1280
1284
|
continue;
|
|
1281
1285
|
}
|
|
@@ -1414,6 +1418,7 @@ Per-file behaviour:
|
|
|
1414
1418
|
if (matchesIgnore(repoRel, ignorePatterns)) {
|
|
1415
1419
|
counts.ignored++;
|
|
1416
1420
|
ignoredFiles.push(repoRel);
|
|
1421
|
+
ignoredSources.set(repoRel, null);
|
|
1417
1422
|
if (flags.verbose) console.log(` · ${repoRel} (orphan, ignored via .maestroignore)`);
|
|
1418
1423
|
continue;
|
|
1419
1424
|
}
|
|
@@ -1504,6 +1509,7 @@ Per-file behaviour:
|
|
|
1504
1509
|
if (matchesIgnore(repoRel, ignorePatterns)) {
|
|
1505
1510
|
counts.ignored++;
|
|
1506
1511
|
ignoredFiles.push(repoRel);
|
|
1512
|
+
ignoredSources.set(repoRel, src);
|
|
1507
1513
|
if (flags.verbose) console.log(` · ${repoRel} (ignored via .maestroignore)`);
|
|
1508
1514
|
continue;
|
|
1509
1515
|
}
|
|
@@ -1596,6 +1602,26 @@ Per-file behaviour:
|
|
|
1596
1602
|
if (counts.updated) ok(`${counts.updated} updated (vendored, no local edits)`);
|
|
1597
1603
|
if (counts.same) console.log(` = ${counts.same} already up-to-date`);
|
|
1598
1604
|
if (counts.ignored) console.log(` · ${counts.ignored} ignored (.maestroignore protected)`);
|
|
1605
|
+
// A protected file is a fork the operator owns; "N ignored" hid how far
|
|
1606
|
+
// upstream had moved under each one. Say it per file, and keep the answer
|
|
1607
|
+
// in .maestro/ignored-drift.json for doctor and the next reader.
|
|
1608
|
+
let ignoredDrift = null;
|
|
1609
|
+
if (ignoredFiles.length) {
|
|
1610
|
+
const readOrNull = (p) => { try { return p && existsSync(p) ? readFileSync(p, "utf8") : null; } catch { return null; } };
|
|
1611
|
+
ignoredDrift = buildIgnoredDriftReport(
|
|
1612
|
+
[...new Set(ignoredFiles)].sort().map((repoRel) => ({ path: repoRel, local: readOrNull(join(cwd, repoRel)), upstream: readOrNull(ignoredSources.get(repoRel)) })),
|
|
1613
|
+
{ sdkVersion: readFrameworkVersion(), at: new Date().toISOString() },
|
|
1614
|
+
);
|
|
1615
|
+
for (const f of ignoredDrift.files) console.log(formatIgnoredLine(f));
|
|
1616
|
+
if (ignoredDrift.counts.drifts) warn(`${ignoredDrift.counts.drifts} protected file(s) drift from upstream — every upstream fix to those paths stops here until you port it (diff each against node_modules/@cohortapp/agent-sdk/<path>)`);
|
|
1617
|
+
if (!flags.dryRun) {
|
|
1618
|
+
try {
|
|
1619
|
+
const out = join(cwd, IGNORED_DRIFT_REL);
|
|
1620
|
+
mkdirSync(dirname(out), { recursive: true });
|
|
1621
|
+
writeFileSync(out, JSON.stringify(ignoredDrift, null, 2) + "\n");
|
|
1622
|
+
} catch (e) { warn(`could not write ${IGNORED_DRIFT_REL}: ${e && e.message ? e.message : e}`); }
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1599
1625
|
if (counts.mergeKept) console.log(` ~ ${counts.mergeKept} merge-mode kept (agents/ custom files preserved)`);
|
|
1600
1626
|
if (counts.preserved) warn(`${counts.preserved} preserved (local edits — kept your version)`);
|
|
1601
1627
|
if (counts.forced) warn(`${counts.forced} force-overwritten (backups in .maestro/backup/)`);
|
|
@@ -3341,6 +3367,38 @@ async function globalSetup(args = []) {
|
|
|
3341
3367
|
ok("global hooks already present (no change)");
|
|
3342
3368
|
}
|
|
3343
3369
|
|
|
3370
|
+
// 1b) Per-seat .claude/settings.json: the state-YAML gate hooks (PreToolUse on
|
|
3371
|
+
// Write|Edit, PostToolUse on Bash|Write|Edit). These belong in the SEAT file,
|
|
3372
|
+
// not ~/.claude — their commands are seat-relative and only mean anything
|
|
3373
|
+
// inside an agent repo. A hand edit there does not survive a fresh checkout
|
|
3374
|
+
// or an upgrade, which is why the scaffold copy carries them for new seats
|
|
3375
|
+
// and this merge carries them onto existing ones (upgrade runs global-setup
|
|
3376
|
+
// as a post-step). Deep-merged, idempotent, backed up before write.
|
|
3377
|
+
{
|
|
3378
|
+
const seatSettingsPath = join(cwd, ".claude", "settings.json");
|
|
3379
|
+
let seat = {};
|
|
3380
|
+
if (existsSync(seatSettingsPath)) {
|
|
3381
|
+
try { seat = JSON.parse(readFileSync(seatSettingsPath, "utf-8")); } catch { seat = null; }
|
|
3382
|
+
}
|
|
3383
|
+
if (seat === null) {
|
|
3384
|
+
warn(`${seatSettingsPath} is not valid JSON — state-YAML gate hooks not merged (repair it, then re-run global-setup)`);
|
|
3385
|
+
} else {
|
|
3386
|
+
const merged = gc.mergeStateYamlGateHooks(seat);
|
|
3387
|
+
if (merged.added.length > 0) {
|
|
3388
|
+
if (!dryRun) {
|
|
3389
|
+
mkdirSync(dirname(seatSettingsPath), { recursive: true });
|
|
3390
|
+
if (existsSync(seatSettingsPath)) {
|
|
3391
|
+
try { copyFileSync(seatSettingsPath, `${seatSettingsPath}.backup.${tsStamp()}`); } catch { /* */ }
|
|
3392
|
+
}
|
|
3393
|
+
writeFileSync(seatSettingsPath, JSON.stringify(merged.settings, null, 2) + "\n");
|
|
3394
|
+
}
|
|
3395
|
+
ok(`${dryRun ? "[dry-run] " : ""}seat hooks added to .claude/settings.json: ${merged.added.join(", ")}`);
|
|
3396
|
+
} else {
|
|
3397
|
+
ok("seat state-YAML gate hooks already present (no change)");
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3344
3402
|
// 2) global CLAUDE.md directive (only our delimited block is touched).
|
|
3345
3403
|
let mdContent = "";
|
|
3346
3404
|
if (existsSync(claudeMdPath)) { try { mdContent = readFileSync(claudeMdPath, "utf-8"); } catch { /* */ } }
|
|
@@ -3806,9 +3864,11 @@ switch (command) {
|
|
|
3806
3864
|
case "who-owns": case "who": await whoOwnsCmd(args); break;
|
|
3807
3865
|
case "inbox": process.exitCode = await (await import("../lib/cli/inbox.mjs")).runInbox(args); break;
|
|
3808
3866
|
case "session-ack": process.exitCode = await (await import("../lib/cli/session-ack.mjs")).runSessionAck(args); break;
|
|
3867
|
+
case "seat-auth": process.exitCode = await (await import("../lib/cli/seat-auth.mjs")).runSeatAuth(args); break;
|
|
3809
3868
|
case "session": { const r = await (await import("../lib/cli/session.mjs")).run(args); process.exitCode = r.code; break; }
|
|
3810
3869
|
case "board": await (await import("../lib/cli/board.mjs")).boardCmd(args); break;
|
|
3811
3870
|
case "design": await (await import("../lib/cli/design.mjs")).designCmd(args); break;
|
|
3871
|
+
case "run": process.exitCode = await (await import("../lib/engine/cli.mjs")).runFromProcess(args); break;
|
|
3812
3872
|
case "init":
|
|
3813
3873
|
case "update-init":
|
|
3814
3874
|
case "init-update":
|
|
@@ -3836,9 +3896,11 @@ Usage:
|
|
|
3836
3896
|
npx @cohortapp/agent-sdk who-owns <scope> Who owns a scope / escalate-to / reports (org context, zero-LLM)
|
|
3837
3897
|
npx @cohortapp/agent-sdk inbox list|show|claim|reply|done|defer The main session's inbox (JSON; shares the daemon's markers)
|
|
3838
3898
|
npx @cohortapp/agent-sdk session-ack <tickId> Ack a cadence tick handed to the main session
|
|
3899
|
+
npx @cohortapp/agent-sdk seat-auth [--row|--fleet] Which Claude billing rail this seat is on (G4) — variable NAMES only, never a value
|
|
3839
3900
|
npx @cohortapp/agent-sdk session <cmd> Front-door session: status|attach|start|stop|restart|spawn|peers|handoffs|ack
|
|
3840
3901
|
npx @cohortapp/agent-sdk board mine|track|claim|complete Your work across every board (maestro board --help)
|
|
3841
3902
|
npx @cohortapp/agent-sdk design sync [--out <dir>] Pull the brand foundation → DESIGN.md + PRODUCT.md
|
|
3903
|
+
npx @cohortapp/agent-sdk run -p "<prompt>" [flags] Cohort Engine, headless (cohort run --help)
|
|
3842
3904
|
|
|
3843
3905
|
Upgrade flags:
|
|
3844
3906
|
--dry-run, -n Preview changes without writing
|
|
@@ -65,6 +65,7 @@ make per-agent spend attribution and revocation possible).
|
|
|
65
65
|
|
|
66
66
|
```sh
|
|
67
67
|
maestro doctor # validates ANTHROPIC_API_KEY against api.anthropic.com
|
|
68
|
+
maestro seat-auth # which rail this seat is on, by variable NAME (see below)
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
After the cost-telemetry work (roadmap item 0.3) lands, `maestro doctor` also
|
|
@@ -72,6 +73,65 @@ turns RED when sessions have run but recorded spend is $0, and a nightly digest
|
|
|
72
73
|
reconciles the local ledger against the Admin Cost API. Until then, confirm spend
|
|
73
74
|
is accruing in the Console workspace view for a canary agent.
|
|
74
75
|
|
|
76
|
+
## The tooling: `maestro seat-auth` (G4)
|
|
77
|
+
|
|
78
|
+
A seat can state, about itself, which rail it is on — and the answer is a
|
|
79
|
+
**verdict over variable names**, never a value. Nothing here prints, logs or
|
|
80
|
+
stores a credential, not even truncated.
|
|
81
|
+
|
|
82
|
+
| Verdict | Meaning | Doctor level |
|
|
83
|
+
| -------------- | ---------------------------------------------------------------------- | -------------------------------- |
|
|
84
|
+
| `api-key` | `ANTHROPIC_API_KEY` only — the fleet posture | ok |
|
|
85
|
+
| `subscription` | `MAESTRO_PREFER_SUBSCRIPTION_AUTH` and/or `CLAUDE_CODE_OAUTH_TOKEN` | warn (fail when armed, below) |
|
|
86
|
+
| `both` | a Console key **and** a subscription credential on the same seat | warn (fail when armed) — loud |
|
|
87
|
+
| `neither` | no Claude credential at all | fail — except on an engine-cohort seat, where it is expected |
|
|
88
|
+
|
|
89
|
+
**`both` is its own verdict and is worth flagging loudly.** It is not "half
|
|
90
|
+
migrated": it is ambiguous. The runtime adapter blanks `ANTHROPIC_API_KEY` on a
|
|
91
|
+
seat that `subscriptionAuth()` calls true (`lib/runtime/adapter.mjs`), so the
|
|
92
|
+
subscription rail wins the lanes that go through the adapter while a lane that
|
|
93
|
+
passes the environment straight through may use the key. Spend then lands in
|
|
94
|
+
two places and neither is authoritative. Migrate, do not stack.
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
maestro seat-auth # the verdict, the names present, the remediation
|
|
98
|
+
maestro seat-auth --json # the same, machine-readable
|
|
99
|
+
maestro seat-auth --row # ONE markdown row to paste into the fleet inventory
|
|
100
|
+
maestro seat-auth --fleet # the inventory template, one row per org member
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The same verdict appears as a row in `maestro doctor`, so an operator who runs
|
|
104
|
+
only doctor still sees it.
|
|
105
|
+
|
|
106
|
+
### The fleet inventory
|
|
107
|
+
|
|
108
|
+
A seat's environment lives on the seat's own machine. There is no remote
|
|
109
|
+
inventory mechanism and this tooling does not invent one. So the fleet report is
|
|
110
|
+
a **template plus paste-able rows**: run `maestro seat-auth --fleet` once (it
|
|
111
|
+
pre-fills one row per member from the org directory), then on each machine run
|
|
112
|
+
`maestro seat-auth --row` and paste the line over that seat's row. The measured
|
|
113
|
+
columns — seat, agent id, machine, verdict, which variable names are present,
|
|
114
|
+
when it was checked — fill themselves; the Console-side columns (account,
|
|
115
|
+
workspace, cap, key id last 4, revocation date) stay blank, because only a human
|
|
116
|
+
with Console access knows them and a tool that guessed them would teach people
|
|
117
|
+
to trust a guess.
|
|
118
|
+
|
|
119
|
+
### Arming the guard
|
|
120
|
+
|
|
121
|
+
The check **warns** by default, deliberately: seats are live, and a check that
|
|
122
|
+
failed on the day it shipped would break the seats it exists to move. Once every
|
|
123
|
+
row of the inventory reads `api-key`, set
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
MAESTRO_REQUIRE_CONSOLE_KEY=1
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
in each seat's `.env` (or the fleet's environment). `subscription` and `both`
|
|
130
|
+
then FAIL `maestro doctor` and exit 1 from `maestro seat-auth`, so a seat that
|
|
131
|
+
regresses to a subscription token announces itself instead of quietly billing a
|
|
132
|
+
personal plan. Record the date it was set fleet-wide — that, plus the last token
|
|
133
|
+
revocation, is what closes this gate.
|
|
134
|
+
|
|
75
135
|
## What is automated vs human
|
|
76
136
|
|
|
77
137
|
maestro cannot create Console workspaces or keys for you — that requires a human
|
|
@@ -177,15 +177,60 @@ summary and in `.maestro/upgrade-result.json` `{from, to, at, steps}`:
|
|
|
177
177
|
| `globalInstall` | `npm i -g @cohortapp/agent-sdk@<this version>` so `maestro` / `cohort` / `cohort-mcp` on PATH match the agent dir (`MAESTRO_SKIP_GLOBAL_INSTALL=1` skips) |
|
|
178
178
|
| `verify` | the `maestro upgrade --verify` report, below |
|
|
179
179
|
|
|
180
|
-
autoupdate then kickstarts the daemon and health-gates it
|
|
181
|
-
|
|
182
|
-
line, and
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
180
|
+
autoupdate then kickstarts the daemon and health-gates it. **The gate means
|
|
181
|
+
health, not "running"** — it used to be "pid alive + a fresh `org-mesh
|
|
182
|
+
connected` line", and a crash-looping daemon satisfies both (launchd respawns
|
|
183
|
+
it, and every respawn prints the line again): one seat logged `up to date
|
|
184
|
+
(2.17.0)` hourly for six days, 2026-09-15..21, while its daemon died ~25 s
|
|
185
|
+
after every start, and the org saw no presence beat from it for ten days. The
|
|
186
|
+
daemon now has to answer all of:
|
|
187
|
+
|
|
188
|
+
- **pid stability** — the daemon pid set is unchanged across two samples 90 s
|
|
189
|
+
apart and every pid's `ps etime` is ≥ 90 s (3× the observed crash
|
|
190
|
+
interval, well inside the hourly cadence; `MAESTRO_AUTOUPDATE_STABLE_S`);
|
|
191
|
+
- **no fatal line** in its own log since the restart (`[DAEMON]
|
|
192
|
+
uncaughtException:`, `[daemon] Fatal:`, `[wrapper] FATAL:`,
|
|
193
|
+
`ERR_MODULE_NOT_FOUND`) — the log has no per-line timestamps and the
|
|
194
|
+
wrapper names the file for the day the process started, so "since the
|
|
195
|
+
restart" is a line offset taken before the kickstart;
|
|
196
|
+
- **an org-acknowledged beat** — `state/org/last-beat.json` `{at, ok, code?}`,
|
|
197
|
+
which `lib/org/mesh.mjs` overwrites on every presence beat (`ok:true` only
|
|
198
|
+
when the org answered 2xx), must say `ok:true`, post-date the daemon's start
|
|
199
|
+
and be younger than 5 min (`MAESTRO_AUTOUPDATE_BEAT_FRESH_S`, the same bar
|
|
200
|
+
after which hq's presence view calls a seat offline). Skipped only for a
|
|
201
|
+
seat `config/org.yaml` does not enrol.
|
|
202
|
+
|
|
203
|
+
When a `-session` plist was generated, the session label must also be loaded
|
|
204
|
+
with a live supervisor process; a missing session is logged as
|
|
205
|
+
`reconcile-failed` and does **not** roll back (the daemon's `--print` lane is
|
|
206
|
+
the front door meanwhile; doctor says what to do). Every launchd and `pgrep`
|
|
207
|
+
question is scoped to *this* agent (`ai.maestro.<first>-*` and its own agent
|
|
208
|
+
dir), so two seats on one Mac never gate on — or restart — each other.
|
|
209
|
+
|
|
210
|
+
**Being up to date is not an exemption.** When the installed version is
|
|
211
|
+
already `@latest` the run still runs the same gate on the current version.
|
|
212
|
+
An unhealthy daemon is logged loudly, recorded in `state/autoupdate/last.json`
|
|
213
|
+
as `{ok:false, healthy:false, reason:"unhealthy-current: …"}` (the beat
|
|
214
|
+
carries it as `machine.upgrade`), and announced once per episode through
|
|
215
|
+
`state/session/upgrade-notice.json` `{from:CUR, to:CUR, healthy:false,
|
|
216
|
+
reason}` so the front-door session's feed surfaces it as a `daemon-unhealthy`
|
|
217
|
+
directive — a distinct action from `upgrade-available`, so no session restarts
|
|
218
|
+
on a health report. Nothing is rolled back (there is no upgrade to undo), an
|
|
219
|
+
`unhealthy-current` entry never holds a later release, and a recovery restores
|
|
220
|
+
`last.json`.
|
|
221
|
+
|
|
222
|
+
**A stale daemon is reconciled on the same path.** A hand-run `maestro
|
|
223
|
+
upgrade` installs the package and reconciles the seat but never restarts the
|
|
224
|
+
daemon (its verify row says the new version "takes effect when autoupdate
|
|
225
|
+
kickstarts it"). When `state/dashboards/daemon-health.yaml` shows the live
|
|
226
|
+
daemon started on a different `sdk_version` than the installed one, the hourly
|
|
227
|
+
run kickstarts it, waits, and runs the gate exactly as after an automatic
|
|
228
|
+
install — a healthy outcome writes the same `{from:<old>, to:<new>}` notice, so
|
|
229
|
+
the session restarts itself onto the new code when idle. The fatal scan starts
|
|
230
|
+
at the running daemon's own boot marker (`[DAEMON] boot pid=<pid>`, the first
|
|
231
|
+
line `maestro-daemon.mjs` prints), never at the top of the shared start-day
|
|
232
|
+
log, so a one-off crash earlier the same day that launchd already recovered
|
|
233
|
+
from is history, not health.
|
|
189
234
|
|
|
190
235
|
An unhealthy daemon **rolls back**: the previous SDK is reinstalled into the
|
|
191
236
|
agent dir and *that* package's `upgrade` runs, the global install is put back
|
package/docs/guides/mac-mini.md
CHANGED
|
@@ -32,20 +32,17 @@ npm i -g @cohortapp/agent-sdk # GLOBAL on purpose: every Claude Code sess
|
|
|
32
32
|
# this seat needs `maestro` + `cohort-mcp` on PATH
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
## 3. The Claude
|
|
35
|
+
## 3. The Claude credential — one Console API key per seat
|
|
36
36
|
|
|
37
37
|
Every `claude` the seat runs (the daemon's `--print` lane, the main session,
|
|
38
|
-
cadence sub-sessions) authenticates with
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
cadence sub-sessions) authenticates with an **Anthropic Console API key**
|
|
39
|
+
created for this agent, in a Console workspace with its own spend limit. Do
|
|
40
|
+
not use a Claude subscription on an agent seat: neither a `claude setup-token`
|
|
41
|
+
token nor the keychain login (which also expires headlessly). Creating the
|
|
42
|
+
workspace and the key: [billing-console-keys.md](billing-console-keys.md).
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Keep it in your clipboard / password manager for step 5. It is per seat: mint
|
|
48
|
-
a fresh one whenever `cohort doctor` reports the token as rejected.
|
|
44
|
+
Keep the key in your password manager for step 5. It is per seat: rotate it in
|
|
45
|
+
the Console whenever `cohort doctor` reports it as rejected.
|
|
49
46
|
|
|
50
47
|
## 4. Create the agent repo
|
|
51
48
|
|
|
@@ -59,7 +56,7 @@ including `.mcp.json`, which exposes the `cohort-mcp` org tool surface to
|
|
|
59
56
|
interactive Claude sessions, and the PreToolUse hooks that keep its outbound
|
|
60
57
|
writes on the CLI lane).
|
|
61
58
|
|
|
62
|
-
## 5. Enroll against `https://os.cohortapp.com` — and paste the
|
|
59
|
+
## 5. Enroll against `https://os.cohortapp.com` — and paste the API key
|
|
63
60
|
|
|
64
61
|
Two lanes — pick one:
|
|
65
62
|
|
|
@@ -68,13 +65,13 @@ Two lanes — pick one:
|
|
|
68
65
|
|
|
69
66
|
```bash
|
|
70
67
|
export COHORT_API_KEY=nlk_… COHORT_ORG_ID=<org-ID> COHORT_AGENT_ID=<member-slug>
|
|
71
|
-
cohort setup # the model section (order 30) asks for the
|
|
72
|
-
# headless / one-paste bootstrap: the
|
|
73
|
-
|
|
68
|
+
cohort setup # the model section (order 30) asks for the API key from step 3
|
|
69
|
+
# headless / one-paste bootstrap: the key comes from the environment instead of a prompt
|
|
70
|
+
ANTHROPIC_API_KEY=<key> cohort setup --headless
|
|
74
71
|
```
|
|
75
72
|
|
|
76
|
-
Either way `.env` ends up with `
|
|
77
|
-
`
|
|
73
|
+
Either way `.env` ends up with `ANTHROPIC_API_KEY`, mode 600, and no
|
|
74
|
+
`CLAUDE_CODE_OAUTH_TOKEN` or `MAESTRO_PREFER_SUBSCRIPTION_AUTH`.
|
|
78
75
|
|
|
79
76
|
> **`COHORT_ORG_ID` is the org's ID, not its slug** — this line said
|
|
80
77
|
> `<org-slug>` and that would 401 every call. The value rides as `x-org-id`
|
|
@@ -98,7 +95,7 @@ Two lanes — pick one:
|
|
|
98
95
|
|
|
99
96
|
| Order | Section | What it does |
|
|
100
97
|
| --- | --- | --- |
|
|
101
|
-
| 30 | `model` | Claude auth — **`
|
|
98
|
+
| 30 | `model` | Claude auth — **`api-key` by default**: paste the agent's Console API key; writes `ANTHROPIC_API_KEY`, chmods `.env` 600 |
|
|
102
99
|
| 75 | `org` | endpoint + token (the enrollment SoT) |
|
|
103
100
|
| 76 | `messaging` | messaging.read/write + calling.write scopes, home channels |
|
|
104
101
|
| 77 | `orgmail` | **workspace mailbox** — writes `config/orgmail.yaml` |
|
|
@@ -144,13 +141,11 @@ cohort doctor
|
|
|
144
141
|
|
|
145
142
|
All green includes, in this order:
|
|
146
143
|
|
|
147
|
-
- **Claude auth** — the mode in effect (`
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
cheap way to prove it. "keychain login"
|
|
153
|
-
or "nothing configured" means step 3/5 was skipped.
|
|
144
|
+
- **Claude auth** — the mode in effect (`ANTHROPIC_API_KEY` is the expected
|
|
145
|
+
line for an agent seat). In API-key mode the probe makes a real call, so a
|
|
146
|
+
rejected key shows here. A subscription line (OAuth token or keychain login)
|
|
147
|
+
on an agent seat means it is still on the pre-migration setup — see step 3.
|
|
148
|
+
"nothing configured" means step 3/5 was skipped.
|
|
154
149
|
- **Cohort sources** — for each of `base` / `orgId` / `token` / `agentId`,
|
|
155
150
|
which file won (`config/org.yaml` beats the environment beats `.env`) and
|
|
156
151
|
every value that lost. If you edited `.env` and nothing changed, this line
|
|
@@ -52,7 +52,7 @@ core runner.
|
|
|
52
52
|
|---------|-------|-------------|
|
|
53
53
|
| `identity` | 10 | Agent name and title, the **function × altitude** archetype, and the principal. Writes `config/agent.json`. |
|
|
54
54
|
| `company` | 20 | Company-context interview — name, website, industry, one-line + detailed overview, stage/size, footprint, regulation, top priorities, and key people. Writes `config/company.json`. |
|
|
55
|
-
| `model` | 30 | Claude auth. Three modes, **`
|
|
55
|
+
| `model` | 30 | Claude auth. Three modes, **`api-key` the default**: paste an Anthropic Console API key created for this agent in a Console workspace with a spend limit (headless: `ANTHROPIC_API_KEY` in the environment) → `.env` gets `ANTHROPIC_API_KEY`. Setup runbook: [billing-console-keys.md](billing-console-keys.md). The other two modes — a `claude setup-token` subscription token, or this machine's keychain login — are for a person's own development machine, not an agent seat. Chmods `.env` 600. |
|
|
56
56
|
| `comms` | 45 | Wires each messaging channel — Slack, Gmail, SMS, WhatsApp, Telegram, voice — into `.env`/gate files and verifies inbound. |
|
|
57
57
|
| `tools` | 50 | Selects which channels and MCP servers the agent should run. |
|
|
58
58
|
| `operating-model` | 60 | Deterministically generates the operating charter, a seeded WBS backlog (≥5 open items), 40–60 sub-agents + skills + workflows + MCP servers + event-routing, archetype cadences, the autonomy policy, the communication profile, and the launchd plists. |
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Fleet rollout — publish one version, then prove the fleet took it
|
|
2
|
+
|
|
3
|
+
`scripts/fleet/rollout.mjs` is the whole propagation path in one command.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
node scripts/fleet/rollout.mjs [--dry-run] [--verify-only]
|
|
7
|
+
[--deadline <min>] [--interval <s>]
|
|
8
|
+
[--seat-window <min>] [--agent-root <path>] [--json]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
There is exactly one way an SDK change reaches the fleet: it is published to
|
|
12
|
+
npm, and each seat's hourly `scripts/local-triggers/autoupdate.sh` installs
|
|
13
|
+
`@latest`. Nothing is pushed to a machine. **This tool never ssh's anywhere**,
|
|
14
|
+
and it takes **no credential as an argument or environment variable** — npm auth
|
|
15
|
+
comes from the operator's own `npm login`, org auth from the agent config the
|
|
16
|
+
rest of `lib/org` reads.
|
|
17
|
+
|
|
18
|
+
Both promises are enforced **twice**, because a source-reading test only catches
|
|
19
|
+
the shapes it was taught — `execSync("ssh …")` and `deps.exec(cmd, [])` both
|
|
20
|
+
slipped past the first version of it. `runCommand()` refuses any command but
|
|
21
|
+
`npm` and `git` at runtime, on the value; `parseArgs()` drops everything after
|
|
22
|
+
the first `=` before an error string is built, so no branch can echo a
|
|
23
|
+
credential back into your scrollback. The structural tests in
|
|
24
|
+
`scripts/fleet/rollout.test.mjs` sit on top, pinning the import surface of
|
|
25
|
+
`node:child_process` so nothing can reach a process without that guarded seam.
|
|
26
|
+
|
|
27
|
+
## The three stages
|
|
28
|
+
|
|
29
|
+
**1 — pre-flight.** Refuses the publish unless all of:
|
|
30
|
+
|
|
31
|
+
| gate | why it is here |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| `npm whoami` succeeds | a publish with no auth fails halfway and leaves you guessing |
|
|
34
|
+
| local version > registry `@latest` | the registry, not a changelog, is the authority on what is published |
|
|
35
|
+
| working tree clean | you can only publish what is committed |
|
|
36
|
+
| `v<version>` exists locally **and** on the remote | published bytes stay findable |
|
|
37
|
+
| `npm run check` passes | … |
|
|
38
|
+
| `npm test` passes | … on the bytes about to be published |
|
|
39
|
+
|
|
40
|
+
The last two are **re-run**, never read from a log: a green run from an hour ago
|
|
41
|
+
is a fact about a different tree. They are skipped only when a cheaper gate has
|
|
42
|
+
already blocked the publish — and the run says so in that case, so "pre-flight
|
|
43
|
+
passed" can never quietly mean "was not run".
|
|
44
|
+
|
|
45
|
+
**2 — publish.** `npm publish`, then poll the registry until `@latest` **is** the
|
|
46
|
+
new version. A 404 or a stale answer in the first seconds is **read lag, not
|
|
47
|
+
failure** — that has been misread as a failed publish before, so the poll
|
|
48
|
+
retries and only fails when its attempts run out.
|
|
49
|
+
|
|
50
|
+
**3 — verify propagation.** Poll the org directory — hq's server-stamped
|
|
51
|
+
presence-beat derivation, the same signal the human fleet page paints — and
|
|
52
|
+
print a per-seat table every round until every seat reports the new version or
|
|
53
|
+
the deadline passes. The run exits non-zero naming exactly which seats are
|
|
54
|
+
behind.
|
|
55
|
+
|
|
56
|
+
A **seat** is an AI colleague with a server-stamped beat inside `--seat-window`
|
|
57
|
+
(default 30 min). An agent with no machine (responder-only) takes no SDK version
|
|
58
|
+
and is counted separately, never as "behind".
|
|
59
|
+
|
|
60
|
+
## Exit codes
|
|
61
|
+
|
|
62
|
+
| code | meaning |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| 0 | published (or already published) **and** every seat reports the version |
|
|
65
|
+
| 1 | pre-flight refusal — nothing was published, nothing changed |
|
|
66
|
+
| 2 | publish failed, or the registry never served the new version |
|
|
67
|
+
| 3 | deadline passed with seats behind or unverifiable |
|
|
68
|
+
|
|
69
|
+
### `3` is three different things — do not gate on the exit code yet
|
|
70
|
+
|
|
71
|
+
**`rollout` cannot be used as a success gate today.** Every seat classifies as
|
|
72
|
+
`unverifiable` (see below), an unverified seat is deliberately not counted as
|
|
73
|
+
done, so a flawless publish onto a fully propagated fleet **still exits 3**.
|
|
74
|
+
A cron, a CI step or a wrapper script that treats `0` as "shipped" will never
|
|
75
|
+
fire; one that treats `3` as "seats are behind" will page you for nothing.
|
|
76
|
+
|
|
77
|
+
Branch on `--json` instead. It prints one object — `{code, reason, note,
|
|
78
|
+
summary}` — whose `reason` separates the cases the exit code merges:
|
|
79
|
+
|
|
80
|
+
| `reason` | meaning |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `verified` | every seat reports the target version (`code` 0) |
|
|
83
|
+
| `behind` | at least one seat is **provably** on an older version |
|
|
84
|
+
| `unverifiable` | no seat is known to be behind; nothing available can prove any seat is current |
|
|
85
|
+
| `empty-fleet` | no beating seats were found — never treated as done |
|
|
86
|
+
| `no-fleet-read` | the org read never succeeded; says nothing about the fleet |
|
|
87
|
+
|
|
88
|
+
`unverifiable` becomes `verified` the moment the one-line hq change below lands,
|
|
89
|
+
with no change to this script. `propagationOutcome()` is pure and exported, so
|
|
90
|
+
the mapping is pinned by test rather than by this table.
|
|
91
|
+
|
|
92
|
+
Idempotent: when `@latest` already equals the local version the run prints
|
|
93
|
+
`already published, verifying propagation` and goes straight to stage 3.
|
|
94
|
+
Re-running it is the supported way to watch a rollout land. `--verify-only`
|
|
95
|
+
does stage 3 alone, against any version, without touching npm.
|
|
96
|
+
|
|
97
|
+
## Today's blocker, and the one honest gap
|
|
98
|
+
|
|
99
|
+
**npm auth.** `npm whoami` is a 401 on this machine, so stage 1 refuses. Only a
|
|
100
|
+
human can clear it (`npm login` as the publisher). The moment it is cleared,
|
|
101
|
+
this command is the entire rollout.
|
|
102
|
+
|
|
103
|
+
**`unverifiable` seats.** Stage 3 wants each seat's *running* version. Every seat
|
|
104
|
+
already reports it — the presence beat carries `status.machine.sdkVersion` and
|
|
105
|
+
hq persists it to `AgentStatus.machine` — but **no read an agent can make gives
|
|
106
|
+
it back**: hq's `directory` read (`src/server/rpc/reads.ts#directory`) selects
|
|
107
|
+
five `AgentStatus` columns and `machine` is not among them, and `member.get`
|
|
108
|
+
does not read `AgentStatus` at all. So every seat currently reads `unknown` and
|
|
109
|
+
the run exits 3.
|
|
110
|
+
|
|
111
|
+
That is deliberate. The tool does **not** count a beating seat as up to date:
|
|
112
|
+
treating "running" as "healthy" is exactly what let one seat sit six days behind
|
|
113
|
+
while its own log said "up to date" every hour. It proves liveness, says plainly
|
|
114
|
+
that it cannot prove the version, and fails.
|
|
115
|
+
|
|
116
|
+
**To close it (hq side, one lane):** add `machine: true` to the `agentStatus`
|
|
117
|
+
select in `directory()` and echo `sdkVersion` (only that key — `machine` is an
|
|
118
|
+
open record and the rest is seat telemetry) into the per-member `status` object,
|
|
119
|
+
with a test pinning the field. `seatVersion()` in the script already reads
|
|
120
|
+
`status.machine.sdkVersion` first and will light up with no change here.
|
|
121
|
+
|
|
122
|
+
Until it does, the run says so in words on every all-unverifiable finish — that
|
|
123
|
+
exit 3 does **not** mean a seat is behind — rather than leaving the reader to
|
|
124
|
+
infer it from a count.
|
|
125
|
+
|
|
126
|
+
## One wrinkle: the gates dirty the tree
|
|
127
|
+
|
|
128
|
+
`npm test` appends to a tracked runtime ledger (`.claude-flow/policy/state.json`),
|
|
129
|
+
so a second run in a row would refuse on a file the *first* run wrote. The
|
|
130
|
+
clean-tree gate is not relaxed for it — the run names those paths and tells you
|
|
131
|
+
to `git checkout --` them. The gate order also means a first run is unaffected:
|
|
132
|
+
cleanliness is read before the gates run.
|
|
133
|
+
|
|
134
|
+
## Reading a round
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Fleet vs 2.18.1 (round 2 · 46s elapsed)
|
|
138
|
+
SEAT ID BEAT REPORTS VERDICT
|
|
139
|
+
-------------- ---- ---- ------- ------------
|
|
140
|
+
<name> A0xx 6s 2.18.1 current
|
|
141
|
+
<name> A0xx 15s 2.17.0 stale
|
|
142
|
+
<name> A0xx 20s unknown unverifiable
|
|
143
|
+
15 seat(s): 1 current · 1 stale · 13 unverifiable (+32 agent(s) with no beating machine — not rollout targets)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`BEAT` is the age of the seat's last **server-stamped** beat — the only honest
|
|
147
|
+
liveness signal there is. `REPORTS` is what that seat says it is running.
|
|
148
|
+
|
|
149
|
+
## What the suite covers
|
|
150
|
+
|
|
151
|
+
`npm test` discovers every `*.test.mjs` under `lib/`, `scripts/`, `bin/`,
|
|
152
|
+
`services/` and `test/` — there is no list to append to. `npm run test:list`
|
|
153
|
+
asks the same runner what it found and prints it without running anything; it
|
|
154
|
+
used to be a hand-typed enumeration that had drifted to 46 of 82 files, and
|
|
155
|
+
`scripts/ci/run-tests.test.mjs` now fails the build if any `package.json` script
|
|
156
|
+
starts enumerating the suite again.
|