context-brake 1.0.0 → 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 (195) hide show
  1. package/README.md +31 -41
  2. package/dist/assets/runtime/antigravity-cli-hook.mjs +68 -23
  3. package/dist/assets/runtime/claude-code-hook.mjs +133 -35
  4. package/dist/assets/runtime/claude-code-mod.mjs +165 -59
  5. package/dist/assets/runtime/claude-code-statusline.mjs +41 -9
  6. package/dist/assets/runtime/codex-cli-hook.mjs +71 -23
  7. package/dist/assets/runtime/cursor-hook.mjs +71 -23
  8. package/dist/assets/runtime/github-copilot-cli-hook.mjs +71 -23
  9. package/dist/assets/runtime/omp-extension.js +70 -23
  10. package/dist/assets/runtime/omp-restart.js +41 -9
  11. package/dist/assets/runtime/opencode-plugin.js +70 -23
  12. package/dist/assets/runtime/pi-extension.js +73 -23
  13. package/dist/assets/runtime/pi-restart.js +41 -9
  14. package/dist/src/cli/assistant/assistant-context.js +7 -0
  15. package/dist/src/cli/assistant/assistant-questions.js +5 -4
  16. package/dist/src/cli/assistant/assistant-session.js +3 -1
  17. package/dist/src/cli/assistant/invocation-facts.d.ts +5 -0
  18. package/dist/src/cli/assistant/invocation-facts.js +6 -0
  19. package/dist/src/cli/assistant/questions-misc.d.ts +1 -0
  20. package/dist/src/cli/assistant/questions-misc.js +3 -2
  21. package/dist/src/cli/assistant/questions-skill.d.ts +21 -0
  22. package/dist/src/cli/assistant/questions-skill.js +45 -0
  23. package/dist/src/cli/assistant/questions-snapshot.d.ts +3 -1
  24. package/dist/src/cli/assistant/questions-snapshot.js +21 -26
  25. package/dist/src/cli/assistant/questions-trigger.d.ts +6 -0
  26. package/dist/src/cli/assistant/questions-trigger.js +56 -0
  27. package/dist/src/cli/assistant/skill-options.d.ts +20 -0
  28. package/dist/src/cli/assistant/skill-options.js +40 -0
  29. package/dist/src/cli/assistant/snapshot-specs.d.ts +7 -1
  30. package/dist/src/cli/assistant/snapshot-specs.js +17 -7
  31. package/dist/src/cli/assistant/summary-rows.d.ts +5 -0
  32. package/dist/src/cli/assistant/summary-rows.js +47 -0
  33. package/dist/src/cli/assistant/summary.d.ts +2 -1
  34. package/dist/src/cli/assistant/summary.js +21 -30
  35. package/dist/src/cli/assistant/types.d.ts +15 -0
  36. package/dist/src/cli/commands/doctor.js +2 -1
  37. package/dist/src/cli/commands/remove.js +1 -1
  38. package/dist/src/cli/init-arguments.js +5 -4
  39. package/dist/src/cli/init-flow.js +1 -1
  40. package/dist/src/cli/init-option-rules.d.ts +5 -0
  41. package/dist/src/cli/init-option-rules.js +16 -0
  42. package/dist/src/cli/output/card.d.ts +8 -0
  43. package/dist/src/cli/output/card.js +30 -0
  44. package/dist/src/cli/output/doctor-mode-text.js +8 -2
  45. package/dist/src/cli/output/install-rows.d.ts +6 -0
  46. package/dist/src/cli/output/install-rows.js +31 -0
  47. package/dist/src/cli/output/install-text.d.ts +4 -0
  48. package/dist/src/cli/output/install-text.js +26 -0
  49. package/dist/src/cli/output/style.d.ts +22 -0
  50. package/dist/src/cli/output/style.js +27 -0
  51. package/dist/src/cli/output/text.d.ts +1 -2
  52. package/dist/src/cli/output/text.js +1 -28
  53. package/dist/src/core/contracts/adapter.d.ts +2 -1
  54. package/dist/src/core/contracts/configuration.d.ts +2 -1
  55. package/dist/src/core/contracts/configuration.js +2 -10
  56. package/dist/src/core/contracts/context-reading.d.ts +16 -0
  57. package/dist/src/core/contracts/context-reading.js +20 -0
  58. package/dist/src/core/contracts/context-window-report.d.ts +8 -1
  59. package/dist/src/core/contracts/context-window-report.js +3 -1
  60. package/dist/src/core/contracts/diagnostics.d.ts +21 -0
  61. package/dist/src/core/contracts/diagnostics.js +2 -1
  62. package/dist/src/core/contracts/manifest.d.ts +16 -0
  63. package/dist/src/core/contracts/manifest.js +6 -0
  64. package/dist/src/core/contracts/runtime.d.ts +2 -0
  65. package/dist/src/core/contracts/skill-catalog.d.ts +11 -0
  66. package/dist/src/core/contracts/skill-catalog.js +1 -0
  67. package/dist/src/core/contracts/skill-invocation.d.ts +3 -0
  68. package/dist/src/core/contracts/skill-invocation.js +1 -0
  69. package/dist/src/core/contracts/skill-name.d.ts +5 -0
  70. package/dist/src/core/contracts/skill-name.js +31 -0
  71. package/dist/src/core/services/brake-engine.js +4 -3
  72. package/dist/src/core/services/doctor-report-extras.d.ts +2 -0
  73. package/dist/src/core/services/doctor-report-extras.js +22 -5
  74. package/dist/src/core/services/doctor-service.d.ts +2 -0
  75. package/dist/src/core/services/doctor-service.js +1 -1
  76. package/dist/src/core/services/failure-policy.js +1 -1
  77. package/dist/src/core/services/injection-policy.d.ts +1 -0
  78. package/dist/src/core/services/injection-policy.js +1 -1
  79. package/dist/src/core/services/installation-adapters.d.ts +2 -1
  80. package/dist/src/core/services/installation-adapters.js +3 -1
  81. package/dist/src/core/services/installation-builder.js +3 -2
  82. package/dist/src/core/services/installation-service.js +1 -1
  83. package/dist/src/core/services/manifest-change.d.ts +2 -1
  84. package/dist/src/core/services/manifest-change.js +2 -1
  85. package/dist/src/core/services/session-reset-handler.js +1 -1
  86. package/dist/src/core/services/skill-candidates.d.ts +16 -0
  87. package/dist/src/core/services/skill-candidates.js +14 -0
  88. package/dist/src/core/services/skill-invocation.d.ts +4 -0
  89. package/dist/src/core/services/skill-invocation.js +12 -0
  90. package/dist/src/core/services/skill-ranking.d.ts +7 -0
  91. package/dist/src/core/services/skill-ranking.js +25 -0
  92. package/dist/src/core/services/snapshot-merge.d.ts +1 -0
  93. package/dist/src/core/services/snapshot-merge.js +12 -5
  94. package/dist/src/core/services/trigger-text.d.ts +5 -0
  95. package/dist/src/core/services/trigger-text.js +4 -0
  96. package/dist/src/core/services/zone-guidance.d.ts +13 -2
  97. package/dist/src/core/services/zone-guidance.js +14 -8
  98. package/dist/src/infrastructure/harnesses/antigravity-cli/runtime.js +2 -1
  99. package/dist/src/infrastructure/harnesses/antigravity-cli/skill-folders.d.ts +1 -0
  100. package/dist/src/infrastructure/harnesses/antigravity-cli/skill-folders.js +1 -0
  101. package/dist/src/infrastructure/harnesses/antigravity-cli/skill-invocation.d.ts +2 -0
  102. package/dist/src/infrastructure/harnesses/antigravity-cli/skill-invocation.js +2 -0
  103. package/dist/src/infrastructure/harnesses/claude-code/adapter.js +6 -4
  104. package/dist/src/infrastructure/harnesses/claude-code/auto-restart-diagnostics.d.ts +1 -0
  105. package/dist/src/infrastructure/harnesses/claude-code/auto-restart-diagnostics.js +2 -2
  106. package/dist/src/infrastructure/harnesses/claude-code/auto-restart-planner.d.ts +5 -1
  107. package/dist/src/infrastructure/harnesses/claude-code/auto-restart-planner.js +6 -6
  108. package/dist/src/infrastructure/harnesses/claude-code/capabilities.js +1 -1
  109. package/dist/src/infrastructure/harnesses/claude-code/context-readings-scan.d.ts +2 -0
  110. package/dist/src/infrastructure/harnesses/claude-code/context-readings-scan.js +21 -0
  111. package/dist/src/infrastructure/harnesses/claude-code/context-source.d.ts +10 -0
  112. package/dist/src/infrastructure/harnesses/claude-code/context-source.js +16 -0
  113. package/dist/src/infrastructure/harnesses/claude-code/mod/context-reading.d.ts +2 -0
  114. package/dist/src/infrastructure/harnesses/claude-code/mod/context-reading.js +67 -0
  115. package/dist/src/infrastructure/harnesses/claude-code/mod/host.d.ts +9 -0
  116. package/dist/src/infrastructure/harnesses/claude-code/mod/mod-info.d.ts +1 -1
  117. package/dist/src/infrastructure/harnesses/claude-code/mod/mod-info.js +1 -1
  118. package/dist/src/infrastructure/harnesses/claude-code/mod/mod-log.d.ts +1 -0
  119. package/dist/src/infrastructure/harnesses/claude-code/mod/mod-log.js +3 -0
  120. package/dist/src/infrastructure/harnesses/claude-code/mod/register.js +6 -1
  121. package/dist/src/infrastructure/harnesses/claude-code/mod-reading.d.ts +6 -0
  122. package/dist/src/infrastructure/harnesses/claude-code/mod-reading.js +37 -0
  123. package/dist/src/infrastructure/harnesses/claude-code/planner.d.ts +2 -1
  124. package/dist/src/infrastructure/harnesses/claude-code/planner.js +4 -4
  125. package/dist/src/infrastructure/harnesses/claude-code/project-root.d.ts +2 -0
  126. package/dist/src/infrastructure/harnesses/claude-code/project-root.js +5 -0
  127. package/dist/src/infrastructure/harnesses/claude-code/runtime.js +12 -7
  128. package/dist/src/infrastructure/harnesses/claude-code/skill-folders.d.ts +1 -0
  129. package/dist/src/infrastructure/harnesses/claude-code/skill-folders.js +1 -0
  130. package/dist/src/infrastructure/harnesses/claude-code/skill-invocation.d.ts +2 -0
  131. package/dist/src/infrastructure/harnesses/claude-code/skill-invocation.js +2 -0
  132. package/dist/src/infrastructure/harnesses/claude-code/statusline-context-window.js +15 -2
  133. package/dist/src/infrastructure/harnesses/claude-code/statusline-diagnostics.js +3 -3
  134. package/dist/src/infrastructure/harnesses/claude-code/statusline-migration.d.ts +3 -0
  135. package/dist/src/infrastructure/harnesses/claude-code/statusline-migration.js +23 -0
  136. package/dist/src/infrastructure/harnesses/claude-code/statusline-planner.d.ts +2 -1
  137. package/dist/src/infrastructure/harnesses/claude-code/statusline-planner.js +7 -4
  138. package/dist/src/infrastructure/harnesses/claude-code/user-settings.d.ts +2 -0
  139. package/dist/src/infrastructure/harnesses/claude-code/user-settings.js +11 -0
  140. package/dist/src/infrastructure/harnesses/codex-cli/adapter.js +5 -4
  141. package/dist/src/infrastructure/harnesses/codex-cli/runtime.js +2 -1
  142. package/dist/src/infrastructure/harnesses/codex-cli/skill-folders.d.ts +1 -0
  143. package/dist/src/infrastructure/harnesses/codex-cli/skill-folders.js +1 -0
  144. package/dist/src/infrastructure/harnesses/codex-cli/skill-invocation.d.ts +2 -0
  145. package/dist/src/infrastructure/harnesses/codex-cli/skill-invocation.js +2 -0
  146. package/dist/src/infrastructure/harnesses/common/config-origin.d.ts +10 -0
  147. package/dist/src/infrastructure/harnesses/common/config-origin.js +52 -0
  148. package/dist/src/infrastructure/harnesses/cursor/adapter.js +5 -4
  149. package/dist/src/infrastructure/harnesses/cursor/runtime.js +2 -1
  150. package/dist/src/infrastructure/harnesses/cursor/skill-folders.d.ts +1 -0
  151. package/dist/src/infrastructure/harnesses/cursor/skill-folders.js +1 -0
  152. package/dist/src/infrastructure/harnesses/cursor/skill-invocation.d.ts +2 -0
  153. package/dist/src/infrastructure/harnesses/cursor/skill-invocation.js +2 -0
  154. package/dist/src/infrastructure/harnesses/github-copilot-cli/runtime.js +2 -1
  155. package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-folders.d.ts +1 -0
  156. package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-folders.js +1 -0
  157. package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-invocation.d.ts +2 -0
  158. package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-invocation.js +2 -0
  159. package/dist/src/infrastructure/harnesses/oh-my-pi/runtime.js +2 -1
  160. package/dist/src/infrastructure/harnesses/oh-my-pi/skill-folders.d.ts +1 -0
  161. package/dist/src/infrastructure/harnesses/oh-my-pi/skill-folders.js +1 -0
  162. package/dist/src/infrastructure/harnesses/oh-my-pi/skill-invocation.d.ts +2 -0
  163. package/dist/src/infrastructure/harnesses/oh-my-pi/skill-invocation.js +2 -0
  164. package/dist/src/infrastructure/harnesses/opencode/runtime.js +2 -1
  165. package/dist/src/infrastructure/harnesses/opencode/skill-folders.d.ts +1 -0
  166. package/dist/src/infrastructure/harnesses/opencode/skill-folders.js +1 -0
  167. package/dist/src/infrastructure/harnesses/opencode/skill-invocation.d.ts +2 -0
  168. package/dist/src/infrastructure/harnesses/opencode/skill-invocation.js +2 -0
  169. package/dist/src/infrastructure/harnesses/pi/runtime.js +2 -1
  170. package/dist/src/infrastructure/harnesses/pi/skill-folders.d.ts +1 -0
  171. package/dist/src/infrastructure/harnesses/pi/skill-folders.js +1 -0
  172. package/dist/src/infrastructure/harnesses/pi/skill-invocation.d.ts +2 -0
  173. package/dist/src/infrastructure/harnesses/pi/skill-invocation.js +2 -0
  174. package/dist/src/infrastructure/harnesses/skill-folders.d.ts +3 -0
  175. package/dist/src/infrastructure/harnesses/skill-folders.js +21 -0
  176. package/dist/src/infrastructure/harnesses/skill-invocations.d.ts +4 -0
  177. package/dist/src/infrastructure/harnesses/skill-invocations.js +21 -0
  178. package/dist/src/infrastructure/runtime/runtime-paths.js +2 -1
  179. package/dist/src/infrastructure/skills/frontmatter.d.ts +5 -0
  180. package/dist/src/infrastructure/skills/frontmatter.js +25 -0
  181. package/dist/src/infrastructure/skills/skill-catalog-reader.d.ts +4 -0
  182. package/dist/src/infrastructure/skills/skill-catalog-reader.js +78 -0
  183. package/dist/src/infrastructure/skills/skill-catalog.d.ts +2 -0
  184. package/dist/src/infrastructure/skills/skill-catalog.js +5 -0
  185. package/dist/src/infrastructure/storage/change-applier.d.ts +1 -0
  186. package/dist/src/infrastructure/storage/change-applier.js +2 -1
  187. package/dist/src/infrastructure/storage/json-document-editor.js +2 -1
  188. package/dist/src/infrastructure/storage/json-node-removal.d.ts +2 -0
  189. package/dist/src/infrastructure/storage/json-node-removal.js +70 -0
  190. package/dist/src/infrastructure/storage/json-span-utils.d.ts +1 -1
  191. package/dist/src/infrastructure/storage/json-span-utils.js +1 -48
  192. package/docs/telemetry-block.md +3 -1
  193. package/package.json +1 -1
  194. package/schemas/context-brake.config.schema.json +9 -4
  195. package/schemas/doctor-report.schema.json +51 -0
