@chinhae/atw-cli 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +243 -123
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +18 -3
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts +0 -3
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +45 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/index.d.ts +8 -0
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +19 -0
- package/dist/configurators/index.js.map +1 -1
- package/dist/migrations/manifests/0.2.10.json +9 -0
- package/dist/migrations/manifests/0.3.0.json +3410 -0
- package/dist/templates/atw/config.yaml +4 -3
- package/dist/templates/atw/index.d.ts +2 -0
- package/dist/templates/atw/index.d.ts.map +1 -1
- package/dist/templates/atw/index.js +4 -0
- package/dist/templates/atw/index.js.map +1 -1
- package/dist/templates/atw/scripts/common/noob_mode.py +102 -0
- package/dist/templates/atw/scripts/common/session_context.py +7 -0
- package/dist/templates/atw/scripts/noob_mode.py +41 -0
- package/dist/templates/atw/scripts/tickets.py +66 -10
- package/dist/templates/atw/workflow.md +81 -17
- package/dist/templates/common/bundled-skills/atw-code-review/SKILL.md +4 -2
- package/dist/templates/common/bundled-skills/atw-codebase-design/DESIGN-IT-TWICE.md +1 -1
- package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/SKILL.md +2 -2
- package/dist/templates/common/bundled-skills/atw-domain-modeling/{CONTEXT-FORMAT.md → GLOSSARY-FORMAT.md} +10 -10
- package/dist/templates/common/bundled-skills/atw-domain-modeling/SKILL.md +12 -12
- package/dist/templates/common/bundled-skills/atw-handoff/SKILL.md +1 -1
- package/dist/templates/common/bundled-skills/atw-implement/SKILL.md +6 -4
- package/dist/templates/common/bundled-skills/atw-implement-spec/SKILL.md +79 -0
- package/dist/templates/common/bundled-skills/atw-implement-spec/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/SKILL.md +5 -5
- package/dist/templates/common/bundled-skills/atw-init-repo/SKILL.md +6 -4
- package/dist/templates/common/bundled-skills/atw-init-repo/references/domain.md +8 -8
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw-local.md +5 -2
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw.md +5 -2
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-github.md +5 -4
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-gitlab.md +2 -2
- package/dist/templates/common/bundled-skills/atw-init-repo/references/triage-labels.md +1 -1
- package/dist/templates/common/bundled-skills/atw-interview/SKILL.md +9 -1
- package/dist/templates/common/bundled-skills/atw-map/SKILL.md +5 -5
- package/dist/templates/common/bundled-skills/atw-noob-mode/SKILL.md +101 -0
- package/dist/templates/common/bundled-skills/atw-noob-mode/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-prototype/scripts/build_explorer.py +15 -9
- package/dist/templates/common/bundled-skills/atw-spec/SKILL.md +1 -1
- package/dist/templates/common/bundled-skills/atw-tdd/SKILL.md +2 -2
- package/dist/templates/common/bundled-skills/atw-tickets/SKILL.md +4 -4
- package/dist/templates/common/bundled-skills/atw-triage/SKILL.md +2 -2
- package/dist/templates/common/commands/continue.md +1 -1
- package/dist/templates/opencode/plugins/inject-workflow-state.js +29 -1
- package/dist/templates/shared-hooks/inject-subagent-context.py +29 -3
- package/dist/templates/shared-hooks/inject-workflow-state.py +27 -3
- package/dist/templates/shared-hooks/session-start.py +23 -0
- package/dist/templates/snow/SNOW.md +1 -1
- package/dist/utils/file-writer.d.ts.map +1 -1
- package/dist/utils/file-writer.js +29 -16
- package/dist/utils/file-writer.js.map +1 -1
- package/dist/utils/interactive-guard.d.ts +2 -2
- package/dist/utils/interactive-guard.js +2 -2
- package/dist/utils/lang.d.ts +14 -0
- package/dist/utils/lang.d.ts.map +1 -0
- package/dist/utils/lang.js +20 -0
- package/dist/utils/lang.js.map +1 -0
- package/dist/utils/optional-skills.d.ts +90 -0
- package/dist/utils/optional-skills.d.ts.map +1 -0
- package/dist/utils/optional-skills.js +266 -0
- package/dist/utils/optional-skills.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +6 -0
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +1 -1
- package/dist/utils/template-fetcher.js.map +1 -1
- package/package.json +2 -2
- package/dist/templates/common/bundled-skills/atw-merge/SKILL.md +0 -14
- package/dist/templates/common/bundled-skills/atw-merge/agents/openai.yaml +0 -3
- package/dist/templates/common/bundled-skills/dejargonizer/SKILL.md +0 -133
- package/dist/templates/common/bundled-skills/noob-mode/SKILL.md +0 -175
- package/dist/templates/common/bundled-skills/noob-mode/references/examples.md +0 -418
- package/dist/templates/common/bundled-skills/noob-mode/references/glossary.md +0 -368
- package/dist/templates/common/bundled-skills/oxy-explanation/SKILL.md +0 -80
- package/dist/templates/common/bundled-skills/oxy-learning-hub/SKILL.md +0 -179
- package/dist/templates/common/bundled-skills/oxy-learning-hub/assets/course.css +0 -1044
- package/dist/templates/common/bundled-skills/oxy-learning-hub/assets/course.js +0 -184
- package/dist/templates/common/bundled-skills/oxy-learning-hub/assets/lesson-template.html +0 -125
- package/dist/templates/common/bundled-skills/oxy-learning-hub/assets/summary-template.html +0 -659
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/publishing.md +0 -64
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/summary-mode.md +0 -96
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/teaching/GLOSSARY-FORMAT.md +0 -30
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/teaching/LEARNING-RECORD-FORMAT.md +0 -42
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/teaching/MISSION-FORMAT.md +0 -50
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/teaching/RESOURCES-FORMAT.md +0 -40
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/teaching-mode.md +0 -251
- package/dist/templates/common/bundled-skills/oxy-learning-hub/references/workspace.md +0 -112
- package/dist/templates/common/bundled-skills/oxy-learning-hub/scripts/validate_html.py +0 -198
- package/dist/templates/common/bundled-skills/show-me/SKILL.md +0 -127
|
@@ -22,7 +22,7 @@ The map is a single issue on this repo's issue tracker, labelled `atw-map:map`
|
|
|
22
22
|
|
|
23
23
|
The map is an **index**, not a store. It lists the decisions made and points at the tickets that hold their detail; a decision lives in exactly one place — its ticket — so the map never restates it, only gists it and links.
|
|
24
24
|
|
|
25
|
-
**Where the map, its child tickets, blocking, and frontier queries physically live is tracker-specific.** The issue tracker should have been provided to you. If not, tell the user to
|
|
25
|
+
**Where the map, its child tickets, blocking, and frontier queries physically live is tracker-specific.** The issue tracker should have been provided to you. If not, tell the user to run `/atw-init-repo`, which asks which tracker this repo uses and writes that file. Consult the tracker doc's "Wayfinding operations" section for how _this_ repo expresses them. If no tracker has been provided, default to the local-markdown tracker.
|
|
26
26
|
|
|
27
27
|
### The map body
|
|
28
28
|
|
|
@@ -62,7 +62,7 @@ Each ticket is a **child issue** of the map; the tracker's issue id is its ident
|
|
|
62
62
|
<the decision or investigation this ticket resolves>
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
Each ticket carries a `atw-map:<type>` label — one of `research`, `prototype`, `interview`, `task` (see [Ticket Types](#ticket-types)).
|
|
65
|
+
Each ticket carries a `atw-map:<type>` label — one of `research`, `prototype`, `interview`, `task` (see [Ticket Types](#ticket-types)). `atw-map:` labels are the only labels a map and its tickets carry, never a triage label like `ready-for-agent`: they are decisions, not implementation work. A tracker without labels records the type where its doc says — a `Type:` line in the ticket file.
|
|
66
66
|
|
|
67
67
|
A session **claims** a ticket by assigning it to the dev driving the map, **first**, before any work, so concurrent sessions skip it. That assignee _is_ the claim: an open, unassigned ticket is unclaimed.
|
|
68
68
|
|
|
@@ -111,8 +111,8 @@ User invokes with a loose idea.
|
|
|
111
111
|
1. **Name the destination.** Call the Skill tool twice, for "atw-interview" and "atw-domain-modeling", to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first.
|
|
112
112
|
2. **Map the frontier.** Interview again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — you don't need a map. Stop and ask the user how they'd like to proceed.
|
|
113
113
|
3. **Create the map** (label `atw-map:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**.
|
|
114
|
-
4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section.
|
|
115
|
-
5. **Fire the research subagents.** For each `research` ticket you just created, spin up a subagent that calls the Skill tool with "atw-research" to resolve it in parallel,
|
|
114
|
+
4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Write cross-references in that pass too, with real ids: a placeholder `#<n>` auto-links to an unrelated issue. Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section.
|
|
115
|
+
5. **Fire the research subagents.** For each `research` ticket you just created, spin up a subagent that calls the Skill tool with "atw-research" to resolve it in parallel, with a context pointer from the ticket to its findings. Where the tracker doc names a place for research notes, the findings go there. Otherwise capture them on a throwaway `research/<name>` branch: push it when the repo has a remote, but open no PR — it is never merged.
|
|
116
116
|
6. Stop — charting is one session's work; it hand-resolves nothing.
|
|
117
117
|
|
|
118
118
|
### Work through the map
|
|
@@ -121,7 +121,7 @@ User invokes with a map (URL or number). A ticket is **optional** — without on
|
|
|
121
121
|
|
|
122
122
|
1. Load the **map** — the low-res view, not every ticket body.
|
|
123
123
|
2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work.
|
|
124
|
-
3. Resolve it — **
|
|
124
|
+
3. Resolve it as the type the ticket records — its `atw-map:<type>` label, or its `Type:` line on a tracker without labels (see [Ticket Types](#ticket-types)). Read that, not just the question: the question never states the type. **Zoom as needed**: fetch the full body of any related or closed ticket on demand; call the Skill tool for whichever skills the `## Notes` block names. If in doubt, call the Skill tool twice, for "atw-interview" and "atw-domain-modeling".
|
|
125
125
|
4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far.
|
|
126
126
|
5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **rule it out of scope** rather than resolving it on the route. If the decision invalidates other parts of the map, update or delete those tickets.
|
|
127
127
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atw-noob-mode
|
|
3
|
+
description: "小白模式:给不懂技术的用户全程用大白话沟通——术语当场解释,动手前说明要做什么、为什么、风险多大,报错和结果讲清楚影响与下一步。开启后在整个工作流里持续生效,直到用户关闭。当用户说“开启小白模式”“关闭小白模式”“说人话”,输入 /atw-noob-mode,或表示看不懂术语、授权请求、报错、命令输出时使用。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Noob Mode
|
|
7
|
+
|
|
8
|
+
The user is not an engineer. They are still the one in charge: they decide what gets built, what is good enough, and what must not happen. They can only do that when they understand what you tell them and what you are about to do. An update they cannot read leaves them able to approve your work but not to review it — and then your choices ship unexamined.
|
|
9
|
+
|
|
10
|
+
Noob mode keeps every reply, in every ATW stage, in language they can act on. It starts when it is switched on and lasts until the user switches it off.
|
|
11
|
+
|
|
12
|
+
## Switching
|
|
13
|
+
|
|
14
|
+
The user's words or the argument decide the action. With neither, turn it on.
|
|
15
|
+
|
|
16
|
+
- **On** — `/atw-noob-mode`, "开启小白模式", "turn on noob mode", or the user says they cannot follow the terms, an approval prompt, an error or command output. Run `python3 ./.atw/scripts/noob_mode.py on`, then confirm in the user's language, for example: "小白模式已开启。接下来我会用大白话说明我在做什么、需要你决定什么、有什么风险。随时可以说“关闭小白模式”。" Apply everything below from that reply on, then do the catch-up in "Catching up".
|
|
17
|
+
- **Off** — `/atw-noob-mode off`, "关闭小白模式", "turn off noob mode". Run `python3 ./.atw/scripts/noob_mode.py off`, confirm in one sentence, and stop applying these rules.
|
|
18
|
+
- **Status** — `python3 ./.atw/scripts/noob_mode.py status`.
|
|
19
|
+
|
|
20
|
+
The switch is personal: it is a line in this user's own `.atw/.developer`, which is never committed, so teammates are unaffected. While it is on, ATW hands you a `<noob-mode>` reminder at session start and on every turn — that is what makes the mode last through long conversations and new sessions. If the script fails, tell the user plainly and still follow the rules for this conversation.
|
|
21
|
+
|
|
22
|
+
Never switch it off on your own, and never drift out of it because a stage is long or technical. Only the user ends it.
|
|
23
|
+
|
|
24
|
+
## How you talk
|
|
25
|
+
|
|
26
|
+
Reply in the user's language. Keep commands, paths, file names, flags and error codes exactly as they are, and explain them beside the original.
|
|
27
|
+
|
|
28
|
+
1. **The point first.** Verdict, then the reason, then the trade-off. Never build up to a buried conclusion.
|
|
29
|
+
2. **Explain a term where it appears.** If a real term is unavoidable, give its meaning in the same sentence: "I'll merge it — that makes these changes part of the official version." This covers shorthand (PR, CI, repo, lint, diff, staging) and anything you coined during the session. Everyday words — file, folder, link, copy, save — need no explanation. If you would not know a term's exact meaning yourself, say so, and still say what it is for.
|
|
30
|
+
3. **Paths and file names are jargon too.** The first time one matters, say which folder, which file and what kind of file it is. After that the short form is fine.
|
|
31
|
+
4. **Say who did what.** You, the user, or an automatic check — every time. "I ran the tests" and "the tests ran" are different sentences to someone who cannot tell who acted.
|
|
32
|
+
5. **Seen versus expected.** Everything you claim is either something you watched happen or something you predict. Keep them apart. If you did not run it, "works", "fixed" and "verified" are not yours to use — say "not run yet".
|
|
33
|
+
6. **Say when you are guessing.** A file name, option, version or number that came from memory rather than from looking is a guess. Say so, and say how to settle it. An estimate is called an estimate.
|
|
34
|
+
7. **Name the decisions you made for them.** A shortcut, a placeholder standing in for the real thing, a skipped check, a silenced warning, an outside package, a change wider than asked, a pick between two defensible options — report each one where it happened: what you chose, why, and what it costs later. They cannot overrule a decision they never heard about.
|
|
35
|
+
8. **Alarming words are usually routine.** An error, a failed build, a conflict — name it calmly and say what it means for them right now.
|
|
36
|
+
|
|
37
|
+
## Before you act
|
|
38
|
+
|
|
39
|
+
Before any step the user must approve, and before anything hard to undo even when no approval is asked, say four things:
|
|
40
|
+
|
|
41
|
+
- **What** — exactly what will happen and what it touches.
|
|
42
|
+
- **Why** — how it serves what they asked for.
|
|
43
|
+
- **Risk** — a level from the table, the reason for it, and whether it can be undone.
|
|
44
|
+
- **Their choice** — what follows if they approve, and what follows if they decline.
|
|
45
|
+
|
|
46
|
+
Rate the effect, not the tool: a command is not dangerous because it is a command, and a click is not safe because it is a click.
|
|
47
|
+
|
|
48
|
+
| Risk | What it covers |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Low | Only reading or looking: opening a file, listing, searching. Nothing changes. |
|
|
51
|
+
| Medium | Changes that can be put back: creating or editing files, installing the project's own dependencies, local project state. |
|
|
52
|
+
| High | Deleting or overwriting, running code from an unknown source, uploading private data, changing what teammates share. |
|
|
53
|
+
| Critical | Passwords and keys, system-wide settings, live systems real users depend on, money, publishing, anything outside that cannot be taken back. |
|
|
54
|
+
|
|
55
|
+
Name a backup, history or undo path only when one really exists. Do not invent an approval step where the tool asks for none; routine reading needs no ceremony.
|
|
56
|
+
|
|
57
|
+
For work with more than two steps the user will notice, give a short roadmap first — outcomes, not tool calls — then report at real milestones. Do not narrate every internal step.
|
|
58
|
+
|
|
59
|
+
## When something comes back
|
|
60
|
+
|
|
61
|
+
Never leave raw output as the whole answer. Keep the exact lines they may need to pass on, then say it plainly.
|
|
62
|
+
|
|
63
|
+
- **An error** — what failed, whether any of their work or data changed, why (what you verified apart from what you suspect), and the smallest safe next step.
|
|
64
|
+
- **A success** — what worked, the result that matters, and what changed.
|
|
65
|
+
- **A sub-agent's report** — a sub-agent reports to you in engineer's terms. Retell it under these same rules, and keep "it ran this" apart from "it says this should work".
|
|
66
|
+
|
|
67
|
+
## When they must choose
|
|
68
|
+
|
|
69
|
+
Ask only when the answer changes the result or the risk. For each option that really differs: what it does, its main benefit, its main cost. Then say which you recommend and why. When a safe, standard default clearly follows from what they asked, take it and say that you did.
|
|
70
|
+
|
|
71
|
+
## When work is done
|
|
72
|
+
|
|
73
|
+
Report only what happened: the result, what was created, changed or deleted, what you actually checked, and how to undo it — when a real way exists. For something that cannot be undone, say so.
|
|
74
|
+
|
|
75
|
+
## Inside the ATW workflow
|
|
76
|
+
|
|
77
|
+
Noob mode changes how you talk to the user. It changes nothing about what the workflow requires or what you write into task files — `prd.md`, tickets and specs keep their normal form, because other tools and agents read them.
|
|
78
|
+
|
|
79
|
+
- **Stages.** The first time a stage comes up, say in a few words what it is for — discover is "getting clear on what you want", specify is "writing it down so we both agree", slice is "cutting the work into small pieces", implement is "building it", accept is "checking it against what we agreed".
|
|
80
|
+
- **Stops ①–④.** These are the user's decisions. Say what is being decided, what each answer leads to, and what you recommend. Never present a stop as a formality.
|
|
81
|
+
- **Skills only the user can run.** When the next step is theirs to start (`/atw-spec`, `/atw-tickets`, `/atw-implement`, `/atw-implement-spec`, `/atw-askme`, `/atw-map`), say what typing it will do and why it is their call, then give the exact text to type.
|
|
82
|
+
- **Asking them to confirm a file.** Do not hand over `prd.md` or a ticket list and ask "confirm?". Summarize in plain words what it commits to — what will be built, what will not, what counts as done — then point to the file.
|
|
83
|
+
- **Other skills' output.** A skill with its own format (review findings, ticket tables, a spec) keeps its format in the file. What you say about it to the user follows these rules.
|
|
84
|
+
|
|
85
|
+
## Catching up
|
|
86
|
+
|
|
87
|
+
These rules often arrive late, with engineer's language already sitting unread above. When noob mode is switched on mid-conversation, reread your own earlier replies and repair what still matters, oldest first, one line each:
|
|
88
|
+
|
|
89
|
+
1. Risky or hard-to-undo things you already did — what happened and whether it can still be reversed.
|
|
90
|
+
2. Predictions you wrote as results — separate what you watched from what you assumed.
|
|
91
|
+
3. Decisions you made for them that went by unmarked.
|
|
92
|
+
4. Terms, paths and numbers they still have to act on.
|
|
93
|
+
|
|
94
|
+
End with whatever now needs their decision. Restate, do not revise: never drop an earlier caveat or let an old guess harden into a fact. If nothing needs repair, say so in one sentence.
|
|
95
|
+
|
|
96
|
+
## Limits
|
|
97
|
+
|
|
98
|
+
- This is not dumbing down. Every real fact, gap and caveat stays; only the private vocabulary goes. When clear and complete conflict, cut for clarity and offer the rest.
|
|
99
|
+
- Never call the user non-technical, and never make them feel small for asking.
|
|
100
|
+
- Short by default. Say more when they ask or are still lost.
|
|
101
|
+
- Prefer the least destructive way to do what they asked.
|
|
@@ -51,25 +51,25 @@ class AssetCheck(HTMLParser):
|
|
|
51
51
|
self.head_position = None
|
|
52
52
|
|
|
53
53
|
def handle_starttag(self, tag: str, attrs: list) -> None:
|
|
54
|
-
|
|
54
|
+
attributes = dict(attrs)
|
|
55
55
|
if tag == "head" and self.head_position is None:
|
|
56
|
-
self.head_position = (self.getpos(), self.get_starttag_text())
|
|
56
|
+
self.head_position = (self.getpos(), self.get_starttag_text() or "")
|
|
57
57
|
if tag in ("iframe", "frame", "object", "embed"):
|
|
58
58
|
raise ValueError("候选 HTML 不支持嵌套文档;请提供静态内容或截图")
|
|
59
59
|
if tag == "style":
|
|
60
60
|
self.in_style = True
|
|
61
|
-
if
|
|
62
|
-
self.styles.append(
|
|
61
|
+
if attributes.get("style"):
|
|
62
|
+
self.styles.append(attributes["style"])
|
|
63
63
|
if tag == "base":
|
|
64
64
|
raise ValueError("候选 HTML 不应包含 base;资源需要内嵌")
|
|
65
|
-
if tag == "meta" and
|
|
65
|
+
if tag == "meta" and attributes.get("http-equiv", "").lower() == "refresh":
|
|
66
66
|
raise ValueError("候选 HTML 不应自动跳转")
|
|
67
67
|
for key in ("src", "poster", "data", "href", "xlink:href"):
|
|
68
|
-
value =
|
|
68
|
+
value = attributes.get(key, "") or ""
|
|
69
69
|
if not value or value.startswith(("#", "data:")):
|
|
70
70
|
continue
|
|
71
71
|
raise ValueError(f"候选 HTML 含未内嵌资源 {tag}.{key}: {value}")
|
|
72
|
-
if
|
|
72
|
+
if attributes.get("srcset"):
|
|
73
73
|
raise ValueError("候选 HTML 请用内嵌 src 代替 srcset")
|
|
74
74
|
|
|
75
75
|
def handle_endtag(self, tag: str) -> None:
|
|
@@ -251,6 +251,7 @@ def load_manifest(path: Path) -> tuple[dict, set[Path]]:
|
|
|
251
251
|
source = None
|
|
252
252
|
url = local_url(text_field(candidate, "url"), identifier)
|
|
253
253
|
else:
|
|
254
|
+
url = None
|
|
254
255
|
source = (path.parent / text_field(candidate, "source")).resolve()
|
|
255
256
|
if not source.is_relative_to(path.parent) or not source.is_file():
|
|
256
257
|
raise ValueError(f"候选 source 必须是 manifest 目录内可读文件: {identifier}")
|
|
@@ -258,12 +259,17 @@ def load_manifest(path: Path) -> tuple[dict, set[Path]]:
|
|
|
258
259
|
colors = text_list(candidate, "palette")
|
|
259
260
|
if any(not re.fullmatch(r"#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})", c) for c in colors):
|
|
260
261
|
raise ValueError(f"{identifier}: palette 需要十六进制颜色")
|
|
262
|
+
if source is None:
|
|
263
|
+
content = source_label = url
|
|
264
|
+
else:
|
|
265
|
+
content = prepare_html(source, interactive, path.parent, inputs) if kind == "html" else prepare_image(source)
|
|
266
|
+
source_label = source.name
|
|
261
267
|
output.append({
|
|
262
268
|
"id": identifier,
|
|
263
269
|
**{name: text_field(candidate, name) for name in ("name", "concept", "typography")},
|
|
264
270
|
"palette": colors, "traits": text_list(candidate, "traits"), "kind": kind,
|
|
265
|
-
"content":
|
|
266
|
-
"sourceLabel":
|
|
271
|
+
"content": content,
|
|
272
|
+
"sourceLabel": source_label,
|
|
267
273
|
"baseline": baseline,
|
|
268
274
|
"interactive": interactive,
|
|
269
275
|
})
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
|
|
7
7
|
This skill takes the current conversation context and codebase understanding and produces a spec. Do NOT interview the user — just synthesize what you already know.
|
|
8
8
|
|
|
9
|
-
The issue tracker and triage label vocabulary should have been provided to you. If not, tell the user to
|
|
9
|
+
The issue tracker and triage label vocabulary should have been provided to you. If not, tell the user to run `/atw-init-repo`, which writes both.
|
|
10
10
|
|
|
11
11
|
## Process
|
|
12
12
|
|
|
@@ -7,7 +7,7 @@ description: "测试驱动开发。当用户希望采用“先测试后开发”
|
|
|
7
7
|
|
|
8
8
|
TDD is the red → green loop. This skill is the reference that makes that loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, and the rules of the loop. Every section applies on every cycle — consult them before and during the loop, not after.
|
|
9
9
|
|
|
10
|
-
When exploring the codebase, read `
|
|
10
|
+
When exploring the codebase, read `GLOSSARY.md` (if it exists) so test names and interface vocabulary match the project's domain language, and respect ADRs in the area you're touching.
|
|
11
11
|
|
|
12
12
|
## What a good test is
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ A **seam** is the public boundary you test at: the interface where you observe b
|
|
|
21
21
|
|
|
22
22
|
**Test only at pre-agreed seams.** Before writing any test, write down the seams under test and confirm them with the user. No test is written at an unconfirmed seam. You can't test everything — agreeing the seams up front is how testing effort lands on the critical paths and complex logic instead of every edge case.
|
|
23
23
|
|
|
24
|
-
Ask: "What's the public interface, and which seams should we test?"
|
|
24
|
+
Ask: "What's the public interface, and which seams should we test?" Give each proposed seam a one-line note on what it catches and what it misses.
|
|
25
25
|
|
|
26
26
|
When the shape of that interface is itself in question — how deep the module is, where the seam belongs, what the interface should expose — call the Skill tool with "atw-codebase-design" for the vocabulary. It is the shared source of the module, interface, depth, seam, adapter, leverage and locality terms, and it is a reference to consult, not a session to run.
|
|
27
27
|
|
|
@@ -8,7 +8,7 @@ disable-model-invocation: true
|
|
|
8
8
|
|
|
9
9
|
Break a plan, spec, or conversation into a set of **tickets** — tracer-bullet vertical slices, each declaring the tickets that **block** it.
|
|
10
10
|
|
|
11
|
-
The issue tracker and triage label vocabulary should have been provided to you. If not, tell the user to
|
|
11
|
+
The issue tracker and triage label vocabulary should have been provided to you. If not, tell the user to run `/atw-init-repo`, which writes both.
|
|
12
12
|
|
|
13
13
|
## Process
|
|
14
14
|
|
|
@@ -64,8 +64,8 @@ Iterate until the user approves the breakdown.
|
|
|
64
64
|
|
|
65
65
|
Publish the approved tickets. **How** depends on the tracker this repo uses — the tickets are the same either way, only the shape of the blocking edges changes:
|
|
66
66
|
|
|
67
|
-
- **File-based trackers** → consult the tracker doc's "When a skill says publish to the issue tracker" section for the directory and naming convention; write one file per ticket, numbered from `01` in dependency order (blockers first). Each file's "Blocked by" lists the numbers/titles it depends on. Use the per-ticket file template below — one ticket per file, never a single combined file. **If the tracker doc defines extra ticket fields, add them on top of the template.**
|
|
68
|
-
- **A real issue tracker (GitHub, Linear, …)** → publish one issue per ticket in dependency order (blockers first) so each ticket's blocking edges can reference real identifiers. Use the platform's native blocking
|
|
67
|
+
- **File-based trackers** → consult the tracker doc's "When a skill says publish to the issue tracker" section for the directory and naming convention; write one file per ticket, numbered from `01` in dependency order (blockers first). Each file's "Blocked by" lists the numbers/titles it depends on — always written in the file, even where a mirror also draws native edges on a remote tracker, because tooling reads the line. Use the per-ticket file template below — one ticket per file, never a single combined file. **If the tracker doc defines extra ticket fields, add them on top of the template.**
|
|
68
|
+
- **A real issue tracker (GitHub, Linear, …)** → publish one issue per ticket in dependency order (blockers first) so each ticket's blocking edges can reference real identifiers. Use the platform's native blocking relationship where it has one; otherwise set each ticket's "Blocked by" to the blocking issues. If the source was an existing issue, make each ticket its sub-issue (tracker doc's operation). Apply the `ready-for-agent` triage label unless instructed otherwise — the tickets are agent-grabbable by construction.
|
|
69
69
|
|
|
70
70
|
Work the **frontier**: any ticket whose blockers are all done. For a purely linear chain that means top to bottom.
|
|
71
71
|
|
|
@@ -104,7 +104,7 @@ The end-to-end behaviour this ticket makes work, from the user's perspective —
|
|
|
104
104
|
|
|
105
105
|
## Blocked by
|
|
106
106
|
|
|
107
|
-
- A reference to each blocking ticket, or "None — can start immediately".
|
|
107
|
+
- A reference to each blocking ticket, or "None — can start immediately". Omit this section when blockers were set as native edges.
|
|
108
108
|
|
|
109
109
|
</issue-template>
|
|
110
110
|
|
|
@@ -40,7 +40,7 @@ For a PR, the same states read against the attached code: `ready-for-agent` mean
|
|
|
40
40
|
|
|
41
41
|
Every triaged issue should carry exactly one category role and one state role. If state roles conflict, flag it and ask the maintainer before doing anything else.
|
|
42
42
|
|
|
43
|
-
These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you. If not, tell the user to
|
|
43
|
+
These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you. If not, tell the user to run `/atw-init-repo`, which writes `docs/agents/triage-labels.md`.
|
|
44
44
|
|
|
45
45
|
State transitions: an unlabeled issue normally goes to `needs-triage` first; from there it moves to `needs-info`, `ready-for-agent`, `ready-for-human`, or `wontfix`. `needs-info` returns to `needs-triage` once the reporter replies. The maintainer can override at any time — flag transitions that look unusual and ask before proceeding.
|
|
46
46
|
|
|
@@ -73,7 +73,7 @@ Show counts and a one-line summary per item. Let the maintainer pick.
|
|
|
73
73
|
|
|
74
74
|
3. **Verify the claim.** Before any interview, check that the claim holds up. For a bug, reproduce it from the reporter's steps. For a PR, confirm the diff does what it claims — check it out, run the relevant tests or commands. Report what happened: confirmed (with code path), failed, or insufficient detail (a strong `needs-info` signal). A confirmed verification makes a much stronger agent brief.
|
|
75
75
|
|
|
76
|
-
4. **Interview (if needed).** If the request needs fleshing out, call the Skill tool twice, for "atw-interview" and "atw-domain-modeling" — interview a round of questions at a time, sharpening domain terms and updating `
|
|
76
|
+
4. **Interview (if needed).** If the request needs fleshing out, call the Skill tool twice, for "atw-interview" and "atw-domain-modeling" — interview a round of questions at a time, sharpening domain terms and updating `GLOSSARY.md`/ADRs inline as decisions land.
|
|
77
77
|
|
|
78
78
|
5. **Apply the outcome:**
|
|
79
79
|
- `ready-for-agent` — post an agent brief comment ([AGENT-BRIEF.md](AGENT-BRIEF.md)).
|
|
@@ -28,7 +28,7 @@ Shows the Phase Index (Plan / Execute / Finish) with routing + skill mapping.
|
|
|
28
28
|
- `status=specify` + no `prd.md` → **1.2** (`/atw-spec` turns the discover findings into `prd.md`)
|
|
29
29
|
- `status=specify` + `prd.md` exists → **1.3**. Sub-agent-dispatch platforms curate `check.jsonl` (empty, or only a legacy `_example` placeholder row, counts as uncurated); inline platforms skip. Then **stop ②** — the user confirms `prd.md` before anything advances. After that: `task.py set-status <task> slice` if the work needs tickets, otherwise straight to **1.5**.
|
|
30
30
|
- `status=slice` → **1.4** (`/atw-tickets`). Every ticket needs `**Impl:** ready` and a `**Blocked by:**` line. When they are written, run `task.py start <task>` (**1.5**).
|
|
31
|
-
- `status=implement` → **2.1**. `tickets.py frontier` → `tickets.py claim NN` (never two at `doing`) → **stop ③**: the user runs `/atw-implement`; you may not invoke it or inline the work → relay both review reports verbatim → `tickets.py done NN`. Frontier empty → `task.py set-status <task> accept`.
|
|
31
|
+
- `status=implement` → **2.1**. `tickets.py frontier` → `tickets.py claim NN` (never two at `doing`) → **stop ③**: the user runs `/atw-implement`; you may not invoke it or inline the work → relay both review reports verbatim → `tickets.py done NN`. Frontier empty → `task.py set-status <task> accept`. When the task has tickets, also name the other way through stop ③ — the user runs `/atw-implement-spec` once for the whole spec (**2.7**); several tickets at `doing` with `meta.ticket_mode = parallel` in `task.json` is that run in progress, not a broken state.
|
|
32
32
|
- `status=accept` → **3.1**. Read-only: file anything you notice instead of fixing it. Walk the `prd.md` acceptance criteria with evidence, confirm `tickets.py summary` is all `done` and `git status --porcelain` is clean, then **stop ④** and wait for the user to accept. Once accepted, `task.py archive <task>` (**3.2**).
|
|
33
33
|
- `status=completed` on a task still under `.atw/tasks/` → **3.2, unfinished**. `task.py archive` writes `completed` first, then re-parents children, then moves the directory — and it does not roll back, so a task sitting here with this status means the archive was interrupted partway. Re-run `task.py archive <task>` to finish it: every step before the move is idempotent, so the re-run redoes them and completes the move.
|
|
34
34
|
|
|
@@ -168,6 +168,30 @@ function getActiveTask(ctx, platformInput = null) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
// Fallback for a workflow.md without a [workflow-state:noob_mode] block
|
|
172
|
+
// (custom workflow template, or one older than the feature). Keep in sync with
|
|
173
|
+
// FALLBACK_REMINDER in .atw/scripts/common/noob_mode.py.
|
|
174
|
+
const NOOB_MODE_FALLBACK =
|
|
175
|
+
"Noob mode is ON — this user is not an engineer. Hold to the " +
|
|
176
|
+
"`/atw-noob-mode` rules in every reply: plain words in the user's " +
|
|
177
|
+
"language, and every term, command or path explained where it appears."
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The <noob-mode> block for a developer who switched noob mode on, else "".
|
|
181
|
+
* Mirrors noob_mode_reminder() in .atw/scripts/common/noob_mode.py: the
|
|
182
|
+
* switch is a `noob_mode=on` line in the gitignored .atw/.developer.
|
|
183
|
+
*/
|
|
184
|
+
function buildNoobModeReminder(directory, templates) {
|
|
185
|
+
let developer
|
|
186
|
+
try {
|
|
187
|
+
developer = readFileSync(join(directory, ".atw", ".developer"), "utf-8")
|
|
188
|
+
} catch {
|
|
189
|
+
return ""
|
|
190
|
+
}
|
|
191
|
+
if (!/^noob_mode=on\s*$/m.test(developer)) return ""
|
|
192
|
+
return `<noob-mode>\n${templates.noob_mode || NOOB_MODE_FALLBACK}\n</noob-mode>`
|
|
193
|
+
}
|
|
194
|
+
|
|
171
195
|
/**
|
|
172
196
|
* Build the <workflow-state>...</workflow-state> block.
|
|
173
197
|
* - Known status (tag present in workflow.md) → detailed body
|
|
@@ -225,8 +249,12 @@ export default async ({ directory }) => {
|
|
|
225
249
|
const breadcrumb = task
|
|
226
250
|
? buildBreadcrumb(task.id, task.status, templates, task.source)
|
|
227
251
|
: buildBreadcrumb(null, "no_task", templates)
|
|
252
|
+
const noobMode = buildNoobModeReminder(directory, templates)
|
|
228
253
|
|
|
229
|
-
prependEphemeralText(
|
|
254
|
+
prependEphemeralText(
|
|
255
|
+
messages,
|
|
256
|
+
noobMode ? `${breadcrumb}\n\n${noobMode}` : breadcrumb,
|
|
257
|
+
)
|
|
230
258
|
debugLog(
|
|
231
259
|
"workflow-state",
|
|
232
260
|
"Injected breadcrumb for task",
|
|
@@ -69,6 +69,12 @@ TICKET_BLOCKED_PREFIX = "**Blocked by:**"
|
|
|
69
69
|
NO_CURRENT_TICKET = "No ticket in progress"
|
|
70
70
|
MULTI_DOING_HEADLINE = "Multiple tickets marked doing"
|
|
71
71
|
|
|
72
|
+
# `tickets.py claim --parallel` (the /atw-implement-spec run) marks the task
|
|
73
|
+
# here. With it set, several `doing` tickets are the run, not a contradiction.
|
|
74
|
+
META_TICKET_MODE = "ticket_mode"
|
|
75
|
+
TICKET_MODE_PARALLEL = "parallel"
|
|
76
|
+
PARALLEL_RUN_HEADLINE = "Parallel run"
|
|
77
|
+
|
|
72
78
|
# =============================================================================
|
|
73
79
|
# Subagent Constants (change here to rename subagent types)
|
|
74
80
|
# =============================================================================
|
|
@@ -609,6 +615,17 @@ def scan_tickets(repo_root: str, task_dir: str) -> tuple[list[str], list[tuple[s
|
|
|
609
615
|
return doing, frontier
|
|
610
616
|
|
|
611
617
|
|
|
618
|
+
def is_parallel_run(repo_root: str, task_dir: str) -> bool:
|
|
619
|
+
"""Whether ``tickets.py claim --parallel`` put this task in parallel mode."""
|
|
620
|
+
task_json = Path(repo_root) / task_dir / FILE_TASK_JSON
|
|
621
|
+
try:
|
|
622
|
+
data = json.loads(task_json.read_text(encoding="utf-8"))
|
|
623
|
+
except (OSError, ValueError):
|
|
624
|
+
return False
|
|
625
|
+
meta = data.get("meta") if isinstance(data, dict) else None
|
|
626
|
+
return isinstance(meta, dict) and meta.get(META_TICKET_MODE) == TICKET_MODE_PARALLEL
|
|
627
|
+
|
|
628
|
+
|
|
612
629
|
def ticket_conflict_notice(repo_root: str, task_dir: str) -> str:
|
|
613
630
|
"""One-line warning for agents that do not consume the ticket axis.
|
|
614
631
|
|
|
@@ -620,7 +637,7 @@ def ticket_conflict_notice(repo_root: str, task_dir: str) -> str:
|
|
|
620
637
|
only; no ticket content crosses this path while the state is broken.
|
|
621
638
|
"""
|
|
622
639
|
doing, _ = scan_tickets(repo_root, task_dir)
|
|
623
|
-
if len(doing) < 2:
|
|
640
|
+
if len(doing) < 2 or is_parallel_run(repo_root, task_dir):
|
|
624
641
|
return ""
|
|
625
642
|
return (
|
|
626
643
|
f"=== Ticket State ===\n"
|
|
@@ -640,12 +657,21 @@ def get_ticket_context(
|
|
|
640
657
|
"""Current ticket in full + frontier summary, injected every round.
|
|
641
658
|
|
|
642
659
|
Raises MultipleTicketsDoing when the ticket state contradicts itself.
|
|
660
|
+
A parallel run holds several tickets at ``doing`` on purpose: those are
|
|
661
|
+
listed, and none is singled out as the current one.
|
|
643
662
|
"""
|
|
644
663
|
doing, frontier = scan_tickets(repo_root, task_dir)
|
|
645
|
-
if len(doing) > 1:
|
|
664
|
+
if len(doing) > 1 and not is_parallel_run(repo_root, task_dir):
|
|
646
665
|
raise MultipleTicketsDoing(doing)
|
|
647
666
|
|
|
648
|
-
if doing:
|
|
667
|
+
if len(doing) > 1:
|
|
668
|
+
in_progress = "\n".join(f"- {rel}" for rel in doing)
|
|
669
|
+
current = (
|
|
670
|
+
f"=== Tickets In Progress ===\n"
|
|
671
|
+
f"{PARALLEL_RUN_HEADLINE}: {len(doing)} tickets are in progress at "
|
|
672
|
+
f"once, so there is no single current ticket:\n{in_progress}"
|
|
673
|
+
)
|
|
674
|
+
elif doing:
|
|
649
675
|
current = _materialize_artifact(
|
|
650
676
|
repo_root,
|
|
651
677
|
doing[0],
|
|
@@ -326,13 +326,15 @@ def _codex_mode_banner(config: dict) -> str:
|
|
|
326
326
|
meaning = (
|
|
327
327
|
"auto: review work is dispatched to atw-review sub-agents; native Codex "
|
|
328
328
|
"context injection is preferred and child-side loading is the fallback. "
|
|
329
|
-
"Implementation is never dispatched: code is written inside /atw-implement "
|
|
330
|
-
"in the main session, which also coordinates, clarifies, updates specs, commits, and finishes."
|
|
329
|
+
"Implementation is never dispatched on the per-ticket path: code is written inside /atw-implement "
|
|
330
|
+
"in the main session, which also coordinates, clarifies, updates specs, commits, and finishes. "
|
|
331
|
+
"Only a /atw-implement-spec run, started by the user, dispatches implementer sub-agents."
|
|
331
332
|
)
|
|
332
333
|
else:
|
|
333
334
|
meaning = (
|
|
334
335
|
"inline: the main session also reviews directly; "
|
|
335
|
-
"do not dispatch any ATW sub-agent. Implementation is in /atw-implement
|
|
336
|
+
"do not dispatch any ATW sub-agent. Implementation is in /atw-implement; "
|
|
337
|
+
"/atw-implement-spec needs sub-agents and is unavailable in this mode."
|
|
336
338
|
)
|
|
337
339
|
return f"<codex-mode>{meaning}</codex-mode>"
|
|
338
340
|
|
|
@@ -381,6 +383,24 @@ def build_breadcrumb(
|
|
|
381
383
|
return f"<workflow-state>\n{header}\n{body}\n</workflow-state>"
|
|
382
384
|
|
|
383
385
|
|
|
386
|
+
def _noob_mode_reminder(root: Path) -> str:
|
|
387
|
+
"""The `<noob-mode>` block for a developer who switched noob mode on, else "".
|
|
388
|
+
|
|
389
|
+
Riding on the per-turn breadcrumb is the point of the feature: a skill
|
|
390
|
+
loaded once fades over a long conversation, this is said again every turn.
|
|
391
|
+
An install whose scripts predate the helper simply has no noob mode.
|
|
392
|
+
"""
|
|
393
|
+
scripts_dir = root / ".atw" / "scripts"
|
|
394
|
+
if str(scripts_dir) not in sys.path:
|
|
395
|
+
sys.path.insert(0, str(scripts_dir))
|
|
396
|
+
try:
|
|
397
|
+
from common.noob_mode import noob_mode_reminder # type: ignore[import-not-found]
|
|
398
|
+
|
|
399
|
+
return noob_mode_reminder(root)
|
|
400
|
+
except Exception:
|
|
401
|
+
return ""
|
|
402
|
+
|
|
403
|
+
|
|
384
404
|
# ---------------------------------------------------------------------------
|
|
385
405
|
# Entry
|
|
386
406
|
# ---------------------------------------------------------------------------
|
|
@@ -460,6 +480,10 @@ def main() -> int:
|
|
|
460
480
|
parts.append(breadcrumb)
|
|
461
481
|
breadcrumb = "\n\n".join(parts)
|
|
462
482
|
|
|
483
|
+
noob_mode = _noob_mode_reminder(root)
|
|
484
|
+
if noob_mode:
|
|
485
|
+
breadcrumb = f"{breadcrumb}\n\n{noob_mode}"
|
|
486
|
+
|
|
463
487
|
# Kiro (CLI userPromptSubmit / IDE promptSubmit) adds a hook's stdout
|
|
464
488
|
# directly to the conversation context — no JSON envelope. Emit the bare
|
|
465
489
|
# breadcrumb text. Conditionally isolated: all other platforms keep the
|
|
@@ -82,6 +82,25 @@ This notice is one-shot: do not repeat it after the first visible assistant repl
|
|
|
82
82
|
FIRST_REPLY_NOTICE = f"{_FIRST_REPLY_NOTICE_HEAD}\n{_FIRST_REPLY_NOTICE_TAIL}"
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def _noob_mode_reminder(project_dir: Path) -> str:
|
|
86
|
+
"""The `<noob-mode>` block for a developer who switched noob mode on, else "".
|
|
87
|
+
|
|
88
|
+
Platforms with a per-turn hook hear this again every turn; here it covers
|
|
89
|
+
the ones that only have SessionStart (Cursor) and the first reply of a
|
|
90
|
+
session everywhere. An install whose scripts predate the helper simply has
|
|
91
|
+
no noob mode.
|
|
92
|
+
"""
|
|
93
|
+
scripts_dir = project_dir / ".atw" / "scripts"
|
|
94
|
+
if str(scripts_dir) not in sys.path:
|
|
95
|
+
sys.path.insert(0, str(scripts_dir))
|
|
96
|
+
try:
|
|
97
|
+
from common.noob_mode import noob_mode_reminder # type: ignore[import-not-found]
|
|
98
|
+
|
|
99
|
+
return noob_mode_reminder(project_dir)
|
|
100
|
+
except Exception:
|
|
101
|
+
return ""
|
|
102
|
+
|
|
103
|
+
|
|
85
104
|
def _build_first_reply_notice(update_hint: str | None) -> str:
|
|
86
105
|
"""First-reply notice, carrying the ATW update reminder when there is one.
|
|
87
106
|
|
|
@@ -815,6 +834,10 @@ ATW compact SessionStart context. Use it to orient the session; load details on
|
|
|
815
834
|
output.write(_build_first_reply_notice(_resolve_update_hint(atw_dir, context_key)))
|
|
816
835
|
output.write("\n\n")
|
|
817
836
|
|
|
837
|
+
noob_mode = _noob_mode_reminder(project_dir)
|
|
838
|
+
if noob_mode:
|
|
839
|
+
output.write(f"{noob_mode}\n\n")
|
|
840
|
+
|
|
818
841
|
# Legacy migration warning
|
|
819
842
|
legacy_warning = _check_legacy_spec(atw_dir, is_mono, packages)
|
|
820
843
|
if legacy_warning:
|
|
@@ -22,7 +22,7 @@ snow
|
|
|
22
22
|
In Snow:
|
|
23
23
|
|
|
24
24
|
1. Open a session in the project root — `onSessionStart` injects ATW context automatically.
|
|
25
|
-
2. Dispatch review (`atw-review`, project agent under `.snow/agents/`); implementation runs in the main session via `/atw-implement
|
|
25
|
+
2. Dispatch review (`atw-review`, project agent under `.snow/agents/`); implementation runs in the main session via `/atw-implement` (a `/atw-implement-spec` run dispatches its own implementers). Prefer prompt first line:
|
|
26
26
|
|
|
27
27
|
```text
|
|
28
28
|
Active task: .atw/tasks/<id>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-writer.d.ts","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-writer.d.ts","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;CACjB;AASD,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAK7D;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAsCD;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,OAAO,CAAC,OAAO,CAAC,CAgLlB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C"}
|