gini-toolkit 6.0.1.dev0__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.
- gini_toolkit-6.0.1.dev0/PKG-INFO +77 -0
- gini_toolkit-6.0.1.dev0/README.md +56 -0
- gini_toolkit-6.0.1.dev0/pyproject.toml +60 -0
- gini_toolkit-6.0.1.dev0/scripts/build_kb_index.py +61 -0
- gini_toolkit-6.0.1.dev0/scripts/gen_cue_shots.py +193 -0
- gini_toolkit-6.0.1.dev0/scripts/image_report.py +123 -0
- gini_toolkit-6.0.1.dev0/scripts/probe_doctor.py +178 -0
- gini_toolkit-6.0.1.dev0/scripts/server_smoke.py +61 -0
- gini_toolkit-6.0.1.dev0/scripts/validate_lesson.py +55 -0
- gini_toolkit-6.0.1.dev0/setup.cfg +4 -0
- gini_toolkit-6.0.1.dev0/src/gini/__init__.py +12 -0
- gini_toolkit-6.0.1.dev0/src/gini/__main__.py +107 -0
- gini_toolkit-6.0.1.dev0/src/gini/_version.py +24 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/__init__.py +17 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/agent_gamemaster.py +140 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/api.py +291 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/ask.py +123 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/authoring.py +72 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/blackboard.py +114 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/contracts.py +142 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/domains.py +91 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/embed.py +123 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/gamemaster.py +256 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/kb.py +148 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/lesson_resolver.py +261 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/llm/__init__.py +5 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/llm/backend.py +43 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/llm/fake.py +25 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/llm/ollama.py +206 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/loop.py +258 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/mcp_server.py +86 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/meaning.py +225 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/mission.py +210 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/mission_controller.py +208 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/narration.py +116 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/notifier.py +86 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/personas.py +79 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/reasoning.py +172 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/recall.py +248 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/session.py +79 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/teaching_center.py +482 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/tools/__init__.py +3 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/tools/registry.py +193 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/__init__.py +28 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/authoring.py +71 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/contracts.py +54 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/dialectic.py +189 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/harness.py +93 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/justify.py +156 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/learner.py +64 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/mission.py +60 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/os_coach.py +79 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/twin/salience.py +30 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/understand.py +250 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/verifiers.py +106 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/wizard.py +178 -0
- gini_toolkit-6.0.1.dev0/src/gini/agent/xv6_pack.py +74 -0
- gini_toolkit-6.0.1.dev0/src/gini/app/__init__.py +3 -0
- gini_toolkit-6.0.1.dev0/src/gini/app/context.py +368 -0
- gini_toolkit-6.0.1.dev0/src/gini/app/paths.py +121 -0
- gini_toolkit-6.0.1.dev0/src/gini/data/README.md +21 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/__init__.py +9 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/assembly.py +209 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/authoring.py +353 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/blueprints.py +5 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/capabilities.py +177 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/catalog.py +85 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/certify.py +201 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/compose.py +413 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/composition.py +88 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/concepts.py +383 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/connection_rules.py +269 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/constraints.py +153 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/content.py +59 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/cpu_journey.py +89 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/devices.py +747 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/diagnose.py +201 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/element_guide.py +327 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/explain.py +90 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/fingerprint.py +201 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/firewall.py +34 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/flowlog.py +61 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/flowtable.py +179 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/fragment_yaml.py +230 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/fragments.py +169 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/__init__.py +2 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/paging_games.py +119 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/policy_game.py +86 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/process_game.py +48 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/thrash_game.py +75 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/translate_game.py +60 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/games/trap_game.py +86 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/grader.py +155 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/grouping.py +67 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/legality.py +103 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/lesson.py +241 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/lexicon.py +150 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/machine_state.py +410 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/basic-lan.yaml +32 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/cache-in-front.yaml +23 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/decouple-with-queue.yaml +31 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/drive-load.yaml +20 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/fix-the-address.yaml +75 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/fix-the-lan.yaml +43 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/inspect-flows.yaml +16 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/k8s-autoscale.yaml +27 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/least-privilege.yaml +21 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/load-balanced-web.yaml +29 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/observe-it.yaml +24 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/put-in-vpc.yaml +30 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/reachability-boundary.yaml +56 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/sdn-reactive.yaml +35 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/send-request.yaml +19 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/serverless-api.yaml +25 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/networking/service-chain.yaml +33 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/os/lottery-fix.yaml +19 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions/os/priority-fix.yaml +24 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/missions.py +111 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/modulechain.py +36 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/objectives.py +488 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/os_zoo.py +79 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/paging_sim.py +141 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/pricing.py +199 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/probes.py +226 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/profile.py +142 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/recipes.py +738 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/riders.py +309 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/router_modules.py +224 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/routetable.py +67 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/scoring.py +76 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/staging.py +122 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/syscall_builder.py +144 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/topic_cloud.py +62 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/topology.py +213 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/vocabulary.py +51 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/xv6.py +808 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/xv6_fs.py +250 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/xv6_runner.py +113 -0
- gini_toolkit-6.0.1.dev0/src/gini/domain/xv6_vm.py +385 -0
- gini_toolkit-6.0.1.dev0/src/gini/gloader.py +17 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/__init__.py +18 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/cloudfabric_agent.py +370 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/console.py +68 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/control.py +70 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/frame.py +138 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/gbridge.py +638 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/grouter.py +223 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/hostsim.py +90 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/shuttle.py +348 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/switch.py +109 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/transport.py +77 -0
- gini_toolkit-6.0.1.dev0/src/gini/runtime/xv6_bridge.py +312 -0
- gini_toolkit-6.0.1.dev0/src/gini/server/__init__.py +22 -0
- gini_toolkit-6.0.1.dev0/src/gini/server/__main__.py +74 -0
- gini_toolkit-6.0.1.dev0/src/gini/server/app.py +140 -0
- gini_toolkit-6.0.1.dev0/src/gini/server/auth.py +82 -0
- gini_toolkit-6.0.1.dev0/src/gini/server/policy.py +57 -0
- gini_toolkit-6.0.1.dev0/src/gini/server/session.py +23 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/__init__.py +15 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/boardflash.py +248 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/boardsetup.py +374 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/cloud_catalog.py +143 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/compiler.py +1858 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/discovery.py +324 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/gloader.py +183 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/orchestrator.py +1460 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/persistence.py +28 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/probe_runner.py +149 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/project.py +217 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/remote.py +93 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/rider_runner.py +96 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/rider_session.py +171 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/shadow_store.py +52 -0
- gini_toolkit-6.0.1.dev0/src/gini/services/terminal.py +45 -0
- gini_toolkit-6.0.1.dev0/src/gini/setup/__init__.py +17 -0
- gini_toolkit-6.0.1.dev0/src/gini/setup/cli.py +109 -0
- gini_toolkit-6.0.1.dev0/src/gini/setup/images.py +33 -0
- gini_toolkit-6.0.1.dev0/src/gini/setup/marker.py +43 -0
- gini_toolkit-6.0.1.dev0/src/gini/setup/runtime.py +69 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/__init__.py +3 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/app_icon.icns +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/app_icon.ico +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/app_icon.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/app_icon_1024.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/_w.txt +1 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ai.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/canvas.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/cloud.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/cost.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/ai.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/canvas.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/cloud.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/cost.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/metrics.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/router.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/run.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/serverless.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/settings.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/welcome.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/dark/wizard.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/ai.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/canvas.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/cloud.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/cost.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/metrics.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/router.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/run.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/serverless.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/settings.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/welcome.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/ginibrand/wizard.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/ai.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/canvas.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/cloud.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/cost.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/metrics.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/router.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/run.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/serverless.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/settings.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/welcome.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/highcontrast/wizard.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/ai.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/canvas.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/cloud.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/cost.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/metrics.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/router.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/run.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/serverless.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/settings.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/welcome.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/light/wizard.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/metrics.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/router.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/run.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/serverless.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/settings.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/welcome.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assets/cue/wizard.png +0 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/assistant.py +2111 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/author_dialog.py +184 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/board_dialog.py +247 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/branding.py +21 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/canvas.py +2007 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/chat_panel.py +7 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/cpu_journey.py +212 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/cpu_lab.py +306 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/cue_cards.py +214 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/dashboard.py +222 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/diagnose_game.py +336 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/fingerprint_lab.py +219 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/flash_dialog.py +244 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/flow_layout.py +63 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/fragment_manager.py +1415 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/game_catalog.py +184 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/game_renderers.py +340 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/games_lab.py +90 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/inspector.py +1055 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/live_metrics.py +130 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/machine_lab.py +1412 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/main_window.py +3153 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/memory_lab.py +371 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/mission_panel.py +302 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/mode_indicator.py +227 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/palette.py +112 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/peripherals.py +218 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/process_tree.py +130 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/reset_dialog.py +179 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/router_lab.py +776 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/run_button.py +183 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/settings_dialog.py +234 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/signin_dialog.py +111 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/storage_lab.py +219 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/syscall_builder.py +235 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/syscall_lab.py +152 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/theme/__init__.py +5 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/theme/icons.py +145 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/theme/manager.py +291 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/theme/tokens.py +194 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/trap_lab.py +270 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/worker_host.py +102 -0
- gini_toolkit-6.0.1.dev0/src/gini/ui/zoo_lab.py +112 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/PKG-INFO +77 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/SOURCES.txt +486 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/dependency_links.txt +1 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/entry_points.txt +3 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/requires.txt +15 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/scm_file_list.json +481 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/scm_version.json +8 -0
- gini_toolkit-6.0.1.dev0/src/gini_toolkit.egg-info/top_level.txt +1 -0
- gini_toolkit-6.0.1.dev0/tests/conftest.py +39 -0
- gini_toolkit-6.0.1.dev0/tests/test_addressing.py +42 -0
- gini_toolkit-6.0.1.dev0/tests/test_agent.py +46 -0
- gini_toolkit-6.0.1.dev0/tests/test_agent_integration.py +58 -0
- gini_toolkit-6.0.1.dev0/tests/test_agent_loop.py +87 -0
- gini_toolkit-6.0.1.dev0/tests/test_ai_context.py +61 -0
- gini_toolkit-6.0.1.dev0/tests/test_approval_build5.py +145 -0
- gini_toolkit-6.0.1.dev0/tests/test_ask.py +70 -0
- gini_toolkit-6.0.1.dev0/tests/test_ask_gini.py +88 -0
- gini_toolkit-6.0.1.dev0/tests/test_ask_pipeline.py +47 -0
- gini_toolkit-6.0.1.dev0/tests/test_assembly.py +61 -0
- gini_toolkit-6.0.1.dev0/tests/test_assistant_explain_routing.py +55 -0
- gini_toolkit-6.0.1.dev0/tests/test_assistant_menu.py +112 -0
- gini_toolkit-6.0.1.dev0/tests/test_auth.py +233 -0
- gini_toolkit-6.0.1.dev0/tests/test_auth_server.py +129 -0
- gini_toolkit-6.0.1.dev0/tests/test_authoring.py +53 -0
- gini_toolkit-6.0.1.dev0/tests/test_authoring_build2.py +122 -0
- gini_toolkit-6.0.1.dev0/tests/test_autobuild_setting.py +113 -0
- gini_toolkit-6.0.1.dev0/tests/test_blackboard.py +83 -0
- gini_toolkit-6.0.1.dev0/tests/test_blueprints.py +2 -0
- gini_toolkit-6.0.1.dev0/tests/test_board_carry.py +46 -0
- gini_toolkit-6.0.1.dev0/tests/test_board_dialog.py +109 -0
- gini_toolkit-6.0.1.dev0/tests/test_board_liveness.py +124 -0
- gini_toolkit-6.0.1.dev0/tests/test_boardflash.py +170 -0
- gini_toolkit-6.0.1.dev0/tests/test_boardsetup.py +309 -0
- gini_toolkit-6.0.1.dev0/tests/test_canvas_connect.py +98 -0
- gini_toolkit-6.0.1.dev0/tests/test_catalog.py +43 -0
- gini_toolkit-6.0.1.dev0/tests/test_certify.py +149 -0
- gini_toolkit-6.0.1.dev0/tests/test_chat_panel.py +3 -0
- gini_toolkit-6.0.1.dev0/tests/test_cloud.py +250 -0
- gini_toolkit-6.0.1.dev0/tests/test_cloud_fabric.py +110 -0
- gini_toolkit-6.0.1.dev0/tests/test_compose.py +269 -0
- gini_toolkit-6.0.1.dev0/tests/test_composer.py +104 -0
- gini_toolkit-6.0.1.dev0/tests/test_composition.py +61 -0
- gini_toolkit-6.0.1.dev0/tests/test_connect_gesture.py +320 -0
- gini_toolkit-6.0.1.dev0/tests/test_connection_rules.py +85 -0
- gini_toolkit-6.0.1.dev0/tests/test_console_routing.py +97 -0
- gini_toolkit-6.0.1.dev0/tests/test_constraints.py +39 -0
- gini_toolkit-6.0.1.dev0/tests/test_content_and_forks.py +127 -0
- gini_toolkit-6.0.1.dev0/tests/test_contract.py +55 -0
- gini_toolkit-6.0.1.dev0/tests/test_control.py +60 -0
- gini_toolkit-6.0.1.dev0/tests/test_cpu_journey.py +29 -0
- gini_toolkit-6.0.1.dev0/tests/test_cpu_lab.py +147 -0
- gini_toolkit-6.0.1.dev0/tests/test_cue_cards.py +92 -0
- gini_toolkit-6.0.1.dev0/tests/test_delete.py +58 -0
- gini_toolkit-6.0.1.dev0/tests/test_desktop.py +24 -0
- gini_toolkit-6.0.1.dev0/tests/test_diagnose.py +104 -0
- gini_toolkit-6.0.1.dev0/tests/test_diagnose_game.py +83 -0
- gini_toolkit-6.0.1.dev0/tests/test_discovery.py +185 -0
- gini_toolkit-6.0.1.dev0/tests/test_domain.py +48 -0
- gini_toolkit-6.0.1.dev0/tests/test_domains.py +45 -0
- gini_toolkit-6.0.1.dev0/tests/test_embed.py +76 -0
- gini_toolkit-6.0.1.dev0/tests/test_experiments.py +182 -0
- gini_toolkit-6.0.1.dev0/tests/test_explain.py +38 -0
- gini_toolkit-6.0.1.dev0/tests/test_faas_authoring.py +128 -0
- gini_toolkit-6.0.1.dev0/tests/test_faces.py +79 -0
- gini_toolkit-6.0.1.dev0/tests/test_fingerprint.py +67 -0
- gini_toolkit-6.0.1.dev0/tests/test_fingerprint_lab.py +84 -0
- gini_toolkit-6.0.1.dev0/tests/test_flash_dialog.py +163 -0
- gini_toolkit-6.0.1.dev0/tests/test_flowlog.py +46 -0
- gini_toolkit-6.0.1.dev0/tests/test_flowtable.py +92 -0
- gini_toolkit-6.0.1.dev0/tests/test_fragment_ports.py +151 -0
- gini_toolkit-6.0.1.dev0/tests/test_fragment_terminals.py +339 -0
- gini_toolkit-6.0.1.dev0/tests/test_fragment_yaml.py +45 -0
- gini_toolkit-6.0.1.dev0/tests/test_gamemaster.py +104 -0
- gini_toolkit-6.0.1.dev0/tests/test_gini32.py +686 -0
- gini_toolkit-6.0.1.dev0/tests/test_gloader.py +63 -0
- gini_toolkit-6.0.1.dev0/tests/test_gradebook_official.py +49 -0
- gini_toolkit-6.0.1.dev0/tests/test_grader.py +80 -0
- gini_toolkit-6.0.1.dev0/tests/test_grounding_stance.py +37 -0
- gini_toolkit-6.0.1.dev0/tests/test_grouping.py +42 -0
- gini_toolkit-6.0.1.dev0/tests/test_guided_missions.py +127 -0
- gini_toolkit-6.0.1.dev0/tests/test_hub.py +89 -0
- gini_toolkit-6.0.1.dev0/tests/test_integration.py +73 -0
- gini_toolkit-6.0.1.dev0/tests/test_k8s.py +270 -0
- gini_toolkit-6.0.1.dev0/tests/test_kata.py +59 -0
- gini_toolkit-6.0.1.dev0/tests/test_kb.py +54 -0
- gini_toolkit-6.0.1.dev0/tests/test_kb_index_sync.py +18 -0
- gini_toolkit-6.0.1.dev0/tests/test_knowledge.py +104 -0
- gini_toolkit-6.0.1.dev0/tests/test_legality.py +59 -0
- gini_toolkit-6.0.1.dev0/tests/test_lesson.py +64 -0
- gini_toolkit-6.0.1.dev0/tests/test_lesson_resolver.py +44 -0
- gini_toolkit-6.0.1.dev0/tests/test_lexicon.py +41 -0
- gini_toolkit-6.0.1.dev0/tests/test_live_metrics.py +131 -0
- gini_toolkit-6.0.1.dev0/tests/test_loadgen_proxy.py +114 -0
- gini_toolkit-6.0.1.dev0/tests/test_loop_visible.py +56 -0
- gini_toolkit-6.0.1.dev0/tests/test_m2_behavioral.py +64 -0
- gini_toolkit-6.0.1.dev0/tests/test_m7_polish.py +46 -0
- gini_toolkit-6.0.1.dev0/tests/test_machine_lab.py +479 -0
- gini_toolkit-6.0.1.dev0/tests/test_machine_state.py +242 -0
- gini_toolkit-6.0.1.dev0/tests/test_machine_toolkit.py +120 -0
- gini_toolkit-6.0.1.dev0/tests/test_meaning.py +87 -0
- gini_toolkit-6.0.1.dev0/tests/test_memory_lab.py +79 -0
- gini_toolkit-6.0.1.dev0/tests/test_mission.py +82 -0
- gini_toolkit-6.0.1.dev0/tests/test_mission_controller.py +93 -0
- gini_toolkit-6.0.1.dev0/tests/test_mission_panel.py +125 -0
- gini_toolkit-6.0.1.dev0/tests/test_missions.py +32 -0
- gini_toolkit-6.0.1.dev0/tests/test_missions_entry.py +117 -0
- gini_toolkit-6.0.1.dev0/tests/test_missions_mode.py +73 -0
- gini_toolkit-6.0.1.dev0/tests/test_name_independence.py +92 -0
- gini_toolkit-6.0.1.dev0/tests/test_naming.py +37 -0
- gini_toolkit-6.0.1.dev0/tests/test_narration.py +80 -0
- gini_toolkit-6.0.1.dev0/tests/test_nfv.py +30 -0
- gini_toolkit-6.0.1.dev0/tests/test_no_vacuous_objectives.py +42 -0
- gini_toolkit-6.0.1.dev0/tests/test_notifier.py +69 -0
- gini_toolkit-6.0.1.dev0/tests/test_objectives.py +113 -0
- gini_toolkit-6.0.1.dev0/tests/test_ollama_thinking.py +83 -0
- gini_toolkit-6.0.1.dev0/tests/test_orchestrator_switch.py +82 -0
- gini_toolkit-6.0.1.dev0/tests/test_os_zoo.py +33 -0
- gini_toolkit-6.0.1.dev0/tests/test_oszoo_compile.py +95 -0
- gini_toolkit-6.0.1.dev0/tests/test_ota_build4.py +132 -0
- gini_toolkit-6.0.1.dev0/tests/test_paging.py +57 -0
- gini_toolkit-6.0.1.dev0/tests/test_paging_games.py +74 -0
- gini_toolkit-6.0.1.dev0/tests/test_palette_taxonomy.py +61 -0
- gini_toolkit-6.0.1.dev0/tests/test_peripherals_wiring.py +35 -0
- gini_toolkit-6.0.1.dev0/tests/test_persistence.py +45 -0
- gini_toolkit-6.0.1.dev0/tests/test_photo.py +68 -0
- gini_toolkit-6.0.1.dev0/tests/test_policy_game.py +33 -0
- gini_toolkit-6.0.1.dev0/tests/test_present.py +48 -0
- gini_toolkit-6.0.1.dev0/tests/test_pricing.py +112 -0
- gini_toolkit-6.0.1.dev0/tests/test_probes.py +121 -0
- gini_toolkit-6.0.1.dev0/tests/test_process_tree.py +76 -0
- gini_toolkit-6.0.1.dev0/tests/test_profai.py +212 -0
- gini_toolkit-6.0.1.dev0/tests/test_profile.py +81 -0
- gini_toolkit-6.0.1.dev0/tests/test_projects.py +241 -0
- gini_toolkit-6.0.1.dev0/tests/test_rank_spot.py +56 -0
- gini_toolkit-6.0.1.dev0/tests/test_reasoning.py +73 -0
- gini_toolkit-6.0.1.dev0/tests/test_recall.py +81 -0
- gini_toolkit-6.0.1.dev0/tests/test_recipes.py +102 -0
- gini_toolkit-6.0.1.dev0/tests/test_recorder.py +164 -0
- gini_toolkit-6.0.1.dev0/tests/test_remote.py +72 -0
- gini_toolkit-6.0.1.dev0/tests/test_remote_gui.py +71 -0
- gini_toolkit-6.0.1.dev0/tests/test_rider_session.py +111 -0
- gini_toolkit-6.0.1.dev0/tests/test_riders.py +251 -0
- gini_toolkit-6.0.1.dev0/tests/test_router_lab.py +50 -0
- gini_toolkit-6.0.1.dev0/tests/test_routetable.py +50 -0
- gini_toolkit-6.0.1.dev0/tests/test_scaffold.py +120 -0
- gini_toolkit-6.0.1.dev0/tests/test_scoring.py +37 -0
- gini_toolkit-6.0.1.dev0/tests/test_sdn.py +93 -0
- gini_toolkit-6.0.1.dev0/tests/test_sdn_dashboard.py +101 -0
- gini_toolkit-6.0.1.dev0/tests/test_sdn_orchestrator.py +61 -0
- gini_toolkit-6.0.1.dev0/tests/test_secgroup.py +76 -0
- gini_toolkit-6.0.1.dev0/tests/test_server.py +159 -0
- gini_toolkit-6.0.1.dev0/tests/test_serverless.py +138 -0
- gini_toolkit-6.0.1.dev0/tests/test_session.py +51 -0
- gini_toolkit-6.0.1.dev0/tests/test_settings.py +131 -0
- gini_toolkit-6.0.1.dev0/tests/test_setup.py +68 -0
- gini_toolkit-6.0.1.dev0/tests/test_sfc_chain.py +53 -0
- gini_toolkit-6.0.1.dev0/tests/test_sfc_ui.py +48 -0
- gini_toolkit-6.0.1.dev0/tests/test_shadow_store.py +29 -0
- gini_toolkit-6.0.1.dev0/tests/test_sizing.py +135 -0
- gini_toolkit-6.0.1.dev0/tests/test_slots.py +72 -0
- gini_toolkit-6.0.1.dev0/tests/test_social.py +146 -0
- gini_toolkit-6.0.1.dev0/tests/test_social_server.py +172 -0
- gini_toolkit-6.0.1.dev0/tests/test_sources_sinks.py +107 -0
- gini_toolkit-6.0.1.dev0/tests/test_sources_sinks_ui.py +178 -0
- gini_toolkit-6.0.1.dev0/tests/test_staging.py +174 -0
- gini_toolkit-6.0.1.dev0/tests/test_stars.py +43 -0
- gini_toolkit-6.0.1.dev0/tests/test_storage_lab.py +38 -0
- gini_toolkit-6.0.1.dev0/tests/test_store_features.py +172 -0
- gini_toolkit-6.0.1.dev0/tests/test_syscall_builder.py +73 -0
- gini_toolkit-6.0.1.dev0/tests/test_syscall_builder_ui.py +67 -0
- gini_toolkit-6.0.1.dev0/tests/test_tap_offload.py +188 -0
- gini_toolkit-6.0.1.dev0/tests/test_tc_delete.py +74 -0
- gini_toolkit-6.0.1.dev0/tests/test_tc_new_format.py +36 -0
- gini_toolkit-6.0.1.dev0/tests/test_teaching_center.py +126 -0
- gini_toolkit-6.0.1.dev0/tests/test_themes_runbutton.py +123 -0
- gini_toolkit-6.0.1.dev0/tests/test_topic_cloud.py +45 -0
- gini_toolkit-6.0.1.dev0/tests/test_topic_cloud_ui.py +55 -0
- gini_toolkit-6.0.1.dev0/tests/test_trap_fault_game.py +44 -0
- gini_toolkit-6.0.1.dev0/tests/test_trap_lab.py +166 -0
- gini_toolkit-6.0.1.dev0/tests/test_tutor.py +240 -0
- gini_toolkit-6.0.1.dev0/tests/test_twin.py +340 -0
- gini_toolkit-6.0.1.dev0/tests/test_twin_surfaces.py +169 -0
- gini_toolkit-6.0.1.dev0/tests/test_ui_tweaks.py +91 -0
- gini_toolkit-6.0.1.dev0/tests/test_understand.py +73 -0
- gini_toolkit-6.0.1.dev0/tests/test_unified_chat.py +135 -0
- gini_toolkit-6.0.1.dev0/tests/test_upload_build3.py +143 -0
- gini_toolkit-6.0.1.dev0/tests/test_user_pill.py +252 -0
- gini_toolkit-6.0.1.dev0/tests/test_validate.py +59 -0
- gini_toolkit-6.0.1.dev0/tests/test_vnf.py +56 -0
- gini_toolkit-6.0.1.dev0/tests/test_vpc.py +126 -0
- gini_toolkit-6.0.1.dev0/tests/test_vpc_canvas.py +56 -0
- gini_toolkit-6.0.1.dev0/tests/test_wizard.py +136 -0
- gini_toolkit-6.0.1.dev0/tests/test_wizard_engine.py +99 -0
- gini_toolkit-6.0.1.dev0/tests/test_xray.py +112 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6.py +353 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_agent.py +62 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_bridge.py +358 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_compile.py +45 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_fs.py +56 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_modes.py +138 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_pack.py +68 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_patch.py +166 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_runner.py +71 -0
- gini_toolkit-6.0.1.dev0/tests/test_xv6_vm.py +129 -0
- gini_toolkit-6.0.1.dev0/token.txt +1 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gini-toolkit
|
|
3
|
+
Version: 6.0.1.dev0
|
|
4
|
+
Summary: GINI gBuilder — next-generation topology builder for computer networks and cloud computing experimentation
|
|
5
|
+
Author: GINI Toolkit
|
|
6
|
+
License: GPL-3.0-or-later
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: PySide6-Essentials>=6.6
|
|
10
|
+
Requires-Dist: PyYAML>=6.0
|
|
11
|
+
Provides-Extra: agent
|
|
12
|
+
Requires-Dist: mcp>=1.0; extra == "agent"
|
|
13
|
+
Provides-Extra: graph
|
|
14
|
+
Requires-Dist: matplotlib>=3.7; extra == "graph"
|
|
15
|
+
Requires-Dist: numpy>=1.24; extra == "graph"
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-qt>=4; extra == "dev"
|
|
19
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
20
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
21
|
+
|
|
22
|
+
# GINI gBuilder — next generation
|
|
23
|
+
|
|
24
|
+
A ground-up rewrite of the GINI gBuilder frontend on **PySide6 (Qt 6) / Python 3**, expanding
|
|
25
|
+
GINI from a computer-networks lab into an **ultimate experimentation toolkit** spanning both
|
|
26
|
+
**computer networks** and **cloud computing**, with a first-class **AI agent layer** so agents can
|
|
27
|
+
build, inspect, and explain topologies for students.
|
|
28
|
+
|
|
29
|
+
## What's here
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
frontend-ng/
|
|
33
|
+
├── pyproject.toml
|
|
34
|
+
├── src/gini/
|
|
35
|
+
│ ├── __main__.py launch the app (python -m gini)
|
|
36
|
+
│ ├── domain/ pure-Python model — NO Qt
|
|
37
|
+
│ │ ├── devices.py device/element registry (networking + cloud)
|
|
38
|
+
│ │ └── topology.py Topology, DeviceInstance, Link
|
|
39
|
+
│ ├── app/
|
|
40
|
+
│ │ └── context.py AppContext + typed event bus (replaces global singletons)
|
|
41
|
+
│ ├── ui/
|
|
42
|
+
│ │ ├── main_window.py shell: toolbar, palette, canvas, inspector, console, assistant
|
|
43
|
+
│ │ ├── canvas.py QGraphicsView scene + node/edge items
|
|
44
|
+
│ │ ├── palette.py searchable, categorized device palette
|
|
45
|
+
│ │ ├── inspector.py tabbed property inspector
|
|
46
|
+
│ │ ├── assistant.py in-app "Ask GINI" AI assistant panel
|
|
47
|
+
│ │ └── theme/
|
|
48
|
+
│ │ ├── tokens.py themeable design tokens (dark / light / brand)
|
|
49
|
+
│ │ ├── manager.py token → QSS generator + ThemeManager
|
|
50
|
+
│ │ └── icons.py license-safe flat SVG icon set, recolored per category
|
|
51
|
+
│ └── agent/
|
|
52
|
+
│ ├── api.py programmatic GiniAPI: build / inspect / explain / run
|
|
53
|
+
│ └── mcp_server.py MCP server exposing GiniAPI to external agents
|
|
54
|
+
└── tests/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Run it
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd frontend-ng
|
|
61
|
+
pip install -e .
|
|
62
|
+
gbuilder # or: python -m gini
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Headless smoke test (no display needed):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
QT_QPA_PLATFORM=offscreen python -m gini --selftest
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Status
|
|
72
|
+
|
|
73
|
+
Early scaffold (Phase 2 of the evolution plan). The UI shell, themeable design system, icon
|
|
74
|
+
system, the expanded device taxonomy, and the agent API/MCP scaffold are in place and runnable.
|
|
75
|
+
The legacy `.gsav`/compiler/protocol services are being ported behind `services/` next.
|
|
76
|
+
|
|
77
|
+
See `../GINI Project/GINI_Frontend_Evolution_Plan.md` for the full roadmap.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# GINI gBuilder — next generation
|
|
2
|
+
|
|
3
|
+
A ground-up rewrite of the GINI gBuilder frontend on **PySide6 (Qt 6) / Python 3**, expanding
|
|
4
|
+
GINI from a computer-networks lab into an **ultimate experimentation toolkit** spanning both
|
|
5
|
+
**computer networks** and **cloud computing**, with a first-class **AI agent layer** so agents can
|
|
6
|
+
build, inspect, and explain topologies for students.
|
|
7
|
+
|
|
8
|
+
## What's here
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
frontend-ng/
|
|
12
|
+
├── pyproject.toml
|
|
13
|
+
├── src/gini/
|
|
14
|
+
│ ├── __main__.py launch the app (python -m gini)
|
|
15
|
+
│ ├── domain/ pure-Python model — NO Qt
|
|
16
|
+
│ │ ├── devices.py device/element registry (networking + cloud)
|
|
17
|
+
│ │ └── topology.py Topology, DeviceInstance, Link
|
|
18
|
+
│ ├── app/
|
|
19
|
+
│ │ └── context.py AppContext + typed event bus (replaces global singletons)
|
|
20
|
+
│ ├── ui/
|
|
21
|
+
│ │ ├── main_window.py shell: toolbar, palette, canvas, inspector, console, assistant
|
|
22
|
+
│ │ ├── canvas.py QGraphicsView scene + node/edge items
|
|
23
|
+
│ │ ├── palette.py searchable, categorized device palette
|
|
24
|
+
│ │ ├── inspector.py tabbed property inspector
|
|
25
|
+
│ │ ├── assistant.py in-app "Ask GINI" AI assistant panel
|
|
26
|
+
│ │ └── theme/
|
|
27
|
+
│ │ ├── tokens.py themeable design tokens (dark / light / brand)
|
|
28
|
+
│ │ ├── manager.py token → QSS generator + ThemeManager
|
|
29
|
+
│ │ └── icons.py license-safe flat SVG icon set, recolored per category
|
|
30
|
+
│ └── agent/
|
|
31
|
+
│ ├── api.py programmatic GiniAPI: build / inspect / explain / run
|
|
32
|
+
│ └── mcp_server.py MCP server exposing GiniAPI to external agents
|
|
33
|
+
└── tests/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Run it
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd frontend-ng
|
|
40
|
+
pip install -e .
|
|
41
|
+
gbuilder # or: python -m gini
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Headless smoke test (no display needed):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
QT_QPA_PLATFORM=offscreen python -m gini --selftest
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Status
|
|
51
|
+
|
|
52
|
+
Early scaffold (Phase 2 of the evolution plan). The UI shell, themeable design system, icon
|
|
53
|
+
system, the expanded device taxonomy, and the agent API/MCP scaffold are in place and runnable.
|
|
54
|
+
The legacy `.gsav`/compiler/protocol services are being ported behind `services/` next.
|
|
55
|
+
|
|
56
|
+
See `../GINI Project/GINI_Frontend_Evolution_Plan.md` for the full roadmap.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "setuptools-scm>=8"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gini-toolkit"
|
|
7
|
+
dynamic = ["version"] # derived from git tags by setuptools-scm (see [tool.setuptools_scm])
|
|
8
|
+
description = "GINI gBuilder — next-generation topology builder for computer networks and cloud computing experimentation"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "GPL-3.0-or-later" }
|
|
12
|
+
authors = [{ name = "GINI Toolkit" }]
|
|
13
|
+
# `pip install gini-toolkit` gives a runnable desktop app: engine + the PySide6/Qt GUI. The
|
|
14
|
+
# container runtime (Docker/Colima) and images are brought in separately by the `gini-setup` command.
|
|
15
|
+
dependencies = [
|
|
16
|
+
"PySide6-Essentials>=6.6", # the Qt6 desktop GUI (gini.ui + the `gbuilder` entrypoint)
|
|
17
|
+
"PyYAML>=6.0", # reads authored Lesson packs (Missions / Teaching Center)
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
agent = [
|
|
22
|
+
"mcp>=1.0", # Model Context Protocol server (in-app + external agents)
|
|
23
|
+
]
|
|
24
|
+
graph = [
|
|
25
|
+
"matplotlib>=3.7", # router / instance statistics graphing
|
|
26
|
+
"numpy>=1.24",
|
|
27
|
+
]
|
|
28
|
+
dev = [
|
|
29
|
+
"pytest>=7",
|
|
30
|
+
"pytest-qt>=4",
|
|
31
|
+
"ruff>=0.4",
|
|
32
|
+
"mypy>=1.8",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
gbuilder = "gini.__main__:main" # the desktop app
|
|
37
|
+
gini-setup = "gini.setup.cli:main" # one-time: bring in the container runtime + images
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
where = ["src"]
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.package-data]
|
|
43
|
+
"gini.ui" = ["assets/*.png", "assets/*.ico", "assets/*.icns"]
|
|
44
|
+
"gini.domain" = ["missions/**/*.yaml"]
|
|
45
|
+
|
|
46
|
+
# Version comes from git tags (e.g. `git tag v6.1.0` -> 6.1.0). The repo root is one level up from
|
|
47
|
+
# this pyproject, hence root = "..". A generated _version.py is written into the package at build
|
|
48
|
+
# time (gitignored). Untagged working trees get e.g. 6.1.0.dev3+g<hash>.
|
|
49
|
+
[tool.setuptools_scm]
|
|
50
|
+
root = ".."
|
|
51
|
+
version_file = "src/gini/_version.py"
|
|
52
|
+
# drop the "+g<hash>" local segment: tagged clean builds -> 6.0.0; between-tag builds -> 6.0.1.dev0
|
|
53
|
+
local_scheme = "no-local-version"
|
|
54
|
+
|
|
55
|
+
[tool.ruff]
|
|
56
|
+
line-length = 100
|
|
57
|
+
target-version = "py310"
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Build the shipped semantic index for Ask GINI's L2 recall.
|
|
3
|
+
|
|
4
|
+
Embeds every KB document (`agent.embed.kb_documents()`) via an Ollama `/api/embed` call and
|
|
5
|
+
writes `src/gini/data/kb_index.json` (model tag + KB hash + id→vector). Run this whenever the
|
|
6
|
+
concept notes, recipes, or element catalog change — a test (`test_kb_index_sync`) fails if the
|
|
7
|
+
shipped index drifts from the live KB.
|
|
8
|
+
|
|
9
|
+
Requires a running Ollama with the embed model pulled, e.g.:
|
|
10
|
+
|
|
11
|
+
ollama pull all-minilm
|
|
12
|
+
GINI_LLM_URL=http://localhost:11434 python scripts/build_kb_index.py
|
|
13
|
+
|
|
14
|
+
Env: GINI_LLM_URL (default http://localhost:11434), GINI_EMBED_MODEL (default all-minilm).
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
|
|
24
|
+
|
|
25
|
+
from gini.agent.embed import _INDEX_PATH, kb_documents, kb_hash # noqa: E402
|
|
26
|
+
from gini.agent.llm import OllamaBackend # noqa: E402
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main() -> int:
|
|
30
|
+
url = os.environ.get("GINI_LLM_URL", "http://localhost:11434")
|
|
31
|
+
model = os.environ.get("GINI_EMBED_MODEL", "all-minilm")
|
|
32
|
+
backend = OllamaBackend(url, embed_model=model)
|
|
33
|
+
if not backend.available():
|
|
34
|
+
print(f"Ollama not reachable at {url} — start it and `ollama pull {model}`.")
|
|
35
|
+
return 1
|
|
36
|
+
|
|
37
|
+
docs = kb_documents()
|
|
38
|
+
ids = [d for d, _ in docs]
|
|
39
|
+
texts = [t for _, t in docs]
|
|
40
|
+
print(f"Embedding {len(texts)} KB documents with '{model}' …")
|
|
41
|
+
|
|
42
|
+
vectors: dict[str, list[float]] = {}
|
|
43
|
+
for i in range(0, len(texts), 32): # batch to be gentle on the server
|
|
44
|
+
chunk_ids = ids[i:i + 32]
|
|
45
|
+
chunk_vecs = backend.embed(texts[i:i + 32])
|
|
46
|
+
if len(chunk_vecs) != len(chunk_ids):
|
|
47
|
+
print(f" embed returned {len(chunk_vecs)} vectors for {len(chunk_ids)} docs — aborting.")
|
|
48
|
+
return 2
|
|
49
|
+
for did, vec in zip(chunk_ids, chunk_vecs):
|
|
50
|
+
vectors[did] = [round(float(x), 6) for x in vec]
|
|
51
|
+
|
|
52
|
+
dim = len(next(iter(vectors.values()))) if vectors else 0
|
|
53
|
+
index = {"model": model, "dim": dim, "kb_hash": kb_hash(), "vectors": vectors}
|
|
54
|
+
_INDEX_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
_INDEX_PATH.write_text(json.dumps(index))
|
|
56
|
+
print(f"Wrote {_INDEX_PATH} — {len(vectors)} vectors, dim {dim}.")
|
|
57
|
+
return 0
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Generate the Cue Cards feature-tour screenshots from the real gBuilder UI, per theme.
|
|
2
|
+
|
|
3
|
+
Renders curated portions of the actual interface (no mockups) to PNGs under
|
|
4
|
+
``src/gini/ui/assets/cue/<theme-slug>/<kind>.png`` — one set per theme, one image per card
|
|
5
|
+
in cue_cards.FEATURE_CARDS — so the tour matches whatever theme GINI is running. Re-run
|
|
6
|
+
after UI changes (best on macOS for native fonts)::
|
|
7
|
+
|
|
8
|
+
QT_QPA_PLATFORM=offscreen python -m scripts.gen_cue_shots
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
import tempfile
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
|
18
|
+
# write any settings to a throwaway home so the generator never changes the user's theme
|
|
19
|
+
os.environ["GINI_HOME_DIR"] = tempfile.mkdtemp(prefix="gini-genshots-")
|
|
20
|
+
|
|
21
|
+
SS = 2 # supersample factor — captures at 2x so the cards stay sharp on Retina
|
|
22
|
+
|
|
23
|
+
from PySide6.QtCore import QPoint, QRectF, Qt
|
|
24
|
+
from PySide6.QtGui import QImage, QPainter
|
|
25
|
+
from PySide6.QtWidgets import QApplication
|
|
26
|
+
|
|
27
|
+
OUT = Path(__file__).resolve().parents[1] / "src" / "gini" / "ui" / "assets" / "cue"
|
|
28
|
+
THEMES = ("Dark", "Light", "GINI Brand", "High Contrast", "Sand", "Blue", "Green")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def theme_slug(name: str) -> str:
|
|
32
|
+
return re.sub(r"[^a-z0-9]", "", (name or "dark").lower()) or "dark"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _bg(theme) -> int:
|
|
36
|
+
c = theme.theme.bg
|
|
37
|
+
from gini.ui.cue_cards import _qcolor
|
|
38
|
+
return _qcolor(c).rgb()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _save(img: QImage, name: str, outdir: Path) -> None:
|
|
42
|
+
outdir.mkdir(parents=True, exist_ok=True)
|
|
43
|
+
img.save(str(outdir / f"{name}.png"))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _scene_shot(scene, name, outdir, bg, scale=2.8, pad=26) -> None:
|
|
47
|
+
rect = scene.itemsBoundingRect().adjusted(-pad, -pad, pad, pad)
|
|
48
|
+
img = QImage(max(1, int(rect.width() * scale)), max(1, int(rect.height() * scale)),
|
|
49
|
+
QImage.Format_ARGB32)
|
|
50
|
+
img.fill(bg)
|
|
51
|
+
p = QPainter(img)
|
|
52
|
+
p.setRenderHint(QPainter.Antialiasing, True)
|
|
53
|
+
p.setRenderHint(QPainter.SmoothPixmapTransform, True)
|
|
54
|
+
p.setRenderHint(QPainter.TextAntialiasing, True)
|
|
55
|
+
scene.render(p, QRectF(img.rect()), rect); p.end()
|
|
56
|
+
_save(img, name, outdir)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _widget_shot(widget, name, outdir, bg, w, h) -> None:
|
|
60
|
+
# render through a painter scaled by SS so the PNG is high-res regardless of the
|
|
61
|
+
# platform's device-pixel-ratio (grab() alone is 1x offscreen on Linux).
|
|
62
|
+
widget.resize(w, h)
|
|
63
|
+
QApplication.processEvents()
|
|
64
|
+
sz = widget.size() # actual size (clamps to the size hint)
|
|
65
|
+
img = QImage(sz.width() * SS, sz.height() * SS, QImage.Format_ARGB32)
|
|
66
|
+
img.fill(bg)
|
|
67
|
+
p = QPainter(img)
|
|
68
|
+
p.scale(SS, SS)
|
|
69
|
+
widget.render(p, QPoint(0, 0))
|
|
70
|
+
p.end()
|
|
71
|
+
_save(img, name, outdir)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _clear_warnings(win) -> None:
|
|
75
|
+
win.ctx.warnings = {}
|
|
76
|
+
for n in win.canvas.scene_.nodes.values():
|
|
77
|
+
n.update()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _generate(win, app, outdir: Path) -> None:
|
|
81
|
+
"""Render the full set of curated shots for the currently-applied theme."""
|
|
82
|
+
api = win.api
|
|
83
|
+
scene = win.canvas.scene_
|
|
84
|
+
bg = _bg(win.theme)
|
|
85
|
+
|
|
86
|
+
def reset():
|
|
87
|
+
for did in list(win.ctx.topology.devices):
|
|
88
|
+
api.remove_device(did)
|
|
89
|
+
|
|
90
|
+
# --- welcome / canvas / run: a small topology ---------------------------
|
|
91
|
+
reset()
|
|
92
|
+
h = api.add_device("host", x=-40, y=120)["id"]
|
|
93
|
+
s = api.add_device("switch", x=180, y=120)["id"]
|
|
94
|
+
r = api.add_device("router", x=400, y=120)["id"]
|
|
95
|
+
db = api.add_device("database", x=620, y=20)["id"]
|
|
96
|
+
wa = api.add_device("web_app", x=620, y=220)["id"]
|
|
97
|
+
for a, b in [(h, s), (s, r), (r, db), (r, wa)]:
|
|
98
|
+
win.ctx.topology.add_link(a, b)
|
|
99
|
+
win.ctx.bus.link_added.emit(list(win.ctx.topology.links)[-1])
|
|
100
|
+
app.processEvents(); _clear_warnings(win)
|
|
101
|
+
_scene_shot(scene, "welcome", outdir, bg)
|
|
102
|
+
_scene_shot(scene, "canvas", outdir, bg)
|
|
103
|
+
for n in scene.nodes.values():
|
|
104
|
+
n.set_status("running")
|
|
105
|
+
app.processEvents()
|
|
106
|
+
_scene_shot(scene, "run", outdir, bg)
|
|
107
|
+
|
|
108
|
+
# --- X-ray / Wizard: ghost ring around a router -------------------------
|
|
109
|
+
reset()
|
|
110
|
+
rr = api.add_device("router", x=120, y=120)["id"]
|
|
111
|
+
app.processEvents(); _clear_warnings(win)
|
|
112
|
+
try:
|
|
113
|
+
win.canvas._lp_node = scene.nodes[rr]
|
|
114
|
+
win.canvas._fire_xray(); app.processEvents()
|
|
115
|
+
_scene_shot(scene, "wizard", outdir, bg, scale=2.4)
|
|
116
|
+
win.canvas.clear_xray()
|
|
117
|
+
except Exception as e:
|
|
118
|
+
print("wizard skipped:", e)
|
|
119
|
+
|
|
120
|
+
# --- cloud & VPCs: a VPC box with services ------------------------------
|
|
121
|
+
reset()
|
|
122
|
+
vpc = api.add_device("vpc", x=20, y=20)["id"]
|
|
123
|
+
win.ctx.topology.devices[vpc].properties["Name"] = "prod"
|
|
124
|
+
api.add_device("database", x=150, y=150); api.add_device("cache", x=150, y=250)
|
|
125
|
+
app.processEvents(); _clear_warnings(win)
|
|
126
|
+
scene._on_device_changed(vpc)
|
|
127
|
+
_scene_shot(scene, "cloud", outdir, bg)
|
|
128
|
+
|
|
129
|
+
# --- serverless: the Function inspector ---------------------------------
|
|
130
|
+
reset()
|
|
131
|
+
fid = api.add_device("function")["id"]
|
|
132
|
+
api.set_property(fid, "Handler", "custom")
|
|
133
|
+
win.ctx.select(fid); win.inspector.set_live_running(True); app.processEvents()
|
|
134
|
+
_widget_shot(win.inspector, "serverless", outdir, bg, 360, 560)
|
|
135
|
+
|
|
136
|
+
# --- cost meter: the dashboard strip ------------------------------------
|
|
137
|
+
from gini.domain.pricing import bill
|
|
138
|
+
for tk in ("k8s_cluster", "pod", "function", "database", "host"):
|
|
139
|
+
api.add_device(tk)
|
|
140
|
+
win.dashboard.set_estimate(bill(win.ctx.topology, win.ctx.settings.prices))
|
|
141
|
+
app.processEvents()
|
|
142
|
+
_widget_shot(win.dashboard, "cost", outdir, bg, 760, 120)
|
|
143
|
+
|
|
144
|
+
# --- live metrics -------------------------------------------------------
|
|
145
|
+
try:
|
|
146
|
+
import math
|
|
147
|
+
from gini.ui.live_metrics import LiveMetrics
|
|
148
|
+
lm = LiveMetrics(win.theme)
|
|
149
|
+
for i in range(60):
|
|
150
|
+
lm.push(40 + 30 * math.sin(i / 6), 300 + 120 * math.sin(i / 9),
|
|
151
|
+
50 + 40 * math.sin(i / 5), 8 + 5 * math.sin(i / 7))
|
|
152
|
+
_widget_shot(lm, "metrics", outdir, bg, 360, 300)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
print("metrics skipped:", e)
|
|
155
|
+
|
|
156
|
+
# --- ask GINI: the assistant panel --------------------------------------
|
|
157
|
+
try:
|
|
158
|
+
_widget_shot(win.assistant, "ai", outdir, bg, 380, 420)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
print("ai skipped:", e)
|
|
161
|
+
|
|
162
|
+
# --- settings: the tabbed dialog ----------------------------------------
|
|
163
|
+
from gini.ui.settings_dialog import SettingsDialog
|
|
164
|
+
dlg = SettingsDialog(win, win.ctx.settings)
|
|
165
|
+
_widget_shot(dlg, "settings", outdir, bg, 480, 360)
|
|
166
|
+
|
|
167
|
+
# --- router lab (best effort) -------------------------------------------
|
|
168
|
+
try:
|
|
169
|
+
reset()
|
|
170
|
+
rid = api.add_device("router")["id"]
|
|
171
|
+
win.ctx.select(rid); win._open_router_lab(rid)
|
|
172
|
+
_widget_shot(win._router_lab, "router", outdir, bg, 560, 420)
|
|
173
|
+
win._router_lab.close()
|
|
174
|
+
except Exception as e:
|
|
175
|
+
print("router skipped:", e)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def main() -> int:
|
|
179
|
+
app = QApplication.instance() or QApplication([])
|
|
180
|
+
from gini.ui.main_window import MainWindow
|
|
181
|
+
win = MainWindow(app)
|
|
182
|
+
for name in THEMES:
|
|
183
|
+
win.theme.set_theme(name)
|
|
184
|
+
app.processEvents()
|
|
185
|
+
outdir = OUT / theme_slug(name)
|
|
186
|
+
_generate(win, app, outdir)
|
|
187
|
+
print("theme done:", name, "->", outdir.name)
|
|
188
|
+
print("all done ->", OUT)
|
|
189
|
+
return 0
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if __name__ == "__main__":
|
|
193
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""image_report — what GINI actually ships, and what it costs.
|
|
3
|
+
|
|
4
|
+
Two things worth separating, because they get conflated and they have different fixes:
|
|
5
|
+
|
|
6
|
+
* IMAGE SIZE — hurts the FIRST run on a machine (build + pull), disk, and CI. On a warm Mac with
|
|
7
|
+
the layers already cached it costs comparatively little per boot.
|
|
8
|
+
* BOOT TIME — what a student actually feels. Driven by container create + whatever the entrypoint
|
|
9
|
+
does before it's useful (our shuttle, a database's initdb, k3s coming up), not by megabytes.
|
|
10
|
+
|
|
11
|
+
So this prints BOTH: the size of every image the topology uses, and the wall-clock time from
|
|
12
|
+
`docker compose up` to each service being up. Optimise what the numbers say, not what we assume.
|
|
13
|
+
|
|
14
|
+
python3 scripts/image_report.py # sizes of every GINI image present
|
|
15
|
+
python3 scripts/image_report.py --boot # …plus time a cold `up` of the running project
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
import subprocess
|
|
22
|
+
import time
|
|
23
|
+
|
|
24
|
+
# every image GINI can instantiate, and where it comes from
|
|
25
|
+
GINI_BUILT = {
|
|
26
|
+
"gini-machine": "Host / Machine — python:3.12-slim + the full book toolkit (apt)",
|
|
27
|
+
"gini-fabric": "the L2 fabric (all switches multiplexed) — python:3.12-slim",
|
|
28
|
+
"gini-grouter": "Router / OVS — debian:bookworm-slim + zig + gcc (single-stage)",
|
|
29
|
+
"gini-pox": "SDN controller — python:3.9-slim + POX",
|
|
30
|
+
"gini-xv6": "Machine (xv6) — debian:bookworm-slim + riscv toolchain + qemu (single-stage)",
|
|
31
|
+
"gini-faas": "serverless runtime — python:3.12-slim + pika/nats/kafka",
|
|
32
|
+
"gini-cloudfabric": "telemetry agent — python:3.12-slim + psycopg2",
|
|
33
|
+
"gini-sg": "security group — alpine:3.20 + iptables ← the lean one",
|
|
34
|
+
}
|
|
35
|
+
PULLED = {
|
|
36
|
+
"postgres:16-alpine": "Database", "redis:7-alpine": "Cache", "nginx:alpine": "Load Balancer",
|
|
37
|
+
"nats:latest": "Messaging", "nginxdemos/hello:latest": "Web App", "registry:2": "Registry",
|
|
38
|
+
"traefik:v3.1": "API Gateway / Proxy", "minio/minio:latest": "Object Store",
|
|
39
|
+
"rabbitmq:3-management-alpine": "Queue", "mongo:7": "NoSQL",
|
|
40
|
+
"redpandadata/redpanda:latest": "Stream", "prom/prometheus:latest": "Metrics",
|
|
41
|
+
"grafana/grafana:latest": "Dashboard", "jaegertracing/all-in-one:latest": "Tracing",
|
|
42
|
+
"fortio/fortio:latest": "Load Generator", "rancher/k3s:v1.30.6-k3s1": "K8s Cluster",
|
|
43
|
+
"gcr.io/cadvisor/cadvisor:v0.49.1": "container metrics",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def sh(cmd, cwd=None):
|
|
48
|
+
try:
|
|
49
|
+
r = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=60)
|
|
50
|
+
return r.returncode, (r.stdout or "") + (r.stderr or "")
|
|
51
|
+
except Exception as e: # noqa: BLE001
|
|
52
|
+
return 127, str(e)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def sizes() -> dict[str, str]:
|
|
56
|
+
code, out = sh(["docker", "images", "--format", "{{.Repository}}:{{.Tag}}\t{{.Size}}"])
|
|
57
|
+
if code != 0:
|
|
58
|
+
return {}
|
|
59
|
+
got = {}
|
|
60
|
+
for line in out.splitlines():
|
|
61
|
+
if "\t" not in line:
|
|
62
|
+
continue
|
|
63
|
+
name, size = line.split("\t", 1)
|
|
64
|
+
got[name.strip()] = size.strip()
|
|
65
|
+
got.setdefault(name.split(":")[0].strip(), size.strip()) # also match untagged lookups
|
|
66
|
+
return got
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def main() -> int:
|
|
70
|
+
ap = argparse.ArgumentParser()
|
|
71
|
+
ap.add_argument("--boot", action="store_true", help="also time the running project's services")
|
|
72
|
+
a = ap.parse_args()
|
|
73
|
+
|
|
74
|
+
have = sizes()
|
|
75
|
+
if not have:
|
|
76
|
+
print("Docker isn't answering — is it running?")
|
|
77
|
+
return 1
|
|
78
|
+
|
|
79
|
+
def table(title, entries):
|
|
80
|
+
print(f"\n\033[1m{title}\033[0m")
|
|
81
|
+
missing = []
|
|
82
|
+
for img, what in entries.items():
|
|
83
|
+
size = have.get(img) or have.get(img.split(":")[0])
|
|
84
|
+
if size is None:
|
|
85
|
+
missing.append(img)
|
|
86
|
+
continue
|
|
87
|
+
print(f" {size:>9} {img:<34} {what}")
|
|
88
|
+
for img in missing:
|
|
89
|
+
print(f" {'—':>9} {img:<34} (not built/pulled here yet)")
|
|
90
|
+
|
|
91
|
+
table("BUILT BY GINI (docker build, on your machine)", GINI_BUILT)
|
|
92
|
+
table("PULLED FROM UPSTREAM", PULLED)
|
|
93
|
+
|
|
94
|
+
print("\n\033[1mNotes\033[0m")
|
|
95
|
+
print(" · gini-machine is instantiated ONCE PER HOST — it's both the fattest and the most")
|
|
96
|
+
print(" replicated image, so it's where any optimisation pays off the most.")
|
|
97
|
+
print(" · gini-grouter and gini-xv6 are SINGLE-STAGE: the compilers (zig/gcc, riscv toolchain,")
|
|
98
|
+
print(" qemu build deps) are still inside the shipped image. A multi-stage build drops them.")
|
|
99
|
+
print(" · ':latest' tags are not reproducible — two students can get different bytes.")
|
|
100
|
+
|
|
101
|
+
if a.boot:
|
|
102
|
+
code, out = sh(["docker", "compose", "ls", "--format", "json"])
|
|
103
|
+
rows = json.loads(out or "[]") if code == 0 else []
|
|
104
|
+
running = [r for r in rows if "running" in str(r.get("Status", "")).lower()]
|
|
105
|
+
if not running:
|
|
106
|
+
print("\n(no running lab to time — start one, then re-run with --boot)")
|
|
107
|
+
return 0
|
|
108
|
+
proj = running[0]["Name"]
|
|
109
|
+
wd = (running[0].get("ConfigFiles") or "").split(",")[0].rsplit("/", 1)[0]
|
|
110
|
+
print(f"\n\033[1mBOOT TIME — restarting '{proj}' to measure\033[0m")
|
|
111
|
+
sh(["docker", "compose", "-p", proj, "down"], cwd=wd)
|
|
112
|
+
t0 = time.time()
|
|
113
|
+
code, _ = sh(["docker", "compose", "-p", proj, "up", "-d"], cwd=wd)
|
|
114
|
+
dt = time.time() - t0
|
|
115
|
+
print(f" compose up returned in \033[1m{dt:.1f}s\033[0m (images already cached)")
|
|
116
|
+
print(" → if this is fast but the FIRST run on a fresh Mac is slow, the cost is image")
|
|
117
|
+
print(" build/pull, not boot: fix it with leaner images. If THIS is slow, the cost is")
|
|
118
|
+
print(" container startup, and leaner images will not help much.")
|
|
119
|
+
return 0
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if __name__ == "__main__":
|
|
123
|
+
raise SystemExit(main())
|