package/README.md CHANGED
@@ -56,7 +56,7 @@ Support levels come from each vendor's documentation, checked in September 2026.
56
56
 
57
57
  | Harness | Integration point | Support level | Main limitation |
58
58
  | :--- | :--- | :--- | :--- |
59
- | Claude Code (`claude-code`) | Hooks in `.claude/settings.json` | Full | Context usage is read from the session transcript, whose format is undocumented, with an estimate as fallback; the context window comes from the status line bridge, which `init` installs by default |
59
+ | Claude Code (`claude-code`) | Hooks in `.claude/settings.json` | Full | Context usage is read from the session transcript, whose format is undocumented, with an estimate as fallback; the context window comes from the [mod](#claude-code-context-source) that `init` installs on Claude Code 2.1.287 or later, or from the status line bridge on older versions |
60
60
  | Codex CLI (`codex-cli`) | Hooks in `.codex/hooks.json` | Full | Context usage and window are read from the session rollout file, whose format is undocumented; falls back to an estimate |
61
61
  | Cursor (`cursor`) | Hooks in `.cursor/hooks.json` | Full | Context usage is only sent before compaction |
62
62
  | GitHub Copilot CLI (`github-copilot-cli`) | Hooks in `.github/hooks/*.json` | Full | Context usage is not exposed to hooks, so ContextBrake estimates it |
@@ -65,7 +65,7 @@ Support levels come from each vendor's documentation, checked in September 2026.
65
65
  | Oh-My-Pi (`oh-my-pi`) | Extensions in `.omp/extensions/` | Full | Restart takes one Enter on the prefilled `/context-brake-restart` |
66
66
  | Antigravity CLI (`antigravity-cli`) | Hooks in `.agents/hooks.json` | Partial | Telemetry is injected through `PreInvocation`, and `PostToolUse` accepts only empty output |
67
67
 
68
- Aider is not supported because it has no hook mechanism. The full capability matrix and its sources are in the [installation PRD](./tasks/prd-01-instalacao-deteccao-diagnostico/prd.md).
68
+ Aider is not supported because it has no hook mechanism. The hook and plugin APIs behind each row, with their sources, are in the [harness research](./docs/research/harness-integrations.md).
69
69
 
70
70
  ---
71
71
 
@@ -110,16 +110,16 @@ npx context-brake init --yes
110
110
  npx context-brake doctor
111
111
  ```
112
112
 
113
- To have the agent save its state before a reset, pass your snapshot command, and optionally the command that resumes the work in the new session:
113
+ To have the agent save its state before a reset, pass the name of your snapshot skill, and optionally the name of the skill that resumes the work in the new session:
114
114
 
115
115
  ```bash
116
- npx context-brake init --yes --snapshot-command "/sdd-snapshot" --resume-command "/sdd-orchestrate-flow"
116
+ npx context-brake init --yes --snapshot-command sdd-snapshot --resume-command sdd-orchestrate-flow
117
117
  ```
118
118
 
119
119
  ### What `context-brake init` does:
120
120
 
121
121
  1. **Detects coding-agent harnesses:** Identifies Claude Code, Cursor, Codex CLI, GitHub Copilot CLI, Antigravity CLI, OpenCode, Pi, and Oh-My-Pi from repository signals and machine configuration.
122
- 2. **Registers integrations safely:** Injects the appropriate hooks/plugins in each harness's own configuration, preserving user settings and comments, and installs the [status line bridge](#claude-code-status-line-bridge) for Claude Code.
122
+ 2. **Registers integrations safely:** Injects the appropriate hooks/plugins in each harness's own configuration, preserving user settings and comments, and, for Claude Code, installs the [mod that reads the context](#claude-code-context-source) or, on versions without mods, the [status line bridge](#claude-code-status-line-bridge).
123
123
  3. **Initializes config:** Creates `context-brake.config.json` with the telemetry limits and the `snapshot` section, and records the installed files in `.context-brake/manifest.json`.
124
124
 
125
125
  It does not touch instruction files such as `CLAUDE.md` and `AGENTS.md`. The only change it makes to your `.gitignore` is the marked block described in [Keeping ContextBrake Out of Git](#keeping-contextbrake-out-of-git). Runtime state lives in `.context-brake/runtime/`, which carries its own `.gitignore`.
@@ -134,7 +134,8 @@ npx context-brake init --interactive --dry-run
134
134
  ```
135
135
 
136
136
  - **When it starts:** only when both stdin and stdout are terminals and none of `--yes`, `--json`, or a configuration flag (`--harness`, `--exclude-harness`, any snapshot flag, `--debug`, `--statusline-bridge`, `--auto-restart`, `--max-restarts`, and their `--no-` forms) is given. Scripts, CI, and `--json` runs never see a prompt and behave exactly as before. `--interactive` without a terminal exits with code 64 and names the flags to use instead; combined with `--yes` or `--json` it is an argument error.
137
- - **Questions, in order:** the harnesses to configure (detected ones are marked with their support level; turning off a detected one excludes it, as `--exclude-harness` does), the snapshot command, its trigger zone and resume command (only when a command is set), restart on or off with the restart mode of each selected harness (only when one can restart), the consecutive-restart limit (only when restart is on), the Claude Code status line bridge (only when Claude Code is selected), and debug mode. Enter keeps the value shown in brackets, which is the current configuration or the default. An invalid answer prints its rule and asks again.
137
+ - **Questions, in order:** the harnesses to configure (detected ones are marked with their support level; turning off a detected one excludes it, as `--exclude-harness` does), the snapshot command, its trigger (a zone or a percentage of the context window) and resume command (only when a command is set), restart on or off with the restart mode of each selected harness (only when one can restart), the consecutive-restart limit (only when restart is on), the Claude Code status line bridge (only when Claude Code is selected), and debug mode. Enter keeps the value shown in brackets, which is the current configuration or the default. An invalid answer prints its rule and asks again.
138
+ - **Skill suggestions:** for the snapshot and the resume questions, the assistant looks at the skill folders of the selected harnesses in the project (for example `.claude/skills`, `.agents/skills`, `.cursor/skills`, `.github/skills`, `.opencode/skills`, `.pi/skills`, `.omp/skills`), reads only the top of each `SKILL.md` for its name and description, and lists the best matches first. A name containing `snapshot`, `handoff`, or `checkpoint` ranks first for the snapshot; `resume`, `continue`, `orchestrate`, `flow`, and the Portuguese `retomar`, `retomada`, `continuar` for the resume; the description counts less, and the skill chosen for the snapshot is never offered for the resume. The list shows the recommended skill, up to three alternatives, `type another`, and for the snapshot `none`, and says where each one was found (the resume skill can be changed here but only removed with `--no-snapshot-command`, which clears both skills). The suggestion is a hint, not a decision: nothing is chosen without your Enter, and when nothing matches (or a folder cannot be read) you get the plain text question. Only skills inside the project folders are read: not your user-level skills, plugin skills, `.claude/commands`, or folders above the project root. A run with `--yes` or any configuration flag reads no skill folder.
138
139
  - **Prompts:** on a terminal the questions use arrow keys, Space to mark, and Enter to confirm (a checkbox list for harnesses, yes or no for the switches, a list for the trigger zone and the restart limit, text fields for the commands). Set `CONTEXT_BRAKE_PLAIN_PROMPTS=1`, or run in a terminal with `TERM=dumb`, to get plain line-by-line questions instead; the questions and the resulting flags are the same.
139
140
  - **Summary and equivalent command:** before the plan, the assistant prints what you chose and the `context-brake init ...` command that reproduces it. Values with spaces or shell characters are single-quoted, and a value that contains a single quote is printed once for POSIX shells and once for PowerShell. Add `--yes` to repeat the setup without prompts; a command with no flags means nothing changes and starts the questions again on a terminal.
140
141
  - **Confirming and cancelling:** the assistant shows the usual plan and asks the usual single confirmation. Ctrl+C or the end of input at any prompt prints `Nothing was written.` and exits with code 0, like a declined confirmation. With `--dry-run` it shows the plan and writes nothing. Typed configuration flags passed together with `--interactive` are not used; only `--dry-run` is.
@@ -194,7 +195,7 @@ The files `init` creates belong to your machine and `init` can regenerate them,
194
195
  }
