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
@@ -1,5 +1,6 @@
1
1
  import type { ApplyReport, ChangeApplier, ChangePlan } from '../../core/contracts/changes.js';
2
2
  export declare const FILE_CHANGED_CODE: "FILE_CHANGED_SINCE_PREVIEW";
3
+ export declare const FILE_UNREADABLE_CODE: "FILE_UNREADABLE";
3
4
  export type ChangeApplierOptions = {
4
5
  pruneRuntime?: boolean | undefined;
5
6
  };
@@ -3,6 +3,7 @@ import { deleteFileIfExists, writeFileAtomically } from './atomic-writer.js';
3
3
  import { pruneEmptyContextBrakeDirectories } from './directory-pruner.js';
4
4
  import { computeSha256 } from './node-file-system.js';
5
5
  export const FILE_CHANGED_CODE = 'FILE_CHANGED_SINCE_PREVIEW';
6
+ export const FILE_UNREADABLE_CODE = 'FILE_UNREADABLE';
6
7
  async function checkPrecondition(change) {
7
8
  try {
8
9
  const current = await readFile(change.realPath, 'utf8');
@@ -22,7 +23,7 @@ async function checkPrecondition(change) {
22
23
  }
23
24
  return null;
24
25
  }
25
- throw err;
26
+ return `${FILE_UNREADABLE_CODE}: ${err.message}`;
26
27
  }
27
28
  }
