@event4u/agent-config 1.13.0 → 1.15.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/.agent-src/commands/agent-handoff.md +4 -1
- package/.agent-src/commands/agent-status.md +3 -0
- package/.agent-src/commands/agents-audit.md +4 -0
- package/.agent-src/commands/agents-cleanup.md +6 -1
- package/.agent-src/commands/agents-prepare.md +3 -0
- package/.agent-src/commands/analyze-reference-repo.md +4 -0
- package/.agent-src/commands/bug-fix.md +7 -3
- package/.agent-src/commands/bug-investigate.md +4 -0
- package/.agent-src/commands/chat-history-checkpoint.md +126 -0
- package/.agent-src/commands/chat-history-clear.md +6 -1
- package/.agent-src/commands/chat-history-resume.md +7 -2
- package/.agent-src/commands/chat-history.md +7 -2
- package/.agent-src/commands/check-current-md.md +137 -0
- package/.agent-src/commands/commit-in-chunks.md +118 -0
- package/.agent-src/commands/commit.md +4 -0
- package/.agent-src/commands/compress.md +37 -2
- package/.agent-src/commands/context-create.md +4 -0
- package/.agent-src/commands/context-refactor.md +4 -0
- package/.agent-src/commands/copilot-agents-init.md +3 -0
- package/.agent-src/commands/copilot-agents-optimize.md +3 -0
- package/.agent-src/commands/create-pr-description.md +4 -0
- package/.agent-src/commands/create-pr.md +4 -0
- package/.agent-src/commands/do-and-judge.md +4 -1
- package/.agent-src/commands/do-in-steps.md +3 -0
- package/.agent-src/commands/e2e-heal.md +4 -0
- package/.agent-src/commands/e2e-plan.md +4 -0
- package/.agent-src/commands/estimate-ticket.md +4 -1
- package/.agent-src/commands/feature-dev.md +4 -0
- package/.agent-src/commands/feature-explore.md +4 -0
- package/.agent-src/commands/feature-plan.md +4 -0
- package/.agent-src/commands/feature-refactor.md +4 -0
- package/.agent-src/commands/feature-roadmap.md +6 -0
- package/.agent-src/commands/fix-ci.md +4 -0
- package/.agent-src/commands/fix-portability.md +5 -2
- package/.agent-src/commands/fix-pr-bot-comments.md +4 -0
- package/.agent-src/commands/fix-pr-comments.md +4 -0
- package/.agent-src/commands/fix-pr-developer-comments.md +4 -0
- package/.agent-src/commands/fix-references.md +3 -0
- package/.agent-src/commands/fix-seeder.md +4 -0
- package/.agent-src/commands/implement-ticket.md +39 -13
- package/.agent-src/commands/jira-ticket.md +4 -0
- package/.agent-src/commands/judge.md +3 -0
- package/.agent-src/commands/memory-add.md +5 -3
- package/.agent-src/commands/memory-full.md +5 -2
- package/.agent-src/commands/memory-promote.md +7 -6
- package/.agent-src/commands/mode.md +3 -0
- package/.agent-src/commands/module-create.md +4 -0
- package/.agent-src/commands/module-explore.md +4 -0
- package/.agent-src/commands/onboard.md +33 -0
- package/.agent-src/commands/optimize-agents.md +4 -0
- package/.agent-src/commands/optimize-augmentignore.md +12 -0
- package/.agent-src/commands/optimize-rtk-filters.md +3 -0
- package/.agent-src/commands/optimize-skills.md +4 -0
- package/.agent-src/commands/override-create.md +4 -0
- package/.agent-src/commands/override-manage.md +4 -0
- package/.agent-src/commands/package-reset.md +3 -0
- package/.agent-src/commands/package-test.md +3 -0
- package/.agent-src/commands/prepare-for-review.md +4 -0
- package/.agent-src/commands/project-analyze.md +4 -0
- package/.agent-src/commands/project-health.md +4 -0
- package/.agent-src/commands/propose-memory.md +6 -8
- package/.agent-src/commands/quality-fix.md +4 -0
- package/.agent-src/commands/refine-ticket.md +12 -7
- package/.agent-src/commands/review-changes.md +39 -8
- package/.agent-src/commands/review-routing.md +4 -0
- package/.agent-src/commands/roadmap-create.md +18 -0
- package/.agent-src/commands/roadmap-execute.md +14 -1
- package/.agent-src/commands/rule-compliance-audit.md +4 -0
- package/.agent-src/commands/set-cost-profile.md +11 -0
- package/.agent-src/commands/sync-agent-settings.md +12 -0
- package/.agent-src/commands/sync-gitignore.md +3 -0
- package/.agent-src/commands/tests-create.md +4 -0
- package/.agent-src/commands/tests-execute.md +6 -3
- package/.agent-src/commands/threat-model.md +4 -0
- package/.agent-src/commands/update-form-request-messages.md +4 -0
- package/.agent-src/commands/upstream-contribute.md +4 -0
- package/.agent-src/commands/work.md +161 -0
- package/.agent-src/guidelines/agent-infra/engineering-memory-data-format.md +2 -6
- package/.agent-src/guidelines/agent-infra/layered-settings.md +0 -1
- package/.agent-src/guidelines/agent-infra/memory-access.md +0 -7
- package/.agent-src/guidelines/agent-infra/role-contracts.md +2 -4
- package/.agent-src/guidelines/agent-infra/self-improvement-pipeline.md +0 -1
- package/.agent-src/guidelines/php/patterns/strategy.md +180 -2
- package/.agent-src/personas/README.md +0 -1
- package/.agent-src/rules/artifact-drafting-protocol.md +7 -2
- package/.agent-src/rules/artifact-engagement-recording.md +133 -0
- package/.agent-src/rules/ask-when-uncertain.md +18 -13
- package/.agent-src/rules/augment-portability.md +64 -37
- package/.agent-src/rules/autonomous-execution.md +158 -0
- package/.agent-src/rules/chat-history-cadence.md +109 -0
- package/.agent-src/rules/chat-history-ownership.md +123 -0
- package/.agent-src/rules/chat-history-visibility.md +96 -0
- package/.agent-src/rules/cli-output-handling.md +27 -4
- package/.agent-src/rules/command-suggestion.md +134 -0
- package/.agent-src/rules/commit-policy.md +109 -0
- package/.agent-src/rules/direct-answers.md +114 -0
- package/.agent-src/rules/docs-sync.md +36 -0
- package/.agent-src/rules/downstream-changes.md +10 -9
- package/.agent-src/rules/improve-before-implement.md +9 -6
- package/.agent-src/rules/language-and-tone.md +85 -6
- package/.agent-src/rules/non-destructive-by-default.md +117 -0
- package/.agent-src/rules/package-ci-checks.md +4 -0
- package/.agent-src/rules/preservation-guard.md +20 -0
- package/.agent-src/rules/roadmap-progress-sync.md +159 -27
- package/.agent-src/rules/role-mode-adherence.md +1 -1
- package/.agent-src/rules/scope-control.md +42 -1
- package/.agent-src/rules/size-enforcement.md +2 -3
- package/.agent-src/rules/skill-quality.md +3 -8
- package/.agent-src/rules/ui-audit-before-build.md +106 -0
- package/.agent-src/rules/user-interaction.md +107 -51
- package/.agent-src/scripts/update_roadmap_progress.py +73 -9
- package/.agent-src/skills/blade-ui/SKILL.md +47 -3
- package/.agent-src/skills/command-routing/SKILL.md +32 -0
- package/.agent-src/skills/command-writing/SKILL.md +52 -2
- package/.agent-src/skills/description-assist/SKILL.md +21 -0
- package/.agent-src/skills/estimate-ticket/SKILL.md +0 -1
- package/.agent-src/skills/existing-ui-audit/SKILL.md +202 -0
- package/.agent-src/skills/fe-design/SKILL.md +78 -61
- package/.agent-src/skills/file-editor/SKILL.md +9 -0
- package/.agent-src/skills/finishing-a-development-branch/SKILL.md +4 -0
- package/.agent-src/skills/flux/SKILL.md +31 -4
- package/.agent-src/skills/guideline-writing/SKILL.md +24 -2
- package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +51 -9
- package/.agent-src/skills/livewire/SKILL.md +49 -4
- package/.agent-src/skills/md-language-check/SKILL.md +103 -0
- package/.agent-src/skills/php-coder/SKILL.md +24 -0
- package/.agent-src/skills/react-shadcn-ui/SKILL.md +121 -0
- package/.agent-src/skills/refine-prompt/SKILL.md +220 -0
- package/.agent-src/skills/refine-ticket/SKILL.md +32 -28
- package/.agent-src/skills/roadmap-management/SKILL.md +24 -11
- package/.agent-src/skills/rule-writing/SKILL.md +23 -1
- package/.agent-src/skills/skill-writing/SKILL.md +3 -5
- package/.agent-src/skills/upstream-contribute/SKILL.md +3 -3
- package/.agent-src/skills/using-git-worktrees/SKILL.md +3 -1
- package/.agent-src/templates/AGENTS.md +24 -6
- package/.agent-src/templates/agent-settings.md +149 -0
- package/.agent-src/templates/roadmaps.md +11 -4
- package/.agent-src/templates/scripts/implement_ticket/__init__.py +63 -26
- package/.agent-src/templates/scripts/implement_ticket/__main__.py +8 -2
- package/.agent-src/templates/scripts/memory_lookup.py +1 -1
- package/.agent-src/templates/scripts/telemetry/__init__.py +42 -0
- package/.agent-src/templates/scripts/telemetry/aggregator.py +154 -0
- package/.agent-src/templates/scripts/telemetry/boundary.py +171 -0
- package/.agent-src/templates/scripts/telemetry/engagement.py +238 -0
- package/.agent-src/templates/scripts/telemetry/report_renderer.py +170 -0
- package/.agent-src/templates/scripts/telemetry/settings.py +112 -0
- package/.agent-src/templates/scripts/telemetry_record.py +166 -0
- package/.agent-src/templates/scripts/telemetry_report.py +161 -0
- package/.agent-src/templates/scripts/telemetry_status.py +142 -0
- package/.agent-src/templates/scripts/work_engine/__init__.py +58 -0
- package/.agent-src/templates/scripts/work_engine/__main__.py +9 -0
- package/.agent-src/templates/scripts/work_engine/cli.py +195 -0
- package/.agent-src/templates/scripts/work_engine/cli_args.py +116 -0
- package/.agent-src/templates/scripts/{implement_ticket → work_engine}/delivery_state.py +10 -3
- package/.agent-src/templates/scripts/work_engine/directives/__init__.py +33 -0
- package/.agent-src/templates/scripts/work_engine/directives/backend/__init__.py +98 -0
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/analyze.py +1 -1
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/implement.py +3 -3
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/memory.py +2 -2
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/plan.py +2 -2
- package/.agent-src/templates/scripts/work_engine/directives/backend/refine.py +396 -0
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/report.py +37 -5
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/test.py +2 -2
- package/.agent-src/templates/scripts/{implement_ticket/steps → work_engine/directives/backend}/verify.py +2 -2
- package/.agent-src/templates/scripts/work_engine/directives/mixed/__init__.py +116 -0
- package/.agent-src/templates/scripts/work_engine/directives/mixed/contract.py +254 -0
- package/.agent-src/templates/scripts/work_engine/directives/mixed/stitch.py +229 -0
- package/.agent-src/templates/scripts/work_engine/directives/mixed/ui.py +231 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/__init__.py +113 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/_passthrough.py +44 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/apply.py +241 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/audit.py +414 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/design.py +335 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/polish.py +510 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui/review.py +468 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/__init__.py +119 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.py +37 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.py +165 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.py +66 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/report.py +62 -0
- package/.agent-src/templates/scripts/work_engine/directives/ui_trivial/test.py +115 -0
- package/.agent-src/templates/scripts/work_engine/dispatcher.py +331 -0
- package/.agent-src/templates/scripts/work_engine/emitters.py +43 -0
- package/.agent-src/templates/scripts/work_engine/errors.py +19 -0
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +76 -0
- package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +54 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +32 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +103 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +44 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +42 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +50 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +49 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.py +53 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.py +50 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.py +52 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/trace.py +84 -0
- package/.agent-src/templates/scripts/work_engine/hooks/context.py +66 -0
- package/.agent-src/templates/scripts/work_engine/hooks/events.py +44 -0
- package/.agent-src/templates/scripts/work_engine/hooks/exceptions.py +79 -0
- package/.agent-src/templates/scripts/work_engine/hooks/registry.py +60 -0
- package/.agent-src/templates/scripts/work_engine/hooks/runner.py +73 -0
- package/.agent-src/templates/scripts/work_engine/hooks/settings.py +141 -0
- package/.agent-src/templates/scripts/work_engine/input_builders.py +163 -0
- package/.agent-src/templates/scripts/work_engine/intent/__init__.py +47 -0
- package/.agent-src/templates/scripts/work_engine/intent/classify.py +280 -0
- package/.agent-src/templates/scripts/work_engine/migration/__init__.py +8 -0
- package/.agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +231 -0
- package/.agent-src/templates/scripts/{implement_ticket → work_engine}/persona_policy.py +1 -1
- package/.agent-src/templates/scripts/work_engine/resolvers/__init__.py +22 -0
- package/.agent-src/templates/scripts/work_engine/resolvers/diff.py +106 -0
- package/.agent-src/templates/scripts/work_engine/resolvers/file.py +113 -0
- package/.agent-src/templates/scripts/work_engine/resolvers/prompt.py +90 -0
- package/.agent-src/templates/scripts/work_engine/scoring/__init__.py +14 -0
- package/.agent-src/templates/scripts/work_engine/scoring/confidence.py +300 -0
- package/.agent-src/templates/scripts/work_engine/stack/__init__.py +31 -0
- package/.agent-src/templates/scripts/work_engine/stack/detect.py +187 -0
- package/.agent-src/templates/scripts/work_engine/state.py +641 -0
- package/.agent-src/templates/scripts/work_engine/state_io.py +202 -0
- package/.claude-plugin/marketplace.json +105 -2
- package/AGENTS.md +38 -8
- package/CHANGELOG.md +609 -0
- package/README.md +136 -14
- package/config/agent-settings.template.yml +45 -0
- package/config/gitignore-block.txt +4 -0
- package/docs/MIGRATION.md +122 -0
- package/docs/architecture.md +111 -35
- package/docs/contracts/STABILITY.md +95 -0
- package/docs/contracts/adr-chat-history-split.md +132 -0
- package/docs/contracts/adr-command-suggestion.md +146 -0
- package/docs/contracts/adr-implement-ticket-runtime.md +122 -0
- package/docs/contracts/adr-product-ui-track.md +384 -0
- package/docs/contracts/adr-prompt-driven-execution.md +187 -0
- package/docs/contracts/agent-memory-contract.md +149 -0
- package/docs/contracts/artifact-engagement-flow.md +262 -0
- package/docs/contracts/command-clusters.md +126 -0
- package/docs/contracts/command-suggestion-flow.md +148 -0
- package/docs/contracts/implement-ticket-flow.md +628 -0
- package/docs/contracts/linear-ai-rules-inclusion.md +143 -0
- package/docs/contracts/linear-ai-three-layers.md +131 -0
- package/docs/contracts/rule-interactions.md +107 -0
- package/docs/contracts/rule-interactions.yml +142 -0
- package/docs/contracts/ui-stack-extension.md +236 -0
- package/docs/contracts/ui-track-flow.md +338 -0
- package/docs/development.md +1 -1
- package/docs/getting-started.md +3 -3
- package/docs/installation.md +124 -2
- package/docs/migrations/commands-1.15.0.md +112 -0
- package/docs/showcase.md +204 -0
- package/docs/ui-track-mental-model.md +121 -0
- package/package.json +1 -1
- package/scripts/agent-config +199 -0
- package/scripts/audit_cloud_compatibility.py +288 -0
- package/scripts/build_cloud_bundle.py +458 -0
- package/scripts/build_linear_digest.py +263 -0
- package/scripts/chat_history.py +796 -7
- package/scripts/check_compression.py +139 -0
- package/scripts/check_iron_law_prominence.py +143 -0
- package/scripts/check_md_language.py +159 -0
- package/scripts/check_portability.py +38 -0
- package/scripts/check_public_links.py +185 -0
- package/scripts/check_references.py +1 -0
- package/scripts/check_reply_consistency.py +140 -0
- package/scripts/command_suggester/__init__.py +51 -0
- package/scripts/command_suggester/cooldown.py +132 -0
- package/scripts/command_suggester/loader.py +70 -0
- package/scripts/command_suggester/match.py +180 -0
- package/scripts/command_suggester/rank.py +120 -0
- package/scripts/command_suggester/render.py +86 -0
- package/scripts/command_suggester/sanitize.py +113 -0
- package/scripts/command_suggester/settings.py +125 -0
- package/scripts/command_suggester/types.py +78 -0
- package/scripts/hooks/augment-chat-history.sh +56 -0
- package/scripts/install-hooks.sh +67 -0
- package/scripts/install.py +150 -33
- package/scripts/lint_marketplace.py +27 -0
- package/scripts/lint_no_new_atomic_commands.py +179 -0
- package/scripts/lint_rule_interactions.py +149 -0
- package/scripts/memory_lookup.py +1 -1
- package/scripts/migrate_command_suggestions.py +151 -0
- package/scripts/release.py +297 -64
- package/scripts/schemas/command.schema.json +41 -0
- package/scripts/skill_linter.py +81 -0
- package/scripts/sync_agent_settings.py +42 -12
- package/scripts/update_counts.py +10 -0
- package/templates/consumer-settings/augment-cli-hooks.json +54 -0
- package/templates/consumer-settings/claude-settings.json +55 -1
- package/.agent-src/rules/chat-history.md +0 -171
- package/.agent-src/templates/scripts/implement_ticket/cli.py +0 -171
- package/.agent-src/templates/scripts/implement_ticket/dispatcher.py +0 -134
- package/.agent-src/templates/scripts/implement_ticket/steps/__init__.py +0 -49
- package/.agent-src/templates/scripts/implement_ticket/steps/refine.py +0 -140
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""``audit`` step — mandatory pre-step for the UI directive set.
|
|
2
|
+
|
|
3
|
+
Routes on ``state.ui_audit`` shape:
|
|
4
|
+
|
|
5
|
+
- **Empty / None** — first pass. Emit an ``@agent-directive:`` halt
|
|
6
|
+
delegating to the ``existing-ui-audit`` skill; on the rebound the
|
|
7
|
+
skill writes findings back into ``state.ui_audit``.
|
|
8
|
+
- **Greenfield without decision** — ``greenfield == True`` and
|
|
9
|
+
``greenfield_decision`` unset. Emit a numbered-options halt; the
|
|
10
|
+
user picks ``scaffold`` / ``bare`` / ``external_reference``.
|
|
11
|
+
- **Populated, ambiguous, no pick** — confidence is medium, OR the
|
|
12
|
+
inventory has multiple matches with similar similarity scores.
|
|
13
|
+
Emit a numbered-options halt; the user picks the candidate to
|
|
14
|
+
extend (or "build new"). Records ``audit_path = "ambiguous"`` plus
|
|
15
|
+
the selected candidate. The downstream design step shows the brief
|
|
16
|
+
as a final summary, not a separate halt.
|
|
17
|
+
- **Populated, high-confidence** — confidence is ``high`` and the
|
|
18
|
+
inventory has exactly one strong reusable match (similarity
|
|
19
|
+
≥ ``STRONG_SIMILARITY``). Records ``audit_path = "high_confidence"``
|
|
20
|
+
and returns ``SUCCESS``; the design step folds the audit findings
|
|
21
|
+
into the design-brief halt as default assumptions.
|
|
22
|
+
- **Populated and decided** — any of the above with the path / pick
|
|
23
|
+
already recorded round-trips through ``SUCCESS``. The audit step
|
|
24
|
+
is idempotent so dispatcher replay never re-emits a halt the user
|
|
25
|
+
already answered.
|
|
26
|
+
|
|
27
|
+
The deterministic checks live here (rather than inside the skill) for
|
|
28
|
+
the same reason as :mod:`work_engine.directives.backend.refine`: the
|
|
29
|
+
dispatcher is synchronous Python and cannot delegate mid-loop. Making
|
|
30
|
+
the gate deterministic keeps "no design without audit findings"
|
|
31
|
+
enforceable from code, not norms.
|
|
32
|
+
"""
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from typing import Any
|
|
36
|
+
|
|
37
|
+
from ...delivery_state import (
|
|
38
|
+
DeliveryState,
|
|
39
|
+
Outcome,
|
|
40
|
+
StepResult,
|
|
41
|
+
agent_directive,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
STRONG_SIMILARITY: float = 0.7
|
|
45
|
+
"""Similarity threshold for a "strong reusable match" (Step 4 contract)."""
|
|
46
|
+
|
|
47
|
+
TIE_GAP: float = 0.05
|
|
48
|
+
"""Top-2 within this gap counts as ambiguous regardless of confidence."""
|
|
49
|
+
|
|
50
|
+
TESTED_AGAINST_SHADCN_MAJOR: int = 2
|
|
51
|
+
"""Major version the ``react-shadcn-ui`` skill body declares as ``Tested
|
|
52
|
+
against`` (``shadcn@2.1`` → major ``2``). When ``state.ui_audit
|
|
53
|
+
.shadcn_inventory.version`` resolves to a different major, audit emits
|
|
54
|
+
the soft version-mismatch halt (Phase 2 Step 5)."""
|
|
55
|
+
|
|
56
|
+
AMBIGUITIES: tuple[dict[str, str], ...] = (
|
|
57
|
+
{
|
|
58
|
+
"code": "audit_missing",
|
|
59
|
+
"trigger": "state.ui_audit is None or empty — skill has not run yet",
|
|
60
|
+
"resolution": "agent directive `existing-ui-audit` → skill writes "
|
|
61
|
+
"findings into state.ui_audit",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"code": "greenfield_undecided",
|
|
65
|
+
"trigger": (
|
|
66
|
+
"state.ui_audit.greenfield is True but greenfield_decision "
|
|
67
|
+
"is unset — user has not picked a scaffolding direction"
|
|
68
|
+
),
|
|
69
|
+
"resolution": "user picks scaffold / bare / external_reference; "
|
|
70
|
+
"agent records the choice in state.ui_audit.greenfield_decision",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"code": "shadcn_version_mismatch",
|
|
74
|
+
"trigger": (
|
|
75
|
+
"state.ui_audit.shadcn_inventory.version major differs from "
|
|
76
|
+
"TESTED_AGAINST_SHADCN_MAJOR — react-shadcn-ui skill was "
|
|
77
|
+
"tested against a different major"
|
|
78
|
+
),
|
|
79
|
+
"resolution": "user accepts cautious composition or aborts; "
|
|
80
|
+
"agent records the choice in "
|
|
81
|
+
"state.ui_audit.version_mismatch_decision",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"code": "audit_ambiguous",
|
|
85
|
+
"trigger": (
|
|
86
|
+
"confidence band is medium, OR inventory has multiple matches "
|
|
87
|
+
"with similar similarity scores, OR no match clears "
|
|
88
|
+
"STRONG_SIMILARITY"
|
|
89
|
+
),
|
|
90
|
+
"resolution": "user picks a candidate to extend (or 'build new'); "
|
|
91
|
+
"agent records the choice in state.ui_audit.audit_path "
|
|
92
|
+
"and state.ui_audit.candidate_pick",
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
"""Declared ambiguity surfaces for this step."""
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def run(state: DeliveryState) -> StepResult:
|
|
99
|
+
"""Apply the audit gate to ``state.ui_audit``."""
|
|
100
|
+
audit = state.ui_audit
|
|
101
|
+
if not _is_populated(audit):
|
|
102
|
+
return _delegate_to_audit_skill(state)
|
|
103
|
+
|
|
104
|
+
if audit.get("greenfield") is True and not audit.get("greenfield_decision"):
|
|
105
|
+
return _halt_greenfield(state, audit)
|
|
106
|
+
|
|
107
|
+
# Greenfield with a recorded decision skips the candidate-pick halt
|
|
108
|
+
# (there are no existing components to weigh) and lands on SUCCESS.
|
|
109
|
+
if audit.get("greenfield") is True:
|
|
110
|
+
if not audit.get("audit_path"):
|
|
111
|
+
audit["audit_path"] = "greenfield"
|
|
112
|
+
return StepResult(outcome=Outcome.SUCCESS)
|
|
113
|
+
|
|
114
|
+
# Soft halt: react-shadcn-ui skill was tested against a specific
|
|
115
|
+
# major; a project on a different major needs an explicit "proceed
|
|
116
|
+
# with cautious composition" pick before apply runs. Idempotent via
|
|
117
|
+
# ``version_mismatch_decision``.
|
|
118
|
+
mismatch = _detect_shadcn_version_mismatch(audit)
|
|
119
|
+
if mismatch is not None and not audit.get("version_mismatch_decision"):
|
|
120
|
+
return _halt_shadcn_version_mismatch(state, mismatch)
|
|
121
|
+
|
|
122
|
+
# Idempotent re-entry: an already-decided path round-trips through
|
|
123
|
+
# SUCCESS without re-emitting the halt the user already answered.
|
|
124
|
+
if audit.get("audit_path") in {"high_confidence", "ambiguous"}:
|
|
125
|
+
return StepResult(outcome=Outcome.SUCCESS)
|
|
126
|
+
|
|
127
|
+
decision = _decide_path(state, audit)
|
|
128
|
+
if decision == "high_confidence":
|
|
129
|
+
audit["audit_path"] = "high_confidence"
|
|
130
|
+
return StepResult(outcome=Outcome.SUCCESS)
|
|
131
|
+
|
|
132
|
+
return _halt_ambiguous(state, audit)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _is_populated(audit: Any) -> bool:
|
|
136
|
+
"""True when ``audit`` carries actionable findings.
|
|
137
|
+
|
|
138
|
+
Non-dict and empty-dict shapes are treated as "skill has not run"
|
|
139
|
+
so the first-pass directive fires. Once the skill writes findings,
|
|
140
|
+
the dict carries at least one of the documented inventory keys
|
|
141
|
+
(``components_found`` or the legacy ``components`` alias).
|
|
142
|
+
"""
|
|
143
|
+
if not isinstance(audit, dict):
|
|
144
|
+
return False
|
|
145
|
+
if not audit:
|
|
146
|
+
return False
|
|
147
|
+
return any(
|
|
148
|
+
key in audit
|
|
149
|
+
for key in ("components_found", "components", "greenfield")
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _preview_input(state: DeliveryState) -> str:
|
|
154
|
+
"""Render a one-line preview of the input being audited."""
|
|
155
|
+
data = state.ticket or {}
|
|
156
|
+
raw = data.get("raw")
|
|
157
|
+
if isinstance(raw, str) and raw.strip():
|
|
158
|
+
text = " ".join(raw.split())
|
|
159
|
+
else:
|
|
160
|
+
title = data.get("title")
|
|
161
|
+
text = title if isinstance(title, str) else (data.get("id") or "(no title)")
|
|
162
|
+
if len(text) <= 80:
|
|
163
|
+
return text
|
|
164
|
+
return text[:79].rstrip() + "\u2026"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _delegate_to_audit_skill(state: DeliveryState) -> StepResult:
|
|
168
|
+
"""Halt with an agent directive so the orchestrator runs ``existing-ui-audit``."""
|
|
169
|
+
preview = _preview_input(state)
|
|
170
|
+
return StepResult(
|
|
171
|
+
outcome=Outcome.BLOCKED,
|
|
172
|
+
questions=[
|
|
173
|
+
agent_directive("existing-ui-audit"),
|
|
174
|
+
f"> Input: {preview}",
|
|
175
|
+
"> No UI audit findings yet — running `existing-ui-audit` "
|
|
176
|
+
"to inventory components, design system, tokens, and "
|
|
177
|
+
"candidate matches before design.",
|
|
178
|
+
"> 1. Continue — let the skill produce the audit",
|
|
179
|
+
"> 2. Abort — drop this UI request",
|
|
180
|
+
],
|
|
181
|
+
message=(
|
|
182
|
+
"UI audit findings missing; delegating to existing-ui-audit skill."
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _halt_greenfield(state: DeliveryState, audit: dict[str, Any]) -> StepResult:
|
|
188
|
+
"""BLOCKED halt — greenfield project needs an explicit scaffolding pick."""
|
|
189
|
+
preview = _preview_input(state)
|
|
190
|
+
questions = [
|
|
191
|
+
f"> Input: {preview}",
|
|
192
|
+
"> No existing UI surface detected — this looks like greenfield.",
|
|
193
|
+
"> 1. Scaffold — minimal token set + base component primitive folder",
|
|
194
|
+
"> 2. Bare — proceed with Tailwind defaults, no scaffolding",
|
|
195
|
+
"> 3. External reference — point me at a design-system URL or file",
|
|
196
|
+
"",
|
|
197
|
+
"**Recommendation: 1 \u2014 Scaffold tokens + primitives** "
|
|
198
|
+
"\u2014 even one extra screen benefits from a shared base; the "
|
|
199
|
+
"scaffold cost is ~10 min and saves re-doing every primitive "
|
|
200
|
+
"on screen 2. Caveat: flip to 2 if this is a demo or "
|
|
201
|
+
"single-page prototype that will not grow.",
|
|
202
|
+
]
|
|
203
|
+
return StepResult(
|
|
204
|
+
outcome=Outcome.BLOCKED,
|
|
205
|
+
questions=questions,
|
|
206
|
+
message=(
|
|
207
|
+
"UI audit detected greenfield; halting for scaffolding "
|
|
208
|
+
"direction (scaffold / bare / external_reference)."
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _decide_path(state: DeliveryState, audit: dict[str, Any]) -> str:
|
|
214
|
+
"""Return ``"high_confidence"`` or ``"ambiguous"`` for a populated audit.
|
|
215
|
+
|
|
216
|
+
High-confidence requires *both*:
|
|
217
|
+
|
|
218
|
+
- ``state.ticket["confidence"]["band"] == "high"`` (or the input
|
|
219
|
+
kind makes confidence inapplicable — see :func:`_confidence_band`).
|
|
220
|
+
- exactly one strong reusable match: top similarity
|
|
221
|
+
``\u2265 STRONG_SIMILARITY`` and no runner-up within
|
|
222
|
+
:data:`TIE_GAP` of it.
|
|
223
|
+
|
|
224
|
+
Anything else is ambiguous \u2014 medium / low confidence, no strong
|
|
225
|
+
match, or two near-identical candidates the user must disambiguate.
|
|
226
|
+
"""
|
|
227
|
+
band = _confidence_band(state)
|
|
228
|
+
if band != "high":
|
|
229
|
+
return "ambiguous"
|
|
230
|
+
|
|
231
|
+
matches = _matches(audit)
|
|
232
|
+
if not matches:
|
|
233
|
+
return "ambiguous"
|
|
234
|
+
|
|
235
|
+
scored = sorted(
|
|
236
|
+
(_similarity_of(m) for m in matches),
|
|
237
|
+
reverse=True,
|
|
238
|
+
)
|
|
239
|
+
top = scored[0]
|
|
240
|
+
if top < STRONG_SIMILARITY:
|
|
241
|
+
return "ambiguous"
|
|
242
|
+
if len(scored) >= 2 and (top - scored[1]) < TIE_GAP:
|
|
243
|
+
return "ambiguous"
|
|
244
|
+
return "high_confidence"
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _confidence_band(state: DeliveryState) -> str:
|
|
248
|
+
"""Return the scored confidence band, or ``"high"`` when not applicable.
|
|
249
|
+
|
|
250
|
+
Ticket inputs that survive the backend refine step carry a band in
|
|
251
|
+
``state.ticket["confidence"]["band"]``. Diff / file envelopes never
|
|
252
|
+
run the scorer; treat them as ``"high"`` because the user is
|
|
253
|
+
pointing at a concrete surface, not asking us to reconstruct one.
|
|
254
|
+
Missing band defaults to ``"medium"`` so the safe path (ambiguous
|
|
255
|
+
halt) is the fall-through.
|
|
256
|
+
"""
|
|
257
|
+
data = state.ticket or {}
|
|
258
|
+
confidence = data.get("confidence")
|
|
259
|
+
if isinstance(confidence, dict):
|
|
260
|
+
band = confidence.get("band")
|
|
261
|
+
if isinstance(band, str) and band:
|
|
262
|
+
return band
|
|
263
|
+
if data.get("input_kind") in {"diff", "file"}:
|
|
264
|
+
return "high"
|
|
265
|
+
return "medium"
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _matches(audit: dict[str, Any]) -> list[dict[str, Any]]:
|
|
269
|
+
"""Return the inventory list, preferring ``components_found``."""
|
|
270
|
+
for key in ("components_found", "components"):
|
|
271
|
+
value = audit.get(key)
|
|
272
|
+
if isinstance(value, list) and value:
|
|
273
|
+
return [m for m in value if isinstance(m, dict)]
|
|
274
|
+
return []
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _similarity_of(match: dict[str, Any]) -> float:
|
|
278
|
+
"""Read a similarity score from a match entry; default to 0.0."""
|
|
279
|
+
raw = match.get("similarity")
|
|
280
|
+
try:
|
|
281
|
+
return float(raw) # type: ignore[arg-type]
|
|
282
|
+
except (TypeError, ValueError):
|
|
283
|
+
return 0.0
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _detect_shadcn_version_mismatch(audit: dict[str, Any]) -> dict[str, Any] | None:
|
|
287
|
+
"""Return mismatch info when the inventory diverges by a major.
|
|
288
|
+
|
|
289
|
+
Reads ``audit["shadcn_inventory"]["version"]`` and compares its
|
|
290
|
+
leading integer with :data:`TESTED_AGAINST_SHADCN_MAJOR`. Returns
|
|
291
|
+
``None`` (no halt) when:
|
|
292
|
+
|
|
293
|
+
- the inventory is missing, not a dict, or has no ``version``;
|
|
294
|
+
- the version string cannot be parsed (treat as "unknown — skill
|
|
295
|
+
will fall back to manual composition rather than a stale skill");
|
|
296
|
+
- the major matches the tested major.
|
|
297
|
+
"""
|
|
298
|
+
inventory = audit.get("shadcn_inventory")
|
|
299
|
+
if not isinstance(inventory, dict):
|
|
300
|
+
return None
|
|
301
|
+
raw_version = inventory.get("version")
|
|
302
|
+
if not isinstance(raw_version, str) or not raw_version.strip():
|
|
303
|
+
return None
|
|
304
|
+
head = raw_version.lstrip("v").split(".", 1)[0].strip()
|
|
305
|
+
try:
|
|
306
|
+
installed_major = int(head)
|
|
307
|
+
except ValueError:
|
|
308
|
+
return None
|
|
309
|
+
if installed_major == TESTED_AGAINST_SHADCN_MAJOR:
|
|
310
|
+
return None
|
|
311
|
+
return {
|
|
312
|
+
"installed_version": raw_version,
|
|
313
|
+
"installed_major": installed_major,
|
|
314
|
+
"tested_major": TESTED_AGAINST_SHADCN_MAJOR,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _halt_shadcn_version_mismatch(
|
|
319
|
+
state: DeliveryState, mismatch: dict[str, Any]
|
|
320
|
+
) -> StepResult:
|
|
321
|
+
"""BLOCKED soft-halt \u2014 user accepts cautious composition or aborts."""
|
|
322
|
+
preview = _preview_input(state)
|
|
323
|
+
installed = mismatch["installed_version"]
|
|
324
|
+
tested = mismatch["tested_major"]
|
|
325
|
+
installed_major = mismatch["installed_major"]
|
|
326
|
+
return StepResult(
|
|
327
|
+
outcome=Outcome.BLOCKED,
|
|
328
|
+
questions=[
|
|
329
|
+
f"> Input: {preview}",
|
|
330
|
+
f"> shadcn skill tested against v{tested}.x; project uses "
|
|
331
|
+
f"`{installed}` (major v{installed_major}).",
|
|
332
|
+
"> 1. Proceed with cautious composition \u2014 skill applies "
|
|
333
|
+
"general patterns, agent verifies primitive APIs against "
|
|
334
|
+
"the installed version",
|
|
335
|
+
"> 2. Abort \u2014 update the `react-shadcn-ui` skill to the "
|
|
336
|
+
"installed major before continuing",
|
|
337
|
+
"",
|
|
338
|
+
"**Recommendation: 1 \u2014 Proceed with caution** "
|
|
339
|
+
"\u2014 most shadcn primitive APIs are stable across "
|
|
340
|
+
"majors; the skill's structural guidance still applies. "
|
|
341
|
+
"Caveat: flip to 2 if the design brief leans on a "
|
|
342
|
+
"primitive whose API changed (Form, Sheet, Dialog have "
|
|
343
|
+
"had breaking renames in past majors).",
|
|
344
|
+
],
|
|
345
|
+
message=(
|
|
346
|
+
f"shadcn version mismatch (skill v{tested}.x vs project "
|
|
347
|
+
f"{installed}); halting for cautious-composition decision."
|
|
348
|
+
),
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _halt_ambiguous(state: DeliveryState, audit: dict[str, Any]) -> StepResult:
|
|
353
|
+
"""BLOCKED halt \u2014 user picks an existing candidate or 'build new'."""
|
|
354
|
+
preview = _preview_input(state)
|
|
355
|
+
matches = _matches(audit)
|
|
356
|
+
scored = sorted(
|
|
357
|
+
matches,
|
|
358
|
+
key=_similarity_of,
|
|
359
|
+
reverse=True,
|
|
360
|
+
)[:3]
|
|
361
|
+
|
|
362
|
+
lines = [
|
|
363
|
+
f"> Input: {preview}",
|
|
364
|
+
"> Audit findings are ambiguous \u2014 pick the candidate to "
|
|
365
|
+
"extend, or build new:",
|
|
366
|
+
]
|
|
367
|
+
for idx, match in enumerate(scored, start=1):
|
|
368
|
+
name = match.get("name") or match.get("path") or "(unnamed)"
|
|
369
|
+
sim = _similarity_of(match)
|
|
370
|
+
path = match.get("path") or ""
|
|
371
|
+
suffix = f" \u2014 `{path}`" if path else ""
|
|
372
|
+
lines.append(f"> {idx}. Extend `{name}` (similarity {sim:.2f}){suffix}")
|
|
373
|
+
next_idx = len(scored) + 1
|
|
374
|
+
lines.append(
|
|
375
|
+
f"> {next_idx}. Build new \u2014 none of the above is close enough",
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
if scored:
|
|
379
|
+
top = scored[0]
|
|
380
|
+
top_name = top.get("name") or top.get("path") or "candidate 1"
|
|
381
|
+
top_sim = _similarity_of(top)
|
|
382
|
+
rec = (
|
|
383
|
+
f"**Recommendation: 1 \u2014 Extend `{top_name}`** \u2014 "
|
|
384
|
+
f"similarity {top_sim:.2f} is the strongest match in the "
|
|
385
|
+
f"inventory; reuse beats new code unless the contract "
|
|
386
|
+
f"diverges. Caveat: flip to {next_idx} if the existing "
|
|
387
|
+
f"component cannot host the new behavior cleanly."
|
|
388
|
+
)
|
|
389
|
+
else:
|
|
390
|
+
rec = (
|
|
391
|
+
f"**Recommendation: {next_idx} \u2014 Build new** \u2014 "
|
|
392
|
+
f"no inventory match cleared the strong-similarity bar. "
|
|
393
|
+
f"Caveat: flip to an extend option only if a near-miss "
|
|
394
|
+
f"is a better fit than starting from scratch."
|
|
395
|
+
)
|
|
396
|
+
lines.extend(["", rec])
|
|
397
|
+
|
|
398
|
+
return StepResult(
|
|
399
|
+
outcome=Outcome.BLOCKED,
|
|
400
|
+
questions=lines,
|
|
401
|
+
message=(
|
|
402
|
+
"UI audit findings ambiguous; halting for candidate pick "
|
|
403
|
+
"(extend existing / build new)."
|
|
404
|
+
),
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
__all__ = [
|
|
409
|
+
"AMBIGUITIES",
|
|
410
|
+
"STRONG_SIMILARITY",
|
|
411
|
+
"TESTED_AGAINST_SHADCN_MAJOR",
|
|
412
|
+
"TIE_GAP",
|
|
413
|
+
"run",
|
|
414
|
+
]
|