195
196
  ```
196
197
 
197
- `contextWindowCeiling` is the session's context budget: when the harness does not report the active model's window, zone percentages are computed against it, and the telemetry block shows `window=config`. A more accurate window comes from the harness (`window=harness`: Pi and Oh-My-Pi, Codex through the session rollout file, and Claude Code through the [status line bridge](#claude-code-status-line-bridge), which `init` installs by default) or, for the harnesses that report none (Cursor, GitHub Copilot, Antigravity, OpenCode), from a window you declare in `telemetry.declaredContextWindow` (`window=declared`). A declared window is ignored by Claude Code, Codex, Pi, and Oh-My-Pi, whose window comes from the harness. The optional `zones.greenMaxTurn` and `zones.yellowMaxTurn` must be set together, with `greenMaxTurn` lower; they raise the zone up to `RED` by turns.
198
+ `contextWindowCeiling` is the session's context budget: when the harness does not report the active model's window, zone percentages are computed against it, and the telemetry block shows `window=config`. A more accurate window comes from the harness (`window=harness`: Pi and Oh-My-Pi, Codex through the session rollout file, and Claude Code through the [mod](#claude-code-context-source), or the [status line bridge](#claude-code-status-line-bridge) on versions without mods) or, for the harnesses that report none (Cursor, GitHub Copilot, Antigravity, OpenCode), from a window you declare in `telemetry.declaredContextWindow` (`window=declared`). A declared window is ignored by Claude Code, Codex, Pi, and Oh-My-Pi, whose window comes from the harness. The optional `zones.greenMaxTurn` and `zones.yellowMaxTurn` must be set together, with `greenMaxTurn` lower; they raise the zone up to `RED` by turns.
198
199
 
199
200
  ### Excluding a Harness
200
201
 
@@ -206,23 +207,34 @@ A configuration that still carries keys ContextBrake no longer reads (for exampl
206
207
 
207
208
  ### Snapshot and Resume Commands
208
209
 
209
- If your workflow saves session state with its own skill or command, as the SDD skills in this repository do, name it in the `snapshot` section:
210
+ If your workflow saves session state with its own skill, as the SDD skills in this repository do, name it in the `snapshot` section. The value is the **bare skill name**, with no `/`, `$`, or `@`; each harness writes the invocation in its own form:
210
211
 
211
212
  ```json
