@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
|
@@ -54,6 +54,12 @@
|
|
|
54
54
|
"use strict";
|
|
55
55
|
|
|
56
56
|
import { SURFACES } from "./surfaces.mjs";
|
|
57
|
+
import { isBroadcast, BROADCAST_KIND, BROADCAST_REASON } from "./broadcast.mjs";
|
|
58
|
+
|
|
59
|
+
// The collective-address vocabulary lives in ONE place (`broadcast.mjs`, with an
|
|
60
|
+
// hq twin at `src/server/llm-responder/broadcast.ts`); re-exported here so the
|
|
61
|
+
// daemon and the tests keep a single import for "is this mine, and why".
|
|
62
|
+
export { isBroadcast, BROADCAST_PATTERNS, BROADCAST_CORPUS } from "./broadcast.mjs";
|
|
57
63
|
|
|
58
64
|
/** Channel kinds where every message is addressed to the room. */
|
|
59
65
|
export const PRIVATE_ROOM_KINDS = Object.freeze(["DM", "GROUP_DM", "HUDDLE"]);
|
|
@@ -68,9 +74,12 @@ export const MEMBERSHIP_REQUIRED_KINDS = Object.freeze([
|
|
|
68
74
|
* The typed reasons a verdict can carry. A daemon switches on `reason` for
|
|
69
75
|
* triage; it is a closed set so a new value is a deliberate, reviewable change.
|
|
70
76
|
*
|
|
71
|
-
* @typedef {"dm"|"mention"|"thread"|"channel"|"participant"
|
|
72
|
-
* |"reviewer"|"direct"|"requester"|"approver"|"proposer"
|
|
73
|
-
* |"owner"|"shared"|"waiting_on"|"task"|"named"} Reason
|
|
77
|
+
* @typedef {"dm"|"mention"|"collective"|"thread"|"channel"|"participant"
|
|
78
|
+
* |"assignee"|"reviewer"|"direct"|"requester"|"approver"|"proposer"
|
|
79
|
+
* |"commenter"|"owner"|"shared"|"waiting_on"|"task"|"named"} Reason
|
|
80
|
+
*
|
|
81
|
+
* `collective` — a HUMAN addressed the whole room I am in ("everyone",
|
|
82
|
+
* "@here", "roll call"); surface `broadcast`. See broadcast.mjs.
|
|
74
83
|
*/
|
|
75
84
|
|
|
76
85
|
/** Narrow an unknown payload to a readable record (never throws). */
|
|
@@ -168,7 +177,7 @@ export function classifyEvent(ev) {
|
|
|
168
177
|
return {
|
|
169
178
|
...base,
|
|
170
179
|
topic: "message",
|
|
171
|
-
surfaces: ["dm", "mention", "thread_reply"],
|
|
180
|
+
surfaces: ["dm", "mention", "broadcast", "thread_reply"],
|
|
172
181
|
ids: {
|
|
173
182
|
channelId,
|
|
174
183
|
channelKind: String(p.channelKind || p.channel_kind || "").toUpperCase() || undefined,
|
|
@@ -179,6 +188,9 @@ export function classifyEvent(ev) {
|
|
|
179
188
|
// mention or a thread reply, so it can be dropped WITHOUT paging the
|
|
180
189
|
// channel at all. That single test is what keeps mention-detection from
|
|
181
190
|
// costing one `messaging.history` per busy public channel per pull.
|
|
191
|
+
// The ONE exception is a HUMAN-authored space post, which may still be a
|
|
192
|
+
// broadcast ("everyone …") — see `needsSpaceProbe`, which lets exactly
|
|
193
|
+
// those through for hydration and still drops agent-authored ones.
|
|
182
194
|
hints: {
|
|
183
195
|
mentionCount: Number.isFinite(Number(p.mentionCount)) ? Number(p.mentionCount) : undefined,
|
|
184
196
|
threaded: typeof p.threaded === "boolean" ? p.threaded : undefined,
|
|
@@ -522,6 +534,11 @@ function resolveCalendar(cand, me, facts, on) {
|
|
|
522
534
|
* 2. private room + I am a member → `dm`
|
|
523
535
|
* 3. private room + I am NOT a member → NOT directed (hard stop)
|
|
524
536
|
* 4. private SPACE + I am not a member → NOT directed (hard stop)
|
|
537
|
+
* 4b. a HUMAN's un-threaded, un-mentioning post to the WHOLE ROOM
|
|
538
|
+
* ("everyone", "@here", "roll call" …) in a space I am a member of
|
|
539
|
+
* → `broadcast` (reason `collective`)
|
|
540
|
+
* — decided BEFORE the structural count drop, because the drop is
|
|
541
|
+
* exactly what silenced thirteen seats on 2026-09-21.
|
|
525
542
|
* 5. mentions[] (from history) names me → `mention`
|
|
526
543
|
* 6. thread root I have spoken in / been named in → `thread_reply`
|
|
527
544
|
* 7. otherwise → ambient chatter, not directed
|
|
@@ -557,12 +574,26 @@ function resolveMessaging(cand, me, facts, on) {
|
|
|
557
574
|
// membership-required — the conservative branch.
|
|
558
575
|
if (!channelKind && !has(members, channelId)) return no("channel_kind_unknown");
|
|
559
576
|
|
|
577
|
+
const msg = lookupMessage(facts, channelId, cand.ids.messageId);
|
|
578
|
+
|
|
579
|
+
// (4b) BROADCAST — a human addressed the whole room. This sits ABOVE the
|
|
580
|
+
// structural drop on purpose: the drop reasons from `mentionCount: 0`,
|
|
581
|
+
// and a roll-call has, by construction, zero mentions. It is gated on
|
|
582
|
+
// every condition the vocabulary module documents — human author, a
|
|
583
|
+
// space I am a MEMBER of (a public room I merely see does not address
|
|
584
|
+
// me), not threaded, and no structured mention of anyone (a message that
|
|
585
|
+
// @-names specific people chose them; "everyone" inside it is prose).
|
|
586
|
+
// A DM never reaches this line: (2) returned `dm` above.
|
|
587
|
+
if (msg && isBroadcastFor(cand, msg, channelId, members, facts)) {
|
|
588
|
+
return on(BROADCAST_KIND) ? yes(BROADCAST_KIND, BROADCAST_REASON) : no("surface_disabled");
|
|
589
|
+
}
|
|
590
|
+
|
|
560
591
|
// Cheap structural drop from the redacted counts, BEFORE any hydration: a
|
|
561
|
-
// space message that mentions nobody and is not threaded cannot be mine
|
|
592
|
+
// space message that mentions nobody and is not threaded cannot be mine —
|
|
593
|
+
// unless a human wrote it, in which case `needsSpaceProbe` answered `null`
|
|
594
|
+
// (page it) and we reach here with the body in hand to say so either way.
|
|
562
595
|
if (needsSpaceProbe(cand, facts) === false) return no("no_mentions_not_threaded");
|
|
563
596
|
|
|
564
|
-
const msg = lookupMessage(facts, channelId, cand.ids.messageId);
|
|
565
|
-
|
|
566
597
|
// (5) An explicit @mention of my member id. The mention list is NOT in the
|
|
567
598
|
// chain payload; it comes from `messaging.history`, which hq ACLs to rooms
|
|
568
599
|
// I may read.
|
|
@@ -764,8 +795,16 @@ function resolveApproval(cand, me, facts, on) {
|
|
|
764
795
|
* Prose-name matching, when the caller enabled it, always needs the body — so a
|
|
765
796
|
* caller with `myNames` gets `null` rather than `false`.
|
|
766
797
|
*
|
|
798
|
+
* A HUMAN-authored post with zero mentions and no thread is the shape of a
|
|
799
|
+
* broadcast ("everyone, status?"), and only the body can tell. So when
|
|
800
|
+
* `facts.memberKinds` PROVES the actor is a human the answer is `null` — page
|
|
801
|
+
* it — while an agent-authored one, or one whose author kind is unknown (the
|
|
802
|
+
* `member.list` read failed, or the surface is off so it was never made),
|
|
803
|
+
* keeps today's `false`. That is the cheapest correct thing: the extra history
|
|
804
|
+
* page is spent only on posts a person wrote, never on agent chatter.
|
|
805
|
+
*
|
|
767
806
|
* @param {Candidate} cand
|
|
768
|
-
* @param {{myNames?: string[]}} [facts]
|
|
807
|
+
* @param {{myNames?: string[], memberKinds?: Map<string,string>|null}} [facts]
|
|
769
808
|
* @returns {boolean|null}
|
|
770
809
|
*/
|
|
771
810
|
export function needsSpaceProbe(cand, facts = {}) {
|
|
@@ -774,9 +813,55 @@ export function needsSpaceProbe(cand, facts = {}) {
|
|
|
774
813
|
if (h.mentionCount === undefined || h.threaded === undefined) return null;
|
|
775
814
|
if (h.mentionCount > 0) return true;
|
|
776
815
|
if (h.threaded) return true;
|
|
816
|
+
if (authorKindOf(facts, cand && cand.actor) === "HUMAN") return null;
|
|
777
817
|
return false;
|
|
778
818
|
}
|
|
779
819
|
|
|
820
|
+
/**
|
|
821
|
+
* The org-directory kind ("HUMAN" | "AI_AGENT" | …) of a member id or slug, from
|
|
822
|
+
* the ONE `member.list` read `facts.mjs` makes per pull. `""` when unknown —
|
|
823
|
+
* and unknown is never treated as human.
|
|
824
|
+
*
|
|
825
|
+
* @param {{memberKinds?: Map<string,string>|null}} facts
|
|
826
|
+
* @param {unknown} id
|
|
827
|
+
* @returns {string}
|
|
828
|
+
*/
|
|
829
|
+
export function authorKindOf(facts, id) {
|
|
830
|
+
const kinds = facts && facts.memberKinds instanceof Map ? facts.memberKinds : null;
|
|
831
|
+
const key = id == null ? "" : String(id).trim();
|
|
832
|
+
if (!kinds || !key) return "";
|
|
833
|
+
return String(kinds.get(key) || kinds.get(key.toLowerCase()) || "").toUpperCase();
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Conditions 1–3 of the broadcast rule (see broadcast.mjs), joined with the
|
|
838
|
+
* body test. `msg` is the hydrated history row — the body never enters the
|
|
839
|
+
* chain, so this can only ever be asked after paging.
|
|
840
|
+
*
|
|
841
|
+
* @param {Candidate} cand
|
|
842
|
+
* @param {object} msg the hydrated message row
|
|
843
|
+
* @param {string} channelId
|
|
844
|
+
* @param {Set<string>|null} members proven memberships (null == unknown)
|
|
845
|
+
* @param {import("./facts.mjs").Facts} facts
|
|
846
|
+
* @returns {boolean}
|
|
847
|
+
*/
|
|
848
|
+
export function isBroadcastFor(cand, msg, channelId, members, facts) {
|
|
849
|
+
if (!msg || !cand) return false;
|
|
850
|
+
// (2) a space I am a MEMBER of. `members` for a PUBLIC room is populated only
|
|
851
|
+
// from hq's own `joined` flag, so visibility alone never qualifies.
|
|
852
|
+
if (!has(members, channelId)) return false;
|
|
853
|
+
// (3) not threaded — a thread reply keeps the thread rule.
|
|
854
|
+
if (msg.threadRootId || msg.thread_root_id) return false;
|
|
855
|
+
if (cand.hints && cand.hints.threaded === true) return false;
|
|
856
|
+
// A message that structurally @-names people is addressed to THEM.
|
|
857
|
+
if (Array.isArray(msg.mentions) && msg.mentions.length > 0) return false;
|
|
858
|
+
// (1) the author is a HUMAN — proven by the directory, never assumed.
|
|
859
|
+
const author = msg.authorId || msg.author || cand.actor;
|
|
860
|
+
if (authorKindOf(facts, author) !== "HUMAN") return false;
|
|
861
|
+
// (4) the body names the whole room.
|
|
862
|
+
return isBroadcast(msg.body ?? msg.text);
|
|
863
|
+
}
|
|
864
|
+
|
|
780
865
|
/** Find a hydrated message row in `facts.channelPages`. */
|
|
781
866
|
export function lookupMessage(facts, channelId, messageId) {
|
|
782
867
|
if (!(facts.channelPages instanceof Map) || !channelId || !messageId) return null;
|
|
@@ -847,6 +932,9 @@ export default {
|
|
|
847
932
|
coordsOf,
|
|
848
933
|
asSet,
|
|
849
934
|
needsSpaceProbe,
|
|
935
|
+
authorKindOf,
|
|
936
|
+
isBroadcastFor,
|
|
937
|
+
isBroadcast,
|
|
850
938
|
lookupMessage,
|
|
851
939
|
matchesMyName,
|
|
852
940
|
taskIdFromFileKey,
|
|
@@ -79,6 +79,8 @@ export const DEFAULT_LIMITS = Object.freeze({
|
|
|
79
79
|
* @property {Map<string,object>|null} fileAcl fileId → {ownerId, shared, mentionsMe, kind}
|
|
80
80
|
* @property {Set<string>|null} myEventIds calendar events I own or attend (null == unreadable)
|
|
81
81
|
* @property {Map<string,object>|null} myEvents eventId → the calendar event DTO
|
|
82
|
+
* @property {Map<string,string>|null} memberKinds member id AND slug → "HUMAN"|"AI_AGENT" (null == not read / unreadable)
|
|
83
|
+
* @property {number|null} aiMemberCount how many AI_AGENT members the org has (the roll-call respondent bound)
|
|
82
84
|
* @property {string[]} degraded names of facts that could not be read
|
|
83
85
|
*/
|
|
84
86
|
|
|
@@ -131,6 +133,8 @@ export async function resolveFacts(o = {}) {
|
|
|
131
133
|
fileAcl: null,
|
|
132
134
|
myEventIds: null,
|
|
133
135
|
myEvents: null,
|
|
136
|
+
memberKinds: null,
|
|
137
|
+
aiMemberCount: null,
|
|
134
138
|
degraded,
|
|
135
139
|
};
|
|
136
140
|
if (!io || candidates.length === 0) return facts;
|
|
@@ -185,6 +189,16 @@ export async function resolveFacts(o = {}) {
|
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
191
|
|
|
192
|
+
// ── 1b. Who is a HUMAN. A broadcast is only ever a human's ("everyone,
|
|
193
|
+
// status?" from a peer agent is ambient), and the chain payload carries
|
|
194
|
+
// no author kind — so the directory is the only proof. ONE `member.list`
|
|
195
|
+
// per pull, and only when this pull holds a space post that the counts
|
|
196
|
+
// alone cannot rule out. Unreadable ⇒ `memberKinds` stays null ⇒ nobody
|
|
197
|
+
// is proven human ⇒ today's structural drop stands (logged, not silent).
|
|
198
|
+
if (families.has("messaging") && on("broadcast") && wantsMemberKinds(candidates, facts, me)) {
|
|
199
|
+
await resolveMemberKinds({ facts, io, log, degraded });
|
|
200
|
+
}
|
|
201
|
+
|
|
188
202
|
// ── 2. Message pages: one per affected, VISIBLE channel. Public-space traffic
|
|
189
203
|
// that the redacted counts already prove uninteresting is skipped.
|
|
190
204
|
if (families.has("messaging")) {
|
|
@@ -307,6 +321,67 @@ async function resolveCalendarFacts({ candidates, facts, io, log, degraded }) {
|
|
|
307
321
|
// Step implementations
|
|
308
322
|
// ---------------------------------------------------------------------------
|
|
309
323
|
|
|
324
|
+
/**
|
|
325
|
+
* Does this batch hold a space post whose author kind could change the verdict?
|
|
326
|
+
* That is: a non-private-room message, in a space I am a MEMBER of, by someone
|
|
327
|
+
* other than me, with counts that would otherwise drop it (0 mentions, not
|
|
328
|
+
* threaded) or counts absent. Anything else never asks the directory.
|
|
329
|
+
*
|
|
330
|
+
* @param {import("./directedness.mjs").Candidate[]} candidates
|
|
331
|
+
* @param {Facts} facts
|
|
332
|
+
* @param {string} me
|
|
333
|
+
* @returns {boolean}
|
|
334
|
+
*/
|
|
335
|
+
export function wantsMemberKinds(candidates, facts, me) {
|
|
336
|
+
const members = facts.memberChannelIds;
|
|
337
|
+
if (!members) return false;
|
|
338
|
+
for (const cand of candidates) {
|
|
339
|
+
if (!cand || cand.family !== "messaging") continue;
|
|
340
|
+
const channelId = String((cand.ids && cand.ids.channelId) || "");
|
|
341
|
+
if (!channelId || !members.has(channelId)) continue;
|
|
342
|
+
const chan = facts.channels.get(channelId);
|
|
343
|
+
const kind = String((cand.ids && cand.ids.channelKind) || (chan && chan.kind) || "").toUpperCase();
|
|
344
|
+
if (PRIVATE_ROOM_KINDS.includes(kind)) continue;
|
|
345
|
+
if (me && String(cand.actor || "") === me) continue;
|
|
346
|
+
const h = cand.hints || {};
|
|
347
|
+
if (h.mentionCount > 0 || h.threaded === true) continue; // paged anyway; no kind needed
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* `member.list` → `facts.memberKinds` keyed by BOTH member id and slug (the
|
|
355
|
+
* chain's `actor` is documented as "member slug or api-key id" while history's
|
|
356
|
+
* `authorId` is the cuid; one map answers either) + `facts.aiMemberCount`.
|
|
357
|
+
* Org-scoped, read-only, the same directory every seat may already list.
|
|
358
|
+
*/
|
|
359
|
+
async function resolveMemberKinds({ facts, io, log, degraded }) {
|
|
360
|
+
const frame = await io.call("member.list", {});
|
|
361
|
+
if (!frame || frame.ok !== true) {
|
|
362
|
+
degraded.push("members");
|
|
363
|
+
log("warn", "[inbound] member.list unreadable — no author can be proven human this tick, so a human's roll-call in a space WILL be dropped as no_mentions_not_threaded");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const kinds = new Map();
|
|
367
|
+
let ai = 0;
|
|
368
|
+
for (const m of arrayOf(resultOf(frame), "members")) {
|
|
369
|
+
if (!m) continue;
|
|
370
|
+
const kind = String(m.kind || "").toUpperCase();
|
|
371
|
+
if (!kind) continue;
|
|
372
|
+
const id = String(m.id || "");
|
|
373
|
+
const slug = String(m.slug || "");
|
|
374
|
+
if (id) kinds.set(id, kind);
|
|
375
|
+
if (slug) {
|
|
376
|
+
kinds.set(slug, kind);
|
|
377
|
+
kinds.set(slug.toLowerCase(), kind);
|
|
378
|
+
}
|
|
379
|
+
if (kind === "AI_AGENT") ai += 1;
|
|
380
|
+
}
|
|
381
|
+
facts.memberKinds = kinds;
|
|
382
|
+
facts.aiMemberCount = ai;
|
|
383
|
+
}
|
|
384
|
+
|
|
310
385
|
/**
|
|
311
386
|
* Fetch one `messaging.history` page per affected channel and fold it into
|
|
312
387
|
* `facts.channelPages` + `facts.myThreadRootIds`.
|
|
@@ -347,8 +422,9 @@ async function pageChannels({ candidates, facts, io, limits, log, on }) {
|
|
|
347
422
|
if (!members || !members.has(channelId)) continue;
|
|
348
423
|
if (!on("dm")) continue;
|
|
349
424
|
} else {
|
|
350
|
-
// A space: paged only if it could be a mention
|
|
351
|
-
|
|
425
|
+
// A space: paged only if it could be a mention, a thread reply or a
|
|
426
|
+
// human's broadcast to the room.
|
|
427
|
+
if (!on("mention") && !on("thread_reply") && !on("broadcast")) continue;
|
|
352
428
|
if (needsSpaceProbe(cand, facts) === false) {
|
|
353
429
|
skippedByCounts += 1;
|
|
354
430
|
continue;
|
|
@@ -123,6 +123,22 @@ export function toMessageEvent(o = {}) {
|
|
|
123
123
|
// TRUE only when this really is a direct address, so downstream triage can
|
|
124
124
|
// trust it. `channel`/`assignee` delivery is directed at the SEAT, not a
|
|
125
125
|
// literal @mention, and says so.
|
|
126
|
+
//
|
|
127
|
+
// `collective` IS DELIBERATELY ABSENT, and this is the one line most
|
|
128
|
+
// likely to be "fixed" by someone chasing the right bug. A work-shaped
|
|
129
|
+
// broadcast ("Everyone, please review the binder by Friday") DID open no
|
|
130
|
+
// board row, and the shortest-looking cure is to add `collective` here so
|
|
131
|
+
// `work-ledger.mjs` reports `directed: true`. That cure is wrong twice
|
|
132
|
+
// over: this flag also gates the daemon's directed-message rules, so it
|
|
133
|
+
// would change what the seat REPLIES to and not only what it tracks; and
|
|
134
|
+
// it would claim EVERY broadcast is assigned work, including "everyone
|
|
135
|
+
// should take a look sometime", which is thirteen board rows for an
|
|
136
|
+
// aside. The audience travels as its own structural fact instead —
|
|
137
|
+
// `isRollCallItem` reads the verdict reason back off the flattened item,
|
|
138
|
+
// `work-ledger.mjs` sends it as `collective`, and hq's
|
|
139
|
+
// `work/collective.ts` decides whether the ask is work. One address, two
|
|
140
|
+
// questions, and the second one is answered in the one place both planes
|
|
141
|
+
// share.
|
|
126
142
|
mentions_agent:
|
|
127
143
|
verdict.reason === "mention" ||
|
|
128
144
|
verdict.reason === "named" ||
|
|
@@ -158,6 +174,12 @@ export function toMessageEvent(o = {}) {
|
|
|
158
174
|
scope_id: s(c.ids.taskId || c.ids.decisionId || c.ids.fileId || "") || null,
|
|
159
175
|
seq: c.seq ?? null,
|
|
160
176
|
me: s(me),
|
|
177
|
+
// A roll-call is answered by every AI member of the room; the org-wide
|
|
178
|
+
// AI count is the honest upper bound a seat can know (it cannot see the
|
|
179
|
+
// room's roster). Carried only on a broadcast, so nothing else changes.
|
|
180
|
+
...(verdict.surface === "broadcast" && Number.isFinite(facts.aiMemberCount)
|
|
181
|
+
? { respondents: facts.aiMemberCount }
|
|
182
|
+
: {}),
|
|
161
183
|
},
|
|
162
184
|
};
|
|
163
185
|
|
|
@@ -55,6 +55,20 @@ export const SURFACES = Object.freeze({
|
|
|
55
55
|
scope: "channel",
|
|
56
56
|
default: true,
|
|
57
57
|
}),
|
|
58
|
+
/**
|
|
59
|
+
* A HUMAN's message to the whole room ("everyone", "@here", "roll call", …)
|
|
60
|
+
* in a space I am a member of. Every addressed member answers for itself, in
|
|
61
|
+
* ≤ 5 lines, with no ack and no election — see `broadcast.mjs` for the
|
|
62
|
+
* vocabulary and the reply shape. Added 2026-09-21 after a #general
|
|
63
|
+
* "can everyone give me an update" drew zero replies from thirteen seats.
|
|
64
|
+
*/
|
|
65
|
+
broadcast: Object.freeze({
|
|
66
|
+
topic: "message",
|
|
67
|
+
kind: "broadcast",
|
|
68
|
+
subject: "Cohort roll-call",
|
|
69
|
+
scope: "channel",
|
|
70
|
+
default: true,
|
|
71
|
+
}),
|
|
58
72
|
/** A reply in a thread I have spoken in / been named in. */
|
|
59
73
|
thread_reply: Object.freeze({
|
|
60
74
|
topic: "message",
|