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
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"""One managed memory push, freshly inspected at dispatch.
|
|
2
|
+
|
|
3
|
+
Ordinary callers cannot publish native history. The optional private record
|
|
4
|
+
owner can supply its typed, single-use in-process permit. This transport never
|
|
5
|
+
fetches, rebases, changes Git configuration, retries a push or writes a queue.
|
|
6
|
+
Manual Git remains outside this boundary. Existing Git configuration owns auth.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
from dataclasses import dataclass, replace
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import math
|
|
15
|
+
import os
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import re
|
|
18
|
+
import subprocess
|
|
19
|
+
import time
|
|
20
|
+
from urllib.parse import urlsplit
|
|
21
|
+
|
|
22
|
+
from . import record_publish as history
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True)
|
|
26
|
+
class PushLimits:
|
|
27
|
+
seconds: float = 90
|
|
28
|
+
command_seconds: float = 15
|
|
29
|
+
push_seconds: float = 45
|
|
30
|
+
output_bytes: int = 65536
|
|
31
|
+
history: history.HistoryLimits = history.DEFAULT_LIMITS
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
DEFAULT_LIMITS = PushLimits()
|
|
35
|
+
EXIT_CODES = {"pushed": 0, "deferred": 2, "rejected": 3, "unknown": 4}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class _Refusal(Exception):
|
|
39
|
+
def __init__(self, cause, *, status="rejected"):
|
|
40
|
+
self.cause, self.status = cause, status
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _Transport(history._Git):
|
|
44
|
+
def __init__(self, root, deadline, limits, allow_local):
|
|
45
|
+
super().__init__(root, deadline)
|
|
46
|
+
# Transport uses normal system/global/local credential configuration.
|
|
47
|
+
# Repository/config/ref redirection from caller environment is removed.
|
|
48
|
+
self.env.pop("GIT_CONFIG_NOSYSTEM", None)
|
|
49
|
+
self.env.pop("GIT_CONFIG_GLOBAL", None)
|
|
50
|
+
for key in ("GIT_ASKPASS", "GIT_SSL_CAINFO", "GIT_SSL_CAPATH"):
|
|
51
|
+
if key in os.environ:
|
|
52
|
+
self.env[key] = os.environ[key]
|
|
53
|
+
self.limits, self.allow_local = limits, allow_local
|
|
54
|
+
|
|
55
|
+
def start(self, args, *, stdin=False):
|
|
56
|
+
return super().start(["-c", "protocol.https.allow=always", "-c",
|
|
57
|
+
"protocol.file.allow=" + ("always" if self.allow_local else "never"),
|
|
58
|
+
"-c", "http.followRedirects=false", "-c", "push.followTags=false",
|
|
59
|
+
"-c", "push.recurseSubmodules=no", "-c", "push.gpgSign=false",
|
|
60
|
+
"-c", "push.autoSetupRemote=false", *args], stdin=stdin)
|
|
61
|
+
|
|
62
|
+
def command(self, *args, seconds=None):
|
|
63
|
+
outer = self.deadline
|
|
64
|
+
self.deadline = min(outer, time.monotonic() + (seconds or self.limits.command_seconds))
|
|
65
|
+
try:
|
|
66
|
+
return self.run(*args, limit=self.limits.output_bytes, allowed=tuple(range(256)))
|
|
67
|
+
finally:
|
|
68
|
+
self.deadline = outer
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _branch(value):
|
|
72
|
+
if not isinstance(value, str):
|
|
73
|
+
raise _Refusal("invalid_destination_branch")
|
|
74
|
+
ref = value if value.startswith("refs/") else "refs/heads/" + value
|
|
75
|
+
if not ref.startswith("refs/heads/") or not history._ref(ref):
|
|
76
|
+
raise _Refusal("invalid_destination_branch")
|
|
77
|
+
return ref
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _safe_ref(git_dir, ref):
|
|
81
|
+
seen = set()
|
|
82
|
+
while True:
|
|
83
|
+
if ref in seen or len(seen) >= 8:
|
|
84
|
+
raise _Refusal("ambiguous_source_ref")
|
|
85
|
+
seen.add(ref)
|
|
86
|
+
if ref != "HEAD" and (not history._ref(ref) or not ref.startswith("refs/heads/")):
|
|
87
|
+
raise _Refusal("invalid_source_ref")
|
|
88
|
+
selected = git_dir
|
|
89
|
+
for part in ref.split("/"):
|
|
90
|
+
selected /= part
|
|
91
|
+
if selected.is_symlink():
|
|
92
|
+
raise _Refusal("unsupported_repository")
|
|
93
|
+
if (git_dir / "packed-refs").is_symlink():
|
|
94
|
+
raise _Refusal("unsupported_repository")
|
|
95
|
+
if not selected.exists():
|
|
96
|
+
return
|
|
97
|
+
raw = history._regular(selected, 1024).strip()
|
|
98
|
+
if not raw.startswith(b"ref: "):
|
|
99
|
+
return
|
|
100
|
+
ref = raw[5:].decode("ascii")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _url(value, allow_local):
|
|
104
|
+
if not value or len(value) > 4096 or any(ord(char) <= 32 or ord(char) == 127 for char in value):
|
|
105
|
+
raise _Refusal("unsupported_destination")
|
|
106
|
+
parsed = urlsplit(value)
|
|
107
|
+
if (parsed.scheme == "https" and parsed.hostname and parsed.username is None and parsed.password is None
|
|
108
|
+
and not parsed.query and not parsed.fragment and parsed.path.startswith("/")
|
|
109
|
+
and not re.search(r"[^A-Za-z0-9.:-]", parsed.netloc)):
|
|
110
|
+
return value
|
|
111
|
+
if allow_local and not parsed.scheme and value.startswith("/"):
|
|
112
|
+
path = Path(value)
|
|
113
|
+
if path == path.resolve() and path.is_dir():
|
|
114
|
+
return value
|
|
115
|
+
raise _Refusal("unsupported_destination")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _snapshot(transport, repository, head_ref, branch_ref):
|
|
119
|
+
root, git_dir = history._repository(repository, transport.deadline)
|
|
120
|
+
_safe_ref(git_dir, head_ref)
|
|
121
|
+
config, code = transport.command("config", "--null", "--list", "--includes")
|
|
122
|
+
if code:
|
|
123
|
+
raise _Refusal("configuration_unavailable", status="deferred")
|
|
124
|
+
values = {}
|
|
125
|
+
for entry in config.split(b"\0"):
|
|
126
|
+
if not entry:
|
|
127
|
+
continue
|
|
128
|
+
key, sep, value = entry.partition(b"\n")
|
|
129
|
+
if not sep:
|
|
130
|
+
# A valueless Boolean key is true in Git's own configuration.
|
|
131
|
+
value = b"true"
|
|
132
|
+
name = key.decode("utf-8").lower()
|
|
133
|
+
values.setdefault(name, []).append(value.decode("utf-8"))
|
|
134
|
+
if any(re.fullmatch(r"url\..*\.(?:push)?insteadof", key) for key in values):
|
|
135
|
+
raise _Refusal("destination_rewrite_unsupported")
|
|
136
|
+
if (len(values.get("remote.origin.url", [])) != 1 or len(values.get("remote.origin.pushurl", [])) > 1
|
|
137
|
+
or any(values.get(key) for key in ("remote.origin.push", "remote.origin.pushoption", "push.pushoption",
|
|
138
|
+
"remote.origin.receivepack", "remote.origin.uploadpack", "remote.origin.vcs"))
|
|
139
|
+
or any(value.lower() not in {"false", "no", "off", "0"} for value in values.get("remote.origin.mirror", []))):
|
|
140
|
+
raise _Refusal("ambiguous_destination")
|
|
141
|
+
selected = values.get("remote.origin.pushurl", values["remote.origin.url"])[0]
|
|
142
|
+
selected = _url(selected, transport.allow_local)
|
|
143
|
+
resolved, code = transport.command("remote", "get-url", "--push", "--all", "origin")
|
|
144
|
+
if code or resolved.decode("utf-8").splitlines() != [selected]:
|
|
145
|
+
raise _Refusal("ambiguous_destination")
|
|
146
|
+
raw_head, code = transport.command("rev-parse", "--verify", head_ref)
|
|
147
|
+
head = raw_head.strip().decode("ascii")
|
|
148
|
+
if code or not history.OID.fullmatch(head):
|
|
149
|
+
raise _Refusal("source_unavailable", status="deferred")
|
|
150
|
+
info, git_info = root.stat(), git_dir.stat()
|
|
151
|
+
return {"url": selected, "head_oid": head, "head_ref": head_ref, "branch_ref": branch_ref,
|
|
152
|
+
"repository_identity": [info.st_dev, info.st_ino, git_info.st_dev, git_info.st_ino],
|
|
153
|
+
"repository_fingerprint": history._digest({"repository": str(root), "git_dir": str(git_dir)}),
|
|
154
|
+
"configuration_digest": hashlib.sha256(config).hexdigest(),
|
|
155
|
+
"destination_fingerprint": history._digest({"url": selected, "ref": branch_ref})}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _remote(transport, selection):
|
|
159
|
+
raw, code = transport.command("ls-remote", "--refs", "--heads", "--", selection["url"], selection["branch_ref"])
|
|
160
|
+
if code:
|
|
161
|
+
raise _Refusal("remote_evidence_unavailable", status="deferred")
|
|
162
|
+
lines = raw.decode("ascii").splitlines()
|
|
163
|
+
if not lines:
|
|
164
|
+
return None
|
|
165
|
+
if len(lines) != 1:
|
|
166
|
+
raise _Refusal("ambiguous_remote_evidence", status="deferred")
|
|
167
|
+
oid, sep, ref = lines[0].partition("\t")
|
|
168
|
+
if not sep or ref != selection["branch_ref"] or not history.OID.fullmatch(oid) or len(oid) != len(selection["head_oid"]):
|
|
169
|
+
raise _Refusal("ambiguous_remote_evidence", status="deferred")
|
|
170
|
+
return oid
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _same(expected, current):
|
|
174
|
+
if expected != current:
|
|
175
|
+
raise _Refusal("source_or_destination_changed", status="deferred")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def inspect_destination(repository, *, branch, head_ref="HEAD", limits=DEFAULT_LIMITS,
|
|
179
|
+
allow_local_transport=False, deadline_monotonic=None):
|
|
180
|
+
"""Fresh read-only host selection. This fact carries no publication grant.
|
|
181
|
+
|
|
182
|
+
The native record owner uses the same bounded destination resolver before
|
|
183
|
+
committing and while reconciling an uncertain exact commit. No fetch,
|
|
184
|
+
reconciliation mutation or push occurs here.
|
|
185
|
+
"""
|
|
186
|
+
_validate_arguments(limits, allow_local_transport, head_ref)
|
|
187
|
+
branch_ref = _branch(branch)
|
|
188
|
+
deadline = _deadline(limits, deadline_monotonic)
|
|
189
|
+
root, _ = history._repository(repository, deadline)
|
|
190
|
+
transport = _Transport(root, deadline, limits, allow_local_transport)
|
|
191
|
+
selection = _snapshot(transport, root, head_ref, branch_ref)
|
|
192
|
+
base = _remote(transport, selection)
|
|
193
|
+
_same(selection, _snapshot(transport, root, head_ref, branch_ref))
|
|
194
|
+
return selection, base
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _deadline(limits, inherited):
|
|
198
|
+
if inherited is not None and (type(inherited) not in (float, int) or not math.isfinite(inherited)):
|
|
199
|
+
raise ValueError("invalid inherited deadline")
|
|
200
|
+
value = time.monotonic() + limits.seconds
|
|
201
|
+
if inherited is not None:
|
|
202
|
+
value = min(value, inherited)
|
|
203
|
+
if value <= time.monotonic():
|
|
204
|
+
raise ValueError("publication deadline expired")
|
|
205
|
+
return value
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _validate_arguments(limits, allow_local_transport, head_ref):
|
|
209
|
+
if (not isinstance(limits, PushLimits) or type(allow_local_transport) is not bool
|
|
210
|
+
or any(type(getattr(limits, key)) not in (int, float) or not 0 < getattr(limits, key) <= getattr(DEFAULT_LIMITS, key)
|
|
211
|
+
for key in ("seconds", "command_seconds", "push_seconds"))
|
|
212
|
+
or type(limits.output_bytes) is not int or not 1 <= limits.output_bytes <= DEFAULT_LIMITS.output_bytes
|
|
213
|
+
or not isinstance(limits.history, history.HistoryLimits)):
|
|
214
|
+
raise _Refusal("invalid_limits")
|
|
215
|
+
if not isinstance(head_ref, str) or not (head_ref == "HEAD" or head_ref.startswith("refs/heads/") and history._ref(head_ref)):
|
|
216
|
+
raise _Refusal("invalid_source_ref")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _empty_receipt():
|
|
220
|
+
return {"schema": "egregore.managed-memory-push/v1", "status": "deferred", "cause": "not_started",
|
|
221
|
+
"source_oid": None, "source_ref": None, "base_oid": None, "destination_ref": None,
|
|
222
|
+
"repository_fingerprint": None, "destination_fingerprint": None, "configuration_digest": None,
|
|
223
|
+
"history_digest": None, "history_status": None, "dispatch_attempted": False,
|
|
224
|
+
"reconciled": False, "retry_safe": False, "observed_remote_oid": None, "native_publication_authority": False}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def push_memory(repository, *, branch, head_ref="HEAD", limits=DEFAULT_LIMITS, allow_local_transport=False,
|
|
228
|
+
native_permit=None, deadline_monotonic=None):
|
|
229
|
+
"""Inspect and perform at most one exact managed push; no reusable permit.
|
|
230
|
+
|
|
231
|
+
HTTPS is the production transport. The explicit local-transport host option
|
|
232
|
+
retains every history/CAS guard and exists for disposable local receivers.
|
|
233
|
+
Config/source checks detect ordinary concurrent changes, not hostile local
|
|
234
|
+
filesystem mutation after the final check. An explicit remote lease closes
|
|
235
|
+
the destination-ref race; it is used only after proving fast-forward ancestry.
|
|
236
|
+
"""
|
|
237
|
+
receipt = _empty_receipt()
|
|
238
|
+
selection, transport = None, None
|
|
239
|
+
try:
|
|
240
|
+
_validate_arguments(limits, allow_local_transport, head_ref)
|
|
241
|
+
branch_ref = _branch(branch)
|
|
242
|
+
if native_permit is not None:
|
|
243
|
+
# The fixed native owner is private. Human-only public bundles do
|
|
244
|
+
# not carry it and must retain the same denied-native boundary.
|
|
245
|
+
try:
|
|
246
|
+
from .record_admission import NativePublicationPermit
|
|
247
|
+
valid_permit = type(native_permit) is NativePublicationPermit
|
|
248
|
+
except ImportError:
|
|
249
|
+
valid_permit = False
|
|
250
|
+
if not valid_permit:
|
|
251
|
+
raise _Refusal("invalid_native_publication_permit")
|
|
252
|
+
deadline = _deadline(limits, deadline_monotonic)
|
|
253
|
+
root, _ = history._repository(repository, deadline)
|
|
254
|
+
transport = _Transport(root, deadline, limits, allow_local_transport)
|
|
255
|
+
selection = _snapshot(transport, root, head_ref, branch_ref)
|
|
256
|
+
receipt.update(source_oid=selection["head_oid"], source_ref=head_ref, destination_ref=branch_ref,
|
|
257
|
+
**{key: selection[key] for key in ("repository_fingerprint", "destination_fingerprint", "configuration_digest")})
|
|
258
|
+
base = _remote(transport, selection)
|
|
259
|
+
receipt.update(base_oid=base, observed_remote_oid=base)
|
|
260
|
+
if base is not None:
|
|
261
|
+
local = history._Git(root, deadline)
|
|
262
|
+
kind, code = local.run("cat-file", "-t", base, limit=32, allowed=(0, 128))
|
|
263
|
+
if code == 128:
|
|
264
|
+
raise _Refusal("remote_base_unavailable_locally", status="deferred")
|
|
265
|
+
if kind.strip() != b"commit":
|
|
266
|
+
raise _Refusal("remote_base_not_commit", status="deferred")
|
|
267
|
+
inspection = history.inspect_outgoing_history(root, base_oid=base, base_ref=None,
|
|
268
|
+
head_oid=selection["head_oid"], head_ref=head_ref,
|
|
269
|
+
limits=replace(limits.history, seconds=min(limits.history.seconds, transport.remaining())))
|
|
270
|
+
receipt.update(history_digest=inspection["digest"], history_status=inspection["status"])
|
|
271
|
+
if inspection["status"] == "present" and native_permit is None:
|
|
272
|
+
raise _Refusal("native_history_requires_admission")
|
|
273
|
+
if inspection["status"] not in {"none", "present"} or not inspection["complete"]:
|
|
274
|
+
raise _Refusal("outgoing_history_unavailable", status="deferred")
|
|
275
|
+
_same(selection, _snapshot(transport, root, head_ref, branch_ref))
|
|
276
|
+
if _remote(transport, selection) != base:
|
|
277
|
+
raise _Refusal("remote_changed", status="deferred")
|
|
278
|
+
# A further source/config check follows the potentially slow remote read.
|
|
279
|
+
_same(selection, _snapshot(transport, root, head_ref, branch_ref))
|
|
280
|
+
if native_permit is not None:
|
|
281
|
+
try:
|
|
282
|
+
native_permit._admit_dispatch(selection, base, inspection)
|
|
283
|
+
except (ValueError, TypeError, AttributeError, OSError, RuntimeError):
|
|
284
|
+
raise _Refusal("native_publication_admission_changed")
|
|
285
|
+
# The fixed owner rechecks source and permissions, potentially over
|
|
286
|
+
# an inherited pipe. Bind HEAD/config once more after that return.
|
|
287
|
+
_same(selection, _snapshot(transport, root, head_ref, branch_ref))
|
|
288
|
+
receipt["native_publication_authority"] = True
|
|
289
|
+
if base == selection["head_oid"]:
|
|
290
|
+
receipt.update(status="pushed", cause="already_current", reconciled=True)
|
|
291
|
+
else:
|
|
292
|
+
receipt["dispatch_attempted"] = True
|
|
293
|
+
push_code = None
|
|
294
|
+
try:
|
|
295
|
+
_, push_code = transport.command("push", "--porcelain", "--no-verify", "--no-follow-tags",
|
|
296
|
+
"--recurse-submodules=no", "--force-with-lease=" + branch_ref + ":" + (base or ""),
|
|
297
|
+
"--", selection["url"], selection["head_oid"] + ":" + branch_ref, seconds=limits.push_seconds)
|
|
298
|
+
except (history._Unknown, OSError, ValueError, subprocess.SubprocessError):
|
|
299
|
+
pass # The only follow-up is a read; never another push.
|
|
300
|
+
try:
|
|
301
|
+
_same(selection, _snapshot(transport, root, head_ref, branch_ref))
|
|
302
|
+
observed = _remote(transport, selection)
|
|
303
|
+
receipt["observed_remote_oid"] = observed
|
|
304
|
+
if observed == selection["head_oid"]:
|
|
305
|
+
receipt.update(status="pushed", cause="acknowledged" if push_code == 0 else "acknowledgement_reconciled", reconciled=True)
|
|
306
|
+
else:
|
|
307
|
+
receipt.update(status="unknown", cause="remote_changed_after_dispatch" if observed != base else "push_acknowledgement_unknown")
|
|
308
|
+
except (history._Unknown, _Refusal, OSError, ValueError, UnicodeError, subprocess.SubprocessError):
|
|
309
|
+
receipt.update(status="unknown", cause="push_acknowledgement_unknown")
|
|
310
|
+
except _Refusal as exc:
|
|
311
|
+
receipt.update(status="unknown" if receipt["dispatch_attempted"] else exc.status,
|
|
312
|
+
cause="push_acknowledgement_unknown" if receipt["dispatch_attempted"] else exc.cause,
|
|
313
|
+
retry_safe=not receipt["dispatch_attempted"] and exc.cause in {
|
|
314
|
+
"source_or_destination_changed", "remote_changed", "remote_base_unavailable_locally"})
|
|
315
|
+
except (history._Unknown, OSError, ValueError, TypeError, UnicodeError, RecursionError, subprocess.SubprocessError):
|
|
316
|
+
receipt.update(status="unknown" if receipt["dispatch_attempted"] else "deferred",
|
|
317
|
+
cause="push_acknowledgement_unknown" if receipt["dispatch_attempted"] else "bounded_evidence_unavailable")
|
|
318
|
+
return {**receipt, "digest": history._digest(receipt)}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def main(argv=None):
|
|
322
|
+
parser = argparse.ArgumentParser(description="Guard one exact managed memory push; native history remains local.")
|
|
323
|
+
parser.add_argument("--repository", required=True)
|
|
324
|
+
parser.add_argument("--branch", required=True)
|
|
325
|
+
parser.add_argument("--head-ref", default="HEAD")
|
|
326
|
+
parser.add_argument("--allow-local-transport", action="store_true", help="explicit local bare fixture transport; all guards remain enabled")
|
|
327
|
+
args = parser.parse_args(argv)
|
|
328
|
+
deadline = time.monotonic() + DEFAULT_LIMITS.seconds
|
|
329
|
+
try:
|
|
330
|
+
# The host selects the memory repository, normally project/memory -> a
|
|
331
|
+
# sibling checkout. Bind that alias once here; the strict history and
|
|
332
|
+
# transport owners receive only its physical path and never reread it.
|
|
333
|
+
repository = Path(args.repository)
|
|
334
|
+
if not repository.is_absolute() or any(ord(c) < 32 or ord(c) == 127 for c in args.repository):
|
|
335
|
+
raise ValueError("invalid repository selection")
|
|
336
|
+
repository = repository.resolve(strict=True)
|
|
337
|
+
except (OSError, ValueError, RuntimeError, UnicodeError):
|
|
338
|
+
receipt = _empty_receipt()
|
|
339
|
+
receipt["cause"] = "bounded_evidence_unavailable"
|
|
340
|
+
receipt["digest"] = history._digest(receipt)
|
|
341
|
+
else:
|
|
342
|
+
receipt = push_memory(repository, branch=args.branch, head_ref=args.head_ref,
|
|
343
|
+
allow_local_transport=args.allow_local_transport, deadline_monotonic=deadline)
|
|
344
|
+
print(json.dumps(receipt, sort_keys=True, separators=(",", ":")))
|
|
345
|
+
return 75 if receipt["retry_safe"] else EXIT_CODES[receipt["status"]]
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
if __name__ == "__main__":
|
|
349
|
+
raise SystemExit(main())
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
import time
|
|
6
7
|
from dataclasses import dataclass, replace
|
|
7
8
|
from datetime import UTC, datetime
|
|
8
9
|
from uuid import uuid4
|
|
10
|
+
from pathlib import Path
|
|
9
11
|
|
|
10
12
|
from .contracts import (
|
|
11
13
|
ActionAuthorizer,
|
|
@@ -14,6 +16,7 @@ from .contracts import (
|
|
|
14
16
|
OrgContext,
|
|
15
17
|
OrgContextCompiler,
|
|
16
18
|
Permission,
|
|
19
|
+
PolicyDecision,
|
|
17
20
|
RetrievalHit,
|
|
18
21
|
RetrievalRequest,
|
|
19
22
|
Retriever,
|
|
@@ -21,10 +24,10 @@ from .contracts import (
|
|
|
21
24
|
TelemetrySink,
|
|
22
25
|
TemporalScope,
|
|
23
26
|
)
|
|
24
|
-
from .admin_gate import AdminGate
|
|
25
27
|
from .errors import AuthorizationDenied, ContextBudgetError
|
|
28
|
+
from .held import RedactionError, identity, redact
|
|
26
29
|
from .lifecycle import AuthorityState, CanonicalLifecycleService, LifecycleRecord
|
|
27
|
-
from .policy import
|
|
30
|
+
from .policy import allows, check, narrow, strips
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
def _token_count(content: str) -> int:
|
|
@@ -37,13 +40,28 @@ def _truncate_to_budget(content: str, budget: int) -> str:
|
|
|
37
40
|
return content[: max(0, budget * 4)]
|
|
38
41
|
|
|
39
42
|
|
|
43
|
+
def _packaged(decision: PolicyDecision, content: str, root: Path) -> str:
|
|
44
|
+
"""``held.redact`` for one passage; a JSON object (discovery's metadata) field by field, keys too, so a
|
|
45
|
+
title that runs into the next field name never breaks it."""
|
|
46
|
+
if not strips(decision):
|
|
47
|
+
return content
|
|
48
|
+
try:
|
|
49
|
+
fields = json.loads(content) if content.startswith("{") else None
|
|
50
|
+
except (ValueError, RecursionError):
|
|
51
|
+
fields = None
|
|
52
|
+
if not isinstance(fields, dict):
|
|
53
|
+
return redact(decision, content, root=root)
|
|
54
|
+
kept = redact(decision, fields, root=root, keys=True)
|
|
55
|
+
return content if kept == fields else json.dumps(kept, ensure_ascii=False)
|
|
56
|
+
|
|
57
|
+
|
|
40
58
|
@dataclass(slots=True)
|
|
41
59
|
class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
42
60
|
authorizer: ActionAuthorizer
|
|
43
61
|
retriever: Retriever
|
|
44
62
|
telemetry: TelemetrySink
|
|
63
|
+
memory_root: Path
|
|
45
64
|
lifecycle: CanonicalLifecycleService | None = None
|
|
46
|
-
admin_gate: AdminGate | None = None
|
|
47
65
|
|
|
48
66
|
def observe(
|
|
49
67
|
self,
|
|
@@ -68,12 +86,13 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
68
86
|
|
|
69
87
|
scopes = tuple(
|
|
70
88
|
scope
|
|
71
|
-
for scope in (request.authorized_scopes or decision.
|
|
72
|
-
if
|
|
89
|
+
for scope in (request.authorized_scopes or decision.read_prefixes)
|
|
90
|
+
if allows(decision, scope, "read", root=self.memory_root)
|
|
73
91
|
)
|
|
74
92
|
if not scopes:
|
|
75
93
|
raise AuthorizationDenied("policy produced no authorized retrieval scope")
|
|
76
94
|
|
|
95
|
+
narrowed = narrow(decision, "read", scopes)
|
|
77
96
|
allowed_ids = request.allowed_artifact_ids
|
|
78
97
|
if decision.resource_ids:
|
|
79
98
|
allowed_ids = tuple(
|
|
@@ -92,33 +111,28 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
92
111
|
scoped_retrieve = getattr(self.retriever, "retrieve_authorized", None)
|
|
93
112
|
result = (
|
|
94
113
|
scoped_retrieve(authorized_request, actor=actor,
|
|
95
|
-
|
|
114
|
+
decision=narrowed, lifecycle=self.lifecycle)
|
|
96
115
|
if callable(scoped_retrieve)
|
|
97
116
|
else self.retriever.retrieve(authorized_request)
|
|
98
117
|
)
|
|
99
118
|
|
|
100
119
|
# Defense in depth: an adapter returning an out-of-scope candidate
|
|
101
120
|
# cannot place it in model context.
|
|
102
|
-
authorized_hits = tuple(
|
|
103
|
-
hit
|
|
104
|
-
for hit in result.hits
|
|
105
|
-
if scope_allows_path(hit.canonical_path, scopes)
|
|
106
|
-
and (not allowed_ids or hit.artifact_id in allowed_ids)
|
|
107
|
-
)
|
|
108
|
-
|
|
109
121
|
# Egregore-surface admin protection: QMD may match an admin-marked
|
|
110
122
|
# document internally, but for a non-admin actor it must contribute
|
|
111
123
|
# nothing to evidence — no title, path, snippet, count detail, or
|
|
112
124
|
# model context. Only an opaque withheld tally survives.
|
|
125
|
+
visible_hits = []
|
|
113
126
|
withheld_admin = 0
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
for hit in result.hits:
|
|
128
|
+
verdict = check(narrowed, hit.canonical_path, "read", root=self.memory_root)
|
|
129
|
+
if allowed_ids and hit.artifact_id not in allowed_ids:
|
|
130
|
+
continue
|
|
131
|
+
if verdict.reason.startswith("held:"):
|
|
132
|
+
withheld_admin += 1
|
|
133
|
+
if verdict.allowed:
|
|
134
|
+
visible_hits.append(hit)
|
|
135
|
+
authorized_hits = tuple(visible_hits)
|
|
122
136
|
|
|
123
137
|
lifecycle_by_path: dict[str, LifecycleRecord] = {}
|
|
124
138
|
lifecycle_revision = "unavailable"
|
|
@@ -128,7 +142,7 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
128
142
|
resolved, lifecycle_revision = self.lifecycle.resolve_paths(
|
|
129
143
|
tuple(hit.canonical_path for hit in authorized_hits),
|
|
130
144
|
source_revision=result.source_revision,
|
|
131
|
-
|
|
145
|
+
decision=narrowed,
|
|
132
146
|
allowed_artifact_ids=allowed_ids,
|
|
133
147
|
)
|
|
134
148
|
lifecycle_by_path = dict(resolved)
|
|
@@ -189,6 +203,7 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
189
203
|
request,
|
|
190
204
|
token_budget,
|
|
191
205
|
lifecycle_by_path,
|
|
206
|
+
decision=decision, # names are shared or not against all the reader may see
|
|
192
207
|
)
|
|
193
208
|
# A rolling-window receipt is reusable only until its oldest delivered
|
|
194
209
|
# source expires. Omitted/withheld hits must not affect this boundary.
|
|
@@ -209,6 +224,20 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
209
224
|
for permission in Permission
|
|
210
225
|
if self.authorizer.authorize_action(actor, permission).allowed
|
|
211
226
|
)
|
|
227
|
+
# Retrieval and source packaging may outlive the authority that admitted
|
|
228
|
+
# them. Do not deliver a prepared context after revocation or a changed
|
|
229
|
+
# policy: even its omissions may name sources the reader can no longer
|
|
230
|
+
# see. The caller can retry with the current effective decision.
|
|
231
|
+
current_decision = self.authorizer.authorize_observe(actor, request)
|
|
232
|
+
if not current_decision.allowed or current_decision != decision:
|
|
233
|
+
raise AuthorizationDenied("retrieval authority changed; retry the request")
|
|
234
|
+
# Holds can change in canonical files without changing a policy receipt.
|
|
235
|
+
# Recheck every selected path, including sources named only by omissions.
|
|
236
|
+
if any(
|
|
237
|
+
not allows(current_decision, hit.canonical_path, "read", root=self.memory_root)
|
|
238
|
+
for hit in selected_hits
|
|
239
|
+
):
|
|
240
|
+
raise AuthorizationDenied("retrieval source access changed; retry the request")
|
|
212
241
|
context = OrgContext(
|
|
213
242
|
schema_version="egregore-context/v1",
|
|
214
243
|
context_id=f"ctx_{uuid4().hex}",
|
|
@@ -275,6 +304,8 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
275
304
|
request: RetrievalRequest,
|
|
276
305
|
token_budget: int,
|
|
277
306
|
lifecycle_by_path: dict[str, LifecycleRecord] | None = None,
|
|
307
|
+
*,
|
|
308
|
+
decision: PolicyDecision,
|
|
278
309
|
) -> tuple[tuple[EvidenceItem, ...], tuple[str, ...], tuple[str, ...], int]:
|
|
279
310
|
evidence: list[EvidenceItem] = []
|
|
280
311
|
opened_ids: list[str] = []
|
|
@@ -298,8 +329,16 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
298
329
|
omissions.append(f"stale-passage:{hit.canonical_path}")
|
|
299
330
|
else:
|
|
300
331
|
content = hit.passage or ""
|
|
332
|
+
# The one packaging, before the budget cuts: names of documents held from this reader leave
|
|
333
|
+
# every excerpt, title, source, revision and id; a text that cannot be redacted is not handed over.
|
|
334
|
+
try:
|
|
335
|
+
content = _packaged(decision, content, self.memory_root)
|
|
336
|
+
revision = redact(decision, hit.revision or "unknown", root=self.memory_root)
|
|
337
|
+
artifact_id = identity(decision, hit.artifact_id, hit.canonical_path, root=self.memory_root)
|
|
338
|
+
except RedactionError:
|
|
339
|
+
continue
|
|
301
340
|
if not content:
|
|
302
|
-
omissions.append(f"empty:{
|
|
341
|
+
omissions.append(f"empty:{artifact_id}")
|
|
303
342
|
continue
|
|
304
343
|
|
|
305
344
|
count = _token_count(content)
|
|
@@ -310,9 +349,9 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
|
|
|
310
349
|
omissions.append(f"truncated:{hit.canonical_path}")
|
|
311
350
|
evidence.append(
|
|
312
351
|
EvidenceItem(
|
|
313
|
-
artifact_id=
|
|
352
|
+
artifact_id=artifact_id,
|
|
314
353
|
canonical_path=hit.canonical_path,
|
|
315
|
-
revision=
|
|
354
|
+
revision=revision,
|
|
316
355
|
reason=self._evidence_reason(
|
|
317
356
|
hit,
|
|
318
357
|
(lifecycle_by_path or {}).get(hit.canonical_path),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Disposable observers for completed, authorized Runtime operations."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Callable
|
|
5
|
+
from .contracts import ExecutionAuthority
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True, slots=True)
|
|
9
|
+
class RuntimeEvent:
|
|
10
|
+
kind: str
|
|
11
|
+
actor_id: str
|
|
12
|
+
session_id: str
|
|
13
|
+
harness: str
|
|
14
|
+
paths: tuple[str, ...]
|
|
15
|
+
execution: ExecutionAuthority | None = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Observer = Callable[[RuntimeEvent], None]
|
|
19
|
+
MAX_EVENT_PATHS = 40
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Load a separately delivered module; failures inside installed code still raise."""
|
|
2
|
+
from importlib import import_module
|
|
3
|
+
from importlib.util import resolve_name
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def optional_module(name: str):
|
|
7
|
+
absolute = resolve_name(name, __package__)
|
|
8
|
+
try:
|
|
9
|
+
return import_module(absolute)
|
|
10
|
+
except ModuleNotFoundError as exc:
|
|
11
|
+
if exc.name != absolute:
|
|
12
|
+
raise
|
|
13
|
+
return None
|