@only1btayy/g2w 1.0.29 → 1.0.31

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.
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ // G2W Commit Guard — PreToolUse hook
3
+ // Fires before Bash commands. Hard blocks git commit and git push
4
+ // unless the user has explicitly approved. Exit code 1 = blocked.
5
+
6
+ let input = '';
7
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
8
+ process.stdin.setEncoding('utf8');
9
+ process.stdin.on('data', chunk => (input += chunk));
10
+ process.stdin.on('end', () => {
11
+ clearTimeout(stdinTimeout);
12
+ try {
13
+ const data = JSON.parse(input);
14
+ if (data.tool_name !== 'Bash') {
15
+ process.exit(0);
16
+ }
17
+
18
+ const cmd = data.tool_input?.command || '';
19
+
20
+ // Detect git commit or git push (with optional flags/args)
21
+ const isCommit = /\bgit\s+commit\b/.test(cmd);
22
+ const isPush = /\bgit\s+push\b/.test(cmd);
23
+
24
+ if (isCommit || isPush) {
25
+ const action = isCommit ? 'commit' : 'push';
26
+ const output = {
27
+ hookSpecificOutput: {
28
+ hookEventName: 'PreToolUse',
29
+ additionalContext:
30
+ `🚫 G2W COMMIT GUARD: You are about to run git ${action}. ` +
31
+ 'This requires explicit user approval. ' +
32
+ 'Stop and ask the user before proceeding. Do not bypass this check.',
33
+ },
34
+ };
35
+ process.stdout.write(JSON.stringify(output));
36
+ process.exit(1);
37
+ }
38
+
39
+ process.exit(0);
40
+ } catch {
41
+ process.exit(0);
42
+ }
43
+ });
package/lib/install.js CHANGED
@@ -42,22 +42,12 @@ const G2W_HOOKS = {
42
42
  ]
43
43
  },
