@cnwenf/occ 2.1.313 → 2.1.315
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/dist/cli.js +431 -144
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
globalThis.MACRO={"VERSION":"2.1.
|
|
2
|
+
globalThis.MACRO={"VERSION":"2.1.315","BINARY_NAME":"occ","BUILD_TIME":"2026-08-28T20:42:08.546Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
|
|
3
3
|
// @bun
|
|
4
4
|
var __create = Object.create;
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
@@ -231222,6 +231222,7 @@ async function loadAgentFromFile(filePath, pluginName, namespace, sourceName, pl
|
|
|
231222
231222
|
}
|
|
231223
231223
|
const isolationRaw = frontmatter.isolation;
|
|
231224
231224
|
const isolation = isolationRaw === "worktree" ? "worktree" : undefined;
|
|
231225
|
+
const cacheTtl = extractAgentCacheTtl(frontmatter);
|
|
231225
231226
|
const effortRaw = frontmatter.effort;
|
|
231226
231227
|
const effort = effortRaw !== undefined ? parseEffortValue(effortRaw) : undefined;
|
|
231227
231228
|
if (effortRaw !== undefined && effort === undefined) {
|
|
@@ -231274,7 +231275,8 @@ async function loadAgentFromFile(filePath, pluginName, namespace, sourceName, pl
|
|
|
231274
231275
|
...memory ? { memory } : {},
|
|
231275
231276
|
...isolation ? { isolation } : {},
|
|
231276
231277
|
...effort !== undefined ? { effort } : {},
|
|
231277
|
-
...maxTurns !== undefined ? { maxTurns } : {}
|
|
231278
|
+
...maxTurns !== undefined ? { maxTurns } : {},
|
|
231279
|
+
...cacheTtl !== undefined ? { cacheTtl } : {}
|
|
231278
231280
|
};
|
|
231279
231281
|
} catch (error52) {
|
|
231280
231282
|
logForDebugging(`Failed to load agent from ${filePath}: ${error52}`, {
|
|
@@ -231291,6 +231293,7 @@ var init_loadPluginAgents = __esm(() => {
|
|
|
231291
231293
|
init_memoize();
|
|
231292
231294
|
init_paths();
|
|
231293
231295
|
init_agentMemory();
|
|
231296
|
+
init_loadAgentsDir();
|
|
231294
231297
|
init_prompt3();
|
|
231295
231298
|
init_prompt4();
|
|
231296
231299
|
init_debug();
|
|
@@ -232235,6 +232238,7 @@ __export(exports_loadAgentsDir, {
|
|
|
232235
232238
|
getAgentDefinitionsWithOverrides: () => getAgentDefinitionsWithOverrides,
|
|
232236
232239
|
getActiveAgentsFromList: () => getActiveAgentsFromList,
|
|
232237
232240
|
filterAgentsByMcpRequirements: () => filterAgentsByMcpRequirements,
|
|
232241
|
+
extractAgentCacheTtl: () => extractAgentCacheTtl,
|
|
232238
232242
|
clearAgentDefinitionsCache: () => clearAgentDefinitionsCache
|
|
232239
232243
|
});
|
|
232240
232244
|
import { basename as basename12, dirname as dirname26, resolve as resolve23, join as join51 } from "path";
|
|
@@ -232438,6 +232442,14 @@ function parseAgentsFromJson(agentsJson, source = "flagSettings") {
|
|
|
232438
232442
|
return [];
|
|
232439
232443
|
}
|
|
232440
232444
|
}
|
|
232445
|
+
function extractAgentCacheTtl(frontmatter) {
|
|
232446
|
+
const experimental = frontmatter.experimental;
|
|
232447
|
+
if (typeof experimental !== "object" || experimental === null) {
|
|
232448
|
+
return;
|
|
232449
|
+
}
|
|
232450
|
+
const raw = Object.entries(experimental).find(([key2]) => key2.toLowerCase() === "cachettl")?.[1];
|
|
232451
|
+
return raw === "5m" || raw === "1h" ? raw : undefined;
|
|
232452
|
+
}
|
|
232441
232453
|
function parseAgentFromMarkdown(filePath, baseDir, frontmatter, content, source) {
|
|
232442
232454
|
try {
|
|
232443
232455
|
const agentType = frontmatter["name"];
|
|
@@ -232487,6 +232499,7 @@ function parseAgentFromMarkdown(filePath, baseDir, frontmatter, content, source)
|
|
|
232487
232499
|
logForDebugging(`Agent file ${filePath} has invalid isolation value '${isolationRaw}'. Valid options: ${VALID_ISOLATION_MODES.join(", ")}`);
|
|
232488
232500
|
}
|
|
232489
232501
|
}
|
|
232502
|
+
const cacheTtl = extractAgentCacheTtl(frontmatter);
|
|
232490
232503
|
const effortRaw = frontmatter["effort"];
|
|
232491
232504
|
const parsedEffort = effortRaw !== undefined ? parseEffortValue(effortRaw) : undefined;
|
|
232492
232505
|
if (effortRaw !== undefined && parsedEffort === undefined) {
|
|
@@ -232564,7 +232577,8 @@ function parseAgentFromMarkdown(filePath, baseDir, frontmatter, content, source)
|
|
|
232564
232577
|
...maxTurns !== undefined ? { maxTurns } : {},
|
|
232565
232578
|
...background ? { background } : {},
|
|
232566
232579
|
...memory ? { memory } : {},
|
|
232567
|
-
...isolation ? { isolation } : {}
|
|
232580
|
+
...isolation ? { isolation } : {},
|
|
232581
|
+
...cacheTtl !== undefined ? { cacheTtl } : {}
|
|
232568
232582
|
};
|
|
232569
232583
|
return agentDef;
|
|
232570
232584
|
} catch (error52) {
|
|
@@ -252352,7 +252366,8 @@ var init_TaskOutput = __esm(() => {
|
|
|
252352
252366
|
const tail = safeJoinLines(recent, `
|
|
252353
252367
|
`);
|
|
252354
252368
|
const sizeKB = Math.round(this.#totalBytes / 1024);
|
|
252355
|
-
const notice = `
|
|
252369
|
+
const notice = this.#disk.failing || this.#disk.lostOutput ? `
|
|
252370
|
+
Output truncated (${sizeKB}KB total). The full output could not all be saved to ${this.path}; that file may be missing or incomplete.` : `
|
|
252356
252371
|
Output truncated (${sizeKB}KB total). Full output saved to: ${this.path}`;
|
|
252357
252372
|
return tail ? tail + notice : notice.trimStart();
|
|
252358
252373
|
}
|
|
@@ -472394,7 +472409,8 @@ async function* runAgent({
|
|
|
472394
472409
|
userContext: resolvedUserContext,
|
|
472395
472410
|
systemContext: resolvedSystemContext,
|
|
472396
472411
|
toolUseContext: agentToolUseContext,
|
|
472397
|
-
forkContextMessages: initialMessages
|
|
472412
|
+
forkContextMessages: initialMessages,
|
|
472413
|
+
...agentDefinition.cacheTtl !== undefined ? { agentCacheTtlOverride: agentDefinition.cacheTtl } : {}
|
|
472398
472414
|
});
|
|
472399
472415
|
}
|
|
472400
472416
|
recordSidechainTranscript(initialMessages, agentId).catch((_err) => logForDebugging(`Failed to record sidechain transcript: ${_err}`));
|
|
@@ -472421,7 +472437,8 @@ async function* runAgent({
|
|
|
472421
472437
|
canUseTool,
|
|
472422
472438
|
toolUseContext: agentToolUseContext,
|
|
472423
472439
|
querySource,
|
|
472424
|
-
maxTurns: maxTurns ?? agentDefinition.maxTurns
|
|
472440
|
+
maxTurns: maxTurns ?? agentDefinition.maxTurns,
|
|
472441
|
+
agentCacheTtlOverride: agentDefinition.cacheTtl
|
|
472425
472442
|
})) {
|
|
472426
472443
|
onQueryProgress?.();
|
|
472427
472444
|
if (message.type === "stream_event" && message.event.type === "message_start" && message.ttftMs != null) {
|
|
@@ -597566,7 +597583,8 @@ async function* queryLoop(params, consumedCommandUuids) {
|
|
|
597566
597583
|
fallbackModel,
|
|
597567
597584
|
querySource,
|
|
597568
597585
|
maxTurns,
|
|
597569
|
-
skipCacheWrite
|
|
597586
|
+
skipCacheWrite,
|
|
597587
|
+
agentCacheTtlOverride
|
|
597570
597588
|
} = params;
|
|
597571
597589
|
const deps = params.deps ?? productionDeps();
|
|
597572
597590
|
let state3 = {
|
|
@@ -597779,6 +597797,7 @@ async function* queryLoop(params, consumedCommandUuids) {
|
|
|
597779
597797
|
effortValue: appState.effortValue,
|
|
597780
597798
|
advisorModel: appState.advisorModel,
|
|
597781
597799
|
skipCacheWrite,
|
|
597800
|
+
agentCacheTtlOverride,
|
|
597782
597801
|
agentId: toolUseContext.agentId,
|
|
597783
597802
|
addNotification: toolUseContext.addNotification,
|
|
597784
597803
|
...params.taskBudget && {
|
|
@@ -599249,7 +599268,8 @@ async function runForkedAgent({
|
|
|
599249
599268
|
userContext,
|
|
599250
599269
|
systemContext,
|
|
599251
599270
|
toolUseContext,
|
|
599252
|
-
forkContextMessages
|
|
599271
|
+
forkContextMessages,
|
|
599272
|
+
agentCacheTtlOverride
|
|
599253
599273
|
} = cacheSafeParams;
|
|
599254
599274
|
const isolatedToolUseContext = createSubagentContext(toolUseContext, overrides);
|
|
599255
599275
|
const initialMessages = [...forkContextMessages, ...promptMessages];
|
|
@@ -599270,7 +599290,8 @@ async function runForkedAgent({
|
|
|
599270
599290
|
querySource,
|
|
599271
599291
|
maxOutputTokensOverride: maxOutputTokens,
|
|
599272
599292
|
maxTurns,
|
|
599273
|
-
skipCacheWrite
|
|
599293
|
+
skipCacheWrite,
|
|
599294
|
+
agentCacheTtlOverride
|
|
599274
599295
|
})) {
|
|
599275
599296
|
if (message.type === "stream_event") {
|
|
599276
599297
|
if ("event" in message && message.event?.type === "message_delta" && message.event.usage) {
|
|
@@ -631304,11 +631325,12 @@ function getPromptCachingEnabled(model) {
|
|
|
631304
631325
|
}
|
|
631305
631326
|
function getCacheControl({
|
|
631306
631327
|
scope,
|
|
631307
|
-
querySource
|
|
631328
|
+
querySource,
|
|
631329
|
+
agentCacheTtlOverride
|
|
631308
631330
|
} = {}) {
|
|
631309
631331
|
return {
|
|
631310
631332
|
type: "ephemeral",
|
|
631311
|
-
...should1hCacheTTL(querySource) && { ttl: "1h" },
|
|
631333
|
+
...should1hCacheTTL(querySource, agentCacheTtlOverride) && { ttl: "1h" },
|
|
631312
631334
|
...scope === "global" && { scope }
|
|
631313
631335
|
};
|
|
631314
631336
|
}
|
|
@@ -631321,7 +631343,7 @@ function isMainThreadQuerySource(querySource) {
|
|
|
631321
631343
|
function parsePromptCacheTtlEnv(value) {
|
|
631322
631344
|
return value === "5m" || value === "1h" ? value : undefined;
|
|
631323
631345
|
}
|
|
631324
|
-
function resolvePromptCacheTtlOverride(querySource) {
|
|
631346
|
+
function resolvePromptCacheTtlOverride(querySource, agentCacheTtlOverride, isUsingOverage = false) {
|
|
631325
631347
|
if (isEnvTruthy(process.env.FORCE_PROMPT_CACHING_5M)) {
|
|
631326
631348
|
return { ttl: "5m", reason: "force_5m_env" };
|
|
631327
631349
|
}
|
|
@@ -631333,16 +631355,21 @@ function resolvePromptCacheTtlOverride(querySource) {
|
|
|
631333
631355
|
const settingTtl = isMainThread ? settings.promptCacheTtl : settings.subagentPromptCacheTtl;
|
|
631334
631356
|
if (settingTtl !== undefined)
|
|
631335
631357
|
return { ttl: settingTtl, reason: "setting" };
|
|
631358
|
+
if (agentCacheTtlOverride !== undefined && !(agentCacheTtlOverride === "1h" && isUsingOverage)) {
|
|
631359
|
+
return { ttl: agentCacheTtlOverride, reason: "agent_frontmatter" };
|
|
631360
|
+
}
|
|
631336
631361
|
if (isEnvTruthy(process.env.ENABLE_PROMPT_CACHING_1H) || getAPIProvider() === "bedrock" && isEnvTruthy(process.env.ENABLE_PROMPT_CACHING_1H_BEDROCK)) {
|
|
631337
631362
|
return { ttl: "1h", reason: "enable_1h_env" };
|
|
631338
631363
|
}
|
|
631339
631364
|
return;
|
|
631340
631365
|
}
|
|
631341
|
-
function resolvePromptCacheTtl(querySource) {
|
|
631342
|
-
const
|
|
631366
|
+
function resolvePromptCacheTtl(querySource, options) {
|
|
631367
|
+
const isSubscriber2 = isClaudeAISubscriber();
|
|
631368
|
+
const isOverage = isSubscriber2 && options?.ignoreOverage !== true && currentLimits.isUsingOverage === true;
|
|
631369
|
+
const override = resolvePromptCacheTtlOverride(querySource, options?.agentCacheTtlOverride, isOverage);
|
|
631343
631370
|
if (override !== undefined)
|
|
631344
631371
|
return override;
|
|
631345
|
-
if (!
|
|
631372
|
+
if (!isSubscriber2 || isOverage) {
|
|
631346
631373
|
return { ttl: "5m", reason: "default" };
|
|
631347
631374
|
}
|
|
631348
631375
|
let allowlist = getPromptCache1hAllowlist();
|
|
@@ -631355,8 +631382,8 @@ function resolvePromptCacheTtl(querySource) {
|
|
|
631355
631382
|
}
|
|
631356
631383
|
return querySourceMatchesPatterns(querySource, allowlist) ? { ttl: "1h", reason: "subscriber" } : { ttl: "5m", reason: "default" };
|
|
631357
631384
|
}
|
|
631358
|
-
function should1hCacheTTL(querySource) {
|
|
631359
|
-
return resolvePromptCacheTtl(querySource).ttl === "1h";
|
|
631385
|
+
function should1hCacheTTL(querySource, agentCacheTtlOverride) {
|
|
631386
|
+
return resolvePromptCacheTtl(querySource, { agentCacheTtlOverride }).ttl === "1h";
|
|
631360
631387
|
}
|
|
631361
631388
|
function configureEffortParams(effortValue, outputConfig, extraBodyParams, betas, model) {
|
|
631362
631389
|
if (!modelSupportsEffort(model) || "effort" in outputConfig) {
|
|
@@ -631447,7 +631474,7 @@ async function verifyApiKey(apiKey, isNonInteractiveSession) {
|
|
|
631447
631474
|
throw error52;
|
|
631448
631475
|
}
|
|
631449
631476
|
}
|
|
631450
|
-
function userMessageToMessageParam(message, addCache = false, enablePromptCaching, querySource) {
|
|
631477
|
+
function userMessageToMessageParam(message, addCache = false, enablePromptCaching, querySource, agentCacheTtlOverride) {
|
|
631451
631478
|
if (addCache) {
|
|
631452
631479
|
if (typeof message.message.content === "string") {
|
|
631453
631480
|
return {
|
|
@@ -631457,7 +631484,10 @@ function userMessageToMessageParam(message, addCache = false, enablePromptCachin
|
|
|
631457
631484
|
type: "text",
|
|
631458
631485
|
text: message.message.content,
|
|
631459
631486
|
...enablePromptCaching && {
|
|
631460
|
-
cache_control: getCacheControl({
|
|
631487
|
+
cache_control: getCacheControl({
|
|
631488
|
+
querySource,
|
|
631489
|
+
agentCacheTtlOverride
|
|
631490
|
+
})
|
|
631461
631491
|
}
|
|
631462
631492
|
}
|
|
631463
631493
|
]
|
|
@@ -631467,7 +631497,12 @@ function userMessageToMessageParam(message, addCache = false, enablePromptCachin
|
|
|
631467
631497
|
role: "user",
|
|
631468
631498
|
content: message.message.content.map((_4, i6) => ({
|
|
631469
631499
|
..._4,
|
|
631470
|
-
...i6 === message.message.content.length - 1 ? enablePromptCaching ? {
|
|
631500
|
+
...i6 === message.message.content.length - 1 ? enablePromptCaching ? {
|
|
631501
|
+
cache_control: getCacheControl({
|
|
631502
|
+
querySource,
|
|
631503
|
+
agentCacheTtlOverride
|
|
631504
|
+
})
|
|
631505
|
+
} : {} : {}
|
|
631471
631506
|
}))
|
|
631472
631507
|
};
|
|
631473
631508
|
}
|
|
@@ -631477,7 +631512,7 @@ function userMessageToMessageParam(message, addCache = false, enablePromptCachin
|
|
|
631477
631512
|
content: Array.isArray(message.message.content) ? [...message.message.content] : message.message.content
|
|
631478
631513
|
};
|
|
631479
631514
|
}
|
|
631480
|
-
function assistantMessageToMessageParam(message, addCache = false, enablePromptCaching, querySource) {
|
|
631515
|
+
function assistantMessageToMessageParam(message, addCache = false, enablePromptCaching, querySource, agentCacheTtlOverride) {
|
|
631481
631516
|
if (addCache) {
|
|
631482
631517
|
if (typeof message.message.content === "string") {
|
|
631483
631518
|
return {
|
|
@@ -631487,7 +631522,10 @@ function assistantMessageToMessageParam(message, addCache = false, enablePromptC
|
|
|
631487
631522
|
type: "text",
|
|
631488
631523
|
text: message.message.content,
|
|
631489
631524
|
...enablePromptCaching && {
|
|
631490
|
-
cache_control: getCacheControl({
|
|
631525
|
+
cache_control: getCacheControl({
|
|
631526
|
+
querySource,
|
|
631527
|
+
agentCacheTtlOverride
|
|
631528
|
+
})
|
|
631491
631529
|
}
|
|
631492
631530
|
}
|
|
631493
631531
|
]
|
|
@@ -631497,7 +631535,12 @@ function assistantMessageToMessageParam(message, addCache = false, enablePromptC
|
|
|
631497
631535
|
role: "assistant",
|
|
631498
631536
|
content: message.message.content.map((_4, i6) => ({
|
|
631499
631537
|
..._4,
|
|
631500
|
-
...i6 === message.message.content.length - 1 && _4.type !== "thinking" && _4.type !== "redacted_thinking" && (feature("CONNECTOR_TEXT") ? !isConnectorTextBlock(_4) : true) ? enablePromptCaching ? {
|
|
631538
|
+
...i6 === message.message.content.length - 1 && _4.type !== "thinking" && _4.type !== "redacted_thinking" && (feature("CONNECTOR_TEXT") ? !isConnectorTextBlock(_4) : true) ? enablePromptCaching ? {
|
|
631539
|
+
cache_control: getCacheControl({
|
|
631540
|
+
querySource,
|
|
631541
|
+
agentCacheTtlOverride
|
|
631542
|
+
})
|
|
631543
|
+
} : {} : {}
|
|
631501
631544
|
}))
|
|
631502
631545
|
};
|
|
631503
631546
|
}
|
|
@@ -631719,7 +631762,7 @@ async function* queryModel(messages, systemPrompt, thinkingConfig, tools, signal
|
|
|
631719
631762
|
queryCheckpoint("query_tool_schema_build_start");
|
|
631720
631763
|
const isAgenticQuery = options.querySource.startsWith("repl_main_thread") || options.querySource.startsWith("agent:") || options.querySource === "sdk" || options.querySource === "hook_agent" || options.querySource === "verification_agent";
|
|
631721
631764
|
const betas = getMergedBetas(options.model, { isAgenticQuery });
|
|
631722
|
-
if (should1hCacheTTL(options.querySource) && shouldSendExtendedCacheTtlBeta() && !betas.includes(EXTENDED_CACHE_TTL_BETA_HEADER)) {
|
|
631765
|
+
if (should1hCacheTTL(options.querySource, options.agentCacheTtlOverride) && shouldSendExtendedCacheTtlBeta() && !betas.includes(EXTENDED_CACHE_TTL_BETA_HEADER)) {
|
|
631723
631766
|
betas.push(EXTENDED_CACHE_TTL_BETA_HEADER);
|
|
631724
631767
|
}
|
|
631725
631768
|
if (isAdvisorEnabled()) {
|
|
@@ -631871,7 +631914,8 @@ ${deferredToolList}
|
|
|
631871
631914
|
const enablePromptCaching = options.enablePromptCaching ?? getPromptCachingEnabled(options.model);
|
|
631872
631915
|
const system = buildSystemPromptBlocks(systemPrompt, enablePromptCaching, {
|
|
631873
631916
|
skipGlobalCacheForSystemPrompt: needsToolBasedCacheMarker,
|
|
631874
|
-
querySource: options.querySource
|
|
631917
|
+
querySource: options.querySource,
|
|
631918
|
+
agentCacheTtlOverride: options.agentCacheTtlOverride
|
|
631875
631919
|
});
|
|
631876
631920
|
const useBetas = betas.length > 0;
|
|
631877
631921
|
const extraToolSchemas = [...options.extraToolSchemas ?? []];
|
|
@@ -632026,7 +632070,7 @@ ${deferredToolList}
|
|
|
632026
632070
|
lastRequestBetas = betasParams;
|
|
632027
632071
|
return {
|
|
632028
632072
|
model: normalizeModelStringForAPI(options.model),
|
|
632029
|
-
messages: addCacheBreakpoints(messagesForAPI, enablePromptCaching2, options.querySource, useCachedMC, consumedCacheEdits, consumedPinnedEdits, options.skipCacheWrite),
|
|
632073
|
+
messages: addCacheBreakpoints(messagesForAPI, enablePromptCaching2, options.querySource, useCachedMC, consumedCacheEdits, consumedPinnedEdits, options.skipCacheWrite, options.agentCacheTtlOverride),
|
|
632030
632074
|
system,
|
|
632031
632075
|
tools: allTools,
|
|
632032
632076
|
tool_choice: options.toolChoice,
|
|
@@ -632880,7 +632924,7 @@ function accumulateUsage(totalUsage, messageUsage) {
|
|
|
632880
632924
|
function isToolResultBlock2(block) {
|
|
632881
632925
|
return block !== null && typeof block === "object" && "type" in block && block.type === "tool_result" && "tool_use_id" in block;
|
|
632882
632926
|
}
|
|
632883
|
-
function addCacheBreakpoints(messages, enablePromptCaching, querySource, useCachedMC = false, newCacheEdits, pinnedEdits, skipCacheWrite = false) {
|
|
632927
|
+
function addCacheBreakpoints(messages, enablePromptCaching, querySource, useCachedMC = false, newCacheEdits, pinnedEdits, skipCacheWrite = false, agentCacheTtlOverride) {
|
|
632884
632928
|
logEvent2("tengu_api_cache_breakpoints", {
|
|
632885
632929
|
totalMessageCount: messages.length,
|
|
632886
632930
|
cachingEnabled: enablePromptCaching,
|
|
@@ -632890,9 +632934,9 @@ function addCacheBreakpoints(messages, enablePromptCaching, querySource, useCach
|
|
|
632890
632934
|
const result = messages.map((msg, index2) => {
|
|
632891
632935
|
const addCache = index2 === markerIndex;
|
|
632892
632936
|
if (msg.type === "user") {
|
|
632893
|
-
return userMessageToMessageParam(msg, addCache, enablePromptCaching, querySource);
|
|
632937
|
+
return userMessageToMessageParam(msg, addCache, enablePromptCaching, querySource, agentCacheTtlOverride);
|
|
632894
632938
|
}
|
|
632895
|
-
return assistantMessageToMessageParam(msg, addCache, enablePromptCaching, querySource);
|
|
632939
|
+
return assistantMessageToMessageParam(msg, addCache, enablePromptCaching, querySource, agentCacheTtlOverride);
|
|
632896
632940
|
});
|
|
632897
632941
|
if (!useCachedMC) {
|
|
632898
632942
|
return result;
|
|
@@ -632983,7 +633027,8 @@ function buildSystemPromptBlocks(systemPrompt, enablePromptCaching, options) {
|
|
|
632983
633027
|
...enablePromptCaching && block.cacheScope !== null && {
|
|
632984
633028
|
cache_control: getCacheControl({
|
|
632985
633029
|
scope: block.cacheScope,
|
|
632986
|
-
querySource: options?.querySource
|
|
633030
|
+
querySource: options?.querySource,
|
|
633031
|
+
agentCacheTtlOverride: options?.agentCacheTtlOverride
|
|
632987
633032
|
})
|
|
632988
633033
|
}
|
|
632989
633034
|
};
|
|
@@ -726092,6 +726137,7 @@ __export(exports_diskOutput, {
|
|
|
726092
726137
|
appendTaskOutput: () => appendTaskOutput,
|
|
726093
726138
|
_resetTaskOutputDirForTest: () => _resetTaskOutputDirForTest,
|
|
726094
726139
|
_clearOutputsForTest: () => _clearOutputsForTest,
|
|
726140
|
+
OUTPUT_OMITTED_MARKER_FOR_TEST: () => OUTPUT_OMITTED_MARKER_FOR_TEST,
|
|
726095
726141
|
MAX_TASK_OUTPUT_BYTES_DISPLAY: () => MAX_TASK_OUTPUT_BYTES_DISPLAY,
|
|
726096
726142
|
MAX_TASK_OUTPUT_BYTES: () => MAX_TASK_OUTPUT_BYTES,
|
|
726097
726143
|
DiskTaskOutput: () => DiskTaskOutput
|
|
@@ -726132,6 +726178,11 @@ class DiskTaskOutput {
|
|
|
726132
726178
|
#queue = [];
|
|
726133
726179
|
#bytesWritten = 0;
|
|
726134
726180
|
#capped = false;
|
|
726181
|
+
#unwrittenChars = 0;
|
|
726182
|
+
#cancelCount = 0;
|
|
726183
|
+
#failing = false;
|
|
726184
|
+
#seenFailureKeys = new Set;
|
|
726185
|
+
#lostOutput = false;
|
|
726135
726186
|
#flushPromise = null;
|
|
726136
726187
|
#flushResolve = null;
|
|
726137
726188
|
constructor(taskId) {
|
|
@@ -726144,11 +726195,14 @@ class DiskTaskOutput {
|
|
|
726144
726195
|
this.#bytesWritten += content.length;
|
|
726145
726196
|
if (this.#bytesWritten > MAX_TASK_OUTPUT_BYTES) {
|
|
726146
726197
|
this.#capped = true;
|
|
726147
|
-
|
|
726198
|
+
const marker = `
|
|
726148
726199
|
[output truncated: exceeded ${MAX_TASK_OUTPUT_BYTES_DISPLAY} disk cap]
|
|
726149
|
-
|
|
726200
|
+
`;
|
|
726201
|
+
this.#queue.push(marker);
|
|
726202
|
+
this.#unwrittenChars += marker.length;
|
|
726150
726203
|
} else {
|
|
726151
726204
|
this.#queue.push(content);
|
|
726205
|
+
this.#unwrittenChars += content.length;
|
|
726152
726206
|
}
|
|
726153
726207
|
if (!this.#flushPromise) {
|
|
726154
726208
|
this.#flushPromise = new Promise((resolve59) => {
|
|
@@ -726160,8 +726214,19 @@ class DiskTaskOutput {
|
|
|
726160
726214
|
flush() {
|
|
726161
726215
|
return this.#flushPromise ?? Promise.resolve();
|
|
726162
726216
|
}
|
|
726217
|
+
get failing() {
|
|
726218
|
+
return this.#failing;
|
|
726219
|
+
}
|
|
726220
|
+
get lostOutput() {
|
|
726221
|
+
return this.#lostOutput;
|
|
726222
|
+
}
|
|
726223
|
+
get unwrittenChars() {
|
|
726224
|
+
return this.#unwrittenChars;
|
|
726225
|
+
}
|
|
726163
726226
|
cancel() {
|
|
726227
|
+
this.#cancelCount += 1;
|
|
726164
726228
|
this.#queue.length = 0;
|
|
726229
|
+
this.#unwrittenChars = 0;
|
|
726165
726230
|
}
|
|
726166
726231
|
async#drainAllChunks() {
|
|
726167
726232
|
while (true) {
|
|
@@ -726171,7 +726236,17 @@ class DiskTaskOutput {
|
|
|
726171
726236
|
this.#fileHandle = await open15(this.#path, process.platform === "win32" ? "a" : fsConstants9.O_WRONLY | fsConstants9.O_APPEND | fsConstants9.O_CREAT | O_NOFOLLOW2);
|
|
726172
726237
|
}
|
|
726173
726238
|
while (true) {
|
|
726174
|
-
|
|
726239
|
+
const cancelCount = this.#cancelCount;
|
|
726240
|
+
try {
|
|
726241
|
+
await this.#writeAllChunks();
|
|
726242
|
+
} catch (e4) {
|
|
726243
|
+
if (this.#cancelCount === cancelCount) {
|
|
726244
|
+
this.#lostOutput = true;
|
|
726245
|
+
this.#queue.unshift(OUTPUT_OMITTED_MARKER);
|
|
726246
|
+
this.#unwrittenChars += OUTPUT_OMITTED_MARKER.length;
|
|
726247
|
+
}
|
|
726248
|
+
throw e4;
|
|
726249
|
+
}
|
|
726175
726250
|
if (this.#queue.length === 0) {
|
|
726176
726251
|
break;
|
|
726177
726252
|
}
|
|
@@ -726194,6 +726269,7 @@ class DiskTaskOutput {
|
|
|
726194
726269
|
}
|
|
726195
726270
|
#queueToBuffers() {
|
|
726196
726271
|
const queue2 = this.#queue.splice(0, this.#queue.length);
|
|
726272
|
+
this.#unwrittenChars = 0;
|
|
726197
726273
|
let totalLength = 0;
|
|
726198
726274
|
for (const str2 of queue2) {
|
|
726199
726275
|
totalLength += Buffer.byteLength(str2, "utf8");
|
|
@@ -726208,13 +726284,18 @@ class DiskTaskOutput {
|
|
|
726208
726284
|
async#drain() {
|
|
726209
726285
|
try {
|
|
726210
726286
|
await this.#drainAllChunks();
|
|
726287
|
+
this.#clearFailureState();
|
|
726211
726288
|
} catch (e4) {
|
|
726212
|
-
|
|
726289
|
+
if (!this.#failing) {
|
|
726290
|
+
this.#failing = true;
|
|
726291
|
+
logError2(new Error(`Task output drain failed (will retry once): ${e4}`));
|
|
726292
|
+
}
|
|
726213
726293
|
if (this.#queue.length > 0) {
|
|
726214
726294
|
try {
|
|
726215
726295
|
await this.#drainAllChunks();
|
|
726296
|
+
this.#clearFailureState();
|
|
726216
726297
|
} catch (e22) {
|
|
726217
|
-
|
|
726298
|
+
this.#handleFinalDrainFailure(e22);
|
|
726218
726299
|
}
|
|
726219
726300
|
}
|
|
726220
726301
|
} finally {
|
|
@@ -726224,6 +726305,30 @@ class DiskTaskOutput {
|
|
|
726224
726305
|
resolve59();
|
|
726225
726306
|
}
|
|
726226
726307
|
}
|
|
726308
|
+
#clearFailureState() {
|
|
726309
|
+
this.#failing = false;
|
|
726310
|
+
this.#seenFailureKeys.clear();
|
|
726311
|
+
}
|
|
726312
|
+
#handleFinalDrainFailure(e4) {
|
|
726313
|
+
const code = getErrnoCode(e4);
|
|
726314
|
+
const kind = code !== undefined && DISK_EXHAUSTION_ERRNOS.has(code) ? "exhaustion" : "unexpected";
|
|
726315
|
+
const failureKey = `${kind}:${code ?? "no errno"}`;
|
|
726316
|
+
if (!this.#seenFailureKeys.has(failureKey)) {
|
|
726317
|
+
this.#seenFailureKeys.add(failureKey);
|
|
726318
|
+
if (kind === "exhaustion") {
|
|
726319
|
+
logError2(new Error(`Task output drain retry failed (${code}): ${e4}`));
|
|
726320
|
+
} else {
|
|
726321
|
+
logError2(e4);
|
|
726322
|
+
}
|
|
726323
|
+
}
|
|
726324
|
+
if (this.#unwrittenChars > MAX_UNWRITTEN_CHARS_BEFORE_DROP) {
|
|
726325
|
+
logError2(new Error(`Task output still cannot be written (${code ?? "no errno"}); dropped ${this.#unwrittenChars} chars of unwritten output`));
|
|
726326
|
+
this.#lostOutput = true;
|
|
726327
|
+
this.#queue.length = 0;
|
|
726328
|
+
this.#queue.push(OUTPUT_OMITTED_MARKER);
|
|
726329
|
+
this.#unwrittenChars = OUTPUT_OMITTED_MARKER.length;
|
|
726330
|
+
}
|
|
726331
|
+
}
|
|
726227
726332
|
}
|
|
726228
726333
|
async function _clearOutputsForTest() {
|
|
726229
726334
|
for (const output2 of outputs.values()) {
|
|
@@ -726242,6 +726347,14 @@ function getOrCreateOutput(taskId) {
|
|
|
726242
726347
|
}
|
|
726243
726348
|
return output2;
|
|
726244
726349
|
}
|
|
726350
|
+
function logTaskOutputFailure(context8, e4) {
|
|
726351
|
+
const code = getErrnoCode(e4);
|
|
726352
|
+
if (code && DISK_EXHAUSTION_ERRNOS.has(code)) {
|
|
726353
|
+
logError2(new Error(`${context8} failed (${code}): ${e4}`));
|
|
726354
|
+
} else {
|
|
726355
|
+
logError2(e4);
|
|
726356
|
+
}
|
|
726357
|
+
}
|
|
726245
726358
|
function appendTaskOutput(taskId, content) {
|
|
726246
726359
|
getOrCreateOutput(taskId).append(content);
|
|
726247
726360
|
}
|
|
@@ -726256,6 +726369,9 @@ function evictTaskOutput(taskId) {
|
|
|
726256
726369
|
const output2 = outputs.get(taskId);
|
|
726257
726370
|
if (output2) {
|
|
726258
726371
|
await output2.flush();
|
|
726372
|
+
if (output2.failing && output2.unwrittenChars > 0) {
|
|
726373
|
+
logError2(new Error(`Task output writer evicted while failing; discarded ${output2.unwrittenChars} chars of unwritten output`));
|
|
726374
|
+
}
|
|
726259
726375
|
outputs.delete(taskId);
|
|
726260
726376
|
}
|
|
726261
726377
|
})());
|
|
@@ -726275,7 +726391,7 @@ async function getTaskOutputDelta(taskId, fromOffset, maxBytes = DEFAULT_MAX_REA
|
|
|
726275
726391
|
if (code === "ENOENT") {
|
|
726276
726392
|
return { content: "", newOffset: fromOffset };
|
|
726277
726393
|
}
|
|
726278
|
-
|
|
726394
|
+
logTaskOutputFailure("getTaskOutputDelta", e4);
|
|
726279
726395
|
return { content: "", newOffset: fromOffset };
|
|
726280
726396
|
}
|
|
726281
726397
|
}
|
|
@@ -726292,7 +726408,7 @@ ${content}`;
|
|
|
726292
726408
|
if (code === "ENOENT") {
|
|
726293
726409
|
return "";
|
|
726294
726410
|
}
|
|
726295
|
-
|
|
726411
|
+
logTaskOutputFailure("getTaskOutput", e4);
|
|
726296
726412
|
return "";
|
|
726297
726413
|
}
|
|
726298
726414
|
}
|
|
@@ -726304,7 +726420,7 @@ async function getTaskOutputSize(taskId) {
|
|
|
726304
726420
|
if (code === "ENOENT") {
|
|
726305
726421
|
return 0;
|
|
726306
726422
|
}
|
|
726307
|
-
|
|
726423
|
+
logTaskOutputFailure("getTaskOutputSize", e4);
|
|
726308
726424
|
return 0;
|
|
726309
726425
|
}
|
|
726310
726426
|
}
|
|
@@ -726321,7 +726437,7 @@ async function cleanupTaskOutput(taskId) {
|
|
|
726321
726437
|
if (code === "ENOENT") {
|
|
726322
726438
|
return;
|
|
726323
726439
|
}
|
|
726324
|
-
|
|
726440
|
+
logTaskOutputFailure("cleanupTaskOutput", e4);
|
|
726325
726441
|
}
|
|
726326
726442
|
}
|
|
726327
726443
|
function initTaskOutput(taskId) {
|
|
@@ -726351,7 +726467,9 @@ function initTaskOutputAsSymlink(taskId, targetPath) {
|
|
|
726351
726467
|
}
|
|
726352
726468
|
})());
|
|
726353
726469
|
}
|
|
726354
|
-
var O_NOFOLLOW2, DEFAULT_MAX_READ_BYTES, MAX_TASK_OUTPUT_BYTES, MAX_TASK_OUTPUT_BYTES_DISPLAY = "5GB",
|
|
726470
|
+
var O_NOFOLLOW2, DEFAULT_MAX_READ_BYTES, MAX_TASK_OUTPUT_BYTES, MAX_TASK_OUTPUT_BYTES_DISPLAY = "5GB", MAX_UNWRITTEN_CHARS_BEFORE_DROP, OUTPUT_OMITTED_MARKER = `
|
|
726471
|
+
[output omitted: it could not be written to disk]
|
|
726472
|
+
`, OUTPUT_OMITTED_MARKER_FOR_TEST, DISK_EXHAUSTION_ERRNOS, _taskOutputDir, _pendingOps, outputs;
|
|
726355
726473
|
var init_diskOutput = __esm(() => {
|
|
726356
726474
|
init_state();
|
|
726357
726475
|
init_errors();
|
|
@@ -726361,6 +726479,14 @@ var init_diskOutput = __esm(() => {
|
|
|
726361
726479
|
O_NOFOLLOW2 = fsConstants9.O_NOFOLLOW ?? 0;
|
|
726362
726480
|
DEFAULT_MAX_READ_BYTES = 8 * 1024 * 1024;
|
|
726363
726481
|
MAX_TASK_OUTPUT_BYTES = 5 * 1024 * 1024 * 1024;
|
|
726482
|
+
MAX_UNWRITTEN_CHARS_BEFORE_DROP = 16 * 1024 * 1024;
|
|
726483
|
+
OUTPUT_OMITTED_MARKER_FOR_TEST = OUTPUT_OMITTED_MARKER;
|
|
726484
|
+
DISK_EXHAUSTION_ERRNOS = new Set([
|
|
726485
|
+
"ENOSPC",
|
|
726486
|
+
"EDQUOT",
|
|
726487
|
+
"ENFILE",
|
|
726488
|
+
"EMFILE"
|
|
726489
|
+
]);
|
|
726364
726490
|
_pendingOps = new Set;
|
|
726365
726491
|
outputs = new Map;
|
|
726366
726492
|
});
|
|
@@ -727073,21 +727199,6 @@ var init_execPromptHook = __esm(() => {
|
|
|
727073
727199
|
init_hookHelpers();
|
|
727074
727200
|
});
|
|
727075
727201
|
|
|
727076
|
-
// src/utils/hooks/hookExit2Block.ts
|
|
727077
|
-
function exit2BlockReason(params) {
|
|
727078
|
-
const { status: status2, validationError, hasJson, stderr, command: command11 } = params;
|
|
727079
|
-
if (status2 !== 2) {
|
|
727080
|
-
return null;
|
|
727081
|
-
}
|
|
727082
|
-
if (hasJson && !validationError) {
|
|
727083
|
-
return null;
|
|
727084
|
-
}
|
|
727085
|
-
return {
|
|
727086
|
-
blockingError: `[${command11}]: ${stderr || "No stderr output"}`,
|
|
727087
|
-
command: command11
|
|
727088
|
-
};
|
|
727089
|
-
}
|
|
727090
|
-
|
|
727091
727202
|
// src/utils/hooks/execAgentHook.ts
|
|
727092
727203
|
import { randomUUID as randomUUID40 } from "crypto";
|
|
727093
727204
|
async function execAgentHook(hook, hookName, hookEvent, jsonInput, signal, toolUseContext, toolUseID, _messages, agentName) {
|
|
@@ -727692,10 +727803,16 @@ var init_execMcpToolHook = __esm(() => {
|
|
|
727692
727803
|
// src/utils/hooks.ts
|
|
727693
727804
|
var exports_hooks2 = {};
|
|
727694
727805
|
__export(exports_hooks2, {
|
|
727806
|
+
wrapHookErrorWithStderr: () => wrapHookErrorWithStderr,
|
|
727695
727807
|
skipFrontmatterHooksForUntrustedOrigin: () => skipFrontmatterHooksForUntrustedOrigin,
|
|
727696
727808
|
shouldSkipHookDueToTrust: () => shouldSkipHookDueToTrust,
|
|
727697
727809
|
processHookJSONOutput: () => processHookJSONOutput,
|
|
727810
|
+
parseHookOutput: () => parseHookOutput,
|
|
727811
|
+
looksLikeMissingHookScript: () => looksLikeMissingHookScript,
|
|
727698
727812
|
isPerHookCallbackTimeout: () => isPerHookCallbackTimeout,
|
|
727813
|
+
isMultipleJsonDocuments: () => isMultipleJsonDocuments,
|
|
727814
|
+
isAsyncHookAnnouncement: () => isAsyncHookAnnouncement,
|
|
727815
|
+
hookOutputSchemaHint: () => hookOutputSchemaHint,
|
|
727699
727816
|
hookCallbackTimeoutMessage: () => hookCallbackTimeoutMessage,
|
|
727700
727817
|
hasWorktreeCreateHook: () => hasWorktreeCreateHook,
|
|
727701
727818
|
hasInstructionsLoadedHook: () => hasInstructionsLoadedHook,
|
|
@@ -727708,6 +727825,7 @@ __export(exports_hooks2, {
|
|
|
727708
727825
|
getSessionEndHookTimeoutMs: () => getSessionEndHookTimeoutMs,
|
|
727709
727826
|
getPreToolHookBlockingMessage: () => getPreToolHookBlockingMessage,
|
|
727710
727827
|
getMatchingHooks: () => getMatchingHooks,
|
|
727828
|
+
formatHookJsonValidationError: () => formatHookJsonValidationError,
|
|
727711
727829
|
executeWorktreeRemoveHook: () => executeWorktreeRemoveHook,
|
|
727712
727830
|
executeWorktreeCreateHook: () => executeWorktreeCreateHook,
|
|
727713
727831
|
executeUserPromptSubmitHooks: () => executeUserPromptSubmitHooks,
|
|
@@ -727911,6 +728029,109 @@ function getSessionCronsForHookInput() {
|
|
|
727911
728029
|
prompt: capHookString(task.prompt ?? "", HOOK_STRING_CAP)
|
|
727912
728030
|
}));
|
|
727913
728031
|
}
|
|
728032
|
+
function isHookJsonPlainObject(value) {
|
|
728033
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
728034
|
+
}
|
|
728035
|
+
function isHookJsonDiscriminatorIssue(issue2) {
|
|
728036
|
+
const last3 = issue2.path.at(-1);
|
|
728037
|
+
return issue2.code === "invalid_value" && typeof last3 === "string" && HOOK_JSON_DISCRIMINATOR_KEYS.has(last3);
|
|
728038
|
+
}
|
|
728039
|
+
function formatHookJsonIssue(issue2, parentPath) {
|
|
728040
|
+
const path39 = [...parentPath, ...issue2.path];
|
|
728041
|
+
if (issue2.code !== "invalid_union" || (issue2.errors?.length ?? 0) === 0) {
|
|
728042
|
+
return { path: path39, message: issue2.message.replace(/^Invalid input: /, "") };
|
|
728043
|
+
}
|
|
728044
|
+
const errors8 = issue2.errors;
|
|
728045
|
+
const relevant = errors8.find((branch2) => branch2.length > 0 && !branch2.some(isHookJsonDiscriminatorIssue))?.[0];
|
|
728046
|
+
if (relevant) {
|
|
728047
|
+
return formatHookJsonIssue(relevant, path39);
|
|
728048
|
+
}
|
|
728049
|
+
const discriminatorIssues = errors8.flat().filter(isHookJsonDiscriminatorIssue);
|
|
728050
|
+
const first2 = discriminatorIssues[0];
|
|
728051
|
+
if (first2?.code !== "invalid_value") {
|
|
728052
|
+
return { path: path39, message: issue2.message };
|
|
728053
|
+
}
|
|
728054
|
+
const values3 = [
|
|
728055
|
+
...new Set(discriminatorIssues.flatMap((discriminator) => discriminator.code === "invalid_value" ? (discriminator.values ?? []).map((value) => jsonStringify(value)) : []))
|
|
728056
|
+
];
|
|
728057
|
+
const preview = values3.slice(0, 6).join(" | ");
|
|
728058
|
+
return {
|
|
728059
|
+
path: [...path39, ...first2.path],
|
|
728060
|
+
message: `expected one of ${preview}${values3.length > 6 ? " | \u2026" : ""}`
|
|
728061
|
+
};
|
|
728062
|
+
}
|
|
728063
|
+
function formatHookJsonPath(path39) {
|
|
728064
|
+
return path39.map(String).join(".") || "(root)";
|
|
728065
|
+
}
|
|
728066
|
+
function formatHookJsonValidationError(parsed, issues) {
|
|
728067
|
+
const hookSpecificOutput = isHookJsonPlainObject(parsed) ? parsed.hookSpecificOutput : undefined;
|
|
728068
|
+
const formatted = issues.map((issue2) => formatHookJsonIssue(issue2, []));
|
|
728069
|
+
const first2 = formatted[0];
|
|
728070
|
+
let primary = first2 ? `${formatHookJsonPath(first2.path)}: ${first2.message}` : "unknown error";
|
|
728071
|
+
if (isHookJsonPlainObject(hookSpecificOutput) && !("hookEventName" in hookSpecificOutput)) {
|
|
728072
|
+
primary = 'hookSpecificOutput is missing required field "hookEventName"';
|
|
728073
|
+
} else if (isHookJsonPlainObject(hookSpecificOutput) && hookSpecificOutput.hookEventName === "PermissionRequest" && !isHookJsonPlainObject(hookSpecificOutput.decision) && first2?.path[0] === "hookSpecificOutput" && first2.path[1] === "decision") {
|
|
728074
|
+
primary += ' (PermissionRequest decision must be {"behavior": "allow"} or {"behavior": "deny", "message": "..."})';
|
|
728075
|
+
} else if (isHookJsonPlainObject(parsed) && first2?.path.length === 1 && first2.path[0] === "decision" && (parsed.decision === "allow" || parsed.decision === "deny" || parsed.decision === "ask")) {
|
|
728076
|
+
primary += parsed.decision === "ask" ? ' (top-level decision is the legacy approve|block field; for "ask" use hookSpecificOutput.permissionDecision in a PreToolUse hook)' : ` (top-level decision is the legacy approve|block field; for "${parsed.decision}" use hookSpecificOutput.permissionDecision in a PreToolUse hook, or hookSpecificOutput.decision: {"behavior": "${parsed.decision}"} in a PermissionRequest hook)`;
|
|
728077
|
+
}
|
|
728078
|
+
const rest = formatted.slice(1).map((entry) => ` - ${formatHookJsonPath(entry.path)}: ${entry.message}`).join(`
|
|
728079
|
+
`);
|
|
728080
|
+
return `${HOOK_JSON_VALIDATION_ERROR_PREFIX}${primary}${rest ? `
|
|
728081
|
+
${rest}` : ""}
|
|
728082
|
+
|
|
728083
|
+
The hook's output was: ${jsonStringify(parsed, null, 2)}`;
|
|
728084
|
+
}
|
|
728085
|
+
function hookOutputSchemaHint() {
|
|
728086
|
+
return jsonStringify({
|
|
728087
|
+
continue: "boolean (optional)",
|
|
728088
|
+
suppressOutput: "boolean (optional)",
|
|
728089
|
+
stopReason: "string (optional)",
|
|
728090
|
+
decision: '"approve" | "block" (optional)',
|
|
728091
|
+
reason: "string (optional)",
|
|
728092
|
+
systemMessage: "string (optional)",
|
|
728093
|
+
terminalSequence: "string (optional)",
|
|
728094
|
+
hookSpecificOutput: {
|
|
728095
|
+
"for PreToolUse": {
|
|
728096
|
+
hookEventName: '"PreToolUse"',
|
|
728097
|
+
permissionDecision: '"allow" | "deny" | "ask" | "defer" (optional)',
|
|
728098
|
+
permissionDecisionReason: "string (optional)",
|
|
728099
|
+
updatedInput: "object (optional) - Modified tool input to use"
|
|
728100
|
+
},
|
|
728101
|
+
"for PermissionRequest": {
|
|
728102
|
+
hookEventName: '"PermissionRequest"',
|
|
728103
|
+
decision: {
|
|
728104
|
+
"to allow": {
|
|
728105
|
+
behavior: '"allow"',
|
|
728106
|
+
updatedInput: "object (optional) - Modified tool input to use",
|
|
728107
|
+
updatedPermissions: "array (optional) - Permission updates"
|
|
728108
|
+
},
|
|
728109
|
+
"to deny": {
|
|
728110
|
+
behavior: '"deny"',
|
|
728111
|
+
message: "string (optional)",
|
|
728112
|
+
interrupt: "boolean (optional)"
|
|
728113
|
+
}
|
|
728114
|
+
}
|
|
728115
|
+
},
|
|
728116
|
+
"for UserPromptSubmit": {
|
|
728117
|
+
hookEventName: '"UserPromptSubmit"',
|
|
728118
|
+
additionalContext: "string (optional)"
|
|
728119
|
+
},
|
|
728120
|
+
"for PostToolUse": {
|
|
728121
|
+
hookEventName: '"PostToolUse"',
|
|
728122
|
+
additionalContext: "string (optional)"
|
|
728123
|
+
},
|
|
728124
|
+
"for PostToolBatch": {
|
|
728125
|
+
hookEventName: '"PostToolBatch"',
|
|
728126
|
+
additionalContext: "string (optional)"
|
|
728127
|
+
},
|
|
728128
|
+
"for Stop / SubagentStop": {
|
|
728129
|
+
hookEventName: '"Stop" | "SubagentStop"',
|
|
728130
|
+
additionalContext: "string (optional) - Feedback for the model; the conversation continues so the model can act on it"
|
|
728131
|
+
}
|
|
728132
|
+
}
|
|
728133
|
+
}, null, 2);
|
|
728134
|
+
}
|
|
727914
728135
|
function validateHookJson(jsonString) {
|
|
727915
728136
|
const parsed = jsonParse(jsonString);
|
|
727916
728137
|
const validation2 = hookJSONOutputSchema().safeParse(parsed);
|
|
@@ -727918,21 +728139,57 @@ function validateHookJson(jsonString) {
|
|
|
727918
728139
|
logForDebugging("Successfully parsed and validated hook JSON output");
|
|
727919
728140
|
return { json: validation2.data };
|
|
727920
728141
|
}
|
|
727921
|
-
const errors8 = validation2.error.issues.map((err2) => ` - ${err2.path.join(".")}: ${err2.message}`).join(`
|
|
727922
|
-
`);
|
|
727923
728142
|
return {
|
|
727924
|
-
validationError:
|
|
727925
|
-
${errors8}
|
|
727926
|
-
|
|
727927
|
-
The hook's output was: ${jsonStringify(parsed, null, 2)}`
|
|
728143
|
+
validationError: formatHookJsonValidationError(parsed, validation2.error.issues)
|
|
727928
728144
|
};
|
|
727929
728145
|
}
|
|
728146
|
+
function isAsyncHookAnnouncement(stdout) {
|
|
728147
|
+
const firstLine = firstLineOf(stdout).trim();
|
|
728148
|
+
if (!firstLine.startsWith("{")) {
|
|
728149
|
+
return false;
|
|
728150
|
+
}
|
|
728151
|
+
try {
|
|
728152
|
+
const parsed = jsonParse(firstLine);
|
|
728153
|
+
return typeof parsed === "object" && parsed !== null && "async" in parsed && parsed.async === true;
|
|
728154
|
+
} catch {
|
|
728155
|
+
return false;
|
|
728156
|
+
}
|
|
728157
|
+
}
|
|
728158
|
+
function isMultipleJsonDocuments(output2) {
|
|
728159
|
+
const lines2 = output2.split(`
|
|
728160
|
+
`).filter((line) => line.trim() !== "");
|
|
728161
|
+
if (lines2.length < 2) {
|
|
728162
|
+
return false;
|
|
728163
|
+
}
|
|
728164
|
+
return lines2.every((line) => {
|
|
728165
|
+
try {
|
|
728166
|
+
const validation2 = hookJSONOutputSchema().safeParse(jsonParse(line.trim()));
|
|
728167
|
+
return !validation2.success || Object.keys(validation2.data).length === 0;
|
|
728168
|
+
} catch {
|
|
728169
|
+
return false;
|
|
728170
|
+
}
|
|
728171
|
+
});
|
|
728172
|
+
}
|
|
728173
|
+
function wrapHookErrorWithStderr(validationError, exitCode, stderr) {
|
|
728174
|
+
const trimmedStderr = stderr.trim();
|
|
728175
|
+
return exitCode !== 0 && trimmedStderr ? `${validationError}
|
|
728176
|
+
|
|
728177
|
+
Hook exited ${exitCode} with stderr:
|
|
728178
|
+
${trimmedStderr}` : validationError;
|
|
728179
|
+
}
|
|
728180
|
+
function looksLikeMissingHookScript(params) {
|
|
728181
|
+
const { hookEvent, stdout, stderr, pluginId } = params;
|
|
728182
|
+
return (MISSING_SCRIPT_HOOK_EVENTS.has(hookEvent) || Boolean(pluginId) && hookEvent === "UserPromptSubmit") && !stdout.trim() && /no such file|can't open/i.test(stderr);
|
|
728183
|
+
}
|
|
727930
728184
|
function parseHookOutput(stdout) {
|
|
727931
728185
|
const trimmed = stdout.trim();
|
|
727932
728186
|
if (!trimmed.startsWith("{")) {
|
|
727933
728187
|
logForDebugging("Hook output does not start with {, treating as plain text");
|
|
727934
728188
|
return { plainText: stdout };
|
|
727935
728189
|
}
|
|
728190
|
+
if (isAsyncHookAnnouncement(stdout)) {
|
|
728191
|
+
return { json: { async: true } };
|
|
728192
|
+
}
|
|
727936
728193
|
try {
|
|
727937
728194
|
const result = validateHookJson(trimmed);
|
|
727938
728195
|
if ("json" in result) {
|
|
@@ -727941,37 +728198,22 @@ function parseHookOutput(stdout) {
|
|
|
727941
728198
|
const errorMessage3 = `${result.validationError}
|
|
727942
728199
|
|
|
727943
728200
|
Expected schema:
|
|
727944
|
-
${
|
|
727945
|
-
continue: "boolean (optional)",
|
|
727946
|
-
suppressOutput: "boolean (optional)",
|
|
727947
|
-
stopReason: "string (optional)",
|
|
727948
|
-
decision: '"approve" | "block" (optional)',
|
|
727949
|
-
reason: "string (optional)",
|
|
727950
|
-
systemMessage: "string (optional)",
|
|
727951
|
-
permissionDecision: '"allow" | "deny" | "ask" (optional)',
|
|
727952
|
-
hookSpecificOutput: {
|
|
727953
|
-
"for PreToolUse": {
|
|
727954
|
-
hookEventName: '"PreToolUse"',
|
|
727955
|
-
permissionDecision: '"allow" | "deny" | "ask" (optional)',
|
|
727956
|
-
permissionDecisionReason: "string (optional)",
|
|
727957
|
-
updatedInput: "object (optional) - Modified tool input to use"
|
|
727958
|
-
},
|
|
727959
|
-
"for UserPromptSubmit": {
|
|
727960
|
-
hookEventName: '"UserPromptSubmit"',
|
|
727961
|
-
additionalContext: "string (required)",
|
|
727962
|
-
sessionTitle: "string (optional) - Set the session title (same effect as /rename)"
|
|
727963
|
-
},
|
|
727964
|
-
"for PostToolUse": {
|
|
727965
|
-
hookEventName: '"PostToolUse"',
|
|
727966
|
-
additionalContext: "string (optional)"
|
|
727967
|
-
}
|
|
727968
|
-
}
|
|
727969
|
-
}, null, 2)}`;
|
|
728201
|
+
${hookOutputSchemaHint()}`;
|
|
727970
728202
|
logForDebugging(errorMessage3);
|
|
727971
728203
|
return { plainText: stdout, validationError: errorMessage3 };
|
|
727972
728204
|
} catch (e4) {
|
|
727973
|
-
|
|
727974
|
-
|
|
728205
|
+
const parseError = e4 instanceof Error ? e4.message : String(e4);
|
|
728206
|
+
if (!trimmed.endsWith("}")) {
|
|
728207
|
+
logForDebugging(`Hook output starts with { but is not a JSON object, treating as plain text: ${parseError}`);
|
|
728208
|
+
return { plainText: stdout };
|
|
728209
|
+
}
|
|
728210
|
+
if (isMultipleJsonDocuments(trimmed)) {
|
|
728211
|
+
logForDebugging("Hook output is several JSON documents, treating as plain text");
|
|
728212
|
+
return { plainText: stdout };
|
|
728213
|
+
}
|
|
728214
|
+
const errorMessage3 = `Hook output looks like a JSON object but is not valid JSON \u2014 ${parseError}. Emit the payload with a JSON encoder (jq, ConvertTo-Json, json.dumps) rather than string concatenation so backslashes and quotes inside strings are escaped.`;
|
|
728215
|
+
logForDebugging(errorMessage3);
|
|
728216
|
+
return { plainText: stdout, validationError: errorMessage3 };
|
|
727975
728217
|
}
|
|
727976
728218
|
}
|
|
727977
728219
|
function parseHttpHookOutput(body) {
|
|
@@ -729130,7 +729372,7 @@ async function* executeHooks({
|
|
|
729130
729372
|
hookEvent,
|
|
729131
729373
|
output: httpResult.body,
|
|
729132
729374
|
stdout: httpResult.body,
|
|
729133
|
-
stderr:
|
|
729375
|
+
stderr: httpValidationError,
|
|
729134
729376
|
exitCode: httpResult.statusCode,
|
|
729135
729377
|
outcome: "error"
|
|
729136
729378
|
});
|
|
@@ -729140,7 +729382,7 @@ async function* executeHooks({
|
|
|
729140
729382
|
hookName,
|
|
729141
729383
|
toolUseID,
|
|
729142
729384
|
hookEvent,
|
|
729143
|
-
stderr:
|
|
729385
|
+
stderr: httpValidationError,
|
|
729144
729386
|
stdout: httpResult.body,
|
|
729145
729387
|
exitCode: httpResult.statusCode ?? 0,
|
|
729146
729388
|
command: hook.url,
|
|
@@ -729271,43 +729513,16 @@ async function* executeHooks({
|
|
|
729271
729513
|
return;
|
|
729272
729514
|
}
|
|
729273
729515
|
const { json: json2, plainText, validationError } = parseHookOutput(result.stdout);
|
|
729274
|
-
if (validationError) {
|
|
729275
|
-
const
|
|
729276
|
-
status: result.status,
|
|
729277
|
-
validationError,
|
|
729278
|
-
hasJson: !!json2,
|
|
729279
|
-
stderr: result.stderr,
|
|
729280
|
-
command: hookCommand
|
|
729281
|
-
});
|
|
729282
|
-
if (exit2Block) {
|
|
729283
|
-
emitHookResponse({
|
|
729284
|
-
hookId,
|
|
729285
|
-
hookName,
|
|
729286
|
-
hookEvent,
|
|
729287
|
-
output: result.output,
|
|
729288
|
-
stdout: result.stdout,
|
|
729289
|
-
stderr: result.stderr,
|
|
729290
|
-
exitCode: result.status,
|
|
729291
|
-
outcome: "error"
|
|
729292
|
-
});
|
|
729293
|
-
yield {
|
|
729294
|
-
blockingError: {
|
|
729295
|
-
blockingError: exit2Block.blockingError,
|
|
729296
|
-
command: exit2Block.command
|
|
729297
|
-
},
|
|
729298
|
-
outcome: "blocking",
|
|
729299
|
-
hook
|
|
729300
|
-
};
|
|
729301
|
-
return;
|
|
729302
|
-
}
|
|
729516
|
+
if (validationError && result.status !== 2) {
|
|
729517
|
+
const stderr = wrapHookErrorWithStderr(validationError, result.status, result.stderr);
|
|
729303
729518
|
emitHookResponse({
|
|
729304
729519
|
hookId,
|
|
729305
729520
|
hookName,
|
|
729306
729521
|
hookEvent,
|
|
729307
729522
|
output: result.output,
|
|
729308
729523
|
stdout: result.stdout,
|
|
729309
|
-
stderr
|
|
729310
|
-
exitCode:
|
|
729524
|
+
stderr,
|
|
729525
|
+
exitCode: result.status,
|
|
729311
729526
|
outcome: "error"
|
|
729312
729527
|
});
|
|
729313
729528
|
yield {
|
|
@@ -729316,9 +729531,9 @@ async function* executeHooks({
|
|
|
729316
729531
|
hookName,
|
|
729317
729532
|
toolUseID,
|
|
729318
729533
|
hookEvent,
|
|
729319
|
-
stderr
|
|
729534
|
+
stderr,
|
|
729320
729535
|
stdout: result.stdout,
|
|
729321
|
-
exitCode:
|
|
729536
|
+
exitCode: result.status,
|
|
729322
729537
|
command: hookCommand,
|
|
729323
729538
|
durationMs
|
|
729324
729539
|
}),
|
|
@@ -729329,6 +729544,55 @@ async function* executeHooks({
|
|
|
729329
729544
|
}
|
|
729330
729545
|
if (json2) {
|
|
729331
729546
|
if (isAsyncHookJSONOutput(json2)) {
|
|
729547
|
+
if (result.status === 2) {
|
|
729548
|
+
emitHookResponse({
|
|
729549
|
+
hookId,
|
|
729550
|
+
hookName,
|
|
729551
|
+
hookEvent,
|
|
729552
|
+
output: result.output,
|
|
729553
|
+
stdout: result.stdout,
|
|
729554
|
+
stderr: result.stderr,
|
|
729555
|
+
exitCode: result.status,
|
|
729556
|
+
outcome: "error"
|
|
729557
|
+
});
|
|
729558
|
+
yield {
|
|
729559
|
+
blockingError: {
|
|
729560
|
+
blockingError: `[${hook.command}]: ${result.stderr || "No stderr output"}`,
|
|
729561
|
+
command: hook.command
|
|
729562
|
+
},
|
|
729563
|
+
outcome: "blocking",
|
|
729564
|
+
hook
|
|
729565
|
+
};
|
|
729566
|
+
return;
|
|
729567
|
+
}
|
|
729568
|
+
if (result.status !== 0) {
|
|
729569
|
+
emitHookResponse({
|
|
729570
|
+
hookId,
|
|
729571
|
+
hookName,
|
|
729572
|
+
hookEvent,
|
|
729573
|
+
output: result.output,
|
|
729574
|
+
stdout: result.stdout,
|
|
729575
|
+
stderr: result.stderr,
|
|
729576
|
+
exitCode: result.status,
|
|
729577
|
+
outcome: "error"
|
|
729578
|
+
});
|
|
729579
|
+
yield {
|
|
729580
|
+
message: createAttachmentMessage({
|
|
729581
|
+
type: "hook_non_blocking_error",
|
|
729582
|
+
hookName,
|
|
729583
|
+
toolUseID,
|
|
729584
|
+
hookEvent,
|
|
729585
|
+
stderr: `Announced async, then failed with status code ${result.status}: ${result.stderr.trim() || "No stderr output"}`,
|
|
729586
|
+
stdout: result.stdout,
|
|
729587
|
+
exitCode: result.status,
|
|
729588
|
+
command: hookCommand,
|
|
729589
|
+
durationMs
|
|
729590
|
+
}),
|
|
729591
|
+
outcome: "non_blocking_error",
|
|
729592
|
+
hook
|
|
729593
|
+
};
|
|
729594
|
+
return;
|
|
729595
|
+
}
|
|
729332
729596
|
yield {
|
|
729333
729597
|
outcome: "success",
|
|
729334
729598
|
hook
|
|
@@ -729431,6 +729695,39 @@ async function* executeHooks({
|
|
|
729431
729695
|
};
|
|
729432
729696
|
return;
|
|
729433
729697
|
}
|
|
729698
|
+
if (result.status === 2 && looksLikeMissingHookScript({
|
|
729699
|
+
hookEvent,
|
|
729700
|
+
stdout: result.stdout,
|
|
729701
|
+
stderr: result.stderr,
|
|
729702
|
+
pluginId
|
|
729703
|
+
})) {
|
|
729704
|
+
emitHookResponse({
|
|
729705
|
+
hookId,
|
|
729706
|
+
hookName,
|
|
729707
|
+
hookEvent,
|
|
729708
|
+
output: result.output,
|
|
729709
|
+
stdout: result.stdout,
|
|
729710
|
+
stderr: result.stderr,
|
|
729711
|
+
exitCode: result.status,
|
|
729712
|
+
outcome: "error"
|
|
729713
|
+
});
|
|
729714
|
+
yield {
|
|
729715
|
+
message: createAttachmentMessage({
|
|
729716
|
+
type: "hook_non_blocking_error",
|
|
729717
|
+
hookName,
|
|
729718
|
+
toolUseID,
|
|
729719
|
+
hookEvent,
|
|
729720
|
+
stderr: `Hook script appears to be missing \u2014 "${hookCommand}" exited 2 with: ${result.stderr.trim()}. Treating as non-blocking. ${pluginId ? `Run \`/plugin\` to reinstall '${pluginId}' or remove it from settings.` : "If this is a plugin hook, check the plugin install (run /plugin)."}`,
|
|
729721
|
+
stdout: result.stdout,
|
|
729722
|
+
exitCode: result.status,
|
|
729723
|
+
command: hookCommand,
|
|
729724
|
+
durationMs
|
|
729725
|
+
}),
|
|
729726
|
+
outcome: "non_blocking_error",
|
|
729727
|
+
hook
|
|
729728
|
+
};
|
|
729729
|
+
return;
|
|
729730
|
+
}
|
|
729434
729731
|
if (result.status === 2) {
|
|
729435
729732
|
emitHookResponse({
|
|
729436
729733
|
hookId,
|
|
@@ -729878,25 +730175,8 @@ async function executeHooksOutsideREPL({
|
|
|
729878
730175
|
}
|
|
729879
730176
|
logForDebugging(`${hookName} [${hook.command}] completed with status ${result.status}`);
|
|
729880
730177
|
const { json: json2, validationError } = parseHookOutput(result.stdout);
|
|
729881
|
-
if (validationError) {
|
|
729882
|
-
|
|
729883
|
-
status: result.status,
|
|
729884
|
-
validationError,
|
|
729885
|
-
hasJson: !!json2,
|
|
729886
|
-
stderr: result.stderr,
|
|
729887
|
-
command: hook.command
|
|
729888
|
-
});
|
|
729889
|
-
if (exit2Block) {
|
|
729890
|
-
return {
|
|
729891
|
-
command: hook.command,
|
|
729892
|
-
succeeded: false,
|
|
729893
|
-
output: result.stderr || "",
|
|
729894
|
-
blocked: true,
|
|
729895
|
-
watchPaths: undefined,
|
|
729896
|
-
systemMessage: undefined
|
|
729897
|
-
};
|
|
729898
|
-
}
|
|
729899
|
-
throw new Error(validationError);
|
|
730178
|
+
if (validationError && result.status !== 2) {
|
|
730179
|
+
throw new Error(wrapHookErrorWithStderr(validationError, result.status, result.stderr));
|
|
729900
730180
|
}
|
|
729901
730181
|
if (json2 && !isAsyncHookJSONOutput(json2)) {
|
|
729902
730182
|
logForDebugging(`Parsed JSON output from hook: ${jsonStringify(json2)}`, { level: "verbose" });
|
|
@@ -730926,7 +731206,7 @@ async function* executeMessageDisplayHooks(display, getAppState, agentId, signal
|
|
|
730926
731206
|
timeoutMs
|
|
730927
731207
|
});
|
|
730928
731208
|
}
|
|
730929
|
-
var TOOL_HOOK_EXECUTION_TIMEOUT_MS, PRE_TOOL_USE_HOOK_TIMEOUT_MESSAGE = "PreToolUse hook did not respond before its timeout (host client may be unreachable). The tool call was not executed; other configured hooks may not have completed.", SESSION_END_HOOK_TIMEOUT_MS_DEFAULT = 1500, BACKGROUND_TASK_TYPE_LABELS, HOOK_STRING_CAP = 1000, MATCHER_COMMA_HYPHEN_EVENTS;
|
|
731209
|
+
var TOOL_HOOK_EXECUTION_TIMEOUT_MS, PRE_TOOL_USE_HOOK_TIMEOUT_MESSAGE = "PreToolUse hook did not respond before its timeout (host client may be unreachable). The tool call was not executed; other configured hooks may not have completed.", SESSION_END_HOOK_TIMEOUT_MS_DEFAULT = 1500, BACKGROUND_TASK_TYPE_LABELS, HOOK_STRING_CAP = 1000, HOOK_JSON_VALIDATION_ERROR_PREFIX = "Hook JSON output validation failed \u2014 ", HOOK_JSON_DISCRIMINATOR_KEYS, MISSING_SCRIPT_HOOK_EVENTS, MATCHER_COMMA_HYPHEN_EVENTS;
|
|
730930
731210
|
var init_hooks5 = __esm(() => {
|
|
730931
731211
|
init_file();
|
|
730932
731212
|
init_envValidation();
|
|
@@ -730989,6 +731269,13 @@ var init_hooks5 = __esm(() => {
|
|
|
730989
731269
|
dream: "dream",
|
|
730990
731270
|
remote_agent: "cloud session"
|
|
730991
731271
|
};
|
|
731272
|
+
HOOK_JSON_DISCRIMINATOR_KEYS = new Set(["async", "hookEventName", "behavior"]);
|
|
731273
|
+
MISSING_SCRIPT_HOOK_EVENTS = new Set([
|
|
731274
|
+
"Stop",
|
|
731275
|
+
"SubagentStop",
|
|
731276
|
+
"TaskCompleted",
|
|
731277
|
+
"TeammateIdle"
|
|
731278
|
+
]);
|
|
730992
731279
|
MATCHER_COMMA_HYPHEN_EVENTS = new Set([
|
|
730993
731280
|
"PreToolUse",
|
|
730994
731281
|
"PostToolUse",
|