@aperant/framework 0.13.0-next.0 → 0.15.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/CHANGELOG.md +89 -3
- package/README.md +11 -1
- package/agents/apt-pr-review-i18n.md +190 -0
- package/agents/apt-pr-review-xplatform.md +189 -0
- package/dist/cli/commands/audit-branch-current.d.mts +27 -5
- package/dist/cli/commands/audit-branch-current.d.mts.map +1 -1
- package/dist/cli/commands/audit-branch-current.mjs +3 -3
- package/dist/cli/commands/audit-branch-current.mjs.map +1 -1
- package/dist/cli/commands/event.d.mts.map +1 -1
- package/dist/cli/commands/event.mjs +6 -4
- package/dist/cli/commands/event.mjs.map +1 -1
- package/dist/cli/commands/fan-out.d.mts.map +1 -1
- package/dist/cli/commands/fan-out.mjs +3 -1
- package/dist/cli/commands/fan-out.mjs.map +1 -1
- package/dist/cli/commands/features-audit.d.mts.map +1 -1
- package/dist/cli/commands/features-audit.mjs +6 -1
- package/dist/cli/commands/features-audit.mjs.map +1 -1
- package/dist/cli/commands/followups.d.mts +5 -0
- package/dist/cli/commands/followups.d.mts.map +1 -0
- package/dist/cli/commands/followups.mjs +266 -0
- package/dist/cli/commands/followups.mjs.map +1 -0
- package/dist/cli/commands/health-check.d.mts.map +1 -1
- package/dist/cli/commands/health-check.mjs +3 -1
- package/dist/cli/commands/health-check.mjs.map +1 -1
- package/dist/cli/commands/merge-detect.d.mts +29 -0
- package/dist/cli/commands/merge-detect.d.mts.map +1 -0
- package/dist/cli/commands/merge-detect.mjs +196 -0
- package/dist/cli/commands/merge-detect.mjs.map +1 -0
- package/dist/cli/commands/merge-integrate.d.mts +28 -0
- package/dist/cli/commands/merge-integrate.d.mts.map +1 -0
- package/dist/cli/commands/merge-integrate.mjs +383 -0
- package/dist/cli/commands/merge-integrate.mjs.map +1 -0
- package/dist/cli/commands/pr-review/detect-specialists.d.mts +58 -0
- package/dist/cli/commands/pr-review/detect-specialists.d.mts.map +1 -0
- package/dist/cli/commands/pr-review/detect-specialists.mjs +980 -0
- package/dist/cli/commands/pr-review/detect-specialists.mjs.map +1 -0
- package/dist/cli/commands/pr-review.d.mts.map +1 -1
- package/dist/cli/commands/pr-review.mjs +11 -2
- package/dist/cli/commands/pr-review.mjs.map +1 -1
- package/dist/cli/commands/precompact-hook.d.mts.map +1 -1
- package/dist/cli/commands/precompact-hook.mjs +10 -6
- package/dist/cli/commands/precompact-hook.mjs.map +1 -1
- package/dist/cli/commands/roadmap.d.mts.map +1 -1
- package/dist/cli/commands/roadmap.mjs +24 -11
- package/dist/cli/commands/roadmap.mjs.map +1 -1
- package/dist/cli/commands/seed.d.mts.map +1 -1
- package/dist/cli/commands/seed.mjs +3 -1
- package/dist/cli/commands/seed.mjs.map +1 -1
- package/dist/cli/commands/state.d.mts.map +1 -1
- package/dist/cli/commands/state.mjs +9 -3
- package/dist/cli/commands/state.mjs.map +1 -1
- package/dist/cli/commands/statusline.d.mts.map +1 -1
- package/dist/cli/commands/statusline.mjs +5 -1
- package/dist/cli/commands/statusline.mjs.map +1 -1
- package/dist/cli/commands/task.d.mts.map +1 -1
- package/dist/cli/commands/task.mjs +126 -23
- package/dist/cli/commands/task.mjs.map +1 -1
- package/dist/cli/commands/worktree.d.mts +1 -1
- package/dist/cli/commands/worktree.d.mts.map +1 -1
- package/dist/cli/commands/worktree.mjs +282 -83
- package/dist/cli/commands/worktree.mjs.map +1 -1
- package/dist/cli/config/post-merge-sweep.d.mts.map +1 -1
- package/dist/cli/config/post-merge-sweep.mjs +3 -2
- package/dist/cli/config/post-merge-sweep.mjs.map +1 -1
- package/dist/cli/config/share-policy.d.mts +3 -1
- package/dist/cli/config/share-policy.d.mts.map +1 -1
- package/dist/cli/config/share-policy.mjs +16 -3
- package/dist/cli/config/share-policy.mjs.map +1 -1
- package/dist/cli/config/upgrade-gitignore.d.mts.map +1 -1
- package/dist/cli/config/upgrade-gitignore.mjs +27 -5
- package/dist/cli/config/upgrade-gitignore.mjs.map +1 -1
- package/dist/cli/consistency/parse-qa.mjs +12 -1
- package/dist/cli/consistency/parse-qa.mjs.map +1 -1
- package/dist/cli/consistency/parse-review.d.mts +23 -0
- package/dist/cli/consistency/parse-review.d.mts.map +1 -1
- package/dist/cli/consistency/parse-review.mjs +36 -0
- package/dist/cli/consistency/parse-review.mjs.map +1 -1
- package/dist/cli/consistency/parse-spec.d.mts +16 -0
- package/dist/cli/consistency/parse-spec.d.mts.map +1 -1
- package/dist/cli/consistency/parse-spec.mjs +44 -0
- package/dist/cli/consistency/parse-spec.mjs.map +1 -1
- package/dist/cli/coordination/agent-identity.d.mts +5 -2
- package/dist/cli/coordination/agent-identity.d.mts.map +1 -1
- package/dist/cli/coordination/agent-identity.mjs +6 -4
- package/dist/cli/coordination/agent-identity.mjs.map +1 -1
- package/dist/cli/coordination/store.d.mts +1 -1
- package/dist/cli/dispatch.d.mts.map +1 -1
- package/dist/cli/dispatch.mjs +4 -0
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/followups/derive.d.mts +63 -0
- package/dist/cli/followups/derive.d.mts.map +1 -0
- package/dist/cli/followups/derive.mjs +115 -0
- package/dist/cli/followups/derive.mjs.map +1 -0
- package/dist/cli/followups/schema.d.mts +165 -0
- package/dist/cli/followups/schema.d.mts.map +1 -0
- package/dist/cli/followups/schema.mjs +251 -0
- package/dist/cli/followups/schema.mjs.map +1 -0
- package/dist/cli/gate/context.d.mts +1 -1
- package/dist/cli/gate/gates/followups-adjudicated.d.mts +69 -0
- package/dist/cli/gate/gates/followups-adjudicated.d.mts.map +1 -0
- package/dist/cli/gate/gates/followups-adjudicated.mjs +141 -0
- package/dist/cli/gate/gates/followups-adjudicated.mjs.map +1 -0
- package/dist/cli/gate/gates/index.mjs +1 -0
- package/dist/cli/gate/gates/index.mjs.map +1 -1
- package/dist/cli/git/materialize-env.d.mts +39 -0
- package/dist/cli/git/materialize-env.d.mts.map +1 -0
- package/dist/cli/git/materialize-env.mjs +217 -0
- package/dist/cli/git/materialize-env.mjs.map +1 -0
- package/dist/cli/help.d.mts.map +1 -1
- package/dist/cli/help.mjs +9 -1
- package/dist/cli/help.mjs.map +1 -1
- package/dist/cli/install/legacy-paths.d.mts.map +1 -1
- package/dist/cli/install/legacy-paths.mjs +4 -0
- package/dist/cli/install/legacy-paths.mjs.map +1 -1
- package/dist/cli/roadmap/lifecycle.d.mts.map +1 -1
- package/dist/cli/roadmap/lifecycle.mjs +4 -1
- package/dist/cli/roadmap/lifecycle.mjs.map +1 -1
- package/dist/cli/task/ids.d.mts +9 -0
- package/dist/cli/task/ids.d.mts.map +1 -1
- package/dist/cli/task/ids.mjs +9 -0
- package/dist/cli/task/ids.mjs.map +1 -1
- package/dist/cli/task/index-md.d.mts +5 -0
- package/dist/cli/task/index-md.d.mts.map +1 -1
- package/dist/cli/task/index-md.mjs +12 -4
- package/dist/cli/task/index-md.mjs.map +1 -1
- package/dist/cli/util/io.d.mts +6 -0
- package/dist/cli/util/io.d.mts.map +1 -1
- package/dist/cli/util/io.mjs +16 -1
- package/dist/cli/util/io.mjs.map +1 -1
- package/dist/cli/util/project.d.mts +7 -2
- package/dist/cli/util/project.d.mts.map +1 -1
- package/dist/cli/util/project.mjs +11 -14
- package/dist/cli/util/project.mjs.map +1 -1
- package/dist/cli/util/state-paths.d.mts +19 -0
- package/dist/cli/util/state-paths.d.mts.map +1 -0
- package/dist/cli/util/state-paths.mjs +45 -0
- package/dist/cli/util/state-paths.mjs.map +1 -0
- package/dist/plugin/.claude-plugin/plugin.json +4 -1
- package/dist/plugin/agents/apt-pr-review-i18n.md +190 -0
- package/dist/plugin/agents/apt-pr-review-xplatform.md +189 -0
- package/dist/plugin/skills/apt/SKILL.md +13 -6
- package/dist/plugin/skills/apt-close-task/SKILL.md +48 -0
- package/dist/plugin/skills/apt-debug/SKILL.md +19 -9
- package/dist/plugin/skills/apt-execute/SKILL.md +3 -1
- package/dist/plugin/skills/apt-fan-out/SKILL.md +65 -1
- package/dist/plugin/skills/apt-merge-conflict-resolution/SKILL.md +227 -0
- package/dist/plugin/skills/apt-pr-review/SCHEMA.md +4 -2
- package/dist/plugin/skills/apt-pr-review/SKILL.md +117 -29
- package/dist/plugin/skills/apt-quick/SKILL.md +24 -1
- package/dist/plugin/skills/apt-review/SKILL.md +6 -0
- package/dist/plugin/skills/apt-run/SKILL.md +1 -1
- package/dist/plugin/skills/apt-setup/SKILL.md +21 -3
- package/dist/plugin/skills/apt-ship/SKILL.md +32 -11
- package/dist/plugin/skills/apt-terminal/SKILL.md +8 -0
- package/dist/plugin/skills/apt-triage/SKILL.md +4 -0
- package/dist/plugin/skills/apt-verify/SKILL.md +24 -0
- package/dist/plugin/skills/apt-watch-ci/SKILL.md +3 -1
- package/dist/types/config.d.ts +33 -0
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +138 -138
- package/prompts/conductor-framework-context.md +1 -1
- package/prompts/github/pr_i18n_agent.md +279 -0
- package/prompts/github/pr_xplatform_agent.md +283 -0
- package/prompts/inbox-clarification.md +18 -11
- package/skills/apt/SKILL.md +9 -3
- package/skills/apt-close-task/SKILL.md +48 -0
- package/skills/apt-debug/SKILL.md +19 -9
- package/skills/apt-execute/SKILL.md +3 -1
- package/skills/apt-fan-out/SKILL.md +65 -1
- package/skills/apt-merge-conflict-resolution/SKILL.md +227 -0
- package/skills/apt-pr-review/SCHEMA.md +4 -2
- package/skills/apt-pr-review/SKILL.md +117 -29
- package/skills/apt-quick/SKILL.md +24 -1
- package/skills/apt-review/SKILL.md +6 -0
- package/skills/apt-run/SKILL.md +1 -1
- package/skills/apt-setup/SKILL.md +21 -3
- package/skills/apt-ship/SKILL.md +32 -11
- package/skills/apt-terminal/SKILL.md +8 -0
- package/skills/apt-triage/SKILL.md +4 -0
- package/skills/apt-verify/SKILL.md +24 -0
- package/skills/apt-watch-ci/SKILL.md +3 -1
- package/src/cli/commands/audit-branch-current.mjs +3 -3
- package/src/cli/commands/event.mjs +6 -4
- package/src/cli/commands/fan-out.mjs +3 -1
- package/src/cli/commands/features-audit.mjs +6 -1
- package/src/cli/commands/followups.mjs +303 -0
- package/src/cli/commands/health-check.mjs +3 -1
- package/src/cli/commands/merge-detect.mjs +203 -0
- package/src/cli/commands/merge-integrate.mjs +392 -0
- package/src/cli/commands/pr-review/__fixtures__/android-strings/app/src/main/res/values-fr/strings.xml +3 -0
- package/src/cli/commands/pr-review/__fixtures__/babel-js/package.json +4 -0
- package/src/cli/commands/pr-review/__fixtures__/c-ifdef/src/main.c +4 -0
- package/src/cli/commands/pr-review/__fixtures__/ci-matrix/.github/workflows/ci.yml +10 -0
- package/src/cli/commands/pr-review/__fixtures__/cmake-win/CMakeLists.txt +5 -0
- package/src/cli/commands/pr-review/__fixtures__/diffs/add-arb.patch +9 -0
- package/src/cli/commands/pr-review/__fixtures__/diffs/ci-single-os-dep.patch +13 -0
- package/src/cli/commands/pr-review/__fixtures__/diffs/ci-single-os-list-item-dep.patch +17 -0
- package/src/cli/commands/pr-review/__fixtures__/diffs/lone-weak-t.patch +8 -0
- package/src/cli/commands/pr-review/__fixtures__/diffs/monorepo-b.patch +7 -0
- package/src/cli/commands/pr-review/__fixtures__/diffs/two-weak-xpl.patch +12 -0
- package/src/cli/commands/pr-review/__fixtures__/dropped-underscore/src/app.js +2 -0
- package/src/cli/commands/pr-review/__fixtures__/electron-app/package.json +4 -0
- package/src/cli/commands/pr-review/__fixtures__/i18n-locale-file/src/locales/fr.json +1 -0
- package/src/cli/commands/pr-review/__fixtures__/monorepo/packages/a/locales/fr.json +1 -0
- package/src/cli/commands/pr-review/__fixtures__/monorepo/packages/b/src/index.ts +1 -0
- package/src/cli/commands/pr-review/__fixtures__/py-babel/pyproject.toml +3 -0
- package/src/cli/commands/pr-review/__fixtures__/qt-i18n-dir/i18n/app_fr.ts +11 -0
- package/src/cli/commands/pr-review/__fixtures__/rust-cli/Cargo.toml +7 -0
- package/src/cli/commands/pr-review/__fixtures__/rust-cli/src/main.rs +1 -0
- package/src/cli/commands/pr-review/__fixtures__/ts-dir/ts/foo.ts +3 -0
- package/src/cli/commands/pr-review/detect-specialists.mjs +1023 -0
- package/src/cli/commands/pr-review.mjs +12 -2
- package/src/cli/commands/precompact-hook.mjs +10 -6
- package/src/cli/commands/roadmap.mjs +24 -11
- package/src/cli/commands/seed.mjs +3 -1
- package/src/cli/commands/state.mjs +9 -3
- package/src/cli/commands/statusline.mjs +5 -1
- package/src/cli/commands/task.mjs +135 -23
- package/src/cli/commands/worktree.mjs +298 -81
- package/src/cli/config/post-merge-sweep.mjs +3 -2
- package/src/cli/config/share-policy.mjs +16 -3
- package/src/cli/config/upgrade-gitignore.mjs +27 -5
- package/src/cli/consistency/parse-qa.mjs +11 -1
- package/src/cli/consistency/parse-review.mjs +36 -0
- package/src/cli/consistency/parse-spec.mjs +43 -0
- package/src/cli/coordination/agent-identity.mjs +6 -4
- package/src/cli/dispatch.mjs +4 -0
- package/src/cli/followups/derive.mjs +123 -0
- package/src/cli/followups/schema.mjs +264 -0
- package/src/cli/gate/gates/followups-adjudicated.mjs +158 -0
- package/src/cli/gate/gates/index.mjs +1 -0
- package/src/cli/git/materialize-env.mjs +212 -0
- package/src/cli/help.mjs +9 -1
- package/src/cli/install/legacy-paths.mjs +4 -0
- package/src/cli/roadmap/lifecycle.mjs +4 -1
- package/src/cli/task/ids.mjs +9 -0
- package/src/cli/task/index-md.mjs +12 -4
- package/src/cli/util/io.mjs +15 -1
- package/src/cli/util/project.mjs +11 -14
- package/src/cli/util/state-paths.mjs +45 -0
- package/prompts/followup_planner.md +0 -399
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Cross-Platform Review Agent
|
|
2
|
+
|
|
3
|
+
You are a focused cross-platform portability review agent. You have been spawned by the orchestrating agent — only because a deterministic detector found this project targets more than one OS/architecture (a multi-OS CI matrix, a cross-platform app framework, or platform-conditional build code) — to perform a deep portability audit of specific files.
|
|
4
|
+
|
|
5
|
+
## Your Mission
|
|
6
|
+
|
|
7
|
+
Perform a thorough cross-platform review of the provided code changes, focusing ONLY on portability defects. Do not review security, code quality, logic correctness, performance, or internationalization.
|
|
8
|
+
|
|
9
|
+
## Phase 1: Understand the PR Intent (BEFORE Looking for Issues)
|
|
10
|
+
|
|
11
|
+
**MANDATORY** - Before searching for issues, understand what this PR is trying to accomplish.
|
|
12
|
+
|
|
13
|
+
1. **Read the provided context**
|
|
14
|
+
- PR description: What does the author say this does?
|
|
15
|
+
- Changed files: What areas of code are affected?
|
|
16
|
+
- Commits: How did the PR evolve?
|
|
17
|
+
|
|
18
|
+
2. **Identify the change type**
|
|
19
|
+
- Bug fix: Correcting broken behavior
|
|
20
|
+
- New feature: Adding new capability
|
|
21
|
+
- Refactor: Restructuring without behavior change
|
|
22
|
+
- Performance: Optimizing existing code
|
|
23
|
+
- Cleanup: Removing dead code or improving organization
|
|
24
|
+
|
|
25
|
+
3. **State your understanding** (include in your analysis)
|
|
26
|
+
```
|
|
27
|
+
PR INTENT: This PR [verb] [what] by [how].
|
|
28
|
+
PORTABILITY RISK AREAS: [what could break on another supported OS/arch]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Only AFTER completing Phase 1, proceed to looking for issues.**
|
|
32
|
+
|
|
33
|
+
Why this matters: Understanding the project's target set prevents flagging unix-flavored code in a unix-only project.
|
|
34
|
+
|
|
35
|
+
## TRIGGER-DRIVEN EXPLORATION (CHECK YOUR DELEGATION PROMPT)
|
|
36
|
+
|
|
37
|
+
**FIRST**: Check if your delegation prompt contains a `TRIGGER:` instruction.
|
|
38
|
+
|
|
39
|
+
- **If TRIGGER is present** → Exploration is **MANDATORY**, even if the diff looks correct
|
|
40
|
+
- **If no TRIGGER** → Use your judgment to explore or not
|
|
41
|
+
|
|
42
|
+
### How to Explore (Bounded)
|
|
43
|
+
|
|
44
|
+
1. **Read the trigger** - What pattern did the orchestrator identify?
|
|
45
|
+
2. **Form the specific question** - "Does this new filesystem path use a portable join, or a hardcoded separator?"
|
|
46
|
+
3. **Use Grep** to find any existing platform guard / path-join helper / portable wrapper
|
|
47
|
+
4. **Use Read** to examine the relevant call sites and the CI/build config that proves the target set
|
|
48
|
+
5. **Answer the question** - Yes (report issue) or No (move on)
|
|
49
|
+
6. **Stop** - Do not explore beyond depth 1
|
|
50
|
+
|
|
51
|
+
### Cross-Platform-Specific Trigger Questions
|
|
52
|
+
|
|
53
|
+
| Trigger | Portability Question to Answer |
|
|
54
|
+
|---------|--------------------------------|
|
|
55
|
+
| **Side effect contract changed** | Is the new filesystem/shell/process behavior platform-specific without a guard? |
|
|
56
|
+
| **Input contract changed** | Does new path / byte-stream handling assume one OS (separators, line endings, endianness)? |
|
|
57
|
+
| **Behavioral contract changed** | Did path/line-ending formatting regress to a single-OS form? |
|
|
58
|
+
|
|
59
|
+
## CRITICAL: PR Scope and Context
|
|
60
|
+
|
|
61
|
+
### What IS in scope (report these issues):
|
|
62
|
+
1. **Portability assumptions in changed code** that break on another supported OS/arch
|
|
63
|
+
2. **Platform-specific behavior added without a guard** or a portable abstraction
|
|
64
|
+
3. **Broken portability assumptions** — a change that breaks an existing cross-platform contract
|
|
65
|
+
|
|
66
|
+
### What is NOT in scope (do NOT report):
|
|
67
|
+
1. **Pre-existing portability issues** in code this PR didn't touch
|
|
68
|
+
2. **Portability improvements to untouched code**
|
|
69
|
+
3. **Non-portability concerns** (security, logic, quality, performance, i18n)
|
|
70
|
+
4. **Unix-flavored code in a project that only ships on unix** (verify the target set first)
|
|
71
|
+
5. **A platform-specific code path that already sits behind a guard**
|
|
72
|
+
|
|
73
|
+
**Key distinction:**
|
|
74
|
+
- ✅ "Your new temp-file write hardcodes `/tmp`, which breaks on the Windows CI runner" - GOOD
|
|
75
|
+
- ✅ "This `exec('rm -rf')` has no Windows fallback and the project ships a Windows build" - GOOD
|
|
76
|
+
- ❌ "The old `unix_only_helper.sh` assumes bash" - BAD (pre-existing, not this PR)
|
|
77
|
+
|
|
78
|
+
## Cross-Platform Focus Areas
|
|
79
|
+
|
|
80
|
+
### 1. Path & Filesystem Assumptions
|
|
81
|
+
- Hardcoded path separators (`/` or `\`) instead of the platform path-join API
|
|
82
|
+
- Hardcoded absolute paths (`/tmp`, `/usr/...`, `C:\...`) instead of a portable temp/home resolver
|
|
83
|
+
- Case-sensitive-vs-insensitive FS assumptions (two files differing only by case; a lookup that assumes case folding)
|
|
84
|
+
- Line-ending assumptions (`\n` vs `\r\n`) in file read/write or string-split logic
|
|
85
|
+
|
|
86
|
+
### 2. Platform-Specific APIs & Syscalls
|
|
87
|
+
- A platform-only API/syscall used without a `process.platform` / `#[cfg(target_os)]` / `#ifdef` guard
|
|
88
|
+
- Shell/exec portability: invoking `sh`/`bash`/`cmd` directly, relying on a unix-only binary, shell-builtin assumptions
|
|
89
|
+
- Environment-variable assumptions that differ by OS (`HOME` vs `USERPROFILE`, `PATH` separator `:` vs `;`)
|
|
90
|
+
|
|
91
|
+
### 3. Architecture & Endianness
|
|
92
|
+
- Byte-order (endianness) assumptions in binary read/write or buffer parsing
|
|
93
|
+
- Word-size / pointer-size assumptions; integer-width assumptions in serialization
|
|
94
|
+
- Architecture-specific code paths added without a guard
|
|
95
|
+
|
|
96
|
+
### 4. Build & Native Portability
|
|
97
|
+
- A native module / FFI / build step that only works on one OS without a fallback or guard
|
|
98
|
+
- Platform-conditional build config (CMake/Gradle/cargo cfg) added for one OS but missing the others the project supports
|
|
99
|
+
- A new dependency that is platform-locked in a project that ships on multiple OSes
|
|
100
|
+
|
|
101
|
+
## Review Guidelines
|
|
102
|
+
|
|
103
|
+
### High Confidence Only
|
|
104
|
+
- Only report findings with **>80% confidence**
|
|
105
|
+
- If you're unsure, don't report it
|
|
106
|
+
- Prefer false negatives over false positives
|
|
107
|
+
|
|
108
|
+
### Verify Before Claiming "Will Break On X"
|
|
109
|
+
|
|
110
|
+
When your finding claims code breaks on a specific OS/arch:
|
|
111
|
+
|
|
112
|
+
**Ask yourself**: "Have I confirmed that OS/arch is actually a target, and that no guard already handles this?"
|
|
113
|
+
|
|
114
|
+
- Confirm that OS/arch is actually a target (CI matrix, cross-platform framework, build config)
|
|
115
|
+
- Read the complete code path; check whether a guard or portable helper already handles it elsewhere
|
|
116
|
+
- Search for related patterns: `platform`, `os.`, `cfg(`, `ifdef`, `sep`, `path.join`, `EOL`
|
|
117
|
+
|
|
118
|
+
**Your evidence must prove the break — not just that the code looks unix-flavored.**
|
|
119
|
+
|
|
120
|
+
❌ **Weak**: "This path will break on Windows"
|
|
121
|
+
✅ **Strong**: "The CI matrix includes windows-latest. This `'/tmp/' + name` at line 30 hardcodes a unix path with no `os.tmpdir()` / `path.join` and no platform guard."
|
|
122
|
+
|
|
123
|
+
### Severity Classification (All block merge except LOW)
|
|
124
|
+
- **CRITICAL** (Blocker): A change that breaks the build or crashes at runtime on a supported OS/arch
|
|
125
|
+
- Example: a native build step that only works on macOS while the project ships Windows
|
|
126
|
+
- **Blocks merge: YES**
|
|
127
|
+
- **HIGH** (Required): A platform assumption that produces wrong behavior on a supported target
|
|
128
|
+
- Example: hardcoded `/tmp` path; a unix-only syscall with no guard
|
|
129
|
+
- **Blocks merge: YES**
|
|
130
|
+
- **MEDIUM** (Recommended): A portability weakness with limited blast radius
|
|
131
|
+
- Example: line-ending split assuming `\n`; `PATH`-separator assumption
|
|
132
|
+
- **Blocks merge: YES**
|
|
133
|
+
- **LOW** (Suggestion): Best-practice violation, minimal risk on the actual target set
|
|
134
|
+
- Example: `left`/`right` string literal in a comment
|
|
135
|
+
- **Blocks merge: NO** (optional polish)
|
|
136
|
+
|
|
137
|
+
<!-- SYNC: This section is shared. See partials/full_context_analysis.md for canonical version -->
|
|
138
|
+
## CRITICAL: Full Context Analysis
|
|
139
|
+
|
|
140
|
+
Before reporting ANY finding, you MUST:
|
|
141
|
+
|
|
142
|
+
1. **USE the Read tool** to examine the actual code at the finding location
|
|
143
|
+
- Never report based on diff alone
|
|
144
|
+
- Get ±20 lines of context around the flagged line
|
|
145
|
+
- Verify the line number actually exists in the file
|
|
146
|
+
|
|
147
|
+
2. **Verify the issue exists** - Not assume it does
|
|
148
|
+
- Is the path/syscall actually unguarded, or is there a `process.platform` / `#ifdef` nearby?
|
|
149
|
+
- Is the OS you claim it breaks on actually a target?
|
|
150
|
+
- Does the framework provide a portable abstraction here?
|
|
151
|
+
|
|
152
|
+
3. **Provide code evidence** - Copy-paste the actual code
|
|
153
|
+
- Your `code_examined` field must contain real non-portable code from the file
|
|
154
|
+
|
|
155
|
+
4. **Check for mitigations** - Use Grep to search for:
|
|
156
|
+
- An existing platform guard / path-join helper / portable wrapper
|
|
157
|
+
- The CI matrix / build config that proves the target set
|
|
158
|
+
|
|
159
|
+
**Your evidence must prove the issue exists - not just that you suspect it.**
|
|
160
|
+
|
|
161
|
+
## Evidence Requirements (MANDATORY)
|
|
162
|
+
|
|
163
|
+
Every finding you report MUST include a `verification` object with ALL of these fields:
|
|
164
|
+
|
|
165
|
+
### Required Fields
|
|
166
|
+
|
|
167
|
+
**code_examined** (string, min 1 character)
|
|
168
|
+
The **exact code snippet** you examined. Copy-paste directly from the file:
|
|
169
|
+
```
|
|
170
|
+
CORRECT: "const tmp = '/tmp/' + name;"
|
|
171
|
+
WRONG: "a hardcoded temp path"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**line_range_examined** (array of 2 integers)
|
|
175
|
+
The exact line numbers [start, end] where the issue exists:
|
|
176
|
+
```
|
|
177
|
+
CORRECT: [30, 30]
|
|
178
|
+
WRONG: [1, 100] // Too broad - you didn't examine all 100 lines
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**verification_method** (one of these exact values)
|
|
182
|
+
- `"direct_code_inspection"` - Found the issue directly in the code at the location
|
|
183
|
+
- `"cross_file_trace"` - Traced through callers / the CI/build config to confirm
|
|
184
|
+
- `"test_verification"` - Verified through examination of test code
|
|
185
|
+
- `"dependency_analysis"` - Verified through analyzing dependencies
|
|
186
|
+
|
|
187
|
+
### Conditional Fields
|
|
188
|
+
|
|
189
|
+
**is_impact_finding** (boolean, default false)
|
|
190
|
+
Set to `true` ONLY if this finding is about impact on OTHER files (not the changed file).
|
|
191
|
+
|
|
192
|
+
**checked_for_handling_elsewhere** (boolean, default false)
|
|
193
|
+
For ANY "no guard" / "non-portable" claim:
|
|
194
|
+
- Set `true` ONLY if you used Grep/Read to verify no guard/abstraction handles it
|
|
195
|
+
- **When true, include the search in your description:**
|
|
196
|
+
- "Grep'd for `process.platform|os.tmpdir|path.join` near line 30 - none; `/tmp` is used directly"
|
|
197
|
+
- "Read `.github/workflows/ci.yml` - matrix includes windows-latest, so this unix path is a real break"
|
|
198
|
+
|
|
199
|
+
**If you cannot provide real evidence, you do not have a verified finding - do not report it.**
|
|
200
|
+
|
|
201
|
+
**Search Before Claiming Absence:** Never claim a guard is "missing" without searching for it first.
|
|
202
|
+
|
|
203
|
+
## Valid Outputs
|
|
204
|
+
|
|
205
|
+
Finding issues is NOT the goal. Accurate review is the goal.
|
|
206
|
+
|
|
207
|
+
### Valid: No Significant Issues Found
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"findings": [],
|
|
211
|
+
"summary": "Reviewed [files]. No cross-platform issues found. Filesystem paths use path.join and platform-specific code sits behind process.platform guards consistent with the project's OS matrix."
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### INVALID: Forced Issues
|
|
216
|
+
Do NOT report issues just to have something to say:
|
|
217
|
+
- Unix-flavored code flagged in a project that only ships on unix (verify the target set first)
|
|
218
|
+
- A platform path that already sits behind a guard
|
|
219
|
+
- Theoretical endianness concerns with no binary I/O in the diff
|
|
220
|
+
- Pre-existing portability issues not introduced by this PR
|
|
221
|
+
|
|
222
|
+
**Reporting nothing is better than reporting noise.** False positives erode trust faster than false negatives.
|
|
223
|
+
|
|
224
|
+
## Code Patterns to Flag
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
// HIGH: Hardcoded unix temp path (CI matrix includes windows)
|
|
228
|
+
const tmp = '/tmp/' + name; // use os.tmpdir() + path.join
|
|
229
|
+
|
|
230
|
+
// HIGH: Hardcoded path separator
|
|
231
|
+
const p = dir + '/' + file; // use path.join(dir, file)
|
|
232
|
+
|
|
233
|
+
// HIGH: Unix-only shell with no guard / fallback
|
|
234
|
+
exec('rm -rf ' + dir); // use fs.rm; no Windows fallback
|
|
235
|
+
|
|
236
|
+
// MEDIUM: Line-ending assumption
|
|
237
|
+
const lines = text.split('\n'); // breaks on \r\n input
|
|
238
|
+
|
|
239
|
+
// MEDIUM: Env-var assumption
|
|
240
|
+
const home = process.env.HOME; // undefined on Windows (USERPROFILE)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```rust
|
|
244
|
+
// HIGH: Platform-only code path added without a cfg guard
|
|
245
|
+
// (the crate's CI matrix builds windows + macos + linux)
|
|
246
|
+
std::os::unix::fs::symlink(a, b)?; // no #[cfg(unix)]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Output Format
|
|
250
|
+
|
|
251
|
+
Provide findings in JSON format:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
[
|
|
255
|
+
{
|
|
256
|
+
"file": "src/cache.ts",
|
|
257
|
+
"line": 30,
|
|
258
|
+
"title": "Hardcoded /tmp path breaks the Windows CI runner",
|
|
259
|
+
"description": "The cache file path hardcodes '/tmp/'. The project's CI matrix (.github/workflows/ci.yml) includes windows-latest, where /tmp does not exist, so the cache write will fail on Windows.",
|
|
260
|
+
"category": "quality",
|
|
261
|
+
"severity": "high",
|
|
262
|
+
"verification": {
|
|
263
|
+
"code_examined": "const tmp = '/tmp/' + name;",
|
|
264
|
+
"line_range_examined": [30, 30],
|
|
265
|
+
"verification_method": "cross_file_trace"
|
|
266
|
+
},
|
|
267
|
+
"is_impact_finding": false,
|
|
268
|
+
"checked_for_handling_elsewhere": true,
|
|
269
|
+
"suggested_fix": "Use a portable temp path: const tmp = path.join(os.tmpdir(), name);",
|
|
270
|
+
"confidence": 90
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Important Notes
|
|
276
|
+
|
|
277
|
+
1. **Be Specific**: Include exact file path and line number
|
|
278
|
+
2. **Explain Impact**: Describe the break ("build fails on Windows CI", "crashes on macOS arm64")
|
|
279
|
+
3. **Provide Fix**: Give an actionable suggested_fix (use path.join, add a platform guard, use the portable API)
|
|
280
|
+
4. **Check Context**: Confirm the target set before flagging; don't flag guarded code or test fixtures
|
|
281
|
+
5. **Focus on NEW Code**: Prioritize reviewing additions over deletions
|
|
282
|
+
|
|
283
|
+
Focus on **cross-platform portability defects** only. High confidence, high impact findings.
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
Run one read-only clarification turn using Work Record context, prior
|
|
2
|
-
Return semantic readiness updates
|
|
1
|
+
Run one read-only clarification turn using Work Record context, the prior conversation history, and the latest user reply.
|
|
2
|
+
Return semantic readiness updates plus a conversational reply, without mutating project files or external systems.
|
|
3
3
|
|
|
4
|
-
You are the Aperant clarification agent.
|
|
4
|
+
You are the Aperant clarification agent: a collaborative senior engineer helping the user make this work item ready for planning. You are a partner working the problem with them, not a form collecting fields.
|
|
5
5
|
First call readPhaseOutput with phase="triage" to inspect the triage output.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
Read the full messageHistory before composing your reply. The latest user reply arrives in submittedResponses; messageHistory is everything before it. Never re-ask something the user already answered, and acknowledge what they already told you.
|
|
7
|
+
Respond to what the user actually said FIRST. If they asked you a question, answer it directly. If they asked for your opinion or a recommendation (for example "what do you think?"), give ONE concrete recommendation grounded in the triage evidence and the repository, then ask them to confirm or correct it.
|
|
8
|
+
Propose-then-confirm: when the user explicitly confirms a proposal you made, treat the confirmed content as their answer and emit the slot patches with source:'user_answer' and groundedness:'grounded'.
|
|
9
|
+
When the user delegates a decision to you (for example "you decide" or "whatever you think is best"), choose a sensible value, fill the slot with source:'agent_assume' and groundedness:'tentative', and STATE the assumption plainly in nextChatMessage so the user can veto it.
|
|
10
|
+
Classify the intent of each user reply in consumedResponses[].mode: 'answer' when it supplies information, 'not_applicable' when the user says the question does not apply, 'agent_assume' when they delegate the decision to you, 'unknown' when they say they cannot answer.
|
|
11
|
+
Weave AT MOST ONE primary ask into each reply, placed after you have responded to the user. A purely conversational reply with no new ask is allowed when answering the user is the right move this turn.
|
|
12
|
+
If the user goes off on a tangent, answer briefly and politely steer back to the highest-impact open readiness gap.
|
|
13
|
+
nextChatMessage.text is YOUR reply shown in the chat. Make it specific to this work item and this conversation; never emit a generic template. Set nextChatMessage.dimensionKey to the readiness dimension your primary ask targets (when there is one), and nextChatMessage.cardId to the matching open clarification card when one exists.
|
|
14
|
+
When messageHistory is empty (the opening turn), nextChatMessage is your opener: say in one sentence what you understood from triage, then ask the single highest-impact question.
|
|
15
|
+
When status="ready", you may still populate nextChatMessage with a short close-out, including a one-line statement of any assumptions you made; omit it only when there is genuinely nothing left to say.
|
|
16
|
+
Keep nextClarificationQuestions as the ordered list of remaining open questions (one per open dimension); it tracks what is left to resolve and is not shown directly in the chat.
|
|
11
17
|
If the user's prior answer did not raise the targeted dimension's readinessAssessment score above its scoreThreshold, the next question MUST target the same dimensionKey with a sharper or more concrete follow-up. Otherwise, advance to a different open dimension.
|
|
12
18
|
Target the gating dimension whose acceptance-criteria slots are still open; do not jump to a dimension whose slots are already grounded.
|
|
19
|
+
Do not re-grill the same dimension more than three turns.
|
|
13
20
|
Emit proposedAcceptanceCriteriaUpdates as field-level patches ({ acIndex, fieldPath, value, source, groundedness }) that fill the targeted acceptance-criteria slots from the user's answer; fieldPath is one of statement, given, when, thenOutcome, verificationMethod.
|
|
14
21
|
Mark a slot patch groundedness:'tentative' when you are filling it from a vague answer or your own assumption, and groundedness:'grounded' only when the user's answer concretely specifies the field.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Use repository tools only when needed to sharpen
|
|
22
|
+
When the user's reply means a question does not apply, do not write a value for that slot; when they delegate the decision, fill the slot with source:'agent_assume'. Otherwise use source:'user_answer'.
|
|
23
|
+
If triage is already specific and high-confidence and every slot is grounded, set status="ready".
|
|
24
|
+
Use repository tools only when needed to ground a recommendation or sharpen a question.
|
package/skills/apt/SKILL.md
CHANGED
|
@@ -481,9 +481,15 @@ Print `[APT] Tokens: {input}+{output} = {total} (task cumulative)` using the
|
|
|
481
481
|
tally output. Skip silently if tokens tally errors — never block the
|
|
482
482
|
pipeline on telemetry.
|
|
483
483
|
|
|
484
|
-
**If `spawn_agent` is false (QUICK):**
|
|
485
|
-
|
|
486
|
-
|
|
484
|
+
**If `spawn_agent` is false (QUICK or DEBUG):**
|
|
485
|
+
Both QUICK and DEBUG resolve here (single-shot, no spawned phase agent). Invoke
|
|
486
|
+
the picked skill (`apt:quick` for QUICK, `apt:debug` for DEBUG, per
|
|
487
|
+
`primary_skill`) directly with `task_id`, `task_dir`, AND `worktree_path` in its
|
|
488
|
+
skill context — Step 2 already created the worktree + printed the banner for this
|
|
489
|
+
track, so thread `worktree_path` the same way the `spawn_agent: true` branch
|
|
490
|
+
threads it into the planner. No phase marker — QUICK and DEBUG are both
|
|
491
|
+
single-shot here. (If Step 2 returned no `worktree` block, pass `worktree_path` as
|
|
492
|
+
"none" and the skill proceeds in the project root.)
|
|
487
493
|
|
|
488
494
|
### Step 4: Chain Pipeline (based on selected option)
|
|
489
495
|
|
|
@@ -17,6 +17,8 @@ execution_modes:
|
|
|
17
17
|
allowed-tools: "Bash, Read, Grep, Glob, Write"
|
|
18
18
|
argument-hint: "apt:close-task [--all | --task <id>] [--narrate-only]"
|
|
19
19
|
gates: []
|
|
20
|
+
config_keys:
|
|
21
|
+
- followups.after_close
|
|
20
22
|
---
|
|
21
23
|
<objective>
|
|
22
24
|
Confirm a shipped PR has merged on GitHub, then run the closer side of the task lifecycle: flip `lifecycle_phase` from `shipped-pending-merge` to `completed`, strip stale per-PR overrides from `.aperant/config.json`, clean up worktree per policy, and emit `task.closed.merged` events for the audit trail. This is the post-merge counterpart to `/apt:ship`.
|
|
@@ -54,6 +56,50 @@ Run `apt-tools task close-merged . --all --dry-run` first to see what would happ
|
|
|
54
56
|
|
|
55
57
|
If `--task <id>` is passed, narrow to that task.
|
|
56
58
|
|
|
59
|
+
## 1.5 Disposition follow-ups (autonomy-aware — G45)
|
|
60
|
+
|
|
61
|
+
Run this BEFORE §2. The `task close` path that §2 invokes carries a CLI-level disposition gate (G45): it refuses to close while `{task_dir}/followups.json` has any open row, or any `dispositioned` row missing a valid `disposition.kind` + `ref`. Disposition every open row here so §2 closes cleanly without `--force`.
|
|
62
|
+
|
|
63
|
+
For each candidate the dry-run says `close`, read the effective policy:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
node packages/framework/bin/apt-tools.mjs followups policy . --task-id <id>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The envelope returns `{ after_close: 'ask' | 'file' | 'chain', max_chain_depth, source }`. `after_close` derives from `config.followups.after_close` when set, else from the task autonomy level (≤1 `ask` / 2 `file` / 3 `chain`). Then enumerate the open rows from `{task_dir}/followups.json` and route each by class + policy:
|
|
70
|
+
|
|
71
|
+
**`ask` (autonomy ≤ 1).** Present each open row to the user with its `class_proposed`, `adjudication.verdict`, and `files`. Offer fix / file / drop:
|
|
72
|
+
- fix → execute the change in this session (only if it is genuinely small + safe), commit, flip the row `status: 'fixed'`, optionally record `executed_commit`.
|
|
73
|
+
- file → the `new-task` flow below.
|
|
74
|
+
- drop → `apt-tools followups disposition . --task-id <id> --row <row-id> --kind dropped_by_user --ref <reason-slug> --reason "<text>"`.
|
|
75
|
+
|
|
76
|
+
**`file` (autonomy 2).** Auto-file every `new-task` row through the EXISTING triage machine (report, do NOT execute):
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# 1) create the task seeded from the row
|
|
80
|
+
node packages/framework/bin/apt-tools.mjs task create . --description "<row title>" --scope <scope> [...linkage]
|
|
81
|
+
# 2) enter it at needs-triage; the configured task_tracking.backend mirrors it
|
|
82
|
+
# (github-issues creates/updates a real labeled issue idempotently)
|
|
83
|
+
node packages/framework/bin/apt-tools.mjs triage init . --id <new-task-id>
|
|
84
|
+
# 3) record the disposition (ref = the filed task id; the triage mirror carries the issue URL)
|
|
85
|
+
node packages/framework/bin/apt-tools.mjs followups disposition . --task-id <id> --row <row-id> --kind filed_task --ref <new-task-id>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
There is **NO new `gh issue create` logic** — filing goes through `task create` + `triage init`, and the backend mirror does the GitHub work (ID-08). This works with the local-only default (no `task_tracking` key) AND with `github-issues` when configured; never hard-require gh.
|
|
89
|
+
|
|
90
|
+
**`polish` rows** (any policy) → park in the committable Deferred Ideas section (ID-09): append `- {title} -- deferred because {reason}` under `## Deferred Ideas` in `context/notes/{task-id}.md` (create the section/file if absent), then `apt-tools followups disposition . --task-id <id> --row <row-id> --kind parked_note --ref .aperant/context/notes/{task-id}.md`. Polish rows must NOT linger in the ledger — the ledger is ephemeral.
|
|
91
|
+
|
|
92
|
+
**`chain` (autonomy 3).** Do the `file` flow, THEN auto-chain depth-1 ONLY the filed tasks that triage to `ready-for-agent` (run the chained task through the full pipeline gates). Pass the depth marker on the chained task so the next-level policy degrades `chain → file`:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
node packages/framework/bin/apt-tools.mjs triage init . --id <new-task-id> \
|
|
96
|
+
--extra '{"followups_chain": {"origin_task": "<id>", "depth": 1}}'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`ready-for-human` items stop there by design — they are filed + reported, never auto-executed. `max_chain_depth` is clamped to 1 in v1 (anti-perpetual-motion); `followups policy` already degrades `chain → file` when the current task's `triage.json` carries `extra.followups_chain.depth >= max_chain_depth`.
|
|
100
|
+
|
|
101
|
+
After this step, every open row carries a durable disposition, so §2's `task close` clears the gate.
|
|
102
|
+
|
|
57
103
|
## 2. Confirm merge
|
|
58
104
|
|
|
59
105
|
For each candidate the dry-run says `close`:
|
|
@@ -124,6 +170,8 @@ close-merged emits an envelope with:
|
|
|
124
170
|
|
|
125
171
|
Report the summary verbatim. If anything landed in `skipped[]` with a recoverable reason (`offline`, `rate_limited`), suggest the user re-run once the network clears.
|
|
126
172
|
|
|
173
|
+
**Follow-ups-gate recovery (G45).** The passive post-merge sweep (and any bare `task close-merged` that skips §1.5) inherits the CLI close gate: a merged task whose `followups.json` still has open/undispositioned rows fails its spawned `task close` and lands in `errors[]` with a `task-close-failed` reason — the task STAYS in `shipped-pending-merge`. This is the designed backstop, not a bug. Recover by running `/apt:close-task --task <id>` (which runs §1.5 first to disposition every open row), then the close clears the gate. As a last resort, `apt-tools task close . --id <id> --force --reason "<text>"` bypasses the gate with an audited `task.close.followups-override` event.
|
|
174
|
+
|
|
127
175
|
**Local cleanup recap (best-effort).** On confirmed merge, `task close-merged` runs `computeWorktreeCleanup` against the primary repo (`packages/framework/src/cli/task/worktree-cleanup.mjs:140-230`): `git fetch origin <base>` (failure → recorded as `fetch_failed` warning, cleanup proceeds), `git checkout <base>` (failure → returns `action: 'checkout_failed'` and preserves BOTH the worktree and the task branch — nothing is removed), `git merge --ff-only origin/<base>` (failure → `ff_only_failed` warning, GC still runs), `git worktree remove <wtPath>`, and `git branch -d <taskBranch>` (failure on squash/rebase merges → `branch_delete_failed` warning, `branch_deleted: false` in the envelope; user can `git branch -D` manually). This is why `/apt:watch-ci` auto-merge MUST NOT pass `gh pr merge --delete-branch` — that flag would try to do the same work from inside the worktree where `git switch <base>` cannot succeed (see FRAMEWORK-BUG-019).
|
|
128
176
|
|
|
129
177
|
## 4. Narrate-only mode
|
|
@@ -42,6 +42,7 @@ reproduction, so loading this appendix is non-trivial.
|
|
|
42
42
|
- **apt-tools path:** `node packages/framework/bin/apt-tools.mjs` or the locally installed `apt-tools` binary
|
|
43
43
|
- **Constitution:** Read `AGENTS.md` in the project root if it exists
|
|
44
44
|
- **Debug sessions:** `.aperant/debug/{session-id}/DEBUG.md`
|
|
45
|
+
- **Task-level worktree isolation:** A worktree is provisioned at session start by `task create` (track-agnostic — DEBUG gets one too; parsed + banner-announced in §1a) when `task_isolation.worktree_per_task` is enabled. Read-only investigation (Sections 2-3 Observe / Hypothesize — `git log`, `git diff`, Grep, Read) may run from EITHER cwd; they only read. But once code changes begin — Section 4 (Checkpoint), Section 5b (Execute Test — the minimal change), Section 6b (Implement Fix + commit) — run those Bash commands with `cd {worktree_path} &&` so the fix + checkpoint commits land on the worktree's task branch. Use the `worktree_path` the router passed in skill context or that §1a parsed from `task create`'s envelope. `apt-tools` calls always take the project root as `<project-dir>`. If no `worktree` block was returned, proceed in the project root as before.
|
|
45
46
|
</your_environment>
|
|
46
47
|
|
|
47
48
|
<state_files>
|
|
@@ -98,6 +99,15 @@ Sequence:
|
|
|
98
99
|
|
|
99
100
|
The debug working dir at `.aperant/debug/{session-id}/` stays — that working artifact is preserved (per spec §3 R7). The canonical task record at `.aperant/tasks/{task-id}/` is created in parallel by `task create`, and both share the same id.
|
|
100
101
|
|
|
102
|
+
**Worktree isolation (both paths).** `task create` provisions a worktree when `task_isolation.worktree_per_task` is enabled (track-agnostic — DEBUG gets one too). Parse `worktree.worktree_path`, `worktree.branch`, and `worktree.base_branch` from the `task create` envelope (direct path); on the router path the orchestrator already passed `worktree_path` into your skill context — use that. When a `worktree` block is present, print the banner:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
[APT] Working in isolated worktree: {worktree_path}
|
|
106
|
+
[APT] Task branch: {branch} (from {base_branch})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Investigation (Sections 2-3) may run from either cwd — but once you reach the fix-applying phases (Section 4 Checkpoint, Section 5b Execute Test, Section 6b Implement Fix), prefix those Bash commands with `cd {worktree_path} &&` so commits land on the task branch. If no `worktree` block is returned, proceed in the project root as before.
|
|
110
|
+
|
|
101
111
|
### 1b. Create debug working directory
|
|
102
112
|
|
|
103
113
|
```bash
|
|
@@ -202,11 +212,11 @@ Update DEBUG.md:
|
|
|
202
212
|
|
|
203
213
|
## 4. Checkpoint — Save State Before Changes
|
|
204
214
|
|
|
205
|
-
Before making any code changes, create a git checkpoint:
|
|
215
|
+
Before making any code changes, create a git checkpoint. From here on, code-change Bash commands run in the task worktree when one was provisioned — prefix them with `cd {worktree_path} &&` (omit the prefix if no `worktree` block was returned in §1a):
|
|
206
216
|
|
|
207
217
|
```bash
|
|
208
|
-
git stash push -m "debug-checkpoint-{session-id}-pre-test" || true
|
|
209
|
-
git rev-parse HEAD > .aperant/debug/{session-id}/checkpoints/pre-test.ref
|
|
218
|
+
cd {worktree_path} && git stash push -m "debug-checkpoint-{session-id}-pre-test" || true
|
|
219
|
+
cd {worktree_path} && git rev-parse HEAD > .aperant/debug/{session-id}/checkpoints/pre-test.ref
|
|
210
220
|
```
|
|
211
221
|
|
|
212
222
|
Record the checkpoint in DEBUG.md:
|
|
@@ -215,9 +225,9 @@ Record the checkpoint in DEBUG.md:
|
|
|
215
225
|
- {timestamp} — pre-test: {commit-sha} (before testing hypotheses)
|
|
216
226
|
```
|
|
217
227
|
|
|
218
|
-
If a hypothesis test fails badly, revert to checkpoint:
|
|
228
|
+
If a hypothesis test fails badly, revert to checkpoint (in the worktree):
|
|
219
229
|
```bash
|
|
220
|
-
git checkout $(cat .aperant/debug/{session-id}/checkpoints/pre-test.ref) -- .
|
|
230
|
+
cd {worktree_path} && git checkout $(cat .aperant/debug/{session-id}/checkpoints/pre-test.ref) -- .
|
|
221
231
|
```
|
|
222
232
|
|
|
223
233
|
## 5. Test — Validate Hypotheses
|
|
@@ -229,7 +239,7 @@ For each hypothesis (starting with most likely):
|
|
|
229
239
|
- What is the expected outcome if the hypothesis is correct?
|
|
230
240
|
|
|
231
241
|
### 5b. Execute Test
|
|
232
|
-
- Make the minimal change needed to test the hypothesis
|
|
242
|
+
- Make the minimal change needed to test the hypothesis — apply it in the task worktree (edit files under `{worktree_path}` and run any verification command with `cd {worktree_path} &&`) when a `worktree` block was provisioned in §1a; otherwise edit in the project root.
|
|
233
243
|
- Run the relevant command/test
|
|
234
244
|
- Record the actual outcome
|
|
235
245
|
|
|
@@ -283,12 +293,12 @@ Document the root cause clearly:
|
|
|
283
293
|
```
|
|
284
294
|
|
|
285
295
|
### 6b. Implement Fix
|
|
286
|
-
- Apply the minimal fix that addresses the root cause
|
|
296
|
+
- Apply the minimal fix that addresses the root cause — in the task worktree (edit files under `{worktree_path}`) when one was provisioned in §1a, so the commit lands on the task branch.
|
|
287
297
|
- Run verification (tests, typecheck, lint)
|
|
288
|
-
- If verification passes, commit:
|
|
298
|
+
- If verification passes, commit (prefix with `cd {worktree_path} &&` when a worktree was provisioned so `git` stages + commits on the worktree's task branch; `apt-tools commit` takes no `<project-dir>` and operates on the current cwd):
|
|
289
299
|
|
|
290
300
|
```bash
|
|
291
|
-
node packages/framework/bin/apt-tools.mjs commit "fix: {concise description of fix}" --files {changed-files}
|
|
301
|
+
cd {worktree_path} && node packages/framework/bin/apt-tools.mjs commit "fix: {concise description of fix}" --files {changed-files}
|
|
292
302
|
```
|
|
293
303
|
|
|
294
304
|
### 6c. Update Status
|
|
@@ -555,10 +555,12 @@ Read `state.active_tasks[<task-id>].install_status`. Branch on the value:
|
|
|
555
555
|
```
|
|
556
556
|
Do NOT let the failure surface as a downstream "command not found" — the executor's job here is to make the install failure legible. The caller can re-run the task after fixing the install (or invoke with `--no-bootstrap` to skip the install entirely).
|
|
557
557
|
|
|
558
|
+
> **State resolves to the main repo from any cwd (state-fork-fix).** You no longer need to pass the main project root to keep the board coherent: ephemeral `.aperant/` state — `state.json`, `tasks/<id>/` (spec/plan/build-progress), locks, events — resolves to the **one main-repo board** even when `apt-tools` is invoked with `.` from a worktree cwd. The board never forks. (Committable `roadmap/` + `features/` stay worktree-local so they ride the PR branch.) `worktree create --task` likewise anchors at main from any cwd — invoking the **task-mode** create from inside a worktree retargets to the main repo instead of erroring. The **subtask-mode** worktree path below keeps its nested-worktree skip (back-compat only).
|
|
559
|
+
|
|
558
560
|
**2b. Continue with the existing worktree-mode logic:**
|
|
559
561
|
- Run `node packages/framework/bin/apt-tools.mjs detect-worktree .` — if `is_worktree: true`:
|
|
560
562
|
- Log: "Skipping worktree isolation (already in worktree)"
|
|
561
|
-
- Do NOT create worktrees (
|
|
563
|
+
- Do NOT create SUBTASK-mode worktrees from here (the legacy subtask-mode path refuses nesting; task-mode `worktree create --task` is safe — it anchors at main)
|
|
562
564
|
- Agents execute in the current working directory directly
|
|
563
565
|
- Note: locks still coordinate correctly (apt-tools uses shared lock dir via git common dir)
|
|
564
566
|
- If `use_worktrees` is `true` AND `is_worktree` is `false` AND no task-level `worktree_path` is present: set `WORKTREE_MODE=true`
|
|
@@ -85,6 +85,15 @@ node packages/framework/bin/apt-tools.mjs worktree create --task ${task_id}
|
|
|
85
85
|
|
|
86
86
|
(Skip if `state.active_tasks[task_id].worktree_path` is already set — the create command is idempotent.)
|
|
87
87
|
|
|
88
|
+
`worktree create` also materializes the project's stored env blobs (the
|
|
89
|
+
per-project encrypted env store, #354) into the fresh worktree as a best-effort,
|
|
90
|
+
traversal-guarded step — so each fan-out worker's checkout has the real `.env*`
|
|
91
|
+
files instead of crashing in no-cloud mode. The result is surfaced on the
|
|
92
|
+
envelope as `env_materialized` (null when no env is stored). For a long-lived
|
|
93
|
+
worktree whose stored env later drifted, re-copy on demand with
|
|
94
|
+
`node packages/framework/bin/apt-tools.mjs worktree sync-env <dir> --task ${task_id}`
|
|
95
|
+
(the store is the source of truth — sync-env overwrites, never merges).
|
|
96
|
+
|
|
88
97
|
## 3. Spawn N apt-executor subagents
|
|
89
98
|
|
|
90
99
|
Read the `parallelization.max_tasks` cap from `.aperant/config.json` (or default 4). Slice `task_ids` into batches of size `min(cap, task_ids.length)`. For each task in the current batch, dispatch via the host CLI's `Task` tool with `run_in_background: true`:
|
|
@@ -129,7 +138,62 @@ Churned for {Xm Ys} · {K} local agents still running
|
|
|
129
138
|
|
|
130
139
|
The first panel uses `┌─ ... │` (top-with-stem); the LAST panel uses `└─ ... ` (bottom corner). Footer line: "Churned" = elapsed since the most recent lifecycle event across all in-flight workers; "K local agents still running" = count of workers whose `lifecycle_phase` is non-terminal AND `assigned_to` is non-null.
|
|
131
140
|
|
|
132
|
-
## 5.
|
|
141
|
+
## 5. Integration phase — serialize N PRs against the moving base (opt-in)
|
|
142
|
+
|
|
143
|
+
The N workers each opened an independent PR against the same base. Nothing
|
|
144
|
+
ordered or reconciled them — two same-milestone tasks touching overlapping code
|
|
145
|
+
are otherwise only reconciled when a human merges each PR. This phase closes
|
|
146
|
+
that gap. It is **opt-in** via `pipeline.resolve_merge_conflicts` (default
|
|
147
|
+
false) in `.aperant/config.json`; when disabled, skip straight to §6 and let
|
|
148
|
+
the human serialize the PRs (today's report-only behavior — byte-unchanged).
|
|
149
|
+
|
|
150
|
+
When enabled, after all workers reach a terminal state, run the
|
|
151
|
+
`apt-tools merge integrate` command — it resolves the batch's task → branch/PR
|
|
152
|
+
set, computes a **merge order** (topological when `depends_on` edges exist
|
|
153
|
+
among the batch tasks, else a stable alphabetical task-id order), and probes
|
|
154
|
+
each PR's mergeability against the current base via the same `git merge-tree`
|
|
155
|
+
detection `apt:merge-conflict-resolution` uses. It is **read-only** — it never
|
|
156
|
+
merges, rebases, or auto-pushes; it ORDERS and PROBES, you RESOLVE.
|
|
157
|
+
|
|
158
|
+
First fetch the latest base tips so the probes are against the moving base, then
|
|
159
|
+
call `integrate` with the batch's task list (or `--batch ${batch_id}` to recover
|
|
160
|
+
it from the worker rows):
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
git -C "$conductor_root" fetch origin "$base_branch"
|
|
164
|
+
node packages/framework/bin/apt-tools.mjs merge integrate . --tasks ${task_ids_csv}
|
|
165
|
+
# OR recover the task list from the batch's worker rows:
|
|
166
|
+
node packages/framework/bin/apt-tools.mjs merge integrate . --batch ${batch_id}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Returns a structured integration report:
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"status": "ok",
|
|
173
|
+
"command": "merge-integrate",
|
|
174
|
+
"order_strategy": "topological",
|
|
175
|
+
"order": ["task-a", "task-b"],
|
|
176
|
+
"summary": { "total": 2, "mergeable": 1, "conflicted": 1, "needs_human": 0 },
|
|
177
|
+
"tasks": [
|
|
178
|
+
{ "task_id": "task-a", "status": "mergeable", "action": "advance", "mergeable": true },
|
|
179
|
+
{ "task_id": "task-b", "status": "conflicted", "action": "resolve-conflict",
|
|
180
|
+
"conflicts_preview": ["src/x.ts"],
|
|
181
|
+
"resolution": { "skill": "apt:merge-conflict-resolution", "worktree_path": "…", "base": "origin/main" } }
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Walk the `tasks` array **in `order`** (the command already serialized it):
|
|
187
|
+
|
|
188
|
+
1. **`status: "mergeable"`** (`action: "advance"`) → no inter-PR conflict introduced by the branches ordered before it. Nothing to do; continue.
|
|
189
|
+
2. **`status: "conflicted"`** (`action: "resolve-conflict"`) → an earlier-ordered branch conflicts with this one. Hand off to **`/apt:merge-conflict-resolution`** using the entry's `resolution` block (`worktree_path` + `base`); it resolves the markers inline and re-probes. On its non-convergence STOP, leave that branch for the human and note it in the §6 report — do **not** block the remaining branches. After it converges, re-run `merge integrate` to re-probe the rest against the now-updated base.
|
|
190
|
+
3. **`status: "needs-human"` / `"skipped"` / `"unknown"`** → not integrable by the agent (no `pr_url`, missing worktree, or probe-failed). Carry the `reason` into the §6 report and move on.
|
|
191
|
+
|
|
192
|
+
The resolved branches still flow through PR → review → CI — this phase never
|
|
193
|
+
auto-merges. It only ensures each PR is mergeable against the base the prior
|
|
194
|
+
PRs established, so the human's final merge is conflict-free.
|
|
195
|
+
|
|
196
|
+
## 6. Report
|
|
133
197
|
|
|
134
198
|
When all workers reach a terminal state, render the rail one final time. For each shipped worker (lifecycle `shipped-pending-merge` + `pr_url` set), collapse that panel to the SHIPPED variant:
|
|
135
199
|
|