aw-spec-cli 0.1.25 → 0.1.27
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/.agents/skills/appweaver/SKILL.md +7 -47
- package/assets/.appweaver/ORCH-DIALECT.md +13 -9
- package/assets/.appweaver/RULE-PARTITION.md +3 -3
- package/assets/.appweaver/STACK-PROFILES.md +188 -101
- package/assets/.appweaver/domain.json +1 -1
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
- package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
- package/assets/.appweaver/orchestrator/README.md +120 -53
- package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
- package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
- package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +349 -0
- package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +381 -0
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
- package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +5 -5
- package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +14 -14
- package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
- package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +13 -13
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +29 -28
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +53 -53
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +284 -128
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +224 -70
- package/assets/.appweaver/scripts/python/aw-foundation.py +809 -20
- package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
- package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
- package/assets/.appweaver/scripts/python/aw-stack.py +195 -89
- package/assets/.appweaver/stack-profiles/angular.json +2 -1
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +16 -3
- package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
- package/assets/.appweaver/stack-profiles/java-spring.json +12 -5
- package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
- package/assets/.appweaver/stack-profiles/node-express.json +8 -2
- package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
- package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
- package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
- package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
- package/assets/.appweaver/stacks.json +37 -1
- package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
- package/assets/.claude/skills/appweaver/SKILL.md +7 -46
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
- package/assets/foundations/foundation.spec.template.txt +73 -0
- package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +1 -1
- package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
- package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
- package/assets/guardrails/README.md +31 -17
- package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +5 -5
- package/assets/guardrails/{projects/dotnet-default-project → project-specific}/tech-rule-bindings.md +151 -114
- package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
- package/assets/guardrails/technology/nextjs/api-client.md +1 -1
- package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
- package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
- package/assets/guardrails/technology/nextjs/design-system.md +1 -1
- package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
- package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
- package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
- package/package.json +1 -1
- package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
- package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
- package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
- package/assets/.kilocode/agent.json +0 -28
- package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
- package/assets/.kilocode/workflows/appweaver.md +0 -55
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/service/technical-requirements.md +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# AppWeaver launcher
|
|
2
|
+
|
|
3
|
+
Every agent's `/appweaver` command points here. These instructions are the same for
|
|
4
|
+
every agent; the launcher you came from only says which agent you are, or — in a
|
|
5
|
+
folder that several agents read — tells you to find yourself in the profile table.
|
|
6
|
+
|
|
7
|
+
Runs one converted `aw-spec-*` workflow on the shared, agent-agnostic engine. All orchestration and **all context management live in the workflow YAML + engine** (`.appweaver/orchestrator/orchestrator.py`): the interpreter assembles the COMPLETE payload (system + user) for every request; you never author generation context yourself. You run the interpreter, fulfill each request it hands you, and relay every human-facing interaction to the user.
|
|
8
|
+
|
|
9
|
+
Usage: `/appweaver <skill> [strategy] [input…]` — e.g. `/appweaver select-stack`, `/appweaver specify spawn Build an order API`, `/appweaver analyze-slice`.
|
|
10
|
+
|
|
11
|
+
- **Engine + workflows (common, shared by all agents):** `.appweaver/orchestrator/orchestrator.py`, `.appweaver/orchestrator/workflows/aw-spec-<skill>.orch.yaml`, shared modules in `.appweaver/orchestrator/modules/`, shared scripts in `.appweaver/scripts/`
|
|
12
|
+
- **Working directory:** run every command from the workspace root (the folder that contains `.appweaver/`).
|
|
13
|
+
|
|
14
|
+
## Profile table
|
|
15
|
+
|
|
16
|
+
Find the row for the agent you are. Its profile is your transport profile: the CLI that `spawn` launches and the SDK that `sdk` / `sdk-apply` import. Read the profile's `note` before using it — it states that agent's limits (model name format, isolation, what must be installed and signed in).
|
|
17
|
+
|
|
18
|
+
| You are | Profile | `spawn` runs | `sdk` / `sdk-apply` |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Claude Code | `.claude/agent.json` | `claude -p` | ✓ |
|
|
21
|
+
| Antigravity | `.agents/agent.json` | `agy` | ✓ |
|
|
22
|
+
| Kilo Code | `.kilo/agent.json` | `kilo run` | ✓ (Claude Agent SDK — needs Claude access) |
|
|
23
|
+
| Cursor | `.cursor/agent.json` | `cursor-agent -p` | — |
|
|
24
|
+
| GitHub Copilot | `.copilot/agent.json` | `copilot -p` | — |
|
|
25
|
+
| Devin Desktop / Devin CLI (formerly Windsurf) | `.devin/agent.json` | `devin -p` | — |
|
|
26
|
+
| Cline | `.cline/agent.json` | `cline` | — |
|
|
27
|
+
| Roo Code | `.roo/agent.json` | `roo --print` | — |
|
|
28
|
+
| opencode | `.opencode/agent.json` | `opencode run` | — |
|
|
29
|
+
| Factory Droid | `.factory/agent.json` | `droid exec` | — |
|
|
30
|
+
| Augment | `.augment/agent.json` | `auggie --print` | — |
|
|
31
|
+
| Continue | `.continue/agent.json` | `cn -p` | — |
|
|
32
|
+
| Kiro | `.kiro/agent.json` | `kiro-cli chat` | — |
|
|
33
|
+
| OpenAI Codex | `.codex/agent.json` | `codex exec` | — |
|
|
34
|
+
| Gemini CLI | `.gemini/agent.json` | `gemini -p` | — |
|
|
35
|
+
| Amp | `.amp/agent.json` | `amp -x` | — |
|
|
36
|
+
| any other agent | — | — | — |
|
|
37
|
+
|
|
38
|
+
## Strategies
|
|
39
|
+
|
|
40
|
+
- **`agent`** (default) — YOU fulfill each generation through the checkpoint channel. Works for every agent and needs no profile.
|
|
41
|
+
- **`spawn`** — each generation runs in a fresh process of your agent's CLI, as your profile describes. Needs your row's profile and that CLI on PATH.
|
|
42
|
+
- **`sdk`** — an isolated SDK session generates and applies. Needs a profile with an `sdk` block.
|
|
43
|
+
- **`sdk-apply`** — an isolated SDK session generates read-only; YOU apply its output (pending kind `apply`). Needs a profile with an `sdk` block.
|
|
44
|
+
|
|
45
|
+
If the user names a strategy your row does not support — or you have no row and they name anything but `agent` — say so and stop.
|
|
46
|
+
|
|
47
|
+
## Execution Steps
|
|
48
|
+
|
|
49
|
+
1. **Parse Arguments** (`<skill> [strategy] [input…]`):
|
|
50
|
+
- `skill` (required): the aw-spec skill name, e.g. `select-stack`, `foundation`, `specify`, `design`, `implement`, `build`. Resolve the workflow file `.appweaver/orchestrator/workflows/aw-spec-<skill>.orch.yaml`. If it does not exist, list the available `aw-spec-*.orch.yaml` files in that folder and stop.
|
|
51
|
+
- `strategy` (optional, one of `agent`, `spawn`, `sdk`, `sdk-apply`; default `agent`): if the first word after the skill is one of these, it is the strategy. Always pass `--strategy <strategy>`.
|
|
52
|
+
- Everything after the strategy is the user input: pass it as `--input "<text>"` (omit when empty).
|
|
53
|
+
- `--agent-profile <your profile>` is required for `spawn`, `sdk`, and `sdk-apply` (`agent` needs no profile). If the SDK package isn't installed, add `--sdk-install`.
|
|
54
|
+
- **Always** pass `--checkpoint .appweaver/orchestrator/.state/<skill>.state.json` — for EVERY strategy. Converted skills contain interactive steps (questions, selections, hooks); the checkpoint is how they reach you and the user. Strategies only govern who generates.
|
|
55
|
+
- `spawn` may also add `--model <name>` (in the form your profile's `note` gives) and `--isolation bare|fresh` (only where your profile defines isolation args); `sdk`/`sdk-apply` accept `--model <name>`.
|
|
56
|
+
|
|
57
|
+
2. **Run the Interpreter** in the terminal:
|
|
58
|
+
```bash
|
|
59
|
+
python3 .appweaver/orchestrator/orchestrator.py \
|
|
60
|
+
.appweaver/orchestrator/workflows/aw-spec-<skill>.orch.yaml \
|
|
61
|
+
--strategy <strategy> \
|
|
62
|
+
--checkpoint .appweaver/orchestrator/.state/<skill>.state.json \
|
|
63
|
+
[--agent-profile <your profile>] # spawn, sdk, sdk-apply \
|
|
64
|
+
[--input "<user input>"] \
|
|
65
|
+
--json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
3. **Handle the Suspend/Resume Loop** — the exit code tells you what happened:
|
|
69
|
+
- `0` — done. Go to step 4.
|
|
70
|
+
- `1` — stopped by a gate. Go to step 4.
|
|
71
|
+
- `2` — **suspended, NOT an error.** The interpreter is waiting for you. Do not debug, retry with other flags, or edit the workflow, engine, or state files. Read the printed `pending` JSON and dispatch on `pending.kind`; fulfill it, write the response to `pending.response_path`, then re-run the SAME command. Repeat until exit `0` or `1`.
|
|
72
|
+
|
|
73
|
+
Dispatch on `pending.kind`:
|
|
74
|
+
- **`ask`** — ask the USER the `prompt` with the listed `options` (use your question tool; without one, post the prompt and options in chat as a numbered list, say that more than one may be picked when `multi` is true, and END YOUR TURN — never answer it yourself). When the user answers, write the chosen answer as PLAIN TEXT to `response_path` (comma-separated values when `multi` is true).
|
|
75
|
+
- **`select`** — ask the USER to pick ONE of `options` (use your question tool; without one, post the options in chat as a numbered list and END YOUR TURN). When the user answers, write the chosen value as plain text to `response_path`.
|
|
76
|
+
- **`hook`** — run each MANDATORY hook in `hooks` in this conversation; optional hooks are at your discretion. Each hook names a slash command (`slash`) from an extension (`extension`); if your agent does not have that command, read `.appweaver/extensions/<extension>/commands/<slash without the leading />.md` and follow it. Then write `done` to `response_path`.
|
|
77
|
+
- **`author`** — read `system_path` + `user_path` and treat them as your ONLY standards and context. Author the COMPLETE content of the file named in `target` and write it — content ONLY, no commentary, no code fence — to `response_path`. Do NOT write the target file yourself; the interpreter does that.
|
|
78
|
+
- **`agent_generate`** — read `system_path` + `user_path`; perform the task YOURSELF with the listed `tools` within `permission_mode`; write your full final reply — ending with the required ```json fence — to `response_path`. `tools` uses Claude Code tool names (`Read`, `Write`, `Edit`, `Bash`, `Glob`, `Grep`); if yours differ, use your own equivalents.
|
|
79
|
+
- **`agent_query` / `agent_review`** — same as above but READ-ONLY (do not modify files); the reply must end with the required ```json fence.
|
|
80
|
+
- **`apply`** — an isolated generation already decided the changes: read `artifact_path` and write its file contents EXACTLY to the paths it names, then write the confirmation ```json fence to `response_path`.
|
|
81
|
+
- If `pending.note` is present, your previous response was rejected — follow the note and rewrite `response_path`.
|
|
82
|
+
|
|
83
|
+
4. **Report**:
|
|
84
|
+
Report the final JSON (`status`, `outputs`, and any `reason`) to the user. On `stopped`, relay the gate message verbatim — it tells the user what to fix or run first.
|
|
85
|
+
|
|
86
|
+
## Adding an agent
|
|
87
|
+
|
|
88
|
+
Add its profile (see `AGENT-PROFILE.md`), add its row to the profile table above, and give it a launcher in its own native format that points here and names that profile.
|
|
@@ -20,38 +20,68 @@ This engine is now the **only** pipeline that ships. The earlier declarative tie
|
|
|
20
20
|
## General vs. agent-specific (file layout)
|
|
21
21
|
|
|
22
22
|
The transport **profile lives once at each agent's root** (`.claude/agent.json`,
|
|
23
|
-
`.agents/agent.json`, `.
|
|
24
|
-
that agent shares it — no per-skill duplication.
|
|
25
|
-
|
|
23
|
+
`.agents/agent.json`, `.kilo/agent.json`, …), so every orchestrator skill for
|
|
24
|
+
that agent shares it — no per-skill duplication. The `/appweaver` instructions
|
|
25
|
+
live once too, in `LAUNCHER.md`; each agent's launcher is a thin pointer to it.
|
|
26
|
+
A launcher in a folder only one agent reads names that agent's profile; a
|
|
27
|
+
launcher in a folder several agents read (`.claude/skills/`, `.agents/skills/`)
|
|
28
|
+
names none, and the agent finds its row in `LAUNCHER.md`'s profile table.
|
|
26
29
|
|
|
27
30
|
```
|
|
28
31
|
.appweaver/orchestrator/ ← GENERAL (shared by all agents)
|
|
29
32
|
orchestrator.py engine (profile-driven; no agent hardcoded)
|
|
30
|
-
|
|
33
|
+
LAUNCHER.md the /appweaver instructions + profile table (every launcher points here)
|
|
34
|
+
workflows/_smoke.orch.yaml CI smoke: every construct, mock, writes only to .smoke-out/
|
|
31
35
|
AGENT-PROFILE.md the transport-profile schema
|
|
32
36
|
README.md
|
|
33
37
|
|
|
34
38
|
.claude/agent.json ← Claude Code profile (all its skills share this)
|
|
35
|
-
.claude/skills/appweaver
|
|
39
|
+
.claude/skills/appweaver/SKILL.md ← launcher (shared folder: Copilot, Cursor, Kilo read it too)
|
|
36
40
|
.agents/agent.json ← Antigravity profile
|
|
37
|
-
.agents/skills/appweaver
|
|
38
|
-
.
|
|
39
|
-
.
|
|
41
|
+
.agents/skills/appweaver/SKILL.md ← launcher (shared folder: Codex, Gemini CLI, Amp, Devin, Copilot, Cursor, Kilo read it too)
|
|
42
|
+
.kilo/agent.json ← Kilo Code profile
|
|
43
|
+
.kilo/agents/appweaver-{edit,read}.md ← Kilo agents a spawned step runs as
|
|
44
|
+
.kilo/commands/appweaver.md ← Kilo Code launcher
|
|
45
|
+
.cursor/agent.json ← Cursor profile
|
|
46
|
+
.cursor/commands/appweaver.md ← Cursor launcher
|
|
47
|
+
.copilot/agent.json ← GitHub Copilot profile
|
|
48
|
+
.github/prompts/appweaver.prompt.md ← GitHub Copilot launcher
|
|
49
|
+
.devin/agent.json ← Devin profile (Devin Desktop, formerly Windsurf)
|
|
50
|
+
.devin/workflows/appweaver.md ← Devin launcher
|
|
51
|
+
.cline/agent.json ← Cline profile (not in .clinerules/: every file there is a rule)
|
|
52
|
+
.clinerules/workflows/appweaver.md ← Cline launcher (/appweaver.md)
|
|
53
|
+
.roo/agent.json ← Roo Code profile
|
|
54
|
+
.roo/commands/appweaver.md ← Roo Code launcher
|
|
55
|
+
.opencode/agent.json ← opencode profile
|
|
56
|
+
.opencode/agents/appweaver-{edit,read}.md ← opencode agents a spawned step runs as
|
|
57
|
+
.opencode/commands/appweaver.md ← opencode launcher
|
|
58
|
+
.factory/agent.json ← Factory Droid profile
|
|
59
|
+
.factory/commands/appweaver.md ← Factory Droid launcher
|
|
60
|
+
.augment/agent.json ← Augment profile
|
|
61
|
+
.augment/commands/appweaver.md ← Augment launcher
|
|
62
|
+
.continue/agent.json ← Continue profile
|
|
63
|
+
.continue/prompts/appweaver.md ← Continue launcher (invokable prompt)
|
|
64
|
+
.kiro/agent.json ← Kiro profile
|
|
65
|
+
.kiro/skills/appweaver/SKILL.md ← Kiro launcher
|
|
66
|
+
.codex/agent.json ← OpenAI Codex profile (launcher: .agents/skills/)
|
|
67
|
+
.gemini/agent.json ← Gemini CLI profile (launcher: .agents/skills/)
|
|
68
|
+
.amp/agent.json ← Amp profile (launcher: .agents/skills/)
|
|
69
|
+
.amp/settings-{edit,read}.json ← Amp permission sets a spawned step runs with
|
|
40
70
|
```
|
|
41
71
|
|
|
42
72
|
## Your diagram → this code
|
|
43
73
|
|
|
44
74
|
| Diagram box | Where it lives |
|
|
45
75
|
|---|---|
|
|
46
|
-
| Agent skill launches the runtime | the per-agent launcher runs `orchestrator.py … --agent-profile <profile>` |
|
|
76
|
+
| Agent skill launches the runtime | the per-agent launcher points at `LAUNCHER.md`, which runs `orchestrator.py … --agent-profile <profile>` |
|
|
47
77
|
| Python Workflow / Interpreter Runtime | `orchestrator.py` — `Orchestrator.run()` |
|
|
48
78
|
| **Builds Complete Context** | `build_context` → `_assemble_system()` + `_assemble_user()` |
|
|
49
|
-
| **Invoke (fresh generation)** | `agent_generate` → `_run_fresh()` → the profile's CLI |
|
|
79
|
+
| **Invoke (fresh generation)** | `agent_generate` → `_run_fresh()` → the profile's CLI (every code step in `workflows/aw-spec-implement.orch.yaml`; `_smoke`'s `gen_file` is the minimal one) |
|
|
50
80
|
| Agent uses tools (Edit, Bash…) | tools/approval flags from the profile |
|
|
51
81
|
| **Return structured result** | trailing ```` ```json {…} ```` block → `_extract_json()` → bound via `outputs:` |
|
|
52
82
|
| Interpreter continues next step | `_run_steps()` / `_run_loop()` |
|
|
53
|
-
| **Review the current output** | `agent_review` → a second fresh, read-only generation |
|
|
54
|
-
| …continues |
|
|
83
|
+
| **Review the current output** | `agent_review` → a second fresh, read-only generation (`_smoke`'s `review_file` reviews what `gen_file` reported) |
|
|
84
|
+
| …continues | a `loop` (`while:` + `break`) around `agent_generate` → `agent_review` — the review→revise cycle |
|
|
55
85
|
|
|
56
86
|
## Why this overrides the launching agent's own context (your R6)
|
|
57
87
|
|
|
@@ -78,31 +108,37 @@ see below.)
|
|
|
78
108
|
## Run it
|
|
79
109
|
|
|
80
110
|
Safe (default) — **no model calls**. Prints the exact payloads the fresh agent
|
|
81
|
-
would receive (proof of isolation), simulates the writes, runs the whole
|
|
111
|
+
would receive (proof of isolation), simulates the writes, runs the whole
|
|
112
|
+
workflow — including the `agent_generate` edit step and the `agent_review` of
|
|
113
|
+
what it wrote. `_smoke` has one `ask`, so it runs with `--non-interactive`:
|
|
82
114
|
|
|
83
115
|
```bash
|
|
84
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
85
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
116
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml --non-interactive # mock
|
|
117
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml --non-interactive --show-full
|
|
86
118
|
```
|
|
87
119
|
|
|
88
120
|
For real — pass an agent profile (implies `--transport real`):
|
|
89
121
|
|
|
90
122
|
```bash
|
|
91
123
|
# Claude Code
|
|
92
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
93
|
-
--agent-profile .claude/agent.json --isolation bare --model opus
|
|
124
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
125
|
+
--non-interactive --agent-profile .claude/agent.json --isolation bare --model opus
|
|
94
126
|
|
|
95
127
|
# Antigravity (Gemini)
|
|
96
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
97
|
-
--agent-profile .agents/agent.json --isolation fresh --model gemini-2.5-pro
|
|
128
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
129
|
+
--non-interactive --agent-profile .agents/agent.json --isolation fresh --model gemini-2.5-pro
|
|
98
130
|
|
|
99
|
-
# Kilo Code (
|
|
100
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
101
|
-
--agent-profile .
|
|
131
|
+
# Kilo Code (kilo run; --model takes Kilo's provider/model form)
|
|
132
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
133
|
+
--non-interactive --agent-profile .kilo/agent.json --model <provider>/<model>
|
|
102
134
|
```
|
|
103
135
|
|
|
104
|
-
Add `--dry-run` to print the exact command a profile would run
|
|
105
|
-
executing
|
|
136
|
+
Add `--dry-run` to print the exact command a profile would run for every model
|
|
137
|
+
step **without executing any of them**: each step then takes its mock result, so
|
|
138
|
+
the run carries on to the next. A dry run never writes an `agent_author` target
|
|
139
|
+
(a later `required_files` gate counts it as present) and never caches a result
|
|
140
|
+
in the checkpoint. Output lands in `.appweaver/orchestrator/.smoke-out/`
|
|
141
|
+
(gitignored, safe to delete).
|
|
106
142
|
|
|
107
143
|
## Execution strategies — `--strategy`, per-step `strategy:`
|
|
108
144
|
|
|
@@ -153,8 +189,8 @@ If spawning a second agent instance is impossible or unwanted, `--checkpoint`
|
|
|
153
189
|
ports run-skill.py's **suspend/resume** method into this engine:
|
|
154
190
|
|
|
155
191
|
```bash
|
|
156
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
157
|
-
--checkpoint .appweaver/orchestrator/.
|
|
192
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
193
|
+
--checkpoint .appweaver/orchestrator/.state/smoke.state.json --json
|
|
158
194
|
```
|
|
159
195
|
|
|
160
196
|
At each `agent_generate` / `agent_review` the interpreter writes the fully
|
|
@@ -166,10 +202,9 @@ the Bash call. The agent fulfills the request **in its own conversation**
|
|
|
166
202
|
required ```` ```json ```` fence — to `<state>.response.md`, and re-runs the
|
|
167
203
|
same command. Completed steps replay from the cache, so the run continues
|
|
168
204
|
exactly where it suspended; on a terminal end the state file and sidecars are
|
|
169
|
-
deleted. Launcher:
|
|
170
|
-
`
|
|
171
|
-
|
|
172
|
-
Kilo Code, natively, with no `claude` CLI.
|
|
205
|
+
deleted. Launcher: `LAUNCHER.md` step 3 (the suspend/resume loop), which every
|
|
206
|
+
agent's `/appweaver` follows. The same loop works for any agent that can run
|
|
207
|
+
bash and read/write files — it needs no profile and no extra CLI.
|
|
173
208
|
|
|
174
209
|
**The trade-off, stated plainly:** the interpreter keeps 100% ownership of
|
|
175
210
|
what goes *into* each payload, but the request executes inside the invoking
|
|
@@ -195,16 +230,39 @@ documented in `.appweaver/ORCH-DIALECT.md`.
|
|
|
195
230
|
| Extra auth / CLI needed | yes (`claude`/`gemini` + key for `--bare`) | none |
|
|
196
231
|
| Permission prompts / HITL | none (headless) | the agent's native ones |
|
|
197
232
|
|
|
198
|
-
## The
|
|
233
|
+
## The agents
|
|
199
234
|
|
|
200
|
-
| Agent |
|
|
201
|
-
|
|
202
|
-
| Claude Code | `.claude/` | `claude -p`
|
|
203
|
-
| Antigravity | `.agents/` | `
|
|
204
|
-
| Kilo Code | `.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
235
|
+
| Agent | Profile | Fresh-generation CLI | Edit steps | Read-only steps |
|
|
236
|
+
|---|---|---|---|---|
|
|
237
|
+
| Claude Code | `.claude/` | `claude -p` (prompt on stdin) | `--tools <list> --permission-mode acceptEdits` | `--tools "" --permission-mode default` |
|
|
238
|
+
| Antigravity | `.agents/` | `agy -p` | `--mode accept-edits` | `--mode plan` |
|
|
239
|
+
| Kilo Code | `.kilo/` | `kilo run` (prompt on stdin) | `--agent appweaver-edit` | `--agent appweaver-read` |
|
|
240
|
+
| Cursor | `.cursor/` | `cursor-agent -p` | `--force` | `--mode ask` |
|
|
241
|
+
| GitHub Copilot | `.copilot/` | `copilot -p` | `--allow-all-tools` | no flag |
|
|
242
|
+
| Devin (formerly Windsurf) | `.devin/` | `devin -p` | `--permission-mode dangerous` | no flag (Devin's default `normal` mode) |
|
|
243
|
+
| Cline | `.cline/` | `cline` | act mode, `--auto-approve true` | `--plan` |
|
|
244
|
+
| Roo Code | `.roo/` | `roo --print` | `--mode code` | `--mode ask` |
|
|
245
|
+
| opencode | `.opencode/` | `opencode run --auto` | `--agent appweaver-edit` | `--agent appweaver-read` |
|
|
246
|
+
| Factory Droid | `.factory/` | `droid exec -o json` (prompt on stdin) | `--auto high` | no flag (read-only by default) |
|
|
247
|
+
| Augment | `.augment/` | `auggie --quiet --print` | no flag | `--ask` |
|
|
248
|
+
| Continue | `.continue/` | `cn --silent -p` | `--auto` | `--readonly` |
|
|
249
|
+
| Kiro | `.kiro/` | `kiro-cli chat --no-interactive` (prompt on stdin) | `--trust-all-tools` | `--trust-tools=read,grep` |
|
|
250
|
+
| OpenAI Codex | `.codex/` | `codex exec` (prompt on stdin) | `--sandbox workspace-write` | `--sandbox read-only` |
|
|
251
|
+
| Gemini CLI | `.gemini/` | `gemini -o json -p` | `--approval-mode auto_edit` | `--approval-mode plan` |
|
|
252
|
+
| Amp | `.amp/` | `amp -x` (prompt on stdin) | `--settings-file .amp/settings-edit.json` | `--settings-file .amp/settings-read.json` |
|
|
253
|
+
|
|
254
|
+
Only Claude Code takes the system block as a flag (`--system-prompt`), limits
|
|
255
|
+
tools per step (`--tools`) and isolates a generation (`--bare`, which needs
|
|
256
|
+
`ANTHROPIC_API_KEY`, or `--setting-sources ""`). Every other profile folds the
|
|
257
|
+
system block into the prompt, and its isolation is best-effort: the agent's own
|
|
258
|
+
rules files still load. Only Claude Code, Antigravity and Kilo Code have an
|
|
259
|
+
`sdk` block. Each profile's `note` gives that agent's limits.
|
|
260
|
+
|
|
261
|
+
Adding an agent = drop an `agent.json` + a thin launcher in its folder that
|
|
262
|
+
points at `LAUNCHER.md`, add the agent's row to `LAUNCHER.md`'s profile
|
|
263
|
+
table, and add its folder to the inventory's `KIT_AGENT_DIRS`
|
|
264
|
+
(`.appweaver/scripts/python/aw-inventory.py`); no engine change. See
|
|
265
|
+
`AGENT-PROFILE.md` for the schema and the full steps.
|
|
208
266
|
|
|
209
267
|
## Invoking from an agent (the top of your diagram)
|
|
210
268
|
|
|
@@ -213,7 +271,7 @@ agent's *only* job is to run the orchestrator and relay the JSON. It **never
|
|
|
213
271
|
generates**; its conversation **never** enters a model request.
|
|
214
272
|
|
|
215
273
|
```
|
|
216
|
-
User → /appweaver
|
|
274
|
+
User → /appweaver <skill> → (agent runs) orchestrator.py --agent-profile <its profile>
|
|
217
275
|
→ interpreter builds context → spawns a fresh CLI per step (isolated)
|
|
218
276
|
→ interpreter reviews + continues → agent reports final JSON
|
|
219
277
|
```
|
|
@@ -240,8 +298,13 @@ the context leak this design removes, and one reason that tier was retired.
|
|
|
240
298
|
- `loop` (`while:` + `max_iterations:`) with `break` (+ `condition:`) — the
|
|
241
299
|
review→revise cycle.
|
|
242
300
|
|
|
301
|
+
`_smoke.orch.yaml` runs one `agent_generate` (`gen_file`) and one
|
|
302
|
+
`agent_review` (`review_file`) of what it wrote, gated on `files[]` being
|
|
303
|
+
non-empty and on `pass`; with no model, the mock writes `SmokeGenerated.cs`
|
|
304
|
+
under `.smoke-out/` and the review passes when the reported files exist.
|
|
305
|
+
|
|
243
306
|
The engine now implements the FULL dialect the `aw-spec-*` conversions need on
|
|
244
|
-
top of these
|
|
307
|
+
top of these actions: `execute_script`, `verify_context`,
|
|
245
308
|
`load_standards` (sticky system prefix), `agent_author` (interpreter-owned
|
|
246
309
|
`output_target`, read-only generation), `agent_query` (generic structured
|
|
247
310
|
JSON), `ask`/`user_select` (HITL via checkpoint), `dispatch_hooks`, `include`
|
|
@@ -282,19 +345,23 @@ at the top of this file).
|
|
|
282
345
|
HITL — IS now ported; see `.appweaver/ORCH-DIALECT.md`.)
|
|
283
346
|
|
|
284
347
|
|
|
285
|
-
|
|
286
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml \
|
|
287
|
-
--strategy spawn --agent-profile .claude/agent.json --isolation bare --json
|
|
348
|
+
## Each strategy on `_smoke`
|
|
288
349
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
350
|
+
```bash
|
|
351
|
+
# spawn (Strategy 3)
|
|
352
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
353
|
+
--non-interactive --strategy spawn --agent-profile .claude/agent.json --isolation bare --json
|
|
354
|
+
|
|
355
|
+
# sdk (Strategy 1)
|
|
356
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
357
|
+
--non-interactive --strategy sdk --agent-profile .claude/agent.json --model opus --json
|
|
292
358
|
|
|
293
|
-
# sdk-apply (Strategy 2) —
|
|
294
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
359
|
+
# sdk-apply (Strategy 2) — then follow the suspend/resume loop
|
|
360
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
295
361
|
--strategy sdk-apply --agent-profile .claude/agent.json \
|
|
296
|
-
--checkpoint .appweaver/orchestrator/.
|
|
362
|
+
--checkpoint .appweaver/orchestrator/.state/smoke.state.json --json
|
|
297
363
|
|
|
298
|
-
# agent (Strategy 4) —
|
|
299
|
-
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/
|
|
300
|
-
--strategy agent --checkpoint .appweaver/orchestrator/.
|
|
364
|
+
# agent (Strategy 4) — then follow the suspend/resume loop
|
|
365
|
+
python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml \
|
|
366
|
+
--strategy agent --checkpoint .appweaver/orchestrator/.state/smoke.state.json --json
|
|
367
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""claude-agent-sdk adapter — a shared SDK adapter, loaded by the
|
|
2
2
|
aw-orchestrator engine when an agent profile's `sdk.adapter` points here
|
|
3
|
-
(both .claude/agent.json and .
|
|
3
|
+
(both .claude/agent.json and .kilo/agent.json do). Adapters live in this
|
|
4
4
|
library keyed by SDK, not by agent: everything claude-agent-sdk-specific is
|
|
5
5
|
HERE, the engine ships no SDK code of its own, and each profile declares
|
|
6
6
|
which adapter drives its SDK.
|
|
@@ -45,13 +45,15 @@ workflow:
|
|
|
45
45
|
- { name: dg_rulemap_exists, from: "$.rulemap_exists" }
|
|
46
46
|
- { name: dg_candidates, from: "$.candidates" }
|
|
47
47
|
|
|
48
|
-
# 2. Domain gate — only when the domain
|
|
48
|
+
# 2. Domain gate — only when the project or its domain-rule-bindings.md is missing.
|
|
49
49
|
- id: gate
|
|
50
50
|
action: ask
|
|
51
51
|
condition: "{{dg_rulemap_exists}} == false"
|
|
52
52
|
prompt: >
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
No domain rule map found for project '{{domain}}': .appweaver/domain.json must name a
|
|
54
|
+
folder under guardrails/ that holds domain-rule-bindings.md (project-specific by default;
|
|
55
|
+
/appweaver select-domain lists the folders that qualify). Continue with technical
|
|
56
|
+
standards only, or exit to fix it?
|
|
55
57
|
options: ["continue", "exit"]
|
|
56
58
|
answer_var: dg_gate
|
|
57
59
|
- id: gate_stop
|
|
@@ -60,7 +62,7 @@ workflow:
|
|
|
60
62
|
require_value: dg_gate
|
|
61
63
|
equals: "continue"
|
|
62
64
|
on_mismatch: stop
|
|
63
|
-
on_mismatch_message: "Exited — run /appweaver select-domain
|
|
65
|
+
on_mismatch_message: "Exited — run /appweaver select-domain, or set \"domain\" in .appweaver/domain.json to a folder under guardrails/ that holds domain-rule-bindings.md (project-specific by default), then re-run."
|
|
64
66
|
|
|
65
67
|
# 3. Selection box — only when a rule map with candidates exists.
|
|
66
68
|
- id: select_mode
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# foundation-lane (orchestrator) — scaffold ONE declared lane
|
|
3
|
+
#
|
|
4
|
+
# Included by aw-spec-foundation once per lane kind — backend first, then frontend — with
|
|
5
|
+
# that lane's fields passed through `with:`. It answers "what is this lane built from?"
|
|
6
|
+
# and hands off:
|
|
7
|
+
#
|
|
8
|
+
# 1. Can the lane take a foundation — does it run its commands inside its lane root folder
|
|
9
|
+
# and keep its tests there? If not, it is reported and passed over. Then: does it
|
|
10
|
+
# already hold files? If so, ask to overwrite them; "no" skips the lane and nothing
|
|
11
|
+
# else is asked. Each lane is asked on its own.
|
|
12
|
+
# 2. List what fits the lane: every pack and spec under foundations/<ecosystem>/ whose
|
|
13
|
+
# `# kind:` / `# profiles:` header admits this lane, then [manual spec] and [skip].
|
|
14
|
+
# 3. Pick one. A fast-path name (`/appweaver foundation VerticalSlice App`) preselects
|
|
15
|
+
# its entry in whichever lane lists it.
|
|
16
|
+
# 4. pack -> foundation-pack (unpack the verified bundle, as before)
|
|
17
|
+
# spec | manual spec -> foundation-spec (an agent builds the project from the spec)
|
|
18
|
+
# skip -> nothing is written.
|
|
19
|
+
#
|
|
20
|
+
# Every refusal in here and in the two route modules RETURNS rather than stops, so the
|
|
21
|
+
# caller always reaches the next lane; the reason is in fl_status, which the caller
|
|
22
|
+
# reports per lane at the end of the run.
|
|
23
|
+
#
|
|
24
|
+
# Inputs (via include `with:`):
|
|
25
|
+
# fl_kind, fl_lane_id, fl_profile, fl_title, fl_language, fl_ecosystem,
|
|
26
|
+
# fl_source_path, fl_test_path, fl_workdir, fl_build
|
|
27
|
+
# Shared with the caller: USER_INPUT (the fast path) and `app` (asked once per run, the
|
|
28
|
+
# first time a lane needs it, and reused by the next lane).
|
|
29
|
+
# Produces: fl_status, fl_route, fl_name, fl_spec_path, fl_files, and fl_overwrite ("yes"
|
|
30
|
+
# when the lane already had files and the operator agreed to overwrite them), which the
|
|
31
|
+
# two route modules read.
|
|
32
|
+
# =============================================================================
|
|
33
|
+
|
|
34
|
+
name: foundation-lane
|
|
35
|
+
dialect: aw-spec.orchestrator/v1
|
|
36
|
+
|
|
37
|
+
scripts:
|
|
38
|
+
actions:
|
|
39
|
+
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
40
|
+
ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
|
|
41
|
+
|
|
42
|
+
workflow:
|
|
43
|
+
|
|
44
|
+
# 0. Vars are shared across the two includes; start this lane clean.
|
|
45
|
+
- id: fl_reset
|
|
46
|
+
action: set
|
|
47
|
+
vars:
|
|
48
|
+
fl_status: "not scaffolded"
|
|
49
|
+
fl_route: ""
|
|
50
|
+
fl_name: ""
|
|
51
|
+
fl_spec_file: ""
|
|
52
|
+
fl_spec_path: ""
|
|
53
|
+
fl_files: ""
|
|
54
|
+
fl_has_files: ""
|
|
55
|
+
fl_files_summary: ""
|
|
56
|
+
fl_self_contained: ""
|
|
57
|
+
fl_shape_reason: ""
|
|
58
|
+
fl_overwrite_answer: ""
|
|
59
|
+
fl_overwrite: ""
|
|
60
|
+
fl_overwrite_note: ""
|
|
61
|
+
fl_go: "true"
|
|
62
|
+
fl_spec_route: ""
|
|
63
|
+
|
|
64
|
+
- id: fl_has_root
|
|
65
|
+
action: verify_context
|
|
66
|
+
require_non_empty: fl_source_path
|
|
67
|
+
on_empty: return
|
|
68
|
+
message_var: fl_status
|
|
69
|
+
on_empty_message: "not scaffolded — lane `{{fl_lane_id}}` declares no lane root folder in .appweaver/stacks.json; re-run /appweaver select-stack and give it its lane root folder"
|
|
70
|
+
|
|
71
|
+
# 1. Does the lane already hold files? Any file in its lane root folder or test path counts,
|
|
72
|
+
# whatever stack wrote it, and so do its build files where its commands run when that
|
|
73
|
+
# is outside the lane (a .NET solution at the repo root). Asked BEFORE the pick list,
|
|
74
|
+
# so "no" skips this lane with nothing else asked and the run moves on to the next one.
|
|
75
|
+
# The first option is the non-interactive default, so an unattended run never
|
|
76
|
+
# overwrites. The answer key carries the lane kind, so a scripted run answers each lane
|
|
77
|
+
# on its own: --answer fl_overwrite_backend=yes --answer fl_overwrite_frontend=no.
|
|
78
|
+
- id: fl_files_check
|
|
79
|
+
action: execute_script
|
|
80
|
+
script: { ref: actions }
|
|
81
|
+
subcommand: foundation-lane-files
|
|
82
|
+
args: ["--source", "{{fl_source_path}}", "--test", "{{fl_test_path}}", "--workdir", "{{fl_workdir}}", "--profile", "{{fl_profile}}"]
|
|
83
|
+
outputs:
|
|
84
|
+
- { name: fl_has_files, from: "$.has_files" }
|
|
85
|
+
- { name: fl_files_summary, from: "$.summary" }
|
|
86
|
+
- { name: fl_self_contained, from: "$.self_contained" }
|
|
87
|
+
- { name: fl_shape_reason, from: "$.shape_reason" }
|
|
88
|
+
|
|
89
|
+
# A foundation is a complete project that lands INSIDE the lane root folder — build files,
|
|
90
|
+
# source and tests — so the lane has to run its commands there and keep its tests there.
|
|
91
|
+
# A lane declared the classic way (code in src/, solution and tests/ at the repo root)
|
|
92
|
+
# suits existing code but would get a project its own build cannot find; it is reported
|
|
93
|
+
# here, before anything is asked, and the run moves on to the next lane.
|
|
94
|
+
- id: fl_shape_gate
|
|
95
|
+
action: verify_context
|
|
96
|
+
require_true: fl_self_contained
|
|
97
|
+
on_false: return
|
|
98
|
+
message_var: fl_status
|
|
99
|
+
on_false_message: "not scaffolded — {{fl_shape_reason}}"
|
|
100
|
+
|
|
101
|
+
- id: fl_ask_overwrite
|
|
102
|
+
action: ask
|
|
103
|
+
condition: "{{fl_has_files}} == true"
|
|
104
|
+
prompt: >
|
|
105
|
+
{{fl_kind}} lane `{{fl_lane_id}}` ({{fl_profile}}) already has files — {{fl_files_summary}}.
|
|
106
|
+
Scaffolding it writes into these folders and replaces files with the same path; files
|
|
107
|
+
with other names stay, and nothing is deleted. Overwrite?
|
|
108
|
+
options: ["no — skip this lane", "yes — overwrite"]
|
|
109
|
+
answer_key: "fl_overwrite_{{fl_kind}}"
|
|
110
|
+
answer_var: fl_overwrite_answer
|
|
111
|
+
|
|
112
|
+
# The answer is free text from the launcher: the full option and a bare `yes` both count.
|
|
113
|
+
- id: fl_overwrite_option
|
|
114
|
+
action: set
|
|
115
|
+
condition: "{{fl_overwrite_answer}} == yes — overwrite"
|
|
116
|
+
vars: { fl_overwrite: "yes" }
|
|
117
|
+
|
|
118
|
+
- id: fl_overwrite_short
|
|
119
|
+
action: set
|
|
120
|
+
condition: "{{fl_overwrite_answer}} == yes"
|
|
121
|
+
vars: { fl_overwrite: "yes" }
|
|
122
|
+
|
|
123
|
+
- id: fl_overwrite_gate
|
|
124
|
+
action: verify_context
|
|
125
|
+
condition: "{{fl_has_files}} == true"
|
|
126
|
+
require_value: fl_overwrite
|
|
127
|
+
equals: "yes"
|
|
128
|
+
on_mismatch: return
|
|
129
|
+
message_var: fl_status
|
|
130
|
+
on_mismatch_message: "skipped — the lane already has files ({{fl_files_summary}}) and overwriting them was declined"
|
|
131
|
+
|
|
132
|
+
- id: fl_overwrite_noted
|
|
133
|
+
action: set
|
|
134
|
+
condition: "{{fl_overwrite}} == yes"
|
|
135
|
+
vars: { fl_overwrite_note: " It already has files, and you chose to overwrite them." }
|
|
136
|
+
|
|
137
|
+
# 2. What fits this lane.
|
|
138
|
+
- id: fl_list
|
|
139
|
+
action: execute_script
|
|
140
|
+
script: { ref: actions }
|
|
141
|
+
subcommand: foundation-list
|
|
142
|
+
args: ["--kind", "{{fl_kind}}", "--profile", "{{fl_profile}}", "--ecosystem", "{{fl_ecosystem}}", "--lane-id", "{{fl_lane_id}}", "--args", "{{USER_INPUT}}"]
|
|
143
|
+
outputs:
|
|
144
|
+
- { name: fl_options, from: "$.options" }
|
|
145
|
+
- { name: fl_count, from: "$.count" }
|
|
146
|
+
- { name: fl_all, from: "$.all_foundations" }
|
|
147
|
+
- { name: fl_preselect, from: "$.preselect_option" }
|
|
148
|
+
|
|
149
|
+
# 3. Pick. There are always at least two options ([manual spec] and [skip]), so this
|
|
150
|
+
# always asks unless the fast path named an entry this lane offers.
|
|
151
|
+
- id: fl_pick
|
|
152
|
+
action: user_select
|
|
153
|
+
prompt: >
|
|
154
|
+
{{fl_kind}} lane `{{fl_lane_id}}` — {{fl_title}} at {{fl_source_path}}.{{fl_overwrite_note}}
|
|
155
|
+
What should it be scaffolded from? A [pack] is a verified project unpacked as-is; a
|
|
156
|
+
[spec] describes a project the agent builds into the lane; [manual spec] lets you give
|
|
157
|
+
that description yourself; [skip] leaves the lane untouched.
|
|
158
|
+
({{fl_count}} of the foundations shipped fit this lane; all of them: {{fl_all}})
|
|
159
|
+
options_from_variable: fl_options
|
|
160
|
+
preselect_from: fl_preselect
|
|
161
|
+
outputs:
|
|
162
|
+
- { name: fl_selection, from: selection }
|
|
163
|
+
|
|
164
|
+
- id: fl_choice
|
|
165
|
+
action: execute_script
|
|
166
|
+
script: { ref: actions }
|
|
167
|
+
subcommand: foundation-choice
|
|
168
|
+
args: ["--selection", "{{fl_selection}}", "--kind", "{{fl_kind}}", "--profile", "{{fl_profile}}", "--ecosystem", "{{fl_ecosystem}}"]
|
|
169
|
+
outputs:
|
|
170
|
+
- { name: fl_choice_ok, from: "$.ok" }
|
|
171
|
+
- { name: fl_route, from: "$.route" }
|
|
172
|
+
- { name: fl_name, from: "$.name" }
|
|
173
|
+
- { name: fl_spec_file, from: "$.file" }
|
|
174
|
+
- { name: fl_choice_msg, from: "$.reason" }
|
|
175
|
+
|
|
176
|
+
- id: fl_choice_gate
|
|
177
|
+
action: verify_context
|
|
178
|
+
require_true: fl_choice_ok
|
|
179
|
+
on_false: return
|
|
180
|
+
message_var: fl_status
|
|
181
|
+
on_false_message: "not scaffolded — {{fl_choice_msg}}"
|
|
182
|
+
|
|
183
|
+
- id: fl_skip
|
|
184
|
+
action: set
|
|
185
|
+
condition: "{{fl_route}} == skip"
|
|
186
|
+
vars: { fl_go: "" }
|
|
187
|
+
|
|
188
|
+
- id: fl_skip_gate
|
|
189
|
+
action: verify_context
|
|
190
|
+
require_true: fl_go
|
|
191
|
+
on_false: return
|
|
192
|
+
message_var: fl_status
|
|
193
|
+
on_false_message: "skipped — left as it is, by choice"
|
|
194
|
+
|
|
195
|
+
# 4. The project name — asked once per run, the first time a lane needs it, unless the
|
|
196
|
+
# fast path gave it. The next lane reuses it.
|
|
197
|
+
- id: fl_ask_app
|
|
198
|
+
action: ask
|
|
199
|
+
condition: "{{app}} == "
|
|
200
|
+
prompt: >
|
|
201
|
+
Enter the project (application) name, e.g. AppWeaver.Health. A pack renames its
|
|
202
|
+
sentinel to it; a spec build names the project after it, in the form the stack uses.
|
|
203
|
+
It is asked once and used for every lane in this run.
|
|
204
|
+
answer_var: app_typed
|
|
205
|
+
|
|
206
|
+
- id: fl_app_from_typed
|
|
207
|
+
action: set
|
|
208
|
+
condition: "{{app}} == "
|
|
209
|
+
vars: { app: "{{app_typed}}" }
|
|
210
|
+
|
|
211
|
+
- id: fl_app_gate
|
|
212
|
+
action: verify_context
|
|
213
|
+
require_non_empty: app
|
|
214
|
+
on_empty: return
|
|
215
|
+
message_var: fl_status
|
|
216
|
+
on_empty_message: "not scaffolded — no project name was given"
|
|
217
|
+
|
|
218
|
+
# 5. Hand off. The engine has no OR, so the two spec routes set one flag.
|
|
219
|
+
- id: fl_route_spec
|
|
220
|
+
action: set
|
|
221
|
+
condition: "{{fl_route}} == spec"
|
|
222
|
+
vars: { fl_spec_route: "true" }
|
|
223
|
+
|
|
224
|
+
- id: fl_route_manual
|
|
225
|
+
action: set
|
|
226
|
+
condition: "{{fl_route}} == manual"
|
|
227
|
+
vars: { fl_spec_route: "true" }
|
|
228
|
+
|
|
229
|
+
- id: pack
|
|
230
|
+
action: include
|
|
231
|
+
condition: "{{fl_route}} == pack"
|
|
232
|
+
module: .appweaver/orchestrator/modules/foundation-pack.orch.yaml
|
|
233
|
+
|
|
234
|
+
- id: spec
|
|
235
|
+
action: include
|
|
236
|
+
condition: "{{fl_spec_route}} == true"
|
|
237
|
+
module: .appweaver/orchestrator/modules/foundation-spec.orch.yaml
|