@chinhae/atw-cli 0.3.6 → 0.5.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 +191 -17
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +25 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +154 -17
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mode.d.ts +21 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +401 -0
- package/dist/commands/mode.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +20 -13
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/workflow.d.ts +17 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +9 -3
- package/dist/commands/workflow.js.map +1 -1
- package/dist/configurators/claude.d.ts +3 -2
- package/dist/configurators/claude.d.ts.map +1 -1
- package/dist/configurators/claude.js +3 -3
- package/dist/configurators/claude.js.map +1 -1
- package/dist/configurators/codex.d.ts +4 -3
- package/dist/configurators/codex.d.ts.map +1 -1
- package/dist/configurators/codex.js +10 -10
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/index.d.ts +9 -3
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +95 -17
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/shared.d.ts +13 -0
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +25 -0
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/workflow.d.ts +15 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +23 -5
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/configurators/zcode.d.ts +1 -1
- package/dist/configurators/zcode.d.ts.map +1 -1
- package/dist/configurators/zcode.js +2 -2
- package/dist/configurators/zcode.js.map +1 -1
- package/dist/constants/paths.d.ts +4 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +4 -0
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.4.0.json +9 -0
- package/dist/migrations/manifests/0.5.0.json +9 -0
- package/dist/templates/atw/config.yaml +7 -6
- package/dist/templates/atw/index.d.ts +10 -1
- package/dist/templates/atw/index.d.ts.map +1 -1
- package/dist/templates/atw/index.js +11 -1
- package/dist/templates/atw/index.js.map +1 -1
- package/dist/templates/atw/scripts/add_session.py +34 -13
- package/dist/templates/atw/scripts/common/active_task.py +2 -2
- package/dist/templates/atw/scripts/common/config.py +13 -0
- package/dist/templates/atw/scripts/common/developer.py +15 -4
- package/dist/templates/atw/scripts/common/noob_mode.py +35 -15
- package/dist/templates/atw/scripts/common/packages_context.py +16 -3
- package/dist/templates/atw/scripts/common/session_context.py +77 -19
- package/dist/templates/atw/scripts/common/task_store.py +78 -27
- package/dist/templates/atw/scripts/noob_mode.py +16 -4
- package/dist/templates/atw/scripts/task.py +99 -38
- package/dist/templates/atw/workflow-general.md +554 -0
- package/dist/templates/atw/workflow.md +49 -19
- package/dist/templates/codex/hooks/session-start.py +69 -18
- package/dist/templates/common/bundled-skills/atw-implement/SKILL.md +8 -0
- package/dist/templates/common/bundled-skills/atw-implement-all/SKILL.md +93 -0
- package/dist/templates/common/bundled-skills/atw-implement-all/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw-local.md +3 -1
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw.md +3 -1
- package/dist/templates/common/bundled-skills/atw-noob-mode/SKILL.md +7 -5
- package/dist/templates/common/bundled-skills/atw-tickets/SKILL.md +2 -0
- package/dist/templates/common/commands/continue.md +1 -1
- package/dist/templates/common/commands/start.md +43 -0
- package/dist/templates/copilot/hooks/session-start.py +69 -18
- package/dist/templates/dsh/DSH.md +43 -0
- package/dist/templates/markdown/agents.md +11 -0
- package/dist/templates/markdown/index.d.ts +9 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +14 -1
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/conventions.md.txt +13 -0
- package/dist/templates/opencode/lib/atw-context.js +19 -0
- package/dist/templates/opencode/lib/session-utils.js +79 -24
- package/dist/templates/opencode/plugins/inject-workflow-state.js +18 -8
- package/dist/templates/pi/extensions/atw/index.ts.txt +20 -9
- package/dist/templates/shared-hooks/inject-shell-session-context.py +3 -3
- package/dist/templates/shared-hooks/inject-workflow-state.py +23 -4
- package/dist/templates/shared-hooks/session-start.py +70 -22
- package/dist/templates/snow/SNOW.md +31 -1
- package/dist/templates/snow/hooks/write-atw-context.py +64 -0
- package/dist/utils/manifest-prune.d.ts +2 -1
- package/dist/utils/manifest-prune.d.ts.map +1 -1
- package/dist/utils/manifest-prune.js +10 -7
- package/dist/utils/manifest-prune.js.map +1 -1
- package/dist/utils/optional-skills.d.ts.map +1 -1
- package/dist/utils/optional-skills.js +2 -1
- package/dist/utils/optional-skills.js.map +1 -1
- package/dist/utils/project-mode.d.ts +30 -0
- package/dist/utils/project-mode.d.ts.map +1 -0
- package/dist/utils/project-mode.js +86 -0
- package/dist/utils/project-mode.js.map +1 -0
- package/dist/utils/workflow-resolver.d.ts +9 -5
- package/dist/utils/workflow-resolver.d.ts.map +1 -1
- package/dist/utils/workflow-resolver.js +25 -11
- package/dist/utils/workflow-resolver.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
{{^MODE_GENERAL}}
|
|
1
2
|
# Start Session
|
|
2
3
|
|
|
3
4
|
Initialize an ATW-managed development session. This platform has no session-start hook, so manually load the equivalent compact context by following these steps.
|
|
@@ -66,3 +67,45 @@ Load the step detail before acting on it:
|
|
|
66
67
|
| Learned something worth capturing | `atw-update-spec` |
|
|
67
68
|
|
|
68
69
|
Full rules + anti-rationalization table in `.atw/workflow.md`.
|
|
70
|
+
{{/MODE_GENERAL}}
|
|
71
|
+
{{#MODE_GENERAL}}
|
|
72
|
+
# Start Session
|
|
73
|
+
|
|
74
|
+
Load this project's ATW context. This platform has no session-start hook, so do it by hand with the steps below.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Step 1: Current state
|
|
79
|
+
Who you are working with, the current task, unfinished tasks, where the journal is, and the project's conventions.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
{{PYTHON_CMD}} ./.atw/scripts/get_context.py
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If this output includes a line beginning `ATW update available:`, copy the full line verbatim when summarizing session context. Do not shorten operational command hints.
|
|
86
|
+
|
|
87
|
+
## Step 2: Workflow overview
|
|
88
|
+
How work goes in this project, and what to do at each task status.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
{{PYTHON_CMD}} ./.atw/scripts/get_context.py --mode phase
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Full guide in `.atw/workflow.md` (read on demand).
|
|
95
|
+
|
|
96
|
+
## Step 3: Conventions
|
|
97
|
+
`.atw/spec/conventions.md` is the one place this project keeps what the user asked for more than once. Step 1 printed it inside `<conventions>`: follow it in every reply. If that block was missing, read the file itself:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cat .atw/spec/conventions.md
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Step 4: Decide next action
|
|
104
|
+
Step 1 gave you the current task and its `status`; Step 2 told you what the workflow does at that status. Do that. With no current task, do what the workflow says for a session that has none.
|
|
105
|
+
|
|
106
|
+
To read one step of the workflow in full:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
{{PYTHON_CMD}} ./.atw/scripts/get_context.py --mode phase --step <X.Y> --platform {{CLI_FLAG}}
|
|
110
|
+
```
|
|
111
|
+
{{/MODE_GENERAL}}
|
|
@@ -131,6 +131,24 @@ def read_file(path: Path, fallback: str = "") -> str:
|
|
|
131
131
|
return fallback
|
|
132
132
|
|
|
133
133
|
|
|
134
|
+
def _conventions_context(project_dir: Path) -> str:
|
|
135
|
+
"""The `<conventions>` block of a `general` project, else "".
|
|
136
|
+
|
|
137
|
+
A general project has one flat conventions file instead of per-package,
|
|
138
|
+
per-layer guideline indexes. An install whose scripts predate the helper is
|
|
139
|
+
treated as a dev project.
|
|
140
|
+
"""
|
|
141
|
+
scripts_dir = project_dir / ".atw" / "scripts"
|
|
142
|
+
if str(scripts_dir) not in sys.path:
|
|
143
|
+
sys.path.insert(0, str(scripts_dir))
|
|
144
|
+
try:
|
|
145
|
+
from common.session_context import conventions_context # type: ignore[import-not-found]
|
|
146
|
+
|
|
147
|
+
return conventions_context(project_dir)
|
|
148
|
+
except Exception:
|
|
149
|
+
return ""
|
|
150
|
+
|
|
151
|
+
|
|
134
152
|
def _resolve_context_key(project_dir: Path, hook_input: dict) -> str | None:
|
|
135
153
|
scripts_dir = project_dir / ".atw" / "scripts"
|
|
136
154
|
if str(scripts_dir) not in sys.path:
|
|
@@ -202,9 +220,20 @@ def _resolve_task_dir(atw_dir: Path, task_ref: str) -> Path:
|
|
|
202
220
|
return atw_dir / "tasks" / path_obj
|
|
203
221
|
|
|
204
222
|
|
|
205
|
-
def _get_task_status(atw_dir: Path, hook_input: dict) -> str:
|
|
223
|
+
def _get_task_status(atw_dir: Path, hook_input: dict, general: bool = False) -> str:
|
|
224
|
+
"""Compact active-task status and next action.
|
|
225
|
+
|
|
226
|
+
In a `general` project the AI decides on its own whether a request gets a
|
|
227
|
+
task, so the no-task line defers to the workflow instead of telling it to
|
|
228
|
+
ask first.
|
|
229
|
+
"""
|
|
206
230
|
active = _resolve_active_task(atw_dir, hook_input)
|
|
207
231
|
if not active.task_path:
|
|
232
|
+
if general:
|
|
233
|
+
return (
|
|
234
|
+
"Status: NO ACTIVE TASK\n"
|
|
235
|
+
"Next: Do what <atw-workflow> above says for a session with no current task."
|
|
236
|
+
)
|
|
208
237
|
return (
|
|
209
238
|
"Status: NO ACTIVE TASK\n"
|
|
210
239
|
"Next: Classify the current turn and ask for task-creation consent "
|
|
@@ -231,6 +260,13 @@ def _get_task_status(atw_dir: Path, hook_input: dict) -> str:
|
|
|
231
260
|
task_status = task_data.get("status", "unknown")
|
|
232
261
|
|
|
233
262
|
if task_status == "completed":
|
|
263
|
+
if general:
|
|
264
|
+
# general 的任务不记分支;在有远端的仓库里不带这个开关归档会被拒绝。
|
|
265
|
+
return (
|
|
266
|
+
f"Status: COMPLETED\nTask: {task_title}\n"
|
|
267
|
+
"Next: The archive was interrupted. Finish it with "
|
|
268
|
+
f"`python3 ./.atw/scripts/task.py archive {task_dir.name} --skip-branch-validation`."
|
|
269
|
+
)
|
|
234
270
|
return (
|
|
235
271
|
f"Status: COMPLETED\nTask: {task_title}\n"
|
|
236
272
|
f"Next: Archive with `python3 ./.atw/scripts/task.py archive {task_dir.name}` "
|
|
@@ -248,6 +284,12 @@ def _get_task_status(atw_dir: Path, hook_input: dict) -> str:
|
|
|
248
284
|
if not has_prd:
|
|
249
285
|
# 这条不以任务状态为门,任何阶段缺 prd.md 都会进——所以状态名要照实报,
|
|
250
286
|
# 不能像以前那样硬编码成一个词表里已经没有的阶段。
|
|
287
|
+
if general:
|
|
288
|
+
# general 不装头脑风暴技能,prd.md 由 AI 照流程自己写。
|
|
289
|
+
return (
|
|
290
|
+
f"Status: {task_status.upper()}\nTask: {task_title}\nPresent: {present_line}\n"
|
|
291
|
+
"Next: Write prd.md as <atw-workflow> above says before task.py start."
|
|
292
|
+
)
|
|
251
293
|
return (
|
|
252
294
|
f"Status: {task_status.upper()}\nTask: {task_title}\nPresent: {present_line}\n"
|
|
253
295
|
"Next: Load atw-brainstorm and write prd.md before task.py start."
|
|
@@ -280,6 +322,9 @@ def _run_git(repo_root: Path, args: list[str]) -> str:
|
|
|
280
322
|
|
|
281
323
|
|
|
282
324
|
def _format_git_state(repo_root: Path) -> str:
|
|
325
|
+
# 普通文件夹没有分支,也谈不上干净:照实说,不编一个状态出来。
|
|
326
|
+
if _run_git(repo_root, ["rev-parse", "--is-inside-work-tree"]) != "true":
|
|
327
|
+
return "Git: not a git repository."
|
|
283
328
|
branch = _run_git(repo_root, ["branch", "--show-current"]) or "(detached)"
|
|
284
329
|
dirty_lines = [
|
|
285
330
|
line for line in _run_git(repo_root, ["status", "--porcelain"]).splitlines()
|
|
@@ -452,7 +497,10 @@ def main() -> None:
|
|
|
452
497
|
configure_project_encoding(project_dir)
|
|
453
498
|
|
|
454
499
|
atw_dir = project_dir / ".atw"
|
|
455
|
-
|
|
500
|
+
# A general project keeps no guideline indexes — whatever a switch from dev
|
|
501
|
+
# left under `.atw/spec/` is not offered there.
|
|
502
|
+
conventions = _conventions_context(project_dir)
|
|
503
|
+
spec_index_paths = [] if conventions else _collect_spec_index_paths(atw_dir)
|
|
456
504
|
|
|
457
505
|
output = StringIO()
|
|
458
506
|
|
|
@@ -470,24 +518,27 @@ ATW compact SessionStart context. Use it to orient the session; load details on
|
|
|
470
518
|
output.write(_build_workflow_toc(atw_dir / "workflow.md"))
|
|
471
519
|
output.write("\n</atw-workflow>\n\n")
|
|
472
520
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
521
|
+
if conventions:
|
|
522
|
+
output.write(f"{conventions}\n\n")
|
|
523
|
+
else:
|
|
524
|
+
output.write("<guidelines>\n")
|
|
525
|
+
output.write(
|
|
526
|
+
"Task context order for implementation/check: jsonl entries -> `prd.md`.\n\n"
|
|
527
|
+
)
|
|
477
528
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
529
|
+
if spec_index_paths:
|
|
530
|
+
output.write("## Available indexes (read on demand)\n")
|
|
531
|
+
for p in spec_index_paths:
|
|
532
|
+
output.write(f"- {p}\n")
|
|
533
|
+
output.write("\n")
|
|
534
|
+
|
|
535
|
+
output.write(
|
|
536
|
+
"Discover more via: "
|
|
537
|
+
"`python3 ./.atw/scripts/get_context.py --mode packages`\n"
|
|
538
|
+
)
|
|
539
|
+
output.write("</guidelines>\n\n")
|
|
489
540
|
|
|
490
|
-
task_status = _get_task_status(atw_dir, hook_input)
|
|
541
|
+
task_status = _get_task_status(atw_dir, hook_input, general=bool(conventions))
|
|
491
542
|
output.write(f"<task-status>\n{task_status}\n</task-status>\n\n")
|
|
492
543
|
|
|
493
544
|
output.write("""<ready>
|
|
@@ -4,6 +4,7 @@ dsh is a **class-2 pull-based** ATW host: no session-start hook auto-injects
|
|
|
4
4
|
workflow context, so the agent loads the ATW skills on demand through its
|
|
5
5
|
skill-loader tool.
|
|
6
6
|
|
|
7
|
+
{{^MODE_GENERAL}}
|
|
7
8
|
| Capability | Status |
|
|
8
9
|
| --- | --- |
|
|
9
10
|
| Skills (`.agents/skills/atw-*/SKILL.md`) | Works — dsh discovers this shared root natively |
|
|
@@ -44,6 +45,46 @@ In dsh:
|
|
|
44
45
|
- `.atw/` — specs, tasks, workspace memory, and the shared scripts the
|
|
45
46
|
skills invoke (`get_context.py`, `task.py`, ...).
|
|
46
47
|
|
|
48
|
+
{{/MODE_GENERAL}}
|
|
49
|
+
{{#MODE_GENERAL}}
|
|
50
|
+
This project is in ATW's `general` mode, for work that is not code: you say
|
|
51
|
+
what you want in your own words, and the workflow in `.atw/workflow.md` has
|
|
52
|
+
the agent do the rest.
|
|
53
|
+
|
|
54
|
+
| Capability | Status |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| Skills (`.agents/skills/atw-*/SKILL.md`) | Works — dsh discovers this shared root natively |
|
|
57
|
+
| Entry skill (`.dsh/skills/atw-start/SKILL.md`) | Works — dsh's own project skill root (highest rank) |
|
|
58
|
+
| Context hooks | None — pull-based: skills read `.atw/` files directly |
|
|
59
|
+
| Sub-agents | None |
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
atw init --dsh --mode general -u your-name
|
|
65
|
+
dsh web # or: dsh --profile headless "plan ..."
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
In dsh:
|
|
69
|
+
|
|
70
|
+
1. Open a session in the project root and say what you want done. The agent
|
|
71
|
+
should first load the `atw-start` skill, which reads the current task,
|
|
72
|
+
the workflow and the project's conventions from `.atw/`.
|
|
73
|
+
2. There is nothing else to ask for by name. The workflow has the agent keep
|
|
74
|
+
the task record, show you what it wrote down before it starts, check the
|
|
75
|
+
result with you, and file it when you accept.
|
|
76
|
+
|
|
77
|
+
## File map
|
|
78
|
+
|
|
79
|
+
- `.agents/skills/` — the six skills of `general` mode: `atw-interview`,
|
|
80
|
+
`atw-research`, `atw-session-insight`, `atw-noob-mode`, `atw-askme`,
|
|
81
|
+
`atw-handoff`.
|
|
82
|
+
- `.dsh/skills/` — the dsh-private entry skill `atw-start`.
|
|
83
|
+
- `.atw/` — tasks, the conventions file (`.atw/spec/conventions.md`),
|
|
84
|
+
workspace memory, and the shared scripts the skills invoke
|
|
85
|
+
(`get_context.py`, `task.py`, ...).
|
|
86
|
+
|
|
87
|
+
{{/MODE_GENERAL}}
|
|
47
88
|
## Notes
|
|
48
89
|
|
|
49
90
|
- Skill scripts pass `--platform dsh` to `get_context.py`; the value is used
|
|
@@ -51,6 +92,8 @@ In dsh:
|
|
|
51
92
|
- The shipped `minimal` agent preset composes only `bash` +
|
|
52
93
|
`str_replace_editor`; the default presets include `web_search` and the
|
|
53
94
|
filesystem/terminal tools the skills assume.
|
|
95
|
+
{{^MODE_GENERAL}}
|
|
54
96
|
- dsh has no project-level sub-agent definition surface, so ATW ships no
|
|
55
97
|
`atw-implement-agent` / `atw-review` agent prompts
|
|
56
98
|
here — the workflow skills run those phases inline in the main session.
|
|
99
|
+
{{/MODE_GENERAL}}
|
|
@@ -5,16 +5,27 @@ These instructions are for AI assistants working in this project.
|
|
|
5
5
|
|
|
6
6
|
This project is managed by ATW. The working knowledge you need lives under `.atw/`:
|
|
7
7
|
|
|
8
|
+
{{^MODE_GENERAL}}
|
|
8
9
|
- `.atw/workflow.md` — development phases, when to create tasks, skill routing
|
|
9
10
|
- `.atw/spec/` — package- and layer-scoped coding guidelines (read before writing code in a given layer)
|
|
11
|
+
{{/MODE_GENERAL}}
|
|
12
|
+
{{#MODE_GENERAL}}
|
|
13
|
+
- `.atw/workflow.md` — how work goes here: when to keep a task, what to write down for the user to confirm, how to check and file the result
|
|
14
|
+
- `.atw/spec/conventions.md` — what the user asked for more than once (follow it in every reply; add to it when they correct you)
|
|
15
|
+
{{/MODE_GENERAL}}
|
|
10
16
|
- `.atw/workspace/` — per-developer journals and session traces
|
|
11
17
|
- `.atw/tasks/` — active and archived tasks (PRDs, research, jsonl context)
|
|
12
18
|
|
|
19
|
+
{{^MODE_GENERAL}}
|
|
13
20
|
ATW commands are written by bare name throughout `.atw/` — `start`, `continue`, `finish-work`. The prefix that invokes them is your platform's, not ATW's: Claude Code uses `/atw:`, Cursor and Pi `/atw-`, Codex `$`, Copilot a plain `/`, and a few hosts expose them as skills instead. Prefer an available ATW command over manual steps; not every platform exposes every command.
|
|
14
21
|
|
|
15
22
|
If you're using Codex or another agent-capable tool, additional project-scoped helpers may live in:
|
|
16
23
|
- `.agents/skills/` — reusable ATW skills
|
|
17
24
|
- `.codex/agents/` — optional custom subagents
|
|
25
|
+
{{/MODE_GENERAL}}
|
|
26
|
+
{{#MODE_GENERAL}}
|
|
27
|
+
The user moves the work along by saying what they want, not by running ATW commands: you create, advance and archive tasks yourself, as the workflow says. The one ATW command is `start`, which loads this context on platforms that do not load it when a session begins; the prefix that invokes it is your platform's, not ATW's.
|
|
28
|
+
{{/MODE_GENERAL}}
|
|
18
29
|
|
|
19
30
|
Managed by ATW. Edits outside this block are preserved; edits inside may be overwritten by a future `atw update`.
|
|
20
31
|
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
* These are GENERIC templates for new projects.
|
|
5
5
|
* Structure templates use .md.txt extension as they are generic templates.
|
|
6
6
|
*/
|
|
7
|
+
import type { ProjectMode } from "../../utils/project-mode.js";
|
|
8
|
+
/**
|
|
9
|
+
* 某个项目模式的根 `AGENTS.md`,即该模式下这个文件的 ATW 原版内容。
|
|
10
|
+
*
|
|
11
|
+
* 初始化、升级和模式切换都从这里取,所以三处给出的是同一份。
|
|
12
|
+
*/
|
|
13
|
+
export declare function agentsMdFor(mode: ProjectMode): string;
|
|
14
|
+
/** dev 项目(以及没有模式配置项的老项目)的 `AGENTS.md`。 */
|
|
7
15
|
export declare const agentsMdContent: string;
|
|
8
16
|
export declare const workspaceIndexContent: string;
|
|
9
17
|
export declare const agentProgressIndexContent: string;
|
|
@@ -25,4 +33,5 @@ export declare const frontendDesignSystemContent: string;
|
|
|
25
33
|
export declare const guidesIndexContent: string;
|
|
26
34
|
export declare const guidesCrossLayerThinkingGuideContent: string;
|
|
27
35
|
export declare const guidesCodeReuseThinkingGuideContent: string;
|
|
36
|
+
export declare const conventionsContent: string;
|
|
28
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAmB/D;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAErD;AAED,0CAA0C;AAC1C,eAAO,MAAM,eAAe,EAAE,MAA2B,CAAC;AAG1D,eAAO,MAAM,qBAAqB,EAAE,MACK,CAAC;AAG1C,eAAO,MAAM,yBAAyB,QAAwB,CAAC;AAG/D,eAAO,MAAM,wBAAwB,EAAE,MACH,CAAC;AAQrC,eAAO,MAAM,mBAAmB,EAAE,MAEjC,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,+BAA+B,EAAE,MAE7C,CAAC;AACF,eAAO,MAAM,+BAA+B,EAAE,MAE7C,CAAC;AACF,eAAO,MAAM,2BAA2B,EAAE,MAEzC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAElC,CAAC;AACF,eAAO,MAAM,iCAAiC,EAAE,MAE/C,CAAC;AACF,eAAO,MAAM,yBAAyB,EAAE,MAEvC,CAAC;AACF,eAAO,MAAM,6BAA6B,EAAE,MAE3C,CAAC;AACF,eAAO,MAAM,kCAAkC,EAAE,MAEhD,CAAC;AACF,eAAO,MAAM,gCAAgC,EAAE,MAE9C,CAAC;AACF,eAAO,MAAM,8BAA8B,EAAE,MAE5C,CAAC;AACF,eAAO,MAAM,2BAA2B,EAAE,MAEzC,CAAC;AAGF,eAAO,MAAM,kBAAkB,EAAE,MAEhC,CAAC;AACF,eAAO,MAAM,oCAAoC,EAAE,MAElD,CAAC;AACF,eAAO,MAAM,mCAAmC,EAAE,MAEjD,CAAC;AAGF,eAAO,MAAM,kBAAkB,EAAE,MAEhC,CAAC"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { readFileSync } from "node:fs";
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { resolveModeBlocks } from "../../configurators/shared.js";
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = dirname(__filename);
|
|
12
13
|
/**
|
|
@@ -19,7 +20,17 @@ function readLocalTemplate(filename) {
|
|
|
19
20
|
// =============================================================================
|
|
20
21
|
// Root files for new projects
|
|
21
22
|
// =============================================================================
|
|
22
|
-
|
|
23
|
+
const agentsMdTemplate = readLocalTemplate("agents.md");
|
|
24
|
+
/**
|
|
25
|
+
* 某个项目模式的根 `AGENTS.md`,即该模式下这个文件的 ATW 原版内容。
|
|
26
|
+
*
|
|
27
|
+
* 初始化、升级和模式切换都从这里取,所以三处给出的是同一份。
|
|
28
|
+
*/
|
|
29
|
+
export function agentsMdFor(mode) {
|
|
30
|
+
return resolveModeBlocks(agentsMdTemplate, mode);
|
|
31
|
+
}
|
|
32
|
+
/** dev 项目(以及没有模式配置项的老项目)的 `AGENTS.md`。 */
|
|
33
|
+
export const agentsMdContent = agentsMdFor("dev");
|
|
23
34
|
// Workspace index template (developer work records)
|
|
24
35
|
export const workspaceIndexContent = readLocalTemplate("workspace-index.md");
|
|
25
36
|
// Backwards compatibility alias
|
|
@@ -50,4 +61,6 @@ export const frontendDesignSystemContent = readLocalTemplate("spec/frontend/desi
|
|
|
50
61
|
export const guidesIndexContent = readLocalTemplate("spec/guides/index.md.txt");
|
|
51
62
|
export const guidesCrossLayerThinkingGuideContent = readLocalTemplate("spec/guides/cross-layer-thinking-guide.md.txt");
|
|
52
63
|
export const guidesCodeReuseThinkingGuideContent = readLocalTemplate("spec/guides/code-reuse-thinking-guide.md.txt");
|
|
64
|
+
// general 项目的约定位置:一个平铺的文件,不分包、不分层
|
|
65
|
+
export const conventionsContent = readLocalTemplate("spec/conventions.md.txt");
|
|
53
66
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3C,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,gFAAgF;AAChF,8BAA8B;AAC9B,gFAAgF;AAEhF,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/markdown/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3C,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,gFAAgF;AAChF,8BAA8B;AAC9B,gFAAgF;AAEhF,MAAM,gBAAgB,GAAW,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,IAAiB;IAC3C,OAAO,iBAAiB,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,0CAA0C;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAW,WAAW,CAAC,KAAK,CAAC,CAAC;AAE1D,oDAAoD;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAChC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;AAE1C,gCAAgC;AAChC,MAAM,CAAC,MAAM,yBAAyB,GAAG,qBAAqB,CAAC;AAE/D,2DAA2D;AAC3D,MAAM,CAAC,MAAM,wBAAwB,GACnC,iBAAiB,CAAC,eAAe,CAAC,CAAC;AAErC,gFAAgF;AAChF,0DAA0D;AAC1D,wEAAwE;AACxE,gFAAgF;AAEhF,uCAAuC;AACvC,MAAM,CAAC,MAAM,mBAAmB,GAAW,iBAAiB,CAC1D,2BAA2B,CAC5B,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,+BAA+B,GAAW,iBAAiB,CACtE,wCAAwC,CACzC,CAAC;AACF,MAAM,CAAC,MAAM,+BAA+B,GAAW,iBAAiB,CACtE,wCAAwC,CACzC,CAAC;AACF,MAAM,CAAC,MAAM,2BAA2B,GAAW,iBAAiB,CAClE,oCAAoC,CACrC,CAAC;AAEF,wCAAwC;AACxC,MAAM,CAAC,MAAM,oBAAoB,GAAW,iBAAiB,CAC3D,4BAA4B,CAC7B,CAAC;AACF,MAAM,CAAC,MAAM,iCAAiC,GAAW,iBAAiB,CACxE,0CAA0C,CAC3C,CAAC;AACF,MAAM,CAAC,MAAM,yBAAyB,GAAW,iBAAiB,CAChE,kCAAkC,CACnC,CAAC;AACF,MAAM,CAAC,MAAM,6BAA6B,GAAW,iBAAiB,CACpE,sCAAsC,CACvC,CAAC;AACF,MAAM,CAAC,MAAM,kCAAkC,GAAW,iBAAiB,CACzE,2CAA2C,CAC5C,CAAC;AACF,MAAM,CAAC,MAAM,gCAAgC,GAAW,iBAAiB,CACvE,yCAAyC,CAC1C,CAAC;AACF,MAAM,CAAC,MAAM,8BAA8B,GAAW,iBAAiB,CACrE,uCAAuC,CACxC,CAAC;AACF,MAAM,CAAC,MAAM,2BAA2B,GAAW,iBAAiB,CAClE,oCAAoC,CACrC,CAAC;AAEF,mBAAmB;AACnB,MAAM,CAAC,MAAM,kBAAkB,GAAW,iBAAiB,CACzD,0BAA0B,CAC3B,CAAC;AACF,MAAM,CAAC,MAAM,oCAAoC,GAAW,iBAAiB,CAC3E,+CAA+C,CAChD,CAAC;AACF,MAAM,CAAC,MAAM,mCAAmC,GAAW,iBAAiB,CAC1E,8CAA8C,CAC/C,CAAC;AAEF,kCAAkC;AAClC,MAAM,CAAC,MAAM,kBAAkB,GAAW,iBAAiB,CACzD,yBAAyB,CAC1B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# 约定 / Conventions
|
|
2
|
+
|
|
3
|
+
这个项目的使用者不止一次提过的要求:东西要怎么写、怎么起名、怎么排版、怎么检查,以及不想要什么。AI 每次开始对话都会先读这个文件,并照着做。
|
|
4
|
+
|
|
5
|
+
AI 自己也会往里记。你纠正了它,或者把某个要求又说了一遍,它就在这里记下一行,这样同样的话不用说第二遍。哪一条不再适用了,你可以自己改掉或删掉。
|
|
6
|
+
|
|
7
|
+
What the user of this project has asked for more than once: how they want things written, named, laid out or checked, and what they do not want. The AI reads this file at the start of every session and follows it.
|
|
8
|
+
|
|
9
|
+
The AI adds to it as well. When the user corrects it, or repeats a preference, it writes that down here as one short line, so nobody has to say it again. Edit or delete any line yourself once it stops being true.
|
|
10
|
+
|
|
11
|
+
## 说定的事 / What we agreed
|
|
12
|
+
|
|
13
|
+
(还没有。/ Nothing yet.)
|
|
@@ -144,6 +144,25 @@ function unquoteYaml(s) {
|
|
|
144
144
|
return s
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Whether the project is in `general` mode. Mirrors
|
|
149
|
+
* `common.config.get_project_mode()`: a top-level `mode:` key in
|
|
150
|
+
* .atw/config.yaml; a missing key or any other value is `dev`.
|
|
151
|
+
*/
|
|
152
|
+
export function isGeneralProject(directory) {
|
|
153
|
+
let text
|
|
154
|
+
try {
|
|
155
|
+
text = readFileSync(join(directory, ".atw", "config.yaml"), "utf-8")
|
|
156
|
+
} catch {
|
|
157
|
+
return false
|
|
158
|
+
}
|
|
159
|
+
for (const line of text.split(/\r?\n/)) {
|
|
160
|
+
const m = line.match(/^mode\s*:\s*(.*)$/)
|
|
161
|
+
if (m) return unquoteYaml(stripInlineComment(m[1]).trim()) === "general"
|
|
162
|
+
}
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
|
|
147
166
|
/**
|
|
148
167
|
* Line-based parser for ONLY the `context_injection:` block of
|
|
149
168
|
* `.atw/config.yaml`. Not a general YAML parser — mirrors
|
|
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from "fs"
|
|
|
3
3
|
import { join } from "path"
|
|
4
4
|
import { execFileSync } from "child_process"
|
|
5
5
|
import { platform } from "os"
|
|
6
|
-
import { debugLog } from "./atw-context.js"
|
|
6
|
+
import { debugLog, isGeneralProject } from "./atw-context.js"
|
|
7
7
|
|
|
8
8
|
const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
|
|
9
9
|
|
|
@@ -18,10 +18,22 @@ The acknowledgment must not alter the language used for the remainder of the res
|
|
|
18
18
|
This notice is one-shot: do not repeat it after the first visible assistant reply in this session.
|
|
19
19
|
</first-reply-notice>`
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Compact active-task status and next action. In a `general` project the AI
|
|
23
|
+
* decides on its own whether a request gets a task, so the no-task line defers
|
|
24
|
+
* to the workflow instead of telling it to ask first — keep the wording in step
|
|
25
|
+
* with `_get_task_status` in the shared session-start hook.
|
|
26
|
+
*/
|
|
27
|
+
function getTaskStatus(ctx, platformInput = null, general = false) {
|
|
22
28
|
const active = ctx.getActiveTask(platformInput)
|
|
23
29
|
const taskRef = active.taskPath
|
|
24
30
|
if (!taskRef) {
|
|
31
|
+
if (general) {
|
|
32
|
+
return (
|
|
33
|
+
"Status: NO ACTIVE TASK\n" +
|
|
34
|
+
"Next-Action: Do what <atw-workflow> above says for a session with no current task."
|
|
35
|
+
)
|
|
36
|
+
}
|
|
25
37
|
return (
|
|
26
38
|
"Status: NO ACTIVE TASK\n" +
|
|
27
39
|
"Next-Action: Classify the current turn before creating any ATW task. " +
|
|
@@ -50,6 +62,11 @@ function getTaskStatus(ctx, platformInput = null) {
|
|
|
50
62
|
const taskStatus = taskData.status || "unknown"
|
|
51
63
|
|
|
52
64
|
if (taskStatus === "completed") {
|
|
65
|
+
if (general) {
|
|
66
|
+
// A general task records no branch; without the switch the archive is
|
|
67
|
+
// refused in a repository that has a remote.
|
|
68
|
+
return `Status: COMPLETED\nTask: ${taskTitle}\nNext-Action: The archive was interrupted — re-run \`task.py archive <task> --skip-branch-validation\` to finish it.`
|
|
69
|
+
}
|
|
53
70
|
return `Status: COMPLETED\nTask: ${taskTitle}\nNext-Action: The archive was interrupted — re-run \`task.py archive <task>\` to finish it. If the working tree is dirty, commit or set the task back to \`implement\` first; there is no wrap-up commit step.`
|
|
54
71
|
}
|
|
55
72
|
|
|
@@ -253,11 +270,16 @@ function buildCompactCurrentState(ctx, platformInput, specIndexPaths) {
|
|
|
253
270
|
const lines = []
|
|
254
271
|
lines.push(`Developer: ${readDeveloper(directory)}`)
|
|
255
272
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
.
|
|
259
|
-
|
|
260
|
-
|
|
273
|
+
// 普通文件夹没有分支,也谈不上干净:照实说,不编一个状态出来。
|
|
274
|
+
if (runGit(directory, ["rev-parse", "--is-inside-work-tree"]) !== "true") {
|
|
275
|
+
lines.push("Git: not a git repository.")
|
|
276
|
+
} else {
|
|
277
|
+
const branch = runGit(directory, ["branch", "--show-current"]) || "(detached)"
|
|
278
|
+
const dirtyCount = runGit(directory, ["status", "--porcelain"])
|
|
279
|
+
.split(/\r?\n/)
|
|
280
|
+
.filter(line => line.trim()).length
|
|
281
|
+
lines.push(`Git: branch ${branch}; ${dirtyCount === 0 ? "clean" : `dirty ${dirtyCount} paths`}.`)
|
|
282
|
+
}
|
|
261
283
|
|
|
262
284
|
const active = ctx.getActiveTask(platformInput)
|
|
263
285
|
if (active.taskPath) {
|
|
@@ -312,6 +334,32 @@ function buildCompactCurrentState(ctx, platformInput, specIndexPaths) {
|
|
|
312
334
|
return lines.join("\n")
|
|
313
335
|
}
|
|
314
336
|
|
|
337
|
+
const CONVENTIONS_PATH = ".atw/spec/conventions.md"
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* The <conventions> block of a `general` project, else "". Mirrors
|
|
341
|
+
* conventions_context() in .atw/scripts/common/session_context.py — keep the two
|
|
342
|
+
* in step: a general project has one flat conventions file instead of
|
|
343
|
+
* per-package, per-layer guideline indexes, and always gets the block, so the
|
|
344
|
+
* AI knows where the first entry goes.
|
|
345
|
+
*/
|
|
346
|
+
function buildConventionsContext(directory) {
|
|
347
|
+
if (!isGeneralProject(directory)) return ""
|
|
348
|
+
const header =
|
|
349
|
+
`Source: ${CONVENTIONS_PATH} — what this project's user asked for more than ` +
|
|
350
|
+
"once. Follow it in every reply."
|
|
351
|
+
let body = ""
|
|
352
|
+
try {
|
|
353
|
+
body = readFileSync(join(directory, CONVENTIONS_PATH), "utf-8").trim()
|
|
354
|
+
} catch {
|
|
355
|
+
// Not written yet.
|
|
356
|
+
}
|
|
357
|
+
if (!body) {
|
|
358
|
+
return `<conventions>\n${header} Nothing is written there yet.\n</conventions>`
|
|
359
|
+
}
|
|
360
|
+
return `<conventions>\n${header}\n\n${body}\n</conventions>`
|
|
361
|
+
}
|
|
362
|
+
|
|
315
363
|
export function buildSessionContext(ctx, platformInput = null) {
|
|
316
364
|
const directory = ctx.directory
|
|
317
365
|
const contextKey = typeof ctx.getContextKey === "function"
|
|
@@ -320,7 +368,10 @@ export function buildSessionContext(ctx, platformInput = null) {
|
|
|
320
368
|
|
|
321
369
|
const config = loadAtwConfig(directory, contextKey)
|
|
322
370
|
const allowedPkgs = resolveSpecScope(config)
|
|
323
|
-
|
|
371
|
+
// A general project keeps no guideline indexes — whatever a switch from dev
|
|
372
|
+
// left under `.atw/spec/` is not offered there.
|
|
373
|
+
const conventions = buildConventionsContext(directory)
|
|
374
|
+
const paths = conventions ? [] : collectSpecIndexPaths(directory, allowedPkgs)
|
|
324
375
|
|
|
325
376
|
const parts = []
|
|
326
377
|
|
|
@@ -374,26 +425,30 @@ ATW compact SessionStart context. Use it to orient the session; load details on
|
|
|
374
425
|
parts.push("</atw-workflow>")
|
|
375
426
|
}
|
|
376
427
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
428
|
+
if (conventions) {
|
|
429
|
+
parts.push(conventions)
|
|
430
|
+
} else {
|
|
431
|
+
parts.push("<guidelines>")
|
|
432
|
+
parts.push(
|
|
433
|
+
"Task context order for implementation/check: jsonl entries -> `prd.md`.\n"
|
|
434
|
+
)
|
|
381
435
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
436
|
+
if (paths.length > 0) {
|
|
437
|
+
parts.push("## Available indexes (read on demand)")
|
|
438
|
+
for (const p of paths) {
|
|
439
|
+
parts.push(`- ${p}`)
|
|
440
|
+
}
|
|
441
|
+
parts.push("")
|
|
386
442
|
}
|
|
387
|
-
parts.push("")
|
|
388
|
-
}
|
|
389
443
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
444
|
+
parts.push(
|
|
445
|
+
"Discover more via: " +
|
|
446
|
+
"`python3 ./.atw/scripts/get_context.py --mode packages`"
|
|
447
|
+
)
|
|
448
|
+
parts.push("</guidelines>")
|
|
449
|
+
}
|
|
395
450
|
|
|
396
|
-
const taskStatus = getTaskStatus(ctx, platformInput)
|
|
451
|
+
const taskStatus = getTaskStatus(ctx, platformInput, Boolean(conventions))
|
|
397
452
|
parts.push(`<task-status>\n${taskStatus}\n</task-status>`)
|
|
398
453
|
|
|
399
454
|
parts.push(`<ready>
|
|
@@ -29,7 +29,12 @@ import {
|
|
|
29
29
|
platformInputFromMessages,
|
|
30
30
|
prependEphemeralText,
|
|
31
31
|
} from "../lib/context-visibility.js"
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
AtwContext,
|
|
34
|
+
debugLog,
|
|
35
|
+
isAtwSubagent,
|
|
36
|
+
isGeneralProject,
|
|
37
|
+
} from "../lib/atw-context.js"
|
|
33
38
|
|
|
34
39
|
// Supports STATUS values with letters, digits, underscores, hyphens
|
|
35
40
|
// (so "in-review" / "blocked-by-team" work alongside "task_error").
|
|
@@ -177,18 +182,23 @@ const NOOB_MODE_FALLBACK =
|
|
|
177
182
|
"language, and every term, command or path explained where it appears."
|
|
178
183
|
|
|
179
184
|
/**
|
|
180
|
-
* The <noob-mode> block
|
|
181
|
-
* Mirrors noob_mode_reminder() in
|
|
182
|
-
*
|
|
185
|
+
* The <noob-mode> block while noob mode is on for this developer, else "".
|
|
186
|
+
* Mirrors is_noob_mode_on() / noob_mode_reminder() in
|
|
187
|
+
* .atw/scripts/common/noob_mode.py — keep the two in step: a `noob_mode=on`
|
|
188
|
+
* or `noob_mode=off` line in the gitignored .atw/.developer is the
|
|
189
|
+
* developer's own choice and wins; without one the project mode decides
|
|
190
|
+
* (on for `general`, off for `dev`).
|
|
183
191
|
*/
|
|
184
192
|
function buildNoobModeReminder(directory, templates) {
|
|
185
|
-
let
|
|
193
|
+
let choice = null
|
|
186
194
|
try {
|
|
187
|
-
developer = readFileSync(join(directory, ".atw", ".developer"), "utf-8")
|
|
195
|
+
const developer = readFileSync(join(directory, ".atw", ".developer"), "utf-8")
|
|
196
|
+
const m = developer.match(/^noob_mode=(.*)$/m)
|
|
197
|
+
if (m) choice = m[1].trim() === "on"
|
|
188
198
|
} catch {
|
|
189
|
-
|
|
199
|
+
// No identity file: this developer never chose.
|
|
190
200
|
}
|
|
191
|
-
if (
|
|
201
|
+
if (!(choice ?? isGeneralProject(directory))) return ""
|
|
192
202
|
return `<noob-mode>\n${templates.noob_mode || NOOB_MODE_FALLBACK}\n</noob-mode>`
|
|
193
203
|
}
|
|
194
204
|
|
|
@@ -1249,18 +1249,24 @@ function buildStartupContext(
|
|
|
1249
1249
|
overview: string,
|
|
1250
1250
|
): string {
|
|
1251
1251
|
const workflow = workflowOverview(root, key);
|
|
1252
|
+
// get_context.py puts a <conventions> block in the overview only for a
|
|
1253
|
+
// `general` project. Its workflow has its own way to pick up unfinished
|
|
1254
|
+
// work; the bare `task.py start` below is one the script refuses there.
|
|
1255
|
+
const ready = overview.includes("\n<conventions>\n")
|
|
1256
|
+
? [
|
|
1257
|
+
"Do what <atw-workflow> above says for the current task's status. With no current task, it also says when to create one and how to pick up unfinished work.",
|
|
1258
|
+
]
|
|
1259
|
+
: [
|
|
1260
|
+
"Use the current workflow state to decide whether to create, continue, or skip an ATW task.",
|
|
1261
|
+
"When CURRENT TASK is (none) but ACTIVE TASKS lists exactly one task assigned to you that is already at the implement or accept stage, this window is merely not bound to it yet: run `python3 ./.atw/scripts/task.py start <task-dir>` for that task, then continue from its stage. Do not ask whether to create a new task in that case.",
|
|
1262
|
+
"If several tasks qualify, or the only candidate is still in a planning stage (discover / specify / slice), ask which task to bind instead of running start: start moves a planning-stage task straight into implement.",
|
|
1263
|
+
];
|
|
1252
1264
|
return [
|
|
1253
1265
|
"<session-context>\nATW compact SessionStart context. Use it to orient the session; load details on demand.\n</session-context>",
|
|
1254
1266
|
FIRST_REPLY_NOTICE,
|
|
1255
1267
|
overview,
|
|
1256
1268
|
workflow,
|
|
1257
|
-
[
|
|
1258
|
-
"<ready>",
|
|
1259
|
-
"Use the current workflow state to decide whether to create, continue, or skip an ATW task.",
|
|
1260
|
-
"When CURRENT TASK is (none) but ACTIVE TASKS lists exactly one task assigned to you that is already at the implement or accept stage, this window is merely not bound to it yet: run `python3 ./.atw/scripts/task.py start <task-dir>` for that task, then continue from its stage. Do not ask whether to create a new task in that case.",
|
|
1261
|
-
"If several tasks qualify, or the only candidate is still in a planning stage (discover / specify / slice), ask which task to bind instead of running start: start moves a planning-stage task straight into implement.",
|
|
1262
|
-
"</ready>",
|
|
1263
|
-
].join("\n"),
|
|
1269
|
+
["<ready>", ...ready, "</ready>"].join("\n"),
|
|
1264
1270
|
]
|
|
1265
1271
|
.filter(Boolean)
|
|
1266
1272
|
.join("\n\n");
|
|
@@ -1983,9 +1989,14 @@ export default function atwExtension(pi: {
|
|
|
1983
1989
|
// Events
|
|
1984
1990
|
pi.on?.("session_start", (event, ctx) => {
|
|
1985
1991
|
const k = getKey(event, ctx);
|
|
1986
|
-
|
|
1992
|
+
const root = resolveRoot(ctx);
|
|
1993
|
+
inheritSessionPointer(root, k, event);
|
|
1994
|
+
// A `general` project installs no /atw-continue prompt.
|
|
1995
|
+
const canContinue = exists(join(root, ".pi", "prompts", "atw-continue.md"));
|
|
1987
1996
|
ctx?.ui?.notify?.(
|
|
1988
|
-
|
|
1997
|
+
canContinue
|
|
1998
|
+
? "ATW project context is available. Use /atw-start to bootstrap or /atw-continue to resume."
|
|
1999
|
+
: "ATW project context is available. Use /atw-start to bootstrap.",
|
|
1989
2000
|
"info",
|
|
1990
2001
|
);
|
|
1991
2002
|
});
|