aw-spec-cli 0.1.21 → 0.1.22
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/assets/.appweaver/STACK-PROFILES.md +87 -8
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +30 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +41 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +62 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +18 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +115 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +225 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +39 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +28 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +100 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +141 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +386 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +135 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +190 -209
- package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +182 -224
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +4 -1
- package/assets/.appweaver/scripts/python/aw-crstate.py +127 -2
- package/assets/.appweaver/scripts/python/aw-gaps.py +119 -0
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +17 -1
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +84 -4
- package/assets/.appweaver/scripts/python/aw-plangate.py +216 -0
- package/assets/.appweaver/scripts/python/aw-principles.py +108 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +6 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +141 -4
- package/assets/.appweaver/stack-profiles/angular.json +26 -0
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +38 -0
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +38 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +19 -0
- package/assets/.appweaver/stack-profiles/nextjs.json +26 -0
- package/assets/.appweaver/stack-profiles/node-express.json +26 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +15 -0
- package/assets/.appweaver/stack-profiles/react-vite.json +26 -0
- package/assets/.appweaver/stack-profiles/sveltekit.json +26 -0
- package/assets/.appweaver/stack-profiles/vue-vite.json +26 -0
- package/assets/.appweaver/templates/ui-model-template.md +67 -0
- package/assets/.appweaver/templates/workflow-model-template.md +62 -0
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +44 -0
- package/package.json +1 -1
|
@@ -107,6 +107,14 @@ standards:
|
|
|
107
107
|
|
|
108
108
|
vars:
|
|
109
109
|
spec_all_pass: "false" # validation-loop guard, flipped by the validate query
|
|
110
|
+
nn_count: "0" # ratified NON-NEGOTIABLE principles, from principles-list.
|
|
111
|
+
# 0 = a project that ratified none, which skips the gate.
|
|
112
|
+
nn_titles: "" # those principles, for the judge's prompt
|
|
113
|
+
nn_compliant: "false" # per-clarification verdict. DEFAULTS TO REFUSE: the gate
|
|
114
|
+
# reads it, so a judge that never answered stops the run
|
|
115
|
+
# rather than passing an unexamined answer through.
|
|
116
|
+
nn_principle: "" # the principle a departing answer was judged against
|
|
117
|
+
nn_why: "" # what it requires and what the answer does instead
|
|
110
118
|
checklist_total: "0" # bound by checklist-read
|
|
111
119
|
checklist_passed: "0" # stays 0 when the checklist has no items to score
|
|
112
120
|
cr_id: "" # set on the DELTA path only
|
|
@@ -520,6 +528,23 @@ workflow:
|
|
|
520
528
|
|
|
521
529
|
# 6. Resolve [NEEDS CLARIFICATION] markers interactively (≤3). Non-interactive
|
|
522
530
|
# runs answer with the first/recommended option (a documented default).
|
|
531
|
+
#
|
|
532
|
+
# THE DEFAULT IS WHY THIS IS GOVERNED. A non-interactive run answers with options[0],
|
|
533
|
+
# so whatever the extraction listed first becomes project policy unattended — and a
|
|
534
|
+
# clarification is asked at exactly the altitude where a ratified principle already
|
|
535
|
+
# has an answer. The constitution halves ARE in context here (build_context put them
|
|
536
|
+
# in the envelope, which include_standards: false does not touch), but nothing told
|
|
537
|
+
# the extraction that a principle outranks a question, and nothing checked the answer
|
|
538
|
+
# afterwards. Both halves of that are below: the ordering rule in the task, and the
|
|
539
|
+
# per-answer gate inside the loop.
|
|
540
|
+
- id: nn_principles
|
|
541
|
+
action: execute_script
|
|
542
|
+
script: { ref: actions }
|
|
543
|
+
subcommand: principles-list
|
|
544
|
+
outputs:
|
|
545
|
+
- { name: nn_count, from: "$.count" }
|
|
546
|
+
- { name: nn_titles, from: "$.titles_csv" }
|
|
547
|
+
|
|
523
548
|
- id: extract_clarifications
|
|
524
549
|
action: agent_query
|
|
525
550
|
context: ["{{quality_target}}"]
|
|
@@ -528,6 +553,15 @@ workflow:
|
|
|
528
553
|
Extract up to 3 unresolved "[NEEDS CLARIFICATION: <question>]" markers from
|
|
529
554
|
the document in context (a feature spec, or one change's delta-spec), most
|
|
530
555
|
scope/security/UX-impacting first. Return {"clarifications":[]} if there are none.
|
|
556
|
+
|
|
557
|
+
A RATIFIED PRINCIPLE IS NOT A QUESTION. The constitution halves in context carry
|
|
558
|
+
principles marked (NON-NEGOTIABLE). Where one of them already settles a marker,
|
|
559
|
+
it is not a clarification: DROP it from the list — the answer is the principle,
|
|
560
|
+
and the document is corrected to match it in the quality loop. Offering it as a
|
|
561
|
+
choice invites a project to vote on something already ratified.
|
|
562
|
+
For a marker that merely TOUCHES such a principle, every option you list must be
|
|
563
|
+
compatible with it, and the most compliant option must be FIRST — an unattended
|
|
564
|
+
run takes the first one.
|
|
531
565
|
schema: { clarifications: [ { id: c1, question: "<the question>", options: ["<answer A>", "<answer B>", "<answer C>"] } ] }
|
|
532
566
|
mock: { clarifications: [] }
|
|
533
567
|
outputs:
|
|
@@ -545,6 +579,72 @@ workflow:
|
|
|
545
579
|
options_from: "{{c.options}}"
|
|
546
580
|
answer_key: "{{c.id}}"
|
|
547
581
|
answer_var: c_answer
|
|
582
|
+
|
|
583
|
+
# THE ANSWER IS CHECKED BEFORE IT IS WRITTEN IN. Placed between the ask and the
|
|
584
|
+
# rewrite on purpose: once resolve_clar has folded the answer into a requirement it
|
|
585
|
+
# is ordinary spec prose, and catching it then means unpicking a document rather
|
|
586
|
+
# than declining an answer. Judged one answer at a time so the stop can quote the
|
|
587
|
+
# question that caused it.
|
|
588
|
+
#
|
|
589
|
+
# The agent judges ONLY against the principles nn_principles found — a citation
|
|
590
|
+
# outside that list is visibly wrong, which is the point of enumerating them with a
|
|
591
|
+
# script instead of asking one agent to both find the principle and object to it.
|
|
592
|
+
#
|
|
593
|
+
# ASKED IN THE POSITIVE, AND RESET FIRST. The gate below reads nn_compliant, so an
|
|
594
|
+
# answer the judge never delivered — a malformed reply, a step that did not run —
|
|
595
|
+
# leaves "false" standing and STOPS. Asking "does it contradict?" would invert that:
|
|
596
|
+
# the same silence would read as no contradiction found. The reset is what makes it
|
|
597
|
+
# per-iteration; vars outlive a loop pass, so without it the second clarification
|
|
598
|
+
# would inherit the first one's verdict.
|
|
599
|
+
- id: governance_reset
|
|
600
|
+
action: set
|
|
601
|
+
vars:
|
|
602
|
+
nn_compliant: "false"
|
|
603
|
+
nn_principle: ""
|
|
604
|
+
nn_why: ""
|
|
605
|
+
|
|
606
|
+
# Skipped where a project ratified no NON-NEGOTIABLE principle: with nothing to
|
|
607
|
+
# depart from there is nothing to ask, and the gate is skipped on the same
|
|
608
|
+
# condition rather than reading the "false" this reset just wrote.
|
|
609
|
+
- id: governance_check
|
|
610
|
+
condition: "{{nn_count}} != 0"
|
|
611
|
+
action: agent_query
|
|
612
|
+
context: ["{{quality_target}}"]
|
|
613
|
+
include_standards: false
|
|
614
|
+
task: |
|
|
615
|
+
The constitution halves in context ratify these NON-NEGOTIABLE principles:
|
|
616
|
+
{{nn_titles}}
|
|
617
|
+
A question was raised about this specification and has just been answered:
|
|
618
|
+
Question: {{c.question}}
|
|
619
|
+
Answer: {{c_answer}}
|
|
620
|
+
Is that answer COMPLIANT with those principles — that is, can the specification
|
|
621
|
+
be amended to say it without asserting something a principle forbids or omitting
|
|
622
|
+
something a principle requires?
|
|
623
|
+
Judge only against the principles listed above, and when it is not compliant
|
|
624
|
+
cite the one it departs from by its id. A principle the question does not engage
|
|
625
|
+
is not a departure, and neither is an answer a principle simply does not speak
|
|
626
|
+
to; where none is engaged the answer is compliant. Report a departure only where
|
|
627
|
+
you can state what the principle requires and what the answer does instead.
|
|
628
|
+
schema: { compliant: true, principle: "<id, or empty>", why: "<one sentence, or empty>" }
|
|
629
|
+
mock: { compliant: true, principle: "", why: "" }
|
|
630
|
+
outputs:
|
|
631
|
+
- { name: nn_compliant, from: "$.compliant" }
|
|
632
|
+
- { name: nn_principle, from: "$.principle" }
|
|
633
|
+
- { name: nn_why, from: "$.why" }
|
|
634
|
+
|
|
635
|
+
# FAIL CLOSED. The constitution's own Governance says a deviation with no named
|
|
636
|
+
# approver is a defect, not a decision — and this answer has no approver at all: it
|
|
637
|
+
# was settled in the run, by an operator picking from a menu or by a non-interactive
|
|
638
|
+
# default. Recording it and carrying on is how an unapproved departure from a
|
|
639
|
+
# NON-NEGOTIABLE principle reaches code, so the run stops here and the choice goes
|
|
640
|
+
# back to a human who can either comply or amend the constitution properly.
|
|
641
|
+
- id: governance_gate
|
|
642
|
+
condition: "{{nn_count}} != 0"
|
|
643
|
+
action: verify_context
|
|
644
|
+
require_true: nn_compliant
|
|
645
|
+
on_false: stop
|
|
646
|
+
on_false_message: "The answer to \"{{c.question}}\" departs from NON-NEGOTIABLE principle {{nn_principle}}: {{nn_why}}. That principle is ratified in .appweaver/memory/ and this answer has no approver — it was settled in this run, not by a domain owner, and the constitution's Governance section holds that a deviation with no named approver is a defect rather than a decision. Re-run specify and answer in a way the principle allows; if the project genuinely intends to depart from it, amend the constitution through its own amendment process FIRST (which names the approver the departure needs) and re-run. Nothing was written to {{quality_target}} for this clarification."
|
|
647
|
+
|
|
548
648
|
- id: resolve_clar
|
|
549
649
|
action: agent_author
|
|
550
650
|
context: ["{{quality_target}}"]
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# aw-spec-ui-model (orchestrator) — Derive UI Model from Workflow Model
|
|
3
|
+
#
|
|
4
|
+
# Stage 3 of the 4-Stage Spec-Driven UI Generation Pipeline.
|
|
5
|
+
# Consumes `specs/<Feature>/ui/workflow-model.md` and maps workflows into concrete UI surfaces
|
|
6
|
+
# (Pages, Sub-Pages, Drawers, Modals, Dialogs), interaction states (Loading, Empty, Populated, Filtered, Error, Success),
|
|
7
|
+
# user actions, and surface transitions.
|
|
8
|
+
# Writes output artifact to `specs/<Feature>/ui/ui-model.md`.
|
|
9
|
+
#
|
|
10
|
+
# Launch:
|
|
11
|
+
# /appweaver ui-model [strategy] [guidance]
|
|
12
|
+
# =============================================================================
|
|
13
|
+
|
|
14
|
+
name: aw-spec-ui-model
|
|
15
|
+
description: Derive the UI Model (specs/<Feature>/ui/ui-model.md) from workflow-model.md, specifying UI surfaces (pages, dialogs, drawers, modals), routes, interaction states, actions, and navigation transitions.
|
|
16
|
+
version: 1.0.0
|
|
17
|
+
agent_agnostic: true
|
|
18
|
+
dialect: aw-spec.orchestrator/v1
|
|
19
|
+
|
|
20
|
+
inputs:
|
|
21
|
+
user_input:
|
|
22
|
+
description: Optional UI layout or surface guidance.
|
|
23
|
+
required: false
|
|
24
|
+
bind: USER_INPUT
|
|
25
|
+
|
|
26
|
+
scripts:
|
|
27
|
+
actions:
|
|
28
|
+
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
29
|
+
ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
|
|
30
|
+
|
|
31
|
+
vars:
|
|
32
|
+
feature: ""
|
|
33
|
+
feature_dir: ""
|
|
34
|
+
feature_slug: ""
|
|
35
|
+
spec_file: ""
|
|
36
|
+
spec_exists: "false"
|
|
37
|
+
workflow_model_file: ""
|
|
38
|
+
workflow_model_exists: "false"
|
|
39
|
+
active_change: ""
|
|
40
|
+
has_change: "false"
|
|
41
|
+
domain: ""
|
|
42
|
+
prototype_root: ""
|
|
43
|
+
|
|
44
|
+
workflow:
|
|
45
|
+
|
|
46
|
+
# 1. Resolve active feature and paths
|
|
47
|
+
- id: feature_paths
|
|
48
|
+
action: execute_script
|
|
49
|
+
on_error: continue
|
|
50
|
+
script: { ref: actions }
|
|
51
|
+
subcommand: feature-paths
|
|
52
|
+
outputs:
|
|
53
|
+
- { name: feature, from: "$.feature" }
|
|
54
|
+
- { name: feature_dir, from: "$.feature_dir" }
|
|
55
|
+
- { name: feature_slug, from: "$.feature_slug" }
|
|
56
|
+
- { name: spec_file, from: "$.spec_file" }
|
|
57
|
+
- { name: spec_exists, from: "$.spec_exists" }
|
|
58
|
+
- { name: domain, from: "$.domain" }
|
|
59
|
+
- { name: prototype_root, from: "$.prototype_root" }
|
|
60
|
+
|
|
61
|
+
- id: require_feature
|
|
62
|
+
action: verify_context
|
|
63
|
+
require_non_empty: feature_dir
|
|
64
|
+
on_empty: stop
|
|
65
|
+
on_empty_message: "No active feature selected. Run /appweaver select-feature first."
|
|
66
|
+
|
|
67
|
+
- id: require_spec
|
|
68
|
+
action: verify_context
|
|
69
|
+
require_true: spec_exists
|
|
70
|
+
on_false: stop
|
|
71
|
+
on_false_message: "No specification found for this feature. Run /appweaver specify first."
|
|
72
|
+
|
|
73
|
+
# 2. Check workflow-model.md existence
|
|
74
|
+
- id: check_workflow_model
|
|
75
|
+
action: execute_script
|
|
76
|
+
on_error: continue
|
|
77
|
+
script: { ref: actions }
|
|
78
|
+
subcommand: path-exists
|
|
79
|
+
args: ["--path", "{{feature_dir}}/ui/workflow-model.md"]
|
|
80
|
+
outputs:
|
|
81
|
+
- { name: workflow_model_exists, from: "$.exists" }
|
|
82
|
+
|
|
83
|
+
- id: require_workflow_model
|
|
84
|
+
action: verify_context
|
|
85
|
+
require_true: workflow_model_exists
|
|
86
|
+
on_false: stop
|
|
87
|
+
on_false_message: "No Workflow Model found at specs/{{feature}}/ui/workflow-model.md. Run /appweaver workflow-model first."
|
|
88
|
+
|
|
89
|
+
# 3. Assemble workflow model & template context
|
|
90
|
+
- id: ctx_ui_model
|
|
91
|
+
action: build_context
|
|
92
|
+
vars:
|
|
93
|
+
feature_name: "{{feature}}"
|
|
94
|
+
feature_dir: "{{feature_dir}}"
|
|
95
|
+
user_preferences: "{{USER_INPUT}}"
|
|
96
|
+
context:
|
|
97
|
+
- "{{feature_dir}}/ui/workflow-model.md"
|
|
98
|
+
- "{{spec_file}}"
|
|
99
|
+
- { path: ".appweaver/templates/ui-model-template.md", optional: true }
|
|
100
|
+
- { path: ".appweaver/memory/constitution.ui.md", optional: true }
|
|
101
|
+
|
|
102
|
+
# 4. Generate UI Model Artifact (specs/<Feature>/ui/ui-model.md)
|
|
103
|
+
- id: generate_ui_model
|
|
104
|
+
action: agent_generate
|
|
105
|
+
tools: "Read,Write,Edit,Bash"
|
|
106
|
+
permission_mode: acceptEdits
|
|
107
|
+
task: |
|
|
108
|
+
You are authoring Stage 3 (UI Model) of the 4-Stage Spec-Driven UI Pipeline for feature `{{feature_name}}`.
|
|
109
|
+
|
|
110
|
+
Target Artifact Path: `{{feature_dir}}/ui/ui-model.md`
|
|
111
|
+
|
|
112
|
+
Instructions:
|
|
113
|
+
1. Read `specs/{{feature}}/ui/workflow-model.md` and `spec.md` in context.
|
|
114
|
+
2. Translate EVERY workflow (WF-1, WF-2, ...) into explicit **UI Surfaces**:
|
|
115
|
+
- Determine the appropriate UI surface type for each workflow step: `Page`, `Sub-Page`, `Dialog`, `Drawer`, `Modal`, `View`.
|
|
116
|
+
- Map routes or component mount paths (e.g. `/{{feature_slug}}`, `/{{feature_slug}}/create`, modal dialog triggers).
|
|
117
|
+
- Define supported interaction states per surface (`Loading`, `Empty`, `Populated`, `Filtered / Searched`, `Validation Error`, `Submitting`, `Success`, `Error`).
|
|
118
|
+
- Specify interactive controls, form fields, action buttons, and table/card layouts.
|
|
119
|
+
- Map explicit navigation & transition triggers (`On Action -> Opens Surface X`).
|
|
120
|
+
3. Remember the core rule: **Workflow != Single Screen**. A workflow can span multiple surfaces or reuse surfaces with state changes.
|
|
121
|
+
4. Format output according to `.appweaver/templates/ui-model-template.md`.
|
|
122
|
+
5. Write the authored markdown content to `{{feature_dir}}/ui/ui-model.md`.
|
|
123
|
+
|
|
124
|
+
User Guidance:
|
|
125
|
+
{{user_preferences}}
|
|
126
|
+
|
|
127
|
+
End your final reply with a summary and a ```json fence:
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"status": "ok",
|
|
131
|
+
"feature": "{{feature_name}}",
|
|
132
|
+
"ui_model_path": "{{feature_dir}}/ui/ui-model.md"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
outputs:
|
|
136
|
+
- { name: result, from: "$" }
|
|
137
|
+
|
|
138
|
+
outputs:
|
|
139
|
+
feature: "{{feature}}"
|
|
140
|
+
ui_model_path: "{{feature_dir}}/ui/ui-model.md"
|
|
141
|
+
next: "Run /appweaver ui-prototype to generate the executable Next.js prototype application."
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# aw-spec-ui-prototype (orchestrator) — Next.js UI prototype per domain
|
|
3
|
+
#
|
|
4
|
+
# Scaffolds a single shared Next.js prototype app per domain (prototypes/<domain>/),
|
|
5
|
+
# then on every subsequent run adds or regenerates just the active feature's screen/route inside it,
|
|
6
|
+
# driven by that feature's spec.md (+ any active delta-spec.md).
|
|
7
|
+
#
|
|
8
|
+
# Launch:
|
|
9
|
+
# /appweaver ui-prototype [strategy] [guidance]
|
|
10
|
+
# =============================================================================
|
|
11
|
+
|
|
12
|
+
name: aw-spec-ui-prototype
|
|
13
|
+
description: Generate or update a single screen/route inside a domain Next.js UI prototype, driven by the active feature's specification (referencing workflow-model.md and ui-model.md if available, or directly from spec.md).
|
|
14
|
+
version: 3.7.0
|
|
15
|
+
agent_agnostic: true
|
|
16
|
+
dialect: aw-spec.orchestrator/v1
|
|
17
|
+
|
|
18
|
+
inputs:
|
|
19
|
+
user_input:
|
|
20
|
+
description: Optional UI styling or behavior preferences (e.g. dark mode, Tailwind aesthetic, specific mock data).
|
|
21
|
+
required: false
|
|
22
|
+
bind: USER_INPUT
|
|
23
|
+
|
|
24
|
+
scripts:
|
|
25
|
+
actions:
|
|
26
|
+
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
27
|
+
ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
|
|
28
|
+
|
|
29
|
+
vars:
|
|
30
|
+
feature: ""
|
|
31
|
+
feature_dir: ""
|
|
32
|
+
feature_slug: ""
|
|
33
|
+
spec_file: ""
|
|
34
|
+
spec_exists: "false"
|
|
35
|
+
context: ""
|
|
36
|
+
context_dir: ""
|
|
37
|
+
domain_model: ""
|
|
38
|
+
domain_model_exists: "false"
|
|
39
|
+
active_change: ""
|
|
40
|
+
has_change: "false"
|
|
41
|
+
domain: ""
|
|
42
|
+
prototype_root: "prototype"
|
|
43
|
+
project_exists: "false"
|
|
44
|
+
|
|
45
|
+
workflow:
|
|
46
|
+
|
|
47
|
+
# 1. Resolve active feature and its spec directly from .appweaver/feature.json
|
|
48
|
+
# which points to the bounded context directory and then the feature (specs/<BoundedContext>/<Feature>/)
|
|
49
|
+
- id: feature_paths
|
|
50
|
+
action: execute_script
|
|
51
|
+
on_error: continue
|
|
52
|
+
script: { ref: actions }
|
|
53
|
+
subcommand: feature-paths
|
|
54
|
+
outputs:
|
|
55
|
+
- { name: feature, from: "$.feature" }
|
|
56
|
+
- { name: feature_slug, from: "$.feature_slug" } # kebab-case route segment
|
|
57
|
+
- { name: feature_dir, from: "$.feature_dir" }
|
|
58
|
+
- { name: spec_file, from: "$.spec_file" }
|
|
59
|
+
- { name: spec_exists, from: "$.spec_exists" }
|
|
60
|
+
|
|
61
|
+
- id: require_feature
|
|
62
|
+
action: verify_context
|
|
63
|
+
require_non_empty: feature_dir
|
|
64
|
+
on_empty: stop
|
|
65
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first, then re-run ui-prototype."
|
|
66
|
+
|
|
67
|
+
- id: require_spec
|
|
68
|
+
action: verify_context
|
|
69
|
+
require_true: spec_exists
|
|
70
|
+
on_false: stop
|
|
71
|
+
on_false_message: "No specification found for this feature at {{spec_file}}. Run /appweaver specify first to create spec.md."
|
|
72
|
+
|
|
73
|
+
# 2. Resolve the bounded context containing this feature and its canonical domain model
|
|
74
|
+
- id: context_paths
|
|
75
|
+
action: execute_script
|
|
76
|
+
on_error: continue
|
|
77
|
+
script: { ref: actions }
|
|
78
|
+
subcommand: context-paths
|
|
79
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
80
|
+
outputs:
|
|
81
|
+
- { name: context, from: "$.context" }
|
|
82
|
+
- { name: context_dir, from: "$.context_dir" }
|
|
83
|
+
- { name: domain_model, from: "$.domain_model" }
|
|
84
|
+
- { name: domain_model_exists, from: "$.domain_model_exists" }
|
|
85
|
+
|
|
86
|
+
# 3. Resolve active domain
|
|
87
|
+
- id: resolve_domain
|
|
88
|
+
action: execute_script
|
|
89
|
+
on_error: continue
|
|
90
|
+
script: { ref: actions }
|
|
91
|
+
subcommand: resolve-domain
|
|
92
|
+
args: ["--command", "/aw-spec-ui-prototype"]
|
|
93
|
+
outputs:
|
|
94
|
+
- { name: domain, from: "$.domain" }
|
|
95
|
+
|
|
96
|
+
# 4. Resolve prototype root from stacks declaration (.appweaver/stacks.json)
|
|
97
|
+
- id: resolve_prototype_lane
|
|
98
|
+
action: execute_script
|
|
99
|
+
on_error: continue
|
|
100
|
+
script: { ref: actions }
|
|
101
|
+
subcommand: lane-resolve
|
|
102
|
+
outputs:
|
|
103
|
+
- { name: prototype_root, from: "$.prototype.root" }
|
|
104
|
+
|
|
105
|
+
# 5. Check for active change requests (feature-level)
|
|
106
|
+
- id: version_read
|
|
107
|
+
action: execute_script
|
|
108
|
+
on_error: continue
|
|
109
|
+
script: { ref: actions }
|
|
110
|
+
subcommand: version-read
|
|
111
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
112
|
+
outputs:
|
|
113
|
+
- { name: active_change, from: "$.active_change" }
|
|
114
|
+
- { name: has_change, from: "$.has_change" }
|
|
115
|
+
|
|
116
|
+
# 6. Check whether the domain prototype project already exists at prototype_root
|
|
117
|
+
- id: check_project
|
|
118
|
+
action: execute_script
|
|
119
|
+
on_error: continue
|
|
120
|
+
script: { ref: actions }
|
|
121
|
+
subcommand: path-exists
|
|
122
|
+
args: ["--path", "{{prototype_root}}/package.json"]
|
|
123
|
+
outputs:
|
|
124
|
+
- { name: project_exists, from: "$.exists" }
|
|
125
|
+
|
|
126
|
+
# 7. Assemble specification, bounded context domain model, optional UI artifacts, and rules context
|
|
127
|
+
- id: ctx_prototype
|
|
128
|
+
action: build_context
|
|
129
|
+
vars:
|
|
130
|
+
feature_name: "{{feature}}"
|
|
131
|
+
feature_slug: "{{feature_slug}}"
|
|
132
|
+
feature_dir: "{{feature_dir}}"
|
|
133
|
+
context_name: "{{context}}"
|
|
134
|
+
context_dir: "{{context_dir}}"
|
|
135
|
+
domain: "{{domain}}"
|
|
136
|
+
prototype_root: "{{prototype_root}}"
|
|
137
|
+
project_exists: "{{project_exists}}"
|
|
138
|
+
user_preferences: "{{USER_INPUT}}"
|
|
139
|
+
context:
|
|
140
|
+
- "{{spec_file}}"
|
|
141
|
+
- { path: "{{domain_model}}", optional: true }
|
|
142
|
+
- { path: "{{feature_dir}}/ui/workflow-model.md", optional: true }
|
|
143
|
+
- { path: "{{feature_dir}}/ui/ui-model.md", optional: true }
|
|
144
|
+
- { path: ".appweaver/memory/constitution.domain.md", optional: true }
|
|
145
|
+
- { path: ".appweaver/memory/constitution.ui.md", optional: true }
|
|
146
|
+
- { path: "{{feature_dir}}/changes/{{active_change}}/delta-spec.md", optional: true }
|
|
147
|
+
- { path: "{{prototype_root}}/screens.json", optional: true }
|
|
148
|
+
|
|
149
|
+
# 5a. First run only: scaffold the domain Next.js prototype shell if missing
|
|
150
|
+
- id: scaffold_project
|
|
151
|
+
action: agent_generate
|
|
152
|
+
condition: "{{project_exists}} == false"
|
|
153
|
+
tools: "Read,Write,Edit,Bash"
|
|
154
|
+
permission_mode: acceptEdits
|
|
155
|
+
task: |
|
|
156
|
+
There is no prototype project for domain `{{domain}}` yet. Scaffold ONE reusable Next.js application
|
|
157
|
+
shell for domain `{{domain}}` at `{{prototype_root}}/`. This project will be reused and extended by every
|
|
158
|
+
subsequent feature run for `{{domain}}` — do not build any single feature's screen content here.
|
|
159
|
+
|
|
160
|
+
Build only the shared shell:
|
|
161
|
+
1. `package.json`, Next.js App Router baseline (`app/layout.tsx`), global styles/design
|
|
162
|
+
tokens, and client-side state/provider pattern screens will share
|
|
163
|
+
(e.g. a lightweight context for active persona/role).
|
|
164
|
+
2. A shared nav/shell component (sidebar or top nav) that lists available screens by
|
|
165
|
+
reading dynamically from `lib/screens-registry.ts`. It renders each entry's
|
|
166
|
+
`title` field verbatim as the visible label — later screen runs are responsible for
|
|
167
|
+
putting a natural, product-appropriate name there (see the per-screen task), not
|
|
168
|
+
a raw spec title.
|
|
169
|
+
3. A shared persona/role-switcher component — its initial role and persona options
|
|
170
|
+
are populated directly from the actors/personas specified in `spec.md` (under `Actors` /
|
|
171
|
+
`Experience Scope` / `User Stories`) and `ui-model.md`, and registered in `lib/screens-registry.ts`.
|
|
172
|
+
4. `lib/screens-registry.ts` — an empty typed registry (array of
|
|
173
|
+
`{ slug, title, route, specVersion, roles }`) plus a `screens.json` mirror for
|
|
174
|
+
non-JS tooling. This file is APPENDED TO by screen runs.
|
|
175
|
+
5. A clean, production-feeling home page (`app/page.tsx`) for the domain application —
|
|
176
|
+
shared nav and an overview relevant to the domain — using the domain's real product
|
|
177
|
+
name (derive one from `{{domain}}`/spec/constitution, e.g. "Acme" not "Acme Prototype").
|
|
178
|
+
This home page is the app's actual dashboard/landing experience — the entry point a
|
|
179
|
+
real user of this product would land on — not a menu of "screens" or a list mirroring
|
|
180
|
+
spec structure.
|
|
181
|
+
|
|
182
|
+
Do not create the route for `{{feature_name}}` yet — that happens in the next step.
|
|
183
|
+
Ensure `npm install && npm run dev` works with just this shell.
|
|
184
|
+
|
|
185
|
+
**This must read as one coherent real application, never as a list of specs:**
|
|
186
|
+
- Never render the words "prototype", "mock", "demo", "scaffold", "shell", "sample",
|
|
187
|
+
or similar anywhere a user can see them — not in the page title, `<title>`/metadata,
|
|
188
|
+
headers, nav labels, empty states, placeholder copy, button text, or console-visible
|
|
189
|
+
UI. Those words are fine in code comments, filenames, or `PROTOTYPE_NOTES.md`, but
|
|
190
|
+
never in rendered UI.
|
|
191
|
+
- Never render raw spec/traceability identifiers anywhere in the UI — no `REQ-###`,
|
|
192
|
+
`SPEC-SCREEN-###`, `SPEC-COMP-###`, `MOCKDATA-###`, `FEEDBACK-###`, `CHANGE-###`, or
|
|
193
|
+
literal spec section titles/filenames. Those are internal authoring artifacts, not
|
|
194
|
+
product language a real user would ever see.
|
|
195
|
+
- The home page, nav, and browser tab title should use the actual product/domain name
|
|
196
|
+
as if this were the shipping application, not a label describing what this project is.
|
|
197
|
+
- The persona/role switcher must be styled and framed as a normal in-app affordance
|
|
198
|
+
(e.g. an account/role menu a real user of this kind of app would plausibly have),
|
|
199
|
+
not as an obvious dev/testing control bolted onto the UI.
|
|
200
|
+
|
|
201
|
+
**Styling must actually render — this is not optional:**
|
|
202
|
+
- Install and fully configure **Tailwind CSS** (latest stable version, matching whatever
|
|
203
|
+
the installed Next.js version's official setup docs specify — App Router's Tailwind
|
|
204
|
+
setup has changed across versions, e.g. `tailwind.config.ts`/PostCSS config differs
|
|
205
|
+
between Tailwind v3 and v4). Do not stop at `npm install tailwindcss` — verify the
|
|
206
|
+
PostCSS config, content globs, and `@tailwind base/components/utilities` (or v4's
|
|
207
|
+
`@import "tailwindcss"`) directives are all present and correct for the version installed.
|
|
208
|
+
- Create `app/globals.css` with the Tailwind directives plus any design-token CSS
|
|
209
|
+
variables (colors, spacing, radii, fonts), and **explicitly `import "./globals.css"`
|
|
210
|
+
at the top of `app/layout.tsx`.** A missing import here is the most common cause of
|
|
211
|
+
a fully unstyled app — verify it's present before finishing.
|
|
212
|
+
- After scaffolding, actually run `npm run dev` (or `next build`) and confirm no
|
|
213
|
+
Tailwind/PostCSS errors appear in the output before ending this step. Don't just
|
|
214
|
+
assume the config is correct because the files exist.
|
|
215
|
+
- If `constitution.ui.md` or USER_INPUT specifies a different styling approach
|
|
216
|
+
(CSS Modules, a specific component library with its own styling, styled-components,
|
|
217
|
+
etc.), follow that instead of Tailwind — but whichever system is chosen, the same
|
|
218
|
+
rule applies: install it fully, wire it into the root layout, and verify it actually
|
|
219
|
+
renders styled output, not just that the packages are present in `package.json`.
|
|
220
|
+
|
|
221
|
+
**Always use the latest versions and current best practices:**
|
|
222
|
+
- Scaffold against the latest stable Next.js (App Router) and React releases available
|
|
223
|
+
at the time of this run — do not pin to or reproduce an older remembered baseline.
|
|
224
|
+
Resolve versions with `npm view <package> version` (or `npm install <package>@latest`)
|
|
225
|
+
rather than assuming a version from memory.
|
|
226
|
+
- Use current, non-deprecated APIs and patterns for whatever is scaffolded (routing,
|
|
227
|
+
data fetching, styling setup). If a pattern you'd default to has since been superseded
|
|
228
|
+
(e.g. an older config format, a deprecated hook/API), use the current replacement.
|
|
229
|
+
- If a UI/component library or design-token approach is implied by
|
|
230
|
+
`constitution.ui.md`, USER_INPUT, or the spec, install its latest published version
|
|
231
|
+
and use its current component APIs — check the library's current docs/changelog
|
|
232
|
+
rather than relying on a possibly-stale remembered API surface.
|
|
233
|
+
- Note the resolved major versions of Next.js/React and any UI library in a short
|
|
234
|
+
comment at the top of `package.json` or in a `PROTOTYPE_NOTES.md`, so later screen
|
|
235
|
+
runs and reviewers know what "latest" resolved to at scaffold time.
|
|
236
|
+
|
|
237
|
+
# 5b. Every run: generate/update this feature's screen inside the existing domain prototype
|
|
238
|
+
- id: generate_screen
|
|
239
|
+
action: agent_generate
|
|
240
|
+
tools: "Read,Write,Edit,Bash"
|
|
241
|
+
permission_mode: acceptEdits
|
|
242
|
+
task: |
|
|
243
|
+
You are adding or regenerating ONE screen inside the existing Next.js prototype for domain `{{domain}}`
|
|
244
|
+
at `{{prototype_root}}/`. Do NOT touch project scaffolding, `package.json`, shared layout,
|
|
245
|
+
or other features' routes/components except where explicitly instructed below.
|
|
246
|
+
|
|
247
|
+
The feature specification is taken directly from the bounded context directory and feature path defined in `.appweaver/feature.json`:
|
|
248
|
+
`{{spec_file}}` (Bounded Context: `{{context_name}}`, Feature: `{{feature_name}}`).
|
|
249
|
+
Read this specification strictly from `{{spec_file}}`, along with the bounded context's canonical domain model (`{{domain_model}}`),
|
|
250
|
+
and when available, the Workflow Model (`{{feature_dir}}/ui/workflow-model.md`) and UI Model (`{{feature_dir}}/ui/ui-model.md`), plus `{{prototype_root}}/lib/screens-registry.ts` / `screens.json`.
|
|
251
|
+
If `workflow-model.md` and `ui-model.md` are not provided, derive all UI surfaces, workflows, and interaction states directly from `{{spec_file}}`.
|
|
252
|
+
|
|
253
|
+
**SPEC-DRIVEN PROTOTYPE GENERATION (STAGE 4 EXECUTION)**:
|
|
254
|
+
Your goal is to build the executable Next.js application surfaces defined in the spec and UI/workflow models (when available):
|
|
255
|
+
- Implement ALL UI surfaces (Primary Page `/{{feature_slug}}`, sub-routes, modal dialogs, drawers, forms, data grids/cards).
|
|
256
|
+
- Realize all user workflows (`WF-1`, `WF-2`, `WF-3`...) with realistic interactive behavior, persona role-switching, and surface navigation transitions.
|
|
257
|
+
- Handle all specified UI states (`Loading`, `Empty`, `Populated`, `Filtered / Searched`, `Validation Error`, `Submitting`, `Success`, `Error`).
|
|
258
|
+
|
|
259
|
+
1. **Multi-Surface & Route Implementation**:
|
|
260
|
+
- Create or fully regenerate `{{prototype_root}}/app/{{feature_slug}}/page.tsx`
|
|
261
|
+
(and any screen-scoped components under
|
|
262
|
+
`{{prototype_root}}/app/{{feature_slug}}/components/`).
|
|
263
|
+
- Treat this route as regenerated wholesale each run — don't hand-patch it.
|
|
264
|
+
- Build the full, finished screen the spec describes — not a wireframe, stub,
|
|
265
|
+
"coming soon," or reduced placeholder version. A user landing on this route should
|
|
266
|
+
see the actual working application screen, fully styled and populated, matching
|
|
267
|
+
spec.md as if it shipped this way.
|
|
268
|
+
- Never surface "prototype/mock/demo/sample" language, or raw spec/traceability IDs
|
|
269
|
+
(`REQ-###`, `SPEC-SCREEN-###`, etc.) anywhere in this screen's rendered UI (titles,
|
|
270
|
+
headers, empty states, tooltips, button copy). Keep all such labeling out of
|
|
271
|
+
user-visible text entirely.
|
|
272
|
+
|
|
273
|
+
2. **Integrate this screen into the app like a real feature, not a spec entry**:
|
|
274
|
+
- `{{feature_name}}` and any spec title/ID are internal identifiers for you to read —
|
|
275
|
+
never repeat them verbatim as the nav label, page heading, or route's display name.
|
|
276
|
+
Derive a natural, user-facing name the way a real product would phrase it (e.g. a
|
|
277
|
+
spec called "Project Creation Screen" surfaces as a "Projects" nav entry whose
|
|
278
|
+
content includes creating a project — not a nav item literally labeled
|
|
279
|
+
"Project Creation Screen").
|
|
280
|
+
- Decide where this screen naturally belongs in the app's information architecture
|
|
281
|
+
based on what the spec describes, the same way a product designer would: a
|
|
282
|
+
top-level nav item, a sub-page reached by an action on another already-generated
|
|
283
|
+
screen (e.g. a "New Project" button on the dashboard or on a "Projects" list),
|
|
284
|
+
or an entry point added to the shared dashboard — whichever fits how a real user
|
|
285
|
+
would discover and reach this functionality. Don't default to "flat nav item per
|
|
286
|
+
spec" if the spec's own content implies a more natural entry point (e.g. reached
|
|
287
|
+
via a button/action from another screen rather than the top-level nav).
|
|
288
|
+
- If the natural entry point is from another already-generated screen or the
|
|
289
|
+
dashboard, update that screen/dashboard minimally to add the real link/button/card
|
|
290
|
+
that leads here — don't leave this screen orphaned and reachable only by URL.
|
|
291
|
+
|
|
292
|
+
3. **Specification-driven behavior**:
|
|
293
|
+
- Derive all behavior exclusively from the active specification for this feature.
|
|
294
|
+
- Implement all functional requirements, business rules, invariants, validations,
|
|
295
|
+
constraints, state transitions, and workflows explicitly defined in spec.md.
|
|
296
|
+
- Do not invent business rules absent from the spec. Use reasonable UI defaults only
|
|
297
|
+
for presentation/interaction mechanics.
|
|
298
|
+
|
|
299
|
+
4. **Roles, personas, and permission rules from spec**:
|
|
300
|
+
- Derive all roles/personas directly from `spec.md` (under `Actors` / `Experience Scope` / `User Stories`) and `ui-model.md`.
|
|
301
|
+
- Ensure every role defined in the specification exists in the SHARED persona/role-switcher context.
|
|
302
|
+
- Wire the UI controls dynamically so switching persona demonstrates role-based visibility, disabled inputs, and permission workflows (e.g. PM vs PMO vs Delivery Head) strictly as specified.
|
|
303
|
+
|
|
304
|
+
5. **Mock data**:
|
|
305
|
+
- Place this feature's mock data under
|
|
306
|
+
`{{prototype_root}}/lib/mock-data/{{feature_slug}}.ts`, isolated from other screens.
|
|
307
|
+
- Data values should read as realistic, plausible content for this domain (real-sounding
|
|
308
|
+
names, dates, amounts, statuses) — not "Lorem ipsum," "Test User 1," "Sample Item,"
|
|
309
|
+
or other obviously-fake placeholder text. The screen should look fully populated and
|
|
310
|
+
real, even though the data behind it is static.
|
|
311
|
+
|
|
312
|
+
6. **Reuse, don't duplicate**:
|
|
313
|
+
- Reuse existing shared components (nav shell, buttons, layout primitives, design
|
|
314
|
+
tokens) from the shell in the project.
|
|
315
|
+
|
|
316
|
+
7. **Styling must render on this screen too**:
|
|
317
|
+
- Before writing this screen, confirm the shell's styling setup is actually wired
|
|
318
|
+
up — `app/globals.css` exists and is imported in `app/layout.tsx`, and the
|
|
319
|
+
Tailwind/CSS config from the shell is intact. If it's missing or broken, fix it
|
|
320
|
+
as part of this run and note that in your final summary; don't build a styled-looking
|
|
321
|
+
screen on top of a broken/absent styling pipeline.
|
|
322
|
+
- Use the shell's existing design tokens and Tailwind utility classes (or whatever
|
|
323
|
+
styling system the shell uses) rather than inline style objects or
|
|
324
|
+
ad-hoc CSS that bypasses the shared system — inline styles that "look fine" in
|
|
325
|
+
isolation are usually the sign the shared pipeline isn't actually being used.
|
|
326
|
+
- If this screen needs a component from a UI library not yet installed in the shell
|
|
327
|
+
(e.g. a data table, date picker), install it into the shell's `package.json` (latest
|
|
328
|
+
version, per below) and ensure its required CSS/theme setup is added to
|
|
329
|
+
`app/globals.css` or its own import — a component library added without its styles
|
|
330
|
+
wired in is another common source of unstyled output.
|
|
331
|
+
|
|
332
|
+
8. **Always use the latest UI, components, and libraries**:
|
|
333
|
+
- Any new dependency added for this screen (UI library, icon set, chart/table/form
|
|
334
|
+
component, date picker, etc.) must be the latest stable published version —
|
|
335
|
+
resolve it with `npm view <package> version` or install via `@latest` rather than
|
|
336
|
+
writing a version from memory.
|
|
337
|
+
- When reusing shared components from the shell, check whether the shell's installed
|
|
338
|
+
versions are current; if `{{prototype_root}}/PROTOTYPE_NOTES.md` or `package.json`
|
|
339
|
+
indicates they're stale relative to what's now available, flag it in your final
|
|
340
|
+
summary rather than silently building on outdated components — don't upgrade
|
|
341
|
+
shared/shell dependencies yourself from a screen run.
|
|
342
|
+
- Prefer each library's current, non-deprecated component API and patterns
|
|
343
|
+
(e.g. current shadcn/ui component structure, current Next.js Image/Link/Font APIs)
|
|
344
|
+
over older remembered forms of the same API.
|
|
345
|
+
- Do not introduce a second library that duplicates something the shell or an
|
|
346
|
+
earlier screen already standardized on — "latest" applies to versions, not to
|
|
347
|
+
swapping in a different library each run.
|
|
348
|
+
|
|
349
|
+
9. **Registry update**:
|
|
350
|
+
- Add or update this feature's entry in `lib/screens-registry.ts` and `screens.json`:
|
|
351
|
+
`{ slug: "{{feature_slug}}", title: "<natural product-facing name from step 2, NOT
|
|
352
|
+
the raw spec title>", route: "/{{feature_slug}}", specVersion: <from spec.md if
|
|
353
|
+
present>, roles: [...] }`.
|
|
354
|
+
- `title` here drives the visible nav label — it must be the naturalized name from
|
|
355
|
+
step 2, never `{{feature_name}}` or a spec ID verbatim. If you need to retain the
|
|
356
|
+
original spec title/ID for traceability, add it as a separate non-rendered field
|
|
357
|
+
(e.g. `specRef`) rather than reusing `title` for it.
|
|
358
|
+
|
|
359
|
+
User Preferences / Guidance:
|
|
360
|
+
{{user_preferences}}
|
|
361
|
+
|
|
362
|
+
End your final reply with a summary of what was added/changed and a ```json code block:
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"status": "ok",
|
|
366
|
+
"domain": "{{domain}}",
|
|
367
|
+
"feature": "{{feature_name}}",
|
|
368
|
+
"slug": "{{feature_slug}}",
|
|
369
|
+
"route": "/{{feature_slug}}",
|
|
370
|
+
"prototype_root": "{{prototype_root}}",
|
|
371
|
+
"launch_command": "cd {{prototype_root}} && npm run dev"
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
outputs:
|
|
375
|
+
- { name: result, from: "$" }
|
|
376
|
+
|
|
377
|
+
outputs:
|
|
378
|
+
domain: "{{domain}}"
|
|
379
|
+
context: "{{context}}"
|
|
380
|
+
context_dir: "{{context_dir}}"
|
|
381
|
+
feature: "{{feature}}"
|
|
382
|
+
spec_file: "{{spec_file}}"
|
|
383
|
+
route: "/{{feature_slug}}"
|
|
384
|
+
prototype_root: "{{prototype_root}}"
|
|
385
|
+
launch_hint: "First time: cd {{prototype_root}} && npm install && npm run dev — after that, just rerun ui-prototype per feature and refresh the browser."
|
|
386
|
+
next: "Visit http://localhost:3000/{{feature_slug}} to review this screen, or / for the full screen list."
|