kanibako-cli 1.8.0.dev98__tar.gz → 1.8.0rc2__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.
- {kanibako_cli-1.8.0.dev98/src/kanibako_cli.egg-info → kanibako_cli-1.8.0rc2}/PKG-INFO +1 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/README.md +49 -34
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/pyproject.toml +5 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/__init__.py +1 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/agent_ref.py +5 -1
- kanibako_cli-1.8.0rc2/src/kanibako/box_lifecycle.py +232 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/box_supervisor.py +544 -19
- kanibako_cli-1.8.0rc2/src/kanibako/channels/channels.py +353 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/helper_listener.py +17 -4
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/helpers.py +19 -6
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/cli.py +20 -5
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/agent_cmd.py +137 -50
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/archive.py +14 -2
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/_duplicate.py +81 -43
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/_lifecycle.py +413 -93
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/_parser.py +64 -11
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/clean.py +24 -8
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/code_cmd.py +125 -19
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/diagnose.py +145 -4
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/flags.py +170 -179
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/helper_cmd.py +4 -2
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/restore.py +1 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/setup_cmd.py +49 -9
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/start.py +864 -1012
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/stop.py +12 -3
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/system_cmd.py +49 -35
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/workset_cmd.py +195 -41
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/core-defaults.yaml +7 -8
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/KICKOFF.md +18 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/COLLECTION.md +7 -10
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/bible/ROM_CONTENTS.md +7 -7
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/bible/box/directives/ROM_BOX.md +2 -1
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/directives/ROM_GENERAL.md +112 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/clear-end.sh +12 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/clear-start.sh +12 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/compact.sh +12 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/edited.sh +7 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/end.sh +12 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/resume.sh +12 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/startup.sh +12 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/stop.sh +7 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/util/pid-add.sh +14 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/util/pid-rm.sh +17 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/bible/workset/directives/ROM_WORKSET.md +2 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/agent_default/canon/handbook/directives/SYS_AGENT.md +3 -3
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/canon/handbook/directives/SYS_BOX.md +2 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/notebook/MY_CONTENTS.md +4 -6
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/notebook/directives/CONVENTIONS.md +4 -10
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/handbook/SYS_CONTENTS.md +6 -6
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/handbook/general/directives/SYS_GENERAL.md +10 -6
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/directives/rules/CANON.md +60 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/directives/rules/DATAPOLICY.md +44 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/directives/rules/INTERACTION.md +32 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/procedures/USING_CHANNELS.md +28 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/behavior/check-comms.sh +74 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/clear-end.sh +8 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/clear-start.sh +8 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/compact.sh +8 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/edited.sh +7 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/end.sh +8 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/resume.sh +8 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/startup.sh +8 -0
- kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/stop.sh +8 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/workset/canon/handbook/directives/SYS_WORKSET.md +7 -9
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/keyspace-manifest.yaml +216 -528
- kanibako_cli-1.8.0rc2/src/kanibako/errors.py +84 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/kuid.py +17 -37
- kanibako_cli-1.8.0rc2/src/kanibako/launch/box_identity.py +231 -0
- kanibako_cli-1.8.0rc2/src/kanibako/launch/box_resolve.py +253 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/launch/creds_watcher.py +7 -1
- kanibako_cli-1.8.0rc2/src/kanibako/launch/journal.py +158 -0
- kanibako_cli-1.8.0rc2/src/kanibako/launch/shells.py +161 -0
- kanibako_cli-1.8.0rc2/src/kanibako/launch/templates.py +1174 -0
- kanibako_cli-1.8.0rc2/src/kanibako/persona_store.py +333 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/project/__init__.py +2 -2
- kanibako_cli-1.8.0rc2/src/kanibako/project/import_reconcile.py +269 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/project/names.py +14 -5
- kanibako_cli-1.8.0rc2/src/kanibako/project/registry_store.py +238 -0
- kanibako_cli-1.8.0rc2/src/kanibako/project/workset.py +1058 -0
- kanibako_cli-1.8.0rc2/src/kanibako/project/workset_registry.py +245 -0
- kanibako_cli-1.8.0rc2/src/kanibako/proxy/__init__.py +36 -0
- kanibako_cli-1.8.0rc2/src/kanibako/proxy/server.py +410 -0
- kanibako_cli-1.8.0rc2/src/kanibako/proxy/sse.py +178 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/container.py +68 -12
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/helper-init.sh +6 -6
- kanibako_cli-1.8.0rc2/src/kanibako/scripts/import-directives.py +1094 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/__init__.py +10 -1
- kanibako_cli-1.8.0rc2/src/kanibako/settings/agent_config.py +255 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/agent_defaults.py +1 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/agent_file.py +246 -239
- kanibako_cli-1.8.0rc2/src/kanibako/settings/agent_representation.py +243 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/agent_select.py +188 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config.py +314 -90
- kanibako_cli-1.8.0rc2/src/kanibako/settings/config_dest.py +410 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config_display.py +138 -75
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config_interface.py +487 -53
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config_io.py +30 -77
- kanibako_cli-1.8.0rc2/src/kanibako/settings/config_keys.py +1902 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/core_defaults.py +13 -4
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/defaults_inventory.py +100 -19
- kanibako_cli-1.8.0rc2/src/kanibako/settings/kb_store.py +60 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/keyspace_manifest.py +52 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/keystore.py +59 -38
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/paths.py +445 -128
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/paths_defaults.py +48 -25
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/settings_assemble.py +392 -54
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_categories.py +811 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_cli_level.py +154 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_configset.py +138 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_expand.py +538 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_keyspace.py +1800 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_keyspace_probe.py +363 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_launch.py +2271 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_merge.py +169 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/settings_prefs.py +232 -229
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_resolve.py +433 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_views.py +543 -0
- kanibako_cli-1.8.0rc2/src/kanibako/settings/store_collapse.py +975 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/store_shape.py +14 -13
- kanibako_cli-1.8.0rc2/src/kanibako/settings/workset_dirkeys.py +143 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/targets/__init__.py +26 -8
- kanibako_cli-1.8.0rc2/src/kanibako/targets/assembly.py +433 -0
- kanibako_cli-1.8.0rc2/src/kanibako/targets/base.py +618 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/vscode/vscode_config.py +24 -11
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/vscode/vscode_remote.py +8 -2
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2/src/kanibako_cli.egg-info}/PKG-INFO +1 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/SOURCES.txt +29 -5
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_box_supervisor.py +949 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_canon_delivery.py +2 -2
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_canon_lifecycle_deletion.py +1 -1
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_categories_live.py +740 -23
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_category_collisions.py +22 -9
- kanibako_cli-1.8.0rc2/tests/test_claude_seed_hooks.py +301 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_cli.py +39 -11
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_cli_exitcodes.py +9 -4
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_create_recovery.py +2 -2
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_delivery_manifest.py +6 -7
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_env_cmd.py +11 -11
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_flawed_oracle.py +51 -17
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_fork.py +90 -3
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_helper_cmd.py +17 -2
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_import.py +210 -42
- kanibako_cli-1.8.0rc2/tests/test_import_directives.py +1484 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_import_recovery.py +17 -14
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_init_cmd.py +18 -10
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_install_integration.py +10 -7
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_instructions_bind.py +80 -32
- kanibako_cli-1.8.0rc2/tests/test_keyspec_extract.py +174 -0
- kanibako_cli-1.8.0rc2/tests/test_keystore_census.py +402 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_lifecycle_integration.py +4 -15
- kanibako_cli-1.8.0rc2/tests/test_meta_pin.py +135 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_persona_config_set.py +30 -16
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_persona_store.py +1 -1
- kanibako_cli-1.8.0rc2/tests/test_plugin_import_compat.py +367 -0
- kanibako_cli-1.8.0rc2/tests/test_plugin_store_isolation.py +254 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_resource_scoping.py +17 -9
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_safety_invariants.py +3 -3
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_seed_hostdest.py +26 -6
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_setup_cmd.py +30 -18
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_status.py +2 -2
- kanibako_cli-1.8.0.dev98/src/kanibako/agent_config.py +0 -86
- kanibako_cli-1.8.0.dev98/src/kanibako/agent_defaults.py +0 -56
- kanibako_cli-1.8.0.dev98/src/kanibako/box_lifecycle.py +0 -285
- kanibako_cli-1.8.0.dev98/src/kanibako/channels/channels.py +0 -264
- kanibako_cli-1.8.0.dev98/src/kanibako/data/global/KICKOFF.md +0 -2
- kanibako_cli-1.8.0.dev98/src/kanibako/data/global/rom/bible/general/directives/ROM_GENERAL.md +0 -95
- kanibako_cli-1.8.0.dev98/src/kanibako/data/global/template/handbook/general/directives/rules/CANON.md +0 -91
- kanibako_cli-1.8.0.dev98/src/kanibako/data/global/template/handbook/general/directives/rules/DATAPOLICY.md +0 -51
- kanibako_cli-1.8.0.dev98/src/kanibako/data/global/template/handbook/general/directives/rules/INTERACTION.md +0 -59
- kanibako_cli-1.8.0.dev98/src/kanibako/errors.py +0 -118
- kanibako_cli-1.8.0.dev98/src/kanibako/launch/box_identity.py +0 -302
- kanibako_cli-1.8.0.dev98/src/kanibako/launch/box_resolve.py +0 -328
- kanibako_cli-1.8.0.dev98/src/kanibako/launch/journal.py +0 -201
- kanibako_cli-1.8.0.dev98/src/kanibako/launch/shells.py +0 -196
- kanibako_cli-1.8.0.dev98/src/kanibako/launch/templates.py +0 -1252
- kanibako_cli-1.8.0.dev98/src/kanibako/persona_store.py +0 -411
- kanibako_cli-1.8.0.dev98/src/kanibako/project/import_reconcile.py +0 -300
- kanibako_cli-1.8.0.dev98/src/kanibako/project/registry_store.py +0 -355
- kanibako_cli-1.8.0.dev98/src/kanibako/project/workset.py +0 -1017
- kanibako_cli-1.8.0.dev98/src/kanibako/project/workset_registry.py +0 -196
- kanibako_cli-1.8.0.dev98/src/kanibako/scripts/import-directives.py +0 -384
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/agent_config.py +0 -235
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/agent_representation.py +0 -342
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/agent_select.py +0 -281
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/config_dest.py +0 -547
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/config_keys.py +0 -1053
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/kb_store.py +0 -74
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/keyspace_manifest.py +0 -63
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_categories.py +0 -1179
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_cli_level.py +0 -274
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_configset.py +0 -281
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_expand.py +0 -667
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_keyspace.py +0 -817
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_launch.py +0 -2712
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_merge.py +0 -275
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_resolve.py +0 -687
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_views.py +0 -674
- kanibako_cli-1.8.0.dev98/src/kanibako/settings/store_collapse.py +0 -444
- kanibako_cli-1.8.0.dev98/src/kanibako/settings_resolve.py +0 -109
- kanibako_cli-1.8.0.dev98/src/kanibako/targets/assembly.py +0 -545
- kanibako_cli-1.8.0.dev98/src/kanibako/targets/base.py +0 -1102
- kanibako_cli-1.8.0.dev98/src/kanibako/vscode_config.py +0 -140
- kanibako_cli-1.8.0.dev98/tests/test_credentials.py +0 -337
- kanibako_cli-1.8.0.dev98/tests/test_import_directives.py +0 -361
- kanibako_cli-1.8.0.dev98/tests/test_meta_pin.py +0 -83
- kanibako_cli-1.8.0.dev98/tests/test_plugin_import_compat.py +0 -314
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/LICENSE.md +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/setup.cfg +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/__main__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/_atomic.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/auth_browser.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/auth_parser.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/browser_sidecar.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/browser_state.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/bun_sea.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/helper_client.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/baseline_cmd.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/fork_cmd.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/image.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/install.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/upgrade.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/vault_cmd.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-android +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-dotnet +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-js +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-jvm +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-systems +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/tmux.conf +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/workbook/devnotes.md +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/workbook/tasks.md +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/image-baseline.yaml +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/git.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/install_method.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/launch/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/launch/hygiene.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/log.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/plugins/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/py.typed +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/baseline.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/containerfiles.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/freshness.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/image_sharing.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/registry.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_bundle.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_meta.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_registry.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_resolve.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_source.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/templates_image.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/kanibako-entry +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/kanibako-secrets.sh +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/keystore_strings.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/snapshots.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/targets/credsync.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/targets/no_agent.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/tweakcc.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/tweakcc_cache.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/utils.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/vscode/__init__.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/dependency_links.txt +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/entry_points.txt +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/requires.txt +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/top_level.txt +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_agent_ref.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_agent_resolution.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_archive_restore_integration.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_atomic.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_auth_browser.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_auth_parser.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_box_lifecycle.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_browser_sidecar.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_browser_state.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_bun_sea.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_comms.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_error_messages.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_explicit_create.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_git.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_kuid.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_log.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_protected_tree_cleanup.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_snapshots.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_start_integration.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_tweakcc.py +0 -0
- {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_utils.py +0 -0
|
@@ -225,7 +225,7 @@ shortcuts for common operations:
|
|
|
225
225
|
|
|
226
226
|
| Subcommand | Description |
|
|
227
227
|
|------------|-------------|
|
|
228
|
-
| `workset create [path]` | Create working set (`--name`, `--
|
|
228
|
+
| `workset create [path]` | Create working set (`--name`, `--image`, `--no-vault`, `--distinct-auth`) |
|
|
229
229
|
| `workset list` / `workset ls` | List working sets (`-q`) |
|
|
230
230
|
| `workset info` / `workset inspect` | Working set details |
|
|
231
231
|
| `workset rm` / `workset delete` | Remove working set (`--purge`, `--force`) |
|
|
@@ -505,8 +505,8 @@ and cannot be used as a named-workset name.
|
|
|
505
505
|
|
|
506
506
|
```
|
|
507
507
|
$XDG_DATA_HOME/kanibako/primary_workset/
|
|
508
|
-
├──
|
|
509
|
-
├── boxes/{name}/{home/ → ~/ ,
|
|
508
|
+
├── workset.yaml
|
|
509
|
+
├── boxes/{name}/{home/ → ~/ , box.yaml}
|
|
510
510
|
├── vault/{ro,rw}/{name}/ → ~/vault/{ro,rw}
|
|
511
511
|
└── logs/{name}.jsonl
|
|
512
512
|
# the box WORKSPACE stays external: your real project dir → ~/workspace
|
|
@@ -515,7 +515,7 @@ $XDG_DATA_HOME/kanibako/primary_workset/
|
|
|
515
515
|
### Named workset
|
|
516
516
|
|
|
517
517
|
A workset is a *named* project group rooted at a directory you pick. It groups
|
|
518
|
-
related projects under one human-readable root, with a single `<root>/
|
|
518
|
+
related projects under one human-readable root, with a single `<root>/workset.yaml`
|
|
519
519
|
(identity + member list + a group-level settings/auth tier that member boxes
|
|
520
520
|
inherit; see [Configuration](#configuration)). A workset name is a shared
|
|
521
521
|
address and must be unique -- a collision at create/import time is refused.
|
|
@@ -529,8 +529,8 @@ kanibako
|
|
|
529
529
|
|
|
530
530
|
```
|
|
531
531
|
{workset}/
|
|
532
|
-
├──
|
|
533
|
-
├── boxes/{name}/{home/ → ~/ ,
|
|
532
|
+
├── workset.yaml
|
|
533
|
+
├── boxes/{name}/{home/ → ~/ , box.yaml}
|
|
534
534
|
├── workspaces/{name}/ → ~/workspace
|
|
535
535
|
├── vault/{ro,rw}/{name}/ → ~/vault/{ro,rw}
|
|
536
536
|
└── logs/{name}.jsonl
|
|
@@ -559,9 +559,9 @@ kanibako box register ~/myproj # or opt in afterwards
|
|
|
559
559
|
|
|
560
560
|
```
|
|
561
561
|
{project}/ ← project root
|
|
562
|
-
├──
|
|
562
|
+
├── workset.yaml ← workset tier (degenerate workset at the root)
|
|
563
563
|
├── workspace/ → ~/workspace (a subdir, not the root)
|
|
564
|
-
├── box_data/{home/ → ~/ , {name}.jsonl}
|
|
564
|
+
├── box_data/{home/ → ~/ , box.yaml, {name}.jsonl}
|
|
565
565
|
└── vault/{ro,rw}/ → ~/vault/{ro,rw}
|
|
566
566
|
```
|
|
567
567
|
|
|
@@ -744,31 +744,33 @@ support `shell.d/` on the next launch.
|
|
|
744
744
|
## Agent Configuration
|
|
745
745
|
|
|
746
746
|
Each agent gets a YAML configuration file inside its per-agent store directory
|
|
747
|
-
at `$XDG_DATA_HOME/kanibako/agents/{agent}/
|
|
747
|
+
at `$XDG_DATA_HOME/kanibako/agents/{agent}/agent.yaml`. The file is
|
|
748
748
|
generated automatically on first use (via the target plugin's
|
|
749
749
|
`generate_agent_config()` method) and can be edited afterwards.
|
|
750
750
|
|
|
751
751
|
```yaml
|
|
752
|
-
|
|
752
|
+
self:
|
|
753
753
|
name: "Claude Code"
|
|
754
|
-
run_args: []
|
|
754
|
+
run_args: ["--verbose"] # extra CLI args prepended on every launch (omit if none)
|
|
755
755
|
model: "opus" # agent-specific state knobs (e.g. --model for Claude)
|
|
756
756
|
access: "permissive"
|
|
757
|
-
env:
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
757
|
+
env:
|
|
758
|
+
# KEY: "value" # raw env vars injected into the box
|
|
759
|
+
transform_settings:
|
|
760
|
+
# enabled: false # enable tweakcc binary patching
|
|
761
|
+
# config: "~/.tweakcc/config.json" # external tweakcc config file
|
|
762
762
|
```
|
|
763
763
|
|
|
764
764
|
**Sections:**
|
|
765
|
-
- `
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
765
|
+
- `self:` -- the file's root table, which stands for the agent whose file it is
|
|
766
|
+
(`agent.<agent>`); it is a spelling of this file only and has no CLI form. It
|
|
767
|
+
holds identity and defaults (`name`, `run_args`) plus runtime state knobs
|
|
768
|
+
translated by the target plugin into CLI args and env vars (e.g. Claude maps
|
|
769
|
+
`model` -> `--model`). Effective state resolves across the settings cascade
|
|
770
|
+
`system < agent.<agent> < workset < box` with the target's declared defaults
|
|
771
|
+
as the floor.
|
|
772
|
+
- `self.env:` -- environment variables injected into the box
|
|
773
|
+
- `self.transform_settings:` -- optional tweakcc integration for binary patching
|
|
772
774
|
(see [docs/tweakcc.md](docs/tweakcc.md))
|
|
773
775
|
|
|
774
776
|
Per-agent common dirs/caches are declared by the plugin (`agent.<agent>.common` /
|
|
@@ -911,12 +913,18 @@ Later sources override earlier ones when two plugins register the same name.
|
|
|
911
913
|
|------|----------|----------|
|
|
912
914
|
| 1. Entry points | `kanibako.agents` entry point group + `kanibako.plugins.*` namespace scan | Pip-installed packages and bind-mounted plugins in nested containers |
|
|
913
915
|
| 2. User directory | `~/.local/share/kanibako/plugins/*.py` | Personal plugins shared across all projects |
|
|
914
|
-
| 3. Project directory | `{project}
|
|
916
|
+
| 3. Project directory | `{project}/box_data/plugins/*.py` | Project-specific plugins |
|
|
915
917
|
|
|
916
918
|
Drop a `.py` file containing a `Target` subclass into the user or project
|
|
917
919
|
plugins directory and Kanibako picks it up automatically -- no packaging or
|
|
918
920
|
`pip install` needed. Files starting with `_` are skipped.
|
|
919
921
|
|
|
922
|
+
**A plugin that fails to load is skipped, not fatal.** If a plugin raises while
|
|
923
|
+
being imported -- most often because it was built against a different
|
|
924
|
+
`kanibako-cli` -- Kanibako names it on standard error, says the rest still works,
|
|
925
|
+
and carries on without it. Only that agent becomes unavailable; every other
|
|
926
|
+
agent, and `kanibako setup`, are unaffected.
|
|
927
|
+
|
|
920
928
|
**Security note:** file-drop plugins run with the same permissions as
|
|
921
929
|
Kanibako itself. Only place files you trust in plugin directories.
|
|
922
930
|
|
|
@@ -928,10 +936,11 @@ guide.
|
|
|
928
936
|
pip install kanibako-target-myagent
|
|
929
937
|
|
|
930
938
|
# Use a specific target
|
|
931
|
-
kanibako box set
|
|
939
|
+
kanibako box set pref.system.agent=myagent
|
|
932
940
|
kanibako start
|
|
933
941
|
|
|
934
|
-
# (`crab_name`
|
|
942
|
+
# (`crab_name` and `box.agent_name` are gone -- select the agent via
|
|
943
|
+
# pref.system.agent, which is the spelling kanibako's own messages print)
|
|
935
944
|
```
|
|
936
945
|
|
|
937
946
|
## Configuration
|
|
@@ -940,15 +949,17 @@ Kanibako splits **config** (layout -- *where things live*, the `system.*`
|
|
|
940
949
|
namespace) from **settings** (behavior -- `agent.*` / `box.*` / `workset.*` plus
|
|
941
950
|
the category keys). They live in separate file sets.
|
|
942
951
|
|
|
943
|
-
**Settings** follow a
|
|
944
|
-
`*_required` is an absolute admin cap above box), below CLI flags:
|
|
952
|
+
**Settings** follow a 5-tier cascade (box wins), below CLI flags:
|
|
945
953
|
|
|
946
954
|
```
|
|
947
|
-
CLI flag >
|
|
955
|
+
CLI flag > box > workset > agent.<agent> > system > settings_base
|
|
948
956
|
```
|
|
949
957
|
|
|
958
|
+
Within the agent tier, `agent.default` supplies the all-agents fallback for any key
|
|
959
|
+
the active agent's own layer does not set.
|
|
960
|
+
|
|
950
961
|
**Config** (`system.*`) is read from the config file set
|
|
951
|
-
(`config_base < ~/.config/kanibako.yaml
|
|
962
|
+
(`config_base < ~/.config/kanibako.yaml`). Config keys are
|
|
952
963
|
**file-only** -- the CLI reads and shows them but refuses to set them (edit the
|
|
953
964
|
file directly); `setup` and programmatic writers still write them.
|
|
954
965
|
|
|
@@ -987,9 +998,13 @@ All kanibako config/settings files are YAML.
|
|
|
987
998
|
|
|
988
999
|
- **Config (global)**: `$XDG_CONFIG_HOME/kanibako.yaml` (`system.*` layout only)
|
|
989
1000
|
- **System settings**: `$XDG_DATA_HOME/kanibako/global/settings.yaml`
|
|
990
|
-
- **Workset settings**: `<workset_root>/
|
|
991
|
-
|
|
992
|
-
- **
|
|
1001
|
+
- **Workset settings**: `<workset_root>/workset.yaml` (optional -- a workset root has
|
|
1002
|
+
one only once you set something there)
|
|
1003
|
+
- **Workset membership**: `<workset_root>/registry.yaml` (its boxes, as flat `name: path`
|
|
1004
|
+
rows -- and nothing else; a workset is NAMED by the global registry's `worksets:` section,
|
|
1005
|
+
never by a file under its own root)
|
|
1006
|
+
- **Per-agent settings**: `$XDG_DATA_HOME/kanibako/agents/{agent}/agent.yaml`
|
|
1007
|
+
- **Per-box settings**: `boxes/{name}/box.yaml` (standalone: `<root>/box_data/box.yaml`)
|
|
993
1008
|
- **Template root**: `$XDG_DATA_HOME/kanibako/global/template/` (the `box`,
|
|
994
1009
|
`workset` and `agent` moulds new stores are stamped from)
|
|
995
1010
|
- **System handbook**: `$XDG_DATA_HOME/kanibako/global/canon/handbook/` -- your
|
|
@@ -1104,7 +1119,7 @@ A broadcast channel (`all/`) is available to all helpers.
|
|
|
1104
1119
|
workspace/ # helper's working directory
|
|
1105
1120
|
vault/ro/ # read-only vault share
|
|
1106
1121
|
vault/rw/ # read-write vault share
|
|
1107
|
-
|
|
1122
|
+
scripts/ # helper-init.sh (entrypoint wrapper)
|
|
1108
1123
|
peers/ # symlinks to peer channels
|
|
1109
1124
|
all -> ../all/ # broadcast channel
|
|
1110
1125
|
spawn.yaml # RO spawn budget
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kanibako-cli"
|
|
7
|
-
version = "1.8.
|
|
7
|
+
version = "1.8.0rc2"
|
|
8
8
|
description = "Run AI coding agents in rootless containers with per-project isolation"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
dependencies = ["argcomplete>=3.0", "PyYAML>=6.0", "packaging>=20.0"]
|
|
@@ -102,5 +102,9 @@ markers = [
|
|
|
102
102
|
# OF ``unshare_chown``/``unshare_chmod`` themselves: patching the subject with
|
|
103
103
|
# the stub turns real assertions into false reds.
|
|
104
104
|
"no_unshare_sim: never apply the protected-canon unshare simulation",
|
|
105
|
+
# The KeyStore census (tests/_keystore_census.py) fails a run on an undeclared
|
|
106
|
+
# key. A test that EXERCISES a refusal has to write one; it names the exact
|
|
107
|
+
# paths here, and a named path that is never written fails the run in its turn.
|
|
108
|
+
"writes_undeclared: this test writes the named UNDECLARED key paths on purpose",
|
|
105
109
|
]
|
|
106
110
|
addopts = "-m 'not integration and not e2e'"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""kanibako: Run AI coding agents in rootless containers with per-project isolation."""
|
|
2
2
|
|
|
3
|
-
__version__ = "1.8.
|
|
3
|
+
__version__ = "1.8.0rc2"
|
|
4
4
|
|
|
5
5
|
# Two-tier setup/config compatibility constants for the 5-band setup-completion
|
|
6
6
|
# gate (design: ``plans/2026-06-23-setup-version-tiers-NEXT.md``). Both are
|
|
@@ -10,7 +10,11 @@ from __future__ import annotations
|
|
|
10
10
|
import re
|
|
11
11
|
from kanibako.errors import ConfigError
|
|
12
12
|
|
|
13
|
-
# Persona/harness separators
|
|
13
|
+
# Persona/harness separators. ``+`` is the spelling wherever a human looks, the on-disk store
|
|
14
|
+
# dirname included (:func:`kanibako.settings.agent_config.store_dirname`). ``℘`` exists for ONE
|
|
15
|
+
# reason: a key path is split on ``.`` into ``SEGMENT_CHAR_CLASS`` segments (below), which admit
|
|
16
|
+
# no ``+`` — so ``agent.nav+claude.model`` would match only ``agent.nav`` and silently resolve a
|
|
17
|
+
# different key. A node wears ``℘`` INSIDE a key and nowhere else.
|
|
14
18
|
SEPARATORS = (PLUS_SEP := "+", CANONICAL_SEP := "℘")
|
|
15
19
|
|
|
16
20
|
# "Safe" characters in agent names
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Box CLIENT-ATTACHMENT detection — the shared PID-1 lifecycle primitive.
|
|
2
|
+
|
|
3
|
+
⚑ Half of the PID-1 pair with :mod:`kanibako.box_supervisor`: PINNED FLAT,
|
|
4
|
+
STDLIB-ONLY, invoked in-box by a dotted literal. Do not package or move it, and
|
|
5
|
+
do not add a non-stdlib import.
|
|
6
|
+
|
|
7
|
+
⚑ Every probe here is TOLERANT — an absent tmux, empty/garbled output or a
|
|
8
|
+
malformed ``/proc`` entry resolves to a safe falsy / ``None``, never an
|
|
9
|
+
exception. This module runs as PID-1; a raise takes the box down.
|
|
10
|
+
|
|
11
|
+
Reasoning, the increment map and the design refs: ``llm-docs/kanibako/box_lifecycle.py.md``.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import subprocess
|
|
17
|
+
from collections.abc import Callable, Iterable
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from enum import Enum
|
|
20
|
+
from glob import glob
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
# VS Code remote-server directory markers (canonical — shared with code_cmd).
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
# ⚑ ILLUSTRATIVE — the known channels, for readers. NOT the matching rule:
|
|
28
|
+
# :func:`is_vscode_server_path_part` is authoritative and deliberately broader,
|
|
29
|
+
# so editing this tuple does NOT change matching.
|
|
30
|
+
VSCODE_SERVER_DIR_MARKERS: tuple[str, ...] = (
|
|
31
|
+
".vscode-server",
|
|
32
|
+
".vscode-server-insiders",
|
|
33
|
+
".vscode-server-oss",
|
|
34
|
+
".cursor-server",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def is_vscode_server_path_part(part: str) -> bool:
|
|
39
|
+
"""True when a single path SEGMENT names a VS Code remote-server dir.
|
|
40
|
+
|
|
41
|
+
Takes ONE path component (e.g. from :attr:`pathlib.Path.parts`), so a
|
|
42
|
+
caller tests each segment of a resolved/cmdline path independently.
|
|
43
|
+
"""
|
|
44
|
+
return part.startswith(".vscode-server") or part == ".cursor-server"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Pure surface detectors.
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
def vscode_server_present(proc_cmdlines: Iterable[str]) -> bool:
|
|
52
|
+
"""True iff any process command line indicates a running in-box VS Code server.
|
|
53
|
+
|
|
54
|
+
PURE, over ALREADY-collected cmdlines: a cmdline counts when any
|
|
55
|
+
``/``-delimited SEGMENT of it names a remote-server dir — so
|
|
56
|
+
``/home/agent/.vscode-server/bin/<hash>/node`` matches while
|
|
57
|
+
``/usr/bin/node`` does not. An empty iterable → ``False``.
|
|
58
|
+
"""
|
|
59
|
+
for cmdline in proc_cmdlines:
|
|
60
|
+
if any(is_vscode_server_path_part(part) for part in cmdline.split("/")):
|
|
61
|
+
return True
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def tmux_terminal_attached(list_clients_output: str) -> bool:
|
|
66
|
+
"""True iff ``tmux list-clients`` output shows ≥1 attached terminal client.
|
|
67
|
+
|
|
68
|
+
PURE: tmux prints one LINE per attached client and nothing otherwise.
|
|
69
|
+
⚑ The CALLER must normalise any tmux error to ``""`` to keep this a pure
|
|
70
|
+
string test — :func:`_tmux_clients_output` is what does that.
|
|
71
|
+
"""
|
|
72
|
+
return bool(list_clients_output.strip())
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
# Attach-state model + transition classifier.
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
@dataclass(frozen=True)
|
|
80
|
+
class AttachState:
|
|
81
|
+
"""Immutable snapshot of which client surfaces are attached to the box.
|
|
82
|
+
|
|
83
|
+
Two surfaces today, kept as named bools so a new one is a single added
|
|
84
|
+
field. Frozen so a prev/cur pair is safe to hold across a watcher tick.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
vscode_server: bool = False
|
|
88
|
+
tmux_terminal: bool = False
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def any_attached(self) -> bool:
|
|
92
|
+
"""True when ANY client surface is currently attached."""
|
|
93
|
+
return self.vscode_server or self.tmux_terminal
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def _surfaces(self) -> tuple[bool, ...]:
|
|
97
|
+
"""The per-surface flags, positionally stable across states.
|
|
98
|
+
|
|
99
|
+
A new surface added to this tuple needs no classifier change.
|
|
100
|
+
"""
|
|
101
|
+
return (self.vscode_server, self.tmux_terminal)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class LifecycleEvent(Enum):
|
|
105
|
+
"""The transition a watcher tick produces (consumed by E2 self-heal / D)."""
|
|
106
|
+
|
|
107
|
+
ATTACH = "attach"
|
|
108
|
+
DETACH = "detach"
|
|
109
|
+
NONE = "none"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def classify_transition(prev: AttachState, cur: AttachState) -> LifecycleEvent:
|
|
113
|
+
"""Classify the attach-state transition ``prev`` → ``cur`` (PURE).
|
|
114
|
+
|
|
115
|
+
* DETACH — ANY surface present in ``prev`` is gone in ``cur``, even when a
|
|
116
|
+
DIFFERENT surface appeared in the same tick.
|
|
117
|
+
* ATTACH — no surface was lost AND at least one new surface appeared.
|
|
118
|
+
* NONE — no surface changed (includes the idempotent same-state tick).
|
|
119
|
+
|
|
120
|
+
⚑ That DETACH bias is deliberate and safety-critical: MISSING a detach
|
|
121
|
+
drops a just-refreshed token, while an EXTRA detach costs only a redundant,
|
|
122
|
+
idempotent writeback. Do not "fix" the mixed tick — see the llm-doc.
|
|
123
|
+
"""
|
|
124
|
+
lost = any(p and not c for p, c in zip(prev._surfaces, cur._surfaces))
|
|
125
|
+
if lost:
|
|
126
|
+
return LifecycleEvent.DETACH
|
|
127
|
+
gained = any(c and not p for p, c in zip(prev._surfaces, cur._surfaces))
|
|
128
|
+
if gained:
|
|
129
|
+
return LifecycleEvent.ATTACH
|
|
130
|
+
return LifecycleEvent.NONE
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
# Thin INJECTABLE system-probe layer (the ONLY side-effecting code).
|
|
135
|
+
# ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
# The subprocess-runner signature the probes call; tests inject a fake.
|
|
138
|
+
_Runner = Callable[..., "subprocess.CompletedProcess[str]"]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _collect_proc_cmdlines() -> list[str]:
|
|
142
|
+
"""Collect running-process command lines from ``/proc/*/cmdline``.
|
|
143
|
+
|
|
144
|
+
The impure companion to :func:`vscode_server_present`. Tolerant: a
|
|
145
|
+
vanished PID, a permission error or a kernel thread's empty cmdline is
|
|
146
|
+
SKIPPED, never raised.
|
|
147
|
+
"""
|
|
148
|
+
cmdlines: list[str] = []
|
|
149
|
+
for entry in glob("/proc/[0-9]*/cmdline"):
|
|
150
|
+
try:
|
|
151
|
+
raw = Path(entry).read_bytes()
|
|
152
|
+
except OSError:
|
|
153
|
+
# PID vanished between glob and read, or unreadable — skip it.
|
|
154
|
+
continue
|
|
155
|
+
# cmdline is NUL-delimited argv (trailing NUL); decode leniently.
|
|
156
|
+
text = raw.replace(b"\x00", b" ").decode("utf-8", "replace").strip()
|
|
157
|
+
if text:
|
|
158
|
+
cmdlines.append(text)
|
|
159
|
+
return cmdlines
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _tmux_clients_output(session: str, run: _Runner) -> str:
|
|
163
|
+
"""Return ``tmux list-clients -t <session>`` stdout, or ``""`` on any failure.
|
|
164
|
+
|
|
165
|
+
Normalises EVERY not-attached / no-tmux condition to the empty string
|
|
166
|
+
:func:`tmux_terminal_attached` reads as "no terminal".
|
|
167
|
+
⚑ ``-F ""`` is NOT used: the default one-line-per-client output IS the
|
|
168
|
+
presence signal being tested.
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
proc = run(
|
|
172
|
+
["tmux", "list-clients", "-t", session],
|
|
173
|
+
capture_output=True,
|
|
174
|
+
text=True,
|
|
175
|
+
check=False,
|
|
176
|
+
)
|
|
177
|
+
except (FileNotFoundError, OSError):
|
|
178
|
+
return ""
|
|
179
|
+
if proc.returncode != 0:
|
|
180
|
+
return ""
|
|
181
|
+
return proc.stdout or ""
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def snapshot_attach_state(
|
|
185
|
+
session: str,
|
|
186
|
+
*,
|
|
187
|
+
run: _Runner = subprocess.run,
|
|
188
|
+
proc_cmdlines: Iterable[str] | None = None,
|
|
189
|
+
) -> AttachState:
|
|
190
|
+
"""Probe the CURRENT client-attachment state of the box (the impure snapshot).
|
|
191
|
+
|
|
192
|
+
Composes the two pure detectors over freshly probed system state; an
|
|
193
|
+
explicit *proc_cmdlines* skips the ``/proc`` read entirely. ⚑ All probing
|
|
194
|
+
in this module is confined here and to the two ``_*`` helpers. Never
|
|
195
|
+
raises.
|
|
196
|
+
"""
|
|
197
|
+
cmdlines = (
|
|
198
|
+
_collect_proc_cmdlines() if proc_cmdlines is None else list(proc_cmdlines)
|
|
199
|
+
)
|
|
200
|
+
return AttachState(
|
|
201
|
+
vscode_server=vscode_server_present(cmdlines),
|
|
202
|
+
tmux_terminal=tmux_terminal_attached(_tmux_clients_output(session, run)),
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def canonical_tmux_session_pid(
|
|
207
|
+
session: str,
|
|
208
|
+
*,
|
|
209
|
+
run: _Runner = subprocess.run,
|
|
210
|
+
) -> int | None:
|
|
211
|
+
"""Best-effort PID of the tmux server hosting *session* (the "live marker").
|
|
212
|
+
|
|
213
|
+
⚑ ``#{pid}`` is the tmux SERVER pid, not a pane or client pid. ``None``
|
|
214
|
+
when the session is absent, tmux is missing, or the output is unparseable.
|
|
215
|
+
E2 uses this to identify the canonical always-on instance.
|
|
216
|
+
"""
|
|
217
|
+
try:
|
|
218
|
+
proc = run(
|
|
219
|
+
["tmux", "display-message", "-p", "-t", session, "#{pid}"],
|
|
220
|
+
capture_output=True,
|
|
221
|
+
text=True,
|
|
222
|
+
check=False,
|
|
223
|
+
)
|
|
224
|
+
except (FileNotFoundError, OSError):
|
|
225
|
+
return None
|
|
226
|
+
if proc.returncode != 0:
|
|
227
|
+
return None
|
|
228
|
+
text = (proc.stdout or "").strip()
|
|
229
|
+
try:
|
|
230
|
+
return int(text)
|
|
231
|
+
except ValueError:
|
|
232
|
+
return None
|