@dgxo/mashadevcli 1.1.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.
Files changed (140) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +393 -0
  3. package/bundle/builtin/skill-creator/SKILL.md +382 -0
  4. package/bundle/builtin/skill-creator/scripts/init_skill.cjs +239 -0
  5. package/bundle/builtin/skill-creator/scripts/package_skill.cjs +131 -0
  6. package/bundle/builtin/skill-creator/scripts/validate_skill.cjs +131 -0
  7. package/bundle/docs/CONTRIBUTING.md +1 -0
  8. package/bundle/docs/admin/enterprise-controls.md +115 -0
  9. package/bundle/docs/assets/connected_devtools.png +0 -0
  10. package/bundle/docs/assets/gemini-screenshot.png +0 -0
  11. package/bundle/docs/assets/monitoring-dashboard-logs.png +0 -0
  12. package/bundle/docs/assets/monitoring-dashboard-metrics.png +0 -0
  13. package/bundle/docs/assets/monitoring-dashboard-overview.png +0 -0
  14. package/bundle/docs/assets/release_patch.png +0 -0
  15. package/bundle/docs/assets/theme-ansi-light.png +0 -0
  16. package/bundle/docs/assets/theme-ansi.png +0 -0
  17. package/bundle/docs/assets/theme-atom-one.png +0 -0
  18. package/bundle/docs/assets/theme-ayu-light.png +0 -0
  19. package/bundle/docs/assets/theme-ayu.png +0 -0
  20. package/bundle/docs/assets/theme-custom.png +0 -0
  21. package/bundle/docs/assets/theme-default-light.png +0 -0
  22. package/bundle/docs/assets/theme-default.png +0 -0
  23. package/bundle/docs/assets/theme-dracula.png +0 -0
  24. package/bundle/docs/assets/theme-github-light.png +0 -0
  25. package/bundle/docs/assets/theme-github.png +0 -0
  26. package/bundle/docs/assets/theme-google-light.png +0 -0
  27. package/bundle/docs/assets/theme-xcode-light.png +0 -0
  28. package/bundle/docs/changelogs/index.md +867 -0
  29. package/bundle/docs/changelogs/latest.md +208 -0
  30. package/bundle/docs/changelogs/preview.md +187 -0
  31. package/bundle/docs/cli/checkpointing.md +93 -0
  32. package/bundle/docs/cli/cli-reference.md +115 -0
  33. package/bundle/docs/cli/creating-skills.md +80 -0
  34. package/bundle/docs/cli/custom-commands.md +327 -0
  35. package/bundle/docs/cli/enterprise.md +604 -0
  36. package/bundle/docs/cli/gemini-ignore.md +71 -0
  37. package/bundle/docs/cli/gemini-md.md +116 -0
  38. package/bundle/docs/cli/generation-settings.md +210 -0
  39. package/bundle/docs/cli/headless.md +50 -0
  40. package/bundle/docs/cli/model-routing.md +42 -0
  41. package/bundle/docs/cli/model.md +53 -0
  42. package/bundle/docs/cli/plan-mode.md +375 -0
  43. package/bundle/docs/cli/rewind.md +51 -0
  44. package/bundle/docs/cli/sandbox.md +257 -0
  45. package/bundle/docs/cli/session-management.md +184 -0
  46. package/bundle/docs/cli/settings.md +165 -0
  47. package/bundle/docs/cli/skills.md +134 -0
  48. package/bundle/docs/cli/system-prompt.md +125 -0
  49. package/bundle/docs/cli/telemetry.md +922 -0
  50. package/bundle/docs/cli/themes.md +269 -0
  51. package/bundle/docs/cli/token-caching.md +20 -0
  52. package/bundle/docs/cli/trusted-folders.md +126 -0
  53. package/bundle/docs/cli/tutorials/automation.md +283 -0
  54. package/bundle/docs/cli/tutorials/file-management.md +142 -0
  55. package/bundle/docs/cli/tutorials/mcp-setup.md +113 -0
  56. package/bundle/docs/cli/tutorials/memory-management.md +126 -0
  57. package/bundle/docs/cli/tutorials/session-management.md +105 -0
  58. package/bundle/docs/cli/tutorials/shell-commands.md +107 -0
  59. package/bundle/docs/cli/tutorials/skills-getting-started.md +110 -0
  60. package/bundle/docs/cli/tutorials/task-planning.md +93 -0
  61. package/bundle/docs/cli/tutorials/web-tools.md +78 -0
  62. package/bundle/docs/core/index.md +107 -0
  63. package/bundle/docs/core/remote-agents.md +84 -0
  64. package/bundle/docs/core/subagents.md +307 -0
  65. package/bundle/docs/examples/proxy-script.md +83 -0
  66. package/bundle/docs/extensions/best-practices.md +188 -0
  67. package/bundle/docs/extensions/index.md +61 -0
  68. package/bundle/docs/extensions/reference.md +333 -0
  69. package/bundle/docs/extensions/releasing.md +154 -0
  70. package/bundle/docs/extensions/writing-extensions.md +308 -0
  71. package/bundle/docs/get-started/authentication.md +402 -0
  72. package/bundle/docs/get-started/examples.md +139 -0
  73. package/bundle/docs/get-started/gemini-3.md +115 -0
  74. package/bundle/docs/get-started/index.md +82 -0
  75. package/bundle/docs/get-started/installation.md +174 -0
  76. package/bundle/docs/hooks/best-practices.md +709 -0
  77. package/bundle/docs/hooks/index.md +164 -0
  78. package/bundle/docs/hooks/reference.md +330 -0
  79. package/bundle/docs/hooks/writing-hooks.md +474 -0
  80. package/bundle/docs/ide-integration/ide-companion-spec.md +267 -0
  81. package/bundle/docs/ide-integration/index.md +224 -0
  82. package/bundle/docs/index.md +141 -0
  83. package/bundle/docs/integration-tests.md +211 -0
  84. package/bundle/docs/issue-and-pr-automation.md +172 -0
  85. package/bundle/docs/local-development.md +134 -0
  86. package/bundle/docs/mermaid/context.mmd +103 -0
  87. package/bundle/docs/mermaid/render-path.mmd +64 -0
  88. package/bundle/docs/npm.md +62 -0
  89. package/bundle/docs/redirects.json +20 -0
  90. package/bundle/docs/reference/commands.md +526 -0
  91. package/bundle/docs/reference/configuration.md +1786 -0
  92. package/bundle/docs/reference/keyboard-shortcuts.md +164 -0
  93. package/bundle/docs/reference/memport.md +246 -0
  94. package/bundle/docs/reference/policy-engine.md +364 -0
  95. package/bundle/docs/reference/tools.md +106 -0
  96. package/bundle/docs/release-confidence.md +164 -0
  97. package/bundle/docs/releases.md +540 -0
  98. package/bundle/docs/resources/faq.md +175 -0
  99. package/bundle/docs/resources/quota-and-pricing.md +165 -0
  100. package/bundle/docs/resources/tos-privacy.md +102 -0
  101. package/bundle/docs/resources/troubleshooting.md +176 -0
  102. package/bundle/docs/resources/uninstall.md +56 -0
  103. package/bundle/docs/sidebar.json +233 -0
  104. package/bundle/docs/tools/activate-skill.md +43 -0
  105. package/bundle/docs/tools/ask-user.md +95 -0
  106. package/bundle/docs/tools/file-system.md +129 -0
  107. package/bundle/docs/tools/internal-docs.md +46 -0
  108. package/bundle/docs/tools/mcp-server.md +1150 -0
  109. package/bundle/docs/tools/memory.md +35 -0
  110. package/bundle/docs/tools/planning.md +58 -0
  111. package/bundle/docs/tools/shell.md +216 -0
  112. package/bundle/docs/tools/todos.md +35 -0
  113. package/bundle/docs/tools/web-fetch.md +35 -0
  114. package/bundle/docs/tools/web-search.md +32 -0
  115. package/bundle/docs/update/update-guide.md +111 -0
  116. package/bundle/masha.js +563471 -0
  117. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/client/main.js +89 -0
  118. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/_client-assets.d.ts +7 -0
  119. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/_client-assets.js +9 -0
  120. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/_client-assets.js.map +1 -0
  121. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/index.d.ts +48 -0
  122. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/index.js +299 -0
  123. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/index.js.map +1 -0
  124. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/types.d.ts +36 -0
  125. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/types.js +7 -0
  126. package/bundle/node_modules/@dgxo/mashadevcli-devtools/dist/src/types.js.map +1 -0
  127. package/bundle/node_modules/@dgxo/mashadevcli-devtools/package.json +32 -0
  128. package/bundle/policies/conseca.toml +6 -0
  129. package/bundle/policies/discovered.toml +8 -0
  130. package/bundle/policies/plan.toml +109 -0
  131. package/bundle/policies/read-only.toml +53 -0
  132. package/bundle/policies/write.toml +80 -0
  133. package/bundle/policies/yolo.toml +54 -0
  134. package/bundle/sandbox-macos-permissive-open.sb +27 -0
  135. package/bundle/sandbox-macos-permissive-proxied.sb +37 -0
  136. package/bundle/sandbox-macos-restrictive-open.sb +96 -0
  137. package/bundle/sandbox-macos-restrictive-proxied.sb +98 -0
  138. package/bundle/sandbox-macos-strict-open.sb +131 -0
  139. package/bundle/sandbox-macos-strict-proxied.sb +133 -0
  140. package/package.json +169 -0