44
44
  {
45
- matcher: 'Edit|Write',
45
+ matcher: 'Bash',
46
46
  hooks: [
47
47
  {
48
- type: 'prompt',
49
- prompt: 'Trust Layer: answer the user\'s question first before acting. Declare scope (exact files you will touch). Stop if scope creeps beyond what was declared. Say "I don\'t know" instead of guessing. No commits without explicit user approval. If the user seems stuck or frustrated — remind them of their vision, not just fix the code.'
50
- }
51
- ]
52
- }
53
- ],
54
- PostMessage: [
55
- {
56
- matcher: '.*',
57
- hooks: [
58
- {
59
- type: 'prompt',
60
- prompt: 'If the context window is at or above 80%, tell the user: "Hey — we\'re getting close to the context limit. Want me to run /g2w:ready2save to save progress and clear context?" If below 80%, do nothing.'
48
+ type: 'command',
49
+ command: 'node "{{HOOKS_DIR}}/g2w-commit-guard.js"',
50
+ timeout: 5
61
51
  }
62
52
  ]
63
53
  }
@@ -123,6 +113,13 @@ function mergeMcpServers(targetBase) {
123
113
  return added;
124
114
  }
125
115
 
116
+ // Unique identifiers for each G2W hook — used for merge and removal
117
+ const HOOK_SIGNATURES = {
118
+ scopeGuard: h => h.hooks?.some(hh => hh.command?.includes('g2w-scope-guard')),
119
+ aGame: h => h.hooks?.some(hh => hh.command?.includes('g2w-agame')),
120
+ commitGuard: h => h.hooks?.some(hh => hh.command?.includes('g2w-commit-guard')),
121
+ };
122
+
126
123
  function mergeHooks(targetBase) {
127
124
  const settingsPath = path.join(targetBase, '.claude', 'settings.json');
128
125
  const hooksDir = path.join(targetBase, '.claude', 'hooks');
@@ -140,22 +137,48 @@ function mergeHooks(targetBase) {
140
137
  JSON.stringify(G2W_HOOKS).replace(/\{\{HOOKS_DIR\}\}/g, hooksDir.replace(/\\/g, '/'))
141
138
  );
142
139
 
143
- // Merge PreToolUse append if not already present (check by scope-guard command)
144
- if (!existing.hooks.PreToolUse) existing.hooks.PreToolUse = [];
145
- const alreadyHasPreHook = existing.hooks.PreToolUse.some(h =>
146
- h.hooks && h.hooks.some(hh => hh.command && hh.command.includes('g2w-scope-guard'))
147
- );
148
- if (!alreadyHasPreHook) {
149
- existing.hooks.PreToolUse.push(...resolvedHooks.PreToolUse);
140
+ // --- Migration: clean up old hook formats from previous G2W versions ---
141
+
142
+ // Remove old PostMessage hooks (no longer used)
143
+ if (existing.hooks.PostMessage) {
144
+ existing.hooks.PostMessage = existing.hooks.PostMessage.filter(h =>
145
+ !(h.hooks && h.hooks.some(hh => hh.prompt && hh.prompt.includes('ready2save')))
146
+ );
147
+ if (existing.hooks.PostMessage.length === 0) delete existing.hooks.PostMessage;
150
148
  }
151
149
 
152
- // Merge PostMessageappend if not already present
153
- if (!existing.hooks.PostMessage) existing.hooks.PostMessage = [];
154
- const alreadyHasPostHook = existing.hooks.PostMessage.some(h =>
155
- h.hooks && h.hooks.some(hh => hh.prompt && hh.prompt.includes('ready2save'))
156
- );
157
- if (!alreadyHasPostHook) {
158
- existing.hooks.PostMessage.push(...resolvedHooks.PostMessage);
150
+ // Remove old UserPromptSubmit hooks (broke chat Trust Layer + context warning)
151
+ if (existing.hooks.UserPromptSubmit) {
152
+ existing.hooks.UserPromptSubmit = existing.hooks.UserPromptSubmit.filter(h =>
153
+ !(h.hooks && h.hooks.some(hh =>
154
+ hh.prompt && (hh.prompt.includes('G2W Trust Layer') || hh.prompt.includes('Context check'))
155
+ ))
156
+ );
157
+ if (existing.hooks.UserPromptSubmit.length === 0) delete existing.hooks.UserPromptSubmit;
158
+ }
159
+
160
+ // Remove old Trust Layer prompt from PreToolUse (was there in early versions)
161
+ if (existing.hooks.PreToolUse) {
162
+ existing.hooks.PreToolUse = existing.hooks.PreToolUse.filter(h =>
163
+ !(h.hooks && h.hooks.some(hh => hh.prompt && hh.prompt.includes('Trust Layer')))
164
+ );
165
+ }
166
+
167
+ // --- Merge current hooks: scope-guard, a-game, commit-guard on PreToolUse ---
168
+
169
+ if (!existing.hooks.PreToolUse) existing.hooks.PreToolUse = [];
170
+ for (const hook of resolvedHooks.PreToolUse) {
171
+ const isScopeGuard = HOOK_SIGNATURES.scopeGuard(hook);
172
+ const isAGame = HOOK_SIGNATURES.aGame(hook);
173
+ const isCommitGuard = HOOK_SIGNATURES.commitGuard(hook);
174
+ const alreadyExists = existing.hooks.PreToolUse.some(h =>
175
+ (isScopeGuard && HOOK_SIGNATURES.scopeGuard(h)) ||
176
+ (isAGame && HOOK_SIGNATURES.aGame(h)) ||
177
+ (isCommitGuard && HOOK_SIGNATURES.commitGuard(h))
178
+ );
179
+ if (!alreadyExists) {
180
+ existing.hooks.PreToolUse.push(hook);
181
+ }
159
182
  }
160
183
 
161
184
  fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
@@ -189,7 +212,7 @@ function removeHooks(targetBase) {
189
212
  const hooksDir = path.join(targetBase, '.claude', 'hooks');
190
213
 
191
214
  // Remove hook scripts
192
- ['g2w-scope-guard.js', 'g2w-agame.js'].forEach(file => {
215
+ ['g2w-scope-guard.js', 'g2w-agame.js', 'g2w-commit-guard.js'].forEach(file => {
193
216
  const p = path.join(hooksDir, file);
194
217
  if (fs.existsSync(p)) fs.rmSync(p);
195
218
  });
@@ -199,18 +222,31 @@ function removeHooks(targetBase) {
199
222
  try { existing = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch { return; }
200
223
 
201
224
  if (existing.hooks) {
225
+ // Remove all G2W PreToolUse hooks (scope-guard, a-game, commit-guard, old Trust Layer prompt)
202
226
  if (existing.hooks.PreToolUse) {
203
227
  existing.hooks.PreToolUse = existing.hooks.PreToolUse.filter(h =>
228
+ !HOOK_SIGNATURES.scopeGuard(h) &&
229
+ !HOOK_SIGNATURES.aGame(h) &&
230
+ !HOOK_SIGNATURES.commitGuard(h) &&
231
+ !(h.hooks && h.hooks.some(hh => hh.prompt && hh.prompt.includes('Trust Layer')))
232
+ );
233
+ if (existing.hooks.PreToolUse.length === 0) delete existing.hooks.PreToolUse;
234
+ }
235
+ // Clean up old UserPromptSubmit hooks (broke chat — removed in v1.0.29+)
236
+ if (existing.hooks.UserPromptSubmit) {
237
+ existing.hooks.UserPromptSubmit = existing.hooks.UserPromptSubmit.filter(h =>
204
238
  !(h.hooks && h.hooks.some(hh =>
205
- (hh.command && (hh.command.includes('g2w-scope-guard') || hh.command.includes('g2w-agame'))) ||
206
- (hh.prompt && hh.prompt.includes('Trust Layer'))
239
+ hh.prompt && (hh.prompt.includes('G2W Trust Layer') || hh.prompt.includes('Context check'))
207
240
  ))
208
241
  );
242
+ if (existing.hooks.UserPromptSubmit.length === 0) delete existing.hooks.UserPromptSubmit;
209
243
  }
244
+ // Clean up old PostMessage hooks from early versions
210
245
  if (existing.hooks.PostMessage) {
211
246
  existing.hooks.PostMessage = existing.hooks.PostMessage.filter(h =>
212
247
  !(h.hooks && h.hooks.some(hh => hh.prompt && hh.prompt.includes('ready2save')))
213
248
  );
249
+ if (existing.hooks.PostMessage.length === 0) delete existing.hooks.PostMessage;
214
250
  }
215
251
  }
216
252
 
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@only1btayy/g2w",
3
- "version": "1.0.29",
3
+ "version": "1.0.31",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
4
7
  "description": "G2W — a relationship protocol for building trust with AI",
5
8
  "bin": {
6
9
  "g2w": "bin/g2w.js"
@@ -16,10 +16,8 @@ You are closing out this session. Leave the project in a state where any future
16
16
 
17
17
  Do NOT ask the user what was done, what to save, or what decisions were made. You witnessed the entire session — extract it yourself and present it. The user confirms or corrects your summary. Never ask them to recall.
18
18
 
19
- 2. **Confirm the active project** — List all folders inside `projects/` and ask:
20
- > "Which project are we saving? (pick one)"
21
-
22
- Wait for the user to confirm. Do not assume based on what was discussed — the user decides.
19
+ 2. **Identify the active project** — Read `~/.g2w/CURRENT.md` (Windows: `C:/Users/[username]/.g2w/CURRENT.md`). If it has an `active:` line, that's the project. Use it. Do NOT ask.
20
+ - Only if the file doesn't exist or has no `active:` line: list folders in `~/.g2w/projects/` and ask which one. This is the ONLY scenario where you ask.
23
21
 
24
22
  3. **Update `.g2w/CURRENT.md`** in the confirmed project folder with exactly three sections:
25
23
  ```
@@ -56,7 +54,14 @@ You are closing out this session. Leave the project in a state where any future
56
54
  - Verified: [how it was verified]
57
55
  ```
58
56
 
59
- Keep it lean: do NOT run git status, git diff, or git log — you already know what changed. One `git add` for the files you touched + one `git commit` = done. Present the commit message to the user. Wait for approval before running.
57
+ Keep it lean: do NOT run git status, git diff, or git log — you already know what changed. Present the commit message to the user. Wait for approval. Then run it as **one single Bash call**:
58
+ ```
59
+ git add [files] && git commit -m "type: summary
60
+
61
+ - What changed
62
+ - Verified: [how]"
63
+ ```
64
+ Never split git add and git commit into separate Bash calls.
60
65
 
61
66
  6. **Announce with personality:**
62
67
  End the session with a closing quote. Pick ONE at random from this list: