@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,260 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# fm-public-followup-emit.sh - emit ONE structured terminal work result for work
|
|
3
|
+
# bound to a public commitment, into the owning home's private event inbox.
|
|
4
|
+
#
|
|
5
|
+
# WHY THIS EXISTS: a public promise is kept by the home that owns the relay
|
|
6
|
+
# consent and the thread binding. The home doing the work only has to report a
|
|
7
|
+
# TYPED result. Firstmate must never recover the source home, work id, outcome,
|
|
8
|
+
# or deliverables by parsing a free-form "done: ..." status sentence, so this
|
|
9
|
+
# script is the structured channel that carries them.
|
|
10
|
+
#
|
|
11
|
+
# WHAT IT DOES NOT DO: it never posts anything, never reads relay credentials,
|
|
12
|
+
# and never resolves a public thread. Outward delivery stays with the owning
|
|
13
|
+
# home (bin/fm-public-followup.sh deliver).
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# fm-public-followup-emit.sh --home <owning-home> \
|
|
17
|
+
# --obligation <obligation-id> --relation <relation-id> \
|
|
18
|
+
# --source-home <main|secondmate:<id>> --work-id <task-id> \
|
|
19
|
+
# --generation <n> --outcome <outcome-type> \
|
|
20
|
+
# [--deliverable <key>=<value>]... \
|
|
21
|
+
# (--outcome-text <text> | --outcome-text-file <path> | --outcome-text -)
|
|
22
|
+
#
|
|
23
|
+
# Options:
|
|
24
|
+
# --home <path> The home that owns the public commitment (the primary
|
|
25
|
+
# that took the mention). Must already have a
|
|
26
|
+
# registration for --obligation; see
|
|
27
|
+
# `fm-public-followup.sh register`.
|
|
28
|
+
# --obligation <id> tasks-axi public-followup obligation id.
|
|
29
|
+
# --relation <id> The relation_id this work fulfills or contributes to.
|
|
30
|
+
# --source-home <id> This worker's stable home identity, exactly as bound:
|
|
31
|
+
# "main" or "secondmate:<stable-id>".
|
|
32
|
+
# --work-id <id> This worker's exact task id, exactly as bound.
|
|
33
|
+
# --generation <n> The bound relation generation (integer >= 1).
|
|
34
|
+
# --outcome <type> Typed outcome. tasks-axi owns the vocabulary and
|
|
35
|
+
# refuses anything it does not accept; this script only
|
|
36
|
+
# checks the token is a safe slug.
|
|
37
|
+
# --deliverable k=v Repeatable safe deliverable (for example
|
|
38
|
+
# pr_url=https://...). tasks-axi owns which keys a given
|
|
39
|
+
# expected-final type permits.
|
|
40
|
+
# --outcome-text ... Public-safe outcome sentence, from an argument, a
|
|
41
|
+
# file, or stdin ("-"). Collapsed to one line; the
|
|
42
|
+
# event builder bounds it by codepoint, so control
|
|
43
|
+
# characters cannot survive.
|
|
44
|
+
#
|
|
45
|
+
# Output: the event id on stdout. Exit 0 on a published or already-present event
|
|
46
|
+
# (both are successes: the id is derived, so re-emitting the same terminal result
|
|
47
|
+
# is a no-op), 2 on a usage or validation error, 1 on a publication failure.
|
|
48
|
+
#
|
|
49
|
+
# IDEMPOTENCY: the event id is a digest of the identity tuple (obligation,
|
|
50
|
+
# relation, source home, work id, generation, outcome type, deliverables), so a
|
|
51
|
+
# retry, a duplicate report, or a rerun after restart resolves to the same file
|
|
52
|
+
# and the first published copy wins. Nothing here needs coordination.
|
|
53
|
+
#
|
|
54
|
+
# SAFETY: the event is published through the shared private-artifact primitive -
|
|
55
|
+
# atomic rename into place, single link, mode 0600 (never executable), inside a
|
|
56
|
+
# 0700 directory this script refuses to create. The owning home must already have
|
|
57
|
+
# registered the obligation, so a home that never opted into the relay can never
|
|
58
|
+
# be given public-followup artifacts by a child.
|
|
59
|
+
set -u
|
|
60
|
+
|
|
61
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
62
|
+
# shellcheck source=bin/fm-public-followup-lib.sh
|
|
63
|
+
. "$SCRIPT_DIR/fm-public-followup-lib.sh"
|
|
64
|
+
|
|
65
|
+
usage() {
|
|
66
|
+
cat >&2 <<'EOF'
|
|
67
|
+
usage: fm-public-followup-emit.sh --home <owning-home> --obligation <id> --relation <id>
|
|
68
|
+
--source-home <main|secondmate:<id>> --work-id <id> --generation <n>
|
|
69
|
+
--outcome <type> [--deliverable <key>=<value>]...
|
|
70
|
+
(--outcome-text <text> | --outcome-text-file <path> | --outcome-text -)
|
|
71
|
+
EOF
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# The header comment IS the help text, so the two can never drift apart.
|
|
75
|
+
help() {
|
|
76
|
+
sed -n '2,/^set -u$/p' "$0" | sed '$d; s/^# \{0,1\}//'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
die() { printf 'fm-public-followup-emit: %s\n' "$1" >&2; exit "${2:-2}"; }
|
|
80
|
+
|
|
81
|
+
HOME_DIR=
|
|
82
|
+
OBLIGATION=
|
|
83
|
+
RELATION=
|
|
84
|
+
SOURCE_HOME=
|
|
85
|
+
WORK_ID=
|
|
86
|
+
GENERATION=
|
|
87
|
+
OUTCOME=
|
|
88
|
+
TEXT_SOURCE=
|
|
89
|
+
TEXT_MODE=
|
|
90
|
+
DELIVERABLE_KEYS=()
|
|
91
|
+
DELIVERABLE_VALUES=()
|
|
92
|
+
|
|
93
|
+
case "${1:-}" in
|
|
94
|
+
--help|-h) help; exit 0 ;;
|
|
95
|
+
'') usage; exit 2 ;;
|
|
96
|
+
esac
|
|
97
|
+
|
|
98
|
+
while [ "$#" -gt 0 ]; do
|
|
99
|
+
case "$1" in
|
|
100
|
+
--home) shift; HOME_DIR=${1:-} ;;
|
|
101
|
+
--obligation) shift; OBLIGATION=${1:-} ;;
|
|
102
|
+
--relation) shift; RELATION=${1:-} ;;
|
|
103
|
+
--source-home) shift; SOURCE_HOME=${1:-} ;;
|
|
104
|
+
--work-id) shift; WORK_ID=${1:-} ;;
|
|
105
|
+
--generation) shift; GENERATION=${1:-} ;;
|
|
106
|
+
--outcome) shift; OUTCOME=${1:-} ;;
|
|
107
|
+
--outcome-text) shift; TEXT_MODE='inline'; TEXT_SOURCE=${1:-} ;;
|
|
108
|
+
--outcome-text-file) shift; TEXT_MODE='file'; TEXT_SOURCE=${1:-} ;;
|
|
109
|
+
--deliverable)
|
|
110
|
+
shift
|
|
111
|
+
case "${1:-}" in
|
|
112
|
+
*=*) ;;
|
|
113
|
+
*) die "--deliverable needs <key>=<value>, got '${1:-}'" ;;
|
|
114
|
+
esac
|
|
115
|
+
DELIVERABLE_KEYS+=("${1%%=*}")
|
|
116
|
+
DELIVERABLE_VALUES+=("${1#*=}")
|
|
117
|
+
;;
|
|
118
|
+
--help|-h) help; exit 0 ;;
|
|
119
|
+
*) die "unknown argument '$1'" ;;
|
|
120
|
+
esac
|
|
121
|
+
shift || true
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
[ -n "$HOME_DIR" ] || { usage; exit 2; }
|
|
125
|
+
[ -n "$OBLIGATION" ] || { usage; exit 2; }
|
|
126
|
+
[ -n "$RELATION" ] || { usage; exit 2; }
|
|
127
|
+
[ -n "$SOURCE_HOME" ] || { usage; exit 2; }
|
|
128
|
+
[ -n "$WORK_ID" ] || { usage; exit 2; }
|
|
129
|
+
[ -n "$GENERATION" ] || { usage; exit 2; }
|
|
130
|
+
[ -n "$OUTCOME" ] || { usage; exit 2; }
|
|
131
|
+
[ -n "$TEXT_MODE" ] || { usage; exit 2; }
|
|
132
|
+
|
|
133
|
+
fm_pf_slug_valid "$OBLIGATION" || die "unsafe obligation id: $OBLIGATION"
|
|
134
|
+
fm_pf_slug_valid "$RELATION" || die "unsafe relation id: $RELATION"
|
|
135
|
+
fm_pf_slug_valid "$WORK_ID" || die "unsafe work id: $WORK_ID"
|
|
136
|
+
fm_pf_slug_valid "$OUTCOME" || die "unsafe outcome type: $OUTCOME"
|
|
137
|
+
fm_pf_home_id_valid "$SOURCE_HOME" \
|
|
138
|
+
|| die "source home must be 'main' or 'secondmate:<stable-id>', got '$SOURCE_HOME'"
|
|
139
|
+
case "$GENERATION" in
|
|
140
|
+
''|*[!0-9]*) die "generation must be a positive integer, got '$GENERATION'" ;;
|
|
141
|
+
esac
|
|
142
|
+
[ "$GENERATION" -ge 1 ] || die "generation must be >= 1, got '$GENERATION'"
|
|
143
|
+
|
|
144
|
+
i=0
|
|
145
|
+
while [ "$i" -lt "${#DELIVERABLE_KEYS[@]}" ]; do
|
|
146
|
+
key=${DELIVERABLE_KEYS[$i]}
|
|
147
|
+
case "$key" in
|
|
148
|
+
''|*[!a-z0-9_]*) die "deliverable key must be lowercase [a-z0-9_], got '$key'" ;;
|
|
149
|
+
esac
|
|
150
|
+
[ "${#DELIVERABLE_VALUES[$i]}" -le 512 ] \
|
|
151
|
+
|| die "deliverable '$key' exceeds 512 characters"
|
|
152
|
+
case "${DELIVERABLE_VALUES[$i]}" in
|
|
153
|
+
*[[:cntrl:]]*) die "deliverable '$key' must be single-line text with no control characters" ;;
|
|
154
|
+
esac
|
|
155
|
+
i=$((i + 1))
|
|
156
|
+
done
|
|
157
|
+
|
|
158
|
+
# Resolve the owning home to a real absolute directory before composing any path
|
|
159
|
+
# under it, so a relative or symlinked argument cannot make the destination
|
|
160
|
+
# ambiguous in a later message or write.
|
|
161
|
+
case "$HOME_DIR" in
|
|
162
|
+
/*) ;;
|
|
163
|
+
*) HOME_DIR=$(CDPATH='' cd -- "$HOME_DIR" 2>/dev/null && pwd -P) \
|
|
164
|
+
|| die "--home is not a reachable directory: $1" ;;
|
|
165
|
+
esac
|
|
166
|
+
[ -d "$HOME_DIR" ] && [ ! -L "$HOME_DIR" ] \
|
|
167
|
+
|| die "--home must name an existing directory, got '$HOME_DIR'"
|
|
168
|
+
|
|
169
|
+
fm_pf_relay_active "$HOME_DIR" || exit 0
|
|
170
|
+
command -v jq >/dev/null 2>&1 || die "jq is required to build a typed terminal event" 1
|
|
171
|
+
|
|
172
|
+
STATE="$HOME_DIR/state"
|
|
173
|
+
REGISTRY="$(fm_pf_registry_dir "$STATE")/$OBLIGATION"
|
|
174
|
+
if [ ! -f "$REGISTRY" ] || [ -L "$REGISTRY" ]; then
|
|
175
|
+
die "home '$HOME_DIR' has no public-followup registration for '$OBLIGATION'; the owning home registers a commitment before its work can report one" 1
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# The registration is the owning home's own record of what it bound, so checking
|
|
179
|
+
# the identity tuple against it catches a mis-briefed worker at the edge with a
|
|
180
|
+
# clear message. tasks-axi still re-validates everything at consume time and
|
|
181
|
+
# remains the authority; this is a cheap early refusal, not a second gatekeeper.
|
|
182
|
+
reg_mismatch() {
|
|
183
|
+
local field=$1 expected=$2 got=$3
|
|
184
|
+
[ -z "$expected" ] || [ "$expected" = "$got" ] \
|
|
185
|
+
|| die "event $field '$got' does not match this home's registration ('$expected')"
|
|
186
|
+
}
|
|
187
|
+
reg_mismatch relation "$(fm_pf_registry_get "$STATE" "$OBLIGATION" relation_id)" "$RELATION"
|
|
188
|
+
reg_mismatch source-home "$(fm_pf_registry_get "$STATE" "$OBLIGATION" work_home)" "$SOURCE_HOME"
|
|
189
|
+
reg_mismatch work-id "$(fm_pf_registry_get "$STATE" "$OBLIGATION" work_id)" "$WORK_ID"
|
|
190
|
+
reg_mismatch generation "$(fm_pf_registry_get "$STATE" "$OBLIGATION" generation)" "$GENERATION"
|
|
191
|
+
|
|
192
|
+
case "$TEXT_MODE" in
|
|
193
|
+
inline) OUTCOME_TEXT=$(printf '%s' "$TEXT_SOURCE" | fm_pf_clean_outcome_text) ;;
|
|
194
|
+
file)
|
|
195
|
+
if [ "$TEXT_SOURCE" = '-' ]; then
|
|
196
|
+
OUTCOME_TEXT=$(fm_pf_clean_outcome_text)
|
|
197
|
+
else
|
|
198
|
+
[ -f "$TEXT_SOURCE" ] || die "outcome text file not found: $TEXT_SOURCE"
|
|
199
|
+
OUTCOME_TEXT=$(fm_pf_clean_outcome_text < "$TEXT_SOURCE")
|
|
200
|
+
fi
|
|
201
|
+
;;
|
|
202
|
+
esac
|
|
203
|
+
[ -n "$OUTCOME_TEXT" ] || die "outcome text is empty once whitespace and control characters are removed"
|
|
204
|
+
|
|
205
|
+
# Canonical deliverables object: sorted keys, compact, so the same deliverables
|
|
206
|
+
# always hash to the same identity regardless of flag order.
|
|
207
|
+
DELIVERABLES_JSON=$(
|
|
208
|
+
{
|
|
209
|
+
i=0
|
|
210
|
+
while [ "$i" -lt "${#DELIVERABLE_KEYS[@]}" ]; do
|
|
211
|
+
printf '%s\n%s\n' "${DELIVERABLE_KEYS[$i]}" "${DELIVERABLE_VALUES[$i]}"
|
|
212
|
+
i=$((i + 1))
|
|
213
|
+
done
|
|
214
|
+
} | jq -Rsc 'split("\n") | .[:-1] | [range(0; length; 2) as $i | {key: .[$i], value: .[$i+1]}] | from_entries | to_entries | sort_by(.key) | from_entries'
|
|
215
|
+
) || die "could not encode deliverables" 1
|
|
216
|
+
|
|
217
|
+
EVENT_ID=$(fm_pf_event_id \
|
|
218
|
+
"$OBLIGATION" "$RELATION" "$SOURCE_HOME" "$WORK_ID" "$GENERATION" "$OUTCOME" \
|
|
219
|
+
"$DELIVERABLES_JSON") || die "sha256 (shasum or sha256sum) is required" 1
|
|
220
|
+
# The derived id becomes a filename, so require the exact digest shape rather
|
|
221
|
+
# than trusting whatever the hashing tool printed.
|
|
222
|
+
case "$EVENT_ID" in
|
|
223
|
+
*[!0-9a-f]*|'') die "could not derive a usable event id" 1 ;;
|
|
224
|
+
esac
|
|
225
|
+
[ "${#EVENT_ID}" -eq 64 ] || die "could not derive a usable event id" 1
|
|
226
|
+
|
|
227
|
+
# jq bounds the outcome text by codepoint, so a long or non-ASCII sentence is
|
|
228
|
+
# capped without ever splitting a multi-byte character.
|
|
229
|
+
EVENT_JSON=$(jq -Sc -n \
|
|
230
|
+
--argjson schema_version "$FM_PF_EVENT_SCHEMA_VERSION" \
|
|
231
|
+
--arg event_id "$EVENT_ID" \
|
|
232
|
+
--arg obligation_id "$OBLIGATION" \
|
|
233
|
+
--arg relation_id "$RELATION" \
|
|
234
|
+
--arg work_id "$WORK_ID" \
|
|
235
|
+
--argjson generation "$GENERATION" \
|
|
236
|
+
--arg source_home_id "$SOURCE_HOME" \
|
|
237
|
+
--arg outcome_type "$OUTCOME" \
|
|
238
|
+
--argjson deliverables "$DELIVERABLES_JSON" \
|
|
239
|
+
--arg public_safe_outcome "$OUTCOME_TEXT" \
|
|
240
|
+
--argjson outcome_max "$FM_PF_OUTCOME_TEXT_MAX" \
|
|
241
|
+
--arg occurred_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
242
|
+
'{schema_version:$schema_version, event_id:$event_id, obligation_id:$obligation_id,
|
|
243
|
+
relation_id:$relation_id, work_id:$work_id, generation:$generation,
|
|
244
|
+
source_home_id:$source_home_id, outcome_type:$outcome_type,
|
|
245
|
+
deliverables:$deliverables,
|
|
246
|
+
public_safe_outcome:($public_safe_outcome[0:$outcome_max]),
|
|
247
|
+
occurred_at:$occurred_at, successor:null}') \
|
|
248
|
+
|| die "could not build the typed terminal event" 1
|
|
249
|
+
|
|
250
|
+
EVENT_BYTES=$(printf '%s\n' "$EVENT_JSON" | LC_ALL=C wc -c | tr -d ' ') \
|
|
251
|
+
|| die "could not measure the typed terminal event" 1
|
|
252
|
+
[ "$EVENT_BYTES" -le "$FM_PF_EVENT_BYTES_MAX" ] \
|
|
253
|
+
|| die "typed terminal event exceeds $FM_PF_EVENT_BYTES_MAX bytes" 2
|
|
254
|
+
|
|
255
|
+
printf '%s\n' "$EVENT_JSON" \
|
|
256
|
+
| fmx_private_artifact_publish_stdin_once "$(fm_pf_events_dir "$STATE")" "$EVENT_ID.json" 600
|
|
257
|
+
case $? in
|
|
258
|
+
0|1) printf '%s\n' "$EVENT_ID" ;;
|
|
259
|
+
*) die "could not publish the terminal event into $HOME_DIR" 1 ;;
|
|
260
|
+
esac
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# fm-public-followup-lib.sh - shared gating and private-transport helpers for the
|
|
3
|
+
# deterministic public-followup consumer.
|
|
4
|
+
#
|
|
5
|
+
# Firstmate promises a public final reply when a myfirstmate relay mention (X or
|
|
6
|
+
# Discord) asks for work. `tasks-axi public-followup` is the sole owner of that
|
|
7
|
+
# typed obligation and its state machine; state/x-context/ is the sole owner of
|
|
8
|
+
# the private full request context. This library owns Firstmate's activation
|
|
9
|
+
# gate, private per-home transport paths, retained-loop state and locking
|
|
10
|
+
# helpers, follow-up window classification, and deterministic terminal-event
|
|
11
|
+
# identity.
|
|
12
|
+
#
|
|
13
|
+
# Sourced, never executed. No side effects on source (it creates nothing), which
|
|
14
|
+
# is what keeps a relay-disabled home free of public-followup artifacts.
|
|
15
|
+
# set -u / set -e safe.
|
|
16
|
+
#
|
|
17
|
+
# GATE ORDER - the acceptance criterion for relay-disabled homes:
|
|
18
|
+
# 1. fm_pf_relay_active <home> the authoritative myfirstmate activation
|
|
19
|
+
# contract, a non-empty FMX_PAIRING_TOKEN in
|
|
20
|
+
# <home>/.env. There is no second flag. When
|
|
21
|
+
# <home>/.env is absent this is a single
|
|
22
|
+
# [ -f ] test and nothing else runs.
|
|
23
|
+
# 2. fm_pf_has_registrations O(1) presence check on the registry created
|
|
24
|
+
# / fm_pf_has_events only by the relay path (fm-public-followup.sh
|
|
25
|
+
# / fm_pf_has_open_loops register). Open loops ARE registrations:
|
|
26
|
+
# a delivered final keeps the record, so this
|
|
27
|
+
# same check is the fail-loud session-start
|
|
28
|
+
# gate. Relay-enabled homes with no public
|
|
29
|
+
# loops stop here, so no tasks-axi call and
|
|
30
|
+
# no backlog scan happens.
|
|
31
|
+
#
|
|
32
|
+
# Private transport layout, all under <home>/state/public-followup (mode 0700,
|
|
33
|
+
# initialized by `fm-public-followup.sh register` and extended only by these
|
|
34
|
+
# public-followup commands):
|
|
35
|
+
# registry/<obligation-id> registration record: the bounded private binding
|
|
36
|
+
# (obligation, relation, work ref and canonical
|
|
37
|
+
# secondmate path, generation, platform, request id)
|
|
38
|
+
# plus the loop fields that survive delivery (state,
|
|
39
|
+
# delivered_at, followup_expires_at,
|
|
40
|
+
# request_context_b64). Presence means the public
|
|
41
|
+
# loop is still open. Delivery
|
|
42
|
+
# stamps state=delivered; only `retire` removes the
|
|
43
|
+
# record. The obligation itself always remains
|
|
44
|
+
# tasks-axi truth.
|
|
45
|
+
# events/<event-id>.json inbound typed terminal events awaiting
|
|
46
|
+
# reconciliation, one file per event id.
|
|
47
|
+
# consumed/<event-id> idempotency ledger: an accepted event id is never
|
|
48
|
+
# replayed, so duplicate emits and restart replay
|
|
49
|
+
# are no-ops.
|
|
50
|
+
# rejected/<event-id>.json events tasks-axi refused, kept with a
|
|
51
|
+
# rejected/<event-id>.reason one-line reason so a refusal is inspectable and
|
|
52
|
+
# never retried in a loop.
|
|
53
|
+
# surfaced last surfaced pending-event signature, so the
|
|
54
|
+
# existing relay poll wakes once per new event set
|
|
55
|
+
# instead of every cycle.
|
|
56
|
+
# retired/<obligation-id> private retirement receipt containing the bounded
|
|
57
|
+
# reason and timestamp recorded before the registry
|
|
58
|
+
# entry is removed; its presence prevents replayed
|
|
59
|
+
# registration from reopening the closed loop.
|
|
60
|
+
#
|
|
61
|
+
# Event identity is DERIVED, never random: fm_pf_event_id hashes the canonical
|
|
62
|
+
# identity tuple, so re-emitting the same terminal result produces the same
|
|
63
|
+
# event id and the same destination path. Idempotency therefore holds across
|
|
64
|
+
# retries, restarts, and duplicate child reports without any coordination.
|
|
65
|
+
#
|
|
66
|
+
# Depends on bin/fm-x-lib.sh for .env reading and the private-artifact
|
|
67
|
+
# publication primitives (atomic, single-link, mode-validated, non-executable);
|
|
68
|
+
# those remain that file's contract and are not restated here.
|
|
69
|
+
|
|
70
|
+
_FM_PF_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd 2>/dev/null)" || _FM_PF_LIB_DIR="."
|
|
71
|
+
# shellcheck source=bin/fm-x-lib.sh
|
|
72
|
+
. "$_FM_PF_LIB_DIR/fm-x-lib.sh"
|
|
73
|
+
|
|
74
|
+
FM_PF_DIRNAME='public-followup'
|
|
75
|
+
# Consumed by the sourcing scripts, not by this library.
|
|
76
|
+
# shellcheck disable=SC2034
|
|
77
|
+
FM_PF_EVENT_SCHEMA_VERSION=1
|
|
78
|
+
# Bounded so a public-safe outcome line can never carry a raw public message,
|
|
79
|
+
# and so one event file stays small enough to read and validate cheaply.
|
|
80
|
+
FM_PF_OUTCOME_TEXT_MAX=${FM_PF_OUTCOME_TEXT_MAX:-600}
|
|
81
|
+
FM_PF_EVENT_BYTES_MAX=${FM_PF_EVENT_BYTES_MAX:-8192}
|
|
82
|
+
|
|
83
|
+
# --- gate 1: the authoritative relay activation contract --------------------
|
|
84
|
+
|
|
85
|
+
# fm_pf_relay_active <home>: 0 when this home has opted into the myfirstmate
|
|
86
|
+
# relay, 1 otherwise. Identical contract to bootstrap's X-mode activation - a
|
|
87
|
+
# non-empty FMX_PAIRING_TOKEN in <home>/.env - so no second activation flag
|
|
88
|
+
# exists to drift. FMX_PAIRING_TOKEN in the environment wins, matching
|
|
89
|
+
# fmx_load_config, so a direct client call and this gate agree.
|
|
90
|
+
fm_pf_relay_active() {
|
|
91
|
+
local home=$1 token
|
|
92
|
+
if [ -n "${FMX_PAIRING_TOKEN+x}" ]; then
|
|
93
|
+
[ -n "${FMX_PAIRING_TOKEN-}" ]
|
|
94
|
+
return $?
|
|
95
|
+
fi
|
|
96
|
+
[ -f "$home/.env" ] || return 1
|
|
97
|
+
token=$(fmx_env_get FMX_PAIRING_TOKEN "$home/.env")
|
|
98
|
+
[ -n "$token" ]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# --- gate 2: O(1) presence checks on relay-path-owned registrations ---------
|
|
102
|
+
|
|
103
|
+
fm_pf_root() { printf '%s\n' "$1/$FM_PF_DIRNAME"; }
|
|
104
|
+
fm_pf_registry_dir() { printf '%s\n' "$1/$FM_PF_DIRNAME/registry"; }
|
|
105
|
+
fm_pf_events_dir() { printf '%s\n' "$1/$FM_PF_DIRNAME/events"; }
|
|
106
|
+
fm_pf_consumed_dir() { printf '%s\n' "$1/$FM_PF_DIRNAME/consumed"; }
|
|
107
|
+
fm_pf_rejected_dir() { printf '%s\n' "$1/$FM_PF_DIRNAME/rejected"; }
|
|
108
|
+
fm_pf_retired_dir() { printf '%s\n' "$1/$FM_PF_DIRNAME/retired"; }
|
|
109
|
+
|
|
110
|
+
fm_pf_retirement_receipt_exists() {
|
|
111
|
+
local file
|
|
112
|
+
file="$(fm_pf_retired_dir "$1")/$2"
|
|
113
|
+
[ -f "$file" ] && [ ! -L "$file" ]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# fm_pf_dir_has_entry <dir>: 0 when <dir> is a real directory holding at least
|
|
117
|
+
# one non-dot entry. Stops at the first hit, so cost does not grow with the
|
|
118
|
+
# directory's size.
|
|
119
|
+
fm_pf_dir_has_entry() {
|
|
120
|
+
local dir=$1 entry
|
|
121
|
+
[ -d "$dir" ] && [ ! -L "$dir" ] || return 1
|
|
122
|
+
for entry in "$dir"/*; do
|
|
123
|
+
[ -e "$entry" ] || continue
|
|
124
|
+
return 0
|
|
125
|
+
done
|
|
126
|
+
return 1
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fm_pf_has_registrations() { fm_pf_dir_has_entry "$(fm_pf_registry_dir "$1")"; }
|
|
130
|
+
fm_pf_has_events() { fm_pf_dir_has_entry "$(fm_pf_events_dir "$1")"; }
|
|
131
|
+
# Every retained registration is an open public loop (owed or delivered). Same
|
|
132
|
+
# O(1) directory presence check as fm_pf_has_registrations; the name is the
|
|
133
|
+
# post-retention semantic so callers do not treat "a reply is owed" as the
|
|
134
|
+
# only reason a record exists.
|
|
135
|
+
fm_pf_has_open_loops() { fm_pf_has_registrations "$1"; }
|
|
136
|
+
|
|
137
|
+
# fm_pf_active <home> <state>: both gates, in order. The single predicate every
|
|
138
|
+
# caller outside the relay path should use before doing any public-followup work.
|
|
139
|
+
fm_pf_active() {
|
|
140
|
+
fm_pf_relay_active "$1" || return 1
|
|
141
|
+
fm_pf_has_registrations "$2" || fm_pf_has_events "$2"
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# --- identifiers ------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
# fm_pf_slug_valid <value>: obligation ids, relation ids, work ids, and request
|
|
147
|
+
# ids all compose filenames. They arrive from tasks-axi, the relay, and child
|
|
148
|
+
# homes, so every one is checked against a conservative slug before use.
|
|
149
|
+
fm_pf_slug_valid() {
|
|
150
|
+
local v=$1
|
|
151
|
+
case "$v" in
|
|
152
|
+
''|.*|*[!A-Za-z0-9._-]*) return 1 ;;
|
|
153
|
+
esac
|
|
154
|
+
[ "${#v}" -le 128 ]
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# fm_pf_home_id_valid <home_id>: tasks-axi accepts "main" or
|
|
158
|
+
# "secondmate:<stable-id>" as a work_ref home. Validate the same shape here so a
|
|
159
|
+
# malformed source home is refused before it reaches a filename or a CLI call.
|
|
160
|
+
fm_pf_home_id_valid() {
|
|
161
|
+
local v=$1
|
|
162
|
+
case "$v" in
|
|
163
|
+
main) return 0 ;;
|
|
164
|
+
secondmate:*) fm_pf_slug_valid "${v#secondmate:}" ;;
|
|
165
|
+
*) return 1 ;;
|
|
166
|
+
esac
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
fm_pf_sha256() {
|
|
170
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
171
|
+
shasum -a 256 2>/dev/null | awk '{print $1}'
|
|
172
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
173
|
+
sha256sum 2>/dev/null | awk '{print $1}'
|
|
174
|
+
else
|
|
175
|
+
return 1
|
|
176
|
+
fi
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# fm_pf_event_id <obligation> <relation> <source_home> <work_id> <generation>
|
|
180
|
+
# <outcome_type> <deliverables-canonical>
|
|
181
|
+
# The stable idempotency identity. Derived from the identity tuple only, so the
|
|
182
|
+
# same terminal result always yields the same id no matter who emits it or how
|
|
183
|
+
# often. Public-safe outcome text is deliberately excluded: rewording the same
|
|
184
|
+
# landed outcome must not create a second event.
|
|
185
|
+
fm_pf_event_id() {
|
|
186
|
+
printf '%s\037%s\037%s\037%s\037%s\037%s\037%s' "$1" "$2" "$3" "$4" "$5" "$6" "$7" \
|
|
187
|
+
| fm_pf_sha256
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# --- bounded public-safe text ----------------------------------------------
|
|
191
|
+
|
|
192
|
+
# fm_pf_clean_outcome_text: read stdin, drop control characters, collapse every
|
|
193
|
+
# whitespace run to a single space, and trim. An event line therefore stays
|
|
194
|
+
# single-line and a raw pasted public message cannot ride along inside it.
|
|
195
|
+
# Deliberately does NOT truncate: a byte-wise cut would split a multi-byte
|
|
196
|
+
# character, so length bounding happens where it can count codepoints - jq, at
|
|
197
|
+
# the point the typed event is built.
|
|
198
|
+
fm_pf_clean_outcome_text() {
|
|
199
|
+
LC_ALL=C tr -d '\000-\010\013\014\016-\037\177' \
|
|
200
|
+
| LC_ALL=C tr '\011\012\015' ' ' \
|
|
201
|
+
| LC_ALL=C tr -s ' ' \
|
|
202
|
+
| sed 's/^ //; s/ $//'
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# fm_pf_bound_bytes <max>: hard byte cap for text that never becomes JSON, such
|
|
206
|
+
# as a quarantined event's one-line refusal reason.
|
|
207
|
+
fm_pf_bound_bytes() {
|
|
208
|
+
LC_ALL=C cut -b "1-$1"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# --- registry records -------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
# fm_pf_registry_get <state> <obligation-id> <key>: read one key=value line from
|
|
214
|
+
# a registration record. Prints nothing and succeeds when absent.
|
|
215
|
+
fm_pf_registry_get() {
|
|
216
|
+
local state=$1 id=$2 key=$3 file line
|
|
217
|
+
fm_pf_slug_valid "$id" || return 1
|
|
218
|
+
file="$(fm_pf_registry_dir "$state")/$id"
|
|
219
|
+
[ -f "$file" ] && [ ! -L "$file" ] || return 0
|
|
220
|
+
line=$(grep -E "^${key}=" "$file" 2>/dev/null | tail -n1) || return 0
|
|
221
|
+
printf '%s' "${line#*=}"
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# fm_pf_registry_ids <state>: every registered obligation id, one per line.
|
|
225
|
+
# The registry only ever holds this home's live public commitments, so this stays
|
|
226
|
+
# a bounded listing rather than a backlog scan.
|
|
227
|
+
fm_pf_registry_ids() {
|
|
228
|
+
local dir entry
|
|
229
|
+
dir=$(fm_pf_registry_dir "$1")
|
|
230
|
+
[ -d "$dir" ] && [ ! -L "$dir" ] || return 0
|
|
231
|
+
for entry in "$dir"/*; do
|
|
232
|
+
[ -f "$entry" ] && [ ! -L "$entry" ] || continue
|
|
233
|
+
basename "$entry"
|
|
234
|
+
done
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
# fm_pf_registry_ids_for_work <state> <work_home_id> <work_id>: the obligations
|
|
238
|
+
# this home registered against one exact work relation. Used by the completion
|
|
239
|
+
# guard so cleanup cannot declare bound work finished while its public promise is
|
|
240
|
+
# still open.
|
|
241
|
+
fm_pf_registry_ids_for_work() {
|
|
242
|
+
local state=$1 home_id=$2 work_id=$3 id
|
|
243
|
+
while IFS= read -r id; do
|
|
244
|
+
[ -n "$id" ] || continue
|
|
245
|
+
[ "$(fm_pf_registry_get "$state" "$id" work_home)" = "$home_id" ] || continue
|
|
246
|
+
[ "$(fm_pf_registry_get "$state" "$id" work_id)" = "$work_id" ] || continue
|
|
247
|
+
printf '%s\n' "$id"
|
|
248
|
+
done <<EOF
|
|
249
|
+
$(fm_pf_registry_ids "$state")
|
|
250
|
+
EOF
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# fm_pf_now_epoch: wall clock as epoch seconds. FMX_NOW_OVERRIDE pins it for
|
|
254
|
+
# tests, matching bin/fm-x-lib.sh.
|
|
255
|
+
fm_pf_now_epoch() {
|
|
256
|
+
printf '%s\n' "${FMX_NOW_OVERRIDE:-$(date +%s)}"
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
# fm_pf_now_rfc3339: UTC timestamp for delivered_at and similar stamps.
|
|
260
|
+
fm_pf_now_rfc3339() {
|
|
261
|
+
local epoch
|
|
262
|
+
epoch=$(fm_pf_now_epoch)
|
|
263
|
+
date -u -r "$epoch" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
264
|
+
|| date -u -d "@$epoch" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
265
|
+
|| date -u +%Y-%m-%dT%H:%M:%SZ
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# fm_pf_rfc3339_to_epoch <rfc3339>: parse a Zulu timestamp. Empty on failure.
|
|
269
|
+
fm_pf_rfc3339_to_epoch() {
|
|
270
|
+
local ts=$1
|
|
271
|
+
[ -n "$ts" ] || return 1
|
|
272
|
+
date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$ts" +%s 2>/dev/null \
|
|
273
|
+
|| date -u -d "$ts" +%s 2>/dev/null \
|
|
274
|
+
|| return 1
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
# fm_pf_followup_window_class <rfc3339>: ok, closing (<48h), expired, or unknown.
|
|
278
|
+
fm_pf_followup_window_class() {
|
|
279
|
+
local ts=$1 exp now
|
|
280
|
+
exp=$(fm_pf_rfc3339_to_epoch "$ts") || { printf 'unknown\n'; return 0; }
|
|
281
|
+
now=$(fm_pf_now_epoch)
|
|
282
|
+
if [ "$now" -ge "$exp" ]; then
|
|
283
|
+
printf 'expired\n'
|
|
284
|
+
elif [ $((exp - now)) -lt 172800 ]; then
|
|
285
|
+
printf 'closing\n'
|
|
286
|
+
else
|
|
287
|
+
printf 'ok\n'
|
|
288
|
+
fi
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
# fm_pf_b64_encode: stdin to a single-line base64 payload (no wrapping).
|
|
292
|
+
fm_pf_b64_encode() {
|
|
293
|
+
base64 2>/dev/null | tr -d '\n\r'
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
# fm_pf_b64_decode: stdin (single-line or wrapped base64) to bytes on stdout.
|
|
297
|
+
fm_pf_b64_decode() {
|
|
298
|
+
local data
|
|
299
|
+
data=$(cat)
|
|
300
|
+
printf '%s\n' "$data" | base64 -d 2>/dev/null \
|
|
301
|
+
|| printf '%s\n' "$data" | base64 -D 2>/dev/null
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
# fm_pf_registry_loop_state <state> <id>: open or delivered. A pre-change
|
|
305
|
+
# record with no state= is treated as open so live homes never crash.
|
|
306
|
+
fm_pf_registry_loop_state() {
|
|
307
|
+
local v
|
|
308
|
+
v=$(fm_pf_registry_get "$1" "$2" state)
|
|
309
|
+
case "$v" in
|
|
310
|
+
delivered) printf 'delivered\n' ;;
|
|
311
|
+
*) printf 'open\n' ;;
|
|
312
|
+
esac
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
# fm_pf_registry_rechainable <state> <id>: 0 when request_context_b64 is present.
|
|
316
|
+
fm_pf_registry_rechainable() {
|
|
317
|
+
local ctx
|
|
318
|
+
ctx=$(fm_pf_registry_get "$1" "$2" request_context_b64)
|
|
319
|
+
[ -n "$ctx" ]
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
# fm_pf_has_delivered_open_loops <state>: 0 when any retained record is
|
|
323
|
+
# state=delivered (an open loop with nothing owed). Pre-change records have no
|
|
324
|
+
# state= and are treated as still-owed, not delivered.
|
|
325
|
+
fm_pf_has_delivered_open_loops() {
|
|
326
|
+
local state=$1 id
|
|
327
|
+
while IFS= read -r id; do
|
|
328
|
+
[ -n "$id" ] || continue
|
|
329
|
+
[ "$(fm_pf_registry_get "$state" "$id" state)" = delivered ] || continue
|
|
330
|
+
return 0
|
|
331
|
+
done <<EOF
|
|
332
|
+
$(fm_pf_registry_ids "$state")
|
|
333
|
+
EOF
|
|
334
|
+
return 1
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
fm_pf_registry_lock_path() {
|
|
338
|
+
printf '%s/.registry-%s.lock\n' "$(fm_pf_root "$1")" "$2"
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
fm_pf_registry_lock_acquire() {
|
|
342
|
+
local state=$1 id=$2
|
|
343
|
+
fm_pf_slug_valid "$id" || return 1
|
|
344
|
+
fmx_private_artifact_dir_prepare "$(fm_pf_root "$state")" >/dev/null || return 1
|
|
345
|
+
if ! command -v fm_lock_acquire_wait >/dev/null 2>&1; then
|
|
346
|
+
# shellcheck source=bin/fm-wake-lib.sh
|
|
347
|
+
. "$_FM_PF_LIB_DIR/fm-wake-lib.sh"
|
|
348
|
+
fi
|
|
349
|
+
fm_lock_acquire_wait "$(fm_pf_registry_lock_path "$state" "$id")"
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
fm_pf_registry_lock_release() {
|
|
353
|
+
fm_lock_release "$(fm_pf_registry_lock_path "$1" "$2")"
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
# fm_pf_registry_stamp_delivered <state> <id> <rfc3339>: rewrite one record
|
|
357
|
+
# with state=delivered and delivered_at, keeping every other field. The record
|
|
358
|
+
# stays; only retire removes it.
|
|
359
|
+
fm_pf_registry_stamp_delivered() {
|
|
360
|
+
local state=$1 id=$2 delivered_at=$3 file rest rc=0
|
|
361
|
+
fm_pf_slug_valid "$id" || return 1
|
|
362
|
+
[ -n "$delivered_at" ] || return 1
|
|
363
|
+
fm_pf_registry_lock_acquire "$state" "$id" || return 1
|
|
364
|
+
file="$(fm_pf_registry_dir "$state")/$id"
|
|
365
|
+
if [ -f "$file" ] && [ ! -L "$file" ]; then
|
|
366
|
+
rest=$(grep -v -E '^(state|delivered_at|delivered_obligation)=' "$file" 2>/dev/null || true)
|
|
367
|
+
printf '%s\nstate=delivered\ndelivered_at=%s\ndelivered_obligation=%s\n' \
|
|
368
|
+
"$rest" "$delivered_at" "$id" \
|
|
369
|
+
| fmx_private_artifact_publish_stdin "$(fm_pf_registry_dir "$state")" "$id" 600 \
|
|
370
|
+
|| rc=$?
|
|
371
|
+
else
|
|
372
|
+
rc=3
|
|
373
|
+
fi
|
|
374
|
+
fm_pf_registry_lock_release "$state" "$id"
|
|
375
|
+
return "$rc"
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
# --- pending-event signature ------------------------------------------------
|
|
379
|
+
|
|
380
|
+
# Consumed by the sourcing scripts, not by this library.
|
|
381
|
+
# shellcheck disable=SC2034
|
|
382
|
+
FM_PF_SURFACED_BASENAME=surfaced
|
|
383
|
+
|
|
384
|
+
# fm_pf_events_signature <state>: a stable digest of the pending event id set.
|
|
385
|
+
# The relay poll compares it against the surfaced record so an unconsumed event
|
|
386
|
+
# wakes firstmate once per new event, not once per poll cycle.
|
|
387
|
+
fm_pf_events_signature() {
|
|
388
|
+
local dir entry pending_names=
|
|
389
|
+
dir=$(fm_pf_events_dir "$1")
|
|
390
|
+
[ -d "$dir" ] && [ ! -L "$dir" ] || return 1
|
|
391
|
+
for entry in "$dir"/*.json; do
|
|
392
|
+
[ -f "$entry" ] && [ ! -L "$entry" ] || continue
|
|
393
|
+
pending_names="$pending_names$(basename "$entry")
|
|
394
|
+
"
|
|
395
|
+
done
|
|
396
|
+
[ -n "$pending_names" ] || return 1
|
|
397
|
+
printf '%s' "$pending_names" | LC_ALL=C sort | fm_pf_sha256
|
|
398
|
+
}
|