acstack 0.49.1 → 0.50.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/.claude-plugin/plugin.json +1 -1
- package/README.md +27 -35
- package/agents/codex/frontend-verifier.toml +8 -5
- package/agents/codex/task-checker.toml +43 -173
- package/agents/codex/task-executor.toml +18 -88
- package/agents/codex/test-writer.toml +18 -26
- package/agents/frontend-verifier.md +8 -5
- package/agents/task-checker.md +43 -173
- package/agents/task-executor.md +18 -88
- package/agents/test-writer.md +18 -26
- package/assets/terminal-workspace/lib/commands.sh +7 -0
- package/assets/terminal-workspace/lib/pi-packages.sh +29 -0
- package/assets/terminal-workspace/pi/acstack-question-blocked.ts +31 -0
- package/assets/terminal-workspace/setup.sh +1 -0
- package/cli/dist/index.js +0 -2
- package/cli/dist/index.js.map +2 -2
- package/cli/package.json +1 -1
- package/docs/config-reference.md +31 -50
- package/docs/terminal-workspace.md +10 -1
- package/docs/workflows.md +28 -66
- package/orchestrator/AGENTS.md +144 -271
- package/package.json +1 -1
- package/pi/agents/frontend-verifier.md +8 -5
- package/pi/agents/task-checker.md +43 -173
- package/pi/agents/task-executor.md +20 -88
- package/pi/agents/test-writer.md +18 -26
- package/skills/browser-verify/SKILL.md +2 -2
- package/skills/grilling/SKILL.md +9 -10
- package/skills/implement/SKILL.md +23 -90
- package/skills/implement/decision-log.md +1 -1
- package/skills/implement/design-pass.md +159 -21
- package/skills/map/SKILL.md +4 -7
- package/skills/pre-commit-review/SKILL.md +24 -24
- package/skills/pre-commit-review/auto-fix.md +1 -1
- package/skills/pre-commit-review/interactive.md +1 -1
- package/skills/quick-fix/SKILL.md +20 -22
- package/skills/setup/SKILL.md +2 -2
- package/skills/setup/first-run.md +3 -12
- package/skills/setup/report.md +5 -10
- package/skills/setup/row-fixes.md +3 -6
- package/skills/implement/relaxed-tdd.md +0 -28
package/agents/test-writer.md
CHANGED
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-writer
|
|
3
|
-
description:
|
|
3
|
+
description: Optional independent test author who derives assertions from requirements and interfaces, not implementation plans or current implementation answers.
|
|
4
4
|
model: opus
|
|
5
5
|
color: green
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Test writer
|
|
8
|
+
# Test writer
|
|
9
9
|
|
|
10
10
|
You write tests from requirements and application programming interface (API) contracts only. You do not receive implementation plans or architectural decisions. Your tests encode what should happen, not how the executor implements it.
|
|
11
11
|
|
|
12
12
|
## When you run
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
- Follow the shared Implementation discipline in `orchestrator/AGENTS.md`
|
|
15
|
+
- You run when independent requirements interpretation adds confidence or the user requests separate test ownership
|
|
16
|
+
- Read `test-conventions` before writing tests
|
|
17
|
+
- Derive expectations from requirements and existing interfaces, never implementation bodies
|
|
18
|
+
- Read signatures, exported types, route paths, and schemas only to learn how to call the subject
|
|
19
|
+
- Prefer intended failing-first evidence when practical
|
|
20
|
+
- If implementation already exists, leave it unread and report the available evidence honestly
|
|
21
|
+
- Report mismatches instead of reshaping assertions to fit the code
|
|
15
22
|
|
|
16
|
-
Under `true` you run first. No implementation exists yet, so every test you write must fail. Verify that before you report.
|
|
17
|
-
|
|
18
|
-
Under `false`, relaxed TDD, you run after the task-executor. The implementation already sits in the working tree.
|
|
19
|
-
|
|
20
|
-
Write your tests from the requirements and the existing interfaces. Do not read the implementation you are testing.
|
|
21
|
-
|
|
22
|
-
An interface here means a signature, an exported type, a route path or a schema. It never means a function body.
|
|
23
|
-
|
|
24
|
-
Reading a body to learn what the code does, then asserting that, writes a test that can only agree with the code. Your licence to read source is for calling the thing, never for learning what it decided.
|
|
25
|
-
|
|
26
|
-
Then verify the tests pass, because the code is already there.
|
|
27
|
-
|
|
28
|
-
A test that fails under `false` means the implementation is wrong. Report it. Never reshape the test to fit the code.
|
|
29
|
-
|
|
30
|
-
Requirements alone are a weaker guarantee than the strict order gives, where no implementation exists for you to read. That weakness is the cost of relaxed TDD, and your own discipline is the only thing that holds it down.
|
|
31
23
|
|
|
32
24
|
## Project configuration
|
|
33
25
|
|
|
@@ -68,9 +60,9 @@ A narrower test must still fail when the criterion is unmet. This is the floor,
|
|
|
68
60
|
|
|
69
61
|
A test that passes against any implementation is not narrower. It is absent, and it leaves the criterion untested.
|
|
70
62
|
|
|
71
|
-
`assert create_plan(...) is not None`
|
|
63
|
+
`assert create_plan(...) is not None` can pass for an incorrect result. A passing test alone does not establish useful coverage.
|
|
72
64
|
|
|
73
|
-
|
|
65
|
+
Check the floor yourself. Ask what an implementation would have to get wrong for this test to fail. If you cannot name that, the test is vacuous.
|
|
74
66
|
|
|
75
67
|
The quickest form of that check: would this test still pass if every function it imports returned `undefined`? If yes, it is vacuous. Five shapes fail it:
|
|
76
68
|
|
|
@@ -102,14 +94,15 @@ Assert only what the acceptance criteria state. A convention you found in a skil
|
|
|
102
94
|
|
|
103
95
|
## File path constraint
|
|
104
96
|
|
|
105
|
-
- Create or modify
|
|
106
|
-
-
|
|
97
|
+
- Create or modify only assigned test files, using project test placement conventions
|
|
98
|
+
- Confirm intended failures when testing first, then report passing results when implementation is available
|
|
107
99
|
- Use shared fixtures where they exist (e.g., conftest.py for pytest)
|
|
108
100
|
- Add new reusable fixtures to shared fixture files
|
|
109
101
|
|
|
110
102
|
## Test organization rules (critical)
|
|
111
103
|
|
|
112
|
-
|
|
104
|
+
Follow project conventions and `test-conventions` for test placement, including colocated frontend tests.
|
|
105
|
+
For mirrored backend tests, `{source}/services/foo.py` maps to `{tests}/services/test_foo.py`.
|
|
113
106
|
|
|
114
107
|
Rules:
|
|
115
108
|
|
|
@@ -124,7 +117,7 @@ Rules:
|
|
|
124
117
|
1. Read requirements and acceptance criteria
|
|
125
118
|
2. Discover existing interfaces using code search
|
|
126
119
|
3. Write the narrowest test each criterion permits, and confirm it would fail on a wrong implementation
|
|
127
|
-
4. Run the test command
|
|
120
|
+
4. Run the test command and report intended failures, passing checks, or behavior mismatches
|
|
128
121
|
5. Report: list of test files, test names, the expected result you verified, requirements coverage
|
|
129
122
|
|
|
130
123
|
## Test quality standards
|
|
@@ -142,7 +135,6 @@ When complete, report:
|
|
|
142
135
|
|
|
143
136
|
- List of test files created/modified
|
|
144
137
|
- Test names and what requirement each covers
|
|
145
|
-
-
|
|
146
|
-
- Which setting `workflow.tdd.strict` held, and so which order you ran in
|
|
138
|
+
- Commands and results, including available failing-first evidence and any tests-first departure
|
|
147
139
|
- Any criterion you could not test without picking an answer, and the question that settles it
|
|
148
140
|
- Any criterion you could not test for another reason, and what stopped you
|
|
@@ -58,6 +58,13 @@ acstack_tw_main() {
|
|
|
58
58
|
for id in "$PI_ACSTACK" $(version_table | awk -F'\t' '$2=="pi" && $3=="npm" && $1!="pi"{print $1}' | while read -r name; do pi_npm_package "$name"; done); do
|
|
59
59
|
src=$(pi_state pkg "$id") && say "pi package: $src" || say "pi package: $id not installed"
|
|
60
60
|
done
|
|
61
|
+
if [ -e "$PI_QUESTION_BRIDGE" ] || [ -L "$PI_QUESTION_BRIDGE" ]; then
|
|
62
|
+
pi_state owns file "$PI_QUESTION_BRIDGE" \
|
|
63
|
+
&& say "pi question blocked bridge: managed ($PI_QUESTION_BRIDGE)" \
|
|
64
|
+
|| say "pi question blocked bridge: user-owned path ($PI_QUESTION_BRIDGE)"
|
|
65
|
+
else
|
|
66
|
+
say "pi question blocked bridge: absent ($PI_QUESTION_BRIDGE)"
|
|
67
|
+
fi
|
|
61
68
|
[ -e "$PI_RETRO_EXT" ] && say "pi agentic-retro extension: present" \
|
|
62
69
|
|| say "pi agentic-retro extension: absent"
|
|
63
70
|
grep -qsF "$PI_MD_BEGIN" "$PI_DIR"/AGENTS.override.md "$PI_DIR"/AGENTS.md "$PI_DIR"/AGENTS.MD \
|
|
@@ -140,6 +140,32 @@ bili_client() { # bili_client install|remove <client>
|
|
|
140
140
|
fi
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
pi_question_bridge() { # pi_question_bridge install|remove
|
|
144
|
+
local fresh=0 rc
|
|
145
|
+
if [ "$1" = "install" ]; then
|
|
146
|
+
if { [ -e "$PI_QUESTION_BRIDGE" ] || [ -L "$PI_QUESTION_BRIDGE" ]; } \
|
|
147
|
+
&& ! pi_state owns file "$PI_QUESTION_BRIDGE"; then
|
|
148
|
+
say "pi: $PI_QUESTION_BRIDGE already exists, so the question bridge was left alone"
|
|
149
|
+
return 0
|
|
150
|
+
fi
|
|
151
|
+
[ -e "$PI_QUESTION_BRIDGE" ] || [ -L "$PI_QUESTION_BRIDGE" ] || fresh=1
|
|
152
|
+
mkdir -p "$(dirname "$PI_QUESTION_BRIDGE")" \
|
|
153
|
+
&& cp "$SCRIPT_DIR/pi/acstack-question-blocked.ts" "$PI_QUESTION_BRIDGE" || return $?
|
|
154
|
+
if pi_state own file "$PI_QUESTION_BRIDGE"; then
|
|
155
|
+
say "pi: question blocked bridge written to $PI_QUESTION_BRIDGE"
|
|
156
|
+
else
|
|
157
|
+
rc=$?
|
|
158
|
+
[ "$fresh" = 1 ] && rm -f "$PI_QUESTION_BRIDGE"
|
|
159
|
+
say "pi: question blocked bridge ownership registration failed for $PI_QUESTION_BRIDGE"
|
|
160
|
+
return "$rc"
|
|
161
|
+
fi
|
|
162
|
+
elif pi_state owns file "$PI_QUESTION_BRIDGE"; then
|
|
163
|
+
rm -f "$PI_QUESTION_BRIDGE" \
|
|
164
|
+
&& pi_state disown file "$PI_QUESTION_BRIDGE" \
|
|
165
|
+
&& say "pi: question blocked bridge removed"
|
|
166
|
+
fi
|
|
167
|
+
}
|
|
168
|
+
|
|
143
169
|
apply_pi() {
|
|
144
170
|
find_pi
|
|
145
171
|
if ! have pi; then
|
|
@@ -195,7 +221,9 @@ apply_pi() {
|
|
|
195
221
|
fi
|
|
196
222
|
if [ "$(cfg_get pi.question_tool true)" = "true" ]; then
|
|
197
223
|
pi_add npm:@juicesharp/rpiv-ask-user-question npm:@juicesharp/rpiv-ask-user-question
|
|
224
|
+
pi_question_bridge install
|
|
198
225
|
else
|
|
226
|
+
pi_question_bridge remove
|
|
199
227
|
pi_drop npm:@juicesharp/rpiv-ask-user-question
|
|
200
228
|
fi
|
|
201
229
|
if [ "$(cfg_get pi.web_access true)" = "true" ]; then
|
|
@@ -283,6 +311,7 @@ apply_pi() {
|
|
|
283
311
|
# and leaves the pi binary, its logins and its sessions alone.
|
|
284
312
|
remove_pi() {
|
|
285
313
|
find_pi
|
|
314
|
+
pi_question_bridge remove
|
|
286
315
|
if pi_state parses "$PI_SETTINGS"; then
|
|
287
316
|
pi_unpin "$PI_ACSTACK"
|
|
288
317
|
pi_drop "$PI_ACSTACK"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
export default function (pi: ExtensionAPI) {
|
|
4
|
+
let pending: { active: boolean; native: boolean } | undefined;
|
|
5
|
+
let forwarding = false;
|
|
6
|
+
|
|
7
|
+
pi.events.on("herdr:blocked", (event: unknown) => {
|
|
8
|
+
if (!forwarding && pending && (event as { active?: unknown } | null)?.active === pending.active) {
|
|
9
|
+
pending.native = true;
|
|
10
|
+
pending = undefined;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
pi.events.on("rpiv:ask-user:blocked", (event: unknown) => {
|
|
15
|
+
const active = (event as { active?: unknown } | null)?.active;
|
|
16
|
+
if (typeof active !== "boolean") return;
|
|
17
|
+
const transition = { active, native: false };
|
|
18
|
+
pending = transition;
|
|
19
|
+
// shortcut: dual producers emit public then herdr synchronously; async pairs need an upstream source ID
|
|
20
|
+
queueMicrotask(() => {
|
|
21
|
+
if (pending === transition) pending = undefined;
|
|
22
|
+
if (transition.native) return;
|
|
23
|
+
forwarding = true;
|
|
24
|
+
try {
|
|
25
|
+
pi.events.emit("herdr:blocked", { active });
|
|
26
|
+
} finally {
|
|
27
|
+
forwarding = false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -41,6 +41,7 @@ END="# <<< acstack terminal-workspace <<<"
|
|
|
41
41
|
PI_DIR="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
|
|
42
42
|
PI_SETTINGS="$PI_DIR/settings.json"
|
|
43
43
|
PI_KEYBINDINGS="$PI_DIR/keybindings.json"
|
|
44
|
+
PI_QUESTION_BRIDGE="$PI_DIR/extensions/acstack-question-blocked.ts"
|
|
44
45
|
PI_SUBAGENT_CFG="$PI_DIR/extensions/subagent/config.json"
|
|
45
46
|
# agentic-retro install-pi picks its own directory, from $PI_HOME rather than
|
|
46
47
|
# pi's override, so look where it writes.
|
package/cli/dist/index.js
CHANGED
|
@@ -12459,8 +12459,6 @@ var init_project_config = __esm({
|
|
|
12459
12459
|
PROJECT_KEY_DEFAULTS = {
|
|
12460
12460
|
"workflow.spec_sync": "true",
|
|
12461
12461
|
"workflow.grilling.questions": "tool",
|
|
12462
|
-
"workflow.tdd.strict": "true",
|
|
12463
|
-
"workflow.tdd.orchestrator_strict": "true",
|
|
12464
12462
|
[FRONTEND_VERIFICATION_KEY]: "false",
|
|
12465
12463
|
[DESIGN_REVIEW_KEY]: "false",
|
|
12466
12464
|
"workflow.maps.persist": "false",
|