coding-os 0.3.2__py3-none-any.whl
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.
- adapters/claude/README.md +6 -0
- adapters/claude/_install_helpers/extract_stacks.py +43 -0
- adapters/claude/_install_helpers/update_mcp_json.py +75 -0
- adapters/claude/adapter.yaml +164 -0
- adapters/claude/hooks/README.md +40 -0
- adapters/claude/hooks/agent_memory_sync.py +131 -0
- adapters/claude/hooks/ensure-agent-memory-link.sh +36 -0
- adapters/claude/hooks/sync-agent-memory.sh +21 -0
- adapters/claude/install.sh +86 -0
- adapters/claude/sdk_dispatcher.py +871 -0
- adapters/claude/settings.local.template.json +31 -0
- adapters/claude/settings.template.json +808 -0
- adapters/claude/update_mcp_json.py +85 -0
- adapters/codex/adapter.yaml +254 -0
- adapters/codex/chat_provider.py +230 -0
- adapters/codex/commands/formula-f1.md +129 -0
- adapters/codex/commands/formula-f10.md +100 -0
- adapters/codex/commands/formula-f11.md +123 -0
- adapters/codex/commands/formula-f2.md +139 -0
- adapters/codex/commands/formula-f3.md +127 -0
- adapters/codex/commands/formula-f4.md +101 -0
- adapters/codex/commands/formula-f5.md +135 -0
- adapters/codex/commands/formula-f6.md +147 -0
- adapters/codex/commands/formula-f7.md +111 -0
- adapters/codex/commands/formula-f8.md +133 -0
- adapters/codex/commands/formula-f9.md +112 -0
- adapters/codex/enable_codex_hooks.py +94 -0
- adapters/codex/ensure_codex_mcp.py +124 -0
- adapters/codex/hooks/codex-merge-hook-output.py +72 -0
- adapters/codex/hooks/codex-normalize-edit.py +96 -0
- adapters/codex/hooks/codex-postedit-dispatch.sh +75 -0
- adapters/codex/hooks/codex-posttool-dispatch.sh +70 -0
- adapters/codex/hooks/codex-preedit-dispatch.sh +83 -0
- adapters/codex/hooks/codex-pretool-dispatch.sh +82 -0
- adapters/codex/hooks/codex-sessionend-dispatch.sh +20 -0
- adapters/codex/hooks/codex-sessionstart-dispatch.sh +68 -0
- adapters/codex/hooks/codex-stop-dispatch.sh +73 -0
- adapters/codex/hooks/codex-userpromptsubmit-dispatch.sh +74 -0
- adapters/codex/hooks.template.json +208 -0
- adapters/codex/install.sh +83 -0
- adapters/codex/sdk_dispatcher.py +449 -0
- board_os/__init__.py +39 -0
- board_os/_agent_runtime.py +256 -0
- board_os/config.py +421 -0
- board_os/git_coherence.py +107 -0
- board_os/hub_adapter_manifest.py +140 -0
- board_os/mcp_tools.py +3228 -0
- board_os/migration.py +166 -0
- board_os/parser.py +317 -0
- board_os/presence.py +156 -0
- board_os/sync.py +320 -0
- board_os/transition_gates.py +224 -0
- board_os/transition_gates_cli.py +272 -0
- board_os/transition_gates_validator.py +551 -0
- board_os/verify_suites.py +126 -0
- board_os/verify_suites_cli.py +328 -0
- board_os/workflow.py +967 -0
- cli/__init__.py +0 -0
- cli/_data_types.py +248 -0
- cli/_init_helpers.py +587 -0
- cli/_resources.py +100 -0
- cli/adapter_registry.py +239 -0
- cli/add_stack.py +315 -0
- cli/aggregator.py +438 -0
- cli/board_commands.py +1218 -0
- cli/brain_commands.py +255 -0
- cli/cognition.py +345 -0
- cli/config_composer.py +349 -0
- cli/core_version.py +41 -0
- cli/cron_commands.py +278 -0
- cli/db_reset.py +298 -0
- cli/doc_commands.py +111 -0
- cli/doctor.py +2953 -0
- cli/doctor_board.py +365 -0
- cli/doctor_extras.py +1121 -0
- cli/doctor_graph.py +608 -0
- cli/doctor_tokens.py +254 -0
- cli/graph_commands.py +1265 -0
- cli/hook_renderer.py +393 -0
- cli/hub_commands.py +580 -0
- cli/list_adapters.py +79 -0
- cli/list_stacks.py +105 -0
- cli/logs_commands.py +89 -0
- cli/main.py +3070 -0
- cli/materialize_file.py +65 -0
- cli/mcp_start.py +153 -0
- cli/module_commands.py +513 -0
- cli/pr_commands.py +2024 -0
- cli/preset_commands.py +126 -0
- cli/preset_registry.py +171 -0
- cli/project_overrides.py +119 -0
- cli/registry.py +365 -0
- cli/remove_stack.py +492 -0
- cli/renderer.py +620 -0
- cli/setup.py +464 -0
- cli/skill_commands.py +689 -0
- cli/skill_registry.py +235 -0
- cli/skills_list.py +332 -0
- cli/stack_lint.py +351 -0
- cli/stack_registry.py +688 -0
- cli/subsystems.py +335 -0
- cli/sync_all.py +310 -0
- cli/tail_command.py +410 -0
- cli/update.py +608 -0
- cli/verify_since_edit.py +439 -0
- coding_os-0.3.2.dist-info/METADATA +508 -0
- coding_os-0.3.2.dist-info/RECORD +1304 -0
- coding_os-0.3.2.dist-info/WHEEL +5 -0
- coding_os-0.3.2.dist-info/entry_points.txt +5 -0
- coding_os-0.3.2.dist-info/licenses/LICENSE +201 -0
- coding_os-0.3.2.dist-info/top_level.txt +10 -0
- core/__init__.py +0 -0
- core/board_os/__init__.py +39 -0
- core/board_os/_agent_runtime.py +256 -0
- core/board_os/config.py +421 -0
- core/board_os/git_coherence.py +107 -0
- core/board_os/hub_adapter_manifest.py +140 -0
- core/board_os/mcp_tools.py +3228 -0
- core/board_os/migration.py +166 -0
- core/board_os/parser.py +317 -0
- core/board_os/presence.py +156 -0
- core/board_os/sync.py +320 -0
- core/board_os/transition-gates.yaml +176 -0
- core/board_os/transition_gates.py +224 -0
- core/board_os/transition_gates_cli.py +272 -0
- core/board_os/transition_gates_validator.py +551 -0
- core/board_os/verify-suites.yaml +113 -0
- core/board_os/verify_suites.py +126 -0
- core/board_os/verify_suites_cli.py +328 -0
- core/board_os/workflow.py +967 -0
- core/commands/board.md +27 -0
- core/commands/classify.md +23 -0
- core/commands/compose.md +23 -0
- core/commands/daily.md +31 -0
- core/commands/diagnose.md +7 -0
- core/commands/memory-search.md +23 -0
- core/commands/new-project.md +33 -0
- core/commands/retro.md +38 -0
- core/commands/review.md +14 -0
- core/commands/task.md +17 -0
- core/commands/verify.md +34 -0
- core/docs/thinking_os-final-edition.md +1449 -0
- core/doctor-config.yaml +74 -0
- core/graph_os/__init__.py +29 -0
- core/graph_os/backend.py +233 -0
- core/graph_os/backends/__init__.py +13 -0
- core/graph_os/backends/sqlite_backend.py +1053 -0
- core/graph_os/bench/__init__.py +17 -0
- core/graph_os/bench/fixtures.py +56 -0
- core/graph_os/bench/harness.py +95 -0
- core/graph_os/bench/persian_precision.py +142 -0
- core/graph_os/bench/scale_500k.py +120 -0
- core/graph_os/bench/token_cost.py +170 -0
- core/graph_os/bench/viewer_fps.py +110 -0
- core/graph_os/communities.py +410 -0
- core/graph_os/enterprise.py +218 -0
- core/graph_os/entry_points.py +226 -0
- core/graph_os/extractors/__init__.py +25 -0
- core/graph_os/extractors/code_generic.py +914 -0
- core/graph_os/extractors/code_go.py +1422 -0
- core/graph_os/extractors/code_json.py +340 -0
- core/graph_os/extractors/code_php.py +979 -0
- core/graph_os/extractors/code_python.py +1454 -0
- core/graph_os/extractors/code_shell.py +538 -0
- core/graph_os/extractors/code_toml.py +302 -0
- core/graph_os/extractors/code_ts.py +1665 -0
- core/graph_os/extractors/code_yaml.py +394 -0
- core/graph_os/extractors/contracts.py +1592 -0
- core/graph_os/extractors/md_links.py +890 -0
- core/graph_os/extractors/task_deps.py +345 -0
- core/graph_os/groups/__init__.py +22 -0
- core/graph_os/groups/cross_repo.py +156 -0
- core/graph_os/groups/manifest.py +141 -0
- core/graph_os/ingest/__init__.py +19 -0
- core/graph_os/ingest/base.py +306 -0
- core/graph_os/ingest/github.py +112 -0
- core/graph_os/ingest/zip.py +95 -0
- core/graph_os/toolchain.py +393 -0
- core/graph_os/tools/__init__.py +9 -0
- core/graph_os/tools/graph.py +5573 -0
- core/graph_os/tools/reindex_dispatch.py +730 -0
- core/graph_os/tree_sitter_overlay.py +235 -0
- core/graph_os/types.py +252 -0
- core/graph_os/vec_index.py +277 -0
- core/graph_os/viewer/__init__.py +12 -0
- core/graph_os/viewer/exporter.py +93 -0
- core/graph_os/viewer/template.py +189 -0
- core/hooks/_helpers/_paths.py +40 -0
- core/hooks/_helpers/advance_role.py +72 -0
- core/hooks/_helpers/auto_compose.py +228 -0
- core/hooks/_helpers/auto_validate_lessons.py +55 -0
- core/hooks/_helpers/branch_guard_check.py +796 -0
- core/hooks/_helpers/check_commit_message.py +108 -0
- core/hooks/_helpers/check_dangerous_rm.py +80 -0
- core/hooks/_helpers/check_git_bypass.py +154 -0
- core/hooks/_helpers/check_git_destructive.py +77 -0
- core/hooks/_helpers/check_settings_write.py +97 -0
- core/hooks/_helpers/consume_override.py +51 -0
- core/hooks/_helpers/context_budget.py +77 -0
- core/hooks/_helpers/cos_say_json.py +103 -0
- core/hooks/_helpers/destructive_edit_check.py +163 -0
- core/hooks/_helpers/detect_status_transition.py +82 -0
- core/hooks/_helpers/digest_regen.py +56 -0
- core/hooks/_helpers/doc_sync_check.py +498 -0
- core/hooks/_helpers/drain_embedding_outbox.py +52 -0
- core/hooks/_helpers/extract_additional_context.py +51 -0
- core/hooks/_helpers/extract_commit_msg_arg.py +74 -0
- core/hooks/_helpers/git_command_parse.py +424 -0
- core/hooks/_helpers/git_settings_fields.py +47 -0
- core/hooks/_helpers/graph_context_match.py +37 -0
- core/hooks/_helpers/graph_marker_check.py +70 -0
- core/hooks/_helpers/jit_recall.py +56 -0
- core/hooks/_helpers/json_field.py +41 -0
- core/hooks/_helpers/narrative_signal.py +59 -0
- core/hooks/_helpers/observation_count.py +31 -0
- core/hooks/_helpers/pre_commit_batch.py +177 -0
- core/hooks/_helpers/pre_commit_fake_input.py +42 -0
- core/hooks/_helpers/presence_gc.py +102 -0
- core/hooks/_helpers/presence_write.py +167 -0
- core/hooks/_helpers/recover_indirect.py +35 -0
- core/hooks/_helpers/routing_evolution.py +104 -0
- core/hooks/_helpers/session_recap.py +72 -0
- core/hooks/_helpers/skill_primer.py +229 -0
- core/hooks/_helpers/task_sync.py +59 -0
- core/hooks/_helpers/tool_failure_capture.py +147 -0
- core/hooks/_helpers/trajectory_autosnap.py +278 -0
- core/hooks/_helpers/trajectory_startup.py +62 -0
- core/hooks/_helpers/turn_summary.py +82 -0
- core/hooks/_helpers/validate_task_frontmatter.py +98 -0
- core/hooks/_helpers/wip_limit_check.py +103 -0
- core/hooks/_helpers/wip_lines.py +53 -0
- core/hooks/_helpers/work_log_append.py +89 -0
- core/hooks/_helpers/wrap_dispatch_output.py +82 -0
- core/hooks/advance-role.sh +48 -0
- core/hooks/agent-presence.sh +179 -0
- core/hooks/auto-brain-decay.sh +184 -0
- core/hooks/auto-compose-roles.sh +83 -0
- core/hooks/auto-graph-reconcile-shell.sh +119 -0
- core/hooks/auto-regen-doc-index.sh +120 -0
- core/hooks/auto-reindex-docs.sh +130 -0
- core/hooks/auto-task-sync.sh +56 -0
- core/hooks/auto-trace-rotate.sh +88 -0
- core/hooks/block-bad-patterns.sh +212 -0
- core/hooks/block-dangerous-commands.sh +182 -0
- core/hooks/block-hardcoded-literals.sh +90 -0
- core/hooks/block-migration-conflict.sh +114 -0
- core/hooks/block-protected-files.sh +129 -0
- core/hooks/block-secrets.sh +185 -0
- core/hooks/block-shared-tree-edit.sh +75 -0
- core/hooks/block-uv-heredoc.sh +78 -0
- core/hooks/branch-guard.sh +122 -0
- core/hooks/capture-observation.sh +76 -0
- core/hooks/capture-tool-failure.sh +24 -0
- core/hooks/capture-work-log.sh +89 -0
- core/hooks/check-agents-md-refs.sh +75 -0
- core/hooks/check-agents-md-size.sh +49 -0
- core/hooks/check-capture-worked.sh +148 -0
- core/hooks/check-doc-size.sh +61 -0
- core/hooks/check-mcp-extras.sh +92 -0
- core/hooks/check-state.sh +87 -0
- core/hooks/classify-task-mode.sh +103 -0
- core/hooks/cos-env.sh +1301 -0
- core/hooks/drain-embedding-outbox.sh +24 -0
- core/hooks/enforce-anti-ambiguity.sh +74 -0
- core/hooks/enforce-commit-message.sh +73 -0
- core/hooks/enforce-doc-anchor.sh +224 -0
- core/hooks/enforce-doc-sync.sh +206 -0
- core/hooks/enforce-graph-context.sh +89 -0
- core/hooks/enforce-graph-first-read.sh +94 -0
- core/hooks/enforce-memory-check.sh +128 -0
- core/hooks/enforce-rename-plan.sh +78 -0
- core/hooks/enforce-scaffold-boundary.sh +68 -0
- core/hooks/enforce-skill.sh +125 -0
- core/hooks/enforce-task-body.sh +52 -0
- core/hooks/enforce-task-start.sh +81 -0
- core/hooks/enforce-task-transition.sh +75 -0
- core/hooks/enforce-template.sh +143 -0
- core/hooks/enforce-verify.sh +112 -0
- core/hooks/enforce-wip-limit.sh +43 -0
- core/hooks/enforce-zoom.sh +69 -0
- core/hooks/ensure-hub-up.sh +67 -0
- core/hooks/inject-mcp-caller-session.sh +70 -0
- core/hooks/jit-recall.sh +65 -0
- core/hooks/link-commit-to-task.sh +143 -0
- core/hooks/lint-task.sh +40 -0
- core/hooks/nudge-docs-first.sh +71 -0
- core/hooks/nudge-git-mode.sh +29 -0
- core/hooks/nudge-graph-os.sh +118 -0
- core/hooks/nudge-learn-narrative.sh +36 -0
- core/hooks/nudge-model-routing.sh +32 -0
- core/hooks/nudge-reentry.sh +101 -0
- core/hooks/nudge-reuse-first.sh +68 -0
- core/hooks/nudge-task-discovery.sh +81 -0
- core/hooks/nudge-thinking-os.sh +109 -0
- core/hooks/pr-reap.sh +23 -0
- core/hooks/reclaim-sweep.sh +58 -0
- core/hooks/record-verify-auto.sh +77 -0
- core/hooks/record-verify.sh +74 -0
- core/hooks/regen-reminder.sh +104 -0
- core/hooks/registry.yaml +1262 -0
- core/hooks/remind-daily.sh +27 -0
- core/hooks/remind-dogfood.sh +70 -0
- core/hooks/remind-learn-validate.sh +94 -0
- core/hooks/rules-primer.sh +50 -0
- core/hooks/search-enforce-inventory.sh +108 -0
- core/hooks/search-verify-remaining.sh +132 -0
- core/hooks/session-context.sh +729 -0
- core/hooks/session-end.sh +145 -0
- core/hooks/session-skill-primer.sh +43 -0
- core/hooks/snapshot-transcript.sh +56 -0
- core/hooks/sync-task-current.sh +85 -0
- core/hooks/test-first-reminder.sh +120 -0
- core/hooks/test-governor.sh +173 -0
- core/hooks/thinking_os-gate.sh +52 -0
- core/hooks/track-backtrack.sh +35 -0
- core/hooks/track-discovery.sh +121 -0
- core/hooks/track-skill.sh +53 -0
- core/hooks/validate-task-frontmatter.sh +49 -0
- core/hooks/verify-rename-callers.sh +119 -0
- core/hooks/warn-abandoned-task.sh +99 -0
- core/hooks/warn-destructive-edit.sh +64 -0
- core/hooks/warn-diff-size.sh +43 -0
- core/hooks/warn-graph-empty.sh +81 -0
- core/hooks/warn-mcp-down.sh +190 -0
- core/hooks/write-state.sh +55 -0
- core/logging_os/__init__.py +33 -0
- core/logging_os/api.py +127 -0
- core/logging_os/bridge.py +80 -0
- core/logging_os/config.py +172 -0
- core/logging_os/fingerprint.py +25 -0
- core/logging_os/redact.py +53 -0
- core/logging_os/render.py +83 -0
- core/logging_os/sinks.py +164 -0
- core/rules/anti-overengineering.md +44 -0
- core/rules/api-contract-discipline.md +41 -0
- core/rules/dimension-registry.md +155 -0
- core/rules/git-workflow.md +57 -0
- core/rules/memory.md +46 -0
- core/rules/model-routing.md +22 -0
- core/rules/skill-enforcement.md +75 -0
- core/rules/test-discipline.md +38 -0
- core/rules/thinking_os.md +48 -0
- core/rules/transparency-banner.md +37 -0
- core/runtime_paths.yaml +36 -0
- core/scaffold_manifest.json +14430 -0
- core/scheduled/__init__.py +0 -0
- core/scheduled/_activity.py +126 -0
- core/scheduled/_state.py +113 -0
- core/scheduled/config.py +86 -0
- core/scheduled/dep_reconcile.py +135 -0
- core/scheduled/error_sweep.py +137 -0
- core/scheduled/nightly.py +930 -0
- core/scheduled/responsive_extract.py +65 -0
- core/schemas/adapter.schema.json +269 -0
- core/schemas/preset.schema.json +50 -0
- core/schemas/skill.schema.json +81 -0
- core/schemas/stack.schema.json +404 -0
- core/scripts/_lib.sh +9 -0
- core/scripts/docs-lint.sh +228 -0
- core/scripts/docs-nav-fix.sh +133 -0
- core/scripts/docs-staleness-check.sh +154 -0
- core/scripts/install-adapter.sh +266 -0
- core/scripts/link-stack-skills.sh +52 -0
- core/scripts/log-latest.sh +106 -0
- core/scripts/log-search.sh +89 -0
- core/scripts/log-write.sh +134 -0
- core/scripts/ref-resolve.sh +71 -0
- core/skills/a11y/SKILL.md +305 -0
- core/skills/a11y/assets/a11y-checklist.md +137 -0
- core/skills/a11y/references/aria-and-focus.md +247 -0
- core/skills/a11y/references/rn-accessibility.md +343 -0
- core/skills/a11y/references/screen-reader-testing.md +190 -0
- core/skills/agent-memory/SKILL.md +191 -0
- core/skills/agent-memory/assets/memory-checklist.md +21 -0
- core/skills/agent-memory/references/memory-recipes.md +57 -0
- core/skills/api-design/SKILL.md +232 -0
- core/skills/api-design/assets/api-design-checklist.md +110 -0
- core/skills/api-design/references/error-envelope.md +381 -0
- core/skills/api-design/references/idempotency-pagination.md +312 -0
- core/skills/api-design/references/rest-contracts.md +426 -0
- core/skills/auth-patterns/SKILL.md +352 -0
- core/skills/auth-patterns/assets/auth-checklist.md +118 -0
- core/skills/auth-patterns/references/jwt-and-service-tokens.md +343 -0
- core/skills/auth-patterns/references/passkeys-2fa.md +289 -0
- core/skills/auth-patterns/references/sessions-vs-jwt.md +230 -0
- core/skills/auth-patterns/scripts/cookie-flag-check.py +146 -0
- core/skills/backend-fundamentals/SKILL.md +238 -0
- core/skills/backend-fundamentals/assets/backend-checklist.md +27 -0
- core/skills/backend-fundamentals/references/backend-patterns.md +56 -0
- core/skills/backend-fundamentals/scripts/check_layering.py +83 -0
- core/skills/clean-code/SKILL.md +642 -0
- core/skills/clean-code/scripts/audit-fail-closed.py +167 -0
- core/skills/codebase-explorer/SKILL.md +89 -0
- core/skills/codebase-explorer/assets/reading-checklist.md +24 -0
- core/skills/codebase-explorer/references/reading-strategies.md +52 -0
- core/skills/codebase-explorer/scripts/outline.py +99 -0
- core/skills/db-design/SKILL.md +327 -0
- core/skills/db-design/assets/migration-template.sql +49 -0
- core/skills/db-design/references/migration-discipline.md +290 -0
- core/skills/db-design/references/postgres-patterns.md +340 -0
- core/skills/db-design/scripts/migration-safety.sh +150 -0
- core/skills/deployment-cicd/SKILL.md +260 -0
- core/skills/deployment-cicd/assets/deploy-checklist.md +26 -0
- core/skills/deployment-cicd/references/pipeline-and-release.md +54 -0
- core/skills/deployment-cicd/scripts/lint_workflow.py +79 -0
- core/skills/docker/SKILL.md +114 -0
- core/skills/docker/assets/dockerfile-checklist.md +31 -0
- core/skills/docker/references/compose-patterns.md +66 -0
- core/skills/docker/references/dockerfile-optimization.md +64 -0
- core/skills/docker/scripts/lint_dockerfile.sh +48 -0
- core/skills/docker/versions.json +16 -0
- core/skills/end-to-end-testing/SKILL.md +101 -0
- core/skills/end-to-end-testing/assets/e2e-checklist.md +23 -0
- core/skills/end-to-end-testing/references/maestro.md +63 -0
- core/skills/end-to-end-testing/references/playwright.md +68 -0
- core/skills/end-to-end-testing/scripts/lint_e2e.py +88 -0
- core/skills/end-to-end-testing/versions.json +16 -0
- core/skills/frontend-design/SKILL.md +76 -0
- core/skills/frontend-design/assets/design-checklist.md +29 -0
- core/skills/frontend-design/references/design-principles.md +65 -0
- core/skills/frontend-design/scripts/check_contrast.py +89 -0
- core/skills/frontend-fundamentals/SKILL.md +213 -0
- core/skills/frontend-fundamentals/assets/frontend-checklist.md +25 -0
- core/skills/frontend-fundamentals/references/rendering-and-state.md +66 -0
- core/skills/frontend-fundamentals/scripts/check_frontend.py +86 -0
- core/skills/graph-explorer/SKILL.md +215 -0
- core/skills/graph-explorer/scripts/explain-impact.sh +64 -0
- core/skills/graphql/SKILL.md +187 -0
- core/skills/grpc-microservices/SKILL.md +174 -0
- core/skills/hexagonal-architecture/SKILL.md +199 -0
- core/skills/hexagonal-architecture/assets/folder-scaffold.md +233 -0
- core/skills/hexagonal-architecture/references/anti-patterns.md +129 -0
- core/skills/hexagonal-architecture/references/go-fiber-layout.md +429 -0
- core/skills/hexagonal-architecture/references/python-fastapi-layout.md +453 -0
- core/skills/hexagonal-architecture/references/react-native-layout.md +428 -0
- core/skills/i18n/SKILL.md +126 -0
- core/skills/incident-response/SKILL.md +225 -0
- core/skills/incident-response/assets/incident-checklist.md +29 -0
- core/skills/incident-response/references/severity-and-runbook.md +53 -0
- core/skills/incident-response/scripts/classify_severity.py +86 -0
- core/skills/linux-sysadmin/SKILL.md +115 -0
- core/skills/linux-sysadmin/assets/hardening-checklist.md +29 -0
- core/skills/linux-sysadmin/references/ssh-hardening.md +62 -0
- core/skills/linux-sysadmin/references/systemd-and-services.md +77 -0
- core/skills/linux-sysadmin/scripts/triage.sh +50 -0
- core/skills/linux-sysadmin/versions.json +17 -0
- core/skills/llm-patterns/SKILL.md +410 -0
- core/skills/llm-patterns/assets/llm-feature-checklist.md +26 -0
- core/skills/llm-patterns/references/rag-and-evals.md +59 -0
- core/skills/llm-patterns/scripts/estimate_tokens.py +75 -0
- core/skills/messaging-queues/SKILL.md +142 -0
- core/skills/mobile-fundamentals/SKILL.md +406 -0
- core/skills/mobile-fundamentals/assets/mobile-launch-checklist.md +130 -0
- core/skills/mobile-fundamentals/references/navigation-and-deep-links.md +337 -0
- core/skills/mobile-fundamentals/references/offline-sync.md +339 -0
- core/skills/node-backend/SKILL.md +114 -0
- core/skills/node-backend/assets/node-checklist.md +25 -0
- core/skills/node-backend/references/async-and-errors.md +67 -0
- core/skills/node-backend/references/event-loop.md +65 -0
- core/skills/node-backend/scripts/check_package.py +78 -0
- core/skills/node-backend/versions.json +17 -0
- core/skills/observability/SKILL.md +289 -0
- core/skills/observability/assets/observability-checklist.md +27 -0
- core/skills/observability/references/instrumentation.md +57 -0
- core/skills/observability/scripts/lint_logging.py +77 -0
- core/skills/payments/SKILL.md +102 -0
- core/skills/performance/SKILL.md +305 -0
- core/skills/performance/assets/perf-checklist.md +143 -0
- core/skills/performance/references/mobile-performance.md +249 -0
- core/skills/performance/references/web-vitals.md +209 -0
- core/skills/php/SKILL.md +116 -0
- core/skills/php/assets/php-checklist.md +26 -0
- core/skills/php/references/modern-php.md +64 -0
- core/skills/php/references/security.md +72 -0
- core/skills/php/scripts/scan_php_smells.py +99 -0
- core/skills/php/versions.json +9 -0
- core/skills/pr-mode-driver/SKILL.md +65 -0
- core/skills/realtime-websockets/SKILL.md +152 -0
- core/skills/redis/SKILL.md +105 -0
- core/skills/redis/assets/redis-checklist.md +27 -0
- core/skills/redis/references/operations.md +66 -0
- core/skills/redis/references/patterns.md +62 -0
- core/skills/redis/scripts/analyze_info.py +101 -0
- core/skills/redis/versions.json +9 -0
- core/skills/search/SKILL.md +91 -0
- core/skills/search/references/grep.md +76 -0
- core/skills/search/scripts/verify-count.sh +73 -0
- core/skills/search-infra/SKILL.md +109 -0
- core/skills/security-mobile/SKILL.md +394 -0
- core/skills/security-mobile/assets/mobile-security-checklist.md +117 -0
- core/skills/security-mobile/references/masvs-l1-checklist.md +127 -0
- core/skills/security-web/SKILL.md +217 -0
- core/skills/security-web/assets/security-web-checklist.md +167 -0
- core/skills/security-web/references/owasp-top-10.md +551 -0
- core/skills/security-web/references/supply-chain.md +179 -0
- core/skills/security-web/scripts/csp-check.sh +153 -0
- core/skills/shell-scripting/SKILL.md +128 -0
- core/skills/shell-scripting/assets/script-checklist.md +33 -0
- core/skills/shell-scripting/references/argument-parsing.md +84 -0
- core/skills/shell-scripting/references/bash-robustness.md +78 -0
- core/skills/shell-scripting/scripts/lint_script.sh +53 -0
- core/skills/shell-scripting/scripts/new_script.py +131 -0
- core/skills/shell-scripting/versions.json +23 -0
- core/skills/sql-authoring/SKILL.md +104 -0
- core/skills/sql-authoring/assets/query-review-checklist.md +26 -0
- core/skills/sql-authoring/references/query-patterns.md +89 -0
- core/skills/sql-authoring/references/reading-explain.md +52 -0
- core/skills/sql-authoring/scripts/analyze_plan.py +100 -0
- core/skills/sql-authoring/versions.json +17 -0
- core/skills/state-management/SKILL.md +428 -0
- core/skills/state-management/references/tanstack-query-recipes.md +301 -0
- core/skills/state-management/references/zustand-recipes.md +364 -0
- core/skills/supabase/SKILL.md +108 -0
- core/skills/supabase/assets/supabase-checklist.md +26 -0
- core/skills/supabase/references/realtime-and-storage.md +55 -0
- core/skills/supabase/references/rls-and-auth.md +65 -0
- core/skills/supabase/scripts/check_rls.py +88 -0
- core/skills/supabase/versions.json +9 -0
- core/skills/task-driver/SKILL.md +272 -0
- core/skills/task-driver/scripts/task-lint.sh +163 -0
- core/skills/technical-writing/SKILL.md +85 -0
- core/skills/technical-writing/assets/doc-checklist.md +29 -0
- core/skills/technical-writing/references/doc-anatomy.md +53 -0
- core/skills/technical-writing/references/writing-craft.md +59 -0
- core/skills/technical-writing/scripts/new_doc.py +81 -0
- core/skills/terraform-k8s/SKILL.md +133 -0
- core/skills/testing-strategy/SKILL.md +266 -0
- core/skills/testing-strategy/assets/test-review-checklist.md +25 -0
- core/skills/testing-strategy/references/test-types.md +52 -0
- core/skills/testing-strategy/scripts/coverage_gate.py +79 -0
- core/skills/thinking_os/SKILL.md +288 -0
- core/skills/thinking_os/scripts/classify.sh +122 -0
- core/skills/typescript/SKILL.md +110 -0
- core/skills/typescript/assets/typescript-checklist.md +24 -0
- core/skills/typescript/references/strictness.md +53 -0
- core/skills/typescript/references/type-system.md +86 -0
- core/skills/typescript/scripts/check_tsconfig.py +92 -0
- core/skills/typescript/versions.json +9 -0
- core/subsystems.yaml +202 -0
- core/thinking_os/__init__.py +1 -0
- core/thinking_os/_agent_markers.py +32 -0
- core/thinking_os/agents/README.md +71 -0
- core/thinking_os/agents/analyst.md +139 -0
- core/thinking_os/agents/architect.md +127 -0
- core/thinking_os/agents/debugger.md +111 -0
- core/thinking_os/agents/deployer.md +112 -0
- core/thinking_os/agents/distiller.md +28 -0
- core/thinking_os/agents/documenter.md +101 -0
- core/thinking_os/agents/implementer.md +135 -0
- core/thinking_os/agents/internal/session_observer.md +39 -0
- core/thinking_os/agents/observer.md +100 -0
- core/thinking_os/agents/onboarder.md +81 -0
- core/thinking_os/agents/refactorer.md +123 -0
- core/thinking_os/agents/repairer.md +47 -0
- core/thinking_os/agents/researcher.md +129 -0
- core/thinking_os/agents/reviewer.md +147 -0
- core/thinking_os/agents/security_auditor.md +133 -0
- core/thinking_os/background.py +405 -0
- core/thinking_os/bootstrap_outcomes.py +200 -0
- core/thinking_os/budget.py +302 -0
- core/thinking_os/capture.py +495 -0
- core/thinking_os/cognition.py +516 -0
- core/thinking_os/cognition_schemas.py +517 -0
- core/thinking_os/compress.py +192 -0
- core/thinking_os/concepts.py +233 -0
- core/thinking_os/dashboard.py +159 -0
- core/thinking_os/database.py +2883 -0
- core/thinking_os/decay.py +393 -0
- core/thinking_os/digest.py +295 -0
- core/thinking_os/dispatcher.py +192 -0
- core/thinking_os/dispatcher_helpers.py +48 -0
- core/thinking_os/dispatchers/__init__.py +3 -0
- core/thinking_os/dispatchers/default.py +47 -0
- core/thinking_os/distill.py +192 -0
- core/thinking_os/doc_indexer.py +905 -0
- core/thinking_os/embeddings.py +943 -0
- core/thinking_os/formula_composer.py +556 -0
- core/thinking_os/gate_marker.py +75 -0
- core/thinking_os/graph.py +296 -0
- core/thinking_os/graph_indexer.py +360 -0
- core/thinking_os/health_check.py +517 -0
- core/thinking_os/impact.py +119 -0
- core/thinking_os/memory_gc.py +356 -0
- core/thinking_os/migrator_embeddings.py +318 -0
- core/thinking_os/precision.py +194 -0
- core/thinking_os/presets/registry.yaml +127 -0
- core/thinking_os/record_outcome.py +399 -0
- core/thinking_os/repair.py +105 -0
- core/thinking_os/retrieval_quality.py +239 -0
- core/thinking_os/roles/analyst.yaml +83 -0
- core/thinking_os/roles/architect.yaml +88 -0
- core/thinking_os/roles/debugger.yaml +71 -0
- core/thinking_os/roles/deployer.yaml +71 -0
- core/thinking_os/roles/documenter.yaml +72 -0
- core/thinking_os/roles/implementer.yaml +83 -0
- core/thinking_os/roles/observer.yaml +70 -0
- core/thinking_os/roles/refactorer.yaml +71 -0
- core/thinking_os/roles/researcher.yaml +72 -0
- core/thinking_os/roles/reviewer.yaml +79 -0
- core/thinking_os/roles/security_auditor.yaml +83 -0
- core/thinking_os/roles_state.py +168 -0
- core/thinking_os/sanitizer.py +320 -0
- core/thinking_os/server.py +3160 -0
- core/thinking_os/session_enrich.py +272 -0
- core/thinking_os/session_observe_worker.py +111 -0
- core/thinking_os/session_startup.py +74 -0
- core/thinking_os/session_summary.py +245 -0
- core/thinking_os/situations/registry.yaml +99 -0
- core/thinking_os/task_analyzer.py +462 -0
- core/thinking_os/task_parser.py +342 -0
- core/thinking_os/task_sync.py +73 -0
- core/thinking_os/tools/__init__.py +6 -0
- core/thinking_os/tools/_shared.py +947 -0
- core/thinking_os/tools/cognition.py +1867 -0
- core/thinking_os/tools/docs.py +770 -0
- core/thinking_os/tools/learning.py +2078 -0
- core/thinking_os/tools/logs.py +79 -0
- core/thinking_os/tools/memory.py +840 -0
- core/thinking_os/tools/metrics.py +200 -0
- core/thinking_os/tools/retrieve.py +415 -0
- core/thinking_os/tools/routing.py +658 -0
- core/thinking_os/tools/tasks.py +449 -0
- core/thinking_os/tools/trajectory.py +181 -0
- core/thinking_os/tracing.py +235 -0
- core/web/__init__.py +5 -0
- core/web/_cache.py +118 -0
- core/web/_deps.py +56 -0
- core/web/_envelope.py +85 -0
- core/web/_project_context.py +140 -0
- core/web/chat_providers.py +108 -0
- core/web/init_jobs.py +216 -0
- core/web/routes/__init__.py +25 -0
- core/web/routes/_bounded_read.py +76 -0
- core/web/routes/board.py +1089 -0
- core/web/routes/cognition.py +1838 -0
- core/web/routes/config.py +635 -0
- core/web/routes/graph.py +513 -0
- core/web/routes/health.py +180 -0
- core/web/routes/hooks.py +288 -0
- core/web/routes/hub.py +1219 -0
- core/web/routes/logs.py +374 -0
- core/web/routes/metrics.py +43 -0
- core/web/routes/observability.py +400 -0
- core/web/routes/patterns.py +227 -0
- core/web/routes/presence.py +609 -0
- core/web/routes/roles.py +446 -0
- core/web/routes/scheduled.py +261 -0
- core/web/routes/search.py +238 -0
- core/web/routes/sessions.py +220 -0
- core/web/routes/settings.py +363 -0
- core/web/routes/stream.py +547 -0
- core/web/security.py +157 -0
- core/web/server.py +283 -0
- graph_os/__init__.py +29 -0
- graph_os/backend.py +233 -0
- graph_os/backends/__init__.py +13 -0
- graph_os/backends/sqlite_backend.py +1053 -0
- graph_os/communities.py +410 -0
- graph_os/enterprise.py +218 -0
- graph_os/entry_points.py +226 -0
- graph_os/extractors/__init__.py +25 -0
- graph_os/extractors/code_generic.py +914 -0
- graph_os/extractors/code_go.py +1422 -0
- graph_os/extractors/code_json.py +340 -0
- graph_os/extractors/code_php.py +979 -0
- graph_os/extractors/code_python.py +1454 -0
- graph_os/extractors/code_shell.py +538 -0
- graph_os/extractors/code_toml.py +302 -0
- graph_os/extractors/code_ts.py +1665 -0
- graph_os/extractors/code_yaml.py +394 -0
- graph_os/extractors/contracts.py +1592 -0
- graph_os/extractors/md_links.py +890 -0
- graph_os/extractors/task_deps.py +345 -0
- graph_os/groups/__init__.py +22 -0
- graph_os/groups/cross_repo.py +156 -0
- graph_os/groups/manifest.py +141 -0
- graph_os/ingest/__init__.py +19 -0
- graph_os/ingest/base.py +306 -0
- graph_os/ingest/github.py +112 -0
- graph_os/ingest/zip.py +95 -0
- graph_os/toolchain.py +393 -0
- graph_os/tools/__init__.py +9 -0
- graph_os/tools/graph.py +5573 -0
- graph_os/tools/reindex_dispatch.py +730 -0
- graph_os/tree_sitter_overlay.py +235 -0
- graph_os/types.py +252 -0
- graph_os/vec_index.py +277 -0
- graph_os/viewer/__init__.py +12 -0
- graph_os/viewer/exporter.py +93 -0
- graph_os/viewer/template.py +189 -0
- scheduled/__init__.py +0 -0
- scheduled/_activity.py +126 -0
- scheduled/_state.py +113 -0
- scheduled/config.py +86 -0
- scheduled/dep_reconcile.py +135 -0
- scheduled/error_sweep.py +137 -0
- scheduled/nightly.py +930 -0
- scheduled/responsive_extract.py +65 -0
- scripts/__init__.py +4 -0
- scripts/_commit_msg_body.sh +31 -0
- scripts/_post_commit_body.sh +49 -0
- scripts/_pre_commit_body.sh +121 -0
- scripts/_prepare_commit_msg_body.sh +53 -0
- scripts/audit_mcp_tools.py +693 -0
- scripts/bench_sdk_dispatcher.py +177 -0
- scripts/capture_golden.py +169 -0
- scripts/check_graph_phantoms.py +75 -0
- scripts/dev/audit_doc_links.py +359 -0
- scripts/dev/audit_scaffold_module_tags.py +107 -0
- scripts/dev/backfill_doc_headers.py +328 -0
- scripts/dev/backfill_nav_lines.py +119 -0
- scripts/dev/fix_nav_placement.py +106 -0
- scripts/dev/inspect_sdk_options.py +45 -0
- scripts/dev/migrate_check_ids.py +170 -0
- scripts/dev/strip_purpose_blocks.py +154 -0
- scripts/dump_openapi.py +66 -0
- scripts/e2e_dispatch_tool.py +195 -0
- scripts/generate_manifest.py +166 -0
- scripts/golden_sections.py +20 -0
- scripts/graph_demo.py +161 -0
- scripts/install-git-hooks.sh +47 -0
- scripts/migrate_embeddings_minilm_to_bge_m3.py +84 -0
- scripts/operational_eval.py +445 -0
- scripts/probe_agent_session_resolver.py +59 -0
- scripts/prune_deleted_path.py +127 -0
- scripts/refactor_agent_dual_mode.py +171 -0
- scripts/refresh_skill_versions.py +302 -0
- scripts/regen_doc_index.py +209 -0
- scripts/regen_doctor_schema.py +62 -0
- scripts/regen_rules.py +94 -0
- scripts/rename_formulas_to_semantic.py +241 -0
- scripts/smoke_db_connections.py +183 -0
- scripts/smoke_doc_header.py +72 -0
- scripts/smoke_graph_e2e.py +374 -0
- scripts/smoke_sdk_dispatch.py +84 -0
- scripts/smoke_uid_resolver.py +164 -0
- scripts/verify_dispatchers.py +244 -0
- scripts/verify_phase_c_e2e.py +436 -0
- templates/__init__.py +6 -0
- templates/_base/Makefile.base +353 -0
- templates/_base/base.yaml +59 -0
- templates/_base/coding-os.yaml.template +39 -0
- templates/_base/dimension-registry.template.md +68 -0
- templates/_base/domain-config.template.json +46 -0
- templates/_base/fragments/anatomy-map.md.tmpl +11 -0
- templates/_base/fragments/context-discipline.md.tmpl +3 -0
- templates/_base/fragments/core-loop.md.tmpl +52 -0
- templates/_base/fragments/engineering-routing.md.tmpl +3 -0
- templates/_base/fragments/header.md.tmpl +6 -0
- templates/_base/fragments/identity.md.tmpl +3 -0
- templates/_base/fragments/principles.md.tmpl +3 -0
- templates/_base/fragments/retrieval-routing.md.tmpl +23 -0
- templates/_base/fragments/session-handoff.md.tmpl +3 -0
- templates/_base/fragments/skills.md.tmpl +3 -0
- templates/_base/fragments/ssot-map.md.tmpl +3 -0
- templates/_base/fragments/stop-conditions.md.tmpl +3 -0
- templates/_base/fragments/subagent-dispatch.md.tmpl +3 -0
- templates/_base/fragments/task-authoring.md.tmpl +69 -0
- templates/_base/fragments/task-logging.md.tmpl +8 -0
- templates/_base/fragments/tool-routing.md.tmpl +9 -0
- templates/_base/fragments/verification-matrix.md.tmpl +12 -0
- templates/_base/lang/dart/analysis_options.yaml +7 -0
- templates/_base/lang/php/phpcs.xml.dist +10 -0
- templates/_base/lang/python/pyproject.toml +19 -0
- templates/_base/lang/rust/clippy.toml +5 -0
- templates/_base/lang/rust/rustfmt.toml +3 -0
- templates/_base/lang/typescript/eslint.config.js +26 -0
- templates/_base/lang/typescript/tsconfig.json +15 -0
- templates/_base/lang/typescript/vitest.config.ts +10 -0
- templates/_base/scaffold/changes.log +1 -0
- templates/_base/scaffold/docs/00-index.md +55 -0
- templates/_base/scaffold/docs/_meta/feature-dependency-tree.md +30 -0
- templates/_base/scaffold/docs/_meta/foundation-map.md +56 -0
- templates/_base/scaffold/docs/_meta/questions.md +8 -0
- templates/_base/scaffold/docs/_meta/roadmap.md +33 -0
- templates/_base/scaffold/docs/api-contracts/00-index.md +58 -0
- templates/_base/scaffold/docs/api-contracts/error-format.md +58 -0
- templates/_base/scaffold/docs/architecture/00-index.md +42 -0
- templates/_base/scaffold/docs/architecture/adr/00-index.md +39 -0
- templates/_base/scaffold/docs/engineering/00-index.md +9 -0
- templates/_base/scaffold/docs/governance/00-index.md +55 -0
- templates/_base/scaffold/docs/governance/_templates/doc-cheat-sheet.md +202 -0
- templates/_base/scaffold/docs/governance/_templates/playbook-template.md +81 -0
- templates/_base/scaffold/docs/governance/_templates/post-mortem-template.md +85 -0
- templates/_base/scaffold/docs/governance/_templates/runbook-template.md +88 -0
- templates/_base/scaffold/docs/governance/_templates/security-review-template.md +111 -0
- templates/_base/scaffold/docs/governance/_templates/task-detail.md +61 -0
- templates/_base/scaffold/docs/governance/agent-workflow.md +101 -0
- templates/_base/scaffold/docs/governance/anatomy-contract.md +150 -0
- templates/_base/scaffold/docs/governance/critical-rules.md +224 -0
- templates/_base/scaffold/docs/governance/decision-records.md +58 -0
- templates/_base/scaffold/docs/governance/docs-first-protocol.md +157 -0
- templates/_base/scaffold/docs/governance/docs-system.md +151 -0
- templates/_base/scaffold/docs/governance/gdpr-compliance.md +66 -0
- templates/_base/scaffold/docs/governance/mcp-tool-inventory.md +112 -0
- templates/_base/scaffold/docs/governance/risk-register.md +26 -0
- templates/_base/scaffold/docs/governance/scaffold-boundary-contract.md +161 -0
- templates/_base/scaffold/docs/governance/task-lifecycle.md +125 -0
- templates/_base/scaffold/docs/governance/wrapper-derivation.md +50 -0
- templates/_base/scaffold/docs/insights/00-index.md +17 -0
- templates/_base/scaffold/docs/ops/00-index.md +59 -0
- templates/_base/scaffold/docs/ops/runbooks/00-index.md +9 -0
- templates/_base/scaffold/docs/playbooks/00-index.md +12 -0
- templates/_base/scaffold/docs/playbooks/research-validation.md +29 -0
- templates/_base/scaffold/docs/playbooks/security-review.md +41 -0
- templates/_base/scaffold/docs/prd/00-index.md +43 -0
- templates/_base/scaffold/docs/prd/01-snapshot-vision.md +56 -0
- templates/_base/scaffold/docs/workflow/workflow-guide.md +138 -0
- templates/_base/scaffold/src/shared/README.md +23 -0
- templates/_base/skill-enforcement.template.md +14 -0
- templates/_base/task-detail.template.md +61 -0
- templates/_presets/ai-saas.yaml +9 -0
- templates/_presets/django-next.yaml +8 -0
- templates/_presets/dotnet-react.yaml +8 -0
- templates/_presets/flutter-baas.yaml +8 -0
- templates/_presets/go-react.yaml +8 -0
- templates/_presets/hexagonal-product.yaml +16 -0
- templates/_presets/jamstack.yaml +8 -0
- templates/_presets/laravel-vue.yaml +8 -0
- templates/_presets/mean.yaml +8 -0
- templates/_presets/mern.yaml +9 -0
- templates/_presets/nest-angular.yaml +8 -0
- templates/_presets/nextjs-fastapi.yaml +10 -0
- templates/_presets/nuxt-fullstack.yaml +9 -0
- templates/_presets/pern.yaml +9 -0
- templates/_presets/rails-react.yaml +8 -0
- templates/_presets/rn-api.yaml +8 -0
- templates/_presets/rust-svelte.yaml +8 -0
- templates/_presets/spring-react.yaml +8 -0
- templates/_presets/t3-style.yaml +9 -0
- templates/_presets/tall.yaml +8 -0
- templates/_presets/wordpress-cms.yaml +8 -0
- templates/angular/rules/frontend.md +19 -0
- templates/angular/scaffold/docs/engineering/accessibility.md +46 -0
- templates/angular/scaffold/docs/engineering/angular-rules.md +35 -0
- templates/angular/scaffold/docs/playbooks/angular-app.md +42 -0
- templates/angular/scaffold/src/frontend/angular.json +52 -0
- templates/angular/scaffold/src/frontend/package.json +28 -0
- templates/angular/scaffold/src/frontend/src/app/app.component.ts +19 -0
- templates/angular/scaffold/src/frontend/src/app/app.config.ts +22 -0
- templates/angular/scaffold/src/frontend/src/app/app.routes.ts +8 -0
- templates/angular/scaffold/src/frontend/src/app/core/global-error-handler.ts +12 -0
- templates/angular/scaffold/src/frontend/src/app/health/health.component.ts +14 -0
- templates/angular/scaffold/src/frontend/src/app/health/health.service.spec.ts +16 -0
- templates/angular/scaffold/src/frontend/src/app/health/health.service.ts +10 -0
- templates/angular/scaffold/src/frontend/src/index.html +11 -0
- templates/angular/scaffold/src/frontend/src/main.ts +9 -0
- templates/angular/scaffold/src/frontend/src/styles.css +14 -0
- templates/angular/scaffold/src/frontend/tsconfig.app.json +8 -0
- templates/angular/scaffold/src/frontend/tsconfig.json +27 -0
- templates/angular/scaffold/src/frontend/tsconfig.spec.json +8 -0
- templates/angular/scaffold-boundary.yaml +27 -0
- templates/angular/skills/angular/SKILL.md +79 -0
- templates/angular/skills/angular/references/anatomy.md +69 -0
- templates/angular/stack.yaml +75 -0
- templates/aspnet-core/rules/backend.md +20 -0
- templates/aspnet-core/scaffold/docs/engineering/aspnet-core-rules.md +36 -0
- templates/aspnet-core/scaffold/docs/playbooks/aspnet-core-service.md +40 -0
- templates/aspnet-core/scaffold/src/backend/Backend.csproj +11 -0
- templates/aspnet-core/scaffold/src/backend/Backend.sln +27 -0
- templates/aspnet-core/scaffold/src/backend/Common/ExceptionHandlingMiddleware.cs +35 -0
- templates/aspnet-core/scaffold/src/backend/Features/Health/HealthEndpoints.cs +10 -0
- templates/aspnet-core/scaffold/src/backend/Features/Health/HealthService.cs +9 -0
- templates/aspnet-core/scaffold/src/backend/Program.cs +22 -0
- templates/aspnet-core/scaffold/src/backend/tests/Backend.Tests/Backend.Tests.csproj +22 -0
- templates/aspnet-core/scaffold/src/backend/tests/Backend.Tests/HealthServiceTests.cs +15 -0
- templates/aspnet-core/scaffold-boundary.yaml +24 -0
- templates/aspnet-core/skills/aspnet-core/SKILL.md +80 -0
- templates/aspnet-core/skills/aspnet-core/references/anatomy.md +65 -0
- templates/aspnet-core/stack.yaml +68 -0
- templates/astro/rules/frontend.md +20 -0
- templates/astro/scaffold/docs/engineering/astro-rules.md +40 -0
- templates/astro/scaffold/docs/playbooks/astro-app.md +57 -0
- templates/astro/scaffold/docs/playbooks/content-seo.md +37 -0
- templates/astro/scaffold/src/frontend/astro.config.mjs +10 -0
- templates/astro/scaffold/src/frontend/package.json +23 -0
- templates/astro/scaffold/src/frontend/src/components/Greeting.astro +13 -0
- templates/astro/scaffold/src/frontend/src/content/posts/hello.md +10 -0
- templates/astro/scaffold/src/frontend/src/content.config.ts +19 -0
- templates/astro/scaffold/src/frontend/src/lib/problem.test.ts +39 -0
- templates/astro/scaffold/src/frontend/src/lib/problem.ts +30 -0
- templates/astro/scaffold/src/frontend/src/pages/api/health.ts +13 -0
- templates/astro/scaffold/src/frontend/src/pages/index.astro +21 -0
- templates/astro/scaffold/src/frontend/tsconfig.json +9 -0
- templates/astro/scaffold/src/frontend/vitest.config.ts +10 -0
- templates/astro/scaffold-boundary.yaml +28 -0
- templates/astro/skills/astro/SKILL.md +71 -0
- templates/astro/skills/astro/references/anatomy.md +66 -0
- templates/astro/stack.yaml +75 -0
- templates/csharp-plain/scaffold/src/backend/Backend.csproj +12 -0
- templates/csharp-plain/scaffold/src/backend/Program.cs +1 -0
- templates/csharp-plain/scaffold-boundary.yaml +23 -0
- templates/csharp-plain/stack.yaml +50 -0
- templates/django/rules/backend.md +18 -0
- templates/django/scaffold/docs/engineering/anti-ambiguity.md +74 -0
- templates/django/scaffold/docs/engineering/backend-rules.md +133 -0
- templates/django/scaffold/docs/engineering/glossary.md +51 -0
- templates/django/scaffold/docs/engineering/logging-standards.md +107 -0
- templates/django/scaffold/docs/engineering/naming-conventions.md +68 -0
- templates/django/scaffold/docs/engineering/secrets-rotation-runbook.md +142 -0
- templates/django/scaffold/docs/playbooks/backend-api.md +119 -0
- templates/django/scaffold/src/backend/config/__init__.py +0 -0
- templates/django/scaffold/src/backend/config/settings.py +31 -0
- templates/django/scaffold/src/backend/config/urls.py +11 -0
- templates/django/scaffold/src/backend/config/wsgi.py +6 -0
- templates/django/scaffold/src/backend/manage.py +14 -0
- templates/django/scaffold/src/backend/pyproject.toml +37 -0
- templates/django/scaffold/src/backend/tests/test_health.py +4 -0
- templates/django/scaffold-boundary.yaml +25 -0
- templates/django/skills/python-django/SKILL.md +450 -0
- templates/django/skills/python-django/references/anatomy.md +117 -0
- templates/django/skills/python-django/scripts/new_endpoint.py +89 -0
- templates/django/stack.yaml +73 -0
- templates/fastapi/rules/backend.md +18 -0
- templates/fastapi/scaffold/docs/engineering/fastapi-rules.md +37 -0
- templates/fastapi/scaffold/docs/playbooks/fastapi-service.md +30 -0
- templates/fastapi/scaffold/src/backend/app/__init__.py +0 -0
- templates/fastapi/scaffold/src/backend/app/main.py +8 -0
- templates/fastapi/scaffold/src/backend/pyproject.toml +39 -0
- templates/fastapi/scaffold/src/backend/tests/test_health.py +11 -0
- templates/fastapi/scaffold-boundary.yaml +25 -0
- templates/fastapi/skills/python-fastapi/SKILL.md +75 -0
- templates/fastapi/skills/python-fastapi/references/anatomy.md +117 -0
- templates/fastapi/skills/python-fastapi/scripts/new_endpoint.py +101 -0
- templates/fastapi/stack.yaml +57 -0
- templates/flutter/rules/mobile.md +26 -0
- templates/flutter/scaffold/docs/engineering/flutter-rules.md +35 -0
- templates/flutter/scaffold/docs/playbooks/flutter-app.md +45 -0
- templates/flutter/scaffold/src/mobile/lib/core/error_mapper.dart +17 -0
- templates/flutter/scaffold/src/mobile/lib/core/router.dart +13 -0
- templates/flutter/scaffold/src/mobile/lib/main.dart +22 -0
- templates/flutter/scaffold/src/mobile/lib/screens/health_screen.dart +32 -0
- templates/flutter/scaffold/src/mobile/lib/services/health_service.dart +11 -0
- templates/flutter/scaffold/src/mobile/lib/state/health_provider.dart +13 -0
- templates/flutter/scaffold/src/mobile/pubspec.yaml +22 -0
- templates/flutter/scaffold/src/mobile/test/health_provider_test.dart +90 -0
- templates/flutter/scaffold-boundary.yaml +28 -0
- templates/flutter/skills/flutter/SKILL.md +76 -0
- templates/flutter/skills/flutter/references/anatomy.md +64 -0
- templates/flutter/stack.yaml +70 -0
- templates/go/rules/backend.md +19 -0
- templates/go/scaffold/docs/engineering/go-rules.md +45 -0
- templates/go/scaffold/docs/playbooks/go-service.md +30 -0
- templates/go/scaffold/src/backend/cmd/api/main.go +22 -0
- templates/go/scaffold/src/backend/cmd/api/main_test.go +20 -0
- templates/go/scaffold/src/backend/go.mod +3 -0
- templates/go/scaffold-boundary.yaml +25 -0
- templates/go/skills/go-patterns/SKILL.md +68 -0
- templates/go/skills/go-patterns/assets/go-checklist.md +29 -0
- templates/go/skills/go-patterns/references/anatomy.md +115 -0
- templates/go/skills/go-patterns/references/go-2026-idioms.md +92 -0
- templates/go/skills/go-patterns/scripts/new_endpoint.py +117 -0
- templates/go/skills/go-patterns/versions.json +16 -0
- templates/go/stack.yaml +54 -0
- templates/go-fiber/rules/backend.md +20 -0
- templates/go-fiber/scaffold/docs/engineering/fiber-rules.md +97 -0
- templates/go-fiber/scaffold/docs/playbooks/fiber-service.md +149 -0
- templates/go-fiber/scaffold/src/backend/cmd/api/main.go +21 -0
- templates/go-fiber/scaffold/src/backend/cmd/api/main_test.go +17 -0
- templates/go-fiber/scaffold/src/backend/go.mod +23 -0
- templates/go-fiber/scaffold/src/backend/go.sum +49 -0
- templates/go-fiber/scaffold-boundary.yaml +26 -0
- templates/go-fiber/skills/go-fiber/SKILL.md +203 -0
- templates/go-fiber/skills/go-fiber/assets/fiber-checklist.md +26 -0
- templates/go-fiber/skills/go-fiber/references/anatomy.md +116 -0
- templates/go-fiber/skills/go-fiber/references/fiber-v3-patterns.md +89 -0
- templates/go-fiber/skills/go-fiber/scripts/new_endpoint.py +107 -0
- templates/go-fiber/skills/go-fiber/versions.json +16 -0
- templates/go-fiber/stack.yaml +59 -0
- templates/go-plain/scaffold/src/backend/go.mod +3 -0
- templates/go-plain/scaffold/src/backend/main.go +7 -0
- templates/go-plain/scaffold-boundary.yaml +22 -0
- templates/go-plain/stack.yaml +51 -0
- templates/java-plain/scaffold/src/backend/mvnw +302 -0
- templates/java-plain/scaffold/src/backend/pom.xml +41 -0
- templates/java-plain/scaffold/src/backend/src/main/java/com/example/app/Main.java +10 -0
- templates/java-plain/scaffold-boundary.yaml +23 -0
- templates/java-plain/stack.yaml +51 -0
- templates/laravel/rules/backend.md +20 -0
- templates/laravel/scaffold/docs/engineering/laravel-rules.md +28 -0
- templates/laravel/scaffold/docs/playbooks/laravel-service.md +28 -0
- templates/laravel/scaffold/src/backend/app/Exceptions/Handler.php +27 -0
- templates/laravel/scaffold/src/backend/app/Http/Controllers/HealthController.php +15 -0
- templates/laravel/scaffold/src/backend/app/Support/HealthStatus.php +14 -0
- templates/laravel/scaffold/src/backend/composer.json +24 -0
- templates/laravel/scaffold/src/backend/phpunit.xml +10 -0
- templates/laravel/scaffold/src/backend/public/index.php +8 -0
- templates/laravel/scaffold/src/backend/routes/api.php +7 -0
- templates/laravel/scaffold/src/backend/tests/Unit/HealthStatusTest.php +16 -0
- templates/laravel/scaffold-boundary.yaml +23 -0
- templates/laravel/skills/laravel/SKILL.md +56 -0
- templates/laravel/skills/laravel/references/anatomy.md +65 -0
- templates/laravel/stack.yaml +66 -0
- templates/meta/rules/graph-first.md +27 -0
- templates/meta/rules/hook-author.md +19 -0
- templates/meta/rules/mcp-tool-author.md +18 -0
- templates/meta/rules/meta-engineering.md +17 -0
- templates/meta/scaffold-boundary.yaml +55 -0
- templates/meta/skills/claude-sdk-integration/SKILL.md +163 -0
- templates/meta/skills/claude-sdk-integration/assets/sdk-checklist.md +27 -0
- templates/meta/skills/claude-sdk-integration/scripts/check_model_ids.py +97 -0
- templates/meta/skills/graph-os-authoring/SKILL.md +278 -0
- templates/meta/skills/graph-os-authoring/assets/graph-os-checklist.md +25 -0
- templates/meta/skills/graph-os-authoring/scripts/new_extractor.py +76 -0
- templates/meta/skills/hook-authoring/SKILL.md +292 -0
- templates/meta/skills/hook-authoring/assets/hook-checklist.md +30 -0
- templates/meta/skills/hook-authoring/scripts/new_hook.sh +75 -0
- templates/meta/skills/mcp-tool-authoring/SKILL.md +301 -0
- templates/meta/skills/mcp-tool-authoring/assets/mcp-tool-checklist.md +29 -0
- templates/meta/skills/mcp-tool-authoring/scripts/new_tool.py +74 -0
- templates/meta/skills/meta-engineering/SKILL.md +151 -0
- templates/meta/skills/meta-engineering/assets/meta-edit-checklist.md +28 -0
- templates/meta/skills/meta-engineering/scripts/which_layer.py +61 -0
- templates/meta/skills/python-meta-server/SKILL.md +162 -0
- templates/meta/skills/python-meta-server/assets/meta-server-checklist.md +28 -0
- templates/meta/skills/python-meta-server/scripts/check_envelope.py +91 -0
- templates/meta/skills/react-vite-hub/SKILL.md +140 -0
- templates/meta/skills/react-vite-hub/assets/hub-ui-checklist.md +23 -0
- templates/meta/skills/react-vite-hub/scripts/check_vite_env.py +73 -0
- templates/meta/stack.yaml +119 -0
- templates/nestjs/rules/backend.md +20 -0
- templates/nestjs/scaffold/docs/engineering/nestjs-rules.md +33 -0
- templates/nestjs/scaffold/docs/playbooks/nestjs-service.md +39 -0
- templates/nestjs/scaffold/src/backend/nest-cli.json +5 -0
- templates/nestjs/scaffold/src/backend/package.json +28 -0
- templates/nestjs/scaffold/src/backend/src/app.module.ts +9 -0
- templates/nestjs/scaffold/src/backend/src/common/all-exceptions.filter.ts +59 -0
- templates/nestjs/scaffold/src/backend/src/health/health.controller.ts +14 -0
- templates/nestjs/scaffold/src/backend/src/health/health.module.ts +10 -0
- templates/nestjs/scaffold/src/backend/src/health/health.service.spec.ts +21 -0
- templates/nestjs/scaffold/src/backend/src/health/health.service.ts +9 -0
- templates/nestjs/scaffold/src/backend/src/main.ts +26 -0
- templates/nestjs/scaffold/src/backend/tsconfig.json +16 -0
- templates/nestjs/scaffold/src/backend/vitest.config.ts +9 -0
- templates/nestjs/scaffold-boundary.yaml +25 -0
- templates/nestjs/skills/nestjs/SKILL.md +67 -0
- templates/nestjs/skills/nestjs/references/anatomy.md +65 -0
- templates/nestjs/stack.yaml +68 -0
- templates/nextjs/rules/frontend.md +18 -0
- templates/nextjs/scaffold/docs/design/00-index.md +23 -0
- templates/nextjs/scaffold/docs/design/colors-tokens.md +141 -0
- templates/nextjs/scaffold/docs/design/components-patterns.md +159 -0
- templates/nextjs/scaffold/docs/design/motion-accessibility.md +137 -0
- templates/nextjs/scaffold/docs/design/typography-spacing.md +107 -0
- templates/nextjs/scaffold/docs/engineering/accessibility-web.md +56 -0
- templates/nextjs/scaffold/docs/engineering/copywriting-standard.md +102 -0
- templates/nextjs/scaffold/docs/engineering/formatting-rules.md +89 -0
- templates/nextjs/scaffold/docs/engineering/frontend-rendering-rules.md +80 -0
- templates/nextjs/scaffold/docs/engineering/frontend-rules.md +183 -0
- templates/nextjs/scaffold/docs/engineering/i18n-policy.md +99 -0
- templates/nextjs/scaffold/docs/pages-content-spec/00-index.md +78 -0
- templates/nextjs/scaffold/docs/playbooks/content-seo.md +55 -0
- templates/nextjs/scaffold/docs/playbooks/docs-governance.md +51 -0
- templates/nextjs/scaffold/docs/playbooks/frontend-ui.md +63 -0
- templates/nextjs/scaffold/src/frontend/app/layout.tsx +14 -0
- templates/nextjs/scaffold/src/frontend/app/page.tsx +3 -0
- templates/nextjs/scaffold/src/frontend/eslint.config.js +17 -0
- templates/nextjs/scaffold/src/frontend/lib/greeting.test.ts +9 -0
- templates/nextjs/scaffold/src/frontend/lib/greeting.ts +3 -0
- templates/nextjs/scaffold/src/frontend/package.json +28 -0
- templates/nextjs/scaffold/src/frontend/tsconfig.json +18 -0
- templates/nextjs/scaffold/src/frontend/vitest.config.ts +10 -0
- templates/nextjs/scaffold-boundary.yaml +30 -0
- templates/nextjs/skills/nextjs-react/SKILL.md +485 -0
- templates/nextjs/skills/nextjs-react/references/anatomy.md +116 -0
- templates/nextjs/skills/nextjs-react/scripts/new_component.py +72 -0
- templates/nextjs/stack.yaml +81 -0
- templates/node-express/rules/backend.md +20 -0
- templates/node-express/scaffold/docs/engineering/express-rules.md +30 -0
- templates/node-express/scaffold/docs/playbooks/express-service.md +35 -0
- templates/node-express/scaffold/src/backend/package.json +24 -0
- templates/node-express/scaffold/src/backend/src/index.ts +17 -0
- templates/node-express/scaffold/src/backend/src/middleware/error-handler.ts +12 -0
- templates/node-express/scaffold/src/backend/src/routes/health.test.ts +33 -0
- templates/node-express/scaffold/src/backend/src/routes/health.ts +7 -0
- templates/node-express/scaffold/src/backend/tsconfig.json +15 -0
- templates/node-express/scaffold/src/backend/types/express-bootstrap.d.ts +21 -0
- templates/node-express/scaffold-boundary.yaml +25 -0
- templates/node-express/skills/node-express/SKILL.md +70 -0
- templates/node-express/skills/node-express/references/anatomy.md +63 -0
- templates/node-express/stack.yaml +63 -0
- templates/python/scaffold/docs/engineering/python-rules.md +27 -0
- templates/python/scaffold/docs/playbooks/python-library.md +35 -0
- templates/python/stack.yaml +60 -0
- templates/rails/rules/backend.md +10 -0
- templates/rails/scaffold/docs/engineering/rails-rules.md +33 -0
- templates/rails/scaffold/docs/playbooks/rails-service.md +42 -0
- templates/rails/scaffold/src/backend/Gemfile +12 -0
- templates/rails/scaffold/src/backend/app/controllers/application_controller.rb +26 -0
- templates/rails/scaffold/src/backend/app/controllers/health_controller.rb +6 -0
- templates/rails/scaffold/src/backend/app/models/health.rb +6 -0
- templates/rails/scaffold/src/backend/config/application.rb +12 -0
- templates/rails/scaffold/src/backend/config/boot.rb +3 -0
- templates/rails/scaffold/src/backend/config/routes.rb +4 -0
- templates/rails/scaffold/src/backend/config.ru +5 -0
- templates/rails/scaffold/src/backend/spec/rails_helper.rb +18 -0
- templates/rails/scaffold/src/backend/spec/requests/health_spec.rb +24 -0
- templates/rails/scaffold-boundary.yaml +25 -0
- templates/rails/skills/rails/SKILL.md +62 -0
- templates/rails/skills/rails/references/anatomy.md +71 -0
- templates/rails/stack.yaml +72 -0
- templates/react-native/rules/mobile.md +26 -0
- templates/react-native/scaffold/docs/engineering/accessibility-mobile.md +95 -0
- templates/react-native/scaffold/docs/engineering/mobile-rules.md +56 -0
- templates/react-native/scaffold/docs/engineering/offline-first.md +61 -0
- templates/react-native/scaffold/docs/playbooks/mobile-app.md +49 -0
- templates/react-native/scaffold/src/mobile/App.tsx +9 -0
- templates/react-native/scaffold/src/mobile/eslint.config.js +17 -0
- templates/react-native/scaffold/src/mobile/package.json +23 -0
- templates/react-native/scaffold/src/mobile/src/greeting.test.ts +9 -0
- templates/react-native/scaffold/src/mobile/src/greeting.ts +3 -0
- templates/react-native/scaffold/src/mobile/tsconfig.json +17 -0
- templates/react-native/scaffold/src/mobile/vitest.config.ts +10 -0
- templates/react-native/scaffold-boundary.yaml +30 -0
- templates/react-native/skills/react-native-mobile/SKILL.md +119 -0
- templates/react-native/skills/react-native-mobile/assets/rn-mobile-checklist.md +28 -0
- templates/react-native/skills/react-native-mobile/references/anatomy.md +140 -0
- templates/react-native/skills/react-native-mobile/references/rn-2026-practices.md +54 -0
- templates/react-native/skills/react-native-mobile/scripts/new_screen.py +73 -0
- templates/react-native/skills/react-native-mobile/versions.json +16 -0
- templates/react-native/skills/react-native-patterns/SKILL.md +512 -0
- templates/react-native/skills/react-native-patterns/assets/rn-review-checklist.md +26 -0
- templates/react-native/skills/react-native-patterns/references/anatomy.md +62 -0
- templates/react-native/skills/react-native-patterns/references/list-performance.md +70 -0
- templates/react-native/skills/react-native-patterns/scripts/scan_rn_perf.py +77 -0
- templates/react-native/stack.yaml +70 -0
- templates/ruby-plain/scaffold/src/backend/Gemfile +8 -0
- templates/ruby-plain/scaffold/src/backend/main.rb +3 -0
- templates/ruby-plain/scaffold-boundary.yaml +23 -0
- templates/ruby-plain/stack.yaml +50 -0
- templates/rust-axum/rules/backend.md +20 -0
- templates/rust-axum/scaffold/docs/engineering/rust-axum-rules.md +35 -0
- templates/rust-axum/scaffold/docs/playbooks/rust-axum-service.md +43 -0
- templates/rust-axum/scaffold/src/backend/Cargo.toml +20 -0
- templates/rust-axum/scaffold/src/backend/src/app.rs +12 -0
- templates/rust-axum/scaffold/src/backend/src/error.rs +48 -0
- templates/rust-axum/scaffold/src/backend/src/main.rs +24 -0
- templates/rust-axum/scaffold/src/backend/src/routes/health.rs +37 -0
- templates/rust-axum/scaffold/src/backend/src/routes/mod.rs +2 -0
- templates/rust-axum/scaffold-boundary.yaml +25 -0
- templates/rust-axum/skills/rust/SKILL.md +73 -0
- templates/rust-axum/skills/rust/references/anatomy.md +63 -0
- templates/rust-axum/stack.yaml +65 -0
- templates/rust-plain/scaffold/src/backend/Cargo.toml +6 -0
- templates/rust-plain/scaffold/src/backend/src/main.rs +3 -0
- templates/rust-plain/scaffold-boundary.yaml +23 -0
- templates/rust-plain/stack.yaml +51 -0
- templates/spring-boot/rules/backend.md +20 -0
- templates/spring-boot/scaffold/docs/engineering/spring-boot-rules.md +35 -0
- templates/spring-boot/scaffold/docs/playbooks/spring-boot-service.md +45 -0
- templates/spring-boot/scaffold/src/backend/mvnw +302 -0
- templates/spring-boot/scaffold/src/backend/pom.xml +69 -0
- templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/Application.java +16 -0
- templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/common/GlobalExceptionHandler.java +31 -0
- templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/health/HealthController.java +22 -0
- templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/health/HealthService.java +12 -0
- templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/health/HealthStatus.java +4 -0
- templates/spring-boot/scaffold/src/backend/src/test/java/com/example/app/health/HealthServiceTest.java +15 -0
- templates/spring-boot/scaffold-boundary.yaml +26 -0
- templates/spring-boot/skills/spring-boot/SKILL.md +84 -0
- templates/spring-boot/skills/spring-boot/references/anatomy.md +63 -0
- templates/spring-boot/stack.yaml +65 -0
- templates/svelte-sveltekit/rules/frontend.md +20 -0
- templates/svelte-sveltekit/scaffold/docs/engineering/svelte-sveltekit-rules.md +37 -0
- templates/svelte-sveltekit/scaffold/docs/playbooks/svelte-sveltekit-app.md +36 -0
- templates/svelte-sveltekit/scaffold/src/frontend/package.json +22 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/app.html +12 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/hooks.server.ts +14 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/lib/components/Greeting.svelte +6 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/lib/stores/count.test.ts +26 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/lib/stores/count.ts +4 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/routes/+layout.svelte +24 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/routes/+page.svelte +9 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/routes/+page.ts +7 -0
- templates/svelte-sveltekit/scaffold/src/frontend/src/routes/health/+server.ts +7 -0
- templates/svelte-sveltekit/scaffold/src/frontend/svelte.config.js +10 -0
- templates/svelte-sveltekit/scaffold/src/frontend/tsconfig.json +7 -0
- templates/svelte-sveltekit/scaffold/src/frontend/vite.config.ts +7 -0
- templates/svelte-sveltekit/scaffold/src/frontend/vitest.config.ts +11 -0
- templates/svelte-sveltekit/scaffold-boundary.yaml +29 -0
- templates/svelte-sveltekit/skills/svelte/SKILL.md +90 -0
- templates/svelte-sveltekit/skills/svelte/references/anatomy.md +62 -0
- templates/svelte-sveltekit/stack.yaml +70 -0
- templates/typescript-plain/scaffold/src/index.ts +3 -0
- templates/typescript-plain/scaffold/tsconfig.json +13 -0
- templates/typescript-plain/scaffold-boundary.yaml +22 -0
- templates/typescript-plain/stack.yaml +44 -0
- templates/vue-nuxt/rules/frontend.md +19 -0
- templates/vue-nuxt/scaffold/docs/engineering/nuxt-rules.md +30 -0
- templates/vue-nuxt/scaffold/docs/playbooks/nuxt-app.md +29 -0
- templates/vue-nuxt/scaffold/src/frontend/app.vue +3 -0
- templates/vue-nuxt/scaffold/src/frontend/nuxt.config.ts +11 -0
- templates/vue-nuxt/scaffold/src/frontend/package.json +20 -0
- templates/vue-nuxt/scaffold/src/frontend/pages/index.test.ts +19 -0
- templates/vue-nuxt/scaffold/src/frontend/pages/index.vue +11 -0
- templates/vue-nuxt/scaffold/src/frontend/vitest.config.ts +12 -0
- templates/vue-nuxt/scaffold-boundary.yaml +26 -0
- templates/vue-nuxt/skills/vue-nuxt/SKILL.md +57 -0
- templates/vue-nuxt/skills/vue-nuxt/references/anatomy.md +60 -0
- templates/vue-nuxt/stack.yaml +61 -0
- templates/wordpress/rules/backend.md +19 -0
- templates/wordpress/scaffold/docs/engineering/wordpress-rules.md +28 -0
- templates/wordpress/scaffold/docs/playbooks/wordpress-service.md +29 -0
- templates/wordpress/scaffold/src/backend/composer.json +17 -0
- templates/wordpress/scaffold/src/backend/phpcs.xml.dist +11 -0
- templates/wordpress/scaffold/src/backend/phpunit.xml +10 -0
- templates/wordpress/scaffold/src/backend/plugin/inc/health.php +8 -0
- templates/wordpress/scaffold/src/backend/plugin/plugin.php +28 -0
- templates/wordpress/scaffold/src/backend/tests/HealthStatusTest.php +15 -0
- templates/wordpress/scaffold/src/backend/theme/functions.php +18 -0
- templates/wordpress/scaffold/src/backend/theme/style.css +11 -0
- templates/wordpress/scaffold-boundary.yaml +23 -0
- templates/wordpress/skills/wordpress/SKILL.md +110 -0
- templates/wordpress/skills/wordpress/assets/wp-checklist.md +28 -0
- templates/wordpress/skills/wordpress/references/wp-development.md +75 -0
- templates/wordpress/skills/wordpress/references/wp-security.md +68 -0
- templates/wordpress/skills/wordpress/scripts/scan_wp_smells.py +91 -0
- templates/wordpress/skills/wordpress/versions.json +16 -0
- templates/wordpress/stack.yaml +60 -0
- thinking_os/__init__.py +1 -0
- thinking_os/_agent_markers.py +32 -0
- thinking_os/background.py +405 -0
- thinking_os/bootstrap_outcomes.py +200 -0
- thinking_os/budget.py +302 -0
- thinking_os/capture.py +495 -0
- thinking_os/cognition.py +516 -0
- thinking_os/cognition_schemas.py +517 -0
- thinking_os/compress.py +192 -0
- thinking_os/concepts.py +233 -0
- thinking_os/dashboard.py +159 -0
- thinking_os/database.py +2883 -0
- thinking_os/decay.py +393 -0
- thinking_os/digest.py +295 -0
- thinking_os/dispatcher.py +192 -0
- thinking_os/dispatcher_helpers.py +48 -0
- thinking_os/dispatchers/__init__.py +3 -0
- thinking_os/dispatchers/default.py +47 -0
- thinking_os/distill.py +192 -0
- thinking_os/doc_indexer.py +905 -0
- thinking_os/embeddings.py +943 -0
- thinking_os/formula_composer.py +556 -0
- thinking_os/gate_marker.py +75 -0
- thinking_os/graph.py +296 -0
- thinking_os/graph_indexer.py +360 -0
- thinking_os/health_check.py +517 -0
- thinking_os/impact.py +119 -0
- thinking_os/memory_gc.py +356 -0
- thinking_os/migrator_embeddings.py +318 -0
- thinking_os/precision.py +194 -0
- thinking_os/record_outcome.py +399 -0
- thinking_os/repair.py +105 -0
- thinking_os/retrieval_quality.py +239 -0
- thinking_os/roles_state.py +168 -0
- thinking_os/sanitizer.py +320 -0
- thinking_os/server.py +3160 -0
- thinking_os/session_enrich.py +272 -0
- thinking_os/session_observe_worker.py +111 -0
- thinking_os/session_startup.py +74 -0
- thinking_os/session_summary.py +245 -0
- thinking_os/task_analyzer.py +462 -0
- thinking_os/task_parser.py +342 -0
- thinking_os/task_sync.py +73 -0
- thinking_os/tools/__init__.py +6 -0
- thinking_os/tools/_shared.py +947 -0
- thinking_os/tools/cognition.py +1867 -0
- thinking_os/tools/docs.py +770 -0
- thinking_os/tools/learning.py +2078 -0
- thinking_os/tools/logs.py +79 -0
- thinking_os/tools/memory.py +840 -0
- thinking_os/tools/metrics.py +200 -0
- thinking_os/tools/retrieve.py +415 -0
- thinking_os/tools/routing.py +658 -0
- thinking_os/tools/tasks.py +449 -0
- thinking_os/tools/trajectory.py +181 -0
- thinking_os/tracing.py +235 -0
- web/__init__.py +5 -0
- web/_cache.py +118 -0
- web/_deps.py +56 -0
- web/_envelope.py +85 -0
- web/_project_context.py +140 -0
- web/chat_providers.py +108 -0
- web/init_jobs.py +216 -0
- web/routes/__init__.py +25 -0
- web/routes/_bounded_read.py +76 -0
- web/routes/board.py +1089 -0
- web/routes/cognition.py +1838 -0
- web/routes/config.py +635 -0
- web/routes/graph.py +513 -0
- web/routes/health.py +180 -0
- web/routes/hooks.py +288 -0
- web/routes/hub.py +1219 -0
- web/routes/logs.py +374 -0
- web/routes/metrics.py +43 -0
- web/routes/observability.py +400 -0
- web/routes/patterns.py +227 -0
- web/routes/presence.py +609 -0
- web/routes/roles.py +446 -0
- web/routes/scheduled.py +261 -0
- web/routes/search.py +238 -0
- web/routes/sessions.py +220 -0
- web/routes/settings.py +363 -0
- web/routes/stream.py +547 -0
- web/security.py +157 -0
- web/server.py +283 -0
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""branch-guard parser — detects branch-create or HEAD-rewriting git ops
|
|
3
|
+
in a Bash command and emits a verdict.
|
|
4
|
+
|
|
5
|
+
Stdin: {"tool_name": ..., "tool_input": {"command": "<bash cmd>"}}
|
|
6
|
+
Stdout: {"verdict": "allow"} OR
|
|
7
|
+
{"verdict": "block", "reason": "<rule-id>", "message": "<stderr msg>"}
|
|
8
|
+
Exit: 0 always — verdict in JSON is the signal (matches the pattern
|
|
9
|
+
used by other `_helpers/*.py` modules).
|
|
10
|
+
|
|
11
|
+
Why a Python helper instead of more bash: the parser must normalize
|
|
12
|
+
whitespace, strip git global options (`git -C path`, `git -c k=v`),
|
|
13
|
+
descend into nested `sh -c "..."` / `bash -c "..."`, split on shell
|
|
14
|
+
command separators, AND keep literal strings inside `echo`/`grep` args
|
|
15
|
+
from triggering — substring matching in bash slipped on all of these
|
|
16
|
+
(see TASK-013 reviewer probes). `shlex` handles quoting correctly.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import fnmatch
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
import re
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
from git_command_parse import (
|
|
28
|
+
abbrev_resolves,
|
|
29
|
+
command_groups,
|
|
30
|
+
commit_flags,
|
|
31
|
+
is_git_word,
|
|
32
|
+
normalize,
|
|
33
|
+
recover_indirect_commands,
|
|
34
|
+
resolve_command,
|
|
35
|
+
strip_env_vars,
|
|
36
|
+
strip_git_globals,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Pre-subcommand git globals, kept local for the pr-mode-specific _git_dir_target
|
|
40
|
+
# below (the shared tokenizer's strip_git_globals already drops them for the
|
|
41
|
+
# subcommand lookup; this set lets _git_dir_target read the `-C`/--work-tree target).
|
|
42
|
+
_GLOBAL_OPTS_WITH_ARG = {"-C", "-c", "--git-dir", "--work-tree", "--namespace"}
|
|
43
|
+
_GLOBAL_OPTS_NO_ARG = {
|
|
44
|
+
"-p",
|
|
45
|
+
"--paginate",
|
|
46
|
+
"-P",
|
|
47
|
+
"--no-pager",
|
|
48
|
+
"--no-replace-objects",
|
|
49
|
+
"--bare",
|
|
50
|
+
"--no-optional-locks",
|
|
51
|
+
"--literal-pathspecs",
|
|
52
|
+
"--glob-pathspecs",
|
|
53
|
+
"--noglob-pathspecs",
|
|
54
|
+
"--icase-pathspecs",
|
|
55
|
+
}
|
|
56
|
+
_GLOBAL_LONG_EQ_PREFIXES = ("--git-dir=", "--work-tree=", "--namespace=", "-c=")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _check_checkout(args: list[str]) -> tuple[str | None, str | None]:
|
|
60
|
+
# Branch create (-b/-B) — caught here too for consistency.
|
|
61
|
+
if any(a in {"-b", "-B"} for a in args):
|
|
62
|
+
return "branch-create-checkout", _MSG["branch-create"]
|
|
63
|
+
# File restore: `--` separator is present.
|
|
64
|
+
if "--" in args:
|
|
65
|
+
return None, None
|
|
66
|
+
arg = _first_positional(args)
|
|
67
|
+
if arg is None or arg in {"main", "HEAD", "."}:
|
|
68
|
+
return None, None
|
|
69
|
+
return "checkout-branch-switch", _MSG["checkout-switch"]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _check_switch(args: list[str]) -> tuple[str | None, str | None]:
|
|
73
|
+
if any(a in {"-c", "-C"} for a in args):
|
|
74
|
+
return "branch-create-checkout", _MSG["branch-create"]
|
|
75
|
+
arg = _first_positional(args)
|
|
76
|
+
if arg is None or arg == "main":
|
|
77
|
+
return None, None
|
|
78
|
+
return "switch-branch", _MSG["switch-branch"]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _check_branch(args: list[str]) -> tuple[str | None, str | None]:
|
|
82
|
+
# Plain create form `git branch <name> [<startpoint>]` — trunk forbids new
|
|
83
|
+
# branches.
|
|
84
|
+
if args and not args[0].startswith("-"):
|
|
85
|
+
return "branch-create", _MSG["branch-create"]
|
|
86
|
+
# Force-rewrite / rename / copy / delete TARGETING the integration or a
|
|
87
|
+
# protected ref (branch -f/-M/-C/-D main) corrupts the shared line — block at
|
|
88
|
+
# parity with pr-mode (BG-1), reusing its refspec-normalizing blocker. Other
|
|
89
|
+
# flagged forms (-d/-m/-v/--list on a feature branch) stay allowed.
|
|
90
|
+
if _pr_branch_blocks(args, _trunk_protected_refs()):
|
|
91
|
+
return "protected-ref-rewrite", _MSG["protected-ref-rewrite"]
|
|
92
|
+
return None, None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _check_update_ref(args: list[str]) -> tuple[str | None, str | None]:
|
|
96
|
+
# `git update-ref` writes a ref directly; trunk previously had no checker for
|
|
97
|
+
# it (BG-2). Block writes/deletes of the integration/protected line OR HEAD
|
|
98
|
+
# (a direct HEAD move is an unguarded reset). Reuse pr-mode's blocker — it
|
|
99
|
+
# fails closed on --stdin — and add the HEAD guard on top.
|
|
100
|
+
positionals = _update_ref_positionals(args)
|
|
101
|
+
if positionals and _unqualify_ref(positionals[0]) == "HEAD":
|
|
102
|
+
return "protected-ref-rewrite", _MSG["protected-ref-rewrite"]
|
|
103
|
+
if _pr_update_ref_blocks(args, _trunk_protected_refs()):
|
|
104
|
+
return "protected-ref-rewrite", _MSG["protected-ref-rewrite"]
|
|
105
|
+
return None, None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _check_worktree(args: list[str]) -> tuple[str | None, str | None]:
|
|
109
|
+
if args and args[0] == "add":
|
|
110
|
+
return "worktree-add", _MSG["branch-create"]
|
|
111
|
+
return None, None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _check_rebase(args: list[str]) -> tuple[str | None, str | None]:
|
|
115
|
+
# Cleanup / inspection of an in-progress rebase doesn't rewrite history.
|
|
116
|
+
_SAFE_REBASE_FLAGS = {
|
|
117
|
+
"--abort",
|
|
118
|
+
"--continue",
|
|
119
|
+
"--skip",
|
|
120
|
+
"--quit",
|
|
121
|
+
"--edit-todo",
|
|
122
|
+
"--show-current-patch",
|
|
123
|
+
}
|
|
124
|
+
for a in args:
|
|
125
|
+
if a in _SAFE_REBASE_FLAGS:
|
|
126
|
+
return None, None
|
|
127
|
+
# Everything else (`git rebase main`, `-i HEAD~3`, bare → upstream)
|
|
128
|
+
# rewrites trunk history and breaks peers.
|
|
129
|
+
return "rebase-history-rewrite", _MSG["rebase-history"]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _check_reset(args: list[str]) -> tuple[str | None, str | None]:
|
|
133
|
+
# Path-mode reset (`-p`, `--patch`, `--pathspec-from-file`, `--` separator)
|
|
134
|
+
# stages/unstages hunks — it NEVER moves HEAD, so it is always safe. git
|
|
135
|
+
# resolves any unambiguous prefix, so test `--pa…`/`--pat…` etc. by resolution,
|
|
136
|
+
# not a literal (`git reset --pa` → --patch was a bypass of the old `in {…}` set).
|
|
137
|
+
for a in args:
|
|
138
|
+
if a == "--" or a == "-p":
|
|
139
|
+
return None, None
|
|
140
|
+
if a.startswith("--") and (
|
|
141
|
+
abbrev_resolves(a, "--patch", _RESET_LONGS)
|
|
142
|
+
or abbrev_resolves(a, "--pathspec-from-file", _RESET_LONGS)
|
|
143
|
+
or abbrev_resolves(a, "--pathspec-file-nul", _RESET_LONGS)
|
|
144
|
+
):
|
|
145
|
+
return None, None
|
|
146
|
+
# Strip ALL leading mode flags incl. abbreviations (`--har`→--hard,
|
|
147
|
+
# `--so`→--soft) and any other non-positional option, so the first POSITIONAL
|
|
148
|
+
# is reached — the old code stripped only a hardcoded literal set, so `--har`
|
|
149
|
+
# read as the first positional, hit the `startswith("--")` path-restore arm,
|
|
150
|
+
# and the HEAD-move slipped (the bypass this closes).
|
|
151
|
+
rest = [a for a in args if not a.startswith("-")]
|
|
152
|
+
if not rest:
|
|
153
|
+
return None, None # `git reset [--mode]` with no target — unstage, no HEAD move
|
|
154
|
+
first = rest[0]
|
|
155
|
+
if first == "HEAD":
|
|
156
|
+
return None, None # `reset HEAD` / `reset --mode HEAD` — HEAD does not move
|
|
157
|
+
return "reset-head-rewrite", _MSG["reset"]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# `git reset`'s long options — the competitor set for prefix disambiguation. A
|
|
161
|
+
# mode/HEAD-mover vs a path-mode marker only needs the options that share a prefix
|
|
162
|
+
# with the path-mode ones, but the full short list keeps `abbrev_resolves` honest
|
|
163
|
+
# if git adds a colliding option (e.g. a future `--pat*`).
|
|
164
|
+
_RESET_LONGS = frozenset(
|
|
165
|
+
{
|
|
166
|
+
"--soft",
|
|
167
|
+
"--mixed",
|
|
168
|
+
"--hard",
|
|
169
|
+
"--merge",
|
|
170
|
+
"--keep",
|
|
171
|
+
"--patch",
|
|
172
|
+
"--quiet",
|
|
173
|
+
"--no-quiet",
|
|
174
|
+
"--refresh",
|
|
175
|
+
"--no-refresh",
|
|
176
|
+
"--stdin",
|
|
177
|
+
"--pathspec-from-file",
|
|
178
|
+
"--pathspec-file-nul",
|
|
179
|
+
"--intent-to-add",
|
|
180
|
+
"--recurse-submodules",
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# Accepts `-` (previous branch/ref) as a positional arg, plus any
|
|
186
|
+
# token that doesn't start with `-`.
|
|
187
|
+
def _first_positional(args: list[str]) -> str | None:
|
|
188
|
+
for a in args:
|
|
189
|
+
if a == "-":
|
|
190
|
+
return a
|
|
191
|
+
if not a.startswith("-"):
|
|
192
|
+
return a
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _check_commit(args: list[str]) -> tuple[str | None, str | None]:
|
|
197
|
+
# Trunk requires explicit-path commits: `git commit -a/--all` stages every
|
|
198
|
+
# tracked modification, sweeping a concurrent session's WIP into this commit
|
|
199
|
+
# (git-workflow.md § The rule). Block the -a forms; `--amend`, `--author`,
|
|
200
|
+
# `--allow-empty`, `-m`, and explicit-path commits stay allowed.
|
|
201
|
+
short, longs = commit_flags(args)
|
|
202
|
+
if "a" in short or "--all" in longs:
|
|
203
|
+
return "commit-all-sweep", _MSG["commit-all"]
|
|
204
|
+
return None, None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _check_filter(args: list[str]) -> tuple[str | None, str | None]:
|
|
208
|
+
# `git filter-branch` / `filter-repo` rewrite the ENTIRE history of the
|
|
209
|
+
# current branch (= main in trunk) — every published commit is replaced,
|
|
210
|
+
# orphaning every peer. No safe in-place form on a shared trunk.
|
|
211
|
+
return "history-rewrite", _MSG["history-rewrite"]
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _check_symbolic_ref(args: list[str]) -> tuple[str | None, str | None]:
|
|
215
|
+
# `git symbolic-ref HEAD <ref>` repoints HEAD (== a branch switch) and
|
|
216
|
+
# `--delete` detaches it — both move off main. A read form
|
|
217
|
+
# (`symbolic-ref HEAD`, `-q`, `--short`) names no target → allowed.
|
|
218
|
+
if any(a in {"-d", "--delete"} for a in args):
|
|
219
|
+
return "symbolic-ref-write", _MSG["protected-ref-rewrite"]
|
|
220
|
+
positionals = [a for a in args if not a.startswith("-")]
|
|
221
|
+
if len(positionals) >= 2: # <name> <new-target> → a write
|
|
222
|
+
return "symbolic-ref-write", _MSG["protected-ref-rewrite"]
|
|
223
|
+
return None, None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
_DISPATCH = {
|
|
227
|
+
"checkout": _check_checkout,
|
|
228
|
+
"switch": _check_switch,
|
|
229
|
+
"branch": _check_branch,
|
|
230
|
+
"update-ref": _check_update_ref,
|
|
231
|
+
"worktree": _check_worktree,
|
|
232
|
+
"reset": _check_reset,
|
|
233
|
+
"rebase": _check_rebase,
|
|
234
|
+
"commit": _check_commit,
|
|
235
|
+
"filter-branch": _check_filter,
|
|
236
|
+
"filter-repo": _check_filter,
|
|
237
|
+
"symbolic-ref": _check_symbolic_ref,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_MSG = {
|
|
241
|
+
"branch-create": (
|
|
242
|
+
"BLOCKED: coding-os uses a trunk-based git workflow — commit\n"
|
|
243
|
+
"directly to main, do not create branches or worktrees.\n"
|
|
244
|
+
"\n"
|
|
245
|
+
" To fix: edit files, then 'git commit <explicit paths>' and\n"
|
|
246
|
+
" 'git pull --rebase origin main && git push origin main'.\n"
|
|
247
|
+
"\n"
|
|
248
|
+
" See src/core/rules/git-workflow.md for the full rule.\n"
|
|
249
|
+
" If the USER explicitly asked: enable pr-mode per-project (Hub →\n"
|
|
250
|
+
" Config → Git) or export COS_GIT_WORKFLOW=pr session-wide — an inline\n"
|
|
251
|
+
" 'COS_GIT_WORKFLOW=pr git …' prefix does NOT work (the guard reads its\n"
|
|
252
|
+
" own process env first)."
|
|
253
|
+
),
|
|
254
|
+
"reset": (
|
|
255
|
+
"BLOCKED: this 'git reset' would move HEAD — in trunk mode\n"
|
|
256
|
+
"moving HEAD off a published commit clobbers peer work.\n"
|
|
257
|
+
"\n"
|
|
258
|
+
" Safe forms: 'git reset' (unstage), 'git reset --mixed HEAD',\n"
|
|
259
|
+
" 'git reset -- <path>' (unstage one path).\n"
|
|
260
|
+
" To undo the last commit: 'git revert HEAD' (new commit,\n"
|
|
261
|
+
" preserves history).\n"
|
|
262
|
+
"\n"
|
|
263
|
+
" See src/core/rules/git-workflow.md. pr-mode is enabled per-project\n"
|
|
264
|
+
" (Hub → Config → Git) or by exporting COS_GIT_WORKFLOW=pr session-wide\n"
|
|
265
|
+
" — an inline 'COS_GIT_WORKFLOW=pr git …' prefix does NOT work."
|
|
266
|
+
),
|
|
267
|
+
"checkout-switch": (
|
|
268
|
+
"BLOCKED: this 'git checkout' switches branches — coding-os\n"
|
|
269
|
+
"uses a trunk-based workflow (main only).\n"
|
|
270
|
+
"\n"
|
|
271
|
+
" To restore a file: 'git restore <path>' or\n"
|
|
272
|
+
" 'git checkout -- <path>' (note the '--' separator).\n"
|
|
273
|
+
" To restore everything in cwd: 'git checkout .' is allowed.\n"
|
|
274
|
+
" To go to main: 'git switch main'.\n"
|
|
275
|
+
"\n"
|
|
276
|
+
" See src/core/rules/git-workflow.md. pr-mode is enabled per-project\n"
|
|
277
|
+
" (Hub → Config → Git) or by exporting COS_GIT_WORKFLOW=pr session-wide\n"
|
|
278
|
+
" — an inline 'COS_GIT_WORKFLOW=pr git …' prefix does NOT work."
|
|
279
|
+
),
|
|
280
|
+
"switch-branch": (
|
|
281
|
+
"BLOCKED: this 'git switch' moves off main — coding-os uses\n"
|
|
282
|
+
"a trunk-based workflow.\n"
|
|
283
|
+
"\n"
|
|
284
|
+
" Only 'git switch main' is allowed in trunk mode.\n"
|
|
285
|
+
"\n"
|
|
286
|
+
" See src/core/rules/git-workflow.md. pr-mode is enabled per-project\n"
|
|
287
|
+
" (Hub → Config → Git) or by exporting COS_GIT_WORKFLOW=pr session-wide\n"
|
|
288
|
+
" — an inline 'COS_GIT_WORKFLOW=pr git …' prefix does NOT work."
|
|
289
|
+
),
|
|
290
|
+
"rebase-history": (
|
|
291
|
+
"BLOCKED: 'git rebase' rewrites history on the shared trunk —\n"
|
|
292
|
+
"peer commits get orphaned and force-push is required.\n"
|
|
293
|
+
"\n"
|
|
294
|
+
" Safe forms (cleanup of an in-progress rebase):\n"
|
|
295
|
+
" git rebase --abort | --continue | --skip | --quit\n"
|
|
296
|
+
" To integrate concurrent commits before push:\n"
|
|
297
|
+
" git pull --rebase origin main (rebases LOCAL commits only)\n"
|
|
298
|
+
" To undo a bad commit:\n"
|
|
299
|
+
" git revert HEAD (new commit, history intact)\n"
|
|
300
|
+
"\n"
|
|
301
|
+
" See src/core/rules/git-workflow.md. pr-mode is enabled per-project\n"
|
|
302
|
+
" (Hub → Config → Git) or by exporting COS_GIT_WORKFLOW=pr session-wide\n"
|
|
303
|
+
" — an inline 'COS_GIT_WORKFLOW=pr git …' prefix does NOT work."
|
|
304
|
+
),
|
|
305
|
+
"protected-ref-rewrite": (
|
|
306
|
+
"BLOCKED: this rewrites the protected integration ref directly\n"
|
|
307
|
+
"(git branch -f/-M/-C/-D main, git update-ref refs/heads/main or HEAD).\n"
|
|
308
|
+
"In trunk mode that clobbers the shared main line and every peer's history.\n"
|
|
309
|
+
"\n"
|
|
310
|
+
" To undo a published commit: 'git revert <sha>' — a new commit that\n"
|
|
311
|
+
" preserves history. Feature-branch admin must not target main.\n"
|
|
312
|
+
" See src/core/rules/git-workflow.md for the full rule."
|
|
313
|
+
),
|
|
314
|
+
"commit-all": (
|
|
315
|
+
"BLOCKED: 'git commit -a/--all' stages every tracked modification —\n"
|
|
316
|
+
"in a multi-session checkout that sweeps another session's WIP into\n"
|
|
317
|
+
"your commit. Trunk requires EXPLICIT paths.\n"
|
|
318
|
+
"\n"
|
|
319
|
+
" To fix: stage what you mean, then 'git commit <explicit paths>'.\n"
|
|
320
|
+
" ('--amend', '--author', '--allow-empty', '-m' stay allowed.)\n"
|
|
321
|
+
" See src/core/rules/git-workflow.md § The rule."
|
|
322
|
+
),
|
|
323
|
+
"history-rewrite": (
|
|
324
|
+
"BLOCKED: 'git filter-branch' / 'filter-repo' rewrites the ENTIRE\n"
|
|
325
|
+
"history of the current branch — on trunk that replaces every published\n"
|
|
326
|
+
"commit on main and orphans every peer's work.\n"
|
|
327
|
+
"\n"
|
|
328
|
+
" To undo specific commits: 'git revert <sha>' (new commits, history\n"
|
|
329
|
+
" preserved). A genuine history scrub is a human, force-push operation\n"
|
|
330
|
+
" done off the shared trunk. See src/core/rules/git-workflow.md."
|
|
331
|
+
),
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _evaluate(command: str, _recover: bool = True) -> tuple[str, str, str]:
|
|
336
|
+
"""Returns (verdict, reason, message). verdict is 'allow' or 'block'. Uses the
|
|
337
|
+
SHARED git_command_parse tokenizer (quote-aware AND `;`-aware) — no private
|
|
338
|
+
segmenter, so branch_guard and the commit/secret gates can never drift apart,
|
|
339
|
+
and a `;`/`(` inside a quoted commit message no longer false-splits (TASK-572)."""
|
|
340
|
+
groups = command_groups(normalize(command))
|
|
341
|
+
if not groups:
|
|
342
|
+
return "allow", "", ""
|
|
343
|
+
if os.environ.get("COS_GIT_WORKFLOW", "trunk") == "pr":
|
|
344
|
+
verdict = _evaluate_pr(groups)
|
|
345
|
+
else:
|
|
346
|
+
verdict = _evaluate_trunk(groups)
|
|
347
|
+
if verdict[0] == "block" or not _recover:
|
|
348
|
+
return verdict
|
|
349
|
+
# Shell-indirection backstop: a protected op hidden inside eval / pipe-into-sh /
|
|
350
|
+
# here-string / xargs is invisible to the tokenizer above. Recover each inner
|
|
351
|
+
# command string and re-evaluate it against the same rules — one level, since a
|
|
352
|
+
# recovered string is a plain git command.
|
|
353
|
+
for recovered in recover_indirect_commands(command):
|
|
354
|
+
r_verdict = _evaluate(recovered, _recover=False)
|
|
355
|
+
if r_verdict[0] == "block":
|
|
356
|
+
return r_verdict
|
|
357
|
+
return verdict
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _evaluate_trunk(groups: list[list[str]]) -> tuple[str, str, str]:
|
|
361
|
+
for g in groups:
|
|
362
|
+
# resolve_command strips a `VAR=val`/`env …`/`{` prefix; is_git_word accepts a
|
|
363
|
+
# path-qualified `/usr/bin/git`. `g` is already tokenized by command_groups.
|
|
364
|
+
_env, tokens = resolve_command(g)
|
|
365
|
+
if not tokens or not is_git_word(tokens[0]):
|
|
366
|
+
continue
|
|
367
|
+
tokens = strip_git_globals(tokens[1:])
|
|
368
|
+
if not tokens:
|
|
369
|
+
continue
|
|
370
|
+
subcmd, args = tokens[0], tokens[1:]
|
|
371
|
+
checker = _DISPATCH.get(subcmd)
|
|
372
|
+
if checker is None:
|
|
373
|
+
continue
|
|
374
|
+
reason, message = checker(args)
|
|
375
|
+
if reason:
|
|
376
|
+
return "block", reason, message or ""
|
|
377
|
+
return "allow", "", ""
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# ---------------------------------------------------------------------------
|
|
381
|
+
# pr-mode policy (TASK-516) — COS_GIT_WORKFLOW=pr. A positive allow-list, NOT a
|
|
382
|
+
# guard-kill: branches and worktrees are the isolation mechanism, so they pass;
|
|
383
|
+
# what is BLOCKED is mutation of the SHARED integration checkout (direct commit,
|
|
384
|
+
# HEAD-rewrite) and any push to a protected/integration branch. HEAD-rewrites
|
|
385
|
+
# and commits are allowed when the command is scoped to a worktree.
|
|
386
|
+
# SPEC: docs/playbooks/pr-workflow.md § 5.
|
|
387
|
+
# ---------------------------------------------------------------------------
|
|
388
|
+
def _protected_branches() -> set[str]:
|
|
389
|
+
raw = os.environ.get("COS_GIT_PROTECTED_BRANCHES", "production")
|
|
390
|
+
return {b for b in re.split(r"[,\s]+", raw) if b}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def _trunk_protected_refs() -> set[str]:
|
|
394
|
+
# The refs trunk mode refuses to force-rewrite / rename / delete: the
|
|
395
|
+
# integration line (main) + any protected branch — the SAME set pr-mode
|
|
396
|
+
# guards, so neither mode is weaker than the other on ref integrity (BG-1/2).
|
|
397
|
+
integration = os.environ.get("COS_GIT_INTEGRATION_BRANCH", "main")
|
|
398
|
+
return _protected_branches() | {integration}
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _is_worktree_path(path: str) -> bool:
|
|
402
|
+
if not path:
|
|
403
|
+
return False
|
|
404
|
+
# Resolve symlinks AND `..` segments before comparing (Rule 5: macOS /tmp ↔
|
|
405
|
+
# /private/tmp); test ONLY the resolved path — a raw arm let a spoof like
|
|
406
|
+
# `.../worktrees/x/../../../realmain` (resolves INTO the shared checkout) pass.
|
|
407
|
+
real = os.path.realpath(path)
|
|
408
|
+
if "/.coding-os/worktrees/" in real:
|
|
409
|
+
return True
|
|
410
|
+
root = os.environ.get("COS_WORKTREE_ROOT", "")
|
|
411
|
+
if not root:
|
|
412
|
+
return False
|
|
413
|
+
root_real = os.path.realpath(root)
|
|
414
|
+
return real == root_real or real.startswith(root_real.rstrip("/") + "/")
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def _current_dir() -> str:
|
|
418
|
+
try:
|
|
419
|
+
return os.getcwd()
|
|
420
|
+
except OSError:
|
|
421
|
+
return "" # cwd deleted out from under us — fall through to segment checks
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _worktree_scoped(groups: list[list[str]]) -> bool:
|
|
425
|
+
# Worktree scope for a git op with NO explicit -C: the process cwd is a
|
|
426
|
+
# worktree, or a `cd <worktree>` in the command line moved into one. An op
|
|
427
|
+
# WITH -C is scoped per-op from its own target in _evaluate_pr (finding 5).
|
|
428
|
+
cwd = _current_dir()
|
|
429
|
+
if cwd and _is_worktree_path(cwd):
|
|
430
|
+
return True
|
|
431
|
+
for g in groups:
|
|
432
|
+
toks = strip_env_vars(g)
|
|
433
|
+
if toks and toks[0] == "cd" and len(toks) >= 2 and _is_worktree_path(toks[1]):
|
|
434
|
+
return True
|
|
435
|
+
return False
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
# In-progress merge / cherry-pick cleanup flags — these don't advance a branch.
|
|
439
|
+
_SAFE_SEQUENCER_FLAGS = {"--abort", "--continue", "--skip", "--quit"}
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def _unqualify_ref(ref: str) -> str:
|
|
443
|
+
# Map a `+force` / `refs/heads/` / `heads/` refspec to its bare branch name so
|
|
444
|
+
# it can't slip past a bare-name membership test. The `heads/` shorthand is a
|
|
445
|
+
# valid push destination git resolves to `refs/heads/` server-side, so it MUST
|
|
446
|
+
# normalize too (`refs/tags/` left intact — it's a tag).
|
|
447
|
+
ref = ref.lstrip("+")
|
|
448
|
+
# Strip the ref-namespace prefix REPEATEDLY: a doubled `refs/heads/refs/heads/x`
|
|
449
|
+
# (or `heads/heads/x`) must normalize to bare `x`, else the nested form slips the
|
|
450
|
+
# membership test and writes a protected branch (D1).
|
|
451
|
+
while True:
|
|
452
|
+
if ref.startswith("refs/heads/"):
|
|
453
|
+
ref = ref[len("refs/heads/") :]
|
|
454
|
+
elif ref.startswith("heads/"):
|
|
455
|
+
ref = ref[len("heads/") :]
|
|
456
|
+
else:
|
|
457
|
+
return ref
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def _matches_blocked_ref(ref: str, blocked: set[str]) -> bool:
|
|
461
|
+
if not ref:
|
|
462
|
+
return False
|
|
463
|
+
bare = _unqualify_ref(ref)
|
|
464
|
+
return any(fnmatch.fnmatchcase(bare, _unqualify_ref(pattern)) for pattern in blocked)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def _push_targets(args: list[str], blocked: set[str]) -> bool:
|
|
468
|
+
# `--mirror` / `--all` push every local ref → can update the integration or a
|
|
469
|
+
# protected branch without naming it; treat as a protected-push (finding 15).
|
|
470
|
+
if any(a in {"--mirror", "--all"} for a in args):
|
|
471
|
+
return True
|
|
472
|
+
for a in args:
|
|
473
|
+
if a.startswith("-"):
|
|
474
|
+
continue
|
|
475
|
+
dst = a.rsplit(":", 1)[-1] if ":" in a else a
|
|
476
|
+
if _matches_blocked_ref(dst, blocked): # bare/+force/refs-heads forms all map here
|
|
477
|
+
return True
|
|
478
|
+
return False
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def _push_names_explicit_dst(args: list[str]) -> bool:
|
|
482
|
+
# True when the push names at least one explicit destination ref that is not
|
|
483
|
+
# `HEAD` — i.e. it is provably NOT a bare/`HEAD`-only push that would advance
|
|
484
|
+
# whatever branch is currently checked out. `git push [remote] [refspec...]`:
|
|
485
|
+
# the first positional is the remote, the rest are refspecs.
|
|
486
|
+
positionals = [a for a in args if not a.startswith("-")]
|
|
487
|
+
for refspec in positionals[1:]:
|
|
488
|
+
dst = refspec.rsplit(":", 1)[-1] if ":" in refspec else refspec
|
|
489
|
+
if _unqualify_ref(dst) != "HEAD":
|
|
490
|
+
return True
|
|
491
|
+
return False
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def _has_unsafe_push_default(global_tokens: list[str]) -> bool:
|
|
495
|
+
# `git -c push.default=matching push` makes a bare push update every same-name
|
|
496
|
+
# branch (incl. the integration line) and `current` pushes whatever is checked
|
|
497
|
+
# out — both can advance a blocked branch a refspec check never sees. The `-c`
|
|
498
|
+
# global is stripped before _pr_check, so it is inspected here on the raw tokens.
|
|
499
|
+
i = 0
|
|
500
|
+
while i < len(global_tokens):
|
|
501
|
+
t = global_tokens[i]
|
|
502
|
+
kv = None
|
|
503
|
+
if t == "-c" and i + 1 < len(global_tokens):
|
|
504
|
+
kv = global_tokens[i + 1]
|
|
505
|
+
i += 2
|
|
506
|
+
elif t.startswith("-c="):
|
|
507
|
+
kv = t[len("-c=") :]
|
|
508
|
+
i += 1
|
|
509
|
+
else:
|
|
510
|
+
i += 1
|
|
511
|
+
continue
|
|
512
|
+
key, _, val = kv.partition("=")
|
|
513
|
+
if key.strip() == "push.default" and val.strip() in {"matching", "current"}:
|
|
514
|
+
return True
|
|
515
|
+
return False
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def _created_ref(subcmd: str, args: list[str]) -> str:
|
|
519
|
+
# The branch ref a checkout/switch force-creates or resets via -b/-B (checkout)
|
|
520
|
+
# or -b/-B/-c/-C (switch). "" when none (a plain switch onto an existing branch
|
|
521
|
+
# writes no ref). Plain `git checkout main` is a read-only switch → not a ref write.
|
|
522
|
+
flags = {"-b", "-B"} if subcmd == "checkout" else {"-b", "-B", "-c", "-C"}
|
|
523
|
+
for i, a in enumerate(args):
|
|
524
|
+
if a in flags and i + 1 < len(args):
|
|
525
|
+
return _unqualify_ref(args[i + 1])
|
|
526
|
+
return ""
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def _worktree_add_branch(args: list[str]) -> str:
|
|
530
|
+
# The branch a `git worktree add` creates (`-b/-B <name>`) or checks out (the
|
|
531
|
+
# optional 2nd positional `git worktree add <path> <branch>`). "" when detached
|
|
532
|
+
# or based on a remote ref. Blocking this keeps the integration/protected line
|
|
533
|
+
# out of any worktree, so a worktree's HEAD is always a non-blocked branch.
|
|
534
|
+
for i, a in enumerate(args):
|
|
535
|
+
if a in {"-b", "-B"} and i + 1 < len(args):
|
|
536
|
+
return _unqualify_ref(args[i + 1])
|
|
537
|
+
positionals = [a for a in args if not a.startswith("-")]
|
|
538
|
+
if len(positionals) >= 2: # add <path> <branch>
|
|
539
|
+
return _unqualify_ref(positionals[1])
|
|
540
|
+
return ""
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def _update_ref_positionals(args: list[str]) -> list[str]:
|
|
544
|
+
# Ref operands of `git update-ref`, dropping `-m <reason>`'s value (a reflog
|
|
545
|
+
# message, not a ref) so `update-ref -m main refs/heads/feature …` reads the
|
|
546
|
+
# ref operand, not the message (review finding B/D).
|
|
547
|
+
out: list[str] = []
|
|
548
|
+
skip = False
|
|
549
|
+
for a in args:
|
|
550
|
+
if skip:
|
|
551
|
+
skip = False
|
|
552
|
+
continue
|
|
553
|
+
if a in {"-m", "--reflog-message"}:
|
|
554
|
+
skip = True
|
|
555
|
+
continue
|
|
556
|
+
if not a.startswith("-"):
|
|
557
|
+
out.append(a)
|
|
558
|
+
return out
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
def _is_branch_filter_flag(arg: str) -> bool:
|
|
562
|
+
# `git branch` selectors whose ref/pattern operand is a FILTER, not a ref to
|
|
563
|
+
# write — present ⇒ a read-only list query, so a protected ref named as the
|
|
564
|
+
# filter must NOT block (review finding C: `branch --contains/--merged main`).
|
|
565
|
+
return arg.split("=", 1)[0] in {
|
|
566
|
+
"--contains",
|
|
567
|
+
"--no-contains",
|
|
568
|
+
"--merged",
|
|
569
|
+
"--no-merged",
|
|
570
|
+
"--points-at",
|
|
571
|
+
"--list",
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def _pr_branch_blocks(args: list[str], blocked: set[str]) -> bool:
|
|
576
|
+
# Worktree scope is irrelevant — branch refs are shared across worktrees via
|
|
577
|
+
# the common dir, so a blocked target trips even from a worktree (agents/*
|
|
578
|
+
# create + `-D agents/...` cleanup still pass: only a blocked target trips).
|
|
579
|
+
if any(_is_branch_filter_flag(a) for a in args):
|
|
580
|
+
return False # read-only list/filter form — the ref operand is a filter
|
|
581
|
+
positionals = [a for a in args if not a.startswith("-")]
|
|
582
|
+
if not positionals:
|
|
583
|
+
return False
|
|
584
|
+
# Copy `-c/-C` writes only the TARGET (last positional); its source ref is
|
|
585
|
+
# read, not modified — `branch -c main backup` must not trip on `main`.
|
|
586
|
+
if any(a in {"-c", "-C", "--copy"} for a in args):
|
|
587
|
+
return _matches_blocked_ref(positionals[-1], blocked)
|
|
588
|
+
# Delete `-d/-D` and rename `-m/-M` put EVERY named ref at risk.
|
|
589
|
+
if any(a in {"-d", "-D", "--delete", "-m", "-M", "--move"} for a in args):
|
|
590
|
+
return any(_matches_blocked_ref(p, blocked) for p in positionals)
|
|
591
|
+
# Plain / force create-or-move: only the written ref (first positional).
|
|
592
|
+
return _matches_blocked_ref(positionals[0], blocked)
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
def _pr_update_ref_blocks(args: list[str], blocked: set[str]) -> bool:
|
|
596
|
+
if "--stdin" in args: # feeds ref commands we can't inspect → fail closed
|
|
597
|
+
return True
|
|
598
|
+
positionals = _update_ref_positionals(args)
|
|
599
|
+
return bool(positionals) and _matches_blocked_ref(positionals[0], blocked)
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def _git_dir_target(global_tokens: list[str]) -> str | None:
|
|
603
|
+
# The path a git invocation is explicitly pointed at via -C / --work-tree /
|
|
604
|
+
# --git-dir (None = the ambient cwd). Scope is decided per git-op from THIS
|
|
605
|
+
# target, never command-globally, so `cd <wt> && git -C <main> reset` is
|
|
606
|
+
# judged against <main>, not the worktree cwd (finding 5).
|
|
607
|
+
i = 0
|
|
608
|
+
while i < len(global_tokens):
|
|
609
|
+
t = global_tokens[i]
|
|
610
|
+
if t in {"-C", "--work-tree", "--git-dir"} and i + 1 < len(global_tokens):
|
|
611
|
+
return global_tokens[i + 1]
|
|
612
|
+
matched_eq = [p for p in ("--work-tree=", "--git-dir=") if t.startswith(p)]
|
|
613
|
+
if matched_eq:
|
|
614
|
+
return t[len(matched_eq[0]) :]
|
|
615
|
+
if t in _GLOBAL_OPTS_WITH_ARG:
|
|
616
|
+
i += 2
|
|
617
|
+
continue
|
|
618
|
+
if t in _GLOBAL_OPTS_NO_ARG or any(t.startswith(p) for p in _GLOBAL_LONG_EQ_PREFIXES):
|
|
619
|
+
i += 1
|
|
620
|
+
continue
|
|
621
|
+
break
|
|
622
|
+
return None
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
def _evaluate_pr(groups: list[list[str]]) -> tuple[str, str, str]:
|
|
626
|
+
integration = os.environ.get("COS_GIT_INTEGRATION_BRANCH", "main")
|
|
627
|
+
blocked_push = _protected_branches() | {integration}
|
|
628
|
+
fallback_scope = _worktree_scoped(groups) # cwd/cd, for ops with no -C
|
|
629
|
+
for g in groups:
|
|
630
|
+
_env, tokens = resolve_command(g)
|
|
631
|
+
if not tokens or not is_git_word(tokens[0]):
|
|
632
|
+
continue
|
|
633
|
+
global_tokens = tokens[1:]
|
|
634
|
+
c_target = _git_dir_target(global_tokens)
|
|
635
|
+
sub = strip_git_globals(global_tokens)
|
|
636
|
+
if not sub:
|
|
637
|
+
continue
|
|
638
|
+
op_scope = _is_worktree_path(c_target) if c_target is not None else fallback_scope
|
|
639
|
+
reason, message = _pr_check(sub[0], sub[1:], op_scope, blocked_push)
|
|
640
|
+
if not reason and sub[0] == "push" and _has_unsafe_push_default(global_tokens):
|
|
641
|
+
reason, message = "pr-protected-push", _PR_MSG["protected-push"]
|
|
642
|
+
if reason:
|
|
643
|
+
return "block", reason, message or ""
|
|
644
|
+
return "allow", "", ""
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def _pr_check(
|
|
648
|
+
subcmd: str, args: list[str], worktree: bool, blocked_push: set[str]
|
|
649
|
+
) -> tuple[str | None, str | None]:
|
|
650
|
+
if subcmd == "push":
|
|
651
|
+
if _push_targets(args, blocked_push):
|
|
652
|
+
return "pr-protected-push", _PR_MSG["protected-push"]
|
|
653
|
+
# A bare / HEAD-only push from the shared checkout advances the integration
|
|
654
|
+
# line (its current branch is integration), outside PR+CI. Allow only when
|
|
655
|
+
# worktree-scoped (HEAD is agents/* there) or it names an explicit non-blocked
|
|
656
|
+
# destination refspec — the sanctioned `cos pr submit` does both.
|
|
657
|
+
if not worktree and not _push_names_explicit_dst(args):
|
|
658
|
+
return "pr-protected-push", _PR_MSG["protected-push"]
|
|
659
|
+
return None, None
|
|
660
|
+
if subcmd == "commit":
|
|
661
|
+
if worktree:
|
|
662
|
+
return None, None
|
|
663
|
+
return "pr-shared-commit", _PR_MSG["shared-commit"]
|
|
664
|
+
if subcmd in {"reset", "rebase"}:
|
|
665
|
+
reason, _ = _DISPATCH[subcmd](args)
|
|
666
|
+
if reason is None: # safe form (unstage/path/HEAD, rebase --abort/...)
|
|
667
|
+
return None, None
|
|
668
|
+
if worktree:
|
|
669
|
+
return None, None # HEAD-rewrite is fine inside an isolated worktree
|
|
670
|
+
return "pr-shared-head-rewrite", _PR_MSG["shared-head"]
|
|
671
|
+
if subcmd in {"merge", "cherry-pick"}:
|
|
672
|
+
# advancing HEAD on the shared checkout lands code outside PR+CI; a
|
|
673
|
+
# worktree only advances its own agents/* HEAD, so it's allowed.
|
|
674
|
+
if any(a in _SAFE_SEQUENCER_FLAGS for a in args):
|
|
675
|
+
return None, None # in-progress cleanup, not an advance
|
|
676
|
+
if worktree:
|
|
677
|
+
return None, None
|
|
678
|
+
# Sanctioned local_autonomous land (TASK-614): `cos pr land` exports COS_PR_LAND
|
|
679
|
+
# into the merge subprocess's ENV, so the guard reads it from os.environ. An
|
|
680
|
+
# agent's inline `COS_PR_LAND=1 git merge …` cannot forge it — resolve_command
|
|
681
|
+
# strips the inline assignment into _env, never os.environ (same protection as
|
|
682
|
+
# the COS_ALLOW_FORCE_PUSH_MAIN prefix guard).
|
|
683
|
+
if os.environ.get("COS_PR_LAND") == "1":
|
|
684
|
+
return None, None
|
|
685
|
+
return "pr-shared-head-rewrite", _PR_MSG["shared-head"]
|
|
686
|
+
if subcmd == "branch":
|
|
687
|
+
if _pr_branch_blocks(args, blocked_push):
|
|
688
|
+
return "pr-protected-ref", _PR_MSG["protected-ref"]
|
|
689
|
+
return None, None # agents/* create + delete stay allowed
|
|
690
|
+
if subcmd == "update-ref":
|
|
691
|
+
positionals = _update_ref_positionals(args)
|
|
692
|
+
if not worktree and positionals and _unqualify_ref(positionals[0]) == "HEAD":
|
|
693
|
+
return "pr-shared-head-rewrite", _PR_MSG["shared-head"]
|
|
694
|
+
if _pr_update_ref_blocks(args, blocked_push):
|
|
695
|
+
return "pr-protected-ref", _PR_MSG["protected-ref"]
|
|
696
|
+
return None, None
|
|
697
|
+
if subcmd in {"fetch", "pull"}:
|
|
698
|
+
# `git fetch/pull origin x:main` / `:production` writes a blocked LOCAL ref
|
|
699
|
+
# (pull is fetch+merge with identical refspec syntax); legit pr-mode fetches
|
|
700
|
+
# never use a colon, so a refspec with one whose destination is blocked is the
|
|
701
|
+
# leak. Refs are global → scope is moot (review finding 3).
|
|
702
|
+
for a in args:
|
|
703
|
+
if a.startswith("-") or ":" not in a:
|
|
704
|
+
continue
|
|
705
|
+
if _matches_blocked_ref(a.rsplit(":", 1)[-1], blocked_push):
|
|
706
|
+
return "pr-protected-ref", _PR_MSG["protected-ref"]
|
|
707
|
+
return None, None
|
|
708
|
+
if subcmd in {"checkout", "switch"}:
|
|
709
|
+
# -b/-B (checkout) or -b/-B/-c/-C (switch) force-create/reset a branch ref;
|
|
710
|
+
# a blocked target is a protected-ref write (refs are global, like branch -f).
|
|
711
|
+
if _matches_blocked_ref(_created_ref(subcmd, args), blocked_push):
|
|
712
|
+
return "pr-protected-ref", _PR_MSG["protected-ref"]
|
|
713
|
+
return None, None
|
|
714
|
+
if subcmd == "worktree":
|
|
715
|
+
# `git worktree add -b|-B <blocked>` or `... <path> <blocked>` would create or
|
|
716
|
+
# check the integration/protected line out into a worktree — refuse it so a
|
|
717
|
+
# worktree HEAD is always a non-blocked branch (keeps the push rule above safe).
|
|
718
|
+
if (
|
|
719
|
+
args
|
|
720
|
+
and args[0] == "add"
|
|
721
|
+
and _matches_blocked_ref(_worktree_add_branch(args[1:]), blocked_push)
|
|
722
|
+
):
|
|
723
|
+
return "pr-protected-ref", _PR_MSG["protected-ref"]
|
|
724
|
+
return None, None
|
|
725
|
+
if subcmd in {"filter-branch", "filter-repo"}:
|
|
726
|
+
# History rewrite touches the shared object db + refs even from a worktree —
|
|
727
|
+
# always blocked (parity with trunk's history-rewrite guard, BG-1/BG-2).
|
|
728
|
+
return "pr-shared-head-rewrite", _PR_MSG["shared-head"]
|
|
729
|
+
if subcmd == "symbolic-ref":
|
|
730
|
+
# Repointing a worktree's OWN HEAD is isolated; on the shared checkout it
|
|
731
|
+
# is an off-integration switch outside PR+CI.
|
|
732
|
+
if _check_symbolic_ref(args)[0] is None:
|
|
733
|
+
return None, None
|
|
734
|
+
return (None, None) if worktree else ("pr-shared-head-rewrite", _PR_MSG["shared-head"])
|
|
735
|
+
# everything else: branches and worktrees are the pr-mode isolation mechanism — allowed.
|
|
736
|
+
return None, None
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
_PR_MSG = {
|
|
740
|
+
"shared-commit": (
|
|
741
|
+
"BLOCKED (pr-mode): direct commit on the shared integration checkout.\n"
|
|
742
|
+
" Every change must be isolated in a worktree.\n"
|
|
743
|
+
" To fix: 'cos pr open' (or 'cos pr open --adhoc' for no-task work),\n"
|
|
744
|
+
" then commit inside the worktree.\n"
|
|
745
|
+
" See docs/playbooks/pr-workflow.md § 5/§6."
|
|
746
|
+
),
|
|
747
|
+
"shared-head": (
|
|
748
|
+
"BLOCKED (pr-mode): HEAD-rewrite (reset/rebase/merge/cherry-pick) on the\n"
|
|
749
|
+
"shared integration checkout corrupts the always-green integration line.\n"
|
|
750
|
+
" These are allowed INSIDE a worktree — scope the op with\n"
|
|
751
|
+
" 'git -C <worktree>' or 'cd <worktree> && …'.\n"
|
|
752
|
+
" See docs/playbooks/pr-workflow.md § 5."
|
|
753
|
+
),
|
|
754
|
+
"protected-ref": (
|
|
755
|
+
"BLOCKED (pr-mode): this rewrites a protected/integration branch ref\n"
|
|
756
|
+
"directly (git branch -f/-D/-m / git update-ref). Branch refs are shared\n"
|
|
757
|
+
"across every worktree, so this corrupts the integration/production line\n"
|
|
758
|
+
"outside the PR+CI flow — worktree scope is NO protection here.\n"
|
|
759
|
+
" Agents mutate only their own 'agents/*' branch; land changes via a PR.\n"
|
|
760
|
+
" See docs/playbooks/pr-workflow.md § 5."
|
|
761
|
+
),
|
|
762
|
+
"protected-push": (
|
|
763
|
+
"BLOCKED (pr-mode): push targets a protected/integration branch.\n"
|
|
764
|
+
" Agents push only to their own 'agents/*' branch, then open a PR.\n"
|
|
765
|
+
" To fix: 'git push --force-with-lease -u origin HEAD' from the\n"
|
|
766
|
+
" worktree branch, then open the PR ('cos pr open' / 'gh pr create').\n"
|
|
767
|
+
" See docs/playbooks/pr-workflow.md § 5/§11."
|
|
768
|
+
),
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
def main() -> int:
|
|
773
|
+
try:
|
|
774
|
+
payload = json.load(sys.stdin)
|
|
775
|
+
except (json.JSONDecodeError, ValueError):
|
|
776
|
+
json.dump({"verdict": "allow"}, sys.stdout)
|
|
777
|
+
return 0
|
|
778
|
+
if payload.get("tool_name") != "Bash":
|
|
779
|
+
json.dump({"verdict": "allow"}, sys.stdout)
|
|
780
|
+
return 0
|
|
781
|
+
command = (payload.get("tool_input") or {}).get("command", "")
|
|
782
|
+
if not isinstance(command, str) or not command:
|
|
783
|
+
json.dump({"verdict": "allow"}, sys.stdout)
|
|
784
|
+
return 0
|
|
785
|
+
|
|
786
|
+
verdict, reason, message = _evaluate(command)
|
|
787
|
+
out: dict[str, str] = {"verdict": verdict}
|
|
788
|
+
if verdict == "block":
|
|
789
|
+
out["reason"] = reason
|
|
790
|
+
out["message"] = message
|
|
791
|
+
json.dump(out, sys.stdout)
|
|
792
|
+
return 0
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
if __name__ == "__main__":
|
|
796
|
+
sys.exit(main())
|