wicked-garden 12.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/archetypes.json +166 -0
- package/.claude-plugin/components.json +75 -0
- package/.claude-plugin/marketplace.json +15 -0
- package/.claude-plugin/plugin.json +174 -0
- package/.claude-plugin/specialist.json +48 -0
- package/.claude-plugin/stack-registry.json +96 -0
- package/AGENTS.md +13 -0
- package/CHANGELOG.md +712 -0
- package/CONTRIBUTING.md +99 -0
- package/ETHOS.md +83 -0
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
- package/agents/agentic/architect.md +449 -0
- package/agents/agentic/performance-analyst.md +702 -0
- package/agents/agentic/safety-reviewer.md +662 -0
- package/agents/crew/implementer.md +163 -0
- package/agents/crew/researcher.md +94 -0
- package/agents/crew/reviewer.md +184 -0
- package/agents/data/data-engineer.md +227 -0
- package/agents/engineering/api-documentarian.md +440 -0
- package/agents/engineering/migration-engineer.md +301 -0
- package/agents/engineering/solution-architect.md +208 -0
- package/agents/jam/brainstorm-facilitator.md +297 -0
- package/agents/jam/council.md +322 -0
- package/agents/jam/quick-facilitator.md +85 -0
- package/agents/persona/persona-agent.md +121 -0
- package/agents/platform/compliance-officer.md +266 -0
- package/agents/platform/privacy-expert.md +496 -0
- package/agents/platform/security-engineer.md +287 -0
- package/agents/product/a11y-expert.md +323 -0
- package/agents/product/requirements-analyst.md +238 -0
- package/agents/product/ui-reviewer.md +180 -0
- package/agents/product/ux-designer.md +199 -0
- package/agents/product/value-strategist.md +269 -0
- package/agents/qe/semantic-reviewer.md +78 -0
- package/commands/agentic/audit.md +24 -0
- package/commands/agentic/design.md +24 -0
- package/commands/agentic/frameworks.md +25 -0
- package/commands/agentic/review.md +27 -0
- package/commands/archetype/build.md +12 -0
- package/commands/archetype/decide.md +12 -0
- package/commands/archetype/explore.md +12 -0
- package/commands/archetype/incident.md +12 -0
- package/commands/archetype/migrate.md +12 -0
- package/commands/archetype/modernize.md +12 -0
- package/commands/archetype/review.md +14 -0
- package/commands/archetype/ship.md +12 -0
- package/commands/archetype/specify.md +12 -0
- package/commands/archetype/triage.md +12 -0
- package/commands/compile.md +37 -0
- package/commands/data/analyze.md +18 -0
- package/commands/data/data.md +21 -0
- package/commands/data/ml.md +18 -0
- package/commands/data/ontology.md +22 -0
- package/commands/data/pipeline.md +17 -0
- package/commands/deliberate.md +181 -0
- package/commands/engineering/add-field.md +77 -0
- package/commands/engineering/apply.md +58 -0
- package/commands/engineering/arch.md +26 -0
- package/commands/engineering/debug.md +27 -0
- package/commands/engineering/docs.md +27 -0
- package/commands/engineering/new-generator.md +257 -0
- package/commands/engineering/patch-plan.md +59 -0
- package/commands/engineering/plan.md +29 -0
- package/commands/engineering/remove.md +48 -0
- package/commands/engineering/rename.md +44 -0
- package/commands/engineering/review.md +32 -0
- package/commands/help.md +128 -0
- package/commands/install.md +118 -0
- package/commands/intent.md +54 -0
- package/commands/jam/brainstorm.md +37 -0
- package/commands/jam/council.md +49 -0
- package/commands/jam/quick.md +21 -0
- package/commands/jam/revisit.md +79 -0
- package/commands/persona/as.md +136 -0
- package/commands/persona/define.md +24 -0
- package/commands/persona/list.md +118 -0
- package/commands/platform/actions.md +20 -0
- package/commands/platform/assert.md +18 -0
- package/commands/platform/audit.md +23 -0
- package/commands/platform/compliance.md +20 -0
- package/commands/platform/gh.md +22 -0
- package/commands/platform/health.md +22 -0
- package/commands/platform/incident.md +23 -0
- package/commands/platform/infra.md +24 -0
- package/commands/platform/peer-health.md +103 -0
- package/commands/platform/plugin-health.md +58 -0
- package/commands/platform/security.md +38 -0
- package/commands/platform/toolchain.md +96 -0
- package/commands/platform/traces.md +20 -0
- package/commands/product/a11y.md +19 -0
- package/commands/product/acceptance.md +19 -0
- package/commands/product/align.md +20 -0
- package/commands/product/analyze.md +23 -0
- package/commands/product/elicit.md +19 -0
- package/commands/product/listen.md +24 -0
- package/commands/product/mockup.md +20 -0
- package/commands/product/screenshot.md +19 -0
- package/commands/product/strategy.md +40 -0
- package/commands/product/synthesize.md +23 -0
- package/commands/product/ux-review.md +42 -0
- package/commands/product/ux.md +20 -0
- package/commands/product/visual-direction.md +34 -0
- package/commands/prove.md +47 -0
- package/commands/report-issue.md +243 -0
- package/commands/reset.md +144 -0
- package/commands/search/blast-radius.md +58 -0
- package/commands/search/hotspots.md +55 -0
- package/commands/search/index.md +38 -0
- package/commands/search/lineage.md +47 -0
- package/commands/search/service-map.md +79 -0
- package/commands/setup.md +363 -0
- package/commands/smaht/briefing.md +200 -0
- package/commands/smaht/events-import.md +95 -0
- package/commands/smaht/state.md +19 -0
- package/commands/where-am-i.md +58 -0
- package/docs/README.md +32 -0
- package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
- package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
- package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
- package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
- package/docs/brain-chunk-format.md +135 -0
- package/docs/compiler.md +95 -0
- package/docs/daemon-api.md +70 -0
- package/docs/domains.md +197 -0
- package/docs/getting-started.md +208 -0
- package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
- package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
- package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
- package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
- package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
- package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
- package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
- package/docs/required-peers.md +60 -0
- package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
- package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
- package/docs/v11/archetypes.md +231 -0
- package/hooks/hooks.json +275 -0
- package/hooks/scripts/bootstrap.py +1797 -0
- package/hooks/scripts/invoke.py +62 -0
- package/hooks/scripts/notification.py +166 -0
- package/hooks/scripts/permission_request.py +223 -0
- package/hooks/scripts/post_tool.py +1374 -0
- package/hooks/scripts/pre_compact.py +272 -0
- package/hooks/scripts/pre_tool.py +1278 -0
- package/hooks/scripts/prompt_submit.py +1109 -0
- package/hooks/scripts/session_end.py +95 -0
- package/hooks/scripts/stop.py +624 -0
- package/hooks/scripts/subagent_lifecycle.py +464 -0
- package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
- package/hooks/scripts/task_completed.py +322 -0
- package/hooks/scripts/worktree_guard.py +148 -0
- package/hooks/subscriptions/on_gate_decided.json +9 -0
- package/install.mjs +128 -0
- package/package.json +41 -0
- package/pyproject.toml +59 -0
- package/schemas/README.md +32 -0
- package/schemas/assert_contracts.json +37 -0
- package/schemas/health_probe.json +46 -0
- package/schemas/plugin_status.json +37 -0
- package/scripts/_adapters/__init__.py +166 -0
- package/scripts/_adapters/jira_adapter.py +18 -0
- package/scripts/_adapters/linear_adapter.py +18 -0
- package/scripts/_adapters/miro_adapter.py +18 -0
- package/scripts/_adapters/notion_adapter.py +18 -0
- package/scripts/_agents.py +357 -0
- package/scripts/_brain_ingest/__init__.py +2 -0
- package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
- package/scripts/_brain_port.py +163 -0
- package/scripts/_bus.py +1081 -0
- package/scripts/_bus_catalog_gen.py +93 -0
- package/scripts/_bus_consumers.json +46 -0
- package/scripts/_bus_emit.py +43 -0
- package/scripts/_capability_registry.py +334 -0
- package/scripts/_capability_resolver.py +322 -0
- package/scripts/_domain_store.py +559 -0
- package/scripts/_event_log_reader.py +154 -0
- package/scripts/_event_schema.py +305 -0
- package/scripts/_event_store.py +397 -0
- package/scripts/_heavy_cadence.py +324 -0
- package/scripts/_integration_resolver.py +321 -0
- package/scripts/_logger.py +151 -0
- package/scripts/_loom.py +482 -0
- package/scripts/_paths.py +133 -0
- package/scripts/_python.sh +22 -0
- package/scripts/_run.py +137 -0
- package/scripts/_session.py +502 -0
- package/scripts/_validate_registry.py +1042 -0
- package/scripts/_wicked_testing_probe.py +277 -0
- package/scripts/agentic/analyze_agents.py +391 -0
- package/scripts/agentic/detect_framework.py +420 -0
- package/scripts/agentic/issue_taxonomy.py +357 -0
- package/scripts/agentic/pattern_scorer.py +434 -0
- package/scripts/classify/persist.py +169 -0
- package/scripts/compiler/compile.py +552 -0
- package/scripts/compiler/phase0/VERDICT.md +60 -0
- package/scripts/compiler/phase0/detect.py +292 -0
- package/scripts/compiler/phase0/emit.py +228 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
- package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
- package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
- package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/verdict.json +104 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
- package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
- package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
- package/scripts/compiler/phase0/run_probe.py +234 -0
- package/scripts/compiler/phase0/wire_vault.py +310 -0
- package/scripts/crew/__init__.py +0 -0
- package/scripts/crew/_task_audit_writer.py +243 -0
- package/scripts/crew/_task_reader.py +389 -0
- package/scripts/crew/archetypes_v11.py +348 -0
- package/scripts/crew/detectors/__init__.py +12 -0
- package/scripts/crew/flow_compiler.py +121 -0
- package/scripts/crew/phase_manager.py +703 -0
- package/scripts/crew/scope_delta.py +264 -0
- package/scripts/crew/specialist_resolver.py +218 -0
- package/scripts/crew/stack_registry.py +189 -0
- package/scripts/data/data_profiler.py +271 -0
- package/scripts/data/ontology_recommender.py +231 -0
- package/scripts/data/schema_validator.py +267 -0
- package/scripts/delivery/drift.py +739 -0
- package/scripts/delivery/telemetry.py +614 -0
- package/scripts/engineering/patch/codegraph_db.py +125 -0
- package/scripts/engineering/patch/generators/__init__.py +56 -0
- package/scripts/engineering/patch/generators/base.py +373 -0
- package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
- package/scripts/engineering/patch/generators/go_generator.py +430 -0
- package/scripts/engineering/patch/generators/java_generator.py +928 -0
- package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
- package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
- package/scripts/engineering/patch/generators/perl_generator.py +510 -0
- package/scripts/engineering/patch/generators/php_generator.py +644 -0
- package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
- package/scripts/engineering/patch/generators/python_generator.py +487 -0
- package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
- package/scripts/engineering/patch/generators/rust_generator.py +400 -0
- package/scripts/engineering/patch/generators/sql_generator.py +594 -0
- package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
- package/scripts/engineering/patch/patch.py +800 -0
- package/scripts/engineering/patch/safety.py +429 -0
- package/scripts/jam/__init__.py +0 -0
- package/scripts/jam/_bus_consumers.py +271 -0
- package/scripts/jam/agentic_cli_registry.py +703 -0
- package/scripts/jam/consensus.py +737 -0
- package/scripts/jam/detect_clis.py +409 -0
- package/scripts/jam/jam.py +283 -0
- package/scripts/jam/save_transcript.py +171 -0
- package/scripts/loom/__init__.py +22 -0
- package/scripts/loom/cli.py +170 -0
- package/scripts/loom/compose.py +180 -0
- package/scripts/loom/gate.py +120 -0
- package/scripts/loom/manifest.py +140 -0
- package/scripts/loom/resolve.py +59 -0
- package/scripts/persona/__init__.py +0 -0
- package/scripts/persona/registry.py +688 -0
- package/scripts/platform/guard_pipeline.py +1214 -0
- package/scripts/platform/guard_profiles.py +216 -0
- package/scripts/platform/observability/assert_contracts.py +434 -0
- package/scripts/platform/observability/health_probe.py +915 -0
- package/scripts/platform/observability/ops_log_viewer.py +209 -0
- package/scripts/platform/prereq_doctor.py +567 -0
- package/scripts/qe/conditions_manifest.py +260 -0
- package/scripts/qe/content_sanitizer.py +160 -0
- package/scripts/qe/coverage_tracker.py +535 -0
- package/scripts/qe/discover_scenarios.py +243 -0
- package/scripts/qe/evidence_tracker.py +232 -0
- package/scripts/qe/prove.py +196 -0
- package/scripts/qe/registry_lookup.py +80 -0
- package/scripts/qe/registry_store.py +176 -0
- package/scripts/qe/semantic_review.py +1005 -0
- package/scripts/qe/vault_gate.py +382 -0
- package/scripts/qe/verdict_audit.py +175 -0
- package/scripts/qe/verdict_schema.py +335 -0
- package/scripts/reset.py +220 -0
- package/scripts/resolve_path.py +22 -0
- package/scripts/sentinel/invariants.py +402 -0
- package/scripts/sentinel/pre_push.py +73 -0
- package/scripts/setup/__init__.py +1 -0
- package/scripts/setup/detect_state.py +114 -0
- package/scripts/setup/migrate_legacy.py +67 -0
- package/scripts/setup/migrate_v6_projects.py +232 -0
- package/scripts/setup/onboarding.py +114 -0
- package/scripts/smaht/_bus_consumers.py +98 -0
- package/scripts/smaht/adapters/__init__.py +83 -0
- package/scripts/smaht/adapters/brain_adapter.py +254 -0
- package/scripts/smaht/adapters/context7_adapter.py +438 -0
- package/scripts/smaht/adapters/delegation_adapter.py +104 -0
- package/scripts/smaht/adapters/domain_adapter.py +206 -0
- package/scripts/smaht/adapters/events_adapter.py +231 -0
- package/scripts/smaht/adapters/tools_adapter.py +49 -0
- package/scripts/smaht/cheatsheet_store.py +236 -0
- package/scripts/smaht/context_package.py +386 -0
- package/scripts/smaht/knowledge_graph.py +395 -0
- package/scripts/smaht/propose_skills.py +856 -0
- package/scripts/smaht/test_cheatsheet_store.py +428 -0
- package/scripts/statusline.py +151 -0
- package/scripts/where_am_i.py +236 -0
- package/skills/agentic/agentic-patterns/SKILL.md +91 -0
- package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
- package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
- package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
- package/skills/agentic/context-engineering/SKILL.md +142 -0
- package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
- package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
- package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
- package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
- package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
- package/skills/agentic/frameworks/SKILL.md +191 -0
- package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
- package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
- package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
- package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
- package/skills/agentic/refs/audit.md +134 -0
- package/skills/agentic/refs/design.md +137 -0
- package/skills/agentic/refs/frameworks.md +102 -0
- package/skills/agentic/refs/review.md +160 -0
- package/skills/agentic/review-methodology/SKILL.md +186 -0
- package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
- package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
- package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
- package/skills/agentic/trust-and-safety/SKILL.md +177 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
- package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
- package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
- package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
- package/skills/archetype/SKILL.md +104 -0
- package/skills/archetype/refs/build.md +142 -0
- package/skills/archetype/refs/decide.md +117 -0
- package/skills/archetype/refs/explore.md +66 -0
- package/skills/archetype/refs/incident.md +149 -0
- package/skills/archetype/refs/migrate.md +170 -0
- package/skills/archetype/refs/modernize.md +187 -0
- package/skills/archetype/refs/review.md +145 -0
- package/skills/archetype/refs/ship.md +117 -0
- package/skills/archetype/refs/specify.md +108 -0
- package/skills/archetype/refs/triage.md +62 -0
- package/skills/classify/SKILL.md +157 -0
- package/skills/data/analysis/SKILL.md +125 -0
- package/skills/data/analysis/refs/templates.md +170 -0
- package/skills/data/data/SKILL.md +118 -0
- package/skills/data/data/refs/examples.md +235 -0
- package/skills/data/ml/SKILL.md +125 -0
- package/skills/data/ml/refs/templates.md +172 -0
- package/skills/data/pipeline/SKILL.md +136 -0
- package/skills/data/pipeline/refs/templates.md +175 -0
- package/skills/data/refs/analyze.md +123 -0
- package/skills/data/refs/data.md +95 -0
- package/skills/data/refs/ml.md +118 -0
- package/skills/data/refs/pipeline.md +92 -0
- package/skills/deliberate/SKILL.md +125 -0
- package/skills/deliberate/refs/architecture-lens.md +37 -0
- package/skills/deliberate/refs/assumptions-lens.md +43 -0
- package/skills/deliberate/refs/code-lens.md +38 -0
- package/skills/deliberate/refs/content-lens.md +37 -0
- package/skills/deliberate/refs/data-lens.md +43 -0
- package/skills/deliberate/refs/design-lens.md +37 -0
- package/skills/deliberate/refs/opportunity-patterns.md +107 -0
- package/skills/deliberate/refs/ops-lens.md +43 -0
- package/skills/deliberate/refs/product-lens.md +46 -0
- package/skills/deliberate/refs/rethink-framework.md +77 -0
- package/skills/deliberate/refs/security-lens.md +47 -0
- package/skills/deliberate/refs/testing-lens.md +45 -0
- package/skills/deliberate/refs/timing-lens.md +42 -0
- package/skills/engineering/architecture/SKILL.md +177 -0
- package/skills/engineering/architecture/refs/adr-template.md +268 -0
- package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
- package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
- package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
- package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
- package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
- package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
- package/skills/engineering/backend/SKILL.md +102 -0
- package/skills/engineering/backend/refs/checklists.md +146 -0
- package/skills/engineering/backend/refs/patterns.md +181 -0
- package/skills/engineering/debugging/SKILL.md +99 -0
- package/skills/engineering/debugging/refs/patterns.md +248 -0
- package/skills/engineering/debugging/refs/process.md +203 -0
- package/skills/engineering/docs/SKILL.md +97 -0
- package/skills/engineering/engineering/SKILL.md +88 -0
- package/skills/engineering/engineering/refs/checklists.md +91 -0
- package/skills/engineering/engineering/refs/templates.md +71 -0
- package/skills/engineering/frontend/SKILL.md +92 -0
- package/skills/engineering/frontend/refs/checklists.md +96 -0
- package/skills/engineering/frontend/refs/patterns.md +167 -0
- package/skills/engineering/integration/SKILL.md +183 -0
- package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
- package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
- package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
- package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
- package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
- package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
- package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
- package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
- package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
- package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
- package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
- package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
- package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
- package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
- package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
- package/skills/engineering/integration/refs/grpc-testing.md +49 -0
- package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
- package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
- package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
- package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
- package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
- package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
- package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
- package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
- package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
- package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
- package/skills/engineering/large-scale-migration/SKILL.md +65 -0
- package/skills/engineering/patch/SKILL.md +184 -0
- package/skills/engineering/refs/arch.md +126 -0
- package/skills/engineering/refs/debug.md +142 -0
- package/skills/engineering/refs/docs.md +190 -0
- package/skills/engineering/refs/plan.md +109 -0
- package/skills/engineering/refs/review.md +138 -0
- package/skills/engineering/system-design/SKILL.md +154 -0
- package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
- package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
- package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
- package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
- package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
- package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
- package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
- package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
- package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
- package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
- package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
- package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
- package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
- package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
- package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
- package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
- package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
- package/skills/engineering/unit-test-quality/SKILL.md +194 -0
- package/skills/ground/SKILL.md +130 -0
- package/skills/integration-discovery/SKILL.md +168 -0
- package/skills/integration-discovery/refs/capabilities.md +282 -0
- package/skills/integration-discovery/refs/cli-detection.md +295 -0
- package/skills/integration-discovery/refs/discovery-sources.md +233 -0
- package/skills/integration-discovery/refs/task-patterns.md +206 -0
- package/skills/jam/SKILL.md +45 -0
- package/skills/jam/refs/facilitation-patterns.md +125 -0
- package/skills/jam/refs/quick.md +64 -0
- package/skills/jam/refs/synthesis-patterns.md +114 -0
- package/skills/multi-model/SKILL.md +168 -0
- package/skills/multi-model/refs/aichat.md +119 -0
- package/skills/multi-model/refs/aider.md +100 -0
- package/skills/multi-model/refs/auditability.md +238 -0
- package/skills/multi-model/refs/codex.md +169 -0
- package/skills/multi-model/refs/context.md +306 -0
- package/skills/multi-model/refs/copilot.md +161 -0
- package/skills/multi-model/refs/examples.md +224 -0
- package/skills/multi-model/refs/gemini.md +185 -0
- package/skills/multi-model/refs/goose.md +112 -0
- package/skills/multi-model/refs/llm.md +124 -0
- package/skills/multi-model/refs/opencode.md +196 -0
- package/skills/multi-model/refs/orchestration.md +188 -0
- package/skills/multi-model/refs/pi.md +208 -0
- package/skills/persona/SKILL.md +144 -0
- package/skills/persona/refs/define.md +133 -0
- package/skills/platform/actions/refs/actions.md +114 -0
- package/skills/platform/audit/SKILL.md +174 -0
- package/skills/platform/audit/refs/audit.md +145 -0
- package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
- package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
- package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
- package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
- package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
- package/skills/platform/compliance/SKILL.md +169 -0
- package/skills/platform/compliance/refs/checklists.md +303 -0
- package/skills/platform/compliance/refs/compliance.md +117 -0
- package/skills/platform/compliance/refs/frameworks.md +282 -0
- package/skills/platform/errors/SKILL.md +183 -0
- package/skills/platform/errors/refs/patterns.md +271 -0
- package/skills/platform/errors/refs/severity.md +264 -0
- package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
- package/skills/platform/gh/refs/gh.md +105 -0
- package/skills/platform/gh-cli/SKILL.md +120 -0
- package/skills/platform/gh-cli/refs/automation.md +63 -0
- package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
- package/skills/platform/gh-cli/refs/patterns.md +132 -0
- package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
- package/skills/platform/github-actions/SKILL.md +159 -0
- package/skills/platform/github-actions/refs/security.md +150 -0
- package/skills/platform/github-actions/refs/templates.md +230 -0
- package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
- package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
- package/skills/platform/gitlab-ci/SKILL.md +140 -0
- package/skills/platform/gitlab-ci/refs/templates.md +223 -0
- package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
- package/skills/platform/glab-cli/SKILL.md +133 -0
- package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
- package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
- package/skills/platform/glab-cli/refs/patterns.md +131 -0
- package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
- package/skills/platform/health/SKILL.md +177 -0
- package/skills/platform/health/refs/health.md +72 -0
- package/skills/platform/health/refs/sources.md +302 -0
- package/skills/platform/incident/refs/incident.md +136 -0
- package/skills/platform/infra/refs/infra.md +104 -0
- package/skills/platform/observability/SKILL.md +128 -0
- package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
- package/skills/platform/prereq-doctor/SKILL.md +57 -0
- package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
- package/skills/platform/traces/refs/traces.md +101 -0
- package/skills/product/acceptance-criteria/SKILL.md +193 -0
- package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
- package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
- package/skills/product/accessibility/SKILL.md +197 -0
- package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
- package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
- package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
- package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
- package/skills/product/accessibility/refs/audit-report-results.md +276 -0
- package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
- package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
- package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
- package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
- package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
- package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
- package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
- package/skills/product/analyze/SKILL.md +164 -0
- package/skills/product/analyze/refs/algorithms.md +238 -0
- package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
- package/skills/product/imagery/SKILL.md +97 -0
- package/skills/product/imagery/alter/SKILL.md +105 -0
- package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
- package/skills/product/imagery/create/SKILL.md +109 -0
- package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
- package/skills/product/imagery/create/refs/provider-reference.md +219 -0
- package/skills/product/imagery/review/SKILL.md +101 -0
- package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
- package/skills/product/imagery/review/refs/quality-gates.md +153 -0
- package/skills/product/imagery/scripts/analyze.sh +23 -0
- package/skills/product/imagery/scripts/edit.sh +14 -0
- package/skills/product/imagery/scripts/generate.sh +13 -0
- package/skills/product/imagery/scripts/provider.py +787 -0
- package/skills/product/listen/SKILL.md +175 -0
- package/skills/product/listen/refs/channels.md +220 -0
- package/skills/product/mockup/SKILL.md +106 -0
- package/skills/product/mockup/refs/templates.md +95 -0
- package/skills/product/refs/a11y.md +109 -0
- package/skills/product/refs/acceptance.md +79 -0
- package/skills/product/refs/align.md +67 -0
- package/skills/product/refs/analyze.md +77 -0
- package/skills/product/refs/elicit.md +67 -0
- package/skills/product/refs/listen.md +58 -0
- package/skills/product/refs/mockup.md +77 -0
- package/skills/product/refs/screenshot.md +59 -0
- package/skills/product/refs/strategy.md +77 -0
- package/skills/product/refs/synthesize.md +54 -0
- package/skills/product/refs/ux-review.md +68 -0
- package/skills/product/refs/ux.md +101 -0
- package/skills/product/requirements-analysis/SKILL.md +136 -0
- package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
- package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
- package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
- package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
- package/skills/product/requirements-graph/SKILL.md +155 -0
- package/skills/product/requirements-graph/refs/examples.md +223 -0
- package/skills/product/requirements-graph/refs/schema.md +162 -0
- package/skills/product/requirements-migrate/SKILL.md +90 -0
- package/skills/product/requirements-navigate/SKILL.md +141 -0
- package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
- package/skills/product/screenshot/SKILL.md +147 -0
- package/skills/product/strategy/SKILL.md +198 -0
- package/skills/product/strategy/refs/frameworks.md +295 -0
- package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
- package/skills/product/strategy/refs/templates-roi-value.md +207 -0
- package/skills/product/synthesize/SKILL.md +116 -0
- package/skills/product/synthesize/refs/journey-mapping.md +212 -0
- package/skills/product/synthesize/refs/prioritization.md +193 -0
- package/skills/product/ux-review/SKILL.md +164 -0
- package/skills/product/visual-direction/SKILL.md +137 -0
- package/skills/product/visual-review/SKILL.md +131 -0
- package/skills/runtime-exec/SKILL.md +138 -0
- package/skills/search/codebase-narrator/SKILL.md +131 -0
- package/skills/search/codebase-narrator/refs/output-template.md +100 -0
- package/skills/smaht/SKILL.md +72 -0
- package/skills/smaht/discovery/SKILL.md +65 -0
- package/skills/smaht/intent/SKILL.md +89 -0
- package/skills/smaht/propose-skills/SKILL.md +142 -0
- package/skills/smaht/refs/state.md +76 -0
- package/skills/swarm/SKILL.md +132 -0
- package/skills/swarm/refs/fan-out.md +104 -0
- package/skills/swarm/refs/independent-verification.md +86 -0
- package/skills/swarm/refs/receipts-and-evidence.md +69 -0
- package/skills/swarm/refs/recon-synthesis.md +87 -0
- package/skills/swarm/refs/ship-discipline.md +90 -0
- package/skills/wickedizer/SKILL.md +147 -0
- package/skills/wickedizer/refs/artifact-types.md +238 -0
- package/skills/wickedizer/refs/complexity.md +278 -0
- package/skills/wickedizer/refs/de-ai-pass.md +140 -0
- package/skills/wickedizer/refs/failure-modes.md +249 -0
- package/skills/wickedizer/refs/patterns.md +282 -0
- package/skills/wickedizer/refs/review.md +221 -0
- package/skills/wickedizer/refs/structure.md +282 -0
- package/skills/wickedizer/refs/voice-profile.md +125 -0
- package/skills/workflow/SKILL.md +132 -0
- package/skills/workflow/refs/archetype-adjustments.md +205 -0
- package/skills/workflow/refs/evidence.md +58 -0
- package/skills/workflow/refs/integration.md +130 -0
- package/skills/workflow/refs/risk-dimension-signals.md +260 -0
- package/skills/workflow/refs/scoring-rubric.md +49 -0
- package/skills/workflow/refs/signal-keywords.md +176 -0
- package/skills/workflow/refs/specialist-routing-rules.md +159 -0
- package/skills/worktrees/SKILL.md +87 -0
- package/skills/worktrees/refs/recipes.md +96 -0
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Java code generator.
|
|
3
|
+
|
|
4
|
+
Generates patches for Java files including:
|
|
5
|
+
- JPA entities (add/modify fields, columns)
|
|
6
|
+
- Controllers (add endpoints, mappings)
|
|
7
|
+
- Services (add methods)
|
|
8
|
+
- DTOs (add fields)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Dict, List, Optional, Set
|
|
14
|
+
import logging
|
|
15
|
+
|
|
16
|
+
from .base import (
|
|
17
|
+
BaseGenerator,
|
|
18
|
+
register_generator,
|
|
19
|
+
ChangeSpec,
|
|
20
|
+
ChangeType,
|
|
21
|
+
FieldSpec,
|
|
22
|
+
Patch,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@register_generator
|
|
29
|
+
class JavaGenerator(BaseGenerator):
|
|
30
|
+
"""Generate patches for Java files."""
|
|
31
|
+
|
|
32
|
+
name = "java"
|
|
33
|
+
extensions = {".java"}
|
|
34
|
+
symbol_types = {"entity", "entity_field", "class", "service", "controller", "dao"}
|
|
35
|
+
|
|
36
|
+
# Type mappings from generic types to Java types
|
|
37
|
+
TYPE_MAP = {
|
|
38
|
+
"string": "String",
|
|
39
|
+
"str": "String",
|
|
40
|
+
"text": "String",
|
|
41
|
+
"int": "int",
|
|
42
|
+
"integer": "Integer",
|
|
43
|
+
"long": "Long",
|
|
44
|
+
"bigint": "Long",
|
|
45
|
+
"float": "float",
|
|
46
|
+
"double": "double",
|
|
47
|
+
"decimal": "BigDecimal",
|
|
48
|
+
"boolean": "boolean",
|
|
49
|
+
"bool": "boolean",
|
|
50
|
+
"date": "LocalDate",
|
|
51
|
+
"datetime": "LocalDateTime",
|
|
52
|
+
"timestamp": "LocalDateTime",
|
|
53
|
+
"time": "LocalTime",
|
|
54
|
+
"uuid": "UUID",
|
|
55
|
+
"binary": "byte[]",
|
|
56
|
+
"blob": "byte[]",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Import mappings for types that need imports
|
|
60
|
+
IMPORT_MAP = {
|
|
61
|
+
"BigDecimal": "java.math.BigDecimal",
|
|
62
|
+
"LocalDate": "java.time.LocalDate",
|
|
63
|
+
"LocalDateTime": "java.time.LocalDateTime",
|
|
64
|
+
"LocalTime": "java.time.LocalTime",
|
|
65
|
+
"UUID": "java.util.UUID",
|
|
66
|
+
"List": "java.util.List",
|
|
67
|
+
"Set": "java.util.Set",
|
|
68
|
+
"Map": "java.util.Map",
|
|
69
|
+
"Date": "java.util.Date",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
def generate(
|
|
73
|
+
self,
|
|
74
|
+
change_spec: ChangeSpec,
|
|
75
|
+
symbol: Dict[str, Any],
|
|
76
|
+
file_content: str,
|
|
77
|
+
) -> List[Patch]:
|
|
78
|
+
"""
|
|
79
|
+
Generate patches for a Java file.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
change_spec: The change specification
|
|
83
|
+
symbol: The symbol being modified
|
|
84
|
+
file_content: Current file content
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
List of patches
|
|
88
|
+
"""
|
|
89
|
+
patches = []
|
|
90
|
+
|
|
91
|
+
if change_spec.change_type == ChangeType.ADD_FIELD:
|
|
92
|
+
patches.extend(self._add_field(change_spec, symbol, file_content))
|
|
93
|
+
elif change_spec.change_type == ChangeType.REMOVE_FIELD:
|
|
94
|
+
patches.extend(self._remove_field(change_spec, symbol, file_content))
|
|
95
|
+
elif change_spec.change_type == ChangeType.RENAME_FIELD:
|
|
96
|
+
patches.extend(self._rename_field(change_spec, symbol, file_content))
|
|
97
|
+
elif change_spec.change_type == ChangeType.MODIFY_FIELD:
|
|
98
|
+
patches.extend(self._modify_field(change_spec, symbol, file_content))
|
|
99
|
+
elif change_spec.change_type == ChangeType.ADD_VALIDATION:
|
|
100
|
+
patches.extend(self._add_validation(change_spec, symbol, file_content))
|
|
101
|
+
|
|
102
|
+
return patches
|
|
103
|
+
|
|
104
|
+
def _detect_class_role(self, symbol: Dict[str, Any], file_content: str) -> str:
|
|
105
|
+
"""Detect the role of a Java class: entity, service, controller, or dto."""
|
|
106
|
+
sym_type = symbol.get("type", "").lower()
|
|
107
|
+
if sym_type in ("service", "controller", "dao"):
|
|
108
|
+
return sym_type
|
|
109
|
+
|
|
110
|
+
name = symbol.get("name", "")
|
|
111
|
+
content_lower = file_content.lower()
|
|
112
|
+
|
|
113
|
+
if "service" in name.lower() or "@service" in content_lower:
|
|
114
|
+
return "service"
|
|
115
|
+
if "controller" in name.lower() or "@controller" in content_lower or "@restcontroller" in content_lower:
|
|
116
|
+
return "controller"
|
|
117
|
+
if "repository" in name.lower() or "@repository" in content_lower:
|
|
118
|
+
return "dao"
|
|
119
|
+
if "@entity" in content_lower or sym_type in ("entity", "entity_field"):
|
|
120
|
+
return "entity"
|
|
121
|
+
return "entity" # default
|
|
122
|
+
|
|
123
|
+
def _add_field(
|
|
124
|
+
self,
|
|
125
|
+
change_spec: ChangeSpec,
|
|
126
|
+
symbol: Dict[str, Any],
|
|
127
|
+
file_content: str,
|
|
128
|
+
) -> List[Patch]:
|
|
129
|
+
"""
|
|
130
|
+
Add a field to a Java class/entity.
|
|
131
|
+
|
|
132
|
+
For entity/DTO classes: generates field declaration + getter + setter.
|
|
133
|
+
For service/controller classes: generates validation logic instead.
|
|
134
|
+
"""
|
|
135
|
+
patches = []
|
|
136
|
+
field_spec = change_spec.field_spec
|
|
137
|
+
if not field_spec:
|
|
138
|
+
return patches
|
|
139
|
+
|
|
140
|
+
lines = file_content.split("\n")
|
|
141
|
+
file_path = symbol.get("file_path", "")
|
|
142
|
+
|
|
143
|
+
# Determine Java type
|
|
144
|
+
java_type = self._map_type(field_spec.type)
|
|
145
|
+
|
|
146
|
+
# For service/controller classes, generate validation instead of field
|
|
147
|
+
class_role = self._detect_class_role(symbol, file_content)
|
|
148
|
+
if class_role in ("service", "controller"):
|
|
149
|
+
return self._add_validation_for_field(change_spec, symbol, file_content, java_type)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Find class body insertion point (after last field declaration)
|
|
153
|
+
class_start, class_end = self._find_class_body(lines, symbol)
|
|
154
|
+
if class_start < 0:
|
|
155
|
+
return patches
|
|
156
|
+
|
|
157
|
+
# Find where to insert the field (after last field, before first method)
|
|
158
|
+
insert_line = self._find_field_insertion_point(lines, class_start, class_end)
|
|
159
|
+
indentation = self._detect_indentation(lines, class_start, class_end)
|
|
160
|
+
|
|
161
|
+
# Build field declaration
|
|
162
|
+
field_lines = self._build_field_declaration(
|
|
163
|
+
field_spec, java_type, indentation, symbol
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
patches.append(Patch(
|
|
167
|
+
file_path=file_path,
|
|
168
|
+
line_start=insert_line + 1, # Insert after this line
|
|
169
|
+
line_end=insert_line, # No lines replaced (insertion)
|
|
170
|
+
old_content="",
|
|
171
|
+
new_content="\n".join(field_lines),
|
|
172
|
+
description=f"Add field '{field_spec.name}' ({java_type})",
|
|
173
|
+
symbol_id=symbol.get("id"),
|
|
174
|
+
confidence="high",
|
|
175
|
+
))
|
|
176
|
+
|
|
177
|
+
# Find where to insert getter/setter (after existing methods or before class end)
|
|
178
|
+
method_insert_line = self._find_method_insertion_point(lines, class_start, class_end)
|
|
179
|
+
|
|
180
|
+
# Build getter
|
|
181
|
+
getter_lines = self._build_getter(field_spec, java_type, indentation)
|
|
182
|
+
patches.append(Patch(
|
|
183
|
+
file_path=file_path,
|
|
184
|
+
line_start=method_insert_line + 1,
|
|
185
|
+
line_end=method_insert_line,
|
|
186
|
+
old_content="",
|
|
187
|
+
new_content="\n".join(getter_lines),
|
|
188
|
+
description=f"Add getter for '{field_spec.name}'",
|
|
189
|
+
symbol_id=symbol.get("id"),
|
|
190
|
+
confidence="high",
|
|
191
|
+
))
|
|
192
|
+
|
|
193
|
+
# Build setter (same insertion point as getter — descending sort
|
|
194
|
+
# in patches_by_file() will place setter after getter, both inside class)
|
|
195
|
+
setter_lines = self._build_setter(field_spec, java_type, indentation)
|
|
196
|
+
patches.append(Patch(
|
|
197
|
+
file_path=file_path,
|
|
198
|
+
line_start=method_insert_line + 1,
|
|
199
|
+
line_end=method_insert_line,
|
|
200
|
+
old_content="",
|
|
201
|
+
new_content="\n".join(setter_lines),
|
|
202
|
+
description=f"Add setter for '{field_spec.name}'",
|
|
203
|
+
symbol_id=symbol.get("id"),
|
|
204
|
+
confidence="high",
|
|
205
|
+
))
|
|
206
|
+
|
|
207
|
+
# Add imports if needed
|
|
208
|
+
import_patch = self._add_imports(java_type, lines, file_path)
|
|
209
|
+
if import_patch:
|
|
210
|
+
patches.insert(0, import_patch) # Imports first
|
|
211
|
+
|
|
212
|
+
return patches
|
|
213
|
+
|
|
214
|
+
def _remove_field(
|
|
215
|
+
self,
|
|
216
|
+
change_spec: ChangeSpec,
|
|
217
|
+
symbol: Dict[str, Any],
|
|
218
|
+
file_content: str,
|
|
219
|
+
) -> List[Patch]:
|
|
220
|
+
"""Remove a field and its getter/setter, or remove usages in non-owner files."""
|
|
221
|
+
patches = []
|
|
222
|
+
field_name = change_spec.old_name or (change_spec.field_spec.name if change_spec.field_spec else None)
|
|
223
|
+
if not field_name:
|
|
224
|
+
return patches
|
|
225
|
+
|
|
226
|
+
lines = file_content.split("\n")
|
|
227
|
+
file_path = symbol.get("file_path", "")
|
|
228
|
+
class_role = self._detect_class_role(symbol, file_content)
|
|
229
|
+
|
|
230
|
+
# Find field declaration (present in owner files: entity, DTO)
|
|
231
|
+
field_start, field_end = self._find_field_declaration(lines, field_name)
|
|
232
|
+
|
|
233
|
+
if field_start >= 0:
|
|
234
|
+
# Owner file: remove field declaration + getter + setter
|
|
235
|
+
patches.append(Patch(
|
|
236
|
+
file_path=file_path,
|
|
237
|
+
line_start=field_start + 1,
|
|
238
|
+
line_end=field_end + 1,
|
|
239
|
+
old_content="\n".join(lines[field_start:field_end + 1]),
|
|
240
|
+
new_content="",
|
|
241
|
+
description=f"Remove field '{field_name}'",
|
|
242
|
+
symbol_id=symbol.get("id"),
|
|
243
|
+
confidence="high",
|
|
244
|
+
))
|
|
245
|
+
|
|
246
|
+
# Find and remove getter
|
|
247
|
+
getter_name = f"get{self._capitalize(field_name)}"
|
|
248
|
+
getter_start, getter_end = self._find_method(lines, getter_name)
|
|
249
|
+
if getter_start >= 0:
|
|
250
|
+
patches.append(Patch(
|
|
251
|
+
file_path=file_path,
|
|
252
|
+
line_start=getter_start + 1,
|
|
253
|
+
line_end=getter_end + 1,
|
|
254
|
+
old_content="\n".join(lines[getter_start:getter_end + 1]),
|
|
255
|
+
new_content="",
|
|
256
|
+
description=f"Remove getter '{getter_name}'",
|
|
257
|
+
symbol_id=symbol.get("id"),
|
|
258
|
+
confidence="high",
|
|
259
|
+
))
|
|
260
|
+
|
|
261
|
+
# Find and remove setter
|
|
262
|
+
setter_name = f"set{self._capitalize(field_name)}"
|
|
263
|
+
setter_start, setter_end = self._find_method(lines, setter_name)
|
|
264
|
+
if setter_start >= 0:
|
|
265
|
+
patches.append(Patch(
|
|
266
|
+
file_path=file_path,
|
|
267
|
+
line_start=setter_start + 1,
|
|
268
|
+
line_end=setter_end + 1,
|
|
269
|
+
old_content="\n".join(lines[setter_start:setter_end + 1]),
|
|
270
|
+
new_content="",
|
|
271
|
+
description=f"Remove setter '{setter_name}'",
|
|
272
|
+
symbol_id=symbol.get("id"),
|
|
273
|
+
confidence="high",
|
|
274
|
+
))
|
|
275
|
+
else:
|
|
276
|
+
# Non-owner file (service, repository, test): remove methods that
|
|
277
|
+
# exclusively use this field's getter/setter, or remove usage lines
|
|
278
|
+
getter_name = f"get{self._capitalize(field_name)}"
|
|
279
|
+
setter_name = f"set{self._capitalize(field_name)}"
|
|
280
|
+
accessor_names = [getter_name, setter_name]
|
|
281
|
+
|
|
282
|
+
patches.extend(
|
|
283
|
+
self._remove_accessor_usages(lines, accessor_names, file_path, symbol)
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
return patches
|
|
287
|
+
|
|
288
|
+
def _remove_accessor_usages(
|
|
289
|
+
self,
|
|
290
|
+
lines: List[str],
|
|
291
|
+
accessor_names: List[str],
|
|
292
|
+
file_path: str,
|
|
293
|
+
symbol: Dict[str, Any],
|
|
294
|
+
) -> List[Patch]:
|
|
295
|
+
"""Remove methods that use deprecated field accessors in non-owner files.
|
|
296
|
+
|
|
297
|
+
Two-pass approach:
|
|
298
|
+
1. Find methods containing accessor calls
|
|
299
|
+
2. If method body is simple (accessor is the primary logic), remove entire method
|
|
300
|
+
Otherwise, remove just the accessor lines
|
|
301
|
+
"""
|
|
302
|
+
patches = []
|
|
303
|
+
removed_methods = set() # Track method-start lines scheduled for full removal
|
|
304
|
+
removed_lines = set() # Track individual lines scheduled for removal
|
|
305
|
+
|
|
306
|
+
for accessor_name in accessor_names:
|
|
307
|
+
# Find all methods that contain calls to this accessor
|
|
308
|
+
i = 0
|
|
309
|
+
while i < len(lines):
|
|
310
|
+
if accessor_name + "(" in lines[i]:
|
|
311
|
+
# Check if this line is inside a method
|
|
312
|
+
method_start = self._find_enclosing_method_start(lines, i)
|
|
313
|
+
if method_start >= 0 and method_start not in removed_methods:
|
|
314
|
+
method_end = self._find_method_end_from(lines, method_start)
|
|
315
|
+
if method_end >= 0:
|
|
316
|
+
# Count how many non-trivial lines are in the method body
|
|
317
|
+
body_lines = [
|
|
318
|
+
l.strip() for l in lines[method_start + 1:method_end]
|
|
319
|
+
if l.strip() and not l.strip().startswith("//") and l.strip() != "{"
|
|
320
|
+
]
|
|
321
|
+
# Count lines that DON'T reference any of the accessors
|
|
322
|
+
non_accessor_lines = [
|
|
323
|
+
l for l in body_lines
|
|
324
|
+
if not any(a + "(" in l for a in accessor_names)
|
|
325
|
+
and l != "}" and l != "{"
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
if len(non_accessor_lines) == 0:
|
|
329
|
+
# Method exclusively uses this accessor — remove entire method
|
|
330
|
+
removed_methods.add(method_start)
|
|
331
|
+
patches.append(Patch(
|
|
332
|
+
file_path=file_path,
|
|
333
|
+
line_start=method_start + 1,
|
|
334
|
+
line_end=method_end + 1,
|
|
335
|
+
old_content="\n".join(lines[method_start:method_end + 1]),
|
|
336
|
+
new_content="",
|
|
337
|
+
description=f"Remove method using deprecated accessor '{accessor_name}'",
|
|
338
|
+
symbol_id=symbol.get("id"),
|
|
339
|
+
confidence="medium",
|
|
340
|
+
))
|
|
341
|
+
else:
|
|
342
|
+
# Mixed method — remove just the lines with accessor calls
|
|
343
|
+
for j in range(method_start, method_end + 1):
|
|
344
|
+
if any(a + "(" in lines[j] for a in accessor_names):
|
|
345
|
+
if j not in removed_lines:
|
|
346
|
+
removed_lines.add(j)
|
|
347
|
+
patches.append(Patch(
|
|
348
|
+
file_path=file_path,
|
|
349
|
+
line_start=j + 1,
|
|
350
|
+
line_end=j + 1,
|
|
351
|
+
old_content=lines[j],
|
|
352
|
+
new_content="",
|
|
353
|
+
description=f"Remove usage of deprecated accessor '{accessor_name}'",
|
|
354
|
+
symbol_id=symbol.get("id"),
|
|
355
|
+
confidence="low",
|
|
356
|
+
))
|
|
357
|
+
i += 1
|
|
358
|
+
|
|
359
|
+
return patches
|
|
360
|
+
|
|
361
|
+
def _find_enclosing_method_start(self, lines: List[str], line_idx: int) -> int:
|
|
362
|
+
"""Walk backward from a line to find the enclosing method signature."""
|
|
363
|
+
brace_count = 0
|
|
364
|
+
for i in range(line_idx, -1, -1):
|
|
365
|
+
brace_count += lines[i].count("}") - lines[i].count("{")
|
|
366
|
+
stripped = lines[i].strip()
|
|
367
|
+
if re.match(r'((public|private|protected)\s+)?\w+\s+\w+\s*\(', stripped):
|
|
368
|
+
# Found a method signature — verify we're inside it
|
|
369
|
+
if brace_count <= 0:
|
|
370
|
+
return i
|
|
371
|
+
return -1
|
|
372
|
+
|
|
373
|
+
def _find_method_end_from(self, lines: List[str], method_start: int) -> int:
|
|
374
|
+
"""Find the end of a method starting from the method signature line."""
|
|
375
|
+
brace_count = 0
|
|
376
|
+
for i in range(method_start, len(lines)):
|
|
377
|
+
brace_count += lines[i].count("{") - lines[i].count("}")
|
|
378
|
+
if i > method_start and brace_count <= 0:
|
|
379
|
+
return i
|
|
380
|
+
return -1
|
|
381
|
+
|
|
382
|
+
def _rename_field(
|
|
383
|
+
self,
|
|
384
|
+
change_spec: ChangeSpec,
|
|
385
|
+
symbol: Dict[str, Any],
|
|
386
|
+
file_content: str,
|
|
387
|
+
) -> List[Patch]:
|
|
388
|
+
"""Rename a field and update getter/setter."""
|
|
389
|
+
patches = []
|
|
390
|
+
old_name = change_spec.old_name
|
|
391
|
+
new_name = change_spec.new_name
|
|
392
|
+
if not old_name or not new_name:
|
|
393
|
+
return patches
|
|
394
|
+
|
|
395
|
+
lines = file_content.split("\n")
|
|
396
|
+
file_path = symbol.get("file_path", "")
|
|
397
|
+
|
|
398
|
+
# Find and rename field declaration
|
|
399
|
+
for i, line in enumerate(lines):
|
|
400
|
+
# Match field declaration: private Type fieldName;
|
|
401
|
+
pattern = rf"(\s*(?:private|protected|public)\s+\w+\s+){old_name}(\s*[;=])"
|
|
402
|
+
match = re.search(pattern, line)
|
|
403
|
+
if match:
|
|
404
|
+
new_line = re.sub(pattern, rf"\1{new_name}\2", line)
|
|
405
|
+
patches.append(Patch(
|
|
406
|
+
file_path=file_path,
|
|
407
|
+
line_start=i + 1,
|
|
408
|
+
line_end=i + 1,
|
|
409
|
+
old_content=line,
|
|
410
|
+
new_content=new_line,
|
|
411
|
+
description=f"Rename field '{old_name}' to '{new_name}'",
|
|
412
|
+
symbol_id=symbol.get("id"),
|
|
413
|
+
confidence="high",
|
|
414
|
+
))
|
|
415
|
+
break
|
|
416
|
+
|
|
417
|
+
# Rename getter
|
|
418
|
+
old_getter = f"get{self._capitalize(old_name)}"
|
|
419
|
+
new_getter = f"get{self._capitalize(new_name)}"
|
|
420
|
+
for i, line in enumerate(lines):
|
|
421
|
+
if old_getter in line and "(" in line:
|
|
422
|
+
new_line = line.replace(old_getter, new_getter)
|
|
423
|
+
patches.append(Patch(
|
|
424
|
+
file_path=file_path,
|
|
425
|
+
line_start=i + 1,
|
|
426
|
+
line_end=i + 1,
|
|
427
|
+
old_content=line,
|
|
428
|
+
new_content=new_line,
|
|
429
|
+
description=f"Rename getter '{old_getter}' to '{new_getter}'",
|
|
430
|
+
symbol_id=symbol.get("id"),
|
|
431
|
+
confidence="high",
|
|
432
|
+
))
|
|
433
|
+
|
|
434
|
+
# Rename setter
|
|
435
|
+
old_setter = f"set{self._capitalize(old_name)}"
|
|
436
|
+
new_setter = f"set{self._capitalize(new_name)}"
|
|
437
|
+
for i, line in enumerate(lines):
|
|
438
|
+
if old_setter in line and "(" in line:
|
|
439
|
+
new_line = line.replace(old_setter, new_setter)
|
|
440
|
+
# Also rename the parameter: (Type oldName) -> (Type newName)
|
|
441
|
+
new_line = re.sub(
|
|
442
|
+
rf'\(\s*([^)]+?)\s+{re.escape(old_name)}\s*\)',
|
|
443
|
+
rf'(\1 {new_name})',
|
|
444
|
+
new_line
|
|
445
|
+
)
|
|
446
|
+
patches.append(Patch(
|
|
447
|
+
file_path=file_path,
|
|
448
|
+
line_start=i + 1,
|
|
449
|
+
line_end=i + 1,
|
|
450
|
+
old_content=line,
|
|
451
|
+
new_content=new_line,
|
|
452
|
+
description=f"Rename setter '{old_setter}' to '{new_setter}' and parameter",
|
|
453
|
+
symbol_id=symbol.get("id"),
|
|
454
|
+
confidence="high",
|
|
455
|
+
))
|
|
456
|
+
|
|
457
|
+
# Update all usages of field within the file (this.field, bare field refs)
|
|
458
|
+
class_start, class_end = self._find_class_body(lines, symbol)
|
|
459
|
+
for i, line in enumerate(lines):
|
|
460
|
+
# Skip lines already patched
|
|
461
|
+
if any(p.line_start == i + 1 for p in patches):
|
|
462
|
+
continue
|
|
463
|
+
|
|
464
|
+
new_line = line
|
|
465
|
+
modified = False
|
|
466
|
+
|
|
467
|
+
# Match this.fieldName
|
|
468
|
+
if f"this.{old_name}" in line:
|
|
469
|
+
new_line = new_line.replace(f"this.{old_name}", f"this.{new_name}")
|
|
470
|
+
modified = True
|
|
471
|
+
|
|
472
|
+
# Match bare field references inside class body (word boundary)
|
|
473
|
+
if class_start >= 0 and class_start < i <= class_end:
|
|
474
|
+
if re.search(rf'\b{re.escape(old_name)}\b', new_line):
|
|
475
|
+
# Only replace if it's clearly a field ref (not in string literals,
|
|
476
|
+
# not a type name, not a local variable declaration)
|
|
477
|
+
stripped = new_line.strip()
|
|
478
|
+
# Skip lines that declare the field or import statements
|
|
479
|
+
if not re.match(r'(private|protected|public)\s+\w+\s+' + re.escape(old_name), stripped) \
|
|
480
|
+
and not stripped.startswith("import "):
|
|
481
|
+
new_line = re.sub(rf'\b{re.escape(old_name)}\b', new_name, new_line)
|
|
482
|
+
modified = True
|
|
483
|
+
|
|
484
|
+
if modified:
|
|
485
|
+
patches.append(Patch(
|
|
486
|
+
file_path=file_path,
|
|
487
|
+
line_start=i + 1,
|
|
488
|
+
line_end=i + 1,
|
|
489
|
+
old_content=line,
|
|
490
|
+
new_content=new_line,
|
|
491
|
+
description=f"Update field reference '{old_name}' to '{new_name}'",
|
|
492
|
+
symbol_id=symbol.get("id"),
|
|
493
|
+
confidence="medium",
|
|
494
|
+
))
|
|
495
|
+
|
|
496
|
+
return patches
|
|
497
|
+
|
|
498
|
+
def _modify_field(
|
|
499
|
+
self,
|
|
500
|
+
change_spec: ChangeSpec,
|
|
501
|
+
symbol: Dict[str, Any],
|
|
502
|
+
file_content: str,
|
|
503
|
+
) -> List[Patch]:
|
|
504
|
+
"""Modify a field's type or annotations."""
|
|
505
|
+
patches = []
|
|
506
|
+
field_spec = change_spec.field_spec
|
|
507
|
+
if not field_spec:
|
|
508
|
+
return patches
|
|
509
|
+
|
|
510
|
+
lines = file_content.split("\n")
|
|
511
|
+
file_path = symbol.get("file_path", "")
|
|
512
|
+
|
|
513
|
+
# Find field declaration
|
|
514
|
+
field_start, field_end = self._find_field_declaration(lines, field_spec.name)
|
|
515
|
+
if field_start < 0:
|
|
516
|
+
return patches
|
|
517
|
+
|
|
518
|
+
# Build new field declaration
|
|
519
|
+
indentation = self._get_indentation(lines[field_start])
|
|
520
|
+
java_type = self._map_type(field_spec.type)
|
|
521
|
+
new_field_lines = self._build_field_declaration(
|
|
522
|
+
field_spec, java_type, indentation, symbol
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
patches.append(Patch(
|
|
526
|
+
file_path=file_path,
|
|
527
|
+
line_start=field_start + 1,
|
|
528
|
+
line_end=field_end + 1,
|
|
529
|
+
old_content="\n".join(lines[field_start:field_end + 1]),
|
|
530
|
+
new_content="\n".join(new_field_lines),
|
|
531
|
+
description=f"Modify field '{field_spec.name}'",
|
|
532
|
+
symbol_id=symbol.get("id"),
|
|
533
|
+
confidence="high",
|
|
534
|
+
))
|
|
535
|
+
|
|
536
|
+
return patches
|
|
537
|
+
|
|
538
|
+
def _add_validation(
|
|
539
|
+
self,
|
|
540
|
+
change_spec: ChangeSpec,
|
|
541
|
+
symbol: Dict[str, Any],
|
|
542
|
+
file_content: str,
|
|
543
|
+
) -> List[Patch]:
|
|
544
|
+
"""Add validation annotations to a field."""
|
|
545
|
+
patches = []
|
|
546
|
+
field_spec = change_spec.field_spec
|
|
547
|
+
if not field_spec or not field_spec.validation:
|
|
548
|
+
return patches
|
|
549
|
+
|
|
550
|
+
lines = file_content.split("\n")
|
|
551
|
+
file_path = symbol.get("file_path", "")
|
|
552
|
+
|
|
553
|
+
# Find field declaration
|
|
554
|
+
field_start, _ = self._find_field_declaration(lines, field_spec.name)
|
|
555
|
+
if field_start < 0:
|
|
556
|
+
return patches
|
|
557
|
+
|
|
558
|
+
# Build validation annotations
|
|
559
|
+
indentation = self._get_indentation(lines[field_start])
|
|
560
|
+
validation_lines = self._build_validation_annotations(
|
|
561
|
+
field_spec.validation, indentation
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
if validation_lines:
|
|
565
|
+
patches.append(Patch(
|
|
566
|
+
file_path=file_path,
|
|
567
|
+
line_start=field_start + 1,
|
|
568
|
+
line_end=field_start, # Insert before field
|
|
569
|
+
old_content="",
|
|
570
|
+
new_content="\n".join(validation_lines),
|
|
571
|
+
description=f"Add validation to '{field_spec.name}'",
|
|
572
|
+
symbol_id=symbol.get("id"),
|
|
573
|
+
confidence="high",
|
|
574
|
+
))
|
|
575
|
+
|
|
576
|
+
return patches
|
|
577
|
+
|
|
578
|
+
def _add_validation_for_field(
|
|
579
|
+
self,
|
|
580
|
+
change_spec: ChangeSpec,
|
|
581
|
+
symbol: Dict[str, Any],
|
|
582
|
+
file_content: str,
|
|
583
|
+
java_type: str,
|
|
584
|
+
) -> List[Patch]:
|
|
585
|
+
"""Add validation logic to a service/controller for a new field."""
|
|
586
|
+
patches = []
|
|
587
|
+
field_spec = change_spec.field_spec
|
|
588
|
+
if not field_spec:
|
|
589
|
+
return patches
|
|
590
|
+
|
|
591
|
+
lines = file_content.split("\n")
|
|
592
|
+
file_path = symbol.get("file_path", "")
|
|
593
|
+
class_start, class_end = self._find_class_body(lines, symbol)
|
|
594
|
+
if class_start < 0:
|
|
595
|
+
return patches
|
|
596
|
+
|
|
597
|
+
indentation = self._detect_indentation(lines, class_start, class_end)
|
|
598
|
+
getter_name = f"get{self._capitalize(field_spec.name)}"
|
|
599
|
+
|
|
600
|
+
# Find a validate method and extract its parameter name
|
|
601
|
+
validate_method_end = -1
|
|
602
|
+
param_name = None
|
|
603
|
+
for i in range(class_start + 1, class_end):
|
|
604
|
+
if "validate" in lines[i].lower() and "(" in lines[i]:
|
|
605
|
+
# Extract parameter name from method signature
|
|
606
|
+
param_match = re.search(r'\(\s*\w+\s+(\w+)\s*\)', lines[i])
|
|
607
|
+
if param_match:
|
|
608
|
+
param_name = param_match.group(1)
|
|
609
|
+
# Find end of this method (j > i ensures we're past the opening brace)
|
|
610
|
+
brace_count = 0
|
|
611
|
+
for j in range(i, class_end + 1):
|
|
612
|
+
brace_count += lines[j].count("{") - lines[j].count("}")
|
|
613
|
+
if j > i and brace_count <= 0:
|
|
614
|
+
validate_method_end = j
|
|
615
|
+
break
|
|
616
|
+
break
|
|
617
|
+
|
|
618
|
+
if validate_method_end > 0:
|
|
619
|
+
# Insert validation check before the closing brace of the validate method
|
|
620
|
+
insert_at = validate_method_end - 1
|
|
621
|
+
else:
|
|
622
|
+
# Insert as a new method before class closing brace
|
|
623
|
+
insert_at = class_end - 1
|
|
624
|
+
|
|
625
|
+
# Derive the object variable name: from method parameter, class name, or generic
|
|
626
|
+
if not param_name:
|
|
627
|
+
class_name = symbol.get("name", "")
|
|
628
|
+
if class_name.endswith("Service"):
|
|
629
|
+
entity = class_name[:-len("Service")]
|
|
630
|
+
elif class_name.endswith("Controller"):
|
|
631
|
+
entity = class_name[:-len("Controller")]
|
|
632
|
+
else:
|
|
633
|
+
entity = class_name
|
|
634
|
+
param_name = entity[0].lower() + entity[1:] if entity else "request"
|
|
635
|
+
|
|
636
|
+
# Build validation code
|
|
637
|
+
if not field_spec.nullable:
|
|
638
|
+
validation_lines = [
|
|
639
|
+
"",
|
|
640
|
+
f"{indentation}// Validate {field_spec.name}",
|
|
641
|
+
f"{indentation}if ({param_name}.{getter_name}() == null || {param_name}.{getter_name}().isEmpty()) {{",
|
|
642
|
+
f'{indentation} throw new IllegalArgumentException("{self._capitalize(field_spec.name)} is required");',
|
|
643
|
+
f"{indentation}}}",
|
|
644
|
+
]
|
|
645
|
+
else:
|
|
646
|
+
validation_lines = [
|
|
647
|
+
"",
|
|
648
|
+
f"{indentation}// Validate {field_spec.name} if provided",
|
|
649
|
+
f"{indentation}if ({param_name}.{getter_name}() != null && {param_name}.{getter_name}().isEmpty()) {{",
|
|
650
|
+
f'{indentation} throw new IllegalArgumentException("{self._capitalize(field_spec.name)} cannot be empty");',
|
|
651
|
+
f"{indentation}}}",
|
|
652
|
+
]
|
|
653
|
+
|
|
654
|
+
patches.append(Patch(
|
|
655
|
+
file_path=file_path,
|
|
656
|
+
line_start=insert_at + 1,
|
|
657
|
+
line_end=insert_at,
|
|
658
|
+
old_content="",
|
|
659
|
+
new_content="\n".join(validation_lines),
|
|
660
|
+
description=f"Add validation for '{field_spec.name}' in service",
|
|
661
|
+
symbol_id=symbol.get("id"),
|
|
662
|
+
confidence="medium",
|
|
663
|
+
))
|
|
664
|
+
|
|
665
|
+
return patches
|
|
666
|
+
|
|
667
|
+
# Helper methods
|
|
668
|
+
|
|
669
|
+
def _map_type(self, generic_type: str, language: str = None) -> str:
|
|
670
|
+
"""Map generic type to Java type."""
|
|
671
|
+
return self.TYPE_MAP.get(generic_type.lower(), generic_type)
|
|
672
|
+
|
|
673
|
+
def _capitalize(self, name: str) -> str:
|
|
674
|
+
"""Capitalize first letter for getter/setter names."""
|
|
675
|
+
return name[0].upper() + name[1:] if name else name
|
|
676
|
+
|
|
677
|
+
def _find_class_body(self, lines: List[str], symbol: Dict[str, Any]) -> tuple:
|
|
678
|
+
"""Find the start and end of the class body."""
|
|
679
|
+
class_name = symbol.get("name", "")
|
|
680
|
+
start = -1
|
|
681
|
+
end = -1
|
|
682
|
+
brace_count = 0
|
|
683
|
+
in_class = False
|
|
684
|
+
|
|
685
|
+
for i, line in enumerate(lines):
|
|
686
|
+
if f"class {class_name}" in line:
|
|
687
|
+
in_class = True
|
|
688
|
+
if "{" in line:
|
|
689
|
+
brace_count = 1
|
|
690
|
+
start = i
|
|
691
|
+
elif in_class:
|
|
692
|
+
brace_count += line.count("{") - line.count("}")
|
|
693
|
+
if brace_count == 1 and start < 0:
|
|
694
|
+
start = i
|
|
695
|
+
elif brace_count == 0:
|
|
696
|
+
end = i
|
|
697
|
+
break
|
|
698
|
+
|
|
699
|
+
return start, end
|
|
700
|
+
|
|
701
|
+
def _find_field_insertion_point(
|
|
702
|
+
self,
|
|
703
|
+
lines: List[str],
|
|
704
|
+
class_start: int,
|
|
705
|
+
class_end: int
|
|
706
|
+
) -> int:
|
|
707
|
+
"""Find the line after which to insert a new field."""
|
|
708
|
+
last_field_line = class_start + 1 # Default: after class opening
|
|
709
|
+
|
|
710
|
+
for i in range(class_start + 1, class_end):
|
|
711
|
+
line = lines[i].strip()
|
|
712
|
+
# Skip comments and blank lines
|
|
713
|
+
if not line or line.startswith("//") or line.startswith("/*"):
|
|
714
|
+
continue
|
|
715
|
+
# Check if this is a field declaration
|
|
716
|
+
if re.match(r"(private|protected|public)\s+\w+\s+\w+\s*[;=]", line):
|
|
717
|
+
last_field_line = i
|
|
718
|
+
# Stop at first method
|
|
719
|
+
elif re.match(r"(private|protected|public)\s+\w+\s+\w+\s*\(", line):
|
|
720
|
+
break
|
|
721
|
+
|
|
722
|
+
return last_field_line
|
|
723
|
+
|
|
724
|
+
def _find_method_insertion_point(
|
|
725
|
+
self,
|
|
726
|
+
lines: List[str],
|
|
727
|
+
class_start: int,
|
|
728
|
+
class_end: int
|
|
729
|
+
) -> int:
|
|
730
|
+
"""Find the line after which to insert new methods."""
|
|
731
|
+
return class_end - 1 # Before closing brace
|
|
732
|
+
|
|
733
|
+
def _detect_indentation(
|
|
734
|
+
self,
|
|
735
|
+
lines: List[str],
|
|
736
|
+
class_start: int,
|
|
737
|
+
class_end: int
|
|
738
|
+
) -> str:
|
|
739
|
+
"""Detect the indentation used in the class body."""
|
|
740
|
+
for i in range(class_start + 1, class_end):
|
|
741
|
+
line = lines[i]
|
|
742
|
+
if line.strip() and not line.strip().startswith("//"):
|
|
743
|
+
return self._get_indentation(line)
|
|
744
|
+
return " " # Default to 4 spaces
|
|
745
|
+
|
|
746
|
+
def _build_field_declaration(
|
|
747
|
+
self,
|
|
748
|
+
field_spec: FieldSpec,
|
|
749
|
+
java_type: str,
|
|
750
|
+
indentation: str,
|
|
751
|
+
symbol: Dict[str, Any]
|
|
752
|
+
) -> List[str]:
|
|
753
|
+
"""Build field declaration with annotations."""
|
|
754
|
+
lines = []
|
|
755
|
+
metadata = symbol.get("metadata", {})
|
|
756
|
+
is_entity = "Entity" in metadata.get("annotations", [])
|
|
757
|
+
|
|
758
|
+
# Add JPA column annotation for entities
|
|
759
|
+
if is_entity:
|
|
760
|
+
column_name = field_spec.column_name or self._to_snake_case(field_spec.name).upper()
|
|
761
|
+
lines.append(f'{indentation}@Column(name = "{column_name}")')
|
|
762
|
+
|
|
763
|
+
# Add nullable constraint
|
|
764
|
+
if not field_spec.nullable:
|
|
765
|
+
lines.append(f'{indentation}@NotNull')
|
|
766
|
+
|
|
767
|
+
# Add custom annotations
|
|
768
|
+
for annotation in field_spec.annotations:
|
|
769
|
+
lines.append(f"{indentation}@{annotation}")
|
|
770
|
+
|
|
771
|
+
# Field declaration
|
|
772
|
+
default_value = ""
|
|
773
|
+
if field_spec.default:
|
|
774
|
+
default_value = f" = {field_spec.default}"
|
|
775
|
+
|
|
776
|
+
lines.append(f"{indentation}private {java_type} {field_spec.name}{default_value};")
|
|
777
|
+
lines.append("") # Blank line after field
|
|
778
|
+
|
|
779
|
+
return lines
|
|
780
|
+
|
|
781
|
+
def _build_getter(
|
|
782
|
+
self,
|
|
783
|
+
field_spec: FieldSpec,
|
|
784
|
+
java_type: str,
|
|
785
|
+
indentation: str
|
|
786
|
+
) -> List[str]:
|
|
787
|
+
"""Build getter method."""
|
|
788
|
+
method_name = f"get{self._capitalize(field_spec.name)}"
|
|
789
|
+
return [
|
|
790
|
+
"",
|
|
791
|
+
f"{indentation}public {java_type} {method_name}() {{",
|
|
792
|
+
f"{indentation} return this.{field_spec.name};",
|
|
793
|
+
f"{indentation}}}",
|
|
794
|
+
]
|
|
795
|
+
|
|
796
|
+
def _build_setter(
|
|
797
|
+
self,
|
|
798
|
+
field_spec: FieldSpec,
|
|
799
|
+
java_type: str,
|
|
800
|
+
indentation: str
|
|
801
|
+
) -> List[str]:
|
|
802
|
+
"""Build setter method."""
|
|
803
|
+
method_name = f"set{self._capitalize(field_spec.name)}"
|
|
804
|
+
return [
|
|
805
|
+
"",
|
|
806
|
+
f"{indentation}public void {method_name}({java_type} {field_spec.name}) {{",
|
|
807
|
+
f"{indentation} this.{field_spec.name} = {field_spec.name};",
|
|
808
|
+
f"{indentation}}}",
|
|
809
|
+
]
|
|
810
|
+
|
|
811
|
+
def _build_validation_annotations(
|
|
812
|
+
self,
|
|
813
|
+
validation: Dict[str, Any],
|
|
814
|
+
indentation: str
|
|
815
|
+
) -> List[str]:
|
|
816
|
+
"""Build validation annotations from spec."""
|
|
817
|
+
lines = []
|
|
818
|
+
|
|
819
|
+
if validation.get("required"):
|
|
820
|
+
lines.append(f"{indentation}@NotNull")
|
|
821
|
+
|
|
822
|
+
if "min" in validation:
|
|
823
|
+
lines.append(f'{indentation}@Min({validation["min"]})')
|
|
824
|
+
|
|
825
|
+
if "max" in validation:
|
|
826
|
+
lines.append(f'{indentation}@Max({validation["max"]})')
|
|
827
|
+
|
|
828
|
+
if "minLength" in validation:
|
|
829
|
+
lines.append(f'{indentation}@Size(min = {validation["minLength"]})')
|
|
830
|
+
|
|
831
|
+
if "maxLength" in validation:
|
|
832
|
+
if "minLength" in validation:
|
|
833
|
+
lines[-1] = f'{indentation}@Size(min = {validation["minLength"]}, max = {validation["maxLength"]})'
|
|
834
|
+
else:
|
|
835
|
+
lines.append(f'{indentation}@Size(max = {validation["maxLength"]})')
|
|
836
|
+
|
|
837
|
+
if "pattern" in validation:
|
|
838
|
+
lines.append(f'{indentation}@Pattern(regexp = "{validation["pattern"]}")')
|
|
839
|
+
|
|
840
|
+
if validation.get("email"):
|
|
841
|
+
lines.append(f"{indentation}@Email")
|
|
842
|
+
|
|
843
|
+
return lines
|
|
844
|
+
|
|
845
|
+
def _find_field_declaration(
|
|
846
|
+
self,
|
|
847
|
+
lines: List[str],
|
|
848
|
+
field_name: str
|
|
849
|
+
) -> tuple:
|
|
850
|
+
"""Find the start and end lines of a field declaration."""
|
|
851
|
+
for i, line in enumerate(lines):
|
|
852
|
+
# Match field declaration
|
|
853
|
+
if re.search(rf"\s+{field_name}\s*[;=]", line):
|
|
854
|
+
# Check for annotations above
|
|
855
|
+
start = i
|
|
856
|
+
while start > 0 and lines[start - 1].strip().startswith("@"):
|
|
857
|
+
start -= 1
|
|
858
|
+
# Field is typically one line
|
|
859
|
+
return start, i
|
|
860
|
+
return -1, -1
|
|
861
|
+
|
|
862
|
+
def _find_method(self, lines: List[str], method_name: str) -> tuple:
|
|
863
|
+
"""Find the start and end lines of a method."""
|
|
864
|
+
start = -1
|
|
865
|
+
brace_count = 0
|
|
866
|
+
|
|
867
|
+
for i, line in enumerate(lines):
|
|
868
|
+
if start < 0 and f"{method_name}(" in line:
|
|
869
|
+
start = i
|
|
870
|
+
brace_count = line.count("{") - line.count("}")
|
|
871
|
+
elif start >= 0:
|
|
872
|
+
brace_count += line.count("{") - line.count("}")
|
|
873
|
+
if brace_count <= 0:
|
|
874
|
+
return start, i
|
|
875
|
+
|
|
876
|
+
return -1, -1
|
|
877
|
+
|
|
878
|
+
def _add_imports(
|
|
879
|
+
self,
|
|
880
|
+
java_type: str,
|
|
881
|
+
lines: List[str],
|
|
882
|
+
file_path: str
|
|
883
|
+
) -> Optional[Patch]:
|
|
884
|
+
"""Add import statement if needed."""
|
|
885
|
+
import_class = self.IMPORT_MAP.get(java_type)
|
|
886
|
+
if not import_class:
|
|
887
|
+
return None
|
|
888
|
+
|
|
889
|
+
import_line = f"import {import_class};"
|
|
890
|
+
|
|
891
|
+
# Check if already imported
|
|
892
|
+
for line in lines:
|
|
893
|
+
if import_line in line:
|
|
894
|
+
return None
|
|
895
|
+
|
|
896
|
+
# Find import section
|
|
897
|
+
for i, line in enumerate(lines):
|
|
898
|
+
if line.startswith("import "):
|
|
899
|
+
# Insert alphabetically
|
|
900
|
+
existing_import = line.strip()
|
|
901
|
+
if import_line < existing_import:
|
|
902
|
+
return Patch(
|
|
903
|
+
file_path=file_path,
|
|
904
|
+
line_start=i + 1,
|
|
905
|
+
line_end=i,
|
|
906
|
+
old_content="",
|
|
907
|
+
new_content=import_line,
|
|
908
|
+
description=f"Add import for {java_type}",
|
|
909
|
+
confidence="high",
|
|
910
|
+
)
|
|
911
|
+
elif line.startswith("public class") or line.startswith("@"):
|
|
912
|
+
# Insert before class definition
|
|
913
|
+
return Patch(
|
|
914
|
+
file_path=file_path,
|
|
915
|
+
line_start=i + 1,
|
|
916
|
+
line_end=i,
|
|
917
|
+
old_content="",
|
|
918
|
+
new_content=import_line + "\n",
|
|
919
|
+
description=f"Add import for {java_type}",
|
|
920
|
+
confidence="high",
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
return None
|
|
924
|
+
|
|
925
|
+
def _to_snake_case(self, name: str) -> str:
|
|
926
|
+
"""Convert camelCase to SNAKE_CASE."""
|
|
927
|
+
result = re.sub(r"([A-Z])", r"_\1", name)
|
|
928
|
+
return result.lstrip("_").upper()
|