212
213
  {
213
214
  "snapshot": {
214
215
  "triggerZone": "RED",
215
- "command": "/sdd-snapshot",
216
- "resumeCommand": "/sdd-orchestrate-flow"
216
+ "command": "sdd-snapshot",
217
+ "resumeCommand": "sdd-orchestrate-flow"
217
218
  }
218
219
  }
219
220
  ```
220
221
 
221
- - **`command`:** from `triggerZone` on (`RED` by default, or `YELLOW`), the telemetry action becomes `run "<command>", then end reply with [REQUEST_SESSION_RESET]`, and in `CRITICAL` it says `now`. ContextBrake never runs the command; it only passes the text to the agent, so the command can be a skill, a slash command, or a short instruction.
222
- - **`resumeCommand`:** after `/clear`, `/new`, or compaction, harnesses that inject context at session start add `[ContextBrake resume v1] Run "<resumeCommand>" before continuing.` A resume command requires a snapshot command.
222
+ - **`command`:** from `triggerZone` on (`RED` by default, or `YELLOW`), the telemetry action becomes `run "<invocation>", then end reply with [REQUEST_SESSION_RESET]`, and in `CRITICAL` it says `now`. ContextBrake never runs the skill; it passes the invocation to the agent, written the way the harness that receives it invokes a skill.
223
+ - **`resumeCommand`:** after `/clear`, `/new`, or compaction, harnesses that inject context at session start add `[ContextBrake resume v1] Run "<invocation>" before continuing.` A resume skill requires a snapshot skill.
224
+
225
+ | Harness | Invocation of `sdd-snapshot` |
226
+ | :--- | :--- |
227
+ | Claude Code, Cursor, GitHub Copilot CLI | `/sdd-snapshot` |
228
+ | Codex CLI | `$sdd-snapshot` |
229
+ | Pi | `/skill:sdd-snapshot` |
230
+ | Oh-My-Pi, OpenCode, Antigravity CLI | `use the sdd-snapshot skill` (these harnesses have no invocation form that works without extra setup) |
231
+
232
+ A name is lowercase letters, digits, and single hyphens, up to 64 characters, optionally prefixed by a plugin name and a colon (`plugin:skill`). A value such as `/sdd-snapshot` is rejected with the bare name to use instead. `context-brake doctor` lists the invocation each active harness receives.
223
233
  - **Without a command:** the telemetry block only carries the generic actions in the [zone table](#-zones), with no reset request, and nothing is injected at session start.
224
234
 
225
- Set them with `init`: `--snapshot-command <text>`, `--resume-command <text>`, and `--snapshot-trigger <YELLOW|RED>`. `--no-snapshot-command` clears both commands and keeps the trigger zone. Each command is one line of at most 200 characters. In Git Bash on Windows, run `MSYS_NO_PATHCONV=1 npx context-brake init ...`, because Git Bash rewrites an argument that starts with `/`, such as `/sdd-snapshot`, into a Windows path. `context-brake doctor` shows the settings in effect, and `doctor --json` reports them under `snapshot`.
235
+ - **`triggerPercentage`:** an optional whole number from 1 to 100 that replaces `triggerZone` as the trigger: the reset action starts once the context usage reaches that percentage, even in `GREEN` and below `activationThresholdPercentage` (the block is injected from that point on). `init` offers it in the trigger question and removes it when you pick a zone again.
236
+
237
+ Set them with `init`: `--snapshot-command <skill>`, `--resume-command <skill>`, `--snapshot-trigger <YELLOW|RED>`, and `--snapshot-trigger-percentage <1-100>` (not together with `--snapshot-trigger`). `--no-snapshot-command` clears both skills and keeps the trigger. `context-brake doctor` shows the settings in effect, and `doctor --json` reports them under `snapshot`, with the invocation of each active harness under `snapshot.invocations`.
226
238
 
227
239
  ### Debug Mode
228
240
 
@@ -249,9 +261,13 @@ The agent copies that line instead of composing it. Nothing is written to instru
249
261
 
250
262
  `context-brake doctor` lists the repository's active sessions with their current context usage: percentage, tokens, window, zone, and whether the reading was measured or estimated. It also shows the time of each session's last activity. The data comes from the session ledger ContextBrake already keeps under `.context-brake/runtime/sessions/`, using the newest reading after the last reset, from the status line bridge or from the last tool call. ContextBrake cannot tell whether a harness process is still running. A session counts as active when its last recorded activity is within 30 minutes, and at most 10 sessions are listed. `doctor --json` reports them under `activeSessions`, and the list is omitted when no session is active.
251
263
 
264
+ ### Claude Code Context Source
265
+
266
+ Claude Code sends the active model's context window only to the status line command and to mods, never to hooks. On Claude Code 2.1.287 or later, `init` installs a mod that publishes the window and the input tokens, so zones use the real window instead of `contextWindowCeiling` and `init` never touches your `statusLine`. The mod runs in the files under `.context-brake/claude-mod/` and registers itself in `.claude/settings.local.json`; it restarts nothing unless you also use `--auto-restart`. `init` reads the installed version with `claude --version`; when it cannot, or the version is older, it installs the status line bridge below instead. Running `init` again on a compatible version migrates an installed bridge: it restores the status line you had and removes the bridge script. `context-brake doctor` reports `contextWindow.source` (`mod`, `statusline`, or `contextWindowCeiling`) and `contextWindow.mod` (`absent`, `installed`, or `reporting`; `reporting` means a session of this repository has reported a reading at some point, with no freshness bound), and warns with `CONTEXT_MOD_SILENT` when the mod is installed but no session has reported yet (mods stay off under `disableAllHooks`, `--safe-mode`, `--bare`, an organization managed policy, and in Desktop WSL sessions).
267
+
252
268
  ### Claude Code Status Line Bridge
253
269
 
254
- Claude Code sends the active model's context window only to the status line command, never to hooks. The bridge reads it there, so zones in Claude Code use the real window instead of `contextWindowCeiling`. `init` installs it by default. To turn it back on after an opt-out:
270
+ On Claude Code versions without mods, the bridge reads the context window from the status line command, so zones use the real window instead of `contextWindowCeiling`. `init` installs it there by default. To use it on any version, including after an opt-out:
255
271
 
256
272
  ```bash
