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.
- package/README.md +31 -41
- package/dist/assets/runtime/antigravity-cli-hook.mjs +68 -23
- package/dist/assets/runtime/claude-code-hook.mjs +133 -35
- package/dist/assets/runtime/claude-code-mod.mjs +165 -59
- package/dist/assets/runtime/claude-code-statusline.mjs +41 -9
- package/dist/assets/runtime/codex-cli-hook.mjs +71 -23
- package/dist/assets/runtime/cursor-hook.mjs +71 -23
- package/dist/assets/runtime/github-copilot-cli-hook.mjs +71 -23
- package/dist/assets/runtime/omp-extension.js +70 -23
- package/dist/assets/runtime/omp-restart.js +41 -9
- package/dist/assets/runtime/opencode-plugin.js +70 -23
- package/dist/assets/runtime/pi-extension.js +73 -23
- package/dist/assets/runtime/pi-restart.js +41 -9
- package/dist/src/cli/assistant/assistant-context.js +7 -0
- package/dist/src/cli/assistant/assistant-questions.js +5 -4
- package/dist/src/cli/assistant/assistant-session.js +3 -1
- package/dist/src/cli/assistant/invocation-facts.d.ts +5 -0
- package/dist/src/cli/assistant/invocation-facts.js +6 -0
- package/dist/src/cli/assistant/questions-misc.d.ts +1 -0
- package/dist/src/cli/assistant/questions-misc.js +3 -2
- package/dist/src/cli/assistant/questions-skill.d.ts +21 -0
- package/dist/src/cli/assistant/questions-skill.js +45 -0
- package/dist/src/cli/assistant/questions-snapshot.d.ts +3 -1
- package/dist/src/cli/assistant/questions-snapshot.js +21 -26
- package/dist/src/cli/assistant/questions-trigger.d.ts +6 -0
- package/dist/src/cli/assistant/questions-trigger.js +56 -0
- package/dist/src/cli/assistant/skill-options.d.ts +20 -0
- package/dist/src/cli/assistant/skill-options.js +40 -0
- package/dist/src/cli/assistant/snapshot-specs.d.ts +7 -1
- package/dist/src/cli/assistant/snapshot-specs.js +17 -7
- package/dist/src/cli/assistant/summary-rows.d.ts +5 -0
- package/dist/src/cli/assistant/summary-rows.js +47 -0
- package/dist/src/cli/assistant/summary.d.ts +2 -1
- package/dist/src/cli/assistant/summary.js +21 -30
- package/dist/src/cli/assistant/types.d.ts +15 -0
- package/dist/src/cli/commands/doctor.js +2 -1
- package/dist/src/cli/commands/remove.js +1 -1
- package/dist/src/cli/init-arguments.js +5 -4
- package/dist/src/cli/init-flow.js +1 -1
- package/dist/src/cli/init-option-rules.d.ts +5 -0
- package/dist/src/cli/init-option-rules.js +16 -0
- package/dist/src/cli/output/card.d.ts +8 -0
- package/dist/src/cli/output/card.js +30 -0
- package/dist/src/cli/output/doctor-mode-text.js +8 -2
- package/dist/src/cli/output/install-rows.d.ts +6 -0
- package/dist/src/cli/output/install-rows.js +31 -0
- package/dist/src/cli/output/install-text.d.ts +4 -0
- package/dist/src/cli/output/install-text.js +26 -0
- package/dist/src/cli/output/style.d.ts +22 -0
- package/dist/src/cli/output/style.js +27 -0
- package/dist/src/cli/output/text.d.ts +1 -2
- package/dist/src/cli/output/text.js +1 -28
- package/dist/src/core/contracts/adapter.d.ts +2 -1
- package/dist/src/core/contracts/configuration.d.ts +2 -1
- package/dist/src/core/contracts/configuration.js +2 -10
- package/dist/src/core/contracts/context-reading.d.ts +16 -0
- package/dist/src/core/contracts/context-reading.js +20 -0
- package/dist/src/core/contracts/context-window-report.d.ts +8 -1
- package/dist/src/core/contracts/context-window-report.js +3 -1
- package/dist/src/core/contracts/diagnostics.d.ts +21 -0
- package/dist/src/core/contracts/diagnostics.js +2 -1
- package/dist/src/core/contracts/manifest.d.ts +16 -0
- package/dist/src/core/contracts/manifest.js +6 -0
- package/dist/src/core/contracts/runtime.d.ts +2 -0
- package/dist/src/core/contracts/skill-catalog.d.ts +11 -0
- package/dist/src/core/contracts/skill-catalog.js +1 -0
- package/dist/src/core/contracts/skill-invocation.d.ts +3 -0
- package/dist/src/core/contracts/skill-invocation.js +1 -0
- package/dist/src/core/contracts/skill-name.d.ts +5 -0
- package/dist/src/core/contracts/skill-name.js +31 -0
- package/dist/src/core/services/brake-engine.js +4 -3
- package/dist/src/core/services/doctor-report-extras.d.ts +2 -0
- package/dist/src/core/services/doctor-report-extras.js +22 -5
- package/dist/src/core/services/doctor-service.d.ts +2 -0
- package/dist/src/core/services/doctor-service.js +1 -1
- package/dist/src/core/services/failure-policy.js +1 -1
- package/dist/src/core/services/injection-policy.d.ts +1 -0
- package/dist/src/core/services/injection-policy.js +1 -1
- package/dist/src/core/services/installation-adapters.d.ts +2 -1
- package/dist/src/core/services/installation-adapters.js +3 -1
- package/dist/src/core/services/installation-builder.js +3 -2
- package/dist/src/core/services/installation-service.js +1 -1
- package/dist/src/core/services/manifest-change.d.ts +2 -1
- package/dist/src/core/services/manifest-change.js +2 -1
- package/dist/src/core/services/session-reset-handler.js +1 -1
- package/dist/src/core/services/skill-candidates.d.ts +16 -0
- package/dist/src/core/services/skill-candidates.js +14 -0
- package/dist/src/core/services/skill-invocation.d.ts +4 -0
- package/dist/src/core/services/skill-invocation.js +12 -0
- package/dist/src/core/services/skill-ranking.d.ts +7 -0
- package/dist/src/core/services/skill-ranking.js +25 -0
- package/dist/src/core/services/snapshot-merge.d.ts +1 -0
- package/dist/src/core/services/snapshot-merge.js +12 -5
- package/dist/src/core/services/trigger-text.d.ts +5 -0
- package/dist/src/core/services/trigger-text.js +4 -0
- package/dist/src/core/services/zone-guidance.d.ts +13 -2
- package/dist/src/core/services/zone-guidance.js +14 -8
- package/dist/src/infrastructure/harnesses/antigravity-cli/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/antigravity-cli/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/antigravity-cli/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/antigravity-cli/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/antigravity-cli/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/adapter.js +6 -4
- package/dist/src/infrastructure/harnesses/claude-code/auto-restart-diagnostics.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/claude-code/auto-restart-diagnostics.js +2 -2
- package/dist/src/infrastructure/harnesses/claude-code/auto-restart-planner.d.ts +5 -1
- package/dist/src/infrastructure/harnesses/claude-code/auto-restart-planner.js +6 -6
- package/dist/src/infrastructure/harnesses/claude-code/capabilities.js +1 -1
- package/dist/src/infrastructure/harnesses/claude-code/context-readings-scan.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/context-readings-scan.js +21 -0
- package/dist/src/infrastructure/harnesses/claude-code/context-source.d.ts +10 -0
- package/dist/src/infrastructure/harnesses/claude-code/context-source.js +16 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod/context-reading.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod/context-reading.js +67 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod/host.d.ts +9 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod/mod-info.d.ts +1 -1
- package/dist/src/infrastructure/harnesses/claude-code/mod/mod-info.js +1 -1
- package/dist/src/infrastructure/harnesses/claude-code/mod/mod-log.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod/mod-log.js +3 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod/register.js +6 -1
- package/dist/src/infrastructure/harnesses/claude-code/mod-reading.d.ts +6 -0
- package/dist/src/infrastructure/harnesses/claude-code/mod-reading.js +37 -0
- package/dist/src/infrastructure/harnesses/claude-code/planner.d.ts +2 -1
- package/dist/src/infrastructure/harnesses/claude-code/planner.js +4 -4
- package/dist/src/infrastructure/harnesses/claude-code/project-root.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/project-root.js +5 -0
- package/dist/src/infrastructure/harnesses/claude-code/runtime.js +12 -7
- package/dist/src/infrastructure/harnesses/claude-code/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/claude-code/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/claude-code/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/statusline-context-window.js +15 -2
- package/dist/src/infrastructure/harnesses/claude-code/statusline-diagnostics.js +3 -3
- package/dist/src/infrastructure/harnesses/claude-code/statusline-migration.d.ts +3 -0
- package/dist/src/infrastructure/harnesses/claude-code/statusline-migration.js +23 -0
- package/dist/src/infrastructure/harnesses/claude-code/statusline-planner.d.ts +2 -1
- package/dist/src/infrastructure/harnesses/claude-code/statusline-planner.js +7 -4
- package/dist/src/infrastructure/harnesses/claude-code/user-settings.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/claude-code/user-settings.js +11 -0
- package/dist/src/infrastructure/harnesses/codex-cli/adapter.js +5 -4
- package/dist/src/infrastructure/harnesses/codex-cli/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/codex-cli/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/codex-cli/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/codex-cli/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/codex-cli/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/common/config-origin.d.ts +10 -0
- package/dist/src/infrastructure/harnesses/common/config-origin.js +52 -0
- package/dist/src/infrastructure/harnesses/cursor/adapter.js +5 -4
- package/dist/src/infrastructure/harnesses/cursor/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/cursor/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/cursor/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/cursor/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/cursor/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/github-copilot-cli/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/github-copilot-cli/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/oh-my-pi/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/oh-my-pi/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/oh-my-pi/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/oh-my-pi/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/oh-my-pi/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/opencode/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/opencode/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/opencode/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/opencode/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/opencode/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/pi/runtime.js +2 -1
- package/dist/src/infrastructure/harnesses/pi/skill-folders.d.ts +1 -0
- package/dist/src/infrastructure/harnesses/pi/skill-folders.js +1 -0
- package/dist/src/infrastructure/harnesses/pi/skill-invocation.d.ts +2 -0
- package/dist/src/infrastructure/harnesses/pi/skill-invocation.js +2 -0
- package/dist/src/infrastructure/harnesses/skill-folders.d.ts +3 -0
- package/dist/src/infrastructure/harnesses/skill-folders.js +21 -0
- package/dist/src/infrastructure/harnesses/skill-invocations.d.ts +4 -0
- package/dist/src/infrastructure/harnesses/skill-invocations.js +21 -0
- package/dist/src/infrastructure/runtime/runtime-paths.js +2 -1
- package/dist/src/infrastructure/skills/frontmatter.d.ts +5 -0
- package/dist/src/infrastructure/skills/frontmatter.js +25 -0
- package/dist/src/infrastructure/skills/skill-catalog-reader.d.ts +4 -0
- package/dist/src/infrastructure/skills/skill-catalog-reader.js +78 -0
- package/dist/src/infrastructure/skills/skill-catalog.d.ts +2 -0
- package/dist/src/infrastructure/skills/skill-catalog.js +5 -0
- package/dist/src/infrastructure/storage/change-applier.d.ts +1 -0
- package/dist/src/infrastructure/storage/change-applier.js +2 -1
- package/dist/src/infrastructure/storage/json-document-editor.js +2 -1
- package/dist/src/infrastructure/storage/json-node-removal.d.ts +2 -0
- package/dist/src/infrastructure/storage/json-node-removal.js +70 -0
- package/dist/src/infrastructure/storage/json-span-utils.d.ts +1 -1
- package/dist/src/infrastructure/storage/json-span-utils.js +1 -48
- package/docs/telemetry-block.md +3 -1
- package/package.json +1 -1
- package/schemas/context-brake.config.schema.json +9 -4
- package/schemas/doctor-report.schema.json +51 -0
|
@@ -4,6 +4,17 @@ 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 slashInvocation(skill) {
|
|
9
|
+
return `/${skill}`;
|
|
10
|
+
}
|
|
11
|
+
function sentenceInvocation(skill) {
|
|
12
|
+
return `use the ${skill} skill`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/infrastructure/harnesses/claude-code/skill-invocation.ts
|
|
16
|
+
var CLAUDE_SKILL_INVOCATION = slashInvocation;
|
|
17
|
+
|
|
7
18
|
// node_modules/zod/v4/mini/external.js
|
|
8
19
|
var external_exports = {};
|
|
9
20
|
__export(external_exports, {
|
|
@@ -5029,7 +5040,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5029
5040
|
var NONE = 0;
|
|
5030
5041
|
var ASSUMED = 1;
|
|
5031
5042
|
var PROVEN = 2;
|
|
5032
|
-
function isRecursive(inst, stack,
|
|
5043
|
+
function isRecursive(inst, stack, resolve7) {
|
|
5033
5044
|
const cached2 = recursive.get(inst);
|
|
5034
5045
|
if (cached2 !== void 0)
|
|
5035
5046
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5039,7 +5050,7 @@ function isRecursive(inst, stack, resolve6) {
|
|
|
5039
5050
|
let result = NONE;
|
|
5040
5051
|
const check2 = (child) => {
|
|
5041
5052
|
if (result !== PROVEN && child?._zod) {
|
|
5042
|
-
const answer = isRecursive(child, stack,
|
|
5053
|
+
const answer = isRecursive(child, stack, resolve7);
|
|
5043
5054
|
if (answer > result)
|
|
5044
5055
|
result = answer;
|
|
5045
5056
|
}
|
|
@@ -5050,7 +5061,7 @@ function isRecursive(inst, stack, resolve6) {
|
|
|
5050
5061
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5051
5062
|
if (spread && !desc.enumerable)
|
|
5052
5063
|
continue;
|
|
5053
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5064
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve7) : NONE;
|
|
5054
5065
|
if (child > answer)
|
|
5055
5066
|
answer = child;
|
|
5056
5067
|
}
|
|
@@ -5114,7 +5125,7 @@ function isRecursive(inst, stack, resolve6) {
|
|
|
5114
5125
|
break;
|
|
5115
5126
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5116
5127
|
case "lazy": {
|
|
5117
|
-
const inner = def._cachedInner ?? (
|
|
5128
|
+
const inner = def._cachedInner ?? (resolve7 ? inst._zod.innerType : void 0);
|
|
5118
5129
|
merge3(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5119
5130
|
break;
|
|
5120
5131
|
}
|
|
@@ -18155,6 +18166,34 @@ var HARNESS_IDS = [
|
|
|
18155
18166
|
"antigravity-cli"
|
|
18156
18167
|
];
|
|
18157
18168
|
|
|
18169
|
+
// src/core/contracts/skill-name.ts
|
|
18170
|
+
var MAX_SKILL_NAME_LENGTH = 64;
|
|
18171
|
+
var NAME_SEGMENT = "[a-z0-9]+(?:-[a-z0-9]+)*";
|
|
18172
|
+
var NAMESPACE_SEPARATOR = ":";
|
|
18173
|
+
var INVOCATION_CHARACTERS = ["/", "$", "@"];
|
|
18174
|
+
var MAX_QUALIFIED_LENGTH = MAX_SKILL_NAME_LENGTH * 2 + NAMESPACE_SEPARATOR.length;
|
|
18175
|
+
function segmentFits(end) {
|
|
18176
|
+
return `(?=[^${NAMESPACE_SEPARATOR}]{1,${MAX_SKILL_NAME_LENGTH}}${end})`;
|
|
18177
|
+
}
|
|
18178
|
+
var PREFIX = `(?:${segmentFits(NAMESPACE_SEPARATOR)}${NAME_SEGMENT}${NAMESPACE_SEPARATOR})?`;
|
|
18179
|
+
var SKILL_NAME_PATTERN = new RegExp(`^${PREFIX}${segmentFits("$")}${NAME_SEGMENT}$`);
|
|
18180
|
+
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`;
|
|
18181
|
+
function isSkillName(value) {
|
|
18182
|
+
return SKILL_NAME_PATTERN.test(value);
|
|
18183
|
+
}
|
|
18184
|
+
function skillNameProblem(value) {
|
|
18185
|
+
if (value === "") return "must not be empty";
|
|
18186
|
+
if (isSkillName(value)) return null;
|
|
18187
|
+
const bare = INVOCATION_CHARACTERS.includes(value.charAt(0)) ? value.slice(1) : null;
|
|
18188
|
+
if (bare !== null && isSkillName(bare)) return `"${value}" is not a skill name; use the bare name ${bare}`;
|
|
18189
|
+
return `"${value}" is not a skill name; use ${SHAPE_RULE}`;
|
|
18190
|
+
}
|
|
18191
|
+
var skillNameSchema = external_exports.string().check((ctx) => {
|
|
18192
|
+
const message = skillNameProblem(ctx.value);
|
|
18193
|
+
if (message !== null) ctx.issues.push({ code: "custom", input: ctx.value, message });
|
|
18194
|
+
});
|
|
18195
|
+
external_exports.globalRegistry.add(skillNameSchema, { pattern: SKILL_NAME_PATTERN.source, maxLength: MAX_QUALIFIED_LENGTH });
|
|
18196
|
+
|
|
18158
18197
|
// src/core/contracts/zones.ts
|
|
18159
18198
|
var ZONES = ["GREEN", "YELLOW", "RED", "CRITICAL"];
|
|
18160
18199
|
var USAGE_SOURCES = ["measured", "estimated"];
|
|
@@ -18178,15 +18217,8 @@ function uniqueCheck(message) {
|
|
|
18178
18217
|
if (!isUnique(ctx.value)) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message });
|
|
18179
18218
|
};
|
|
18180
18219
|
}
|
|
18181
|
-
var MAX_AGENT_COMMAND_LENGTH = 200;
|
|
18182
|
-
var TRIMMED_RULE = "must not have leading or trailing whitespace";
|
|
18183
18220
|
var RESUME_REQUIRES_COMMAND_RULE = "requires snapshot.command";
|
|
18184
|
-
var
|
|
18185
|
-
var agentCommand = external_exports.string().check(external_exports.minLength(1), external_exports.maxLength(MAX_AGENT_COMMAND_LENGTH), (ctx) => {
|
|
18186
|
-
if (ctx.value.trim() !== ctx.value) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message: TRIMMED_RULE });
|
|
18187
|
-
if (/[\r\n]/.test(ctx.value)) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message: SINGLE_LINE_RULE });
|
|
18188
|
-
});
|
|
18189
|
-
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) => {
|
|
18221
|
+
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) => {
|
|
18190
18222
|
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 });
|
|
18191
18223
|
});
|
|
18192
18224
|
var DEFAULT_SNAPSHOT = { triggerZone: "RED" };
|
|
@@ -18267,21 +18299,25 @@ var GENERIC_ACTIONS = {
|
|
|
18267
18299
|
RED: "finish or pause the current unit and tell the user what remains",
|
|
18268
18300
|
CRITICAL: "stop starting new work; tell the user what remains"
|
|
18269
18301
|
};
|
|
18270
|
-
function
|
|
18271
|
-
if (
|
|
18272
|
-
|
|
18273
|
-
|
|
18302
|
+
function isResetDue(reading, snapshot) {
|
|
18303
|
+
if (snapshot.triggerPercentage !== void 0) return reading.usagePercentage >= snapshot.triggerPercentage;
|
|
18304
|
+
return reading.zone !== "GREEN" && isAtOrAbove(reading.zone, snapshot.triggerZone);
|
|
18305
|
+
}
|
|
18306
|
+
function zoneAction(zone, snapshot, options = {}) {
|
|
18307
|
+
if (!isResetDue({ zone, usagePercentage: options.usagePercentage ?? 0 }, snapshot)) return GENERIC_ACTIONS[zone];
|
|
18308
|
+
if (snapshot.command !== void 0) return snapshotAction(zone, (options.invoke ?? sentenceInvocation)(snapshot.command));
|
|
18309
|
+
if ((options.mode ?? "off") !== "handoff") return GENERIC_ACTIONS[zone];
|
|
18274
18310
|
return `save handoff to ${HANDOFF_PATH}, end reply with ${SESSION_RESET_SIGNAL}`;
|
|
18275
18311
|
}
|
|
18276
|
-
function snapshotAction(zone,
|
|
18312
|
+
function snapshotAction(zone, invocation) {
|
|
18277
18313
|
const now = zone === "CRITICAL" ? " now" : "";
|
|
18278
|
-
return `run "${
|
|
18314
|
+
return `run "${invocation}"${now}, then end reply with ${SESSION_RESET_SIGNAL}`;
|
|
18279
18315
|
}
|
|
18280
18316
|
function handoffResumeText(archivedPath) {
|
|
18281
18317
|
return `${RESUME_PREFIX} Read "${archivedPath}" and continue the previous work from it.`;
|
|
18282
18318
|
}
|
|
18283
|
-
function resumeText(snapshot) {
|
|
18284
|
-
return snapshot.resumeCommand === void 0 ? null : `${RESUME_PREFIX} Run "${snapshot.resumeCommand}" before continuing.`;
|
|
18319
|
+
function resumeText(snapshot, invoke = sentenceInvocation) {
|
|
18320
|
+
return snapshot.resumeCommand === void 0 ? null : `${RESUME_PREFIX} Run "${invoke(snapshot.resumeCommand)}" before continuing.`;
|
|
18285
18321
|
}
|
|
18286
18322
|
function isAtOrAbove(zone, trigger) {
|
|
18287
18323
|
return ZONES.indexOf(zone) >= ZONES.indexOf(trigger);
|
|
@@ -18326,7 +18362,7 @@ async function resolveFailure(input2) {
|
|
|
18326
18362
|
return { kind: "neutral" };
|
|
18327
18363
|
}
|
|
18328
18364
|
function deadlineBootDecision(input2) {
|
|
18329
|
-
const text = resumeText((input2.config ?? DEFAULT_CONFIG).snapshot);
|
|
18365
|
+
const text = resumeText((input2.config ?? DEFAULT_CONFIG).snapshot, input2.descriptor?.skillInvocation);
|
|
18330
18366
|
return text === null ? { kind: "neutral" } : { kind: "context", block: text };
|
|
18331
18367
|
}
|
|
18332
18368
|
async function recordRuntimeFailure(errors, record2) {
|
|
@@ -18447,7 +18483,7 @@ function isDebugModeInEffect(config2) {
|
|
|
18447
18483
|
|
|
18448
18484
|
// src/core/services/injection-policy.ts
|
|
18449
18485
|
function decideInjection(input2) {
|
|
18450
|
-
if (input2.debug || input2.telemetry.injectionMode === "always") return true;
|
|
18486
|
+
if (input2.debug || input2.resetDue === true || input2.telemetry.injectionMode === "always") return true;
|
|
18451
18487
|
return input2.zone !== "GREEN" || input2.usagePercentage >= input2.telemetry.activationThresholdPercentage;
|
|
18452
18488
|
}
|
|
18453
18489
|
|
|
@@ -18598,7 +18634,7 @@ async function handleSessionReset(options, event, hooks = {}) {
|
|
|
18598
18634
|
if (!options.descriptor.capabilities.some((entry) => entry.id === "session_boot" && entry.state === "supported")) return NEUTRAL;
|
|
18599
18635
|
if (event.reason === "compact" && !COMPACTION_BOOT_HARNESSES.includes(options.descriptor.harness)) return NEUTRAL;
|
|
18600
18636
|
hooks.onPhase?.("guidance");
|
|
18601
|
-
const text = resumeText(options.config.snapshot) ?? await claimHandoff(options, event.reason, hooks.deadline);
|
|
18637
|
+
const text = resumeText(options.config.snapshot, options.descriptor.skillInvocation) ?? await claimHandoff(options, event.reason, hooks.deadline);
|
|
18602
18638
|
return text === null ? NEUTRAL : { kind: "context", block: text };
|
|
18603
18639
|
}
|
|
18604
18640
|
async function claimHandoff(options, reason, deadline) {
|
|
@@ -18640,8 +18676,9 @@ async function handlePreInvocation(options, event, input2) {
|
|
|
18640
18676
|
return telemetryDecision(options, summary.turns, readZone(options, { summary, turns: summary.turns, observedCharacters: 0, measured: input2.measured }));
|
|
18641
18677
|
}
|
|
18642
18678
|
async function telemetryDecision(options, turn, view) {
|
|
18643
|
-
|
|
18644
|
-
|
|
18679
|
+
const resetDue = isResetDue({ zone: view.zone, usagePercentage: view.percentage }, options.config.snapshot);
|
|
18680
|
+
if (!decideInjection({ telemetry: options.config.telemetry, zone: view.zone, usagePercentage: view.percentage, debug: isDebugModeInEffect(options.config), resetDue })) return NEUTRAL2;
|
|
18681
|
+
const action = zoneAction(view.zone, options.config.snapshot, { mode: restartMode(options.config), invoke: options.descriptor.skillInvocation, usagePercentage: view.percentage });
|
|
18645
18682
|
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) }) };
|
|
18646
18683
|
}
|
|
18647
18684
|
async function handleResponseEnd(options, event) {
|
|
@@ -18675,6 +18712,26 @@ import { createHash } from "node:crypto";
|
|
|
18675
18712
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
18676
18713
|
import { join as join2, resolve as resolve3 } from "node:path";
|
|
18677
18714
|
|
|
18715
|
+
// src/core/contracts/context-reading.ts
|
|
18716
|
+
var CONTEXT_READINGS_RELATIVE_DIR = ".context-brake/runtime/context-readings";
|
|
18717
|
+
var CONTEXT_READING_MAXIMUM_CHARACTERS = 1024;
|
|
18718
|
+
var RUNTIME_IGNORE_CONTENT = "*\n";
|
|
18719
|
+
var SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
18720
|
+
var PERCENTAGE_MAXIMUM = 100;
|
|
18721
|
+
var contextReadingSchema = external_exports.strictObject({
|
|
18722
|
+
v: external_exports.literal(1),
|
|
18723
|
+
at: external_exports.string().check(external_exports.minLength(1)),
|
|
18724
|
+
windowTokens: external_exports.nullable(external_exports.int().check(external_exports.positive())),
|
|
18725
|
+
inputTokens: external_exports.nullable(external_exports.int().check(external_exports.nonnegative())),
|
|
18726
|
+
usedPercentage: external_exports.nullable(external_exports.number().check(external_exports.gte(0), external_exports.lte(PERCENTAGE_MAXIMUM)))
|
|
18727
|
+
});
|
|
18728
|
+
function isReadingSessionId(value) {
|
|
18729
|
+
return value !== void 0 && SESSION_ID_PATTERN.test(value);
|
|
18730
|
+
}
|
|
18731
|
+
function contextReadingRelativePath(harness, sessionId) {
|
|
18732
|
+
return `${CONTEXT_READINGS_RELATIVE_DIR}/${harness}/${sessionId}.json`;
|
|
18733
|
+
}
|
|
18734
|
+
|
|
18678
18735
|
// src/infrastructure/storage/runtime-state-files.ts
|
|
18679
18736
|
import { readdir } from "node:fs/promises";
|
|
18680
18737
|
import { join, relative, resolve as resolve2 } from "node:path";
|
|
@@ -18694,7 +18751,7 @@ async function listRuntimeStateFiles(root, readdirFn = readdir) {
|
|
|
18694
18751
|
}
|
|
18695
18752
|
|
|
18696
18753
|
// src/infrastructure/runtime/runtime-paths.ts
|
|
18697
|
-
var RUNTIME_GITIGNORE_CONTENT =
|
|
18754
|
+
var RUNTIME_GITIGNORE_CONTENT = RUNTIME_IGNORE_CONTENT;
|
|
18698
18755
|
var SESSIONS_DIR_NAME = "sessions";
|
|
18699
18756
|
var LEDGER_FILE_EXTENSION = ".jsonl";
|
|
18700
18757
|
var SESSIONS_RELATIVE_PREFIX = `${RUNTIME_STATE_RELATIVE_DIR}/${SESSIONS_DIR_NAME}/`;
|
|
@@ -19035,7 +19092,7 @@ var defaultProcessHookContext = {
|
|
|
19035
19092
|
sessionStartDeadlineMilliseconds: SESSION_START_DEADLINE_MILLISECONDS
|
|
19036
19093
|
};
|
|
19037
19094
|
function readStdinUpTo(stream, maximumBytes) {
|
|
19038
|
-
return new Promise((
|
|
19095
|
+
return new Promise((resolve7, reject) => {
|
|
19039
19096
|
const chunks = [];
|
|
19040
19097
|
let size = 0;
|
|
19041
19098
|
stream.on("data", (chunk) => {
|
|
@@ -19044,7 +19101,7 @@ function readStdinUpTo(stream, maximumBytes) {
|
|
|
19044
19101
|
chunks.push(remaining >= chunk.length ? chunk : chunk.subarray(0, remaining));
|
|
19045
19102
|
size += chunk.length;
|
|
19046
19103
|
});
|
|
19047
|
-
stream.on("end", () =>
|
|
19104
|
+
stream.on("end", () => resolve7(Buffer.concat(chunks).toString("utf8")));
|
|
19048
19105
|
stream.on("error", (error62) => reject(error62));
|
|
19049
19106
|
});
|
|
19050
19107
|
}
|
|
@@ -19100,10 +19157,49 @@ function parsePayload2(raw) {
|
|
|
19100
19157
|
var CLAUDE_CAPABILITIES = [
|
|
19101
19158
|
{ id: "post_tool_telemetry", state: "supported" },
|
|
19102
19159
|
{ id: "session_boot", state: "supported" },
|
|
19103
|
-
{ id: "context_usage", state: "unknown", impact: "Read from the session transcript, whose format is undocumented; falls back to an estimate. The context window comes from the status line bridge
|
|
19160
|
+
{ id: "context_usage", state: "unknown", impact: "Read from the session transcript, whose format is undocumented; falls back to an estimate. The context window comes from the mod that init installs on Claude Code 2.1.287 or later, or from the status line bridge on older versions; without either, it falls back to contextWindowCeiling." },
|
|
19104
19161
|
{ id: "auto_restart", state: "unknown", impact: "Opt-in through init --auto-restart; needs Claude Code 2.1.287 or later with mods enabled. Run doctor to check that the mod loads." }
|
|
19105
19162
|
];
|
|
19106
19163
|
|
|
19164
|
+
// src/infrastructure/harnesses/claude-code/mod-reading.ts
|
|
19165
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
19166
|
+
import { resolve as resolve6 } from "node:path";
|
|
19167
|
+
|
|
19168
|
+
// src/infrastructure/harnesses/claude-code/project-root.ts
|
|
19169
|
+
var PROJECT_DIRECTORY_VARIABLE = "CLAUDE_PROJECT_DIR";
|
|
19170
|
+
async function resolveClaudeProjectRoot() {
|
|
19171
|
+
return projectRootFromEnvironment([PROJECT_DIRECTORY_VARIABLE]) ?? await assetProjectRoot();
|
|
19172
|
+
}
|
|
19173
|
+
|
|
19174
|
+
// src/infrastructure/harnesses/claude-code/mod-reading.ts
|
|
19175
|
+
function parseContextReading(text) {
|
|
19176
|
+
if (text.length > CONTEXT_READING_MAXIMUM_CHARACTERS) return null;
|
|
19177
|
+
try {
|
|
19178
|
+
const parsed = contextReadingSchema.safeParse(JSON.parse(text));
|
|
19179
|
+
return parsed.success ? parsed.data : null;
|
|
19180
|
+
} catch {
|
|
19181
|
+
return null;
|
|
19182
|
+
}
|
|
19183
|
+
}
|
|
19184
|
+
async function readContextReading(sessionId) {
|
|
19185
|
+
if (!isReadingSessionId(sessionId)) return null;
|
|
19186
|
+
const path = resolve6(await resolveClaudeProjectRoot(), contextReadingRelativePath("claude-code", sessionId));
|
|
19187
|
+
return parseContextReading(await readFile3(path, "utf8").catch(() => ""));
|
|
19188
|
+
}
|
|
19189
|
+
function isNotOlder(reading, transcript) {
|
|
19190
|
+
return transcript === null || Date.parse(reading.at) >= Date.parse(transcript.at);
|
|
19191
|
+
}
|
|
19192
|
+
function chooseTokens(transcript, reading) {
|
|
19193
|
+
if (reading !== null && reading.inputTokens !== null && isNotOlder(reading, transcript)) return { tokens: reading.inputTokens, at: reading.at };
|
|
19194
|
+
if (transcript === null) return { tokens: null, at: reading?.at };
|
|
19195
|
+
return { tokens: transcript.tokens, at: transcript.at };
|
|
19196
|
+
}
|
|
19197
|
+
function freshestMeasured(transcript, reading) {
|
|
19198
|
+
if (transcript === null && reading === null) return void 0;
|
|
19199
|
+
const choice = chooseTokens(transcript, reading);
|
|
19200
|
+
return { tokens: choice.tokens, contextWindow: reading?.windowTokens ?? null, at: choice.at };
|
|
19201
|
+
}
|
|
19202
|
+
|
|
19107
19203
|
// src/infrastructure/harnesses/claude-code/schemas.ts
|
|
19108
19204
|
var claudeHookItemSchema = external_exports.looseObject({
|
|
19109
19205
|
type: external_exports.optional(external_exports.string()),
|
|
@@ -19232,7 +19328,7 @@ var HARNESS = "claude-code";
|
|
|
19232
19328
|
var ESTIMATION = { baselineTokens: 15e3, tokensPerTurn: 150 };
|
|
19233
19329
|
var WRITE_TOOLS = ["Write", "Edit", "MultiEdit", "NotebookEdit"];
|
|
19234
19330
|
var SKILL_TOOL = "Skill";
|
|
19235
|
-
var claudeDescriptor = { harness: HARNESS, capabilities: CLAUDE_CAPABILITIES, estimation: ESTIMATION, newSessionCommand: "/clear" };
|
|
19331
|
+
var claudeDescriptor = { harness: HARNESS, capabilities: CLAUDE_CAPABILITIES, estimation: ESTIMATION, newSessionCommand: "/clear", skillInvocation: CLAUDE_SKILL_INVOCATION };
|
|
19236
19332
|
function sessionOf(payload) {
|
|
19237
19333
|
return { harness: HARNESS, sessionId: requireIdentifier(payload.session_id), agentId: payload.agent_id ?? null };
|
|
19238
19334
|
}
|
|
@@ -19269,17 +19365,19 @@ function mapClaudeEvent(eventName, payload) {
|
|
|
19269
19365
|
async function mapClaudeInput(eventName, payload, errors) {
|
|
19270
19366
|
if (eventName !== "PostToolUse") return {};
|
|
19271
19367
|
const data = parsePayload(claudePayloadSchema, payload);
|
|
19272
|
-
const measured = data.agent_id === void 0 ? await measuredUsage({ path: data.transcript_path, eventName, errors }) : void 0;
|
|
19368
|
+
const measured = data.agent_id === void 0 ? await measuredUsage({ path: data.transcript_path, sessionId: data.session_id, eventName, errors }) : void 0;
|
|
19273
19369
|
const usage = measured === void 0 ? {} : { measured };
|
|
19274
19370
|
return { ...usage, observedCharacters: characterLength(data.tool_input) + characterLength(data.tool_response) };
|
|
19275
19371
|
}
|
|
19276
19372
|
async function measuredUsage(input2) {
|
|
19373
|
+
return freshestMeasured(await transcriptUsage(input2), await readContextReading(input2.sessionId));
|
|
19374
|
+
}
|
|
19375
|
+
async function transcriptUsage(input2) {
|
|
19277
19376
|
try {
|
|
19278
|
-
|
|
19279
|
-
return usage === null ? void 0 : { tokens: usage.tokens, contextWindow: null, at: usage.at };
|
|
19377
|
+
return await readTranscriptUsage(input2.path);
|
|
19280
19378
|
} catch (error62) {
|
|
19281
19379
|
await recordRuntimeFailure(input2.errors, { harness: HARNESS, event: input2.eventName, code: "UNEXPECTED", detail: failureDetail(error62) });
|
|
19282
|
-
return
|
|
19380
|
+
return null;
|
|
19283
19381
|
}
|
|
19284
19382
|
}
|
|
19285
19383
|
function renderClaudeDecision(decision, eventName) {
|
|
@@ -19292,7 +19390,7 @@ var claudeAdapter = {
|
|
|
19292
19390
|
mapEvent: mapClaudeEvent,
|
|
19293
19391
|
mapInput: mapClaudeInput,
|
|
19294
19392
|
renderDecision: renderClaudeDecision,
|
|
19295
|
-
resolveProjectRoot:
|
|
19393
|
+
resolveProjectRoot: resolveClaudeProjectRoot
|
|
19296
19394
|
};
|
|
19297
19395
|
function runClaudeCodeHook() {
|
|
19298
19396
|
return runProcessHook(claudeAdapter);
|
|
@@ -18136,6 +18136,26 @@ function date4(params) {
|
|
|
18136
18136
|
return _coercedDate(ZodMiniDate, params);
|
|
18137
18137
|
}
|
|
18138
18138
|
|
|
18139
|
+
// src/core/contracts/context-reading.ts
|
|
18140
|
+
var CONTEXT_READINGS_RELATIVE_DIR = ".context-brake/runtime/context-readings";
|
|
18141
|
+
var RUNTIME_IGNORE_RELATIVE_PATH = ".context-brake/runtime/.gitignore";
|
|
18142
|
+
var RUNTIME_IGNORE_CONTENT = "*\n";
|
|
18143
|
+
var SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
18144
|
+
var PERCENTAGE_MAXIMUM = 100;
|
|
18145
|
+
var contextReadingSchema = external_exports.strictObject({
|
|
18146
|
+
v: external_exports.literal(1),
|
|
18147
|
+
at: external_exports.string().check(external_exports.minLength(1)),
|
|
18148
|
+
windowTokens: external_exports.nullable(external_exports.int().check(external_exports.positive())),
|
|
18149
|
+
inputTokens: external_exports.nullable(external_exports.int().check(external_exports.nonnegative())),
|
|
18150
|
+
usedPercentage: external_exports.nullable(external_exports.number().check(external_exports.gte(0), external_exports.lte(PERCENTAGE_MAXIMUM)))
|
|
18151
|
+
});
|
|
18152
|
+
function isReadingSessionId(value) {
|
|
18153
|
+
return value !== void 0 && SESSION_ID_PATTERN.test(value);
|
|
18154
|
+
}
|
|
18155
|
+
function contextReadingRelativePath(harness, sessionId) {
|
|
18156
|
+
return `${CONTEXT_READINGS_RELATIVE_DIR}/${harness}/${sessionId}.json`;
|
|
18157
|
+
}
|
|
18158
|
+
|
|
18139
18159
|
// src/core/contracts/auto-restart.ts
|
|
18140
18160
|
var DEFAULT_MAX_CONSECUTIVE_RESTARTS = 2;
|
|
18141
18161
|
var MIN_CONSECUTIVE_RESTARTS = 1;
|
|
@@ -18180,56 +18200,6 @@ var restartLogSchema = external_exports.strictObject({
|
|
|
18180
18200
|
records: external_exports.array(restartLogRecordSchema).check(external_exports.maxLength(RESTART_LOG_MAX_RECORDS))
|
|
18181
18201
|
});
|
|
18182
18202
|
|
|
18183
|
-
// src/infrastructure/harnesses/claude-code/mod/mod-info.ts
|
|
18184
|
-
var MOD_VERSION = "1.0.0";
|
|
18185
|
-
var MOD_LOG_DIR = `${RESTART_LOG_RELATIVE_DIR}/claude-code`;
|
|
18186
|
-
var CONFIG_FILE = "context-brake.config.json";
|
|
18187
|
-
var PERSON_PROMPT_ORIGINS = ["composer", "bridge"];
|
|
18188
|
-
|
|
18189
|
-
// src/core/contracts/restart-host.ts
|
|
18190
|
-
var guardStateSchema = external_exports.strictObject({ consecutive: external_exports.int().check(external_exports.minimum(0)), toolCallsSinceSeed: external_exports.nullable(external_exports.int().check(external_exports.minimum(0))) });
|
|
18191
|
-
var IDLE_GUARD_STATE = { consecutive: 0, toolCallsSinceSeed: null };
|
|
18192
|
-
|
|
18193
|
-
// src/core/services/restart-guards.ts
|
|
18194
|
-
async function bumpConsecutive(store) {
|
|
18195
|
-
const state = await store.read();
|
|
18196
|
-
await store.write({ ...state, consecutive: state.consecutive + 1 });
|
|
18197
|
-
}
|
|
18198
|
-
async function rollbackConsecutive(store) {
|
|
18199
|
-
const state = await store.read();
|
|
18200
|
-
await store.write({ ...state, consecutive: Math.max(0, state.consecutive - 1) });
|
|
18201
|
-
}
|
|
18202
|
-
async function markSeeded(store) {
|
|
18203
|
-
const state = await store.read();
|
|
18204
|
-
await store.write({ ...state, toolCallsSinceSeed: 0 });
|
|
18205
|
-
}
|
|
18206
|
-
async function foldToolCalls(store, calls) {
|
|
18207
|
-
const state = await store.read();
|
|
18208
|
-
if (state.toolCallsSinceSeed === null || calls === 0) return;
|
|
18209
|
-
await store.write({ ...state, toolCallsSinceSeed: state.toolCallsSinceSeed + calls });
|
|
18210
|
-
}
|
|
18211
|
-
async function resetConsecutive(store) {
|
|
18212
|
-
const state = await store.read();
|
|
18213
|
-
if (state.consecutive === 0 && state.toolCallsSinceSeed === null) return;
|
|
18214
|
-
await store.write(IDLE_GUARD_STATE);
|
|
18215
|
-
}
|
|
18216
|
-
|
|
18217
|
-
// src/infrastructure/harnesses/claude-code/mod/mod-guards.ts
|
|
18218
|
-
function guardKey(root) {
|
|
18219
|
-
return `contextbrake:autorestart:${root}`;
|
|
18220
|
-
}
|
|
18221
|
-
function modGuardStore($, root) {
|
|
18222
|
-
return {
|
|
18223
|
-
read: async () => {
|
|
18224
|
-
const parsed = guardStateSchema.safeParse(await $.store.get(guardKey(root)));
|
|
18225
|
-
return parsed.success ? parsed.data : IDLE_GUARD_STATE;
|
|
18226
|
-
},
|
|
18227
|
-
write: async (state) => {
|
|
18228
|
-
await $.store.set(guardKey(root), state);
|
|
18229
|
-
}
|
|
18230
|
-
};
|
|
18231
|
-
}
|
|
18232
|
-
|
|
18233
18203
|
// src/core/services/auto-restart-notices.ts
|
|
18234
18204
|
var SEED_BASE = "ContextBrake: this session was restarted automatically. Continue the previous work from the state it recorded.";
|
|
18235
18205
|
var SKIPPED = "ContextBrake: automatic restart skipped: ";
|
|
@@ -18260,6 +18230,12 @@ function appendLogRecord(records, record2) {
|
|
|
18260
18230
|
return [...records, record2].slice(-RESTART_LOG_MAX_RECORDS);
|
|
18261
18231
|
}
|
|
18262
18232
|
|
|
18233
|
+
// src/infrastructure/harnesses/claude-code/mod/mod-info.ts
|
|
18234
|
+
var MOD_VERSION = "1.1.0";
|
|
18235
|
+
var MOD_LOG_DIR = `${RESTART_LOG_RELATIVE_DIR}/claude-code`;
|
|
18236
|
+
var CONFIG_FILE = "context-brake.config.json";
|
|
18237
|
+
var PERSON_PROMPT_ORIGINS = ["composer", "bridge"];
|
|
18238
|
+
|
|
18263
18239
|
// src/infrastructure/harnesses/claude-code/mod/mod-log.ts
|
|
18264
18240
|
async function logPath($) {
|
|
18265
18241
|
return `${await $.session.root()}/${MOD_LOG_DIR}/${await $.session.id()}.json`;
|
|
@@ -18280,6 +18256,9 @@ async function writeLog($, path, log) {
|
|
|
18280
18256
|
await $.fs.write(path, `${JSON.stringify(log, null, 2)}
|
|
18281
18257
|
`);
|
|
18282
18258
|
}
|
|
18259
|
+
async function lastRecordedCode($) {
|
|
18260
|
+
return (await readLog($, await logPath($))).records.at(-1)?.code;
|
|
18261
|
+
}
|
|
18283
18262
|
async function recordLoaded($) {
|
|
18284
18263
|
const path = await logPath($);
|
|
18285
18264
|
const log = await readLog($, path);
|
|
@@ -18298,6 +18277,34 @@ function endsWithResetSignal(text) {
|
|
|
18298
18277
|
return text.trimEnd().split(/\r?\n/).at(-1)?.endsWith(SESSION_RESET_SIGNAL) ?? false;
|
|
18299
18278
|
}
|
|
18300
18279
|
|
|
18280
|
+
// src/core/contracts/restart-host.ts
|
|
18281
|
+
var guardStateSchema = external_exports.strictObject({ consecutive: external_exports.int().check(external_exports.minimum(0)), toolCallsSinceSeed: external_exports.nullable(external_exports.int().check(external_exports.minimum(0))) });
|
|
18282
|
+
var IDLE_GUARD_STATE = { consecutive: 0, toolCallsSinceSeed: null };
|
|
18283
|
+
|
|
18284
|
+
// src/core/services/restart-guards.ts
|
|
18285
|
+
async function bumpConsecutive(store) {
|
|
18286
|
+
const state = await store.read();
|
|
18287
|
+
await store.write({ ...state, consecutive: state.consecutive + 1 });
|
|
18288
|
+
}
|
|
18289
|
+
async function rollbackConsecutive(store) {
|
|
18290
|
+
const state = await store.read();
|
|
18291
|
+
await store.write({ ...state, consecutive: Math.max(0, state.consecutive - 1) });
|
|
18292
|
+
}
|
|
18293
|
+
async function markSeeded(store) {
|
|
18294
|
+
const state = await store.read();
|
|
18295
|
+
await store.write({ ...state, toolCallsSinceSeed: 0 });
|
|
18296
|
+
}
|
|
18297
|
+
async function foldToolCalls(store, calls) {
|
|
18298
|
+
const state = await store.read();
|
|
18299
|
+
if (state.toolCallsSinceSeed === null || calls === 0) return;
|
|
18300
|
+
await store.write({ ...state, toolCallsSinceSeed: state.toolCallsSinceSeed + calls });
|
|
18301
|
+
}
|
|
18302
|
+
async function resetConsecutive(store) {
|
|
18303
|
+
const state = await store.read();
|
|
18304
|
+
if (state.consecutive === 0 && state.toolCallsSinceSeed === null) return;
|
|
18305
|
+
await store.write(IDLE_GUARD_STATE);
|
|
18306
|
+
}
|
|
18307
|
+
|
|
18301
18308
|
// src/core/services/auto-restart-policy.ts
|
|
18302
18309
|
function standDownCode(facts) {
|
|
18303
18310
|
if (facts.disabledByEnv) return "SKIP_DISABLED_ENV";
|
|
@@ -18361,6 +18368,34 @@ async function handleTurnEnd(host, turn) {
|
|
|
18361
18368
|
});
|
|
18362
18369
|
}
|
|
18363
18370
|
|
|
18371
|
+
// src/core/contracts/skill-name.ts
|
|
18372
|
+
var MAX_SKILL_NAME_LENGTH = 64;
|
|
18373
|
+
var NAME_SEGMENT = "[a-z0-9]+(?:-[a-z0-9]+)*";
|
|
18374
|
+
var NAMESPACE_SEPARATOR = ":";
|
|
18375
|
+
var INVOCATION_CHARACTERS = ["/", "$", "@"];
|
|
18376
|
+
var MAX_QUALIFIED_LENGTH = MAX_SKILL_NAME_LENGTH * 2 + NAMESPACE_SEPARATOR.length;
|
|
18377
|
+
function segmentFits(end) {
|
|
18378
|
+
return `(?=[^${NAMESPACE_SEPARATOR}]{1,${MAX_SKILL_NAME_LENGTH}}${end})`;
|
|
18379
|
+
}
|
|
18380
|
+
var PREFIX = `(?:${segmentFits(NAMESPACE_SEPARATOR)}${NAME_SEGMENT}${NAMESPACE_SEPARATOR})?`;
|
|
18381
|
+
var SKILL_NAME_PATTERN = new RegExp(`^${PREFIX}${segmentFits("$")}${NAME_SEGMENT}$`);
|
|
18382
|
+
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`;
|
|
18383
|
+
function isSkillName(value) {
|
|
18384
|
+
return SKILL_NAME_PATTERN.test(value);
|
|
18385
|
+
}
|
|
18386
|
+
function skillNameProblem(value) {
|
|
18387
|
+
if (value === "") return "must not be empty";
|
|
18388
|
+
if (isSkillName(value)) return null;
|
|
18389
|
+
const bare = INVOCATION_CHARACTERS.includes(value.charAt(0)) ? value.slice(1) : null;
|
|
18390
|
+
if (bare !== null && isSkillName(bare)) return `"${value}" is not a skill name; use the bare name ${bare}`;
|
|
18391
|
+
return `"${value}" is not a skill name; use ${SHAPE_RULE}`;
|
|
18392
|
+
}
|
|
18393
|
+
var skillNameSchema = external_exports.string().check((ctx) => {
|
|
18394
|
+
const message = skillNameProblem(ctx.value);
|
|
18395
|
+
if (message !== null) ctx.issues.push({ code: "custom", input: ctx.value, message });
|
|
18396
|
+
});
|
|
18397
|
+
external_exports.globalRegistry.add(skillNameSchema, { pattern: SKILL_NAME_PATTERN.source, maxLength: MAX_QUALIFIED_LENGTH });
|
|
18398
|
+
|
|
18364
18399
|
// src/core/contracts/zones.ts
|
|
18365
18400
|
var SNAPSHOT_TRIGGER_ZONES = ["YELLOW", "RED"];
|
|
18366
18401
|
|
|
@@ -18381,15 +18416,8 @@ function uniqueCheck(message) {
|
|
|
18381
18416
|
if (!isUnique(ctx.value)) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message });
|
|
18382
18417
|
};
|
|
18383
18418
|
}
|
|
18384
|
-
var MAX_AGENT_COMMAND_LENGTH = 200;
|
|
18385
|
-
var TRIMMED_RULE = "must not have leading or trailing whitespace";
|
|
18386
18419
|
var RESUME_REQUIRES_COMMAND_RULE = "requires snapshot.command";
|
|
18387
|
-
var
|
|
18388
|
-
var agentCommand = external_exports.string().check(external_exports.minLength(1), external_exports.maxLength(MAX_AGENT_COMMAND_LENGTH), (ctx) => {
|
|
18389
|
-
if (ctx.value.trim() !== ctx.value) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message: TRIMMED_RULE });
|
|
18390
|
-
if (/[\r\n]/.test(ctx.value)) addIssue(ctx, { code: "custom", path: [], input: ctx.value, message: SINGLE_LINE_RULE });
|
|
18391
|
-
});
|
|
18392
|
-
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) => {
|
|
18420
|
+
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) => {
|
|
18393
18421
|
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 });
|
|
18394
18422
|
});
|
|
18395
18423
|
var DEFAULT_SNAPSHOT = { triggerZone: "RED" };
|
|
@@ -18442,6 +18470,22 @@ async function readModConfig($) {
|
|
|
18442
18470
|
};
|
|
18443
18471
|
}
|
|
18444
18472
|
|
|
18473
|
+
// src/infrastructure/harnesses/claude-code/mod/mod-guards.ts
|
|
18474
|
+
function guardKey(root) {
|
|
18475
|
+
return `contextbrake:autorestart:${root}`;
|
|
18476
|
+
}
|
|
18477
|
+
function modGuardStore($, root) {
|
|
18478
|
+
return {
|
|
18479
|
+
read: async () => {
|
|
18480
|
+
const parsed = guardStateSchema.safeParse(await $.store.get(guardKey(root)));
|
|
18481
|
+
return parsed.success ? parsed.data : IDLE_GUARD_STATE;
|
|
18482
|
+
},
|
|
18483
|
+
write: async (state) => {
|
|
18484
|
+
await $.store.set(guardKey(root), state);
|
|
18485
|
+
}
|
|
18486
|
+
};
|
|
18487
|
+
}
|
|
18488
|
+
|
|
18445
18489
|
// src/core/contracts/handoff.ts
|
|
18446
18490
|
var HANDOFF_RELATIVE_PATH = ".context-brake/handoff.md";
|
|
18447
18491
|
|
|
@@ -18517,6 +18561,64 @@ async function handleTurnComplete($, event) {
|
|
|
18517
18561
|
await handleTurnEnd(createModRestartHost($, config2), { text, settings: { maxConsecutive: config2.maxConsecutive, mode: config2.mode } });
|
|
18518
18562
|
}
|
|
18519
18563
|
|
|
18564
|
+
// src/infrastructure/harnesses/claude-code/mod/context-reading.ts
|
|
18565
|
+
var READING_HARNESS = "claude-code";
|
|
18566
|
+
var READING_VERSION = 1;
|
|
18567
|
+
var PERCENTAGE_MAXIMUM2 = 100;
|
|
18568
|
+
var UNREADABLE_CODE = "ERROR_INTERNAL";
|
|
18569
|
+
function positiveIntegerOrNull(value) {
|
|
18570
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
18571
|
+
}
|
|
18572
|
+
function countOrNull(value) {
|
|
18573
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null;
|
|
18574
|
+
}
|
|
18575
|
+
function percentageOrNull(value) {
|
|
18576
|
+
return typeof value === "number" && value >= 0 && value <= PERCENTAGE_MAXIMUM2 ? value : null;
|
|
18577
|
+
}
|
|
18578
|
+
function readingOf(context, at) {
|
|
18579
|
+
return { v: READING_VERSION, at, windowTokens: positiveIntegerOrNull(context.window), inputTokens: countOrNull(context.tokens), usedPercentage: percentageOrNull(context.percent) };
|
|
18580
|
+
}
|
|
18581
|
+
async function isAlreadyPublished($, path, reading) {
|
|
18582
|
+
if (!await $.fs.exists(path)) return false;
|
|
18583
|
+
try {
|
|
18584
|
+
const previous = contextReadingSchema.safeParse(JSON.parse(String(await $.fs.read(path))));
|
|
18585
|
+
return previous.success && previous.data.windowTokens === reading.windowTokens && previous.data.inputTokens === reading.inputTokens;
|
|
18586
|
+
} catch {
|
|
18587
|
+
return false;
|
|
18588
|
+
}
|
|
18589
|
+
}
|
|
18590
|
+
async function ensureRuntimeIgnore($, root) {
|
|
18591
|
+
const path = `${root}/${RUNTIME_IGNORE_RELATIVE_PATH}`;
|
|
18592
|
+
if (!await $.fs.exists(path)) await $.fs.write(path, RUNTIME_IGNORE_CONTENT);
|
|
18593
|
+
}
|
|
18594
|
+
async function reportOnce($) {
|
|
18595
|
+
try {
|
|
18596
|
+
if (await lastRecordedCode($) === UNREADABLE_CODE) return;
|
|
18597
|
+
} catch {
|
|
18598
|
+
return;
|
|
18599
|
+
}
|
|
18600
|
+
await reportSafely($, UNREADABLE_CODE);
|
|
18601
|
+
}
|
|
18602
|
+
async function publishChanged($) {
|
|
18603
|
+
const sessionId = await $.session.id();
|
|
18604
|
+
if (!isReadingSessionId(sessionId)) return;
|
|
18605
|
+
const reading = readingOf((await $.session.usage()).context, new Date(await $.clock.now()).toISOString());
|
|
18606
|
+
if (reading.windowTokens === null) return reportOnce($);
|
|
18607
|
+
const root = await $.session.root();
|
|
18608
|
+
const path = `${root}/${contextReadingRelativePath(READING_HARNESS, sessionId)}`;
|
|
18609
|
+
if (await isAlreadyPublished($, path, reading)) return;
|
|
18610
|
+
await ensureRuntimeIgnore($, root);
|
|
18611
|
+
await $.fs.write(path, `${JSON.stringify(reading)}
|
|
18612
|
+
`);
|
|
18613
|
+
}
|
|
18614
|
+
async function publishContextReading($) {
|
|
18615
|
+
try {
|
|
18616
|
+
await publishChanged($);
|
|
18617
|
+
} catch {
|
|
18618
|
+
await reportOnce($);
|
|
18619
|
+
}
|
|
18620
|
+
}
|
|
18621
|
+
|
|
18520
18622
|
// src/infrastructure/harnesses/claude-code/mod/hooks.ts
|
|
18521
18623
|
async function onSessionStart($) {
|
|
18522
18624
|
try {
|
|
@@ -18555,17 +18657,21 @@ async function onPromptSubmit($, event) {
|
|
|
18555
18657
|
function register(on) {
|
|
18556
18658
|
on("session.start", async ($, e, next) => {
|
|
18557
18659
|
await onSessionStart($);
|
|
18660
|
+
await publishContextReading($);
|
|
18558
18661
|
return next(e);
|
|
18559
18662
|
});
|
|
18560
18663
|
on("turn.start", async ($, e, next) => {
|
|
18561
18664
|
await onTurnStart($);
|
|
18665
|
+
await publishContextReading($);
|
|
18562
18666
|
return next(e);
|
|
18563
18667
|
});
|
|
18564
|
-
on("tool.call", async (
|
|
18668
|
+
on("tool.call", async ($, e, next) => {
|
|
18565
18669
|
onToolCall();
|
|
18670
|
+
await publishContextReading($);
|
|
18566
18671
|
return next(e);
|
|
18567
18672
|
});
|
|
18568
18673
|
on("turn.complete", async ($, e, next) => {
|
|
18674
|
+
await publishContextReading($);
|
|
18569
18675
|
await onTurnComplete($, e);
|
|
18570
18676
|
return next(e);
|
|
18571
18677
|
});
|