aw-spec-cli 0.1.21 → 0.1.23
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/orchestrator.py +47 -3
- 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-constitution.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +4 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +115 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +5 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +225 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1 -1
- 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-select-domain.orch.yaml +3 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +104 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +159 -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 +153 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +203 -212
- package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +191 -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/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +3 -3
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +5 -123
- package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +784 -0
- package/assets/foundations/java/Hexagonal/pack-foundation.sh +357 -0
- package/assets/foundations/java/Hexagonal/unpack-foundation.sh +399 -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}}"]
|
|
@@ -671,4 +771,7 @@ outputs:
|
|
|
671
771
|
checklist_file: "{{checklist_file}}"
|
|
672
772
|
checklist_quality: "{{checklist_passed}}/{{checklist_total}} items passing"
|
|
673
773
|
note: "Behaviour and structure were authored together: the spec says what the system must do, {{domain_model}} says what the domain IS. The aggregate root, its entities and its invariants (BR-n) live in the model and are cited from the spec by id — never restated there, because several specs act on one aggregate and a per-spec copy drifts. On the DELTA path neither master was touched: this run wrote changes/{{cr_id}}/delta-spec.md and {{delta_model}}, and that model delta sits BESIDE the master where every other open delta can see it while being authored. WAVE {{wave}} is its parallel-development level — deltas sharing a wave are independent, a higher wave is implemented only after the lower ones land. The wave is DERIVED from the model delta's `## Depends on`: one above the highest delta named there, stamped into both halves as soon as it was authored ({{wave_message}}). To move it, correct that section and re-run `.appweaver/scripts/bash/aw-spec-actions.sh cr-wave-derive --cr-id {{cr_id}} --stamp`; finalize-delta refuses a change whose wave contradicts it. {{open_count}} change(s) are open on this feature."
|
|
674
|
-
|
|
774
|
+
# Both paths spell out their WHOLE remaining chain. The bootstrap path named only
|
|
775
|
+
# `plan` and stopped there, which left a first greenfield run with no successor at
|
|
776
|
+
# the exact point the delta path was fully documented.
|
|
777
|
+
next: "/appweaver plan — BOOTSTRAP authors backend-plan.md from the spec + the domain model (plus frontend-plan.md where a UI lane is declared); a DELTA (this run opened change {{cr_id}}, wave {{wave}}) authors the delta plans for it. BOOTSTRAP then flows: plan → analyze-plan → implement → build → analyze-slice → run → deploy (analyze-plan is the spec↔plan gate and it repairs and stops only while NO change is open). A change instead flows: analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta (finalize-delta merges the delta into spec.md + domain-model.md — not the lane plans, which are derived from those two — but leaves the change open; analyze-slice verifies the slice against the merged master; close-delta archives the change and bumps the version). ⚠️ With more than one change open, plan, analyze-plan-delta and implement ASK which one they are for (pass the id as the argument to skip the prompt) and activate the answer; finalize-delta and close-delta still act on whichever change is active — so finish or close the others deliberately."
|
|
@@ -0,0 +1,159 @@
|
|
|
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" } # kebab-case route segment
|
|
56
|
+
- { name: spec_file, from: "$.spec_file" }
|
|
57
|
+
- { name: spec_exists, from: "$.spec_exists" }
|
|
58
|
+
|
|
59
|
+
# domain and prototype_root have their OWN resolvers — feature-paths answers for the
|
|
60
|
+
# feature's documents and nothing else, so binding them here left both empty and the
|
|
61
|
+
# emptiness reached the prompts as a blank path segment rather than an error.
|
|
62
|
+
- id: resolve_domain
|
|
63
|
+
action: execute_script
|
|
64
|
+
on_error: continue
|
|
65
|
+
script: { ref: actions }
|
|
66
|
+
subcommand: resolve-domain
|
|
67
|
+
args: ["--command", "/aw-spec-ui-model"]
|
|
68
|
+
outputs:
|
|
69
|
+
- { name: domain, from: "$.domain" }
|
|
70
|
+
|
|
71
|
+
- id: resolve_prototype_lane
|
|
72
|
+
action: execute_script
|
|
73
|
+
on_error: continue
|
|
74
|
+
script: { ref: actions }
|
|
75
|
+
subcommand: lane-resolve
|
|
76
|
+
outputs:
|
|
77
|
+
- { name: prototype_root, from: "$.prototype.root" }
|
|
78
|
+
|
|
79
|
+
- id: require_feature
|
|
80
|
+
action: verify_context
|
|
81
|
+
require_non_empty: feature_dir
|
|
82
|
+
on_empty: stop
|
|
83
|
+
on_empty_message: "No active feature selected. Run /appweaver select-feature first."
|
|
84
|
+
|
|
85
|
+
- id: require_spec
|
|
86
|
+
action: verify_context
|
|
87
|
+
require_true: spec_exists
|
|
88
|
+
on_false: stop
|
|
89
|
+
on_false_message: "No specification found for this feature. Run /appweaver specify first."
|
|
90
|
+
|
|
91
|
+
# 2. Check workflow-model.md existence
|
|
92
|
+
- id: check_workflow_model
|
|
93
|
+
action: execute_script
|
|
94
|
+
on_error: continue
|
|
95
|
+
script: { ref: actions }
|
|
96
|
+
subcommand: path-exists
|
|
97
|
+
args: ["--path", "{{feature_dir}}/ui/workflow-model.md"]
|
|
98
|
+
outputs:
|
|
99
|
+
- { name: workflow_model_exists, from: "$.exists" }
|
|
100
|
+
|
|
101
|
+
- id: require_workflow_model
|
|
102
|
+
action: verify_context
|
|
103
|
+
require_true: workflow_model_exists
|
|
104
|
+
on_false: stop
|
|
105
|
+
on_false_message: "No Workflow Model found at specs/{{feature}}/ui/workflow-model.md. Run /appweaver workflow-model first."
|
|
106
|
+
|
|
107
|
+
# 3. Assemble workflow model & template context
|
|
108
|
+
- id: ctx_ui_model
|
|
109
|
+
action: build_context
|
|
110
|
+
vars:
|
|
111
|
+
feature_name: "{{feature}}"
|
|
112
|
+
feature_dir: "{{feature_dir}}"
|
|
113
|
+
user_preferences: "{{USER_INPUT}}"
|
|
114
|
+
context:
|
|
115
|
+
- "{{feature_dir}}/ui/workflow-model.md"
|
|
116
|
+
- "{{spec_file}}"
|
|
117
|
+
- { path: ".appweaver/templates/ui-model-template.md", optional: true }
|
|
118
|
+
- { path: ".appweaver/memory/constitution.ui.md", optional: true }
|
|
119
|
+
|
|
120
|
+
# 4. Generate UI Model Artifact (specs/<Feature>/ui/ui-model.md)
|
|
121
|
+
- id: generate_ui_model
|
|
122
|
+
action: agent_generate
|
|
123
|
+
tools: "Read,Write,Edit,Bash"
|
|
124
|
+
permission_mode: acceptEdits
|
|
125
|
+
task: |
|
|
126
|
+
You are authoring Stage 3 (UI Model) of the 4-Stage Spec-Driven UI Pipeline for feature `{{feature_name}}`.
|
|
127
|
+
|
|
128
|
+
Target Artifact Path: `{{feature_dir}}/ui/ui-model.md`
|
|
129
|
+
|
|
130
|
+
Instructions:
|
|
131
|
+
1. Read `specs/{{feature}}/ui/workflow-model.md` and `spec.md` in context.
|
|
132
|
+
2. Translate EVERY workflow (WF-1, WF-2, ...) into explicit **UI Surfaces**:
|
|
133
|
+
- Determine the appropriate UI surface type for each workflow step: `Page`, `Sub-Page`, `Dialog`, `Drawer`, `Modal`, `View`.
|
|
134
|
+
- Map routes or component mount paths (e.g. `/{{feature_slug}}`, `/{{feature_slug}}/create`, modal dialog triggers).
|
|
135
|
+
- Define supported interaction states per surface (`Loading`, `Empty`, `Populated`, `Filtered / Searched`, `Validation Error`, `Submitting`, `Success`, `Error`).
|
|
136
|
+
- Specify interactive controls, form fields, action buttons, and table/card layouts.
|
|
137
|
+
- Map explicit navigation & transition triggers (`On Action -> Opens Surface X`).
|
|
138
|
+
3. Remember the core rule: **Workflow != Single Screen**. A workflow can span multiple surfaces or reuse surfaces with state changes.
|
|
139
|
+
4. Format output according to `.appweaver/templates/ui-model-template.md`.
|
|
140
|
+
5. Write the authored markdown content to `{{feature_dir}}/ui/ui-model.md`.
|
|
141
|
+
|
|
142
|
+
User Guidance:
|
|
143
|
+
{{user_preferences}}
|
|
144
|
+
|
|
145
|
+
End your final reply with a summary and a ```json fence:
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"status": "ok",
|
|
149
|
+
"feature": "{{feature_name}}",
|
|
150
|
+
"ui_model_path": "{{feature_dir}}/ui/ui-model.md"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
outputs:
|
|
154
|
+
- { name: result, from: "$" }
|
|
155
|
+
|
|
156
|
+
outputs:
|
|
157
|
+
feature: "{{feature}}"
|
|
158
|
+
ui_model_path: "{{feature_dir}}/ui/ui-model.md"
|
|
159
|
+
next: "Run /appweaver ui-prototype to generate the executable Next.js prototype application."
|