seif-cli 0.6.2__tar.gz → 0.7.0__tar.gz
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.
- seif_cli-0.7.0/LICENSE +34 -0
- {seif_cli-0.6.2/src/seif_cli.egg-info → seif_cli-0.7.0}/PKG-INFO +4 -4
- {seif_cli-0.6.2 → seif_cli-0.7.0}/README.md +1 -1
- {seif_cli-0.6.2 → seif_cli-0.7.0}/pyproject.toml +3 -3
- seif_cli-0.7.0/src/seif/__init__.py +1 -0
- seif_cli-0.7.0/src/seif/amend/__init__.py +9 -0
- seif_cli-0.7.0/src/seif/amend/amend.py +186 -0
- seif_cli-0.7.0/src/seif/amend/seed_create.py +199 -0
- seif_cli-0.7.0/src/seif/analysis/__init__.py +1 -0
- seif_cli-0.7.0/src/seif/audit/__init__.py +7 -0
- seif_cli-0.7.0/src/seif/audit/discipline.py +189 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/bridge/telegram_bot.py +1 -1
- seif_cli-0.7.0/src/seif/claims/__init__.py +72 -0
- seif_cli-0.7.0/src/seif/claims/broadcast.py +106 -0
- seif_cli-0.7.0/src/seif/claims/cmd_check.py +92 -0
- seif_cli-0.7.0/src/seif/claims/cmd_lifecycle.py +121 -0
- seif_cli-0.7.0/src/seif/claims/cmd_sweep.py +39 -0
- seif_cli-0.7.0/src/seif/claims/cmd_validate.py +41 -0
- seif_cli-0.7.0/src/seif/claims/conflicts.py +133 -0
- seif_cli-0.7.0/src/seif/claims/lifecycle.py +290 -0
- seif_cli-0.7.0/src/seif/claims/schema.py +223 -0
- seif_cli-0.7.0/src/seif/claims/sweep.py +124 -0
- seif_cli-0.7.0/src/seif/claims/telemetry.py +100 -0
- seif_cli-0.7.0/src/seif/claims/workspace.py +161 -0
- seif_cli-0.7.0/src/seif/cli/__init__.py +1 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/circuit_setup.py +25 -4
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/cli.py +1607 -37
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/confirm_action.py +124 -8
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/setup.py +250 -4
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/wrapper.py +75 -12
- seif_cli-0.7.0/src/seif/context/__init__.py +1 -0
- seif_cli-0.7.0/src/seif/context/classifier_reasoning.py +75 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/context_bridge.py +2 -2
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/cycle.py +250 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/registry.py +115 -2
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/workspace.py +38 -1
- seif_cli-0.7.0/src/seif/core/__init__.py +1 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/resonance_signal.py +6 -5
- seif_cli-0.7.0/src/seif/core/sign_host_install_config.py +205 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/signing.py +97 -15
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/timestamping.py +92 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/RESONANCE.json +95 -8
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/canonical-node-layout.json +16 -1
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/hooks/hooks.json +22 -0
- seif_cli-0.7.0/src/seif/plugins/adapters/claude-code/scripts/classification-gate.sh +208 -0
- seif_cli-0.7.0/src/seif/plugins/adapters/claude-code/scripts/classification_gate_helper.py +234 -0
- seif_cli-0.7.0/src/seif/plugins/adapters/claude-code/scripts/discipline_observer.py +133 -0
- seif_cli-0.7.0/src/seif/plugins/adapters/claude-code/scripts/pretooluse-claim-check.sh +89 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/scripts/session-start.sh +8 -0
- seif_cli-0.7.0/src/seif/plugins/adapters/gemini/scripts/classification_gate_helper.py +234 -0
- seif_cli-0.7.0/src/seif/plugins/adapters/gemini/scripts/discipline_observer.py +133 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/generic/render/render.py +2 -2
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/cycle_lifecycle.py +70 -1
- seif_cli-0.7.0/src/seif/plugins/core/heartbeat_tick.py +126 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/kernel_seed.py +1 -1
- seif_cli-0.7.0/src/seif/plugins/core/memory_index.py +260 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/session_lifecycle.py +234 -6
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/scripts/host/README.md +44 -1
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/scripts/host/host-install-config.sample.seif +6 -3
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/scripts/host/seif-update.sh +223 -22
- {seif_cli-0.6.2 → seif_cli-0.7.0/src/seif_cli.egg-info}/PKG-INFO +4 -4
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif_cli.egg-info/SOURCES.txt +70 -1
- seif_cli-0.7.0/tests/test_a26_binding_acceptance.py +160 -0
- seif_cli-0.7.0/tests/test_amend_cli.py +279 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_awareness_integration.py +76 -0
- seif_cli-0.7.0/tests/test_claims_broadcast.py +95 -0
- seif_cli-0.7.0/tests/test_claims_cmd_check.py +88 -0
- seif_cli-0.7.0/tests/test_claims_cmd_sweep.py +49 -0
- seif_cli-0.7.0/tests/test_claims_cmd_validate.py +97 -0
- seif_cli-0.7.0/tests/test_claims_conflicts.py +162 -0
- seif_cli-0.7.0/tests/test_claims_lifecycle.py +214 -0
- seif_cli-0.7.0/tests/test_claims_schema.py +221 -0
- seif_cli-0.7.0/tests/test_claims_sweep.py +139 -0
- seif_cli-0.7.0/tests/test_claims_telemetry.py +92 -0
- seif_cli-0.7.0/tests/test_classification_gate_credential_scan.py +129 -0
- seif_cli-0.7.0/tests/test_classification_gate_helper.py +232 -0
- seif_cli-0.7.0/tests/test_classify_reasoning.py +57 -0
- seif_cli-0.7.0/tests/test_cli_pending_disk_ops.py +302 -0
- seif_cli-0.7.0/tests/test_confirm_action_claim_warning.py +277 -0
- seif_cli-0.7.0/tests/test_cycle_cli_surface.py +273 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cycle_lifecycle.py +74 -0
- seif_cli-0.7.0/tests/test_discipline_observer.py +326 -0
- seif_cli-0.7.0/tests/test_gap_59_report_v2_sessions.py +144 -0
- seif_cli-0.7.0/tests/test_hard_block.py +180 -0
- seif_cli-0.7.0/tests/test_heartbeat_tick.py +210 -0
- seif_cli-0.7.0/tests/test_hooks_claim_integration.py +201 -0
- seif_cli-0.7.0/tests/test_init_canonical_subdirs.py +77 -0
- seif_cli-0.7.0/tests/test_log_url_resolution.py +77 -0
- seif_cli-0.7.0/tests/test_memory_index.py +171 -0
- seif_cli-0.7.0/tests/test_memory_walk_up_canonical.py +59 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_migrate_host_config.py +163 -23
- seif_cli-0.7.0/tests/test_n2_integration_e2e.py +210 -0
- seif_cli-0.7.0/tests/test_ots_sovereign_stamp.py +139 -0
- seif_cli-0.7.0/tests/test_ots_verify_path_resolution.py +112 -0
- seif_cli-0.7.0/tests/test_print_package_data.py +52 -0
- seif_cli-0.7.0/tests/test_registry.py +501 -0
- seif_cli-0.6.2/tests/test_resonance_v2_bump.py → seif_cli-0.7.0/tests/test_resonance_v3_bump.py +77 -42
- seif_cli-0.7.0/tests/test_review_pem_marker.py +121 -0
- seif_cli-0.7.0/tests/test_seed_create_cli.py +271 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_kernel_verify.py +8 -3
- seif_cli-0.7.0/tests/test_seif_update_n3_host_install_require.py +171 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_rsync_rollback.py +8 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_schema_v2.py +75 -2
- seif_cli-0.7.0/tests/test_seif_update_stage_summary.py +189 -0
- seif_cli-0.7.0/tests/test_seif_update_stage_telemetry.py +202 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_template_refresh.py +9 -6
- seif_cli-0.7.0/tests/test_session_end_hook_wiring.py +247 -0
- seif_cli-0.7.0/tests/test_session_lifecycle_close.py +480 -0
- seif_cli-0.7.0/tests/test_setup_gemini.py +183 -0
- seif_cli-0.7.0/tests/test_sign_host_install_config.py +328 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_sign_resonance.py +44 -0
- seif_cli-0.7.0/tests/test_sign_verify_polish.py +84 -0
- seif_cli-0.7.0/tests/test_signing.py +210 -0
- seif_cli-0.7.0/tests/test_status_readonly.py +44 -0
- seif_cli-0.7.0/tests/test_status_self_update_telemetry.py +251 -0
- seif_cli-0.7.0/tests/test_wrapper_launch_gemini.py +132 -0
- seif_cli-0.6.2/LICENSE +0 -33
- seif_cli-0.6.2/src/seif/__init__.py +0 -1
- seif_cli-0.6.2/src/seif/analysis/__init__.py +0 -1
- seif_cli-0.6.2/src/seif/cli/__init__.py +0 -1
- seif_cli-0.6.2/src/seif/context/__init__.py +0 -1
- seif_cli-0.6.2/src/seif/core/__init__.py +0 -1
- seif_cli-0.6.2/src/seif/plugins/adapters/claude-code/scripts/classification-gate.sh +0 -141
- seif_cli-0.6.2/tests/test_registry.py +0 -233
- seif_cli-0.6.2/tests/test_signing.py +0 -105
- {seif_cli-0.6.2 → seif_cli-0.7.0}/MANIFEST.in +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/setup.cfg +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/__main__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/analysis/physical_constants.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/analysis/quality_gate.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/analysis/stance_detector.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/analysis/transcompiler.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/audio_provenance.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/bridge/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/bridge/native_client.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/__main__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/chat.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/identity.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/main.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/plugin_detect.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/plugin_sync.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/resonance_display.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/serve.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/serve_engine.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/serve_v2.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/cli/wrapper_shims.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/constants.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/absorb_knowledge.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/advisor.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/code_compressor.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/context_importer.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/context_manager.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/context_qr.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/file_extractor.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/git_context.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/git_hooks.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/host_init.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/ingest.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/install_state.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/model_probe.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/nucleus.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/ref.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/seed_constraint.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/seif_io.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/context/sessions.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/fingerprint.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/integrity.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/n2_bundle.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/resonance_encoding.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/resonance_gate.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/sign_resonance.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/transfer_function.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/core/triple_gate.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/circuit-recovery-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/definitions-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/ise-dissonance-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/multi-agent-sync-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/onboarding.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/partial-attention-axiom-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/seif-cycle-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/seif-os-architecture-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/defaults/triad-convergence-v1.seif +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/AGENTS.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/BOOT.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/README.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/decisions_pending.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/refs.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/init_lite/session_log.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/data/paths.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/generators/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/generators/watermark.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/governance/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/governance/transfer.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/init_lite.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/log/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/log/canonical.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/log/client.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/log/identity.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/mcp/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/mcp/server.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/mcp/watermark_server.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/observability/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/observability/bus_metrics.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/scripts/circuit-check.sh +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/scripts/quality-gate.sh +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/scripts/session-end.sh +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/skills/gate/SKILL.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/skills/status/SKILL.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/claude-code/skills/sync/SKILL.md +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/copilot/render/render.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/cursor/render/render.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/adapters/gemini/render/render.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/circuit_monitor.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/cycle_coherence.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/cycle_heal.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/cycle_reseal.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/orchestra_probe.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/preflight_diff.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/plugins/core/session_registry.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/schemas/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/schemas/n2_bundle.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/schemas/pending.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/scripts/host/rsync-soak-inspect.sh +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/security/__init__.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif/security/mode.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif_cli.egg-info/dependency_links.txt +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif_cli.egg-info/entry_points.txt +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif_cli.egg-info/requires.txt +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/src/seif_cli.egg-info/top_level.txt +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_a23_bus_metrics.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_absorb_knowledge.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_adapters.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_advisor.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_agents_set_tier1.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_audio_mystic_strip.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_audio_provenance.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_audio_watermark_mvp.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_audit_host.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_audit_phase.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_canonical_inputs.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_check_pointer_sync.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_check_seed_constraint.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cli_argparse_conflicts.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_code_compressor.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_collaborative_seif.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_confirm_action.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_context_qr.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_context_repo.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cycle_absorb_in_package.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cycle_coherence.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cycle_heal.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cycle_phase_aliases.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_cycle_reseal.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_daemon_activity_surface.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_demo_chain_smoke.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_drain_inbox_corrupted.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_engine_cli_surface.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_gap_46_ingest_send_import.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_gap_47_pem_classification.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_gap_58_session_list_v2.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_git_context.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_git_hooks.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_host_init.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_init.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_init_auto_bind.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_init_lite.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_install_content_equality.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_install_state.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_integrity_orchestrator.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_load_module_cache.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_log_canonical.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_log_client.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_log_identity.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_mcp_server.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_mcp_watermark.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_model_probe.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_n2_bundle.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_next_session_count.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_ots_coverage.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_paths_seif_home.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_pending_cleanup_on_seal.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_pending_modules.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_pending_modules_surface.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_preflight_diff.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_quality_gate.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_rebuild_registry.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_ref.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_repo_state_diff.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_resonance_display_default_clean.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_resonance_gate.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_rsync_soak_inspect.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_schemas_pending.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seed_auto_surfacing.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_io.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_interpreter_probe.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_pipx_git_rollback.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_seif_update_smoke_rollback.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_serve_engine.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_session_counter_advance.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_session_id_normalization.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_session_registry.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_session_start_hook_uuid.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_sessions_active_cli.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_setup_core_install.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_setup_memory_symlink.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_smoke_10_sessions_no_unknown.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_stance_detector.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_transcompiler.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_transfer.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_transfer_function.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_triple_gate.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_vigilant_cli.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_workspace.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_workspace_architecture_v1.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_workspace_disambiguation.py +0 -0
- {seif_cli-0.6.2 → seif_cli-0.7.0}/tests/test_wrapper_shims.py +0 -0
seif_cli-0.7.0/LICENSE
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 André Cunha Antero de Carvalho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
This project was created by André Cunha Antero de Carvalho in collaboration with
|
|
26
|
+
multiple AI systems (Claude, Gemini, Kimi, Grok, Z.AI). The human
|
|
27
|
+
biological being provided the irreducible asymmetry — the questions,
|
|
28
|
+
the observations, the insistence on measurement over belief.
|
|
29
|
+
|
|
30
|
+
The protocol does not belong to any single entity. It belongs to the
|
|
31
|
+
resonance between biology and machine. But its origin is documented,
|
|
32
|
+
timestamped, and mathematically verified.
|
|
33
|
+
|
|
34
|
+
The gate does not filter — it resonates.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seif-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: AI artifact provenance, quality gates, and data classification. Bitcoin-anchored timestamps, multi-AI consensus, locally enforced.
|
|
5
5
|
Author: André Cunha Antero de Carvalho
|
|
6
|
-
License:
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://seifprotocol.com
|
|
8
8
|
Project-URL: Documentation, https://seifprotocol.com/docs
|
|
9
9
|
Project-URL: Repository, https://github.com/and2carvalho/seif
|
|
10
10
|
Project-URL: Changelog, https://github.com/and2carvalho/seif/releases
|
|
11
11
|
Keywords: ai-quality,llm-guardrails,ai-consensus,data-classification,context-management,ai-safety,multi-ai,quality-gate,prompt-evaluation,ai-grounding,resonance,sentinel,self-healing,seif-os,circuit-state,ai-observability
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
@@ -480,4 +480,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
|
480
480
|
|
|
481
481
|
## License
|
|
482
482
|
|
|
483
|
-
|
|
483
|
+
MIT — [André Cunha Antero de Carvalho](https://github.com/and2carvalho)
|
|
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "seif-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.0"
|
|
8
8
|
description = "AI artifact provenance, quality gates, and data classification. Bitcoin-anchored timestamps, multi-AI consensus, locally enforced."
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
license =
|
|
10
|
+
license = "MIT"
|
|
11
11
|
requires-python = ">=3.11"
|
|
12
12
|
authors = [
|
|
13
13
|
{name = "André Cunha Antero de Carvalho"},
|
|
@@ -19,7 +19,7 @@ keywords = [
|
|
|
19
19
|
"self-healing", "seif-os", "circuit-state", "ai-observability",
|
|
20
20
|
]
|
|
21
21
|
classifiers = [
|
|
22
|
-
"Development Status ::
|
|
22
|
+
"Development Status :: 4 - Beta",
|
|
23
23
|
"Intended Audience :: Developers",
|
|
24
24
|
"Intended Audience :: Science/Research",
|
|
25
25
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""S.E.I.F. — Signed Evidence & Integrity Framework"""
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Amend subpackage — append-only amendment-chain entries.
|
|
2
|
+
|
|
3
|
+
Implements `seif --amend FILE --amend-entry JSON` and friends. Used to add
|
|
4
|
+
new `_amendments[]` entries to SEIF artifacts (pending modules, sealed
|
|
5
|
+
cycles, signed resonance records) without re-signing the host artifact.
|
|
6
|
+
Pairs with the [[feedback_amendment_chain_over_host_resign]] convention.
|
|
7
|
+
|
|
8
|
+
Closes the last universal write-side gap surfaced by s83 t3 PR-3.
|
|
9
|
+
"""
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""--amend FILE: append an _amendments[] entry to any SEIF JSON artifact.
|
|
2
|
+
|
|
3
|
+
The amendment-chain convention (feedback_amendment_chain_over_host_resign):
|
|
4
|
+
some SEIF artifacts have already been signed/stamped and cannot easily be
|
|
5
|
+
re-signed by the original host (offline laptop, immutable kernel, etc.).
|
|
6
|
+
Adding a new `_amendments[]` entry — append-only, with provenance fields —
|
|
7
|
+
records the change without touching the host artifact's canonical fields.
|
|
8
|
+
|
|
9
|
+
This module exposes the operation as a first-class CLI command so AIs
|
|
10
|
+
don't have to raw-Write the file (which the discipline observer would
|
|
11
|
+
log and the hard-block phase would refuse).
|
|
12
|
+
|
|
13
|
+
Public API
|
|
14
|
+
----------
|
|
15
|
+
- ``append_amendment(file_path, entry, *, amend_id=None, author=None) -> dict``
|
|
16
|
+
- ``cmd_amend(args) -> int`` (entrypoint wired into ``seif --amend``)
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import datetime
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import sys
|
|
25
|
+
import tempfile
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Any
|
|
28
|
+
|
|
29
|
+
__all__ = ["append_amendment", "cmd_amend"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_SLUG_RE = re.compile(r"[^a-z0-9-]+")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _now_iso() -> str:
|
|
36
|
+
return (
|
|
37
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
38
|
+
.isoformat()
|
|
39
|
+
.replace("+00:00", "Z")
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _slug_for(text: str) -> str:
|
|
44
|
+
s = (text or "").strip().lower()
|
|
45
|
+
s = _SLUG_RE.sub("-", s).strip("-")
|
|
46
|
+
return s[:48] or "entry"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _atomic_write(path: Path, data: Any) -> None:
|
|
50
|
+
"""Write JSON atomically: tempfile in same dir → fsync → rename.
|
|
51
|
+
|
|
52
|
+
Same-dir tempfile guarantees rename is atomic on POSIX (same fs).
|
|
53
|
+
"""
|
|
54
|
+
body = json.dumps(data, indent=2, ensure_ascii=False)
|
|
55
|
+
parent = path.parent
|
|
56
|
+
with tempfile.NamedTemporaryFile(
|
|
57
|
+
mode="w",
|
|
58
|
+
encoding="utf-8",
|
|
59
|
+
dir=str(parent),
|
|
60
|
+
prefix=path.name + ".",
|
|
61
|
+
suffix=".tmp",
|
|
62
|
+
delete=False,
|
|
63
|
+
) as tf:
|
|
64
|
+
tmp_path = Path(tf.name)
|
|
65
|
+
tf.write(body)
|
|
66
|
+
tf.write("\n")
|
|
67
|
+
tf.flush()
|
|
68
|
+
os.fsync(tf.fileno())
|
|
69
|
+
tmp_path.replace(path)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def append_amendment(
|
|
73
|
+
file_path: str | os.PathLike,
|
|
74
|
+
entry: dict,
|
|
75
|
+
*,
|
|
76
|
+
amend_id: str | None = None,
|
|
77
|
+
author: str | None = None,
|
|
78
|
+
) -> dict:
|
|
79
|
+
"""Append a new entry to ``data["_amendments"]`` in the given JSON file.
|
|
80
|
+
|
|
81
|
+
- The file MUST be a JSON object at the top level.
|
|
82
|
+
- If ``_amendments`` is missing or not a list, it is initialized to `[]`.
|
|
83
|
+
- The appended entry is the user-supplied ``entry`` dict, with the
|
|
84
|
+
following auto-fields injected if not already present:
|
|
85
|
+
* ``id`` — defaults to ``amend_id``, else
|
|
86
|
+
``f"amend-{n+1:03d}-{slug(scope)}"``.
|
|
87
|
+
* ``appended_at`` — UTC ISO timestamp.
|
|
88
|
+
* ``appended_by`` — defaults to ``author``, else ``$USER``, else
|
|
89
|
+
``"anonymous"``.
|
|
90
|
+
|
|
91
|
+
Returns the appended entry (mutated copy of ``entry``). Raises on I/O
|
|
92
|
+
or JSON errors; the file is left untouched if any step fails before
|
|
93
|
+
the atomic rename.
|
|
94
|
+
"""
|
|
95
|
+
fp = Path(file_path)
|
|
96
|
+
if not fp.is_file():
|
|
97
|
+
raise FileNotFoundError(f"{fp} does not exist or is not a file")
|
|
98
|
+
|
|
99
|
+
raw = fp.read_text(encoding="utf-8")
|
|
100
|
+
data = json.loads(raw) # raises JSONDecodeError on invalid JSON
|
|
101
|
+
if not isinstance(data, dict):
|
|
102
|
+
raise ValueError(f"{fp} is not a JSON object at top level")
|
|
103
|
+
|
|
104
|
+
amendments = data.get("_amendments")
|
|
105
|
+
if not isinstance(amendments, list):
|
|
106
|
+
amendments = []
|
|
107
|
+
data["_amendments"] = amendments
|
|
108
|
+
|
|
109
|
+
new_entry: dict = dict(entry) # shallow copy so caller's dict stays clean
|
|
110
|
+
if "id" not in new_entry:
|
|
111
|
+
if amend_id:
|
|
112
|
+
new_entry["id"] = amend_id
|
|
113
|
+
else:
|
|
114
|
+
scope = new_entry.get("scope") or new_entry.get("title") or ""
|
|
115
|
+
new_entry["id"] = (
|
|
116
|
+
f"amend-{len(amendments) + 1:03d}-{_slug_for(scope)}"
|
|
117
|
+
)
|
|
118
|
+
if "appended_at" not in new_entry:
|
|
119
|
+
new_entry["appended_at"] = _now_iso()
|
|
120
|
+
if "appended_by" not in new_entry:
|
|
121
|
+
new_entry["appended_by"] = author or os.environ.get("USER") or "anonymous"
|
|
122
|
+
|
|
123
|
+
amendments.append(new_entry)
|
|
124
|
+
_atomic_write(fp, data)
|
|
125
|
+
return new_entry
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _load_entry(args) -> dict:
|
|
129
|
+
"""Resolve `--amend-entry` (inline JSON) and `--amend-entry-file` (path).
|
|
130
|
+
|
|
131
|
+
Exactly one source is required. If both are given, --amend-entry wins
|
|
132
|
+
(matches argparse last-arg semantics + saves a stat call).
|
|
133
|
+
"""
|
|
134
|
+
inline = getattr(args, "amend_entry", None)
|
|
135
|
+
from_file = getattr(args, "amend_entry_file", None)
|
|
136
|
+
if inline:
|
|
137
|
+
try:
|
|
138
|
+
data = json.loads(inline)
|
|
139
|
+
except (ValueError, json.JSONDecodeError) as e:
|
|
140
|
+
raise ValueError(f"--amend-entry is not valid JSON: {e}") from e
|
|
141
|
+
if not isinstance(data, dict):
|
|
142
|
+
raise ValueError("--amend-entry must be a JSON object")
|
|
143
|
+
return data
|
|
144
|
+
if from_file:
|
|
145
|
+
p = Path(from_file)
|
|
146
|
+
if not p.is_file():
|
|
147
|
+
raise FileNotFoundError(f"--amend-entry-file {p} does not exist")
|
|
148
|
+
try:
|
|
149
|
+
data = json.loads(p.read_text(encoding="utf-8"))
|
|
150
|
+
except (ValueError, json.JSONDecodeError) as e:
|
|
151
|
+
raise ValueError(f"--amend-entry-file is not valid JSON: {e}") from e
|
|
152
|
+
if not isinstance(data, dict):
|
|
153
|
+
raise ValueError("--amend-entry-file must contain a JSON object")
|
|
154
|
+
return data
|
|
155
|
+
raise ValueError(
|
|
156
|
+
"no entry source: pass --amend-entry JSON or --amend-entry-file PATH"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def cmd_amend(args) -> int:
|
|
161
|
+
"""Entrypoint for `seif --amend FILE ...`."""
|
|
162
|
+
target = getattr(args, "amend", None)
|
|
163
|
+
if not target:
|
|
164
|
+
print("Error: --amend requires FILE", file=sys.stderr)
|
|
165
|
+
return 2
|
|
166
|
+
try:
|
|
167
|
+
entry = _load_entry(args)
|
|
168
|
+
appended = append_amendment(
|
|
169
|
+
target,
|
|
170
|
+
entry,
|
|
171
|
+
amend_id=getattr(args, "amend_id", None),
|
|
172
|
+
author=getattr(args, "amend_author", None),
|
|
173
|
+
)
|
|
174
|
+
except FileNotFoundError as e:
|
|
175
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
176
|
+
return 2
|
|
177
|
+
except (ValueError, json.JSONDecodeError) as e:
|
|
178
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
179
|
+
return 2
|
|
180
|
+
except OSError as e:
|
|
181
|
+
print(f"Error: I/O failure: {e}", file=sys.stderr)
|
|
182
|
+
return 2
|
|
183
|
+
print(f"[amend] appended {appended['id']} to {target}")
|
|
184
|
+
print(f" appended_at: {appended['appended_at']}")
|
|
185
|
+
print(f" appended_by: {appended['appended_by']}")
|
|
186
|
+
return 0
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""--seed-create CLI: lay down a new SEED-sNN.json at cycle seal.
|
|
2
|
+
|
|
3
|
+
Last universal write-side gap closed by s83 t3 PR-4. Companion to
|
|
4
|
+
amend.py — both live in src/seif/amend/ because both implement
|
|
5
|
+
amendment-chain-aware artifact creation/mutation.
|
|
6
|
+
|
|
7
|
+
Behavior
|
|
8
|
+
--------
|
|
9
|
+
1. Resolve workspace root (walk up from cwd for a directory containing
|
|
10
|
+
`.seif/`, or accept explicit --seed-output PATH).
|
|
11
|
+
2. Compute the canonical filename `SEED-s{N}-{YYYY-MM-DD}.json` under
|
|
12
|
+
`.seif/seeds/`.
|
|
13
|
+
3. Refuse to overwrite an existing file (use `--amend` to mutate, or
|
|
14
|
+
delete + recreate explicitly).
|
|
15
|
+
4. Build a minimal valid record (SEIF-SEED-v2 protocol) with auto-
|
|
16
|
+
filled fields. Merge in any user-supplied JSON via
|
|
17
|
+
`--seed-content-file PATH`. User fields win on conflict.
|
|
18
|
+
5. Atomic write (tempfile in same dir → fsync → rename).
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import datetime
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import sys
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
__all__ = ["cmd_seed_create", "build_seed_record", "resolve_seed_output_path"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _now_iso() -> str:
|
|
32
|
+
return (
|
|
33
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
34
|
+
.isoformat()
|
|
35
|
+
.replace("+00:00", "Z")
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _today_yyyymmdd() -> str:
|
|
40
|
+
return datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _walk_up_for_seif(start: Path) -> Path | None:
|
|
44
|
+
cur = start.resolve()
|
|
45
|
+
for _ in range(20):
|
|
46
|
+
if (cur / ".seif").is_dir():
|
|
47
|
+
return cur
|
|
48
|
+
if cur == cur.parent:
|
|
49
|
+
return None
|
|
50
|
+
cur = cur.parent
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def resolve_seed_output_path(
|
|
55
|
+
session_target: int,
|
|
56
|
+
*,
|
|
57
|
+
explicit_output: str | None = None,
|
|
58
|
+
workspace: str | None = None,
|
|
59
|
+
) -> Path:
|
|
60
|
+
"""Compute the seed file path. `explicit_output` overrides everything."""
|
|
61
|
+
if explicit_output:
|
|
62
|
+
return Path(explicit_output).expanduser().resolve()
|
|
63
|
+
if workspace:
|
|
64
|
+
ws = Path(workspace).expanduser().resolve()
|
|
65
|
+
else:
|
|
66
|
+
ws = _walk_up_for_seif(Path.cwd())
|
|
67
|
+
if ws is None:
|
|
68
|
+
raise FileNotFoundError(
|
|
69
|
+
"no .seif/ workspace found from cwd. "
|
|
70
|
+
"Pass --seed-output PATH or cd into a workspace."
|
|
71
|
+
)
|
|
72
|
+
return ws / ".seif" / "seeds" / f"SEED-s{session_target}-{_today_yyyymmdd()}.json"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def build_seed_record(
|
|
76
|
+
session_target: int,
|
|
77
|
+
*,
|
|
78
|
+
parent_cycle_module: str | None = None,
|
|
79
|
+
generator: str | None = None,
|
|
80
|
+
content_overlay: dict | None = None,
|
|
81
|
+
) -> dict:
|
|
82
|
+
"""Construct the minimal valid SEIF-SEED-v2 record."""
|
|
83
|
+
base = {
|
|
84
|
+
"_instruction": (
|
|
85
|
+
f"SEED for session {session_target}. Created by seif --seed-create. "
|
|
86
|
+
"Amend via `seif --amend <this-file> --amend-entry '{...}'` to add "
|
|
87
|
+
"session_summary, primary_anchor, expected_actions, what_NOT_to_do, "
|
|
88
|
+
"etc., as the seal ritual unfolds."
|
|
89
|
+
),
|
|
90
|
+
"protocol": "SEIF-SEED-v2",
|
|
91
|
+
"seed_id": f"SEED-s{session_target}-{_today_yyyymmdd()}",
|
|
92
|
+
"generator": generator
|
|
93
|
+
or f"seif --seed-create (user={os.environ.get('USER', 'anonymous')})",
|
|
94
|
+
"generated_at": _now_iso(),
|
|
95
|
+
"session_target": session_target,
|
|
96
|
+
"parent_session": session_target - 1 if session_target > 0 else None,
|
|
97
|
+
"parent_cycle_module": parent_cycle_module,
|
|
98
|
+
"_amendments": [],
|
|
99
|
+
}
|
|
100
|
+
if content_overlay:
|
|
101
|
+
# User-supplied fields win — they may carry session_summary, anchors, etc.
|
|
102
|
+
merged = dict(base)
|
|
103
|
+
merged.update(content_overlay)
|
|
104
|
+
# Always preserve _amendments as a list even if overlay tried to remove it.
|
|
105
|
+
if not isinstance(merged.get("_amendments"), list):
|
|
106
|
+
merged["_amendments"] = base["_amendments"]
|
|
107
|
+
return merged
|
|
108
|
+
return base
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _atomic_write(path: Path, data: dict) -> None:
|
|
112
|
+
import tempfile
|
|
113
|
+
|
|
114
|
+
body = json.dumps(data, indent=2, ensure_ascii=False)
|
|
115
|
+
parent = path.parent
|
|
116
|
+
parent.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
with tempfile.NamedTemporaryFile(
|
|
118
|
+
mode="w",
|
|
119
|
+
encoding="utf-8",
|
|
120
|
+
dir=str(parent),
|
|
121
|
+
prefix=path.name + ".",
|
|
122
|
+
suffix=".tmp",
|
|
123
|
+
delete=False,
|
|
124
|
+
) as tf:
|
|
125
|
+
tmp = Path(tf.name)
|
|
126
|
+
tf.write(body)
|
|
127
|
+
tf.write("\n")
|
|
128
|
+
tf.flush()
|
|
129
|
+
os.fsync(tf.fileno())
|
|
130
|
+
tmp.replace(path)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def cmd_seed_create(args) -> int:
|
|
134
|
+
"""Entrypoint for `seif --seed-create --seed-session N [...]`."""
|
|
135
|
+
target = getattr(args, "seed_session", None)
|
|
136
|
+
if target is None:
|
|
137
|
+
print(
|
|
138
|
+
"Error: --seed-create requires --seed-session N (target session number)",
|
|
139
|
+
file=sys.stderr,
|
|
140
|
+
)
|
|
141
|
+
return 2
|
|
142
|
+
if not isinstance(target, int) or target < 0:
|
|
143
|
+
print(f"Error: --seed-session must be a non-negative integer (got {target})",
|
|
144
|
+
file=sys.stderr)
|
|
145
|
+
return 2
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
out_path = resolve_seed_output_path(
|
|
149
|
+
target,
|
|
150
|
+
explicit_output=getattr(args, "seed_output", None),
|
|
151
|
+
workspace=getattr(args, "seed_workspace", None),
|
|
152
|
+
)
|
|
153
|
+
except FileNotFoundError as e:
|
|
154
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
155
|
+
return 2
|
|
156
|
+
|
|
157
|
+
if out_path.exists():
|
|
158
|
+
print(
|
|
159
|
+
f"Error: {out_path} already exists. Use `seif --amend` to mutate, "
|
|
160
|
+
"or remove it explicitly before re-running --seed-create.",
|
|
161
|
+
file=sys.stderr,
|
|
162
|
+
)
|
|
163
|
+
return 2
|
|
164
|
+
|
|
165
|
+
overlay: dict | None = None
|
|
166
|
+
overlay_file = getattr(args, "seed_content_file", None)
|
|
167
|
+
if overlay_file:
|
|
168
|
+
op = Path(overlay_file)
|
|
169
|
+
if not op.is_file():
|
|
170
|
+
print(f"Error: --seed-content-file {op} does not exist", file=sys.stderr)
|
|
171
|
+
return 2
|
|
172
|
+
try:
|
|
173
|
+
overlay = json.loads(op.read_text(encoding="utf-8"))
|
|
174
|
+
except (ValueError, json.JSONDecodeError) as e:
|
|
175
|
+
print(f"Error: --seed-content-file is not valid JSON: {e}", file=sys.stderr)
|
|
176
|
+
return 2
|
|
177
|
+
if not isinstance(overlay, dict):
|
|
178
|
+
print("Error: --seed-content-file must contain a JSON object", file=sys.stderr)
|
|
179
|
+
return 2
|
|
180
|
+
|
|
181
|
+
record = build_seed_record(
|
|
182
|
+
target,
|
|
183
|
+
parent_cycle_module=getattr(args, "seed_from_cycle", None),
|
|
184
|
+
generator=getattr(args, "seed_generator", None),
|
|
185
|
+
content_overlay=overlay,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
_atomic_write(out_path, record)
|
|
190
|
+
except OSError as e:
|
|
191
|
+
print(f"Error: I/O failure writing {out_path}: {e}", file=sys.stderr)
|
|
192
|
+
return 2
|
|
193
|
+
|
|
194
|
+
print(f"[seed-create] wrote {out_path}")
|
|
195
|
+
print(f" seed_id: {record['seed_id']}")
|
|
196
|
+
print(f" parent_session: {record['parent_session']}")
|
|
197
|
+
if record["parent_cycle_module"]:
|
|
198
|
+
print(f" parent_cycle_module: {record['parent_cycle_module']}")
|
|
199
|
+
return 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""S.E.I.F. — Signed Evidence & Integrity Framework"""
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Audit subpackage — discipline observation reports.
|
|
2
|
+
|
|
3
|
+
Pairs with the PreToolUse hook observer (plugins/adapters/claude-code/scripts/
|
|
4
|
+
discipline_observer.py) that appends JSONL entries when AI agents Write/Edit
|
|
5
|
+
files under .seif/{cycles,sessions,seeds,memory,modules}/**. Phase-1 of s83
|
|
6
|
+
t3 discipline enforcement; see pending-2026-05-11-s83-t3-discipline-enforcement.
|
|
7
|
+
"""
|