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,85 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Reflex (show): a session inside a sandbox says what runs degraded and
|
|
3
|
+
# what will not work.
|
|
4
|
+
#
|
|
5
|
+
# Positive markers only, the predicate bin/lib/secret_entry.py and
|
|
6
|
+
# egregore_runtime/sandbox.py use: CODEX_SANDBOX set to anything but empty,
|
|
7
|
+
# none, false or 0, or APP_SANDBOX_CONTAINER_ID set. No marker, no line, on
|
|
8
|
+
# every harness; a missing DISPLAY or a failing write never names a sandbox.
|
|
9
|
+
# With a marker, one file is created and removed where the runtime keeps its
|
|
10
|
+
# per-user state (search and telemetry, resolved as egregore_runtime does).
|
|
11
|
+
# The line follows the result: writable state, and search and browser checks
|
|
12
|
+
# will not work; refused state, and search runs degraded on the workspace
|
|
13
|
+
# copy, with a second line saying that state is read-only here.
|
|
14
|
+
set -u
|
|
15
|
+
|
|
16
|
+
marker="$(printf '%s' "${CODEX_SANDBOX:-}" | tr '[:upper:]' '[:lower:]')"
|
|
17
|
+
case "$marker" in
|
|
18
|
+
""|none|false|0) [ -n "${APP_SANDBOX_CONTAINER_ID:-}" ] || exit 0 ;;
|
|
19
|
+
esac
|
|
20
|
+
|
|
21
|
+
# Create and remove one file in the nearest existing ancestor of a directory;
|
|
22
|
+
# fails when that location refuses the write or keeps the file. A probe file
|
|
23
|
+
# that outlives its test is removed again on the way out, and that retry
|
|
24
|
+
# never fails the probe, even under an inherited errexit.
|
|
25
|
+
probe_file=""
|
|
26
|
+
trap 'if [ -n "$probe_file" ]; then rm -f "$probe_file" 2>/dev/null || true; fi' EXIT
|
|
27
|
+
writable() {
|
|
28
|
+
local dir="$1" parent
|
|
29
|
+
case "$dir" in \~/*) dir="${HOME:-}/${dir#\~/}" ;; esac
|
|
30
|
+
# A relative override is relative to the current directory, as the runtime
|
|
31
|
+
# resolves it; the walk must reach that directory, never stop short of it.
|
|
32
|
+
case "$dir" in /*) ;; *) dir="$PWD/$dir" ;; esac
|
|
33
|
+
while [ ! -e "$dir" ]; do
|
|
34
|
+
parent="${dir%/*}"
|
|
35
|
+
[ -n "$parent" ] || parent=/
|
|
36
|
+
[ "$parent" != "$dir" ] || break
|
|
37
|
+
dir="$parent"
|
|
38
|
+
done
|
|
39
|
+
[ -d "$dir" ] || return 0
|
|
40
|
+
probe_file="$(mktemp "$dir/.egregore-write-probe.XXXXXX" 2>/dev/null)" || { probe_file=""; return 1; }
|
|
41
|
+
rm -f "$probe_file" 2>/dev/null || return 1
|
|
42
|
+
probe_file=""
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Both stores key their per-user directory by the resolved memory checkout
|
|
46
|
+
# (QmdLocalRetriever._instance_hash, LocalTelemetrySink's namespace).
|
|
47
|
+
root="${EGREGORE_ROOT:-.}"
|
|
48
|
+
memory="$(cd "$root/memory" 2>/dev/null && pwd -P)" \
|
|
49
|
+
|| memory="$(cd "$root" 2>/dev/null && pwd -P)/memory"
|
|
50
|
+
digest=""
|
|
51
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
52
|
+
digest="$(printf '%s' "$memory" | LC_ALL=C shasum -a 256 2>/dev/null)"
|
|
53
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
54
|
+
digest="$(printf '%s' "$memory" | sha256sum 2>/dev/null)"
|
|
55
|
+
fi
|
|
56
|
+
digest="${digest%% *}"
|
|
57
|
+
|
|
58
|
+
search_state="${EGREGORE_QMD_RUNTIME_DIR:-}"
|
|
59
|
+
telemetry_state="${EGREGORE_TELEMETRY_DIR:-}"
|
|
60
|
+
if [ -n "${HOME:-}" ]; then
|
|
61
|
+
[ -n "$search_state" ] || search_state="$HOME/.egregore/runtime/qmd${digest:+/${digest:0:16}}"
|
|
62
|
+
[ -n "$telemetry_state" ] || telemetry_state="$HOME/.egregore/telemetry${digest:+/${digest:0:20}}"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
refused=""
|
|
66
|
+
for state in "$search_state" "$telemetry_state"; do
|
|
67
|
+
[ -n "$state" ] || continue
|
|
68
|
+
if ! writable "$state"; then
|
|
69
|
+
refused=1
|
|
70
|
+
break
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
# shellcheck disable=SC2016 # the backticks are part of each line
|
|
75
|
+
if [ -n "$refused" ]; then
|
|
76
|
+
# The runtime falls back to the workspace copy: lexical search, telemetry
|
|
77
|
+
# kept there. The read-only fact gets its own line, because this one uses
|
|
78
|
+
# 157 of the runner's 160 characters.
|
|
79
|
+
printf '%s\n' 'this session runs in a sandbox: search runs degraded, telemetry stays in the workspace and browser checks will not work · start through `egregore` to lift it'
|
|
80
|
+
printf '%s\n' 'per-user state is read-only here'
|
|
81
|
+
else
|
|
82
|
+
# Per-user state stays in use, but the sandbox refuses the loopback port
|
|
83
|
+
# of the query worker, so search fails instead of degrading.
|
|
84
|
+
printf '%s\n' 'this session runs in a sandbox: search and browser checks will not work · start through `egregore` to lift it'
|
|
85
|
+
fi
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Reflex: your session cost over seven days. Show tier.
|
|
3
|
+
|
|
4
|
+
Reads the current person's session records from the last seven days, today
|
|
5
|
+
included, and only the files whose names fall in that window. A priced record
|
|
6
|
+
counts under its harness (a record priced at list price is a Codex session);
|
|
7
|
+
an unpriced record counts apart, with the input tokens from its Cost section.
|
|
8
|
+
Prints one line, leaving out the parts that are zero, and nothing without
|
|
9
|
+
records. Numbers only: no topic, branch or prompt text.
|
|
10
|
+
"""
|
|
11
|
+
import datetime
|
|
12
|
+
import json
|
|
13
|
+
import math
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
DAYS = 7
|
|
20
|
+
READ_LIMIT = 256 * 1024
|
|
21
|
+
PRICED = ("ledger", "estimate", "list price")
|
|
22
|
+
LABELS = {"claude": "Claude", "codex": "Codex", "pi": "Pi", "prime": "Prime", "other": "Other"}
|
|
23
|
+
TOKENS = re.compile(r"^- tokens: (\d+) input\b", re.M)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def front_matter(text):
|
|
27
|
+
if not text.startswith("---\n"):
|
|
28
|
+
return {}
|
|
29
|
+
block = text[4:].partition("\n---")[0]
|
|
30
|
+
fields = {}
|
|
31
|
+
for line in block.splitlines():
|
|
32
|
+
key, sep, value = line.partition(":")
|
|
33
|
+
if not sep:
|
|
34
|
+
continue
|
|
35
|
+
value = value.strip()
|
|
36
|
+
try:
|
|
37
|
+
value = json.loads(value)
|
|
38
|
+
except ValueError:
|
|
39
|
+
pass
|
|
40
|
+
fields[key.strip()] = value
|
|
41
|
+
return fields
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def amount(value):
|
|
45
|
+
try:
|
|
46
|
+
number = float(value)
|
|
47
|
+
except (TypeError, ValueError):
|
|
48
|
+
return 0.0
|
|
49
|
+
return number if math.isfinite(number) and number > 0 else 0.0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def compact(count):
|
|
53
|
+
value, unit = float(count), ""
|
|
54
|
+
for name in ("K", "M", "B"):
|
|
55
|
+
if round(value, 1) < 1000:
|
|
56
|
+
break
|
|
57
|
+
value, unit = value / 1000, name
|
|
58
|
+
return (f"{value:.1f}".removesuffix(".0") if unit else str(count)) + unit
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def main():
|
|
62
|
+
memory = os.environ.get("EGREGORE_MEMORY", "")
|
|
63
|
+
author = re.sub(r"[^a-z0-9_-]", "", os.environ.get("EGREGORE_AUTHOR", "").strip().lower())
|
|
64
|
+
sessions = Path(memory) / "sessions" if memory else None
|
|
65
|
+
if not author or sessions is None or not sessions.is_dir():
|
|
66
|
+
return 0
|
|
67
|
+
today = datetime.date.today()
|
|
68
|
+
priced = dict.fromkeys(LABELS.values(), 0.0)
|
|
69
|
+
unpriced, tokens, seen = 0, 0, set()
|
|
70
|
+
for offset in range(DAYS):
|
|
71
|
+
day = today - datetime.timedelta(days=offset)
|
|
72
|
+
try:
|
|
73
|
+
paths = sorted((sessions / day.strftime("%Y-%m")).glob(day.strftime("%d-") + author + "-*.md"))
|
|
74
|
+
except OSError:
|
|
75
|
+
continue
|
|
76
|
+
for path in paths:
|
|
77
|
+
try:
|
|
78
|
+
with path.open("rb") as stream:
|
|
79
|
+
text = stream.read(READ_LIMIT).decode("utf-8", errors="replace")
|
|
80
|
+
except OSError:
|
|
81
|
+
continue
|
|
82
|
+
meta = front_matter(text)
|
|
83
|
+
owner = str(meta.get("from", "")).strip().lower()
|
|
84
|
+
# Producer-bearing records are never a person's session, including
|
|
85
|
+
# malformed metadata and records copied without a private adapter.
|
|
86
|
+
if any(key.strip().strip("\"'").casefold() in
|
|
87
|
+
{"producer", "producer_principal_id", "producer_identity", "record_owner_actor_id", "subject_kind"}
|
|
88
|
+
and (key != "subject_kind" or value != "human-session") for key, value in meta.items()):
|
|
89
|
+
continue
|
|
90
|
+
session = str(meta.get("session", path.name))
|
|
91
|
+
if meta.get("kind") != "session-record" or owner != author or session in seen:
|
|
92
|
+
continue
|
|
93
|
+
seen.add(session)
|
|
94
|
+
source = meta.get("cost_source", "estimate")
|
|
95
|
+
if source in PRICED:
|
|
96
|
+
harness = "codex" if source == "list price" else str(meta.get("harness") or "claude").lower()
|
|
97
|
+
priced[LABELS.get(harness, "Other")] += amount(meta.get("cost_usd"))
|
|
98
|
+
continue
|
|
99
|
+
unpriced += 1
|
|
100
|
+
match = TOKENS.search(text.partition("\n## Cost\n")[2])
|
|
101
|
+
tokens += int(match.group(1)) if match else 0
|
|
102
|
+
parts = []
|
|
103
|
+
total = sum(priced.values())
|
|
104
|
+
if round(total, 2) > 0:
|
|
105
|
+
split = ", ".join(f"{label} ${value:,.2f}" for label, value in priced.items() if round(value, 2) > 0)
|
|
106
|
+
parts.append(f"${total:,.2f} priced ({split})")
|
|
107
|
+
if unpriced:
|
|
108
|
+
part = f"{unpriced} unpriced session" + ("" if unpriced == 1 else "s")
|
|
109
|
+
parts.append(part + (f", {compact(tokens)} input tokens" if tokens else ""))
|
|
110
|
+
if parts:
|
|
111
|
+
print("7 days: " + " · ".join(parts))
|
|
112
|
+
return 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
sys.exit(main())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Reflex: refused shell shapes. Show tier.
|
|
3
|
+
|
|
4
|
+
Reads yesterday's session records of the current person and sums the
|
|
5
|
+
`worktree-guard refusals` counter from their Friction sections. Three or
|
|
6
|
+
more prints one line with the count and the pointer to the plain forms.
|
|
7
|
+
"""
|
|
8
|
+
import datetime
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
COUNTER = re.compile(r"^- worktree-guard refusals: (\d+)\s*$", re.M)
|
|
15
|
+
FROM = re.compile(r"^from:\s*(.+?)\s*$", re.M)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main():
|
|
19
|
+
memory = os.environ.get("EGREGORE_MEMORY", "")
|
|
20
|
+
author = os.environ.get("EGREGORE_AUTHOR", "").strip().casefold()
|
|
21
|
+
sessions = Path(memory) / "sessions" if memory else None
|
|
22
|
+
if sessions is None or not sessions.is_dir():
|
|
23
|
+
return 0
|
|
24
|
+
yesterday = datetime.date.today() - datetime.timedelta(days=1)
|
|
25
|
+
folder = sessions / yesterday.strftime("%Y-%m")
|
|
26
|
+
total, files = 0, 0
|
|
27
|
+
try:
|
|
28
|
+
paths = sorted(folder.glob(yesterday.strftime("%d-") + "*.md"))
|
|
29
|
+
except OSError:
|
|
30
|
+
return 0
|
|
31
|
+
for path in paths:
|
|
32
|
+
try:
|
|
33
|
+
text = path.read_text(encoding="utf-8", errors="replace")[:200000]
|
|
34
|
+
except OSError:
|
|
35
|
+
continue
|
|
36
|
+
head = text.partition("\n---")[0]
|
|
37
|
+
owner = FROM.search(head)
|
|
38
|
+
if author and owner and owner.group(1).strip("\"'").casefold() != author:
|
|
39
|
+
continue
|
|
40
|
+
match = COUNTER.search(text)
|
|
41
|
+
if match:
|
|
42
|
+
total += int(match.group(1))
|
|
43
|
+
files += 1
|
|
44
|
+
if total >= 3:
|
|
45
|
+
noun = "session" if files == 1 else "sessions"
|
|
46
|
+
print(f"{total} refused shell commands yesterday across {files} {noun} · plain forms: .claude/context/plain-shell.md")
|
|
47
|
+
return 0
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
sys.exit(main())
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Reflexes
|
|
2
|
+
|
|
3
|
+
A reflex is a probe with a tier. The probe states a fact about yesterday; the
|
|
4
|
+
tier says how far the egregore may go on its own: say it (show), end the line
|
|
5
|
+
with the command to run (propose), or do it and leave a receipt (act). The
|
|
6
|
+
startup card is where the probes speak, on every harness. The act tier never
|
|
7
|
+
prints from here; it lives in the path it governs, such as the merge gate in
|
|
8
|
+
the save path.
|
|
9
|
+
|
|
10
|
+
## A probe
|
|
11
|
+
|
|
12
|
+
One file in this directory: a `.sh` or `.py` file, or any executable. The
|
|
13
|
+
runner (`bin/reflexes.sh`, `bin/lib/reflexes.py`) runs them in name order,
|
|
14
|
+
one at a time, and prints each line a probe writes to stdout with the card's
|
|
15
|
+
sigil in front. A probe prints nothing when there is nothing to say, one line
|
|
16
|
+
for a fact, two at most. Lines are cut at 160 characters.
|
|
17
|
+
|
|
18
|
+
The runner never fails the card. A probe that exits non-zero, prints nothing,
|
|
19
|
+
or runs past one second is silent; the runner stops launching probes once
|
|
20
|
+
three seconds have passed in total. `bash bin/reflexes.sh --debug` names
|
|
21
|
+
every silent probe and the reason.
|
|
22
|
+
|
|
23
|
+
Sessions started minutes apart print the same card, so the runner keeps the
|
|
24
|
+
last card for each harness in `.egregore/runtime/reflexes/` and prints it
|
|
25
|
+
again, for up to ten minutes, while what the probes read is unchanged: the
|
|
26
|
+
probe and `bin/lib` files, everything under `memory/sessions` (records and
|
|
27
|
+
ledgers), the features in `egregore.json`, the person's names and records
|
|
28
|
+
switch in the state file, the local date and nightly's cache (`cache_key` in
|
|
29
|
+
`bin/lib/reflexes.py`). Anything else, such as the memory lookups the
|
|
30
|
+
retrieval line counts, can be up to ten minutes old on the card. `--debug`, a
|
|
31
|
+
sandbox marker, or a run in which a probe ran past its budget or never
|
|
32
|
+
started skips the cache.
|
|
33
|
+
|
|
34
|
+
Every probe gets, on top of the caller's environment:
|
|
35
|
+
|
|
36
|
+
- `EGREGORE_ROOT` the project root
|
|
37
|
+
- `EGREGORE_MEMORY` the memory directory, which may not exist
|
|
38
|
+
- `EGREGORE_STATE` the per-instance state file (`.egregore-state.json`)
|
|
39
|
+
- `EGREGORE_AUTHOR` the person's GitHub username, when known
|
|
40
|
+
- `EGREGORE_HARNESS` `claude`, `codex`, `pi` or `prime`
|
|
41
|
+
|
|
42
|
+
A probe reads records, state and local files; it never reaches the network
|
|
43
|
+
without a cache and a budget, never writes outside `tmp/` (beyond one file
|
|
44
|
+
created and removed to test a directory, as `20-sandbox.sh` does), and never
|
|
45
|
+
prints anything a record would withhold.
|
|
46
|
+
|
|
47
|
+
## Adding one
|
|
48
|
+
|
|
49
|
+
Add a file here with a two-digit prefix for order (`20-nightly.sh`), make it
|
|
50
|
+
print its line only when its predicate holds, and give it a case in
|
|
51
|
+
`tests/test-reflexes.sh` or a test of its own. A probe that reads a file the
|
|
52
|
+
cache key does not cover shows its change up to ten minutes late; add the
|
|
53
|
+
file to `cache_key` when that matters. The runtime bundle ships this
|
|
54
|
+
directory whole (`BIN_DIRS` in the bundle builder), so a tracked probe needs
|
|
55
|
+
no allowlist entry. An organisation adds its own probes the same way.
|
|
56
|
+
|
|
57
|
+
## Wording
|
|
58
|
+
|
|
59
|
+
A show line states the fact: `3 open items are older than three days and
|
|
60
|
+
have no owner`. A propose line ends with the command: `... · /records file
|
|
61
|
+
a1b2c3`. No exclamation marks, no advice, no explanation of the mechanism.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# The reflexes: one runner, a directory of probes. See bin/reflexes/README.md.
|
|
3
|
+
# Prints the probes' lines for the startup card; never fails the card.
|
|
4
|
+
set -uo pipefail
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" || exit 0
|
|
6
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
7
|
+
exec python3 "$SCRIPT_DIR/bin/lib/reflexes.py" --root "$SCRIPT_DIR" "$@"
|
|
@@ -14,6 +14,8 @@ ROOT="${EGREGORE_INSTANCE_ROOT:-$RUNTIME_ROOT}"
|
|
|
14
14
|
ROOT="$(cd "$ROOT" && pwd)"
|
|
15
15
|
CONFIG="$ROOT/egregore.json"
|
|
16
16
|
STATE="$ROOT/.egregore-state.json"
|
|
17
|
+
# shellcheck source=bin/lib/config.sh
|
|
18
|
+
source "$RUNTIME_ROOT/bin/lib/config.sh"
|
|
17
19
|
|
|
18
20
|
resolved() {
|
|
19
21
|
[ -f "$CONFIG" ] && [ -f "$STATE" ] || return 1
|
|
@@ -26,6 +28,114 @@ resolved() {
|
|
|
26
28
|
' "$STATE" >/dev/null 2>&1
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
# The saved address is resolved: an egregore.json saved before the October
|
|
32
|
+
# 2026 move still names the retired origin, which never receives a token.
|
|
33
|
+
connected_config() {
|
|
34
|
+
api_url="$(_config_api_url)" || api_url=""
|
|
35
|
+
slug="$(jq -r '.slug // empty' "$CONFIG" 2>/dev/null)"
|
|
36
|
+
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2- || true)"
|
|
37
|
+
[ -n "$api_url" ] && [ -n "$slug" ]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# The greeting's one note about the organization key (bin/lib/health-footer.sh
|
|
41
|
+
# renders it): "renewed" shows once; "needs_sign_in" shows until renewal works.
|
|
42
|
+
key_notice_state() {
|
|
43
|
+
jq -r '.hosted_key_notice.state // empty' "$STATE" 2>/dev/null || true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
key_notice() {
|
|
47
|
+
local file tmp
|
|
48
|
+
[ -f "$STATE" ] || return 0
|
|
49
|
+
# A worktree links the checkout's state file: rename onto its target.
|
|
50
|
+
file="$(realpath "$STATE" 2>/dev/null)" || file="$STATE"
|
|
51
|
+
tmp="$(mktemp "$file.XXXXXX" 2>/dev/null)" || return 0
|
|
52
|
+
if [ "$1" = clear ]; then
|
|
53
|
+
jq 'if .hosted_key_notice.state == "needs_sign_in" then del(.hosted_key_notice) else . end' \
|
|
54
|
+
"$file" >"$tmp" 2>/dev/null
|
|
55
|
+
else
|
|
56
|
+
jq --arg state "$1" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
57
|
+
'.hosted_key_notice = {state: $state, at: $at}' "$file" >"$tmp" 2>/dev/null
|
|
58
|
+
fi && [ -s "$tmp" ] && mv "$tmp" "$file" || rm -f "$tmp"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# One authenticated status read; sets status_code and status_body.
|
|
62
|
+
probe_status() {
|
|
63
|
+
local response=""
|
|
64
|
+
status_code=""
|
|
65
|
+
status_body=""
|
|
66
|
+
[ -n "$api_key" ] || return 0
|
|
67
|
+
response="$(curl -s "$api_url/api/org/status" \
|
|
68
|
+
-H "Authorization: Bearer $api_key" --connect-timeout 2 --max-time 4 \
|
|
69
|
+
-w '\n%{http_code}' 2>/dev/null || true)"
|
|
70
|
+
status_code="${response##*$'\n'}"
|
|
71
|
+
status_body="${response%$'\n'*}"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
status_ok() {
|
|
75
|
+
[ "$status_code" = 200 ] && printf '%s' "$status_body" | jq -e --arg slug "$slug" '
|
|
76
|
+
(.org_id | type == "string" and length > 0) and .slug == $slug
|
|
77
|
+
' >/dev/null 2>&1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
rejection_code() {
|
|
81
|
+
[ "$status_code" = 401 ] || return 0
|
|
82
|
+
printf '%s' "$status_body" | jq -r '.code // empty' 2>/dev/null || true
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Recover the configured org's key only through the membership-verifying
|
|
86
|
+
# endpoint, which renews a key retired in the October 2026 security reset.
|
|
87
|
+
# A historic path/namespace collision could also leave this checkout with
|
|
88
|
+
# another Egregore's key. Install it atomically, then verify it. No
|
|
89
|
+
# credential bytes are printed. $1 is the API's code for the rejected key.
|
|
90
|
+
recover_key() {
|
|
91
|
+
local rejected="${1:-}" github_token encoded_slug response code recovered renewed previous_key
|
|
92
|
+
github_token="$(grep '^GITHUB_TOKEN=' "$ROOT/.env" 2>/dev/null | cut -d= -f2- || true)"
|
|
93
|
+
if [ -z "$github_token" ]; then
|
|
94
|
+
[ "$rejected" != key_retired ] || key_notice needs_sign_in
|
|
95
|
+
return 1
|
|
96
|
+
fi
|
|
97
|
+
encoded_slug="$(printf '%s' "$slug" | jq -sRr @uri)"
|
|
98
|
+
response="$(curl -s "$api_url/api/org/$encoded_slug/key" \
|
|
99
|
+
-H "Authorization: Bearer $github_token" --connect-timeout 2 --max-time 12 \
|
|
100
|
+
-w '\n%{http_code}' 2>/dev/null || true)"
|
|
101
|
+
code="${response##*$'\n'}"
|
|
102
|
+
recovered="${response%$'\n'*}"
|
|
103
|
+
if [ "$code" = 401 ]; then
|
|
104
|
+
# The GitHub sign-in was rejected; a fresh one renews the key.
|
|
105
|
+
[ "$rejected" != key_retired ] || key_notice needs_sign_in
|
|
106
|
+
return 1
|
|
107
|
+
fi
|
|
108
|
+
[ "$code" = 200 ] || return 1
|
|
109
|
+
# The key itself must name this org (ek_<slug>_<secret>), not just the reply.
|
|
110
|
+
printf '%s' "$recovered" | jq -e --arg slug "$slug" '
|
|
111
|
+
(.api_key | type == "string" and startswith("ek_" + $slug + "_")
|
|
112
|
+
and length > ($slug | length) + 4)
|
|
113
|
+
and .org_slug == $slug
|
|
114
|
+
' >/dev/null 2>&1 || return 1
|
|
115
|
+
renewed="$(printf '%s' "$recovered" | jq -r '.renewed == true' 2>/dev/null || echo false)"
|
|
116
|
+
# Prove the candidate works before it replaces the saved key.
|
|
117
|
+
previous_key="$api_key"
|
|
118
|
+
api_key="$(printf '%s' "$recovered" | jq -r '.api_key')"
|
|
119
|
+
probe_status
|
|
120
|
+
if ! status_ok; then
|
|
121
|
+
api_key="$previous_key"
|
|
122
|
+
return 1
|
|
123
|
+
fi
|
|
124
|
+
if ! printf '%s' "$recovered" | \
|
|
125
|
+
EGREGORE_ROOT="$ROOT" \
|
|
126
|
+
PYTHONSAFEPATH=1 PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
127
|
+
python3 -m egregore_runtime.identity_cli install-connected-key >/dev/null; then
|
|
128
|
+
api_key="$previous_key"
|
|
129
|
+
return 1
|
|
130
|
+
fi
|
|
131
|
+
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2- || true)"
|
|
132
|
+
if [ "$rejected" = key_retired ] || [ "$renewed" = true ]; then
|
|
133
|
+
key_notice renewed
|
|
134
|
+
else
|
|
135
|
+
key_notice clear
|
|
136
|
+
fi
|
|
137
|
+
}
|
|
138
|
+
|
|
29
139
|
case "${1:-ensure}" in
|
|
30
140
|
status)
|
|
31
141
|
if resolved; then
|
|
@@ -35,56 +145,44 @@ case "${1:-ensure}" in
|
|
|
35
145
|
printf '{"status":"unresolved"}\n'
|
|
36
146
|
exit 1
|
|
37
147
|
;;
|
|
148
|
+
recover)
|
|
149
|
+
# A hosted request just rejected the organization key ($2 is the API's
|
|
150
|
+
# code). Once a fresh sign-in is known to be needed, only session start
|
|
151
|
+
# retries, so the notice and the retry stay one per session.
|
|
152
|
+
[ "$(key_notice_state)" != needs_sign_in ] || exit 1
|
|
153
|
+
connected_config || exit 1
|
|
154
|
+
recover_key "${2:-}"
|
|
155
|
+
;;
|
|
38
156
|
ensure)
|
|
39
|
-
resolved
|
|
157
|
+
if resolved; then
|
|
158
|
+
# Healthy starts stop here, with no network call. After a recorded
|
|
159
|
+
# need for a fresh sign-in, retry so the greeting shows the outcome.
|
|
160
|
+
[ "$(key_notice_state)" = needs_sign_in ] || exit 0
|
|
161
|
+
connected_config || exit 0
|
|
162
|
+
probe_status
|
|
163
|
+
if status_ok; then
|
|
164
|
+
key_notice clear
|
|
165
|
+
else
|
|
166
|
+
recover_key "$(rejection_code)" || true
|
|
167
|
+
fi
|
|
168
|
+
exit 0
|
|
169
|
+
fi
|
|
40
170
|
mode="$(jq -r 'if (.mode // "local") == "connected" or (.api_url // "") != "" then "connected" else "local" end' "$CONFIG" 2>/dev/null || echo local)"
|
|
41
171
|
if [ "$mode" = "local" ]; then
|
|
42
172
|
EGREGORE_ROOT="$ROOT" \
|
|
43
173
|
PYTHONSAFEPATH=1 PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
44
174
|
python3 -m egregore_runtime.identity_cli initialize-local >/dev/null
|
|
45
175
|
else
|
|
46
|
-
|
|
47
|
-
slug="$(jq -r '.slug // empty' "$CONFIG" 2>/dev/null)"
|
|
48
|
-
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
49
|
-
[ -n "$api_url" ] && [ -n "$slug" ] || exit 1
|
|
176
|
+
connected_config || exit 1
|
|
50
177
|
# Identity repair selects already-existing account and membership
|
|
51
|
-
# records, then adopts their opaque IDs locally.
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
if
|
|
56
|
-
|
|
57
|
-
-H "Authorization: Bearer $api_key" --connect-timeout 2 --max-time 4 \
|
|
58
|
-
2>/dev/null || true)"
|
|
59
|
-
fi
|
|
60
|
-
if ! printf '%s' "$control_plane" | jq -e --arg slug "$slug" '
|
|
61
|
-
(.org_id | type == "string" and length > 0) and .slug == $slug
|
|
62
|
-
' >/dev/null 2>&1; then
|
|
63
|
-
# A historic path/namespace collision could leave this checkout with
|
|
64
|
-
# another Egregore's API key. Recover the configured org's existing key
|
|
65
|
-
# only through the membership-verifying endpoint, install it atomically,
|
|
66
|
-
# and retry. No credential bytes are printed.
|
|
67
|
-
github_token="$(grep '^GITHUB_TOKEN=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
68
|
-
[ -n "$github_token" ] || exit 1
|
|
69
|
-
encoded_slug="$(printf '%s' "$slug" | jq -sRr @uri)"
|
|
70
|
-
recovered="$(curl -sf "$api_url/api/org/$encoded_slug/key" \
|
|
71
|
-
-H "Authorization: Bearer $github_token" --connect-timeout 2 --max-time 12 \
|
|
72
|
-
2>/dev/null || true)"
|
|
73
|
-
printf '%s' "$recovered" | jq -e --arg slug "$slug" '
|
|
74
|
-
(.api_key | type == "string" and length > 0) and .org_slug == $slug
|
|
75
|
-
' >/dev/null 2>&1 || exit 1
|
|
76
|
-
printf '%s' "$recovered" | \
|
|
77
|
-
EGREGORE_ROOT="$ROOT" \
|
|
78
|
-
PYTHONSAFEPATH=1 PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
79
|
-
python3 -m egregore_runtime.identity_cli install-connected-key >/dev/null
|
|
80
|
-
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
81
|
-
control_plane="$(curl -sf "$api_url/api/org/status" \
|
|
82
|
-
-H "Authorization: Bearer $api_key" --connect-timeout 2 --max-time 4 \
|
|
83
|
-
2>/dev/null || true)"
|
|
84
|
-
printf '%s' "$control_plane" | jq -e --arg slug "$slug" '
|
|
85
|
-
(.org_id | type == "string" and length > 0) and .slug == $slug
|
|
86
|
-
' >/dev/null 2>&1 || exit 1
|
|
178
|
+
# records, then adopts their opaque IDs locally. A rejected key is
|
|
179
|
+
# recovered for the configured org only, through verified GitHub
|
|
180
|
+
# membership. No control-plane records are made.
|
|
181
|
+
probe_status
|
|
182
|
+
if ! status_ok; then
|
|
183
|
+
recover_key "$(rejection_code)" || exit 1
|
|
87
184
|
fi
|
|
185
|
+
control_plane="$status_body"
|
|
88
186
|
roster="$(curl -sf "$api_url/api/org/$slug/members?include_removed=true" \
|
|
89
187
|
-H "Authorization: Bearer $api_key" --connect-timeout 2 --max-time 4 \
|
|
90
188
|
2>/dev/null || true)"
|
|
@@ -102,7 +200,7 @@ case "${1:-ensure}" in
|
|
|
102
200
|
resolved
|
|
103
201
|
;;
|
|
104
202
|
*)
|
|
105
|
-
echo 'usage: bash bin/runtime-identity.sh {ensure|status}' >&2
|
|
203
|
+
echo 'usage: bash bin/runtime-identity.sh {ensure|status|recover [code]}' >&2
|
|
106
204
|
exit 2
|
|
107
205
|
;;
|
|
108
206
|
esac
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Render an HTML file or a URL to a PNG with headless Chrome.
|
|
3
|
+
# bin/screenshot.sh <file.html|url> <out.png> [width] [height] (1440 x 2400)
|
|
4
|
+
# Chrome: $EGREGORE_CHROME when set, with no fallback when it is wrong; else
|
|
5
|
+
# the macOS Google Chrome app; else google-chrome or chromium on PATH. An
|
|
6
|
+
# aborted render (no file, or zero bytes) is retried once; each try is capped
|
|
7
|
+
# at 30 s. Prints "<out>: <bytes> bytes"; a failure prints one line naming the
|
|
8
|
+
# cause and exits non-zero.
|
|
9
|
+
# Headless Chrome enforces a minimum window width near 500 px, so phone checks
|
|
10
|
+
# use 600. Heights above about 5400 px yield no file. Run one headless Chrome
|
|
11
|
+
# at a time. Chrome dies at launch under the Codex sandbox, so in a minion run
|
|
12
|
+
# the driver renders (.claude/skills/minion/SKILL.md, LAND).
|
|
13
|
+
set -u
|
|
14
|
+
|
|
15
|
+
die() { printf 'screenshot: %s\n' "$1" >&2; exit "${2:-1}"; }
|
|
16
|
+
whole() { for n in "$@"; do case $n in '' | 0* | *[!0-9]*) return 1 ;; esac; done; }
|
|
17
|
+
|
|
18
|
+
[ $# -ge 2 ] && [ $# -le 4 ] || die "usage: bin/screenshot.sh <file.html|url> <out.png> [width] [height]" 2
|
|
19
|
+
input=$1 out=$2 width=${3:-1440} height=${4:-2400}
|
|
20
|
+
whole "$width" "$height" || die "width and height must be whole pixels, got $width x $height" 2
|
|
21
|
+
|
|
22
|
+
if [[ $input =~ ^[A-Za-z][A-Za-z0-9+.-]*:// ]] || [[ $input == data:* ]] || [[ $input == about:* ]]; then
|
|
23
|
+
url=$input
|
|
24
|
+
else
|
|
25
|
+
[ -f "$input" ] && [ -r "$input" ] || die "input file missing: $input"
|
|
26
|
+
case $input in */*) dir=${input%/*} ;; *) dir=. ;; esac
|
|
27
|
+
dir=$(cd -- "${dir:-/}" && pwd -P) || die "input file missing: $input"
|
|
28
|
+
url=file://
|
|
29
|
+
# Percent-encode every byte outside the unreserved set, so a space, "#", "?",
|
|
30
|
+
# "%", a control character or a non-UTF-8 name reaches Chrome intact.
|
|
31
|
+
# shellcheck disable=SC2046 # the words are od's hex pairs; splitting them is the point
|
|
32
|
+
for byte in $(printf '%s' "${dir%/}/${input##*/}" | od -An -v -tx1); do
|
|
33
|
+
case $byte in
|
|
34
|
+
2[d-f] | 3[0-9] | 4[1-9a-f] | 5[0-9a] | 5f | 6[1-9a-f] | 7[0-9a] | 7e)
|
|
35
|
+
printf -v char '%b' "\\x$byte"; url+=$char ;;
|
|
36
|
+
*) url+=%$byte ;;
|
|
37
|
+
esac
|
|
38
|
+
done
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
case $out in */*) outdir=${out%/*} ;; *) outdir=. ;; esac
|
|
42
|
+
[ -d "${outdir:-/}" ] && [ -w "${outdir:-/}" ] || die "output directory missing or not writable: ${outdir:-/}"
|
|
43
|
+
[ ! -d "$out" ] || die "output path is a directory: $out"
|
|
44
|
+
|
|
45
|
+
if [ -n "${EGREGORE_CHROME:-}" ]; then
|
|
46
|
+
chrome=$EGREGORE_CHROME
|
|
47
|
+
[ -f "$chrome" ] && [ -x "$chrome" ] || die "no Chrome found: EGREGORE_CHROME=$chrome is not an executable file"
|
|
48
|
+
else
|
|
49
|
+
chrome="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
50
|
+
[ -x "$chrome" ] || chrome=$(command -v google-chrome || command -v chromium) \
|
|
51
|
+
|| die "no Chrome found: set EGREGORE_CHROME, or install Google Chrome or Chromium"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
pid=
|
|
55
|
+
trap '[ -z "$pid" ] || kill "$pid" 2>/dev/null' EXIT
|
|
56
|
+
trap 'exit 130' INT TERM HUP
|
|
57
|
+
|
|
58
|
+
render() { # one try; true when Chrome left a non-empty file at $out
|
|
59
|
+
rm -f -- "$out"; timed_out=0 ticks=0
|
|
60
|
+
"$chrome" --headless=new --disable-gpu --hide-scrollbars --window-size="$width,$height" \
|
|
61
|
+
--virtual-time-budget=4000 --screenshot="$out" "$url" >/dev/null 2>&1 &
|
|
62
|
+
pid=$!
|
|
63
|
+
while kill -0 "$pid" 2>/dev/null; do
|
|
64
|
+
[ "$ticks" -lt 150 ] || { kill -9 "$pid" 2>/dev/null; timed_out=1; break; }
|
|
65
|
+
sleep 0.2; ticks=$((ticks + 1))
|
|
66
|
+
done
|
|
67
|
+
wait "$pid" 2>/dev/null; pid=
|
|
68
|
+
[ -f "$out" ] && [ -s "$out" ]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if ! render && ! render; then
|
|
72
|
+
cause="no file at $out"
|
|
73
|
+
[ "$timed_out" = 0 ] || cause="the last try timed out after 30 s"
|
|
74
|
+
[ "$height" -le 5400 ] || cause="$cause; heights above about 5400 px yield no file"
|
|
75
|
+
die "render aborted twice ($cause)"
|
|
76
|
+
fi
|
|
77
|
+
printf '%s: %s bytes\n' "$out" "$(wc -c < "$out" | tr -d ' ')"
|
|
@@ -3,7 +3,7 @@ set -euo pipefail
|
|
|
3
3
|
|
|
4
4
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
5
|
export EGREGORE_ROOT="$ROOT"
|
|
6
|
-
export EGREGORE_SESSION_ID="${EGREGORE_SESSION_ID:-$(cat "$ROOT/.egregore-session-id" 2>/dev/null || true)}"
|
|
6
|
+
export EGREGORE_SESSION_ID="${EGREGORE_SESSION_ID:-$(bash "$ROOT/bin/session-id.sh" --root "$ROOT" 2>/dev/null || cat "$ROOT/.egregore-session-id" 2>/dev/null || true)}"
|
|
7
7
|
export PYTHONSAFEPATH=1 PYTHONPATH="$ROOT${PYTHONPATH:+:$PYTHONPATH}"
|
|
8
8
|
|
|
9
9
|
exec python3 -m egregore_runtime.scroll_cli "$@"
|