diff --git a/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-3.md b/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-3.md index ddaf5696f..9ecbafac5 100644 --- a/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-3.md +++ b/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-3.md @@ -1,5 +1,5 @@ --- -status: pending +status: done --- @@ -12,13 +12,26 @@ status: pending ```txt cli/ -├── src/contexts/tools/domain/profiles/antigravity/ -│ ├── antigravity-hooks.ts ✅ named-hook shape: merge AIDD's `aidd-memory` key into `.agents/hooks.json`, strip it on uninstall, convert Claude-shaped flat hooks -│ ├── profile.ts ✏️ HooksCapability on `.agents/hooks.json` -│ └── build.ts ✏️ hooks artifact: scripts under `.agents/hooks//`, hooksMerge into `.agents/hooks.json` +├── src/contexts/tools/domain/ +│ ├── formats/ +│ │ ├── project-hooks-format.ts ✅ per-tool project hooks file strategy: merge, unmerge, contributed entries, empty check, script path and dir +│ │ └── cursor-hooks-project-merge.ts ✏️ Cursor's functions exposed as one `ProjectHooksFormat`, behaviour unchanged +│ ├── capabilities/plugins-capability.ts ✏️ `hooksDestination: "project"` + `projectHooksRelativePath` + `projectHooksFormat` allowed on flat params too +│ ├── build-contract.ts ✏️ `hooksMerge` receives the plugin name +│ └── profiles/ +│ ├── cursor/profile.ts ✏️ declares Cursor's `ProjectHooksFormat` +│ └── antigravity/ +│ ├── antigravity-hooks.ts ✅ named-hook shape: one `` key, handlers under `SessionStart`, `cd .. && ` prefix, other events skipped with a warning +│ ├── profile.ts ✏️ flat `acceptsHooks: true`, `hooksDestination: "project"` on `.agents/hooks.json` +│ └── build.ts ✏️ hooks artifact: scripts under `.agents/hooks//`, hooksMerge into `.agents/hooks.json` +├── src/contexts/framework/application/ +│ ├── framework/translator/project-hooks-materializer.ts ✏️ reads the tool's `ProjectHooksFormat`; invalid JSON names the file; messages name the tool +│ └── shared/remove-project-hooks.ts ✏️ same, no Cursor import left +├── src/contexts/translate/application/strategies/flat-build-strategy.ts ✏️ passes the plugin name to `hooksMerge` ├── tests/contexts/tools/domain/profiles/antigravity/ -│ └── antigravity-hooks.unit.test.ts ✅ merge, idempotence, foreign keys kept, invalid JSON, strip -├── tests/contexts/tools/domain/build-hooks-support-declaration.unit.test.ts ✏️ antigravity now supports hooks +│ └── antigravity-hooks.unit.test.ts ✅ merge, idempotence, foreign keys kept, invalid JSON, unmerge, empty check, unmapped event warning +├── tests/ (Cursor project-hooks suites) ✏️ only messages that named Cursor generically, if any; behaviour assertions untouched +├── tests/ (antigravity profile, build, build-hooks-support-declaration, registry-conformance) ✏️ antigravity now delivers hooks to `.agents/hooks.json` └── tests/golden/snapshots/framework-build/golden.json ✏️ `antigravity:flat` cell only ``` @@ -26,10 +39,10 @@ cli/ ```mermaid flowchart TD - A[aidd setup --ai antigravity] --> B[.agents/hooks.json gains key aidd-memory with SessionStart command] + A[aidd setup --ai antigravity] --> B[.agents/hooks.json gains key aidd-context with SessionStart command, script under .agents/hooks/aidd-context/] B --> C[agy new session in trusted folder] C --> D[log: loaded N named hooks; memory refresh runs at repo root] - E[aidd clean antigravity] --> F[aidd-memory key removed, other named hooks kept, file deleted only if empty] + E[aidd clean antigravity] --> F[aidd-context key and its scripts removed, other named hooks kept, file deleted only if empty] ``` ## Test Scope @@ -40,9 +53,9 @@ title: Test scope --- journey section Setup - agy 1.2.14 logged in, probe hook printing cwd and workspacePaths => measured cwd recorded: 5: system + agy 1.2.17 logged in, interactive session under a pty, probe hook printing cwd and workspacePaths => measured cwd recorded: 5: system section Happy path - aidd setup --ai antigravity on empty project => .agents/hooks.json has aidd-memory SessionStart entry: 5: cli + aidd setup --ai antigravity on empty project => .agents/hooks.json has aidd-context SessionStart entry: 5: cli second setup => file byte-identical: 5: cli translate --to antigravity --as flat => same hooks.json shape and scripts under .agents/hooks/: 5: cli section Edge case - user hooks present @@ -55,25 +68,29 @@ journey ## Tasks to do -### `1)` Measure the hook `cwd` on 1.2.14 +### `1)` Measure the hook `cwd` on 1.2.17 > #890 measured `cwd = /.agents` on 1.2.5; `update_memory.js` silently no-ops when `aidd_docs/` is not in `cwd`. -1. Local probe: a `SessionStart` hook writing `pwd` and its stdin payload to a marker; read the marker, not the turn. -2. Pick the command from the result: if `cwd` is `.agents`, the command must reach the repo root (e.g. `node ../.aidd/scripts/update_memory.cjs`, or a root resolved from `workspacePaths[0]`); record the evidence in the PR. +1. Local probe: a `SessionStart` hook writing `pwd` and its stdin payload to a marker; read the marker, not the turn. On 1.2.17 a print-mode turn never reaches the model and fires no hook at all, so the probe runs interactive under a pty: `script -q /dev/null agy -i "reply OK" --add-dir `, killed after 60s. Without `--add-dir` it loads 0 hooks. +2. Measured on 2026-10-05: `cwd` is `/.agents`, as on 1.2.5; stdin carries `workspacePaths[0]` = ``. A root-relative command needs a `cd .. && ` prefix, and `agy` runs it through a shell: a real session running `cd .. && node ` wrote `AIDD-MEMORY-MARKER cwd= docs=true`. Record the evidence in the PR. -### `2)` Named-hook merge, test first +### `2)` Named-hook format, test first -> Shape `{ "": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "…", "timeout": 30 } ] } ] } }`, no wrapper. +> Shape `{ "": { "SessionStart": [ { "type": "command", "command": "…", "timeout": 30 } ] } }`: no top-level `hooks` wrapper, and handlers sit directly under the event. 1.2.17 rejects the Claude-style nested `[ { "hooks": [ … ] } ]` with `command hook must specify 'command'`; only `PreToolUse` and `PostToolUse` take a `matcher` entry. -1. Tests: empty file, existing foreign keys, re-run idempotent, invalid JSON fails loud (Codex's silent `catch { parsed = {} }` is not copied), strip leaves foreign keys. -2. Implement in `antigravity-hooks.ts`; mutate the foreign-key preservation and watch its test fail. +1. Tests: empty file, existing foreign keys, re-run idempotent, invalid JSON fails loud (Codex's silent `catch { parsed = {} }` is not copied), unmerge leaves foreign keys, empty check, an event other than `SessionStart` skipped with a warning (Claude and `agy` tool names differ; the telemetry host is out of scope). +2. Implement in `antigravity-hooks.ts` as a `ProjectHooksFormat`: the key is the plugin name, each command gets `cd .. && ` and runs `./.agents/hooks//