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
|
@@ -6,14 +6,20 @@ and telemetry implementations stay behind their respective adapters.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import contextlib
|
|
10
|
+
import errno
|
|
11
|
+
import os
|
|
12
|
+
import stat
|
|
13
|
+
import time
|
|
9
14
|
import uuid
|
|
10
15
|
from dataclasses import replace
|
|
11
16
|
from datetime import UTC, datetime
|
|
12
|
-
from pathlib import Path
|
|
17
|
+
from pathlib import Path, PurePosixPath
|
|
13
18
|
from typing import Callable, Sequence
|
|
14
19
|
|
|
15
20
|
from .artifacts import (
|
|
16
21
|
ARTIFACT_SCHEMA_VERSION,
|
|
22
|
+
ArtifactConflictError,
|
|
17
23
|
CanonicalArtifactStore,
|
|
18
24
|
CanonicalDocument,
|
|
19
25
|
artifact_id_from_path,
|
|
@@ -37,7 +43,46 @@ from .contracts import (
|
|
|
37
43
|
WritebackStatus,
|
|
38
44
|
)
|
|
39
45
|
from .telemetry import TELEMETRY_SCHEMA_VERSION
|
|
40
|
-
from .policy import
|
|
46
|
+
from .policy import allows
|
|
47
|
+
from .held import package
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_LINK_REFUSAL = "canonical file path must not pass through a symbolic link"
|
|
51
|
+
_NO_FOLLOW = getattr(os, "O_NOFOLLOW", 0)
|
|
52
|
+
_FOLDER = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | _NO_FOLLOW
|
|
53
|
+
_STAGING = ".staging"
|
|
54
|
+
_IGNORE_ALL = b"*\n"
|
|
55
|
+
_STALE_STAGING_SECONDS = 24 * 60 * 60
|
|
56
|
+
# What a link failure means when the filesystem has no hard links at all.
|
|
57
|
+
_NO_HARD_LINKS = frozenset({errno.EPERM, errno.ENOTSUP, errno.EOPNOTSUPP, errno.EXDEV, errno.ENOSYS})
|
|
58
|
+
# The calls creating a file makes through folder descriptors, captured at
|
|
59
|
+
# import so that a wrapped function is not mistaken for a missing one.
|
|
60
|
+
_DIR_FD_CALLS = tuple(getattr(os, name, None) for name in ("open", "mkdir", "link", "stat", "unlink"))
|
|
61
|
+
_LINK, _LISTDIR = getattr(os, "link", None), os.listdir
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class UnsupportedPlatformError(OSError):
|
|
65
|
+
"""This platform cannot walk folders and link files through descriptors,
|
|
66
|
+
so it cannot create a file safely. Checked before anything is written."""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class NoHardLinksError(OSError):
|
|
70
|
+
"""This filesystem has no hard links, so a file cannot appear complete
|
|
71
|
+
without replacing another. The staged copy is removed; nothing is written."""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def require_descriptor_calls() -> None:
|
|
75
|
+
"""Refuse, before any write, a platform (Windows, for one) without the
|
|
76
|
+
descriptor-relative calls creating a file depends on."""
|
|
77
|
+
|
|
78
|
+
if not (
|
|
79
|
+
all(call in os.supports_dir_fd for call in _DIR_FD_CALLS)
|
|
80
|
+
and _LINK in os.supports_follow_symlinks
|
|
81
|
+
and _LISTDIR in os.supports_fd
|
|
82
|
+
):
|
|
83
|
+
raise UnsupportedPlatformError(
|
|
84
|
+
"this platform cannot create files through folder descriptors; nothing was written"
|
|
85
|
+
)
|
|
41
86
|
|
|
42
87
|
|
|
43
88
|
def canonical_file_path(memory_root: Path, raw_path: str) -> Path:
|
|
@@ -61,6 +106,148 @@ def canonical_file_path(memory_root: Path, raw_path: str) -> Path:
|
|
|
61
106
|
return source
|
|
62
107
|
|
|
63
108
|
|
|
109
|
+
def canonical_new_file_path(memory_root: Path, raw_path: str) -> tuple[Path, str]:
|
|
110
|
+
"""Name a file to create inside canonical memory, reached through no link.
|
|
111
|
+
|
|
112
|
+
Authorization names the lexical path, so the file written must be that
|
|
113
|
+
path: a symbolic link anywhere below memory/ (a directory linked to
|
|
114
|
+
../private, or the file itself) would carry the write somewhere else.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
memory = memory_root.resolve()
|
|
118
|
+
relative = canonical_relative_path(raw_path.strip().removeprefix("memory/"))
|
|
119
|
+
parts = PurePosixPath(relative).parts
|
|
120
|
+
if ".git" in parts:
|
|
121
|
+
raise ValueError("canonical file must be inside memory/, outside .git")
|
|
122
|
+
if relative.casefold().endswith(".md"):
|
|
123
|
+
raise ValueError("Markdown is written through the artifact store, which checks its envelope")
|
|
124
|
+
target = memory
|
|
125
|
+
for part in parts:
|
|
126
|
+
target = target / part
|
|
127
|
+
if target.is_symlink():
|
|
128
|
+
raise ValueError(_LINK_REFUSAL)
|
|
129
|
+
return target, relative
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _open_below(name: str, folder: int, flags: int, mode: int = 0o777) -> int:
|
|
133
|
+
"""Open ``name`` inside the open folder ``folder``, never through a link."""
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
return os.open(name, flags | _NO_FOLLOW, mode, dir_fd=folder)
|
|
137
|
+
except FileNotFoundError:
|
|
138
|
+
raise
|
|
139
|
+
except OSError:
|
|
140
|
+
with contextlib.suppress(OSError):
|
|
141
|
+
if stat.S_ISLNK(os.stat(name, dir_fd=folder, follow_symlinks=False).st_mode):
|
|
142
|
+
raise ValueError(_LINK_REFUSAL) from None
|
|
143
|
+
raise
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _open_folders(memory: Path, names: Sequence[str]) -> int:
|
|
147
|
+
"""The folder a new file goes in, reached from the memory root one name at
|
|
148
|
+
a time through open descriptors, creating missing folders and following
|
|
149
|
+
no link. No path string is resolved after this walk, so a folder swapped
|
|
150
|
+
for a link while it runs cannot carry the write elsewhere."""
|
|
151
|
+
|
|
152
|
+
folder = os.open(memory, _FOLDER)
|
|
153
|
+
try:
|
|
154
|
+
for name in names:
|
|
155
|
+
try:
|
|
156
|
+
child = _open_below(name, folder, _FOLDER)
|
|
157
|
+
except FileNotFoundError:
|
|
158
|
+
with contextlib.suppress(FileExistsError):
|
|
159
|
+
os.mkdir(name, 0o755, dir_fd=folder)
|
|
160
|
+
child = _open_below(name, folder, _FOLDER)
|
|
161
|
+
os.close(folder)
|
|
162
|
+
folder = child
|
|
163
|
+
except BaseException:
|
|
164
|
+
os.close(folder)
|
|
165
|
+
raise
|
|
166
|
+
return folder
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _open_staging(memory: Path, top: Sequence[str]) -> int:
|
|
170
|
+
"""The folder a file is written in before it is published: ``.staging``
|
|
171
|
+
in the destination's top folder (``taste/.staging/`` for an event), on
|
|
172
|
+
the destination's filesystem, reached by the same descriptor walk. Its
|
|
173
|
+
``.gitignore`` holds ``*`` and is written before anything is staged, so
|
|
174
|
+
Git and autosave's ``git add -A`` never see the folder or anything in
|
|
175
|
+
it, the ``.gitignore`` included. Staged files a crash left there more
|
|
176
|
+
than a day ago are removed."""
|
|
177
|
+
|
|
178
|
+
staging = _open_folders(memory, (*top, _STAGING))
|
|
179
|
+
try:
|
|
180
|
+
if _read_below(".gitignore", staging) != _IGNORE_ALL:
|
|
181
|
+
# Written in place, never emptied first: two first writers both
|
|
182
|
+
# put the same bytes at the start, so a file that already
|
|
183
|
+
# ignores everything keeps doing so while the other stages.
|
|
184
|
+
ignore = _open_below(".gitignore", staging, os.O_WRONLY | os.O_CREAT, 0o644)
|
|
185
|
+
try:
|
|
186
|
+
os.pwrite(ignore, _IGNORE_ALL, 0)
|
|
187
|
+
os.ftruncate(ignore, len(_IGNORE_ALL))
|
|
188
|
+
os.fsync(ignore)
|
|
189
|
+
finally:
|
|
190
|
+
os.close(ignore)
|
|
191
|
+
except BaseException:
|
|
192
|
+
os.close(staging)
|
|
193
|
+
raise
|
|
194
|
+
cutoff = time.time() - _STALE_STAGING_SECONDS
|
|
195
|
+
with contextlib.suppress(OSError):
|
|
196
|
+
for name in os.listdir(staging):
|
|
197
|
+
with contextlib.suppress(OSError):
|
|
198
|
+
found = os.stat(name, dir_fd=staging, follow_symlinks=False)
|
|
199
|
+
if name.endswith(".tmp") and stat.S_ISREG(found.st_mode) and found.st_mtime < cutoff:
|
|
200
|
+
os.unlink(name, dir_fd=staging)
|
|
201
|
+
return staging
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _read_below(name: str, folder: int) -> bytes | None:
|
|
205
|
+
try:
|
|
206
|
+
descriptor = _open_below(name, folder, os.O_RDONLY)
|
|
207
|
+
except FileNotFoundError:
|
|
208
|
+
return None
|
|
209
|
+
with open(descriptor, "rb") as handle:
|
|
210
|
+
return handle.read()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _publish(data: bytes, name: str, folder: int, staging: int) -> os.stat_result:
|
|
214
|
+
"""Write and flush ``data`` in staging, then link it into ``folder`` as
|
|
215
|
+
``name``: the file appears complete or not at all. A link never replaces
|
|
216
|
+
a name, so ``FileExistsError`` means another writer published first. A
|
|
217
|
+
filesystem without hard links refuses; a rename would replace a name."""
|
|
218
|
+
|
|
219
|
+
staged = f"{uuid.uuid4().hex}.tmp"
|
|
220
|
+
descriptor = os.open(staged, os.O_WRONLY | os.O_CREAT | os.O_EXCL | _NO_FOLLOW, 0o644, dir_fd=staging)
|
|
221
|
+
try:
|
|
222
|
+
with open(descriptor, "wb") as handle:
|
|
223
|
+
handle.write(data)
|
|
224
|
+
handle.flush()
|
|
225
|
+
os.fsync(handle.fileno())
|
|
226
|
+
written = os.fstat(handle.fileno())
|
|
227
|
+
try:
|
|
228
|
+
os.link(staged, name, src_dir_fd=staging, dst_dir_fd=folder, follow_symlinks=False)
|
|
229
|
+
except OSError as error:
|
|
230
|
+
if error.errno in _NO_HARD_LINKS:
|
|
231
|
+
raise NoHardLinksError(
|
|
232
|
+
"this memory folder's filesystem cannot create files safely (no hard links); "
|
|
233
|
+
"nothing was written"
|
|
234
|
+
) from error
|
|
235
|
+
raise
|
|
236
|
+
try:
|
|
237
|
+
os.fsync(folder) # the new name survives a power loss
|
|
238
|
+
except OSError as error:
|
|
239
|
+
if error.errno not in (errno.EINVAL, errno.ENOTSUP):
|
|
240
|
+
raise
|
|
241
|
+
finally:
|
|
242
|
+
with contextlib.suppress(FileNotFoundError):
|
|
243
|
+
os.unlink(staged, dir_fd=staging)
|
|
244
|
+
return written
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
_ECHOED = ("artifact_type", "title", "created_by", "status", "workstream", "visibility", "relationships", "supersedes",
|
|
248
|
+
"provenance")
|
|
249
|
+
|
|
250
|
+
|
|
64
251
|
class CanonicalArtifactWriteback:
|
|
65
252
|
"""Authorize and persist canonical state, then update disposable projections."""
|
|
66
253
|
|
|
@@ -88,6 +275,21 @@ class CanonicalArtifactWriteback:
|
|
|
88
275
|
def _event_id(self) -> str:
|
|
89
276
|
return self.id_factory()
|
|
90
277
|
|
|
278
|
+
def _echo(self, receipt, root: Path | None = None):
|
|
279
|
+
"""A receipt as its writer reads it back: the names of documents held from them leave its title and
|
|
280
|
+
warnings (a sync or index message can name another file); when that fails, both are dropped."""
|
|
281
|
+
root = root if root is not None else getattr(self.store, "root", None)
|
|
282
|
+
if root is None:
|
|
283
|
+
return receipt
|
|
284
|
+
artifact = getattr(receipt, "artifact", None) # an existing document's metadata comes from memory
|
|
285
|
+
shown = {"warnings": receipt.warnings, **({name: getattr(artifact, name) for name in _ECHOED} if artifact else {})}
|
|
286
|
+
kept = package(receipt.permission_decision, shown, root=Path(root))
|
|
287
|
+
if kept == shown:
|
|
288
|
+
return receipt
|
|
289
|
+
kept = kept or {name: type(value)() for name, value in shown.items()}
|
|
290
|
+
warnings = kept.pop("warnings")
|
|
291
|
+
return replace(replace(receipt, artifact=replace(artifact, **kept)) if artifact else receipt, warnings=warnings)
|
|
292
|
+
|
|
91
293
|
def _emit(
|
|
92
294
|
self,
|
|
93
295
|
*,
|
|
@@ -151,6 +353,7 @@ class CanonicalArtifactWriteback:
|
|
|
151
353
|
warnings=(source_document.warnings if source_document else ()),
|
|
152
354
|
replaces_existing=(source_document.replaces_existing if source_document else False),
|
|
153
355
|
expected_revision=(source_document.expected_revision if source_document else None),
|
|
356
|
+
expected_sha256=(source_document.expected_sha256 if source_document else None),
|
|
154
357
|
)
|
|
155
358
|
|
|
156
359
|
def write(
|
|
@@ -159,22 +362,28 @@ class CanonicalArtifactWriteback:
|
|
|
159
362
|
artifact: CanonicalArtifact,
|
|
160
363
|
content: str,
|
|
161
364
|
) -> WritebackEvent:
|
|
162
|
-
return self._write(actor, artifact, content, policy_hints={}, source_document=None)
|
|
365
|
+
return self._echo(self._write(actor, artifact, content, policy_hints={}, source_document=None))
|
|
163
366
|
|
|
164
367
|
def write_document(
|
|
165
368
|
self,
|
|
166
369
|
actor: ActorContext,
|
|
167
370
|
document: CanonicalDocument,
|
|
371
|
+
*,
|
|
372
|
+
message: str | None = None,
|
|
168
373
|
) -> WritebackEvent:
|
|
169
|
-
"""Richer local API that preserves advisory envelope policy hints.
|
|
374
|
+
"""Richer local API that preserves advisory envelope policy hints.
|
|
170
375
|
|
|
171
|
-
|
|
376
|
+
``message`` replaces the commit's own ``docs(memory): capture <type>``
|
|
377
|
+
(an edit names its file and why); without it nothing changes."""
|
|
378
|
+
|
|
379
|
+
return self._echo(self._write(
|
|
172
380
|
actor,
|
|
173
381
|
document.artifact,
|
|
174
382
|
document.body,
|
|
175
383
|
policy_hints=dict(document.policy_hints),
|
|
176
384
|
source_document=document,
|
|
177
|
-
|
|
385
|
+
message=message,
|
|
386
|
+
))
|
|
178
387
|
|
|
179
388
|
def commit_files(
|
|
180
389
|
self,
|
|
@@ -183,12 +392,16 @@ class CanonicalArtifactWriteback:
|
|
|
183
392
|
*,
|
|
184
393
|
memory_root: Path,
|
|
185
394
|
message: str,
|
|
395
|
+
refresh_retrieval: bool = True,
|
|
186
396
|
) -> CanonicalFilesWritebackEvent:
|
|
187
397
|
"""Version rendered auxiliary canonical files through the normal transport.
|
|
188
398
|
|
|
189
399
|
YAML registries and compatibility ledgers have no artifact envelope to
|
|
190
400
|
normalize or project. Their authorized Git provenance, retrieval refresh,
|
|
191
401
|
and telemetry still belong to the same Runtime writeback boundary.
|
|
402
|
+
``refresh_retrieval=False`` is for files search never reads: retrieval
|
|
403
|
+
indexes Markdown, so there is nothing to refresh, and its next update
|
|
404
|
+
records the new revision without rescanning an unchanged corpus.
|
|
192
405
|
"""
|
|
193
406
|
|
|
194
407
|
if not paths or not message.strip():
|
|
@@ -207,8 +420,8 @@ class CanonicalArtifactWriteback:
|
|
|
207
420
|
)
|
|
208
421
|
event_id = self._event_id()
|
|
209
422
|
decision = self.authorizer.authorize_action(actor, Permission.WRITE, canonical_paths)
|
|
210
|
-
if decision.allowed and
|
|
211
|
-
not
|
|
423
|
+
if decision.allowed and any(
|
|
424
|
+
not allows(decision, f"memory/{path}", "write", root=memory)
|
|
212
425
|
for path in canonical_paths
|
|
213
426
|
):
|
|
214
427
|
decision = replace(
|
|
@@ -232,9 +445,9 @@ class CanonicalArtifactWriteback:
|
|
|
232
445
|
except Exception as exc:
|
|
233
446
|
warnings.append(f"sync: {exc}")
|
|
234
447
|
|
|
235
|
-
if git_revision is None:
|
|
448
|
+
if refresh_retrieval and git_revision is None:
|
|
236
449
|
warnings.append("retrieval: skipped because canonical Git provenance failed")
|
|
237
|
-
|
|
450
|
+
elif refresh_retrieval:
|
|
238
451
|
try:
|
|
239
452
|
health = self.retriever.update(tuple(str(source) for source in sources))
|
|
240
453
|
index_revision = health.index_revision
|
|
@@ -270,7 +483,7 @@ class CanonicalArtifactWriteback:
|
|
|
270
483
|
if status is WritebackStatus.ACCEPTED:
|
|
271
484
|
status = WritebackStatus.PARTIAL
|
|
272
485
|
|
|
273
|
-
return CanonicalFilesWritebackEvent(
|
|
486
|
+
return self._echo(CanonicalFilesWritebackEvent(
|
|
274
487
|
event_id=event_id,
|
|
275
488
|
canonical_path=canonical_paths[0],
|
|
276
489
|
canonical_paths=canonical_paths,
|
|
@@ -280,6 +493,104 @@ class CanonicalArtifactWriteback:
|
|
|
280
493
|
index_revision=index_revision,
|
|
281
494
|
embedding_state=embedding_state,
|
|
282
495
|
warnings=tuple(warnings),
|
|
496
|
+
), memory)
|
|
497
|
+
|
|
498
|
+
def create_file(
|
|
499
|
+
self,
|
|
500
|
+
actor: ActorContext,
|
|
501
|
+
raw_path: str,
|
|
502
|
+
content: str,
|
|
503
|
+
*,
|
|
504
|
+
memory_root: Path,
|
|
505
|
+
message: str,
|
|
506
|
+
) -> CanonicalFilesWritebackEvent:
|
|
507
|
+
"""Create one immutable canonical file, then version it.
|
|
508
|
+
|
|
509
|
+
The append-only lifecycle for records search never reads, such as one
|
|
510
|
+
JSON file per event. The content is written and flushed in a staging
|
|
511
|
+
folder Git ignores, on the same filesystem, then linked into place,
|
|
512
|
+
so the file appears complete or not at all: an autosave, a rebase or
|
|
513
|
+
a crash never sees it partly written. A platform or filesystem that
|
|
514
|
+
cannot do this is refused with nothing written, never served by a
|
|
515
|
+
replacing rename. A link never replaces a name, so a rebase cannot
|
|
516
|
+
overwrite it and two clones never write the same path. A path already
|
|
517
|
+
holding exactly this content (a retry, or a file an autosave committed
|
|
518
|
+
first) is only versioned again; different content is an
|
|
519
|
+
``ArtifactConflictError``. Authorization comes before any write. No
|
|
520
|
+
step below memory/ may be a symbolic link: the path is checked before
|
|
521
|
+
authorization, the folders are then walked through descriptors that
|
|
522
|
+
follow no link, and the path is checked again before Git receives it.
|
|
523
|
+
Retrieval indexes Markdown only, so no index refresh is asked for.
|
|
524
|
+
"""
|
|
525
|
+
|
|
526
|
+
if not message.strip():
|
|
527
|
+
raise ValueError("canonical file creation requires a non-empty message")
|
|
528
|
+
require_descriptor_calls()
|
|
529
|
+
memory = memory_root.resolve()
|
|
530
|
+
target, relative = canonical_new_file_path(memory, raw_path)
|
|
531
|
+
event_id = self._event_id()
|
|
532
|
+
decision = self.authorizer.authorize_action(actor, Permission.WRITE, (relative,))
|
|
533
|
+
# Revalidate after authorization: it may have swapped a parent for a symlink.
|
|
534
|
+
canonical_new_file_path(memory, relative)
|
|
535
|
+
if decision.allowed and not allows(decision, f"memory/{relative}", "write", root=memory):
|
|
536
|
+
decision = replace(
|
|
537
|
+
decision,
|
|
538
|
+
allowed=False,
|
|
539
|
+
reasons=(*decision.reasons, "canonical write path is outside the actor's authorized scope"),
|
|
540
|
+
)
|
|
541
|
+
if not decision.allowed:
|
|
542
|
+
warnings = tuple(decision.reasons)
|
|
543
|
+
try:
|
|
544
|
+
self._emit(
|
|
545
|
+
actor=actor, event_id=event_id, artifact_id="",
|
|
546
|
+
status=WritebackStatus.REJECTED, warning_count=len(warnings),
|
|
547
|
+
)
|
|
548
|
+
except Exception:
|
|
549
|
+
warnings += ("telemetry: failed to record denied writeback",)
|
|
550
|
+
return CanonicalFilesWritebackEvent(
|
|
551
|
+
event_id=event_id,
|
|
552
|
+
canonical_path=relative,
|
|
553
|
+
canonical_paths=(relative,),
|
|
554
|
+
permission_decision=decision,
|
|
555
|
+
status=WritebackStatus.REJECTED,
|
|
556
|
+
warnings=warnings,
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
data = content.encode("utf-8")
|
|
560
|
+
*names, name = PurePosixPath(relative).parts
|
|
561
|
+
folder = _open_folders(memory, names)
|
|
562
|
+
written = None
|
|
563
|
+
try:
|
|
564
|
+
existing = _read_below(name, folder)
|
|
565
|
+
if existing is None:
|
|
566
|
+
staging = _open_staging(memory, names[:1])
|
|
567
|
+
try:
|
|
568
|
+
written = _publish(data, name, folder, staging)
|
|
569
|
+
except FileExistsError:
|
|
570
|
+
existing = _read_below(name, folder)
|
|
571
|
+
finally:
|
|
572
|
+
os.close(staging)
|
|
573
|
+
if existing is not None and existing != data:
|
|
574
|
+
raise ArtifactConflictError(
|
|
575
|
+
f"{relative} already holds different content; an immutable file is never replaced"
|
|
576
|
+
)
|
|
577
|
+
try:
|
|
578
|
+
# Git receives the path, so the path must still name these
|
|
579
|
+
# bytes through no link; else what was just published goes.
|
|
580
|
+
canonical_new_file_path(memory, relative)
|
|
581
|
+
with open(os.open(target, os.O_RDONLY | _NO_FOLLOW), "rb") as handle:
|
|
582
|
+
if handle.read() != data:
|
|
583
|
+
raise ArtifactConflictError(f"{relative} changed while it was written")
|
|
584
|
+
except BaseException:
|
|
585
|
+
with contextlib.suppress(OSError):
|
|
586
|
+
found = os.stat(name, dir_fd=folder, follow_symlinks=False)
|
|
587
|
+
if written is not None and (found.st_dev, found.st_ino) == (written.st_dev, written.st_ino):
|
|
588
|
+
os.unlink(name, dir_fd=folder)
|
|
589
|
+
raise
|
|
590
|
+
finally:
|
|
591
|
+
os.close(folder)
|
|
592
|
+
return self.commit_files(
|
|
593
|
+
actor, (str(target),), memory_root=memory, message=message, refresh_retrieval=False,
|
|
283
594
|
)
|
|
284
595
|
|
|
285
596
|
def write_documents(
|
|
@@ -320,16 +631,10 @@ class CanonicalArtifactWriteback:
|
|
|
320
631
|
)
|
|
321
632
|
for document in documents
|
|
322
633
|
)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if not scope_allows_path(
|
|
328
|
-
f"memory/{document.artifact.canonical_path}", decision.scopes
|
|
329
|
-
)
|
|
330
|
-
)
|
|
331
|
-
if outside:
|
|
332
|
-
raise PermissionError("canonical write path is outside the actor's authorized scope")
|
|
634
|
+
outside = tuple(document.artifact.canonical_path for document in prepared
|
|
635
|
+
if not allows(decision, f"memory/{document.artifact.canonical_path}", "write", root=self.store.root))
|
|
636
|
+
if outside:
|
|
637
|
+
raise PermissionError("canonical write path is outside the actor's authorized scope")
|
|
333
638
|
|
|
334
639
|
# Catch deterministic conflicts before any item changes. persist() checks
|
|
335
640
|
# again so concurrent changes cannot bypass the store's normal rules.
|
|
@@ -430,7 +735,7 @@ class CanonicalArtifactWriteback:
|
|
|
430
735
|
receipt.status is WritebackStatus.ACCEPTED for receipt in receipts
|
|
431
736
|
):
|
|
432
737
|
receipts = tuple(replace(receipt, status=status, warnings=tuple(warnings)) for receipt in receipts)
|
|
433
|
-
return receipts + rejected
|
|
738
|
+
return tuple(self._echo(receipt) for receipt in receipts + rejected)
|
|
434
739
|
|
|
435
740
|
def _write(
|
|
436
741
|
self,
|
|
@@ -440,6 +745,7 @@ class CanonicalArtifactWriteback:
|
|
|
440
745
|
*,
|
|
441
746
|
policy_hints: dict[str, object],
|
|
442
747
|
source_document: CanonicalDocument | None,
|
|
748
|
+
message: str | None = None,
|
|
443
749
|
) -> WritebackEvent:
|
|
444
750
|
event_id = self._event_id()
|
|
445
751
|
resource = artifact.artifact_id or artifact.canonical_path
|
|
@@ -465,7 +771,7 @@ class CanonicalArtifactWriteback:
|
|
|
465
771
|
)
|
|
466
772
|
|
|
467
773
|
path = canonical_relative_path(artifact.canonical_path)
|
|
468
|
-
if
|
|
774
|
+
if not allows(decision, f"memory/{path}", "write", root=self.store.root):
|
|
469
775
|
raise PermissionError("canonical write path is outside the actor's authorized scope")
|
|
470
776
|
|
|
471
777
|
document = self._prepare(
|
|
@@ -485,7 +791,7 @@ class CanonicalArtifactWriteback:
|
|
|
485
791
|
|
|
486
792
|
try:
|
|
487
793
|
sync = self.sync_transport.push(
|
|
488
|
-
message=f"docs(memory): capture {artifact.artifact_type}",
|
|
794
|
+
message=message or f"docs(memory): capture {artifact.artifact_type}",
|
|
489
795
|
paths=(str(persisted_path),),
|
|
490
796
|
)
|
|
491
797
|
git_revision = sync.local_revision
|