@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,1023 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Parity guard for firstmate's shell-lint definition.
|
|
3
|
+
#
|
|
4
|
+
# bin/fm-lint.sh must be the single owner that BOTH CI
|
|
5
|
+
# (.github/workflows/ci.yml) and the pre-push gate (.no-mistakes.yaml
|
|
6
|
+
# commands.lint) invoke, so the local lint can never diverge from CI again.
|
|
7
|
+
# Regression origin: with no commands.lint configured, the local no-mistakes
|
|
8
|
+
# lint step never ran the deterministic
|
|
9
|
+
# `shellcheck bin/*.sh bin/backends/*.sh tests/*.sh`, so PRs passed local
|
|
10
|
+
# validation yet failed that exact check in CI on info/warning findings such as
|
|
11
|
+
# SC2015, SC1007, and SC2034. A second axis was tool-version skew: CI's
|
|
12
|
+
# ShellCheck floated with the runner image and still emitted SC2015, which
|
|
13
|
+
# ShellCheck retired in 0.11.0. fm-lint.sh now pins one exact version and both
|
|
14
|
+
# gates resolve it, so command, file set, config, AND version all match.
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
# shellcheck source=tests/lib.sh
|
|
18
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
19
|
+
|
|
20
|
+
LINT="$ROOT/bin/fm-lint.sh"
|
|
21
|
+
INSTALLER="$ROOT/bin/fm-install-shellcheck.sh"
|
|
22
|
+
# The pinned version, read from the single source (the one owner itself).
|
|
23
|
+
REQUIRED=$("$LINT" --required-version)
|
|
24
|
+
|
|
25
|
+
# Official GitHub release asset sha256 values for shellcheck v0.11.0 .tar.xz
|
|
26
|
+
# archives (https://github.com/koalaman/shellcheck/releases/tag/v0.11.0). Tests
|
|
27
|
+
# compare installer behavior against these published digests, not script source.
|
|
28
|
+
SHELLCHECK_SHA_LINUX_X86_64=8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198
|
|
29
|
+
SHELLCHECK_SHA_LINUX_AARCH64=12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588
|
|
30
|
+
SHELLCHECK_SHA_DARWIN_X86_64=3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6
|
|
31
|
+
SHELLCHECK_SHA_DARWIN_AARCH64=56affdd8de5527894dca6dc3d7e0a99a873b0f004d7aabc30ae407d3f48b0a79
|
|
32
|
+
|
|
33
|
+
# fm_install_stub_uname <fakebin>: uname -s / uname -m from FM_TEST_UNAME_S/M.
|
|
34
|
+
fm_install_stub_uname() {
|
|
35
|
+
local fakebin=$1
|
|
36
|
+
cat > "$fakebin/uname" <<'SH'
|
|
37
|
+
#!/usr/bin/env bash
|
|
38
|
+
case "${1:-}" in
|
|
39
|
+
-s) printf '%s\n' "${FM_TEST_UNAME_S:-Linux}" ;;
|
|
40
|
+
-m) printf '%s\n' "${FM_TEST_UNAME_M:-x86_64}" ;;
|
|
41
|
+
*) printf '%s\n' "${FM_TEST_UNAME_S:-Linux}" ;;
|
|
42
|
+
esac
|
|
43
|
+
SH
|
|
44
|
+
chmod +x "$fakebin/uname"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# fm_install_stub_curl <fakebin>: log the URL, fail CURL_FAIL_UNTIL times, then
|
|
48
|
+
# write an empty file at -o. CURL_COUNT and CURL_URL_LOG are paths the stub
|
|
49
|
+
# updates when invoked.
|
|
50
|
+
fm_install_stub_curl() {
|
|
51
|
+
local fakebin=$1
|
|
52
|
+
cat > "$fakebin/curl" <<'SH'
|
|
53
|
+
#!/usr/bin/env bash
|
|
54
|
+
count=0
|
|
55
|
+
[ ! -f "${CURL_COUNT:-}" ] || count=$(cat "$CURL_COUNT")
|
|
56
|
+
count=$((count + 1))
|
|
57
|
+
[ -z "${CURL_COUNT:-}" ] || printf '%s\n' "$count" > "$CURL_COUNT"
|
|
58
|
+
url=
|
|
59
|
+
out=
|
|
60
|
+
while [ "$#" -gt 0 ]; do
|
|
61
|
+
case "$1" in
|
|
62
|
+
-o)
|
|
63
|
+
out=$2
|
|
64
|
+
shift 2
|
|
65
|
+
;;
|
|
66
|
+
-*)
|
|
67
|
+
shift
|
|
68
|
+
;;
|
|
69
|
+
*)
|
|
70
|
+
url=$1
|
|
71
|
+
shift
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
done
|
|
75
|
+
[ -z "${CURL_URL_LOG:-}" ] || printf '%s\n' "$url" >> "$CURL_URL_LOG"
|
|
76
|
+
fail_until=${CURL_FAIL_UNTIL:-0}
|
|
77
|
+
[ "$count" -gt "$fail_until" ] || exit 22
|
|
78
|
+
: > "$out"
|
|
79
|
+
exit 0
|
|
80
|
+
SH
|
|
81
|
+
chmod +x "$fakebin/curl"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# fm_install_stub_hasher <fakebin> <name>: sha256sum or shasum stub that prints
|
|
85
|
+
# SHA256_STUB_HASH and records the invocation on HASHER_LOG. shasum requires -a 256.
|
|
86
|
+
fm_install_stub_hasher() {
|
|
87
|
+
local fakebin=$1 name=$2
|
|
88
|
+
cat > "$fakebin/$name" <<'SH'
|
|
89
|
+
#!/usr/bin/env bash
|
|
90
|
+
self=${0##*/}
|
|
91
|
+
if [ -n "${HASHER_LOG:-}" ]; then
|
|
92
|
+
printf '%s\n' "$self $*" >> "$HASHER_LOG"
|
|
93
|
+
fi
|
|
94
|
+
file=$1
|
|
95
|
+
if [ "$self" = shasum ]; then
|
|
96
|
+
algo=
|
|
97
|
+
file=
|
|
98
|
+
while [ "$#" -gt 0 ]; do
|
|
99
|
+
case "$1" in
|
|
100
|
+
-a)
|
|
101
|
+
algo=$2
|
|
102
|
+
shift 2
|
|
103
|
+
;;
|
|
104
|
+
*)
|
|
105
|
+
file=$1
|
|
106
|
+
shift
|
|
107
|
+
;;
|
|
108
|
+
esac
|
|
109
|
+
done
|
|
110
|
+
[ "$algo" = 256 ] || exit 1
|
|
111
|
+
fi
|
|
112
|
+
printf '%s %s\n' "${SHA256_STUB_HASH:?}" "$file"
|
|
113
|
+
SH
|
|
114
|
+
chmod +x "$fakebin/$name"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fm_install_stub_tar_shellcheck() {
|
|
118
|
+
local fakebin=$1
|
|
119
|
+
cat > "$fakebin/tar" <<'SH'
|
|
120
|
+
#!/usr/bin/env bash
|
|
121
|
+
while [ "$#" -gt 0 ]; do
|
|
122
|
+
if [ "$1" = "-C" ]; then
|
|
123
|
+
mkdir -p "$2/shellcheck-v0.11.0"
|
|
124
|
+
cat > "$2/shellcheck-v0.11.0/shellcheck" <<'EOF'
|
|
125
|
+
#!/usr/bin/env bash
|
|
126
|
+
printf 'ShellCheck - shell script analysis tool\nversion: 0.11.0\n'
|
|
127
|
+
EOF
|
|
128
|
+
chmod +x "$2/shellcheck-v0.11.0/shellcheck"
|
|
129
|
+
exit 0
|
|
130
|
+
fi
|
|
131
|
+
shift
|
|
132
|
+
done
|
|
133
|
+
exit 2
|
|
134
|
+
SH
|
|
135
|
+
chmod +x "$fakebin/tar"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fm_install_stub_sleep() {
|
|
139
|
+
local fakebin=$1
|
|
140
|
+
cat > "$fakebin/sleep" <<'SH'
|
|
141
|
+
#!/usr/bin/env bash
|
|
142
|
+
exit 0
|
|
143
|
+
SH
|
|
144
|
+
chmod +x "$fakebin/sleep"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
# True only when the resolved shellcheck is exactly the pinned version, so the
|
|
148
|
+
# lint-running tests below match what CI enforces instead of a runner default.
|
|
149
|
+
pinned_ready() {
|
|
150
|
+
command -v shellcheck >/dev/null 2>&1 || return 1
|
|
151
|
+
[ "$(shellcheck --version | awk '/^version:/ {print $2; exit}')" = "$REQUIRED" ]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
test_help_reports_the_complete_interface() {
|
|
155
|
+
local help
|
|
156
|
+
help=$("$LINT" --help) || fail "fm-lint.sh --help failed"
|
|
157
|
+
assert_contains "$help" "--telemetry" "fm-lint.sh --help omitted --telemetry"
|
|
158
|
+
assert_contains "$help" "--required-version" "fm-lint.sh --help omitted --required-version"
|
|
159
|
+
assert_contains "$help" "--list-files" "fm-lint.sh --help omitted --list-files"
|
|
160
|
+
assert_contains "$help" "--help" "fm-lint.sh --help omitted --help"
|
|
161
|
+
assert_contains "$help" "--fast" "fm-lint.sh --help omitted --fast"
|
|
162
|
+
pass "fm-lint.sh --help reports the complete executable interface"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
test_list_files_reports_the_shell_inventory() {
|
|
166
|
+
local listed expected
|
|
167
|
+
# CI=true forces the full canonical set regardless of the ambient branch or
|
|
168
|
+
# working-tree diff a local test run happens to have, so this stays a pure
|
|
169
|
+
# inventory check independent of fm-lint.sh's own changed-file mode below.
|
|
170
|
+
listed=$(CI=true "$LINT" --list-files)
|
|
171
|
+
expected=$(find bin bin/backends tests -maxdepth 1 -type f -name '*.sh' -print | LC_ALL=C sort)
|
|
172
|
+
[ "$(printf '%s\n' "$listed" | LC_ALL=C sort)" = "$expected" ] \
|
|
173
|
+
|| fail "fm-lint.sh --list-files did not return the complete shell inventory"
|
|
174
|
+
pass "fm-lint.sh --list-files reports the complete shell inventory"
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# fm_lint_stub_git <fakebin-dir>: install a git stub for the changed-file mode
|
|
178
|
+
# tests below. Its answers are driven by env vars the caller sets before
|
|
179
|
+
# invoking fm-lint.sh, so those tests can steer git state without depending on
|
|
180
|
+
# this worktree's actual branch, remotes, or history:
|
|
181
|
+
# FM_TEST_GIT_INSIDE_WORKTREE 1 (default) or 0
|
|
182
|
+
# FM_TEST_GIT_BRANCH branch name for `rev-parse --abbrev-ref HEAD`
|
|
183
|
+
# FM_TEST_GIT_HAS_ORIGIN_MAIN 1 (default) or 0
|
|
184
|
+
# FM_TEST_GIT_HAS_MAIN 1 (default) or 0
|
|
185
|
+
# FM_TEST_GIT_MERGE_BASE_OK 1 (default) or 0
|
|
186
|
+
# FM_TEST_GIT_MERGE_BASE merge-base value to print when OK
|
|
187
|
+
# FM_TEST_GIT_DIFF_FILE path to a file of NUL-separated changed paths
|
|
188
|
+
fm_lint_stub_git() {
|
|
189
|
+
local fakebin=$1
|
|
190
|
+
cat > "$fakebin/git" <<'SH'
|
|
191
|
+
#!/usr/bin/env bash
|
|
192
|
+
case "$*" in
|
|
193
|
+
"rev-parse --is-inside-work-tree")
|
|
194
|
+
[ "${FM_TEST_GIT_INSIDE_WORKTREE:-1}" = 1 ] || exit 1
|
|
195
|
+
printf 'true\n'
|
|
196
|
+
exit 0
|
|
197
|
+
;;
|
|
198
|
+
"rev-parse --abbrev-ref HEAD")
|
|
199
|
+
printf '%s\n' "${FM_TEST_GIT_BRANCH:-feature}"
|
|
200
|
+
exit 0
|
|
201
|
+
;;
|
|
202
|
+
"rev-parse --verify -q origin/main")
|
|
203
|
+
[ "${FM_TEST_GIT_HAS_ORIGIN_MAIN:-1}" = 1 ] && exit 0 || exit 1
|
|
204
|
+
;;
|
|
205
|
+
"rev-parse --verify -q main")
|
|
206
|
+
[ "${FM_TEST_GIT_HAS_MAIN:-1}" = 1 ] && exit 0 || exit 1
|
|
207
|
+
;;
|
|
208
|
+
"merge-base "*)
|
|
209
|
+
if [ "${FM_TEST_GIT_MERGE_BASE_OK:-1}" = 1 ]; then
|
|
210
|
+
printf '%s\n' "${FM_TEST_GIT_MERGE_BASE:-fakebase123}"
|
|
211
|
+
exit 0
|
|
212
|
+
fi
|
|
213
|
+
exit 1
|
|
214
|
+
;;
|
|
215
|
+
"diff --name-only --diff-filter=ACMR -z "*)
|
|
216
|
+
if [ -n "${FM_TEST_GIT_DIFF_FILE:-}" ] && [ -f "$FM_TEST_GIT_DIFF_FILE" ]; then
|
|
217
|
+
cat "$FM_TEST_GIT_DIFF_FILE"
|
|
218
|
+
fi
|
|
219
|
+
exit 0
|
|
220
|
+
;;
|
|
221
|
+
*)
|
|
222
|
+
exit 1
|
|
223
|
+
;;
|
|
224
|
+
esac
|
|
225
|
+
SH
|
|
226
|
+
chmod +x "$fakebin/git"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
# fm_lint_write_diff_file <file> <path>...: writes NUL-separated changed paths
|
|
230
|
+
# in the shape `git diff --name-only -z` produces, for FM_TEST_GIT_DIFF_FILE.
|
|
231
|
+
fm_lint_write_diff_file() {
|
|
232
|
+
local file=$1
|
|
233
|
+
shift
|
|
234
|
+
printf '%s\0' "$@" > "$file"
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
# fm_lint_stub_shellcheck <fakebin-dir> <log-file>: install a ShellCheck stub
|
|
238
|
+
# that answers --version with the pinned version and otherwise logs the file
|
|
239
|
+
# roots it was asked to check (one per line) instead of actually analyzing
|
|
240
|
+
# them, so changed-file mode tests can assert exactly which files fm-lint.sh
|
|
241
|
+
# selected without depending on real ShellCheck findings. When
|
|
242
|
+
# FM_TEST_MODE_LOG is set, it records the effective analysis mode, treating
|
|
243
|
+
# ShellCheck's default as full analysis.
|
|
244
|
+
fm_lint_stub_shellcheck() {
|
|
245
|
+
local fakebin=$1 log=$2
|
|
246
|
+
: > "$log"
|
|
247
|
+
cat > "$fakebin/shellcheck" <<SH
|
|
248
|
+
#!/usr/bin/env bash
|
|
249
|
+
if [ "\${1:-}" = --version ]; then
|
|
250
|
+
printf 'ShellCheck - shell script analysis tool\nversion: 0.11.0\n'
|
|
251
|
+
exit 0
|
|
252
|
+
fi
|
|
253
|
+
mode=on
|
|
254
|
+
while [ "\$#" -gt 0 ] && [ "\$1" != -- ]; do
|
|
255
|
+
[ "\$1" = --extended-analysis=false ] && mode=off
|
|
256
|
+
shift
|
|
257
|
+
done
|
|
258
|
+
if [ -n "\${FM_TEST_MODE_LOG:-}" ]; then
|
|
259
|
+
printf '%s\n' "\$mode" >> "\$FM_TEST_MODE_LOG"
|
|
260
|
+
fi
|
|
261
|
+
[ "\$#" -eq 0 ] || shift
|
|
262
|
+
printf '%s\n' "\$@" >> "$log"
|
|
263
|
+
exit 0
|
|
264
|
+
SH
|
|
265
|
+
chmod +x "$fakebin/shellcheck"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
test_fast_mode_disables_extended_analysis() {
|
|
269
|
+
local tmp fakebin log mode_log telemetry fixture out
|
|
270
|
+
tmp=$(fm_test_tmproot fm-lint-fast-mode)
|
|
271
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
272
|
+
fixture="$tmp/fixture.sh"
|
|
273
|
+
log="$tmp/shellcheck.log"
|
|
274
|
+
mode_log="$tmp/mode.log"
|
|
275
|
+
telemetry="$tmp/telemetry.tsv"
|
|
276
|
+
cat > "$fixture" <<'SH'
|
|
277
|
+
#!/usr/bin/env bash
|
|
278
|
+
printf '%s\n' "${1:-ok}"
|
|
279
|
+
SH
|
|
280
|
+
chmod +x "$fixture"
|
|
281
|
+
fm_lint_stub_shellcheck "$fakebin" "$log"
|
|
282
|
+
|
|
283
|
+
out=$(PATH="$fakebin:$PATH" GITHUB_ACTIONS='' CI='' FM_LINT_JOBS=1 \
|
|
284
|
+
FM_TEST_MODE_LOG="$mode_log" "$LINT" --fast --telemetry "$telemetry" "$fixture" 2>&1) \
|
|
285
|
+
|| fail "fast lint mode failed"$'\n'"$out"
|
|
286
|
+
[ "$(cat "$mode_log")" = off ] \
|
|
287
|
+
|| fail "fast lint mode did not disable extended analysis"
|
|
288
|
+
[ "$(cat "$log")" = "$fixture" ] \
|
|
289
|
+
|| fail "fast lint mode did not lint the requested root"
|
|
290
|
+
assert_grep $'analysis_mode\tfast' "$telemetry" "telemetry did not record fast analysis mode"
|
|
291
|
+
pass "fm-lint.sh --fast disables ShellCheck extended analysis"
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
test_ci_defaults_to_full_analysis() {
|
|
295
|
+
local tmp fakebin log mode_log fixture out
|
|
296
|
+
tmp=$(fm_test_tmproot fm-lint-ci-analysis)
|
|
297
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
298
|
+
fixture="$tmp/fixture.sh"
|
|
299
|
+
log="$tmp/shellcheck.log"
|
|
300
|
+
mode_log="$tmp/mode.log"
|
|
301
|
+
cat > "$fixture" <<'SH'
|
|
302
|
+
#!/usr/bin/env bash
|
|
303
|
+
printf '%s\n' "${1:-ok}"
|
|
304
|
+
SH
|
|
305
|
+
chmod +x "$fixture"
|
|
306
|
+
fm_lint_stub_shellcheck "$fakebin" "$log"
|
|
307
|
+
|
|
308
|
+
out=$(PATH="$fakebin:$PATH" CI=true GITHUB_ACTIONS=true FM_LINT_FAST=1 FM_LINT_JOBS=1 \
|
|
309
|
+
FM_TEST_MODE_LOG="$mode_log" "$LINT" "$fixture" 2>&1) \
|
|
310
|
+
|| fail "CI full lint mode failed"$'\n'"$out"
|
|
311
|
+
[ "$(cat "$mode_log")" = on ] \
|
|
312
|
+
|| fail "CI default did not keep full ShellCheck analysis"
|
|
313
|
+
pass "fm-lint.sh keeps full ShellCheck analysis by default in CI"
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
test_ci_rejects_explicit_fast_mode() {
|
|
317
|
+
local tmp fakebin log fixture out rc
|
|
318
|
+
tmp=$(fm_test_tmproot fm-lint-ci-reject-fast)
|
|
319
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
320
|
+
fixture="$tmp/fixture.sh"
|
|
321
|
+
log="$tmp/shellcheck.log"
|
|
322
|
+
cat > "$fixture" <<'SH'
|
|
323
|
+
#!/usr/bin/env bash
|
|
324
|
+
printf '%s\n' "${1:-ok}"
|
|
325
|
+
SH
|
|
326
|
+
chmod +x "$fixture"
|
|
327
|
+
fm_lint_stub_shellcheck "$fakebin" "$log"
|
|
328
|
+
|
|
329
|
+
rc=0
|
|
330
|
+
out=$(PATH="$fakebin:$PATH" CI=true GITHUB_ACTIONS=true FM_LINT_JOBS=1 \
|
|
331
|
+
"$LINT" --fast "$fixture" 2>&1) || rc=$?
|
|
332
|
+
[ "$rc" -eq 2 ] \
|
|
333
|
+
|| fail "CI accepted explicit fast lint mode (exit $rc)"$'\n'"$out"
|
|
334
|
+
assert_contains "$out" "--fast is local-only" \
|
|
335
|
+
"CI fast-mode rejection did not explain the policy"
|
|
336
|
+
[ ! -s "$log" ] || fail "CI invoked ShellCheck after rejecting fast mode"
|
|
337
|
+
pass "fm-lint.sh rejects explicit --fast mode in CI"
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
test_fast_mode_catches_a_real_lint_defect() {
|
|
341
|
+
if ! pinned_ready; then
|
|
342
|
+
pass "SKIP (ShellCheck $REQUIRED not resolved): fast lint-defect regression check"
|
|
343
|
+
return
|
|
344
|
+
fi
|
|
345
|
+
local tmp bad out rc
|
|
346
|
+
tmp=$(fm_test_tmproot fm-lint-fast-bad)
|
|
347
|
+
bad="$tmp/bad.sh"
|
|
348
|
+
cat > "$bad" <<'SH'
|
|
349
|
+
#!/usr/bin/env bash
|
|
350
|
+
foo() {
|
|
351
|
+
local a= b=
|
|
352
|
+
echo "$a$b"
|
|
353
|
+
}
|
|
354
|
+
foo
|
|
355
|
+
SH
|
|
356
|
+
rc=0
|
|
357
|
+
out=$(GITHUB_ACTIONS='' CI='' "$LINT" --fast "$bad" 2>&1) || rc=$?
|
|
358
|
+
[ "$rc" -ne 0 ] || fail "fast lint mode passed a known-bad fixture"$'\n'"$out"
|
|
359
|
+
assert_contains "$out" "SC1007" "fast lint mode did not report the expected ShellCheck finding"
|
|
360
|
+
pass "fm-lint.sh --fast catches an ordinary shell lint defect"
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
test_changed_mode_lints_only_the_changed_file() {
|
|
364
|
+
local tmp fakebin log diff_file out target
|
|
365
|
+
tmp=$(fm_test_tmproot fm-lint-changed)
|
|
366
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
367
|
+
fm_lint_stub_git "$fakebin"
|
|
368
|
+
log="$tmp/shellcheck.log"
|
|
369
|
+
fm_lint_stub_shellcheck "$fakebin" "$log"
|
|
370
|
+
diff_file="$tmp/diff.nul"
|
|
371
|
+
target="bin/fm-install-shellcheck.sh"
|
|
372
|
+
fm_lint_write_diff_file "$diff_file" "$target" "README.md"
|
|
373
|
+
|
|
374
|
+
# Clear the ambient CI/GITHUB_ACTIONS signals so changed-file mode is actually
|
|
375
|
+
# exercised: a CI run sets them and would otherwise force the full lint here.
|
|
376
|
+
out=$(PATH="$fakebin:$PATH" GITHUB_ACTIONS='' CI='' FM_LINT_JOBS=1 \
|
|
377
|
+
FM_TEST_GIT_BRANCH=feature \
|
|
378
|
+
FM_TEST_GIT_DIFF_FILE="$diff_file" "$LINT" 2>&1) \
|
|
379
|
+
|| fail "changed-mode lint run failed"$'\n'"$out"
|
|
380
|
+
[ "$(cat "$log")" = "$target" ] \
|
|
381
|
+
|| fail "changed-mode lint did not run ShellCheck on exactly the changed file"$'\n'"logged: $(cat "$log")"
|
|
382
|
+
pass "fm-lint.sh changed mode lints only the changed canonical file"
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
test_ci_forces_full_lint_even_with_empty_diff() {
|
|
386
|
+
local listed expected
|
|
387
|
+
# No git stub: CI=true must short-circuit fm-lint.sh's mode selection before
|
|
388
|
+
# it ever consults git, so this proves CI wins regardless of local diff state.
|
|
389
|
+
listed=$(CI=true "$LINT" --list-files)
|
|
390
|
+
expected=$(find bin bin/backends tests -maxdepth 1 -type f -name '*.sh' -print | LC_ALL=C sort)
|
|
391
|
+
[ "$(printf '%s\n' "$listed" | LC_ALL=C sort)" = "$expected" ] \
|
|
392
|
+
|| fail "CI=true did not force the full canonical file set"
|
|
393
|
+
pass "fm-lint.sh forces a full lint in CI even when the local diff would be empty"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
test_main_branch_forces_full_lint() {
|
|
397
|
+
local tmp fakebin listed expected
|
|
398
|
+
tmp=$(fm_test_tmproot fm-lint-main-full)
|
|
399
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
400
|
+
fm_lint_stub_git "$fakebin"
|
|
401
|
+
|
|
402
|
+
# Clear CI/GITHUB_ACTIONS so the on-main branch is what forces the full lint,
|
|
403
|
+
# not the ambient CI signal a real CI run would otherwise supply.
|
|
404
|
+
listed=$(PATH="$fakebin:$PATH" GITHUB_ACTIONS='' CI='' \
|
|
405
|
+
FM_TEST_GIT_BRANCH=main "$LINT" --list-files)
|
|
406
|
+
expected=$(find bin bin/backends tests -maxdepth 1 -type f -name '*.sh' -print | LC_ALL=C sort)
|
|
407
|
+
[ "$(printf '%s\n' "$listed" | LC_ALL=C sort)" = "$expected" ] \
|
|
408
|
+
|| fail "fm-lint.sh did not force a full lint when HEAD is on main"
|
|
409
|
+
pass "fm-lint.sh forces a full lint when HEAD is on main"
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
test_explicit_path_bypasses_changed_logic() {
|
|
413
|
+
local tmp fakebin log out target
|
|
414
|
+
tmp=$(fm_test_tmproot fm-lint-explicit-override)
|
|
415
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
416
|
+
fm_lint_stub_git "$fakebin"
|
|
417
|
+
log="$tmp/shellcheck.log"
|
|
418
|
+
fm_lint_stub_shellcheck "$fakebin" "$log"
|
|
419
|
+
target="bin/fm-install-shellcheck.sh"
|
|
420
|
+
|
|
421
|
+
# The git stub reports a broken merge-base, which would force a full lint
|
|
422
|
+
# under the no-args default. Clearing CI/GITHUB_ACTIONS keeps changed-file
|
|
423
|
+
# selection live so this proves the explicit path bypasses it, not that CI
|
|
424
|
+
# already forced full mode. An explicit path must never even consult git.
|
|
425
|
+
out=$(PATH="$fakebin:$PATH" GITHUB_ACTIONS='' CI='' FM_LINT_JOBS=1 \
|
|
426
|
+
FM_TEST_GIT_MERGE_BASE_OK=0 \
|
|
427
|
+
"$LINT" "$target" 2>&1) || fail "explicit-path lint failed"$'\n'"$out"
|
|
428
|
+
[ "$(cat "$log")" = "$target" ] \
|
|
429
|
+
|| fail "explicit path lint did not run on exactly the requested file"$'\n'"logged: $(cat "$log")"
|
|
430
|
+
pass "fm-lint.sh explicit paths bypass changed-file mode selection"
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
test_zero_changed_files_exits_clean() {
|
|
434
|
+
local tmp fakebin diff_file out rc
|
|
435
|
+
tmp=$(fm_test_tmproot fm-lint-zero-changed)
|
|
436
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
437
|
+
fm_lint_stub_git "$fakebin"
|
|
438
|
+
diff_file="$tmp/diff.nul"
|
|
439
|
+
: > "$diff_file"
|
|
440
|
+
|
|
441
|
+
rc=0
|
|
442
|
+
# Clear CI/GITHUB_ACTIONS so changed-file mode runs and can reach the empty
|
|
443
|
+
# target set; a CI run would otherwise force a full lint instead.
|
|
444
|
+
out=$(PATH="$fakebin:$PATH" GITHUB_ACTIONS='' CI='' FM_TEST_GIT_BRANCH=feature \
|
|
445
|
+
FM_TEST_GIT_DIFF_FILE="$diff_file" "$LINT" 2>&1) || rc=$?
|
|
446
|
+
[ "$rc" -eq 0 ] || fail "zero changed lint targets must exit 0, got $rc"$'\n'"$out"
|
|
447
|
+
assert_contains "$out" "ShellCheck 0.11.0" "zero-changed run did not print the ShellCheck version line"
|
|
448
|
+
assert_contains "$out" "no changed lint targets" "zero-changed run did not note the empty target set"
|
|
449
|
+
assert_contains "$out" "workflow files valid" \
|
|
450
|
+
"zero-changed run skipped workflow YAML validation"
|
|
451
|
+
pass "fm-lint.sh exits 0 with a note when the local branch has no changed lint targets"
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
test_list_files_respects_changed_mode() {
|
|
455
|
+
local tmp fakebin diff_file listed
|
|
456
|
+
tmp=$(fm_test_tmproot fm-lint-list-changed)
|
|
457
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
458
|
+
fm_lint_stub_git "$fakebin"
|
|
459
|
+
diff_file="$tmp/diff.nul"
|
|
460
|
+
# A real canonical file, a non-canonical file, and a canonical-looking path
|
|
461
|
+
# that does not exist: only the first should survive into the listed set.
|
|
462
|
+
fm_lint_write_diff_file "$diff_file" \
|
|
463
|
+
"tests/fm-lint.test.sh" "docs/README.md" "bin/definitely-not-real-file.sh"
|
|
464
|
+
|
|
465
|
+
# Clear CI/GITHUB_ACTIONS so --list-files reflects the changed set rather than
|
|
466
|
+
# the full canonical set a CI run's ambient signals would otherwise force.
|
|
467
|
+
listed=$(PATH="$fakebin:$PATH" GITHUB_ACTIONS='' CI='' FM_TEST_GIT_BRANCH=feature \
|
|
468
|
+
FM_TEST_GIT_DIFF_FILE="$diff_file" "$LINT" --list-files)
|
|
469
|
+
[ "$listed" = "tests/fm-lint.test.sh" ] \
|
|
470
|
+
|| fail "--list-files did not report the would-be changed set in changed mode"$'\n'"got: $listed"
|
|
471
|
+
pass "fm-lint.sh --list-files reports the would-be changed set in changed mode"
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
test_pins_an_explicit_version() {
|
|
475
|
+
[ -n "$REQUIRED" ] || fail "fm-lint.sh --required-version printed nothing"
|
|
476
|
+
# The captain-agreed pin: adopt ShellCheck 0.11.0's rule set consistently,
|
|
477
|
+
# which is also what drops the upstream-retired, false-positive-prone SC2015.
|
|
478
|
+
assert_contains "$REQUIRED" "0.11.0" "fm-lint.sh must pin ShellCheck 0.11.0"
|
|
479
|
+
pass "fm-lint.sh pins an explicit ShellCheck version ($REQUIRED)"
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
test_installer_retries_transient_download_failure() {
|
|
483
|
+
local tmp fakebin destination out
|
|
484
|
+
tmp=$(fm_test_tmproot fm-shellcheck-download)
|
|
485
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
486
|
+
destination="$tmp/bin"
|
|
487
|
+
|
|
488
|
+
fm_install_stub_uname "$fakebin"
|
|
489
|
+
fm_install_stub_curl "$fakebin"
|
|
490
|
+
fm_install_stub_hasher "$fakebin" sha256sum
|
|
491
|
+
fm_install_stub_tar_shellcheck "$fakebin"
|
|
492
|
+
fm_install_stub_sleep "$fakebin"
|
|
493
|
+
|
|
494
|
+
# Reproduce the CI incident: the release endpoint returned 503 for all three
|
|
495
|
+
# formerly configured attempts before recovering. Force linux/x86_64 so the
|
|
496
|
+
# retry path stays the CI archive even when this suite runs on macOS.
|
|
497
|
+
out=$(CURL_COUNT="$tmp/curl-count" CURL_FAIL_UNTIL=3 \
|
|
498
|
+
SHA256_STUB_HASH="$SHELLCHECK_SHA_LINUX_X86_64" \
|
|
499
|
+
FM_TEST_UNAME_S=Linux FM_TEST_UNAME_M=x86_64 \
|
|
500
|
+
PATH="$fakebin:$PATH" "$INSTALLER" "$destination" 2>&1) \
|
|
501
|
+
|| fail "installer did not recover from a transient download failure"$'\n'"$out"
|
|
502
|
+
[ "$(cat "$tmp/curl-count")" -eq 4 ] || fail "installer did not recover after three failed downloads"
|
|
503
|
+
assert_contains "$out" "download attempt 3 failed; retrying" "installer did not disclose its third retry"
|
|
504
|
+
[ -x "$destination/shellcheck" ] || fail "installer did not install ShellCheck after retrying"
|
|
505
|
+
pass "ShellCheck installer retries a transient download failure"
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
test_installer_selects_platform_archive_url_and_checksum() {
|
|
509
|
+
local tmp fakebin destination out url_log uname_s uname_m archive sha
|
|
510
|
+
tmp=$(fm_test_tmproot fm-shellcheck-platform)
|
|
511
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
512
|
+
destination="$tmp/bin"
|
|
513
|
+
url_log="$tmp/curl-url.log"
|
|
514
|
+
|
|
515
|
+
fm_install_stub_uname "$fakebin"
|
|
516
|
+
fm_install_stub_curl "$fakebin"
|
|
517
|
+
fm_install_stub_hasher "$fakebin" sha256sum
|
|
518
|
+
fm_install_stub_tar_shellcheck "$fakebin"
|
|
519
|
+
fm_install_stub_sleep "$fakebin"
|
|
520
|
+
|
|
521
|
+
while IFS=$'\t' read -r uname_s uname_m archive sha; do
|
|
522
|
+
[ -n "$uname_s" ] || continue
|
|
523
|
+
rm -rf "$destination"
|
|
524
|
+
: > "$url_log"
|
|
525
|
+
out=$(CURL_URL_LOG="$url_log" SHA256_STUB_HASH="$sha" \
|
|
526
|
+
FM_TEST_UNAME_S="$uname_s" FM_TEST_UNAME_M="$uname_m" \
|
|
527
|
+
PATH="$fakebin:$PATH" "$INSTALLER" "$destination" 2>&1) \
|
|
528
|
+
|| fail "installer failed for ${uname_s}/${uname_m}"$'\n'"$out"
|
|
529
|
+
assert_contains "$(cat "$url_log")" "$archive" \
|
|
530
|
+
"installer did not download $archive for ${uname_s}/${uname_m}"
|
|
531
|
+
assert_contains "$(cat "$url_log")" \
|
|
532
|
+
"https://github.com/koalaman/shellcheck/releases/download/v${REQUIRED}/${archive}" \
|
|
533
|
+
"installer used the wrong URL for ${uname_s}/${uname_m}"
|
|
534
|
+
[ -x "$destination/shellcheck" ] || fail "installer did not install ShellCheck for ${uname_s}/${uname_m}"
|
|
535
|
+
done <<EOF
|
|
536
|
+
Linux x86_64 shellcheck-v${REQUIRED}.linux.x86_64.tar.xz $SHELLCHECK_SHA_LINUX_X86_64
|
|
537
|
+
Linux amd64 shellcheck-v${REQUIRED}.linux.x86_64.tar.xz $SHELLCHECK_SHA_LINUX_X86_64
|
|
538
|
+
Linux aarch64 shellcheck-v${REQUIRED}.linux.aarch64.tar.xz $SHELLCHECK_SHA_LINUX_AARCH64
|
|
539
|
+
Linux arm64 shellcheck-v${REQUIRED}.linux.aarch64.tar.xz $SHELLCHECK_SHA_LINUX_AARCH64
|
|
540
|
+
Darwin x86_64 shellcheck-v${REQUIRED}.darwin.x86_64.tar.xz $SHELLCHECK_SHA_DARWIN_X86_64
|
|
541
|
+
Darwin amd64 shellcheck-v${REQUIRED}.darwin.x86_64.tar.xz $SHELLCHECK_SHA_DARWIN_X86_64
|
|
542
|
+
Darwin arm64 shellcheck-v${REQUIRED}.darwin.aarch64.tar.xz $SHELLCHECK_SHA_DARWIN_AARCH64
|
|
543
|
+
Darwin aarch64 shellcheck-v${REQUIRED}.darwin.aarch64.tar.xz $SHELLCHECK_SHA_DARWIN_AARCH64
|
|
544
|
+
EOF
|
|
545
|
+
pass "ShellCheck installer selects the official archive, URL, and checksum per OS/arch"
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
test_installer_rejects_wrong_checksum() {
|
|
549
|
+
local tmp fakebin destination out rc
|
|
550
|
+
tmp=$(fm_test_tmproot fm-shellcheck-badsum)
|
|
551
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
552
|
+
destination="$tmp/bin"
|
|
553
|
+
|
|
554
|
+
fm_install_stub_uname "$fakebin"
|
|
555
|
+
fm_install_stub_curl "$fakebin"
|
|
556
|
+
fm_install_stub_hasher "$fakebin" sha256sum
|
|
557
|
+
fm_install_stub_tar_shellcheck "$fakebin"
|
|
558
|
+
fm_install_stub_sleep "$fakebin"
|
|
559
|
+
|
|
560
|
+
rc=0
|
|
561
|
+
out=$(SHA256_STUB_HASH=0000000000000000000000000000000000000000000000000000000000000000 \
|
|
562
|
+
FM_TEST_UNAME_S=Linux FM_TEST_UNAME_M=x86_64 \
|
|
563
|
+
PATH="$fakebin:$PATH" "$INSTALLER" "$destination" 2>&1) || rc=$?
|
|
564
|
+
[ "$rc" -ne 0 ] || fail "installer accepted a wrong checksum"$'\n'"$out"
|
|
565
|
+
assert_contains "$out" "checksum mismatch" "installer did not report a checksum mismatch"
|
|
566
|
+
assert_contains "$out" "shellcheck-v${REQUIRED}.linux.x86_64.tar.xz" \
|
|
567
|
+
"mismatch did not name the selected archive"
|
|
568
|
+
assert_contains "$out" "$SHELLCHECK_SHA_LINUX_X86_64" \
|
|
569
|
+
"mismatch did not name the pinned linux/x86_64 checksum"
|
|
570
|
+
[ ! -e "$destination/shellcheck" ] || fail "installer installed ShellCheck after a checksum mismatch"
|
|
571
|
+
pass "ShellCheck installer rejects a wrong checksum"
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
test_installer_falls_back_to_shasum() {
|
|
575
|
+
local tmp fakebin destination out hasher_log tool
|
|
576
|
+
tmp=$(fm_test_tmproot fm-shellcheck-shasum)
|
|
577
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
578
|
+
destination="$tmp/bin"
|
|
579
|
+
hasher_log="$tmp/hasher.log"
|
|
580
|
+
|
|
581
|
+
for tool in bash dirname mktemp rm awk mkdir install cat chmod; do
|
|
582
|
+
ln -s "$(command -v "$tool")" "$fakebin/$tool"
|
|
583
|
+
done
|
|
584
|
+
fm_install_stub_uname "$fakebin"
|
|
585
|
+
fm_install_stub_curl "$fakebin"
|
|
586
|
+
fm_install_stub_hasher "$fakebin" shasum
|
|
587
|
+
fm_install_stub_tar_shellcheck "$fakebin"
|
|
588
|
+
fm_install_stub_sleep "$fakebin"
|
|
589
|
+
|
|
590
|
+
# Restricted PATH: shasum is present, sha256sum is not.
|
|
591
|
+
: > "$hasher_log"
|
|
592
|
+
out=$(CURL_URL_LOG="$tmp/curl-url.log" HASHER_LOG="$hasher_log" \
|
|
593
|
+
SHA256_STUB_HASH="$SHELLCHECK_SHA_LINUX_X86_64" \
|
|
594
|
+
FM_TEST_UNAME_S=Linux FM_TEST_UNAME_M=x86_64 \
|
|
595
|
+
PATH="$fakebin" "$INSTALLER" "$destination" 2>&1) \
|
|
596
|
+
|| fail "installer did not fall back to shasum -a 256"$'\n'"$out"
|
|
597
|
+
assert_grep 'shasum -a 256' "$hasher_log" "installer did not invoke shasum -a 256"
|
|
598
|
+
[ -x "$destination/shellcheck" ] || fail "installer did not install ShellCheck via shasum"
|
|
599
|
+
pass "ShellCheck installer falls back to shasum -a 256 when sha256sum is absent"
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
test_installer_prefers_sha256sum_over_shasum() {
|
|
603
|
+
local tmp fakebin destination hasher_log
|
|
604
|
+
tmp=$(fm_test_tmproot fm-shellcheck-sha256sum-pref)
|
|
605
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
606
|
+
destination="$tmp/bin"
|
|
607
|
+
hasher_log="$tmp/hasher.log"
|
|
608
|
+
|
|
609
|
+
fm_install_stub_uname "$fakebin"
|
|
610
|
+
fm_install_stub_curl "$fakebin"
|
|
611
|
+
fm_install_stub_hasher "$fakebin" sha256sum
|
|
612
|
+
fm_install_stub_hasher "$fakebin" shasum
|
|
613
|
+
fm_install_stub_tar_shellcheck "$fakebin"
|
|
614
|
+
fm_install_stub_sleep "$fakebin"
|
|
615
|
+
|
|
616
|
+
: > "$hasher_log"
|
|
617
|
+
PATH="$fakebin:$PATH" HASHER_LOG="$hasher_log" \
|
|
618
|
+
SHA256_STUB_HASH="$SHELLCHECK_SHA_LINUX_X86_64" \
|
|
619
|
+
FM_TEST_UNAME_S=Linux FM_TEST_UNAME_M=x86_64 \
|
|
620
|
+
"$INSTALLER" "$destination" >/dev/null \
|
|
621
|
+
|| fail "installer failed when both hashers were present"
|
|
622
|
+
assert_grep 'sha256sum' "$hasher_log" "installer did not prefer sha256sum"
|
|
623
|
+
if grep -q 'shasum' "$hasher_log"; then
|
|
624
|
+
fail "installer invoked shasum even though sha256sum was present"$'\n'"$(cat "$hasher_log")"
|
|
625
|
+
fi
|
|
626
|
+
pass "ShellCheck installer prefers sha256sum when both hashers are present"
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
test_installer_rejects_unsupported_platform() {
|
|
630
|
+
local tmp fakebin destination out rc
|
|
631
|
+
tmp=$(fm_test_tmproot fm-shellcheck-unsupported)
|
|
632
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
633
|
+
destination="$tmp/bin"
|
|
634
|
+
|
|
635
|
+
fm_install_stub_uname "$fakebin"
|
|
636
|
+
fm_install_stub_curl "$fakebin"
|
|
637
|
+
|
|
638
|
+
rc=0
|
|
639
|
+
out=$(FM_TEST_UNAME_S=FreeBSD FM_TEST_UNAME_M=amd64 \
|
|
640
|
+
PATH="$fakebin:$PATH" "$INSTALLER" "$destination" 2>&1) || rc=$?
|
|
641
|
+
[ "$rc" -ne 0 ] || fail "installer accepted an unsupported OS"$'\n'"$out"
|
|
642
|
+
assert_contains "$out" "unsupported platform" "installer did not name the unsupported platform"
|
|
643
|
+
assert_contains "$out" "FreeBSD-amd64" "installer did not report the detected OS/arch"
|
|
644
|
+
|
|
645
|
+
rc=0
|
|
646
|
+
out=$(FM_TEST_UNAME_S=Linux FM_TEST_UNAME_M=ppc64le \
|
|
647
|
+
PATH="$fakebin:$PATH" "$INSTALLER" "$destination" 2>&1) || rc=$?
|
|
648
|
+
[ "$rc" -ne 0 ] || fail "installer accepted an unsupported architecture"$'\n'"$out"
|
|
649
|
+
assert_contains "$out" "unsupported platform" "installer did not reject linux/ppc64le"
|
|
650
|
+
pass "ShellCheck installer rejects an unsupported OS or architecture"
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
test_missing_shellcheck_fails_closed() {
|
|
654
|
+
local tmp fakebin out rc tool
|
|
655
|
+
tmp=$(fm_test_tmproot fm-lint-noshellcheck)
|
|
656
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
657
|
+
for tool in bash dirname; do
|
|
658
|
+
ln -s "$(command -v "$tool")" "$fakebin/$tool"
|
|
659
|
+
done
|
|
660
|
+
rc=0
|
|
661
|
+
out=$(PATH="$fakebin" CI=true GITHUB_ACTIONS=true "$LINT" 2>&1) || rc=$?
|
|
662
|
+
[ "$rc" -eq 1 ] || fail "missing ShellCheck expected exit 1, got $rc"$'\n'"$out"
|
|
663
|
+
assert_contains "$out" "ShellCheck not found" \
|
|
664
|
+
"missing ShellCheck did not name the required linter"
|
|
665
|
+
assert_contains "$out" "$REQUIRED" \
|
|
666
|
+
"missing ShellCheck did not name the pinned version"
|
|
667
|
+
assert_contains "$out" "fm-install-shellcheck.sh" \
|
|
668
|
+
"missing ShellCheck did not name the pinned installer"
|
|
669
|
+
pass "missing ShellCheck fails closed"
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
test_rejects_wrong_shellcheck_version() {
|
|
673
|
+
# Version-independent: a fake shellcheck reporting a different version must be
|
|
674
|
+
# refused before any lint, proving local and CI cannot silently diverge.
|
|
675
|
+
local tmp fakebin out rc
|
|
676
|
+
tmp=$(fm_test_tmproot fm-lint-ver)
|
|
677
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
678
|
+
cat > "$fakebin/shellcheck" <<'SH'
|
|
679
|
+
#!/usr/bin/env bash
|
|
680
|
+
if [ "$1" = "--version" ]; then
|
|
681
|
+
printf 'ShellCheck - shell script analysis tool\nversion: 0.9.9\nlicense: x\nwebsite: y\n'
|
|
682
|
+
exit 0
|
|
683
|
+
fi
|
|
684
|
+
exit 0
|
|
685
|
+
SH
|
|
686
|
+
chmod +x "$fakebin/shellcheck"
|
|
687
|
+
rc=0
|
|
688
|
+
out=$(PATH="$fakebin:$PATH" "$LINT" 2>&1) || rc=$?
|
|
689
|
+
[ "$rc" -ne 0 ] || fail "fm-lint.sh accepted a shellcheck version other than the pin"$'\n'"$out"
|
|
690
|
+
assert_contains "$out" "$REQUIRED" "fm-lint.sh did not name the required version on mismatch"
|
|
691
|
+
assert_contains "$out" "0.9.9" "fm-lint.sh did not report the resolved (wrong) version"
|
|
692
|
+
pass "fm-lint.sh refuses to lint under a non-pinned ShellCheck version"
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
test_catches_a_real_lint_defect() {
|
|
696
|
+
if ! pinned_ready; then
|
|
697
|
+
pass "SKIP (ShellCheck $REQUIRED not resolved): lint-defect regression check"
|
|
698
|
+
return
|
|
699
|
+
fi
|
|
700
|
+
# A script with a genuine ShellCheck finding must make the one owner exit
|
|
701
|
+
# non-zero, proving local now runs real shellcheck instead of the old no-op
|
|
702
|
+
# lint step. We deliberately do NOT assert SC2015 (PR 475's actual failure):
|
|
703
|
+
# ShellCheck removed SC2015 in the pinned 0.11.0, so asserting it would make
|
|
704
|
+
# this test itself version-fragile - the very trap being fixed. SC1007 is a
|
|
705
|
+
# warning present at default severity (and is itself one of the recurring
|
|
706
|
+
# classes that slipped through, PR 474).
|
|
707
|
+
local tmp bad out rc
|
|
708
|
+
tmp=$(fm_test_tmproot fm-lint-bad)
|
|
709
|
+
mkdir -p "$tmp"
|
|
710
|
+
bad="$tmp/bad.sh"
|
|
711
|
+
cat > "$bad" <<'SH'
|
|
712
|
+
#!/usr/bin/env bash
|
|
713
|
+
foo() {
|
|
714
|
+
local a= b=
|
|
715
|
+
echo "$a$b"
|
|
716
|
+
}
|
|
717
|
+
foo
|
|
718
|
+
SH
|
|
719
|
+
rc=0
|
|
720
|
+
out=$("$LINT" "$bad" 2>&1) || rc=$?
|
|
721
|
+
[ "$rc" -ne 0 ] || fail "fm-lint.sh passed a known-bad fixture"$'\n'"$out"
|
|
722
|
+
assert_contains "$out" "SC1007" "fm-lint.sh did not report the expected ShellCheck finding"
|
|
723
|
+
pass "fm-lint.sh catches a real lint defect the old no-op gate passed"
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
test_ignores_ambient_shellcheck_opts() {
|
|
727
|
+
if ! pinned_ready; then
|
|
728
|
+
pass "SKIP (ShellCheck $REQUIRED not resolved): ambient options regression check"
|
|
729
|
+
return
|
|
730
|
+
fi
|
|
731
|
+
local tmp bad out rc
|
|
732
|
+
tmp=$(fm_test_tmproot fm-lint-opts)
|
|
733
|
+
mkdir -p "$tmp"
|
|
734
|
+
bad="$tmp/bad.sh"
|
|
735
|
+
cat > "$bad" <<'SH'
|
|
736
|
+
#!/usr/bin/env bash
|
|
737
|
+
foo() {
|
|
738
|
+
local a= b=
|
|
739
|
+
echo "$a$b"
|
|
740
|
+
}
|
|
741
|
+
foo
|
|
742
|
+
SH
|
|
743
|
+
rc=0
|
|
744
|
+
out=$(SHELLCHECK_OPTS='--exclude=SC1007' "$LINT" "$bad" 2>&1) || rc=$?
|
|
745
|
+
[ "$rc" -ne 0 ] || fail "fm-lint.sh allowed ambient SHELLCHECK_OPTS to hide a finding"$'\n'"$out"
|
|
746
|
+
assert_contains "$out" "SC1007" "fm-lint.sh did not neutralize ambient SHELLCHECK_OPTS"
|
|
747
|
+
pass "fm-lint.sh ignores ambient ShellCheck options"
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
test_clean_fixture_passes() {
|
|
751
|
+
if ! pinned_ready; then
|
|
752
|
+
pass "SKIP (ShellCheck $REQUIRED not resolved): clean fixture check"
|
|
753
|
+
return
|
|
754
|
+
fi
|
|
755
|
+
local tmp good rc
|
|
756
|
+
tmp=$(fm_test_tmproot fm-lint-good)
|
|
757
|
+
mkdir -p "$tmp"
|
|
758
|
+
good="$tmp/good.sh"
|
|
759
|
+
cat > "$good" <<'SH'
|
|
760
|
+
#!/usr/bin/env bash
|
|
761
|
+
set -eu
|
|
762
|
+
if [ -n "${1:-}" ] && [ -d "$1" ]; then
|
|
763
|
+
printf 'ok\n'
|
|
764
|
+
fi
|
|
765
|
+
SH
|
|
766
|
+
rc=0
|
|
767
|
+
"$LINT" "$good" >/dev/null 2>&1 || rc=$?
|
|
768
|
+
[ "$rc" -eq 0 ] || fail "fm-lint.sh flagged a clean fixture (exit $rc)"
|
|
769
|
+
pass "fm-lint.sh passes a clean fixture"
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
test_jobs_are_deterministic_and_complete() {
|
|
773
|
+
if ! pinned_ready; then
|
|
774
|
+
pass "SKIP (ShellCheck $REQUIRED not resolved): deterministic bounded jobs check"
|
|
775
|
+
return
|
|
776
|
+
fi
|
|
777
|
+
local tmp good bad_a bad_b out_clean_1 out_clean_2 out_fail_1 out_fail_2 out_fail_2b
|
|
778
|
+
local telemetry telemetry_out cleanup_tmp cleanup_out rc_clean_1 rc_clean_2 rc_fail_1 rc_fail_2 rc_fail_2b rc_bad_jobs
|
|
779
|
+
tmp=$(fm_test_tmproot fm-lint-jobs)
|
|
780
|
+
mkdir -p "$tmp"
|
|
781
|
+
good="$tmp/good.sh"
|
|
782
|
+
bad_a="$tmp/bad-a.sh"
|
|
783
|
+
bad_b="$tmp/bad-b.sh"
|
|
784
|
+
telemetry="$tmp/telemetry.tsv"
|
|
785
|
+
cat > "$good" <<'SH'
|
|
786
|
+
#!/usr/bin/env bash
|
|
787
|
+
printf '%s\n' "${1:-ok}"
|
|
788
|
+
SH
|
|
789
|
+
cat > "$bad_a" <<'SH'
|
|
790
|
+
#!/usr/bin/env bash
|
|
791
|
+
bad_a() {
|
|
792
|
+
local a= b=
|
|
793
|
+
printf '%s\n' "$a$b"
|
|
794
|
+
}
|
|
795
|
+
SH
|
|
796
|
+
cat > "$bad_b" <<'SH'
|
|
797
|
+
#!/usr/bin/env bash
|
|
798
|
+
bad_b() {
|
|
799
|
+
printf '%s\n' $1
|
|
800
|
+
}
|
|
801
|
+
SH
|
|
802
|
+
|
|
803
|
+
rc_clean_1=0
|
|
804
|
+
out_clean_1=$(FM_LINT_JOBS=1 "$LINT" "$good" 2>&1) || rc_clean_1=$?
|
|
805
|
+
rc_clean_2=0
|
|
806
|
+
out_clean_2=$(FM_LINT_JOBS=2 "$LINT" "$good" 2>&1) || rc_clean_2=$?
|
|
807
|
+
[ "$rc_clean_1" -eq 0 ] && [ "$rc_clean_2" -eq 0 ] || fail "clean jobs=1/jobs=2 paths must both pass"
|
|
808
|
+
[ "$out_clean_1" = "$out_clean_2" ] || fail "clean jobs=1/jobs=2 output differs"
|
|
809
|
+
|
|
810
|
+
rc_fail_1=0
|
|
811
|
+
out_fail_1=$(FM_LINT_JOBS=1 "$LINT" "$bad_a" "$bad_b" 2>&1) || rc_fail_1=$?
|
|
812
|
+
rc_fail_2=0
|
|
813
|
+
out_fail_2=$(FM_LINT_JOBS=2 "$LINT" "$bad_a" "$bad_b" 2>&1) || rc_fail_2=$?
|
|
814
|
+
rc_fail_2b=0
|
|
815
|
+
out_fail_2b=$(FM_LINT_JOBS=2 "$LINT" "$bad_a" "$bad_b" 2>&1) || rc_fail_2b=$?
|
|
816
|
+
[ "$rc_fail_1" -ne 0 ] && [ "$rc_fail_1" -eq "$rc_fail_2" ] && [ "$rc_fail_2" -eq "$rc_fail_2b" ] \
|
|
817
|
+
|| fail "failing jobs=1/jobs=2 exit results differ: $rc_fail_1/$rc_fail_2/$rc_fail_2b"
|
|
818
|
+
[ "$out_fail_1" = "$out_fail_2" ] && [ "$out_fail_2" = "$out_fail_2b" ] \
|
|
819
|
+
|| fail "failing diagnostics are not byte-identical and deterministic across jobs"
|
|
820
|
+
assert_contains "$out_fail_1" "SC1007" "the first failing root diagnostic was lost"
|
|
821
|
+
assert_contains "$out_fail_1" "SC2086" "the later failing root diagnostic was lost"
|
|
822
|
+
rc_bad_jobs=0
|
|
823
|
+
FM_LINT_JOBS=3 "$LINT" "$good" >/dev/null 2>&1 || rc_bad_jobs=$?
|
|
824
|
+
[ "$rc_bad_jobs" -eq 2 ] || fail "the lint owner must reject unbounded worker counts"
|
|
825
|
+
|
|
826
|
+
telemetry_out=$(FM_LINT_JOBS=2 FM_LINT_TELEMETRY="$telemetry" "$LINT" "$good" 2>&1) \
|
|
827
|
+
|| fail "telemetry-enabled clean lint failed"
|
|
828
|
+
[ "$telemetry_out" = "$out_clean_2" ] || fail "quiet telemetry changed routine lint output"
|
|
829
|
+
assert_grep $'format\tfm-lint-telemetry-v1' "$telemetry" "telemetry format marker is missing"
|
|
830
|
+
assert_grep $'analysis_mode\tfull' "$telemetry" "telemetry did not record full analysis mode"
|
|
831
|
+
assert_grep $'jobs\t2' "$telemetry" "telemetry did not record bounded jobs"
|
|
832
|
+
assert_grep $'root_count\t1' "$telemetry" "telemetry did not record root count"
|
|
833
|
+
assert_grep $'wall_seconds\t' "$telemetry" "telemetry did not record wall time"
|
|
834
|
+
assert_grep $'user_seconds\t' "$telemetry" "telemetry did not record user CPU"
|
|
835
|
+
assert_grep $'system_seconds\t' "$telemetry" "telemetry did not record system CPU"
|
|
836
|
+
assert_grep $'max_worker_rss_kib\t' "$telemetry" "telemetry did not record maximum RSS"
|
|
837
|
+
assert_grep $'source_boundary_directives\t' "$telemetry" "telemetry did not record source-graph boundaries"
|
|
838
|
+
assert_grep $'shellcheck_processes_start\t' "$telemetry" "telemetry did not record competing ShellCheck conditions"
|
|
839
|
+
|
|
840
|
+
cleanup_tmp="$tmp/lint-tmp"
|
|
841
|
+
mkdir -p "$cleanup_tmp"
|
|
842
|
+
cleanup_out=$(TMPDIR="$cleanup_tmp" FM_LINT_JOBS=2 "$LINT" "$good" 2>&1) \
|
|
843
|
+
|| fail "cleanup fixture lint failed"
|
|
844
|
+
[ "$cleanup_out" = "$out_clean_2" ] || fail "cleanup fixture changed routine diagnostics"
|
|
845
|
+
[ -z "$(find "$cleanup_tmp" -mindepth 1 -maxdepth 1 -name 'fm-lint.*' -print -quit)" ] \
|
|
846
|
+
|| fail "bounded lint left temporary worker state behind"
|
|
847
|
+
pass "jobs=1 and jobs=2 preserve deterministic diagnostics, failures, cleanup bounds, and quiet telemetry"
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
test_worker_trees_stop_on_signal() {
|
|
851
|
+
local tmp fakebin fixture jobs telemetry lint_tmp pid_file out_file telemetry_file
|
|
852
|
+
local parent_pid shellcheck_pid i parent_rc survivor
|
|
853
|
+
tmp=$(fm_test_tmproot fm-lint-signal)
|
|
854
|
+
mkdir -p "$tmp"
|
|
855
|
+
fakebin=$(fm_fakebin "$tmp")
|
|
856
|
+
fixture="$tmp/good.sh"
|
|
857
|
+
cat > "$fixture" <<'SH'
|
|
858
|
+
#!/usr/bin/env bash
|
|
859
|
+
printf '%s\n' "${1:-ok}"
|
|
860
|
+
SH
|
|
861
|
+
cat > "$fakebin/shellcheck" <<'SH'
|
|
862
|
+
#!/usr/bin/env bash
|
|
863
|
+
if [ "${1:-}" = "--version" ]; then
|
|
864
|
+
printf 'ShellCheck - shell script analysis tool\nversion: 0.11.0\n'
|
|
865
|
+
exit 0
|
|
866
|
+
fi
|
|
867
|
+
printf '%s\n' "$$" > "$FM_TEST_SHELLCHECK_PID"
|
|
868
|
+
trap 'exit 143' HUP INT TERM
|
|
869
|
+
while :; do
|
|
870
|
+
sleep 1
|
|
871
|
+
done
|
|
872
|
+
SH
|
|
873
|
+
chmod +x "$fakebin/shellcheck"
|
|
874
|
+
|
|
875
|
+
for jobs in 1 2; do
|
|
876
|
+
for telemetry in off on; do
|
|
877
|
+
lint_tmp="$tmp/lint-$jobs-$telemetry"
|
|
878
|
+
pid_file="$tmp/shellcheck-$jobs-$telemetry.pid"
|
|
879
|
+
out_file="$tmp/output-$jobs-$telemetry"
|
|
880
|
+
telemetry_file=
|
|
881
|
+
mkdir -p "$lint_tmp"
|
|
882
|
+
if [ "$telemetry" = on ]; then
|
|
883
|
+
telemetry_file="$tmp/telemetry-$jobs.tsv"
|
|
884
|
+
fi
|
|
885
|
+
PATH="$fakebin:$PATH" TMPDIR="$lint_tmp" FM_LINT_JOBS="$jobs" \
|
|
886
|
+
FM_LINT_TELEMETRY="$telemetry_file" FM_TEST_SHELLCHECK_PID="$pid_file" \
|
|
887
|
+
"$LINT" "$fixture" > "$out_file" 2>&1 &
|
|
888
|
+
parent_pid=$!
|
|
889
|
+
i=0
|
|
890
|
+
while [ "$i" -lt 500 ] && [ ! -s "$pid_file" ]; do
|
|
891
|
+
kill -0 "$parent_pid" 2>/dev/null || break
|
|
892
|
+
sleep 0.01
|
|
893
|
+
i=$((i + 1))
|
|
894
|
+
done
|
|
895
|
+
[ -s "$pid_file" ] || {
|
|
896
|
+
kill -TERM "$parent_pid" 2>/dev/null || true
|
|
897
|
+
wait "$parent_pid" 2>/dev/null || true
|
|
898
|
+
fail "jobs=$jobs telemetry=$telemetry did not start ShellCheck"
|
|
899
|
+
}
|
|
900
|
+
shellcheck_pid=$(cat "$pid_file")
|
|
901
|
+
kill -TERM "$parent_pid" 2>/dev/null \
|
|
902
|
+
|| fail "jobs=$jobs telemetry=$telemetry parent could not be interrupted"
|
|
903
|
+
parent_rc=0
|
|
904
|
+
wait "$parent_pid" 2>/dev/null || parent_rc=$?
|
|
905
|
+
survivor=0
|
|
906
|
+
i=0
|
|
907
|
+
while [ "$i" -lt 100 ] && kill -0 "$shellcheck_pid" 2>/dev/null; do
|
|
908
|
+
sleep 0.01
|
|
909
|
+
i=$((i + 1))
|
|
910
|
+
done
|
|
911
|
+
if kill -0 "$shellcheck_pid" 2>/dev/null; then
|
|
912
|
+
survivor=1
|
|
913
|
+
kill -KILL "$shellcheck_pid" 2>/dev/null || true
|
|
914
|
+
fi
|
|
915
|
+
[ "$parent_rc" -eq 143 ] \
|
|
916
|
+
|| fail "jobs=$jobs telemetry=$telemetry signal exit was $parent_rc, expected 143"
|
|
917
|
+
[ "$survivor" -eq 0 ] \
|
|
918
|
+
|| fail "jobs=$jobs telemetry=$telemetry left ShellCheck running"
|
|
919
|
+
[ -z "$(find "$lint_tmp" -mindepth 1 -maxdepth 1 -name 'fm-lint.*' -print -quit)" ] \
|
|
920
|
+
|| fail "jobs=$jobs telemetry=$telemetry left temporary worker state"
|
|
921
|
+
done
|
|
922
|
+
done
|
|
923
|
+
pass "jobs=1 and jobs=2 stop complete worker trees with and without telemetry"
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
test_seeded_module_boundary_parity() {
|
|
927
|
+
if ! pinned_ready; then
|
|
928
|
+
pass "SKIP (ShellCheck $REQUIRED not resolved): seeded source-boundary parity check"
|
|
929
|
+
return
|
|
930
|
+
fi
|
|
931
|
+
local tmp rel adapter dispatcher dep owner test_root out rc
|
|
932
|
+
tmp=$(mktemp -d "$ROOT/.fm-lint-parity.XXXXXX")
|
|
933
|
+
if [ "${#FM_TEST_CLEANUP_DIRS[@]}" -eq 0 ]; then
|
|
934
|
+
trap fm_test_cleanup EXIT
|
|
935
|
+
fi
|
|
936
|
+
FM_TEST_CLEANUP_DIRS+=("$tmp")
|
|
937
|
+
rel=${tmp#"$ROOT/"}
|
|
938
|
+
adapter="$tmp/adapter.sh"
|
|
939
|
+
dispatcher="$tmp/dispatcher.sh"
|
|
940
|
+
dep="$tmp/owner-dep.sh"
|
|
941
|
+
owner="$tmp/owner.sh"
|
|
942
|
+
test_root="$tmp/test-local.sh"
|
|
943
|
+
|
|
944
|
+
cat > "$adapter" <<'SH'
|
|
945
|
+
#!/usr/bin/env bash
|
|
946
|
+
adapter_bad() {
|
|
947
|
+
rm $1
|
|
948
|
+
}
|
|
949
|
+
SH
|
|
950
|
+
cat > "$dispatcher" <<SH
|
|
951
|
+
#!/usr/bin/env bash
|
|
952
|
+
# shellcheck source=/dev/null
|
|
953
|
+
. "$adapter"
|
|
954
|
+
dispatcher_bad() {
|
|
955
|
+
local a= b=
|
|
956
|
+
printf '%s\n' "\$a\$b"
|
|
957
|
+
}
|
|
958
|
+
SH
|
|
959
|
+
cat > "$dep" <<'SH'
|
|
960
|
+
#!/usr/bin/env bash
|
|
961
|
+
owner_dependency_value=ok
|
|
962
|
+
SH
|
|
963
|
+
cat > "$owner" <<SH
|
|
964
|
+
#!/usr/bin/env bash
|
|
965
|
+
# shellcheck source=$rel/owner-dep.sh
|
|
966
|
+
. "$dep"
|
|
967
|
+
owner_bad() {
|
|
968
|
+
printf '%s\n' "\$owner_dependency_value"
|
|
969
|
+
cd "\$1"
|
|
970
|
+
}
|
|
971
|
+
SH
|
|
972
|
+
cat > "$test_root" <<SH
|
|
973
|
+
#!/usr/bin/env bash
|
|
974
|
+
# shellcheck source=/dev/null
|
|
975
|
+
. "$owner"
|
|
976
|
+
test_local_bad() {
|
|
977
|
+
local output=\$(printf ok)
|
|
978
|
+
printf '%s\n' "\$output"
|
|
979
|
+
}
|
|
980
|
+
SH
|
|
981
|
+
|
|
982
|
+
rc=0
|
|
983
|
+
out=$(FM_LINT_JOBS=2 "$LINT" "$dispatcher" "$adapter" "$owner" "$test_root" 2>&1) || rc=$?
|
|
984
|
+
[ "$rc" -ne 0 ] || fail "seeded module-boundary defects unexpectedly passed"
|
|
985
|
+
assert_contains "$out" "SC1007" "representative dispatcher defect was hidden"
|
|
986
|
+
assert_contains "$out" "SC2086" "representative canonical adapter defect was hidden"
|
|
987
|
+
assert_contains "$out" "SC2164" "representative production-owner defect was hidden"
|
|
988
|
+
assert_contains "$out" "SC2155" "representative test-local defect was hidden"
|
|
989
|
+
assert_not_contains "$out" "SC2154" "the production owner lost source-aware dependency context"
|
|
990
|
+
[ "$(printf '%s\n' "$out" | grep -Fc 'SC2086 (info)')" -eq 1 ] \
|
|
991
|
+
|| fail "the dispatcher boundary re-imported the adapter diagnostic"
|
|
992
|
+
[ "$(printf '%s\n' "$out" | grep -Fc 'SC2164 (warning)')" -eq 1 ] \
|
|
993
|
+
|| fail "the test boundary re-imported the production-owner diagnostic"
|
|
994
|
+
pass "seeded dispatcher, adapter, production-owner, and test-local diagnostics preserve parity"
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
test_help_reports_the_complete_interface
|
|
998
|
+
test_list_files_reports_the_shell_inventory
|
|
999
|
+
test_fast_mode_disables_extended_analysis
|
|
1000
|
+
test_ci_defaults_to_full_analysis
|
|
1001
|
+
test_ci_rejects_explicit_fast_mode
|
|
1002
|
+
test_fast_mode_catches_a_real_lint_defect
|
|
1003
|
+
test_pins_an_explicit_version
|
|
1004
|
+
test_installer_retries_transient_download_failure
|
|
1005
|
+
test_installer_selects_platform_archive_url_and_checksum
|
|
1006
|
+
test_installer_rejects_wrong_checksum
|
|
1007
|
+
test_installer_falls_back_to_shasum
|
|
1008
|
+
test_installer_prefers_sha256sum_over_shasum
|
|
1009
|
+
test_installer_rejects_unsupported_platform
|
|
1010
|
+
test_missing_shellcheck_fails_closed
|
|
1011
|
+
test_rejects_wrong_shellcheck_version
|
|
1012
|
+
test_catches_a_real_lint_defect
|
|
1013
|
+
test_ignores_ambient_shellcheck_opts
|
|
1014
|
+
test_clean_fixture_passes
|
|
1015
|
+
test_jobs_are_deterministic_and_complete
|
|
1016
|
+
test_worker_trees_stop_on_signal
|
|
1017
|
+
test_seeded_module_boundary_parity
|
|
1018
|
+
test_changed_mode_lints_only_the_changed_file
|
|
1019
|
+
test_ci_forces_full_lint_even_with_empty_diff
|
|
1020
|
+
test_main_branch_forces_full_lint
|
|
1021
|
+
test_explicit_path_bypasses_changed_logic
|
|
1022
|
+
test_zero_changed_files_exits_clean
|
|
1023
|
+
test_list_files_respects_changed_mode
|