257
273
  npx context-brake init --statusline-bridge
@@ -309,38 +325,12 @@ Each hook call has an internal deadline of 1.5 seconds; the session start event
309
325
 
310
326
  | Command | Options | Description |
311
327
  | :--- | :--- | :--- |
312
- | `context-brake init` | `--dry-run`, `--yes` (`-y`), `--json`, `--harness <id>`, `--exclude-harness <id>`, `--snapshot-command <text>`, `--snapshot-trigger <YELLOW\|RED>`, `--resume-command <text>`, `--no-snapshot-command`, `--debug`, `--no-debug`, `--statusline-bridge`, `--no-statusline-bridge`, `--auto-restart`, `--no-auto-restart`, `--max-restarts <1-10>`, `--interactive`, `--gitignore`, `--no-gitignore` | Detects harnesses, registers integrations, and creates or updates the configuration and the manifest. `--exclude-harness` turns a harness off persistently and `--harness` turns it back on. In a terminal with no other option, or with `--interactive`, it asks the [setup questions](#interactive-setup). |
328
+ | `context-brake init` | `--dry-run`, `--yes` (`-y`), `--json`, `--harness <id>`, `--exclude-harness <id>`, `--snapshot-command <skill>`, `--snapshot-trigger <YELLOW\|RED>`, `--snapshot-trigger-percentage <1-100>`, `--resume-command <skill>`, `--no-snapshot-command`, `--debug`, `--no-debug`, `--statusline-bridge`, `--no-statusline-bridge`, `--auto-restart`, `--no-auto-restart`, `--max-restarts <1-10>`, `--interactive`, `--gitignore`, `--no-gitignore` | Detects harnesses, registers integrations, and creates or updates the configuration and the manifest. `--exclude-harness` turns a harness off persistently and `--harness` turns it back on. In a terminal with no other option, or with `--interactive`, it asks the [setup questions](#interactive-setup). |
313
329
  | `context-brake doctor` | `--json`, `--harness <id>` | Inspects integrations, configuration integrity, versions, support levels, missing capabilities, snapshot settings, and active sessions with their context usage, and measures overhead p95. |
314
330
  | `context-brake remove` | `--dry-run`, `--yes` (`-y`), `--json` | Uninstalls the integrations and deletes the configuration, the manifest, and the runtime files. |
315
331
 
316
332
  ---
317
333
 
318
- ## 🧭 Roadmap
319
-
320
- | PRD | Scope | Status |
321
- | :--- | :--- | :--- |
322
- | [Installation, detection, and diagnostics](./tasks/prd-01-instalacao-deteccao-diagnostico/prd.md) | `init`, `doctor`, `remove`, harness support levels | Implemented |
323
- | [Installation follow-ups](./tasks/prd-01.1-pendencias-da-instalacao/prd.md) | Capabilities, overhead measurement, manifest, and installed assets | Implemented |
324
- | [Telemetry, zones, and brake](./tasks/prd-02-telemetria-zonas-e-freio/prd.md) | Turn counting, context measurement, zones | Implemented; the tool-call deny was removed by the single mode |
325
- | [Brake by measured usage](./tasks/prd-02.1-freio-por-uso-medido/prd.md) | Usage-only `CRITICAL`, optional turn limits, measured usage in Claude Code | Implemented |
326
- | [Claude Code context window](./tasks/prd-02.2-janela-de-contexto-do-claude-code/prd.md) | Status line bridge | Implemented |
327
- | [Plan, checkpoint, and boot](./tasks/prd-03-plano-checkpoint-e-boot/prd.md) | State files and boot summary | Superseded by the single mode |
328
- | [Automatic reset runner](./tasks/prd-04-runner-de-reinicio-automatico/prd.md) | Post-MVP runner | Superseded by the single mode |
329
- | [Release automation](./tasks/prd-05-automacao-de-release-e-publicacao/prd.md) | Automated release and npm publishing | Implemented |
330
- | [Delegated snapshot mode](./tasks/prd-06-modo-snapshot-delegado/prd.md) | Snapshot command without a task plan | Superseded by the single mode |
331
- | [Light mode](./tasks/prd-07-modo-leve/prd.md) | Telemetry only, and active-session usage in `doctor` | Superseded by the single mode |
332
- | [Debug mode](./tasks/prd-08-modo-debug/prd.md) | Usage line printed by the agent | Implemented |
333
- | [Brake with a trusted window](./tasks/prd-09-freio-com-janela-confiavel/prd.md) | Window origin and declared window | Implemented |
334
- | [Status line under PowerShell](./tasks/prd-10-statusline-powershell-e-modo-light/prd.md) | Shell-neutral bridge and debug line | Implemented |
335
- | [Automatic restart in Claude Code](./tasks/prd-11-reinicio-automatico-no-claude-code/prd.md) | Claude Code mod that clears and resumes the session | Implemented |
336
- | [Single mode](./tasks/prd-12-refatoracao-modo-leve-modo-unico/prd.md) | One mode with optional snapshot and resume commands, advisory brake | In progress |
337
- | [Fast test suite](./tasks/prd-13-refatoracao-modo-leve-testes-rapidos/prd.md) | Test budget | Planned |
338
- | [Restart and handoff across harnesses](./tasks/prd-14-refatoracao-modo-leve-reinicio-multi-harness/prd.md) | Automatic restart and markdown handoff beyond Claude Code | In progress |
339
-
340
- The PRDs are written in Portuguese, except the later ones.
341
-
342
- ---
343
-
344
334
  ## 🤝 Contributing
345
335
 
346
336
  This project follows Spec-Driven Development. Read [AGENTS.md](./AGENTS.md) and the PRD of the feature you are changing before opening a pull request.
@@ -4,6 +4,14 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
+ // src/core/services/skill-invocation.ts
8
+ function sentenceInvocation(skill) {
9
+ return `use the ${skill} skill`;
10
+ }
11
+
12
+ // src/infrastructure/harnesses/antigravity-cli/skill-invocation.ts
13
+ var ANTIGRAVITY_SKILL_INVOCATION = sentenceInvocation;
14
+
7
15
  // src/infrastructure/harnesses/common/runtime-support.ts
8
16
  import { realpath } from "node:fs/promises";
9
17
  import { dirname, resolve } from "node:path";
@@ -18160,6 +18168,34 @@ var HARNESS_IDS = [
18160
18168
  "antigravity-cli"
18161
18169
  ];
18162
18170
 
18171
+ // src/core/contracts/skill-name.ts
18172
+ var MAX_SKILL_NAME_LENGTH = 64;
18173
+ var NAME_SEGMENT = "[a-z0-9]+(?:-[a-z0-9]+)*";
18174
+ var NAMESPACE_SEPARATOR = ":";
18175
+ var INVOCATION_CHARACTERS = ["/", "$", "@"];
18176
+ var MAX_QUALIFIED_LENGTH = MAX_SKILL_NAME_LENGTH * 2 + NAMESPACE_SEPARATOR.length;
18177
+ function segmentFits(end) {
18178
+ return `(?=[^${NAMESPACE_SEPARATOR}]{1,${MAX_SKILL_NAME_LENGTH}}${end})`;
18179
+ }
18180
+ var PREFIX = `(?:${segmentFits(NAMESPACE_SEPARATOR)}${NAME_SEGMENT}${NAMESPACE_SEPARATOR})?`;
18181
+ var SKILL_NAME_PATTERN = new RegExp(`^${PREFIX}${segmentFits("$")}${NAME_SEGMENT}$`);
18182
+ var SHAPE_RULE = `lowercase letters, digits, and single hyphens, up to ${MAX_SKILL_NAME_LENGTH} characters, optionally prefixed by a plugin name and a colon`;
18183
+ function isSkillName(value) {
18184
+ return SKILL_NAME_PATTERN.test(value);
18185
+ }
18186
+ function skillNameProblem(value) {
18187
+ if (value === "") return "must not be empty";
18188
+ if (isSkillName(value)) return null;
18189
+ const bare = INVOCATION_CHARACTERS.includes(value.charAt(0)) ? value.slice(1) : null;
18190
+ if (bare !== null && isSkillName(bare)) return `"${value}" is not a skill name; use the bare name ${bare}`;
18191
+ return `"${value}" is not a skill name; use ${SHAPE_RULE}`;
18192
+ }
18193
+ var skillNameSchema = external_exports.string().check((ctx) => {
18194
+ const message = skillNameProblem(ctx.value);
18195
+ if (message !== null) ctx.issues.push({ code: "custom", input: ctx.value, message });
18196
+ });
18197
+ external_exports.globalRegistry.add(skillNameSchema, { pattern: SKILL_NAME_PATTERN.source, maxLength: MAX_QUALIFIED_LENGTH });
18198
+
18163
18199
  // src/core/contracts/zones.ts
18164
18200
  var ZONES = ["GREEN", "YELLOW", "RED", "CRITICAL"];
18165
18201
  var USAGE_SOURCES = ["measured", "estimated"];
@@ -18183,15 +18219,8 @@ function uniqueCheck(message) {
18183
18219
  if (!isUnique(ctx.value)) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message });
18184
18220
  };
