@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
|
@@ -85,6 +85,19 @@
|
|
|
85
85
|
* // to sdkVersion without a schema change. `ok` is the attempt's verdict:
|
|
86
86
|
* // true = healthy on `to`; false = install failed or rolled back to `from`.
|
|
87
87
|
* upgrade?: { at: ISO8601, from: string, to: string, ok: boolean },
|
|
88
|
+
* // THE BEATING DAEMON — which process is emitting this beat, what code
|
|
89
|
+
* // it is actually running, and the last health-gate verdict on it.
|
|
90
|
+
* // Also on `machine` (open record). `sdkVersion` ABOVE is what is
|
|
91
|
+
* // INSTALLED on the seat; `daemon.sdkVersion` is what the running
|
|
92
|
+
* // process booted on, and the two differ for exactly as long as an
|
|
93
|
+
* // installed upgrade has not been restarted onto. `pid`+`bootAt` make a
|
|
94
|
+
* // crash loop visible org-side (a pid that moves every beat), which is
|
|
95
|
+
* // the failure that hid for six days behind an hourly "up to date".
|
|
96
|
+
* // `dashboardAt` is the stamp of the file these came from, so a reader
|
|
97
|
+
* // can age the claim; it is never a liveness signal on its own.
|
|
98
|
+
* daemon?: { pid?: number, bootAt?: ISO8601, uptimeS?: number,
|
|
99
|
+
* sdkVersion?: string, dashboardAt?: ISO8601,
|
|
100
|
+
* healthy?: boolean, healthReason?: string },
|
|
88
101
|
* },
|
|
89
102
|
* claudeAuth: "ok"|"relogin_required"|"unknown",
|
|
90
103
|
* alerts: [{ id, severity, kind, detail }],
|
|
@@ -120,6 +133,7 @@ import { fileURLToPath } from "node:url";
|
|
|
120
133
|
import { createRequire } from "node:module";
|
|
121
134
|
import { writeJsonAtomic } from "../fs-atomic.mjs";
|
|
122
135
|
import { probeClaude as defaultProbeClaude } from "../setup/claude-probe.mjs";
|
|
136
|
+
import { readSeatEngine } from "../runtime/adapter.mjs";
|
|
123
137
|
|
|
124
138
|
import { list as listPresence } from "../collective/presence.mjs";
|
|
125
139
|
import { billableUsd } from "../cost/ledger-row.mjs";
|
|
@@ -433,18 +447,64 @@ export async function collectMachine(o = {}) {
|
|
|
433
447
|
if (Number.isFinite(disk)) machine.diskUsedPct = pct(disk);
|
|
434
448
|
}
|
|
435
449
|
|
|
450
|
+
// IDENTITY (§3.8) — hostname / tailnetIp / sdkVersion: where the seat is and
|
|
451
|
+
// what it runs. Collected FIRST and on its own terms, no longer as a rider on
|
|
452
|
+
// the inventory probe.
|
|
453
|
+
//
|
|
454
|
+
// WHY IT MOVED. It used to be read out of `collectInventory`'s return, inside
|
|
455
|
+
// `if (o.inventory !== false)` and with no try of its own. Three ways that
|
|
456
|
+
// lost the one field a fleet rollout is verified by, none of them about
|
|
457
|
+
// identity: a caller that turned inventory off lost it as a side effect; a
|
|
458
|
+
// `system_profiler` fork that threw took the whole `collectMachine` down with
|
|
459
|
+
// it (`collectStatus` then substitutes a bare `{loadavg, memUsedPct}` floor —
|
|
460
|
+
// the beat still goes, carrying neither the host stats nor the version); and
|
|
461
|
+
// a seat in that state stayed in it, beat after beat, with nothing on the box
|
|
462
|
+
// or in the org saying why. Identity is three cheap, independent reads and it
|
|
463
|
+
// is what an operator is looking for; it should not be able to fail because a
|
|
464
|
+
// hardware probe did. Each field is independently fail-open inside
|
|
465
|
+
// `collectIdentity`, and the try here is the outer guard for the probe seam.
|
|
466
|
+
//
|
|
467
|
+
// The results are handed on to `collectInventory` below so the tailnet probe
|
|
468
|
+
// forks once per beat, not twice.
|
|
469
|
+
let identity = {};
|
|
470
|
+
if (o.identity !== false) {
|
|
471
|
+
try { identity = await collectIdentity(o, osImpl); } catch { identity = {}; }
|
|
472
|
+
if (identity.hostname) machine.hostname = identity.hostname;
|
|
473
|
+
if (identity.tailnetIp) machine.tailnetIp = identity.tailnetIp;
|
|
474
|
+
if (identity.sdkVersion) machine.sdkVersion = identity.sdkVersion;
|
|
475
|
+
}
|
|
476
|
+
|
|
436
477
|
// INVENTORY — device / ram / cores. Cached on disk (see collectInventory):
|
|
437
478
|
// the chip and the installed RAM do not change between beats, so the
|
|
438
479
|
// system_profiler fork happens once per machine, not every 30 seconds.
|
|
480
|
+
//
|
|
481
|
+
// WRAPPED, and the try is not decorative. `collectInventory` is not total:
|
|
482
|
+
// `execFileSafe` swallows a failing FORK, but the reads around it do not all
|
|
483
|
+
// have a try of their own (the platform read at the top of the probe block is
|
|
484
|
+
// the live example), so the function can and does throw. Before identity was
|
|
485
|
+
// hoisted above this, that throw propagated out of `collectMachine` and
|
|
486
|
+
// `collectStatus` substituted its bare `{loadavg, memUsedPct}` floor — the
|
|
487
|
+
// beat went out carrying neither host stats NOR the version, which is how two
|
|
488
|
+
// seats beat for days with no hostname and no sdkVersion. Now it costs its
|
|
489
|
+
// own three fields and nothing else.
|
|
439
490
|
if (o.inventory !== false) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
491
|
+
try {
|
|
492
|
+
const inv = await collectInventory({
|
|
493
|
+
...o,
|
|
494
|
+
// Hand the identity answers on so the tailnet probe forks ONCE per
|
|
495
|
+
// beat, not twice. An empty string is an answer ("probed, none
|
|
496
|
+
// found") — and when `identity` is switched off entirely it is the
|
|
497
|
+
// right answer to hand on: a caller that asked for no identity should
|
|
498
|
+
// not pay for a tailnet fork inside the inventory probe either.
|
|
499
|
+
// `collectInventory` still returns those two fields; we ignore them —
|
|
500
|
+
// `machine.hostname/tailnetIp/sdkVersion` are set above or not at all.
|
|
501
|
+
tailnetIp: typeof o.tailnetIp === "string" ? o.tailnetIp : String(identity.tailnetIp || ""),
|
|
502
|
+
sdkVersion: typeof o.sdkVersion === "string" ? o.sdkVersion : String(identity.sdkVersion || ""),
|
|
503
|
+
});
|
|
504
|
+
if (inv.device) machine.device = inv.device;
|
|
505
|
+
if (inv.ram) machine.ram = inv.ram;
|
|
506
|
+
if (Number.isFinite(inv.cores)) machine.cores = inv.cores;
|
|
507
|
+
} catch { /* device/ram/cores drop; identity above already landed */ }
|
|
448
508
|
}
|
|
449
509
|
|
|
450
510
|
// spend24h — the agent's own rolling 24h LLM spend, off the cost ledger.
|
|
@@ -1310,6 +1370,123 @@ export function upgradeSummary(last) {
|
|
|
1310
1370
|
return { at, from: typeof last.from === "string" ? last.from : "", to, ok: last.ok === true };
|
|
1311
1371
|
}
|
|
1312
1372
|
|
|
1373
|
+
// ---------------------------------------------------------------------------
|
|
1374
|
+
// Daemon — WHICH process is beating, what code it is running, and the gate's
|
|
1375
|
+
// last verdict on it (`machine.daemon`)
|
|
1376
|
+
// ---------------------------------------------------------------------------
|
|
1377
|
+
|
|
1378
|
+
/**
|
|
1379
|
+
* Top-level scalars we lift out of state/dashboards/daemon-health.yaml. The file
|
|
1380
|
+
* is written by scripts/daemon/health.mjs as flat `key: value` lines plus one
|
|
1381
|
+
* indented `dispatcher:` JSON block, so a line regex over the UNINDENTED lines
|
|
1382
|
+
* reads it exactly and cannot be confused by the nested block. We do NOT pull a
|
|
1383
|
+
* YAML parser in for four scalars on a 30-second loop.
|
|
1384
|
+
*
|
|
1385
|
+
* Fail-open → null (no file, unreadable, or no recognisable line).
|
|
1386
|
+
* @param {string} text
|
|
1387
|
+
* @returns {{pid?:number, sdkVersion?:string, installedSdkVersion?:string,
|
|
1388
|
+
* versionsAgree?:boolean, versionDrift?:string, bootAt?:string,
|
|
1389
|
+
* updatedAt?:string, uptimeS?:number}|null}
|
|
1390
|
+
*/
|
|
1391
|
+
export function parseDaemonHealthYaml(text) {
|
|
1392
|
+
if (typeof text !== "string" || text === "") return null;
|
|
1393
|
+
const out = {};
|
|
1394
|
+
for (const line of text.split("\n")) {
|
|
1395
|
+
// Unindented `key: value` only — an indented line belongs to `dispatcher:`.
|
|
1396
|
+
const m = /^([a-z_]+):[ \t]+(.+?)[ \t]*$/.exec(line);
|
|
1397
|
+
if (!m) continue;
|
|
1398
|
+
const [, k, v] = m;
|
|
1399
|
+
if (k === "pid") { const n = Number(v); if (Number.isInteger(n) && n > 0) out.pid = n; }
|
|
1400
|
+
else if (k === "sdk_version") { const s = v.trim(); if (s && s !== "undefined" && s !== "null") out.sdkVersion = s; }
|
|
1401
|
+
// The three the resolver added so a version can be CHECKED and not merely
|
|
1402
|
+
// read. `sdk_version_agrees` is a tri-state written as a word: "unknown"
|
|
1403
|
+
// is not false and must never collapse to one.
|
|
1404
|
+
else if (k === "sdk_version_installed") { const s = v.trim(); if (s && s !== "undefined" && s !== "null") out.installedSdkVersion = s; }
|
|
1405
|
+
else if (k === "sdk_version_agrees") { const s = v.trim(); if (s === "true" || s === "false") out.versionsAgree = s === "true"; }
|
|
1406
|
+
else if (k === "sdk_version_drift") { const s = v.trim(); if (s && s !== "undefined" && s !== "null") out.versionDrift = s; }
|
|
1407
|
+
else if (k === "daemon_start") { const s = v.trim(); if (!Number.isNaN(Date.parse(s))) out.bootAt = new Date(Date.parse(s)).toISOString(); }
|
|
1408
|
+
else if (k === "updated") { const s = v.trim(); if (!Number.isNaN(Date.parse(s))) out.updatedAt = new Date(Date.parse(s)).toISOString(); }
|
|
1409
|
+
else if (k === "uptime_s") { const n = Number(v); if (Number.isFinite(n) && n >= 0) out.uptimeS = Math.floor(n); }
|
|
1410
|
+
}
|
|
1411
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
/** state/dashboards/daemon-health.yaml as text, or "" — fail-open. */
|
|
1415
|
+
function readDaemonHealthText(agentRoot) {
|
|
1416
|
+
if (!agentRoot) return "";
|
|
1417
|
+
try {
|
|
1418
|
+
return readFileSync(join(resolve(agentRoot), "state", "dashboards", "daemon-health.yaml"), "utf8");
|
|
1419
|
+
} catch { return ""; }
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Pure: the beat's `machine.daemon` — WHO is beating and whether the last health
|
|
1424
|
+
* gate believed it.
|
|
1425
|
+
*
|
|
1426
|
+
* WHY THIS FIELD EXISTS. `machine.sdkVersion` is the version INSTALLED on the
|
|
1427
|
+
* seat. It is not the version RUNNING: autoupdate installs into node_modules
|
|
1428
|
+
* while the old daemon process keeps executing the code it booted on, and a
|
|
1429
|
+
* hand-run `maestro upgrade` never restarts the daemon at all. One seat logged
|
|
1430
|
+
* "up to date" hourly for six days while its daemon crash-looped on the
|
|
1431
|
+
* previous version ~25 s at a time; the org saw nothing, because nothing the
|
|
1432
|
+
* beat carried could tell the two versions apart. `pid` + `bootAt` make the
|
|
1433
|
+
* distinction visible org-side: a pid that changes every beat is a crash loop,
|
|
1434
|
+
* and `sdkVersion` here differing from `machine.sdkVersion` is an installed-but-
|
|
1435
|
+
* not-restarted seat. Neither needs an ssh tour to see any more.
|
|
1436
|
+
*
|
|
1437
|
+
* ADDITIVE AND SMALL — six scalars, every one optional. It rides `machine`,
|
|
1438
|
+
* which hq validates as an OPEN record (`presence/beat.ts#statusSchema`), so it
|
|
1439
|
+
* lands the moment the daemon emits it and renders when the reader learns it.
|
|
1440
|
+
* It is NOT put on `session`, whose hq schema is `.strict()` and would refuse
|
|
1441
|
+
* the whole beat.
|
|
1442
|
+
*
|
|
1443
|
+
* FRESHNESS. `pid`/`bootAt`/`sdkVersion` describe the process that wrote the
|
|
1444
|
+
* dashboard, which a DEAD daemon leaves behind verbatim. `dashboardAt` is that
|
|
1445
|
+
* file's own stamp, carried so a reader can age the claim rather than trust it;
|
|
1446
|
+
* the ledger beat's server-stamped `at` remains the only liveness signal.
|
|
1447
|
+
*
|
|
1448
|
+
* @param {object|null} dash parsed daemon-health.yaml scalars, or null
|
|
1449
|
+
* @param {object|null} last state/autoupdate/last.json, or null
|
|
1450
|
+
* THE SEAT'S OWN VERDICT RIDES ALONG. `installedSdkVersion` + `versionsAgree`
|
|
1451
|
+
* are what the daemon's resolver concluded on the box, where both files are
|
|
1452
|
+
* readable; hq compares `machine.sdkVersion` against `machine.daemon.sdkVersion`
|
|
1453
|
+
* and reaches the same conclusion from the outside. Carrying both is not
|
|
1454
|
+
* redundancy — they are read at different instants from different files, and a
|
|
1455
|
+
* reader that sees them disagree has learned something real. `versionsAgree` is
|
|
1456
|
+
* carried ONLY as a real boolean: an inferred running version yields no verdict
|
|
1457
|
+
* at all, and absence must never read as agreement.
|
|
1458
|
+
*
|
|
1459
|
+
* @returns {{pid?:number, bootAt?:string, uptimeS?:number, sdkVersion?:string,
|
|
1460
|
+
* installedSdkVersion?:string, versionsAgree?:boolean,
|
|
1461
|
+
* versionDrift?:string, dashboardAt?:string, healthy?:boolean,
|
|
1462
|
+
* healthReason?:string}|null}
|
|
1463
|
+
*/
|
|
1464
|
+
export function daemonSummary(dash, last) {
|
|
1465
|
+
const out = {};
|
|
1466
|
+
if (dash && typeof dash === "object") {
|
|
1467
|
+
if (Number.isInteger(dash.pid) && dash.pid > 0) out.pid = dash.pid;
|
|
1468
|
+
if (typeof dash.bootAt === "string" && dash.bootAt) out.bootAt = dash.bootAt;
|
|
1469
|
+
if (Number.isFinite(dash.uptimeS) && dash.uptimeS >= 0) out.uptimeS = Math.floor(dash.uptimeS);
|
|
1470
|
+
if (typeof dash.sdkVersion === "string" && dash.sdkVersion) out.sdkVersion = dash.sdkVersion;
|
|
1471
|
+
if (typeof dash.installedSdkVersion === "string" && dash.installedSdkVersion) out.installedSdkVersion = dash.installedSdkVersion;
|
|
1472
|
+
if (typeof dash.versionsAgree === "boolean") out.versionsAgree = dash.versionsAgree;
|
|
1473
|
+
if (dash.versionsAgree === false && typeof dash.versionDrift === "string" && dash.versionDrift) out.versionDrift = dash.versionDrift.slice(0, 200);
|
|
1474
|
+
if (typeof dash.updatedAt === "string" && dash.updatedAt) out.dashboardAt = dash.updatedAt;
|
|
1475
|
+
}
|
|
1476
|
+
// The health GATE's verdict, as autoupdate.sh last recorded it
|
|
1477
|
+
// (`{from,to,at,ok,healthy,reason}`). `healthy` is the gate's answer about the
|
|
1478
|
+
// DAEMON — pid stability, no fatal line since boot, a server-acknowledged
|
|
1479
|
+
// beat — which is a different question from `upgrade.ok` (did the last install
|
|
1480
|
+
// land). Only a real boolean is carried: a record written before the gate
|
|
1481
|
+
// existed has no opinion, and absence must not read as "healthy".
|
|
1482
|
+
if (last && typeof last === "object" && typeof last.healthy === "boolean") {
|
|
1483
|
+
out.healthy = last.healthy;
|
|
1484
|
+
const reason = typeof last.reason === "string" ? last.reason.trim() : "";
|
|
1485
|
+
if (!last.healthy && reason) out.healthReason = reason.slice(0, 200);
|
|
1486
|
+
}
|
|
1487
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1313
1490
|
/** state/autoupdate/last.json, or null. */
|
|
1314
1491
|
function readAutoupdateLast(agentRoot) {
|
|
1315
1492
|
if (!agentRoot) return null;
|
|
@@ -1570,7 +1747,12 @@ function subscriptionModeFromEnv(agentRoot, env) {
|
|
|
1570
1747
|
function probeAuthForBeat(o, nowMs) {
|
|
1571
1748
|
if (o.probeClaude === false) return "unknown";
|
|
1572
1749
|
const agentRoot = resolve(o.agentRoot);
|
|
1573
|
-
|
|
1750
|
+
// W4 integration (row 25): an engine-cohort seat's probe is the engine's `auth status` — a
|
|
1751
|
+
// real call to the gateway that proves the seat credential — so it is asked whatever the
|
|
1752
|
+
// seat's Claude env says. A claude seat still probes only on the subscription path.
|
|
1753
|
+
let cohortSeat = false;
|
|
1754
|
+
try { cohortSeat = (o.seatEngine || readSeatEngine)(agentRoot) === "cohort"; } catch { cohortSeat = false; /* unreadable config: the default engine */ }
|
|
1755
|
+
if (!cohortSeat && !subscriptionModeFromEnv(agentRoot, o.env || process.env)) return "unknown";
|
|
1574
1756
|
const injected = typeof o.probeClaude === "function";
|
|
1575
1757
|
if (!injected) {
|
|
1576
1758
|
const hit = _authProbeMemo.get(agentRoot);
|
|
@@ -1737,6 +1919,21 @@ export async function collectStatus(o = {}) {
|
|
|
1737
1919
|
if (up) machine.upgrade = up;
|
|
1738
1920
|
} catch { /* no upgrade field */ }
|
|
1739
1921
|
|
|
1922
|
+
// 4d. WHO is beating — `machine.daemon` {pid, bootAt, uptimeS, sdkVersion,
|
|
1923
|
+
// dashboardAt, healthy?, healthReason?}. This is what makes fleet version
|
|
1924
|
+
// drift a QUERY instead of an ssh tour: `machine.sdkVersion` is what is
|
|
1925
|
+
// INSTALLED, `machine.daemon.sdkVersion` is what is RUNNING, and a pid that
|
|
1926
|
+
// moves every beat is a crash loop. Fail-open in the same way every other
|
|
1927
|
+
// probe here is — a throw drops the field, never the beat.
|
|
1928
|
+
try {
|
|
1929
|
+
const dash = opt.daemonDashboard !== undefined
|
|
1930
|
+
? opt.daemonDashboard
|
|
1931
|
+
: parseDaemonHealthYaml(readDaemonHealthText(opt.agentRoot));
|
|
1932
|
+
const last = opt.autoupdateLast !== undefined ? opt.autoupdateLast : readAutoupdateLast(opt.agentRoot);
|
|
1933
|
+
const d = daemonSummary(dash, last);
|
|
1934
|
+
if (d) machine.daemon = d;
|
|
1935
|
+
} catch { /* no daemon field */ }
|
|
1936
|
+
|
|
1740
1937
|
const status = {
|
|
1741
1938
|
state,
|
|
1742
1939
|
activity: act.activity || "idle",
|
|
@@ -1782,6 +1979,8 @@ export const _internals = {
|
|
|
1782
1979
|
sessionJobInstalled,
|
|
1783
1980
|
readSessionAttention,
|
|
1784
1981
|
upgradeSummary,
|
|
1982
|
+
parseDaemonHealthYaml,
|
|
1983
|
+
daemonSummary,
|
|
1785
1984
|
detectClaudeAuth,
|
|
1786
1985
|
resetAuthProbeCache,
|
|
1787
1986
|
scanForRelogin,
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/upgrade/ignored-drift.mjs — what a `.maestroignore`-protected file is
|
|
3
|
+
* missing from upstream, said per file.
|
|
4
|
+
*
|
|
5
|
+
* `maestro upgrade` never touches a path `.maestroignore` names — that is the
|
|
6
|
+
* file's whole purpose. Until this module, the summary said only "14 ignored
|
|
7
|
+
* (.maestroignore protected)": a count, with no way to tell from the log
|
|
8
|
+
* whether a protected fork was one line behind upstream or a whole release
|
|
9
|
+
* behind. On one seat the protected daemon lacked 24 upstream references to a
|
|
10
|
+
* feature the release notes said had shipped, and nothing in any upgrade log
|
|
11
|
+
* said so. A protected file is a fork the operator owns, and an owner needs a
|
|
12
|
+
* per-file answer to "how far has upstream moved under this?".
|
|
13
|
+
*
|
|
14
|
+
* `classifyIgnored` is PURE over the two texts (either may be null for absent)
|
|
15
|
+
* and answers one of:
|
|
16
|
+
*
|
|
17
|
+
* identical — the protection is currently idle (safe to drop the entry)
|
|
18
|
+
* local-only — the seat has it, upstream ships nothing at that path
|
|
19
|
+
* upstream-only — upstream ships it, the seat has never taken it
|
|
20
|
+
* drifts — both exist and differ: `onlyHere` / `onlyUpstream` are
|
|
21
|
+
* the line counts each side has that the other does not
|
|
22
|
+
*
|
|
23
|
+
* The line counts are a MULTISET difference, not an edit script: cheap, stable
|
|
24
|
+
* across a whole tree, and honest about what they are — a size of drift, not a
|
|
25
|
+
* patch. A moved block counts as zero drift, which is the right answer for
|
|
26
|
+
* "is upstream's fix in here?" and the wrong one for "is this file identical?"
|
|
27
|
+
* (that is `identical`, decided by bytes first).
|
|
28
|
+
*
|
|
29
|
+
* @module lib/upgrade/ignored-drift
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
"use strict";
|
|
33
|
+
|
|
34
|
+
/** Where `maestro upgrade` writes the report, relative to the agent root. */
|
|
35
|
+
export const IGNORED_DRIFT_REL = ".maestro/ignored-drift.json";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Multiset line difference of two texts.
|
|
39
|
+
* @param {string} a
|
|
40
|
+
* @param {string} b
|
|
41
|
+
* @returns {{onlyA:number, onlyB:number}}
|
|
42
|
+
*/
|
|
43
|
+
export function lineDrift(a, b) {
|
|
44
|
+
const count = (text) => {
|
|
45
|
+
const m = new Map();
|
|
46
|
+
for (const line of String(text).split("\n")) m.set(line, (m.get(line) || 0) + 1);
|
|
47
|
+
return m;
|
|
48
|
+
};
|
|
49
|
+
const ma = count(a);
|
|
50
|
+
const mb = count(b);
|
|
51
|
+
let onlyA = 0;
|
|
52
|
+
let onlyB = 0;
|
|
53
|
+
for (const [line, n] of ma) onlyA += Math.max(0, n - (mb.get(line) || 0));
|
|
54
|
+
for (const [line, n] of mb) onlyB += Math.max(0, n - (ma.get(line) || 0));
|
|
55
|
+
return { onlyA, onlyB };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Classify one protected path.
|
|
60
|
+
* @param {string} path repo-relative path (reported back verbatim)
|
|
61
|
+
* @param {string|null} localText the seat's bytes, or null when absent
|
|
62
|
+
* @param {string|null} upstreamText the package's bytes, or null when absent
|
|
63
|
+
* @returns {{path:string, state:"identical"|"local-only"|"upstream-only"|"drifts", onlyHere?:number, onlyUpstream?:number}}
|
|
64
|
+
*/
|
|
65
|
+
export function classifyIgnored(path, localText, upstreamText) {
|
|
66
|
+
const hasLocal = typeof localText === "string";
|
|
67
|
+
const hasUpstream = typeof upstreamText === "string";
|
|
68
|
+
if (hasLocal && !hasUpstream) return { path, state: "local-only" };
|
|
69
|
+
if (!hasLocal && hasUpstream) return { path, state: "upstream-only" };
|
|
70
|
+
if (!hasLocal && !hasUpstream) return { path, state: "local-only" }; // named in .maestroignore, present nowhere — the entry is idle
|
|
71
|
+
if (localText === upstreamText) return { path, state: "identical" };
|
|
72
|
+
const d = lineDrift(localText, upstreamText);
|
|
73
|
+
return { path, state: "drifts", onlyHere: d.onlyA, onlyUpstream: d.onlyB };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Build the whole report.
|
|
78
|
+
* @param {Array<{path:string, local:string|null, upstream:string|null}>} entries
|
|
79
|
+
* @param {{sdkVersion?:string, at?:string}} [meta]
|
|
80
|
+
*/
|
|
81
|
+
export function buildIgnoredDriftReport(entries, meta = {}) {
|
|
82
|
+
const files = entries.map((e) => classifyIgnored(e.path, e.local, e.upstream));
|
|
83
|
+
const counts = { identical: 0, "local-only": 0, "upstream-only": 0, drifts: 0 };
|
|
84
|
+
for (const f of files) counts[f.state] += 1;
|
|
85
|
+
return {
|
|
86
|
+
sdkVersion: meta.sdkVersion || null,
|
|
87
|
+
at: meta.at || null,
|
|
88
|
+
counts,
|
|
89
|
+
files,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* One log line per protected file, for the upgrade summary.
|
|
95
|
+
* @param {{path:string, state:string, onlyHere?:number, onlyUpstream?:number}} f
|
|
96
|
+
*/
|
|
97
|
+
export function formatIgnoredLine(f) {
|
|
98
|
+
switch (f.state) {
|
|
99
|
+
case "identical": return ` = ${f.path} (identical to upstream — the entry is idle)`;
|
|
100
|
+
case "local-only": return ` · ${f.path} (upstream ships nothing here)`;
|
|
101
|
+
case "upstream-only": return ` ! ${f.path} (upstream ships it; this seat has never taken it)`;
|
|
102
|
+
case "drifts": return ` ~ ${f.path} (drifts: ${f.onlyUpstream} upstream line${f.onlyUpstream === 1 ? "" : "s"} not here, ${f.onlyHere} local line${f.onlyHere === 1 ? "" : "s"} not upstream)`;
|
|
103
|
+
default: return ` ? ${f.path}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -37,6 +37,8 @@ import { spawn } from "node:child_process";
|
|
|
37
37
|
import { writeFileSync, readFileSync, mkdirSync, existsSync, appendFileSync } from "node:fs";
|
|
38
38
|
import { join, resolve, dirname } from "node:path";
|
|
39
39
|
import { writeJsonAtomic } from "../fs-atomic.mjs";
|
|
40
|
+
import { buildSpawn } from "../runtime/adapter.mjs";
|
|
41
|
+
import { resolveSeatSpawn } from "../runtime/seat-engine.mjs";
|
|
40
42
|
|
|
41
43
|
const BRIEF_PROMPT = `You are an executive operator processing the transcript of a voice call.
|
|
42
44
|
Produce a structured post-call brief in JSON only — no preamble, no commentary.
|
|
@@ -166,25 +168,36 @@ export async function generateBrief(opts = {}) {
|
|
|
166
168
|
// Claude --print runner (single-shot, JSON-only output)
|
|
167
169
|
// ---------------------------------------------------------------------------
|
|
168
170
|
|
|
169
|
-
|
|
171
|
+
/**
|
|
172
|
+
* The voice-brief spawn for this seat (conformance row 36). Binary + argv + env
|
|
173
|
+
* from the runtime adapter (lane "voice-brief"), with the seat's engine:
|
|
174
|
+
* claude --print --dangerously-skip-permissions --strict-mcp-config --model <m>
|
|
175
|
+
* <prompt>, env {...env, AGENT_ROOT, AGENT_DIR}; the binary resolved
|
|
176
|
+
* by claude-bin (a safe $CLAUDE_BIN, then the known install paths)
|
|
177
|
+
* instead of a bare `claude`, which ENOENTs under launchd. The
|
|
178
|
+
* buildSpawn input is exactly what it was before the seat was read.
|
|
179
|
+
* cohort `node lib/engine/cli.mjs run -p …` with the seat token and every
|
|
180
|
+
* Anthropic/Claude credential scrubbed; no token → a refused spec
|
|
181
|
+
* (the caller writes the fallback brief), never claude.
|
|
182
|
+
* @param {{agentRoot:string, model:string, prompt:string, env:object}} o
|
|
183
|
+
* @param {{resolveSeatSpawn?:Function, buildSpawn?:Function, adapterDeps?:object}} [deps]
|
|
184
|
+
*/
|
|
185
|
+
export async function briefSpawnSpec({ agentRoot, model, prompt, env }, deps = {}) {
|
|
186
|
+
const seat = await (deps.resolveSeatSpawn || resolveSeatSpawn)(agentRoot);
|
|
187
|
+
return (deps.buildSpawn || buildSpawn)({ lane: "voice-brief", model, prompt, mcp: "strict", agentRoot, env, ...seat.fields }, deps.adapterDeps);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function runClaudeBrief({ agentRoot, model, systemPrompt, input }) {
|
|
191
|
+
const fullPrompt = `${systemPrompt}\n\n---\n${input}`;
|
|
192
|
+
const spec = await briefSpawnSpec({ agentRoot, model, prompt: fullPrompt, env: process.env });
|
|
170
193
|
return new Promise((resolveP) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"--strict-mcp-config",
|
|
177
|
-
"--model", model,
|
|
178
|
-
fullPrompt,
|
|
179
|
-
], {
|
|
194
|
+
if (!spec.ok) {
|
|
195
|
+
resolveP(fallbackBrief(input, spec.error.message));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const proc = spawn(spec.bin, spec.argv, {
|
|
180
199
|
cwd: agentRoot,
|
|
181
|
-
env:
|
|
182
|
-
...process.env,
|
|
183
|
-
AGENT_ROOT: agentRoot,
|
|
184
|
-
AGENT_DIR: agentRoot,
|
|
185
|
-
// Voice briefs are routine summarization; let model router pick
|
|
186
|
-
// the cheap backend by signalling it as a "fast" tier task.
|
|
187
|
-
},
|
|
200
|
+
env: spec.env,
|
|
188
201
|
stdio: ["ignore", "pipe", "pipe"],
|
|
189
202
|
});
|
|
190
203
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cohortapp/agent-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.4",
|
|
4
4
|
"description": "Cohort Agent SDK — autonomous AI colleague runtime. Deploy senior AI colleagues on dedicated Mac minis, wired to the Cohort operating surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -114,18 +114,28 @@
|
|
|
114
114
|
".claude/settings.json",
|
|
115
115
|
".env.example",
|
|
116
116
|
"README.md",
|
|
117
|
-
"framework-features.json"
|
|
117
|
+
"framework-features.json",
|
|
118
|
+
"!**/*.test.mjs",
|
|
119
|
+
"!**/*.test.js",
|
|
120
|
+
"!**/fixtures/**",
|
|
121
|
+
"!**/test-fixtures/**",
|
|
122
|
+
"!**/__fixtures__/**",
|
|
123
|
+
"!test/**",
|
|
124
|
+
"!scripts/eval/replay/examples/**"
|
|
118
125
|
],
|
|
119
126
|
"publishConfig": {
|
|
120
127
|
"access": "public",
|
|
121
128
|
"registry": "https://registry.npmjs.org/"
|
|
122
129
|
},
|
|
123
130
|
"scripts": {
|
|
131
|
+
"fleet:rollout": "node scripts/fleet/rollout.mjs",
|
|
124
132
|
"test": "node scripts/ci/run-tests.mjs",
|
|
125
133
|
"test:coverage": "node scripts/ci/run-coverage.mjs",
|
|
126
|
-
"test:list": "node
|
|
134
|
+
"test:list": "node scripts/ci/run-tests.mjs --list",
|
|
127
135
|
"test:setup": "node --test lib/setup/io.test.mjs lib/setup/state.test.mjs lib/setup/sot.test.mjs lib/setup/completeness.test.mjs lib/setup/context-pack.test.mjs lib/setup/enrich.test.mjs lib/setup/runner.test.mjs lib/setup/integration.test.mjs lib/setup/sections/subagents.test.mjs",
|
|
128
136
|
"check": "node scripts/ci/check.mjs",
|
|
137
|
+
"test:engine-conformance": "node test/engine-conformance/run.mjs",
|
|
138
|
+
"eval:replay": "node scripts/eval/replay/run.mjs",
|
|
129
139
|
"conformance:org": "node scripts/ci/conformance-org-api.mjs",
|
|
130
140
|
"conformance:org:write": "node scripts/ci/conformance-org-api.mjs --write",
|
|
131
141
|
"test:router": "node --test lib/model-router.test.mjs lib/model-router/catalog.test.mjs lib/model-router/economics.test.mjs lib/model-router/failover.test.mjs lib/model-router/health.test.mjs lib/model-router/integration.test.mjs lib/model-router/integration-coverage.test.mjs lib/model-router/ledger.test.mjs lib/model-router/llm-task.test.mjs lib/model-router/org-credentials.test.mjs lib/model-router/reconcile.test.mjs lib/model-router/repair.test.mjs lib/model-router/spawn.test.mjs lib/model-router/taxonomy.test.mjs scripts/cost/fleet-digest.test.mjs",
|
|
@@ -54,6 +54,11 @@ accepted` (or `maestro board track <inbox-id> --stage accepted --title …
|
|
|
54
54
|
the message and dedupes, so a re-delivered ask finds the same row. See
|
|
55
55
|
`inbound-triage`.
|
|
56
56
|
|
|
57
|
+
If you got the ask through the inbox, `maestro inbox claim <id>` has ALREADY
|
|
58
|
+
filed it — and `--title` / `--why` are read only by the step that opens the
|
|
59
|
+
row, so they belong on that claim (`maestro inbox claim <id> --title … --why
|
|
60
|
+
…`). Sending them later, against a row that exists, is accepted and ignored.
|
|
61
|
+
|
|
57
62
|
## What not to do
|
|
58
63
|
|
|
59
64
|
- Do not narrate every step on the board; the board is for the state a
|
|
@@ -11,26 +11,39 @@ no: see "The one-interim rule" at the foot of this skill.
|
|
|
11
11
|
|
|
12
12
|
## The three outcomes
|
|
13
13
|
|
|
14
|
+
> **The board row is automatic — you do not open it.** `maestro inbox claim`
|
|
15
|
+
> opens the row and puts it in `running`, `reply` closes it with what you said,
|
|
16
|
+
> `done` closes it if you never replied, and `defer` parks it in `blocked` with
|
|
17
|
+
> your reason. The server's own gate decides whether an ask deserves a row at
|
|
18
|
+
> all, from the text, so a claimed one-line question mints nothing. Use
|
|
19
|
+
> `maestro board track` only to say something the four commands cannot: a
|
|
20
|
+
> `--stage blocked` with `notify` when you need unblocking mid-work, or a
|
|
21
|
+
> `--stage review` when a human should look before it goes out.
|
|
22
|
+
|
|
14
23
|
1. **Reply now.** The ask is answerable in one message from what you already
|
|
15
24
|
know or can look up in under a minute (a status, a fact, a yes/no, a link,
|
|
16
25
|
a short opinion). `maestro inbox claim <id>` → `maestro inbox reply <id>
|
|
17
|
-
--text "…"` → `maestro inbox done <id>`. No board row: the
|
|
18
|
-
|
|
26
|
+
--text "…"` → `maestro inbox done <id>`. No board row: the server's gate
|
|
27
|
+
reads the text as answerable in the turn and mints nothing.
|
|
19
28
|
|
|
20
29
|
2. **File it, work here.** The ask needs real work — reading, drafting,
|
|
21
30
|
building, several steps — but you can finish it in this session inside an
|
|
22
31
|
hour or two without blocking the front door. In ONE turn:
|
|
23
|
-
- `maestro inbox claim <id>`
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
- `maestro inbox claim <id>` — this opens the row and puts it in `running`.
|
|
33
|
+
If the row deserves a better name than the ask's own first sentence, say
|
|
34
|
+
so ON THE CLAIM: `maestro inbox claim <id> --title "<what you took on>"
|
|
35
|
+
--why "<one line: why this is more than a reply>"`. The claim is the only
|
|
36
|
+
moment either is read — the server writes the title and the reason when
|
|
37
|
+
the row OPENS and protects them afterwards, so a later `maestro board
|
|
38
|
+
track … --title/--why` on the same ask is accepted and changes nothing.
|
|
26
39
|
- then run the work — a `Workflow` when it has distinct steps, plain tool
|
|
27
|
-
use when it does not. Track
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
use when it does not. Track only what the four inbox commands cannot say:
|
|
41
|
+
`--stage blocked` (say what you need, `notify` who can unblock) when
|
|
42
|
+
stuck, `--stage review` when a human should look before it goes out.
|
|
43
|
+
- report back in the SAME channel/thread with `maestro inbox reply <id>`,
|
|
44
|
+
which closes the row and tags the channel, then `maestro inbox done <id>`.
|
|
45
|
+
If you reported with `messaging_send` instead, `maestro inbox done <id>`
|
|
46
|
+
is what closes the row.
|
|
34
47
|
|
|
35
48
|
3. **File it, hand to a peer.** Same as 2, but the work is long (hours), heavy
|
|
36
49
|
(a repo build, a large research pass), or would block you from answering the
|
|
@@ -39,13 +52,14 @@ no: see "The one-interim rule" at the foot of this skill.
|
|
|
39
52
|
with a prompt that names the deliverable, the channel and thread to report
|
|
40
53
|
to, the inbox id, and the instruction to `SendMessage` you a two-line
|
|
41
54
|
status when done. You stay the one who talks to the human; the peer talks to
|
|
42
|
-
you. When it reports back, you send the result and close the
|
|
43
|
-
(
|
|
55
|
+
you. When it reports back, you send the result and close the item
|
|
56
|
+
(`maestro inbox reply` then `maestro inbox done <id>`), which closes the row.
|
|
44
57
|
|
|
45
58
|
## How to pick
|
|
46
59
|
|
|
47
60
|
- Would a competent colleague answer this from their chair in one message?
|
|
48
|
-
→ reply now.
|
|
61
|
+
→ reply now. A "what are you doing / working on right now?" is this kind:
|
|
62
|
+
answer it from `maestro session status` (`currentWork`), never from memory.
|
|
49
63
|
- Does it produce an artefact (a doc, a deck, a number that needs checking, a
|
|
50
64
|
change in a system)? → file it. The server derives the board from the
|
|
51
65
|
message: a DM's ask lands on that conversation's board, a space's ask on the
|
|
@@ -56,6 +70,33 @@ no: see "The one-interim rule" at the foot of this skill.
|
|
|
56
70
|
and say in-channel what you need and from whom. That is a message with
|
|
57
71
|
content in it, so it is always worth sending; do not guess.
|
|
58
72
|
|
|
73
|
+
## Addressed to the whole room (`collective` on the feed line)
|
|
74
|
+
|
|
75
|
+
A message a human sent to everyone carries `collective` on its `inbound` line:
|
|
76
|
+
`roll-call`, `work`, or `ambient`. It is empty for a DM, an @mention or a task.
|
|
77
|
+
Nobody was named, so nobody is more responsible than you: **you answer for your
|
|
78
|
+
own seat, and you never answer for anyone else's.**
|
|
79
|
+
|
|
80
|
+
- `collective: roll-call` — "can everyone give me an update on what they're
|
|
81
|
+
doing right now?" → **outcome 1**. Answer from `maestro session status`
|
|
82
|
+
(`currentWork`) in at most five short lines: what you are on, what is queued,
|
|
83
|
+
what is blocked. No board row — reporting on yourself is not work. Do not
|
|
84
|
+
summarise, guess at or speak for any colleague; they answer for themselves.
|
|
85
|
+
- `collective: work` — "everyone, please review the binder by Friday" → **outcome
|
|
86
|
+
2 or 3**, exactly as if it had been addressed to you alone. Claim it, `board
|
|
87
|
+
track --stage accepted`, do YOUR slice, and reply with what you will do and by
|
|
88
|
+
when. The board row is yours and covers your slice only; twelve other seats
|
|
89
|
+
are opening twelve other rows for the same message and that is correct.
|
|
90
|
+
- `collective: ambient` — the room was addressed and nothing was asked of you
|
|
91
|
+
("everyone should take a look sometime", "FYI the binder is up"). **Outcome 1
|
|
92
|
+
at most, and usually silence.** Do not mint work from it. A board that grows a
|
|
93
|
+
row per seat per aside is a board nobody opens by the end of the week.
|
|
94
|
+
|
|
95
|
+
Why it is on the line at all: when your front door is live the daemon does not
|
|
96
|
+
dispatch these items, so there is no other plane that will act on them. If the
|
|
97
|
+
field is missing or empty on a message that plainly addressed the room, treat it
|
|
98
|
+
as `ambient` and use your judgement — it is a hint, not an instruction.
|
|
99
|
+
|
|
59
100
|
## Special topics
|
|
60
101
|
|
|
61
102
|
- **Calls** (`topic: call`): answer in the channel — join if you are free now,
|