agy-context-saver 1.5.0 → 1.6.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 +42 -0
- package/README.md +40 -2
- package/assets/logo.svg +51 -0
- package/install.ps1 +86 -42
- package/mcp/index.js +174 -30
- package/package.json +18 -2
- package/plugin.json +9 -2
- package/rules/AGENTS.md +9 -4
- package/scripts/execution-guard-hook.mjs +174 -22
- package/scripts/install-register.mjs +177 -63
- package/scripts/provision-rtk.mjs +67 -14
- package/scripts/release-preflight.mjs +147 -0
- package/skills/context-governance/SKILL.md +26 -50
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ 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.0] - 2026-10-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **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.
|
|
12
|
+
- **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`).
|
|
13
|
+
- **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.
|
|
14
|
+
- **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.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **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).
|
|
18
|
+
- **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).
|
|
19
|
+
- **Zensical Documentation Navigation**: Registered `docs/roadmap.md` in navigation and validated zero dead anchors across the entire documentation site (`zensical build`).
|
|
20
|
+
- **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`.
|
|
21
|
+
|
|
22
|
+
### Security, Installer Hardening & Hermetic CI
|
|
23
|
+
- **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`.
|
|
24
|
+
- **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`.
|
|
25
|
+
- **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.
|
|
26
|
+
- **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.
|
|
27
|
+
- **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`).
|
|
28
|
+
|
|
29
|
+
## [1.5.1] - 2026-10-11
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- **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.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- **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.
|
|
36
|
+
- **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.
|
|
37
|
+
|
|
8
38
|
## [1.5.0] - 2026-10-08
|
|
9
39
|
|
|
10
40
|
### Performance & Memory Optimizations
|
|
@@ -123,3 +153,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
123
153
|
- Initial release of Agy-Context-Saver.
|
|
124
154
|
- Antigravity Model Context Protocol (MCP) server.
|
|
125
155
|
- Background task lifecycle governance and reactive wakeup enforcement.
|
|
156
|
+
|
|
157
|
+
[1.6.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.5.1...v1.6.0
|
|
158
|
+
[1.5.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.5.0...v1.5.1
|
|
159
|
+
[1.5.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.4.0...v1.5.0
|
|
160
|
+
[1.4.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.3.2...v1.4.0
|
|
161
|
+
[1.3.2]: https://github.com/paragon-ux/agy-context-saver/compare/v1.3.1...v1.3.2
|
|
162
|
+
[1.3.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.3.0...v1.3.1
|
|
163
|
+
[1.3.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.2.1...v1.3.0
|
|
164
|
+
[1.2.1]: https://github.com/paragon-ux/agy-context-saver/compare/v1.2.0...v1.2.1
|
|
165
|
+
[1.2.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.1.0...v1.2.0
|
|
166
|
+
[1.1.0]: https://github.com/paragon-ux/agy-context-saver/compare/v1.0.0...v1.1.0
|
|
167
|
+
[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
|
|
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
|
|
178
|
+
*Runs all 10 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, and malformed configuration preservation).*
|
|
150
179
|
|
|
151
180
|
### 3. Run Targeted Tests Individually
|
|
152
181
|
```bash
|
|
@@ -170,6 +199,15 @@ 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
|
|
173
211
|
```
|
|
174
212
|
|
|
175
213
|
### 4. Test MCP Tools from Antigravity Agent
|
package/assets/logo.svg
ADDED
|
@@ -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
|
-
$
|
|
7
|
-
$
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
$
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
36
|
-
$
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
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 (
|
|
59
|
+
} else if (statusFlag) {
|
|
45
60
|
runStatus();
|
|
46
61
|
process.exit(0);
|
|
47
|
-
} else if (
|
|
48
|
-
|
|
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.
|
|
75
|
+
Agy-Context-Saver 🛡️ (v1.6.0)
|
|
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.
|
|
122
|
+
const SERVER_VERSION = "1.6.0";
|
|
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
|
|
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
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
548
|
-
const
|
|
549
|
-
const brainCandidate = path.join(
|
|
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(
|
|
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
|
}
|