agy-context-saver 1.5.0 → 1.6.1

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 CHANGED
@@ -5,6 +5,44 @@ All notable changes to `Agy-Context-Saver` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.6.1] - 2026-10-12
9
+
10
+ ### Added
11
+ - **Dual-MCP Waymark Code Intelligence & Subagent Synergy Suite (`tests/test-waymark-synergy.mjs`)**: Added a 6-trial automated integration and benchmark suite (`npm run test:synergy` / `npm test`) spawning both `agy-context-saver` and `waymark-engine` over concurrent JSON-RPC 2.0 stdio streams (with a deterministic `WAYMARK_FORCE_SHIM=1` fallback for standalone CI runners). Validates AST-narrowed `subagent_brief` generation, Pointer-Over-Wire (POW) to `waymark_memory` consensus charting with Anti-Hallucination Guard checks, 4-layer token compression benchmarking, combined context health + Semantic Repo Map status audits, missing-facet multi-subagent orchestration, and `.mjs` Tree-sitter AST extraction.
12
+ - **Aggressive RTK Read Shim Support (`tests/helpers/hermetic-fixture.mjs`)**: Enhanced the hermetic RTK CLI shim to support `rtk read --level aggressive` comment stripping for deterministic cross-platform token compression benchmarks.
13
+
14
+ ---
15
+
16
+ ## [1.6.0] - 2026-10-12
17
+
18
+ ### Added
19
+ - **Full Cycle Product Development (FCPD) Strategic Roadmap**: Published `docs/roadmap.md` establishing a phased product architecture grounded in FCPD methodology: MVP hardening (shipped in v1.6.0), public validation & bug triage loop, and Antigravity ecosystem scale.
20
+ - **Multi-Role Subagent Batching & Pointer-Over-Wire (POW)**: Added turnkey multi-agent batch configuration in `subagent_brief` (`subagents` array) with per-agent role, model, and workspace customizability. Validated across single-subagent, multi-role, and error-recovery trials (`tests/test-subagent-trials.mjs`).
21
+ - **Comprehensive MCP Tool, Prompt & CLI Reference**: Authored an exhaustive handbook in `docs/tools.md` detailing all 6 canonical MCP tools with parameter tables, concrete JSON-RPC payloads, sample outputs, forensic search walkthroughs, and diagnostic triage playbooks.
22
+ - **Labeled Diagnostic Telemetry**: Refined `check_context_health` with explicit labeled sections (`[Active Session Metrics]` vs. `[Local RTK Environment]`), eliminating metric ambiguity between active conversation byte weight and machine-wide cumulative `rtk gain` host tokens.
23
+
24
+ ### Changed
25
+ - **Broadened Multi-Agent Positioning**: Shifted documentation and positioning from a narrow coding focus to affordable, reliable multi-agent workflows across general tasks (development, deep research, operations, analysis, and document drafting).
26
+ - **Subagent Brief Schema Freeze**: Formally froze `subagent_brief` as a lightweight ergonomic utility adhering strictly to YAGNI principles; rejected feature creep (finding ledgers, citation judges, blinding switches).
27
+ - **Zensical Documentation Navigation**: Registered `docs/roadmap.md` in navigation and validated zero dead anchors across the entire documentation site (`zensical build`).
28
+ - **Release-Readiness & Hero Positioning**: Elevated Pointer-Over-Wire (POW) and the Enterprise Non-Destructive Guarantee to landing hero sections, added the flagship before/after comparison table to `README.md`, unified the 3-Layer Governance taxonomy, and completed 100% parameter tables in `docs/tools.md`.
29
+
30
+ ### Security, Installer Hardening & Hermetic CI
31
+ - **Strict Read-Only `--check` & CLI Flag Validation (`scripts/install-register.mjs`, `mcp/index.js`, `install.ps1`)**: Hoisted `--check` pre-flight validation ahead of all filesystem and network operations, added fail-closed `parseAndValidateJsonConfig()` checks on existing `hooks.json` and `mcp_config.json` before any writes or `--check` success returns, and rejected conflicting read-only + mutating CLI flags (`--check --restore-backups`, `--check --uninstall`, `--check --status`) with exit code `1`.
32
+ - **Windows `install.ps1` Wrapper Safety (`install.ps1`)**: Reordered `install.ps1` to execute `scripts/install-register.mjs` validation **before** writing `node.cmd`, added automatic backup (`.bak`) for pre-existing unmanaged `node.cmd` wrappers, and added clean wrapper removal/restoration during `--uninstall`.
33
+ - **RTK Supply-Chain SHA-256 Verification & Semver Pinning (`scripts/provision-rtk.mjs`, `scripts/execution-guard-hook.mjs`)**: Pinned RTK provisioning to `v0.51.0` with precomputed SHA-256 archive digest verification across all 5 supported OS/arch targets, enforced strict `[>=0.50.0 <0.52.0]` runtime compatibility without bypasses, and updated `execution-guard-hook.mjs` (`resolveCompatibleRtk()`) to fall back to the compatible local binary path when `PATH` contains an incompatible RTK version.
34
+ - **10-Suite Hermetic Test Matrix & Cross-OS CI (`tests/helpers/hermetic-fixture.mjs`, `.github/workflows/ci-matrix.yml`)**: Expanded automated verification from 8 to 10 hermetic test suites (`test-check-only-readonly.mjs`, `test-malformed-config-preservation.mjs`, and shared `setupHermeticTestEnv()` fixtures) running with zero host-profile mutation across Ubuntu, macOS, and Windows on Node.js 22 and 24.
35
+ - **Release Engineering & Governance Policies (`scripts/release-preflight.mjs`, `.github/workflows/release-tag.yml`)**: Added non-destructive release preflight validation, tag-gated npm Trusted Publishing (`--provenance`), and repository governance policies (`SECURITY.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `docs/INSTALLER-HARDENING.md`, `docs/RTK-SUPPORT-MATRIX.md`).
36
+
37
+ ## [1.5.1] - 2026-10-11
38
+
39
+ ### Added
40
+ - **Bounded Slice Safe Harbor for `view_file`**: Added support for bounded line slice inspection (`StartLine` & `EndLine` $\le 150$ lines) directly in `execution-guard-hook.mjs`. Enables surgical, token-efficient code inspections (e.g. reviewing specific function bodies, classes, or test spans) natively without triggering hook denials or requiring subagents to fall back to custom Node.js reading scripts.
41
+
42
+ ### Changed
43
+ - **Anti-Gaming Inspection Guidance**: Preserved the original denial message (`Run 'rtk read <file>' via run_command instead`) for standard unbounded `view_file` calls with zero slice advertisement, preventing LLM agents from systematically gaming the system with synthetic line slices to bypass RTK. Oversized slice guidance is surfaced only when the caller explicitly attempts an inspection exceeding 150 lines.
44
+ - **Root Protection Integrity**: Maintained absolute root-level denial on internal execution state (`.system_generated/`) ahead of the slice safe harbor, ensuring bounded ranges cannot be used to inspect raw transcripts or active task logs.
45
+
8
46
  ## [1.5.0] - 2026-10-08
9
47
 
10
48
  ### Performance & Memory Optimizations
@@ -123,3 +161,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
123
161
  - Initial release of Agy-Context-Saver.
124
162
  - Antigravity Model Context Protocol (MCP) server.
125
163
  - Background task lifecycle governance and reactive wakeup enforcement.
164
+
165
+ [1.6.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.6.0...v1.6.1
166
+ [1.6.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.5.1...v1.6.0
167
+ [1.5.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.5.0...v1.5.1
168
+ [1.5.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.4.0...v1.5.0
169
+ [1.4.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.3.2...v1.4.0
170
+ [1.3.2]: https://github.com/paragon-ux/agy-context-saver/compare/v1.3.1...v1.3.2
171
+ [1.3.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.3.0...v1.3.1
172
+ [1.3.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.2.1...v1.3.0
173
+ [1.2.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.2.0...v1.2.1
174
+ [1.2.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.1.0...v1.2.0
175
+ [1.1.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.0.0...v1.1.0
176
+ [1.0.0]: https://github.com/paragon-ux/agy-context-saver/releases/tag/v1.0.0
package/README.md CHANGED
@@ -13,6 +13,29 @@ It permanently eliminates session degradation, memory bloat, and context window
13
13
 
14
14
  ---
15
15
 
16
+ ## Core Value Proposition
17
+
18
+ | Metric / Capability | Without Governor | With Agy-Context-Saver + RTK |
19
+ | :--- | :--- | :--- |
20
+ | **Command Output Bloat** | Unlimited raw test dots, ANSI dumps | RTK transparent reduction (60–90% token savings) |
21
+ | **Workspace File Inspection** | Massive uncompressed view_file dumps | Compact `rtk read`, `rtk grep`, `rtk find` |
22
+ | **Long Command Execution** | Detached after 5s $\to$ busy-wait loop | Synchronous window expanded to 10s $\to$ finishes in-turn |
23
+ | **Background Task Monitoring** | Repetitive busy-polling loops | Enforced Reactive Wakeup with 5-strike circuit breaker |
24
+ | **Subagent Delegation** | In-band truncated >16KB JSON dumps | Pointer-Over-Wire (POW) protocols via `subagent_brief` |
25
+ | **Configuration Safety** | Risk of third-party config clobber | Non-destructive preservation of foreign hooks/MCP with `.bak` backups |
26
+ | **Transcript Review** | Raw JSONL dumped into context | Clean human-readable Markdown via `read_transcript` |
27
+ | **Runtime Dependencies** | N/A | **Zero** external npm dependencies (100% Node.js stdlib) + native RTK binary |
28
+
29
+ ---
30
+
31
+ ## Canonical 3-Layer Governance Architecture
32
+
33
+ 1. **Layer 1: Reactive Lifecycle & Polling Immunity**: Replaces destructive busy-polling loops with native Antigravity **Reactive Wakeup**, governed by an exponential Proportional Backoff curve and a 5-strike circuit breaker.
34
+ 2. **Layer 2: Transparent CLI & Codebase Streamlining**: Intercepts shell execution via PreToolUse hooks, transparently rewriting commands to RTK (`rtk git`, `rtk pytest`), hard-routing workspace searches to `rtk read`/`find`/`rg`, and shielding internal `.system_generated` state.
35
+ 3. **Layer 3: Orchestration, Delegation & Pointer-Over-Wire (POW)**: Expands synchronous execution windows to 10s and enforces Pointer-Over-Wire contracts across subagent teams (`subagent_brief`).
36
+
37
+ ---
38
+
16
39
  ## Quickstart (Instant Install)
17
40
 
18
41
  Install and synchronize the governor and RTK across your Antigravity environment:
@@ -28,6 +51,9 @@ npm run setup
28
51
  npm run status
29
52
  ```
30
53
 
54
+ > [!TIP]
55
+ > **Enterprise Non-Destructive Guarantee**: Agy-Context-Saver requires **zero external npm dependencies** (100% native Node.js standard library), strictly preserves existing foreign hooks (e.g. `waymark-continuity`) and foreign MCP servers, automatically writes atomic `.bak` configuration backups, and supports clean 1-step rollback.
56
+
31
57
  ---
32
58
 
33
59
  ## Architectural Division of Responsibilities
@@ -79,12 +105,14 @@ npm run status
79
105
  2. **The Terminal Bloat Trap**: Routine test runs and git operations dump hundreds of lines of noise into context. RTK compresses these outputs natively before they enter model context.
80
106
  3. **The Raw Transcript Trap**: Reading `transcript.jsonl` dumps megabytes of raw JSON into context. Agy blocks direct reads of `.system_generated` and provides high-density Markdown streaming tools.
81
107
  4. **Native Inspection Bypass**: Native inspection tools (`view_file`, `grep_search`, `find_by_name`, `list_dir`) bypass token reduction. Agy hard-routes workspace inspection to RTK's canonical CLI (`rtk read`, `rtk grep`, `rtk find`, `rtk ls`).
108
+ 5. **The Subagent Truncation Trap**: When subagents return massive audits or code in-band over `send_message`, payloads exceed transport limits (~16 KB) and pollute parent context. Agy enforces **Pointer-Over-Wire (POW)**: subagents dump detailed reports to disk and transmit only high-signal summaries and clickable links.
82
109
 
83
110
  ---
84
111
 
85
112
  ## Key Capabilities
86
113
 
87
114
  - **Transparent RTK Rewriting**: Native `run_command` calls are automatically rewritten (e.g. `pytest` $\to$ `rtk pytest`) via Antigravity PreToolUse hooks.
115
+ - **Pointer-Over-Wire (POW) Subagent Architecture**: Equips `subagent_brief` payloads with isolated workspaces and file-pointer reporting, eliminating context pollution and message truncation during multi-agent workflows.
88
116
  - **Canonical Codebase Inspection**:
89
117
  - `rtk read <file>`: Read file with intelligent token filtering and line ranges.
90
118
  - `rtk find <path>`: Compact file search tree and directory listing (cross-platform, works on Windows & POSIX).
@@ -111,8 +139,9 @@ For complete technical references, architectural specifications, and governance
111
139
  - 🏗️ **[Architecture & Internals](docs/architecture.md)**: Closed Execution Topology, RTK separation of concerns, and the Four Non-Fragile Architectural Pillars.
112
140
  - 🛡️ **[Lifecycle Governance & Hooks](docs/governance.md)**: Proportional Backoff curve, Reactive Wakeup invariants, and the 5-strike circuit breaker.
113
141
  - 🧰 **[MCP Tools & CLI Reference](docs/tools.md)**: Complete specifications for all 6 canonical autonomous MCP tools, slash commands, and diagnostic utilities.
114
- - 🔬 **[Forensic & Output Inspection](docs/architecture.md#6-output-governance--spillover-safe-harbor-0-new-tools)**: Ephemeral tool spillover resolution, post-mortem task retrieval, and Pointer-Over-Wire (POW) contracts.
142
+ - 🔬 **[Forensic & Output Inspection](docs/architecture.md#6-output-governance-spillover-safe-harbor-0-new-tools)**: Ephemeral tool spillover resolution, post-mortem task retrieval, and Pointer-Over-Wire (POW) contracts.
115
143
  - 🚀 **[Publishing & Verification Playbook](docs/publishing.md)**: Clean-room test runs, release procedures, and multi-suite verification matrix.
144
+ - 🗺️ **[Product Roadmap](docs/roadmap.md)**: Phased strategic roadmap focusing on affordable and reliable multi-agent workflows across general tasks.
116
145
 
117
146
  ---
118
147
 
@@ -146,7 +175,7 @@ node mcp/index.js status
146
175
  ```bash
147
176
  npm test
148
177
  ```
149
- *Runs all 7 test suites (hook governance, MCP protocol, output inspection governance, E2E probes, performance probes, installed verification, lifecycle rollback).*
178
+ *Runs all 11 test suites (hook governance, MCP protocol, output inspection governance, E2E probes, performance probes, installed verification, lifecycle rollback, subagent delegation trials, check-only read-only safety, malformed configuration preservation, and Waymark dual-MCP synergy).*
150
179
 
151
180
  ### 3. Run Targeted Tests Individually
152
181
  ```bash
@@ -170,6 +199,18 @@ node tests/test-installed-verification.mjs
170
199
 
171
200
  # Clean install/uninstall/restore lifecycle test
172
201
  node tests/test-lifecycle-rollback.mjs
202
+
203
+ # Subagent delegation trials & batching
204
+ node tests/test-subagent-trials.mjs
205
+
206
+ # Check-only read-only isolation regression test
207
+ node tests/test-check-only-readonly.mjs
208
+
209
+ # Malformed config preservation fail-closed regression test
210
+ node tests/test-malformed-config-preservation.mjs
211
+
212
+ # Dual-MCP Waymark code intelligence + subagent synergy suite
213
+ node tests/test-waymark-synergy.mjs
173
214
  ```
174
215
 
175
216
  ### 4. Test MCP Tools from Antigravity Agent
@@ -0,0 +1,51 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128" height="128">
2
+ <defs>
3
+ <linearGradient id="shieldGrad" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#4F46E5" />
5
+ <stop offset="50%" stop-color="#7C3AED" />
6
+ <stop offset="100%" stop-color="#2563EB" />
7
+ </linearGradient>
8
+ <linearGradient id="coreGrad" x1="0%" y1="0%" x2="100%" y2="100%">
9
+ <stop offset="0%" stop-color="#38BDF8" />
10
+ <stop offset="100%" stop-color="#818CF8" />
11
+ </linearGradient>
12
+ <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
13
+ <feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#4F46E5" flood-opacity="0.35" />
14
+ </filter>
15
+ </defs>
16
+
17
+ <!-- Outer Shield Outline -->
18
+ <path d="M 64 12 C 86 24 104 28 108 30 C 108 64 96 98 64 116 C 32 98 20 64 20 30 C 24 28 42 24 64 12 Z"
19
+ fill="none"
20
+ stroke="url(#shieldGrad)"
21
+ stroke-width="5"
22
+ stroke-linejoin="round"
23
+ filter="url(#glow)" />
24
+
25
+ <!-- Inner Protective Plate -->
26
+ <path d="M 64 22 C 82 32 94 35 98 37 C 98 65 88 92 64 106 C 40 92 30 65 30 37 C 34 35 46 32 64 22 Z"
27
+ fill="url(#shieldGrad)"
28
+ fill-opacity="0.12"
29
+ stroke="url(#coreGrad)"
30
+ stroke-width="2.5"
31
+ stroke-linejoin="round" />
32
+
33
+ <!-- Dynamic Energy Node / Context Saver Symbol -->
34
+ <!-- Central Pulse Ring -->
35
+ <circle cx="64" cy="62" r="14" fill="none" stroke="url(#coreGrad)" stroke-width="3" stroke-dasharray="4 3" />
36
+
37
+ <!-- Central Shield Core Dot -->
38
+ <circle cx="64" cy="62" r="6" fill="url(#coreGrad)" />
39
+
40
+ <!-- Synapse Rings (Context Boundary Links) -->
41
+ <line x1="64" y1="36" x2="64" y2="48" stroke="#38BDF8" stroke-width="3" stroke-linecap="round" />
42
+ <line x1="64" y1="76" x2="64" y2="88" stroke="#38BDF8" stroke-width="3" stroke-linecap="round" />
43
+ <line x1="42" y1="62" x2="50" y2="62" stroke="#818CF8" stroke-width="3" stroke-linecap="round" />
44
+ <line x1="78" y1="62" x2="86" y2="62" stroke="#818CF8" stroke-width="3" stroke-linecap="round" />
45
+
46
+ <!-- Node Dots -->
47
+ <circle cx="64" cy="34" r="3.5" fill="#38BDF8" />
48
+ <circle cx="64" cy="90" r="3.5" fill="#38BDF8" />
49
+ <circle cx="40" cy="62" r="3.5" fill="#818CF8" />
50
+ <circle cx="88" cy="62" r="3.5" fill="#818CF8" />
51
+ </svg>
package/install.ps1 CHANGED
@@ -1,42 +1,86 @@
1
- # Agy-Context-Saver Universal Installer for Windows
2
- # Installs hook script, wrapper, and registers in ~/.gemini/config/hooks.json & mcp_config.json
3
-
4
- $ErrorActionPreference = "Stop"
5
-
6
- $GeminiConfigDir = [System.IO.Path]::Combine($env:USERPROFILE, ".gemini", "config")
7
- $DestHook = [System.IO.Path]::Combine($GeminiConfigDir, "scripts", "execution-guard-hook.mjs")
8
-
9
- # 1. Ensure ~/.gemini/config exists
10
- if (-not (Test-Path $GeminiConfigDir)) {
11
- New-Item -ItemType Directory -Path $GeminiConfigDir -Force | Out-Null
12
- }
13
-
14
- # 2. Create node.cmd wrapper in ~/.gemini/config (prevents Windows cmd quote issues)
15
- $NodeCmdPath = [System.IO.Path]::Combine($GeminiConfigDir, "node.cmd")
16
- $NodeCmdLines = @(
17
- '@echo off',
18
- 'setlocal',
19
- 'set "ARGS=%*"',
20
- '',
21
- 'echo %ARGS% | findstr /i "execution-guard" >nul',
22
- 'if %errorlevel% equ 0 (',
23
- " `"C:\Program Files\nodejs\node.exe`" `"$DestHook`"",
24
- ' exit /b %errorlevel%',
25
- ')',
26
- '',
27
- 'echo %ARGS% | findstr /i "waymark" >nul',
28
- 'if %errorlevel% equ 0 (',
29
- ' "C:\Program Files\nodejs\node.exe" "%USERPROFILE%\Desktop\Frameworks\Deepseek-Project\Waymark\scripts\hooks\waymark-compact-hook.mjs"',
30
- ' exit /b %errorlevel%',
31
- ')',
32
- '',
33
- 'echo {"decision": "allow"}',
34
- 'exit /b 0'
35
- )
36
- $NodeCmdContent = $NodeCmdLines -join "`r`n"
37
- Set-Content -Path $NodeCmdPath -Value $NodeCmdContent -Encoding ASCII
38
- Write-Host "[OK] Node wrapper installed to: $NodeCmdPath" -ForegroundColor Green
39
-
40
- # 3. Run cross-platform registration engine
41
- $RegisterScript = [System.IO.Path]::Combine($PSScriptRoot, "scripts", "install-register.mjs")
42
- & node "$RegisterScript"
1
+ # Agy-Context-Saver Universal Installer for Windows
2
+ # Installs hook script, wrapper, and registers in ~/.gemini/config/hooks.json & mcp_config.json
3
+
4
+ $ErrorActionPreference = "Stop"
5
+
6
+ $ProfileRoot = if ($env:AGY_TEST_PROFILE_DIR) { $env:AGY_TEST_PROFILE_DIR } else { $env:USERPROFILE }
7
+ $GeminiConfigDir = [System.IO.Path]::Combine($ProfileRoot, ".gemini", "config")
8
+ $DestHook = [System.IO.Path]::Combine($GeminiConfigDir, "scripts", "execution-guard-hook.mjs")
9
+ $NodeCmdPath = [System.IO.Path]::Combine($GeminiConfigDir, "node.cmd")
10
+ $NodeCmdBakPath = [System.IO.Path]::Combine($GeminiConfigDir, "node.cmd.bak")
11
+
12
+ # Dynamic Node executable resolution
13
+ $NodeCmdObj = Get-Command node -ErrorAction SilentlyContinue
14
+ if ($NodeCmdObj -and $NodeCmdObj.Source) {
15
+ $NodeExe = $NodeCmdObj.Source
16
+ } elseif (Test-Path "C:\Program Files\nodejs\node.exe") {
17
+ $NodeExe = "C:\Program Files\nodejs\node.exe"
18
+ } else {
19
+ $NodeExe = "node"
20
+ }
21
+
22
+ # 1. Run cross-platform registration engine FIRST (validates config & provisions RTK before any wrapper write)
23
+ $RegisterScript = [System.IO.Path]::Combine($PSScriptRoot, "scripts", "install-register.mjs")
24
+ & $NodeExe "$RegisterScript" @args
25
+ $RegExitCode = $LASTEXITCODE
26
+ if ($RegExitCode -ne 0) {
27
+ exit $RegExitCode
28
+ }
29
+
30
+ $IsReadOnly = $args -contains "--check" -or $args -contains "-c" -or $args -contains "--status" -or $args -contains "status" -or $args -contains "--help" -or $args -contains "-h" -or $args -contains "help"
31
+ $IsUninstall = $args -contains "--uninstall" -or $args -contains "uninstall"
32
+ $IsRestoreOnly = ($args -contains "--restore-backups" -or $args -contains "restore-backups") -and (-not $IsUninstall)
33
+
34
+ if ($IsUninstall) {
35
+ if (Test-Path $NodeCmdPath) {
36
+ $ExistingContent = Get-Content -Path $NodeCmdPath -Raw -ErrorAction SilentlyContinue
37
+ if ($ExistingContent -match "agy-context-saver-managed") {
38
+ Remove-Item -Path $NodeCmdPath -Force -ErrorAction SilentlyContinue
39
+ if (Test-Path $NodeCmdBakPath) {
40
+ Copy-Item -Path $NodeCmdBakPath -Destination $NodeCmdPath -Force
41
+ Write-Host "[OK] Restored previous node.cmd from backup: $NodeCmdBakPath" -ForegroundColor Green
42
+ } else {
43
+ Write-Host "[OK] Removed managed node.cmd wrapper: $NodeCmdPath" -ForegroundColor Green
44
+ }
45
+ }
46
+ }
47
+ exit 0
48
+ }
49
+
50
+ if (-not $IsReadOnly -and -not $IsRestoreOnly) {
51
+ # 2. Ensure ~/.gemini/config exists after preflight/registration succeeded
52
+ if (-not (Test-Path $GeminiConfigDir)) {
53
+ New-Item -ItemType Directory -Path $GeminiConfigDir -Force | Out-Null
54
+ }
55
+
56
+ # Preserve any pre-existing unmanaged node.cmd wrapper
57
+ if (Test-Path $NodeCmdPath) {
58
+ $ExistingWrapper = Get-Content -Path $NodeCmdPath -Raw -ErrorAction SilentlyContinue
59
+ if ($ExistingWrapper -and ($ExistingWrapper -notmatch "agy-context-saver-managed") -and (-not (Test-Path $NodeCmdBakPath))) {
60
+ Copy-Item -Path $NodeCmdPath -Destination $NodeCmdBakPath -Force
61
+ Write-Host "[OK] Backed up existing node.cmd to: $NodeCmdBakPath" -ForegroundColor Green
62
+ }
63
+ }
64
+
65
+ # 3. Create managed node.cmd wrapper in ~/.gemini/config (delegates non-governor calls to real node.exe)
66
+ $NodeCmdLines = @(
67
+ '@echo off',
68
+ 'REM agy-context-saver-managed',
69
+ 'setlocal',
70
+ 'set "ARGS=%*"',
71
+ '',
72
+ 'echo %ARGS% | findstr /i "execution-guard" >nul',
73
+ 'if %errorlevel% equ 0 (',
74
+ " `"$NodeExe`" `"$DestHook`"",
75
+ ' exit /b %errorlevel%',
76
+ ')',
77
+ '',
78
+ "`"$NodeExe`" %*",
79
+ 'exit /b %errorlevel%'
80
+ )
81
+ $NodeCmdContent = $NodeCmdLines -join "`r`n"
82
+ Set-Content -Path $NodeCmdPath -Value $NodeCmdContent -Encoding ASCII
83
+ Write-Host "[OK] Node wrapper installed to: $NodeCmdPath" -ForegroundColor Green
84
+ }
85
+
86
+ exit 0
package/mcp/index.js CHANGED
@@ -28,30 +28,51 @@ import os from "node:os";
28
28
  import path from "node:path";
29
29
  import readline from "node:readline";
30
30
  import { fileURLToPath } from "node:url";
31
- import { runInstall, runUninstall, runStatus, detectExistingInstallation } from "../scripts/install-register.mjs";
31
+ import { runInstall, runUninstall, runStatus, runRestoreBackups, detectExistingInstallation } from "../scripts/install-register.mjs";
32
32
  import { findExistingRtk } from "../scripts/provision-rtk.mjs";
33
33
 
34
34
  // Handle CLI subcommands (e.g. npx agy-context-saver install)
35
- const cliArg = process.argv[2];
36
- const checkFlag = process.argv.includes("--check") || process.argv.includes("-c");
37
- if (cliArg === "install" || cliArg === "--install") {
38
- await runInstall({ checkOnly: checkFlag });
35
+ const cliArgs = process.argv.slice(2);
36
+ const cliArg = cliArgs[0];
37
+ const checkFlag = cliArgs.includes("--check") || cliArgs.includes("-c");
38
+ const statusFlag = cliArgs.includes("--status") || cliArgs.includes("status");
39
+ const uninstallFlag = cliArgs.includes("--uninstall") || cliArgs.includes("uninstall");
40
+ const restoreFlag = cliArgs.includes("--restore-backups") || cliArgs.includes("restore-backups");
41
+ const helpFlag = cliArgs.includes("--help") || cliArgs.includes("-h") || cliArgs.includes("help");
42
+ const allowDegraded = cliArgs.includes("--allow-degraded");
43
+
44
+ if (helpFlag) {
45
+ printHelp();
39
46
  process.exit(0);
40
- } else if (cliArg === "uninstall" || cliArg === "--uninstall") {
41
- const restoreBackups = process.argv.includes("--restore-backups");
42
- await runUninstall({ restoreBackups });
47
+ }
48
+ if ((checkFlag || statusFlag) && (uninstallFlag || restoreFlag)) {
49
+ console.error("Error: Read-only flags (--check, --status) cannot be combined with mutating flags (--uninstall, --restore-backups).");
50
+ process.exit(1);
51
+ }
52
+ if (checkFlag && statusFlag) {
53
+ console.error("Error: Conflicting flags: specify either --check or --status, not both.");
54
+ process.exit(1);
55
+ }
56
+ if (checkFlag) {
57
+ await runInstall({ checkOnly: true, allowDegraded });
43
58
  process.exit(0);
44
- } else if (cliArg === "status" || cliArg === "--status") {
59
+ } else if (statusFlag) {
45
60
  runStatus();
46
61
  process.exit(0);
47
- } else if (cliArg === "--help" || cliArg === "-h" || cliArg === "help") {
48
- printHelp();
62
+ } else if (uninstallFlag) {
63
+ await runUninstall({ restoreBackups: restoreFlag });
64
+ process.exit(0);
65
+ } else if (restoreFlag) {
66
+ await runRestoreBackups();
67
+ process.exit(0);
68
+ } else if (cliArg === "install" || cliArg === "--install") {
69
+ await runInstall({ allowDegraded });
49
70
  process.exit(0);
50
71
  }
51
72
 
52
73
  function printHelp() {
53
74
  console.log(`
54
- Agy-Context-Saver 🛡️ (v1.2.1)
75
+ Agy-Context-Saver 🛡️ (v1.6.1)
55
76
  Universal MCP Server & Lifecycle Governor for Google Antigravity (Powered by RTK)
56
77
 
57
78
  Usage:
@@ -98,7 +119,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
98
119
  const rulesPath = path.resolve(__dirname, "../rules/AGENTS.md");
99
120
 
100
121
  const SERVER_NAME = "agy-context-saver";
101
- const SERVER_VERSION = "1.5.0";
122
+ const SERVER_VERSION = "1.6.1";
102
123
 
103
124
  // --- Tools Specification ---
104
125
  const TOOLS = [
@@ -121,13 +142,21 @@ const TOOLS = [
121
142
  },
122
143
  {
123
144
  name: "subagent_brief",
124
- description: "Generates a scope-isolated, anti-bloat prompt for invoking a subagent. Instructs the subagent to absorb all intermediate file reads/searches and return only high-signal findings.",
145
+ description: "Generates scope-isolated, anti-bloat prompts and ready-to-use invoke_subagent JSON payloads for single or multiple delegated subagents. Instructs subagents to absorb intermediate file reads/searches and return only high-signal findings.",
125
146
  inputSchema: {
126
147
  type: "object",
127
148
  properties: {
128
149
  objective: {
129
150
  type: "string",
130
- description: "The core research or investigative objective."
151
+ description: "The core research or investigative objective (for single subagent)."
152
+ },
153
+ role: {
154
+ type: "string",
155
+ description: "2-5 word role description (e.g. 'Comprehensive Test Engineer', 'Codebase Security Auditor'). Defaults to 'Scope-Isolated Deep Research Subagent'."
156
+ },
157
+ instructions: {
158
+ type: "string",
159
+ description: "Optional step-by-step instructions or specialized directives."
131
160
  },
132
161
  scopeFiles: {
133
162
  type: "array",
@@ -137,9 +166,40 @@ const TOOLS = [
137
166
  expectedDeliverable: {
138
167
  type: "string",
139
168
  description: "The concise format expected back by the parent agent."
169
+ },
170
+ typeName: {
171
+ type: "string",
172
+ description: "Subagent type name: 'self' (default, inherits parent tools/prompt/model) or 'research' (read-only)."
173
+ },
174
+ model: {
175
+ type: "string",
176
+ enum: ["inherit", "flash_lite", "flash", "pro"],
177
+ description: "Model tier: 'inherit' (default), 'flash_lite', 'flash', or 'pro'."
178
+ },
179
+ workspace: {
180
+ type: "string",
181
+ enum: ["inherit", "branch", "share"],
182
+ description: "Workspace isolation: 'inherit' (default), 'branch', or 'share'."
183
+ },
184
+ subagents: {
185
+ type: "array",
186
+ description: "Optional array of subagent configurations to formulate multiple subagents at once.",
187
+ items: {
188
+ type: "object",
189
+ properties: {
190
+ role: { type: "string", description: "2-5 word role description." },
191
+ objective: { type: "string", description: "The core objective for this subagent." },
192
+ instructions: { type: "string", description: "Optional step-by-step instructions." },
193
+ scopeFiles: { type: "array", items: { type: "string" }, description: "Files/directories to investigate." },
194
+ expectedDeliverable: { type: "string", description: "Expected deliverable format." },
195
+ typeName: { type: "string", description: "Subagent type name: 'self' or 'research'." },
196
+ model: { type: "string", enum: ["inherit", "flash_lite", "flash", "pro"], description: "Model tier." },
197
+ workspace: { type: "string", enum: ["inherit", "branch", "share"], description: "Workspace isolation." }
198
+ },
199
+ required: ["objective"]
200
+ }
140
201
  }
141
- },
142
- required: ["objective"]
202
+ }
143
203
  }
144
204
  },
145
205
  {
@@ -365,19 +425,25 @@ async function handleCheckContextHealth(args = {}) {
365
425
  const rtkInfo = findExistingRtk();
366
426
  const reportLines = [
367
427
  `### Context Health Report: ${healthStatus}`,
428
+ "",
429
+ "#### [Active Session Metrics]",
368
430
  `- Total Steps: ${totalSteps}`,
369
431
  `- User Turns: ${userTurns}`,
370
432
  `- Assistant Responses: ${modelTurns}`,
371
433
  `- Tool Calls: ${toolCalls}`,
372
434
  `- Detected Busy-Polling Events: ${pollingEvents}`,
373
- `- Approximate Raw Transcript Size: ${kb} KB`,
374
- `- RTK Command Optimizer: ${rtkInfo ? `Active (${rtkInfo.version})` : "Missing (run sync_installation)"}`
435
+ `- Approximate Raw Transcript Size: ${kb} KB`
375
436
  ];
376
437
 
377
438
  if (corruptLines > 0) {
378
439
  reportLines.push(`- Corrupted/Unparsed Lines: ${corruptLines}`);
379
440
  }
380
441
 
442
+ reportLines.push("");
443
+ reportLines.push("#### [Local RTK Environment]");
444
+ reportLines.push(`- RTK Command Optimizer: ${rtkInfo ? `Active (${rtkInfo.version})` : "Missing (run sync_installation)"}`);
445
+ reportLines.push(`- Note: Lifetime token gains from 'rtk gain' represent cumulative machine-wide host savings, not single-session metrics.`);
446
+
381
447
  reportLines.push("");
382
448
  if (pollingEvents > 0) {
383
449
  reportLines.push("⚠️ Recommendation: Background polling detected! Cease manage_task(status) calls and yield execution to native Reactive Wakeup.");
@@ -397,11 +463,18 @@ async function handleCheckContextHealth(args = {}) {
397
463
  }
398
464
  }
399
465
 
400
- function handleSubagentBrief({ objective, scopeFiles = [], expectedDeliverable = "Synthesized factual findings" }) {
401
- const scopeStr = scopeFiles.length ? `\n\nTarget files:\n${scopeFiles.map(f => `- ${f}`).join("\n")}` : "";
402
- const prompt = [
403
- `ROLE: Scope-Isolated Deep Research Subagent`,
404
- `OBJECTIVE: ${objective}${scopeStr}`,
466
+ function formatSingleBrief({
467
+ role = "Scope-Isolated Deep Research Subagent",
468
+ objective = "",
469
+ instructions = "",
470
+ scopeFiles = [],
471
+ expectedDeliverable = "Synthesized factual findings"
472
+ } = {}) {
473
+ const scopeStr = scopeFiles && scopeFiles.length ? `\n\nTarget files:\n${scopeFiles.map(f => `- ${f}`).join("\n")}` : "";
474
+ const instrStr = instructions && instructions.trim() ? `\n\nSPECIFIC INSTRUCTIONS:\n${instructions.trim()}` : "";
475
+ return [
476
+ `ROLE: ${role}`,
477
+ `OBJECTIVE: ${objective}${scopeStr}${instrStr}`,
405
478
  ``,
406
479
  `CRITICAL CONTEXT GOVERNANCE INSTRUCTIONS (POINTER-OVER-WIRE):`,
407
480
  `1. Isolated Workspace: Do all necessary multi-file exploration, searches, and analysis in this subagent sandbox.`,
@@ -415,8 +488,71 @@ function handleSubagentBrief({ objective, scopeFiles = [], expectedDeliverable =
415
488
  `4. Format: ${expectedDeliverable}`,
416
489
  `5. Citation Mandate: Keep your final response concise, structured, and cite exact file:line references.`
417
490
  ].join("\n");
491
+ }
492
+
493
+ function handleSubagentBrief(args = {}) {
494
+ let specs = [];
495
+ if (Array.isArray(args.subagents) && args.subagents.length > 0) {
496
+ specs = args.subagents;
497
+ } else if (args.objective || args.role || args.instructions) {
498
+ specs = [args];
499
+ } else {
500
+ return {
501
+ isError: true,
502
+ content: [{ type: "text", text: "subagent_brief error: provide either 'objective' (for a single subagent) or 'subagents' array (for multiple subagents)." }]
503
+ };
504
+ }
505
+
506
+ const subagentsPayload = [];
507
+ const renderedBriefs = [];
508
+
509
+ for (let i = 0; i < specs.length; i++) {
510
+ const spec = specs[i] || {};
511
+ const role = spec.role || spec.Role || "Scope-Isolated Deep Research Subagent";
512
+ const objective = spec.objective || spec.Objective || "";
513
+ const instructions = spec.instructions || spec.Instructions || "";
514
+ const scopeFiles = spec.scopeFiles || spec.ScopeFiles || [];
515
+ const expectedDeliverable = spec.expectedDeliverable || spec.ExpectedDeliverable || "Synthesized factual findings";
516
+ const typeName = spec.typeName || spec.TypeName || "self";
517
+ const model = spec.model || spec.Model || "inherit";
518
+ const workspace = spec.workspace || spec.Workspace || "inherit";
519
+
520
+ const promptText = formatSingleBrief({
521
+ role,
522
+ objective,
523
+ instructions,
524
+ scopeFiles,
525
+ expectedDeliverable
526
+ });
418
527
 
419
- return { content: [{ type: "text", text: prompt }] };
528
+ subagentsPayload.push({
529
+ TypeName: typeName,
530
+ Role: role,
531
+ Model: model,
532
+ Workspace: workspace,
533
+ Prompt: promptText
534
+ });
535
+
536
+ if (specs.length === 1) {
537
+ renderedBriefs.push(promptText);
538
+ } else {
539
+ renderedBriefs.push(`### Subagent ${i + 1}: ${role}\n${promptText}`);
540
+ }
541
+ }
542
+
543
+ const payloadJson = JSON.stringify({ Subagents: subagentsPayload }, null, 2);
544
+
545
+ const fullText = [
546
+ renderedBriefs.join("\n\n---\n\n"),
547
+ "",
548
+ "==================================================",
549
+ "READY-TO-USE invoke_subagent PAYLOAD:",
550
+ "```json",
551
+ payloadJson,
552
+ "```"
553
+ ].join("\n");
554
+
555
+ return { content: [{ type: "text", text: fullText }] };
420
556
  }
421
557
 
422
558
  function handleGetInstallationStatus() {
@@ -478,6 +614,14 @@ function extractConvId(p) {
478
614
  let cachedActiveConv = null;
479
615
  let cachedActiveConvTime = 0;
480
616
 
617
+ function getProfileHomeDir() {
618
+ return process.env.AGY_TEST_PROFILE_DIR || os.homedir();
619
+ }
620
+
621
+ function getBrainDir() {
622
+ return process.env.AGY_BRAIN_DIR || path.join(getProfileHomeDir(), ".gemini", "antigravity", "brain");
623
+ }
624
+
481
625
  function resolveTranscriptPath(target, mode = "compact") {
482
626
  const isFull = mode === "full";
483
627
  const fileName = isFull ? "transcript_full.jsonl" : "transcript.jsonl";
@@ -492,7 +636,7 @@ function resolveTranscriptPath(target, mode = "compact") {
492
636
  if (cachedActiveConv && (now - cachedActiveConvTime) < 5000) {
493
637
  raw = cachedActiveConv;
494
638
  } else {
495
- const brainDir = path.join(os.homedir(), ".gemini", "antigravity", "brain");
639
+ const brainDir = getBrainDir();
496
640
  try {
497
641
  const entries = fs.readdirSync(brainDir, { withFileTypes: true });
498
642
  let bestMtime = 0;
@@ -544,14 +688,14 @@ function resolveTranscriptPath(target, mode = "compact") {
544
688
  }
545
689
  }
546
690
 
547
- // 4. UUID / Directory resolution under ~/.gemini/antigravity/brain/<id>
548
- const homeDir = os.homedir();
549
- const brainCandidate = path.join(homeDir, ".gemini", "antigravity", "brain", normalized, ".system_generated", "logs", fileName);
691
+ // 4. UUID / Directory resolution under <brainDir>/<id>
692
+ const primaryBrainDir = getBrainDir();
693
+ const brainCandidate = path.join(primaryBrainDir, normalized, ".system_generated", "logs", fileName);
550
694
  if (fs.existsSync(brainCandidate)) {
551
695
  return { filePath: brainCandidate, convId: normalized };
552
696
  }
553
697
  if (isFull) {
554
- const compactFallback = path.join(homeDir, ".gemini", "antigravity", "brain", normalized, ".system_generated", "logs", "transcript.jsonl");
698
+ const compactFallback = path.join(primaryBrainDir, normalized, ".system_generated", "logs", "transcript.jsonl");
555
699
  if (fs.existsSync(compactFallback)) {
556
700
  return { filePath: compactFallback, convId: normalized };
557
701
  }