@aperant/framework 0.8.7 → 0.10.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 +142 -0
- package/agents/apt-pr-review-fixer.md +9 -4
- package/agents/apt-verifier.md +6 -3
- package/dist/cli/commands/init.d.mts.map +1 -1
- package/dist/cli/commands/init.mjs +157 -23
- package/dist/cli/commands/init.mjs.map +1 -1
- package/dist/cli/commands/toolchain-detect.d.mts.map +1 -1
- package/dist/cli/commands/toolchain-detect.mjs +44 -0
- package/dist/cli/commands/toolchain-detect.mjs.map +1 -1
- package/dist/cli/commands/triage.d.mts.map +1 -1
- package/dist/cli/commands/triage.mjs +346 -13
- package/dist/cli/commands/triage.mjs.map +1 -1
- package/dist/cli/commands/uninstall.d.mts.map +1 -1
- package/dist/cli/commands/uninstall.mjs +11 -8
- package/dist/cli/commands/uninstall.mjs.map +1 -1
- package/dist/cli/consistency/parse-review.mjs +5 -3
- package/dist/cli/consistency/parse-review.mjs.map +1 -1
- package/dist/cli/consistency/rules/r5-verdict-consistency.d.mts.map +1 -1
- package/dist/cli/consistency/rules/r5-verdict-consistency.mjs +10 -8
- package/dist/cli/consistency/rules/r5-verdict-consistency.mjs.map +1 -1
- package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
- package/dist/cli/gate/gates/review-clean.mjs +4 -2
- package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
- package/dist/cli/install/mcp-provision.d.mts +26 -0
- package/dist/cli/install/mcp-provision.d.mts.map +1 -0
- package/dist/cli/install/mcp-provision.mjs +281 -0
- package/dist/cli/install/mcp-provision.mjs.map +1 -0
- package/dist/cli/install/mcp-server-specs.d.mts +80 -0
- package/dist/cli/install/mcp-server-specs.d.mts.map +1 -0
- package/dist/cli/install/mcp-server-specs.mjs +102 -0
- package/dist/cli/install/mcp-server-specs.mjs.map +1 -0
- package/dist/cli/install/runtime-detect.d.mts +27 -0
- package/dist/cli/install/runtime-detect.d.mts.map +1 -1
- package/dist/cli/install/runtime-detect.mjs +32 -0
- package/dist/cli/install/runtime-detect.mjs.map +1 -1
- package/dist/cli/install/toml-merge.d.mts +40 -0
- package/dist/cli/install/toml-merge.d.mts.map +1 -0
- package/dist/cli/install/toml-merge.mjs +134 -0
- package/dist/cli/install/toml-merge.mjs.map +1 -0
- package/dist/cli/util/aperant-section.d.mts +12 -0
- package/dist/cli/util/aperant-section.d.mts.map +1 -1
- package/dist/cli/util/aperant-section.mjs +12 -0
- package/dist/cli/util/aperant-section.mjs.map +1 -1
- package/dist/cli/util/copy.d.mts +27 -0
- package/dist/cli/util/copy.d.mts.map +1 -1
- package/dist/cli/util/copy.mjs +49 -5
- package/dist/cli/util/copy.mjs.map +1 -1
- package/dist/cli/util/events-path.d.mts +8 -0
- package/dist/cli/util/events-path.d.mts.map +1 -0
- package/dist/cli/util/events-path.mjs +23 -0
- package/dist/cli/util/events-path.mjs.map +1 -0
- package/dist/cli/util/runtime-capabilities.d.mts +30 -0
- package/dist/cli/util/runtime-capabilities.d.mts.map +1 -0
- package/dist/cli/util/runtime-capabilities.mjs +214 -0
- package/dist/cli/util/runtime-capabilities.mjs.map +1 -0
- package/dist/cli/verify-proof/audit.d.mts +2 -7
- package/dist/cli/verify-proof/audit.d.mts.map +1 -1
- package/dist/cli/verify-proof/audit.mjs +11 -17
- package/dist/cli/verify-proof/audit.mjs.map +1 -1
- package/dist/cli/verify-proof/idl/index.d.mts +12 -1
- package/dist/cli/verify-proof/idl/index.d.mts.map +1 -1
- package/dist/cli/verify-proof/idl/index.mjs +50 -1
- package/dist/cli/verify-proof/idl/index.mjs.map +1 -1
- package/dist/cli/verify-proof/resolver.d.mts.map +1 -1
- package/dist/cli/verify-proof/resolver.mjs +51 -1
- package/dist/cli/verify-proof/resolver.mjs.map +1 -1
- package/dist/cli/verify-proof/runtime-detect.d.mts +2 -29
- package/dist/cli/verify-proof/runtime-detect.d.mts.map +1 -1
- package/dist/cli/verify-proof/runtime-detect.mjs +8 -203
- package/dist/cli/verify-proof/runtime-detect.mjs.map +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/agents/apt-pr-review-fixer.md +9 -4
- package/dist/plugin/agents/apt-verifier.md +6 -3
- package/dist/plugin/skills/apt-pr-review/SKILL.md +106 -15
- package/dist/plugin/skills/apt-setup/SKILL.md +7 -6
- package/dist/plugin/skills/apt-triage/SKILL.md +8 -6
- package/dist/plugin/skills/apt-update/SKILL.md +1 -1
- package/dist/plugin/skills/apt-verify/SKILL.md +1 -1
- package/dist/plugin/skills/apt-verify-proof/SKILL.md +25 -1
- package/drivers/browser/skill/agent-browser/SKILL.md +51 -0
- package/drivers/tauri/README.md +107 -0
- package/drivers/tauri/driver.mjs +88 -0
- package/drivers/tauri/manifest.json +37 -0
- package/drivers/tauri/scripts/tauri-mcp.sh +41 -0
- package/package.json +1 -1
- package/skills/apt-pr-review/SKILL.md +106 -15
- package/skills/apt-setup/SKILL.md +7 -6
- package/skills/apt-triage/SKILL.md +8 -6
- package/skills/apt-update/SKILL.md +1 -1
- package/skills/apt-verify/SKILL.md +1 -1
- package/skills/apt-verify-proof/SKILL.md +25 -1
- package/src/cli/commands/init.mjs +163 -19
- package/src/cli/commands/toolchain-detect.mjs +44 -0
- package/src/cli/commands/triage.mjs +352 -11
- package/src/cli/commands/uninstall.mjs +11 -8
- package/src/cli/consistency/parse-review.mjs +5 -3
- package/src/cli/consistency/rules/r5-verdict-consistency.mjs +14 -9
- package/src/cli/gate/gates/review-clean.mjs +4 -2
- package/src/cli/install/mcp-provision.mjs +293 -0
- package/src/cli/install/mcp-server-specs.mjs +101 -0
- package/src/cli/install/runtime-detect.mjs +36 -0
- package/src/cli/install/toml-merge.mjs +139 -0
- package/src/cli/util/aperant-section.mjs +14 -0
- package/src/cli/util/copy.mjs +53 -8
- package/src/cli/util/events-path.mjs +24 -0
- package/src/cli/util/runtime-capabilities.mjs +216 -0
- package/src/cli/verify-proof/audit.mjs +11 -17
- package/src/cli/verify-proof/idl/index.mjs +49 -11
- package/src/cli/verify-proof/resolver.mjs +49 -2
- package/src/cli/verify-proof/runtime-detect.mjs +11 -204
- package/templates/config.json +2 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-browser
|
|
3
|
+
description: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.
|
|
4
|
+
allowed-tools: Bash(agent-browser:*), Bash(npx agent-browser:*)
|
|
5
|
+
hidden: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# agent-browser
|
|
9
|
+
|
|
10
|
+
Fast browser automation CLI for AI agents. Chrome/Chromium via CDP with
|
|
11
|
+
accessibility-tree snapshots and compact `@eN` element refs.
|
|
12
|
+
|
|
13
|
+
Install: `npm i -g agent-browser && agent-browser install`
|
|
14
|
+
|
|
15
|
+
## Start here
|
|
16
|
+
|
|
17
|
+
This file is a discovery stub, not the usage guide. Before running any
|
|
18
|
+
`agent-browser` command, load the actual workflow content from the CLI:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
agent-browser skills get core # start here — workflows, common patterns, troubleshooting
|
|
22
|
+
agent-browser skills get core --full # include full command reference and templates
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The CLI serves skill content that always matches the installed version,
|
|
26
|
+
so instructions never go stale. The content in this stub cannot change
|
|
27
|
+
between releases, which is why it just points at `skills get core`.
|
|
28
|
+
|
|
29
|
+
## Specialized skills
|
|
30
|
+
|
|
31
|
+
Load a specialized skill when the task falls outside browser web pages:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
agent-browser skills get electron # Electron desktop apps (VS Code, Slack, Discord, Figma, ...)
|
|
35
|
+
agent-browser skills get slack # Slack workspace automation
|
|
36
|
+
agent-browser skills get dogfood # Exploratory testing / QA / bug hunts
|
|
37
|
+
agent-browser skills get vercel-sandbox # agent-browser inside Vercel Sandbox microVMs
|
|
38
|
+
agent-browser skills get agentcore # AWS Bedrock AgentCore cloud browsers
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Run `agent-browser skills list` to see everything available on the
|
|
42
|
+
installed version.
|
|
43
|
+
|
|
44
|
+
## Why agent-browser
|
|
45
|
+
|
|
46
|
+
- Fast native Rust CLI, not a Node.js wrapper
|
|
47
|
+
- Works with any AI agent (Cursor, Claude Code, Codex, Continue, Windsurf, etc.)
|
|
48
|
+
- Chrome/Chromium via CDP with no Playwright or Puppeteer dependency
|
|
49
|
+
- Accessibility-tree snapshots with element refs for reliable interaction
|
|
50
|
+
- Sessions, authentication vault, state persistence, video recording
|
|
51
|
+
- Specialized skills for Electron apps, Slack, exploratory testing, cloud providers
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Tauri Driver
|
|
2
|
+
|
|
3
|
+
Bundled, first-party verify-proof driver for [Tauri](https://tauri.app)
|
|
4
|
+
desktop applications. The most common non-Electron desktop framework.
|
|
5
|
+
|
|
6
|
+
## When Aperant picks this driver
|
|
7
|
+
|
|
8
|
+
`/apt:verify-proof` auto-selects `tauri` when:
|
|
9
|
+
|
|
10
|
+
- The project's `package.json` declares `@tauri-apps/api` (or `tauri`) as
|
|
11
|
+
a dependency — including the `apps/*` monorepo walk that
|
|
12
|
+
`loadRuntimeCapabilities` performs.
|
|
13
|
+
- The required IDL capabilities are a subset of: `click`, `type`, `key`,
|
|
14
|
+
`navigate`, `screenshot`, `assert_visible`, `assert_text`,
|
|
15
|
+
`wait_for_idle`, `execute_js`, `dump_state`.
|
|
16
|
+
|
|
17
|
+
## Capabilities
|
|
18
|
+
|
|
19
|
+
| IDL verb | Maps to Tauri MCP tool |
|
|
20
|
+
|----------|------------------------|
|
|
21
|
+
| `click` | `mcp__tauri__click` |
|
|
22
|
+
| `type` | `mcp__tauri__type_text` |
|
|
23
|
+
| `key` | `mcp__tauri__mouse_action` (keyboard/shortcut dispatch) |
|
|
24
|
+
| `navigate` | `mcp__tauri__navigate` |
|
|
25
|
+
| `screenshot` | `mcp__tauri__take_screenshot` |
|
|
26
|
+
| `assert_visible` | `mcp__tauri__query_page` (mode: `find_element`) |
|
|
27
|
+
| `assert_text` | `mcp__tauri__query_page` (mode: `html`, textContent match) |
|
|
28
|
+
| `wait_for_idle` | `mcp__tauri__wait_for` |
|
|
29
|
+
| `execute_js` | `mcp__tauri__execute_js` |
|
|
30
|
+
| `dump_state` | `mcp__tauri__query_page` (mode: `state`) / `mcp__tauri__manage_window` |
|
|
31
|
+
|
|
32
|
+
These are the documented tools of the
|
|
33
|
+
[`tauri-plugin-mcp-server`](https://www.npmjs.com/package/tauri-plugin-mcp-server)
|
|
34
|
+
npm package (`take_screenshot`, `query_page`, `click`, `type_text`,
|
|
35
|
+
`mouse_action`, `navigate`, `execute_js`, `manage_storage`,
|
|
36
|
+
`manage_window`, `wait_for`, `restart_app`, `list_windows`, `ping`),
|
|
37
|
+
namespaced under `mcp__tauri__*` by the MCP server id.
|
|
38
|
+
|
|
39
|
+
## Manifest
|
|
40
|
+
|
|
41
|
+
- **Priority:** 85 (below the electron driver's 90 — Tauri is rarer than
|
|
42
|
+
Electron in the desktop-app population).
|
|
43
|
+
- **Stability:** `ga`.
|
|
44
|
+
- **Trust:** `first_party_signed` (default-allow).
|
|
45
|
+
- **Network posture:** `deny` (Tauri apps shouldn't be hitting the network
|
|
46
|
+
during proof verification).
|
|
47
|
+
- **Transport:** `{ mcp_server_id: "tauri" }`.
|
|
48
|
+
|
|
49
|
+
## Transport — how the MCP server is launched
|
|
50
|
+
|
|
51
|
+
The `tauri-plugin-mcp-server` npm bin ships **without a shebang**, so
|
|
52
|
+
`npx -y tauri-plugin-mcp-server` runs the `.js` as a shell script and
|
|
53
|
+
fails. Install-time provisioning therefore writes a launcher script at
|
|
54
|
+
`scripts/tauri-mcp.sh` that `exec node`s the bin via a stable path, loads
|
|
55
|
+
`.env`, and sets `TAURI_MCP_CONNECTION_TYPE=ipc` +
|
|
56
|
+
`TAURI_MCP_IPC_PATH` (a per-project socket). The host config entry is:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{ "command": "bash", "args": ["./scripts/tauri-mcp.sh"] }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
— identical to the proven shape. The launcher template lives at
|
|
63
|
+
`drivers/tauri/scripts/tauri-mcp.sh`; provisioning copies it idempotently
|
|
64
|
+
(never clobbering a user-edited launcher).
|
|
65
|
+
|
|
66
|
+
## PREREQUISITE — the app-side Rust plugin (OUT of framework scope)
|
|
67
|
+
|
|
68
|
+
This driver names the **transport**; it does NOT install the app-side
|
|
69
|
+
plugin. For the `mcp__tauri__*` tools to actually reach a running Tauri
|
|
70
|
+
app you must, in your own Tauri project:
|
|
71
|
+
|
|
72
|
+
1. Add the [`tauri-plugin-mcp`](https://github.com/P3GLEG/tauri-plugin-mcp)
|
|
73
|
+
Rust plugin to `src-tauri/` and register it in your app builder.
|
|
74
|
+
2. Run the app with the MCP debug feature enabled, e.g.
|
|
75
|
+
`tauri dev --features mcp-debug` (or your project's equivalent), so the
|
|
76
|
+
plugin opens the IPC socket the launcher connects to.
|
|
77
|
+
3. Install the npm transport package as a devDependency:
|
|
78
|
+
`pnpm add -D tauri-plugin-mcp-server`.
|
|
79
|
+
|
|
80
|
+
This is the SAME class of one-time, project-specific prerequisite as the
|
|
81
|
+
`electron-mcp-server` npm package for the electron driver — documented
|
|
82
|
+
here, never installed or modified by the Aperant framework.
|
|
83
|
+
|
|
84
|
+
**macOS note:** the plugin's `take_screenshot` does *screen-region*
|
|
85
|
+
capture at the window's bounds — keep the app foregrounded on the active
|
|
86
|
+
Space, or prefer `query_page` (DOM-only) for pixel-free assertions.
|
|
87
|
+
|
|
88
|
+
## Why hardcoded MCP tool names live here
|
|
89
|
+
|
|
90
|
+
Per [ID-01](../../../docs/frameworks/spec-gaps.md): the verify-proof
|
|
91
|
+
workflow prose refers ONLY to IDL verbs (`driver.click(target)`,
|
|
92
|
+
`driver.screenshot(path)`). The mapping from a verb to a concrete
|
|
93
|
+
`mcp__tauri__*` tool name exists in exactly two places — this README and
|
|
94
|
+
`driver.mjs`. The grep guard in
|
|
95
|
+
`packages/framework/src/__tests__/verify-proof-workflow-grep-guard.test.ts`
|
|
96
|
+
asserts zero `mcp__tauri__*` matches in `workflows/verify-proof.md`.
|
|
97
|
+
Adding this Tauri driver required zero edits to the workflow.
|
|
98
|
+
|
|
99
|
+
## V1 scope — adapter is thin
|
|
100
|
+
|
|
101
|
+
This driver's `driver.mjs` is a manifest-conformant **adapter shim** in
|
|
102
|
+
v1: each verb validates its args against `IDL_VERB_ARGS` and returns a
|
|
103
|
+
VerbResult stub. The actual `mcp__tauri__*` tool invocations happen at the
|
|
104
|
+
workflow-runner layer (the model holds the MCP tool surface, NOT the
|
|
105
|
+
driver process). The verb→tool mapping table above is the contract the
|
|
106
|
+
workflow runner consults; the driver itself is the validator + manifest +
|
|
107
|
+
resolver-anchor in v1 — same shape as `electron/driver.mjs`.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tauri/driver.mjs — bundled Tauri driver.
|
|
3
|
+
*
|
|
4
|
+
* Maps IDL verbs to the Tauri MCP server's tool surface. The
|
|
5
|
+
* transport.mcp_server_id="tauri" string in manifest.json names the
|
|
6
|
+
* MCP server config the resolver hands off to (the `tauri-plugin-mcp-server`
|
|
7
|
+
* npm package, launched via scripts/tauri-mcp.sh — see README.md).
|
|
8
|
+
*
|
|
9
|
+
* Per ID-01 — the workflow prose NEVER names mcp__tauri__* tools.
|
|
10
|
+
* That mapping lives ONLY here in driver.mjs.
|
|
11
|
+
*
|
|
12
|
+
* IDL verb → MCP tool mapping (one place, one purpose):
|
|
13
|
+
* click → mcp__tauri__click
|
|
14
|
+
* type → mcp__tauri__type_text
|
|
15
|
+
* key → mcp__tauri__mouse_action (keyboard/shortcut dispatch)
|
|
16
|
+
* navigate → mcp__tauri__navigate
|
|
17
|
+
* screenshot → mcp__tauri__take_screenshot
|
|
18
|
+
* assert_visible → mcp__tauri__query_page (mode: find_element)
|
|
19
|
+
* assert_text → mcp__tauri__query_page (mode: html / textContent match)
|
|
20
|
+
* wait_for_idle → mcp__tauri__wait_for
|
|
21
|
+
* execute_js → mcp__tauri__execute_js
|
|
22
|
+
* dump_state → mcp__tauri__query_page (mode: state) / mcp__tauri__manage_window
|
|
23
|
+
*
|
|
24
|
+
* The driver is a thin adapter — same shape as electron/driver.mjs.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { validateVerbArgs } from '../../src/cli/verify-proof/idl/index.mjs'
|
|
28
|
+
|
|
29
|
+
function ok(evidence_paths = []) {
|
|
30
|
+
return { status: 'success', evidence_paths, duration_ms: 0, retry_count: 0 }
|
|
31
|
+
}
|
|
32
|
+
function fail(error) {
|
|
33
|
+
return { status: 'fail', evidence_paths: [], duration_ms: 0, retry_count: 0, error }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function adaptVerb(verb, args) {
|
|
37
|
+
const check = validateVerbArgs(verb, args)
|
|
38
|
+
if (!check.valid) {
|
|
39
|
+
return fail(`tauri.${verb}: missing required args: ${check.missing.join(', ')}`)
|
|
40
|
+
}
|
|
41
|
+
if (verb === 'screenshot' && typeof args.output_path === 'string') {
|
|
42
|
+
return ok([args.output_path])
|
|
43
|
+
}
|
|
44
|
+
if (verb === 'dump_state' && typeof args.output_path === 'string') {
|
|
45
|
+
return ok([args.output_path])
|
|
46
|
+
}
|
|
47
|
+
return ok()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function click(args) {
|
|
51
|
+
return adaptVerb('click', args)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function type(args) {
|
|
55
|
+
return adaptVerb('type', args)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function key(args) {
|
|
59
|
+
return adaptVerb('key', args)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function navigate(args) {
|
|
63
|
+
return adaptVerb('navigate', args)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function screenshot(args) {
|
|
67
|
+
return adaptVerb('screenshot', args)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function assert_visible(args) {
|
|
71
|
+
return adaptVerb('assert_visible', args)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function assert_text(args) {
|
|
75
|
+
return adaptVerb('assert_text', args)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function wait_for_idle(args) {
|
|
79
|
+
return adaptVerb('wait_for_idle', args)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function execute_js(args) {
|
|
83
|
+
return adaptVerb('execute_js', args)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function dump_state(args) {
|
|
87
|
+
return adaptVerb('dump_state', args)
|
|
88
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"driverId": "tauri",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"targets": ["tauri@>=1"],
|
|
5
|
+
"capabilities": [
|
|
6
|
+
"click",
|
|
7
|
+
"type",
|
|
8
|
+
"key",
|
|
9
|
+
"navigate",
|
|
10
|
+
"screenshot",
|
|
11
|
+
"assert_visible",
|
|
12
|
+
"assert_text",
|
|
13
|
+
"wait_for_idle",
|
|
14
|
+
"execute_js",
|
|
15
|
+
"dump_state"
|
|
16
|
+
],
|
|
17
|
+
"evidence_capabilities": ["screenshot", "dom_dump", "capture_logs"],
|
|
18
|
+
"frameworkApiRange": "^1.0.0",
|
|
19
|
+
"priority": 85,
|
|
20
|
+
"stability": "ga",
|
|
21
|
+
"trust": {
|
|
22
|
+
"tier": "first_party_signed",
|
|
23
|
+
"publisher": {
|
|
24
|
+
"name": "Aperant",
|
|
25
|
+
"npm_scope": "@aperant",
|
|
26
|
+
"github_org": "Mikalsen-AI",
|
|
27
|
+
"verified": true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"security": {
|
|
31
|
+
"sandbox_profile": "workspace_write",
|
|
32
|
+
"network": "deny",
|
|
33
|
+
"requires_user_approval": false
|
|
34
|
+
},
|
|
35
|
+
"audit": { "log_invocations": true, "log_manifest_hash": true },
|
|
36
|
+
"transport": { "mcp_server_id": "tauri" }
|
|
37
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Launches the tauri-plugin-mcp-server with the project's .env injected.
|
|
3
|
+
# Generated by `apt-tools init` (Aperant Framework) and referenced from the
|
|
4
|
+
# host CLI's MCP config as: { command: "bash", args: ["./scripts/tauri-mcp.sh"] }
|
|
5
|
+
#
|
|
6
|
+
# This launcher exists because the tauri-plugin-mcp-server npm bin ships
|
|
7
|
+
# WITHOUT a shebang, so `npx -y tauri-plugin-mcp-server` runs the .js as a
|
|
8
|
+
# shell script and fails. We invoke the bin via `node` with a stable path.
|
|
9
|
+
#
|
|
10
|
+
# Idempotent: this file is never overwritten once present (edit it freely).
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
15
|
+
|
|
16
|
+
# Load .env (gitignored) WITHOUT executing it. We do NOT dot-source the file
|
|
17
|
+
# (that would run any `$(...)`, backticks, or function defs it contains as
|
|
18
|
+
# shell). Instead parse it line-by-line: skip blank/comment lines, and export
|
|
19
|
+
# only well-formed `KEY=VALUE` assignments whose key is a valid shell name.
|
|
20
|
+
if [[ -f "$ROOT/.env" ]]; then
|
|
21
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
22
|
+
# Strip a leading `export ` prefix if present.
|
|
23
|
+
line="${line#export }"
|
|
24
|
+
# Skip blank lines and comments.
|
|
25
|
+
[[ -z "$line" || "$line" == \#* ]] && continue
|
|
26
|
+
# Only accept lines of the form NAME=VALUE (bash-style identifier name).
|
|
27
|
+
if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
|
|
28
|
+
key="${line%%=*}"
|
|
29
|
+
value="${line#*=}"
|
|
30
|
+
export "$key=$value"
|
|
31
|
+
fi
|
|
32
|
+
done < "$ROOT/.env"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
export TAURI_MCP_CONNECTION_TYPE="${TAURI_MCP_CONNECTION_TYPE:-ipc}"
|
|
36
|
+
export TAURI_MCP_IPC_PATH="${TAURI_MCP_IPC_PATH:-$HOME/.{{PROJECT_SOCKET}}-mcp.sock}"
|
|
37
|
+
|
|
38
|
+
# Install the transport package as a devDependency first:
|
|
39
|
+
# pnpm add -D tauri-plugin-mcp-server
|
|
40
|
+
# and add the tauri-plugin-mcp Rust plugin to your app (see drivers/tauri/README.md).
|
|
41
|
+
exec node "$ROOT/node_modules/tauri-plugin-mcp-server/build/index.js"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aperant/framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "AI coding framework — composable skills for planning, executing, verifying, and reviewing code with any LLM provider. Works as Claude Code commands, Codex tasks, or programmatically.",
|
|
5
5
|
"author": "Mikalsen AI <hello@mikalsen.ai>",
|
|
6
6
|
"type": "module",
|
|
@@ -65,11 +65,12 @@ PHASE 3 -- PARALLEL REVIEW (6 agents, independent, all spawned in ONE message):
|
|
|
65
65
|
PHASE 4 -- VALIDATION (1 agent):
|
|
66
66
|
validator -> Re-investigates every finding, confirms or dismisses
|
|
67
67
|
|
|
68
|
-
PHASE 6 -- FIX LOOP (up to 3
|
|
69
|
-
fixer-1, fixer-2, fixer-3
|
|
68
|
+
PHASE 6 -- FIX LOOP (up to 3 fixers per iteration, spawned ONE AT A TIME, max 4 iterations):
|
|
69
|
+
fixer-1, fixer-2, fixer-3 (groups still exist; they run SEQUENTIALLY, never concurrently)
|
|
70
70
|
- Read validated finding files directly
|
|
71
|
-
- Fix assigned issues, run verification,
|
|
71
|
+
- Fix assigned issues, run verification, commit atomically per finding
|
|
72
72
|
- Report brief status to orchestrator
|
|
73
|
+
- NEVER run pr-review fixers in parallel in a shared worktree (FRAMEWORK-BUG-006)
|
|
73
74
|
|
|
74
75
|
PHASE 7 -- SELF-REVIEW (1 fresh agent):
|
|
75
76
|
self-reviewer
|
|
@@ -468,6 +469,55 @@ fi
|
|
|
468
469
|
|
|
469
470
|
After this point, the per-round artifact root is `.aperant/pr-reviews/pr-${PR_NUMBER}/rounds/${ROUND}/` (the `${REVIEW_ID}` is still used for the git worktree branch and temporary files). Subsequent `git diff` invocations within the round use `${PINNED_HEAD_SHA}` as the head ref.
|
|
470
471
|
|
|
472
|
+
### Step 4c: Mergeability Pre-Check (PR reviews only)
|
|
473
|
+
|
|
474
|
+
**Why this exists.** The review diff is `git diff {BASE}...{HEAD}` (three-dot — from the *merge-base*), so it shows the PR's own changes relative to where it branched. It is **blind to drift on `{BASE}` since then** and therefore says nothing about whether the PR still merges cleanly. A PR can pass a glowing review and be unmergeable. This step closes that gap: it is **informational, never blocking** (the review still runs in full), but a conflicting/stale state MUST be surfaced so the reader doesn't trust a review of a diff that no longer applies.
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
# PR-mode only. Query GitHub's authoritative mergeability + measure drift.
|
|
478
|
+
if [ -n "$PR_NUMBER" ]; then
|
|
479
|
+
MERGE_JSON=$(gh pr view ${PR_NUMBER} --json mergeable,mergeStateStatus,baseRefName 2>/dev/null)
|
|
480
|
+
MERGEABLE=$(echo "$MERGE_JSON" | jq -r '.mergeable // "UNKNOWN"')
|
|
481
|
+
MERGE_STATE=$(echo "$MERGE_JSON" | jq -r '.mergeStateStatus // "UNKNOWN"')
|
|
482
|
+
BASE_REF=$(echo "$MERGE_JSON" | jq -r '.baseRefName // "main"')
|
|
483
|
+
git fetch origin "${BASE_REF}" 2>/dev/null
|
|
484
|
+
BEHIND=$(git rev-list --count ${PINNED_HEAD_SHA}..origin/${BASE_REF} 2>/dev/null || echo "?")
|
|
485
|
+
AHEAD=$(git rev-list --count origin/${BASE_REF}..${PINNED_HEAD_SHA} 2>/dev/null || echo "?")
|
|
486
|
+
|
|
487
|
+
# If GitHub reports a conflict (or hasn't computed yet), enumerate the conflicting
|
|
488
|
+
# files locally without touching any working tree (git >= 2.38):
|
|
489
|
+
CONFLICT_FILES=""
|
|
490
|
+
if [ "$MERGEABLE" = "CONFLICTING" ] || [ "$MERGE_STATE" = "DIRTY" ]; then
|
|
491
|
+
CONFLICT_FILES=$(git merge-tree --write-tree --name-only origin/${BASE_REF} ${PINNED_HEAD_SHA} 2>/dev/null \
|
|
492
|
+
| tail -n +2 | sed '/^$/d' | grep '/' )
|
|
493
|
+
fi
|
|
494
|
+
fi
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Record the result in `metadata.json` under a `mergeability` key:
|
|
498
|
+
|
|
499
|
+
```json
|
|
500
|
+
{
|
|
501
|
+
"mergeability": {
|
|
502
|
+
"mergeable": "CONFLICTING | MERGEABLE | UNKNOWN",
|
|
503
|
+
"merge_state_status": "DIRTY | CLEAN | BLOCKED | BEHIND | ...",
|
|
504
|
+
"base_ref": "main",
|
|
505
|
+
"commits_behind_base": 101,
|
|
506
|
+
"commits_ahead_base": 91,
|
|
507
|
+
"conflicting_files": ["apps/.../App.tsx", "..."]
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**How to use the result:**
|
|
513
|
+
|
|
514
|
+
- `MERGEABLE` ∈ {`CONFLICTING`} OR `MERGE_STATE` = `DIRTY` → the PR has conflicts. Surface a **⚠️ Mergeability** block in the Phase 5 intermediate report AND the Phase 8 final report, listing `commits_behind_base` and the `conflicting_files`. In **external / comment-only** mode, include the same block in the Phase 6b comment. State plainly that the branch needs a rebase/merge from `{BASE}` and that **the reviewed diff may be stale** with respect to current `{BASE}`.
|
|
515
|
+
- `MERGE_STATE` = `BEHIND` (mergeable but behind) → note the drift (`commits_behind_base`) as a softer advisory; no conflict, but the diff predates recent `{BASE}` commits.
|
|
516
|
+
- `MERGEABLE` = `UNKNOWN` (GitHub hasn't finished computing, common right after a push) → record `UNKNOWN`; optionally re-poll once after a few seconds. Do not block.
|
|
517
|
+
- `MERGEABLE` = `MERGEABLE`, `MERGE_STATE` = `CLEAN` → record it and move on silently.
|
|
518
|
+
|
|
519
|
+
This step never changes the review's findings or assessment — a conflicting PR with zero code findings is still `approve` on its own merits. Mergeability is reported as a **separate** signal so the reader knows whether the approval can actually land.
|
|
520
|
+
|
|
471
521
|
### Step 5: Read All Changed Files
|
|
472
522
|
|
|
473
523
|
For every file in the changed file list, read it in full using the Read tool **from the worktree**:
|
|
@@ -594,6 +644,16 @@ Construct a toolchain commands object:
|
|
|
594
644
|
|
|
595
645
|
Save to `.aperant/pr-reviews/${REVIEW_ID}/toolchain.json`.
|
|
596
646
|
|
|
647
|
+
**Cache-bypass variant (FRAMEWORK-BUG-006 Part B).** `toolchain-detect` emits an additive
|
|
648
|
+
`no_cache_command` field on `typecheck` (and `test`) when the project's verify command is turbo-backed
|
|
649
|
+
(e.g. `typecheck: { tool, command, no_cache_command: "pnpm run typecheck --force" }`). A turbo-backed
|
|
650
|
+
verify can return a STALE CACHE HIT ("replaying logs") that reports PASS while a fixer-introduced broken
|
|
651
|
+
import sits on disk — sighted on PR #244, where only a `--force` (no-cache) typecheck exposed it.
|
|
652
|
+
**Whenever a `no_cache_command` exists for a check, every POST-FIX verification (auto-checks re-runs,
|
|
653
|
+
the Phase 6 fixer verification, and the Phase 7 self-reviewer) MUST use it instead of the plain
|
|
654
|
+
`command`** so a stale cache cannot mask a broken import. Non-turbo projects have no `no_cache_command`
|
|
655
|
+
(plain `tsc`/`vitest` have no cache to bust) and use the plain command unchanged.
|
|
656
|
+
|
|
597
657
|
Update `metadata.json` with the toolchain summary and trigger count.
|
|
598
658
|
|
|
599
659
|
---
|
|
@@ -663,8 +723,8 @@ cd {WORKTREE_PATH}
|
|
|
663
723
|
```
|
|
664
724
|
|
|
665
725
|
1. Lint: {LINT_COMMAND}
|
|
666
|
-
2. Typecheck: {TYPECHECK_COMMAND}
|
|
667
|
-
3. Tests: {TEST_COMMAND}
|
|
726
|
+
2. Typecheck: {TYPECHECK_COMMAND} (use toolchain.json `typecheck.no_cache_command` if present — FRAMEWORK-BUG-006: a turbo-backed typecheck can replay a stale cached PASS and mask a broken import)
|
|
727
|
+
3. Tests: {TEST_COMMAND} (use toolchain.json `test.no_cache_command` if present, same cache-bypass rationale)
|
|
668
728
|
|
|
669
729
|
## Output
|
|
670
730
|
|
|
@@ -1047,6 +1107,10 @@ Review Synthesis (Before Auto-Fix)
|
|
|
1047
1107
|
Auto-Checks: {PASS/FAIL}
|
|
1048
1108
|
lint: {P/F} | typecheck: {P/F} | tests: {P/F}
|
|
1049
1109
|
|
|
1110
|
+
Mergeability (PR reviews — from Step 4c): {MERGEABLE/CONFLICTING/UNKNOWN}
|
|
1111
|
+
{if CONFLICTING/DIRTY: "⚠️ conflicts with {BASE} — {behind} commits behind — needs rebase — reviewed diff may be stale"}
|
|
1112
|
+
{if conflicting_files: list them}
|
|
1113
|
+
|
|
1050
1114
|
Validated Findings:
|
|
1051
1115
|
CRITICAL: {N}
|
|
1052
1116
|
HIGH: {N}
|
|
@@ -1171,8 +1235,9 @@ This is the owned-mode path. External-mode invocations run Phase 6b instead of t
|
|
|
1171
1235
|
for ITERATION in 1 2 3 4:
|
|
1172
1236
|
1. Create iteration directory
|
|
1173
1237
|
2. Group findings into fix assignments (max 3 groups)
|
|
1174
|
-
3. Spawn fix agents
|
|
1175
|
-
|
|
1238
|
+
3. Spawn fix agents ONE AT A TIME (never in parallel — FRAMEWORK-BUG-006):
|
|
1239
|
+
for each group: spawn fixer → wait → audit (Step 4b) → next group
|
|
1240
|
+
4. (folded into step 3's per-fixer wait)
|
|
1176
1241
|
5. Generate new diff
|
|
1177
1242
|
6. If fixes were applied: spawn fresh review on new diff
|
|
1178
1243
|
7. If ITERATION <= 2: accept new findings into the backlog
|
|
@@ -1197,6 +1262,14 @@ Take all confirmed, fixable findings and group them into up to 3 independent gro
|
|
|
1197
1262
|
|
|
1198
1263
|
#### Step 3: Spawn Fix Agents
|
|
1199
1264
|
|
|
1265
|
+
> **HARD RULE (FRAMEWORK-BUG-006): NEVER run pr-review fixers in parallel in a shared worktree.**
|
|
1266
|
+
> All fixers share ONE worktree, ONE git index, and ONE branch. git's index is not a
|
|
1267
|
+
> concurrency-safe surface — concurrent `git add` / `git commit` / self-audit `git log`/`git diff`
|
|
1268
|
+
> from sibling fixers either SWEEP one fixer's staged files into another's commit (PR #114
|
|
1269
|
+
> entanglement) or CLOBBER another fixer's working-tree edits entirely (PR #244 work-loss). Spawn
|
|
1270
|
+
> fixers **one at a time**: spawn fixer-1, wait for it to return, run the Step 4b audit-fixer gate on
|
|
1271
|
+
> it, THEN spawn fixer-2, and so on. At most one fixer touches the shared worktree at any moment.
|
|
1272
|
+
|
|
1200
1273
|
**Capture the iteration-start SHA BEFORE spawning fixers** (used by both the Step 4b audit gate AND the per-fixer Pre-Return Self-Audit added in BUG-016 — fixers now commit atomically per finding, and the audit window is scoped by this SHA):
|
|
1201
1274
|
|
|
1202
1275
|
```bash
|
|
@@ -1211,9 +1284,9 @@ For each fix group, spawn a fix agent. Read the agent definition from `.claude/a
|
|
|
1211
1284
|
| `[FIX_ASSIGNMENT]` | List of finding IDs and files for this group |
|
|
1212
1285
|
| `[N]` | Current iteration number |
|
|
1213
1286
|
| `[FIXER_NAME]` | `fixer-1`, `fixer-2`, or `fixer-3` |
|
|
1214
|
-
| `[TOOLCHAIN_COMMANDS]` | Commands from `toolchain.json` (the `all` command, or individual commands) |
|
|
1287
|
+
| `[TOOLCHAIN_COMMANDS]` | Commands from `toolchain.json` (the `all` command, or individual commands). **For the post-fix typecheck/test, pass the `no_cache_command` variant when `toolchain.json` provides one** (FRAMEWORK-BUG-006: a turbo-backed verify can replay a stale cached PASS and mask the fixer's own broken import). |
|
|
1215
1288
|
| `[CRITICAL_APPROVAL]` | `true` or `false` for each critical finding in this group |
|
|
1216
|
-
| `[PARALLEL_FIXERS]` | `
|
|
1289
|
+
| `[PARALLEL_FIXERS]` | Always `false` (FRAMEWORK-BUG-006). Fixers are spawned one at a time in the shared worktree — never concurrently. The placeholder is retained only so the fixer-agent Coordination Protocol can assert "you are the only fixer touching this worktree right now." |
|
|
1217
1290
|
| `[WORKTREE_PATH]` | The worktree path — fix agents edit files HERE, not in the user's working directory |
|
|
1218
1291
|
| `[ITERATION_START_SHA]` | The SHA captured BEFORE spawning fixers (see Step 4b's `ITERATION_START_SHA=$(...)` capture). Required for BUG-016 commit-discipline Pre-Return Self-Audit. |
|
|
1219
1292
|
|
|
@@ -1226,18 +1299,31 @@ Agent(
|
|
|
1226
1299
|
)
|
|
1227
1300
|
```
|
|
1228
1301
|
|
|
1229
|
-
If there are 2-3 groups, spawn
|
|
1302
|
+
If there are 2-3 groups, spawn the fixers **sequentially — one fixer at a time, never in parallel**
|
|
1303
|
+
(FRAMEWORK-BUG-006). Concretely, loop over the groups:
|
|
1304
|
+
|
|
1305
|
+
```
|
|
1306
|
+
for each fix group (in order):
|
|
1307
|
+
1. Spawn the fixer for THIS group only (a single Agent call in its own message)
|
|
1308
|
+
2. Wait for it to return its brief status line (Step 4)
|
|
1309
|
+
3. Run the Step 4b audit-fixer gate on it
|
|
1310
|
+
4. Only THEN spawn the fixer for the next group
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
Do NOT batch multiple `Agent(...)` fixer calls into one message — that is the parallel-shared-worktree
|
|
1314
|
+
race this bug fixes. The atomic-per-finding commit discipline (BUG-016) and the Step 4b audit gate are
|
|
1315
|
+
UNCHANGED; they now simply run without a concurrent sibling mutating the index.
|
|
1230
1316
|
|
|
1231
1317
|
#### Step 4: Wait for Completion
|
|
1232
1318
|
|
|
1233
|
-
Wait for
|
|
1319
|
+
Wait for the **current** fix agent to return its brief status (you spawned only one this turn):
|
|
1234
1320
|
```
|
|
1235
1321
|
FIXED: X | FAILED: Y | SKIPPED: Z | VERIFICATION: PASS/FAIL
|
|
1236
1322
|
```
|
|
1237
1323
|
|
|
1238
1324
|
#### Step 4b: Audit Fixer Output (Hallucination Gate)
|
|
1239
1325
|
|
|
1240
|
-
On 2026-04-20 a live fix agent returned `FIXED: 2 | FAILED: 0 | SKIPPED: 0 | VERIFICATION: PASS` and wrote a convincing 140-line `fixes-applied.md` — but the worktree had zero edits matching the claimed files. The orchestrator trusted the self-reported status line and nearly shipped two fabricated fixes. This step is the deterministic gate that closes that hole: for
|
|
1326
|
+
On 2026-04-20 a live fix agent returned `FIXED: 2 | FAILED: 0 | SKIPPED: 0 | VERIFICATION: PASS` and wrote a convincing 140-line `fixes-applied.md` — but the worktree had zero edits matching the claimed files. The orchestrator trusted the self-reported status line and nearly shipped two fabricated fixes. This step is the deterministic gate that closes that hole: for the fixer that just returned in Step 4 (fixers run one at a time — FRAMEWORK-BUG-006), run the audit CLI and cross-check the fixer's claims against the actual git state BEFORE spawning the next group's fixer.
|
|
1241
1327
|
|
|
1242
1328
|
**Capture the iteration-start SHA BEFORE spawning fixers** so the audit can cover committed fixes (bug-5, 2026-04-23 — fixers that commit their edits before returning would otherwise present an empty working tree and trip a false-positive hallucination verdict):
|
|
1243
1329
|
|
|
@@ -1271,7 +1357,7 @@ Rule of thumb: pass `--since-sha "${ITERATION_START_SHA}"` on every audit invoca
|
|
|
1271
1357
|
|
|
1272
1358
|
The CLI returns a JSON envelope with `verdict` ∈ `verified | hallucinated | skipped`, writes `iterations/${ITERATION}/audit.json` (append-only), and bumps `metadata.json.fixer_hallucinations_total` on every `hallucinated` outcome. The envelope's `observed.since_sha` + `observed.since_sha_source` fields record which SHA was used and where it came from (`flag` | `merge-base` | `null`). The same envelope is used for the fixer and the self-reviewer (Phase 7) — `--fixer self-reviewer` reads from `self-review.md`.
|
|
1273
1359
|
|
|
1274
|
-
**Canonical fix-report filename per fixer (BUG-030):** each fixer agent writes to `fixes-applied-${FIXER_NAME}.md` (e.g. `fixes-applied-fixer-1.md`). The audit CLI resolves candidates in strict order: `fixes-applied-group{N}.md` (legacy group-named, pre-BUG-030 reviews) → `fixes-applied-fixer-{N}.md` (NEW fixer-named) → `fixes-applied-${FIXER_NAME}.md` (exact match, preferred for non-numeric fixer names) → `fixes-applied.md` (legacy unscoped, single-fixer reviews only). Writing the canonical name eliminates the cross-fixer false-positive `hallucinated` verdict that fired when
|
|
1360
|
+
**Canonical fix-report filename per fixer (BUG-030):** each fixer agent writes to `fixes-applied-${FIXER_NAME}.md` (e.g. `fixes-applied-fixer-1.md`). The audit CLI resolves candidates in strict order: `fixes-applied-group{N}.md` (legacy group-named, pre-BUG-030 reviews) → `fixes-applied-fixer-{N}.md` (NEW fixer-named) → `fixes-applied-${FIXER_NAME}.md` (exact match, preferred for non-numeric fixer names) → `fixes-applied.md` (legacy unscoped, single-fixer reviews only). Writing the canonical name eliminates the cross-fixer false-positive `hallucinated` verdict that fired when fixers shared `fixes-applied.md` (a per-fixer report path is still correct now that fixers run sequentially — each fixer owns its own report file).
|
|
1275
1361
|
|
|
1276
1362
|
| Verdict | Orchestrator Action |
|
|
1277
1363
|
|---------|---------------------|
|
|
@@ -1430,7 +1516,7 @@ Read the agent definition from `.claude/agents/apt-pr-review-self-reviewer.md` a
|
|
|
1430
1516
|
|-------------|-------|
|
|
1431
1517
|
| `[FIX_DIFF]` | The combined fix diff content or path to the concatenated file |
|
|
1432
1518
|
| `[REVIEW_DIR]` | `.aperant/pr-reviews/{REVIEW_ID}` |
|
|
1433
|
-
| `[TOOLCHAIN_COMMANDS]` | Commands from `toolchain.json` |
|
|
1519
|
+
| `[TOOLCHAIN_COMMANDS]` | Commands from `toolchain.json`. **Use the `no_cache_command` variant for the typecheck/test when one is present** (FRAMEWORK-BUG-006: a turbo-backed verify can replay a stale cached PASS and mask a broken import the fixes introduced). |
|
|
1434
1520
|
| `[WORKTREE_PATH]` | The worktree path — self-reviewer works HERE |
|
|
1435
1521
|
|
|
1436
1522
|
```
|
|
@@ -1597,6 +1683,7 @@ Output the human-readable summary:
|
|
|
1597
1683
|
|
|
1598
1684
|
Review ID: {REVIEW_ID}
|
|
1599
1685
|
Assessment: {APPROVE / REQUEST CHANGES / COMMENT}
|
|
1686
|
+
Mergeability: {MERGEABLE / CONFLICTING (N behind {BASE}, needs rebase) / UNKNOWN} # PR reviews — from Step 4c / metadata.json.mergeability
|
|
1600
1687
|
|
|
1601
1688
|
Scores:
|
|
1602
1689
|
Security: {score}/10
|
|
@@ -1683,11 +1770,15 @@ Fix agents self-report their outcome via a status line (`FIXED: X | FAILED: Y |
|
|
|
1683
1770
|
**Wrong:** Reading the full finding text from agent responses and processing it in orchestrator context.
|
|
1684
1771
|
**Right:** Agent responses are brief (3-5 lines). All detail goes to files. Orchestrator reads files via Read tool only when needed.
|
|
1685
1772
|
|
|
1686
|
-
### Mistake 2: Spawning Agents Sequentially
|
|
1773
|
+
### Mistake 2: Spawning the Phase 3 REVIEW Agents Sequentially
|
|
1687
1774
|
|
|
1688
1775
|
**Wrong:** Spawn security agent, wait, spawn quality agent, wait, etc.
|
|
1689
1776
|
**Right:** Spawn all 6 review agents in ONE message using 6 parallel Agent tool calls. They run concurrently.
|
|
1690
1777
|
|
|
1778
|
+
> Scope note: this applies ONLY to the Phase 3 review specialists, which are read-only (Read/Grep/Glob,
|
|
1779
|
+
> no Edit/Bash, no git writes) and therefore cannot race the index. The Phase 6 FIXERS are the
|
|
1780
|
+
> opposite — they MUST be spawned one at a time (FRAMEWORK-BUG-006). Never parallelize fixers.
|
|
1781
|
+
|
|
1691
1782
|
### Mistake 3: Skipping the Validator
|
|
1692
1783
|
|
|
1693
1784
|
**Wrong:** Sending raw review findings directly to fix agents.
|
|
@@ -966,8 +966,9 @@ ST-3 apt:execute --tdd).
|
|
|
966
966
|
|
|
967
967
|
Per ID-01 (Framework full-featured locally; backends are pluggable), the
|
|
968
968
|
default is `local-only` — zero GitHub auth required on first run. Users
|
|
969
|
-
can switch to `github-issues` (
|
|
970
|
-
the
|
|
969
|
+
can switch to `github-issues` (implemented — creates + syncs real issues
|
|
970
|
+
via the `gh` CLI) or `app-inbox` (still a stub) later; the framework
|
|
971
|
+
abstraction is open for further adapter implementations.
|
|
971
972
|
|
|
972
973
|
### 3g.1 Present the task-tracking picker
|
|
973
974
|
|
|
@@ -979,10 +980,10 @@ AskUserQuestion([
|
|
|
979
980
|
options: [
|
|
980
981
|
{ label: "Local files only (recommended for solo / 2-founder)",
|
|
981
982
|
description: "Writes to .aperant/tasks/{id}/triage.json. Zero net dep." },
|
|
982
|
-
{ label: "GitHub Issues (
|
|
983
|
-
description: "
|
|
984
|
-
{ label: "App inbox (post-app-launch — stub
|
|
985
|
-
description: "Convex-backed; same state machine, app-rendered." }
|
|
983
|
+
{ label: "GitHub Issues (creates + syncs real issues via the gh CLI)",
|
|
984
|
+
description: "First mirror creates an issue; transitions update the same issue (label swap), wontfix closes it as not-planned. Requires gh installed + authed + a git remote." },
|
|
985
|
+
{ label: "App inbox (post-app-launch — stub)",
|
|
986
|
+
description: "Convex-backed; same state machine, app-rendered. Still a stub." }
|
|
986
987
|
]
|
|
987
988
|
},
|
|
988
989
|
{
|
|
@@ -127,16 +127,18 @@ needed.
|
|
|
127
127
|
|
|
128
128
|
`.aperant/config.json.task_tracking.backend` selects the mirror:
|
|
129
129
|
|
|
130
|
-
| Backend |
|
|
130
|
+
| Backend | behavior |
|
|
131
131
|
|---|---|
|
|
132
132
|
| `local-only` (default) | State mirrors to `.aperant/tasks/{task-id}/triage.json` only. Zero network dependency. |
|
|
133
|
-
| `github-issues` |
|
|
134
|
-
| `app-inbox` |
|
|
133
|
+
| `github-issues` | Mirrors triage state to a real GitHub issue via the `gh` CLI. The first mirror CREATES an issue (`triage: <task-id>`, labelled `<category>` + `<vocab>:<state>`); subsequent transitions UPDATE the same issue (label swap), and `wontfix` CLOSES it as "not planned". The issue pointer (`github.{issue_number, issue_url, repo}`) persists on `triage.json` so transitions stay idempotent — no duplicates. Honors `task_tracking.tracker_label_vocabulary` (default → `triage:<state>`). Requires `gh` installed + authenticated + a resolvable git remote; otherwise returns a structured error (`reason: gh-unavailable | gh-unauthenticated | no-remote | gh-command-failed`) and exits non-zero — never a crash/stacktrace. Label ops are best-effort: an unknown label degrades to a `warnings[]` entry while the open/closed state change still lands. |
|
|
134
|
+
| `app-inbox` | Still a stub: returns `{status: 'not-implemented', backend: 'app-inbox', v2_issue: '#TBD'}`. Belongs to a future Convex-backed task (post-app-launch). |
|
|
135
135
|
|
|
136
136
|
Skill body reads `task_tracking.backend` at the start of every
|
|
137
|
-
invocation.
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
invocation. For `app-inbox` (still unimplemented), the skill fails fast
|
|
138
|
+
with the `not-implemented` envelope — it does NOT silently fall back to
|
|
139
|
+
`local-only`. The `github-issues` backend is fully implemented (see
|
|
140
|
+
above); its preflight/`gh` failures surface as structured errors, again
|
|
141
|
+
without falling back to `local-only`.
|
|
140
142
|
|
|
141
143
|
## Fast Path Guarantee — QUICK never enters triage (AC9, ID-05)
|
|
142
144
|
|
|
@@ -287,6 +287,6 @@ Runtime files were still refreshed; `/apt` will still work from PATH if `apt-too
|
|
|
287
287
|
- **Worker hasn't run yet**: the cache file is missing. That's fine — run check-version directly (step 1 is robust to a missing cache). Proceed normally.
|
|
288
288
|
- **Re-install fails (non-zero exit from init)**: surface the JSON `error` field verbatim in a single line, then stop. Do NOT delete the cache file — the chip should remain visible so the user sees the failure persists.
|
|
289
289
|
- **Kernel install fails but runtime install succeeds**: see Scenario D above. Do not treat this as a total failure; the user's skills still work via PATH fallback.
|
|
290
|
-
- **
|
|
290
|
+
- **Instruction-file foreign rows (exit 2, `instruction-file.foreign-rows`)** — 0.7.0+ — init now refuses to silently clobber custom rows in the `<!-- APT:framework-* -->` block. Since the multi-file fix, init stamps the block into EVERY instruction file the selected runtimes read (claude → CLAUDE.md, codex/opencode → AGENTS.md, gemini → GEMINI.md) and runs an all-target foreign-row preflight: if ANY target has foreign rows, init writes NOTHING and exits 2 (no partial install). If `init` exits 2 with `code: instruction-file.foreign-rows`, the `foreignRowIds[]` field lists the rows the generator did NOT produce and `instructionFiles[]` lists the offending files. Two paths: (a) remove the foreign rows from the listed file(s) by hand and re-run init, or (b) re-run with `--force-overwrite-catalog` to regenerate anyway. Unattended upgrade flows should detect this code and surface it to the operator — silent bypass is a regression.
|
|
291
291
|
|
|
292
292
|
</edge_cases>
|
|
@@ -60,7 +60,7 @@ Before spawning any verifier subagent or running scoring against acceptance crit
|
|
|
60
60
|
</locked_decisions>
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
Verifiers apply this digest when interpreting "completeness" and "correctness" — if a decision explicitly deferred a behavior, its absence is NOT a verification failure.
|
|
63
|
+
Verifiers apply this digest when interpreting "completeness" and "correctness" — if a decision explicitly deferred a behavior AND the deferred finding has severity below critical or major, its absence is NOT a verification failure. A deferred critical or major finding IS a Completeness gap — score accordingly and note it in the issues list.
|
|
64
64
|
</decision_ledger_inject>
|
|
65
65
|
|
|
66
66
|
<process>
|