@cohortapp/agent-sdk 2.17.0 → 2.18.5
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-slots.mjs +234 -0
- package/lib/collective/capture.mjs +8 -6
- package/lib/collective/config.mjs +2 -0
- package/lib/collective/global-config.mjs +63 -1
- package/lib/collective/loop-guard.mjs +155 -0
- 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 +833 -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 +229 -11
- 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/scaffold/config/collective.yaml +7 -0
- package/scripts/ci/check-durable-write-seam.mjs +3 -1
- 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 +142 -19
- 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 +1151 -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 +465 -81
- 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
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/org/inbound/broadcast.mjs — "did a human just address EVERYONE?"
|
|
3
|
+
*
|
|
4
|
+
* PURE. No IO, no clock, no config. The one place the collective-address
|
|
5
|
+
* vocabulary lives on this side of the org.
|
|
6
|
+
*
|
|
7
|
+
* ── WHY THIS EXISTS ──
|
|
8
|
+
* On 2026-09-21 a human posted in #general: "Can everyone give me an update on
|
|
9
|
+
* what they're doing right now (across sessions on your machines)?". Thirteen
|
|
10
|
+
* agents were members. Zero replied. Not a regression — a standing gap: the
|
|
11
|
+
* addressing layer knew DMs, @mentions, threads and prose names, and had NO
|
|
12
|
+
* concept of a message addressed to the whole room. A space post with
|
|
13
|
+
* `mentionCount: 0` was dropped structurally (`no_mentions_not_threaded`)
|
|
14
|
+
* before its body was ever read, on every seat, including the ones that were
|
|
15
|
+
* up and healthy.
|
|
16
|
+
*
|
|
17
|
+
* ── THE RULE (implemented by `resolveMessaging` in directedness.mjs) ──
|
|
18
|
+
* A space post is a BROADCAST when ALL of:
|
|
19
|
+
* 1. the author is HUMAN — agents never broadcast to each other; a peer's
|
|
20
|
+
* "everyone please review" is ambient traffic, not a roll-call;
|
|
21
|
+
* 2. it is in a public/private SPACE this seat is a member of — never a DM
|
|
22
|
+
* (a DM is already addressed by construction and stays a DM even when it
|
|
23
|
+
* says "everyone");
|
|
24
|
+
* 3. it is not threaded — a thread reply keeps the existing thread rule;
|
|
25
|
+
* 4. the body matches one of {@link BROADCAST_PATTERNS}.
|
|
26
|
+
*
|
|
27
|
+
* ── THE TWIN ──
|
|
28
|
+
* hq carries a faithful port of this module at
|
|
29
|
+
* `src/server/llm-responder/broadcast.ts` for agents WITHOUT a machine (the
|
|
30
|
+
* LLM_RESPONDER path). The two are separate packages and cannot import each
|
|
31
|
+
* other, so BOTH pin the same {@link BROADCAST_CORPUS} in their tests. Change
|
|
32
|
+
* a pattern here and the hq twin's test goes red until it is changed there
|
|
33
|
+
* too — that is the drift guard, keep the corpus identical on both sides.
|
|
34
|
+
*
|
|
35
|
+
* @module lib/org/inbound/broadcast
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
"use strict";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The explicit collective addresses, in match order. Case-insensitive, anchored
|
|
42
|
+
* to word boundaries, so "all" alone, "you" alone, "you all right?" and
|
|
43
|
+
* "thanks all" do NOT match — only a phrase that unambiguously names the whole
|
|
44
|
+
* room does. `team,` is only a broadcast when it OPENS the message ("Team, quick
|
|
45
|
+
* check-in") — mid-sentence "the team" is a noun, not an address.
|
|
46
|
+
*
|
|
47
|
+
* Ordered most-common-first; order does not change the verdict, only which
|
|
48
|
+
* pattern is reported as the match.
|
|
49
|
+
*
|
|
50
|
+
* @type {readonly RegExp[]}
|
|
51
|
+
*/
|
|
52
|
+
export const BROADCAST_PATTERNS = Object.freeze([
|
|
53
|
+
/\beveryone\b/i,
|
|
54
|
+
/\beverybody\b/i,
|
|
55
|
+
/\ball of you\b/i,
|
|
56
|
+
/\beach of you\b/i,
|
|
57
|
+
/\bthe whole team\b/i,
|
|
58
|
+
/^\s*team\s*,/i,
|
|
59
|
+
/(^|[^\w@])@here\b/i,
|
|
60
|
+
/(^|[^\w@])@channel\b/i,
|
|
61
|
+
/(^|[^\w@])@all\b/i,
|
|
62
|
+
/\ball agents\b/i,
|
|
63
|
+
/\ball colleagues\b/i,
|
|
64
|
+
/\broll[ -]?call\b/i,
|
|
65
|
+
/\bsound off\b/i,
|
|
66
|
+
/\bstatus check\b/i,
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Is this message body an explicit address to the whole room?
|
|
71
|
+
*
|
|
72
|
+
* Pure text test — the author/room/thread conditions are the caller's
|
|
73
|
+
* (`resolveMessaging`); this answers ONLY condition 4.
|
|
74
|
+
*
|
|
75
|
+
* @param {unknown} body
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
export function isBroadcast(body) {
|
|
79
|
+
const text = typeof body === "string" ? body : "";
|
|
80
|
+
if (!text.trim()) return false;
|
|
81
|
+
return BROADCAST_PATTERNS.some((re) => re.test(text));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Which pattern matched, as a stable label for a log line / a test. Null when
|
|
86
|
+
* none did.
|
|
87
|
+
*
|
|
88
|
+
* @param {unknown} body
|
|
89
|
+
* @returns {string|null}
|
|
90
|
+
*/
|
|
91
|
+
export function broadcastMatch(body) {
|
|
92
|
+
const text = typeof body === "string" ? body : "";
|
|
93
|
+
if (!text.trim()) return null;
|
|
94
|
+
for (const re of BROADCAST_PATTERNS) {
|
|
95
|
+
const m = re.exec(text);
|
|
96
|
+
if (m) return m[0].trim().toLowerCase();
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* THE SHARED CORPUS. Literal strings, pinned by directedness.test.mjs here and
|
|
103
|
+
* by hq's broadcast.test.ts. `positive` must all be broadcasts; `negative` must
|
|
104
|
+
* all NOT be. The first positive is the actual message that went unanswered.
|
|
105
|
+
*/
|
|
106
|
+
export const BROADCAST_CORPUS = Object.freeze({
|
|
107
|
+
positive: Object.freeze([
|
|
108
|
+
"Can everyone give me an update on what they're doing right now (across sessions on your machines)?",
|
|
109
|
+
"did everyone see the deck?",
|
|
110
|
+
"Everybody: standup in 5",
|
|
111
|
+
"Quick one for all of you — what's blocking you today?",
|
|
112
|
+
"I'd like each of you to post your top priority",
|
|
113
|
+
"Thanks to the whole team for the push last night, what's next on your plates?",
|
|
114
|
+
"Team, quick check-in: what are you on?",
|
|
115
|
+
"@here who is around?",
|
|
116
|
+
"@channel status please",
|
|
117
|
+
"@all please confirm you can see this",
|
|
118
|
+
"all agents: report your current task",
|
|
119
|
+
"All colleagues, a quick update from your side please",
|
|
120
|
+
"roll call",
|
|
121
|
+
"Roll-call — sound off with what you're working on",
|
|
122
|
+
"status check: where is everyone at?",
|
|
123
|
+
]),
|
|
124
|
+
negative: Object.freeze([
|
|
125
|
+
"all good here",
|
|
126
|
+
"thanks all",
|
|
127
|
+
"I'll take all three",
|
|
128
|
+
"you all right?",
|
|
129
|
+
"pushed the fix, ready for review",
|
|
130
|
+
"can you look at the deck?",
|
|
131
|
+
"the team offsite is on Thursday",
|
|
132
|
+
"email me at ops@all-hands.example",
|
|
133
|
+
"what is the status of the migration?",
|
|
134
|
+
"",
|
|
135
|
+
]),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Reply shaping — what a roll-call respondent is told
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
/** The MessageEvent / inbox `kind` and the verdict `reason` a broadcast carries. */
|
|
143
|
+
export const BROADCAST_KIND = "broadcast";
|
|
144
|
+
export const BROADCAST_REASON = "collective";
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Is this flattened inbox item a roll-call delivery? Reads the two fields the
|
|
148
|
+
* projection carries across `eventToInboxItem` (`kind`, `direct_reason`), so a
|
|
149
|
+
* daemon can gate on it without re-parsing prose.
|
|
150
|
+
*
|
|
151
|
+
* @param {object} item
|
|
152
|
+
* @returns {boolean}
|
|
153
|
+
*/
|
|
154
|
+
export function isRollCallItem(item) {
|
|
155
|
+
if (!item || typeof item !== "object") return false;
|
|
156
|
+
if (String(item.kind || "") === BROADCAST_KIND) return true;
|
|
157
|
+
if (String(item.direct_reason || "") === BROADCAST_REASON) return true;
|
|
158
|
+
const cohort = item.cohort && typeof item.cohort === "object" ? item.cohort : null;
|
|
159
|
+
return !!cohort && String(cohort.surface || "") === BROADCAST_KIND;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Hard ceiling on a roll-call reply, in lines. The prompt says it; the fleet keeps it. */
|
|
163
|
+
export const ROLL_CALL_MAX_LINES = 5;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The reply-shaping block injected into whichever prompt composes the answer —
|
|
167
|
+
* the daemon's quick-reply responder or a spawned session. One text, both
|
|
168
|
+
* paths, so a collective answer reads the same however it was produced. The
|
|
169
|
+
* FACTS the answer is composed from are the current-work block
|
|
170
|
+
* (lib/session/current-work), which both paths already carry.
|
|
171
|
+
*
|
|
172
|
+
* ONE TEXT, THREE INTENTS (`collective.mjs`). The discipline is shared —
|
|
173
|
+
* answer for yourself, do not speak for anyone else, do not @mention, do not
|
|
174
|
+
* acknowledge — and exactly one line differs, because exactly one thing
|
|
175
|
+
* differs:
|
|
176
|
+
*
|
|
177
|
+
* roll-call → report on yourself: what you are doing, queued, blocked.
|
|
178
|
+
* work → say what YOUR slice is and by when. The ask is already a row
|
|
179
|
+
* on the board (one per addressee), so the reply is a plan, not
|
|
180
|
+
* a status line — and telling the session the row exists is what
|
|
181
|
+
* stops it writing "I'll open a task for this".
|
|
182
|
+
* ambient → the room was addressed and nothing was asked. Answer in your
|
|
183
|
+
* own lane and do NOT mint work from it, which is the prompt-side
|
|
184
|
+
* half of the same guard `HEDGE_PATTERNS` enforces in code.
|
|
185
|
+
*
|
|
186
|
+
* Word-for-word hq's `src/server/llm-responder/broadcast.ts`, so a seat
|
|
187
|
+
* answered by its own daemon and a seat answered by hq read the same in the
|
|
188
|
+
* room.
|
|
189
|
+
*
|
|
190
|
+
* @param {{intent?: string, respondents?: number|null}} [o] `respondents` — how
|
|
191
|
+
* many AI members the org has (an upper bound on who else answers; the room
|
|
192
|
+
* roster is not visible to a seat). Omitted or non-finite ⇒ "several".
|
|
193
|
+
* @returns {string}
|
|
194
|
+
*/
|
|
195
|
+
export function collectiveInstructions(o = {}) {
|
|
196
|
+
const n = Number.isFinite(o.respondents) && o.respondents > 0 ? o.respondents : null;
|
|
197
|
+
const who = n ? `one of up to ${n} colleagues` : "one of several colleagues";
|
|
198
|
+
const intent = o.intent || "roll-call";
|
|
199
|
+
const banner = intent === "roll-call" ? "ROLL-CALL" : "ADDRESSED TO EVERYONE";
|
|
200
|
+
const framing =
|
|
201
|
+
intent === "work"
|
|
202
|
+
? `A human asked the whole room to do something, not you specifically. You are ${who} who will answer the same message. Every addressed member owns its own slice; nobody answers for the group.`
|
|
203
|
+
: `A human addressed the whole room, not you specifically. You are ${who} who will answer the same message. Every addressed member answers for itself; nobody answers for the group.`;
|
|
204
|
+
const content =
|
|
205
|
+
intent === "work"
|
|
206
|
+
? `- This ask is already on the board as YOUR OWN item, so do not open another one. Reply in at most ${ROLL_CALL_MAX_LINES} short lines, about your slice only: what you will do about it, and by when. Facts, not adjectives.`
|
|
207
|
+
: intent === "ambient"
|
|
208
|
+
? `- Nothing was asked of you here, so do not turn it into a task. Reply in at most ${ROLL_CALL_MAX_LINES} short lines, from your own lane only. Facts, not adjectives.`
|
|
209
|
+
: `- Reply in at most ${ROLL_CALL_MAX_LINES} short lines, about YOURSELF only: what you are doing right now, what is queued, what is blocked. Facts, not adjectives.`;
|
|
210
|
+
return [
|
|
211
|
+
`===== ${banner} =====`,
|
|
212
|
+
framing,
|
|
213
|
+
content,
|
|
214
|
+
"- Do NOT summarise, list, guess at or speak for anyone else's status.",
|
|
215
|
+
"- Do NOT @mention anyone. Do not address other agents. Do not ask the room a question back.",
|
|
216
|
+
"- Do NOT post an acknowledgement, a holding line or a 'checking now' — say nothing until the answer itself is ready, then post it once.",
|
|
217
|
+
"- Do not restate the question and do not open with a greeting; the first line is already the answer.",
|
|
218
|
+
`===== END ${banner} =====`,
|
|
219
|
+
].join("\n");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* The roll-call arm of {@link collectiveInstructions}, kept as its own export
|
|
224
|
+
* because it is what every existing call site and test names. Byte-identical to
|
|
225
|
+
* the text this module has always produced.
|
|
226
|
+
*
|
|
227
|
+
* @param {{respondents?: number|null}} [o]
|
|
228
|
+
* @returns {string}
|
|
229
|
+
*/
|
|
230
|
+
export function rollCallInstructions(o = {}) {
|
|
231
|
+
return collectiveInstructions({ ...o, intent: "roll-call" });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// WHAT THE SEAT IS DOING is not rendered here. This module briefly carried a
|
|
235
|
+
// `renderSelfActivity` (status by session name, peers by name, handoffs,
|
|
236
|
+
// every board row, the daemon's active sessions) that the quick reply injected
|
|
237
|
+
// NEXT TO lib/session/current-work's block — two accounts of one state, and
|
|
238
|
+
// the one here quoted session names. The single renderer is
|
|
239
|
+
// lib/session/current-work (`currentWorkBlock`, audience- and barrier-scoped);
|
|
240
|
+
// what this one carried that it lacked moved there. Do not add a second.
|
|
241
|
+
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
// Rate shaping — 13 replies must not land in the same second
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
|
|
246
|
+
/** The jitter window a roll-call reply is spread across, per channel. */
|
|
247
|
+
export const ROLL_CALL_JITTER_MAX_MS = 20_000;
|
|
248
|
+
|
|
249
|
+
/** FNV-1a 32-bit over a string. Deterministic, dependency-free. */
|
|
250
|
+
function fnv1a(s) {
|
|
251
|
+
let h = 0x811c9dc5;
|
|
252
|
+
for (let i = 0; i < s.length; i += 1) {
|
|
253
|
+
h ^= s.charCodeAt(i);
|
|
254
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
255
|
+
}
|
|
256
|
+
return h >>> 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* How long THIS seat waits before posting its roll-call answer. Deterministic
|
|
261
|
+
* per (seat, channel, message): the same seat answering the same roll-call
|
|
262
|
+
* after a crash waits the same amount, and thirteen seats spread across the
|
|
263
|
+
* window instead of stacking on the second the event landed. Pure — no
|
|
264
|
+
* randomness — so a test can pin it.
|
|
265
|
+
*
|
|
266
|
+
* @param {{seat?:string, channelId?:string, messageId?:string, maxMs?:number}} o
|
|
267
|
+
* @returns {number} milliseconds in [0, maxMs)
|
|
268
|
+
*/
|
|
269
|
+
export function rollCallJitterMs(o = {}) {
|
|
270
|
+
const max = Number.isFinite(o.maxMs) && o.maxMs >= 0 ? o.maxMs : ROLL_CALL_JITTER_MAX_MS;
|
|
271
|
+
if (max === 0) return 0;
|
|
272
|
+
const key = `${o.seat || ""}|${o.channelId || ""}|${o.messageId || ""}`;
|
|
273
|
+
return fnv1a(key) % max;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export default {
|
|
277
|
+
BROADCAST_PATTERNS,
|
|
278
|
+
BROADCAST_CORPUS,
|
|
279
|
+
BROADCAST_KIND,
|
|
280
|
+
BROADCAST_REASON,
|
|
281
|
+
ROLL_CALL_MAX_LINES,
|
|
282
|
+
ROLL_CALL_JITTER_MAX_MS,
|
|
283
|
+
isBroadcast,
|
|
284
|
+
broadcastMatch,
|
|
285
|
+
isRollCallItem,
|
|
286
|
+
collectiveInstructions,
|
|
287
|
+
rollCallInstructions,
|
|
288
|
+
rollCallJitterMs,
|
|
289
|
+
};
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/org/inbound/collective.mjs — a message addressed to EVERYONE: is it work?
|
|
3
|
+
*
|
|
4
|
+
* PURE. No IO, no clock, no config. The twin of hq's
|
|
5
|
+
* `src/server/work/collective.ts`.
|
|
6
|
+
*
|
|
7
|
+
* ── THE QUESTION THIS ANSWERS, AND THE ONE IT DOES NOT ──
|
|
8
|
+
* `broadcast.mjs#isBroadcast` answers ADDRESSING: did a human name the whole
|
|
9
|
+
* room? This module answers what comes next, and only that: GIVEN that the
|
|
10
|
+
* room was addressed collectively, is the message a ROLL-CALL (report on
|
|
11
|
+
* yourself), WORK (go and do a thing), or AMBIENT (neither)?
|
|
12
|
+
*
|
|
13
|
+
* It deliberately does NOT re-test the address — `directedness.mjs#
|
|
14
|
+
* isBroadcastFor` already settled that, and asking twice is how two places
|
|
15
|
+
* come to disagree about one question.
|
|
16
|
+
*
|
|
17
|
+
* ── WHY IT EXISTS ──
|
|
18
|
+
* 2026-09-21 fixed the first half: "Can everyone give me an update?" drew zero
|
|
19
|
+
* replies from thirteen members. The half it did not fix: "Everyone, please
|
|
20
|
+
* review the binder by Friday" drew replies and NO BOARD ROWS, on both planes.
|
|
21
|
+
* Work addressed to everyone did no work.
|
|
22
|
+
*
|
|
23
|
+
* ── THE RULE, IN THE CODE THAT IMPLEMENTS IT ──
|
|
24
|
+
*
|
|
25
|
+
* 1. ROLL-CALL AND WORK ARE NOT MUTUALLY EXCLUSIVE TEXT, so they are not
|
|
26
|
+
* tested in sequence. "Everyone, please review the binder and give me an
|
|
27
|
+
* update when it's done" is BOTH shapes in one sentence, and a first-match
|
|
28
|
+
* ladder gets it wrong whichever order it is written in. Instead the
|
|
29
|
+
* roll-call phrases are EXCISED from the body and the work gate runs on
|
|
30
|
+
* what is left: if the residue still asks for work, it is work; if the work
|
|
31
|
+
* reading only ever came from the status phrasing, it is a roll-call. That
|
|
32
|
+
* is also what keeps "can everyone give me an UPDATE" from being work —
|
|
33
|
+
* `update` is an action verb, and without the excision the plainest
|
|
34
|
+
* roll-call in the corpus would open thirteen board rows.
|
|
35
|
+
*
|
|
36
|
+
* 2. A HEDGE DEFUSES WORK. "everyone should take a look sometime", "feel free
|
|
37
|
+
* to review when you get a chance", "no rush" — a board that mints thirteen
|
|
38
|
+
* rows for each of those is a board the owner stops opening within a week.
|
|
39
|
+
* A hedge is read BEFORE the verb, so no amount of imperative grammar beats
|
|
40
|
+
* "if anyone has a minute".
|
|
41
|
+
*
|
|
42
|
+
* 3. THE WORK TEST IS hq's. `asksForWork` / `hasSubstance` below are a VERBATIM
|
|
43
|
+
* port of `src/server/work/threshold.ts` — not a second opinion about what
|
|
44
|
+
* work looks like. A collective ask and a direct ask are the same ask with a
|
|
45
|
+
* different audience.
|
|
46
|
+
*
|
|
47
|
+
* ── WHAT THIS FILE MAY AND MAY NOT DECIDE ──
|
|
48
|
+
* It shapes a PROMPT and routes a FAST PATH. It NEVER decides whether a board
|
|
49
|
+
* row exists. That judgement stays single-implementation on the server:
|
|
50
|
+
* `work-ledger.mjs` sends `collective: true` plus the body over `board.track`,
|
|
51
|
+
* and hq's `assessAskWithAudience` runs its own copy of this classifier. A
|
|
52
|
+
* daemon that got the verdict wrong here therefore loses a nicely-shaped
|
|
53
|
+
* prompt, never a row it should not have opened.
|
|
54
|
+
*
|
|
55
|
+
* ── THE TWIN ──
|
|
56
|
+
* Both sides pin {@link COLLECTIVE_CORPUS}, byte-for-byte. Change a pattern
|
|
57
|
+
* here and hq's `collective.test.ts` goes red until it is changed there too —
|
|
58
|
+
* the same drift guard BROADCAST_CORPUS already runs for the address.
|
|
59
|
+
*
|
|
60
|
+
* @module lib/org/inbound/collective
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
"use strict";
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// VERBATIM PORT of hq src/server/work/threshold.ts. Do not "improve" either
|
|
67
|
+
// copy alone: the corpus below is what holds them together, and the board gate
|
|
68
|
+
// that matters runs hq's copy.
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
/** Shortest ask we will treat as an ask at all. */
|
|
72
|
+
const MIN_SUBSTANCE_CHARS = 12;
|
|
73
|
+
|
|
74
|
+
/** A chase or a pleasantry — a reaction to work, never a request for it. */
|
|
75
|
+
const NO_SUBSTANCE =
|
|
76
|
+
/^(?:[\s?!.…]*|\?+|pls|please|ping|bump|any\s+updates?|updates?|status|well\?|and\?|thanks?|thank\s+you|ty|thx|cheers|ok(?:ay)?|kk|got\s+it|sure|nice|great|cool|perfect|lovely|yes|yep|no|nope|nvm|never\s+mind|👍|🙏|🎉)[\s?!.…]*$/i;
|
|
77
|
+
|
|
78
|
+
/** An explicit "do not action this" prefix, honoured before anything else. */
|
|
79
|
+
const NO_ACTION_PREFIX = /^\s*(?:fyi\b|no\s+action\b|just\s+so\s+you\s+know\b)/i;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Verbs that name WORK. Kept to things that produce an artifact or change the
|
|
83
|
+
* world — deliberately NOT "explain", "tell", "what", "why", which are answered
|
|
84
|
+
* in the turn and leave the reply as their own artifact.
|
|
85
|
+
*/
|
|
86
|
+
const ACTION_VERB =
|
|
87
|
+
"(?:fix|ship|build|write|draft|send|create|make|set\\s+up|update|upgrade|migrate|deploy|" +
|
|
88
|
+
"investigate|look\\s+into|dig\\s+into|sort\\s+out|figure\\s+out|chase|review|prepare|prep|" +
|
|
89
|
+
"schedule|book|publish|add|remove|delete|refactor|debug|push|merge|implement|plan|research|" +
|
|
90
|
+
"analyse|analyze|compile|produce|generate|organise|organize|follow\\s+up|resolve|land|" +
|
|
91
|
+
"roll\\s+out|audit|clean\\s+up|tidy|rename|document|write\\s+up|pull\\s+together|put\\s+together|" +
|
|
92
|
+
"sort|handle|action|own|drive|unblock|test|verify|check\\s+into|reconcile)";
|
|
93
|
+
|
|
94
|
+
/** An imperative: the verb opens a sentence ("fix these issues and push them"). */
|
|
95
|
+
const IMPERATIVE = new RegExp(
|
|
96
|
+
`(?:^|[.!?;,\\n]\\s*|\\b(?:and|then|also|please|pls|first|next|now)\\s+)` +
|
|
97
|
+
`(?:(?:also|then|now|and|please|pls|first|next)\\s+){0,2}${ACTION_VERB}\\b`,
|
|
98
|
+
"i",
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
/** A polite request wrapper ("could you look into…", "I need you to draft…"). */
|
|
102
|
+
const REQUEST = new RegExp(
|
|
103
|
+
`\\b(?:can|could|would|will|please|pls|need\\s+(?:you\\s+)?to|needs?\\s+to|want\\s+you\\s+to|` +
|
|
104
|
+
`like\\s+you\\s+to|should\\s+you|mind)\\b[^.!?\\n]{0,40}?\\b${ACTION_VERB}\\b`,
|
|
105
|
+
"i",
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Does this text ask the agent to DO something (as opposed to answer something)?
|
|
110
|
+
* @param {unknown} body
|
|
111
|
+
* @returns {boolean}
|
|
112
|
+
*/
|
|
113
|
+
export function asksForWork(body) {
|
|
114
|
+
const text = String(body == null ? "" : body).trim();
|
|
115
|
+
if (!text) return false;
|
|
116
|
+
if (NO_ACTION_PREFIX.test(text)) return false;
|
|
117
|
+
return IMPERATIVE.test(text) || REQUEST.test(text);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Is there enough here to be an ask at all?
|
|
122
|
+
* @param {unknown} body
|
|
123
|
+
* @returns {boolean}
|
|
124
|
+
*/
|
|
125
|
+
export function hasSubstance(body) {
|
|
126
|
+
const text = String(body == null ? "" : body).trim();
|
|
127
|
+
if (!text) return false;
|
|
128
|
+
if (NO_SUBSTANCE.test(text)) return false;
|
|
129
|
+
return text.length >= MIN_SUBSTANCE_CHARS;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// The collective classifier
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @typedef {"roll-call"|"work"|"ambient"} CollectiveIntent
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
/** The three intents, in the order a reader should meet them. */
|
|
141
|
+
export const COLLECTIVE_INTENTS = Object.freeze(["roll-call", "work", "ambient"]);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Phrases that ask each addressee to REPORT ON ITSELF. Excised from the body
|
|
145
|
+
* before the work gate runs (see rule 1), so a status ask that happens to use
|
|
146
|
+
* an action verb — "give me an UPDATE", "REVIEW your plate" — cannot read as a
|
|
147
|
+
* request to go and do something.
|
|
148
|
+
*
|
|
149
|
+
* Every one is anchored to a self-reference (`you`, `your`, `their`,
|
|
150
|
+
* `everyone`) or is a named ritual (roll call, standup, sound off). A bare
|
|
151
|
+
* "status" or "update" is NOT here: "update the binder" is work.
|
|
152
|
+
*
|
|
153
|
+
* @type {readonly RegExp[]}
|
|
154
|
+
*/
|
|
155
|
+
export const ROLL_CALL_PATTERNS = Object.freeze([
|
|
156
|
+
/\broll[ -]?call\b/gi,
|
|
157
|
+
/\bsound off\b/gi,
|
|
158
|
+
/\bstatus check\b/gi,
|
|
159
|
+
/\bstand[ -]?up\b/gi,
|
|
160
|
+
/\bcheck[ -]?in\b/gi,
|
|
161
|
+
/\bwho(?:'s| is| has| are)\b[^.!?\n]{0,24}\b(?:around|online|here|available|free|working)\b/gi,
|
|
162
|
+
/\bwhat\b[^.!?\n]{0,16}\b(?:you|they)(?:'re| are)?\b[^.!?\n]{0,12}\b(?:working on|doing|up to|on right now)\b/gi,
|
|
163
|
+
/\b(?:give|post|share|send|drop|leave)\b[^.!?\n]{0,24}\b(?:an?\s+|your\s+|their\s+)?(?:update|status)\b/gi,
|
|
164
|
+
/\b(?:update|status)\b[^.!?\n]{0,24}\bfrom (?:your|their|each|you)\b/gi,
|
|
165
|
+
/\b(?:update|status)s?\s*(?:please|pls|report)\b/gi,
|
|
166
|
+
/\bupdate on what\b/gi,
|
|
167
|
+
/\bwhat(?:'s| is)\b[^.!?\n]{0,16}\bblocking (?:you|everyone|anyone)\b/gi,
|
|
168
|
+
/\bwhat(?:'s| is) next on (?:your|their)\b/gi,
|
|
169
|
+
/\b(?:your|their) (?:top |current )?(?:priority|priorities|task|tasks|plate|plates|lane|lanes)\b/gi,
|
|
170
|
+
/\breport (?:your|their|back with your)\b/gi,
|
|
171
|
+
/\bconfirm you can (?:see|read|hear)\b/gi,
|
|
172
|
+
/\bwhere (?:is|are) (?:everyone|everybody|we all)\b/gi,
|
|
173
|
+
/\bdid (?:everyone|everybody|you all|all of you)\b/gi,
|
|
174
|
+
]);
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Phrases that make a work-shaped sentence NOT an assignment. Read before the
|
|
178
|
+
* verb: this is the guard against "everyone should take a look sometime"
|
|
179
|
+
* minting thirteen rows, and it is deliberately the widest net here, because
|
|
180
|
+
* the asymmetry is real — a missed row costs one invisible ask, a spurious row
|
|
181
|
+
* costs thirteen and the owner's attention for the board itself.
|
|
182
|
+
*
|
|
183
|
+
* @type {readonly RegExp[]}
|
|
184
|
+
*/
|
|
185
|
+
export const HEDGE_PATTERNS = Object.freeze([
|
|
186
|
+
/\bsometime\b/i,
|
|
187
|
+
/\bat some point\b/i,
|
|
188
|
+
/\bwhen(?:ever)? (?:you|anyone|someone|folks|people)\b[^.!?\n]{0,20}\b(?:chance|moment|time|minute|min|sec|second|bandwidth|capacity)\b/i,
|
|
189
|
+
/\bno (?:rush|hurry|pressure|urgency|action|need)\b/i,
|
|
190
|
+
/\bif (?:anyone|anybody|someone|you)\b[^.!?\n]{0,24}\b(?:time|chance|moment|minute|min|sec|bandwidth|capacity|curious|interested|keen)\b/i,
|
|
191
|
+
/\bfeel free\b/i,
|
|
192
|
+
/\bno action (?:needed|required|necessary)\b/i,
|
|
193
|
+
/\bnothing (?:to do|needed|required)\b/i,
|
|
194
|
+
/\b(?:purely |just )?(?:fyi|for (?:your )?(?:info|information|awareness|visibility))\b/i,
|
|
195
|
+
/\bmight (?:want|be worth|be of interest)\b/i,
|
|
196
|
+
/\bworth a (?:look|read|skim)\b/i,
|
|
197
|
+
/\boptional\b/i,
|
|
198
|
+
/\bwhenever\b/i,
|
|
199
|
+
/\bif you(?:'re| are) (?:curious|interested|bored)\b/i,
|
|
200
|
+
]);
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Does this body hedge hard enough that no verb in it is an assignment?
|
|
204
|
+
* @param {unknown} body
|
|
205
|
+
* @returns {boolean}
|
|
206
|
+
*/
|
|
207
|
+
export function isHedged(body) {
|
|
208
|
+
const text = typeof body === "string" ? body : "";
|
|
209
|
+
if (!text.trim()) return false;
|
|
210
|
+
return HEDGE_PATTERNS.some((re) => re.test(text));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The body with every roll-call phrase blanked out. Exported for the tests and
|
|
215
|
+
* for a log line: "we called this a roll-call, and here is what was left after
|
|
216
|
+
* the status phrasing came out" is the one sentence that makes a wrong verdict
|
|
217
|
+
* diagnosable without a debugger.
|
|
218
|
+
*
|
|
219
|
+
* @param {unknown} body
|
|
220
|
+
* @returns {string}
|
|
221
|
+
*/
|
|
222
|
+
export function withoutRollCallPhrases(body) {
|
|
223
|
+
let text = typeof body === "string" ? body : "";
|
|
224
|
+
if (!text.trim()) return "";
|
|
225
|
+
for (const re of ROLL_CALL_PATTERNS) {
|
|
226
|
+
// Every pattern is /g; `replace` with a global regex is stateless per call
|
|
227
|
+
// (it resets lastIndex itself), so these are safe as module constants —
|
|
228
|
+
// `test()` on a /g regex would NOT be, which is why nothing here calls it.
|
|
229
|
+
text = text.replace(re, " ");
|
|
230
|
+
}
|
|
231
|
+
return text;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Did any roll-call phrase appear at all?
|
|
236
|
+
* @param {unknown} body
|
|
237
|
+
* @returns {boolean}
|
|
238
|
+
*/
|
|
239
|
+
export function hasRollCallPhrase(body) {
|
|
240
|
+
const text = typeof body === "string" ? body : "";
|
|
241
|
+
if (!text.trim()) return false;
|
|
242
|
+
return withoutRollCallPhrases(text) !== text;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* THE decision. Pure, total, and the only implementation on this plane.
|
|
247
|
+
*
|
|
248
|
+
* Call it ONLY for a message already known to be collectively addressed; for
|
|
249
|
+
* anything else the answer is meaningless (a 1:1 DM saying "review the binder"
|
|
250
|
+
* is directed work and the ordinary path owns it).
|
|
251
|
+
*
|
|
252
|
+
* @param {unknown} body
|
|
253
|
+
* @returns {{intent: CollectiveIntent, reason: string}}
|
|
254
|
+
*/
|
|
255
|
+
export function collectiveIntent(body) {
|
|
256
|
+
const text = (typeof body === "string" ? body : "").trim();
|
|
257
|
+
if (!text) return { intent: "ambient", reason: "empty" };
|
|
258
|
+
|
|
259
|
+
const rollCallPhrase = hasRollCallPhrase(text);
|
|
260
|
+
|
|
261
|
+
// A hedge beats every verb in the sentence — but NOT a roll-call. "everyone
|
|
262
|
+
// sound off whenever you get a sec" is still a roll-call; it just is not
|
|
263
|
+
// work, and a roll-call was never going to open a row anyway.
|
|
264
|
+
if (isHedged(text)) {
|
|
265
|
+
return rollCallPhrase
|
|
266
|
+
? { intent: "roll-call", reason: "roll-call-phrase" }
|
|
267
|
+
: { intent: "ambient", reason: "hedged" };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const residue = rollCallPhrase ? withoutRollCallPhrases(text) : text;
|
|
271
|
+
if (hasSubstance(residue) && asksForWork(residue)) {
|
|
272
|
+
return { intent: "work", reason: "asks-for-work" };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (rollCallPhrase) return { intent: "roll-call", reason: "roll-call-phrase" };
|
|
276
|
+
return { intent: "ambient", reason: "no-work-asked" };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Convenience: is this collective message WORK?
|
|
281
|
+
* @param {unknown} body
|
|
282
|
+
* @returns {boolean}
|
|
283
|
+
*/
|
|
284
|
+
export function isCollectiveWork(body) {
|
|
285
|
+
return collectiveIntent(body).intent === "work";
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The intent of a flattened INBOX ITEM that the inbound join already decided is
|
|
290
|
+
* a broadcast (`isRollCallItem`). Returns null for anything that is not one —
|
|
291
|
+
* a DM, an @mention, a task comment — because the classifier's answer is only
|
|
292
|
+
* meaningful once the collective address is established.
|
|
293
|
+
*
|
|
294
|
+
* Lives here rather than in broadcast.mjs so that module stays what it is: the
|
|
295
|
+
* ADDRESS, with no opinion about what the address asked for.
|
|
296
|
+
*
|
|
297
|
+
* @param {object} item flattened inbox item
|
|
298
|
+
* @param {(item:object)=>boolean} isCollectiveItem usually `isRollCallItem`
|
|
299
|
+
* @returns {CollectiveIntent|null}
|
|
300
|
+
*/
|
|
301
|
+
export function itemCollectiveIntent(item, isCollectiveItem) {
|
|
302
|
+
if (typeof isCollectiveItem !== "function" || !isCollectiveItem(item)) return null;
|
|
303
|
+
const body = item && (item.content || item.text || item.subject);
|
|
304
|
+
return collectiveIntent(body).intent;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* THE SHARED CORPUS. Literal strings, pinned by `collective.test.mjs` here and
|
|
309
|
+
* by hq's `src/server/work/collective.test.ts`. Every string is one a human
|
|
310
|
+
* could plausibly type into #general; every one already satisfies
|
|
311
|
+
* `isBroadcast`, so the only thing each pins is the intent.
|
|
312
|
+
*
|
|
313
|
+
* Same contract as BROADCAST_CORPUS: change a pattern on either plane and the
|
|
314
|
+
* other plane's test goes red until the two agree again.
|
|
315
|
+
*/
|
|
316
|
+
export const COLLECTIVE_CORPUS = Object.freeze({
|
|
317
|
+
/** WORK: every addressee opens a row of its own. */
|
|
318
|
+
work: Object.freeze([
|
|
319
|
+
"Everyone, please review the binder by Friday",
|
|
320
|
+
"Everybody: please update your KPI rows in the mandate before end of week",
|
|
321
|
+
"@here we need to draft the board pack today",
|
|
322
|
+
"@channel please push your branches before the 18:00 freeze",
|
|
323
|
+
"All of you: please audit your channel memberships this week",
|
|
324
|
+
"Team, please prepare your section of the deck before Thursday",
|
|
325
|
+
"the whole team needs to review the binder before Friday",
|
|
326
|
+
"Everyone, please review the binder and give me an update when it's done",
|
|
327
|
+
"@all please fix the failing checks on your own repos today",
|
|
328
|
+
]),
|
|
329
|
+
/** ROLL-CALL: every addressee answers for itself; no rows. */
|
|
330
|
+
rollCall: Object.freeze([
|
|
331
|
+
"Can everyone give me an update on what they're doing right now (across sessions on your machines)?",
|
|
332
|
+
"did everyone see the deck?",
|
|
333
|
+
"Everybody: standup in 5",
|
|
334
|
+
"Quick one for all of you — what's blocking you today?",
|
|
335
|
+
"I'd like each of you to post your top priority",
|
|
336
|
+
"Thanks to the whole team for the push last night, what's next on your plates?",
|
|
337
|
+
"Team, quick check-in: what are you on?",
|
|
338
|
+
"@here who is around?",
|
|
339
|
+
"@channel status please",
|
|
340
|
+
"@all please confirm you can see this",
|
|
341
|
+
"all agents: report your current task",
|
|
342
|
+
"All colleagues, a quick update from your side please",
|
|
343
|
+
"roll call",
|
|
344
|
+
"Roll-call — sound off with what you're working on",
|
|
345
|
+
"status check: where is everyone at?",
|
|
346
|
+
"everyone sound off whenever you get a sec",
|
|
347
|
+
]),
|
|
348
|
+
/** AMBIENT: addressed to the room, asking for nothing. No rows. */
|
|
349
|
+
ambient: Object.freeze([
|
|
350
|
+
"everyone should take a look at the binder sometime",
|
|
351
|
+
"Everyone, feel free to review the binder when you get a chance",
|
|
352
|
+
"FYI everyone — the binder is up in the drive",
|
|
353
|
+
"@here the deploy finished, no action needed",
|
|
354
|
+
"Everyone, the offsite is on Thursday at the usual place",
|
|
355
|
+
"@channel just publishing the notes for visibility",
|
|
356
|
+
"Everybody: nice work this week, genuinely",
|
|
357
|
+
"everyone might want to review the new brand kit at some point",
|
|
358
|
+
"@all optional: the reading group meets at 4",
|
|
359
|
+
]),
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
export default {
|
|
363
|
+
COLLECTIVE_INTENTS,
|
|
364
|
+
COLLECTIVE_CORPUS,
|
|
365
|
+
ROLL_CALL_PATTERNS,
|
|
366
|
+
HEDGE_PATTERNS,
|
|
367
|
+
asksForWork,
|
|
368
|
+
hasSubstance,
|
|
369
|
+
isHedged,
|
|
370
|
+
withoutRollCallPhrases,
|
|
371
|
+
hasRollCallPhrase,
|
|
372
|
+
collectiveIntent,
|
|
373
|
+
isCollectiveWork,
|
|
374
|
+
itemCollectiveIntent,
|
|
375
|
+
};
|