@cohortapp/agent-sdk 2.3.0
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/commands/init-agent.md +104 -0
- package/.claude/commands/init-maestro.md +1187 -0
- package/.claude/settings.json +161 -0
- package/.env.example +216 -0
- package/README.md +632 -0
- package/agents/browser-operator/agent.md +52 -0
- package/agents/calendar-ops/agent.md +50 -0
- package/agents/communications/agent.md +96 -0
- package/agents/decision-log/agent.md +65 -0
- package/agents/desktop-operator/agent.md +59 -0
- package/agents/gmail-operator/agent.md +62 -0
- package/agents/inbound-dispatcher/agent.md +66 -0
- package/agents/inbox-processor/agent.md +39 -0
- package/agents/pmo-execution/agent.md +60 -0
- package/agents/session-spawner/agent.md +64 -0
- package/agents/slack-operator/agent.md +60 -0
- package/agents/whatsapp-operator/agent.md +60 -0
- package/agents/workflow-automation/agent.md +61 -0
- package/archetypes/altitudes/c-suite.yaml +58 -0
- package/archetypes/altitudes/founder.yaml +68 -0
- package/archetypes/altitudes/senior-manager.yaml +63 -0
- package/archetypes/altitudes/svp.yaml +60 -0
- package/archetypes/altitudes/vp.yaml +50 -0
- package/archetypes/archetype.schema.json +77 -0
- package/archetypes/base.yaml +47 -0
- package/archetypes/capabilities/commercial-leader.yaml +159 -0
- package/archetypes/capabilities/compliance-officer.yaml +159 -0
- package/archetypes/capabilities/executive-operator.yaml +169 -0
- package/archetypes/capabilities/finance-leader.yaml +162 -0
- package/archetypes/capabilities/operations-leader.yaml +154 -0
- package/archetypes/capabilities/product-leader.yaml +148 -0
- package/archetypes/capabilities/technical-leader.yaml +146 -0
- package/archetypes/functions/commercial-leader.yaml +62 -0
- package/archetypes/functions/compliance-officer.yaml +64 -0
- package/archetypes/functions/executive-operator.yaml +70 -0
- package/archetypes/functions/finance-leader.yaml +70 -0
- package/archetypes/functions/operations-leader.yaml +62 -0
- package/archetypes/functions/product-leader.yaml +61 -0
- package/archetypes/functions/technical-leader.yaml +57 -0
- package/bin/cohort-mcp.mjs +81 -0
- package/bin/maestro.mjs +3516 -0
- package/bin/maestro.test.mjs +1015 -0
- package/desktop-control/README.md +56 -0
- package/desktop-control/app-profiles/gmail.yaml +120 -0
- package/desktop-control/app-profiles/slack.yaml +315 -0
- package/desktop-control/app-profiles/whatsapp.yaml +107 -0
- package/docs/architecture/agent-topology.md +2239 -0
- package/docs/architecture/archetype-agent-factory.md +110 -0
- package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
- package/docs/architecture/continuous-monitoring.md +221 -0
- package/docs/architecture/mcp-capability-map.md +585 -0
- package/docs/architecture/system-architecture.md +1272 -0
- package/docs/company-context/README.md +40 -0
- package/docs/guides/agent-persona-setup.md +600 -0
- package/docs/guides/agents-observe-setup.md +64 -0
- package/docs/guides/billing-console-keys.md +88 -0
- package/docs/guides/ccxray-diagnostics.md +65 -0
- package/docs/guides/channel-bus.md +127 -0
- package/docs/guides/claude-mem-setup.md +79 -0
- package/docs/guides/claude-pace-setup.md +56 -0
- package/docs/guides/claudraband-sessions.md +98 -0
- package/docs/guides/clawteam-swarm.md +116 -0
- package/docs/guides/code-review-graph-setup.md +86 -0
- package/docs/guides/email-setup.md +431 -0
- package/docs/guides/mac-mini.md +119 -0
- package/docs/guides/media-generation-setup.md +349 -0
- package/docs/guides/model-routing.md +162 -0
- package/docs/guides/observability-otel.md +265 -0
- package/docs/guides/org-onboarding.md +132 -0
- package/docs/guides/outbound-governance-setup.md +437 -0
- package/docs/guides/pdf-generation-setup.md +315 -0
- package/docs/guides/poller-daemon-setup.md +563 -0
- package/docs/guides/rag-context-setup.md +459 -0
- package/docs/guides/self-optimization-pattern.md +82 -0
- package/docs/guides/setup-wizard.md +178 -0
- package/docs/guides/slack-setup.md +350 -0
- package/docs/guides/telegram-setup.md +227 -0
- package/docs/guides/twilio-subaccounts-setup.md +223 -0
- package/docs/guides/verification.md +128 -0
- package/docs/guides/voice-mode.md +188 -0
- package/docs/guides/voice-sms-setup.md +698 -0
- package/docs/guides/webhook-relay-setup.md +349 -0
- package/docs/guides/whatsapp-setup.md +288 -0
- package/docs/prompts/board-pack-cover-template.md +36 -0
- package/docs/prompts/decision-recommendation-template.md +88 -0
- package/docs/prompts/followup-message-template.md +141 -0
- package/docs/prompts/investor-letter-template.md +52 -0
- package/docs/prompts/morning-brief-template.md +82 -0
- package/docs/prompts/presentation-template.md +58 -0
- package/docs/prompts/weekly-strategic-memo-template.md +104 -0
- package/docs/research/hallucinated-tool-output-investigation.md +151 -0
- package/docs/runbooks/backup-restore.md +205 -0
- package/docs/runbooks/cohort-cutover.md +129 -0
- package/docs/runbooks/fleet-operations.md +200 -0
- package/docs/runbooks/incident-response.md +226 -0
- package/docs/runbooks/mac-mini-bootstrap.md +431 -0
- package/docs/runbooks/perpetual-operations.md +509 -0
- package/docs/runbooks/recovery-and-failover.md +260 -0
- package/framework-features.json +267 -0
- package/ingest/README.md +87 -0
- package/lib/action-executor.js +689 -0
- package/lib/action-executor.test.mjs +871 -0
- package/lib/agent-root.mjs +37 -0
- package/lib/archetype.mjs +236 -0
- package/lib/archetype.test.mjs +132 -0
- package/lib/autonomy.mjs +114 -0
- package/lib/autonomy.test.mjs +66 -0
- package/lib/backlog.mjs +358 -0
- package/lib/backlog.test.mjs +266 -0
- package/lib/budget-guard.mjs +279 -0
- package/lib/budget-guard.test.mjs +291 -0
- package/lib/cadence-bus-schedule.test.mjs +194 -0
- package/lib/cadence-bus.mjs +1120 -0
- package/lib/cadence-bus.test.mjs +720 -0
- package/lib/cadences.mjs +205 -0
- package/lib/cadences.test.mjs +125 -0
- package/lib/capability.mjs +154 -0
- package/lib/capability.test.mjs +78 -0
- package/lib/channels/base-adapter.mjs +719 -0
- package/lib/channels/base-adapter.test.mjs +590 -0
- package/lib/channels/channel.mjs +128 -0
- package/lib/channels/channels.test.mjs +371 -0
- package/lib/channels/contract.mjs +215 -0
- package/lib/channels/contract.test.mjs +137 -0
- package/lib/channels/conversation-resolver.mjs +95 -0
- package/lib/channels/gmail/adapter.mjs +87 -0
- package/lib/channels/inbox-item.mjs +255 -0
- package/lib/channels/inbox-item.test.mjs +335 -0
- package/lib/channels/index.mjs +94 -0
- package/lib/channels/orgmail/adapter.mjs +353 -0
- package/lib/channels/orgmail/adapter.test.mjs +311 -0
- package/lib/channels/pairing.mjs +363 -0
- package/lib/channels/pairing.test.mjs +270 -0
- package/lib/channels/registry.mjs +164 -0
- package/lib/channels/slack/adapter.mjs +317 -0
- package/lib/channels/slack-adapter.test.mjs +212 -0
- package/lib/channels/sms/adapter.mjs +43 -0
- package/lib/channels/telegram/adapter.mjs +432 -0
- package/lib/channels/telegram-adapter.test.mjs +306 -0
- package/lib/channels/voice/adapter.mjs +301 -0
- package/lib/channels/voice/adapter.test.mjs +278 -0
- package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
- package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
- package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
- package/lib/charter.mjs +256 -0
- package/lib/charter.test.mjs +89 -0
- package/lib/claude-bin.mjs +134 -0
- package/lib/claude-bin.test.mjs +75 -0
- package/lib/collective/capture.mjs +185 -0
- package/lib/collective/capture.test.mjs +121 -0
- package/lib/collective/cards.mjs +201 -0
- package/lib/collective/cards.test.mjs +114 -0
- package/lib/collective/config.mjs +186 -0
- package/lib/collective/config.test.mjs +123 -0
- package/lib/collective/global-config.mjs +113 -0
- package/lib/collective/global-config.test.mjs +75 -0
- package/lib/collective/presence.mjs +201 -0
- package/lib/collective/presence.test.mjs +95 -0
- package/lib/collective/recall.mjs +215 -0
- package/lib/collective/recall.test.mjs +116 -0
- package/lib/comms/send-gate.mjs +554 -0
- package/lib/comms/send-gate.test.mjs +577 -0
- package/lib/comms.mjs +67 -0
- package/lib/comms.test.mjs +41 -0
- package/lib/diagnostics/alerts.mjs +424 -0
- package/lib/diagnostics/alerts.test.mjs +318 -0
- package/lib/diagnostics/backup-freshness.mjs +188 -0
- package/lib/diagnostics/backup-freshness.test.mjs +185 -0
- package/lib/diagnostics/counters.mjs +269 -0
- package/lib/diagnostics/counters.test.mjs +206 -0
- package/lib/diagnostics/events.mjs +188 -0
- package/lib/diagnostics/events.test.mjs +290 -0
- package/lib/diagnostics/otel.mjs +237 -0
- package/lib/diagnostics/otel.test.mjs +196 -0
- package/lib/diagnostics/trace.mjs +216 -0
- package/lib/diagnostics/trace.test.mjs +251 -0
- package/lib/env-compat.mjs +74 -0
- package/lib/env-compat.test.mjs +104 -0
- package/lib/feature-init.mjs +331 -0
- package/lib/fs-atomic.mjs +112 -0
- package/lib/fs-atomic.test.mjs +72 -0
- package/lib/fs-ownership.mjs +111 -0
- package/lib/fs-ownership.test.mjs +158 -0
- package/lib/hooks/bus.mjs +347 -0
- package/lib/hooks/bus.test.mjs +387 -0
- package/lib/index.js +16 -0
- package/lib/learning/config.mjs +106 -0
- package/lib/learning/config.test.mjs +75 -0
- package/lib/learning/counters.mjs +156 -0
- package/lib/learning/counters.test.mjs +69 -0
- package/lib/learning/curator-consolidate.test.mjs +238 -0
- package/lib/learning/curator.mjs +453 -0
- package/lib/learning/curator.test.mjs +106 -0
- package/lib/learning/log.mjs +40 -0
- package/lib/learning/reflect.mjs +534 -0
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.mjs +352 -0
- package/lib/learning/session-index.test.mjs +125 -0
- package/lib/learning/skill-writer.mjs +474 -0
- package/lib/learning/skill-writer.test.mjs +210 -0
- package/lib/mcp/server.mjs +328 -0
- package/lib/mcp/server.test.mjs +400 -0
- package/lib/model-router/auth-profiles.mjs +758 -0
- package/lib/model-router/auth-profiles.test.mjs +580 -0
- package/lib/model-router/catalog/anthropic.yaml +153 -0
- package/lib/model-router/catalog/deepseek.yaml +86 -0
- package/lib/model-router/catalog/moonshot.yaml +81 -0
- package/lib/model-router/catalog/qwen.yaml +114 -0
- package/lib/model-router/catalog.mjs +925 -0
- package/lib/model-router/catalog.test.mjs +385 -0
- package/lib/model-router/economics.mjs +564 -0
- package/lib/model-router/economics.test.mjs +344 -0
- package/lib/model-router/failover.mjs +298 -0
- package/lib/model-router/failover.test.mjs +439 -0
- package/lib/model-router/health.mjs +453 -0
- package/lib/model-router/health.test.mjs +338 -0
- package/lib/model-router/integration-coverage.test.mjs +829 -0
- package/lib/model-router/integration.test.mjs +564 -0
- package/lib/model-router/ledger.mjs +402 -0
- package/lib/model-router/ledger.test.mjs +382 -0
- package/lib/model-router/llm-task.mjs +515 -0
- package/lib/model-router/llm-task.test.mjs +392 -0
- package/lib/model-router/org-credentials.mjs +260 -0
- package/lib/model-router/org-credentials.test.mjs +265 -0
- package/lib/model-router/pricing-refresh.mjs +463 -0
- package/lib/model-router/pricing-refresh.test.mjs +286 -0
- package/lib/model-router/reconcile.mjs +429 -0
- package/lib/model-router/reconcile.test.mjs +316 -0
- package/lib/model-router/repair.mjs +471 -0
- package/lib/model-router/repair.test.mjs +180 -0
- package/lib/model-router/resolve.mjs +1206 -0
- package/lib/model-router/spawn.mjs +497 -0
- package/lib/model-router/spawn.test.mjs +425 -0
- package/lib/model-router/taxonomy.mjs +893 -0
- package/lib/model-router/taxonomy.test.mjs +410 -0
- package/lib/model-router.mjs +677 -0
- package/lib/model-router.test.mjs +907 -0
- package/lib/org/activity.mjs +211 -0
- package/lib/org/activity.test.mjs +134 -0
- package/lib/org/approvals.mjs +448 -0
- package/lib/org/approvals.test.mjs +216 -0
- package/lib/org/awareness.mjs +222 -0
- package/lib/org/awareness.test.mjs +159 -0
- package/lib/org/board.mjs +229 -0
- package/lib/org/board.test.mjs +177 -0
- package/lib/org/bootstrap-context.mjs +169 -0
- package/lib/org/bootstrap-context.test.mjs +153 -0
- package/lib/org/client.mjs +1628 -0
- package/lib/org/client.test.mjs +1107 -0
- package/lib/org/cohort-client.mjs +67 -0
- package/lib/org/cohort-client.test.mjs +126 -0
- package/lib/org/cost-sync.mjs +227 -0
- package/lib/org/cost-sync.test.mjs +153 -0
- package/lib/org/doctor.mjs +212 -0
- package/lib/org/doctor.test.mjs +212 -0
- package/lib/org/handoff.mjs +293 -0
- package/lib/org/handoff.test.mjs +269 -0
- package/lib/org/integration-tools.mjs +182 -0
- package/lib/org/integration-tools.test.mjs +160 -0
- package/lib/org/keys.mjs +131 -0
- package/lib/org/keys.test.mjs +92 -0
- package/lib/org/knowledge.mjs +463 -0
- package/lib/org/knowledge.test.mjs +319 -0
- package/lib/org/leases.mjs +335 -0
- package/lib/org/leases.test.mjs +235 -0
- package/lib/org/mesh-integration.test.mjs +127 -0
- package/lib/org/mesh.mjs +459 -0
- package/lib/org/mesh.test.mjs +345 -0
- package/lib/org/messaging.mjs +503 -0
- package/lib/org/messaging.test.mjs +238 -0
- package/lib/org/policy.mjs +345 -0
- package/lib/org/policy.test.mjs +237 -0
- package/lib/org/protocol.checksum +1 -0
- package/lib/org/protocol.checksum.test.mjs +90 -0
- package/lib/org/protocol.mjs +967 -0
- package/lib/org/protocol.test.mjs +264 -0
- package/lib/org/registry.mjs +194 -0
- package/lib/org/registry.test.mjs +100 -0
- package/lib/org/tool-surface-integration.test.mjs +120 -0
- package/lib/org/tool-surface.mjs +2535 -0
- package/lib/org/tool-surface.test.mjs +589 -0
- package/lib/org/ui-parity.mjs +3236 -0
- package/lib/org/ui-parity.test.mjs +348 -0
- package/lib/org/verify.mjs +176 -0
- package/lib/org/verify.test.mjs +194 -0
- package/lib/rag/embed.mjs +188 -0
- package/lib/rag/indexer.mjs +425 -0
- package/lib/rag/rag.test.mjs +505 -0
- package/lib/rag/search.mjs +475 -0
- package/lib/rate-guard.mjs +246 -0
- package/lib/rate-guard.test.mjs +201 -0
- package/lib/render.mjs +112 -0
- package/lib/render.test.mjs +68 -0
- package/lib/resource-governor.mjs +297 -0
- package/lib/resource-governor.test.mjs +262 -0
- package/lib/scheduling/dynamic-jobs.mjs +675 -0
- package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
- package/lib/scheduling/jitter.mjs +0 -0
- package/lib/scheduling/jitter.test.mjs +140 -0
- package/lib/secrets/broker.mjs +315 -0
- package/lib/secrets/broker.test.mjs +280 -0
- package/lib/secrets/providers.mjs +461 -0
- package/lib/secrets/providers.test.mjs +274 -0
- package/lib/security/audit-engine.mjs +684 -0
- package/lib/security/audit-engine.test.mjs +389 -0
- package/lib/security/coerce-args.mjs +552 -0
- package/lib/security/coerce-args.test.mjs +281 -0
- package/lib/security/dangerous-tools.mjs +97 -0
- package/lib/security/dangerous-tools.test.mjs +68 -0
- package/lib/security/external-content.mjs +145 -0
- package/lib/security/external-content.test.mjs +67 -0
- package/lib/security/redact.mjs +592 -0
- package/lib/security/redact.test.mjs +441 -0
- package/lib/security/secret-equal.mjs +73 -0
- package/lib/security/secret-equal.test.mjs +55 -0
- package/lib/session-permissions.mjs +101 -0
- package/lib/session-permissions.test.mjs +100 -0
- package/lib/setup/claude-probe.mjs +74 -0
- package/lib/setup/completeness.mjs +175 -0
- package/lib/setup/completeness.test.mjs +110 -0
- package/lib/setup/context-pack.mjs +173 -0
- package/lib/setup/context-pack.test.mjs +89 -0
- package/lib/setup/enrich.mjs +277 -0
- package/lib/setup/enrich.test.mjs +115 -0
- package/lib/setup/enroll-from-cohort.mjs +441 -0
- package/lib/setup/enroll-from-cohort.test.mjs +233 -0
- package/lib/setup/integration.test.mjs +162 -0
- package/lib/setup/io.mjs +360 -0
- package/lib/setup/io.test.mjs +77 -0
- package/lib/setup/run-generator.mjs +81 -0
- package/lib/setup/runner.mjs +244 -0
- package/lib/setup/runner.test.mjs +132 -0
- package/lib/setup/sections/comms.mjs +173 -0
- package/lib/setup/sections/company.mjs +120 -0
- package/lib/setup/sections/enrich.mjs +138 -0
- package/lib/setup/sections/identity.mjs +182 -0
- package/lib/setup/sections/identity.test.mjs +140 -0
- package/lib/setup/sections/learning.mjs +153 -0
- package/lib/setup/sections/learning.test.mjs +81 -0
- package/lib/setup/sections/messaging.mjs +219 -0
- package/lib/setup/sections/messaging.test.mjs +127 -0
- package/lib/setup/sections/model.mjs +102 -0
- package/lib/setup/sections/operating-model.mjs +78 -0
- package/lib/setup/sections/org.mjs +475 -0
- package/lib/setup/sections/org.test.mjs +313 -0
- package/lib/setup/sections/orgmail.mjs +173 -0
- package/lib/setup/sections/orgmail.test.mjs +118 -0
- package/lib/setup/sections/recovery.mjs +159 -0
- package/lib/setup/sections/recovery.test.mjs +98 -0
- package/lib/setup/sections/tools.mjs +132 -0
- package/lib/setup/sections/verify.mjs +97 -0
- package/lib/setup/sot.mjs +205 -0
- package/lib/setup/sot.test.mjs +81 -0
- package/lib/setup/state.mjs +151 -0
- package/lib/setup/state.test.mjs +92 -0
- package/lib/singleton.js +229 -0
- package/lib/singleton.test.mjs +135 -0
- package/lib/telemetry/alerts.mjs +216 -0
- package/lib/telemetry/alerts.test.mjs +109 -0
- package/lib/telemetry/collect.mjs +512 -0
- package/lib/telemetry/collect.test.mjs +202 -0
- package/lib/tool-definitions-integration.test.mjs +83 -0
- package/lib/tool-definitions.js +738 -0
- package/lib/tool-definitions.test.mjs +437 -0
- package/lib/util/fetch-timeout.mjs +136 -0
- package/lib/util/fetch-timeout.test.mjs +202 -0
- package/lib/util/reconnect.mjs +343 -0
- package/lib/util/reconnect.test.mjs +369 -0
- package/lib/util/unhandled.mjs +205 -0
- package/lib/util/unhandled.test.mjs +216 -0
- package/lib/voice/context-loader.mjs +466 -0
- package/lib/voice/index.mjs +100 -0
- package/lib/voice/openai-realtime.mjs +510 -0
- package/lib/voice/outbound.mjs +542 -0
- package/lib/voice/outbound.test.mjs +69 -0
- package/lib/voice/post-call-brief.mjs +428 -0
- package/lib/voice/provider.mjs +52 -0
- package/lib/voice/session-rotation.mjs +257 -0
- package/lib/voice/stt.mjs +161 -0
- package/lib/voice/stt.test.mjs +226 -0
- package/lib/voice/tool-bridge.mjs +370 -0
- package/lib/voice/tts.mjs +104 -0
- package/lib/voice/twilio-sip-bridge.mjs +288 -0
- package/lib/voice/voice.test.mjs +990 -0
- package/mcp/README.md +80 -0
- package/package.json +151 -0
- package/plugins/maestro-skills/plugin.json +139 -0
- package/plugins/maestro-skills/skills/agents-observe.md +110 -0
- package/plugins/maestro-skills/skills/board-deck.md +68 -0
- package/plugins/maestro-skills/skills/books-close.md +77 -0
- package/plugins/maestro-skills/skills/brand-steward.md +121 -0
- package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
- package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
- package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
- package/plugins/maestro-skills/skills/claude-pace.md +61 -0
- package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
- package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
- package/plugins/maestro-skills/skills/decision-brief.md +89 -0
- package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
- package/plugins/maestro-skills/skills/draft-comms.md +84 -0
- package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
- package/plugins/maestro-skills/skills/files-find.md +65 -0
- package/plugins/maestro-skills/skills/generative-ui.md +228 -0
- package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
- package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
- package/plugins/maestro-skills/skills/mail-triage.md +86 -0
- package/plugins/maestro-skills/skills/morning-brief.md +54 -0
- package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
- package/plugins/maestro-skills/skills/org-board.md +133 -0
- package/plugins/maestro-skills/skills/org-credential.md +68 -0
- package/plugins/maestro-skills/skills/org-recall.md +81 -0
- package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
- package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
- package/plugins/maestro-skills/skills/router-why.md +78 -0
- package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
- package/plugins/maestro-skills/skills/session-search.md +71 -0
- package/plugins/maestro-skills/skills/set-reminder.md +93 -0
- package/plugins/maestro-skills/skills/slack-followup.md +64 -0
- package/plugins/maestro-skills/skills/team-activity.md +86 -0
- package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
- package/policies/action-classification.yaml +114 -0
- package/policies/ai-disclosure.yaml +294 -0
- package/policies/communication-style.md +139 -0
- package/policies/information-barriers.yaml +118 -0
- package/policies/prompt-injection-defence.yaml +138 -0
- package/public/assets/icon-dark.png +0 -0
- package/public/assets/icon-dark.svg +9 -0
- package/public/assets/icon-light.svg +9 -0
- package/public/assets/logo-dark.svg +15 -0
- package/public/assets/logo-light.svg +15 -0
- package/scaffold/.mcp.json +7 -0
- package/scaffold/CLAUDE.md +368 -0
- package/scaffold/config/agent.json +55 -0
- package/scaffold/config/agent.ts +76 -0
- package/scaffold/config/agent.ts.example +89 -0
- package/scaffold/config/alerts.yaml +23 -0
- package/scaffold/config/allowlist.yaml.example +25 -0
- package/scaffold/config/caller-id-map.yaml +46 -0
- package/scaffold/config/collective.yaml +49 -0
- package/scaffold/config/company.json +20 -0
- package/scaffold/config/known-agents.json +6 -0
- package/scaffold/config/learning.yaml +55 -0
- package/scaffold/config/model-routing.yaml.example +104 -0
- package/scaffold/config/org.yaml +25 -0
- package/scaffold/config/orgmail.yaml.example +19 -0
- package/scaffold/config/recovery.yaml +72 -0
- package/scaffold/config/secrets.yaml +27 -0
- package/scaffold/config/slack.yaml.example +35 -0
- package/scaffold/config/telegram.yaml.example +38 -0
- package/scaffold/config/voice.yaml.example +89 -0
- package/scaffold/config/whatsapp.yaml.example +39 -0
- package/schedules/README.md +49 -0
- package/schedules/triggers/backlog-executor.md +102 -0
- package/schedules/triggers/brand-steward.md +72 -0
- package/schedules/triggers/daily-evening-wrap.md +159 -0
- package/schedules/triggers/daily-midday-sweep.md +58 -0
- package/schedules/triggers/daily-morning-brief.md +55 -0
- package/schedules/triggers/directory-hygiene.md +81 -0
- package/schedules/triggers/dynamic-jobs.md +40 -0
- package/schedules/triggers/inbox-processor.md +115 -0
- package/schedules/triggers/meeting-action-capture.md +60 -0
- package/schedules/triggers/meeting-prep.md +69 -0
- package/schedules/triggers/messaging-inbound.md +50 -0
- package/schedules/triggers/org-pulse.md +24 -0
- package/schedules/triggers/quarterly-self-assessment.md +54 -0
- package/schedules/triggers/weekly-engineering-health.md +37 -0
- package/schedules/triggers/weekly-execution.md +65 -0
- package/schedules/triggers/weekly-hiring.md +53 -0
- package/schedules/triggers/weekly-priorities.md +38 -0
- package/schedules/triggers/weekly-strategic-memo.md +124 -0
- package/scripts/archive-email.sh +55 -0
- package/scripts/cadence/cadence-status.mjs +36 -0
- package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
- package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
- package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
- package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
- package/scripts/ci/check-docs-accuracy.mjs +493 -0
- package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
- package/scripts/ci/check-exports-exist.mjs +140 -0
- package/scripts/ci/check-files-exist.mjs +107 -0
- package/scripts/ci/check-no-build-artifacts.mjs +111 -0
- package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
- package/scripts/ci/check-no-confidential.mjs +198 -0
- package/scripts/ci/check-no-conflict-markers.mjs +169 -0
- package/scripts/ci/check-no-residual-identity.mjs +163 -0
- package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
- package/scripts/ci/check-tarball-fidelity.mjs +205 -0
- package/scripts/ci/check-unresolved-tokens.mjs +83 -0
- package/scripts/ci/check.mjs +109 -0
- package/scripts/ci/check.test.mjs +194 -0
- package/scripts/ci/run-coverage.mjs +82 -0
- package/scripts/ci/run-tests.mjs +71 -0
- package/scripts/cloud-relay/README.md +59 -0
- package/scripts/cloud-relay/index.mjs +233 -0
- package/scripts/cloud-relay/package.json +15 -0
- package/scripts/cloud-relay/railway.json +13 -0
- package/scripts/cloud-relay/voice/README.md +94 -0
- package/scripts/cloud-relay/voice/package-lock.json +39 -0
- package/scripts/cloud-relay/voice/package.json +16 -0
- package/scripts/cloud-relay/voice/railway.json +13 -0
- package/scripts/cloud-relay/voice/server.mjs +532 -0
- package/scripts/collective/hook-runner.mjs +211 -0
- package/scripts/collective/hook-runner.test.mjs +90 -0
- package/scripts/collective/org-pulse.mjs +72 -0
- package/scripts/collective/org-sync.mjs +61 -0
- package/scripts/collective/recall.mjs +45 -0
- package/scripts/collective/who.mjs +30 -0
- package/scripts/comms-monitor.sh +288 -0
- package/scripts/configure-whatsapp-sandbox.sh +201 -0
- package/scripts/continuous-monitor.sh +91 -0
- package/scripts/cost/fleet-digest.mjs +407 -0
- package/scripts/cost/fleet-digest.test.mjs +207 -0
- package/scripts/cost/track-claude-usage.mjs +169 -0
- package/scripts/daemon/agent-daemon.mjs +989 -0
- package/scripts/daemon/agent-daemon.test.mjs +525 -0
- package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
- package/scripts/daemon/cadence-consumer.mjs +1080 -0
- package/scripts/daemon/cadence-consumer.test.mjs +770 -0
- package/scripts/daemon/cadence-handlers.mjs +1121 -0
- package/scripts/daemon/cadence-handlers.test.mjs +617 -0
- package/scripts/daemon/classifier.mjs +704 -0
- package/scripts/daemon/classifier.test.mjs +238 -0
- package/scripts/daemon/classify-kind.mjs +54 -0
- package/scripts/daemon/classify-kind.test.mjs +40 -0
- package/scripts/daemon/context-compiler.mjs +605 -0
- package/scripts/daemon/context-compiler.test.mjs +300 -0
- package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
- package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
- package/scripts/daemon/dispatcher.mjs +1516 -0
- package/scripts/daemon/health.mjs +72 -0
- package/scripts/daemon/inbox-deferral.mjs +210 -0
- package/scripts/daemon/inbox-deferral.test.mjs +242 -0
- package/scripts/daemon/integration.test.mjs +149 -0
- package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
- package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
- package/scripts/daemon/launchd-wrapper.sh +91 -0
- package/scripts/daemon/lib/session-router.mjs +274 -0
- package/scripts/daemon/lib/session-router.test.mjs +295 -0
- package/scripts/daemon/maestro-daemon.mjs +275 -0
- package/scripts/daemon/prompt-builder.mjs +685 -0
- package/scripts/daemon/prompt-builder.test.mjs +213 -0
- package/scripts/daemon/responder.mjs +854 -0
- package/scripts/daemon/session-lock.mjs +721 -0
- package/scripts/daemon/session-lock.test.mjs +252 -0
- package/scripts/daemon/session-outcomes.mjs +640 -0
- package/scripts/daemon/session-outcomes.test.mjs +533 -0
- package/scripts/daemon/typing-registry.mjs +90 -0
- package/scripts/daemon/typing-registry.test.mjs +77 -0
- package/scripts/daemon/voice-webhook-server.mjs +804 -0
- package/scripts/decisions/capture-decision.mjs +116 -0
- package/scripts/disclosure_assessment.py +873 -0
- package/scripts/disclosure_boundaries.py +562 -0
- package/scripts/email-signature-principal.html +52 -0
- package/scripts/email-signature.html +60 -0
- package/scripts/email_quote_thread.py +167 -0
- package/scripts/email_thread_dedup.py +362 -0
- package/scripts/emergency-stop.sh +81 -0
- package/scripts/healthcheck.sh +116 -0
- package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
- package/scripts/hooks/block-mcp-slack-send.sh +7 -0
- package/scripts/hooks/post-action-log.sh +126 -0
- package/scripts/hooks/pre-send-audit.sh +174 -0
- package/scripts/hooks/pre-send-audit.test.mjs +215 -0
- package/scripts/hooks/session-end-log.sh +27 -0
- package/scripts/hooks/session-start-banner.sh +115 -0
- package/scripts/huddle/audio-bridge.mjs +664 -0
- package/scripts/huddle/boot-slack-cdp.sh +102 -0
- package/scripts/huddle/huddle-controller.mjs +942 -0
- package/scripts/huddle/huddle-server.mjs +1229 -0
- package/scripts/huddle/launch-slack.sh +232 -0
- package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
- package/scripts/huddle/package-lock.json +62 -0
- package/scripts/huddle/package.json +22 -0
- package/scripts/huddle/setup-audio.sh +239 -0
- package/scripts/huddle/start-call.mjs +318 -0
- package/scripts/huddle/test-pipeline.mjs +263 -0
- package/scripts/learning/consolidate-skills.mjs +72 -0
- package/scripts/learning/session-search.mjs +125 -0
- package/scripts/llm_email_dedup.py +442 -0
- package/scripts/local-triggers/generate-plists.sh +432 -0
- package/scripts/local-triggers/generate-plists.test.mjs +413 -0
- package/scripts/local-triggers/install-all.sh +49 -0
- package/scripts/local-triggers/plists/.gitkeep +0 -0
- package/scripts/local-triggers/run-trigger.sh +63 -0
- package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
- package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
- package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
- package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
- package/scripts/maintenance/backup-to-cloud.sh +124 -0
- package/scripts/maintenance/health-check.sh +377 -0
- package/scripts/media-generation/README.md +105 -0
- package/scripts/media-generation/gemini-image-client.mjs +173 -0
- package/scripts/media-generation/generate-assets.mjs +289 -0
- package/scripts/media-generation/veo-video-client.mjs +219 -0
- package/scripts/org/send-orgmail.mjs +227 -0
- package/scripts/outbound-dedup-cleanup.sh +43 -0
- package/scripts/outbound-dedup.sh +477 -0
- package/scripts/outbound_dedup.py +115 -0
- package/scripts/parse-voice-transcript.mjs +481 -0
- package/scripts/pdf-generation/README.md +63 -0
- package/scripts/pdf-generation/build-document.mjs +247 -0
- package/scripts/pdf-generation/templates/board-pack.latex +136 -0
- package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
- package/scripts/pdf-generation/templates/memo.latex +114 -0
- package/scripts/poll-slack-events.sh +35 -0
- package/scripts/poller/calendar-poller.mjs +12 -0
- package/scripts/poller/gmail-poller.mjs +192 -0
- package/scripts/poller/imap-client.mjs +289 -0
- package/scripts/poller/inbox-scan-poller.mjs +156 -0
- package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
- package/scripts/poller/index.mjs +73 -0
- package/scripts/poller/intra-session-check.mjs +285 -0
- package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
- package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
- package/scripts/poller/secondary-gmail-poller.mjs +132 -0
- package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
- package/scripts/poller/slack-poller.mjs +854 -0
- package/scripts/poller/slack-socket-mode.mjs +917 -0
- package/scripts/poller/slack-socket-mode.test.mjs +753 -0
- package/scripts/poller/trigger.mjs +75 -0
- package/scripts/poller/utils.mjs +371 -0
- package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
- package/scripts/poller/voice-poller.mjs +236 -0
- package/scripts/poller-launchd/install.sh +66 -0
- package/scripts/poller-launchd/poller.plist.template +40 -0
- package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
- package/scripts/post-interaction-indexer.py +1598 -0
- package/scripts/pre-draft-context.py +994 -0
- package/scripts/pre_draft_lookup.py +258 -0
- package/scripts/rag/build-index.mjs +47 -0
- package/scripts/rag/ingest.mjs +111 -0
- package/scripts/rag/search.mjs +119 -0
- package/scripts/rag-indexer.py +629 -0
- package/scripts/restore-from-backup.sh +248 -0
- package/scripts/restore-from-backup.test.mjs +178 -0
- package/scripts/resume-operations.sh +80 -0
- package/scripts/search-secondary-inbox.py +181 -0
- package/scripts/secondary-inbox-poller.py +437 -0
- package/scripts/self-optimization/compute-metrics.py +398 -0
- package/scripts/send-email-as-principal.py +369 -0
- package/scripts/send-email-threaded.py +392 -0
- package/scripts/send-email-with-attachment.py +377 -0
- package/scripts/send-email.sh +131 -0
- package/scripts/send-sms.sh +175 -0
- package/scripts/send-whatsapp.sh +292 -0
- package/scripts/session-start.sh +106 -0
- package/scripts/setup/boot-claude-session.sh +94 -0
- package/scripts/setup/configure-macos.sh +674 -0
- package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
- package/scripts/setup/configure-voice-tunnel.mjs +182 -0
- package/scripts/setup/generate-agent-env.mjs +92 -0
- package/scripts/setup/generate-agent-package-json.mjs +222 -0
- package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
- package/scripts/setup/generate-autonomy.mjs +60 -0
- package/scripts/setup/generate-backlog.mjs +101 -0
- package/scripts/setup/generate-cadences.mjs +92 -0
- package/scripts/setup/generate-capability.mjs +162 -0
- package/scripts/setup/generate-charter.mjs +76 -0
- package/scripts/setup/generate-comms.mjs +59 -0
- package/scripts/setup/generate-company.mjs +92 -0
- package/scripts/setup/init-agent.sh +547 -0
- package/scripts/setup/init-agent.test.mjs +151 -0
- package/scripts/setup/init-archetype.mjs +74 -0
- package/scripts/setup/init-backup.mjs +54 -0
- package/scripts/setup/init-cadence-bus.mjs +60 -0
- package/scripts/setup/init-channel-bus.mjs +46 -0
- package/scripts/setup/init-cost-tracking.mjs +45 -0
- package/scripts/setup/init-decision-capture.mjs +66 -0
- package/scripts/setup/init-known-agents.mjs +57 -0
- package/scripts/setup/init-learning.mjs +70 -0
- package/scripts/setup/init-memory-executive.mjs +45 -0
- package/scripts/setup/init-model-router.mjs +124 -0
- package/scripts/setup/init-rag.mjs +174 -0
- package/scripts/setup/init-session-router.mjs +38 -0
- package/scripts/setup/init-slack-socket-mode.mjs +260 -0
- package/scripts/setup/init-telegram.mjs +165 -0
- package/scripts/setup/init-voice-realtime.mjs +204 -0
- package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
- package/scripts/setup/install-dev-tools.sh +150 -0
- package/scripts/setup/lib/install-plist.mjs +95 -0
- package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
- package/scripts/setup/render-environment-yaml.mjs +133 -0
- package/scripts/slack-events-ctl.sh +177 -0
- package/scripts/slack-events-server.mjs +1045 -0
- package/scripts/slack-react.mjs +89 -0
- package/scripts/slack-responded.sh +232 -0
- package/scripts/slack-send.sh +287 -0
- package/scripts/slack-typing.mjs +196 -0
- package/scripts/slack-upload-v2.py +95 -0
- package/scripts/sms-handler.mjs +450 -0
- package/scripts/spawn-session.sh +120 -0
- package/scripts/sync-protocol.mjs +217 -0
- package/scripts/system-verify.sh +184 -0
- package/scripts/test-email-thread-dedup.py +239 -0
- package/scripts/test-information-barriers.py +484 -0
- package/scripts/test-llm-email-dedup.py +251 -0
- package/scripts/test-pre-draft-integration.py +203 -0
- package/scripts/test-rag-phase2.sh +442 -0
- package/scripts/test-rag-search.sh +251 -0
- package/scripts/test-voice-parser.mjs +316 -0
- package/scripts/user-context-search.py +659 -0
- package/scripts/validate_outbound.py +1504 -0
- package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
- package/scripts/watchdog/force-reboot.sh +157 -0
- package/scripts/watchdog/memory-watchdog.sh +473 -0
- package/scripts/whatsapp-handler.mjs +538 -0
- package/teams/desktop-operations.yaml +34 -0
- package/teams/executive-office.yaml +27 -0
- package/teams/legal-and-regulatory.yaml +24 -0
- package/teams/platform-and-engineering.yaml +23 -0
- package/teams/strategy-and-growth.yaml +29 -0
- package/workflows/continuous/backlog-executor.yaml +141 -0
- package/workflows/continuous/inbound-monitor.yaml +168 -0
- package/workflows/daily/applicant-triage.yaml +197 -0
- package/workflows/daily/comms-triage.yaml +80 -0
- package/workflows/daily/evening-wrap.yaml +105 -0
- package/workflows/daily/morning-brief.yaml +164 -0
- package/workflows/daily/slack-followup-sweep.yaml +87 -0
- package/workflows/event-driven/README.md +50 -0
- package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
- package/workflows/event-driven/pr-review.yaml +107 -0
- package/workflows/monthly/board-readiness.yaml +76 -0
- package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
- package/workflows/session-protocol.md +171 -0
- package/workflows/weekly/engineering-health.yaml +154 -0
- package/workflows/weekly/hiring-review.yaml +169 -0
- package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
- package/workflows/weekly/strategic-memo.yaml +79 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/telemetry/collect.mjs — build the SHARED STATUS SNAPSHOT for an agent.
|
|
3
|
+
*
|
|
4
|
+
* THE GAP this closes: the org mesh presence-beat already proves an agent is
|
|
5
|
+
* alive, but it carries no picture of WHAT the agent is doing or HOW healthy its
|
|
6
|
+
* machine is. `collectStatus` assembles the one snapshot the whole fleet agrees
|
|
7
|
+
* on — emitted by the client on every presence beat, stored by the server, and
|
|
8
|
+
* read back by `lib/org/activity.mjs` so any agent (or a human) can ask "who is
|
|
9
|
+
* doing what right now". The snapshot shape is the frozen contract:
|
|
10
|
+
*
|
|
11
|
+
* status = {
|
|
12
|
+
* state: "active"|"idle"|"busy"|"error"|"offline",
|
|
13
|
+
* activity: string, // human-readable ("handling inbox" / "session: <taskClass>" / "idle")
|
|
14
|
+
* subAgentsRunning: number, // running claude child processes (best-effort)
|
|
15
|
+
* session: { id?, taskClass?, model? } | null,
|
|
16
|
+
* machine: {
|
|
17
|
+
* loadavg: [n,n,n],
|
|
18
|
+
* memUsedPct: number, // 1 - free/total
|
|
19
|
+
* cpuPct?: number, // best-effort (powermetrics)
|
|
20
|
+
* tempC?: number, // best-effort (powermetrics)
|
|
21
|
+
* diskUsedPct?: number,
|
|
22
|
+
* },
|
|
23
|
+
* claudeAuth: "ok"|"relogin_required"|"unknown",
|
|
24
|
+
* alerts: [{ id, severity, kind, detail }],
|
|
25
|
+
* ts: ISO8601,
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* It rides `presence.beat` params as `params.status` — NO protocol change (the
|
|
29
|
+
* server handler validates beat params and stores the snapshot).
|
|
30
|
+
*
|
|
31
|
+
* DESIGN: pure-ish + fully injectable. The real I/O surfaces (node:os, the
|
|
32
|
+
* session/presence state on disk, `powermetrics`, `df`, the log files) are all
|
|
33
|
+
* reached through an injectable `deps` bag so tests are hermetic and CI never
|
|
34
|
+
* forks `powermetrics`. Every gather step is independently fail-open: a broken
|
|
35
|
+
* probe degrades that one field (best-effort fields drop out; required fields get
|
|
36
|
+
* a benign default), it NEVER throws and NEVER blocks the beat.
|
|
37
|
+
*
|
|
38
|
+
* G16 (zero-LLM-in-the-coordination-loop): pure os reads + file reads + a guarded
|
|
39
|
+
* `powermetrics`/`df` exec. ZERO LLM calls.
|
|
40
|
+
*
|
|
41
|
+
* Constraints (CLAUDE.md): ESM, execFile (not exec), Node built-ins only,
|
|
42
|
+
* everything injectable.
|
|
43
|
+
*
|
|
44
|
+
* @module lib/telemetry/collect
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
"use strict";
|
|
48
|
+
|
|
49
|
+
import os from "node:os";
|
|
50
|
+
import { execFile } from "node:child_process";
|
|
51
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
52
|
+
import { join, resolve } from "node:path";
|
|
53
|
+
|
|
54
|
+
import { list as listPresence } from "../collective/presence.mjs";
|
|
55
|
+
import { liveClaudeStats } from "../resource-governor.mjs";
|
|
56
|
+
|
|
57
|
+
/** Default temperature probe ceiling — used only as a guard in alerts; here we just report. */
|
|
58
|
+
const VALID_STATES = new Set(["active", "idle", "busy", "error", "offline"]);
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Small helpers
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
function nowMsFrom(now) {
|
|
65
|
+
if (typeof now === "function") { const v = Number(now()); return Number.isFinite(v) ? v : Date.now(); }
|
|
66
|
+
if (Number.isFinite(now)) return Number(now);
|
|
67
|
+
return Date.now();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function pct(n) {
|
|
71
|
+
const v = Number(n);
|
|
72
|
+
if (!Number.isFinite(v)) return 0;
|
|
73
|
+
return Math.round(Math.max(0, Math.min(100, v)) * 10) / 10;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function safeReadJson(path) {
|
|
77
|
+
try { return JSON.parse(readFileSync(path, "utf8")); } catch { return null; }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Run a command via execFile with a hard timeout, resolving to its stdout string
|
|
82
|
+
* or "" on ANY failure (timeout, missing binary, non-zero exit). Never rejects —
|
|
83
|
+
* a slow/absent powermetrics must never wedge the beat.
|
|
84
|
+
*/
|
|
85
|
+
function execFileSafe(execFileImpl, cmd, args, timeoutMs) {
|
|
86
|
+
return new Promise((res) => {
|
|
87
|
+
let done = false;
|
|
88
|
+
const finish = (v) => { if (!done) { done = true; res(v || ""); } };
|
|
89
|
+
try {
|
|
90
|
+
const child = execFileImpl(cmd, args, { timeout: timeoutMs, maxBuffer: 4 * 1024 * 1024 }, (err, stdout) => {
|
|
91
|
+
if (err) return finish("");
|
|
92
|
+
finish(typeof stdout === "string" ? stdout : "");
|
|
93
|
+
});
|
|
94
|
+
// execFile's own timeout kills the child; this belt-and-braces guard
|
|
95
|
+
// resolves us even if the callback never fires.
|
|
96
|
+
const t = setTimeout(() => finish(""), timeoutMs + 250);
|
|
97
|
+
if (t && typeof t.unref === "function") t.unref();
|
|
98
|
+
if (child && typeof child.on === "function") child.on("error", () => finish(""));
|
|
99
|
+
} catch { finish(""); }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// State + activity (what is the agent doing right now)
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolve the current session/activity from local daemon + presence state. We
|
|
109
|
+
* look at, in order:
|
|
110
|
+
* 1. an explicit `deps.sessions` array (injected; tests)
|
|
111
|
+
* 2. the live presence registry (state/collective/presence) — daemon + sessions
|
|
112
|
+
* The "primary" session is the most-recently-beating non-daemon session, else the
|
|
113
|
+
* daemon record. We derive:
|
|
114
|
+
* - session: { id?, taskClass?, model? } | null
|
|
115
|
+
* - activity: a human-readable line
|
|
116
|
+
* - state: idle | busy | active
|
|
117
|
+
* Best-effort; never throws.
|
|
118
|
+
*
|
|
119
|
+
* @returns {{ session:object|null, activity:string, state:string }}
|
|
120
|
+
*/
|
|
121
|
+
export function resolveActivity(o = {}) {
|
|
122
|
+
const agentRoot = o.agentRoot;
|
|
123
|
+
const nowMs = nowMsFrom(o.now);
|
|
124
|
+
let records = [];
|
|
125
|
+
try {
|
|
126
|
+
if (Array.isArray(o.sessions)) records = o.sessions;
|
|
127
|
+
else if (agentRoot) records = listPresence(agentRoot, { nowMs, reap: false });
|
|
128
|
+
} catch { records = []; }
|
|
129
|
+
records = Array.isArray(records) ? records.filter((r) => r && typeof r === "object") : [];
|
|
130
|
+
|
|
131
|
+
// Split daemon vs work sessions.
|
|
132
|
+
const work = records.filter((r) => (r.kind || "interactive") !== "daemon");
|
|
133
|
+
const daemons = records.filter((r) => (r.kind || "interactive") === "daemon");
|
|
134
|
+
|
|
135
|
+
// Primary = newest-beating work session, else the daemon.
|
|
136
|
+
const byBeat = (a, b) => Date.parse(b.lastBeat || b.startedAt || 0) - Date.parse(a.lastBeat || a.startedAt || 0);
|
|
137
|
+
const primary = work.slice().sort(byBeat)[0] || daemons.slice().sort(byBeat)[0] || null;
|
|
138
|
+
|
|
139
|
+
// Map a presence record's intent → a taskClass label. The daemon writes
|
|
140
|
+
// intent like "session: <taskClass>" / "<cadence>"; we surface the raw intent
|
|
141
|
+
// as the activity line and best-effort split a taskClass out of it.
|
|
142
|
+
let session = null;
|
|
143
|
+
let activity = "idle";
|
|
144
|
+
let state = "idle";
|
|
145
|
+
|
|
146
|
+
if (work.length > 0 && primary) {
|
|
147
|
+
state = "busy";
|
|
148
|
+
const taskClass = deriveTaskClass(primary.intent);
|
|
149
|
+
session = {
|
|
150
|
+
id: primary.sessionId || undefined,
|
|
151
|
+
taskClass: taskClass || undefined,
|
|
152
|
+
model: primary.model || undefined,
|
|
153
|
+
};
|
|
154
|
+
activity = humanActivity(primary.intent, taskClass);
|
|
155
|
+
} else if (daemons.length > 0) {
|
|
156
|
+
// Daemon up but no work session running → the agent is alive and idle.
|
|
157
|
+
state = "idle";
|
|
158
|
+
activity = "idle";
|
|
159
|
+
session = null;
|
|
160
|
+
} else {
|
|
161
|
+
state = "idle";
|
|
162
|
+
activity = "idle";
|
|
163
|
+
session = null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { session, activity, state };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Pull a taskClass out of an intent string ("session: inbox" → "inbox"). */
|
|
170
|
+
function deriveTaskClass(intent) {
|
|
171
|
+
const s = String(intent || "").trim();
|
|
172
|
+
if (!s) return "";
|
|
173
|
+
const m = s.match(/(?:session|task|cadence)\s*[:=]\s*([a-z0-9._-]+)/i);
|
|
174
|
+
if (m) return m[1];
|
|
175
|
+
// A bare single-token intent (e.g. "inbox", "morning-brief") is itself the class.
|
|
176
|
+
if (/^[a-z0-9._-]+$/i.test(s)) return s;
|
|
177
|
+
return "";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Build a human-readable activity line from an intent + derived taskClass. */
|
|
181
|
+
function humanActivity(intent, taskClass) {
|
|
182
|
+
const s = String(intent || "").trim();
|
|
183
|
+
if (s) return s.length > 120 ? `${s.slice(0, 117)}...` : s;
|
|
184
|
+
if (taskClass) return `session: ${taskClass}`;
|
|
185
|
+
return "working";
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// Machine stats
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Gather machine stats from node:os plus best-effort `powermetrics` (temp/cpu)
|
|
194
|
+
* and `df` (disk). The exec probes are guarded + injected; on macOS powermetrics
|
|
195
|
+
* needs root so a non-root agent simply gets no temp/cpu (those fields drop out).
|
|
196
|
+
*
|
|
197
|
+
* @returns {Promise<{loadavg:number[], memUsedPct:number, cpuPct?:number, tempC?:number, diskUsedPct?:number}>}
|
|
198
|
+
*/
|
|
199
|
+
export async function collectMachine(o = {}) {
|
|
200
|
+
const osImpl = o.os || os;
|
|
201
|
+
const machine = { loadavg: [0, 0, 0], memUsedPct: 0 };
|
|
202
|
+
|
|
203
|
+
// loadavg
|
|
204
|
+
try {
|
|
205
|
+
const la = osImpl.loadavg();
|
|
206
|
+
if (Array.isArray(la) && la.length >= 3) {
|
|
207
|
+
machine.loadavg = [round2(la[0]), round2(la[1]), round2(la[2])];
|
|
208
|
+
}
|
|
209
|
+
} catch { /* keep [0,0,0] */ }
|
|
210
|
+
|
|
211
|
+
// memUsedPct = 1 - free/total
|
|
212
|
+
try {
|
|
213
|
+
const total = Number(osImpl.totalmem());
|
|
214
|
+
const free = Number(osImpl.freemem());
|
|
215
|
+
if (Number.isFinite(total) && total > 0 && Number.isFinite(free)) {
|
|
216
|
+
machine.memUsedPct = pct((1 - free / total) * 100);
|
|
217
|
+
}
|
|
218
|
+
} catch { /* keep 0 */ }
|
|
219
|
+
|
|
220
|
+
// cpuPct — coarse instantaneous estimate from loadavg/cpus when powermetrics
|
|
221
|
+
// is unavailable. powermetrics (if it yields) overrides below.
|
|
222
|
+
try {
|
|
223
|
+
const cpus = osImpl.cpus();
|
|
224
|
+
const n = Array.isArray(cpus) ? cpus.length : 0;
|
|
225
|
+
if (n > 0 && Number.isFinite(machine.loadavg[0])) {
|
|
226
|
+
const est = (machine.loadavg[0] / n) * 100;
|
|
227
|
+
if (Number.isFinite(est)) machine.cpuPct = pct(est);
|
|
228
|
+
}
|
|
229
|
+
} catch { /* no cpuPct */ }
|
|
230
|
+
|
|
231
|
+
// Best-effort temp + cpu via powermetrics (guarded, injected, never blocks).
|
|
232
|
+
if (o.powermetrics !== false) {
|
|
233
|
+
const pm = await collectPowermetrics(o);
|
|
234
|
+
if (Number.isFinite(pm.tempC)) machine.tempC = round1(pm.tempC);
|
|
235
|
+
if (Number.isFinite(pm.cpuPct)) machine.cpuPct = pct(pm.cpuPct);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Best-effort diskUsedPct via df.
|
|
239
|
+
if (o.disk !== false) {
|
|
240
|
+
const disk = await collectDisk(o);
|
|
241
|
+
if (Number.isFinite(disk)) machine.diskUsedPct = pct(disk);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return machine;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Parse `powermetrics` for CPU temperature + active CPU%. Guarded: only attempts
|
|
249
|
+
* the exec on darwin (unless an explicit `deps.execFile` + `deps.platform` say
|
|
250
|
+
* otherwise for tests). Returns {} on any failure. NEVER blocks past timeoutMs.
|
|
251
|
+
*
|
|
252
|
+
* @returns {Promise<{ tempC?:number, cpuPct?:number }>}
|
|
253
|
+
*/
|
|
254
|
+
export async function collectPowermetrics(o = {}) {
|
|
255
|
+
const platform = o.platform || (o.os && o.os.platform && o.os.platform()) || process.platform;
|
|
256
|
+
const execFileImpl = o.execFile || execFile;
|
|
257
|
+
if (platform !== "darwin" && !o.execFile) return {}; // only darwin in the wild; tests inject execFile
|
|
258
|
+
const timeoutMs = Number.isFinite(o.pmTimeoutMs) ? o.pmTimeoutMs : 1500;
|
|
259
|
+
const bin = o.powermetricsBin || "/usr/bin/powermetrics";
|
|
260
|
+
if (!o.execFile && !existsSync(bin)) return {};
|
|
261
|
+
const out = await execFileSafe(
|
|
262
|
+
execFileImpl, bin,
|
|
263
|
+
["-n", "1", "-i", "200", "--samplers", "smc,cpu_power", "--show-process-energy"],
|
|
264
|
+
timeoutMs,
|
|
265
|
+
);
|
|
266
|
+
if (!out) return {};
|
|
267
|
+
return parsePowermetrics(out);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Pure parser for powermetrics text → { tempC?, cpuPct? }. Tolerant of format drift. */
|
|
271
|
+
export function parsePowermetrics(text) {
|
|
272
|
+
const out = {};
|
|
273
|
+
const s = String(text || "");
|
|
274
|
+
// Temperature: "CPU die temperature: 54.21 C" or "GPU die temperature: ..."
|
|
275
|
+
const temp = s.match(/CPU die temperature:\s*([\d.]+)\s*C/i) || s.match(/die temperature:\s*([\d.]+)\s*C/i);
|
|
276
|
+
if (temp) { const v = Number(temp[1]); if (Number.isFinite(v)) out.tempC = v; }
|
|
277
|
+
// Active CPU%: "CPU Average frequency as fraction of nominal: ..." isn't util;
|
|
278
|
+
// prefer an explicit "... active residency" total or a "CPU usage" line.
|
|
279
|
+
const idle = s.match(/CPU\s+(?:Average\s+)?idle\s+residency:\s*([\d.]+)\s*%/i);
|
|
280
|
+
if (idle) { const v = Number(idle[1]); if (Number.isFinite(v)) out.cpuPct = Math.max(0, 100 - v); }
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Best-effort diskUsedPct for the agent root's filesystem via `df -k .`. */
|
|
285
|
+
export async function collectDisk(o = {}) {
|
|
286
|
+
const execFileImpl = o.execFile || execFile;
|
|
287
|
+
const root = o.agentRoot ? resolve(o.agentRoot) : (process.env.AGENT_ROOT || process.cwd());
|
|
288
|
+
const timeoutMs = Number.isFinite(o.dfTimeoutMs) ? o.dfTimeoutMs : 1500;
|
|
289
|
+
const out = await execFileSafe(execFileImpl, "/bin/df", ["-k", root], timeoutMs);
|
|
290
|
+
if (!out) return undefined;
|
|
291
|
+
return parseDf(out);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Pure parser for `df -k` text → used percent number, or undefined. */
|
|
295
|
+
export function parseDf(text) {
|
|
296
|
+
const lines = String(text || "").trim().split("\n");
|
|
297
|
+
if (lines.length < 2) return undefined;
|
|
298
|
+
// The data row may wrap; scan for a token ending in "%".
|
|
299
|
+
for (let i = lines.length - 1; i >= 1; i--) {
|
|
300
|
+
const cols = lines[i].trim().split(/\s+/);
|
|
301
|
+
const capCol = cols.find((c) => /^\d+%$/.test(c));
|
|
302
|
+
if (capCol) { const v = Number(capCol.replace("%", "")); if (Number.isFinite(v)) return v; }
|
|
303
|
+
}
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function round1(n) { return Math.round(Number(n) * 10) / 10; }
|
|
308
|
+
function round2(n) { return Math.round(Number(n) * 100) / 100; }
|
|
309
|
+
|
|
310
|
+
// ---------------------------------------------------------------------------
|
|
311
|
+
// claudeAuth detection
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
|
|
314
|
+
/** Auth-failure fingerprints we treat as "the agent needs to re-login". */
|
|
315
|
+
const RELOGIN_FINGERPRINTS = [
|
|
316
|
+
"relogin_required",
|
|
317
|
+
"please run /login",
|
|
318
|
+
"please run claude login",
|
|
319
|
+
"run `claude login`",
|
|
320
|
+
"invalid api key",
|
|
321
|
+
"oauth token has expired",
|
|
322
|
+
"authentication_error",
|
|
323
|
+
"credentials have expired",
|
|
324
|
+
"not logged in",
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Detect whether Claude auth is healthy by scanning recent log tails for a
|
|
329
|
+
* re-login/auth fingerprint. Looks at the most recent file in each of a small set
|
|
330
|
+
* of log dirs (sessions, diagnostics) within a freshness window.
|
|
331
|
+
*
|
|
332
|
+
* Returns:
|
|
333
|
+
* "relogin_required" a recent auth/login failure is present
|
|
334
|
+
* "ok" logs exist and show no recent auth failure
|
|
335
|
+
* "unknown" no logs to judge from
|
|
336
|
+
*
|
|
337
|
+
* `deps.logText` (string) short-circuits the file scan for tests.
|
|
338
|
+
*
|
|
339
|
+
* @returns {"ok"|"relogin_required"|"unknown"}
|
|
340
|
+
*/
|
|
341
|
+
export function detectClaudeAuth(o = {}) {
|
|
342
|
+
const nowMs = nowMsFrom(o.now);
|
|
343
|
+
const windowMs = Number.isFinite(o.authWindowMs) ? o.authWindowMs : 6 * 60 * 60 * 1000; // 6h
|
|
344
|
+
|
|
345
|
+
// Test / explicit override.
|
|
346
|
+
if (typeof o.logText === "string") {
|
|
347
|
+
return scanForRelogin(o.logText) ? "relogin_required" : (o.logText ? "ok" : "unknown");
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const agentRoot = o.agentRoot;
|
|
351
|
+
if (!agentRoot) return "unknown";
|
|
352
|
+
|
|
353
|
+
const dirs = [
|
|
354
|
+
join(agentRoot, "logs", "sessions"),
|
|
355
|
+
join(agentRoot, "logs", "diagnostics"),
|
|
356
|
+
join(agentRoot, "logs"),
|
|
357
|
+
];
|
|
358
|
+
let sawAny = false;
|
|
359
|
+
let sawRelogin = false;
|
|
360
|
+
for (const dir of dirs) {
|
|
361
|
+
const file = newestFileWithin(dir, nowMs, windowMs);
|
|
362
|
+
if (!file) continue;
|
|
363
|
+
sawAny = true;
|
|
364
|
+
const text = tailFile(file, 64 * 1024);
|
|
365
|
+
if (scanForRelogin(text)) { sawRelogin = true; break; }
|
|
366
|
+
}
|
|
367
|
+
if (sawRelogin) return "relogin_required";
|
|
368
|
+
return sawAny ? "ok" : "unknown";
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function scanForRelogin(text) {
|
|
372
|
+
const lower = String(text || "").toLowerCase();
|
|
373
|
+
return RELOGIN_FINGERPRINTS.some((f) => lower.includes(f));
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Newest *.jsonl/*.log file in dir modified within windowMs of now, else null. */
|
|
377
|
+
function newestFileWithin(dir, nowMs, windowMs) {
|
|
378
|
+
try {
|
|
379
|
+
if (!existsSync(dir)) return null;
|
|
380
|
+
let best = null;
|
|
381
|
+
for (const name of readdirSync(dir)) {
|
|
382
|
+
if (!/\.(jsonl|log|txt)$/i.test(name)) continue;
|
|
383
|
+
const p = join(dir, name);
|
|
384
|
+
let st;
|
|
385
|
+
try { st = statSync(p); } catch { continue; }
|
|
386
|
+
if (!st.isFile()) continue;
|
|
387
|
+
const age = nowMs - st.mtimeMs;
|
|
388
|
+
if (!Number.isFinite(age) || age > windowMs) continue;
|
|
389
|
+
if (!best || st.mtimeMs > best.mtimeMs) best = { p, mtimeMs: st.mtimeMs };
|
|
390
|
+
}
|
|
391
|
+
return best ? best.p : null;
|
|
392
|
+
} catch { return null; }
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Read the last `bytes` of a file as utf8 (best-effort). */
|
|
396
|
+
function tailFile(path, bytes) {
|
|
397
|
+
try {
|
|
398
|
+
const buf = readFileSync(path);
|
|
399
|
+
if (buf.length <= bytes) return buf.toString("utf8");
|
|
400
|
+
return buf.slice(buf.length - bytes).toString("utf8");
|
|
401
|
+
} catch { return ""; }
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// ---------------------------------------------------------------------------
|
|
405
|
+
// subAgentsRunning
|
|
406
|
+
// ---------------------------------------------------------------------------
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Count running claude child processes (best-effort). Prefers an injected count;
|
|
410
|
+
* else reuses the resource-governor's `liveClaudeStats()` (one `ps` parse, 2s
|
|
411
|
+
* cached) so the governor and telemetry agree on "live claude". Fail-open → 0.
|
|
412
|
+
*/
|
|
413
|
+
export function countSubAgents(o = {}) {
|
|
414
|
+
if (Number.isFinite(o.subAgentsRunning)) return Math.max(0, Math.floor(o.subAgentsRunning));
|
|
415
|
+
if (typeof o.liveClaudeStats === "function") {
|
|
416
|
+
try { const v = o.liveClaudeStats(); return Math.max(0, Math.floor(Number(v && v.count) || 0)); }
|
|
417
|
+
catch { return 0; }
|
|
418
|
+
}
|
|
419
|
+
try { const v = liveClaudeStats(); return Math.max(0, Math.floor(Number(v && v.count) || 0)); }
|
|
420
|
+
catch { return 0; }
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
// collectStatus — the public assembler
|
|
425
|
+
// ---------------------------------------------------------------------------
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Build the SHARED STATUS SNAPSHOT. Every step is independently fail-open; the
|
|
429
|
+
* function never throws and always returns a well-formed snapshot.
|
|
430
|
+
*
|
|
431
|
+
* @param {object} o
|
|
432
|
+
* @param {string} [o.agentRoot] agent repo root (for state/log reads)
|
|
433
|
+
* @param {number|Function} [o.now] clock (ms or () => ms); default Date.now
|
|
434
|
+
* @param {object} [o.deps] injectable probes (see below) — also accepted at top level
|
|
435
|
+
* @param {object[]} [o.sessions] presence records override (tests)
|
|
436
|
+
* @param {number} [o.subAgentsRunning] override the child-process count (tests)
|
|
437
|
+
* @param {Function} [o.liveClaudeStats] override the ps-based count (tests)
|
|
438
|
+
* @param {object} [o.os] node:os override (tests)
|
|
439
|
+
* @param {Function}[o.execFile] execFile override (tests; gates powermetrics/df)
|
|
440
|
+
* @param {string} [o.logText] log text override for auth detection (tests)
|
|
441
|
+
* @param {object} [o.thresholds] alert thresholds passed to deriveAlerts
|
|
442
|
+
* @param {boolean} [o.withAlerts=true] derive + attach alerts inline
|
|
443
|
+
* @returns {Promise<object>} the status snapshot
|
|
444
|
+
*/
|
|
445
|
+
export async function collectStatus(o = {}) {
|
|
446
|
+
// Allow callers to pass probes under `deps` or at top level (top level wins).
|
|
447
|
+
const deps = (o && typeof o.deps === "object" && o.deps) || {};
|
|
448
|
+
const opt = { ...deps, ...o };
|
|
449
|
+
const nowMs = nowMsFrom(opt.now);
|
|
450
|
+
|
|
451
|
+
// 1. state + activity + session
|
|
452
|
+
let act = { session: null, activity: "idle", state: "idle" };
|
|
453
|
+
try { act = resolveActivity(opt); } catch { /* defaults */ }
|
|
454
|
+
|
|
455
|
+
// 2. subAgentsRunning
|
|
456
|
+
let subAgentsRunning = 0;
|
|
457
|
+
try { subAgentsRunning = countSubAgents(opt); } catch { subAgentsRunning = 0; }
|
|
458
|
+
|
|
459
|
+
// 3. machine
|
|
460
|
+
let machine = { loadavg: [0, 0, 0], memUsedPct: 0 };
|
|
461
|
+
try { machine = await collectMachine(opt); } catch { machine = { loadavg: [0, 0, 0], memUsedPct: 0 }; }
|
|
462
|
+
|
|
463
|
+
// 4. claudeAuth
|
|
464
|
+
let claudeAuth = "unknown";
|
|
465
|
+
try { claudeAuth = detectClaudeAuth(opt); } catch { claudeAuth = "unknown"; }
|
|
466
|
+
|
|
467
|
+
// Promote state to "busy" if there are sub-agents but resolveActivity said idle
|
|
468
|
+
// (a daemon spawning work but its own presence record lags). Honour an explicit
|
|
469
|
+
// override.
|
|
470
|
+
let state = VALID_STATES.has(opt.state) ? opt.state : act.state;
|
|
471
|
+
if (claudeAuth === "relogin_required") state = "error";
|
|
472
|
+
else if (state === "idle" && subAgentsRunning > 0) state = "busy";
|
|
473
|
+
|
|
474
|
+
const status = {
|
|
475
|
+
state,
|
|
476
|
+
activity: act.activity || "idle",
|
|
477
|
+
subAgentsRunning,
|
|
478
|
+
session: act.session || null,
|
|
479
|
+
machine,
|
|
480
|
+
claudeAuth,
|
|
481
|
+
alerts: [],
|
|
482
|
+
ts: new Date(nowMs).toISOString(),
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// 5. alerts (inline, unless the caller wants to derive them itself)
|
|
486
|
+
if (opt.withAlerts !== false) {
|
|
487
|
+
try {
|
|
488
|
+
const mod = await import("./alerts.mjs");
|
|
489
|
+
status.alerts = mod.deriveAlerts(status, opt.thresholds) || [];
|
|
490
|
+
} catch { status.alerts = []; }
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return status;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export const _internals = {
|
|
497
|
+
resolveActivity,
|
|
498
|
+
deriveTaskClass,
|
|
499
|
+
humanActivity,
|
|
500
|
+
collectMachine,
|
|
501
|
+
collectPowermetrics,
|
|
502
|
+
parsePowermetrics,
|
|
503
|
+
collectDisk,
|
|
504
|
+
parseDf,
|
|
505
|
+
detectClaudeAuth,
|
|
506
|
+
scanForRelogin,
|
|
507
|
+
countSubAgents,
|
|
508
|
+
execFileSafe,
|
|
509
|
+
RELOGIN_FINGERPRINTS,
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
export default { collectStatus, _internals };
|