28
29
  async function applySingleChange(change) {
@@ -1,6 +1,7 @@
1
1
  import { findNodeAtLocation, getNodeValue } from 'jsonc-parser';
2
2
  import { parseAndValidateJson } from './json-validator.js';
3
- import { detectEol, detectIndent, formatJsonValue, insertArrayItem, insertObjectEntry, removeNodeSpan } from './json-span-utils.js';
3
+ import { detectEol, detectIndent, formatJsonValue, insertArrayItem, insertObjectEntry } from './json-span-utils.js';
4
+ import { removeNodeSpan } from './json-node-removal.js';
4
5
  export { InvalidJsonDocumentError, validateJsonDocument, parseAndValidateJson } from './json-validator.js';
5
6
  export function setJsonProperty(text, path, value) {
6
7
  const root = parseAndValidateJson(text);
@@ -0,0 +1,2 @@
1
+ import type { Node } from 'jsonc-parser';
2
+ export declare function removeNodeSpan(text: string, node: Node): string;
@@ -0,0 +1,70 @@
1
+ import { findLineEndAfter, findSeparatorComma } from './json-span-utils.js';
2
+ function siblingContext(node) {
3
+ const list = node.parent?.children;
4
+ return list ? { list, index: list.indexOf(node) } : undefined;
5
+ }
6
+ function commaAfterPrevious(text, node) {
7
+ const context = siblingContext(node);
8
+ if (!context || context.index <= 0)
9
+ return -1;
10
+ const previous = context.list[context.index - 1];
11
+ return findSeparatorComma(text, previous.offset + previous.length, node.offset);
12
+ }
13
+ function commaBeforeNext(text, node) {
14
+ const context = siblingContext(node);
15
+ const next = context?.list[context.index + 1];
16
+ return next ? findSeparatorComma(text, node.offset + node.length, next.offset) : -1;
17
+ }
18
+ function isLastChild(node) {
19
+ const context = siblingContext(node);
20
+ return context === undefined || context.index === context.list.length - 1;
21
+ }
22
+ function isOnlyNodeOnLine(text, span) {
23
+ const leading = text.slice(span.lineStart, span.start);
24
+ return /^\s*$/.test(leading) && /^[ \t]*,?[ \t]*\r?\n?$/.test(text.slice(span.end, span.lineEnd));
25
+ }
26
+ function removeLastNode(text, node, span) {
27
+ const ownLine = isOnlyNodeOnLine(text, span);
28
+ const after = text.slice(ownLine ? span.lineEnd : span.end);
29
+ const comma = !ownLine || isLastChild(node) ? commaAfterPrevious(text, node) : -1;
30
+ const cut = ownLine ? span.lineStart : span.start;
31
+ if (comma === -1)
32
+ return `${text.slice(0, cut)}${after}`;
33
+ return `${text.slice(0, comma)}${text.slice(comma + 1, cut)}${after}`;
34
+ }
35
+ function removeBeforeComma(text, node, span) {
36
+ const before = text.slice(0, span.start);
37
+ const leadingComma = before.match(/,\s*$/);
38
+ if (leadingComma?.index !== undefined)
39
+ return `${before.slice(0, leadingComma.index)}${text.slice(span.end)}`;
40
+ const comma = commaBeforeNext(text, node);
41
+ if (comma === -1)
42
+ return `${before}${text.slice(span.end)}`;
43
+ return `${before}${text.slice(span.end, comma)}${text.slice(comma + 1)}`;
44
+ }
45
+ function emptyContainer(text, node) {
46
+ const container = node.parent;
47
+ if (container?.children?.length !== 1)
48
+ return undefined;
49
+ const open = container.offset + 1;
50
+ const close = container.offset + container.length - 1;
51
+ const rest = `${text.slice(open, node.offset)}${text.slice(node.offset + node.length, close)}`;
52
+ return /^\s*$/.test(rest) ? `${text.slice(0, open)}${text.slice(close)}` : undefined;
53
+ }
54
+ export function removeNodeSpan(text, node) {
55
+ const emptied = emptyContainer(text, node);
56
+ if (emptied !== undefined)
57
+ return emptied;
58
+ const start = node.offset;
59
+ const end = start + node.length;
60
+ const lineStart = text.lastIndexOf('\n', start) + 1;
61
+ const span = { start, end, lineStart, lineEnd: findLineEndAfter(text, end) };
62
+ if (isOnlyNodeOnLine(text, span))
63
+ return removeLastNode(text, node, span);
64
+ const trailingComma = text.slice(end).match(/^\s*,/);
65
+ if (trailingComma)
66
+ return `${text.slice(0, start)}${text.slice(end + trailingComma[0].length)}`;
67
+ if (isLastChild(node))
68
+ return removeLastNode(text, node, span);
69
+ return removeBeforeComma(text, node, span);
70
+ }
@@ -19,6 +19,6 @@ export declare function detectEol(text: string): string;
19
19
  export declare function detectIndent(text: string): string;
20
20
  export declare function findLineEndAfter(text: string, offset: number): number;
21
21
  export declare function formatJsonValue(value: unknown, opts: FormatOptions): string;
22
+ export declare function findSeparatorComma(text: string, from: number, to: number): number;
22
23
  export declare function insertObjectEntry(text: string, parentNode: Node, opts: InsertEntryOptions): string;
23
24
  export declare function insertArrayItem(text: string, arrayNode: Node, opts: InsertItemOptions): string;
24
- export declare function removeNodeSpan(text: string, node: Node): string;
@@ -16,7 +16,7 @@ export function formatJsonValue(value, opts) {
16
16
  const prefix = opts.indent.repeat(opts.depth);
17
17
  return raw.split('\n').map((line, idx) => (idx === 0 ? line : `${prefix}${line}`)).join(opts.eol);
18
18
  }
19
- function findSeparatorComma(text, from, to) {
19
+ export function findSeparatorComma(text, from, to) {
20
20
  let index = from;
21
21
  while (index < to) {
22
22
  if (text.startsWith('//', index))
@@ -55,50 +55,3 @@ export function insertObjectEntry(text, parentNode, opts) {
55
55
  export function insertArrayItem(text, arrayNode, opts) {
56
56
  return insertIntoContainer(text, arrayNode, { item: opts.formattedVal, indent: opts.indent, depth: opts.depth });
57
57
  }
58
- function siblingContext(node) {
59
- const list = node.parent?.children;
60
- return list ? { list, index: list.indexOf(node) } : undefined;
61
- }
62
- function commaAfterPrevious(text, node) {
63
- const context = siblingContext(node);
64
- if (!context || context.index <= 0)
65
- return -1;
66
- const previous = context.list[context.index - 1];
67
- return findSeparatorComma(text, previous.offset + previous.length, node.offset);
68
- }
69
- function isLastChild(node) {
70
- const context = siblingContext(node);
71
- return context === undefined || context.index === context.list.length - 1;
72
- }
73
- function isOnlyNodeOnLine(text, span) {
74
- const leading = text.slice(span.lineStart, span.start);
75
- return /^\s*$/.test(leading) && /^[ \t]*,?[ \t]*\r?\n?$/.test(text.slice(span.end, span.lineEnd));
76
- }
77
- function removeLastNode(text, node, span) {
78
- const ownLine = isOnlyNodeOnLine(text, span);
79
- const after = text.slice(ownLine ? span.lineEnd : span.end);
80
- const comma = !ownLine || /^\s*[\]}]/.test(after) ? commaAfterPrevious(text, node) : -1;
81
- const cut = ownLine ? span.lineStart : span.start;
82
- if (comma === -1)
83
- return `${text.slice(0, cut)}${after}`;
84
- return `${text.slice(0, comma)}${text.slice(comma + 1, cut)}${after}`;
85
- }
86
- export function removeNodeSpan(text, node) {
87
- const start = node.offset;
88
- const end = start + node.length;
89
- const lineStart = text.lastIndexOf('\n', start) + 1;
90
- const span = { start, end, lineStart, lineEnd: findLineEndAfter(text, end) };
91
- if (isOnlyNodeOnLine(text, span))
92
- return removeLastNode(text, node, span);
93
- const after = text.slice(end);
94
- const trailingComma = after.match(/^\s*,/);
95
- if (trailingComma)
96
- return `${text.slice(0, start)}${after.slice(trailingComma[0].length)}`;
97
- if (isLastChild(node))
98
- return removeLastNode(text, node, span);
99
- const before = text.slice(0, start);
100
- const leadingComma = before.match(/,\s*$/);
101
- if (leadingComma?.index !== undefined)
102
- return `${before.slice(0, leadingComma.index)}${after}`;
103
- return `${before}${after}`;
104
- }
@@ -44,6 +44,8 @@ With `snapshot.command` set, from `snapshot.triggerZone` (`RED` by default, or `
44
44
  | `YELLOW` or `RED` at or above the trigger | `run "<command>", then end reply with [REQUEST_SESSION_RESET]` |
45
45
  | `CRITICAL` | `run "<command>" now, then end reply with [REQUEST_SESSION_RESET]` |
46
46
 
47
+ When `snapshot.triggerPercentage` is set, it replaces the zone rule: the same actions start once the usage reaches that percentage in any zone, `GREEN` included, and the block is injected from there even below the activation threshold.
48
+
47
49
  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. The longest block, with any action variant and a typical command, stays within 60 tokens.
48
50
 
49
51
  ### Versioning Rule
@@ -88,7 +90,7 @@ With turn limits of `greenMaxTurn: 59` and `yellowMaxTurn: 99`, the turn shows w
88
90
  ```
89
91
 
90
92
  ### 🔴 `RED` Zone
91
- The session is in danger of context exhaustion. With `snapshot.command` set to `/sdd-snapshot`, the agent saves its state and requests a session reset; without it, the agent wraps up and reports what remains:
93
+ The session is in danger of context exhaustion. With `snapshot.command` set to `sdd-snapshot` (written `/sdd-snapshot` for Claude Code), the agent saves its state and requests a session reset; without it, the agent wraps up and reports what remains:
92
94
 
93
95
  ```text
94
96
  [ContextBrake v3] turn=11 usage=68% tokens=87040/128000 source=estimated window=config zone=RED action=run "/sdd-snapshot", then end reply with [REQUEST_SESSION_RESET]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-brake",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Context telemetry and an advisory brake for coding-agent harnesses",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -136,15 +136,20 @@
136
136
  "RED"
137
137
  ]
138
138
  },
139
+ "triggerPercentage": {
140
+ "type": "integer",
141
+ "minimum": 1,
142
+ "maximum": 100
143
+ },
139
144
  "command": {
140
145
  "type": "string",
141
- "minLength": 1,
142
- "maxLength": 200
146
+ "pattern": "^(?:(?=[^:]{1,64}:)[a-z0-9]+(?:-[a-z0-9]+)*:)?(?=[^:]{1,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$",
147
+ "maxLength": 129
143
148
  },
144
149
  "resumeCommand": {
145
150
  "type": "string",
146
- "minLength": 1,
147
- "maxLength": 200
151
+ "pattern": "^(?:(?=[^:]{1,64}:)[a-z0-9]+(?:-[a-z0-9]+)*:)?(?=[^:]{1,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$",
152
+ "maxLength": 129
148
153
  }
149
154
  },
150
155
  "additionalProperties": false
@@ -427,6 +427,11 @@
427
427
  "RED"
428
428
  ]
429
429
  },
430
+ "triggerPercentage": {
431
+ "type": "integer",
432
+ "minimum": 1,
433
+ "maximum": 100
434
+ },
430
435
  "command": {
431
436
  "type": [
432
437
  "string",
@@ -438,6 +443,42 @@
438
443
  "string",
439
444
  "null"
440
445
  ]
446
+ },
447
+ "invocations": {
448
+ "type": "array",
449
+ "items": {
450
+ "type": "object",
451
+ "properties": {
452
+ "harness": {
453
+ "type": "string",
454
+ "enum": [
455
+ "claude-code",
456
+ "codex-cli",
457
+ "cursor",
458
+ "github-copilot-cli",
459
+ "opencode",
460
+ "pi",
461
+ "oh-my-pi",
462
+ "antigravity-cli"
463
+ ]
464
+ },
465
+ "command": {
466
+ "type": "string"
467
+ },
468
+ "resumeCommand": {
469
+ "type": [
470
+ "string",
471
+ "null"
472
+ ]
473
+ }
474
+ },
475
+ "required": [
476
+ "harness",
477
+ "command",
478
+ "resumeCommand"
479
+ ],
480
+ "additionalProperties": false
481
+ }
441
482
  }
442
483
  },
443
484
  "required": [
@@ -458,9 +499,18 @@
458
499
  "inactive"
459
500
  ]
460
501
  },
502
+ "mod": {
503
+ "type": "string",
504
+ "enum": [
505
+ "absent",
506
+ "installed",
507
+ "reporting"
508
+ ]
509
+ },
461
510
  "source": {
462
511
  "type": "string",
463
512
  "enum": [
513
+ "mod",
464
514
  "statusline",
465
515
  "contextWindowCeiling"
466
516
  ]
@@ -480,6 +530,7 @@
480
530
  },
481
531
  "required": [
482
532
  "bridge",
533
+ "mod",
483
534
  "source",
484
535
  "lastWindowTokens"
485
536
  ],