@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
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* resolve.test.mjs — three-layer, total, per-slug resolution (§3):
|
|
3
|
-
* LOCAL > WORKSPACE > SDK, layers never merge, and a local edit is never
|
|
4
|
-
* clobbered without --force.
|
|
5
|
-
* Run: node --test lib/subagents/resolve.test.mjs
|
|
6
|
-
*/
|
|
7
|
-
"use strict";
|
|
8
|
-
|
|
9
|
-
import { test } from "node:test";
|
|
10
|
-
import assert from "node:assert/strict";
|
|
11
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
12
|
-
import { tmpdir } from "node:os";
|
|
13
|
-
import { join } from "node:path";
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
LAYERS,
|
|
17
|
-
agentFilePath,
|
|
18
|
-
buildWorkspaceLayer,
|
|
19
|
-
classifyLocal,
|
|
20
|
-
materialise,
|
|
21
|
-
materialiseAll,
|
|
22
|
-
readLocalAgents,
|
|
23
|
-
resolveSubagents,
|
|
24
|
-
} from "./resolve.mjs";
|
|
25
|
-
import { buildManifest, writeManifest } from "./manifest.mjs";
|
|
26
|
-
import { mergeLock, readLock, writeCache } from "./lock.mjs";
|
|
27
|
-
import { hashBody, hashFile, parseAgentMd, stringifyAgentMd } from "./schema.mjs";
|
|
28
|
-
|
|
29
|
-
function md(slug, body = "# body\n\nprose\n", over = {}) {
|
|
30
|
-
return stringifyAgentMd({ name: slug, description: `${slug} does things`, model: "sonnet", tools: ["Read"], ...over }, body);
|
|
31
|
-
}
|
|
32
|
-
function put(root, slug, text) {
|
|
33
|
-
mkdirSync(join(root, "agents", slug), { recursive: true });
|
|
34
|
-
writeFileSync(join(root, "agents", slug, "agent.md"), text);
|
|
35
|
-
return text;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** An SDK checkout shipping `slugs`, with its manifest generated. */
|
|
39
|
-
function sdkWith(slugs, bodies = {}) {
|
|
40
|
-
const root = mkdtempSync(join(tmpdir(), "subagent-sdk-"));
|
|
41
|
-
for (const s of slugs) put(root, s, md(s, bodies[s] || `# ${s}\n\nsdk body\n`));
|
|
42
|
-
writeManifest(root, buildManifest({ maestroRoot: root, sdkVersion: "9.9.9" }).manifest);
|
|
43
|
-
return root;
|
|
44
|
-
}
|
|
45
|
-
const agentRepo = () => mkdtempSync(join(tmpdir(), "subagent-agent-"));
|
|
46
|
-
|
|
47
|
-
// ---------------------------------------------------------------------------
|
|
48
|
-
// classification — the rule everything else rests on
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
|
|
51
|
-
test("LAYERS is the precedence order", () => {
|
|
52
|
-
assert.deepEqual(LAYERS, ["local", "workspace", "sdk"]);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("classifyLocal: the four cases of §3 rule 1", () => {
|
|
56
|
-
const shas = new Set(["sdk-sha"]);
|
|
57
|
-
assert.deepEqual(classifyLocal({ fileHash: "h", lockEntry: { fileHash: "h" }, shas }).localEdits, false);
|
|
58
|
-
assert.deepEqual(classifyLocal({ fileHash: "changed", lockEntry: { fileHash: "h" }, shas }).localEdits, true);
|
|
59
|
-
assert.deepEqual(classifyLocal({ fileHash: "sdk-sha", lockEntry: null, shas }).localEdits, false);
|
|
60
|
-
assert.deepEqual(classifyLocal({ fileHash: "mystery", lockEntry: null, shas }).localEdits, true);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("classifyLocal: no lock and no manifest ⇒ local edit ⇒ nothing is overwritten", () => {
|
|
64
|
-
// The safe default in every degraded case.
|
|
65
|
-
const c = classifyLocal({ fileHash: "x", lockEntry: null, shas: new Set() });
|
|
66
|
-
assert.equal(c.localEdits, true);
|
|
67
|
-
assert.match(c.reason, /no lock entry and no SDK sha match/);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("readLocalAgents: reads every on-disk agent.md with its file hash", () => {
|
|
71
|
-
const root = agentRepo();
|
|
72
|
-
const text = put(root, "alpha", md("alpha"));
|
|
73
|
-
mkdirSync(join(root, "agents", "hollow"), { recursive: true });
|
|
74
|
-
const { files, empty } = readLocalAgents(root);
|
|
75
|
-
assert.equal(files.get("alpha").fileHash, hashFile(text));
|
|
76
|
-
assert.deepEqual(empty, ["hollow"]);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
// precedence
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
|
|
83
|
-
test("SDK wins when nothing else offers the slug", () => {
|
|
84
|
-
const sdk = sdkWith(["alpha"]);
|
|
85
|
-
const agent = agentRepo();
|
|
86
|
-
const r = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
87
|
-
assert.deepEqual(r.entries.map((e) => [e.slug, e.layer]), [["alpha", "sdk"]]);
|
|
88
|
-
assert.equal(r.entries[0].source, "sdk://9.9.9/alpha");
|
|
89
|
-
assert.equal(r.entries[0].onDisk, false);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test("WORKSPACE beats SDK for the same slug (total precedence, no merging)", () => {
|
|
93
|
-
const sdk = sdkWith(["alpha"]);
|
|
94
|
-
const agent = agentRepo();
|
|
95
|
-
const r = resolveSubagents({
|
|
96
|
-
agentRoot: agent, maestroRoot: sdk, orgSlug: "acme",
|
|
97
|
-
pins: [{ slug: "alpha", definitionId: "def_1", version: 7, body: "# alpha\n\nworkspace body\n", frontmatter: { name: "alpha" } }],
|
|
98
|
-
});
|
|
99
|
-
const e = r.bySlug.get("alpha");
|
|
100
|
-
assert.equal(e.layer, "workspace");
|
|
101
|
-
assert.equal(e.version, 7);
|
|
102
|
-
assert.equal(e.definitionId, "def_1");
|
|
103
|
-
assert.equal(e.source, "cohort://acme/alpha");
|
|
104
|
-
assert.match(e.body, /workspace body/);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("LOCAL beats everything and is reported as a local edit", () => {
|
|
108
|
-
const sdk = sdkWith(["alpha"]);
|
|
109
|
-
const agent = agentRepo();
|
|
110
|
-
put(agent, "alpha", md("alpha", "# alpha\n\nHAND EDITED\n"));
|
|
111
|
-
const r = resolveSubagents({
|
|
112
|
-
agentRoot: agent, maestroRoot: sdk,
|
|
113
|
-
pins: [{ slug: "alpha", version: 7, body: "# alpha\n\nworkspace body\n" }],
|
|
114
|
-
});
|
|
115
|
-
const e = r.bySlug.get("alpha");
|
|
116
|
-
assert.equal(e.layer, "local");
|
|
117
|
-
assert.equal(e.localEdits, true);
|
|
118
|
-
assert.match(e.body, /HAND EDITED/);
|
|
119
|
-
assert.deepEqual(r.localEdits, ["alpha"]);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("a file matching the SDK manifest sha is MANAGED — the higher layer still wins", () => {
|
|
123
|
-
// This is the graft that lets `create`'s copy list and UPGRADE_PATHS stay as
|
|
124
|
-
// they are: a pristine copy is updatable, a human's edit is sacred.
|
|
125
|
-
const sdk = sdkWith(["alpha"]);
|
|
126
|
-
const agent = agentRepo();
|
|
127
|
-
put(agent, "alpha", readFileSync(join(sdk, "agents", "alpha", "agent.md"), "utf8"));
|
|
128
|
-
const r = resolveSubagents({
|
|
129
|
-
agentRoot: agent, maestroRoot: sdk,
|
|
130
|
-
pins: [{ slug: "alpha", version: 3, body: "# alpha\n\nworkspace body\n" }],
|
|
131
|
-
});
|
|
132
|
-
assert.equal(r.bySlug.get("alpha").layer, "workspace");
|
|
133
|
-
assert.deepEqual(r.localEdits, []);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test("the slug set is (SDK manifest) ∪ (pins) ∪ (on-disk), sorted", () => {
|
|
137
|
-
const sdk = sdkWith(["from-sdk"]);
|
|
138
|
-
const agent = agentRepo();
|
|
139
|
-
put(agent, "on-disk", md("on-disk"));
|
|
140
|
-
const r = resolveSubagents({
|
|
141
|
-
agentRoot: agent, maestroRoot: sdk,
|
|
142
|
-
pins: [{ slug: "pinned", version: 1, body: "b\n" }],
|
|
143
|
-
});
|
|
144
|
-
assert.deepEqual(r.entries.map((e) => e.slug), ["from-sdk", "on-disk", "pinned"]);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("an orphaned managed file still resolves, flagged rather than mislabelled as SDK", () => {
|
|
148
|
-
const sdk = sdkWith([]);
|
|
149
|
-
const agent = agentRepo();
|
|
150
|
-
const text = put(agent, "gone", md("gone"));
|
|
151
|
-
mergeLock(agent, { agents: { gone: { layer: "workspace", fileHash: hashFile(text), version: 4, definitionId: "def_9" } } });
|
|
152
|
-
const r = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
153
|
-
const e = r.bySlug.get("gone");
|
|
154
|
-
assert.equal(e.layer, "local");
|
|
155
|
-
assert.equal(e.orphaned, true);
|
|
156
|
-
assert.equal(e.localEdits, false);
|
|
157
|
-
assert.equal(e.version, 4);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// ---------------------------------------------------------------------------
|
|
161
|
-
// the workspace layer, offline
|
|
162
|
-
// ---------------------------------------------------------------------------
|
|
163
|
-
|
|
164
|
-
test("buildWorkspaceLayer: a body-less pin is filled from the offline cache", () => {
|
|
165
|
-
const agent = agentRepo();
|
|
166
|
-
writeCache(agent, "alpha", 4, stringifyAgentMd({ name: "alpha", description: "d", model: "sonnet", tools: ["Read"] }, "cached body\n"));
|
|
167
|
-
const m = buildWorkspaceLayer({ agentRoot: agent, pins: [{ slug: "alpha", version: 4, contentHash: "" }] });
|
|
168
|
-
assert.equal(m.get("alpha").fromCache, true);
|
|
169
|
-
assert.equal(m.get("alpha").body, "cached body\n");
|
|
170
|
-
assert.equal(m.get("alpha").contentHash, hashBody("cached body\n"));
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("buildWorkspaceLayer: a pin with no body and no cache has NO workspace layer", () => {
|
|
174
|
-
// Degraded-but-correct: resolution falls through to SDK rather than
|
|
175
|
-
// materialising an empty body.
|
|
176
|
-
const m = buildWorkspaceLayer({ agentRoot: agentRepo(), pins: [{ slug: "alpha", version: 1 }] });
|
|
177
|
-
assert.equal(m.size, 0);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test("resolveSubagents: a cache-sourced workspace layer sets degraded", () => {
|
|
181
|
-
const sdk = sdkWith(["alpha"]);
|
|
182
|
-
const agent = agentRepo();
|
|
183
|
-
writeCache(agent, "alpha", 2, stringifyAgentMd({ name: "alpha", description: "d", model: "sonnet", tools: ["Read"] }, "cached\n"));
|
|
184
|
-
const r = resolveSubagents({ agentRoot: agent, maestroRoot: sdk, pins: [{ slug: "alpha", version: 2 }] });
|
|
185
|
-
assert.equal(r.bySlug.get("alpha").layer, "workspace");
|
|
186
|
-
assert.deepEqual(r.degraded, ["workspace-from-cache"]);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test("resolveSubagents: cold cache + no pins + no manifest resolves nothing and throws nothing", () => {
|
|
190
|
-
const r = resolveSubagents({ agentRoot: agentRepo(), maestroRoot: mkdtempSync(join(tmpdir(), "empty-sdk-")) });
|
|
191
|
-
assert.deepEqual(r.entries, []);
|
|
192
|
-
assert.deepEqual(r.localEdits, []);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// ---------------------------------------------------------------------------
|
|
196
|
-
// materialise
|
|
197
|
-
// ---------------------------------------------------------------------------
|
|
198
|
-
|
|
199
|
-
test("materialise: writes the winner with provenance stamped in the frontmatter", () => {
|
|
200
|
-
const sdk = sdkWith(["alpha"]);
|
|
201
|
-
const agent = agentRepo();
|
|
202
|
-
const r = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
203
|
-
const out = materialise({ agentRoot: agent, entry: r.bySlug.get("alpha") });
|
|
204
|
-
assert.equal(out.written, true);
|
|
205
|
-
const text = readFileSync(agentFilePath(agent, "alpha"), "utf8");
|
|
206
|
-
const fm = parseAgentMd(text).frontmatter;
|
|
207
|
-
assert.equal(fm.layer, "sdk");
|
|
208
|
-
assert.equal(fm.source, "sdk://9.9.9/alpha");
|
|
209
|
-
assert.equal(fm.contentHash, hashBody(r.bySlug.get("alpha").body));
|
|
210
|
-
assert.equal(fm.model, "claude-sonnet-4-6", "the model alias is normalised on the way to disk");
|
|
211
|
-
assert.equal(out.fileHash, hashFile(text));
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("materialise: is idempotent — a second pass writes nothing", () => {
|
|
215
|
-
// Not just an optimisation: a no-op write would churn mtime on every doctor
|
|
216
|
-
// run and make "when did this last change" useless.
|
|
217
|
-
const sdk = sdkWith(["alpha"]);
|
|
218
|
-
const agent = agentRepo();
|
|
219
|
-
const entry = resolveSubagents({ agentRoot: agent, maestroRoot: sdk }).bySlug.get("alpha");
|
|
220
|
-
assert.equal(materialise({ agentRoot: agent, entry }).written, true);
|
|
221
|
-
const second = materialise({ agentRoot: agent, entry });
|
|
222
|
-
assert.equal(second.written, false);
|
|
223
|
-
assert.equal(second.reason, "already up to date");
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test("materialise: REFUSES to overwrite a local edit without --force", () => {
|
|
227
|
-
const sdk = sdkWith(["alpha"]);
|
|
228
|
-
const agent = agentRepo();
|
|
229
|
-
const mine = put(agent, "alpha", md("alpha", "# alpha\n\nMINE\n"));
|
|
230
|
-
const r = resolveSubagents({ agentRoot: agent, maestroRoot: sdk, pins: [{ slug: "alpha", version: 2, body: "theirs\n" }] });
|
|
231
|
-
const refused = materialise({ agentRoot: agent, entry: r.bySlug.get("alpha") });
|
|
232
|
-
assert.equal(refused.written, false);
|
|
233
|
-
assert.match(refused.reason, /--force/);
|
|
234
|
-
assert.equal(readFileSync(agentFilePath(agent, "alpha"), "utf8"), mine);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
test("--force demotes the local layer so the upstream body actually wins", () => {
|
|
238
|
-
// Both halves are required: resolution must stop letting the file absorb the
|
|
239
|
-
// slug, AND materialise must permit the write. Either alone is a no-op — with
|
|
240
|
-
// force only on the write, --force would rewrite the file from itself.
|
|
241
|
-
const sdk = sdkWith(["alpha"]);
|
|
242
|
-
const agent = agentRepo();
|
|
243
|
-
put(agent, "alpha", md("alpha", "# alpha\n\nMINE\n"));
|
|
244
|
-
|
|
245
|
-
const unforced = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
246
|
-
assert.equal(unforced.bySlug.get("alpha").layer, "local");
|
|
247
|
-
|
|
248
|
-
const forced = resolveSubagents({ agentRoot: agent, maestroRoot: sdk, force: true });
|
|
249
|
-
assert.equal(forced.bySlug.get("alpha").layer, "sdk", "the local layer is demoted");
|
|
250
|
-
assert.deepEqual(forced.localEdits, ["alpha"], "…but the edit is still REPORTED");
|
|
251
|
-
|
|
252
|
-
assert.equal(materialise({ agentRoot: agent, entry: forced.bySlug.get("alpha"), force: true }).written, true);
|
|
253
|
-
assert.match(readFileSync(agentFilePath(agent, "alpha"), "utf8"), /sdk body/);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
test("--force with NO upstream layer keeps the file and still flags the edit", () => {
|
|
257
|
-
// There is nothing to override it WITH; blanking it would be data loss.
|
|
258
|
-
const agent = agentRepo();
|
|
259
|
-
put(agent, "solo", md("solo", "# solo\n\nMINE\n"));
|
|
260
|
-
const r = resolveSubagents({ agentRoot: agent, maestroRoot: sdkWith([]), force: true });
|
|
261
|
-
const e = r.bySlug.get("solo");
|
|
262
|
-
assert.equal(e.layer, "local");
|
|
263
|
-
assert.equal(e.localEdits, true);
|
|
264
|
-
assert.equal(e.orphaned, false, "an edited file is not an orphan");
|
|
265
|
-
assert.match(e.body, /MINE/);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test("materialise: refuses a body declaring tokens THIS agent cannot render", () => {
|
|
269
|
-
// hq deliberately does not vendor KNOWN_TOKENS, so the fetching agent is the
|
|
270
|
-
// only place this can be caught — refusing here makes the unresolved-token CI
|
|
271
|
-
// guard structurally unable to fail after a fetch.
|
|
272
|
-
const agent = agentRepo();
|
|
273
|
-
const out = materialise({
|
|
274
|
-
agentRoot: agent,
|
|
275
|
-
entry: {
|
|
276
|
-
slug: "alpha", layer: "workspace", source: "cohort://o/alpha", version: 1,
|
|
277
|
-
frontmatter: { name: "alpha", description: "d", model: "sonnet", tools: ["Read"], tokens: ["agent.firstName", "agent.invented"] },
|
|
278
|
-
body: "hi {{agent.firstName}} {{agent.invented}}\n",
|
|
279
|
-
contentHash: "h",
|
|
280
|
-
},
|
|
281
|
-
});
|
|
282
|
-
assert.equal(out.written, false);
|
|
283
|
-
assert.match(out.reason, /cannot render: agent\.invented/);
|
|
284
|
-
assert.equal(existsSync(agentFilePath(agent, "alpha")), false);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
test("materialise: refuses a body that fails the schema", () => {
|
|
288
|
-
const agent = agentRepo();
|
|
289
|
-
const out = materialise({
|
|
290
|
-
agentRoot: agent,
|
|
291
|
-
entry: { slug: "alpha", layer: "sdk", frontmatter: { name: "WRONG", description: "d", model: "sonnet", tools: ["Read"] }, body: "b\n" },
|
|
292
|
-
});
|
|
293
|
-
assert.equal(out.written, false);
|
|
294
|
-
assert.equal(out.reason, "failed schema validation");
|
|
295
|
-
assert.match(out.errors.join(" "), /must equal the directory name/);
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
test("materialiseAll: writes every winner and returns the lock patch", () => {
|
|
299
|
-
const sdk = sdkWith(["alpha", "beta"]);
|
|
300
|
-
const agent = agentRepo();
|
|
301
|
-
const resolved = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
302
|
-
const out = materialiseAll({ agentRoot: agent, resolved });
|
|
303
|
-
assert.equal(out.written, 2);
|
|
304
|
-
assert.deepEqual(Object.keys(out.lockAgents).sort(), ["alpha", "beta"]);
|
|
305
|
-
assert.equal(out.lockAgents.alpha.layer, "sdk");
|
|
306
|
-
assert.equal(out.lockAgents.alpha.fileHash, hashFile(readFileSync(agentFilePath(agent, "alpha"), "utf8")));
|
|
307
|
-
assert.ok(out.lockAgents.alpha.materialisedAt);
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
test("materialiseAll: `only` restricts the write set", () => {
|
|
311
|
-
const sdk = sdkWith(["alpha", "beta"]);
|
|
312
|
-
const agent = agentRepo();
|
|
313
|
-
const resolved = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
314
|
-
const out = materialiseAll({ agentRoot: agent, resolved, only: ["alpha"] });
|
|
315
|
-
assert.equal(out.written, 1);
|
|
316
|
-
assert.equal(existsSync(agentFilePath(agent, "beta")), false);
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
test("materialiseAll: a refusal is reported and still recorded in the lock patch", () => {
|
|
320
|
-
const sdk = sdkWith(["alpha"]);
|
|
321
|
-
const agent = agentRepo();
|
|
322
|
-
put(agent, "alpha", md("alpha", "# alpha\n\nMINE\n"));
|
|
323
|
-
const resolved = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
324
|
-
const out = materialiseAll({ agentRoot: agent, resolved });
|
|
325
|
-
assert.equal(out.written, 0);
|
|
326
|
-
assert.equal(out.lockAgents.alpha.localEdits, true, "so the next run does not re-offer the same overwrite");
|
|
327
|
-
assert.equal(out.lockAgents.alpha.materialisedAt, "", "we never claim to have written what we did not");
|
|
328
|
-
assert.equal(
|
|
329
|
-
out.lockAgents.alpha.fileHash,
|
|
330
|
-
"",
|
|
331
|
-
"and we never record an unmanaged file's bytes as ours — that is a licence to overwrite",
|
|
332
|
-
);
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
test("a refused local edit SURVIVES repeated runs (no --force) — data-loss regression", () => {
|
|
336
|
-
// The refusal used to protect the file for exactly ONE run: it recorded the
|
|
337
|
-
// human's own hash as `fileHash`, i.e. as bytes we had materialised, so the
|
|
338
|
-
// next resolve classified the file as managed and overwrote it silently.
|
|
339
|
-
// Reproduced end to end before the fix: run 1 refused, run 2 destroyed the
|
|
340
|
-
// edit with no --force and no warning.
|
|
341
|
-
const sdk = sdkWith(["alpha"]);
|
|
342
|
-
const agent = agentRepo();
|
|
343
|
-
const MINE = md("alpha", "# alpha\n\nMY PRECIOUS LOCAL EDIT\n");
|
|
344
|
-
put(agent, "alpha", MINE);
|
|
345
|
-
|
|
346
|
-
let lock;
|
|
347
|
-
for (let run = 1; run <= 3; run++) {
|
|
348
|
-
const resolved = resolveSubagents({ agentRoot: agent, maestroRoot: sdk, lock });
|
|
349
|
-
const out = materialiseAll({ agentRoot: agent, resolved });
|
|
350
|
-
lock = { agents: out.lockAgents };
|
|
351
|
-
assert.equal(out.written, 0, `run ${run} must not write over a local edit`);
|
|
352
|
-
assert.equal(out.lockAgents.alpha.localEdits, true, `run ${run} must keep the edit flagged`);
|
|
353
|
-
assert.equal(
|
|
354
|
-
readFileSync(agentFilePath(agent, "alpha"), "utf8"),
|
|
355
|
-
MINE,
|
|
356
|
-
`run ${run} must leave the human's bytes untouched`,
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
test("--force resolves the edit, and the file is managed from then on", () => {
|
|
362
|
-
// The other half: once we DO overwrite, the flag must clear, or the file
|
|
363
|
-
// would be treated as dirty forever and never updated again.
|
|
364
|
-
const sdk = sdkWith(["alpha"]);
|
|
365
|
-
const agent = agentRepo();
|
|
366
|
-
put(agent, "alpha", md("alpha", "# alpha\n\nMINE\n"));
|
|
367
|
-
|
|
368
|
-
const first = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
369
|
-
const forced = materialiseAll({ agentRoot: agent, resolved: first, force: true });
|
|
370
|
-
assert.equal(forced.written, 1);
|
|
371
|
-
assert.equal(forced.lockAgents.alpha.localEdits, false, "the edit is resolved");
|
|
372
|
-
assert.ok(forced.lockAgents.alpha.fileHash, "and now we DID write these bytes");
|
|
373
|
-
|
|
374
|
-
const second = resolveSubagents({
|
|
375
|
-
agentRoot: agent,
|
|
376
|
-
maestroRoot: sdk,
|
|
377
|
-
lock: { agents: forced.lockAgents },
|
|
378
|
-
});
|
|
379
|
-
const entry = second.entries.find((e) => e.slug === "alpha");
|
|
380
|
-
assert.equal(entry.localEdits, false, "a managed file stays managed");
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
// ---------------------------------------------------------------------------
|
|
384
|
-
// the full loop — this is what `pull` does
|
|
385
|
-
// ---------------------------------------------------------------------------
|
|
386
|
-
|
|
387
|
-
test("resolve → materialise → lock → resolve is STABLE (no phantom local edits)", () => {
|
|
388
|
-
const sdk = sdkWith(["alpha"]);
|
|
389
|
-
const agent = agentRepo();
|
|
390
|
-
|
|
391
|
-
const first = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
392
|
-
const out = materialiseAll({ agentRoot: agent, resolved: first });
|
|
393
|
-
mergeLock(agent, { agents: out.lockAgents });
|
|
394
|
-
|
|
395
|
-
const second = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
396
|
-
assert.equal(second.bySlug.get("alpha").layer, "sdk", "the file we just wrote must not read as a local edit");
|
|
397
|
-
assert.deepEqual(second.localEdits, []);
|
|
398
|
-
assert.equal(materialiseAll({ agentRoot: agent, resolved: second }).written, 0);
|
|
399
|
-
|
|
400
|
-
// …and a human edit after that IS detected.
|
|
401
|
-
writeFileSync(agentFilePath(agent, "alpha"), readFileSync(agentFilePath(agent, "alpha"), "utf8") + "\nhand written\n");
|
|
402
|
-
const third = resolveSubagents({ agentRoot: agent, maestroRoot: sdk, lock: readLock(agent) });
|
|
403
|
-
assert.equal(third.bySlug.get("alpha").layer, "local");
|
|
404
|
-
assert.deepEqual(third.localEdits, ["alpha"]);
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
test("an SDK upgrade re-materialises a MANAGED file but not an edited one", () => {
|
|
408
|
-
const sdk = sdkWith(["alpha"]);
|
|
409
|
-
const agent = agentRepo();
|
|
410
|
-
const first = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
411
|
-
mergeLock(agent, { agents: materialiseAll({ agentRoot: agent, resolved: first }).lockAgents });
|
|
412
|
-
|
|
413
|
-
// Ship a new SDK body + regenerate the manifest (history carries the old sha).
|
|
414
|
-
const prev = buildManifest({ maestroRoot: sdk }).manifest;
|
|
415
|
-
put(sdk, "alpha", md("alpha", "# alpha\n\nSDK v2 body\n"));
|
|
416
|
-
writeManifest(sdk, buildManifest({ maestroRoot: sdk, sdkVersion: "9.9.10", previous: prev }).manifest);
|
|
417
|
-
|
|
418
|
-
const upgraded = resolveSubagents({ agentRoot: agent, maestroRoot: sdk });
|
|
419
|
-
assert.equal(upgraded.bySlug.get("alpha").layer, "sdk");
|
|
420
|
-
assert.equal(materialiseAll({ agentRoot: agent, resolved: upgraded }).written, 1);
|
|
421
|
-
assert.match(readFileSync(agentFilePath(agent, "alpha"), "utf8"), /SDK v2 body/);
|
|
422
|
-
});
|