@@ -0,0 +1,474 @@
1
+ # Writing hooks for Gemini CLI
2
+
3
+ This guide will walk you through creating hooks for Gemini CLI, from a simple
4
+ logging hook to a comprehensive workflow assistant.
5
+
6
+ ## Prerequisites
7
+
8
+ Before you start, make sure you have:
9
+
10
+ - Gemini CLI installed and configured
11
+ - Basic understanding of shell scripting or JavaScript/Node.js
12
+ - Familiarity with JSON for hook input/output
13
+
14
+ ## Quick start
15
+
16
+ Let's create a simple hook that logs all tool executions to understand the
17
+ basics.
18
+
19
+ **Crucial Rule:** Always write logs to `stderr`. Write only the final JSON to
20
+ `stdout`.
21
+
22
+ ### Step 1: Create your hook script
23
+
24
+ Create a directory for hooks and a simple logging script.
25
+
26
+ > **Note**:
27
+ >
28
+ > This example uses `jq` to parse JSON. If you don't have it installed, you can
29
+ > perform similar logic using Node.js or Python.
30
+
31
+ **macOS/Linux**
32
+
33
+ ```bash
34
+ mkdir -p .gemini/hooks
35
+ cat > .gemini/hooks/log-tools.sh << 'EOF'
36
+ #!/usr/bin/env bash
37
+ # Read hook input from stdin
38
+ input=$(cat)
39
+
40
+ # Extract tool name (requires jq)
41
+ tool_name=$(echo "$input" | jq -r '.tool_name')
42
+
43
+ # Log to stderr (visible in terminal if hook fails, or captured in logs)
44
+ echo "Logging tool: $tool_name" >&2
45
+
46
+ # Log to file
47
+ echo "[$(date)] Tool executed: $tool_name" >> .gemini/tool-log.txt
48
+
49
+ # Return success (exit 0) with empty JSON
50
+ echo "{}"
51
+ exit 0
52
+ EOF
53
+
54
+ chmod +x .gemini/hooks/log-tools.sh
55
+ ```
56
+
57
+ **Windows (PowerShell)**
58
+
59
+ ```powershell
60
+ New-Item -ItemType Directory -Force -Path ".gemini\hooks"
61
+ @"
62
+ # Read hook input from stdin
63
+ `$inputJson = `$input | Out-String | ConvertFrom-Json
64
+
65
+ # Extract tool name
66
+ `$toolName = `$inputJson.tool_name
67
+
68
+ # Log to stderr (visible in terminal if hook fails, or captured in logs)
69
+ [Console]::Error.WriteLine("Logging tool: `$toolName")
70
+
71
+ # Log to file
72
+ "[`$(Get-Date -Format 'o')] Tool executed: `$toolName" | Out-File -FilePath ".gemini\tool-log.txt" -Append -Encoding utf8
73
+
74
+ # Return success with empty JSON
75
+ "{}"
76
+ "@ | Out-File -FilePath ".gemini\hooks\log-tools.ps1" -Encoding utf8
77
+ ```
78
+
79
+ ## Exit Code Strategies
80
+
81
+ There are two ways to control or block an action in Gemini CLI:
82
+
83
+ | Strategy | Exit Code | Implementation | Best For |
84
+ | :------------------------- | :-------- | :----------------------------------------------------------------- | :---------------------------------------------------------- |
85
+ | **Structured (Idiomatic)** | `0` | Return a JSON object like `{"decision": "deny", "reason": "..."}`. | Production hooks, custom user feedback, and complex logic. |
86
+ | **Emergency Brake** | `2` | Print the error message to `stderr` and exit. | Simple security gates, script errors, or rapid prototyping. |
87
+
88
+ ## Practical examples
89
+
90
+ ### Security: Block secrets in commits
91
+
92
+ Prevent committing files containing API keys or passwords. Note that we use
93
+ **Exit Code 0** to provide a structured denial message to the agent.
94
+
95
+ **`.gemini/hooks/block-secrets.sh`:**
96
+
97
+ ```bash
98
+ #!/usr/bin/env bash
99
+ input=$(cat)
100
+
101
+ # Extract content being written
102
+ content=$(echo "$input" | jq -r '.tool_input.content // .tool_input.new_string // ""')
103
+
104
+ # Check for secrets
105
+ if echo "$content" | grep -qE 'api[_-]?key|password|secret'; then
106
+ # Log to stderr
107
+ echo "Blocked potential secret" >&2
108
+
109
+ # Return structured denial to stdout
110
+ cat <<EOF
111
+ {
112
+ "decision": "deny",
113
+ "reason": "Security Policy: Potential secret detected in content.",
114
+ "systemMessage": "🔒 Security scanner blocked operation"
115
+ }
116
+ EOF
117
+ exit 0
118
+ fi
119
+
120
+ # Allow
121
+ echo '{"decision": "allow"}'
122
+ exit 0
123
+ ```
124
+
125
+ ### Dynamic context injection (Git History)
126
+
127
+ Add relevant project context before each agent interaction.
128
+
129
+ **`.gemini/hooks/inject-context.sh`:**
130
+
131
+ ```bash
132
+ #!/usr/bin/env bash
133
+
134
+ # Get recent git commits for context
135
+ context=$(git log -5 --oneline 2>/dev/null || echo "No git history")
136
+
137
+ # Return as JSON
138
+ cat <<EOF
139
+ {
140
+ "hookSpecificOutput": {
141
+ "hookEventName": "BeforeAgent",
142
+ "additionalContext": "Recent commits:\n$context"
143
+ }
144
+ }
145
+ EOF
146
+ ```
147
+
148
+ ### RAG-based Tool Filtering (BeforeToolSelection)
149
+
150
+ Use `BeforeToolSelection` to intelligently reduce the tool space. This example
151
+ uses a Node.js script to check the user's prompt and allow only relevant tools.
152
+
153
+ **`.gemini/hooks/filter-tools.js`:**
154
+
155
+ ```javascript
156
+ #!/usr/bin/env node
157
+ const fs = require('fs');
158
+
159
+ async function main() {
160
+ const input = JSON.parse(fs.readFileSync(0, 'utf-8'));
161
+ const { llm_request } = input;
162
+
163
+ // Decoupled API: Access messages from llm_request
164
+ const messages = llm_request.messages || [];
165
+ const lastUserMessage = messages
166
+ .slice()
167
+ .reverse()
168
+ .find((m) => m.role === 'user');
169
+
170
+ if (!lastUserMessage) {
171
+ console.log(JSON.stringify({})); // Do nothing
172
+ return;
173
+ }
174
+
175
+ const text = lastUserMessage.content;
176
+ const allowed = ['write_todos']; // Always allow memory
177
+
178
+ // Simple keyword matching
179
+ if (text.includes('read') || text.includes('check')) {
180
+ allowed.push('read_file', 'list_directory');
181
+ }
182
+ if (text.includes('test')) {
183
+ allowed.push('run_shell_command');
184
+ }
185
+
186
+ // If we found specific intent, filter tools. Otherwise allow all.
187
+ if (allowed.length > 1) {
188
+ console.log(
189
+ JSON.stringify({
190
+ hookSpecificOutput: {
191
+ hookEventName: 'BeforeToolSelection',
192
+ toolConfig: {
193
+ mode: 'ANY', // Force usage of one of these tools (or AUTO)
194
+ allowedFunctionNames: allowed,
195
+ },
196
+ },
197
+ }),
198
+ );
199
+ } else {
200
+ console.log(JSON.stringify({}));
201
+ }
202
+ }
203
+
204
+ main().catch((err) => {
205
+ console.error(err);
206
+ process.exit(1);
207
+ });
208
+ ```
209
+
210
+ **`.gemini/settings.json`:**
211
+
212
+ ```json
213
+ {
214
+ "hooks": {
215
+ "BeforeToolSelection": [
216
+ {
217
+ "matcher": "*",
218
+ "hooks": [
219
+ {
220
+ "name": "intent-filter",
221
+ "type": "command",
222
+ "command": "node .gemini/hooks/filter-tools.js"
223
+ }
224
+ ]
225
+ }
226
+ ]
227
+ }
228
+ }
229
+ ```
230
+
231
+ > **TIP**
232
+ >
233
+ > **Union Aggregation Strategy**: `BeforeToolSelection` is unique in that it
234
+ > combines the results of all matching hooks. If you have multiple filtering
235
+ > hooks, the agent will receive the **union** of all whitelisted tools. Only
236
+ > using `mode: "NONE"` will override other hooks to disable all tools.
237
+
238
+ ## Complete example: Smart Development Workflow Assistant
239
+
240
+ This comprehensive example demonstrates all hook events working together. We
241
+ will build a system that maintains memory, filters tools, and checks for
242
+ security.
243
+
244
+ ### Architecture
245
+
246
+ 1. **SessionStart**: Load project memories.
247
+ 2. **BeforeAgent**: Inject memories into context.
248
+ 3. **BeforeToolSelection**: Filter tools based on intent.
249
+ 4. **BeforeTool**: Scan for secrets.
250
+ 5. **AfterModel**: Record interactions.
251
+ 6. **AfterAgent**: Validate final response quality (Retry).
252
+ 7. **SessionEnd**: Consolidate memories.
253
+
254
+ ### Configuration (`.gemini/settings.json`)
255
+
256
+ ```json
257
+ {
258
+ "hooks": {
259
+ "SessionStart": [
260
+ {
261
+ "matcher": "startup",
262
+ "hooks": [
263
+ {
264
+ "name": "init",
265
+ "type": "command",
266
+ "command": "node .gemini/hooks/init.js"
267
+ }
268
+ ]
269
+ }
270
+ ],
271
+ "BeforeAgent": [
272
+ {
273
+ "matcher": "*",
274
+ "hooks": [
275
+ {
276
+ "name": "memory",
277
+ "type": "command",
278
+ "command": "node .gemini/hooks/inject-memories.js"
279
+ }
280
+ ]
281
+ }
282
+ ],
283
+ "BeforeToolSelection": [
284
+ {
285
+ "matcher": "*",
286
+ "hooks": [
287
+ {
288
+ "name": "filter",
289
+ "type": "command",
290
+ "command": "node .gemini/hooks/rag-filter.js"
291
+ }
292
+ ]
293
+ }
294
+ ],
295
+ "BeforeTool": [
296
+ {
297
+ "matcher": "write_file",
298
+ "hooks": [
299
+ {
300
+ "name": "security",
301
+ "type": "command",
302
+ "command": "node .gemini/hooks/security.js"
303
+ }
304
+ ]
305
+ }
306
+ ],
307
+ "AfterModel": [
308
+ {
309
+ "matcher": "*",
310
+ "hooks": [
311
+ {
312
+ "name": "record",
313
+ "type": "command",
314
+ "command": "node .gemini/hooks/record.js"
315
+ }
316
+ ]
317
+ }
318
+ ],
319
+ "AfterAgent": [
320
+ {
321
+ "matcher": "*",
322
+ "hooks": [
323
+ {
324
+ "name": "validate",
325
+ "type": "command",
326
+ "command": "node .gemini/hooks/validate.js"
327
+ }
328
+ ]
329
+ }
330
+ ],
331
+ "SessionEnd": [
332
+ {
333
+ "matcher": "exit",
334
+ "hooks": [
335
+ {
336
+ "name": "save",
337
+ "type": "command",
338
+ "command": "node .gemini/hooks/consolidate.js"
339
+ }
340
+ ]
341
+ }
342
+ ]
343
+ }
344
+ }
345
+ ```
346
+
347
+ ### Hook Scripts
348
+
349
+ > **Note**: For brevity, these scripts use `console.error` for logging and
350
+ > standard `console.log` for JSON output.
351
+
352
+ #### 1. Initialize (`init.js`)
353
+
354
+ ```javascript
355
+ #!/usr/bin/env node
356
+ // Initialize DB or resources
357
+ console.error('Initializing assistant...');
358
+
359
+ // Output to user
360
+ console.log(
361
+ JSON.stringify({
362
+ systemMessage: '🧠 Smart Assistant Loaded',
363
+ }),
364
+ );
365
+ ```
366
+
367
+ #### 2. Inject Memories (`inject-memories.js`)
368
+
369
+ ```javascript
370
+ #!/usr/bin/env node
371
+ const fs = require('fs');
372
+
373
+ async function main() {
374
+ const input = JSON.parse(fs.readFileSync(0, 'utf-8'));
375
+ // Assume we fetch memories from a DB here
376
+ const memories = '- [Memory] Always use TypeScript for this project.';
377
+
378
+ console.log(
379
+ JSON.stringify({
380
+ hookSpecificOutput: {
381
+ hookEventName: 'BeforeAgent',
382
+ additionalContext: `\n## Relevant Memories\n${memories}`,
383
+ },
384
+ }),
385
+ );
386
+ }
387
+ main();
388
+ ```
389
+
390
+ #### 3. Security Check (`security.js`)
391
+
392
+ ```javascript
393
+ #!/usr/bin/env node
394
+ const fs = require('fs');
395
+ const input = JSON.parse(fs.readFileSync(0));
396
+ const content = input.tool_input.content || '';
397
+
398
+ if (content.includes('SECRET_KEY')) {
399
+ console.log(
400
+ JSON.stringify({
401
+ decision: 'deny',
402
+ reason: 'Found SECRET_KEY in content',
403
+ systemMessage: '🚨 Blocked sensitive commit',
404
+ }),
405
+ );
406
+ process.exit(0);
407
+ }
408
+
409
+ console.log(JSON.stringify({ decision: 'allow' }));
410
+ ```
411
+
412
+ #### 4. Record Interaction (`record.js`)
413
+
414
+ ```javascript
415
+ #!/usr/bin/env node
416
+ const fs = require('fs');
417
+ const path = require('path');
418
+
419
+ const input = JSON.parse(fs.readFileSync(0));
420
+ const { llm_request, llm_response } = input;
421
+ const logFile = path.join(
422
+ process.env.GEMINI_PROJECT_DIR,
423
+ '.gemini/memory/session.jsonl',
424
+ );
425
+
426
+ fs.appendFileSync(
427
+ logFile,
428
+ JSON.stringify({
429
+ request: llm_request,
430
+ response: llm_response,
431
+ timestamp: new Date().toISOString(),
432
+ }) + '\n',
433
+ );
434
+
435
+ console.log(JSON.stringify({}));
436
+ ```
437
+
438
+ #### 5. Validate Response (`validate.js`)
439
+
440
+ ```javascript
441
+ #!/usr/bin/env node
442
+ const fs = require('fs');
443
+ const input = JSON.parse(fs.readFileSync(0));
444
+ const response = input.prompt_response;
445
+
446
+ // Example: Check if the agent forgot to include a summary
447
+ if (!response.includes('Summary:')) {
448
+ console.log(
449
+ JSON.stringify({
450
+ decision: 'block', // Triggers an automatic retry turn
451
+ reason: 'Your response is missing a Summary section. Please add one.',
452
+ systemMessage: '🔄 Requesting missing summary...',
453
+ }),
454
+ );
455
+ process.exit(0);
456
+ }
457
+
458
+ console.log(JSON.stringify({ decision: 'allow' }));
459
+ ```
460
+
461
+ #### 6. Consolidate Memories (`consolidate.js`)
462
+
463
+ ```javascript
464
+ #!/usr/bin/env node
465
+ // Logic to save final session state
466
+ console.error('Consolidating memories for session end...');
467
+ ```
468
+
469
+ ## Packaging as an extension
470
+
471
+ While project-level hooks are great for specific repositories, you can share
472
+ your hooks across multiple projects by packaging them as a
473
+ [Gemini CLI extension](https://www.google.com/search?q=../extensions/index.md).
474
+ This provides version control, easy distribution, and centralized management.