@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
|
@@ -200,14 +200,25 @@ export function buildIdentityClaudeMd(agentJson, o = {}) {
|
|
|
200
200
|
* Default command is the bare `cohort-mcp` (the global npm install); a caller
|
|
201
201
|
* that knows it is not on PATH passes `{command, args}` (e.g. the current node
|
|
202
202
|
* + this package's bin/cohort-mcp.mjs) so the server still starts. Pure.
|
|
203
|
+
*
|
|
204
|
+
* `inheritEnv` (CF-22, W5-B): the Cohort Engine gives no MCP server a
|
|
205
|
+
* credential its entry does not name, so the entry names the org credential
|
|
206
|
+
* cohort-mcp resolves from the environment (lib/org/client.mjs, both brands —
|
|
207
|
+
* bin/cohort-mcp.mjs bridges NEOLITH_* at boot). An enrolled seat's cohort-mcp
|
|
208
|
+
* reads its token from config/org.yaml first; the list keeps an env-only seat
|
|
209
|
+
* working. The claude binary tolerates the key; `claude mcp add-json` drops it,
|
|
210
|
+
* so global-setup's verify step falls back to the JSON merge, which keeps it.
|
|
203
211
|
* @param {string} agentRoot @param {{command?:string, args?:string[]}} [o]
|
|
204
212
|
*/
|
|
205
213
|
export function cohortMcpEntry(agentRoot, o = {}) {
|
|
206
214
|
const command = o.command ? String(o.command) : "cohort-mcp";
|
|
207
215
|
const args = Array.isArray(o.args) ? o.args.map(String) : [];
|
|
208
|
-
return { command, args, env: { COHORT_AGENT_ROOT: String(agentRoot || "") } };
|
|
216
|
+
return { command, args, env: { COHORT_AGENT_ROOT: String(agentRoot || "") }, inheritEnv: [...COHORT_MCP_INHERIT_ENV] };
|
|
209
217
|
}
|
|
210
218
|
|
|
219
|
+
/** The org credential names cohort-mcp's entry inherits (= lib/engine/context/child-env.mjs ORG_CREDENTIAL_ENV). */
|
|
220
|
+
export const COHORT_MCP_INHERIT_ENV = Object.freeze(["COHORT_API_TOKEN", "COHORT_TOKEN", "COHORT_API_KEY", "NEOLITH_API_TOKEN", "NEOLITH_TOKEN", "NEOLITH_API_KEY"]);
|
|
221
|
+
|
|
211
222
|
function clone(v) { return JSON.parse(JSON.stringify(v)); }
|
|
212
223
|
function isObj(v) { return v && typeof v === "object" && !Array.isArray(v); }
|
|
213
224
|
|
|
@@ -305,6 +316,57 @@ export function mergeSessionSettings(settings, o = {}) {
|
|
|
305
316
|
return { settings: out, changes };
|
|
306
317
|
}
|
|
307
318
|
|
|
319
|
+
// ---------------------------------------------------------------------------
|
|
320
|
+
// State-YAML gates (2026-09): the two hooks that keep an agent's state/queues,
|
|
321
|
+
// state/dashboards and state/indexes YAML parseable and un-clobbered. They live
|
|
322
|
+
// in the SEAT's .claude/settings.json (commands are seat-relative and only make
|
|
323
|
+
// sense inside an agent repo), never in ~/.claude. A hand edit to that file does
|
|
324
|
+
// not survive a fresh checkout (the scaffold copy is what `create` ships) or an
|
|
325
|
+
// upgrade (settings.json is not on the upgrade path), so the scaffold carries
|
|
326
|
+
// them for new seats and `global-setup` — which `upgrade` runs as a post-step —
|
|
327
|
+
// merges them onto existing ones with this helper. Pure; I/O is in bin/maestro.
|
|
328
|
+
// ---------------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
/** The two hook groups, in the exact shape the scaffold .claude/settings.json carries. */
|
|
331
|
+
export const STATE_YAML_GATE_HOOKS = Object.freeze([
|
|
332
|
+
Object.freeze({
|
|
333
|
+
event: "PreToolUse",
|
|
334
|
+
matcher: "Write|Edit",
|
|
335
|
+
marker: "scripts/hooks/pre-write-yaml-validate.mjs",
|
|
336
|
+
command: "node ./scripts/hooks/pre-write-yaml-validate.mjs",
|
|
337
|
+
}),
|
|
338
|
+
Object.freeze({
|
|
339
|
+
event: "PostToolUse",
|
|
340
|
+
matcher: "Bash|Write|Edit",
|
|
341
|
+
marker: "scripts/hooks/validate-state-yaml.sh",
|
|
342
|
+
command: "./scripts/hooks/validate-state-yaml.sh",
|
|
343
|
+
}),
|
|
344
|
+
]);
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Merge the state-YAML gate hook groups into a seat's settings.json object, once.
|
|
348
|
+
* Presence is judged by the script marker anywhere under the event (any matcher),
|
|
349
|
+
* so an operator who already wired the script by hand is left alone. Existing
|
|
350
|
+
* groups, permissions and every other key are preserved. Idempotent. Pure.
|
|
351
|
+
*
|
|
352
|
+
* @param {object} settings parsed .claude/settings.json ({} / null when absent)
|
|
353
|
+
* @returns {{ settings: object, added: string[] }} added = "PreToolUse:pre-write-yaml-validate" ...
|
|
354
|
+
*/
|
|
355
|
+
export function mergeStateYamlGateHooks(settings) {
|
|
356
|
+
const out = isObj(settings) ? clone(settings) : {};
|
|
357
|
+
const added = [];
|
|
358
|
+
if (!isObj(out.hooks)) out.hooks = {};
|
|
359
|
+
for (const g of STATE_YAML_GATE_HOOKS) {
|
|
360
|
+
if (!Array.isArray(out.hooks[g.event])) out.hooks[g.event] = [];
|
|
361
|
+
const present = out.hooks[g.event].some((grp) =>
|
|
362
|
+
grp && Array.isArray(grp.hooks) && grp.hooks.some((h) => h && typeof h.command === "string" && h.command.includes(g.marker)));
|
|
363
|
+
if (present) continue;
|
|
364
|
+
out.hooks[g.event].push({ matcher: g.matcher, hooks: [{ type: "command", command: g.command }] });
|
|
365
|
+
added.push(`${g.event}:${basename(g.marker).replace(/\.(mjs|sh)$/, "")}`);
|
|
366
|
+
}
|
|
367
|
+
return { settings: out, added };
|
|
368
|
+
}
|
|
369
|
+
|
|
308
370
|
/** Build the machine pointer object. */
|
|
309
371
|
export function buildPointer(repoRoot, agentName, nowMs) {
|
|
310
372
|
return {
|
|
@@ -23,10 +23,128 @@ import {
|
|
|
23
23
|
readFileSync, unlinkSync, readdirSync, mkdirSync, existsSync,
|
|
24
24
|
} from "node:fs";
|
|
25
25
|
import { join, basename } from "node:path";
|
|
26
|
+
import { execFileSync } from "node:child_process";
|
|
26
27
|
import { writeJsonAtomic } from "../fs-atomic.mjs";
|
|
27
28
|
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Whose session is this? (the hook's owner, not the hook)
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* THE BUG THIS EXISTS FOR. `register()` defaults `pid` to `process.pid`, and
|
|
35
|
+
* the caller is a Claude Code HOOK (scripts/collective/hook-runner.mjs) — a
|
|
36
|
+
* node process that exits the moment it has written the record. `list()` then
|
|
37
|
+
* probes that pid, finds it dead, and reaps the record. So every interactive
|
|
38
|
+
* session on every machine registered itself and was deleted on the very next
|
|
39
|
+
* read: `who.mjs` said "No active Claude Code sessions" on a box with two of
|
|
40
|
+
* them open, and the "N other sessions active" digest line never fired. The
|
|
41
|
+
* presence registry was structurally empty from the day it shipped.
|
|
42
|
+
*
|
|
43
|
+
* The owner is up the process tree: hook → (a shell, sometimes) → the Claude
|
|
44
|
+
* Code / engine session that ran the hook. {@link owningSession} walks
|
|
45
|
+
* parents until it meets one, bounded, and reads its `--name` when it has one
|
|
46
|
+
* (a front door is `claude --name <first>-main`, a peer `--name <first>-<slug>`).
|
|
47
|
+
*
|
|
48
|
+
* `owningSession` is pure over an injected `readParent`; {@link readParentOf}
|
|
49
|
+
* is the `ps` reader. Fail-open: no owner found ⇒ `{pid:null}`, and `list()`
|
|
50
|
+
* treats an unknown pid as alive (liveness then rests on the heartbeat alone).
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/** Commands that ARE a session: Claude Code, an engine front door/peer, an engine run. */
|
|
54
|
+
const OWNER_RE = /(^|\/|\s)claude(\s|$)|(^|\s)cohort-session:\S|\/lib\/engine\/cli\.mjs\s+(run|session)(\s|$)/;
|
|
55
|
+
/** Claude Code's own infrastructure processes are never a session's owner. */
|
|
56
|
+
const NOT_OWNER_RE = /\bbg-pty-host\b|\bbg-spare\b|(^|\s)claude\s+daemon\s+run\b/;
|
|
57
|
+
|
|
58
|
+
/** `--name X` off a command line, or "". */
|
|
59
|
+
export function sessionNameOf(command) {
|
|
60
|
+
const m = String(command || "").match(/(?:^|\s)--name(?:=|\s+)(\S+)/);
|
|
61
|
+
return m ? m[1] : "";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Walk parents from `startPid` to the session that owns it. PURE over
|
|
66
|
+
* `readParent(pid) → {ppid, command, elapsedSec?} | null`.
|
|
67
|
+
*
|
|
68
|
+
* `startedAt` is the OWNER PROCESS's start (its `ps etime`), when the reader
|
|
69
|
+
* supplies one: that is when the session opened, which is what a "since T"
|
|
70
|
+
* about it should mean — not the moment a hook last happened to write the
|
|
71
|
+
* record. `null` when the reader has no elapsed time.
|
|
72
|
+
*
|
|
73
|
+
* @param {number} startPid
|
|
74
|
+
* @param {(pid:number) => ({ppid:number, command:string, elapsedSec?:number}|null)} readParent
|
|
75
|
+
* @param {{maxHops?:number, now?:number}} [opts]
|
|
76
|
+
* @returns {{pid:number|null, name:string, command:string, startedAt:string|null}}
|
|
77
|
+
*/
|
|
78
|
+
export function owningSession(startPid, readParent, opts = {}) {
|
|
79
|
+
const maxHops = Number.isFinite(opts.maxHops) ? opts.maxHops : 8;
|
|
80
|
+
const now = Number.isFinite(opts.now) ? opts.now : Date.now();
|
|
81
|
+
let pid = Number(startPid);
|
|
82
|
+
for (let hop = 0; hop < maxHops && Number.isFinite(pid) && pid > 1; hop++) {
|
|
83
|
+
let row = null;
|
|
84
|
+
try { row = readParent(pid); } catch { row = null; }
|
|
85
|
+
if (!row) break;
|
|
86
|
+
const cmd = String(row.command || "");
|
|
87
|
+
if (OWNER_RE.test(cmd) && !NOT_OWNER_RE.test(cmd)) {
|
|
88
|
+
const el = Number(row.elapsedSec);
|
|
89
|
+
const startedAt = Number.isFinite(el) && el >= 0 ? new Date(now - el * 1000).toISOString() : null;
|
|
90
|
+
return { pid, name: sessionNameOf(cmd), command: cmd.slice(0, 200), startedAt };
|
|
91
|
+
}
|
|
92
|
+
const ppid = Number(row.ppid);
|
|
93
|
+
if (!Number.isFinite(ppid) || ppid === pid) break;
|
|
94
|
+
pid = ppid;
|
|
95
|
+
}
|
|
96
|
+
return { pid: null, name: "", command: "", startedAt: null };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* `ps etime` → seconds. The format is `[[dd-]hh:]mm:ss`; anything else is null.
|
|
101
|
+
* Exported for its test.
|
|
102
|
+
*/
|
|
103
|
+
export function parseElapsed(etime) {
|
|
104
|
+
const m = String(etime || "").trim().match(/^(?:(\d+)-)?(?:(\d+):)?(\d{1,2}):(\d{2})$/);
|
|
105
|
+
if (!m) return null;
|
|
106
|
+
const [, d, h, mi, s] = m;
|
|
107
|
+
return (Number(d || 0) * 86400) + (Number(h || 0) * 3600) + (Number(mi) * 60) + Number(s);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** `ps` reader for {@link owningSession}: `{ppid, command, elapsedSec}` of one pid, or null. */
|
|
111
|
+
export function readParentOf(pid) {
|
|
112
|
+
try {
|
|
113
|
+
const out = execFileSync("/bin/ps", ["-o", "ppid=,etime=,command=", "-p", String(pid)], { encoding: "utf8", timeout: 2000 });
|
|
114
|
+
const line = out.split("\n").map((l) => l.trim()).find(Boolean);
|
|
115
|
+
if (!line) return null;
|
|
116
|
+
const m = line.match(/^(\d+)\s+(\S+)\s+(.*)$/);
|
|
117
|
+
if (!m) return null;
|
|
118
|
+
const elapsedSec = parseElapsed(m[2]);
|
|
119
|
+
return { ppid: Number(m[1]), command: m[3], elapsedSec: elapsedSec === null ? undefined : elapsedSec };
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The session that owns the CURRENT process (a hook). Starts at the parent —
|
|
127
|
+
* the hook itself is never the owner.
|
|
128
|
+
* @param {number} [fromPid] defaults to process.ppid
|
|
129
|
+
*/
|
|
130
|
+
export function resolveOwner(fromPid = process.ppid) {
|
|
131
|
+
return owningSession(fromPid, readParentOf);
|
|
132
|
+
}
|
|
133
|
+
|
|
28
134
|
const PRESENCE_REL = "state/collective/presence";
|
|
29
135
|
const DEFAULT_STALE_SEC = 300;
|
|
136
|
+
/**
|
|
137
|
+
* A record whose owner pid is KNOWN and ALIVE is not reaped for a stale
|
|
138
|
+
* heartbeat: the beat is a PostToolUse hook, so an open-but-idle interactive
|
|
139
|
+
* session stops beating after its last tool call and would otherwise vanish
|
|
140
|
+
* from every count five minutes later (and come back, re-registered, with a
|
|
141
|
+
* `startedAt` of "whenever the next beat happened"). Liveness for such a record
|
|
142
|
+
* is the pid probe. This cap is the one bound on that: a pid can be reused
|
|
143
|
+
* after a reboot, so a record that has not beaten in this long is reaped even
|
|
144
|
+
* if something answers at its pid. Two days is longer than any session a hook
|
|
145
|
+
* beats for and shorter than the gap in which a reused pid stays plausible.
|
|
146
|
+
*/
|
|
147
|
+
export const DEFAULT_IDLE_CAP_SEC = 48 * 3600;
|
|
30
148
|
|
|
31
149
|
function presenceDir(agentRoot) {
|
|
32
150
|
return join(agentRoot, PRESENCE_REL);
|
|
@@ -65,16 +183,26 @@ export function register(agentRoot, info = {}) {
|
|
|
65
183
|
const path = join(dir, `${safeId(info.sessionId)}.json`);
|
|
66
184
|
try {
|
|
67
185
|
mkdirSync(dir, { recursive: true });
|
|
68
|
-
|
|
186
|
+
// startedAt, in order of trust: the prior record's (a re-register keeps
|
|
187
|
+
// the original), then the OWNER PROCESS's start when the caller resolved
|
|
188
|
+
// one (a hook re-registering a session that lost its record still says
|
|
189
|
+
// when the session opened, not when this write happened), then now.
|
|
190
|
+
let startedAt = null;
|
|
69
191
|
try {
|
|
70
192
|
if (existsSync(path)) {
|
|
71
193
|
const prev = JSON.parse(readFileSync(path, "utf8"));
|
|
72
194
|
if (prev && prev.startedAt) startedAt = prev.startedAt;
|
|
73
195
|
}
|
|
74
196
|
} catch { /* ignore prior */ }
|
|
197
|
+
if (!startedAt && typeof info.startedAt === "string" && Number.isFinite(Date.parse(info.startedAt))) startedAt = info.startedAt;
|
|
198
|
+
if (!startedAt) startedAt = nowIso(info.nowMs);
|
|
75
199
|
const rec = {
|
|
76
200
|
sessionId: String(info.sessionId),
|
|
77
|
-
|
|
201
|
+
// `null` is an honest "unknown owner" (the walk found nothing): list()
|
|
202
|
+
// then judges liveness by the heartbeat alone. Absent still means "me",
|
|
203
|
+
// which is right for a session registering itself, wrong for a hook —
|
|
204
|
+
// hooks pass what resolveOwner() found.
|
|
205
|
+
pid: info.pid === null ? null : Number.isFinite(info.pid) ? info.pid : process.pid,
|
|
78
206
|
cwd: info.cwd || "",
|
|
79
207
|
repo: info.repo || (info.cwd ? basename(info.cwd) : ""),
|
|
80
208
|
agentName: info.agentName || "",
|
|
@@ -125,7 +253,14 @@ export function deregister(agentRoot, sessionId) {
|
|
|
125
253
|
* entries as a side effect. Newest-heartbeat first.
|
|
126
254
|
*
|
|
127
255
|
* @param {string} agentRoot
|
|
128
|
-
*
|
|
256
|
+
* THE RULE. A record with a KNOWN pid lives exactly as long as that pid does
|
|
257
|
+
* (bounded by `idleCapSec`, see {@link DEFAULT_IDLE_CAP_SEC}); a record with
|
|
258
|
+
* an UNKNOWN pid (`null` — the owner walk found nothing) lives as long as its
|
|
259
|
+
* heartbeat is within `staleSec`. The heartbeat is a tool-use hook, so it is
|
|
260
|
+
* evidence of activity, not of existence — and "is this session open" is the
|
|
261
|
+
* existence question.
|
|
262
|
+
*
|
|
263
|
+
* @param {object} [opts] - { staleSec, idleCapSec, nowMs, reap=true }
|
|
129
264
|
* @returns {object[]}
|
|
130
265
|
*/
|
|
131
266
|
export function list(agentRoot, opts = {}) {
|
|
@@ -133,6 +268,7 @@ export function list(agentRoot, opts = {}) {
|
|
|
133
268
|
const dir = presenceDir(agentRoot);
|
|
134
269
|
if (!existsSync(dir)) return [];
|
|
135
270
|
const staleMs = (Number.isFinite(opts.staleSec) ? opts.staleSec : DEFAULT_STALE_SEC) * 1000;
|
|
271
|
+
const idleCapMs = (Number.isFinite(opts.idleCapSec) ? opts.idleCapSec : DEFAULT_IDLE_CAP_SEC) * 1000;
|
|
136
272
|
const nowMs = Number.isFinite(opts.nowMs) ? opts.nowMs : Date.now();
|
|
137
273
|
const reap = opts.reap !== false;
|
|
138
274
|
let files;
|
|
@@ -152,8 +288,9 @@ export function list(agentRoot, opts = {}) {
|
|
|
152
288
|
continue;
|
|
153
289
|
}
|
|
154
290
|
const age = nowMs - Date.parse(rec.lastBeat || rec.startedAt || 0);
|
|
155
|
-
const
|
|
156
|
-
const dead = !isProcessRunning(rec.pid);
|
|
291
|
+
const pidKnown = Number.isFinite(rec.pid) && rec.pid > 0;
|
|
292
|
+
const dead = pidKnown && !isProcessRunning(rec.pid);
|
|
293
|
+
const stale = !Number.isFinite(age) || (pidKnown ? age > idleCapMs : age > staleMs);
|
|
157
294
|
if (stale || dead) {
|
|
158
295
|
if (reap) { try { unlinkSync(path); } catch { /* */ } }
|
|
159
296
|
continue;
|