create-egregore 0.21.6 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/egregore-launcher.js +58 -6
- package/assets/egregore-launcher.sh +15 -2
- package/lib/claude-runtime.js +2 -0
- package/lib/codex-runtime.js +2 -0
- package/lib/setup.js +20 -3
- package/package.json +2 -2
- package/runtime/claude/.claude/context/commit-format.md +7 -4
- package/runtime/claude/.claude/context/handoff-claiming.md +32 -0
- package/runtime/claude/.claude/context/notification-consent.md +12 -9
- package/runtime/claude/.claude/hooks/boundary-check.sh +14 -331
- package/runtime/claude/.claude/hooks/memory-read-guard.sh +9 -1
- package/runtime/claude/.claude/rules/voice-bedrock.md +6 -2
- package/runtime/claude/.claude/settings.json +1 -1
- package/runtime/claude/.claude/skills/commit/SKILL.md +5 -3
- package/runtime/claude/.claude/skills/dark-mode/SKILL.md +48 -369
- package/runtime/claude/.claude/skills/records/SKILL.md +158 -0
- package/runtime/claude/.claude/skills/reflect/SKILL.md +50 -21
- package/runtime/claude/.claude/skills/review-pr/SKILL.md +4 -2
- package/runtime/claude/.claude/skills/save/SKILL.md +9 -3
- package/runtime/claude/.claude/skills/summon/SKILL.md +138 -207
- package/runtime/claude/.claude/skills/tui-design/SKILL.md +1 -1
- package/runtime/claude/.claude/skills/update/SKILL.md +1 -1
- package/runtime/claude/.claude/skills/view/SKILL.md +52 -16
- package/runtime/claude/.claude/skills/view/compose-scaffold.html +19 -13
- package/runtime/claude/CLAUDE.md +59 -95
- package/runtime/claude/bin/agent.sh +231 -7
- package/runtime/claude/bin/api-call.sh +44 -23
- package/runtime/claude/bin/artifact-register.sh +7 -1
- package/runtime/claude/bin/artifact-writeback.sh +1 -1
- package/runtime/claude/bin/artifacts.sh +66 -265
- package/runtime/claude/bin/attendant.sh +4 -1
- package/runtime/claude/bin/boundary-guard.cjs +1848 -0
- package/runtime/claude/bin/boundary-hook.sh +41 -0
- package/runtime/claude/bin/boundary.sh +15 -155
- package/runtime/claude/bin/capture-run.sh +32 -2
- package/runtime/claude/bin/codex-render-spec.mjs +24 -46
- package/runtime/claude/bin/codex-session-start.sh +19 -0
- package/runtime/claude/bin/codex-skill-render.mjs +18 -0
- package/runtime/claude/bin/config-get.sh +10 -1
- package/runtime/claude/bin/connect-refresh.sh +16 -0
- package/runtime/claude/bin/corpus_map.py +5 -0
- package/runtime/claude/bin/data/capabilities/claude.json +1480 -0
- package/runtime/claude/bin/genui.sh +19 -0
- package/runtime/claude/bin/graph-batch.sh +1 -1
- package/runtime/claude/bin/graph-op.sh +14 -0
- package/runtime/claude/bin/graph.sh +1 -1
- package/runtime/claude/bin/handoff-pr-backfill.sh +1 -1
- package/runtime/claude/bin/handoff-run.sh +11 -6
- package/runtime/claude/bin/ingest-item.sh +1 -1
- package/runtime/claude/bin/ingest-surface.html +22 -4
- package/runtime/claude/bin/issue.sh +1 -1
- package/runtime/claude/bin/knowledge.sh +1 -1
- package/runtime/claude/bin/lib/card-delivery.sh +329 -0
- package/runtime/claude/bin/lib/config.sh +148 -3
- package/runtime/claude/bin/lib/context.sh +38 -67
- package/runtime/claude/bin/lib/genui-entry.py +36 -0
- package/runtime/claude/bin/lib/git-message.sh +25 -6
- package/runtime/claude/bin/lib/git-sync.sh +12 -4
- package/runtime/claude/bin/lib/greeting.sh +255 -28
- package/runtime/claude/bin/lib/handoff_meta.py +294 -0
- package/runtime/claude/bin/lib/health-footer.sh +83 -2
- package/runtime/claude/bin/lib/identity.sh +31 -10
- package/runtime/claude/bin/lib/instance-registry.sh +71 -0
- package/runtime/claude/bin/lib/local_ci_receipt.py +249 -0
- package/runtime/claude/bin/lib/metrics.sh +121 -8
- package/runtime/claude/bin/lib/notices.sh +36 -0
- package/runtime/claude/bin/lib/record_outcomes.py +729 -0
- package/runtime/claude/bin/lib/reflexes.py +267 -0
- package/runtime/claude/bin/lib/retrieval_scorecard.py +624 -0
- package/runtime/claude/bin/lib/session-record-prompt.txt +18 -0
- package/runtime/claude/bin/lib/session_record.py +3747 -0
- package/runtime/claude/bin/lib/session_trail.py +1983 -0
- package/runtime/claude/bin/lib/settings-drift.sh +8 -5
- package/runtime/claude/bin/lib/startup-restart.sh +41 -0
- package/runtime/claude/bin/lib/worktree-links.sh +92 -0
- package/runtime/claude/bin/memory-push.sh +6 -0
- package/runtime/claude/bin/merge-gate.sh +498 -0
- package/runtime/claude/bin/notify.sh +5 -2
- package/runtime/claude/bin/page-access.sh +103 -0
- package/runtime/claude/bin/person.sh +13 -2
- package/runtime/claude/bin/pi-render-spec.mjs +0 -1
- package/runtime/claude/bin/pi-spirit-discovery.mjs +34 -0
- package/runtime/claude/bin/post-update.sh +181 -0
- package/runtime/claude/bin/prime-render-spec.mjs +0 -1
- package/runtime/claude/bin/publish-artifact.sh +89 -42
- package/runtime/claude/bin/qa-inventory.sh +2 -2
- package/runtime/claude/bin/quest.sh +1 -1
- package/runtime/claude/bin/records.sh +11 -0
- package/runtime/claude/bin/reflexes/05-vitals.sh +9 -0
- package/runtime/claude/bin/reflexes/10-open-items.sh +12 -0
- package/runtime/claude/bin/reflexes/15-retrieval.sh +8 -0
- package/runtime/claude/bin/reflexes/20-nightly.sh +100 -0
- package/runtime/claude/bin/reflexes/20-sandbox.sh +85 -0
- package/runtime/claude/bin/reflexes/30-cost.py +116 -0
- package/runtime/claude/bin/reflexes/40-shells.py +51 -0
- package/runtime/claude/bin/reflexes/README.md +61 -0
- package/runtime/claude/bin/reflexes.sh +7 -0
- package/runtime/claude/bin/runtime-identity.sh +140 -42
- package/runtime/claude/bin/screenshot.sh +77 -0
- package/runtime/claude/bin/scroll.sh +1 -1
- package/runtime/claude/bin/search.sh +31 -5
- package/runtime/claude/bin/session-autosave.sh +6 -3
- package/runtime/claude/bin/session-id.sh +147 -0
- package/runtime/claude/bin/session-log.sh +19 -0
- package/runtime/claude/bin/session-record.sh +26 -0
- package/runtime/claude/bin/session-start.sh +121 -151
- package/runtime/claude/bin/settings.sh +13 -8
- package/runtime/claude/bin/spirit-discovery-claude.sh +4 -0
- package/runtime/claude/bin/spirit-discovery-codex.sh +4 -0
- package/runtime/claude/bin/spirit-discovery-pi.sh +4 -0
- package/runtime/claude/bin/spirit-discovery-prime.sh +4 -0
- package/runtime/claude/bin/spirit-discovery.sh +4 -0
- package/runtime/claude/bin/startup-check.sh +1 -1
- package/runtime/claude/bin/telemetry.sh +11 -4
- package/runtime/claude/bin/test-baseline.sh +33 -5
- package/runtime/claude/bin/todo.sh +1 -1
- package/runtime/claude/bin/worktree-create.sh +15 -45
- package/runtime/claude/bin/worktree.sh +6 -0
- package/runtime/claude/docs/spirit-discovery.md +96 -0
- package/runtime/claude/egregore_runtime/__init__.py +18 -12
- package/runtime/claude/egregore_runtime/access.py +608 -0
- package/runtime/claude/egregore_runtime/access_cli.py +190 -0
- package/runtime/claude/egregore_runtime/adapters/invitation.py +5 -3
- package/runtime/claude/egregore_runtime/adapters/qmd.py +521 -47
- package/runtime/claude/egregore_runtime/admin_entry.py +56 -0
- package/runtime/claude/egregore_runtime/artifacts.py +222 -16
- package/runtime/claude/egregore_runtime/contracts.py +27 -0
- package/runtime/claude/egregore_runtime/eligibility.py +5 -12
- package/runtime/claude/egregore_runtime/episode_binding.py +16 -5
- package/runtime/claude/egregore_runtime/github_issues.py +2 -2
- package/runtime/claude/egregore_runtime/handoff_lookup.py +9 -20
- package/runtime/claude/egregore_runtime/harness_cli.py +674 -149
- package/runtime/claude/egregore_runtime/held.py +2436 -0
- package/runtime/claude/egregore_runtime/hosted_api.py +137 -0
- package/runtime/claude/egregore_runtime/identity.py +196 -65
- package/runtime/claude/egregore_runtime/identity_transfer.py +6 -2
- package/runtime/claude/egregore_runtime/ingest_cli.py +2 -2
- package/runtime/claude/egregore_runtime/ingest_index_cli.py +4 -16
- package/runtime/claude/egregore_runtime/installation.py +119 -0
- package/runtime/claude/egregore_runtime/investigation.py +64 -41
- package/runtime/claude/egregore_runtime/investigation_guidance.py +16 -11
- package/runtime/claude/egregore_runtime/issue_cli.py +51 -32
- package/runtime/claude/egregore_runtime/issue_reporting.py +4 -3
- package/runtime/claude/egregore_runtime/issue_triage_service.py +2 -2
- package/runtime/claude/egregore_runtime/issues.py +12 -6
- package/runtime/claude/egregore_runtime/knowledge.py +331 -5
- package/runtime/claude/egregore_runtime/knowledge_cli.py +57 -17
- package/runtime/claude/egregore_runtime/lifecycle.py +88 -22
- package/runtime/claude/egregore_runtime/lifecycle_cli.py +21 -13
- package/runtime/claude/egregore_runtime/line_ids.py +10 -0
- package/runtime/claude/egregore_runtime/memory_push.py +349 -0
- package/runtime/claude/egregore_runtime/observe.py +64 -25
- package/runtime/claude/egregore_runtime/observers.py +19 -0
- package/runtime/claude/egregore_runtime/optional_modules.py +13 -0
- package/runtime/claude/egregore_runtime/outputs_cli.py +321 -0
- package/runtime/claude/egregore_runtime/policy.py +651 -24
- package/runtime/claude/egregore_runtime/private_result.py +2 -1
- package/runtime/claude/egregore_runtime/projection.py +946 -0
- package/runtime/claude/egregore_runtime/quest_cli.py +20 -23
- package/runtime/claude/egregore_runtime/question_cli.py +15 -11
- package/runtime/claude/egregore_runtime/questions.py +10 -10
- package/runtime/claude/egregore_runtime/quests.py +10 -10
- package/runtime/claude/egregore_runtime/record_publish.py +548 -0
- package/runtime/claude/egregore_runtime/record_subject.py +564 -0
- package/runtime/claude/egregore_runtime/research_ingest.py +2 -4
- package/runtime/claude/egregore_runtime/runtime.py +169 -60
- package/runtime/claude/egregore_runtime/sandbox.py +194 -0
- package/runtime/claude/egregore_runtime/scroll_cli.py +22 -32
- package/runtime/claude/egregore_runtime/scrolls.py +23 -15
- package/runtime/claude/egregore_runtime/shadow.py +262 -0
- package/runtime/claude/egregore_runtime/spirit_discovery.py +487 -0
- package/runtime/claude/egregore_runtime/spirit_discovery_cli.py +25 -0
- package/runtime/claude/egregore_runtime/spirit_discovery_transport.py +18 -0
- package/runtime/claude/egregore_runtime/status.py +101 -44
- package/runtime/claude/egregore_runtime/status_cli.py +13 -5
- package/runtime/claude/egregore_runtime/sync.py +39 -21
- package/runtime/claude/egregore_runtime/taste.py +934 -0
- package/runtime/claude/egregore_runtime/taste_cli.py +242 -0
- package/runtime/claude/egregore_runtime/taste_rules.py +91 -0
- package/runtime/claude/egregore_runtime/telemetry.py +26 -3
- package/runtime/claude/egregore_runtime/todo_cli.py +15 -12
- package/runtime/claude/egregore_runtime/todos.py +3 -2
- package/runtime/claude/egregore_runtime/upgrade.py +85 -58
- package/runtime/claude/egregore_runtime/writeback.py +330 -24
- package/runtime/claude/manifest.json +65 -5
- package/runtime/codex/.claude/context/handoff-claiming.md +32 -0
- package/runtime/codex/.claude/context/notification-consent.md +12 -9
- package/runtime/codex/.claude/skills/view/SKILL.md +438 -0
- package/runtime/codex/.codex/hooks.json +11 -0
- package/runtime/codex/.codex/skills/dark-mode/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/records/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/summon/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/view/assets/compose-scaffold.html +19 -13
- package/runtime/codex/.codex/spec-manifest.json +13 -19
- package/runtime/codex/AGENTS.md +54 -105
- package/runtime/codex/bin/agent.sh +231 -7
- package/runtime/codex/bin/api-call.sh +44 -23
- package/runtime/codex/bin/artifact-register.sh +7 -1
- package/runtime/codex/bin/artifact-writeback.sh +1 -1
- package/runtime/codex/bin/artifacts.sh +66 -265
- package/runtime/codex/bin/attendant.sh +4 -1
- package/runtime/codex/bin/boundary-guard.cjs +1848 -0
- package/runtime/codex/bin/boundary-hook.sh +41 -0
- package/runtime/codex/bin/capture-run.sh +32 -2
- package/runtime/codex/bin/codex-render-spec.mjs +24 -46
- package/runtime/codex/bin/codex-session-start.sh +19 -0
- package/runtime/codex/bin/codex-skill-render.mjs +18 -0
- package/runtime/codex/bin/config-get.sh +10 -1
- package/runtime/codex/bin/connect-refresh.sh +16 -0
- package/runtime/codex/bin/corpus_map.py +5 -0
- package/runtime/codex/bin/data/capabilities/codex.json +1458 -0
- package/runtime/codex/bin/genui.sh +19 -0
- package/runtime/codex/bin/graph-batch.sh +1 -1
- package/runtime/codex/bin/graph-op.sh +14 -0
- package/runtime/codex/bin/graph.sh +1 -1
- package/runtime/codex/bin/handoff-pr-backfill.sh +1 -1
- package/runtime/codex/bin/handoff-run.sh +11 -6
- package/runtime/codex/bin/ingest-item.sh +1 -1
- package/runtime/codex/bin/ingest-surface.html +22 -4
- package/runtime/codex/bin/issue.sh +1 -1
- package/runtime/codex/bin/knowledge.sh +1 -1
- package/runtime/codex/bin/lib/card-delivery.sh +329 -0
- package/runtime/codex/bin/lib/config.sh +148 -3
- package/runtime/codex/bin/lib/context.sh +38 -67
- package/runtime/codex/bin/lib/genui-entry.py +36 -0
- package/runtime/codex/bin/lib/git-message.sh +25 -6
- package/runtime/codex/bin/lib/git-sync.sh +12 -4
- package/runtime/codex/bin/lib/greeting.sh +255 -28
- package/runtime/codex/bin/lib/handoff_meta.py +294 -0
- package/runtime/codex/bin/lib/health-footer.sh +83 -2
- package/runtime/codex/bin/lib/identity.sh +31 -10
- package/runtime/codex/bin/lib/instance-registry.sh +71 -0
- package/runtime/codex/bin/lib/local_ci_receipt.py +249 -0
- package/runtime/codex/bin/lib/metrics.sh +121 -8
- package/runtime/codex/bin/lib/notices.sh +36 -0
- package/runtime/codex/bin/lib/record_outcomes.py +729 -0
- package/runtime/codex/bin/lib/reflexes.py +267 -0
- package/runtime/codex/bin/lib/retrieval_scorecard.py +624 -0
- package/runtime/codex/bin/lib/session-record-prompt.txt +18 -0
- package/runtime/codex/bin/lib/session_record.py +3747 -0
- package/runtime/codex/bin/lib/session_trail.py +1983 -0
- package/runtime/codex/bin/lib/settings-drift.sh +8 -5
- package/runtime/codex/bin/lib/startup-restart.sh +41 -0
- package/runtime/codex/bin/lib/worktree-links.sh +92 -0
- package/runtime/codex/bin/memory-push.sh +6 -0
- package/runtime/codex/bin/merge-gate.sh +498 -0
- package/runtime/codex/bin/notify.sh +5 -2
- package/runtime/codex/bin/page-access.sh +103 -0
- package/runtime/codex/bin/person.sh +13 -2
- package/runtime/codex/bin/pi-render-spec.mjs +0 -1
- package/runtime/codex/bin/pi-spirit-discovery.mjs +34 -0
- package/runtime/codex/bin/post-update.sh +181 -0
- package/runtime/codex/bin/prime-render-spec.mjs +0 -1
- package/runtime/codex/bin/publish-artifact.sh +89 -42
- package/runtime/codex/bin/qa-inventory.sh +2 -2
- package/runtime/codex/bin/quest.sh +1 -1
- package/runtime/codex/bin/records.sh +11 -0
- package/runtime/codex/bin/reflexes/05-vitals.sh +9 -0
- package/runtime/codex/bin/reflexes/10-open-items.sh +12 -0
- package/runtime/codex/bin/reflexes/15-retrieval.sh +8 -0
- package/runtime/codex/bin/reflexes/20-nightly.sh +100 -0
- package/runtime/codex/bin/reflexes/20-sandbox.sh +85 -0
- package/runtime/codex/bin/reflexes/30-cost.py +116 -0
- package/runtime/codex/bin/reflexes/40-shells.py +51 -0
- package/runtime/codex/bin/reflexes/README.md +61 -0
- package/runtime/codex/bin/reflexes.sh +7 -0
- package/runtime/codex/bin/runtime-identity.sh +140 -42
- package/runtime/codex/bin/screenshot.sh +77 -0
- package/runtime/codex/bin/scroll.sh +1 -1
- package/runtime/codex/bin/search.sh +31 -5
- package/runtime/codex/bin/session-autosave.sh +6 -3
- package/runtime/codex/bin/session-id.sh +147 -0
- package/runtime/codex/bin/session-log.sh +19 -0
- package/runtime/codex/bin/session-record.sh +26 -0
- package/runtime/codex/bin/settings.sh +13 -8
- package/runtime/codex/bin/spirit-discovery-claude.sh +4 -0
- package/runtime/codex/bin/spirit-discovery-codex.sh +4 -0
- package/runtime/codex/bin/spirit-discovery-pi.sh +4 -0
- package/runtime/codex/bin/spirit-discovery-prime.sh +4 -0
- package/runtime/codex/bin/spirit-discovery.sh +4 -0
- package/runtime/codex/bin/startup-check.sh +1 -1
- package/runtime/codex/bin/telemetry.sh +11 -4
- package/runtime/codex/bin/test-baseline.sh +33 -5
- package/runtime/codex/bin/todo.sh +1 -1
- package/runtime/codex/bin/worktree-create.sh +15 -45
- package/runtime/codex/bin/worktree.sh +6 -0
- package/runtime/codex/docs/spirit-discovery.md +96 -0
- package/runtime/codex/egregore_runtime/__init__.py +18 -12
- package/runtime/codex/egregore_runtime/access.py +608 -0
- package/runtime/codex/egregore_runtime/access_cli.py +190 -0
- package/runtime/codex/egregore_runtime/adapters/invitation.py +5 -3
- package/runtime/codex/egregore_runtime/adapters/qmd.py +521 -47
- package/runtime/codex/egregore_runtime/admin_entry.py +56 -0
- package/runtime/codex/egregore_runtime/artifacts.py +222 -16
- package/runtime/codex/egregore_runtime/contracts.py +27 -0
- package/runtime/codex/egregore_runtime/eligibility.py +5 -12
- package/runtime/codex/egregore_runtime/episode_binding.py +16 -5
- package/runtime/codex/egregore_runtime/github_issues.py +2 -2
- package/runtime/codex/egregore_runtime/handoff_lookup.py +9 -20
- package/runtime/codex/egregore_runtime/harness_cli.py +674 -149
- package/runtime/codex/egregore_runtime/held.py +2436 -0
- package/runtime/codex/egregore_runtime/hosted_api.py +137 -0
- package/runtime/codex/egregore_runtime/identity.py +196 -65
- package/runtime/codex/egregore_runtime/identity_transfer.py +6 -2
- package/runtime/codex/egregore_runtime/ingest_cli.py +2 -2
- package/runtime/codex/egregore_runtime/ingest_index_cli.py +4 -16
- package/runtime/codex/egregore_runtime/installation.py +119 -0
- package/runtime/codex/egregore_runtime/investigation.py +64 -41
- package/runtime/codex/egregore_runtime/investigation_guidance.py +16 -11
- package/runtime/codex/egregore_runtime/issue_cli.py +51 -32
- package/runtime/codex/egregore_runtime/issue_reporting.py +4 -3
- package/runtime/codex/egregore_runtime/issue_triage_service.py +2 -2
- package/runtime/codex/egregore_runtime/issues.py +12 -6
- package/runtime/codex/egregore_runtime/knowledge.py +331 -5
- package/runtime/codex/egregore_runtime/knowledge_cli.py +57 -17
- package/runtime/codex/egregore_runtime/lifecycle.py +88 -22
- package/runtime/codex/egregore_runtime/lifecycle_cli.py +21 -13
- package/runtime/codex/egregore_runtime/line_ids.py +10 -0
- package/runtime/codex/egregore_runtime/memory_push.py +349 -0
- package/runtime/codex/egregore_runtime/observe.py +64 -25
- package/runtime/codex/egregore_runtime/observers.py +19 -0
- package/runtime/codex/egregore_runtime/optional_modules.py +13 -0
- package/runtime/codex/egregore_runtime/outputs_cli.py +321 -0
- package/runtime/codex/egregore_runtime/policy.py +651 -24
- package/runtime/codex/egregore_runtime/private_result.py +2 -1
- package/runtime/codex/egregore_runtime/projection.py +946 -0
- package/runtime/codex/egregore_runtime/quest_cli.py +20 -23
- package/runtime/codex/egregore_runtime/question_cli.py +15 -11
- package/runtime/codex/egregore_runtime/questions.py +10 -10
- package/runtime/codex/egregore_runtime/quests.py +10 -10
- package/runtime/codex/egregore_runtime/record_publish.py +548 -0
- package/runtime/codex/egregore_runtime/record_subject.py +564 -0
- package/runtime/codex/egregore_runtime/research_ingest.py +2 -4
- package/runtime/codex/egregore_runtime/runtime.py +169 -60
- package/runtime/codex/egregore_runtime/sandbox.py +194 -0
- package/runtime/codex/egregore_runtime/scroll_cli.py +22 -32
- package/runtime/codex/egregore_runtime/scrolls.py +23 -15
- package/runtime/codex/egregore_runtime/shadow.py +262 -0
- package/runtime/codex/egregore_runtime/spirit_discovery.py +487 -0
- package/runtime/codex/egregore_runtime/spirit_discovery_cli.py +25 -0
- package/runtime/codex/egregore_runtime/spirit_discovery_transport.py +18 -0
- package/runtime/codex/egregore_runtime/status.py +101 -44
- package/runtime/codex/egregore_runtime/status_cli.py +13 -5
- package/runtime/codex/egregore_runtime/sync.py +39 -21
- package/runtime/codex/egregore_runtime/taste.py +934 -0
- package/runtime/codex/egregore_runtime/taste_cli.py +242 -0
- package/runtime/codex/egregore_runtime/taste_rules.py +91 -0
- package/runtime/codex/egregore_runtime/telemetry.py +26 -3
- package/runtime/codex/egregore_runtime/todo_cli.py +15 -12
- package/runtime/codex/egregore_runtime/todos.py +3 -2
- package/runtime/codex/egregore_runtime/upgrade.py +85 -58
- package/runtime/codex/egregore_runtime/writeback.py +330 -24
- package/runtime/codex/manifest.json +66 -5
- package/runtime/pi/.claude/context/handoff-claiming.md +32 -0
- package/runtime/pi/.claude/context/notification-consent.md +12 -9
- package/runtime/pi/.claude/skills/view/SKILL.md +438 -0
- package/runtime/pi/.codex/hooks.json +11 -0
- package/runtime/pi/.codex/skills/dark-mode/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/records/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/summon/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +19 -13
- package/runtime/pi/.codex/spec-manifest.json +13 -19
- package/runtime/pi/.pi/APPEND_SYSTEM.md +53 -99
- package/runtime/pi/.pi/extensions/egregore.ts +13 -1
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +54 -105
- package/runtime/pi/bin/agent.sh +231 -7
- package/runtime/pi/bin/api-call.sh +44 -23
- package/runtime/pi/bin/artifact-register.sh +7 -1
- package/runtime/pi/bin/artifact-writeback.sh +1 -1
- package/runtime/pi/bin/artifacts.sh +66 -265
- package/runtime/pi/bin/attendant.sh +4 -1
- package/runtime/pi/bin/boundary-guard.cjs +1848 -0
- package/runtime/pi/bin/boundary-hook.sh +41 -0
- package/runtime/pi/bin/capture-run.sh +32 -2
- package/runtime/pi/bin/codex-render-spec.mjs +24 -46
- package/runtime/pi/bin/codex-session-start.sh +19 -0
- package/runtime/pi/bin/codex-skill-render.mjs +18 -0
- package/runtime/pi/bin/config-get.sh +10 -1
- package/runtime/pi/bin/connect-refresh.sh +16 -0
- package/runtime/pi/bin/corpus_map.py +5 -0
- package/runtime/pi/bin/data/capabilities/pi.json +1458 -0
- package/runtime/pi/bin/genui.sh +19 -0
- package/runtime/pi/bin/graph-batch.sh +1 -1
- package/runtime/pi/bin/graph-op.sh +14 -0
- package/runtime/pi/bin/graph.sh +1 -1
- package/runtime/pi/bin/handoff-pr-backfill.sh +1 -1
- package/runtime/pi/bin/handoff-run.sh +11 -6
- package/runtime/pi/bin/ingest-item.sh +1 -1
- package/runtime/pi/bin/ingest-surface.html +22 -4
- package/runtime/pi/bin/issue.sh +1 -1
- package/runtime/pi/bin/knowledge.sh +1 -1
- package/runtime/pi/bin/lib/card-delivery.sh +329 -0
- package/runtime/pi/bin/lib/config.sh +148 -3
- package/runtime/pi/bin/lib/context.sh +38 -67
- package/runtime/pi/bin/lib/genui-entry.py +36 -0
- package/runtime/pi/bin/lib/git-message.sh +25 -6
- package/runtime/pi/bin/lib/git-sync.sh +12 -4
- package/runtime/pi/bin/lib/greeting.sh +255 -28
- package/runtime/pi/bin/lib/handoff_meta.py +294 -0
- package/runtime/pi/bin/lib/health-footer.sh +83 -2
- package/runtime/pi/bin/lib/identity.sh +31 -10
- package/runtime/pi/bin/lib/instance-registry.sh +71 -0
- package/runtime/pi/bin/lib/local_ci_receipt.py +249 -0
- package/runtime/pi/bin/lib/metrics.sh +121 -8
- package/runtime/pi/bin/lib/notices.sh +36 -0
- package/runtime/pi/bin/lib/record_outcomes.py +729 -0
- package/runtime/pi/bin/lib/reflexes.py +267 -0
- package/runtime/pi/bin/lib/retrieval_scorecard.py +624 -0
- package/runtime/pi/bin/lib/session-record-prompt.txt +18 -0
- package/runtime/pi/bin/lib/session_record.py +3747 -0
- package/runtime/pi/bin/lib/session_trail.py +1983 -0
- package/runtime/pi/bin/lib/settings-drift.sh +8 -5
- package/runtime/pi/bin/lib/startup-restart.sh +41 -0
- package/runtime/pi/bin/lib/worktree-links.sh +92 -0
- package/runtime/pi/bin/memory-push.sh +6 -0
- package/runtime/pi/bin/merge-gate.sh +498 -0
- package/runtime/pi/bin/notify.sh +5 -2
- package/runtime/pi/bin/page-access.sh +103 -0
- package/runtime/pi/bin/person.sh +13 -2
- package/runtime/pi/bin/pi-branch-policy.mjs +37 -0
- package/runtime/pi/bin/pi-observe-context.mjs +97 -4
- package/runtime/pi/bin/pi-render-spec.mjs +0 -1
- package/runtime/pi/bin/pi-session-start.sh +4 -1
- package/runtime/pi/bin/pi-spirit-discovery.mjs +34 -0
- package/runtime/pi/bin/post-update.sh +181 -0
- package/runtime/pi/bin/prime-render-spec.mjs +0 -1
- package/runtime/pi/bin/publish-artifact.sh +89 -42
- package/runtime/pi/bin/qa-inventory.sh +2 -2
- package/runtime/pi/bin/quest.sh +1 -1
- package/runtime/pi/bin/records.sh +11 -0
- package/runtime/pi/bin/reflexes/05-vitals.sh +9 -0
- package/runtime/pi/bin/reflexes/10-open-items.sh +12 -0
- package/runtime/pi/bin/reflexes/15-retrieval.sh +8 -0
- package/runtime/pi/bin/reflexes/20-nightly.sh +100 -0
- package/runtime/pi/bin/reflexes/20-sandbox.sh +85 -0
- package/runtime/pi/bin/reflexes/30-cost.py +116 -0
- package/runtime/pi/bin/reflexes/40-shells.py +51 -0
- package/runtime/pi/bin/reflexes/README.md +61 -0
- package/runtime/pi/bin/reflexes.sh +7 -0
- package/runtime/pi/bin/runtime-identity.sh +140 -42
- package/runtime/pi/bin/screenshot.sh +77 -0
- package/runtime/pi/bin/scroll.sh +1 -1
- package/runtime/pi/bin/search.sh +31 -5
- package/runtime/pi/bin/session-autosave.sh +6 -3
- package/runtime/pi/bin/session-id.sh +147 -0
- package/runtime/pi/bin/session-log.sh +19 -0
- package/runtime/pi/bin/session-record.sh +26 -0
- package/runtime/pi/bin/settings.sh +13 -8
- package/runtime/pi/bin/spirit-discovery-claude.sh +4 -0
- package/runtime/pi/bin/spirit-discovery-codex.sh +4 -0
- package/runtime/pi/bin/spirit-discovery-pi.sh +4 -0
- package/runtime/pi/bin/spirit-discovery-prime.sh +4 -0
- package/runtime/pi/bin/spirit-discovery.sh +4 -0
- package/runtime/pi/bin/startup-check.sh +1 -1
- package/runtime/pi/bin/telemetry.sh +11 -4
- package/runtime/pi/bin/test-baseline.sh +33 -5
- package/runtime/pi/bin/todo.sh +1 -1
- package/runtime/pi/bin/worktree-create.sh +15 -45
- package/runtime/pi/bin/worktree.sh +6 -0
- package/runtime/pi/docs/spirit-discovery.md +96 -0
- package/runtime/pi/egregore_runtime/__init__.py +18 -12
- package/runtime/pi/egregore_runtime/access.py +608 -0
- package/runtime/pi/egregore_runtime/access_cli.py +190 -0
- package/runtime/pi/egregore_runtime/adapters/invitation.py +5 -3
- package/runtime/pi/egregore_runtime/adapters/qmd.py +521 -47
- package/runtime/pi/egregore_runtime/admin_entry.py +56 -0
- package/runtime/pi/egregore_runtime/artifacts.py +222 -16
- package/runtime/pi/egregore_runtime/contracts.py +27 -0
- package/runtime/pi/egregore_runtime/eligibility.py +5 -12
- package/runtime/pi/egregore_runtime/episode_binding.py +16 -5
- package/runtime/pi/egregore_runtime/github_issues.py +2 -2
- package/runtime/pi/egregore_runtime/handoff_lookup.py +9 -20
- package/runtime/pi/egregore_runtime/harness_cli.py +674 -149
- package/runtime/pi/egregore_runtime/held.py +2436 -0
- package/runtime/pi/egregore_runtime/hosted_api.py +137 -0
- package/runtime/pi/egregore_runtime/identity.py +196 -65
- package/runtime/pi/egregore_runtime/identity_transfer.py +6 -2
- package/runtime/pi/egregore_runtime/ingest_cli.py +2 -2
- package/runtime/pi/egregore_runtime/ingest_index_cli.py +4 -16
- package/runtime/pi/egregore_runtime/installation.py +119 -0
- package/runtime/pi/egregore_runtime/investigation.py +64 -41
- package/runtime/pi/egregore_runtime/investigation_guidance.py +16 -11
- package/runtime/pi/egregore_runtime/issue_cli.py +51 -32
- package/runtime/pi/egregore_runtime/issue_reporting.py +4 -3
- package/runtime/pi/egregore_runtime/issue_triage_service.py +2 -2
- package/runtime/pi/egregore_runtime/issues.py +12 -6
- package/runtime/pi/egregore_runtime/knowledge.py +331 -5
- package/runtime/pi/egregore_runtime/knowledge_cli.py +57 -17
- package/runtime/pi/egregore_runtime/lifecycle.py +88 -22
- package/runtime/pi/egregore_runtime/lifecycle_cli.py +21 -13
- package/runtime/pi/egregore_runtime/line_ids.py +10 -0
- package/runtime/pi/egregore_runtime/memory_push.py +349 -0
- package/runtime/pi/egregore_runtime/observe.py +64 -25
- package/runtime/pi/egregore_runtime/observers.py +19 -0
- package/runtime/pi/egregore_runtime/optional_modules.py +13 -0
- package/runtime/pi/egregore_runtime/outputs_cli.py +321 -0
- package/runtime/pi/egregore_runtime/policy.py +651 -24
- package/runtime/pi/egregore_runtime/private_result.py +2 -1
- package/runtime/pi/egregore_runtime/projection.py +946 -0
- package/runtime/pi/egregore_runtime/quest_cli.py +20 -23
- package/runtime/pi/egregore_runtime/question_cli.py +15 -11
- package/runtime/pi/egregore_runtime/questions.py +10 -10
- package/runtime/pi/egregore_runtime/quests.py +10 -10
- package/runtime/pi/egregore_runtime/record_publish.py +548 -0
- package/runtime/pi/egregore_runtime/record_subject.py +564 -0
- package/runtime/pi/egregore_runtime/research_ingest.py +2 -4
- package/runtime/pi/egregore_runtime/runtime.py +169 -60
- package/runtime/pi/egregore_runtime/sandbox.py +194 -0
- package/runtime/pi/egregore_runtime/scroll_cli.py +22 -32
- package/runtime/pi/egregore_runtime/scrolls.py +23 -15
- package/runtime/pi/egregore_runtime/shadow.py +262 -0
- package/runtime/pi/egregore_runtime/spirit_discovery.py +487 -0
- package/runtime/pi/egregore_runtime/spirit_discovery_cli.py +25 -0
- package/runtime/pi/egregore_runtime/spirit_discovery_transport.py +18 -0
- package/runtime/pi/egregore_runtime/status.py +101 -44
- package/runtime/pi/egregore_runtime/status_cli.py +13 -5
- package/runtime/pi/egregore_runtime/sync.py +39 -21
- package/runtime/pi/egregore_runtime/taste.py +934 -0
- package/runtime/pi/egregore_runtime/taste_cli.py +242 -0
- package/runtime/pi/egregore_runtime/taste_rules.py +91 -0
- package/runtime/pi/egregore_runtime/telemetry.py +26 -3
- package/runtime/pi/egregore_runtime/todo_cli.py +15 -12
- package/runtime/pi/egregore_runtime/todos.py +3 -2
- package/runtime/pi/egregore_runtime/upgrade.py +85 -58
- package/runtime/pi/egregore_runtime/writeback.py +330 -24
- package/runtime/pi/manifest.json +66 -5
- package/runtime/prime/.claude/context/handoff-claiming.md +32 -0
- package/runtime/prime/.claude/context/notification-consent.md +12 -9
- package/runtime/prime/.claude/skills/view/SKILL.md +438 -0
- package/runtime/prime/.codex/hooks.json +11 -0
- package/runtime/prime/.codex/skills/dark-mode/SKILL.md +1 -1
- package/runtime/prime/.codex/skills/records/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/summon/SKILL.md +1 -1
- package/runtime/prime/.codex/skills/view/assets/compose-scaffold.html +19 -13
- package/runtime/prime/.codex/spec-manifest.json +13 -19
- package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +53 -99
- package/runtime/prime/.prime/agent/extensions/egregore.ts +14 -1
- package/runtime/prime/.prime/agent/skills/egregore/SKILL.md +14 -6
- package/runtime/prime/.prime/agent/skills/egregore/src/egregore/__init__.py +66 -1
- package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
- package/runtime/prime/AGENTS.md +54 -105
- package/runtime/prime/bin/agent.sh +231 -7
- package/runtime/prime/bin/api-call.sh +44 -23
- package/runtime/prime/bin/artifact-register.sh +7 -1
- package/runtime/prime/bin/artifact-writeback.sh +1 -1
- package/runtime/prime/bin/artifacts.sh +66 -265
- package/runtime/prime/bin/attendant.sh +4 -1
- package/runtime/prime/bin/boundary-guard.cjs +1848 -0
- package/runtime/prime/bin/boundary-hook.sh +41 -0
- package/runtime/prime/bin/capture-run.sh +32 -2
- package/runtime/prime/bin/codex-render-spec.mjs +24 -46
- package/runtime/prime/bin/codex-session-start.sh +19 -0
- package/runtime/prime/bin/codex-skill-render.mjs +18 -0
- package/runtime/prime/bin/config-get.sh +10 -1
- package/runtime/prime/bin/connect-refresh.sh +16 -0
- package/runtime/prime/bin/corpus_map.py +5 -0
- package/runtime/prime/bin/data/capabilities/prime.json +1458 -0
- package/runtime/prime/bin/genui.sh +19 -0
- package/runtime/prime/bin/graph-batch.sh +1 -1
- package/runtime/prime/bin/graph-op.sh +14 -0
- package/runtime/prime/bin/graph.sh +1 -1
- package/runtime/prime/bin/handoff-pr-backfill.sh +1 -1
- package/runtime/prime/bin/handoff-run.sh +11 -6
- package/runtime/prime/bin/ingest-item.sh +1 -1
- package/runtime/prime/bin/ingest-surface.html +22 -4
- package/runtime/prime/bin/issue.sh +1 -1
- package/runtime/prime/bin/knowledge.sh +1 -1
- package/runtime/prime/bin/lib/card-delivery.sh +329 -0
- package/runtime/prime/bin/lib/config.sh +148 -3
- package/runtime/prime/bin/lib/context.sh +38 -67
- package/runtime/prime/bin/lib/genui-entry.py +36 -0
- package/runtime/prime/bin/lib/git-message.sh +25 -6
- package/runtime/prime/bin/lib/git-sync.sh +12 -4
- package/runtime/prime/bin/lib/greeting.sh +255 -28
- package/runtime/prime/bin/lib/handoff_meta.py +294 -0
- package/runtime/prime/bin/lib/health-footer.sh +83 -2
- package/runtime/prime/bin/lib/identity.sh +31 -10
- package/runtime/prime/bin/lib/instance-registry.sh +71 -0
- package/runtime/prime/bin/lib/local_ci_receipt.py +249 -0
- package/runtime/prime/bin/lib/metrics.sh +121 -8
- package/runtime/prime/bin/lib/notices.sh +36 -0
- package/runtime/prime/bin/lib/record_outcomes.py +729 -0
- package/runtime/prime/bin/lib/reflexes.py +267 -0
- package/runtime/prime/bin/lib/retrieval_scorecard.py +624 -0
- package/runtime/prime/bin/lib/session-record-prompt.txt +18 -0
- package/runtime/prime/bin/lib/session_record.py +3747 -0
- package/runtime/prime/bin/lib/session_trail.py +1983 -0
- package/runtime/prime/bin/lib/settings-drift.sh +8 -5
- package/runtime/prime/bin/lib/startup-restart.sh +41 -0
- package/runtime/prime/bin/lib/worktree-links.sh +92 -0
- package/runtime/prime/bin/memory-push.sh +6 -0
- package/runtime/prime/bin/merge-gate.sh +498 -0
- package/runtime/prime/bin/notify.sh +5 -2
- package/runtime/prime/bin/page-access.sh +103 -0
- package/runtime/prime/bin/person.sh +13 -2
- package/runtime/prime/bin/pi-branch-policy.mjs +37 -0
- package/runtime/prime/bin/pi-observe-context.mjs +97 -4
- package/runtime/prime/bin/pi-render-spec.mjs +0 -1
- package/runtime/prime/bin/pi-spirit-discovery.mjs +34 -0
- package/runtime/prime/bin/post-update.sh +181 -0
- package/runtime/prime/bin/prime-render-spec.mjs +0 -1
- package/runtime/prime/bin/prime-session-start.sh +3 -1
- package/runtime/prime/bin/publish-artifact.sh +89 -42
- package/runtime/prime/bin/qa-inventory.sh +2 -2
- package/runtime/prime/bin/quest.sh +1 -1
- package/runtime/prime/bin/records.sh +11 -0
- package/runtime/prime/bin/reflexes/05-vitals.sh +9 -0
- package/runtime/prime/bin/reflexes/10-open-items.sh +12 -0
- package/runtime/prime/bin/reflexes/15-retrieval.sh +8 -0
- package/runtime/prime/bin/reflexes/20-nightly.sh +100 -0
- package/runtime/prime/bin/reflexes/20-sandbox.sh +85 -0
- package/runtime/prime/bin/reflexes/30-cost.py +116 -0
- package/runtime/prime/bin/reflexes/40-shells.py +51 -0
- package/runtime/prime/bin/reflexes/README.md +61 -0
- package/runtime/prime/bin/reflexes.sh +7 -0
- package/runtime/prime/bin/runtime-identity.sh +140 -42
- package/runtime/prime/bin/screenshot.sh +77 -0
- package/runtime/prime/bin/scroll.sh +1 -1
- package/runtime/prime/bin/search.sh +31 -5
- package/runtime/prime/bin/session-autosave.sh +6 -3
- package/runtime/prime/bin/session-id.sh +147 -0
- package/runtime/prime/bin/session-log.sh +19 -0
- package/runtime/prime/bin/session-record.sh +26 -0
- package/runtime/prime/bin/settings.sh +13 -8
- package/runtime/prime/bin/spirit-discovery-claude.sh +4 -0
- package/runtime/prime/bin/spirit-discovery-codex.sh +4 -0
- package/runtime/prime/bin/spirit-discovery-pi.sh +4 -0
- package/runtime/prime/bin/spirit-discovery-prime.sh +4 -0
- package/runtime/prime/bin/spirit-discovery.sh +4 -0
- package/runtime/prime/bin/startup-check.sh +1 -1
- package/runtime/prime/bin/telemetry.sh +11 -4
- package/runtime/prime/bin/test-baseline.sh +33 -5
- package/runtime/prime/bin/todo.sh +1 -1
- package/runtime/prime/bin/worktree-create.sh +15 -45
- package/runtime/prime/bin/worktree.sh +6 -0
- package/runtime/prime/docs/spirit-discovery.md +96 -0
- package/runtime/prime/egregore_runtime/__init__.py +18 -12
- package/runtime/prime/egregore_runtime/access.py +608 -0
- package/runtime/prime/egregore_runtime/access_cli.py +190 -0
- package/runtime/prime/egregore_runtime/adapters/invitation.py +5 -3
- package/runtime/prime/egregore_runtime/adapters/qmd.py +521 -47
- package/runtime/prime/egregore_runtime/admin_entry.py +56 -0
- package/runtime/prime/egregore_runtime/artifacts.py +222 -16
- package/runtime/prime/egregore_runtime/contracts.py +27 -0
- package/runtime/prime/egregore_runtime/eligibility.py +5 -12
- package/runtime/prime/egregore_runtime/episode_binding.py +16 -5
- package/runtime/prime/egregore_runtime/github_issues.py +2 -2
- package/runtime/prime/egregore_runtime/handoff_lookup.py +9 -20
- package/runtime/prime/egregore_runtime/harness_cli.py +674 -149
- package/runtime/prime/egregore_runtime/held.py +2436 -0
- package/runtime/prime/egregore_runtime/hosted_api.py +137 -0
- package/runtime/prime/egregore_runtime/identity.py +196 -65
- package/runtime/prime/egregore_runtime/identity_transfer.py +6 -2
- package/runtime/prime/egregore_runtime/ingest_cli.py +2 -2
- package/runtime/prime/egregore_runtime/ingest_index_cli.py +4 -16
- package/runtime/prime/egregore_runtime/installation.py +119 -0
- package/runtime/prime/egregore_runtime/investigation.py +64 -41
- package/runtime/prime/egregore_runtime/investigation_guidance.py +16 -11
- package/runtime/prime/egregore_runtime/issue_cli.py +51 -32
- package/runtime/prime/egregore_runtime/issue_reporting.py +4 -3
- package/runtime/prime/egregore_runtime/issue_triage_service.py +2 -2
- package/runtime/prime/egregore_runtime/issues.py +12 -6
- package/runtime/prime/egregore_runtime/knowledge.py +331 -5
- package/runtime/prime/egregore_runtime/knowledge_cli.py +57 -17
- package/runtime/prime/egregore_runtime/lifecycle.py +88 -22
- package/runtime/prime/egregore_runtime/lifecycle_cli.py +21 -13
- package/runtime/prime/egregore_runtime/line_ids.py +10 -0
- package/runtime/prime/egregore_runtime/memory_push.py +349 -0
- package/runtime/prime/egregore_runtime/observe.py +64 -25
- package/runtime/prime/egregore_runtime/observers.py +19 -0
- package/runtime/prime/egregore_runtime/optional_modules.py +13 -0
- package/runtime/prime/egregore_runtime/outputs_cli.py +321 -0
- package/runtime/prime/egregore_runtime/policy.py +651 -24
- package/runtime/prime/egregore_runtime/private_result.py +2 -1
- package/runtime/prime/egregore_runtime/projection.py +946 -0
- package/runtime/prime/egregore_runtime/quest_cli.py +20 -23
- package/runtime/prime/egregore_runtime/question_cli.py +15 -11
- package/runtime/prime/egregore_runtime/questions.py +10 -10
- package/runtime/prime/egregore_runtime/quests.py +10 -10
- package/runtime/prime/egregore_runtime/record_publish.py +548 -0
- package/runtime/prime/egregore_runtime/record_subject.py +564 -0
- package/runtime/prime/egregore_runtime/research_ingest.py +2 -4
- package/runtime/prime/egregore_runtime/runtime.py +169 -60
- package/runtime/prime/egregore_runtime/sandbox.py +194 -0
- package/runtime/prime/egregore_runtime/scroll_cli.py +22 -32
- package/runtime/prime/egregore_runtime/scrolls.py +23 -15
- package/runtime/prime/egregore_runtime/shadow.py +262 -0
- package/runtime/prime/egregore_runtime/spirit_discovery.py +487 -0
- package/runtime/prime/egregore_runtime/spirit_discovery_cli.py +25 -0
- package/runtime/prime/egregore_runtime/spirit_discovery_transport.py +18 -0
- package/runtime/prime/egregore_runtime/status.py +101 -44
- package/runtime/prime/egregore_runtime/status_cli.py +13 -5
- package/runtime/prime/egregore_runtime/sync.py +39 -21
- package/runtime/prime/egregore_runtime/taste.py +934 -0
- package/runtime/prime/egregore_runtime/taste_cli.py +242 -0
- package/runtime/prime/egregore_runtime/taste_rules.py +91 -0
- package/runtime/prime/egregore_runtime/telemetry.py +26 -3
- package/runtime/prime/egregore_runtime/todo_cli.py +15 -12
- package/runtime/prime/egregore_runtime/todos.py +3 -2
- package/runtime/prime/egregore_runtime/upgrade.py +85 -58
- package/runtime/prime/egregore_runtime/writeback.py +330 -24
- package/runtime/prime/manifest.json +66 -5
- package/runtime/claude/bin/thread.sh +0 -9
- package/runtime/claude/egregore_runtime/admin_gate.py +0 -102
- package/runtime/claude/egregore_runtime/thread_cli.py +0 -173
- package/runtime/claude/egregore_runtime/threads.py +0 -521
- package/runtime/codex/bin/thread.sh +0 -9
- package/runtime/codex/egregore_runtime/admin_gate.py +0 -102
- package/runtime/codex/egregore_runtime/thread_cli.py +0 -173
- package/runtime/codex/egregore_runtime/threads.py +0 -521
- package/runtime/pi/bin/thread.sh +0 -9
- package/runtime/pi/egregore_runtime/admin_gate.py +0 -102
- package/runtime/pi/egregore_runtime/thread_cli.py +0 -173
- package/runtime/pi/egregore_runtime/threads.py +0 -521
- package/runtime/prime/bin/thread.sh +0 -9
- package/runtime/prime/egregore_runtime/admin_gate.py +0 -102
- package/runtime/prime/egregore_runtime/thread_cli.py +0 -173
- package/runtime/prime/egregore_runtime/threads.py +0 -521
|
@@ -22,6 +22,76 @@
|
|
|
22
22
|
# Output: the footer lines on stdout, each already indented two spaces.
|
|
23
23
|
# Returns 0 when nothing failed, 1 when at least one dimension failed.
|
|
24
24
|
|
|
25
|
+
# Dated, release-delivered incident copy, not a live availability check. Keep
|
|
26
|
+
# the launcher counterpart aligned; launcher-connected-status.test.js checks
|
|
27
|
+
# the actual output of both implementations. No network or credential reads.
|
|
28
|
+
_hosted_recovery_notice() {
|
|
29
|
+
[ "${LOCAL_MODE:-true}" != "true" ] || return 0
|
|
30
|
+
local origin now
|
|
31
|
+
[ -f "${CONFIG:-}" ] || return 0
|
|
32
|
+
origin=$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null) || return 0
|
|
33
|
+
case "$origin" in
|
|
34
|
+
https://api.egregore.xyz|https://api.egregore.xyz/|https://egregore-production-55f2.up.railway.app|https://egregore-production-55f2.up.railway.app/) ;;
|
|
35
|
+
*) return 0 ;;
|
|
36
|
+
esac
|
|
37
|
+
now=$(date -u +%s 2>/dev/null) || now=0
|
|
38
|
+
# A stale bundled notice never presents itself as current service status.
|
|
39
|
+
if [ "$now" -ge 1792627200 ] 2>/dev/null && [ "$now" -lt 1792800000 ] 2>/dev/null; then
|
|
40
|
+
printf '%s\n' ' ◐ Service recovery · 22 Oct 2026' \
|
|
41
|
+
' Some connected services are temporarily unavailable' \
|
|
42
|
+
' during security recovery.'
|
|
43
|
+
else
|
|
44
|
+
printf '%s\n' ' ◐ Service recovery · last update 22 Oct 2026' \
|
|
45
|
+
' Some connected services were unavailable at this update.' \
|
|
46
|
+
' Current hosted availability has not been checked.'
|
|
47
|
+
fi
|
|
48
|
+
printf '%s\n' ' Local memory and search remain available.' \
|
|
49
|
+
' Keep your existing Egregore; you do not need to set it up again.'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Recorded in .egregore-state.json by bin/runtime-identity.sh when it renews,
|
|
53
|
+
# or cannot renew, an organization key retired in the October 2026 security
|
|
54
|
+
# reset. Local state only; no network. The renewal shows once; the sign-in
|
|
55
|
+
# line shows each session until a renewal works.
|
|
56
|
+
_hosted_key_notice() {
|
|
57
|
+
[ "${LOCAL_MODE:-true}" != "true" ] || return 0
|
|
58
|
+
local state_file="${STATE_FILE:-}" file tmp
|
|
59
|
+
[ -n "$state_file" ] && [ -f "$state_file" ] || return 0
|
|
60
|
+
case "$(jq -r '.hosted_key_notice.state // empty' "$state_file" 2>/dev/null)" in
|
|
61
|
+
renewed)
|
|
62
|
+
printf '%s\n' " ↻ Hosted services renewed this organization's key after" \
|
|
63
|
+
' the October security reset. Your memory, files and' \
|
|
64
|
+
' history are untouched.'
|
|
65
|
+
file=$(realpath "$state_file" 2>/dev/null) || file="$state_file"
|
|
66
|
+
tmp=$(mktemp "$file.XXXXXX" 2>/dev/null) || return 0
|
|
67
|
+
jq 'if .hosted_key_notice.state == "renewed" then del(.hosted_key_notice) else . end' \
|
|
68
|
+
"$file" > "$tmp" 2>/dev/null && [ -s "$tmp" ] && mv "$tmp" "$file" || rm -f "$tmp"
|
|
69
|
+
;;
|
|
70
|
+
needs_sign_in)
|
|
71
|
+
printf '%s\n' ' ◐ Hosted services need a fresh key after the October' \
|
|
72
|
+
' security reset. Your memory, files and history are' \
|
|
73
|
+
' untouched. Run bash bin/github-auth.sh and start a new' \
|
|
74
|
+
' session — it renews on its own.'
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
return 0
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# A Connected org whose saved api_url is not a plain web address sends nothing
|
|
81
|
+
# to hosted services (bin/lib/config.sh refuses it), and /update rewrites only
|
|
82
|
+
# a plain retired address. Say so each session until egregore.json is fixed.
|
|
83
|
+
# Needs config.sh's resolver; reads local config only.
|
|
84
|
+
_hosted_address_notice() {
|
|
85
|
+
[ "${LOCAL_MODE:-true}" != "true" ] || return 0
|
|
86
|
+
[ -f "${CONFIG:-}" ] || return 0
|
|
87
|
+
command -v _config_api_url >/dev/null 2>&1 || return 0
|
|
88
|
+
EGREGORE_ADDRESS_NOTICE=shown _config_api_url >/dev/null 2>&1 && return 0
|
|
89
|
+
printf '%s\n' " ◐ Hosted services are off: api_url in egregore.json isn't" \
|
|
90
|
+
' a plain web address, so nothing is sent to it. Correct it' \
|
|
91
|
+
" (the hosted address is ${EGREGORE_HOSTED_API_ORIGIN:-https://api.egregore.xyz})" \
|
|
92
|
+
' and start a new session. Local memory and search work.'
|
|
93
|
+
}
|
|
94
|
+
|
|
25
95
|
_health_footer_label() {
|
|
26
96
|
case "$1" in
|
|
27
97
|
github) printf 'github' ;;
|
|
@@ -65,7 +135,16 @@ _health_footer_check() {
|
|
|
65
135
|
}
|
|
66
136
|
|
|
67
137
|
_render_health_footer() {
|
|
68
|
-
local width="${LINE_WIDTH:-65}" failed=0
|
|
138
|
+
local width="${LINE_WIDTH:-65}" failed=0 recovery_notice key_notice address_notice local_only=""
|
|
139
|
+
address_notice=$(_hosted_address_notice)
|
|
140
|
+
[ -z "$address_notice" ] || { printf '%s\n' "$address_notice"; local_only=1; }
|
|
141
|
+
recovery_notice=$(_hosted_recovery_notice)
|
|
142
|
+
[ -z "$recovery_notice" ] || printf '%s\n' "$recovery_notice"
|
|
143
|
+
key_notice=$(_hosted_key_notice)
|
|
144
|
+
[ -z "$key_notice" ] || printf '%s\n' "$key_notice"
|
|
145
|
+
# Hosted services stay out of reach for this person until the key renews.
|
|
146
|
+
[ -z "$recovery_notice" ] || local_only=1
|
|
147
|
+
case "$key_notice" in *"need a fresh key"*) local_only=1 ;; esac
|
|
69
148
|
_health_footer_check github "${HEALTH_GITHUB:-skip}" || failed=1
|
|
70
149
|
_health_footer_check git "${HEALTH_GIT:-skip}" || failed=1
|
|
71
150
|
_health_footer_check memory "${HEALTH_MEMORY:-skip}" || failed=1
|
|
@@ -87,7 +166,9 @@ _render_health_footer() {
|
|
|
87
166
|
fi
|
|
88
167
|
|
|
89
168
|
local left right pad
|
|
90
|
-
if [ "$
|
|
169
|
+
if [ -n "$local_only" ]; then
|
|
170
|
+
left=" ✓ local checks ready"
|
|
171
|
+
elif [ "${FRAMEWORK_UPDATED:-false}" = "true" ]; then
|
|
91
172
|
left=" ◆ updated"
|
|
92
173
|
else
|
|
93
174
|
left=" ✓ ready"
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
# 3. Graph person lookup (existing team member on new machine)
|
|
8
8
|
# 4. Global git config user.name (last resort)
|
|
9
9
|
#
|
|
10
|
-
# Inputs: STATE_FILE, ENV_FILE, SCRIPT_DIR, HEALTH_GITHUB
|
|
10
|
+
# Inputs: STATE_FILE, ENV_FILE, SCRIPT_DIR, HEALTH_GITHUB; optionally
|
|
11
|
+
# EGREGORE_START_HARNESS with EGREGORE_NATIVE_SESSION_ID/_HARNESS
|
|
11
12
|
# Outputs: AUTHOR, DISPLAY_NAME_STATE, FIRST_SESSION, HEALTH_GITHUB,
|
|
12
13
|
# EGREGORE_USER, EGREGORE_ORG, EGREGORE_SESSION_ID
|
|
13
|
-
# Writes .egregore-session-id and ~/.egregore/session-*.id
|
|
14
|
+
# Writes .egregore-session-id and ~/.egregore/session-*.id, and
|
|
15
|
+
# maps the native session id via bin/session-id.sh
|
|
14
16
|
|
|
15
17
|
STORED_USERNAME=""
|
|
16
18
|
FIRST_SESSION=""
|
|
@@ -192,16 +194,35 @@ fi
|
|
|
192
194
|
# --- Export telemetry identity env vars ---
|
|
193
195
|
export EGREGORE_USER="$AUTHOR"
|
|
194
196
|
export EGREGORE_ORG="$(jq -r '.slug // .github_org // empty' "$SCRIPT_DIR/egregore.json" 2>/dev/null || true)"
|
|
195
|
-
export EGREGORE_SESSION_ID="$(date -u +%Y%m%dT%H%M%S)-${AUTHOR}-$$"
|
|
196
|
-
|
|
197
|
-
# Persist session ID to file so telemetry.sh can read it
|
|
198
|
-
# (env vars from hooks don't propagate into the Claude Code agent)
|
|
199
197
|
SESSION_ID_DIR="$HOME/.egregore"
|
|
200
198
|
mkdir -p "$SESSION_ID_DIR"
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
#
|
|
204
|
-
|
|
199
|
+
if [ -n "${_EGREGORE_REUSE_SESSION_ID:-}" ]; then
|
|
200
|
+
# Background refresh of a session the quick startup pass already identified
|
|
201
|
+
# (bin/lib/card-delivery.sh): keep its id, and leave the id files and the
|
|
202
|
+
# native mapping as that pass wrote them; a newer session may own them now.
|
|
203
|
+
export EGREGORE_SESSION_ID="$_EGREGORE_REUSE_SESSION_ID"
|
|
204
|
+
unset _EGREGORE_REUSE_SESSION_ID
|
|
205
|
+
else
|
|
206
|
+
export EGREGORE_SESSION_ID="$(date -u +%Y%m%dT%H%M%S)-${AUTHOR}-$$"
|
|
207
|
+
|
|
208
|
+
# Persist session ID to file so telemetry.sh can read it
|
|
209
|
+
# (env vars from hooks don't propagate into the Claude Code agent)
|
|
210
|
+
PROJ_HASH=$(echo -n "$SCRIPT_DIR" | md5 2>/dev/null || echo -n "$SCRIPT_DIR" | md5sum 2>/dev/null | cut -d' ' -f1)
|
|
211
|
+
echo "$EGREGORE_SESSION_ID" > "$SESSION_ID_DIR/session-${PROJ_HASH}.id"
|
|
212
|
+
# Also write project-local file (CLAUDE.md reads this — no glob needed)
|
|
213
|
+
echo "$EGREGORE_SESSION_ID" > "$SCRIPT_DIR/.egregore-session-id"
|
|
214
|
+
fi
|
|
215
|
+
# Every worktree links that file, so a parallel session start rewrites it
|
|
216
|
+
# under this session. Map the starting harness session's own id to this id
|
|
217
|
+
# (bin/session-id.sh) so its commits keep their own Egregore-Session trailer.
|
|
218
|
+
# Each entry point names the harness it starts; a native id inherited from
|
|
219
|
+
# another session's shell never matches that name.
|
|
220
|
+
if [ -n "${EGREGORE_START_HARNESS:-}" ] && [ -n "${EGREGORE_NATIVE_SESSION_ID:-}" ] \
|
|
221
|
+
&& [ "${EGREGORE_NATIVE_HARNESS:-}" = "$EGREGORE_START_HARNESS" ] \
|
|
222
|
+
&& [ -f "$SCRIPT_DIR/bin/session-id.sh" ]; then
|
|
223
|
+
bash "$SCRIPT_DIR/bin/session-id.sh" record "$EGREGORE_START_HARNESS" \
|
|
224
|
+
"$EGREGORE_NATIVE_SESSION_ID" "$EGREGORE_SESSION_ID" --root "$SCRIPT_DIR" >/dev/null 2>&1 || true
|
|
225
|
+
fi
|
|
205
226
|
|
|
206
227
|
# Model stamp hashes the git common-dir root because telemetry.sh resolves it that way.
|
|
207
228
|
MODEL_REPO_ROOT=$(git -C "$SCRIPT_DIR" rev-parse --path-format=absolute --git-common-dir 2>/dev/null | sed 's|/\.git$||') || MODEL_REPO_ROOT="$SCRIPT_DIR"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# instance-registry.sh — session start's maintenance of the instance registry
|
|
3
|
+
# (~/.egregore/instances.json). Sourced by bin/session-start.sh (register +
|
|
4
|
+
# prune) and bin/codex-session-start.sh (prune). Requires jq.
|
|
5
|
+
#
|
|
6
|
+
# egregore_registry_prune <registry>
|
|
7
|
+
# Drop entries that can never be an instance: a checkout inside another
|
|
8
|
+
# registered instance's .egregore/ runtime directory (an evaluation
|
|
9
|
+
# sandbox) is runtime state of that instance.
|
|
10
|
+
# egregore_registry_register <registry> <dir> <slug> <name> [org_id]
|
|
11
|
+
# Register <dir> unless it is already registered or is such runtime
|
|
12
|
+
# state; patch a legacy entry with its org_id.
|
|
13
|
+
#
|
|
14
|
+
# Every write goes through a temporary file and a rename: the boundary check
|
|
15
|
+
# reads an empty or half-written registry as damage and fails closed.
|
|
16
|
+
|
|
17
|
+
# True when $p sits inside another listed path's .egregore/ directory.
|
|
18
|
+
_EGREGORE_REGISTRY_JQ_DEFS='
|
|
19
|
+
def runtime_state($all): . as $p | any($all[]; . as $root | $root != $p and ($p | startswith($root + "/.egregore/")));
|
|
20
|
+
def registered_paths: [.[] | objects | .path | strings];
|
|
21
|
+
def runtime_entry($all): type == "object" and (.path | type) == "string" and (.path | runtime_state($all));
|
|
22
|
+
'
|
|
23
|
+
|
|
24
|
+
_egregore_registry_write() {
|
|
25
|
+
local registry="$1" tmp="$1.tmp.$$"
|
|
26
|
+
shift
|
|
27
|
+
if jq "$@" "$registry" > "$tmp" 2>/dev/null && [ -s "$tmp" ]; then
|
|
28
|
+
mv "$tmp" "$registry"
|
|
29
|
+
else
|
|
30
|
+
rm -f "$tmp"
|
|
31
|
+
return 1
|
|
32
|
+
fi
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
egregore_registry_prune() {
|
|
36
|
+
local registry="$1" pruned
|
|
37
|
+
[ -f "$registry" ] || return 0
|
|
38
|
+
pruned=$(jq "$_EGREGORE_REGISTRY_JQ_DEFS"'
|
|
39
|
+
if type == "array" then registered_paths as $all | [.[] | select(runtime_entry($all))] | length else 0 end' \
|
|
40
|
+
"$registry" 2>/dev/null) || return 0
|
|
41
|
+
[ "${pruned:-0}" -gt 0 ] 2>/dev/null || return 0
|
|
42
|
+
_egregore_registry_write "$registry" "$_EGREGORE_REGISTRY_JQ_DEFS"'
|
|
43
|
+
registered_paths as $all | map(select(runtime_entry($all) | not))'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
egregore_registry_register() {
|
|
47
|
+
local registry="$1" dir="$2" slug="$3" name="$4" org="${5:-}" entry
|
|
48
|
+
[ -n "$dir" ] && [ -n "$slug" ] && [ -n "$name" ] || return 0
|
|
49
|
+
mkdir -p "$(dirname "$registry")" || return 0
|
|
50
|
+
if [ ! -f "$registry" ]; then
|
|
51
|
+
echo "[]" > "$registry.tmp.$$" && mv "$registry.tmp.$$" "$registry"
|
|
52
|
+
fi
|
|
53
|
+
# Runtime state of another registered instance never registers itself.
|
|
54
|
+
if jq -e --arg p "$dir" "$_EGREGORE_REGISTRY_JQ_DEFS"'registered_paths as $all | $p | runtime_state($all)' \
|
|
55
|
+
"$registry" >/dev/null 2>&1; then
|
|
56
|
+
return 0
|
|
57
|
+
fi
|
|
58
|
+
if [ "$(jq --arg p "$dir" '[.[] | objects | select(.path == $p)] | length' "$registry" 2>/dev/null)" = "0" ]; then
|
|
59
|
+
# org_id is the stable identity other sessions use to prove this
|
|
60
|
+
# checkout is same-organization rather than foreign
|
|
61
|
+
entry=$(jq -n --arg s "$slug" --arg n "$name" --arg p "$dir" --arg o "$org" \
|
|
62
|
+
'{slug: $s, name: $n, path: $p} + (if $o == "" then {} else {org_id: $o} end)')
|
|
63
|
+
_egregore_registry_write "$registry" --argjson e "$entry" '. + [$e]'
|
|
64
|
+
elif [ -n "$org" ]; then
|
|
65
|
+
# Backward compatibility: patch this checkout's own legacy entry with its
|
|
66
|
+
# org_id so other sessions can prove identity instead of failing closed
|
|
67
|
+
# against it
|
|
68
|
+
_egregore_registry_write "$registry" --arg p "$dir" --arg o "$org" \
|
|
69
|
+
'map(if type == "object" and .path == $p and ((.org_id // "") == "") then . + {org_id: $o} else . end)'
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Bind caller-recorded local checks to a PR commit while hosted CI is unavailable.
|
|
3
|
+
|
|
4
|
+
generate --records FILE accepts a JSON array of {suite, command, exit_code, log}.
|
|
5
|
+
It copies logs beside the receipt and hashes them. validate checks identity,
|
|
6
|
+
Git trees and retained log integrity; it does not execute commands or certify
|
|
7
|
+
that the caller actually ran them. Authorization belongs to the merge caller.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
import re
|
|
17
|
+
import stat
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
SCHEMA = "local-ci/v1"
|
|
22
|
+
REASON = "GitHub Actions credits exhausted"
|
|
23
|
+
MAX_JSON = 1024 * 1024
|
|
24
|
+
MAX_LOG = 64 * 1024 * 1024
|
|
25
|
+
SHA = re.compile(r"[0-9a-f]{40}")
|
|
26
|
+
DIGEST = re.compile(r"[0-9a-f]{64}")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Invalid(ValueError):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def require(condition, message):
|
|
34
|
+
if not condition:
|
|
35
|
+
raise Invalid(message)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def read_file(path, limit):
|
|
39
|
+
"""Read a bounded regular file without following its final symlink."""
|
|
40
|
+
fd = os.open(path, os.O_RDONLY | os.O_NONBLOCK | getattr(os, "O_NOFOLLOW", 0))
|
|
41
|
+
with os.fdopen(fd, "rb") as stream:
|
|
42
|
+
info = os.fstat(stream.fileno())
|
|
43
|
+
require(stat.S_ISREG(info.st_mode) and info.st_size <= limit, "invalid evidence file")
|
|
44
|
+
value = stream.read(limit + 1)
|
|
45
|
+
require(len(value) <= limit, "evidence file exceeds limit")
|
|
46
|
+
return value
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def read_log(root, relative):
|
|
50
|
+
"""A receipt can read regular log descendants only, without symlink hops."""
|
|
51
|
+
require(isinstance(relative, str) and relative, "missing retained log path")
|
|
52
|
+
path = Path(relative)
|
|
53
|
+
require(path.parts and not path.is_absolute() and all(p not in (".", "..") for p in path.parts),
|
|
54
|
+
"retained log must stay beside the receipt")
|
|
55
|
+
fd = os.open(root, os.O_RDONLY | os.O_DIRECTORY)
|
|
56
|
+
try:
|
|
57
|
+
for part in path.parts[:-1]:
|
|
58
|
+
child = os.open(part, os.O_RDONLY | os.O_DIRECTORY | getattr(os, "O_NOFOLLOW", 0), dir_fd=fd)
|
|
59
|
+
os.close(fd)
|
|
60
|
+
fd = child
|
|
61
|
+
leaf = os.open(path.parts[-1], os.O_RDONLY | os.O_NONBLOCK | getattr(os, "O_NOFOLLOW", 0), dir_fd=fd)
|
|
62
|
+
with os.fdopen(leaf, "rb") as stream:
|
|
63
|
+
info = os.fstat(stream.fileno())
|
|
64
|
+
require(stat.S_ISREG(info.st_mode) and info.st_size <= MAX_LOG, "invalid retained log")
|
|
65
|
+
content = stream.read(MAX_LOG + 1)
|
|
66
|
+
require(len(content) <= MAX_LOG, "retained log exceeds limit")
|
|
67
|
+
return content
|
|
68
|
+
finally:
|
|
69
|
+
os.close(fd)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def document(path):
|
|
73
|
+
value = json.loads(read_file(path, MAX_JSON))
|
|
74
|
+
require(isinstance(value, dict), "receipt must be an object")
|
|
75
|
+
return value
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def git(checkout, *args, failure="Git identity is unavailable"):
|
|
79
|
+
env = {k: v for k, v in os.environ.items() if not k.startswith("GIT_")}
|
|
80
|
+
env.update(GIT_OPTIONAL_LOCKS="0", GIT_CONFIG_NOSYSTEM="1", GIT_NO_REPLACE_OBJECTS="1")
|
|
81
|
+
result = subprocess.run(["git", "-c", "core.fsmonitor=false", "-C", str(checkout), *args], env=env,
|
|
82
|
+
capture_output=True, text=True, timeout=15)
|
|
83
|
+
require(result.returncode == 0, failure)
|
|
84
|
+
return result.stdout.strip()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def text(value, label, limit=4096):
|
|
88
|
+
require(isinstance(value, str) and 0 < len(value) <= limit
|
|
89
|
+
and all(ord(c) >= 32 or c in "\n\t" for c in value), f"invalid {label}")
|
|
90
|
+
return value
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def identity(row):
|
|
94
|
+
require(row.get("schema") == SCHEMA, "unsupported local CI receipt schema")
|
|
95
|
+
require(isinstance(row.get("repo"), str) and
|
|
96
|
+
re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", row["repo"]), "invalid repository")
|
|
97
|
+
require(type(row.get("pr")) is int and row["pr"] > 0, "invalid PR number")
|
|
98
|
+
for key in ("head", "base_sha", "tree_sha"):
|
|
99
|
+
require(isinstance(row.get(key), str) and SHA.fullmatch(row[key]), f"invalid {key}")
|
|
100
|
+
text(row.get("base"), "base ref", 200)
|
|
101
|
+
require("\n" not in row["base"] and "\t" not in row["base"] and not row["base"].startswith("-"),
|
|
102
|
+
"invalid base ref")
|
|
103
|
+
text(row.get("checkout"), "checkout")
|
|
104
|
+
require(Path(row["checkout"]).is_absolute(), "checkout must be absolute")
|
|
105
|
+
require(row.get("unavailable_reason") == REASON, "unsupported hosted CI exception")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def validate(path, *, repo, pr, head, base, base_sha):
|
|
109
|
+
row = document(path)
|
|
110
|
+
identity(row)
|
|
111
|
+
for key, wanted in (("repo", repo), ("pr", pr), ("head", head), ("base", base), ("base_sha", base_sha)):
|
|
112
|
+
require(row[key] == wanted, f"receipt {key} does not match current PR")
|
|
113
|
+
require(git(row["checkout"], "rev-parse", "--verify", row["head"] + "^{tree}") == row["tree_sha"],
|
|
114
|
+
"tested tree does not match PR head")
|
|
115
|
+
require(git(row["checkout"], "rev-parse", "--verify", row["base_sha"] + "^{commit}") == row["base_sha"],
|
|
116
|
+
"base commit is unavailable")
|
|
117
|
+
git(row["checkout"], "merge-base", "--is-ancestor", row["base_sha"], row["head"],
|
|
118
|
+
failure="tested head does not contain the current base")
|
|
119
|
+
suites = row.get("required_suites")
|
|
120
|
+
require(isinstance(suites, list) and 0 < len(suites) <= 100, "required suites are missing")
|
|
121
|
+
for suite in suites:
|
|
122
|
+
text(suite, "suite name", 200)
|
|
123
|
+
require(len(set(suites)) == len(suites), "required suites are duplicated")
|
|
124
|
+
results = row.get("results")
|
|
125
|
+
require(isinstance(results, list) and len(results) == len(suites), "required suite results are incomplete")
|
|
126
|
+
seen = set()
|
|
127
|
+
for result in results:
|
|
128
|
+
require(isinstance(result, dict), "invalid suite result")
|
|
129
|
+
suite = result.get("suite")
|
|
130
|
+
require(isinstance(suite, str) and suite in suites and suite not in seen,
|
|
131
|
+
"unexpected or duplicate suite result")
|
|
132
|
+
seen.add(suite)
|
|
133
|
+
text(result.get("command"), "recorded command", 16384)
|
|
134
|
+
require(type(result.get("exit_code")) is int and result["exit_code"] == 0,
|
|
135
|
+
f"required suite did not pass: {suite}")
|
|
136
|
+
require(isinstance(result.get("sha256"), str) and DIGEST.fullmatch(result["sha256"]),
|
|
137
|
+
"invalid log digest")
|
|
138
|
+
log = read_log(Path(path).resolve().parent, result.get("log"))
|
|
139
|
+
require(hashlib.sha256(log).hexdigest() == result["sha256"], f"log changed: {suite}")
|
|
140
|
+
failed = row.get("failed_checks")
|
|
141
|
+
require(isinstance(failed, list) and len(failed) <= 100, "failed_checks must be a list")
|
|
142
|
+
named = set()
|
|
143
|
+
for check in failed:
|
|
144
|
+
require(isinstance(check, dict), "invalid hosted check explanation")
|
|
145
|
+
name = text(check.get("name"), "hosted check name", 300)
|
|
146
|
+
text(check.get("reason"), "hosted check reason")
|
|
147
|
+
require(name not in named, "duplicate hosted check explanation")
|
|
148
|
+
named.add(name)
|
|
149
|
+
return row
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def quoted(value):
|
|
153
|
+
"""Single-line Markdown code, including hostile backticks, without HTML."""
|
|
154
|
+
value = " ".join(str(value).split())
|
|
155
|
+
runs = re.findall(r"`+", value)
|
|
156
|
+
fence = "`" * (1 + max(map(len, runs), default=0))
|
|
157
|
+
return f"{fence} {value} {fence}"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def markdown(row):
|
|
161
|
+
lines = ["## Local CI receipt", "",
|
|
162
|
+
f"Repository {quoted(row['repo'])}, PR #{row['pr']}.",
|
|
163
|
+
f"Head {quoted(row['head'])}; base {quoted(row['base'])} at {quoted(row['base_sha'])}.",
|
|
164
|
+
f"Tested tree {quoted(row['tree_sha'])}.",
|
|
165
|
+
f"Caller-reported hosted CI exception: {REASON}.", "",
|
|
166
|
+
"The caller recorded these checks. Validation verified commit identity and retained log hashes; "
|
|
167
|
+
"it did not independently execute or attest the commands. The receipt does not grant merge authorization.",
|
|
168
|
+
""]
|
|
169
|
+
for result in row["results"]:
|
|
170
|
+
lines.append(f"- {quoted(result['suite'])}: recorded exit 0; {quoted(result['command'])}; "
|
|
171
|
+
f"log SHA256 {quoted(result['sha256'])}.")
|
|
172
|
+
if row["failed_checks"]:
|
|
173
|
+
lines.extend(["", "Hosted checks covered by this local exception:", ""])
|
|
174
|
+
for check in row["failed_checks"]:
|
|
175
|
+
lines.append(f"- {quoted(check['name'])}: {quoted(check['reason'])}.")
|
|
176
|
+
return "\n".join(lines) + "\n"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def generate(args):
|
|
180
|
+
checkout = Path(args.checkout).resolve()
|
|
181
|
+
tree = args.tree
|
|
182
|
+
if tree is None:
|
|
183
|
+
require(git(checkout, "rev-parse", "HEAD") == args.head, "checkout is not at the tested head")
|
|
184
|
+
require(not git(checkout, "status", "--porcelain", "--untracked-files=no"), "tracked checkout is dirty")
|
|
185
|
+
tree = git(checkout, "rev-parse", "HEAD^{tree}")
|
|
186
|
+
row = {"schema": SCHEMA, "repo": args.repo, "pr": args.pr, "head": args.head,
|
|
187
|
+
"base": args.base, "base_sha": args.base_sha, "tree_sha": tree,
|
|
188
|
+
"checkout": str(checkout), "unavailable_reason": args.unavailable_reason,
|
|
189
|
+
"required_suites": args.required_suite, "results": [],
|
|
190
|
+
"failed_checks": json.loads(read_file(args.failed_checks, MAX_JSON)) if args.failed_checks else []}
|
|
191
|
+
identity(row)
|
|
192
|
+
records = json.loads(read_file(args.records, MAX_JSON))
|
|
193
|
+
require(isinstance(records, list), "records must be a JSON array")
|
|
194
|
+
output = Path(args.output).absolute()
|
|
195
|
+
require(not output.exists(), "receipt output already exists")
|
|
196
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
197
|
+
log_root = output.parent / (output.name + ".logs")
|
|
198
|
+
log_root.mkdir(mode=0o700)
|
|
199
|
+
for index, result in enumerate(records):
|
|
200
|
+
require(isinstance(result, dict), "invalid caller record")
|
|
201
|
+
content = read_file(Path(args.records).resolve().parent / result["log"], MAX_LOG)
|
|
202
|
+
target = log_root / f"{index + 1:03d}.log"
|
|
203
|
+
with target.open("xb") as stream:
|
|
204
|
+
stream.write(content)
|
|
205
|
+
target.chmod(0o600)
|
|
206
|
+
row["results"].append({key: result.get(key) for key in ("suite", "command", "exit_code")} |
|
|
207
|
+
{"log": str(target.relative_to(output.parent)),
|
|
208
|
+
"sha256": hashlib.sha256(content).hexdigest()})
|
|
209
|
+
with output.open("x", encoding="utf-8") as stream:
|
|
210
|
+
json.dump(row, stream, indent=2)
|
|
211
|
+
stream.write("\n")
|
|
212
|
+
output.chmod(0o600)
|
|
213
|
+
validate(output, repo=args.repo, pr=args.pr, head=args.head, base=args.base, base_sha=args.base_sha)
|
|
214
|
+
return output
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def main(argv=None):
|
|
218
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
219
|
+
sub = parser.add_subparsers(dest="action", required=True)
|
|
220
|
+
for action in ("generate", "validate"):
|
|
221
|
+
command = sub.add_parser(action)
|
|
222
|
+
for flag in ("repo", "head", "base", "base-sha"):
|
|
223
|
+
command.add_argument("--" + flag, required=True)
|
|
224
|
+
command.add_argument("--pr", type=int, required=True)
|
|
225
|
+
if action == "validate":
|
|
226
|
+
command.add_argument("--receipt", type=Path, required=True)
|
|
227
|
+
else:
|
|
228
|
+
command.add_argument("--output", type=Path, required=True)
|
|
229
|
+
command.add_argument("--checkout", type=Path, required=True)
|
|
230
|
+
command.add_argument("--records", type=Path, required=True)
|
|
231
|
+
command.add_argument("--required-suite", action="append", required=True)
|
|
232
|
+
command.add_argument("--unavailable-reason", required=True)
|
|
233
|
+
command.add_argument("--failed-checks", type=Path, help="JSON array of hosted {name, reason} explanations")
|
|
234
|
+
command.add_argument("--tree", help="explicit tested Git tree, for checks run before committing that tree")
|
|
235
|
+
args = parser.parse_args(argv)
|
|
236
|
+
try:
|
|
237
|
+
if args.action == "generate":
|
|
238
|
+
print(generate(args))
|
|
239
|
+
else:
|
|
240
|
+
print(markdown(validate(args.receipt, repo=args.repo, pr=args.pr, head=args.head,
|
|
241
|
+
base=args.base, base_sha=args.base_sha)), end="")
|
|
242
|
+
except (Invalid, OSError, ValueError, KeyError, TypeError, subprocess.SubprocessError) as error:
|
|
243
|
+
print(f"local-ci: {error}", file=sys.stderr)
|
|
244
|
+
return 1
|
|
245
|
+
return 0
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
if __name__ == "__main__":
|
|
249
|
+
raise SystemExit(main())
|