18185
18221
  }
18186
- var MAX_AGENT_COMMAND_LENGTH = 200;
18187
- var TRIMMED_RULE = "must not have leading or trailing whitespace";
18188
18222
  var RESUME_REQUIRES_COMMAND_RULE = "requires snapshot.command";
18189
- var SINGLE_LINE_RULE = "must be a single line";
18190
- var agentCommand = external_exports.string().check(external_exports.minLength(1), external_exports.maxLength(MAX_AGENT_COMMAND_LENGTH), (ctx) => {
18191
- if (ctx.value.trim() !== ctx.value) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message: TRIMMED_RULE });
18192
- if (/[\r\n]/.test(ctx.value)) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message: SINGLE_LINE_RULE });
18193
- });
18194
- var snapshotSchema = external_exports.strictObject({ triggerZone: external_exports._default(external_exports.enum(SNAPSHOT_TRIGGER_ZONES), "RED"), command: external_exports.optional(agentCommand), resumeCommand: external_exports.optional(agentCommand) }).check((ctx) => {
18223
+ var snapshotSchema = external_exports.strictObject({ triggerZone: external_exports._default(external_exports.enum(SNAPSHOT_TRIGGER_ZONES), "RED"), triggerPercentage: external_exports.optional(external_exports.int().check(external_exports.minimum(1), external_exports.maximum(100))), command: external_exports.optional(skillNameSchema), resumeCommand: external_exports.optional(skillNameSchema) }).check((ctx) => {
18195
18224
  if (ctx.value.resumeCommand !== void 0 && ctx.value.command === void 0) addIssue(ctx, { code: "custom", path: ["resumeCommand"], input: ctx.value.resumeCommand, message: RESUME_REQUIRES_COMMAND_RULE });
18196
18225
  });
18197
18226
  var DEFAULT_SNAPSHOT = { triggerZone: "RED" };
@@ -18272,21 +18301,25 @@ var GENERIC_ACTIONS = {
18272
18301
  RED: "finish or pause the current unit and tell the user what remains",
18273
18302
  CRITICAL: "stop starting new work; tell the user what remains"
18274
18303
  };
18275
- function zoneAction(zone, snapshot, mode = "off") {
18276
- if (zone === "GREEN" || !isAtOrAbove(zone, snapshot.triggerZone)) return GENERIC_ACTIONS[zone];
18277
- if (snapshot.command !== void 0) return snapshotAction(zone, snapshot.command);
18278
- if (mode !== "handoff") return GENERIC_ACTIONS[zone];
18304
+ function isResetDue(reading, snapshot) {
18305
+ if (snapshot.triggerPercentage !== void 0) return reading.usagePercentage >= snapshot.triggerPercentage;
18306
+ return reading.zone !== "GREEN" && isAtOrAbove(reading.zone, snapshot.triggerZone);
18307
+ }
18308
+ function zoneAction(zone, snapshot, options = {}) {
18309
+ if (!isResetDue({ zone, usagePercentage: options.usagePercentage ?? 0 }, snapshot)) return GENERIC_ACTIONS[zone];
18310
+ if (snapshot.command !== void 0) return snapshotAction(zone, (options.invoke ?? sentenceInvocation)(snapshot.command));
18311
+ if ((options.mode ?? "off") !== "handoff") return GENERIC_ACTIONS[zone];
18279
18312
  return `save handoff to ${HANDOFF_PATH}, end reply with ${SESSION_RESET_SIGNAL}`;
18280
18313
  }
18281
- function snapshotAction(zone, command) {
18314
+ function snapshotAction(zone, invocation) {
18282
18315
  const now = zone === "CRITICAL" ? " now" : "";
18283
- return `run "${command}"${now}, then end reply with ${SESSION_RESET_SIGNAL}`;
18316
+ return `run "${invocation}"${now}, then end reply with ${SESSION_RESET_SIGNAL}`;
18284
18317
  }
18285
18318
  function handoffResumeText(archivedPath) {
18286
18319
  return `${RESUME_PREFIX} Read "${archivedPath}" and continue the previous work from it.`;
18287
18320
  }
18288
- function resumeText(snapshot) {
18289
- return snapshot.resumeCommand === void 0 ? null : `${RESUME_PREFIX} Run "${snapshot.resumeCommand}" before continuing.`;
18321
+ function resumeText(snapshot, invoke = sentenceInvocation) {
18322
+ return snapshot.resumeCommand === void 0 ? null : `${RESUME_PREFIX} Run "${invoke(snapshot.resumeCommand)}" before continuing.`;
18290
18323
  }
18291
18324
  function isAtOrAbove(zone, trigger) {
18292
18325
  return ZONES.indexOf(zone) >= ZONES.indexOf(trigger);
@@ -18331,7 +18364,7 @@ async function resolveFailure(input2) {
18331
18364
  return { kind: "neutral" };
18332
18365
  }
18333
18366
  function deadlineBootDecision(input2) {
18334
- const text = resumeText((input2.config ?? DEFAULT_CONFIG).snapshot);
18367
+ const text = resumeText((input2.config ?? DEFAULT_CONFIG).snapshot, input2.descriptor?.skillInvocation);
18335
18368
  return text === null ? { kind: "neutral" } : { kind: "context", block: text };
18336
18369
  }
18337
18370
  async function recordRuntimeFailure(errors, record2) {
@@ -18442,7 +18475,7 @@ function isDebugModeInEffect(config2) {
18442
18475
 
18443
18476
  // src/core/services/injection-policy.ts
18444
18477
  function decideInjection(input2) {
18445
- if (input2.debug || input2.telemetry.injectionMode === "always") return true;
18478
+ if (input2.debug || input2.resetDue === true || input2.telemetry.injectionMode === "always") return true;
18446
18479
  return input2.zone !== "GREEN" || input2.usagePercentage >= input2.telemetry.activationThresholdPercentage;
18447
18480
  }
18448
18481
 
@@ -18593,7 +18626,7 @@ async function handleSessionReset(options, event, hooks = {}) {
18593
18626
  if (!options.descriptor.capabilities.some((entry) => entry.id === "session_boot" && entry.state === "supported")) return NEUTRAL;
18594
18627
  if (event.reason === "compact" && !COMPACTION_BOOT_HARNESSES.includes(options.descriptor.harness)) return NEUTRAL;
18595
18628
  hooks.onPhase?.("guidance");
18596
- const text = resumeText(options.config.snapshot) ?? await claimHandoff(options, event.reason, hooks.deadline);
18629
+ const text = resumeText(options.config.snapshot, options.descriptor.skillInvocation) ?? await claimHandoff(options, event.reason, hooks.deadline);
18597
18630
  return text === null ? NEUTRAL : { kind: "context", block: text };
18598
18631
  }
18599
18632
  async function claimHandoff(options, reason, deadline) {
@@ -18635,8 +18668,9 @@ async function handlePreInvocation(options, event, input2) {
18635
18668
  return telemetryDecision(options, summary.turns, readZone(options, { summary, turns: summary.turns, observedCharacters: 0, measured: input2.measured }));
18636
18669
  }
18637
18670
  async function telemetryDecision(options, turn, view) {
18638
- if (!decideInjection({ telemetry: options.config.telemetry, zone: view.zone, usagePercentage: view.percentage, debug: isDebugModeInEffect(options.config) })) return NEUTRAL2;
18639
- const action = zoneAction(view.zone, options.config.snapshot, restartMode(options.config));
18671
+ const resetDue = isResetDue({ zone: view.zone, usagePercentage: view.percentage }, options.config.snapshot);
18672
+ if (!decideInjection({ telemetry: options.config.telemetry, zone: view.zone, usagePercentage: view.percentage, debug: isDebugModeInEffect(options.config), resetDue })) return NEUTRAL2;
18673
+ const action = zoneAction(view.zone, options.config.snapshot, { mode: restartMode(options.config), invoke: options.descriptor.skillInvocation, usagePercentage: view.percentage });
18640
18674
  return { kind: "context", block: renderTelemetryBlock({ turn, turnCeiling: redStartTurn(options.config.telemetry.zones), usagePercentage: view.percentage, usage: view.reading, zone: view.zone, action, debug: isDebugModeInEffect(options.config) }) };
18641
18675
  }
18642
18676
  async function handleResponseEnd(options, event) {
@@ -18670,6 +18704,17 @@ import { createHash } from "node:crypto";
18670
18704
  import { mkdir, writeFile } from "node:fs/promises";
18671
18705
  import { join as join2, resolve as resolve3 } from "node:path";
18672
18706
 
18707
+ // src/core/contracts/context-reading.ts
18708
+ var RUNTIME_IGNORE_CONTENT = "*\n";
18709
+ var PERCENTAGE_MAXIMUM = 100;
18710
+ var contextReadingSchema = external_exports.strictObject({
18711
+ v: external_exports.literal(1),
18712
+ at: external_exports.string().check(external_exports.minLength(1)),
18713
+ windowTokens: external_exports.nullable(external_exports.int().check(external_exports.positive())),
18714
+ inputTokens: external_exports.nullable(external_exports.int().check(external_exports.nonnegative())),
18715
+ usedPercentage: external_exports.nullable(external_exports.number().check(external_exports.gte(0), external_exports.lte(PERCENTAGE_MAXIMUM)))
18716
+ });
18717
+
18673
18718
  // src/infrastructure/storage/runtime-state-files.ts
18674
18719
  import { readdir } from "node:fs/promises";
18675
18720
  import { join, relative, resolve as resolve2 } from "node:path";
@@ -18689,7 +18734,7 @@ async function listRuntimeStateFiles(root, readdirFn = readdir) {
18689
18734
  }
18690
18735
 
18691
18736
  // src/infrastructure/runtime/runtime-paths.ts
18692
- var RUNTIME_GITIGNORE_CONTENT = "*\n";
18737
+ var RUNTIME_GITIGNORE_CONTENT = RUNTIME_IGNORE_CONTENT;
18693
18738
  var SESSIONS_DIR_NAME = "sessions";
18694
18739
  var LEDGER_FILE_EXTENSION = ".jsonl";
18695
18740
  var SESSIONS_RELATIVE_PREFIX = `${RUNTIME_STATE_RELATIVE_DIR}/${SESSIONS_DIR_NAME}/`;
@@ -19124,7 +19169,7 @@ var antigravityPayloadSchema = external_exports.looseObject({
19124
19169
  // src/infrastructure/harnesses/antigravity-cli/runtime.ts
19125
19170
  var HARNESS = "antigravity-cli";
19126
19171
  var ESTIMATION = { baselineTokens: 15e3, tokensPerTurn: 150 };
19127
- var antigravityDescriptor = { harness: HARNESS, capabilities: ANTIGRAVITY_CAPABILITIES, estimation: ESTIMATION, newSessionCommand: null };
19172
+ var antigravityDescriptor = { harness: HARNESS, capabilities: ANTIGRAVITY_CAPABILITIES, estimation: ESTIMATION, newSessionCommand: null, skillInvocation: ANTIGRAVITY_SKILL_INVOCATION };
19128
19173
  function sessionOf(payload) {
19129
19174
  return { harness: HARNESS, sessionId: requireIdentifier(payload.conversationId), agentId: null };
19130
19175
  }