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.
Files changed (51) hide show
  1. package/assets/.appweaver/STACK-PROFILES.md +87 -8
  2. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +30 -0
  3. package/assets/.appweaver/orchestrator/orchestrator.py +47 -3
  4. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +41 -8
  5. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +62 -2
  6. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +18 -5
  7. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +1 -1
  8. package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +4 -1
  9. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +115 -27
  10. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +5 -1
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +225 -27
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -15
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1 -1
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +39 -0
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +28 -7
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +3 -1
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +104 -1
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +159 -0
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +386 -0
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +153 -0
  21. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +203 -212
  22. package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
  23. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +191 -224
  24. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +4 -1
  25. package/assets/.appweaver/scripts/python/aw-crstate.py +127 -2
  26. package/assets/.appweaver/scripts/python/aw-gaps.py +119 -0
  27. package/assets/.appweaver/scripts/python/aw-payload-parity.py +17 -1
  28. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +84 -4
  29. package/assets/.appweaver/scripts/python/aw-plangate.py +216 -0
  30. package/assets/.appweaver/scripts/python/aw-principles.py +108 -0
  31. package/assets/.appweaver/scripts/python/aw-stack.py +6 -0
  32. package/assets/.appweaver/scripts/python/aw-xref.py +141 -4
  33. package/assets/.appweaver/stack-profiles/angular.json +26 -0
  34. package/assets/.appweaver/stack-profiles/blazor-wasm.json +38 -0
  35. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +38 -0
  36. package/assets/.appweaver/stack-profiles/java-spring.json +19 -0
  37. package/assets/.appweaver/stack-profiles/nextjs.json +26 -0
  38. package/assets/.appweaver/stack-profiles/node-express.json +26 -0
  39. package/assets/.appweaver/stack-profiles/python-fastapi.json +15 -0
  40. package/assets/.appweaver/stack-profiles/react-vite.json +26 -0
  41. package/assets/.appweaver/stack-profiles/sveltekit.json +26 -0
  42. package/assets/.appweaver/stack-profiles/vue-vite.json +26 -0
  43. package/assets/.appweaver/templates/ui-model-template.md +67 -0
  44. package/assets/.appweaver/templates/workflow-model-template.md +62 -0
  45. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +3 -3
  46. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +5 -123
  47. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +784 -0
  48. package/assets/foundations/java/Hexagonal/pack-foundation.sh +357 -0
  49. package/assets/foundations/java/Hexagonal/unpack-foundation.sh +399 -0
  50. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +44 -0
  51. 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
- next: "/appweaver plan — BOOTSTRAP authors backend-plan.md from the spec + the domain model; a DELTA (this run opened change {{cr_id}}, wave {{wave}}) authors the delta plans for it. A change then 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."
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."