@zerwiz/ymir 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +291 -0
- package/.agents/agents/bragi-marketer.md +111 -0
- package/.agents/agents/brokk.md +352 -0
- package/.agents/agents/forseti-reviewer.md +93 -0
- package/.agents/agents/frigg-consent.md +77 -0
- package/.agents/agents/groa-update.md +77 -0
- package/.agents/agents/hnoss-designer.md +69 -0
- package/.agents/agents/huginn-researcher.md +99 -0
- package/.agents/agents/jord-projects.md +78 -0
- package/.agents/agents/kvasir-scout.md +91 -0
- package/.agents/agents/mimir-planner.md +92 -0
- package/.agents/agents/muninn-stow.md +77 -0
- package/.agents/agents/saga-bearings.md +78 -0
- package/.agents/agents/sindri-developer.md +114 -0
- package/.agents/agents/snotra-documenter.md +105 -0
- package/.agents/agents/syn-recovery.md +78 -0
- package/.agents/agents/tyr-check.md +78 -0
- package/.agents/agents/urdh-hold.md +77 -0
- package/.agents/agents/volundr-smith.md +80 -0
- package/.agents/agents/vor-diagnostics.md +77 -0
- package/.agents/assets/agents/naming.md +50 -0
- package/.agents/assets/agents/registry.md +93 -0
- package/.agents/assets/agents/runtime.md +36 -0
- package/.agents/assets/agents/toon-tasks-cli.md +42 -0
- package/.agents/assets/templates/company_entity.template.md +37 -0
- package/.agents/backend/backends/cmux.sh +649 -0
- package/.agents/backend/backends/herdr-eventwait.py +157 -0
- package/.agents/backend/backends/herdr-workspace-move.py +114 -0
- package/.agents/backend/backends/herdr.sh +3386 -0
- package/.agents/backend/backends/orca.sh +290 -0
- package/.agents/backend/backends/tmux.sh +357 -0
- package/.agents/backend/backends/zellij.sh +700 -0
- package/.agents/backend/fm-afk-launch.sh +654 -0
- package/.agents/backend/fm-afk-return.sh +241 -0
- package/.agents/backend/fm-afk-start.sh +172 -0
- package/.agents/backend/fm-arm-command-policy.mjs +960 -0
- package/.agents/backend/fm-arm-pretool-check.sh +200 -0
- package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
- package/.agents/backend/fm-backend.sh +981 -0
- package/.agents/backend/fm-backlog-handoff.sh +909 -0
- package/.agents/backend/fm-backlog-receive.sh +187 -0
- package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
- package/.agents/backend/fm-bearings-board.sh +204 -0
- package/.agents/backend/fm-bearings-snapshot.sh +546 -0
- package/.agents/backend/fm-bootstrap.sh +1568 -0
- package/.agents/backend/fm-branch-outcome.sh +203 -0
- package/.agents/backend/fm-branch-prompt.sh +101 -0
- package/.agents/backend/fm-brief.sh +452 -0
- package/.agents/backend/fm-busy-event.sh +234 -0
- package/.agents/backend/fm-busy-lib.sh +986 -0
- package/.agents/backend/fm-captain-hold.sh +1001 -0
- package/.agents/backend/fm-cd-command-policy.mjs +153 -0
- package/.agents/backend/fm-cd-pretool-check.sh +190 -0
- package/.agents/backend/fm-check-lib.sh +74 -0
- package/.agents/backend/fm-check-register.sh +42 -0
- package/.agents/backend/fm-check-unregister.sh +52 -0
- package/.agents/backend/fm-classify-lib.sh +1770 -0
- package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
- package/.agents/backend/fm-composer-lib.sh +1416 -0
- package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
- package/.agents/backend/fm-config-push.sh +254 -0
- package/.agents/backend/fm-control-lib.sh +251 -0
- package/.agents/backend/fm-control.sh +878 -0
- package/.agents/backend/fm-crew-state.sh +625 -0
- package/.agents/backend/fm-cursor-lib.sh +243 -0
- package/.agents/backend/fm-decision-hold.sh +232 -0
- package/.agents/backend/fm-doc-audience-check.sh +269 -0
- package/.agents/backend/fm-dod-lib.sh +67 -0
- package/.agents/backend/fm-ensure-agents-md.sh +253 -0
- package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
- package/.agents/backend/fm-extension.mjs +2577 -0
- package/.agents/backend/fm-extension.sh +16 -0
- package/.agents/backend/fm-ff-lib.sh +420 -0
- package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
- package/.agents/backend/fm-fleet-sync.sh +458 -0
- package/.agents/backend/fm-fleet-view.sh +96 -0
- package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
- package/.agents/backend/fm-guard.sh +242 -0
- package/.agents/backend/fm-harness.sh +195 -0
- package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
- package/.agents/backend/fm-herdr-lab.sh +346 -0
- package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
- package/.agents/backend/fm-home-seed.sh +984 -0
- package/.agents/backend/fm-home-summary-refresh.sh +255 -0
- package/.agents/backend/fm-hook-host-lib.sh +36 -0
- package/.agents/backend/fm-inactive-reconcile.sh +531 -0
- package/.agents/backend/fm-inbox.sh +399 -0
- package/.agents/backend/fm-install-actionlint.sh +84 -0
- package/.agents/backend/fm-install-herdr.sh +96 -0
- package/.agents/backend/fm-install-shellcheck.sh +84 -0
- package/.agents/backend/fm-install-treehouse.sh +95 -0
- package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
- package/.agents/backend/fm-lease-lib.sh +218 -0
- package/.agents/backend/fm-lease.sh +189 -0
- package/.agents/backend/fm-line-cap-lib.sh +51 -0
- package/.agents/backend/fm-lint-workflows.sh +137 -0
- package/.agents/backend/fm-lint.sh +591 -0
- package/.agents/backend/fm-lock-lib.sh +104 -0
- package/.agents/backend/fm-lock.sh +107 -0
- package/.agents/backend/fm-marker-lib.sh +12 -0
- package/.agents/backend/fm-merge-local.sh +74 -0
- package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
- package/.agents/backend/fm-nm-run-lib.sh +124 -0
- package/.agents/backend/fm-on.sh +125 -0
- package/.agents/backend/fm-operational-input.sh +253 -0
- package/.agents/backend/fm-peek.sh +46 -0
- package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
- package/.agents/backend/fm-pr-check.sh +135 -0
- package/.agents/backend/fm-pr-lib.sh +1016 -0
- package/.agents/backend/fm-pr-merge.sh +707 -0
- package/.agents/backend/fm-pr-poll.sh +110 -0
- package/.agents/backend/fm-primary-scope-lib.sh +33 -0
- package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
- package/.agents/backend/fm-procevent-lavish.sh +628 -0
- package/.agents/backend/fm-procevent-lib.sh +892 -0
- package/.agents/backend/fm-procevent-quota.sh +290 -0
- package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
- package/.agents/backend/fm-procevent-when.sh +504 -0
- package/.agents/backend/fm-procevent.sh +1466 -0
- package/.agents/backend/fm-project-mode.sh +92 -0
- package/.agents/backend/fm-project-origin-lib.sh +180 -0
- package/.agents/backend/fm-promote.sh +282 -0
- package/.agents/backend/fm-public-followup-emit.sh +260 -0
- package/.agents/backend/fm-public-followup-lib.sh +398 -0
- package/.agents/backend/fm-public-followup.sh +1330 -0
- package/.agents/backend/fm-push-transition-lib.sh +168 -0
- package/.agents/backend/fm-quota-axi-lib.sh +93 -0
- package/.agents/backend/fm-quota-choose.sh +384 -0
- package/.agents/backend/fm-remote-delta-read.sh +189 -0
- package/.agents/backend/fm-remote-doctor.sh +800 -0
- package/.agents/backend/fm-remote-entrypoint.sh +193 -0
- package/.agents/backend/fm-remote-file.sh +234 -0
- package/.agents/backend/fm-remote-home-provision.sh +259 -0
- package/.agents/backend/fm-remote-home-seed.sh +259 -0
- package/.agents/backend/fm-remote-inherit-push.sh +90 -0
- package/.agents/backend/fm-remote-inherit.sh +179 -0
- package/.agents/backend/fm-remote-job-lib.sh +1241 -0
- package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
- package/.agents/backend/fm-remote-job-worker.sh +1124 -0
- package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
- package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
- package/.agents/backend/fm-review-diff.sh +158 -0
- package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
- package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
- package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
- package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
- package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
- package/.agents/backend/fm-secondmate-report.sh +88 -0
- package/.agents/backend/fm-send.sh +1059 -0
- package/.agents/backend/fm-session-lock-lib.sh +176 -0
- package/.agents/backend/fm-session-start.sh +970 -0
- package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
- package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
- package/.agents/backend/fm-sessionstart-run.sh +145 -0
- package/.agents/backend/fm-spawn.sh +3153 -0
- package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
- package/.agents/backend/fm-startup-memory-budget.sh +94 -0
- package/.agents/backend/fm-startup-network.sh +642 -0
- package/.agents/backend/fm-stow-cascade.sh +251 -0
- package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
- package/.agents/backend/fm-supervise-daemon.sh +1732 -0
- package/.agents/backend/fm-supervision-instructions.sh +215 -0
- package/.agents/backend/fm-supervision-lib.sh +90 -0
- package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
- package/.agents/backend/fm-tangle-lib.sh +53 -0
- package/.agents/backend/fm-task-inbox-lib.sh +402 -0
- package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
- package/.agents/backend/fm-teardown.sh +2922 -0
- package/.agents/backend/fm-test-isolation-proof.sh +588 -0
- package/.agents/backend/fm-test-run.sh +2191 -0
- package/.agents/backend/fm-timeout-lib.sh +141 -0
- package/.agents/backend/fm-timing-lib.sh +179 -0
- package/.agents/backend/fm-tmux-lib.sh +291 -0
- package/.agents/backend/fm-tool-update-check.sh +898 -0
- package/.agents/backend/fm-trace-context-lib.sh +227 -0
- package/.agents/backend/fm-transition-lib.sh +103 -0
- package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
- package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
- package/.agents/backend/fm-turnend-guard.sh +432 -0
- package/.agents/backend/fm-update.sh +110 -0
- package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
- package/.agents/backend/fm-voice-client.py +1373 -0
- package/.agents/backend/fm-voice-relay.py +1256 -0
- package/.agents/backend/fm-wake-drain.sh +592 -0
- package/.agents/backend/fm-wake-grant.sh +127 -0
- package/.agents/backend/fm-wake-lib.sh +1849 -0
- package/.agents/backend/fm-watch-arm.sh +602 -0
- package/.agents/backend/fm-watch-checkpoint.sh +109 -0
- package/.agents/backend/fm-watch.sh +1962 -0
- package/.agents/backend/fm-x-dismiss.sh +116 -0
- package/.agents/backend/fm-x-followup.sh +286 -0
- package/.agents/backend/fm-x-lib.sh +1000 -0
- package/.agents/backend/fm-x-link.sh +234 -0
- package/.agents/backend/fm-x-poll.sh +185 -0
- package/.agents/backend/fm-x-reply.sh +385 -0
- package/.agents/backend/fm_voice_frame.py +166 -0
- package/.agents/backend/fm_voice_records.py +574 -0
- package/.agents/backend/model-bridge.py +290 -0
- package/.agents/backend/opencode-go-bridge.py +30 -0
- package/.agents/bus/README.md +12 -0
- package/.agents/bus/messages.json +1 -0
- package/.agents/config/agents.machine.example.yaml +16 -0
- package/.agents/config/agents.yaml +50 -0
- package/.agents/config/agents.yaml.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +9 -0
- package/.agents/config/eindri-dispatch.json +67 -0
- package/.agents/config/eindri-harness +1 -0
- package/.agents/config/startup-memory-budget +1 -0
- package/.agents/config/tailscale-sync.yaml +27 -0
- package/.agents/filebrowser/.filebrowser.json +6 -0
- package/.agents/filebrowser/README.md +11 -0
- package/.agents/gateway/README.md +12 -0
- package/.agents/github/README.md +15 -0
- package/.agents/github/webhooks/.gitkeep +0 -0
- package/.agents/github/workflows/.gitkeep +0 -0
- package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
- package/.agents/harness/opencode/plugins/package.json +4 -0
- package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
- package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
- package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
- package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
- package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
- package/.agents/memory/README.md +46 -0
- package/.agents/memory/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/runes_audit.md +5 -0
- package/.agents/memory/well/episodes.jsonl +367 -0
- package/.agents/memory/well/workspace.jsonl +27 -0
- package/.agents/migrations/0001-hodd-layout.sh +38 -0
- package/.agents/migrations/0002-a2a-mcp.sh +27 -0
- package/.agents/migrations/0003-private-data-separation.sh +111 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
- package/.agents/sandbox/Dockerfile.utgard +19 -0
- package/.agents/sandbox/README.md +14 -0
- package/.agents/sandbox/utgard.config.json +14 -0
- package/.agents/skills/README.md +59 -0
- package/.agents/skills/bragi-marketing/README.md +3 -0
- package/.agents/skills/bragi-marketing/SKILL.md +82 -0
- package/.agents/skills/eindri-homes/README.md +3 -0
- package/.agents/skills/eindri-homes/SKILL.md +291 -0
- package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
- package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
- package/.agents/skills/frigg-consent/README.md +3 -0
- package/.agents/skills/frigg-consent/SKILL.md +56 -0
- package/.agents/skills/galdr-ymirsystem/README.md +3 -0
- package/.agents/skills/galdr-ymirsystem/SKILL.md +158 -0
- package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
- package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +673 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +496 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +161 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +96 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
- package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
- package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
- package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +175 -0
- package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
- package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
- package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +360 -0
- package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
- package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
- package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
- package/.agents/skills/gjallarhorn-relay/README.md +3 -0
- package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
- package/.agents/skills/groa-update/SKILL.md +70 -0
- package/.agents/skills/hamr-adapters/README.md +3 -0
- package/.agents/skills/hamr-adapters/SKILL.md +123 -0
- package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
- package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
- package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
- package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
- package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
- package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
- package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
- package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
- package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
- package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
- package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
- package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
- package/.agents/skills/herdr-panes/README.md +3 -0
- package/.agents/skills/herdr-panes/SKILL.md +92 -0
- package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
- package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
- package/.agents/skills/hnoss-design/DESIGN.md +19 -0
- package/.agents/skills/hnoss-design/README.md +3 -0
- package/.agents/skills/hnoss-design/SKILL.md +83 -0
- package/.agents/skills/hvild-afk/README.md +3 -0
- package/.agents/skills/hvild-afk/SKILL.md +241 -0
- package/.agents/skills/jord-projects/README.md +3 -0
- package/.agents/skills/jord-projects/SKILL.md +92 -0
- package/.agents/skills/lifecycle/SKILL.md +56 -0
- package/.agents/skills/lifecycle/smoke_test.sh +52 -0
- package/.agents/skills/lifecycle/start.sh +21 -0
- package/.agents/skills/lifecycle/status.sh +35 -0
- package/.agents/skills/lifecycle/stop.sh +16 -0
- package/.agents/skills/muninn-stow/README.md +3 -0
- package/.agents/skills/muninn-stow/SKILL.md +309 -0
- package/.agents/skills/no-mistakes/SKILL.md +379 -0
- package/.agents/skills/nornir-schedule/README.md +3 -0
- package/.agents/skills/nornir-schedule/SKILL.md +25 -0
- package/.agents/skills/nornir-schedule/assets/events.md +137 -0
- package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
- package/.agents/skills/nsr-compliance/README.md +3 -0
- package/.agents/skills/nsr-compliance/SKILL.md +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/pr-ops/README.md +3 -0
- package/.agents/skills/pr-ops/SKILL.md +109 -0
- package/.agents/skills/ratatoskr-a2a/README.md +3 -0
- package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
- package/.agents/skills/rules-check-drift/SKILL.md +81 -0
- package/.agents/skills/saga-bearings/README.md +3 -0
- package/.agents/skills/saga-bearings/SKILL.md +26 -0
- package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
- package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
- package/.agents/skills/saga-bearings/assets/recap.md +56 -0
- package/.agents/skills/syn-recovery/README.md +3 -0
- package/.agents/skills/syn-recovery/SKILL.md +54 -0
- package/.agents/skills/tyr-check/README.md +3 -0
- package/.agents/skills/tyr-check/SKILL.md +218 -0
- package/.agents/skills/urdh-hold/README.md +3 -0
- package/.agents/skills/urdh-hold/SKILL.md +25 -0
- package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
- package/.agents/skills/urdh-hold/assets/hold.md +54 -0
- package/.agents/skills/vor-diagnostics/README.md +3 -0
- package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
- package/.agents/skills/ymir-host/README.md +3 -0
- package/.agents/skills/ymir-host/SKILL.md +34 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -0
- package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
- package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
- package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
- package/.agents/skills/ymir-host/assets/update.md +64 -0
- package/.agents/tests/assets/board-render-harness.mjs +117 -0
- package/.agents/tests/cmux-test-safety.sh +51 -0
- package/.agents/tests/fixtures.sh +291 -0
- package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
- package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
- package/.agents/tests/fm-afk-launch.test.sh +961 -0
- package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
- package/.agents/tests/fm-afk-return.test.sh +283 -0
- package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
- package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
- package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
- package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
- package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
- package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
- package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
- package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
- package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
- package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
- package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
- package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
- package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
- package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
- package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
- package/.agents/tests/fm-backend-orca.test.sh +1357 -0
- package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
- package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
- package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
- package/.agents/tests/fm-backend.test.sh +1142 -0
- package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
- package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
- package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
- package/.agents/tests/fm-bearings-board.test.sh +414 -0
- package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
- package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
- package/.agents/tests/fm-bootstrap.test.sh +1178 -0
- package/.agents/tests/fm-branch-supervision.test.sh +552 -0
- package/.agents/tests/fm-brief.test.sh +785 -0
- package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
- package/.agents/tests/fm-busy-state.test.sh +465 -0
- package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
- package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
- package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
- package/.agents/tests/fm-check-unregister.test.sh +198 -0
- package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
- package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
- package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
- package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
- package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
- package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
- package/.agents/tests/fm-composer-ghost.test.sh +716 -0
- package/.agents/tests/fm-composer-lib.test.sh +666 -0
- package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
- package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
- package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
- package/.agents/tests/fm-control.test.sh +910 -0
- package/.agents/tests/fm-crew-state.test.sh +1610 -0
- package/.agents/tests/fm-cursor-harness.test.sh +404 -0
- package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
- package/.agents/tests/fm-cursor-primary.test.sh +708 -0
- package/.agents/tests/fm-daemon.test.sh +2740 -0
- package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
- package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
- package/.agents/tests/fm-extension-binding.test.sh +2187 -0
- package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
- package/.agents/tests/fm-fleet-sync.test.sh +721 -0
- package/.agents/tests/fm-gate-refuse.test.sh +356 -0
- package/.agents/tests/fm-gitignore-config.test.sh +89 -0
- package/.agents/tests/fm-gotmp.test.sh +230 -0
- package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
- package/.agents/tests/fm-grok-harness.test.sh +117 -0
- package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
- package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
- package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
- package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
- package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
- package/.agents/tests/fm-herdr-lab.test.sh +243 -0
- package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
- package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
- package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
- package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
- package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
- package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
- package/.agents/tests/fm-kimi-harness.test.sh +687 -0
- package/.agents/tests/fm-lint-workflows.test.sh +532 -0
- package/.agents/tests/fm-lint.test.sh +1023 -0
- package/.agents/tests/fm-muse-harness.test.sh +932 -0
- package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
- package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
- package/.agents/tests/fm-on.test.sh +507 -0
- package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
- package/.agents/tests/fm-operational-input.test.sh +160 -0
- package/.agents/tests/fm-peek-remote.test.sh +110 -0
- package/.agents/tests/fm-pending-reply.test.sh +1288 -0
- package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
- package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
- package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
- package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
- package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
- package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
- package/.agents/tests/fm-pr-merge.test.sh +2135 -0
- package/.agents/tests/fm-procevent-quota.test.sh +225 -0
- package/.agents/tests/fm-procevent-when.test.sh +406 -0
- package/.agents/tests/fm-procevent.test.sh +1745 -0
- package/.agents/tests/fm-project-origin.test.sh +110 -0
- package/.agents/tests/fm-public-followup.test.sh +2272 -0
- package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
- package/.agents/tests/fm-quota-choose.test.sh +626 -0
- package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
- package/.agents/tests/fm-remote-doctor.test.sh +625 -0
- package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
- package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
- package/.agents/tests/fm-remote-job.test.sh +768 -0
- package/.agents/tests/fm-remote-reply.test.sh +520 -0
- package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
- package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
- package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
- package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
- package/.agents/tests/fm-review-diff.test.sh +176 -0
- package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
- package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
- package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
- package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
- package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
- package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
- package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
- package/.agents/tests/fm-send-inbox.test.sh +352 -0
- package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
- package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
- package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
- package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
- package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
- package/.agents/tests/fm-send-settle.test.sh +147 -0
- package/.agents/tests/fm-send-strict.test.sh +241 -0
- package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
- package/.agents/tests/fm-session-start.test.sh +2515 -0
- package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
- package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
- package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
- package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
- package/.agents/tests/fm-spawn-batch.test.sh +148 -0
- package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
- package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
- package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
- package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
- package/.agents/tests/fm-startup-network.test.sh +712 -0
- package/.agents/tests/fm-stow-cascade.test.sh +370 -0
- package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
- package/.agents/tests/fm-supervision-events.test.sh +156 -0
- package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
- package/.agents/tests/fm-tangle-guard.test.sh +277 -0
- package/.agents/tests/fm-task-delivery.test.sh +420 -0
- package/.agents/tests/fm-task-inbox.test.sh +513 -0
- package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
- package/.agents/tests/fm-teardown.test.sh +2665 -0
- package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
- package/.agents/tests/fm-test-fixtures.test.sh +132 -0
- package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
- package/.agents/tests/fm-test-run.test.sh +1196 -0
- package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
- package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
- package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
- package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
- package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
- package/.agents/tests/fm-transition-lib.test.sh +54 -0
- package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
- package/.agents/tests/fm-update.test.sh +304 -0
- package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
- package/.agents/tests/fm-voice-relay.test.sh +4741 -0
- package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
- package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
- package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
- package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
- package/.agents/tests/fm-wake-queue.test.sh +1224 -0
- package/.agents/tests/fm-watch-arm.test.sh +821 -0
- package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
- package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
- package/.agents/tests/fm-watch-triage.test.sh +3889 -0
- package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
- package/.agents/tests/fm-x-mode.test.sh +3042 -0
- package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
- package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
- package/.agents/tests/herdr-test-safety.sh +42 -0
- package/.agents/tests/lib.sh +315 -0
- package/.agents/tests/remote-herdr-fixture.sh +125 -0
- package/.agents/tests/secondmate-helpers.sh +193 -0
- package/.agents/tests/smoke.test.sh +93 -0
- package/.agents/tests/wake-helpers.sh +338 -0
- package/.agents/tests/zellij-test-safety.sh +60 -0
- package/.agents/tools/README.md +10 -0
- package/.agents/tools/bin/tasks-cli +267 -0
- package/.agents/tools/tasks-cli.ts +216 -0
- package/AGENTS.md +454 -0
- package/CHANGELOG.md +881 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +113 -59
- package/RULES/01-domains.md +51 -0
- package/RULES/02-agents.md +78 -0
- package/RULES/03-houses.md +61 -0
- package/RULES/04-hoard.md +65 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +58 -0
- package/RULES/07-config.md +45 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/README.md +20 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +98 -0
- package/bin/a2a-serve.py +103 -0
- package/bin/a2a-serve.sh +8 -0
- package/bin/a2a-talk.sh +50 -0
- package/bin/a2abridge-ensure.sh +108 -0
- package/bin/agent-run.sh +43 -0
- package/bin/agents-config.sh +233 -0
- package/bin/apodex-smoke-test.sh +92 -0
- package/bin/bifrost-bridge.sh +112 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +107 -0
- package/bin/bootstrap-windows.ps1 +112 -0
- package/bin/branch-guard.sh +64 -0
- package/bin/brokk +73 -0
- package/bin/brokk-classify-lib.sh +1770 -0
- package/bin/brokk-lease-lib.sh +222 -0
- package/bin/brokk-lease.sh +193 -0
- package/bin/brokk-lint.sh +65 -0
- package/bin/brokk-send.sh +38 -0
- package/bin/brokk-update.sh +9 -0
- package/bin/brokk-wake-grant.sh +127 -0
- package/bin/brokk-wake-lib.sh +1849 -0
- package/bin/changelog-guard.sh +165 -0
- package/bin/crash-sense.sh +160 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +207 -0
- package/bin/eindri-acclaim.sh +34 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seen.sh +41 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +85 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +112 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/fleet-apply.sh +68 -0
- package/bin/github-deploy.sh +81 -0
- package/bin/gjallarhorn-expose.sh +102 -0
- package/bin/gjallarhorn-notify.sh +58 -0
- package/bin/gjallarhorn-purge.sh +54 -0
- package/bin/gjallarhorn-tunnel.sh +72 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +122 -0
- package/bin/hall-snapshot.sh +92 -0
- package/bin/hamr-harness.sh +246 -0
- package/bin/heimdall-ssh-keys.sh +374 -0
- package/bin/herdr-agents.py +44 -0
- package/bin/herdr-ensure.sh +104 -0
- package/bin/herdr-run.sh +431 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hoard-lib.sh +25 -0
- package/bin/hodd.sh +78 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +108 -0
- package/bin/local-model-lock.sh +51 -0
- package/bin/mimir-bridge.py +226 -0
- package/bin/mimir-bridge.sh +87 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +59 -0
- package/bin/mjollnir.sh +85 -0
- package/bin/model-hardware.sh +82 -0
- package/bin/model-resolve.sh +147 -0
- package/bin/models-detect.sh +178 -0
- package/bin/nornir-cron-start.sh +162 -0
- package/bin/nornir-job-daily-briefing.sh +191 -0
- package/bin/nornir-job-git-sync.sh +152 -0
- package/bin/nornir-job-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +148 -0
- package/bin/omarchy-plugins.sh +174 -0
- package/bin/omarchy-sense.sh +149 -0
- package/bin/perm-guard.sh +30 -0
- package/bin/pi-agent.sh +68 -0
- package/bin/pi-ensure.sh +77 -0
- package/bin/pi-local.sh +37 -0
- package/bin/pi-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +38 -0
- package/bin/project-git.sh +55 -0
- package/bin/public-guard.sh +70 -0
- package/bin/ratatoskr.sh +49 -0
- package/bin/realm-lib.sh +32 -0
- package/bin/repo-scrub.sh +62 -0
- package/bin/rodd-operational-input.sh +250 -0
- package/bin/runes-append.sh +198 -0
- package/bin/saga-session-start.sh +172 -0
- package/bin/saga-sessionstart-run.sh +79 -0
- package/bin/saga-wake-drain.sh +41 -0
- package/bin/secret-guard.sh +63 -0
- package/bin/sessrumnir-ensure.sh +100 -0
- package/bin/sessrumnir-sync.sh +237 -0
- package/bin/sessrumnir.sh +91 -0
- package/bin/skillopt-setup.sh +76 -0
- package/bin/skuld-branch-outcome.sh +203 -0
- package/bin/skuld-branch-prompt.sh +101 -0
- package/bin/smidja-bootstrap.sh +90 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +76 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +190 -0
- package/bin/telegram-bot.sh +69 -0
- package/bin/toolchain.sh +74 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +260 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +47 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +150 -0
- package/bin/wyrd-db.sh +47 -0
- package/bin/yggdrasil.sh +152 -0
- package/bin/ymir-edit.sh +145 -0
- package/bin/ymir-install.sh +641 -0
- package/bin/ymir-invite.sh +93 -0
- package/bin/ymir-isolation.sh +88 -0
- package/bin/ymir-migrate.sh +61 -0
- package/bin/ymir-platform.sh +348 -0
- package/bin/ymir-say.sh +97 -0
- package/bin/ymir-setup-auth.sh +108 -0
- package/bin/ymir-validate.sh +173 -0
- package/bin/ymir.js +74 -16
- package/docs/Architecture.md +339 -0
- package/docs/design.md +351 -0
- package/docs/installations/README.md +63 -0
- package/docs/installations/ymir-home.md +93 -0
- package/docs/integration.md +105 -0
- package/docs/lore.md +1056 -0
- package/docs/research/agent-harnesses.md +290 -0
- package/docs/runbooks/README.md +19 -0
- package/docs/runbooks/a2a.md +91 -0
- package/docs/runbooks/agent-permissions.md +99 -0
- package/docs/runbooks/agents.md +57 -0
- package/docs/runbooks/models.md +69 -0
- package/docs/runbooks/realm-onboarding.md +60 -0
- package/docs/runbooks/secrets-and-hoard.md +60 -0
- package/docs/runbooks/updates-and-migrations.md +110 -0
- package/docs/runbooks/worktrees-isolation.md +72 -0
- package/docs/session-start.md +105 -0
- package/docs/skillopt-integration.md +321 -0
- package/docs/sync-system.md +66 -0
- package/docs/workspaces.md +104 -0
- package/docs/ymir-rut.md +260 -0
- package/package.json +44 -14
- package/packaging/build.sh +74 -0
- package/packaging/macos/Ymir Installer.command +43 -0
- package/packaging/windows/ymir-setup.nsi +74 -0
- package/scripts/README.md +22 -0
- package/scripts/electron.sh +210 -0
- package/scripts/start.sh +167 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tests/fm-composer-lib.test.sh - the shared composer-content classifier
|
|
3
|
+
# (bin/fm-composer-lib.sh), the ONE fleet-wide owner every backend adapter
|
|
4
|
+
# delegates its empty|pending|unknown verdict to.
|
|
5
|
+
#
|
|
6
|
+
# The load-bearing contract, task fm-composer-shellglyph-safety:
|
|
7
|
+
# 1. A BARE shell prompt glyph (`>`/`$`/`%`/`#`) on an unstructured row is a
|
|
8
|
+
# dead shell, NOT an empty agent composer - it must read `unknown`
|
|
9
|
+
# (unsafe-for-injection), never `empty`. This is the safety fix.
|
|
10
|
+
# 2. The SAME shell glyph INSIDE a bordered composer box is the harness's own
|
|
11
|
+
# prompt and still reads `empty` (existing behavior preserved).
|
|
12
|
+
# 3. The AGENT prompt glyphs `❯` (claude), `›` (codex), `⟩` (muse), and `→`
|
|
13
|
+
# (cursor) are a genuine empty agent composer either way, bordered or bare.
|
|
14
|
+
# 4. Real unsubmitted text reads `pending`; a known idle placeholder reads
|
|
15
|
+
# `empty`.
|
|
16
|
+
set -u
|
|
17
|
+
|
|
18
|
+
# shellcheck source=tests/lib.sh
|
|
19
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
20
|
+
|
|
21
|
+
# shellcheck source=/dev/null
|
|
22
|
+
. "$ROOT/bin/fm-composer-lib.sh"
|
|
23
|
+
|
|
24
|
+
# classify <bordered> <content> [idle_re] -> echoes the verdict.
|
|
25
|
+
classify() { fm_composer_classify_content "$@"; }
|
|
26
|
+
|
|
27
|
+
# --- Safety fix: bare shell prompt is NOT an empty agent composer -----------
|
|
28
|
+
|
|
29
|
+
test_bare_shell_glyphs_are_unknown() {
|
|
30
|
+
local g out
|
|
31
|
+
for g in '>' '$' '%' '#'; do
|
|
32
|
+
out=$(classify 0 "$g")
|
|
33
|
+
[ "$out" = unknown ] \
|
|
34
|
+
|| fail "bare shell glyph '$g' must read unknown (dead shell, unsafe), got '$out'"
|
|
35
|
+
done
|
|
36
|
+
pass "fm_composer_classify_content: a bare shell prompt glyph (>/\$/%/#) reads unknown, never empty"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
test_stripped_unbordered_content_uses_plain_content() {
|
|
40
|
+
local plain out
|
|
41
|
+
for plain in '$' 'user@host $'; do
|
|
42
|
+
out=$(classify 0 '' '' sensitive "$plain")
|
|
43
|
+
[ "$out" = unknown ] \
|
|
44
|
+
|| fail "stripped unbordered content '$plain' must retain its unknown safety verdict, got '$out'"
|
|
45
|
+
done
|
|
46
|
+
# muse draws `⟩` at luminance ~150, the tightest margin over the 128 ghost
|
|
47
|
+
# threshold in the fleet, so a raised threshold really can strip it to empty
|
|
48
|
+
# and leave only the plain row. This branch is what keeps that pane readable.
|
|
49
|
+
for plain in '❯' '›' '⟩'; do
|
|
50
|
+
out=$(classify 0 '' '' sensitive "$plain")
|
|
51
|
+
[ "$out" = empty ] \
|
|
52
|
+
|| fail "a stripped agent glyph '$plain' must remain empty, got '$out'"
|
|
53
|
+
done
|
|
54
|
+
pass "fm_composer_classify_content: stripped unbordered content is unknown except verified agent glyphs"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
test_bare_shell_prompt_with_command_is_not_empty() {
|
|
58
|
+
local out
|
|
59
|
+
# A dead shell showing a typed command must not read empty either.
|
|
60
|
+
out=$(classify 0 '$ ls -la')
|
|
61
|
+
[ "$out" != empty ] || fail "a bare shell prompt with a command must not read empty, got '$out'"
|
|
62
|
+
pass "fm_composer_classify_content: a bare shell prompt carrying a command is not empty"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# --- Preserved: shell glyph inside a composer box is the harness prompt ------
|
|
66
|
+
|
|
67
|
+
test_bordered_shell_glyph_is_empty() {
|
|
68
|
+
local g out
|
|
69
|
+
for g in '>' '$' '%' '#'; do
|
|
70
|
+
out=$(classify 1 "$g")
|
|
71
|
+
[ "$out" = empty ] \
|
|
72
|
+
|| fail "a shell glyph '$g' inside a bordered composer box must read empty, got '$out'"
|
|
73
|
+
done
|
|
74
|
+
pass "fm_composer_classify_content: a bare prompt glyph inside a bordered composer box reads empty (claude's own idle composer)"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# --- Agent glyphs are empty either way --------------------------------------
|
|
78
|
+
|
|
79
|
+
test_agent_glyphs_are_empty_bordered_and_bare() {
|
|
80
|
+
local out
|
|
81
|
+
out=$(classify 0 '❯'); [ "$out" = empty ] || fail "bare claude '❯' should read empty, got '$out'"
|
|
82
|
+
out=$(classify 0 '›'); [ "$out" = empty ] || fail "bare codex '›' should read empty, got '$out'"
|
|
83
|
+
out=$(classify 1 '❯'); [ "$out" = empty ] || fail "bordered claude '❯' should read empty, got '$out'"
|
|
84
|
+
out=$(classify 1 '›'); [ "$out" = empty ] || fail "bordered codex '›' should read empty, got '$out'"
|
|
85
|
+
out=$(classify 0 '⟩'); [ "$out" = empty ] || fail "bare muse '⟩' should read empty, got '$out'"
|
|
86
|
+
out=$(classify 1 '⟩'); [ "$out" = empty ] || fail "bordered muse '⟩' should read empty, got '$out'"
|
|
87
|
+
pass "fm_composer_classify_content: agent prompt glyphs (❯ claude, › codex, ⟩ muse) read empty bordered or bare"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# --- Empty content and idle placeholder -------------------------------------
|
|
91
|
+
|
|
92
|
+
test_empty_content_is_empty() {
|
|
93
|
+
local out
|
|
94
|
+
out=$(classify 0 ''); [ "$out" = empty ] || fail "empty bare content should read empty, got '$out'"
|
|
95
|
+
out=$(classify 1 ''); [ "$out" = empty ] || fail "empty bordered content should read empty, got '$out'"
|
|
96
|
+
pass "fm_composer_classify_content: an empty composer reads empty"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
test_idle_placeholder_is_empty() {
|
|
100
|
+
local idle='^Type a message\.\.\.$' out
|
|
101
|
+
out=$(classify 1 'Type a message...' "$idle" sensitive 'Type a message...' 1 1)
|
|
102
|
+
[ "$out" = pending ] || fail "placeholder-like text surviving a styled box capture should read pending, got '$out'"
|
|
103
|
+
out=$(classify 1 '❯ Type a message...' "$idle" sensitive '❯ Type a message...' 1 0)
|
|
104
|
+
[ "$out" = empty ] || fail "a glyph-bearing plain box placeholder should read empty, got '$out'"
|
|
105
|
+
out=$(classify 0 '❯ Type a message...' "$idle" sensitive '❯ Type a message...' 0 1)
|
|
106
|
+
[ "$out" = pending ] || fail "placeholder text on a styled bare input row must be pending, got '$out'"
|
|
107
|
+
out=$(classify 0 '❯ Type a message...' "$idle" sensitive '❯ Type a message...' 0 0)
|
|
108
|
+
[ "$out" = unknown ] || fail "placeholder text on a plain bare input row must be unknown, got '$out'"
|
|
109
|
+
out=$(classify 1 'Type a message...')
|
|
110
|
+
[ "$out" = pending ] || fail "without an idle regex the placeholder text is pending, got '$out'"
|
|
111
|
+
pass "fm_composer_classify_content: idle matching is limited to proven placeholder positions"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
test_idle_placeholder_case_mode_is_explicit() {
|
|
115
|
+
local idle='^Type a message\.\.\.$' out
|
|
116
|
+
out=$(classify 1 'type a message...' "$idle" sensitive 'type a message...' 1 0)
|
|
117
|
+
[ "$out" = pending ] || fail "a case-variant idle placeholder should remain pending by default, got '$out'"
|
|
118
|
+
out=$(classify 1 'type a message...' "$idle" insensitive 'type a message...' 1 0)
|
|
119
|
+
[ "$out" = empty ] || fail "an explicitly insensitive plain placeholder should read empty, got '$out'"
|
|
120
|
+
pass "fm_composer_classify_content: idle matching preserves the caller's case mode"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# --- Real text is pending ---------------------------------------------------
|
|
124
|
+
|
|
125
|
+
test_real_text_is_pending() {
|
|
126
|
+
local out
|
|
127
|
+
out=$(classify 0 '❯ fix findings 1 and 3'); [ "$out" = pending ] || fail "bare '❯ <text>' should be pending, got '$out'"
|
|
128
|
+
out=$(classify 1 '> deploy staging now'); [ "$out" = pending ] || fail "bordered '> <text>' should be pending, got '$out'"
|
|
129
|
+
# muse restores the interrupted prompt into its composer after Escape, as real
|
|
130
|
+
# bright text. Reading that as pending is correct - it really is unsubmitted.
|
|
131
|
+
out=$(classify 0 '⟩ second turn to interrupt'); [ "$out" = pending ] || fail "bare '⟩ <text>' should be pending, got '$out'"
|
|
132
|
+
# A slash-command popup argument-hint placeholder is still unsubmitted text.
|
|
133
|
+
out=$(classify 1 '/compact compaction instructions'); [ "$out" = pending ] || fail "a popup placeholder fill should be pending, got '$out'"
|
|
134
|
+
pass "fm_composer_classify_content: real unsubmitted text reads pending (including a popup argument-hint fill)"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
# =============================================================================
|
|
138
|
+
# fm_composer_classify_screen: the adapter-facing screen classifier and the
|
|
139
|
+
# correctness matrix (audit data/fm-composer-consolidation-audit-s1, task
|
|
140
|
+
# fm-composer-thin-adapter-refactor-r1).
|
|
141
|
+
#
|
|
142
|
+
# Fixtures are the audit's byte-level captures of six REAL idle harnesses:
|
|
143
|
+
# claude 2.1.226 (bare `❯` + U+00A0 NO-BREAK SPACE), codex 0.146.0 (bold `›`
|
|
144
|
+
# + SGR-2 dim hint), muse (truecolor `⟩`, 38;2;90;160;255), pi (blank row
|
|
145
|
+
# between solid `─` rules), opencode 1.14.46 (left-bar `┃` rows), and grok
|
|
146
|
+
# 1.0.0 (bordered box with a TITLED bottom border), plus claude captured
|
|
147
|
+
# inside zellij through `dump-screen --ansi` (`ESC[m` `❯` U+00A0).
|
|
148
|
+
#
|
|
149
|
+
# Capability profiles mirror the real adapters' descriptors: tmux
|
|
150
|
+
# (styled+cursor+identity), herdr/zellij (styled), cmux/orca (plain). Every
|
|
151
|
+
# emptiness verdict is asserted under the ambient UTF-8 locale AND LC_ALL=C,
|
|
152
|
+
# pinning the locale-safe Unicode-space normalization (issue #1988).
|
|
153
|
+
# =============================================================================
|
|
154
|
+
|
|
155
|
+
ESC=$(printf '\033')
|
|
156
|
+
NBSP=$(printf '\302\240')
|
|
157
|
+
CAPS_TMUX=$'styled=1\ncursor=1\nidentity=1\nrows=0'
|
|
158
|
+
CAPS_STYLED=$'styled=1\ncursor=0\nidentity=1\nrows=20' # herdr
|
|
159
|
+
CAPS_STYLED_NOID=$'styled=1\ncursor=0\nidentity=0\nrows=20' # zellij
|
|
160
|
+
CAPS_PLAIN=$'styled=0\ncursor=0\nidentity=0\nrows=20' # cmux, orca
|
|
161
|
+
|
|
162
|
+
# assert_screen <label> <want> <caps> <screen> [cursor] [identity]: one
|
|
163
|
+
# verdict, asserted under the ambient locale AND LC_ALL=C.
|
|
164
|
+
assert_screen() {
|
|
165
|
+
local label=$1 want=$2 out
|
|
166
|
+
shift 2
|
|
167
|
+
out=$(fm_composer_classify_screen "$@")
|
|
168
|
+
[ "$out" = "$want" ] || fail "$label: expected $want, got '$out'"
|
|
169
|
+
out=$(LC_ALL=C fm_composer_classify_screen "$@")
|
|
170
|
+
[ "$out" = "$want" ] || fail "$label under LC_ALL=C: expected $want, got '$out'"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
test_matrix_claude_bare_nbsp_row() {
|
|
174
|
+
# Real idle claude: `❯` + U+00A0, borderless, between horizontal rules.
|
|
175
|
+
# The audit's headline defect: this row read `pending` under LC_ALL=C
|
|
176
|
+
# (issue #1988), deferring every away-mode escalation in daemon contexts.
|
|
177
|
+
local screen typed
|
|
178
|
+
screen=$'transcript line\n────────────────────────\n❯'"$NBSP"$'\n────────────────────────\n bypass permissions'
|
|
179
|
+
assert_screen "claude idle on tmux" empty "$CAPS_TMUX" "$screen" 2 probe-absent
|
|
180
|
+
assert_screen "claude idle on herdr" empty "$CAPS_STYLED" "$screen" '' probe-absent
|
|
181
|
+
assert_screen "claude idle on zellij" empty "$CAPS_STYLED_NOID" "$screen"
|
|
182
|
+
assert_screen "claude idle on cmux/orca" empty "$CAPS_PLAIN" "$screen"
|
|
183
|
+
typed=$'────────────────────────\n❯ fix the login bug\n────────────────────────'
|
|
184
|
+
assert_screen "claude typed on tmux" pending "$CAPS_TMUX" "$typed" 1 probe-absent
|
|
185
|
+
# Plain capture cannot tell typed text from claude's rotating suggestion:
|
|
186
|
+
# the styled=0 degradation defers instead of fabricating pending.
|
|
187
|
+
assert_screen "claude typed on plain backends" unknown "$CAPS_PLAIN" "$typed"
|
|
188
|
+
pass "matrix: claude's ❯+NBSP row reads empty on every profile in both locales (#1988)"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
test_matrix_codex_dim_hint_row() {
|
|
192
|
+
# Real idle codex: bold `›`, reset, then an SGR-2 dim hint. Styled captures
|
|
193
|
+
# strip the ghost and prove empty; plain captures must defer as unknown -
|
|
194
|
+
# NEVER the old false `pending` that read the hint as unsent text.
|
|
195
|
+
local styled plain
|
|
196
|
+
styled=$'banner\n'"${ESC}[1m›${ESC}[0m ${ESC}[2mUse /skills to list available skills${ESC}[0m"
|
|
197
|
+
plain=$'banner\n› Use /skills to list available skills'
|
|
198
|
+
assert_screen "codex idle on tmux" empty "$CAPS_TMUX" "$styled" 1
|
|
199
|
+
assert_screen "codex idle on herdr" empty "$CAPS_STYLED" "$styled"
|
|
200
|
+
assert_screen "codex idle on zellij" empty "$CAPS_STYLED_NOID" "$styled"
|
|
201
|
+
assert_screen "codex idle on plain backends" unknown "$CAPS_PLAIN" "$plain"
|
|
202
|
+
pass "matrix: codex's dim hint is empty when styling proves it, unknown (never pending) when it cannot"
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
test_matrix_muse_truecolor_glyph_survives_signal_loss() {
|
|
206
|
+
# Real idle muse: truecolor `⟩` (38;2;90;160;255, luminance ~149.9) under a
|
|
207
|
+
# TITLED rule. Two independent signals prove emptiness: the glyph surviving
|
|
208
|
+
# the ghost strip, and the UNSTRIPPED plain row carrying an agent glyph.
|
|
209
|
+
# Drive them apart: with the luma threshold raised past the glyph's
|
|
210
|
+
# luminance, the ghost strip erases it, and the verdict must survive on the
|
|
211
|
+
# plain-row signal alone.
|
|
212
|
+
local screen plain out
|
|
213
|
+
screen=$'── Voice input (⌥ + v to start) ─────\n'"${ESC}[0m${ESC}[38;2;90;160;255m⟩${ESC}[0m"
|
|
214
|
+
plain=$'── Voice input (⌥ + v to start) ─────\n⟩'
|
|
215
|
+
assert_screen "muse idle on tmux" empty "$CAPS_TMUX" "$screen" 1
|
|
216
|
+
assert_screen "muse idle on herdr" empty "$CAPS_STYLED" "$screen"
|
|
217
|
+
assert_screen "muse idle on zellij" empty "$CAPS_STYLED_NOID" "$screen"
|
|
218
|
+
assert_screen "muse idle on cmux/orca" empty "$CAPS_PLAIN" "$plain"
|
|
219
|
+
out=$(FM_COMPOSER_GHOST_LUMA_MAX=200 fm_composer_classify_screen "$CAPS_STYLED" "$screen")
|
|
220
|
+
[ "$out" = empty ] || fail "muse must stay empty when the ghost strip eats its glyph (plain-row signal), got '$out'"
|
|
221
|
+
pass "matrix: muse's ⟩ reads empty everywhere and survives losing the styled-glyph signal"
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
test_matrix_cursor_reverse_video_placeholder_remnant() {
|
|
225
|
+
# Real idle cursor-agent (2026.08.11-e8db854), captured byte-for-byte from a
|
|
226
|
+
# live pane: the `→ ` glyph and the placeholder tail are dim (SGR 2), but the
|
|
227
|
+
# cell under the terminal cursor is REVERSE VIDEO (SGR 0;7). Reverse video is
|
|
228
|
+
# neither dim nor a dark foreground, so the ghost stripper keeps that one
|
|
229
|
+
# character and an idle composer reduces to a lone `P`.
|
|
230
|
+
local row screen plain out stripped
|
|
231
|
+
row="${ESC}[48;2;21;21;21m ${ESC}[2m→ ${ESC}[0;7m${ESC}[48;2;21;21;21mP"
|
|
232
|
+
row="${row}${ESC}[0;2m${ESC}[48;2;21;21;21mlan, search, build anything${ESC}[0m"
|
|
233
|
+
screen=$'transcript\n\n'"$row"
|
|
234
|
+
plain=$'transcript\n\n → Plan, search, build anything'
|
|
235
|
+
|
|
236
|
+
# NON-VACUOUSNESS: prove the remnant really survives stripping. If the ghost
|
|
237
|
+
# stripper ever learned SGR 7, `stripped` would be empty and the verdict below
|
|
238
|
+
# would come from the empty-content path instead, silently retiring the
|
|
239
|
+
# plain-row branch this case exists to cover.
|
|
240
|
+
stripped=$(printf '%s' "$row" | fm_composer_strip_ghost)
|
|
241
|
+
fm_composer_normalize_trim_var stripped
|
|
242
|
+
[ "$stripped" = P ] \
|
|
243
|
+
|| fail "cursor's reverse-video remnant must survive ghost stripping as 'P', got '$stripped'"
|
|
244
|
+
|
|
245
|
+
assert_screen "cursor idle on herdr" empty "$CAPS_STYLED" "$screen"
|
|
246
|
+
assert_screen "cursor idle on zellij" empty "$CAPS_STYLED_NOID" "$screen"
|
|
247
|
+
# An UNSTYLED capture carries no ghost-strip proof, so a bare row matching a
|
|
248
|
+
# placeholder is indistinguishable from typed text and must stay unknown -
|
|
249
|
+
# the same degradation every other bare-row placeholder already takes.
|
|
250
|
+
assert_screen "cursor idle on cmux/orca" unknown "$CAPS_PLAIN" "$plain"
|
|
251
|
+
|
|
252
|
+
# The dangerous direction: text a user actually TYPED is uniformly bright, so
|
|
253
|
+
# stripping leaves it EQUAL to the plain row. Even when that text is exactly
|
|
254
|
+
# the placeholder, it must stay pending - never a false empty.
|
|
255
|
+
local typed typed_plain
|
|
256
|
+
typed="${ESC}[48;2;21;21;21m ${ESC}[2m→ ${ESC}[0m${ESC}[38;2;224;222;244mAdd a follow-up${ESC}[0m"
|
|
257
|
+
typed_plain=$'transcript\n\n → Add a follow-up'
|
|
258
|
+
assert_screen "cursor typed placeholder text stays pending" pending \
|
|
259
|
+
"$CAPS_STYLED" $'transcript\n\n'"$typed"
|
|
260
|
+
# Without styling there is no proof either way, so it must not read empty.
|
|
261
|
+
out=$(fm_composer_classify_screen "$CAPS_PLAIN" "$typed_plain")
|
|
262
|
+
[ "$out" != empty ] \
|
|
263
|
+
|| fail "an unstyled cursor row matching the placeholder must not read empty, got '$out'"
|
|
264
|
+
pass "matrix: cursor's reverse-video placeholder remnant reads empty; real typed text stays pending"
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
test_matrix_herdr_halfblock_rule_bounds_bare_wrap() {
|
|
268
|
+
# Herdr draws a composer's rules with half-block glyphs (▄ above, ▀ below)
|
|
269
|
+
# rather than the box-drawing family. Without treating those as edges, a bare
|
|
270
|
+
# composer's WRAP region walks through its own closing rule and swallows the
|
|
271
|
+
# footer, whose real content turns an idle pane into a false `pending`.
|
|
272
|
+
# Captured live from a herdr cursor pane.
|
|
273
|
+
local screen plain out
|
|
274
|
+
plain=$'transcript\n \u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\n \u2192 Add a follow-up\n \u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\n Cursor Grok 4.5 High \u00b7 6.7% Run Everything\n ~/wt \u00b7 64cdd3a'
|
|
275
|
+
# The closing rule must bound the region, so the footer below is not input.
|
|
276
|
+
fm_composer_row_has_edge " $(printf '\u2580\u2580\u2580')" \
|
|
277
|
+
|| fail "a half-block rule row must count as a structural edge"
|
|
278
|
+
fm_composer_row_has_edge " $(printf '\u2584\u2584\u2584')" \
|
|
279
|
+
|| fail "the upper half-block rule must count as a structural edge"
|
|
280
|
+
# Non-vacuousness: the footer rows really are non-blank content that would be
|
|
281
|
+
# swallowed if the rule did not bound the region.
|
|
282
|
+
case "$plain" in *"Run Everything"*) : ;; *) fail "fixture lost its footer content" ;; esac
|
|
283
|
+
ESC_LOCAL=$(printf '\033')
|
|
284
|
+
screen=$'transcript\n \u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\n'" ${ESC_LOCAL}[2m\u2192 ${ESC_LOCAL}[0;7mA${ESC_LOCAL}[0;2mdd a follow-up${ESC_LOCAL}[0m"$'\n \u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\n Cursor Grok 4.5 High \u00b7 6.7% Run Everything\n ~/wt \u00b7 64cdd3a'
|
|
285
|
+
out=$(fm_composer_classify_screen "$CAPS_STYLED" "$(printf '%b' "$screen")")
|
|
286
|
+
[ "$out" = empty ] \
|
|
287
|
+
|| fail "an idle cursor composer inside herdr half-block rules must read empty, got '$out'"
|
|
288
|
+
pass "matrix: herdr half-block rules bound a bare composer's wrap region"
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
test_matrix_pi_separated_needs_identity() {
|
|
292
|
+
# Real idle pi: a blank row between two solid rules. The blank row alone is
|
|
293
|
+
# exactly what the strict rule refuses; only structure PLUS a live
|
|
294
|
+
# idle/done pi identity proves the composer (herdr's rule, now
|
|
295
|
+
# fleet-wide; tmux supplies identity from its foreground-process probe).
|
|
296
|
+
local screen typed pi_idle pi_working pi_blocked none
|
|
297
|
+
screen=$'transcript\n────────────────────────\n\n────────────────────────\n footer'
|
|
298
|
+
pi_idle=$(printf 'pi\tidle'); pi_working=$(printf 'pi\tworking'); none=$(printf 'zsh\t')
|
|
299
|
+
pi_blocked=$(printf 'pi\tblocked')
|
|
300
|
+
assert_screen "pi idle with identity" empty "$CAPS_STYLED" "$screen" '' "$pi_idle"
|
|
301
|
+
assert_screen "pi idle on tmux with identity" empty "$CAPS_TMUX" "$screen" 2 "$pi_idle"
|
|
302
|
+
assert_screen "pi idle on zellij" unknown "$CAPS_STYLED_NOID" "$screen"
|
|
303
|
+
# Identity-capable but unfetched: the adapter is asked to probe lazily.
|
|
304
|
+
[ "$(fm_composer_classify_screen "$CAPS_STYLED" "$screen")" = need-identity ] \
|
|
305
|
+
|| fail "an identity-capable profile should request the lazy identity probe"
|
|
306
|
+
# No identity capability (cmux/orca/zellij): the shape is unprovable.
|
|
307
|
+
assert_screen "pi pair without identity capability" unknown "$CAPS_PLAIN" "$screen"
|
|
308
|
+
# A working pi cannot authorize injection into the blank region.
|
|
309
|
+
assert_screen "working pi defers" unknown "$CAPS_STYLED" "$screen" '' "$pi_working"
|
|
310
|
+
# A pi parked on an interactive prompt reports `blocked`: it is waiting on a
|
|
311
|
+
# human keystroke, so the blank region is a menu's, not a free composer's.
|
|
312
|
+
# Typing there answers the prompt and the text is discarded (issue #2797).
|
|
313
|
+
assert_screen "blocked pi defers" unknown "$CAPS_STYLED" "$screen" '' "$pi_blocked"
|
|
314
|
+
# The audit's live counterexample: a plain shell running sleep, cursor
|
|
315
|
+
# parked on a blank line between two rules, NO pi process. The permissive
|
|
316
|
+
# rule read this `empty`; identity+structure refuses it.
|
|
317
|
+
assert_screen "sleep-pane counterexample" unknown "$CAPS_TMUX" "$screen" 2 "$none"
|
|
318
|
+
assert_screen "absent identity cannot prove blank pi pair" unknown "$CAPS_TMUX" "$screen" 2 probe-absent
|
|
319
|
+
typed=$'────────────────────────\nfix the flaky test\n────────────────────────'
|
|
320
|
+
assert_screen "pi typed" pending "$CAPS_STYLED" "$typed" '' "$pi_idle"
|
|
321
|
+
typed=$'────────────────────────\n❯\n────────────────────────'
|
|
322
|
+
assert_screen "pi lone-glyph draft with identity" pending "$CAPS_STYLED" "$typed" '' "$pi_idle"
|
|
323
|
+
assert_screen "pi lone-glyph draft on tmux" pending "$CAPS_TMUX" "$typed" 1 "$pi_idle"
|
|
324
|
+
assert_screen "lone glyph without identity capability" empty "$CAPS_STYLED_NOID" "$typed"
|
|
325
|
+
assert_screen "lone glyph on plain backend" empty "$CAPS_PLAIN" "$typed"
|
|
326
|
+
assert_screen "lone glyph with non-pi identity" empty "$CAPS_STYLED" "$typed" '' "$none"
|
|
327
|
+
pass "matrix: pi's separated composer needs identity + structure; the blank row alone never proves it"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
test_matrix_opencode_leftbar_signals() {
|
|
331
|
+
# Real idle opencode: `┃`-prefixed rows holding the "Ask anything..." hint,
|
|
332
|
+
# blanks, and a Build-mode footer. Two independent idle signals: the shared
|
|
333
|
+
# idle-placeholder pattern (works on plain captures) and the ghost strip
|
|
334
|
+
# (works on styled captures even if the pattern is overridden away).
|
|
335
|
+
local screen typed dim_screen out
|
|
336
|
+
screen=$' ┃\n ┃ Ask anything... "What is the tech stack?"\n ┃\n ┃ Build · GPT-5.5 Fast OpenAI · high\n ╹▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀'
|
|
337
|
+
dim_screen=$' ┃\n ┃ '"${ESC}[2mAsk anything...${ESC}[0m"$'\n ┃\n ┃ Build · GPT-5.5 Fast OpenAI · high\n ╹▀▀▀▀'
|
|
338
|
+
assert_screen "opencode idle on tmux (cursor on hint)" empty "$CAPS_TMUX" "$dim_screen" 1
|
|
339
|
+
assert_screen "opencode idle on herdr" empty "$CAPS_STYLED" "$dim_screen"
|
|
340
|
+
assert_screen "opencode idle on zellij" empty "$CAPS_STYLED_NOID" "$dim_screen"
|
|
341
|
+
assert_screen "opencode idle on cmux/orca" empty "$CAPS_PLAIN" "$screen"
|
|
342
|
+
# Signal separation: with the idle pattern overridden to something that
|
|
343
|
+
# cannot match, a DIM-styled hint still proves empty through the ghost strip.
|
|
344
|
+
out=$(FM_COMPOSER_IDLE_RE='^NEVER-MATCHES$' fm_composer_classify_screen "$CAPS_TMUX" "$dim_screen" 1)
|
|
345
|
+
[ "$out" = empty ] || fail "a dim opencode hint must stay empty via the ghost strip alone, got '$out'"
|
|
346
|
+
typed=$'┃\n┃ refactor the parser please\n┃\n┃ Build · GPT-5.5 Fast OpenAI · high\n╹▀▀▀▀'
|
|
347
|
+
assert_screen "opencode typed on tmux" pending "$CAPS_TMUX" "$typed" 1
|
|
348
|
+
assert_screen "opencode typed on plain backends" unknown "$CAPS_PLAIN" "$typed"
|
|
349
|
+
typed=$'┃ Ask anything... please investigate\n┃\n┃ Build · GPT-5.5 Fast OpenAI · high\n╹▀▀▀▀'
|
|
350
|
+
assert_screen "opencode placeholder-like input on tmux" pending "$CAPS_TMUX" "$typed" 0
|
|
351
|
+
assert_screen "opencode placeholder-like input on plain backends" unknown "$CAPS_PLAIN" "$typed"
|
|
352
|
+
typed=$'┃ refactor the parser please\n┃\n┃ Build · GPT-5.5 Fast OpenAI · high'
|
|
353
|
+
assert_screen "opencode multiline draft above blank cursor row" pending "$CAPS_TMUX" "$typed" 1
|
|
354
|
+
pass "matrix: opencode's left-bar composer reads empty everywhere and scans the full active run"
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
test_matrix_grok_titled_bottom_border() {
|
|
358
|
+
# Real idle grok: a bordered box whose BOTTOM border carries the model name.
|
|
359
|
+
# The audit showed the title alone flipped tmux's geometry check to
|
|
360
|
+
# ambiguous and the verdict to unknown, stranding every grok steer.
|
|
361
|
+
local titled plain_border typed placeholder_draft
|
|
362
|
+
titled=$' ╭──────────────────────────────────────╮\n │ ❯ │\n ╰──────────────────── Grok 4.5 (high) ─╯'
|
|
363
|
+
plain_border=$' ╭──────────────────────────────────────╮\n │ ❯ │\n ╰──────────────────────────────────────╯'
|
|
364
|
+
assert_screen "grok titled on tmux" empty "$CAPS_TMUX" "$titled" 1
|
|
365
|
+
assert_screen "grok titled on tmux bottom-border cursor" empty "$CAPS_TMUX" "$titled" 2
|
|
366
|
+
assert_screen "grok titled on herdr" empty "$CAPS_STYLED" "$titled"
|
|
367
|
+
placeholder_draft=$' ╭──────────────────────────────────────╮\n │ ❯ Type a message... │\n ╰──────────────────── Grok 4.5 (high) ─╯'
|
|
368
|
+
assert_screen "grok bright placeholder-like draft on tmux" pending "$CAPS_TMUX" "$placeholder_draft" 1
|
|
369
|
+
assert_screen "grok placeholder on plain backends" empty "$CAPS_PLAIN" "$placeholder_draft"
|
|
370
|
+
assert_screen "grok titled on cmux/orca" empty "$CAPS_PLAIN" "$titled"
|
|
371
|
+
assert_screen "grok titled on zellij" empty "$CAPS_STYLED_NOID" "$titled"
|
|
372
|
+
# The tolerance is additive: an untitled border still proves the same box.
|
|
373
|
+
assert_screen "grok untitled border" empty "$CAPS_TMUX" "$plain_border" 1
|
|
374
|
+
typed=$' ╭──────────────────────────────────────╮\n │ ❯ deploy the fix │\n ╰──────────────────── Grok 4.5 (high) ─╯'
|
|
375
|
+
assert_screen "grok typed on tmux" pending "$CAPS_TMUX" "$typed" 1
|
|
376
|
+
pass "matrix: grok's titled bottom border is tolerated as a title, not read as ambiguity"
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
test_matrix_kimi_bordered_shell_glyph_box() {
|
|
380
|
+
# Kimi's bordered `│ > │` composer - the shape fm-spawn.sh's retired
|
|
381
|
+
# spawn-local regex used to own. Now the shared owner proves it everywhere,
|
|
382
|
+
# which is what kimi launch-readiness and delivery route through.
|
|
383
|
+
local screen
|
|
384
|
+
screen=$'╭────────────────────────╮\n│ > │\n╰────────────────────────╯'
|
|
385
|
+
assert_screen "kimi idle on tmux" empty "$CAPS_TMUX" "$screen" 1
|
|
386
|
+
assert_screen "kimi idle on cmux/orca" empty "$CAPS_PLAIN" "$screen"
|
|
387
|
+
assert_screen "kimi idle on herdr" empty "$CAPS_STYLED" "$screen"
|
|
388
|
+
assert_screen "kimi idle on zellij" empty "$CAPS_STYLED_NOID" "$screen"
|
|
389
|
+
pass "matrix: kimi's bordered shell-glyph box reads empty through the shared owner (spawn's fourth copy retired)"
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
test_matrix_claude_inside_zellij_ansi_dump() {
|
|
393
|
+
# Real claude captured through `zellij action dump-screen --ansi`
|
|
394
|
+
# (capability established by the audit): `ESC[m` `❯` U+00A0.
|
|
395
|
+
local screen plain
|
|
396
|
+
screen=$'zellij pane transcript\n'"${ESC}[m❯${NBSP}"
|
|
397
|
+
plain=$'zellij pane transcript\n❯'"$NBSP"
|
|
398
|
+
assert_screen "claude-in-zellij on tmux" empty "$CAPS_TMUX" "$screen" 1
|
|
399
|
+
assert_screen "claude-in-zellij on herdr" empty "$CAPS_STYLED" "$screen"
|
|
400
|
+
assert_screen "claude-in-zellij on zellij" empty "$CAPS_STYLED_NOID" "$screen"
|
|
401
|
+
assert_screen "claude-in-zellij on plain backends" empty "$CAPS_PLAIN" "$plain"
|
|
402
|
+
pass "matrix: the real claude-in-zellij --ansi dump reads empty in both locales"
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
test_strict_blank_row_divergence() {
|
|
406
|
+
# THE STRICT POSTURE PIN (captain decision blank-row-injection-posture,
|
|
407
|
+
# 2026-08-09): a blank or otherwise unidentified input row with no positive
|
|
408
|
+
# container proof is `unknown`. Each case below read `empty` (or `pending`)
|
|
409
|
+
# under the replaced permissive rule; if any of them drifts back, the
|
|
410
|
+
# permissive posture has silently returned and away-mode injection would
|
|
411
|
+
# again type escalations into unproven panes.
|
|
412
|
+
local out
|
|
413
|
+
# Permissive read this blank cursor row as empty = safe to inject.
|
|
414
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" $'some output\nmore output\n' 2)
|
|
415
|
+
[ "$out" = unknown ] || fail "a blank unidentified cursor row must be unknown (was permissive empty), got '$out'"
|
|
416
|
+
# A dead shell's prompt row.
|
|
417
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" $'output\n$ ' 1)
|
|
418
|
+
[ "$out" = unknown ] || fail "a dead-shell prompt row must be unknown, got '$out'"
|
|
419
|
+
# A bare busy-footer row is not a composer container.
|
|
420
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" $'Working...' 0)
|
|
421
|
+
[ "$out" = unknown ] || fail "a bare busy-footer row must be unknown (was permissive empty), got '$out'"
|
|
422
|
+
# An unidentified free-text cursor row carries no container proof either.
|
|
423
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" $'output\nhuman draft text' 1)
|
|
424
|
+
[ "$out" = unknown ] || fail "an unidentified text row must be unknown under strict, got '$out'"
|
|
425
|
+
# A blank screen with no cursor capability.
|
|
426
|
+
out=$(fm_composer_classify_screen "$CAPS_PLAIN" $'\n\n')
|
|
427
|
+
[ "$out" = unknown ] || fail "a blank screen must be unknown, got '$out'"
|
|
428
|
+
pass "strict posture: blank and unidentified rows are unknown, never injectable empty"
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
test_bare_wrap_region_classifies() {
|
|
432
|
+
# Long typed input wraps below the glyph row; the cursor rides the wrapped
|
|
433
|
+
# continuation. The region is IDENTIFIED (glyph row + contiguous non-blank,
|
|
434
|
+
# non-structural rows), so a swallowed Enter still reads pending and earns
|
|
435
|
+
# its retry; a wrapped GHOST suggestion still proves empty.
|
|
436
|
+
local wrapped ghost_wrapped out
|
|
437
|
+
wrapped=$'❯ a very long steer message that\nwraps onto the following line'
|
|
438
|
+
assert_screen "wrapped typed input" pending "$CAPS_TMUX" "$wrapped" 1
|
|
439
|
+
wrapped=$'❯ wrapped typed input\ncontinues without a terminal-inserted glyph'
|
|
440
|
+
assert_screen "ordinary wrapped input" pending "$CAPS_TMUX" "$wrapped" 1
|
|
441
|
+
ghost_wrapped=$'❯ '"${ESC}[2ma long rotating suggestion that${ESC}[0m"$'\n'"${ESC}[2mwraps onto the next line${ESC}[0m"
|
|
442
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" "$ghost_wrapped" 1)
|
|
443
|
+
[ "$out" = empty ] || fail "a wrapped ghost suggestion should still prove empty, got '$out'"
|
|
444
|
+
# A structural row between the glyph and the cursor breaks the wrap claim.
|
|
445
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" $'❯ text\n────────────────\nbelow the rule' 2)
|
|
446
|
+
[ "$out" = unknown ] || fail "a rule between glyph and cursor must break the wrap region, got '$out'"
|
|
447
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" $'❯ text\n$ live shell' 1)
|
|
448
|
+
[ "$out" = unknown ] || fail "a shell prompt below a glyph row must not become wrapped input, got '$out'"
|
|
449
|
+
pass "fm_composer_classify_screen: the bare composer's wrap region stays identified; structure breaks it"
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
test_contiguous_transcript_reanchors_on_live_prompt() {
|
|
453
|
+
local screen
|
|
454
|
+
screen=$'❯ hi\nHello!\n❯'
|
|
455
|
+
assert_screen "contiguous transcript live prompt on cursorless styled backend" empty "$CAPS_STYLED_NOID" "$screen"
|
|
456
|
+
assert_screen "contiguous transcript live prompt on cursorless plain backend" empty "$CAPS_PLAIN" "$screen"
|
|
457
|
+
assert_screen "contiguous transcript live prompt with cursor" empty "$CAPS_TMUX" "$screen" 2
|
|
458
|
+
pass "fm_composer_classify_screen: a row-leading agent glyph reanchors the live composer"
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
test_lower_dead_shell_invalidates_cursorless_candidate() {
|
|
462
|
+
local stale live out
|
|
463
|
+
stale=$'old transcript\n❯\nprocess exited\n$'
|
|
464
|
+
assert_screen "stale composer above dead shell on herdr" unknown "$CAPS_STYLED" "$stale"
|
|
465
|
+
assert_screen "stale composer above dead shell on zellij" unknown "$CAPS_STYLED_NOID" "$stale"
|
|
466
|
+
assert_screen "stale composer above dead shell on cmux/orca" unknown "$CAPS_PLAIN" "$stale"
|
|
467
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" "$stale" 1)
|
|
468
|
+
[ "$out" = empty ] \
|
|
469
|
+
|| fail "cursor mode must keep the cursor-anchored composer verdict, got '$out'"
|
|
470
|
+
|
|
471
|
+
live=$'transcript shell snippet\n$ echo old output\nmore transcript\n❯'
|
|
472
|
+
assert_screen "shell transcript above live composer on herdr" empty "$CAPS_STYLED" "$live"
|
|
473
|
+
assert_screen "shell transcript above live composer on zellij" empty "$CAPS_STYLED_NOID" "$live"
|
|
474
|
+
assert_screen "shell transcript above live composer on cmux/orca" empty "$CAPS_PLAIN" "$live"
|
|
475
|
+
pass "fm_composer_classify_screen: a lower dead shell invalidates only cursorless stale composers"
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
test_cursorless_bare_wrap_region_classifies() {
|
|
479
|
+
local activity status bounded ghost out
|
|
480
|
+
activity=$'❯\nWorking on request...'
|
|
481
|
+
assert_screen "cursorless activity below bare row on herdr" pending "$CAPS_STYLED" "$activity"
|
|
482
|
+
assert_screen "cursorless activity below bare row on zellij" pending "$CAPS_STYLED_NOID" "$activity"
|
|
483
|
+
assert_screen "cursorless activity below bare row on cmux/orca" unknown "$CAPS_PLAIN" "$activity"
|
|
484
|
+
|
|
485
|
+
status=$'›\n\ncodex status line'
|
|
486
|
+
assert_screen "blank-separated codex status on herdr" empty "$CAPS_STYLED" "$status"
|
|
487
|
+
assert_screen "blank-separated codex status on zellij" empty "$CAPS_STYLED_NOID" "$status"
|
|
488
|
+
assert_screen "blank-separated codex status on cmux/orca" empty "$CAPS_PLAIN" "$status"
|
|
489
|
+
|
|
490
|
+
bounded=$'────────────────────────\n❯\n────────────────────────\nClaude 4.1'
|
|
491
|
+
assert_screen "rule-bounded claude footer on herdr" empty "$CAPS_STYLED" "$bounded" '' probe-absent
|
|
492
|
+
assert_screen "rule-bounded claude footer on zellij" empty "$CAPS_STYLED_NOID" "$bounded"
|
|
493
|
+
assert_screen "rule-bounded claude footer on cmux/orca" empty "$CAPS_PLAIN" "$bounded"
|
|
494
|
+
|
|
495
|
+
ghost=$'❯ '"${ESC}[2ma long rotating suggestion that${ESC}[0m"$'\n'"${ESC}[2mwraps onto the next line${ESC}[0m"
|
|
496
|
+
out=$(fm_composer_classify_screen "$CAPS_STYLED" "$ghost")
|
|
497
|
+
[ "$out" = empty ] || fail "cursorless ghost wrap on herdr should be empty, got '$out'"
|
|
498
|
+
out=$(fm_composer_classify_screen "$CAPS_STYLED_NOID" "$ghost")
|
|
499
|
+
[ "$out" = empty ] || fail "cursorless ghost wrap on zellij should be empty, got '$out'"
|
|
500
|
+
pass "fm_composer_classify_screen: cursorless bare wrap regions participate in verdicts"
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
test_cursorless_container_rejects_contiguous_lower_activity() {
|
|
504
|
+
local box leftbar grok kimi opencode
|
|
505
|
+
box=$'╭────────────────────────╮\n│ ❯ │\n╰────────────────────────╯\nWorking on request...'
|
|
506
|
+
assert_screen "stale box above activity on herdr" unknown "$CAPS_STYLED" "$box"
|
|
507
|
+
assert_screen "stale box above activity on zellij" unknown "$CAPS_STYLED_NOID" "$box"
|
|
508
|
+
assert_screen "stale box above activity on cmux/orca" unknown "$CAPS_PLAIN" "$box"
|
|
509
|
+
|
|
510
|
+
leftbar=$'┃\n┃ Ask anything...\n┃\n┃ Build · GPT-5.5 Fast OpenAI · high\n╹▀▀▀▀▀▀▀▀\nWorking on request...'
|
|
511
|
+
assert_screen "stale left-bar above activity on herdr" unknown "$CAPS_STYLED" "$leftbar"
|
|
512
|
+
assert_screen "stale left-bar above activity on zellij" unknown "$CAPS_STYLED_NOID" "$leftbar"
|
|
513
|
+
assert_screen "stale left-bar above activity on cmux/orca" unknown "$CAPS_PLAIN" "$leftbar"
|
|
514
|
+
|
|
515
|
+
grok=$'╭────────────────────────╮\n│ ❯ │\n╰──────── Grok 4.5 ──────╯\n\nGrok status'
|
|
516
|
+
kimi=$'╭────────────────────────╮\n│ > │\n╰────────────────────────╯\n\nKimi status'
|
|
517
|
+
opencode=$'┃\n┃ Ask anything...\n┃\n┃ Build · GPT-5.5 Fast OpenAI · high\n╹▀▀▀▀▀▀▀▀\n\nOpenCode status'
|
|
518
|
+
assert_screen "blank-separated grok footer" empty "$CAPS_STYLED_NOID" "$grok"
|
|
519
|
+
assert_screen "blank-separated kimi footer" empty "$CAPS_PLAIN" "$kimi"
|
|
520
|
+
assert_screen "left-bar floor and blank-separated footer" empty "$CAPS_STYLED_NOID" "$opencode"
|
|
521
|
+
pass "fm_composer_classify_screen: cursorless containers reject only contiguous unclaimed activity"
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
test_bottom_most_candidate_wins() {
|
|
525
|
+
# The one ranking rule: the live composer is bottom-anchored, so a stale
|
|
526
|
+
# decorative box (codex's startup banner) can never outrank the real row
|
|
527
|
+
# below it - the confidently-wrong orca case from the audit.
|
|
528
|
+
local screen out
|
|
529
|
+
screen=$'╭────────────────────────╮\n│ permissions: YOLO mode │\n╰────────────────────────╯\n❯'"$NBSP"
|
|
530
|
+
assert_screen "banner above live claude row" empty "$CAPS_PLAIN" "$screen"
|
|
531
|
+
out=$(fm_composer_classify_screen "$CAPS_PLAIN" $'╭────────────────────────╮\n│ permissions: YOLO mode │\n╰────────────────────────╯\n› Use /skills to list available skills')
|
|
532
|
+
[ "$out" != pending ] || fail "a stale banner must never classify as pending composer text"
|
|
533
|
+
screen=$'❯ old draft\n\n❯'
|
|
534
|
+
assert_screen "blank-separated newer bare composer" empty "$CAPS_STYLED_NOID" "$screen"
|
|
535
|
+
pass "fm_composer_classify_screen: the bottom-most candidate wins; stale banners cannot"
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
test_incomplete_lower_box_invalidates_stale_candidate() {
|
|
539
|
+
local screen out
|
|
540
|
+
screen=$'╭────────────────────────╮\n│ ❯ │\n╰────────────────────────╯\nstartup complete\n╭────────────────────────╮\n│ ❯ clipped live draft '
|
|
541
|
+
out=$(fm_composer_classify_screen "$CAPS_PLAIN" "$screen")
|
|
542
|
+
[ "$out" = unknown ] \
|
|
543
|
+
|| fail "an incomplete lower box must invalidate an earlier empty box, got '$out'"
|
|
544
|
+
pass "fm_composer_classify_screen: incomplete lower structure invalidates stale boxes"
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
test_titled_bottom_requires_matching_width() {
|
|
548
|
+
local screen out
|
|
549
|
+
screen=$'╭────────────────────────╮\n│ ❯ │\n╰─ Grok ─╯'
|
|
550
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" "$screen" 1)
|
|
551
|
+
[ "$out" = unknown ] \
|
|
552
|
+
|| fail "a short titled bottom must not prove an empty box, got '$out'"
|
|
553
|
+
pass "fm_composer_classify_screen: titled bottoms retain full box geometry"
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
test_cursor_on_proven_box_bottom_classifies_content() {
|
|
557
|
+
local screen out
|
|
558
|
+
screen=$'╭────────────────────────╮\n│ ❯ │\n╰────────────────────────╯'
|
|
559
|
+
out=$(fm_composer_classify_screen "$CAPS_TMUX" "$screen" 2)
|
|
560
|
+
[ "$out" = empty ] \
|
|
561
|
+
|| fail "a cursor on a proven box bottom must classify its content, got '$out'"
|
|
562
|
+
pass "fm_composer_classify_screen: a proven box tolerates a bottom-border cursor"
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
test_selected_content_is_composer_scoped_and_wrap_normalized() {
|
|
566
|
+
local screen out
|
|
567
|
+
screen=$'hello captain in transcript\n╭────────────────────╮\n│ unrelated │\n│ draft │\n╰────────────────────╯'
|
|
568
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
569
|
+
[ "$out" = 'unrelated draft' ] \
|
|
570
|
+
|| fail "box extraction should contain only normalized selected composer rows, got '$out'"
|
|
571
|
+
screen=$'hello captain in transcript\n┃ hello\n┃ captain\n┃ Build · GPT-5.5 Fast OpenAI · high'
|
|
572
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
573
|
+
[ "$out" = 'hello captain' ] \
|
|
574
|
+
|| fail "left-bar extraction should join user rows without footer furniture, got '$out'"
|
|
575
|
+
screen=$'╭────────────────────╮\n│ ❯ '"${ESC}[2mType a message...${ESC}[0m"$'│\n╰────────────────────╯'
|
|
576
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
577
|
+
[ -z "$out" ] \
|
|
578
|
+
|| fail "ghost agent-prompt placeholders should be excluded from extracted user content, got '$out'"
|
|
579
|
+
screen=$'╭────────────────────╮\n│ > '"${ESC}[2mType a message...${ESC}[0m"$'│\n╰────────────────────╯'
|
|
580
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
581
|
+
[ -z "$out" ] \
|
|
582
|
+
|| fail "ghost shell-prompt placeholders should be excluded from boxed user content, got '$out'"
|
|
583
|
+
screen=$'╭────────────────────╮\n│ ❯ Type a message...│\n╰────────────────────╯'
|
|
584
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
585
|
+
[ "$out" = 'Type a message...' ] \
|
|
586
|
+
|| fail "surviving placeholder-like input should remain extracted user content, got '$out'"
|
|
587
|
+
screen=$'❯ a legitimately long steer that\nwraps across the next bare row\n\ntranscript below the break'
|
|
588
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
589
|
+
[ "$out" = 'a legitimately long steer that wraps across the next bare row' ] \
|
|
590
|
+
|| fail "bare extraction should include only its contiguous wrap region, got '$out'"
|
|
591
|
+
screen=$'❯ wrapped user content\ncontinuation preserves a mid-row ❯ glyph'
|
|
592
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
593
|
+
[ "$out" = 'wrapped user content continuation preserves a mid-row ❯ glyph' ] \
|
|
594
|
+
|| fail "bare extraction should preserve mid-row agent glyph bytes, got '$out'"
|
|
595
|
+
screen=$'❯ stale composer\n$ live shell'
|
|
596
|
+
if out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen"); then
|
|
597
|
+
fail "a lower live shell must invalidate composer extraction, got '$out'"
|
|
598
|
+
fi
|
|
599
|
+
screen=$'╭──────────────────────────────╮\n│ > wrapped user content │\n│ ❯ preserves its leading glyph│\n╰──────────────────────────────╯'
|
|
600
|
+
out=$(fm_composer_extract_selected_content "$CAPS_STYLED_NOID" "$screen")
|
|
601
|
+
[ "$out" = 'wrapped user content ❯ preserves its leading glyph' ] \
|
|
602
|
+
|| fail "box extraction should strip only its actual prompt-row glyph, got '$out'"
|
|
603
|
+
pass "fm_composer_extract_selected_content: scopes user content and excludes furniture"
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
test_bare_shell_glyphs_are_unknown
|
|
607
|
+
test_stripped_unbordered_content_uses_plain_content
|
|
608
|
+
test_bare_shell_prompt_with_command_is_not_empty
|
|
609
|
+
test_bordered_shell_glyph_is_empty
|
|
610
|
+
test_agent_glyphs_are_empty_bordered_and_bare
|
|
611
|
+
test_empty_content_is_empty
|
|
612
|
+
test_idle_placeholder_is_empty
|
|
613
|
+
test_idle_placeholder_case_mode_is_explicit
|
|
614
|
+
test_real_text_is_pending
|
|
615
|
+
test_matrix_claude_bare_nbsp_row
|
|
616
|
+
test_matrix_codex_dim_hint_row
|
|
617
|
+
test_matrix_muse_truecolor_glyph_survives_signal_loss
|
|
618
|
+
test_matrix_cursor_reverse_video_placeholder_remnant
|
|
619
|
+
test_matrix_herdr_halfblock_rule_bounds_bare_wrap
|
|
620
|
+
test_matrix_pi_separated_needs_identity
|
|
621
|
+
test_matrix_opencode_leftbar_signals
|
|
622
|
+
test_matrix_grok_titled_bottom_border
|
|
623
|
+
test_matrix_kimi_bordered_shell_glyph_box
|
|
624
|
+
test_matrix_claude_inside_zellij_ansi_dump
|
|
625
|
+
test_strict_blank_row_divergence
|
|
626
|
+
test_bare_wrap_region_classifies
|
|
627
|
+
test_contiguous_transcript_reanchors_on_live_prompt
|
|
628
|
+
test_lower_dead_shell_invalidates_cursorless_candidate
|
|
629
|
+
test_cursorless_bare_wrap_region_classifies
|
|
630
|
+
test_cursorless_container_rejects_contiguous_lower_activity
|
|
631
|
+
test_bottom_most_candidate_wins
|
|
632
|
+
test_incomplete_lower_box_invalidates_stale_candidate
|
|
633
|
+
test_titled_bottom_requires_matching_width
|
|
634
|
+
test_cursor_on_proven_box_bottom_classifies_content
|
|
635
|
+
test_selected_content_is_composer_scoped_and_wrap_normalized
|
|
636
|
+
|
|
637
|
+
test_queued_enter_verdict_busy_pending_is_empty() {
|
|
638
|
+
local out
|
|
639
|
+
out=$(fm_composer_queued_enter_verdict pending busy)
|
|
640
|
+
[ "$out" = empty ] || fail "busy + proven pending must be queued delivery (empty), got '$out'"
|
|
641
|
+
pass "fm_composer_queued_enter_verdict: pending + busy returns empty (queued Enter)"
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
test_queued_enter_verdict_idle_pending_stays_pending() {
|
|
645
|
+
local out
|
|
646
|
+
out=$(fm_composer_queued_enter_verdict pending idle)
|
|
647
|
+
[ "$out" = pending ] || fail "idle + proven pending must stay a genuine swallow, got '$out'"
|
|
648
|
+
out=$(fm_composer_queued_enter_verdict pending unknown)
|
|
649
|
+
[ "$out" = pending ] || fail "unknown busy is not proof of a queue, got '$out'"
|
|
650
|
+
pass "fm_composer_queued_enter_verdict: pending + idle/unknown stays pending"
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
test_queued_enter_verdict_does_not_convert_other_states() {
|
|
654
|
+
local state out
|
|
655
|
+
for state in empty pending-unproven unknown send-failed future-state; do
|
|
656
|
+
out=$(fm_composer_queued_enter_verdict "$state" busy)
|
|
657
|
+
[ "$out" = "$state" ] || fail "busy must not convert '$state', got '$out'"
|
|
658
|
+
out=$(fm_composer_queued_enter_verdict "$state" idle)
|
|
659
|
+
[ "$out" = "$state" ] || fail "idle must not convert '$state', got '$out'"
|
|
660
|
+
done
|
|
661
|
+
pass "fm_composer_queued_enter_verdict: only proven pending is converted"
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
test_queued_enter_verdict_busy_pending_is_empty
|
|
665
|
+
test_queued_enter_verdict_idle_pending_stays_pending
|
|
666
|
+
test_queued_enter_verdict_does_not_convert_other_states
|