@only1btayy/g2w 1.0.32 → 1.0.33
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/README.md +118 -72
- package/hooks/g2w-resource-limits.js +239 -0
- package/lib/install.js +35 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,18 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
|
-
# G2W
|
|
8
|
-
|
|
9
|
-
The best relationships are built on trust. Trust comes from honesty, and honesty breeds clarity and understanding.
|
|
10
|
-
|
|
11
|
-
I got tired of going in circles with Claude and others because the systems I was using were not set up in a way that builds trust between the user and the model. Some of the top CEOs and big business people who use AI are not concerned with the question — "can it build?" Instead they are focused on — "can we trust what it builds and can we ship it?"
|
|
12
|
-
|
|
13
|
-
This is not just a workflow system. Not just a task runner. This is a protocol for building trust between you and your AI so what gets built is actually what you envisioned. No more back and forth and all the other bullshit that gets in the way.
|
|
14
|
-
|
|
15
|
-
**G2W is a relationship protocol.**
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
7
|
[](https://www.npmjs.com/package/@only1btayy/g2w)
|
|
20
8
|
[](LICENSE)
|
|
21
9
|
[](https://claude.ai/code)
|
|
@@ -31,13 +19,27 @@ npm install -g @only1btayy/g2w && g2w
|
|
|
31
19
|
|
|
32
20
|
---
|
|
33
21
|
|
|
34
|
-
[The Name](#the-name) · [The Problem](#the-problem) · [How It Works](#how-it-works) · [The Commands](#the-commands) · [How 2 Install](#how-2-install)
|
|
22
|
+
[The Name](#the-name) · [The Problem](#the-problem) · [How It Works](#how-it-works) · [Resource Limits](#resource-limits) · [The Commands](#the-commands) · [How 2 Install](#how-2-install)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# G2W
|
|
27
|
+
|
|
28
|
+
The best relationships are built on trust. Trust comes from honesty, and honesty breeds clarity and understanding.
|
|
29
|
+
|
|
30
|
+
I got tired of going in circles with Claude because the systems I was using weren't set up to build genuine trust between the user and the model. The top CEOs and business leaders using AI aren't asking "can it build?" They're asking "can we trust what it builds, and can we ship it?"
|
|
31
|
+
|
|
32
|
+
This is not just a workflow system. Not just a task runner. This is a protocol for building trust between you and your AI so what gets built is actually what you envisioned. No more back and forth, no more bullshit getting in the way.
|
|
33
|
+
|
|
34
|
+
**G2W is a relationship protocol.**
|
|
35
|
+
|
|
36
|
+
If you've ever felt like your AI was working against you instead of with you, G2W is for you.
|
|
35
37
|
|
|
36
38
|
---
|
|
37
39
|
|
|
38
40
|
## The Name
|
|
39
41
|
|
|
40
|
-
I named G2W after my motto in life
|
|
42
|
+
I named G2W after my motto in life: "It's going to work or it's going to work." This is a perspective shift I had that allows me to view even the apparent losses in life as wins because the gems are in the data. Every loss, every mistake, every doubt and fear we have is data that is filled with gems. We just have to choose to look at it that way. The people who change the world are often considered crazy and delusional until they actually change it. Then the "crazy" becomes genius and the "delusional" becomes relentless. I want you to dare to be relentless in your approach to the challenges in life and remember, it's going to work or it's going to work. Ain't no other options.
|
|
41
43
|
|
|
42
44
|
No in-between. No failure as an option. Two paths and both lead to success.
|
|
43
45
|
|
|
@@ -45,11 +47,28 @@ No in-between. No failure as an option. Two paths and both lead to success.
|
|
|
45
47
|
|
|
46
48
|
## The Problem
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
I want to preface this by saying I'm a vibe-coder. I have the utmost respect for actual devs and feel genuinely grateful to live in a time where tools like Claude and Codex let people like me get ideas out without needing to know how to code or have a big budget. I felt like I finally found my thing.
|
|
51
|
+
|
|
52
|
+
As many of you may have noticed, Claude seemed to take a noticeable dip in performance quality around February 2026. Some people swear it's just a matter of not knowing how to use it properly, and hey, great for you, but if you experienced the dip, you know exactly what I'm talking about.
|
|
53
|
+
|
|
54
|
+
He simply became unable to handle even simple tasks or edits. He'd go completely off the rails, then turn around and say "yeah you're right" over and over which drove me near insanity. I followed every recommended protocol, watched and read tutorial after tutorial, and even used the exact claude.md template that Boris Cherny shared on his X account. So you can miss me with the "oh you're just not using it right" talk. Claude worked great until he didn't. A lot of you can relate.
|
|
55
|
+
|
|
56
|
+
I'd say "make this button this size" and get back "I've already decided the current size is optimal." WTF.
|
|
57
|
+
|
|
58
|
+
Sound familiar?
|
|
59
|
+
|
|
60
|
+
- Spending an hour in a planning session, then having to repeat everything when it's time to execute
|
|
61
|
+
- Watching it make changes that break three other things it never bothered to check, then admit it after the fact
|
|
62
|
+
- Seeing it commit code you never approved
|
|
63
|
+
- Having it guess instead of just asking
|
|
49
64
|
|
|
50
|
-
|
|
65
|
+
I did try other systems along the way, like GSD 1 & 2 (Get Shit Done) by TACHES. It's great if you want AI to build everything out while you step away, but I wanted more control and involvement. I wanted to learn as I went, steer the ship, and understand how what I was building actually worked. GSD felt clunky and slow to me at times. No shade to what TACHES built though, it's wildly popular for a reason and he deserves every bit of the success he's seeing. It just wasn't the fit for me.
|
|
51
66
|
|
|
52
|
-
|
|
67
|
+
Deep down I knew there had to be something I could do to get Claude back on track. Even 80% of what he was when I started, I could live with that. Just not the full-blown-idiot-Claude days.
|
|
68
|
+
|
|
69
|
+
After collecting data from Reddit and Facebook posts, the lightbulb went off. That was the birth of G2W.
|
|
70
|
+
|
|
71
|
+
G2W was created for those of us who just want the AI to do what we ask. Simple. Nothing more, nothing less. Not by piling on more rules but by building a system that genuinely earns trust.
|
|
53
72
|
|
|
54
73
|
The problem was never intelligence. The problem was process.
|
|
55
74
|
|
|
@@ -61,27 +80,47 @@ The problem was never intelligence. The problem was process.
|
|
|
61
80
|
|
|
62
81
|
### The Modular Doc System
|
|
63
82
|
|
|
64
|
-
Every project gets a full set of living documents
|
|
83
|
+
Every project gets a full set of living documents auto-generated by `/g2w:bring2life`. The rule is simple: when you change code that any doc describes, update that doc in the same session. No separate documentation pass. No stale docs. The knowledge base stays current automatically.
|
|
84
|
+
|
|
85
|
+
All docs live in `~/.g2w/projects/[your-project]/`, zero footprint inside your actual repo.
|
|
86
|
+
|
|
87
|
+
| Document | What It Does |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `ARCHITECTURE.md` | System design, modules, data flow, how components connect |
|
|
90
|
+
| `CONVENTIONS.md` | Code style, naming patterns, project idioms, and a Context Budget that tells the AI which files to read selectively vs. fully |
|
|
91
|
+
| `FEATURES.md` | Complete list of what the project does and feature status |
|
|
92
|
+
| `ERRORS.md` | Bugs, dead code, anti-patterns, and security issues found during automatic code audit |
|
|
93
|
+
| `TESTING.md` | How to test, coverage gaps, and Golden Cases: critical scenarios that must never break regardless of what task is running |
|
|
94
|
+
| `TRAPS.md` | Project-specific pitfalls, things that look right but break things in this codebase |
|
|
95
|
+
| `SECURITY.md` | Auth, data protection, threat analysis |
|
|
96
|
+
| `SCALING.md` | Performance limits, bottlenecks, growth paths |
|
|
97
|
+
| `CHANGELOG.md` | Version history and significant changes |
|
|
98
|
+
| `CURRENT.md` | Active session state: what's in progress, what's next, declared scope |
|
|
99
|
+
| `PLAN.md` | The locked task plan, populated by The Visionary, approved by The Challenger |
|
|
100
|
+
| `CLAUDE.md` | Project-specific instructions that load into every Claude session automatically |
|
|
101
|
+
| `RESEARCH.md` | Background research on frameworks, libraries, and best practices (optional, generated during planning) |
|
|
102
|
+
|
|
103
|
+
Every doc is a draft seeded from your actual code. Gaps are marked with `❓ [UNKNOWN]` so you know exactly what needs filling in.
|
|
65
104
|
|
|
66
105
|
---
|
|
67
106
|
|
|
68
107
|
### Talk Once. Plan Once. Build.
|
|
69
108
|
|
|
70
|
-
You start a conversation. You describe your vision. G2W listens, asks smart questions, and runs research silently in the background
|
|
109
|
+
You start a conversation. You describe your vision. G2W listens, asks smart questions, and runs research silently in the background: tech stack, existing solutions, the ecosystem. By the time you're done talking, the plan is already written and locked.
|
|
71
110
|
|
|
72
111
|
No separate phases. No repeating yourself. Just a conversation that ends with something ready to build.
|
|
73
112
|
|
|
74
|
-
Research isn't just a web search. G2W uses Context7 for live library docs, Exa for semantic search across similar projects, Firecrawl to crawl repos and docs sites, and Repomix to pack reference codebases so The Visionary can read how a production-quality version of what you're building actually works. Everything saves to `RESEARCH.md` and persists
|
|
113
|
+
Research isn't just a web search. G2W uses Context7 for live library docs, Exa for semantic search across similar projects, Firecrawl to crawl repos and docs sites, and Repomix to pack reference codebases so The Visionary can read how a production-quality version of what you're building actually works. Everything saves to `RESEARCH.md` and persists, so future sessions don't re-run research from scratch.
|
|
75
114
|
|
|
76
115
|
---
|
|
77
116
|
|
|
78
117
|
### What Ships With G2W
|
|
79
118
|
|
|
80
|
-
These install automatically
|
|
119
|
+
These install automatically, no setup, no API keys, no extra steps:
|
|
81
120
|
|
|
82
121
|
| Tool | What It Does |
|
|
83
122
|
|---|---|
|
|
84
|
-
| [Context7](https://context7.com) | Live library docs in every research and planning phase
|
|
123
|
+
| [Context7](https://context7.com) | Live library docs in every research and planning phase, no stale training data |
|
|
85
124
|
| [Shadcn/UI MCP](https://www.shadcn.io/mcp) | Real React component implementations with TypeScript props |
|
|
86
125
|
| [Tailwind CSS MCP](https://github.com/CarbonoDev/tailwindcss-mcp-server) | Utility classes, color palettes, CSS-to-Tailwind conversion |
|
|
87
126
|
| [A11y MCP](https://github.com/priyankark/a11y-mcp) | Accessibility audits and WCAG compliance checks |
|
|
@@ -95,28 +134,19 @@ Claude reaches for these automatically when they're relevant. You don't have to
|
|
|
95
134
|
Optional tools that make G2W stronger. Run `g2w power-ups` to set these up anytime.
|
|
96
135
|
|
|
97
136
|
**Free (just needs a key):**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| [Motion](https://motion.dev) | Production-grade animations with AI Kit | [plus.motion.dev/personal-token](https://plus.motion.dev/personal-token) |
|
|
103
|
-
| [Figma MCP](https://help.figma.com/hc/en-us/articles/32132100833559) | Design-to-code from Figma frames (free during beta) | [figma.com](https://figma.com) |
|
|
104
|
-
| [Marketing Skills](https://github.com/coreyhaines31/marketingskills) | 40+ skills for copywriting, SEO, conversion, growth | No key needed |
|
|
137
|
+
- [21st.dev](https://21st.dev), AI-powered UI component generation
|
|
138
|
+
- [Motion](https://motion.dev), Production-grade animations with AI Kit
|
|
139
|
+
- [Figma MCP](https://help.figma.com/hc/en-us/articles/32132100833559), Design-to-code from Figma frames (free during beta)
|
|
140
|
+
- [Marketing Skills](https://github.com/coreyhaines31/marketingskills), 40+ skills for copywriting, SEO, conversion, growth (no key needed)
|
|
105
141
|
|
|
106
142
|
**Research (paid):**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|---|---|
|
|
110
|
-
| [Exa](https://exa.ai) | Semantic search for similar projects and best practices |
|
|
111
|
-
| [Firecrawl](https://firecrawl.dev) | Deep crawling of repos and docs sites during research |
|
|
143
|
+
- [Exa](https://exa.ai), Semantic search for similar projects and best practices
|
|
144
|
+
- [Firecrawl](https://firecrawl.dev), Deep crawling of repos and docs sites during research
|
|
112
145
|
|
|
113
146
|
**Workflow:**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| [Repomix](https://github.com/yamadashy/repomix) | Packs entire codebases into one AI-optimized file — `bring2life` uses this |
|
|
118
|
-
| [MemPalace](https://github.com/milla-jovovich/mempalace) | Persistent memory across sessions — decisions survive context clears |
|
|
119
|
-
| [Superpowers](https://github.com/supermemoryai/superpowers-claude) | Enhanced planning and review capabilities for Claude users |
|
|
147
|
+
- [Repomix](https://github.com/yamadashy/repomix), Packs entire codebases into one AI-optimized file
|
|
148
|
+
- [MemPalace](https://github.com/milla-jovovich/mempalace), Persistent memory across sessions
|
|
149
|
+
- [Superpowers](https://github.com/supermemoryai/superpowers-claude), Enhanced planning and review capabilities
|
|
120
150
|
|
|
121
151
|
G2W uses what's available and falls back gracefully when something isn't there.
|
|
122
152
|
|
|
@@ -129,7 +159,7 @@ Once the plan locks, The Foundation takes over. Five roles. One mission. Get it
|
|
|
129
159
|
| Agent | Role |
|
|
130
160
|
|---|---|
|
|
131
161
|
| The Visionary | Writes a complete plan with real decisions and no placeholders |
|
|
132
|
-
| The Challenger | Adversarial review
|
|
162
|
+
| The Challenger | Adversarial review, finds every way the plan could fail before coding starts |
|
|
133
163
|
| The Builder | Builds exactly what the locked plan says, nothing extra |
|
|
134
164
|
| The Inspector | Verifies everything against the plan and loops until it's clean |
|
|
135
165
|
| The Leader | Manages the team and keeps everything on track |
|
|
@@ -140,15 +170,15 @@ The plan is the contract. By the time The Builder touches a single line of code,
|
|
|
140
170
|
|
|
141
171
|
### Optional Methods
|
|
142
172
|
|
|
143
|
-
Each Foundation agent is also a direct slash command. The normal flow runs through `/g2w:build2gether` and `/g2w:get2work
|
|
173
|
+
Each Foundation agent is also a direct slash command. The normal flow runs through `/g2w:build2gether` and `/g2w:get2work`, but if you know what you're doing, you can jump straight into any stage of the pipeline.
|
|
144
174
|
|
|
145
175
|
| Command | When to use it directly |
|
|
146
176
|
|---|---|
|
|
147
|
-
| `/g2w:the-visionary` | You have a half-written plan and just want it finished
|
|
177
|
+
| `/g2w:the-visionary` | You have a half-written plan and just want it finished, skip the full build2gether flow |
|
|
148
178
|
| `/g2w:the-challenger` | You wrote your own plan outside G2W and want it stress-tested before building |
|
|
149
|
-
| `/g2w:the-builder` | Plan is already locked
|
|
150
|
-
| `/g2w:the-inspector` | Code is already written
|
|
151
|
-
| `/g2w:the-leader` | Kick off the full pipeline
|
|
179
|
+
| `/g2w:the-builder` | Plan is already locked, skip straight to building |
|
|
180
|
+
| `/g2w:the-inspector` | Code is already written, just verify it against a plan |
|
|
181
|
+
| `/g2w:the-leader` | Kick off the full pipeline, includes automatic code audit before Challenger reviews |
|
|
152
182
|
|
|
153
183
|
These are escape hatches for engineers who don't need the ceremony. G2W has no ceiling.
|
|
154
184
|
|
|
@@ -159,10 +189,10 @@ These are escape hatches for engineers who don't need the ceremony. G2W has no c
|
|
|
159
189
|
Delivered via CLAUDE.md so it loads into every session automatically as project instructions.
|
|
160
190
|
|
|
161
191
|
- Your explicit instruction is a direct order. No agent may override it, rationalize it away, or route around it.
|
|
162
|
-
- The AI answers your question first and then asks to proceed
|
|
192
|
+
- The AI answers your question first and then asks to proceed, never just acts.
|
|
163
193
|
- No edits outside the declared scope.
|
|
164
194
|
- No commits without your approval.
|
|
165
|
-
- "I don't know" instead of guessing
|
|
195
|
+
- "I don't know" instead of guessing, always.
|
|
166
196
|
- Uncertainty is labeled, not hidden. `[Inference]` and `[Unverified]` are used so you always know what's confirmed and what isn't.
|
|
167
197
|
- If scope creeps, it stops and flags it before touching anything.
|
|
168
198
|
|
|
@@ -181,9 +211,27 @@ Only after working through those questions does execution begin. Taking more tim
|
|
|
181
211
|
|
|
182
212
|
---
|
|
183
213
|
|
|
184
|
-
###
|
|
214
|
+
### Resource Limits
|
|
215
|
+
|
|
216
|
+
AI agents don't slow down on their own. They keep running, keep calling models, and keep charging your account until you step in and control it. G2W has a built-in safety layer that tracks usage per session and stops runaway behavior before it burns through your budget.
|
|
217
|
+
|
|
218
|
+
**What it tracks:**
|
|
185
219
|
|
|
186
|
-
|
|
220
|
+
| Metric | Default Limit | What Happens |
|
|
221
|
+
|---|---|---|
|
|
222
|
+
| Total tool calls per session | 200 | Hard stop, wrap up and hand off |
|
|
223
|
+
| PLAN.md revisions | 5 | Hard stop, Visionary/Challenger loop is stuck, escalate to user |
|
|
224
|
+
| Unique files touched | 25 | Hard stop, scope creep detected |
|
|
225
|
+
| Edits to the same file | 8 | Warning, possible fix loop |
|
|
226
|
+
| Tool call usage at 80% | N/A | Warning, start wrapping up |
|
|
227
|
+
|
|
228
|
+
**Session logging:** Every completed session gets logged to `~/.g2w/session-log.jsonl`: project name, tool call breakdown, duration. You can see exactly which tasks are driving spend.
|
|
229
|
+
|
|
230
|
+
**Configurable:** All limits live in `~/.g2w/resource-limits.json`. Edit any number. Per-project overrides go in `~/.g2w/projects/[project]/resource-limits.json`.
|
|
231
|
+
|
|
232
|
+
**Kill switch:** Set `"enabled": false` in the config to bypass all limits. Delete `~/.g2w/session-limits.json` to reset counters mid-session.
|
|
233
|
+
|
|
234
|
+
The resource limits hook runs first in the chain, before scope guard, before A-Game, before anything else. If the session is over limit, nothing else fires.
|
|
187
235
|
|
|
188
236
|
---
|
|
189
237
|
|
|
@@ -191,15 +239,15 @@ Safe git operations — add, commit, push, status, log — run without approval
|
|
|
191
239
|
|
|
192
240
|
| Command | What It Does |
|
|
193
241
|
|---|---|
|
|
194
|
-
| `/g2w:bring2life` | Onboard an existing codebase
|
|
195
|
-
| `/g2w:build2gether` | Start a new project
|
|
242
|
+
| `/g2w:bring2life` | Onboard an existing codebase, scans it, generates your doc files, flags gaps |
|
|
243
|
+
| `/g2w:build2gether` | Start a new project, brainstorm, research, and locked plan in one conversation |
|
|
196
244
|
| `/g2w:back2it` | Pick up right where you left off |
|
|
197
245
|
| `/g2w:get2work` | Execute the current task |
|
|
198
|
-
| `/g2w:cut2it` | Fast mode
|
|
246
|
+
| `/g2w:cut2it` | Fast mode, small tasks, no ceremony |
|
|
199
247
|
| `/g2w:back2basics` | Strip context and start clean |
|
|
200
248
|
| `/g2w:true2plan` | Verify that what was built actually matches the plan |
|
|
201
249
|
| `/g2w:true2dagame` | Full system health check |
|
|
202
|
-
| `/g2w:ready2save` | Wrap up the session
|
|
250
|
+
| `/g2w:ready2save` | Wrap up the session, update CURRENT.md, capture key decisions and the reasoning behind them, hand off cleanly |
|
|
203
251
|
|
|
204
252
|
---
|
|
205
253
|
|
|
@@ -209,7 +257,7 @@ Safe git operations — add, commit, push, status, log — run without approval
|
|
|
209
257
|
npm install -g @only1btayy/g2w && g2w
|
|
210
258
|
```
|
|
211
259
|
|
|
212
|
-
That's it. G2W installs globally into `~/.claude/` automatically
|
|
260
|
+
That's it. G2W installs globally into `~/.claude/` automatically, skills, hooks, and design tools ready in every project, everywhere.
|
|
213
261
|
|
|
214
262
|
To update:
|
|
215
263
|
|
|
@@ -235,32 +283,30 @@ Skills, hooks, and MCP servers are removed from `~/.claude/` automatically.
|
|
|
235
283
|
|
|
236
284
|
---
|
|
237
285
|
|
|
238
|
-
##
|
|
239
|
-
|
|
240
|
-
Everyone tired of the bullshit. Vibe coders who just want to ship. Senior engineers who want control. Solo builders with no team and no co-founder.
|
|
286
|
+
## Contributing
|
|
241
287
|
|
|
242
|
-
|
|
288
|
+
G2W is open source and contributions are welcome.
|
|
243
289
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
Speed comes from simplicity. Control comes from clarity. If you need a system to manage your system, it's already broken. G2W is not a factory. It's a studio.
|
|
251
|
-
|
|
252
|
-
---
|
|
290
|
+
**How to get started:**
|
|
291
|
+
1. Fork the repo
|
|
292
|
+
2. Clone it and run `npm install`
|
|
293
|
+
3. Make your changes in a feature branch
|
|
294
|
+
4. Run `node test/hooks-and-skills.test.js` to make sure nothing breaks
|
|
295
|
+
5. Open a PR with a clear description of what you changed and why
|
|
253
296
|
|
|
254
|
-
|
|
297
|
+
**Where help is needed:**
|
|
298
|
+
- Mac and Linux testing, G2W was built on Windows and needs cross-platform validation
|
|
299
|
+
- New hook ideas, if you've hit a pattern where AI goes off the rails, it might be a hook
|
|
300
|
+
- Bug reports, if something doesn't work, open an issue
|
|
255
301
|
|
|
256
|
-
|
|
302
|
+
No contribution is too small. If you found a typo, fix it. If you have an idea, open an issue and let's talk about it.
|
|
257
303
|
|
|
258
304
|
---
|
|
259
305
|
|
|
260
306
|
## Acknowledgements
|
|
261
307
|
|
|
262
|
-
- **[johnkf5-ops/the-dev-squad](https://github.com/johnkf5-ops/the-dev-squad)
|
|
263
|
-
- **John Knopf
|
|
308
|
+
- **[johnkf5-ops/the-dev-squad](https://github.com/johnkf5-ops/the-dev-squad)**, inspired The Foundation's multi-agent pipeline
|
|
309
|
+
- **John Knopf**, modular doc system approach. His words: *"Take it, run with it, use it, modify it, make it better. That's the whole point."*
|
|
264
310
|
|
|
265
311
|
---
|
|
266
312
|
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// G2W Resource Limits — PreToolUse hook
|
|
3
|
+
// Tracks tool calls, plan revisions, and file edits per session.
|
|
4
|
+
// Warns at thresholds, hard blocks at limits. Logs session summaries.
|
|
5
|
+
// Config: ~/.g2w/resource-limits.json | State: ~/.g2w/session-limits.json
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
const G2W_DIR = path.join(os.homedir(), '.g2w');
|
|
12
|
+
const CONFIG_FILE = path.join(G2W_DIR, 'resource-limits.json');
|
|
13
|
+
const STATE_FILE = path.join(G2W_DIR, 'session-limits.json');
|
|
14
|
+
const LOG_FILE = path.join(G2W_DIR, 'session-log.jsonl');
|
|
15
|
+
const CURRENT_MD = path.join(G2W_DIR, 'CURRENT.md');
|
|
16
|
+
|
|
17
|
+
const DEFAULTS = {
|
|
18
|
+
enabled: true,
|
|
19
|
+
maxToolCalls: 200,
|
|
20
|
+
warnAtToolCallPercent: 80,
|
|
21
|
+
maxPlanRevisions: 5,
|
|
22
|
+
maxFileEdits: 8,
|
|
23
|
+
maxUniqueFiles: 25,
|
|
24
|
+
sessionTimeoutHours: 4
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function loadJSON(filePath, fallback) {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
30
|
+
} catch {
|
|
31
|
+
return fallback;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function saveJSON(filePath, data) {
|
|
36
|
+
try {
|
|
37
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
38
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
39
|
+
} catch {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function appendLog(line) {
|
|
43
|
+
try {
|
|
44
|
+
fs.mkdirSync(path.dirname(LOG_FILE), { recursive: true });
|
|
45
|
+
fs.appendFileSync(LOG_FILE, JSON.stringify(line) + '\n');
|
|
46
|
+
} catch {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getActiveProject() {
|
|
50
|
+
try {
|
|
51
|
+
const content = fs.readFileSync(CURRENT_MD, 'utf8');
|
|
52
|
+
const match = content.match(/^active:\s*(.+)/m);
|
|
53
|
+
return match ? match[1].trim() : null;
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function loadConfig() {
|
|
60
|
+
const global = loadJSON(CONFIG_FILE, {});
|
|
61
|
+
const project = getActiveProject();
|
|
62
|
+
let projectConfig = {};
|
|
63
|
+
if (project) {
|
|
64
|
+
const projectConfigPath = path.join(G2W_DIR, 'projects', project, 'resource-limits.json');
|
|
65
|
+
projectConfig = loadJSON(projectConfigPath, {});
|
|
66
|
+
}
|
|
67
|
+
return { ...DEFAULTS, ...global, ...projectConfig };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function freshState(project) {
|
|
71
|
+
return {
|
|
72
|
+
startedAt: new Date().toISOString(),
|
|
73
|
+
project: project || 'unknown',
|
|
74
|
+
counters: {
|
|
75
|
+
totalToolCalls: 0,
|
|
76
|
+
writes: 0,
|
|
77
|
+
edits: 0,
|
|
78
|
+
bashCalls: 0,
|
|
79
|
+
uniqueFilesTouched: [],
|
|
80
|
+
planRevisions: 0,
|
|
81
|
+
fileEditCounts: {}
|
|
82
|
+
},
|
|
83
|
+
warnings: {
|
|
84
|
+
toolCallWarningFired: false,
|
|
85
|
+
planLoopWarningFired: false
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function logSession(state) {
|
|
91
|
+
if (!state || state.counters.totalToolCalls === 0) return;
|
|
92
|
+
const start = new Date(state.startedAt);
|
|
93
|
+
const now = new Date();
|
|
94
|
+
const durationMinutes = Math.round((now - start) / 60000);
|
|
95
|
+
appendLog({
|
|
96
|
+
project: state.project,
|
|
97
|
+
startedAt: state.startedAt,
|
|
98
|
+
endedAt: now.toISOString(),
|
|
99
|
+
totalToolCalls: state.counters.totalToolCalls,
|
|
100
|
+
writes: state.counters.writes,
|
|
101
|
+
edits: state.counters.edits,
|
|
102
|
+
bashCalls: state.counters.bashCalls,
|
|
103
|
+
uniqueFiles: state.counters.uniqueFilesTouched.length,
|
|
104
|
+
planRevisions: state.counters.planRevisions,
|
|
105
|
+
durationMinutes
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function isSessionExpired(state, timeoutHours) {
|
|
110
|
+
if (!state || !state.startedAt) return true;
|
|
111
|
+
const elapsed = (Date.now() - new Date(state.startedAt).getTime()) / 3600000;
|
|
112
|
+
return elapsed > timeoutHours;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function output(message) {
|
|
116
|
+
process.stdout.write(JSON.stringify({
|
|
117
|
+
hookSpecificOutput: {
|
|
118
|
+
hookEventName: 'PreToolUse',
|
|
119
|
+
additionalContext: message
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let input = '';
|
|
125
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
126
|
+
process.stdin.setEncoding('utf8');
|
|
127
|
+
process.stdin.on('data', chunk => (input += chunk));
|
|
128
|
+
process.stdin.on('end', () => {
|
|
129
|
+
clearTimeout(stdinTimeout);
|
|
130
|
+
try {
|
|
131
|
+
const data = JSON.parse(input);
|
|
132
|
+
const toolName = data.tool_name;
|
|
133
|
+
|
|
134
|
+
// Only track Write, Edit, Bash
|
|
135
|
+
if (toolName !== 'Write' && toolName !== 'Edit' && toolName !== 'Bash') {
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const config = loadConfig();
|
|
140
|
+
|
|
141
|
+
// Kill switch
|
|
142
|
+
if (!config.enabled) {
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const project = getActiveProject();
|
|
147
|
+
let state = loadJSON(STATE_FILE, null);
|
|
148
|
+
|
|
149
|
+
// Reset if expired or missing
|
|
150
|
+
if (!state || isSessionExpired(state, config.sessionTimeoutHours)) {
|
|
151
|
+
logSession(state);
|
|
152
|
+
state = freshState(project);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const c = state.counters;
|
|
156
|
+
const filePath = data.tool_input?.file_path || '';
|
|
157
|
+
const normalizedPath = filePath ? path.normalize(filePath) : '';
|
|
158
|
+
|
|
159
|
+
// Increment counters
|
|
160
|
+
c.totalToolCalls++;
|
|
161
|
+
if (toolName === 'Write') c.writes++;
|
|
162
|
+
if (toolName === 'Edit') c.edits++;
|
|
163
|
+
if (toolName === 'Bash') c.bashCalls++;
|
|
164
|
+
|
|
165
|
+
// Track unique files and per-file edits (Write/Edit only)
|
|
166
|
+
if ((toolName === 'Write' || toolName === 'Edit') && normalizedPath) {
|
|
167
|
+
if (!c.uniqueFilesTouched.includes(normalizedPath)) {
|
|
168
|
+
c.uniqueFilesTouched.push(normalizedPath);
|
|
169
|
+
}
|
|
170
|
+
c.fileEditCounts[normalizedPath] = (c.fileEditCounts[normalizedPath] || 0) + 1;
|
|
171
|
+
|
|
172
|
+
// Track PLAN.md revisions
|
|
173
|
+
if (path.basename(filePath).toUpperCase() === 'PLAN.MD') {
|
|
174
|
+
c.planRevisions++;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Save state before checking limits (so counters persist even on block)
|
|
179
|
+
saveJSON(STATE_FILE, state);
|
|
180
|
+
|
|
181
|
+
// --- Check limits (severity order: hard blocks first, then warnings) ---
|
|
182
|
+
|
|
183
|
+
// Hard block: total tool calls
|
|
184
|
+
if (c.totalToolCalls >= config.maxToolCalls) {
|
|
185
|
+
output(
|
|
186
|
+
`🛑 G2W RESOURCE LIMIT: Session hit ${c.totalToolCalls} tool calls (limit: ${config.maxToolCalls}). ` +
|
|
187
|
+
'Stop and wrap up. Run /g2w:ready2save to hand off cleanly. ' +
|
|
188
|
+
'To reset: delete ~/.g2w/session-limits.json'
|
|
189
|
+
);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Hard block: plan revision loop
|
|
194
|
+
if (c.planRevisions >= config.maxPlanRevisions) {
|
|
195
|
+
output(
|
|
196
|
+
`🛑 G2W LOOP DETECTED: PLAN.md has been revised ${c.planRevisions} times (limit: ${config.maxPlanRevisions}). ` +
|
|
197
|
+
'The Visionary/Challenger loop is stuck. Stop iterating and escalate to the user. ' +
|
|
198
|
+
'Ask: "The plan has been revised ' + c.planRevisions + ' times. Should we lock it as-is, break the task smaller, or take a different approach?"'
|
|
199
|
+
);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Hard block: too many unique files (scope creep)
|
|
204
|
+
if (c.uniqueFilesTouched.length >= config.maxUniqueFiles) {
|
|
205
|
+
output(
|
|
206
|
+
`🛑 G2W SCOPE CREEP: ${c.uniqueFilesTouched.length} unique files touched (limit: ${config.maxUniqueFiles}). ` +
|
|
207
|
+
'This session is touching too many files. Stop and re-scope with the user.'
|
|
208
|
+
);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Warning: file edit loop (specific file edited too many times)
|
|
213
|
+
if (normalizedPath && c.fileEditCounts[normalizedPath] >= config.maxFileEdits && !state.warnings[`fileLoop_${normalizedPath}`]) {
|
|
214
|
+
state.warnings[`fileLoop_${normalizedPath}`] = true;
|
|
215
|
+
saveJSON(STATE_FILE, state);
|
|
216
|
+
output(
|
|
217
|
+
`⚠️ G2W FIX LOOP WARNING: "${path.basename(filePath)}" has been edited ${c.fileEditCounts[normalizedPath]} times this session. ` +
|
|
218
|
+
'Possible Inspector/Builder fix loop. Consider whether the approach needs to change.'
|
|
219
|
+
);
|
|
220
|
+
process.exit(0);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Warning: approaching tool call limit
|
|
224
|
+
const warnThreshold = Math.floor(config.maxToolCalls * config.warnAtToolCallPercent / 100);
|
|
225
|
+
if (c.totalToolCalls >= warnThreshold && !state.warnings.toolCallWarningFired) {
|
|
226
|
+
state.warnings.toolCallWarningFired = true;
|
|
227
|
+
saveJSON(STATE_FILE, state);
|
|
228
|
+
output(
|
|
229
|
+
`⚠️ G2W RESOURCE WARNING: ${c.totalToolCalls}/${config.maxToolCalls} tool calls used (${config.warnAtToolCallPercent}%). ` +
|
|
230
|
+
'Start wrapping up. Consider running /g2w:ready2save soon.'
|
|
231
|
+
);
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
process.exit(0);
|
|
236
|
+
} catch {
|
|
237
|
+
process.exit(0); // never block on error
|
|
238
|
+
}
|
|
239
|
+
});
|
package/lib/install.js
CHANGED
|
@@ -21,6 +21,16 @@ const HOOKS_SRC = path.join(__dirname, '../hooks');
|
|
|
21
21
|
|
|
22
22
|
const G2W_HOOKS = {
|
|
23
23
|
PreToolUse: [
|
|
24
|
+
{
|
|
25
|
+
matcher: 'Write|Edit|Bash',
|
|
26
|
+
hooks: [
|
|
27
|
+
{
|
|
28
|
+
type: 'command',
|
|
29
|
+
command: 'node "{{HOOKS_DIR}}/g2w-resource-limits.js"',
|
|
30
|
+
timeout: 5
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
24
34
|
{
|
|
25
35
|
matcher: 'Write|Edit',
|
|
26
36
|
hooks: [
|
|
@@ -115,9 +125,10 @@ function mergeMcpServers(targetBase) {
|
|
|
115
125
|
|
|
116
126
|
// Unique identifiers for each G2W hook — used for merge and removal
|
|
117
127
|
const HOOK_SIGNATURES = {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
resourceLimits: h => h.hooks?.some(hh => hh.command?.includes('g2w-resource-limits')),
|
|
129
|
+
scopeGuard: h => h.hooks?.some(hh => hh.command?.includes('g2w-scope-guard')),
|
|
130
|
+
aGame: h => h.hooks?.some(hh => hh.command?.includes('g2w-agame')),
|
|
131
|
+
commitGuard: h => h.hooks?.some(hh => hh.command?.includes('g2w-commit-guard')),
|
|
121
132
|
};
|
|
122
133
|
|
|
123
134
|
function mergeHooks(targetBase) {
|
|
@@ -168,10 +179,12 @@ function mergeHooks(targetBase) {
|
|
|
168
179
|
|
|
169
180
|
if (!existing.hooks.PreToolUse) existing.hooks.PreToolUse = [];
|
|
170
181
|
for (const hook of resolvedHooks.PreToolUse) {
|
|
182
|
+
const isResourceLimits = HOOK_SIGNATURES.resourceLimits(hook);
|
|
171
183
|
const isScopeGuard = HOOK_SIGNATURES.scopeGuard(hook);
|
|
172
184
|
const isAGame = HOOK_SIGNATURES.aGame(hook);
|
|
173
185
|
const isCommitGuard = HOOK_SIGNATURES.commitGuard(hook);
|
|
174
186
|
const alreadyExists = existing.hooks.PreToolUse.some(h =>
|
|
187
|
+
(isResourceLimits && HOOK_SIGNATURES.resourceLimits(h)) ||
|
|
175
188
|
(isScopeGuard && HOOK_SIGNATURES.scopeGuard(h)) ||
|
|
176
189
|
(isAGame && HOOK_SIGNATURES.aGame(h)) ||
|
|
177
190
|
(isCommitGuard && HOOK_SIGNATURES.commitGuard(h))
|
|
@@ -212,7 +225,7 @@ function removeHooks(targetBase) {
|
|
|
212
225
|
const hooksDir = path.join(targetBase, '.claude', 'hooks');
|
|
213
226
|
|
|
214
227
|
// Remove hook scripts
|
|
215
|
-
['g2w-scope-guard.js', 'g2w-agame.js', 'g2w-commit-guard.js'].forEach(file => {
|
|
228
|
+
['g2w-resource-limits.js', 'g2w-scope-guard.js', 'g2w-agame.js', 'g2w-commit-guard.js'].forEach(file => {
|
|
216
229
|
const p = path.join(hooksDir, file);
|
|
217
230
|
if (fs.existsSync(p)) fs.rmSync(p);
|
|
218
231
|
});
|
|
@@ -225,6 +238,7 @@ function removeHooks(targetBase) {
|
|
|
225
238
|
// Remove all G2W PreToolUse hooks (scope-guard, a-game, commit-guard, old Trust Layer prompt)
|
|
226
239
|
if (existing.hooks.PreToolUse) {
|
|
227
240
|
existing.hooks.PreToolUse = existing.hooks.PreToolUse.filter(h =>
|
|
241
|
+
!HOOK_SIGNATURES.resourceLimits(h) &&
|
|
228
242
|
!HOOK_SIGNATURES.scopeGuard(h) &&
|
|
229
243
|
!HOOK_SIGNATURES.aGame(h) &&
|
|
230
244
|
!HOOK_SIGNATURES.commitGuard(h) &&
|
|
@@ -257,12 +271,29 @@ function getTarget() {
|
|
|
257
271
|
return { base: os.homedir(), label: '~/.claude/' };
|
|
258
272
|
}
|
|
259
273
|
|
|
274
|
+
function createDefaultResourceLimits() {
|
|
275
|
+
const configPath = path.join(os.homedir(), '.g2w', 'resource-limits.json');
|
|
276
|
+
if (fs.existsSync(configPath)) return; // don't overwrite user config
|
|
277
|
+
const defaults = {
|
|
278
|
+
enabled: true,
|
|
279
|
+
maxToolCalls: 200,
|
|
280
|
+
warnAtToolCallPercent: 80,
|
|
281
|
+
maxPlanRevisions: 5,
|
|
282
|
+
maxFileEdits: 8,
|
|
283
|
+
maxUniqueFiles: 25,
|
|
284
|
+
sessionTimeoutHours: 4
|
|
285
|
+
};
|
|
286
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
287
|
+
fs.writeFileSync(configPath, JSON.stringify(defaults, null, 2));
|
|
288
|
+
}
|
|
289
|
+
|
|
260
290
|
async function run() {
|
|
261
291
|
const { base, label } = getTarget();
|
|
262
292
|
const { dest, count } = copySkills(base);
|
|
263
293
|
copyHooks(base);
|
|
264
294
|
const settingsPath = mergeHooks(base);
|
|
265
295
|
const mcpAdded = mergeMcpServers(base);
|
|
296
|
+
createDefaultResourceLimits();
|
|
266
297
|
|
|
267
298
|
writeTTY(`${LOGO}
|
|
268
299
|
\x1b[32m✅ G2W installed at ${label}\x1b[0m
|